diff options
Diffstat (limited to 'fs')
-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 | /* |