public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 000 of 16] knfsd: Introduction
@ 2006-04-03  5:18 NeilBrown
  2006-04-03  5:18 ` [PATCH 001 of 16] knfsd: locks: flag NFSv4-owned locks NeilBrown
                   ` (15 more replies)
  0 siblings, 16 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:18 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel

Groan, I missed the merge-window, but that's for new features, and this
is bug fixes...

The following 16 patches fix various bugs in the nfs server, mostly
related to NFSv4, but there are a couple that are more generally
applicable (005 in particular).

They are against 2.6.16-mm2 and should be suitable for 2.6.17-rc2.

Thanks,
NeilBrown


 [PATCH 001 of 16] knfsd: locks: flag NFSv4-owned locks
 [PATCH 002 of 16] knfsd: nfsd4: Wrong error handling in nfs4acl
 [PATCH 003 of 16] knfsd: nfsd4: better nfs4acl errors
 [PATCH 004 of 16] knfsd: nfsd4: fix acl xattr length return
 [PATCH 005 of 16] knfsd: nfsd: oops exporting nonexistent directory
 [PATCH 006 of 16] knfsd: nfsd: nfsd_setuser doesn't really need to modify rqstp->rq_cred.
 [PATCH 007 of 16] knfsd: nfsd4: remove nfsd_setuser from putrootfh
 [PATCH 008 of 16] knfsd: nfsd4: fix corruption of returned data when using 64k pages
 [PATCH 009 of 16] knfsd: nfsd4: fix corruption on readdir encoding with 64k pages
 [PATCH 010 of 16] knfsd: svcrpc: gss: don't call svc_take_page unnecessarily
 [PATCH 011 of 16] knfsd: svcrpc: WARN() instead of returning an error from svc_take_page
 [PATCH 012 of 16] knfsd: nfsd4: fix laundromat shutdown race
 [PATCH 013 of 16] knfsd: nfsd4: nfsd4_probe_callback cleanup
 [PATCH 014 of 16] knfsd: nfsd4: add missing rpciod_down()
 [PATCH 015 of 16] knfsd: nfsd4: limit number of delegations handed out.
 [PATCH 016 of 16] knfsd: nfsd4: grant delegations more frequently

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

* [PATCH 001 of 16] knfsd: locks: flag NFSv4-owned locks
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
@ 2006-04-03  5:18 ` NeilBrown
  2006-04-03  5:18 ` [PATCH 002 of 16] knfsd: nfsd4: Wrong error handling in nfs4acl NeilBrown
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:18 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


Use the fl_lmops field to identify which locks are ours, instead of trying
to look them up in our private hash.  This is safer and more efficient.

Earlier versions of this patch used a lock flag instead, but Trond pointed
out that adding a new flag for each lock manager wasn't going to scale
well, and suggested this approach instead; a separate patch converts lockd
to using fl_lmops in the same way.

In the NFSv4 case this looks like a bit of a hack, since the NFSv4 server
isn't currently actually defining a lock_manager_operations struct, so we
end up defining one *just* to serve as a cookie to identify our locks.

But it works, and we actually do expect to start using the
lock_manager_operations at some point anyway.

Signed-off-by: Marc Eshel <eshel@almaden.ibm.com>
Signed-off-by: Andy Adamson <andros@citi.umich.edu>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/nfs4state.c |   38 ++++++++++++++++----------------------
 1 file changed, 16 insertions(+), 22 deletions(-)

diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
--- ./fs/nfsd/nfs4state.c~current~	2006-04-03 15:12:03.000000000 +1000
+++ ./fs/nfsd/nfs4state.c	2006-04-03 15:12:03.000000000 +1000
@@ -2495,36 +2495,27 @@ nfs4_transform_lock_offset(struct file_l
 		lock->fl_end = OFFSET_MAX;
 }
 
-static int
-nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval)
-{
-	struct nfs4_stateowner *local = NULL;
-	int status = 0;
-			        
-	if (hashval >= LOCK_HASH_SIZE)
-		goto out;
-	list_for_each_entry(local, &lock_ownerid_hashtbl[hashval], so_idhash) {
-		if (local == sop) {
-			status = 1;
-			goto out;
-		}
-	}
-out:
-	return status;
-}
-
+/* Hack!: For now, we're defining this just so we can use a pointer to it
+ * as a unique cookie to identify our (NFSv4's) posix locks. */
+struct lock_manager_operations nfsd_posix_mng_ops  = {
+};
 
 static inline void
 nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
 {
-	struct nfs4_stateowner *sop = (struct nfs4_stateowner *) fl->fl_owner;
-	unsigned int hval = lockownerid_hashval(sop->so_id);
+	struct nfs4_stateowner *sop;
+	unsigned int hval;
 
-	deny->ld_sop = NULL;
-	if (nfs4_verify_lock_stateowner(sop, hval)) {
+	if (fl->fl_lmops == &nfsd_posix_mng_ops) {
+		sop = (struct nfs4_stateowner *) fl->fl_owner;
+		hval = lockownerid_hashval(sop->so_id);
 		kref_get(&sop->so_ref);
 		deny->ld_sop = sop;
 		deny->ld_clientid = sop->so_client->cl_clientid;
+	} else {
+		deny->ld_sop = NULL;
+		deny->ld_clientid.cl_boot = 0;
+		deny->ld_clientid.cl_id = 0;
 	}
 	deny->ld_start = fl->fl_start;
 	deny->ld_length = ~(u64)0;
@@ -2736,6 +2727,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
 	file_lock.fl_pid = current->tgid;
 	file_lock.fl_file = filp;
 	file_lock.fl_flags = FL_POSIX;
+	file_lock.fl_lmops = &nfsd_posix_mng_ops;
 
 	file_lock.fl_start = lock->lk_offset;
 	if ((lock->lk_length == ~(u64)0) || 
@@ -2841,6 +2833,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
 		file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner;
 	file_lock.fl_pid = current->tgid;
 	file_lock.fl_flags = FL_POSIX;
+	file_lock.fl_lmops = &nfsd_posix_mng_ops;
 
 	file_lock.fl_start = lockt->lt_offset;
 	if ((lockt->lt_length == ~(u64)0) || LOFF_OVERFLOW(lockt->lt_offset, lockt->lt_length))
@@ -2900,6 +2893,7 @@ nfsd4_locku(struct svc_rqst *rqstp, stru
 	file_lock.fl_pid = current->tgid;
 	file_lock.fl_file = filp;
 	file_lock.fl_flags = FL_POSIX; 
+	file_lock.fl_lmops = &nfsd_posix_mng_ops;
 	file_lock.fl_start = locku->lu_offset;
 
 	if ((locku->lu_length == ~(u64)0) || LOFF_OVERFLOW(locku->lu_offset, locku->lu_length))

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

* [PATCH 002 of 16] knfsd: nfsd4: Wrong error handling in nfs4acl
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
  2006-04-03  5:18 ` [PATCH 001 of 16] knfsd: locks: flag NFSv4-owned locks NeilBrown
@ 2006-04-03  5:18 ` NeilBrown
  2006-04-03  5:18 ` [PATCH 003 of 16] knfsd: nfsd4: better nfs4acl errors NeilBrown
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:18 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel



this fixes coverity id #3. Coverity detected dead code,
since the == -1 comparison only returns 0 or 1 to error.
Therefore the if ( error < 0 ) statement was always false.
Seems that this was an if( error = nfs4... ) statement some time
ago, which got broken during cleanup.

Signed-off-by: Eric Sesterhenn <snakebyte@gmx.de>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/nfs4acl.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff ./fs/nfsd/nfs4acl.c~current~ ./fs/nfsd/nfs4acl.c
--- ./fs/nfsd/nfs4acl.c~current~	2006-04-03 15:12:05.000000000 +1000
+++ ./fs/nfsd/nfs4acl.c	2006-04-03 15:12:05.000000000 +1000
@@ -790,7 +790,7 @@ nfs4_acl_split(struct nfs4_acl *acl, str
 			continue;
 
 		error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
-				ace->access_mask, ace->whotype, ace->who) == -1;
+				ace->access_mask, ace->whotype, ace->who);
 		if (error < 0)
 			goto out;
 

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

* [PATCH 003 of 16] knfsd: nfsd4: better nfs4acl errors
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
  2006-04-03  5:18 ` [PATCH 001 of 16] knfsd: locks: flag NFSv4-owned locks NeilBrown
  2006-04-03  5:18 ` [PATCH 002 of 16] knfsd: nfsd4: Wrong error handling in nfs4acl NeilBrown
@ 2006-04-03  5:18 ` NeilBrown
  2006-04-03  5:18 ` [PATCH 004 of 16] knfsd: nfsd4: fix acl xattr length return NeilBrown
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:18 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


We're returning -1 in a few places in the NFSv4<->POSIX acl translation
code where we could return a reasonable error.

Also allows some minor simplification elsewhere.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/nfs4acl.c |    6 +++---
 ./fs/nfsd/nfs4xdr.c |    7 +++----
 2 files changed, 6 insertions(+), 7 deletions(-)

diff ./fs/nfsd/nfs4acl.c~current~ ./fs/nfsd/nfs4acl.c
--- ./fs/nfsd/nfs4acl.c~current~	2006-04-03 15:12:05.000000000 +1000
+++ ./fs/nfsd/nfs4acl.c	2006-04-03 15:12:06.000000000 +1000
@@ -710,9 +710,9 @@ calculate_posix_ace_count(struct nfs4_ac
 		/* Also, the remaining entries are for named users and
 		 * groups, and come in threes (mask, allow, deny): */
 		if (n4acl->naces < 7)
-			return -1;
+			return -EINVAL;
 		if ((n4acl->naces - 7) % 3)
-			return -1;
+			return -EINVAL;
 		return 4 + (n4acl->naces - 7)/3;
 	}
 }
@@ -866,7 +866,7 @@ nfs4_acl_add_ace(struct nfs4_acl *acl, u
 	struct nfs4_ace *ace;
 
 	if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL)
-		return -1;
+		return -ENOMEM;
 
 	ace->type = type;
 	ace->flag = flag;

diff ./fs/nfsd/nfs4xdr.c~current~ ./fs/nfsd/nfs4xdr.c
--- ./fs/nfsd/nfs4xdr.c~current~	2006-04-03 15:12:06.000000000 +1000
+++ ./fs/nfsd/nfs4xdr.c	2006-04-03 15:12:06.000000000 +1000
@@ -299,11 +299,10 @@ nfsd4_decode_fattr(struct nfsd4_compound
 						buf, dummy32, &ace.who);
 			if (status)
 				goto out_nfserr;
-			if (nfs4_acl_add_ace(*acl, ace.type, ace.flag,
-				 ace.access_mask, ace.whotype, ace.who) != 0) {
-				status = -ENOMEM;
+			status = nfs4_acl_add_ace(*acl, ace.type, ace.flag,
+				 ace.access_mask, ace.whotype, ace.who);
+			if (status)
 				goto out_nfserr;
-			}
 		}
 	} else
 		*acl = NULL;

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

* [PATCH 004 of 16] knfsd: nfsd4: fix acl xattr length return
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (2 preceding siblings ...)
  2006-04-03  5:18 ` [PATCH 003 of 16] knfsd: nfsd4: better nfs4acl errors NeilBrown
@ 2006-04-03  5:18 ` NeilBrown
  2006-04-03  5:18 ` [PATCH 005 of 16] knfsd: nfsd: oops exporting nonexistent directory NeilBrown
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:18 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


We should be using the length from the second vfs_getxattr, in case it
changed.  (Note: there's still a small race here; we could end up returning
-ENOMEM if the length increased between the first and second call.  I don't
know whether it's worth spending a lot of effort to fix that.)

This makes XFS ACLs usable on NFS exports, which they currently aren't,
since XFS appears to be returning a too-large value for vfs_getxattr() when
it's passed a NULL buffer.  So there's probably an XFS bug here too, though
since getxattr with a NULL buffer is usually used to decide how much memory
to allocate, it may be a fairly harmless bug in most cases.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/vfs.c |    6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff ./fs/nfsd/vfs.c~current~ ./fs/nfsd/vfs.c
--- ./fs/nfsd/vfs.c~current~	2006-04-03 15:12:07.000000000 +1000
+++ ./fs/nfsd/vfs.c	2006-04-03 15:12:07.000000000 +1000
@@ -371,7 +371,6 @@ out_nfserr:
 static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
 {
 	ssize_t buflen;
-	int error;
 
 	buflen = vfs_getxattr(dentry, key, NULL, 0);
 	if (buflen <= 0)
@@ -381,10 +380,7 @@ static ssize_t nfsd_getxattr(struct dent
 	if (!*buf)
 		return -ENOMEM;
 
-	error = vfs_getxattr(dentry, key, *buf, buflen);
-	if (error < 0)
-		return error;
-	return buflen;
+	return vfs_getxattr(dentry, key, *buf, buflen);
 }
 #endif
 

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

* [PATCH 005 of 16] knfsd: nfsd: oops exporting nonexistent directory
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (3 preceding siblings ...)
  2006-04-03  5:18 ` [PATCH 004 of 16] knfsd: nfsd4: fix acl xattr length return NeilBrown
@ 2006-04-03  5:18 ` NeilBrown
  2006-04-03  5:18 ` [PATCH 006 of 16] knfsd: nfsd: nfsd_setuser doesn't really need to modify rqstp->rq_cred NeilBrown
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:18 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel



Export a directory that does not exist:
	exportfs -orw,fsid=0,insecure,no_subtree_check client:/home/NFS4

Try to mount from client with nfs4. Mount hangs (I'm not sure why -
that's another issue).

While client is hung, back on server

	mkdir /home/NFS4

The server panics in dput. I traced the problem back to svc_export_parse()
calling path_release() even though path_lookup() failed (it happens
to fill in the nameidata structure with a negative dentry - so the test
after out: succeeds).

After patching, an recreating the problem, the client mount still takes
some time before finally exiting with a message "couldn't read
superblock".

Here is a simple patch to resolve this issue:

Signed-Off-By: Frank Filz <ffilzlnx@us.ibm.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/export.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff ./fs/nfsd/export.c~current~ ./fs/nfsd/export.c
--- ./fs/nfsd/export.c~current~	2006-04-03 15:12:08.000000000 +1000
+++ ./fs/nfsd/export.c	2006-04-03 15:12:08.000000000 +1000
@@ -422,7 +422,7 @@ static int svc_export_parse(struct cache
 	if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 		goto out;
 	err = path_lookup(buf, 0, &nd);
-	if (err) goto out;
+	if (err) goto out_no_path;
 
 	exp.h.flags = 0;
 	exp.ex_client = dom;
@@ -475,6 +475,7 @@ static int svc_export_parse(struct cache
  out:
 	if (nd.dentry)
 		path_release(&nd);
+ out_no_path:
 	if (dom)
 		auth_domain_put(dom);
 	kfree(buf);

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

* [PATCH 006 of 16] knfsd: nfsd: nfsd_setuser doesn't really need to modify rqstp->rq_cred.
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (4 preceding siblings ...)
  2006-04-03  5:18 ` [PATCH 005 of 16] knfsd: nfsd: oops exporting nonexistent directory NeilBrown
@ 2006-04-03  5:18 ` NeilBrown
  2006-04-03  5:18 ` [PATCH 007 of 16] knfsd: nfsd4: remove nfsd_setuser from putrootfh NeilBrown
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:18 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


In addition to setting the processes filesystem id's, nfsd_setuser also
modifies the value of the rq_cred which stores the id's that originally
came from the rpc call, for example to reflect root squashing.

There's no real reason to do that--the only case where rqstp->rq_cred 
is actually used later on is in the NFSv4 SETCLIENTID/SETCLIENTID_CONFIRM
operations, and there the results are the opposite of what we want--those
two operations don't deal with the filesystem at all, they only record the
credentials used with the rpc call for later reference (so that we may
require the same credentials be used on later operations), and the
credentials shouldn't vary just because there was or wasn't a previous
operation in the compound that referred to some export  

This fixes a bug which caused mounts from Solaris clients to fail.

Signed-off-by: Andy Adamson <andros@citi.umich.edu>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/auth.c |   46 +++++++++++++++++++++++-----------------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff ./fs/nfsd/auth.c~current~ ./fs/nfsd/auth.c
--- ./fs/nfsd/auth.c~current~	2006-04-03 15:12:09.000000000 +1000
+++ ./fs/nfsd/auth.c	2006-04-03 15:12:09.000000000 +1000
@@ -14,46 +14,46 @@
 
 int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
 {
-	struct svc_cred	*cred = &rqstp->rq_cred;
+	struct svc_cred	cred = rqstp->rq_cred;
 	int i;
 	int ret;
 
 	if (exp->ex_flags & NFSEXP_ALLSQUASH) {
-		cred->cr_uid = exp->ex_anon_uid;
-		cred->cr_gid = exp->ex_anon_gid;
-		put_group_info(cred->cr_group_info);
-		cred->cr_group_info = groups_alloc(0);
+		cred.cr_uid = exp->ex_anon_uid;
+		cred.cr_gid = exp->ex_anon_gid;
+		cred.cr_group_info = groups_alloc(0);
 	} else if (exp->ex_flags & NFSEXP_ROOTSQUASH) {
 		struct group_info *gi;
-		if (!cred->cr_uid)
-			cred->cr_uid = exp->ex_anon_uid;
-		if (!cred->cr_gid)
-			cred->cr_gid = exp->ex_anon_gid;
-		gi = groups_alloc(cred->cr_group_info->ngroups);
+		if (!cred.cr_uid)
+			cred.cr_uid = exp->ex_anon_uid;
+		if (!cred.cr_gid)
+			cred.cr_gid = exp->ex_anon_gid;
+		gi = groups_alloc(cred.cr_group_info->ngroups);
 		if (gi)
-			for (i = 0; i < cred->cr_group_info->ngroups; i++) {
-				if (!GROUP_AT(cred->cr_group_info, i))
+			for (i = 0; i < cred.cr_group_info->ngroups; i++) {
+				if (!GROUP_AT(cred.cr_group_info, i))
 					GROUP_AT(gi, i) = exp->ex_anon_gid;
 				else
-					GROUP_AT(gi, i) = GROUP_AT(cred->cr_group_info, i);
+					GROUP_AT(gi, i) = GROUP_AT(cred.cr_group_info, i);
 			}
-		put_group_info(cred->cr_group_info);
-		cred->cr_group_info = gi;
-	}
+		cred.cr_group_info = gi;
+	} else
+		get_group_info(cred.cr_group_info);
 
-	if (cred->cr_uid != (uid_t) -1)
-		current->fsuid = cred->cr_uid;
+	if (cred.cr_uid != (uid_t) -1)
+		current->fsuid = cred.cr_uid;
 	else
 		current->fsuid = exp->ex_anon_uid;
-	if (cred->cr_gid != (gid_t) -1)
-		current->fsgid = cred->cr_gid;
+	if (cred.cr_gid != (gid_t) -1)
+		current->fsgid = cred.cr_gid;
 	else
 		current->fsgid = exp->ex_anon_gid;
 
-	if (!cred->cr_group_info)
+	if (!cred.cr_group_info)
 		return -ENOMEM;
-	ret = set_current_groups(cred->cr_group_info);
-	if ((cred->cr_uid)) {
+	ret = set_current_groups(cred.cr_group_info);
+	put_group_info(cred.cr_group_info);
+	if ((cred.cr_uid)) {
 		cap_t(current->cap_effective) &= ~CAP_NFSD_MASK;
 	} else {
 		cap_t(current->cap_effective) |= (CAP_NFSD_MASK &

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

* [PATCH 007 of 16] knfsd: nfsd4: remove nfsd_setuser from putrootfh
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (5 preceding siblings ...)
  2006-04-03  5:18 ` [PATCH 006 of 16] knfsd: nfsd: nfsd_setuser doesn't really need to modify rqstp->rq_cred NeilBrown
@ 2006-04-03  5:18 ` NeilBrown
  2006-04-03  5:18 ` [PATCH 008 of 16] knfsd: nfsd4: fix corruption of returned data when using 64k pages NeilBrown
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:18 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel



Since nfsd_setuser() is already called from any operation that uses the
current filehandle (because it's called from fh_verify), there's no reason
to call it from putrootfh.

Signed-off-by: Andy Adamson <andros@citi.umich.edu>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/nfs4proc.c |    2 --
 1 file changed, 2 deletions(-)

diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
--- ./fs/nfsd/nfs4proc.c~current~	2006-04-03 15:12:10.000000000 +1000
+++ ./fs/nfsd/nfs4proc.c	2006-04-03 15:12:10.000000000 +1000
@@ -288,8 +288,6 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, 
 	fh_put(current_fh);
 	status = exp_pseudoroot(rqstp->rq_client, current_fh,
 			      &rqstp->rq_chandle);
-	if (!status)
-		status = nfserrno(nfsd_setuser(rqstp, current_fh->fh_export));
 	return status;
 }
 

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

* [PATCH 008 of 16] knfsd: nfsd4: fix corruption of returned data when using 64k pages
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (6 preceding siblings ...)
  2006-04-03  5:18 ` [PATCH 007 of 16] knfsd: nfsd4: remove nfsd_setuser from putrootfh NeilBrown
@ 2006-04-03  5:18 ` NeilBrown
  2006-04-03  5:18 ` [PATCH 009 of 16] knfsd: nfsd4: fix corruption on readdir encoding with " NeilBrown
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:18 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


In v4 we grab an extra page just for the padding of returned data.  The
formula that the rpc server uses to allocate pages for the response doesn't
take into account this extra page.

Instead of adjusting those formulae, we adopt the same solution as v2 and
v3, and put the "tail" data in the same page as the "head" data.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/nfs4xdr.c |   42 +++++++++++++++++-------------------------
 1 file changed, 17 insertions(+), 25 deletions(-)

diff ./fs/nfsd/nfs4xdr.c~current~ ./fs/nfsd/nfs4xdr.c
--- ./fs/nfsd/nfs4xdr.c~current~	2006-04-03 15:12:06.000000000 +1000
+++ ./fs/nfsd/nfs4xdr.c	2006-04-03 15:12:11.000000000 +1000
@@ -2084,27 +2084,20 @@ nfsd4_encode_read(struct nfsd4_compoundr
 	WRITE32(eof);
 	WRITE32(maxcount);
 	ADJUST_ARGS();
-	resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base;
-
+	resp->xbuf->head[0].iov_len = (char*)p
+					- (char*)resp->xbuf->head[0].iov_base;
 	resp->xbuf->page_len = maxcount;
 
-	/* read zero bytes -> don't set up tail */
-	if(!maxcount)
-		return 0;        
-
-	/* set up page for remaining responses */
-	svc_take_page(resp->rqstp);
-	resp->xbuf->tail[0].iov_base = 
-		page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
-	resp->rqstp->rq_restailpage = resp->rqstp->rq_resused-1;
+	/* Use rest of head for padding and remaining ops: */
+	resp->rqstp->rq_restailpage = 0;
+	resp->xbuf->tail[0].iov_base = p;
 	resp->xbuf->tail[0].iov_len = 0;
-	resp->p = resp->xbuf->tail[0].iov_base;
-	resp->end = resp->p + PAGE_SIZE/4;
-
 	if (maxcount&3) {
-		*(resp->p)++ = 0;
+		RESERVE_SPACE(4);
+		WRITE32(0);
 		resp->xbuf->tail[0].iov_base += maxcount&3;
 		resp->xbuf->tail[0].iov_len = 4 - (maxcount&3);
+		ADJUST_ARGS();
 	}
 	return 0;
 }
@@ -2141,21 +2134,20 @@ nfsd4_encode_readlink(struct nfsd4_compo
 
 	WRITE32(maxcount);
 	ADJUST_ARGS();
-	resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base;
+	resp->xbuf->head[0].iov_len = (char*)p
+				- (char*)resp->xbuf->head[0].iov_base;
+	resp->xbuf->page_len = maxcount;
 
-	svc_take_page(resp->rqstp);
-	resp->xbuf->tail[0].iov_base = 
-		page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
-	resp->rqstp->rq_restailpage = resp->rqstp->rq_resused-1;
+	/* Use rest of head for padding and remaining ops: */
+	resp->rqstp->rq_restailpage = 0;
+	resp->xbuf->tail[0].iov_base = p;
 	resp->xbuf->tail[0].iov_len = 0;
-	resp->p = resp->xbuf->tail[0].iov_base;
-	resp->end = resp->p + PAGE_SIZE/4;
-
-	resp->xbuf->page_len = maxcount;
 	if (maxcount&3) {
-		*(resp->p)++ = 0;
+		RESERVE_SPACE(4);
+		WRITE32(0);
 		resp->xbuf->tail[0].iov_base += maxcount&3;
 		resp->xbuf->tail[0].iov_len = 4 - (maxcount&3);
+		ADJUST_ARGS();
 	}
 	return 0;
 }

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

* [PATCH 009 of 16] knfsd: nfsd4: fix corruption on readdir encoding with 64k pages
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (7 preceding siblings ...)
  2006-04-03  5:18 ` [PATCH 008 of 16] knfsd: nfsd4: fix corruption of returned data when using 64k pages NeilBrown
@ 2006-04-03  5:18 ` NeilBrown
  2006-04-03  5:18 ` [PATCH 010 of 16] knfsd: svcrpc: gss: don't call svc_take_page unnecessarily NeilBrown
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:18 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


Fix corruption on readdir encoding with 64k pages.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/nfs4xdr.c |   13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff ./fs/nfsd/nfs4xdr.c~current~ ./fs/nfsd/nfs4xdr.c
--- ./fs/nfsd/nfs4xdr.c~current~	2006-04-03 15:12:11.000000000 +1000
+++ ./fs/nfsd/nfs4xdr.c	2006-04-03 15:12:13.000000000 +1000
@@ -2157,7 +2157,7 @@ nfsd4_encode_readdir(struct nfsd4_compou
 {
 	int maxcount;
 	loff_t offset;
-	u32 *page, *savep;
+	u32 *page, *savep, *tailbase;
 	ENCODE_HEAD;
 
 	if (nfserr)
@@ -2173,6 +2173,7 @@ nfsd4_encode_readdir(struct nfsd4_compou
 	WRITE32(0);
 	ADJUST_ARGS();
 	resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base;
+	tailbase = p;
 
 	maxcount = PAGE_SIZE;
 	if (maxcount > readdir->rd_maxcount)
@@ -2217,14 +2218,12 @@ nfsd4_encode_readdir(struct nfsd4_compou
 	*p++ = htonl(readdir->common.err == nfserr_eof);
 	resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
 
-	/* allocate a page for the tail */
-	svc_take_page(resp->rqstp);
-	resp->xbuf->tail[0].iov_base = 
-		page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
-	resp->rqstp->rq_restailpage = resp->rqstp->rq_resused-1;
+	/* Use rest of head for padding and remaining ops: */
+	resp->rqstp->rq_restailpage = 0;
+	resp->xbuf->tail[0].iov_base = tailbase;
 	resp->xbuf->tail[0].iov_len = 0;
 	resp->p = resp->xbuf->tail[0].iov_base;
-	resp->end = resp->p + PAGE_SIZE/4;
+	resp->end = resp->p + (PAGE_SIZE - resp->xbuf->head[0].iov_len)/4;
 
 	return 0;
 err_no_verf:

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

* [PATCH 010 of 16] knfsd: svcrpc: gss: don't call svc_take_page unnecessarily
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (8 preceding siblings ...)
  2006-04-03  5:18 ` [PATCH 009 of 16] knfsd: nfsd4: fix corruption on readdir encoding with " NeilBrown
@ 2006-04-03  5:18 ` NeilBrown
  2006-04-03  5:19 ` [PATCH 011 of 16] knfsd: svcrpc: WARN() instead of returning an error from svc_take_page NeilBrown
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:18 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


We're using svc_take_page here to get another page for the tail in case one
wasn't already allocated.  But there isn't always guaranteed to be another
page available.

Also fix a typo that made us check the tail buffer for space when we meant
to be checking the head buffer.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./net/sunrpc/auth_gss/svcauth_gss.c |   14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff ./net/sunrpc/auth_gss/svcauth_gss.c~current~ ./net/sunrpc/auth_gss/svcauth_gss.c
--- ./net/sunrpc/auth_gss/svcauth_gss.c~current~	2006-04-03 15:12:14.000000000 +1000
+++ ./net/sunrpc/auth_gss/svcauth_gss.c	2006-04-03 15:12:14.000000000 +1000
@@ -1122,18 +1122,20 @@ svcauth_gss_release(struct svc_rqst *rqs
 					integ_len))
 			BUG();
 		if (resbuf->page_len == 0
-			&& resbuf->tail[0].iov_len + RPC_MAX_AUTH_SIZE
+			&& resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE
 				< PAGE_SIZE) {
 			BUG_ON(resbuf->tail[0].iov_len);
 			/* Use head for everything */
 			resv = &resbuf->head[0];
 		} else if (resbuf->tail[0].iov_base == NULL) {
-			/* copied from nfsd4_encode_read */
-			svc_take_page(rqstp);
-			resbuf->tail[0].iov_base = page_address(rqstp
-					->rq_respages[rqstp->rq_resused-1]);
-			rqstp->rq_restailpage = rqstp->rq_resused-1;
+			if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE
+					> PAGE_SIZE)
+				goto out_err;
+			resbuf->tail[0].iov_base =
+				resbuf->head[0].iov_base
+				+ resbuf->head[0].iov_len;
 			resbuf->tail[0].iov_len = 0;
+			rqstp->rq_restailpage = 0;
 			resv = &resbuf->tail[0];
 		} else {
 			resv = &resbuf->tail[0];

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

* [PATCH 011 of 16] knfsd: svcrpc: WARN() instead of returning an error from svc_take_page
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (9 preceding siblings ...)
  2006-04-03  5:18 ` [PATCH 010 of 16] knfsd: svcrpc: gss: don't call svc_take_page unnecessarily NeilBrown
@ 2006-04-03  5:19 ` NeilBrown
  2006-04-03 22:02   ` Ingo Oeser
  2006-04-03  5:19 ` [PATCH 012 of 16] knfsd: nfsd4: fix laundromat shutdown race NeilBrown
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:19 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


Every caller of svc_take_page ignores its return value and assumes it
succeeded.  So just WARN() instead of returning an ignored error.  This
would have saved some time debugging a recent nfsd4 problem.

If there are still failure cases here, then the result is probably that we
overwrite an earlier part of the reply while xdr-encoding.

While the corrupted reply is a nasty bug, it would be worse to panic here
and create the possibility of a remote DOS; hence WARN() instead of BUG().

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./include/linux/sunrpc/svc.h |    6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff ./include/linux/sunrpc/svc.h~current~ ./include/linux/sunrpc/svc.h
--- ./include/linux/sunrpc/svc.h~current~	2006-04-03 15:12:15.000000000 +1000
+++ ./include/linux/sunrpc/svc.h	2006-04-03 15:12:15.000000000 +1000
@@ -197,15 +197,13 @@ svc_take_res_page(struct svc_rqst *rqstp
 	return rqstp->rq_respages[rqstp->rq_resused++];
 }
 
-static inline int svc_take_page(struct svc_rqst *rqstp)
+static inline void svc_take_page(struct svc_rqst *rqstp)
 {
-	if (rqstp->rq_arghi <= rqstp->rq_argused)
-		return -ENOMEM;
+	WARN_ON(rqstp->rq_arghi <= rqstp->rq_argused);
 	rqstp->rq_arghi--;
 	rqstp->rq_respages[rqstp->rq_resused] =
 		rqstp->rq_argpages[rqstp->rq_arghi];
 	rqstp->rq_resused++;
-	return 0;
 }
 
 static inline void svc_pushback_allpages(struct svc_rqst *rqstp)

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

* [PATCH 012 of 16] knfsd: nfsd4: fix laundromat shutdown race
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (10 preceding siblings ...)
  2006-04-03  5:19 ` [PATCH 011 of 16] knfsd: svcrpc: WARN() instead of returning an error from svc_take_page NeilBrown
@ 2006-04-03  5:19 ` NeilBrown
  2006-04-03  5:19 ` [PATCH 013 of 16] knfsd: nfsd4: nfsd4_probe_callback cleanup NeilBrown
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:19 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


We need to make sure the laundromat work doesn't reschedule itself just when
we try to cancel it.  Also, we shouldn't be waiting for it to finish running
while holding the state lock, as that's a potential deadlock.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/nfs4state.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
--- ./fs/nfsd/nfs4state.c~current~	2006-04-03 15:12:03.000000000 +1000
+++ ./fs/nfsd/nfs4state.c	2006-04-03 15:12:16.000000000 +1000
@@ -3238,8 +3238,6 @@ __nfs4_state_shutdown(void)
 	}
 
 	cancel_delayed_work(&laundromat_work);
-	flush_workqueue(laundry_wq);
-	destroy_workqueue(laundry_wq);
 	nfsd4_shutdown_recdir();
 	nfs4_init = 0;
 }
@@ -3247,6 +3245,8 @@ __nfs4_state_shutdown(void)
 void
 nfs4_state_shutdown(void)
 {
+	cancel_rearming_delayed_workqueue(laundry_wq, &laundromat_work);
+	destroy_workqueue(laundry_wq);
 	nfs4_lock_state();
 	nfs4_release_reclaim();
 	__nfs4_state_shutdown();

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

* [PATCH 013 of 16] knfsd: nfsd4: nfsd4_probe_callback cleanup
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (11 preceding siblings ...)
  2006-04-03  5:19 ` [PATCH 012 of 16] knfsd: nfsd4: fix laundromat shutdown race NeilBrown
@ 2006-04-03  5:19 ` NeilBrown
  2006-04-03  5:19 ` [PATCH 014 of 16] knfsd: nfsd4: add missing rpciod_down() NeilBrown
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:19 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


Some obvious cleanup.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/nfs4callback.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff ./fs/nfsd/nfs4callback.c~current~ ./fs/nfsd/nfs4callback.c
--- ./fs/nfsd/nfs4callback.c~current~	2006-04-03 15:12:16.000000000 +1000
+++ ./fs/nfsd/nfs4callback.c	2006-04-03 15:12:16.000000000 +1000
@@ -441,8 +441,9 @@ nfsd4_probe_callback(struct nfs4_client 
 		goto out_clnt;
 	}
 
-	/* the task holds a reference to the nfs4_client struct */
 	cb->cb_client = clnt;
+
+	/* the task holds a reference to the nfs4_client struct */
 	atomic_inc(&clp->cl_count);
 
 	msg.rpc_cred = nfsd4_lookupcred(clp,0);
@@ -460,13 +461,12 @@ nfsd4_probe_callback(struct nfs4_client 
 out_rpciod:
 	atomic_dec(&clp->cl_count);
 	rpciod_down();
+	cb->cb_client = NULL;
 out_clnt:
 	rpc_shutdown_client(clnt);
-	goto out_err;
 out_err:
 	dprintk("NFSD: warning: no callback path to client %.*s\n",
 		(int)clp->cl_name.len, clp->cl_name.data);
-	cb->cb_client = NULL;
 }
 
 static void

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

* [PATCH 014 of 16] knfsd: nfsd4: add missing rpciod_down()
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (12 preceding siblings ...)
  2006-04-03  5:19 ` [PATCH 013 of 16] knfsd: nfsd4: nfsd4_probe_callback cleanup NeilBrown
@ 2006-04-03  5:19 ` NeilBrown
  2006-04-03  5:19 ` [PATCH 015 of 16] knfsd: nfsd4: limit number of delegations handed out NeilBrown
  2006-04-03  5:19 ` [PATCH 016 of 16] knfsd: nfsd4: grant delegations more frequently NeilBrown
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:19 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


We should be shutting down rpciod for the callback channel when we shut down
the server.

Also note that we do rpciod_up() and create the callback client *before*
setting cb_set--the cb_set only determines whether the initial null was
succesful.  So cb_set is not a reliable determiner of whether we need to
clean up, only cb_client is.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/nfs4state.c |   21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
--- ./fs/nfsd/nfs4state.c~current~	2006-04-03 15:12:16.000000000 +1000
+++ ./fs/nfsd/nfs4state.c	2006-04-03 15:12:16.000000000 +1000
@@ -330,22 +330,29 @@ put_nfs4_client(struct nfs4_client *clp)
 }
 
 static void
+shutdown_callback_client(struct nfs4_client *clp)
+{
+	struct rpc_clnt *clnt = clp->cl_callback.cb_client;
+
+	/* shutdown rpc client, ending any outstanding recall rpcs */
+	if (clnt) {
+		clp->cl_callback.cb_client = NULL;
+		rpc_shutdown_client(clnt);
+		rpciod_down();
+	}
+}
+
+static void
 expire_client(struct nfs4_client *clp)
 {
 	struct nfs4_stateowner *sop;
 	struct nfs4_delegation *dp;
-	struct nfs4_callback *cb = &clp->cl_callback;
-	struct rpc_clnt *clnt = clp->cl_callback.cb_client;
 	struct list_head reaplist;
 
 	dprintk("NFSD: expire_client cl_count %d\n",
 	                    atomic_read(&clp->cl_count));
 
-	/* shutdown rpc client, ending any outstanding recall rpcs */
-	if (atomic_read(&cb->cb_set) == 1 && clnt) {
-		rpc_shutdown_client(clnt);
-		clnt = clp->cl_callback.cb_client = NULL;
-	}
+	shutdown_callback_client(clp);
 
 	INIT_LIST_HEAD(&reaplist);
 	spin_lock(&recall_lock);

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

* [PATCH 015 of 16] knfsd: nfsd4: limit number of delegations handed out.
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (13 preceding siblings ...)
  2006-04-03  5:19 ` [PATCH 014 of 16] knfsd: nfsd4: add missing rpciod_down() NeilBrown
@ 2006-04-03  5:19 ` NeilBrown
  2006-04-03  5:19 ` [PATCH 016 of 16] knfsd: nfsd4: grant delegations more frequently NeilBrown
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:19 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


It's very easy for the server to DOS itself by just giving out too many
delegations.

For now we just solve the problem with a dumb hard limit.  Eventually we'll
want a smarter policy.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/nfs4state.c |   73 ++++++++++++++++++++++++++------------------------
 1 file changed, 39 insertions(+), 34 deletions(-)

diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
--- ./fs/nfsd/nfs4state.c~current~	2006-04-03 15:12:16.000000000 +1000
+++ ./fs/nfsd/nfs4state.c	2006-04-03 15:12:17.000000000 +1000
@@ -147,6 +147,41 @@ get_nfs4_file(struct nfs4_file *fi)
 	kref_get(&fi->fi_ref);
 }
 
+int num_delegations = 0;
+/*
+ * Open owner state (share locks)
+ */
+
+/* hash tables for nfs4_stateowner */
+#define OWNER_HASH_BITS              8
+#define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
+#define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
+
+#define ownerid_hashval(id) \
+        ((id) & OWNER_HASH_MASK)
+#define ownerstr_hashval(clientid, ownername) \
+        (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
+
+static struct list_head	ownerid_hashtbl[OWNER_HASH_SIZE];
+static struct list_head	ownerstr_hashtbl[OWNER_HASH_SIZE];
+
+/* hash table for nfs4_file */
+#define FILE_HASH_BITS                   8
+#define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
+#define FILE_HASH_MASK                  (FILE_HASH_SIZE - 1)
+/* hash table for (open)nfs4_stateid */
+#define STATEID_HASH_BITS              10
+#define STATEID_HASH_SIZE              (1 << STATEID_HASH_BITS)
+#define STATEID_HASH_MASK              (STATEID_HASH_SIZE - 1)
+
+#define file_hashval(x) \
+        hash_ptr(x, FILE_HASH_BITS)
+#define stateid_hashval(owner_id, file_id)  \
+        (((owner_id) + (file_id)) & STATEID_HASH_MASK)
+
+static struct list_head file_hashtbl[FILE_HASH_SIZE];
+static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
+
 static struct nfs4_delegation *
 alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
 {
@@ -155,9 +190,12 @@ alloc_init_deleg(struct nfs4_client *clp
 	struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
 
 	dprintk("NFSD alloc_init_deleg\n");
+	if (num_delegations > STATEID_HASH_SIZE * 4)
+		return NULL;
 	dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
 	if (dp == NULL)
 		return dp;
+	num_delegations++;
 	INIT_LIST_HEAD(&dp->dl_perfile);
 	INIT_LIST_HEAD(&dp->dl_perclnt);
 	INIT_LIST_HEAD(&dp->dl_recall_lru);
@@ -192,6 +230,7 @@ nfs4_put_delegation(struct nfs4_delegati
 		dprintk("NFSD: freeing dp %p\n",dp);
 		put_nfs4_file(dp->dl_file);
 		kmem_cache_free(deleg_slab, dp);
+		num_delegations--;
 	}
 }
 
@@ -943,40 +982,6 @@ out:
 	return status;
 }
 
-/* 
- * Open owner state (share locks)
- */
-
-/* hash tables for nfs4_stateowner */
-#define OWNER_HASH_BITS              8
-#define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
-#define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
-
-#define ownerid_hashval(id) \
-        ((id) & OWNER_HASH_MASK)
-#define ownerstr_hashval(clientid, ownername) \
-        (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
-
-static struct list_head	ownerid_hashtbl[OWNER_HASH_SIZE];
-static struct list_head	ownerstr_hashtbl[OWNER_HASH_SIZE];
-
-/* hash table for nfs4_file */
-#define FILE_HASH_BITS                   8
-#define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
-#define FILE_HASH_MASK                  (FILE_HASH_SIZE - 1)
-/* hash table for (open)nfs4_stateid */
-#define STATEID_HASH_BITS              10
-#define STATEID_HASH_SIZE              (1 << STATEID_HASH_BITS)
-#define STATEID_HASH_MASK              (STATEID_HASH_SIZE - 1)
-
-#define file_hashval(x) \
-        hash_ptr(x, FILE_HASH_BITS)
-#define stateid_hashval(owner_id, file_id)  \
-        (((owner_id) + (file_id)) & STATEID_HASH_MASK)
-
-static struct list_head file_hashtbl[FILE_HASH_SIZE];
-static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];
-
 /* OPEN Share state helper functions */
 static inline struct nfs4_file *
 alloc_init_file(struct inode *ino)

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

* [PATCH 016 of 16] knfsd: nfsd4: grant delegations more frequently
  2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
                   ` (14 preceding siblings ...)
  2006-04-03  5:19 ` [PATCH 015 of 16] knfsd: nfsd4: limit number of delegations handed out NeilBrown
@ 2006-04-03  5:19 ` NeilBrown
  15 siblings, 0 replies; 19+ messages in thread
From: NeilBrown @ 2006-04-03  5:19 UTC (permalink / raw)
  To: Andrew Morton; +Cc: nfs, linux-kernel


Keep unused openowners around for at least one lease period, to avoid the
need for as many open confirmations and to allow handing out more
delegations.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/nfsd/nfs4state.c |   13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
--- ./fs/nfsd/nfs4state.c~current~	2006-04-03 15:12:17.000000000 +1000
+++ ./fs/nfsd/nfs4state.c	2006-04-03 15:12:17.000000000 +1000
@@ -1198,8 +1198,7 @@ move_to_close_lru(struct nfs4_stateowner
 {
 	dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);
 
-	unhash_stateowner(sop);
-	list_add_tail(&sop->so_close_lru, &close_lru);
+	list_move_tail(&sop->so_close_lru, &close_lru);
 	sop->so_time = get_seconds();
 }
 
@@ -1928,8 +1927,7 @@ nfs4_laundromat(void)
 		}
 		dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
 			sop->so_id);
-		list_del(&sop->so_close_lru);
-		nfs4_put_stateowner(sop);
+		release_stateowner(sop);
 	}
 	if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
 		clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
@@ -3217,15 +3215,8 @@ __nfs4_state_shutdown(void)
 	int i;
 	struct nfs4_client *clp = NULL;
 	struct nfs4_delegation *dp = NULL;
-	struct nfs4_stateowner *sop = NULL;
 	struct list_head *pos, *next, reaplist;
 
-	list_for_each_safe(pos, next, &close_lru) {
-		sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);
-		list_del(&sop->so_close_lru);
-		nfs4_put_stateowner(sop);
-	}
-
 	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
 		while (!list_empty(&conf_id_hashtbl[i])) {
 			clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);

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

* Re: [PATCH 011 of 16] knfsd: svcrpc: WARN() instead of returning an error from svc_take_page
  2006-04-03  5:19 ` [PATCH 011 of 16] knfsd: svcrpc: WARN() instead of returning an error from svc_take_page NeilBrown
@ 2006-04-03 22:02   ` Ingo Oeser
  2006-04-04  2:26     ` [NFS] " J. Bruce Fields
  0 siblings, 1 reply; 19+ messages in thread
From: Ingo Oeser @ 2006-04-03 22:02 UTC (permalink / raw)
  To: NeilBrown; +Cc: nfs, linux-kernel, Andrew Morton

On Monday, 3. April 2006 07:19, you wrote:
> diff ./include/linux/sunrpc/svc.h~current~ ./include/linux/sunrpc/svc.h
> --- ./include/linux/sunrpc/svc.h~current~	2006-04-03 15:12:15.000000000 +1000
> +++ ./include/linux/sunrpc/svc.h	2006-04-03 15:12:15.000000000 +1000
> @@ -197,15 +197,13 @@ svc_take_res_page(struct svc_rqst *rqstp
>  	return rqstp->rq_respages[rqstp->rq_resused++];
>  }
>  
> -static inline int svc_take_page(struct svc_rqst *rqstp)
> +static inline void svc_take_page(struct svc_rqst *rqstp)
>  {
> -	if (rqstp->rq_arghi <= rqstp->rq_argused)
> -		return -ENOMEM;
> +	WARN_ON(rqstp->rq_arghi <= rqstp->rq_argused);
>  	rqstp->rq_arghi--;
>  	rqstp->rq_respages[rqstp->rq_resused] =
>  		rqstp->rq_argpages[rqstp->rq_arghi];
>  	rqstp->rq_resused++;
> -	return 0;
>  }

What will prevent underflow of ->rq_arghi and overflow of ->rq_resused here?

Before that change, this code would return without 
modifying both members here on error.

Now this code makes the error worse with each call.

Just ignore me, if this is ok :-)


Regards

Ingo Oeser

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

* Re: [NFS] Re: [PATCH 011 of 16] knfsd: svcrpc: WARN() instead of returning an error from svc_take_page
  2006-04-03 22:02   ` Ingo Oeser
@ 2006-04-04  2:26     ` J. Bruce Fields
  0 siblings, 0 replies; 19+ messages in thread
From: J. Bruce Fields @ 2006-04-04  2:26 UTC (permalink / raw)
  To: Ingo Oeser; +Cc: NeilBrown, nfs, linux-kernel, Andrew Morton

On Tue, Apr 04, 2006 at 12:02:21AM +0200, Ingo Oeser wrote:
> On Monday, 3. April 2006 07:19, you wrote:
> > diff ./include/linux/sunrpc/svc.h~current~ ./include/linux/sunrpc/svc.h
> > --- ./include/linux/sunrpc/svc.h~current~	2006-04-03 15:12:15.000000000 +1000
> > +++ ./include/linux/sunrpc/svc.h	2006-04-03 15:12:15.000000000 +1000
> > @@ -197,15 +197,13 @@ svc_take_res_page(struct svc_rqst *rqstp
> >  	return rqstp->rq_respages[rqstp->rq_resused++];
> >  }
> >  
> > -static inline int svc_take_page(struct svc_rqst *rqstp)
> > +static inline void svc_take_page(struct svc_rqst *rqstp)
> >  {
> > -	if (rqstp->rq_arghi <= rqstp->rq_argused)
> > -		return -ENOMEM;
> > +	WARN_ON(rqstp->rq_arghi <= rqstp->rq_argused);
> >  	rqstp->rq_arghi--;
> >  	rqstp->rq_respages[rqstp->rq_resused] =
> >  		rqstp->rq_argpages[rqstp->rq_arghi];
> >  	rqstp->rq_resused++;
> > -	return 0;
> >  }
> 
> What will prevent underflow of ->rq_arghi and overflow of ->rq_resused here?
> 
> Before that change, this code would return without 
> modifying both members here on error.
> 
> Now this code makes the error worse with each call.
> 
> Just ignore me, if this is ok :-)

No, you're right, apologies.  The results could be worse than if we'd
just BUG()'d there.

So we should probably either just bite the bullet and make that a BUG(),
or add back the return.  The latter option appended in the form of a
replacement patch....

--b.

svcrpc: WARN() instead of returning an error from svc_take_page

Every caller of svc_take_page ignores its return value and assumes it
succeeded.  So just WARN() instead of returning an ignored error.  This
would have saved some time debugging a recent nfsd4 problem.

If there are still failure cases here, then the result is probably that we
overwrite an earlier part of the reply while xdr-encoding.

While the corrupted reply is a nasty bug, it would be worse to panic here
and create the possibility of a remote DOS; hence WARN() instead of BUG().

Thanks to Ingo Oeser for noticing a bug in an earlier version of this
patch.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---

 include/linux/sunrpc/svc.h |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 50cab2a..5035643 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -197,15 +197,16 @@ svc_take_res_page(struct svc_rqst *rqstp
 	return rqstp->rq_respages[rqstp->rq_resused++];
 }
 
-static inline int svc_take_page(struct svc_rqst *rqstp)
+static inline void svc_take_page(struct svc_rqst *rqstp)
 {
-	if (rqstp->rq_arghi <= rqstp->rq_argused)
-		return -ENOMEM;
+	if (rqstp->rq_arghi <= rqstp->rq_argused) {
+		WARN_ON(1);
+		return;
+	}
 	rqstp->rq_arghi--;
 	rqstp->rq_respages[rqstp->rq_resused] =
 		rqstp->rq_argpages[rqstp->rq_arghi];
 	rqstp->rq_resused++;
-	return 0;
 }
 
 static inline void svc_pushback_allpages(struct svc_rqst *rqstp)

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

end of thread, other threads:[~2006-04-04  2:26 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-04-03  5:18 [PATCH 000 of 16] knfsd: Introduction NeilBrown
2006-04-03  5:18 ` [PATCH 001 of 16] knfsd: locks: flag NFSv4-owned locks NeilBrown
2006-04-03  5:18 ` [PATCH 002 of 16] knfsd: nfsd4: Wrong error handling in nfs4acl NeilBrown
2006-04-03  5:18 ` [PATCH 003 of 16] knfsd: nfsd4: better nfs4acl errors NeilBrown
2006-04-03  5:18 ` [PATCH 004 of 16] knfsd: nfsd4: fix acl xattr length return NeilBrown
2006-04-03  5:18 ` [PATCH 005 of 16] knfsd: nfsd: oops exporting nonexistent directory NeilBrown
2006-04-03  5:18 ` [PATCH 006 of 16] knfsd: nfsd: nfsd_setuser doesn't really need to modify rqstp->rq_cred NeilBrown
2006-04-03  5:18 ` [PATCH 007 of 16] knfsd: nfsd4: remove nfsd_setuser from putrootfh NeilBrown
2006-04-03  5:18 ` [PATCH 008 of 16] knfsd: nfsd4: fix corruption of returned data when using 64k pages NeilBrown
2006-04-03  5:18 ` [PATCH 009 of 16] knfsd: nfsd4: fix corruption on readdir encoding with " NeilBrown
2006-04-03  5:18 ` [PATCH 010 of 16] knfsd: svcrpc: gss: don't call svc_take_page unnecessarily NeilBrown
2006-04-03  5:19 ` [PATCH 011 of 16] knfsd: svcrpc: WARN() instead of returning an error from svc_take_page NeilBrown
2006-04-03 22:02   ` Ingo Oeser
2006-04-04  2:26     ` [NFS] " J. Bruce Fields
2006-04-03  5:19 ` [PATCH 012 of 16] knfsd: nfsd4: fix laundromat shutdown race NeilBrown
2006-04-03  5:19 ` [PATCH 013 of 16] knfsd: nfsd4: nfsd4_probe_callback cleanup NeilBrown
2006-04-03  5:19 ` [PATCH 014 of 16] knfsd: nfsd4: add missing rpciod_down() NeilBrown
2006-04-03  5:19 ` [PATCH 015 of 16] knfsd: nfsd4: limit number of delegations handed out NeilBrown
2006-04-03  5:19 ` [PATCH 016 of 16] knfsd: nfsd4: grant delegations more frequently NeilBrown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox