aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2014-10-14 01:57:26 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-11-07 13:54:38 -0500
commit4ef67a8c95f32ed0c8c6ed5fe01d1dd16358350e (patch)
tree82e66c1da3bbe63345edb27d7e64e3245df729ee /fs
parent2b75869bba676c248d8d25ae6d2bd9221dfffdb6 (diff)
sysfs/kernfs: make read requests on pre-alloc files use the buffer.
To match the previous patch which used the pre-alloc buffer for writes, this patch causes reads to use the same buffer. This is not strictly necessary as the current seq_read() will allocate on first read, so user-space can trigger the required pre-alloc. But consistency is valuable. The read function is somewhat simpler than seq_read() and, for example, does not support reading from an offset into the file: reads must be at the start of the file. As seq_read() does not use the prealloc buffer, ->seq_show is incompatible with ->prealloc and caused an EINVAL return from open(). sysfs code which calls into kernfs always chooses the correct function. As the buffer is shared with writes and other reads, the mutex is extended to cover the copy_to_user. Signed-off-by: NeilBrown <neilb@suse.de> Reviewed-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/kernfs/file.c30
-rw-r--r--fs/sysfs/file.c32
2 files changed, 49 insertions, 13 deletions
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 70186e2e692a..697390ea47b8 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -189,13 +189,16 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
189 const struct kernfs_ops *ops; 189 const struct kernfs_ops *ops;
190 char *buf; 190 char *buf;
191 191
192 buf = kmalloc(len, GFP_KERNEL); 192 buf = of->prealloc_buf;
193 if (!buf)
194 buf = kmalloc(len, GFP_KERNEL);
193 if (!buf) 195 if (!buf)
194 return -ENOMEM; 196 return -ENOMEM;
195 197
196 /* 198 /*
197 * @of->mutex nests outside active ref and is primarily to ensure that 199 * @of->mutex nests outside active ref and is used both to ensure that
198 * the ops aren't called concurrently for the same open file. 200 * the ops aren't called concurrently for the same open file, and
201 * to provide exclusive access to ->prealloc_buf (when that exists).
199 */ 202 */
200 mutex_lock(&of->mutex); 203 mutex_lock(&of->mutex);
201 if (!kernfs_get_active(of->kn)) { 204 if (!kernfs_get_active(of->kn)) {
@@ -210,21 +213,22 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
210 else 213 else
211 len = -EINVAL; 214 len = -EINVAL;
212 215
213 kernfs_put_active(of->kn);
214 mutex_unlock(&of->mutex);
215
216 if (len < 0) 216 if (len < 0)
217 goto out_free; 217 goto out_unlock;
218 218
219 if (copy_to_user(user_buf, buf, len)) { 219 if (copy_to_user(user_buf, buf, len)) {
220 len = -EFAULT; 220 len = -EFAULT;
221 goto out_free; 221 goto out_unlock;
222 } 222 }
223 223
224 *ppos += len; 224 *ppos += len;
225 225
226 out_unlock:
227 kernfs_put_active(of->kn);
228 mutex_unlock(&of->mutex);
226 out_free: 229 out_free:
227 kfree(buf); 230 if (buf != of->prealloc_buf)
231 kfree(buf);
228 return len; 232 return len;
229} 233}
230 234
@@ -690,6 +694,14 @@ static int kernfs_fop_open(struct inode *inode, struct file *file)
690 */ 694 */
691 of->atomic_write_len = ops->atomic_write_len; 695 of->atomic_write_len = ops->atomic_write_len;
692 696
697 error = -EINVAL;
698 /*
699 * ->seq_show is incompatible with ->prealloc,
700 * as seq_read does its own allocation.
701 * ->read must be used instead.
702 */
703 if (ops->prealloc && ops->seq_show)
704 goto err_free;
693 if (ops->prealloc) { 705 if (ops->prealloc) {
694 int len = of->atomic_write_len ?: PAGE_SIZE; 706 int len = of->atomic_write_len ?: PAGE_SIZE;
695 of->prealloc_buf = kmalloc(len + 1, GFP_KERNEL); 707 of->prealloc_buf = kmalloc(len + 1, GFP_KERNEL);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 4ad3721a991c..dfe928a9540f 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -102,6 +102,22 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
102 return battr->read(of->file, kobj, battr, buf, pos, count); 102 return battr->read(of->file, kobj, battr, buf, pos, count);
103} 103}
104 104
105/* kernfs read callback for regular sysfs files with pre-alloc */
106static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf,
107 size_t count, loff_t pos)
108{
109 const struct sysfs_ops *ops = sysfs_file_ops(of->kn);
110 struct kobject *kobj = of->kn->parent->priv;
111
112 /*
113 * If buf != of->prealloc_buf, we don't know how
114 * large it is, so cannot safely pass it to ->show
115 */
116 if (pos || WARN_ON_ONCE(buf != of->prealloc_buf))
117 return 0;
118 return ops->show(kobj, of->kn->priv, buf);
119}
120
105/* kernfs write callback for regular sysfs files */ 121/* kernfs write callback for regular sysfs files */
106static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf, 122static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf,
107 size_t count, loff_t pos) 123 size_t count, loff_t pos)
@@ -184,13 +200,18 @@ static const struct kernfs_ops sysfs_file_kfops_rw = {
184 .write = sysfs_kf_write, 200 .write = sysfs_kf_write,
185}; 201};
186 202
203static const struct kernfs_ops sysfs_prealloc_kfops_ro = {
204 .read = sysfs_kf_read,
205 .prealloc = true,
206};
207
187static const struct kernfs_ops sysfs_prealloc_kfops_wo = { 208static const struct kernfs_ops sysfs_prealloc_kfops_wo = {
188 .write = sysfs_kf_write, 209 .write = sysfs_kf_write,
189 .prealloc = true, 210 .prealloc = true,
190}; 211};
191 212
192static const struct kernfs_ops sysfs_prealloc_kfops_rw = { 213static const struct kernfs_ops sysfs_prealloc_kfops_rw = {
193 .seq_show = sysfs_kf_seq_show, 214 .read = sysfs_kf_read,
194 .write = sysfs_kf_write, 215 .write = sysfs_kf_write,
195 .prealloc = true, 216 .prealloc = true,
196}; 217};
@@ -238,9 +259,12 @@ int sysfs_add_file_mode_ns(struct kernfs_node *parent,
238 ops = &sysfs_prealloc_kfops_rw; 259 ops = &sysfs_prealloc_kfops_rw;
239 else 260 else
240 ops = &sysfs_file_kfops_rw; 261 ops = &sysfs_file_kfops_rw;
241 } else if (sysfs_ops->show) 262 } else if (sysfs_ops->show) {
242 ops = &sysfs_file_kfops_ro; 263 if (mode & SYSFS_PREALLOC)
243 else if (sysfs_ops->store) { 264 ops = &sysfs_prealloc_kfops_ro;
265 else
266 ops = &sysfs_file_kfops_ro;
267 } else if (sysfs_ops->store) {
244 if (mode & SYSFS_PREALLOC) 268 if (mode & SYSFS_PREALLOC)
245 ops = &sysfs_prealloc_kfops_wo; 269 ops = &sysfs_prealloc_kfops_wo;
246 else 270 else