aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2013-05-10 14:50:26 -0400
committerDavid Howells <dhowells@redhat.com>2013-06-19 09:16:47 -0400
commitcaaef6900befb45689b1d1831ce3c7e7fb5b504f (patch)
tree557fa8f425bd18261bea4950a2d821ffe8051903
parent493f7bc11457bc1f6fbf25a4b2bdf215ebaf050f (diff)
FS-Cache: Fix object state machine to have separate work and wait states
Fix object state machine to have separate work and wait states as that makes it easier to envision. There are now three kinds of state: (1) Work state. This is an execution state. No event processing is performed by a work state. The function attached to a work state returns a pointer indicating the next state to which the OSM should transition. Returning NO_TRANSIT repeats the current state, but goes back to the scheduler first. (2) Wait state. This is an event processing state. No execution is performed by a wait state. Wait states are just tables of "if event X occurs, clear it and transition to state Y". The dispatcher returns to the scheduler if none of the events in which the wait state has an interest are currently pending. (3) Out-of-band state. This is a special work state. Transitions to normal states can be overridden when an unexpected event occurs (eg. I/O error). Instead the dispatcher disables and clears the OOB event and transits to the specified work state. This then acts as an ordinary work state, though object->state points to the overridden destination. Returning NO_TRANSIT resumes the overridden transition. In addition, the states have names in their definitions, so there's no need for tables of state names. Further, the EV_REQUEUE event is no longer necessary as that is automatic for work states. Since the states are now separate structs rather than values in an enum, it's not possible to use comparisons other than (non-)equality between them, so use some object->flags to indicate what phase an object is in. The EV_RELEASE, EV_RETIRE and EV_WITHDRAW events have been squished into one (EV_KILL). An object flag now carries the information about retirement. Similarly, the RELEASING, RECYCLING and WITHDRAWING states have been merged into an KILL_OBJECT state and additional states have been added for handling waiting dependent objects (JUMPSTART_DEPS and KILL_DEPENDENTS). A state has also been added for synchronising with parent object initialisation (WAIT_FOR_PARENT) and another for initiating look up (PARENT_READY). Signed-off-by: David Howells <dhowells@redhat.com> Tested-By: Milosz Tanski <milosz@adfin.com> Acked-by: Jeff Layton <jlayton@redhat.com>
-rw-r--r--fs/cachefiles/interface.c2
-rw-r--r--fs/cachefiles/namei.c4
-rw-r--r--fs/fscache/cache.c32
-rw-r--r--fs/fscache/cookie.c9
-rw-r--r--fs/fscache/internal.h8
-rw-r--r--fs/fscache/object-list.c10
-rw-r--r--fs/fscache/object.c1018
-rw-r--r--fs/fscache/operation.c22
-rw-r--r--fs/fscache/page.c11
-rw-r--r--include/linux/fscache-cache.h66
10 files changed, 605 insertions, 577 deletions
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c
index 746ce532e130..3d763217faf3 100644
--- a/fs/cachefiles/interface.c
+++ b/fs/cachefiles/interface.c
@@ -263,7 +263,7 @@ static void cachefiles_drop_object(struct fscache_object *_object)
263#endif 263#endif
264 264
265 /* delete retired objects */ 265 /* delete retired objects */
266 if (object->fscache.state == FSCACHE_OBJECT_RECYCLING && 266 if (test_bit(FSCACHE_OBJECT_RETIRE, &object->fscache.flags) &&
267 _object != cache->cache.fsdef 267 _object != cache->cache.fsdef
268 ) { 268 ) {
269 _debug("- retire object OBJ%x", object->fscache.debug_id); 269 _debug("- retire object OBJ%x", object->fscache.debug_id);
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index 01979a3f5121..25badd1aec5c 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -38,7 +38,7 @@ void __cachefiles_printk_object(struct cachefiles_object *object,
38 printk(KERN_ERR "%sobject: OBJ%x\n", 38 printk(KERN_ERR "%sobject: OBJ%x\n",
39 prefix, object->fscache.debug_id); 39 prefix, object->fscache.debug_id);
40 printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n", 40 printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n",
41 prefix, fscache_object_states[object->fscache.state], 41 prefix, object->fscache.state->name,
42 object->fscache.flags, work_busy(&object->fscache.work), 42 object->fscache.flags, work_busy(&object->fscache.work),
43 object->fscache.events, object->fscache.event_mask); 43 object->fscache.events, object->fscache.event_mask);
44 printk(KERN_ERR "%sops=%u inp=%u exc=%u\n", 44 printk(KERN_ERR "%sops=%u inp=%u exc=%u\n",
@@ -127,7 +127,7 @@ static void cachefiles_mark_object_buried(struct cachefiles_cache *cache,
127found_dentry: 127found_dentry:
128 kdebug("preemptive burial: OBJ%x [%s] %p", 128 kdebug("preemptive burial: OBJ%x [%s] %p",
129 object->fscache.debug_id, 129 object->fscache.debug_id,
130 fscache_object_states[object->fscache.state], 130 object->fscache.state->name,
131 dentry); 131 dentry);
132 132
133 if (fscache_object_is_live(&object->fscache)) { 133 if (fscache_object_is_live(&object->fscache)) {
diff --git a/fs/fscache/cache.c b/fs/fscache/cache.c
index 129ea537f023..f7cff367db7f 100644
--- a/fs/fscache/cache.c
+++ b/fs/fscache/cache.c
@@ -224,8 +224,10 @@ int fscache_add_cache(struct fscache_cache *cache,
224 BUG_ON(!ifsdef); 224 BUG_ON(!ifsdef);
225 225
226 cache->flags = 0; 226 cache->flags = 0;
227 ifsdef->event_mask = ULONG_MAX & ~(1 << FSCACHE_OBJECT_EV_CLEARED); 227 ifsdef->event_mask =
228 ifsdef->state = FSCACHE_OBJECT_ACTIVE; 228 ((1 << NR_FSCACHE_OBJECT_EVENTS) - 1) &
229 ~(1 << FSCACHE_OBJECT_EV_CLEARED);
230 __set_bit(FSCACHE_OBJECT_IS_AVAILABLE, &ifsdef->flags);
229 231
230 if (!tagname) 232 if (!tagname)
231 tagname = cache->identifier; 233 tagname = cache->identifier;
@@ -330,25 +332,25 @@ static void fscache_withdraw_all_objects(struct fscache_cache *cache,
330{ 332{
331 struct fscache_object *object; 333 struct fscache_object *object;
332 334
333 spin_lock(&cache->object_list_lock);
334
335 while (!list_empty(&cache->object_list)) { 335 while (!list_empty(&cache->object_list)) {
336 object = list_entry(cache->object_list.next, 336 spin_lock(&cache->object_list_lock);
337 struct fscache_object, cache_link);
338 list_move_tail(&object->cache_link, dying_objects);
339 337
340 _debug("withdraw %p", object->cookie); 338 if (!list_empty(&cache->object_list)) {
339 object = list_entry(cache->object_list.next,
340 struct fscache_object, cache_link);
341 list_move_tail(&object->cache_link, dying_objects);
341 342
342 spin_lock(&object->lock); 343 _debug("withdraw %p", object->cookie);
343 spin_unlock(&cache->object_list_lock); 344
344 fscache_raise_event(object, FSCACHE_OBJECT_EV_WITHDRAW); 345 /* This must be done under object_list_lock to prevent
345 spin_unlock(&object->lock); 346 * a race with fscache_drop_object().
347 */
348 fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL);
349 }
346 350
351 spin_unlock(&cache->object_list_lock);
347 cond_resched(); 352 cond_resched();
348 spin_lock(&cache->object_list_lock);
349 } 353 }
350
351 spin_unlock(&cache->object_list_lock);
352} 354}
353 355
354/** 356/**
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c
index a5f36c921e91..eee436646989 100644
--- a/fs/fscache/cookie.c
+++ b/fs/fscache/cookie.c
@@ -205,7 +205,7 @@ static int fscache_acquire_non_index_cookie(struct fscache_cookie *cookie)
205 205
206 /* initiate the process of looking up all the objects in the chain 206 /* initiate the process of looking up all the objects in the chain
207 * (done by fscache_initialise_object()) */ 207 * (done by fscache_initialise_object()) */
208 fscache_enqueue_object(object); 208 fscache_raise_event(object, FSCACHE_OBJECT_EV_NEW_CHILD);
209 209
210 spin_unlock(&cookie->lock); 210 spin_unlock(&cookie->lock);
211 211
@@ -469,7 +469,6 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire)
469{ 469{
470 struct fscache_cache *cache; 470 struct fscache_cache *cache;
471 struct fscache_object *object; 471 struct fscache_object *object;
472 unsigned long event;
473 472
474 fscache_stat(&fscache_n_relinquishes); 473 fscache_stat(&fscache_n_relinquishes);
475 if (retire) 474 if (retire)
@@ -497,8 +496,6 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire)
497 fscache_wait_bit, TASK_UNINTERRUPTIBLE); 496 fscache_wait_bit, TASK_UNINTERRUPTIBLE);
498 } 497 }
499 498
500 event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE;
501
502try_again: 499try_again:
503 spin_lock(&cookie->lock); 500 spin_lock(&cookie->lock);
504 501
@@ -533,7 +530,9 @@ try_again:
533 530
534 cache = object->cache; 531 cache = object->cache;
535 object->cookie = NULL; 532 object->cookie = NULL;
536 fscache_raise_event(object, event); 533 if (retire)
534 set_bit(FSCACHE_OBJECT_RETIRE, &object->flags);
535 fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL);
537 spin_unlock(&object->lock); 536 spin_unlock(&object->lock);
538 537
539 if (atomic_dec_and_test(&cookie->usage)) 538 if (atomic_dec_and_test(&cookie->usage))
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h
index ee38fef4be51..3322d3c42ba8 100644
--- a/fs/fscache/internal.h
+++ b/fs/fscache/internal.h
@@ -97,10 +97,6 @@ extern int fscache_wait_bit_interruptible(void *);
97/* 97/*
98 * object.c 98 * object.c
99 */ 99 */
100extern const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5];
101
102extern void fscache_withdrawing_object(struct fscache_cache *,
103 struct fscache_object *);
104extern void fscache_enqueue_object(struct fscache_object *); 100extern void fscache_enqueue_object(struct fscache_object *);
105 101
106/* 102/*
@@ -291,6 +287,10 @@ static inline void fscache_raise_event(struct fscache_object *object,
291 unsigned event) 287 unsigned event)
292{ 288{
293 BUG_ON(event >= NR_FSCACHE_OBJECT_EVENTS); 289 BUG_ON(event >= NR_FSCACHE_OBJECT_EVENTS);
290#if 0
291 printk("*** fscache_raise_event(OBJ%d{%lx},%x)\n",
292 object->debug_id, object->event_mask, (1 << event));
293#endif
294 if (!test_and_set_bit(event, &object->events) && 294 if (!test_and_set_bit(event, &object->events) &&
295 test_bit(event, &object->event_mask)) 295 test_bit(event, &object->event_mask))
296 fscache_enqueue_object(object); 296 fscache_enqueue_object(object);
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c
index f27c89d17885..4a386b080e03 100644
--- a/fs/fscache/object-list.c
+++ b/fs/fscache/object-list.c
@@ -174,7 +174,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v)
174 174
175 if ((unsigned long) v == 1) { 175 if ((unsigned long) v == 1) {
176 seq_puts(m, "OBJECT PARENT STAT CHLDN OPS OOP IPR EX READS" 176 seq_puts(m, "OBJECT PARENT STAT CHLDN OPS OOP IPR EX READS"
177 " EM EV F S" 177 " EM EV FL S"
178 " | NETFS_COOKIE_DEF TY FL NETFS_DATA"); 178 " | NETFS_COOKIE_DEF TY FL NETFS_DATA");
179 if (config & (FSCACHE_OBJLIST_CONFIG_KEY | 179 if (config & (FSCACHE_OBJLIST_CONFIG_KEY |
180 FSCACHE_OBJLIST_CONFIG_AUX)) 180 FSCACHE_OBJLIST_CONFIG_AUX))
@@ -193,7 +193,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v)
193 193
194 if ((unsigned long) v == 2) { 194 if ((unsigned long) v == 2) {
195 seq_puts(m, "======== ======== ==== ===== === === === == =====" 195 seq_puts(m, "======== ======== ==== ===== === === === == ====="
196 " == == = =" 196 " == == == ="
197 " | ================ == == ================"); 197 " | ================ == == ================");
198 if (config & (FSCACHE_OBJLIST_CONFIG_KEY | 198 if (config & (FSCACHE_OBJLIST_CONFIG_KEY |
199 FSCACHE_OBJLIST_CONFIG_AUX)) 199 FSCACHE_OBJLIST_CONFIG_AUX))
@@ -219,7 +219,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v)
219 if (~config) { 219 if (~config) {
220 FILTER(obj->cookie, 220 FILTER(obj->cookie,
221 COOKIE, NOCOOKIE); 221 COOKIE, NOCOOKIE);
222 FILTER(obj->state != FSCACHE_OBJECT_ACTIVE || 222 FILTER(fscache_object_is_active(obj) ||
223 obj->n_ops != 0 || 223 obj->n_ops != 0 ||
224 obj->n_obj_ops != 0 || 224 obj->n_obj_ops != 0 ||
225 obj->flags || 225 obj->flags ||
@@ -235,10 +235,10 @@ static int fscache_objlist_show(struct seq_file *m, void *v)
235 } 235 }
236 236
237 seq_printf(m, 237 seq_printf(m,
238 "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1x | ", 238 "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %2lx %1x | ",
239 obj->debug_id, 239 obj->debug_id,
240 obj->parent ? obj->parent->debug_id : -1, 240 obj->parent ? obj->parent->debug_id : -1,
241 fscache_object_states_short[obj->state], 241 obj->state->short_name,
242 obj->n_children, 242 obj->n_children,
243 obj->n_ops, 243 obj->n_ops,
244 obj->n_obj_ops, 244 obj->n_obj_ops,
diff --git a/fs/fscache/object.c b/fs/fscache/object.c
index 863f6873c0f0..8f17debd7979 100644
--- a/fs/fscache/object.c
+++ b/fs/fscache/object.c
@@ -15,52 +15,133 @@
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 <linux/slab.h>
18#include <linux/prefetch.h>
18#include "internal.h" 19#include "internal.h"
19 20
20const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { 21static const struct fscache_state *fscache_abort_initialisation(struct fscache_object *, int);
21 [FSCACHE_OBJECT_INIT] = "OBJECT_INIT", 22static const struct fscache_state *fscache_kill_dependents(struct fscache_object *, int);
22 [FSCACHE_OBJECT_LOOKING_UP] = "OBJECT_LOOKING_UP", 23static const struct fscache_state *fscache_drop_object(struct fscache_object *, int);
23 [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", 24static const struct fscache_state *fscache_initialise_object(struct fscache_object *, int);
24 [FSCACHE_OBJECT_AVAILABLE] = "OBJECT_AVAILABLE", 25static const struct fscache_state *fscache_invalidate_object(struct fscache_object *, int);
25 [FSCACHE_OBJECT_ACTIVE] = "OBJECT_ACTIVE", 26static const struct fscache_state *fscache_jumpstart_dependents(struct fscache_object *, int);
26 [FSCACHE_OBJECT_INVALIDATING] = "OBJECT_INVALIDATING", 27static const struct fscache_state *fscache_kill_object(struct fscache_object *, int);
27 [FSCACHE_OBJECT_UPDATING] = "OBJECT_UPDATING", 28static const struct fscache_state *fscache_lookup_failure(struct fscache_object *, int);
28 [FSCACHE_OBJECT_DYING] = "OBJECT_DYING", 29static const struct fscache_state *fscache_look_up_object(struct fscache_object *, int);
29 [FSCACHE_OBJECT_LC_DYING] = "OBJECT_LC_DYING", 30static const struct fscache_state *fscache_object_available(struct fscache_object *, int);
30 [FSCACHE_OBJECT_ABORT_INIT] = "OBJECT_ABORT_INIT", 31static const struct fscache_state *fscache_parent_ready(struct fscache_object *, int);
31 [FSCACHE_OBJECT_RELEASING] = "OBJECT_RELEASING", 32static const struct fscache_state *fscache_update_object(struct fscache_object *, int);
32 [FSCACHE_OBJECT_RECYCLING] = "OBJECT_RECYCLING", 33static const struct fscache_state *fscache_detach_from_cookie(struct fscache_object *, int);
33 [FSCACHE_OBJECT_WITHDRAWING] = "OBJECT_WITHDRAWING", 34
34 [FSCACHE_OBJECT_DEAD] = "OBJECT_DEAD", 35#define __STATE_NAME(n) fscache_osm_##n
36#define STATE(n) (&__STATE_NAME(n))
37
38/*
39 * Define a work state. Work states are execution states. No event processing
40 * is performed by them. The function attached to a work state returns a
41 * pointer indicating the next state to which the state machine should
42 * transition. Returning NO_TRANSIT repeats the current state, but goes back
43 * to the scheduler first.
44 */
45#define WORK_STATE(n, sn, f) \
46 const struct fscache_state __STATE_NAME(n) = { \
47 .name = #n, \
48 .short_name = sn, \
49 .work = f \
50 }
51
52/*
53 * Returns from work states.
54 */
55#define transit_to(state) ({ prefetch(&STATE(state)->work); STATE(state); })
56
57#define NO_TRANSIT ((struct fscache_state *)NULL)
58
59/*
60 * Define a wait state. Wait states are event processing states. No execution
61 * is performed by them. Wait states are just tables of "if event X occurs,
62 * clear it and transition to state Y". The dispatcher returns to the
63 * scheduler if none of the events in which the wait state has an interest are
64 * currently pending.
65 */
66#define WAIT_STATE(n, sn, ...) \
67 const struct fscache_state __STATE_NAME(n) = { \
68 .name = #n, \
69 .short_name = sn, \
70 .work = NULL, \
71 .transitions = { __VA_ARGS__, { 0, NULL } } \
72 }
73
74#define TRANSIT_TO(state, emask) \
75 { .events = (emask), .transit_to = STATE(state) }
76
77/*
78 * The object state machine.
79 */
80static WORK_STATE(INIT_OBJECT, "INIT", fscache_initialise_object);
81static WORK_STATE(PARENT_READY, "PRDY", fscache_parent_ready);
82static WORK_STATE(ABORT_INIT, "ABRT", fscache_abort_initialisation);
83static WORK_STATE(LOOK_UP_OBJECT, "LOOK", fscache_look_up_object);
84static WORK_STATE(CREATE_OBJECT, "CRTO", fscache_look_up_object);
85static WORK_STATE(OBJECT_AVAILABLE, "AVBL", fscache_object_available);
86static WORK_STATE(JUMPSTART_DEPS, "JUMP", fscache_jumpstart_dependents);
87
88static WORK_STATE(INVALIDATE_OBJECT, "INVL", fscache_invalidate_object);
89static WORK_STATE(UPDATE_OBJECT, "UPDT", fscache_update_object);
90
91static WORK_STATE(LOOKUP_FAILURE, "LCFL", fscache_lookup_failure);
92static WORK_STATE(KILL_OBJECT, "KILL", fscache_kill_object);
93static WORK_STATE(KILL_DEPENDENTS, "KDEP", fscache_kill_dependents);
94static WORK_STATE(DROP_OBJECT, "DROP", fscache_drop_object);
95static WORK_STATE(DETACH_FROM_COOKIE, "DTCH", fscache_detach_from_cookie);
96static WORK_STATE(OBJECT_DEAD, "DEAD", (void*)2UL);
97
98static WAIT_STATE(WAIT_FOR_INIT, "?INI",
99 TRANSIT_TO(INIT_OBJECT, 1 << FSCACHE_OBJECT_EV_NEW_CHILD));
100
101static WAIT_STATE(WAIT_FOR_PARENT, "?PRN",
102 TRANSIT_TO(PARENT_READY, 1 << FSCACHE_OBJECT_EV_PARENT_READY));
103
104static WAIT_STATE(WAIT_FOR_CMD, "?CMD",
105 TRANSIT_TO(INVALIDATE_OBJECT, 1 << FSCACHE_OBJECT_EV_INVALIDATE),
106 TRANSIT_TO(UPDATE_OBJECT, 1 << FSCACHE_OBJECT_EV_UPDATE),
107 TRANSIT_TO(JUMPSTART_DEPS, 1 << FSCACHE_OBJECT_EV_NEW_CHILD));
108
109static WAIT_STATE(WAIT_FOR_CLEARANCE, "?CLR",
110 TRANSIT_TO(KILL_OBJECT, 1 << FSCACHE_OBJECT_EV_CLEARED));
111
112/*
113 * Out-of-band event transition tables. These are for handling unexpected
114 * events, such as an I/O error. If an OOB event occurs, the state machine
115 * clears and disables the event and forces a transition to the nominated work
116 * state (acurrently executing work states will complete first).
117 *
118 * In such a situation, object->state remembers the state the machine should
119 * have been in/gone to and returning NO_TRANSIT returns to that.
120 */
121static const struct fscache_transition fscache_osm_init_oob[] = {
122 TRANSIT_TO(ABORT_INIT,
123 (1 << FSCACHE_OBJECT_EV_ERROR) |
124 (1 << FSCACHE_OBJECT_EV_KILL)),
125 { 0, NULL }
35}; 126};
36EXPORT_SYMBOL(fscache_object_states); 127
37 128static const struct fscache_transition fscache_osm_lookup_oob[] = {
38const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { 129 TRANSIT_TO(LOOKUP_FAILURE,
39 [FSCACHE_OBJECT_INIT] = "INIT", 130 (1 << FSCACHE_OBJECT_EV_ERROR) |
40 [FSCACHE_OBJECT_LOOKING_UP] = "LOOK", 131 (1 << FSCACHE_OBJECT_EV_KILL)),
41 [FSCACHE_OBJECT_CREATING] = "CRTN", 132 { 0, NULL }
42 [FSCACHE_OBJECT_AVAILABLE] = "AVBL", 133};
43 [FSCACHE_OBJECT_ACTIVE] = "ACTV", 134
44 [FSCACHE_OBJECT_INVALIDATING] = "INVL", 135static const struct fscache_transition fscache_osm_run_oob[] = {
45 [FSCACHE_OBJECT_UPDATING] = "UPDT", 136 TRANSIT_TO(KILL_OBJECT,
46 [FSCACHE_OBJECT_DYING] = "DYNG", 137 (1 << FSCACHE_OBJECT_EV_ERROR) |
47 [FSCACHE_OBJECT_LC_DYING] = "LCDY", 138 (1 << FSCACHE_OBJECT_EV_KILL)),
48 [FSCACHE_OBJECT_ABORT_INIT] = "ABTI", 139 { 0, NULL }
49 [FSCACHE_OBJECT_RELEASING] = "RELS",
50 [FSCACHE_OBJECT_RECYCLING] = "RCYC",
51 [FSCACHE_OBJECT_WITHDRAWING] = "WTHD",
52 [FSCACHE_OBJECT_DEAD] = "DEAD",
53}; 140};
54 141
55static int fscache_get_object(struct fscache_object *); 142static int fscache_get_object(struct fscache_object *);
56static void fscache_put_object(struct fscache_object *); 143static void fscache_put_object(struct fscache_object *);
57static void fscache_initialise_object(struct fscache_object *); 144static bool fscache_enqueue_dependents(struct fscache_object *, int);
58static void fscache_lookup_object(struct fscache_object *);
59static void fscache_object_available(struct fscache_object *);
60static void fscache_invalidate_object(struct fscache_object *);
61static void fscache_release_object(struct fscache_object *);
62static void fscache_withdraw_object(struct fscache_object *);
63static void fscache_enqueue_dependents(struct fscache_object *);
64static void fscache_dequeue_object(struct fscache_object *); 145static void fscache_dequeue_object(struct fscache_object *);
65 146
66/* 147/*
@@ -83,281 +164,102 @@ static inline void fscache_done_parent_op(struct fscache_object *object)
83} 164}
84 165
85/* 166/*
86 * Notify netfs of invalidation completion. 167 * Object state machine dispatcher.
87 */ 168 */
88static inline void fscache_invalidation_complete(struct fscache_cookie *cookie) 169static void fscache_object_sm_dispatcher(struct fscache_object *object)
89{ 170{
90 if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) 171 const struct fscache_transition *t;
91 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); 172 const struct fscache_state *state, *new_state;
92} 173 unsigned long events, event_mask;
93 174 int event = -1;
94/*
95 * process events that have been sent to an object's state machine
96 * - initiates parent lookup
97 * - does object lookup
98 * - does object creation
99 * - does object recycling and retirement
100 * - does object withdrawal
101 */
102static void fscache_object_state_machine(struct fscache_object *object)
103{
104 enum fscache_object_state new_state;
105 struct fscache_cookie *cookie;
106 int event;
107 175
108 ASSERT(object != NULL); 176 ASSERT(object != NULL);
109 177
110 _enter("{OBJ%x,%s,%lx}", 178 _enter("{OBJ%x,%s,%lx}",
111 object->debug_id, fscache_object_states[object->state], 179 object->debug_id, object->state->name, object->events);
112 object->events); 180
113 181 event_mask = object->event_mask;
114 switch (object->state) { 182restart:
115 /* wait for the parent object to become ready */ 183 object->event_mask = 0; /* Mask normal event handling */
116 case FSCACHE_OBJECT_INIT: 184 state = object->state;
117 object->event_mask = 185restart_masked:
118 FSCACHE_OBJECT_EVENTS_MASK & 186 events = object->events;
119 ~(1 << FSCACHE_OBJECT_EV_CLEARED); 187
120 fscache_initialise_object(object); 188 /* Handle any out-of-band events (typically an error) */
121 goto done; 189 if (events & object->oob_event_mask) {
122 190 _debug("{OBJ%x} oob %lx",
123 /* look up the object metadata on disk */ 191 object->debug_id, events & object->oob_event_mask);
124 case FSCACHE_OBJECT_LOOKING_UP: 192 for (t = object->oob_table; t->events; t++) {
125 fscache_lookup_object(object); 193 if (events & t->events) {
126 goto lookup_transit; 194 state = t->transit_to;
127 195 ASSERT(state->work != NULL);
128 /* create the object metadata on disk */ 196 event = fls(events & t->events) - 1;
129 case FSCACHE_OBJECT_CREATING: 197 __clear_bit(event, &object->oob_event_mask);
130 fscache_lookup_object(object); 198 clear_bit(event, &object->events);
131 goto lookup_transit; 199 goto execute_work_state;
132 200 }
133 /* handle an object becoming available; start pending
134 * operations and queue dependent operations for processing */
135 case FSCACHE_OBJECT_AVAILABLE:
136 fscache_object_available(object);
137 goto active_transit;
138
139 /* normal running state */
140 case FSCACHE_OBJECT_ACTIVE:
141 goto active_transit;
142
143 /* Invalidate an object on disk */
144 case FSCACHE_OBJECT_INVALIDATING:
145 clear_bit(FSCACHE_OBJECT_EV_INVALIDATE, &object->events);
146 fscache_stat(&fscache_n_invalidates_run);
147 fscache_stat(&fscache_n_cop_invalidate_object);
148 fscache_invalidate_object(object);
149 fscache_stat_d(&fscache_n_cop_invalidate_object);
150 fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE);
151 goto active_transit;
152
153 /* update the object metadata on disk */
154 case FSCACHE_OBJECT_UPDATING:
155 clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events);
156 fscache_stat(&fscache_n_updates_run);
157 fscache_stat(&fscache_n_cop_update_object);
158 object->cache->ops->update_object(object);
159 fscache_stat_d(&fscache_n_cop_update_object);
160 goto active_transit;
161
162 /* handle an object dying during lookup or creation */
163 case FSCACHE_OBJECT_LC_DYING:
164 object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE);
165 fscache_stat(&fscache_n_cop_lookup_complete);
166 object->cache->ops->lookup_complete(object);
167 fscache_stat_d(&fscache_n_cop_lookup_complete);
168
169 spin_lock(&object->lock);
170 object->state = FSCACHE_OBJECT_DYING;
171 cookie = object->cookie;
172 if (cookie) {
173 if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP,
174 &cookie->flags))
175 wake_up_bit(&cookie->flags,
176 FSCACHE_COOKIE_LOOKING_UP);
177 if (test_and_clear_bit(FSCACHE_COOKIE_CREATING,
178 &cookie->flags))
179 wake_up_bit(&cookie->flags,
180 FSCACHE_COOKIE_CREATING);
181 } 201 }
182 spin_unlock(&object->lock); 202 }
183 203
184 fscache_done_parent_op(object); 204 /* Wait states are just transition tables */
205 if (!state->work) {
206 if (events & event_mask) {
207 for (t = state->transitions; t->events; t++) {
208 if (events & t->events) {
209 new_state = t->transit_to;
210 event = fls(events & t->events) - 1;
211 clear_bit(event, &object->events);
212 _debug("{OBJ%x} ev %d: %s -> %s",
213 object->debug_id, event,
214 state->name, new_state->name);
215 object->state = state = new_state;
216 goto execute_work_state;
217 }
218 }
185 219
186 /* wait for completion of all active operations on this object 220 /* The event mask didn't include all the tabled bits */
187 * and the death of all child objects of this object */ 221 BUG();
188 case FSCACHE_OBJECT_DYING:
189 dying:
190 clear_bit(FSCACHE_OBJECT_EV_CLEARED, &object->events);
191 spin_lock(&object->lock);
192 _debug("dying OBJ%x {%d,%d}",
193 object->debug_id, object->n_ops, object->n_children);
194 if (object->n_ops == 0 && object->n_children == 0) {
195 object->event_mask &=
196 ~(1 << FSCACHE_OBJECT_EV_CLEARED);
197 object->event_mask |=
198 (1 << FSCACHE_OBJECT_EV_WITHDRAW) |
199 (1 << FSCACHE_OBJECT_EV_RETIRE) |
200 (1 << FSCACHE_OBJECT_EV_RELEASE) |
201 (1 << FSCACHE_OBJECT_EV_ERROR);
202 } else {
203 object->event_mask &=
204 ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) |
205 (1 << FSCACHE_OBJECT_EV_RETIRE) |
206 (1 << FSCACHE_OBJECT_EV_RELEASE) |
207 (1 << FSCACHE_OBJECT_EV_ERROR));
208 object->event_mask |=
209 1 << FSCACHE_OBJECT_EV_CLEARED;
210 } 222 }
211 spin_unlock(&object->lock); 223 /* Randomly woke up */
212 fscache_enqueue_dependents(object); 224 goto unmask_events;
213 fscache_start_operations(object);
214 goto terminal_transit;
215
216 /* handle an abort during initialisation */
217 case FSCACHE_OBJECT_ABORT_INIT:
218 _debug("handle abort init %lx", object->events);
219 object->event_mask &= ~(1 << FSCACHE_OBJECT_EV_UPDATE);
220
221 spin_lock(&object->lock);
222 fscache_dequeue_object(object);
223
224 object->state = FSCACHE_OBJECT_DYING;
225 if (test_and_clear_bit(FSCACHE_COOKIE_CREATING,
226 &object->cookie->flags))
227 wake_up_bit(&object->cookie->flags,
228 FSCACHE_COOKIE_CREATING);
229 spin_unlock(&object->lock);
230 goto dying;
231
232 /* handle the netfs releasing an object and possibly marking it
233 * obsolete too */
234 case FSCACHE_OBJECT_RELEASING:
235 case FSCACHE_OBJECT_RECYCLING:
236 object->event_mask &=
237 ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) |
238 (1 << FSCACHE_OBJECT_EV_RETIRE) |
239 (1 << FSCACHE_OBJECT_EV_RELEASE) |
240 (1 << FSCACHE_OBJECT_EV_ERROR));
241 fscache_release_object(object);
242 spin_lock(&object->lock);
243 object->state = FSCACHE_OBJECT_DEAD;
244 spin_unlock(&object->lock);
245 fscache_stat(&fscache_n_object_dead);
246 goto terminal_transit;
247
248 /* handle the parent cache of this object being withdrawn from
249 * active service */
250 case FSCACHE_OBJECT_WITHDRAWING:
251 object->event_mask &=
252 ~((1 << FSCACHE_OBJECT_EV_WITHDRAW) |
253 (1 << FSCACHE_OBJECT_EV_RETIRE) |
254 (1 << FSCACHE_OBJECT_EV_RELEASE) |
255 (1 << FSCACHE_OBJECT_EV_ERROR));
256 fscache_withdraw_object(object);
257 spin_lock(&object->lock);
258 object->state = FSCACHE_OBJECT_DEAD;
259 spin_unlock(&object->lock);
260 fscache_stat(&fscache_n_object_dead);
261 goto terminal_transit;
262
263 /* complain about the object being woken up once it is
264 * deceased */
265 case FSCACHE_OBJECT_DEAD:
266 printk(KERN_ERR "FS-Cache:"
267 " Unexpected event in dead state %lx\n",
268 object->events & object->event_mask);
269 BUG();
270
271 default:
272 printk(KERN_ERR "FS-Cache: Unknown object state %u\n",
273 object->state);
274 BUG();
275 } 225 }
276 226
277 /* determine the transition from a lookup state */ 227execute_work_state:
278lookup_transit: 228 _debug("{OBJ%x} exec %s", object->debug_id, state->name);
279 event = fls(object->events & object->event_mask) - 1;
280 switch (event) {
281 case FSCACHE_OBJECT_EV_WITHDRAW:
282 case FSCACHE_OBJECT_EV_RETIRE:
283 case FSCACHE_OBJECT_EV_RELEASE:
284 case FSCACHE_OBJECT_EV_ERROR:
285 new_state = FSCACHE_OBJECT_LC_DYING;
286 goto change_state;
287 case FSCACHE_OBJECT_EV_INVALIDATE:
288 new_state = FSCACHE_OBJECT_INVALIDATING;
289 goto change_state;
290 case FSCACHE_OBJECT_EV_REQUEUE:
291 goto done;
292 case -1:
293 goto done; /* sleep until event */
294 default:
295 goto unsupported_event;
296 }
297
298 /* determine the transition from an active state */
299active_transit:
300 event = fls(object->events & object->event_mask) - 1;
301 switch (event) {
302 case FSCACHE_OBJECT_EV_WITHDRAW:
303 case FSCACHE_OBJECT_EV_RETIRE:
304 case FSCACHE_OBJECT_EV_RELEASE:
305 case FSCACHE_OBJECT_EV_ERROR:
306 new_state = FSCACHE_OBJECT_DYING;
307 goto change_state;
308 case FSCACHE_OBJECT_EV_INVALIDATE:
309 new_state = FSCACHE_OBJECT_INVALIDATING;
310 goto change_state;
311 case FSCACHE_OBJECT_EV_UPDATE:
312 new_state = FSCACHE_OBJECT_UPDATING;
313 goto change_state;
314 case -1:
315 new_state = FSCACHE_OBJECT_ACTIVE;
316 goto change_state; /* sleep until event */
317 default:
318 goto unsupported_event;
319 }
320 229
321 /* determine the transition from a terminal state */ 230 new_state = state->work(object, event);
322terminal_transit: 231 event = -1;
323 event = fls(object->events & object->event_mask) - 1; 232 if (new_state == NO_TRANSIT) {
324 switch (event) { 233 _debug("{OBJ%x} %s notrans", object->debug_id, state->name);
325 case FSCACHE_OBJECT_EV_WITHDRAW: 234 fscache_enqueue_object(object);
326 new_state = FSCACHE_OBJECT_WITHDRAWING; 235 event_mask = object->oob_event_mask;
327 goto change_state; 236 goto unmask_events;
328 case FSCACHE_OBJECT_EV_RETIRE:
329 new_state = FSCACHE_OBJECT_RECYCLING;
330 goto change_state;
331 case FSCACHE_OBJECT_EV_RELEASE:
332 new_state = FSCACHE_OBJECT_RELEASING;
333 goto change_state;
334 case FSCACHE_OBJECT_EV_ERROR:
335 new_state = FSCACHE_OBJECT_WITHDRAWING;
336 goto change_state;
337 case FSCACHE_OBJECT_EV_CLEARED:
338 new_state = FSCACHE_OBJECT_DYING;
339 goto change_state;
340 case -1:
341 goto done; /* sleep until event */
342 default:
343 goto unsupported_event;
344 } 237 }
345 238
346change_state: 239 _debug("{OBJ%x} %s -> %s",
347 spin_lock(&object->lock); 240 object->debug_id, state->name, new_state->name);
348 object->state = new_state; 241 object->state = state = new_state;
349 spin_unlock(&object->lock);
350 242
351done: 243 if (state->work) {
352 _leave(" [->%s]", fscache_object_states[object->state]); 244 if (unlikely(state->work == ((void *)2UL))) {
353 return; 245 _leave(" [dead]");
246 return;
247 }
248 goto restart_masked;
249 }
354 250
355unsupported_event: 251 /* Transited to wait state */
356 printk(KERN_ERR "FS-Cache:" 252 event_mask = object->oob_event_mask;
357 " Unsupported event %d [%lx/%lx] in state %s\n", 253 for (t = state->transitions; t->events; t++)
358 event, object->events, object->event_mask, 254 event_mask |= t->events;
359 fscache_object_states[object->state]); 255
360 BUG(); 256unmask_events:
257 object->event_mask = event_mask;
258 smp_mb();
259 events = object->events;
260 if (events & event_mask)
261 goto restart;
262 _leave(" [msk %lx]", event_mask);
361} 263}
362 264
363/* 265/*
@@ -372,11 +274,8 @@ static void fscache_object_work_func(struct work_struct *work)
372 _enter("{OBJ%x}", object->debug_id); 274 _enter("{OBJ%x}", object->debug_id);
373 275
374 start = jiffies; 276 start = jiffies;
375 fscache_object_state_machine(object); 277 fscache_object_sm_dispatcher(object);
376 fscache_hist(fscache_objs_histogram, start); 278 fscache_hist(fscache_objs_histogram, start);
377 if (object->events & object->event_mask)
378 fscache_enqueue_object(object);
379 clear_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
380 fscache_put_object(object); 279 fscache_put_object(object);
381} 280}
382 281
@@ -395,9 +294,13 @@ void fscache_object_init(struct fscache_object *object,
395 struct fscache_cookie *cookie, 294 struct fscache_cookie *cookie,
396 struct fscache_cache *cache) 295 struct fscache_cache *cache)
397{ 296{
297 const struct fscache_transition *t;
298
398 atomic_inc(&cache->object_count); 299 atomic_inc(&cache->object_count);
399 300
400 object->state = FSCACHE_OBJECT_INIT; 301 object->state = STATE(WAIT_FOR_INIT);
302 object->oob_table = fscache_osm_init_oob;
303 object->flags = 1 << FSCACHE_OBJECT_IS_LIVE;
401 spin_lock_init(&object->lock); 304 spin_lock_init(&object->lock);
402 INIT_LIST_HEAD(&object->cache_link); 305 INIT_LIST_HEAD(&object->cache_link);
403 INIT_HLIST_NODE(&object->cookie_link); 306 INIT_HLIST_NODE(&object->cookie_link);
@@ -407,17 +310,48 @@ void fscache_object_init(struct fscache_object *object,
407 INIT_LIST_HEAD(&object->pending_ops); 310 INIT_LIST_HEAD(&object->pending_ops);
408 object->n_children = 0; 311 object->n_children = 0;
409 object->n_ops = object->n_in_progress = object->n_exclusive = 0; 312 object->n_ops = object->n_in_progress = object->n_exclusive = 0;
410 object->events = object->event_mask = 0; 313 object->events = 0;
411 object->flags = 0;
412 object->store_limit = 0; 314 object->store_limit = 0;
413 object->store_limit_l = 0; 315 object->store_limit_l = 0;
414 object->cache = cache; 316 object->cache = cache;
415 object->cookie = cookie; 317 object->cookie = cookie;
416 object->parent = NULL; 318 object->parent = NULL;
319
320 object->oob_event_mask = 0;
321 for (t = object->oob_table; t->events; t++)
322 object->oob_event_mask |= t->events;
323 object->event_mask = object->oob_event_mask;
324 for (t = object->state->transitions; t->events; t++)
325 object->event_mask |= t->events;
417} 326}
418EXPORT_SYMBOL(fscache_object_init); 327EXPORT_SYMBOL(fscache_object_init);
419 328
420/* 329/*
330 * Abort object initialisation before we start it.
331 */
332static const struct fscache_state *fscache_abort_initialisation(struct fscache_object *object,
333 int event)
334{
335 struct fscache_cookie *cookie;
336
337 _enter("{OBJ%x},%d", object->debug_id, event);
338
339 object->oob_event_mask = 0;
340 clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags);
341
342 fscache_dequeue_object(object);
343
344 spin_lock(&object->lock);
345 cookie = object->cookie;
346 clear_bit_unlock(FSCACHE_COOKIE_CREATING, &cookie->flags);
347 spin_unlock(&object->lock);
348
349 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING);
350
351 return transit_to(KILL_OBJECT);
352}
353
354/*
421 * initialise an object 355 * initialise an object
422 * - check the specified object's parent to see if we can make use of it 356 * - check the specified object's parent to see if we can make use of it
423 * immediately to do a creation 357 * immediately to do a creation
@@ -426,74 +360,78 @@ EXPORT_SYMBOL(fscache_object_init);
426 * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the 360 * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the
427 * leaf-most cookies of the object and all its children 361 * leaf-most cookies of the object and all its children
428 */ 362 */
429static void fscache_initialise_object(struct fscache_object *object) 363static const struct fscache_state *fscache_initialise_object(struct fscache_object *object,
364 int event)
430{ 365{
431 struct fscache_object *parent; 366 struct fscache_object *parent;
367 bool success;
432 368
433 _enter(""); 369 _enter("{OBJ%x},%d", object->debug_id, event);
434 ASSERT(object->cookie != NULL);
435 ASSERT(object->cookie->parent != NULL);
436 370
437 if (object->events & ((1 << FSCACHE_OBJECT_EV_ERROR) | 371 ASSERT(list_empty(&object->dep_link));
438 (1 << FSCACHE_OBJECT_EV_RELEASE) |
439 (1 << FSCACHE_OBJECT_EV_RETIRE) |
440 (1 << FSCACHE_OBJECT_EV_WITHDRAW))) {
441 _debug("abort init %lx", object->events);
442 spin_lock(&object->lock);
443 object->state = FSCACHE_OBJECT_ABORT_INIT;
444 spin_unlock(&object->lock);
445 return;
446 }
447
448 spin_lock(&object->cookie->lock);
449 spin_lock_nested(&object->cookie->parent->lock, 1);
450 372
451 parent = object->parent; 373 parent = object->parent;
452 if (!parent) { 374 if (!parent) {
453 _debug("no parent"); 375 _leave(" [no parent]");
454 set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events); 376 return transit_to(DETACH_FROM_COOKIE);
455 } else { 377 }
456 spin_lock(&object->lock);
457 spin_lock_nested(&parent->lock, 1);
458 _debug("parent %s", fscache_object_states[parent->state]);
459
460 if (fscache_object_is_dying(parent)) {
461 _debug("bad parent");
462 set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events);
463 } else if (!fscache_object_is_available(parent)) {
464 _debug("wait");
465
466 /* we may get woken up in this state by child objects
467 * binding on to us, so we need to make sure we don't
468 * add ourself to the list multiple times */
469 if (list_empty(&object->dep_link)) {
470 fscache_stat(&fscache_n_cop_grab_object);
471 object->cache->ops->grab_object(object);
472 fscache_stat_d(&fscache_n_cop_grab_object);
473 list_add(&object->dep_link,
474 &parent->dependents);
475
476 /* fscache_acquire_non_index_cookie() uses this
477 * to wake the chain up */
478 if (parent->state == FSCACHE_OBJECT_INIT)
479 fscache_enqueue_object(parent);
480 }
481 } else {
482 _debug("go");
483 parent->n_ops++;
484 parent->n_obj_ops++;
485 object->lookup_jif = jiffies;
486 object->state = FSCACHE_OBJECT_LOOKING_UP;
487 set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
488 }
489 378
490 spin_unlock(&parent->lock); 379 _debug("parent %s", parent->state->name);
491 spin_unlock(&object->lock); 380
381 if (fscache_object_is_dying(parent)) {
382 _leave(" [bad parent]");
383 return transit_to(DETACH_FROM_COOKIE);
384 }
385
386 if (fscache_object_is_available(parent)) {
387 _leave(" [ready]");
388 return transit_to(PARENT_READY);
389 }
390
391 _debug("wait");
392
393 spin_lock(&parent->lock);
394 fscache_stat(&fscache_n_cop_grab_object);
395 success = false;
396 if (fscache_object_is_live(parent) &&
397 object->cache->ops->grab_object(object)) {
398 list_add(&object->dep_link, &parent->dependents);
399 success = true;
400 }
401 fscache_stat_d(&fscache_n_cop_grab_object);
402 spin_unlock(&parent->lock);
403 if (!success) {
404 _leave(" [grab failed]");
405 return transit_to(DETACH_FROM_COOKIE);
492 } 406 }
493 407
494 spin_unlock(&object->cookie->parent->lock); 408 /* fscache_acquire_non_index_cookie() uses this
495 spin_unlock(&object->cookie->lock); 409 * to wake the chain up */
410 fscache_raise_event(parent, FSCACHE_OBJECT_EV_NEW_CHILD);
411 _leave(" [wait]");
412 return transit_to(WAIT_FOR_PARENT);
413}
414
415/*
416 * Once the parent object is ready, we should kick off our lookup op.
417 */
418static const struct fscache_state *fscache_parent_ready(struct fscache_object *object,
419 int event)
420{
421 struct fscache_object *parent = object->parent;
422
423 _enter("{OBJ%x},%d", object->debug_id, event);
424
425 ASSERT(parent != NULL);
426
427 spin_lock(&parent->lock);
428 parent->n_ops++;
429 parent->n_obj_ops++;
430 object->lookup_jif = jiffies;
431 spin_unlock(&parent->lock);
432
496 _leave(""); 433 _leave("");
434 return transit_to(LOOK_UP_OBJECT);
497} 435}
498 436
499/* 437/*
@@ -503,15 +441,17 @@ static void fscache_initialise_object(struct fscache_object *object)
503 * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the 441 * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the
504 * leaf-most cookies of the object and all its children 442 * leaf-most cookies of the object and all its children
505 */ 443 */
506static void fscache_lookup_object(struct fscache_object *object) 444static const struct fscache_state *fscache_look_up_object(struct fscache_object *object,
445 int event)
507{ 446{
508 struct fscache_cookie *cookie = object->cookie; 447 struct fscache_cookie *cookie = object->cookie;
509 struct fscache_object *parent; 448 struct fscache_object *parent = object->parent;
510 int ret; 449 int ret;
511 450
512 _enter(""); 451 _enter("{OBJ%x},%d", object->debug_id, event);
452
453 object->oob_table = fscache_osm_lookup_oob;
513 454
514 parent = object->parent;
515 ASSERT(parent != NULL); 455 ASSERT(parent != NULL);
516 ASSERTCMP(parent->n_ops, >, 0); 456 ASSERTCMP(parent->n_ops, >, 0);
517 ASSERTCMP(parent->n_obj_ops, >, 0); 457 ASSERTCMP(parent->n_obj_ops, >, 0);
@@ -521,10 +461,8 @@ static void fscache_lookup_object(struct fscache_object *object)
521 461
522 if (fscache_object_is_dying(parent) || 462 if (fscache_object_is_dying(parent) ||
523 test_bit(FSCACHE_IOERROR, &object->cache->flags)) { 463 test_bit(FSCACHE_IOERROR, &object->cache->flags)) {
524 _debug("unavailable"); 464 _leave(" [unavailable]");
525 set_bit(FSCACHE_OBJECT_EV_WITHDRAW, &object->events); 465 return transit_to(LOOKUP_FAILURE);
526 _leave("");
527 return;
528 } 466 }
529 467
530 _debug("LOOKUP \"%s/%s\" in \"%s\"", 468 _debug("LOOKUP \"%s/%s\" in \"%s\"",
@@ -543,10 +481,17 @@ static void fscache_lookup_object(struct fscache_object *object)
543 /* probably stuck behind another object, so move this one to 481 /* probably stuck behind another object, so move this one to
544 * the back of the queue */ 482 * the back of the queue */
545 fscache_stat(&fscache_n_object_lookups_timed_out); 483 fscache_stat(&fscache_n_object_lookups_timed_out);
546 set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events); 484 _leave(" [timeout]");
485 return NO_TRANSIT;
547 } 486 }
548 487
549 _leave(""); 488 if (ret < 0) {
489 _leave(" [error]");
490 return transit_to(LOOKUP_FAILURE);
491 }
492
493 _leave(" [ok]");
494 return transit_to(OBJECT_AVAILABLE);
550} 495}
551 496
552/** 497/**
@@ -560,32 +505,20 @@ void fscache_object_lookup_negative(struct fscache_object *object)
560{ 505{
561 struct fscache_cookie *cookie = object->cookie; 506 struct fscache_cookie *cookie = object->cookie;
562 507
563 _enter("{OBJ%x,%s}", 508 _enter("{OBJ%x,%s}", object->debug_id, object->state->name);
564 object->debug_id, fscache_object_states[object->state]);
565 509
566 spin_lock(&object->lock); 510 if (!test_and_set_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)) {
567 if (object->state == FSCACHE_OBJECT_LOOKING_UP) {
568 fscache_stat(&fscache_n_object_lookups_negative); 511 fscache_stat(&fscache_n_object_lookups_negative);
569 512
570 /* transit here to allow write requests to begin stacking up 513 /* Allow write requests to begin stacking up and read requests to begin
571 * and read requests to begin returning ENODATA */ 514 * returning ENODATA.
572 object->state = FSCACHE_OBJECT_CREATING; 515 */
573 spin_unlock(&object->lock);
574
575 set_bit(FSCACHE_COOKIE_PENDING_FILL, &cookie->flags);
576 set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); 516 set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags);
577 517
578 _debug("wake up lookup %p", &cookie->flags); 518 _debug("wake up lookup %p", &cookie->flags);
579 smp_mb__before_clear_bit(); 519 clear_bit_unlock(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags);
580 clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags);
581 smp_mb__after_clear_bit();
582 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP); 520 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP);
583 set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
584 } else {
585 ASSERTCMP(object->state, ==, FSCACHE_OBJECT_CREATING);
586 spin_unlock(&object->lock);
587 } 521 }
588
589 _leave(""); 522 _leave("");
590} 523}
591EXPORT_SYMBOL(fscache_object_lookup_negative); 524EXPORT_SYMBOL(fscache_object_lookup_negative);
@@ -604,37 +537,30 @@ void fscache_obtained_object(struct fscache_object *object)
604{ 537{
605 struct fscache_cookie *cookie = object->cookie; 538 struct fscache_cookie *cookie = object->cookie;
606 539
607 _enter("{OBJ%x,%s}", 540 _enter("{OBJ%x,%s}", object->debug_id, object->state->name);
608 object->debug_id, fscache_object_states[object->state]);
609 541
610 /* if we were still looking up, then we must have a positive lookup 542 /* if we were still looking up, then we must have a positive lookup
611 * result, in which case there may be data available */ 543 * result, in which case there may be data available */
612 spin_lock(&object->lock); 544 if (!test_and_set_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)) {
613 if (object->state == FSCACHE_OBJECT_LOOKING_UP) {
614 fscache_stat(&fscache_n_object_lookups_positive); 545 fscache_stat(&fscache_n_object_lookups_positive);
615 546
616 clear_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); 547 /* We do (presumably) have data */
617 548 clear_bit_unlock(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags);
618 object->state = FSCACHE_OBJECT_AVAILABLE;
619 spin_unlock(&object->lock);
620 549
621 smp_mb__before_clear_bit(); 550 /* Allow write requests to begin stacking up and read requests
622 clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags); 551 * to begin shovelling data.
623 smp_mb__after_clear_bit(); 552 */
553 clear_bit_unlock(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags);
624 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP); 554 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP);
625 set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
626 } else { 555 } else {
627 ASSERTCMP(object->state, ==, FSCACHE_OBJECT_CREATING);
628 fscache_stat(&fscache_n_object_created); 556 fscache_stat(&fscache_n_object_created);
629
630 object->state = FSCACHE_OBJECT_AVAILABLE;
631 spin_unlock(&object->lock);
632 set_bit(FSCACHE_OBJECT_EV_REQUEUE, &object->events);
633 smp_wmb();
634 } 557 }
635 558
636 if (test_and_clear_bit(FSCACHE_COOKIE_CREATING, &cookie->flags)) 559 set_bit(FSCACHE_OBJECT_IS_AVAILABLE, &object->flags);
637 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING); 560
561 /* Permit __fscache_relinquish_cookie() to proceed */
562 clear_bit_unlock(FSCACHE_COOKIE_CREATING, &cookie->flags);
563 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING);
638 564
639 _leave(""); 565 _leave("");
640} 566}
@@ -643,15 +569,18 @@ EXPORT_SYMBOL(fscache_obtained_object);
643/* 569/*
644 * handle an object that has just become available 570 * handle an object that has just become available
645 */ 571 */
646static void fscache_object_available(struct fscache_object *object) 572static const struct fscache_state *fscache_object_available(struct fscache_object *object,
573 int event)
647{ 574{
648 _enter("{OBJ%x}", object->debug_id); 575 struct fscache_cookie *cookie = object->cookie;
576
577 _enter("{OBJ%x},%d", object->debug_id, event);
578
579 object->oob_table = fscache_osm_run_oob;
649 580
650 spin_lock(&object->lock); 581 spin_lock(&object->lock);
651 582
652 if (object->cookie && 583 ASSERTIF(cookie, !test_bit(FSCACHE_COOKIE_CREATING, &object->cookie->flags));
653 test_and_clear_bit(FSCACHE_COOKIE_CREATING, &object->cookie->flags))
654 wake_up_bit(&object->cookie->flags, FSCACHE_COOKIE_CREATING);
655 584
656 fscache_done_parent_op(object); 585 fscache_done_parent_op(object);
657 if (object->n_in_progress == 0) { 586 if (object->n_in_progress == 0) {
@@ -667,72 +596,117 @@ static void fscache_object_available(struct fscache_object *object)
667 fscache_stat(&fscache_n_cop_lookup_complete); 596 fscache_stat(&fscache_n_cop_lookup_complete);
668 object->cache->ops->lookup_complete(object); 597 object->cache->ops->lookup_complete(object);
669 fscache_stat_d(&fscache_n_cop_lookup_complete); 598 fscache_stat_d(&fscache_n_cop_lookup_complete);
670 fscache_enqueue_dependents(object);
671 599
672 fscache_hist(fscache_obj_instantiate_histogram, object->lookup_jif); 600 fscache_hist(fscache_obj_instantiate_histogram, object->lookup_jif);
673 fscache_stat(&fscache_n_object_avail); 601 fscache_stat(&fscache_n_object_avail);
674 602
675 _leave(""); 603 _leave("");
604 return transit_to(JUMPSTART_DEPS);
676} 605}
677 606
678/* 607/*
679 * drop an object's attachments 608 * Wake up this object's dependent objects now that we've become available.
680 */ 609 */
681static void fscache_drop_object(struct fscache_object *object) 610static const struct fscache_state *fscache_jumpstart_dependents(struct fscache_object *object,
611 int event)
682{ 612{
683 struct fscache_object *parent = object->parent; 613 _enter("{OBJ%x},%d", object->debug_id, event);
684 struct fscache_cache *cache = object->cache;
685 614
686 _enter("{OBJ%x,%d}", object->debug_id, object->n_children); 615 if (!fscache_enqueue_dependents(object, FSCACHE_OBJECT_EV_PARENT_READY))
616 return NO_TRANSIT; /* Not finished; requeue */
617 return transit_to(WAIT_FOR_CMD);
618}
687 619
688 ASSERTCMP(object->cookie, ==, NULL); 620/*
689 ASSERT(hlist_unhashed(&object->cookie_link)); 621 * Handle lookup or creation failute.
622 */
623static const struct fscache_state *fscache_lookup_failure(struct fscache_object *object,
624 int event)
625{
626 struct fscache_cookie *cookie;
627 bool wake_looking_up = false;
690 628
691 spin_lock(&cache->object_list_lock); 629 _enter("{OBJ%x},%d", object->debug_id, event);
692 list_del_init(&object->cache_link);
693 spin_unlock(&cache->object_list_lock);
694 630
695 fscache_stat(&fscache_n_cop_drop_object); 631 object->oob_event_mask = 0;
696 cache->ops->drop_object(object);
697 fscache_stat_d(&fscache_n_cop_drop_object);
698 632
699 if (parent) { 633 fscache_stat(&fscache_n_cop_lookup_complete);
700 _debug("release parent OBJ%x {%d}", 634 object->cache->ops->lookup_complete(object);
701 parent->debug_id, parent->n_children); 635 fscache_stat_d(&fscache_n_cop_lookup_complete);
702 636
703 spin_lock(&parent->lock); 637 spin_lock(&object->lock);
704 parent->n_children--; 638 cookie = object->cookie;
705 if (parent->n_children == 0) 639 set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags);
706 fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED); 640 if (cookie) {
707 spin_unlock(&parent->lock); 641 if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags))
708 object->parent = NULL; 642 wake_looking_up = true;
643 clear_bit_unlock(FSCACHE_COOKIE_CREATING, &cookie->flags);
709 } 644 }
645 spin_unlock(&object->lock);
710 646
711 /* this just shifts the object release to the work processor */ 647 if (wake_looking_up)
712 fscache_put_object(object); 648 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP);
649 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING);
713 650
714 _leave(""); 651 fscache_done_parent_op(object);
652 return transit_to(KILL_OBJECT);
653}
654
655/*
656 * Wait for completion of all active operations on this object and the death of
657 * all child objects of this object.
658 */
659static const struct fscache_state *fscache_kill_object(struct fscache_object *object,
660 int event)
661{
662 _enter("{OBJ%x,%d,%d},%d",
663 object->debug_id, object->n_ops, object->n_children, event);
664
665 object->oob_event_mask = 0;
666
667 spin_lock(&object->lock);
668 clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags);
669 spin_unlock(&object->lock);
670
671 if (list_empty(&object->dependents) &&
672 object->n_ops == 0 &&
673 object->n_children == 0)
674 return object->cookie ?
675 transit_to(DETACH_FROM_COOKIE) : transit_to(DROP_OBJECT);
676
677 spin_lock(&object->lock);
678 fscache_start_operations(object);
679 spin_unlock(&object->lock);
680
681 if (!list_empty(&object->dependents))
682 return transit_to(KILL_DEPENDENTS);
683
684 return transit_to(WAIT_FOR_CLEARANCE);
715} 685}
716 686
717/* 687/*
718 * release or recycle an object that the netfs has discarded 688 * Kill dependent objects.
719 */ 689 */
720static void fscache_release_object(struct fscache_object *object) 690static const struct fscache_state *fscache_kill_dependents(struct fscache_object *object,
691 int event)
721{ 692{
722 _enter(""); 693 _enter("{OBJ%x},%d", object->debug_id, event);
723 694
724 fscache_drop_object(object); 695 if (!fscache_enqueue_dependents(object, FSCACHE_OBJECT_EV_KILL))
696 return NO_TRANSIT; /* Not finished */
697 return transit_to(WAIT_FOR_CLEARANCE);
725} 698}
726 699
727/* 700/*
728 * withdraw an object from active service 701 * withdraw an object from active service
729 */ 702 */
730static void fscache_withdraw_object(struct fscache_object *object) 703static const struct fscache_state *fscache_detach_from_cookie(struct fscache_object *object,
704 int event)
731{ 705{
732 struct fscache_cookie *cookie; 706 struct fscache_cookie *cookie;
733 bool detached; 707 bool detached = false, awaken = false;
734 708
735 _enter(""); 709 _enter("{OBJ%x},%d", object->debug_id, event);
736 710
737 spin_lock(&object->lock); 711 spin_lock(&object->lock);
738 cookie = object->cookie; 712 cookie = object->cookie;
@@ -742,14 +716,15 @@ static void fscache_withdraw_object(struct fscache_object *object)
742 atomic_inc(&cookie->usage); 716 atomic_inc(&cookie->usage);
743 spin_unlock(&object->lock); 717 spin_unlock(&object->lock);
744 718
745 detached = false;
746 spin_lock(&cookie->lock); 719 spin_lock(&cookie->lock);
747 spin_lock(&object->lock); 720 spin_lock(&object->lock);
748 721
749 if (object->cookie == cookie) { 722 if (object->cookie == cookie) {
750 hlist_del_init(&object->cookie_link); 723 hlist_del_init(&object->cookie_link);
751 object->cookie = NULL; 724 object->cookie = NULL;
752 fscache_invalidation_complete(cookie); 725 if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING,
726 &cookie->flags))
727 awaken = true;
753 detached = true; 728 detached = true;
754 } 729 }
755 spin_unlock(&cookie->lock); 730 spin_unlock(&cookie->lock);
@@ -760,37 +735,62 @@ static void fscache_withdraw_object(struct fscache_object *object)
760 735
761 spin_unlock(&object->lock); 736 spin_unlock(&object->lock);
762 737
763 fscache_drop_object(object); 738 if (awaken)
739 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING);
740
741 fscache_stat(&fscache_n_object_dead);
742 _leave("");
743 return transit_to(DROP_OBJECT);
764} 744}
765 745
766/* 746/*
767 * withdraw an object from active service at the behest of the cache 747 * Drop an object's attachments
768 * - need break the links to a cached object cookie 748 */
769 * - called under two situations: 749static const struct fscache_state *fscache_drop_object(struct fscache_object *object,
770 * (1) recycler decides to reclaim an in-use object 750 int event)
771 * (2) a cache is unmounted
772 * - have to take care as the cookie can be being relinquished by the netfs
773 * simultaneously
774 * - the object is pinned by the caller holding a refcount on it
775 */
776void fscache_withdrawing_object(struct fscache_cache *cache,
777 struct fscache_object *object)
778{ 751{
779 bool enqueue = false; 752 struct fscache_object *parent = object->parent;
753 struct fscache_cache *cache = object->cache;
780 754
781 _enter(",OBJ%x", object->debug_id); 755 _enter("{OBJ%x,%d},%d", object->debug_id, object->n_children, event);
782 756
757 ASSERTCMP(object->cookie, ==, NULL);
758 ASSERT(hlist_unhashed(&object->cookie_link));
759
760 /* Prevent a race with our last child, which has to signal EV_CLEARED
761 * before dropping our spinlock.
762 */
783 spin_lock(&object->lock); 763 spin_lock(&object->lock);
784 if (object->state < FSCACHE_OBJECT_WITHDRAWING) {
785 object->state = FSCACHE_OBJECT_WITHDRAWING;
786 enqueue = true;
787 }
788 spin_unlock(&object->lock); 764 spin_unlock(&object->lock);
789 765
790 if (enqueue) 766 /* Discard from the cache's collection of objects */
791 fscache_enqueue_object(object); 767 spin_lock(&cache->object_list_lock);
768 list_del_init(&object->cache_link);
769 spin_unlock(&cache->object_list_lock);
770
771 fscache_stat(&fscache_n_cop_drop_object);
772 cache->ops->drop_object(object);
773 fscache_stat_d(&fscache_n_cop_drop_object);
774
775 /* The parent object wants to know when all it dependents have gone */
776 if (parent) {
777 _debug("release parent OBJ%x {%d}",
778 parent->debug_id, parent->n_children);
779
780 spin_lock(&parent->lock);
781 parent->n_children--;
782 if (parent->n_children == 0)
783 fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED);
784 spin_unlock(&parent->lock);
785 object->parent = NULL;
786 }
787
788 /* this just shifts the object release to the work processor */
789 fscache_put_object(object);
790 fscache_stat(&fscache_n_object_dead);
792 791
793 _leave(""); 792 _leave("");
793 return transit_to(OBJECT_DEAD);
794} 794}
795 795
796/* 796/*
@@ -807,7 +807,7 @@ static int fscache_get_object(struct fscache_object *object)
807} 807}
808 808
809/* 809/*
810 * discard a ref on a work item 810 * Discard a ref on an object
811 */ 811 */
812static void fscache_put_object(struct fscache_object *object) 812static void fscache_put_object(struct fscache_object *object)
813{ 813{
@@ -839,7 +839,7 @@ void fscache_enqueue_object(struct fscache_object *object)
839 839
840/** 840/**
841 * fscache_object_sleep_till_congested - Sleep until object wq is congested 841 * fscache_object_sleep_till_congested - Sleep until object wq is congested
842 * @timoutp: Scheduler sleep timeout 842 * @timeoutp: Scheduler sleep timeout
843 * 843 *
844 * Allow an object handler to sleep until the object workqueue is congested. 844 * Allow an object handler to sleep until the object workqueue is congested.
845 * 845 *
@@ -867,18 +867,21 @@ bool fscache_object_sleep_till_congested(signed long *timeoutp)
867EXPORT_SYMBOL_GPL(fscache_object_sleep_till_congested); 867EXPORT_SYMBOL_GPL(fscache_object_sleep_till_congested);
868 868
869/* 869/*
870 * enqueue the dependents of an object for metadata-type processing 870 * Enqueue the dependents of an object for metadata-type processing.
871 * - the caller must hold the object's lock 871 *
872 * - this may cause an already locked object to wind up being processed again 872 * If we don't manage to finish the list before the scheduler wants to run
873 * again then return false immediately. We return true if the list was
874 * cleared.
873 */ 875 */
874static void fscache_enqueue_dependents(struct fscache_object *object) 876static bool fscache_enqueue_dependents(struct fscache_object *object, int event)
875{ 877{
876 struct fscache_object *dep; 878 struct fscache_object *dep;
879 bool ret = true;
877 880
878 _enter("{OBJ%x}", object->debug_id); 881 _enter("{OBJ%x}", object->debug_id);
879 882
880 if (list_empty(&object->dependents)) 883 if (list_empty(&object->dependents))
881 return; 884 return true;
882 885
883 spin_lock(&object->lock); 886 spin_lock(&object->lock);
884 887
@@ -887,23 +890,23 @@ static void fscache_enqueue_dependents(struct fscache_object *object)
887 struct fscache_object, dep_link); 890 struct fscache_object, dep_link);
888 list_del_init(&dep->dep_link); 891 list_del_init(&dep->dep_link);
889 892
890 893 fscache_raise_event(dep, event);
891 /* sort onto appropriate lists */
892 fscache_enqueue_object(dep);
893 fscache_put_object(dep); 894 fscache_put_object(dep);
894 895
895 if (!list_empty(&object->dependents)) 896 if (!list_empty(&object->dependents) && need_resched()) {
896 cond_resched_lock(&object->lock); 897 ret = false;
898 break;
899 }
897 } 900 }
898 901
899 spin_unlock(&object->lock); 902 spin_unlock(&object->lock);
903 return ret;
900} 904}
901 905
902/* 906/*
903 * remove an object from whatever queue it's waiting on 907 * remove an object from whatever queue it's waiting on
904 * - the caller must hold object->lock
905 */ 908 */
906void fscache_dequeue_object(struct fscache_object *object) 909static void fscache_dequeue_object(struct fscache_object *object)
907{ 910{
908 _enter("{OBJ%x}", object->debug_id); 911 _enter("{OBJ%x}", object->debug_id);
909 912
@@ -963,12 +966,14 @@ EXPORT_SYMBOL(fscache_check_aux);
963/* 966/*
964 * Asynchronously invalidate an object. 967 * Asynchronously invalidate an object.
965 */ 968 */
966static void fscache_invalidate_object(struct fscache_object *object) 969static const struct fscache_state *_fscache_invalidate_object(struct fscache_object *object,
970 int event)
967{ 971{
968 struct fscache_operation *op; 972 struct fscache_operation *op;
969 struct fscache_cookie *cookie = object->cookie; 973 struct fscache_cookie *cookie = object->cookie;
970 974
971 _enter("{OBJ%x}", object->debug_id); 975 _enter("{OBJ%x},%d", object->debug_id, event);
976
972 977
973 /* Reject any new read/write ops and abort any that are pending. */ 978 /* Reject any new read/write ops and abort any that are pending. */
974 fscache_invalidate_writes(cookie); 979 fscache_invalidate_writes(cookie);
@@ -978,9 +983,9 @@ static void fscache_invalidate_object(struct fscache_object *object)
978 /* Now we have to wait for in-progress reads and writes */ 983 /* Now we have to wait for in-progress reads and writes */
979 op = kzalloc(sizeof(*op), GFP_KERNEL); 984 op = kzalloc(sizeof(*op), GFP_KERNEL);
980 if (!op) { 985 if (!op) {
981 fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR); 986 clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags);
982 _leave(" [ENOMEM]"); 987 _leave(" [ENOMEM]");
983 return; 988 return transit_to(KILL_OBJECT);
984 } 989 }
985 990
986 fscache_operation_init(op, object->cache->ops->invalidate_object, NULL); 991 fscache_operation_init(op, object->cache->ops->invalidate_object, NULL);
@@ -1001,13 +1006,44 @@ static void fscache_invalidate_object(struct fscache_object *object)
1001 /* We can allow read and write requests to come in once again. They'll 1006 /* We can allow read and write requests to come in once again. They'll
1002 * queue up behind our exclusive invalidation operation. 1007 * queue up behind our exclusive invalidation operation.
1003 */ 1008 */
1004 fscache_invalidation_complete(cookie); 1009 if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags))
1005 _leave(""); 1010 wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING);
1006 return; 1011 _leave(" [ok]");
1012 return transit_to(UPDATE_OBJECT);
1007 1013
1008submit_op_failed: 1014submit_op_failed:
1015 clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags);
1009 spin_unlock(&cookie->lock); 1016 spin_unlock(&cookie->lock);
1010 kfree(op); 1017 kfree(op);
1011 fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR);
1012 _leave(" [EIO]"); 1018 _leave(" [EIO]");
1019 return transit_to(KILL_OBJECT);
1020}
1021
1022static const struct fscache_state *fscache_invalidate_object(struct fscache_object *object,
1023 int event)
1024{
1025 const struct fscache_state *s;
1026
1027 fscache_stat(&fscache_n_invalidates_run);
1028 fscache_stat(&fscache_n_cop_invalidate_object);
1029 s = _fscache_invalidate_object(object, event);
1030 fscache_stat_d(&fscache_n_cop_invalidate_object);
1031 return s;
1032}
1033
1034/*
1035 * Asynchronously update an object.
1036 */
1037static const struct fscache_state *fscache_update_object(struct fscache_object *object,
1038 int event)
1039{
1040 _enter("{OBJ%x},%d", object->debug_id, event);
1041
1042 fscache_stat(&fscache_n_updates_run);
1043 fscache_stat(&fscache_n_cop_update_object);
1044 object->cache->ops->update_object(object);
1045 fscache_stat_d(&fscache_n_cop_update_object);
1046
1047 _leave("");
1048 return transit_to(WAIT_FOR_CMD);
1013} 1049}
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c
index ccf02194e7a6..4da211b21ddf 100644
--- a/fs/fscache/operation.c
+++ b/fs/fscache/operation.c
@@ -119,7 +119,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
119 /* need to issue a new write op after this */ 119 /* need to issue a new write op after this */
120 clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); 120 clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
121 ret = 0; 121 ret = 0;
122 } else if (object->state == FSCACHE_OBJECT_CREATING) { 122 } else if (test_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)) {
123 op->object = object; 123 op->object = object;
124 object->n_ops++; 124 object->n_ops++;
125 object->n_exclusive++; /* reads and writes must wait */ 125 object->n_exclusive++; /* reads and writes must wait */
@@ -144,7 +144,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
144 */ 144 */
145static void fscache_report_unexpected_submission(struct fscache_object *object, 145static void fscache_report_unexpected_submission(struct fscache_object *object,
146 struct fscache_operation *op, 146 struct fscache_operation *op,
147 unsigned long ostate) 147 const struct fscache_state *ostate)
148{ 148{
149 static bool once_only; 149 static bool once_only;
150 struct fscache_operation *p; 150 struct fscache_operation *p;
@@ -155,11 +155,8 @@ static void fscache_report_unexpected_submission(struct fscache_object *object,
155 once_only = true; 155 once_only = true;
156 156
157 kdebug("unexpected submission OP%x [OBJ%x %s]", 157 kdebug("unexpected submission OP%x [OBJ%x %s]",
158 op->debug_id, object->debug_id, 158 op->debug_id, object->debug_id, object->state->name);
159 fscache_object_states[object->state]); 159 kdebug("objstate=%s [%s]", object->state->name, ostate->name);
160 kdebug("objstate=%s [%s]",
161 fscache_object_states[object->state],
162 fscache_object_states[ostate]);
163 kdebug("objflags=%lx", object->flags); 160 kdebug("objflags=%lx", object->flags);
164 kdebug("objevent=%lx [%lx]", object->events, object->event_mask); 161 kdebug("objevent=%lx [%lx]", object->events, object->event_mask);
165 kdebug("ops=%u inp=%u exc=%u", 162 kdebug("ops=%u inp=%u exc=%u",
@@ -190,7 +187,7 @@ static void fscache_report_unexpected_submission(struct fscache_object *object,
190int fscache_submit_op(struct fscache_object *object, 187int fscache_submit_op(struct fscache_object *object,
191 struct fscache_operation *op) 188 struct fscache_operation *op)
192{ 189{
193 unsigned long ostate; 190 const struct fscache_state *ostate;
194 int ret; 191 int ret;
195 192
196 _enter("{OBJ%x OP%x},{%u}", 193 _enter("{OBJ%x OP%x},{%u}",
@@ -226,16 +223,14 @@ int fscache_submit_op(struct fscache_object *object,
226 fscache_run_op(object, op); 223 fscache_run_op(object, op);
227 } 224 }
228 ret = 0; 225 ret = 0;
229 } else if (object->state == FSCACHE_OBJECT_CREATING) { 226 } else if (test_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)) {
230 op->object = object; 227 op->object = object;
231 object->n_ops++; 228 object->n_ops++;
232 atomic_inc(&op->usage); 229 atomic_inc(&op->usage);
233 list_add_tail(&op->pend_link, &object->pending_ops); 230 list_add_tail(&op->pend_link, &object->pending_ops);
234 fscache_stat(&fscache_n_op_pend); 231 fscache_stat(&fscache_n_op_pend);
235 ret = 0; 232 ret = 0;
236 } else if (object->state == FSCACHE_OBJECT_DYING || 233 } else if (fscache_object_is_dying(object)) {
237 object->state == FSCACHE_OBJECT_LC_DYING ||
238 object->state == FSCACHE_OBJECT_WITHDRAWING) {
239 fscache_stat(&fscache_n_op_rejected); 234 fscache_stat(&fscache_n_op_rejected);
240 op->state = FSCACHE_OP_ST_CANCELLED; 235 op->state = FSCACHE_OP_ST_CANCELLED;
241 ret = -ENOBUFS; 236 ret = -ENOBUFS;
@@ -266,13 +261,14 @@ void fscache_abort_object(struct fscache_object *object)
266 261
267/* 262/*
268 * jump start the operation processing on an object 263 * jump start the operation processing on an object
269 * - caller must hold object->lock
270 */ 264 */
271void fscache_start_operations(struct fscache_object *object) 265void fscache_start_operations(struct fscache_object *object)
272{ 266{
273 struct fscache_operation *op; 267 struct fscache_operation *op;
274 bool stop = false; 268 bool stop = false;
275 269
270 ASSERT(spin_is_locked(&object->lock));
271
276 while (!list_empty(&object->pending_ops) && !stop) { 272 while (!list_empty(&object->pending_ops) && !stop) {
277 op = list_entry(object->pending_ops.next, 273 op = list_entry(object->pending_ops.next,
278 struct fscache_operation, pend_link); 274 struct fscache_operation, pend_link);
diff --git a/fs/fscache/page.c b/fs/fscache/page.c
index 42f8f2d8a197..b4e4b424160a 100644
--- a/fs/fscache/page.c
+++ b/fs/fscache/page.c
@@ -408,7 +408,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
408 object = hlist_entry(cookie->backing_objects.first, 408 object = hlist_entry(cookie->backing_objects.first,
409 struct fscache_object, cookie_link); 409 struct fscache_object, cookie_link);
410 410
411 ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); 411 ASSERT(test_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags));
412 412
413 atomic_inc(&object->n_reads); 413 atomic_inc(&object->n_reads);
414 __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); 414 __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags);
@@ -729,8 +729,9 @@ static void fscache_write_op(struct fscache_operation *_op)
729 */ 729 */
730 spin_unlock(&object->lock); 730 spin_unlock(&object->lock);
731 fscache_op_complete(&op->op, false); 731 fscache_op_complete(&op->op, false);
732 _leave(" [cancel] op{f=%lx s=%u} obj{s=%u f=%lx}", 732 _leave(" [cancel] op{f=%lx s=%u} obj{s=%s f=%lx}",
733 _op->flags, _op->state, object->state, object->flags); 733 _op->flags, _op->state, object->state->short_name,
734 object->flags);
734 return; 735 return;
735 } 736 }
736 737
@@ -833,14 +834,12 @@ void fscache_invalidate_writes(struct fscache_cookie *cookie)
833 * (1) negative lookup, object not yet created (FSCACHE_COOKIE_CREATING is 834 * (1) negative lookup, object not yet created (FSCACHE_COOKIE_CREATING is
834 * set) 835 * set)
835 * 836 *
836 * (a) no writes yet (set FSCACHE_COOKIE_PENDING_FILL and queue deferred 837 * (a) no writes yet
837 * fill op)
838 * 838 *
839 * (b) writes deferred till post-creation (mark page for writing and 839 * (b) writes deferred till post-creation (mark page for writing and
840 * return immediately) 840 * return immediately)
841 * 841 *
842 * (2) negative lookup, object created, initial fill being made from netfs 842 * (2) negative lookup, object created, initial fill being made from netfs
843 * (FSCACHE_COOKIE_INITIAL_FILL is set)
844 * 843 *
845 * (a) fill point not yet reached this page (mark page for writing and 844 * (a) fill point not yet reached this page (mark page for writing and
846 * return) 845 * return)
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h
index c5f92347cbf8..9ff516b1b9a0 100644
--- a/include/linux/fscache-cache.h
+++ b/include/linux/fscache-cache.h
@@ -328,11 +328,9 @@ struct fscache_cookie {
328#define FSCACHE_COOKIE_LOOKING_UP 0 /* T if non-index cookie being looked up still */ 328#define FSCACHE_COOKIE_LOOKING_UP 0 /* T if non-index cookie being looked up still */
329#define FSCACHE_COOKIE_CREATING 1 /* T if non-index object being created still */ 329#define FSCACHE_COOKIE_CREATING 1 /* T if non-index object being created still */
330#define FSCACHE_COOKIE_NO_DATA_YET 2 /* T if new object with no cached data yet */ 330#define FSCACHE_COOKIE_NO_DATA_YET 2 /* T if new object with no cached data yet */
331#define FSCACHE_COOKIE_PENDING_FILL 3 /* T if pending initial fill on object */ 331#define FSCACHE_COOKIE_UNAVAILABLE 3 /* T if cookie is unavailable (error, etc) */
332#define FSCACHE_COOKIE_FILLING 4 /* T if filling object incrementally */ 332#define FSCACHE_COOKIE_WAITING_ON_READS 4 /* T if cookie is waiting on reads */
333#define FSCACHE_COOKIE_UNAVAILABLE 5 /* T if cookie is unavailable (error, etc) */ 333#define FSCACHE_COOKIE_INVALIDATING 5 /* T if cookie is being invalidated */
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 */
336}; 334};
337 335
338extern struct fscache_cookie fscache_fsdef_index; 336extern struct fscache_cookie fscache_fsdef_index;
@@ -341,45 +339,40 @@ extern struct fscache_cookie fscache_fsdef_index;
341 * Event list for fscache_object::{event_mask,events} 339 * Event list for fscache_object::{event_mask,events}
342 */ 340 */
343enum { 341enum {
344 FSCACHE_OBJECT_EV_REQUEUE, /* T if object should be requeued */ 342 FSCACHE_OBJECT_EV_NEW_CHILD, /* T if object has a new child */
343 FSCACHE_OBJECT_EV_PARENT_READY, /* T if object's parent is ready */
345 FSCACHE_OBJECT_EV_UPDATE, /* T if object should be updated */ 344 FSCACHE_OBJECT_EV_UPDATE, /* T if object should be updated */
346 FSCACHE_OBJECT_EV_INVALIDATE, /* T if cache requested object invalidation */ 345 FSCACHE_OBJECT_EV_INVALIDATE, /* T if cache requested object invalidation */
347 FSCACHE_OBJECT_EV_CLEARED, /* T if accessors all gone */ 346 FSCACHE_OBJECT_EV_CLEARED, /* T if accessors all gone */
348 FSCACHE_OBJECT_EV_ERROR, /* T if fatal error occurred during processing */ 347 FSCACHE_OBJECT_EV_ERROR, /* T if fatal error occurred during processing */
349 FSCACHE_OBJECT_EV_RELEASE, /* T if netfs requested object release */ 348 FSCACHE_OBJECT_EV_KILL, /* T if netfs relinquished or cache withdrew object */
350 FSCACHE_OBJECT_EV_RETIRE, /* T if netfs requested object retirement */
351 FSCACHE_OBJECT_EV_WITHDRAW, /* T if cache requested object withdrawal */
352 NR_FSCACHE_OBJECT_EVENTS 349 NR_FSCACHE_OBJECT_EVENTS
353}; 350};
354 351
355#define FSCACHE_OBJECT_EVENTS_MASK ((1UL << NR_FSCACHE_OBJECT_EVENTS) - 1) 352#define FSCACHE_OBJECT_EVENTS_MASK ((1UL << NR_FSCACHE_OBJECT_EVENTS) - 1)
356 353
357/* 354/*
355 * States for object state machine.
356 */
357struct fscache_transition {
358 unsigned long events;
359 const struct fscache_state *transit_to;
360};
361
362struct fscache_state {
363 char name[24];
364 char short_name[8];
365 const struct fscache_state *(*work)(struct fscache_object *object,
366 int event);
367 const struct fscache_transition transitions[];
368};
369
370/*
358 * on-disk cache file or index handle 371 * on-disk cache file or index handle
359 */ 372 */
360struct fscache_object { 373struct fscache_object {
361 enum fscache_object_state { 374 const struct fscache_state *state; /* Object state machine state */
362 FSCACHE_OBJECT_INIT, /* object in initial unbound state */ 375 const struct fscache_transition *oob_table; /* OOB state transition table */
363 FSCACHE_OBJECT_LOOKING_UP, /* looking up object */
364 FSCACHE_OBJECT_CREATING, /* creating object */
365
366 /* active states */
367 FSCACHE_OBJECT_AVAILABLE, /* cleaning up object after creation */
368 FSCACHE_OBJECT_ACTIVE, /* object is usable */
369 FSCACHE_OBJECT_INVALIDATING, /* object is invalidating */
370 FSCACHE_OBJECT_UPDATING, /* object is updating */
371
372 /* terminal states */
373 FSCACHE_OBJECT_DYING, /* object waiting for accessors to finish */
374 FSCACHE_OBJECT_LC_DYING, /* object cleaning up after lookup/create */
375 FSCACHE_OBJECT_ABORT_INIT, /* abort the init state */
376 FSCACHE_OBJECT_RELEASING, /* releasing object */
377 FSCACHE_OBJECT_RECYCLING, /* retiring object */
378 FSCACHE_OBJECT_WITHDRAWING, /* withdrawing object */
379 FSCACHE_OBJECT_DEAD, /* object is now dead */
380 FSCACHE_OBJECT__NSTATES
381 } state;
382
383 int debug_id; /* debugging ID */ 376 int debug_id; /* debugging ID */
384 int n_children; /* number of child objects */ 377 int n_children; /* number of child objects */
385 int n_ops; /* number of extant ops on object */ 378 int n_ops; /* number of extant ops on object */
@@ -390,6 +383,7 @@ struct fscache_object {
390 spinlock_t lock; /* state and operations lock */ 383 spinlock_t lock; /* state and operations lock */
391 384
392 unsigned long lookup_jif; /* time at which lookup started */ 385 unsigned long lookup_jif; /* time at which lookup started */
386 unsigned long oob_event_mask; /* OOB events this object is interested in */
393 unsigned long event_mask; /* events this object is interested in */ 387 unsigned long event_mask; /* events this object is interested in */
394 unsigned long events; /* events to be processed by this object 388 unsigned long events; /* events to be processed by this object
395 * (order is important - using fls) */ 389 * (order is important - using fls) */
@@ -398,6 +392,10 @@ struct fscache_object {
398#define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */ 392#define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */
399#define FSCACHE_OBJECT_PENDING_WRITE 1 /* T if object has pending write */ 393#define FSCACHE_OBJECT_PENDING_WRITE 1 /* T if object has pending write */
400#define FSCACHE_OBJECT_WAITING 2 /* T if object is waiting on its parent */ 394#define FSCACHE_OBJECT_WAITING 2 /* T if object is waiting on its parent */
395#define FSCACHE_OBJECT_RETIRE 3 /* T if object should be retired */
396#define FSCACHE_OBJECT_IS_LIVE 4 /* T if object is not withdrawn or relinquished */
397#define FSCACHE_OBJECT_IS_LOOKED_UP 5 /* T if object has been looked up */
398#define FSCACHE_OBJECT_IS_AVAILABLE 6 /* T if object has become active */
401 399
402 struct list_head cache_link; /* link in cache->object_list */ 400 struct list_head cache_link; /* link in cache->object_list */
403 struct hlist_node cookie_link; /* link in cookie->backing_objects */ 401 struct hlist_node cookie_link; /* link in cookie->backing_objects */
@@ -415,8 +413,6 @@ struct fscache_object {
415 loff_t store_limit_l; /* current storage limit */ 413 loff_t store_limit_l; /* current storage limit */
416}; 414};
417 415
418extern const char *fscache_object_states[];
419
420extern void fscache_object_init(struct fscache_object *, struct fscache_cookie *, 416extern void fscache_object_init(struct fscache_object *, struct fscache_cookie *,
421 struct fscache_cache *); 417 struct fscache_cache *);
422 418
@@ -431,7 +427,7 @@ extern void fscache_object_destroy(struct fscache_object *object);
431 427
432static inline bool fscache_object_is_live(struct fscache_object *object) 428static inline bool fscache_object_is_live(struct fscache_object *object)
433{ 429{
434 return object->state < FSCACHE_OBJECT_DYING; 430 return test_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags);
435} 431}
436 432
437static inline bool fscache_object_is_dying(struct fscache_object *object) 433static inline bool fscache_object_is_dying(struct fscache_object *object)
@@ -441,7 +437,7 @@ static inline bool fscache_object_is_dying(struct fscache_object *object)
441 437
442static inline bool fscache_object_is_available(struct fscache_object *object) 438static inline bool fscache_object_is_available(struct fscache_object *object)
443{ 439{
444 return object->state >= FSCACHE_OBJECT_AVAILABLE; 440 return test_bit(FSCACHE_OBJECT_IS_AVAILABLE, &object->flags);
445} 441}
446 442
447static inline bool fscache_object_is_active(struct fscache_object *object) 443static inline bool fscache_object_is_active(struct fscache_object *object)