diff options
Diffstat (limited to 'fs/locks.c')
| -rw-r--r-- | fs/locks.c | 123 |
1 files changed, 32 insertions, 91 deletions
diff --git a/fs/locks.c b/fs/locks.c index ab61a8b54829..1ad29c9b6252 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -703,7 +703,7 @@ EXPORT_SYMBOL(posix_test_lock); | |||
| 703 | * from a broken NFS client. But broken NFS clients have a lot more to | 703 | * from a broken NFS client. But broken NFS clients have a lot more to |
| 704 | * worry about than proper deadlock detection anyway... --okir | 704 | * worry about than proper deadlock detection anyway... --okir |
| 705 | */ | 705 | */ |
| 706 | int posix_locks_deadlock(struct file_lock *caller_fl, | 706 | static int posix_locks_deadlock(struct file_lock *caller_fl, |
| 707 | struct file_lock *block_fl) | 707 | struct file_lock *block_fl) |
| 708 | { | 708 | { |
| 709 | struct list_head *tmp; | 709 | struct list_head *tmp; |
| @@ -722,8 +722,6 @@ next_task: | |||
| 722 | return 0; | 722 | return 0; |
| 723 | } | 723 | } |
| 724 | 724 | ||
| 725 | EXPORT_SYMBOL(posix_locks_deadlock); | ||
| 726 | |||
| 727 | /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks | 725 | /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks |
| 728 | * at the head of the list, but that's secret knowledge known only to | 726 | * at the head of the list, but that's secret knowledge known only to |
| 729 | * flock_lock_file and posix_lock_file. | 727 | * flock_lock_file and posix_lock_file. |
| @@ -794,7 +792,8 @@ out: | |||
| 794 | static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock) | 792 | static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock) |
| 795 | { | 793 | { |
| 796 | struct file_lock *fl; | 794 | struct file_lock *fl; |
| 797 | struct file_lock *new_fl, *new_fl2; | 795 | struct file_lock *new_fl = NULL; |
| 796 | struct file_lock *new_fl2 = NULL; | ||
| 798 | struct file_lock *left = NULL; | 797 | struct file_lock *left = NULL; |
| 799 | struct file_lock *right = NULL; | 798 | struct file_lock *right = NULL; |
| 800 | struct file_lock **before; | 799 | struct file_lock **before; |
| @@ -803,9 +802,15 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request | |||
| 803 | /* | 802 | /* |
| 804 | * We may need two file_lock structures for this operation, | 803 | * We may need two file_lock structures for this operation, |
| 805 | * so we get them in advance to avoid races. | 804 | * so we get them in advance to avoid races. |
| 805 | * | ||
| 806 | * In some cases we can be sure, that no new locks will be needed | ||
| 806 | */ | 807 | */ |
| 807 | new_fl = locks_alloc_lock(); | 808 | if (!(request->fl_flags & FL_ACCESS) && |
| 808 | new_fl2 = locks_alloc_lock(); | 809 | (request->fl_type != F_UNLCK || |
| 810 | request->fl_start != 0 || request->fl_end != OFFSET_MAX)) { | ||
| 811 | new_fl = locks_alloc_lock(); | ||
| 812 | new_fl2 = locks_alloc_lock(); | ||
| 813 | } | ||
| 809 | 814 | ||
| 810 | lock_kernel(); | 815 | lock_kernel(); |
| 811 | if (request->fl_type != F_UNLCK) { | 816 | if (request->fl_type != F_UNLCK) { |
| @@ -834,14 +839,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request | |||
| 834 | if (request->fl_flags & FL_ACCESS) | 839 | if (request->fl_flags & FL_ACCESS) |
| 835 | goto out; | 840 | goto out; |
| 836 | 841 | ||
| 837 | error = -ENOLCK; /* "no luck" */ | ||
| 838 | if (!(new_fl && new_fl2)) | ||
| 839 | goto out; | ||
| 840 | |||
| 841 | /* | 842 | /* |
| 842 | * We've allocated the new locks in advance, so there are no | ||
| 843 | * errors possible (and no blocking operations) from here on. | ||
| 844 | * | ||
| 845 | * Find the first old lock with the same owner as the new lock. | 843 | * Find the first old lock with the same owner as the new lock. |
| 846 | */ | 844 | */ |
| 847 | 845 | ||
| @@ -938,10 +936,25 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request | |||
| 938 | before = &fl->fl_next; | 936 | before = &fl->fl_next; |
| 939 | } | 937 | } |
| 940 | 938 | ||
| 939 | /* | ||
| 940 | * The above code only modifies existing locks in case of | ||
| 941 | * merging or replacing. If new lock(s) need to be inserted | ||
| 942 | * all modifications are done bellow this, so it's safe yet to | ||
| 943 | * bail out. | ||
| 944 | */ | ||
| 945 | error = -ENOLCK; /* "no luck" */ | ||
| 946 | if (right && left == right && !new_fl2) | ||
| 947 | goto out; | ||
| 948 | |||
| 941 | error = 0; | 949 | error = 0; |
| 942 | if (!added) { | 950 | if (!added) { |
| 943 | if (request->fl_type == F_UNLCK) | 951 | if (request->fl_type == F_UNLCK) |
| 944 | goto out; | 952 | goto out; |
| 953 | |||
| 954 | if (!new_fl) { | ||
| 955 | error = -ENOLCK; | ||
| 956 | goto out; | ||
| 957 | } | ||
| 945 | locks_copy_lock(new_fl, request); | 958 | locks_copy_lock(new_fl, request); |
| 946 | locks_insert_lock(before, new_fl); | 959 | locks_insert_lock(before, new_fl); |
| 947 | new_fl = NULL; | 960 | new_fl = NULL; |
| @@ -1881,19 +1894,18 @@ out: | |||
| 1881 | */ | 1894 | */ |
| 1882 | void locks_remove_posix(struct file *filp, fl_owner_t owner) | 1895 | void locks_remove_posix(struct file *filp, fl_owner_t owner) |
| 1883 | { | 1896 | { |
| 1884 | struct file_lock lock, **before; | 1897 | struct file_lock lock; |
| 1885 | 1898 | ||
| 1886 | /* | 1899 | /* |
| 1887 | * If there are no locks held on this file, we don't need to call | 1900 | * If there are no locks held on this file, we don't need to call |
| 1888 | * posix_lock_file(). Another process could be setting a lock on this | 1901 | * posix_lock_file(). Another process could be setting a lock on this |
| 1889 | * file at the same time, but we wouldn't remove that lock anyway. | 1902 | * file at the same time, but we wouldn't remove that lock anyway. |
| 1890 | */ | 1903 | */ |
| 1891 | before = &filp->f_dentry->d_inode->i_flock; | 1904 | if (!filp->f_dentry->d_inode->i_flock) |
| 1892 | if (*before == NULL) | ||
| 1893 | return; | 1905 | return; |
| 1894 | 1906 | ||
| 1895 | lock.fl_type = F_UNLCK; | 1907 | lock.fl_type = F_UNLCK; |
| 1896 | lock.fl_flags = FL_POSIX; | 1908 | lock.fl_flags = FL_POSIX | FL_CLOSE; |
| 1897 | lock.fl_start = 0; | 1909 | lock.fl_start = 0; |
| 1898 | lock.fl_end = OFFSET_MAX; | 1910 | lock.fl_end = OFFSET_MAX; |
| 1899 | lock.fl_owner = owner; | 1911 | lock.fl_owner = owner; |
| @@ -1902,25 +1914,11 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner) | |||
| 1902 | lock.fl_ops = NULL; | 1914 | lock.fl_ops = NULL; |
| 1903 | lock.fl_lmops = NULL; | 1915 | lock.fl_lmops = NULL; |
| 1904 | 1916 | ||
| 1905 | if (filp->f_op && filp->f_op->lock != NULL) { | 1917 | if (filp->f_op && filp->f_op->lock != NULL) |
| 1906 | filp->f_op->lock(filp, F_SETLK, &lock); | 1918 | filp->f_op->lock(filp, F_SETLK, &lock); |
| 1907 | goto out; | 1919 | else |
| 1908 | } | 1920 | posix_lock_file(filp, &lock); |
| 1909 | 1921 | ||
| 1910 | /* Can't use posix_lock_file here; we need to remove it no matter | ||
| 1911 | * which pid we have. | ||
| 1912 | */ | ||
| 1913 | lock_kernel(); | ||
| 1914 | while (*before != NULL) { | ||
| 1915 | struct file_lock *fl = *before; | ||
| 1916 | if (IS_POSIX(fl) && posix_same_owner(fl, &lock)) { | ||
| 1917 | locks_delete_lock(before); | ||
| 1918 | continue; | ||
| 1919 | } | ||
| 1920 | before = &fl->fl_next; | ||
| 1921 | } | ||
| 1922 | unlock_kernel(); | ||
| 1923 | out: | ||
| 1924 | if (lock.fl_ops && lock.fl_ops->fl_release_private) | 1922 | if (lock.fl_ops && lock.fl_ops->fl_release_private) |
| 1925 | lock.fl_ops->fl_release_private(&lock); | 1923 | lock.fl_ops->fl_release_private(&lock); |
| 1926 | } | 1924 | } |
| @@ -2206,63 +2204,6 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len) | |||
| 2206 | 2204 | ||
| 2207 | EXPORT_SYMBOL(lock_may_write); | 2205 | EXPORT_SYMBOL(lock_may_write); |
| 2208 | 2206 | ||
| 2209 | static inline void __steal_locks(struct file *file, fl_owner_t from) | ||
| 2210 | { | ||
| 2211 | struct inode *inode = file->f_dentry->d_inode; | ||
| 2212 | struct file_lock *fl = inode->i_flock; | ||
| 2213 | |||
| 2214 | while (fl) { | ||
| 2215 | if (fl->fl_file == file && fl->fl_owner == from) | ||
| 2216 | fl->fl_owner = current->files; | ||
| 2217 | fl = fl->fl_next; | ||
| 2218 | } | ||
| 2219 | } | ||
| 2220 | |||
| 2221 | /* When getting ready for executing a binary, we make sure that current | ||
| 2222 | * has a files_struct on its own. Before dropping the old files_struct, | ||
| 2223 | * we take over ownership of all locks for all file descriptors we own. | ||
| 2224 | * Note that we may accidentally steal a lock for a file that a sibling | ||
| 2225 | * has created since the unshare_files() call. | ||
| 2226 | */ | ||
| 2227 | void steal_locks(fl_owner_t from) | ||
| 2228 | { | ||
| 2229 | struct files_struct *files = current->files; | ||
| 2230 | int i, j; | ||
| 2231 | struct fdtable *fdt; | ||
| 2232 | |||
| 2233 | if (from == files) | ||
| 2234 | return; | ||
| 2235 | |||
| 2236 | lock_kernel(); | ||
| 2237 | j = 0; | ||
| 2238 | |||
| 2239 | /* | ||
| 2240 | * We are not taking a ref to the file structures, so | ||
| 2241 | * we need to acquire ->file_lock. | ||
| 2242 | */ | ||
| 2243 | spin_lock(&files->file_lock); | ||
| 2244 | fdt = files_fdtable(files); | ||
| 2245 | for (;;) { | ||
| 2246 | unsigned long set; | ||
| 2247 | i = j * __NFDBITS; | ||
| 2248 | if (i >= fdt->max_fdset || i >= fdt->max_fds) | ||
| 2249 | break; | ||
| 2250 | set = fdt->open_fds->fds_bits[j++]; | ||
| 2251 | while (set) { | ||
| 2252 | if (set & 1) { | ||
| 2253 | struct file *file = fdt->fd[i]; | ||
| 2254 | if (file) | ||
| 2255 | __steal_locks(file, from); | ||
| 2256 | } | ||
| 2257 | i++; | ||
| 2258 | set >>= 1; | ||
| 2259 | } | ||
| 2260 | } | ||
| 2261 | spin_unlock(&files->file_lock); | ||
| 2262 | unlock_kernel(); | ||
| 2263 | } | ||
| 2264 | EXPORT_SYMBOL(steal_locks); | ||
| 2265 | |||
| 2266 | static int __init filelock_init(void) | 2207 | static int __init filelock_init(void) |
| 2267 | { | 2208 | { |
| 2268 | filelock_cache = kmem_cache_create("file_lock_cache", | 2209 | filelock_cache = kmem_cache_create("file_lock_cache", |
