diff options
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r-- | kernel/workqueue.c | 82 |
1 files changed, 59 insertions, 23 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 57cd77de4a4f..729ac6a44860 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -268,6 +268,9 @@ static int wq_numa_tbl_len; /* highest possible NUMA node id + 1 */ | |||
268 | static cpumask_var_t *wq_numa_possible_cpumask; | 268 | static cpumask_var_t *wq_numa_possible_cpumask; |
269 | /* possible CPUs of each node */ | 269 | /* possible CPUs of each node */ |
270 | 270 | ||
271 | static bool wq_disable_numa; | ||
272 | module_param_named(disable_numa, wq_disable_numa, bool, 0444); | ||
273 | |||
271 | static bool wq_numa_enabled; /* unbound NUMA affinity enabled */ | 274 | static bool wq_numa_enabled; /* unbound NUMA affinity enabled */ |
272 | 275 | ||
273 | /* buf for wq_update_unbound_numa_attrs(), protected by CPU hotplug exclusion */ | 276 | /* buf for wq_update_unbound_numa_attrs(), protected by CPU hotplug exclusion */ |
@@ -517,21 +520,6 @@ static int worker_pool_assign_id(struct worker_pool *pool) | |||
517 | } | 520 | } |
518 | 521 | ||
519 | /** | 522 | /** |
520 | * first_pwq - return the first pool_workqueue of the specified workqueue | ||
521 | * @wq: the target workqueue | ||
522 | * | ||
523 | * This must be called either with wq->mutex held or sched RCU read locked. | ||
524 | * If the pwq needs to be used beyond the locking in effect, the caller is | ||
525 | * responsible for guaranteeing that the pwq stays online. | ||
526 | */ | ||
527 | static struct pool_workqueue *first_pwq(struct workqueue_struct *wq) | ||
528 | { | ||
529 | assert_rcu_or_wq_mutex(wq); | ||
530 | return list_first_or_null_rcu(&wq->pwqs, struct pool_workqueue, | ||
531 | pwqs_node); | ||
532 | } | ||
533 | |||
534 | /** | ||
535 | * unbound_pwq_by_node - return the unbound pool_workqueue for the given node | 523 | * unbound_pwq_by_node - return the unbound pool_workqueue for the given node |
536 | * @wq: the target workqueue | 524 | * @wq: the target workqueue |
537 | * @node: the node ID | 525 | * @node: the node ID |
@@ -3114,16 +3102,21 @@ static struct device_attribute wq_sysfs_attrs[] = { | |||
3114 | __ATTR_NULL, | 3102 | __ATTR_NULL, |
3115 | }; | 3103 | }; |
3116 | 3104 | ||
3117 | static ssize_t wq_pool_id_show(struct device *dev, | 3105 | static ssize_t wq_pool_ids_show(struct device *dev, |
3118 | struct device_attribute *attr, char *buf) | 3106 | struct device_attribute *attr, char *buf) |
3119 | { | 3107 | { |
3120 | struct workqueue_struct *wq = dev_to_wq(dev); | 3108 | struct workqueue_struct *wq = dev_to_wq(dev); |
3121 | struct worker_pool *pool; | 3109 | const char *delim = ""; |
3122 | int written; | 3110 | int node, written = 0; |
3123 | 3111 | ||
3124 | rcu_read_lock_sched(); | 3112 | rcu_read_lock_sched(); |
3125 | pool = first_pwq(wq)->pool; | 3113 | for_each_node(node) { |
3126 | written = scnprintf(buf, PAGE_SIZE, "%d\n", pool->id); | 3114 | written += scnprintf(buf + written, PAGE_SIZE - written, |
3115 | "%s%d:%d", delim, node, | ||
3116 | unbound_pwq_by_node(wq, node)->pool->id); | ||
3117 | delim = " "; | ||
3118 | } | ||
3119 | written += scnprintf(buf + written, PAGE_SIZE - written, "\n"); | ||
3127 | rcu_read_unlock_sched(); | 3120 | rcu_read_unlock_sched(); |
3128 | 3121 | ||
3129 | return written; | 3122 | return written; |
@@ -3212,10 +3205,46 @@ static ssize_t wq_cpumask_store(struct device *dev, | |||
3212 | return ret ?: count; | 3205 | return ret ?: count; |
3213 | } | 3206 | } |
3214 | 3207 | ||
3208 | static ssize_t wq_numa_show(struct device *dev, struct device_attribute *attr, | ||
3209 | char *buf) | ||
3210 | { | ||
3211 | struct workqueue_struct *wq = dev_to_wq(dev); | ||
3212 | int written; | ||
3213 | |||
3214 | mutex_lock(&wq->mutex); | ||
3215 | written = scnprintf(buf, PAGE_SIZE, "%d\n", | ||
3216 | !wq->unbound_attrs->no_numa); | ||
3217 | mutex_unlock(&wq->mutex); | ||
3218 | |||
3219 | return written; | ||
3220 | } | ||
3221 | |||
3222 | static ssize_t wq_numa_store(struct device *dev, struct device_attribute *attr, | ||
3223 | const char *buf, size_t count) | ||
3224 | { | ||
3225 | struct workqueue_struct *wq = dev_to_wq(dev); | ||
3226 | struct workqueue_attrs *attrs; | ||
3227 | int v, ret; | ||
3228 | |||
3229 | attrs = wq_sysfs_prep_attrs(wq); | ||
3230 | if (!attrs) | ||
3231 | return -ENOMEM; | ||
3232 | |||
3233 | ret = -EINVAL; | ||
3234 | if (sscanf(buf, "%d", &v) == 1) { | ||
3235 | attrs->no_numa = !v; | ||
3236 | ret = apply_workqueue_attrs(wq, attrs); | ||
3237 | } | ||
3238 | |||
3239 | free_workqueue_attrs(attrs); | ||
3240 | return ret ?: count; | ||
3241 | } | ||
3242 | |||
3215 | static struct device_attribute wq_sysfs_unbound_attrs[] = { | 3243 | static struct device_attribute wq_sysfs_unbound_attrs[] = { |
3216 | __ATTR(pool_id, 0444, wq_pool_id_show, NULL), | 3244 | __ATTR(pool_ids, 0444, wq_pool_ids_show, NULL), |
3217 | __ATTR(nice, 0644, wq_nice_show, wq_nice_store), | 3245 | __ATTR(nice, 0644, wq_nice_show, wq_nice_store), |
3218 | __ATTR(cpumask, 0644, wq_cpumask_show, wq_cpumask_store), | 3246 | __ATTR(cpumask, 0644, wq_cpumask_show, wq_cpumask_store), |
3247 | __ATTR(numa, 0644, wq_numa_show, wq_numa_store), | ||
3219 | __ATTR_NULL, | 3248 | __ATTR_NULL, |
3220 | }; | 3249 | }; |
3221 | 3250 | ||
@@ -3750,7 +3779,7 @@ static void free_unbound_pwq(struct pool_workqueue *pwq) | |||
3750 | static bool wq_calc_node_cpumask(const struct workqueue_attrs *attrs, int node, | 3779 | static bool wq_calc_node_cpumask(const struct workqueue_attrs *attrs, int node, |
3751 | int cpu_going_down, cpumask_t *cpumask) | 3780 | int cpu_going_down, cpumask_t *cpumask) |
3752 | { | 3781 | { |
3753 | if (!wq_numa_enabled) | 3782 | if (!wq_numa_enabled || attrs->no_numa) |
3754 | goto use_dfl; | 3783 | goto use_dfl; |
3755 | 3784 | ||
3756 | /* does @node have any online CPUs @attrs wants? */ | 3785 | /* does @node have any online CPUs @attrs wants? */ |
@@ -3951,6 +3980,8 @@ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, | |||
3951 | cpumask = target_attrs->cpumask; | 3980 | cpumask = target_attrs->cpumask; |
3952 | 3981 | ||
3953 | mutex_lock(&wq->mutex); | 3982 | mutex_lock(&wq->mutex); |
3983 | if (wq->unbound_attrs->no_numa) | ||
3984 | goto out_unlock; | ||
3954 | 3985 | ||
3955 | copy_workqueue_attrs(target_attrs, wq->unbound_attrs); | 3986 | copy_workqueue_attrs(target_attrs, wq->unbound_attrs); |
3956 | pwq = unbound_pwq_by_node(wq, node); | 3987 | pwq = unbound_pwq_by_node(wq, node); |
@@ -4763,6 +4794,11 @@ static void __init wq_numa_init(void) | |||
4763 | if (num_possible_nodes() <= 1) | 4794 | if (num_possible_nodes() <= 1) |
4764 | return; | 4795 | return; |
4765 | 4796 | ||
4797 | if (wq_disable_numa) { | ||
4798 | pr_info("workqueue: NUMA affinity support disabled\n"); | ||
4799 | return; | ||
4800 | } | ||
4801 | |||
4766 | wq_update_unbound_numa_attrs_buf = alloc_workqueue_attrs(GFP_KERNEL); | 4802 | wq_update_unbound_numa_attrs_buf = alloc_workqueue_attrs(GFP_KERNEL); |
4767 | BUG_ON(!wq_update_unbound_numa_attrs_buf); | 4803 | BUG_ON(!wq_update_unbound_numa_attrs_buf); |
4768 | 4804 | ||