diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index 112b4c8b..ebe68445 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -479,6 +479,16 @@ ifneq (,$(shell grep '^unsigned int stack_trace_save' include/linux/stacktrace.h ccflags-y += -DKC_STACK_TRACE_SAVE endif +# +# v3.14-rc1-7-g4e34e719e457 +# +# .set_acl callback added to struct inode_operations. Most kernels +# we target have it, but el7 (3.10 base) does not, so detect. +# +ifneq (,$(shell grep 'int ..set_acl..struct' include/linux/fs.h)) +ccflags-y += -DKC_HAS_SET_ACL +endif + # # v6.1-rc1-2-g138060ba92b3 # diff --git a/kmod/src/acl.c b/kmod/src/acl.c index 356e3107..c836df19 100644 --- a/kmod/src/acl.c +++ b/kmod/src/acl.c @@ -216,7 +216,8 @@ int scoutfs_set_acl(KC_VFS_NS_DEF { struct inode *inode = dentry->d_inode; #else -int scoutfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) +int scoutfs_set_acl(KC_VFS_NS_DEF + struct inode *inode, struct posix_acl *acl, int type) { #endif struct super_block *sb = inode->i_sb; @@ -309,7 +310,7 @@ int scoutfs_acl_set_xattr(struct dentry *dentry, const char *name, const void *v #ifdef KC_SET_ACL_DENTRY ret = scoutfs_set_acl(KC_VFS_INIT_NS dentry, acl, type); #else - ret = scoutfs_set_acl(dentry->d_inode, acl, type); + ret = scoutfs_set_acl(KC_VFS_INIT_NS dentry->d_inode, acl, type); #endif out: posix_acl_release(acl); diff --git a/kmod/src/acl.h b/kmod/src/acl.h index a5bf21d6..2b64fafa 100644 --- a/kmod/src/acl.h +++ b/kmod/src/acl.h @@ -5,7 +5,8 @@ int scoutfs_set_acl(KC_VFS_NS_DEF struct dentry *dentry, struct posix_acl *acl, int type); #else -int scoutfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); +int scoutfs_set_acl(KC_VFS_NS_DEF + struct inode *inode, struct posix_acl *acl, int type); #endif #ifdef KC_GET_INODE_ACL struct posix_acl *scoutfs_get_acl(struct inode *inode, int type, bool rcu); diff --git a/kmod/src/dir.c b/kmod/src/dir.c index efcdef24..f9729d7d 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -2063,7 +2063,7 @@ const struct inode_operations scoutfs_dir_iops = { #else .get_acl = scoutfs_get_acl, #endif -#ifdef KC_SET_ACL_DENTRY +#ifdef KC_HAS_SET_ACL .set_acl = scoutfs_set_acl, #endif .symlink = scoutfs_symlink, diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 96376dc0..621833d2 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -154,7 +154,7 @@ static const struct inode_operations scoutfs_file_iops = { #else .get_acl = scoutfs_get_acl, #endif -#ifdef KC_SET_ACL_DENTRY +#ifdef KC_HAS_SET_ACL .set_acl = scoutfs_set_acl, #endif .fiemap = scoutfs_data_fiemap, @@ -174,7 +174,7 @@ static const struct inode_operations scoutfs_special_iops = { #else .get_acl = scoutfs_get_acl, #endif -#ifdef KC_SET_ACL_DENTRY +#ifdef KC_HAS_SET_ACL .set_acl = scoutfs_set_acl, #endif }; diff --git a/tests/funcs/filter.sh b/tests/funcs/filter.sh index 1016b8ef..3d89e855 100644 --- a/tests/funcs/filter.sh +++ b/tests/funcs/filter.sh @@ -171,6 +171,13 @@ t_filter_dmesg() # orphan log trees reclaim is handled, not an error re="$re|scoutfs .* reclaiming orphan log trees" + # nfs can emit a whole range of messages we can ignore + re="$re|Installing knfsd .*" + re="$re|nfsd: .*" + re="$re|NFSD: .*" + re="$re|RPC: .*" + re="$re|FS-Cache: .*" + # fencing tests force unmounts and trigger timeouts re="$re|scoutfs .* forcing unmount" re="$re|scoutfs .* reconnect timed out" diff --git a/tests/golden/basic-nfs b/tests/golden/basic-nfs new file mode 100644 index 00000000..4e722fb4 --- /dev/null +++ b/tests/golden/basic-nfs @@ -0,0 +1,32 @@ +== write via NFS, read both sides +== POSIX ACL set via NFS, read both sides +user::rw- +user:22222:rw- +group::r-- +mask::rw- +other::r-- + +user::rw- +user:22222:rw- +group::r-- +mask::rw- +other::r-- + +== POSIX ACL set on scoutfs, read via NFS +user::rw- +user:22222:rw- +group::r-- +group:44444:r-- +mask::rw- +other::r-- + +== default ACL inheritance via NFS +user::rw- +user:22222:rwx #effective:rw- +group::r-x #effective:r-- +mask::rw- +other::r-- + +== NFS read demand-stages a released file +1 +== cleanup diff --git a/tests/sequence b/tests/sequence index 909e665a..32a5cf4f 100644 --- a/tests/sequence +++ b/tests/sequence @@ -3,6 +3,7 @@ basic-block-counts.sh basic-bad-mounts.sh basic-posix-acl.sh basic-acl-consistency.sh +basic-nfs.sh inode-items-updated.sh simple-inode-index.sh simple-staging.sh diff --git a/tests/tests/basic-nfs.sh b/tests/tests/basic-nfs.sh new file mode 100644 index 00000000..a347178d --- /dev/null +++ b/tests/tests/basic-nfs.sh @@ -0,0 +1,86 @@ +# +# Test basic scoutfs-nfs interactions: +# - read/write +# - stage/release and data wait +# - nfs setacl/getacl mapping +# + +t_require_commands scoutfs setfacl getfacl exportfs mount.nfs umount \ + stat dd cmp systemctl + +systemctl start nfs-server >> "$T_TMPDIR/nfs.log" 2>&1 || \ + t_skip "nfs-server not available" + +# Keep file creation modes deterministic for the ACL golden output. +umask 022 + +EXPORT_OPTS="rw,async,no_root_squash,no_subtree_check,fsid=42" +NFS_MNT="$T_TMP.nfs" +NFS_DIR="$NFS_MNT/test/basic-nfs" + +filter() { sed "s@$T_TMPDIR@T_TMPDIR@g" | t_filter_fs; } +gf() { getfacl -n --omit-header "$@" 2>/dev/null; } + +teardown_nfs() +{ + ( + umount "$NFS_MNT" + exportfs -u "127.0.0.1:$T_M0" + exportfs -f + systemctl stop nfs-server + rmdir "$NFS_MNT" + ) >> "$T_TMPDIR/nfs.log" 2>&1 +} +trap teardown_nfs EXIT + +exportfs -u "127.0.0.1:$T_M0" >> "$T_TMPDIR/nfs.log" 2>&1 || true +t_quiet mkdir -p "$NFS_MNT" +exportfs -o "$EXPORT_OPTS" "127.0.0.1:$T_M0" >> "$T_TMPDIR/nfs.log" 2>&1 +mount.nfs -o vers=3,noac,actimeo=0 "127.0.0.1:$T_M0" "$NFS_MNT" >> "$T_TMPDIR/nfs.log" 2>&1 + +test -d "$NFS_DIR" || t_fail "test dir $NFS_DIR not visible over NFS" + +echo "== write via NFS, read both sides" +dd if=/dev/urandom bs=4096 count=1 of="$T_TMP.data" status=none +cp "$T_TMP.data" "$NFS_DIR/file" +cmp "$T_TMP.data" "$T_D0/file" +cmp "$T_TMP.data" "$NFS_DIR/file" + +echo "== POSIX ACL set via NFS, read both sides" +setfacl -m u:22222:rw "$NFS_DIR/file" 2>&1 | filter +gf "$NFS_DIR/file" +gf "$T_D0/file" + +echo "== POSIX ACL set on scoutfs, read via NFS" +setfacl -m g:44444:r "$T_D0/file" 2>&1 | filter +gf "$NFS_DIR/file" + +echo "== default ACL inheritance via NFS" +mkdir "$NFS_DIR/d" +setfacl -d -m u:22222:rwx "$NFS_DIR/d" 2>&1 | filter +touch "$NFS_DIR/d/child" +gf "$NFS_DIR/d/child" + +echo "== NFS read demand-stages a released file" +dd if=/dev/urandom bs=4096 count=1 of="$T_TMP.big" status=none +cp "$T_TMP.big" "$T_D0/big" +sync +vers=$(scoutfs stat -s data_version "$T_D0/big") +t_quiet scoutfs release "$T_D0/big" -V "$vers" -o 0 -l 4K + +# NFS read against the offline file blocks in scoutfs_read waiting +# for the data to come back online. +cat "$NFS_DIR/big" > "$T_TMP.read" & +read_pid=$! +sleep 1 +scoutfs data-waiting -B 0 -I 0 -p "$T_D0" | wc -l + +t_quiet scoutfs stage "$T_TMP.big" "$T_D0/big" -V "$vers" -o 0 -l 4096 +wait "$read_pid" +cmp "$T_TMP.big" "$T_TMP.read" + +echo "== cleanup" +rm -f "$T_D0/file" "$T_D0/big" +rm -rf "$T_D0/d" + +t_pass