diff options
Diffstat (limited to 'fs/fscache/object.c')
-rw-r--r-- | fs/fscache/object.c | 188 |
1 files changed, 75 insertions, 113 deletions
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 8f17debd7979..86d75a60b20c 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -30,7 +30,6 @@ static const struct fscache_state *fscache_look_up_object(struct fscache_object static const struct fscache_state *fscache_object_available(struct fscache_object *, int); static const struct fscache_state *fscache_parent_ready(struct fscache_object *, int); static const struct fscache_state *fscache_update_object(struct fscache_object *, int); -static const struct fscache_state *fscache_detach_from_cookie(struct fscache_object *, int); #define __STATE_NAME(n) fscache_osm_##n #define STATE(n) (&__STATE_NAME(n)) @@ -92,7 +91,6 @@ static WORK_STATE(LOOKUP_FAILURE, "LCFL", fscache_lookup_failure); static WORK_STATE(KILL_OBJECT, "KILL", fscache_kill_object); static WORK_STATE(KILL_DEPENDENTS, "KDEP", fscache_kill_dependents); static WORK_STATE(DROP_OBJECT, "DROP", fscache_drop_object); -static WORK_STATE(DETACH_FROM_COOKIE, "DTCH", fscache_detach_from_cookie); static WORK_STATE(OBJECT_DEAD, "DEAD", (void*)2UL); static WAIT_STATE(WAIT_FOR_INIT, "?INI", @@ -156,8 +154,8 @@ static inline void fscache_done_parent_op(struct fscache_object *object) object->debug_id, parent->debug_id, parent->n_ops); spin_lock_nested(&parent->lock, 1); - parent->n_ops--; parent->n_obj_ops--; + parent->n_ops--; if (parent->n_ops == 0) fscache_raise_event(parent, FSCACHE_OBJECT_EV_CLEARED); spin_unlock(&parent->lock); @@ -332,22 +330,10 @@ EXPORT_SYMBOL(fscache_object_init); static const struct fscache_state *fscache_abort_initialisation(struct fscache_object *object, int event) { - struct fscache_cookie *cookie; - _enter("{OBJ%x},%d", object->debug_id, event); object->oob_event_mask = 0; - clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); - fscache_dequeue_object(object); - - spin_lock(&object->lock); - cookie = object->cookie; - clear_bit_unlock(FSCACHE_COOKIE_CREATING, &cookie->flags); - spin_unlock(&object->lock); - - wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING); - return transit_to(KILL_OBJECT); } @@ -357,8 +343,6 @@ static const struct fscache_state *fscache_abort_initialisation(struct fscache_o * immediately to do a creation * - we may need to start the process of creating a parent and we need to wait * for the parent's lookup and creation to complete if it's not there yet - * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the - * leaf-most cookies of the object and all its children */ static const struct fscache_state *fscache_initialise_object(struct fscache_object *object, int event) @@ -373,14 +357,14 @@ static const struct fscache_state *fscache_initialise_object(struct fscache_obje parent = object->parent; if (!parent) { _leave(" [no parent]"); - return transit_to(DETACH_FROM_COOKIE); + return transit_to(DROP_OBJECT); } - _debug("parent %s", parent->state->name); + _debug("parent: %s of:%lx", parent->state->name, parent->flags); if (fscache_object_is_dying(parent)) { _leave(" [bad parent]"); - return transit_to(DETACH_FROM_COOKIE); + return transit_to(DROP_OBJECT); } if (fscache_object_is_available(parent)) { @@ -402,7 +386,7 @@ static const struct fscache_state *fscache_initialise_object(struct fscache_obje spin_unlock(&parent->lock); if (!success) { _leave(" [grab failed]"); - return transit_to(DETACH_FROM_COOKIE); + return transit_to(DROP_OBJECT); } /* fscache_acquire_non_index_cookie() uses this @@ -438,8 +422,6 @@ static const struct fscache_state *fscache_parent_ready(struct fscache_object *o * look an object up in the cache from which it was allocated * - we hold an "access lock" on the parent object, so the parent object cannot * be withdrawn by either party till we've finished - * - an object's cookie is pinned until we clear FSCACHE_COOKIE_CREATING on the - * leaf-most cookies of the object and all its children */ static const struct fscache_state *fscache_look_up_object(struct fscache_object *object, int event) @@ -460,22 +442,21 @@ static const struct fscache_state *fscache_look_up_object(struct fscache_object ASSERT(fscache_object_is_available(parent)); if (fscache_object_is_dying(parent) || - test_bit(FSCACHE_IOERROR, &object->cache->flags)) { + test_bit(FSCACHE_IOERROR, &object->cache->flags) || + !fscache_use_cookie(object)) { _leave(" [unavailable]"); return transit_to(LOOKUP_FAILURE); } - _debug("LOOKUP \"%s/%s\" in \"%s\"", - parent->cookie->def->name, cookie->def->name, - object->cache->tag->name); + _debug("LOOKUP \"%s\" in \"%s\"", + cookie->def->name, object->cache->tag->name); fscache_stat(&fscache_n_object_lookups); fscache_stat(&fscache_n_cop_lookup_object); ret = object->cache->ops->lookup_object(object); fscache_stat_d(&fscache_n_cop_lookup_object); - if (test_bit(FSCACHE_OBJECT_EV_ERROR, &object->events)) - set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); + fscache_unuse_cookie(object); if (ret == -ETIMEDOUT) { /* probably stuck behind another object, so move this one to @@ -557,11 +538,6 @@ void fscache_obtained_object(struct fscache_object *object) } set_bit(FSCACHE_OBJECT_IS_AVAILABLE, &object->flags); - - /* Permit __fscache_relinquish_cookie() to proceed */ - clear_bit_unlock(FSCACHE_COOKIE_CREATING, &cookie->flags); - wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING); - _leave(""); } EXPORT_SYMBOL(fscache_obtained_object); @@ -572,16 +548,12 @@ EXPORT_SYMBOL(fscache_obtained_object); static const struct fscache_state *fscache_object_available(struct fscache_object *object, int event) { - struct fscache_cookie *cookie = object->cookie; - _enter("{OBJ%x},%d", object->debug_id, event); object->oob_table = fscache_osm_run_oob; spin_lock(&object->lock); - ASSERTIF(cookie, !test_bit(FSCACHE_COOKIE_CREATING, &object->cookie->flags)); - fscache_done_parent_op(object); if (object->n_in_progress == 0) { if (object->n_ops > 0) { @@ -624,7 +596,6 @@ static const struct fscache_state *fscache_lookup_failure(struct fscache_object int event) { struct fscache_cookie *cookie; - bool wake_looking_up = false; _enter("{OBJ%x},%d", object->debug_id, event); @@ -634,19 +605,10 @@ static const struct fscache_state *fscache_lookup_failure(struct fscache_object object->cache->ops->lookup_complete(object); fscache_stat_d(&fscache_n_cop_lookup_complete); - spin_lock(&object->lock); cookie = object->cookie; set_bit(FSCACHE_COOKIE_UNAVAILABLE, &cookie->flags); - if (cookie) { - if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags)) - wake_looking_up = true; - clear_bit_unlock(FSCACHE_COOKIE_CREATING, &cookie->flags); - } - spin_unlock(&object->lock); - - if (wake_looking_up) + if (test_and_clear_bit(FSCACHE_COOKIE_LOOKING_UP, &cookie->flags)) wake_up_bit(&cookie->flags, FSCACHE_COOKIE_LOOKING_UP); - wake_up_bit(&cookie->flags, FSCACHE_COOKIE_CREATING); fscache_done_parent_op(object); return transit_to(KILL_OBJECT); @@ -662,21 +624,20 @@ static const struct fscache_state *fscache_kill_object(struct fscache_object *ob _enter("{OBJ%x,%d,%d},%d", object->debug_id, object->n_ops, object->n_children, event); - object->oob_event_mask = 0; - - spin_lock(&object->lock); clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); - spin_unlock(&object->lock); + object->oob_event_mask = 0; if (list_empty(&object->dependents) && object->n_ops == 0 && object->n_children == 0) - return object->cookie ? - transit_to(DETACH_FROM_COOKIE) : transit_to(DROP_OBJECT); + return transit_to(DROP_OBJECT); - spin_lock(&object->lock); - fscache_start_operations(object); - spin_unlock(&object->lock); + if (object->n_in_progress == 0) { + spin_lock(&object->lock); + if (object->n_ops > 0 && object->n_in_progress == 0) + fscache_start_operations(object); + spin_unlock(&object->lock); + } if (!list_empty(&object->dependents)) return transit_to(KILL_DEPENDENTS); @@ -698,64 +659,32 @@ static const struct fscache_state *fscache_kill_dependents(struct fscache_object } /* - * withdraw an object from active service - */ -static const struct fscache_state *fscache_detach_from_cookie(struct fscache_object *object, - int event) -{ - struct fscache_cookie *cookie; - bool detached = false, awaken = false; - - _enter("{OBJ%x},%d", object->debug_id, event); - - spin_lock(&object->lock); - cookie = object->cookie; - if (cookie) { - /* need to get the cookie lock before the object lock, starting - * from the object pointer */ - atomic_inc(&cookie->usage); - spin_unlock(&object->lock); - - spin_lock(&cookie->lock); - spin_lock(&object->lock); - - if (object->cookie == cookie) { - hlist_del_init(&object->cookie_link); - object->cookie = NULL; - if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, - &cookie->flags)) - awaken = true; - detached = true; - } - spin_unlock(&cookie->lock); - fscache_cookie_put(cookie); - if (detached) - fscache_cookie_put(cookie); - } - - spin_unlock(&object->lock); - - if (awaken) - wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); - - fscache_stat(&fscache_n_object_dead); - _leave(""); - return transit_to(DROP_OBJECT); -} - -/* * Drop an object's attachments */ static const struct fscache_state *fscache_drop_object(struct fscache_object *object, int event) { struct fscache_object *parent = object->parent; + struct fscache_cookie *cookie = object->cookie; struct fscache_cache *cache = object->cache; + bool awaken = false; _enter("{OBJ%x,%d},%d", object->debug_id, object->n_children, event); - ASSERTCMP(object->cookie, ==, NULL); - ASSERT(hlist_unhashed(&object->cookie_link)); + ASSERT(cookie != NULL); + ASSERT(!hlist_unhashed(&object->cookie_link)); + + /* Make sure the cookie no longer points here and that the netfs isn't + * waiting for us. + */ + spin_lock(&cookie->lock); + hlist_del_init(&object->cookie_link); + if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) + awaken = true; + spin_unlock(&cookie->lock); + + if (awaken) + wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); /* Prevent a race with our last child, which has to signal EV_CLEARED * before dropping our spinlock. @@ -816,6 +745,22 @@ static void fscache_put_object(struct fscache_object *object) fscache_stat_d(&fscache_n_cop_put_object); } +/** + * fscache_object_destroy - Note that a cache object is about to be destroyed + * @object: The object to be destroyed + * + * Note the imminent destruction and deallocation of a cache object record. + */ +void fscache_object_destroy(struct fscache_object *object) +{ + fscache_objlist_remove(object); + + /* We can get rid of the cookie now */ + fscache_cookie_put(object->cookie); + object->cookie = NULL; +} +EXPORT_SYMBOL(fscache_object_destroy); + /* * enqueue an object for metadata-type processing */ @@ -925,7 +870,10 @@ static void fscache_dequeue_object(struct fscache_object *object) * @data: The auxiliary data for the object * @datalen: The size of the auxiliary data * - * This function consults the netfs about the coherency state of an object + * This function consults the netfs about the coherency state of an object. + * The caller must be holding a ref on cookie->n_active (held by + * fscache_look_up_object() on behalf of the cache backend during object lookup + * and creation). */ enum fscache_checkaux fscache_check_aux(struct fscache_object *object, const void *data, uint16_t datalen) @@ -974,6 +922,15 @@ static const struct fscache_state *_fscache_invalidate_object(struct fscache_obj _enter("{OBJ%x},%d", object->debug_id, event); + /* We're going to need the cookie. If the cookie is not available then + * retire the object instead. + */ + if (!fscache_use_cookie(object)) { + ASSERT(object->cookie->stores.rnode == NULL); + set_bit(FSCACHE_COOKIE_RETIRED, &cookie->flags); + _leave(" [no cookie]"); + return transit_to(KILL_OBJECT); + } /* Reject any new read/write ops and abort any that are pending. */ fscache_invalidate_writes(cookie); @@ -982,14 +939,13 @@ static const struct fscache_state *_fscache_invalidate_object(struct fscache_obj /* Now we have to wait for in-progress reads and writes */ op = kzalloc(sizeof(*op), GFP_KERNEL); - if (!op) { - clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); - _leave(" [ENOMEM]"); - return transit_to(KILL_OBJECT); - } + if (!op) + goto nomem; fscache_operation_init(op, object->cache->ops->invalidate_object, NULL); - op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE); + op->flags = FSCACHE_OP_ASYNC | + (1 << FSCACHE_OP_EXCLUSIVE) | + (1 << FSCACHE_OP_UNUSE_COOKIE); spin_lock(&cookie->lock); if (fscache_submit_exclusive_op(object, op) < 0) @@ -1011,6 +967,12 @@ static const struct fscache_state *_fscache_invalidate_object(struct fscache_obj _leave(" [ok]"); return transit_to(UPDATE_OBJECT); +nomem: + clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); + fscache_unuse_cookie(object); + _leave(" [ENOMEM]"); + return transit_to(KILL_OBJECT); + submit_op_failed: clear_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); spin_unlock(&cookie->lock); |