diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 43775a6ca505..11e47a530435 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2192,6 +2192,7 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd) * mapped so that it can be written out (and thus forward progress is * guaranteed). After mapping we submit all mapped pages for IO. */ +#include static int mpage_map_and_submit_extent(handle_t *handle, struct mpage_da_data *mpd, bool *give_up_on_write) @@ -2203,6 +2204,7 @@ static int mpage_map_and_submit_extent(handle_t *handle, int progress = 0; ext4_io_end_t *io_end = mpd->io_submit.io_end; struct ext4_io_end_vec *io_end_vec; + static int wait = 0; io_end_vec = ext4_alloc_io_end_vec(io_end); if (IS_ERR(io_end_vec)) @@ -2213,6 +2215,26 @@ static int mpage_map_and_submit_extent(handle_t *handle, if (err < 0) { struct super_block *sb = inode->i_sb; + if (!wait && err == -ENOSPC) { + wait = 1; + if (!ext4_count_free_clusters(sb)) { + /* + * Failed to allocate data block, wait + * test.sh to free a block. + */ + pr_err("wait free\n"); + msleep(3000); + pr_err("after free, now %llu\n", + ext4_count_free_clusters(sb)); + } else { + /* + * Failed to allocate metadata block, + * will trigger infinite loop and hung. + */ + pr_err("will hung\n"); + } + } + if (ext4_forced_shutdown(EXT4_SB(sb)) || ext4_test_mount_flag(sb, EXT4_MF_FS_ABORTED)) goto invalidate_dirty_pages; @@ -2888,6 +2910,10 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, /* In case writeback began while the folio was unlocked */ folio_wait_stable(folio); + /* Use task name and DISCARD mount option as delay inject filter. */ + if (!strcmp(current->comm, "dd") && test_opt(inode->i_sb, DISCARD)) + msleep(3000); + #ifdef CONFIG_FS_ENCRYPTION ret = ext4_block_write_begin(folio, pos, len, ext4_da_get_block_prep); #else diff --git a/fs/ext4/super.c b/fs/ext4/super.c index c94ebf704616..79f4e96b8691 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -5715,6 +5715,15 @@ static int ext4_fill_super(struct super_block *sb, struct fs_context *fc) /* Update the s_overhead_clusters if necessary */ ext4_update_overhead(sb, false); + + if (!strcmp(sb->s_bdev->bd_disk->disk_name, "sda")) { + pr_err("r_blocks %lld s_resv_clusters %llu free %lld dirty %lld EXT4_FREECLUSTERS_WATERMARK %u\n", + (ext4_r_blocks_count(sbi->s_es) >> sbi->s_cluster_bits), + atomic64_read(&sbi->s_resv_clusters), + percpu_counter_read_positive(&sbi->s_freeclusters_counter), + percpu_counter_read_positive(&sbi->s_dirtyclusters_counter), + EXT4_FREECLUSTERS_WATERMARK); + } return 0; free_sbi: