1*ea8dc4b6Seschrock /* 2*ea8dc4b6Seschrock * CDDL HEADER START 3*ea8dc4b6Seschrock * 4*ea8dc4b6Seschrock * The contents of this file are subject to the terms of the 5*ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6*ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7*ea8dc4b6Seschrock * 8*ea8dc4b6Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*ea8dc4b6Seschrock * or http://www.opensolaris.org/os/licensing. 10*ea8dc4b6Seschrock * See the License for the specific language governing permissions 11*ea8dc4b6Seschrock * and limitations under the License. 12*ea8dc4b6Seschrock * 13*ea8dc4b6Seschrock * When distributing Covered Code, include this CDDL HEADER in each 14*ea8dc4b6Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*ea8dc4b6Seschrock * If applicable, add the following below this CDDL HEADER, with the 16*ea8dc4b6Seschrock * fields enclosed by brackets "[]" replaced with your own identifying 17*ea8dc4b6Seschrock * information: Portions Copyright [yyyy] [name of copyright owner] 18*ea8dc4b6Seschrock * 19*ea8dc4b6Seschrock * CDDL HEADER END 20*ea8dc4b6Seschrock */ 21*ea8dc4b6Seschrock /* 22*ea8dc4b6Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*ea8dc4b6Seschrock * Use is subject to license terms. 24*ea8dc4b6Seschrock */ 25*ea8dc4b6Seschrock 26*ea8dc4b6Seschrock #pragma ident "%Z%%M% %I% %E% SMI" 27*ea8dc4b6Seschrock 28*ea8dc4b6Seschrock /* 29*ea8dc4b6Seschrock * Routines to manage the on-disk persistent error log. 30*ea8dc4b6Seschrock * 31*ea8dc4b6Seschrock * Each pool stores a log of all logical data errors seen during normal 32*ea8dc4b6Seschrock * operation. This is actually the union of two distinct logs: the last log, 33*ea8dc4b6Seschrock * and the current log. All errors seen are logged to the current log. When a 34*ea8dc4b6Seschrock * scrub completes, the current log becomes the last log, the last log is thrown 35*ea8dc4b6Seschrock * out, and the current log is reinitialized. This way, if an error is somehow 36*ea8dc4b6Seschrock * corrected, a new scrub will show that that it no longer exists, and will be 37*ea8dc4b6Seschrock * deleted from the log when the scrub completes. 38*ea8dc4b6Seschrock * 39*ea8dc4b6Seschrock * The log is stored using a ZAP object whose key is a string form of the 40*ea8dc4b6Seschrock * zbookmark tuple (objset, object, level, blkid), and whose contents is an 41*ea8dc4b6Seschrock * optional 'objset:object' human-readable string describing the data. When an 42*ea8dc4b6Seschrock * error is first logged, this string will be empty, indicating that no name is 43*ea8dc4b6Seschrock * known. This prevents us from having to issue a potentially large amount of 44*ea8dc4b6Seschrock * I/O to discover the object name during an error path. Instead, we do the 45*ea8dc4b6Seschrock * calculation when the data is requested, storing the result so future queries 46*ea8dc4b6Seschrock * will be faster. 47*ea8dc4b6Seschrock * 48*ea8dc4b6Seschrock * This log is then shipped into an nvlist where the key is the dataset name and 49*ea8dc4b6Seschrock * the value is the object name. Userland is then responsible for uniquifying 50*ea8dc4b6Seschrock * this list and displaying it to the user. 51*ea8dc4b6Seschrock */ 52*ea8dc4b6Seschrock 53*ea8dc4b6Seschrock #include <sys/dmu_tx.h> 54*ea8dc4b6Seschrock #include <sys/spa.h> 55*ea8dc4b6Seschrock #include <sys/spa_impl.h> 56*ea8dc4b6Seschrock #include <sys/zap.h> 57*ea8dc4b6Seschrock #include <sys/zio.h> 58*ea8dc4b6Seschrock 59*ea8dc4b6Seschrock /* 60*ea8dc4b6Seschrock * This is a stripped-down version of strtoull, suitable only for converting 61*ea8dc4b6Seschrock * lowercase hexidecimal numbers that don't overflow. 62*ea8dc4b6Seschrock */ 63*ea8dc4b6Seschrock static uint64_t 64*ea8dc4b6Seschrock strtonum(char *str, char **nptr) 65*ea8dc4b6Seschrock { 66*ea8dc4b6Seschrock uint64_t val = 0; 67*ea8dc4b6Seschrock char c; 68*ea8dc4b6Seschrock int digit; 69*ea8dc4b6Seschrock 70*ea8dc4b6Seschrock while ((c = *str) != '\0') { 71*ea8dc4b6Seschrock if (c >= '0' && c <= '9') 72*ea8dc4b6Seschrock digit = c - '0'; 73*ea8dc4b6Seschrock else if (c >= 'a' && c <= 'f') 74*ea8dc4b6Seschrock digit = 10 + c - 'a'; 75*ea8dc4b6Seschrock else 76*ea8dc4b6Seschrock break; 77*ea8dc4b6Seschrock 78*ea8dc4b6Seschrock val *= 16; 79*ea8dc4b6Seschrock val += digit; 80*ea8dc4b6Seschrock 81*ea8dc4b6Seschrock str++; 82*ea8dc4b6Seschrock } 83*ea8dc4b6Seschrock 84*ea8dc4b6Seschrock *nptr = str; 85*ea8dc4b6Seschrock 86*ea8dc4b6Seschrock return (val); 87*ea8dc4b6Seschrock } 88*ea8dc4b6Seschrock 89*ea8dc4b6Seschrock /* 90*ea8dc4b6Seschrock * Convert a bookmark to a string. 91*ea8dc4b6Seschrock */ 92*ea8dc4b6Seschrock static void 93*ea8dc4b6Seschrock bookmark_to_name(zbookmark_t *zb, char *buf, size_t len) 94*ea8dc4b6Seschrock { 95*ea8dc4b6Seschrock (void) snprintf(buf, len, "%llx:%llx:%llx:%llx", 96*ea8dc4b6Seschrock (u_longlong_t)zb->zb_objset, (u_longlong_t)zb->zb_object, 97*ea8dc4b6Seschrock (u_longlong_t)zb->zb_level, (u_longlong_t)zb->zb_blkid); 98*ea8dc4b6Seschrock } 99*ea8dc4b6Seschrock 100*ea8dc4b6Seschrock /* 101*ea8dc4b6Seschrock * Convert a string to a bookmark 102*ea8dc4b6Seschrock */ 103*ea8dc4b6Seschrock static void 104*ea8dc4b6Seschrock name_to_bookmark(char *buf, zbookmark_t *zb) 105*ea8dc4b6Seschrock { 106*ea8dc4b6Seschrock zb->zb_objset = strtonum(buf, &buf); 107*ea8dc4b6Seschrock ASSERT(*buf == ':'); 108*ea8dc4b6Seschrock zb->zb_object = strtonum(buf + 1, &buf); 109*ea8dc4b6Seschrock ASSERT(*buf == ':'); 110*ea8dc4b6Seschrock zb->zb_level = (int)strtonum(buf + 1, &buf); 111*ea8dc4b6Seschrock ASSERT(*buf == ':'); 112*ea8dc4b6Seschrock zb->zb_blkid = strtonum(buf + 1, &buf); 113*ea8dc4b6Seschrock ASSERT(*buf == '\0'); 114*ea8dc4b6Seschrock } 115*ea8dc4b6Seschrock 116*ea8dc4b6Seschrock /* 117*ea8dc4b6Seschrock * Log an uncorrectable error to the persistent error log. We add it to the 118*ea8dc4b6Seschrock * spa's list of pending errors. The changes are actually synced out to disk 119*ea8dc4b6Seschrock * during spa_errlog_sync(). 120*ea8dc4b6Seschrock */ 121*ea8dc4b6Seschrock void 122*ea8dc4b6Seschrock spa_log_error(spa_t *spa, zio_t *zio) 123*ea8dc4b6Seschrock { 124*ea8dc4b6Seschrock zbookmark_t *zb = &zio->io_logical->io_bookmark; 125*ea8dc4b6Seschrock spa_error_entry_t search; 126*ea8dc4b6Seschrock spa_error_entry_t *new; 127*ea8dc4b6Seschrock avl_tree_t *tree; 128*ea8dc4b6Seschrock avl_index_t where; 129*ea8dc4b6Seschrock 130*ea8dc4b6Seschrock /* 131*ea8dc4b6Seschrock * If we are trying to import a pool, ignore any errors, as we won't be 132*ea8dc4b6Seschrock * writing to the pool any time soon. 133*ea8dc4b6Seschrock */ 134*ea8dc4b6Seschrock if (spa->spa_load_state == SPA_LOAD_TRYIMPORT) 135*ea8dc4b6Seschrock return; 136*ea8dc4b6Seschrock 137*ea8dc4b6Seschrock mutex_enter(&spa->spa_errlist_lock); 138*ea8dc4b6Seschrock 139*ea8dc4b6Seschrock /* 140*ea8dc4b6Seschrock * If we have had a request to rotate the log, log it to the next list 141*ea8dc4b6Seschrock * instead of the current one. 142*ea8dc4b6Seschrock */ 143*ea8dc4b6Seschrock if (spa->spa_scrub_active || spa->spa_scrub_finished) 144*ea8dc4b6Seschrock tree = &spa->spa_errlist_scrub; 145*ea8dc4b6Seschrock else 146*ea8dc4b6Seschrock tree = &spa->spa_errlist_last; 147*ea8dc4b6Seschrock 148*ea8dc4b6Seschrock search.se_bookmark = *zb; 149*ea8dc4b6Seschrock if (avl_find(tree, &search, &where) != NULL) { 150*ea8dc4b6Seschrock mutex_exit(&spa->spa_errlist_lock); 151*ea8dc4b6Seschrock return; 152*ea8dc4b6Seschrock } 153*ea8dc4b6Seschrock 154*ea8dc4b6Seschrock new = kmem_zalloc(sizeof (spa_error_entry_t), KM_SLEEP); 155*ea8dc4b6Seschrock new->se_bookmark = *zb; 156*ea8dc4b6Seschrock avl_insert(tree, new, where); 157*ea8dc4b6Seschrock 158*ea8dc4b6Seschrock mutex_exit(&spa->spa_errlist_lock); 159*ea8dc4b6Seschrock } 160*ea8dc4b6Seschrock 161*ea8dc4b6Seschrock /* 162*ea8dc4b6Seschrock * Return the number of errors currently in the error log. This is actually the 163*ea8dc4b6Seschrock * sum of both the last log and the current log, since we don't know the union 164*ea8dc4b6Seschrock * of these logs until we reach userland. 165*ea8dc4b6Seschrock */ 166*ea8dc4b6Seschrock uint64_t 167*ea8dc4b6Seschrock spa_get_errlog_size(spa_t *spa) 168*ea8dc4b6Seschrock { 169*ea8dc4b6Seschrock uint64_t total = 0, count; 170*ea8dc4b6Seschrock 171*ea8dc4b6Seschrock mutex_enter(&spa->spa_errlog_lock); 172*ea8dc4b6Seschrock if (spa->spa_errlog_scrub != 0 && 173*ea8dc4b6Seschrock zap_count(spa->spa_meta_objset, spa->spa_errlog_scrub, 174*ea8dc4b6Seschrock &count) == 0) 175*ea8dc4b6Seschrock total += count; 176*ea8dc4b6Seschrock 177*ea8dc4b6Seschrock if (spa->spa_errlog_last != 0 && !spa->spa_scrub_finished && 178*ea8dc4b6Seschrock zap_count(spa->spa_meta_objset, spa->spa_errlog_last, 179*ea8dc4b6Seschrock &count) == 0) 180*ea8dc4b6Seschrock total += count; 181*ea8dc4b6Seschrock mutex_exit(&spa->spa_errlog_lock); 182*ea8dc4b6Seschrock 183*ea8dc4b6Seschrock mutex_enter(&spa->spa_errlist_lock); 184*ea8dc4b6Seschrock total += avl_numnodes(&spa->spa_errlist_last); 185*ea8dc4b6Seschrock total += avl_numnodes(&spa->spa_errlist_scrub); 186*ea8dc4b6Seschrock mutex_exit(&spa->spa_errlist_lock); 187*ea8dc4b6Seschrock 188*ea8dc4b6Seschrock return (total); 189*ea8dc4b6Seschrock } 190*ea8dc4b6Seschrock 191*ea8dc4b6Seschrock #ifdef _KERNEL 192*ea8dc4b6Seschrock static int 193*ea8dc4b6Seschrock process_error_log(spa_t *spa, uint64_t obj, void *addr, size_t *count) 194*ea8dc4b6Seschrock { 195*ea8dc4b6Seschrock zap_cursor_t zc; 196*ea8dc4b6Seschrock zap_attribute_t za; 197*ea8dc4b6Seschrock zbookmark_t zb; 198*ea8dc4b6Seschrock 199*ea8dc4b6Seschrock if (obj == 0) 200*ea8dc4b6Seschrock return (0); 201*ea8dc4b6Seschrock 202*ea8dc4b6Seschrock for (zap_cursor_init(&zc, spa->spa_meta_objset, obj); 203*ea8dc4b6Seschrock zap_cursor_retrieve(&zc, &za) == 0; 204*ea8dc4b6Seschrock zap_cursor_advance(&zc)) { 205*ea8dc4b6Seschrock 206*ea8dc4b6Seschrock if (*count == 0) { 207*ea8dc4b6Seschrock zap_cursor_fini(&zc); 208*ea8dc4b6Seschrock return (ENOMEM); 209*ea8dc4b6Seschrock } 210*ea8dc4b6Seschrock 211*ea8dc4b6Seschrock name_to_bookmark(za.za_name, &zb); 212*ea8dc4b6Seschrock 213*ea8dc4b6Seschrock if (copyout(&zb, (char *)addr + 214*ea8dc4b6Seschrock (*count - 1) * sizeof (zbookmark_t), 215*ea8dc4b6Seschrock sizeof (zbookmark_t)) != 0) 216*ea8dc4b6Seschrock return (EFAULT); 217*ea8dc4b6Seschrock 218*ea8dc4b6Seschrock *count -= 1; 219*ea8dc4b6Seschrock } 220*ea8dc4b6Seschrock 221*ea8dc4b6Seschrock zap_cursor_fini(&zc); 222*ea8dc4b6Seschrock 223*ea8dc4b6Seschrock return (0); 224*ea8dc4b6Seschrock } 225*ea8dc4b6Seschrock 226*ea8dc4b6Seschrock static int 227*ea8dc4b6Seschrock process_error_list(avl_tree_t *list, void *addr, size_t *count) 228*ea8dc4b6Seschrock { 229*ea8dc4b6Seschrock spa_error_entry_t *se; 230*ea8dc4b6Seschrock 231*ea8dc4b6Seschrock for (se = avl_first(list); se != NULL; se = AVL_NEXT(list, se)) { 232*ea8dc4b6Seschrock 233*ea8dc4b6Seschrock if (*count == 0) 234*ea8dc4b6Seschrock return (ENOMEM); 235*ea8dc4b6Seschrock 236*ea8dc4b6Seschrock if (copyout(&se->se_bookmark, (char *)addr + 237*ea8dc4b6Seschrock (*count - 1) * sizeof (zbookmark_t), 238*ea8dc4b6Seschrock sizeof (zbookmark_t)) != 0) 239*ea8dc4b6Seschrock return (EFAULT); 240*ea8dc4b6Seschrock 241*ea8dc4b6Seschrock *count -= 1; 242*ea8dc4b6Seschrock } 243*ea8dc4b6Seschrock 244*ea8dc4b6Seschrock return (0); 245*ea8dc4b6Seschrock } 246*ea8dc4b6Seschrock #endif 247*ea8dc4b6Seschrock 248*ea8dc4b6Seschrock /* 249*ea8dc4b6Seschrock * Copy all known errors to userland as an array of bookmarks. This is 250*ea8dc4b6Seschrock * actually a union of the on-disk last log and current log, as well as any 251*ea8dc4b6Seschrock * pending error requests. 252*ea8dc4b6Seschrock * 253*ea8dc4b6Seschrock * Because the act of reading the on-disk log could cause errors to be 254*ea8dc4b6Seschrock * generated, we have two separate locks: one for the error log and one for the 255*ea8dc4b6Seschrock * in-core error lists. We only need the error list lock to log and error, so 256*ea8dc4b6Seschrock * we grab the error log lock while we read the on-disk logs, and only pick up 257*ea8dc4b6Seschrock * the error list lock when we are finished. 258*ea8dc4b6Seschrock */ 259*ea8dc4b6Seschrock int 260*ea8dc4b6Seschrock spa_get_errlog(spa_t *spa, void *uaddr, size_t *count) 261*ea8dc4b6Seschrock { 262*ea8dc4b6Seschrock int ret = 0; 263*ea8dc4b6Seschrock 264*ea8dc4b6Seschrock #ifdef _KERNEL 265*ea8dc4b6Seschrock mutex_enter(&spa->spa_errlog_lock); 266*ea8dc4b6Seschrock 267*ea8dc4b6Seschrock ret = process_error_log(spa, spa->spa_errlog_scrub, uaddr, count); 268*ea8dc4b6Seschrock 269*ea8dc4b6Seschrock if (!ret && !spa->spa_scrub_finished) 270*ea8dc4b6Seschrock ret = process_error_log(spa, spa->spa_errlog_last, uaddr, 271*ea8dc4b6Seschrock count); 272*ea8dc4b6Seschrock 273*ea8dc4b6Seschrock mutex_enter(&spa->spa_errlist_lock); 274*ea8dc4b6Seschrock if (!ret) 275*ea8dc4b6Seschrock ret = process_error_list(&spa->spa_errlist_scrub, uaddr, 276*ea8dc4b6Seschrock count); 277*ea8dc4b6Seschrock if (!ret) 278*ea8dc4b6Seschrock ret = process_error_list(&spa->spa_errlist_last, uaddr, 279*ea8dc4b6Seschrock count); 280*ea8dc4b6Seschrock mutex_exit(&spa->spa_errlist_lock); 281*ea8dc4b6Seschrock 282*ea8dc4b6Seschrock mutex_exit(&spa->spa_errlog_lock); 283*ea8dc4b6Seschrock #endif 284*ea8dc4b6Seschrock 285*ea8dc4b6Seschrock return (ret); 286*ea8dc4b6Seschrock } 287*ea8dc4b6Seschrock 288*ea8dc4b6Seschrock /* 289*ea8dc4b6Seschrock * Called when a scrub completes. This simply set a bit which tells which AVL 290*ea8dc4b6Seschrock * tree to add new errors. spa_errlog_sync() is responsible for actually 291*ea8dc4b6Seschrock * syncing the changes to the underlying objects. 292*ea8dc4b6Seschrock */ 293*ea8dc4b6Seschrock void 294*ea8dc4b6Seschrock spa_errlog_rotate(spa_t *spa) 295*ea8dc4b6Seschrock { 296*ea8dc4b6Seschrock mutex_enter(&spa->spa_errlist_lock); 297*ea8dc4b6Seschrock 298*ea8dc4b6Seschrock ASSERT(!spa->spa_scrub_finished); 299*ea8dc4b6Seschrock spa->spa_scrub_finished = B_TRUE; 300*ea8dc4b6Seschrock 301*ea8dc4b6Seschrock mutex_exit(&spa->spa_errlist_lock); 302*ea8dc4b6Seschrock } 303*ea8dc4b6Seschrock 304*ea8dc4b6Seschrock /* 305*ea8dc4b6Seschrock * Discard any pending errors from the spa_t. Called when unloading a faulted 306*ea8dc4b6Seschrock * pool, as the errors encountered during the open cannot be synced to disk. 307*ea8dc4b6Seschrock */ 308*ea8dc4b6Seschrock void 309*ea8dc4b6Seschrock spa_errlog_drain(spa_t *spa) 310*ea8dc4b6Seschrock { 311*ea8dc4b6Seschrock spa_error_entry_t *se; 312*ea8dc4b6Seschrock void *cookie; 313*ea8dc4b6Seschrock 314*ea8dc4b6Seschrock mutex_enter(&spa->spa_errlist_lock); 315*ea8dc4b6Seschrock 316*ea8dc4b6Seschrock cookie = NULL; 317*ea8dc4b6Seschrock while ((se = avl_destroy_nodes(&spa->spa_errlist_last, 318*ea8dc4b6Seschrock &cookie)) != NULL) 319*ea8dc4b6Seschrock kmem_free(se, sizeof (spa_error_entry_t)); 320*ea8dc4b6Seschrock cookie = NULL; 321*ea8dc4b6Seschrock while ((se = avl_destroy_nodes(&spa->spa_errlist_scrub, 322*ea8dc4b6Seschrock &cookie)) != NULL) 323*ea8dc4b6Seschrock kmem_free(se, sizeof (spa_error_entry_t)); 324*ea8dc4b6Seschrock 325*ea8dc4b6Seschrock mutex_exit(&spa->spa_errlist_lock); 326*ea8dc4b6Seschrock } 327*ea8dc4b6Seschrock 328*ea8dc4b6Seschrock /* 329*ea8dc4b6Seschrock * Process a list of errors into the current on-disk log. 330*ea8dc4b6Seschrock */ 331*ea8dc4b6Seschrock static void 332*ea8dc4b6Seschrock sync_error_list(spa_t *spa, avl_tree_t *t, uint64_t *obj, dmu_tx_t *tx) 333*ea8dc4b6Seschrock { 334*ea8dc4b6Seschrock spa_error_entry_t *se; 335*ea8dc4b6Seschrock char buf[64]; 336*ea8dc4b6Seschrock void *cookie; 337*ea8dc4b6Seschrock 338*ea8dc4b6Seschrock if (avl_numnodes(t) != 0) { 339*ea8dc4b6Seschrock /* create log if necessary */ 340*ea8dc4b6Seschrock if (*obj == 0) 341*ea8dc4b6Seschrock *obj = zap_create(spa->spa_meta_objset, 342*ea8dc4b6Seschrock DMU_OT_ERROR_LOG, DMU_OT_NONE, 343*ea8dc4b6Seschrock 0, tx); 344*ea8dc4b6Seschrock 345*ea8dc4b6Seschrock /* add errors to the current log */ 346*ea8dc4b6Seschrock for (se = avl_first(t); se != NULL; se = AVL_NEXT(t, se)) { 347*ea8dc4b6Seschrock char *name = se->se_name ? se->se_name : ""; 348*ea8dc4b6Seschrock 349*ea8dc4b6Seschrock bookmark_to_name(&se->se_bookmark, buf, sizeof (buf)); 350*ea8dc4b6Seschrock 351*ea8dc4b6Seschrock (void) zap_update(spa->spa_meta_objset, 352*ea8dc4b6Seschrock *obj, buf, 1, strlen(name) + 1, name, tx); 353*ea8dc4b6Seschrock } 354*ea8dc4b6Seschrock 355*ea8dc4b6Seschrock /* purge the error list */ 356*ea8dc4b6Seschrock cookie = NULL; 357*ea8dc4b6Seschrock while ((se = avl_destroy_nodes(t, &cookie)) != NULL) 358*ea8dc4b6Seschrock kmem_free(se, sizeof (spa_error_entry_t)); 359*ea8dc4b6Seschrock } 360*ea8dc4b6Seschrock } 361*ea8dc4b6Seschrock 362*ea8dc4b6Seschrock /* 363*ea8dc4b6Seschrock * Sync the error log out to disk. This is a little tricky because the act of 364*ea8dc4b6Seschrock * writing the error log requires the spa_errlist_lock. So, we need to lock the 365*ea8dc4b6Seschrock * error lists, take a copy of the lists, and then reinitialize them. Then, we 366*ea8dc4b6Seschrock * drop the error list lock and take the error log lock, at which point we 367*ea8dc4b6Seschrock * do the errlog processing. Then, if we encounter an I/O error during this 368*ea8dc4b6Seschrock * process, we can successfully add the error to the list. Note that this will 369*ea8dc4b6Seschrock * result in the perpetual recycling of errors, but it is an unlikely situation 370*ea8dc4b6Seschrock * and not a performance critical operation. 371*ea8dc4b6Seschrock */ 372*ea8dc4b6Seschrock void 373*ea8dc4b6Seschrock spa_errlog_sync(spa_t *spa, uint64_t txg) 374*ea8dc4b6Seschrock { 375*ea8dc4b6Seschrock dmu_tx_t *tx; 376*ea8dc4b6Seschrock avl_tree_t scrub, last; 377*ea8dc4b6Seschrock int scrub_finished; 378*ea8dc4b6Seschrock 379*ea8dc4b6Seschrock mutex_enter(&spa->spa_errlist_lock); 380*ea8dc4b6Seschrock 381*ea8dc4b6Seschrock /* 382*ea8dc4b6Seschrock * Bail out early under normal circumstances. 383*ea8dc4b6Seschrock */ 384*ea8dc4b6Seschrock if (avl_numnodes(&spa->spa_errlist_scrub) == 0 && 385*ea8dc4b6Seschrock avl_numnodes(&spa->spa_errlist_last) == 0 && 386*ea8dc4b6Seschrock !spa->spa_scrub_finished) { 387*ea8dc4b6Seschrock mutex_exit(&spa->spa_errlist_lock); 388*ea8dc4b6Seschrock return; 389*ea8dc4b6Seschrock } 390*ea8dc4b6Seschrock 391*ea8dc4b6Seschrock spa_get_errlists(spa, &last, &scrub); 392*ea8dc4b6Seschrock scrub_finished = spa->spa_scrub_finished; 393*ea8dc4b6Seschrock spa->spa_scrub_finished = B_FALSE; 394*ea8dc4b6Seschrock 395*ea8dc4b6Seschrock mutex_exit(&spa->spa_errlist_lock); 396*ea8dc4b6Seschrock mutex_enter(&spa->spa_errlog_lock); 397*ea8dc4b6Seschrock 398*ea8dc4b6Seschrock tx = dmu_tx_create_assigned(spa->spa_dsl_pool, txg); 399*ea8dc4b6Seschrock 400*ea8dc4b6Seschrock /* 401*ea8dc4b6Seschrock * Sync out the current list of errors. 402*ea8dc4b6Seschrock */ 403*ea8dc4b6Seschrock sync_error_list(spa, &last, &spa->spa_errlog_last, tx); 404*ea8dc4b6Seschrock 405*ea8dc4b6Seschrock /* 406*ea8dc4b6Seschrock * Rotate the log if necessary. 407*ea8dc4b6Seschrock */ 408*ea8dc4b6Seschrock if (scrub_finished) { 409*ea8dc4b6Seschrock if (spa->spa_errlog_last != 0) 410*ea8dc4b6Seschrock VERIFY(dmu_object_free(spa->spa_meta_objset, 411*ea8dc4b6Seschrock spa->spa_errlog_last, tx) == 0); 412*ea8dc4b6Seschrock spa->spa_errlog_last = spa->spa_errlog_scrub; 413*ea8dc4b6Seschrock spa->spa_errlog_scrub = 0; 414*ea8dc4b6Seschrock 415*ea8dc4b6Seschrock sync_error_list(spa, &scrub, &spa->spa_errlog_last, tx); 416*ea8dc4b6Seschrock } 417*ea8dc4b6Seschrock 418*ea8dc4b6Seschrock /* 419*ea8dc4b6Seschrock * Sync out any pending scrub errors. 420*ea8dc4b6Seschrock */ 421*ea8dc4b6Seschrock sync_error_list(spa, &scrub, &spa->spa_errlog_scrub, tx); 422*ea8dc4b6Seschrock 423*ea8dc4b6Seschrock /* 424*ea8dc4b6Seschrock * Update the MOS to reflect the new values. 425*ea8dc4b6Seschrock */ 426*ea8dc4b6Seschrock (void) zap_update(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT, 427*ea8dc4b6Seschrock DMU_POOL_ERRLOG_LAST, sizeof (uint64_t), 1, 428*ea8dc4b6Seschrock &spa->spa_errlog_last, tx); 429*ea8dc4b6Seschrock (void) zap_update(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT, 430*ea8dc4b6Seschrock DMU_POOL_ERRLOG_SCRUB, sizeof (uint64_t), 1, 431*ea8dc4b6Seschrock &spa->spa_errlog_scrub, tx); 432*ea8dc4b6Seschrock 433*ea8dc4b6Seschrock dmu_tx_commit(tx); 434*ea8dc4b6Seschrock 435*ea8dc4b6Seschrock mutex_exit(&spa->spa_errlog_lock); 436*ea8dc4b6Seschrock } 437