diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4state.c | 104 | ||||
-rw-r--r-- | fs/nfsd/state.h | 1 |
2 files changed, 59 insertions, 46 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 5c0cac173068..e9c3afe4b5d3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -218,6 +218,13 @@ static void nfsd4_put_session(struct nfsd4_session *ses) | |||
218 | spin_unlock(&nn->client_lock); | 218 | spin_unlock(&nn->client_lock); |
219 | } | 219 | } |
220 | 220 | ||
221 | static inline struct nfs4_stateowner * | ||
222 | nfs4_get_stateowner(struct nfs4_stateowner *sop) | ||
223 | { | ||
224 | atomic_inc(&sop->so_count); | ||
225 | return sop; | ||
226 | } | ||
227 | |||
221 | static int | 228 | static int |
222 | same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner) | 229 | same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner) |
223 | { | 230 | { |
@@ -237,10 +244,8 @@ find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open, | |||
237 | so_strhash) { | 244 | so_strhash) { |
238 | if (!so->so_is_open_owner) | 245 | if (!so->so_is_open_owner) |
239 | continue; | 246 | continue; |
240 | if (same_owner_str(so, &open->op_owner)) { | 247 | if (same_owner_str(so, &open->op_owner)) |
241 | atomic_inc(&so->so_count); | 248 | return openowner(nfs4_get_stateowner(so)); |
242 | return openowner(so); | ||
243 | } | ||
244 | } | 249 | } |
245 | return NULL; | 250 | return NULL; |
246 | } | 251 | } |
@@ -678,18 +683,14 @@ nfs4_put_stid(struct nfs4_stid *s) | |||
678 | static void nfs4_put_deleg_lease(struct nfs4_file *fp) | 683 | static void nfs4_put_deleg_lease(struct nfs4_file *fp) |
679 | { | 684 | { |
680 | struct file *filp = NULL; | 685 | struct file *filp = NULL; |
681 | struct file_lock *fl; | ||
682 | 686 | ||
683 | spin_lock(&fp->fi_lock); | 687 | spin_lock(&fp->fi_lock); |
684 | if (fp->fi_lease && atomic_dec_and_test(&fp->fi_delegees)) { | 688 | if (fp->fi_deleg_file && atomic_dec_and_test(&fp->fi_delegees)) |
685 | swap(filp, fp->fi_deleg_file); | 689 | swap(filp, fp->fi_deleg_file); |
686 | fl = fp->fi_lease; | ||
687 | fp->fi_lease = NULL; | ||
688 | } | ||
689 | spin_unlock(&fp->fi_lock); | 690 | spin_unlock(&fp->fi_lock); |
690 | 691 | ||
691 | if (filp) { | 692 | if (filp) { |
692 | vfs_setlease(filp, F_UNLCK, &fl); | 693 | vfs_setlease(filp, F_UNLCK, NULL, NULL); |
693 | fput(filp); | 694 | fput(filp); |
694 | } | 695 | } |
695 | } | 696 | } |
@@ -1655,7 +1656,7 @@ __destroy_client(struct nfs4_client *clp) | |||
1655 | } | 1656 | } |
1656 | while (!list_empty(&clp->cl_openowners)) { | 1657 | while (!list_empty(&clp->cl_openowners)) { |
1657 | oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); | 1658 | oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); |
1658 | atomic_inc(&oo->oo_owner.so_count); | 1659 | nfs4_get_stateowner(&oo->oo_owner); |
1659 | release_openowner(oo); | 1660 | release_openowner(oo); |
1660 | } | 1661 | } |
1661 | nfsd4_shutdown_callback(clp); | 1662 | nfsd4_shutdown_callback(clp); |
@@ -3067,8 +3068,8 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct knfsd_fh *fh) | |||
3067 | INIT_LIST_HEAD(&fp->fi_stateids); | 3068 | INIT_LIST_HEAD(&fp->fi_stateids); |
3068 | INIT_LIST_HEAD(&fp->fi_delegations); | 3069 | INIT_LIST_HEAD(&fp->fi_delegations); |
3069 | fh_copy_shallow(&fp->fi_fhandle, fh); | 3070 | fh_copy_shallow(&fp->fi_fhandle, fh); |
3071 | fp->fi_deleg_file = NULL; | ||
3070 | fp->fi_had_conflict = false; | 3072 | fp->fi_had_conflict = false; |
3071 | fp->fi_lease = NULL; | ||
3072 | fp->fi_share_deny = 0; | 3073 | fp->fi_share_deny = 0; |
3073 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); | 3074 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); |
3074 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); | 3075 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); |
@@ -3136,8 +3137,7 @@ static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, | |||
3136 | { | 3137 | { |
3137 | if (!nfsd4_has_session(cstate)) { | 3138 | if (!nfsd4_has_session(cstate)) { |
3138 | mutex_lock(&so->so_replay.rp_mutex); | 3139 | mutex_lock(&so->so_replay.rp_mutex); |
3139 | cstate->replay_owner = so; | 3140 | cstate->replay_owner = nfs4_get_stateowner(so); |
3140 | atomic_inc(&so->so_count); | ||
3141 | } | 3141 | } |
3142 | } | 3142 | } |
3143 | 3143 | ||
@@ -3236,8 +3236,7 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, | |||
3236 | atomic_inc(&stp->st_stid.sc_count); | 3236 | atomic_inc(&stp->st_stid.sc_count); |
3237 | stp->st_stid.sc_type = NFS4_OPEN_STID; | 3237 | stp->st_stid.sc_type = NFS4_OPEN_STID; |
3238 | INIT_LIST_HEAD(&stp->st_locks); | 3238 | INIT_LIST_HEAD(&stp->st_locks); |
3239 | stp->st_stateowner = &oo->oo_owner; | 3239 | stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); |
3240 | atomic_inc(&stp->st_stateowner->so_count); | ||
3241 | get_nfs4_file(fp); | 3240 | get_nfs4_file(fp); |
3242 | stp->st_stid.sc_file = fp; | 3241 | stp->st_stid.sc_file = fp; |
3243 | stp->st_access_bmap = 0; | 3242 | stp->st_access_bmap = 0; |
@@ -3434,18 +3433,20 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp) | |||
3434 | } | 3433 | } |
3435 | 3434 | ||
3436 | /* Called from break_lease() with i_lock held. */ | 3435 | /* Called from break_lease() with i_lock held. */ |
3437 | static void nfsd_break_deleg_cb(struct file_lock *fl) | 3436 | static bool |
3437 | nfsd_break_deleg_cb(struct file_lock *fl) | ||
3438 | { | 3438 | { |
3439 | bool ret = false; | ||
3439 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; | 3440 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; |
3440 | struct nfs4_delegation *dp; | 3441 | struct nfs4_delegation *dp; |
3441 | 3442 | ||
3442 | if (!fp) { | 3443 | if (!fp) { |
3443 | WARN(1, "(%p)->fl_owner NULL\n", fl); | 3444 | WARN(1, "(%p)->fl_owner NULL\n", fl); |
3444 | return; | 3445 | return ret; |
3445 | } | 3446 | } |
3446 | if (fp->fi_had_conflict) { | 3447 | if (fp->fi_had_conflict) { |
3447 | WARN(1, "duplicate break on %p\n", fp); | 3448 | WARN(1, "duplicate break on %p\n", fp); |
3448 | return; | 3449 | return ret; |
3449 | } | 3450 | } |
3450 | /* | 3451 | /* |
3451 | * We don't want the locks code to timeout the lease for us; | 3452 | * We don't want the locks code to timeout the lease for us; |
@@ -3457,24 +3458,23 @@ static void nfsd_break_deleg_cb(struct file_lock *fl) | |||
3457 | spin_lock(&fp->fi_lock); | 3458 | spin_lock(&fp->fi_lock); |
3458 | fp->fi_had_conflict = true; | 3459 | fp->fi_had_conflict = true; |
3459 | /* | 3460 | /* |
3460 | * If there are no delegations on the list, then we can't count on this | 3461 | * If there are no delegations on the list, then return true |
3461 | * lease ever being cleaned up. Set the fl_break_time to jiffies so that | 3462 | * so that the lease code will go ahead and delete it. |
3462 | * time_out_leases will do it ASAP. The fact that fi_had_conflict is now | ||
3463 | * true should keep any new delegations from being hashed. | ||
3464 | */ | 3463 | */ |
3465 | if (list_empty(&fp->fi_delegations)) | 3464 | if (list_empty(&fp->fi_delegations)) |
3466 | fl->fl_break_time = jiffies; | 3465 | ret = true; |
3467 | else | 3466 | else |
3468 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) | 3467 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) |
3469 | nfsd_break_one_deleg(dp); | 3468 | nfsd_break_one_deleg(dp); |
3470 | spin_unlock(&fp->fi_lock); | 3469 | spin_unlock(&fp->fi_lock); |
3470 | return ret; | ||
3471 | } | 3471 | } |
3472 | 3472 | ||
3473 | static | 3473 | static int |
3474 | int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | 3474 | nfsd_change_deleg_cb(struct file_lock **onlist, int arg, struct list_head *dispose) |
3475 | { | 3475 | { |
3476 | if (arg & F_UNLCK) | 3476 | if (arg & F_UNLCK) |
3477 | return lease_modify(onlist, arg); | 3477 | return lease_modify(onlist, arg, dispose); |
3478 | else | 3478 | else |
3479 | return -EAGAIN; | 3479 | return -EAGAIN; |
3480 | } | 3480 | } |
@@ -3820,7 +3820,7 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag) | |||
3820 | static int nfs4_setlease(struct nfs4_delegation *dp) | 3820 | static int nfs4_setlease(struct nfs4_delegation *dp) |
3821 | { | 3821 | { |
3822 | struct nfs4_file *fp = dp->dl_stid.sc_file; | 3822 | struct nfs4_file *fp = dp->dl_stid.sc_file; |
3823 | struct file_lock *fl; | 3823 | struct file_lock *fl, *ret; |
3824 | struct file *filp; | 3824 | struct file *filp; |
3825 | int status = 0; | 3825 | int status = 0; |
3826 | 3826 | ||
@@ -3834,11 +3834,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp) | |||
3834 | return -EBADF; | 3834 | return -EBADF; |
3835 | } | 3835 | } |
3836 | fl->fl_file = filp; | 3836 | fl->fl_file = filp; |
3837 | status = vfs_setlease(filp, fl->fl_type, &fl); | 3837 | ret = fl; |
3838 | if (status) { | 3838 | status = vfs_setlease(filp, fl->fl_type, &fl, NULL); |
3839 | if (fl) | ||
3839 | locks_free_lock(fl); | 3840 | locks_free_lock(fl); |
3841 | if (status) | ||
3840 | goto out_fput; | 3842 | goto out_fput; |
3841 | } | ||
3842 | spin_lock(&state_lock); | 3843 | spin_lock(&state_lock); |
3843 | spin_lock(&fp->fi_lock); | 3844 | spin_lock(&fp->fi_lock); |
3844 | /* Did the lease get broken before we took the lock? */ | 3845 | /* Did the lease get broken before we took the lock? */ |
@@ -3846,13 +3847,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp) | |||
3846 | if (fp->fi_had_conflict) | 3847 | if (fp->fi_had_conflict) |
3847 | goto out_unlock; | 3848 | goto out_unlock; |
3848 | /* Race breaker */ | 3849 | /* Race breaker */ |
3849 | if (fp->fi_lease) { | 3850 | if (fp->fi_deleg_file) { |
3850 | status = 0; | 3851 | status = 0; |
3851 | atomic_inc(&fp->fi_delegees); | 3852 | atomic_inc(&fp->fi_delegees); |
3852 | hash_delegation_locked(dp, fp); | 3853 | hash_delegation_locked(dp, fp); |
3853 | goto out_unlock; | 3854 | goto out_unlock; |
3854 | } | 3855 | } |
3855 | fp->fi_lease = fl; | ||
3856 | fp->fi_deleg_file = filp; | 3856 | fp->fi_deleg_file = filp; |
3857 | atomic_set(&fp->fi_delegees, 1); | 3857 | atomic_set(&fp->fi_delegees, 1); |
3858 | hash_delegation_locked(dp, fp); | 3858 | hash_delegation_locked(dp, fp); |
@@ -3885,7 +3885,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, | |||
3885 | spin_lock(&state_lock); | 3885 | spin_lock(&state_lock); |
3886 | spin_lock(&fp->fi_lock); | 3886 | spin_lock(&fp->fi_lock); |
3887 | dp->dl_stid.sc_file = fp; | 3887 | dp->dl_stid.sc_file = fp; |
3888 | if (!fp->fi_lease) { | 3888 | if (!fp->fi_deleg_file) { |
3889 | spin_unlock(&fp->fi_lock); | 3889 | spin_unlock(&fp->fi_lock); |
3890 | spin_unlock(&state_lock); | 3890 | spin_unlock(&state_lock); |
3891 | status = nfs4_setlease(dp); | 3891 | status = nfs4_setlease(dp); |
@@ -4929,9 +4929,25 @@ nfs4_transform_lock_offset(struct file_lock *lock) | |||
4929 | lock->fl_end = OFFSET_MAX; | 4929 | lock->fl_end = OFFSET_MAX; |
4930 | } | 4930 | } |
4931 | 4931 | ||
4932 | /* Hack!: For now, we're defining this just so we can use a pointer to it | 4932 | static void nfsd4_fl_get_owner(struct file_lock *dst, struct file_lock *src) |
4933 | * as a unique cookie to identify our (NFSv4's) posix locks. */ | 4933 | { |
4934 | struct nfs4_lockowner *lo = (struct nfs4_lockowner *)src->fl_owner; | ||
4935 | dst->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lo->lo_owner)); | ||
4936 | } | ||
4937 | |||
4938 | static void nfsd4_fl_put_owner(struct file_lock *fl) | ||
4939 | { | ||
4940 | struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner; | ||
4941 | |||
4942 | if (lo) { | ||
4943 | nfs4_put_stateowner(&lo->lo_owner); | ||
4944 | fl->fl_owner = NULL; | ||
4945 | } | ||
4946 | } | ||
4947 | |||
4934 | static const struct lock_manager_operations nfsd_posix_mng_ops = { | 4948 | static const struct lock_manager_operations nfsd_posix_mng_ops = { |
4949 | .lm_get_owner = nfsd4_fl_get_owner, | ||
4950 | .lm_put_owner = nfsd4_fl_put_owner, | ||
4935 | }; | 4951 | }; |
4936 | 4952 | ||
4937 | static inline void | 4953 | static inline void |
@@ -4977,10 +4993,8 @@ find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner, | |||
4977 | so_strhash) { | 4993 | so_strhash) { |
4978 | if (so->so_is_open_owner) | 4994 | if (so->so_is_open_owner) |
4979 | continue; | 4995 | continue; |
4980 | if (!same_owner_str(so, owner)) | 4996 | if (same_owner_str(so, owner)) |
4981 | continue; | 4997 | return lockowner(nfs4_get_stateowner(so)); |
4982 | atomic_inc(&so->so_count); | ||
4983 | return lockowner(so); | ||
4984 | } | 4998 | } |
4985 | return NULL; | 4999 | return NULL; |
4986 | } | 5000 | } |
@@ -5059,8 +5073,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, | |||
5059 | 5073 | ||
5060 | atomic_inc(&stp->st_stid.sc_count); | 5074 | atomic_inc(&stp->st_stid.sc_count); |
5061 | stp->st_stid.sc_type = NFS4_LOCK_STID; | 5075 | stp->st_stid.sc_type = NFS4_LOCK_STID; |
5062 | stp->st_stateowner = &lo->lo_owner; | 5076 | stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); |
5063 | atomic_inc(&lo->lo_owner.so_count); | ||
5064 | get_nfs4_file(fp); | 5077 | get_nfs4_file(fp); |
5065 | stp->st_stid.sc_file = fp; | 5078 | stp->st_stid.sc_file = fp; |
5066 | stp->st_stid.sc_free = nfs4_free_lock_stateid; | 5079 | stp->st_stid.sc_free = nfs4_free_lock_stateid; |
@@ -5299,7 +5312,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5299 | status = nfserr_openmode; | 5312 | status = nfserr_openmode; |
5300 | goto out; | 5313 | goto out; |
5301 | } | 5314 | } |
5302 | file_lock->fl_owner = (fl_owner_t)lock_sop; | 5315 | |
5316 | file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); | ||
5303 | file_lock->fl_pid = current->tgid; | 5317 | file_lock->fl_pid = current->tgid; |
5304 | file_lock->fl_file = filp; | 5318 | file_lock->fl_file = filp; |
5305 | file_lock->fl_flags = FL_POSIX; | 5319 | file_lock->fl_flags = FL_POSIX; |
@@ -5495,7 +5509,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5495 | } | 5509 | } |
5496 | 5510 | ||
5497 | file_lock->fl_type = F_UNLCK; | 5511 | file_lock->fl_type = F_UNLCK; |
5498 | file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); | 5512 | file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); |
5499 | file_lock->fl_pid = current->tgid; | 5513 | file_lock->fl_pid = current->tgid; |
5500 | file_lock->fl_file = filp; | 5514 | file_lock->fl_file = filp; |
5501 | file_lock->fl_flags = FL_POSIX; | 5515 | file_lock->fl_flags = FL_POSIX; |
@@ -5602,7 +5616,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
5602 | } | 5616 | } |
5603 | } | 5617 | } |
5604 | 5618 | ||
5605 | atomic_inc(&sop->so_count); | 5619 | nfs4_get_stateowner(sop); |
5606 | break; | 5620 | break; |
5607 | } | 5621 | } |
5608 | spin_unlock(&clp->cl_lock); | 5622 | spin_unlock(&clp->cl_lock); |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 0a47c6a6b301..2712042a66b1 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -486,7 +486,6 @@ struct nfs4_file { | |||
486 | atomic_t fi_access[2]; | 486 | atomic_t fi_access[2]; |
487 | u32 fi_share_deny; | 487 | u32 fi_share_deny; |
488 | struct file *fi_deleg_file; | 488 | struct file *fi_deleg_file; |
489 | struct file_lock *fi_lease; | ||
490 | atomic_t fi_delegees; | 489 | atomic_t fi_delegees; |
491 | struct knfsd_fh fi_fhandle; | 490 | struct knfsd_fh fi_fhandle; |
492 | bool fi_had_conflict; | 491 | bool fi_had_conflict; |