@@ -419,28 +419,42 @@ static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, lo
419
419
return ret ;
420
420
}
421
421
422
- ssize_t __vfs_read (struct file * file , char __user * buf , size_t count ,
423
- loff_t * pos )
422
+ ssize_t __kernel_read (struct file * file , void * buf , size_t count , loff_t * pos )
424
423
{
424
+ mm_segment_t old_fs = get_fs ();
425
+ ssize_t ret ;
426
+
427
+ if (WARN_ON_ONCE (!(file -> f_mode & FMODE_READ )))
428
+ return - EINVAL ;
429
+ if (!(file -> f_mode & FMODE_CAN_READ ))
430
+ return - EINVAL ;
431
+
432
+ if (count > MAX_RW_COUNT )
433
+ count = MAX_RW_COUNT ;
434
+ set_fs (KERNEL_DS );
425
435
if (file -> f_op -> read )
426
- return file -> f_op -> read (file , buf , count , pos );
436
+ ret = file -> f_op -> read (file , ( void __user * ) buf , count , pos );
427
437
else if (file -> f_op -> read_iter )
428
- return new_sync_read (file , buf , count , pos );
438
+ ret = new_sync_read (file , ( void __user * ) buf , count , pos );
429
439
else
430
- return - EINVAL ;
440
+ ret = - EINVAL ;
441
+ set_fs (old_fs );
442
+ if (ret > 0 ) {
443
+ fsnotify_access (file );
444
+ add_rchar (current , ret );
445
+ }
446
+ inc_syscr (current );
447
+ return ret ;
431
448
}
432
449
433
450
ssize_t kernel_read (struct file * file , void * buf , size_t count , loff_t * pos )
434
451
{
435
- mm_segment_t old_fs ;
436
- ssize_t result ;
452
+ ssize_t ret ;
437
453
438
- old_fs = get_fs ();
439
- set_fs (KERNEL_DS );
440
- /* The cast to a user pointer is valid due to the set_fs() */
441
- result = vfs_read (file , (void __user * )buf , count , pos );
442
- set_fs (old_fs );
443
- return result ;
454
+ ret = rw_verify_area (READ , file , pos , count );
455
+ if (ret )
456
+ return ret ;
457
+ return __kernel_read (file , buf , count , pos );
444
458
}
445
459
EXPORT_SYMBOL (kernel_read );
446
460
@@ -456,17 +470,22 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
456
470
return - EFAULT ;
457
471
458
472
ret = rw_verify_area (READ , file , pos , count );
459
- if (!ret ) {
460
- if (count > MAX_RW_COUNT )
461
- count = MAX_RW_COUNT ;
462
- ret = __vfs_read (file , buf , count , pos );
463
- if (ret > 0 ) {
464
- fsnotify_access (file );
465
- add_rchar (current , ret );
466
- }
467
- inc_syscr (current );
468
- }
473
+ if (ret )
474
+ return ret ;
475
+ if (count > MAX_RW_COUNT )
476
+ count = MAX_RW_COUNT ;
469
477
478
+ if (file -> f_op -> read )
479
+ ret = file -> f_op -> read (file , buf , count , pos );
480
+ else if (file -> f_op -> read_iter )
481
+ ret = new_sync_read (file , buf , count , pos );
482
+ else
483
+ ret = - EINVAL ;
484
+ if (ret > 0 ) {
485
+ fsnotify_access (file );
486
+ add_rchar (current , ret );
487
+ }
488
+ inc_syscr (current );
470
489
return ret ;
471
490
}
472
491
@@ -488,23 +507,15 @@ static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t
488
507
return ret ;
489
508
}
490
509
491
- static ssize_t __vfs_write (struct file * file , const char __user * p ,
492
- size_t count , loff_t * pos )
493
- {
494
- if (file -> f_op -> write )
495
- return file -> f_op -> write (file , p , count , pos );
496
- else if (file -> f_op -> write_iter )
497
- return new_sync_write (file , p , count , pos );
498
- else
499
- return - EINVAL ;
500
- }
501
-
510
+ /* caller is responsible for file_start_write/file_end_write */
502
511
ssize_t __kernel_write (struct file * file , const void * buf , size_t count , loff_t * pos )
503
512
{
504
513
mm_segment_t old_fs ;
505
514
const char __user * p ;
506
515
ssize_t ret ;
507
516
517
+ if (WARN_ON_ONCE (!(file -> f_mode & FMODE_WRITE )))
518
+ return - EBADF ;
508
519
if (!(file -> f_mode & FMODE_CAN_WRITE ))
509
520
return - EINVAL ;
510
521
@@ -513,7 +524,12 @@ ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t
513
524
p = (__force const char __user * )buf ;
514
525
if (count > MAX_RW_COUNT )
515
526
count = MAX_RW_COUNT ;
516
- ret = __vfs_write (file , p , count , pos );
527
+ if (file -> f_op -> write )
528
+ ret = file -> f_op -> write (file , p , count , pos );
529
+ else if (file -> f_op -> write_iter )
530
+ ret = new_sync_write (file , p , count , pos );
531
+ else
532
+ ret = - EINVAL ;
517
533
set_fs (old_fs );
518
534
if (ret > 0 ) {
519
535
fsnotify_modify (file );
@@ -522,21 +538,20 @@ ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t
522
538
inc_syscw (current );
523
539
return ret ;
524
540
}
525
- EXPORT_SYMBOL (__kernel_write );
526
541
527
542
ssize_t kernel_write (struct file * file , const void * buf , size_t count ,
528
543
loff_t * pos )
529
544
{
530
- mm_segment_t old_fs ;
531
- ssize_t res ;
545
+ ssize_t ret ;
532
546
533
- old_fs = get_fs ();
534
- set_fs (KERNEL_DS );
535
- /* The cast to a user pointer is valid due to the set_fs() */
536
- res = vfs_write (file , (__force const char __user * )buf , count , pos );
537
- set_fs (old_fs );
547
+ ret = rw_verify_area (WRITE , file , pos , count );
548
+ if (ret )
549
+ return ret ;
538
550
539
- return res ;
551
+ file_start_write (file );
552
+ ret = __kernel_write (file , buf , count , pos );
553
+ file_end_write (file );
554
+ return ret ;
540
555
}
541
556
EXPORT_SYMBOL (kernel_write );
542
557
@@ -552,19 +567,23 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
552
567
return - EFAULT ;
553
568
554
569
ret = rw_verify_area (WRITE , file , pos , count );
555
- if (!ret ) {
556
- if (count > MAX_RW_COUNT )
557
- count = MAX_RW_COUNT ;
558
- file_start_write (file );
559
- ret = __vfs_write (file , buf , count , pos );
560
- if (ret > 0 ) {
561
- fsnotify_modify (file );
562
- add_wchar (current , ret );
563
- }
564
- inc_syscw (current );
565
- file_end_write (file );
570
+ if (ret )
571
+ return ret ;
572
+ if (count > MAX_RW_COUNT )
573
+ count = MAX_RW_COUNT ;
574
+ file_start_write (file );
575
+ if (file -> f_op -> write )
576
+ ret = file -> f_op -> write (file , buf , count , pos );
577
+ else if (file -> f_op -> write_iter )
578
+ ret = new_sync_write (file , buf , count , pos );
579
+ else
580
+ ret = - EINVAL ;
581
+ if (ret > 0 ) {
582
+ fsnotify_modify (file );
583
+ add_wchar (current , ret );
566
584
}
567
-
585
+ inc_syscw (current );
586
+ file_end_write (file );
568
587
return ret ;
569
588
}
570
589
0 commit comments