kNFSdv4 - 0 of 10 - Introduction
Subsystems (3)
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
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
@@ -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_reqstruct 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]
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 dowake_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
@@ -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, wamemset (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
Re: [PATCH] kNFSdv4 - 1 of 10 - idmap bugfixes and cleanup
In reply to a message not in the archiveQuoted 2 lines · Andrew Morton
- Cannot
idmap_lookup()return in stateTASK_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]
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, oridmap_wait(which always callsput_mdr) is called, andput_mdrdoes awake_up. So I believe this is correct, though I do wish it was clearer.
wake_up()doesn't alter the caller'stask->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]
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
PATCH 1/1 kNFSdv4 - 2 of 10 - better handling of failed idmap lookups
In reply to NeilBrownFrom: "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
@@ -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
@@ -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
@@ -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
PATCH 1/1 kNFSdv4 - 3 of 10 - complain if idmapd doesn't have channel open
In reply to NeilBrownFrom: "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
@@ -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
PATCH 1/1 kNFSdv4 - 5 of 10 - Fix bad error returm from svcauth_gss_accept
In reply to NeilBrownFrom: "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
@@ -895,6 +895,7 @@ svcauth_gss_accept(struct svc_rqst *rqstsvc_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
PATCH 1/1 kNFSdv4 - 9 of 10 - Set credentials properly when puutrootfh is used
In reply to NeilBrownThe 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_setuserinnfsd4_putrootfhso 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
@@ -194,9 +194,14 @@ nfsd4_putfh(struct svc_rqst *rqstp, strustatic 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
PATCH 1/1 kNFSdv4 - 7 of 10 - Allow locku replays aswell
In reply to NeilBrownFrom: "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
@@ -789,6 +789,7 @@ nfsd4_proc_compound(struct svc_rqst *rqsbreak ;case OP_LOCKU : op->status =nfsd4_locku (rqstp, ¤t_fh, &op->u.locku); + op->replay = &op->u.locku.lu_stateowner->so_replay;break ;case OP_LOOKUP : op->status =nfsd4_lookup (rqstp, ¤t_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
PATCH 1/1 kNFSdv4 - 4 of 10 - nfsd4_readdir fixes
In reply to NeilBrownFrom: "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
@@ -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
@@ -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
PATCH 1/1 kNFSdv4 - 10 of 10 - Implement server-side reboot recovery (mostly)
In reply to NeilBrownFrom: "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
@@ -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, sif (!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, + ¤t_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, strucint 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, struu32 *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
@@ -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
@@ -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
PATCH 1/1 kNFSdv4 - 6 of 10 - Keep state to allow replays for 'close' to work.
In reply to NeilBrownFrom: "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
@@ -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 intINIT_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_stateownelist_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_stateiddprintk ("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_tnfs4_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 intINIT_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
@@ -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]
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
@@ -380,7 +380,6 @@ nfsd4_setclientid(struct svc_rqst *rqstpunsigned 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 *rqstpbreak ; } 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_rqsstruct 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 hasstatic 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 *curreunsigned 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 *rqsstruct 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 *rqsif (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_hashstruct 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_lint 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 *fstatic 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
PATCH 1/1 kNFSdv4 - 8 of 10 - Improve how locking copes with replays
In reply to NeilBrownFrom: "J. Bruce Fields" <[email protected]>
Quoted 1 line
From Andros: Hold
state_locklonger 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
@@ -113,17 +113,24 @@ do_open_lookup(struct svc_rqst *rqstp, sreturn 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 *rqsbreak ;case OP_CLOSE : op->status =nfsd4_close (rqstp, ¤t_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, ¤t_fh, &op->u.commit);
@@ -782,14 +791,18 @@ nfsd4_proc_compound(struct svc_rqst *rqsbreak ;case OP_LOCK : op->status =nfsd4_lock (rqstp, ¤t_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, ¤t_fh, &op->u.lockt);break ;case OP_LOCKU : op->status =nfsd4_locku (rqstp, ¤t_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, ¤t_fh, &op->u.lookup);
@@ -804,15 +817,21 @@ nfsd4_proc_compound(struct svc_rqst *rqsbreak ;case OP_OPEN : op->status =nfsd4_open (rqstp, ¤t_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, ¤t_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, ¤t_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, ¤t_fh, &op->u.putfh);
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +24 -11
@@ -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 *oif (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 *rqsif (!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 *rqmemcpy (&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, struif (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, strumemcpy (&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
@@ -484,11 +484,14 @@ nfsd4_decode_access(struct nfsd4_compounDECODE_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_compoundamemset (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_compoundrENCODE_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_compoundrBUG (); }/* XXX save filehandle here */ - +out:ENCODE_SEQID_OP_TAIL (open->op_stateowner); }
@@ -2297,14 +2309,8 @@ nfsd4_encode_operation(struct nfsd4_compRESERVE_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_compounRESERVE_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