aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2011-09-23 17:01:19 -0400
committerJ. Bruce Fields <bfields@redhat.com>2011-09-26 17:35:28 -0400
commit38c2f4b12a455cb3a108fd5c79a10df2ba3ec9a7 (patch)
tree125aa30a29a2863b448d66b2b0d31d4f65db0533 /fs/nfsd
parent36279ac10c3d69372af875f1affafd375db687a9 (diff)
nfsd4: look up stateid's per clientid
Use a separate stateid idr per client, and lookup a stateid by first finding the client, then looking up the stateid relative to that client. Also some minor refactoring. This allows us to improve error returns: we can return expired when the clientid is not found and bad_stateid when the clientid is found but not the stateid, as opposed to returning expired for both cases. I hope this will also help to replace the state lock mostly by a per-client lock, but that hasn't been done yet. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4state.c112
-rw-r--r--fs/nfsd/nfs4xdr.c3
-rw-r--r--fs/nfsd/state.h4
3 files changed, 54 insertions, 65 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index daf75fa4c027..931155f51ecc 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -32,7 +32,6 @@
32* 32*
33*/ 33*/
34 34
35#include <linux/idr.h>
36#include <linux/file.h> 35#include <linux/file.h>
37#include <linux/fs.h> 36#include <linux/fs.h>
38#include <linux/slab.h> 37#include <linux/slab.h>
@@ -149,8 +148,6 @@ static struct list_head open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE];
149#define FILE_HASH_BITS 8 148#define FILE_HASH_BITS 8
150#define FILE_HASH_SIZE (1 << FILE_HASH_BITS) 149#define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
151 150
152struct idr stateids;
153
154static unsigned int file_hashval(struct inode *ino) 151static unsigned int file_hashval(struct inode *ino)
155{ 152{
156 /* XXX: why are we hashing on inode pointer, anyway? */ 153 /* XXX: why are we hashing on inode pointer, anyway? */
@@ -209,13 +206,14 @@ static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
209static inline int get_new_stid(struct nfs4_stid *stid) 206static inline int get_new_stid(struct nfs4_stid *stid)
210{ 207{
211 static int min_stateid = 0; 208 static int min_stateid = 0;
209 struct idr *stateids = &stid->sc_client->cl_stateids;
212 int new_stid; 210 int new_stid;
213 int error; 211 int error;
214 212
215 if (!idr_pre_get(&stateids, GFP_KERNEL)) 213 if (!idr_pre_get(stateids, GFP_KERNEL))
216 return -ENOMEM; 214 return -ENOMEM;
217 215
218 error = idr_get_new_above(&stateids, stid, min_stateid, &new_stid); 216 error = idr_get_new_above(stateids, stid, min_stateid, &new_stid);
219 /* 217 /*
220 * All this code is currently serialized; the preallocation 218 * All this code is currently serialized; the preallocation
221 * above should still be ours: 219 * above should still be ours:
@@ -324,7 +322,9 @@ static void nfs4_put_deleg_lease(struct nfs4_file *fp)
324 322
325static void unhash_stid(struct nfs4_stid *s) 323static void unhash_stid(struct nfs4_stid *s)
326{ 324{
327 idr_remove(&stateids, s->sc_stateid.si_opaque.so_id); 325 struct idr *stateids = &s->sc_client->cl_stateids;
326
327 idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
328} 328}
329 329
330/* Called under the state lock. */ 330/* Called under the state lock. */
@@ -1126,16 +1126,16 @@ static void gen_confirm(struct nfs4_client *clp)
1126 *p++ = i++; 1126 *p++ = i++;
1127} 1127}
1128 1128
1129static struct nfs4_stid *find_stateid(stateid_t *t) 1129static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
1130{ 1130{
1131 return idr_find(&stateids, t->si_opaque.so_id); 1131 return idr_find(&cl->cl_stateids, t->si_opaque.so_id);
1132} 1132}
1133 1133
1134static struct nfs4_stid *find_stateid_by_type(stateid_t *t, char typemask) 1134static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
1135{ 1135{
1136 struct nfs4_stid *s; 1136 struct nfs4_stid *s;
1137 1137
1138 s = find_stateid(t); 1138 s = find_stateid(cl, t);
1139 if (!s) 1139 if (!s)
1140 return NULL; 1140 return NULL;
1141 if (typemask & s->sc_type) 1141 if (typemask & s->sc_type)
@@ -1143,16 +1143,6 @@ static struct nfs4_stid *find_stateid_by_type(stateid_t *t, char typemask)
1143 return NULL; 1143 return NULL;
1144} 1144}
1145 1145
1146static struct nfs4_ol_stateid *find_ol_stateid_by_type(stateid_t *t, char typemask)
1147{
1148 struct nfs4_stid *s;
1149
1150 s = find_stateid_by_type(t, typemask);
1151 if (!s)
1152 return NULL;
1153 return openlockstateid(s);
1154}
1155
1156static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, 1146static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
1157 struct svc_rqst *rqstp, nfs4_verifier *verf) 1147 struct svc_rqst *rqstp, nfs4_verifier *verf)
1158{ 1148{
@@ -1175,6 +1165,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
1175 } 1165 }
1176 } 1166 }
1177 1167
1168 idr_init(&clp->cl_stateids);
1178 memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); 1169 memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
1179 atomic_set(&clp->cl_refcount, 0); 1170 atomic_set(&clp->cl_refcount, 0);
1180 clp->cl_cb_state = NFSD4_CB_UNKNOWN; 1171 clp->cl_cb_state = NFSD4_CB_UNKNOWN;
@@ -2611,24 +2602,24 @@ static int share_access_to_flags(u32 share_access)
2611 return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 2602 return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
2612} 2603}
2613 2604
2614static struct nfs4_delegation *find_deleg_stateid(stateid_t *s) 2605static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s)
2615{ 2606{
2616 struct nfs4_stid *ret; 2607 struct nfs4_stid *ret;
2617 2608
2618 ret = find_stateid_by_type(s, NFS4_DELEG_STID); 2609 ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
2619 if (!ret) 2610 if (!ret)
2620 return NULL; 2611 return NULL;
2621 return delegstateid(ret); 2612 return delegstateid(ret);
2622} 2613}
2623 2614
2624static __be32 2615static __be32
2625nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, 2616nfs4_check_deleg(struct nfs4_client *cl, struct nfs4_file *fp, struct nfsd4_open *open,
2626 struct nfs4_delegation **dp) 2617 struct nfs4_delegation **dp)
2627{ 2618{
2628 int flags; 2619 int flags;
2629 __be32 status = nfserr_bad_stateid; 2620 __be32 status = nfserr_bad_stateid;
2630 2621
2631 *dp = find_deleg_stateid(&open->op_delegate_stateid); 2622 *dp = find_deleg_stateid(cl, &open->op_delegate_stateid);
2632 if (*dp == NULL) 2623 if (*dp == NULL)
2633 goto out; 2624 goto out;
2634 flags = share_access_to_flags(open->op_share_access); 2625 flags = share_access_to_flags(open->op_share_access);
@@ -2920,6 +2911,7 @@ __be32
2920nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 2911nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
2921{ 2912{
2922 struct nfsd4_compoundres *resp = rqstp->rq_resp; 2913 struct nfsd4_compoundres *resp = rqstp->rq_resp;
2914 struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
2923 struct nfs4_file *fp = NULL; 2915 struct nfs4_file *fp = NULL;
2924 struct inode *ino = current_fh->fh_dentry->d_inode; 2916 struct inode *ino = current_fh->fh_dentry->d_inode;
2925 struct nfs4_ol_stateid *stp = NULL; 2917 struct nfs4_ol_stateid *stp = NULL;
@@ -2939,7 +2931,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
2939 if (fp) { 2931 if (fp) {
2940 if ((status = nfs4_check_open(fp, open, &stp))) 2932 if ((status = nfs4_check_open(fp, open, &stp)))
2941 goto out; 2933 goto out;
2942 status = nfs4_check_deleg(fp, open, &dp); 2934 status = nfs4_check_deleg(cl, fp, open, &dp);
2943 if (status) 2935 if (status)
2944 goto out; 2936 goto out;
2945 } else { 2937 } else {
@@ -3256,7 +3248,7 @@ static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_sess
3256 return nfserr_old_stateid; 3248 return nfserr_old_stateid;
3257} 3249}
3258 3250
3259__be32 nfs4_validate_stateid(stateid_t *stateid) 3251__be32 nfs4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
3260{ 3252{
3261 struct nfs4_stid *s; 3253 struct nfs4_stid *s;
3262 struct nfs4_ol_stateid *ols; 3254 struct nfs4_ol_stateid *ols;
@@ -3265,7 +3257,7 @@ __be32 nfs4_validate_stateid(stateid_t *stateid)
3265 if (STALE_STATEID(stateid)) 3257 if (STALE_STATEID(stateid))
3266 return nfserr_stale_stateid; 3258 return nfserr_stale_stateid;
3267 3259
3268 s = find_stateid(stateid); 3260 s = find_stateid(cl, stateid);
3269 if (!s) 3261 if (!s)
3270 return nfserr_stale_stateid; 3262 return nfserr_stale_stateid;
3271 status = check_stateid_generation(stateid, &s->sc_stateid, 1); 3263 status = check_stateid_generation(stateid, &s->sc_stateid, 1);
@@ -3280,6 +3272,24 @@ __be32 nfs4_validate_stateid(stateid_t *stateid)
3280 return nfs_ok; 3272 return nfs_ok;
3281} 3273}
3282 3274
3275static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s)
3276{
3277 struct nfs4_client *cl;
3278
3279 if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
3280 return nfserr_bad_stateid;
3281 if (STALE_STATEID(stateid))
3282 return nfserr_stale_stateid;
3283 cl = find_confirmed_client(&stateid->si_opaque.so_clid);
3284 if (!cl)
3285 return nfserr_expired;
3286 *s = find_stateid_by_type(cl, stateid, typemask);
3287 if (!*s)
3288 return nfserr_bad_stateid;
3289 return nfs_ok;
3290
3291}
3292
3283/* 3293/*
3284* Checks for stateid operations 3294* Checks for stateid operations
3285*/ 3295*/
@@ -3303,18 +3313,9 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
3303 if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 3313 if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
3304 return check_special_stateids(current_fh, stateid, flags); 3314 return check_special_stateids(current_fh, stateid, flags);
3305 3315
3306 status = nfserr_stale_stateid; 3316 status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s);
3307 if (STALE_STATEID(stateid)) 3317 if (status)
3308 goto out; 3318 return status;
3309
3310 /*
3311 * We assume that any stateid that has the current boot time,
3312 * but that we can't find, is expired:
3313 */
3314 status = nfserr_expired;
3315 s = find_stateid(stateid);
3316 if (!s)
3317 goto out;
3318 status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); 3319 status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
3319 if (status) 3320 if (status)
3320 goto out; 3321 goto out;
@@ -3384,10 +3385,11 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3384{ 3385{
3385 stateid_t *stateid = &free_stateid->fr_stateid; 3386 stateid_t *stateid = &free_stateid->fr_stateid;
3386 struct nfs4_stid *s; 3387 struct nfs4_stid *s;
3388 struct nfs4_client *cl = cstate->session->se_client;
3387 __be32 ret = nfserr_bad_stateid; 3389 __be32 ret = nfserr_bad_stateid;
3388 3390
3389 nfs4_lock_state(); 3391 nfs4_lock_state();
3390 s = find_stateid(stateid); 3392 s = find_stateid(cl, stateid);
3391 if (!s) 3393 if (!s)
3392 goto out; 3394 goto out;
3393 switch (s->sc_type) { 3395 switch (s->sc_type) {
@@ -3419,15 +3421,6 @@ setlkflg (int type)
3419 RD_STATE : WR_STATE; 3421 RD_STATE : WR_STATE;
3420} 3422}
3421 3423
3422static __be32 nfs4_nospecial_stateid_checks(stateid_t *stateid)
3423{
3424 if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
3425 return nfserr_bad_stateid;
3426 if (STALE_STATEID(stateid))
3427 return nfserr_stale_stateid;
3428 return nfs_ok;
3429}
3430
3431static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 3424static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
3432{ 3425{
3433 struct svc_fh *current_fh = &cstate->current_fh; 3426 struct svc_fh *current_fh = &cstate->current_fh;
@@ -3458,17 +3451,16 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
3458 struct nfs4_ol_stateid **stpp) 3451 struct nfs4_ol_stateid **stpp)
3459{ 3452{
3460 __be32 status; 3453 __be32 status;
3454 struct nfs4_stid *s;
3461 3455
3462 dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, 3456 dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
3463 seqid, STATEID_VAL(stateid)); 3457 seqid, STATEID_VAL(stateid));
3464 3458
3465 *stpp = NULL; 3459 *stpp = NULL;
3466 status = nfs4_nospecial_stateid_checks(stateid); 3460 status = nfsd4_lookup_stateid(stateid, typemask, &s);
3467 if (status) 3461 if (status)
3468 return status; 3462 return status;
3469 *stpp = find_ol_stateid_by_type(stateid, typemask); 3463 *stpp = openlockstateid(s);
3470 if (*stpp == NULL)
3471 return nfserr_expired;
3472 cstate->replay_owner = (*stpp)->st_stateowner; 3464 cstate->replay_owner = (*stpp)->st_stateowner;
3473 renew_client((*stpp)->st_stateowner->so_client); 3465 renew_client((*stpp)->st_stateowner->so_client);
3474 3466
@@ -3673,6 +3665,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3673{ 3665{
3674 struct nfs4_delegation *dp; 3666 struct nfs4_delegation *dp;
3675 stateid_t *stateid = &dr->dr_stateid; 3667 stateid_t *stateid = &dr->dr_stateid;
3668 struct nfs4_stid *s;
3676 struct inode *inode; 3669 struct inode *inode;
3677 __be32 status; 3670 __be32 status;
3678 3671
@@ -3681,16 +3674,10 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3681 inode = cstate->current_fh.fh_dentry->d_inode; 3674 inode = cstate->current_fh.fh_dentry->d_inode;
3682 3675
3683 nfs4_lock_state(); 3676 nfs4_lock_state();
3684 status = nfserr_bad_stateid; 3677 status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s);
3685 if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) 3678 if (status)
3686 goto out;
3687 status = nfserr_stale_stateid;
3688 if (STALE_STATEID(stateid))
3689 goto out;
3690 status = nfserr_expired;
3691 dp = find_deleg_stateid(stateid);
3692 if (!dp)
3693 goto out; 3679 goto out;
3680 dp = delegstateid(s);
3694 status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate)); 3681 status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
3695 if (status) 3682 if (status)
3696 goto out; 3683 goto out;
@@ -4409,7 +4396,6 @@ nfs4_state_init(void)
4409 for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) { 4396 for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) {
4410 INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]); 4397 INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]);
4411 } 4398 }
4412 idr_init(&stateids);
4413 for (i = 0; i < LOCK_HASH_SIZE; i++) { 4399 for (i = 0; i < LOCK_HASH_SIZE; i++) {
4414 INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]); 4400 INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
4415 } 4401 }
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 2429fffa31dd..5779acde7e70 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3287,6 +3287,7 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
3287 struct nfsd4_test_stateid *test_stateid) 3287 struct nfsd4_test_stateid *test_stateid)
3288{ 3288{
3289 struct nfsd4_compoundargs *argp; 3289 struct nfsd4_compoundargs *argp;
3290 struct nfs4_client *cl = resp->cstate.session->se_client;
3290 stateid_t si; 3291 stateid_t si;
3291 __be32 *p; 3292 __be32 *p;
3292 int i; 3293 int i;
@@ -3302,7 +3303,7 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
3302 nfs4_lock_state(); 3303 nfs4_lock_state();
3303 for (i = 0; i < test_stateid->ts_num_ids; i++) { 3304 for (i = 0; i < test_stateid->ts_num_ids; i++) {
3304 nfsd4_decode_stateid(argp, &si); 3305 nfsd4_decode_stateid(argp, &si);
3305 valid = nfs4_validate_stateid(&si); 3306 valid = nfs4_validate_stateid(cl, &si);
3306 RESERVE_SPACE(4); 3307 RESERVE_SPACE(4);
3307 *p++ = htonl(valid); 3308 *p++ = htonl(valid);
3308 resp->p = p; 3309 resp->p = p;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 55a4d6a108a2..13f6f9f5ceec 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -35,6 +35,7 @@
35#ifndef _NFSD4_STATE_H 35#ifndef _NFSD4_STATE_H
36#define _NFSD4_STATE_H 36#define _NFSD4_STATE_H
37 37
38#include <linux/idr.h>
38#include <linux/sunrpc/svc_xprt.h> 39#include <linux/sunrpc/svc_xprt.h>
39#include <linux/nfsd/nfsfh.h> 40#include <linux/nfsd/nfsfh.h>
40#include "nfsfh.h" 41#include "nfsfh.h"
@@ -231,6 +232,7 @@ struct nfs4_client {
231 struct list_head cl_idhash; /* hash by cl_clientid.id */ 232 struct list_head cl_idhash; /* hash by cl_clientid.id */
232 struct list_head cl_strhash; /* hash by cl_name */ 233 struct list_head cl_strhash; /* hash by cl_name */
233 struct list_head cl_openowners; 234 struct list_head cl_openowners;
235 struct idr cl_stateids; /* stateid lookup */
234 struct list_head cl_delegations; 236 struct list_head cl_delegations;
235 struct list_head cl_lru; /* tail queue */ 237 struct list_head cl_lru; /* tail queue */
236 struct xdr_netobj cl_name; /* id generated by client */ 238 struct xdr_netobj cl_name; /* id generated by client */
@@ -508,7 +510,7 @@ extern void nfsd4_recdir_purge_old(void);
508extern int nfsd4_create_clid_dir(struct nfs4_client *clp); 510extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
509extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); 511extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
510extern void release_session_client(struct nfsd4_session *); 512extern void release_session_client(struct nfsd4_session *);
511extern __be32 nfs4_validate_stateid(stateid_t *); 513extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
512extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); 514extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
513 515
514#endif /* NFSD4_STATE_H */ 516#endif /* NFSD4_STATE_H */