All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jaegeuk Kim <jaegeuk@kernel.org>
To: Chao Yu <chao@kernel.org>
Cc: linux-kernel@vger.kernel.org, stable@vger.kernel.org,
	linux-f2fs-devel@lists.sourceforge.net
Subject: Re: [f2fs-dev] [PATCH] f2fs: remove i_xattr_sem to avoid deadlock and fix the original issue
Date: Wed, 28 Jun 2023 01:07:14 -0700	[thread overview]
Message-ID: <ZJvqMpWiit24BnXL@google.com> (raw)
In-Reply-To: <8a370c8e-3b5f-5ea7-5839-76896d1ec69e@kernel.org>

On 06/27, Chao Yu wrote:
> On 2023/6/26 21:11, Jaegeuk Kim wrote:
> > On 06/25, Chao Yu wrote:
> > > On 2023/6/25 15:26, Chao Yu wrote:
> > > > One concern below:
> > > > 
> > > > Thread A:                    Thread B:
> > > > - f2fs_getxattr
> > > >    - lookup_all_xattrs
> > > >     - read_inline_xattr
> > > >      - f2fs_get_node_page(ino)
> > > >      - memcpy inline xattr
> > > >      - f2fs_put_page
> > > >                           - f2fs_setxattr
> > > >                            - __f2fs_setxattr
> > > >                             - __f2fs_setxattr
> > > >                              - write_all_xattrs
> > > >                               - write xnode and inode
> > > >     ---> inline xattr may out of update here.
> > > >     - read_xattr_block
> > > >      - f2fs_get_node_page(xnid)
> > > >      - memcpy xnode xattr
> > > >      - f2fs_put_page
> > > > 
> > > > Do we need to keep xattr_{get,set} being atomical operation?
> > > 
> > > It seems xfstest starts to complain w/ below message...
> > 
> > I don't see any failure. Which test do you see?
> 
> 051, 083, ... 467, 642
> 
> Testcase doesn't fail, but kernel log shows inode has corrupted xattr.

I got it. It seems I had to fix the above issue only while keeping the sem. :(

> 
> > 
> > > 
> > > [ 3400.856443] F2FS-fs (vdc): inode (2187) has invalid last xattr entry, entry_size: 21468
> > > [ 3400.864042] F2FS-fs (vdc): inode (1595) has invalid last xattr entry, entry_size: 26580
> > > [ 3400.865764] F2FS-fs (vdc): inode (2187) has invalid last xattr entry, entry_size: 21468
> > > [ 3400.880067] F2FS-fs (vdc): inode (9839) has corrupted xattr
> > > [ 3400.880714] F2FS-fs (vdc): inode (10855) has corrupted xattr
> > > 
> > > Thanks,
> > > 
> > > > 
> > > > Thanks,
> > > > 
> > > > > 
> > > > > I think we don't need to truncate xattr pages eagerly which introduces lots of
> > > > > data races without big benefits.
> > > > > 
> > > > > Cc: <stable@vger.kernel.org>
> > > > > Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> > > > > ---
> > > > >    fs/f2fs/f2fs.h  |  1 -
> > > > >    fs/f2fs/super.c |  1 -
> > > > >    fs/f2fs/xattr.c | 31 ++++++++-----------------------
> > > > >    3 files changed, 8 insertions(+), 25 deletions(-)
> > > > > 
> > > > > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > > > > index 3f5b161dd743..7b9af2d51656 100644
> > > > > --- a/fs/f2fs/f2fs.h
> > > > > +++ b/fs/f2fs/f2fs.h
> > > > > @@ -838,7 +838,6 @@ struct f2fs_inode_info {
> > > > >        /* 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 changing EAs */
> > > > >        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 1b2c788ed80d..c917fa771f0e 100644
> > > > > --- a/fs/f2fs/super.c
> > > > > +++ b/fs/f2fs/super.c
> > > > > @@ -1418,7 +1418,6 @@ static struct inode *f2fs_alloc_inode(struct super_block *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);
> > > > >        /* Will be used by directory only */
> > > > >        fi->i_dir_level = F2FS_SB(sb)->dir_level;
> > > > > diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
> > > > > index 213805d3592c..bdc8a55085a2 100644
> > > > > --- a/fs/f2fs/xattr.c
> > > > > +++ b/fs/f2fs/xattr.c
> > > > > @@ -433,7 +433,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
> > > > >    {
> > > > >        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> > > > >        size_t inline_size = inline_xattr_size(inode);
> > > > > -    struct page *in_page = NULL;
> > > > > +    struct page *in_page = ipage;
> > > > >        void *xattr_addr;
> > > > >        void *inline_addr = NULL;
> > > > >        struct page *xpage;
> > > > > @@ -446,29 +446,19 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
> > > > >        /* write to inline xattr */
> > > > >        if (inline_size) {
> > > > > -        if (ipage) {
> > > > > -            inline_addr = inline_xattr_addr(inode, ipage);
> > > > > -        } else {
> > > > > +        if (!in_page) {
> > > > >                in_page = f2fs_get_node_page(sbi, inode->i_ino);
> > > > >                if (IS_ERR(in_page)) {
> > > > >                    f2fs_alloc_nid_failed(sbi, new_nid);
> > > > >                    return PTR_ERR(in_page);
> > > > >                }
> > > > > -            inline_addr = inline_xattr_addr(inode, in_page);
> > > > >            }
> > > > > +        inline_addr = inline_xattr_addr(inode, in_page);
> > > > > -        f2fs_wait_on_page_writeback(ipage ? ipage : in_page,
> > > > > -                            NODE, true, true);
> > > > > -        /* no need to use xattr node block */
> > > > > +        f2fs_wait_on_page_writeback(in_page, NODE, true, true);
> > > > >            if (hsize <= inline_size) {
> > > > > -            err = f2fs_truncate_xattr_node(inode);
> > > > > -            f2fs_alloc_nid_failed(sbi, new_nid);
> > > > > -            if (err) {
> > > > > -                f2fs_put_page(in_page, 1);
> > > > > -                return err;
> > > > > -            }
> > > > >                memcpy(inline_addr, txattr_addr, inline_size);
> > > > > -            set_page_dirty(ipage ? ipage : in_page);
> > > > > +            set_page_dirty(in_page);
> > > > >                goto in_page_out;
> > > > >            }
> > > > >        }
> > > > > @@ -502,12 +492,13 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
> > > > >        memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE);
> > > > >        if (inline_size)
> > > > > -        set_page_dirty(ipage ? ipage : in_page);
> > > > > +        set_page_dirty(in_page);
> > > > >        set_page_dirty(xpage);
> > > > >        f2fs_put_page(xpage, 1);
> > > > >    in_page_out:
> > > > > -    f2fs_put_page(in_page, 1);
> > > > > +    if (in_page != ipage)
> > > > > +        f2fs_put_page(in_page, 1);
> > > > >        return err;
> > > > >    }
> > > > > @@ -528,10 +519,8 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
> > > > >        if (len > F2FS_NAME_LEN)
> > > > >            return -ERANGE;
> > > > > -    f2fs_down_read(&F2FS_I(inode)->i_xattr_sem);
> > > > >        error = lookup_all_xattrs(inode, ipage, index, len, name,
> > > > >                    &entry, &base_addr, &base_size, &is_inline);
> > > > > -    f2fs_up_read(&F2FS_I(inode)->i_xattr_sem);
> > > > >        if (error)
> > > > >            return error;
> > > > > @@ -565,9 +554,7 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
> > > > >        int error;
> > > > >        size_t rest = buffer_size;
> > > > > -    f2fs_down_read(&F2FS_I(inode)->i_xattr_sem);
> > > > >        error = read_all_xattrs(inode, NULL, &base_addr);
> > > > > -    f2fs_up_read(&F2FS_I(inode)->i_xattr_sem);
> > > > >        if (error)
> > > > >            return error;
> > > > > @@ -794,9 +781,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
> > > > >        f2fs_balance_fs(sbi, true);
> > > > >        f2fs_lock_op(sbi);
> > > > > -    f2fs_down_write(&F2FS_I(inode)->i_xattr_sem);
> > > > >        err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags);
> > > > > -    f2fs_up_write(&F2FS_I(inode)->i_xattr_sem);
> > > > >        f2fs_unlock_op(sbi);
> > > > >        f2fs_update_time(sbi, REQ_TIME);
> > > > 
> > > > 
> > > > _______________________________________________
> > > > Linux-f2fs-devel mailing list
> > > > Linux-f2fs-devel@lists.sourceforge.net
> > > > https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

WARNING: multiple messages have this Message-ID (diff)
From: Jaegeuk Kim <jaegeuk@kernel.org>
To: Chao Yu <chao@kernel.org>
Cc: linux-kernel@vger.kernel.org,
	linux-f2fs-devel@lists.sourceforge.net, stable@vger.kernel.org
Subject: Re: [f2fs-dev] [PATCH] f2fs: remove i_xattr_sem to avoid deadlock and fix the original issue
Date: Wed, 28 Jun 2023 01:07:14 -0700	[thread overview]
Message-ID: <ZJvqMpWiit24BnXL@google.com> (raw)
In-Reply-To: <8a370c8e-3b5f-5ea7-5839-76896d1ec69e@kernel.org>

On 06/27, Chao Yu wrote:
> On 2023/6/26 21:11, Jaegeuk Kim wrote:
> > On 06/25, Chao Yu wrote:
> > > On 2023/6/25 15:26, Chao Yu wrote:
> > > > One concern below:
> > > > 
> > > > Thread A:                    Thread B:
> > > > - f2fs_getxattr
> > > >    - lookup_all_xattrs
> > > >     - read_inline_xattr
> > > >      - f2fs_get_node_page(ino)
> > > >      - memcpy inline xattr
> > > >      - f2fs_put_page
> > > >                           - f2fs_setxattr
> > > >                            - __f2fs_setxattr
> > > >                             - __f2fs_setxattr
> > > >                              - write_all_xattrs
> > > >                               - write xnode and inode
> > > >     ---> inline xattr may out of update here.
> > > >     - read_xattr_block
> > > >      - f2fs_get_node_page(xnid)
> > > >      - memcpy xnode xattr
> > > >      - f2fs_put_page
> > > > 
> > > > Do we need to keep xattr_{get,set} being atomical operation?
> > > 
> > > It seems xfstest starts to complain w/ below message...
> > 
> > I don't see any failure. Which test do you see?
> 
> 051, 083, ... 467, 642
> 
> Testcase doesn't fail, but kernel log shows inode has corrupted xattr.

I got it. It seems I had to fix the above issue only while keeping the sem. :(

> 
> > 
> > > 
> > > [ 3400.856443] F2FS-fs (vdc): inode (2187) has invalid last xattr entry, entry_size: 21468
> > > [ 3400.864042] F2FS-fs (vdc): inode (1595) has invalid last xattr entry, entry_size: 26580
> > > [ 3400.865764] F2FS-fs (vdc): inode (2187) has invalid last xattr entry, entry_size: 21468
> > > [ 3400.880067] F2FS-fs (vdc): inode (9839) has corrupted xattr
> > > [ 3400.880714] F2FS-fs (vdc): inode (10855) has corrupted xattr
> > > 
> > > Thanks,
> > > 
> > > > 
> > > > Thanks,
> > > > 
> > > > > 
> > > > > I think we don't need to truncate xattr pages eagerly which introduces lots of
> > > > > data races without big benefits.
> > > > > 
> > > > > Cc: <stable@vger.kernel.org>
> > > > > Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
> > > > > ---
> > > > >    fs/f2fs/f2fs.h  |  1 -
> > > > >    fs/f2fs/super.c |  1 -
> > > > >    fs/f2fs/xattr.c | 31 ++++++++-----------------------
> > > > >    3 files changed, 8 insertions(+), 25 deletions(-)
> > > > > 
> > > > > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> > > > > index 3f5b161dd743..7b9af2d51656 100644
> > > > > --- a/fs/f2fs/f2fs.h
> > > > > +++ b/fs/f2fs/f2fs.h
> > > > > @@ -838,7 +838,6 @@ struct f2fs_inode_info {
> > > > >        /* 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 changing EAs */
> > > > >        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 1b2c788ed80d..c917fa771f0e 100644
> > > > > --- a/fs/f2fs/super.c
> > > > > +++ b/fs/f2fs/super.c
> > > > > @@ -1418,7 +1418,6 @@ static struct inode *f2fs_alloc_inode(struct super_block *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);
> > > > >        /* Will be used by directory only */
> > > > >        fi->i_dir_level = F2FS_SB(sb)->dir_level;
> > > > > diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
> > > > > index 213805d3592c..bdc8a55085a2 100644
> > > > > --- a/fs/f2fs/xattr.c
> > > > > +++ b/fs/f2fs/xattr.c
> > > > > @@ -433,7 +433,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
> > > > >    {
> > > > >        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> > > > >        size_t inline_size = inline_xattr_size(inode);
> > > > > -    struct page *in_page = NULL;
> > > > > +    struct page *in_page = ipage;
> > > > >        void *xattr_addr;
> > > > >        void *inline_addr = NULL;
> > > > >        struct page *xpage;
> > > > > @@ -446,29 +446,19 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
> > > > >        /* write to inline xattr */
> > > > >        if (inline_size) {
> > > > > -        if (ipage) {
> > > > > -            inline_addr = inline_xattr_addr(inode, ipage);
> > > > > -        } else {
> > > > > +        if (!in_page) {
> > > > >                in_page = f2fs_get_node_page(sbi, inode->i_ino);
> > > > >                if (IS_ERR(in_page)) {
> > > > >                    f2fs_alloc_nid_failed(sbi, new_nid);
> > > > >                    return PTR_ERR(in_page);
> > > > >                }
> > > > > -            inline_addr = inline_xattr_addr(inode, in_page);
> > > > >            }
> > > > > +        inline_addr = inline_xattr_addr(inode, in_page);
> > > > > -        f2fs_wait_on_page_writeback(ipage ? ipage : in_page,
> > > > > -                            NODE, true, true);
> > > > > -        /* no need to use xattr node block */
> > > > > +        f2fs_wait_on_page_writeback(in_page, NODE, true, true);
> > > > >            if (hsize <= inline_size) {
> > > > > -            err = f2fs_truncate_xattr_node(inode);
> > > > > -            f2fs_alloc_nid_failed(sbi, new_nid);
> > > > > -            if (err) {
> > > > > -                f2fs_put_page(in_page, 1);
> > > > > -                return err;
> > > > > -            }
> > > > >                memcpy(inline_addr, txattr_addr, inline_size);
> > > > > -            set_page_dirty(ipage ? ipage : in_page);
> > > > > +            set_page_dirty(in_page);
> > > > >                goto in_page_out;
> > > > >            }
> > > > >        }
> > > > > @@ -502,12 +492,13 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
> > > > >        memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE);
> > > > >        if (inline_size)
> > > > > -        set_page_dirty(ipage ? ipage : in_page);
> > > > > +        set_page_dirty(in_page);
> > > > >        set_page_dirty(xpage);
> > > > >        f2fs_put_page(xpage, 1);
> > > > >    in_page_out:
> > > > > -    f2fs_put_page(in_page, 1);
> > > > > +    if (in_page != ipage)
> > > > > +        f2fs_put_page(in_page, 1);
> > > > >        return err;
> > > > >    }
> > > > > @@ -528,10 +519,8 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
> > > > >        if (len > F2FS_NAME_LEN)
> > > > >            return -ERANGE;
> > > > > -    f2fs_down_read(&F2FS_I(inode)->i_xattr_sem);
> > > > >        error = lookup_all_xattrs(inode, ipage, index, len, name,
> > > > >                    &entry, &base_addr, &base_size, &is_inline);
> > > > > -    f2fs_up_read(&F2FS_I(inode)->i_xattr_sem);
> > > > >        if (error)
> > > > >            return error;
> > > > > @@ -565,9 +554,7 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
> > > > >        int error;
> > > > >        size_t rest = buffer_size;
> > > > > -    f2fs_down_read(&F2FS_I(inode)->i_xattr_sem);
> > > > >        error = read_all_xattrs(inode, NULL, &base_addr);
> > > > > -    f2fs_up_read(&F2FS_I(inode)->i_xattr_sem);
> > > > >        if (error)
> > > > >            return error;
> > > > > @@ -794,9 +781,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
> > > > >        f2fs_balance_fs(sbi, true);
> > > > >        f2fs_lock_op(sbi);
> > > > > -    f2fs_down_write(&F2FS_I(inode)->i_xattr_sem);
> > > > >        err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags);
> > > > > -    f2fs_up_write(&F2FS_I(inode)->i_xattr_sem);
> > > > >        f2fs_unlock_op(sbi);
> > > > >        f2fs_update_time(sbi, REQ_TIME);
> > > > 
> > > > 
> > > > _______________________________________________
> > > > Linux-f2fs-devel mailing list
> > > > Linux-f2fs-devel@lists.sourceforge.net
> > > > https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

  reply	other threads:[~2023-06-28  8:07 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-06-13 23:39 [f2fs-dev] [PATCH] f2fs: remove i_xattr_sem to avoid deadlock and fix the original issue Jaegeuk Kim
2023-06-13 23:39 ` Jaegeuk Kim
2023-06-15 18:00 ` [f2fs-dev] " patchwork-bot+f2fs
2023-06-15 18:00   ` patchwork-bot+f2fs
2023-06-25  7:26 ` Chao Yu
2023-06-25  7:26   ` Chao Yu
2023-06-25 10:27   ` Chao Yu
2023-06-25 10:27     ` Chao Yu
2023-06-26 13:11     ` Jaegeuk Kim
2023-06-26 13:11       ` Jaegeuk Kim
2023-06-27 13:37       ` Chao Yu
2023-06-27 13:37         ` Chao Yu
2023-06-28  8:07         ` Jaegeuk Kim [this message]
2023-06-28  8:07           ` Jaegeuk Kim
2023-06-28  8:08   ` [f2fs-dev] [PATCH v2] f2fs: fix deadlock in i_xattr_sem and inode page lock " Jaegeuk Kim
2023-06-28  8:08     ` Jaegeuk Kim
2023-06-28  8:36     ` [f2fs-dev] " Chao Yu
2023-06-28  8:36       ` Chao Yu
2023-06-28 18:33       ` [f2fs-dev] " Jaegeuk Kim
2023-06-28 18:33         ` Jaegeuk Kim
2023-06-30 21:59         ` [f2fs-dev] " Jaegeuk Kim
2023-06-30 21:59           ` Jaegeuk Kim
2023-06-30 23:36           ` Chao Yu
2023-06-30 23:36             ` Chao Yu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ZJvqMpWiit24BnXL@google.com \
    --to=jaegeuk@kernel.org \
    --cc=chao@kernel.org \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.