aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/kernfs/file.c')
-rw-r--r--fs/kernfs/file.c51
1 files changed, 29 insertions, 22 deletions
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 7247252ee9b1..e1574008adc9 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -190,15 +190,16 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
190 char *buf; 190 char *buf;
191 191
192 buf = of->prealloc_buf; 192 buf = of->prealloc_buf;
193 if (!buf) 193 if (buf)
194 mutex_lock(&of->prealloc_mutex);
195 else
194 buf = kmalloc(len, GFP_KERNEL); 196 buf = kmalloc(len, GFP_KERNEL);
195 if (!buf) 197 if (!buf)
196 return -ENOMEM; 198 return -ENOMEM;
197 199
198 /* 200 /*
199 * @of->mutex nests outside active ref and is used both to ensure that 201 * @of->mutex nests outside active ref and is used both to ensure that
200 * the ops aren't called concurrently for the same open file, and 202 * the ops aren't called concurrently for the same open file.
201 * to provide exclusive access to ->prealloc_buf (when that exists).
202 */ 203 */
203 mutex_lock(&of->mutex); 204 mutex_lock(&of->mutex);
204 if (!kernfs_get_active(of->kn)) { 205 if (!kernfs_get_active(of->kn)) {
@@ -214,21 +215,23 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
214 else 215 else
215 len = -EINVAL; 216 len = -EINVAL;
216 217
218 kernfs_put_active(of->kn);
219 mutex_unlock(&of->mutex);
220
217 if (len < 0) 221 if (len < 0)
218 goto out_unlock; 222 goto out_free;
219 223
220 if (copy_to_user(user_buf, buf, len)) { 224 if (copy_to_user(user_buf, buf, len)) {
221 len = -EFAULT; 225 len = -EFAULT;
222 goto out_unlock; 226 goto out_free;
223 } 227 }
224 228
225 *ppos += len; 229 *ppos += len;
226 230
227 out_unlock:
228 kernfs_put_active(of->kn);
229 mutex_unlock(&of->mutex);
230 out_free: 231 out_free:
231 if (buf != of->prealloc_buf) 232 if (buf == of->prealloc_buf)
233 mutex_unlock(&of->prealloc_mutex);
234 else
232 kfree(buf); 235 kfree(buf);
233 return len; 236 return len;
234} 237}
@@ -284,15 +287,22 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
284 } 287 }
285 288
286 buf = of->prealloc_buf; 289 buf = of->prealloc_buf;
287 if (!buf) 290 if (buf)
291 mutex_lock(&of->prealloc_mutex);
292 else
288 buf = kmalloc(len + 1, GFP_KERNEL); 293 buf = kmalloc(len + 1, GFP_KERNEL);
289 if (!buf) 294 if (!buf)
290 return -ENOMEM; 295 return -ENOMEM;
291 296
297 if (copy_from_user(buf, user_buf, len)) {
298 len = -EFAULT;
299 goto out_free;
300 }
301 buf[len] = '\0'; /* guarantee string termination */
302
292 /* 303 /*
293 * @of->mutex nests outside active ref and is used both to ensure that 304 * @of->mutex nests outside active ref and is used both to ensure that
294 * the ops aren't called concurrently for the same open file, and 305 * the ops aren't called concurrently for the same open file.
295 * to provide exclusive access to ->prealloc_buf (when that exists).
296 */ 306 */
297 mutex_lock(&of->mutex); 307 mutex_lock(&of->mutex);
298 if (!kernfs_get_active(of->kn)) { 308 if (!kernfs_get_active(of->kn)) {
@@ -301,26 +311,22 @@ static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf,
301 goto out_free; 311 goto out_free;
302 } 312 }
303 313
304 if (copy_from_user(buf, user_buf, len)) {
305 len = -EFAULT;
306 goto out_unlock;
307 }
308 buf[len] = '\0'; /* guarantee string termination */
309
310 ops = kernfs_ops(of->kn); 314 ops = kernfs_ops(of->kn);
311 if (ops->write) 315 if (ops->write)
312 len = ops->write(of, buf, len, *ppos); 316 len = ops->write(of, buf, len, *ppos);
313 else 317 else
314 len = -EINVAL; 318 len = -EINVAL;
315 319
320 kernfs_put_active(of->kn);
321 mutex_unlock(&of->mutex);
322
316 if (len > 0) 323 if (len > 0)
317 *ppos += len; 324 *ppos += len;
318 325
319out_unlock:
320 kernfs_put_active(of->kn);
321 mutex_unlock(&of->mutex);
322out_free: 326out_free:
323 if (buf != of->prealloc_buf) 327 if (buf == of->prealloc_buf)
328 mutex_unlock(&of->prealloc_mutex);
329 else
324 kfree(buf); 330 kfree(buf);
325 return len; 331 return len;
326} 332}
@@ -687,6 +693,7 @@ static int kernfs_fop_open(struct inode *inode, struct file *file)
687 error = -ENOMEM; 693 error = -ENOMEM;
688 if (!of->prealloc_buf) 694 if (!of->prealloc_buf)
689 goto err_free; 695 goto err_free;
696 mutex_init(&of->prealloc_mutex);
690 } 697 }
691 698
692 /* 699 /*