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

FS-Cache: Provide the ability to enable/disable cookies

Provide the ability to enable and disable fscache cookies. A disabled cookie
will reject or ignore further requests to:

Acquire a child cookie
Invalidate and update backing objects
Check the consistency of a backing object
Allocate storage for backing page
Read backing pages
Write to backing pages

but still allows:

Checks/waits on the completion of already in-progress objects
Uncaching of pages
Relinquishment of cookies

Two new operations are provided:

(1) Disable a cookie:

void fscache_disable_cookie(struct fscache_cookie *cookie,
bool invalidate);

If the cookie is not already disabled, this locks the cookie against other
dis/enablement ops, marks the cookie as being disabled, discards or
invalidates any backing objects and waits for cessation of activity on any
associated object.

This is a wrapper around a chunk split out of fscache_relinquish_cookie(),
but it reinitialises the cookie such that it can be reenabled.

All possible failures are handled internally. The caller should consider
calling fscache_uncache_all_inode_pages() afterwards to make sure all page
markings are cleared up.

(2) Enable a cookie:

void fscache_enable_cookie(struct fscache_cookie *cookie,
bool (*can_enable)(void *data),
void *data)

If the cookie is not already enabled, this locks the cookie against other
dis/enablement ops, invokes can_enable() and, if the cookie is not an
index cookie, will begin the procedure of acquiring backing objects.

The optional can_enable() function is passed the data argument and returns
a ruling as to whether or not enablement should actually be permitted to
begin.

All possible failures are handled internally. The cookie will only be
marked as enabled if provisional backing objects are allocated.

A later patch will introduce these to NFS. Cookie enablement during nfs_open()
is then contingent on i_writecount <= 0. can_enable() checks for a race
between open(O_RDONLY) and open(O_WRONLY/O_RDWR). This simplifies NFS's cookie
handling and allows us to get rid of open(O_RDONLY) accidentally introducing
caching to an inode that's open for writing already.

One operation has its API modified:

(3) Acquire a cookie.

struct fscache_cookie *fscache_acquire_cookie(
struct fscache_cookie *parent,
const struct fscache_cookie_def *def,
void *netfs_data,
bool enable);

This now has an additional argument that indicates whether the requested
cookie should be enabled by default. It doesn't need the can_enable()
function because the caller must prevent multiple calls for the same netfs
object and it doesn't need to take the enablement lock because no one else
can get at the cookie before this returns.

Signed-off-by: David Howells <dhowells@redhat.com

+334 -132
+60 -13
Documentation/filesystems/caching/netfs-api.txt
··· 29 29 (6) Index registration 30 30 (7) Data file registration 31 31 (8) Miscellaneous object registration 32 - (9) Setting the data file size 32 + (9) Setting the data file size 33 33 (10) Page alloc/read/write 34 34 (11) Page uncaching 35 35 (12) Index and data file consistency 36 - (13) Miscellaneous cookie operations 37 - (14) Cookie unregistration 38 - (15) Index invalidation 39 - (16) Data file invalidation 40 - (17) FS-Cache specific page flags. 36 + (13) Cookie enablement 37 + (14) Miscellaneous cookie operations 38 + (15) Cookie unregistration 39 + (16) Index invalidation 40 + (17) Data file invalidation 41 + (18) FS-Cache specific page flags. 41 42 42 43 43 44 ============================= ··· 335 334 struct fscache_cookie * 336 335 fscache_acquire_cookie(struct fscache_cookie *parent, 337 336 const struct fscache_object_def *def, 338 - void *netfs_data); 337 + void *netfs_data, 338 + bool enable); 339 339 340 340 This function creates an index entry in the index represented by parent, 341 341 filling in the index entry by calling the operations pointed to by def. ··· 352 350 may be created in several different caches independently at different times. 353 351 This is all handled transparently, and the netfs doesn't see any of it. 354 352 353 + A cookie will be created in the disabled state if enabled is false. A cookie 354 + must be enabled to do anything with it. A disabled cookie can be enabled by 355 + calling fscache_enable_cookie() (see below). 356 + 355 357 For example, with AFS, a cell would be added to the primary index. This index 356 358 entry would have a dependent inode containing a volume location index for the 357 359 volume mappings within this cell: ··· 363 357 cell->cache = 364 358 fscache_acquire_cookie(afs_cache_netfs.primary_index, 365 359 &afs_cell_cache_index_def, 366 - cell); 360 + cell, true); 367 361 368 362 Then when a volume location was accessed, it would be entered into the cell's 369 363 index and an inode would be allocated that acts as a volume type and hash chain ··· 372 366 vlocation->cache = 373 367 fscache_acquire_cookie(cell->cache, 374 368 &afs_vlocation_cache_index_def, 375 - vlocation); 369 + vlocation, true); 376 370 377 371 And then a particular flavour of volume (R/O for example) could be added to 378 372 that index, creating another index for vnodes (AFS inode equivalents): ··· 380 374 volume->cache = 381 375 fscache_acquire_cookie(vlocation->cache, 382 376 &afs_volume_cache_index_def, 383 - volume); 377 + volume, true); 384 378 385 379 386 380 ====================== ··· 394 388 vnode->cache = 395 389 fscache_acquire_cookie(volume->cache, 396 390 &afs_vnode_cache_object_def, 397 - vnode); 391 + vnode, true); 398 392 399 393 400 394 ================================= ··· 410 404 xattr->cache = 411 405 fscache_acquire_cookie(vnode->cache, 412 406 &afs_xattr_cache_object_def, 413 - xattr); 407 + xattr, true); 414 408 415 409 Miscellaneous objects might be used to store extended attributes or directory 416 410 entries for example. ··· 739 733 data blocks are added to a data file object. 740 734 741 735 736 + ================= 737 + COOKIE ENABLEMENT 738 + ================= 739 + 740 + Cookies exist in one of two states: enabled and disabled. If a cookie is 741 + disabled, it ignores all attempts to acquire child cookies; check, update or 742 + invalidate its state; allocate, read or write backing pages - though it is 743 + still possible to uncache pages and relinquish the cookie. 744 + 745 + The initial enablement state is set by fscache_acquire_cookie(), but the cookie 746 + can be enabled or disabled later. To disable a cookie, call: 747 + 748 + void fscache_disable_cookie(struct fscache_cookie *cookie, 749 + bool invalidate); 750 + 751 + If the cookie is not already disabled, this locks the cookie against other 752 + enable and disable ops, marks the cookie as being disabled, discards or 753 + invalidates any backing objects and waits for cessation of activity on any 754 + associated object before unlocking the cookie. 755 + 756 + All possible failures are handled internally. The caller should consider 757 + calling fscache_uncache_all_inode_pages() afterwards to make sure all page 758 + markings are cleared up. 759 + 760 + Cookies can be enabled or reenabled with: 761 + 762 + void fscache_enable_cookie(struct fscache_cookie *cookie, 763 + bool (*can_enable)(void *data), 764 + void *data) 765 + 766 + If the cookie is not already enabled, this locks the cookie against other 767 + enable and disable ops, invokes can_enable() and, if the cookie is not an index 768 + cookie, will begin the procedure of acquiring backing objects. 769 + 770 + The optional can_enable() function is passed the data argument and returns a 771 + ruling as to whether or not enablement should actually be permitted to begin. 772 + 773 + All possible failures are handled internally. The cookie will only be marked 774 + as enabled if provisional backing objects are allocated. 775 + 776 + 742 777 =============================== 743 778 MISCELLANEOUS COOKIE OPERATIONS 744 779 =============================== ··· 825 778 To get rid of a cookie, this function should be called. 826 779 827 780 void fscache_relinquish_cookie(struct fscache_cookie *cookie, 828 - int retire); 781 + bool retire); 829 782 830 783 If retire is non-zero, then the object will be marked for recycling, and all 831 784 copies of it will be removed from all active caches in which it is present.
+3 -3
fs/9p/cache.c
··· 90 90 91 91 v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index, 92 92 &v9fs_cache_session_index_def, 93 - v9ses); 93 + v9ses, true); 94 94 p9_debug(P9_DEBUG_FSC, "session %p get cookie %p\n", 95 95 v9ses, v9ses->fscache); 96 96 } ··· 204 204 v9ses = v9fs_inode2v9ses(inode); 205 205 v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, 206 206 &v9fs_cache_inode_index_def, 207 - v9inode); 207 + v9inode, true); 208 208 209 209 p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n", 210 210 inode, v9inode->fscache); ··· 271 271 v9ses = v9fs_inode2v9ses(inode); 272 272 v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, 273 273 &v9fs_cache_inode_index_def, 274 - v9inode); 274 + v9inode, true); 275 275 p9_debug(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p\n", 276 276 inode, old, v9inode->fscache); 277 277
+1 -1
fs/afs/cell.c
··· 179 179 /* put it up for caching (this never returns an error) */ 180 180 cell->cache = fscache_acquire_cookie(afs_cache_netfs.primary_index, 181 181 &afs_cell_cache_index_def, 182 - cell); 182 + cell, true); 183 183 #endif 184 184 185 185 /* add to the cell lists */
+1 -1
fs/afs/inode.c
··· 259 259 #ifdef CONFIG_AFS_FSCACHE 260 260 vnode->cache = fscache_acquire_cookie(vnode->volume->cache, 261 261 &afs_vnode_cache_index_def, 262 - vnode); 262 + vnode, true); 263 263 #endif 264 264 265 265 ret = afs_inode_map_status(vnode, key);
+2 -1
fs/afs/vlocation.c
··· 308 308 /* see if we have an in-cache copy (will set vl->valid if there is) */ 309 309 #ifdef CONFIG_AFS_FSCACHE 310 310 vl->cache = fscache_acquire_cookie(vl->cell->cache, 311 - &afs_vlocation_cache_index_def, vl); 311 + &afs_vlocation_cache_index_def, vl, 312 + true); 312 313 #endif 313 314 314 315 if (vl->valid) {
+1 -1
fs/afs/volume.c
··· 131 131 #ifdef CONFIG_AFS_FSCACHE 132 132 volume->cache = fscache_acquire_cookie(vlocation->cache, 133 133 &afs_volume_cache_index_def, 134 - volume); 134 + volume, true); 135 135 #endif 136 136 afs_get_vlocation(vlocation); 137 137 volume->vlocation = vlocation;
+1 -1
fs/cachefiles/interface.c
··· 270 270 #endif 271 271 272 272 /* delete retired objects */ 273 - if (test_bit(FSCACHE_COOKIE_RETIRED, &object->fscache.cookie->flags) && 273 + if (test_bit(FSCACHE_OBJECT_RETIRED, &object->fscache.flags) && 274 274 _object != cache->cache.fsdef 275 275 ) { 276 276 _debug("- retire object OBJ%x", object->fscache.debug_id);
+2 -2
fs/ceph/cache.c
··· 68 68 { 69 69 fsc->fscache = fscache_acquire_cookie(ceph_cache_netfs.primary_index, 70 70 &ceph_fscache_fsid_object_def, 71 - fsc); 71 + fsc, true); 72 72 73 73 if (fsc->fscache == NULL) { 74 74 pr_err("Unable to resgister fsid: %p fscache cookie", fsc); ··· 204 204 205 205 ci->fscache = fscache_acquire_cookie(fsc->fscache, 206 206 &ceph_fscache_inode_object_def, 207 - ci); 207 + ci, true); 208 208 done: 209 209 mutex_unlock(&inode->i_mutex); 210 210
+4 -4
fs/cifs/fscache.c
··· 27 27 { 28 28 server->fscache = 29 29 fscache_acquire_cookie(cifs_fscache_netfs.primary_index, 30 - &cifs_fscache_server_index_def, server); 30 + &cifs_fscache_server_index_def, server, true); 31 31 cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", 32 32 __func__, server, server->fscache); 33 33 } ··· 46 46 47 47 tcon->fscache = 48 48 fscache_acquire_cookie(server->fscache, 49 - &cifs_fscache_super_index_def, tcon); 49 + &cifs_fscache_super_index_def, tcon, true); 50 50 cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", 51 51 __func__, server->fscache, tcon->fscache); 52 52 } ··· 69 69 70 70 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) { 71 71 cifsi->fscache = fscache_acquire_cookie(tcon->fscache, 72 - &cifs_fscache_inode_object_def, cifsi); 72 + &cifs_fscache_inode_object_def, cifsi, true); 73 73 cifs_dbg(FYI, "%s: got FH cookie (0x%p/0x%p)\n", 74 74 __func__, tcon->fscache, cifsi->fscache); 75 75 } ··· 119 119 cifsi->fscache = fscache_acquire_cookie( 120 120 cifs_sb_master_tcon(cifs_sb)->fscache, 121 121 &cifs_fscache_inode_object_def, 122 - cifsi); 122 + cifsi, true); 123 123 cifs_dbg(FYI, "%s: new cookie 0x%p oldcookie 0x%p\n", 124 124 __func__, cifsi->fscache, old); 125 125 }
+137 -49
fs/fscache/cookie.c
··· 58 58 struct fscache_cookie *__fscache_acquire_cookie( 59 59 struct fscache_cookie *parent, 60 60 const struct fscache_cookie_def *def, 61 - void *netfs_data) 61 + void *netfs_data, 62 + bool enable) 62 63 { 63 64 struct fscache_cookie *cookie; 64 65 65 66 BUG_ON(!def); 66 67 67 - _enter("{%s},{%s},%p", 68 + _enter("{%s},{%s},%p,%u", 68 69 parent ? (char *) parent->def->name : "<no-parent>", 69 - def->name, netfs_data); 70 + def->name, netfs_data, enable); 70 71 71 72 fscache_stat(&fscache_n_acquires); 72 73 ··· 107 106 cookie->def = def; 108 107 cookie->parent = parent; 109 108 cookie->netfs_data = netfs_data; 110 - cookie->flags = 0; 109 + cookie->flags = (1 << FSCACHE_COOKIE_NO_DATA_YET); 111 110 112 111 /* radix tree insertion won't use the preallocation pool unless it's 113 112 * told it may not wait */ ··· 125 124 break; 126 125 } 127 126 128 - /* if the object is an index then we need do nothing more here - we 129 - * create indices on disk when we need them as an index may exist in 130 - * multiple caches */ 131 - if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { 132 - if (fscache_acquire_non_index_cookie(cookie) < 0) { 133 - atomic_dec(&parent->n_children); 134 - __fscache_cookie_put(cookie); 135 - fscache_stat(&fscache_n_acquires_nobufs); 136 - _leave(" = NULL"); 137 - return NULL; 127 + if (enable) { 128 + /* if the object is an index then we need do nothing more here 129 + * - we create indices on disk when we need them as an index 130 + * may exist in multiple caches */ 131 + if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { 132 + if (fscache_acquire_non_index_cookie(cookie) == 0) { 133 + set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); 134 + } else { 135 + atomic_dec(&parent->n_children); 136 + __fscache_cookie_put(cookie); 137 + fscache_stat(&fscache_n_acquires_nobufs); 138 + _leave(" = NULL"); 139 + return NULL; 140 + } 141 + } else { 142 + set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); 138 143 } 139 144 } 140 145 ··· 149 142 return cookie; 150 143 } 151 144 EXPORT_SYMBOL(__fscache_acquire_cookie); 145 + 146 + /* 147 + * Enable a cookie to permit it to accept new operations. 148 + */ 149 + void __fscache_enable_cookie(struct fscache_cookie *cookie, 150 + bool (*can_enable)(void *data), 151 + void *data) 152 + { 153 + _enter("%p", cookie); 154 + 155 + wait_on_bit_lock(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK, 156 + fscache_wait_bit, TASK_UNINTERRUPTIBLE); 157 + 158 + if (test_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags)) 159 + goto out_unlock; 160 + 161 + if (can_enable && !can_enable(data)) { 162 + /* The netfs decided it didn't want to enable after all */ 163 + } else if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { 164 + /* Wait for outstanding disablement to complete */ 165 + __fscache_wait_on_invalidate(cookie); 166 + 167 + if (fscache_acquire_non_index_cookie(cookie) == 0) 168 + set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); 169 + } else { 170 + set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); 171 + } 172 + 173 + out_unlock: 174 + clear_bit_unlock(FSCACHE_COOKIE_ENABLEMENT_LOCK, &cookie->flags); 175 + wake_up_bit(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK); 176 + } 177 + EXPORT_SYMBOL(__fscache_enable_cookie); 152 178 153 179 /* 154 180 * acquire a non-index cookie ··· 197 157 198 158 _enter(""); 199 159 200 - cookie->flags = 1 << FSCACHE_COOKIE_UNAVAILABLE; 160 + set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); 201 161 202 162 /* now we need to see whether the backing objects for this cookie yet 203 163 * exist, if not there'll be nothing to search */ ··· 220 180 221 181 _debug("cache %s", cache->tag->name); 222 182 223 - cookie->flags = 224 - (1 << FSCACHE_COOKIE_LOOKING_UP) | 225 - (1 << FSCACHE_COOKIE_NO_DATA_YET); 183 + set_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags); 226 184 227 185 /* ask the cache to allocate objects for this cookie and its parent 228 186 * chain */ ··· 436 398 if (!hlist_empty(&cookie->backing_objects)) { 437 399 spin_lock(&cookie->lock); 438 400 439 - if (!hlist_empty(&cookie->backing_objects) && 401 + if (fscache_cookie_enabled(cookie) && 402 + !hlist_empty(&cookie->backing_objects) && 440 403 !test_and_set_bit(FSCACHE_COOKIE_INVALIDATING, 441 404 &cookie->flags)) { 442 405 object = hlist_entry(cookie->backing_objects.first, ··· 491 452 492 453 spin_lock(&cookie->lock); 493 454 494 - /* update the index entry on disk in each cache backing this cookie */ 495 - hlist_for_each_entry(object, 496 - &cookie->backing_objects, cookie_link) { 497 - fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); 455 + if (fscache_cookie_enabled(cookie)) { 456 + /* update the index entry on disk in each cache backing this 457 + * cookie. 458 + */ 459 + hlist_for_each_entry(object, 460 + &cookie->backing_objects, cookie_link) { 461 + fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); 462 + } 498 463 } 499 464 500 465 spin_unlock(&cookie->lock); ··· 507 464 EXPORT_SYMBOL(__fscache_update_cookie); 508 465 509 466 /* 467 + * Disable a cookie to stop it from accepting new requests from the netfs. 468 + */ 469 + void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) 470 + { 471 + struct fscache_object *object; 472 + bool awaken = false; 473 + 474 + _enter("%p,%u", cookie, invalidate); 475 + 476 + ASSERTCMP(atomic_read(&cookie->n_active), >, 0); 477 + 478 + if (atomic_read(&cookie->n_children) != 0) { 479 + printk(KERN_ERR "FS-Cache: Cookie '%s' still has children\n", 480 + cookie->def->name); 481 + BUG(); 482 + } 483 + 484 + wait_on_bit_lock(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK, 485 + fscache_wait_bit, TASK_UNINTERRUPTIBLE); 486 + if (!test_and_clear_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags)) 487 + goto out_unlock_enable; 488 + 489 + /* If the cookie is being invalidated, wait for that to complete first 490 + * so that we can reuse the flag. 491 + */ 492 + __fscache_wait_on_invalidate(cookie); 493 + 494 + /* Dispose of the backing objects */ 495 + set_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags); 496 + 497 + spin_lock(&cookie->lock); 498 + if (!hlist_empty(&cookie->backing_objects)) { 499 + hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) { 500 + if (invalidate) 501 + set_bit(FSCACHE_OBJECT_RETIRED, &object->flags); 502 + fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); 503 + } 504 + } else { 505 + if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) 506 + awaken = true; 507 + } 508 + spin_unlock(&cookie->lock); 509 + if (awaken) 510 + wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); 511 + 512 + /* Wait for cessation of activity requiring access to the netfs (when 513 + * n_active reaches 0). This makes sure outstanding reads and writes 514 + * have completed. 515 + */ 516 + if (!atomic_dec_and_test(&cookie->n_active)) 517 + wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, 518 + TASK_UNINTERRUPTIBLE); 519 + 520 + /* Reset the cookie state if it wasn't relinquished */ 521 + if (!test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) { 522 + atomic_inc(&cookie->n_active); 523 + set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); 524 + } 525 + 526 + out_unlock_enable: 527 + clear_bit_unlock(FSCACHE_COOKIE_ENABLEMENT_LOCK, &cookie->flags); 528 + wake_up_bit(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK); 529 + _leave(""); 530 + } 531 + EXPORT_SYMBOL(__fscache_disable_cookie); 532 + 533 + /* 510 534 * release a cookie back to the cache 511 535 * - the object will be marked as recyclable on disk if retire is true 512 536 * - all dependents of this cookie must have already been unregistered 513 537 * (indices/files/pages) 514 538 */ 515 - void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) 539 + void __fscache_relinquish_cookie(struct fscache_cookie *cookie, bool retire) 516 540 { 517 - struct fscache_object *object; 518 - 519 541 fscache_stat(&fscache_n_relinquishes); 520 542 if (retire) 521 543 fscache_stat(&fscache_n_relinquishes_retire); ··· 595 487 cookie, cookie->def->name, cookie->netfs_data, 596 488 atomic_read(&cookie->n_active), retire); 597 489 598 - ASSERTCMP(atomic_read(&cookie->n_active), >, 0); 599 - 600 - if (atomic_read(&cookie->n_children) != 0) { 601 - printk(KERN_ERR "FS-Cache: Cookie '%s' still has children\n", 602 - cookie->def->name); 603 - BUG(); 604 - } 605 - 606 490 /* No further netfs-accessing operations on this cookie permitted */ 607 491 set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags); 608 - if (retire) 609 - set_bit(FSCACHE_COOKIE_RETIRED, &cookie->flags); 610 492 611 - spin_lock(&cookie->lock); 612 - hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) { 613 - fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL); 614 - } 615 - spin_unlock(&cookie->lock); 616 - 617 - /* Wait for cessation of activity requiring access to the netfs (when 618 - * n_active reaches 0). 619 - */ 620 - if (!atomic_dec_and_test(&cookie->n_active)) 621 - wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t, 622 - TASK_UNINTERRUPTIBLE); 493 + __fscache_disable_cookie(cookie, retire); 623 494 624 495 /* Clear pointers back to the netfs */ 625 496 cookie->netfs_data = NULL; ··· 679 592 680 593 spin_lock(&cookie->lock); 681 594 682 - if (hlist_empty(&cookie->backing_objects)) 595 + if (!fscache_cookie_enabled(cookie) || 596 + hlist_empty(&cookie->backing_objects)) 683 597 goto inconsistent; 684 598 object = hlist_entry(cookie->backing_objects.first, 685 599 struct fscache_object, cookie_link);
+1
fs/fscache/fsdef.c
··· 59 59 .lock = __SPIN_LOCK_UNLOCKED(fscache_fsdef_index.lock), 60 60 .backing_objects = HLIST_HEAD_INIT, 61 61 .def = &fscache_fsdef_index_def, 62 + .flags = 1 << FSCACHE_COOKIE_ENABLED, 62 63 }; 63 64 EXPORT_SYMBOL(fscache_fsdef_index); 64 65
+1
fs/fscache/netfs.c
··· 45 45 netfs->primary_index->def = &fscache_fsdef_netfs_def; 46 46 netfs->primary_index->parent = &fscache_fsdef_index; 47 47 netfs->primary_index->netfs_data = netfs; 48 + netfs->primary_index->flags = 1 << FSCACHE_COOKIE_ENABLED; 48 49 49 50 atomic_inc(&netfs->primary_index->parent->usage); 50 51 atomic_inc(&netfs->primary_index->parent->n_children);
+5 -2
fs/fscache/object.c
··· 495 495 * returning ENODATA. 496 496 */ 497 497 set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); 498 + clear_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); 498 499 499 500 _debug("wake up lookup %p", &cookie->flags); 500 501 clear_bit_unlock(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags); ··· 528 527 529 528 /* We do (presumably) have data */ 530 529 clear_bit_unlock(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); 530 + clear_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); 531 531 532 532 /* Allow write requests to begin stacking up and read requests 533 533 * to begin shovelling data. ··· 681 679 */ 682 680 spin_lock(&cookie->lock); 683 681 hlist_del_init(&object->cookie_link); 684 - if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) 682 + if (hlist_empty(&cookie->backing_objects) && 683 + test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) 685 684 awaken = true; 686 685 spin_unlock(&cookie->lock); 687 686 ··· 930 927 */ 931 928 if (!fscache_use_cookie(object)) { 932 929 ASSERT(object->cookie->stores.rnode == NULL); 933 - set_bit(FSCACHE_COOKIE_RETIRED, &cookie->flags); 930 + set_bit(FSCACHE_OBJECT_RETIRED, &object->flags); 934 931 _leave(" [no cookie]"); 935 932 return transit_to(KILL_OBJECT); 936 933 }
+11 -6
fs/fscache/page.c
··· 204 204 205 205 spin_lock(&cookie->lock); 206 206 207 - if (hlist_empty(&cookie->backing_objects)) 207 + if (!fscache_cookie_enabled(cookie) || 208 + hlist_empty(&cookie->backing_objects)) 208 209 goto nobufs; 209 210 object = hlist_entry(cookie->backing_objects.first, 210 211 struct fscache_object, cookie_link); ··· 411 410 return -ERESTARTSYS; 412 411 413 412 op = fscache_alloc_retrieval(cookie, page->mapping, 414 - end_io_func,context); 413 + end_io_func, context); 415 414 if (!op) { 416 415 _leave(" = -ENOMEM"); 417 416 return -ENOMEM; ··· 420 419 421 420 spin_lock(&cookie->lock); 422 421 423 - if (hlist_empty(&cookie->backing_objects)) 422 + if (!fscache_cookie_enabled(cookie) || 423 + hlist_empty(&cookie->backing_objects)) 424 424 goto nobufs_unlock; 425 425 object = hlist_entry(cookie->backing_objects.first, 426 426 struct fscache_object, cookie_link); ··· 553 551 554 552 spin_lock(&cookie->lock); 555 553 556 - if (hlist_empty(&cookie->backing_objects)) 554 + if (!fscache_cookie_enabled(cookie) || 555 + hlist_empty(&cookie->backing_objects)) 557 556 goto nobufs_unlock; 558 557 object = hlist_entry(cookie->backing_objects.first, 559 558 struct fscache_object, cookie_link); ··· 669 666 670 667 spin_lock(&cookie->lock); 671 668 672 - if (hlist_empty(&cookie->backing_objects)) 669 + if (!fscache_cookie_enabled(cookie) || 670 + hlist_empty(&cookie->backing_objects)) 673 671 goto nobufs_unlock; 674 672 object = hlist_entry(cookie->backing_objects.first, 675 673 struct fscache_object, cookie_link); ··· 942 938 ret = -ENOBUFS; 943 939 spin_lock(&cookie->lock); 944 940 945 - if (hlist_empty(&cookie->backing_objects)) 941 + if (!fscache_cookie_enabled(cookie) || 942 + hlist_empty(&cookie->backing_objects)) 946 943 goto nobufs; 947 944 object = hlist_entry(cookie->backing_objects.first, 948 945 struct fscache_object, cookie_link);
+4 -4
fs/nfs/fscache.c
··· 39 39 /* create a cache index for looking up filehandles */ 40 40 clp->fscache = fscache_acquire_cookie(nfs_fscache_netfs.primary_index, 41 41 &nfs_fscache_server_index_def, 42 - clp); 42 + clp, true); 43 43 dfprintk(FSCACHE, "NFS: get client cookie (0x%p/0x%p)\n", 44 44 clp, clp->fscache); 45 45 } ··· 139 139 /* create a cache index for looking up filehandles */ 140 140 nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache, 141 141 &nfs_fscache_super_index_def, 142 - nfss); 142 + nfss, true); 143 143 dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n", 144 144 nfss, nfss->fscache); 145 145 return; ··· 200 200 nfsi->fscache = fscache_acquire_cookie( 201 201 NFS_SB(sb)->fscache, 202 202 &nfs_fscache_inode_object_def, 203 - nfsi); 203 + nfsi, true); 204 204 205 205 dfprintk(FSCACHE, "NFS: get FH cookie (0x%p/0x%p/0x%p)\n", 206 206 sb, nfsi, nfsi->fscache); ··· 327 327 nfsi->fscache = fscache_acquire_cookie( 328 328 nfss->nfs_client->fscache, 329 329 &nfs_fscache_inode_object_def, 330 - nfsi); 330 + nfsi, true); 331 331 332 332 dfprintk(FSCACHE, 333 333 "NFS: revalidation new cookie (0x%p/0x%p/0x%p/0x%p)\n",
+1 -30
include/linux/fscache-cache.h
··· 308 308 void (*dissociate_pages)(struct fscache_cache *cache); 309 309 }; 310 310 311 - /* 312 - * data file or index object cookie 313 - * - a file will only appear in one cache 314 - * - a request to cache a file may or may not be honoured, subject to 315 - * constraints such as disk space 316 - * - indices are created on disk just-in-time 317 - */ 318 - struct fscache_cookie { 319 - atomic_t usage; /* number of users of this cookie */ 320 - atomic_t n_children; /* number of children of this cookie */ 321 - atomic_t n_active; /* number of active users of netfs ptrs */ 322 - spinlock_t lock; 323 - spinlock_t stores_lock; /* lock on page store tree */ 324 - struct hlist_head backing_objects; /* object(s) backing this file/index */ 325 - const struct fscache_cookie_def *def; /* definition */ 326 - struct fscache_cookie *parent; /* parent of this entry */ 327 - void *netfs_data; /* back pointer to netfs */ 328 - struct radix_tree_root stores; /* pages to be stored on this cookie */ 329 - #define FSCACHE_COOKIE_PENDING_TAG 0 /* pages tag: pending write to cache */ 330 - #define FSCACHE_COOKIE_STORING_TAG 1 /* pages tag: writing to cache */ 331 - 332 - unsigned long flags; 333 - #define FSCACHE_COOKIE_LOOKING_UP 0 /* T if non-index cookie being looked up still */ 334 - #define FSCACHE_COOKIE_NO_DATA_YET 1 /* T if new object with no cached data yet */ 335 - #define FSCACHE_COOKIE_UNAVAILABLE 2 /* T if cookie is unavailable (error, etc) */ 336 - #define FSCACHE_COOKIE_INVALIDATING 3 /* T if cookie is being invalidated */ 337 - #define FSCACHE_COOKIE_RELINQUISHED 4 /* T if cookie has been relinquished */ 338 - #define FSCACHE_COOKIE_RETIRED 5 /* T if cookie was retired */ 339 - }; 340 - 341 311 extern struct fscache_cookie fscache_fsdef_index; 342 312 343 313 /* ··· 370 400 #define FSCACHE_OBJECT_IS_LIVE 3 /* T if object is not withdrawn or relinquished */ 371 401 #define FSCACHE_OBJECT_IS_LOOKED_UP 4 /* T if object has been looked up */ 372 402 #define FSCACHE_OBJECT_IS_AVAILABLE 5 /* T if object has become active */ 403 + #define FSCACHE_OBJECT_RETIRED 6 /* T if object was retired on relinquishment */ 373 404 374 405 struct list_head cache_link; /* link in cache->object_list */ 375 406 struct hlist_node cookie_link; /* link in cookie->backing_objects */
+99 -14
include/linux/fscache.h
··· 167 167 }; 168 168 169 169 /* 170 + * data file or index object cookie 171 + * - a file will only appear in one cache 172 + * - a request to cache a file may or may not be honoured, subject to 173 + * constraints such as disk space 174 + * - indices are created on disk just-in-time 175 + */ 176 + struct fscache_cookie { 177 + atomic_t usage; /* number of users of this cookie */ 178 + atomic_t n_children; /* number of children of this cookie */ 179 + atomic_t n_active; /* number of active users of netfs ptrs */ 180 + spinlock_t lock; 181 + spinlock_t stores_lock; /* lock on page store tree */ 182 + struct hlist_head backing_objects; /* object(s) backing this file/index */ 183 + const struct fscache_cookie_def *def; /* definition */ 184 + struct fscache_cookie *parent; /* parent of this entry */ 185 + void *netfs_data; /* back pointer to netfs */ 186 + struct radix_tree_root stores; /* pages to be stored on this cookie */ 187 + #define FSCACHE_COOKIE_PENDING_TAG 0 /* pages tag: pending write to cache */ 188 + #define FSCACHE_COOKIE_STORING_TAG 1 /* pages tag: writing to cache */ 189 + 190 + unsigned long flags; 191 + #define FSCACHE_COOKIE_LOOKING_UP 0 /* T if non-index cookie being looked up still */ 192 + #define FSCACHE_COOKIE_NO_DATA_YET 1 /* T if new object with no cached data yet */ 193 + #define FSCACHE_COOKIE_UNAVAILABLE 2 /* T if cookie is unavailable (error, etc) */ 194 + #define FSCACHE_COOKIE_INVALIDATING 3 /* T if cookie is being invalidated */ 195 + #define FSCACHE_COOKIE_RELINQUISHED 4 /* T if cookie has been relinquished */ 196 + #define FSCACHE_COOKIE_ENABLED 5 /* T if cookie is enabled */ 197 + #define FSCACHE_COOKIE_ENABLEMENT_LOCK 6 /* T if cookie is being en/disabled */ 198 + }; 199 + 200 + static inline bool fscache_cookie_enabled(struct fscache_cookie *cookie) 201 + { 202 + return test_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); 203 + } 204 + 205 + /* 170 206 * slow-path functions for when there is actually caching available, and the 171 207 * netfs does actually have a valid token 172 208 * - these are not to be called directly ··· 217 181 extern struct fscache_cookie *__fscache_acquire_cookie( 218 182 struct fscache_cookie *, 219 183 const struct fscache_cookie_def *, 220 - void *); 221 - extern void __fscache_relinquish_cookie(struct fscache_cookie *, int); 184 + void *, bool); 185 + extern void __fscache_relinquish_cookie(struct fscache_cookie *, bool); 222 186 extern int __fscache_check_consistency(struct fscache_cookie *); 223 187 extern void __fscache_update_cookie(struct fscache_cookie *); 224 188 extern int __fscache_attr_changed(struct fscache_cookie *); ··· 247 211 struct inode *); 248 212 extern void __fscache_readpages_cancel(struct fscache_cookie *cookie, 249 213 struct list_head *pages); 214 + extern void __fscache_disable_cookie(struct fscache_cookie *, bool); 215 + extern void __fscache_enable_cookie(struct fscache_cookie *, 216 + bool (*)(void *), void *); 250 217 251 218 /** 252 219 * fscache_register_netfs - Register a filesystem as desiring caching services ··· 328 289 * @def: A description of the cache object, including callback operations 329 290 * @netfs_data: An arbitrary piece of data to be kept in the cookie to 330 291 * represent the cache object to the netfs 292 + * @enable: Whether or not to enable a data cookie immediately 331 293 * 332 294 * This function is used to inform FS-Cache about part of an index hierarchy 333 295 * that can be used to locate files. This is done by requesting a cookie for ··· 341 301 struct fscache_cookie *fscache_acquire_cookie( 342 302 struct fscache_cookie *parent, 343 303 const struct fscache_cookie_def *def, 344 - void *netfs_data) 304 + void *netfs_data, 305 + bool enable) 345 306 { 346 - if (fscache_cookie_valid(parent)) 347 - return __fscache_acquire_cookie(parent, def, netfs_data); 307 + if (fscache_cookie_valid(parent) && fscache_cookie_enabled(parent)) 308 + return __fscache_acquire_cookie(parent, def, netfs_data, 309 + enable); 348 310 else 349 311 return NULL; 350 312 } ··· 364 322 * description. 365 323 */ 366 324 static inline 367 - void fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) 325 + void fscache_relinquish_cookie(struct fscache_cookie *cookie, bool retire) 368 326 { 369 327 if (fscache_cookie_valid(cookie)) 370 328 __fscache_relinquish_cookie(cookie, retire); ··· 383 341 static inline 384 342 int fscache_check_consistency(struct fscache_cookie *cookie) 385 343 { 386 - if (fscache_cookie_valid(cookie)) 344 + if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) 387 345 return __fscache_check_consistency(cookie); 388 346 else 389 347 return 0; ··· 402 360 static inline 403 361 void fscache_update_cookie(struct fscache_cookie *cookie) 404 362 { 405 - if (fscache_cookie_valid(cookie)) 363 + if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) 406 364 __fscache_update_cookie(cookie); 407 365 } 408 366 ··· 449 407 static inline 450 408 int fscache_attr_changed(struct fscache_cookie *cookie) 451 409 { 452 - if (fscache_cookie_valid(cookie)) 410 + if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) 453 411 return __fscache_attr_changed(cookie); 454 412 else 455 413 return -ENOBUFS; ··· 471 429 static inline 472 430 void fscache_invalidate(struct fscache_cookie *cookie) 473 431 { 474 - if (fscache_cookie_valid(cookie)) 432 + if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) 475 433 __fscache_invalidate(cookie); 476 434 } 477 435 ··· 545 503 void *context, 546 504 gfp_t gfp) 547 505 { 548 - if (fscache_cookie_valid(cookie)) 506 + if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) 549 507 return __fscache_read_or_alloc_page(cookie, page, end_io_func, 550 508 context, gfp); 551 509 else ··· 596 554 void *context, 597 555 gfp_t gfp) 598 556 { 599 - if (fscache_cookie_valid(cookie)) 557 + if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) 600 558 return __fscache_read_or_alloc_pages(cookie, mapping, pages, 601 559 nr_pages, end_io_func, 602 560 context, gfp); ··· 627 585 struct page *page, 628 586 gfp_t gfp) 629 587 { 630 - if (fscache_cookie_valid(cookie)) 588 + if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) 631 589 return __fscache_alloc_page(cookie, page, gfp); 632 590 else 633 591 return -ENOBUFS; ··· 676 634 struct page *page, 677 635 gfp_t gfp) 678 636 { 679 - if (fscache_cookie_valid(cookie)) 637 + if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) 680 638 return __fscache_write_page(cookie, page, gfp); 681 639 else 682 640 return -ENOBUFS; ··· 784 742 { 785 743 if (fscache_cookie_valid(cookie)) 786 744 __fscache_uncache_all_inode_pages(cookie, inode); 745 + } 746 + 747 + /** 748 + * fscache_disable_cookie - Disable a cookie 749 + * @cookie: The cookie representing the cache object 750 + * @invalidate: Invalidate the backing object 751 + * 752 + * Disable a cookie from accepting further alloc, read, write, invalidate, 753 + * update or acquire operations. Outstanding operations can still be waited 754 + * upon and pages can still be uncached and the cookie relinquished. 755 + * 756 + * This will not return until all outstanding operations have completed. 757 + * 758 + * If @invalidate is set, then the backing object will be invalidated and 759 + * detached, otherwise it will just be detached. 760 + */ 761 + static inline 762 + void fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) 763 + { 764 + if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) 765 + __fscache_disable_cookie(cookie, invalidate); 766 + } 767 + 768 + /** 769 + * fscache_enable_cookie - Reenable a cookie 770 + * @cookie: The cookie representing the cache object 771 + * @can_enable: A function to permit enablement once lock is held 772 + * @data: Data for can_enable() 773 + * 774 + * Reenable a previously disabled cookie, allowing it to accept further alloc, 775 + * read, write, invalidate, update or acquire operations. An attempt will be 776 + * made to immediately reattach the cookie to a backing object. 777 + * 778 + * The can_enable() function is called (if not NULL) once the enablement lock 779 + * is held to rule on whether enablement is still permitted to go ahead. 780 + */ 781 + static inline 782 + void fscache_enable_cookie(struct fscache_cookie *cookie, 783 + bool (*can_enable)(void *data), 784 + void *data) 785 + { 786 + if (fscache_cookie_valid(cookie) && !fscache_cookie_enabled(cookie)) 787 + __fscache_enable_cookie(cookie, can_enable, data); 787 788 } 788 789 789 790 #endif /* _LINUX_FSCACHE_H */