linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* nfs-utils crossmnt bugfix, and cleanup
@ 2011-06-14 14:58 J. Bruce Fields
  2011-06-14 14:58 ` [PATCH 1/4] mountd: prefer explicit subexports over crossmnt parents J. Bruce Fields
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: J. Bruce Fields @ 2011-06-14 14:58 UTC (permalink / raw)
  To: Steve Dickson; +Cc: linux-nfs

We've long had a bug with crossmnt handling which could cause a parent's
export options to override those of a child in some cases.

While I was there, I also did some cleanup, mainly of nfsd_fh().  It was
long and complicated, now it's short and complicated.  We could probably
simplify the logic with a little more work.

--b.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/4] mountd: prefer explicit subexports over crossmnt parents
  2011-06-14 14:58 nfs-utils crossmnt bugfix, and cleanup J. Bruce Fields
@ 2011-06-14 14:58 ` J. Bruce Fields
  2011-06-14 14:58 ` [PATCH 2/4] mountd: gather fsid information into one struct J. Bruce Fields
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: J. Bruce Fields @ 2011-06-14 14:58 UTC (permalink / raw)
  To: Steve Dickson; +Cc: linux-nfs, J. Bruce Fields

If a parent is exported with crossmnt, and if a child is also explicitly
exported, then both exports could potentially produce matches in this
loop; that isn't a bug.

Instead of warning and ignoring the second match we find, we should
instead prefer whichever export is deeper in the tree, so that
children's options can override those of their parents.

Reported-by: Olga Kornievskaia <aglo@citi.umich.edu>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
 utils/mountd/cache.c |   18 +++++++++++++++---
 1 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
index 68cccdf..c3dee13 100644
--- a/utils/mountd/cache.c
+++ b/utils/mountd/cache.c
@@ -341,6 +341,17 @@ static char *next_mnt(void **v, char *p)
 	return me->mnt_dir;
 }
 
+/* True iff e1 is a child of e2 and e2 has crossmnt set: */
+static bool subexport(struct exportent *e1, struct exportent *e2)
+{
+	char *p1 = e1->e_path, *p2 = e2->e_path;
+	int l2 = strlen(p2);
+
+	return e2->e_flags & NFSEXP_CROSSMOUNT
+	       && strncmp(p1, p2, l2) == 0
+	       && p1[l2] == '/';
+}
+
 static void nfsd_fh(FILE *f)
 {
 	/* request are:
@@ -550,13 +561,14 @@ static void nfsd_fh(FILE *f)
 				if (!client_check(exp->m_client, ai))
 					continue;
 			}
-			/* It's a match !! */
-			if (!found) {
+			if (!found || subexport(&exp->m_export, found)) {
 				found = &exp->m_export;
+				free(found_path);
 				found_path = strdup(path);
 				if (found_path == NULL)
 					goto out;
-			} else if (strcmp(found->e_path, exp->m_export.e_path)!= 0)
+			} else if (strcmp(found->e_path, exp->m_export.e_path)
+				   && !subexport(found, &exp->m_export))
 			{
 				xlog(L_WARNING, "%s and %s have same filehandle for %s, using first",
 				     found_path, path, dom);
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/4] mountd: gather fsid information into one struct
  2011-06-14 14:58 nfs-utils crossmnt bugfix, and cleanup J. Bruce Fields
  2011-06-14 14:58 ` [PATCH 1/4] mountd: prefer explicit subexports over crossmnt parents J. Bruce Fields
@ 2011-06-14 14:58 ` J. Bruce Fields
  2011-06-14 14:58 ` [PATCH 3/4] mountd: move fsidtype-specific code to helpers J. Bruce Fields
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: J. Bruce Fields @ 2011-06-14 14:58 UTC (permalink / raw)
  To: Steve Dickson; +Cc: linux-nfs, J. Bruce Fields

A large part of nfsd_fh() is concerned with extracting
fsid-type-specific information from the fsid, then matching that
information with information from the export list and the filesystem.

Moving all that information into one struct will allow some further
simplifications.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
 utils/mountd/cache.c |   79 ++++++++++++++++++++++++++++---------------------
 1 files changed, 45 insertions(+), 34 deletions(-)

diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
index c3dee13..897d61d 100644
--- a/utils/mountd/cache.c
+++ b/utils/mountd/cache.c
@@ -352,6 +352,18 @@ static bool subexport(struct exportent *e1, struct exportent *e2)
 	       && p1[l2] == '/';
 }
 
+struct parsed_fsid {
+	int fsidtype;
+	/* We could use a union for this, but it would be more
+	 * complicated; why bother? */
+	unsigned int inode;
+	unsigned int minor;
+	unsigned int major;
+	unsigned int fsidnum;
+	int uuidlen;
+	char *fhuuid;
+};
+
 static void nfsd_fh(FILE *f)
 {
 	/* request are:
@@ -363,19 +375,16 @@ static void nfsd_fh(FILE *f)
 	char *dom;
 	int fsidtype;
 	int fsidlen;
-	unsigned int dev, major=0, minor=0;
-	unsigned int inode=0;
 	unsigned long long inode64;
-	unsigned int fsidnum=0;
+	unsigned int dev;
 	char fsid[32];
+	struct parsed_fsid parsed;
 	struct exportent *found = NULL;
 	struct addrinfo *ai = NULL;
 	char *found_path = NULL;
 	nfs_export *exp;
 	int i;
 	int dev_missing = 0;
-	int uuidlen = 0;
-	char *fhuuid = NULL;
 
 	if (readline(fileno(f), &lbuf, &lbuflen) != 1)
 		return;
@@ -400,15 +409,15 @@ static void nfsd_fh(FILE *f)
 		if (fsidlen != 8)
 			goto out;
 		memcpy(&dev, fsid, 4);
-		memcpy(&inode, fsid+4, 4);
-		major = ntohl(dev)>>16;
-		minor = ntohl(dev) & 0xFFFF;
+		memcpy(&parsed.inode, fsid+4, 4);
+		parsed.major = ntohl(dev)>>16;
+		parsed.minor = ntohl(dev) & 0xFFFF;
 		break;
 
 	case FSID_NUM: /* 4 bytes - fsid */
 		if (fsidlen != 4)
 			goto out;
-		memcpy(&fsidnum, fsid, 4);
+		memcpy(&parsed.fsidnum, fsid, 4);
 		break;
 
 	case FSID_MAJOR_MINOR: /* 12 bytes: 4 major, 4 minor, 4 inode 
@@ -417,9 +426,11 @@ static void nfsd_fh(FILE *f)
 		 */
 		if (fsidlen != 12)
 			goto out;
-		memcpy(&dev, fsid, 4); major = ntohl(dev);
-		memcpy(&dev, fsid+4, 4); minor = ntohl(dev);
-		memcpy(&inode, fsid+8, 4);
+		memcpy(&dev, fsid, 4);
+		parsed.major = ntohl(dev);
+		memcpy(&dev, fsid+4, 4);
+		parsed.minor = ntohl(dev);
+		memcpy(&parsed.inode, fsid+8, 4);
 		break;
 
 	case FSID_ENCODE_DEV: /* 8 bytes: 4 byte packed device number, 4 inode */
@@ -429,37 +440,37 @@ static void nfsd_fh(FILE *f)
 		if (fsidlen != 8)
 			goto out;
 		memcpy(&dev, fsid, 4);
-		memcpy(&inode, fsid+4, 4);
-		major = (dev & 0xfff00) >> 8;
-		minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
+		memcpy(&parsed.inode, fsid+4, 4);
+		parsed.major = (dev & 0xfff00) >> 8;
+		parsed.minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
 		break;
 
 	case FSID_UUID4_INUM: /* 4 byte inode number and 4 byte uuid */
 		if (fsidlen != 8)
 			goto out;
-		memcpy(&inode, fsid, 4);
-		uuidlen = 4;
-		fhuuid = fsid+4;
+		memcpy(&parsed.inode, fsid, 4);
+		parsed.uuidlen = 4;
+		parsed.fhuuid = fsid+4;
 		break;
 	case FSID_UUID8: /* 8 byte uuid */
 		if (fsidlen != 8)
 			goto out;
-		uuidlen = 8;
-		fhuuid = fsid;
+		parsed.uuidlen = 8;
+		parsed.fhuuid = fsid;
 		break;
 	case FSID_UUID16: /* 16 byte uuid */
 		if (fsidlen != 16)
 			goto out;
-		uuidlen = 16;
-		fhuuid = fsid;
+		parsed.uuidlen = 16;
+		parsed.fhuuid = fsid;
 		break;
 	case FSID_UUID16_INUM: /* 8 byte inode number and 16 byte uuid */
 		if (fsidlen != 24)
 			goto out;
 		memcpy(&inode64, fsid, 8);
-		inode = inode64;
-		uuidlen = 16;
-		fhuuid = fsid+8;
+		parsed.inode = inode64;
+		parsed.uuidlen = 16;
+		parsed.fhuuid = fsid+8;
 		break;
 	}
 
@@ -514,20 +525,20 @@ static void nfsd_fh(FILE *f)
 			case FSID_DEV:
 			case FSID_MAJOR_MINOR:
 			case FSID_ENCODE_DEV:
-				if (stb.st_ino != inode)
+				if (stb.st_ino != parsed.inode)
 					continue;
-				if (major != major(stb.st_dev) ||
-				    minor != minor(stb.st_dev))
+				if (parsed.major != major(stb.st_dev) ||
+				    parsed.minor != minor(stb.st_dev))
 					continue;
 				break;
 			case FSID_NUM:
 				if (((exp->m_export.e_flags & NFSEXP_FSID) == 0 ||
-				     exp->m_export.e_fsid != fsidnum))
+				     exp->m_export.e_fsid != parsed.fsidnum))
 					continue;
 				break;
 			case FSID_UUID4_INUM:
 			case FSID_UUID16_INUM:
-				if (stb.st_ino != inode)
+				if (stb.st_ino != parsed.inode)
 					continue;
 				goto check_uuid;
 			case FSID_UUID8:
@@ -537,15 +548,15 @@ static void nfsd_fh(FILE *f)
 			check_uuid:
 				if (exp->m_export.e_uuid)
 					get_uuid(exp->m_export.e_uuid,
-						 uuidlen, u);
+						 parsed.uuidlen, u);
 				else
 					for (type = 0;
-					     uuid_by_path(path, type, uuidlen, u);
+					     uuid_by_path(path, type, parsed.uuidlen, u);
 					     type++)
-						if (memcmp(u, fhuuid, uuidlen) == 0)
+						if (memcmp(u, parsed.fhuuid, parsed.uuidlen) == 0)
 							break;
 
-				if (memcmp(u, fhuuid, uuidlen) != 0)
+				if (memcmp(u, parsed.fhuuid, parsed.uuidlen) != 0)
 					continue;
 				break;
 			}
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/4] mountd: move fsidtype-specific code to helpers
  2011-06-14 14:58 nfs-utils crossmnt bugfix, and cleanup J. Bruce Fields
  2011-06-14 14:58 ` [PATCH 1/4] mountd: prefer explicit subexports over crossmnt parents J. Bruce Fields
  2011-06-14 14:58 ` [PATCH 2/4] mountd: gather fsid information into one struct J. Bruce Fields
@ 2011-06-14 14:58 ` J. Bruce Fields
  2011-06-14 14:58 ` [PATCH 4/4] mountd: don't automatically add subexports to kernel cache J. Bruce Fields
  2011-06-18 13:27 ` nfs-utils crossmnt bugfix, and cleanup Steve Dickson
  4 siblings, 0 replies; 10+ messages in thread
From: J. Bruce Fields @ 2011-06-14 14:58 UTC (permalink / raw)
  To: Steve Dickson; +Cc: linux-nfs, J. Bruce Fields

Now we can move these big switch statements into helper functions.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
 utils/mountd/cache.c |  240 +++++++++++++++++++++++++++-----------------------
 1 files changed, 129 insertions(+), 111 deletions(-)

diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
index 897d61d..d2ae4563 100644
--- a/utils/mountd/cache.c
+++ b/utils/mountd/cache.c
@@ -364,60 +364,26 @@ struct parsed_fsid {
 	char *fhuuid;
 };
 
-static void nfsd_fh(FILE *f)
+int parse_fsid(int fsidtype, int fsidlen, char *fsid, struct parsed_fsid *parsed)
 {
-	/* request are:
-	 *  domain fsidtype fsid
-	 * interpret fsid, find export point and options, and write:
-	 *  domain fsidtype fsid expiry path
-	 */
-	char *cp;
-	char *dom;
-	int fsidtype;
-	int fsidlen;
-	unsigned long long inode64;
 	unsigned int dev;
-	char fsid[32];
-	struct parsed_fsid parsed;
-	struct exportent *found = NULL;
-	struct addrinfo *ai = NULL;
-	char *found_path = NULL;
-	nfs_export *exp;
-	int i;
-	int dev_missing = 0;
-
-	if (readline(fileno(f), &lbuf, &lbuflen) != 1)
-		return;
-
-	xlog(D_CALL, "nfsd_fh: inbuf '%s'", lbuf);
+	unsigned long long inode64;
 
-	cp = lbuf;
-	
-	dom = malloc(strlen(cp));
-	if (dom == NULL)
-		return;
-	if (qword_get(&cp, dom, strlen(cp)) <= 0)
-		goto out;
-	if (qword_get_int(&cp, &fsidtype) != 0)
-		goto out;
-	if (fsidtype < 0 || fsidtype > 7)
-		goto out; /* unknown type */
-	if ((fsidlen = qword_get(&cp, fsid, 32)) <= 0)
-		goto out;
+	parsed->fsidtype = fsidtype;
 	switch(fsidtype) {
 	case FSID_DEV: /* 4 bytes: 2 major, 2 minor, 4 inode */
 		if (fsidlen != 8)
-			goto out;
+			return -1;
 		memcpy(&dev, fsid, 4);
-		memcpy(&parsed.inode, fsid+4, 4);
-		parsed.major = ntohl(dev)>>16;
-		parsed.minor = ntohl(dev) & 0xFFFF;
+		memcpy(&parsed->inode, fsid+4, 4);
+		parsed->major = ntohl(dev)>>16;
+		parsed->minor = ntohl(dev) & 0xFFFF;
 		break;
 
 	case FSID_NUM: /* 4 bytes - fsid */
 		if (fsidlen != 4)
-			goto out;
-		memcpy(&parsed.fsidnum, fsid, 4);
+			return -1;
+		memcpy(&parsed->fsidnum, fsid, 4);
 		break;
 
 	case FSID_MAJOR_MINOR: /* 12 bytes: 4 major, 4 minor, 4 inode 
@@ -425,12 +391,12 @@ static void nfsd_fh(FILE *f)
 		 * an historical accident
 		 */
 		if (fsidlen != 12)
-			goto out;
+			return -1;
 		memcpy(&dev, fsid, 4);
-		parsed.major = ntohl(dev);
+		parsed->major = ntohl(dev);
 		memcpy(&dev, fsid+4, 4);
-		parsed.minor = ntohl(dev);
-		memcpy(&parsed.inode, fsid+8, 4);
+		parsed->minor = ntohl(dev);
+		memcpy(&parsed->inode, fsid+8, 4);
 		break;
 
 	case FSID_ENCODE_DEV: /* 8 bytes: 4 byte packed device number, 4 inode */
@@ -438,41 +404,137 @@ static void nfsd_fh(FILE *f)
 		 * no-one outside this host has any business interpreting it
 		 */
 		if (fsidlen != 8)
-			goto out;
+			return -1;
 		memcpy(&dev, fsid, 4);
-		memcpy(&parsed.inode, fsid+4, 4);
-		parsed.major = (dev & 0xfff00) >> 8;
-		parsed.minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
+		memcpy(&parsed->inode, fsid+4, 4);
+		parsed->major = (dev & 0xfff00) >> 8;
+		parsed->minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
 		break;
 
 	case FSID_UUID4_INUM: /* 4 byte inode number and 4 byte uuid */
 		if (fsidlen != 8)
-			goto out;
-		memcpy(&parsed.inode, fsid, 4);
-		parsed.uuidlen = 4;
-		parsed.fhuuid = fsid+4;
+			return -1;
+		memcpy(&parsed->inode, fsid, 4);
+		parsed->uuidlen = 4;
+		parsed->fhuuid = fsid+4;
 		break;
 	case FSID_UUID8: /* 8 byte uuid */
 		if (fsidlen != 8)
-			goto out;
-		parsed.uuidlen = 8;
-		parsed.fhuuid = fsid;
+			return -1;
+		parsed->uuidlen = 8;
+		parsed->fhuuid = fsid;
 		break;
 	case FSID_UUID16: /* 16 byte uuid */
 		if (fsidlen != 16)
-			goto out;
-		parsed.uuidlen = 16;
-		parsed.fhuuid = fsid;
+			return -1;
+		parsed->uuidlen = 16;
+		parsed->fhuuid = fsid;
 		break;
 	case FSID_UUID16_INUM: /* 8 byte inode number and 16 byte uuid */
 		if (fsidlen != 24)
-			goto out;
+			return -1;
 		memcpy(&inode64, fsid, 8);
-		parsed.inode = inode64;
-		parsed.uuidlen = 16;
-		parsed.fhuuid = fsid+8;
+		parsed->inode = inode64;
+		parsed->uuidlen = 16;
+		parsed->fhuuid = fsid+8;
 		break;
 	}
+	return 0;
+}
+
+static bool match_fsid(struct parsed_fsid *parsed, nfs_export *exp, char *path)
+{
+	struct stat stb;
+	int type;
+	char u[16];
+
+	if (stat(path, &stb) != 0)
+		return false;
+	if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode))
+		return false;
+
+	switch (parsed->fsidtype) {
+	case FSID_DEV:
+	case FSID_MAJOR_MINOR:
+	case FSID_ENCODE_DEV:
+		if (stb.st_ino != parsed->inode)
+			return false;
+		if (parsed->major != major(stb.st_dev) ||
+		    parsed->minor != minor(stb.st_dev))
+			return false;
+		return true;
+	case FSID_NUM:
+		if (((exp->m_export.e_flags & NFSEXP_FSID) == 0 ||
+		     exp->m_export.e_fsid != parsed->fsidnum))
+			return false;
+		return true;
+	case FSID_UUID4_INUM:
+	case FSID_UUID16_INUM:
+		if (stb.st_ino != parsed->inode)
+			return false;
+		goto check_uuid;
+	case FSID_UUID8:
+	case FSID_UUID16:
+		if (!is_mountpoint(path))
+			return false;
+	check_uuid:
+		if (exp->m_export.e_uuid)
+			get_uuid(exp->m_export.e_uuid, parsed->uuidlen, u);
+		else
+			for (type = 0;
+			     uuid_by_path(path, type, parsed->uuidlen, u);
+			     type++)
+				if (memcmp(u, parsed->fhuuid, parsed->uuidlen) == 0)
+					return true;
+
+		if (memcmp(u, parsed->fhuuid, parsed->uuidlen) != 0)
+			return false;
+		return true;
+	}
+	/* Well, unreachable, actually: */
+	return false;
+}
+
+static void nfsd_fh(FILE *f)
+{
+	/* request are:
+	 *  domain fsidtype fsid
+	 * interpret fsid, find export point and options, and write:
+	 *  domain fsidtype fsid expiry path
+	 */
+	char *cp;
+	char *dom;
+	int fsidtype;
+	int fsidlen;
+	char fsid[32];
+	struct parsed_fsid parsed;
+	struct exportent *found = NULL;
+	struct addrinfo *ai = NULL;
+	char *found_path = NULL;
+	nfs_export *exp;
+	int i;
+	int dev_missing = 0;
+
+	if (readline(fileno(f), &lbuf, &lbuflen) != 1)
+		return;
+
+	xlog(D_CALL, "nfsd_fh: inbuf '%s'", lbuf);
+
+	cp = lbuf;
+
+	dom = malloc(strlen(cp));
+	if (dom == NULL)
+		return;
+	if (qword_get(&cp, dom, strlen(cp)) <= 0)
+		goto out;
+	if (qword_get_int(&cp, &fsidtype) != 0)
+		goto out;
+	if (fsidtype < 0 || fsidtype > 7)
+		goto out; /* unknown type */
+	if ((fsidlen = qword_get(&cp, fsid, 32)) <= 0)
+		goto out;
+	if (parse_fsid(fsidtype, fsidlen, fsid, &parsed))
+		goto out;
 
 	auth_reload();
 
@@ -480,10 +542,7 @@ static void nfsd_fh(FILE *f)
 	for (i=0 ; i < MCL_MAXTYPES; i++) {
 		nfs_export *next_exp;
 		for (exp = exportlist[i].p_head; exp; exp = next_exp) {
-			struct stat stb;
-			char u[16];
 			char *path;
-			int type;
 
 			if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) {
 				static nfs_export *prev = NULL;
@@ -516,50 +575,9 @@ static void nfsd_fh(FILE *f)
 					   exp->m_export.e_mountpoint:
 					   exp->m_export.e_path))
 				dev_missing ++;
-			if (stat(path, &stb) != 0)
-				continue;
-			if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
+
+			if (!match_fsid(&parsed, exp, path))
 				continue;
-			}
-			switch(fsidtype){
-			case FSID_DEV:
-			case FSID_MAJOR_MINOR:
-			case FSID_ENCODE_DEV:
-				if (stb.st_ino != parsed.inode)
-					continue;
-				if (parsed.major != major(stb.st_dev) ||
-				    parsed.minor != minor(stb.st_dev))
-					continue;
-				break;
-			case FSID_NUM:
-				if (((exp->m_export.e_flags & NFSEXP_FSID) == 0 ||
-				     exp->m_export.e_fsid != parsed.fsidnum))
-					continue;
-				break;
-			case FSID_UUID4_INUM:
-			case FSID_UUID16_INUM:
-				if (stb.st_ino != parsed.inode)
-					continue;
-				goto check_uuid;
-			case FSID_UUID8:
-			case FSID_UUID16:
-				if (!is_mountpoint(path))
-					continue;
-			check_uuid:
-				if (exp->m_export.e_uuid)
-					get_uuid(exp->m_export.e_uuid,
-						 parsed.uuidlen, u);
-				else
-					for (type = 0;
-					     uuid_by_path(path, type, parsed.uuidlen, u);
-					     type++)
-						if (memcmp(u, parsed.fhuuid, parsed.uuidlen) == 0)
-							break;
-
-				if (memcmp(u, parsed.fhuuid, parsed.uuidlen) != 0)
-					continue;
-				break;
-			}
 			if (use_ipaddr) {
 				if (ai == NULL) {
 					struct addrinfo *tmp;
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/4] mountd: don't automatically add subexports to kernel cache
  2011-06-14 14:58 nfs-utils crossmnt bugfix, and cleanup J. Bruce Fields
                   ` (2 preceding siblings ...)
  2011-06-14 14:58 ` [PATCH 3/4] mountd: move fsidtype-specific code to helpers J. Bruce Fields
@ 2011-06-14 14:58 ` J. Bruce Fields
  2011-06-22 22:30   ` Steve Dickson
  2011-06-18 13:27 ` nfs-utils crossmnt bugfix, and cleanup Steve Dickson
  4 siblings, 1 reply; 10+ messages in thread
From: J. Bruce Fields @ 2011-06-14 14:58 UTC (permalink / raw)
  To: Steve Dickson; +Cc: linux-nfs, J. Bruce Fields

Given a crossmnt export and a child path, search for all mountpoints in
between and add exports for them to the kernel.

This isn't necessary; if the the kernel needs one of the subexports, it
can always ask.

It might be some sort of minor optimization to add exports preemptively.
But if so, why not just add them all?  Why this particular subset?

Given the chance to delete some code I can't justify, I'll take it.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
 utils/mountd/cache.c |   42 +-----------------------------------------
 1 files changed, 1 insertions(+), 41 deletions(-)

diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
index d2ae4563..c77eb27 100644
--- a/utils/mountd/cache.c
+++ b/utils/mountd/cache.c
@@ -945,53 +945,13 @@ static int cache_export_ent(char *domain, struct exportent *exp, char *path)
 	if (!f)
 		return -1;
 
-	err = dump_to_cache(f, domain, exp->e_path, exp);
+	err = dump_to_cache(f, domain, path, exp);
 	if (err) {
 		xlog(L_WARNING,
 		     "Cannot export %s, possibly unsupported filesystem or"
 		     " fsid= required", exp->e_path);
 	}
 
-	while (err == 0 && (exp->e_flags & NFSEXP_CROSSMOUNT) && path) {
-		/* really an 'if', but we can break out of
-		 * a 'while' more easily */
-		/* Look along 'path' for other filesystems
-		 * and export them with the same options
-		 */
-		struct stat stb;
-		size_t l = strlen(exp->e_path);
-		__dev_t dev;
-
-		if (strlen(path) <= l || path[l] != '/' ||
-		    strncmp(exp->e_path, path, l) != 0)
-			break;
-		if (stat(exp->e_path, &stb) != 0)
-			break;
-		dev = stb.st_dev;
-		while(path[l] == '/') {
-			char c;
-			/* errors for submount should fail whole filesystem */
-			int err2;
-
-			l++;
-			while (path[l] != '/' && path[l])
-				l++;
-			c = path[l];
-			path[l] = 0;
-			err2 = lstat(path, &stb);
-			path[l] = c;
-			if (err2 < 0)
-				break;
-			if (stb.st_dev == dev)
-				continue;
-			dev = stb.st_dev;
-			path[l] = 0;
-			dump_to_cache(f, domain, path, exp);
-			path[l] = c;
-		}
-		break;
-	}
-
 	fclose(f);
 	return err;
 }
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: nfs-utils crossmnt bugfix, and cleanup
  2011-06-14 14:58 nfs-utils crossmnt bugfix, and cleanup J. Bruce Fields
                   ` (3 preceding siblings ...)
  2011-06-14 14:58 ` [PATCH 4/4] mountd: don't automatically add subexports to kernel cache J. Bruce Fields
@ 2011-06-18 13:27 ` Steve Dickson
  2011-06-18 19:50   ` J. Bruce Fields
  4 siblings, 1 reply; 10+ messages in thread
From: Steve Dickson @ 2011-06-18 13:27 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: linux-nfs

Hey Bruce,

On 06/14/2011 10:58 AM, J. Bruce Fields wrote:
> We've long had a bug with crossmnt handling which could cause a parent's
> export options to override those of a child in some cases.
> 
> While I was there, I also did some cleanup, mainly of nfsd_fh().  It was
> long and complicated, now it's short and complicated.  We could probably
> simplify the logic with a little more work.
> 
> --b.
Which bug are you referring to?

steved. 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: nfs-utils crossmnt bugfix, and cleanup
  2011-06-18 13:27 ` nfs-utils crossmnt bugfix, and cleanup Steve Dickson
@ 2011-06-18 19:50   ` J. Bruce Fields
  0 siblings, 0 replies; 10+ messages in thread
From: J. Bruce Fields @ 2011-06-18 19:50 UTC (permalink / raw)
  To: Steve Dickson; +Cc: J. Bruce Fields, linux-nfs

On Sat, Jun 18, 2011 at 09:27:30AM -0400, Steve Dickson wrote:
> Hey Bruce,
> 
> On 06/14/2011 10:58 AM, J. Bruce Fields wrote:
> > We've long had a bug with crossmnt handling which could cause a parent's
> > export options to override those of a child in some cases.
> > 
> > While I was there, I also did some cleanup, mainly of nfsd_fh().  It was
> > long and complicated, now it's short and complicated.  We could probably
> > simplify the logic with a little more work.
> > 
> > --b.
> Which bug are you referring to?

Suppose /etc/exports contains:

	/foo		*(rw,crossmnt)
	/foo/bar	*(ro)

The "crossmnt" tells us to export all filesystems under /foo recursively
with the same options as /foo is exported with.  So there's a conflict:
should /foo/bar be exported ro, or rw?

The logical thing to do is to make the "ro" on the explicit export of
/foo/bar override the inherited "rw" from /foo, and in practice that's
what people have obviously expected in every case I've seen.

But we don't do that.  Actually, it's worse than that: the /foo export
wins in the nfsd_fh upcall, and the /foo/bar export wins in the
nfsd_export upcall.  So you can get inconsistent results depending on
which order things happen in.

So the first patch fixes nfsd_fh to behave like nfsd_export does, and
prefer /foo/bar.

This was most commonly a problem with people doing fsid=0 exports, so
it's less of a problem now that we have the v4root stuff, but definitely
it still needs fixing.

--b.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] mountd: don't automatically add subexports to kernel cache
  2011-06-14 14:58 ` [PATCH 4/4] mountd: don't automatically add subexports to kernel cache J. Bruce Fields
@ 2011-06-22 22:30   ` Steve Dickson
  2011-06-22 22:34     ` J. Bruce Fields
  0 siblings, 1 reply; 10+ messages in thread
From: Steve Dickson @ 2011-06-22 22:30 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: linux-nfs

Hey Bruce,

This patch breaks cross mounts... Here is my set up

/home/fs1 two different file systems:

Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/mapper/VolGroup00-HomeDirs
                      15236080   9439036   5010612  66% /home
RedHat# df /home/fs1
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/mapper/VolGroup00-FS1
                      10321208    154468   9642452   2% /home/fs1

The export is:
  /home *(rw,crossmnt,nohide,sec=sys:krb5:krb5i:krb5p)

when I mount from a f15 client
    mount -v -o v3 redhat:/home/fs1/tmp/tophat /mnt/tmp
I get:
    mount.nfs: mount(2): Stale NFS file handle

When I revert the patch, the mount works.

Unfortunately I'm going to be taking the next few days off
so I am not going be able to debug this... So I'm going to 
wait on the entire patch series until we can sort this out...

steved.

On 06/14/2011 10:58 AM, J. Bruce Fields wrote:
> Given a crossmnt export and a child path, search for all mountpoints in
> between and add exports for them to the kernel.
> 
> This isn't necessary; if the the kernel needs one of the subexports, it
> can always ask.
> 
> It might be some sort of minor optimization to add exports preemptively.
> But if so, why not just add them all?  Why this particular subset?
> 
> Given the chance to delete some code I can't justify, I'll take it.
> 
> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
> ---
>  utils/mountd/cache.c |   42 +-----------------------------------------
>  1 files changed, 1 insertions(+), 41 deletions(-)
> 
> diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
> index d2ae4563..c77eb27 100644
> --- a/utils/mountd/cache.c
> +++ b/utils/mountd/cache.c
> @@ -945,53 +945,13 @@ static int cache_export_ent(char *domain, struct exportent *exp, char *path)
>  	if (!f)
>  		return -1;
>  
> -	err = dump_to_cache(f, domain, exp->e_path, exp);
> +	err = dump_to_cache(f, domain, path, exp);
>  	if (err) {
>  		xlog(L_WARNING,
>  		     "Cannot export %s, possibly unsupported filesystem or"
>  		     " fsid= required", exp->e_path);
>  	}
>  
> -	while (err == 0 && (exp->e_flags & NFSEXP_CROSSMOUNT) && path) {
> -		/* really an 'if', but we can break out of
> -		 * a 'while' more easily */
> -		/* Look along 'path' for other filesystems
> -		 * and export them with the same options
> -		 */
> -		struct stat stb;
> -		size_t l = strlen(exp->e_path);
> -		__dev_t dev;
> -
> -		if (strlen(path) <= l || path[l] != '/' ||
> -		    strncmp(exp->e_path, path, l) != 0)
> -			break;
> -		if (stat(exp->e_path, &stb) != 0)
> -			break;
> -		dev = stb.st_dev;
> -		while(path[l] == '/') {
> -			char c;
> -			/* errors for submount should fail whole filesystem */
> -			int err2;
> -
> -			l++;
> -			while (path[l] != '/' && path[l])
> -				l++;
> -			c = path[l];
> -			path[l] = 0;
> -			err2 = lstat(path, &stb);
> -			path[l] = c;
> -			if (err2 < 0)
> -				break;
> -			if (stb.st_dev == dev)
> -				continue;
> -			dev = stb.st_dev;
> -			path[l] = 0;
> -			dump_to_cache(f, domain, path, exp);
> -			path[l] = c;
> -		}
> -		break;
> -	}
> -
>  	fclose(f);
>  	return err;
>  }

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] mountd: don't automatically add subexports to kernel cache
  2011-06-22 22:30   ` Steve Dickson
@ 2011-06-22 22:34     ` J. Bruce Fields
  2011-06-27 16:36       ` Steve Dickson
  0 siblings, 1 reply; 10+ messages in thread
From: J. Bruce Fields @ 2011-06-22 22:34 UTC (permalink / raw)
  To: Steve Dickson; +Cc: linux-nfs

On Wed, Jun 22, 2011 at 06:30:32PM -0400, Steve Dickson wrote:
> Hey Bruce,
> 
> This patch breaks cross mounts... Here is my set up
> 
> /home/fs1 two different file systems:
> 
> Filesystem           1K-blocks      Used Available Use% Mounted on
> /dev/mapper/VolGroup00-HomeDirs
>                       15236080   9439036   5010612  66% /home
> RedHat# df /home/fs1
> Filesystem           1K-blocks      Used Available Use% Mounted on
> /dev/mapper/VolGroup00-FS1
>                       10321208    154468   9642452   2% /home/fs1
> 
> The export is:
>   /home *(rw,crossmnt,nohide,sec=sys:krb5:krb5i:krb5p)
> 
> when I mount from a f15 client
>     mount -v -o v3 redhat:/home/fs1/tmp/tophat /mnt/tmp
> I get:
>     mount.nfs: mount(2): Stale NFS file handle
> 
> When I revert the patch, the mount works.

Oh, crap, I didn't check v3.  And, OK, it makes sense that v3 might need
this.

> Unfortunately I'm going to be taking the next few days off
> so I am not going be able to debug this... So I'm going to 
> wait on the entire patch series until we can sort this out...

No problem.  But if you want to apply the rest of the series and drop
just this one patch, that would be fine too.  (That's probably what will
end up being the fix anyway.)

--b.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] mountd: don't automatically add subexports to kernel cache
  2011-06-22 22:34     ` J. Bruce Fields
@ 2011-06-27 16:36       ` Steve Dickson
  0 siblings, 0 replies; 10+ messages in thread
From: Steve Dickson @ 2011-06-27 16:36 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: linux-nfs



On 06/22/2011 06:34 PM, J. Bruce Fields wrote:
> On Wed, Jun 22, 2011 at 06:30:32PM -0400, Steve Dickson wrote:
>> Hey Bruce,
>>
>> This patch breaks cross mounts... Here is my set up
>>
>> /home/fs1 two different file systems:
>>
>> Filesystem           1K-blocks      Used Available Use% Mounted on
>> /dev/mapper/VolGroup00-HomeDirs
>>                       15236080   9439036   5010612  66% /home
>> RedHat# df /home/fs1
>> Filesystem           1K-blocks      Used Available Use% Mounted on
>> /dev/mapper/VolGroup00-FS1
>>                       10321208    154468   9642452   2% /home/fs1
>>
>> The export is:
>>   /home *(rw,crossmnt,nohide,sec=sys:krb5:krb5i:krb5p)
>>
>> when I mount from a f15 client
>>     mount -v -o v3 redhat:/home/fs1/tmp/tophat /mnt/tmp
>> I get:
>>     mount.nfs: mount(2): Stale NFS file handle
>>
>> When I revert the patch, the mount works.
> 
> Oh, crap, I didn't check v3.  And, OK, it makes sense that v3 might need
> this.
> 
>> Unfortunately I'm going to be taking the next few days off
>> so I am not going be able to debug this... So I'm going to 
>> wait on the entire patch series until we can sort this out...
> 
> No problem.  But if you want to apply the rest of the series and drop
> just this one patch, that would be fine too.  (That's probably what will
> end up being the fix anyway.)
Ok... I just committed the first three patches of this series...

steved.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-06-27 16:36 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-06-14 14:58 nfs-utils crossmnt bugfix, and cleanup J. Bruce Fields
2011-06-14 14:58 ` [PATCH 1/4] mountd: prefer explicit subexports over crossmnt parents J. Bruce Fields
2011-06-14 14:58 ` [PATCH 2/4] mountd: gather fsid information into one struct J. Bruce Fields
2011-06-14 14:58 ` [PATCH 3/4] mountd: move fsidtype-specific code to helpers J. Bruce Fields
2011-06-14 14:58 ` [PATCH 4/4] mountd: don't automatically add subexports to kernel cache J. Bruce Fields
2011-06-22 22:30   ` Steve Dickson
2011-06-22 22:34     ` J. Bruce Fields
2011-06-27 16:36       ` Steve Dickson
2011-06-18 13:27 ` nfs-utils crossmnt bugfix, and cleanup Steve Dickson
2011-06-18 19:50   ` J. Bruce Fields

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).