diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-18 13:21:47 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-18 13:21:47 -0500 |
| commit | b2b89ebfc0f0287e20516a5443d93af309b800cf (patch) | |
| tree | d3c1e02fbc3ed33ebc00b88d6265a3cd2f5d1015 | |
| parent | eaa0eda56223815cd9dc1225f715ff673ae77198 (diff) | |
| parent | 2e2f756f81edd7c3ba6ed384385ae1d6491652eb (diff) | |
Merge tag 'locks-v3.20-2' of git://git.samba.org/jlayton/linux
Pull file locking fixes from Jeff Layton:
"A small set of patches to fix problems with the recent file locking
changes that we discussed earlier this week"
"
* tag 'locks-v3.20-2' of git://git.samba.org/jlayton/linux:
locks: fix list insertion when lock is split in two
locks: remove conditional lock release in middle of flock_lock_file
locks: only remove leases associated with the file being closed
Revert "locks: keep a count of locks on the flctx lists"
| -rw-r--r-- | fs/ceph/locks.c | 9 | ||||
| -rw-r--r-- | fs/cifs/file.c | 14 | ||||
| -rw-r--r-- | fs/locks.c | 59 | ||||
| -rw-r--r-- | include/linux/fs.h | 3 |
4 files changed, 36 insertions, 49 deletions
diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 06ea5cd05cd9..4347039ecc18 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c | |||
| @@ -245,6 +245,7 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) | |||
| 245 | */ | 245 | */ |
| 246 | void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count) | 246 | void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count) |
| 247 | { | 247 | { |
| 248 | struct file_lock *lock; | ||
| 248 | struct file_lock_context *ctx; | 249 | struct file_lock_context *ctx; |
| 249 | 250 | ||
| 250 | *fcntl_count = 0; | 251 | *fcntl_count = 0; |
| @@ -252,8 +253,12 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count) | |||
| 252 | 253 | ||
| 253 | ctx = inode->i_flctx; | 254 | ctx = inode->i_flctx; |
| 254 | if (ctx) { | 255 | if (ctx) { |
| 255 | *fcntl_count = ctx->flc_posix_cnt; | 256 | spin_lock(&ctx->flc_lock); |
| 256 | *flock_count = ctx->flc_flock_cnt; | 257 | list_for_each_entry(lock, &ctx->flc_posix, fl_list) |
| 258 | ++(*fcntl_count); | ||
| 259 | list_for_each_entry(lock, &ctx->flc_flock, fl_list) | ||
| 260 | ++(*flock_count); | ||
| 261 | spin_unlock(&ctx->flc_lock); | ||
| 257 | } | 262 | } |
| 258 | dout("counted %d flock locks and %d fcntl locks", | 263 | dout("counted %d flock locks and %d fcntl locks", |
| 259 | *flock_count, *fcntl_count); | 264 | *flock_count, *fcntl_count); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8fe1f7a21b3e..a94b3e673182 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -1129,7 +1129,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
| 1129 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1129 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
| 1130 | struct file_lock *flock; | 1130 | struct file_lock *flock; |
| 1131 | struct file_lock_context *flctx = inode->i_flctx; | 1131 | struct file_lock_context *flctx = inode->i_flctx; |
| 1132 | unsigned int i; | 1132 | unsigned int count = 0, i; |
| 1133 | int rc = 0, xid, type; | 1133 | int rc = 0, xid, type; |
| 1134 | struct list_head locks_to_send, *el; | 1134 | struct list_head locks_to_send, *el; |
| 1135 | struct lock_to_push *lck, *tmp; | 1135 | struct lock_to_push *lck, *tmp; |
| @@ -1140,14 +1140,20 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
| 1140 | if (!flctx) | 1140 | if (!flctx) |
| 1141 | goto out; | 1141 | goto out; |
| 1142 | 1142 | ||
| 1143 | spin_lock(&flctx->flc_lock); | ||
| 1144 | list_for_each(el, &flctx->flc_posix) { | ||
| 1145 | count++; | ||
| 1146 | } | ||
| 1147 | spin_unlock(&flctx->flc_lock); | ||
| 1148 | |||
| 1143 | INIT_LIST_HEAD(&locks_to_send); | 1149 | INIT_LIST_HEAD(&locks_to_send); |
| 1144 | 1150 | ||
| 1145 | /* | 1151 | /* |
| 1146 | * Allocating flc_posix_cnt locks is enough because no FL_POSIX locks | 1152 | * Allocating count locks is enough because no FL_POSIX locks can be |
| 1147 | * can be added to the list while we are holding cinode->lock_sem that | 1153 | * added to the list while we are holding cinode->lock_sem that |
| 1148 | * protects locking operations of this inode. | 1154 | * protects locking operations of this inode. |
| 1149 | */ | 1155 | */ |
| 1150 | for (i = 0; i < flctx->flc_posix_cnt; i++) { | 1156 | for (i = 0; i < count; i++) { |
| 1151 | lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL); | 1157 | lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL); |
| 1152 | if (!lck) { | 1158 | if (!lck) { |
| 1153 | rc = -ENOMEM; | 1159 | rc = -ENOMEM; |
diff --git a/fs/locks.c b/fs/locks.c index 4753218f308e..365c82e1b3a9 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -681,21 +681,18 @@ static void locks_wake_up_blocks(struct file_lock *blocker) | |||
| 681 | } | 681 | } |
| 682 | 682 | ||
| 683 | static void | 683 | static void |
| 684 | locks_insert_lock_ctx(struct file_lock *fl, int *counter, | 684 | locks_insert_lock_ctx(struct file_lock *fl, struct list_head *before) |
| 685 | struct list_head *before) | ||
| 686 | { | 685 | { |
| 687 | fl->fl_nspid = get_pid(task_tgid(current)); | 686 | fl->fl_nspid = get_pid(task_tgid(current)); |
| 688 | list_add_tail(&fl->fl_list, before); | 687 | list_add_tail(&fl->fl_list, before); |
| 689 | ++*counter; | ||
| 690 | locks_insert_global_locks(fl); | 688 | locks_insert_global_locks(fl); |
| 691 | } | 689 | } |
| 692 | 690 | ||
| 693 | static void | 691 | static void |
| 694 | locks_unlink_lock_ctx(struct file_lock *fl, int *counter) | 692 | locks_unlink_lock_ctx(struct file_lock *fl) |
| 695 | { | 693 | { |
| 696 | locks_delete_global_locks(fl); | 694 | locks_delete_global_locks(fl); |
| 697 | list_del_init(&fl->fl_list); | 695 | list_del_init(&fl->fl_list); |
| 698 | --*counter; | ||
| 699 | if (fl->fl_nspid) { | 696 | if (fl->fl_nspid) { |
| 700 | put_pid(fl->fl_nspid); | 697 | put_pid(fl->fl_nspid); |
| 701 | fl->fl_nspid = NULL; | 698 | fl->fl_nspid = NULL; |
| @@ -704,10 +701,9 @@ locks_unlink_lock_ctx(struct file_lock *fl, int *counter) | |||
| 704 | } | 701 | } |
| 705 | 702 | ||
| 706 | static void | 703 | static void |
| 707 | locks_delete_lock_ctx(struct file_lock *fl, int *counter, | 704 | locks_delete_lock_ctx(struct file_lock *fl, struct list_head *dispose) |
| 708 | struct list_head *dispose) | ||
| 709 | { | 705 | { |
| 710 | locks_unlink_lock_ctx(fl, counter); | 706 | locks_unlink_lock_ctx(fl); |
| 711 | if (dispose) | 707 | if (dispose) |
| 712 | list_add(&fl->fl_list, dispose); | 708 | list_add(&fl->fl_list, dispose); |
| 713 | else | 709 | else |
| @@ -895,7 +891,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) | |||
| 895 | if (request->fl_type == fl->fl_type) | 891 | if (request->fl_type == fl->fl_type) |
| 896 | goto out; | 892 | goto out; |
| 897 | found = true; | 893 | found = true; |
| 898 | locks_delete_lock_ctx(fl, &ctx->flc_flock_cnt, &dispose); | 894 | locks_delete_lock_ctx(fl, &dispose); |
| 899 | break; | 895 | break; |
| 900 | } | 896 | } |
| 901 | 897 | ||
| @@ -905,16 +901,6 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) | |||
| 905 | goto out; | 901 | goto out; |
| 906 | } | 902 | } |
| 907 | 903 | ||
| 908 | /* | ||
| 909 | * If a higher-priority process was blocked on the old file lock, | ||
| 910 | * give it the opportunity to lock the file. | ||
| 911 | */ | ||
| 912 | if (found) { | ||
| 913 | spin_unlock(&ctx->flc_lock); | ||
| 914 | cond_resched(); | ||
| 915 | spin_lock(&ctx->flc_lock); | ||
| 916 | } | ||
| 917 | |||
| 918 | find_conflict: | 904 | find_conflict: |
| 919 | list_for_each_entry(fl, &ctx->flc_flock, fl_list) { | 905 | list_for_each_entry(fl, &ctx->flc_flock, fl_list) { |
| 920 | if (!flock_locks_conflict(request, fl)) | 906 | if (!flock_locks_conflict(request, fl)) |
| @@ -929,7 +915,7 @@ find_conflict: | |||
| 929 | if (request->fl_flags & FL_ACCESS) | 915 | if (request->fl_flags & FL_ACCESS) |
| 930 | goto out; | 916 | goto out; |
| 931 | locks_copy_lock(new_fl, request); | 917 | locks_copy_lock(new_fl, request); |
| 932 | locks_insert_lock_ctx(new_fl, &ctx->flc_flock_cnt, &ctx->flc_flock); | 918 | locks_insert_lock_ctx(new_fl, &ctx->flc_flock); |
| 933 | new_fl = NULL; | 919 | new_fl = NULL; |
| 934 | error = 0; | 920 | error = 0; |
| 935 | 921 | ||
| @@ -1046,8 +1032,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
| 1046 | else | 1032 | else |
| 1047 | request->fl_end = fl->fl_end; | 1033 | request->fl_end = fl->fl_end; |
| 1048 | if (added) { | 1034 | if (added) { |
| 1049 | locks_delete_lock_ctx(fl, &ctx->flc_posix_cnt, | 1035 | locks_delete_lock_ctx(fl, &dispose); |
| 1050 | &dispose); | ||
| 1051 | continue; | 1036 | continue; |
| 1052 | } | 1037 | } |
| 1053 | request = fl; | 1038 | request = fl; |
| @@ -1076,8 +1061,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
| 1076 | * one (This may happen several times). | 1061 | * one (This may happen several times). |
| 1077 | */ | 1062 | */ |
| 1078 | if (added) { | 1063 | if (added) { |
| 1079 | locks_delete_lock_ctx(fl, | 1064 | locks_delete_lock_ctx(fl, &dispose); |
| 1080 | &ctx->flc_posix_cnt, &dispose); | ||
| 1081 | continue; | 1065 | continue; |
| 1082 | } | 1066 | } |
| 1083 | /* | 1067 | /* |
| @@ -1093,10 +1077,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
| 1093 | locks_copy_lock(new_fl, request); | 1077 | locks_copy_lock(new_fl, request); |
| 1094 | request = new_fl; | 1078 | request = new_fl; |
| 1095 | new_fl = NULL; | 1079 | new_fl = NULL; |
| 1096 | locks_insert_lock_ctx(request, | 1080 | locks_insert_lock_ctx(request, &fl->fl_list); |
| 1097 | &ctx->flc_posix_cnt, &fl->fl_list); | 1081 | locks_delete_lock_ctx(fl, &dispose); |
| 1098 | locks_delete_lock_ctx(fl, | ||
| 1099 | &ctx->flc_posix_cnt, &dispose); | ||
| 1100 | added = true; | 1082 | added = true; |
| 1101 | } | 1083 | } |
| 1102 | } | 1084 | } |
| @@ -1124,8 +1106,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
| 1124 | goto out; | 1106 | goto out; |
| 1125 | } | 1107 | } |
| 1126 | locks_copy_lock(new_fl, request); | 1108 | locks_copy_lock(new_fl, request); |
| 1127 | locks_insert_lock_ctx(new_fl, &ctx->flc_posix_cnt, | 1109 | locks_insert_lock_ctx(new_fl, &fl->fl_list); |
| 1128 | &fl->fl_list); | 1110 | fl = new_fl; |
| 1129 | new_fl = NULL; | 1111 | new_fl = NULL; |
| 1130 | } | 1112 | } |
| 1131 | if (right) { | 1113 | if (right) { |
| @@ -1136,8 +1118,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
| 1136 | left = new_fl2; | 1118 | left = new_fl2; |
| 1137 | new_fl2 = NULL; | 1119 | new_fl2 = NULL; |
| 1138 | locks_copy_lock(left, right); | 1120 | locks_copy_lock(left, right); |
| 1139 | locks_insert_lock_ctx(left, &ctx->flc_posix_cnt, | 1121 | locks_insert_lock_ctx(left, &fl->fl_list); |
| 1140 | &fl->fl_list); | ||
| 1141 | } | 1122 | } |
| 1142 | right->fl_start = request->fl_end + 1; | 1123 | right->fl_start = request->fl_end + 1; |
| 1143 | locks_wake_up_blocks(right); | 1124 | locks_wake_up_blocks(right); |
| @@ -1321,7 +1302,6 @@ static void lease_clear_pending(struct file_lock *fl, int arg) | |||
| 1321 | /* We already had a lease on this file; just change its type */ | 1302 | /* We already had a lease on this file; just change its type */ |
| 1322 | int lease_modify(struct file_lock *fl, int arg, struct list_head *dispose) | 1303 | int lease_modify(struct file_lock *fl, int arg, struct list_head *dispose) |
| 1323 | { | 1304 | { |
| 1324 | struct file_lock_context *flctx; | ||
| 1325 | int error = assign_type(fl, arg); | 1305 | int error = assign_type(fl, arg); |
| 1326 | 1306 | ||
| 1327 | if (error) | 1307 | if (error) |
| @@ -1331,7 +1311,6 @@ int lease_modify(struct file_lock *fl, int arg, struct list_head *dispose) | |||
| 1331 | if (arg == F_UNLCK) { | 1311 | if (arg == F_UNLCK) { |
| 1332 | struct file *filp = fl->fl_file; | 1312 | struct file *filp = fl->fl_file; |
| 1333 | 1313 | ||
| 1334 | flctx = file_inode(filp)->i_flctx; | ||
| 1335 | f_delown(filp); | 1314 | f_delown(filp); |
| 1336 | filp->f_owner.signum = 0; | 1315 | filp->f_owner.signum = 0; |
| 1337 | fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync); | 1316 | fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync); |
| @@ -1339,7 +1318,7 @@ int lease_modify(struct file_lock *fl, int arg, struct list_head *dispose) | |||
| 1339 | printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync); | 1318 | printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync); |
| 1340 | fl->fl_fasync = NULL; | 1319 | fl->fl_fasync = NULL; |
| 1341 | } | 1320 | } |
| 1342 | locks_delete_lock_ctx(fl, &flctx->flc_lease_cnt, dispose); | 1321 | locks_delete_lock_ctx(fl, dispose); |
| 1343 | } | 1322 | } |
| 1344 | return 0; | 1323 | return 0; |
| 1345 | } | 1324 | } |
| @@ -1456,8 +1435,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) | |||
| 1456 | fl->fl_downgrade_time = break_time; | 1435 | fl->fl_downgrade_time = break_time; |
| 1457 | } | 1436 | } |
| 1458 | if (fl->fl_lmops->lm_break(fl)) | 1437 | if (fl->fl_lmops->lm_break(fl)) |
| 1459 | locks_delete_lock_ctx(fl, &ctx->flc_lease_cnt, | 1438 | locks_delete_lock_ctx(fl, &dispose); |
| 1460 | &dispose); | ||
| 1461 | } | 1439 | } |
| 1462 | 1440 | ||
| 1463 | if (list_empty(&ctx->flc_lease)) | 1441 | if (list_empty(&ctx->flc_lease)) |
| @@ -1697,7 +1675,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr | |||
| 1697 | if (!leases_enable) | 1675 | if (!leases_enable) |
| 1698 | goto out; | 1676 | goto out; |
| 1699 | 1677 | ||
| 1700 | locks_insert_lock_ctx(lease, &ctx->flc_lease_cnt, &ctx->flc_lease); | 1678 | locks_insert_lock_ctx(lease, &ctx->flc_lease); |
| 1701 | /* | 1679 | /* |
| 1702 | * The check in break_lease() is lockless. It's possible for another | 1680 | * The check in break_lease() is lockless. It's possible for another |
| 1703 | * open to race in after we did the earlier check for a conflicting | 1681 | * open to race in after we did the earlier check for a conflicting |
| @@ -1710,7 +1688,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr | |||
| 1710 | smp_mb(); | 1688 | smp_mb(); |
| 1711 | error = check_conflicting_open(dentry, arg, lease->fl_flags); | 1689 | error = check_conflicting_open(dentry, arg, lease->fl_flags); |
| 1712 | if (error) { | 1690 | if (error) { |
| 1713 | locks_unlink_lock_ctx(lease, &ctx->flc_lease_cnt); | 1691 | locks_unlink_lock_ctx(lease); |
| 1714 | goto out; | 1692 | goto out; |
| 1715 | } | 1693 | } |
| 1716 | 1694 | ||
| @@ -2448,7 +2426,8 @@ locks_remove_lease(struct file *filp) | |||
| 2448 | 2426 | ||
| 2449 | spin_lock(&ctx->flc_lock); | 2427 | spin_lock(&ctx->flc_lock); |
| 2450 | list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) | 2428 | list_for_each_entry_safe(fl, tmp, &ctx->flc_lease, fl_list) |
| 2451 | lease_modify(fl, F_UNLCK, &dispose); | 2429 | if (filp == fl->fl_file) |
| 2430 | lease_modify(fl, F_UNLCK, &dispose); | ||
| 2452 | spin_unlock(&ctx->flc_lock); | 2431 | spin_unlock(&ctx->flc_lock); |
| 2453 | locks_dispose_list(&dispose); | 2432 | locks_dispose_list(&dispose); |
| 2454 | } | 2433 | } |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 447932aed1e1..b4d71b5e1ff2 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -968,9 +968,6 @@ struct file_lock_context { | |||
| 968 | struct list_head flc_flock; | 968 | struct list_head flc_flock; |
| 969 | struct list_head flc_posix; | 969 | struct list_head flc_posix; |
| 970 | struct list_head flc_lease; | 970 | struct list_head flc_lease; |
| 971 | int flc_flock_cnt; | ||
| 972 | int flc_posix_cnt; | ||
| 973 | int flc_lease_cnt; | ||
| 974 | }; | 971 | }; |
| 975 | 972 | ||
| 976 | /* The following constant reflects the upper bound of the file/locking space */ | 973 | /* The following constant reflects the upper bound of the file/locking space */ |
