From: Jeff Layton <jlayton@redhat.com>
To: viro@zeniv.linux.org.uk, matthew@wil.cx, bfields@fieldses.org
Cc: linux-cifs@vger.kernel.org, linux-nfs@vger.kernel.org,
cluster-devel@redhat.com, sage@inktank.com,
samba-technical@lists.samba.org, Trond.Myklebust@netapp.com,
linux-kernel@vger.kernel.org, piastryyy@gmail.com,
linux-afs@lists.infradead.org, dhowells@redhat.com,
smfrench@gmail.com, linux-fsdevel@vger.kernel.org,
ceph-devel@vger.kernel.org, akpm@linux-foundation.org
Subject: [PATCH v2 08/14] locks: ensure that deadlock detection is atomic with respect to blocked_list modification
Date: Tue, 11 Jun 2013 07:09:02 -0400 [thread overview]
Message-ID: <1370948948-31784-9-git-send-email-jlayton@redhat.com> (raw)
In-Reply-To: <1370948948-31784-1-git-send-email-jlayton@redhat.com>
Sound deadlock detection requires that we hold the file-lock state
steady while checking for them, and also ensure that updates to that
state are atomic with respect to those checks.
For the checking and insertion side, push the acquisition of the
global lock into __posix_lock_file and ensure that checking and update
of the global lists are done without dropping the lock in between.
On the removal side, when waking up blocked POSIX lock waiters, take
the global lock before walking the blocked list and dequeue the waiters
from the global list prior to removal from the i_flock list.
With this, deadlock detection should be race free while we minimize
excessive file_lock_lock thrashing.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/locks.c | 71 +++++++++++++++++++++++++++++++++++++++++++----------------
1 files changed, 52 insertions(+), 19 deletions(-)
diff --git a/fs/locks.c b/fs/locks.c
index d7342a3..b8cd1b1 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -475,16 +475,20 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
static inline void
locks_insert_global_blocked(struct file_lock *waiter)
{
- spin_lock(&file_lock_lock);
list_add(&waiter->fl_link, &blocked_list);
- spin_unlock(&file_lock_lock);
+}
+
+static inline void
+__locks_delete_global_blocked(struct file_lock *waiter)
+{
+ list_del_init(&waiter->fl_link);
}
static inline void
locks_delete_global_blocked(struct file_lock *waiter)
{
spin_lock(&file_lock_lock);
- list_del_init(&waiter->fl_link);
+ __locks_delete_global_blocked(waiter);
spin_unlock(&file_lock_lock);
}
@@ -509,7 +513,6 @@ locks_delete_global_locks(struct file_lock *waiter)
*/
static void __locks_delete_block(struct file_lock *waiter)
{
- locks_delete_global_blocked(waiter);
list_del_init(&waiter->fl_block);
waiter->fl_next = NULL;
}
@@ -558,6 +561,30 @@ static void locks_wake_up_blocks(struct file_lock *blocker)
}
}
+/*
+ * Wake up processes blocked waiting for blocker. In the FL_POSIX case, we must
+ * also take the global file_lock_lock and dequeue it from the global blocked
+ * list as we wake the processes.
+ *
+ * Must be called with the inode->i_lock of the blocker held!
+ */
+static void locks_wake_up_posix_blocks(struct file_lock *blocker)
+{
+ spin_lock(&file_lock_lock);
+ while (!list_empty(&blocker->fl_block)) {
+ struct file_lock *waiter;
+
+ waiter = list_first_entry(&blocker->fl_block,
+ struct file_lock, fl_block);
+ __locks_delete_global_blocked(waiter);
+ __locks_delete_block(waiter);
+ if (waiter->fl_lmops && waiter->fl_lmops->lm_notify)
+ waiter->fl_lmops->lm_notify(waiter);
+ else
+ wake_up(&waiter->fl_wait);
+ }
+ spin_unlock(&file_lock_lock);
+}
/* Insert file lock fl into an inode's lock list at the position indicated
* by pos. At the same time add the lock to the global file lock list.
*/
@@ -592,7 +619,11 @@ static void locks_delete_lock(struct file_lock **thisfl_p)
fl->fl_nspid = NULL;
}
- locks_wake_up_blocks(fl);
+ if (IS_POSIX(fl))
+ locks_wake_up_posix_blocks(fl);
+ else
+ locks_wake_up_blocks(fl);
+
locks_free_lock(fl);
}
@@ -705,6 +736,7 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl)
return NULL;
}
+/* Must be called with the file_lock_lock held! */
static int posix_locks_deadlock(struct file_lock *caller_fl,
struct file_lock *block_fl)
{
@@ -848,17 +880,13 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
if (!(request->fl_flags & FL_SLEEP))
goto out;
error = -EDEADLK;
- /*
- * XXX: potential race here. We should be adding the
- * file_lock to the global list before releasing lock.
- */
spin_lock(&file_lock_lock);
- if (posix_locks_deadlock(request, fl))
- goto out;
+ if (likely(!posix_locks_deadlock(request, fl))) {
+ error = FILE_LOCK_DEFERRED;
+ locks_insert_block(fl, request);
+ locks_insert_global_blocked(request);
+ }
spin_unlock(&file_lock_lock);
- error = FILE_LOCK_DEFERRED;
- locks_insert_block(fl, request);
- locks_insert_global_blocked(request);
goto out;
}
}
@@ -949,7 +977,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
* as the change in lock type might satisfy
* their needs.
*/
- locks_wake_up_blocks(fl);
+ locks_wake_up_posix_blocks(fl);
fl->fl_start = request->fl_start;
fl->fl_end = request->fl_end;
fl->fl_type = request->fl_type;
@@ -1001,11 +1029,11 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
locks_insert_lock(before, left);
}
right->fl_start = request->fl_end + 1;
- locks_wake_up_blocks(right);
+ locks_wake_up_posix_blocks(right);
}
if (left) {
left->fl_end = request->fl_start - 1;
- locks_wake_up_blocks(left);
+ locks_wake_up_posix_blocks(left);
}
out:
spin_unlock(&inode->i_lock);
@@ -1061,6 +1089,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
if (!error)
continue;
+ locks_delete_global_blocked(fl);
locks_delete_block(fl);
break;
}
@@ -1139,6 +1168,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
continue;
}
+ locks_delete_global_blocked(&fl);
locks_delete_block(&fl);
break;
}
@@ -1851,6 +1881,7 @@ static int do_lock_file_wait(struct file *filp, unsigned int cmd,
if (!error)
continue;
+ locks_delete_global_blocked(fl);
locks_delete_block(fl);
break;
}
@@ -2148,10 +2179,12 @@ posix_unblock_lock(struct file *filp, struct file_lock *waiter)
int status = 0;
spin_lock(&inode->i_lock);
- if (waiter->fl_next)
+ if (waiter->fl_next) {
+ locks_delete_global_blocked(waiter);
__locks_delete_block(waiter);
- else
+ } else {
status = -ENOENT;
+ }
spin_unlock(&inode->i_lock);
return status;
}
--
1.7.1
next prev parent reply other threads:[~2013-06-11 11:09 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-06-11 11:08 [PATCH v2 00/14] locks: scalability improvements for file locking Jeff Layton
2013-06-11 11:08 ` [PATCH v2 02/14] locks: make generic_add_lease and generic_delete_lease static Jeff Layton
2013-06-11 11:08 ` [PATCH v2 03/14] locks: comment cleanups and clarifications Jeff Layton
2013-06-11 11:08 ` [PATCH v2 04/14] locks: make "added" in __posix_lock_file a bool Jeff Layton
2013-06-11 11:08 ` [PATCH v2 05/14] locks: encapsulate the fl_link list handling Jeff Layton
2013-06-11 11:09 ` [PATCH v2 07/14] locks: convert to i_lock to protect i_flock list Jeff Layton
2013-06-13 14:41 ` J. Bruce Fields
2013-06-13 15:09 ` Jeff Layton
2013-06-11 11:09 ` Jeff Layton [this message]
2013-06-11 11:09 ` [PATCH v2 09/14] locks: convert fl_link to a hlist_node Jeff Layton
2013-06-11 11:09 ` [PATCH v2 10/14] locks: turn the blocked_list into a hashtable Jeff Layton
2013-06-13 14:50 ` J. Bruce Fields
2013-06-11 11:09 ` [PATCH v2 11/14] locks: add a new "lm_owner_key" lock operation Jeff Layton
[not found] ` <1370948948-31784-12-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-06-13 15:00 ` J. Bruce Fields
[not found] ` <1370948948-31784-1-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-06-11 11:08 ` [PATCH v2 01/14] cifs: use posix_unblock_lock instead of locks_delete_block Jeff Layton
2013-06-11 11:09 ` [PATCH v2 06/14] locks: don't walk inode->i_flock list in locks_show Jeff Layton
2013-06-13 19:45 ` J. Bruce Fields
2013-06-13 20:26 ` Jeff Layton
[not found] ` <51BB040C.3050101@samba.org>
2013-06-15 11:05 ` Jeff Layton
[not found] ` <20130615070535.6367eed9-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2013-06-15 15:04 ` Simo
2013-06-11 11:09 ` [PATCH v2 12/14] locks: give the blocked_hash its own spinlock Jeff Layton
[not found] ` <1370948948-31784-13-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-06-13 15:02 ` J. Bruce Fields
2013-06-13 15:18 ` Jeff Layton
[not found] ` <20130613111844.59421622-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2013-06-13 15:20 ` J. Bruce Fields
2013-06-11 16:04 ` [PATCH v2 00/14] locks: scalability improvements for file locking J. Bruce Fields
2013-06-11 16:35 ` Jeff Layton
2013-06-11 11:09 ` [PATCH v2 13/14] seq_file: add seq_list_*_percpu helpers Jeff Layton
[not found] ` <1370948948-31784-14-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-06-13 15:27 ` J. Bruce Fields
2013-06-11 11:09 ` [PATCH v2 14/14] locks: move file_lock_list to a set of percpu hlist_heads and convert file_lock_lock to an lglock Jeff Layton
[not found] ` <1370948948-31784-15-git-send-email-jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-06-13 15:37 ` J. Bruce Fields
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1370948948-31784-9-git-send-email-jlayton@redhat.com \
--to=jlayton@redhat.com \
--cc=Trond.Myklebust@netapp.com \
--cc=akpm@linux-foundation.org \
--cc=bfields@fieldses.org \
--cc=ceph-devel@vger.kernel.org \
--cc=cluster-devel@redhat.com \
--cc=dhowells@redhat.com \
--cc=linux-afs@lists.infradead.org \
--cc=linux-cifs@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=matthew@wil.cx \
--cc=piastryyy@gmail.com \
--cc=sage@inktank.com \
--cc=samba-technical@lists.samba.org \
--cc=smfrench@gmail.com \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).