On 2024/4/29 17:16, Jan Kara wrote: > On Wed 10-04-24 11:41:59, Zhang Yi wrote: >> From: Zhang Yi <yi.zhang@xxxxxxxxxx> >> >> Rename ext4_es_insert_delayed_block() to ext4_es_insert_delayed_extent() >> and pass length parameter to make it insert multi delalloc blocks once a >> time. For the case of bigalloc, expand the allocated parameter to >> lclu_allocated and end_allocated. lclu_allocated indicates the allocate >> state of the cluster which containing the lblk, end_allocated represents >> the end, and the middle clusters must be unallocated. >> >> Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx> > > Looks mostly good, just one comment below: > >> diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c >> index 4a00e2f019d9..2320b0d71001 100644 >> --- a/fs/ext4/extents_status.c >> +++ b/fs/ext4/extents_status.c >> @@ -2052,34 +2052,42 @@ bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk) >> } >> >> /* >> - * ext4_es_insert_delayed_block - adds a delayed block to the extents status >> - * tree, adding a pending reservation where >> - * needed >> + * ext4_es_insert_delayed_extent - adds some delayed blocks to the extents >> + * status tree, adding a pending reservation >> + * where needed >> * >> * @inode - file containing the newly added block >> - * @lblk - logical block to be added >> - * @allocated - indicates whether a physical cluster has been allocated for >> - * the logical cluster that contains the block >> + * @lblk - start logical block to be added >> + * @len - length of blocks to be added >> + * @lclu_allocated/end_allocated - indicates whether a physical cluster has >> + * been allocated for the logical cluster >> + * that contains the block > ^^^^ "start / end > block" to make it clearer... > >> -void ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk, >> - bool allocated) >> +void ext4_es_insert_delayed_extent(struct inode *inode, ext4_lblk_t lblk, >> + ext4_lblk_t len, bool lclu_allocated, >> + bool end_allocated) >> { >> struct extent_status newes; >> + ext4_lblk_t end = lblk + len - 1; >> int err1 = 0, err2 = 0, err3 = 0; >> struct extent_status *es1 = NULL; >> struct extent_status *es2 = NULL; >> - struct pending_reservation *pr = NULL; >> + struct pending_reservation *pr1 = NULL; >> + struct pending_reservation *pr2 = NULL; >> >> if (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY) >> return; >> >> - es_debug("add [%u/1) delayed to extent status tree of inode %lu\n", >> - lblk, inode->i_ino); >> + es_debug("add [%u/%u) delayed to extent status tree of inode %lu\n", >> + lblk, len, inode->i_ino); >> + if (!len) >> + return; >> >> newes.es_lblk = lblk; >> - newes.es_len = 1; >> + newes.es_len = len; >> ext4_es_store_pblock_status(&newes, ~0, EXTENT_STATUS_DELAYED); >> - trace_ext4_es_insert_delayed_block(inode, &newes, allocated); >> + trace_ext4_es_insert_delayed_extent(inode, &newes, lclu_allocated, >> + end_allocated); >> >> ext4_es_insert_extent_check(inode, &newes); >> >> @@ -2088,11 +2096,15 @@ void ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk, >> es1 = __es_alloc_extent(true); >> if ((err1 || err2) && !es2) >> es2 = __es_alloc_extent(true); >> - if ((err1 || err2 || err3) && allocated && !pr) >> - pr = __alloc_pending(true); >> + if (err1 || err2 || err3) { >> + if (lclu_allocated && !pr1) >> + pr1 = __alloc_pending(true); >> + if (end_allocated && !pr2) >> + pr2 = __alloc_pending(true); >> + } >> write_lock(&EXT4_I(inode)->i_es_lock); >> >> - err1 = __es_remove_extent(inode, lblk, lblk, NULL, es1); >> + err1 = __es_remove_extent(inode, lblk, end, NULL, es1); >> if (err1 != 0) >> goto error; >> /* Free preallocated extent if it didn't get used. */ >> @@ -2112,13 +2124,22 @@ void ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk, >> es2 = NULL; >> } >> >> - if (allocated) { >> - err3 = __insert_pending(inode, lblk, &pr); >> + if (lclu_allocated) { >> + err3 = __insert_pending(inode, lblk, &pr1); >> if (err3 != 0) >> goto error; >> - if (pr) { >> - __free_pending(pr); >> - pr = NULL; >> + if (pr1) { >> + __free_pending(pr1); >> + pr1 = NULL; >> + } >> + } >> + if (end_allocated) { > > So there's one unclear thing here: What if 'lblk' and 'end' are in the same > cluster? We don't want two pending reservation structures for the cluster. > __insert_pending() already handles this gracefully but perhaps we don't > need to allocate 'pr2' in that case and call __insert_pending() at all? I > think it could be easily handled by something like: > > if (EXT4_B2C(lblk) == EXT4_B2C(end)) > end_allocated = false; > > at appropriate place in ext4_es_insert_delayed_extent(). > I've done the check "EXT4_B2C(lblk) == EXT4_B2C(end)" in the caller ext4_insert_delayed_blocks() in patch 8, becasue there is no need to check the allocation state if they are in the same cluster, so it could make sure that end_allocated is always false when 'lblk' and 'end' are in the same cluster. So I suppose check and set it here again maybe redundant, how about add a wanging here in ext4_es_insert_delayed_extent(), like: WARN_ON_ONCE((EXT4_B2C(sbi, lblk) == EXT4_B2C(sbi, end)) && end_allocated); and modify the 'lclu_allocated/end_allocated' parameter comments, note that end_allocated should always be set to false if the extent is in one cluster. Is it fine? Thanks, Yi.