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 | |
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')
-rw-r--r-- | fs/orangefs/devorangefs-req.c | 20 | ||||
-rw-r--r-- | fs/orangefs/orangefs-kernel.h | 2 | ||||
-rw-r--r-- | fs/orangefs/waitqueue.c | 22 |
3 files changed, 21 insertions, 23 deletions
diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c index 89c282afeb29..f7914f5d296f 100644 --- a/fs/orangefs/devorangefs-req.c +++ b/fs/orangefs/devorangefs-req.c | |||
@@ -58,9 +58,9 @@ static struct orangefs_kernel_op_s *orangefs_devreq_remove_op(__u64 tag) | |||
58 | next, | 58 | next, |
59 | &htable_ops_in_progress[index], | 59 | &htable_ops_in_progress[index], |
60 | list) { | 60 | list) { |
61 | if (op->tag == tag && !op_state_purged(op)) { | 61 | if (op->tag == tag && !op_state_purged(op) && |
62 | !op_state_given_up(op)) { | ||
62 | list_del_init(&op->list); | 63 | list_del_init(&op->list); |
63 | get_op(op); /* increase ref count. */ | ||
64 | spin_unlock(&htable_ops_in_progress_lock); | 64 | spin_unlock(&htable_ops_in_progress_lock); |
65 | return op; | 65 | return op; |
66 | } | 66 | } |
@@ -133,7 +133,7 @@ restart: | |||
133 | __s32 fsid; | 133 | __s32 fsid; |
134 | /* This lock is held past the end of the loop when we break. */ | 134 | /* This lock is held past the end of the loop when we break. */ |
135 | spin_lock(&op->lock); | 135 | spin_lock(&op->lock); |
136 | if (unlikely(op_state_purged(op))) { | 136 | if (unlikely(op_state_purged(op) || op_state_given_up(op))) { |
137 | spin_unlock(&op->lock); | 137 | spin_unlock(&op->lock); |
138 | continue; | 138 | continue; |
139 | } | 139 | } |
@@ -199,13 +199,12 @@ restart: | |||
199 | */ | 199 | */ |
200 | if (op_state_in_progress(cur_op) || op_state_serviced(cur_op)) { | 200 | if (op_state_in_progress(cur_op) || op_state_serviced(cur_op)) { |
201 | gossip_err("orangefs: ERROR: Current op already queued.\n"); | 201 | gossip_err("orangefs: ERROR: Current op already queued.\n"); |
202 | list_del(&cur_op->list); | 202 | list_del_init(&cur_op->list); |
203 | spin_unlock(&cur_op->lock); | 203 | spin_unlock(&cur_op->lock); |
204 | spin_unlock(&orangefs_request_list_lock); | 204 | spin_unlock(&orangefs_request_list_lock); |
205 | return -EAGAIN; | 205 | return -EAGAIN; |
206 | } | 206 | } |
207 | list_del_init(&cur_op->list); | 207 | list_del_init(&cur_op->list); |
208 | get_op(op); | ||
209 | spin_unlock(&orangefs_request_list_lock); | 208 | spin_unlock(&orangefs_request_list_lock); |
210 | 209 | ||
211 | spin_unlock(&cur_op->lock); | 210 | spin_unlock(&cur_op->lock); |
@@ -230,7 +229,7 @@ restart: | |||
230 | if (unlikely(op_state_given_up(cur_op))) { | 229 | if (unlikely(op_state_given_up(cur_op))) { |
231 | spin_unlock(&cur_op->lock); | 230 | spin_unlock(&cur_op->lock); |
232 | spin_unlock(&htable_ops_in_progress_lock); | 231 | spin_unlock(&htable_ops_in_progress_lock); |
233 | op_release(cur_op); | 232 | complete(&cur_op->waitq); |
234 | goto restart; | 233 | goto restart; |
235 | } | 234 | } |
236 | 235 | ||
@@ -242,7 +241,6 @@ restart: | |||
242 | orangefs_devreq_add_op(cur_op); | 241 | orangefs_devreq_add_op(cur_op); |
243 | spin_unlock(&cur_op->lock); | 242 | spin_unlock(&cur_op->lock); |
244 | spin_unlock(&htable_ops_in_progress_lock); | 243 | spin_unlock(&htable_ops_in_progress_lock); |
245 | op_release(cur_op); | ||
246 | 244 | ||
247 | /* The client only asks to read one size buffer. */ | 245 | /* The client only asks to read one size buffer. */ |
248 | return MAX_DEV_REQ_UPSIZE; | 246 | return MAX_DEV_REQ_UPSIZE; |
@@ -258,10 +256,12 @@ error: | |||
258 | if (likely(!op_state_given_up(cur_op))) { | 256 | if (likely(!op_state_given_up(cur_op))) { |
259 | set_op_state_waiting(cur_op); | 257 | set_op_state_waiting(cur_op); |
260 | list_add(&cur_op->list, &orangefs_request_list); | 258 | list_add(&cur_op->list, &orangefs_request_list); |
259 | spin_unlock(&cur_op->lock); | ||
260 | } else { | ||
261 | spin_unlock(&cur_op->lock); | ||
262 | complete(&cur_op->waitq); | ||
261 | } | 263 | } |
262 | spin_unlock(&cur_op->lock); | ||
263 | spin_unlock(&orangefs_request_list_lock); | 264 | spin_unlock(&orangefs_request_list_lock); |
264 | op_release(cur_op); | ||
265 | return -EFAULT; | 265 | return -EFAULT; |
266 | } | 266 | } |
267 | 267 | ||
@@ -405,11 +405,11 @@ wakeup: | |||
405 | put_cancel(op); | 405 | put_cancel(op); |
406 | } else if (unlikely(op_state_given_up(op))) { | 406 | } else if (unlikely(op_state_given_up(op))) { |
407 | spin_unlock(&op->lock); | 407 | spin_unlock(&op->lock); |
408 | complete(&op->waitq); | ||
408 | } else { | 409 | } else { |
409 | set_op_state_serviced(op); | 410 | set_op_state_serviced(op); |
410 | spin_unlock(&op->lock); | 411 | spin_unlock(&op->lock); |
411 | } | 412 | } |
412 | op_release(op); | ||
413 | return ret; | 413 | return ret; |
414 | 414 | ||
415 | Efault: | 415 | Efault: |
diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h index 1d20eadaefd8..7d0c8b3afc7e 100644 --- a/fs/orangefs/orangefs-kernel.h +++ b/fs/orangefs/orangefs-kernel.h | |||
@@ -259,7 +259,7 @@ static inline void set_op_state_purged(struct orangefs_kernel_op_s *op) | |||
259 | { | 259 | { |
260 | spin_lock(&op->lock); | 260 | spin_lock(&op->lock); |
261 | if (unlikely(op_is_cancel(op))) { | 261 | if (unlikely(op_is_cancel(op))) { |
262 | list_del(&op->list); | 262 | list_del_init(&op->list); |
263 | spin_unlock(&op->lock); | 263 | spin_unlock(&op->lock); |
264 | put_cancel(op); | 264 | put_cancel(op); |
265 | } else { | 265 | } else { |
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 | |||
208 | * Called with op->lock held. | 208 | * Called with op->lock held. |
209 | */ | 209 | */ |
210 | op->op_state |= OP_VFS_STATE_GIVEN_UP; | 210 | op->op_state |= OP_VFS_STATE_GIVEN_UP; |
211 | 211 | /* from that point on it can't be moved by anybody else */ | |
212 | if (op_state_waiting(op)) { | 212 | if (list_empty(&op->list)) { |
213 | /* caught copying to/from daemon */ | ||
214 | BUG_ON(op_state_serviced(op)); | ||
215 | spin_unlock(&op->lock); | ||
216 | wait_for_completion(&op->waitq); | ||
217 | } else if (op_state_waiting(op)) { | ||
213 | /* | 218 | /* |
214 | * upcall hasn't been read; remove op from upcall request | 219 | * upcall hasn't been read; remove op from upcall request |
215 | * list. | 220 | * list. |
216 | */ | 221 | */ |
217 | spin_unlock(&op->lock); | 222 | spin_unlock(&op->lock); |
218 | spin_lock(&orangefs_request_list_lock); | 223 | spin_lock(&orangefs_request_list_lock); |
219 | list_del(&op->list); | 224 | list_del_init(&op->list); |
220 | spin_unlock(&orangefs_request_list_lock); | 225 | spin_unlock(&orangefs_request_list_lock); |
221 | gossip_debug(GOSSIP_WAIT_DEBUG, | 226 | gossip_debug(GOSSIP_WAIT_DEBUG, |
222 | "Interrupted: Removed op %p from request_list\n", | 227 | "Interrupted: Removed op %p from request_list\n", |
@@ -225,23 +230,16 @@ static void orangefs_clean_up_interrupted_operation(struct orangefs_kernel_op_s | |||
225 | /* op must be removed from the in progress htable */ | 230 | /* op must be removed from the in progress htable */ |
226 | spin_unlock(&op->lock); | 231 | spin_unlock(&op->lock); |
227 | spin_lock(&htable_ops_in_progress_lock); | 232 | spin_lock(&htable_ops_in_progress_lock); |
228 | list_del(&op->list); | 233 | list_del_init(&op->list); |
229 | spin_unlock(&htable_ops_in_progress_lock); | 234 | spin_unlock(&htable_ops_in_progress_lock); |
230 | gossip_debug(GOSSIP_WAIT_DEBUG, | 235 | gossip_debug(GOSSIP_WAIT_DEBUG, |
231 | "Interrupted: Removed op %p" | 236 | "Interrupted: Removed op %p" |
232 | " from htable_ops_in_progress\n", | 237 | " from htable_ops_in_progress\n", |
233 | op); | 238 | op); |
234 | } else if (!op_state_serviced(op)) { | 239 | } else { |
235 | spin_unlock(&op->lock); | 240 | spin_unlock(&op->lock); |
236 | gossip_err("interrupted operation is in a weird state 0x%x\n", | 241 | gossip_err("interrupted operation is in a weird state 0x%x\n", |
237 | op->op_state); | 242 | op->op_state); |
238 | } else { | ||
239 | /* | ||
240 | * It is not intended for execution to flow here, | ||
241 | * but having this unlock here makes sparse happy. | ||
242 | */ | ||
243 | gossip_err("%s: can't get here.\n", __func__); | ||
244 | spin_unlock(&op->lock); | ||
245 | } | 243 | } |
246 | reinit_completion(&op->waitq); | 244 | reinit_completion(&op->waitq); |
247 | } | 245 | } |