diff options
-rw-r--r-- | fs/ceph/locks.c | 58 | ||||
-rw-r--r-- | fs/cifs/file.c | 26 | ||||
-rw-r--r-- | fs/lockd/svcsubs.c | 20 | ||||
-rw-r--r-- | fs/locks.c | 108 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 28 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 52 | ||||
-rw-r--r-- | fs/nfs/pagelist.c | 8 | ||||
-rw-r--r-- | fs/nfs/write.c | 30 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 18 | ||||
-rw-r--r-- | fs/read_write.c | 2 | ||||
-rw-r--r-- | include/linux/fs.h | 3 |
11 files changed, 155 insertions, 198 deletions
diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 917656ea8dcf..19beeed83233 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c | |||
@@ -253,18 +253,15 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count) | |||
253 | *fcntl_count = 0; | 253 | *fcntl_count = 0; |
254 | *flock_count = 0; | 254 | *flock_count = 0; |
255 | 255 | ||
256 | spin_lock(&inode->i_lock); | ||
257 | for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { | ||
258 | if (lock->fl_flags & FL_POSIX) | ||
259 | ++(*fcntl_count); | ||
260 | } | ||
261 | |||
262 | ctx = inode->i_flctx; | 256 | ctx = inode->i_flctx; |
263 | if (ctx) { | 257 | if (ctx) { |
258 | spin_lock(&inode->i_lock); | ||
259 | list_for_each_entry(lock, &ctx->flc_posix, fl_list) | ||
260 | ++(*fcntl_count); | ||
264 | list_for_each_entry(lock, &ctx->flc_flock, fl_list) | 261 | list_for_each_entry(lock, &ctx->flc_flock, fl_list) |
265 | ++(*flock_count); | 262 | ++(*flock_count); |
263 | spin_unlock(&inode->i_lock); | ||
266 | } | 264 | } |
267 | spin_unlock(&inode->i_lock); | ||
268 | dout("counted %d flock locks and %d fcntl locks", | 265 | dout("counted %d flock locks and %d fcntl locks", |
269 | *flock_count, *fcntl_count); | 266 | *flock_count, *fcntl_count); |
270 | } | 267 | } |
@@ -279,7 +276,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode, | |||
279 | int num_fcntl_locks, int num_flock_locks) | 276 | int num_fcntl_locks, int num_flock_locks) |
280 | { | 277 | { |
281 | struct file_lock *lock; | 278 | struct file_lock *lock; |
282 | struct file_lock_context *ctx; | 279 | struct file_lock_context *ctx = inode->i_flctx; |
283 | int err = 0; | 280 | int err = 0; |
284 | int seen_fcntl = 0; | 281 | int seen_fcntl = 0; |
285 | int seen_flock = 0; | 282 | int seen_flock = 0; |
@@ -288,34 +285,31 @@ int ceph_encode_locks_to_buffer(struct inode *inode, | |||
288 | dout("encoding %d flock and %d fcntl locks", num_flock_locks, | 285 | dout("encoding %d flock and %d fcntl locks", num_flock_locks, |
289 | num_fcntl_locks); | 286 | num_fcntl_locks); |
290 | 287 | ||
288 | if (!ctx) | ||
289 | return 0; | ||
290 | |||
291 | spin_lock(&inode->i_lock); | 291 | spin_lock(&inode->i_lock); |
292 | for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { | 292 | list_for_each_entry(lock, &ctx->flc_flock, fl_list) { |
293 | if (lock->fl_flags & FL_POSIX) { | 293 | ++seen_fcntl; |
294 | ++seen_fcntl; | 294 | if (seen_fcntl > num_fcntl_locks) { |
295 | if (seen_fcntl > num_fcntl_locks) { | 295 | err = -ENOSPC; |
296 | err = -ENOSPC; | 296 | goto fail; |
297 | goto fail; | ||
298 | } | ||
299 | err = lock_to_ceph_filelock(lock, &flocks[l]); | ||
300 | if (err) | ||
301 | goto fail; | ||
302 | ++l; | ||
303 | } | 297 | } |
298 | err = lock_to_ceph_filelock(lock, &flocks[l]); | ||
299 | if (err) | ||
300 | goto fail; | ||
301 | ++l; | ||
304 | } | 302 | } |
305 | 303 | list_for_each_entry(lock, &ctx->flc_flock, fl_list) { | |
306 | ctx = inode->i_flctx; | 304 | ++seen_flock; |
307 | if (ctx) { | 305 | if (seen_flock > num_flock_locks) { |
308 | list_for_each_entry(lock, &ctx->flc_flock, fl_list) { | 306 | err = -ENOSPC; |
309 | ++seen_flock; | 307 | goto fail; |
310 | if (seen_flock > num_flock_locks) { | ||
311 | err = -ENOSPC; | ||
312 | goto fail; | ||
313 | } | ||
314 | err = lock_to_ceph_filelock(lock, &flocks[l]); | ||
315 | if (err) | ||
316 | goto fail; | ||
317 | ++l; | ||
318 | } | 308 | } |
309 | err = lock_to_ceph_filelock(lock, &flocks[l]); | ||
310 | if (err) | ||
311 | goto fail; | ||
312 | ++l; | ||
319 | } | 313 | } |
320 | fail: | 314 | fail: |
321 | spin_unlock(&inode->i_lock); | 315 | spin_unlock(&inode->i_lock); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 96b7e9b7706d..ea78f6f81ce2 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1109,11 +1109,6 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
1109 | return rc; | 1109 | return rc; |
1110 | } | 1110 | } |
1111 | 1111 | ||
1112 | /* copied from fs/locks.c with a name change */ | ||
1113 | #define cifs_for_each_lock(inode, lockp) \ | ||
1114 | for (lockp = &inode->i_flock; *lockp != NULL; \ | ||
1115 | lockp = &(*lockp)->fl_next) | ||
1116 | |||
1117 | struct lock_to_push { | 1112 | struct lock_to_push { |
1118 | struct list_head llist; | 1113 | struct list_head llist; |
1119 | __u64 offset; | 1114 | __u64 offset; |
@@ -1128,8 +1123,9 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
1128 | { | 1123 | { |
1129 | struct inode *inode = cfile->dentry->d_inode; | 1124 | struct inode *inode = cfile->dentry->d_inode; |
1130 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1125 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1131 | struct file_lock *flock, **before; | 1126 | struct file_lock *flock; |
1132 | unsigned int count = 0, i = 0; | 1127 | struct file_lock_context *flctx = inode->i_flctx; |
1128 | unsigned int count = 0, i; | ||
1133 | int rc = 0, xid, type; | 1129 | int rc = 0, xid, type; |
1134 | struct list_head locks_to_send, *el; | 1130 | struct list_head locks_to_send, *el; |
1135 | struct lock_to_push *lck, *tmp; | 1131 | struct lock_to_push *lck, *tmp; |
@@ -1137,10 +1133,12 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
1137 | 1133 | ||
1138 | xid = get_xid(); | 1134 | xid = get_xid(); |
1139 | 1135 | ||
1136 | if (!flctx) | ||
1137 | goto out; | ||
1138 | |||
1140 | spin_lock(&inode->i_lock); | 1139 | spin_lock(&inode->i_lock); |
1141 | cifs_for_each_lock(inode, before) { | 1140 | list_for_each(el, &flctx->flc_posix) { |
1142 | if ((*before)->fl_flags & FL_POSIX) | 1141 | count++; |
1143 | count++; | ||
1144 | } | 1142 | } |
1145 | spin_unlock(&inode->i_lock); | 1143 | spin_unlock(&inode->i_lock); |
1146 | 1144 | ||
@@ -1151,7 +1149,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
1151 | * added to the list while we are holding cinode->lock_sem that | 1149 | * added to the list while we are holding cinode->lock_sem that |
1152 | * protects locking operations of this inode. | 1150 | * protects locking operations of this inode. |
1153 | */ | 1151 | */ |
1154 | for (; i < count; i++) { | 1152 | for (i = 0; i < count; i++) { |
1155 | lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL); | 1153 | lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL); |
1156 | if (!lck) { | 1154 | if (!lck) { |
1157 | rc = -ENOMEM; | 1155 | rc = -ENOMEM; |
@@ -1162,10 +1160,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
1162 | 1160 | ||
1163 | el = locks_to_send.next; | 1161 | el = locks_to_send.next; |
1164 | spin_lock(&inode->i_lock); | 1162 | spin_lock(&inode->i_lock); |
1165 | cifs_for_each_lock(inode, before) { | 1163 | list_for_each_entry(flock, &flctx->flc_posix, fl_list) { |
1166 | flock = *before; | ||
1167 | if ((flock->fl_flags & FL_POSIX) == 0) | ||
1168 | continue; | ||
1169 | if (el == &locks_to_send) { | 1164 | if (el == &locks_to_send) { |
1170 | /* | 1165 | /* |
1171 | * The list ended. We don't have enough allocated | 1166 | * The list ended. We don't have enough allocated |
@@ -1185,7 +1180,6 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
1185 | lck->length = length; | 1180 | lck->length = length; |
1186 | lck->type = type; | 1181 | lck->type = type; |
1187 | lck->offset = flock->fl_start; | 1182 | lck->offset = flock->fl_start; |
1188 | el = el->next; | ||
1189 | } | 1183 | } |
1190 | spin_unlock(&inode->i_lock); | 1184 | spin_unlock(&inode->i_lock); |
1191 | 1185 | ||
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index d12ff4e2dbe7..5300bb53835f 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c | |||
@@ -164,12 +164,15 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, | |||
164 | { | 164 | { |
165 | struct inode *inode = nlmsvc_file_inode(file); | 165 | struct inode *inode = nlmsvc_file_inode(file); |
166 | struct file_lock *fl; | 166 | struct file_lock *fl; |
167 | struct file_lock_context *flctx = inode->i_flctx; | ||
167 | struct nlm_host *lockhost; | 168 | struct nlm_host *lockhost; |
168 | 169 | ||
170 | if (!flctx || list_empty_careful(&flctx->flc_posix)) | ||
171 | return 0; | ||
169 | again: | 172 | again: |
170 | file->f_locks = 0; | 173 | file->f_locks = 0; |
171 | spin_lock(&inode->i_lock); | 174 | spin_lock(&inode->i_lock); |
172 | for (fl = inode->i_flock; fl; fl = fl->fl_next) { | 175 | list_for_each_entry(fl, &flctx->flc_posix, fl_list) { |
173 | if (fl->fl_lmops != &nlmsvc_lock_operations) | 176 | if (fl->fl_lmops != &nlmsvc_lock_operations) |
174 | continue; | 177 | continue; |
175 | 178 | ||
@@ -223,18 +226,21 @@ nlm_file_inuse(struct nlm_file *file) | |||
223 | { | 226 | { |
224 | struct inode *inode = nlmsvc_file_inode(file); | 227 | struct inode *inode = nlmsvc_file_inode(file); |
225 | struct file_lock *fl; | 228 | struct file_lock *fl; |
229 | struct file_lock_context *flctx = inode->i_flctx; | ||
226 | 230 | ||
227 | if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares) | 231 | if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares) |
228 | return 1; | 232 | return 1; |
229 | 233 | ||
230 | spin_lock(&inode->i_lock); | 234 | if (flctx && !list_empty_careful(&flctx->flc_posix)) { |
231 | for (fl = inode->i_flock; fl; fl = fl->fl_next) { | 235 | spin_lock(&inode->i_lock); |
232 | if (fl->fl_lmops == &nlmsvc_lock_operations) { | 236 | list_for_each_entry(fl, &flctx->flc_posix, fl_list) { |
233 | spin_unlock(&inode->i_lock); | 237 | if (fl->fl_lmops == &nlmsvc_lock_operations) { |
234 | return 1; | 238 | spin_unlock(&inode->i_lock); |
239 | return 1; | ||
240 | } | ||
235 | } | 241 | } |
242 | spin_unlock(&inode->i_lock); | ||
236 | } | 243 | } |
237 | spin_unlock(&inode->i_lock); | ||
238 | file->f_locks = 0; | 244 | file->f_locks = 0; |
239 | return 0; | 245 | return 0; |
240 | } | 246 | } |
diff --git a/fs/locks.c b/fs/locks.c index 055df53f19de..e50bb4d9e757 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -157,9 +157,6 @@ static int target_leasetype(struct file_lock *fl) | |||
157 | int leases_enable = 1; | 157 | int leases_enable = 1; |
158 | int lease_break_time = 45; | 158 | int lease_break_time = 45; |
159 | 159 | ||
160 | #define for_each_lock(inode, lockp) \ | ||
161 | for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) | ||
162 | |||
163 | /* | 160 | /* |
164 | * The global file_lock_list is only used for displaying /proc/locks, so we | 161 | * The global file_lock_list is only used for displaying /proc/locks, so we |
165 | * keep a list on each CPU, with each list protected by its own spinlock via | 162 | * keep a list on each CPU, with each list protected by its own spinlock via |
@@ -218,6 +215,7 @@ locks_get_lock_context(struct inode *inode) | |||
218 | goto out; | 215 | goto out; |
219 | 216 | ||
220 | INIT_LIST_HEAD(&new->flc_flock); | 217 | INIT_LIST_HEAD(&new->flc_flock); |
218 | INIT_LIST_HEAD(&new->flc_posix); | ||
221 | 219 | ||
222 | /* | 220 | /* |
223 | * Assign the pointer if it's not already assigned. If it is, then | 221 | * Assign the pointer if it's not already assigned. If it is, then |
@@ -241,6 +239,7 @@ locks_free_lock_context(struct file_lock_context *ctx) | |||
241 | { | 239 | { |
242 | if (ctx) { | 240 | if (ctx) { |
243 | WARN_ON_ONCE(!list_empty(&ctx->flc_flock)); | 241 | WARN_ON_ONCE(!list_empty(&ctx->flc_flock)); |
242 | WARN_ON_ONCE(!list_empty(&ctx->flc_posix)); | ||
244 | kmem_cache_free(flctx_cache, ctx); | 243 | kmem_cache_free(flctx_cache, ctx); |
245 | } | 244 | } |
246 | } | 245 | } |
@@ -809,21 +808,26 @@ void | |||
809 | posix_test_lock(struct file *filp, struct file_lock *fl) | 808 | posix_test_lock(struct file *filp, struct file_lock *fl) |
810 | { | 809 | { |
811 | struct file_lock *cfl; | 810 | struct file_lock *cfl; |
811 | struct file_lock_context *ctx; | ||
812 | struct inode *inode = file_inode(filp); | 812 | struct inode *inode = file_inode(filp); |
813 | 813 | ||
814 | ctx = inode->i_flctx; | ||
815 | if (!ctx || list_empty_careful(&ctx->flc_posix)) { | ||
816 | fl->fl_type = F_UNLCK; | ||
817 | return; | ||
818 | } | ||
819 | |||
814 | spin_lock(&inode->i_lock); | 820 | spin_lock(&inode->i_lock); |
815 | for (cfl = file_inode(filp)->i_flock; cfl; cfl = cfl->fl_next) { | 821 | list_for_each_entry(cfl, &ctx->flc_posix, fl_list) { |
816 | if (!IS_POSIX(cfl)) | 822 | if (posix_locks_conflict(fl, cfl)) { |
817 | continue; | 823 | locks_copy_conflock(fl, cfl); |
818 | if (posix_locks_conflict(fl, cfl)) | 824 | if (cfl->fl_nspid) |
819 | break; | 825 | fl->fl_pid = pid_vnr(cfl->fl_nspid); |
826 | goto out; | ||
827 | } | ||
820 | } | 828 | } |
821 | if (cfl) { | 829 | fl->fl_type = F_UNLCK; |
822 | locks_copy_conflock(fl, cfl); | 830 | out: |
823 | if (cfl->fl_nspid) | ||
824 | fl->fl_pid = pid_vnr(cfl->fl_nspid); | ||
825 | } else | ||
826 | fl->fl_type = F_UNLCK; | ||
827 | spin_unlock(&inode->i_lock); | 831 | spin_unlock(&inode->i_lock); |
828 | return; | 832 | return; |
829 | } | 833 | } |
@@ -983,16 +987,20 @@ out: | |||
983 | 987 | ||
984 | static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock) | 988 | static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock) |
985 | { | 989 | { |
986 | struct file_lock *fl; | 990 | struct file_lock *fl, *tmp; |
987 | struct file_lock *new_fl = NULL; | 991 | struct file_lock *new_fl = NULL; |
988 | struct file_lock *new_fl2 = NULL; | 992 | struct file_lock *new_fl2 = NULL; |
989 | struct file_lock *left = NULL; | 993 | struct file_lock *left = NULL; |
990 | struct file_lock *right = NULL; | 994 | struct file_lock *right = NULL; |
991 | struct file_lock **before; | 995 | struct file_lock_context *ctx; |
992 | int error; | 996 | int error; |
993 | bool added = false; | 997 | bool added = false; |
994 | LIST_HEAD(dispose); | 998 | LIST_HEAD(dispose); |
995 | 999 | ||
1000 | ctx = locks_get_lock_context(inode); | ||
1001 | if (!ctx) | ||
1002 | return -ENOMEM; | ||
1003 | |||
996 | /* | 1004 | /* |
997 | * We may need two file_lock structures for this operation, | 1005 | * We may need two file_lock structures for this operation, |
998 | * so we get them in advance to avoid races. | 1006 | * so we get them in advance to avoid races. |
@@ -1013,8 +1021,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
1013 | * blocker's list of waiters and the global blocked_hash. | 1021 | * blocker's list of waiters and the global blocked_hash. |
1014 | */ | 1022 | */ |
1015 | if (request->fl_type != F_UNLCK) { | 1023 | if (request->fl_type != F_UNLCK) { |
1016 | for_each_lock(inode, before) { | 1024 | list_for_each_entry(fl, &ctx->flc_posix, fl_list) { |
1017 | fl = *before; | ||
1018 | if (!IS_POSIX(fl)) | 1025 | if (!IS_POSIX(fl)) |
1019 | continue; | 1026 | continue; |
1020 | if (!posix_locks_conflict(request, fl)) | 1027 | if (!posix_locks_conflict(request, fl)) |
@@ -1044,29 +1051,25 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
1044 | if (request->fl_flags & FL_ACCESS) | 1051 | if (request->fl_flags & FL_ACCESS) |
1045 | goto out; | 1052 | goto out; |
1046 | 1053 | ||
1047 | /* | 1054 | /* Find the first old lock with the same owner as the new lock */ |
1048 | * Find the first old lock with the same owner as the new lock. | 1055 | list_for_each_entry(fl, &ctx->flc_posix, fl_list) { |
1049 | */ | 1056 | if (posix_same_owner(request, fl)) |
1050 | 1057 | break; | |
1051 | before = &inode->i_flock; | ||
1052 | |||
1053 | /* First skip locks owned by other processes. */ | ||
1054 | while ((fl = *before) && (!IS_POSIX(fl) || | ||
1055 | !posix_same_owner(request, fl))) { | ||
1056 | before = &fl->fl_next; | ||
1057 | } | 1058 | } |
1058 | 1059 | ||
1059 | /* Process locks with this owner. */ | 1060 | /* Process locks with this owner. */ |
1060 | while ((fl = *before) && posix_same_owner(request, fl)) { | 1061 | list_for_each_entry_safe_from(fl, tmp, &ctx->flc_posix, fl_list) { |
1061 | /* Detect adjacent or overlapping regions (if same lock type) | 1062 | if (!posix_same_owner(request, fl)) |
1062 | */ | 1063 | break; |
1064 | |||
1065 | /* Detect adjacent or overlapping regions (if same lock type) */ | ||
1063 | if (request->fl_type == fl->fl_type) { | 1066 | if (request->fl_type == fl->fl_type) { |
1064 | /* In all comparisons of start vs end, use | 1067 | /* In all comparisons of start vs end, use |
1065 | * "start - 1" rather than "end + 1". If end | 1068 | * "start - 1" rather than "end + 1". If end |
1066 | * is OFFSET_MAX, end + 1 will become negative. | 1069 | * is OFFSET_MAX, end + 1 will become negative. |
1067 | */ | 1070 | */ |
1068 | if (fl->fl_end < request->fl_start - 1) | 1071 | if (fl->fl_end < request->fl_start - 1) |
1069 | goto next_lock; | 1072 | continue; |
1070 | /* If the next lock in the list has entirely bigger | 1073 | /* If the next lock in the list has entirely bigger |
1071 | * addresses than the new one, insert the lock here. | 1074 | * addresses than the new one, insert the lock here. |
1072 | */ | 1075 | */ |
@@ -1087,18 +1090,17 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
1087 | else | 1090 | else |
1088 | request->fl_end = fl->fl_end; | 1091 | request->fl_end = fl->fl_end; |
1089 | if (added) { | 1092 | if (added) { |
1090 | locks_delete_lock(before, &dispose); | 1093 | locks_delete_lock_ctx(fl, &dispose); |
1091 | continue; | 1094 | continue; |
1092 | } | 1095 | } |
1093 | request = fl; | 1096 | request = fl; |
1094 | added = true; | 1097 | added = true; |
1095 | } | 1098 | } else { |
1096 | else { | ||
1097 | /* Processing for different lock types is a bit | 1099 | /* Processing for different lock types is a bit |
1098 | * more complex. | 1100 | * more complex. |
1099 | */ | 1101 | */ |
1100 | if (fl->fl_end < request->fl_start) | 1102 | if (fl->fl_end < request->fl_start) |
1101 | goto next_lock; | 1103 | continue; |
1102 | if (fl->fl_start > request->fl_end) | 1104 | if (fl->fl_start > request->fl_end) |
1103 | break; | 1105 | break; |
1104 | if (request->fl_type == F_UNLCK) | 1106 | if (request->fl_type == F_UNLCK) |
@@ -1117,7 +1119,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
1117 | * one (This may happen several times). | 1119 | * one (This may happen several times). |
1118 | */ | 1120 | */ |
1119 | if (added) { | 1121 | if (added) { |
1120 | locks_delete_lock(before, &dispose); | 1122 | locks_delete_lock_ctx(fl, &dispose); |
1121 | continue; | 1123 | continue; |
1122 | } | 1124 | } |
1123 | /* | 1125 | /* |
@@ -1133,15 +1135,11 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
1133 | locks_copy_lock(new_fl, request); | 1135 | locks_copy_lock(new_fl, request); |
1134 | request = new_fl; | 1136 | request = new_fl; |
1135 | new_fl = NULL; | 1137 | new_fl = NULL; |
1136 | locks_delete_lock(before, &dispose); | 1138 | locks_insert_lock_ctx(request, &fl->fl_list); |
1137 | locks_insert_lock(before, request); | 1139 | locks_delete_lock_ctx(fl, &dispose); |
1138 | added = true; | 1140 | added = true; |
1139 | } | 1141 | } |
1140 | } | 1142 | } |
1141 | /* Go on to next lock. | ||
1142 | */ | ||
1143 | next_lock: | ||
1144 | before = &fl->fl_next; | ||
1145 | } | 1143 | } |
1146 | 1144 | ||
1147 | /* | 1145 | /* |
@@ -1166,7 +1164,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
1166 | goto out; | 1164 | goto out; |
1167 | } | 1165 | } |
1168 | locks_copy_lock(new_fl, request); | 1166 | locks_copy_lock(new_fl, request); |
1169 | locks_insert_lock(before, new_fl); | 1167 | locks_insert_lock_ctx(new_fl, &fl->fl_list); |
1170 | new_fl = NULL; | 1168 | new_fl = NULL; |
1171 | } | 1169 | } |
1172 | if (right) { | 1170 | if (right) { |
@@ -1177,7 +1175,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
1177 | left = new_fl2; | 1175 | left = new_fl2; |
1178 | new_fl2 = NULL; | 1176 | new_fl2 = NULL; |
1179 | locks_copy_lock(left, right); | 1177 | locks_copy_lock(left, right); |
1180 | locks_insert_lock(before, left); | 1178 | locks_insert_lock_ctx(left, &fl->fl_list); |
1181 | } | 1179 | } |
1182 | right->fl_start = request->fl_end + 1; | 1180 | right->fl_start = request->fl_end + 1; |
1183 | locks_wake_up_blocks(right); | 1181 | locks_wake_up_blocks(right); |
@@ -1257,22 +1255,29 @@ EXPORT_SYMBOL(posix_lock_file_wait); | |||
1257 | */ | 1255 | */ |
1258 | int locks_mandatory_locked(struct file *file) | 1256 | int locks_mandatory_locked(struct file *file) |
1259 | { | 1257 | { |
1258 | int ret; | ||
1260 | struct inode *inode = file_inode(file); | 1259 | struct inode *inode = file_inode(file); |
1260 | struct file_lock_context *ctx; | ||
1261 | struct file_lock *fl; | 1261 | struct file_lock *fl; |
1262 | 1262 | ||
1263 | ctx = inode->i_flctx; | ||
1264 | if (!ctx || list_empty_careful(&ctx->flc_posix)) | ||
1265 | return 0; | ||
1266 | |||
1263 | /* | 1267 | /* |
1264 | * Search the lock list for this inode for any POSIX locks. | 1268 | * Search the lock list for this inode for any POSIX locks. |
1265 | */ | 1269 | */ |
1266 | spin_lock(&inode->i_lock); | 1270 | spin_lock(&inode->i_lock); |
1267 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 1271 | ret = 0; |
1268 | if (!IS_POSIX(fl)) | 1272 | list_for_each_entry(fl, &ctx->flc_posix, fl_list) { |
1269 | continue; | ||
1270 | if (fl->fl_owner != current->files && | 1273 | if (fl->fl_owner != current->files && |
1271 | fl->fl_owner != file) | 1274 | fl->fl_owner != file) { |
1275 | ret = -EAGAIN; | ||
1272 | break; | 1276 | break; |
1277 | } | ||
1273 | } | 1278 | } |
1274 | spin_unlock(&inode->i_lock); | 1279 | spin_unlock(&inode->i_lock); |
1275 | return fl ? -EAGAIN : 0; | 1280 | return ret; |
1276 | } | 1281 | } |
1277 | 1282 | ||
1278 | /** | 1283 | /** |
@@ -2389,13 +2394,14 @@ out: | |||
2389 | void locks_remove_posix(struct file *filp, fl_owner_t owner) | 2394 | void locks_remove_posix(struct file *filp, fl_owner_t owner) |
2390 | { | 2395 | { |
2391 | struct file_lock lock; | 2396 | struct file_lock lock; |
2397 | struct file_lock_context *ctx = file_inode(filp)->i_flctx; | ||
2392 | 2398 | ||
2393 | /* | 2399 | /* |
2394 | * If there are no locks held on this file, we don't need to call | 2400 | * If there are no locks held on this file, we don't need to call |
2395 | * posix_lock_file(). Another process could be setting a lock on this | 2401 | * posix_lock_file(). Another process could be setting a lock on this |
2396 | * file at the same time, but we wouldn't remove that lock anyway. | 2402 | * file at the same time, but we wouldn't remove that lock anyway. |
2397 | */ | 2403 | */ |
2398 | if (!file_inode(filp)->i_flock) | 2404 | if (!ctx || list_empty(&ctx->flc_posix)) |
2399 | return; | 2405 | return; |
2400 | 2406 | ||
2401 | lock.fl_type = F_UNLCK; | 2407 | lock.fl_type = F_UNLCK; |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 9f9f67b17e2b..3fb1caa3874d 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -85,17 +85,17 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ | |||
85 | { | 85 | { |
86 | struct inode *inode = state->inode; | 86 | struct inode *inode = state->inode; |
87 | struct file_lock *fl; | 87 | struct file_lock *fl; |
88 | struct file_lock_context *flctx; | 88 | struct file_lock_context *flctx = inode->i_flctx; |
89 | struct list_head *list; | ||
89 | int status = 0; | 90 | int status = 0; |
90 | 91 | ||
91 | if (inode->i_flock == NULL && inode->i_flctx == NULL) | 92 | if (flctx == NULL) |
92 | goto out; | 93 | goto out; |
93 | 94 | ||
94 | /* Protect inode->i_flock using the i_lock */ | 95 | list = &flctx->flc_posix; |
95 | spin_lock(&inode->i_lock); | 96 | spin_lock(&inode->i_lock); |
96 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 97 | restart: |
97 | if (!(fl->fl_flags & (FL_POSIX))) | 98 | list_for_each_entry(fl, list, fl_list) { |
98 | continue; | ||
99 | if (nfs_file_open_context(fl->fl_file) != ctx) | 99 | if (nfs_file_open_context(fl->fl_file) != ctx) |
100 | continue; | 100 | continue; |
101 | spin_unlock(&inode->i_lock); | 101 | spin_unlock(&inode->i_lock); |
@@ -104,19 +104,9 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ | |||
104 | goto out; | 104 | goto out; |
105 | spin_lock(&inode->i_lock); | 105 | spin_lock(&inode->i_lock); |
106 | } | 106 | } |
107 | 107 | if (list == &flctx->flc_posix) { | |
108 | flctx = inode->i_flctx; | 108 | list = &flctx->flc_flock; |
109 | if (flctx) { | 109 | goto restart; |
110 | list_for_each_entry(fl, &flctx->flc_flock, fl_list) { | ||
111 | if (nfs_file_open_context(fl->fl_file) != ctx) | ||
112 | continue; | ||
113 | spin_unlock(&inode->i_lock); | ||
114 | status = nfs4_lock_delegation_recall(fl, state, | ||
115 | stateid); | ||
116 | if (status < 0) | ||
117 | goto out; | ||
118 | spin_lock(&inode->i_lock); | ||
119 | } | ||
120 | } | 110 | } |
121 | spin_unlock(&inode->i_lock); | 111 | spin_unlock(&inode->i_lock); |
122 | out: | 112 | out: |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 65c404bf61ae..6084c267f3a0 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -1367,53 +1367,18 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
1367 | struct file_lock *fl; | 1367 | struct file_lock *fl; |
1368 | int status = 0; | 1368 | int status = 0; |
1369 | struct file_lock_context *flctx = inode->i_flctx; | 1369 | struct file_lock_context *flctx = inode->i_flctx; |
1370 | struct list_head *list; | ||
1370 | 1371 | ||
1371 | if (inode->i_flock == NULL && flctx == NULL) | 1372 | if (flctx == NULL) |
1372 | return 0; | 1373 | return 0; |
1373 | 1374 | ||
1375 | list = &flctx->flc_posix; | ||
1376 | |||
1374 | /* Guard against delegation returns and new lock/unlock calls */ | 1377 | /* Guard against delegation returns and new lock/unlock calls */ |
1375 | down_write(&nfsi->rwsem); | 1378 | down_write(&nfsi->rwsem); |
1376 | /* Protect inode->i_flock using the BKL */ | ||
1377 | spin_lock(&inode->i_lock); | 1379 | spin_lock(&inode->i_lock); |
1378 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 1380 | restart: |
1379 | if (!(fl->fl_flags & FL_POSIX)) | 1381 | list_for_each_entry(fl, list, fl_list) { |
1380 | continue; | ||
1381 | if (nfs_file_open_context(fl->fl_file)->state != state) | ||
1382 | continue; | ||
1383 | spin_unlock(&inode->i_lock); | ||
1384 | status = ops->recover_lock(state, fl); | ||
1385 | switch (status) { | ||
1386 | case 0: | ||
1387 | break; | ||
1388 | case -ESTALE: | ||
1389 | case -NFS4ERR_ADMIN_REVOKED: | ||
1390 | case -NFS4ERR_STALE_STATEID: | ||
1391 | case -NFS4ERR_BAD_STATEID: | ||
1392 | case -NFS4ERR_EXPIRED: | ||
1393 | case -NFS4ERR_NO_GRACE: | ||
1394 | case -NFS4ERR_STALE_CLIENTID: | ||
1395 | case -NFS4ERR_BADSESSION: | ||
1396 | case -NFS4ERR_BADSLOT: | ||
1397 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
1398 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
1399 | goto out; | ||
1400 | default: | ||
1401 | printk(KERN_ERR "NFS: %s: unhandled error %d\n", | ||
1402 | __func__, status); | ||
1403 | case -ENOMEM: | ||
1404 | case -NFS4ERR_DENIED: | ||
1405 | case -NFS4ERR_RECLAIM_BAD: | ||
1406 | case -NFS4ERR_RECLAIM_CONFLICT: | ||
1407 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | ||
1408 | status = 0; | ||
1409 | } | ||
1410 | spin_lock(&inode->i_lock); | ||
1411 | } | ||
1412 | |||
1413 | if (!flctx) | ||
1414 | goto out_unlock; | ||
1415 | |||
1416 | list_for_each_entry(fl, &flctx->flc_flock, fl_list) { | ||
1417 | if (nfs_file_open_context(fl->fl_file)->state != state) | 1382 | if (nfs_file_open_context(fl->fl_file)->state != state) |
1418 | continue; | 1383 | continue; |
1419 | spin_unlock(&inode->i_lock); | 1384 | spin_unlock(&inode->i_lock); |
@@ -1445,7 +1410,10 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
1445 | } | 1410 | } |
1446 | spin_lock(&inode->i_lock); | 1411 | spin_lock(&inode->i_lock); |
1447 | } | 1412 | } |
1448 | out_unlock: | 1413 | if (list == &flctx->flc_posix) { |
1414 | list = &flctx->flc_flock; | ||
1415 | goto restart; | ||
1416 | } | ||
1449 | spin_unlock(&inode->i_lock); | 1417 | spin_unlock(&inode->i_lock); |
1450 | out: | 1418 | out: |
1451 | up_write(&nfsi->rwsem); | 1419 | up_write(&nfsi->rwsem); |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index a3b62e15b444..29c7f33c9cf1 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -831,12 +831,10 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev, | |||
831 | if (prev) { | 831 | if (prev) { |
832 | if (!nfs_match_open_context(req->wb_context, prev->wb_context)) | 832 | if (!nfs_match_open_context(req->wb_context, prev->wb_context)) |
833 | return false; | 833 | return false; |
834 | if (req->wb_context->dentry->d_inode->i_flock != NULL && | ||
835 | !nfs_match_lock_context(req->wb_lock_context, | ||
836 | prev->wb_lock_context)) | ||
837 | return false; | ||
838 | flctx = req->wb_context->dentry->d_inode->i_flctx; | 834 | flctx = req->wb_context->dentry->d_inode->i_flctx; |
839 | if (flctx != NULL && !list_empty_careful(&flctx->flc_flock) && | 835 | if (flctx != NULL && |
836 | !(list_empty_careful(&flctx->flc_posix) && | ||
837 | list_empty_careful(&flctx->flc_flock)) && | ||
840 | !nfs_match_lock_context(req->wb_lock_context, | 838 | !nfs_match_lock_context(req->wb_lock_context, |
841 | prev->wb_lock_context)) | 839 | prev->wb_lock_context)) |
842 | return false; | 840 | return false; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e072aeb34195..784c13485b3f 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1091,6 +1091,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page) | |||
1091 | { | 1091 | { |
1092 | struct nfs_open_context *ctx = nfs_file_open_context(file); | 1092 | struct nfs_open_context *ctx = nfs_file_open_context(file); |
1093 | struct nfs_lock_context *l_ctx; | 1093 | struct nfs_lock_context *l_ctx; |
1094 | struct file_lock_context *flctx = file_inode(file)->i_flctx; | ||
1094 | struct nfs_page *req; | 1095 | struct nfs_page *req; |
1095 | int do_flush, status; | 1096 | int do_flush, status; |
1096 | /* | 1097 | /* |
@@ -1109,12 +1110,9 @@ int nfs_flush_incompatible(struct file *file, struct page *page) | |||
1109 | do_flush = req->wb_page != page || req->wb_context != ctx; | 1110 | do_flush = req->wb_page != page || req->wb_context != ctx; |
1110 | /* for now, flush if more than 1 request in page_group */ | 1111 | /* for now, flush if more than 1 request in page_group */ |
1111 | do_flush |= req->wb_this_page != req; | 1112 | do_flush |= req->wb_this_page != req; |
1112 | if (l_ctx && ctx->dentry->d_inode->i_flock != NULL) { | 1113 | if (l_ctx && flctx && |
1113 | do_flush |= l_ctx->lockowner.l_owner != current->files | 1114 | !(list_empty_careful(&flctx->flc_posix) && |
1114 | || l_ctx->lockowner.l_pid != current->tgid; | 1115 | list_empty_careful(&flctx->flc_flock))) { |
1115 | } | ||
1116 | if (l_ctx && ctx->dentry->d_inode->i_flctx && | ||
1117 | !list_empty_careful(&ctx->dentry->d_inode->i_flctx->flc_flock)) { | ||
1118 | do_flush |= l_ctx->lockowner.l_owner != current->files | 1116 | do_flush |= l_ctx->lockowner.l_owner != current->files |
1119 | || l_ctx->lockowner.l_pid != current->tgid; | 1117 | || l_ctx->lockowner.l_pid != current->tgid; |
1120 | } | 1118 | } |
@@ -1202,26 +1200,24 @@ static int nfs_can_extend_write(struct file *file, struct page *page, struct ino | |||
1202 | return 0; | 1200 | return 0; |
1203 | if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) | 1201 | if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) |
1204 | return 1; | 1202 | return 1; |
1205 | if (!inode->i_flock && !flctx) | 1203 | if (!flctx || (list_empty_careful(&flctx->flc_flock) && |
1204 | list_empty_careful(&flctx->flc_posix))) | ||
1206 | return 0; | 1205 | return 0; |
1207 | 1206 | ||
1208 | /* Check to see if there are whole file write locks */ | 1207 | /* Check to see if there are whole file write locks */ |
1209 | spin_lock(&inode->i_lock); | ||
1210 | ret = 0; | 1208 | ret = 0; |
1211 | 1209 | spin_lock(&inode->i_lock); | |
1212 | fl = inode->i_flock; | 1210 | if (!list_empty(&flctx->flc_posix)) { |
1213 | if (fl && is_whole_file_wrlock(fl)) { | 1211 | fl = list_first_entry(&flctx->flc_posix, struct file_lock, |
1214 | ret = 1; | 1212 | fl_list); |
1215 | goto out; | 1213 | if (is_whole_file_wrlock(fl)) |
1216 | } | 1214 | ret = 1; |
1217 | 1215 | } else if (!list_empty(&flctx->flc_flock)) { | |
1218 | if (!list_empty(&flctx->flc_flock)) { | ||
1219 | fl = list_first_entry(&flctx->flc_flock, struct file_lock, | 1216 | fl = list_first_entry(&flctx->flc_flock, struct file_lock, |
1220 | fl_list); | 1217 | fl_list); |
1221 | if (fl->fl_type == F_WRLCK) | 1218 | if (fl->fl_type == F_WRLCK) |
1222 | ret = 1; | 1219 | ret = 1; |
1223 | } | 1220 | } |
1224 | out: | ||
1225 | spin_unlock(&inode->i_lock); | 1221 | spin_unlock(&inode->i_lock); |
1226 | return ret; | 1222 | return ret; |
1227 | } | 1223 | } |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c06a1ba80d73..fad821991369 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -5556,10 +5556,11 @@ out_nfserr: | |||
5556 | static bool | 5556 | static bool |
5557 | check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) | 5557 | check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) |
5558 | { | 5558 | { |
5559 | struct file_lock **flpp; | 5559 | struct file_lock *fl; |
5560 | int status = false; | 5560 | int status = false; |
5561 | struct file *filp = find_any_file(fp); | 5561 | struct file *filp = find_any_file(fp); |
5562 | struct inode *inode; | 5562 | struct inode *inode; |
5563 | struct file_lock_context *flctx; | ||
5563 | 5564 | ||
5564 | if (!filp) { | 5565 | if (!filp) { |
5565 | /* Any valid lock stateid should have some sort of access */ | 5566 | /* Any valid lock stateid should have some sort of access */ |
@@ -5568,15 +5569,18 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) | |||
5568 | } | 5569 | } |
5569 | 5570 | ||
5570 | inode = file_inode(filp); | 5571 | inode = file_inode(filp); |
5572 | flctx = inode->i_flctx; | ||
5571 | 5573 | ||
5572 | spin_lock(&inode->i_lock); | 5574 | if (flctx && !list_empty_careful(&flctx->flc_posix)) { |
5573 | for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { | 5575 | spin_lock(&inode->i_lock); |
5574 | if ((*flpp)->fl_owner == (fl_owner_t)lowner) { | 5576 | list_for_each_entry(fl, &flctx->flc_posix, fl_list) { |
5575 | status = true; | 5577 | if (fl->fl_owner == (fl_owner_t)lowner) { |
5576 | break; | 5578 | status = true; |
5579 | break; | ||
5580 | } | ||
5577 | } | 5581 | } |
5582 | spin_unlock(&inode->i_lock); | ||
5578 | } | 5583 | } |
5579 | spin_unlock(&inode->i_lock); | ||
5580 | fput(filp); | 5584 | fput(filp); |
5581 | return status; | 5585 | return status; |
5582 | } | 5586 | } |
diff --git a/fs/read_write.c b/fs/read_write.c index c0805c93b6fa..4060691e78f7 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -358,7 +358,7 @@ int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t | |||
358 | return retval; | 358 | return retval; |
359 | } | 359 | } |
360 | 360 | ||
361 | if (unlikely(inode->i_flock && mandatory_lock(inode))) { | 361 | if (unlikely(inode->i_flctx && mandatory_lock(inode))) { |
362 | retval = locks_mandatory_area( | 362 | retval = locks_mandatory_area( |
363 | read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, | 363 | read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, |
364 | inode, file, pos, count); | 364 | inode, file, pos, count); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index dec0d38b05de..571f113588e9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -968,6 +968,7 @@ struct file_lock { | |||
968 | 968 | ||
969 | struct file_lock_context { | 969 | struct file_lock_context { |
970 | struct list_head flc_flock; | 970 | struct list_head flc_flock; |
971 | struct list_head flc_posix; | ||
971 | }; | 972 | }; |
972 | 973 | ||
973 | /* The following constant reflects the upper bound of the file/locking space */ | 974 | /* The following constant reflects the upper bound of the file/locking space */ |
@@ -1971,7 +1972,7 @@ static inline int locks_verify_truncate(struct inode *inode, | |||
1971 | struct file *filp, | 1972 | struct file *filp, |
1972 | loff_t size) | 1973 | loff_t size) |
1973 | { | 1974 | { |
1974 | if (inode->i_flock && mandatory_lock(inode)) | 1975 | if (inode->i_flctx && mandatory_lock(inode)) |
1975 | return locks_mandatory_area( | 1976 | return locks_mandatory_area( |
1976 | FLOCK_VERIFY_WRITE, inode, filp, | 1977 | FLOCK_VERIFY_WRITE, inode, filp, |
1977 | size < inode->i_size ? size : inode->i_size, | 1978 | size < inode->i_size ? size : inode->i_size, |