aboutsummaryrefslogtreecommitdiffstats
path: root/fs/locks.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/locks.c')
-rw-r--r--fs/locks.c90
1 files changed, 52 insertions, 38 deletions
diff --git a/fs/locks.c b/fs/locks.c
index 50ec15927aab..0e62dd35d088 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -186,7 +186,7 @@ void locks_release_private(struct file_lock *fl)
186EXPORT_SYMBOL_GPL(locks_release_private); 186EXPORT_SYMBOL_GPL(locks_release_private);
187 187
188/* Free a lock which is not in use. */ 188/* Free a lock which is not in use. */
189static void locks_free_lock(struct file_lock *fl) 189void locks_free_lock(struct file_lock *fl)
190{ 190{
191 BUG_ON(waitqueue_active(&fl->fl_wait)); 191 BUG_ON(waitqueue_active(&fl->fl_wait));
192 BUG_ON(!list_empty(&fl->fl_block)); 192 BUG_ON(!list_empty(&fl->fl_block));
@@ -195,6 +195,7 @@ static void locks_free_lock(struct file_lock *fl)
195 locks_release_private(fl); 195 locks_release_private(fl);
196 kmem_cache_free(filelock_cache, fl); 196 kmem_cache_free(filelock_cache, fl);
197} 197}
198EXPORT_SYMBOL(locks_free_lock);
198 199
199void locks_init_lock(struct file_lock *fl) 200void locks_init_lock(struct file_lock *fl)
200{ 201{
@@ -234,11 +235,8 @@ static void locks_copy_private(struct file_lock *new, struct file_lock *fl)
234 fl->fl_ops->fl_copy_lock(new, fl); 235 fl->fl_ops->fl_copy_lock(new, fl);
235 new->fl_ops = fl->fl_ops; 236 new->fl_ops = fl->fl_ops;
236 } 237 }
237 if (fl->fl_lmops) { 238 if (fl->fl_lmops)
238 if (fl->fl_lmops->fl_copy_lock)
239 fl->fl_lmops->fl_copy_lock(new, fl);
240 new->fl_lmops = fl->fl_lmops; 239 new->fl_lmops = fl->fl_lmops;
241 }
242} 240}
243 241
244/* 242/*
@@ -1371,20 +1369,22 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
1371 struct inode *inode = dentry->d_inode; 1369 struct inode *inode = dentry->d_inode;
1372 int error, rdlease_count = 0, wrlease_count = 0; 1370 int error, rdlease_count = 0, wrlease_count = 0;
1373 1371
1372 lease = *flp;
1373
1374 error = -EACCES;
1374 if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE)) 1375 if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE))
1375 return -EACCES; 1376 goto out;
1377 error = -EINVAL;
1376 if (!S_ISREG(inode->i_mode)) 1378 if (!S_ISREG(inode->i_mode))
1377 return -EINVAL; 1379 goto out;
1378 error = security_file_lock(filp, arg); 1380 error = security_file_lock(filp, arg);
1379 if (error) 1381 if (error)
1380 return error; 1382 goto out;
1381 1383
1382 time_out_leases(inode); 1384 time_out_leases(inode);
1383 1385
1384 BUG_ON(!(*flp)->fl_lmops->fl_break); 1386 BUG_ON(!(*flp)->fl_lmops->fl_break);
1385 1387
1386 lease = *flp;
1387
1388 if (arg != F_UNLCK) { 1388 if (arg != F_UNLCK) {
1389 error = -EAGAIN; 1389 error = -EAGAIN;
1390 if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) 1390 if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
@@ -1425,8 +1425,9 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
1425 goto out; 1425 goto out;
1426 1426
1427 if (my_before != NULL) { 1427 if (my_before != NULL) {
1428 *flp = *my_before;
1429 error = lease->fl_lmops->fl_change(my_before, arg); 1428 error = lease->fl_lmops->fl_change(my_before, arg);
1429 if (!error)
1430 *flp = *my_before;
1430 goto out; 1431 goto out;
1431 } 1432 }
1432 1433
@@ -1441,7 +1442,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
1441 return 0; 1442 return 0;
1442 1443
1443out: 1444out:
1444 locks_free_lock(lease);
1445 return error; 1445 return error;
1446} 1446}
1447EXPORT_SYMBOL(generic_setlease); 1447EXPORT_SYMBOL(generic_setlease);
@@ -1493,21 +1493,19 @@ int vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
1493} 1493}
1494EXPORT_SYMBOL_GPL(vfs_setlease); 1494EXPORT_SYMBOL_GPL(vfs_setlease);
1495 1495
1496/** 1496static int do_fcntl_delete_lease(struct file *filp)
1497 * fcntl_setlease - sets a lease on an open file
1498 * @fd: open file descriptor
1499 * @filp: file pointer
1500 * @arg: type of lease to obtain
1501 *
1502 * Call this fcntl to establish a lease on the file.
1503 * Note that you also need to call %F_SETSIG to
1504 * receive a signal when the lease is broken.
1505 */
1506int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
1507{ 1497{
1508 struct file_lock *fl; 1498 struct file_lock fl, *flp = &fl;
1499
1500 lease_init(filp, F_UNLCK, flp);
1501
1502 return vfs_setlease(filp, F_UNLCK, &flp);
1503}
1504
1505static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
1506{
1507 struct file_lock *fl, *ret;
1509 struct fasync_struct *new; 1508 struct fasync_struct *new;
1510 struct inode *inode = filp->f_path.dentry->d_inode;
1511 int error; 1509 int error;
1512 1510
1513 fl = lease_alloc(filp, arg); 1511 fl = lease_alloc(filp, arg);
@@ -1519,10 +1517,16 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
1519 locks_free_lock(fl); 1517 locks_free_lock(fl);
1520 return -ENOMEM; 1518 return -ENOMEM;
1521 } 1519 }
1520 ret = fl;
1522 lock_flocks(); 1521 lock_flocks();
1523 error = __vfs_setlease(filp, arg, &fl); 1522 error = __vfs_setlease(filp, arg, &ret);
1524 if (error || arg == F_UNLCK) 1523 if (error) {
1525 goto out_unlock; 1524 unlock_flocks();
1525 locks_free_lock(fl);
1526 goto out_free_fasync;
1527 }
1528 if (ret != fl)
1529 locks_free_lock(fl);
1526 1530
1527 /* 1531 /*
1528 * fasync_insert_entry() returns the old entry if any. 1532 * fasync_insert_entry() returns the old entry if any.
@@ -1530,26 +1534,36 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
1530 * inserted it into the fasync list. Clear new so that 1534 * inserted it into the fasync list. Clear new so that
1531 * we don't release it here. 1535 * we don't release it here.
1532 */ 1536 */
1533 if (!fasync_insert_entry(fd, filp, &fl->fl_fasync, new)) 1537 if (!fasync_insert_entry(fd, filp, &ret->fl_fasync, new))
1534 new = NULL; 1538 new = NULL;
1535 1539
1536 if (error < 0) {
1537 /* remove lease just inserted by setlease */
1538 fl->fl_type = F_UNLCK | F_INPROGRESS;
1539 fl->fl_break_time = jiffies - 10;
1540 time_out_leases(inode);
1541 goto out_unlock;
1542 }
1543
1544 error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); 1540 error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
1545out_unlock:
1546 unlock_flocks(); 1541 unlock_flocks();
1542
1543out_free_fasync:
1547 if (new) 1544 if (new)
1548 fasync_free(new); 1545 fasync_free(new);
1549 return error; 1546 return error;
1550} 1547}
1551 1548
1552/** 1549/**
1550 * fcntl_setlease - sets a lease on an open file
1551 * @fd: open file descriptor
1552 * @filp: file pointer
1553 * @arg: type of lease to obtain
1554 *
1555 * Call this fcntl to establish a lease on the file.
1556 * Note that you also need to call %F_SETSIG to
1557 * receive a signal when the lease is broken.
1558 */
1559int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
1560{
1561 if (arg == F_UNLCK)
1562 return do_fcntl_delete_lease(filp);
1563 return do_fcntl_add_lease(fd, filp, arg);
1564}
1565
1566/**
1553 * flock_lock_file_wait - Apply a FLOCK-style lock to a file 1567 * flock_lock_file_wait - Apply a FLOCK-style lock to a file
1554 * @filp: The file to apply the lock to 1568 * @filp: The file to apply the lock to
1555 * @fl: The lock to be applied 1569 * @fl: The lock to be applied