@@ -29,7 +29,7 @@ static int exfat_cont_expand(struct inode *inode, loff_t size)
29
29
if (ret )
30
30
return ret ;
31
31
32
- num_clusters = EXFAT_B_TO_CLU_ROUND_UP ( ei -> i_size_ondisk , sbi );
32
+ num_clusters = EXFAT_B_TO_CLU ( exfat_ondisk_size ( inode ) , sbi );
33
33
new_num_clusters = EXFAT_B_TO_CLU_ROUND_UP (size , sbi );
34
34
35
35
if (new_num_clusters == num_clusters )
@@ -74,8 +74,6 @@ static int exfat_cont_expand(struct inode *inode, loff_t size)
74
74
/* Expanded range not zeroed, do not update valid_size */
75
75
i_size_write (inode , size );
76
76
77
- ei -> i_size_aligned = round_up (size , sb -> s_blocksize );
78
- ei -> i_size_ondisk = ei -> i_size_aligned ;
79
77
inode -> i_blocks = round_up (size , sbi -> cluster_size ) >> 9 ;
80
78
mark_inode_dirty (inode );
81
79
@@ -159,7 +157,7 @@ int __exfat_truncate(struct inode *inode)
159
157
exfat_set_volume_dirty (sb );
160
158
161
159
num_clusters_new = EXFAT_B_TO_CLU_ROUND_UP (i_size_read (inode ), sbi );
162
- num_clusters_phys = EXFAT_B_TO_CLU_ROUND_UP ( ei -> i_size_ondisk , sbi );
160
+ num_clusters_phys = EXFAT_B_TO_CLU ( exfat_ondisk_size ( inode ) , sbi );
163
161
164
162
exfat_chain_set (& clu , ei -> start_clu , num_clusters_phys , ei -> flags );
165
163
@@ -245,8 +243,6 @@ void exfat_truncate(struct inode *inode)
245
243
struct super_block * sb = inode -> i_sb ;
246
244
struct exfat_sb_info * sbi = EXFAT_SB (sb );
247
245
struct exfat_inode_info * ei = EXFAT_I (inode );
248
- unsigned int blocksize = i_blocksize (inode );
249
- loff_t aligned_size ;
250
246
int err ;
251
247
252
248
mutex_lock (& sbi -> s_lock );
@@ -264,17 +260,6 @@ void exfat_truncate(struct inode *inode)
264
260
265
261
inode -> i_blocks = round_up (i_size_read (inode ), sbi -> cluster_size ) >> 9 ;
266
262
write_size :
267
- aligned_size = i_size_read (inode );
268
- if (aligned_size & (blocksize - 1 )) {
269
- aligned_size |= (blocksize - 1 );
270
- aligned_size ++ ;
271
- }
272
-
273
- if (ei -> i_size_ondisk > i_size_read (inode ))
274
- ei -> i_size_ondisk = aligned_size ;
275
-
276
- if (ei -> i_size_aligned > i_size_read (inode ))
277
- ei -> i_size_aligned = aligned_size ;
278
263
mutex_unlock (& sbi -> s_lock );
279
264
}
280
265
@@ -302,6 +287,9 @@ int exfat_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
302
287
unsigned int ia_valid ;
303
288
int error ;
304
289
290
+ if (unlikely (exfat_forced_shutdown (inode -> i_sb )))
291
+ return - EIO ;
292
+
305
293
if ((attr -> ia_valid & ATTR_SIZE ) &&
306
294
attr -> ia_size > i_size_read (inode )) {
307
295
error = exfat_cont_expand (inode , attr -> ia_size );
@@ -485,6 +473,19 @@ static int exfat_ioctl_fitrim(struct inode *inode, unsigned long arg)
485
473
return 0 ;
486
474
}
487
475
476
+ static int exfat_ioctl_shutdown (struct super_block * sb , unsigned long arg )
477
+ {
478
+ u32 flags ;
479
+
480
+ if (!capable (CAP_SYS_ADMIN ))
481
+ return - EPERM ;
482
+
483
+ if (get_user (flags , (__u32 __user * )arg ))
484
+ return - EFAULT ;
485
+
486
+ return exfat_force_shutdown (sb , flags );
487
+ }
488
+
488
489
long exfat_ioctl (struct file * filp , unsigned int cmd , unsigned long arg )
489
490
{
490
491
struct inode * inode = file_inode (filp );
@@ -495,6 +496,8 @@ long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
495
496
return exfat_ioctl_get_attributes (inode , user_attr );
496
497
case FAT_IOCTL_SET_ATTRIBUTES :
497
498
return exfat_ioctl_set_attributes (filp , user_attr );
499
+ case EXFAT_IOC_SHUTDOWN :
500
+ return exfat_ioctl_shutdown (inode -> i_sb , arg );
498
501
case FITRIM :
499
502
return exfat_ioctl_fitrim (inode , arg );
500
503
default :
@@ -515,6 +518,9 @@ int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
515
518
struct inode * inode = filp -> f_mapping -> host ;
516
519
int err ;
517
520
521
+ if (unlikely (exfat_forced_shutdown (inode -> i_sb )))
522
+ return - EIO ;
523
+
518
524
err = __generic_file_fsync (filp , start , end , datasync );
519
525
if (err )
520
526
return err ;
@@ -526,32 +532,32 @@ int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
526
532
return blkdev_issue_flush (inode -> i_sb -> s_bdev );
527
533
}
528
534
529
- static int exfat_file_zeroed_range (struct file * file , loff_t start , loff_t end )
535
+ static int exfat_extend_valid_size (struct file * file , loff_t new_valid_size )
530
536
{
531
537
int err ;
538
+ loff_t pos ;
532
539
struct inode * inode = file_inode (file );
540
+ struct exfat_inode_info * ei = EXFAT_I (inode );
533
541
struct address_space * mapping = inode -> i_mapping ;
534
542
const struct address_space_operations * ops = mapping -> a_ops ;
535
543
536
- while (start < end ) {
537
- u32 zerofrom , len ;
544
+ pos = ei -> valid_size ;
545
+ while (pos < new_valid_size ) {
546
+ u32 len ;
538
547
struct folio * folio ;
539
548
540
- zerofrom = start & (PAGE_SIZE - 1 );
541
- len = PAGE_SIZE - zerofrom ;
542
- if (start + len > end )
543
- len = end - start ;
549
+ len = PAGE_SIZE - (pos & (PAGE_SIZE - 1 ));
550
+ if (pos + len > new_valid_size )
551
+ len = new_valid_size - pos ;
544
552
545
- err = ops -> write_begin (file , mapping , start , len , & folio , NULL );
553
+ err = ops -> write_begin (file , mapping , pos , len , & folio , NULL );
546
554
if (err )
547
555
goto out ;
548
556
549
- folio_zero_range (folio , offset_in_folio (folio , start ), len );
550
-
551
- err = ops -> write_end (file , mapping , start , len , len , folio , NULL );
557
+ err = ops -> write_end (file , mapping , pos , len , len , folio , NULL );
552
558
if (err < 0 )
553
559
goto out ;
554
- start += len ;
560
+ pos += len ;
555
561
556
562
balance_dirty_pages_ratelimited (mapping );
557
563
cond_resched ();
@@ -579,7 +585,7 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
579
585
goto unlock ;
580
586
581
587
if (pos > valid_size ) {
582
- ret = exfat_file_zeroed_range (file , valid_size , pos );
588
+ ret = exfat_extend_valid_size (file , pos );
583
589
if (ret < 0 && ret != - ENOSPC ) {
584
590
exfat_err (inode -> i_sb ,
585
591
"write: fail to zero from %llu to %llu(%zd)" ,
@@ -613,26 +619,46 @@ static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
613
619
return ret ;
614
620
}
615
621
616
- static int exfat_file_mmap (struct file * file , struct vm_area_struct * vma )
622
+ static vm_fault_t exfat_page_mkwrite (struct vm_fault * vmf )
617
623
{
618
- int ret ;
624
+ int err ;
625
+ struct vm_area_struct * vma = vmf -> vma ;
626
+ struct file * file = vma -> vm_file ;
619
627
struct inode * inode = file_inode (file );
620
628
struct exfat_inode_info * ei = EXFAT_I (inode );
621
- loff_t start = ((loff_t )vma -> vm_pgoff << PAGE_SHIFT );
622
- loff_t end = min_t (loff_t , i_size_read (inode ),
629
+ loff_t start , end ;
630
+
631
+ if (!inode_trylock (inode ))
632
+ return VM_FAULT_RETRY ;
633
+
634
+ start = ((loff_t )vma -> vm_pgoff << PAGE_SHIFT );
635
+ end = min_t (loff_t , i_size_read (inode ),
623
636
start + vma -> vm_end - vma -> vm_start );
624
637
625
- if ((vma -> vm_flags & VM_WRITE ) && ei -> valid_size < end ) {
626
- ret = exfat_file_zeroed_range (file , ei -> valid_size , end );
627
- if (ret < 0 ) {
628
- exfat_err (inode -> i_sb ,
629
- "mmap: fail to zero from %llu to %llu(%d)" ,
630
- start , end , ret );
631
- return ret ;
638
+ if (ei -> valid_size < end ) {
639
+ err = exfat_extend_valid_size (file , end );
640
+ if (err < 0 ) {
641
+ inode_unlock (inode );
642
+ return vmf_fs_error (err );
632
643
}
633
644
}
634
645
635
- return generic_file_mmap (file , vma );
646
+ inode_unlock (inode );
647
+
648
+ return filemap_page_mkwrite (vmf );
649
+ }
650
+
651
+ static const struct vm_operations_struct exfat_file_vm_ops = {
652
+ .fault = filemap_fault ,
653
+ .map_pages = filemap_map_pages ,
654
+ .page_mkwrite = exfat_page_mkwrite ,
655
+ };
656
+
657
+ static int exfat_file_mmap (struct file * file , struct vm_area_struct * vma )
658
+ {
659
+ file_accessed (file );
660
+ vma -> vm_ops = & exfat_file_vm_ops ;
661
+ return 0 ;
636
662
}
637
663
638
664
const struct file_operations exfat_file_operations = {
0 commit comments