diff options
author | Tejun Heo <tj@kernel.org> | 2013-11-28 14:54:17 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-11-29 20:33:46 -0500 |
commit | 50b38ca086e4d9920eede98b871b971e9958d70d (patch) | |
tree | 0dc2d4f8066b15f25747fa5c024544158135ad1b /fs/sysfs/file.c | |
parent | c2b19daf6760fae9d5db9e9d1683644728888293 (diff) |
sysfs, kernfs: prepare write path for kernfs
We're in the process of separating out core sysfs functionality into
kernfs which will deal with sysfs_dirents directly. This patch
rearranges write path so that the kernfs and sysfs parts are separate.
kernfs_file_write() handles all boilerplate work including buffer
management and locking and invokes sysfs_kf_write() or
sysfs_kf_bin_write() depending on the file type which deals with the
interaction with kobj store or bin_attribute write method.
While this patch changes the order of some operations, it shouldn't
change any visible behavior.
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/sysfs/file.c')
-rw-r--r-- | fs/sysfs/file.c | 103 |
1 files changed, 50 insertions, 53 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index b695b8b229fc..2f849e82c0eb 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -267,61 +267,50 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, | |||
267 | return seq_read(file, user_buf, count, ppos); | 267 | return seq_read(file, user_buf, count, ppos); |
268 | } | 268 | } |
269 | 269 | ||
270 | /** | 270 | /* kernfs write callback for regular sysfs files */ |
271 | * flush_write_buffer - push buffer to kobject | 271 | static ssize_t sysfs_kf_write(struct sysfs_open_file *of, char *buf, |
272 | * @of: open file | 272 | size_t count, loff_t pos) |
273 | * @buf: data buffer for file | ||
274 | * @off: file offset to write to | ||
275 | * @count: number of bytes | ||
276 | * | ||
277 | * Get the correct pointers for the kobject and the attribute we're dealing | ||
278 | * with, then call the store() method for it with @buf. | ||
279 | */ | ||
280 | static int flush_write_buffer(struct sysfs_open_file *of, char *buf, loff_t off, | ||
281 | size_t count) | ||
282 | { | 273 | { |
274 | const struct sysfs_ops *ops = sysfs_file_ops(of->sd); | ||
283 | struct kobject *kobj = of->sd->s_parent->priv; | 275 | struct kobject *kobj = of->sd->s_parent->priv; |
284 | int rc = 0; | ||
285 | 276 | ||
286 | /* | 277 | if (!count) |
287 | * Need @of->sd for attr and ops, its parent for kobj. @of->mutex | 278 | return 0; |
288 | * nests outside active ref and is just to ensure that the ops | ||
289 | * aren't called concurrently for the same open file. | ||
290 | */ | ||
291 | mutex_lock(&of->mutex); | ||
292 | if (!sysfs_get_active(of->sd)) { | ||
293 | mutex_unlock(&of->mutex); | ||
294 | return -ENODEV; | ||
295 | } | ||
296 | 279 | ||
297 | if (sysfs_is_bin(of->sd)) { | 280 | return ops->store(kobj, of->sd->priv, buf, count); |
298 | struct bin_attribute *battr = of->sd->priv; | 281 | } |
299 | 282 | ||
300 | rc = -EIO; | 283 | /* kernfs write callback for bin sysfs files */ |
301 | if (battr->write) | 284 | static ssize_t sysfs_kf_bin_write(struct sysfs_open_file *of, char *buf, |
302 | rc = battr->write(of->file, kobj, battr, buf, off, | 285 | size_t count, loff_t pos) |
303 | count); | 286 | { |
304 | } else { | 287 | struct bin_attribute *battr = of->sd->priv; |
305 | const struct sysfs_ops *ops = sysfs_file_ops(of->sd); | 288 | struct kobject *kobj = of->sd->s_parent->priv; |
289 | loff_t size = file_inode(of->file)->i_size; | ||
306 | 290 | ||
307 | rc = ops->store(kobj, of->sd->priv, buf, count); | 291 | if (size) { |
292 | if (size <= pos) | ||
293 | return 0; | ||
294 | count = min_t(ssize_t, count, size - pos); | ||
308 | } | 295 | } |
296 | if (!count) | ||
297 | return 0; | ||
309 | 298 | ||
310 | sysfs_put_active(of->sd); | 299 | if (!battr->write) |
311 | mutex_unlock(&of->mutex); | 300 | return -EIO; |
312 | 301 | ||
313 | return rc; | 302 | return battr->write(of->file, kobj, battr, buf, pos, count); |
314 | } | 303 | } |
315 | 304 | ||
316 | /** | 305 | /** |
317 | * sysfs_write_file - write an attribute | 306 | * kernfs_file_write - kernfs vfs write callback |
318 | * @file: file pointer | 307 | * @file: file pointer |
319 | * @user_buf: data to write | 308 | * @user_buf: data to write |
320 | * @count: number of bytes | 309 | * @count: number of bytes |
321 | * @ppos: starting offset | 310 | * @ppos: starting offset |
322 | * | 311 | * |
323 | * Copy data in from userland and pass it to the matching | 312 | * Copy data in from userland and pass it to the matching kernfs write |
324 | * sysfs_ops->store() by invoking flush_write_buffer(). | 313 | * operation. |
325 | * | 314 | * |
326 | * There is no easy way for us to know if userspace is only doing a partial | 315 | * There is no easy way for us to know if userspace is only doing a partial |
327 | * write, so we don't support them. We expect the entire buffer to come on | 316 | * write, so we don't support them. We expect the entire buffer to come on |
@@ -329,23 +318,13 @@ static int flush_write_buffer(struct sysfs_open_file *of, char *buf, loff_t off, | |||
329 | * modify only the the value you're changing, then write entire buffer | 318 | * modify only the the value you're changing, then write entire buffer |
330 | * back. | 319 | * back. |
331 | */ | 320 | */ |
332 | static ssize_t sysfs_write_file(struct file *file, const char __user *user_buf, | 321 | static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf, |
333 | size_t count, loff_t *ppos) | 322 | size_t count, loff_t *ppos) |
334 | { | 323 | { |
335 | struct sysfs_open_file *of = sysfs_of(file); | 324 | struct sysfs_open_file *of = sysfs_of(file); |
336 | ssize_t len = min_t(size_t, count, PAGE_SIZE); | 325 | ssize_t len = min_t(size_t, count, PAGE_SIZE); |
337 | loff_t size = file_inode(file)->i_size; | ||
338 | char *buf; | 326 | char *buf; |
339 | 327 | ||
340 | if (sysfs_is_bin(of->sd) && size) { | ||
341 | if (size <= *ppos) | ||
342 | return 0; | ||
343 | len = min_t(ssize_t, len, size - *ppos); | ||
344 | } | ||
345 | |||
346 | if (!len) | ||
347 | return 0; | ||
348 | |||
349 | buf = kmalloc(len + 1, GFP_KERNEL); | 328 | buf = kmalloc(len + 1, GFP_KERNEL); |
350 | if (!buf) | 329 | if (!buf) |
351 | return -ENOMEM; | 330 | return -ENOMEM; |
@@ -356,7 +335,25 @@ static ssize_t sysfs_write_file(struct file *file, const char __user *user_buf, | |||
356 | } | 335 | } |
357 | buf[len] = '\0'; /* guarantee string termination */ | 336 | buf[len] = '\0'; /* guarantee string termination */ |
358 | 337 | ||
359 | len = flush_write_buffer(of, buf, *ppos, len); | 338 | /* |
339 | * @of->mutex nests outside active ref and is just to ensure that | ||
340 | * the ops aren't called concurrently for the same open file. | ||
341 | */ | ||
342 | mutex_lock(&of->mutex); | ||
343 | if (!sysfs_get_active(of->sd)) { | ||
344 | mutex_unlock(&of->mutex); | ||
345 | len = -ENODEV; | ||
346 | goto out_free; | ||
347 | } | ||
348 | |||
349 | if (sysfs_is_bin(of->sd)) | ||
350 | len = sysfs_kf_bin_write(of, buf, len, *ppos); | ||
351 | else | ||
352 | len = sysfs_kf_write(of, buf, len, *ppos); | ||
353 | |||
354 | sysfs_put_active(of->sd); | ||
355 | mutex_unlock(&of->mutex); | ||
356 | |||
360 | if (len > 0) | 357 | if (len > 0) |
361 | *ppos += len; | 358 | *ppos += len; |
362 | out_free: | 359 | out_free: |
@@ -878,7 +875,7 @@ EXPORT_SYMBOL_GPL(sysfs_notify); | |||
878 | 875 | ||
879 | const struct file_operations sysfs_file_operations = { | 876 | const struct file_operations sysfs_file_operations = { |
880 | .read = kernfs_file_read, | 877 | .read = kernfs_file_read, |
881 | .write = sysfs_write_file, | 878 | .write = kernfs_file_write, |
882 | .llseek = generic_file_llseek, | 879 | .llseek = generic_file_llseek, |
883 | .open = sysfs_open_file, | 880 | .open = sysfs_open_file, |
884 | .release = sysfs_release, | 881 | .release = sysfs_release, |
@@ -887,7 +884,7 @@ const struct file_operations sysfs_file_operations = { | |||
887 | 884 | ||
888 | const struct file_operations sysfs_bin_operations = { | 885 | const struct file_operations sysfs_bin_operations = { |
889 | .read = kernfs_file_read, | 886 | .read = kernfs_file_read, |
890 | .write = sysfs_write_file, | 887 | .write = kernfs_file_write, |
891 | .llseek = generic_file_llseek, | 888 | .llseek = generic_file_llseek, |
892 | .mmap = sysfs_bin_mmap, | 889 | .mmap = sysfs_bin_mmap, |
893 | .open = sysfs_open_file, | 890 | .open = sysfs_open_file, |