Commit ec0328e4 authored by David Howells's avatar David Howells

fscache: Maintain a catalogue of allocated cookies

Maintain a catalogue of allocated cookies so that cookie collisions can be
handled properly.  For the moment, this just involves printing a warning
and returning a NULL cookie to the caller of fscache_acquire_cookie(), but
in future it might make sense to wait for the old cookie to finish being
cleaned up.

This requires the cookie key to be stored attached to the cookie so that we
still have the key available if the netfs relinquishes the cookie.  This is
done by an earlier patch.

The catalogue also renders redundant fscache_netfs_list (used for checking
for duplicates), so that can be removed.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarAnna Schumaker <anna.schumaker@netapp.com>
Tested-by: default avatarSteve Dickson <steved@redhat.com>
parent ee1235a9
This diff is collapsed.
......@@ -49,7 +49,14 @@ extern struct fscache_cache *fscache_select_cache_for_object(
*/
extern struct kmem_cache *fscache_cookie_jar;
extern void fscache_free_cookie(struct fscache_cookie *);
extern void fscache_cookie_init_once(void *);
extern struct fscache_cookie *fscache_alloc_cookie(struct fscache_cookie *,
const struct fscache_cookie_def *,
const void *, size_t,
const void *, size_t,
void *, loff_t);
extern struct fscache_cookie *fscache_hash_cookie(struct fscache_cookie *);
extern void fscache_cookie_put(struct fscache_cookie *,
enum fscache_cookie_trace);
......
......@@ -14,85 +14,51 @@
#include <linux/slab.h>
#include "internal.h"
static LIST_HEAD(fscache_netfs_list);
/*
* register a network filesystem for caching
*/
int __fscache_register_netfs(struct fscache_netfs *netfs)
{
struct fscache_netfs *ptr;
struct fscache_cookie *cookie;
int ret;
struct fscache_cookie *candidate, *cookie;
_enter("{%s}", netfs->name);
INIT_LIST_HEAD(&netfs->link);
/* allocate a cookie for the primary index */
cookie = kmem_cache_zalloc(fscache_cookie_jar, GFP_KERNEL);
if (!cookie) {
candidate = fscache_alloc_cookie(&fscache_fsdef_index,
&fscache_fsdef_netfs_def,
netfs->name, strlen(netfs->name),
&netfs->version, sizeof(netfs->version),
netfs, 0);
if (!candidate) {
_leave(" = -ENOMEM");
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);
atomic_set(&cookie->n_active, 1);
cookie->def = &fscache_fsdef_netfs_def;
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);
INIT_HLIST_HEAD(&cookie->backing_objects);
candidate->flags = 1 << FSCACHE_COOKIE_ENABLED;
/* check the netfs type is not already present */
down_write(&fscache_addremove_sem);
ret = -EEXIST;
list_for_each_entry(ptr, &fscache_netfs_list, link) {
if (strcmp(ptr->name, netfs->name) == 0)
goto already_registered;
cookie = fscache_hash_cookie(candidate);
if (!cookie)
goto already_registered;
if (cookie != candidate) {
trace_fscache_cookie(candidate, fscache_cookie_discard, 1);
fscache_free_cookie(candidate);
}
fscache_cookie_get(cookie->parent, fscache_cookie_get_register_netfs);
atomic_inc(&cookie->parent->n_children);
netfs->primary_index = cookie;
list_add(&netfs->link, &fscache_netfs_list);
ret = 0;
pr_notice("Netfs '%s' registered for caching\n", netfs->name);
trace_fscache_netfs(netfs);
_leave(" = 0");
return 0;
already_registered:
up_write(&fscache_addremove_sem);
nomem:
if (ret < 0)
kmem_cache_free(fscache_cookie_jar, cookie);
_leave(" = %d", ret);
return ret;
fscache_cookie_put(candidate, fscache_cookie_put_dup_netfs);
_leave(" = -EEXIST");
return -EEXIST;
}
EXPORT_SYMBOL(__fscache_register_netfs);
......@@ -104,15 +70,8 @@ void __fscache_unregister_netfs(struct fscache_netfs *netfs)
{
_enter("{%s.%u}", netfs->name, netfs->version);
down_write(&fscache_addremove_sem);
list_del(&netfs->link);
fscache_relinquish_cookie(netfs->primary_index, NULL, false);
up_write(&fscache_addremove_sem);
pr_notice("Netfs '%s' unregistered from caching\n",
netfs->name);
pr_notice("Netfs '%s' unregistered from caching\n", netfs->name);
_leave("");
}
......
......@@ -22,6 +22,7 @@
#include <linux/list.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
#include <linux/list_bl.h>
#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
#define fscache_available() (1)
......@@ -124,7 +125,6 @@ struct fscache_netfs {
uint32_t version; /* indexing version */
const char *name; /* filesystem name */
struct fscache_cookie *primary_index;
struct list_head link; /* internal link */
};
/*
......@@ -143,6 +143,7 @@ struct fscache_cookie {
struct hlist_head backing_objects; /* object(s) backing this file/index */
const struct fscache_cookie_def *def; /* definition */
struct fscache_cookie *parent; /* parent of this entry */
struct hlist_bl_node hash_link; /* Link in hash table */
void *netfs_data; /* back pointer to netfs */
struct radix_tree_root stores; /* pages to be stored on this cookie */
#define FSCACHE_COOKIE_PENDING_TAG 0 /* pages tag: pending write to cache */
......@@ -156,11 +157,14 @@ struct fscache_cookie {
#define FSCACHE_COOKIE_RELINQUISHED 4 /* T if cookie has been relinquished */
#define FSCACHE_COOKIE_ENABLED 5 /* T if cookie is enabled */
#define FSCACHE_COOKIE_ENABLEMENT_LOCK 6 /* T if cookie is being en/disabled */
#define FSCACHE_COOKIE_AUX_UPDATED 7 /* T if the auxiliary data was updated */
#define FSCACHE_COOKIE_AUX_UPDATED 8 /* T if the auxiliary data was updated */
#define FSCACHE_COOKIE_ACQUIRED 9 /* T if cookie is in use */
#define FSCACHE_COOKIE_RELINQUISHING 10 /* T if cookie is being relinquished */
u8 type; /* Type of object */
u8 key_len; /* Length of index key */
u8 aux_len; /* Length of auxiliary data */
u32 key_hash; /* Hash of parent, type, key, len */
union {
void *key; /* Index key */
u8 inline_key[16]; /* - If the key is short enough */
......
......@@ -24,10 +24,14 @@
#define __FSCACHE_DECLARE_TRACE_ENUMS_ONCE_ONLY
enum fscache_cookie_trace {
fscache_cookie_collision,
fscache_cookie_discard,
fscache_cookie_get_acquire_parent,
fscache_cookie_get_attach_object,
fscache_cookie_get_reacquire,
fscache_cookie_get_register_netfs,
fscache_cookie_put_acquire_nobufs,
fscache_cookie_put_dup_netfs,
fscache_cookie_put_relinquish,
fscache_cookie_put_object,
fscache_cookie_put_parent,
......@@ -86,10 +90,14 @@ enum fscache_page_op_trace {
* Declare tracing information enums and their string mappings for display.
*/
#define fscache_cookie_traces \
EM(fscache_cookie_collision, "*COLLISION*") \
EM(fscache_cookie_discard, "DISCARD") \
EM(fscache_cookie_get_acquire_parent, "GET prn") \
EM(fscache_cookie_get_attach_object, "GET obj") \
EM(fscache_cookie_get_reacquire, "GET raq") \
EM(fscache_cookie_get_register_netfs, "GET net") \
EM(fscache_cookie_put_acquire_nobufs, "PUT nbf") \
EM(fscache_cookie_put_dup_netfs, "PUT dnt") \
EM(fscache_cookie_put_relinquish, "PUT rlq") \
EM(fscache_cookie_put_object, "PUT obj") \
E_(fscache_cookie_put_parent, "PUT prn")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment