aboutsummaryrefslogtreecommitdiffstats
path: root/fs/locks.c
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2012-03-05 13:18:59 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2013-11-09 00:16:41 -0500
commitdf4e8d2c1d2bbbbace706bfe5417320c9e3fbee3 (patch)
tree0a56a71e11f39a638be30064411dc6c3363114b6 /fs/locks.c
parent617588d5186c887eb94321b021bb5a46f896f4b3 (diff)
locks: implement delegations
Implement NFSv4 delegations at the vfs level using the new FL_DELEG lock type. Note nfsd is the only delegation user and is only using read delegations. Warn on any attempt to set a write delegation for now. We'll come back to that case later. Acked-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/locks.c')
-rw-r--r--fs/locks.c55
1 files changed, 45 insertions, 10 deletions
diff --git a/fs/locks.c b/fs/locks.c
index 079abcd8a836..f99d52bdd05a 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1292,28 +1292,40 @@ static void time_out_leases(struct inode *inode)
1292 } 1292 }
1293} 1293}
1294 1294
1295static 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 */
1305int __break_lease(struct inode *inode, unsigned int mode) 1315int __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,26 @@ 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 WARN_ON_ONCE(1);
1498 return -EINVAL;
1499 }
1466 1500
1467 error = -EAGAIN; 1501 error = -EAGAIN;
1468 if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) 1502 if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
@@ -1514,9 +1548,10 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
1514 goto out; 1548 goto out;
1515 1549
1516 locks_insert_lock(before, lease); 1550 locks_insert_lock(before, lease);
1517 return 0; 1551 error = 0;
1518
1519out: 1552out:
1553 if (is_deleg)
1554 mutex_unlock(&inode->i_mutex);
1520 return error; 1555 return error;
1521} 1556}
1522 1557