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

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>

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