Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+154 -28
+9
Documentation/filesystems/caching/backend-api.txt
··· 299 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 311 (*) Update object [mandatory]: 303 312 304 313 int (*update_object)(struct fscache_object *object)
+13 -4
Documentation/filesystems/caching/netfs-api.txt
··· 32 32 (9) Setting the data file size 33 33 (10) Page alloc/read/write 34 34 (11) Page uncaching 35 - (12) Index and data file update 35 + (12) Index and data file consistency 36 36 (13) Miscellaneous cookie operations 37 37 (14) Cookie unregistration 38 38 (15) Index invalidation ··· 690 690 error is returned. 691 691 692 692 693 - ========================== 694 - INDEX AND DATA FILE UPDATE 695 - ========================== 693 + =============================== 694 + INDEX AND DATA FILE CONSISTENCY 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 706 To request an update of the index data for an index or other object, the 698 707 following function should be called:
+71
fs/fscache/cookie.c
··· 558 558 559 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);
+6
fs/fscache/internal.h
··· 130 130 /* 131 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 139 extern void fscache_invalidate_writes(struct fscache_cookie *); 134 140 135 141 /*
+31 -24
fs/fscache/page.c
··· 278 278 /* 279 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 283 unsigned long jif; 284 284 ··· 322 322 /* 323 323 * wait for an object to become active (or dead) 324 324 */ 325 - static int fscache_wait_for_retrieval_activation(struct fscache_object *object, 326 - struct fscache_retrieval *op, 327 - atomic_t *stat_op_waits, 328 - atomic_t *stat_object_dead) 325 + int fscache_wait_for_operation_activation(struct fscache_object *object, 326 + struct fscache_operation *op, 327 + atomic_t *stat_op_waits, 328 + atomic_t *stat_object_dead, 329 + void (*do_cancel)(struct fscache_operation *)) 329 330 { 330 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 334 goto check_if_dead; 334 335 335 336 _debug(">>> WT"); 336 - fscache_stat(stat_op_waits); 337 - if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, 337 + if (stat_op_waits) 338 + fscache_stat(stat_op_waits); 339 + if (wait_on_bit(&op->flags, FSCACHE_OP_WAITING, 338 340 fscache_wait_bit_interruptible, 339 341 TASK_INTERRUPTIBLE) != 0) { 340 - ret = fscache_cancel_op(&op->op, fscache_do_cancel_retrieval); 342 + ret = fscache_cancel_op(op, do_cancel); 341 343 if (ret == 0) 342 344 return -ERESTARTSYS; 343 345 344 346 /* it's been removed from the pending queue by another party, 345 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 349 fscache_wait_bit, TASK_UNINTERRUPTIBLE); 348 350 } 349 351 _debug("<<< GO"); 350 352 351 353 check_if_dead: 352 - if (op->op.state == FSCACHE_OP_ST_CANCELLED) { 353 - fscache_stat(stat_object_dead); 354 + if (op->state == FSCACHE_OP_ST_CANCELLED) { 355 + if (stat_object_dead) 356 + fscache_stat(stat_object_dead); 354 357 _leave(" = -ENOBUFS [cancelled]"); 355 358 return -ENOBUFS; 356 359 } 357 360 if (unlikely(fscache_object_is_dead(object))) { 358 - pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->op.state); 359 - fscache_cancel_op(&op->op, fscache_do_cancel_retrieval); 360 - fscache_stat(stat_object_dead); 361 + pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->state); 362 + fscache_cancel_op(op, do_cancel); 363 + if (stat_object_dead) 364 + fscache_stat(stat_object_dead); 361 365 return -ENOBUFS; 362 366 } 363 367 return 0; ··· 436 432 437 433 /* we wait for the operation to become active, and then process it 438 434 * *here*, in this thread, and not in the thread pool */ 439 - ret = fscache_wait_for_retrieval_activation( 440 - object, op, 435 + ret = fscache_wait_for_operation_activation( 436 + object, &op->op, 441 437 __fscache_stat(&fscache_n_retrieval_op_waits), 442 - __fscache_stat(&fscache_n_retrievals_object_dead)); 438 + __fscache_stat(&fscache_n_retrievals_object_dead), 439 + fscache_do_cancel_retrieval); 443 440 if (ret < 0) 444 441 goto error; 445 442 ··· 562 557 563 558 /* we wait for the operation to become active, and then process it 564 559 * *here*, in this thread, and not in the thread pool */ 565 - ret = fscache_wait_for_retrieval_activation( 566 - object, op, 560 + ret = fscache_wait_for_operation_activation( 561 + object, &op->op, 567 562 __fscache_stat(&fscache_n_retrieval_op_waits), 568 - __fscache_stat(&fscache_n_retrievals_object_dead)); 563 + __fscache_stat(&fscache_n_retrievals_object_dead), 564 + fscache_do_cancel_retrieval); 569 565 if (ret < 0) 570 566 goto error; 571 567 ··· 664 658 665 659 fscache_stat(&fscache_n_alloc_ops); 666 660 667 - ret = fscache_wait_for_retrieval_activation( 668 - object, op, 661 + ret = fscache_wait_for_operation_activation( 662 + object, &op->op, 669 663 __fscache_stat(&fscache_n_alloc_op_waits), 670 - __fscache_stat(&fscache_n_allocs_object_dead)); 664 + __fscache_stat(&fscache_n_allocs_object_dead), 665 + fscache_do_cancel_retrieval); 671 666 if (ret < 0) 672 667 goto error; 673 668
+4
include/linux/fscache-cache.h
··· 251 251 /* unpin an object in the cache */ 252 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 258 /* store the updated auxiliary data on an object */ 255 259 void (*update_object)(struct fscache_object *object); 256 260
+20
include/linux/fscache.h
··· 183 183 const struct fscache_cookie_def *, 184 184 void *); 185 185 extern void __fscache_relinquish_cookie(struct fscache_cookie *, int); 186 + extern int __fscache_check_consistency(struct fscache_cookie *); 186 187 extern void __fscache_update_cookie(struct fscache_cookie *); 187 188 extern int __fscache_attr_changed(struct fscache_cookie *); 188 189 extern void __fscache_invalidate(struct fscache_cookie *); ··· 324 323 { 325 324 if (fscache_cookie_valid(cookie)) 326 325 __fscache_relinquish_cookie(cookie, retire); 326 + } 327 + 328 + /** 329 + * fscache_check_consistency - Request that if the cache is updated 330 + * @cookie: The cookie representing the cache object 331 + * 332 + * Request an consistency check from fscache, which passes the request 333 + * to the backing cache. 334 + * 335 + * Returns 0 if consistent and -ESTALE if inconsistent. May also 336 + * return -ENOMEM and -ERESTARTSYS. 337 + */ 338 + static inline 339 + int fscache_check_consistency(struct fscache_cookie *cookie) 340 + { 341 + if (fscache_cookie_valid(cookie)) 342 + return __fscache_check_consistency(cookie); 343 + else 344 + return 0; 327 345 } 328 346 329 347 /**