[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20070411191012.15499.94466.stgit@warthog.cambridge.redhat.com>
Date: Wed, 11 Apr 2007 20:10:12 +0100
From: David Howells <dhowells@...hat.com>
To: torvalds@...l.org, akpm@...l.org
Cc: linux-kernel@...r.kernel.org, linux-fsdevel@...r.kernel.org,
netdev@...r.kernel.org, dhowells@...hat.com
Subject: [PATCH 3/8] AFS: Fix callback aggregator work item deadlock
Fix a deadlock in the give-up-callback aggregator dispatcher work item whereby
the aggregator runs on keventd as does timed autounmount, thus leading to the
unmount blocking keventd whilst waiting for keventd to run the aggregator when
the give-up-callback buffer is full.
Signed-Off-By: David Howells <dhowells@...hat.com>
---
fs/afs/callback.c | 14 +++++++++-----
fs/afs/fsclient.c | 6 ++++--
2 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index fdad11c..1533b49 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -232,7 +232,8 @@ static void afs_do_give_up_callback(struct afs_server *server,
* possible to ship in one operation */
switch (atomic_inc_return(&server->cb_break_n)) {
case 1 ... AFSCBMAX - 1:
- schedule_delayed_work(&server->cb_break_work, HZ * 2);
+ queue_delayed_work(afs_callback_update_worker,
+ &server->cb_break_work, HZ * 2);
break;
case AFSCBMAX:
afs_flush_callback_breaks(server);
@@ -271,9 +272,11 @@ void afs_give_up_callback(struct afs_vnode *vnode)
spin_lock(&server->cb_lock);
if (vnode->cb_promised && afs_breakring_space(server) == 0) {
add_wait_queue(&server->cb_break_waitq, &myself);
- while (vnode->cb_promised &&
- afs_breakring_space(server) == 0) {
+ for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
+ if (!vnode->cb_promised ||
+ afs_breakring_space(server) != 0)
+ break;
spin_unlock(&server->cb_lock);
schedule();
spin_lock(&server->cb_lock);
@@ -315,7 +318,8 @@ void afs_dispatch_give_up_callbacks(struct work_struct *work)
void afs_flush_callback_breaks(struct afs_server *server)
{
if (try_to_cancel_delayed_work(&server->cb_break_work) >= 0)
- schedule_delayed_work(&server->cb_break_work, 0);
+ queue_delayed_work(afs_callback_update_worker,
+ &server->cb_break_work, 0);
}
#if 0
@@ -426,7 +430,7 @@ static void afs_callback_updater(struct work_struct *work)
int __init afs_callback_update_init(void)
{
afs_callback_update_worker =
- create_singlethread_workqueue("kafs_cbupdated");
+ create_singlethread_workqueue("kafs_callbackd");
return afs_callback_update_worker ? 0 : -ENOMEM;
}
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index d955178..e2a36f8 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -355,10 +355,11 @@ int afs_fs_give_up_callbacks(struct afs_server *server,
__be32 *bp, *tp;
int loop;
- _enter("");
-
ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
ARRAY_SIZE(server->cb_break));
+
+ _enter("{%zu},", ncallbacks);
+
if (ncallbacks == 0)
return 0;
if (ncallbacks > AFSCBMAX)
@@ -398,6 +399,7 @@ int afs_fs_give_up_callbacks(struct afs_server *server,
(ARRAY_SIZE(server->cb_break) - 1);
}
+ ASSERT(ncallbacks > 0);
wake_up_nr(&server->cb_break_waitq, ncallbacks);
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists