Convert libata pio task to slow-work
cover Convert libata pio task to slow-work
Hi,
This patchset adds support for slow-work for delayed slow work and for cancelling slow work. Note that these patches are totally untested!
Signature · 1 line
Jens Axboe
PATCH 1/3 slow-work: add delayed_slow_work support
This adds support for starting slow work with a delay, similar to the functionality we have for workqueues.
--- include/linux/slow-work.h | 15 +++++++++++ kernel/slow-work.c | 59 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 0 deletions(-)
include/linux/slow-work.h +15 -0
@@ -51,6 +51,11 @@ struct slow_work {struct list_head link;/* link in queue */ }; +struct delayed_slow_work { +struct timer_list timer; +struct slow_work work; +}; +/** * slow_work_init - Initialise a slow work item * @work: The work item to initialise
@@ -66,6 +71,13 @@ static inline void slow_work_init(struct slow_work *work,INIT_LIST_HEAD (&work->link); } +static inline void delayed_slow_work_init (struct delayed_slow_work *dwork, +const struct slow_work_ops *ops) +{ +init_timer (&dwork->timer); +slow_work_init (&dwork->work, ops); +} +/** * vslow_work_init - Initialise a very slow work item * @work: The work item to initialise
@@ -87,6 +99,9 @@ extern int slow_work_enqueue(struct slow_work *work);extern int slow_work_register_user (void );extern void slow_work_unregister_user (void ); +extern int delayed_slow_work_enqueue (struct delayed_slow_work *dwork, +unsigned long delay); +#ifdef CONFIG_SYSCTL extern ctl_table slow_work_sysctls[];#endif
kernel/slow-work.c +59 -0
65 lines not on this page · raw message
Signature · 1 line
1.6.4.1.207.g68ea
PATCH 2/3 slow-work: add support for cancellation of slow work
This adds support for cancellation of queued slow work and delayed slow work. If the work is already queued, it will not be executed. If work is attempted queued while the cancellation is running, it will fail.
--- include/linux/slow-work.h | 3 +++ kernel/slow-work.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-)
include/linux/slow-work.h +3 -0
@@ -47,6 +47,7 @@ struct slow_work {#define SLOW_WORK_EXECUTING 1/* item currently executing */ #define SLOW_WORK_ENQ_DEFERRED 2/* item enqueue deferred */ #define SLOW_WORK_VERY_SLOW 3/* item is very slow */ +#define SLOW_WORK_CANCEL 4/* item is cancelled, don't enqueue */ const struct slow_work_ops *ops;/* operations table for this item */ struct list_head link;/* link in queue */ };
@@ -96,11 +97,13 @@ static inline void vslow_work_init(struct slow_work *work, }extern int slow_work_enqueue (struct slow_work *work); +extern void cancel_slow_work (struct slow_work *work);extern int slow_work_register_user (void );extern void slow_work_unregister_user (void );extern int delayed_slow_work_enqueue (struct delayed_slow_work *dwork,unsigned long delay); +extern void cancel_delayed_slow_work (struct delayed_slow_work *dwork);#ifdef CONFIG_SYSCTL extern ctl_table slow_work_sysctls[];
kernel/slow-work.c +40 -2
76 lines not on this page · raw message
Signature · 1 line
1.6.4.1.207.g68ea
PATCH 3/3 libata: switch pio task from workqueue to slow-work
A workqueue isn't a good fit for the pio task:
- It does not require per-CPU support, thus wasting many threads.
- The pio task would like to have more than one thread per CPU in some cases, for the single CPU case of having more than one pio device active.
So convert to slow-work instead, this is now possible with support for delayed slow work and cancellation.
--- drivers/ata/libata-core.c | 35 ++++++++++++++++++++++------------- drivers/ata/libata-sff.c | 2 +- drivers/ata/libata.h | 2 +- include/linux/libata.h | 3 ++- 4 files changed, 26 insertions(+), 16 deletions(-)
drivers/ata/libata-core.c +22 -13
@@ -95,7 +95,6 @@ static void ata_dev_xfermask(struct ata_device *dev);static unsigned long ata_dev_blacklisted (const struct ata_device *dev);unsigned int ata_print_id =1 ; -static struct workqueue_struct *ata_wq;struct workqueue_struct *ata_aux_wq;
@@ -1700,7 +1699,7 @@ void ata_pio_queue_task(struct ata_port *ap, void *data, unsigned long delay) ap->port_task_data = data;/* may fail if ata_port_flush_task() in progress */ -queue_delayed_work (ata_wq, &ap->port_task,msecs_to_jiffies (delay)); +delayed_slow_work_enqueue (&ap->port_task,msecs_to_jiffies (delay)); }/**
@@ -1717,7 +1716,7 @@ void ata_port_flush_task(struct ata_port *ap) {DPRINTK ("ENTER\n" ); -cancel_rearming_delayed_work (&ap->port_task); +cancel_delayed_slow_work (&ap->port_task);if (ata_msg_ctl (ap))ata_port_printk (ap,KERN_DEBUG ,"%s: EXIT\n" , __func__);
@@ -5600,6 +5599,20 @@ int sata_link_init_spd(struct ata_link *link)return 0 ; } +static int ata_slow_work_get (struct slow_work *work) +{ +return 0 ; +} + +static const struct slow_work_ops ata_work_ops_sff = { + .get_ref = ata_slow_work_get, + .execute = ata_pio_task, +}; + +static const struct slow_work_ops ata_work_ops = { + .get_ref = ata_slow_work_get, +}; +/** * ata_port_alloc - allocate and initialize basic ATA port resources * @host: ATA host this allocated port belongs to
@@ -5641,9 +5654,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host)#endif #ifdef CONFIG_ATA_SFF -INIT_DELAYED_WORK (&ap->port_task, ata_pio_task); +delayed_slow_work_init (&ap->port_task, &ata_work_ops_sff);#else -INIT_DELAYED_WORK (&ap->port_task,NULL ); +delayed_slow_work_init (&ap->port_task, &ata_work_ops);#endif INIT_DELAYED_WORK (&ap->hotplug_task, ata_scsi_hotplug);INIT_WORK (&ap->scsi_rescan_task, ata_scsi_dev_rescan);
@@ -6580,19 +6593,15 @@ static int __init ata_init(void) {ata_parse_force_param (); - ata_wq =create_workqueue ("ata" ); -if (!ata_wq) - goto free_force_tbl; - ata_aux_wq =create_singlethread_workqueue ("ata_aux" );if (!ata_aux_wq) - goto free_wq; + goto free_force_tbl; + +slow_work_register_user ();printk (KERN_DEBUG "libata version " DRV_VERSION " loaded.\n" );return 0 ; -free_wq: -destroy_workqueue (ata_wq); free_force_tbl:kfree (ata_force_tbl);return -ENOMEM ;
@@ -6601,8 +6610,8 @@ free_force_tbl: static void __exit ata_exit(void) {kfree (ata_force_tbl); -destroy_workqueue (ata_wq);destroy_workqueue (ata_aux_wq); +slow_work_unregister_user (); }subsys_initcall (ata_init);
drivers/ata/libata-sff.c +1 -1
@@ -1454,7 +1454,7 @@ fsm_start: }EXPORT_SYMBOL_GPL (ata_sff_hsm_move); -void ata_pio_task (struct work_struct *work) +void ata_pio_task (struct slow_work *work) {struct ata_port *ap = container_of(work, struct ata_port, port_task.work);
drivers/ata/libata.h +1 -1
@@ -202,7 +202,7 @@ static inline int sata_pmp_attach(struct ata_device *dev)extern void ata_dev_select (struct ata_port *ap,unsigned int device,unsigned int wait,unsigned int can_sleep);extern u8 ata_irq_on (struct ata_port *ap); -extern void ata_pio_task (struct work_struct *work); +extern void ata_pio_task (struct slow_work *work);#endif /* CONFIG_ATA_SFF */ #endif /* __LIBATA_H__ */
include/linux/libata.h +2 -1
@@ -34,6 +34,7 @@#include <linux/io.h> #include <linux/ata.h> #include <linux/workqueue.h> +#include <linux/slow-work.h> #include <scsi/scsi_host.h> #include <linux/acpi.h> #include <linux/cdrom.h>
@@ -734,7 +735,7 @@ struct ata_port {struct device *dev;void *port_task_data; -struct delayed_work port_task; +struct delayed_slow_work port_task;struct delayed_work hotplug_task;struct work_struct scsi_rescan_task;
Signature · 1 line
1.6.4.1.207.g68ea
Re: [PATCH 2/3] slow-work: add support for cancellation of slow work
In reply to Jens AxboeQuoted 22 lines · Jens Axboe
kernel/slow-work.c +10
-1@@ -194,12 +194,21 @@ static bool slow_work_execute(void)if (!test_and_clear_bit (SLOW_WORK_PENDING , &work->flags))BUG (); - work->ops->execute (work); +/* +* Don't execute if the work was cancelled after being added +*/ +if (!test_bit (SLOW_WORK_CANCEL , &work->flags)) + work->ops->execute (work);if (very_slow)atomic_dec (&vslow_work_executing_count);clear_bit_unlock (SLOW_WORK_EXECUTING , &work->flags); +/* +* Wake anyone waiting for this work to be done +*/ +wake_up_bit (&work->flags,SLOW_WORK_EXECUTING ); +/* if someone tried to enqueue the item whilst we were executing it, * then it'll be left unenqueued to avoid multiple threads trying to
kernel/slow-work.c static bool slow_work_execute(void)
Quoted 10 lines
kernel/slow-work.c +8
-0* execute it simultaneously +void cancel_slow_work(struct slow_work *work) +{ +set_bit (SLOW_WORK_CANCEL , &work->flags); +wait_on_bit (&work->flags,SLOW_WORK_EXECUTING , slow_work_wait, +TASK_UNINTERRUPTIBLE ); +clear_bit (SLOW_WORK_CANCEL , &work->flags); +} +EXPORT_SYMBOL (cancel_slow_work);
We want to use SLOW_WORK_PENDING for this logic, not SLOW_WORK_EXECUTING. I'll update it.
Signature · 1 line
Jens Axboe
PATCH 2/3 slow-work: add support for cancellation of slow work (updated)
Quoted 2 lines
From
542bd594356125971a518a4c7a3e4ead21ea256aMon Sep 17 00:00:00 2001
From: Jens Axboe <[email protected]>
Date: Thu, 27 Aug 2009 11:17:04 +0200
Subject: [PATCH 1/2] slow-work: add support for cancellation of slow work
This adds support for cancellation of queued slow work and delayed slow work. If the work is already queued, it will not be executed. If work is attempted queued while the cancellation is running, it will fail.
--- include/linux/slow-work.h | 3 +++ kernel/slow-work.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-)
include/linux/slow-work.h +3 -0
@@ -47,6 +47,7 @@ struct slow_work {#define SLOW_WORK_EXECUTING 1/* item currently executing */ #define SLOW_WORK_ENQ_DEFERRED 2/* item enqueue deferred */ #define SLOW_WORK_VERY_SLOW 3/* item is very slow */ +#define SLOW_WORK_CANCEL 4/* item is cancelled, don't enqueue */ const struct slow_work_ops *ops;/* operations table for this item */ struct list_head link;/* link in queue */ };
@@ -96,11 +97,13 @@ static inline void vslow_work_init(struct slow_work *work, }extern int slow_work_enqueue (struct slow_work *work); +extern void cancel_slow_work (struct slow_work *work);extern int slow_work_register_user (void );extern void slow_work_unregister_user (void );extern int delayed_slow_work_enqueue (struct delayed_slow_work *dwork,unsigned long delay); +extern void cancel_delayed_slow_work (struct delayed_slow_work *dwork);#ifdef CONFIG_SYSCTL extern ctl_table slow_work_sysctls[];
kernel/slow-work.c +41 -2
72 lines not on this page · raw message
Signature · 4 lines
1.6.4.1.207.g68ea -- Jens Axboe
Tejun Heo
maintainerHello, Jens.
Quoted 5 lines · Jens Axboe
Hi,
This patchset adds support for slow-work for delayed slow work and for cancelling slow work. Note that these patches are totally untested!
As what I'm currently working on is likely to collide with these changes, here is a short summary of what's been going on.
/* excerpted from internal weekly work report and edited */
The principle is the same as I described before. It hooks into the scheduler using an alias scheduler class of sched_fair and gets notifications of workqueue threads going into sleep, waking up and getting preempted from which worker pool is managed automatically for full concurrency with the least number of concurrent threads.
There's a global workqueue per-cpu and each actual workqueue is front to the global one adding necessary attributes and/or defining a flushing domain. Each global workqueue can have multiple workers (upto 128 in the current incarnation) and creates and kicks new ones as necessary to keep the cpu occupied.
The diffcult part was teaching workqueue how to handle multiple workers yet maintaining its exclusion properties, flushing rules and forward progress guarantees - a single work can't be running concurrently on the same cpu but can across different cpus, flush_work() deals with single cpu flushing but others deal with all the cpus and so on. Because each work struct can't be accessed once the work actually begins running, keeping track of things become somewhat difficult as multiple workers now process works from a single queue. Anyways, after much head scratching, I think most problems have been nailed down although I wouldn't know for sure till I get it actually working.
There's slight more book keeping to do on each work-processing iteration but overall I think it will be a win considering that it can remove unnecessary task switchings, usage of different stacks (cache foot-print) and cross-cpu work bouncing (for currently single threaded workqueues). If it really works as expected, it should be able to replace async, [very]_slow_work and remove most of private workqueues while losing no concurrency or forward-progress guarantees, which would be pretty decent.
/**/
I finished first draft implementation and review pass yesterday and it seems like there shouldn't be any major problem now but I haven't even tried to compile it yet, so I'm not yet entirely sure how it would eventually turn out and if I hit some major roadblock I might just drop it.
It would be nice if merging of this series and the lazy work can be held a bit but there's no harm in merging either. If the concurrency managed workqueue turns out to be a good idea, we can replace it then.
Thanks a lot.
Signature · 1 line
tejun
Quoted 55 lines · Tejun Heo
Hello, Jens.
Quoted 5 lines · Jens Axboe
Hi,
This patchset adds support for slow-work for delayed slow work and for cancelling slow work. Note that these patches are totally untested!
As what I'm currently working on is likely to collide with these changes, here is a short summary of what's been going on.
/* excerpted from internal weekly work report and edited */
The principle is the same as I described before. It hooks into the scheduler using an alias scheduler class of
sched_fairand gets notifications of workqueue threads going into sleep, waking up and getting preempted from which worker pool is managed automatically for full concurrency with the least number of concurrent threads.There's a global workqueue per-cpu and each actual workqueue is front to the global one adding necessary attributes and/or defining a flushing domain. Each global workqueue can have multiple workers (upto 128 in the current incarnation) and creates and kicks new ones as necessary to keep the cpu occupied.
The diffcult part was teaching workqueue how to handle multiple workers yet maintaining its exclusion properties, flushing rules and forward progress guarantees - a single work can't be running concurrently on the same cpu but can across different cpus,
flush_work()deals with single cpu flushing but others deal with all the cpus and so on. Because each work struct can't be accessed once the work actually begins running, keeping track of things become somewhat difficult as multiple workers now process works from a single queue. Anyways, after much head scratching, I think most problems have been nailed down although I wouldn't know for sure till I get it actually working.There's slight more book keeping to do on each work-processing iteration but overall I think it will be a win considering that it can remove unnecessary task switchings, usage of different stacks (cache foot-print) and cross-cpu work bouncing (for currently single threaded workqueues). If it really works as expected, it should be able to replace async, [very]_slow_work and remove most of private workqueues while losing no concurrency or forward-progress guarantees, which would be pretty decent.
/**/
I finished first draft implementation and review pass yesterday and it seems like there shouldn't be any major problem now but I haven't even tried to compile it yet, so I'm not yet entirely sure how it would eventually turn out and if I hit some major roadblock I might just drop it.
Quoted 3 lines
It would be nice if merging of this series and the lazy work can be held a bit but there's no harm in merging either. If the concurrency managed workqueue turns out to be a good idea, we can replace it then.
It can wait, what you describe above sounds really cool and would hopefully allow us to get rid of all workqueues (provided it scales well and doesn't fall down on cache line contention with many different instances pounding on it).
Care to post it? I know you don't think it's perfect yet, but it would make a lot more sense to throw effort into this rather than waste time on partial solutions.
Signature · 1 line
Jens Axboe
Tejun Heo
maintainerHello, Jens.
Quoted 8 lines · Jens Axboe
Quoted 3 lines
It would be nice if merging of this series and the lazy work can be held a bit but there's no harm in merging either. If the concurrency managed workqueue turns out to be a good idea, we can replace it then.
It can wait, what you describe above sounds really cool and would hopefully allow us to get rid of all workqueues (provided it scales well and doesn't fall down on cache line contention with many different instances pounding on it).
Almost all operations are per-cpu so cache lines shouldn't bounce too much. The only part I worry about is the part which checks whether a work is currently executing on the current cpu which currently is implemeted as a hash table. The hash table is only 16 pointers long and will be mostly empty so hopefully it doesn't add any significant overhead.
Quoted 3 lines
Care to post it? I know you don't think it's perfect yet, but it would make a lot more sense to throw effort into this rather than waste time on partial solutions.
I have this printed out code with full of red markings from proof reading and flush implementation is mostly broken. Please give me a couple of days. I'll post a rough unsplit version which at least compiles with the planned changes applied by the end of the week. :-)
Thanks.
Signature · 1 line
tejun
Quoted 12 lines · Tejun Heo
Hello, Jens.
Quoted 8 lines · Jens Axboe
Quoted 3 lines
It would be nice if merging of this series and the lazy work can be held a bit but there's no harm in merging either. If the concurrency managed workqueue turns out to be a good idea, we can replace it then.
It can wait, what you describe above sounds really cool and would hopefully allow us to get rid of all workqueues (provided it scales well and doesn't fall down on cache line contention with many different instances pounding on it).
Quoted 6 lines
Almost all operations are per-cpu so cache lines shouldn't bounce too much. The only part I worry about is the part which checks whether a work is currently executing on the current cpu which currently is implemeted as a hash table. The hash table is only 16 pointers long and will be mostly empty so hopefully it doesn't add any significant overhead.
OK, we'll let time and experimentation be the judge.
Quoted 8 lines
Quoted 3 lines
Care to post it? I know you don't think it's perfect yet, but it would make a lot more sense to throw effort into this rather than waste time on partial solutions.
I have this printed out code with full of red markings from proof reading and flush implementation is mostly broken. Please give me a couple of days. I'll post a rough unsplit version which at least compiles with the planned changes applied by the end of the week. :-)
Alright, fair enough.
One question - do the 'exposed' workqueues (the ones that drivers allocate/create) sitting in front of the global cpu queue allow more than one thread per cpu, or is that property retained for the global cpu queue (where it is a necessity)?
Signature · 1 line
Jens Axboe
Tejun Heo
maintainerHello, Jens.
Quoted 8 lines · Jens Axboe
Quoted 6 lines
Almost all operations are per-cpu so cache lines shouldn't bounce too much. The only part I worry about is the part which checks whether a work is currently executing on the current cpu which currently is implemeted as a hash table. The hash table is only 16 pointers long and will be mostly empty so hopefully it doesn't add any significant overhead.
OK, we'll let time and experimentation be the judge.
Yeap.
Quoted 8 lines
Quoted 7 lines
Quoted 3 lines
Care to post it? I know you don't think it's perfect yet, but it would make a lot more sense to throw effort into this rather than waste time on partial solutions.
I have this printed out code with full of red markings from proof reading and flush implementation is mostly broken. Please give me a couple of days. I'll post a rough unsplit version which at least compiles with the planned changes applied by the end of the week. :-)
Quoted 6 lines
Alright, fair enough.
One question - do the 'exposed' workqueues (the ones that drivers allocate/create) sitting in front of the global cpu queue allow more than one thread per cpu, or is that property retained for the global cpu queue (where it is a necessity)?
The exposed workqueues basically just play the gateway and don't have threads associated with it, well, at least not the normal ones. It may have single dedicated thread which usually isn't used but only gets summoned when a queue stall is detected (new thread needs to be created but blocks on allocation kind of situation). So, only the global cpu queue has normal workers and there are multiple per cpu and they're shared by all exported workqueues.
Thanks.
Signature · 1 line
tejun
Quoted 15 lines · Tejun Heo
Quoted 8 lines
Quoted 7 lines
Quoted 3 lines
Care to post it? I know you don't think it's perfect yet, but it would make a lot more sense to throw effort into this rather than waste time on partial solutions.
I have this printed out code with full of red markings from proof reading and flush implementation is mostly broken. Please give me a couple of days. I'll post a rough unsplit version which at least compiles with the planned changes applied by the end of the week. :-)
Quoted 6 lines
Alright, fair enough.
One question - do the 'exposed' workqueues (the ones that drivers allocate/create) sitting in front of the global cpu queue allow more than one thread per cpu, or is that property retained for the global cpu queue (where it is a necessity)?
Quoted 7 lines
The exposed workqueues basically just play the gateway and don't have threads associated with it, well, at least not the normal ones. It may have single dedicated thread which usually isn't used but only gets summoned when a queue stall is detected (new thread needs to be created but blocks on allocation kind of situation). So, only the global cpu queue has normal workers and there are multiple per cpu and they're shared by all exported workqueues.
Thanks for the clarification, it answers the question on what level of functionality is observed by the exported workqueues. Sounds good!
Signature · 1 line
Jens Axboe
Tejun Heo
maintainerPATCH 1/1 workqueue: implement global cpu workqueue
Okay, here's the early version which finally builds. It's a rather huge patch and contains a large number of known and unknown bugs and doesn't actually convert any users but it should be enough to show the basic idea and how each area of the problem space is solved.
I'll post a proper cleaned-up and hopefully working version in several days.
Thanks.
SERIOUSLY_BROKEN_AND_NOT_SIGNED_OFF_BY_ANYONE
--- include/linux/kthread.h | 1 include/linux/sched.h | 3 include/linux/stop_machine.h | 6 include/linux/workqueue.h | 52 - init/main.c | 2 kernel/kthread.c | 7 kernel/sched.c | 14 kernel/sched_fair.c | 58 - kernel/sched_idletask.c | 1 kernel/sched_rt.c | 1 kernel/sched_workqueue.c | 53 + kernel/sched_workqueue.h | 5 kernel/stop_machine.c | 151 +++ kernel/workqueue.c | 1738 +++++++++++++++++++++++++++++++++---------- 14 files changed, 1655 insertions(+), 437 deletions(-)
include/linux/stop_machine.h +6 -0
@@ -53,6 +53,11 @@ int stop_machine_create(void);*/ void stop_machine_destroy (void ); +/** +* init_stop_machine: initialize stop_machine during boot +*/ +void init_stop_machine (void ); +#else static inline int stop_machine(int (*fn)(void *), void *data,
@@ -67,6 +72,7 @@ static inline int stop_machine(int (*fn)static inline int stop_machine_create (void ) {return 0 ; }static inline void stop_machine_destroy (void ) { } +static inline void init_stop_machine (void ) { }#endif /* CONFIG_SMP */ #endif /* _LINUX_STOP_MACHINE */
init/main.c +2 -0
@@ -35,6 +35,7 @@#include <linux/security.h> #include <linux/smp.h> #include <linux/workqueue.h> +#include <linux/stop_machine.h> #include <linux/profile.h> #include <linux/rcupdate.h> #include <linux/moduleparam.h>
@@ -807,6 +808,7 @@ static void __init do_basic_setup(void) {rcu_init_sched ();/* needed by module_init stage. */ init_workqueues (); +init_stop_machine ();cpuset_init_smp ();usermodehelper_init ();driver_init ();
kernel/stop_machine.c +125 -26
229 lines not on this page · raw message
include/linux/workqueue.h +36 -16
81 lines not on this page · raw message
kernel/workqueue.c +1369 -369
2,011 lines not on this page · raw message
kernel/sched.c +10 -4
@@ -1732,10 +1732,13 @@ static void cfs_rq_set_shares(struct cfsstatic void calc_load_account_active (struct rq *this_rq); +#define sched_class_equal (a, b) ((a)->identity == (b)->identity) +#include "sched_stats.h" #include "sched_idletask.c" #include "sched_fair.c" #include "sched_rt.c" +#include "sched_workqueue.c" #ifdef CONFIG_SCHED_DEBUG # include "sched_debug.c" #endif
@@ -1906,7 +1909,7 @@ static inline void check_class_changed(sconst struct sched_class *prev_class, int oldprio, int running) { - if (prev_class != p->sched_class) { + if (!sched_class_equal(prev_class, p->sched_class)) { if (prev_class->switched_from) prev_class->switched_from(rq, p, running); p->sched_class->switched_to (rq, p, running);
@@ -1938,7 +1941,7 @@ task_hot(struct task_struct *p, u64 now, &p->se == cfs_rq_of(&p->se)->last))return 1 ; -if (p->sched_class != &fair_sched_class) +if (!sched_class_equal (p->sched_class, &fair_sched_class))return 0 ;if (sysctl_sched_migration_cost ==-1 )
@@ -6085,7 +6088,10 @@ __setscheduler(struct rq *rq, struct tascase SCHED_NORMAL :case SCHED_BATCH :case SCHED_IDLE : - p->sched_class = &fair_sched_class; +if (p->flags &PF_WORKQUEUE ) + p->sched_class = &workqueue_sched_class; +else + p->sched_class = &fair_sched_class;break ;case SCHED_FIFO :case SCHED_RR :
@@ -10230,7 +10236,7 @@ cpu_cgroup_can_attach(struct cgroup_subsreturn -EINVAL ;#else /* We don't support RT-tasks being in separate groups */ -if (tsk->sched_class != &fair_sched_class) +if (!sched_class_equal (tsk->sched_class, &fair_sched_class))return -EINVAL ;#endif
kernel/sched_fair.c +36 -22
84 lines not on this page · raw message
include/linux/sched.h +3 -0
@@ -1023,6 +1023,7 @@ struct sched_domain;struct sched_class {const struct sched_class *next; +const struct sched_class *identity;void (*enqueue_task) (struct rq *rq,struct task_struct *p,int wakeup);void (*dequeue_task) (struct rq *rq,struct task_struct *p,int sleep);
@@ -1694,6 +1695,7 @@ extern cputime_t task_gtime(struct task_#define PF_SPREAD_PAGE 0x01000000/* Spread page cache over cpuset */ #define PF_SPREAD_SLAB 0x02000000/* Spread some slab caches over cpuset */ #define PF_THREAD_BOUND 0x04000000/* Thread bound to specific cpu */ +#define PF_WORKQUEUE 0x08000000/* I'm a workqueue worker */ #define PF_MEMPOLICY 0x10000000/* Non-default NUMA mempolicy */ #define PF_MUTEX_TESTER 0x20000000/* Thread belongs to the rt mutex tester */ #define PF_FREEZER_SKIP 0x40000000/* Freezer should not count it as freezeable */
@@ -1865,6 +1867,7 @@ extern int idle_cpu(int cpu);extern int sched_setscheduler (struct task_struct *,int ,struct sched_param *);extern int sched_setscheduler_nocheck (struct task_struct *,int ,struct sched_param *); +extern void sched_setscheduler_workqueue (struct task_struct *p);extern struct task_struct *idle_task (int cpu);extern struct task_struct *curr_task (int cpu);extern void set_curr_task (int cpu,struct task_struct *p);
kernel/sched_idletask.c +1 -0
@@ -101,6 +101,7 @@ static void prio_changed_idle(struct rq* Simple, special scheduling class for the per-CPU idle tasks: */ static const struct sched_class idle_sched_class = { + .identity = &idle_sched_class,/* .next is NULL */ /* no enqueue/yield_task for idle tasks */
kernel/sched_rt.c +1 -0
@@ -1739,6 +1739,7 @@ static void set_curr_task_rt(struct rq * }static const struct sched_class rt_sched_class = { + .identity = &rt_sched_class, .next = &fair_sched_class, .enqueue_task = enqueue_task_rt, .dequeue_task = dequeue_task_rt,
kernel/sched_workqueue.c new file +53 -0
53 lines not on this page · raw message
include/linux/kthread.h +1 -0
@@ -30,6 +30,7 @@ struct task_struct *kthread_create(int (void kthread_bind (struct task_struct *k,unsigned int cpu);int kthread_stop (struct task_struct *k);int kthread_should_stop (void ); +void *kthread_data (struct task_struct *k);int kthreadd (void *unused);extern struct task_struct *kthreadd_task;
kernel/kthread.c +7 -0
@@ -37,6 +37,7 @@ struct kthread_create_infostruct kthread {int should_stop; +void *data;struct completion exited; };
@@ -56,6 +57,11 @@ int kthread_should_stop(void) }EXPORT_SYMBOL (kthread_should_stop); +void *kthread_data (struct task_struct *task) +{ +return to_kthread (current)->data; +} +static int kthread (void *_create) {/* Copy data: it's on kthread's stack */
@@ -66,6 +72,7 @@ static int kthread(void *_create)int ret; self.should_stop =0 ; + self.data = data;init_completion (&self.exited); current->vfork_done = &self.exited;
kernel/sched_workqueue.h new file +5 -0
@@ -0,0 +1,5 @@ +void sched_workqueue_worker_wakeup (struct task_struct *task); +void sched_workqueue_worker_sleep (struct task_struct *task); +void sched_workqueue_worker_preempted (struct task_struct *task); + +bool sched_workqueue_wake_up_process (struct task_struct *p);