| 1141 | EXPORT_SYMBOL(taskq_create); |
| 1142 | |
| 1143 | void |
| 1144 | taskq_destroy(taskq_t *tq) |
| 1145 | { |
| 1146 | struct task_struct *thread; |
| 1147 | taskq_thread_t *tqt; |
| 1148 | taskq_ent_t *t; |
| 1149 | unsigned long flags; |
| 1150 | |
| 1151 | ASSERT(tq); |
| 1152 | spin_lock_irqsave_nested(&tq->tq_lock, flags, tq->tq_lock_class); |
| 1153 | tq->tq_flags &= ~TASKQ_ACTIVE; |
| 1154 | spin_unlock_irqrestore(&tq->tq_lock, flags); |
| 1155 | |
| 1156 | #ifdef HAVE_CPU_HOTPLUG |
| 1157 | if (tq->tq_hp_support) { |
| 1158 | VERIFY0(cpuhp_state_remove_instance_nocalls( |
| 1159 | spl_taskq_cpuhp_state, &tq->tq_hp_cb_node)); |
| 1160 | } |
| 1161 | #endif |
| 1162 | /* |
| 1163 | * When TASKQ_ACTIVE is clear new tasks may not be added nor may |
| 1164 | * new worker threads be spawned for dynamic taskq. |
| 1165 | */ |
| 1166 | if (dynamic_taskq != NULL) |
| 1167 | taskq_wait_outstanding(dynamic_taskq, 0); |
| 1168 | |
| 1169 | taskq_wait(tq); |
| 1170 | |
| 1171 | /* remove taskq from global list used by the kstats */ |
| 1172 | down_write(&tq_list_sem); |
| 1173 | list_del(&tq->tq_taskqs); |
| 1174 | up_write(&tq_list_sem); |
| 1175 | |
| 1176 | spin_lock_irqsave_nested(&tq->tq_lock, flags, tq->tq_lock_class); |
| 1177 | /* wait for spawning threads to insert themselves to the list */ |
| 1178 | while (tq->tq_nspawn) { |
| 1179 | spin_unlock_irqrestore(&tq->tq_lock, flags); |
| 1180 | schedule_timeout_interruptible(1); |
| 1181 | spin_lock_irqsave_nested(&tq->tq_lock, flags, |
| 1182 | tq->tq_lock_class); |
| 1183 | } |
| 1184 | |
| 1185 | /* |
| 1186 | * Signal each thread to exit and block until it does. Each thread |
| 1187 | * is responsible for removing itself from the list and freeing its |
| 1188 | * taskq_thread_t. This allows for idle threads to opt to remove |
| 1189 | * themselves from the taskq. They can be recreated as needed. |
| 1190 | */ |
| 1191 | while (!list_empty(&tq->tq_thread_list)) { |
| 1192 | tqt = list_entry(tq->tq_thread_list.next, |
| 1193 | taskq_thread_t, tqt_thread_list); |
| 1194 | thread = tqt->tqt_thread; |
| 1195 | spin_unlock_irqrestore(&tq->tq_lock, flags); |
| 1196 | |
| 1197 | kthread_stop(thread); |
| 1198 | |
| 1199 | spin_lock_irqsave_nested(&tq->tq_lock, flags, |
| 1200 | tq->tq_lock_class); |
no test coverage detected