From 1fcbcf06e4f159e0db39a53fe258336febbba804 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Wed, 3 Jun 2020 16:44:29 +0800 Subject: ext2: fix improper assignment for e_value_offs In the process of changing value for existing EA, there is an improper assignment of e_value_offs(setting to 0), because it will be reset to incorrect value in the following loop(shifting EA values before target). Delayed assignment can avoid this issue. Link: https://lore.kernel.org/r/20200603084429.25344-1-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/xattr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/ext2') diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 943cc469f42f..c802ea682e7f 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -588,7 +588,6 @@ bad_block: /* Remove the old value. */ memmove(first_val + size, first_val, val - first_val); memset(first_val, 0, size); - here->e_value_offs = 0; min_offs += size; /* Adjust all value offsets. */ @@ -600,6 +599,8 @@ bad_block: cpu_to_le16(o + size); last = EXT2_XATTR_NEXT(last); } + + here->e_value_offs = 0; } if (value == NULL) { /* Remove the old name. */ -- cgit From b4962091a54c8c332e4c6c211a86b7f6d6e1f759 Mon Sep 17 00:00:00 2001 From: "zhangyi (F)" Date: Mon, 8 Jun 2020 11:40:42 +0800 Subject: ext2: propagate errors up to ext2_find_entry()'s callers The same to commit <36de928641ee4> (ext4: propagate errors up to ext4_find_entry()'s callers') in ext4, also return error instead of NULL pointer in case of some error happens in ext2_find_entry() (e.g. -ENOMEM or -EIO). This could avoid a negative dentry cache entry installed even it failed to read directory block due to IO error. Link: https://lore.kernel.org/r/20200608034043.10451-1-yi.zhang@huawei.com Signed-off-by: zhangyi (F) Signed-off-by: Jan Kara --- fs/ext2/dir.c | 53 ++++++++++++++++++++++++++--------------------------- fs/ext2/ext2.h | 3 ++- fs/ext2/namei.c | 32 ++++++++++++++++++++++++++------ 3 files changed, 54 insertions(+), 34 deletions(-) (limited to 'fs/ext2') diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 13318e255ebf..95e4f0bd55a3 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -348,7 +348,6 @@ struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir, struct page *page = NULL; struct ext2_inode_info *ei = EXT2_I(dir); ext2_dirent * de; - int dir_has_error = 0; if (npages == 0) goto out; @@ -362,25 +361,25 @@ struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir, n = start; do { char *kaddr; - page = ext2_get_page(dir, n, dir_has_error); - if (!IS_ERR(page)) { - kaddr = page_address(page); - de = (ext2_dirent *) kaddr; - kaddr += ext2_last_byte(dir, n) - reclen; - while ((char *) de <= kaddr) { - if (de->rec_len == 0) { - ext2_error(dir->i_sb, __func__, - "zero-length directory entry"); - ext2_put_page(page); - goto out; - } - if (ext2_match (namelen, name, de)) - goto found; - de = ext2_next_entry(de); + page = ext2_get_page(dir, n, 0); + if (IS_ERR(page)) + return ERR_CAST(page); + + kaddr = page_address(page); + de = (ext2_dirent *) kaddr; + kaddr += ext2_last_byte(dir, n) - reclen; + while ((char *) de <= kaddr) { + if (de->rec_len == 0) { + ext2_error(dir->i_sb, __func__, + "zero-length directory entry"); + ext2_put_page(page); + goto out; } - ext2_put_page(page); - } else - dir_has_error = 1; + if (ext2_match(namelen, name, de)) + goto found; + de = ext2_next_entry(de); + } + ext2_put_page(page); if (++n >= npages) n = 0; @@ -414,18 +413,18 @@ struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p) return de; } -ino_t ext2_inode_by_name(struct inode *dir, const struct qstr *child) +int ext2_inode_by_name(struct inode *dir, const struct qstr *child, ino_t *ino) { - ino_t res = 0; struct ext2_dir_entry_2 *de; struct page *page; - de = ext2_find_entry (dir, child, &page); - if (de) { - res = le32_to_cpu(de->inode); - ext2_put_page(page); - } - return res; + de = ext2_find_entry(dir, child, &page); + if (IS_ERR_OR_NULL(de)) + return PTR_ERR(de); + + *ino = le32_to_cpu(de->inode); + ext2_put_page(page); + return 0; } static int ext2_prepare_chunk(struct page *page, loff_t pos, unsigned len) diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 8178bd38a9d6..a321ff9bf1b4 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -738,7 +738,8 @@ extern void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_wind /* dir.c */ extern int ext2_add_link (struct dentry *, struct inode *); -extern ino_t ext2_inode_by_name(struct inode *, const struct qstr *); +extern int ext2_inode_by_name(struct inode *dir, + const struct qstr *child, ino_t *ino); extern int ext2_make_empty(struct inode *, struct inode *); extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,const struct qstr *, struct page **); extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *); diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index ba3e3e075891..9a6ab213bc4d 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -56,12 +56,15 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode) static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags) { struct inode * inode; - ino_t ino; + ino_t ino = 0; + int res; if (dentry->d_name.len > EXT2_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); - ino = ext2_inode_by_name(dir, &dentry->d_name); + res = ext2_inode_by_name(dir, &dentry->d_name, &ino); + if (res) + return ERR_PTR(res); inode = NULL; if (ino) { inode = ext2_iget(dir->i_sb, ino); @@ -78,7 +81,12 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, uns struct dentry *ext2_get_parent(struct dentry *child) { struct qstr dotdot = QSTR_INIT("..", 2); - unsigned long ino = ext2_inode_by_name(d_inode(child), &dotdot); + ino_t ino = 0; + int res; + + res = ext2_inode_by_name(d_inode(child), &dotdot, &ino); + if (res) + return ERR_PTR(res); if (!ino) return ERR_PTR(-ENOENT); return d_obtain_alias(ext2_iget(child->d_sb, ino)); @@ -274,7 +282,11 @@ static int ext2_unlink(struct inode * dir, struct dentry *dentry) if (err) goto out; - de = ext2_find_entry (dir, &dentry->d_name, &page); + de = ext2_find_entry(dir, &dentry->d_name, &page); + if (IS_ERR(de)) { + err = PTR_ERR(de); + goto out; + } if (!de) { err = -ENOENT; goto out; @@ -330,7 +342,11 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, if (err) goto out; - old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page); + old_de = ext2_find_entry(old_dir, &old_dentry->d_name, &old_page); + if (IS_ERR(old_de)) { + err = PTR_ERR(old_de); + goto out; + } if (!old_de) { err = -ENOENT; goto out; @@ -352,7 +368,11 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, goto out_dir; err = -ENOENT; - new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page); + new_de = ext2_find_entry(new_dir, &new_dentry->d_name, &new_page); + if (IS_ERR(new_de)) { + err = PTR_ERR(new_de); + goto out_dir; + } if (!new_de) goto out_dir; ext2_set_link(new_dir, new_de, new_page, old_inode, 1); -- cgit From a43850a380ef56009ce721737b0c08984b663b99 Mon Sep 17 00:00:00 2001 From: "zhangyi (F)" Date: Mon, 8 Jun 2020 11:40:43 +0800 Subject: ext2: ext2_find_entry() return -ENOENT if no entry found Almost all callers of ext2_find_entry() transform NULL return value to -ENOENT, so just let ext2_find_entry() retuen -ENOENT instead of NULL if no valid entry found, and also switch to check the return value of ext2_inode_by_name() in ext2_lookup() and ext2_get_parent(). Link: https://lore.kernel.org/r/20200608034043.10451-2-yi.zhang@huawei.com Signed-off-by: zhangyi (F) Suggested-by: Jan Kara Signed-off-by: Jan Kara --- fs/ext2/dir.c | 4 ++-- fs/ext2/namei.c | 27 ++++++++------------------- 2 files changed, 10 insertions(+), 21 deletions(-) (limited to 'fs/ext2') diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 95e4f0bd55a3..70355ab6740e 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -393,7 +393,7 @@ struct ext2_dir_entry_2 *ext2_find_entry (struct inode *dir, } } while (n != start); out: - return NULL; + return ERR_PTR(-ENOENT); found: *res_page = page; @@ -419,7 +419,7 @@ int ext2_inode_by_name(struct inode *dir, const struct qstr *child, ino_t *ino) struct page *page; de = ext2_find_entry(dir, child, &page); - if (IS_ERR_OR_NULL(de)) + if (IS_ERR(de)) return PTR_ERR(de); *ino = le32_to_cpu(de->inode); diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 9a6ab213bc4d..5bf2c145643b 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -56,17 +56,18 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode) static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags) { struct inode * inode; - ino_t ino = 0; + ino_t ino; int res; if (dentry->d_name.len > EXT2_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); res = ext2_inode_by_name(dir, &dentry->d_name, &ino); - if (res) - return ERR_PTR(res); - inode = NULL; - if (ino) { + if (res) { + if (res != -ENOENT) + return ERR_PTR(res); + inode = NULL; + } else { inode = ext2_iget(dir->i_sb, ino); if (inode == ERR_PTR(-ESTALE)) { ext2_error(dir->i_sb, __func__, @@ -81,14 +82,13 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, uns struct dentry *ext2_get_parent(struct dentry *child) { struct qstr dotdot = QSTR_INIT("..", 2); - ino_t ino = 0; + ino_t ino; int res; res = ext2_inode_by_name(d_inode(child), &dotdot, &ino); if (res) return ERR_PTR(res); - if (!ino) - return ERR_PTR(-ENOENT); + return d_obtain_alias(ext2_iget(child->d_sb, ino)); } @@ -287,10 +287,6 @@ static int ext2_unlink(struct inode * dir, struct dentry *dentry) err = PTR_ERR(de); goto out; } - if (!de) { - err = -ENOENT; - goto out; - } err = ext2_delete_entry (de, page); if (err) @@ -347,10 +343,6 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, err = PTR_ERR(old_de); goto out; } - if (!old_de) { - err = -ENOENT; - goto out; - } if (S_ISDIR(old_inode->i_mode)) { err = -EIO; @@ -367,14 +359,11 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, if (dir_de && !ext2_empty_dir (new_inode)) goto out_dir; - err = -ENOENT; new_de = ext2_find_entry(new_dir, &new_dentry->d_name, &new_page); if (IS_ERR(new_de)) { err = PTR_ERR(new_de); goto out_dir; } - if (!new_de) - goto out_dir; ext2_set_link(new_dir, new_de, new_page, old_inode, 1); new_inode->i_ctime = current_time(new_inode); if (dir_de) -- cgit From bc2fbaa4d3808aef82dd1064a8e61c16549fe956 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Mon, 20 Apr 2020 16:02:21 -0400 Subject: ext2: fix missing percpu_counter_inc sbi->s_freeinodes_counter is only decreased by the ext2 code, it is never increased. This patch fixes it. Note that sbi->s_freeinodes_counter is only used in the algorithm that tries to find the group for new allocations, so this bug is not easily visible (the only visibility is that the group finding algorithm selects inoptinal result). Link: https://lore.kernel.org/r/alpine.LRH.2.02.2004201538300.19436@file01.intranet.prod.int.rdu2.redhat.com Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Jan Kara --- fs/ext2/ialloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/ext2') diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index fda7d3f5b4be..432c3febea6d 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -80,6 +80,7 @@ static void ext2_release_inode(struct super_block *sb, int group, int dir) if (dir) le16_add_cpu(&desc->bg_used_dirs_count, -1); spin_unlock(sb_bgl_lock(EXT2_SB(sb), group)); + percpu_counter_inc(&EXT2_SB(sb)->s_freeinodes_counter); if (dir) percpu_counter_dec(&EXT2_SB(sb)->s_dirs_counter); mark_buffer_dirty(bh); @@ -528,7 +529,7 @@ got: goto fail; } - percpu_counter_add(&sbi->s_freeinodes_counter, -1); + percpu_counter_dec(&sbi->s_freeinodes_counter); if (S_ISDIR(mode)) percpu_counter_inc(&sbi->s_dirs_counter); -- cgit From 30b42a714d3241ce2aa2561f629dd6088c60fef7 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Fri, 19 Jun 2020 15:31:44 +0800 Subject: ext2: remove nocheck option Remove useless nocheck option. Link: https://lore.kernel.org/r/20200619073144.4701-1-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/ext2.h | 1 - fs/ext2/super.c | 10 +--------- 2 files changed, 1 insertion(+), 10 deletions(-) (limited to 'fs/ext2') diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index a321ff9bf1b4..0debad3e10e3 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -374,7 +374,6 @@ struct ext2_inode { /* * Mount flags */ -#define EXT2_MOUNT_CHECK 0x000001 /* Do mount-time checks */ #define EXT2_MOUNT_OLDALLOC 0x000002 /* Don't use the new Orlov allocator */ #define EXT2_MOUNT_GRPID 0x000004 /* Create files with directory's group */ #define EXT2_MOUNT_DEBUG 0x000008 /* Some debugging messages */ diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 4a4ab683250d..dda860562ca3 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -431,7 +431,7 @@ static unsigned long get_sb_block(void **data) enum { Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, - Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug, + Opt_err_ro, Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip, Opt_dax, Opt_ignore, Opt_err, Opt_quota, Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation @@ -451,8 +451,6 @@ static const match_table_t tokens = { {Opt_err_panic, "errors=panic"}, {Opt_err_ro, "errors=remount-ro"}, {Opt_nouid32, "nouid32"}, - {Opt_nocheck, "check=none"}, - {Opt_nocheck, "nocheck"}, {Opt_debug, "debug"}, {Opt_oldalloc, "oldalloc"}, {Opt_orlov, "orlov"}, @@ -546,12 +544,6 @@ static int parse_options(char *options, struct super_block *sb, case Opt_nouid32: set_opt (opts->s_mount_opt, NO_UID32); break; - case Opt_nocheck: - ext2_msg(sb, KERN_WARNING, - "Option nocheck/check=none is deprecated and" - " will be removed in June 2020."); - clear_opt (opts->s_mount_opt, CHECK); - break; case Opt_debug: set_opt (opts->s_mount_opt, DEBUG); break; -- cgit From cf1013f441eb997ae770566f88cf021086d34cff Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Fri, 3 Jul 2020 20:44:11 +0800 Subject: ext2: fix some incorrect comments in inode.c There are some incorrect comments in inode.c, so fix them properly. Link: https://lore.kernel.org/r/20200703124411.24085-1-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Signed-off-by: Jan Kara --- fs/ext2/inode.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'fs/ext2') diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index c8b371c82b4f..80662e1f7889 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -356,8 +356,7 @@ static inline ext2_fsblk_t ext2_find_goal(struct inode *inode, long block, * @blks: number of data blocks to be mapped. * @blocks_to_boundary: the offset in the indirect block * - * return the total number of blocks to be allocate, including the - * direct and indirect blocks. + * return the number of direct blocks to allocate. */ static int ext2_blks_to_allocate(Indirect * branch, int k, unsigned long blks, @@ -390,11 +389,9 @@ ext2_blks_to_allocate(Indirect * branch, int k, unsigned long blks, * ext2_alloc_blocks: multiple allocate blocks needed for a branch * @indirect_blks: the number of blocks need to allocate for indirect * blocks - * + * @blks: the number of blocks need to allocate for direct blocks * @new_blocks: on return it will store the new block numbers for * the indirect blocks(if needed) and the first direct block, - * @blks: on return it will store the total number of allocated - * direct blocks */ static int ext2_alloc_blocks(struct inode *inode, ext2_fsblk_t goal, int indirect_blks, int blks, -- cgit From 1197d04fd3f1daf75cfd0a68442080186e546178 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Fri, 26 Jun 2020 13:49:59 +0800 Subject: ext2: initialize quota info in ext2_xattr_set() In order to correctly account/limit space usage, should initialize quota info before calling quota related functions. Link: https://lore.kernel.org/r/20200626054959.114177-1-cgxu519@mykernel.net Signed-off-by: Chengguang Xu Reviewed-by: Reviewed-by: Ritesh Harjani Signed-off-by: Jan Kara --- fs/ext2/xattr.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'fs/ext2') diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index c802ea682e7f..841fa6d9d744 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -437,6 +437,9 @@ ext2_xattr_set(struct inode *inode, int name_index, const char *name, name_len = strlen(name); if (name_len > 255 || value_len > sb->s_blocksize) return -ERANGE; + error = dquot_initialize(inode); + if (error) + return error; down_write(&EXT2_I(inode)->xattr_sem); if (EXT2_I(inode)->i_file_acl) { /* The inode already has an extended attribute block. */ -- cgit From 17a0445e7b5d0238c01a7e9b9885a4464408eb5d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 19 Jul 2020 17:13:27 -0700 Subject: ext2: ext2.h: fix duplicated word + typos Change the repeated word "the" in "it the the" to "it is the". Fix typo "recentl" to "recently". Fix verb "give" to "gives". Link: https://lore.kernel.org/r/20200720001327.23603-1-rdunlap@infradead.org Signed-off-by: Randy Dunlap Cc: Jan Kara Cc: linux-ext4@vger.kernel.org Signed-off-by: Jan Kara --- fs/ext2/ext2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/ext2') diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 0debad3e10e3..5136b7289e8d 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -52,8 +52,8 @@ struct ext2_block_alloc_info { /* * Was i_next_alloc_goal in ext2_inode_info * is the *physical* companion to i_next_alloc_block. - * it the the physical block number of the block which was most-recentl - * allocated to this file. This give us the goal (target) for the next + * it is the physical block number of the block which was most-recently + * allocated to this file. This gives us the goal (target) for the next * allocation when we detect linearly ascending requests. */ ext2_fsblk_t last_alloc_physical_block; -- cgit