workqueue: ensure attrs changes are properly synchronized
Current modification to attrs via sysfs is not fully synchronized. Process A (change cpumask) | Process B (change numa affinity) wq_cpumask_store() | wq_sysfs_prep_attrs() | | apply_workqueue_attrs() apply_workqueue_attrs() | It results that the Process B's operation is totally reverted without any notification, it is a buggy behavior. So this patch moves wq_sysfs_prep_attrs() into the protection under wq_pool_mutex to ensure attrs changes are properly synchronized. Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
a0111cf671
commit
d4d3e25797
1 changed files with 21 additions and 9 deletions
|
@ -4954,18 +4954,22 @@ static ssize_t wq_nice_store(struct device *dev, struct device_attribute *attr,
|
||||||
{
|
{
|
||||||
struct workqueue_struct *wq = dev_to_wq(dev);
|
struct workqueue_struct *wq = dev_to_wq(dev);
|
||||||
struct workqueue_attrs *attrs;
|
struct workqueue_attrs *attrs;
|
||||||
int ret;
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
|
apply_wqattrs_lock();
|
||||||
|
|
||||||
attrs = wq_sysfs_prep_attrs(wq);
|
attrs = wq_sysfs_prep_attrs(wq);
|
||||||
if (!attrs)
|
if (!attrs)
|
||||||
return -ENOMEM;
|
goto out_unlock;
|
||||||
|
|
||||||
if (sscanf(buf, "%d", &attrs->nice) == 1 &&
|
if (sscanf(buf, "%d", &attrs->nice) == 1 &&
|
||||||
attrs->nice >= MIN_NICE && attrs->nice <= MAX_NICE)
|
attrs->nice >= MIN_NICE && attrs->nice <= MAX_NICE)
|
||||||
ret = apply_workqueue_attrs(wq, attrs);
|
ret = apply_workqueue_attrs_locked(wq, attrs);
|
||||||
else
|
else
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
apply_wqattrs_unlock();
|
||||||
free_workqueue_attrs(attrs);
|
free_workqueue_attrs(attrs);
|
||||||
return ret ?: count;
|
return ret ?: count;
|
||||||
}
|
}
|
||||||
|
@ -4989,16 +4993,20 @@ static ssize_t wq_cpumask_store(struct device *dev,
|
||||||
{
|
{
|
||||||
struct workqueue_struct *wq = dev_to_wq(dev);
|
struct workqueue_struct *wq = dev_to_wq(dev);
|
||||||
struct workqueue_attrs *attrs;
|
struct workqueue_attrs *attrs;
|
||||||
int ret;
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
|
apply_wqattrs_lock();
|
||||||
|
|
||||||
attrs = wq_sysfs_prep_attrs(wq);
|
attrs = wq_sysfs_prep_attrs(wq);
|
||||||
if (!attrs)
|
if (!attrs)
|
||||||
return -ENOMEM;
|
goto out_unlock;
|
||||||
|
|
||||||
ret = cpumask_parse(buf, attrs->cpumask);
|
ret = cpumask_parse(buf, attrs->cpumask);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = apply_workqueue_attrs(wq, attrs);
|
ret = apply_workqueue_attrs_locked(wq, attrs);
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
apply_wqattrs_unlock();
|
||||||
free_workqueue_attrs(attrs);
|
free_workqueue_attrs(attrs);
|
||||||
return ret ?: count;
|
return ret ?: count;
|
||||||
}
|
}
|
||||||
|
@ -5022,18 +5030,22 @@ static ssize_t wq_numa_store(struct device *dev, struct device_attribute *attr,
|
||||||
{
|
{
|
||||||
struct workqueue_struct *wq = dev_to_wq(dev);
|
struct workqueue_struct *wq = dev_to_wq(dev);
|
||||||
struct workqueue_attrs *attrs;
|
struct workqueue_attrs *attrs;
|
||||||
int v, ret;
|
int v, ret = -ENOMEM;
|
||||||
|
|
||||||
|
apply_wqattrs_lock();
|
||||||
|
|
||||||
attrs = wq_sysfs_prep_attrs(wq);
|
attrs = wq_sysfs_prep_attrs(wq);
|
||||||
if (!attrs)
|
if (!attrs)
|
||||||
return -ENOMEM;
|
goto out_unlock;
|
||||||
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if (sscanf(buf, "%d", &v) == 1) {
|
if (sscanf(buf, "%d", &v) == 1) {
|
||||||
attrs->no_numa = !v;
|
attrs->no_numa = !v;
|
||||||
ret = apply_workqueue_attrs(wq, attrs);
|
ret = apply_workqueue_attrs_locked(wq, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
apply_wqattrs_unlock();
|
||||||
free_workqueue_attrs(attrs);
|
free_workqueue_attrs(attrs);
|
||||||
return ret ?: count;
|
return ret ?: count;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue