aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@primarydata.com>2015-01-16 15:05:55 -0500
committerJeff Layton <jeff.layton@primarydata.com>2015-01-16 15:09:25 -0500
commit5263e31e452fb84138b9bee061d5c06c0f359fea (patch)
tree68726ce860d2c824f605e6ec3f2adc9187d6dc86
parentc362781cadd37858c3d8f5d18b1e9957d4671298 (diff)
locks: move flock locks to file_lock_context
Signed-off-by: Jeff Layton <jlayton@primarydata.com> Acked-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/ceph/locks.c23
-rw-r--r--fs/locks.c54
-rw-r--r--fs/nfs/delegation.c19
-rw-r--r--fs/nfs/nfs4state.c42
-rw-r--r--fs/nfs/pagelist.c6
-rw-r--r--fs/nfs/write.c43
6 files changed, 152 insertions, 35 deletions
diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c
index 366dc2412605..917656ea8dcf 100644
--- a/fs/ceph/locks.c
+++ b/fs/ceph/locks.c
@@ -239,14 +239,16 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
239 return err; 239 return err;
240} 240}
241 241
242/** 242/*
243 * Must be called with lock_flocks() already held. Fills in the passed 243 * Fills in the passed counter variables, so you can prepare pagelist metadata
244 * counter variables, so you can prepare pagelist metadata before calling 244 * before calling ceph_encode_locks.
245 * ceph_encode_locks. 245 *
246 * FIXME: add counters to struct file_lock_context so we don't need to do this?
246 */ 247 */
247void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count) 248void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
248{ 249{
249 struct file_lock *lock; 250 struct file_lock *lock;
251 struct file_lock_context *ctx;
250 252
251 *fcntl_count = 0; 253 *fcntl_count = 0;
252 *flock_count = 0; 254 *flock_count = 0;
@@ -255,7 +257,11 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
255 for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { 257 for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
256 if (lock->fl_flags & FL_POSIX) 258 if (lock->fl_flags & FL_POSIX)
257 ++(*fcntl_count); 259 ++(*fcntl_count);
258 else if (lock->fl_flags & FL_FLOCK) 260 }
261
262 ctx = inode->i_flctx;
263 if (ctx) {
264 list_for_each_entry(lock, &ctx->flc_flock, fl_list)
259 ++(*flock_count); 265 ++(*flock_count);
260 } 266 }
261 spin_unlock(&inode->i_lock); 267 spin_unlock(&inode->i_lock);
@@ -273,6 +279,7 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
273 int num_fcntl_locks, int num_flock_locks) 279 int num_fcntl_locks, int num_flock_locks)
274{ 280{
275 struct file_lock *lock; 281 struct file_lock *lock;
282 struct file_lock_context *ctx;
276 int err = 0; 283 int err = 0;
277 int seen_fcntl = 0; 284 int seen_fcntl = 0;
278 int seen_flock = 0; 285 int seen_flock = 0;
@@ -295,8 +302,10 @@ int ceph_encode_locks_to_buffer(struct inode *inode,
295 ++l; 302 ++l;
296 } 303 }
297 } 304 }
298 for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { 305
299 if (lock->fl_flags & FL_FLOCK) { 306 ctx = inode->i_flctx;
307 if (ctx) {
308 list_for_each_entry(lock, &ctx->flc_flock, fl_list) {
300 ++seen_flock; 309 ++seen_flock;
301 if (seen_flock > num_flock_locks) { 310 if (seen_flock > num_flock_locks) {
302 err = -ENOSPC; 311 err = -ENOSPC;
diff --git a/fs/locks.c b/fs/locks.c
index 526d5fca67c8..055df53f19de 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -694,6 +694,14 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
694 locks_insert_global_locks(fl); 694 locks_insert_global_locks(fl);
695} 695}
696 696
697static void
698locks_insert_lock_ctx(struct file_lock *fl, struct list_head *before)
699{
700 fl->fl_nspid = get_pid(task_tgid(current));
701 list_add_tail(&fl->fl_list, before);
702 locks_insert_global_locks(fl);
703}
704
697/** 705/**
698 * locks_delete_lock - Delete a lock and then free it. 706 * locks_delete_lock - Delete a lock and then free it.
699 * @thisfl_p: pointer that points to the fl_next field of the previous 707 * @thisfl_p: pointer that points to the fl_next field of the previous
@@ -739,6 +747,18 @@ static void locks_delete_lock(struct file_lock **thisfl_p,
739 locks_free_lock(fl); 747 locks_free_lock(fl);
740} 748}
741 749
750static void
751locks_delete_lock_ctx(struct file_lock *fl, struct list_head *dispose)
752{
753 locks_delete_global_locks(fl);
754 if (fl->fl_nspid) {
755 put_pid(fl->fl_nspid);
756 fl->fl_nspid = NULL;
757 }
758 locks_wake_up_blocks(fl);
759 list_move(&fl->fl_list, dispose);
760}
761
742/* Determine if lock sys_fl blocks lock caller_fl. Common functionality 762/* Determine if lock sys_fl blocks lock caller_fl. Common functionality
743 * checks for shared/exclusive status of overlapping locks. 763 * checks for shared/exclusive status of overlapping locks.
744 */ 764 */
@@ -888,12 +908,17 @@ static int posix_locks_deadlock(struct file_lock *caller_fl,
888static int flock_lock_file(struct file *filp, struct file_lock *request) 908static int flock_lock_file(struct file *filp, struct file_lock *request)
889{ 909{
890 struct file_lock *new_fl = NULL; 910 struct file_lock *new_fl = NULL;
891 struct file_lock **before; 911 struct file_lock *fl;
892 struct inode * inode = file_inode(filp); 912 struct file_lock_context *ctx;
913 struct inode *inode = file_inode(filp);
893 int error = 0; 914 int error = 0;
894 int found = 0; 915 bool found = false;
895 LIST_HEAD(dispose); 916 LIST_HEAD(dispose);
896 917
918 ctx = locks_get_lock_context(inode);
919 if (!ctx)
920 return -ENOMEM;
921
897 if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) { 922 if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) {
898 new_fl = locks_alloc_lock(); 923 new_fl = locks_alloc_lock();
899 if (!new_fl) 924 if (!new_fl)
@@ -904,18 +929,13 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
904 if (request->fl_flags & FL_ACCESS) 929 if (request->fl_flags & FL_ACCESS)
905 goto find_conflict; 930 goto find_conflict;
906 931
907 for_each_lock(inode, before) { 932 list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
908 struct file_lock *fl = *before;
909 if (IS_POSIX(fl))
910 break;
911 if (IS_LEASE(fl))
912 continue;
913 if (filp != fl->fl_file) 933 if (filp != fl->fl_file)
914 continue; 934 continue;
915 if (request->fl_type == fl->fl_type) 935 if (request->fl_type == fl->fl_type)
916 goto out; 936 goto out;
917 found = 1; 937 found = true;
918 locks_delete_lock(before, &dispose); 938 locks_delete_lock_ctx(fl, &dispose);
919 break; 939 break;
920 } 940 }
921 941
@@ -936,12 +956,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
936 } 956 }
937 957
938find_conflict: 958find_conflict:
939 for_each_lock(inode, before) { 959 list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
940 struct file_lock *fl = *before;
941 if (IS_POSIX(fl))
942 break;
943 if (IS_LEASE(fl))
944 continue;
945 if (!flock_locks_conflict(request, fl)) 960 if (!flock_locks_conflict(request, fl))
946 continue; 961 continue;
947 error = -EAGAIN; 962 error = -EAGAIN;
@@ -954,7 +969,7 @@ find_conflict:
954 if (request->fl_flags & FL_ACCESS) 969 if (request->fl_flags & FL_ACCESS)
955 goto out; 970 goto out;
956 locks_copy_lock(new_fl, request); 971 locks_copy_lock(new_fl, request);
957 locks_insert_lock(before, new_fl); 972 locks_insert_lock_ctx(new_fl, &ctx->flc_flock);
958 new_fl = NULL; 973 new_fl = NULL;
959 error = 0; 974 error = 0;
960 975
@@ -2412,8 +2427,9 @@ locks_remove_flock(struct file *filp)
2412 .fl_type = F_UNLCK, 2427 .fl_type = F_UNLCK,
2413 .fl_end = OFFSET_MAX, 2428 .fl_end = OFFSET_MAX,
2414 }; 2429 };
2430 struct file_lock_context *flctx = file_inode(filp)->i_flctx;
2415 2431
2416 if (!file_inode(filp)->i_flock) 2432 if (!flctx || list_empty(&flctx->flc_flock))
2417 return; 2433 return;
2418 2434
2419 if (filp->f_op->flock) 2435 if (filp->f_op->flock)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 7f3f60641344..9f9f67b17e2b 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -85,15 +85,16 @@ 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 int status = 0; 89 int status = 0;
89 90
90 if (inode->i_flock == NULL) 91 if (inode->i_flock == NULL && inode->i_flctx == NULL)
91 goto out; 92 goto out;
92 93
93 /* Protect inode->i_flock using the i_lock */ 94 /* Protect inode->i_flock using the i_lock */
94 spin_lock(&inode->i_lock); 95 spin_lock(&inode->i_lock);
95 for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { 96 for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
96 if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) 97 if (!(fl->fl_flags & (FL_POSIX)))
97 continue; 98 continue;
98 if (nfs_file_open_context(fl->fl_file) != ctx) 99 if (nfs_file_open_context(fl->fl_file) != ctx)
99 continue; 100 continue;
@@ -103,6 +104,20 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
103 goto out; 104 goto out;
104 spin_lock(&inode->i_lock); 105 spin_lock(&inode->i_lock);
105 } 106 }
107
108 flctx = inode->i_flctx;
109 if (flctx) {
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 }
106 spin_unlock(&inode->i_lock); 121 spin_unlock(&inode->i_lock);
107out: 122out:
108 return status; 123 return status;
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 5194933ed419..65c404bf61ae 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1366,8 +1366,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
1366 struct nfs_inode *nfsi = NFS_I(inode); 1366 struct nfs_inode *nfsi = NFS_I(inode);
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 1370
1370 if (inode->i_flock == NULL) 1371 if (inode->i_flock == NULL && flctx == NULL)
1371 return 0; 1372 return 0;
1372 1373
1373 /* Guard against delegation returns and new lock/unlock calls */ 1374 /* Guard against delegation returns and new lock/unlock calls */
@@ -1375,7 +1376,7 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
1375 /* Protect inode->i_flock using the BKL */ 1376 /* Protect inode->i_flock using the BKL */
1376 spin_lock(&inode->i_lock); 1377 spin_lock(&inode->i_lock);
1377 for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { 1378 for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
1378 if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) 1379 if (!(fl->fl_flags & FL_POSIX))
1379 continue; 1380 continue;
1380 if (nfs_file_open_context(fl->fl_file)->state != state) 1381 if (nfs_file_open_context(fl->fl_file)->state != state)
1381 continue; 1382 continue;
@@ -1408,6 +1409,43 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
1408 } 1409 }
1409 spin_lock(&inode->i_lock); 1410 spin_lock(&inode->i_lock);
1410 } 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)
1418 continue;
1419 spin_unlock(&inode->i_lock);
1420 status = ops->recover_lock(state, fl);
1421 switch (status) {
1422 case 0:
1423 break;
1424 case -ESTALE:
1425 case -NFS4ERR_ADMIN_REVOKED:
1426 case -NFS4ERR_STALE_STATEID:
1427 case -NFS4ERR_BAD_STATEID:
1428 case -NFS4ERR_EXPIRED:
1429 case -NFS4ERR_NO_GRACE:
1430 case -NFS4ERR_STALE_CLIENTID:
1431 case -NFS4ERR_BADSESSION:
1432 case -NFS4ERR_BADSLOT:
1433 case -NFS4ERR_BAD_HIGH_SLOT:
1434 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
1435 goto out;
1436 default:
1437 pr_err("NFS: %s: unhandled error %d\n",
1438 __func__, status);
1439 case -ENOMEM:
1440 case -NFS4ERR_DENIED:
1441 case -NFS4ERR_RECLAIM_BAD:
1442 case -NFS4ERR_RECLAIM_CONFLICT:
1443 /* kill_proc(fl->fl_pid, SIGLOST, 1); */
1444 status = 0;
1445 }
1446 spin_lock(&inode->i_lock);
1447 }
1448out_unlock:
1411 spin_unlock(&inode->i_lock); 1449 spin_unlock(&inode->i_lock);
1412out: 1450out:
1413 up_write(&nfsi->rwsem); 1451 up_write(&nfsi->rwsem);
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 2b5e769beb16..a3b62e15b444 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -826,6 +826,7 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
826 struct nfs_pageio_descriptor *pgio) 826 struct nfs_pageio_descriptor *pgio)
827{ 827{
828 size_t size; 828 size_t size;
829 struct file_lock_context *flctx;
829 830
830 if (prev) { 831 if (prev) {
831 if (!nfs_match_open_context(req->wb_context, prev->wb_context)) 832 if (!nfs_match_open_context(req->wb_context, prev->wb_context))
@@ -834,6 +835,11 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
834 !nfs_match_lock_context(req->wb_lock_context, 835 !nfs_match_lock_context(req->wb_lock_context,
835 prev->wb_lock_context)) 836 prev->wb_lock_context))
836 return false; 837 return false;
838 flctx = req->wb_context->dentry->d_inode->i_flctx;
839 if (flctx != NULL && !list_empty_careful(&flctx->flc_flock) &&
840 !nfs_match_lock_context(req->wb_lock_context,
841 prev->wb_lock_context))
842 return false;
837 if (req_offset(req) != req_offset(prev) + prev->wb_bytes) 843 if (req_offset(req) != req_offset(prev) + prev->wb_bytes)
838 return false; 844 return false;
839 if (req->wb_page == prev->wb_page) { 845 if (req->wb_page == prev->wb_page) {
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index af3af685a9e3..e072aeb34195 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -1113,6 +1113,11 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
1113 do_flush |= l_ctx->lockowner.l_owner != current->files 1113 do_flush |= l_ctx->lockowner.l_owner != current->files
1114 || l_ctx->lockowner.l_pid != current->tgid; 1114 || l_ctx->lockowner.l_pid != current->tgid;
1115 } 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
1119 || l_ctx->lockowner.l_pid != current->tgid;
1120 }
1116 nfs_release_request(req); 1121 nfs_release_request(req);
1117 if (!do_flush) 1122 if (!do_flush)
1118 return 0; 1123 return 0;
@@ -1170,6 +1175,13 @@ out:
1170 return PageUptodate(page) != 0; 1175 return PageUptodate(page) != 0;
1171} 1176}
1172 1177
1178static bool
1179is_whole_file_wrlock(struct file_lock *fl)
1180{
1181 return fl->fl_start == 0 && fl->fl_end == OFFSET_MAX &&
1182 fl->fl_type == F_WRLCK;
1183}
1184
1173/* If we know the page is up to date, and we're not using byte range locks (or 1185/* If we know the page is up to date, and we're not using byte range locks (or
1174 * if we have the whole file locked for writing), it may be more efficient to 1186 * if we have the whole file locked for writing), it may be more efficient to
1175 * extend the write to cover the entire page in order to avoid fragmentation 1187 * extend the write to cover the entire page in order to avoid fragmentation
@@ -1180,17 +1192,38 @@ out:
1180 */ 1192 */
1181static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode) 1193static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode)
1182{ 1194{
1195 int ret;
1196 struct file_lock_context *flctx = inode->i_flctx;
1197 struct file_lock *fl;
1198
1183 if (file->f_flags & O_DSYNC) 1199 if (file->f_flags & O_DSYNC)
1184 return 0; 1200 return 0;
1185 if (!nfs_write_pageuptodate(page, inode)) 1201 if (!nfs_write_pageuptodate(page, inode))
1186 return 0; 1202 return 0;
1187 if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) 1203 if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
1188 return 1; 1204 return 1;
1189 if (inode->i_flock == NULL || (inode->i_flock->fl_start == 0 && 1205 if (!inode->i_flock && !flctx)
1190 inode->i_flock->fl_end == OFFSET_MAX && 1206 return 0;
1191 inode->i_flock->fl_type != F_RDLCK)) 1207
1192 return 1; 1208 /* Check to see if there are whole file write locks */
1193 return 0; 1209 spin_lock(&inode->i_lock);
1210 ret = 0;
1211
1212 fl = inode->i_flock;
1213 if (fl && is_whole_file_wrlock(fl)) {
1214 ret = 1;
1215 goto out;
1216 }
1217
1218 if (!list_empty(&flctx->flc_flock)) {
1219 fl = list_first_entry(&flctx->flc_flock, struct file_lock,
1220 fl_list);
1221 if (fl->fl_type == F_WRLCK)
1222 ret = 1;
1223 }
1224out:
1225 spin_unlock(&inode->i_lock);
1226 return ret;
1194} 1227}
1195 1228
1196/* 1229/*