Whamcloud - gitweb
LU-15097 quota: stop pool_recalc before killing pool
[fs/lustre-release.git] / lustre / quota / qmt_pool.c
index 37bb488..c4398a5 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 */
@@ -459,6 +466,8 @@ void qmt_pool_fini(const struct lu_env *env, struct qmt_device *qmt)
 
        /* parse list of pool and destroy each element */
        list_for_each_entry_safe(pool, tmp, &qmt->qmt_pool_list, qpi_linkage) {
+               /* stop all recalc threads - it may hold qpi reference */
+               qmt_stop_pool_recalc(pool);
                /* release extra reference taken in qmt_pool_alloc */
                qpi_putref(env, pool);
        }
@@ -670,6 +679,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;
        }
@@ -1155,6 +1165,13 @@ static int qmt_pool_recalc(void *args)
 
        pool = args;
 
+       rc = lu_env_init(&env, LCT_MD_THREAD);
+       if (rc) {
+               CERROR("%s: cannot init env: rc = %d\n",
+                      pool->qpi_qmt->qmt_svname, rc);
+               GOTO(out, rc);
+       }
+
        obd = qmt_get_mgc(pool->qpi_qmt);
        if (IS_ERR(obd))
                GOTO(out, rc = PTR_ERR(obd));
@@ -1164,6 +1181,7 @@ static int qmt_pool_recalc(void *args)
                while (obd->obd_process_conf)
                        schedule_timeout_uninterruptible(cfs_time_seconds(1));
 
+       OBD_FAIL_TIMEOUT(OBD_FAIL_QUOTA_RECALC, cfs_fail_val);
        sem = qmt_sarr_rwsem(pool);
        LASSERT(sem);
        down_read(sem);
@@ -1183,15 +1201,9 @@ static int qmt_pool_recalc(void *args)
         * solution looks more complex, so leave it as it is. */
        down_write(&pool->qpi_recalc_sem);
 
-       rc = lu_env_init(&env, LCT_MD_THREAD);
-       if (rc) {
-               CERROR("%s: cannot init env: rc = %d\n", obd->obd_name, rc);
-               GOTO(out, rc);
-       }
-
        glbl_pool = qmt_pool_lookup_glb(&env, pool->qpi_qmt, pool->qpi_rtype);
        if (IS_ERR(glbl_pool))
-               GOTO(out_env, rc = PTR_ERR(glbl_pool));
+               GOTO(out, rc = PTR_ERR(glbl_pool));
 
        slaves_cnt = qmt_sarr_count(pool);
        CDEBUG(D_QUOTA, "Starting pool recalculation for %d slaves in %s\n",
@@ -1237,8 +1249,6 @@ static int qmt_pool_recalc(void *args)
        GOTO(out_stop, rc);
 out_stop:
        qpi_putref(&env, glbl_pool);
-out_env:
-       lu_env_fini(&env);
 out:
        if (xchg(&pool->qpi_recalc_task, NULL) == NULL)
                /*
@@ -1251,12 +1261,20 @@ out:
 
        clear_bit(QPI_FLAG_RECALC_OFFSET, &pool->qpi_flags);
        /* Pool can't be changed, since sem has been down.
-        * Thus until up_read, no one can restart recalc thread. */
+        * Thus until up_read, no one can restart recalc thread.
+        */
        if (sem) {
                up_read(sem);
                up_write(&pool->qpi_recalc_sem);
        }
-       qpi_putref(&env, pool);
+
+       /* qpi_getref has been called in qmt_start_pool_recalc,
+        * however we can't call qpi_putref if lu_env_init failed.
+        */
+       if (env.le_ctx.lc_state == LCS_ENTERED) {
+               qpi_putref(&env, pool);
+               lu_env_fini(&env);
+       }
 
        return rc;
 }
@@ -1349,6 +1367,9 @@ static int qmt_pool_add_rem(struct obd_device *obd, char *poolname,
        int                      rc, idx;
        ENTRY;
 
+       if (qmt->qmt_stopping)
+               RETURN(0);
+
        if (strnlen(poolname, LOV_MAXPOOLNAME + 1) > LOV_MAXPOOLNAME)
                RETURN(-ENAMETOOLONG);