Skip to content

Commit 3f24fcd

Browse files
committed
Merge tag 'for-linus-6.8-rc3' of git://git.kernel.org/pub/scm/linux/kernel/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() ...
2 parents 9e28c7a + ec9d669 commit 3f24fcd

File tree

11 files changed

+203
-189
lines changed

11 files changed

+203
-189
lines changed

fs/ext4/ext4.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,10 @@ struct ext4_allocation_request {
252252
#define EXT4_MAP_MAPPED BIT(BH_Mapped)
253253
#define EXT4_MAP_UNWRITTEN BIT(BH_Unwritten)
254254
#define EXT4_MAP_BOUNDARY BIT(BH_Boundary)
255+
#define EXT4_MAP_DELAYED BIT(BH_Delay)
255256
#define EXT4_MAP_FLAGS (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\
256-
EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY)
257+
EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY |\
258+
EXT4_MAP_DELAYED)
257259

258260
struct ext4_map_blocks {
259261
ext4_fsblk_t m_pblk;
@@ -2912,10 +2914,10 @@ extern const struct seq_operations ext4_mb_seq_groups_ops;
29122914
extern const struct seq_operations ext4_mb_seq_structs_summary_ops;
29132915
extern int ext4_seq_mb_stats_show(struct seq_file *seq, void *offset);
29142916
extern int ext4_mb_init(struct super_block *);
2915-
extern int ext4_mb_release(struct super_block *);
2917+
extern void ext4_mb_release(struct super_block *);
29162918
extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *,
29172919
struct ext4_allocation_request *, int *);
2918-
extern void ext4_discard_preallocations(struct inode *, unsigned int);
2920+
extern void ext4_discard_preallocations(struct inode *);
29192921
extern int __init ext4_init_mballoc(void);
29202922
extern void ext4_exit_mballoc(void);
29212923
extern ext4_group_t ext4_mb_prefetch(struct super_block *sb,

fs/ext4/extents.c

+78-46
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped)
100100
* i_rwsem. So we can safely drop the i_data_sem here.
101101
*/
102102
BUG_ON(EXT4_JOURNAL(inode) == NULL);
103-
ext4_discard_preallocations(inode, 0);
103+
ext4_discard_preallocations(inode);
104104
up_write(&EXT4_I(inode)->i_data_sem);
105105
*dropped = 1;
106106
return 0;
@@ -2229,7 +2229,7 @@ static int ext4_fill_es_cache_info(struct inode *inode,
22292229

22302230

22312231
/*
2232-
* ext4_ext_determine_hole - determine hole around given block
2232+
* ext4_ext_find_hole - find hole around given block according to the given path
22332233
* @inode: inode we lookup in
22342234
* @path: path in extent tree to @lblk
22352235
* @lblk: pointer to logical block around which we want to determine hole
@@ -2241,9 +2241,9 @@ static int ext4_fill_es_cache_info(struct inode *inode,
22412241
* The function returns the length of a hole starting at @lblk. We update @lblk
22422242
* to the beginning of the hole if we managed to find it.
22432243
*/
2244-
static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode,
2245-
struct ext4_ext_path *path,
2246-
ext4_lblk_t *lblk)
2244+
static ext4_lblk_t ext4_ext_find_hole(struct inode *inode,
2245+
struct ext4_ext_path *path,
2246+
ext4_lblk_t *lblk)
22472247
{
22482248
int depth = ext_depth(inode);
22492249
struct ext4_extent *ex;
@@ -2270,30 +2270,6 @@ static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode,
22702270
return len;
22712271
}
22722272

2273-
/*
2274-
* ext4_ext_put_gap_in_cache:
2275-
* calculate boundaries of the gap that the requested block fits into
2276-
* and cache this gap
2277-
*/
2278-
static void
2279-
ext4_ext_put_gap_in_cache(struct inode *inode, ext4_lblk_t hole_start,
2280-
ext4_lblk_t hole_len)
2281-
{
2282-
struct extent_status es;
2283-
2284-
ext4_es_find_extent_range(inode, &ext4_es_is_delayed, hole_start,
2285-
hole_start + hole_len - 1, &es);
2286-
if (es.es_len) {
2287-
/* There's delayed extent containing lblock? */
2288-
if (es.es_lblk <= hole_start)
2289-
return;
2290-
hole_len = min(es.es_lblk - hole_start, hole_len);
2291-
}
2292-
ext_debug(inode, " -> %u:%u\n", hole_start, hole_len);
2293-
ext4_es_insert_extent(inode, hole_start, hole_len, ~0,
2294-
EXTENT_STATUS_HOLE);
2295-
}
2296-
22972273
/*
22982274
* ext4_ext_rm_idx:
22992275
* removes index from the index block.
@@ -4062,6 +4038,72 @@ static int get_implied_cluster_alloc(struct super_block *sb,
40624038
return 0;
40634039
}
40644040

4041+
/*
4042+
* Determine hole length around the given logical block, first try to
4043+
* locate and expand the hole from the given @path, and then adjust it
4044+
* if it's partially or completely converted to delayed extents, insert
4045+
* it into the extent cache tree if it's indeed a hole, finally return
4046+
* the length of the determined extent.
4047+
*/
4048+
static ext4_lblk_t ext4_ext_determine_insert_hole(struct inode *inode,
4049+
struct ext4_ext_path *path,
4050+
ext4_lblk_t lblk)
4051+
{
4052+
ext4_lblk_t hole_start, len;
4053+
struct extent_status es;
4054+
4055+
hole_start = lblk;
4056+
len = ext4_ext_find_hole(inode, path, &hole_start);
4057+
again:
4058+
ext4_es_find_extent_range(inode, &ext4_es_is_delayed, hole_start,
4059+
hole_start + len - 1, &es);
4060+
if (!es.es_len)
4061+
goto insert_hole;
4062+
4063+
/*
4064+
* There's a delalloc extent in the hole, handle it if the delalloc
4065+
* extent is in front of, behind and straddle the queried range.
4066+
*/
4067+
if (lblk >= es.es_lblk + es.es_len) {
4068+
/*
4069+
* The delalloc extent is in front of the queried range,
4070+
* find again from the queried start block.
4071+
*/
4072+
len -= lblk - hole_start;
4073+
hole_start = lblk;
4074+
goto again;
4075+
} else if (in_range(lblk, es.es_lblk, es.es_len)) {
4076+
/*
4077+
* The delalloc extent containing lblk, it must have been
4078+
* added after ext4_map_blocks() checked the extent status
4079+
* tree so we are not holding i_rwsem and delalloc info is
4080+
* only stabilized by i_data_sem we are going to release
4081+
* soon. Don't modify the extent status tree and report
4082+
* extent as a hole, just adjust the length to the delalloc
4083+
* extent's after lblk.
4084+
*/
4085+
len = es.es_lblk + es.es_len - lblk;
4086+
return len;
4087+
} else {
4088+
/*
4089+
* The delalloc extent is partially or completely behind
4090+
* the queried range, update hole length until the
4091+
* beginning of the delalloc extent.
4092+
*/
4093+
len = min(es.es_lblk - hole_start, len);
4094+
}
4095+
4096+
insert_hole:
4097+
/* Put just found gap into cache to speed up subsequent requests */
4098+
ext_debug(inode, " -> %u:%u\n", hole_start, len);
4099+
ext4_es_insert_extent(inode, hole_start, len, ~0, EXTENT_STATUS_HOLE);
4100+
4101+
/* Update hole_len to reflect hole size after lblk */
4102+
if (hole_start != lblk)
4103+
len -= lblk - hole_start;
4104+
4105+
return len;
4106+
}
40654107

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

4184-
hole_start = map->m_lblk;
4185-
hole_len = ext4_ext_determine_hole(inode, path, &hole_start);
4186-
/*
4187-
* put just found gap into cache to speed up
4188-
* subsequent requests
4189-
*/
4190-
ext4_ext_put_gap_in_cache(inode, hole_start, hole_len);
4226+
len = ext4_ext_determine_insert_hole(inode, path, map->m_lblk);
41914227

4192-
/* Update hole_len to reflect hole size after map->m_lblk */
4193-
if (hole_start != map->m_lblk)
4194-
hole_len -= map->m_lblk - hole_start;
41954228
map->m_pblk = 0;
4196-
map->m_len = min_t(unsigned int, map->m_len, hole_len);
4197-
4229+
map->m_len = min_t(unsigned int, map->m_len, len);
41984230
goto out;
41994231
}
42004232

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

53595391
down_write(&EXT4_I(inode)->i_data_sem);
5360-
ext4_discard_preallocations(inode, 0);
5392+
ext4_discard_preallocations(inode);
53615393
ext4_es_remove_extent(inode, punch_start, EXT_MAX_BLOCKS - punch_start);
53625394

53635395
ret = ext4_ext_remove_space(inode, punch_start, punch_stop - 1);
53645396
if (ret) {
53655397
up_write(&EXT4_I(inode)->i_data_sem);
53665398
goto out_stop;
53675399
}
5368-
ext4_discard_preallocations(inode, 0);
5400+
ext4_discard_preallocations(inode);
53695401

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

54995531
down_write(&EXT4_I(inode)->i_data_sem);
5500-
ext4_discard_preallocations(inode, 0);
5532+
ext4_discard_preallocations(inode);
55015533

55025534
path = ext4_find_extent(inode, offset_lblk, NULL, 0);
55035535
if (IS_ERR(path)) {

fs/ext4/file.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ static int ext4_release_file(struct inode *inode, struct file *filp)
174174
(atomic_read(&inode->i_writecount) == 1) &&
175175
!EXT4_I(inode)->i_reserved_data_blocks) {
176176
down_write(&EXT4_I(inode)->i_data_sem);
177-
ext4_discard_preallocations(inode, 0);
177+
ext4_discard_preallocations(inode);
178178
up_write(&EXT4_I(inode)->i_data_sem);
179179
}
180180
if (is_dx(inode) && filp->private_data)

fs/ext4/indirect.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ static int ext4_ind_trunc_restart_fn(handle_t *handle, struct inode *inode,
714714
* i_rwsem. So we can safely drop the i_data_sem here.
715715
*/
716716
BUG_ON(EXT4_JOURNAL(inode) == NULL);
717-
ext4_discard_preallocations(inode, 0);
717+
ext4_discard_preallocations(inode);
718718
up_write(&EXT4_I(inode)->i_data_sem);
719719
*dropped = 1;
720720
return 0;

0 commit comments

Comments
 (0)