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(). Otherwise the patch looks good. Honza -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR