1 /* 2 * CDDL HEADER START 3 * 4 * This file and its contents are supplied under the terms of the 5 * Common Development and Distribution License ("CDDL"), version 1.0. 6 * You may only use this file in accordance with the terms of version 7 * 1.0 of the CDDL. 8 * 9 * A full copy of the text of the CDDL should have accompanied this 10 * source. A copy of the CDDL is also available via the Internet at 11 * http://www.illumos.org/license/CDDL. 12 * 13 * CDDL HEADER END 14 */ 15 16 /* 17 * Copyright (c) 2017 by Delphix. All rights reserved. 18 */ 19 20 /* 21 * ZTHR Infrastructure 22 * =================== 23 * 24 * ZTHR threads are used for isolated operations that span multiple txgs 25 * within a SPA. They generally exist from SPA creation/loading and until 26 * the SPA is exported/destroyed. The ideal requirements for an operation 27 * to be modeled with a zthr are the following: 28 * 29 * 1] The operation needs to run over multiple txgs. 30 * 2] There is be a single point of reference in memory or on disk that 31 * indicates whether the operation should run/is running or is 32 * stopped. 33 * 34 * If the operation satisfies the above then the following rules guarantee 35 * a certain level of correctness: 36 * 37 * 1] Any thread EXCEPT the zthr changes the work indicator from stopped 38 * to running but not the opposite. 39 * 2] Only the zthr can change the work indicator from running to stopped 40 * (e.g. when it is done) but not the opposite. 41 * 42 * This way a normal zthr cycle should go like this: 43 * 44 * 1] An external thread changes the work indicator from stopped to 45 * running and wakes up the zthr. 46 * 2] The zthr wakes up, checks the indicator and starts working. 47 * 3] When the zthr is done, it changes the indicator to stopped, allowing 48 * a new cycle to start. 49 * 50 * Besides being awakened by other threads, a zthr can be configured 51 * during creation to wakeup on it's own after a specified interval 52 * [see zthr_create_timer()]. 53 * 54 * == ZTHR creation 55 * 56 * Every zthr needs three inputs to start running: 57 * 58 * 1] A user-defined checker function (checkfunc) that decides whether 59 * the zthr should start working or go to sleep. The function should 60 * return TRUE when the zthr needs to work or FALSE to let it sleep, 61 * and should adhere to the following signature: 62 * boolean_t checkfunc_name(void *args, zthr_t *t); 63 * 64 * 2] A user-defined ZTHR function (func) which the zthr executes when 65 * it is not sleeping. The function should adhere to the following 66 * signature type: 67 * int func_name(void *args, zthr_t *t); 68 * 69 * 3] A void args pointer that will be passed to checkfunc and func 70 * implicitly by the infrastructure. 71 * 72 * The reason why the above API needs two different functions, 73 * instead of one that both checks and does the work, has to do with 74 * the zthr's internal lock (zthr_lock) and the allowed cancellation 75 * windows. We want to hold the zthr_lock while running checkfunc 76 * but not while running func. This way the zthr can be cancelled 77 * while doing work and not while checking for work. 78 * 79 * To start a zthr: 80 * zthr_t *zthr_pointer = zthr_create(checkfunc, func, args); 81 * or 82 * zthr_t *zthr_pointer = zthr_create_timer(checkfunc, func, 83 * args, max_sleep); 84 * 85 * After that you should be able to wakeup, cancel, and resume the 86 * zthr from another thread using zthr_pointer. 87 * 88 * NOTE: ZTHR threads could potentially wake up spuriously and the 89 * user should take this into account when writing a checkfunc. 90 * [see ZTHR state transitions] 91 * 92 * == ZTHR cancellation 93 * 94 * ZTHR threads must be cancelled when their SPA is being exported 95 * or when they need to be paused so they don't interfere with other 96 * operations. 97 * 98 * To cancel a zthr: 99 * zthr_cancel(zthr_pointer); 100 * 101 * To resume it: 102 * zthr_resume(zthr_pointer); 103 * 104 * A zthr will implicitly check if it has received a cancellation 105 * signal every time func returns and everytime it wakes up [see ZTHR 106 * state transitions below]. 107 * 108 * At times, waiting for the zthr's func to finish its job may take 109 * time. This may be very time-consuming for some operations that 110 * need to cancel the SPA's zthrs (e.g spa_export). For this scenario 111 * the user can explicitly make their ZTHR function aware of incoming 112 * cancellation signals using zthr_iscancelled(). A common pattern for 113 * that looks like this: 114 * 115 * int 116 * func_name(void *args, zthr_t *t) 117 * { 118 * ... <unpack args> ... 119 * while (!work_done && !zthr_iscancelled(t)) { 120 * ... <do more work> ... 121 * } 122 * return (0); 123 * } 124 * 125 * == ZTHR exit 126 * 127 * For the rare cases where the zthr wants to stop running voluntarily 128 * while running its ZTHR function (func), we provide zthr_exit(). 129 * When a zthr has voluntarily stopped running, it can be resumed with 130 * zthr_resume(), just like it would if it was cancelled by some other 131 * thread. 132 * 133 * == ZTHR cleanup 134 * 135 * Cancelling a zthr doesn't clean up its metadata (internal locks, 136 * function pointers to func and checkfunc, etc..). This is because 137 * we want to keep them around in case we want to resume the execution 138 * of the zthr later. Similarly for zthrs that exit themselves. 139 * 140 * To completely cleanup a zthr, cancel it first to ensure that it 141 * is not running and then use zthr_destroy(). 142 * 143 * == ZTHR state transitions 144 * 145 * zthr creation 146 * + 147 * | 148 * | woke up 149 * | +--------------+ sleep 150 * | | ^ 151 * | | | 152 * | | | FALSE 153 * | | | 154 * v v FALSE + 155 * cancelled? +---------> checkfunc? 156 * + ^ + 157 * | | | 158 * | | | TRUE 159 * | | | 160 * | | func returned v 161 * | +---------------+ func 162 * | 163 * | TRUE 164 * | 165 * v 166 * zthr stopped running 167 * 168 */ 169 170 #include <sys/zfs_context.h> 171 #include <sys/zthr.h> 172 173 void 174 zthr_exit(zthr_t *t, int rc) 175 { 176 ASSERT3P(t->zthr_thread, ==, curthread); 177 mutex_enter(&t->zthr_lock); 178 t->zthr_thread = NULL; 179 t->zthr_rc = rc; 180 cv_broadcast(&t->zthr_cv); 181 mutex_exit(&t->zthr_lock); 182 thread_exit(); 183 } 184 185 static void 186 zthr_procedure(void *arg) 187 { 188 zthr_t *t = arg; 189 int rc = 0; 190 191 mutex_enter(&t->zthr_lock); 192 while (!t->zthr_cancel) { 193 if (t->zthr_checkfunc(t->zthr_arg, t)) { 194 mutex_exit(&t->zthr_lock); 195 rc = t->zthr_func(t->zthr_arg, t); 196 mutex_enter(&t->zthr_lock); 197 } else { 198 /* go to sleep */ 199 if (t->zthr_wait_time == 0) { 200 cv_wait(&t->zthr_cv, &t->zthr_lock); 201 } else { 202 (void) cv_timedwait_hires(&t->zthr_cv, 203 &t->zthr_lock, t->zthr_wait_time, 204 MSEC2NSEC(1), 0); 205 } 206 } 207 } 208 mutex_exit(&t->zthr_lock); 209 210 zthr_exit(t, rc); 211 } 212 213 zthr_t * 214 zthr_create(zthr_checkfunc_t *checkfunc, zthr_func_t *func, void *arg) 215 { 216 return (zthr_create_timer(checkfunc, func, arg, (hrtime_t)0)); 217 } 218 219 /* 220 * Create a zthr with specified maximum sleep time. If the time 221 * in sleeping state exceeds max_sleep, a wakeup(do the check and 222 * start working if required) will be triggered. 223 */ 224 zthr_t * 225 zthr_create_timer(zthr_checkfunc_t *checkfunc, zthr_func_t *func, 226 void *arg, hrtime_t max_sleep) 227 { 228 zthr_t *t = kmem_zalloc(sizeof (*t), KM_SLEEP); 229 mutex_init(&t->zthr_lock, NULL, MUTEX_DEFAULT, NULL); 230 cv_init(&t->zthr_cv, NULL, CV_DEFAULT, NULL); 231 232 mutex_enter(&t->zthr_lock); 233 t->zthr_checkfunc = checkfunc; 234 t->zthr_func = func; 235 t->zthr_arg = arg; 236 t->zthr_wait_time = max_sleep; 237 238 t->zthr_thread = thread_create(NULL, 0, zthr_procedure, t, 239 0, &p0, TS_RUN, minclsyspri); 240 mutex_exit(&t->zthr_lock); 241 242 return (t); 243 } 244 245 void 246 zthr_destroy(zthr_t *t) 247 { 248 VERIFY3P(t->zthr_thread, ==, NULL); 249 mutex_destroy(&t->zthr_lock); 250 cv_destroy(&t->zthr_cv); 251 kmem_free(t, sizeof (*t)); 252 } 253 254 /* 255 * Note: If the zthr is not sleeping and misses the wakeup 256 * (e.g it is running its ZTHR function), it will check if 257 * there is work to do before going to sleep using its checker 258 * function [see ZTHR state transition in ZTHR block comment]. 259 * Thus, missing the wakeup still yields the expected behavior. 260 */ 261 void 262 zthr_wakeup(zthr_t *t) 263 { 264 mutex_enter(&t->zthr_lock); 265 cv_broadcast(&t->zthr_cv); 266 mutex_exit(&t->zthr_lock); 267 } 268 269 /* 270 * Note: If the zthr is not running (e.g. has been cancelled 271 * already), this is a no-op. 272 */ 273 int 274 zthr_cancel(zthr_t *t) 275 { 276 int rc = 0; 277 278 mutex_enter(&t->zthr_lock); 279 280 /* broadcast in case the zthr is sleeping */ 281 cv_broadcast(&t->zthr_cv); 282 283 t->zthr_cancel = B_TRUE; 284 while (t->zthr_thread != NULL) 285 cv_wait(&t->zthr_cv, &t->zthr_lock); 286 t->zthr_cancel = B_FALSE; 287 rc = t->zthr_rc; 288 mutex_exit(&t->zthr_lock); 289 290 return (rc); 291 } 292 293 void 294 zthr_resume(zthr_t *t) 295 { 296 ASSERT3P(t->zthr_thread, ==, NULL); 297 298 mutex_enter(&t->zthr_lock); 299 300 ASSERT3P(&t->zthr_checkfunc, !=, NULL); 301 ASSERT3P(&t->zthr_func, !=, NULL); 302 ASSERT(!t->zthr_cancel); 303 304 t->zthr_thread = thread_create(NULL, 0, zthr_procedure, t, 305 0, &p0, TS_RUN, minclsyspri); 306 307 mutex_exit(&t->zthr_lock); 308 } 309 310 /* 311 * This function is intended to be used by the zthr itself 312 * to check if another thread has signal it to stop running. 313 * 314 * returns TRUE if we are in the middle of trying to cancel 315 * this thread. 316 * 317 * returns FALSE otherwise. 318 */ 319 boolean_t 320 zthr_iscancelled(zthr_t *t) 321 { 322 boolean_t cancelled; 323 324 ASSERT3P(t->zthr_thread, ==, curthread); 325 326 mutex_enter(&t->zthr_lock); 327 cancelled = t->zthr_cancel; 328 mutex_exit(&t->zthr_lock); 329 330 return (cancelled); 331 } 332 333 boolean_t 334 zthr_isrunning(zthr_t *t) 335 { 336 boolean_t running; 337 338 mutex_enter(&t->zthr_lock); 339 running = (t->zthr_thread != NULL); 340 mutex_exit(&t->zthr_lock); 341 342 return (running); 343 } 344