aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2013-08-21 17:29:38 -0400
committerDavid Howells <dhowells@redhat.com>2013-09-06 04:17:30 -0400
commitda9803bc8812f5bd3b26baaa90e515b843c65ff7 (patch)
tree889b39ec88863fb46606cf345eeb4fdf8a90a67e
parent6e4664525b1db28f8c4e1130957f70a94c19213e (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.txt9
-rw-r--r--Documentation/filesystems/caching/netfs-api.txt17
-rw-r--r--fs/fscache/cookie.c71
-rw-r--r--fs/fscache/internal.h6
-rw-r--r--fs/fscache/page.c55
-rw-r--r--include/linux/fscache-cache.h4
-rw-r--r--include/linux/fscache.h20
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
690error is returned. 690error is returned.
691 691
692 692
693========================== 693===============================
694INDEX AND DATA FILE UPDATE 694INDEX AND DATA FILE CONSISTENCY
695========================== 695===============================
696
697To find out whether auxiliary data for an object is up to data within the
698cache, the following function can be called:
699
700 int fscache_check_consistency(struct fscache_cookie *cookie)
701
702This will call back to the netfs to check whether the auxiliary data associated
703with a cookie is correct. It returns 0 if it is and -ESTALE if it isn't; it
704may also return -ENOMEM and -ERESTARTSYS.
696 705
697To request an update of the index data for an index or other object, the 706To request an update of the index data for an index or other object, the
698following function should be called: 707following 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 */
567int __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
623submit_failed:
624 atomic_dec(&cookie->n_active);
625inconsistent:
626 spin_unlock(&cookie->lock);
627 kfree(op);
628 _leave(" = -ESTALE");
629 return -ESTALE;
630}
631EXPORT_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 */
133extern int fscache_wait_for_deferred_lookup(struct fscache_cookie *);
134extern int fscache_wait_for_operation_activation(struct fscache_object *,
135 struct fscache_operation *,
136 atomic_t *,
137 atomic_t *,
138 void (*)(struct fscache_operation *));
133extern void fscache_invalidate_writes(struct fscache_cookie *); 139extern 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 */
281static int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie) 281int 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 */
325static int fscache_wait_for_retrieval_activation(struct fscache_object *object, 325int 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
351check_if_dead: 353check_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 *);
185extern void __fscache_relinquish_cookie(struct fscache_cookie *, int); 185extern void __fscache_relinquish_cookie(struct fscache_cookie *, int);
186extern int __fscache_check_consistency(struct fscache_cookie *);
186extern void __fscache_update_cookie(struct fscache_cookie *); 187extern void __fscache_update_cookie(struct fscache_cookie *);
187extern int __fscache_attr_changed(struct fscache_cookie *); 188extern int __fscache_attr_changed(struct fscache_cookie *);
188extern void __fscache_invalidate(struct fscache_cookie *); 189extern 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 */
339static inline
340int 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 *