diff options
author | Arnd Bergmann <arnd@arndb.de> | 2010-10-27 09:46:08 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2010-10-27 15:41:50 -0400 |
commit | c5b1f0d92c36851aca09ac6c7c0c4f9690ac14f3 (patch) | |
tree | c8aa4ad65aea3b97292135a4c23d512e6071dc8d | |
parent | a282a1fa6b23bd21ba0b86e53ed2a316b001836f (diff) |
locks/nfsd: allocate file lock outside of spinlock
As suggested by Christoph Hellwig, this moves allocation
of new file locks out of generic_setlease into the
callers, nfs4_open_delegation and fcntl_setlease in order
to allow GFP_KERNEL allocations when lock_flocks has
become a spinlock.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r-- | fs/locks.c | 36 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 26 | ||||
-rw-r--r-- | include/linux/fs.h | 1 |
3 files changed, 28 insertions, 35 deletions
diff --git a/fs/locks.c b/fs/locks.c index 8b2b6ad56a09..0391d2ff5a4e 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -162,10 +162,11 @@ EXPORT_SYMBOL_GPL(unlock_flocks); | |||
162 | static struct kmem_cache *filelock_cache __read_mostly; | 162 | static struct kmem_cache *filelock_cache __read_mostly; |
163 | 163 | ||
164 | /* Allocate an empty lock structure. */ | 164 | /* Allocate an empty lock structure. */ |
165 | static struct file_lock *locks_alloc_lock(void) | 165 | struct file_lock *locks_alloc_lock(void) |
166 | { | 166 | { |
167 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); | 167 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); |
168 | } | 168 | } |
169 | EXPORT_SYMBOL_GPL(locks_alloc_lock); | ||
169 | 170 | ||
170 | void locks_release_private(struct file_lock *fl) | 171 | void locks_release_private(struct file_lock *fl) |
171 | { | 172 | { |
@@ -1365,7 +1366,6 @@ int fcntl_getlease(struct file *filp) | |||
1365 | int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | 1366 | int generic_setlease(struct file *filp, long arg, struct file_lock **flp) |
1366 | { | 1367 | { |
1367 | struct file_lock *fl, **before, **my_before = NULL, *lease; | 1368 | struct file_lock *fl, **before, **my_before = NULL, *lease; |
1368 | struct file_lock *new_fl = NULL; | ||
1369 | struct dentry *dentry = filp->f_path.dentry; | 1369 | struct dentry *dentry = filp->f_path.dentry; |
1370 | struct inode *inode = dentry->d_inode; | 1370 | struct inode *inode = dentry->d_inode; |
1371 | int error, rdlease_count = 0, wrlease_count = 0; | 1371 | int error, rdlease_count = 0, wrlease_count = 0; |
@@ -1385,11 +1385,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1385 | lease = *flp; | 1385 | lease = *flp; |
1386 | 1386 | ||
1387 | if (arg != F_UNLCK) { | 1387 | if (arg != F_UNLCK) { |
1388 | error = -ENOMEM; | ||
1389 | new_fl = locks_alloc_lock(); | ||
1390 | if (new_fl == NULL) | ||
1391 | goto out; | ||
1392 | |||
1393 | error = -EAGAIN; | 1388 | error = -EAGAIN; |
1394 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) | 1389 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) |
1395 | goto out; | 1390 | goto out; |
@@ -1434,7 +1429,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1434 | goto out; | 1429 | goto out; |
1435 | } | 1430 | } |
1436 | 1431 | ||
1437 | error = 0; | ||
1438 | if (arg == F_UNLCK) | 1432 | if (arg == F_UNLCK) |
1439 | goto out; | 1433 | goto out; |
1440 | 1434 | ||
@@ -1442,15 +1436,11 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1442 | if (!leases_enable) | 1436 | if (!leases_enable) |
1443 | goto out; | 1437 | goto out; |
1444 | 1438 | ||
1445 | locks_copy_lock(new_fl, lease); | 1439 | locks_insert_lock(before, lease); |
1446 | locks_insert_lock(before, new_fl); | ||
1447 | |||
1448 | *flp = new_fl; | ||
1449 | return 0; | 1440 | return 0; |
1450 | 1441 | ||
1451 | out: | 1442 | out: |
1452 | if (new_fl != NULL) | 1443 | locks_free_lock(lease); |
1453 | locks_free_lock(new_fl); | ||
1454 | return error; | 1444 | return error; |
1455 | } | 1445 | } |
1456 | EXPORT_SYMBOL(generic_setlease); | 1446 | EXPORT_SYMBOL(generic_setlease); |
@@ -1514,26 +1504,24 @@ EXPORT_SYMBOL_GPL(vfs_setlease); | |||
1514 | */ | 1504 | */ |
1515 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | 1505 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) |
1516 | { | 1506 | { |
1517 | struct file_lock fl, *flp = &fl; | 1507 | struct file_lock *fl; |
1518 | struct inode *inode = filp->f_path.dentry->d_inode; | 1508 | struct inode *inode = filp->f_path.dentry->d_inode; |
1519 | int error; | 1509 | int error; |
1520 | 1510 | ||
1521 | locks_init_lock(&fl); | 1511 | fl = lease_alloc(filp, arg); |
1522 | error = lease_init(filp, arg, &fl); | 1512 | if (IS_ERR(fl)) |
1523 | if (error) | 1513 | return PTR_ERR(fl); |
1524 | return error; | ||
1525 | 1514 | ||
1526 | lock_flocks(); | 1515 | lock_flocks(); |
1527 | 1516 | error = __vfs_setlease(filp, arg, &fl); | |
1528 | error = __vfs_setlease(filp, arg, &flp); | ||
1529 | if (error || arg == F_UNLCK) | 1517 | if (error || arg == F_UNLCK) |
1530 | goto out_unlock; | 1518 | goto out_unlock; |
1531 | 1519 | ||
1532 | error = fasync_helper(fd, filp, 1, &flp->fl_fasync); | 1520 | error = fasync_helper(fd, filp, 1, &fl->fl_fasync); |
1533 | if (error < 0) { | 1521 | if (error < 0) { |
1534 | /* remove lease just inserted by setlease */ | 1522 | /* remove lease just inserted by setlease */ |
1535 | flp->fl_type = F_UNLCK | F_INPROGRESS; | 1523 | fl->fl_type = F_UNLCK | F_INPROGRESS; |
1536 | flp->fl_break_time = jiffies - 10; | 1524 | fl->fl_break_time = jiffies - 10; |
1537 | time_out_leases(inode); | 1525 | time_out_leases(inode); |
1538 | goto out_unlock; | 1526 | goto out_unlock; |
1539 | } | 1527 | } |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 9019e8ec9dc8..56347e0ac88d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -2614,7 +2614,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2614 | struct nfs4_delegation *dp; | 2614 | struct nfs4_delegation *dp; |
2615 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2615 | struct nfs4_stateowner *sop = stp->st_stateowner; |
2616 | int cb_up = atomic_read(&sop->so_client->cl_cb_set); | 2616 | int cb_up = atomic_read(&sop->so_client->cl_cb_set); |
2617 | struct file_lock fl, *flp = &fl; | 2617 | struct file_lock *fl; |
2618 | int status, flag = 0; | 2618 | int status, flag = 0; |
2619 | 2619 | ||
2620 | flag = NFS4_OPEN_DELEGATE_NONE; | 2620 | flag = NFS4_OPEN_DELEGATE_NONE; |
@@ -2648,20 +2648,24 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2648 | flag = NFS4_OPEN_DELEGATE_NONE; | 2648 | flag = NFS4_OPEN_DELEGATE_NONE; |
2649 | goto out; | 2649 | goto out; |
2650 | } | 2650 | } |
2651 | locks_init_lock(&fl); | 2651 | status = -ENOMEM; |
2652 | fl.fl_lmops = &nfsd_lease_mng_ops; | 2652 | fl = locks_alloc_lock(); |
2653 | fl.fl_flags = FL_LEASE; | 2653 | if (!fl) |
2654 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; | 2654 | goto out; |
2655 | fl.fl_end = OFFSET_MAX; | 2655 | locks_init_lock(fl); |
2656 | fl.fl_owner = (fl_owner_t)dp; | 2656 | fl->fl_lmops = &nfsd_lease_mng_ops; |
2657 | fl.fl_file = find_readable_file(stp->st_file); | 2657 | fl->fl_flags = FL_LEASE; |
2658 | BUG_ON(!fl.fl_file); | 2658 | fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; |
2659 | fl.fl_pid = current->tgid; | 2659 | fl->fl_end = OFFSET_MAX; |
2660 | fl->fl_owner = (fl_owner_t)dp; | ||
2661 | fl->fl_file = find_readable_file(stp->st_file); | ||
2662 | BUG_ON(!fl->fl_file); | ||
2663 | fl->fl_pid = current->tgid; | ||
2660 | 2664 | ||
2661 | /* vfs_setlease checks to see if delegation should be handed out. | 2665 | /* vfs_setlease checks to see if delegation should be handed out. |
2662 | * the lock_manager callbacks fl_mylease and fl_change are used | 2666 | * the lock_manager callbacks fl_mylease and fl_change are used |
2663 | */ | 2667 | */ |
2664 | if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) { | 2668 | if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) { |
2665 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); | 2669 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); |
2666 | unhash_delegation(dp); | 2670 | unhash_delegation(dp); |
2667 | flag = NFS4_OPEN_DELEGATE_NONE; | 2671 | flag = NFS4_OPEN_DELEGATE_NONE; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index bb20373d0b46..8d7de08ab546 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1113,6 +1113,7 @@ extern int fcntl_getlease(struct file *filp); | |||
1113 | 1113 | ||
1114 | /* fs/locks.c */ | 1114 | /* fs/locks.c */ |
1115 | extern void locks_init_lock(struct file_lock *); | 1115 | extern void locks_init_lock(struct file_lock *); |
1116 | extern struct file_lock * locks_alloc_lock(void); | ||
1116 | extern void locks_copy_lock(struct file_lock *, struct file_lock *); | 1117 | extern void locks_copy_lock(struct file_lock *, struct file_lock *); |
1117 | extern void __locks_copy_lock(struct file_lock *, const struct file_lock *); | 1118 | extern void __locks_copy_lock(struct file_lock *, const struct file_lock *); |
1118 | extern void locks_remove_posix(struct file *, fl_owner_t); | 1119 | extern void locks_remove_posix(struct file *, fl_owner_t); |