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