@@ -190,15 +190,16 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
190
190
char * buf ;
191
191
192
192
buf = of -> prealloc_buf ;
193
- if (!buf )
193
+ if (buf )
194
+ mutex_lock (& of -> prealloc_mutex );
195
+ else
194
196
buf = kmalloc (len , GFP_KERNEL );
195
197
if (!buf )
196
198
return - ENOMEM ;
197
199
198
200
/*
199
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
201
- * to provide exclusive access to ->prealloc_buf (when that exists).
202
+ * the ops aren't called concurrently for the same open file.
202
203
*/
203
204
mutex_lock (& of -> mutex );
204
205
if (!kernfs_get_active (of -> kn )) {
@@ -214,21 +215,23 @@ static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of,
214
215
else
215
216
len = - EINVAL ;
216
217
218
+ kernfs_put_active (of -> kn );
219
+ mutex_unlock (& of -> mutex );
220
+
217
221
if (len < 0 )
218
- goto out_unlock ;
222
+ goto out_free ;
219
223
220
224
if (copy_to_user (user_buf , buf , len )) {
221
225
len = - EFAULT ;
222
- goto out_unlock ;
226
+ goto out_free ;
223
227
}
224
228
225
229
* ppos += len ;
226
230
227
- out_unlock :
228
- kernfs_put_active (of -> kn );
229
- mutex_unlock (& of -> mutex );
230
231
out_free :
231
- if (buf != of -> prealloc_buf )
232
+ if (buf == of -> prealloc_buf )
233
+ mutex_unlock (& of -> prealloc_mutex );
234
+ else
232
235
kfree (buf );
233
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
289
buf = of -> prealloc_buf ;
287
- if (!buf )
290
+ if (buf )
291
+ mutex_lock (& of -> prealloc_mutex );
292
+ else
288
293
buf = kmalloc (len + 1 , GFP_KERNEL );
289
294
if (!buf )
290
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
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
295
- * to provide exclusive access to ->prealloc_buf (when that exists).
305
+ * the ops aren't called concurrently for the same open file.
296
306
*/
297
307
mutex_lock (& of -> mutex );
298
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
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
314
ops = kernfs_ops (of -> kn );
311
315
if (ops -> write )
312
316
len = ops -> write (of , buf , len , * ppos );
313
317
else
314
318
len = - EINVAL ;
315
319
320
+ kernfs_put_active (of -> kn );
321
+ mutex_unlock (& of -> mutex );
322
+
316
323
if (len > 0 )
317
324
* ppos += len ;
318
325
319
- out_unlock :
320
- kernfs_put_active (of -> kn );
321
- mutex_unlock (& of -> mutex );
322
326
out_free :
323
- if (buf != of -> prealloc_buf )
327
+ if (buf == of -> prealloc_buf )
328
+ mutex_unlock (& of -> prealloc_mutex );
329
+ else
324
330
kfree (buf );
325
331
return len ;
326
332
}
@@ -687,6 +693,7 @@ static int kernfs_fop_open(struct inode *inode, struct file *file)
687
693
error = - ENOMEM ;
688
694
if (!of -> prealloc_buf )
689
695
goto err_free ;
696
+ mutex_init (& of -> prealloc_mutex );
690
697
}
691
698
692
699
/*
0 commit comments