summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-10-01 17:42:05 -0400
committerPawel Osmialowski <p.osmialowsk@mcdsrvbld02.digital.local>2015-03-27 14:37:24 +0100
commitace3773f3de73b4f33a9c4bc7b59730ce5fb3aae (patch)
treebbb34e0958800b870c8f4eae1ed0dd99aadc8420
parent6e7347a7c743e7309855debff1d3dc41245878e2 (diff)
downloadlinux-3.10-ace3773f3de73b4f33a9c4bc7b59730ce5fb3aae.tar.gz
linux-3.10-ace3773f3de73b4f33a9c4bc7b59730ce5fb3aae.tar.bz2
linux-3.10-ace3773f3de73b4f33a9c4bc7b59730ce5fb3aae.zip
sysfs: prepare path write for unified regular / bin file handling
sysfs bin file handling will be merged into the regular file support. This patch prepares the write path. bin file write is almost identical to regular file write except that the write length is capped by the inode size and @off is passed to the write method. This patch adds bin file handling to sysfs_write_file() so that it can handle both regular and bin files. A new file_operations struct sysfs_bin_operations is added, which currently only hosts sysfs_write_file() and generic_file_llseek(). This isn't used yet but will eventually replace fs/sysfs/bin.c. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/sysfs/file.c40
-rw-r--r--fs/sysfs/sysfs.h1
2 files changed, 35 insertions, 6 deletions
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 4921bda3a37..b36473f2182 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -54,6 +54,11 @@ struct sysfs_open_file {
struct list_head list;
};
+static bool sysfs_is_bin(struct sysfs_dirent *sd)
+{
+ return sysfs_type(sd) == SYSFS_KOBJ_BIN_ATTR;
+}
+
static struct sysfs_open_file *sysfs_of(struct file *file)
{
return ((struct seq_file *)file->private_data)->private;
@@ -138,16 +143,16 @@ static int sysfs_seq_show(struct seq_file *sf, void *v)
* flush_write_buffer - push buffer to kobject
* @of: open file
* @buf: data buffer for file
+ * @off: file offset to write to
* @count: number of bytes
*
* Get the correct pointers for the kobject and the attribute we're dealing
* with, then call the store() method for it with @buf.
*/
-static int flush_write_buffer(struct sysfs_open_file *of, char *buf,
+static int flush_write_buffer(struct sysfs_open_file *of, char *buf, loff_t off,
size_t count)
{
struct kobject *kobj = of->sd->s_parent->s_dir.kobj;
- const struct sysfs_ops *ops;
int rc = 0;
/*
@@ -161,8 +166,18 @@ static int flush_write_buffer(struct sysfs_open_file *of, char *buf,
return -ENODEV;
}
- ops = sysfs_file_ops(of->sd);
- rc = ops->store(kobj, of->sd->s_attr.attr, buf, count);
+ if (sysfs_is_bin(of->sd)) {
+ struct bin_attribute *battr = of->sd->s_bin_attr.bin_attr;
+
+ rc = -EIO;
+ if (battr->write)
+ rc = battr->write(of->file, kobj, battr, buf, off,
+ count);
+ } else {
+ const struct sysfs_ops *ops = sysfs_file_ops(of->sd);
+
+ rc = ops->store(kobj, of->sd->s_attr.attr, buf, count);
+ }
sysfs_put_active(of->sd);
mutex_unlock(&of->mutex);
@@ -190,9 +205,17 @@ static ssize_t sysfs_write_file(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct sysfs_open_file *of = sysfs_of(file);
- ssize_t len = min_t(size_t, count, PAGE_SIZE - 1);
+ ssize_t len = min_t(size_t, count, PAGE_SIZE);
char *buf;
+ if (sysfs_is_bin(of->sd)) {
+ loff_t size = file_inode(file)->i_size;
+
+ if (size <= *ppos)
+ return 0;
+ len = min_t(ssize_t, len, size - *ppos);
+ }
+
if (!len)
return 0;
@@ -206,7 +229,7 @@ static ssize_t sysfs_write_file(struct file *file, const char __user *user_buf,
}
buf[len] = '\0'; /* guarantee string termination */
- len = flush_write_buffer(of, buf, len);
+ len = flush_write_buffer(of, buf, *ppos, len);
if (len > 0)
*ppos += len;
out_free:
@@ -471,6 +494,11 @@ const struct file_operations sysfs_file_operations = {
.poll = sysfs_poll,
};
+const struct file_operations sysfs_bin_operations = {
+ .write = sysfs_write_file,
+ .llseek = generic_file_llseek,
+};
+
int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd,
const struct attribute *attr, int type,
umode_t amode, const void *ns)
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 7ffc2f732e8..16ea6d07bdf 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -211,6 +211,7 @@ int sysfs_inode_init(void);
* file.c
*/
extern const struct file_operations sysfs_file_operations;
+extern const struct file_operations sysfs_bin_operations;
int sysfs_add_file(struct sysfs_dirent *dir_sd,
const struct attribute *attr, int type);