+/* Release the ressource used by the coordinator. Called when the
+ * coordinator is stopping. */
+static void mdt_hsm_cdt_cleanup(struct mdt_device *mdt)
+{
+ struct coordinator *cdt = &mdt->mdt_coordinator;
+ struct cdt_agent_req *car, *tmp1;
+ struct hsm_agent *ha, *tmp2;
+ struct cdt_restore_handle *crh, *tmp3;
+ struct mdt_thread_info *cdt_mti;
+
+ /* start cleaning */
+ down_write(&cdt->cdt_request_lock);
+ list_for_each_entry_safe(car, tmp1, &cdt->cdt_request_list,
+ car_request_list) {
+ cfs_hash_del(cdt->cdt_request_cookie_hash,
+ &car->car_hai->hai_cookie,
+ &car->car_cookie_hash);
+ list_del(&car->car_request_list);
+ mdt_cdt_put_request(car);
+ }
+ up_write(&cdt->cdt_request_lock);
+
+ down_write(&cdt->cdt_agent_lock);
+ list_for_each_entry_safe(ha, tmp2, &cdt->cdt_agents, ha_list) {
+ list_del(&ha->ha_list);
+ OBD_FREE_PTR(ha);
+ }
+ up_write(&cdt->cdt_agent_lock);
+
+ cdt_mti = lu_context_key_get(&cdt->cdt_env.le_ctx, &mdt_thread_key);
+ mutex_lock(&cdt->cdt_restore_lock);
+ list_for_each_entry_safe(crh, tmp3, &cdt->cdt_restore_hdl, crh_list) {
+ list_del(&crh->crh_list);
+ /* give back layout lock */
+ mdt_object_unlock(cdt_mti, NULL, &crh->crh_lh, 1);
+ OBD_SLAB_FREE_PTR(crh, mdt_hsm_cdt_kmem);
+ }
+ mutex_unlock(&cdt->cdt_restore_lock);
+}
+
+/*
+ * Coordinator state transition table, indexed on enum cdt_states, taking
+ * from and to states. For instance since CDT_INIT to CDT_RUNNING is a
+ * valid transition, cdt_transition[CDT_INIT][CDT_RUNNING] is true.
+ */
+static bool cdt_transition[CDT_STATES_COUNT][CDT_STATES_COUNT] = {
+ /* from -> to: stopped init running disable stopping */
+ /* stopped */ { true, true, false, false, false },
+ /* init */ { true, false, true, false, false },
+ /* running */ { false, false, true, true, true },
+ /* disable */ { false, false, true, true, true },
+ /* stopping */ { true, false, false, false, false }
+};
+
+/**
+ * Change coordinator thread state
+ * Some combinations are not valid, so catch them here.
+ *
+ * Returns 0 on success, with old_state set if not NULL, or -EINVAL if
+ * the transition was not possible.
+ */
+static int set_cdt_state(struct coordinator *cdt, enum cdt_states new_state,
+ enum cdt_states *old_state)
+{
+ int rc;
+ enum cdt_states state;
+
+ spin_lock(&cdt->cdt_state_lock);
+
+ state = cdt->cdt_state;
+
+ if (cdt_transition[state][new_state]) {
+ cdt->cdt_state = new_state;
+ spin_unlock(&cdt->cdt_state_lock);
+ if (old_state)
+ *old_state = state;
+ rc = 0;
+ } else {
+ spin_unlock(&cdt->cdt_state_lock);
+ CDEBUG(D_HSM,
+ "unexpected coordinator transition, from=%s, to=%s\n",
+ cdt_mdt_state2str(state), cdt_mdt_state2str(new_state));
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+