cachefiles: Implement object lifecycle funcs

Implement allocate, get, see and put functions for the cachefiles_object
struct.  The members of the struct we're going to need are also added.

Additionally, implement a lifecycle tracepoint.

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
Link: https://lore.kernel.org/r/163819639457.215744.4600093239395728232.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/163906939569.143852.3594314410666551982.stgit@warthog.procyon.org.uk/ # v2
Link: https://lore.kernel.org/r/163967148857.1823006.6332962598220464364.stgit@warthog.procyon.org.uk/ # v3
Link: https://lore.kernel.org/r/164021547762.640689.8422781599594931000.stgit@warthog.procyon.org.uk/ # v4
This commit is contained in:
David Howells 2021-11-17 16:22:21 +00:00
parent 13871bad1e
commit df98e87f20
5 changed files with 197 additions and 2 deletions

View File

@ -13,6 +13,92 @@
#include <trace/events/fscache.h>
#include "internal.h"
static atomic_t cachefiles_object_debug_id;
/*
* Allocate a cache object record.
*/
static
struct cachefiles_object *cachefiles_alloc_object(struct fscache_cookie *cookie)
{
struct fscache_volume *vcookie = cookie->volume;
struct cachefiles_volume *volume = vcookie->cache_priv;
struct cachefiles_object *object;
_enter("{%s},%x,", vcookie->key, cookie->debug_id);
object = kmem_cache_zalloc(cachefiles_object_jar, GFP_KERNEL);
if (!object)
return NULL;
refcount_set(&object->ref, 1);
spin_lock_init(&object->lock);
INIT_LIST_HEAD(&object->cache_link);
object->volume = volume;
object->debug_id = atomic_inc_return(&cachefiles_object_debug_id);
object->cookie = fscache_get_cookie(cookie, fscache_cookie_get_attach_object);
fscache_count_object(vcookie->cache);
trace_cachefiles_ref(object->debug_id, cookie->debug_id, 1,
cachefiles_obj_new);
return object;
}
/*
* Note that an object has been seen.
*/
void cachefiles_see_object(struct cachefiles_object *object,
enum cachefiles_obj_ref_trace why)
{
trace_cachefiles_ref(object->debug_id, object->cookie->debug_id,
refcount_read(&object->ref), why);
}
/*
* Increment the usage count on an object;
*/
struct cachefiles_object *cachefiles_grab_object(struct cachefiles_object *object,
enum cachefiles_obj_ref_trace why)
{
int r;
__refcount_inc(&object->ref, &r);
trace_cachefiles_ref(object->debug_id, object->cookie->debug_id, r, why);
return object;
}
/*
* dispose of a reference to an object
*/
void cachefiles_put_object(struct cachefiles_object *object,
enum cachefiles_obj_ref_trace why)
{
unsigned int object_debug_id = object->debug_id;
unsigned int cookie_debug_id = object->cookie->debug_id;
struct fscache_cache *cache;
bool done;
int r;
done = __refcount_dec_and_test(&object->ref, &r);
trace_cachefiles_ref(object_debug_id, cookie_debug_id, r, why);
if (done) {
_debug("- kill object OBJ%x", object_debug_id);
ASSERTCMP(object->file, ==, NULL);
kfree(object->d_name);
cache = object->volume->cache->cache;
fscache_put_cookie(object->cookie, fscache_cookie_put_object);
object->cookie = NULL;
kmem_cache_free(cachefiles_object_jar, object);
fscache_uncount_object(cache);
}
_leave("");
}
const struct fscache_cache_ops cachefiles_cache_ops = {
.name = "cachefiles",
.acquire_volume = cachefiles_acquire_volume,

View File

@ -19,6 +19,16 @@
struct cachefiles_cache;
struct cachefiles_object;
enum cachefiles_content {
/* These values are saved on disk */
CACHEFILES_CONTENT_NO_DATA = 0, /* No content stored */
CACHEFILES_CONTENT_SINGLE = 1, /* Content is monolithic, all is present */
CACHEFILES_CONTENT_ALL = 2, /* Content is all present, no map */
CACHEFILES_CONTENT_BACKFS_MAP = 3, /* Content is piecemeal, mapped through backing fs */
CACHEFILES_CONTENT_DIRTY = 4, /* Content is dirty (only seen on disk) */
nr__cachefiles_content
};
/*
* Cached volume representation.
*/
@ -31,10 +41,20 @@ struct cachefiles_volume {
};
/*
* Data file records.
* Backing file state.
*/
struct cachefiles_object {
int debug_id; /* debugging ID */
struct fscache_cookie *cookie; /* Netfs data storage object cookie */
struct cachefiles_volume *volume; /* Cache volume that holds this object */
struct list_head cache_link; /* Link in cache->*_list */
struct file *file; /* The file representing this object */
char *d_name; /* Backing file name */
int debug_id;
spinlock_t lock;
refcount_t ref;
u8 d_name_len; /* Length of filename */
enum cachefiles_content content_info:8; /* Info about content presence */
unsigned long flags;
};
/*
@ -146,6 +166,17 @@ static inline int cachefiles_inject_remove_error(void)
* interface.c
*/
extern const struct fscache_cache_ops cachefiles_cache_ops;
extern void cachefiles_see_object(struct cachefiles_object *object,
enum cachefiles_obj_ref_trace why);
extern struct cachefiles_object *cachefiles_grab_object(struct cachefiles_object *object,
enum cachefiles_obj_ref_trace why);
extern void cachefiles_put_object(struct cachefiles_object *object,
enum cachefiles_obj_ref_trace why);
/*
* main.c
*/
extern struct kmem_cache *cachefiles_object_jar;
/*
* namei.c

View File

@ -31,6 +31,8 @@ MODULE_DESCRIPTION("Mounted-filesystem based cache");
MODULE_AUTHOR("Red Hat, Inc.");
MODULE_LICENSE("GPL");
struct kmem_cache *cachefiles_object_jar;
static struct miscdevice cachefiles_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "cachefiles",
@ -51,9 +53,22 @@ static int __init cachefiles_init(void)
if (ret < 0)
goto error_dev;
/* create an object jar */
ret = -ENOMEM;
cachefiles_object_jar =
kmem_cache_create("cachefiles_object_jar",
sizeof(struct cachefiles_object),
0, SLAB_HWCACHE_ALIGN, NULL);
if (!cachefiles_object_jar) {
pr_notice("Failed to allocate an object jar\n");
goto error_object_jar;
}
pr_info("Loaded\n");
return 0;
error_object_jar:
misc_deregister(&cachefiles_dev);
error_dev:
cachefiles_unregister_error_injection();
error_einj:
@ -70,6 +85,7 @@ static void __exit cachefiles_exit(void)
{
pr_info("Unloading\n");
kmem_cache_destroy(cachefiles_object_jar);
misc_deregister(&cachefiles_dev);
cachefiles_unregister_error_injection();
}

View File

@ -18,6 +18,21 @@
#ifndef __CACHEFILES_DECLARE_TRACE_ENUMS_ONCE_ONLY
#define __CACHEFILES_DECLARE_TRACE_ENUMS_ONCE_ONLY
enum cachefiles_obj_ref_trace {
cachefiles_obj_get_ioreq,
cachefiles_obj_new,
cachefiles_obj_put_alloc_fail,
cachefiles_obj_put_detach,
cachefiles_obj_put_ioreq,
cachefiles_obj_see_clean_commit,
cachefiles_obj_see_clean_delete,
cachefiles_obj_see_clean_drop_tmp,
cachefiles_obj_see_lookup_cookie,
cachefiles_obj_see_lookup_failed,
cachefiles_obj_see_withdraw_cookie,
cachefiles_obj_see_withdrawal,
};
enum fscache_why_object_killed {
FSCACHE_OBJECT_IS_STALE,
FSCACHE_OBJECT_IS_WEIRD,
@ -66,6 +81,20 @@ enum cachefiles_error_trace {
EM(FSCACHE_OBJECT_WAS_RETIRED, "was_retired") \
E_(FSCACHE_OBJECT_WAS_CULLED, "was_culled")
#define cachefiles_obj_ref_traces \
EM(cachefiles_obj_get_ioreq, "GET ioreq") \
EM(cachefiles_obj_new, "NEW obj") \
EM(cachefiles_obj_put_alloc_fail, "PUT alloc_fail") \
EM(cachefiles_obj_put_detach, "PUT detach") \
EM(cachefiles_obj_put_ioreq, "PUT ioreq") \
EM(cachefiles_obj_see_clean_commit, "SEE clean_commit") \
EM(cachefiles_obj_see_clean_delete, "SEE clean_delete") \
EM(cachefiles_obj_see_clean_drop_tmp, "SEE clean_drop_tmp") \
EM(cachefiles_obj_see_lookup_cookie, "SEE lookup_cookie") \
EM(cachefiles_obj_see_lookup_failed, "SEE lookup_failed") \
EM(cachefiles_obj_see_withdraw_cookie, "SEE withdraw_cookie") \
E_(cachefiles_obj_see_withdrawal, "SEE withdrawal")
#define cachefiles_trunc_traces \
EM(cachefiles_trunc_dio_adjust, "DIOADJ") \
EM(cachefiles_trunc_expand_tmpfile, "EXPTMP") \
@ -100,6 +129,7 @@ enum cachefiles_error_trace {
#define E_(a, b) TRACE_DEFINE_ENUM(a);
cachefiles_obj_kill_traces;
cachefiles_obj_ref_traces;
cachefiles_trunc_traces;
cachefiles_error_traces;
@ -113,6 +143,34 @@ cachefiles_error_traces;
#define E_(a, b) { a, b }
TRACE_EVENT(cachefiles_ref,
TP_PROTO(unsigned int object_debug_id,
unsigned int cookie_debug_id,
int usage,
enum cachefiles_obj_ref_trace why),
TP_ARGS(object_debug_id, cookie_debug_id, usage, why),
/* Note that obj may be NULL */
TP_STRUCT__entry(
__field(unsigned int, obj )
__field(unsigned int, cookie )
__field(enum cachefiles_obj_ref_trace, why )
__field(int, usage )
),
TP_fast_assign(
__entry->obj = object_debug_id;
__entry->cookie = cookie_debug_id;
__entry->usage = usage;
__entry->why = why;
),
TP_printk("c=%08x o=%08x u=%d %s",
__entry->cookie, __entry->obj, __entry->usage,
__print_symbolic(__entry->why, cachefiles_obj_ref_traces))
);
TRACE_EVENT(cachefiles_lookup,
TP_PROTO(struct cachefiles_object *obj,
struct dentry *de),

View File

@ -49,6 +49,7 @@ enum fscache_volume_trace {
enum fscache_cookie_trace {
fscache_cookie_collision,
fscache_cookie_discard,
fscache_cookie_get_attach_object,
fscache_cookie_get_end_access,
fscache_cookie_get_hash_collision,
fscache_cookie_get_inval_work,
@ -57,6 +58,7 @@ enum fscache_cookie_trace {
fscache_cookie_new_acquire,
fscache_cookie_put_hash_collision,
fscache_cookie_put_lru,
fscache_cookie_put_object,
fscache_cookie_put_over_queued,
fscache_cookie_put_relinquish,
fscache_cookie_put_withdrawn,
@ -122,6 +124,7 @@ enum fscache_access_trace {
#define fscache_cookie_traces \
EM(fscache_cookie_collision, "*COLLIDE*") \
EM(fscache_cookie_discard, "DISCARD ") \
EM(fscache_cookie_get_attach_object, "GET attch") \
EM(fscache_cookie_get_hash_collision, "GET hcoll") \
EM(fscache_cookie_get_end_access, "GQ endac") \
EM(fscache_cookie_get_inval_work, "GQ inval") \
@ -130,6 +133,7 @@ enum fscache_access_trace {
EM(fscache_cookie_new_acquire, "NEW acq ") \
EM(fscache_cookie_put_hash_collision, "PUT hcoll") \
EM(fscache_cookie_put_lru, "PUT lru ") \
EM(fscache_cookie_put_object, "PUT obj ") \
EM(fscache_cookie_put_over_queued, "PQ overq") \
EM(fscache_cookie_put_relinquish, "PUT relnq") \
EM(fscache_cookie_put_withdrawn, "PUT wthdn") \