FreeBSD ZFS
The Zettabyte File System

spa_errlog.c

Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines