aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJeff Layton <jlayton@primarydata.com>2014-08-11 14:20:31 -0400
committerJeff Layton <jlayton@primarydata.com>2014-08-14 10:07:47 -0400
commited9814d85810c27670987b40c77e8a07105838fe (patch)
tree445d69a6adf6a9f9aaedd118f714c07abc96ba1b /fs
parentb84d49f9440b2b039828f3eb114e4bd4ebeb0c54 (diff)
locks: defer freeing locks in locks_delete_lock until after i_lock has been dropped
In commit 72f98e72551fa (locks: turn lock_flocks into a spinlock), we moved from using the BKL to a global spinlock. With this change, we lost the ability to block in the fl_release_private operation. This is problematic for NFS (and probably some other filesystems as well). Add a new list_head argument to locks_delete_lock. If that argument is non-NULL, then queue any locks that we want to free to the list instead of freeing them. Then, add a new locks_dispose_list function that will walk such a list and call locks_free_lock on them after the i_lock has been dropped. Finally, change all of the callers of locks_delete_lock to pass in a list_head, except for lease_modify. That function can be called long after the i_lock has been acquired. Deferring the freeing of a lease after unlocking it in that function is non-trivial until we overhaul some of the spinlocking in the lease code. Currently though, no filesystem that sets fl_release_private supports leases, so this is not currently a problem. We'll eventually want to make the same change in the lease code, but it needs a lot more work before we can reasonably do so. Acked-by: J. Bruce Fields <bfields@fieldses.org> Signed-off-by: Jeff Layton <jlayton@primarydata.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/locks.c38
1 files changed, 30 insertions, 8 deletions
diff --git a/fs/locks.c b/fs/locks.c
index 7dd4defb4d8d..4ce087cca501 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -247,6 +247,18 @@ void locks_free_lock(struct file_lock *fl)
247} 247}
248EXPORT_SYMBOL(locks_free_lock); 248EXPORT_SYMBOL(locks_free_lock);
249 249
250static void
251locks_dispose_list(struct list_head *dispose)
252{
253 struct file_lock *fl;
254
255 while (!list_empty(dispose)) {
256 fl = list_first_entry(dispose, struct file_lock, fl_block);
257 list_del_init(&fl->fl_block);
258 locks_free_lock(fl);
259 }
260}
261
250void locks_init_lock(struct file_lock *fl) 262void locks_init_lock(struct file_lock *fl)
251{ 263{
252 memset(fl, 0, sizeof(struct file_lock)); 264 memset(fl, 0, sizeof(struct file_lock));
@@ -651,12 +663,16 @@ static void locks_unlink_lock(struct file_lock **thisfl_p)
651 * 663 *
652 * Must be called with i_lock held! 664 * Must be called with i_lock held!
653 */ 665 */
654static void locks_delete_lock(struct file_lock **thisfl_p) 666static void locks_delete_lock(struct file_lock **thisfl_p,
667 struct list_head *dispose)
655{ 668{
656 struct file_lock *fl = *thisfl_p; 669 struct file_lock *fl = *thisfl_p;
657 670
658 locks_unlink_lock(thisfl_p); 671 locks_unlink_lock(thisfl_p);
659 locks_free_lock(fl); 672 if (dispose)
673 list_add(&fl->fl_block, dispose);
674 else
675 locks_free_lock(fl);
660} 676}
661 677
662/* Determine if lock sys_fl blocks lock caller_fl. Common functionality 678/* Determine if lock sys_fl blocks lock caller_fl. Common functionality
@@ -812,6 +828,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
812 struct inode * inode = file_inode(filp); 828 struct inode * inode = file_inode(filp);
813 int error = 0; 829 int error = 0;
814 int found = 0; 830 int found = 0;
831 LIST_HEAD(dispose);
815 832
816 if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) { 833 if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) {
817 new_fl = locks_alloc_lock(); 834 new_fl = locks_alloc_lock();
@@ -834,7 +851,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
834 if (request->fl_type == fl->fl_type) 851 if (request->fl_type == fl->fl_type)
835 goto out; 852 goto out;
836 found = 1; 853 found = 1;
837 locks_delete_lock(before); 854 locks_delete_lock(before, &dispose);
838 break; 855 break;
839 } 856 }
840 857
@@ -881,6 +898,7 @@ out:
881 spin_unlock(&inode->i_lock); 898 spin_unlock(&inode->i_lock);
882 if (new_fl) 899 if (new_fl)
883 locks_free_lock(new_fl); 900 locks_free_lock(new_fl);
901 locks_dispose_list(&dispose);
884 return error; 902 return error;
885} 903}
886 904
@@ -894,6 +912,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
894 struct file_lock **before; 912 struct file_lock **before;
895 int error; 913 int error;
896 bool added = false; 914 bool added = false;
915 LIST_HEAD(dispose);
897 916
898 /* 917 /*
899 * We may need two file_lock structures for this operation, 918 * We may need two file_lock structures for this operation,
@@ -989,7 +1008,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
989 else 1008 else
990 request->fl_end = fl->fl_end; 1009 request->fl_end = fl->fl_end;
991 if (added) { 1010 if (added) {
992 locks_delete_lock(before); 1011 locks_delete_lock(before, &dispose);
993 continue; 1012 continue;
994 } 1013 }
995 request = fl; 1014 request = fl;
@@ -1019,7 +1038,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
1019 * one (This may happen several times). 1038 * one (This may happen several times).
1020 */ 1039 */
1021 if (added) { 1040 if (added) {
1022 locks_delete_lock(before); 1041 locks_delete_lock(before, &dispose);
1023 continue; 1042 continue;
1024 } 1043 }
1025 /* 1044 /*
@@ -1035,7 +1054,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
1035 locks_copy_lock(new_fl, request); 1054 locks_copy_lock(new_fl, request);
1036 request = new_fl; 1055 request = new_fl;
1037 new_fl = NULL; 1056 new_fl = NULL;
1038 locks_delete_lock(before); 1057 locks_delete_lock(before, &dispose);
1039 locks_insert_lock(before, request); 1058 locks_insert_lock(before, request);
1040 added = true; 1059 added = true;
1041 } 1060 }
@@ -1097,6 +1116,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
1097 locks_free_lock(new_fl); 1116 locks_free_lock(new_fl);
1098 if (new_fl2) 1117 if (new_fl2)
1099 locks_free_lock(new_fl2); 1118 locks_free_lock(new_fl2);
1119 locks_dispose_list(&dispose);
1100 return error; 1120 return error;
1101} 1121}
1102 1122
@@ -1272,7 +1292,7 @@ int lease_modify(struct file_lock **before, int arg)
1272 printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync); 1292 printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
1273 fl->fl_fasync = NULL; 1293 fl->fl_fasync = NULL;
1274 } 1294 }
1275 locks_delete_lock(before); 1295 locks_delete_lock(before, NULL);
1276 } 1296 }
1277 return 0; 1297 return 0;
1278} 1298}
@@ -2324,6 +2344,7 @@ void locks_remove_file(struct file *filp)
2324 struct inode * inode = file_inode(filp); 2344 struct inode * inode = file_inode(filp);
2325 struct file_lock *fl; 2345 struct file_lock *fl;
2326 struct file_lock **before; 2346 struct file_lock **before;
2347 LIST_HEAD(dispose);
2327 2348
2328 if (!inode->i_flock) 2349 if (!inode->i_flock)
2329 return; 2350 return;
@@ -2369,12 +2390,13 @@ void locks_remove_file(struct file *filp)
2369 fl->fl_type, fl->fl_flags, 2390 fl->fl_type, fl->fl_flags,
2370 fl->fl_start, fl->fl_end); 2391 fl->fl_start, fl->fl_end);
2371 2392
2372 locks_delete_lock(before); 2393 locks_delete_lock(before, &dispose);
2373 continue; 2394 continue;
2374 } 2395 }
2375 before = &fl->fl_next; 2396 before = &fl->fl_next;
2376 } 2397 }
2377 spin_unlock(&inode->i_lock); 2398 spin_unlock(&inode->i_lock);
2399 locks_dispose_list(&dispose);
2378} 2400}
2379 2401
2380/** 2402/**