Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'for-2.6.38' of git://linux-nfs.org/~bfields/linux

* 'for-2.6.38' of git://linux-nfs.org/~bfields/linux:
nfsd: break lease on unlink due to rename
nfsd4: acquire only one lease per file
nfsd4: modify fi_delegations under recall_lock
nfsd4: remove unused deleg dprintk's.
nfsd4: split lease setting into separate function
nfsd4: fix leak on allocation error
nfsd4: add helper function for lease setup
nfsd4: split up nfsd_break_deleg_cb
NFSD: memory corruption due to writing beyond the stat array
NFSD: use nfserr for status after decode_cb_op_status
nfsd: don't leak dentry count on mnt_want_write failure

+125 -93
+2 -4
fs/nfsd/nfs4callback.c
··· 484 484 out: 485 485 return status; 486 486 out_default: 487 - return nfs_cb_stat_to_errno(status); 487 + return nfs_cb_stat_to_errno(nfserr); 488 488 } 489 489 490 490 /* ··· 564 564 if (unlikely(status)) 565 565 goto out; 566 566 if (unlikely(nfserr != NFS4_OK)) 567 - goto out_default; 567 + status = nfs_cb_stat_to_errno(nfserr); 568 568 out: 569 569 return status; 570 - out_default: 571 - return nfs_cb_stat_to_errno(status); 572 570 } 573 571 574 572 /*
+106 -80
fs/nfsd/nfs4state.c
··· 230 230 dp->dl_client = clp; 231 231 get_nfs4_file(fp); 232 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 233 dp->dl_type = type; 237 234 dp->dl_stateid.si_boot = boot_time; 238 235 dp->dl_stateid.si_stateownerid = current_delegid++; ··· 238 241 fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle); 239 242 dp->dl_time = 0; 240 243 atomic_set(&dp->dl_count, 1); 241 - list_add(&dp->dl_perfile, &fp->fi_delegations); 242 - list_add(&dp->dl_perclnt, &clp->cl_delegations); 243 244 INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); 244 245 return dp; 245 246 } ··· 248 253 if (atomic_dec_and_test(&dp->dl_count)) { 249 254 dprintk("NFSD: freeing dp %p\n",dp); 250 255 put_nfs4_file(dp->dl_file); 251 - fput(dp->dl_vfs_file); 252 256 kmem_cache_free(deleg_slab, dp); 253 257 num_delegations--; 254 258 } 255 259 } 256 260 257 - /* Remove the associated file_lock first, then remove the delegation. 258 - * lease_modify() is called to remove the FS_LEASE file_lock from 259 - * the i_flock list, eventually calling nfsd's lock_manager 260 - * fl_release_callback. 261 - */ 262 - static void 263 - nfs4_close_delegation(struct nfs4_delegation *dp) 261 + static void nfs4_put_deleg_lease(struct nfs4_file *fp) 264 262 { 265 - dprintk("NFSD: close_delegation dp %p\n",dp); 266 - /* XXX: do we even need this check?: */ 267 - if (dp->dl_flock) 268 - vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock); 263 + if (atomic_dec_and_test(&fp->fi_delegees)) { 264 + vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease); 265 + fp->fi_lease = NULL; 266 + fp->fi_deleg_file = NULL; 267 + } 269 268 } 270 269 271 270 /* Called under the state lock. */ 272 271 static void 273 272 unhash_delegation(struct nfs4_delegation *dp) 274 273 { 275 - list_del_init(&dp->dl_perfile); 276 274 list_del_init(&dp->dl_perclnt); 277 275 spin_lock(&recall_lock); 276 + list_del_init(&dp->dl_perfile); 278 277 list_del_init(&dp->dl_recall_lru); 279 278 spin_unlock(&recall_lock); 280 - nfs4_close_delegation(dp); 279 + nfs4_put_deleg_lease(dp->dl_file); 281 280 nfs4_put_delegation(dp); 282 281 } 283 282 ··· 947 958 spin_lock(&recall_lock); 948 959 while (!list_empty(&clp->cl_delegations)) { 949 960 dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 950 - dprintk("NFSD: expire client. dp %p, fp %p\n", dp, 951 - dp->dl_flock); 952 961 list_del_init(&dp->dl_perclnt); 953 962 list_move(&dp->dl_recall_lru, &reaplist); 954 963 } ··· 2065 2078 fp->fi_inode = igrab(ino); 2066 2079 fp->fi_id = current_fileid++; 2067 2080 fp->fi_had_conflict = false; 2081 + fp->fi_lease = NULL; 2068 2082 memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 2069 2083 memset(fp->fi_access, 0, sizeof(fp->fi_access)); 2070 2084 spin_lock(&recall_lock); ··· 2317 2329 nfs4_file_put_access(fp, O_RDONLY); 2318 2330 } 2319 2331 2320 - /* 2321 - * Spawn a thread to perform a recall on the delegation represented 2322 - * by the lease (file_lock) 2323 - * 2324 - * Called from break_lease() with lock_flocks() held. 2325 - * Note: we assume break_lease will only call this *once* for any given 2326 - * lease. 2327 - */ 2328 - static 2329 - void nfsd_break_deleg_cb(struct file_lock *fl) 2332 + static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 2330 2333 { 2331 - struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; 2332 - 2333 - dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); 2334 - if (!dp) 2335 - return; 2336 - 2337 2334 /* We're assuming the state code never drops its reference 2338 2335 * without first removing the lease. Since we're in this lease 2339 2336 * callback (and since the lease code is serialized by the kernel ··· 2326 2353 * it's safe to take a reference: */ 2327 2354 atomic_inc(&dp->dl_count); 2328 2355 2329 - spin_lock(&recall_lock); 2330 2356 list_add_tail(&dp->dl_recall_lru, &del_recall_lru); 2331 - spin_unlock(&recall_lock); 2332 2357 2333 2358 /* only place dl_time is set. protected by lock_flocks*/ 2334 2359 dp->dl_time = get_seconds(); 2335 2360 2361 + nfsd4_cb_recall(dp); 2362 + } 2363 + 2364 + /* Called from break_lease() with lock_flocks() held. */ 2365 + static void nfsd_break_deleg_cb(struct file_lock *fl) 2366 + { 2367 + struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; 2368 + struct nfs4_delegation *dp; 2369 + 2370 + BUG_ON(!fp); 2371 + /* We assume break_lease is only called once per lease: */ 2372 + BUG_ON(fp->fi_had_conflict); 2336 2373 /* 2337 2374 * We don't want the locks code to timeout the lease for us; 2338 - * we'll remove it ourself if the delegation isn't returned 2339 - * in time. 2375 + * we'll remove it ourself if a delegation isn't returned 2376 + * in time: 2340 2377 */ 2341 2378 fl->fl_break_time = 0; 2342 2379 2343 - dp->dl_file->fi_had_conflict = true; 2344 - nfsd4_cb_recall(dp); 2380 + spin_lock(&recall_lock); 2381 + fp->fi_had_conflict = true; 2382 + list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) 2383 + nfsd_break_one_deleg(dp); 2384 + spin_unlock(&recall_lock); 2345 2385 } 2346 2386 2347 2387 static ··· 2445 2459 static struct nfs4_delegation * 2446 2460 find_delegation_file(struct nfs4_file *fp, stateid_t *stid) 2447 2461 { 2448 - struct nfs4_delegation *dp; 2462 + struct nfs4_delegation *dp = NULL; 2449 2463 2464 + spin_lock(&recall_lock); 2450 2465 list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) { 2451 2466 if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) 2452 - return dp; 2467 + break; 2453 2468 } 2454 - return NULL; 2469 + spin_unlock(&recall_lock); 2470 + return dp; 2455 2471 } 2456 2472 2457 2473 int share_access_to_flags(u32 share_access) ··· 2629 2641 return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 2630 2642 } 2631 2643 2644 + static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int flag) 2645 + { 2646 + struct file_lock *fl; 2647 + 2648 + fl = locks_alloc_lock(); 2649 + if (!fl) 2650 + return NULL; 2651 + locks_init_lock(fl); 2652 + fl->fl_lmops = &nfsd_lease_mng_ops; 2653 + fl->fl_flags = FL_LEASE; 2654 + fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 2655 + fl->fl_end = OFFSET_MAX; 2656 + fl->fl_owner = (fl_owner_t)(dp->dl_file); 2657 + fl->fl_pid = current->tgid; 2658 + return fl; 2659 + } 2660 + 2661 + static int nfs4_setlease(struct nfs4_delegation *dp, int flag) 2662 + { 2663 + struct nfs4_file *fp = dp->dl_file; 2664 + struct file_lock *fl; 2665 + int status; 2666 + 2667 + fl = nfs4_alloc_init_lease(dp, flag); 2668 + if (!fl) 2669 + return -ENOMEM; 2670 + fl->fl_file = find_readable_file(fp); 2671 + list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); 2672 + status = vfs_setlease(fl->fl_file, fl->fl_type, &fl); 2673 + if (status) { 2674 + list_del_init(&dp->dl_perclnt); 2675 + locks_free_lock(fl); 2676 + return -ENOMEM; 2677 + } 2678 + fp->fi_lease = fl; 2679 + fp->fi_deleg_file = fl->fl_file; 2680 + get_file(fp->fi_deleg_file); 2681 + atomic_set(&fp->fi_delegees, 1); 2682 + list_add(&dp->dl_perfile, &fp->fi_delegations); 2683 + return 0; 2684 + } 2685 + 2686 + static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) 2687 + { 2688 + struct nfs4_file *fp = dp->dl_file; 2689 + 2690 + if (!fp->fi_lease) 2691 + return nfs4_setlease(dp, flag); 2692 + spin_lock(&recall_lock); 2693 + if (fp->fi_had_conflict) { 2694 + spin_unlock(&recall_lock); 2695 + return -EAGAIN; 2696 + } 2697 + atomic_inc(&fp->fi_delegees); 2698 + list_add(&dp->dl_perfile, &fp->fi_delegations); 2699 + spin_unlock(&recall_lock); 2700 + list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); 2701 + return 0; 2702 + } 2703 + 2632 2704 /* 2633 2705 * Attempt to hand out a delegation. 2634 2706 */ ··· 2698 2650 struct nfs4_delegation *dp; 2699 2651 struct nfs4_stateowner *sop = stp->st_stateowner; 2700 2652 int cb_up; 2701 - struct file_lock *fl; 2702 2653 int status, flag = 0; 2703 2654 2704 2655 cb_up = nfsd4_cb_channel_good(sop->so_client); ··· 2728 2681 } 2729 2682 2730 2683 dp = alloc_init_deleg(sop->so_client, stp, fh, flag); 2731 - if (dp == NULL) { 2732 - flag = NFS4_OPEN_DELEGATE_NONE; 2733 - goto out; 2734 - } 2735 - status = -ENOMEM; 2736 - fl = locks_alloc_lock(); 2737 - if (!fl) 2738 - goto out; 2739 - locks_init_lock(fl); 2740 - fl->fl_lmops = &nfsd_lease_mng_ops; 2741 - fl->fl_flags = FL_LEASE; 2742 - fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 2743 - fl->fl_end = OFFSET_MAX; 2744 - fl->fl_owner = (fl_owner_t)dp; 2745 - fl->fl_file = find_readable_file(stp->st_file); 2746 - BUG_ON(!fl->fl_file); 2747 - fl->fl_pid = current->tgid; 2748 - dp->dl_flock = fl; 2749 - 2750 - /* vfs_setlease checks to see if delegation should be handed out. 2751 - * the lock_manager callback fl_change is used 2752 - */ 2753 - if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) { 2754 - dprintk("NFSD: setlease failed [%d], no delegation\n", status); 2755 - dp->dl_flock = NULL; 2756 - locks_free_lock(fl); 2757 - unhash_delegation(dp); 2758 - flag = NFS4_OPEN_DELEGATE_NONE; 2759 - goto out; 2760 - } 2684 + if (dp == NULL) 2685 + goto out_no_deleg; 2686 + status = nfs4_set_delegation(dp, flag); 2687 + if (status) 2688 + goto out_free; 2761 2689 2762 2690 memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid)); 2763 2691 ··· 2744 2722 && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) 2745 2723 dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 2746 2724 open->op_delegate_type = flag; 2725 + return; 2726 + out_free: 2727 + nfs4_put_delegation(dp); 2728 + out_no_deleg: 2729 + flag = NFS4_OPEN_DELEGATE_NONE; 2730 + goto out; 2747 2731 } 2748 2732 2749 2733 /* ··· 2944 2916 test_val = u; 2945 2917 break; 2946 2918 } 2947 - dprintk("NFSD: purging unused delegation dp %p, fp %p\n", 2948 - dp, dp->dl_flock); 2949 2919 list_move(&dp->dl_recall_lru, &reaplist); 2950 2920 } 2951 2921 spin_unlock(&recall_lock); ··· 3154 3128 goto out; 3155 3129 renew_client(dp->dl_client); 3156 3130 if (filpp) { 3157 - *filpp = find_readable_file(dp->dl_file); 3131 + *filpp = dp->dl_file->fi_deleg_file; 3158 3132 BUG_ON(!*filpp); 3159 3133 } 3160 3134 } else { /* open or lock stateid */
+3 -2
fs/nfsd/state.h
··· 83 83 atomic_t dl_count; /* ref count */ 84 84 struct nfs4_client *dl_client; 85 85 struct nfs4_file *dl_file; 86 - struct file *dl_vfs_file; 87 - struct file_lock *dl_flock; 88 86 u32 dl_type; 89 87 time_t dl_time; 90 88 /* For recall: */ ··· 377 379 */ 378 380 atomic_t fi_readers; 379 381 atomic_t fi_writers; 382 + struct file *fi_deleg_file; 383 + struct file_lock *fi_lease; 384 + atomic_t fi_delegees; 380 385 struct inode *fi_inode; 381 386 u32 fi_id; /* used with stateowner->so_id 382 387 * for stateid_hashtbl hash */
+14 -7
fs/nfsd/vfs.c
··· 808 808 if (ra->p_count == 0) 809 809 frap = rap; 810 810 } 811 - depth = nfsdstats.ra_size*11/10; 811 + depth = nfsdstats.ra_size; 812 812 if (!frap) { 813 813 spin_unlock(&rab->pb_lock); 814 814 return NULL; ··· 1744 1744 host_err = nfsd_break_lease(odentry->d_inode); 1745 1745 if (host_err) 1746 1746 goto out_drop_write; 1747 + if (ndentry->d_inode) { 1748 + host_err = nfsd_break_lease(ndentry->d_inode); 1749 + if (host_err) 1750 + goto out_drop_write; 1751 + } 1752 + if (host_err) 1753 + goto out_drop_write; 1747 1754 host_err = vfs_rename(fdir, odentry, tdir, ndentry); 1748 1755 if (!host_err) { 1749 1756 host_err = commit_metadata(tfhp); ··· 1819 1812 1820 1813 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); 1821 1814 if (host_err) 1822 - goto out_nfserr; 1815 + goto out_put; 1823 1816 1824 1817 host_err = nfsd_break_lease(rdentry->d_inode); 1825 1818 if (host_err) 1826 - goto out_put; 1819 + goto out_drop_write; 1827 1820 if (type != S_IFDIR) 1828 1821 host_err = vfs_unlink(dirp, rdentry); 1829 1822 else 1830 1823 host_err = vfs_rmdir(dirp, rdentry); 1824 + if (!host_err) 1825 + host_err = commit_metadata(fhp); 1826 + out_drop_write: 1827 + mnt_drop_write(fhp->fh_export->ex_path.mnt); 1831 1828 out_put: 1832 1829 dput(rdentry); 1833 1830 1834 - if (!host_err) 1835 - host_err = commit_metadata(fhp); 1836 - 1837 - mnt_drop_write(fhp->fh_export->ex_path.mnt); 1838 1831 out_nfserr: 1839 1832 err = nfserrno(host_err); 1840 1833 out: