From 158be76c01172f4ffa3f10e2b4b433b3e496c75d Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Mon, 21 Oct 2019 07:23:26 +0800 Subject: ext2: adjust block num when retry allocation Set block num to original *count in a case of retrying allocation in case num < *count Link: https://lore.kernel.org/r/20191020232326.84881-1-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/balloc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/ext2') diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index e0cc55164505..924c1c765306 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -1404,6 +1404,7 @@ allocated: * use. So we may want to selectively mark some of the blocks * as free */ + num = *count; goto retry_alloc; } -- cgit v1.2.3 From ba1af2e47446ac353395b4c274408944284ceeaa Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Tue, 22 Oct 2019 17:17:38 +0800 Subject: ext2: add missing brelse in ext2_new_blocks() Fix missing brelse of bitmap_bh in the case of retry. Link: https://lore.kernel.org/r/20191022091738.9160-1-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/balloc.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'fs/ext2') diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 924c1c765306..4664d324567c 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -1313,6 +1313,13 @@ retry_alloc: if (free_blocks > 0) { grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb)); + /* + * In case we retry allocation (due to fs reservation not + * working out or fs corruption), the bitmap_bh is non-null + * pointer and we have to release it before calling + * read_block_bitmap(). + */ + brelse(bitmap_bh); bitmap_bh = read_block_bitmap(sb, group_no); if (!bitmap_bh) goto io_error; -- cgit v1.2.3 From acd1f04679803af84e7ab76f37df30d8598b07b9 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Wed, 23 Oct 2019 21:56:43 +0800 Subject: ext2: return error when fail to allocating memory in ioctl Currently, we do not check memory allocation result for ei->i_block_alloc_info in ioctl, this patch checks it and returns error in failure case. Link: https://lore.kernel.org/r/20191023135643.28837-1-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/ioctl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'fs/ext2') diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index 1b853fb0b163..32a8d10b579d 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -145,10 +145,13 @@ setversion_out: if (ei->i_block_alloc_info){ struct ext2_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; rsv->rsv_goal_size = rsv_window_size; + } else { + ret = -ENOMEM; } + mutex_unlock(&ei->truncate_mutex); mnt_drop_write_file(filp); - return 0; + return ret; } default: return -ENOTTY; -- cgit v1.2.3 From 30ef0e4085070312101be26c015f36277f02e12b Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Sat, 26 Oct 2019 17:07:21 +0800 Subject: ext2: don't set *count in the case of failure in ext2_try_to_allocate() Currently we set *count to num(value 0) in the failure of block allocation in ext2_try_to_allocate(). Without reservation, we reuse *count(value 0) to retry block allocation and wrong *count will cause only allocating maximum 1 block even though having sufficent free blocks in that block group. Finally, it probably cause significant fragmentation. Link: https://lore.kernel.org/r/20191026090721.23794-1-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/balloc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs/ext2') diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 4664d324567c..19bce75d207b 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -736,7 +736,6 @@ repeat: *count = num; return grp_goal - num; fail_access: - *count = num; return -1; } -- cgit v1.2.3 From e705f4b8aa27a59f8933e8f384e9752f052c469c Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Tue, 5 Nov 2019 12:51:00 +0800 Subject: ext2: check err when partial != NULL Check err when partial == NULL is meaningless because partial == NULL means getting branch successfully without error. CC: stable@vger.kernel.org Link: https://lore.kernel.org/r/20191105045100.7104-1-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/inode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'fs/ext2') diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 7004ce581a32..a16c53655e77 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -701,10 +701,13 @@ static int ext2_get_blocks(struct inode *inode, if (!partial) { count++; mutex_unlock(&ei->truncate_mutex); - if (err) - goto cleanup; goto got_it; } + + if (err) { + mutex_unlock(&ei->truncate_mutex); + goto cleanup; + } } /* -- cgit v1.2.3 From eb9e47fc230aafc3ac1e5eeae6d0d8d5e108bbae Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Mon, 4 Nov 2019 19:40:32 +0800 Subject: ext2: introduce new helper ext2_group_last_block_no() Introduce new helper ext2_group_last_block_no() to calculate last block num for specific block group, we can replace open coded logic by calling this common helper. Link: https://lore.kernel.org/r/20191104114036.9893-1-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/ext2.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'fs/ext2') diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 10ab238de9a6..8178bd38a9d6 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -813,6 +813,18 @@ ext2_group_first_block_no(struct super_block *sb, unsigned long group_no) le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block); } +static inline ext2_fsblk_t +ext2_group_last_block_no(struct super_block *sb, unsigned long group_no) +{ + struct ext2_sb_info *sbi = EXT2_SB(sb); + + if (group_no == sbi->s_groups_count - 1) + return le32_to_cpu(sbi->s_es->s_blocks_count) - 1; + else + return ext2_group_first_block_no(sb, group_no) + + EXT2_BLOCKS_PER_GROUP(sb) - 1; +} + #define ext2_set_bit __test_and_set_bit_le #define ext2_clear_bit __test_and_clear_bit_le #define ext2_test_bit test_bit_le -- cgit v1.2.3 From 90f3741c2b567d3f16c13d574dbd5d42ed076b2e Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Mon, 4 Nov 2019 19:40:33 +0800 Subject: ext2: code cleanup by calling ext2_group_last_block_no() Call common helper ext2_group_last_block_no() to calculate group last block number. Link: https://lore.kernel.org/r/20191104114036.9893-2-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/balloc.c | 16 ++++++++-------- fs/ext2/super.c | 8 +------- 2 files changed, 9 insertions(+), 15 deletions(-) (limited to 'fs/ext2') diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 19bce75d207b..994a1fd18e93 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -269,7 +269,7 @@ goal_in_my_reservation(struct ext2_reserve_window *rsv, ext2_grpblk_t grp_goal, ext2_fsblk_t group_first_block, group_last_block; group_first_block = ext2_group_first_block_no(sb, group); - group_last_block = group_first_block + EXT2_BLOCKS_PER_GROUP(sb) - 1; + group_last_block = ext2_group_last_block_no(sb, group); if ((rsv->_rsv_start > group_last_block) || (rsv->_rsv_end < group_first_block)) @@ -666,22 +666,22 @@ ext2_try_to_allocate(struct super_block *sb, int group, unsigned long *count, struct ext2_reserve_window *my_rsv) { - ext2_fsblk_t group_first_block; + ext2_fsblk_t group_first_block = ext2_group_first_block_no(sb, group); + ext2_fsblk_t group_last_block = ext2_group_last_block_no(sb, group); ext2_grpblk_t start, end; unsigned long num = 0; /* we do allocation within the reservation window if we have a window */ if (my_rsv) { - group_first_block = ext2_group_first_block_no(sb, group); if (my_rsv->_rsv_start >= group_first_block) start = my_rsv->_rsv_start - group_first_block; else /* reservation window cross group boundary */ start = 0; end = my_rsv->_rsv_end - group_first_block + 1; - if (end > EXT2_BLOCKS_PER_GROUP(sb)) + if (end > group_last_block - group_first_block + 1) /* reservation window crosses group boundary */ - end = EXT2_BLOCKS_PER_GROUP(sb); + end = group_last_block - group_first_block + 1; if ((start <= grp_goal) && (grp_goal < end)) start = grp_goal; else @@ -691,7 +691,7 @@ ext2_try_to_allocate(struct super_block *sb, int group, start = grp_goal; else start = 0; - end = EXT2_BLOCKS_PER_GROUP(sb); + end = group_last_block - group_first_block + 1; } BUG_ON(start > EXT2_BLOCKS_PER_GROUP(sb)); @@ -907,7 +907,7 @@ static int alloc_new_reservation(struct ext2_reserve_window_node *my_rsv, spinlock_t *rsv_lock = &EXT2_SB(sb)->s_rsv_window_lock; group_first_block = ext2_group_first_block_no(sb, group); - group_end_block = group_first_block + (EXT2_BLOCKS_PER_GROUP(sb) - 1); + group_end_block = ext2_group_last_block_no(sb, group); if (grp_goal < 0) start_block = group_first_block; @@ -1114,7 +1114,7 @@ ext2_try_to_allocate_with_rsv(struct super_block *sb, unsigned int group, * first block is the block number of the first block in this group */ group_first_block = ext2_group_first_block_no(sb, group); - group_last_block = group_first_block + (EXT2_BLOCKS_PER_GROUP(sb) - 1); + group_last_block = ext2_group_last_block_no(sb, group); /* * Basically we will allocate a new block from inode's reservation diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 30c630d73f0f..4cd401a2f207 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -702,13 +702,7 @@ static int ext2_check_descriptors(struct super_block *sb) for (i = 0; i < sbi->s_groups_count; i++) { struct ext2_group_desc *gdp = ext2_get_group_desc(sb, i, NULL); ext2_fsblk_t first_block = ext2_group_first_block_no(sb, i); - ext2_fsblk_t last_block; - - if (i == sbi->s_groups_count - 1) - last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; - else - last_block = first_block + - (EXT2_BLOCKS_PER_GROUP(sb) - 1); + ext2_fsblk_t last_block = ext2_group_last_block_no(sb, i); if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || le32_to_cpu(gdp->bg_block_bitmap) > last_block) -- cgit v1.2.3 From cf4eb321b3ad63248069a8038df126fcf9ed9100 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 6 Nov 2019 16:39:26 +0100 Subject: ext2: Simplify initialization in ext2_try_to_allocate() Somewhat simplify the logic initializing search start and end in ext2_try_to_allocate(). No functional change. Signed-off-by: Jan Kara --- fs/ext2/balloc.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) (limited to 'fs/ext2') diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 994a1fd18e93..b7a4d74dfde7 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -671,29 +671,17 @@ ext2_try_to_allocate(struct super_block *sb, int group, ext2_grpblk_t start, end; unsigned long num = 0; + start = 0; + end = group_last_block - group_first_block + 1; /* we do allocation within the reservation window if we have a window */ if (my_rsv) { if (my_rsv->_rsv_start >= group_first_block) start = my_rsv->_rsv_start - group_first_block; - else - /* reservation window cross group boundary */ - start = 0; - end = my_rsv->_rsv_end - group_first_block + 1; - if (end > group_last_block - group_first_block + 1) - /* reservation window crosses group boundary */ - end = group_last_block - group_first_block + 1; - if ((start <= grp_goal) && (grp_goal < end)) - start = grp_goal; - else + if (my_rsv->_rsv_end < group_last_block) + end = my_rsv->_rsv_end - group_first_block + 1; + if (grp_goal < start || grp_goal >= end) grp_goal = -1; - } else { - if (grp_goal > 0) - start = grp_goal; - else - start = 0; - end = group_last_block - group_first_block + 1; } - BUG_ON(start > EXT2_BLOCKS_PER_GROUP(sb)); repeat: -- cgit v1.2.3 From ac3820f8222b6563580605f427ff03474a2f003a Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Mon, 4 Nov 2019 19:40:34 +0800 Subject: ext2: skip unnecessary operations in ext2_try_to_allocate() Move 'repeat' tag to proper place so that we can skip unnecessary operations in ext2_try_to_allocate(). Link: https://lore.kernel.org/r/20191104114036.9893-3-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/balloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/ext2') diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index b7a4d74dfde7..f3ff05edaf8c 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -684,7 +684,6 @@ ext2_try_to_allocate(struct super_block *sb, int group, } BUG_ON(start > EXT2_BLOCKS_PER_GROUP(sb)); -repeat: if (grp_goal < 0) { grp_goal = find_next_usable_block(start, bitmap_bh, end); if (grp_goal < 0) @@ -701,6 +700,7 @@ repeat: } start = grp_goal; +repeat: if (ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), grp_goal, bitmap_bh->b_data)) { /* -- cgit v1.2.3 From 44dd6161338ef528b5b011184639beadcf038b14 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Mon, 4 Nov 2019 19:40:35 +0800 Subject: ext2: code cleanup for ext2_try_to_allocate() Code cleanup by removing duplicated code. Link: https://lore.kernel.org/r/20191104114036.9893-4-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/balloc.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) (limited to 'fs/ext2') diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index f3ff05edaf8c..4beb416be9cf 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -698,29 +698,20 @@ ext2_try_to_allocate(struct super_block *sb, int group, ; } } - start = grp_goal; -repeat: - if (ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), grp_goal, - bitmap_bh->b_data)) { - /* - * The block was allocated by another thread, or it was - * allocated and then freed by another thread - */ - start++; - grp_goal++; - if (start >= end) - goto fail_access; - goto repeat; - } - num++; - grp_goal++; - while (num < *count && grp_goal < end - && !ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), + for (; num < *count && grp_goal < end; grp_goal++) { + if (ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), grp_goal, bitmap_bh->b_data)) { + if (num == 0) + continue; + break; + } num++; - grp_goal++; } + + if (num == 0) + goto fail_access; + *count = num; return grp_goal - num; fail_access: -- cgit v1.2.3 From 355b9aae868512747c0ff90231e8ae8ea0278a60 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Mon, 4 Nov 2019 19:40:36 +0800 Subject: ext2: fix improper function comment Just fix a improper function comment. Link: https://lore.kernel.org/r/20191104114036.9893-5-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/balloc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'fs/ext2') diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 4beb416be9cf..fa9c951d3471 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -732,10 +732,9 @@ fail_access: * but we will shift to the place where start_block is, * then start from there, when looking for a reservable space. * - * @size: the target new reservation window size + * @sb: the super block. * - * @group_first_block: the first block we consider to start - * the real search from + * @start_block: the first block we consider to start the real search from * * @last_block: * the maximum block number that our goal reservable space -- cgit v1.2.3 From 545886fead7abfdbeb46d3ac62256e1db72739a3 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Sat, 16 Nov 2019 06:49:00 +0800 Subject: ext2: code cleanup for descriptor_loc() Code cleanup by removing unnecessary variable in descriptor_loc(). Link: https://lore.kernel.org/r/20191115224900.2613-1-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/super.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'fs/ext2') diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 4cd401a2f207..bcffe25da2f0 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -800,7 +800,6 @@ static unsigned long descriptor_loc(struct super_block *sb, { struct ext2_sb_info *sbi = EXT2_SB(sb); unsigned long bg, first_meta_bg; - int has_super = 0; first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); @@ -808,10 +807,8 @@ static unsigned long descriptor_loc(struct super_block *sb, nr < first_meta_bg) return (logic_sb_block + nr + 1); bg = sbi->s_desc_per_block * nr; - if (ext2_bg_has_super(sb, bg)) - has_super = 1; - return ext2_group_first_block_no(sb, bg) + has_super; + return ext2_group_first_block_no(sb, bg) + ext2_bg_has_super(sb, bg); } static int ext2_fill_super(struct super_block *sb, void *data, int silent) -- cgit v1.2.3