diff options
Diffstat (limited to 'fs/locks.c')
| -rw-r--r-- | fs/locks.c | 81 |
1 files changed, 48 insertions, 33 deletions
diff --git a/fs/locks.c b/fs/locks.c index 29fa5da6c117..11956b6179ff 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -1591,7 +1591,8 @@ out: | |||
| 1591 | /* Apply the lock described by l to an open file descriptor. | 1591 | /* Apply the lock described by l to an open file descriptor. |
| 1592 | * 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(). |
| 1593 | */ | 1593 | */ |
| 1594 | 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) | ||
| 1595 | { | 1596 | { |
| 1596 | struct file_lock *file_lock = locks_alloc_lock(); | 1597 | struct file_lock *file_lock = locks_alloc_lock(); |
| 1597 | struct flock flock; | 1598 | struct flock flock; |
| @@ -1620,6 +1621,7 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l) | |||
| 1620 | goto out; | 1621 | goto out; |
| 1621 | } | 1622 | } |
| 1622 | 1623 | ||
| 1624 | again: | ||
| 1623 | error = flock_to_posix_lock(filp, file_lock, &flock); | 1625 | error = flock_to_posix_lock(filp, file_lock, &flock); |
| 1624 | if (error) | 1626 | if (error) |
| 1625 | goto out; | 1627 | goto out; |
| @@ -1648,25 +1650,33 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l) | |||
| 1648 | if (error) | 1650 | if (error) |
| 1649 | goto out; | 1651 | goto out; |
| 1650 | 1652 | ||
| 1651 | if (filp->f_op && filp->f_op->lock != NULL) { | 1653 | if (filp->f_op && filp->f_op->lock != NULL) |
| 1652 | error = filp->f_op->lock(filp, cmd, file_lock); | 1654 | error = filp->f_op->lock(filp, cmd, file_lock); |
| 1653 | goto out; | 1655 | else { |
| 1654 | } | 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; | ||
| 1655 | 1664 | ||
| 1656 | for (;;) { | 1665 | locks_delete_block(file_lock); |
| 1657 | error = __posix_lock_file(inode, file_lock); | ||
| 1658 | if ((error != -EAGAIN) || (cmd == F_SETLK)) | ||
| 1659 | break; | 1666 | break; |
| 1660 | error = wait_event_interruptible(file_lock->fl_wait, | 1667 | } |
| 1661 | !file_lock->fl_next); | 1668 | } |
| 1662 | if (!error) | ||
| 1663 | continue; | ||
| 1664 | 1669 | ||
| 1665 | locks_delete_block(file_lock); | 1670 | /* |
| 1666 | 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; | ||
| 1667 | } | 1677 | } |
| 1668 | 1678 | ||
| 1669 | out: | 1679 | out: |
| 1670 | locks_free_lock(file_lock); | 1680 | locks_free_lock(file_lock); |
| 1671 | return error; | 1681 | return error; |
| 1672 | } | 1682 | } |
| @@ -1724,7 +1734,8 @@ out: | |||
| 1724 | /* Apply the lock described by l to an open file descriptor. | 1734 | /* Apply the lock described by l to an open file descriptor. |
| 1725 | * 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(). |
| 1726 | */ | 1736 | */ |
| 1727 | 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) | ||
| 1728 | { | 1739 | { |
| 1729 | struct file_lock *file_lock = locks_alloc_lock(); | 1740 | struct file_lock *file_lock = locks_alloc_lock(); |
| 1730 | struct flock64 flock; | 1741 | struct flock64 flock; |
| @@ -1753,6 +1764,7 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) | |||
| 1753 | goto out; | 1764 | goto out; |
| 1754 | } | 1765 | } |
| 1755 | 1766 | ||
| 1767 | again: | ||
| 1756 | error = flock64_to_posix_lock(filp, file_lock, &flock); | 1768 | error = flock64_to_posix_lock(filp, file_lock, &flock); |
| 1757 | if (error) | 1769 | if (error) |
| 1758 | goto out; | 1770 | goto out; |
| @@ -1781,22 +1793,30 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) | |||
| 1781 | if (error) | 1793 | if (error) |
| 1782 | goto out; | 1794 | goto out; |
| 1783 | 1795 | ||
| 1784 | if (filp->f_op && filp->f_op->lock != NULL) { | 1796 | if (filp->f_op && filp->f_op->lock != NULL) |
| 1785 | error = filp->f_op->lock(filp, cmd, file_lock); | 1797 | error = filp->f_op->lock(filp, cmd, file_lock); |
| 1786 | goto out; | 1798 | else { |
| 1787 | } | 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; | ||
| 1788 | 1807 | ||
| 1789 | for (;;) { | 1808 | locks_delete_block(file_lock); |
| 1790 | error = __posix_lock_file(inode, file_lock); | ||
| 1791 | if ((error != -EAGAIN) || (cmd == F_SETLK64)) | ||
| 1792 | break; | 1809 | break; |
| 1793 | error = wait_event_interruptible(file_lock->fl_wait, | 1810 | } |
| 1794 | !file_lock->fl_next); | 1811 | } |
| 1795 | if (!error) | ||
| 1796 | continue; | ||
| 1797 | 1812 | ||
| 1798 | locks_delete_block(file_lock); | 1813 | /* |
| 1799 | 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; | ||
| 1800 | } | 1820 | } |
| 1801 | 1821 | ||
| 1802 | out: | 1822 | out: |
| @@ -1888,12 +1908,7 @@ void locks_remove_flock(struct file *filp) | |||
| 1888 | 1908 | ||
| 1889 | while ((fl = *before) != NULL) { | 1909 | while ((fl = *before) != NULL) { |
| 1890 | if (fl->fl_file == filp) { | 1910 | if (fl->fl_file == filp) { |
| 1891 | /* | 1911 | if (IS_FLOCK(fl)) { |
| 1892 | * We might have a POSIX lock that was created at the same time | ||
| 1893 | * the filp was closed for the last time. Just remove that too, | ||
| 1894 | * regardless of ownership, since nobody can own it. | ||
| 1895 | */ | ||
| 1896 | if (IS_FLOCK(fl) || IS_POSIX(fl)) { | ||
| 1897 | locks_delete_lock(before); | 1912 | locks_delete_lock(before); |
| 1898 | continue; | 1913 | continue; |
| 1899 | } | 1914 | } |
