diff options
-rw-r--r-- | Documentation/filesystems/caching/backend-api.txt | 12 | ||||
-rw-r--r-- | Documentation/filesystems/caching/netfs-api.txt | 46 | ||||
-rw-r--r-- | Documentation/filesystems/caching/object.txt | 23 | ||||
-rw-r--r-- | fs/fscache/cookie.c | 60 | ||||
-rw-r--r-- | fs/fscache/internal.h | 10 | ||||
-rw-r--r-- | fs/fscache/object.c | 72 | ||||
-rw-r--r-- | fs/fscache/operation.c | 32 | ||||
-rw-r--r-- | fs/fscache/page.c | 51 | ||||
-rw-r--r-- | fs/fscache/stats.c | 11 | ||||
-rw-r--r-- | include/linux/fscache-cache.h | 8 | ||||
-rw-r--r-- | include/linux/fscache.h | 38 |
11 files changed, 345 insertions, 18 deletions
diff --git a/Documentation/filesystems/caching/backend-api.txt b/Documentation/filesystems/caching/backend-api.txt index f4769b9399df..d78bab9622c6 100644 --- a/Documentation/filesystems/caching/backend-api.txt +++ b/Documentation/filesystems/caching/backend-api.txt | |||
@@ -308,6 +308,18 @@ performed on the denizens of the cache. These are held in a structure of type: | |||
308 | obtained by calling object->cookie->def->get_aux()/get_attr(). | 308 | obtained by calling object->cookie->def->get_aux()/get_attr(). |
309 | 309 | ||
310 | 310 | ||
311 | (*) Invalidate data object [mandatory]: | ||
312 | |||
313 | int (*invalidate_object)(struct fscache_operation *op) | ||
314 | |||
315 | This is called to invalidate a data object (as pointed to by op->object). | ||
316 | All the data stored for this object should be discarded and an | ||
317 | attr_changed operation should be performed. The caller will follow up | ||
318 | with an object update operation. | ||
319 | |||
320 | fscache_op_complete() must be called on op before returning. | ||
321 | |||
322 | |||
311 | (*) Discard object [mandatory]: | 323 | (*) Discard object [mandatory]: |
312 | 324 | ||
313 | void (*drop_object)(struct fscache_object *object) | 325 | void (*drop_object)(struct fscache_object *object) |
diff --git a/Documentation/filesystems/caching/netfs-api.txt b/Documentation/filesystems/caching/netfs-api.txt index 7cc6bf2871eb..97e6c0ecc5ef 100644 --- a/Documentation/filesystems/caching/netfs-api.txt +++ b/Documentation/filesystems/caching/netfs-api.txt | |||
@@ -35,8 +35,9 @@ This document contains the following sections: | |||
35 | (12) Index and data file update | 35 | (12) Index and data file update |
36 | (13) Miscellaneous cookie operations | 36 | (13) Miscellaneous cookie operations |
37 | (14) Cookie unregistration | 37 | (14) Cookie unregistration |
38 | (15) Index and data file invalidation | 38 | (15) Index invalidation |
39 | (16) FS-Cache specific page flags. | 39 | (16) Data file invalidation |
40 | (17) FS-Cache specific page flags. | ||
40 | 41 | ||
41 | 42 | ||
42 | ============================= | 43 | ============================= |
@@ -767,13 +768,42 @@ the cookies for "child" indices, objects and pages have been relinquished | |||
767 | first. | 768 | first. |
768 | 769 | ||
769 | 770 | ||
770 | ================================ | 771 | ================== |
771 | INDEX AND DATA FILE INVALIDATION | 772 | INDEX INVALIDATION |
772 | ================================ | 773 | ================== |
774 | |||
775 | There is no direct way to invalidate an index subtree. To do this, the caller | ||
776 | should relinquish and retire the cookie they have, and then acquire a new one. | ||
777 | |||
778 | |||
779 | ====================== | ||
780 | DATA FILE INVALIDATION | ||
781 | ====================== | ||
782 | |||
783 | Sometimes it will be necessary to invalidate an object that contains data. | ||
784 | Typically this will be necessary when the server tells the netfs of a foreign | ||
785 | change - at which point the netfs has to throw away all the state it had for an | ||
786 | inode and reload from the server. | ||
787 | |||
788 | To indicate that a cache object should be invalidated, the following function | ||
789 | can be called: | ||
790 | |||
791 | void fscache_invalidate(struct fscache_cookie *cookie); | ||
792 | |||
793 | This can be called with spinlocks held as it defers the work to a thread pool. | ||
794 | All extant storage, retrieval and attribute change ops at this point are | ||
795 | cancelled and discarded. Some future operations will be rejected until the | ||
796 | cache has had a chance to insert a barrier in the operations queue. After | ||
797 | that, operations will be queued again behind the invalidation operation. | ||
798 | |||
799 | The invalidation operation will perform an attribute change operation and an | ||
800 | auxiliary data update operation as it is very likely these will have changed. | ||
801 | |||
802 | Using the following function, the netfs can wait for the invalidation operation | ||
803 | to have reached a point at which it can start submitting ordinary operations | ||
804 | once again: | ||
773 | 805 | ||
774 | There is no direct way to invalidate an index subtree or a data file. To do | 806 | void fscache_wait_on_invalidate(struct fscache_cookie *cookie); |
775 | this, the caller should relinquish and retire the cookie they have, and then | ||
776 | acquire a new one. | ||
777 | 807 | ||
778 | 808 | ||
779 | =========================== | 809 | =========================== |
diff --git a/Documentation/filesystems/caching/object.txt b/Documentation/filesystems/caching/object.txt index 58313348da87..100ff41127e4 100644 --- a/Documentation/filesystems/caching/object.txt +++ b/Documentation/filesystems/caching/object.txt | |||
@@ -216,7 +216,14 @@ servicing netfs requests: | |||
216 | The normal running state. In this state, requests the netfs makes will be | 216 | The normal running state. In this state, requests the netfs makes will be |
217 | passed on to the cache. | 217 | passed on to the cache. |
218 | 218 | ||
219 | (6) State FSCACHE_OBJECT_UPDATING. | 219 | (6) State FSCACHE_OBJECT_INVALIDATING. |
220 | |||
221 | The object is undergoing invalidation. When the state comes here, it | ||
222 | discards all pending read, write and attribute change operations as it is | ||
223 | going to clear out the cache entirely and reinitialise it. It will then | ||
224 | continue to the FSCACHE_OBJECT_UPDATING state. | ||
225 | |||
226 | (7) State FSCACHE_OBJECT_UPDATING. | ||
220 | 227 | ||
221 | The state machine comes here to update the object in the cache from the | 228 | The state machine comes here to update the object in the cache from the |
222 | netfs's records. This involves updating the auxiliary data that is used | 229 | netfs's records. This involves updating the auxiliary data that is used |
@@ -225,13 +232,13 @@ servicing netfs requests: | |||
225 | And there are terminal states in which an object cleans itself up, deallocates | 232 | And there are terminal states in which an object cleans itself up, deallocates |
226 | memory and potentially deletes stuff from disk: | 233 | memory and potentially deletes stuff from disk: |
227 | 234 | ||
228 | (7) State FSCACHE_OBJECT_LC_DYING. | 235 | (8) State FSCACHE_OBJECT_LC_DYING. |
229 | 236 | ||
230 | The object comes here if it is dying because of a lookup or creation | 237 | The object comes here if it is dying because of a lookup or creation |
231 | error. This would be due to a disk error or system error of some sort. | 238 | error. This would be due to a disk error or system error of some sort. |
232 | Temporary data is cleaned up, and the parent is released. | 239 | Temporary data is cleaned up, and the parent is released. |
233 | 240 | ||
234 | (8) State FSCACHE_OBJECT_DYING. | 241 | (9) State FSCACHE_OBJECT_DYING. |
235 | 242 | ||
236 | The object comes here if it is dying due to an error, because its parent | 243 | The object comes here if it is dying due to an error, because its parent |
237 | cookie has been relinquished by the netfs or because the cache is being | 244 | cookie has been relinquished by the netfs or because the cache is being |
@@ -241,27 +248,27 @@ memory and potentially deletes stuff from disk: | |||
241 | can destroy themselves. This object waits for all its children to go away | 248 | can destroy themselves. This object waits for all its children to go away |
242 | before advancing to the next state. | 249 | before advancing to the next state. |
243 | 250 | ||
244 | (9) State FSCACHE_OBJECT_ABORT_INIT. | 251 | (10) State FSCACHE_OBJECT_ABORT_INIT. |
245 | 252 | ||
246 | The object comes to this state if it was waiting on its parent in | 253 | The object comes to this state if it was waiting on its parent in |
247 | FSCACHE_OBJECT_INIT, but its parent died. The object will destroy itself | 254 | FSCACHE_OBJECT_INIT, but its parent died. The object will destroy itself |
248 | so that the parent may proceed from the FSCACHE_OBJECT_DYING state. | 255 | so that the parent may proceed from the FSCACHE_OBJECT_DYING state. |
249 | 256 | ||
250 | (10) State FSCACHE_OBJECT_RELEASING. | 257 | (11) State FSCACHE_OBJECT_RELEASING. |
251 | (11) State FSCACHE_OBJECT_RECYCLING. | 258 | (12) State FSCACHE_OBJECT_RECYCLING. |
252 | 259 | ||
253 | The object comes to one of these two states when dying once it is rid of | 260 | The object comes to one of these two states when dying once it is rid of |
254 | all its children, if it is dying because the netfs relinquished its | 261 | all its children, if it is dying because the netfs relinquished its |
255 | cookie. In the first state, the cached data is expected to persist, and | 262 | cookie. In the first state, the cached data is expected to persist, and |
256 | in the second it will be deleted. | 263 | in the second it will be deleted. |
257 | 264 | ||
258 | (12) State FSCACHE_OBJECT_WITHDRAWING. | 265 | (13) State FSCACHE_OBJECT_WITHDRAWING. |
259 | 266 | ||
260 | The object transits to this state if the cache decides it wants to | 267 | The object transits to this state if the cache decides it wants to |
261 | withdraw the object from service, perhaps to make space, but also due to | 268 | withdraw the object from service, perhaps to make space, but also due to |
262 | error or just because the whole cache is being withdrawn. | 269 | error or just because the whole cache is being withdrawn. |
263 | 270 | ||
264 | (13) State FSCACHE_OBJECT_DEAD. | 271 | (14) State FSCACHE_OBJECT_DEAD. |
265 | 272 | ||
266 | The object transits to this state when the in-memory object record is | 273 | The object transits to this state when the in-memory object record is |
267 | ready to be deleted. The object processor shouldn't ever see an object in | 274 | ready to be deleted. The object processor shouldn't ever see an object in |
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 66be9eccede0..8dcb114758e3 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c | |||
@@ -370,6 +370,66 @@ cant_attach_object: | |||
370 | } | 370 | } |
371 | 371 | ||
372 | /* | 372 | /* |
373 | * Invalidate an object. Callable with spinlocks held. | ||
374 | */ | ||
375 | void __fscache_invalidate(struct fscache_cookie *cookie) | ||
376 | { | ||
377 | struct fscache_object *object; | ||
378 | |||
379 | _enter("{%s}", cookie->def->name); | ||
380 | |||
381 | fscache_stat(&fscache_n_invalidates); | ||
382 | |||
383 | /* Only permit invalidation of data files. Invalidating an index will | ||
384 | * require the caller to release all its attachments to the tree rooted | ||
385 | * there, and if it's doing that, it may as well just retire the | ||
386 | * cookie. | ||
387 | */ | ||
388 | ASSERTCMP(cookie->def->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE); | ||
389 | |||
390 | /* We will be updating the cookie too. */ | ||
391 | BUG_ON(!cookie->def->get_aux); | ||
392 | |||
393 | /* If there's an object, we tell the object state machine to handle the | ||
394 | * invalidation on our behalf, otherwise there's nothing to do. | ||
395 | */ | ||
396 | if (!hlist_empty(&cookie->backing_objects)) { | ||
397 | spin_lock(&cookie->lock); | ||
398 | |||
399 | if (!hlist_empty(&cookie->backing_objects) && | ||
400 | !test_and_set_bit(FSCACHE_COOKIE_INVALIDATING, | ||
401 | &cookie->flags)) { | ||
402 | object = hlist_entry(cookie->backing_objects.first, | ||
403 | struct fscache_object, | ||
404 | cookie_link); | ||
405 | if (object->state < FSCACHE_OBJECT_DYING) | ||
406 | fscache_raise_event( | ||
407 | object, FSCACHE_OBJECT_EV_INVALIDATE); | ||
408 | } | ||
409 | |||
410 | spin_unlock(&cookie->lock); | ||
411 | } | ||
412 | |||
413 | _leave(""); | ||
414 | } | ||
415 | EXPORT_SYMBOL(__fscache_invalidate); | ||
416 | |||
417 | /* | ||
418 | * Wait for object invalidation to complete. | ||
419 | */ | ||
420 | void __fscache_wait_on_invalidate(struct fscache_cookie *cookie) | ||
421 | { | ||
422 | _enter("%p", cookie); | ||
423 | |||
424 | wait_on_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING, | ||
425 | fscache_wait_bit_interruptible, | ||
426 | TASK_UNINTERRUPTIBLE); | ||
427 | |||
428 | _leave(""); | ||
429 | } | ||
430 | EXPORT_SYMBOL(__fscache_wait_on_invalidate); | ||
431 | |||
432 | /* | ||
373 | * update the index entries backing a cookie | 433 | * update the index entries backing a cookie |
374 | */ | 434 | */ |
375 | void __fscache_update_cookie(struct fscache_cookie *cookie) | 435 | void __fscache_update_cookie(struct fscache_cookie *cookie) |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index f6aad48d38a8..c81179303930 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -122,11 +122,17 @@ extern int fscache_submit_exclusive_op(struct fscache_object *, | |||
122 | extern int fscache_submit_op(struct fscache_object *, | 122 | extern int fscache_submit_op(struct fscache_object *, |
123 | struct fscache_operation *); | 123 | struct fscache_operation *); |
124 | extern int fscache_cancel_op(struct fscache_operation *); | 124 | extern int fscache_cancel_op(struct fscache_operation *); |
125 | extern void fscache_cancel_all_ops(struct fscache_object *); | ||
125 | extern void fscache_abort_object(struct fscache_object *); | 126 | extern void fscache_abort_object(struct fscache_object *); |
126 | extern void fscache_start_operations(struct fscache_object *); | 127 | extern void fscache_start_operations(struct fscache_object *); |
127 | extern void fscache_operation_gc(struct work_struct *); | 128 | extern void fscache_operation_gc(struct work_struct *); |
128 | 129 | ||
129 | /* | 130 | /* |
131 | * page.c | ||
132 | */ | ||
133 | extern void fscache_invalidate_writes(struct fscache_cookie *); | ||
134 | |||
135 | /* | ||
130 | * proc.c | 136 | * proc.c |
131 | */ | 137 | */ |
132 | #ifdef CONFIG_PROC_FS | 138 | #ifdef CONFIG_PROC_FS |
@@ -205,6 +211,9 @@ extern atomic_t fscache_n_acquires_ok; | |||
205 | extern atomic_t fscache_n_acquires_nobufs; | 211 | extern atomic_t fscache_n_acquires_nobufs; |
206 | extern atomic_t fscache_n_acquires_oom; | 212 | extern atomic_t fscache_n_acquires_oom; |
207 | 213 | ||
214 | extern atomic_t fscache_n_invalidates; | ||
215 | extern atomic_t fscache_n_invalidates_run; | ||
216 | |||
208 | extern atomic_t fscache_n_updates; | 217 | extern atomic_t fscache_n_updates; |
209 | extern atomic_t fscache_n_updates_null; | 218 | extern atomic_t fscache_n_updates_null; |
210 | extern atomic_t fscache_n_updates_run; | 219 | extern atomic_t fscache_n_updates_run; |
@@ -237,6 +246,7 @@ extern atomic_t fscache_n_cop_alloc_object; | |||
237 | extern atomic_t fscache_n_cop_lookup_object; | 246 | extern atomic_t fscache_n_cop_lookup_object; |
238 | extern atomic_t fscache_n_cop_lookup_complete; | 247 | extern atomic_t fscache_n_cop_lookup_complete; |
239 | extern atomic_t fscache_n_cop_grab_object; | 248 | extern atomic_t fscache_n_cop_grab_object; |
249 | extern atomic_t fscache_n_cop_invalidate_object; | ||
240 | extern atomic_t fscache_n_cop_update_object; | 250 | extern atomic_t fscache_n_cop_update_object; |
241 | extern atomic_t fscache_n_cop_drop_object; | 251 | extern atomic_t fscache_n_cop_drop_object; |
242 | extern atomic_t fscache_n_cop_put_object; | 252 | extern atomic_t fscache_n_cop_put_object; |
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 773bc798a416..80b549141ea6 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | #define FSCACHE_DEBUG_LEVEL COOKIE | 15 | #define FSCACHE_DEBUG_LEVEL COOKIE |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/slab.h> | ||
17 | #include "internal.h" | 18 | #include "internal.h" |
18 | 19 | ||
19 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { | 20 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { |
@@ -22,6 +23,7 @@ const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { | |||
22 | [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", | 23 | [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", |
23 | [FSCACHE_OBJECT_AVAILABLE] = "OBJECT_AVAILABLE", | 24 | [FSCACHE_OBJECT_AVAILABLE] = "OBJECT_AVAILABLE", |
24 | [FSCACHE_OBJECT_ACTIVE] = "OBJECT_ACTIVE", | 25 | [FSCACHE_OBJECT_ACTIVE] = "OBJECT_ACTIVE", |
26 | [FSCACHE_OBJECT_INVALIDATING] = "OBJECT_INVALIDATING", | ||
25 | [FSCACHE_OBJECT_UPDATING] = "OBJECT_UPDATING", | 27 | [FSCACHE_OBJECT_UPDATING] = "OBJECT_UPDATING", |
26 | [FSCACHE_OBJECT_DYING] = "OBJECT_DYING", | 28 | [FSCACHE_OBJECT_DYING] = "OBJECT_DYING", |
27 | [FSCACHE_OBJECT_LC_DYING] = "OBJECT_LC_DYING", | 29 | [FSCACHE_OBJECT_LC_DYING] = "OBJECT_LC_DYING", |
@@ -39,6 +41,7 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { | |||
39 | [FSCACHE_OBJECT_CREATING] = "CRTN", | 41 | [FSCACHE_OBJECT_CREATING] = "CRTN", |
40 | [FSCACHE_OBJECT_AVAILABLE] = "AVBL", | 42 | [FSCACHE_OBJECT_AVAILABLE] = "AVBL", |
41 | [FSCACHE_OBJECT_ACTIVE] = "ACTV", | 43 | [FSCACHE_OBJECT_ACTIVE] = "ACTV", |
44 | [FSCACHE_OBJECT_INVALIDATING] = "INVL", | ||
42 | [FSCACHE_OBJECT_UPDATING] = "UPDT", | 45 | [FSCACHE_OBJECT_UPDATING] = "UPDT", |
43 | [FSCACHE_OBJECT_DYING] = "DYNG", | 46 | [FSCACHE_OBJECT_DYING] = "DYNG", |
44 | [FSCACHE_OBJECT_LC_DYING] = "LCDY", | 47 | [FSCACHE_OBJECT_LC_DYING] = "LCDY", |
@@ -54,6 +57,7 @@ static void fscache_put_object(struct fscache_object *); | |||
54 | static void fscache_initialise_object(struct fscache_object *); | 57 | static void fscache_initialise_object(struct fscache_object *); |
55 | static void fscache_lookup_object(struct fscache_object *); | 58 | static void fscache_lookup_object(struct fscache_object *); |
56 | static void fscache_object_available(struct fscache_object *); | 59 | static void fscache_object_available(struct fscache_object *); |
60 | static void fscache_invalidate_object(struct fscache_object *); | ||
57 | static void fscache_release_object(struct fscache_object *); | 61 | static void fscache_release_object(struct fscache_object *); |
58 | static void fscache_withdraw_object(struct fscache_object *); | 62 | static void fscache_withdraw_object(struct fscache_object *); |
59 | static void fscache_enqueue_dependents(struct fscache_object *); | 63 | static void fscache_enqueue_dependents(struct fscache_object *); |
@@ -79,6 +83,15 @@ static inline void fscache_done_parent_op(struct fscache_object *object) | |||
79 | } | 83 | } |
80 | 84 | ||
81 | /* | 85 | /* |
86 | * Notify netfs of invalidation completion. | ||
87 | */ | ||
88 | static inline void fscache_invalidation_complete(struct fscache_cookie *cookie) | ||
89 | { | ||
90 | if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) | ||
91 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); | ||
92 | } | ||
93 | |||
94 | /* | ||
82 | * process events that have been sent to an object's state machine | 95 | * process events that have been sent to an object's state machine |
83 | * - initiates parent lookup | 96 | * - initiates parent lookup |
84 | * - does object lookup | 97 | * - does object lookup |
@@ -125,6 +138,16 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
125 | case FSCACHE_OBJECT_ACTIVE: | 138 | case FSCACHE_OBJECT_ACTIVE: |
126 | goto active_transit; | 139 | goto active_transit; |
127 | 140 | ||
141 | /* Invalidate an object on disk */ | ||
142 | case FSCACHE_OBJECT_INVALIDATING: | ||
143 | clear_bit(FSCACHE_OBJECT_EV_INVALIDATE, &object->events); | ||
144 | fscache_stat(&fscache_n_invalidates_run); | ||
145 | fscache_stat(&fscache_n_cop_invalidate_object); | ||
146 | fscache_invalidate_object(object); | ||
147 | fscache_stat_d(&fscache_n_cop_invalidate_object); | ||
148 | fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); | ||
149 | goto active_transit; | ||
150 | |||
128 | /* update the object metadata on disk */ | 151 | /* update the object metadata on disk */ |
129 | case FSCACHE_OBJECT_UPDATING: | 152 | case FSCACHE_OBJECT_UPDATING: |
130 | clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); | 153 | clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); |
@@ -275,6 +298,9 @@ active_transit: | |||
275 | case FSCACHE_OBJECT_EV_ERROR: | 298 | case FSCACHE_OBJECT_EV_ERROR: |
276 | new_state = FSCACHE_OBJECT_DYING; | 299 | new_state = FSCACHE_OBJECT_DYING; |
277 | goto change_state; | 300 | goto change_state; |
301 | case FSCACHE_OBJECT_EV_INVALIDATE: | ||
302 | new_state = FSCACHE_OBJECT_INVALIDATING; | ||
303 | goto change_state; | ||
278 | case FSCACHE_OBJECT_EV_UPDATE: | 304 | case FSCACHE_OBJECT_EV_UPDATE: |
279 | new_state = FSCACHE_OBJECT_UPDATING; | 305 | new_state = FSCACHE_OBJECT_UPDATING; |
280 | goto change_state; | 306 | goto change_state; |
@@ -679,6 +705,7 @@ static void fscache_withdraw_object(struct fscache_object *object) | |||
679 | if (object->cookie == cookie) { | 705 | if (object->cookie == cookie) { |
680 | hlist_del_init(&object->cookie_link); | 706 | hlist_del_init(&object->cookie_link); |
681 | object->cookie = NULL; | 707 | object->cookie = NULL; |
708 | fscache_invalidation_complete(cookie); | ||
682 | detached = true; | 709 | detached = true; |
683 | } | 710 | } |
684 | spin_unlock(&cookie->lock); | 711 | spin_unlock(&cookie->lock); |
@@ -888,3 +915,48 @@ enum fscache_checkaux fscache_check_aux(struct fscache_object *object, | |||
888 | return result; | 915 | return result; |
889 | } | 916 | } |
890 | EXPORT_SYMBOL(fscache_check_aux); | 917 | EXPORT_SYMBOL(fscache_check_aux); |
918 | |||
919 | /* | ||
920 | * Asynchronously invalidate an object. | ||
921 | */ | ||
922 | static void fscache_invalidate_object(struct fscache_object *object) | ||
923 | { | ||
924 | struct fscache_operation *op; | ||
925 | struct fscache_cookie *cookie = object->cookie; | ||
926 | |||
927 | _enter("{OBJ%x}", object->debug_id); | ||
928 | |||
929 | /* Reject any new read/write ops and abort any that are pending. */ | ||
930 | fscache_invalidate_writes(cookie); | ||
931 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | ||
932 | fscache_cancel_all_ops(object); | ||
933 | |||
934 | /* Now we have to wait for in-progress reads and writes */ | ||
935 | op = kzalloc(sizeof(*op), GFP_KERNEL); | ||
936 | if (!op) { | ||
937 | fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR); | ||
938 | _leave(" [ENOMEM]"); | ||
939 | return; | ||
940 | } | ||
941 | |||
942 | fscache_operation_init(op, object->cache->ops->invalidate_object, NULL); | ||
943 | op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE); | ||
944 | |||
945 | spin_lock(&cookie->lock); | ||
946 | if (fscache_submit_exclusive_op(object, op) < 0) | ||
947 | BUG(); | ||
948 | spin_unlock(&cookie->lock); | ||
949 | fscache_put_operation(op); | ||
950 | |||
951 | /* Once we've completed the invalidation, we know there will be no data | ||
952 | * stored in the cache and thus we can reinstate the data-check-skip | ||
953 | * optimisation. | ||
954 | */ | ||
955 | set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); | ||
956 | |||
957 | /* We can allow read and write requests to come in once again. They'll | ||
958 | * queue up behind our exclusive invalidation operation. | ||
959 | */ | ||
960 | fscache_invalidation_complete(cookie); | ||
961 | _leave(""); | ||
962 | } | ||
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 748f9553c2cb..c58dbe613266 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
@@ -324,6 +324,38 @@ int fscache_cancel_op(struct fscache_operation *op) | |||
324 | } | 324 | } |
325 | 325 | ||
326 | /* | 326 | /* |
327 | * Cancel all pending operations on an object | ||
328 | */ | ||
329 | void fscache_cancel_all_ops(struct fscache_object *object) | ||
330 | { | ||
331 | struct fscache_operation *op; | ||
332 | |||
333 | _enter("OBJ%x", object->debug_id); | ||
334 | |||
335 | spin_lock(&object->lock); | ||
336 | |||
337 | while (!list_empty(&object->pending_ops)) { | ||
338 | op = list_entry(object->pending_ops.next, | ||
339 | struct fscache_operation, pend_link); | ||
340 | fscache_stat(&fscache_n_op_cancelled); | ||
341 | list_del_init(&op->pend_link); | ||
342 | |||
343 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING); | ||
344 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
345 | |||
346 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
347 | object->n_exclusive--; | ||
348 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
349 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
350 | fscache_put_operation(op); | ||
351 | cond_resched_lock(&object->lock); | ||
352 | } | ||
353 | |||
354 | spin_unlock(&object->lock); | ||
355 | _leave(""); | ||
356 | } | ||
357 | |||
358 | /* | ||
327 | * Record the completion of an in-progress operation. | 359 | * Record the completion of an in-progress operation. |
328 | */ | 360 | */ |
329 | void fscache_op_complete(struct fscache_operation *op) | 361 | void fscache_op_complete(struct fscache_operation *op) |
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index b38b13d2a555..7bf9d2557052 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -361,6 +361,11 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
361 | if (hlist_empty(&cookie->backing_objects)) | 361 | if (hlist_empty(&cookie->backing_objects)) |
362 | goto nobufs; | 362 | goto nobufs; |
363 | 363 | ||
364 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { | ||
365 | _leave(" = -ENOBUFS [invalidating]"); | ||
366 | return -ENOBUFS; | ||
367 | } | ||
368 | |||
364 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); | 369 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); |
365 | ASSERTCMP(page, !=, NULL); | 370 | ASSERTCMP(page, !=, NULL); |
366 | 371 | ||
@@ -483,6 +488,11 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
483 | if (hlist_empty(&cookie->backing_objects)) | 488 | if (hlist_empty(&cookie->backing_objects)) |
484 | goto nobufs; | 489 | goto nobufs; |
485 | 490 | ||
491 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { | ||
492 | _leave(" = -ENOBUFS [invalidating]"); | ||
493 | return -ENOBUFS; | ||
494 | } | ||
495 | |||
486 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); | 496 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); |
487 | ASSERTCMP(*nr_pages, >, 0); | 497 | ASSERTCMP(*nr_pages, >, 0); |
488 | ASSERT(!list_empty(pages)); | 498 | ASSERT(!list_empty(pages)); |
@@ -591,6 +601,11 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
591 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); | 601 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); |
592 | ASSERTCMP(page, !=, NULL); | 602 | ASSERTCMP(page, !=, NULL); |
593 | 603 | ||
604 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { | ||
605 | _leave(" = -ENOBUFS [invalidating]"); | ||
606 | return -ENOBUFS; | ||
607 | } | ||
608 | |||
594 | if (fscache_wait_for_deferred_lookup(cookie) < 0) | 609 | if (fscache_wait_for_deferred_lookup(cookie) < 0) |
595 | return -ERESTARTSYS; | 610 | return -ERESTARTSYS; |
596 | 611 | ||
@@ -731,6 +746,37 @@ superseded: | |||
731 | } | 746 | } |
732 | 747 | ||
733 | /* | 748 | /* |
749 | * Clear the pages pending writing for invalidation | ||
750 | */ | ||
751 | void fscache_invalidate_writes(struct fscache_cookie *cookie) | ||
752 | { | ||
753 | struct page *page; | ||
754 | void *results[16]; | ||
755 | int n, i; | ||
756 | |||
757 | _enter(""); | ||
758 | |||
759 | while (spin_lock(&cookie->stores_lock), | ||
760 | n = radix_tree_gang_lookup_tag(&cookie->stores, results, 0, | ||
761 | ARRAY_SIZE(results), | ||
762 | FSCACHE_COOKIE_PENDING_TAG), | ||
763 | n > 0) { | ||
764 | for (i = n - 1; i >= 0; i--) { | ||
765 | page = results[i]; | ||
766 | radix_tree_delete(&cookie->stores, page->index); | ||
767 | } | ||
768 | |||
769 | spin_unlock(&cookie->stores_lock); | ||
770 | |||
771 | for (i = n - 1; i >= 0; i--) | ||
772 | page_cache_release(results[i]); | ||
773 | } | ||
774 | |||
775 | spin_unlock(&cookie->stores_lock); | ||
776 | _leave(""); | ||
777 | } | ||
778 | |||
779 | /* | ||
734 | * request a page be stored in the cache | 780 | * request a page be stored in the cache |
735 | * - returns: | 781 | * - returns: |
736 | * -ENOMEM - out of memory, nothing done | 782 | * -ENOMEM - out of memory, nothing done |
@@ -776,6 +822,11 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
776 | 822 | ||
777 | fscache_stat(&fscache_n_stores); | 823 | fscache_stat(&fscache_n_stores); |
778 | 824 | ||
825 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { | ||
826 | _leave(" = -ENOBUFS [invalidating]"); | ||
827 | return -ENOBUFS; | ||
828 | } | ||
829 | |||
779 | op = kzalloc(sizeof(*op), GFP_NOIO | __GFP_NOMEMALLOC | __GFP_NORETRY); | 830 | op = kzalloc(sizeof(*op), GFP_NOIO | __GFP_NOMEMALLOC | __GFP_NORETRY); |
780 | if (!op) | 831 | if (!op) |
781 | goto nomem; | 832 | goto nomem; |
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index 4765190d537f..51cdaee14109 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c | |||
@@ -80,6 +80,9 @@ atomic_t fscache_n_acquires_ok; | |||
80 | atomic_t fscache_n_acquires_nobufs; | 80 | atomic_t fscache_n_acquires_nobufs; |
81 | atomic_t fscache_n_acquires_oom; | 81 | atomic_t fscache_n_acquires_oom; |
82 | 82 | ||
83 | atomic_t fscache_n_invalidates; | ||
84 | atomic_t fscache_n_invalidates_run; | ||
85 | |||
83 | atomic_t fscache_n_updates; | 86 | atomic_t fscache_n_updates; |
84 | atomic_t fscache_n_updates_null; | 87 | atomic_t fscache_n_updates_null; |
85 | atomic_t fscache_n_updates_run; | 88 | atomic_t fscache_n_updates_run; |
@@ -112,6 +115,7 @@ atomic_t fscache_n_cop_alloc_object; | |||
112 | atomic_t fscache_n_cop_lookup_object; | 115 | atomic_t fscache_n_cop_lookup_object; |
113 | atomic_t fscache_n_cop_lookup_complete; | 116 | atomic_t fscache_n_cop_lookup_complete; |
114 | atomic_t fscache_n_cop_grab_object; | 117 | atomic_t fscache_n_cop_grab_object; |
118 | atomic_t fscache_n_cop_invalidate_object; | ||
115 | atomic_t fscache_n_cop_update_object; | 119 | atomic_t fscache_n_cop_update_object; |
116 | atomic_t fscache_n_cop_drop_object; | 120 | atomic_t fscache_n_cop_drop_object; |
117 | atomic_t fscache_n_cop_put_object; | 121 | atomic_t fscache_n_cop_put_object; |
@@ -168,6 +172,10 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
168 | atomic_read(&fscache_n_object_created), | 172 | atomic_read(&fscache_n_object_created), |
169 | atomic_read(&fscache_n_object_lookups_timed_out)); | 173 | atomic_read(&fscache_n_object_lookups_timed_out)); |
170 | 174 | ||
175 | seq_printf(m, "Invals : n=%u run=%u\n", | ||
176 | atomic_read(&fscache_n_invalidates), | ||
177 | atomic_read(&fscache_n_invalidates_run)); | ||
178 | |||
171 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", | 179 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", |
172 | atomic_read(&fscache_n_updates), | 180 | atomic_read(&fscache_n_updates), |
173 | atomic_read(&fscache_n_updates_null), | 181 | atomic_read(&fscache_n_updates_null), |
@@ -246,7 +254,8 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
246 | atomic_read(&fscache_n_cop_lookup_object), | 254 | atomic_read(&fscache_n_cop_lookup_object), |
247 | atomic_read(&fscache_n_cop_lookup_complete), | 255 | atomic_read(&fscache_n_cop_lookup_complete), |
248 | atomic_read(&fscache_n_cop_grab_object)); | 256 | atomic_read(&fscache_n_cop_grab_object)); |
249 | seq_printf(m, "CacheOp: upo=%d dro=%d pto=%d atc=%d syn=%d\n", | 257 | seq_printf(m, "CacheOp: inv=%d upo=%d dro=%d pto=%d atc=%d syn=%d\n", |
258 | atomic_read(&fscache_n_cop_invalidate_object), | ||
250 | atomic_read(&fscache_n_cop_update_object), | 259 | atomic_read(&fscache_n_cop_update_object), |
251 | atomic_read(&fscache_n_cop_drop_object), | 260 | atomic_read(&fscache_n_cop_drop_object), |
252 | atomic_read(&fscache_n_cop_put_object), | 261 | atomic_read(&fscache_n_cop_put_object), |
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index f5facd1d333f..1e454ad7a832 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h | |||
@@ -254,6 +254,9 @@ struct fscache_cache_ops { | |||
254 | /* store the updated auxiliary data on an object */ | 254 | /* store the updated auxiliary data on an object */ |
255 | void (*update_object)(struct fscache_object *object); | 255 | void (*update_object)(struct fscache_object *object); |
256 | 256 | ||
257 | /* Invalidate an object */ | ||
258 | void (*invalidate_object)(struct fscache_operation *op); | ||
259 | |||
257 | /* discard the resources pinned by an object and effect retirement if | 260 | /* discard the resources pinned by an object and effect retirement if |
258 | * necessary */ | 261 | * necessary */ |
259 | void (*drop_object)(struct fscache_object *object); | 262 | void (*drop_object)(struct fscache_object *object); |
@@ -329,6 +332,7 @@ struct fscache_cookie { | |||
329 | #define FSCACHE_COOKIE_FILLING 4 /* T if filling object incrementally */ | 332 | #define FSCACHE_COOKIE_FILLING 4 /* T if filling object incrementally */ |
330 | #define FSCACHE_COOKIE_UNAVAILABLE 5 /* T if cookie is unavailable (error, etc) */ | 333 | #define FSCACHE_COOKIE_UNAVAILABLE 5 /* T if cookie is unavailable (error, etc) */ |
331 | #define FSCACHE_COOKIE_WAITING_ON_READS 6 /* T if cookie is waiting on reads */ | 334 | #define FSCACHE_COOKIE_WAITING_ON_READS 6 /* T if cookie is waiting on reads */ |
335 | #define FSCACHE_COOKIE_INVALIDATING 7 /* T if cookie is being invalidated */ | ||
332 | }; | 336 | }; |
333 | 337 | ||
334 | extern struct fscache_cookie fscache_fsdef_index; | 338 | extern struct fscache_cookie fscache_fsdef_index; |
@@ -345,6 +349,7 @@ struct fscache_object { | |||
345 | /* active states */ | 349 | /* active states */ |
346 | FSCACHE_OBJECT_AVAILABLE, /* cleaning up object after creation */ | 350 | FSCACHE_OBJECT_AVAILABLE, /* cleaning up object after creation */ |
347 | FSCACHE_OBJECT_ACTIVE, /* object is usable */ | 351 | FSCACHE_OBJECT_ACTIVE, /* object is usable */ |
352 | FSCACHE_OBJECT_INVALIDATING, /* object is invalidating */ | ||
348 | FSCACHE_OBJECT_UPDATING, /* object is updating */ | 353 | FSCACHE_OBJECT_UPDATING, /* object is updating */ |
349 | 354 | ||
350 | /* terminal states */ | 355 | /* terminal states */ |
@@ -378,7 +383,8 @@ struct fscache_object { | |||
378 | #define FSCACHE_OBJECT_EV_RELEASE 4 /* T if netfs requested object release */ | 383 | #define FSCACHE_OBJECT_EV_RELEASE 4 /* T if netfs requested object release */ |
379 | #define FSCACHE_OBJECT_EV_RETIRE 5 /* T if netfs requested object retirement */ | 384 | #define FSCACHE_OBJECT_EV_RETIRE 5 /* T if netfs requested object retirement */ |
380 | #define FSCACHE_OBJECT_EV_WITHDRAW 6 /* T if cache requested object withdrawal */ | 385 | #define FSCACHE_OBJECT_EV_WITHDRAW 6 /* T if cache requested object withdrawal */ |
381 | #define FSCACHE_OBJECT_EVENTS_MASK 0x7f /* mask of all events*/ | 386 | #define FSCACHE_OBJECT_EV_INVALIDATE 7 /* T if cache requested object invalidation */ |
387 | #define FSCACHE_OBJECT_EVENTS_MASK 0xff /* mask of all events*/ | ||
382 | 388 | ||
383 | unsigned long flags; | 389 | unsigned long flags; |
384 | #define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */ | 390 | #define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */ |
diff --git a/include/linux/fscache.h b/include/linux/fscache.h index f4b6353543bf..7a086235da4b 100644 --- a/include/linux/fscache.h +++ b/include/linux/fscache.h | |||
@@ -185,6 +185,8 @@ extern struct fscache_cookie *__fscache_acquire_cookie( | |||
185 | extern void __fscache_relinquish_cookie(struct fscache_cookie *, int); | 185 | extern void __fscache_relinquish_cookie(struct fscache_cookie *, int); |
186 | extern void __fscache_update_cookie(struct fscache_cookie *); | 186 | extern void __fscache_update_cookie(struct fscache_cookie *); |
187 | extern int __fscache_attr_changed(struct fscache_cookie *); | 187 | extern int __fscache_attr_changed(struct fscache_cookie *); |
188 | extern void __fscache_invalidate(struct fscache_cookie *); | ||
189 | extern void __fscache_wait_on_invalidate(struct fscache_cookie *); | ||
188 | extern int __fscache_read_or_alloc_page(struct fscache_cookie *, | 190 | extern int __fscache_read_or_alloc_page(struct fscache_cookie *, |
189 | struct page *, | 191 | struct page *, |
190 | fscache_rw_complete_t, | 192 | fscache_rw_complete_t, |
@@ -390,6 +392,42 @@ int fscache_attr_changed(struct fscache_cookie *cookie) | |||
390 | } | 392 | } |
391 | 393 | ||
392 | /** | 394 | /** |
395 | * fscache_invalidate - Notify cache that an object needs invalidation | ||
396 | * @cookie: The cookie representing the cache object | ||
397 | * | ||
398 | * Notify the cache that an object is needs to be invalidated and that it | ||
399 | * should abort any retrievals or stores it is doing on the cache. The object | ||
400 | * is then marked non-caching until such time as the invalidation is complete. | ||
401 | * | ||
402 | * This can be called with spinlocks held. | ||
403 | * | ||
404 | * See Documentation/filesystems/caching/netfs-api.txt for a complete | ||
405 | * description. | ||
406 | */ | ||
407 | static inline | ||
408 | void fscache_invalidate(struct fscache_cookie *cookie) | ||
409 | { | ||
410 | if (fscache_cookie_valid(cookie)) | ||
411 | __fscache_invalidate(cookie); | ||
412 | } | ||
413 | |||
414 | /** | ||
415 | * fscache_wait_on_invalidate - Wait for invalidation to complete | ||
416 | * @cookie: The cookie representing the cache object | ||
417 | * | ||
418 | * Wait for the invalidation of an object to complete. | ||
419 | * | ||
420 | * See Documentation/filesystems/caching/netfs-api.txt for a complete | ||
421 | * description. | ||
422 | */ | ||
423 | static inline | ||
424 | void fscache_wait_on_invalidate(struct fscache_cookie *cookie) | ||
425 | { | ||
426 | if (fscache_cookie_valid(cookie)) | ||
427 | __fscache_wait_on_invalidate(cookie); | ||
428 | } | ||
429 | |||
430 | /** | ||
393 | * fscache_reserve_space - Reserve data space for a cached object | 431 | * fscache_reserve_space - Reserve data space for a cached object |
394 | * @cookie: The cookie representing the cache object | 432 | * @cookie: The cookie representing the cache object |
395 | * @i_size: The amount of space to be reserved | 433 | * @i_size: The amount of space to be reserved |