[PATCH] Updated to F-12 NFSv4 server code...

Steve Dickson SteveD at redhat.com
Tue Dec 8 12:48:33 UTC 2009


Here is a patch that will updated the NFSv4 server code
in the F-12 kernel. This patch along with an upcoming 
nfs-utils update, fixes the a problem with v4 clients 
failing with when mounting an export that contains 
a different file system other than the root file system
(bz 538609)

The is part of the ongoing work that will allow 
existing exports to be mountable by v4 clients.
The whole pseudo root discussion... 

In the end, the patch should have no effect on existing 
NFS servers since the default protocol version is still
version 3 in F-12. But there has been a lot of people 
experimenting with v4, which is a good thing and something
I would like to promote by keeping the F-12 kernel 
up to date with the latest stable code. 

steved.


Date:   Mon Dec 7 17:23:48 2009 -0500
Author: J. Bruce Fields <bfields at citi.umich.edu>
Author: Steve Dickson <steved at redhat.com>

Update to latest pseudo root release which will
allow existing export to be mountable by v4
clients without any changes to the existing
exports. 

Signed-off-by: Steve Dickson <steved at redhat.com>

-------------------------------------------
diff -up linux-2.6.31.i686/fs/nfsd/export.c.save linux-2.6.31.i686/fs/nfsd/export.c
--- linux-2.6.31.i686/fs/nfsd/export.c.save	2009-12-07 12:13:28.000000000 -0500
+++ linux-2.6.31.i686/fs/nfsd/export.c	2009-12-07 12:15:32.000000000 -0500
@@ -362,10 +362,12 @@ static struct svc_export *svc_export_loo
 static int check_export(struct inode *inode, int flags, unsigned char *uuid)
 {
 
-	/* We currently export only dirs and regular files.
-	 * This is what umountd does.
+	/*
+	 * We currently export only dirs, regular files, and (for v4
+	 * pseudoroot) symlinks.
 	 */
 	if (!S_ISDIR(inode->i_mode) &&
+	    !S_ISLNK(inode->i_mode) &&
 	    !S_ISREG(inode->i_mode))
 		return -ENOTDIR;
 
@@ -1413,6 +1415,7 @@ static struct flags {
 	{ NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
 	{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
 	{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
+	{ NFSEXP_V4ROOT, {"v4root", ""}},
 #ifdef MSNFS
 	{ NFSEXP_MSNFS, {"msnfs", ""}},
 #endif
@@ -1493,7 +1496,7 @@ static int e_show(struct seq_file *m, vo
 	struct svc_export *exp = container_of(cp, struct svc_export, h);
 
 	if (p == SEQ_START_TOKEN) {
-		seq_puts(m, "# Version 1.1\n");
+		seq_puts(m, "# Version 1.2\n");
 		seq_puts(m, "# Path Client(Flags) # IPs\n");
 		return 0;
 	}
diff -up linux-2.6.31.i686/fs/nfsd/nfs4xdr.c.save linux-2.6.31.i686/fs/nfsd/nfs4xdr.c
--- linux-2.6.31.i686/fs/nfsd/nfs4xdr.c.save	2009-12-07 12:13:28.000000000 -0500
+++ linux-2.6.31.i686/fs/nfsd/nfs4xdr.c	2009-12-07 12:15:32.000000000 -0500
@@ -2206,11 +2206,14 @@ nfsd4_encode_dirent_fattr(struct nfsd4_r
 	 * we will not follow the cross mount and will fill the attribtutes
 	 * directly from the mountpoint dentry.
 	 */
-	if (d_mountpoint(dentry) && !attributes_need_mount(cd->rd_bmval))
-		ignore_crossmnt = 1;
-	else if (d_mountpoint(dentry)) {
+	if (nfsd_mountpoint(dentry, exp)) {
 		int err;
 
+		if (!(exp->ex_flags & NFSEXP_V4ROOT)
+				&& !attributes_need_mount(cd->rd_bmval)) {
+			ignore_crossmnt = 1;
+			goto out_encode;
+		}
 		/*
 		 * Why the heck aren't we just using nfsd_lookup??
 		 * Different "."/".." handling?  Something else?
@@ -2226,6 +2229,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_r
 			goto out_put;
 
 	}
+out_encode:
 	nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
 					cd->rd_rqstp, ignore_crossmnt);
 out_put:
diff -up linux-2.6.31.i686/fs/nfsd/nfsfh.c.save linux-2.6.31.i686/fs/nfsd/nfsfh.c
--- linux-2.6.31.i686/fs/nfsd/nfsfh.c.save	2009-12-07 12:13:28.000000000 -0500
+++ linux-2.6.31.i686/fs/nfsd/nfsfh.c	2009-12-07 12:15:32.000000000 -0500
@@ -109,6 +109,36 @@ static __be32 nfsd_setuser_and_check_por
 	return nfserrno(nfsd_setuser(rqstp, exp));
 }
 
+static inline __be32 check_pseudo_root(struct svc_rqst *rqstp,
+	struct dentry *dentry, struct svc_export *exp)
+{
+	if (!(exp->ex_flags & NFSEXP_V4ROOT))
+		return nfs_ok;
+	/*
+	 * v2/v3 clients have no need for the V4ROOT export--they use
+	 * the mount protocl instead; also, further V4ROOT checks may be
+	 * in v4-specific code, in which case v2/v3 clients could bypass
+	 * them.
+	 */
+	if (!nfsd_v4client(rqstp))
+		return nfserr_stale;
+	/*
+	 * We're exposing only the directories and symlinks that have to be
+	 * traversed on the way to real exports:
+	 */
+	if (unlikely(!S_ISDIR(dentry->d_inode->i_mode) &&
+		     !S_ISLNK(dentry->d_inode->i_mode)))
+		return nfserr_stale;
+	/*
+	 * A pseudoroot export gives permission to access only one
+	 * single directory; the kernel has to make another upcall
+	 * before granting access to anything else under it:
+	 */
+	if (unlikely(dentry != exp->ex_path.dentry))
+		return nfserr_stale;
+	return nfs_ok;
+}
+
 /*
  * Use the given filehandle to look up the corresponding export and
  * dentry.  On success, the results are used to set fh_export and
@@ -317,6 +347,13 @@ fh_verify(struct svc_rqst *rqstp, struct
 			goto out;
 	}
 
+	/*
+	 * Do some spoof checking if we are on the pseudo root
+	 */
+	error = check_pseudo_root(rqstp, dentry, exp);
+	if (error)
+		goto out;
+
 	error = nfsd_mode_check(rqstp, dentry->d_inode->i_mode, type);
 	if (error)
 		goto out;
diff -up linux-2.6.31.i686/fs/nfsd/vfs.c.save linux-2.6.31.i686/fs/nfsd/vfs.c
--- linux-2.6.31.i686/fs/nfsd/vfs.c.save	2009-12-07 12:13:28.000000000 -0500
+++ linux-2.6.31.i686/fs/nfsd/vfs.c	2009-12-07 12:22:32.000000000 -0500
@@ -110,12 +110,21 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, s
 
 	exp2 = rqst_exp_get_by_name(rqstp, &path);
 	if (IS_ERR(exp2)) {
-		if (PTR_ERR(exp2) != -ENOENT)
-			err = PTR_ERR(exp2);
+		err = PTR_ERR(exp2);
+		/*
+		 * We normally allow NFS clients to continue
+		 * "underneath" a mountpoint that is not exported.
+		 * The exception is V4ROOT, where no traversal is ever
+		 * allowed without an explicit export of the new
+		 * directory.
+		 */
+		if (err == -ENOENT && !(exp->ex_flags & NFSEXP_V4ROOT))
+			err = 0;
 		path_put(&path);
 		goto out;
 	}
-	if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
+	if (nfsd_v4client(rqstp) ||
+		(exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
 		/* successfully crossed mount point */
 		/*
 		 * This is subtle: path.dentry is *not* on path.mnt
@@ -134,6 +143,19 @@ out:
 	return err;
 }
 
+/*
+ * For nfsd purposes, we treat V4ROOT exports as though there was an
+ * export at *every* directory.
+ */
+int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp)
+{
+	if (d_mountpoint(dentry))
+		return 1;
+	if (!(exp->ex_flags & NFSEXP_V4ROOT))
+		return 0;
+	return dentry->d_inode != NULL;
+}
+
 __be32
 nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		   const char *name, unsigned int len,
@@ -201,7 +223,7 @@ nfsd_lookup_dentry(struct svc_rqst *rqst
 		/*
 		 * check if we have crossed a mount point ...
 		 */
-		if (d_mountpoint(dentry)) {
+		if (nfsd_mountpoint(dentry, exp)) {
 			if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
 				dput(dentry);
 				goto out_nfserr;
diff -up linux-2.6.31.i686/include/linux/nfsd/export.h.save linux-2.6.31.i686/include/linux/nfsd/export.h
--- linux-2.6.31.i686/include/linux/nfsd/export.h.save	2009-12-07 12:13:28.000000000 -0500
+++ linux-2.6.31.i686/include/linux/nfsd/export.h	2009-12-07 12:15:39.000000000 -0500
@@ -39,7 +39,17 @@
 #define NFSEXP_FSID		0x2000
 #define	NFSEXP_CROSSMOUNT	0x4000
 #define	NFSEXP_NOACL		0x8000	/* reserved for possible ACL related use */
-#define NFSEXP_ALLFLAGS		0xFE3F
+/*
+ * The NFSEXP_V4ROOT flag causes the kernel to give access only to NFSv4
+ * clients, and only to the single directory that is the root of the
+ * export; further lookup and readdir operations are treated as if every
+ * subdirectory was a mountpoint, and ignored if they are not themselves
+ * exported.  This is used by nfsd and mountd to construct the NFSv4
+ * pseudofilesystem, which provides access only to paths leading to each
+ * exported filesystem.
+ */
+#define	NFSEXP_V4ROOT		0x10000
+#define NFSEXP_ALLFLAGS		0x1FE3F
 
 /* The flags that may vary depending on security flavor: */
 #define NFSEXP_SECINFO_FLAGS	(NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
diff -up linux-2.6.31.i686/include/linux/nfsd/nfsd.h.save linux-2.6.31.i686/include/linux/nfsd/nfsd.h
--- linux-2.6.31.i686/include/linux/nfsd/nfsd.h.save	2009-12-07 12:13:28.000000000 -0500
+++ linux-2.6.31.i686/include/linux/nfsd/nfsd.h	2009-12-07 12:15:39.000000000 -0500
@@ -83,6 +83,7 @@ __be32		 nfsd_lookup_dentry(struct svc_r
 				struct svc_export **, struct dentry **);
 __be32		nfsd_setattr(struct svc_rqst *, struct svc_fh *,
 				struct iattr *, int, time_t);
+int nfsd_mountpoint(struct dentry *, struct svc_export *);
 #ifdef CONFIG_NFSD_V4
 __be32          nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
                     struct nfs4_acl *);
@@ -391,6 +392,10 @@ static inline u32 nfsd_suppattrs2(u32 mi
 	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
 			    : NFSD4_SUPPORTED_ATTRS_WORD2;
 }
+static inline int nfsd_v4client(struct svc_rqst *rq)
+{
+	return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4;
+}
 
 /* These will return ERR_INVAL if specified in GETATTR or READDIR. */
 #define NFSD_WRITEONLY_ATTRS_WORD1							    \





More information about the Fedora-kernel-list mailing list