diff mbox series

[v2,8/9] ext4: make ext4_insert_delayed_block() insert multi-blocks

Message ID 20240410034203.2188357-9-yi.zhang@huaweicloud.com
State New
Headers show
Series ext4: support adding multi-delalloc blocks | expand

Commit Message

Zhang Yi April 10, 2024, 3:42 a.m. UTC
From: Zhang Yi <yi.zhang@huawei.com>

Rename ext4_insert_delayed_block() to ext4_insert_delayed_blocks(),
pass length parameter to make it insert multi delalloc blocks once a
time. For non-bigalloc case, just reserve len blocks and insert delalloc
extent. For bigalloc case, we can ensure the middle clusters are not
allocated, but need to check whether the start and end clusters are
delayed/allocated, if not, we should reserve more space for the start
and/or end block(s).

Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
---
 fs/ext4/inode.c | 51 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 36 insertions(+), 15 deletions(-)

Comments

Jan Kara April 29, 2024, 10:06 a.m. UTC | #1
On Wed 10-04-24 11:42:02, Zhang Yi wrote:
> From: Zhang Yi <yi.zhang@huawei.com>
> 
> Rename ext4_insert_delayed_block() to ext4_insert_delayed_blocks(),
> pass length parameter to make it insert multi delalloc blocks once a
> time. For non-bigalloc case, just reserve len blocks and insert delalloc
> extent. For bigalloc case, we can ensure the middle clusters are not
> allocated, but need to check whether the start and end clusters are
> delayed/allocated, if not, we should reserve more space for the start
> and/or end block(s).
> 
> Signed-off-by: Zhang Yi <yi.zhang@huawei.com>

Thanks for the patch. Some comments below.

> ---
>  fs/ext4/inode.c | 51 ++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 36 insertions(+), 15 deletions(-)
> 
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index 46c34baa848a..08e2692b7286 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -1678,24 +1678,28 @@ static int ext4_da_check_clu_allocated(struct inode *inode, ext4_lblk_t lblk,
>  }
>  
>  /*
> - * ext4_insert_delayed_block - adds a delayed block to the extents status
> - *                             tree, incrementing the reserved cluster/block
> - *                             count or making a pending reservation
> - *                             where needed
> + * ext4_insert_delayed_blocks - adds a multiple delayed blocks to the extents
> + *                              status tree, incrementing the reserved
> + *                              cluster/block count or making pending
> + *                              reservations where needed
>   *
>   * @inode - file containing the newly added block
> - * @lblk - logical block to be added
> + * @lblk - start logical block to be added
> + * @len - length of blocks to be added
>   *
>   * Returns 0 on success, negative error code on failure.
>   */
> -static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk)
> +static int ext4_insert_delayed_blocks(struct inode *inode, ext4_lblk_t lblk,
> +				      ext4_lblk_t len)
>  {
>  	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
> -	int ret;
> -	bool allocated = false;
> +	int resv_clu, ret;
	    ^^^ this variable is in prinple the length of the extent. Thus
it should be ext4_lblk_t type.

> +	bool lclu_allocated = false;
> +	bool end_allocated = false;
> +	ext4_lblk_t end = lblk + len - 1;
>  
>  	/*
> -	 * If the cluster containing lblk is shared with a delayed,
> +	 * If the cluster containing lblk or end is shared with a delayed,
>  	 * written, or unwritten extent in a bigalloc file system, it's
>  	 * already been accounted for and does not need to be reserved.
>  	 * A pending reservation must be made for the cluster if it's
> @@ -1706,21 +1710,38 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk)
>  	 * extents status tree doesn't get a match.
>  	 */
>  	if (sbi->s_cluster_ratio == 1) {
> -		ret = ext4_da_reserve_space(inode, 1);
> +		ret = ext4_da_reserve_space(inode, len);
>  		if (ret != 0)   /* ENOSPC */
>  			return ret;
>  	} else {   /* bigalloc */
> -		ret = ext4_da_check_clu_allocated(inode, lblk, &allocated);
> +		resv_clu = EXT4_B2C(sbi, end) - EXT4_B2C(sbi, lblk) - 1;
> +		if (resv_clu < 0)
> +			resv_clu = 0;

Here resv_clu going negative is strange I'm not sure the math is 100%
correct in all the cases. I think it would be more logical as:

		resv_clu = EXT4_B2C(sbi, end) - EXT4_B2C(sbi, lblk) + 1;

and then update resv_clu below as:

> +
> +		ret = ext4_da_check_clu_allocated(inode, lblk, &lclu_allocated);
>  		if (ret < 0)
>  			return ret;
> -		if (ret > 0) {
> -			ret = ext4_da_reserve_space(inode, 1);
> +		if (ret > 0)
> +			resv_clu++;

Here we would do:
		if (ret == 0)
			resv_clu--;

> +
> +		if (EXT4_B2C(sbi, lblk) != EXT4_B2C(sbi, end)) {
> +			ret = ext4_da_check_clu_allocated(inode, end,
> +							  &end_allocated);
> +			if (ret < 0)
> +				return ret;
> +			if (ret > 0)
> +				resv_clu++;

And similarly here:
			if (ret == 0)
				resv_clu--;

									Honza

> +		}
> +
> +		if (resv_clu) {
> +			ret = ext4_da_reserve_space(inode, resv_clu);
>  			if (ret != 0)   /* ENOSPC */
>  				return ret;
>  		}
>  	}
>  
> -	ext4_es_insert_delayed_extent(inode, lblk, 1, allocated, false);
> +	ext4_es_insert_delayed_extent(inode, lblk, len, lclu_allocated,
> +				      end_allocated);
>  	return 0;
>  }
>  
> @@ -1823,7 +1844,7 @@ static int ext4_da_map_blocks(struct inode *inode, struct ext4_map_blocks *map,
>  		}
>  	}
>  
> -	retval = ext4_insert_delayed_block(inode, map->m_lblk);
> +	retval = ext4_insert_delayed_blocks(inode, map->m_lblk, map->m_len);
>  	up_write(&EXT4_I(inode)->i_data_sem);
>  	if (retval)
>  		return retval;
> -- 
> 2.39.2
>
Zhang Yi April 29, 2024, 12:54 p.m. UTC | #2
On 2024/4/29 18:06, Jan Kara wrote:
> On Wed 10-04-24 11:42:02, Zhang Yi wrote:
>> From: Zhang Yi <yi.zhang@huawei.com>
>>
>> Rename ext4_insert_delayed_block() to ext4_insert_delayed_blocks(),
>> pass length parameter to make it insert multi delalloc blocks once a
>> time. For non-bigalloc case, just reserve len blocks and insert delalloc
>> extent. For bigalloc case, we can ensure the middle clusters are not
>> allocated, but need to check whether the start and end clusters are
>> delayed/allocated, if not, we should reserve more space for the start
>> and/or end block(s).
>>
>> Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
> 
> Thanks for the patch. Some comments below.
> 
>> ---
>>  fs/ext4/inode.c | 51 ++++++++++++++++++++++++++++++++++---------------
>>  1 file changed, 36 insertions(+), 15 deletions(-)
>>
>> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
>> index 46c34baa848a..08e2692b7286 100644
>> --- a/fs/ext4/inode.c
>> +++ b/fs/ext4/inode.c
>> @@ -1678,24 +1678,28 @@ static int ext4_da_check_clu_allocated(struct inode *inode, ext4_lblk_t lblk,
>>  }
>>  
>>  /*
>> - * ext4_insert_delayed_block - adds a delayed block to the extents status
>> - *                             tree, incrementing the reserved cluster/block
>> - *                             count or making a pending reservation
>> - *                             where needed
>> + * ext4_insert_delayed_blocks - adds a multiple delayed blocks to the extents
>> + *                              status tree, incrementing the reserved
>> + *                              cluster/block count or making pending
>> + *                              reservations where needed
>>   *
>>   * @inode - file containing the newly added block
>> - * @lblk - logical block to be added
>> + * @lblk - start logical block to be added
>> + * @len - length of blocks to be added
>>   *
>>   * Returns 0 on success, negative error code on failure.
>>   */
>> -static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk)
>> +static int ext4_insert_delayed_blocks(struct inode *inode, ext4_lblk_t lblk,
>> +				      ext4_lblk_t len)
>>  {
>>  	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
>> -	int ret;
>> -	bool allocated = false;
>> +	int resv_clu, ret;
> 	    ^^^ this variable is in prinple the length of the extent. Thus
> it should be ext4_lblk_t type.
> 
>> +	bool lclu_allocated = false;
>> +	bool end_allocated = false;
>> +	ext4_lblk_t end = lblk + len - 1;
>>  
>>  	/*
>> -	 * If the cluster containing lblk is shared with a delayed,
>> +	 * If the cluster containing lblk or end is shared with a delayed,
>>  	 * written, or unwritten extent in a bigalloc file system, it's
>>  	 * already been accounted for and does not need to be reserved.
>>  	 * A pending reservation must be made for the cluster if it's
>> @@ -1706,21 +1710,38 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk)
>>  	 * extents status tree doesn't get a match.
>>  	 */
>>  	if (sbi->s_cluster_ratio == 1) {
>> -		ret = ext4_da_reserve_space(inode, 1);
>> +		ret = ext4_da_reserve_space(inode, len);
>>  		if (ret != 0)   /* ENOSPC */
>>  			return ret;
>>  	} else {   /* bigalloc */
>> -		ret = ext4_da_check_clu_allocated(inode, lblk, &allocated);
>> +		resv_clu = EXT4_B2C(sbi, end) - EXT4_B2C(sbi, lblk) - 1;
>> +		if (resv_clu < 0)
>> +			resv_clu = 0;
> 
> Here resv_clu going negative is strange I'm not sure the math is 100%
> correct in all the cases. I think it would be more logical as:
> 
> 		resv_clu = EXT4_B2C(sbi, end) - EXT4_B2C(sbi, lblk) + 1;
>> and then update resv_clu below as:
> 
>> +
>> +		ret = ext4_da_check_clu_allocated(inode, lblk, &lclu_allocated);
>>  		if (ret < 0)
>>  			return ret;
>> -		if (ret > 0) {
>> -			ret = ext4_da_reserve_space(inode, 1);
>> +		if (ret > 0)
>> +			resv_clu++;
> 
> Here we would do:
> 		if (ret == 0)
> 			resv_clu--;
> 
>> +
>> +		if (EXT4_B2C(sbi, lblk) != EXT4_B2C(sbi, end)) {
>> +			ret = ext4_da_check_clu_allocated(inode, end,
>> +							  &end_allocated);
>> +			if (ret < 0)
>> +				return ret;
>> +			if (ret > 0)
>> +				resv_clu++;
> 
> And similarly here:
> 			if (ret == 0)
> 				resv_clu--;

Oh, yes, it is definitely more logical than mine. Thanks for taking time
to review this series, other changelog and comments suggestions in this
series are looks fine to me, I will use them. Besides, Ritesh improved
my changelog in patch 2, I will keep your reviewed tag if you don't have
different opinions.

Thanks,
Yi.

> 
>> +		}
>> +
>> +		if (resv_clu) {
>> +			ret = ext4_da_reserve_space(inode, resv_clu);
>>  			if (ret != 0)   /* ENOSPC */
>>  				return ret;
>>  		}
>>  	}
>>  
>> -	ext4_es_insert_delayed_extent(inode, lblk, 1, allocated, false);
>> +	ext4_es_insert_delayed_extent(inode, lblk, len, lclu_allocated,
>> +				      end_allocated);
>>  	return 0;
>>  }
>>  
>> @@ -1823,7 +1844,7 @@ static int ext4_da_map_blocks(struct inode *inode, struct ext4_map_blocks *map,
>>  		}
>>  	}
>>  
>> -	retval = ext4_insert_delayed_block(inode, map->m_lblk);
>> +	retval = ext4_insert_delayed_blocks(inode, map->m_lblk, map->m_len);
>>  	up_write(&EXT4_I(inode)->i_data_sem);
>>  	if (retval)
>>  		return retval;
>> -- 
>> 2.39.2
>>
diff mbox series

Patch

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 46c34baa848a..08e2692b7286 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1678,24 +1678,28 @@  static int ext4_da_check_clu_allocated(struct inode *inode, ext4_lblk_t lblk,
 }
 
 /*
- * ext4_insert_delayed_block - adds a delayed block to the extents status
- *                             tree, incrementing the reserved cluster/block
- *                             count or making a pending reservation
- *                             where needed
+ * ext4_insert_delayed_blocks - adds a multiple delayed blocks to the extents
+ *                              status tree, incrementing the reserved
+ *                              cluster/block count or making pending
+ *                              reservations where needed
  *
  * @inode - file containing the newly added block
- * @lblk - logical block to be added
+ * @lblk - start logical block to be added
+ * @len - length of blocks to be added
  *
  * Returns 0 on success, negative error code on failure.
  */
-static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk)
+static int ext4_insert_delayed_blocks(struct inode *inode, ext4_lblk_t lblk,
+				      ext4_lblk_t len)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
-	int ret;
-	bool allocated = false;
+	int resv_clu, ret;
+	bool lclu_allocated = false;
+	bool end_allocated = false;
+	ext4_lblk_t end = lblk + len - 1;
 
 	/*
-	 * If the cluster containing lblk is shared with a delayed,
+	 * If the cluster containing lblk or end is shared with a delayed,
 	 * written, or unwritten extent in a bigalloc file system, it's
 	 * already been accounted for and does not need to be reserved.
 	 * A pending reservation must be made for the cluster if it's
@@ -1706,21 +1710,38 @@  static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk)
 	 * extents status tree doesn't get a match.
 	 */
 	if (sbi->s_cluster_ratio == 1) {
-		ret = ext4_da_reserve_space(inode, 1);
+		ret = ext4_da_reserve_space(inode, len);
 		if (ret != 0)   /* ENOSPC */
 			return ret;
 	} else {   /* bigalloc */
-		ret = ext4_da_check_clu_allocated(inode, lblk, &allocated);
+		resv_clu = EXT4_B2C(sbi, end) - EXT4_B2C(sbi, lblk) - 1;
+		if (resv_clu < 0)
+			resv_clu = 0;
+
+		ret = ext4_da_check_clu_allocated(inode, lblk, &lclu_allocated);
 		if (ret < 0)
 			return ret;
-		if (ret > 0) {
-			ret = ext4_da_reserve_space(inode, 1);
+		if (ret > 0)
+			resv_clu++;
+
+		if (EXT4_B2C(sbi, lblk) != EXT4_B2C(sbi, end)) {
+			ret = ext4_da_check_clu_allocated(inode, end,
+							  &end_allocated);
+			if (ret < 0)
+				return ret;
+			if (ret > 0)
+				resv_clu++;
+		}
+
+		if (resv_clu) {
+			ret = ext4_da_reserve_space(inode, resv_clu);
 			if (ret != 0)   /* ENOSPC */
 				return ret;
 		}
 	}
 
-	ext4_es_insert_delayed_extent(inode, lblk, 1, allocated, false);
+	ext4_es_insert_delayed_extent(inode, lblk, len, lclu_allocated,
+				      end_allocated);
 	return 0;
 }
 
@@ -1823,7 +1844,7 @@  static int ext4_da_map_blocks(struct inode *inode, struct ext4_map_blocks *map,
 		}
 	}
 
-	retval = ext4_insert_delayed_block(inode, map->m_lblk);
+	retval = ext4_insert_delayed_blocks(inode, map->m_lblk, map->m_len);
 	up_write(&EXT4_I(inode)->i_data_sem);
 	if (retval)
 		return retval;