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
4954{4954{
4955 struct workqueue_struct *wq = dev_to_wq(dev);4955 struct workqueue_struct *wq = dev_to_wq(dev);
4956 struct workqueue_attrs *attrs;4956 struct workqueue_attrs *attrs;
4957 int ret;4957 int ret = -ENOMEM;
4958
4959 apply_wqattrs_lock();
4958 4960
4959 attrs = wq_sysfs_prep_attrs(wq);4961 attrs = wq_sysfs_prep_attrs(wq);
4960 if (!attrs)4962 if (!attrs)
4961 return -ENOMEM;4963 goto out_unlock;
4962 4964
4963 if (sscanf(buf, "%d", &attrs->nice) == 1 &&4965 if (sscanf(buf, "%d", &attrs->nice) == 1 &&
4964 attrs->nice >= MIN_NICE && attrs->nice <= MAX_NICE)4966 attrs->nice >= MIN_NICE && attrs->nice <= MAX_NICE)
4965 ret = apply_workqueue_attrs(wq, attrs);4967 ret = apply_workqueue_attrs_locked(wq, attrs);
4966 else4968 else
4967 ret = -EINVAL;4969 ret = -EINVAL;
4968 4970
4971out_unlock:
4972 apply_wqattrs_unlock();
4969 free_workqueue_attrs(attrs);4973 free_workqueue_attrs(attrs);
4970 return ret ?: count;4974 return ret ?: count;
4971}4975}
@@ -4989,16 +4993,20 @@ static ssize_t wq_cpumask_store(struct device *dev, · 17 unmodified lines
4989{4993{
4990 struct workqueue_struct *wq = dev_to_wq(dev);4994 struct workqueue_struct *wq = dev_to_wq(dev);
4991 struct workqueue_attrs *attrs;4995 struct workqueue_attrs *attrs;
4992 int ret;4996 int ret = -ENOMEM;
4997
4998 apply_wqattrs_lock();
4993 4999
4994 attrs = wq_sysfs_prep_attrs(wq);5000 attrs = wq_sysfs_prep_attrs(wq);
4995 if (!attrs)5001 if (!attrs)
4996 return -ENOMEM;5002 goto out_unlock;
4997 5003
4998 ret = cpumask_parse(buf, attrs->cpumask);5004 ret = cpumask_parse(buf, attrs->cpumask);
4999 if (!ret)5005 if (!ret)
5000 ret = apply_workqueue_attrs(wq, attrs);5006 ret = apply_workqueue_attrs_locked(wq, attrs);
5001 5007
5008out_unlock:
5009 apply_wqattrs_unlock();
5002 free_workqueue_attrs(attrs);5010 free_workqueue_attrs(attrs);
5003 return ret ?: count;5011 return ret ?: count;
5004}5012}
@@ -5022,18 +5030,22 @@ static ssize_t wq_numa_store(struct device *dev, struct device_attribute *attr, · 17 unmodified lines
5022{5030{
5023 struct workqueue_struct *wq = dev_to_wq(dev);5031 struct workqueue_struct *wq = dev_to_wq(dev);
5024 struct workqueue_attrs *attrs;5032 struct workqueue_attrs *attrs;
5025 int v, ret;5033 int v, ret = -ENOMEM;
5034
5035 apply_wqattrs_lock();
5026 5036
5027 attrs = wq_sysfs_prep_attrs(wq);5037 attrs = wq_sysfs_prep_attrs(wq);
5028 if (!attrs)5038 if (!attrs)
5029 return -ENOMEM;5039 goto out_unlock;
5030 5040
5031 ret = -EINVAL;5041 ret = -EINVAL;
5032 if (sscanf(buf, "%d", &v) == 1) {5042 if (sscanf(buf, "%d", &v) == 1) {
5033 attrs->no_numa = !v;5043 attrs->no_numa = !v;
5034 ret = apply_workqueue_attrs(wq, attrs);5044 ret = apply_workqueue_attrs_locked(wq, attrs);
5035 }5045 }
5036 5046
5047out_unlock:
5048 apply_wqattrs_unlock();
5037 free_workqueue_attrs(attrs);5049 free_workqueue_attrs(attrs);
5038 return ret ?: count;5050 return ret ?: count;
5039}5051}