Skip to content

Commit

Permalink
Merge tag 'for-linus-6.8-rc3' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/tytso/ext4

Pull ext4 fixes from Ted Ts'o:
 "Miscellaneous bug fixes and cleanups in ext4's multi-block allocator
  and extent handling code"

* tag 'for-linus-6.8-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (23 commits)
  ext4: make ext4_set_iomap() recognize IOMAP_DELALLOC map type
  ext4: make ext4_map_blocks() distinguish delalloc only extent
  ext4: add a hole extent entry in cache after punch
  ext4: correct the hole length returned by ext4_map_blocks()
  ext4: convert to exclusive lock while inserting delalloc extents
  ext4: refactor ext4_da_map_blocks()
  ext4: remove 'needed' in trace_ext4_discard_preallocations
  ext4: remove unnecessary parameter "needed" in ext4_discard_preallocations
  ext4: remove unused return value of ext4_mb_release_group_pa
  ext4: remove unused return value of ext4_mb_release_inode_pa
  ext4: remove unused return value of ext4_mb_release
  ext4: remove unused ext4_allocation_context::ac_groups_considered
  ext4: remove unneeded return value of ext4_mb_release_context
  ext4: remove unused parameter ngroup in ext4_mb_choose_next_group_*()
  ext4: remove unused return value of __mb_check_buddy
  ext4: mark the group block bitmap as corrupted before reporting an error
  ext4: avoid allocating blocks from corrupted group in ext4_mb_find_by_goal()
  ext4: avoid allocating blocks from corrupted group in ext4_mb_try_best_found()
  ext4: avoid dividing by 0 in mb_update_avg_fragment_size() when block bitmap corrupt
  ext4: avoid bb_free and bb_fragments inconsistency in mb_free_blocks()
  ...
  • Loading branch information
Linus Torvalds committed Feb 4, 2024
2 parents 9e28c7a + ec9d669 commit 3f24fcd
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 189 deletions.
8 changes: 5 additions & 3 deletions fs/ext4/ext4.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,10 @@ struct ext4_allocation_request {
#define EXT4_MAP_MAPPED BIT(BH_Mapped)
#define EXT4_MAP_UNWRITTEN BIT(BH_Unwritten)
#define EXT4_MAP_BOUNDARY BIT(BH_Boundary)
#define EXT4_MAP_DELAYED BIT(BH_Delay)
#define EXT4_MAP_FLAGS (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\
EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY)
EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY |\
EXT4_MAP_DELAYED)

struct ext4_map_blocks {
ext4_fsblk_t m_pblk;
Expand Down Expand Up @@ -2912,10 +2914,10 @@ extern const struct seq_operations ext4_mb_seq_groups_ops;
extern const struct seq_operations ext4_mb_seq_structs_summary_ops;
extern int ext4_seq_mb_stats_show(struct seq_file *seq, void *offset);
extern int ext4_mb_init(struct super_block *);
extern int ext4_mb_release(struct super_block *);
extern void ext4_mb_release(struct super_block *);
extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *,
struct ext4_allocation_request *, int *);
extern void ext4_discard_preallocations(struct inode *, unsigned int);
extern void ext4_discard_preallocations(struct inode *);
extern int __init ext4_init_mballoc(void);
extern void ext4_exit_mballoc(void);
extern ext4_group_t ext4_mb_prefetch(struct super_block *sb,
Expand Down
124 changes: 78 additions & 46 deletions fs/ext4/extents.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
* i_rwsem. So we can safely drop the i_data_sem here.
*/
BUG_ON(EXT4_JOURNAL(inode) == NULL);
ext4_discard_preallocations(inode, 0);
ext4_discard_preallocations(inode);
up_write(&EXT4_I(inode)->i_data_sem);
*dropped = 1;
return 0;
Expand Down Expand Up @@ -2229,7 +2229,7 @@ static int ext4_fill_es_cache_info(struct inode *inode,


/*
* ext4_ext_determine_hole - determine hole around given block
* ext4_ext_find_hole - find hole around given block according to the given path
* @inode: inode we lookup in
* @path: path in extent tree to @lblk
* @lblk: pointer to logical block around which we want to determine hole
Expand All @@ -2241,9 +2241,9 @@ static int ext4_fill_es_cache_info(struct inode *inode,
* The function returns the length of a hole starting at @lblk. We update @lblk
* to the beginning of the hole if we managed to find it.
*/
static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode,
struct ext4_ext_path *path,
ext4_lblk_t *lblk)
static ext4_lblk_t ext4_ext_find_hole(struct inode *inode,
struct ext4_ext_path *path,
ext4_lblk_t *lblk)
{
int depth = ext_depth(inode);
struct ext4_extent *ex;
Expand All @@ -2270,30 +2270,6 @@ static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode,
return len;
}

/*
* ext4_ext_put_gap_in_cache:
* calculate boundaries of the gap that the requested block fits into
* and cache this gap
*/
static void
ext4_ext_put_gap_in_cache(struct inode *inode, ext4_lblk_t hole_start,
ext4_lblk_t hole_len)
{
struct extent_status es;

ext4_es_find_extent_range(inode, &ext4_es_is_delayed, hole_start,
hole_start + hole_len - 1, &es);
if (es.es_len) {
/* There's delayed extent containing lblock? */
if (es.es_lblk <= hole_start)
return;
hole_len = min(es.es_lblk - hole_start, hole_len);
}
ext_debug(inode, " -> %u:%u\n", hole_start, hole_len);
ext4_es_insert_extent(inode, hole_start, hole_len, ~0,
EXTENT_STATUS_HOLE);
}

/*
* ext4_ext_rm_idx:
* removes index from the index block.
Expand Down Expand Up @@ -4062,6 +4038,72 @@ static int get_implied_cluster_alloc(struct super_block *sb,
return 0;
}

/*
* Determine hole length around the given logical block, first try to
* locate and expand the hole from the given @path, and then adjust it
* if it's partially or completely converted to delayed extents, insert
* it into the extent cache tree if it's indeed a hole, finally return
* the length of the determined extent.
*/
static ext4_lblk_t ext4_ext_determine_insert_hole(struct inode *inode,
struct ext4_ext_path *path,
ext4_lblk_t lblk)
{
ext4_lblk_t hole_start, len;
struct extent_status es;

hole_start = lblk;
len = ext4_ext_find_hole(inode, path, &hole_start);
again:
ext4_es_find_extent_range(inode, &ext4_es_is_delayed, hole_start,
hole_start + len - 1, &es);
if (!es.es_len)
goto insert_hole;

/*
* There's a delalloc extent in the hole, handle it if the delalloc
* extent is in front of, behind and straddle the queried range.
*/
if (lblk >= es.es_lblk + es.es_len) {
/*
* The delalloc extent is in front of the queried range,
* find again from the queried start block.
*/
len -= lblk - hole_start;
hole_start = lblk;
goto again;
} else if (in_range(lblk, es.es_lblk, es.es_len)) {
/*
* The delalloc extent containing lblk, it must have been
* added after ext4_map_blocks() checked the extent status
* tree so we are not holding i_rwsem and delalloc info is
* only stabilized by i_data_sem we are going to release
* soon. Don't modify the extent status tree and report
* extent as a hole, just adjust the length to the delalloc
* extent's after lblk.
*/
len = es.es_lblk + es.es_len - lblk;
return len;
} else {
/*
* The delalloc extent is partially or completely behind
* the queried range, update hole length until the
* beginning of the delalloc extent.
*/
len = min(es.es_lblk - hole_start, len);
}

insert_hole:
/* Put just found gap into cache to speed up subsequent requests */
ext_debug(inode, " -> %u:%u\n", hole_start, len);
ext4_es_insert_extent(inode, hole_start, len, ~0, EXTENT_STATUS_HOLE);

/* Update hole_len to reflect hole size after lblk */
if (hole_start != lblk)
len -= lblk - hole_start;

return len;
}

/*
* Block allocation/map/preallocation routine for extents based files
Expand Down Expand Up @@ -4179,22 +4221,12 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
* we couldn't try to create block if create flag is zero
*/
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
ext4_lblk_t hole_start, hole_len;
ext4_lblk_t len;

hole_start = map->m_lblk;
hole_len = ext4_ext_determine_hole(inode, path, &hole_start);
/*
* put just found gap into cache to speed up
* subsequent requests
*/
ext4_ext_put_gap_in_cache(inode, hole_start, hole_len);
len = ext4_ext_determine_insert_hole(inode, path, map->m_lblk);

/* Update hole_len to reflect hole size after map->m_lblk */
if (hole_start != map->m_lblk)
hole_len -= map->m_lblk - hole_start;
map->m_pblk = 0;
map->m_len = min_t(unsigned int, map->m_len, hole_len);

map->m_len = min_t(unsigned int, map->m_len, len);
goto out;
}

Expand Down Expand Up @@ -4313,7 +4345,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
* not a good idea to call discard here directly,
* but otherwise we'd need to call it every free().
*/
ext4_discard_preallocations(inode, 0);
ext4_discard_preallocations(inode);
if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
fb_flags = EXT4_FREE_BLOCKS_NO_QUOT_UPDATE;
ext4_free_blocks(handle, inode, NULL, newblock,
Expand Down Expand Up @@ -5357,15 +5389,15 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)
ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE, handle);

down_write(&EXT4_I(inode)->i_data_sem);
ext4_discard_preallocations(inode, 0);
ext4_discard_preallocations(inode);
ext4_es_remove_extent(inode, punch_start, EXT_MAX_BLOCKS - punch_start);

ret = ext4_ext_remove_space(inode, punch_start, punch_stop - 1);
if (ret) {
up_write(&EXT4_I(inode)->i_data_sem);
goto out_stop;
}
ext4_discard_preallocations(inode, 0);
ext4_discard_preallocations(inode);

ret = ext4_ext_shift_extents(inode, handle, punch_stop,
punch_stop - punch_start, SHIFT_LEFT);
Expand Down Expand Up @@ -5497,7 +5529,7 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
goto out_stop;

down_write(&EXT4_I(inode)->i_data_sem);
ext4_discard_preallocations(inode, 0);
ext4_discard_preallocations(inode);

path = ext4_find_extent(inode, offset_lblk, NULL, 0);
if (IS_ERR(path)) {
Expand Down
2 changes: 1 addition & 1 deletion fs/ext4/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ static int ext4_release_file(struct inode *inode, struct file *filp)
(atomic_read(&inode->i_writecount) == 1) &&
!EXT4_I(inode)->i_reserved_data_blocks) {
down_write(&EXT4_I(inode)->i_data_sem);
ext4_discard_preallocations(inode, 0);
ext4_discard_preallocations(inode);
up_write(&EXT4_I(inode)->i_data_sem);
}
if (is_dx(inode) && filp->private_data)
Expand Down
2 changes: 1 addition & 1 deletion fs/ext4/indirect.c
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ static int ext4_ind_trunc_restart_fn(handle_t *handle, struct inode *inode,
* i_rwsem. So we can safely drop the i_data_sem here.
*/
BUG_ON(EXT4_JOURNAL(inode) == NULL);
ext4_discard_preallocations(inode, 0);
ext4_discard_preallocations(inode);
up_write(&EXT4_I(inode)->i_data_sem);
*dropped = 1;
return 0;
Expand Down
Loading

0 comments on commit 3f24fcd

Please sign in to comment.