Commit 3f24fcda authored by Linus Torvalds's avatar Linus Torvalds

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()
  ...
parents 9e28c7a2 ec9d669e
...@@ -252,8 +252,10 @@ struct ext4_allocation_request { ...@@ -252,8 +252,10 @@ struct ext4_allocation_request {
#define EXT4_MAP_MAPPED BIT(BH_Mapped) #define EXT4_MAP_MAPPED BIT(BH_Mapped)
#define EXT4_MAP_UNWRITTEN BIT(BH_Unwritten) #define EXT4_MAP_UNWRITTEN BIT(BH_Unwritten)
#define EXT4_MAP_BOUNDARY BIT(BH_Boundary) #define EXT4_MAP_BOUNDARY BIT(BH_Boundary)
#define EXT4_MAP_DELAYED BIT(BH_Delay)
#define EXT4_MAP_FLAGS (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\ #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 { struct ext4_map_blocks {
ext4_fsblk_t m_pblk; ext4_fsblk_t m_pblk;
...@@ -2912,10 +2914,10 @@ extern const struct seq_operations ext4_mb_seq_groups_ops; ...@@ -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 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_seq_mb_stats_show(struct seq_file *seq, void *offset);
extern int ext4_mb_init(struct super_block *); 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 *, extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *,
struct ext4_allocation_request *, int *); 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 int __init ext4_init_mballoc(void);
extern void ext4_exit_mballoc(void); extern void ext4_exit_mballoc(void);
extern ext4_group_t ext4_mb_prefetch(struct super_block *sb, extern ext4_group_t ext4_mb_prefetch(struct super_block *sb,
......
...@@ -100,7 +100,7 @@ static int ext4_ext_trunc_restart_fn(struct inode *inode, int *dropped) ...@@ -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. * i_rwsem. So we can safely drop the i_data_sem here.
*/ */
BUG_ON(EXT4_JOURNAL(inode) == NULL); BUG_ON(EXT4_JOURNAL(inode) == NULL);
ext4_discard_preallocations(inode, 0); ext4_discard_preallocations(inode);
up_write(&EXT4_I(inode)->i_data_sem); up_write(&EXT4_I(inode)->i_data_sem);
*dropped = 1; *dropped = 1;
return 0; return 0;
...@@ -2229,7 +2229,7 @@ static int ext4_fill_es_cache_info(struct inode *inode, ...@@ -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 * @inode: inode we lookup in
* @path: path in extent tree to @lblk * @path: path in extent tree to @lblk
* @lblk: pointer to logical block around which we want to determine hole * @lblk: pointer to logical block around which we want to determine hole
...@@ -2241,7 +2241,7 @@ static int ext4_fill_es_cache_info(struct inode *inode, ...@@ -2241,7 +2241,7 @@ static int ext4_fill_es_cache_info(struct inode *inode,
* The function returns the length of a hole starting at @lblk. We update @lblk * 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. * to the beginning of the hole if we managed to find it.
*/ */
static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode, static ext4_lblk_t ext4_ext_find_hole(struct inode *inode,
struct ext4_ext_path *path, struct ext4_ext_path *path,
ext4_lblk_t *lblk) ext4_lblk_t *lblk)
{ {
...@@ -2270,30 +2270,6 @@ static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode, ...@@ -2270,30 +2270,6 @@ static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode,
return len; 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: * ext4_ext_rm_idx:
* removes index from the index block. * removes index from the index block.
...@@ -4062,6 +4038,72 @@ static int get_implied_cluster_alloc(struct super_block *sb, ...@@ -4062,6 +4038,72 @@ static int get_implied_cluster_alloc(struct super_block *sb,
return 0; 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 * Block allocation/map/preallocation routine for extents based files
...@@ -4179,22 +4221,12 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, ...@@ -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 * we couldn't try to create block if create flag is zero
*/ */
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
ext4_lblk_t hole_start, hole_len; ext4_lblk_t len;
hole_start = map->m_lblk; len = ext4_ext_determine_insert_hole(inode, path, 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);
/* 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_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; goto out;
} }
...@@ -4313,7 +4345,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, ...@@ -4313,7 +4345,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
* not a good idea to call discard here directly, * not a good idea to call discard here directly,
* but otherwise we'd need to call it every free(). * 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) if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)
fb_flags = EXT4_FREE_BLOCKS_NO_QUOT_UPDATE; fb_flags = EXT4_FREE_BLOCKS_NO_QUOT_UPDATE;
ext4_free_blocks(handle, inode, NULL, newblock, ext4_free_blocks(handle, inode, NULL, newblock,
...@@ -5357,7 +5389,7 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len) ...@@ -5357,7 +5389,7 @@ 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); ext4_fc_mark_ineligible(sb, EXT4_FC_REASON_FALLOC_RANGE, handle);
down_write(&EXT4_I(inode)->i_data_sem); 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); ext4_es_remove_extent(inode, punch_start, EXT_MAX_BLOCKS - punch_start);
ret = ext4_ext_remove_space(inode, punch_start, punch_stop - 1); ret = ext4_ext_remove_space(inode, punch_start, punch_stop - 1);
...@@ -5365,7 +5397,7 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len) ...@@ -5365,7 +5397,7 @@ static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)
up_write(&EXT4_I(inode)->i_data_sem); up_write(&EXT4_I(inode)->i_data_sem);
goto out_stop; goto out_stop;
} }
ext4_discard_preallocations(inode, 0); ext4_discard_preallocations(inode);
ret = ext4_ext_shift_extents(inode, handle, punch_stop, ret = ext4_ext_shift_extents(inode, handle, punch_stop,
punch_stop - punch_start, SHIFT_LEFT); punch_stop - punch_start, SHIFT_LEFT);
...@@ -5497,7 +5529,7 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len) ...@@ -5497,7 +5529,7 @@ static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
goto out_stop; goto out_stop;
down_write(&EXT4_I(inode)->i_data_sem); 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); path = ext4_find_extent(inode, offset_lblk, NULL, 0);
if (IS_ERR(path)) { if (IS_ERR(path)) {
......
...@@ -174,7 +174,7 @@ static int ext4_release_file(struct inode *inode, struct file *filp) ...@@ -174,7 +174,7 @@ static int ext4_release_file(struct inode *inode, struct file *filp)
(atomic_read(&inode->i_writecount) == 1) && (atomic_read(&inode->i_writecount) == 1) &&
!EXT4_I(inode)->i_reserved_data_blocks) { !EXT4_I(inode)->i_reserved_data_blocks) {
down_write(&EXT4_I(inode)->i_data_sem); 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); up_write(&EXT4_I(inode)->i_data_sem);
} }
if (is_dx(inode) && filp->private_data) if (is_dx(inode) && filp->private_data)
......
...@@ -714,7 +714,7 @@ static int ext4_ind_trunc_restart_fn(handle_t *handle, struct inode *inode, ...@@ -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. * i_rwsem. So we can safely drop the i_data_sem here.
*/ */
BUG_ON(EXT4_JOURNAL(inode) == NULL); BUG_ON(EXT4_JOURNAL(inode) == NULL);
ext4_discard_preallocations(inode, 0); ext4_discard_preallocations(inode);
up_write(&EXT4_I(inode)->i_data_sem); up_write(&EXT4_I(inode)->i_data_sem);
*dropped = 1; *dropped = 1;
return 0; return 0;
......
...@@ -371,7 +371,7 @@ void ext4_da_update_reserve_space(struct inode *inode, ...@@ -371,7 +371,7 @@ void ext4_da_update_reserve_space(struct inode *inode,
*/ */
if ((ei->i_reserved_data_blocks == 0) && if ((ei->i_reserved_data_blocks == 0) &&
!inode_is_open_for_write(inode)) !inode_is_open_for_write(inode))
ext4_discard_preallocations(inode, 0); ext4_discard_preallocations(inode);
} }
static int __check_block_validity(struct inode *inode, const char *func, static int __check_block_validity(struct inode *inode, const char *func,
...@@ -515,6 +515,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, ...@@ -515,6 +515,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
map->m_len = retval; map->m_len = retval;
} else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) { } else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) {
map->m_pblk = 0; map->m_pblk = 0;
map->m_flags |= ext4_es_is_delayed(&es) ?
EXT4_MAP_DELAYED : 0;
retval = es.es_len - (map->m_lblk - es.es_lblk); retval = es.es_len - (map->m_lblk - es.es_lblk);
if (retval > map->m_len) if (retval > map->m_len)
retval = map->m_len; retval = map->m_len;
...@@ -1703,11 +1705,8 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, ...@@ -1703,11 +1705,8 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
/* Lookup extent status tree firstly */ /* Lookup extent status tree firstly */
if (ext4_es_lookup_extent(inode, iblock, NULL, &es)) { if (ext4_es_lookup_extent(inode, iblock, NULL, &es)) {
if (ext4_es_is_hole(&es)) { if (ext4_es_is_hole(&es))
retval = 0;
down_read(&EXT4_I(inode)->i_data_sem);
goto add_delayed; goto add_delayed;
}
/* /*
* Delayed extent could be allocated by fallocate. * Delayed extent could be allocated by fallocate.
...@@ -1749,26 +1748,11 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, ...@@ -1749,26 +1748,11 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
retval = ext4_ext_map_blocks(NULL, inode, map, 0); retval = ext4_ext_map_blocks(NULL, inode, map, 0);
else else
retval = ext4_ind_map_blocks(NULL, inode, map, 0); retval = ext4_ind_map_blocks(NULL, inode, map, 0);
if (retval < 0) {
add_delayed: up_read(&EXT4_I(inode)->i_data_sem);
if (retval == 0) { return retval;
int ret;
/*
* XXX: __block_prepare_write() unmaps passed block,
* is it OK?
*/
ret = ext4_insert_delayed_block(inode, map->m_lblk);
if (ret != 0) {
retval = ret;
goto out_unlock;
} }
if (retval > 0) {
map_bh(bh, inode->i_sb, invalid_block);
set_buffer_new(bh);
set_buffer_delay(bh);
} else if (retval > 0) {
unsigned int status; unsigned int status;
if (unlikely(retval != map->m_len)) { if (unlikely(retval != map->m_len)) {
...@@ -1783,11 +1767,21 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, ...@@ -1783,11 +1767,21 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
ext4_es_insert_extent(inode, map->m_lblk, map->m_len, ext4_es_insert_extent(inode, map->m_lblk, map->m_len,
map->m_pblk, status); map->m_pblk, status);
up_read(&EXT4_I(inode)->i_data_sem);
return retval;
} }
up_read(&EXT4_I(inode)->i_data_sem);
out_unlock: add_delayed:
up_read((&EXT4_I(inode)->i_data_sem)); down_write(&EXT4_I(inode)->i_data_sem);
retval = ext4_insert_delayed_block(inode, map->m_lblk);
up_write(&EXT4_I(inode)->i_data_sem);
if (retval)
return retval;
map_bh(bh, inode->i_sb, invalid_block);
set_buffer_new(bh);
set_buffer_delay(bh);
return retval; return retval;
} }
...@@ -3268,6 +3262,9 @@ static void ext4_set_iomap(struct inode *inode, struct iomap *iomap, ...@@ -3268,6 +3262,9 @@ static void ext4_set_iomap(struct inode *inode, struct iomap *iomap,
iomap->addr = (u64) map->m_pblk << blkbits; iomap->addr = (u64) map->m_pblk << blkbits;
if (flags & IOMAP_DAX) if (flags & IOMAP_DAX)
iomap->addr += EXT4_SB(inode->i_sb)->s_dax_part_off; iomap->addr += EXT4_SB(inode->i_sb)->s_dax_part_off;
} else if (map->m_flags & EXT4_MAP_DELAYED) {
iomap->type = IOMAP_DELALLOC;
iomap->addr = IOMAP_NULL_ADDR;
} else { } else {
iomap->type = IOMAP_HOLE; iomap->type = IOMAP_HOLE;
iomap->addr = IOMAP_NULL_ADDR; iomap->addr = IOMAP_NULL_ADDR;
...@@ -3430,35 +3427,11 @@ const struct iomap_ops ext4_iomap_overwrite_ops = { ...@@ -3430,35 +3427,11 @@ const struct iomap_ops ext4_iomap_overwrite_ops = {
.iomap_end = ext4_iomap_end, .iomap_end = ext4_iomap_end,
}; };
static bool ext4_iomap_is_delalloc(struct inode *inode,
struct ext4_map_blocks *map)
{
struct extent_status es;
ext4_lblk_t offset = 0, end = map->m_lblk + map->m_len - 1;
ext4_es_find_extent_range(inode, &ext4_es_is_delayed,
map->m_lblk, end, &es);
if (!es.es_len || es.es_lblk > end)
return false;
if (es.es_lblk > map->m_lblk) {
map->m_len = es.es_lblk - map->m_lblk;
return false;
}
offset = map->m_lblk - es.es_lblk;
map->m_len = es.es_len - offset;
return true;
}
static int ext4_iomap_begin_report(struct inode *inode, loff_t offset, static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,
loff_t length, unsigned int flags, loff_t length, unsigned int flags,
struct iomap *iomap, struct iomap *srcmap) struct iomap *iomap, struct iomap *srcmap)
{ {
int ret; int ret;
bool delalloc = false;
struct ext4_map_blocks map; struct ext4_map_blocks map;
u8 blkbits = inode->i_blkbits; u8 blkbits = inode->i_blkbits;
...@@ -3499,13 +3472,8 @@ static int ext4_iomap_begin_report(struct inode *inode, loff_t offset, ...@@ -3499,13 +3472,8 @@ static int ext4_iomap_begin_report(struct inode *inode, loff_t offset,
ret = ext4_map_blocks(NULL, inode, &map, 0); ret = ext4_map_blocks(NULL, inode, &map, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (ret == 0)
delalloc = ext4_iomap_is_delalloc(inode, &map);
set_iomap: set_iomap:
ext4_set_iomap(inode, iomap, &map, offset, length, flags); ext4_set_iomap(inode, iomap, &map, offset, length, flags);
if (delalloc && iomap->type == IOMAP_HOLE)
iomap->type = IOMAP_DELALLOC;
return 0; return 0;
} }
...@@ -4015,12 +3983,12 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) ...@@ -4015,12 +3983,12 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
/* If there are blocks to remove, do it */ /* If there are blocks to remove, do it */
if (stop_block > first_block) { if (stop_block > first_block) {
ext4_lblk_t hole_len = stop_block - first_block;
down_write(&EXT4_I(inode)->i_data_sem); down_write(&EXT4_I(inode)->i_data_sem);
ext4_discard_preallocations(inode, 0); ext4_discard_preallocations(inode);
ext4_es_remove_extent(inode, first_block, ext4_es_remove_extent(inode, first_block, hole_len);
stop_block - first_block);
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
ret = ext4_ext_remove_space(inode, first_block, ret = ext4_ext_remove_space(inode, first_block,
...@@ -4029,6 +3997,8 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) ...@@ -4029,6 +3997,8 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
ret = ext4_ind_remove_space(handle, inode, first_block, ret = ext4_ind_remove_space(handle, inode, first_block,
stop_block); stop_block);
ext4_es_insert_extent(inode, first_block, hole_len, ~0,
EXTENT_STATUS_HOLE);
up_write(&EXT4_I(inode)->i_data_sem); up_write(&EXT4_I(inode)->i_data_sem);
} }
ext4_fc_track_range(handle, inode, first_block, stop_block); ext4_fc_track_range(handle, inode, first_block, stop_block);
...@@ -4170,7 +4140,7 @@ int ext4_truncate(struct inode *inode) ...@@ -4170,7 +4140,7 @@ int ext4_truncate(struct inode *inode)
down_write(&EXT4_I(inode)->i_data_sem); down_write(&EXT4_I(inode)->i_data_sem);
ext4_discard_preallocations(inode, 0); ext4_discard_preallocations(inode);
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
err = ext4_ext_truncate(handle, inode); err = ext4_ext_truncate(handle, inode);
......
...@@ -467,7 +467,7 @@ static long swap_inode_boot_loader(struct super_block *sb, ...@@ -467,7 +467,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
ext4_reset_inode_seed(inode); ext4_reset_inode_seed(inode);
ext4_reset_inode_seed(inode_bl); ext4_reset_inode_seed(inode_bl);
ext4_discard_preallocations(inode, 0); ext4_discard_preallocations(inode);
err = ext4_mark_inode_dirty(handle, inode); err = ext4_mark_inode_dirty(handle, inode);
if (err < 0) { if (err < 0) {
......
This diff is collapsed.
...@@ -192,7 +192,6 @@ struct ext4_allocation_context { ...@@ -192,7 +192,6 @@ struct ext4_allocation_context {
*/ */
ext4_grpblk_t ac_orig_goal_len; ext4_grpblk_t ac_orig_goal_len;
__u32 ac_groups_considered;
__u32 ac_flags; /* allocation hints */ __u32 ac_flags; /* allocation hints */
__u16 ac_groups_scanned; __u16 ac_groups_scanned;
__u16 ac_groups_linear_remaining; __u16 ac_groups_linear_remaining;
......
...@@ -618,6 +618,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk, ...@@ -618,6 +618,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
goto out; goto out;
o_end = o_start + len; o_end = o_start + len;
*moved_len = 0;
while (o_start < o_end) { while (o_start < o_end) {
struct ext4_extent *ex; struct ext4_extent *ex;
ext4_lblk_t cur_blk, next_blk; ext4_lblk_t cur_blk, next_blk;
...@@ -672,7 +673,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk, ...@@ -672,7 +673,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
*/ */
ext4_double_up_write_data_sem(orig_inode, donor_inode); ext4_double_up_write_data_sem(orig_inode, donor_inode);
/* Swap original branches with new branches */ /* Swap original branches with new branches */
move_extent_per_page(o_filp, donor_inode, *moved_len += move_extent_per_page(o_filp, donor_inode,
orig_page_index, donor_page_index, orig_page_index, donor_page_index,
offset_in_page, cur_len, offset_in_page, cur_len,
unwritten, &ret); unwritten, &ret);
...@@ -682,14 +683,11 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk, ...@@ -682,14 +683,11 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
o_start += cur_len; o_start += cur_len;
d_start += cur_len; d_start += cur_len;
} }
*moved_len = o_start - orig_blk;
if (*moved_len > len)
*moved_len = len;
out: out:
if (*moved_len) { if (*moved_len) {
ext4_discard_preallocations(orig_inode, 0); ext4_discard_preallocations(orig_inode);
ext4_discard_preallocations(donor_inode, 0); ext4_discard_preallocations(donor_inode);
} }
ext4_free_ext_path(path); ext4_free_ext_path(path);
......
...@@ -1525,7 +1525,7 @@ void ext4_clear_inode(struct inode *inode) ...@@ -1525,7 +1525,7 @@ void ext4_clear_inode(struct inode *inode)
ext4_fc_del(inode); ext4_fc_del(inode);
invalidate_inode_buffers(inode); invalidate_inode_buffers(inode);
clear_inode(inode); clear_inode(inode);
ext4_discard_preallocations(inode, 0); ext4_discard_preallocations(inode);
ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS); ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
dquot_drop(inode); dquot_drop(inode);
if (EXT4_I(inode)->jinode) { if (EXT4_I(inode)->jinode) {
......
...@@ -772,15 +772,14 @@ TRACE_EVENT(ext4_mb_release_group_pa, ...@@ -772,15 +772,14 @@ TRACE_EVENT(ext4_mb_release_group_pa,
); );
TRACE_EVENT(ext4_discard_preallocations, TRACE_EVENT(ext4_discard_preallocations,
TP_PROTO(struct inode *inode, unsigned int len, unsigned int needed), TP_PROTO(struct inode *inode, unsigned int len),
TP_ARGS(inode, len, needed), TP_ARGS(inode, len),
TP_STRUCT__entry( TP_STRUCT__entry(
__field( dev_t, dev ) __field( dev_t, dev )
__field( ino_t, ino ) __field( ino_t, ino )
__field( unsigned int, len ) __field( unsigned int, len )
__field( unsigned int, needed )
), ),
...@@ -788,13 +787,11 @@ TRACE_EVENT(ext4_discard_preallocations, ...@@ -788,13 +787,11 @@ TRACE_EVENT(ext4_discard_preallocations,
__entry->dev = inode->i_sb->s_dev; __entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino; __entry->ino = inode->i_ino;
__entry->len = len; __entry->len = len;
__entry->needed = needed;
), ),
TP_printk("dev %d,%d ino %lu len: %u needed %u", TP_printk("dev %d,%d ino %lu len: %u",
MAJOR(__entry->dev), MINOR(__entry->dev), MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long) __entry->ino, __entry->len, (unsigned long) __entry->ino, __entry->len)
__entry->needed)
); );
TRACE_EVENT(ext4_mb_discard_preallocations, TRACE_EVENT(ext4_mb_discard_preallocations,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment