diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-02-18 18:59:44 -0500 |
---|---|---|
committer | Mike Marshall <hubcap@omnibond.com> | 2016-02-19 13:45:56 -0500 |
commit | 05a50a5be897004b6c1399645256bcf2e768b4ef (patch) | |
tree | 084ec3b056a0eca7773dcb58b90177677f487b50 /fs/orangefs/waitqueue.c | |
parent | 5964c1b83912dd5052f66ceb50634df958129981 (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.c | 22 |
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); } |