diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-27 21:13:34 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-27 21:13:34 -0400 |
commit | 7420a8c0de8d99b201aeeab6fed16ca95ebf55a5 (patch) | |
tree | 0787800f490f98ffd41b958e52ab15732335744e /fs/locks.c | |
parent | 12ba8d1e9262ce81a695795410bd9ee5c9407ba1 (diff) | |
parent | 72f98e72551fad573c6cace8e8551ef094f482dd (diff) |
Merge branch 'flock' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/bkl
* 'flock' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd/bkl:
locks: turn lock_flocks into a spinlock
fasync: re-organize fasync entry insertion to allow it under a spinlock
locks/nfsd: allocate file lock outside of spinlock
lockd: fix nlmsvc_notify_blocked locking
lockd: push lock_flocks down
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 57 |
1 files changed, 31 insertions, 26 deletions
diff --git a/fs/locks.c b/fs/locks.c index 4de3a2666810..50ec15927aab 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -142,6 +142,7 @@ int lease_break_time = 45; | |||
142 | 142 | ||
143 | static LIST_HEAD(file_lock_list); | 143 | static LIST_HEAD(file_lock_list); |
144 | static LIST_HEAD(blocked_list); | 144 | static LIST_HEAD(blocked_list); |
145 | static DEFINE_SPINLOCK(file_lock_lock); | ||
145 | 146 | ||
146 | /* | 147 | /* |
147 | * Protects the two list heads above, plus the inode->i_flock list | 148 | * Protects the two list heads above, plus the inode->i_flock list |
@@ -149,23 +150,24 @@ static LIST_HEAD(blocked_list); | |||
149 | */ | 150 | */ |
150 | void lock_flocks(void) | 151 | void lock_flocks(void) |
151 | { | 152 | { |
152 | lock_kernel(); | 153 | spin_lock(&file_lock_lock); |
153 | } | 154 | } |
154 | EXPORT_SYMBOL_GPL(lock_flocks); | 155 | EXPORT_SYMBOL_GPL(lock_flocks); |
155 | 156 | ||
156 | void unlock_flocks(void) | 157 | void unlock_flocks(void) |
157 | { | 158 | { |
158 | unlock_kernel(); | 159 | spin_unlock(&file_lock_lock); |
159 | } | 160 | } |
160 | EXPORT_SYMBOL_GPL(unlock_flocks); | 161 | EXPORT_SYMBOL_GPL(unlock_flocks); |
161 | 162 | ||
162 | static struct kmem_cache *filelock_cache __read_mostly; | 163 | static struct kmem_cache *filelock_cache __read_mostly; |
163 | 164 | ||
164 | /* Allocate an empty lock structure. */ | 165 | /* Allocate an empty lock structure. */ |
165 | static struct file_lock *locks_alloc_lock(void) | 166 | struct file_lock *locks_alloc_lock(void) |
166 | { | 167 | { |
167 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); | 168 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); |
168 | } | 169 | } |
170 | EXPORT_SYMBOL_GPL(locks_alloc_lock); | ||
169 | 171 | ||
170 | void locks_release_private(struct file_lock *fl) | 172 | void locks_release_private(struct file_lock *fl) |
171 | { | 173 | { |
@@ -1365,7 +1367,6 @@ int fcntl_getlease(struct file *filp) | |||
1365 | int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | 1367 | int generic_setlease(struct file *filp, long arg, struct file_lock **flp) |
1366 | { | 1368 | { |
1367 | struct file_lock *fl, **before, **my_before = NULL, *lease; | 1369 | struct file_lock *fl, **before, **my_before = NULL, *lease; |
1368 | struct file_lock *new_fl = NULL; | ||
1369 | struct dentry *dentry = filp->f_path.dentry; | 1370 | struct dentry *dentry = filp->f_path.dentry; |
1370 | struct inode *inode = dentry->d_inode; | 1371 | struct inode *inode = dentry->d_inode; |
1371 | int error, rdlease_count = 0, wrlease_count = 0; | 1372 | int error, rdlease_count = 0, wrlease_count = 0; |
@@ -1385,11 +1386,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1385 | lease = *flp; | 1386 | lease = *flp; |
1386 | 1387 | ||
1387 | if (arg != F_UNLCK) { | 1388 | 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; | 1389 | error = -EAGAIN; |
1394 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) | 1390 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) |
1395 | goto out; | 1391 | goto out; |
@@ -1434,7 +1430,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1434 | goto out; | 1430 | goto out; |
1435 | } | 1431 | } |
1436 | 1432 | ||
1437 | error = 0; | ||
1438 | if (arg == F_UNLCK) | 1433 | if (arg == F_UNLCK) |
1439 | goto out; | 1434 | goto out; |
1440 | 1435 | ||
@@ -1442,15 +1437,11 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1442 | if (!leases_enable) | 1437 | if (!leases_enable) |
1443 | goto out; | 1438 | goto out; |
1444 | 1439 | ||
1445 | locks_copy_lock(new_fl, lease); | 1440 | locks_insert_lock(before, lease); |
1446 | locks_insert_lock(before, new_fl); | ||
1447 | |||
1448 | *flp = new_fl; | ||
1449 | return 0; | 1441 | return 0; |
1450 | 1442 | ||
1451 | out: | 1443 | out: |
1452 | if (new_fl != NULL) | 1444 | locks_free_lock(lease); |
1453 | locks_free_lock(new_fl); | ||
1454 | return error; | 1445 | return error; |
1455 | } | 1446 | } |
1456 | EXPORT_SYMBOL(generic_setlease); | 1447 | EXPORT_SYMBOL(generic_setlease); |
@@ -1514,26 +1505,38 @@ EXPORT_SYMBOL_GPL(vfs_setlease); | |||
1514 | */ | 1505 | */ |
1515 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | 1506 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) |
1516 | { | 1507 | { |
1517 | struct file_lock fl, *flp = &fl; | 1508 | struct file_lock *fl; |
1509 | struct fasync_struct *new; | ||
1518 | struct inode *inode = filp->f_path.dentry->d_inode; | 1510 | struct inode *inode = filp->f_path.dentry->d_inode; |
1519 | int error; | 1511 | int error; |
1520 | 1512 | ||
1521 | locks_init_lock(&fl); | 1513 | fl = lease_alloc(filp, arg); |
1522 | error = lease_init(filp, arg, &fl); | 1514 | if (IS_ERR(fl)) |
1523 | if (error) | 1515 | return PTR_ERR(fl); |
1524 | return error; | ||
1525 | 1516 | ||
1517 | new = fasync_alloc(); | ||
1518 | if (!new) { | ||
1519 | locks_free_lock(fl); | ||
1520 | return -ENOMEM; | ||
1521 | } | ||
1526 | lock_flocks(); | 1522 | lock_flocks(); |
1527 | 1523 | error = __vfs_setlease(filp, arg, &fl); | |
1528 | error = __vfs_setlease(filp, arg, &flp); | ||
1529 | if (error || arg == F_UNLCK) | 1524 | if (error || arg == F_UNLCK) |
1530 | goto out_unlock; | 1525 | goto out_unlock; |
1531 | 1526 | ||
1532 | error = fasync_helper(fd, filp, 1, &flp->fl_fasync); | 1527 | /* |
1528 | * fasync_insert_entry() returns the old entry if any. | ||
1529 | * If there was no old entry, then it used 'new' and | ||
1530 | * inserted it into the fasync list. Clear new so that | ||
1531 | * we don't release it here. | ||
1532 | */ | ||
1533 | if (!fasync_insert_entry(fd, filp, &fl->fl_fasync, new)) | ||
1534 | new = NULL; | ||
1535 | |||
1533 | if (error < 0) { | 1536 | if (error < 0) { |
1534 | /* remove lease just inserted by setlease */ | 1537 | /* remove lease just inserted by setlease */ |
1535 | flp->fl_type = F_UNLCK | F_INPROGRESS; | 1538 | fl->fl_type = F_UNLCK | F_INPROGRESS; |
1536 | flp->fl_break_time = jiffies - 10; | 1539 | fl->fl_break_time = jiffies - 10; |
1537 | time_out_leases(inode); | 1540 | time_out_leases(inode); |
1538 | goto out_unlock; | 1541 | goto out_unlock; |
1539 | } | 1542 | } |
@@ -1541,6 +1544,8 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | |||
1541 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); | 1544 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); |
1542 | out_unlock: | 1545 | out_unlock: |
1543 | unlock_flocks(); | 1546 | unlock_flocks(); |
1547 | if (new) | ||
1548 | fasync_free(new); | ||
1544 | return error; | 1549 | return error; |
1545 | } | 1550 | } |
1546 | 1551 | ||