nfsd: allow filesystems to opt out of subtree checking
authorJeff Layton <jeff.layton@primarydata.com>
Mon, 30 Nov 2020 22:03:15 +0000 (17:03 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Wed, 9 Dec 2020 14:39:38 +0000 (09:39 -0500)
When we start allowing NFS to be reexported, then we have some problems
when it comes to subtree checking. In principle, we could allow it, but
it would mean encoding parent info in the filehandles and there may not
be enough space for that in a NFSv3 filehandle.

To enforce this at export upcall time, we add a new export_ops flag
that declares the filesystem ineligible for subtree checking.

Signed-off-by: Jeff Layton <jeff.layton@primarydata.com>
Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Documentation/filesystems/nfs/exporting.rst
fs/nfs/export.c
fs/nfsd/export.c
include/linux/exportfs.h

index cbe542ad52333c5bbead36784c2bb99abfec04c3..960be64446cb9678ef475a6905688d42c24f74ec 100644 (file)
@@ -190,3 +190,15 @@ following flags are defined:
     this on filesystems that have an expensive ->getattr inode operation,
     or when atomicity between pre and post operation attribute collection
     is impossible to guarantee.
+
+  EXPORT_OP_NOSUBTREECHK - disallow subtree checking on this fs
+    Many NFS operations deal with filehandles, which the server must then
+    vet to ensure that they live inside of an exported tree. When the
+    export consists of an entire filesystem, this is trivial. nfsd can just
+    ensure that the filehandle live on the filesystem. When only part of a
+    filesystem is exported however, then nfsd must walk the ancestors of the
+    inode to ensure that it's within an exported subtree. This is an
+    expensive operation and not all filesystems can support it properly.
+    This flag exempts the filesystem from subtree checking and causes
+    exportfs to get back an error if it tries to enable subtree checking
+    on it.
index 8f4c528865c57678e09341a073a6f3d88f9905a4..b9ba306bf912055f946587e557d5c40d7aa4e9e5 100644 (file)
@@ -171,5 +171,5 @@ const struct export_operations nfs_export_ops = {
        .encode_fh = nfs_encode_fh,
        .fh_to_dentry = nfs_fh_to_dentry,
        .get_parent = nfs_get_parent,
-       .flags = EXPORT_OP_NOWCC,
+       .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK,
 };
index 21e404e7cb68c718c20f67f76714a26f14f1d4d0..81e7bb12aca69435a3563677599a8c31f224a015 100644 (file)
@@ -408,6 +408,12 @@ static int check_export(struct inode *inode, int *flags, unsigned char *uuid)
                return -EINVAL;
        }
 
+       if (inode->i_sb->s_export_op->flags & EXPORT_OP_NOSUBTREECHK &&
+           !(*flags & NFSEXP_NOSUBTREECHECK)) {
+               dprintk("%s: %s does not support subtree checking!\n",
+                       __func__, inode->i_sb->s_type->name);
+               return -EINVAL;
+       }
        return 0;
 
 }
index e7de0103a32e88058d631b453f1e71de7be4799c..2fcbab0f6b612fb5f672e25d39a1ced99701075f 100644 (file)
@@ -214,6 +214,7 @@ struct export_operations {
        int (*commit_blocks)(struct inode *inode, struct iomap *iomaps,
                             int nr_iomaps, struct iattr *iattr);
 #define        EXPORT_OP_NOWCC         (0x1)   /* Don't collect wcc data for NFSv3 replies */
+#define        EXPORT_OP_NOSUBTREECHK  (0x2)   /* Subtree checking is not supported! */
        unsigned long   flags;
 };