* [PATCH] kNFSdv4 - 1 of 10 - idmap bugfixes and cleanup
2004-04-08 1:18 [PATCH] kNFSdv4 - 0 of 10 - Introduction NeilBrown
@ 2004-04-08 1:18 ` NeilBrown
[not found] ` <20040407233608.6414089a.akpm@osdl.org>
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 4 of 10 - nfsd4_readdir fixes NeilBrown
` (8 subsequent siblings)
9 siblings, 1 reply; 16+ messages in thread
From: NeilBrown @ 2004-04-08 1:18 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@fieldses.org>
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(-)
diff ./fs/nfsd/nfs4idmap.c~current~ ./fs/nfsd/nfs4idmap.c
--- ./fs/nfsd/nfs4idmap.c~current~ 2004-04-06 10:57:05.000000000 +1000
+++ ./fs/nfsd/nfs4idmap.c 2004-04-08 10:50:09.000000000 +1000
@@ -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 - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH] kNFSdv4 - 4 of 10 - nfsd4_readdir fixes
2004-04-08 1:18 [PATCH] kNFSdv4 - 0 of 10 - Introduction NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 1 of 10 - idmap bugfixes and cleanup NeilBrown
@ 2004-04-08 1:18 ` NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 2 of 10 - better handling of failed idmap lookups NeilBrown
` (7 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: NeilBrown @ 2004-04-08 1:18 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@fieldses.org>
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(-)
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
--- ./fs/nfsd/nfs4proc.c~current~ 2004-04-08 10:56:00.000000000 +1000
+++ ./fs/nfsd/nfs4proc.c 2004-04-08 10:56:00.000000000 +1000
@@ -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;
diff ./fs/nfsd/nfs4xdr.c~current~ ./fs/nfsd/nfs4xdr.c
--- ./fs/nfsd/nfs4xdr.c~current~ 2004-04-08 10:56:00.000000000 +1000
+++ ./fs/nfsd/nfs4xdr.c 2004-04-08 10:56:00.000000000 +1000
@@ -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 - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH] kNFSdv4 - 2 of 10 - better handling of failed idmap lookups
2004-04-08 1:18 [PATCH] kNFSdv4 - 0 of 10 - Introduction NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 1 of 10 - idmap bugfixes and cleanup NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 4 of 10 - nfsd4_readdir fixes NeilBrown
@ 2004-04-08 1:18 ` NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 9 of 10 - Set credentials properly when puutrootfh is used NeilBrown
` (6 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: NeilBrown @ 2004-04-08 1:18 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@fieldses.org>
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(+)
diff ./fs/nfsd/nfs4idmap.c~current~ ./fs/nfsd/nfs4idmap.c
--- ./fs/nfsd/nfs4idmap.c~current~ 2004-04-08 10:50:09.000000000 +1000
+++ ./fs/nfsd/nfs4idmap.c 2004-04-08 10:50:13.000000000 +1000
@@ -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);
diff ./fs/nfsd/nfsproc.c~current~ ./fs/nfsd/nfsproc.c
--- ./fs/nfsd/nfsproc.c~current~ 2004-04-06 10:57:05.000000000 +1000
+++ ./fs/nfsd/nfsproc.c 2004-04-08 10:50:13.000000000 +1000
@@ -588,6 +588,7 @@ nfserrno (int errno)
{ nfserr_jukebox, -ETIMEDOUT },
{ nfserr_dropit, -EAGAIN },
{ nfserr_dropit, -ENOMEM },
+ { nfserr_badname, -ESRCH },
{ -1, -EIO }
};
int i;
diff ./include/linux/nfsd/nfsd.h~current~ ./include/linux/nfsd/nfsd.h
--- ./include/linux/nfsd/nfsd.h~current~ 2004-04-06 10:57:05.000000000 +1000
+++ ./include/linux/nfsd/nfsd.h 2004-04-08 10:50:13.000000000 +1000
@@ -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 - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH] kNFSdv4 - 9 of 10 - Set credentials properly when puutrootfh is used
2004-04-08 1:18 [PATCH] kNFSdv4 - 0 of 10 - Introduction NeilBrown
` (2 preceding siblings ...)
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 2 of 10 - better handling of failed idmap lookups NeilBrown
@ 2004-04-08 1:18 ` NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 5 of 10 - Fix bad error returm from svcauth_gss_accept NeilBrown
` (5 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: NeilBrown @ 2004-04-08 1:18 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, J. Bruce Fields
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" <bfields@fieldses.org>
>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(-)
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
--- ./fs/nfsd/nfs4proc.c~current~ 2004-04-08 10:57:00.000000000 +1000
+++ ./fs/nfsd/nfs4proc.c 2004-04-08 10:57:10.000000000 +1000
@@ -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 - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH] kNFSdv4 - 5 of 10 - Fix bad error returm from svcauth_gss_accept
2004-04-08 1:18 [PATCH] kNFSdv4 - 0 of 10 - Introduction NeilBrown
` (3 preceding siblings ...)
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 9 of 10 - Set credentials properly when puutrootfh is used NeilBrown
@ 2004-04-08 1:18 ` NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 10 of 10 - Implement server-side reboot recovery (mostly) NeilBrown
` (4 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: NeilBrown @ 2004-04-08 1:18 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@fieldses.org>
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(+)
diff ./net/sunrpc/auth_gss/svcauth_gss.c~current~ ./net/sunrpc/auth_gss/svcauth_gss.c
--- ./net/sunrpc/auth_gss/svcauth_gss.c~current~ 2004-04-08 10:56:10.000000000 +1000
+++ ./net/sunrpc/auth_gss/svcauth_gss.c 2004-04-08 10:56:10.000000000 +1000
@@ -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 - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH] kNFSdv4 - 10 of 10 - Implement server-side reboot recovery (mostly)
2004-04-08 1:18 [PATCH] kNFSdv4 - 0 of 10 - Introduction NeilBrown
` (4 preceding siblings ...)
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 5 of 10 - Fix bad error returm from svcauth_gss_accept NeilBrown
@ 2004-04-08 1:18 ` NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 3 of 10 - complain if idmapd doesn't have channel open NeilBrown
` (3 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: NeilBrown @ 2004-04-08 1:18 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@fieldses.org>
>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(-)
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
--- ./fs/nfsd/nfs4proc.c~current~ 2004-04-08 10:57:10.000000000 +1000
+++ ./fs/nfsd/nfs4proc.c 2004-04-08 10:57:18.000000000 +1000
@@ -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,
+ ¤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, 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)
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
--- ./fs/nfsd/nfs4state.c~current~ 2004-04-08 10:57:00.000000000 +1000
+++ ./fs/nfsd/nfs4state.c 2004-04-08 10:57:18.000000000 +1000
@@ -52,6 +52,7 @@
/* Globals */
time_t boot_time;
+static time_t grace_end = 0;
static u32 current_clientid = 1;
static u32 current_ownerid;
static u32 current_fileid;
@@ -1104,7 +1105,7 @@ nfsd4_process_open1(struct nfsd4_open *o
status = nfserr_stale_clientid;
if (STALE_CLIENTID(&open->op_clientid))
- goto out;
+ return status;
strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
if (find_openstateowner_str(strhashval, open, &sop)) {
@@ -1125,7 +1126,7 @@ nfsd4_process_open1(struct nfsd4_open *o
}
/* replay: indicate to calling function */
status = NFSERR_REPLAY_ME;
- goto out;
+ return status;
}
if (sop->so_confirmed) {
if (open->op_seqid == sop->so_seqid + 1) {
@@ -1163,6 +1164,8 @@ instantiate_new_owner:
renew:
renew_client(sop->so_client);
out:
+ if (status && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ status = nfserr_reclaim_bad;
return status;
}
/*
@@ -1173,7 +1176,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
{
struct iattr iattr;
struct nfs4_stateowner *sop = open->op_stateowner;
- struct nfs4_file *fp;
+ struct nfs4_file *fp = NULL;
struct inode *ino;
unsigned int fi_hashval;
struct list_head *pos, *next;
@@ -1182,7 +1185,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
status = nfserr_resource;
if (!sop)
- goto out;
+ return status;
ino = current_fh->fh_dentry->d_inode;
@@ -1274,6 +1277,17 @@ out:
if (fp && list_empty(&fp->fi_perfile))
release_file(fp);
+ if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
+ if (status)
+ status = nfserr_reclaim_bad;
+ else {
+ /* successful reclaim. so_seqid is decremented because
+ * it will be bumped in encode_open
+ */
+ open->op_stateowner->so_confirmed = 1;
+ open->op_stateowner->so_seqid--;
+ }
+ }
/*
* To finish the open response, we just need to set the rflags.
*/
@@ -1286,6 +1300,7 @@ out_free:
kfree(stp);
goto out;
}
+
static struct work_struct laundromat_work;
static void laundromat_main(void *);
static DECLARE_WORK(laundromat_work, laundromat_main, NULL);
@@ -1983,6 +1998,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
(long long) lock->lk_offset,
(long long) lock->lk_length);
+ if (nfs4_in_grace() && !lock->lk_reclaim)
+ return nfserr_grace;
+ if (nfs4_in_no_grace() && lock->lk_reclaim)
+ return nfserr_no_grace;
+
if (check_lock_length(lock->lk_offset, lock->lk_length))
return nfserr_inval;
@@ -2012,8 +2032,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
CHECK_FH | OPEN_STATE,
&open_sop, &open_stp,
&lock->v.new.clientid);
- if (status)
+ if (status) {
+ if (lock->lk_reclaim)
+ status = nfserr_reclaim_bad;
goto out;
+ }
/* create lockowner and lock stateid */
fp = open_stp->st_file;
strhashval = lock_ownerstr_hashval(fp->fi_inode,
@@ -2148,6 +2171,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
unsigned int strhashval;
int status;
+ if (nfs4_in_grace())
+ return nfserr_grace;
+
if (check_lock_length(lockt->lt_offset, lockt->lt_length))
return nfserr_inval;
@@ -2377,6 +2403,7 @@ void
nfs4_state_init(void)
{
int i;
+ time_t start = get_seconds();
if (nfs4_init)
return;
@@ -2407,13 +2434,27 @@ nfs4_state_init(void)
INIT_LIST_HEAD(&close_lru);
INIT_LIST_HEAD(&client_lru);
init_MUTEX(&client_sema);
- boot_time = get_seconds();
+ boot_time = start;
+ grace_end = start + NFSD_LEASE_TIME;
INIT_WORK(&laundromat_work,laundromat_main, NULL);
schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ);
nfs4_init = 1;
}
+int
+nfs4_in_grace(void)
+{
+ return time_before(get_seconds(), (unsigned long)grace_end);
+}
+
+int
+nfs4_in_no_grace(void)
+{
+ return (grace_end < get_seconds());
+}
+
+
static void
__nfs4_state_shutdown(void)
{
diff ./include/linux/nfsd/nfsd.h~current~ ./include/linux/nfsd/nfsd.h
--- ./include/linux/nfsd/nfsd.h~current~ 2004-04-08 10:50:13.000000000 +1000
+++ ./include/linux/nfsd/nfsd.h 2004-04-08 10:57:18.000000000 +1000
@@ -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.
diff ./include/linux/nfsd/state.h~current~ ./include/linux/nfsd/state.h
--- ./include/linux/nfsd/state.h~current~ 2004-04-08 10:56:23.000000000 +1000
+++ ./include/linux/nfsd/state.h 2004-04-08 10:57:18.000000000 +1000
@@ -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 - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH] kNFSdv4 - 3 of 10 - complain if idmapd doesn't have channel open
2004-04-08 1:18 [PATCH] kNFSdv4 - 0 of 10 - Introduction NeilBrown
` (5 preceding siblings ...)
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 10 of 10 - Implement server-side reboot recovery (mostly) NeilBrown
@ 2004-04-08 1:18 ` NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 7 of 10 - Allow locku replays aswell NeilBrown
` (2 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: NeilBrown @ 2004-04-08 1:18 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@fieldses.org>
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(+)
diff ./fs/nfsd/nfs4idmap.c~current~ ./fs/nfsd/nfs4idmap.c
--- ./fs/nfsd/nfs4idmap.c~current~ 2004-04-08 10:50:13.000000000 +1000
+++ ./fs/nfsd/nfs4idmap.c 2004-04-08 10:50:15.000000000 +1000
@@ -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 - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH] kNFSdv4 - 7 of 10 - Allow locku replays aswell
2004-04-08 1:18 [PATCH] kNFSdv4 - 0 of 10 - Introduction NeilBrown
` (6 preceding siblings ...)
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 3 of 10 - complain if idmapd doesn't have channel open NeilBrown
@ 2004-04-08 1:18 ` NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 8 of 10 - Improve how locking copes with replays NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 6 of 10 - Keep state to allow replays for 'close' to work NeilBrown
9 siblings, 0 replies; 16+ messages in thread
From: NeilBrown @ 2004-04-08 1:18 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@fieldses.org>
>From Andros: locku replies should be saved for possible replay as well.
----------- Diffstat output ------------
./fs/nfsd/nfs4proc.c | 1 +
1 files changed, 1 insertion(+)
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
--- ./fs/nfsd/nfs4proc.c~current~ 2004-04-08 10:56:00.000000000 +1000
+++ ./fs/nfsd/nfs4proc.c 2004-04-08 10:56:52.000000000 +1000
@@ -789,6 +789,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
break;
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 - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH] kNFSdv4 - 8 of 10 - Improve how locking copes with replays
2004-04-08 1:18 [PATCH] kNFSdv4 - 0 of 10 - Introduction NeilBrown
` (7 preceding siblings ...)
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 7 of 10 - Allow locku replays aswell NeilBrown
@ 2004-04-08 1:18 ` NeilBrown
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 6 of 10 - Keep state to allow replays for 'close' to work NeilBrown
9 siblings, 0 replies; 16+ messages in thread
From: NeilBrown @ 2004-04-08 1:18 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@fieldses.org>
>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(-)
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
--- ./fs/nfsd/nfs4proc.c~current~ 2004-04-08 10:56:52.000000000 +1000
+++ ./fs/nfsd/nfs4proc.c 2004-04-08 10:57:00.000000000 +1000
@@ -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, ¤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 *rqs
break;
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 *rqs
break;
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);
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
--- ./fs/nfsd/nfs4state.c~current~ 2004-04-08 10:56:23.000000000 +1000
+++ ./fs/nfsd/nfs4state.c 2004-04-08 10:57:00.000000000 +1000
@@ -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:
diff ./fs/nfsd/nfs4xdr.c~current~ ./fs/nfsd/nfs4xdr.c
--- ./fs/nfsd/nfs4xdr.c~current~ 2004-04-08 10:56:00.000000000 +1000
+++ ./fs/nfsd/nfs4xdr.c 2004-04-08 10:57:00.000000000 +1000
@@ -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 - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH] kNFSdv4 - 6 of 10 - Keep state to allow replays for 'close' to work.
2004-04-08 1:18 [PATCH] kNFSdv4 - 0 of 10 - Introduction NeilBrown
` (8 preceding siblings ...)
2004-04-08 1:18 ` [PATCH] kNFSdv4 - 8 of 10 - Improve how locking copes with replays NeilBrown
@ 2004-04-08 1:18 ` NeilBrown
[not found] ` <20040407234541.7f2bb6d3.akpm@osdl.org>
9 siblings, 1 reply; 16+ messages in thread
From: NeilBrown @ 2004-04-08 1:18 UTC (permalink / raw)
To: Andrew Morton; +Cc: nfs, J. Bruce Fields
From: "J. Bruce Fields" <bfields@fieldses.org>
>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(-)
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
--- ./fs/nfsd/nfs4state.c~current~ 2004-04-08 10:56:23.000000000 +1000
+++ ./fs/nfsd/nfs4state.c 2004-04-08 10:56:23.000000000 +1000
@@ -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();
diff ./include/linux/nfsd/state.h~current~ ./include/linux/nfsd/state.h
--- ./include/linux/nfsd/state.h~current~ 2004-04-08 10:56:23.000000000 +1000
+++ ./include/linux/nfsd/state.h 2004-04-08 10:56:23.000000000 +1000
@@ -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 - NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs
^ permalink raw reply [flat|nested] 16+ messages in thread