Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8b8edefa authored by Tejun Heo's avatar Tejun Heo
Browse files

fscache: convert object to use workqueue instead of slow-work



Make fscache object state transition callbacks use workqueue instead
of slow-work.  New dedicated unbound CPU workqueue fscache_object_wq
is created.  get/put callbacks are renamed and modified to take
@object and called directly from the enqueue wrapper and the work
function.  While at it, make all open coded instances of get/put to
use fscache_get/put_object().

* Unbound workqueue is used.

* work_busy() output is printed instead of slow-work flags in object
  debugging outputs.  They mean basically the same thing bit-for-bit.

* sysctl fscache.object_max_active added to control concurrency.  The
  default value is nr_cpus clamped between 4 and
  WQ_UNBOUND_MAX_ACTIVE.

* slow_work_sleep_till_thread_needed() is replaced with fscache
  private implementation fscache_object_sleep_till_congested() which
  waits on fscache_object_wq congestion.

* debugfs support is dropped for now.  Tracing API based debug
  facility is planned to be added.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Acked-by: default avatarDavid Howells <dhowells@redhat.com>
parent e120153d
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -343,8 +343,8 @@ This will look something like:
	[root@andromeda ~]# head /proc/fs/fscache/objects
	OBJECT   PARENT   STAT CHLDN OPS OOP IPR EX READS EM EV F S | NETFS_COOKIE_DEF TY FL NETFS_DATA       OBJECT_KEY, AUX_DATA
	======== ======== ==== ===== === === === == ===== == == = = | ================ == == ================ ================
	   17e4b        2 ACTV     0   0   0   0  0     0 7b  4 0 8 | NFS.fh           DT  0 ffff88001dd82820 010006017edcf8bbc93b43298fdfbe71e50b57b13a172c0117f38472, e567634700000000000000000000000063f2404a000000000000000000000000c9030000000000000000000063f2404a
	   1693a        2 ACTV     0   0   0   0  0     0 7b  4 0 8 | NFS.fh           DT  0 ffff88002db23380 010006017edcf8bbc93b43298fdfbe71e50b57b1e0162c01a2df0ea6, 420ebc4a000000000000000000000000420ebc4a0000000000000000000000000e1801000000000000000000420ebc4a
	   17e4b        2 ACTV     0   0   0   0  0     0 7b  4 0 0 | NFS.fh           DT  0 ffff88001dd82820 010006017edcf8bbc93b43298fdfbe71e50b57b13a172c0117f38472, e567634700000000000000000000000063f2404a000000000000000000000000c9030000000000000000000063f2404a
	   1693a        2 ACTV     0   0   0   0  0     0 7b  4 0 0 | NFS.fh           DT  0 ffff88002db23380 010006017edcf8bbc93b43298fdfbe71e50b57b1e0162c01a2df0ea6, 420ebc4a000000000000000000000000420ebc4a0000000000000000000000000e1801000000000000000000420ebc4a

where the first set of columns before the '|' describe the object:

@@ -362,7 +362,7 @@ where the first set of columns before the '|' describe the object:
	EM	Object's event mask
	EV	Events raised on this object
	F	Object flags
	S	Object slow-work work item flags
	S	Object work item busy state mask (1:pending 2:running)

and the second set of columns describe the object's cookie, if present:

@@ -395,8 +395,8 @@ and the following paired letters:
	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
	S	Show objects that have work queued
	s	Show objects that don't have work queued

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

+6 −7
Original line number Diff line number Diff line
@@ -37,9 +37,9 @@ void __cachefiles_printk_object(struct cachefiles_object *object,

	printk(KERN_ERR "%sobject: OBJ%x\n",
	       prefix, object->fscache.debug_id);
	printk(KERN_ERR "%sobjstate=%s fl=%lx swfl=%lx ev=%lx[%lx]\n",
	printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n",
	       prefix, fscache_object_states[object->fscache.state],
	       object->fscache.flags, object->fscache.work.flags,
	       object->fscache.flags, work_busy(&object->fscache.work),
	       object->fscache.events,
	       object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK);
	printk(KERN_ERR "%sops=%u inp=%u exc=%u\n",
@@ -212,7 +212,7 @@ wait_for_old_object:

		/* if the object we're waiting for is queued for processing,
		 * then just put ourselves on the queue behind it */
		if (slow_work_is_queued(&xobject->fscache.work)) {
		if (work_pending(&xobject->fscache.work)) {
			_debug("queue OBJ%x behind OBJ%x immediately",
			       object->fscache.debug_id,
			       xobject->fscache.debug_id);
@@ -220,8 +220,7 @@ wait_for_old_object:
		}

		/* otherwise we sleep until either the object we're waiting for
		 * is done, or the slow-work facility wants the thread back to
		 * do other work */
		 * is done, or the fscache_object is congested */
		wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE);
		init_wait(&wait);
		requeue = false;
@@ -229,8 +228,8 @@ wait_for_old_object:
			prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
			if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags))
				break;
			requeue = slow_work_sleep_till_thread_needed(
				&object->fscache.work, &timeout);

			requeue = fscache_object_sleep_till_congested(&timeout);
		} while (timeout > 0 && !requeue);
		finish_wait(wq, &wait);

+7 −0
Original line number Diff line number Diff line
@@ -82,6 +82,13 @@ extern unsigned fscache_defer_lookup;
extern unsigned fscache_defer_create;
extern unsigned fscache_debug;
extern struct kobject *fscache_root;
extern struct workqueue_struct *fscache_object_wq;
DECLARE_PER_CPU(wait_queue_head_t, fscache_object_cong_wait);

static inline bool fscache_object_congested(void)
{
	return workqueue_congested(WORK_CPU_UNBOUND, fscache_object_wq);
}

extern int fscache_wait_bit(void *);
extern int fscache_wait_bit_interruptible(void *);
+76 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
#include "internal.h"

MODULE_DESCRIPTION("FS Cache Manager");
@@ -40,22 +41,89 @@ MODULE_PARM_DESC(fscache_debug,
		 "FS-Cache debugging mask");

struct kobject *fscache_root;
struct workqueue_struct *fscache_object_wq;

DEFINE_PER_CPU(wait_queue_head_t, fscache_object_cong_wait);

/* these values serve as lower bounds, will be adjusted in fscache_init() */
static unsigned fscache_object_max_active = 4;

#ifdef CONFIG_SYSCTL
static struct ctl_table_header *fscache_sysctl_header;

static int fscache_max_active_sysctl(struct ctl_table *table, int write,
				     void __user *buffer,
				     size_t *lenp, loff_t *ppos)
{
	struct workqueue_struct **wqp = table->extra1;
	unsigned int *datap = table->data;
	int ret;

	ret = proc_dointvec(table, write, buffer, lenp, ppos);
	if (ret == 0)
		workqueue_set_max_active(*wqp, *datap);
	return ret;
}

ctl_table fscache_sysctls[] = {
	{
		.procname	= "object_max_active",
		.data		= &fscache_object_max_active,
		.maxlen		= sizeof(unsigned),
		.mode		= 0644,
		.proc_handler	= fscache_max_active_sysctl,
		.extra1		= &fscache_object_wq,
	},
	{}
};

ctl_table fscache_sysctls_root[] = {
	{
		.procname	= "fscache",
		.mode		= 0555,
		.child		= fscache_sysctls,
	},
	{}
};
#endif

/*
 * initialise the fs caching module
 */
static int __init fscache_init(void)
{
	unsigned int nr_cpus = num_possible_cpus();
	unsigned int cpu;
	int ret;

	ret = slow_work_register_user(THIS_MODULE);
	if (ret < 0)
		goto error_slow_work;

	fscache_object_max_active =
		clamp_val(nr_cpus,
			  fscache_object_max_active, WQ_UNBOUND_MAX_ACTIVE);

	ret = -ENOMEM;
	fscache_object_wq = alloc_workqueue("fscache_object", WQ_UNBOUND,
					    fscache_object_max_active);
	if (!fscache_object_wq)
		goto error_object_wq;

	for_each_possible_cpu(cpu)
		init_waitqueue_head(&per_cpu(fscache_object_cong_wait, cpu));

	ret = fscache_proc_init();
	if (ret < 0)
		goto error_proc;

#ifdef CONFIG_SYSCTL
	ret = -ENOMEM;
	fscache_sysctl_header = register_sysctl_table(fscache_sysctls_root);
	if (!fscache_sysctl_header)
		goto error_sysctl;
#endif

	fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar",
					       sizeof(struct fscache_cookie),
					       0,
@@ -78,8 +146,14 @@ static int __init fscache_init(void)
error_kobj:
	kmem_cache_destroy(fscache_cookie_jar);
error_cookie_jar:
#ifdef CONFIG_SYSCTL
	unregister_sysctl_table(fscache_sysctl_header);
error_sysctl:
#endif
	fscache_proc_cleanup();
error_proc:
	destroy_workqueue(fscache_object_wq);
error_object_wq:
	slow_work_unregister_user(THIS_MODULE);
error_slow_work:
	return ret;
@@ -96,7 +170,9 @@ static void __exit fscache_exit(void)

	kobject_put(fscache_root);
	kmem_cache_destroy(fscache_cookie_jar);
	unregister_sysctl_table(fscache_sysctl_header);
	fscache_proc_cleanup();
	destroy_workqueue(fscache_object_wq);
	slow_work_unregister_user(THIS_MODULE);
	printk(KERN_NOTICE "FS-Cache: Unloaded\n");
}
+5 −6
Original line number Diff line number Diff line
@@ -34,8 +34,8 @@ struct fscache_objlist_data {
#define FSCACHE_OBJLIST_CONFIG_NOREADS	0x00000200	/* show objects without active reads */
#define FSCACHE_OBJLIST_CONFIG_EVENTS	0x00000400	/* show objects with events */
#define FSCACHE_OBJLIST_CONFIG_NOEVENTS	0x00000800	/* show objects without no events */
#define FSCACHE_OBJLIST_CONFIG_WORK	0x00001000	/* show objects with slow work */
#define FSCACHE_OBJLIST_CONFIG_NOWORK	0x00002000	/* show objects without slow work */
#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 */
};
@@ -231,12 +231,11 @@ static int fscache_objlist_show(struct seq_file *m, void *v)
		       READS, NOREADS);
		FILTER(obj->events & obj->event_mask,
		       EVENTS, NOEVENTS);
		FILTER(obj->work.flags & ~(1UL << SLOW_WORK_VERY_SLOW),
		       WORK, NOWORK);
		FILTER(work_busy(&obj->work), WORK, NOWORK);
	}

	seq_printf(m,
		   "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1lx | ",
		   "%8x %8x %s %5u %3u %3u %3u %2u %5u %2lx %2lx %1lx %1x | ",
		   obj->debug_id,
		   obj->parent ? obj->parent->debug_id : -1,
		   fscache_object_states_short[obj->state],
@@ -249,7 +248,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v)
		   obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK,
		   obj->events,
		   obj->flags,
		   obj->work.flags);
		   work_busy(&obj->work));

	no_cookie = true;
	keylen = auxlen = 0;
Loading