Skip to content

Commit

Permalink
[PATCH] knfsd: nfsd: don't drop silently on upcall deferral
Browse files Browse the repository at this point in the history
To avoid tying up server threads when nfsd makes an upcall (to mountd, to get
export options, to idmapd, for nfsv4 name<->id mapping, etc.), we temporarily
"drop" the request and save enough information so that we can revisit it
later.

Certain failures during the deferral process can cause us to really drop the
request and never revisit it.

This is often less than ideal, and is unacceptable in the NFSv4 case--rfc 3530
forbids the server from dropping a request without also closing the
connection.

As a first step, we modify the deferral code to return -ETIMEDOUT (which is
translated to nfserr_jukebox in the v3 and v4 cases, and remains a drop in the
v2 case).

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
J.Bruce Fields authored and Linus Torvalds committed Dec 13, 2006
1 parent 021d3a7 commit e0bb89e
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 11 deletions.
11 changes: 8 additions & 3 deletions fs/nfsd/export.c
Original file line number Diff line number Diff line change
Expand Up @@ -787,15 +787,20 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
key.ex_dentry = dentry;

exp = svc_export_lookup(&key);
if (exp != NULL)
switch (cache_check(&svc_export_cache, &exp->h, reqp)) {
if (exp != NULL) {
int err;

err = cache_check(&svc_export_cache, &exp->h, reqp);
switch (err) {
case 0: break;
case -EAGAIN:
exp = ERR_PTR(-EAGAIN);
case -ETIMEDOUT:
exp = ERR_PTR(err);
break;
default:
exp = NULL;
}
}

return exp;
}
Expand Down
6 changes: 4 additions & 2 deletions fs/nfsd/nfsfh.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,11 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle);
}

error = nfserr_dropit;
if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN)
if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN
|| PTR_ERR(exp) == -ETIMEDOUT)) {
error = nfserrno(PTR_ERR(exp));
goto out;
}

error = nfserr_stale;
if (!exp || IS_ERR(exp))
Expand Down
2 changes: 1 addition & 1 deletion fs/nfsd/vfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE];
/*
* Called from nfsd_lookup and encode_dirent. Check if we have crossed
* a mount point.
* Returns -EAGAIN leaving *dpp and *expp unchanged,
* Returns -EAGAIN or -ETIMEDOUT leaving *dpp and *expp unchanged,
* or nfs_ok having possibly changed *dpp and *expp
*/
int
Expand Down
2 changes: 1 addition & 1 deletion net/sunrpc/auth_gss/svcauth_gss.c
Original file line number Diff line number Diff line change
Expand Up @@ -1066,7 +1066,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
}
switch(cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
case -EAGAIN:
goto drop;
case -ETIMEDOUT:
case -ENOENT:
goto drop;
case 0:
Expand Down
11 changes: 7 additions & 4 deletions net/sunrpc/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

#define RPCDBG_FACILITY RPCDBG_CACHE

static void cache_defer_req(struct cache_req *req, struct cache_head *item);
static int cache_defer_req(struct cache_req *req, struct cache_head *item);
static void cache_revisit_request(struct cache_head *item);

static void cache_init(struct cache_head *h)
Expand Down Expand Up @@ -185,6 +185,7 @@ static int cache_make_upcall(struct cache_detail *detail, struct cache_head *h);
*
* Returns 0 if the cache_head can be used, or cache_puts it and returns
* -EAGAIN if upcall is pending,
* -ETIMEDOUT if upcall failed and should be retried,
* -ENOENT if cache entry was negative
*/
int cache_check(struct cache_detail *detail,
Expand Down Expand Up @@ -236,7 +237,8 @@ int cache_check(struct cache_detail *detail,
}

if (rv == -EAGAIN)
cache_defer_req(rqstp, h);
if (cache_defer_req(rqstp, h) != 0)
rv = -ETIMEDOUT;

if (rv)
cache_put(h, detail);
Expand Down Expand Up @@ -523,14 +525,14 @@ static LIST_HEAD(cache_defer_list);
static struct list_head cache_defer_hash[DFR_HASHSIZE];
static int cache_defer_cnt;

static void cache_defer_req(struct cache_req *req, struct cache_head *item)
static int cache_defer_req(struct cache_req *req, struct cache_head *item)
{
struct cache_deferred_req *dreq;
int hash = DFR_HASH(item);

dreq = req->defer(req);
if (dreq == NULL)
return;
return -ETIMEDOUT;

dreq->item = item;
dreq->recv_time = get_seconds();
Expand Down Expand Up @@ -571,6 +573,7 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item)
/* must have just been validated... */
cache_revisit_request(item);
}
return 0;
}

static void cache_revisit_request(struct cache_head *item)
Expand Down
1 change: 1 addition & 0 deletions net/sunrpc/svcauth_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
default:
BUG();
case -EAGAIN:
case -ETIMEDOUT:
return SVC_DROP;
case -ENOENT:
return SVC_DENIED;
Expand Down

0 comments on commit e0bb89e

Please sign in to comment.