diff options
author | David Howells <dhowells@redhat.com> | 2009-11-19 13:11:45 -0500 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2009-11-19 13:11:45 -0500 |
commit | 60d543ca724be155c2b6166e36a00c80b21bd810 (patch) | |
tree | 90ec6edd77ddb7666dbf7069aa2e001f155cea49 | |
parent | d461d26dde901b0523c46b0317e7fccf574a3933 (diff) |
FS-Cache: Start processing an object's operations on that object's death
Start processing an object's operations when that object moves into the DYING
state as the object cannot be destroyed until all its outstanding operations
have completed.
Furthermore, make sure that read and allocation operations handle being woken
up on a dead object. Such events are recorded in the Allocs.abt and
Retrvls.abt statistics as viewable through /proc/fs/fscache/stats.
The code for waiting for object activation for the read and allocation
operations is also extracted into its own function as it is much the same in
all cases, differing only in the stats incremented.
Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r-- | Documentation/filesystems/caching/fscache.txt | 2 | ||||
-rw-r--r-- | fs/fscache/internal.h | 5 | ||||
-rw-r--r-- | fs/fscache/object.c | 1 | ||||
-rw-r--r-- | fs/fscache/page.c | 112 | ||||
-rw-r--r-- | fs/fscache/stats.c | 12 | ||||
-rw-r--r-- | include/linux/fscache-cache.h | 4 |
6 files changed, 75 insertions, 61 deletions
diff --git a/Documentation/filesystems/caching/fscache.txt b/Documentation/filesystems/caching/fscache.txt index 7097fd29fb3d..3c23411956bb 100644 --- a/Documentation/filesystems/caching/fscache.txt +++ b/Documentation/filesystems/caching/fscache.txt | |||
@@ -253,6 +253,7 @@ proc files. | |||
253 | int=N Number of alloc reqs aborted -ERESTARTSYS | 253 | int=N Number of alloc reqs aborted -ERESTARTSYS |
254 | ops=N Number of alloc reqs submitted | 254 | ops=N Number of alloc reqs submitted |
255 | owt=N Number of alloc reqs waited for CPU time | 255 | owt=N Number of alloc reqs waited for CPU time |
256 | abt=N Number of alloc reqs aborted due to object death | ||
256 | Retrvls n=N Number of retrieval (read) requests seen | 257 | Retrvls n=N Number of retrieval (read) requests seen |
257 | ok=N Number of successful retr reqs | 258 | ok=N Number of successful retr reqs |
258 | wt=N Number of retr reqs that waited on lookup completion | 259 | wt=N Number of retr reqs that waited on lookup completion |
@@ -262,6 +263,7 @@ proc files. | |||
262 | oom=N Number of retr reqs failed -ENOMEM | 263 | oom=N Number of retr reqs failed -ENOMEM |
263 | ops=N Number of retr reqs submitted | 264 | ops=N Number of retr reqs submitted |
264 | owt=N Number of retr reqs waited for CPU time | 265 | owt=N Number of retr reqs waited for CPU time |
266 | abt=N Number of retr reqs aborted due to object death | ||
265 | Stores n=N Number of storage (write) requests seen | 267 | Stores n=N Number of storage (write) requests seen |
266 | ok=N Number of successful store reqs | 268 | ok=N Number of successful store reqs |
267 | agn=N Number of store reqs on a page already pending storage | 269 | agn=N Number of store reqs on a page already pending storage |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index 2bf463d26080..5b49a373689b 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -156,6 +156,7 @@ extern atomic_t fscache_n_allocs_ok; | |||
156 | extern atomic_t fscache_n_allocs_wait; | 156 | extern atomic_t fscache_n_allocs_wait; |
157 | extern atomic_t fscache_n_allocs_nobufs; | 157 | extern atomic_t fscache_n_allocs_nobufs; |
158 | extern atomic_t fscache_n_allocs_intr; | 158 | extern atomic_t fscache_n_allocs_intr; |
159 | extern atomic_t fscache_n_allocs_object_dead; | ||
159 | extern atomic_t fscache_n_alloc_ops; | 160 | extern atomic_t fscache_n_alloc_ops; |
160 | extern atomic_t fscache_n_alloc_op_waits; | 161 | extern atomic_t fscache_n_alloc_op_waits; |
161 | 162 | ||
@@ -166,6 +167,7 @@ extern atomic_t fscache_n_retrievals_nodata; | |||
166 | extern atomic_t fscache_n_retrievals_nobufs; | 167 | extern atomic_t fscache_n_retrievals_nobufs; |
167 | extern atomic_t fscache_n_retrievals_intr; | 168 | extern atomic_t fscache_n_retrievals_intr; |
168 | extern atomic_t fscache_n_retrievals_nomem; | 169 | extern atomic_t fscache_n_retrievals_nomem; |
170 | extern atomic_t fscache_n_retrievals_object_dead; | ||
169 | extern atomic_t fscache_n_retrieval_ops; | 171 | extern atomic_t fscache_n_retrieval_ops; |
170 | extern atomic_t fscache_n_retrieval_op_waits; | 172 | extern atomic_t fscache_n_retrieval_op_waits; |
171 | 173 | ||
@@ -249,9 +251,12 @@ static inline void fscache_stat_d(atomic_t *stat) | |||
249 | atomic_dec(stat); | 251 | atomic_dec(stat); |
250 | } | 252 | } |
251 | 253 | ||
254 | #define __fscache_stat(stat) (stat) | ||
255 | |||
252 | extern const struct file_operations fscache_stats_fops; | 256 | extern const struct file_operations fscache_stats_fops; |
253 | #else | 257 | #else |
254 | 258 | ||
259 | #define __fscache_stat(stat) (NULL) | ||
255 | #define fscache_stat(stat) do {} while (0) | 260 | #define fscache_stat(stat) do {} while (0) |
256 | #endif | 261 | #endif |
257 | 262 | ||
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 74bc562a2cbc..c85c9f582166 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -201,6 +201,7 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
201 | } | 201 | } |
202 | spin_unlock(&object->lock); | 202 | spin_unlock(&object->lock); |
203 | fscache_enqueue_dependents(object); | 203 | fscache_enqueue_dependents(object); |
204 | fscache_start_operations(object); | ||
204 | goto terminal_transit; | 205 | goto terminal_transit; |
205 | 206 | ||
206 | /* handle an abort during initialisation */ | 207 | /* handle an abort during initialisation */ |
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index fc76798bd968..c598ea4c4e7d 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -314,6 +314,43 @@ static int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie) | |||
314 | } | 314 | } |
315 | 315 | ||
316 | /* | 316 | /* |
317 | * wait for an object to become active (or dead) | ||
318 | */ | ||
319 | static int fscache_wait_for_retrieval_activation(struct fscache_object *object, | ||
320 | struct fscache_retrieval *op, | ||
321 | atomic_t *stat_op_waits, | ||
322 | atomic_t *stat_object_dead) | ||
323 | { | ||
324 | int ret; | ||
325 | |||
326 | if (!test_bit(FSCACHE_OP_WAITING, &op->op.flags)) | ||
327 | goto check_if_dead; | ||
328 | |||
329 | _debug(">>> WT"); | ||
330 | fscache_stat(stat_op_waits); | ||
331 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
332 | fscache_wait_bit_interruptible, | ||
333 | TASK_INTERRUPTIBLE) < 0) { | ||
334 | ret = fscache_cancel_op(&op->op); | ||
335 | if (ret == 0) | ||
336 | return -ERESTARTSYS; | ||
337 | |||
338 | /* it's been removed from the pending queue by another party, | ||
339 | * so we should get to run shortly */ | ||
340 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
341 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
342 | } | ||
343 | _debug("<<< GO"); | ||
344 | |||
345 | check_if_dead: | ||
346 | if (unlikely(fscache_object_is_dead(object))) { | ||
347 | fscache_stat(stat_object_dead); | ||
348 | return -ENOBUFS; | ||
349 | } | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | /* | ||
317 | * read a page from the cache or allocate a block in which to store it | 354 | * read a page from the cache or allocate a block in which to store it |
318 | * - we return: | 355 | * - we return: |
319 | * -ENOMEM - out of memory, nothing done | 356 | * -ENOMEM - out of memory, nothing done |
@@ -376,25 +413,12 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
376 | 413 | ||
377 | /* we wait for the operation to become active, and then process it | 414 | /* we wait for the operation to become active, and then process it |
378 | * *here*, in this thread, and not in the thread pool */ | 415 | * *here*, in this thread, and not in the thread pool */ |
379 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 416 | ret = fscache_wait_for_retrieval_activation( |
380 | _debug(">>> WT"); | 417 | object, op, |
381 | fscache_stat(&fscache_n_retrieval_op_waits); | 418 | __fscache_stat(&fscache_n_retrieval_op_waits), |
382 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 419 | __fscache_stat(&fscache_n_retrievals_object_dead)); |
383 | fscache_wait_bit_interruptible, | 420 | if (ret < 0) |
384 | TASK_INTERRUPTIBLE) < 0) { | 421 | goto error; |
385 | ret = fscache_cancel_op(&op->op); | ||
386 | if (ret == 0) { | ||
387 | ret = -ERESTARTSYS; | ||
388 | goto error; | ||
389 | } | ||
390 | |||
391 | /* it's been removed from the pending queue by another | ||
392 | * party, so we should get to run shortly */ | ||
393 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
394 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
395 | } | ||
396 | _debug("<<< GO"); | ||
397 | } | ||
398 | 422 | ||
399 | /* ask the cache to honour the operation */ | 423 | /* ask the cache to honour the operation */ |
400 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) { | 424 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) { |
@@ -506,25 +530,12 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
506 | 530 | ||
507 | /* we wait for the operation to become active, and then process it | 531 | /* we wait for the operation to become active, and then process it |
508 | * *here*, in this thread, and not in the thread pool */ | 532 | * *here*, in this thread, and not in the thread pool */ |
509 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 533 | ret = fscache_wait_for_retrieval_activation( |
510 | _debug(">>> WT"); | 534 | object, op, |
511 | fscache_stat(&fscache_n_retrieval_op_waits); | 535 | __fscache_stat(&fscache_n_retrieval_op_waits), |
512 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 536 | __fscache_stat(&fscache_n_retrievals_object_dead)); |
513 | fscache_wait_bit_interruptible, | 537 | if (ret < 0) |
514 | TASK_INTERRUPTIBLE) < 0) { | 538 | goto error; |
515 | ret = fscache_cancel_op(&op->op); | ||
516 | if (ret == 0) { | ||
517 | ret = -ERESTARTSYS; | ||
518 | goto error; | ||
519 | } | ||
520 | |||
521 | /* it's been removed from the pending queue by another | ||
522 | * party, so we should get to run shortly */ | ||
523 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
524 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
525 | } | ||
526 | _debug("<<< GO"); | ||
527 | } | ||
528 | 539 | ||
529 | /* ask the cache to honour the operation */ | 540 | /* ask the cache to honour the operation */ |
530 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) { | 541 | if (test_bit(FSCACHE_COOKIE_NO_DATA_YET, &object->cookie->flags)) { |
@@ -612,25 +623,12 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
612 | 623 | ||
613 | fscache_stat(&fscache_n_alloc_ops); | 624 | fscache_stat(&fscache_n_alloc_ops); |
614 | 625 | ||
615 | if (test_bit(FSCACHE_OP_WAITING, &op->op.flags)) { | 626 | ret = fscache_wait_for_retrieval_activation( |
616 | _debug(">>> WT"); | 627 | object, op, |
617 | fscache_stat(&fscache_n_alloc_op_waits); | 628 | __fscache_stat(&fscache_n_alloc_op_waits), |
618 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 629 | __fscache_stat(&fscache_n_allocs_object_dead)); |
619 | fscache_wait_bit_interruptible, | 630 | if (ret < 0) |
620 | TASK_INTERRUPTIBLE) < 0) { | 631 | goto error; |
621 | ret = fscache_cancel_op(&op->op); | ||
622 | if (ret == 0) { | ||
623 | ret = -ERESTARTSYS; | ||
624 | goto error; | ||
625 | } | ||
626 | |||
627 | /* it's been removed from the pending queue by another | ||
628 | * party, so we should get to run shortly */ | ||
629 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | ||
630 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
631 | } | ||
632 | _debug("<<< GO"); | ||
633 | } | ||
634 | 632 | ||
635 | /* ask the cache to honour the operation */ | 633 | /* ask the cache to honour the operation */ |
636 | fscache_stat(&fscache_n_cop_allocate_page); | 634 | fscache_stat(&fscache_n_cop_allocate_page); |
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index 9e15289eb5c1..05f77caf4a2d 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c | |||
@@ -39,6 +39,7 @@ atomic_t fscache_n_allocs_ok; | |||
39 | atomic_t fscache_n_allocs_wait; | 39 | atomic_t fscache_n_allocs_wait; |
40 | atomic_t fscache_n_allocs_nobufs; | 40 | atomic_t fscache_n_allocs_nobufs; |
41 | atomic_t fscache_n_allocs_intr; | 41 | atomic_t fscache_n_allocs_intr; |
42 | atomic_t fscache_n_allocs_object_dead; | ||
42 | atomic_t fscache_n_alloc_ops; | 43 | atomic_t fscache_n_alloc_ops; |
43 | atomic_t fscache_n_alloc_op_waits; | 44 | atomic_t fscache_n_alloc_op_waits; |
44 | 45 | ||
@@ -49,6 +50,7 @@ atomic_t fscache_n_retrievals_nodata; | |||
49 | atomic_t fscache_n_retrievals_nobufs; | 50 | atomic_t fscache_n_retrievals_nobufs; |
50 | atomic_t fscache_n_retrievals_intr; | 51 | atomic_t fscache_n_retrievals_intr; |
51 | atomic_t fscache_n_retrievals_nomem; | 52 | atomic_t fscache_n_retrievals_nomem; |
53 | atomic_t fscache_n_retrievals_object_dead; | ||
52 | atomic_t fscache_n_retrieval_ops; | 54 | atomic_t fscache_n_retrieval_ops; |
53 | atomic_t fscache_n_retrieval_op_waits; | 55 | atomic_t fscache_n_retrieval_op_waits; |
54 | 56 | ||
@@ -188,9 +190,10 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
188 | atomic_read(&fscache_n_allocs_wait), | 190 | atomic_read(&fscache_n_allocs_wait), |
189 | atomic_read(&fscache_n_allocs_nobufs), | 191 | atomic_read(&fscache_n_allocs_nobufs), |
190 | atomic_read(&fscache_n_allocs_intr)); | 192 | atomic_read(&fscache_n_allocs_intr)); |
191 | seq_printf(m, "Allocs : ops=%u owt=%u\n", | 193 | seq_printf(m, "Allocs : ops=%u owt=%u abt=%u\n", |
192 | atomic_read(&fscache_n_alloc_ops), | 194 | atomic_read(&fscache_n_alloc_ops), |
193 | atomic_read(&fscache_n_alloc_op_waits)); | 195 | atomic_read(&fscache_n_alloc_op_waits), |
196 | atomic_read(&fscache_n_allocs_object_dead)); | ||
194 | 197 | ||
195 | seq_printf(m, "Retrvls: n=%u ok=%u wt=%u nod=%u nbf=%u" | 198 | seq_printf(m, "Retrvls: n=%u ok=%u wt=%u nod=%u nbf=%u" |
196 | " int=%u oom=%u\n", | 199 | " int=%u oom=%u\n", |
@@ -201,9 +204,10 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
201 | atomic_read(&fscache_n_retrievals_nobufs), | 204 | atomic_read(&fscache_n_retrievals_nobufs), |
202 | atomic_read(&fscache_n_retrievals_intr), | 205 | atomic_read(&fscache_n_retrievals_intr), |
203 | atomic_read(&fscache_n_retrievals_nomem)); | 206 | atomic_read(&fscache_n_retrievals_nomem)); |
204 | seq_printf(m, "Retrvls: ops=%u owt=%u\n", | 207 | seq_printf(m, "Retrvls: ops=%u owt=%u abt=%u\n", |
205 | atomic_read(&fscache_n_retrieval_ops), | 208 | atomic_read(&fscache_n_retrieval_ops), |
206 | atomic_read(&fscache_n_retrieval_op_waits)); | 209 | atomic_read(&fscache_n_retrieval_op_waits), |
210 | atomic_read(&fscache_n_retrievals_object_dead)); | ||
207 | 211 | ||
208 | seq_printf(m, "Stores : n=%u ok=%u agn=%u nbf=%u oom=%u\n", | 212 | seq_printf(m, "Stores : n=%u ok=%u agn=%u nbf=%u oom=%u\n", |
209 | atomic_read(&fscache_n_stores), | 213 | atomic_read(&fscache_n_stores), |
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 4750d5fb419f..907bb56c5888 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h | |||
@@ -404,6 +404,10 @@ extern const char *fscache_object_states[]; | |||
404 | (obj)->state >= FSCACHE_OBJECT_AVAILABLE && \ | 404 | (obj)->state >= FSCACHE_OBJECT_AVAILABLE && \ |
405 | (obj)->state < FSCACHE_OBJECT_DYING) | 405 | (obj)->state < FSCACHE_OBJECT_DYING) |
406 | 406 | ||
407 | #define fscache_object_is_dead(obj) \ | ||
408 | (test_bit(FSCACHE_IOERROR, &(obj)->cache->flags) && \ | ||
409 | (obj)->state >= FSCACHE_OBJECT_DYING) | ||
410 | |||
407 | extern const struct slow_work_ops fscache_object_slow_work_ops; | 411 | extern const struct slow_work_ops fscache_object_slow_work_ops; |
408 | 412 | ||
409 | /** | 413 | /** |