|
@@ -305,6 +305,9 @@ static DEFINE_HASHTABLE(unbound_pool_hash, UNBOUND_POOL_HASH_ORDER);
|
|
|
/* I: attributes used when instantiating standard unbound pools on demand */
|
|
|
static struct workqueue_attrs *unbound_std_wq_attrs[NR_STD_WORKER_POOLS];
|
|
|
|
|
|
+/* I: attributes used when instantiating ordered pools on demand */
|
|
|
+static struct workqueue_attrs *ordered_wq_attrs[NR_STD_WORKER_POOLS];
|
|
|
+
|
|
|
struct workqueue_struct *system_wq __read_mostly;
|
|
|
EXPORT_SYMBOL(system_wq);
|
|
|
struct workqueue_struct *system_highpri_wq __read_mostly;
|
|
@@ -518,14 +521,21 @@ static inline void debug_work_activate(struct work_struct *work) { }
|
|
|
static inline void debug_work_deactivate(struct work_struct *work) { }
|
|
|
#endif
|
|
|
|
|
|
-/* allocate ID and assign it to @pool */
|
|
|
+/**
|
|
|
+ * worker_pool_assign_id - allocate ID and assing it to @pool
|
|
|
+ * @pool: the pool pointer of interest
|
|
|
+ *
|
|
|
+ * Returns 0 if ID in [0, WORK_OFFQ_POOL_NONE) is allocated and assigned
|
|
|
+ * successfully, -errno on failure.
|
|
|
+ */
|
|
|
static int worker_pool_assign_id(struct worker_pool *pool)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
lockdep_assert_held(&wq_pool_mutex);
|
|
|
|
|
|
- ret = idr_alloc(&worker_pool_idr, pool, 0, 0, GFP_KERNEL);
|
|
|
+ ret = idr_alloc(&worker_pool_idr, pool, 0, WORK_OFFQ_POOL_NONE,
|
|
|
+ GFP_KERNEL);
|
|
|
if (ret >= 0) {
|
|
|
pool->id = ret;
|
|
|
return 0;
|
|
@@ -1320,7 +1330,7 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
|
|
|
|
|
|
debug_work_activate(work);
|
|
|
|
|
|
- /* if dying, only works from the same workqueue are allowed */
|
|
|
+ /* if draining, only works from the same workqueue are allowed */
|
|
|
if (unlikely(wq->flags & __WQ_DRAINING) &&
|
|
|
WARN_ON_ONCE(!is_chained_work(wq)))
|
|
|
return;
|
|
@@ -1736,16 +1746,17 @@ static struct worker *create_worker(struct worker_pool *pool)
|
|
|
if (IS_ERR(worker->task))
|
|
|
goto fail;
|
|
|
|
|
|
+ set_user_nice(worker->task, pool->attrs->nice);
|
|
|
+
|
|
|
+ /* prevent userland from meddling with cpumask of workqueue workers */
|
|
|
+ worker->task->flags |= PF_NO_SETAFFINITY;
|
|
|
+
|
|
|
/*
|
|
|
* set_cpus_allowed_ptr() will fail if the cpumask doesn't have any
|
|
|
* online CPUs. It'll be re-applied when any of the CPUs come up.
|
|
|
*/
|
|
|
- set_user_nice(worker->task, pool->attrs->nice);
|
|
|
set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask);
|
|
|
|
|
|
- /* prevent userland from meddling with cpumask of workqueue workers */
|
|
|
- worker->task->flags |= PF_NO_SETAFFINITY;
|
|
|
-
|
|
|
/*
|
|
|
* The caller is responsible for ensuring %POOL_DISASSOCIATED
|
|
|
* remains stable across this function. See the comments above the
|
|
@@ -4106,7 +4117,7 @@ out_unlock:
|
|
|
static int alloc_and_link_pwqs(struct workqueue_struct *wq)
|
|
|
{
|
|
|
bool highpri = wq->flags & WQ_HIGHPRI;
|
|
|
- int cpu;
|
|
|
+ int cpu, ret;
|
|
|
|
|
|
if (!(wq->flags & WQ_UNBOUND)) {
|
|
|
wq->cpu_pwqs = alloc_percpu(struct pool_workqueue);
|
|
@@ -4126,6 +4137,13 @@ static int alloc_and_link_pwqs(struct workqueue_struct *wq)
|
|
|
mutex_unlock(&wq->mutex);
|
|
|
}
|
|
|
return 0;
|
|
|
+ } else if (wq->flags & __WQ_ORDERED) {
|
|
|
+ ret = apply_workqueue_attrs(wq, ordered_wq_attrs[highpri]);
|
|
|
+ /* there should only be single pwq for ordering guarantee */
|
|
|
+ WARN(!ret && (wq->pwqs.next != &wq->dfl_pwq->pwqs_node ||
|
|
|
+ wq->pwqs.prev != &wq->dfl_pwq->pwqs_node),
|
|
|
+ "ordering guarantee broken for workqueue %s\n", wq->name);
|
|
|
+ return ret;
|
|
|
} else {
|
|
|
return apply_workqueue_attrs(wq, unbound_std_wq_attrs[highpri]);
|
|
|
}
|
|
@@ -5009,10 +5027,6 @@ static int __init init_workqueues(void)
|
|
|
int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL };
|
|
|
int i, cpu;
|
|
|
|
|
|
- /* make sure we have enough bits for OFFQ pool ID */
|
|
|
- BUILD_BUG_ON((1LU << (BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT)) <
|
|
|
- WORK_CPU_END * NR_STD_WORKER_POOLS);
|
|
|
-
|
|
|
WARN_ON(__alignof__(struct pool_workqueue) < __alignof__(long long));
|
|
|
|
|
|
pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC);
|
|
@@ -5051,13 +5065,23 @@ static int __init init_workqueues(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /* create default unbound wq attrs */
|
|
|
+ /* create default unbound and ordered wq attrs */
|
|
|
for (i = 0; i < NR_STD_WORKER_POOLS; i++) {
|
|
|
struct workqueue_attrs *attrs;
|
|
|
|
|
|
BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL)));
|
|
|
attrs->nice = std_nice[i];
|
|
|
unbound_std_wq_attrs[i] = attrs;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * An ordered wq should have only one pwq as ordering is
|
|
|
+ * guaranteed by max_active which is enforced by pwqs.
|
|
|
+ * Turn off NUMA so that dfl_pwq is used for all nodes.
|
|
|
+ */
|
|
|
+ BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL)));
|
|
|
+ attrs->nice = std_nice[i];
|
|
|
+ attrs->no_numa = true;
|
|
|
+ ordered_wq_attrs[i] = attrs;
|
|
|
}
|
|
|
|
|
|
system_wq = alloc_workqueue("events", 0, 0);
|