From nobody Sat Feb 7 15:22:27 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EA1EBEB64D9 for ; Mon, 10 Jul 2023 06:10:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230379AbjGJGKe (ORCPT ); Mon, 10 Jul 2023 02:10:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58132 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229701AbjGJGKc (ORCPT ); Mon, 10 Jul 2023 02:10:32 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 606B5FB for ; Sun, 9 Jul 2023 23:10:30 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id D9A2960DF3 for ; Mon, 10 Jul 2023 06:10:29 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id ED32CC433C7; Mon, 10 Jul 2023 06:10:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1688969429; bh=qs3ZE8+Wjvpkte9fL5xfVgr8N2UAlRGg11JcBoIaJHE=; h=From:To:Cc:Subject:Date:From; b=N5IoN5RGgAYYTzey+fz43/KLYZPncacZnqg8DP+RvF+Yg2CD6GoFHwm1p1QC7qJ3m 4CAqk5GcpBwJgItZVqqN2v7+IeaxMqdejRxCOVJV7vujp0biZ/JKtYNa0Gao9uTYcE BiJeHFyZcKJL2kSjwq8uwheQkDRO2VJV1xe/WMHlqtEf8SnFCpn53cRW5QccqZMHTr /24MkptpfPJOiKfdoOnu5uc9t48h2kmg5cEZx8kZKH0eugCJ/a4uJF3iQFyFUCdguU younKnOVn+cl8gxXobRPuIdwqVl5CkTLfJrVRVFcyGqpu3qdJ3RuesJhzazLAFtuGC 1P28omNbXyZqQ== From: Chao Yu To: jaegeuk@kernel.org Cc: linux-f2fs-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org, Chao Yu , syzbot+e5600587fa9cbf8e3826@syzkaller.appspotmail.com Subject: [PATCH] f2fs: fix potential deadlock by reordering w/ i_sem Date: Mon, 10 Jul 2023 14:10:21 +0800 Message-Id: <20230710061021.2303432-1-chao@kernel.org> X-Mailer: git-send-email 2.40.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" syzbot reports deadlock bug as below: -> #1 (&fi->i_sem){+.+.}-{3:3}: down_write+0x3a/0x50 kernel/locking/rwsem.c:1573 f2fs_down_write fs/f2fs/f2fs.h:2133 [inline] f2fs_add_inline_entry+0x3a8/0x760 fs/f2fs/inline.c:644 f2fs_add_dentry+0xba/0x1e0 fs/f2fs/dir.c:784 f2fs_do_add_link+0x21e/0x340 fs/f2fs/dir.c:827 f2fs_add_link fs/f2fs/f2fs.h:3554 [inline] f2fs_create+0x32c/0x530 fs/f2fs/namei.c:377 lookup_open fs/namei.c:3492 [inline] open_last_lookups fs/namei.c:3560 [inline] path_openat+0x13e7/0x3180 fs/namei.c:3790 do_filp_open+0x234/0x490 fs/namei.c:3820 do_sys_openat2+0x13e/0x1d0 fs/open.c:1407 do_sys_open fs/open.c:1422 [inline] __do_sys_open fs/open.c:1430 [inline] __se_sys_open fs/open.c:1426 [inline] __x64_sys_open+0x225/0x270 fs/open.c:1426 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd -> #0 (&fi->i_xattr_sem){.+.+}-{3:3}: check_prev_add kernel/locking/lockdep.c:3142 [inline] check_prevs_add kernel/locking/lockdep.c:3261 [inline] validate_chain kernel/locking/lockdep.c:3876 [inline] __lock_acquire+0x39ff/0x7f70 kernel/locking/lockdep.c:5144 lock_acquire+0x1e3/0x520 kernel/locking/lockdep.c:5761 down_read+0x47/0x2f0 kernel/locking/rwsem.c:1520 f2fs_down_read fs/f2fs/f2fs.h:2108 [inline] f2fs_getxattr+0xb8/0x1460 fs/f2fs/xattr.c:532 __f2fs_get_acl+0x52/0x8e0 fs/f2fs/acl.c:179 f2fs_acl_create fs/f2fs/acl.c:377 [inline] f2fs_init_acl+0xd7/0x9a0 fs/f2fs/acl.c:420 f2fs_init_inode_metadata+0x824/0x1190 fs/f2fs/dir.c:558 f2fs_do_tmpfile+0x34/0x170 fs/f2fs/dir.c:839 __f2fs_tmpfile+0x1f9/0x380 fs/f2fs/namei.c:884 f2fs_ioc_start_atomic_write+0x4a3/0x9e0 fs/f2fs/file.c:2099 __f2fs_ioctl+0x1b5c/0xb770 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl+0xf8/0x170 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd The root cause is as below reversed lock order: - f2fs_create - f2fs_add_dentry - f2fs_down_write(&F2FS_I(dir)->i_xattr_sem) - f2fs_ioc_start_atomic_write - __f2fs_tmpfile - f2fs_do_tmpfile - f2fs_down_write(&F2FS_I(inode)->i_sem) - f2fs_init_inode_metadata - f2fs_init_acl - __f2fs_get_acl - f2fs_getxattr - f2fs_down_read(&F2FS_I(dir)->i_xattr_sem) - f2fs_add_inline_entry - f2fs_down_write(&F2FS_I(inode)->i_sem) We can break the dependency of deadlock by below change: - use i_sem to keep order of {get,set}xattr instead of i_xattr_sem - keep below lock order in inode operation to avoid deadlock: dir->i_sem -> inode->i_sem dir->i_sem -> dpage_lock Fixes: 5eda1ad1aaff ("f2fs: fix deadlock in i_xattr_sem and inode page lock= ") Reported-by: syzbot+e5600587fa9cbf8e3826@syzkaller.appspotmail.com Closes: https://lore.kernel.org/linux-f2fs-devel/00000000000096797d06001a35= 9d@google.com Signed-off-by: Chao Yu --- fs/f2fs/acl.c | 36 +++++++++++++++++++----------------- fs/f2fs/acl.h | 4 ++-- fs/f2fs/dir.c | 22 ++++++++++++++++------ fs/f2fs/f2fs.h | 1 - fs/f2fs/super.c | 5 ++--- fs/f2fs/verity.c | 5 +++-- fs/f2fs/xattr.c | 37 +++++++++++++++++++++---------------- fs/f2fs/xattr.h | 19 +++++++++++++------ 8 files changed, 76 insertions(+), 53 deletions(-) diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index ec2aeccb69a3..af58b38e953c 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c @@ -166,7 +166,7 @@ static void *f2fs_acl_to_disk(struct f2fs_sb_info *sbi, } =20 static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type, - struct page *dpage) + struct page *dpage, bool locked) { int name_index =3D F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; void *value =3D NULL; @@ -176,13 +176,13 @@ static struct posix_acl *__f2fs_get_acl(struct inode = *inode, int type, if (type =3D=3D ACL_TYPE_ACCESS) name_index =3D F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; =20 - retval =3D f2fs_getxattr(inode, name_index, "", NULL, 0, dpage); + retval =3D f2fs_getxattr(inode, name_index, "", NULL, 0, dpage, locked); if (retval > 0) { value =3D f2fs_kmalloc(F2FS_I_SB(inode), retval, GFP_F2FS_ZERO); if (!value) return ERR_PTR(-ENOMEM); retval =3D f2fs_getxattr(inode, name_index, "", value, - retval, dpage); + retval, dpage, locked); } =20 if (retval > 0) @@ -201,7 +201,7 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int= type, bool rcu) if (rcu) return ERR_PTR(-ECHILD); =20 - return __f2fs_get_acl(inode, type, NULL); + return __f2fs_get_acl(inode, type, NULL, false); } =20 static int f2fs_acl_update_mode(struct mnt_idmap *idmap, @@ -226,9 +226,9 @@ static int f2fs_acl_update_mode(struct mnt_idmap *idmap, return 0; } =20 -static int __f2fs_set_acl(struct mnt_idmap *idmap, - struct inode *inode, int type, - struct posix_acl *acl, struct page *ipage) +static int __f2fs_set_acl(struct mnt_idmap *idmap, struct inode *inode, + int type, struct posix_acl *acl, + struct page *ipage, bool locked) { int name_index; void *value =3D NULL; @@ -266,7 +266,8 @@ static int __f2fs_set_acl(struct mnt_idmap *idmap, } } =20 - error =3D f2fs_setxattr(inode, name_index, "", value, size, ipage, 0); + error =3D f2fs_setxattr(inode, name_index, "", value, size, + ipage, 0, locked); =20 kfree(value); if (!error) @@ -284,7 +285,7 @@ int f2fs_set_acl(struct mnt_idmap *idmap, struct dentry= *dentry, if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) return -EIO; =20 - return __f2fs_set_acl(idmap, inode, type, acl, NULL); + return __f2fs_set_acl(idmap, inode, type, acl, NULL, false); } =20 /* @@ -362,7 +363,7 @@ static int f2fs_acl_create_masq(struct posix_acl *acl, = umode_t *mode_p) =20 static int f2fs_acl_create(struct inode *dir, umode_t *mode, struct posix_acl **default_acl, struct posix_acl **acl, - struct page *dpage) + struct page *dpage, bool locked) { struct posix_acl *p; struct posix_acl *clone; @@ -374,7 +375,7 @@ static int f2fs_acl_create(struct inode *dir, umode_t *= mode, if (S_ISLNK(*mode) || !IS_POSIXACL(dir)) return 0; =20 - p =3D __f2fs_get_acl(dir, ACL_TYPE_DEFAULT, dpage); + p =3D __f2fs_get_acl(dir, ACL_TYPE_DEFAULT, dpage, locked); if (!p || p =3D=3D ERR_PTR(-EOPNOTSUPP)) { *mode &=3D ~current_umask(); return 0; @@ -412,28 +413,29 @@ static int f2fs_acl_create(struct inode *dir, umode_t= *mode, } =20 int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipa= ge, - struct page *dpage) + struct page *dpage, bool locked) { struct posix_acl *default_acl =3D NULL, *acl =3D NULL; int error; =20 - error =3D f2fs_acl_create(dir, &inode->i_mode, &default_acl, &acl, dpage); + error =3D f2fs_acl_create(dir, &inode->i_mode, &default_acl, &acl, + dpage, locked); if (error) return error; =20 f2fs_mark_inode_dirty_sync(inode, true); =20 if (default_acl) { - error =3D __f2fs_set_acl(NULL, inode, ACL_TYPE_DEFAULT, default_acl, - ipage); + error =3D __f2fs_set_acl(NULL, inode, ACL_TYPE_DEFAULT, + default_acl, ipage, locked); posix_acl_release(default_acl); } else { inode->i_default_acl =3D NULL; } if (acl) { if (!error) - error =3D __f2fs_set_acl(NULL, inode, ACL_TYPE_ACCESS, acl, - ipage); + error =3D __f2fs_set_acl(NULL, inode, ACL_TYPE_ACCESS, + acl, ipage, locked); posix_acl_release(acl); } else { inode->i_acl =3D NULL; diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h index 94ebfbfbdc6f..9c14b6f549c6 100644 --- a/fs/f2fs/acl.h +++ b/fs/f2fs/acl.h @@ -37,13 +37,13 @@ extern struct posix_acl *f2fs_get_acl(struct inode *, i= nt, bool); extern int f2fs_set_acl(struct mnt_idmap *, struct dentry *, struct posix_acl *, int); extern int f2fs_init_acl(struct inode *, struct inode *, struct page *, - struct page *); + struct page *, bool); #else #define f2fs_get_acl NULL #define f2fs_set_acl NULL =20 static inline int f2fs_init_acl(struct inode *inode, struct inode *dir, - struct page *ipage, struct page *dpage) + struct page *ipage, struct page *dpage, bool locked) { return 0; } diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index d635c58cf5a3..4b5c62e18d67 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -540,6 +540,8 @@ struct page *f2fs_init_inode_metadata(struct inode *ino= de, struct inode *dir, int err; =20 if (is_inode_flag_set(inode, FI_NEW_INODE)) { + struct f2fs_xattr_arg xarg; + page =3D f2fs_new_inode_page(inode); if (IS_ERR(page)) return page; @@ -555,12 +557,16 @@ struct page *f2fs_init_inode_metadata(struct inode *i= node, struct inode *dir, put_page(page); } =20 - err =3D f2fs_init_acl(inode, dir, page, dpage); + err =3D f2fs_init_acl(inode, dir, page, dpage, true); if (err) goto put_error; =20 + xarg.page =3D page; + xarg.locked =3D true; + err =3D f2fs_init_security(inode, dir, - fname ? fname->usr_fname : NULL, page); + fname ? fname->usr_fname : NULL, + &xarg); if (err) goto put_error; =20 @@ -775,18 +781,20 @@ int f2fs_add_dentry(struct inode *dir, const struct f= 2fs_filename *fname, { int err =3D -EAGAIN; =20 + f2fs_down_read(&F2FS_I(dir)->i_sem); + if (f2fs_has_inline_dentry(dir)) { /* - * Should get i_xattr_sem to keep the lock order: - * i_xattr_sem -> inode_page lock used by f2fs_setxattr. + * Should get i_sem to keep the lock order: + * i_sem -> inode_page lock used by f2fs_setxattr. */ - f2fs_down_read(&F2FS_I(dir)->i_xattr_sem); err =3D f2fs_add_inline_entry(dir, fname, inode, ino, mode); - f2fs_up_read(&F2FS_I(dir)->i_xattr_sem); } if (err =3D=3D -EAGAIN) err =3D f2fs_add_regular_entry(dir, fname, inode, ino, mode); =20 + f2fs_up_read(&F2FS_I(dir)->i_sem); + f2fs_update_time(F2FS_I_SB(dir), REQ_TIME); return err; } @@ -835,6 +843,7 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *= dir) struct page *page; int err =3D 0; =20 + f2fs_down_write(&F2FS_I(dir)->i_sem); f2fs_down_write(&F2FS_I(inode)->i_sem); page =3D f2fs_init_inode_metadata(inode, dir, NULL, NULL); if (IS_ERR(page)) { @@ -847,6 +856,7 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *= dir) f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); fail: f2fs_up_write(&F2FS_I(inode)->i_sem); + f2fs_up_write(&F2FS_I(dir)->i_sem); return err; } =20 diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index c7cb2177b252..60ec032be48d 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -838,7 +838,6 @@ struct f2fs_inode_info { =20 /* avoid racing between foreground op and gc */ struct f2fs_rwsem i_gc_rwsem[2]; - struct f2fs_rwsem i_xattr_sem; /* avoid racing between reading and changi= ng EAs */ =20 int i_extra_isize; /* size of extra space located in i_addr */ kprojid_t i_projid; /* id for project quota */ diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index ca31163da00a..c72fda24cffd 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1418,7 +1418,6 @@ static struct inode *f2fs_alloc_inode(struct super_bl= ock *sb) INIT_LIST_HEAD(&fi->gdirty_list); init_f2fs_rwsem(&fi->i_gc_rwsem[READ]); init_f2fs_rwsem(&fi->i_gc_rwsem[WRITE]); - init_f2fs_rwsem(&fi->i_xattr_sem); =20 /* Will be used by directory only */ fi->i_dir_level =3D F2FS_SB(sb)->dir_level; @@ -3163,7 +3162,7 @@ static int f2fs_get_context(struct inode *inode, void= *ctx, size_t len) { return f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, - ctx, len, NULL); + ctx, len, NULL, false); } =20 static int f2fs_set_context(struct inode *inode, const void *ctx, size_t l= en, @@ -3183,7 +3182,7 @@ static int f2fs_set_context(struct inode *inode, cons= t void *ctx, size_t len, =20 return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, - ctx, len, fs_data, XATTR_CREATE); + ctx, len, fs_data, XATTR_CREATE, true); } =20 static const union fscrypt_policy *f2fs_get_dummy_policy(struct super_bloc= k *sb) diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c index 4fc95f353a7a..e181528b1f26 100644 --- a/fs/f2fs/verity.c +++ b/fs/f2fs/verity.c @@ -181,7 +181,7 @@ static int f2fs_end_enable_verity(struct file *filp, co= nst void *desc, /* Set the verity xattr. */ err =3D f2fs_setxattr(inode, F2FS_XATTR_INDEX_VERITY, F2FS_XATTR_NAME_VERITY, &dloc, sizeof(dloc), - NULL, XATTR_CREATE); + NULL, XATTR_CREATE, false); if (err) goto cleanup; =20 @@ -226,7 +226,8 @@ static int f2fs_get_verity_descriptor(struct inode *ino= de, void *buf, =20 /* Get the descriptor location */ res =3D f2fs_getxattr(inode, F2FS_XATTR_INDEX_VERITY, - F2FS_XATTR_NAME_VERITY, &dloc, sizeof(dloc), NULL); + F2FS_XATTR_NAME_VERITY, &dloc, sizeof(dloc), + NULL, false); if (res < 0 && res !=3D -ERANGE) return res; if (res !=3D sizeof(dloc) || dloc.version !=3D cpu_to_le32(F2FS_VERIFY_VE= R)) { diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c index 476b186b90a6..a6a611f8a771 100644 --- a/fs/f2fs/xattr.c +++ b/fs/f2fs/xattr.c @@ -61,7 +61,7 @@ static int f2fs_xattr_generic_get(const struct xattr_hand= ler *handler, return -EINVAL; } return f2fs_getxattr(inode, handler->flags, name, - buffer, size, NULL); + buffer, size, NULL, false); } =20 static int f2fs_xattr_generic_set(const struct xattr_handler *handler, @@ -84,7 +84,7 @@ static int f2fs_xattr_generic_set(const struct xattr_hand= ler *handler, return -EINVAL; } return f2fs_setxattr(inode, handler->flags, name, - value, size, NULL, flags); + value, size, NULL, flags, false); } =20 static bool f2fs_xattr_user_list(struct dentry *dentry) @@ -136,15 +136,16 @@ static int f2fs_xattr_advise_set(const struct xattr_h= andler *handler, =20 #ifdef CONFIG_F2FS_FS_SECURITY static int f2fs_initxattrs(struct inode *inode, const struct xattr *xattr_= array, - void *page) + void *fs_data) { + struct f2fs_xattr_arg *xarg =3D (struct f2fs_xattr_arg *)fs_data; const struct xattr *xattr; int err =3D 0; =20 for (xattr =3D xattr_array; xattr->name !=3D NULL; xattr++) { err =3D f2fs_setxattr(inode, F2FS_XATTR_INDEX_SECURITY, xattr->name, xattr->value, - xattr->value_len, (struct page *)page, 0); + xattr->value_len, xarg->page, 0, xarg->locked); if (err < 0) break; } @@ -152,10 +153,11 @@ static int f2fs_initxattrs(struct inode *inode, const= struct xattr *xattr_array, } =20 int f2fs_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr, struct page *ipage) + const struct qstr *qstr, + struct f2fs_xattr_arg *xarg) { return security_inode_init_security(inode, dir, qstr, - &f2fs_initxattrs, ipage); + &f2fs_initxattrs, xarg); } #endif =20 @@ -512,7 +514,8 @@ static inline int write_all_xattrs(struct inode *inode,= __u32 hsize, } =20 int f2fs_getxattr(struct inode *inode, int index, const char *name, - void *buffer, size_t buffer_size, struct page *ipage) + void *buffer, size_t buffer_size, + struct page *ipage, bool locked) { struct f2fs_xattr_entry *entry =3D NULL; int error; @@ -528,12 +531,12 @@ int f2fs_getxattr(struct inode *inode, int index, con= st char *name, if (len > F2FS_NAME_LEN) return -ERANGE; =20 - if (!ipage) - f2fs_down_read(&F2FS_I(inode)->i_xattr_sem); + if (!locked) + f2fs_down_read(&F2FS_I(inode)->i_sem); error =3D lookup_all_xattrs(inode, ipage, index, len, name, &entry, &base_addr, &base_size, &is_inline); - if (!ipage) - f2fs_up_read(&F2FS_I(inode)->i_xattr_sem); + if (!locked) + f2fs_up_read(&F2FS_I(inode)->i_sem); if (error) return error; =20 @@ -567,9 +570,9 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buf= fer, size_t buffer_size) int error; size_t rest =3D buffer_size; =20 - f2fs_down_read(&F2FS_I(inode)->i_xattr_sem); + f2fs_down_read(&F2FS_I(inode)->i_sem); error =3D read_all_xattrs(inode, NULL, &base_addr); - f2fs_up_read(&F2FS_I(inode)->i_xattr_sem); + f2fs_up_read(&F2FS_I(inode)->i_sem); if (error) return error; =20 @@ -775,7 +778,7 @@ static int __f2fs_setxattr(struct inode *inode, int ind= ex, =20 int f2fs_setxattr(struct inode *inode, int index, const char *name, const void *value, size_t size, - struct page *ipage, int flags) + struct page *ipage, int flags, bool locked) { struct f2fs_sb_info *sbi =3D F2FS_I_SB(inode); int err; @@ -796,9 +799,11 @@ int f2fs_setxattr(struct inode *inode, int index, cons= t char *name, f2fs_balance_fs(sbi, true); =20 f2fs_lock_op(sbi); - f2fs_down_write(&F2FS_I(inode)->i_xattr_sem); + if (!locked) + f2fs_down_write(&F2FS_I(inode)->i_sem); err =3D __f2fs_setxattr(inode, index, name, value, size, ipage, flags); - f2fs_up_write(&F2FS_I(inode)->i_xattr_sem); + if (!locked) + f2fs_up_write(&F2FS_I(inode)->i_sem); f2fs_unlock_op(sbi); =20 f2fs_update_time(sbi, REQ_TIME); diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h index b1811c392e6f..170e4a49af31 100644 --- a/fs/f2fs/xattr.h +++ b/fs/f2fs/xattr.h @@ -52,6 +52,11 @@ struct f2fs_xattr_entry { char e_name[]; /* attribute name */ }; =20 +struct f2fs_xattr_arg { + struct page *page; /* inode page */ + bool locked; /* indicate i_sem is locked */ +}; + #define XATTR_HDR(ptr) ((struct f2fs_xattr_header *)(ptr)) #define XATTR_ENTRY(ptr) ((struct f2fs_xattr_entry *)(ptr)) #define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr) + 1)) @@ -128,9 +133,9 @@ extern const struct xattr_handler f2fs_xattr_security_h= andler; extern const struct xattr_handler *f2fs_xattr_handlers[]; =20 extern int f2fs_setxattr(struct inode *, int, const char *, - const void *, size_t, struct page *, int); + const void *, size_t, struct page *, int, bool); extern int f2fs_getxattr(struct inode *, int, const char *, void *, - size_t, struct page *); + size_t, struct page *, bool locked); extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t); extern int f2fs_init_xattr_caches(struct f2fs_sb_info *); extern void f2fs_destroy_xattr_caches(struct f2fs_sb_info *); @@ -140,13 +145,13 @@ extern void f2fs_destroy_xattr_caches(struct f2fs_sb_= info *); #define f2fs_listxattr NULL static inline int f2fs_setxattr(struct inode *inode, int index, const char *name, const void *value, size_t size, - struct page *page, int flags) + struct page *page, int flags, bool locked) { return -EOPNOTSUPP; } static inline int f2fs_getxattr(struct inode *inode, int index, const char *name, void *buffer, - size_t buffer_size, struct page *dpage) + size_t buffer_size, struct page *dpage, bool locked) { return -EOPNOTSUPP; } @@ -156,10 +161,12 @@ static inline void f2fs_destroy_xattr_caches(struct f= 2fs_sb_info *sbi) { } =20 #ifdef CONFIG_F2FS_FS_SECURITY extern int f2fs_init_security(struct inode *, struct inode *, - const struct qstr *, struct page *); + const struct qstr *, + struct f2fs_xattr_arg *xarg); #else static inline int f2fs_init_security(struct inode *inode, struct inode *di= r, - const struct qstr *qstr, struct page *ipage) + const struct qstr *qstr, + struct f2fs_xattr_arg *xarg) { return 0; } --=20 2.40.1