aboutsummaryrefslogtreecommitdiffstats
path: root/fs/locks.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/locks.c')
-rw-r--r--fs/locks.c108
1 files changed, 57 insertions, 51 deletions
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)
157int leases_enable = 1; 157int leases_enable = 1;
158int lease_break_time = 45; 158int 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
809posix_test_lock(struct file *filp, struct file_lock *fl) 808posix_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); 830out:
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
984static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock) 988static 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 */
1258int locks_mandatory_locked(struct file *file) 1256int 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:
2389void locks_remove_posix(struct file *filp, fl_owner_t owner) 2394void 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;