aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2013-06-21 08:58:15 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-06-29 04:57:42 -0400
commit1c8c601a8c0dc59fe64907dcd9d512a3d181ddc7 (patch)
tree1a9c91de460a7c2f9fd6ad77060be484456e49b9 /fs/cifs
parent889746917193ab3007a779d65231510715b20fb6 (diff)
locks: protect most of the file_lock handling with i_lock
Having a global lock that protects all of this code is a clear scalability problem. Instead of doing that, move most of the code to be protected by the i_lock instead. The exceptions are the global lists that the ->fl_link sits on, and the ->fl_block list. ->fl_link is what connects these structures to the global lists, so we must ensure that we hold those locks when iterating over or updating these lists. Furthermore, sound deadlock detection requires that we hold the blocked_list state steady while checking for loops. We also must ensure that the search and update to the list are atomic. For the checking and insertion side of the blocked_list, push the acquisition of the global lock into __posix_lock_file and ensure that checking and update of the blocked_list is done without dropping the lock in between. On the removal side, when waking up blocked lock waiters, take the global lock before walking the blocked list and dequeue the waiters from the global list prior to removal from the fl_block list. With this, deadlock detection should be race free while we minimize excessive file_lock_lock thrashing. Finally, in order to avoid a lock inversion problem when handling /proc/locks output we must ensure that manipulations of the fl_block list are also protected by the file_lock_lock. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsfs.c2
-rw-r--r--fs/cifs/file.c13
2 files changed, 8 insertions, 7 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 540c1ccfcdb2..a445e71746fa 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -765,7 +765,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
765 765
766static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) 766static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
767{ 767{
768 /* note that this is called by vfs setlease with lock_flocks held 768 /* note that this is called by vfs setlease with i_lock held
769 to protect *lease from going away */ 769 to protect *lease from going away */
770 struct inode *inode = file_inode(file); 770 struct inode *inode = file_inode(file);
771 struct cifsFileInfo *cfile = file->private_data; 771 struct cifsFileInfo *cfile = file->private_data;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 1686e4085646..0630710a9c3f 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1092,6 +1092,7 @@ struct lock_to_push {
1092static int 1092static int
1093cifs_push_posix_locks(struct cifsFileInfo *cfile) 1093cifs_push_posix_locks(struct cifsFileInfo *cfile)
1094{ 1094{
1095 struct inode *inode = cfile->dentry->d_inode;
1095 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 1096 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
1096 struct file_lock *flock, **before; 1097 struct file_lock *flock, **before;
1097 unsigned int count = 0, i = 0; 1098 unsigned int count = 0, i = 0;
@@ -1102,12 +1103,12 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
1102 1103
1103 xid = get_xid(); 1104 xid = get_xid();
1104 1105
1105 lock_flocks(); 1106 spin_lock(&inode->i_lock);
1106 cifs_for_each_lock(cfile->dentry->d_inode, before) { 1107 cifs_for_each_lock(inode, before) {
1107 if ((*before)->fl_flags & FL_POSIX) 1108 if ((*before)->fl_flags & FL_POSIX)
1108 count++; 1109 count++;
1109 } 1110 }
1110 unlock_flocks(); 1111 spin_unlock(&inode->i_lock);
1111 1112
1112 INIT_LIST_HEAD(&locks_to_send); 1113 INIT_LIST_HEAD(&locks_to_send);
1113 1114
@@ -1126,8 +1127,8 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
1126 } 1127 }
1127 1128
1128 el = locks_to_send.next; 1129 el = locks_to_send.next;
1129 lock_flocks(); 1130 spin_lock(&inode->i_lock);
1130 cifs_for_each_lock(cfile->dentry->d_inode, before) { 1131 cifs_for_each_lock(inode, before) {
1131 flock = *before; 1132 flock = *before;
1132 if ((flock->fl_flags & FL_POSIX) == 0) 1133 if ((flock->fl_flags & FL_POSIX) == 0)
1133 continue; 1134 continue;
@@ -1152,7 +1153,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
1152 lck->offset = flock->fl_start; 1153 lck->offset = flock->fl_start;
1153 el = el->next; 1154 el = el->next;
1154 } 1155 }
1155 unlock_flocks(); 1156 spin_unlock(&inode->i_lock);
1156 1157
1157 list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) { 1158 list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
1158 int stored_rc; 1159 int stored_rc;