diff options
author | Tejun Heo <tj@kernel.org> | 2013-04-01 14:23:34 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-04-01 14:23:34 -0400 |
commit | 6029a91829ad2bd876fed78bc088d3469a9dd777 (patch) | |
tree | b5767d17ce0ed6f0ecee7d1b2ad8fcfe753505d9 /kernel/workqueue.c | |
parent | f3f90ad46934202eeefac454fd5d89bf73c6aa34 (diff) |
workqueue: add workqueue->unbound_attrs
Currently, when exposing attrs of an unbound workqueue via sysfs, the
workqueue_attrs of first_pwq() is used as that should equal the
current state of the workqueue.
The planned NUMA affinity support will make unbound workqueues make
use of multiple pool_workqueues for different NUMA nodes and the above
assumption will no longer hold. Introduce workqueue->unbound_attrs
which records the current attrs in effect and use it for sysfs instead
of first_pwq()->attrs.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r-- | kernel/workqueue.c | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 3e18c7b865eb..32b474463053 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -244,6 +244,8 @@ struct workqueue_struct { | |||
244 | int nr_drainers; /* WQ: drain in progress */ | 244 | int nr_drainers; /* WQ: drain in progress */ |
245 | int saved_max_active; /* WQ: saved pwq max_active */ | 245 | int saved_max_active; /* WQ: saved pwq max_active */ |
246 | 246 | ||
247 | struct workqueue_attrs *unbound_attrs; /* WQ: only for unbound wqs */ | ||
248 | |||
247 | #ifdef CONFIG_SYSFS | 249 | #ifdef CONFIG_SYSFS |
248 | struct wq_device *wq_dev; /* I: for sysfs interface */ | 250 | struct wq_device *wq_dev; /* I: for sysfs interface */ |
249 | #endif | 251 | #endif |
@@ -3088,10 +3090,9 @@ static ssize_t wq_nice_show(struct device *dev, struct device_attribute *attr, | |||
3088 | struct workqueue_struct *wq = dev_to_wq(dev); | 3090 | struct workqueue_struct *wq = dev_to_wq(dev); |
3089 | int written; | 3091 | int written; |
3090 | 3092 | ||
3091 | rcu_read_lock_sched(); | 3093 | mutex_lock(&wq->mutex); |
3092 | written = scnprintf(buf, PAGE_SIZE, "%d\n", | 3094 | written = scnprintf(buf, PAGE_SIZE, "%d\n", wq->unbound_attrs->nice); |
3093 | first_pwq(wq)->pool->attrs->nice); | 3095 | mutex_unlock(&wq->mutex); |
3094 | rcu_read_unlock_sched(); | ||
3095 | 3096 | ||
3096 | return written; | 3097 | return written; |
3097 | } | 3098 | } |
@@ -3105,9 +3106,9 @@ static struct workqueue_attrs *wq_sysfs_prep_attrs(struct workqueue_struct *wq) | |||
3105 | if (!attrs) | 3106 | if (!attrs) |
3106 | return NULL; | 3107 | return NULL; |
3107 | 3108 | ||
3108 | rcu_read_lock_sched(); | 3109 | mutex_lock(&wq->mutex); |
3109 | copy_workqueue_attrs(attrs, first_pwq(wq)->pool->attrs); | 3110 | copy_workqueue_attrs(attrs, wq->unbound_attrs); |
3110 | rcu_read_unlock_sched(); | 3111 | mutex_unlock(&wq->mutex); |
3111 | return attrs; | 3112 | return attrs; |
3112 | } | 3113 | } |
3113 | 3114 | ||
@@ -3138,10 +3139,9 @@ static ssize_t wq_cpumask_show(struct device *dev, | |||
3138 | struct workqueue_struct *wq = dev_to_wq(dev); | 3139 | struct workqueue_struct *wq = dev_to_wq(dev); |
3139 | int written; | 3140 | int written; |
3140 | 3141 | ||
3141 | rcu_read_lock_sched(); | 3142 | mutex_lock(&wq->mutex); |
3142 | written = cpumask_scnprintf(buf, PAGE_SIZE, | 3143 | written = cpumask_scnprintf(buf, PAGE_SIZE, wq->unbound_attrs->cpumask); |
3143 | first_pwq(wq)->pool->attrs->cpumask); | 3144 | mutex_unlock(&wq->mutex); |
3144 | rcu_read_unlock_sched(); | ||
3145 | 3145 | ||
3146 | written += scnprintf(buf + written, PAGE_SIZE - written, "\n"); | 3146 | written += scnprintf(buf + written, PAGE_SIZE - written, "\n"); |
3147 | return written; | 3147 | return written; |
@@ -3558,8 +3558,10 @@ static void pwq_unbound_release_workfn(struct work_struct *work) | |||
3558 | * If we're the last pwq going away, @wq is already dead and no one | 3558 | * If we're the last pwq going away, @wq is already dead and no one |
3559 | * is gonna access it anymore. Free it. | 3559 | * is gonna access it anymore. Free it. |
3560 | */ | 3560 | */ |
3561 | if (is_last) | 3561 | if (is_last) { |
3562 | free_workqueue_attrs(wq->unbound_attrs); | ||
3562 | kfree(wq); | 3563 | kfree(wq); |
3564 | } | ||
3563 | } | 3565 | } |
3564 | 3566 | ||
3565 | /** | 3567 | /** |
@@ -3634,6 +3636,9 @@ static void init_and_link_pwq(struct pool_workqueue *pwq, | |||
3634 | /* link in @pwq */ | 3636 | /* link in @pwq */ |
3635 | list_add_rcu(&pwq->pwqs_node, &wq->pwqs); | 3637 | list_add_rcu(&pwq->pwqs_node, &wq->pwqs); |
3636 | 3638 | ||
3639 | if (wq->flags & WQ_UNBOUND) | ||
3640 | copy_workqueue_attrs(wq->unbound_attrs, pool->attrs); | ||
3641 | |||
3637 | mutex_unlock(&wq->mutex); | 3642 | mutex_unlock(&wq->mutex); |
3638 | } | 3643 | } |
3639 | 3644 | ||
@@ -3766,6 +3771,12 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, | |||
3766 | if (!wq) | 3771 | if (!wq) |
3767 | return NULL; | 3772 | return NULL; |
3768 | 3773 | ||
3774 | if (flags & WQ_UNBOUND) { | ||
3775 | wq->unbound_attrs = alloc_workqueue_attrs(GFP_KERNEL); | ||
3776 | if (!wq->unbound_attrs) | ||
3777 | goto err_free_wq; | ||
3778 | } | ||
3779 | |||
3769 | vsnprintf(wq->name, namelen, fmt, args1); | 3780 | vsnprintf(wq->name, namelen, fmt, args1); |
3770 | va_end(args); | 3781 | va_end(args); |
3771 | va_end(args1); | 3782 | va_end(args1); |
@@ -3835,6 +3846,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt, | |||
3835 | return wq; | 3846 | return wq; |
3836 | 3847 | ||
3837 | err_free_wq: | 3848 | err_free_wq: |
3849 | free_workqueue_attrs(wq->unbound_attrs); | ||
3838 | kfree(wq); | 3850 | kfree(wq); |
3839 | return NULL; | 3851 | return NULL; |
3840 | err_destroy: | 3852 | err_destroy: |