diff options
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 267 |
1 files changed, 157 insertions, 110 deletions
diff --git a/fs/locks.c b/fs/locks.c index 52a81005dab4..671a034dc999 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -203,8 +203,7 @@ static void init_once(void *foo, struct kmem_cache *cache, unsigned long flags) | |||
203 | { | 203 | { |
204 | struct file_lock *lock = (struct file_lock *) foo; | 204 | struct file_lock *lock = (struct file_lock *) foo; |
205 | 205 | ||
206 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) != | 206 | if (!(flags & SLAB_CTOR_CONSTRUCTOR)) |
207 | SLAB_CTOR_CONSTRUCTOR) | ||
208 | return; | 207 | return; |
209 | 208 | ||
210 | locks_init_lock(lock); | 209 | locks_init_lock(lock); |
@@ -666,11 +665,11 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w | |||
666 | } | 665 | } |
667 | 666 | ||
668 | int | 667 | int |
669 | posix_test_lock(struct file *filp, struct file_lock *fl, | 668 | posix_test_lock(struct file *filp, struct file_lock *fl) |
670 | struct file_lock *conflock) | ||
671 | { | 669 | { |
672 | struct file_lock *cfl; | 670 | struct file_lock *cfl; |
673 | 671 | ||
672 | fl->fl_type = F_UNLCK; | ||
674 | lock_kernel(); | 673 | lock_kernel(); |
675 | for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { | 674 | for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { |
676 | if (!IS_POSIX(cfl)) | 675 | if (!IS_POSIX(cfl)) |
@@ -679,7 +678,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl, | |||
679 | break; | 678 | break; |
680 | } | 679 | } |
681 | if (cfl) { | 680 | if (cfl) { |
682 | __locks_copy_lock(conflock, cfl); | 681 | __locks_copy_lock(fl, cfl); |
683 | unlock_kernel(); | 682 | unlock_kernel(); |
684 | return 1; | 683 | return 1; |
685 | } | 684 | } |
@@ -801,7 +800,7 @@ out: | |||
801 | return error; | 800 | return error; |
802 | } | 801 | } |
803 | 802 | ||
804 | static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock) | 803 | static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock) |
805 | { | 804 | { |
806 | struct file_lock *fl; | 805 | struct file_lock *fl; |
807 | struct file_lock *new_fl = NULL; | 806 | struct file_lock *new_fl = NULL; |
@@ -1007,6 +1006,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request | |||
1007 | * posix_lock_file - Apply a POSIX-style lock to a file | 1006 | * posix_lock_file - Apply a POSIX-style lock to a file |
1008 | * @filp: The file to apply the lock to | 1007 | * @filp: The file to apply the lock to |
1009 | * @fl: The lock to be applied | 1008 | * @fl: The lock to be applied |
1009 | * @conflock: Place to return a copy of the conflicting lock, if found. | ||
1010 | * | 1010 | * |
1011 | * Add a POSIX style lock to a file. | 1011 | * Add a POSIX style lock to a file. |
1012 | * We merge adjacent & overlapping locks whenever possible. | 1012 | * We merge adjacent & overlapping locks whenever possible. |
@@ -1016,26 +1016,12 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request | |||
1016 | * whether or not a lock was successfully freed by testing the return | 1016 | * whether or not a lock was successfully freed by testing the return |
1017 | * value for -ENOENT. | 1017 | * value for -ENOENT. |
1018 | */ | 1018 | */ |
1019 | int posix_lock_file(struct file *filp, struct file_lock *fl) | 1019 | int posix_lock_file(struct file *filp, struct file_lock *fl, |
1020 | { | ||
1021 | return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, NULL); | ||
1022 | } | ||
1023 | EXPORT_SYMBOL(posix_lock_file); | ||
1024 | |||
1025 | /** | ||
1026 | * posix_lock_file_conf - Apply a POSIX-style lock to a file | ||
1027 | * @filp: The file to apply the lock to | ||
1028 | * @fl: The lock to be applied | ||
1029 | * @conflock: Place to return a copy of the conflicting lock, if found. | ||
1030 | * | ||
1031 | * Except for the conflock parameter, acts just like posix_lock_file. | ||
1032 | */ | ||
1033 | int posix_lock_file_conf(struct file *filp, struct file_lock *fl, | ||
1034 | struct file_lock *conflock) | 1020 | struct file_lock *conflock) |
1035 | { | 1021 | { |
1036 | return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, conflock); | 1022 | return __posix_lock_file(filp->f_path.dentry->d_inode, fl, conflock); |
1037 | } | 1023 | } |
1038 | EXPORT_SYMBOL(posix_lock_file_conf); | 1024 | EXPORT_SYMBOL(posix_lock_file); |
1039 | 1025 | ||
1040 | /** | 1026 | /** |
1041 | * posix_lock_file_wait - Apply a POSIX-style lock to a file | 1027 | * posix_lock_file_wait - Apply a POSIX-style lock to a file |
@@ -1051,7 +1037,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl) | |||
1051 | int error; | 1037 | int error; |
1052 | might_sleep (); | 1038 | might_sleep (); |
1053 | for (;;) { | 1039 | for (;;) { |
1054 | error = posix_lock_file(filp, fl); | 1040 | error = posix_lock_file(filp, fl, NULL); |
1055 | if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) | 1041 | if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) |
1056 | break; | 1042 | break; |
1057 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); | 1043 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); |
@@ -1123,7 +1109,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, | |||
1123 | fl.fl_end = offset + count - 1; | 1109 | fl.fl_end = offset + count - 1; |
1124 | 1110 | ||
1125 | for (;;) { | 1111 | for (;;) { |
1126 | error = __posix_lock_file_conf(inode, &fl, NULL); | 1112 | error = __posix_lock_file(inode, &fl, NULL); |
1127 | if (error != -EAGAIN) | 1113 | if (error != -EAGAIN) |
1128 | break; | 1114 | break; |
1129 | if (!(fl.fl_flags & FL_SLEEP)) | 1115 | if (!(fl.fl_flags & FL_SLEEP)) |
@@ -1611,12 +1597,62 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) | |||
1611 | return error; | 1597 | return error; |
1612 | } | 1598 | } |
1613 | 1599 | ||
1600 | /** | ||
1601 | * vfs_test_lock - test file byte range lock | ||
1602 | * @filp: The file to test lock for | ||
1603 | * @fl: The lock to test | ||
1604 | * @conf: Place to return a copy of the conflicting lock, if found | ||
1605 | * | ||
1606 | * Returns -ERRNO on failure. Indicates presence of conflicting lock by | ||
1607 | * setting conf->fl_type to something other than F_UNLCK. | ||
1608 | */ | ||
1609 | int vfs_test_lock(struct file *filp, struct file_lock *fl) | ||
1610 | { | ||
1611 | if (filp->f_op && filp->f_op->lock) | ||
1612 | return filp->f_op->lock(filp, F_GETLK, fl); | ||
1613 | posix_test_lock(filp, fl); | ||
1614 | return 0; | ||
1615 | } | ||
1616 | EXPORT_SYMBOL_GPL(vfs_test_lock); | ||
1617 | |||
1618 | static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl) | ||
1619 | { | ||
1620 | flock->l_pid = fl->fl_pid; | ||
1621 | #if BITS_PER_LONG == 32 | ||
1622 | /* | ||
1623 | * Make sure we can represent the posix lock via | ||
1624 | * legacy 32bit flock. | ||
1625 | */ | ||
1626 | if (fl->fl_start > OFFT_OFFSET_MAX) | ||
1627 | return -EOVERFLOW; | ||
1628 | if (fl->fl_end != OFFSET_MAX && fl->fl_end > OFFT_OFFSET_MAX) | ||
1629 | return -EOVERFLOW; | ||
1630 | #endif | ||
1631 | flock->l_start = fl->fl_start; | ||
1632 | flock->l_len = fl->fl_end == OFFSET_MAX ? 0 : | ||
1633 | fl->fl_end - fl->fl_start + 1; | ||
1634 | flock->l_whence = 0; | ||
1635 | return 0; | ||
1636 | } | ||
1637 | |||
1638 | #if BITS_PER_LONG == 32 | ||
1639 | static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl) | ||
1640 | { | ||
1641 | flock->l_pid = fl->fl_pid; | ||
1642 | flock->l_start = fl->fl_start; | ||
1643 | flock->l_len = fl->fl_end == OFFSET_MAX ? 0 : | ||
1644 | fl->fl_end - fl->fl_start + 1; | ||
1645 | flock->l_whence = 0; | ||
1646 | flock->l_type = fl->fl_type; | ||
1647 | } | ||
1648 | #endif | ||
1649 | |||
1614 | /* Report the first existing lock that would conflict with l. | 1650 | /* Report the first existing lock that would conflict with l. |
1615 | * This implements the F_GETLK command of fcntl(). | 1651 | * This implements the F_GETLK command of fcntl(). |
1616 | */ | 1652 | */ |
1617 | int fcntl_getlk(struct file *filp, struct flock __user *l) | 1653 | int fcntl_getlk(struct file *filp, struct flock __user *l) |
1618 | { | 1654 | { |
1619 | struct file_lock *fl, cfl, file_lock; | 1655 | struct file_lock file_lock; |
1620 | struct flock flock; | 1656 | struct flock flock; |
1621 | int error; | 1657 | int error; |
1622 | 1658 | ||
@@ -1631,38 +1667,15 @@ int fcntl_getlk(struct file *filp, struct flock __user *l) | |||
1631 | if (error) | 1667 | if (error) |
1632 | goto out; | 1668 | goto out; |
1633 | 1669 | ||
1634 | if (filp->f_op && filp->f_op->lock) { | 1670 | error = vfs_test_lock(filp, &file_lock); |
1635 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); | 1671 | if (error) |
1636 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | 1672 | goto out; |
1637 | file_lock.fl_ops->fl_release_private(&file_lock); | ||
1638 | if (error < 0) | ||
1639 | goto out; | ||
1640 | else | ||
1641 | fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); | ||
1642 | } else { | ||
1643 | fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL); | ||
1644 | } | ||
1645 | 1673 | ||
1646 | flock.l_type = F_UNLCK; | 1674 | flock.l_type = file_lock.fl_type; |
1647 | if (fl != NULL) { | 1675 | if (file_lock.fl_type != F_UNLCK) { |
1648 | flock.l_pid = fl->fl_pid; | 1676 | error = posix_lock_to_flock(&flock, &file_lock); |
1649 | #if BITS_PER_LONG == 32 | 1677 | if (error) |
1650 | /* | ||
1651 | * Make sure we can represent the posix lock via | ||
1652 | * legacy 32bit flock. | ||
1653 | */ | ||
1654 | error = -EOVERFLOW; | ||
1655 | if (fl->fl_start > OFFT_OFFSET_MAX) | ||
1656 | goto out; | ||
1657 | if ((fl->fl_end != OFFSET_MAX) | ||
1658 | && (fl->fl_end > OFFT_OFFSET_MAX)) | ||
1659 | goto out; | 1678 | goto out; |
1660 | #endif | ||
1661 | flock.l_start = fl->fl_start; | ||
1662 | flock.l_len = fl->fl_end == OFFSET_MAX ? 0 : | ||
1663 | fl->fl_end - fl->fl_start + 1; | ||
1664 | flock.l_whence = 0; | ||
1665 | flock.l_type = fl->fl_type; | ||
1666 | } | 1679 | } |
1667 | error = -EFAULT; | 1680 | error = -EFAULT; |
1668 | if (!copy_to_user(l, &flock, sizeof(flock))) | 1681 | if (!copy_to_user(l, &flock, sizeof(flock))) |
@@ -1671,6 +1684,48 @@ out: | |||
1671 | return error; | 1684 | return error; |
1672 | } | 1685 | } |
1673 | 1686 | ||
1687 | /** | ||
1688 | * vfs_lock_file - file byte range lock | ||
1689 | * @filp: The file to apply the lock to | ||
1690 | * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.) | ||
1691 | * @fl: The lock to be applied | ||
1692 | * @conf: Place to return a copy of the conflicting lock, if found. | ||
1693 | * | ||
1694 | * A caller that doesn't care about the conflicting lock may pass NULL | ||
1695 | * as the final argument. | ||
1696 | * | ||
1697 | * If the filesystem defines a private ->lock() method, then @conf will | ||
1698 | * be left unchanged; so a caller that cares should initialize it to | ||
1699 | * some acceptable default. | ||
1700 | * | ||
1701 | * To avoid blocking kernel daemons, such as lockd, that need to acquire POSIX | ||
1702 | * locks, the ->lock() interface may return asynchronously, before the lock has | ||
1703 | * been granted or denied by the underlying filesystem, if (and only if) | ||
1704 | * fl_grant is set. Callers expecting ->lock() to return asynchronously | ||
1705 | * will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if) | ||
1706 | * the request is for a blocking lock. When ->lock() does return asynchronously, | ||
1707 | * it must return -EINPROGRESS, and call ->fl_grant() when the lock | ||
1708 | * request completes. | ||
1709 | * If the request is for non-blocking lock the file system should return | ||
1710 | * -EINPROGRESS then try to get the lock and call the callback routine with | ||
1711 | * the result. If the request timed out the callback routine will return a | ||
1712 | * nonzero return code and the file system should release the lock. The file | ||
1713 | * system is also responsible to keep a corresponding posix lock when it | ||
1714 | * grants a lock so the VFS can find out which locks are locally held and do | ||
1715 | * the correct lock cleanup when required. | ||
1716 | * The underlying filesystem must not drop the kernel lock or call | ||
1717 | * ->fl_grant() before returning to the caller with a -EINPROGRESS | ||
1718 | * return code. | ||
1719 | */ | ||
1720 | int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf) | ||
1721 | { | ||
1722 | if (filp->f_op && filp->f_op->lock) | ||
1723 | return filp->f_op->lock(filp, cmd, fl); | ||
1724 | else | ||
1725 | return posix_lock_file(filp, fl, conf); | ||
1726 | } | ||
1727 | EXPORT_SYMBOL_GPL(vfs_lock_file); | ||
1728 | |||
1674 | /* Apply the lock described by l to an open file descriptor. | 1729 | /* Apply the lock described by l to an open file descriptor. |
1675 | * This implements both the F_SETLK and F_SETLKW commands of fcntl(). | 1730 | * This implements both the F_SETLK and F_SETLKW commands of fcntl(). |
1676 | */ | 1731 | */ |
@@ -1733,21 +1788,17 @@ again: | |||
1733 | if (error) | 1788 | if (error) |
1734 | goto out; | 1789 | goto out; |
1735 | 1790 | ||
1736 | if (filp->f_op && filp->f_op->lock != NULL) | 1791 | for (;;) { |
1737 | error = filp->f_op->lock(filp, cmd, file_lock); | 1792 | error = vfs_lock_file(filp, cmd, file_lock, NULL); |
1738 | else { | 1793 | if (error != -EAGAIN || cmd == F_SETLK) |
1739 | for (;;) { | ||
1740 | error = posix_lock_file(filp, file_lock); | ||
1741 | if ((error != -EAGAIN) || (cmd == F_SETLK)) | ||
1742 | break; | ||
1743 | error = wait_event_interruptible(file_lock->fl_wait, | ||
1744 | !file_lock->fl_next); | ||
1745 | if (!error) | ||
1746 | continue; | ||
1747 | |||
1748 | locks_delete_block(file_lock); | ||
1749 | break; | 1794 | break; |
1750 | } | 1795 | error = wait_event_interruptible(file_lock->fl_wait, |
1796 | !file_lock->fl_next); | ||
1797 | if (!error) | ||
1798 | continue; | ||
1799 | |||
1800 | locks_delete_block(file_lock); | ||
1801 | break; | ||
1751 | } | 1802 | } |
1752 | 1803 | ||
1753 | /* | 1804 | /* |
@@ -1770,7 +1821,7 @@ out: | |||
1770 | */ | 1821 | */ |
1771 | int fcntl_getlk64(struct file *filp, struct flock64 __user *l) | 1822 | int fcntl_getlk64(struct file *filp, struct flock64 __user *l) |
1772 | { | 1823 | { |
1773 | struct file_lock *fl, cfl, file_lock; | 1824 | struct file_lock file_lock; |
1774 | struct flock64 flock; | 1825 | struct flock64 flock; |
1775 | int error; | 1826 | int error; |
1776 | 1827 | ||
@@ -1785,27 +1836,14 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l) | |||
1785 | if (error) | 1836 | if (error) |
1786 | goto out; | 1837 | goto out; |
1787 | 1838 | ||
1788 | if (filp->f_op && filp->f_op->lock) { | 1839 | error = vfs_test_lock(filp, &file_lock); |
1789 | error = filp->f_op->lock(filp, F_GETLK, &file_lock); | 1840 | if (error) |
1790 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | 1841 | goto out; |
1791 | file_lock.fl_ops->fl_release_private(&file_lock); | 1842 | |
1792 | if (error < 0) | 1843 | flock.l_type = file_lock.fl_type; |
1793 | goto out; | 1844 | if (file_lock.fl_type != F_UNLCK) |
1794 | else | 1845 | posix_lock_to_flock64(&flock, &file_lock); |
1795 | fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); | 1846 | |
1796 | } else { | ||
1797 | fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL); | ||
1798 | } | ||
1799 | |||
1800 | flock.l_type = F_UNLCK; | ||
1801 | if (fl != NULL) { | ||
1802 | flock.l_pid = fl->fl_pid; | ||
1803 | flock.l_start = fl->fl_start; | ||
1804 | flock.l_len = fl->fl_end == OFFSET_MAX ? 0 : | ||
1805 | fl->fl_end - fl->fl_start + 1; | ||
1806 | flock.l_whence = 0; | ||
1807 | flock.l_type = fl->fl_type; | ||
1808 | } | ||
1809 | error = -EFAULT; | 1847 | error = -EFAULT; |
1810 | if (!copy_to_user(l, &flock, sizeof(flock))) | 1848 | if (!copy_to_user(l, &flock, sizeof(flock))) |
1811 | error = 0; | 1849 | error = 0; |
@@ -1876,21 +1914,17 @@ again: | |||
1876 | if (error) | 1914 | if (error) |
1877 | goto out; | 1915 | goto out; |
1878 | 1916 | ||
1879 | if (filp->f_op && filp->f_op->lock != NULL) | 1917 | for (;;) { |
1880 | error = filp->f_op->lock(filp, cmd, file_lock); | 1918 | error = vfs_lock_file(filp, cmd, file_lock, NULL); |
1881 | else { | 1919 | if (error != -EAGAIN || cmd == F_SETLK64) |
1882 | for (;;) { | ||
1883 | error = posix_lock_file(filp, file_lock); | ||
1884 | if ((error != -EAGAIN) || (cmd == F_SETLK64)) | ||
1885 | break; | ||
1886 | error = wait_event_interruptible(file_lock->fl_wait, | ||
1887 | !file_lock->fl_next); | ||
1888 | if (!error) | ||
1889 | continue; | ||
1890 | |||
1891 | locks_delete_block(file_lock); | ||
1892 | break; | 1920 | break; |
1893 | } | 1921 | error = wait_event_interruptible(file_lock->fl_wait, |
1922 | !file_lock->fl_next); | ||
1923 | if (!error) | ||
1924 | continue; | ||
1925 | |||
1926 | locks_delete_block(file_lock); | ||
1927 | break; | ||
1894 | } | 1928 | } |
1895 | 1929 | ||
1896 | /* | 1930 | /* |
@@ -1935,10 +1969,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner) | |||
1935 | lock.fl_ops = NULL; | 1969 | lock.fl_ops = NULL; |
1936 | lock.fl_lmops = NULL; | 1970 | lock.fl_lmops = NULL; |
1937 | 1971 | ||
1938 | if (filp->f_op && filp->f_op->lock != NULL) | 1972 | vfs_lock_file(filp, F_SETLK, &lock, NULL); |
1939 | filp->f_op->lock(filp, F_SETLK, &lock); | ||
1940 | else | ||
1941 | posix_lock_file(filp, &lock); | ||
1942 | 1973 | ||
1943 | if (lock.fl_ops && lock.fl_ops->fl_release_private) | 1974 | if (lock.fl_ops && lock.fl_ops->fl_release_private) |
1944 | lock.fl_ops->fl_release_private(&lock); | 1975 | lock.fl_ops->fl_release_private(&lock); |
@@ -2015,6 +2046,22 @@ posix_unblock_lock(struct file *filp, struct file_lock *waiter) | |||
2015 | 2046 | ||
2016 | EXPORT_SYMBOL(posix_unblock_lock); | 2047 | EXPORT_SYMBOL(posix_unblock_lock); |
2017 | 2048 | ||
2049 | /** | ||
2050 | * vfs_cancel_lock - file byte range unblock lock | ||
2051 | * @filp: The file to apply the unblock to | ||
2052 | * @fl: The lock to be unblocked | ||
2053 | * | ||
2054 | * Used by lock managers to cancel blocked requests | ||
2055 | */ | ||
2056 | int vfs_cancel_lock(struct file *filp, struct file_lock *fl) | ||
2057 | { | ||
2058 | if (filp->f_op && filp->f_op->lock) | ||
2059 | return filp->f_op->lock(filp, F_CANCELLK, fl); | ||
2060 | return 0; | ||
2061 | } | ||
2062 | |||
2063 | EXPORT_SYMBOL_GPL(vfs_cancel_lock); | ||
2064 | |||
2018 | static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) | 2065 | static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) |
2019 | { | 2066 | { |
2020 | struct inode *inode = NULL; | 2067 | struct inode *inode = NULL; |