Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

workqueue: Make default affinity_scope dynamically updatable

While workqueue.default_affinity_scope is writable, it only affects
workqueues which are created afterwards and isn't very useful. Instead,
let's introduce explicit "default" scope and update the effective scope
dynamically when workqueue.default_affinity_scope is changed.

Signed-off-by: Tejun Heo <tj@kernel.org>

+52 -13
+4 -4
Documentation/admin-guide/kernel-parameters.txt
··· 7014 7014 information, see the Affinity Scopes section in 7015 7015 Documentation/core-api/workqueue.rst. 7016 7016 7017 - This can be updated after boot through the matching 7018 - file under /sys/module/workqueue/parameters. 7019 - However, the changed default will only apply to 7020 - unbound workqueues created afterwards. 7017 + This can be changed after boot by writing to the 7018 + matching /sys/module/workqueue/parameters file. All 7019 + workqueues with the "default" affinity scope will be 7020 + updated accordignly. 7021 7021 7022 7022 workqueue.debug_force_rr_cpu 7023 7023 Workqueue used to implicitly guarantee that work
+8 -1
Documentation/core-api/workqueue.rst
··· 358 358 Once started, the worker may or may not be allowed to move outside the scope 359 359 depending on the ``affinity_strict`` setting of the scope. 360 360 361 - Workqueue currently supports the following five affinity scopes. 361 + Workqueue currently supports the following affinity scopes. 362 + 363 + ``default`` 364 + Use the scope in module parameter ``workqueue.default_affinity_scope`` 365 + which is always set to one of the scopes below. 362 366 363 367 ``cpu`` 364 368 CPUs are not grouped. A work item issued on one CPU is processed by a ··· 395 391 396 392 ``affinity_scope`` 397 393 Read to see the current affinity scope. Write to change. 394 + 395 + When default is the current scope, reading this file will also show the 396 + current effective scope in parentheses, for example, ``default (cache)``. 398 397 399 398 ``affinity_strict`` 400 399 0 by default indicating that affinity scopes are not strict. When a work
+1 -2
include/linux/workqueue.h
··· 126 126 }; 127 127 128 128 enum wq_affn_scope { 129 + WQ_AFFN_DFL, /* use system default */ 129 130 WQ_AFFN_CPU, /* one pod per CPU */ 130 131 WQ_AFFN_SMT, /* one pod poer SMT */ 131 132 WQ_AFFN_CACHE, /* one pod per LLC */ ··· 134 133 WQ_AFFN_SYSTEM, /* one pod across the whole system */ 135 134 136 135 WQ_AFFN_NR_TYPES, 137 - 138 - WQ_AFFN_DFL = WQ_AFFN_CACHE, 139 136 }; 140 137 141 138 /**
+39 -6
kernel/workqueue.c
··· 339 339 }; 340 340 341 341 static struct wq_pod_type wq_pod_types[WQ_AFFN_NR_TYPES]; 342 - static enum wq_affn_scope wq_affn_dfl = WQ_AFFN_DFL; 342 + static enum wq_affn_scope wq_affn_dfl = WQ_AFFN_CACHE; 343 343 344 344 static const char *wq_affn_names[WQ_AFFN_NR_TYPES] = { 345 + [WQ_AFFN_DFL] = "default", 345 346 [WQ_AFFN_CPU] = "cpu", 346 347 [WQ_AFFN_SMT] = "smt", 347 348 [WQ_AFFN_CACHE] = "cache", ··· 3735 3734 goto fail; 3736 3735 3737 3736 cpumask_copy(attrs->cpumask, cpu_possible_mask); 3738 - attrs->affn_scope = wq_affn_dfl; 3737 + attrs->affn_scope = WQ_AFFN_DFL; 3739 3738 return attrs; 3740 3739 fail: 3741 3740 free_workqueue_attrs(attrs); ··· 3816 3815 static const struct wq_pod_type * 3817 3816 wqattrs_pod_type(const struct workqueue_attrs *attrs) 3818 3817 { 3819 - struct wq_pod_type *pt = &wq_pod_types[attrs->affn_scope]; 3818 + enum wq_affn_scope scope; 3819 + struct wq_pod_type *pt; 3820 + 3821 + /* to synchronize access to wq_affn_dfl */ 3822 + lockdep_assert_held(&wq_pool_mutex); 3823 + 3824 + if (attrs->affn_scope == WQ_AFFN_DFL) 3825 + scope = wq_affn_dfl; 3826 + else 3827 + scope = attrs->affn_scope; 3828 + 3829 + pt = &wq_pod_types[scope]; 3820 3830 3821 3831 if (!WARN_ON_ONCE(attrs->affn_scope == WQ_AFFN_NR_TYPES) && 3822 3832 likely(pt->nr_pods)) ··· 5859 5847 5860 5848 static int wq_affn_dfl_set(const char *val, const struct kernel_param *kp) 5861 5849 { 5862 - int affn; 5850 + struct workqueue_struct *wq; 5851 + int affn, cpu; 5863 5852 5864 5853 affn = parse_affn_scope(val); 5865 5854 if (affn < 0) 5866 5855 return affn; 5856 + if (affn == WQ_AFFN_DFL) 5857 + return -EINVAL; 5858 + 5859 + cpus_read_lock(); 5860 + mutex_lock(&wq_pool_mutex); 5867 5861 5868 5862 wq_affn_dfl = affn; 5863 + 5864 + list_for_each_entry(wq, &workqueues, list) { 5865 + for_each_online_cpu(cpu) { 5866 + wq_update_pod(wq, cpu, cpu, true); 5867 + } 5868 + } 5869 + 5870 + mutex_unlock(&wq_pool_mutex); 5871 + cpus_read_unlock(); 5872 + 5869 5873 return 0; 5870 5874 } 5871 5875 ··· 6061 6033 int written; 6062 6034 6063 6035 mutex_lock(&wq->mutex); 6064 - written = scnprintf(buf, PAGE_SIZE, "%s\n", 6065 - wq_affn_names[wq->unbound_attrs->affn_scope]); 6036 + if (wq->unbound_attrs->affn_scope == WQ_AFFN_DFL) 6037 + written = scnprintf(buf, PAGE_SIZE, "%s (%s)\n", 6038 + wq_affn_names[WQ_AFFN_DFL], 6039 + wq_affn_names[wq_affn_dfl]); 6040 + else 6041 + written = scnprintf(buf, PAGE_SIZE, "%s\n", 6042 + wq_affn_names[wq->unbound_attrs->affn_scope]); 6066 6043 mutex_unlock(&wq->mutex); 6067 6044 6068 6045 return written;