Whamcloud - gitweb
LU-12755 ldiskfs: fix project quota unpon unpatched kernel 70/36270/4
authorWang Shilong <wshilong@ddn.com>
Mon, 23 Sep 2019 16:34:24 +0000 (09:34 -0700)
committerOleg Drokin <green@whamcloud.com>
Fri, 4 Oct 2019 20:30:25 +0000 (20:30 +0000)
The value of MAXQUOTAS is the number of quota types supported
by kernel. With project quotas patch applied, MAXQUOTAS is
equal to EXT4_MAXQUOTAS. However, on an unpatched kernel,
project quota type is not supported and MAXQUOTAS is one less
than EXT4_MAXQUOTAS.

In ldiskfs, we need to make sure that the loop in
ext4_quota_off_umount() is limiting the EXT4_MAXQUOTAS loop
to the kernel MAXQUOTAS value. Otherwise, it is trying to
dereference sb_dqopt(sb)->files[2] which is not an inode at all,
and cause the kernel stick on a spinlock in ext4_quota_off()
as follows during unmount:

Call Trace:
[<ffffffffb9d733c5>] queued_spin_lock_slowpath+0xb/0xf
[<ffffffffb9d81b30>] _raw_spin_lock+0x20/0x30
[<ffffffffb9865e2e>] igrab+0x1e/0x60
[<ffffffffc08a8c4b>] ldiskfs_quota_off+0x3b/0x130 [ldiskfs]
[<ffffffffc08abcdd>] ldiskfs_put_super+0x4d/0x400 [ldiskfs]
[<ffffffffb984b13d>] generic_shutdown_super+0x6d/0x100
[<ffffffffb984b5b7>] kill_block_super+0x27/0x70
[<ffffffffb984b91e>] deactivate_locked_super+0x4e/0x70
[<ffffffffb984c0a6>] deactivate_super+0x46/0x60
[<ffffffffb986abff>] cleanup_mnt+0x3f/0x80
[<ffffffffb986ac92>] __cleanup_mnt+0x12/0x20
[<ffffffffb96c1c0b>] task_work_run+0xbb/0xe0
[<ffffffffb962cc65>] do_notify_resume+0xa5/0xc0
[<ffffffffb9d8d23b>] int_signal+0x12/0x17

This patch is back-ported from the following one:
Lustre-commit: 4b013aa4cdc12647cb1aa9c93bdd72d741b83af4
Lustre-change: https://review.whamcloud.com/36203

Test-Parameters: clientdistro=el7.7 serverdistro=el7.7

Change-Id: I18a4d97656e2f8478754943424c0fac927f843ca
Signed-off-by: Wang Shilong <wshilong@ddn.com>
Reviewed-on: https://review.whamcloud.com/36270
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Li Xi <lixi@ddn.com>
Reviewed-by: Jian Yu <yujian@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
ldiskfs/kernel_patches/patches/rhel7.7/ext4-fix-project-with-unpatched-kernel.patch [new file with mode: 0644]
ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.7.series

diff --git a/ldiskfs/kernel_patches/patches/rhel7.7/ext4-fix-project-with-unpatched-kernel.patch b/ldiskfs/kernel_patches/patches/rhel7.7/ext4-fix-project-with-unpatched-kernel.patch
new file mode 100644 (file)
index 0000000..cf4da55
--- /dev/null
@@ -0,0 +1,96 @@
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index 388b6bcd..111ac5e1 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -1485,6 +1485,8 @@ struct ext4_sb_info {
+       struct ratelimit_state s_warning_ratelimit_state;
+       struct ratelimit_state s_msg_ratelimit_state;
+       struct dax_device *s_daxdev;
++
++      bool s_proj_kernel_supported;
+ };
+ static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index e6566eb9..ac0dd4a7 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -4390,6 +4390,17 @@ int ext4_get_projid(struct inode *inode, kprojid_t *projid)
+ {
+       struct ext4_super_block *sbi = EXT4_SB(inode->i_sb)->s_es;
++      /*
++       * This is tricky and just used to detect whether kernel
++       * supports project quota, return error to make sure dquot_initialize()
++       * doesn't do anything except calling this function.
++       */
++      if (inode->i_ino == EXT4_ROOT_INO &&
++          !EXT4_SB(inode->i_sb)->s_proj_kernel_supported) {
++              EXT4_SB(inode->i_sb)->s_proj_kernel_supported = true;
++              return -EINVAL;
++      }
++
+       if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, EXT4_FEATURE_RO_COMPAT_PROJECT) &&
+           !sbi->s_prj_quota_inum)
+               return -EOPNOTSUPP;
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 1c81d178..bb92ea94 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -819,8 +819,11 @@ static inline void ext4_quota_off_umount(struct super_block *sb)
+       int type;
+       /* Use our quota_off function to clear inode flags etc. */
+-      for (type = 0; type < EXT4_MAXQUOTAS; type++)
++      for (type = 0; type < EXT4_MAXQUOTAS; type++) {
++              if (!EXT4_SB(sb)->s_proj_kernel_supported && type == PRJQUOTA)
++                      continue;
+               ext4_quota_off(sb, type);
++      }
+ }
+ #else
+ static inline void ext4_quota_off_umount(struct super_block *sb)
+@@ -2430,6 +2433,9 @@ static void ext4_orphan_cleanup(struct super_block *sb,
+       /* Turn off quotas if they were enabled for orphan cleanup */
+       if (quota_update) {
+               for (i = 0; i < EXT4_MAXQUOTAS; i++) {
++                      if (!EXT4_SB(sb)->s_proj_kernel_supported &&
++                          i == PRJQUOTA)
++                              continue;
+                       if (sb_dqopt(sb)->files[i])
+                               dquot_quota_off(sb, i);
+               }
+@@ -3630,6 +3636,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
+       int err = 0;
+       unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
+       ext4_group_t first_not_zeroed;
++      unsigned int quota_flags;
+       if ((data && !orig_data) || !sbi)
+               goto out_free_base;
+@@ -4356,6 +4363,14 @@ no_journal:
+               root = NULL;
+               goto failed_mount4;
+       }
++      /*
++       * Enable project usage temporarily to give dquota_initialize() a
++       * chance to check whether kernel supports Project quota.
++       */
++      quota_flags = sb_dqopt(sb)->flags;
++      sb_dqopt(sb)->flags |= dquot_state_flag(DQUOT_USAGE_ENABLED, PRJQUOTA);
++      dquot_initialize(root);
++      sb_dqopt(sb)->flags = quota_flags;
+       if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
+               ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck");
+               iput(root);
+@@ -5671,6 +5686,10 @@ static int ext4_enable_quotas(struct super_block *sb)
+       sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
+       for (type = 0; type < EXT4_MAXQUOTAS; type++) {
++
++              if (!EXT4_SB(sb)->s_proj_kernel_supported && type == PRJQUOTA)
++                      continue;
++
+               if (qf_inums[type]) {
+                       err = ext4_quota_enable(sb, type, QFMT_VFS_V1,
+                                               DQUOT_USAGE_ENABLED);
index de0fcee..4a99cf2 100644 (file)
@@ -36,3 +36,4 @@ rhel7/ext4-use-GFP_NOFS-in-ext4_inode_attach_jinode.patch
 rhel7/ext4-export-orphan-add.patch
 rhel7/ext4-include-terminating-u32-in-size-of-xattr-entries-when-expanding-inodes.patch
 rhel7.2/ext4-export-mb-stream-allocator-variables.patch
+rhel7.7/ext4-fix-project-with-unpatched-kernel.patch