Message ID | 20240410034203.2188357-6-yi.zhang@huaweicloud.com |
---|---|
State | New |
Headers | show |
Series | ext4: support adding multi-delalloc blocks | expand |
On Wed 10-04-24 11:41:59, Zhang Yi wrote: > From: Zhang Yi <yi.zhang@huawei.com> > > 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@huawei.com> 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
On Wed 10-04-24 11:41:59, Zhang Yi wrote: > From: Zhang Yi <yi.zhang@huawei.com> I've realized I wanted to suggest some language changes for the changelog: > 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 ^^^ multiple delalloc blocks at a time. > time. For the case of bigalloc, expand the allocated parameter to ^^^^ split > lclu_allocated and end_allocated. lclu_allocated indicates the allocate ^^^ allocation > state of the cluster which containing the lblk, end_allocated represents ^^^^ which is containing ^^^^ indicates the allocation state of the extent end > the end, and the middle clusters must be unallocated. ^^^. Clusters in the middle of delay allocated extent must be unallocated. Honza > > Signed-off-by: Zhang Yi <yi.zhang@huawei.com> > --- > fs/ext4/extents_status.c | 63 ++++++++++++++++++++++++------------- > fs/ext4/extents_status.h | 5 +-- > fs/ext4/inode.c | 2 +- > include/trace/events/ext4.h | 16 +++++----- > 4 files changed, 55 insertions(+), 31 deletions(-) > > 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 > */ > -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) { > + err3 = __insert_pending(inode, end, &pr2); > + if (err3 != 0) > + goto error; > + if (pr2) { > + __free_pending(pr2); > + pr2 = NULL; > } > } > error: > diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h > index d9847a4a25db..3c8e2edee5d5 100644 > --- a/fs/ext4/extents_status.h > +++ b/fs/ext4/extents_status.h > @@ -249,8 +249,9 @@ extern void ext4_exit_pending(void); > extern void ext4_init_pending_tree(struct ext4_pending_tree *tree); > extern void ext4_remove_pending(struct inode *inode, ext4_lblk_t lblk); > extern bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk); > -extern void ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk, > - bool allocated); > +extern void ext4_es_insert_delayed_extent(struct inode *inode, ext4_lblk_t lblk, > + ext4_lblk_t len, bool lclu_allocated, > + bool end_allocated); > extern unsigned int ext4_es_delayed_clu(struct inode *inode, ext4_lblk_t lblk, > ext4_lblk_t len); > extern void ext4_clear_inode_es(struct inode *inode); > diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c > index cccc16506f5f..d37233e2ed0b 100644 > --- a/fs/ext4/inode.c > +++ b/fs/ext4/inode.c > @@ -1702,7 +1702,7 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk) > } > } > > - ext4_es_insert_delayed_block(inode, lblk, allocated); > + ext4_es_insert_delayed_extent(inode, lblk, 1, allocated, false); > return 0; > } > > diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h > index a697f4b77162..6b41ac61310f 100644 > --- a/include/trace/events/ext4.h > +++ b/include/trace/events/ext4.h > @@ -2478,11 +2478,11 @@ TRACE_EVENT(ext4_es_shrink, > __entry->scan_time, __entry->nr_skipped, __entry->retried) > ); > > -TRACE_EVENT(ext4_es_insert_delayed_block, > +TRACE_EVENT(ext4_es_insert_delayed_extent, > TP_PROTO(struct inode *inode, struct extent_status *es, > - bool allocated), > + bool lclu_allocated, bool end_allocated), > > - TP_ARGS(inode, es, allocated), > + TP_ARGS(inode, es, lclu_allocated, end_allocated), > > TP_STRUCT__entry( > __field( dev_t, dev ) > @@ -2491,7 +2491,8 @@ TRACE_EVENT(ext4_es_insert_delayed_block, > __field( ext4_lblk_t, len ) > __field( ext4_fsblk_t, pblk ) > __field( char, status ) > - __field( bool, allocated ) > + __field( bool, lclu_allocated ) > + __field( bool, end_allocated ) > ), > > TP_fast_assign( > @@ -2501,16 +2502,17 @@ TRACE_EVENT(ext4_es_insert_delayed_block, > __entry->len = es->es_len; > __entry->pblk = ext4_es_show_pblock(es); > __entry->status = ext4_es_status(es); > - __entry->allocated = allocated; > + __entry->lclu_allocated = lclu_allocated; > + __entry->end_allocated = end_allocated; > ), > > TP_printk("dev %d,%d ino %lu es [%u/%u) mapped %llu status %s " > - "allocated %d", > + "allocated %d %d", > MAJOR(__entry->dev), MINOR(__entry->dev), > (unsigned long) __entry->ino, > __entry->lblk, __entry->len, > __entry->pblk, show_extent_status(__entry->status), > - __entry->allocated) > + __entry->lclu_allocated, __entry->end_allocated) > ); > > /* fsmap traces */ > -- > 2.39.2 >
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@huawei.com> >> >> 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@huawei.com> > > 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.
On Mon 29-04-24 20:09:46, Zhang Yi wrote: > 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@huawei.com> > >> > >> 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@huawei.com> ... > >> @@ -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? Yes, that is a good solution as well! Honza
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 */ -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) { + err3 = __insert_pending(inode, end, &pr2); + if (err3 != 0) + goto error; + if (pr2) { + __free_pending(pr2); + pr2 = NULL; } } error: diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h index d9847a4a25db..3c8e2edee5d5 100644 --- a/fs/ext4/extents_status.h +++ b/fs/ext4/extents_status.h @@ -249,8 +249,9 @@ extern void ext4_exit_pending(void); extern void ext4_init_pending_tree(struct ext4_pending_tree *tree); extern void ext4_remove_pending(struct inode *inode, ext4_lblk_t lblk); extern bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk); -extern void ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk, - bool allocated); +extern void ext4_es_insert_delayed_extent(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t len, bool lclu_allocated, + bool end_allocated); extern unsigned int ext4_es_delayed_clu(struct inode *inode, ext4_lblk_t lblk, ext4_lblk_t len); extern void ext4_clear_inode_es(struct inode *inode); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index cccc16506f5f..d37233e2ed0b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1702,7 +1702,7 @@ static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk) } } - ext4_es_insert_delayed_block(inode, lblk, allocated); + ext4_es_insert_delayed_extent(inode, lblk, 1, allocated, false); return 0; } diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index a697f4b77162..6b41ac61310f 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -2478,11 +2478,11 @@ TRACE_EVENT(ext4_es_shrink, __entry->scan_time, __entry->nr_skipped, __entry->retried) ); -TRACE_EVENT(ext4_es_insert_delayed_block, +TRACE_EVENT(ext4_es_insert_delayed_extent, TP_PROTO(struct inode *inode, struct extent_status *es, - bool allocated), + bool lclu_allocated, bool end_allocated), - TP_ARGS(inode, es, allocated), + TP_ARGS(inode, es, lclu_allocated, end_allocated), TP_STRUCT__entry( __field( dev_t, dev ) @@ -2491,7 +2491,8 @@ TRACE_EVENT(ext4_es_insert_delayed_block, __field( ext4_lblk_t, len ) __field( ext4_fsblk_t, pblk ) __field( char, status ) - __field( bool, allocated ) + __field( bool, lclu_allocated ) + __field( bool, end_allocated ) ), TP_fast_assign( @@ -2501,16 +2502,17 @@ TRACE_EVENT(ext4_es_insert_delayed_block, __entry->len = es->es_len; __entry->pblk = ext4_es_show_pblock(es); __entry->status = ext4_es_status(es); - __entry->allocated = allocated; + __entry->lclu_allocated = lclu_allocated; + __entry->end_allocated = end_allocated; ), TP_printk("dev %d,%d ino %lu es [%u/%u) mapped %llu status %s " - "allocated %d", + "allocated %d %d", MAJOR(__entry->dev), MINOR(__entry->dev), (unsigned long) __entry->ino, __entry->lblk, __entry->len, __entry->pblk, show_extent_status(__entry->status), - __entry->allocated) + __entry->lclu_allocated, __entry->end_allocated) ); /* fsmap traces */