diff options
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 192 |
1 files changed, 86 insertions, 106 deletions
diff --git a/fs/locks.c b/fs/locks.c index c795eaaf6c4c..7f9a3ea47418 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -534,7 +534,9 @@ static void locks_insert_block(struct file_lock *blocker, | |||
534 | static void locks_wake_up_blocks(struct file_lock *blocker) | 534 | static void locks_wake_up_blocks(struct file_lock *blocker) |
535 | { | 535 | { |
536 | while (!list_empty(&blocker->fl_block)) { | 536 | while (!list_empty(&blocker->fl_block)) { |
537 | struct file_lock *waiter = list_entry(blocker->fl_block.next, | 537 | struct file_lock *waiter; |
538 | |||
539 | waiter = list_first_entry(&blocker->fl_block, | ||
538 | struct file_lock, fl_block); | 540 | struct file_lock, fl_block); |
539 | __locks_delete_block(waiter); | 541 | __locks_delete_block(waiter); |
540 | if (waiter->fl_lmops && waiter->fl_lmops->fl_notify) | 542 | if (waiter->fl_lmops && waiter->fl_lmops->fl_notify) |
@@ -668,7 +670,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl) | |||
668 | for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { | 670 | for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { |
669 | if (!IS_POSIX(cfl)) | 671 | if (!IS_POSIX(cfl)) |
670 | continue; | 672 | continue; |
671 | if (posix_locks_conflict(cfl, fl)) | 673 | if (posix_locks_conflict(fl, cfl)) |
672 | break; | 674 | break; |
673 | } | 675 | } |
674 | if (cfl) | 676 | if (cfl) |
@@ -698,13 +700,12 @@ EXPORT_SYMBOL(posix_test_lock); | |||
698 | static int posix_locks_deadlock(struct file_lock *caller_fl, | 700 | static int posix_locks_deadlock(struct file_lock *caller_fl, |
699 | struct file_lock *block_fl) | 701 | struct file_lock *block_fl) |
700 | { | 702 | { |
701 | struct list_head *tmp; | 703 | struct file_lock *fl; |
702 | 704 | ||
703 | next_task: | 705 | next_task: |
704 | if (posix_same_owner(caller_fl, block_fl)) | 706 | if (posix_same_owner(caller_fl, block_fl)) |
705 | return 1; | 707 | return 1; |
706 | list_for_each(tmp, &blocked_list) { | 708 | list_for_each_entry(fl, &blocked_list, fl_link) { |
707 | struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); | ||
708 | if (posix_same_owner(fl, block_fl)) { | 709 | if (posix_same_owner(fl, block_fl)) { |
709 | fl = fl->fl_next; | 710 | fl = fl->fl_next; |
710 | block_fl = fl; | 711 | block_fl = fl; |
@@ -715,8 +716,7 @@ next_task: | |||
715 | } | 716 | } |
716 | 717 | ||
717 | /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks | 718 | /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks |
718 | * at the head of the list, but that's secret knowledge known only to | 719 | * after any leases, but before any posix locks. |
719 | * flock_lock_file and posix_lock_file. | ||
720 | * | 720 | * |
721 | * Note that if called with an FL_EXISTS argument, the caller may determine | 721 | * Note that if called with an FL_EXISTS argument, the caller may determine |
722 | * whether or not a lock was successfully freed by testing the return | 722 | * whether or not a lock was successfully freed by testing the return |
@@ -733,6 +733,15 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) | |||
733 | lock_kernel(); | 733 | lock_kernel(); |
734 | if (request->fl_flags & FL_ACCESS) | 734 | if (request->fl_flags & FL_ACCESS) |
735 | goto find_conflict; | 735 | goto find_conflict; |
736 | |||
737 | if (request->fl_type != F_UNLCK) { | ||
738 | error = -ENOMEM; | ||
739 | new_fl = locks_alloc_lock(); | ||
740 | if (new_fl == NULL) | ||
741 | goto out; | ||
742 | error = 0; | ||
743 | } | ||
744 | |||
736 | for_each_lock(inode, before) { | 745 | for_each_lock(inode, before) { |
737 | struct file_lock *fl = *before; | 746 | struct file_lock *fl = *before; |
738 | if (IS_POSIX(fl)) | 747 | if (IS_POSIX(fl)) |
@@ -754,10 +763,6 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) | |||
754 | goto out; | 763 | goto out; |
755 | } | 764 | } |
756 | 765 | ||
757 | error = -ENOMEM; | ||
758 | new_fl = locks_alloc_lock(); | ||
759 | if (new_fl == NULL) | ||
760 | goto out; | ||
761 | /* | 766 | /* |
762 | * If a higher-priority process was blocked on the old file lock, | 767 | * If a higher-priority process was blocked on the old file lock, |
763 | * give it the opportunity to lock the file. | 768 | * give it the opportunity to lock the file. |
@@ -819,7 +824,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
819 | lock_kernel(); | 824 | lock_kernel(); |
820 | if (request->fl_type != F_UNLCK) { | 825 | if (request->fl_type != F_UNLCK) { |
821 | for_each_lock(inode, before) { | 826 | for_each_lock(inode, before) { |
822 | struct file_lock *fl = *before; | 827 | fl = *before; |
823 | if (!IS_POSIX(fl)) | 828 | if (!IS_POSIX(fl)) |
824 | continue; | 829 | continue; |
825 | if (!posix_locks_conflict(request, fl)) | 830 | if (!posix_locks_conflict(request, fl)) |
@@ -1113,7 +1118,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, | |||
1113 | * If we've been sleeping someone might have | 1118 | * If we've been sleeping someone might have |
1114 | * changed the permissions behind our back. | 1119 | * changed the permissions behind our back. |
1115 | */ | 1120 | */ |
1116 | if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) | 1121 | if (__mandatory_lock(inode)) |
1117 | continue; | 1122 | continue; |
1118 | } | 1123 | } |
1119 | 1124 | ||
@@ -1337,6 +1342,7 @@ int fcntl_getlease(struct file *filp) | |||
1337 | int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | 1342 | int generic_setlease(struct file *filp, long arg, struct file_lock **flp) |
1338 | { | 1343 | { |
1339 | struct file_lock *fl, **before, **my_before = NULL, *lease; | 1344 | struct file_lock *fl, **before, **my_before = NULL, *lease; |
1345 | struct file_lock *new_fl = NULL; | ||
1340 | struct dentry *dentry = filp->f_path.dentry; | 1346 | struct dentry *dentry = filp->f_path.dentry; |
1341 | struct inode *inode = dentry->d_inode; | 1347 | struct inode *inode = dentry->d_inode; |
1342 | int error, rdlease_count = 0, wrlease_count = 0; | 1348 | int error, rdlease_count = 0, wrlease_count = 0; |
@@ -1363,6 +1369,11 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1363 | || (atomic_read(&inode->i_count) > 1))) | 1369 | || (atomic_read(&inode->i_count) > 1))) |
1364 | goto out; | 1370 | goto out; |
1365 | 1371 | ||
1372 | error = -ENOMEM; | ||
1373 | new_fl = locks_alloc_lock(); | ||
1374 | if (new_fl == NULL) | ||
1375 | goto out; | ||
1376 | |||
1366 | /* | 1377 | /* |
1367 | * At this point, we know that if there is an exclusive | 1378 | * At this point, we know that if there is an exclusive |
1368 | * lease on this file, then we hold it on this filp | 1379 | * lease on this file, then we hold it on this filp |
@@ -1405,18 +1416,15 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1405 | if (!leases_enable) | 1416 | if (!leases_enable) |
1406 | goto out; | 1417 | goto out; |
1407 | 1418 | ||
1408 | error = -ENOMEM; | 1419 | locks_copy_lock(new_fl, lease); |
1409 | fl = locks_alloc_lock(); | 1420 | locks_insert_lock(before, new_fl); |
1410 | if (fl == NULL) | ||
1411 | goto out; | ||
1412 | |||
1413 | locks_copy_lock(fl, lease); | ||
1414 | 1421 | ||
1415 | locks_insert_lock(before, fl); | 1422 | *flp = new_fl; |
1423 | return 0; | ||
1416 | 1424 | ||
1417 | *flp = fl; | ||
1418 | error = 0; | ||
1419 | out: | 1425 | out: |
1426 | if (new_fl != NULL) | ||
1427 | locks_free_lock(new_fl); | ||
1420 | return error; | 1428 | return error; |
1421 | } | 1429 | } |
1422 | EXPORT_SYMBOL(generic_setlease); | 1430 | EXPORT_SYMBOL(generic_setlease); |
@@ -1752,9 +1760,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, | |||
1752 | /* Don't allow mandatory locks on files that may be memory mapped | 1760 | /* Don't allow mandatory locks on files that may be memory mapped |
1753 | * and shared. | 1761 | * and shared. |
1754 | */ | 1762 | */ |
1755 | if (IS_MANDLOCK(inode) && | 1763 | if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) { |
1756 | (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && | ||
1757 | mapping_writably_mapped(filp->f_mapping)) { | ||
1758 | error = -EAGAIN; | 1764 | error = -EAGAIN; |
1759 | goto out; | 1765 | goto out; |
1760 | } | 1766 | } |
@@ -1878,9 +1884,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, | |||
1878 | /* Don't allow mandatory locks on files that may be memory mapped | 1884 | /* Don't allow mandatory locks on files that may be memory mapped |
1879 | * and shared. | 1885 | * and shared. |
1880 | */ | 1886 | */ |
1881 | if (IS_MANDLOCK(inode) && | 1887 | if (mandatory_lock(inode) && mapping_writably_mapped(filp->f_mapping)) { |
1882 | (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && | ||
1883 | mapping_writably_mapped(filp->f_mapping)) { | ||
1884 | error = -EAGAIN; | 1888 | error = -EAGAIN; |
1885 | goto out; | 1889 | goto out; |
1886 | } | 1890 | } |
@@ -2062,138 +2066,114 @@ int vfs_cancel_lock(struct file *filp, struct file_lock *fl) | |||
2062 | 2066 | ||
2063 | EXPORT_SYMBOL_GPL(vfs_cancel_lock); | 2067 | EXPORT_SYMBOL_GPL(vfs_cancel_lock); |
2064 | 2068 | ||
2065 | static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) | 2069 | #ifdef CONFIG_PROC_FS |
2070 | #include <linux/seq_file.h> | ||
2071 | |||
2072 | static void lock_get_status(struct seq_file *f, struct file_lock *fl, | ||
2073 | int id, char *pfx) | ||
2066 | { | 2074 | { |
2067 | struct inode *inode = NULL; | 2075 | struct inode *inode = NULL; |
2068 | 2076 | ||
2069 | if (fl->fl_file != NULL) | 2077 | if (fl->fl_file != NULL) |
2070 | inode = fl->fl_file->f_path.dentry->d_inode; | 2078 | inode = fl->fl_file->f_path.dentry->d_inode; |
2071 | 2079 | ||
2072 | out += sprintf(out, "%d:%s ", id, pfx); | 2080 | seq_printf(f, "%d:%s ", id, pfx); |
2073 | if (IS_POSIX(fl)) { | 2081 | if (IS_POSIX(fl)) { |
2074 | out += sprintf(out, "%6s %s ", | 2082 | seq_printf(f, "%6s %s ", |
2075 | (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", | 2083 | (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", |
2076 | (inode == NULL) ? "*NOINODE*" : | 2084 | (inode == NULL) ? "*NOINODE*" : |
2077 | (IS_MANDLOCK(inode) && | 2085 | mandatory_lock(inode) ? "MANDATORY" : "ADVISORY "); |
2078 | (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ? | ||
2079 | "MANDATORY" : "ADVISORY "); | ||
2080 | } else if (IS_FLOCK(fl)) { | 2086 | } else if (IS_FLOCK(fl)) { |
2081 | if (fl->fl_type & LOCK_MAND) { | 2087 | if (fl->fl_type & LOCK_MAND) { |
2082 | out += sprintf(out, "FLOCK MSNFS "); | 2088 | seq_printf(f, "FLOCK MSNFS "); |
2083 | } else { | 2089 | } else { |
2084 | out += sprintf(out, "FLOCK ADVISORY "); | 2090 | seq_printf(f, "FLOCK ADVISORY "); |
2085 | } | 2091 | } |
2086 | } else if (IS_LEASE(fl)) { | 2092 | } else if (IS_LEASE(fl)) { |
2087 | out += sprintf(out, "LEASE "); | 2093 | seq_printf(f, "LEASE "); |
2088 | if (fl->fl_type & F_INPROGRESS) | 2094 | if (fl->fl_type & F_INPROGRESS) |
2089 | out += sprintf(out, "BREAKING "); | 2095 | seq_printf(f, "BREAKING "); |
2090 | else if (fl->fl_file) | 2096 | else if (fl->fl_file) |
2091 | out += sprintf(out, "ACTIVE "); | 2097 | seq_printf(f, "ACTIVE "); |
2092 | else | 2098 | else |
2093 | out += sprintf(out, "BREAKER "); | 2099 | seq_printf(f, "BREAKER "); |
2094 | } else { | 2100 | } else { |
2095 | out += sprintf(out, "UNKNOWN UNKNOWN "); | 2101 | seq_printf(f, "UNKNOWN UNKNOWN "); |
2096 | } | 2102 | } |
2097 | if (fl->fl_type & LOCK_MAND) { | 2103 | if (fl->fl_type & LOCK_MAND) { |
2098 | out += sprintf(out, "%s ", | 2104 | seq_printf(f, "%s ", |
2099 | (fl->fl_type & LOCK_READ) | 2105 | (fl->fl_type & LOCK_READ) |
2100 | ? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ " | 2106 | ? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ " |
2101 | : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE "); | 2107 | : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE "); |
2102 | } else { | 2108 | } else { |
2103 | out += sprintf(out, "%s ", | 2109 | seq_printf(f, "%s ", |
2104 | (fl->fl_type & F_INPROGRESS) | 2110 | (fl->fl_type & F_INPROGRESS) |
2105 | ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ " | 2111 | ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ " |
2106 | : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); | 2112 | : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); |
2107 | } | 2113 | } |
2108 | if (inode) { | 2114 | if (inode) { |
2109 | #ifdef WE_CAN_BREAK_LSLK_NOW | 2115 | #ifdef WE_CAN_BREAK_LSLK_NOW |
2110 | out += sprintf(out, "%d %s:%ld ", fl->fl_pid, | 2116 | seq_printf(f, "%d %s:%ld ", fl->fl_pid, |
2111 | inode->i_sb->s_id, inode->i_ino); | 2117 | inode->i_sb->s_id, inode->i_ino); |
2112 | #else | 2118 | #else |
2113 | /* userspace relies on this representation of dev_t ;-( */ | 2119 | /* userspace relies on this representation of dev_t ;-( */ |
2114 | out += sprintf(out, "%d %02x:%02x:%ld ", fl->fl_pid, | 2120 | seq_printf(f, "%d %02x:%02x:%ld ", fl->fl_pid, |
2115 | MAJOR(inode->i_sb->s_dev), | 2121 | MAJOR(inode->i_sb->s_dev), |
2116 | MINOR(inode->i_sb->s_dev), inode->i_ino); | 2122 | MINOR(inode->i_sb->s_dev), inode->i_ino); |
2117 | #endif | 2123 | #endif |
2118 | } else { | 2124 | } else { |
2119 | out += sprintf(out, "%d <none>:0 ", fl->fl_pid); | 2125 | seq_printf(f, "%d <none>:0 ", fl->fl_pid); |
2120 | } | 2126 | } |
2121 | if (IS_POSIX(fl)) { | 2127 | if (IS_POSIX(fl)) { |
2122 | if (fl->fl_end == OFFSET_MAX) | 2128 | if (fl->fl_end == OFFSET_MAX) |
2123 | out += sprintf(out, "%Ld EOF\n", fl->fl_start); | 2129 | seq_printf(f, "%Ld EOF\n", fl->fl_start); |
2124 | else | 2130 | else |
2125 | out += sprintf(out, "%Ld %Ld\n", fl->fl_start, | 2131 | seq_printf(f, "%Ld %Ld\n", fl->fl_start, fl->fl_end); |
2126 | fl->fl_end); | ||
2127 | } else { | 2132 | } else { |
2128 | out += sprintf(out, "0 EOF\n"); | 2133 | seq_printf(f, "0 EOF\n"); |
2129 | } | 2134 | } |
2130 | } | 2135 | } |
2131 | 2136 | ||
2132 | static void move_lock_status(char **p, off_t* pos, off_t offset) | 2137 | static int locks_show(struct seq_file *f, void *v) |
2133 | { | 2138 | { |
2134 | int len; | 2139 | struct file_lock *fl, *bfl; |
2135 | len = strlen(*p); | 2140 | |
2136 | if(*pos >= offset) { | 2141 | fl = list_entry(v, struct file_lock, fl_link); |
2137 | /* the complete line is valid */ | 2142 | |
2138 | *p += len; | 2143 | lock_get_status(f, fl, (long)f->private, ""); |
2139 | *pos += len; | 2144 | |
2140 | return; | 2145 | list_for_each_entry(bfl, &fl->fl_block, fl_block) |
2141 | } | 2146 | lock_get_status(f, bfl, (long)f->private, " ->"); |
2142 | if(*pos+len > offset) { | 2147 | |
2143 | /* use the second part of the line */ | 2148 | f->private++; |
2144 | int i = offset-*pos; | 2149 | return 0; |
2145 | memmove(*p,*p+i,len-i); | ||
2146 | *p += len-i; | ||
2147 | *pos += len; | ||
2148 | return; | ||
2149 | } | ||
2150 | /* discard the complete line */ | ||
2151 | *pos += len; | ||
2152 | } | 2150 | } |
2153 | 2151 | ||
2154 | /** | 2152 | static void *locks_start(struct seq_file *f, loff_t *pos) |
2155 | * get_locks_status - reports lock usage in /proc/locks | 2153 | { |
2156 | * @buffer: address in userspace to write into | 2154 | lock_kernel(); |
2157 | * @start: ? | 2155 | f->private = (void *)1; |
2158 | * @offset: how far we are through the buffer | 2156 | return seq_list_start(&file_lock_list, *pos); |
2159 | * @length: how much to read | 2157 | } |
2160 | */ | ||
2161 | 2158 | ||
2162 | int get_locks_status(char *buffer, char **start, off_t offset, int length) | 2159 | static void *locks_next(struct seq_file *f, void *v, loff_t *pos) |
2163 | { | 2160 | { |
2164 | struct list_head *tmp; | 2161 | return seq_list_next(v, &file_lock_list, pos); |
2165 | char *q = buffer; | 2162 | } |
2166 | off_t pos = 0; | ||
2167 | int i = 0; | ||
2168 | 2163 | ||
2169 | lock_kernel(); | 2164 | static void locks_stop(struct seq_file *f, void *v) |
2170 | list_for_each(tmp, &file_lock_list) { | 2165 | { |
2171 | struct list_head *btmp; | ||
2172 | struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); | ||
2173 | lock_get_status(q, fl, ++i, ""); | ||
2174 | move_lock_status(&q, &pos, offset); | ||
2175 | |||
2176 | if(pos >= offset+length) | ||
2177 | goto done; | ||
2178 | |||
2179 | list_for_each(btmp, &fl->fl_block) { | ||
2180 | struct file_lock *bfl = list_entry(btmp, | ||
2181 | struct file_lock, fl_block); | ||
2182 | lock_get_status(q, bfl, i, " ->"); | ||
2183 | move_lock_status(&q, &pos, offset); | ||
2184 | |||
2185 | if(pos >= offset+length) | ||
2186 | goto done; | ||
2187 | } | ||
2188 | } | ||
2189 | done: | ||
2190 | unlock_kernel(); | 2166 | unlock_kernel(); |
2191 | *start = buffer; | ||
2192 | if(q-buffer < length) | ||
2193 | return (q-buffer); | ||
2194 | return length; | ||
2195 | } | 2167 | } |
2196 | 2168 | ||
2169 | struct seq_operations locks_seq_operations = { | ||
2170 | .start = locks_start, | ||
2171 | .next = locks_next, | ||
2172 | .stop = locks_stop, | ||
2173 | .show = locks_show, | ||
2174 | }; | ||
2175 | #endif | ||
2176 | |||
2197 | /** | 2177 | /** |
2198 | * lock_may_read - checks that the region is free of locks | 2178 | * lock_may_read - checks that the region is free of locks |
2199 | * @inode: the inode that is being read | 2179 | * @inode: the inode that is being read |