diff options
| author | Jeff Layton <jlayton@primarydata.com> | 2015-01-16 15:05:55 -0500 |
|---|---|---|
| committer | Jeff Layton <jeff.layton@primarydata.com> | 2015-01-16 16:08:17 -0500 |
| commit | 8634b51f6ca298fb8b07aa4847340764903533ab (patch) | |
| tree | e3c32514f05317bacc40aba8782a9912f887cebd | |
| parent | bd61e0a9c852de2d705b6f1bb2cc54c5774db570 (diff) | |
locks: convert lease handling to file_lock_context
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
Acked-by: Christoph Hellwig <hch@lst.de>
| -rw-r--r-- | fs/locks.c | 252 | ||||
| -rw-r--r-- | include/linux/fs.h | 5 |
2 files changed, 102 insertions, 155 deletions
diff --git a/fs/locks.c b/fs/locks.c index e50bb4d9e757..d46e70567b99 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -216,6 +216,7 @@ locks_get_lock_context(struct inode *inode) | |||
| 216 | 216 | ||
| 217 | INIT_LIST_HEAD(&new->flc_flock); | 217 | INIT_LIST_HEAD(&new->flc_flock); |
| 218 | INIT_LIST_HEAD(&new->flc_posix); | 218 | INIT_LIST_HEAD(&new->flc_posix); |
| 219 | INIT_LIST_HEAD(&new->flc_lease); | ||
| 219 | 220 | ||
| 220 | /* | 221 | /* |
| 221 | * Assign the pointer if it's not already assigned. If it is, then | 222 | * Assign the pointer if it's not already assigned. If it is, then |
| @@ -240,6 +241,7 @@ locks_free_lock_context(struct file_lock_context *ctx) | |||
| 240 | if (ctx) { | 241 | if (ctx) { |
| 241 | WARN_ON_ONCE(!list_empty(&ctx->flc_flock)); | 242 | WARN_ON_ONCE(!list_empty(&ctx->flc_flock)); |
| 242 | WARN_ON_ONCE(!list_empty(&ctx->flc_posix)); | 243 | WARN_ON_ONCE(!list_empty(&ctx->flc_posix)); |
| 244 | WARN_ON_ONCE(!list_empty(&ctx->flc_lease)); | ||
| 243 | kmem_cache_free(flctx_cache, ctx); | 245 | kmem_cache_free(flctx_cache, ctx); |
| 244 | } | 246 | } |
| 245 | } | 247 | } |
| @@ -677,22 +679,6 @@ static void locks_wake_up_blocks(struct file_lock *blocker) | |||
| 677 | spin_unlock(&blocked_lock_lock); | 679 | spin_unlock(&blocked_lock_lock); |
| 678 | } | 680 | } |
| 679 | 681 | ||
| 680 | /* Insert file lock fl into an inode's lock list at the position indicated | ||
| 681 | * by pos. At the same time add the lock to the global file lock list. | ||
| 682 | * | ||
| 683 | * Must be called with the i_lock held! | ||
| 684 | */ | ||
| 685 | static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) | ||
| 686 | { | ||
| 687 | fl->fl_nspid = get_pid(task_tgid(current)); | ||
| 688 | |||
| 689 | /* insert into file's list */ | ||
| 690 | fl->fl_next = *pos; | ||
| 691 | *pos = fl; | ||
| 692 | |||
| 693 | locks_insert_global_locks(fl); | ||
| 694 | } | ||
| 695 | |||
| 696 | static void | 682 | static void |
| 697 | locks_insert_lock_ctx(struct file_lock *fl, struct list_head *before) | 683 | locks_insert_lock_ctx(struct file_lock *fl, struct list_head *before) |
| 698 | { | 684 | { |
| @@ -701,63 +687,28 @@ locks_insert_lock_ctx(struct file_lock *fl, struct list_head *before) | |||
| 701 | locks_insert_global_locks(fl); | 687 | locks_insert_global_locks(fl); |
| 702 | } | 688 | } |
| 703 | 689 | ||
| 704 | /** | 690 | static void |
| 705 | * locks_delete_lock - Delete a lock and then free it. | 691 | locks_unlink_lock_ctx(struct file_lock *fl) |
| 706 | * @thisfl_p: pointer that points to the fl_next field of the previous | ||
| 707 | * inode->i_flock list entry | ||
| 708 | * | ||
| 709 | * Unlink a lock from all lists and free the namespace reference, but don't | ||
| 710 | * free it yet. Wake up processes that are blocked waiting for this lock and | ||
| 711 | * notify the FS that the lock has been cleared. | ||
| 712 | * | ||
| 713 | * Must be called with the i_lock held! | ||
| 714 | */ | ||
| 715 | static void locks_unlink_lock(struct file_lock **thisfl_p) | ||
| 716 | { | 692 | { |
| 717 | struct file_lock *fl = *thisfl_p; | ||
| 718 | |||
| 719 | locks_delete_global_locks(fl); | 693 | locks_delete_global_locks(fl); |
| 720 | 694 | list_del_init(&fl->fl_list); | |
| 721 | *thisfl_p = fl->fl_next; | ||
| 722 | fl->fl_next = NULL; | ||
| 723 | |||
| 724 | if (fl->fl_nspid) { | 695 | if (fl->fl_nspid) { |
| 725 | put_pid(fl->fl_nspid); | 696 | put_pid(fl->fl_nspid); |
| 726 | fl->fl_nspid = NULL; | 697 | fl->fl_nspid = NULL; |
| 727 | } | 698 | } |
| 728 | |||
| 729 | locks_wake_up_blocks(fl); | 699 | locks_wake_up_blocks(fl); |
| 730 | } | 700 | } |
| 731 | 701 | ||
| 732 | /* | 702 | static void |
| 733 | * Unlink a lock from all lists and free it. | 703 | locks_delete_lock_ctx(struct file_lock *fl, struct list_head *dispose) |
| 734 | * | ||
| 735 | * Must be called with i_lock held! | ||
| 736 | */ | ||
| 737 | static void locks_delete_lock(struct file_lock **thisfl_p, | ||
| 738 | struct list_head *dispose) | ||
| 739 | { | 704 | { |
| 740 | struct file_lock *fl = *thisfl_p; | 705 | locks_unlink_lock_ctx(fl); |
| 741 | |||
| 742 | locks_unlink_lock(thisfl_p); | ||
| 743 | if (dispose) | 706 | if (dispose) |
| 744 | list_add(&fl->fl_list, dispose); | 707 | list_add(&fl->fl_list, dispose); |
| 745 | else | 708 | else |
| 746 | locks_free_lock(fl); | 709 | locks_free_lock(fl); |
| 747 | } | 710 | } |
| 748 | 711 | ||
| 749 | static void | ||
| 750 | locks_delete_lock_ctx(struct file_lock *fl, struct list_head *dispose) | ||
| 751 | { | ||
| 752 | locks_delete_global_locks(fl); | ||
| 753 | if (fl->fl_nspid) { | ||
| 754 | put_pid(fl->fl_nspid); | ||
| 755 | fl->fl_nspid = NULL; | ||
| 756 | } | ||
| 757 | locks_wake_up_blocks(fl); | ||
| 758 | list_move(&fl->fl_list, dispose); | ||
| 759 | } | ||
| 760 | |||
| 761 | /* Determine if lock sys_fl blocks lock caller_fl. Common functionality | 712 | /* Determine if lock sys_fl blocks lock caller_fl. Common functionality |
| 762 | * checks for shared/exclusive status of overlapping locks. | 713 | * checks for shared/exclusive status of overlapping locks. |
| 763 | */ | 714 | */ |
| @@ -1376,7 +1327,7 @@ int lease_modify(struct file_lock **before, int arg, struct list_head *dispose) | |||
| 1376 | printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync); | 1327 | printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync); |
| 1377 | fl->fl_fasync = NULL; | 1328 | fl->fl_fasync = NULL; |
| 1378 | } | 1329 | } |
| 1379 | locks_delete_lock(before, dispose); | 1330 | locks_delete_lock_ctx(fl, dispose); |
| 1380 | } | 1331 | } |
| 1381 | return 0; | 1332 | return 0; |
| 1382 | } | 1333 | } |
| @@ -1392,20 +1343,17 @@ static bool past_time(unsigned long then) | |||
| 1392 | 1343 | ||
| 1393 | static void time_out_leases(struct inode *inode, struct list_head *dispose) | 1344 | static void time_out_leases(struct inode *inode, struct list_head *dispose) |
| 1394 | { | 1345 | { |
| 1395 | struct file_lock **before; | 1346 | struct file_lock_context *ctx = inode->i_flctx; |
| 1396 | struct file_lock *fl; | 1347 | struct file_lock *fl, *tmp; |
| 1397 | 1348 | ||
| 1398 | lockdep_assert_held(&inode->i_lock); | 1349 | lockdep_assert_held(&inode->i_lock); |
| 1399 | 1350 | ||
| 1400 | before = &inode->i_flock; | 1351 | list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) { |
| 1401 | while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) { | ||
| 1402 | trace_time_out_leases(inode, fl); | 1352 | trace_time_out_leases(inode, fl); |
| 1403 | if (past_time(fl->fl_downgrade_time)) | 1353 | if (past_time(fl->fl_downgrade_time)) |
| 1404 | lease_modify(before, F_RDLCK, dispose); | 1354 | lease_modify(&fl, F_RDLCK, dispose); |
| 1405 | if (past_time(fl->fl_break_time)) | 1355 | if (past_time(fl->fl_break_time)) |
| 1406 | lease_modify(before, F_UNLCK, dispose); | 1356 | lease_modify(&fl, F_UNLCK, dispose); |
| 1407 | if (fl == *before) /* lease_modify may have freed fl */ | ||
| 1408 | before = &fl->fl_next; | ||
| 1409 | } | 1357 | } |
| 1410 | } | 1358 | } |
| 1411 | 1359 | ||
| @@ -1419,11 +1367,12 @@ static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker) | |||
| 1419 | static bool | 1367 | static bool |
| 1420 | any_leases_conflict(struct inode *inode, struct file_lock *breaker) | 1368 | any_leases_conflict(struct inode *inode, struct file_lock *breaker) |
| 1421 | { | 1369 | { |
| 1370 | struct file_lock_context *ctx = inode->i_flctx; | ||
| 1422 | struct file_lock *fl; | 1371 | struct file_lock *fl; |
| 1423 | 1372 | ||
| 1424 | lockdep_assert_held(&inode->i_lock); | 1373 | lockdep_assert_held(&inode->i_lock); |
| 1425 | 1374 | ||
| 1426 | for (fl = inode->i_flock ; fl && IS_LEASE(fl); fl = fl->fl_next) { | 1375 | list_for_each_entry(fl, &ctx->flc_lease, fl_list) { |
| 1427 | if (leases_conflict(fl, breaker)) | 1376 | if (leases_conflict(fl, breaker)) |
| 1428 | return true; | 1377 | return true; |
| 1429 | } | 1378 | } |
| @@ -1447,7 +1396,8 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) | |||
| 1447 | { | 1396 | { |
| 1448 | int error = 0; | 1397 | int error = 0; |
| 1449 | struct file_lock *new_fl; | 1398 | struct file_lock *new_fl; |
| 1450 | struct file_lock *fl, **before; | 1399 | struct file_lock_context *ctx = inode->i_flctx; |
| 1400 | struct file_lock *fl; | ||
| 1451 | unsigned long break_time; | 1401 | unsigned long break_time; |
| 1452 | int want_write = (mode & O_ACCMODE) != O_RDONLY; | 1402 | int want_write = (mode & O_ACCMODE) != O_RDONLY; |
| 1453 | LIST_HEAD(dispose); | 1403 | LIST_HEAD(dispose); |
| @@ -1457,6 +1407,12 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) | |||
| 1457 | return PTR_ERR(new_fl); | 1407 | return PTR_ERR(new_fl); |
| 1458 | new_fl->fl_flags = type; | 1408 | new_fl->fl_flags = type; |
| 1459 | 1409 | ||
| 1410 | /* typically we will check that ctx is non-NULL before calling */ | ||
| 1411 | if (!ctx) { | ||
| 1412 | WARN_ON_ONCE(1); | ||
| 1413 | return error; | ||
| 1414 | } | ||
| 1415 | |||
| 1460 | spin_lock(&inode->i_lock); | 1416 | spin_lock(&inode->i_lock); |
| 1461 | 1417 | ||
| 1462 | time_out_leases(inode, &dispose); | 1418 | time_out_leases(inode, &dispose); |
| @@ -1471,9 +1427,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) | |||
| 1471 | break_time++; /* so that 0 means no break time */ | 1427 | break_time++; /* so that 0 means no break time */ |
| 1472 | } | 1428 | } |
| 1473 | 1429 | ||
| 1474 | for (before = &inode->i_flock; | 1430 | list_for_each_entry(fl, &ctx->flc_lease, fl_list) { |
| 1475 | ((fl = *before) != NULL) && IS_LEASE(fl); | ||
| 1476 | before = &fl->fl_next) { | ||
| 1477 | if (!leases_conflict(fl, new_fl)) | 1431 | if (!leases_conflict(fl, new_fl)) |
| 1478 | continue; | 1432 | continue; |
| 1479 | if (want_write) { | 1433 | if (want_write) { |
| @@ -1482,17 +1436,16 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) | |||
| 1482 | fl->fl_flags |= FL_UNLOCK_PENDING; | 1436 | fl->fl_flags |= FL_UNLOCK_PENDING; |
| 1483 | fl->fl_break_time = break_time; | 1437 | fl->fl_break_time = break_time; |
| 1484 | } else { | 1438 | } else { |
| 1485 | if (lease_breaking(inode->i_flock)) | 1439 | if (lease_breaking(fl)) |
| 1486 | continue; | 1440 | continue; |
| 1487 | fl->fl_flags |= FL_DOWNGRADE_PENDING; | 1441 | fl->fl_flags |= FL_DOWNGRADE_PENDING; |
| 1488 | fl->fl_downgrade_time = break_time; | 1442 | fl->fl_downgrade_time = break_time; |
| 1489 | } | 1443 | } |
| 1490 | if (fl->fl_lmops->lm_break(fl)) | 1444 | if (fl->fl_lmops->lm_break(fl)) |
| 1491 | locks_delete_lock(before, &dispose); | 1445 | locks_delete_lock_ctx(fl, &dispose); |
| 1492 | } | 1446 | } |
| 1493 | 1447 | ||
| 1494 | fl = inode->i_flock; | 1448 | if (list_empty(&ctx->flc_lease)) |
| 1495 | if (!fl || !IS_LEASE(fl)) | ||
| 1496 | goto out; | 1449 | goto out; |
| 1497 | 1450 | ||
| 1498 | if (mode & O_NONBLOCK) { | 1451 | if (mode & O_NONBLOCK) { |
| @@ -1502,12 +1455,13 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) | |||
| 1502 | } | 1455 | } |
| 1503 | 1456 | ||
| 1504 | restart: | 1457 | restart: |
| 1505 | break_time = inode->i_flock->fl_break_time; | 1458 | fl = list_first_entry(&ctx->flc_lease, struct file_lock, fl_list); |
| 1459 | break_time = fl->fl_break_time; | ||
| 1506 | if (break_time != 0) | 1460 | if (break_time != 0) |
| 1507 | break_time -= jiffies; | 1461 | break_time -= jiffies; |
| 1508 | if (break_time == 0) | 1462 | if (break_time == 0) |
| 1509 | break_time++; | 1463 | break_time++; |
| 1510 | locks_insert_block(inode->i_flock, new_fl); | 1464 | locks_insert_block(fl, new_fl); |
| 1511 | trace_break_lease_block(inode, new_fl); | 1465 | trace_break_lease_block(inode, new_fl); |
| 1512 | spin_unlock(&inode->i_lock); | 1466 | spin_unlock(&inode->i_lock); |
| 1513 | locks_dispose_list(&dispose); | 1467 | locks_dispose_list(&dispose); |
| @@ -1525,10 +1479,8 @@ restart: | |||
| 1525 | time_out_leases(inode, &dispose); | 1479 | time_out_leases(inode, &dispose); |
| 1526 | if (any_leases_conflict(inode, new_fl)) | 1480 | if (any_leases_conflict(inode, new_fl)) |
| 1527 | goto restart; | 1481 | goto restart; |
| 1528 | |||
| 1529 | error = 0; | 1482 | error = 0; |
| 1530 | } | 1483 | } |
| 1531 | |||
| 1532 | out: | 1484 | out: |
| 1533 | spin_unlock(&inode->i_lock); | 1485 | spin_unlock(&inode->i_lock); |
| 1534 | locks_dispose_list(&dispose); | 1486 | locks_dispose_list(&dispose); |
| @@ -1550,13 +1502,17 @@ EXPORT_SYMBOL(__break_lease); | |||
| 1550 | void lease_get_mtime(struct inode *inode, struct timespec *time) | 1502 | void lease_get_mtime(struct inode *inode, struct timespec *time) |
| 1551 | { | 1503 | { |
| 1552 | bool has_lease = false; | 1504 | bool has_lease = false; |
| 1553 | struct file_lock *flock; | 1505 | struct file_lock_context *ctx = inode->i_flctx; |
| 1506 | struct file_lock *fl; | ||
| 1554 | 1507 | ||
| 1555 | if (inode->i_flock) { | 1508 | if (ctx && !list_empty_careful(&ctx->flc_lease)) { |
| 1556 | spin_lock(&inode->i_lock); | 1509 | spin_lock(&inode->i_lock); |
| 1557 | flock = inode->i_flock; | 1510 | if (!list_empty(&ctx->flc_lease)) { |
| 1558 | if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK)) | 1511 | fl = list_first_entry(&ctx->flc_lease, |
| 1559 | has_lease = true; | 1512 | struct file_lock, fl_list); |
| 1513 | if (fl->fl_type == F_WRLCK) | ||
| 1514 | has_lease = true; | ||
| 1515 | } | ||
| 1560 | spin_unlock(&inode->i_lock); | 1516 | spin_unlock(&inode->i_lock); |
| 1561 | } | 1517 | } |
| 1562 | 1518 | ||
| @@ -1595,20 +1551,22 @@ int fcntl_getlease(struct file *filp) | |||
| 1595 | { | 1551 | { |
| 1596 | struct file_lock *fl; | 1552 | struct file_lock *fl; |
| 1597 | struct inode *inode = file_inode(filp); | 1553 | struct inode *inode = file_inode(filp); |
| 1554 | struct file_lock_context *ctx = inode->i_flctx; | ||
| 1598 | int type = F_UNLCK; | 1555 | int type = F_UNLCK; |
| 1599 | LIST_HEAD(dispose); | 1556 | LIST_HEAD(dispose); |
| 1600 | 1557 | ||
| 1601 | spin_lock(&inode->i_lock); | 1558 | if (ctx && !list_empty_careful(&ctx->flc_lease)) { |
| 1602 | time_out_leases(file_inode(filp), &dispose); | 1559 | spin_lock(&inode->i_lock); |
| 1603 | for (fl = file_inode(filp)->i_flock; fl && IS_LEASE(fl); | 1560 | time_out_leases(file_inode(filp), &dispose); |
| 1604 | fl = fl->fl_next) { | 1561 | list_for_each_entry(fl, &ctx->flc_lease, fl_list) { |
| 1605 | if (fl->fl_file == filp) { | 1562 | if (fl->fl_file != filp) |
| 1563 | continue; | ||
| 1606 | type = target_leasetype(fl); | 1564 | type = target_leasetype(fl); |
| 1607 | break; | 1565 | break; |
| 1608 | } | 1566 | } |
| 1567 | spin_unlock(&inode->i_lock); | ||
| 1568 | locks_dispose_list(&dispose); | ||
| 1609 | } | 1569 | } |
| 1610 | spin_unlock(&inode->i_lock); | ||
| 1611 | locks_dispose_list(&dispose); | ||
| 1612 | return type; | 1570 | return type; |
| 1613 | } | 1571 | } |
| 1614 | 1572 | ||
| @@ -1641,9 +1599,10 @@ check_conflicting_open(const struct dentry *dentry, const long arg) | |||
| 1641 | static int | 1599 | static int |
| 1642 | generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **priv) | 1600 | generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **priv) |
| 1643 | { | 1601 | { |
| 1644 | struct file_lock *fl, **before, **my_before = NULL, *lease; | 1602 | struct file_lock *fl, *my_fl = NULL, *lease; |
| 1645 | struct dentry *dentry = filp->f_path.dentry; | 1603 | struct dentry *dentry = filp->f_path.dentry; |
| 1646 | struct inode *inode = dentry->d_inode; | 1604 | struct inode *inode = dentry->d_inode; |
| 1605 | struct file_lock_context *ctx; | ||
| 1647 | bool is_deleg = (*flp)->fl_flags & FL_DELEG; | 1606 | bool is_deleg = (*flp)->fl_flags & FL_DELEG; |
| 1648 | int error; | 1607 | int error; |
| 1649 | LIST_HEAD(dispose); | 1608 | LIST_HEAD(dispose); |
| @@ -1651,6 +1610,10 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr | |||
| 1651 | lease = *flp; | 1610 | lease = *flp; |
| 1652 | trace_generic_add_lease(inode, lease); | 1611 | trace_generic_add_lease(inode, lease); |
| 1653 | 1612 | ||
| 1613 | ctx = locks_get_lock_context(inode); | ||
| 1614 | if (!ctx) | ||
| 1615 | return -ENOMEM; | ||
| 1616 | |||
| 1654 | /* | 1617 | /* |
| 1655 | * In the delegation case we need mutual exclusion with | 1618 | * In the delegation case we need mutual exclusion with |
| 1656 | * a number of operations that take the i_mutex. We trylock | 1619 | * a number of operations that take the i_mutex. We trylock |
| @@ -1684,13 +1647,12 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr | |||
| 1684 | * except for this filp. | 1647 | * except for this filp. |
| 1685 | */ | 1648 | */ |
| 1686 | error = -EAGAIN; | 1649 | error = -EAGAIN; |
| 1687 | for (before = &inode->i_flock; | 1650 | list_for_each_entry(fl, &ctx->flc_lease, fl_list) { |
| 1688 | ((fl = *before) != NULL) && IS_LEASE(fl); | ||
| 1689 | before = &fl->fl_next) { | ||
| 1690 | if (fl->fl_file == filp) { | 1651 | if (fl->fl_file == filp) { |
| 1691 | my_before = before; | 1652 | my_fl = fl; |
| 1692 | continue; | 1653 | continue; |
| 1693 | } | 1654 | } |
| 1655 | |||
| 1694 | /* | 1656 | /* |
| 1695 | * No exclusive leases if someone else has a lease on | 1657 | * No exclusive leases if someone else has a lease on |
| 1696 | * this file: | 1658 | * this file: |
| @@ -1705,9 +1667,8 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr | |||
| 1705 | goto out; | 1667 | goto out; |
| 1706 | } | 1668 | } |
| 1707 | 1669 | ||
| 1708 | if (my_before != NULL) { | 1670 | if (my_fl != NULL) { |
| 1709 | lease = *my_before; | 1671 | error = lease->fl_lmops->lm_change(&my_fl, arg, &dispose); |
| 1710 | error = lease->fl_lmops->lm_change(my_before, arg, &dispose); | ||
| 1711 | if (error) | 1672 | if (error) |
| 1712 | goto out; | 1673 | goto out; |
| 1713 | goto out_setup; | 1674 | goto out_setup; |
| @@ -1717,7 +1678,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr | |||
| 1717 | if (!leases_enable) | 1678 | if (!leases_enable) |
| 1718 | goto out; | 1679 | goto out; |
| 1719 | 1680 | ||
| 1720 | locks_insert_lock(before, lease); | 1681 | locks_insert_lock_ctx(lease, &ctx->flc_lease); |
| 1721 | /* | 1682 | /* |
| 1722 | * The check in break_lease() is lockless. It's possible for another | 1683 | * The check in break_lease() is lockless. It's possible for another |
| 1723 | * open to race in after we did the earlier check for a conflicting | 1684 | * open to race in after we did the earlier check for a conflicting |
| @@ -1729,8 +1690,10 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr | |||
| 1729 | */ | 1690 | */ |
| 1730 | smp_mb(); | 1691 | smp_mb(); |
| 1731 | error = check_conflicting_open(dentry, arg); | 1692 | error = check_conflicting_open(dentry, arg); |
| 1732 | if (error) | 1693 | if (error) { |
| 1733 | goto out_unlink; | 1694 | locks_unlink_lock_ctx(lease); |
| 1695 | goto out; | ||
| 1696 | } | ||
| 1734 | 1697 | ||
| 1735 | out_setup: | 1698 | out_setup: |
| 1736 | if (lease->fl_lmops->lm_setup) | 1699 | if (lease->fl_lmops->lm_setup) |
| @@ -1740,33 +1703,35 @@ out: | |||
| 1740 | locks_dispose_list(&dispose); | 1703 | locks_dispose_list(&dispose); |
| 1741 | if (is_deleg) | 1704 | if (is_deleg) |
| 1742 | mutex_unlock(&inode->i_mutex); | 1705 | mutex_unlock(&inode->i_mutex); |
| 1743 | if (!error && !my_before) | 1706 | if (!error && !my_fl) |
| 1744 | *flp = NULL; | 1707 | *flp = NULL; |
| 1745 | return error; | 1708 | return error; |
| 1746 | out_unlink: | ||
| 1747 | locks_unlink_lock(before); | ||
| 1748 | goto out; | ||
| 1749 | } | 1709 | } |
| 1750 | 1710 | ||
| 1751 | static int generic_delete_lease(struct file *filp) | 1711 | static int generic_delete_lease(struct file *filp) |
| 1752 | { | 1712 | { |
| 1753 | int error = -EAGAIN; | 1713 | int error = -EAGAIN; |
| 1754 | struct file_lock *fl, **before; | 1714 | struct file_lock *fl, *victim = NULL; |
| 1755 | struct dentry *dentry = filp->f_path.dentry; | 1715 | struct dentry *dentry = filp->f_path.dentry; |
| 1756 | struct inode *inode = dentry->d_inode; | 1716 | struct inode *inode = dentry->d_inode; |
| 1717 | struct file_lock_context *ctx = inode->i_flctx; | ||
| 1757 | LIST_HEAD(dispose); | 1718 | LIST_HEAD(dispose); |
| 1758 | 1719 | ||
| 1720 | if (!ctx) { | ||
| 1721 | trace_generic_delete_lease(inode, NULL); | ||
| 1722 | return error; | ||
| 1723 | } | ||
| 1724 | |||
| 1759 | spin_lock(&inode->i_lock); | 1725 | spin_lock(&inode->i_lock); |
| 1760 | time_out_leases(inode, &dispose); | 1726 | list_for_each_entry(fl, &ctx->flc_lease, fl_list) { |
| 1761 | for (before = &inode->i_flock; | 1727 | if (fl->fl_file == filp) { |
| 1762 | ((fl = *before) != NULL) && IS_LEASE(fl); | 1728 | victim = fl; |
| 1763 | before = &fl->fl_next) { | ||
| 1764 | if (fl->fl_file == filp) | ||
| 1765 | break; | 1729 | break; |
| 1730 | } | ||
| 1766 | } | 1731 | } |
| 1767 | trace_generic_delete_lease(inode, fl); | 1732 | trace_generic_delete_lease(inode, fl); |
| 1768 | if (fl && IS_LEASE(fl)) | 1733 | if (victim) |
| 1769 | error = fl->fl_lmops->lm_change(before, F_UNLCK, &dispose); | 1734 | error = fl->fl_lmops->lm_change(&victim, F_UNLCK, &dispose); |
| 1770 | spin_unlock(&inode->i_lock); | 1735 | spin_unlock(&inode->i_lock); |
| 1771 | locks_dispose_list(&dispose); | 1736 | locks_dispose_list(&dispose); |
| 1772 | return error; | 1737 | return error; |
| @@ -2447,56 +2412,37 @@ locks_remove_flock(struct file *filp) | |||
| 2447 | fl.fl_ops->fl_release_private(&fl); | 2412 | fl.fl_ops->fl_release_private(&fl); |
| 2448 | } | 2413 | } |
| 2449 | 2414 | ||
| 2415 | static void | ||
| 2416 | locks_remove_lease(struct file *filp) | ||
| 2417 | { | ||
| 2418 | struct inode *inode = file_inode(filp); | ||
| 2419 | struct file_lock_context *ctx = inode->i_flctx; | ||
| 2420 | struct file_lock *fl, *tmp; | ||
| 2421 | LIST_HEAD(dispose); | ||
| 2422 | |||
| 2423 | if (!ctx || list_empty(&ctx->flc_lease)) | ||
| 2424 | return; | ||
| 2425 | |||
| 2426 | spin_lock(&inode->i_lock); | ||
| 2427 | list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) | ||
| 2428 | lease_modify(&fl, F_UNLCK, &dispose); | ||
| 2429 | spin_unlock(&inode->i_lock); | ||
| 2430 | locks_dispose_list(&dispose); | ||
| 2431 | } | ||
| 2432 | |||
| 2450 | /* | 2433 | /* |
| 2451 | * This function is called on the last close of an open file. | 2434 | * This function is called on the last close of an open file. |
| 2452 | */ | 2435 | */ |
| 2453 | void locks_remove_file(struct file *filp) | 2436 | void locks_remove_file(struct file *filp) |
| 2454 | { | 2437 | { |
| 2455 | struct inode * inode = file_inode(filp); | ||
| 2456 | struct file_lock *fl; | ||
| 2457 | struct file_lock **before; | ||
| 2458 | LIST_HEAD(dispose); | ||
| 2459 | |||
| 2460 | /* remove any OFD locks */ | 2438 | /* remove any OFD locks */ |
| 2461 | locks_remove_posix(filp, filp); | 2439 | locks_remove_posix(filp, filp); |
| 2462 | 2440 | ||
| 2463 | /* remove flock locks */ | 2441 | /* remove flock locks */ |
| 2464 | locks_remove_flock(filp); | 2442 | locks_remove_flock(filp); |
| 2465 | 2443 | ||
| 2466 | if (!inode->i_flock) | 2444 | /* remove any leases */ |
| 2467 | return; | 2445 | locks_remove_lease(filp); |
| 2468 | |||
| 2469 | spin_lock(&inode->i_lock); | ||
| 2470 | before = &inode->i_flock; | ||
| 2471 | |||
| 2472 | while ((fl = *before) != NULL) { | ||
| 2473 | if (fl->fl_file == filp) { | ||
| 2474 | if (IS_LEASE(fl)) { | ||
| 2475 | lease_modify(before, F_UNLCK, &dispose); | ||
| 2476 | continue; | ||
| 2477 | } | ||
| 2478 | |||
| 2479 | /* | ||
| 2480 | * There's a leftover lock on the list of a type that | ||
| 2481 | * we didn't expect to see. Most likely a classic | ||
| 2482 | * POSIX lock that ended up not getting released | ||
| 2483 | * properly, or that raced onto the list somehow. Log | ||
| 2484 | * some info about it and then just remove it from | ||
| 2485 | * the list. | ||
| 2486 | */ | ||
| 2487 | WARN(1, "leftover lock: dev=%u:%u ino=%lu type=%hhd flags=0x%x start=%lld end=%lld\n", | ||
| 2488 | MAJOR(inode->i_sb->s_dev), | ||
| 2489 | MINOR(inode->i_sb->s_dev), inode->i_ino, | ||
| 2490 | fl->fl_type, fl->fl_flags, | ||
| 2491 | fl->fl_start, fl->fl_end); | ||
| 2492 | |||
| 2493 | locks_delete_lock(before, &dispose); | ||
| 2494 | continue; | ||
| 2495 | } | ||
| 2496 | before = &fl->fl_next; | ||
| 2497 | } | ||
| 2498 | spin_unlock(&inode->i_lock); | ||
| 2499 | locks_dispose_list(&dispose); | ||
| 2500 | } | 2446 | } |
| 2501 | 2447 | ||
| 2502 | /** | 2448 | /** |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 571f113588e9..2ddec3cf81b9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -969,6 +969,7 @@ struct file_lock { | |||
| 969 | struct file_lock_context { | 969 | struct file_lock_context { |
| 970 | struct list_head flc_flock; | 970 | struct list_head flc_flock; |
| 971 | struct list_head flc_posix; | 971 | struct list_head flc_posix; |
| 972 | struct list_head flc_lease; | ||
| 972 | }; | 973 | }; |
| 973 | 974 | ||
| 974 | /* The following constant reflects the upper bound of the file/locking space */ | 975 | /* The following constant reflects the upper bound of the file/locking space */ |
| @@ -1990,7 +1991,7 @@ static inline int break_lease(struct inode *inode, unsigned int mode) | |||
| 1990 | * end up racing with tasks trying to set a new lease on this file. | 1991 | * end up racing with tasks trying to set a new lease on this file. |
| 1991 | */ | 1992 | */ |
| 1992 | smp_mb(); | 1993 | smp_mb(); |
| 1993 | if (inode->i_flock) | 1994 | if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) |
| 1994 | return __break_lease(inode, mode, FL_LEASE); | 1995 | return __break_lease(inode, mode, FL_LEASE); |
| 1995 | return 0; | 1996 | return 0; |
| 1996 | } | 1997 | } |
| @@ -2003,7 +2004,7 @@ static inline int break_deleg(struct inode *inode, unsigned int mode) | |||
| 2003 | * end up racing with tasks trying to set a new lease on this file. | 2004 | * end up racing with tasks trying to set a new lease on this file. |
| 2004 | */ | 2005 | */ |
| 2005 | smp_mb(); | 2006 | smp_mb(); |
| 2006 | if (inode->i_flock) | 2007 | if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) |
| 2007 | return __break_lease(inode, mode, FL_DELEG); | 2008 | return __break_lease(inode, mode, FL_DELEG); |
| 2008 | return 0; | 2009 | return 0; |
| 2009 | } | 2010 | } |
