Whamcloud - gitweb
LU-13587 quota: protect qpi in proc 87/43987/15
authorSergey Cheremencev <sergey.cheremencev@hpe.com>
Thu, 15 Apr 2021 14:14:51 +0000 (17:14 +0300)
committerOleg Drokin <green@whamcloud.com>
Thu, 6 Jan 2022 21:59:22 +0000 (21:59 +0000)
Access to pool info only when pool is fully inited.
This patch protects from following panic:

[212010.467347] BUG: unable to handle kernel NULL pointer dereference at           (null)
[212010.468205] IP: [<ffffffffc0e55e46>] qpi_state_seq_show+0x86/0xe0 [lquota]
...
[212010.486786] Call Trace:
[212010.487344]  [<ffffffffbbc68b50>] seq_read+0x130/0x440
[212010.487741]  [<ffffffffbbcb8380>] proc_reg_read+0x40/0x80
[212010.488445]  [<ffffffffbbc4118f>] vfs_read+0x9f/0x170
[212010.489056]  [<ffffffffbbc4204f>] SyS_read+0x7f/0xf0
[212010.489920]  [<ffffffffbc176ddb>] system_call_fastpath+0x22/0x27
[212010.490861] Code: 5c a8 01 00 00 41 8b 8c 1c c0 01 00 00 48 c7 c6 18
[212010.493235] RIP  [<ffffffffc0e55e46>] qpi_state_seq_show+0x86/0xe0 [lquota]
[212010.493672] RSP <ffff908505747e28>
[212010.494161] CR2: 0000000000000000

Add test 79 to sanity-quota to check that race between
access to /proc/.../dt-pool_name/info of non-existed pool
with this pool creating doesn't cause a panic.

HPE-bug-id: LUS-9938
Change-Id: I8eff846c6c3881a8431a98efb54e660ecb9155bf
Signed-off-by: Sergey Cheremencev <sergey.cheremencev@hpe.com>
Reviewed-on: https://review.whamcloud.com/43987
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Patrick Farrell <pfarrell@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/quota/qmt_internal.h
lustre/quota/qmt_pool.c
lustre/tests/sanity-quota.sh

index 7d3b7ce..72b4c22 100644 (file)
@@ -100,6 +100,7 @@ enum {
 enum {
        /* set while recalc_thread is working */
        QPI_FLAG_RECALC_OFFSET,
+       QPI_FLAG_STATE_INITED,
 };
 
 /*
index 7bb1ee3..bf9241c 100644 (file)
@@ -79,6 +79,8 @@ static int qpi_state_seq_show(struct seq_file *m, void *data)
        int                      type;
 
        LASSERT(pool != NULL);
+       if (unlikely(!test_bit(QPI_FLAG_STATE_INITED, &pool->qpi_flags)))
+               return -ENOENT;
 
        seq_printf(m, "pool:\n"
                   "    id: %u\n"
@@ -106,6 +108,8 @@ static int qpi_soft_least_qunit_seq_show(struct seq_file *m, void *data)
 {
        struct qmt_pool_info    *pool = m->private;
        LASSERT(pool != NULL);
+       if (unlikely(!test_bit(QPI_FLAG_STATE_INITED, &pool->qpi_flags)))
+               return -ENOENT;
 
        seq_printf(m, "%lu\n", pool->qpi_soft_least_qunit);
        return 0;
@@ -121,6 +125,8 @@ qpi_soft_least_qunit_seq_write(struct file *file, const char __user *buffer,
        int rc;
 
        LASSERT(pool != NULL);
+       if (unlikely(!test_bit(QPI_FLAG_STATE_INITED, &pool->qpi_flags)))
+               return -ENOENT;
 
        /* Not tuneable for inode limit */
        if (pool->qpi_rtype != LQUOTA_RES_DT)
@@ -177,6 +183,7 @@ static int qmt_pool_alloc(const struct lu_env *env, struct qmt_device *qmt,
        init_rwsem(&pool->qpi_recalc_sem);
 
        pool->qpi_rtype = pool_type;
+       pool->qpi_flags = 0;
 
        /* initialize refcount to 1, hash table will then grab an additional
         * reference */
@@ -670,6 +677,7 @@ int qmt_pool_prepare(const struct lu_env *env, struct qmt_device *qmt,
                                      qmt->qmt_svname, PFID(&qti->qti_fid), rc);
 #endif
                }
+               set_bit(QPI_FLAG_STATE_INITED, &pool->qpi_flags);
                if (name)
                        break;
        }
index 52b820b..614fd46 100755 (executable)
@@ -5105,6 +5105,22 @@ test_78()
 }
 run_test 78 "Check fallocate increase quota usage"
 
+test_79()
+{
+       local qpool="qpool1"
+       local cmd="$LCTL get_param -n qmt.$FSNAME-QMT0000.dt-$qpool.info"
+       local stopf=$TMP/$tfile
+
+       do_facet mds1 "touch $stopf"
+       stack_trap "do_facet mds1 'rm -f $stopf'"
+       do_facet mds1 "while [ -e $stopf ]; do $cmd &>/dev/null; done"&
+       local pid=$!
+       pool_add $qpool || error "pool_add failed"
+       do_facet mds1 "rm $stopf"
+       wait $pid
+}
+run_test 79 "access to non-existed dt-pool/info doesn't cause a panic"
+
 quota_fini()
 {
        do_nodes $(comma_list $(nodes_list)) \