diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 118 |
1 files changed, 118 insertions, 0 deletions
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 | { |