Commit 182d919b authored by David Howells's avatar David Howells

FS-Cache: Count culled objects and objects rejected due to lack of space

Count the number of objects that get culled by the cache backend and the
number of objects that the cache backend declines to instantiate due to lack
of space in the cache.

These numbers are made available through /proc/fs/fscache/stats
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarSteve Dickson <steved@redhat.com>
Acked-by: default avatarJeff Layton <jeff.layton@primarydata.com>
parent b2b89ebf
...@@ -676,6 +676,29 @@ FS-Cache provides some utilities that a cache backend may make use of: ...@@ -676,6 +676,29 @@ FS-Cache provides some utilities that a cache backend may make use of:
as possible. as possible.
(*) Indicate that a stale object was found and discarded:
void fscache_object_retrying_stale(struct fscache_object *object);
This is called to indicate that the lookup procedure found an object in
the cache that the netfs decided was stale. The object has been
discarded from the cache and the lookup will be performed again.
(*) Indicate that the caching backend killed an object:
void fscache_object_mark_killed(struct fscache_object *object,
enum fscache_why_object_killed why);
This is called to indicate that the cache backend preemptively killed an
object. The why parameter should be set to indicate the reason:
FSCACHE_OBJECT_IS_STALE - the object was stale and needs discarding.
FSCACHE_OBJECT_NO_SPACE - there was insufficient cache space
FSCACHE_OBJECT_WAS_RETIRED - the object was retired when relinquished.
FSCACHE_OBJECT_WAS_CULLED - the object was culled to make space.
(*) Get and release references on a retrieval record: (*) Get and release references on a retrieval record:
void fscache_get_retrieval(struct fscache_retrieval *op); void fscache_get_retrieval(struct fscache_retrieval *op);
......
...@@ -303,6 +303,10 @@ proc files. ...@@ -303,6 +303,10 @@ proc files.
wrp=N Number of in-progress write_page() cache ops wrp=N Number of in-progress write_page() cache ops
ucp=N Number of in-progress uncache_page() cache ops ucp=N Number of in-progress uncache_page() cache ops
dsp=N Number of in-progress dissociate_pages() cache ops dsp=N Number of in-progress dissociate_pages() cache ops
CacheEv nsp=N Number of object lookups/creations rejected due to lack of space
stl=N Number of stale objects deleted
rtr=N Number of objects retired when relinquished
cul=N Number of objects culled
(*) /proc/fs/fscache/histogram (*) /proc/fs/fscache/histogram
......
...@@ -43,7 +43,6 @@ struct cachefiles_object { ...@@ -43,7 +43,6 @@ struct cachefiles_object {
loff_t i_size; /* object size */ loff_t i_size; /* object size */
unsigned long flags; unsigned long flags;
#define CACHEFILES_OBJECT_ACTIVE 0 /* T if marked active */ #define CACHEFILES_OBJECT_ACTIVE 0 /* T if marked active */
#define CACHEFILES_OBJECT_BURIED 1 /* T if preemptively buried */
atomic_t usage; /* object usage count */ atomic_t usage; /* object usage count */
uint8_t type; /* object type */ uint8_t type; /* object type */
uint8_t new; /* T if object new */ uint8_t new; /* T if object new */
......
...@@ -97,7 +97,8 @@ static noinline void cachefiles_printk_object(struct cachefiles_object *object, ...@@ -97,7 +97,8 @@ static noinline void cachefiles_printk_object(struct cachefiles_object *object,
* call vfs_unlink(), vfs_rmdir() or vfs_rename() * call vfs_unlink(), vfs_rmdir() or vfs_rename()
*/ */
static void cachefiles_mark_object_buried(struct cachefiles_cache *cache, static void cachefiles_mark_object_buried(struct cachefiles_cache *cache,
struct dentry *dentry) struct dentry *dentry,
enum fscache_why_object_killed why)
{ {
struct cachefiles_object *object; struct cachefiles_object *object;
struct rb_node *p; struct rb_node *p;
...@@ -132,8 +133,9 @@ static void cachefiles_mark_object_buried(struct cachefiles_cache *cache, ...@@ -132,8 +133,9 @@ static void cachefiles_mark_object_buried(struct cachefiles_cache *cache,
pr_err("\n"); pr_err("\n");
pr_err("Error: Can't preemptively bury live object\n"); pr_err("Error: Can't preemptively bury live object\n");
cachefiles_printk_object(object, NULL); cachefiles_printk_object(object, NULL);
} else if (test_and_set_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) { } else {
pr_err("Error: Object already preemptively buried\n"); if (why != FSCACHE_OBJECT_IS_STALE)
fscache_object_mark_killed(&object->fscache, why);
} }
write_unlock(&cache->active_lock); write_unlock(&cache->active_lock);
...@@ -265,7 +267,8 @@ static int cachefiles_mark_object_active(struct cachefiles_cache *cache, ...@@ -265,7 +267,8 @@ static int cachefiles_mark_object_active(struct cachefiles_cache *cache,
static int cachefiles_bury_object(struct cachefiles_cache *cache, static int cachefiles_bury_object(struct cachefiles_cache *cache,
struct dentry *dir, struct dentry *dir,
struct dentry *rep, struct dentry *rep,
bool preemptive) bool preemptive,
enum fscache_why_object_killed why)
{ {
struct dentry *grave, *trap; struct dentry *grave, *trap;
struct path path, path_to_graveyard; struct path path, path_to_graveyard;
...@@ -289,7 +292,7 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache, ...@@ -289,7 +292,7 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
ret = vfs_unlink(dir->d_inode, rep, NULL); ret = vfs_unlink(dir->d_inode, rep, NULL);
if (preemptive) if (preemptive)
cachefiles_mark_object_buried(cache, rep); cachefiles_mark_object_buried(cache, rep, why);
} }
mutex_unlock(&dir->d_inode->i_mutex); mutex_unlock(&dir->d_inode->i_mutex);
...@@ -394,7 +397,7 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache, ...@@ -394,7 +397,7 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
"Rename failed with error %d", ret); "Rename failed with error %d", ret);
if (preemptive) if (preemptive)
cachefiles_mark_object_buried(cache, rep); cachefiles_mark_object_buried(cache, rep, why);
} }
unlock_rename(cache->graveyard, dir); unlock_rename(cache->graveyard, dir);
...@@ -422,7 +425,7 @@ int cachefiles_delete_object(struct cachefiles_cache *cache, ...@@ -422,7 +425,7 @@ int cachefiles_delete_object(struct cachefiles_cache *cache,
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
if (test_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) { if (test_bit(FSCACHE_OBJECT_KILLED_BY_CACHE, &object->fscache.flags)) {
/* object allocation for the same key preemptively deleted this /* object allocation for the same key preemptively deleted this
* object's file so that it could create its own file */ * object's file so that it could create its own file */
_debug("object preemptively buried"); _debug("object preemptively buried");
...@@ -433,7 +436,8 @@ int cachefiles_delete_object(struct cachefiles_cache *cache, ...@@ -433,7 +436,8 @@ int cachefiles_delete_object(struct cachefiles_cache *cache,
* may have been renamed */ * may have been renamed */
if (dir == object->dentry->d_parent) { if (dir == object->dentry->d_parent) {
ret = cachefiles_bury_object(cache, dir, ret = cachefiles_bury_object(cache, dir,
object->dentry, false); object->dentry, false,
FSCACHE_OBJECT_WAS_RETIRED);
} else { } else {
/* it got moved, presumably by cachefilesd culling it, /* it got moved, presumably by cachefilesd culling it,
* so it's no longer in the key path and we can ignore * so it's no longer in the key path and we can ignore
...@@ -522,7 +526,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent, ...@@ -522,7 +526,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
if (!next->d_inode) { if (!next->d_inode) {
ret = cachefiles_has_space(cache, 1, 0); ret = cachefiles_has_space(cache, 1, 0);
if (ret < 0) if (ret < 0)
goto create_error; goto no_space_error;
path.dentry = dir; path.dentry = dir;
ret = security_path_mkdir(&path, next, 0); ret = security_path_mkdir(&path, next, 0);
...@@ -551,7 +555,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent, ...@@ -551,7 +555,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
if (!next->d_inode) { if (!next->d_inode) {
ret = cachefiles_has_space(cache, 1, 0); ret = cachefiles_has_space(cache, 1, 0);
if (ret < 0) if (ret < 0)
goto create_error; goto no_space_error;
path.dentry = dir; path.dentry = dir;
ret = security_path_mknod(&path, next, S_IFREG, 0); ret = security_path_mknod(&path, next, S_IFREG, 0);
...@@ -602,7 +606,8 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent, ...@@ -602,7 +606,8 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
* mutex) */ * mutex) */
object->dentry = NULL; object->dentry = NULL;
ret = cachefiles_bury_object(cache, dir, next, true); ret = cachefiles_bury_object(cache, dir, next, true,
FSCACHE_OBJECT_IS_STALE);
dput(next); dput(next);
next = NULL; next = NULL;
...@@ -610,6 +615,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent, ...@@ -610,6 +615,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
goto delete_error; goto delete_error;
_debug("redo lookup"); _debug("redo lookup");
fscache_object_retrying_stale(&object->fscache);
goto lookup_again; goto lookup_again;
} }
} }
...@@ -662,6 +668,8 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent, ...@@ -662,6 +668,8 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
_leave(" = 0 [%lu]", object->dentry->d_inode->i_ino); _leave(" = 0 [%lu]", object->dentry->d_inode->i_ino);
return 0; return 0;
no_space_error:
fscache_object_mark_killed(&object->fscache, FSCACHE_OBJECT_NO_SPACE);
create_error: create_error:
_debug("create error %d", ret); _debug("create error %d", ret);
if (ret == -EIO) if (ret == -EIO)
...@@ -927,7 +935,8 @@ int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, ...@@ -927,7 +935,8 @@ int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir,
/* actually remove the victim (drops the dir mutex) */ /* actually remove the victim (drops the dir mutex) */
_debug("bury"); _debug("bury");
ret = cachefiles_bury_object(cache, dir, victim, false); ret = cachefiles_bury_object(cache, dir, victim, false,
FSCACHE_OBJECT_WAS_CULLED);
if (ret < 0) if (ret < 0)
goto error; goto error;
......
...@@ -271,6 +271,11 @@ extern atomic_t fscache_n_cop_write_page; ...@@ -271,6 +271,11 @@ extern atomic_t fscache_n_cop_write_page;
extern atomic_t fscache_n_cop_uncache_page; extern atomic_t fscache_n_cop_uncache_page;
extern atomic_t fscache_n_cop_dissociate_pages; extern atomic_t fscache_n_cop_dissociate_pages;
extern atomic_t fscache_n_cache_no_space_reject;
extern atomic_t fscache_n_cache_stale_objects;
extern atomic_t fscache_n_cache_retired_objects;
extern atomic_t fscache_n_cache_culled_objects;
static inline void fscache_stat(atomic_t *stat) static inline void fscache_stat(atomic_t *stat)
{ {
atomic_inc(stat); atomic_inc(stat);
......
...@@ -1016,3 +1016,50 @@ static const struct fscache_state *fscache_update_object(struct fscache_object * ...@@ -1016,3 +1016,50 @@ static const struct fscache_state *fscache_update_object(struct fscache_object *
_leave(""); _leave("");
return transit_to(WAIT_FOR_CMD); return transit_to(WAIT_FOR_CMD);
} }
/**
* fscache_object_retrying_stale - Note retrying stale object
* @object: The object that will be retried
*
* Note that an object lookup found an on-disk object that was adjudged to be
* stale and has been deleted. The lookup will be retried.
*/
void fscache_object_retrying_stale(struct fscache_object *object)
{
fscache_stat(&fscache_n_cache_no_space_reject);
}
EXPORT_SYMBOL(fscache_object_retrying_stale);
/**
* fscache_object_mark_killed - Note that an object was killed
* @object: The object that was culled
* @why: The reason the object was killed.
*
* Note that an object was killed. Returns true if the object was
* already marked killed, false if it wasn't.
*/
void fscache_object_mark_killed(struct fscache_object *object,
enum fscache_why_object_killed why)
{
if (test_and_set_bit(FSCACHE_OBJECT_KILLED_BY_CACHE, &object->flags)) {
pr_err("Error: Object already killed by cache [%s]\n",
object->cache->identifier);
return;
}
switch (why) {
case FSCACHE_OBJECT_NO_SPACE:
fscache_stat(&fscache_n_cache_no_space_reject);
break;
case FSCACHE_OBJECT_IS_STALE:
fscache_stat(&fscache_n_cache_stale_objects);
break;
case FSCACHE_OBJECT_WAS_RETIRED:
fscache_stat(&fscache_n_cache_retired_objects);
break;
case FSCACHE_OBJECT_WAS_CULLED:
fscache_stat(&fscache_n_cache_culled_objects);
break;
}
}
EXPORT_SYMBOL(fscache_object_mark_killed);
...@@ -130,6 +130,11 @@ atomic_t fscache_n_cop_write_page; ...@@ -130,6 +130,11 @@ atomic_t fscache_n_cop_write_page;
atomic_t fscache_n_cop_uncache_page; atomic_t fscache_n_cop_uncache_page;
atomic_t fscache_n_cop_dissociate_pages; atomic_t fscache_n_cop_dissociate_pages;
atomic_t fscache_n_cache_no_space_reject;
atomic_t fscache_n_cache_stale_objects;
atomic_t fscache_n_cache_retired_objects;
atomic_t fscache_n_cache_culled_objects;
/* /*
* display the general statistics * display the general statistics
*/ */
...@@ -271,6 +276,11 @@ static int fscache_stats_show(struct seq_file *m, void *v) ...@@ -271,6 +276,11 @@ static int fscache_stats_show(struct seq_file *m, void *v)
atomic_read(&fscache_n_cop_write_page), atomic_read(&fscache_n_cop_write_page),
atomic_read(&fscache_n_cop_uncache_page), atomic_read(&fscache_n_cop_uncache_page),
atomic_read(&fscache_n_cop_dissociate_pages)); atomic_read(&fscache_n_cop_dissociate_pages));
seq_printf(m, "CacheEv: nsp=%d stl=%d rtr=%d cul=%d\n",
atomic_read(&fscache_n_cache_no_space_reject),
atomic_read(&fscache_n_cache_stale_objects),
atomic_read(&fscache_n_cache_retired_objects),
atomic_read(&fscache_n_cache_culled_objects));
return 0; return 0;
} }
......
...@@ -371,6 +371,7 @@ struct fscache_object { ...@@ -371,6 +371,7 @@ struct fscache_object {
#define FSCACHE_OBJECT_IS_LOOKED_UP 4 /* T if object has been looked up */ #define FSCACHE_OBJECT_IS_LOOKED_UP 4 /* T if object has been looked up */
#define FSCACHE_OBJECT_IS_AVAILABLE 5 /* T if object has become active */ #define FSCACHE_OBJECT_IS_AVAILABLE 5 /* T if object has become active */
#define FSCACHE_OBJECT_RETIRED 6 /* T if object was retired on relinquishment */ #define FSCACHE_OBJECT_RETIRED 6 /* T if object was retired on relinquishment */
#define FSCACHE_OBJECT_KILLED_BY_CACHE 7 /* T if object was killed by the cache */
struct list_head cache_link; /* link in cache->object_list */ struct list_head cache_link; /* link in cache->object_list */
struct hlist_node cookie_link; /* link in cookie->backing_objects */ struct hlist_node cookie_link; /* link in cookie->backing_objects */
...@@ -551,4 +552,15 @@ extern enum fscache_checkaux fscache_check_aux(struct fscache_object *object, ...@@ -551,4 +552,15 @@ extern enum fscache_checkaux fscache_check_aux(struct fscache_object *object,
const void *data, const void *data,
uint16_t datalen); uint16_t datalen);
extern void fscache_object_retrying_stale(struct fscache_object *object);
enum fscache_why_object_killed {
FSCACHE_OBJECT_IS_STALE,
FSCACHE_OBJECT_NO_SPACE,
FSCACHE_OBJECT_WAS_RETIRED,
FSCACHE_OBJECT_WAS_CULLED,
};
extern void fscache_object_mark_killed(struct fscache_object *object,
enum fscache_why_object_killed why);
#endif /* _LINUX_FSCACHE_CACHE_H */ #endif /* _LINUX_FSCACHE_CACHE_H */
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