]> 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 5ec8e688e7898bca588bb9524f120cd573267766..50c3b9afd80515ec43259fb8a99a56485d09b2c8 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  */
 
@@ -34,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>
@@ -48,6 +49,7 @@
 #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"
 
@@ -236,6 +238,32 @@ static avl_tree_t spa_l2cache_avl;
 kmem_cache_t *spa_buffer_pool;
 int spa_mode_global;
 
+/*
+ * 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;
+
+/*
+ * By default the deadman is enabled.
+ */
+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;
+
 /*
  * ==========================================================================
  * SPA config locking
@@ -250,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;
        }
@@ -308,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)
@@ -388,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
@@ -454,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);
 
@@ -494,9 +543,11 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
 
        if (spa->spa_label_features == NULL) {
                VERIFY(nvlist_alloc(&spa->spa_label_features, NV_UNIQUE_NAME,
-                   KM_SLEEP) == 0);
+                   KM_PUSHPAGE) == 0);
        }
 
+       spa->spa_debug = ((zfs_flags & ZFS_DEBUG_SPA) != 0);
+
        return (spa);
 }
 
@@ -539,6 +590,7 @@ spa_remove(spa_t *spa)
 
        refcount_destroy(&spa->spa_refcount);
 
+       spa_stats_destroy(spa);
        spa_config_lock_destroy(spa);
 
        for (t = 0; t < TXG_SIZE; t++)
@@ -934,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);
@@ -1044,15 +1096,17 @@ spa_vdev_state_exit(spa_t *spa, vdev_t *vd, int error)
 void
 spa_activate_mos_feature(spa_t *spa, const char *feature)
 {
-       (void) nvlist_add_boolean(spa->spa_label_features, feature);
-       vdev_config_dirty(spa->spa_root_vdev);
+       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)
 {
-       (void) nvlist_remove_all(spa->spa_label_features, feature);
-       vdev_config_dirty(spa->spa_root_vdev);
+       if (nvlist_remove_all(spa->spa_label_features, feature) == 0)
+               vdev_config_dirty(spa->spa_root_vdev);
 }
 
 /*
@@ -1245,7 +1299,7 @@ spa_freeze(spa_t *spa)
 
 /*
  * 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)
@@ -1410,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
@@ -1492,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)
 {
@@ -1502,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);
@@ -1582,13 +1637,33 @@ 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();
@@ -1603,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();
@@ -1707,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 */
@@ -1812,4 +1890,14 @@ EXPORT_SYMBOL(spa_writeable);
 EXPORT_SYMBOL(spa_mode);
 
 EXPORT_SYMBOL(spa_namespace_lock);
+
+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