6039 lines · 165.7 KB · C
RawDownload
 	ida_destroy(&pool->worker_ida);	free_workqueue_attrs(pool->attrs);	kfree(pool);} /* This returns with the lock held on success (pool manager is inactive). */static bool wq_manager_inactive(struct worker_pool *pool){	raw_spin_lock_irq(&pool->lock); 	if (pool->flags & POOL_MANAGER_ACTIVE) {		raw_spin_unlock_irq(&pool->lock);		return false;	}	return true;} /** * put_unbound_pool - put a worker_pool * @pool: worker_pool to put * * Put @pool.  If its refcnt reaches zero, it gets destroyed in RCU * safe manner.  get_unbound_pool() calls this function on its failure path * and this function should be able to release pools which went through, * successfully or not, init_worker_pool(). * * Should be called with wq_pool_mutex held. */static void put_unbound_pool(struct worker_pool *pool){	DECLARE_COMPLETION_ONSTACK(detach_completion);	struct worker *worker; 	lockdep_assert_held(&wq_pool_mutex); 	if (--pool->refcnt)		return; 	/* sanity checks */	if (WARN_ON(!(pool->cpu < 0)) ||	    WARN_ON(!list_empty(&pool->worklist)))		return; 	/* release id and unhash */	if (pool->id >= 0)		idr_remove(&worker_pool_idr, pool->id);	hash_del(&pool->hash_node); 	/*	 * Become the manager and destroy all workers.  This prevents	 * @pool's workers from blocking on attach_mutex.  We're the last	 * manager and @pool gets freed with the flag set.	 * Because of how wq_manager_inactive() works, we will hold the	 * spinlock after a successful wait.	 */	rcuwait_wait_event(&manager_wait, wq_manager_inactive(pool),			   TASK_UNINTERRUPTIBLE);	pool->flags |= POOL_MANAGER_ACTIVE; 	while ((worker = first_idle_worker(pool)))		destroy_worker(worker);	WARN_ON(pool->nr_workers || pool->nr_idle);	raw_spin_unlock_irq(&pool->lock); 	mutex_lock(&wq_pool_attach_mutex);	if (!list_empty(&pool->workers))		pool->detach_completion = &detach_completion;	mutex_unlock(&wq_pool_attach_mutex); 	if (pool->detach_completion)		wait_for_completion(pool->detach_completion); 	/* shut down the timers */	del_timer_sync(&pool->idle_timer);	del_timer_sync(&pool->mayday_timer); 	/* RCU protected to allow dereferences from get_work_pool() */	call_rcu(&pool->rcu, rcu_free_pool);} /** * get_unbound_pool - get a worker_pool with the specified attributes * @attrs: the attributes of the worker_pool to get * * Obtain a worker_pool which has the same attributes as @attrs, bump the * reference count and return it.  If there already is a matching * worker_pool, it will be used; otherwise, this function attempts to * create a new one. * * Should be called with wq_pool_mutex held. * * Return: On success, a worker_pool with the same attributes as @attrs. * On failure, %NULL. */static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs){	u32 hash = wqattrs_hash(attrs);	struct worker_pool *pool;	int node;	int target_node = NUMA_NO_NODE; 	lockdep_assert_held(&wq_pool_mutex); 	/* do we already have a matching pool? */	hash_for_each_possible(unbound_pool_hash, pool, hash_node, hash) {		if (wqattrs_equal(pool->attrs, attrs)) {			pool->refcnt++;			return pool;		}	} 	/* if cpumask is contained inside a NUMA node, we belong to that node */	if (wq_numa_enabled) {		for_each_node(node) {			if (cpumask_subset(attrs->cpumask,					   wq_numa_possible_cpumask[node])) {				target_node = node;				break;			}		}	} 	/* nope, create a new one */	pool = kzalloc_node(sizeof(*pool), GFP_KERNEL, target_node);	if (!pool || init_worker_pool(pool) < 0)		goto fail; 	lockdep_set_subclass(&pool->lock, 1);	/* see put_pwq() */	copy_workqueue_attrs(pool->attrs, attrs);	pool->node = target_node; 	/*	 * no_numa isn't a worker_pool attribute, always clear it.  See	 * 'struct workqueue_attrs' comments for detail.	 */	pool->attrs->no_numa = false; 	if (worker_pool_assign_id(pool) < 0)		goto fail; 	/* create and start the initial worker */	if (wq_online && !create_worker(pool))		goto fail; 	/* install */	hash_add(unbound_pool_hash, &pool->hash_node, hash); 	return pool;fail:	if (pool)		put_unbound_pool(pool);	return NULL;} static void rcu_free_pwq(struct rcu_head *rcu){	kmem_cache_free(pwq_cache,			container_of(rcu, struct pool_workqueue, rcu));} /* * Scheduled on system_wq by put_pwq() when an unbound pwq hits zero refcnt * and needs to be destroyed. */static void pwq_unbound_release_workfn(struct work_struct *work){	struct pool_workqueue *pwq = container_of(work, struct pool_workqueue,						  unbound_release_work);	struct workqueue_struct *wq = pwq->wq;	struct worker_pool *pool = pwq->pool;	bool is_last; 	if (WARN_ON_ONCE(!(wq->flags & WQ_UNBOUND)))		return; 	mutex_lock(&wq->mutex);	list_del_rcu(&pwq->pwqs_node);	is_last = list_empty(&wq->pwqs);	mutex_unlock(&wq->mutex); 	mutex_lock(&wq_pool_mutex);	put_unbound_pool(pool);	mutex_unlock(&wq_pool_mutex); 	call_rcu(&pwq->rcu, rcu_free_pwq); 	/*	 * If we're the last pwq going away, @wq is already dead and no one	 * is gonna access it anymore.  Schedule RCU free.	 */	if (is_last) {		wq_unregister_lockdep(wq);		call_rcu(&wq->rcu, rcu_free_wq);	}} /** * pwq_adjust_max_active - update a pwq's max_active to the current setting * @pwq: target pool_workqueue * * If @pwq isn't freezing, set @pwq->max_active to the associated * workqueue's saved_max_active and activate delayed work items * accordingly.  If @pwq is freezing, clear @pwq->max_active to zero. */static void pwq_adjust_max_active(struct pool_workqueue *pwq){	struct workqueue_struct *wq = pwq->wq;	bool freezable = wq->flags & WQ_FREEZABLE;	unsigned long flags; 	/* for @wq->saved_max_active */	lockdep_assert_held(&wq->mutex); 	/* fast exit for non-freezable wqs */	if (!freezable && pwq->max_active == wq->saved_max_active)		return; 	/* this function can be called during early boot w/ irq disabled */	raw_spin_lock_irqsave(&pwq->pool->lock, flags); 	/*	 * During [un]freezing, the caller is responsible for ensuring that	 * this function is called at least once after @workqueue_freezing	 * is updated and visible.	 */	if (!freezable || !workqueue_freezing) {		pwq->max_active = wq->saved_max_active; 		while (!list_empty(&pwq->delayed_works) &&		       pwq->nr_active < pwq->max_active)			pwq_activate_first_delayed(pwq); 		/*		 * Need to kick a worker after thawed or an unbound wq's		 * max_active is bumped.  It's a slow path.  Do it always.		 */		wake_up_worker(pwq->pool);	} else {		pwq->max_active = 0;	} 	raw_spin_unlock_irqrestore(&pwq->pool->lock, flags);} /* initialize newly alloced @pwq which is associated with @wq and @pool */static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq,		     struct worker_pool *pool){	BUG_ON((unsigned long)pwq & WORK_STRUCT_FLAG_MASK); 	memset(pwq, 0, sizeof(*pwq)); 	pwq->pool = pool;	pwq->wq = wq;	pwq->flush_color = -1;	pwq->refcnt = 1;	INIT_LIST_HEAD(&pwq->delayed_works);	INIT_LIST_HEAD(&pwq->pwqs_node);	INIT_LIST_HEAD(&pwq->mayday_node);	INIT_WORK(&pwq->unbound_release_work, pwq_unbound_release_workfn);} /* sync @pwq with the current state of its associated wq and link it */static void link_pwq(struct pool_workqueue *pwq){	struct workqueue_struct *wq = pwq->wq; 	lockdep_assert_held(&wq->mutex); 	/* may be called multiple times, ignore if already linked */	if (!list_empty(&pwq->pwqs_node))		return; 	/* set the matching work_color */	pwq->work_color = wq->work_color; 	/* sync max_active to the current setting */	pwq_adjust_max_active(pwq); 	/* link in @pwq */	list_add_rcu(&pwq->pwqs_node, &wq->pwqs);} /* obtain a pool matching @attr and create a pwq associating the pool and @wq */static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq,					const struct workqueue_attrs *attrs){	struct worker_pool *pool;	struct pool_workqueue *pwq; 	lockdep_assert_held(&wq_pool_mutex); 	pool = get_unbound_pool(attrs);	if (!pool)		return NULL; 	pwq = kmem_cache_alloc_node(pwq_cache, GFP_KERNEL, pool->node);	if (!pwq) {		put_unbound_pool(pool);		return NULL;	} 	init_pwq(pwq, wq, pool);	return pwq;} /** * wq_calc_node_cpumask - calculate a wq_attrs' cpumask for the specified node * @attrs: the wq_attrs of the default pwq of the target workqueue * @node: the target NUMA node * @cpu_going_down: if >= 0, the CPU to consider as offline * @cpumask: outarg, the resulting cpumask * * Calculate the cpumask a workqueue with @attrs should use on @node.  If * @cpu_going_down is >= 0, that cpu is considered offline during * calculation.  The result is stored in @cpumask. * * If NUMA affinity is not enabled, @attrs->cpumask is always used.  If * enabled and @node has online CPUs requested by @attrs, the returned * cpumask is the intersection of the possible CPUs of @node and * @attrs->cpumask. * * The caller is responsible for ensuring that the cpumask of @node stays * stable. * * Return: %true if the resulting @cpumask is different from @attrs->cpumask, * %false if equal. */static bool wq_calc_node_cpumask(const struct workqueue_attrs *attrs, int node,				 int cpu_going_down, cpumask_t *cpumask){	if (!wq_numa_enabled || attrs->no_numa)		goto use_dfl; 	/* does @node have any online CPUs @attrs wants? */	cpumask_and(cpumask, cpumask_of_node(node), attrs->cpumask);	if (cpu_going_down >= 0)		cpumask_clear_cpu(cpu_going_down, cpumask); 	if (cpumask_empty(cpumask))		goto use_dfl; 	/* yeap, return possible CPUs in @node that @attrs wants */	cpumask_and(cpumask, attrs->cpumask, wq_numa_possible_cpumask[node]); 	if (cpumask_empty(cpumask)) {		pr_warn_once("WARNING: workqueue cpumask: online intersect > "				"possible intersect\n");		return false;	} 	return !cpumask_equal(cpumask, attrs->cpumask); use_dfl:	cpumask_copy(cpumask, attrs->cpumask);	return false;} /* install @pwq into @wq's numa_pwq_tbl[] for @node and return the old pwq */static struct pool_workqueue *numa_pwq_tbl_install(struct workqueue_struct *wq,						   int node,						   struct pool_workqueue *pwq){	struct pool_workqueue *old_pwq; 	lockdep_assert_held(&wq_pool_mutex);	lockdep_assert_held(&wq->mutex); 	/* link_pwq() can handle duplicate calls */	link_pwq(pwq); 	old_pwq = rcu_access_pointer(wq->numa_pwq_tbl[node]);	rcu_assign_pointer(wq->numa_pwq_tbl[node], pwq);	return old_pwq;} /* context to store the prepared attrs & pwqs before applying */struct apply_wqattrs_ctx {	struct workqueue_struct	*wq;		/* target workqueue */	struct workqueue_attrs	*attrs;		/* attrs to apply */	struct list_head	list;		/* queued for batching commit */	struct pool_workqueue	*dfl_pwq;	struct pool_workqueue	*pwq_tbl[];}; /* free the resources after success or abort */static void apply_wqattrs_cleanup(struct apply_wqattrs_ctx *ctx){	if (ctx) {		int node; 		for_each_node(node)			put_pwq_unlocked(ctx->pwq_tbl[node]);		put_pwq_unlocked(ctx->dfl_pwq); 		free_workqueue_attrs(ctx->attrs); 		kfree(ctx);	}} /* allocate the attrs and pwqs for later installation */static struct apply_wqattrs_ctx *apply_wqattrs_prepare(struct workqueue_struct *wq,		      const struct workqueue_attrs *attrs){	struct apply_wqattrs_ctx *ctx;	struct workqueue_attrs *new_attrs, *tmp_attrs;	int node; 	lockdep_assert_held(&wq_pool_mutex); 	ctx = kzalloc(struct_size(ctx, pwq_tbl, nr_node_ids), GFP_KERNEL); 	new_attrs = alloc_workqueue_attrs();	tmp_attrs = alloc_workqueue_attrs();	if (!ctx || !new_attrs || !tmp_attrs)		goto out_free; 	/*	 * Calculate the attrs of the default pwq.	 * If the user configured cpumask doesn't overlap with the	 * wq_unbound_cpumask, we fallback to the wq_unbound_cpumask.	 */	copy_workqueue_attrs(new_attrs, attrs);	cpumask_and(new_attrs->cpumask, new_attrs->cpumask, wq_unbound_cpumask);	if (unlikely(cpumask_empty(new_attrs->cpumask)))		cpumask_copy(new_attrs->cpumask, wq_unbound_cpumask); 	/*	 * We may create multiple pwqs with differing cpumasks.  Make a	 * copy of @new_attrs which will be modified and used to obtain	 * pools.	 */	copy_workqueue_attrs(tmp_attrs, new_attrs); 	/*	 * If something goes wrong during CPU up/down, we'll fall back to	 * the default pwq covering whole @attrs->cpumask.  Always create	 * it even if we don't use it immediately.	 */	ctx->dfl_pwq = alloc_unbound_pwq(wq, new_attrs);	if (!ctx->dfl_pwq)		goto out_free; 	for_each_node(node) {		if (wq_calc_node_cpumask(new_attrs, node, -1, tmp_attrs->cpumask)) {			ctx->pwq_tbl[node] = alloc_unbound_pwq(wq, tmp_attrs);			if (!ctx->pwq_tbl[node])				goto out_free;		} else {			ctx->dfl_pwq->refcnt++;			ctx->pwq_tbl[node] = ctx->dfl_pwq;		}	} 	/* save the user configured attrs and sanitize it. */	copy_workqueue_attrs(new_attrs, attrs);	cpumask_and(new_attrs->cpumask, new_attrs->cpumask, cpu_possible_mask);	ctx->attrs = new_attrs; 	ctx->wq = wq;	free_workqueue_attrs(tmp_attrs);	return ctx; out_free:	free_workqueue_attrs(tmp_attrs);	free_workqueue_attrs(new_attrs);	apply_wqattrs_cleanup(ctx);	return NULL;} /* set attrs and install prepared pwqs, @ctx points to old pwqs on return */static void apply_wqattrs_commit(struct apply_wqattrs_ctx *ctx){	int node; 	/* all pwqs have been created successfully, let's install'em */	mutex_lock(&ctx->wq->mutex); 	copy_workqueue_attrs(ctx->wq->unbound_attrs, ctx->attrs); 	/* save the previous pwq and install the new one */	for_each_node(node)		ctx->pwq_tbl[node] = numa_pwq_tbl_install(ctx->wq, node,							  ctx->pwq_tbl[node]); 	/* @dfl_pwq might not have been used, ensure it's linked */	link_pwq(ctx->dfl_pwq);	swap(ctx->wq->dfl_pwq, ctx->dfl_pwq); 	mutex_unlock(&ctx->wq->mutex);} static void apply_wqattrs_lock(void){	/* CPUs should stay stable across pwq creations and installations */	get_online_cpus();	mutex_lock(&wq_pool_mutex);

Lines 3501–4000 of 6039. Previous lines