History

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.

Lai Jiangshan committed 11 years ago

Commit d4d3e251 parent a0111cf1 file · +21 −9Browse files

Showing the changes to kernel/workqueue.c (1 of 1 file). Show all

Unified · Split

kernel/workqueue.c+21−9
@@ -4954,18 +4954,22 @@ static ssize_t wq_nice_store(struct device *dev, struct device_attribute *attr, · 4953 unmodified lines
49544954 {
49554955 struct workqueue_struct *wq = dev_to_wq(dev);
49564956 struct workqueue_attrs *attrs;
4957− int ret;
4957+ int ret = -ENOMEM;
4958+
4959+ apply_wqattrs_lock();
49584960
49594961 attrs = wq_sysfs_prep_attrs(wq);
49604962 if (!attrs)
4961− return -ENOMEM;
4963+ goto out_unlock;
49624964
49634965 if (sscanf(buf, "%d", &attrs->nice) == 1 &&
49644966 attrs->nice >= MIN_NICE && attrs->nice <= MAX_NICE)
4965− ret = apply_workqueue_attrs(wq, attrs);
4967+ ret = apply_workqueue_attrs_locked(wq, attrs);
49664968 else
49674969 ret = -EINVAL;
49684970
4971+out_unlock:
4972+ apply_wqattrs_unlock();
49694973 free_workqueue_attrs(attrs);
49704974 return ret ?: count;
49714975 }
@@ -4989,16 +4993,20 @@ static ssize_t wq_cpumask_store(struct device *dev, · 17 unmodified lines
49894993 {
49904994 struct workqueue_struct *wq = dev_to_wq(dev);
49914995 struct workqueue_attrs *attrs;
4992− int ret;
4996+ int ret = -ENOMEM;
4997+
4998+ apply_wqattrs_lock();
49934999
49945000 attrs = wq_sysfs_prep_attrs(wq);
49955001 if (!attrs)
4996− return -ENOMEM;
5002+ goto out_unlock;
49975003
49985004 ret = cpumask_parse(buf, attrs->cpumask);
49995005 if (!ret)
5000− ret = apply_workqueue_attrs(wq, attrs);
5006+ ret = apply_workqueue_attrs_locked(wq, attrs);
50015007
5008+out_unlock:
5009+ apply_wqattrs_unlock();
50025010 free_workqueue_attrs(attrs);
50035011 return ret ?: count;
50045012 }
@@ -5022,18 +5030,22 @@ static ssize_t wq_numa_store(struct device *dev, struct device_attribute *attr, · 17 unmodified lines
50225030 {
50235031 struct workqueue_struct *wq = dev_to_wq(dev);
50245032 struct workqueue_attrs *attrs;
5025− int v, ret;
5033+ int v, ret = -ENOMEM;
5034+
5035+ apply_wqattrs_lock();
50265036
50275037 attrs = wq_sysfs_prep_attrs(wq);
50285038 if (!attrs)
5029− return -ENOMEM;
5039+ goto out_unlock;
50305040
50315041 ret = -EINVAL;
50325042 if (sscanf(buf, "%d", &v) == 1) {
50335043 attrs->no_numa = !v;
5034− ret = apply_workqueue_attrs(wq, attrs);
5044+ ret = apply_workqueue_attrs_locked(wq, attrs);
50355045 }
50365046
5047+out_unlock:
5048+ apply_wqattrs_unlock();
50375049 free_workqueue_attrs(attrs);
50385050 return ret ?: count;
50395051 }