workqueue: replace slow-work with workqueue
Subsystems (7)
PATCH 1/1 workqueue: replace slow-work with workqueue
Hello,
With cmwq, workqueue now can handle all use cases of slow-work. This patchset converts all slow-work users to use workqueue instead and remove slow-work from the kernel. The following users are converted.
* fscache-object: a dedicated unbound workqueue is used.
* fscache-operation: a dedicated unbound workqueue is used.
* cifs: system_nrt_wq is used.
* gfs2: a dedicated nrt workqueue is used.
* drm: system_nrt_wq is used.
cifs and gfs2 conversions largely remained unchanged from the last posting. fscache conversions are updated to use unbound workqueues and debugfs support is dropped for now (workqueue debugfs support is not included in wq#for-next). Tracing API based debug implementation is planned.
The drm conversion is new but the conversion is mostly trivial and my simplistic testing involving plugging and unplugging monitor works fine.
David, fscache conversion now uses unbound workqueues and it should behave virtually the same with slow-work.
As whether cmwq will get merged isn't completely clear yet, I think it would be better to keep these changes in the wq tree instead of scattering them around multiple trees. Would the maintainers be okay with that?
This patchset contains the following patches.
0001-fscache-convert-object-to-use-workqueue-instead-of-s.patch 0002-fscache-convert-operation-to-use-workqueue-instead-o.patch 0003-fscache-drop-references-to-slow-work.patch 0004-cifs-use-workqueue-instead-of-slow-work.patch 0005-gfs2-use-workqueue-instead-of-slow-work.patch 0006-drm-use-workqueue-instead-of-slow-work.patch 0007-slow-work-kill-it.patch
It's on top of the following branch.
git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git for-next
and is available in the following git branch
git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git review-slow-work-conversion
and contains the following changes.
Documentation/filesystems/caching/fscache.txt | 10 Documentation/slow-work.txt | 322 ------- drivers/gpu/drm/drm_crtc_helper.c | 29 fs/cachefiles/namei.c | 13 fs/cachefiles/rdwr.c | 4 fs/cifs/Kconfig | 1 fs/cifs/cifsfs.c | 5 fs/cifs/cifsglob.h | 8 fs/cifs/dir.c | 2 fs/cifs/file.c | 30 fs/cifs/misc.c | 20 fs/fscache/Kconfig | 1 fs/fscache/internal.h | 8 fs/fscache/main.c | 104 ++ fs/fscache/object-list.c | 11 fs/fscache/object.c | 106 +- fs/fscache/operation.c | 67 - fs/fscache/page.c | 36 fs/gfs2/Kconfig | 1 fs/gfs2/incore.h | 3 fs/gfs2/main.c | 14 fs/gfs2/ops_fstype.c | 8 fs/gfs2/recovery.c | 54 - fs/gfs2/recovery.h | 6 fs/gfs2/sys.c | 3 include/drm/drm_crtc.h | 3 include/linux/fscache-cache.h | 47 - include/linux/slow-work.h | 163 --- init/Kconfig | 24 kernel/Makefile | 2 kernel/slow-work-debugfs.c | 227 ----- kernel/slow-work.c | 1068 -------------------------- kernel/slow-work.h | 72 - kernel/sysctl.c | 8 34 files changed, 292 insertions(+), 2188 deletions(-)
Thanks.
--
tejun
PATCH 1/7 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.
--- Documentation/filesystems/caching/fscache.txt | 10 +- fs/cachefiles/namei.c | 13 ++-- fs/fscache/internal.h | 7 ++ fs/fscache/main.c | 76 ++++++++++++++++++ fs/fscache/object-list.c | 11 +-- fs/fscache/object.c | 106 ++++++++++++------------ include/linux/fscache-cache.h | 9 ++- 7 files changed, 158 insertions(+), 74 deletions(-)
Documentation/filesystems/caching/fscache.txt +5 -5
@@ -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:
fs/cachefiles/namei.c +6 -7
@@ -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);
fs/fscache/internal.h +7 -0
@@ -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 *);
fs/fscache/main.c +76 -0
119 lines not on this page · raw message
fs/fscache/object-list.c +5 -6
@@ -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 ;
fs/fscache/object.c +53 -53
178 lines not on this page · raw message
include/linux/fscache-cache.h +6 -3
@@ -21,6 +21,7 @@#include <linux/fscache.h> #include <linux/sched.h> #include <linux/slow-work.h> +#include <linux/workqueue.h> #define NR_MAXCACHES BITS_PER_LONG
@@ -389,7 +390,7 @@ struct fscache_object {struct fscache_cache *cache;/* cache that supplied this object */ struct fscache_cookie *cookie;/* netfs's file/index object */ struct fscache_object *parent;/* parent object */ -struct slow_work work;/* attention scheduling record */ +struct work_struct work;/* attention scheduling record */ struct list_head dependents;/* FIFO of dependent objects */ struct list_head dep_link;/* link in parent's dependents list */ struct list_head pending_ops;/* unstarted operations on this object */
@@ -411,7 +412,7 @@ extern const char *fscache_object_states[]; (test_bit (FSCACHE_IOERROR , &(obj)->cache->flags) && \ (obj)->state >= FSCACHE_OBJECT_DYING) -extern const struct slow_work_ops fscache_object_slow_work_ops; +extern void fscache_object_work_func (struct work_struct *work);/** * fscache_object_init - Initialise a cache object description
@@ -433,7 +434,7 @@ void fscache_object_init(struct fscache_object *object,spin_lock_init (&object->lock);INIT_LIST_HEAD (&object->cache_link);INIT_HLIST_NODE (&object->cookie_link); -vslow_work_init (&object->work, &fscache_object_slow_work_ops); +INIT_WORK (&object->work, fscache_object_work_func);INIT_LIST_HEAD (&object->dependents);INIT_LIST_HEAD (&object->dep_link);INIT_LIST_HEAD (&object->pending_ops);
@@ -534,6 +535,8 @@ extern void fscache_io_error(struct fscache_cache *cache);extern void fscache_mark_pages_cached (struct fscache_retrieval *op,struct pagevec *pagevec); +extern bool fscache_object_sleep_till_congested (signed long *timeoutp); +extern enum fscache_checkaux fscache_check_aux (struct fscache_object *object,const void *data,uint16_t datalen);
Signature · 1 line
1.6.4.2
PATCH 2/7 fscache: convert operation to use workqueue instead of slow-work
In reply to Tejun HeoMake fscache operation to use only workqueue instead of combination of workqueue and slow-work. FSCACHE_OP_SLOW is dropped and FSCACHE_OP_FAST is renamed to FSCACHE_OP_ASYNC and uses newly added fscache_op_wq workqueue to execute op->processor(). fscache_operation_init_slow() is dropped and fscache_operation_init() now takes @processor argument directly.
* Unbound workqueue is used.
* fscache_retrieval_work() is no longer necessary as OP_ASYNC now does the equivalent thing.
* sysctl fscache.operation_max_active added to control concurrency. The default value is nr_cpus clamped between 2 and WQ_UNBOUND_MAX_ACTIVE.
* debugfs support is dropped for now. Tracing API based debug facility is planned to be added.
--- fs/cachefiles/rdwr.c | 4 +- fs/fscache/internal.h | 1 + fs/fscache/main.c | 23 ++++++++++++++ fs/fscache/operation.c | 67 +++++------------------------------------ fs/fscache/page.c | 36 +++++----------------- include/linux/fscache-cache.h | 37 +++++++---------------- 6 files changed, 53 insertions(+), 115 deletions(-)
fs/cachefiles/rdwr.c +2 -2
@@ -422,7 +422,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, shift =PAGE_SHIFT - inode->i_sb->s_blocksize_bits; op->op.flags &=FSCACHE_OP_KEEP_FLAGS ; - op->op.flags |=FSCACHE_OP_FAST ; + op->op.flags |=FSCACHE_OP_ASYNC ; op->op.processor = cachefiles_read_copier;pagevec_init (&pagevec,0 );
@@ -729,7 +729,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,pagevec_init (&pagevec,0 ); op->op.flags &=FSCACHE_OP_KEEP_FLAGS ; - op->op.flags |=FSCACHE_OP_FAST ; + op->op.flags |=FSCACHE_OP_ASYNC ; op->op.processor = cachefiles_read_copier;INIT_LIST_HEAD (&backpages);
fs/fscache/internal.h +1 -0
@@ -83,6 +83,7 @@ extern unsigned fscache_defer_create;extern unsigned fscache_debug;extern struct kobject *fscache_root;extern struct workqueue_struct *fscache_object_wq; +extern struct workqueue_struct *fscache_op_wq;DECLARE_PER_CPU (wait_queue_head_t, fscache_object_cong_wait);static inline bool fscache_object_congested (void )
fs/fscache/main.c +23 -0
@@ -42,11 +42,13 @@ MODULE_PARM_DESC(fscache_debug,struct kobject *fscache_root;struct workqueue_struct *fscache_object_wq; +struct workqueue_struct *fscache_op_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 ; +static unsigned fscache_op_max_active =2 ;#ifdef CONFIG_SYSCTL static struct ctl_table_header *fscache_sysctl_header;
@@ -74,6 +76,14 @@ ctl_table fscache_sysctls[] = { .proc_handler = fscache_max_active_sysctl, .extra1 = &fscache_object_wq, }, + { + .procname = "operation_max_active", + .data = &fscache_op_max_active, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = fscache_max_active_sysctl, + .extra1 = &fscache_op_wq, + }, {} };
@@ -110,6 +120,16 @@ static int __init fscache_init(void)if (!fscache_object_wq) goto error_object_wq; + fscache_op_max_active = +clamp_val (fscache_object_max_active /2 , + fscache_op_max_active,WQ_UNBOUND_MAX_ACTIVE ); + + ret = -ENOMEM ; + fscache_op_wq =alloc_workqueue ("fscache_operation" ,WQ_UNBOUND , + fscache_op_max_active); +if (!fscache_op_wq) + goto error_op_wq; +for_each_possible_cpu (cpu)init_waitqueue_head (&per_cpu (fscache_object_cong_wait, cpu));
@@ -152,6 +172,8 @@ error_sysctl:#endif fscache_proc_cleanup (); error_proc: +destroy_workqueue (fscache_op_wq); +error_op_wq:destroy_workqueue (fscache_object_wq); error_object_wq:slow_work_unregister_user (THIS_MODULE );
@@ -172,6 +194,7 @@ static void __exit fscache_exit(void)kmem_cache_destroy (fscache_cookie_jar);unregister_sysctl_table (fscache_sysctl_header);fscache_proc_cleanup (); +destroy_workqueue (fscache_op_wq);destroy_workqueue (fscache_object_wq);slow_work_unregister_user (THIS_MODULE );printk (KERN_NOTICE "FS-Cache: Unloaded\n" );
fs/fscache/operation.c +8 -59
91 lines not on this page · raw message
fs/fscache/page.c +8 -28
@@ -105,7 +105,7 @@ bool __fscache_maybe_release_page(struct fscache_cookie *cookie, page_busy:/* we might want to wait here, but that could deadlock the allocator as -* the slow-work threads writing to the cache may all end up sleeping +* the work threads writing to the cache may all end up sleeping * on memory allocation */ fscache_stat (&fscache_n_store_vmscan_busy);return false;
@@ -188,9 +188,8 @@ int __fscache_attr_changed(struct fscache_cookie *cookie)return -ENOMEM ; } -fscache_operation_init (op,NULL ); -fscache_operation_init_slow (op, fscache_attr_changed_op); - op->flags =FSCACHE_OP_SLOW | (1 <<FSCACHE_OP_EXCLUSIVE ); +fscache_operation_init (op, fscache_attr_changed_op,NULL ); + op->flags =FSCACHE_OP_ASYNC | (1 <<FSCACHE_OP_EXCLUSIVE );fscache_set_op_name (op,"Attr" );spin_lock (&cookie->lock);
@@ -218,24 +217,6 @@ nobufs:EXPORT_SYMBOL (__fscache_attr_changed);/* -* handle secondary execution given to a retrieval op on behalf of the -* cache -*/ -static void fscache_retrieval_work (struct work_struct *work) -{ -struct fscache_retrieval *op = - container_of(work, struct fscache_retrieval, op.fast_work); -unsigned long start; - -_enter ("{OP%x}" , op->op.debug_id); - - start = jiffies; - op->op.processor (&op->op); -fscache_hist (fscache_ops_histogram, start); -fscache_put_operation (&op->op); -} - -/* * release a retrieval op reference */ static void fscache_release_retrieval_op (struct fscache_operation *_op)
@@ -269,13 +250,12 @@ static struct fscache_retrieval *fscache_alloc_retrieval(return NULL ; } -fscache_operation_init (&op->op, fscache_release_retrieval_op); +fscache_operation_init (&op->op,NULL , fscache_release_retrieval_op); op->op.flags =FSCACHE_OP_MYTHREAD | (1 <<FSCACHE_OP_WAITING ); op->mapping = mapping; op->end_io_func = end_io_func; op->context = context; op->start_time = jiffies; -INIT_WORK (&op->op.fast_work, fscache_retrieval_work);INIT_LIST_HEAD (&op->to_do);fscache_set_op_name (&op->op,"Retr" );return op;
@@ -795,9 +775,9 @@ int __fscache_write_page(struct fscache_cookie *cookie,if (!op) goto nomem; -fscache_operation_init (&op->op, fscache_release_write_op); -fscache_operation_init_slow (&op->op, fscache_write_op); - op->op.flags =FSCACHE_OP_SLOW | (1 <<FSCACHE_OP_WAITING ); +fscache_operation_init (&op->op, fscache_write_op, + fscache_release_write_op); + op->op.flags =FSCACHE_OP_ASYNC | (1 <<FSCACHE_OP_WAITING );fscache_set_op_name (&op->op,"Write1" ); ret =radix_tree_preload (gfp & ~__GFP_HIGHMEM);
@@ -852,7 +832,7 @@ int __fscache_write_page(struct fscache_cookie *cookie,fscache_stat (&fscache_n_store_ops);fscache_stat (&fscache_n_stores_ok); -/* the slow work queue now carries its own ref on the object */ +/* the work queue now carries its own ref on the object */ fscache_put_operation (&op->op);_leave (" = 0" );return 0 ;
include/linux/fscache-cache.h +11 -26
@@ -77,18 +77,14 @@ typedef void (*fscache_operation_release_t)(struct fscache_operation *op);typedef void (*fscache_operation_processor_t )(struct fscache_operation *op);struct fscache_operation { -union { -struct work_struct fast_work;/* record for fast ops */ -struct slow_work slow_work;/* record for (very) slow ops */ - }; +struct work_struct work;/* record for async ops */ struct list_head pend_link;/* link in object->pending_ops */ struct fscache_object *object;/* object to be operated upon */ unsigned long flags;#define FSCACHE_OP_TYPE 0x000f/* operation type */ -#define FSCACHE_OP_FAST 0x0001/* - fast op, processor may not sleep for disk */ -#define FSCACHE_OP_SLOW 0x0002/* - (very) slow op, processor may sleep for disk */ -#define FSCACHE_OP_MYTHREAD 0x0003/* - processing is done be issuing thread, not pool */ +#define FSCACHE_OP_ASYNC 0x0001/* - async op, processor may sleep for disk */ +#define FSCACHE_OP_MYTHREAD 0x0002/* - processing is done be issuing thread, not pool */ #define FSCACHE_OP_WAITING 4/* cleared when op is woken */ #define FSCACHE_OP_EXCLUSIVE 5/* exclusive op, other ops must wait */ #define FSCACHE_OP_DEAD 6/* op is now dead */
@@ -106,7 +102,8 @@ struct fscache_operation {/* operation releaser */ fscache_operation_release_t release; -#ifdef CONFIG_SLOW_WORK_DEBUG +#ifdef CONFIG_WORKQUEUE_DEBUGFS +struct work_struct put_work;/* work to delay operation put */ const char *name;/* operation name */ const char *state;/* operation state */ #define fscache_set_op_name (OP ,N ) do { (OP)->name = (N); } while(0)
@@ -118,7 +115,7 @@ struct fscache_operation { };extern atomic_t fscache_op_debug_id; -extern const struct slow_work_ops fscache_op_slow_work_ops; +extern void fscache_op_work_func (struct work_struct *work);extern void fscache_enqueue_operation (struct fscache_operation *);extern void fscache_put_operation (struct fscache_operation *);
@@ -129,33 +126,21 @@ extern void fscache_put_operation(struct fscache_operation *);* @release: The release function to assign * * Do basic initialisation of an operation. The caller must still set flags, -* object, either fast_work or slow_work if necessary, and processor if needed. +* object and processor if needed. */ static inline void fscache_operation_init (struct fscache_operation *op, -fscache_operation_release_t release) +fscache_operation_processor_t processor, +fscache_operation_release_t release) { +INIT_WORK (&op->work, fscache_op_work_func);atomic_set (&op->usage,1 ); op->debug_id =atomic_inc_return (&fscache_op_debug_id); + op->processor = processor; op->release = release;INIT_LIST_HEAD (&op->pend_link);fscache_set_op_state (op,"Init" ); } -/** -* fscache_operation_init_slow - Do additional initialisation of a slow op -* @op: The operation to initialise -* @processor: The processor function to assign -* -* Do additional initialisation of an operation as required for slow work. -*/ -static inline -void fscache_operation_init_slow (struct fscache_operation *op, -fscache_operation_processor_t processor) -{ - op->processor = processor; -slow_work_init (&op->slow_work, &fscache_op_slow_work_ops); -} -/* * data read operation */
Signature · 1 line
1.6.4.2
PATCH 3/7 fscache: drop references to slow-work
In reply to Tejun Heofscache no longer uses slow-work. Drop references to it.
--- fs/fscache/Kconfig | 1 - fs/fscache/main.c | 7 ------- include/linux/fscache-cache.h | 1 - 3 files changed, 0 insertions(+), 9 deletions(-)
fs/fscache/Kconfig +0 -1
@@ -1,7 +1,6 @@ config FSCACHE tristate "General filesystem local caching manager" - select SLOW_WORK help This option enables a generic filesystem caching manager that can be used by various network and other filesystems to cache data locally.
fs/fscache/main.c +0 -7
@@ -106,10 +106,6 @@ static int __init fscache_init(void)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 );
@@ -176,8 +172,6 @@ error_proc: error_op_wq:destroy_workqueue (fscache_object_wq); error_object_wq: -slow_work_unregister_user (THIS_MODULE ); -error_slow_work:return ret; }
@@ -196,7 +190,6 @@ static void __exit fscache_exit(void)fscache_proc_cleanup ();destroy_workqueue (fscache_op_wq);destroy_workqueue (fscache_object_wq); -slow_work_unregister_user (THIS_MODULE );printk (KERN_NOTICE "FS-Cache: Unloaded\n" ); }
include/linux/fscache-cache.h +0 -1
@@ -20,7 +20,6 @@#include <linux/fscache.h> #include <linux/sched.h> -#include <linux/slow-work.h> #include <linux/workqueue.h> #define NR_MAXCACHES BITS_PER_LONG
Signature · 1 line
1.6.4.2
PATCH 4/7 cifs: use workqueue instead of slow-work
In reply to Tejun HeoWorkqueue can now handle high concurrency. Use system_nrt_wq instead of slow-work.
* Updated is_valid_oplock_break() to not call cifs_oplock_break_put() as advised by Steve French. It might cause deadlock. Instead, reference is increased after queueing succeeded and cifs_oplock_break() briefly grabs GlobalSMBSeslock before putting the cfile to make sure it doesn't put before the matching get is finished.
* Anton Blanchard reported that cifs conversion was using now gone system_single_wq. Use system_nrt_wq which provides non-reentrance guarantee which is enough and much better.
--- fs/cifs/Kconfig | 1 - fs/cifs/cifsfs.c | 5 ----- fs/cifs/cifsglob.h | 8 +++++--- fs/cifs/dir.c | 2 +- fs/cifs/file.c | 30 +++++++++++++----------------- fs/cifs/misc.c | 20 ++++++++++++-------- 6 files changed, 31 insertions(+), 35 deletions(-)
fs/cifs/Kconfig +0 -1
@@ -2,7 +2,6 @@ config CIFS tristate "CIFS support (advanced network filesystem, SMBFS successor)" depends on INET select NLS - select SLOW_WORK help This is the client VFS module for the Common Internet File System (CIFS) protocol which is the successor to the Server Message Block
fs/cifs/cifsfs.c +0 -5
@@ -917,15 +917,10 @@ init_cifs(void)if (rc) goto out_unregister_key_type;#endif - rc =slow_work_register_user (THIS_MODULE ); -if (rc) - goto out_unregister_resolver_key;return 0 ; - out_unregister_resolver_key:#ifdef CONFIG_CIFS_DFS_UPCALL -unregister_key_type (&key_type_dns_resolver); out_unregister_key_type:#endif #ifdef CONFIG_CIFS_UPCALL
fs/cifs/cifsglob.h +5 -3
@@ -19,7 +19,7 @@#include <linux/in.h> #include <linux/in6.h> #include <linux/slab.h> -#include <linux/slow-work.h> +#include <linux/workqueue.h> #include "cifs_fs_sb.h" #include "cifsacl.h" /*
@@ -363,7 +363,7 @@ struct cifsFileInfo {atomic_t count;/* reference count */ struct mutex fh_mutex;/* prevents reopen race after dead ses*/ struct cifs_search_info srch_inf; -struct slow_work oplock_break;/* slow_work job for oplock breaks */ +struct work_struct oplock_break;/* work for oplock breaks */ };/* Take a reference on the file private data */
@@ -732,4 +732,6 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ -extern const struct slow_work_ops cifs_oplock_break_ops; +void cifs_oplock_break (struct work_struct *work); +void cifs_oplock_break_get (struct cifsFileInfo *cfile); +void cifs_oplock_break_put (struct cifsFileInfo *cfile);
fs/cifs/dir.c +1 -1
@@ -162,7 +162,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,mutex_init (&pCifsFile->lock_mutex);INIT_LIST_HEAD (&pCifsFile->llist);atomic_set (&pCifsFile->count,1 ); -slow_work_init (&pCifsFile->oplock_break, &cifs_oplock_break_ops); +INIT_WORK (&pCifsFile->oplock_break, cifs_oplock_break);write_lock (&GlobalSMBSeslock);list_add (&pCifsFile->tlist, &cifs_sb->tcon->openFileList);
fs/cifs/file.c +13 -17
@@ -2295,8 +2295,7 @@ out:return rc; } -static void -cifs_oplock_break (struct slow_work *work) +void cifs_oplock_break (struct work_struct *work) { struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, oplock_break);
@@ -2333,33 +2332,30 @@ cifs_oplock_break(struct slow_work *work) LOCKING_ANDX_OPLOCK_RELEASE, false);cFYI (1 ,"Oplock release rc = %d" , rc); } + +/* +* We might have kicked in before is_valid_oplock_break() +* finished grabbing reference for us. Make sure it's done by +* waiting for GlobalSMSSeslock. +*/ +write_lock (&GlobalSMBSeslock); +write_unlock (&GlobalSMBSeslock); + +cifs_oplock_break_put (cfile); } -static int -cifs_oplock_break_get (struct slow_work *work) +void cifs_oplock_break_get (struct cifsFileInfo *cfile) { - struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, - oplock_break);mntget (cfile->mnt);cifsFileInfo_get (cfile); -return 0 ; } -static void -cifs_oplock_break_put (struct slow_work *work) +void cifs_oplock_break_put (struct cifsFileInfo *cfile) { - struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, - oplock_break);mntput (cfile->mnt);cifsFileInfo_put (cfile); } -const struct slow_work_ops cifs_oplock_break_ops = { - .get_ref = cifs_oplock_break_get, - .put_ref = cifs_oplock_break_put, - .execute = cifs_oplock_break, -}; -const struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, .readpages = cifs_readpages,
fs/cifs/misc.c +12 -8
@@ -498,7 +498,6 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)struct cifsTconInfo *tcon;struct cifsInodeInfo *pCifsInode;struct cifsFileInfo *netfile; -int rc;cFYI (1 ,"Checking for oplock break or dnotify response" ); if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
@@ -583,13 +582,18 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) pCifsInode->clientCanCacheAll = false;if (pSMB->OplockLevel ==0 ) pCifsInode->clientCanCacheRead = false; - rc =slow_work_enqueue (&netfile->oplock_break); -if (rc) { -cERROR (1 ,"failed to enqueue oplock " -"break: %d\n" , rc); - }else { - netfile->oplock_break_cancelled = false; - } + +/* +* cifs_oplock_break_put() can't be called +* from here. Get reference after queueing +* succeeded. cifs_oplock_break() will +* synchronize using GlobalSMSSeslock. +*/ +if (queue_work (system_nrt_wq, + &netfile->oplock_break)) +cifs_oplock_break_get (netfile); + netfile->oplock_break_cancelled = false; +read_unlock (&GlobalSMBSeslock);read_unlock (&cifs_tcp_ses_lock);return true;
Signature · 1 line
1.6.4.2
Re: [PATCH 4/7] cifs: use workqueue instead of slow-work
Quoted 17 lines · Tejun Heo
Workqueue can now handle high concurrency. Use
system_nrt_wqinstead of slow-work.* Updated
is_valid_oplock_break()to not callcifs_oplock_break_put()as advised by Steve French. It might cause deadlock. Instead, reference is increased after queueing succeeded andcifs_oplock_break()briefly grabs GlobalSMBSeslock before putting the cfile to make sure it doesn't put before the matching get is finished.* Anton Blanchard reported that cifs conversion was using now gone
system_single_wq. Usesystem_nrt_wqwhich provides non-reentrance guarantee which is enough and much better.Signed-off-by Tejun Heo <[email protected]>Cc Steve French <[email protected]>Cc Anton Blanchard <[email protected]>
Quoted 8 lines
---
fs/cifs/Kconfig | 1 -
fs/cifs/cifsfs.c | 5 -----fs/cifs/cifsglob.h| 8 +++++---fs/cifs/dir.c| 2 +-
fs/cifs/file.c | 30 +++++++++++++-----------------fs/cifs/misc.c| 20 ++++++++++++--------6 files changed, 31 insertions(+), 35 deletions(-)
Signature · 3 lines
Thanks, Steve
PATCH 5/7 gfs2: use workqueue instead of slow-work
In reply to Tejun HeoWorkqueue can now handle high concurrency. Convert gfs to use workqueue instead of slow-work.
* Steven pointed out that recovery path might be run from allocation path and thus requires forward progress guarantee without memory allocation. Create and use gfs_recovery_wq with rescuer. Please note that forward progress wasn't guaranteed with slow-work.
* Updated to use non-reentrant workqueue.
--- fs/gfs2/Kconfig | 1 - fs/gfs2/incore.h | 3 +- fs/gfs2/main.c | 14 +++++++----- fs/gfs2/ops_fstype.c | 8 +++--- fs/gfs2/recovery.c | 54 +++++++++++++++++++------------------------------ fs/gfs2/recovery.h | 6 +++- fs/gfs2/sys.c | 3 +- 7 files changed, 40 insertions(+), 49 deletions(-)
fs/gfs2/Kconfig +0 -1
@@ -7,7 +7,6 @@ config GFS2_FS select IP_SCTP if DLM_SCTP select FS_POSIX_ACL select CRC32 - select SLOW_WORK select QUOTACTL help A cluster filesystem.
fs/gfs2/incore.h +1 -2
@@ -12,7 +12,6 @@#include <linux/fs.h> #include <linux/workqueue.h> -#include <linux/slow-work.h> #include <linux/dlm.h> #include <linux/buffer_head.h>
@@ -383,7 +382,7 @@ struct gfs2_journal_extent {struct gfs2_jdesc {struct list_head jd_list;struct list_head extent_list; -struct slow_work jd_work; +struct work_struct jd_work;struct inode *jd_inode;unsigned long jd_flags;#define JDF_RECOVERY 1
fs/gfs2/main.c +8 -6
@@ -15,7 +15,6 @@#include <linux/init.h> #include <linux/gfs2_ondisk.h> #include <asm/atomic.h> -#include <linux/slow-work.h> #include "gfs2.h" #include "incore.h"
@@ -24,6 +23,7 @@#include "util.h" #include "glock.h" #include "quota.h" +#include "recovery.h" static struct shrinker qd_shrinker = { .shrink = gfs2_shrink_qd_memory,
@@ -138,9 +138,11 @@ static int __init init_gfs2_fs(void)if (error) goto fail_unregister; - error =slow_work_register_user (THIS_MODULE ); -if (error) - goto fail_slow; + error = -ENOMEM ; + gfs_recovery_wq =alloc_workqueue ("gfs_recovery" , +WQ_NON_REENTRANT |WQ_RESCUER ,0 ); +if (!gfs_recovery_wq) + goto fail_wq;gfs2_register_debugfs ();
@@ -148,7 +150,7 @@ static int __init init_gfs2_fs(void)return 0 ; -fail_slow: +fail_wq:unregister_filesystem (&gfs2meta_fs_type); fail_unregister:unregister_filesystem (&gfs2_fs_type);
@@ -190,7 +192,7 @@ static void __exit exit_gfs2_fs(void)gfs2_unregister_debugfs ();unregister_filesystem (&gfs2_fs_type);unregister_filesystem (&gfs2meta_fs_type); -slow_work_unregister_user (THIS_MODULE ); +destroy_workqueue (gfs_recovery_wq);kmem_cache_destroy (gfs2_quotad_cachep);kmem_cache_destroy (gfs2_rgrpd_cachep);
fs/gfs2/ops_fstype.c +4 -4
@@ -17,7 +17,6 @@#include <linux/namei.h> #include <linux/mount.h> #include <linux/gfs2_ondisk.h> -#include <linux/slow-work.h> #include <linux/quotaops.h> #include "gfs2.h"
@@ -673,7 +672,7 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)break ;INIT_LIST_HEAD (&jd->extent_list); -slow_work_init (&jd->jd_work, &gfs2_recover_ops); +INIT_WORK (&jd->jd_work, gfs2_recover_func); jd->jd_inode =gfs2_lookupi (sdp->sd_jindex, &name,1 );if (!jd->jd_inode ||IS_ERR (jd->jd_inode)) {if (!jd->jd_inode)
@@ -782,7 +781,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)if (sdp->sd_lockstruct.ls_first) {unsigned int x;for (x =0 ; x < sdp->sd_journals; x++) { - error =gfs2_recover_journal (gfs2_jdesc_find (sdp, x)); + error =gfs2_recover_journal (gfs2_jdesc_find (sdp, x), + true);if (error) {fs_err (sdp,"error recovering journal %u: %d\n" , x, error);
@@ -792,7 +792,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)gfs2_others_may_mount (sdp); }else if (!sdp->sd_args.ar_spectator) { - error =gfs2_recover_journal (sdp->sd_jdesc); + error =gfs2_recover_journal (sdp->sd_jdesc, true);if (error) {fs_err (sdp,"error recovering my journal: %d\n" , error); goto fail_jinode_gh;
fs/gfs2/recovery.c +21 -33
96 lines not on this page · raw message
fs/gfs2/recovery.h +4 -2
@@ -12,6 +12,8 @@#include "incore.h" +extern struct workqueue_struct *gfs_recovery_wq; +static inline void gfs2_replay_incr_blk (struct gfs2_sbd *sdp,unsigned int *blk) {if (++*blk == sdp->sd_jdesc->jd_blocks)
@@ -27,8 +29,8 @@ extern void gfs2_revoke_clean(struct gfs2_sbd *sdp);extern int gfs2_find_jhead (struct gfs2_jdesc *jd,struct gfs2_log_header_host *head); -extern int gfs2_recover_journal (struct gfs2_jdesc *gfs2_jd); -extern struct slow_work_ops gfs2_recover_ops; +extern int gfs2_recover_journal (struct gfs2_jdesc *gfs2_jd,bool wait); +extern void gfs2_recover_func (struct work_struct *work);#endif /* __RECOVERY_DOT_H__ */
fs/gfs2/sys.c +2 -1
@@ -25,6 +25,7 @@#include "quota.h" #include "util.h" #include "glops.h" +#include "recovery.h" struct gfs2_attr {struct attribute attr;
@@ -352,7 +353,7 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)list_for_each_entry (jd, &sdp->sd_jindex_list, jd_list) {if (jd->jd_jid != jid)continue ; - rv =slow_work_enqueue (&jd->jd_work); + rv =gfs2_recover_journal (jd, false);break ; } out:
Signature · 1 line
1.6.4.2
Re: [PATCH 5/7] gfs2: use workqueue instead of slow-work
Quoted 8 lines · Tejun Heo
Workqueue can now handle high concurrency. Convert gfs to use workqueue instead of slow-work.
* Steven pointed out that recovery path might be run from allocation path and thus requires forward progress guarantee without memory allocation. Create and use
gfs_recovery_wqwith rescuer. Please note that forward progress wasn't guaranteed with slow-work.
Quoted 4 lines
* Updated to use non-reentrant workqueue.
Signed-off-by Tejun Heo <[email protected]>Cc Steven Whitehouse <[email protected]>
Steven, can you please review the change?
Thanks.
Signature · 1 line
tejun
Re: [PATCH 5/7] gfs2: use workqueue instead of slow-work
In reply to Tejun HeoHi,
Quoted 8 lines · Tejun Heo
Workqueue can now handle high concurrency. Convert gfs to use workqueue instead of slow-work.
* Steven pointed out that recovery path might be run from allocation path and thus requires forward progress guarantee without memory allocation. Create and use
gfs_recovery_wqwith rescuer. Please note that forward progress wasn't guaranteed with slow-work.
Quoted 4 lines
* Updated to use non-reentrant workqueue.
Signed-off-by Tejun Heo <[email protected]>Cc Steven Whitehouse <[email protected]>
I'm assuming that you'll push this along with the workqueue changes? Probably easier than pushing it through my tree,
Steve.
Re: [PATCH 5/7] gfs2: use workqueue instead of slow-work
Quoted 11 lines · Steven Whitehouse
Hi,
Quoted 8 lines · Tejun Heo
Workqueue can now handle high concurrency. Convert gfs to use workqueue instead of slow-work.
* Steven pointed out that recovery path might be run from allocation path and thus requires forward progress guarantee without memory allocation. Create and use
gfs_recovery_wqwith rescuer. Please note that forward progress wasn't guaranteed with slow-work.
Quoted 8 lines
Quoted 4 lines
* Updated to use non-reentrant workqueue.
Signed-off-by Tejun Heo <[email protected]>Cc Steven Whitehouse <[email protected]>I'm assuming that you'll push this along with the workqueue changes? Probably easier than pushing it through my tree,
Yeah, I'll route this through the wq tree with all other workqueue related changes.
Thank you.
Signature · 1 line
tejun
PATCH 6/7 drm: use workqueue instead of slow-work
In reply to Tejun HeoWorkqueue can now handle high concurrency. Convert drm_crtc_helper to use system_nrt_wq instead of slow-work. The conversion is mostly straight forward. One difference is that drm_helper_hpd_irq_event() no longer blocks and can be called from any context.
--- drivers/gpu/drm/drm_crtc_helper.c | 29 ++++++++++------------------- include/drm/drm_crtc.h | 3 +-- 2 files changed, 11 insertions(+), 21 deletions(-)
drivers/gpu/drm/drm_crtc_helper.c +10 -19
@@ -808,13 +808,11 @@ int drm_helper_resume_force_mode(struct drm_device *dev) }EXPORT_SYMBOL (drm_helper_resume_force_mode); -static struct slow_work_ops output_poll_ops; -#define DRM_OUTPUT_POLL_PERIOD (10*HZ) -static void output_poll_execute (struct slow_work *work) +static void output_poll_execute (struct work_struct *work) { - struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work); - struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work); +struct delayed_work *delayed_work =to_delayed_work (work); + struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);struct drm_connector *connector;enum drm_connector_status old_status, status;bool repoll = false, changed = false;
@@ -854,7 +852,7 @@ static void output_poll_execute(struct slow_work *work) }if (repoll) { - ret =delayed_slow_work_enqueue (delayed_work,DRM_OUTPUT_POLL_PERIOD ); + ret =queue_delayed_work (system_nrt_wq, delayed_work,DRM_OUTPUT_POLL_PERIOD );if (ret)DRM_ERROR ("delayed enqueue failed %d\n" , ret); }
@@ -864,7 +862,7 @@ void drm_kms_helper_poll_disable(struct drm_device *dev) {if (!dev->mode_config.poll_enabled)return ; -delayed_slow_work_cancel (&dev->mode_config.output_poll_slow_work); +cancel_delayed_work_sync (&dev->mode_config.output_poll_work); }EXPORT_SYMBOL (drm_kms_helper_poll_disable);
@@ -880,7 +878,7 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) }if (poll) { - ret =delayed_slow_work_enqueue (&dev->mode_config.output_poll_slow_work,DRM_OUTPUT_POLL_PERIOD ); + ret =queue_delayed_work (system_nrt_wq, &dev->mode_config.output_poll_work,DRM_OUTPUT_POLL_PERIOD );if (ret)DRM_ERROR ("delayed enqueue failed %d\n" , ret); }
@@ -889,9 +887,7 @@ EXPORT_SYMBOL(drm_kms_helper_poll_enable);void drm_kms_helper_poll_init (struct drm_device *dev) { -slow_work_register_user (THIS_MODULE ); -delayed_slow_work_init (&dev->mode_config.output_poll_slow_work, - &output_poll_ops); +INIT_DELAYED_WORK (&dev->mode_config.output_poll_work, output_poll_execute); dev->mode_config.poll_enabled = true;drm_kms_helper_poll_enable (dev);
@@ -901,7 +897,6 @@ EXPORT_SYMBOL(drm_kms_helper_poll_init);void drm_kms_helper_poll_fini (struct drm_device *dev) {drm_kms_helper_poll_disable (dev); -slow_work_unregister_user (THIS_MODULE ); }EXPORT_SYMBOL (drm_kms_helper_poll_fini);
@@ -909,12 +904,8 @@ void drm_helper_hpd_irq_event(struct drm_device *dev) {if (!dev->mode_config.poll_enabled)return ; -delayed_slow_work_cancel (&dev->mode_config.output_poll_slow_work); -/* schedule a slow work asap */ -delayed_slow_work_enqueue (&dev->mode_config.output_poll_slow_work,0 ); +/* kill timer and schedule immediate execution, this doesn't block */ +cancel_delayed_work (&dev->mode_config.output_poll_work); +queue_delayed_work (system_nrt_wq, &dev->mode_config.output_poll_work,0 ); }EXPORT_SYMBOL (drm_helper_hpd_irq_event); - -static struct slow_work_ops output_poll_ops = { - .execute = output_poll_execute, -};
include/drm/drm_crtc.h +1 -2
@@ -31,7 +31,6 @@#include <linux/idr.h> #include <linux/fb.h> -#include <linux/slow-work.h> struct drm_device ;struct drm_mode_set ;
@@ -595,7 +594,7 @@ struct drm_mode_config {/* output poll support */ bool poll_enabled; -struct delayed_slow_work output_poll_slow_work; +struct delayed_work output_poll_work;/* pointers to standard properties */ struct list_head property_blob_list;
Signature · 1 line
1.6.4.2
Re: [PATCH 6/7] drm: use workqueue instead of slow-work
Quoted 7 lines · Tejun Heo
Workqueue can now handle high concurrency. Convert
drm_crtc_helperto usesystem_nrt_wqinstead of slow-work. The conversion is mostly straight forward. One difference is thatdrm_helper_hpd_irq_event()no longer blocks and can be called from any context.Signed-off-by Tejun Heo <[email protected]>Cc David Airlie <[email protected]>
David, can you please review the change?
Thanks.
Signature · 1 line
tejun
Dave Airlie
Acked-byRe: [PATCH 6/7] drm: use workqueue instead of slow-work
Quoted 10 lines · Tejun Heo
Quoted 7 lines · Tejun Heo
Workqueue can now handle high concurrency. Convert
drm_crtc_helperto usesystem_nrt_wqinstead of slow-work. The conversion is mostly straight forward. One difference is thatdrm_helper_hpd_irq_event()no longer blocks and can be called from any context.Signed-off-by Tejun Heo <[email protected]>Cc David Airlie <[email protected]>David, can you please review the change?
Yes seems fine to me, in as much as I understand the difference between slow-work and workqueue, but if you say one replaces the other correctly now I'm happy for you to carry this patch.
Dave.
Quoted 3 lines
Thanks.
Re: [PATCH 6/7] drm: use workqueue instead of slow-work
Quoted 10 lines · Dave Airlie
Quoted 9 lines · Tejun Heo
Quoted 7 lines · Tejun Heo
Workqueue can now handle high concurrency. Convert
drm_crtc_helperto usesystem_nrt_wqinstead of slow-work. The conversion is mostly straight forward. One difference is thatdrm_helper_hpd_irq_event()no longer blocks and can be called from any context.Signed-off-by Tejun Heo <[email protected]>Cc David Airlie <[email protected]>
Quoted 7 lines
Quoted 1 line
David, can you please review the change?
Yes seems fine to me, in as much as I understand the difference between slow-work and workqueue, but if you say one replaces the other correctly now I'm happy for you to carry this patch.
Acked-by Dave Airlie <[email protected]>
Thank you. Will push out to #for-next.
Signature · 1 line
tejun
PATCH 7/7 slow-work: kill it
In reply to Tejun Heoslow-work doesn't have any user left. Kill it.
--- Documentation/slow-work.txt | 322 ------------- include/linux/slow-work.h | 163 ------- init/Kconfig | 24 - kernel/Makefile | 2 - kernel/slow-work-debugfs.c | 227 --------- kernel/slow-work.c | 1068 ------------------------------------------- kernel/slow-work.h | 72 --- kernel/sysctl.c | 8 - 8 files changed, 0 insertions(+), 1886 deletions(-) delete mode 100644 Documentation/slow-work.txt delete mode 100644 include/linux/slow-work.h delete mode 100644 kernel/slow-work-debugfs.c delete mode 100644 kernel/slow-work.c delete mode 100644 kernel/slow-work.h
Documentation/slow-work.txt deleted +0 -322
@@ -1,322 +0,0 @@ - ==================================== - SLOW WORK ITEM EXECUTION THREAD POOL - ==================================== - -By: David Howells <[email protected]> - -The slow work item execution thread pool is a pool of threads for performing -things that take a relatively long time, such as making mkdir calls. -Typically, when processing something, these items will spend a lot of time -blocking a thread on I/O, thus making that thread unavailable for doing other -work. - -The standard workqueue model is unsuitable for this class of work item as that -limits the owner to a single thread or a single thread per CPU. For some -tasks, however, more threads - or fewer - are required. - -There is just one pool per system. It contains no threads unless something -wants to use it - and that something must register its interest first. When -the pool is active, the number of threads it contains is dynamic, varying -between a maximum and minimum setting, depending on the load. - - -==================== -CLASSES OF WORK ITEM -==================== - -This pool support two classes of work items: - - (*) Slow work items. - - (*) Very slow work items. - -The former are expected to finish much quicker than the latter. - -An operation of the very slow class may do a batch combination of several -lookups, mkdirs, and a create for instance. - -An operation of the ordinarily slow class may, for example, write stuff or -expand files, provided the time taken to do so isn't too long. - -Operations of both types may sleep during execution, thus tying up the thread -loaned to it. - -A further class of work item is available, based on the slow work item class: - - (*) Delayed slow work items. - -These are slow work items that have a timer to defer queueing of the item for -a while. - - -THREAD-TO-CLASS ALLOCATION --------------------------- - -Not all the threads in the pool are available to work on very slow work items. -The number will be between one and one fewer than the number of active threads. -This is configurable (see the "Pool Configuration" section). - -All the threads are available to work on ordinarily slow work items, but a -percentage of the threads will prefer to work on very slow work items. - -The configuration ensures that at least one thread will be available to work on -very slow work items, and at least one thread will be available that won't work -on very slow work items at all. - - -===================== -USING SLOW WORK ITEMS -===================== - -Firstly, a module or subsystem wanting to make use of slow work items must -register its interest: - - int ret = slow_work_register_user(struct module *module); - -This will return 0 if successful, or a -ve error upon failure. The module -pointer should be the module interested in using this facility (almost -certainly THIS_MODULE). - - -Slow work items may then be set up by: - - (1) Declaring a slow_work struct type variable: - - #include <linux/slow-work.h> - - struct slow_work myitem; - - (2) Declaring the operations to be used for this item: - - struct slow_work_ops myitem_ops = { - .get_ref = myitem_get_ref, - .put_ref = myitem_put_ref, - .execute = myitem_execute, - }; - - [*] For a description of the ops, see section "Item Operations". - - (3) Initialising the item: - - slow_work_init(&myitem, &myitem_ops); - - or: - - delayed_slow_work_init(&myitem, &myitem_ops); - - or: - - vslow_work_init(&myitem, &myitem_ops); - - depending on its class. - -A suitably set up work item can then be enqueued for processing: - - int ret = slow_work_enqueue(&myitem); - -This will return a -ve error if the thread pool is unable to gain a reference -on the item, 0 otherwise, or (for delayed work): - - int ret = delayed_slow_work_enqueue(&myitem, my_jiffy_delay); - - -The items are reference counted, so there ought to be no need for a flush -operation. But as the reference counting is optional, means to cancel -existing work items are also included: - - cancel_slow_work(&myitem); - cancel_delayed_slow_work(&myitem); - -can be used to cancel pending work. The above cancel function waits for -existing work to have been executed (or prevent execution of them, depending -on timing). - - -When all a module's slow work items have been processed, and the -module has no further interest in the facility, it should unregister its -interest: - - slow_work_unregister_user(struct module *module); - -The module pointer is used to wait for all outstanding work items for that -module before completing the unregistration. This prevents the put_ref() code -from being taken away before it completes. module should almost certainly be -THIS_MODULE. - - -================ -HELPER FUNCTIONS -================ - -The slow-work facility provides a function by which it can be determined -whether or not an item is queued for later execution: - - bool queued = slow_work_is_queued(struct slow_work *work); - -If it returns false, then the item is not on the queue (it may be executing -with a requeue pending). This can be used to work out whether an item on which -another depends is on the queue, thus allowing a dependent item to be queued -after it. - -If the above shows an item on which another depends not to be queued, then the -owner of the dependent item might need to wait. However, to avoid locking up -the threads unnecessarily be sleeping in them, it can make sense under some -circumstances to return the work item to the queue, thus deferring it until -some other items have had a chance to make use of the yielded thread. - -To yield a thread and defer an item, the work function should simply enqueue -the work item again and return. However, this doesn't work if there's nothing -actually on the queue, as the thread just vacated will jump straight back into -the item's work function, thus busy waiting on a CPU. - -Instead, the item should use the thread to wait for the dependency to go away, -but rather than using schedule() or schedule_timeout() to sleep, it should use -the following function: - - bool requeue = slow_work_sleep_till_thread_needed( - struct slow_work *work, - signed long *_timeout); - -This will add a second wait and then sleep, such that it will be woken up if -either something appears on the queue that could usefully make use of the -thread - and behind which this item can be queued, or if the event the caller -set up to wait for happens. True will be returned if something else appeared -on the queue and this work function should perhaps return, of false if -something else woke it up. The timeout is as for schedule_timeout(). - -For example: - - wq = bit_waitqueue(&my_flags, MY_BIT); - init_wait(&wait); - requeue = false; - do { - prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); - if (!test_bit(MY_BIT, &my_flags)) - break; - requeue = slow_work_sleep_till_thread_needed(&my_work, - &timeout); - } while (timeout > 0 && !requeue); - finish_wait(wq, &wait); - if (!test_bit(MY_BIT, &my_flags) - goto do_my_thing; - if (requeue) - return; // to slow_work - - -=============== -ITEM OPERATIONS -=============== - -Each work item requires a table of operations of type struct slow_work_ops. -Only ->execute() is required; the getting and putting of a reference and the -describing of an item are all optional. - - (*) Get a reference on an item: - - int (*get_ref)(struct slow_work *work); - - This allows the thread pool to attempt to pin an item by getting a - reference on it. This function should return 0 if the reference was - granted, or a -ve error otherwise. If an error is returned, - slow_work_enqueue() will fail. - - The reference is held whilst the item is queued and whilst it is being - executed. The item may then be requeued with the same reference held, or - the reference will be released. - - (*) Release a reference on an item: - - void (*put_ref)(struct slow_work *work); - - This allows the thread pool to unpin an item by releasing the reference on - it. The thread pool will not touch the item again once this has been - called. - - (*) Execute an item: - - void (*execute)(struct slow_work *work); - - This should perform the work required of the item. It may sleep, it may - perform disk I/O and it may wait for locks. - - (*) View an item through /proc: - - void (*desc)(struct slow_work *work, struct seq_file *m); - - If supplied, this should print to 'm' a small string describing the work - the item is to do. This should be no more than about 40 characters, and - shouldn't include a newline character. - - See the 'Viewing executing and queued items' section below. - - -================== -POOL CONFIGURATION -================== - -The slow-work thread pool has a number of configurables: - - (*) /proc/sys/kernel/slow-work/min-threads - - The minimum number of threads that should be in the pool whilst it is in - use. This may be anywhere between 2 and max-threads. - - (*) /proc/sys/kernel/slow-work/max-threads - - The maximum number of threads that should in the pool. This may be - anywhere between min-threads and 255 or NR_CPUS * 2, whichever is greater. - - (*) /proc/sys/kernel/slow-work/vslow-percentage - - The percentage of active threads in the pool that may be used to execute - very slow work items. This may be between 1 and 99. The resultant number - is bounded to between 1 and one fewer than the number of active threads. - This ensures there is always at least one thread that can process very - slow work items, and always at least one thread that won't. - - -================================== -VIEWING EXECUTING AND QUEUED ITEMS -================================== - -If CONFIG_SLOW_WORK_DEBUG is enabled, a debugfs file is made available: - - /sys/kernel/debug/slow_work/runqueue - -through which the list of work items being executed and the queues of items to -be executed may be viewed. The owner of a work item is given the chance to -add some information of its own. - -The contents look something like the following: - - THR PID ITEM ADDR FL MARK DESC - === ===== ================ == ===== ========== - 0 3005 ffff880023f52348 a 952ms FSC: OBJ17d3: LOOK - 1 3006 ffff880024e33668 2 160ms FSC: OBJ17e5 OP60d3b: Write1/Store fl=2 - 2 3165 ffff8800296dd180 a 424ms FSC: OBJ17e4: LOOK - 3 4089 ffff8800262c8d78 a 212ms FSC: OBJ17ea: CRTN - 4 4090 ffff88002792bed8 2 388ms FSC: OBJ17e8 OP60d36: Write1/Store fl=2 - 5 4092 ffff88002a0ef308 2 388ms FSC: OBJ17e7 OP60d2e: Write1/Store fl=2 - 6 4094 ffff88002abaf4b8 2 132ms FSC: OBJ17e2 OP60d4e: Write1/Store fl=2 - 7 4095 ffff88002bb188e0 a 388ms FSC: OBJ17e9: CRTN - vsq - ffff880023d99668 1 308ms FSC: OBJ17e0 OP60f91: Write1/EnQ fl=2 - vsq - ffff8800295d1740 1 212ms FSC: OBJ16be OP4d4b6: Write1/EnQ fl=2 - vsq - ffff880025ba3308 1 160ms FSC: OBJ179a OP58dec: Write1/EnQ fl=2 - vsq - ffff880024ec83e0 1 160ms FSC: OBJ17ae OP599f2: Write1/EnQ fl=2 - vsq - ffff880026618e00 1 160ms FSC: OBJ17e6 OP60d33: Write1/EnQ fl=2 - vsq - ffff880025a2a4b8 1 132ms FSC: OBJ16a2 OP4d583: Write1/EnQ fl=2 - vsq - ffff880023cbe6d8 9 212ms FSC: OBJ17eb: LOOK - vsq - ffff880024d37590 9 212ms FSC: OBJ17ec: LOOK - vsq - ffff880027746cb0 9 212ms FSC: OBJ17ed: LOOK - vsq - ffff880024d37ae8 9 212ms FSC: OBJ17ee: LOOK - vsq - ffff880024d37cb0 9 212ms FSC: OBJ17ef: LOOK - vsq - ffff880025036550 9 212ms FSC: OBJ17f0: LOOK - vsq - ffff8800250368e0 9 212ms FSC: OBJ17f1: LOOK - vsq - ffff880025036aa8 9 212ms FSC: OBJ17f2: LOOK - -In the 'THR' column, executing items show the thread they're occupying and -queued threads indicate which queue they're on. 'PID' shows the process ID of -a slow-work thread that's executing something. 'FL' shows the work item flags. -'MARK' indicates how long since an item was queued or began executing. Lastly, -the 'DESC' column permits the owner of an item to give some information. -
include/linux/slow-work.h deleted +0 -163
163 lines not on this page · raw message
init/Kconfig +0 -24
@@ -1143,30 +1143,6 @@ config TRACEPOINTS source "arch/Kconfig" -config SLOW_WORK - default n - bool - help - The slow work thread pool provides a number of dynamically allocated - threads that can be used by the kernel to perform operations that - take a relatively long time. - - An example of this would be CacheFiles doing a path lookup followed - by a series of mkdirs and a create call, all of which have to touch - disk. - - See Documentation/slow-work.txt. - -config SLOW_WORK_DEBUG - bool "Slow work debugging through debugfs" - default n - depends on SLOW_WORK && DEBUG_FS - help - Display the contents of the slow work run queue through debugfs, - including items currently executing. - - See Documentation/slow-work.txt. - endmenu # General setup config HAVE_GENERIC_DMA_COHERENT
kernel/Makefile +0 -2
@@ -99,8 +99,6 @@ obj-$(CONFIG_TRACING) += trace/ obj-$(CONFIG_X86_DS) += trace/ obj-$(CONFIG_RING_BUFFER) += trace/ obj-$(CONFIG_SMP) += sched_cpupri.o -obj-$(CONFIG_SLOW_WORK) += slow-work.o -obj-$(CONFIG_SLOW_WORK_DEBUG) += slow-work-debugfs.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
kernel/slow-work-debugfs.c deleted +0 -227
227 lines not on this page · raw message
kernel/slow-work.c deleted +0 -1068
1,068 lines not on this page · raw message
kernel/slow-work.h deleted +0 -72
72 lines not on this page · raw message
kernel/sysctl.c +0 -8
@@ -50,7 +50,6 @@#include <linux/acpi.h> #include <linux/reboot.h> #include <linux/ftrace.h> -#include <linux/slow-work.h> #include <linux/perf_event.h> #include <linux/kprobes.h> #include <linux/pipe_fs_i.h>
@@ -906,13 +905,6 @@ static struct ctl_table kern_table[] = { .proc_handler = proc_dointvec, },#endif -#ifdef CONFIG_SLOW_WORK - { - .procname = "slow-work", - .mode = 0555, - .child = slow_work_sysctls, - }, -#endif#ifdef CONFIG_PERF_EVENTS { .procname = "perf_event_paranoid",
Signature · 1 line
1.6.4.2
Quoted 4 lines · Tejun Heo
0001-fscache-convert-object-to-use-workqueue-instead-of-s.patch 0002-fscache-convert-operation-to-use-workqueue-instead-o.patch 0003-fscache-drop-references-to-slow-work.patch 0004-cifs-use-workqueue-instead-of-slow-work.patch
0001-0004 now pushed out to wq#for-next w/ acks added.
Thank you.
Signature · 1 line
tejun
Quoted 7 lines · Tejun Heo
Quoted 4 lines · Tejun Heo
0001-fscache-convert-object-to-use-workqueue-instead-of-s.patch 0002-fscache-convert-operation-to-use-workqueue-instead-o.patch 0003-fscache-drop-references-to-slow-work.patch 0004-cifs-use-workqueue-instead-of-slow-work.patch
0001-0004 now pushed out to wq#for-next w/ acks added.
The rest of the series pushed out to wq#for-next.
Thanks.
Signature · 1 line
tejun