]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/spa_misc.c
Illumos 4171, 4172
[mirror_zfs.git] / module / zfs / spa_misc.c
index e4e0c35f01df4cc3efbbaabf9532b1cdf2f1c864..50c3b9afd80515ec43259fb8a99a56485d09b2c8 100644 (file)
@@ -20,7 +20,8 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -33,6 +34,7 @@
 #include <sys/zap.h>
 #include <sys/zil.h>
 #include <sys/vdev_impl.h>
+#include <sys/vdev_file.h>
 #include <sys/metaslab.h>
 #include <sys/uberblock_impl.h>
 #include <sys/txg.h>
@@ -47,7 +49,9 @@
 #include <sys/metaslab_impl.h>
 #include <sys/arc.h>
 #include <sys/ddt.h>
+#include <sys/kstat.h>
 #include "zfs_prop.h"
+#include "zfeature_common.h"
 
 /*
  * SPA locking
  * Like spa_vdev_enter/exit, these are convenience wrappers -- the actual
  * locking is, always, based on spa_namespace_lock and spa_config_lock[].
  *
- * spa_rename() is also implemented within this file since is requires
+ * spa_rename() is also implemented within this file since it requires
  * manipulation of the namespace.
  */
 
@@ -234,20 +238,31 @@ static avl_tree_t spa_l2cache_avl;
 kmem_cache_t *spa_buffer_pool;
 int spa_mode_global;
 
-#ifdef ZFS_DEBUG
-/* Everything except dprintf is on by default in debug builds */
-int zfs_flags = ~ZFS_DEBUG_DPRINTF;
-#else
-int zfs_flags = 0;
-#endif
+/*
+ * Expiration time in milliseconds. This value has two meanings. First it is
+ * used to determine when the spa_deadman() logic should fire. By default the
+ * spa_deadman() will fire if spa_sync() has not completed in 1000 seconds.
+ * Secondly, the value determines if an I/O is considered "hung". Any I/O that
+ * has not completed in zfs_deadman_synctime_ms is considered "hung" resulting
+ * in a system panic.
+ */
+unsigned long zfs_deadman_synctime_ms = 1000000ULL;
 
 /*
- * zfs_recover can be set to nonzero to attempt to recover from
- * otherwise-fatal errors, typically caused by on-disk corruption.  When
- * set, calls to zfs_panic_recover() will turn into warning messages.
+ * By default the deadman is enabled.
  */
-int zfs_recover = 0;
+int zfs_deadman_enabled = 1;
 
+/*
+ * The worst case is single-sector max-parity RAID-Z blocks, in which
+ * case the space requirement is exactly (VDEV_RAIDZ_MAXPARITY + 1)
+ * times the size; so just assume that.  Add to this the fact that
+ * we can have up to 3 DVAs per bp, and one more factor of 2 because
+ * the block may be dittoed with up to 3 DVAs by ddt_sync().  All together,
+ * the worst case is:
+ *     (VDEV_RAIDZ_MAXPARITY + 1) * SPA_DVAS_PER_BP * 2 == 24
+ */
+int spa_asize_inflation = 24;
 
 /*
  * ==========================================================================
@@ -263,7 +278,7 @@ spa_config_lock_init(spa_t *spa)
                spa_config_lock_t *scl = &spa->spa_config_lock[i];
                mutex_init(&scl->scl_lock, NULL, MUTEX_DEFAULT, NULL);
                cv_init(&scl->scl_cv, NULL, CV_DEFAULT, NULL);
-               refcount_create(&scl->scl_count);
+               refcount_create_untracked(&scl->scl_count);
                scl->scl_writer = NULL;
                scl->scl_write_wanted = 0;
        }
@@ -321,6 +336,8 @@ spa_config_enter(spa_t *spa, int locks, void *tag, krw_t rw)
        int wlocks_held = 0;
        int i;
 
+       ASSERT3U(SCL_LOCKS, <, sizeof (wlocks_held) * NBBY);
+
        for (i = 0; i < SCL_LOCKS; i++) {
                spa_config_lock_t *scl = &spa->spa_config_lock[i];
                if (scl->scl_writer == curthread)
@@ -401,30 +418,46 @@ spa_lookup(const char *name)
        static spa_t search;    /* spa_t is large; don't allocate on stack */
        spa_t *spa;
        avl_index_t where;
-       char c = 0;
        char *cp;
 
        ASSERT(MUTEX_HELD(&spa_namespace_lock));
 
+       (void) strlcpy(search.spa_name, name, sizeof (search.spa_name));
+
        /*
         * If it's a full dataset name, figure out the pool name and
         * just use that.
         */
-       cp = strpbrk(name, "/@");
-       if (cp) {
-               c = *cp;
+       cp = strpbrk(search.spa_name, "/@");
+       if (cp != NULL)
                *cp = '\0';
-       }
 
-       (void) strlcpy(search.spa_name, name, sizeof (search.spa_name));
        spa = avl_find(&spa_namespace_avl, &search, &where);
 
-       if (cp)
-               *cp = c;
-
        return (spa);
 }
 
+/*
+ * Fires when spa_sync has not completed within zfs_deadman_synctime_ms.
+ * If the zfs_deadman_enabled flag is set then it inspects all vdev queues
+ * looking for potentially hung I/Os.
+ */
+void
+spa_deadman(void *arg)
+{
+       spa_t *spa = arg;
+
+       zfs_dbgmsg("slow spa_sync: started %llu seconds ago, calls %llu",
+           (gethrtime() - spa->spa_sync_starttime) / NANOSEC,
+           ++spa->spa_deadman_calls);
+       if (zfs_deadman_enabled)
+               vdev_deadman(spa->spa_root_vdev);
+
+       spa->spa_deadman_tqid = taskq_dispatch_delay(system_taskq,
+           spa_deadman, spa, TQ_PUSHPAGE, ddi_get_lbolt() +
+           NSEC_TO_TICK(spa->spa_deadman_synctime));
+}
+
 /*
  * Create an uninitialized spa_t with the given name.  Requires
  * spa_namespace_lock.  The caller must ensure that the spa_t doesn't already
@@ -439,7 +472,7 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
 
        ASSERT(MUTEX_HELD(&spa_namespace_lock));
 
-       spa = kmem_zalloc(sizeof (spa_t), KM_SLEEP | KM_NODEBUG);
+       spa = kmem_zalloc(sizeof (spa_t), KM_PUSHPAGE | KM_NODEBUG);
 
        mutex_init(&spa->spa_async_lock, NULL, MUTEX_DEFAULT, NULL);
        mutex_init(&spa->spa_errlist_lock, NULL, MUTEX_DEFAULT, NULL);
@@ -467,8 +500,11 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
        spa->spa_proc = &p0;
        spa->spa_proc_state = SPA_PROC_NONE;
 
+       spa->spa_deadman_synctime = MSEC2NSEC(zfs_deadman_synctime_ms);
+
        refcount_create(&spa->spa_refcount);
        spa_config_lock_init(spa);
+       spa_stats_init(spa);
 
        avl_add(&spa_namespace_avl, spa);
 
@@ -486,15 +522,31 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
        list_create(&spa->spa_config_list, sizeof (spa_config_dirent_t),
            offsetof(spa_config_dirent_t, scd_link));
 
-       dp = kmem_zalloc(sizeof (spa_config_dirent_t), KM_SLEEP);
+       dp = kmem_zalloc(sizeof (spa_config_dirent_t), KM_PUSHPAGE);
        dp->scd_path = altroot ? NULL : spa_strdup(spa_config_path);
        list_insert_head(&spa->spa_config_list, dp);
 
        VERIFY(nvlist_alloc(&spa->spa_load_info, NV_UNIQUE_NAME,
-           KM_SLEEP) == 0);
+           KM_PUSHPAGE) == 0);
+
+       if (config != NULL) {
+               nvlist_t *features;
+
+               if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURES_FOR_READ,
+                   &features) == 0) {
+                       VERIFY(nvlist_dup(features, &spa->spa_label_features,
+                           0) == 0);
+               }
 
-       if (config != NULL)
                VERIFY(nvlist_dup(config, &spa->spa_config, 0) == 0);
+       }
+
+       if (spa->spa_label_features == NULL) {
+               VERIFY(nvlist_alloc(&spa->spa_label_features, NV_UNIQUE_NAME,
+                   KM_PUSHPAGE) == 0);
+       }
+
+       spa->spa_debug = ((zfs_flags & ZFS_DEBUG_SPA) != 0);
 
        return (spa);
 }
@@ -532,11 +584,13 @@ spa_remove(spa_t *spa)
 
        list_destroy(&spa->spa_config_list);
 
+       nvlist_free(spa->spa_label_features);
        nvlist_free(spa->spa_load_info);
        spa_config_set(spa, NULL);
 
        refcount_destroy(&spa->spa_refcount);
 
+       spa_stats_destroy(spa);
        spa_config_lock_destroy(spa);
 
        for (t = 0; t < TXG_SIZE; t++)
@@ -661,7 +715,7 @@ spa_aux_add(vdev_t *vd, avl_tree_t *avl)
        if ((aux = avl_find(avl, &search, &where)) != NULL) {
                aux->aux_count++;
        } else {
-               aux = kmem_zalloc(sizeof (spa_aux_t), KM_SLEEP);
+               aux = kmem_zalloc(sizeof (spa_aux_t), KM_PUSHPAGE);
                aux->aux_guid = vd->vdev_guid;
                aux->aux_count = 1;
                avl_insert(avl, aux, where);
@@ -932,7 +986,7 @@ spa_vdev_config_exit(spa_t *spa, vdev_t *vd, uint64_t txg, int error, char *tag)
                txg_wait_synced(spa->spa_dsl_pool, txg);
 
        if (vd != NULL) {
-               ASSERT(!vd->vdev_detached || vd->vdev_dtl_smo.smo_object == 0);
+               ASSERT(!vd->vdev_detached || vd->vdev_dtl_sm == NULL);
                spa_config_enter(spa, SCL_ALL, spa, RW_WRITER);
                vdev_free(vd);
                spa_config_exit(spa, SCL_ALL, spa);
@@ -1039,6 +1093,22 @@ spa_vdev_state_exit(spa_t *spa, vdev_t *vd, int error)
  * ==========================================================================
  */
 
+void
+spa_activate_mos_feature(spa_t *spa, const char *feature)
+{
+       if (!nvlist_exists(spa->spa_label_features, feature)) {
+               fnvlist_add_boolean(spa->spa_label_features, feature);
+               vdev_config_dirty(spa->spa_root_vdev);
+       }
+}
+
+void
+spa_deactivate_mos_feature(spa_t *spa, const char *feature)
+{
+       if (nvlist_remove_all(spa->spa_label_features, feature) == 0)
+               vdev_config_dirty(spa->spa_root_vdev);
+}
+
 /*
  * Rename a spa_t.
  */
@@ -1145,7 +1215,7 @@ spa_strdup(const char *s)
        char *new;
 
        len = strlen(s);
-       new = kmem_alloc(len + 1, KM_SLEEP);
+       new = kmem_alloc(len + 1, KM_PUSHPAGE);
        bcopy(s, new, len);
        new[len] = '\0';
 
@@ -1189,12 +1259,22 @@ spa_generate_guid(spa_t *spa)
 void
 sprintf_blkptr(char *buf, const blkptr_t *bp)
 {
-       char *type = NULL;
+       char type[256];
        char *checksum = NULL;
        char *compress = NULL;
 
        if (bp != NULL) {
-               type = dmu_ot[BP_GET_TYPE(bp)].ot_name;
+               if (BP_GET_TYPE(bp) & DMU_OT_NEWTYPE) {
+                       dmu_object_byteswap_t bswap =
+                           DMU_OT_BYTESWAP(BP_GET_TYPE(bp));
+                       (void) snprintf(type, sizeof (type), "bswap %s %s",
+                           DMU_OT_IS_METADATA(BP_GET_TYPE(bp)) ?
+                           "metadata" : "data",
+                           dmu_ot_byteswap[bswap].ob_name);
+               } else {
+                       (void) strlcpy(type, dmu_ot[BP_GET_TYPE(bp)].ot_name,
+                           sizeof (type));
+               }
                checksum = zio_checksum_table[BP_GET_CHECKSUM(bp)].ci_name;
                compress = zio_compress_table[BP_GET_COMPRESS(bp)].ci_name;
        }
@@ -1217,19 +1297,9 @@ spa_freeze(spa_t *spa)
                txg_wait_synced(spa_get_dsl(spa), freeze_txg);
 }
 
-void
-zfs_panic_recover(const char *fmt, ...)
-{
-       va_list adx;
-
-       va_start(adx, fmt);
-       vcmn_err(zfs_recover ? CE_WARN : CE_PANIC, fmt, adx);
-       va_end(adx);
-}
-
 /*
  * This is a stripped-down version of strtoull, suitable only for converting
- * lowercase hexidecimal numbers that don't overflow.
+ * lowercase hexadecimal numbers that don't overflow.
  */
 uint64_t
 strtonum(const char *str, char **nptr)
@@ -1276,6 +1346,12 @@ spa_get_dsl(spa_t *spa)
        return (spa->spa_dsl_pool);
 }
 
+boolean_t
+spa_is_initializing(spa_t *spa)
+{
+       return (spa->spa_is_initializing);
+}
+
 blkptr_t *
 spa_get_rootblkptr(spa_t *spa)
 {
@@ -1312,16 +1388,40 @@ spa_name(spa_t *spa)
 uint64_t
 spa_guid(spa_t *spa)
 {
+       dsl_pool_t *dp = spa_get_dsl(spa);
+       uint64_t guid;
+
        /*
         * If we fail to parse the config during spa_load(), we can go through
         * the error path (which posts an ereport) and end up here with no root
-        * vdev.  We stash the original pool guid in 'spa_load_guid' to handle
+        * vdev.  We stash the original pool guid in 'spa_config_guid' to handle
         * this case.
         */
-       if (spa->spa_root_vdev != NULL)
+       if (spa->spa_root_vdev == NULL)
+               return (spa->spa_config_guid);
+
+       guid = spa->spa_last_synced_guid != 0 ?
+           spa->spa_last_synced_guid : spa->spa_root_vdev->vdev_guid;
+
+       /*
+        * Return the most recently synced out guid unless we're
+        * in syncing context.
+        */
+       if (dp && dsl_pool_sync_context(dp))
                return (spa->spa_root_vdev->vdev_guid);
        else
-               return (spa->spa_load_guid);
+               return (guid);
+}
+
+uint64_t
+spa_load_guid(spa_t *spa)
+{
+       /*
+        * This is a GUID that exists solely as a reference for the
+        * purposes of the arc.  It is generated at load time, and
+        * is never written to persistent storage.
+        */
+       return (spa->spa_load_guid);
 }
 
 uint64_t
@@ -1364,14 +1464,7 @@ spa_freeze_txg(spa_t *spa)
 uint64_t
 spa_get_asize(spa_t *spa, uint64_t lsize)
 {
-       /*
-        * The worst case is single-sector max-parity RAID-Z blocks, in which
-        * case the space requirement is exactly (VDEV_RAIDZ_MAXPARITY + 1)
-        * times the size; so just assume that.  Add to this the fact that
-        * we can have up to 3 DVAs per bp, and one more factor of 2 because
-        * the block may be dittoed with up to 3 DVAs by ddt_sync().
-        */
-       return (lsize * (VDEV_RAIDZ_MAXPARITY + 1) * SPA_DVAS_PER_BP * 2);
+       return (lsize * spa_asize_inflation);
 }
 
 uint64_t
@@ -1446,6 +1539,12 @@ spa_prev_software_version(spa_t *spa)
        return (spa->spa_prev_software_version);
 }
 
+uint64_t
+spa_deadman_synctime(spa_t *spa)
+{
+       return (spa->spa_deadman_synctime);
+}
+
 uint64_t
 dva_get_dsize_sync(spa_t *spa, const dva_t *dva)
 {
@@ -1456,7 +1555,9 @@ dva_get_dsize_sync(spa_t *spa, const dva_t *dva)
 
        if (asize != 0 && spa->spa_deflate) {
                vdev_t *vd = vdev_lookup_top(spa, DVA_GET_VDEV(dva));
-               dsize = (asize >> SPA_MINBLOCKSHIFT) * vd->vdev_deflate_ratio;
+               if (vd != NULL)
+                       dsize = (asize >> SPA_MINBLOCKSHIFT) *
+                           vd->vdev_deflate_ratio;
        }
 
        return (dsize);
@@ -1536,15 +1637,36 @@ spa_init(int mode)
 
        spa_mode_global = mode;
 
+#ifndef _KERNEL
+       if (spa_mode_global != FREAD && dprintf_find_string("watch")) {
+               struct sigaction sa;
+
+               sa.sa_flags = SA_SIGINFO;
+               sigemptyset(&sa.sa_mask);
+               sa.sa_sigaction = arc_buf_sigsegv;
+
+               if (sigaction(SIGSEGV, &sa, NULL) == -1) {
+                       perror("could not enable watchpoints: "
+                           "sigaction(SIGSEGV, ...) = ");
+               } else {
+                       arc_watch = B_TRUE;
+               }
+       }
+#endif
+
        fm_init();
        refcount_init();
        unique_init();
+       range_tree_init();
+       ddt_init();
        zio_init();
        dmu_init();
        zil_init();
        vdev_cache_stat_init();
+       vdev_file_init();
        zfs_prop_init();
        zpool_prop_init();
+       zpool_feature_init();
        spa_config_load();
        l2arc_start();
 }
@@ -1556,10 +1678,13 @@ spa_fini(void)
 
        spa_evict_all();
 
+       vdev_file_fini();
        vdev_cache_stat_fini();
        zil_fini();
        dmu_fini();
        zio_fini();
+       ddt_fini();
+       range_tree_fini();
        unique_fini();
        refcount_fini();
        fm_fini();
@@ -1660,7 +1785,7 @@ spa_scan_get_stats(spa_t *spa, pool_scan_stat_t *ps)
        dsl_scan_t *scn = spa->spa_dsl_pool ? spa->spa_dsl_pool->dp_scan : NULL;
 
        if (scn == NULL || scn->scn_phys.scn_func == POOL_SCAN_NONE)
-               return (ENOENT);
+               return (SET_ERROR(ENOENT));
        bzero(ps, sizeof (pool_scan_stat_t));
 
        /* data stored on disk */
@@ -1766,6 +1891,13 @@ EXPORT_SYMBOL(spa_mode);
 
 EXPORT_SYMBOL(spa_namespace_lock);
 
-module_param(zfs_recover, int, 0644);
-MODULE_PARM_DESC(zfs_recover, "Set to attempt to recover from fatal errors");
+module_param(zfs_deadman_synctime_ms, ulong, 0644);
+MODULE_PARM_DESC(zfs_deadman_synctime_ms, "Expiration time in milliseconds");
+
+module_param(zfs_deadman_enabled, int, 0644);
+MODULE_PARM_DESC(zfs_deadman_enabled, "Enable deadman timer");
+
+module_param(spa_asize_inflation, int, 0644);
+MODULE_PARM_DESC(spa_asize_inflation,
+       "SPA size estimate multiplication factor");
 #endif