Skip to contentSkip to conversation

kNFSdv4 - 0 of 10 - Introduction

PATCH New NeilBrown 2 participants 16 messages Apr 8, 2004 4 messages not in the archive

Subsystems (3)
lore
Share & tools
lore

NeilBrown

author
#0 lore raw

PATCH 1/1 kNFSdv4 - 0 of 10 - Introduction

Hi Andrew,
here are 10 patches for the NFSv4 server in 2.6-latested. Some relate to the "idmapper" which is used to map between textual identities (used by the protocol) and numerical identitied (i.e. uids). Others relate to better handling of replayed requests.

All are purely nfsv4 which is still "Experimental" and should be as safe as the rest of the nfsv4 server code.

Thanks,
NeilBrown

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#1 lore raw

PATCH 1/1 kNFSdv4 - 1 of 10 - idmap bugfixes and cleanup

From: "J. Bruce Fields" <[email protected]>

Fix race conditions and leaks on error; split up code a bit to make it easier to verify correctness.

----------- Diffstat output ------------

 ./fs/nfsd/nfs4idmap.c |  100 ++++++++++++++++++++++++++++++++------------------
 1 files changed, 65 insertions(+), 35 deletions(-)
fs/nfsd/nfs4idmap.c renamed from fs/nfsd/nfs4idmap.c~current~ +65 -35
diff ./fs/nfsd/nfs4idmap.c~current~ ./fs/nfsd/nfs4idmap.c
@@ -412,8 +412,12 @@ struct idmap_defer_req {
 static void
 put_mdr(struct idmap_defer_req *mdr)
 {
+	wait_queue_head_t	*waitq = &mdr->waitq;
+
 	if (atomic_dec_and_test(&mdr->count))
 		kfree(mdr);
+	else
+		wake_up(waitq);
 }
 
 static void
@@ -422,7 +426,6 @@ idmap_revisit(struct cache_deferred_req 
 	struct idmap_defer_req *mdr =
 		container_of(dreq, struct idmap_defer_req, deferred_req);
 
-	wake_up(&mdr->waitq);
 	put_mdr(mdr);
 }
 
@@ -438,65 +441,92 @@ idmap_defer(struct cache_req *req)
 
 static int threads_waiting = 0;
 
-static inline int
-idmap_lookup_wait(struct idmap_defer_req *mdr, wait_queue_t waitq, struct
-		svc_rqst *rqstp) {
-	int ret = -ETIMEDOUT;
+static inline void
+idmap_wait(struct idmap_defer_req *mdr, struct svc_rqst *rqstp) {
 
-	set_task_state(current, TASK_INTERRUPTIBLE);
+	/* Note: BKL prevents races with nfsd_svc and other lookups */
 	lock_kernel();
 	/* XXX: Does it matter that threads_waiting isn't per-server? */
-	/* Note: BKL prevents races with nfsd_svc and other lookups */
 	if (2 * threads_waiting > rqstp->rq_server->sv_nrthreads)
 		goto out;
 	threads_waiting++;
 	schedule_timeout(10 * HZ);
 	threads_waiting--;
-	ret = 0;
 out:
 	unlock_kernel();
-	remove_wait_queue(&mdr->waitq, &waitq);
-	set_task_state(current, TASK_RUNNING);
 	put_mdr(mdr);
+}
+
+static inline int
+do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *, int), struct ent *key,
+		struct cache_detail *detail, struct ent **item,
+		struct idmap_defer_req *mdr)
+{
+	*item = lookup_fn(key, 0);
+	if (!*item)
+		return -ENOMEM;
+	return cache_check(detail, &(*item)->h, &mdr->req);
+}
+
+static inline int
+do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *, int),
+			struct ent *key, struct cache_detail *detail,
+			struct ent **item)
+{
+	int ret = -ENOMEM;
+
+	*item = lookup_fn(key, 0);
+	if (!*item)
+		goto out_err;
+	ret = -ETIMEDOUT;
+	if (!test_bit(CACHE_VALID, &(*item)->h.flags)
+			|| (*item)->h.expiry_time < get_seconds()
+			|| detail->flush_time > (*item)->h.last_refresh)
+		goto out_put;
+	ret = -ENOENT;
+	if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags))
+		goto out_put;
+	return 0;
+out_put:
+	ent_put(&(*item)->h, detail);
+out_err:
+	*item = NULL;
 	return ret;
 }
 
+static inline void
+init_mdr(struct idmap_defer_req *mdr, wait_queue_t *waitq)
+{
+
+	memset(mdr, 0, sizeof(*mdr));
+	init_waitqueue_head(&mdr->waitq);
+	add_wait_queue(&mdr->waitq, waitq);
+	atomic_set(&mdr->count, 2);
+	mdr->req.defer = idmap_defer;
+}
+
 static int
 idmap_lookup(struct svc_rqst *rqstp,
 		struct ent *(*lookup_fn)(struct ent *, int), struct ent *key,
 		struct cache_detail *detail, struct ent **item)
 {
-	struct idmap_defer_req *mdr;
 	DECLARE_WAITQUEUE(waitq, current);
+	struct idmap_defer_req *mdr;
 	int ret;
 
-	*item = lookup_fn(key, 0);
-	if (!*item)
-		return -ENOMEM;
 	mdr = kmalloc(sizeof(*mdr), GFP_KERNEL);
-	memset(mdr, 0, sizeof(*mdr));
-	init_waitqueue_head(&mdr->waitq);
-	add_wait_queue(&mdr->waitq, &waitq);
-	atomic_set(&mdr->count, 2);
-	mdr->req.defer = idmap_defer;
-	ret = cache_check(detail, &(*item)->h, &mdr->req);
+	if (!mdr)
+		return -ENOMEM;
+	init_mdr(mdr, &waitq);
+	set_task_state(current, TASK_INTERRUPTIBLE);
+	ret = do_idmap_lookup(lookup_fn, key, detail, item, mdr);
 	if (ret == -EAGAIN) {
-		ret = idmap_lookup_wait(mdr, waitq, rqstp);
-		if (ret)
-			goto out;
-		/* Try again, but don't wait. */
-		*item = lookup_fn(key, 0);
-		ret = -ENOMEM;
-		if (!*item)
-			goto out;
-		ret = -ETIMEDOUT;
-		if (!test_bit(CACHE_VALID, &(*item)->h.flags)) {
-			ent_put(&(*item)->h, detail);
-			goto out;
-		}
-		ret = cache_check(detail, &(*item)->h, NULL);
+		idmap_wait(mdr, rqstp);
+		ret = do_idmap_lookup_nowait(lookup_fn, key, detail, item);
+	} else {
+		put_mdr(mdr);
+		put_mdr(mdr);
 	}
-out:
 	return ret;
 }
 

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

A message that is not in the archive (sent off-list or not yet received): [email protected]

#3 lore raw

Re: [PATCH] kNFSdv4 - 1 of 10 - idmap bugfixes and cleanup

Quoted 6 lines · Andrew Morton

Random observations which may be wrong:

- If two CPUs run put_mdr() at the same time, one of them can do wake_up() of a now-kfreed pointer. This function requires higher-level locking of some form.

Argh, there isn't any, so you're right of course, thanks.

So I just use a spinlock. That also makes the atomic_t superfluous. Here's an incremental patch.

--b.

 fs/nfsd/nfs4idmap.c |   15 +++++++++------
 1 files changed, 9 insertions(+), 6 deletions(-)
fs/nfsd/nfs4idmap.c renamed from fs/nfsd/nfs4idmap.c~nfsd_idmap_mdr_put_fix +9 -6
diff -puN fs/nfsd/nfs4idmap.c~nfsd_idmap_mdr_put_fix fs/nfsd/nfs4idmap.c
@@ -406,18 +406,21 @@ struct idmap_defer_req {
        struct cache_req		req;
        struct cache_deferred_req deferred_req;
        wait_queue_head_t	waitq;
-       atomic_t			count;
+       int			count;
 };
 
+static spinlock_t mdr_lock = SPIN_LOCK_UNLOCKED;
+
 static void
 put_mdr(struct idmap_defer_req *mdr)
 {
-	wait_queue_head_t	*waitq = &mdr->waitq;
-
-	if (atomic_dec_and_test(&mdr->count))
+	spin_lock(&mdr_lock);
+	mdr->count--;
+	if (mdr->count == 0)
 		kfree(mdr);
 	else
-		wake_up(waitq);
+		wake_up(&mdr->waitq);
+	spin_unlock(&mdr_lock);
 }
 
 static void
@@ -501,7 +504,7 @@ init_mdr(struct idmap_defer_req *mdr, wa
 	memset(mdr, 0, sizeof(*mdr));
 	init_waitqueue_head(&mdr->waitq);
 	add_wait_queue(&mdr->waitq, waitq);
-	atomic_set(&mdr->count, 2);
+	mdr->count = 2;
 	mdr->req.defer = idmap_defer;
 }
 

_

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

#4 lore raw

Re: [PATCH] kNFSdv4 - 1 of 10 - idmap bugfixes and cleanup

In reply to a message not in the archive
Quoted 2 lines · Andrew Morton

- Cannot idmap_lookup() return in state TASK_UNINTERRUPTIBLE?

I assume you meant TASK_INTERRUPTIBLE.

After the

	set_task_state(current, TASK_INTERRUPTIBLE);

either put_mdr, or idmap_wait (which always calls put_mdr) is called, and put_mdr does a wake_up. So I believe this is correct, though I do wish it was clearer.

--b.

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

A message that is not in the archive (sent off-list or not yet received): [email protected]

#6 lore raw

Re: [PATCH] kNFSdv4 - 1 of 10 - idmap bugfixes and cleanup

Quoted 10 lines · Andrew Morton
Quoted 7 lines · J. Bruce Fields

After the

	set_task_state(current, TASK_INTERRUPTIBLE);

either put_mdr, or idmap_wait (which always calls put_mdr) is called, and put_mdr does a wake_up. So I believe this is correct, though I do wish it was clearer.

wake_up() doesn't alter the caller's task->state.

The caller is on the waitqueue in this case.

But now that I look at it more carefully, there's more serious problems; it'll take another day for me to get this right, sorry; drop the idmap patches or not, and that particular code is in almost equally bad shape....

--b.

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

A message that is not in the archive (sent off-list or not yet received): [email protected]

#8 lore raw

Re: [PATCH] kNFSdv4 - 1 of 10 - idmap bugfixes and cleanup

Quoted 1 line · Andrew Morton

What do you want me to do?

Could you just drop the first 4 for now? Thanks.

Quoted 4 lines

kNFSdv4-1-of-10-idmap-bugfixes-and-cleanup.patch nfsd_idmap_mdr_put_fix.patch kNFSdv4-2-of-10-better-handling-of-failed-idmap-lookups.patch kNFSdv4-3-of-10-complain-if-idmapd-doesnt-have-channel-open.patch

And then I'll just resubmit those through Neil when they're fixed. Sorry about that.--b.

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#9 lore raw

PATCH 1/1 kNFSdv4 - 2 of 10 - better handling of failed idmap lookups

In reply to NeilBrown

From: "J. Bruce Fields" <[email protected]>

Slightly better behavior on failed mapping (which may happen either because idmapd is not running, or because there it has told us it doesn't know the mapping.):
on name->id (setattr), return BADNAME. (I used ESRCH to
communicate BADNAME, just because it was the first error in include/asm-generic/errno-base.h that had something to do with nonexistance of something, and that we weren't already using.)
id->name (getattr), return a string representation of the numerical
id. This is probably useless to the client, especially since we're unlikely to accept such a string on a setattr, but perhaps some client will find it mildly helpful.

----------- Diffstat output ------------

 ./fs/nfsd/nfs4idmap.c       |    4 ++++
 ./fs/nfsd/nfsproc.c         |    1 +
 ./include/linux/nfsd/nfsd.h |    1 +
 3 files changed, 6 insertions(+)
fs/nfsd/nfs4idmap.c renamed from fs/nfsd/nfs4idmap.c~current~ +4 -0
diff ./fs/nfsd/nfs4idmap.c~current~ ./fs/nfsd/nfs4idmap.c
@@ -545,6 +545,8 @@ idmap_name_to_id(struct svc_rqst *rqstp,
 	key.name[namelen] = '\0';
 	strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
 	ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item);
+	if (ret == -ENOENT)
+		ret = -ESRCH; /* nfserr_badname */
 	if (ret)
 		return ret;
 	*id = item->id;
@@ -563,6 +565,8 @@ idmap_id_to_name(struct svc_rqst *rqstp,
 
 	strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
 	ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item);
+	if (ret == -ENOENT)
+		return sprintf(name, "%u", id);
 	if (ret)
 		return ret;
 	ret = strlen(item->name);
fs/nfsd/nfsproc.c renamed from fs/nfsd/nfsproc.c~current~ +1 -0
diff ./fs/nfsd/nfsproc.c~current~ ./fs/nfsd/nfsproc.c
@@ -588,6 +588,7 @@ nfserrno (int errno)
 		{ nfserr_jukebox, -ETIMEDOUT },
 		{ nfserr_dropit, -EAGAIN },
 		{ nfserr_dropit, -ENOMEM },
+		{ nfserr_badname, -ESRCH },
 		{ -1, -EIO }
 	};
 	int	i;
include/linux/nfsd/nfsd.h renamed from include/linux/nfsd/nfsd.h~current~ +1 -0
diff ./include/linux/nfsd/nfsd.h~current~ ./include/linux/nfsd/nfsd.h
@@ -196,6 +196,7 @@ void		nfsd_lockd_shutdown(void);
 #define	nfserr_openmode		__constant_htonl(NFSERR_OPENMODE)
 #define	nfserr_locks_held	__constant_htonl(NFSERR_LOCKS_HELD)
 #define	nfserr_op_illegal	__constant_htonl(NFSERR_OP_ILLEGAL)
+#define nfserr_badname		__constant_htonl(NFSERR_BADNAME)
 
 /* error codes for internal use */
 /* if a request fails due to kmalloc failure, it gets dropped.

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#10 lore raw

PATCH 1/1 kNFSdv4 - 3 of 10 - complain if idmapd doesn't have channel open

In reply to NeilBrown

From: "J. Bruce Fields" <[email protected]>

Currently if a user mounts a server that doesn't have idmapd running, the mount may block for 10 seconds to a minute, and there's no useful errors on the client or server side.

Help out by:
1) Failing lookups immediately whenever no process has opened the files in idmapd that are used to do idmapping upcalls.
2) Doing a printk() in this situation so they know idmapd needs to be run.

----------- Diffstat output ------------

 ./fs/nfsd/nfs4idmap.c |   15 +++++++++++++++
 1 files changed, 15 insertions(+)
fs/nfsd/nfs4idmap.c renamed from fs/nfsd/nfs4idmap.c~current~ +15 -0
diff ./fs/nfsd/nfs4idmap.c~current~ ./fs/nfsd/nfs4idmap.c
@@ -505,6 +505,17 @@ init_mdr(struct idmap_defer_req *mdr, wa
 	mdr->req.defer = idmap_defer;
 }
 
+static inline void
+warn_no_idmapd(void) {
+	static time_t last_warning = 0;
+
+	if (last_warning < get_seconds() - 60) {
+		last_warning = get_seconds();
+		printk(KERN_WARNING "nfsd: idmap failing; check if idmapd"
+				" is running?\n");
+	}
+}
+
 static int
 idmap_lookup(struct svc_rqst *rqstp,
 		struct ent *(*lookup_fn)(struct ent *, int), struct ent *key,
@@ -514,6 +525,10 @@ idmap_lookup(struct svc_rqst *rqstp,
 	struct idmap_defer_req *mdr;
 	int ret;
 
+	if (atomic_read(&detail->readers) == 0) {
+		warn_no_idmapd();
+		return -ENOENT;
+	}
 	mdr = kmalloc(sizeof(*mdr), GFP_KERNEL);
 	if (!mdr)
 		return -ENOMEM;

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#11 lore raw

PATCH 1/1 kNFSdv4 - 5 of 10 - Fix bad error returm from svcauth_gss_accept

In reply to NeilBrown

From: "J. Bruce Fields" <[email protected]>

Error return when the client supplies a bad service should be badcred.

----------- Diffstat output ------------

 ./net/sunrpc/auth_gss/svcauth_gss.c |    1 +
 1 files changed, 1 insertion(+)
net/sunrpc/auth_gss/svcauth_gss.c renamed from net/sunrpc/auth_gss/svcauth_gss.c~current~ +1 -0
diff ./net/sunrpc/auth_gss/svcauth_gss.c~current~ ./net/sunrpc/auth_gss/svcauth_gss.c
@@ -895,6 +895,7 @@ svcauth_gss_accept(struct svc_rqst *rqst
 		svc_putu32(resv, rpc_success);
 		goto complete;
 	case RPC_GSS_PROC_DATA:
+		*authp = rpc_autherr_badcred;
 		rqstp->rq_client =
 			find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
 		if (rqstp->rq_client == NULL)

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#12 lore raw

PATCH 1/1 kNFSdv4 - 9 of 10 - Set credentials properly when puutrootfh is used

In reply to NeilBrown

The credentials (uid/gid) of a process are set when a filehandle is verified. Nfsv4 allows requests without an explicit filehandle (instead, an implicit 'root' filehandle) so we much make sure the credentials are set for these requests too.

From: "J. Bruce Fields" <[email protected]>

Quoted 1 line

From Andros: added a call to nfsd_setuser in nfsd4_putrootfh so that nfsd runs

as the rpc->cred user.

----------- Diffstat output ------------

 ./fs/nfsd/nfs4proc.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletion(-)
fs/nfsd/nfs4proc.c renamed from fs/nfsd/nfs4proc.c~current~ +6 -1
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
@@ -194,9 +194,14 @@ nfsd4_putfh(struct svc_rqst *rqstp, stru
 static inline int
 nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh)
 {
+	int status;
+
 	fh_put(current_fh);
-	return exp_pseudoroot(rqstp->rq_client, current_fh,
+	status = exp_pseudoroot(rqstp->rq_client, current_fh,
 			      &rqstp->rq_chandle);
+	if (!status)
+		status = nfsd_setuser(rqstp, current_fh->fh_export);
+	return status;
 }
 
 static inline int

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#13 lore raw

PATCH 1/1 kNFSdv4 - 7 of 10 - Allow locku replays aswell

In reply to NeilBrown

From: "J. Bruce Fields" <[email protected]>

Quoted 1 line

From Andros: locku replies should be saved for possible replay as well.

----------- Diffstat output ------------

 ./fs/nfsd/nfs4proc.c |    1 +
 1 files changed, 1 insertion(+)
fs/nfsd/nfs4proc.c renamed from fs/nfsd/nfs4proc.c~current~ +1 -0
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
@@ -789,6 +789,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 			break;
 		case OP_LOCKU:
 			op->status = nfsd4_locku(rqstp, &current_fh, &op->u.locku);
+			op->replay = &op->u.locku.lu_stateowner->so_replay;
 			break;
 		case OP_LOOKUP:
 			op->status = nfsd4_lookup(rqstp, &current_fh, &op->u.lookup);

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#14 lore raw

PATCH 1/1 kNFSdv4 - 4 of 10 - nfsd4_readdir fixes

In reply to NeilBrown

From: "J. Bruce Fields" <[email protected]>

Fix out-of-spec errors in nfs4 readdir. Add checks for bad cookie values.

----------- Diffstat output ------------

 ./fs/nfsd/nfs4proc.c |    8 +++++++-
 ./fs/nfsd/nfs4xdr.c  |    2 ++
 2 files changed, 9 insertions(+), 1 deletion(-)
fs/nfsd/nfs4proc.c renamed from fs/nfsd/nfs4proc.c~current~ +7 -1
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
@@ -448,6 +448,11 @@ out:
 static inline int
 nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir)
 {
+	u64 cookie = readdir->rd_cookie;
+	static const nfs4_verifier zeroverf = {
+		.data[0] = 0,
+	};
+
 	/* no need to check permission - this will be done in nfsd_readdir() */
 
 	if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
@@ -456,7 +461,8 @@ nfsd4_readdir(struct svc_rqst *rqstp, st
 	readdir->rd_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
 	readdir->rd_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;
 
-	if (readdir->rd_cookie > ~(u32)0)
+	if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) ||
+	    (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
 		return nfserr_bad_cookie;
 
 	readdir->rd_rqstp = rqstp;
fs/nfsd/nfs4xdr.c renamed from fs/nfsd/nfs4xdr.c~current~ +2 -0
diff ./fs/nfsd/nfs4xdr.c~current~ ./fs/nfsd/nfs4xdr.c
@@ -2179,6 +2179,8 @@ nfsd4_encode_readdir(struct nfsd4_compou
 	    readdir->common.err == nfserr_toosmall &&
 	    readdir->buffer == page) 
 		nfserr = nfserr_toosmall;
+	if (nfserr == nfserr_symlink)
+		nfserr = nfserr_notdir;
 	if (nfserr)
 		goto err_no_verf;
 

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#15 lore raw

PATCH 1/1 kNFSdv4 - 10 of 10 - Implement server-side reboot recovery (mostly)

In reply to NeilBrown

From: "J. Bruce Fields" <[email protected]>

Quoted 1 line

From Andros: Implement server-side reboot recovery (server now handles open and

lock reclaims). Not completely to spec: we don't yet store the state in stable storage that would be required to recover correctly in certain situations.

----------- Diffstat output ------------

 ./fs/nfsd/nfs4proc.c         |  102 +++++++++++++++++++++++++++++++++++++------
 ./fs/nfsd/nfs4state.c        |   53 +++++++++++++++++++---
 ./include/linux/nfsd/nfsd.h  |    3 +
 ./include/linux/nfsd/state.h |    2 
 4 files changed, 140 insertions(+), 20 deletions(-)
fs/nfsd/nfs4proc.c renamed from fs/nfsd/nfs4proc.c~current~ +88 -14
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
@@ -66,10 +66,31 @@ fh_dup2(struct svc_fh *dst, struct svc_f
 }
 
 static int
+do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+{
+	int accmode, status;
+
+	if (open->op_truncate && 
+		!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
+		return nfserr_inval;
+
+	accmode = MAY_NOP;
+	if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
+		accmode = MAY_READ;
+	if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE)
+		accmode |= (MAY_WRITE | MAY_TRUNC);
+	accmode |= MAY_OWNER_OVERRIDE;
+
+	status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
+
+	return status;
+}
+
+static int
 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
 	struct svc_fh resfh;
-	int accmode, status;
+	int status;
 
 	fh_init(&resfh, NFS4_FHSIZE);
 	open->op_truncate = 0;
@@ -92,6 +113,8 @@ do_open_lookup(struct svc_rqst *rqstp, s
 
 	if (!status) {
 		set_change_info(&open->op_cinfo, current_fh);
+
+		/* set reply cache */
 		fh_dup2(current_fh, &resfh);
 		/* XXXJBF: keep a saved svc_fh struct instead?? */
 		open->op_stateowner->so_replay.rp_openfh_len =
@@ -100,19 +123,41 @@ do_open_lookup(struct svc_rqst *rqstp, s
 				&resfh.fh_handle.fh_base,
 				resfh.fh_handle.fh_size);
 
-		accmode = MAY_NOP;
-		if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
-			accmode = MAY_READ;
-		if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE)
-			accmode |= (MAY_WRITE | MAY_TRUNC);
-		accmode |= MAY_OWNER_OVERRIDE;
-		status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
+		status = do_open_permission(rqstp, current_fh, open);
 	}
 
 	fh_put(&resfh);
 	return status;
 }
 
+static int
+do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+{
+	int status;
+
+	dprintk("NFSD: do_open_fhandle\n");
+
+	/* we don't know the target directory, and therefore can not
+	* set the change info
+	*/
+
+	memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));
+
+	/* set replay cache */
+	open->op_stateowner->so_replay.rp_openfh_len = current_fh->fh_handle.fh_size;
+	memcpy(open->op_stateowner->so_replay.rp_openfh,
+		&current_fh->fh_handle.fh_base,
+		current_fh->fh_handle.fh_size);
+
+	open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
+	!open->op_iattr.ia_size;
+
+	status = do_open_permission(rqstp, current_fh, open);
+
+	return status;
+}
+
+
 /*
  * nfs4_unlock_state() called in encode
  */
@@ -124,6 +169,13 @@ nfsd4_open(struct svc_rqst *rqstp, struc
 		(int)open->op_fname.len, open->op_fname.data,
 		open->op_stateowner);
 
+	if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+		return nfserr_grace;
+
+	if (nfs4_in_no_grace() &&
+		           open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+		return nfserr_no_grace;
+
 	/* This check required by spec. */
 	if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
 		return nfserr_inval;
@@ -148,16 +200,30 @@ nfsd4_open(struct svc_rqst *rqstp, struc
 	}
 	if (status)
 		return status;
+	if (open->op_claim_type == NFS4_OPEN_CLAIM_NULL) {
 	/*
 	 * This block of code will (1) set CURRENT_FH to the file being opened,
 	 * creating it if necessary, (2) set open->op_cinfo, 
 	 * (3) set open->op_truncate if the file is to be truncated 
 	 * after opening, (4) do permission checking.
 	 */
-	status = do_open_lookup(rqstp, current_fh, open);
-	if (status)
-		return status;
-
+		status = do_open_lookup(rqstp, current_fh, open);
+		if (status)
+			return status;
+	} else if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
+	/*
+	* The CURRENT_FH is already set to the file being opened. This 
+	* block of code will (1) set open->op_cinfo, (2) set 
+	* open->op_truncate if the file is to be truncated after opening, 
+	* (3) do permission checking.
+	*/
+		status = do_open_fhandle(rqstp, current_fh, open);
+		if (status)
+			return status;
+	} else {
+		printk("NFSD: unsupported OPEN claim type\n");
+		return nfserr_inval;
+	}
 	/*
 	 * nfsd4_process_open2() does the actual opening of the file.  If
 	 * successful, it (1) truncates the file if open->op_truncate was
@@ -414,6 +480,8 @@ nfsd4_read(struct svc_rqst *rqstp, struc
 	int status;
 
 	/* no need to check permission - this will be done in nfsd_read() */
+	if (nfs4_in_grace())
+		return nfserr_grace;
 
 	if (read->rd_offset >= OFFSET_MAX)
 		return nfserr_inval;
@@ -539,10 +607,13 @@ static inline int
 nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr)
 {
 	struct nfs4_stateid *stp;
-	int status = nfserr_nofilehandle;
+	int status = nfs_ok;
+
+	if (nfs4_in_grace())
+		return nfserr_grace;
 
 	if (!current_fh->fh_dentry)
-		goto out;
+		return nfserr_nofilehandle;
 
 	status = nfs_ok;
 	if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
@@ -581,6 +652,9 @@ nfsd4_write(struct svc_rqst *rqstp, stru
 	u32 *p;
 	int status = nfs_ok;
 
+	if (nfs4_in_grace())
+		return nfserr_grace;
+
 	/* no need to check permission - this will be done in nfsd_write() */
 
 	if (write->wr_offset >= OFFSET_MAX)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +47 -6

138 lines not on this page · raw message

include/linux/nfsd/nfsd.h renamed from include/linux/nfsd/nfsd.h~current~ +3 -0
diff ./include/linux/nfsd/nfsd.h~current~ ./include/linux/nfsd/nfsd.h
@@ -197,6 +197,9 @@ void		nfsd_lockd_shutdown(void);
 #define	nfserr_locks_held	__constant_htonl(NFSERR_LOCKS_HELD)
 #define	nfserr_op_illegal	__constant_htonl(NFSERR_OP_ILLEGAL)
 #define nfserr_badname		__constant_htonl(NFSERR_BADNAME)
+#define	nfserr_grace		__constant_htonl(NFSERR_GRACE)
+#define	nfserr_no_grace		__constant_htonl(NFSERR_NO_GRACE)
+#define	nfserr_reclaim_bad	__constant_htonl(NFSERR_RECLAIM_BAD)
 
 /* error codes for internal use */
 /* if a request fails due to kmalloc failure, it gets dropped.
include/linux/nfsd/state.h renamed from include/linux/nfsd/state.h~current~ +2 -0
diff ./include/linux/nfsd/state.h~current~ ./include/linux/nfsd/state.h
@@ -215,4 +215,6 @@ extern int nfs4_share_conflict(struct sv
 		unsigned int deny_type);
 extern void nfs4_lock_state(void);
 extern void nfs4_unlock_state(void);
+extern int nfs4_in_grace(void);
+extern int nfs4_in_no_grace(void);
 #endif   /* NFSD4_STATE_H */

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#16 lore raw

PATCH 1/1 kNFSdv4 - 6 of 10 - Keep state to allow replays for 'close' to work.

In reply to NeilBrown

From: "J. Bruce Fields" <[email protected]>

Quoted 1 line

From Andros: Idea is to keep around a list of openowners recently released by

closes, and make sure they stay around long enough so that replays still work.

----------- Diffstat output ------------

 ./fs/nfsd/nfs4state.c        |   85 +++++++++++++++++++++++++++++++------------
 ./include/linux/nfsd/state.h |    6 +++
 2 files changed, 69 insertions(+), 22 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +63 -22
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -136,12 +136,16 @@ static void release_file(struct nfs4_fil
  *
  * client_lru holds client queue ordered by nfs4_client.cl_time
  * for lease renewal.
+ *
+ * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
+ * for last close replay.
  */
 static struct list_head	conf_id_hashtbl[CLIENT_HASH_SIZE];
 static struct list_head	conf_str_hashtbl[CLIENT_HASH_SIZE];
 static struct list_head	unconf_str_hashtbl[CLIENT_HASH_SIZE];
 static struct list_head	unconf_id_hashtbl[CLIENT_HASH_SIZE];
 static struct list_head client_lru;
+static struct list_head close_lru;
 
 static inline void
 renew_client(struct nfs4_client *clp)
@@ -774,6 +778,8 @@ alloc_init_open_stateowner(unsigned int 
 	INIT_LIST_HEAD(&sop->so_perclient);
 	INIT_LIST_HEAD(&sop->so_perfilestate);
 	INIT_LIST_HEAD(&sop->so_perlockowner);  /* not used */
+	INIT_LIST_HEAD(&sop->so_close_lru);
+	sop->so_time = 0;
 	list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);
 	list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
 	list_add(&sop->so_perclient, &clp->cl_perclient);
@@ -814,6 +820,7 @@ release_stateowner(struct nfs4_stateowne
 	list_del(&sop->so_strhash);
 	list_del(&sop->so_perclient);
 	list_del(&sop->so_perlockowner);
+	list_del(&sop->so_close_lru);
 	del_perclient++;
 	while (!list_empty(&sop->so_perfilestate)) {
 		stp = list_entry(sop->so_perfilestate.next, 
@@ -882,6 +889,19 @@ release_file(struct nfs4_file *fp)
 }	
 
 void
+move_to_close_lru(struct nfs4_stateowner *sop)
+{
+	dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);
+	/* remove stateowner from all other hash lists except perclient */
+	list_del_init(&sop->so_idhash);
+	list_del_init(&sop->so_strhash);
+	list_del_init(&sop->so_perlockowner);
+
+        list_add_tail(&sop->so_close_lru, &close_lru);
+        sop->so_time = get_seconds();
+}
+
+void
 release_state_owner(struct nfs4_stateid *stp, struct nfs4_stateowner **sopp,
 		int flag)
 {
@@ -890,16 +910,13 @@ release_state_owner(struct nfs4_stateid 
 
 	dprintk("NFSD: release_state_owner\n");
 	release_stateid(stp, flag);
-	/*
-	 * release unused nfs4_stateowners.
-	 * XXX will need to be placed  on an  open_stateid_lru list to be
+
+	/* place unused nfs4_stateowners on so_close_lru list to be
 	 * released by the laundromat service after the lease period
 	 * to enable us to handle CLOSE replay
 	 */
-	if (sop->so_confirmed && list_empty(&sop->so_perfilestate)) {
-		release_stateowner(sop);
-		*sopp = NULL;
-	}
+	if (sop->so_confirmed && list_empty(&sop->so_perfilestate))
+		move_to_close_lru(sop);
 	/* unused nfs4_file's are releseed. XXX slab cache? */
 	if (list_empty(&fp->fi_perfile)) {
 		release_file(fp);
@@ -1316,9 +1333,11 @@ time_t
 nfs4_laundromat(void)
 {
 	struct nfs4_client *clp;
+	struct nfs4_stateowner *sop;
 	struct list_head *pos, *next;
 	time_t cutoff = get_seconds() - NFSD_LEASE_TIME;
-	time_t t, return_val = NFSD_LEASE_TIME;
+	time_t t, clientid_val = NFSD_LEASE_TIME;
+	time_t u, close_val = NFSD_LEASE_TIME;
 
 	nfs4_lock_state();
 
@@ -1327,18 +1346,30 @@ nfs4_laundromat(void)
 		clp = list_entry(pos, struct nfs4_client, cl_lru);
 		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
 			t = clp->cl_time - cutoff;
-			if (return_val > t)
-				return_val = t;
+			if (clientid_val > t)
+				clientid_val = t;
 			break;
 		}
 		dprintk("NFSD: purging unused client (clientid %08x)\n",
 			clp->cl_clientid.cl_id);
 		expire_client(clp);
 	}
-	if (return_val < NFSD_LAUNDROMAT_MINTIMEOUT)
-		return_val = NFSD_LAUNDROMAT_MINTIMEOUT;
+	list_for_each_safe(pos, next, &close_lru) {
+		sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);
+		if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) {
+			u = sop->so_time - cutoff;
+			if (close_val > u)
+				close_val = u;
+			break;
+		}
+		dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
+			sop->so_id);
+		release_stateowner(sop);
+	}
+	if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
+		clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
 	nfs4_unlock_state();
-	return return_val;
+	return clientid_val;
 }
 
 void
@@ -1351,17 +1382,22 @@ laundromat_main(void *not_used)
 	schedule_delayed_work(&laundromat_work, t*HZ);
 }
 
-/* search ownerid_hashtbl[] for stateid owner (stateid->si_stateownerid) */
+/* search ownerid_hashtbl[] and close_lru for stateid owner 
+ * (stateid->si_stateownerid) 
+ */
 struct nfs4_stateowner *
-find_openstateowner_id(u32 st_id) {
+find_openstateowner_id(u32 st_id, int flags) {
 	struct list_head *pos, *next;
 	struct nfs4_stateowner *local = NULL;
-	unsigned int hashval = ownerid_hashval(st_id);
 
-	list_for_each_safe(pos, next, &ownerid_hashtbl[hashval]) {
-		local = list_entry(pos, struct nfs4_stateowner, so_idhash);
-		if(local->so_id == st_id)
-			return local;
+	dprintk("NFSD: find_openstateowner_id %d\n", st_id);
+	if (flags & CLOSE_STATE) {
+		list_for_each_safe(pos, next, &close_lru) {
+			local = list_entry(pos, struct nfs4_stateowner, 
+			                    so_close_lru);
+			if(local->so_id == st_id)
+				return local;
+		}
 	}
 	return NULL;
 }
@@ -1547,11 +1583,12 @@ no_nfs4_stateid:
 	* starting by trying to look up the stateowner.
 	* If stateowner is not found - stateid is bad.
 	*/
-	if (!(sop = find_openstateowner_id(stateid->si_stateownerid))) {
+	if (!(sop = find_openstateowner_id(stateid->si_stateownerid, flags))) {
 		printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");
 		status = nfserr_bad_stateid;
 		goto out;
 	}
+	*sopp = sop;
 
 check_replay:
 	if (seqid == sop->so_seqid) {
@@ -1690,9 +1727,10 @@ nfsd4_close(struct svc_rqst *rqstp, stru
 			current_fh->fh_dentry->d_name.name);
 
 	nfs4_lock_state();
+	/* check close_lru for replay */
 	if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid, 
 					&close->cl_stateid, 
-					CHECK_FH | OPEN_STATE, 
+					CHECK_FH | OPEN_STATE | CLOSE_STATE, 
 					&close->cl_stateowner, &stp, NULL)))
 		goto out; 
 	/*
@@ -1854,6 +1892,8 @@ alloc_init_lock_stateowner(unsigned int 
 	INIT_LIST_HEAD(&sop->so_perclient);
 	INIT_LIST_HEAD(&sop->so_perfilestate);
 	INIT_LIST_HEAD(&sop->so_perlockowner);
+	INIT_LIST_HEAD(&sop->so_close_lru); /* not used */
+	sop->so_time = 0;
 	list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);
 	list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);
 	list_add(&sop->so_perclient, &clp->cl_perclient);
@@ -2351,6 +2391,7 @@ nfs4_state_init(void)
 	memset(&zerostateid, 0, sizeof(stateid_t));
 	memset(&onestateid, ~0, sizeof(stateid_t));
 
+	INIT_LIST_HEAD(&close_lru);
 	INIT_LIST_HEAD(&client_lru);
 	init_MUTEX(&client_sema);
 	boot_time = get_seconds();
include/linux/nfsd/state.h renamed from include/linux/nfsd/state.h~current~ +6 -0
diff ./include/linux/nfsd/state.h~current~ ./include/linux/nfsd/state.h
@@ -132,6 +132,9 @@ struct nfs4_replay {
 *         release a stateowner.
 *    so_perlockowner: (open) nfs4_stateid->st_perlockowner entry - used when
 *         close is called to reap associated byte-range locks
+*    so_close_lru: (open) stateowner is placed on this list instead of being
+*         reaped (when so_perfilestate is empty) to hold the last close replay.
+*         reaped by laundramat thread after lease period.
 */
 struct nfs4_stateowner {
 	struct list_head        so_idhash;   /* hash by so_id */
@@ -139,6 +142,8 @@ struct nfs4_stateowner {
 	struct list_head        so_perclient; /* nfs4_client->cl_perclient */
 	struct list_head        so_perfilestate; /* list: nfs4_stateid */
 	struct list_head        so_perlockowner; /* nfs4_stateid->st_perlockowner */
+	struct list_head	so_close_lru; /* tail queue */
+	time_t			so_time; /* time of placement on so_close_lru */
 	int			so_is_open_owner; /* 1=openowner,0=lockowner */
 	u32                     so_id;
 	struct nfs4_client *    so_client;
@@ -194,6 +199,7 @@ struct nfs4_stateid {
 #define OPEN_STATE              0x00000004
 #define LOCK_STATE              0x00000008
 #define RDWR_STATE              0x00000010
+#define CLOSE_STATE             0x00000020
 
 #define seqid_mutating_err(err)                       \
 	(((err) != nfserr_stale_clientid) &&    \

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

A message that is not in the archive (sent off-list or not yet received): [email protected]

#18 lore raw

Re: [PATCH] kNFSdv4 - 6 of 10 - Keep state to allow replays for 'close' to work.

Quoted 14 lines · Andrew Morton

Review

Quoted 10 lines · NeilBrown
(quoted diff) +1 -0
+	dprintk("NFSD: find_openstateowner_id %d\n", st_id);
 +	if (flags & CLOSE_STATE) {
 +		list_for_each_safe(pos, next, &close_lru) {
 +			local = list_entry(pos, struct nfs4_stateowner, 
 +			                    so_close_lru);
 +			if(local->so_id == st_id)
 +				return local;
 +		}
  	}

list_for_each() is adequate here. list_for_each_safe() is only needed if you're removing things from the list inside the body of the loop.

Someone was very fond of list_for_each_safe(). The following (applies on top of the above) removes all the list_for_each_safe()'s in nfs4state.c except for the two that were actually needed.

Quoted 1 line

The locking in here is, err, a little coarse-grained?

Yeah, everything on the server that deals with nfsv4 open and locking state takes a single big semaphore. We should fix that some day.

--b.

 fs/nfsd/nfs4state.c |   70 +++++++++++++---------------------------------------
 1 files changed, 18 insertions(+), 52 deletions(-)

diff -puN fs/nfs/nfs4state.c~nfsd_list_cleanup fs/nfs/nfs4state.c

fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~nfsd_list_cleanup +18 -52
diff -puN fs/nfsd/nfs4state.c~nfsd_list_cleanup fs/nfsd/nfs4state.c
@@ -380,7 +380,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp
 	unsigned int 		strhashval;
 	struct nfs4_client *	conf, * unconf, * new, * clp;
 	int 			status;
-	struct list_head *pos, *next;
 	
 	status = nfserr_inval;
 	if (!check_name(clname))
@@ -395,8 +394,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp
 
 	conf = NULL;
 	nfs4_lock_state();
-	list_for_each_safe(pos, next, &conf_str_hashtbl[strhashval]) {
-		clp = list_entry(pos, struct nfs4_client, cl_strhash);
+	list_for_each_entry(clp, &conf_str_hashtbl[strhashval], cl_strhash) {
 		if (!cmp_name(&clp->cl_name, &clname))
 			continue;
 		/* 
@@ -426,8 +424,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp
 		break;
 	}
 	unconf = NULL;
-	list_for_each_safe(pos, next, &unconf_str_hashtbl[strhashval]) {
-		clp = list_entry(pos, struct nfs4_client, cl_strhash);
+	list_for_each_entry(clp, &unconf_str_hashtbl[strhashval], cl_strhash) {
 		if (!cmp_name(&clp->cl_name, &clname))
 			continue;
 		/* cl_name match from a previous SETCLIENTID operation */
@@ -553,7 +550,6 @@ nfsd4_setclientid_confirm(struct svc_rqs
 	struct nfs4_client *clp, *conf = NULL, *unconf = NULL;
 	nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
 	clientid_t * clid = &setclientid_confirm->sc_clientid;
-	struct list_head *pos, *next;
 	int status;
 
 	status = nfserr_stale_clientid;
@@ -566,8 +562,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
 
 	idhashval = clientid_hashval(clid->cl_id);
 	nfs4_lock_state();
-	list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
-		clp = list_entry(pos, struct nfs4_client, cl_idhash);
+	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
 		if (!cmp_clid(&clp->cl_clientid, clid))
 			continue;
 
@@ -586,8 +581,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
 		conf = clp;
 		break;
 	}
-	list_for_each_safe(pos, next, &unconf_id_hashtbl[idhashval]) {
-		clp = list_entry(pos, struct nfs4_client, cl_idhash);
+	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
 		if (!cmp_clid(&clp->cl_clientid, clid))
 			continue;
 		status = nfserr_inval;
@@ -933,11 +927,9 @@ cmp_owner_str(struct nfs4_stateowner *so
 /* search ownerstr_hashtbl[] for owner */
 static int
 find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, struct nfs4_stateowner **op) {
-	struct list_head *pos, *next;
 	struct nfs4_stateowner *local = NULL;
 
-	list_for_each_safe(pos, next, &ownerstr_hashtbl[hashval]) {
-		local = list_entry(pos, struct nfs4_stateowner, so_strhash);
+	list_for_each_entry(local, &ownerstr_hashtbl[hashval], so_strhash) {
 		if(!cmp_owner_str(local, &open->op_owner, &open->op_clientid)) 
 			continue;
 		*op = local;
@@ -950,12 +942,10 @@ find_openstateowner_str(unsigned int has
 static int
 verify_clientid(struct nfs4_client **client, clientid_t *clid) {
 
-	struct list_head *pos, *next;
 	struct nfs4_client *clp;
 	unsigned int idhashval = clientid_hashval(clid->cl_id);
 
-	list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
-		clp = list_entry(pos, struct nfs4_client, cl_idhash);
+	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
 		if (!cmp_clid(&clp->cl_clientid, clid))
 			continue;
 		*client = clp;
@@ -968,11 +958,9 @@ verify_clientid(struct nfs4_client **cli
 /* search file_hashtbl[] for file */
 static int
 find_file(unsigned int hashval, struct inode *ino, struct nfs4_file **fp) {
-	struct list_head *pos, *next;
 	struct nfs4_file *local = NULL;
 
-	list_for_each_safe(pos, next, &file_hashtbl[hashval]) {
-		local = list_entry(pos, struct nfs4_file, fi_hash);
+	list_for_each_entry(local, &file_hashtbl[hashval], fi_hash) {
 		if (local->fi_inode == ino) {
 			*fp = local;
 			return(1);
@@ -1028,15 +1016,13 @@ nfs4_share_conflict(struct svc_fh *curre
 	unsigned int fi_hashval;
 	struct nfs4_file *fp;
 	struct nfs4_stateid *stp;
-	struct list_head *pos, *next;
 
 	dprintk("NFSD: nfs4_share_conflict\n");
 
 	fi_hashval = file_hashval(ino);
 	if (find_file(fi_hashval, ino, &fp)) {
 	/* Search for conflicting share reservations */
-		list_for_each_safe(pos, next, &fp->fi_perfile) {
-			stp = list_entry(pos, struct nfs4_stateid, st_perfile);
+		list_for_each_entry(stp, &fp->fi_perfile, st_perfile) {
 			if (test_bit(deny_type, &stp->st_deny_bmap) ||
 			    test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
 				return nfserr_share_denied;
@@ -1171,7 +1157,6 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	struct nfs4_file *fp;
 	struct inode *ino;
 	unsigned int fi_hashval;
-	struct list_head *pos, *next;
 	struct nfs4_stateid *stq, *stp = NULL;
 	int status;
 
@@ -1190,8 +1175,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	if (find_file(fi_hashval, ino, &fp)) {
 		/* Search for conflicting share reservations */
 		status = nfserr_share_denied;
-		list_for_each_safe(pos, next, &fp->fi_perfile) {
-		stq = list_entry(pos, struct nfs4_stateid, st_perfile);
+		list_for_each_entry(stq, &fp->fi_perfile, st_perfile) {
 			if(stq->st_stateowner == sop) {
 				stp = stq;
 				continue;
@@ -1291,7 +1275,6 @@ int 
 nfsd4_renew(clientid_t *clid)
 {
 	struct nfs4_client *clp;
-	struct list_head *pos, *next;
 	unsigned int idhashval;
 	int status;
 
@@ -1303,15 +1286,13 @@ nfsd4_renew(clientid_t *clid)
 		goto out;
 	status = nfs_ok;
 	idhashval = clientid_hashval(clid->cl_id);
-	list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
-		clp = list_entry(pos, struct nfs4_client, cl_idhash);
+	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
 		if (!cmp_clid(&clp->cl_clientid, clid))
 			continue;
 		renew_client(clp);
 		goto out;
 	}
-	list_for_each_safe(pos, next, &unconf_id_hashtbl[idhashval]) {
-		clp = list_entry(pos, struct nfs4_client, cl_idhash);
+	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
 		if (!cmp_clid(&clp->cl_clientid, clid))
 			continue;
 		renew_client(clp);
@@ -1387,14 +1368,11 @@ laundromat_main(void *not_used)
  */
 struct nfs4_stateowner *
 find_openstateowner_id(u32 st_id, int flags) {
-	struct list_head *pos, *next;
 	struct nfs4_stateowner *local = NULL;
 
 	dprintk("NFSD: find_openstateowner_id %d\n", st_id);
 	if (flags & CLOSE_STATE) {
-		list_for_each_safe(pos, next, &close_lru) {
-			local = list_entry(pos, struct nfs4_stateowner, 
-			                    so_close_lru);
+		list_for_each_entry(local, &close_lru, so_close_lru) {
 			if(local->so_id == st_id)
 				return local;
 		}
@@ -1767,7 +1745,6 @@ static struct list_head lockstateid_hash
 struct nfs4_stateid *
 find_stateid(stateid_t *stid, int flags)
 {
-	struct list_head *pos, *next;
 	struct nfs4_stateid *local = NULL;
 	u32 st_id = stid->si_stateownerid;
 	u32 f_id = stid->si_fileid;
@@ -1776,8 +1753,7 @@ find_stateid(stateid_t *stid, int flags)
 	dprintk("NFSD: find_stateid flags 0x%x\n",flags);
 	if ((flags & LOCK_STATE) || (flags & RDWR_STATE)) {
 		hashval = stateid_hashval(st_id, f_id);
-		list_for_each_safe(pos, next, &lockstateid_hashtbl[hashval]) {
-			local = list_entry(pos, struct nfs4_stateid, st_hash);
+		list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
 			if((local->st_stateid.si_stateownerid == st_id) &&
 			   (local->st_stateid.si_fileid == f_id))
 				return local;
@@ -1785,8 +1761,7 @@ find_stateid(stateid_t *stid, int flags)
 	} 
 	if ((flags & OPEN_STATE) || (flags & RDWR_STATE)) {
 		hashval = stateid_hashval(st_id, f_id);
-		list_for_each_safe(pos, next, &stateid_hashtbl[hashval]) {
-			local = list_entry(pos, struct nfs4_stateid, st_hash);
+		list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
 			if((local->st_stateid.si_stateownerid == st_id) &&
 			   (local->st_stateid.si_fileid == f_id))
 				return local;
@@ -1817,14 +1792,12 @@ nfs4_transform_lock_offset(struct file_l
 int
 nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval)
 {
-	struct list_head *pos, *next;
 	struct nfs4_stateowner *local = NULL;
 	int status = 0;
 			        
 	if (hashval >= LOCK_HASH_SIZE)
 		goto out;
-	list_for_each_safe(pos, next, &lock_ownerid_hashtbl[hashval]) {
-		local = list_entry(pos, struct nfs4_stateowner, so_idhash);
+	list_for_each_entry(local, &lock_ownerid_hashtbl[hashval], so_idhash) {
 		if (local == sop) {
 			status = 1;
 			goto out;
@@ -1855,11 +1828,9 @@ nfs4_set_lock_denied(struct file_lock *f
 
 static int
 find_lockstateowner_str(unsigned int hashval, struct xdr_netobj *owner, clientid_t *clid, struct nfs4_stateowner **op) {
-	struct list_head *pos, *next;
 	struct nfs4_stateowner *local = NULL;
 
-	list_for_each_safe(pos, next, &lock_ownerstr_hashtbl[hashval]) {
-		local = list_entry(pos, struct nfs4_stateowner, so_strhash);
+	list_for_each_entry(local, &lock_ownerstr_hashtbl[hashval], so_strhash) {
 		if(!cmp_owner_str(local, owner, clid)) 
 			continue;
 		*op = local;
@@ -2305,7 +2276,6 @@ int
 nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
 {
 	clientid_t *clid = &rlockowner->rl_clientid;
-	struct list_head *pos, *next;
 	struct nfs4_stateowner *local = NULL;
 	struct xdr_netobj *owner = &rlockowner->rl_owner;
 	int status, i;
@@ -2326,9 +2296,7 @@ nfsd4_release_lockowner(struct svc_rqst 
 	/* find the lockowner */
         status = nfs_ok;
 	for (i=0; i < LOCK_HASH_SIZE; i++) {
-		list_for_each_safe(pos, next, &lock_ownerstr_hashtbl[i]) {
-			local = list_entry(pos, struct nfs4_stateowner,
-						so_strhash);
+		list_for_each_entry(local, &lock_ownerstr_hashtbl[i], so_strhash) {
 			if(cmp_owner_str(local, owner, clid))
 				break;
 		}
@@ -2339,9 +2307,7 @@ nfsd4_release_lockowner(struct svc_rqst 
 		/* check for any locks held by any stateid associated with the
 		 * (lock) stateowner */
 		status = nfserr_locks_held;
-		list_for_each_safe(pos, next, &local->so_perfilestate) {
-			stp = list_entry(pos, struct nfs4_stateid,
-					                    st_perfilestate);
+		list_for_each_entry(stp, &local->so_perfilestate, st_perfilestate) {
 			if(stp->st_vfs_set) {
 				if (check_for_locks(&stp->st_vfs_file, local))
 					goto out;

_

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#19 lore raw

PATCH 1/1 kNFSdv4 - 8 of 10 - Improve how locking copes with replays

In reply to NeilBrown

From: "J. Bruce Fields" <[email protected]>

Quoted 1 line

From Andros: Hold state_lock longer so the stateowner doesn't diseappear out

from under us before we get the chance to encode the replay. Don't attempt to save replay if we failed to find a stateowner.

----------- Diffstat output ------------

 ./fs/nfsd/nfs4proc.c  |   35 +++++++++++++++++++++++++++--------
 ./fs/nfsd/nfs4state.c |   35 ++++++++++++++++++++++++-----------
 ./fs/nfsd/nfs4xdr.c   |   33 +++++++++++++++++++++------------
 3 files changed, 72 insertions(+), 31 deletions(-)
fs/nfsd/nfs4proc.c renamed from fs/nfsd/nfs4proc.c~current~ +27 -8
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
@@ -113,17 +113,24 @@ do_open_lookup(struct svc_rqst *rqstp, s
 	return status;
 }
 
+/*
+ * nfs4_unlock_state() called in encode
+ */
 static inline int
 nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
 	int status;
-	dprintk("NFSD: nfsd4_open filename %.*s\n",
-		(int)open->op_fname.len, open->op_fname.data);
+	dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
+		(int)open->op_fname.len, open->op_fname.data,
+		open->op_stateowner);
 
 	/* This check required by spec. */
 	if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
 		return nfserr_inval;
 
+	open->op_stateowner = NULL;
+	nfs4_lock_state();
+
 	/* check seqid for replay. set nfs4_owner */
 	status = nfsd4_process_open1(open);
 	if (status == NFSERR_REPLAY_ME) {
@@ -763,7 +770,9 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 			break;
 		case OP_CLOSE:
 			op->status = nfsd4_close(rqstp, &current_fh, &op->u.close);
-			op->replay = &op->u.close.cl_stateowner->so_replay;
+			if (op->u.close.cl_stateowner)
+				op->replay = 
+					&op->u.close.cl_stateowner->so_replay;
 			break;
 		case OP_COMMIT:
 			op->status = nfsd4_commit(rqstp, &current_fh, &op->u.commit);
@@ -782,14 +791,18 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 			break;
 		case OP_LOCK:
 			op->status = nfsd4_lock(rqstp, &current_fh, &op->u.lock);
-			op->replay = &op->u.lock.lk_stateowner->so_replay;
+			if (op->u.lock.lk_stateowner)
+				op->replay = 
+					&op->u.lock.lk_stateowner->so_replay;
 			break;
 		case OP_LOCKT:
 			op->status = nfsd4_lockt(rqstp, &current_fh, &op->u.lockt);
 			break;
 		case OP_LOCKU:
 			op->status = nfsd4_locku(rqstp, &current_fh, &op->u.locku);
-			op->replay = &op->u.locku.lu_stateowner->so_replay;
+			if (op->u.locku.lu_stateowner)
+				op->replay = 
+					&op->u.locku.lu_stateowner->so_replay;
 			break;
 		case OP_LOOKUP:
 			op->status = nfsd4_lookup(rqstp, &current_fh, &op->u.lookup);
@@ -804,15 +817,21 @@ nfsd4_proc_compound(struct svc_rqst *rqs
 			break;
 		case OP_OPEN:
 			op->status = nfsd4_open(rqstp, &current_fh, &op->u.open);
-			op->replay = &op->u.open.op_stateowner->so_replay;
+			if (op->u.open.op_stateowner)
+				op->replay = 
+					&op->u.open.op_stateowner->so_replay;
 			break;
 		case OP_OPEN_CONFIRM:
 			op->status = nfsd4_open_confirm(rqstp, &current_fh, &op->u.open_confirm);
-			op->replay = &op->u.open_confirm.oc_stateowner->so_replay;
+			if (op->u.open_confirm.oc_stateowner)
+				op->replay = 
+					&op->u.open_confirm.oc_stateowner->so_replay;
 			break;
 		case OP_OPEN_DOWNGRADE:
 			op->status = nfsd4_open_downgrade(rqstp, &current_fh, &op->u.open_downgrade);
-			op->replay = &op->u.open_downgrade.od_stateowner->so_replay;
+			if (op->u.open_downgrade.od_stateowner)
+				op->replay = 
+					&op->u.open_downgrade.od_stateowner->so_replay;
 			break;
 		case OP_PUTFH:
 			op->status = nfsd4_putfh(rqstp, &current_fh, &op->u.putfh);
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +24 -11
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -89,6 +89,9 @@ nfs4_lock_state(void)
 	down(&client_sema);
 }
 
+/*
+ * nfs4_unlock_state(); called in encode
+ */
 void
 nfs4_unlock_state(void)
 {
@@ -1083,6 +1086,8 @@ nfs4_file_downgrade(struct file *filp, u
  * 		notfound:
  * 			verify clientid
  * 			create new owner
+ *
+ * called with nfs4_lock_state() held.
  */
 int
 nfsd4_process_open1(struct nfsd4_open *open)
@@ -1101,7 +1106,6 @@ nfsd4_process_open1(struct nfsd4_open *o
 	if (STALE_CLIENTID(&open->op_clientid))
 		goto out;
 
-	nfs4_lock_state();
 	strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
 	if (find_openstateowner_str(strhashval, open, &sop)) {
 		open->op_stateowner = sop;
@@ -1159,10 +1163,11 @@ instantiate_new_owner:
 renew:
 	renew_client(sop->so_client);
 out:
-	nfs4_unlock_state();
 	return status;
 }
-
+/*
+ * called with nfs4_lock_state() held.
+ */
 int
 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
@@ -1185,7 +1190,6 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
 		goto out;
 
-	nfs4_lock_state();
 	fi_hashval = file_hashval(ino);
 	if (find_file(fi_hashval, ino, &fp)) {
 		/* Search for conflicting share reservations */
@@ -1277,7 +1281,6 @@ out:
 	if (!open->op_stateowner->so_confirmed)
 		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
 
-	nfs4_unlock_state();
 	return status;
 out_free:
 	kfree(stp);
@@ -1598,11 +1601,15 @@ check_replay:
 	} else  {
 		printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
 
+		*sopp = NULL;
 		status = nfserr_bad_seqid;
 	}
 	goto out;
 }
 
+/*
+ * nfs4_unlock_state(); called in encode
+ */
 int
 nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc)
 {
@@ -1638,7 +1645,6 @@ nfsd4_open_confirm(struct svc_rqst *rqst
 		         stp->st_stateid.si_generation);
 	status = nfs_ok;
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
@@ -1667,6 +1673,9 @@ reset_union_bmap_deny(unsigned long deny
 	}
 }
 
+/* 
+ * nfs4_unlock_state(); called in encode
+ */
 
 int
 nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od)
@@ -1679,6 +1688,7 @@ nfsd4_open_downgrade(struct svc_rqst *rq
 			(int)current_fh->fh_dentry->d_name.len,
 			current_fh->fh_dentry->d_name.name);
 
+	od->od_stateowner = NULL;
 	status = nfserr_inval;
 	if (!TEST_ACCESS(od->od_share_access) || !TEST_DENY(od->od_share_deny))
 		goto out;
@@ -1712,10 +1722,12 @@ nfsd4_open_downgrade(struct svc_rqst *rq
 	memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
 	status = nfs_ok;
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
+/* 
+ * nfs4_unlock_state() called after encode
+ */
 int
 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
 {
@@ -1726,6 +1738,7 @@ nfsd4_close(struct svc_rqst *rqstp, stru
 			(int)current_fh->fh_dentry->d_name.len,
 			current_fh->fh_dentry->d_name.name);
 
+	close->cl_stateowner = NULL;
 	nfs4_lock_state();
 	/* check close_lru for replay */
 	if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid, 
@@ -1743,7 +1756,6 @@ nfsd4_close(struct svc_rqst *rqstp, stru
 	/* release_state_owner() calls nfsd_close() if needed */
 	release_state_owner(stp, &close->cl_stateowner, OPEN_STATE);
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
@@ -1953,6 +1965,8 @@ check_lock_length(u64 offset, u64 length
 
 /*
  *  LOCK operation 
+ *  
+ * nfs4_unlock_state(); called in encode
  */
 int
 nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock)
@@ -2117,7 +2131,6 @@ out_destroy_new_stateid:
 		release_state_owner(lock_stp, &lock->lk_stateowner, LOCK_STATE);
 	}
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
@@ -2212,7 +2225,7 @@ out:
 	nfs4_unlock_state();
 	return status;
 }
-
+	
 int
 nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku)
 {
@@ -2228,6 +2241,7 @@ nfsd4_locku(struct svc_rqst *rqstp, stru
 	if (check_lock_length(locku->lu_offset, locku->lu_length))
 		 return nfserr_inval;
 
+	locku->lu_stateowner = NULL;
 	nfs4_lock_state();
 									        
 	if ((status = nfs4_preprocess_seqid_op(current_fh, 
@@ -2270,7 +2284,6 @@ nfsd4_locku(struct svc_rqst *rqstp, stru
 	memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t));
 
 out:
-	nfs4_unlock_state();
 	return status;
 
 out_nfserr:
fs/nfsd/nfs4xdr.c renamed from fs/nfsd/nfs4xdr.c~current~ +21 -12
diff ./fs/nfsd/nfs4xdr.c~current~ ./fs/nfsd/nfs4xdr.c
@@ -484,11 +484,14 @@ nfsd4_decode_access(struct nfsd4_compoun
 	DECODE_TAIL;
 }
 
+#define NFS4_STATE_NOT_LOCKED	((void *)-1)
+
 static int
 nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
 {
 	DECODE_HEAD;
 
+	close->cl_stateowner = NFS4_STATE_NOT_LOCKED;
 	READ_BUF(4 + sizeof(stateid_t));
 	READ32(close->cl_seqid);
 	READ32(close->cl_stateid.si_generation);
@@ -579,6 +582,7 @@ nfsd4_decode_lock(struct nfsd4_compounda
 {
 	DECODE_HEAD;
 
+	lock->lk_stateowner = NFS4_STATE_NOT_LOCKED;
 	/*
 	* type, reclaim(boolean), offset, length, new_lock_owner(boolean)
 	*/
@@ -636,6 +640,7 @@ nfsd4_decode_locku(struct nfsd4_compound
 {
 	DECODE_HEAD;
 
+	locku->lu_stateowner = NFS4_STATE_NOT_LOCKED;
 	READ_BUF(24 + sizeof(stateid_t));
 	READ32(locku->lu_type);
 	if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
@@ -671,6 +676,7 @@ nfsd4_decode_open(struct nfsd4_compounda
 
 	memset(open->op_bmval, 0, sizeof(open->op_bmval));
 	open->op_iattr.ia_valid = 0;
+	open->op_stateowner = NFS4_STATE_NOT_LOCKED;
 
 	/* seqid, share_access, share_deny, clientid, ownerlen */
 	READ_BUF(16 + sizeof(clientid_t));
@@ -746,6 +752,7 @@ nfsd4_decode_open_confirm(struct nfsd4_c
 {
 	DECODE_HEAD;
 		    
+	open_conf->oc_stateowner = NFS4_STATE_NOT_LOCKED;
 	READ_BUF(4 + sizeof(stateid_t));
 	READ32(open_conf->oc_req_stateid.si_generation);
 	COPYMEM(&open_conf->oc_req_stateid.si_opaque, sizeof(stateid_opaque_t));
@@ -759,6 +766,7 @@ nfsd4_decode_open_downgrade(struct nfsd4
 {
 	DECODE_HEAD;
 		    
+	open_down->od_stateowner = NFS4_STATE_NOT_LOCKED;
 	READ_BUF(4 + sizeof(stateid_t));
 	READ32(open_down->od_stateid.si_generation);
 	COPYMEM(&open_down->od_stateid.si_opaque, sizeof(stateid_opaque_t));
@@ -1259,7 +1267,8 @@ nfsd4_decode_compound(struct nfsd4_compo
  */
 
 #define ENCODE_SEQID_OP_TAIL(stateowner) do {			\
-	if (seqid_mutating_err(nfserr) && stateowner) {		\
+	if (seqid_mutating_err(nfserr) && stateowner		\
+	    && (stateowner != NFS4_STATE_NOT_LOCKED)) { 	\
 		if (stateowner->so_confirmed)			\
 			stateowner->so_seqid++;			\
 		stateowner->so_replay.rp_status = nfserr;   	\
@@ -1267,7 +1276,10 @@ nfsd4_decode_compound(struct nfsd4_compo
 			  (((char *)(resp)->p - (char *)save)); \
 		memcpy(stateowner->so_replay.rp_buf, save,      \
  			stateowner->so_replay.rp_buflen); 	\
-	} } while(0)
+	}							\
+	if (stateowner != NFS4_STATE_NOT_LOCKED)		\
+		nfs4_unlock_state();				\
+	} while (0);
 
 
 static u32 nfs4_ftypes[16] = {
@@ -1917,7 +1929,7 @@ nfsd4_encode_open(struct nfsd4_compoundr
 	ENCODE_SEQID_OP_HEAD;
 
 	if (nfserr)
-		return;
+		goto out;
 
 	RESERVE_SPACE(36 + sizeof(stateid_t));
 	WRITE32(open->op_stateid.si_generation);
@@ -1972,7 +1984,7 @@ nfsd4_encode_open(struct nfsd4_compoundr
 		BUG();
 	}
 	/* XXX save filehandle here */
-
+out:
 	ENCODE_SEQID_OP_TAIL(open->op_stateowner);
 }
 
@@ -2297,14 +2309,8 @@ nfsd4_encode_operation(struct nfsd4_comp
 
 	RESERVE_SPACE(8);
 	WRITE32(op->opnum);
-	if ((op->opnum != OP_SETATTR) && (op->opnum != OP_LOCK) && (op->opnum != OP_LOCKT) && (op->opnum != OP_SETCLIENTID) && (op->status)) {
-		*p++ = op->status;
-		ADJUST_ARGS();
-		return;
-	} else {
-		statp = p++;        /* to be backfilled at the end */
-		ADJUST_ARGS();
-	}
+	statp = p++;	/* to be backfilled at the end */
+	ADJUST_ARGS();
 
 	switch (op->opnum) {
 	case OP_ACCESS:
@@ -2408,6 +2414,8 @@ nfsd4_encode_operation(struct nfsd4_comp
  * 
  * XDR note: do not encode rp->rp_buflen: the buffer contains the
  * previously sent already encoded operation.
+ *
+ * called with nfs4_lock_state() held
  */
 void
 nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
@@ -2425,6 +2433,7 @@ nfsd4_encode_replay(struct nfsd4_compoun
 	RESERVE_SPACE(rp->rp_buflen);
 	WRITEMEM(rp->rp_buf, rp->rp_buflen);
 	ADJUST_ARGS();
+	nfs4_unlock_state();
 }
 
 /*

-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials Free Linux tutorial presented by Daniel Robbins, President and CEO of GenToo technologies. Learn everything from fundamentals to system administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs