6039 lines · 165.7 KB · C
RawDownload
				const char *buf, size_t count){	struct workqueue_struct *wq = dev_to_wq(dev);	struct workqueue_attrs *attrs;	int ret = -ENOMEM; 	apply_wqattrs_lock(); 	attrs = wq_sysfs_prep_attrs(wq);	if (!attrs)		goto out_unlock; 	ret = cpumask_parse(buf, attrs->cpumask);	if (!ret)		ret = apply_workqueue_attrs_locked(wq, attrs); out_unlock:	apply_wqattrs_unlock();	free_workqueue_attrs(attrs);	return ret ?: count;} static ssize_t wq_numa_show(struct device *dev, struct device_attribute *attr,			    char *buf){	struct workqueue_struct *wq = dev_to_wq(dev);	int written; 	mutex_lock(&wq->mutex);	written = scnprintf(buf, PAGE_SIZE, "%d\n",			    !wq->unbound_attrs->no_numa);	mutex_unlock(&wq->mutex); 	return written;} static ssize_t wq_numa_store(struct device *dev, struct device_attribute *attr,			     const char *buf, size_t count){	struct workqueue_struct *wq = dev_to_wq(dev);	struct workqueue_attrs *attrs;	int v, ret = -ENOMEM; 	apply_wqattrs_lock(); 	attrs = wq_sysfs_prep_attrs(wq);	if (!attrs)		goto out_unlock; 	ret = -EINVAL;	if (sscanf(buf, "%d", &v) == 1) {		attrs->no_numa = !v;		ret = apply_workqueue_attrs_locked(wq, attrs);	} out_unlock:	apply_wqattrs_unlock();	free_workqueue_attrs(attrs);	return ret ?: count;} static struct device_attribute wq_sysfs_unbound_attrs[] = {	__ATTR(pool_ids, 0444, wq_pool_ids_show, NULL),	__ATTR(nice, 0644, wq_nice_show, wq_nice_store),	__ATTR(cpumask, 0644, wq_cpumask_show, wq_cpumask_store),	__ATTR(numa, 0644, wq_numa_show, wq_numa_store),	__ATTR_NULL,}; static struct bus_type wq_subsys = {	.name				= "workqueue",	.dev_groups			= wq_sysfs_groups,}; static ssize_t wq_unbound_cpumask_show(struct device *dev,		struct device_attribute *attr, char *buf){	int written; 	mutex_lock(&wq_pool_mutex);	written = scnprintf(buf, PAGE_SIZE, "%*pb\n",			    cpumask_pr_args(wq_unbound_cpumask));	mutex_unlock(&wq_pool_mutex); 	return written;} static ssize_t wq_unbound_cpumask_store(struct device *dev,		struct device_attribute *attr, const char *buf, size_t count){	cpumask_var_t cpumask;	int ret; 	if (!zalloc_cpumask_var(&cpumask, GFP_KERNEL))		return -ENOMEM; 	ret = cpumask_parse(buf, cpumask);	if (!ret)		ret = workqueue_set_unbound_cpumask(cpumask); 	free_cpumask_var(cpumask);	return ret ? ret : count;} static struct device_attribute wq_sysfs_cpumask_attr =	__ATTR(cpumask, 0644, wq_unbound_cpumask_show,	       wq_unbound_cpumask_store); static int __init wq_sysfs_init(void){	int err; 	err = subsys_virtual_register(&wq_subsys, NULL);	if (err)		return err; 	return device_create_file(wq_subsys.dev_root, &wq_sysfs_cpumask_attr);}core_initcall(wq_sysfs_init); static void wq_device_release(struct device *dev){	struct wq_device *wq_dev = container_of(dev, struct wq_device, dev); 	kfree(wq_dev);} /** * workqueue_sysfs_register - make a workqueue visible in sysfs * @wq: the workqueue to register * * Expose @wq in sysfs under /sys/bus/workqueue/devices. * alloc_workqueue*() automatically calls this function if WQ_SYSFS is set * which is the preferred method. * * Workqueue user should use this function directly iff it wants to apply * workqueue_attrs before making the workqueue visible in sysfs; otherwise, * apply_workqueue_attrs() may race against userland updating the * attributes. * * Return: 0 on success, -errno on failure. */int workqueue_sysfs_register(struct workqueue_struct *wq){	struct wq_device *wq_dev;	int ret; 	/*	 * Adjusting max_active or creating new pwqs by applying	 * attributes breaks ordering guarantee.  Disallow exposing ordered	 * workqueues.	 */	if (WARN_ON(wq->flags & __WQ_ORDERED_EXPLICIT))		return -EINVAL; 	wq->wq_dev = wq_dev = kzalloc(sizeof(*wq_dev), GFP_KERNEL);	if (!wq_dev)		return -ENOMEM; 	wq_dev->wq = wq;	wq_dev->dev.bus = &wq_subsys;	wq_dev->dev.release = wq_device_release;	dev_set_name(&wq_dev->dev, "%s", wq->name); 	/*	 * unbound_attrs are created separately.  Suppress uevent until	 * everything is ready.	 */	dev_set_uevent_suppress(&wq_dev->dev, true); 	ret = device_register(&wq_dev->dev);	if (ret) {		put_device(&wq_dev->dev);		wq->wq_dev = NULL;		return ret;	} 	if (wq->flags & WQ_UNBOUND) {		struct device_attribute *attr; 		for (attr = wq_sysfs_unbound_attrs; attr->attr.name; attr++) {			ret = device_create_file(&wq_dev->dev, attr);			if (ret) {				device_unregister(&wq_dev->dev);				wq->wq_dev = NULL;				return ret;			}		}	} 	dev_set_uevent_suppress(&wq_dev->dev, false);	kobject_uevent(&wq_dev->dev.kobj, KOBJ_ADD);	return 0;} /** * workqueue_sysfs_unregister - undo workqueue_sysfs_register() * @wq: the workqueue to unregister * * If @wq is registered to sysfs by workqueue_sysfs_register(), unregister. */static void workqueue_sysfs_unregister(struct workqueue_struct *wq){	struct wq_device *wq_dev = wq->wq_dev; 	if (!wq->wq_dev)		return; 	wq->wq_dev = NULL;	device_unregister(&wq_dev->dev);}#else	/* CONFIG_SYSFS */static void workqueue_sysfs_unregister(struct workqueue_struct *wq)	{ }#endif	/* CONFIG_SYSFS */ /* * Workqueue watchdog. * * Stall may be caused by various bugs - missing WQ_MEM_RECLAIM, illegal * flush dependency, a concurrency managed work item which stays RUNNING * indefinitely.  Workqueue stalls can be very difficult to debug as the * usual warning mechanisms don't trigger and internal workqueue state is * largely opaque. * * Workqueue watchdog monitors all worker pools periodically and dumps * state if some pools failed to make forward progress for a while where * forward progress is defined as the first item on ->worklist changing. * * This mechanism is controlled through the kernel parameter * "workqueue.watchdog_thresh" which can be updated at runtime through the * corresponding sysfs parameter file. */#ifdef CONFIG_WQ_WATCHDOG static unsigned long wq_watchdog_thresh = 30;static struct timer_list wq_watchdog_timer; static unsigned long wq_watchdog_touched = INITIAL_JIFFIES;static DEFINE_PER_CPU(unsigned long, wq_watchdog_touched_cpu) = INITIAL_JIFFIES; static void wq_watchdog_reset_touched(void){	int cpu; 	wq_watchdog_touched = jiffies;	for_each_possible_cpu(cpu)		per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies;} static void wq_watchdog_timer_fn(struct timer_list *unused){	unsigned long thresh = READ_ONCE(wq_watchdog_thresh) * HZ;	bool lockup_detected = false;	struct worker_pool *pool;	int pi; 	if (!thresh)		return; 	rcu_read_lock(); 	for_each_pool(pool, pi) {		unsigned long pool_ts, touched, ts; 		if (list_empty(&pool->worklist))			continue; 		/* get the latest of pool and touched timestamps */		pool_ts = READ_ONCE(pool->watchdog_ts);		touched = READ_ONCE(wq_watchdog_touched); 		if (time_after(pool_ts, touched))			ts = pool_ts;		else			ts = touched; 		if (pool->cpu >= 0) {			unsigned long cpu_touched =				READ_ONCE(per_cpu(wq_watchdog_touched_cpu,						  pool->cpu));			if (time_after(cpu_touched, ts))				ts = cpu_touched;		} 		/* did we stall? */		if (time_after(jiffies, ts + thresh)) {			lockup_detected = true;			pr_emerg("BUG: workqueue lockup - pool");			pr_cont_pool_info(pool);			pr_cont(" stuck for %us!\n",				jiffies_to_msecs(jiffies - pool_ts) / 1000);		}	} 	rcu_read_unlock(); 	if (lockup_detected)		show_workqueue_state(); 	wq_watchdog_reset_touched();	mod_timer(&wq_watchdog_timer, jiffies + thresh);} notrace void wq_watchdog_touch(int cpu){	if (cpu >= 0)		per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies;	else		wq_watchdog_touched = jiffies;} static void wq_watchdog_set_thresh(unsigned long thresh){	wq_watchdog_thresh = 0;	del_timer_sync(&wq_watchdog_timer); 	if (thresh) {		wq_watchdog_thresh = thresh;		wq_watchdog_reset_touched();		mod_timer(&wq_watchdog_timer, jiffies + thresh * HZ);	}} static int wq_watchdog_param_set_thresh(const char *val,					const struct kernel_param *kp){	unsigned long thresh;	int ret; 	ret = kstrtoul(val, 0, &thresh);	if (ret)		return ret; 	if (system_wq)		wq_watchdog_set_thresh(thresh);	else		wq_watchdog_thresh = thresh; 	return 0;} static const struct kernel_param_ops wq_watchdog_thresh_ops = {	.set	= wq_watchdog_param_set_thresh,	.get	= param_get_ulong,}; module_param_cb(watchdog_thresh, &wq_watchdog_thresh_ops, &wq_watchdog_thresh,		0644); static void wq_watchdog_init(void){	timer_setup(&wq_watchdog_timer, wq_watchdog_timer_fn, TIMER_DEFERRABLE);	wq_watchdog_set_thresh(wq_watchdog_thresh);} #else	/* CONFIG_WQ_WATCHDOG */ static inline void wq_watchdog_init(void) { } #endif	/* CONFIG_WQ_WATCHDOG */ static void __init wq_numa_init(void){	cpumask_var_t *tbl;	int node, cpu; 	if (num_possible_nodes() <= 1)		return; 	if (wq_disable_numa) {		pr_info("workqueue: NUMA affinity support disabled\n");		return;	} 	wq_update_unbound_numa_attrs_buf = alloc_workqueue_attrs();	BUG_ON(!wq_update_unbound_numa_attrs_buf); 	/*	 * We want masks of possible CPUs of each node which isn't readily	 * available.  Build one from cpu_to_node() which should have been	 * fully initialized by now.	 */	tbl = kcalloc(nr_node_ids, sizeof(tbl[0]), GFP_KERNEL);	BUG_ON(!tbl); 	for_each_node(node)		BUG_ON(!zalloc_cpumask_var_node(&tbl[node], GFP_KERNEL,				node_online(node) ? node : NUMA_NO_NODE)); 	for_each_possible_cpu(cpu) {		node = cpu_to_node(cpu);		if (WARN_ON(node == NUMA_NO_NODE)) {			pr_warn("workqueue: NUMA node mapping not available for cpu%d, disabling NUMA support\n", cpu);			/* happens iff arch is bonkers, let's just proceed */			return;		}		cpumask_set_cpu(cpu, tbl[node]);	} 	wq_numa_possible_cpumask = tbl;	wq_numa_enabled = true;} /** * workqueue_init_early - early init for workqueue subsystem * * This is the first half of two-staged workqueue subsystem initialization * and invoked as soon as the bare basics - memory allocation, cpumasks and * idr are up.  It sets up all the data structures and system workqueues * and allows early boot code to create workqueues and queue/cancel work * items.  Actual work item execution starts only after kthreads can be * created and scheduled right before early initcalls. */void __init workqueue_init_early(void){	int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL };	int hk_flags = HK_FLAG_DOMAIN | HK_FLAG_WQ;	int i, cpu; 	BUILD_BUG_ON(__alignof__(struct pool_workqueue) < __alignof__(long long)); 	BUG_ON(!alloc_cpumask_var(&wq_unbound_cpumask, GFP_KERNEL));	cpumask_copy(wq_unbound_cpumask, housekeeping_cpumask(hk_flags)); 	pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC); 	/* initialize CPU pools */	for_each_possible_cpu(cpu) {		struct worker_pool *pool; 		i = 0;		for_each_cpu_worker_pool(pool, cpu) {			BUG_ON(init_worker_pool(pool));			pool->cpu = cpu;			cpumask_copy(pool->attrs->cpumask, cpumask_of(cpu));			pool->attrs->nice = std_nice[i++];			pool->node = cpu_to_node(cpu); 			/* alloc pool ID */			mutex_lock(&wq_pool_mutex);			BUG_ON(worker_pool_assign_id(pool));			mutex_unlock(&wq_pool_mutex);		}	} 	/* 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()));		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()));		attrs->nice = std_nice[i];		attrs->no_numa = true;		ordered_wq_attrs[i] = attrs;	} 	system_wq = alloc_workqueue("events", 0, 0);	system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI, 0);	system_long_wq = alloc_workqueue("events_long", 0, 0);	system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND,					    WQ_UNBOUND_MAX_ACTIVE);	system_freezable_wq = alloc_workqueue("events_freezable",					      WQ_FREEZABLE, 0);	system_power_efficient_wq = alloc_workqueue("events_power_efficient",					      WQ_POWER_EFFICIENT, 0);	system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_power_efficient",					      WQ_FREEZABLE | WQ_POWER_EFFICIENT,					      0);	BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq ||	       !system_unbound_wq || !system_freezable_wq ||	       !system_power_efficient_wq ||	       !system_freezable_power_efficient_wq);} /** * workqueue_init - bring workqueue subsystem fully online * * This is the latter half of two-staged workqueue subsystem initialization * and invoked as soon as kthreads can be created and scheduled. * Workqueues have been created and work items queued on them, but there * are no kworkers executing the work items yet.  Populate the worker pools * with the initial workers and enable future kworker creations. */void __init workqueue_init(void){	struct workqueue_struct *wq;	struct worker_pool *pool;	int cpu, bkt; 	/*	 * It'd be simpler to initialize NUMA in workqueue_init_early() but	 * CPU to node mapping may not be available that early on some

Lines 5501–6000 of 6039. Previous lines