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_attrs *attrs;
|
||||
int ret;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
apply_wqattrs_lock();
|
||||
|
||||
attrs = wq_sysfs_prep_attrs(wq);
|
||||
if (!attrs)
|
||||
return -ENOMEM;
|
||||
goto out_unlock;
|
||||
|
||||
if (sscanf(buf, "%d", &attrs->nice) == 1 &&
|
||||
attrs->nice >= MIN_NICE && attrs->nice <= MAX_NICE)
|
||||
ret = apply_workqueue_attrs(wq, attrs);
|
||||
ret = apply_workqueue_attrs_locked(wq, attrs);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
out_unlock:
|
||||
apply_wqattrs_unlock();
|
||||
free_workqueue_attrs(attrs);
|
||||
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_attrs *attrs;
|
||||
int ret;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
apply_wqattrs_lock();
|
||||
|
||||
attrs = wq_sysfs_prep_attrs(wq);
|
||||
if (!attrs)
|
||||
return -ENOMEM;
|
||||
goto out_unlock;
|
||||
|
||||
ret = cpumask_parse(buf, attrs->cpumask);
|
||||
if (!ret)
|
||||
ret = apply_workqueue_attrs(wq, attrs);
|
||||
ret = apply_workqueue_attrs_locked(wq, attrs);
|
||||
|
||||
out_unlock:
|
||||
apply_wqattrs_unlock();
|
||||
free_workqueue_attrs(attrs);
|
||||
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_attrs *attrs;
|
||||
int v, ret;
|
||||
int v, ret = -ENOMEM;
|
||||
|
||||
apply_wqattrs_lock();
|
||||
|
||||
attrs = wq_sysfs_prep_attrs(wq);
|
||||
if (!attrs)
|
||||
return -ENOMEM;
|
||||
goto out_unlock;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (sscanf(buf, "%d", &v) == 1) {
|
||||
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);
|
||||
return ret ?: count;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue