aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-10-01 17:42:05 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-05 20:27:40 -0400
commitf9b9a6217cf10fd5d3002627cc13c4789a777213 (patch)
tree7c253a5ad2a30364ab6696f6b32c3119dd7cd515 /fs/sysfs
parent3ff65d3cb09ee642363bcaf12c6c38670263d93a (diff)
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>
Diffstat (limited to 'fs/sysfs')
-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 4921bda3a37a..b36473f21824 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -54,6 +54,11 @@ struct sysfs_open_file {
54 struct list_head list; 54 struct list_head list;
55}; 55};
56 56
57static bool sysfs_is_bin(struct sysfs_dirent *sd)
58{
59 return sysfs_type(sd) == SYSFS_KOBJ_BIN_ATTR;
60}
61
57static struct sysfs_open_file *sysfs_of(struct file *file) 62static struct sysfs_open_file *sysfs_of(struct file *file)
58{ 63{
59 return ((struct seq_file *)file->private_data)->private; 64 return ((struct seq_file *)file->private_data)->private;
@@ -138,16 +143,16 @@ static int sysfs_seq_show(struct seq_file *sf, void *v)
138 * flush_write_buffer - push buffer to kobject 143 * flush_write_buffer - push buffer to kobject
139 * @of: open file 144 * @of: open file
140 * @buf: data buffer for file 145 * @buf: data buffer for file
146 * @off: file offset to write to
141 * @count: number of bytes 147 * @count: number of bytes
142 * 148 *
143 * Get the correct pointers for the kobject and the attribute we're dealing 149 * Get the correct pointers for the kobject and the attribute we're dealing
144 * with, then call the store() method for it with @buf. 150 * with, then call the store() method for it with @buf.
145 */ 151 */
146static int flush_write_buffer(struct sysfs_open_file *of, char *buf, 152static int flush_write_buffer(struct sysfs_open_file *of, char *buf, loff_t off,
147 size_t count) 153 size_t count)
148{ 154{
149 struct kobject *kobj = of->sd->s_parent->s_dir.kobj; 155 struct kobject *kobj = of->sd->s_parent->s_dir.kobj;
150 const struct sysfs_ops *ops;
151 int rc = 0; 156 int rc = 0;
152 157
153 /* 158 /*
@@ -161,8 +166,18 @@ static int flush_write_buffer(struct sysfs_open_file *of, char *buf,
161 return -ENODEV; 166 return -ENODEV;
162 } 167 }
163 168
164 ops = sysfs_file_ops(of->sd); 169 if (sysfs_is_bin(of->sd)) {
165 rc = ops->store(kobj, of->sd->s_attr.attr, buf, count); 170 struct bin_attribute *battr = of->sd->s_bin_attr.bin_attr;
171
172 rc = -EIO;
173 if (battr->write)
174 rc = battr->write(of->file, kobj, battr, buf, off,
175 count);
176 } else {
177 const struct sysfs_ops *ops = sysfs_file_ops(of->sd);
178
179 rc = ops->store(kobj, of->sd->s_attr.attr, buf, count);
180 }
166 181
167 sysfs_put_active(of->sd); 182 sysfs_put_active(of->sd);
168 mutex_unlock(&of->mutex); 183 mutex_unlock(&of->mutex);
@@ -190,9 +205,17 @@ static ssize_t sysfs_write_file(struct file *file, const char __user *user_buf,
190 size_t count, loff_t *ppos) 205 size_t count, loff_t *ppos)
191{ 206{
192 struct sysfs_open_file *of = sysfs_of(file); 207 struct sysfs_open_file *of = sysfs_of(file);
193 ssize_t len = min_t(size_t, count, PAGE_SIZE - 1); 208 ssize_t len = min_t(size_t, count, PAGE_SIZE);
194 char *buf; 209 char *buf;
195 210
211 if (sysfs_is_bin(of->sd)) {
212 loff_t size = file_inode(file)->i_size;
213
214 if (size <= *ppos)
215 return 0;
216 len = min_t(ssize_t, len, size - *ppos);
217 }
218
196 if (!len) 219 if (!len)
197 return 0; 220 return 0;
198 221
@@ -206,7 +229,7 @@ static ssize_t sysfs_write_file(struct file *file, const char __user *user_buf,
206 } 229 }
207 buf[len] = '\0'; /* guarantee string termination */ 230 buf[len] = '\0'; /* guarantee string termination */
208 231
209 len = flush_write_buffer(of, buf, len); 232 len = flush_write_buffer(of, buf, *ppos, len);
210 if (len > 0) 233 if (len > 0)
211 *ppos += len; 234 *ppos += len;
212out_free: 235out_free:
@@ -471,6 +494,11 @@ const struct file_operations sysfs_file_operations = {
471 .poll = sysfs_poll, 494 .poll = sysfs_poll,
472}; 495};
473 496
497const struct file_operations sysfs_bin_operations = {
498 .write = sysfs_write_file,
499 .llseek = generic_file_llseek,
500};
501
474int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, 502int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd,
475 const struct attribute *attr, int type, 503 const struct attribute *attr, int type,
476 umode_t amode, const void *ns) 504 umode_t amode, const void *ns)
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 4b1d8258b071..f103bac53df7 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -212,6 +212,7 @@ int sysfs_inode_init(void);
212 * file.c 212 * file.c
213 */ 213 */
214extern const struct file_operations sysfs_file_operations; 214extern const struct file_operations sysfs_file_operations;
215extern const struct file_operations sysfs_bin_operations;
215 216
216int sysfs_add_file(struct sysfs_dirent *dir_sd, 217int sysfs_add_file(struct sysfs_dirent *dir_sd,
217 const struct attribute *attr, int type); 218 const struct attribute *attr, int type);