diff options
Diffstat (limited to 'fs/fscache')
-rw-r--r-- | fs/fscache/cache.c | 2 | ||||
-rw-r--r-- | fs/fscache/cookie.c | 88 | ||||
-rw-r--r-- | fs/fscache/fsdef.c | 49 | ||||
-rw-r--r-- | fs/fscache/internal.h | 21 | ||||
-rw-r--r-- | fs/fscache/netfs.c | 17 | ||||
-rw-r--r-- | fs/fscache/object-list.c | 28 | ||||
-rw-r--r-- | fs/fscache/object.c | 22 | ||||
-rw-r--r-- | fs/fscache/operation.c | 2 |
8 files changed, 140 insertions, 89 deletions
diff --git a/fs/fscache/cache.c b/fs/fscache/cache.c index 56cce7fdd39e..c184c5a356ff 100644 --- a/fs/fscache/cache.c +++ b/fs/fscache/cache.c @@ -125,7 +125,7 @@ struct fscache_cache *fscache_select_cache_for_object( } /* the parent is unbacked */ - if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { + if (cookie->type != FSCACHE_COOKIE_TYPE_INDEX) { /* cookie not an index and is unbacked */ spin_unlock(&cookie->lock); _leave(" = NULL [cookie ub,ni]"); diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index ea1f80daaff4..4d6210082a60 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c @@ -58,6 +58,8 @@ void fscache_cookie_init_once(void *_cookie) struct fscache_cookie *__fscache_acquire_cookie( struct fscache_cookie *parent, const struct fscache_cookie_def *def, + const void *index_key, size_t index_key_len, + const void *aux_data, size_t aux_data_len, void *netfs_data, bool enable) { @@ -69,6 +71,13 @@ struct fscache_cookie *__fscache_acquire_cookie( parent ? (char *) parent->def->name : "<no-parent>", def->name, netfs_data, enable); + if (!index_key || !index_key_len || index_key_len > 255 || aux_data_len > 255) + return NULL; + if (!aux_data || !aux_data_len) { + aux_data = NULL; + aux_data_len = 0; + } + fscache_stat(&fscache_n_acquires); /* if there's no parent cookie, then we don't create one here either */ @@ -79,11 +88,10 @@ struct fscache_cookie *__fscache_acquire_cookie( } /* validate the definition */ - BUG_ON(!def->get_key); BUG_ON(!def->name[0]); BUG_ON(def->type == FSCACHE_COOKIE_TYPE_INDEX && - parent->def->type != FSCACHE_COOKIE_TYPE_INDEX); + parent->type != FSCACHE_COOKIE_TYPE_INDEX); /* allocate and initialise a cookie */ cookie = kmem_cache_alloc(fscache_cookie_jar, GFP_KERNEL); @@ -93,6 +101,25 @@ struct fscache_cookie *__fscache_acquire_cookie( return NULL; } + cookie->key_len = index_key_len; + cookie->aux_len = aux_data_len; + + if (cookie->key_len <= sizeof(cookie->inline_key)) { + memcpy(cookie->inline_key, index_key, cookie->key_len); + } else { + cookie->key = kmemdup(index_key, cookie->key_len, GFP_KERNEL); + if (!cookie->key) + goto nomem; + } + + if (cookie->aux_len <= sizeof(cookie->inline_aux)) { + memcpy(cookie->inline_aux, aux_data, cookie->aux_len); + } else { + cookie->aux = kmemdup(aux_data, cookie->aux_len, GFP_KERNEL); + if (!cookie->aux) + goto nomem; + } + atomic_set(&cookie->usage, 1); atomic_set(&cookie->n_children, 0); @@ -108,12 +135,13 @@ struct fscache_cookie *__fscache_acquire_cookie( cookie->parent = parent; cookie->netfs_data = netfs_data; cookie->flags = (1 << FSCACHE_COOKIE_NO_DATA_YET); - + cookie->type = def->type; + /* radix tree insertion won't use the preallocation pool unless it's * told it may not wait */ INIT_RADIX_TREE(&cookie->stores, GFP_NOFS & ~__GFP_DIRECT_RECLAIM); - switch (cookie->def->type) { + switch (cookie->type) { case FSCACHE_COOKIE_TYPE_INDEX: fscache_stat(&fscache_n_cookie_index); break; @@ -131,7 +159,7 @@ struct fscache_cookie *__fscache_acquire_cookie( /* if the object is an index then we need do nothing more here * - we create indices on disk when we need them as an index * may exist in multiple caches */ - if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { + if (cookie->type != FSCACHE_COOKIE_TYPE_INDEX) { if (fscache_acquire_non_index_cookie(cookie) == 0) { set_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); } else { @@ -150,6 +178,14 @@ struct fscache_cookie *__fscache_acquire_cookie( fscache_stat(&fscache_n_acquires_ok); _leave(" = %p", cookie); return cookie; + +nomem: + if (cookie->aux_len > sizeof(cookie->inline_aux)) + kfree(cookie->aux); + if (cookie->key_len > sizeof(cookie->inline_key)) + kfree(cookie->key); + kmem_cache_free(fscache_cookie_jar, cookie); + return NULL; } EXPORT_SYMBOL(__fscache_acquire_cookie); @@ -157,6 +193,7 @@ EXPORT_SYMBOL(__fscache_acquire_cookie); * Enable a cookie to permit it to accept new operations. */ void __fscache_enable_cookie(struct fscache_cookie *cookie, + const void *aux_data, bool (*can_enable)(void *data), void *data) { @@ -167,12 +204,14 @@ void __fscache_enable_cookie(struct fscache_cookie *cookie, wait_on_bit_lock(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK, TASK_UNINTERRUPTIBLE); + fscache_update_aux(cookie, aux_data); + if (test_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags)) goto out_unlock; if (can_enable && !can_enable(data)) { /* The netfs decided it didn't want to enable after all */ - } else if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) { + } else if (cookie->type != FSCACHE_COOKIE_TYPE_INDEX) { /* Wait for outstanding disablement to complete */ __fscache_wait_on_invalidate(cookie); @@ -431,10 +470,7 @@ void __fscache_invalidate(struct fscache_cookie *cookie) * there, and if it's doing that, it may as well just retire the * cookie. */ - ASSERTCMP(cookie->def->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE); - - /* We will be updating the cookie too. */ - BUG_ON(!cookie->def->get_aux); + ASSERTCMP(cookie->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE); /* If there's an object, we tell the object state machine to handle the * invalidation on our behalf, otherwise there's nothing to do. @@ -478,7 +514,7 @@ EXPORT_SYMBOL(__fscache_wait_on_invalidate); /* * update the index entries backing a cookie */ -void __fscache_update_cookie(struct fscache_cookie *cookie) +void __fscache_update_cookie(struct fscache_cookie *cookie, const void *aux_data) { struct fscache_object *object; @@ -492,10 +528,10 @@ void __fscache_update_cookie(struct fscache_cookie *cookie) _enter("{%s}", cookie->def->name); - BUG_ON(!cookie->def->get_aux); - spin_lock(&cookie->lock); + fscache_update_aux(cookie, aux_data); + if (fscache_cookie_enabled(cookie)) { /* update the index entry on disk in each cache backing this * cookie. @@ -514,7 +550,9 @@ EXPORT_SYMBOL(__fscache_update_cookie); /* * Disable a cookie to stop it from accepting new requests from the netfs. */ -void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) +void __fscache_disable_cookie(struct fscache_cookie *cookie, + const void *aux_data, + bool invalidate) { struct fscache_object *object; bool awaken = false; @@ -533,6 +571,9 @@ void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) wait_on_bit_lock(&cookie->flags, FSCACHE_COOKIE_ENABLEMENT_LOCK, TASK_UNINTERRUPTIBLE); + + fscache_update_aux(cookie, aux_data); + if (!test_and_clear_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags)) goto out_unlock_enable; @@ -570,7 +611,7 @@ void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) } /* Make sure any pending writes are cancelled. */ - if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX) + if (cookie->type != FSCACHE_COOKIE_TYPE_INDEX) fscache_invalidate_writes(cookie); /* Reset the cookie state if it wasn't relinquished */ @@ -592,7 +633,9 @@ EXPORT_SYMBOL(__fscache_disable_cookie); * - all dependents of this cookie must have already been unregistered * (indices/files/pages) */ -void __fscache_relinquish_cookie(struct fscache_cookie *cookie, bool retire) +void __fscache_relinquish_cookie(struct fscache_cookie *cookie, + const void *aux_data, + bool retire) { fscache_stat(&fscache_n_relinquishes); if (retire) @@ -614,7 +657,7 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, bool retire) if (test_and_set_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) BUG(); - __fscache_disable_cookie(cookie, retire); + __fscache_disable_cookie(cookie, aux_data, retire); /* Clear pointers back to the netfs */ cookie->netfs_data = NULL; @@ -656,6 +699,10 @@ void fscache_cookie_put(struct fscache_cookie *cookie, parent = cookie->parent; BUG_ON(!hlist_empty(&cookie->backing_objects)); + if (cookie->aux_len > sizeof(cookie->inline_aux)) + kfree(cookie->aux); + if (cookie->key_len > sizeof(cookie->inline_key)) + kfree(cookie->key); kmem_cache_free(fscache_cookie_jar, cookie); cookie = parent; @@ -670,7 +717,8 @@ void fscache_cookie_put(struct fscache_cookie *cookie, * * NOTE: it only serves no-index type */ -int __fscache_check_consistency(struct fscache_cookie *cookie) +int __fscache_check_consistency(struct fscache_cookie *cookie, + const void *aux_data) { struct fscache_operation *op; struct fscache_object *object; @@ -679,7 +727,7 @@ int __fscache_check_consistency(struct fscache_cookie *cookie) _enter("%p,", cookie); - ASSERTCMP(cookie->def->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE); + ASSERTCMP(cookie->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE); if (fscache_wait_for_deferred_lookup(cookie) < 0) return -ERESTARTSYS; @@ -699,6 +747,8 @@ int __fscache_check_consistency(struct fscache_cookie *cookie) spin_lock(&cookie->lock); + fscache_update_aux(cookie, aux_data); + if (!fscache_cookie_enabled(cookie) || hlist_empty(&cookie->backing_objects)) goto inconsistent; diff --git a/fs/fscache/fsdef.c b/fs/fscache/fsdef.c index 5a117df2a9ef..1122e97d56e8 100644 --- a/fs/fscache/fsdef.c +++ b/fs/fscache/fsdef.c @@ -13,12 +13,6 @@ #include <linux/module.h> #include "internal.h" -static uint16_t fscache_fsdef_netfs_get_key(const void *cookie_netfs_data, - void *buffer, uint16_t bufmax); - -static uint16_t fscache_fsdef_netfs_get_aux(const void *cookie_netfs_data, - void *buffer, uint16_t bufmax); - static enum fscache_checkaux fscache_fsdef_netfs_check_aux(void *cookie_netfs_data, const void *data, @@ -60,6 +54,7 @@ struct fscache_cookie fscache_fsdef_index = { .backing_objects = HLIST_HEAD_INIT, .def = &fscache_fsdef_index_def, .flags = 1 << FSCACHE_COOKIE_ENABLED, + .type = FSCACHE_COOKIE_TYPE_INDEX, }; EXPORT_SYMBOL(fscache_fsdef_index); @@ -71,52 +66,10 @@ EXPORT_SYMBOL(fscache_fsdef_index); struct fscache_cookie_def fscache_fsdef_netfs_def = { .name = "FSDEF.netfs", .type = FSCACHE_COOKIE_TYPE_INDEX, - .get_key = fscache_fsdef_netfs_get_key, - .get_aux = fscache_fsdef_netfs_get_aux, .check_aux = fscache_fsdef_netfs_check_aux, }; /* - * get the key data for an FSDEF index record - this is the name of the netfs - * for which this entry is created - */ -static uint16_t fscache_fsdef_netfs_get_key(const void *cookie_netfs_data, - void *buffer, uint16_t bufmax) -{ - const struct fscache_netfs *netfs = cookie_netfs_data; - unsigned klen; - - _enter("{%s.%u},", netfs->name, netfs->version); - - klen = strlen(netfs->name); - if (klen > bufmax) - return 0; - - memcpy(buffer, netfs->name, klen); - return klen; -} - -/* - * get the auxiliary data for an FSDEF index record - this is the index - * structure version number of the netfs for which this version is created - */ -static uint16_t fscache_fsdef_netfs_get_aux(const void *cookie_netfs_data, - void *buffer, uint16_t bufmax) -{ - const struct fscache_netfs *netfs = cookie_netfs_data; - unsigned dlen; - - _enter("{%s.%u},", netfs->name, netfs->version); - - dlen = sizeof(uint32_t); - if (dlen > bufmax) - return 0; - - memcpy(buffer, &netfs->version, dlen); - return dlen; -} - -/* * check that the index structure version number stored in the auxiliary data * matches the one the netfs gave us */ diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index c27e2db3004e..5f905a499306 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h @@ -342,6 +342,27 @@ void fscache_put_context(struct fscache_cookie *cookie, void *context) cookie->def->put_context(cookie->netfs_data, context); } +/* + * Update the auxiliary data on a cookie. + */ +static inline +void fscache_update_aux(struct fscache_cookie *cookie, const void *aux_data) +{ + void *p; + + if (!aux_data) + return; + if (cookie->aux_len <= sizeof(cookie->inline_aux)) + p = cookie->inline_aux; + else + p = cookie->aux; + + if (memcmp(p, aux_data, cookie->aux_len) != 0) { + memcpy(p, aux_data, cookie->aux_len); + set_bit(FSCACHE_COOKIE_AUX_UPDATED, &cookie->flags); + } +} + /*****************************************************************************/ /* * debug tracing diff --git a/fs/fscache/netfs.c b/fs/fscache/netfs.c index c816600d1dde..a5998dfab7e7 100644 --- a/fs/fscache/netfs.c +++ b/fs/fscache/netfs.c @@ -37,6 +37,19 @@ int __fscache_register_netfs(struct fscache_netfs *netfs) return -ENOMEM; } + cookie->key_len = strlen(netfs->name); + if (cookie->key_len <= sizeof(cookie->inline_key)) { + memcpy(cookie->inline_key, netfs->name, strlen(netfs->name)); + } else { + ret = -ENOMEM; + cookie->key = kmemdup(netfs->name, cookie->key_len, GFP_KERNEL); + if (!cookie->key) + goto nomem; + } + + cookie->aux_len = sizeof(netfs->version); + memcpy(cookie->inline_aux, &netfs->version, cookie->aux_len); + /* initialise the primary index cookie */ atomic_set(&cookie->usage, 1); atomic_set(&cookie->n_children, 0); @@ -46,6 +59,7 @@ int __fscache_register_netfs(struct fscache_netfs *netfs) cookie->parent = &fscache_fsdef_index; cookie->netfs_data = netfs; cookie->flags = 1 << FSCACHE_COOKIE_ENABLED; + cookie->type = FSCACHE_COOKIE_TYPE_INDEX; spin_lock_init(&cookie->lock); spin_lock_init(&cookie->stores_lock); @@ -73,6 +87,7 @@ int __fscache_register_netfs(struct fscache_netfs *netfs) already_registered: up_write(&fscache_addremove_sem); +nomem: if (ret < 0) kmem_cache_free(fscache_cookie_jar, cookie); @@ -92,7 +107,7 @@ void __fscache_unregister_netfs(struct fscache_netfs *netfs) down_write(&fscache_addremove_sem); list_del(&netfs->link); - fscache_relinquish_cookie(netfs->primary_index, 0); + fscache_relinquish_cookie(netfs->primary_index, NULL, false); up_write(&fscache_addremove_sem); diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c index 0438d4cd91ef..43e6e28c164f 100644 --- a/fs/fscache/object-list.c +++ b/fs/fscache/object-list.c @@ -36,8 +36,6 @@ struct fscache_objlist_data { #define FSCACHE_OBJLIST_CONFIG_NOEVENTS 0x00000800 /* show objects without no events */ #define FSCACHE_OBJLIST_CONFIG_WORK 0x00001000 /* show objects with work */ #define FSCACHE_OBJLIST_CONFIG_NOWORK 0x00002000 /* show objects without work */ - - u8 buf[512]; /* key and aux data buffer */ }; /* @@ -170,7 +168,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v) struct fscache_cookie *cookie; unsigned long config = data->config; char _type[3], *type; - u8 *buf = data->buf, *p; + u8 *p; if ((unsigned long) v == 1) { seq_puts(m, "OBJECT PARENT STAT CHLDN OPS OOP IPR EX READS" @@ -254,7 +252,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v) if (fscache_use_cookie(obj)) { uint16_t keylen = 0, auxlen = 0; - switch (cookie->def->type) { + switch (cookie->type) { case 0: type = "IX"; break; @@ -263,7 +261,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v) break; default: snprintf(_type, sizeof(_type), "%02u", - cookie->def->type); + cookie->type); type = _type; break; } @@ -274,30 +272,30 @@ static int fscache_objlist_show(struct seq_file *m, void *v) cookie->flags, cookie->netfs_data); - if (cookie->def->get_key && - config & FSCACHE_OBJLIST_CONFIG_KEY) - keylen = cookie->def->get_key(cookie->netfs_data, - buf, 400); + if (config & FSCACHE_OBJLIST_CONFIG_KEY) + keylen = cookie->key_len; - if (cookie->def->get_aux && - config & FSCACHE_OBJLIST_CONFIG_AUX) - auxlen = cookie->def->get_aux(cookie->netfs_data, - buf + keylen, 512 - keylen); - fscache_unuse_cookie(obj); + if (config & FSCACHE_OBJLIST_CONFIG_AUX) + auxlen = cookie->aux_len; if (keylen > 0 || auxlen > 0) { seq_puts(m, " "); - for (p = buf; keylen > 0; keylen--) + p = keylen <= sizeof(cookie->inline_key) ? + cookie->inline_key : cookie->key; + for (; keylen > 0; keylen--) seq_printf(m, "%02x", *p++); if (auxlen > 0) { if (config & FSCACHE_OBJLIST_CONFIG_KEY) seq_puts(m, ", "); + p = auxlen <= sizeof(cookie->inline_aux) ? + cookie->inline_aux : cookie->aux; for (; auxlen > 0; auxlen--) seq_printf(m, "%02x", *p++); } } seq_puts(m, "\n"); + fscache_unuse_cookie(obj); } else { seq_puts(m, "<no_netfs>\n"); } diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 7c0ddb7ae29a..a7b28f876fde 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -144,6 +144,7 @@ static void fscache_put_object(struct fscache_object *, enum fscache_obj_ref_trace); static bool fscache_enqueue_dependents(struct fscache_object *, int); static void fscache_dequeue_object(struct fscache_object *); +static void fscache_update_aux_data(struct fscache_object *); /* * we need to notify the parent when an op completes that we had outstanding @@ -711,6 +712,11 @@ static const struct fscache_state *fscache_drop_object(struct fscache_object *ob ASSERT(cookie != NULL); ASSERT(!hlist_unhashed(&object->cookie_link)); + if (test_bit(FSCACHE_COOKIE_AUX_UPDATED, &cookie->flags)) { + _debug("final update"); + fscache_update_aux_data(object); + } + /* Make sure the cookie no longer points here and that the netfs isn't * waiting for us. */ @@ -1037,6 +1043,17 @@ static const struct fscache_state *fscache_invalidate_object(struct fscache_obje } /* + * Update auxiliary data. + */ +static void fscache_update_aux_data(struct fscache_object *object) +{ + fscache_stat(&fscache_n_updates_run); + fscache_stat(&fscache_n_cop_update_object); + object->cache->ops->update_object(object); + fscache_stat_d(&fscache_n_cop_update_object); +} + +/* * Asynchronously update an object. */ static const struct fscache_state *fscache_update_object(struct fscache_object *object, @@ -1044,10 +1061,7 @@ static const struct fscache_state *fscache_update_object(struct fscache_object * { _enter("{OBJ%x},%d", object->debug_id, event); - fscache_stat(&fscache_n_updates_run); - fscache_stat(&fscache_n_cop_update_object); - object->cache->ops->update_object(object); - fscache_stat_d(&fscache_n_cop_update_object); + fscache_update_aux_data(object); _leave(""); return transit_to(WAIT_FOR_CMD); diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 7a071e1e952d..e30c5975ea58 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c @@ -506,7 +506,7 @@ void fscache_put_operation(struct fscache_operation *op) if (!atomic_dec_and_test(&op->usage)) return; - trace_fscache_op(op->object->cookie, op, fscache_op_put); + trace_fscache_op(op->object ? op->object->cookie : NULL, op, fscache_op_put); _debug("PUT OP"); ASSERTIFCMP(op->state != FSCACHE_OP_ST_INITIALISED && |