diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 186 |
1 files changed, 106 insertions, 80 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d98d0213285d..54b60bfceb8d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -230,9 +230,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
230 | dp->dl_client = clp; | 230 | dp->dl_client = clp; |
231 | get_nfs4_file(fp); | 231 | get_nfs4_file(fp); |
232 | dp->dl_file = fp; | 232 | dp->dl_file = fp; |
233 | dp->dl_vfs_file = find_readable_file(fp); | ||
234 | get_file(dp->dl_vfs_file); | ||
235 | dp->dl_flock = NULL; | ||
236 | dp->dl_type = type; | 233 | dp->dl_type = type; |
237 | dp->dl_stateid.si_boot = boot_time; | 234 | dp->dl_stateid.si_boot = boot_time; |
238 | dp->dl_stateid.si_stateownerid = current_delegid++; | 235 | dp->dl_stateid.si_stateownerid = current_delegid++; |
@@ -241,8 +238,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
241 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); | 238 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); |
242 | dp->dl_time = 0; | 239 | dp->dl_time = 0; |
243 | atomic_set(&dp->dl_count, 1); | 240 | atomic_set(&dp->dl_count, 1); |
244 | list_add(&dp->dl_perfile, &fp->fi_delegations); | ||
245 | list_add(&dp->dl_perclnt, &clp->cl_delegations); | ||
246 | INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); | 241 | INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); |
247 | return dp; | 242 | return dp; |
248 | } | 243 | } |
@@ -253,36 +248,30 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
253 | if (atomic_dec_and_test(&dp->dl_count)) { | 248 | if (atomic_dec_and_test(&dp->dl_count)) { |
254 | dprintk("NFSD: freeing dp %p\n",dp); | 249 | dprintk("NFSD: freeing dp %p\n",dp); |
255 | put_nfs4_file(dp->dl_file); | 250 | put_nfs4_file(dp->dl_file); |
256 | fput(dp->dl_vfs_file); | ||
257 | kmem_cache_free(deleg_slab, dp); | 251 | kmem_cache_free(deleg_slab, dp); |
258 | num_delegations--; | 252 | num_delegations--; |
259 | } | 253 | } |
260 | } | 254 | } |
261 | 255 | ||
262 | /* Remove the associated file_lock first, then remove the delegation. | 256 | static void nfs4_put_deleg_lease(struct nfs4_file *fp) |
263 | * lease_modify() is called to remove the FS_LEASE file_lock from | ||
264 | * the i_flock list, eventually calling nfsd's lock_manager | ||
265 | * fl_release_callback. | ||
266 | */ | ||
267 | static void | ||
268 | nfs4_close_delegation(struct nfs4_delegation *dp) | ||
269 | { | 257 | { |
270 | dprintk("NFSD: close_delegation dp %p\n",dp); | 258 | if (atomic_dec_and_test(&fp->fi_delegees)) { |
271 | /* XXX: do we even need this check?: */ | 259 | vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease); |
272 | if (dp->dl_flock) | 260 | fp->fi_lease = NULL; |
273 | vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock); | 261 | fp->fi_deleg_file = NULL; |
262 | } | ||
274 | } | 263 | } |
275 | 264 | ||
276 | /* Called under the state lock. */ | 265 | /* Called under the state lock. */ |
277 | static void | 266 | static void |
278 | unhash_delegation(struct nfs4_delegation *dp) | 267 | unhash_delegation(struct nfs4_delegation *dp) |
279 | { | 268 | { |
280 | list_del_init(&dp->dl_perfile); | ||
281 | list_del_init(&dp->dl_perclnt); | 269 | list_del_init(&dp->dl_perclnt); |
282 | spin_lock(&recall_lock); | 270 | spin_lock(&recall_lock); |
271 | list_del_init(&dp->dl_perfile); | ||
283 | list_del_init(&dp->dl_recall_lru); | 272 | list_del_init(&dp->dl_recall_lru); |
284 | spin_unlock(&recall_lock); | 273 | spin_unlock(&recall_lock); |
285 | nfs4_close_delegation(dp); | 274 | nfs4_put_deleg_lease(dp->dl_file); |
286 | nfs4_put_delegation(dp); | 275 | nfs4_put_delegation(dp); |
287 | } | 276 | } |
288 | 277 | ||
@@ -958,8 +947,6 @@ expire_client(struct nfs4_client *clp) | |||
958 | spin_lock(&recall_lock); | 947 | spin_lock(&recall_lock); |
959 | while (!list_empty(&clp->cl_delegations)) { | 948 | while (!list_empty(&clp->cl_delegations)) { |
960 | dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); | 949 | dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); |
961 | dprintk("NFSD: expire client. dp %p, fp %p\n", dp, | ||
962 | dp->dl_flock); | ||
963 | list_del_init(&dp->dl_perclnt); | 950 | list_del_init(&dp->dl_perclnt); |
964 | list_move(&dp->dl_recall_lru, &reaplist); | 951 | list_move(&dp->dl_recall_lru, &reaplist); |
965 | } | 952 | } |
@@ -2078,6 +2065,7 @@ alloc_init_file(struct inode *ino) | |||
2078 | fp->fi_inode = igrab(ino); | 2065 | fp->fi_inode = igrab(ino); |
2079 | fp->fi_id = current_fileid++; | 2066 | fp->fi_id = current_fileid++; |
2080 | fp->fi_had_conflict = false; | 2067 | fp->fi_had_conflict = false; |
2068 | fp->fi_lease = NULL; | ||
2081 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); | 2069 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); |
2082 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); | 2070 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); |
2083 | spin_lock(&recall_lock); | 2071 | spin_lock(&recall_lock); |
@@ -2329,23 +2317,8 @@ nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access) | |||
2329 | nfs4_file_put_access(fp, O_RDONLY); | 2317 | nfs4_file_put_access(fp, O_RDONLY); |
2330 | } | 2318 | } |
2331 | 2319 | ||
2332 | /* | 2320 | static void nfsd_break_one_deleg(struct nfs4_delegation *dp) |
2333 | * Spawn a thread to perform a recall on the delegation represented | ||
2334 | * by the lease (file_lock) | ||
2335 | * | ||
2336 | * Called from break_lease() with lock_flocks() held. | ||
2337 | * Note: we assume break_lease will only call this *once* for any given | ||
2338 | * lease. | ||
2339 | */ | ||
2340 | static | ||
2341 | void nfsd_break_deleg_cb(struct file_lock *fl) | ||
2342 | { | 2321 | { |
2343 | struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; | ||
2344 | |||
2345 | dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); | ||
2346 | if (!dp) | ||
2347 | return; | ||
2348 | |||
2349 | /* We're assuming the state code never drops its reference | 2322 | /* We're assuming the state code never drops its reference |
2350 | * without first removing the lease. Since we're in this lease | 2323 | * without first removing the lease. Since we're in this lease |
2351 | * callback (and since the lease code is serialized by the kernel | 2324 | * callback (and since the lease code is serialized by the kernel |
@@ -2353,22 +2326,35 @@ void nfsd_break_deleg_cb(struct file_lock *fl) | |||
2353 | * it's safe to take a reference: */ | 2326 | * it's safe to take a reference: */ |
2354 | atomic_inc(&dp->dl_count); | 2327 | atomic_inc(&dp->dl_count); |
2355 | 2328 | ||
2356 | spin_lock(&recall_lock); | ||
2357 | list_add_tail(&dp->dl_recall_lru, &del_recall_lru); | 2329 | list_add_tail(&dp->dl_recall_lru, &del_recall_lru); |
2358 | spin_unlock(&recall_lock); | ||
2359 | 2330 | ||
2360 | /* only place dl_time is set. protected by lock_flocks*/ | 2331 | /* only place dl_time is set. protected by lock_flocks*/ |
2361 | dp->dl_time = get_seconds(); | 2332 | dp->dl_time = get_seconds(); |
2362 | 2333 | ||
2334 | nfsd4_cb_recall(dp); | ||
2335 | } | ||
2336 | |||
2337 | /* Called from break_lease() with lock_flocks() held. */ | ||
2338 | static void nfsd_break_deleg_cb(struct file_lock *fl) | ||
2339 | { | ||
2340 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; | ||
2341 | struct nfs4_delegation *dp; | ||
2342 | |||
2343 | BUG_ON(!fp); | ||
2344 | /* We assume break_lease is only called once per lease: */ | ||
2345 | BUG_ON(fp->fi_had_conflict); | ||
2363 | /* | 2346 | /* |
2364 | * We don't want the locks code to timeout the lease for us; | 2347 | * We don't want the locks code to timeout the lease for us; |
2365 | * we'll remove it ourself if the delegation isn't returned | 2348 | * we'll remove it ourself if a delegation isn't returned |
2366 | * in time. | 2349 | * in time: |
2367 | */ | 2350 | */ |
2368 | fl->fl_break_time = 0; | 2351 | fl->fl_break_time = 0; |
2369 | 2352 | ||
2370 | dp->dl_file->fi_had_conflict = true; | 2353 | spin_lock(&recall_lock); |
2371 | nfsd4_cb_recall(dp); | 2354 | fp->fi_had_conflict = true; |
2355 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) | ||
2356 | nfsd_break_one_deleg(dp); | ||
2357 | spin_unlock(&recall_lock); | ||
2372 | } | 2358 | } |
2373 | 2359 | ||
2374 | static | 2360 | static |
@@ -2459,13 +2445,15 @@ nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) | |||
2459 | static struct nfs4_delegation * | 2445 | static struct nfs4_delegation * |
2460 | find_delegation_file(struct nfs4_file *fp, stateid_t *stid) | 2446 | find_delegation_file(struct nfs4_file *fp, stateid_t *stid) |
2461 | { | 2447 | { |
2462 | struct nfs4_delegation *dp; | 2448 | struct nfs4_delegation *dp = NULL; |
2463 | 2449 | ||
2450 | spin_lock(&recall_lock); | ||
2464 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) { | 2451 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) { |
2465 | if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) | 2452 | if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) |
2466 | return dp; | 2453 | break; |
2467 | } | 2454 | } |
2468 | return NULL; | 2455 | spin_unlock(&recall_lock); |
2456 | return dp; | ||
2469 | } | 2457 | } |
2470 | 2458 | ||
2471 | int share_access_to_flags(u32 share_access) | 2459 | int share_access_to_flags(u32 share_access) |
@@ -2641,6 +2629,66 @@ static bool nfsd4_cb_channel_good(struct nfs4_client *clp) | |||
2641 | return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; | 2629 | return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; |
2642 | } | 2630 | } |
2643 | 2631 | ||
2632 | static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int flag) | ||
2633 | { | ||
2634 | struct file_lock *fl; | ||
2635 | |||
2636 | fl = locks_alloc_lock(); | ||
2637 | if (!fl) | ||
2638 | return NULL; | ||
2639 | locks_init_lock(fl); | ||
2640 | fl->fl_lmops = &nfsd_lease_mng_ops; | ||
2641 | fl->fl_flags = FL_LEASE; | ||
2642 | fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; | ||
2643 | fl->fl_end = OFFSET_MAX; | ||
2644 | fl->fl_owner = (fl_owner_t)(dp->dl_file); | ||
2645 | fl->fl_pid = current->tgid; | ||
2646 | return fl; | ||
2647 | } | ||
2648 | |||
2649 | static int nfs4_setlease(struct nfs4_delegation *dp, int flag) | ||
2650 | { | ||
2651 | struct nfs4_file *fp = dp->dl_file; | ||
2652 | struct file_lock *fl; | ||
2653 | int status; | ||
2654 | |||
2655 | fl = nfs4_alloc_init_lease(dp, flag); | ||
2656 | if (!fl) | ||
2657 | return -ENOMEM; | ||
2658 | fl->fl_file = find_readable_file(fp); | ||
2659 | list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); | ||
2660 | status = vfs_setlease(fl->fl_file, fl->fl_type, &fl); | ||
2661 | if (status) { | ||
2662 | list_del_init(&dp->dl_perclnt); | ||
2663 | locks_free_lock(fl); | ||
2664 | return -ENOMEM; | ||
2665 | } | ||
2666 | fp->fi_lease = fl; | ||
2667 | fp->fi_deleg_file = fl->fl_file; | ||
2668 | get_file(fp->fi_deleg_file); | ||
2669 | atomic_set(&fp->fi_delegees, 1); | ||
2670 | list_add(&dp->dl_perfile, &fp->fi_delegations); | ||
2671 | return 0; | ||
2672 | } | ||
2673 | |||
2674 | static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) | ||
2675 | { | ||
2676 | struct nfs4_file *fp = dp->dl_file; | ||
2677 | |||
2678 | if (!fp->fi_lease) | ||
2679 | return nfs4_setlease(dp, flag); | ||
2680 | spin_lock(&recall_lock); | ||
2681 | if (fp->fi_had_conflict) { | ||
2682 | spin_unlock(&recall_lock); | ||
2683 | return -EAGAIN; | ||
2684 | } | ||
2685 | atomic_inc(&fp->fi_delegees); | ||
2686 | list_add(&dp->dl_perfile, &fp->fi_delegations); | ||
2687 | spin_unlock(&recall_lock); | ||
2688 | list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); | ||
2689 | return 0; | ||
2690 | } | ||
2691 | |||
2644 | /* | 2692 | /* |
2645 | * Attempt to hand out a delegation. | 2693 | * Attempt to hand out a delegation. |
2646 | */ | 2694 | */ |
@@ -2650,7 +2698,6 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2650 | struct nfs4_delegation *dp; | 2698 | struct nfs4_delegation *dp; |
2651 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2699 | struct nfs4_stateowner *sop = stp->st_stateowner; |
2652 | int cb_up; | 2700 | int cb_up; |
2653 | struct file_lock *fl; | ||
2654 | int status, flag = 0; | 2701 | int status, flag = 0; |
2655 | 2702 | ||
2656 | cb_up = nfsd4_cb_channel_good(sop->so_client); | 2703 | cb_up = nfsd4_cb_channel_good(sop->so_client); |
@@ -2681,36 +2728,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2681 | } | 2728 | } |
2682 | 2729 | ||
2683 | dp = alloc_init_deleg(sop->so_client, stp, fh, flag); | 2730 | dp = alloc_init_deleg(sop->so_client, stp, fh, flag); |
2684 | if (dp == NULL) { | 2731 | if (dp == NULL) |
2685 | flag = NFS4_OPEN_DELEGATE_NONE; | 2732 | goto out_no_deleg; |
2686 | goto out; | 2733 | status = nfs4_set_delegation(dp, flag); |
2687 | } | 2734 | if (status) |
2688 | status = -ENOMEM; | 2735 | goto out_free; |
2689 | fl = locks_alloc_lock(); | ||
2690 | if (!fl) | ||
2691 | goto out; | ||
2692 | locks_init_lock(fl); | ||
2693 | fl->fl_lmops = &nfsd_lease_mng_ops; | ||
2694 | fl->fl_flags = FL_LEASE; | ||
2695 | fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; | ||
2696 | fl->fl_end = OFFSET_MAX; | ||
2697 | fl->fl_owner = (fl_owner_t)dp; | ||
2698 | fl->fl_file = find_readable_file(stp->st_file); | ||
2699 | BUG_ON(!fl->fl_file); | ||
2700 | fl->fl_pid = current->tgid; | ||
2701 | dp->dl_flock = fl; | ||
2702 | |||
2703 | /* vfs_setlease checks to see if delegation should be handed out. | ||
2704 | * the lock_manager callback fl_change is used | ||
2705 | */ | ||
2706 | if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) { | ||
2707 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); | ||
2708 | dp->dl_flock = NULL; | ||
2709 | locks_free_lock(fl); | ||
2710 | unhash_delegation(dp); | ||
2711 | flag = NFS4_OPEN_DELEGATE_NONE; | ||
2712 | goto out; | ||
2713 | } | ||
2714 | 2736 | ||
2715 | memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid)); | 2737 | memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid)); |
2716 | 2738 | ||
@@ -2722,6 +2744,12 @@ out: | |||
2722 | && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) | 2744 | && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) |
2723 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | 2745 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); |
2724 | open->op_delegate_type = flag; | 2746 | open->op_delegate_type = flag; |
2747 | return; | ||
2748 | out_free: | ||
2749 | nfs4_put_delegation(dp); | ||
2750 | out_no_deleg: | ||
2751 | flag = NFS4_OPEN_DELEGATE_NONE; | ||
2752 | goto out; | ||
2725 | } | 2753 | } |
2726 | 2754 | ||
2727 | /* | 2755 | /* |
@@ -2916,8 +2944,6 @@ nfs4_laundromat(void) | |||
2916 | test_val = u; | 2944 | test_val = u; |
2917 | break; | 2945 | break; |
2918 | } | 2946 | } |
2919 | dprintk("NFSD: purging unused delegation dp %p, fp %p\n", | ||
2920 | dp, dp->dl_flock); | ||
2921 | list_move(&dp->dl_recall_lru, &reaplist); | 2947 | list_move(&dp->dl_recall_lru, &reaplist); |
2922 | } | 2948 | } |
2923 | spin_unlock(&recall_lock); | 2949 | spin_unlock(&recall_lock); |
@@ -3128,7 +3154,7 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
3128 | goto out; | 3154 | goto out; |
3129 | renew_client(dp->dl_client); | 3155 | renew_client(dp->dl_client); |
3130 | if (filpp) { | 3156 | if (filpp) { |
3131 | *filpp = find_readable_file(dp->dl_file); | 3157 | *filpp = dp->dl_file->fi_deleg_file; |
3132 | BUG_ON(!*filpp); | 3158 | BUG_ON(!*filpp); |
3133 | } | 3159 | } |
3134 | } else { /* open or lock stateid */ | 3160 | } else { /* open or lock stateid */ |