diff options
author | Tejun Heo <tj@kernel.org> | 2013-12-05 12:28:03 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-12-05 12:28:03 -0500 |
commit | a742c59de66ea080afa3edaf3428b3cdd5aa87cd (patch) | |
tree | 62611be278e8727cd24f86c07f245b949d2f6a6d /kernel/cgroup.c | |
parent | 6e0755b08dd6a3b5260fafc6969268c2ba261300 (diff) |
cgroup: unify cgroup_write_X64() and cgroup_write_string()
cgroup_write_X64() and cgroup_write_string() both implement about the
same buffering logic. Unify the two into cgroup_file_write() which
always allocates dynamic buffer for simplicity and uses kstrto*()
instead of simple_strto*().
This patch doesn't make any visible behavior changes except for
possibly different error value from kstrsto*().
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 112 |
1 files changed, 36 insertions, 76 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index b132ff94fc6f..eb34caf98124 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -2249,90 +2249,50 @@ static int cgroup_sane_behavior_show(struct cgroup_subsys_state *css, | |||
2249 | /* A buffer size big enough for numbers or short strings */ | 2249 | /* A buffer size big enough for numbers or short strings */ |
2250 | #define CGROUP_LOCAL_BUFFER_SIZE 64 | 2250 | #define CGROUP_LOCAL_BUFFER_SIZE 64 |
2251 | 2251 | ||
2252 | static ssize_t cgroup_write_X64(struct cgroup_subsys_state *css, | 2252 | static ssize_t cgroup_file_write(struct file *file, const char __user *userbuf, |
2253 | struct cftype *cft, struct file *file, | 2253 | size_t nbytes, loff_t *ppos) |
2254 | const char __user *userbuf, size_t nbytes, | ||
2255 | loff_t *unused_ppos) | ||
2256 | { | ||
2257 | char buffer[CGROUP_LOCAL_BUFFER_SIZE]; | ||
2258 | int retval = 0; | ||
2259 | char *end; | ||
2260 | |||
2261 | if (!nbytes) | ||
2262 | return -EINVAL; | ||
2263 | if (nbytes >= sizeof(buffer)) | ||
2264 | return -E2BIG; | ||
2265 | if (copy_from_user(buffer, userbuf, nbytes)) | ||
2266 | return -EFAULT; | ||
2267 | |||
2268 | buffer[nbytes] = 0; /* nul-terminate */ | ||
2269 | if (cft->write_u64) { | ||
2270 | u64 val = simple_strtoull(strstrip(buffer), &end, 0); | ||
2271 | if (*end) | ||
2272 | return -EINVAL; | ||
2273 | retval = cft->write_u64(css, cft, val); | ||
2274 | } else { | ||
2275 | s64 val = simple_strtoll(strstrip(buffer), &end, 0); | ||
2276 | if (*end) | ||
2277 | return -EINVAL; | ||
2278 | retval = cft->write_s64(css, cft, val); | ||
2279 | } | ||
2280 | if (!retval) | ||
2281 | retval = nbytes; | ||
2282 | return retval; | ||
2283 | } | ||
2284 | |||
2285 | static ssize_t cgroup_write_string(struct cgroup_subsys_state *css, | ||
2286 | struct cftype *cft, struct file *file, | ||
2287 | const char __user *userbuf, size_t nbytes, | ||
2288 | loff_t *unused_ppos) | ||
2289 | { | 2254 | { |
2290 | char local_buffer[CGROUP_LOCAL_BUFFER_SIZE]; | 2255 | struct cfent *cfe = __d_cfe(file->f_dentry); |
2291 | int retval = 0; | 2256 | struct cftype *cft = __d_cft(file->f_dentry); |
2292 | size_t max_bytes = cft->max_write_len; | 2257 | struct cgroup_subsys_state *css = cfe->css; |
2293 | char *buffer = local_buffer; | 2258 | size_t max_bytes = cft->max_write_len ?: CGROUP_LOCAL_BUFFER_SIZE - 1; |
2259 | char *buf; | ||
2260 | int ret; | ||
2294 | 2261 | ||
2295 | if (!max_bytes) | ||
2296 | max_bytes = sizeof(local_buffer) - 1; | ||
2297 | if (nbytes >= max_bytes) | 2262 | if (nbytes >= max_bytes) |
2298 | return -E2BIG; | 2263 | return -E2BIG; |
2299 | /* Allocate a dynamic buffer if we need one */ | ||
2300 | if (nbytes >= sizeof(local_buffer)) { | ||
2301 | buffer = kmalloc(nbytes + 1, GFP_KERNEL); | ||
2302 | if (buffer == NULL) | ||
2303 | return -ENOMEM; | ||
2304 | } | ||
2305 | if (nbytes && copy_from_user(buffer, userbuf, nbytes)) { | ||
2306 | retval = -EFAULT; | ||
2307 | goto out; | ||
2308 | } | ||
2309 | 2264 | ||
2310 | buffer[nbytes] = 0; /* nul-terminate */ | 2265 | buf = kmalloc(nbytes + 1, GFP_KERNEL); |
2311 | retval = cft->write_string(css, cft, strstrip(buffer)); | 2266 | if (!buf) |
2312 | if (!retval) | 2267 | return -ENOMEM; |
2313 | retval = nbytes; | ||
2314 | out: | ||
2315 | if (buffer != local_buffer) | ||
2316 | kfree(buffer); | ||
2317 | return retval; | ||
2318 | } | ||
2319 | 2268 | ||
2320 | static ssize_t cgroup_file_write(struct file *file, const char __user *buf, | 2269 | if (copy_from_user(buf, userbuf, nbytes)) { |
2321 | size_t nbytes, loff_t *ppos) | 2270 | ret = -EFAULT; |
2322 | { | 2271 | goto out_free; |
2323 | struct cfent *cfe = __d_cfe(file->f_dentry); | 2272 | } |
2324 | struct cftype *cft = __d_cft(file->f_dentry); | ||
2325 | struct cgroup_subsys_state *css = cfe->css; | ||
2326 | 2273 | ||
2327 | if (cft->write_u64 || cft->write_s64) | 2274 | buf[nbytes] = '\0'; |
2328 | return cgroup_write_X64(css, cft, file, buf, nbytes, ppos); | 2275 | |
2329 | if (cft->write_string) | 2276 | if (cft->write_string) { |
2330 | return cgroup_write_string(css, cft, file, buf, nbytes, ppos); | 2277 | ret = cft->write_string(css, cft, strstrip(buf)); |
2331 | if (cft->trigger) { | 2278 | } else if (cft->write_u64) { |
2332 | int ret = cft->trigger(css, (unsigned int)cft->private); | 2279 | unsigned long long v; |
2333 | return ret ? ret : nbytes; | 2280 | ret = kstrtoull(buf, 0, &v); |
2281 | if (!ret) | ||
2282 | ret = cft->write_u64(css, cft, v); | ||
2283 | } else if (cft->write_s64) { | ||
2284 | long long v; | ||
2285 | ret = kstrtoll(buf, 0, &v); | ||
2286 | if (!ret) | ||
2287 | ret = cft->write_s64(css, cft, v); | ||
2288 | } else if (cft->trigger) { | ||
2289 | ret = cft->trigger(css, (unsigned int)cft->private); | ||
2290 | } else { | ||
2291 | ret = -EINVAL; | ||
2334 | } | 2292 | } |
2335 | return -EINVAL; | 2293 | out_free: |
2294 | kfree(buf); | ||
2295 | return ret ?: nbytes; | ||
2336 | } | 2296 | } |
2337 | 2297 | ||
2338 | static ssize_t cgroup_read_u64(struct cgroup_subsys_state *css, | 2298 | static ssize_t cgroup_read_u64(struct cgroup_subsys_state *css, |