Skip to content

Commit fe28f63

Browse files
Waiman-Longhtejun
authored andcommitted
workqueue: Add workqueue_unbound_exclude_cpumask() to exclude CPUs from wq_unbound_cpumask
When the "isolcpus" boot command line option is used to add a set of isolated CPUs, those CPUs will be excluded automatically from wq_unbound_cpumask to avoid running work functions from unbound workqueues. Recently cpuset has been extended to allow the creation of partitions of isolated CPUs dynamically. To make it closer to the "isolcpus" in functionality, the CPUs in those isolated cpuset partitions should be excluded from wq_unbound_cpumask as well. This can be done currently by explicitly writing to the workqueue's cpumask sysfs file after creating the isolated partitions. However, this process can be error prone. Ideally, the cpuset code should be allowed to request the workqueue code to exclude those isolated CPUs from wq_unbound_cpumask so that this operation can be done automatically and the isolated CPUs will be returned back to wq_unbound_cpumask after the destructions of the isolated cpuset partitions. This patch adds a new workqueue_unbound_exclude_cpumask() function to enable that. This new function will exclude the specified isolated CPUs from wq_unbound_cpumask. To be able to restore those isolated CPUs back after the destruction of isolated cpuset partitions, a new wq_requested_unbound_cpumask is added to store the user provided unbound cpumask either from the boot command line options or from writing to the cpumask sysfs file. This new cpumask provides the basis for CPU exclusion. To enable users to understand how the wq_unbound_cpumask is being modified internally, this patch also exposes the newly introduced wq_requested_unbound_cpumask as well as a wq_isolated_cpumask to store the cpumask to be excluded from wq_unbound_cpumask as read-only sysfs files. Signed-off-by: Waiman Long <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent 421fc85 commit fe28f63

File tree

2 files changed

+84
-9
lines changed

2 files changed

+84
-9
lines changed

include/linux/workqueue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ struct workqueue_attrs *alloc_workqueue_attrs(void);
491491
void free_workqueue_attrs(struct workqueue_attrs *attrs);
492492
int apply_workqueue_attrs(struct workqueue_struct *wq,
493493
const struct workqueue_attrs *attrs);
494-
int workqueue_set_unbound_cpumask(cpumask_var_t cpumask);
494+
extern int workqueue_unbound_exclude_cpumask(cpumask_var_t cpumask);
495495

496496
extern bool queue_work_on(int cpu, struct workqueue_struct *wq,
497497
struct work_struct *work);

kernel/workqueue.c

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,12 @@ static bool workqueue_freezing; /* PL: have wqs started freezing? */
381381
/* PL&A: allowable cpus for unbound wqs and work items */
382382
static cpumask_var_t wq_unbound_cpumask;
383383

384+
/* PL: user requested unbound cpumask via sysfs */
385+
static cpumask_var_t wq_requested_unbound_cpumask;
386+
387+
/* PL: isolated cpumask to be excluded from unbound cpumask */
388+
static cpumask_var_t wq_isolated_cpumask;
389+
384390
/* for further constrain wq_unbound_cpumask by cmdline parameter*/
385391
static struct cpumask wq_cmdline_cpumask __initdata;
386392

@@ -5839,7 +5845,7 @@ static int workqueue_apply_unbound_cpumask(const cpumask_var_t unbound_cpumask)
58395845
* -EINVAL - Invalid @cpumask
58405846
* -ENOMEM - Failed to allocate memory for attrs or pwqs.
58415847
*/
5842-
int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
5848+
static int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
58435849
{
58445850
int ret = -EINVAL;
58455851

@@ -5850,6 +5856,7 @@ int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
58505856
cpumask_and(cpumask, cpumask, cpu_possible_mask);
58515857
if (!cpumask_empty(cpumask)) {
58525858
apply_wqattrs_lock();
5859+
cpumask_copy(wq_requested_unbound_cpumask, cpumask);
58535860
if (cpumask_equal(cpumask, wq_unbound_cpumask)) {
58545861
ret = 0;
58555862
goto out_unlock;
@@ -5864,6 +5871,44 @@ int workqueue_set_unbound_cpumask(cpumask_var_t cpumask)
58645871
return ret;
58655872
}
58665873

5874+
/**
5875+
* workqueue_unbound_exclude_cpumask - Exclude given CPUs from unbound cpumask
5876+
* @exclude_cpumask: the cpumask to be excluded from wq_unbound_cpumask
5877+
*
5878+
* This function can be called from cpuset code to provide a set of isolated
5879+
* CPUs that should be excluded from wq_unbound_cpumask. The caller must hold
5880+
* either cpus_read_lock or cpus_write_lock.
5881+
*/
5882+
int workqueue_unbound_exclude_cpumask(cpumask_var_t exclude_cpumask)
5883+
{
5884+
cpumask_var_t cpumask;
5885+
int ret = 0;
5886+
5887+
if (!zalloc_cpumask_var(&cpumask, GFP_KERNEL))
5888+
return -ENOMEM;
5889+
5890+
lockdep_assert_cpus_held();
5891+
mutex_lock(&wq_pool_mutex);
5892+
5893+
/* Save the current isolated cpumask & export it via sysfs */
5894+
cpumask_copy(wq_isolated_cpumask, exclude_cpumask);
5895+
5896+
/*
5897+
* If the operation fails, it will fall back to
5898+
* wq_requested_unbound_cpumask which is initially set to
5899+
* (HK_TYPE_WQ ∩ HK_TYPE_DOMAIN) house keeping mask and rewritten
5900+
* by any subsequent write to workqueue/cpumask sysfs file.
5901+
*/
5902+
if (!cpumask_andnot(cpumask, wq_requested_unbound_cpumask, exclude_cpumask))
5903+
cpumask_copy(cpumask, wq_requested_unbound_cpumask);
5904+
if (!cpumask_equal(cpumask, wq_unbound_cpumask))
5905+
ret = workqueue_apply_unbound_cpumask(cpumask);
5906+
5907+
mutex_unlock(&wq_pool_mutex);
5908+
free_cpumask_var(cpumask);
5909+
return ret;
5910+
}
5911+
58675912
static int parse_affn_scope(const char *val)
58685913
{
58695914
int i;
@@ -6158,19 +6203,36 @@ static struct bus_type wq_subsys = {
61586203
.dev_groups = wq_sysfs_groups,
61596204
};
61606205

6161-
static ssize_t wq_unbound_cpumask_show(struct device *dev,
6162-
struct device_attribute *attr, char *buf)
6206+
static ssize_t __wq_cpumask_show(struct device *dev,
6207+
struct device_attribute *attr, char *buf, cpumask_var_t mask)
61636208
{
61646209
int written;
61656210

61666211
mutex_lock(&wq_pool_mutex);
6167-
written = scnprintf(buf, PAGE_SIZE, "%*pb\n",
6168-
cpumask_pr_args(wq_unbound_cpumask));
6212+
written = scnprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask));
61696213
mutex_unlock(&wq_pool_mutex);
61706214

61716215
return written;
61726216
}
61736217

6218+
static ssize_t wq_unbound_cpumask_show(struct device *dev,
6219+
struct device_attribute *attr, char *buf)
6220+
{
6221+
return __wq_cpumask_show(dev, attr, buf, wq_unbound_cpumask);
6222+
}
6223+
6224+
static ssize_t wq_requested_cpumask_show(struct device *dev,
6225+
struct device_attribute *attr, char *buf)
6226+
{
6227+
return __wq_cpumask_show(dev, attr, buf, wq_requested_unbound_cpumask);
6228+
}
6229+
6230+
static ssize_t wq_isolated_cpumask_show(struct device *dev,
6231+
struct device_attribute *attr, char *buf)
6232+
{
6233+
return __wq_cpumask_show(dev, attr, buf, wq_isolated_cpumask);
6234+
}
6235+
61746236
static ssize_t wq_unbound_cpumask_store(struct device *dev,
61756237
struct device_attribute *attr, const char *buf, size_t count)
61766238
{
@@ -6188,9 +6250,13 @@ static ssize_t wq_unbound_cpumask_store(struct device *dev,
61886250
return ret ? ret : count;
61896251
}
61906252

6191-
static struct device_attribute wq_sysfs_cpumask_attr =
6253+
static struct device_attribute wq_sysfs_cpumask_attrs[] = {
61926254
__ATTR(cpumask, 0644, wq_unbound_cpumask_show,
6193-
wq_unbound_cpumask_store);
6255+
wq_unbound_cpumask_store),
6256+
__ATTR(cpumask_requested, 0444, wq_requested_cpumask_show, NULL),
6257+
__ATTR(cpumask_isolated, 0444, wq_isolated_cpumask_show, NULL),
6258+
__ATTR_NULL,
6259+
};
61946260

61956261
static int __init wq_sysfs_init(void)
61966262
{
@@ -6203,7 +6269,13 @@ static int __init wq_sysfs_init(void)
62036269

62046270
dev_root = bus_get_dev_root(&wq_subsys);
62056271
if (dev_root) {
6206-
err = device_create_file(dev_root, &wq_sysfs_cpumask_attr);
6272+
struct device_attribute *attr;
6273+
6274+
for (attr = wq_sysfs_cpumask_attrs; attr->attr.name; attr++) {
6275+
err = device_create_file(dev_root, attr);
6276+
if (err)
6277+
break;
6278+
}
62076279
put_device(dev_root);
62086280
}
62096281
return err;
@@ -6534,11 +6606,14 @@ void __init workqueue_init_early(void)
65346606
BUILD_BUG_ON(__alignof__(struct pool_workqueue) < __alignof__(long long));
65356607

65366608
BUG_ON(!alloc_cpumask_var(&wq_unbound_cpumask, GFP_KERNEL));
6609+
BUG_ON(!alloc_cpumask_var(&wq_requested_unbound_cpumask, GFP_KERNEL));
6610+
BUG_ON(!zalloc_cpumask_var(&wq_isolated_cpumask, GFP_KERNEL));
65376611
cpumask_copy(wq_unbound_cpumask, housekeeping_cpumask(HK_TYPE_WQ));
65386612
cpumask_and(wq_unbound_cpumask, wq_unbound_cpumask, housekeeping_cpumask(HK_TYPE_DOMAIN));
65396613

65406614
if (!cpumask_empty(&wq_cmdline_cpumask))
65416615
cpumask_and(wq_unbound_cpumask, wq_unbound_cpumask, &wq_cmdline_cpumask);
6616+
cpumask_copy(wq_requested_unbound_cpumask, wq_unbound_cpumask);
65426617

65436618
pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC);
65446619

0 commit comments

Comments
 (0)