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 | } |