diff options
author | David Howells <dhowells@redhat.com> | 2013-08-21 17:29:38 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2013-09-06 04:17:30 -0400 |
commit | da9803bc8812f5bd3b26baaa90e515b843c65ff7 (patch) | |
tree | 889b39ec88863fb46606cf345eeb4fdf8a90a67e | |
parent | 6e4664525b1db28f8c4e1130957f70a94c19213e (diff) |
FS-Cache: Add interface to check consistency of a cached object
Extend the fscache netfs API so that the netfs can ask as to whether a cache
object is up to date with respect to its corresponding netfs object:
int fscache_check_consistency(struct fscache_cookie *cookie)
This will call back to the netfs to check whether the auxiliary data associated
with a cookie is correct. It returns 0 if it is and -ESTALE if it isn't; it
may also return -ENOMEM and -ERESTARTSYS.
The backends now have to implement a mandatory operation pointer:
int (*check_consistency)(struct fscache_object *object)
that corresponds to the above API call. FS-Cache takes care of pinning the
object and the cookie in memory and managing this call with respect to the
object state.
Original-author: Hongyi Jia <jiayisuse@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Hongyi Jia <jiayisuse@gmail.com>
cc: Milosz Tanski <milosz@adfin.com>
-rw-r--r-- | Documentation/filesystems/caching/backend-api.txt | 9 | ||||
-rw-r--r-- | Documentation/filesystems/caching/netfs-api.txt | 17 | ||||
-rw-r--r-- | fs/fscache/cookie.c | 71 | ||||
-rw-r--r-- | fs/fscache/internal.h | 6 | ||||
-rw-r--r-- | fs/fscache/page.c | 55 | ||||
-rw-r--r-- | include/linux/fscache-cache.h | 4 | ||||
-rw-r--r-- | include/linux/fscache.h | 20 |
7 files changed, 154 insertions, 28 deletions
diff --git a/Documentation/filesystems/caching/backend-api.txt b/Documentation/filesystems/caching/backend-api.txt index d78bab9622c6..277d1e810670 100644 --- a/Documentation/filesystems/caching/backend-api.txt +++ b/Documentation/filesystems/caching/backend-api.txt | |||
@@ -299,6 +299,15 @@ performed on the denizens of the cache. These are held in a structure of type: | |||
299 | enough space in the cache to permit this. | 299 | enough space in the cache to permit this. |
300 | 300 | ||
301 | 301 | ||
302 | (*) Check coherency state of an object [mandatory]: | ||
303 | |||
304 | int (*check_consistency)(struct fscache_object *object) | ||
305 | |||
306 | This method is called to have the cache check the saved auxiliary data of | ||
307 | the object against the netfs's idea of the state. 0 should be returned | ||
308 | if they're consistent and -ESTALE otherwise. -ENOMEM and -ERESTARTSYS | ||
309 | may also be returned. | ||
310 | |||
302 | (*) Update object [mandatory]: | 311 | (*) Update object [mandatory]: |
303 | 312 | ||
304 | int (*update_object)(struct fscache_object *object) | 313 | int (*update_object)(struct fscache_object *object) |
diff --git a/Documentation/filesystems/caching/netfs-api.txt b/Documentation/filesystems/caching/netfs-api.txt index 97e6c0ecc5ef..12b344251523 100644 --- a/Documentation/filesystems/caching/netfs-api.txt +++ b/Documentation/filesystems/caching/netfs-api.txt | |||
@@ -32,7 +32,7 @@ This document contains the following sections: | |||
32 | (9) Setting the data file size | 32 | (9) Setting the data file size |
33 | (10) Page alloc/read/write | 33 | (10) Page alloc/read/write |
34 | (11) Page uncaching | 34 | (11) Page uncaching |
35 | (12) Index and data file update | 35 | (12) Index and data file consistency |
36 | (13) Miscellaneous cookie operations | 36 | (13) Miscellaneous cookie operations |
37 | (14) Cookie unregistration | 37 | (14) Cookie unregistration |
38 | (15) Index invalidation | 38 | (15) Index invalidation |
@@ -690,9 +690,18 @@ written to the cache and for the cache to finish with the page generally. No | |||
690 | error is returned. | 690 | error is returned. |
691 | 691 | ||
692 | 692 | ||
693 | ========================== | 693 | =============================== |
694 | INDEX AND DATA FILE UPDATE | 694 | INDEX AND DATA FILE CONSISTENCY |
695 | ========================== | 695 | =============================== |
696 | |||
697 | To find out whether auxiliary data for an object is up to data within the | ||
698 | cache, the following function can be called: | ||
699 | |||
700 | int fscache_check_consistency(struct fscache_cookie *cookie) | ||
701 | |||
702 | This will call back to the netfs to check whether the auxiliary data associated | ||
703 | with a cookie is correct. It returns 0 if it is and -ESTALE if it isn't; it | ||
704 | may also return -ENOMEM and -ERESTARTSYS. | ||
696 | 705 | ||
697 | To request an update of the index data for an index or other object, the | 706 | To request an update of the index data for an index or other object, the |
698 | following function should be called: | 707 | following function should be called: |
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 0e91a3c9fdb2..318e8433527c 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c | |||
@@ -558,3 +558,74 @@ void __fscache_cookie_put(struct fscache_cookie *cookie) | |||
558 | 558 | ||
559 | _leave(""); | 559 | _leave(""); |
560 | } | 560 | } |
561 | |||
562 | /* | ||
563 | * check the consistency between the netfs inode and the backing cache | ||
564 | * | ||
565 | * NOTE: it only serves no-index type | ||
566 | */ | ||
567 | int __fscache_check_consistency(struct fscache_cookie *cookie) | ||
568 | { | ||
569 | struct fscache_operation *op; | ||
570 | struct fscache_object *object; | ||
571 | int ret; | ||
572 | |||
573 | _enter("%p,", cookie); | ||
574 | |||
575 | ASSERTCMP(cookie->def->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE); | ||
576 | |||
577 | if (fscache_wait_for_deferred_lookup(cookie) < 0) | ||
578 | return -ERESTARTSYS; | ||
579 | |||
580 | if (hlist_empty(&cookie->backing_objects)) | ||
581 | return 0; | ||
582 | |||
583 | op = kzalloc(sizeof(*op), GFP_NOIO | __GFP_NOMEMALLOC | __GFP_NORETRY); | ||
584 | if (!op) | ||
585 | return -ENOMEM; | ||
586 | |||
587 | fscache_operation_init(op, NULL, NULL); | ||
588 | op->flags = FSCACHE_OP_MYTHREAD | | ||
589 | (1 << FSCACHE_OP_WAITING); | ||
590 | |||
591 | spin_lock(&cookie->lock); | ||
592 | |||
593 | if (hlist_empty(&cookie->backing_objects)) | ||
594 | goto inconsistent; | ||
595 | object = hlist_entry(cookie->backing_objects.first, | ||
596 | struct fscache_object, cookie_link); | ||
597 | if (test_bit(FSCACHE_IOERROR, &object->cache->flags)) | ||
598 | goto inconsistent; | ||
599 | |||
600 | op->debug_id = atomic_inc_return(&fscache_op_debug_id); | ||
601 | |||
602 | atomic_inc(&cookie->n_active); | ||
603 | if (fscache_submit_op(object, op) < 0) | ||
604 | goto submit_failed; | ||
605 | |||
606 | /* the work queue now carries its own ref on the object */ | ||
607 | spin_unlock(&cookie->lock); | ||
608 | |||
609 | ret = fscache_wait_for_operation_activation(object, op, | ||
610 | NULL, NULL, NULL); | ||
611 | if (ret == 0) { | ||
612 | /* ask the cache to honour the operation */ | ||
613 | ret = object->cache->ops->check_consistency(op); | ||
614 | fscache_op_complete(op, false); | ||
615 | } else if (ret == -ENOBUFS) { | ||
616 | ret = 0; | ||
617 | } | ||
618 | |||
619 | fscache_put_operation(op); | ||
620 | _leave(" = %d", ret); | ||
621 | return ret; | ||
622 | |||
623 | submit_failed: | ||
624 | atomic_dec(&cookie->n_active); | ||
625 | inconsistent: | ||
626 | spin_unlock(&cookie->lock); | ||
627 | kfree(op); | ||
628 | _leave(" = -ESTALE"); | ||
629 | return -ESTALE; | ||
630 | } | ||
631 | EXPORT_SYMBOL(__fscache_check_consistency); | ||
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index 12d505bedb5c..4226f6680b06 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -130,6 +130,12 @@ extern void fscache_operation_gc(struct work_struct *); | |||
130 | /* | 130 | /* |
131 | * page.c | 131 | * page.c |
132 | */ | 132 | */ |
133 | extern int fscache_wait_for_deferred_lookup(struct fscache_cookie *); | ||
134 | extern int fscache_wait_for_operation_activation(struct fscache_object *, | ||
135 | struct fscache_operation *, | ||
136 | atomic_t *, | ||
137 | atomic_t *, | ||
138 | void (*)(struct fscache_operation *)); | ||
133 | extern void fscache_invalidate_writes(struct fscache_cookie *); | 139 | extern void fscache_invalidate_writes(struct fscache_cookie *); |
134 | 140 | ||
135 | /* | 141 | /* |
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index d479ab3c63e4..793e3d5ca4b5 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -278,7 +278,7 @@ static struct fscache_retrieval *fscache_alloc_retrieval( | |||
278 | /* | 278 | /* |
279 | * wait for a deferred lookup to complete | 279 | * wait for a deferred lookup to complete |
280 | */ | 280 | */ |
281 | static int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie) | 281 | int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie) |
282 | { | 282 | { |
283 | unsigned long jif; | 283 | unsigned long jif; |
284 | 284 | ||
@@ -322,42 +322,46 @@ static void fscache_do_cancel_retrieval(struct fscache_operation *_op) | |||
322 | /* | 322 | /* |
323 | * wait for an object to become active (or dead) | 323 | * wait for an object to become active (or dead) |
324 | */ | 324 | */ |
325 | static int fscache_wait_for_retrieval_activation(struct fscache_object *object, | 325 | int fscache_wait_for_operation_activation(struct fscache_object *object, |
326 | struct fscache_retrieval *op, | 326 | struct fscache_operation *op, |
327 | atomic_t *stat_op_waits, | 327 | atomic_t *stat_op_waits, |
328 | atomic_t *stat_object_dead) | 328 | atomic_t *stat_object_dead, |
329 | void (*do_cancel)(struct fscache_operation *)) | ||
329 | { | 330 | { |
330 | int ret; | 331 | int ret; |
331 | 332 | ||
332 | if (!test_bit(FSCACHE_OP_WAITING, &op->op.flags)) | 333 | if (!test_bit(FSCACHE_OP_WAITING, &op->flags)) |
333 | goto check_if_dead; | 334 | goto check_if_dead; |
334 | 335 | ||
335 | _debug(">>> WT"); | 336 | _debug(">>> WT"); |
336 | fscache_stat(stat_op_waits); | 337 | if (stat_op_waits) |
337 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 338 | fscache_stat(stat_op_waits); |
339 | if (wait_on_bit(&op->flags, FSCACHE_OP_WAITING, | ||
338 | fscache_wait_bit_interruptible, | 340 | fscache_wait_bit_interruptible, |
339 | TASK_INTERRUPTIBLE) != 0) { | 341 | TASK_INTERRUPTIBLE) != 0) { |
340 | ret = fscache_cancel_op(&op->op, fscache_do_cancel_retrieval); | 342 | ret = fscache_cancel_op(op, do_cancel); |
341 | if (ret == 0) | 343 | if (ret == 0) |
342 | return -ERESTARTSYS; | 344 | return -ERESTARTSYS; |
343 | 345 | ||
344 | /* it's been removed from the pending queue by another party, | 346 | /* it's been removed from the pending queue by another party, |
345 | * so we should get to run shortly */ | 347 | * so we should get to run shortly */ |
346 | wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 348 | wait_on_bit(&op->flags, FSCACHE_OP_WAITING, |
347 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | 349 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); |
348 | } | 350 | } |
349 | _debug("<<< GO"); | 351 | _debug("<<< GO"); |
350 | 352 | ||
351 | check_if_dead: | 353 | check_if_dead: |
352 | if (op->op.state == FSCACHE_OP_ST_CANCELLED) { | 354 | if (op->state == FSCACHE_OP_ST_CANCELLED) { |
353 | fscache_stat(stat_object_dead); | 355 | if (stat_object_dead) |
356 | fscache_stat(stat_object_dead); | ||
354 | _leave(" = -ENOBUFS [cancelled]"); | 357 | _leave(" = -ENOBUFS [cancelled]"); |
355 | return -ENOBUFS; | 358 | return -ENOBUFS; |
356 | } | 359 | } |
357 | if (unlikely(fscache_object_is_dead(object))) { | 360 | if (unlikely(fscache_object_is_dead(object))) { |
358 | pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->op.state); | 361 | pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->state); |
359 | fscache_cancel_op(&op->op, fscache_do_cancel_retrieval); | 362 | fscache_cancel_op(op, do_cancel); |
360 | fscache_stat(stat_object_dead); | 363 | if (stat_object_dead) |
364 | fscache_stat(stat_object_dead); | ||
361 | return -ENOBUFS; | 365 | return -ENOBUFS; |
362 | } | 366 | } |
363 | return 0; | 367 | return 0; |
@@ -432,10 +436,11 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
432 | 436 | ||
433 | /* we wait for the operation to become active, and then process it | 437 | /* we wait for the operation to become active, and then process it |
434 | * *here*, in this thread, and not in the thread pool */ | 438 | * *here*, in this thread, and not in the thread pool */ |
435 | ret = fscache_wait_for_retrieval_activation( | 439 | ret = fscache_wait_for_operation_activation( |
436 | object, op, | 440 | object, &op->op, |
437 | __fscache_stat(&fscache_n_retrieval_op_waits), | 441 | __fscache_stat(&fscache_n_retrieval_op_waits), |
438 | __fscache_stat(&fscache_n_retrievals_object_dead)); | 442 | __fscache_stat(&fscache_n_retrievals_object_dead), |
443 | fscache_do_cancel_retrieval); | ||
439 | if (ret < 0) | 444 | if (ret < 0) |
440 | goto error; | 445 | goto error; |
441 | 446 | ||
@@ -557,10 +562,11 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
557 | 562 | ||
558 | /* we wait for the operation to become active, and then process it | 563 | /* we wait for the operation to become active, and then process it |
559 | * *here*, in this thread, and not in the thread pool */ | 564 | * *here*, in this thread, and not in the thread pool */ |
560 | ret = fscache_wait_for_retrieval_activation( | 565 | ret = fscache_wait_for_operation_activation( |
561 | object, op, | 566 | object, &op->op, |
562 | __fscache_stat(&fscache_n_retrieval_op_waits), | 567 | __fscache_stat(&fscache_n_retrieval_op_waits), |
563 | __fscache_stat(&fscache_n_retrievals_object_dead)); | 568 | __fscache_stat(&fscache_n_retrievals_object_dead), |
569 | fscache_do_cancel_retrieval); | ||
564 | if (ret < 0) | 570 | if (ret < 0) |
565 | goto error; | 571 | goto error; |
566 | 572 | ||
@@ -658,10 +664,11 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
658 | 664 | ||
659 | fscache_stat(&fscache_n_alloc_ops); | 665 | fscache_stat(&fscache_n_alloc_ops); |
660 | 666 | ||
661 | ret = fscache_wait_for_retrieval_activation( | 667 | ret = fscache_wait_for_operation_activation( |
662 | object, op, | 668 | object, &op->op, |
663 | __fscache_stat(&fscache_n_alloc_op_waits), | 669 | __fscache_stat(&fscache_n_alloc_op_waits), |
664 | __fscache_stat(&fscache_n_allocs_object_dead)); | 670 | __fscache_stat(&fscache_n_allocs_object_dead), |
671 | fscache_do_cancel_retrieval); | ||
665 | if (ret < 0) | 672 | if (ret < 0) |
666 | goto error; | 673 | goto error; |
667 | 674 | ||
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index a9ff9a36b86d..7823e9ef995e 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h | |||
@@ -251,6 +251,10 @@ struct fscache_cache_ops { | |||
251 | /* unpin an object in the cache */ | 251 | /* unpin an object in the cache */ |
252 | void (*unpin_object)(struct fscache_object *object); | 252 | void (*unpin_object)(struct fscache_object *object); |
253 | 253 | ||
254 | /* check the consistency between the backing cache and the FS-Cache | ||
255 | * cookie */ | ||
256 | bool (*check_consistency)(struct fscache_operation *op); | ||
257 | |||
254 | /* store the updated auxiliary data on an object */ | 258 | /* store the updated auxiliary data on an object */ |
255 | void (*update_object)(struct fscache_object *object); | 259 | void (*update_object)(struct fscache_object *object); |
256 | 260 | ||
diff --git a/include/linux/fscache.h b/include/linux/fscache.h index 7a086235da4b..d984aff32a11 100644 --- a/include/linux/fscache.h +++ b/include/linux/fscache.h | |||
@@ -183,6 +183,7 @@ extern struct fscache_cookie *__fscache_acquire_cookie( | |||
183 | const struct fscache_cookie_def *, | 183 | const struct fscache_cookie_def *, |
184 | void *); | 184 | void *); |
185 | extern void __fscache_relinquish_cookie(struct fscache_cookie *, int); | 185 | extern void __fscache_relinquish_cookie(struct fscache_cookie *, int); |
186 | extern int __fscache_check_consistency(struct fscache_cookie *); | ||
186 | extern void __fscache_update_cookie(struct fscache_cookie *); | 187 | extern void __fscache_update_cookie(struct fscache_cookie *); |
187 | extern int __fscache_attr_changed(struct fscache_cookie *); | 188 | extern int __fscache_attr_changed(struct fscache_cookie *); |
188 | extern void __fscache_invalidate(struct fscache_cookie *); | 189 | extern void __fscache_invalidate(struct fscache_cookie *); |
@@ -326,6 +327,25 @@ void fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
326 | } | 327 | } |
327 | 328 | ||
328 | /** | 329 | /** |
330 | * fscache_check_consistency - Request that if the cache is updated | ||
331 | * @cookie: The cookie representing the cache object | ||
332 | * | ||
333 | * Request an consistency check from fscache, which passes the request | ||
334 | * to the backing cache. | ||
335 | * | ||
336 | * Returns 0 if consistent and -ESTALE if inconsistent. May also | ||
337 | * return -ENOMEM and -ERESTARTSYS. | ||
338 | */ | ||
339 | static inline | ||
340 | int fscache_check_consistency(struct fscache_cookie *cookie) | ||
341 | { | ||
342 | if (fscache_cookie_valid(cookie)) | ||
343 | return __fscache_check_consistency(cookie); | ||
344 | else | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | /** | ||
329 | * fscache_update_cookie - Request that a cache object be updated | 349 | * fscache_update_cookie - Request that a cache object be updated |
330 | * @cookie: The cookie representing the cache object | 350 | * @cookie: The cookie representing the cache object |
331 | * | 351 | * |