@@ -4501,6 +4501,8 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
4501
4501
struct ext4_map_blocks map ;
4502
4502
unsigned int credits ;
4503
4503
loff_t epos , old_size = i_size_read (inode );
4504
+ unsigned int blkbits = inode -> i_blkbits ;
4505
+ bool alloc_zero = false;
4504
4506
4505
4507
BUG_ON (!ext4_test_inode_flag (inode , EXT4_INODE_EXTENTS ));
4506
4508
map .m_lblk = offset ;
@@ -4513,6 +4515,17 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
4513
4515
if (len <= EXT_UNWRITTEN_MAX_LEN )
4514
4516
flags |= EXT4_GET_BLOCKS_NO_NORMALIZE ;
4515
4517
4518
+ /*
4519
+ * Do the actual write zero during a running journal transaction
4520
+ * costs a lot. First allocate an unwritten extent and then
4521
+ * convert it to written after zeroing it out.
4522
+ */
4523
+ if (flags & EXT4_GET_BLOCKS_ZERO ) {
4524
+ flags &= ~EXT4_GET_BLOCKS_ZERO ;
4525
+ flags |= EXT4_GET_BLOCKS_UNWRIT_EXT ;
4526
+ alloc_zero = true;
4527
+ }
4528
+
4516
4529
/*
4517
4530
* credits to insert 1 extent into extent tree
4518
4531
*/
@@ -4549,9 +4562,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
4549
4562
* allow a full retry cycle for any remaining allocations
4550
4563
*/
4551
4564
retries = 0 ;
4552
- map .m_lblk += ret ;
4553
- map .m_len = len = len - ret ;
4554
- epos = (loff_t )map .m_lblk << inode -> i_blkbits ;
4565
+ epos = (loff_t )(map .m_lblk + ret ) << blkbits ;
4555
4566
inode_set_ctime_current (inode );
4556
4567
if (new_size ) {
4557
4568
if (epos > new_size )
@@ -4571,6 +4582,21 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
4571
4582
ret2 = ret3 ? ret3 : ret2 ;
4572
4583
if (unlikely (ret2 ))
4573
4584
break ;
4585
+
4586
+ if (alloc_zero &&
4587
+ (map .m_flags & (EXT4_MAP_MAPPED | EXT4_MAP_UNWRITTEN ))) {
4588
+ ret2 = ext4_issue_zeroout (inode , map .m_lblk , map .m_pblk ,
4589
+ map .m_len );
4590
+ if (likely (!ret2 ))
4591
+ ret2 = ext4_convert_unwritten_extents (NULL ,
4592
+ inode , (loff_t )map .m_lblk << blkbits ,
4593
+ (loff_t )map .m_len << blkbits );
4594
+ if (ret2 )
4595
+ break ;
4596
+ }
4597
+
4598
+ map .m_lblk += ret ;
4599
+ map .m_len = len = len - ret ;
4574
4600
}
4575
4601
if (ret == - ENOSPC && ext4_should_retry_alloc (inode -> i_sb , & retries ))
4576
4602
goto retry ;
@@ -4636,7 +4662,11 @@ static long ext4_zero_range(struct file *file, loff_t offset,
4636
4662
if (end_lblk > start_lblk ) {
4637
4663
ext4_lblk_t zero_blks = end_lblk - start_lblk ;
4638
4664
4639
- flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN | EXT4_EX_NOCACHE );
4665
+ if (mode & FALLOC_FL_WRITE_ZEROES )
4666
+ flags = EXT4_GET_BLOCKS_CREATE_ZERO | EXT4_EX_NOCACHE ;
4667
+ else
4668
+ flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN |
4669
+ EXT4_EX_NOCACHE );
4640
4670
ret = ext4_alloc_file_blocks (file , start_lblk , zero_blks ,
4641
4671
new_size , flags );
4642
4672
if (ret )
@@ -4745,11 +4775,18 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
4745
4775
if (IS_ENCRYPTED (inode ) &&
4746
4776
(mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE )))
4747
4777
return - EOPNOTSUPP ;
4778
+ /*
4779
+ * Don't allow writing zeroes if the underlying device does not
4780
+ * enable the unmap write zeroes operation.
4781
+ */
4782
+ if ((mode & FALLOC_FL_WRITE_ZEROES ) &&
4783
+ !bdev_write_zeroes_unmap_sectors (inode -> i_sb -> s_bdev ))
4784
+ return - EOPNOTSUPP ;
4748
4785
4749
4786
/* Return error if mode is not supported */
4750
4787
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
4751
- FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE |
4752
- FALLOC_FL_INSERT_RANGE ))
4788
+ FALLOC_FL_ZERO_RANGE | FALLOC_FL_COLLAPSE_RANGE |
4789
+ FALLOC_FL_INSERT_RANGE | FALLOC_FL_WRITE_ZEROES ))
4753
4790
return - EOPNOTSUPP ;
4754
4791
4755
4792
inode_lock (inode );
@@ -4780,16 +4817,23 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
4780
4817
if (ret )
4781
4818
goto out_invalidate_lock ;
4782
4819
4783
- if (mode & FALLOC_FL_PUNCH_HOLE )
4820
+ switch (mode & FALLOC_FL_MODE_MASK ) {
4821
+ case FALLOC_FL_PUNCH_HOLE :
4784
4822
ret = ext4_punch_hole (file , offset , len );
4785
- else if (mode & FALLOC_FL_COLLAPSE_RANGE )
4823
+ break ;
4824
+ case FALLOC_FL_COLLAPSE_RANGE :
4786
4825
ret = ext4_collapse_range (file , offset , len );
4787
- else if (mode & FALLOC_FL_INSERT_RANGE )
4826
+ break ;
4827
+ case FALLOC_FL_INSERT_RANGE :
4788
4828
ret = ext4_insert_range (file , offset , len );
4789
- else if (mode & FALLOC_FL_ZERO_RANGE )
4829
+ break ;
4830
+ case FALLOC_FL_ZERO_RANGE :
4831
+ case FALLOC_FL_WRITE_ZEROES :
4790
4832
ret = ext4_zero_range (file , offset , len , mode );
4791
- else
4833
+ break ;
4834
+ default :
4792
4835
ret = - EOPNOTSUPP ;
4836
+ }
4793
4837
4794
4838
out_invalidate_lock :
4795
4839
filemap_invalidate_unlock (mapping );
0 commit comments