]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/vdev_queue.c
OpenZFS 9102 - zfs should be able to initialize storage devices
[mirror_zfs.git] / module / zfs / vdev_queue.c
index 2439f2951c23f3cbb5596421ca2df58bba5cb167..939699cb837349f159867e7d032d05cfa68aac14 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 /*
- * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -152,6 +152,10 @@ uint32_t zfs_vdev_async_write_min_active = 2;
 uint32_t zfs_vdev_async_write_max_active = 10;
 uint32_t zfs_vdev_scrub_min_active = 1;
 uint32_t zfs_vdev_scrub_max_active = 2;
+uint32_t zfs_vdev_removal_min_active = 1;
+uint32_t zfs_vdev_removal_max_active = 2;
+uint32_t zfs_vdev_initializing_min_active = 1;
+uint32_t zfs_vdev_initializing_max_active = 1;
 
 /*
  * When the pool has less than zfs_vdev_async_write_active_min_dirty_percent
@@ -169,7 +173,7 @@ int zfs_vdev_async_write_active_max_dirty_percent = 60;
  * we include spans of optional I/Os to aid aggregation at the disk even when
  * they aren't able to help us aggregate at this level.
  */
-int zfs_vdev_aggregation_limit = SPA_OLD_MAXBLOCKSIZE;
+int zfs_vdev_aggregation_limit = 1 << 20;
 int zfs_vdev_read_gap_limit = 32 << 10;
 int zfs_vdev_write_gap_limit = 4 << 10;
 
@@ -189,6 +193,15 @@ int zfs_vdev_queue_depth_pct = 1000;
 int zfs_vdev_queue_depth_pct = 300;
 #endif
 
+/*
+ * When performing allocations for a given metaslab, we want to make sure that
+ * there are enough IOs to aggregate together to improve throughput. We want to
+ * ensure that there are at least 128k worth of IOs that can be aggregated, and
+ * we assume that the average allocation size is 4k, so we need the queue depth
+ * to be 32 per allocator to get good aggregation of sequential writes.
+ */
+int zfs_vdev_def_queue_depth = 32;
+
 
 int
 vdev_queue_offset_compare(const void *x1, const void *x2)
@@ -248,6 +261,10 @@ vdev_queue_class_min_active(zio_priority_t p)
                return (zfs_vdev_async_write_min_active);
        case ZIO_PRIORITY_SCRUB:
                return (zfs_vdev_scrub_min_active);
+       case ZIO_PRIORITY_REMOVAL:
+               return (zfs_vdev_removal_min_active);
+       case ZIO_PRIORITY_INITIALIZING:
+               return (zfs_vdev_initializing_min_active);
        default:
                panic("invalid priority %u", p);
                return (0);
@@ -316,6 +333,10 @@ vdev_queue_class_max_active(spa_t *spa, zio_priority_t p)
                return (vdev_queue_max_async_writes(spa));
        case ZIO_PRIORITY_SCRUB:
                return (zfs_vdev_scrub_max_active);
+       case ZIO_PRIORITY_REMOVAL:
+               return (zfs_vdev_removal_max_active);
+       case ZIO_PRIORITY_INITIALIZING:
+               return (zfs_vdev_initializing_max_active);
        default:
                panic("invalid priority %u", p);
                return (0);
@@ -393,16 +414,15 @@ vdev_queue_init(vdev_t *vd)
                    sizeof (zio_t), offsetof(struct zio, io_queue_node));
        }
 
-       vq->vq_lastoffset = 0;
+       vq->vq_last_offset = 0;
 }
 
 void
 vdev_queue_fini(vdev_t *vd)
 {
        vdev_queue_t *vq = &vd->vdev_queue;
-       zio_priority_t p;
 
-       for (p = 0; p < ZIO_PRIORITY_NUM_QUEUEABLE; p++)
+       for (zio_priority_t p = 0; p < ZIO_PRIORITY_NUM_QUEUEABLE; p++)
                avl_destroy(vdev_queue_class_tree(vq, p));
        avl_destroy(&vq->vq_active_tree);
        avl_destroy(vdev_queue_type_tree(vq, ZIO_TYPE_READ));
@@ -415,16 +435,16 @@ static void
 vdev_queue_io_add(vdev_queue_t *vq, zio_t *zio)
 {
        spa_t *spa = zio->io_spa;
-       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+       spa_history_kstat_t *shk = &spa->spa_stats.io_history;
 
        ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE);
        avl_add(vdev_queue_class_tree(vq, zio->io_priority), zio);
        avl_add(vdev_queue_type_tree(vq, zio->io_type), zio);
 
-       if (ssh->kstat != NULL) {
-               mutex_enter(&ssh->lock);
-               kstat_waitq_enter(ssh->kstat->ks_data);
-               mutex_exit(&ssh->lock);
+       if (shk->kstat != NULL) {
+               mutex_enter(&shk->lock);
+               kstat_waitq_enter(shk->kstat->ks_data);
+               mutex_exit(&shk->lock);
        }
 }
 
@@ -432,16 +452,16 @@ static void
 vdev_queue_io_remove(vdev_queue_t *vq, zio_t *zio)
 {
        spa_t *spa = zio->io_spa;
-       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+       spa_history_kstat_t *shk = &spa->spa_stats.io_history;
 
        ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE);
        avl_remove(vdev_queue_class_tree(vq, zio->io_priority), zio);
        avl_remove(vdev_queue_type_tree(vq, zio->io_type), zio);
 
-       if (ssh->kstat != NULL) {
-               mutex_enter(&ssh->lock);
-               kstat_waitq_exit(ssh->kstat->ks_data);
-               mutex_exit(&ssh->lock);
+       if (shk->kstat != NULL) {
+               mutex_enter(&shk->lock);
+               kstat_waitq_exit(shk->kstat->ks_data);
+               mutex_exit(&shk->lock);
        }
 }
 
@@ -449,17 +469,17 @@ static void
 vdev_queue_pending_add(vdev_queue_t *vq, zio_t *zio)
 {
        spa_t *spa = zio->io_spa;
-       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+       spa_history_kstat_t *shk = &spa->spa_stats.io_history;
 
        ASSERT(MUTEX_HELD(&vq->vq_lock));
        ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE);
        vq->vq_class[zio->io_priority].vqc_active++;
        avl_add(&vq->vq_active_tree, zio);
 
-       if (ssh->kstat != NULL) {
-               mutex_enter(&ssh->lock);
-               kstat_runq_enter(ssh->kstat->ks_data);
-               mutex_exit(&ssh->lock);
+       if (shk->kstat != NULL) {
+               mutex_enter(&shk->lock);
+               kstat_runq_enter(shk->kstat->ks_data);
+               mutex_exit(&shk->lock);
        }
 }
 
@@ -467,17 +487,17 @@ static void
 vdev_queue_pending_remove(vdev_queue_t *vq, zio_t *zio)
 {
        spa_t *spa = zio->io_spa;
-       spa_stats_history_t *ssh = &spa->spa_stats.io_history;
+       spa_history_kstat_t *shk = &spa->spa_stats.io_history;
 
        ASSERT(MUTEX_HELD(&vq->vq_lock));
        ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE);
        vq->vq_class[zio->io_priority].vqc_active--;
        avl_remove(&vq->vq_active_tree, zio);
 
-       if (ssh->kstat != NULL) {
-               kstat_io_t *ksio = ssh->kstat->ks_data;
+       if (shk->kstat != NULL) {
+               kstat_io_t *ksio = shk->kstat->ks_data;
 
-               mutex_enter(&ssh->lock);
+               mutex_enter(&shk->lock);
                kstat_runq_exit(ksio);
                if (zio->io_type == ZIO_TYPE_READ) {
                        ksio->reads++;
@@ -486,7 +506,7 @@ vdev_queue_pending_remove(vdev_queue_t *vq, zio_t *zio)
                        ksio->writes++;
                        ksio->nwritten += zio->io_size;
                }
-               mutex_exit(&ssh->lock);
+               mutex_exit(&shk->lock);
        }
 }
 
@@ -518,16 +538,18 @@ static zio_t *
 vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
 {
        zio_t *first, *last, *aio, *dio, *mandatory, *nio;
+       zio_link_t *zl = NULL;
        uint64_t maxgap = 0;
        uint64_t size;
        uint64_t limit;
+       int maxblocksize;
        boolean_t stretch = B_FALSE;
        avl_tree_t *t = vdev_queue_type_tree(vq, zio->io_type);
        enum zio_flag flags = zio->io_flags & ZIO_FLAG_AGG_INHERIT;
        abd_t *abd;
 
-       limit = MAX(MIN(zfs_vdev_aggregation_limit,
-           spa_maxblocksize(vq->vq_vdev->vdev_spa)), 0);
+       maxblocksize = spa_maxblocksize(vq->vq_vdev->vdev_spa);
+       limit = MAX(MIN(zfs_vdev_aggregation_limit, maxblocksize), 0);
 
        if (zio->io_flags & ZIO_FLAG_DONT_AGGREGATE || limit == 0)
                return (NULL);
@@ -559,7 +581,8 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
        while ((dio = AVL_PREV(t, first)) != NULL &&
            (dio->io_flags & ZIO_FLAG_AGG_INHERIT) == flags &&
            IO_SPAN(dio, last) <= limit &&
-           IO_GAP(dio, first) <= maxgap) {
+           IO_GAP(dio, first) <= maxgap &&
+           dio->io_type == zio->io_type) {
                first = dio;
                if (mandatory == NULL && !(first->io_flags & ZIO_FLAG_OPTIONAL))
                        mandatory = first;
@@ -584,7 +607,9 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
            (dio->io_flags & ZIO_FLAG_AGG_INHERIT) == flags &&
            (IO_SPAN(first, dio) <= limit ||
            (dio->io_flags & ZIO_FLAG_OPTIONAL)) &&
-           IO_GAP(last, dio) <= maxgap) {
+           IO_SPAN(first, dio) <= maxblocksize &&
+           IO_GAP(last, dio) <= maxgap &&
+           dio->io_type == zio->io_type) {
                last = dio;
                if (!(last->io_flags & ZIO_FLAG_OPTIONAL))
                        mandatory = last;
@@ -635,6 +660,7 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
                return (NULL);
 
        size = IO_SPAN(first, last);
+       ASSERT3U(size, <=, maxblocksize);
 
        abd = abd_alloc_for_io(size, B_TRUE);
        if (abd == NULL)
@@ -663,9 +689,18 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
 
                zio_add_child(dio, aio);
                vdev_queue_io_remove(vq, dio);
+       } while (dio != last);
+
+       /*
+        * We need to drop the vdev queue's lock to avoid a deadlock that we
+        * could encounter since this I/O will complete immediately.
+        */
+       mutex_exit(&vq->vq_lock);
+       while ((dio = zio_walk_parents(aio, &zl)) != NULL) {
                zio_vdev_io_bypass(dio);
                zio_execute(dio);
-       } while (dio != last);
+       }
+       mutex_enter(&vq->vq_lock);
 
        return (aio);
 }
@@ -689,16 +724,15 @@ again:
        }
 
        /*
-        * For LBA-ordered queues (async / scrub), issue the i/o which follows
-        * the most recently issued i/o in LBA (offset) order.
+        * For LBA-ordered queues (async / scrub / initializing), issue the
+        * i/o which follows the most recently issued i/o in LBA (offset) order.
         *
         * For FIFO queues (sync), issue the i/o with the lowest timestamp.
         */
        tree = vdev_queue_class_tree(vq, p);
        vq->vq_io_search.io_timestamp = 0;
-       vq->vq_io_search.io_offset = vq->vq_last_offset + 1;
-       VERIFY3P(avl_find(tree, &vq->vq_io_search,
-           &idx), ==, NULL);
+       vq->vq_io_search.io_offset = vq->vq_last_offset - 1;
+       VERIFY3P(avl_find(tree, &vq->vq_io_search, &idx), ==, NULL);
        zio = avl_nearest(tree, idx, AVL_AFTER);
        if (zio == NULL)
                zio = avl_first(tree);
@@ -725,7 +759,7 @@ again:
        }
 
        vdev_queue_pending_add(vq, zio);
-       vq->vq_last_offset = zio->io_offset;
+       vq->vq_last_offset = zio->io_offset + zio->io_size;
 
        return (zio);
 }
@@ -746,12 +780,16 @@ vdev_queue_io(zio_t *zio)
        if (zio->io_type == ZIO_TYPE_READ) {
                if (zio->io_priority != ZIO_PRIORITY_SYNC_READ &&
                    zio->io_priority != ZIO_PRIORITY_ASYNC_READ &&
-                   zio->io_priority != ZIO_PRIORITY_SCRUB)
+                   zio->io_priority != ZIO_PRIORITY_SCRUB &&
+                   zio->io_priority != ZIO_PRIORITY_REMOVAL &&
+                   zio->io_priority != ZIO_PRIORITY_INITIALIZING)
                        zio->io_priority = ZIO_PRIORITY_ASYNC_READ;
        } else {
                ASSERT(zio->io_type == ZIO_TYPE_WRITE);
                if (zio->io_priority != ZIO_PRIORITY_SYNC_WRITE &&
-                   zio->io_priority != ZIO_PRIORITY_ASYNC_WRITE)
+                   zio->io_priority != ZIO_PRIORITY_ASYNC_WRITE &&
+                   zio->io_priority != ZIO_PRIORITY_REMOVAL &&
+                   zio->io_priority != ZIO_PRIORITY_INITIALIZING)
                        zio->io_priority = ZIO_PRIORITY_ASYNC_WRITE;
        }
 
@@ -802,8 +840,59 @@ vdev_queue_io_done(zio_t *zio)
        mutex_exit(&vq->vq_lock);
 }
 
+void
+vdev_queue_change_io_priority(zio_t *zio, zio_priority_t priority)
+{
+       vdev_queue_t *vq = &zio->io_vd->vdev_queue;
+       avl_tree_t *tree;
+
+       /*
+        * ZIO_PRIORITY_NOW is used by the vdev cache code and the aggregate zio
+        * code to issue IOs without adding them to the vdev queue. In this
+        * case, the zio is already going to be issued as quickly as possible
+        * and so it doesn't need any reprioitization to help.
+        */
+       if (zio->io_priority == ZIO_PRIORITY_NOW)
+               return;
+
+       ASSERT3U(zio->io_priority, <, ZIO_PRIORITY_NUM_QUEUEABLE);
+       ASSERT3U(priority, <, ZIO_PRIORITY_NUM_QUEUEABLE);
+
+       if (zio->io_type == ZIO_TYPE_READ) {
+               if (priority != ZIO_PRIORITY_SYNC_READ &&
+                   priority != ZIO_PRIORITY_ASYNC_READ &&
+                   priority != ZIO_PRIORITY_SCRUB)
+                       priority = ZIO_PRIORITY_ASYNC_READ;
+       } else {
+               ASSERT(zio->io_type == ZIO_TYPE_WRITE);
+               if (priority != ZIO_PRIORITY_SYNC_WRITE &&
+                   priority != ZIO_PRIORITY_ASYNC_WRITE)
+                       priority = ZIO_PRIORITY_ASYNC_WRITE;
+       }
+
+       mutex_enter(&vq->vq_lock);
+
+       /*
+        * If the zio is in none of the queues we can simply change
+        * the priority. If the zio is waiting to be submitted we must
+        * remove it from the queue and re-insert it with the new priority.
+        * Otherwise, the zio is currently active and we cannot change its
+        * priority.
+        */
+       tree = vdev_queue_class_tree(vq, zio->io_priority);
+       if (avl_find(tree, zio, NULL) == zio) {
+               avl_remove(vdev_queue_class_tree(vq, zio->io_priority), zio);
+               zio->io_priority = priority;
+               avl_add(vdev_queue_class_tree(vq, zio->io_priority), zio);
+       } else if (avl_find(&vq->vq_active_tree, zio, NULL) != zio) {
+               zio->io_priority = priority;
+       }
+
+       mutex_exit(&vq->vq_lock);
+}
+
 /*
- * As these three methods are only used for load calculations we're not
+ * As these two methods are only used for load calculations we're not
  * concerned if we get an incorrect value on 32bit platforms due to lack of
  * vq_lock mutex use here, instead we prefer to keep it lock free for
  * performance.
@@ -815,18 +904,12 @@ vdev_queue_length(vdev_t *vd)
 }
 
 uint64_t
-vdev_queue_lastoffset(vdev_t *vd)
+vdev_queue_last_offset(vdev_t *vd)
 {
-       return (vd->vdev_queue.vq_lastoffset);
+       return (vd->vdev_queue.vq_last_offset);
 }
 
-void
-vdev_queue_register_lastoffset(vdev_t *vd, zio_t *zio)
-{
-       vd->vdev_queue.vq_lastoffset = zio->io_offset + zio->io_size;
-}
-
-#if defined(_KERNEL) && defined(HAVE_SPL)
+#if defined(_KERNEL)
 module_param(zfs_vdev_aggregation_limit, int, 0644);
 MODULE_PARM_DESC(zfs_vdev_aggregation_limit, "Max vdev I/O aggregation size");
 
@@ -863,11 +946,29 @@ module_param(zfs_vdev_async_write_min_active, int, 0644);
 MODULE_PARM_DESC(zfs_vdev_async_write_min_active,
        "Min active async write I/Os per vdev");
 
+module_param(zfs_vdev_initializing_max_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_initializing_max_active,
+       "Max active initializing I/Os per vdev");
+
+module_param(zfs_vdev_initializing_min_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_initializing_min_active,
+       "Min active initializing I/Os per vdev");
+
+module_param(zfs_vdev_removal_max_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_removal_max_active,
+       "Max active removal I/Os per vdev");
+
+module_param(zfs_vdev_removal_min_active, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_removal_min_active,
+       "Min active removal I/Os per vdev");
+
 module_param(zfs_vdev_scrub_max_active, int, 0644);
-MODULE_PARM_DESC(zfs_vdev_scrub_max_active, "Max active scrub I/Os per vdev");
+MODULE_PARM_DESC(zfs_vdev_scrub_max_active,
+       "Max active scrub I/Os per vdev");
 
 module_param(zfs_vdev_scrub_min_active, int, 0644);
-MODULE_PARM_DESC(zfs_vdev_scrub_min_active, "Min active scrub I/Os per vdev");
+MODULE_PARM_DESC(zfs_vdev_scrub_min_active,
+       "Min active scrub I/Os per vdev");
 
 module_param(zfs_vdev_sync_read_max_active, int, 0644);
 MODULE_PARM_DESC(zfs_vdev_sync_read_max_active,