Commit 6370a6ad authored by Tejun Heo's avatar Tejun Heo

workqueue: add and use WQ_MEM_RECLAIM flag

Add WQ_MEM_RECLAIM flag which currently maps to WQ_RESCUER, mark
WQ_RESCUER as internal and replace all external WQ_RESCUER usages to
WQ_MEM_RECLAIM.

This makes the API users express the intent of the workqueue instead
of indicating the internal mechanism used to guarantee forward
progress.  This is also to make it cleaner to add more semantics to
WQ_MEM_RECLAIM.  For example, if deemed necessary, memory reclaim
workqueues can be made highpri.

This patch doesn't introduce any functional change.
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Cc: Jeff Garzik <jgarzik@pobox.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Steven Whitehouse <swhiteho@redhat.com>
parent 30310045
...@@ -196,11 +196,11 @@ resources, scheduled and executed. ...@@ -196,11 +196,11 @@ resources, scheduled and executed.
suspend operations. Work items on the wq are drained and no suspend operations. Work items on the wq are drained and no
new work item starts execution until thawed. new work item starts execution until thawed.
WQ_RESCUER WQ_MEM_RECLAIM
All wq which might be used in the memory reclaim paths _MUST_ All wq which might be used in the memory reclaim paths _MUST_
have this flag set. This reserves one worker exclusively for have this flag set. The wq is guaranteed to have at least one
the execution of this wq under memory pressure. execution context regardless of memory pressure.
WQ_HIGHPRI WQ_HIGHPRI
...@@ -356,11 +356,11 @@ If q1 has WQ_CPU_INTENSIVE set, ...@@ -356,11 +356,11 @@ If q1 has WQ_CPU_INTENSIVE set,
6. Guidelines 6. Guidelines
* Do not forget to use WQ_RESCUER if a wq may process work items which * Do not forget to use WQ_MEM_RECLAIM if a wq may process work items
are used during memory reclaim. Each wq with WQ_RESCUER set has one which are used during memory reclaim. Each wq with WQ_MEM_RECLAIM
rescuer thread reserved for it. If there is dependency among set has an execution context reserved for it. If there is
multiple work items used during memory reclaim, they should be dependency among multiple work items used during memory reclaim,
queued to separate wq each with WQ_RESCUER. they should be queued to separate wq each with WQ_MEM_RECLAIM.
* Unless strict ordering is required, there is no need to use ST wq. * Unless strict ordering is required, there is no need to use ST wq.
...@@ -368,12 +368,13 @@ If q1 has WQ_CPU_INTENSIVE set, ...@@ -368,12 +368,13 @@ If q1 has WQ_CPU_INTENSIVE set,
recommended. In most use cases, concurrency level usually stays recommended. In most use cases, concurrency level usually stays
well under the default limit. well under the default limit.
* A wq serves as a domain for forward progress guarantee (WQ_RESCUER), * A wq serves as a domain for forward progress guarantee
flush and work item attributes. Work items which are not involved (WQ_MEM_RECLAIM, flush and work item attributes. Work items which
in memory reclaim and don't need to be flushed as a part of a group are not involved in memory reclaim and don't need to be flushed as a
of work items, and don't require any special attribute, can use one part of a group of work items, and don't require any special
of the system wq. There is no difference in execution attribute, can use one of the system wq. There is no difference in
characteristics between using a dedicated wq and a system wq. execution characteristics between using a dedicated wq and a system
wq.
* Unless work items are expected to consume a huge amount of CPU * Unless work items are expected to consume a huge amount of CPU
cycles, using a bound wq is usually beneficial due to the increased cycles, using a bound wq is usually beneficial due to the increased
......
...@@ -3335,7 +3335,7 @@ void ata_sff_port_init(struct ata_port *ap) ...@@ -3335,7 +3335,7 @@ void ata_sff_port_init(struct ata_port *ap)
int __init ata_sff_init(void) int __init ata_sff_init(void)
{ {
ata_sff_wq = alloc_workqueue("ata_sff", WQ_RESCUER, WQ_MAX_ACTIVE); ata_sff_wq = alloc_workqueue("ata_sff", WQ_MEM_RECLAIM, WQ_MAX_ACTIVE);
if (!ata_sff_wq) if (!ata_sff_wq)
return -ENOMEM; return -ENOMEM;
......
...@@ -140,7 +140,7 @@ static int __init init_gfs2_fs(void) ...@@ -140,7 +140,7 @@ static int __init init_gfs2_fs(void)
error = -ENOMEM; error = -ENOMEM;
gfs_recovery_wq = alloc_workqueue("gfs_recovery", gfs_recovery_wq = alloc_workqueue("gfs_recovery",
WQ_NON_REENTRANT | WQ_RESCUER, 0); WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
if (!gfs_recovery_wq) if (!gfs_recovery_wq)
goto fail_wq; goto fail_wq;
......
...@@ -1933,7 +1933,7 @@ xfs_buf_init(void) ...@@ -1933,7 +1933,7 @@ xfs_buf_init(void)
goto out; goto out;
xfslogd_workqueue = alloc_workqueue("xfslogd", xfslogd_workqueue = alloc_workqueue("xfslogd",
WQ_RESCUER | WQ_HIGHPRI, 1); WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
if (!xfslogd_workqueue) if (!xfslogd_workqueue)
goto out_free_buf_zone; goto out_free_buf_zone;
......
...@@ -243,11 +243,12 @@ enum { ...@@ -243,11 +243,12 @@ enum {
WQ_NON_REENTRANT = 1 << 0, /* guarantee non-reentrance */ WQ_NON_REENTRANT = 1 << 0, /* guarantee non-reentrance */
WQ_UNBOUND = 1 << 1, /* not bound to any cpu */ WQ_UNBOUND = 1 << 1, /* not bound to any cpu */
WQ_FREEZEABLE = 1 << 2, /* freeze during suspend */ WQ_FREEZEABLE = 1 << 2, /* freeze during suspend */
WQ_RESCUER = 1 << 3, /* has an rescue worker */ WQ_MEM_RECLAIM = 1 << 3, /* may be used for memory reclaim */
WQ_HIGHPRI = 1 << 4, /* high priority */ WQ_HIGHPRI = 1 << 4, /* high priority */
WQ_CPU_INTENSIVE = 1 << 5, /* cpu instensive workqueue */ WQ_CPU_INTENSIVE = 1 << 5, /* cpu instensive workqueue */
WQ_DYING = 1 << 6, /* internal: workqueue is dying */ WQ_DYING = 1 << 6, /* internal: workqueue is dying */
WQ_RESCUER = 1 << 7, /* internal: workqueue has rescuer */
WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */ WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */
WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */ WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */
...@@ -309,7 +310,7 @@ __alloc_workqueue_key(const char *name, unsigned int flags, int max_active, ...@@ -309,7 +310,7 @@ __alloc_workqueue_key(const char *name, unsigned int flags, int max_active,
/** /**
* alloc_ordered_workqueue - allocate an ordered workqueue * alloc_ordered_workqueue - allocate an ordered workqueue
* @name: name of the workqueue * @name: name of the workqueue
* @flags: WQ_* flags (only WQ_FREEZEABLE and WQ_RESCUER are meaningful) * @flags: WQ_* flags (only WQ_FREEZEABLE and WQ_MEM_RECLAIM are meaningful)
* *
* Allocate an ordered workqueue. An ordered workqueue executes at * Allocate an ordered workqueue. An ordered workqueue executes at
* most one work item at any given time in the queued order. They are * most one work item at any given time in the queued order. They are
...@@ -325,11 +326,11 @@ alloc_ordered_workqueue(const char *name, unsigned int flags) ...@@ -325,11 +326,11 @@ alloc_ordered_workqueue(const char *name, unsigned int flags)
} }
#define create_workqueue(name) \ #define create_workqueue(name) \
alloc_workqueue((name), WQ_RESCUER, 1) alloc_workqueue((name), WQ_MEM_RECLAIM, 1)
#define create_freezeable_workqueue(name) \ #define create_freezeable_workqueue(name) \
alloc_workqueue((name), WQ_FREEZEABLE | WQ_UNBOUND | WQ_RESCUER, 1) alloc_workqueue((name), WQ_FREEZEABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
#define create_singlethread_workqueue(name) \ #define create_singlethread_workqueue(name) \
alloc_workqueue((name), WQ_UNBOUND | WQ_RESCUER, 1) alloc_workqueue((name), WQ_UNBOUND | WQ_MEM_RECLAIM, 1)
extern void destroy_workqueue(struct workqueue_struct *wq); extern void destroy_workqueue(struct workqueue_struct *wq);
......
...@@ -2847,6 +2847,13 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name, ...@@ -2847,6 +2847,13 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name,
struct workqueue_struct *wq; struct workqueue_struct *wq;
unsigned int cpu; unsigned int cpu;
/*
* Workqueues which may be used during memory reclaim should
* have a rescuer to guarantee forward progress.
*/
if (flags & WQ_MEM_RECLAIM)
flags |= WQ_RESCUER;
/* /*
* Unbound workqueues aren't concurrency managed and should be * Unbound workqueues aren't concurrency managed and should be
* dispatched to workers immediately. * dispatched to workers immediately.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment