Commit 4fbf4291aa15926cd4fdca0ffe9122e89d0459db

Authored by David Howells
1 parent 440f0affe2

FS-Cache: Allow the current state of all objects to be dumped

Allow the current state of all fscache objects to be dumped by doing:

	cat /proc/fs/fscache/objects

By default, all objects and all fields will be shown.  This can be restricted
by adding a suitable key to one of the caller's keyrings (such as the session
keyring):

	keyctl add user fscache:objlist "<restrictions>" @s

The <restrictions> are:

	K	Show hexdump of object key (don't show if not given)
	A	Show hexdump of object aux data (don't show if not given)

And paired restrictions:

	C	Show objects that have a cookie
	c	Show objects that don't have a cookie
	B	Show objects that are busy
	b	Show objects that aren't busy
	W	Show objects that have pending writes
	w	Show objects that don't have pending writes
	R	Show objects that have outstanding reads
	r	Show objects that don't have outstanding reads
	S	Show objects that have slow work queued
	s	Show objects that don't have slow work queued

If neither side of a restriction pair is given, then both are implied.  For
example:

	keyctl add user fscache:objlist KB @s

shows objects that are busy, and lists their object keys, but does not dump
their auxiliary data.  It also implies "CcWwRrSs", but as 'B' is given, 'b' is
not implied.

Signed-off-by: David Howells <dhowells@redhat.com>

Showing 14 changed files with 578 additions and 3 deletions Side-by-side Diff

Documentation/filesystems/caching/fscache.txt
... ... @@ -299,6 +299,87 @@
299 299 jiffy range covered, and the SECS field the equivalent number of seconds.
300 300  
301 301  
  302 +===========
  303 +OBJECT LIST
  304 +===========
  305 +
  306 +If CONFIG_FSCACHE_OBJECT_LIST is enabled, the FS-Cache facility will maintain a
  307 +list of all the objects currently allocated and allow them to be viewed
  308 +through:
  309 +
  310 + /proc/fs/fscache/objects
  311 +
  312 +This will look something like:
  313 +
  314 + [root@andromeda ~]# head /proc/fs/fscache/objects
  315 + OBJECT PARENT STAT CHLDN OPS OOP IPR EX READS EM EV F S | NETFS_COOKIE_DEF TY FL NETFS_DATA OBJECT_KEY, AUX_DATA
  316 + ======== ======== ==== ===== === === === == ===== == == = = | ================ == == ================ ================
  317 + 17e4b 2 ACTV 0 0 0 0 0 0 7b 4 0 8 | NFS.fh DT 0 ffff88001dd82820 010006017edcf8bbc93b43298fdfbe71e50b57b13a172c0117f38472, e567634700000000000000000000000063f2404a000000000000000000000000c9030000000000000000000063f2404a
  318 + 1693a 2 ACTV 0 0 0 0 0 0 7b 4 0 8 | NFS.fh DT 0 ffff88002db23380 010006017edcf8bbc93b43298fdfbe71e50b57b1e0162c01a2df0ea6, 420ebc4a000000000000000000000000420ebc4a0000000000000000000000000e1801000000000000000000420ebc4a
  319 +
  320 +where the first set of columns before the '|' describe the object:
  321 +
  322 + COLUMN DESCRIPTION
  323 + ======= ===============================================================
  324 + OBJECT Object debugging ID (appears as OBJ%x in some debug messages)
  325 + PARENT Debugging ID of parent object
  326 + STAT Object state
  327 + CHLDN Number of child objects of this object
  328 + OPS Number of outstanding operations on this object
  329 + OOP Number of outstanding child object management operations
  330 + IPR
  331 + EX Number of outstanding exclusive operations
  332 + READS Number of outstanding read operations
  333 + EM Object's event mask
  334 + EV Events raised on this object
  335 + F Object flags
  336 + S Object slow-work work item flags
  337 +
  338 +and the second set of columns describe the object's cookie, if present:
  339 +
  340 + COLUMN DESCRIPTION
  341 + =============== =======================================================
  342 + NETFS_COOKIE_DEF Name of netfs cookie definition
  343 + TY Cookie type (IX - index, DT - data, hex - special)
  344 + FL Cookie flags
  345 + NETFS_DATA Netfs private data stored in the cookie
  346 + OBJECT_KEY Object key } 1 column, with separating comma
  347 + AUX_DATA Object aux data } presence may be configured
  348 +
  349 +The data shown may be filtered by attaching the a key to an appropriate keyring
  350 +before viewing the file. Something like:
  351 +
  352 + keyctl add user fscache:objlist <restrictions> @s
  353 +
  354 +where <restrictions> are a selection of the following letters:
  355 +
  356 + K Show hexdump of object key (don't show if not given)
  357 + A Show hexdump of object aux data (don't show if not given)
  358 +
  359 +and the following paired letters:
  360 +
  361 + C Show objects that have a cookie
  362 + c Show objects that don't have a cookie
  363 + B Show objects that are busy
  364 + b Show objects that aren't busy
  365 + W Show objects that have pending writes
  366 + w Show objects that don't have pending writes
  367 + R Show objects that have outstanding reads
  368 + r Show objects that don't have outstanding reads
  369 + S Show objects that have slow work queued
  370 + s Show objects that don't have slow work queued
  371 +
  372 +If neither side of a letter pair is given, then both are implied. For example:
  373 +
  374 + keyctl add user fscache:objlist KB @s
  375 +
  376 +shows objects that are busy, and lists their object keys, but does not dump
  377 +their auxiliary data. It also implies "CcWwRrSs", but as 'B' is given, 'b' is
  378 +not implied.
  379 +
  380 +By default all objects and all fields will be shown.
  381 +
  382 +
302 383 =========
303 384 DEBUGGING
304 385 =========
fs/cachefiles/interface.c
... ... @@ -331,6 +331,7 @@
331 331 }
332 332  
333 333 cache = object->fscache.cache;
  334 + fscache_object_destroy(&object->fscache);
334 335 kmem_cache_free(cachefiles_object_jar, object);
335 336 fscache_object_destroyed(cache);
336 337 }
fs/cachefiles/rdwr.c
... ... @@ -333,7 +333,8 @@
333 333  
334 334 shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
335 335  
336   - op->op.flags = FSCACHE_OP_FAST;
  336 + op->op.flags &= FSCACHE_OP_KEEP_FLAGS;
  337 + op->op.flags |= FSCACHE_OP_FAST;
337 338 op->op.processor = cachefiles_read_copier;
338 339  
339 340 pagevec_init(&pagevec, 0);
... ... @@ -639,7 +640,8 @@
639 640  
640 641 pagevec_init(&pagevec, 0);
641 642  
642   - op->op.flags = FSCACHE_OP_FAST;
  643 + op->op.flags &= FSCACHE_OP_KEEP_FLAGS;
  644 + op->op.flags |= FSCACHE_OP_FAST;
643 645 op->op.processor = cachefiles_read_copier;
644 646  
645 647 INIT_LIST_HEAD(&backpages);
... ... @@ -54,4 +54,11 @@
54 54 enabled by setting bits in /sys/modules/fscache/parameter/debug.
55 55  
56 56 See Documentation/filesystems/caching/fscache.txt for more information.
  57 +
  58 +config FSCACHE_OBJECT_LIST
  59 + bool "Maintain global object list for debugging purposes"
  60 + depends on FSCACHE && PROC_FS
  61 + help
  62 + Maintain a global list of active fscache objects that can be
  63 + retrieved through /proc/fs/fscache/objects for debugging purposes
... ... @@ -15,6 +15,7 @@
15 15 fscache-$(CONFIG_PROC_FS) += proc.o
16 16 fscache-$(CONFIG_FSCACHE_STATS) += stats.o
17 17 fscache-$(CONFIG_FSCACHE_HISTOGRAM) += histogram.o
  18 +fscache-$(CONFIG_FSCACHE_OBJECT_LIST) += object-list.o
18 19  
19 20 obj-$(CONFIG_FSCACHE) := fscache.o
... ... @@ -263,6 +263,7 @@
263 263 spin_lock(&cache->object_list_lock);
264 264 list_add_tail(&ifsdef->cache_link, &cache->object_list);
265 265 spin_unlock(&cache->object_list_lock);
  266 + fscache_objlist_add(ifsdef);
266 267  
267 268 /* add the cache's netfs definition index object to the top level index
268 269 * cookie as a known backing object */
... ... @@ -349,6 +349,8 @@
349 349 object->cookie = cookie;
350 350 atomic_inc(&cookie->usage);
351 351 hlist_add_head(&object->cookie_link, &cookie->backing_objects);
  352 +
  353 + fscache_objlist_add(object);
352 354 ret = 0;
353 355  
354 356 cant_attach_object:
fs/fscache/internal.h
... ... @@ -88,9 +88,22 @@
88 88 /*
89 89 * object.c
90 90 */
  91 +extern const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5];
  92 +
91 93 extern void fscache_withdrawing_object(struct fscache_cache *,
92 94 struct fscache_object *);
93 95 extern void fscache_enqueue_object(struct fscache_object *);
  96 +
  97 +/*
  98 + * object-list.c
  99 + */
  100 +#ifdef CONFIG_FSCACHE_OBJECT_LIST
  101 +extern const struct file_operations fscache_objlist_fops;
  102 +
  103 +extern void fscache_objlist_add(struct fscache_object *);
  104 +#else
  105 +#define fscache_objlist_add(object) do {} while(0)
  106 +#endif
94 107  
95 108 /*
96 109 * operation.c
fs/fscache/object-list.c
  1 +/* Global fscache object list maintainer and viewer
  2 + *
  3 + * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
  4 + * Written by David Howells (dhowells@redhat.com)
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public Licence
  8 + * as published by the Free Software Foundation; either version
  9 + * 2 of the Licence, or (at your option) any later version.
  10 + */
  11 +
  12 +#define FSCACHE_DEBUG_LEVEL COOKIE
  13 +#include <linux/module.h>
  14 +#include <linux/seq_file.h>
  15 +#include <linux/key.h>
  16 +#include <keys/user-type.h>
  17 +#include "internal.h"
  18 +
  19 +static struct rb_root fscache_object_list;
  20 +static DEFINE_RWLOCK(fscache_object_list_lock);
  21 +
  22 +struct fscache_objlist_data {
  23 + unsigned long config; /* display configuration */
  24 +#define FSCACHE_OBJLIST_CONFIG_KEY 0x00000001 /* show object keys */
  25 +#define FSCACHE_OBJLIST_CONFIG_AUX 0x00000002 /* show object auxdata */
  26 +#define FSCACHE_OBJLIST_CONFIG_COOKIE 0x00000004 /* show objects with cookies */
  27 +#define FSCACHE_OBJLIST_CONFIG_NOCOOKIE 0x00000008 /* show objects without cookies */
  28 +#define FSCACHE_OBJLIST_CONFIG_BUSY 0x00000010 /* show busy objects */
  29 +#define FSCACHE_OBJLIST_CONFIG_IDLE 0x00000020 /* show idle objects */
  30 +#define FSCACHE_OBJLIST_CONFIG_PENDWR 0x00000040 /* show objects with pending writes */
  31 +#define FSCACHE_OBJLIST_CONFIG_NOPENDWR 0x00000080 /* show objects without pending writes */
  32 +#define FSCACHE_OBJLIST_CONFIG_READS 0x00000100 /* show objects with active reads */
  33 +#define FSCACHE_OBJLIST_CONFIG_NOREADS 0x00000200 /* show objects without active reads */
  34 +#define FSCACHE_OBJLIST_CONFIG_EVENTS 0x00000400 /* show objects with events */
  35 +#define FSCACHE_OBJLIST_CONFIG_NOEVENTS 0x00000800 /* show objects without no events */
  36 +#define FSCACHE_OBJLIST_CONFIG_WORK 0x00001000 /* show objects with slow work */
  37 +#define FSCACHE_OBJLIST_CONFIG_NOWORK 0x00002000 /* show objects without slow work */
  38 +
  39 + u8 buf[512]; /* key and aux data buffer */
  40 +};
  41 +
  42 +/*
  43 + * Add an object to the object list
  44 + * - we use the address of the fscache_object structure as the key into the
  45 + * tree
  46 + */
  47 +void fscache_objlist_add(struct fscache_object *obj)
  48 +{
  49 + struct fscache_object *xobj;
  50 + struct rb_node **p = &fscache_object_list.rb_node, *parent = NULL;
  51 +
  52 + write_lock(&fscache_object_list_lock);
  53 +
  54 + while (*p) {
  55 + parent = *p;
  56 + xobj = rb_entry(parent, struct fscache_object, objlist_link);
  57 +
  58 + if (obj < xobj)
  59 + p = &(*p)->rb_left;
  60 + else if (obj > xobj)
  61 + p = &(*p)->rb_right;
  62 + else
  63 + BUG();
  64 + }
  65 +
  66 + rb_link_node(&obj->objlist_link, parent, p);
  67 + rb_insert_color(&obj->objlist_link, &fscache_object_list);
  68 +
  69 + write_unlock(&fscache_object_list_lock);
  70 +}
  71 +
  72 +/**
  73 + * fscache_object_destroy - Note that a cache object is about to be destroyed
  74 + * @object: The object to be destroyed
  75 + *
  76 + * Note the imminent destruction and deallocation of a cache object record.
  77 + */
  78 +void fscache_object_destroy(struct fscache_object *obj)
  79 +{
  80 + write_lock(&fscache_object_list_lock);
  81 +
  82 + BUG_ON(RB_EMPTY_ROOT(&fscache_object_list));
  83 + rb_erase(&obj->objlist_link, &fscache_object_list);
  84 +
  85 + write_unlock(&fscache_object_list_lock);
  86 +}
  87 +EXPORT_SYMBOL(fscache_object_destroy);
  88 +
  89 +/*
  90 + * find the object in the tree on or after the specified index
  91 + */
  92 +static struct fscache_object *fscache_objlist_lookup(loff_t *_pos)
  93 +{
  94 + struct fscache_object *pobj, *obj, *minobj = NULL;
  95 + struct rb_node *p;
  96 + unsigned long pos;
  97 +
  98 + if (*_pos >= (unsigned long) ERR_PTR(-ENOENT))
  99 + return NULL;
  100 + pos = *_pos;
  101 +
  102 + /* banners (can't represent line 0 by pos 0 as that would involve
  103 + * returning a NULL pointer) */
  104 + if (pos == 0)
  105 + return (struct fscache_object *) ++(*_pos);
  106 + if (pos < 3)
  107 + return (struct fscache_object *)pos;
  108 +
  109 + pobj = (struct fscache_object *)pos;
  110 + p = fscache_object_list.rb_node;
  111 + while (p) {
  112 + obj = rb_entry(p, struct fscache_object, objlist_link);
  113 + if (pobj < obj) {
  114 + if (!minobj || minobj > obj)
  115 + minobj = obj;
  116 + p = p->rb_left;
  117 + } else if (pobj > obj) {
  118 + p = p->rb_right;
  119 + } else {
  120 + minobj = obj;
  121 + break;
  122 + }
  123 + obj = NULL;
  124 + }
  125 +
  126 + if (!minobj)
  127 + *_pos = (unsigned long) ERR_PTR(-ENOENT);
  128 + else if (minobj != obj)
  129 + *_pos = (unsigned long) minobj;
  130 + return minobj;
  131 +}
  132 +
  133 +/*
  134 + * set up the iterator to start reading from the first line
  135 + */
  136 +static void *fscache_objlist_start(struct seq_file *m, loff_t *_pos)
  137 + __acquires(&fscache_object_list_lock)
  138 +{
  139 + read_lock(&fscache_object_list_lock);
  140 + return fscache_objlist_lookup(_pos);
  141 +}
  142 +
  143 +/*
  144 + * move to the next line
  145 + */
  146 +static void *fscache_objlist_next(struct seq_file *m, void *v, loff_t *_pos)
  147 +{
  148 + (*_pos)++;
  149 + return fscache_objlist_lookup(_pos);
  150 +}
  151 +
  152 +/*
  153 + * clean up after reading
  154 + */
  155 +static void fscache_objlist_stop(struct seq_file *m, void *v)
  156 + __releases(&fscache_object_list_lock)
  157 +{
  158 + read_unlock(&fscache_object_list_lock);
  159 +}
  160 +
  161 +/*
  162 + * display an object
  163 + */
  164 +static int fscache_objlist_show(struct seq_file *m, void *v)
  165 +{
  166 + struct fscache_objlist_data *data = m->private;
  167 + struct fscache_object *obj = v;
  168 + unsigned long config = data->config;
  169 + uint16_t keylen, auxlen;
  170 + char _type[3], *type;
  171 + bool no_cookie;
  172 + u8 *buf = data->buf, *p;
  173 +
  174 + if ((unsigned long) v == 1) {
  175 + seq_puts(m, "OBJECT PARENT STAT CHLDN OPS OOP IPR EX READS"
  176 + " EM EV F S"
  177 + " | NETFS_COOKIE_DEF TY FL NETFS_DATA");
  178 + if (config & (FSCACHE_OBJLIST_CONFIG_KEY |
  179 + FSCACHE_OBJLIST_CONFIG_AUX))
  180 + seq_puts(m, " ");
  181 + if (config & FSCACHE_OBJLIST_CONFIG_KEY)
  182 + seq_puts(m, "OBJECT_KEY");
  183 + if ((config & (FSCACHE_OBJLIST_CONFIG_KEY |
  184 + FSCACHE_OBJLIST_CONFIG_AUX)) ==
  185 + (FSCACHE_OBJLIST_CONFIG_KEY | FSCACHE_OBJLIST_CONFIG_AUX))
  186 + seq_puts(m, ", ");
  187 + if (config & FSCACHE_OBJLIST_CONFIG_AUX)
  188 + seq_puts(m, "AUX_DATA");
  189 + seq_puts(m, "\n");
  190 + return 0;
  191 + }
  192 +
  193 + if ((unsigned long) v == 2) {
  194 + seq_puts(m, "======== ======== ==== ===== === === === == ====="
  195 + " == == = ="
  196 + " | ================ == == ================");
  197 + if (config & (FSCACHE_OBJLIST_CONFIG_KEY |
  198 + FSCACHE_OBJLIST_CONFIG_AUX))
  199 + seq_puts(m, " ================");
  200 + seq_puts(m, "\n");
  201 + return 0;
  202 + }
  203 +
  204 + /* filter out any unwanted objects */
  205 +#define FILTER(criterion, _yes, _no) \
  206 + do { \
  207 + unsigned long yes = FSCACHE_OBJLIST_CONFIG_##_yes; \
  208 + unsigned long no = FSCACHE_OBJLIST_CONFIG_##_no; \
  209 + if (criterion) { \
  210 + if (!(config & yes)) \
  211 + return 0; \
  212 + } else { \
  213 + if (!(config & no)) \
  214 + return 0; \
  215 + } \
  216 + } while(0)
  217 +
  218 + if (~config) {
  219 + FILTER(obj->cookie,
  220 + COOKIE, NOCOOKIE);
  221 + FILTER(obj->state != FSCACHE_OBJECT_ACTIVE ||
  222 + obj->n_ops != 0 ||
  223 + obj->n_obj_ops != 0 ||
  224 + obj->flags ||
  225 + !list_empty(&obj->dependents),
  226 + BUSY, IDLE);
  227 + FILTER(test_bit(FSCACHE_OBJECT_PENDING_WRITE, &obj->flags),
  228 + PENDWR, NOPENDWR);
  229 + FILTER(atomic_read(&obj->n_reads),
  230 + READS, NOREADS);
  231 + FILTER(obj->events & obj->event_mask,
  232 + EVENTS, NOEVENTS);
  233 + FILTER(obj->work.flags & ~(1UL << SLOW_WORK_VERY_SLOW),
  234 + WORK, NOWORK);
  235 + }
  236 +
  237 + seq_printf(m,
  238 + "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1lx | ",
  239 + obj->debug_id,
  240 + obj->parent ? obj->parent->debug_id : -1,
  241 + fscache_object_states_short[obj->state],
  242 + obj->n_children,
  243 + obj->n_ops,
  244 + obj->n_obj_ops,
  245 + obj->n_in_progress,
  246 + obj->n_exclusive,
  247 + atomic_read(&obj->n_reads),
  248 + obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK,
  249 + obj->events,
  250 + obj->flags,
  251 + obj->work.flags);
  252 +
  253 + no_cookie = true;
  254 + keylen = auxlen = 0;
  255 + if (obj->cookie) {
  256 + spin_lock(&obj->lock);
  257 + if (obj->cookie) {
  258 + switch (obj->cookie->def->type) {
  259 + case 0:
  260 + type = "IX";
  261 + break;
  262 + case 1:
  263 + type = "DT";
  264 + break;
  265 + default:
  266 + sprintf(_type, "%02u",
  267 + obj->cookie->def->type);
  268 + type = _type;
  269 + break;
  270 + }
  271 +
  272 + seq_printf(m, "%-16s %s %2lx %16p",
  273 + obj->cookie->def->name,
  274 + type,
  275 + obj->cookie->flags,
  276 + obj->cookie->netfs_data);
  277 +
  278 + if (obj->cookie->def->get_key &&
  279 + config & FSCACHE_OBJLIST_CONFIG_KEY)
  280 + keylen = obj->cookie->def->get_key(
  281 + obj->cookie->netfs_data,
  282 + buf, 400);
  283 +
  284 + if (obj->cookie->def->get_aux &&
  285 + config & FSCACHE_OBJLIST_CONFIG_AUX)
  286 + auxlen = obj->cookie->def->get_aux(
  287 + obj->cookie->netfs_data,
  288 + buf + keylen, 512 - keylen);
  289 +
  290 + no_cookie = false;
  291 + }
  292 + spin_unlock(&obj->lock);
  293 +
  294 + if (!no_cookie && (keylen > 0 || auxlen > 0)) {
  295 + seq_printf(m, " ");
  296 + for (p = buf; keylen > 0; keylen--)
  297 + seq_printf(m, "%02x", *p++);
  298 + if (auxlen > 0) {
  299 + if (config & FSCACHE_OBJLIST_CONFIG_KEY)
  300 + seq_printf(m, ", ");
  301 + for (; auxlen > 0; auxlen--)
  302 + seq_printf(m, "%02x", *p++);
  303 + }
  304 + }
  305 + }
  306 +
  307 + if (no_cookie)
  308 + seq_printf(m, "<no_cookie>\n");
  309 + else
  310 + seq_printf(m, "\n");
  311 + return 0;
  312 +}
  313 +
  314 +static const struct seq_operations fscache_objlist_ops = {
  315 + .start = fscache_objlist_start,
  316 + .stop = fscache_objlist_stop,
  317 + .next = fscache_objlist_next,
  318 + .show = fscache_objlist_show,
  319 +};
  320 +
  321 +/*
  322 + * get the configuration for filtering the list
  323 + */
  324 +static void fscache_objlist_config(struct fscache_objlist_data *data)
  325 +{
  326 +#ifdef CONFIG_KEYS
  327 + struct user_key_payload *confkey;
  328 + unsigned long config;
  329 + struct key *key;
  330 + const char *buf;
  331 + int len;
  332 +
  333 + key = request_key(&key_type_user, "fscache:objlist", NULL);
  334 + if (IS_ERR(key))
  335 + goto no_config;
  336 +
  337 + config = 0;
  338 + rcu_read_lock();
  339 +
  340 + confkey = key->payload.data;
  341 + buf = confkey->data;
  342 +
  343 + for (len = confkey->datalen - 1; len >= 0; len--) {
  344 + switch (buf[len]) {
  345 + case 'K': config |= FSCACHE_OBJLIST_CONFIG_KEY; break;
  346 + case 'A': config |= FSCACHE_OBJLIST_CONFIG_AUX; break;
  347 + case 'C': config |= FSCACHE_OBJLIST_CONFIG_COOKIE; break;
  348 + case 'c': config |= FSCACHE_OBJLIST_CONFIG_NOCOOKIE; break;
  349 + case 'B': config |= FSCACHE_OBJLIST_CONFIG_BUSY; break;
  350 + case 'b': config |= FSCACHE_OBJLIST_CONFIG_IDLE; break;
  351 + case 'W': config |= FSCACHE_OBJLIST_CONFIG_PENDWR; break;
  352 + case 'w': config |= FSCACHE_OBJLIST_CONFIG_NOPENDWR; break;
  353 + case 'R': config |= FSCACHE_OBJLIST_CONFIG_READS; break;
  354 + case 'r': config |= FSCACHE_OBJLIST_CONFIG_NOREADS; break;
  355 + case 'S': config |= FSCACHE_OBJLIST_CONFIG_WORK; break;
  356 + case 's': config |= FSCACHE_OBJLIST_CONFIG_NOWORK; break;
  357 + }
  358 + }
  359 +
  360 + rcu_read_unlock();
  361 + key_put(key);
  362 +
  363 + if (!(config & (FSCACHE_OBJLIST_CONFIG_COOKIE | FSCACHE_OBJLIST_CONFIG_NOCOOKIE)))
  364 + config |= FSCACHE_OBJLIST_CONFIG_COOKIE | FSCACHE_OBJLIST_CONFIG_NOCOOKIE;
  365 + if (!(config & (FSCACHE_OBJLIST_CONFIG_BUSY | FSCACHE_OBJLIST_CONFIG_IDLE)))
  366 + config |= FSCACHE_OBJLIST_CONFIG_BUSY | FSCACHE_OBJLIST_CONFIG_IDLE;
  367 + if (!(config & (FSCACHE_OBJLIST_CONFIG_PENDWR | FSCACHE_OBJLIST_CONFIG_NOPENDWR)))
  368 + config |= FSCACHE_OBJLIST_CONFIG_PENDWR | FSCACHE_OBJLIST_CONFIG_NOPENDWR;
  369 + if (!(config & (FSCACHE_OBJLIST_CONFIG_READS | FSCACHE_OBJLIST_CONFIG_NOREADS)))
  370 + config |= FSCACHE_OBJLIST_CONFIG_READS | FSCACHE_OBJLIST_CONFIG_NOREADS;
  371 + if (!(config & (FSCACHE_OBJLIST_CONFIG_EVENTS | FSCACHE_OBJLIST_CONFIG_NOEVENTS)))
  372 + config |= FSCACHE_OBJLIST_CONFIG_EVENTS | FSCACHE_OBJLIST_CONFIG_NOEVENTS;
  373 + if (!(config & (FSCACHE_OBJLIST_CONFIG_WORK | FSCACHE_OBJLIST_CONFIG_NOWORK)))
  374 + config |= FSCACHE_OBJLIST_CONFIG_WORK | FSCACHE_OBJLIST_CONFIG_NOWORK;
  375 +
  376 + data->config = config;
  377 + return;
  378 +
  379 +no_config:
  380 +#endif
  381 + data->config = ULONG_MAX;
  382 +}
  383 +
  384 +/*
  385 + * open "/proc/fs/fscache/objects" to provide a list of active objects
  386 + * - can be configured by a user-defined key added to the caller's keyrings
  387 + */
  388 +static int fscache_objlist_open(struct inode *inode, struct file *file)
  389 +{
  390 + struct fscache_objlist_data *data;
  391 + struct seq_file *m;
  392 + int ret;
  393 +
  394 + ret = seq_open(file, &fscache_objlist_ops);
  395 + if (ret < 0)
  396 + return ret;
  397 +
  398 + m = file->private_data;
  399 +
  400 + /* buffer for key extraction */
  401 + data = kmalloc(sizeof(struct fscache_objlist_data), GFP_KERNEL);
  402 + if (!data) {
  403 + seq_release(inode, file);
  404 + return -ENOMEM;
  405 + }
  406 +
  407 + /* get the configuration key */
  408 + fscache_objlist_config(data);
  409 +
  410 + m->private = data;
  411 + return 0;
  412 +}
  413 +
  414 +/*
  415 + * clean up on close
  416 + */
  417 +static int fscache_objlist_release(struct inode *inode, struct file *file)
  418 +{
  419 + struct seq_file *m = file->private_data;
  420 +
  421 + kfree(m->private);
  422 + m->private = NULL;
  423 + return seq_release(inode, file);
  424 +}
  425 +
  426 +const struct file_operations fscache_objlist_fops = {
  427 + .owner = THIS_MODULE,
  428 + .open = fscache_objlist_open,
  429 + .read = seq_read,
  430 + .llseek = seq_lseek,
  431 + .release = fscache_objlist_release,
  432 +};
... ... @@ -34,7 +34,7 @@
34 34 };
35 35 EXPORT_SYMBOL(fscache_object_states);
36 36  
37   -static const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = {
  37 +const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = {
38 38 [FSCACHE_OBJECT_INIT] = "INIT",
39 39 [FSCACHE_OBJECT_LOOKING_UP] = "LOOK",
40 40 [FSCACHE_OBJECT_CREATING] = "CRTN",
fs/fscache/operation.c
... ... @@ -322,6 +322,9 @@
322 322  
323 323 object = op->object;
324 324  
  325 + if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags))
  326 + atomic_dec(&object->n_reads);
  327 +
325 328 /* now... we may get called with the object spinlock held, so we
326 329 * complete the cleanup here only if we can immediately acquire the
327 330 * lock, and defer it otherwise */
... ... @@ -275,6 +275,9 @@
275 275  
276 276 ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP);
277 277  
  278 + atomic_inc(&object->n_reads);
  279 + set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags);
  280 +
278 281 if (fscache_submit_op(object, &op->op) < 0)
279 282 goto nobufs_unlock;
280 283 spin_unlock(&cookie->lock);
... ... @@ -385,6 +388,9 @@
385 388 goto nobufs_unlock;
386 389 object = hlist_entry(cookie->backing_objects.first,
387 390 struct fscache_object, cookie_link);
  391 +
  392 + atomic_inc(&object->n_reads);
  393 + set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags);
388 394  
389 395 if (fscache_submit_op(object, &op->op) < 0)
390 396 goto nobufs_unlock;
... ... @@ -37,10 +37,20 @@
37 37 goto error_histogram;
38 38 #endif
39 39  
  40 +#ifdef CONFIG_FSCACHE_OBJECT_LIST
  41 + if (!proc_create("fs/fscache/objects", S_IFREG | 0444, NULL,
  42 + &fscache_objlist_fops))
  43 + goto error_objects;
  44 +#endif
  45 +
40 46 _leave(" = 0");
41 47 return 0;
42 48  
  49 +#ifdef CONFIG_FSCACHE_OBJECT_LIST
  50 +error_objects:
  51 +#endif
43 52 #ifdef CONFIG_FSCACHE_HISTOGRAM
  53 + remove_proc_entry("fs/fscache/histogram", NULL);
44 54 error_histogram:
45 55 #endif
46 56 #ifdef CONFIG_FSCACHE_STATS
... ... @@ -58,6 +68,9 @@
58 68 */
59 69 void fscache_proc_cleanup(void)
60 70 {
  71 +#ifdef CONFIG_FSCACHE_OBJECT_LIST
  72 + remove_proc_entry("fs/fscache/objects", NULL);
  73 +#endif
61 74 #ifdef CONFIG_FSCACHE_HISTOGRAM
62 75 remove_proc_entry("fs/fscache/histogram", NULL);
63 76 #endif
include/linux/fscache-cache.h
... ... @@ -91,6 +91,8 @@
91 91 #define FSCACHE_OP_WAITING 4 /* cleared when op is woken */
92 92 #define FSCACHE_OP_EXCLUSIVE 5 /* exclusive op, other ops must wait */
93 93 #define FSCACHE_OP_DEAD 6 /* op is now dead */
  94 +#define FSCACHE_OP_DEC_READ_CNT 7 /* decrement object->n_reads on destruction */
  95 +#define FSCACHE_OP_KEEP_FLAGS 0xc0 /* flags to keep when repurposing an op */
94 96  
95 97 atomic_t usage;
96 98 unsigned debug_id; /* debugging ID */
... ... @@ -357,6 +359,7 @@
357 359 int n_obj_ops; /* number of object ops outstanding on object */
358 360 int n_in_progress; /* number of ops in progress */
359 361 int n_exclusive; /* number of exclusive ops queued */
  362 + atomic_t n_reads; /* number of read ops in progress */
360 363 spinlock_t lock; /* state and operations lock */
361 364  
362 365 unsigned long lookup_jif; /* time at which lookup started */
... ... @@ -370,6 +373,7 @@
370 373 #define FSCACHE_OBJECT_EV_RELEASE 4 /* T if netfs requested object release */
371 374 #define FSCACHE_OBJECT_EV_RETIRE 5 /* T if netfs requested object retirement */
372 375 #define FSCACHE_OBJECT_EV_WITHDRAW 6 /* T if cache requested object withdrawal */
  376 +#define FSCACHE_OBJECT_EVENTS_MASK 0x7f /* mask of all events*/
373 377  
374 378 unsigned long flags;
375 379 #define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */
... ... @@ -385,6 +389,9 @@
385 389 struct list_head dependents; /* FIFO of dependent objects */
386 390 struct list_head dep_link; /* link in parent's dependents list */
387 391 struct list_head pending_ops; /* unstarted operations on this object */
  392 +#ifdef CONFIG_FSCACHE_OBJECT_LIST
  393 + struct rb_node objlist_link; /* link in global object list */
  394 +#endif
388 395 pgoff_t store_limit; /* current storage limit */
389 396 };
390 397  
... ... @@ -433,6 +440,12 @@
433 440  
434 441 extern void fscache_object_lookup_negative(struct fscache_object *object);
435 442 extern void fscache_obtained_object(struct fscache_object *object);
  443 +
  444 +#ifdef CONFIG_FSCACHE_OBJECT_LIST
  445 +extern void fscache_object_destroy(struct fscache_object *object);
  446 +#else
  447 +#define fscache_object_destroy(object) do {} while(0)
  448 +#endif
436 449  
437 450 /**
438 451 * fscache_object_destroyed - Note destruction of an object in a cache