diff options
-rw-r--r-- | Documentation/filesystems/caching/fscache.txt | 2 | ||||
-rw-r--r-- | fs/fscache/internal.h | 3 | ||||
-rw-r--r-- | fs/fscache/operation.c | 82 | ||||
-rw-r--r-- | fs/fscache/page.c | 55 | ||||
-rw-r--r-- | fs/fscache/stats.c | 12 |
5 files changed, 115 insertions, 39 deletions
diff --git a/Documentation/filesystems/caching/fscache.txt b/Documentation/filesystems/caching/fscache.txt index b6c32c080ab1..0a77868f4977 100644 --- a/Documentation/filesystems/caching/fscache.txt +++ b/Documentation/filesystems/caching/fscache.txt | |||
@@ -250,6 +250,7 @@ proc files. | |||
250 | ok=N Number of successful alloc reqs | 250 | ok=N Number of successful alloc reqs |
251 | wt=N Number of alloc reqs that waited on lookup completion | 251 | wt=N Number of alloc reqs that waited on lookup completion |
252 | nbf=N Number of alloc reqs rejected -ENOBUFS | 252 | nbf=N Number of alloc reqs rejected -ENOBUFS |
253 | int=N Number of alloc reqs aborted -ERESTARTSYS | ||
253 | ops=N Number of alloc reqs submitted | 254 | ops=N Number of alloc reqs submitted |
254 | owt=N Number of alloc reqs waited for CPU time | 255 | owt=N Number of alloc reqs waited for CPU time |
255 | Retrvls n=N Number of retrieval (read) requests seen | 256 | Retrvls n=N Number of retrieval (read) requests seen |
@@ -271,6 +272,7 @@ proc files. | |||
271 | Ops pend=N Number of times async ops added to pending queues | 272 | Ops pend=N Number of times async ops added to pending queues |
272 | run=N Number of times async ops given CPU time | 273 | run=N Number of times async ops given CPU time |
273 | enq=N Number of times async ops queued for processing | 274 | enq=N Number of times async ops queued for processing |
275 | can=N Number of async ops cancelled | ||
274 | dfr=N Number of async ops queued for deferred release | 276 | dfr=N Number of async ops queued for deferred release |
275 | rel=N Number of async ops released | 277 | rel=N Number of async ops released |
276 | gc=N Number of deferred-release async ops garbage collected | 278 | gc=N Number of deferred-release async ops garbage collected |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index b85cc8906818..50324ad2b194 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -112,6 +112,7 @@ extern int fscache_submit_exclusive_op(struct fscache_object *, | |||
112 | struct fscache_operation *); | 112 | struct fscache_operation *); |
113 | extern int fscache_submit_op(struct fscache_object *, | 113 | extern int fscache_submit_op(struct fscache_object *, |
114 | struct fscache_operation *); | 114 | struct fscache_operation *); |
115 | extern int fscache_cancel_op(struct fscache_operation *); | ||
115 | extern void fscache_abort_object(struct fscache_object *); | 116 | extern void fscache_abort_object(struct fscache_object *); |
116 | extern void fscache_start_operations(struct fscache_object *); | 117 | extern void fscache_start_operations(struct fscache_object *); |
117 | extern void fscache_operation_gc(struct work_struct *); | 118 | extern void fscache_operation_gc(struct work_struct *); |
@@ -140,6 +141,7 @@ extern atomic_t fscache_n_op_enqueue; | |||
140 | extern atomic_t fscache_n_op_deferred_release; | 141 | extern atomic_t fscache_n_op_deferred_release; |
141 | extern atomic_t fscache_n_op_release; | 142 | extern atomic_t fscache_n_op_release; |
142 | extern atomic_t fscache_n_op_gc; | 143 | extern atomic_t fscache_n_op_gc; |
144 | extern atomic_t fscache_n_op_cancelled; | ||
143 | 145 | ||
144 | extern atomic_t fscache_n_attr_changed; | 146 | extern atomic_t fscache_n_attr_changed; |
145 | extern atomic_t fscache_n_attr_changed_ok; | 147 | extern atomic_t fscache_n_attr_changed_ok; |
@@ -151,6 +153,7 @@ extern atomic_t fscache_n_allocs; | |||
151 | extern atomic_t fscache_n_allocs_ok; | 153 | extern atomic_t fscache_n_allocs_ok; |
152 | extern atomic_t fscache_n_allocs_wait; | 154 | extern atomic_t fscache_n_allocs_wait; |
153 | extern atomic_t fscache_n_allocs_nobufs; | 155 | extern atomic_t fscache_n_allocs_nobufs; |
156 | extern atomic_t fscache_n_allocs_intr; | ||
154 | extern atomic_t fscache_n_alloc_ops; | 157 | extern atomic_t fscache_n_alloc_ops; |
155 | extern atomic_t fscache_n_alloc_op_waits; | 158 | extern atomic_t fscache_n_alloc_op_waits; |
156 | 159 | ||
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 09e43b6e822f..296492efb81b 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
@@ -34,32 +34,31 @@ void fscache_enqueue_operation(struct fscache_operation *op) | |||
34 | 34 | ||
35 | fscache_set_op_state(op, "EnQ"); | 35 | fscache_set_op_state(op, "EnQ"); |
36 | 36 | ||
37 | ASSERT(list_empty(&op->pend_link)); | ||
37 | ASSERT(op->processor != NULL); | 38 | ASSERT(op->processor != NULL); |
38 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); | 39 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); |
39 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 40 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
40 | 41 | ||
41 | if (list_empty(&op->pend_link)) { | 42 | fscache_stat(&fscache_n_op_enqueue); |
42 | switch (op->flags & FSCACHE_OP_TYPE) { | 43 | switch (op->flags & FSCACHE_OP_TYPE) { |
43 | case FSCACHE_OP_FAST: | 44 | case FSCACHE_OP_FAST: |
44 | _debug("queue fast"); | 45 | _debug("queue fast"); |
45 | atomic_inc(&op->usage); | 46 | atomic_inc(&op->usage); |
46 | if (!schedule_work(&op->fast_work)) | 47 | if (!schedule_work(&op->fast_work)) |
47 | fscache_put_operation(op); | 48 | fscache_put_operation(op); |
48 | break; | 49 | break; |
49 | case FSCACHE_OP_SLOW: | 50 | case FSCACHE_OP_SLOW: |
50 | _debug("queue slow"); | 51 | _debug("queue slow"); |
51 | slow_work_enqueue(&op->slow_work); | 52 | slow_work_enqueue(&op->slow_work); |
52 | break; | 53 | break; |
53 | case FSCACHE_OP_MYTHREAD: | 54 | case FSCACHE_OP_MYTHREAD: |
54 | _debug("queue for caller's attention"); | 55 | _debug("queue for caller's attention"); |
55 | break; | 56 | break; |
56 | default: | 57 | default: |
57 | printk(KERN_ERR "FS-Cache: Unexpected op type %lx", | 58 | printk(KERN_ERR "FS-Cache: Unexpected op type %lx", |
58 | op->flags); | 59 | op->flags); |
59 | BUG(); | 60 | BUG(); |
60 | break; | 61 | break; |
61 | } | ||
62 | fscache_stat(&fscache_n_op_enqueue); | ||
63 | } | 62 | } |
64 | } | 63 | } |
65 | EXPORT_SYMBOL(fscache_enqueue_operation); | 64 | EXPORT_SYMBOL(fscache_enqueue_operation); |
@@ -97,6 +96,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
97 | spin_lock(&object->lock); | 96 | spin_lock(&object->lock); |
98 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 97 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
99 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 98 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
99 | ASSERT(list_empty(&op->pend_link)); | ||
100 | 100 | ||
101 | ret = -ENOBUFS; | 101 | ret = -ENOBUFS; |
102 | if (fscache_object_is_active(object)) { | 102 | if (fscache_object_is_active(object)) { |
@@ -202,6 +202,7 @@ int fscache_submit_op(struct fscache_object *object, | |||
202 | spin_lock(&object->lock); | 202 | spin_lock(&object->lock); |
203 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 203 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
204 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 204 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
205 | ASSERT(list_empty(&op->pend_link)); | ||
205 | 206 | ||
206 | ostate = object->state; | 207 | ostate = object->state; |
207 | smp_rmb(); | 208 | smp_rmb(); |
@@ -273,12 +274,7 @@ void fscache_start_operations(struct fscache_object *object) | |||
273 | stop = true; | 274 | stop = true; |
274 | } | 275 | } |
275 | list_del_init(&op->pend_link); | 276 | list_del_init(&op->pend_link); |
276 | object->n_in_progress++; | 277 | fscache_run_op(object, op); |
277 | |||
278 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
279 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
280 | if (op->processor) | ||
281 | fscache_enqueue_operation(op); | ||
282 | 278 | ||
283 | /* the pending queue was holding a ref on the object */ | 279 | /* the pending queue was holding a ref on the object */ |
284 | fscache_put_operation(op); | 280 | fscache_put_operation(op); |
@@ -291,6 +287,36 @@ void fscache_start_operations(struct fscache_object *object) | |||
291 | } | 287 | } |
292 | 288 | ||
293 | /* | 289 | /* |
290 | * cancel an operation that's pending on an object | ||
291 | */ | ||
292 | int fscache_cancel_op(struct fscache_operation *op) | ||
293 | { | ||
294 | struct fscache_object *object = op->object; | ||
295 | int ret; | ||
296 | |||
297 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); | ||
298 | |||
299 | spin_lock(&object->lock); | ||
300 | |||
301 | ret = -EBUSY; | ||
302 | if (!list_empty(&op->pend_link)) { | ||
303 | fscache_stat(&fscache_n_op_cancelled); | ||
304 | list_del_init(&op->pend_link); | ||
305 | object->n_ops--; | ||
306 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
307 | object->n_exclusive--; | ||
308 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
309 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
310 | fscache_put_operation(op); | ||
311 | ret = 0; | ||
312 | } | ||
313 | |||
314 | spin_unlock(&object->lock); | ||
315 | _leave(" = %d", ret); | ||
316 | return ret; | ||
317 | } | ||
318 | |||
319 | /* | ||
294 | * release an operation | 320 | * release an operation |
295 | * - queues pending ops if this is the last in-progress op | 321 | * - queues pending ops if this is the last in-progress op |
296 | */ | 322 | */ |
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 250dfd34c07b..e6f2e61133a1 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -295,8 +295,20 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
295 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 295 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { |
296 | _debug(">>> WT"); | 296 | _debug(">>> WT"); |
297 | fscache_stat(&fscache_n_retrieval_op_waits); | 297 | fscache_stat(&fscache_n_retrieval_op_waits); |
298 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 298 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, |
299 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | 299 | fscache_wait_bit_interruptible, |
300 | TASK_INTERRUPTIBLE) < 0) { | ||
301 | ret = fscache_cancel_op(&op->op); | ||
302 | if (ret == 0) { | ||
303 | ret = -ERESTARTSYS; | ||
304 | goto error; | ||
305 | } | ||
306 | |||
307 | /* it's been removed from the pending queue by another | ||
308 | * party, so we should get to run shortly */ | ||
309 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
310 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
311 | } | ||
300 | _debug("<<< GO"); | 312 | _debug("<<< GO"); |
301 | } | 313 | } |
302 | 314 | ||
@@ -313,6 +325,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
313 | fscache_stat_d(&fscache_n_cop_read_or_alloc_page); | 325 | fscache_stat_d(&fscache_n_cop_read_or_alloc_page); |
314 | } | 326 | } |
315 | 327 | ||
328 | error: | ||
316 | if (ret == -ENOMEM) | 329 | if (ret == -ENOMEM) |
317 | fscache_stat(&fscache_n_retrievals_nomem); | 330 | fscache_stat(&fscache_n_retrievals_nomem); |
318 | else if (ret == -ERESTARTSYS) | 331 | else if (ret == -ERESTARTSYS) |
@@ -412,8 +425,20 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
412 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 425 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { |
413 | _debug(">>> WT"); | 426 | _debug(">>> WT"); |
414 | fscache_stat(&fscache_n_retrieval_op_waits); | 427 | fscache_stat(&fscache_n_retrieval_op_waits); |
415 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 428 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, |
416 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | 429 | fscache_wait_bit_interruptible, |
430 | TASK_INTERRUPTIBLE) < 0) { | ||
431 | ret = fscache_cancel_op(&op->op); | ||
432 | if (ret == 0) { | ||
433 | ret = -ERESTARTSYS; | ||
434 | goto error; | ||
435 | } | ||
436 | |||
437 | /* it's been removed from the pending queue by another | ||
438 | * party, so we should get to run shortly */ | ||
439 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
440 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
441 | } | ||
417 | _debug("<<< GO"); | 442 | _debug("<<< GO"); |
418 | } | 443 | } |
419 | 444 | ||
@@ -430,6 +455,7 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
430 | fscache_stat_d(&fscache_n_cop_read_or_alloc_pages); | 455 | fscache_stat_d(&fscache_n_cop_read_or_alloc_pages); |
431 | } | 456 | } |
432 | 457 | ||
458 | error: | ||
433 | if (ret == -ENOMEM) | 459 | if (ret == -ENOMEM) |
434 | fscache_stat(&fscache_n_retrievals_nomem); | 460 | fscache_stat(&fscache_n_retrievals_nomem); |
435 | else if (ret == -ERESTARTSYS) | 461 | else if (ret == -ERESTARTSYS) |
@@ -505,8 +531,20 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
505 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 531 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { |
506 | _debug(">>> WT"); | 532 | _debug(">>> WT"); |
507 | fscache_stat(&fscache_n_alloc_op_waits); | 533 | fscache_stat(&fscache_n_alloc_op_waits); |
508 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 534 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, |
509 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | 535 | fscache_wait_bit_interruptible, |
536 | TASK_INTERRUPTIBLE) < 0) { | ||
537 | ret = fscache_cancel_op(&op->op); | ||
538 | if (ret == 0) { | ||
539 | ret = -ERESTARTSYS; | ||
540 | goto error; | ||
541 | } | ||
542 | |||
543 | /* it's been removed from the pending queue by another | ||
544 | * party, so we should get to run shortly */ | ||
545 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
546 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
547 | } | ||
510 | _debug("<<< GO"); | 548 | _debug("<<< GO"); |
511 | } | 549 | } |
512 | 550 | ||
@@ -515,7 +553,10 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
515 | ret = object->cache->ops->allocate_page(op, page, gfp); | 553 | ret = object->cache->ops->allocate_page(op, page, gfp); |
516 | fscache_stat_d(&fscache_n_cop_allocate_page); | 554 | fscache_stat_d(&fscache_n_cop_allocate_page); |
517 | 555 | ||
518 | if (ret < 0) | 556 | error: |
557 | if (ret == -ERESTARTSYS) | ||
558 | fscache_stat(&fscache_n_allocs_intr); | ||
559 | else if (ret < 0) | ||
519 | fscache_stat(&fscache_n_allocs_nobufs); | 560 | fscache_stat(&fscache_n_allocs_nobufs); |
520 | else | 561 | else |
521 | fscache_stat(&fscache_n_allocs_ok); | 562 | fscache_stat(&fscache_n_allocs_ok); |
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index 20233fb44bfd..4c07439d1307 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c | |||
@@ -25,6 +25,7 @@ atomic_t fscache_n_op_requeue; | |||
25 | atomic_t fscache_n_op_deferred_release; | 25 | atomic_t fscache_n_op_deferred_release; |
26 | atomic_t fscache_n_op_release; | 26 | atomic_t fscache_n_op_release; |
27 | atomic_t fscache_n_op_gc; | 27 | atomic_t fscache_n_op_gc; |
28 | atomic_t fscache_n_op_cancelled; | ||
28 | 29 | ||
29 | atomic_t fscache_n_attr_changed; | 30 | atomic_t fscache_n_attr_changed; |
30 | atomic_t fscache_n_attr_changed_ok; | 31 | atomic_t fscache_n_attr_changed_ok; |
@@ -36,6 +37,7 @@ atomic_t fscache_n_allocs; | |||
36 | atomic_t fscache_n_allocs_ok; | 37 | atomic_t fscache_n_allocs_ok; |
37 | atomic_t fscache_n_allocs_wait; | 38 | atomic_t fscache_n_allocs_wait; |
38 | atomic_t fscache_n_allocs_nobufs; | 39 | atomic_t fscache_n_allocs_nobufs; |
40 | atomic_t fscache_n_allocs_intr; | ||
39 | atomic_t fscache_n_alloc_ops; | 41 | atomic_t fscache_n_alloc_ops; |
40 | atomic_t fscache_n_alloc_op_waits; | 42 | atomic_t fscache_n_alloc_op_waits; |
41 | 43 | ||
@@ -169,11 +171,12 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
169 | atomic_read(&fscache_n_attr_changed_nomem), | 171 | atomic_read(&fscache_n_attr_changed_nomem), |
170 | atomic_read(&fscache_n_attr_changed_calls)); | 172 | atomic_read(&fscache_n_attr_changed_calls)); |
171 | 173 | ||
172 | seq_printf(m, "Allocs : n=%u ok=%u wt=%u nbf=%u\n", | 174 | seq_printf(m, "Allocs : n=%u ok=%u wt=%u nbf=%u int=%u\n", |
173 | atomic_read(&fscache_n_allocs), | 175 | atomic_read(&fscache_n_allocs), |
174 | atomic_read(&fscache_n_allocs_ok), | 176 | atomic_read(&fscache_n_allocs_ok), |
175 | atomic_read(&fscache_n_allocs_wait), | 177 | atomic_read(&fscache_n_allocs_wait), |
176 | atomic_read(&fscache_n_allocs_nobufs)); | 178 | atomic_read(&fscache_n_allocs_nobufs), |
179 | atomic_read(&fscache_n_allocs_intr)); | ||
177 | seq_printf(m, "Allocs : ops=%u owt=%u\n", | 180 | seq_printf(m, "Allocs : ops=%u owt=%u\n", |
178 | atomic_read(&fscache_n_alloc_ops), | 181 | atomic_read(&fscache_n_alloc_ops), |
179 | atomic_read(&fscache_n_alloc_op_waits)); | 182 | atomic_read(&fscache_n_alloc_op_waits)); |
@@ -201,10 +204,11 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
201 | atomic_read(&fscache_n_store_ops), | 204 | atomic_read(&fscache_n_store_ops), |
202 | atomic_read(&fscache_n_store_calls)); | 205 | atomic_read(&fscache_n_store_calls)); |
203 | 206 | ||
204 | seq_printf(m, "Ops : pend=%u run=%u enq=%u\n", | 207 | seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u\n", |
205 | atomic_read(&fscache_n_op_pend), | 208 | atomic_read(&fscache_n_op_pend), |
206 | atomic_read(&fscache_n_op_run), | 209 | atomic_read(&fscache_n_op_run), |
207 | atomic_read(&fscache_n_op_enqueue)); | 210 | atomic_read(&fscache_n_op_enqueue), |
211 | atomic_read(&fscache_n_op_cancelled)); | ||
208 | seq_printf(m, "Ops : dfr=%u rel=%u gc=%u\n", | 212 | seq_printf(m, "Ops : dfr=%u rel=%u gc=%u\n", |
209 | atomic_read(&fscache_n_op_deferred_release), | 213 | atomic_read(&fscache_n_op_deferred_release), |
210 | atomic_read(&fscache_n_op_release), | 214 | atomic_read(&fscache_n_op_release), |