summaryrefslogtreecommitdiff
path: root/fs/orangefs/waitqueue.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-02-18 18:59:44 -0500
committerMike Marshall <hubcap@omnibond.com>2016-02-19 13:45:56 -0500
commit05a50a5be897004b6c1399645256bcf2e768b4ef (patch)
tree084ec3b056a0eca7773dcb58b90177677f487b50 /fs/orangefs/waitqueue.c
parent5964c1b83912dd5052f66ceb50634df958129981 (diff)
orangefs: have ..._clean_interrupted_...() wait for copy to/from daemon
* turn all those list_del(&op->list) into list_del_init() * don't pick ops that are already given up in control device ->read()/->write_iter(). * have orangefs_clean_interrupted_operation() notice if op is currently being copied to/from daemon (by said ->read()/->write_iter()) and wait for that to finish. * when we are done copying to/from daemon and find that it had been given up while we were doing that, wake the waiting ..._clean_interrupted_... As the result, we are guaranteed that orangefs_clean_interrupted_operation(op) doesn't return until nobody else can see op. Moreover, we don't need to play with op refcounts anymore. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Mike Marshall <hubcap@omnibond.com>
Diffstat (limited to 'fs/orangefs/waitqueue.c')
-rw-r--r--fs/orangefs/waitqueue.c22
1 files changed, 10 insertions, 12 deletions
diff --git a/fs/orangefs/waitqueue.c b/fs/orangefs/waitqueue.c
index d980240b0fa7..3f9e43066444 100644
--- a/fs/orangefs/waitqueue.c
+++ b/fs/orangefs/waitqueue.c
@@ -208,15 +208,20 @@ static void orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s
* Called with op->lock held.
*/
op->op_state |= OP_VFS_STATE_GIVEN_UP;
-
- if (op_state_waiting(op)) {
+ /* from that point on it can't be moved by anybody else */
+ if (list_empty(&op->list)) {
+ /* caught copying to/from daemon */
+ BUG_ON(op_state_serviced(op));
+ spin_unlock(&op->lock);
+ wait_for_completion(&op->waitq);
+ } else if (op_state_waiting(op)) {
/*
* upcall hasn't been read; remove op from upcall request
* list.
*/
spin_unlock(&op->lock);
spin_lock(&orangefs_request_list_lock);
- list_del(&op->list);
+ list_del_init(&op->list);
spin_unlock(&orangefs_request_list_lock);
gossip_debug(GOSSIP_WAIT_DEBUG,
"Interrupted: Removed op %p from request_list\n",
@@ -225,23 +230,16 @@ static void orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s
/* op must be removed from the in progress htable */
spin_unlock(&op->lock);
spin_lock(&htable_ops_in_progress_lock);
- list_del(&op->list);
+ list_del_init(&op->list);
spin_unlock(&htable_ops_in_progress_lock);
gossip_debug(GOSSIP_WAIT_DEBUG,
"Interrupted: Removed op %p"
" from htable_ops_in_progress\n",
op);
- } else if (!op_state_serviced(op)) {
+ } else {
spin_unlock(&op->lock);
gossip_err("interrupted operation is in a weird state 0x%x\n",
op->op_state);
- } else {
- /*
- * It is not intended for execution to flow here,
- * but having this unlock here makes sparse happy.
- */
- gossip_err("%s: can't get here.\n", __func__);
- spin_unlock(&op->lock);
}
reinit_completion(&op->waitq);
}