FreeBSD ZFS
The Zettabyte File System
|
00001 /* 00002 * CDDL HEADER START 00003 * 00004 * The contents of this file are subject to the terms of the 00005 * Common Development and Distribution License (the "License"). 00006 * You may not use this file except in compliance with the License. 00007 * 00008 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 00009 * or http://www.opensolaris.org/os/licensing. 00010 * See the License for the specific language governing permissions 00011 * and limitations under the License. 00012 * 00013 * When distributing Covered Code, include this CDDL HEADER in each 00014 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 00015 * If applicable, add the following below this CDDL HEADER, with the 00016 * fields enclosed by brackets "[]" replaced with your own identifying 00017 * information: Portions Copyright [yyyy] [name of copyright owner] 00018 * 00019 * CDDL HEADER END 00020 */ 00021 /* 00022 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 00023 */ 00024 00051 #include <sys/dmu_tx.h> 00052 #include <sys/spa.h> 00053 #include <sys/spa_impl.h> 00054 #include <sys/zap.h> 00055 #include <sys/zio.h> 00056 00057 00061 static void 00062 bookmark_to_name(zbookmark_t *zb, char *buf, size_t len) 00063 { 00064 (void) snprintf(buf, len, "%llx:%llx:%llx:%llx", 00065 (u_longlong_t)zb->zb_objset, (u_longlong_t)zb->zb_object, 00066 (u_longlong_t)zb->zb_level, (u_longlong_t)zb->zb_blkid); 00067 } 00068 00072 #ifdef _KERNEL 00073 static void 00074 name_to_bookmark(char *buf, zbookmark_t *zb) 00075 { 00076 zb->zb_objset = strtonum(buf, &buf); 00077 ASSERT(*buf == ':'); 00078 zb->zb_object = strtonum(buf + 1, &buf); 00079 ASSERT(*buf == ':'); 00080 zb->zb_level = (int)strtonum(buf + 1, &buf); 00081 ASSERT(*buf == ':'); 00082 zb->zb_blkid = strtonum(buf + 1, &buf); 00083 ASSERT(*buf == '\0'); 00084 } 00085 #endif 00086 00092 void 00093 spa_log_error(spa_t *spa, zio_t *zio) 00094 { 00095 zbookmark_t *zb = &zio->io_logical->io_bookmark; 00096 spa_error_entry_t search; 00097 spa_error_entry_t *new; 00098 avl_tree_t *tree; 00099 avl_index_t where; 00100 00101 /* 00102 * If we are trying to import a pool, ignore any errors, as we won't be 00103 * writing to the pool any time soon. 00104 */ 00105 if (spa_load_state(spa) == SPA_LOAD_TRYIMPORT) 00106 return; 00107 00108 mutex_enter(&spa->spa_errlist_lock); 00109 00110 /* 00111 * If we have had a request to rotate the log, log it to the next list 00112 * instead of the current one. 00113 */ 00114 if (spa->spa_scrub_active || spa->spa_scrub_finished) 00115 tree = &spa->spa_errlist_scrub; 00116 else 00117 tree = &spa->spa_errlist_last; 00118 00119 search.se_bookmark = *zb; 00120 if (avl_find(tree, &search, &where) != NULL) { 00121 mutex_exit(&spa->spa_errlist_lock); 00122 return; 00123 } 00124 00125 new = kmem_zalloc(sizeof (spa_error_entry_t), KM_SLEEP); 00126 new->se_bookmark = *zb; 00127 avl_insert(tree, new, where); 00128 00129 mutex_exit(&spa->spa_errlist_lock); 00130 } 00131 00137 uint64_t 00138 spa_get_errlog_size(spa_t *spa) 00139 { 00140 uint64_t total = 0, count; 00141 00142 mutex_enter(&spa->spa_errlog_lock); 00143 if (spa->spa_errlog_scrub != 0 && 00144 zap_count(spa->spa_meta_objset, spa->spa_errlog_scrub, 00145 &count) == 0) 00146 total += count; 00147 00148 if (spa->spa_errlog_last != 0 && !spa->spa_scrub_finished && 00149 zap_count(spa->spa_meta_objset, spa->spa_errlog_last, 00150 &count) == 0) 00151 total += count; 00152 mutex_exit(&spa->spa_errlog_lock); 00153 00154 mutex_enter(&spa->spa_errlist_lock); 00155 total += avl_numnodes(&spa->spa_errlist_last); 00156 total += avl_numnodes(&spa->spa_errlist_scrub); 00157 mutex_exit(&spa->spa_errlist_lock); 00158 00159 return (total); 00160 } 00161 00162 #ifdef _KERNEL 00163 static int 00164 process_error_log(spa_t *spa, uint64_t obj, void *addr, size_t *count) 00165 { 00166 zap_cursor_t zc; 00167 zap_attribute_t za; 00168 zbookmark_t zb; 00169 00170 if (obj == 0) 00171 return (0); 00172 00173 for (zap_cursor_init(&zc, spa->spa_meta_objset, obj); 00174 zap_cursor_retrieve(&zc, &za) == 0; 00175 zap_cursor_advance(&zc)) { 00176 00177 if (*count == 0) { 00178 zap_cursor_fini(&zc); 00179 return (ENOMEM); 00180 } 00181 00182 name_to_bookmark(za.za_name, &zb); 00183 00184 if (copyout(&zb, (char *)addr + 00185 (*count - 1) * sizeof (zbookmark_t), 00186 sizeof (zbookmark_t)) != 0) 00187 return (EFAULT); 00188 00189 *count -= 1; 00190 } 00191 00192 zap_cursor_fini(&zc); 00193 00194 return (0); 00195 } 00196 00197 static int 00198 process_error_list(avl_tree_t *list, void *addr, size_t *count) 00199 { 00200 spa_error_entry_t *se; 00201 00202 for (se = avl_first(list); se != NULL; se = AVL_NEXT(list, se)) { 00203 00204 if (*count == 0) 00205 return (ENOMEM); 00206 00207 if (copyout(&se->se_bookmark, (char *)addr + 00208 (*count - 1) * sizeof (zbookmark_t), 00209 sizeof (zbookmark_t)) != 0) 00210 return (EFAULT); 00211 00212 *count -= 1; 00213 } 00214 00215 return (0); 00216 } 00217 #endif 00218 00230 int 00231 spa_get_errlog(spa_t *spa, void *uaddr, size_t *count) 00232 { 00233 int ret = 0; 00234 00235 #ifdef _KERNEL 00236 mutex_enter(&spa->spa_errlog_lock); 00237 00238 ret = process_error_log(spa, spa->spa_errlog_scrub, uaddr, count); 00239 00240 if (!ret && !spa->spa_scrub_finished) 00241 ret = process_error_log(spa, spa->spa_errlog_last, uaddr, 00242 count); 00243 00244 mutex_enter(&spa->spa_errlist_lock); 00245 if (!ret) 00246 ret = process_error_list(&spa->spa_errlist_scrub, uaddr, 00247 count); 00248 if (!ret) 00249 ret = process_error_list(&spa->spa_errlist_last, uaddr, 00250 count); 00251 mutex_exit(&spa->spa_errlist_lock); 00252 00253 mutex_exit(&spa->spa_errlog_lock); 00254 #endif 00255 00256 return (ret); 00257 } 00258 00264 void 00265 spa_errlog_rotate(spa_t *spa) 00266 { 00267 mutex_enter(&spa->spa_errlist_lock); 00268 spa->spa_scrub_finished = B_TRUE; 00269 mutex_exit(&spa->spa_errlist_lock); 00270 } 00271 00276 void 00277 spa_errlog_drain(spa_t *spa) 00278 { 00279 spa_error_entry_t *se; 00280 void *cookie; 00281 00282 mutex_enter(&spa->spa_errlist_lock); 00283 00284 cookie = NULL; 00285 while ((se = avl_destroy_nodes(&spa->spa_errlist_last, 00286 &cookie)) != NULL) 00287 kmem_free(se, sizeof (spa_error_entry_t)); 00288 cookie = NULL; 00289 while ((se = avl_destroy_nodes(&spa->spa_errlist_scrub, 00290 &cookie)) != NULL) 00291 kmem_free(se, sizeof (spa_error_entry_t)); 00292 00293 mutex_exit(&spa->spa_errlist_lock); 00294 } 00295 00299 static void 00300 sync_error_list(spa_t *spa, avl_tree_t *t, uint64_t *obj, dmu_tx_t *tx) 00301 { 00302 spa_error_entry_t *se; 00303 char buf[64]; 00304 void *cookie; 00305 00306 if (avl_numnodes(t) != 0) { 00307 /* create log if necessary */ 00308 if (*obj == 0) 00309 *obj = zap_create(spa->spa_meta_objset, 00310 DMU_OT_ERROR_LOG, DMU_OT_NONE, 00311 0, tx); 00312 00313 /* add errors to the current log */ 00314 for (se = avl_first(t); se != NULL; se = AVL_NEXT(t, se)) { 00315 char *name = se->se_name ? se->se_name : ""; 00316 00317 bookmark_to_name(&se->se_bookmark, buf, sizeof (buf)); 00318 00319 (void) zap_update(spa->spa_meta_objset, 00320 *obj, buf, 1, strlen(name) + 1, name, tx); 00321 } 00322 00323 /* purge the error list */ 00324 cookie = NULL; 00325 while ((se = avl_destroy_nodes(t, &cookie)) != NULL) 00326 kmem_free(se, sizeof (spa_error_entry_t)); 00327 } 00328 } 00329 00340 void 00341 spa_errlog_sync(spa_t *spa, uint64_t txg) 00342 { 00343 dmu_tx_t *tx; 00344 avl_tree_t scrub, last; 00345 int scrub_finished; 00346 00347 mutex_enter(&spa->spa_errlist_lock); 00348 00349 /* 00350 * Bail out early under normal circumstances. 00351 */ 00352 if (avl_numnodes(&spa->spa_errlist_scrub) == 0 && 00353 avl_numnodes(&spa->spa_errlist_last) == 0 && 00354 !spa->spa_scrub_finished) { 00355 mutex_exit(&spa->spa_errlist_lock); 00356 return; 00357 } 00358 00359 spa_get_errlists(spa, &last, &scrub); 00360 scrub_finished = spa->spa_scrub_finished; 00361 spa->spa_scrub_finished = B_FALSE; 00362 00363 mutex_exit(&spa->spa_errlist_lock); 00364 mutex_enter(&spa->spa_errlog_lock); 00365 00366 tx = dmu_tx_create_assigned(spa->spa_dsl_pool, txg); 00367 00368 /* 00369 * Sync out the current list of errors. 00370 */ 00371 sync_error_list(spa, &last, &spa->spa_errlog_last, tx); 00372 00373 /* 00374 * Rotate the log if necessary. 00375 */ 00376 if (scrub_finished) { 00377 if (spa->spa_errlog_last != 0) 00378 VERIFY(dmu_object_free(spa->spa_meta_objset, 00379 spa->spa_errlog_last, tx) == 0); 00380 spa->spa_errlog_last = spa->spa_errlog_scrub; 00381 spa->spa_errlog_scrub = 0; 00382 00383 sync_error_list(spa, &scrub, &spa->spa_errlog_last, tx); 00384 } 00385 00386 /* 00387 * Sync out any pending scrub errors. 00388 */ 00389 sync_error_list(spa, &scrub, &spa->spa_errlog_scrub, tx); 00390 00391 /* 00392 * Update the MOS to reflect the new values. 00393 */ 00394 (void) zap_update(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT, 00395 DMU_POOL_ERRLOG_LAST, sizeof (uint64_t), 1, 00396 &spa->spa_errlog_last, tx); 00397 (void) zap_update(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT, 00398 DMU_POOL_ERRLOG_SCRUB, sizeof (uint64_t), 1, 00399 &spa->spa_errlog_scrub, tx); 00400 00401 dmu_tx_commit(tx); 00402 00403 mutex_exit(&spa->spa_errlog_lock); 00404 }