diff options
Diffstat (limited to 'fs/locks.c')
| -rw-r--r-- | fs/locks.c | 93 |
1 files changed, 56 insertions, 37 deletions
diff --git a/fs/locks.c b/fs/locks.c index a0bc03495bd4..c2c09b4798d6 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -1276,7 +1276,7 @@ int fcntl_getlease(struct file *filp) | |||
| 1276 | */ | 1276 | */ |
| 1277 | static int __setlease(struct file *filp, long arg, struct file_lock **flp) | 1277 | static int __setlease(struct file *filp, long arg, struct file_lock **flp) |
| 1278 | { | 1278 | { |
| 1279 | struct file_lock *fl, **before, **my_before = NULL, *lease = *flp; | 1279 | struct file_lock *fl, **before, **my_before = NULL, *lease; |
| 1280 | struct dentry *dentry = filp->f_dentry; | 1280 | struct dentry *dentry = filp->f_dentry; |
| 1281 | struct inode *inode = dentry->d_inode; | 1281 | struct inode *inode = dentry->d_inode; |
| 1282 | int error, rdlease_count = 0, wrlease_count = 0; | 1282 | int error, rdlease_count = 0, wrlease_count = 0; |
| @@ -1287,6 +1287,8 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp) | |||
| 1287 | if (!flp || !(*flp) || !(*flp)->fl_lmops || !(*flp)->fl_lmops->fl_break) | 1287 | if (!flp || !(*flp) || !(*flp)->fl_lmops || !(*flp)->fl_lmops->fl_break) |
| 1288 | goto out; | 1288 | goto out; |
| 1289 | 1289 | ||
| 1290 | lease = *flp; | ||
| 1291 | |||
| 1290 | error = -EAGAIN; | 1292 | error = -EAGAIN; |
| 1291 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) | 1293 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) |
| 1292 | goto out; | 1294 | goto out; |
| @@ -1589,7 +1591,8 @@ out: | |||
| 1589 | /* Apply the lock described by l to an open file descriptor. | 1591 | /* Apply the lock described by l to an open file descriptor. |
| 1590 | * This implements both the F_SETLK and F_SETLKW commands of fcntl(). | 1592 | * This implements both the F_SETLK and F_SETLKW commands of fcntl(). |
| 1591 | */ | 1593 | */ |
| 1592 | int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l) | 1594 | int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, |
| 1595 | struct flock __user *l) | ||
| 1593 | { | 1596 | { |
| 1594 | struct file_lock *file_lock = locks_alloc_lock(); | 1597 | struct file_lock *file_lock = locks_alloc_lock(); |
| 1595 | struct flock flock; | 1598 | struct flock flock; |
| @@ -1618,6 +1621,7 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l) | |||
| 1618 | goto out; | 1621 | goto out; |
| 1619 | } | 1622 | } |
| 1620 | 1623 | ||
| 1624 | again: | ||
| 1621 | error = flock_to_posix_lock(filp, file_lock, &flock); | 1625 | error = flock_to_posix_lock(filp, file_lock, &flock); |
| 1622 | if (error) | 1626 | if (error) |
| 1623 | goto out; | 1627 | goto out; |
| @@ -1646,25 +1650,33 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l) | |||
| 1646 | if (error) | 1650 | if (error) |
| 1647 | goto out; | 1651 | goto out; |
| 1648 | 1652 | ||
| 1649 | if (filp->f_op && filp->f_op->lock != NULL) { | 1653 | if (filp->f_op && filp->f_op->lock != NULL) |
| 1650 | error = filp->f_op->lock(filp, cmd, file_lock); | 1654 | error = filp->f_op->lock(filp, cmd, file_lock); |
| 1651 | goto out; | 1655 | else { |
| 1652 | } | 1656 | for (;;) { |
| 1657 | error = __posix_lock_file(inode, file_lock); | ||
| 1658 | if ((error != -EAGAIN) || (cmd == F_SETLK)) | ||
| 1659 | break; | ||
| 1660 | error = wait_event_interruptible(file_lock->fl_wait, | ||
| 1661 | !file_lock->fl_next); | ||
| 1662 | if (!error) | ||
| 1663 | continue; | ||
| 1653 | 1664 | ||
| 1654 | for (;;) { | 1665 | locks_delete_block(file_lock); |
| 1655 | error = __posix_lock_file(inode, file_lock); | ||
| 1656 | if ((error != -EAGAIN) || (cmd == F_SETLK)) | ||
| 1657 | break; | 1666 | break; |
| 1658 | error = wait_event_interruptible(file_lock->fl_wait, | 1667 | } |
| 1659 | !file_lock->fl_next); | 1668 | } |
| 1660 | if (!error) | ||
| 1661 | continue; | ||
| 1662 | 1669 | ||
| 1663 | locks_delete_block(file_lock); | 1670 | /* |
| 1664 | break; | 1671 | * Attempt to detect a close/fcntl race and recover by |
| 1672 | * releasing the lock that was just acquired. | ||
| 1673 | */ | ||
| 1674 | if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) { | ||
| 1675 | flock.l_type = F_UNLCK; | ||
| 1676 | goto again; | ||
| 1665 | } | 1677 | } |
| 1666 | 1678 | ||
| 1667 | out: | 1679 | out: |
| 1668 | locks_free_lock(file_lock); | 1680 | locks_free_lock(file_lock); |
| 1669 | return error; | 1681 | return error; |
| 1670 | } | 1682 | } |
| @@ -1722,7 +1734,8 @@ out: | |||
| 1722 | /* Apply the lock described by l to an open file descriptor. | 1734 | /* Apply the lock described by l to an open file descriptor. |
| 1723 | * This implements both the F_SETLK and F_SETLKW commands of fcntl(). | 1735 | * This implements both the F_SETLK and F_SETLKW commands of fcntl(). |
| 1724 | */ | 1736 | */ |
| 1725 | int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) | 1737 | int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, |
| 1738 | struct flock64 __user *l) | ||
| 1726 | { | 1739 | { |
| 1727 | struct file_lock *file_lock = locks_alloc_lock(); | 1740 | struct file_lock *file_lock = locks_alloc_lock(); |
| 1728 | struct flock64 flock; | 1741 | struct flock64 flock; |
| @@ -1751,6 +1764,7 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) | |||
| 1751 | goto out; | 1764 | goto out; |
| 1752 | } | 1765 | } |
| 1753 | 1766 | ||
| 1767 | again: | ||
| 1754 | error = flock64_to_posix_lock(filp, file_lock, &flock); | 1768 | error = flock64_to_posix_lock(filp, file_lock, &flock); |
| 1755 | if (error) | 1769 | if (error) |
| 1756 | goto out; | 1770 | goto out; |
| @@ -1779,22 +1793,30 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) | |||
| 1779 | if (error) | 1793 | if (error) |
| 1780 | goto out; | 1794 | goto out; |
| 1781 | 1795 | ||
| 1782 | if (filp->f_op && filp->f_op->lock != NULL) { | 1796 | if (filp->f_op && filp->f_op->lock != NULL) |
| 1783 | error = filp->f_op->lock(filp, cmd, file_lock); | 1797 | error = filp->f_op->lock(filp, cmd, file_lock); |
| 1784 | goto out; | 1798 | else { |
| 1785 | } | 1799 | for (;;) { |
| 1800 | error = __posix_lock_file(inode, file_lock); | ||
| 1801 | if ((error != -EAGAIN) || (cmd == F_SETLK64)) | ||
| 1802 | break; | ||
| 1803 | error = wait_event_interruptible(file_lock->fl_wait, | ||
| 1804 | !file_lock->fl_next); | ||
| 1805 | if (!error) | ||
| 1806 | continue; | ||
| 1786 | 1807 | ||
| 1787 | for (;;) { | 1808 | locks_delete_block(file_lock); |
| 1788 | error = __posix_lock_file(inode, file_lock); | ||
| 1789 | if ((error != -EAGAIN) || (cmd == F_SETLK64)) | ||
| 1790 | break; | 1809 | break; |
| 1791 | error = wait_event_interruptible(file_lock->fl_wait, | 1810 | } |
| 1792 | !file_lock->fl_next); | 1811 | } |
| 1793 | if (!error) | ||
| 1794 | continue; | ||
| 1795 | 1812 | ||
| 1796 | locks_delete_block(file_lock); | 1813 | /* |
| 1797 | break; | 1814 | * Attempt to detect a close/fcntl race and recover by |
| 1815 | * releasing the lock that was just acquired. | ||
| 1816 | */ | ||
| 1817 | if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) { | ||
| 1818 | flock.l_type = F_UNLCK; | ||
| 1819 | goto again; | ||
| 1798 | } | 1820 | } |
| 1799 | 1821 | ||
| 1800 | out: | 1822 | out: |
| @@ -1886,12 +1908,7 @@ void locks_remove_flock(struct file *filp) | |||
| 1886 | 1908 | ||
| 1887 | while ((fl = *before) != NULL) { | 1909 | while ((fl = *before) != NULL) { |
| 1888 | if (fl->fl_file == filp) { | 1910 | if (fl->fl_file == filp) { |
| 1889 | /* | 1911 | if (IS_FLOCK(fl)) { |
| 1890 | * We might have a POSIX lock that was created at the same time | ||
| 1891 | * the filp was closed for the last time. Just remove that too, | ||
| 1892 | * regardless of ownership, since nobody can own it. | ||
| 1893 | */ | ||
| 1894 | if (IS_FLOCK(fl) || IS_POSIX(fl)) { | ||
| 1895 | locks_delete_lock(before); | 1912 | locks_delete_lock(before); |
| 1896 | continue; | 1913 | continue; |
| 1897 | } | 1914 | } |
| @@ -2181,21 +2198,23 @@ void steal_locks(fl_owner_t from) | |||
| 2181 | { | 2198 | { |
| 2182 | struct files_struct *files = current->files; | 2199 | struct files_struct *files = current->files; |
| 2183 | int i, j; | 2200 | int i, j; |
| 2201 | struct fdtable *fdt; | ||
| 2184 | 2202 | ||
| 2185 | if (from == files) | 2203 | if (from == files) |
| 2186 | return; | 2204 | return; |
| 2187 | 2205 | ||
| 2188 | lock_kernel(); | 2206 | lock_kernel(); |
| 2189 | j = 0; | 2207 | j = 0; |
| 2208 | fdt = files_fdtable(files); | ||
| 2190 | for (;;) { | 2209 | for (;;) { |
| 2191 | unsigned long set; | 2210 | unsigned long set; |
| 2192 | i = j * __NFDBITS; | 2211 | i = j * __NFDBITS; |
| 2193 | if (i >= files->max_fdset || i >= files->max_fds) | 2212 | if (i >= fdt->max_fdset || i >= fdt->max_fds) |
| 2194 | break; | 2213 | break; |
| 2195 | set = files->open_fds->fds_bits[j++]; | 2214 | set = fdt->open_fds->fds_bits[j++]; |
| 2196 | while (set) { | 2215 | while (set) { |
| 2197 | if (set & 1) { | 2216 | if (set & 1) { |
| 2198 | struct file *file = files->fd[i]; | 2217 | struct file *file = fdt->fd[i]; |
| 2199 | if (file) | 2218 | if (file) |
| 2200 | __steal_locks(file, from); | 2219 | __steal_locks(file, from); |
| 2201 | } | 2220 | } |
