diff options
Diffstat (limited to 'fs/fscache/operation.c')
-rw-r--r-- | fs/fscache/operation.c | 120 |
1 files changed, 92 insertions, 28 deletions
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index e7f8d53b8b6b..313e79a14266 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #define FSCACHE_DEBUG_LEVEL OPERATION | 14 | #define FSCACHE_DEBUG_LEVEL OPERATION |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/seq_file.h> | ||
16 | #include "internal.h" | 17 | #include "internal.h" |
17 | 18 | ||
18 | atomic_t fscache_op_debug_id; | 19 | atomic_t fscache_op_debug_id; |
@@ -31,32 +32,33 @@ void fscache_enqueue_operation(struct fscache_operation *op) | |||
31 | _enter("{OBJ%x OP%x,%u}", | 32 | _enter("{OBJ%x OP%x,%u}", |
32 | op->object->debug_id, op->debug_id, atomic_read(&op->usage)); | 33 | op->object->debug_id, op->debug_id, atomic_read(&op->usage)); |
33 | 34 | ||
35 | fscache_set_op_state(op, "EnQ"); | ||
36 | |||
37 | ASSERT(list_empty(&op->pend_link)); | ||
34 | ASSERT(op->processor != NULL); | 38 | ASSERT(op->processor != NULL); |
35 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); | 39 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); |
36 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 40 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
37 | 41 | ||
38 | if (list_empty(&op->pend_link)) { | 42 | fscache_stat(&fscache_n_op_enqueue); |
39 | switch (op->flags & FSCACHE_OP_TYPE) { | 43 | switch (op->flags & FSCACHE_OP_TYPE) { |
40 | case FSCACHE_OP_FAST: | 44 | case FSCACHE_OP_FAST: |
41 | _debug("queue fast"); | 45 | _debug("queue fast"); |
42 | atomic_inc(&op->usage); | 46 | atomic_inc(&op->usage); |
43 | if (!schedule_work(&op->fast_work)) | 47 | if (!schedule_work(&op->fast_work)) |
44 | fscache_put_operation(op); | 48 | fscache_put_operation(op); |
45 | break; | 49 | break; |
46 | case FSCACHE_OP_SLOW: | 50 | case FSCACHE_OP_SLOW: |
47 | _debug("queue slow"); | 51 | _debug("queue slow"); |
48 | slow_work_enqueue(&op->slow_work); | 52 | slow_work_enqueue(&op->slow_work); |
49 | break; | 53 | break; |
50 | case FSCACHE_OP_MYTHREAD: | 54 | case FSCACHE_OP_MYTHREAD: |
51 | _debug("queue for caller's attention"); | 55 | _debug("queue for caller's attention"); |
52 | break; | 56 | break; |
53 | default: | 57 | default: |
54 | printk(KERN_ERR "FS-Cache: Unexpected op type %lx", | 58 | printk(KERN_ERR "FS-Cache: Unexpected op type %lx", |
55 | op->flags); | 59 | op->flags); |
56 | BUG(); | 60 | BUG(); |
57 | break; | 61 | break; |
58 | } | ||
59 | fscache_stat(&fscache_n_op_enqueue); | ||
60 | } | 62 | } |
61 | } | 63 | } |
62 | EXPORT_SYMBOL(fscache_enqueue_operation); | 64 | EXPORT_SYMBOL(fscache_enqueue_operation); |
@@ -67,6 +69,8 @@ EXPORT_SYMBOL(fscache_enqueue_operation); | |||
67 | static void fscache_run_op(struct fscache_object *object, | 69 | static void fscache_run_op(struct fscache_object *object, |
68 | struct fscache_operation *op) | 70 | struct fscache_operation *op) |
69 | { | 71 | { |
72 | fscache_set_op_state(op, "Run"); | ||
73 | |||
70 | object->n_in_progress++; | 74 | object->n_in_progress++; |
71 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | 75 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) |
72 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | 76 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); |
@@ -87,9 +91,12 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
87 | 91 | ||
88 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); | 92 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); |
89 | 93 | ||
94 | fscache_set_op_state(op, "SubmitX"); | ||
95 | |||
90 | spin_lock(&object->lock); | 96 | spin_lock(&object->lock); |
91 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 97 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
92 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 98 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
99 | ASSERT(list_empty(&op->pend_link)); | ||
93 | 100 | ||
94 | ret = -ENOBUFS; | 101 | ret = -ENOBUFS; |
95 | if (fscache_object_is_active(object)) { | 102 | if (fscache_object_is_active(object)) { |
@@ -190,9 +197,12 @@ int fscache_submit_op(struct fscache_object *object, | |||
190 | 197 | ||
191 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 198 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
192 | 199 | ||
200 | fscache_set_op_state(op, "Submit"); | ||
201 | |||
193 | spin_lock(&object->lock); | 202 | spin_lock(&object->lock); |
194 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 203 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
195 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 204 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
205 | ASSERT(list_empty(&op->pend_link)); | ||
196 | 206 | ||
197 | ostate = object->state; | 207 | ostate = object->state; |
198 | smp_rmb(); | 208 | smp_rmb(); |
@@ -222,6 +232,11 @@ int fscache_submit_op(struct fscache_object *object, | |||
222 | list_add_tail(&op->pend_link, &object->pending_ops); | 232 | list_add_tail(&op->pend_link, &object->pending_ops); |
223 | fscache_stat(&fscache_n_op_pend); | 233 | fscache_stat(&fscache_n_op_pend); |
224 | ret = 0; | 234 | ret = 0; |
235 | } else if (object->state == FSCACHE_OBJECT_DYING || | ||
236 | object->state == FSCACHE_OBJECT_LC_DYING || | ||
237 | object->state == FSCACHE_OBJECT_WITHDRAWING) { | ||
238 | fscache_stat(&fscache_n_op_rejected); | ||
239 | ret = -ENOBUFS; | ||
225 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { | 240 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { |
226 | fscache_report_unexpected_submission(object, op, ostate); | 241 | fscache_report_unexpected_submission(object, op, ostate); |
227 | ASSERT(!fscache_object_is_active(object)); | 242 | ASSERT(!fscache_object_is_active(object)); |
@@ -264,12 +279,7 @@ void fscache_start_operations(struct fscache_object *object) | |||
264 | stop = true; | 279 | stop = true; |
265 | } | 280 | } |
266 | list_del_init(&op->pend_link); | 281 | list_del_init(&op->pend_link); |
267 | object->n_in_progress++; | 282 | fscache_run_op(object, op); |
268 | |||
269 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
270 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
271 | if (op->processor) | ||
272 | fscache_enqueue_operation(op); | ||
273 | 283 | ||
274 | /* the pending queue was holding a ref on the object */ | 284 | /* the pending queue was holding a ref on the object */ |
275 | fscache_put_operation(op); | 285 | fscache_put_operation(op); |
@@ -282,6 +292,36 @@ void fscache_start_operations(struct fscache_object *object) | |||
282 | } | 292 | } |
283 | 293 | ||
284 | /* | 294 | /* |
295 | * cancel an operation that's pending on an object | ||
296 | */ | ||
297 | int fscache_cancel_op(struct fscache_operation *op) | ||
298 | { | ||
299 | struct fscache_object *object = op->object; | ||
300 | int ret; | ||
301 | |||
302 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); | ||
303 | |||
304 | spin_lock(&object->lock); | ||
305 | |||
306 | ret = -EBUSY; | ||
307 | if (!list_empty(&op->pend_link)) { | ||
308 | fscache_stat(&fscache_n_op_cancelled); | ||
309 | list_del_init(&op->pend_link); | ||
310 | object->n_ops--; | ||
311 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
312 | object->n_exclusive--; | ||
313 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
314 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
315 | fscache_put_operation(op); | ||
316 | ret = 0; | ||
317 | } | ||
318 | |||
319 | spin_unlock(&object->lock); | ||
320 | _leave(" = %d", ret); | ||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | /* | ||
285 | * release an operation | 325 | * release an operation |
286 | * - queues pending ops if this is the last in-progress op | 326 | * - queues pending ops if this is the last in-progress op |
287 | */ | 327 | */ |
@@ -298,6 +338,8 @@ void fscache_put_operation(struct fscache_operation *op) | |||
298 | if (!atomic_dec_and_test(&op->usage)) | 338 | if (!atomic_dec_and_test(&op->usage)) |
299 | return; | 339 | return; |
300 | 340 | ||
341 | fscache_set_op_state(op, "Put"); | ||
342 | |||
301 | _debug("PUT OP"); | 343 | _debug("PUT OP"); |
302 | if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags)) | 344 | if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags)) |
303 | BUG(); | 345 | BUG(); |
@@ -311,6 +353,9 @@ void fscache_put_operation(struct fscache_operation *op) | |||
311 | 353 | ||
312 | object = op->object; | 354 | object = op->object; |
313 | 355 | ||
356 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) | ||
357 | atomic_dec(&object->n_reads); | ||
358 | |||
314 | /* now... we may get called with the object spinlock held, so we | 359 | /* now... we may get called with the object spinlock held, so we |
315 | * complete the cleanup here only if we can immediately acquire the | 360 | * complete the cleanup here only if we can immediately acquire the |
316 | * lock, and defer it otherwise */ | 361 | * lock, and defer it otherwise */ |
@@ -452,8 +497,27 @@ static void fscache_op_execute(struct slow_work *work) | |||
452 | _leave(""); | 497 | _leave(""); |
453 | } | 498 | } |
454 | 499 | ||
500 | /* | ||
501 | * describe an operation for slow-work debugging | ||
502 | */ | ||
503 | #ifdef CONFIG_SLOW_WORK_PROC | ||
504 | static void fscache_op_desc(struct slow_work *work, struct seq_file *m) | ||
505 | { | ||
506 | struct fscache_operation *op = | ||
507 | container_of(work, struct fscache_operation, slow_work); | ||
508 | |||
509 | seq_printf(m, "FSC: OBJ%x OP%x: %s/%s fl=%lx", | ||
510 | op->object->debug_id, op->debug_id, | ||
511 | op->name, op->state, op->flags); | ||
512 | } | ||
513 | #endif | ||
514 | |||
455 | const struct slow_work_ops fscache_op_slow_work_ops = { | 515 | const struct slow_work_ops fscache_op_slow_work_ops = { |
516 | .owner = THIS_MODULE, | ||
456 | .get_ref = fscache_op_get_ref, | 517 | .get_ref = fscache_op_get_ref, |
457 | .put_ref = fscache_op_put_ref, | 518 | .put_ref = fscache_op_put_ref, |
458 | .execute = fscache_op_execute, | 519 | .execute = fscache_op_execute, |
520 | #ifdef CONFIG_SLOW_WORK_PROC | ||
521 | .desc = fscache_op_desc, | ||
522 | #endif | ||
459 | }; | 523 | }; |