diff options
-rw-r--r-- | fs/kernfs/file.c | 30 | ||||
-rw-r--r-- | fs/sysfs/file.c | 32 |
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 */ | ||
106 | static 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 */ |
106 | static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf, | 122 | static 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 | ||
203 | static const struct kernfs_ops sysfs_prealloc_kfops_ro = { | ||
204 | .read = sysfs_kf_read, | ||
205 | .prealloc = true, | ||
206 | }; | ||
207 | |||
187 | static const struct kernfs_ops sysfs_prealloc_kfops_wo = { | 208 | static 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 | ||
192 | static const struct kernfs_ops sysfs_prealloc_kfops_rw = { | 213 | static 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 |