From: Andrew Perepechko Date: Mon, 31 Jan 2022 16:55:31 +0000 (+0300) Subject: LU-15404 ldiskfs: truncate during setxattr leads to kernel panic X-Git-Tag: 2.15.0-RC1~2 X-Git-Url: https://git.whamcloud.com/gitweb?a=commitdiff_plain;h=e239a14001b62d96c186ae2c9f58402f73e63dcc;p=fs%2Flustre-release.git LU-15404 ldiskfs: truncate during setxattr leads to kernel panic When changing a large xattr value to a different large xattr value, the old xattr inode is freed. Truncate during the final iput causes current transaction restart. Eventually, parent inode bh is marked dirty and kernel panic happens when jbd2 figures out that this bh belongs to the committed transaction. A possible fix is to call this final iput in a separate thread. This way, setxattr transactions will never be split into two. Since the setxattr code adds xattr inodes with nlink=0 into the orphan list, old xattr inodes will be properly cleaned up in any case. Change-Id: Idd70befa6a83818ece06daccf9bb6256812674b9 Signed-off-by: Andrew Perepechko HPE-bug-id: LUS-10534 Reviewed-on: https://review.whamcloud.com/46358 Reviewed-by: Andreas Dilger Reviewed-by: Alexander Zarochentsev Tested-by: jenkins Tested-by: Maloo Reviewed-by: Oleg Drokin --- diff --git a/ldiskfs/kernel_patches/patches/base/ext4-delayed-iput.patch b/ldiskfs/kernel_patches/patches/base/ext4-delayed-iput.patch new file mode 100644 index 0000000..7543cce --- /dev/null +++ b/ldiskfs/kernel_patches/patches/base/ext4-delayed-iput.patch @@ -0,0 +1,79 @@ +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 1ac2f2cdc..197dd546d 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -972,6 +972,8 @@ static void ext4_put_super(struct super_block *sb) + int aborted = 0; + int i, err; + ++ flush_scheduled_work(); ++ + ext4_unregister_li_request(sb); + ext4_quota_off_umount(sb); + +diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c +index 491f9ee40..6a77f12d1 100644 +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -1551,6 +1551,31 @@ static int ext4_xattr_inode_lookup_create(handle_t *handle, struct inode *inode, + return 0; + } + ++struct delayed_iput_work { ++ struct work_struct work; ++ struct inode *inode; ++}; ++ ++static void delayed_iput_fn(struct work_struct *work) ++{ ++ struct delayed_iput_work *diwork; ++ ++ diwork = container_of(work, struct delayed_iput_work, work); ++ iput(diwork->inode); ++ kfree(diwork); ++} ++ ++static void delayed_iput(struct inode *inode, struct delayed_iput_work *work) ++{ ++ if (!work) { ++ iput(inode); ++ } else { ++ INIT_WORK(&work->work, delayed_iput_fn); ++ work->inode = inode; ++ schedule_work(&work->work); ++ } ++} ++ + /* + * Reserve min(block_size/8, 1024) bytes for xattr entries/names if ea_inode + * feature is enabled. +@@ -1568,6 +1593,7 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i, + int in_inode = i->in_inode; + struct inode *old_ea_inode = NULL; + struct inode *new_ea_inode = NULL; ++ struct delayed_iput_work *diwork = NULL; + size_t old_size, new_size; + int ret; + +@@ -1644,7 +1670,11 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i, + * Finish that work before doing any modifications to the xattr data. + */ + if (!s->not_found && here->e_value_inum) { +- ret = ext4_xattr_inode_iget(inode, ++ diwork = kmalloc(sizeof(*diwork), GFP_NOFS); ++ if (!diwork) ++ ret = -ENOMEM; ++ else ++ ret = ext4_xattr_inode_iget(inode, + le32_to_cpu(here->e_value_inum), + le32_to_cpu(here->e_hash), + &old_ea_inode); +@@ -1797,7 +1827,7 @@ update_hash: + + ret = 0; + out: +- iput(old_ea_inode); ++ delayed_iput(old_ea_inode, diwork); + iput(new_ea_inode); + return ret; + } diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.1.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.1.series index 2b9b8be..dd0475e 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.1.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.1.series @@ -29,3 +29,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch rhel8/linux-5.4/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.2.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.2.series index ffcd76b..e5911c2 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.2.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.2.series @@ -29,3 +29,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch rhel8/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.3.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.3.series index 9dffa05..8092cd9 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.3.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.3.series @@ -29,3 +29,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch rhel8/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.4.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.4.series index f5b966c..97a3200 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.4.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.4.series @@ -29,3 +29,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch rhel8.4/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.5.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.5.series index a739214..0a5a156 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.5.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.5.series @@ -29,3 +29,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch rhel8.5/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.series index 1f9a593..2bfffb9 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.series @@ -31,3 +31,4 @@ base/ext4-reset-exts-for-gcc10.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch ubuntu18/ext4-projid-xattrs.patch rhel8/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-42-ubuntu20.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-42-ubuntu20.series index 4843c9b..40732f0 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-42-ubuntu20.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-42-ubuntu20.series @@ -30,3 +30,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch linux-5.4/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-66-ubuntu20.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-66-ubuntu20.series index e9d7770..f00707c 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-66-ubuntu20.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-66-ubuntu20.series @@ -30,3 +30,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch linux-5.4/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-80-ubuntu20.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-80-ubuntu20.series index 105612b..a468bb0 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-80-ubuntu20.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-80-ubuntu20.series @@ -30,3 +30,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch linux-5.4/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-90-ubuntu20.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-90-ubuntu20.series index da2b6ee..8960c0b 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-90-ubuntu20.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-90-ubuntu20.series @@ -30,3 +30,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch linux-5.4/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-ml.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-ml.series index 424ae1c..d79ae0f 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-ml.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-ml.series @@ -30,3 +30,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch linux-5.4/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.136-ml.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.136-ml.series index 834806c..ce959ff 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.136-ml.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.136-ml.series @@ -30,3 +30,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch linux-5.4/ext4-enc-flag.patch +base/ext4-delayed-iput.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.21-ml.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.21-ml.series index 4843c9b..40732f0 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.21-ml.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.21-ml.series @@ -30,3 +30,4 @@ base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch linux-5.4/ext4-enc-flag.patch +base/ext4-delayed-iput.patch