rpms/kernel/devel linux-2.6-nfsd4-proots.patch, NONE, 1.1 kernel.spec, 1.1611, 1.1612

Steve Dickson steved at fedoraproject.org
Wed Jul 8 13:27:36 UTC 2009


Author: steved

Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv27785

Modified Files:
	kernel.spec 
Added Files:
	linux-2.6-nfsd4-proots.patch 
Log Message:
- Added NFSD v4 dynamic pseudo root patch which allows
  NFS v3 exports to be mounted by v4 clients.


linux-2.6-nfsd4-proots.patch:

--- NEW FILE linux-2.6-nfsd4-proots.patch ---
diff -up linux-2.6.30.noarch/fs/nfsd/export.c.save linux-2.6.30.noarch/fs/nfsd/export.c
--- linux-2.6.30.noarch/fs/nfsd/export.c.save	2009-07-02 11:34:38.000000000 -0400
+++ linux-2.6.30.noarch/fs/nfsd/export.c	2009-07-02 11:35:44.000000000 -0400
@@ -104,6 +104,7 @@ static int expkey_parse(struct cache_det
 	if (mesg[mlen-1] != '\n')
 		return -EINVAL;
 	mesg[mlen-1] = 0;
+	dprintk("expkey_parse: '%s'\n", mesg);
 
 	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 	err = -ENOMEM;
@@ -181,6 +182,8 @@ static int expkey_parse(struct cache_det
 	if (dom)
 		auth_domain_put(dom);
 	kfree(buf);
+	if (err)
+		dprintk("expkey_parse: err %d\n", err);
 	return err;
 }
 
@@ -351,7 +354,10 @@ static void svc_export_request(struct ca
 		(*bpp)[0] = '\n';
 		return;
 	}
+
 	qword_add(bpp, blen, pth);
+	dprintk("svc_export_request: pth %s\n", pth);
+
 	(*bpp)[-1] = '\n';
 }
 
@@ -500,6 +506,7 @@ static int svc_export_parse(struct cache
 	if (mesg[mlen-1] != '\n')
 		return -EINVAL;
 	mesg[mlen-1] = 0;
+	dprintk("svc_export_parse: '%s'\n", mesg);
 
 	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 	if (!buf)
@@ -619,6 +626,8 @@ out1:
 	auth_domain_put(dom);
 out:
 	kfree(buf);
+	if (err)
+		dprintk("svc_export_parse: err %d\n", err);
 	return err;
 }
 
@@ -1413,6 +1422,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 +1503,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.30.noarch/fs/nfsd/nfs4xdr.c.save linux-2.6.30.noarch/fs/nfsd/nfs4xdr.c
--- linux-2.6.30.noarch/fs/nfsd/nfs4xdr.c.save	2009-07-02 11:34:38.000000000 -0400
+++ linux-2.6.30.noarch/fs/nfsd/nfs4xdr.c	2009-07-02 11:35:31.000000000 -0400
@@ -2176,28 +2176,62 @@ static inline int attributes_need_mount(
 	return 0;
 }
 
-static __be32
-nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
-		const char *name, int namlen, __be32 *p, int *buflen)
+struct dentry *
+nfsd_check_export(struct nfsd4_readdir *cd, const char *name, int namlen)
 {
 	struct svc_export *exp = cd->rd_fhp->fh_export;
 	struct dentry *dentry;
-	__be32 nfserr;
-	int ignore_crossmnt = 0;
+	int err;
 
 	dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
 	if (IS_ERR(dentry))
-		return nfserrno(PTR_ERR(dentry));
+		return dentry;
 	if (!dentry->d_inode) {
-		/*
-		 * nfsd_buffered_readdir drops the i_mutex between
-		 * readdir and calling this callback, leaving a window
-		 * where this directory entry could have gone away.
-		 */
 		dput(dentry);
-		return nfserr_noent;
+		return ERR_PTR(-ENOENT);
+	}
+	
+	/*
+	 * Check to see if this dentry is part 
+	 * of the psuedo root
+	 */
+	if ((exp->ex_flags & NFSEXP_V4ROOT) == 0)
+		return dentry;
+
+	/*
+	 * Only exported directories are visable
+	 * on psuedo exports
+	 */
+	if (!S_ISDIR(dentry->d_inode->i_mode)) {
+		dput(dentry);
+		return ERR_PTR(-ENOENT);
 	}
 
+	/*
+	 * Make the upcall to see if this directory
+	 * is exported.
+	 */
+	exp_get(exp);
+	err = nfsd_export_lookup(cd->rd_rqstp, dentry, exp);
+	if (err) {
+		exp_put(exp);
+		dput(dentry);
+		return ERR_PTR(err);
+	}
+	exp_put(exp);
+
+	return dentry;
+}
+
+static __be32
+nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
+		struct dentry *dentry, __be32 *p, int *buflen)
+{
+	struct svc_export *exp = cd->rd_fhp->fh_export;
+	__be32 nfserr;
+	int ignore_crossmnt = 0;
+	int err, v4root = (exp->ex_flags & NFSEXP_V4ROOT);
+
 	exp_get(exp);
 	/*
 	 * In the case of a mountpoint, the client may be asking for
@@ -2208,18 +2242,29 @@ nfsd4_encode_dirent_fattr(struct nfsd4_r
 	 */
 	if (d_mountpoint(dentry) && !attributes_need_mount(cd->rd_bmval))
 		ignore_crossmnt = 1;
-	else if (d_mountpoint(dentry)) {
-		int err;
-
+	else if (d_mountpoint(dentry) || v4root) {
+		/*
+		 * Make sure the dentry is viewable on the psuedo export
+		 */
+		v4root = (dentry->d_inode && v4root);
+		if (v4root) {
+			err = nfsd_export_lookup(cd->rd_rqstp, dentry, exp);
+			if (err) {
+				nfserr = nfserrno(err);
+				goto out_put;
+			}
+		}
 		/*
 		 * Why the heck aren't we just using nfsd_lookup??
 		 * Different "."/".." handling?  Something else?
 		 * At least, add a comment here to explain....
 		 */
-		err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
-		if (err) {
-			nfserr = nfserrno(err);
-			goto out_put;
+		if (d_mountpoint(dentry) || v4root) {
+			err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
+			if (err) {
+				nfserr = nfserrno(err);
+				goto out_put;
+			}
 		}
 		nfserr = check_nfsd_access(exp, cd->rd_rqstp);
 		if (nfserr)
@@ -2258,6 +2303,7 @@ nfsd4_encode_dirent(void *ccdv, const ch
 	struct readdir_cd *ccd = ccdv;
 	struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
 	int buflen;
+	struct dentry *dentry;
 	__be32 *p = cd->buffer;
 	__be32 *cookiep;
 	__be32 nfserr = nfserr_toosmall;
@@ -2268,19 +2314,40 @@ nfsd4_encode_dirent(void *ccdv, const ch
 		return 0;
 	}
 
+	/*
+	 * Do the lookup and make sure the dentry is 
+	 * visible on the exported directory
+	 */
+	dentry = nfsd_check_export(cd, name, namlen);
+	if (IS_ERR(dentry)) {
+		if (PTR_ERR(dentry) == -ENOENT) {
+			cd->common.err = nfs_ok;
+			return 0;
+		}
+		cd->common.err = nfserrno(PTR_ERR(dentry));
+		return -EINVAL;
+	}
+ 
 	if (cd->offset)
 		xdr_encode_hyper(cd->offset, (u64) offset);
 
 	buflen = cd->buflen - 4 - XDR_QUADLEN(namlen);
-	if (buflen < 0)
+	if (buflen < 0) {
+		dput(dentry);
 		goto fail;
+	}
 
 	*p++ = xdr_one;                             /* mark entry present */
 	cookiep = p;
 	p = xdr_encode_hyper(p, NFS_OFFSET_MAX);    /* offset of next entry */
 	p = xdr_encode_array(p, name, namlen);      /* name length & name */
 
-	nfserr = nfsd4_encode_dirent_fattr(cd, name, namlen, p, &buflen);
+	/*
+	 * Note: the dput() on the dentry is done in 
+	 * nfsd4_encode_dirent_fattr() since the dentry can
+	 * change when crossing a mount point.
+	 */
+	nfserr = nfsd4_encode_dirent_fattr(cd, dentry, p, &buflen);
 	switch (nfserr) {
 	case nfs_ok:
 		p += buflen;
diff -up linux-2.6.30.noarch/fs/nfsd/nfsfh.c.save linux-2.6.30.noarch/fs/nfsd/nfsfh.c
--- linux-2.6.30.noarch/fs/nfsd/nfsfh.c.save	2009-07-02 11:34:38.000000000 -0400
+++ linux-2.6.30.noarch/fs/nfsd/nfsfh.c	2009-07-02 11:35:48.000000000 -0400
@@ -109,6 +109,34 @@ 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)
+{
+	int error;
+
+	/*
+	 * Only interested in pseudo roots
+	 */
+	if (!(exp->ex_flags & NFSEXP_V4ROOT))
+		return nfs_ok;
+
+	/*
+	 * Only directories should be on the pseudo root
+	 */
+	if (unlikely(!S_ISDIR(dentry->d_inode->i_mode)))
+		return nfserr_stale;
+	/*
+	 * Check non-root directories to make sure
+	 * they are truly exported
+	 */
+	if (unlikely(dentry->d_name.len > 1)) {
+		error = nfsd_export_lookup(rqstp, dentry, exp);
+		return nfserrno(error);
+	}
+
+	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
@@ -315,6 +343,14 @@ fh_verify(struct svc_rqst *rqstp, struct
 		error = nfsd_setuser_and_check_port(rqstp, exp);
 		if (error)
 			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);
diff -up linux-2.6.30.noarch/fs/nfsd/vfs.c.save linux-2.6.30.noarch/fs/nfsd/vfs.c
--- linux-2.6.30.noarch/fs/nfsd/vfs.c.save	2009-07-02 11:34:38.000000000 -0400
+++ linux-2.6.30.noarch/fs/nfsd/vfs.c	2009-07-02 11:35:39.000000000 -0400
@@ -89,6 +89,12 @@ struct raparm_hbucket {
 #define RAPARM_HASH_MASK	(RAPARM_HASH_SIZE-1)
 static struct raparm_hbucket	raparm_hash[RAPARM_HASH_SIZE];
 
+static inline int
+nfsd_v4client(struct svc_rqst *rq)
+{
+    return((rq->rq_prog == NFS_PROGRAM) && (rq->rq_vers == 4));
+}
+
 /* 
  * Called from nfsd_lookup and encode_dirent. Check if we have crossed 
  * a mount point.
@@ -115,7 +121,8 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, s
 		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 +141,55 @@ out:
 	return err;
 }
 
+/*
+ * Lookup the export the dentry is on. To be
+ * viewable on an pseudo export, the dentry
+ * has to be an exported directory. 
+ */
+int
+nfsd_export_lookup(struct svc_rqst *rqstp, struct dentry *dentry,
+	struct svc_export *exp)
+{
+	struct svc_export *exp2 = NULL;
+	struct path path;
+	int err = 0;
+
+	if ((exp->ex_flags & NFSEXP_V4ROOT) == 0)
+		return 0;
+
+	/*
+	 * Make sure the export is the parent of the dentry
+	 */
+	if (dentry->d_parent != exp->ex_path.dentry)
+		return 0;
+
+	/*
+	 * Only directories are seen on psuedo exports
+	 */
+	if (!S_ISDIR(dentry->d_inode->i_mode))
+		return -ENOENT;
+
+	/*
+	 * Make the upcall 
+	 */
+	path.mnt = mntget(exp->ex_path.mnt);
+	path.dentry = dget(dentry);
+	while (d_mountpoint(path.dentry) && follow_down(&path));
+
+	exp2 = rqst_exp_get_by_name(rqstp, &path);
+	if (IS_ERR(exp2))
+		err = PTR_ERR(exp2);
+	else  {
+		/*
+		 * The export exist so allow the access
+		 */
+		exp_put(exp2);
+	}
+
+	dput(path.dentry);
+	mntput(path.mnt);
+	return err;
+}
 __be32
 nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		   const char *name, unsigned int len,
@@ -143,7 +199,7 @@ nfsd_lookup_dentry(struct svc_rqst *rqst
 	struct dentry		*dparent;
 	struct dentry		*dentry;
 	__be32			err;
-	int			host_err;
+	int			host_err, v4root;
 
 	dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);
 
@@ -155,6 +211,7 @@ nfsd_lookup_dentry(struct svc_rqst *rqst
 	dparent = fhp->fh_dentry;
 	exp  = fhp->fh_export;
 	exp_get(exp);
+	v4root = (exp->ex_flags & NFSEXP_V4ROOT);
 
 	/* Lookup the name, but don't follow links */
 	if (isdotent(name, len)) {
@@ -199,9 +256,21 @@ nfsd_lookup_dentry(struct svc_rqst *rqst
 		if (IS_ERR(dentry))
 			goto out_nfserr;
 		/*
+		 * The export is a pseudo one, make sure the
+		 * dentry is accessible 
+		 */
+		v4root = (dentry->d_inode && v4root);
+		if (v4root) {
+			host_err = nfsd_export_lookup(rqstp, dentry, exp);
+			if (host_err) {
+				dput(dentry);
+				goto out_nfserr;
+			}
+		}
+		/*
 		 * check if we have crossed a mount point ...
 		 */
-		if (d_mountpoint(dentry)) {
+		if (d_mountpoint(dentry) || v4root) {
 			if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
 				dput(dentry);
 				goto out_nfserr;
diff -up linux-2.6.30.noarch/include/linux/nfsd/export.h.save linux-2.6.30.noarch/include/linux/nfsd/export.h
--- linux-2.6.30.noarch/include/linux/nfsd/export.h.save	2009-07-02 11:34:38.000000000 -0400
+++ linux-2.6.30.noarch/include/linux/nfsd/export.h	2009-07-02 11:35:22.000000000 -0400
@@ -39,7 +39,8 @@
 #define NFSEXP_FSID		0x2000
 #define	NFSEXP_CROSSMOUNT	0x4000
 #define	NFSEXP_NOACL		0x8000	/* reserved for possible ACL related use */
-#define NFSEXP_ALLFLAGS		0xFE3F
+#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.30.noarch/include/linux/nfsd/nfsd.h.save linux-2.6.30.noarch/include/linux/nfsd/nfsd.h
--- linux-2.6.30.noarch/include/linux/nfsd/nfsd.h.save	2009-07-02 11:34:38.000000000 -0400
+++ linux-2.6.30.noarch/include/linux/nfsd/nfsd.h	2009-07-02 11:35:27.000000000 -0400
@@ -76,6 +76,8 @@ int		nfsd_racache_init(int);
 void		nfsd_racache_shutdown(void);
 int		nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
 		                struct svc_export **expp);
+int		nfsd_export_lookup(struct svc_rqst *rqstp, struct dentry *dpp,
+		                struct svc_export *exp);
 __be32		nfsd_lookup(struct svc_rqst *, struct svc_fh *,
 				const char *, unsigned int, struct svc_fh *);
 __be32		 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,


Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel.spec,v
retrieving revision 1.1611
retrieving revision 1.1612
diff -u -p -r1.1611 -r1.1612
--- kernel.spec	8 Jul 2009 02:13:19 -0000	1.1611
+++ kernel.spec	8 Jul 2009 13:27:06 -0000	1.1612
@@ -677,6 +677,9 @@ Patch2903: linux-2.6-revert-dvb-net-kabi
 # fs fixes
 Patch3000: linux-2.6-btrfs-experimental-branch.patch
 
+# NFSv4
+Patch3050: linux-2.6-nfsd4-proots.patch
+
 #snmp fixes
 Patch10000: linux-2.6-missing-rfc2465-stats.patch
 
@@ -1137,6 +1140,9 @@ ApplyPatch linux-2.6-execshield.patch
 # btrfs
 #ApplyPatch linux-2.6-btrfs-experimental-branch.patch
 
+# NFSv4
+ApplyPatch linux-2.6-nfsd4-proots.patch
+
 # USB
 
 # ACPI
@@ -1843,6 +1849,10 @@ fi
 # and build.
 
 %changelog
+* Wed Jul 08 2009 Steve Dickson <steved at redhat.com>
+- Added NFSD v4 dynamic pseudo root patch which allows
+  NFS v3 exports to be mounted by v4 clients.
+
 * Tue Jul 07 2009 Jarod Wilson <jarod at redhat.com>
 - See if we can't make lirc_streamzap behave better... (#508952)
 




More information about the fedora-extras-commits mailing list