diff options
| author | Bryan Schumaker <bjschuma@netapp.com> | 2011-07-13 11:04:21 -0400 |
|---|---|---|
| committer | J. Bruce Fields <bfields@redhat.com> | 2011-07-15 18:58:47 -0400 |
| commit | e1ca12dfb1be7fe8b82ca723a9b511f7d808bf81 (patch) | |
| tree | 4d70be30b1bbd329d1edb036f9b974cce24f9b40 | |
| parent | ebc63e531cc6a457595dd110b07ac530eae788c3 (diff) | |
NFSD: added FREE_STATEID operation
This operation is used by the client to tell the server to free a
stateid.
Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
| -rw-r--r-- | fs/nfsd/nfs4proc.c | 5 | ||||
| -rw-r--r-- | fs/nfsd/nfs4state.c | 118 | ||||
| -rw-r--r-- | fs/nfsd/nfs4xdr.c | 32 | ||||
| -rw-r--r-- | fs/nfsd/xdr4.h | 8 |
4 files changed, 161 insertions, 2 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 7406f1cfd001..a27dea50273d 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
| @@ -1417,6 +1417,11 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
| 1417 | .op_flags = OP_HANDLES_WRONGSEC, | 1417 | .op_flags = OP_HANDLES_WRONGSEC, |
| 1418 | .op_name = "OP_SECINFO_NO_NAME", | 1418 | .op_name = "OP_SECINFO_NO_NAME", |
| 1419 | }, | 1419 | }, |
| 1420 | [OP_FREE_STATEID] = { | ||
| 1421 | .op_func = (nfsd4op_func)nfsd4_free_stateid, | ||
| 1422 | .op_flags = ALLOWED_WITHOUT_FH, | ||
| 1423 | .op_name = "OP_FREE_STATEID", | ||
| 1424 | }, | ||
| 1420 | }; | 1425 | }; |
| 1421 | 1426 | ||
| 1422 | static const char *nfsd4_op_name(unsigned opnum) | 1427 | static const char *nfsd4_op_name(unsigned opnum) |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e98f3c2e9492..55c36e267b7d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -60,9 +60,12 @@ static u64 current_sessionid = 1; | |||
| 60 | 60 | ||
| 61 | /* forward declarations */ | 61 | /* forward declarations */ |
| 62 | static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); | 62 | static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); |
| 63 | static struct nfs4_stateid * search_for_stateid(stateid_t *stid); | ||
| 64 | static struct nfs4_delegation * search_for_delegation(stateid_t *stid); | ||
| 63 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); | 65 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); |
| 64 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | 66 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; |
| 65 | static void nfs4_set_recdir(char *recdir); | 67 | static void nfs4_set_recdir(char *recdir); |
| 68 | static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner); | ||
| 66 | 69 | ||
| 67 | /* Locking: */ | 70 | /* Locking: */ |
| 68 | 71 | ||
| @@ -3137,6 +3140,11 @@ static int is_delegation_stateid(stateid_t *stateid) | |||
| 3137 | return stateid->si_fileid == 0; | 3140 | return stateid->si_fileid == 0; |
| 3138 | } | 3141 | } |
| 3139 | 3142 | ||
| 3143 | static int is_open_stateid(struct nfs4_stateid *stateid) | ||
| 3144 | { | ||
| 3145 | return stateid->st_openstp == NULL; | ||
| 3146 | } | ||
| 3147 | |||
| 3140 | /* | 3148 | /* |
| 3141 | * Checks for stateid operations | 3149 | * Checks for stateid operations |
| 3142 | */ | 3150 | */ |
| @@ -3216,6 +3224,70 @@ out: | |||
| 3216 | return status; | 3224 | return status; |
| 3217 | } | 3225 | } |
| 3218 | 3226 | ||
| 3227 | static __be32 | ||
| 3228 | nfsd4_free_delegation_stateid(stateid_t *stateid) | ||
| 3229 | { | ||
| 3230 | struct nfs4_delegation *dp = search_for_delegation(stateid); | ||
| 3231 | if (dp) | ||
| 3232 | return nfserr_locks_held; | ||
| 3233 | return nfserr_bad_stateid; | ||
| 3234 | } | ||
| 3235 | |||
| 3236 | static __be32 | ||
| 3237 | nfsd4_free_lock_stateid(struct nfs4_stateid *stp) | ||
| 3238 | { | ||
| 3239 | if (check_for_locks(stp->st_file, stp->st_stateowner)) | ||
| 3240 | return nfserr_locks_held; | ||
| 3241 | release_lock_stateid(stp); | ||
| 3242 | return nfs_ok; | ||
| 3243 | } | ||
| 3244 | |||
| 3245 | /* | ||
| 3246 | * Free a state id | ||
| 3247 | */ | ||
| 3248 | __be32 | ||
| 3249 | nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
| 3250 | struct nfsd4_free_stateid *free_stateid) | ||
| 3251 | { | ||
| 3252 | stateid_t *stateid = &free_stateid->fr_stateid; | ||
| 3253 | struct nfs4_stateid *stp; | ||
| 3254 | __be32 ret; | ||
| 3255 | |||
| 3256 | nfs4_lock_state(); | ||
| 3257 | if (is_delegation_stateid(stateid)) { | ||
| 3258 | ret = nfsd4_free_delegation_stateid(stateid); | ||
| 3259 | goto out; | ||
| 3260 | } | ||
| 3261 | |||
| 3262 | stp = search_for_stateid(stateid); | ||
| 3263 | if (!stp) { | ||
| 3264 | ret = nfserr_bad_stateid; | ||
| 3265 | goto out; | ||
| 3266 | } | ||
| 3267 | if (stateid->si_generation != 0) { | ||
| 3268 | if (stateid->si_generation < stp->st_stateid.si_generation) { | ||
| 3269 | ret = nfserr_old_stateid; | ||
| 3270 | goto out; | ||
| 3271 | } | ||
| 3272 | if (stateid->si_generation > stp->st_stateid.si_generation) { | ||
| 3273 | ret = nfserr_bad_stateid; | ||
| 3274 | goto out; | ||
| 3275 | } | ||
| 3276 | } | ||
| 3277 | |||
| 3278 | if (is_open_stateid(stp)) { | ||
| 3279 | ret = nfserr_locks_held; | ||
| 3280 | goto out; | ||
| 3281 | } else { | ||
| 3282 | ret = nfsd4_free_lock_stateid(stp); | ||
| 3283 | goto out; | ||
| 3284 | } | ||
| 3285 | |||
| 3286 | out: | ||
| 3287 | nfs4_unlock_state(); | ||
| 3288 | return ret; | ||
| 3289 | } | ||
| 3290 | |||
| 3219 | static inline int | 3291 | static inline int |
| 3220 | setlkflg (int type) | 3292 | setlkflg (int type) |
| 3221 | { | 3293 | { |
| @@ -3594,6 +3666,14 @@ static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE]; | |||
| 3594 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; | 3666 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; |
| 3595 | static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; | 3667 | static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; |
| 3596 | 3668 | ||
| 3669 | static int | ||
| 3670 | same_stateid(stateid_t *id_one, stateid_t *id_two) | ||
| 3671 | { | ||
| 3672 | if (id_one->si_stateownerid != id_two->si_stateownerid) | ||
| 3673 | return 0; | ||
| 3674 | return id_one->si_fileid == id_two->si_fileid; | ||
| 3675 | } | ||
| 3676 | |||
| 3597 | static struct nfs4_stateid * | 3677 | static struct nfs4_stateid * |
| 3598 | find_stateid(stateid_t *stid, int flags) | 3678 | find_stateid(stateid_t *stid, int flags) |
| 3599 | { | 3679 | { |
| @@ -3623,6 +3703,44 @@ find_stateid(stateid_t *stid, int flags) | |||
| 3623 | return NULL; | 3703 | return NULL; |
| 3624 | } | 3704 | } |
| 3625 | 3705 | ||
| 3706 | static struct nfs4_stateid * | ||
| 3707 | search_for_stateid(stateid_t *stid) | ||
| 3708 | { | ||
| 3709 | struct nfs4_stateid *local; | ||
| 3710 | unsigned int hashval = stateid_hashval(stid->si_stateownerid, stid->si_fileid); | ||
| 3711 | |||
| 3712 | list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) { | ||
| 3713 | if (same_stateid(&local->st_stateid, stid)) | ||
| 3714 | return local; | ||
| 3715 | } | ||
| 3716 | |||
| 3717 | list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) { | ||
| 3718 | if (same_stateid(&local->st_stateid, stid)) | ||
| 3719 | return local; | ||
| 3720 | } | ||
| 3721 | return NULL; | ||
| 3722 | } | ||
| 3723 | |||
| 3724 | static struct nfs4_delegation * | ||
| 3725 | search_for_delegation(stateid_t *stid) | ||
| 3726 | { | ||
| 3727 | struct nfs4_file *fp; | ||
| 3728 | struct nfs4_delegation *dp; | ||
| 3729 | struct list_head *pos; | ||
| 3730 | int i; | ||
| 3731 | |||
| 3732 | for (i = 0; i < FILE_HASH_SIZE; i++) { | ||
| 3733 | list_for_each_entry(fp, &file_hashtbl[i], fi_hash) { | ||
| 3734 | list_for_each(pos, &fp->fi_delegations) { | ||
| 3735 | dp = list_entry(pos, struct nfs4_delegation, dl_perfile); | ||
| 3736 | if (same_stateid(&dp->dl_stateid, stid)) | ||
| 3737 | return dp; | ||
| 3738 | } | ||
| 3739 | } | ||
| 3740 | } | ||
| 3741 | return NULL; | ||
| 3742 | } | ||
| 3743 | |||
| 3626 | static struct nfs4_delegation * | 3744 | static struct nfs4_delegation * |
| 3627 | find_delegation_stateid(struct inode *ino, stateid_t *stid) | 3745 | find_delegation_stateid(struct inode *ino, stateid_t *stid) |
| 3628 | { | 3746 | { |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 990181103214..ef9bd6f24fc0 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
| @@ -1246,6 +1246,19 @@ nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp, | |||
| 1246 | } | 1246 | } |
| 1247 | 1247 | ||
| 1248 | static __be32 | 1248 | static __be32 |
| 1249 | nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, | ||
| 1250 | struct nfsd4_free_stateid *free_stateid) | ||
| 1251 | { | ||
| 1252 | DECODE_HEAD; | ||
| 1253 | |||
| 1254 | READ_BUF(sizeof(stateid_t)); | ||
| 1255 | READ32(free_stateid->fr_stateid.si_generation); | ||
| 1256 | COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t)); | ||
| 1257 | |||
| 1258 | DECODE_TAIL; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | static __be32 | ||
| 1249 | nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, | 1262 | nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, |
| 1250 | struct nfsd4_sequence *seq) | 1263 | struct nfsd4_sequence *seq) |
| 1251 | { | 1264 | { |
| @@ -1370,7 +1383,7 @@ static nfsd4_dec nfsd41_dec_ops[] = { | |||
| 1370 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, | 1383 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, |
| 1371 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, | 1384 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, |
| 1372 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, | 1385 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, |
| 1373 | [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, | 1386 | [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid, |
| 1374 | [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, | 1387 | [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1375 | [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, | 1388 | [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1376 | [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, | 1389 | [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, |
| @@ -3116,6 +3129,21 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr, | |||
| 3116 | } | 3129 | } |
| 3117 | 3130 | ||
| 3118 | static __be32 | 3131 | static __be32 |
| 3132 | nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr, | ||
| 3133 | struct nfsd4_free_stateid *free_stateid) | ||
| 3134 | { | ||
| 3135 | __be32 *p; | ||
| 3136 | |||
| 3137 | if (nfserr) | ||
| 3138 | return nfserr; | ||
| 3139 | |||
| 3140 | RESERVE_SPACE(4); | ||
| 3141 | WRITE32(nfserr); | ||
| 3142 | ADJUST_ARGS(); | ||
| 3143 | return nfserr; | ||
| 3144 | } | ||
| 3145 | |||
| 3146 | static __be32 | ||
| 3119 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | 3147 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, |
| 3120 | struct nfsd4_sequence *seq) | 3148 | struct nfsd4_sequence *seq) |
| 3121 | { | 3149 | { |
| @@ -3196,7 +3224,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
| 3196 | [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, | 3224 | [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, |
| 3197 | [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, | 3225 | [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, |
| 3198 | [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session, | 3226 | [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session, |
| 3199 | [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop, | 3227 | [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_free_stateid, |
| 3200 | [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, | 3228 | [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, |
| 3201 | [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, | 3229 | [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, |
| 3202 | [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, | 3230 | [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 366401e1a536..ed1784d31a60 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
| @@ -342,6 +342,11 @@ struct nfsd4_setclientid_confirm { | |||
| 342 | nfs4_verifier sc_confirm; | 342 | nfs4_verifier sc_confirm; |
| 343 | }; | 343 | }; |
| 344 | 344 | ||
| 345 | struct nfsd4_free_stateid { | ||
| 346 | stateid_t fr_stateid; /* request */ | ||
| 347 | __be32 fr_status; /* response */ | ||
| 348 | }; | ||
| 349 | |||
| 345 | /* also used for NVERIFY */ | 350 | /* also used for NVERIFY */ |
| 346 | struct nfsd4_verify { | 351 | struct nfsd4_verify { |
| 347 | u32 ve_bmval[3]; /* request */ | 352 | u32 ve_bmval[3]; /* request */ |
| @@ -432,6 +437,7 @@ struct nfsd4_op { | |||
| 432 | struct nfsd4_destroy_session destroy_session; | 437 | struct nfsd4_destroy_session destroy_session; |
| 433 | struct nfsd4_sequence sequence; | 438 | struct nfsd4_sequence sequence; |
| 434 | struct nfsd4_reclaim_complete reclaim_complete; | 439 | struct nfsd4_reclaim_complete reclaim_complete; |
| 440 | struct nfsd4_free_stateid free_stateid; | ||
| 435 | } u; | 441 | } u; |
| 436 | struct nfs4_replay * replay; | 442 | struct nfs4_replay * replay; |
| 437 | }; | 443 | }; |
| @@ -564,6 +570,8 @@ extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp, | |||
| 564 | struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr); | 570 | struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr); |
| 565 | extern __be32 nfsd4_renew(struct svc_rqst *rqstp, | 571 | extern __be32 nfsd4_renew(struct svc_rqst *rqstp, |
| 566 | struct nfsd4_compound_state *, clientid_t *clid); | 572 | struct nfsd4_compound_state *, clientid_t *clid); |
| 573 | extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp, | ||
| 574 | struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid); | ||
| 567 | #endif | 575 | #endif |
| 568 | 576 | ||
| 569 | /* | 577 | /* |
