diff options
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 70 |
1 files changed, 53 insertions, 17 deletions
diff --git a/fs/locks.c b/fs/locks.c index b27a3005d78d..92a0f0a52b06 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -134,7 +134,7 @@ | |||
134 | 134 | ||
135 | #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) | 135 | #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) |
136 | #define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK) | 136 | #define IS_FLOCK(fl) (fl->fl_flags & FL_FLOCK) |
137 | #define IS_LEASE(fl) (fl->fl_flags & FL_LEASE) | 137 | #define IS_LEASE(fl) (fl->fl_flags & (FL_LEASE|FL_DELEG)) |
138 | 138 | ||
139 | static bool lease_breaking(struct file_lock *fl) | 139 | static bool lease_breaking(struct file_lock *fl) |
140 | { | 140 | { |
@@ -1292,28 +1292,40 @@ static void time_out_leases(struct inode *inode) | |||
1292 | } | 1292 | } |
1293 | } | 1293 | } |
1294 | 1294 | ||
1295 | static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker) | ||
1296 | { | ||
1297 | if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE)) | ||
1298 | return false; | ||
1299 | return locks_conflict(breaker, lease); | ||
1300 | } | ||
1301 | |||
1295 | /** | 1302 | /** |
1296 | * __break_lease - revoke all outstanding leases on file | 1303 | * __break_lease - revoke all outstanding leases on file |
1297 | * @inode: the inode of the file to return | 1304 | * @inode: the inode of the file to return |
1298 | * @mode: the open mode (read or write) | 1305 | * @mode: O_RDONLY: break only write leases; O_WRONLY or O_RDWR: |
1306 | * break all leases | ||
1307 | * @type: FL_LEASE: break leases and delegations; FL_DELEG: break | ||
1308 | * only delegations | ||
1299 | * | 1309 | * |
1300 | * break_lease (inlined for speed) has checked there already is at least | 1310 | * break_lease (inlined for speed) has checked there already is at least |
1301 | * some kind of lock (maybe a lease) on this file. Leases are broken on | 1311 | * some kind of lock (maybe a lease) on this file. Leases are broken on |
1302 | * a call to open() or truncate(). This function can sleep unless you | 1312 | * a call to open() or truncate(). This function can sleep unless you |
1303 | * specified %O_NONBLOCK to your open(). | 1313 | * specified %O_NONBLOCK to your open(). |
1304 | */ | 1314 | */ |
1305 | int __break_lease(struct inode *inode, unsigned int mode) | 1315 | int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) |
1306 | { | 1316 | { |
1307 | int error = 0; | 1317 | int error = 0; |
1308 | struct file_lock *new_fl, *flock; | 1318 | struct file_lock *new_fl, *flock; |
1309 | struct file_lock *fl; | 1319 | struct file_lock *fl; |
1310 | unsigned long break_time; | 1320 | unsigned long break_time; |
1311 | int i_have_this_lease = 0; | 1321 | int i_have_this_lease = 0; |
1322 | bool lease_conflict = false; | ||
1312 | int want_write = (mode & O_ACCMODE) != O_RDONLY; | 1323 | int want_write = (mode & O_ACCMODE) != O_RDONLY; |
1313 | 1324 | ||
1314 | new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK); | 1325 | new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK); |
1315 | if (IS_ERR(new_fl)) | 1326 | if (IS_ERR(new_fl)) |
1316 | return PTR_ERR(new_fl); | 1327 | return PTR_ERR(new_fl); |
1328 | new_fl->fl_flags = type; | ||
1317 | 1329 | ||
1318 | spin_lock(&inode->i_lock); | 1330 | spin_lock(&inode->i_lock); |
1319 | 1331 | ||
@@ -1323,13 +1335,16 @@ int __break_lease(struct inode *inode, unsigned int mode) | |||
1323 | if ((flock == NULL) || !IS_LEASE(flock)) | 1335 | if ((flock == NULL) || !IS_LEASE(flock)) |
1324 | goto out; | 1336 | goto out; |
1325 | 1337 | ||
1326 | if (!locks_conflict(flock, new_fl)) | 1338 | for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) { |
1339 | if (leases_conflict(fl, new_fl)) { | ||
1340 | lease_conflict = true; | ||
1341 | if (fl->fl_owner == current->files) | ||
1342 | i_have_this_lease = 1; | ||
1343 | } | ||
1344 | } | ||
1345 | if (!lease_conflict) | ||
1327 | goto out; | 1346 | goto out; |
1328 | 1347 | ||
1329 | for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) | ||
1330 | if (fl->fl_owner == current->files) | ||
1331 | i_have_this_lease = 1; | ||
1332 | |||
1333 | break_time = 0; | 1348 | break_time = 0; |
1334 | if (lease_break_time > 0) { | 1349 | if (lease_break_time > 0) { |
1335 | break_time = jiffies + lease_break_time * HZ; | 1350 | break_time = jiffies + lease_break_time * HZ; |
@@ -1338,6 +1353,8 @@ int __break_lease(struct inode *inode, unsigned int mode) | |||
1338 | } | 1353 | } |
1339 | 1354 | ||
1340 | for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) { | 1355 | for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) { |
1356 | if (!leases_conflict(fl, new_fl)) | ||
1357 | continue; | ||
1341 | if (want_write) { | 1358 | if (want_write) { |
1342 | if (fl->fl_flags & FL_UNLOCK_PENDING) | 1359 | if (fl->fl_flags & FL_UNLOCK_PENDING) |
1343 | continue; | 1360 | continue; |
@@ -1379,7 +1396,7 @@ restart: | |||
1379 | */ | 1396 | */ |
1380 | for (flock = inode->i_flock; flock && IS_LEASE(flock); | 1397 | for (flock = inode->i_flock; flock && IS_LEASE(flock); |
1381 | flock = flock->fl_next) { | 1398 | flock = flock->fl_next) { |
1382 | if (locks_conflict(new_fl, flock)) | 1399 | if (leases_conflict(new_fl, flock)) |
1383 | goto restart; | 1400 | goto restart; |
1384 | } | 1401 | } |
1385 | error = 0; | 1402 | error = 0; |
@@ -1460,9 +1477,27 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp | |||
1460 | struct file_lock *fl, **before, **my_before = NULL, *lease; | 1477 | struct file_lock *fl, **before, **my_before = NULL, *lease; |
1461 | struct dentry *dentry = filp->f_path.dentry; | 1478 | struct dentry *dentry = filp->f_path.dentry; |
1462 | struct inode *inode = dentry->d_inode; | 1479 | struct inode *inode = dentry->d_inode; |
1480 | bool is_deleg = (*flp)->fl_flags & FL_DELEG; | ||
1463 | int error; | 1481 | int error; |
1464 | 1482 | ||
1465 | lease = *flp; | 1483 | lease = *flp; |
1484 | /* | ||
1485 | * In the delegation case we need mutual exclusion with | ||
1486 | * a number of operations that take the i_mutex. We trylock | ||
1487 | * because delegations are an optional optimization, and if | ||
1488 | * there's some chance of a conflict--we'd rather not | ||
1489 | * bother, maybe that's a sign this just isn't a good file to | ||
1490 | * hand out a delegation on. | ||
1491 | */ | ||
1492 | if (is_deleg && !mutex_trylock(&inode->i_mutex)) | ||
1493 | return -EAGAIN; | ||
1494 | |||
1495 | if (is_deleg && arg == F_WRLCK) { | ||
1496 | /* Write delegations are not currently supported: */ | ||
1497 | mutex_unlock(&inode->i_mutex); | ||
1498 | WARN_ON_ONCE(1); | ||
1499 | return -EINVAL; | ||
1500 | } | ||
1466 | 1501 | ||
1467 | error = -EAGAIN; | 1502 | error = -EAGAIN; |
1468 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) | 1503 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) |
@@ -1514,9 +1549,10 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp | |||
1514 | goto out; | 1549 | goto out; |
1515 | 1550 | ||
1516 | locks_insert_lock(before, lease); | 1551 | locks_insert_lock(before, lease); |
1517 | return 0; | 1552 | error = 0; |
1518 | |||
1519 | out: | 1553 | out: |
1554 | if (is_deleg) | ||
1555 | mutex_unlock(&inode->i_mutex); | ||
1520 | return error; | 1556 | return error; |
1521 | } | 1557 | } |
1522 | 1558 | ||
@@ -1579,7 +1615,7 @@ EXPORT_SYMBOL(generic_setlease); | |||
1579 | 1615 | ||
1580 | static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease) | 1616 | static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease) |
1581 | { | 1617 | { |
1582 | if (filp->f_op && filp->f_op->setlease) | 1618 | if (filp->f_op->setlease) |
1583 | return filp->f_op->setlease(filp, arg, lease); | 1619 | return filp->f_op->setlease(filp, arg, lease); |
1584 | else | 1620 | else |
1585 | return generic_setlease(filp, arg, lease); | 1621 | return generic_setlease(filp, arg, lease); |
@@ -1771,7 +1807,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) | |||
1771 | if (error) | 1807 | if (error) |
1772 | goto out_free; | 1808 | goto out_free; |
1773 | 1809 | ||
1774 | if (f.file->f_op && f.file->f_op->flock) | 1810 | if (f.file->f_op->flock) |
1775 | error = f.file->f_op->flock(f.file, | 1811 | error = f.file->f_op->flock(f.file, |
1776 | (can_sleep) ? F_SETLKW : F_SETLK, | 1812 | (can_sleep) ? F_SETLKW : F_SETLK, |
1777 | lock); | 1813 | lock); |
@@ -1797,7 +1833,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) | |||
1797 | */ | 1833 | */ |
1798 | int vfs_test_lock(struct file *filp, struct file_lock *fl) | 1834 | int vfs_test_lock(struct file *filp, struct file_lock *fl) |
1799 | { | 1835 | { |
1800 | if (filp->f_op && filp->f_op->lock) | 1836 | if (filp->f_op->lock) |
1801 | return filp->f_op->lock(filp, F_GETLK, fl); | 1837 | return filp->f_op->lock(filp, F_GETLK, fl); |
1802 | posix_test_lock(filp, fl); | 1838 | posix_test_lock(filp, fl); |
1803 | return 0; | 1839 | return 0; |
@@ -1909,7 +1945,7 @@ out: | |||
1909 | */ | 1945 | */ |
1910 | int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf) | 1946 | int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf) |
1911 | { | 1947 | { |
1912 | if (filp->f_op && filp->f_op->lock) | 1948 | if (filp->f_op->lock) |
1913 | return filp->f_op->lock(filp, cmd, fl); | 1949 | return filp->f_op->lock(filp, cmd, fl); |
1914 | else | 1950 | else |
1915 | return posix_lock_file(filp, fl, conf); | 1951 | return posix_lock_file(filp, fl, conf); |
@@ -2182,7 +2218,7 @@ void locks_remove_flock(struct file *filp) | |||
2182 | if (!inode->i_flock) | 2218 | if (!inode->i_flock) |
2183 | return; | 2219 | return; |
2184 | 2220 | ||
2185 | if (filp->f_op && filp->f_op->flock) { | 2221 | if (filp->f_op->flock) { |
2186 | struct file_lock fl = { | 2222 | struct file_lock fl = { |
2187 | .fl_pid = current->tgid, | 2223 | .fl_pid = current->tgid, |
2188 | .fl_file = filp, | 2224 | .fl_file = filp, |
@@ -2246,7 +2282,7 @@ EXPORT_SYMBOL(posix_unblock_lock); | |||
2246 | */ | 2282 | */ |
2247 | int vfs_cancel_lock(struct file *filp, struct file_lock *fl) | 2283 | int vfs_cancel_lock(struct file *filp, struct file_lock *fl) |
2248 | { | 2284 | { |
2249 | if (filp->f_op && filp->f_op->lock) | 2285 | if (filp->f_op->lock) |
2250 | return filp->f_op->lock(filp, F_CANCELLK, fl); | 2286 | return filp->f_op->lock(filp, F_CANCELLK, fl); |
2251 | return 0; | 2287 | return 0; |
2252 | } | 2288 | } |