Whamcloud - gitweb
LU-15049 quota: fix a panic with pool number > 16
[fs/lustre-release.git] / lustre / quota / qmt_pool.c
index 93d2d44..755effd 100644 (file)
@@ -174,8 +174,6 @@ static int qmt_pool_alloc(const struct lu_env *env, struct qmt_device *qmt,
        if (pool == NULL)
                RETURN(-ENOMEM);
        INIT_LIST_HEAD(&pool->qpi_linkage);
-       init_waitqueue_head(&pool->qpi_recalc_thread.t_ctl_waitq);
-       thread_set_flags(&pool->qpi_recalc_thread, SVC_STOPPED);
        init_rwsem(&pool->qpi_recalc_sem);
 
        pool->qpi_rtype = pool_type;
@@ -314,7 +312,7 @@ static inline int qti_pools_add(const struct lu_env *env,
        LASSERTF(qti->qti_pools_num >= QMT_MAX_POOL_NUM,
                 "Forgot init? %p\n", qti);
 
-       if (qti->qti_pools_cnt > qti->qti_pools_num) {
+       if (qti->qti_pools_cnt >= qti->qti_pools_num) {
                OBD_ALLOC(pools, sizeof(qpi) * qti->qti_pools_num * 2);
                if (!pools)
                        return -ENOMEM;
@@ -394,8 +392,8 @@ struct qmt_pool_info *qmt_pool_lookup(const struct lu_env *env,
                RETURN(ERR_PTR(-ENOENT));
        }
 
-       CDEBUG(D_QUOTA, "type %d name %p index %d\n",
-              rtype, pool_name, idx);
+       CDEBUG(D_QUOTA, "type %d name %s index %d\n",
+              rtype, pool_name ?: "<none>", idx);
        /* Now just find a pool with correct type in a list. Further we need
         * to go through the list and find a pool that includes requested OST
         * or MDT. Possibly this would return a list of pools that includes
@@ -847,9 +845,14 @@ out:
 static int lqes_cmp(const void *arg1, const void *arg2)
 {
        const struct lquota_entry *lqe1, *lqe2;
-       lqe1 = arg1;
-       lqe2 = arg2;
-       return lqe1->lqe_qunit > lqe2->lqe_qunit;
+
+       lqe1 = *(const struct lquota_entry **)arg1;
+       lqe2 = *(const struct lquota_entry **)arg2;
+       if (lqe1->lqe_qunit > lqe2->lqe_qunit)
+               return 1;
+       if (lqe1->lqe_qunit < lqe2->lqe_qunit)
+               return -1;
+       return 0;
 }
 
 void qmt_lqes_sort(const struct lu_env *env)
@@ -990,7 +993,7 @@ out_env:
 
 static int
 qmt_obj_recalc(const struct lu_env *env, struct dt_object *obj,
-              struct ptlrpc_thread *thread, struct lquota_site *site)
+              struct lquota_site *site)
 {
        struct qmt_thread_info *qti = qmt_info(env);
        union lquota_id *qid = &qti->qti_id;
@@ -1054,7 +1057,7 @@ next:
                        CWARN("quota: failed to parse index "DFID
                              ", ->next error: rc = %d\n",
                              PFID(&qti->qti_fid), rc);
-       } while (rc == 0 && thread_is_running(thread));
+       } while (rc == 0 && !kthread_should_stop());
 
 out:
        iops->put(env, it);
@@ -1160,7 +1163,6 @@ static int qmt_pool_recalc(void *args)
        ENTRY;
 
        pool = args;
-       thread_set_flags(&pool->qpi_recalc_thread, SVC_RUNNING);
 
        obd = qmt_get_mgc(pool->qpi_qmt);
        if (IS_ERR(obd))
@@ -1211,7 +1213,7 @@ static int qmt_pool_recalc(void *args)
                        struct obd_uuid uuid;
                        int idx;
 
-                       if (thread_is_stopping(&pool->qpi_recalc_thread))
+                       if (kthread_should_stop())
                                GOTO(out_stop, rc = 0);
                        idx = qmt_sarr_get_idx(pool, i);
                        LASSERT(idx >= 0);
@@ -1232,9 +1234,7 @@ static int qmt_pool_recalc(void *args)
 
                        CDEBUG(D_QUOTA, "slv_obj is found %p for uuid %s\n",
                               slv_obj, uuid.uuid);
-                       qmt_obj_recalc(&env, slv_obj,
-                                      &pool->qpi_recalc_thread,
-                                      pool->qpi_site[qtype]);
+                       qmt_obj_recalc(&env, slv_obj, pool->qpi_site[qtype]);
                        dt_object_put(&env, slv_obj);
                }
                /* Now go trough the site hash and compare lqe_granted
@@ -1249,8 +1249,15 @@ out_stop:
 out_env:
        lu_env_fini(&env);
 out:
-       thread_set_flags(&pool->qpi_recalc_thread, SVC_STOPPED);
-       wake_up(&pool->qpi_recalc_thread.t_ctl_waitq);
+       if (xchg(&pool->qpi_recalc_task, NULL) == NULL)
+               /*
+                * Someone is waiting for us to stop - be sure not to exit
+                * before kthread_stop() gets a ref on the task.  No event
+                * will happen on 'pool, this is just a convenient way to
+                * wait.
+                */
+               wait_var_event(pool, kthread_should_stop());
+
        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. */
@@ -1266,29 +1273,27 @@ out:
 static int qmt_start_pool_recalc(struct lu_env *env, struct qmt_pool_info *qpi)
 {
        struct task_struct *task;
-       char *name;
        int rc = 0;
 
        if (!test_and_set_bit(QPI_FLAG_RECALC_OFFSET, &qpi->qpi_flags)) {
-               LASSERT(thread_is_stopped(&qpi->qpi_recalc_thread) ||
-                       thread_is_init(&qpi->qpi_recalc_thread));
-               OBD_ALLOC(name, QPI_MAXNAME + sizeof("qmt_pool_recalc_"));
-               if (name == NULL)
-                       RETURN(-ENOMEM);
-
-               snprintf(name, QPI_MAXNAME, "qsd_reint_%s",
-                        qpi->qpi_name);
+               LASSERT(!qpi->qpi_recalc_task);
 
                qpi_getref(qpi);
-               thread_set_flags(&qpi->qpi_recalc_thread, SVC_STARTING);
-               task = kthread_run(qmt_pool_recalc, qpi, name);
+               task = kthread_create(qmt_pool_recalc, qpi,
+                                     "qsd_reint_%s", qpi->qpi_name);
                if (IS_ERR(task)) {
-                       thread_set_flags(&qpi->qpi_recalc_thread, SVC_STOPPED);
                        clear_bit(QPI_FLAG_RECALC_OFFSET, &qpi->qpi_flags);
                        rc = PTR_ERR(task);
                        qpi_putref(env, qpi);
+               } else {
+                       qpi->qpi_recalc_task = task;
+                       /* Using park/unpark to start the thread ensures that
+                        * the thread function does get calls, so the
+                        * ref on qpi will be dropped
+                        */
+                       kthread_park(task);
+                       kthread_unpark(task);
                }
-               OBD_FREE(name, QPI_MAXNAME + sizeof("qmt_pool_recalc_"));
        }
 
        RETURN(rc);
@@ -1296,15 +1301,11 @@ static int qmt_start_pool_recalc(struct lu_env *env, struct qmt_pool_info *qpi)
 
 static inline void qmt_stop_pool_recalc(struct qmt_pool_info *qpi)
 {
-       struct ptlrpc_thread    *thread = &qpi->qpi_recalc_thread;
-
-       if (!thread_is_stopped(thread)) {
-               thread_set_flags(thread, SVC_STOPPING);
-               wake_up(&thread->t_ctl_waitq);
+       struct task_struct *task;
 
-               wait_event_idle(thread->t_ctl_waitq,
-                               thread_is_stopped(thread));
-       }
+       task = xchg(&qpi->qpi_recalc_task, NULL);
+       if (task)
+               kthread_stop(task);
 }
 
 static int qmt_pool_slv_nr_change(const struct lu_env *env,
@@ -1509,7 +1510,7 @@ static inline int qmt_sarr_pool_init(struct qmt_pool_info *qpi)
 
        switch (qpi->qpi_rtype) {
        case LQUOTA_RES_DT:
-               return tgt_pool_init(&qpi->qpi_sarr.osts, 0);
+               return lu_tgt_pool_init(&qpi->qpi_sarr.osts, 0);
        case LQUOTA_RES_MD:
        default:
                return 0;
@@ -1520,7 +1521,7 @@ static inline int qmt_sarr_pool_add(struct qmt_pool_info *qpi, int idx, int min)
 {
        switch (qpi->qpi_rtype) {
        case LQUOTA_RES_DT:
-               return tgt_pool_add(&qpi->qpi_sarr.osts, idx, min);
+               return lu_tgt_pool_add(&qpi->qpi_sarr.osts, idx, min);
        case LQUOTA_RES_MD:
        default:
                return 0;
@@ -1531,7 +1532,7 @@ static inline int qmt_sarr_pool_rem(struct qmt_pool_info *qpi, int idx)
 {
        switch (qpi->qpi_rtype) {
        case LQUOTA_RES_DT:
-               return tgt_pool_remove(&qpi->qpi_sarr.osts, idx);
+               return lu_tgt_pool_remove(&qpi->qpi_sarr.osts, idx);
        case LQUOTA_RES_MD:
        default:
                return 0;
@@ -1547,7 +1548,7 @@ static inline int qmt_sarr_pool_free(struct qmt_pool_info *qpi)
        case LQUOTA_RES_DT:
                if (!qpi->qpi_sarr.osts.op_array)
                        return 0;
-               return tgt_pool_free(&qpi->qpi_sarr.osts);
+               return lu_tgt_pool_free(&qpi->qpi_sarr.osts);
        case LQUOTA_RES_MD:
        default:
                return 0;
@@ -1561,14 +1562,14 @@ static inline int qmt_sarr_check_idx(struct qmt_pool_info *qpi, int idx)
 
        switch (qpi->qpi_rtype) {
        case LQUOTA_RES_DT:
-               return tgt_check_index(idx, &qpi->qpi_sarr.osts);
+               return lu_tgt_check_index(idx, &qpi->qpi_sarr.osts);
        case LQUOTA_RES_MD:
        default:
                return 0;
        }
 }
 
-inline struct rw_semaphore *qmt_sarr_rwsem(struct qmt_pool_info *qpi)
+struct rw_semaphore *qmt_sarr_rwsem(struct qmt_pool_info *qpi)
 {
        switch (qpi->qpi_rtype) {
        case LQUOTA_RES_DT:
@@ -1580,7 +1581,7 @@ inline struct rw_semaphore *qmt_sarr_rwsem(struct qmt_pool_info *qpi)
        }
 }
 
-inline int qmt_sarr_get_idx(struct qmt_pool_info *qpi, int arr_idx)
+int qmt_sarr_get_idx(struct qmt_pool_info *qpi, int arr_idx)
 {
 
        if (qmt_pool_global(qpi))
@@ -1599,7 +1600,7 @@ inline int qmt_sarr_get_idx(struct qmt_pool_info *qpi, int arr_idx)
 }
 
 /* Number of slaves in a pool */
-inline unsigned int qmt_sarr_count(struct qmt_pool_info *qpi)
+unsigned int qmt_sarr_count(struct qmt_pool_info *qpi)
 {
        switch (qpi->qpi_rtype) {
        case LQUOTA_RES_DT: