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", |