aboutsummaryrefslogtreecommitdiffstats
path: root/fs/locks.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/locks.c')
-rw-r--r--fs/locks.c267
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
668int 667int
669posix_test_lock(struct file *filp, struct file_lock *fl, 668posix_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
804static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock) 803static 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 */
1019int posix_lock_file(struct file *filp, struct file_lock *fl) 1019int 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}
1023EXPORT_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 */
1033int 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}
1038EXPORT_SYMBOL(posix_lock_file_conf); 1024EXPORT_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 */
1609int 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}
1616EXPORT_SYMBOL_GPL(vfs_test_lock);
1617
1618static 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
1639static 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 */
1617int fcntl_getlk(struct file *filp, struct flock __user *l) 1653int 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 */
1720int 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}
1727EXPORT_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 */
1771int fcntl_getlk64(struct file *filp, struct flock64 __user *l) 1822int 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
2016EXPORT_SYMBOL(posix_unblock_lock); 2047EXPORT_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 */
2056int 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
2063EXPORT_SYMBOL_GPL(vfs_cancel_lock);
2064
2018static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) 2065static 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;