2008-11-20 23:01:55 +03:00
|
|
|
/*
|
|
|
|
* CDDL HEADER START
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the terms of the
|
|
|
|
* Common Development and Distribution License (the "License").
|
|
|
|
* You may not use this file except in compliance with the License.
|
|
|
|
*
|
|
|
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
|
|
* or http://www.opensolaris.org/os/licensing.
|
|
|
|
* See the License for the specific language governing permissions
|
|
|
|
* and limitations under the License.
|
|
|
|
*
|
|
|
|
* When distributing Covered Code, include this CDDL HEADER in each
|
|
|
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
|
|
* If applicable, add the following below this CDDL HEADER, with the
|
|
|
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
|
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
|
|
*
|
|
|
|
* CDDL HEADER END
|
|
|
|
*/
|
|
|
|
/*
|
2010-05-29 00:45:14 +04:00
|
|
|
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
2015-05-20 07:14:01 +03:00
|
|
|
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
|
2008-11-20 23:01:55 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _SYS_VDEV_IMPL_H
|
|
|
|
#define _SYS_VDEV_IMPL_H
|
|
|
|
|
|
|
|
#include <sys/avl.h>
|
|
|
|
#include <sys/dmu.h>
|
|
|
|
#include <sys/metaslab.h>
|
|
|
|
#include <sys/nvpair.h>
|
|
|
|
#include <sys/space_map.h>
|
|
|
|
#include <sys/vdev.h>
|
|
|
|
#include <sys/dkio.h>
|
|
|
|
#include <sys/uberblock_impl.h>
|
2016-10-19 22:55:59 +03:00
|
|
|
#include <sys/zfs_ratelimit.h>
|
2008-11-20 23:01:55 +03:00
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Virtual device descriptors.
|
|
|
|
*
|
|
|
|
* All storage pool operations go through the virtual device framework,
|
|
|
|
* which provides data replication and I/O scheduling.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Forward declarations that lots of things need.
|
|
|
|
*/
|
|
|
|
typedef struct vdev_queue vdev_queue_t;
|
|
|
|
typedef struct vdev_cache vdev_cache_t;
|
|
|
|
typedef struct vdev_cache_entry vdev_cache_entry_t;
|
|
|
|
|
2016-10-14 03:59:18 +03:00
|
|
|
extern int zfs_vdev_queue_depth_pct;
|
|
|
|
extern uint32_t zfs_vdev_async_write_max_active;
|
|
|
|
|
2008-11-20 23:01:55 +03:00
|
|
|
/*
|
|
|
|
* Virtual device operations
|
|
|
|
*/
|
2012-01-24 06:43:32 +04:00
|
|
|
typedef int vdev_open_func_t(vdev_t *vd, uint64_t *size, uint64_t *max_size,
|
|
|
|
uint64_t *ashift);
|
2008-11-20 23:01:55 +03:00
|
|
|
typedef void vdev_close_func_t(vdev_t *vd);
|
|
|
|
typedef uint64_t vdev_asize_func_t(vdev_t *vd, uint64_t psize);
|
2014-10-21 02:07:45 +04:00
|
|
|
typedef void vdev_io_start_func_t(zio_t *zio);
|
2008-12-03 23:09:06 +03:00
|
|
|
typedef void vdev_io_done_func_t(zio_t *zio);
|
2008-11-20 23:01:55 +03:00
|
|
|
typedef void vdev_state_change_func_t(vdev_t *vd, int, int);
|
2010-05-29 00:45:14 +04:00
|
|
|
typedef void vdev_hold_func_t(vdev_t *vd);
|
|
|
|
typedef void vdev_rele_func_t(vdev_t *vd);
|
2008-11-20 23:01:55 +03:00
|
|
|
|
2013-02-15 08:37:43 +04:00
|
|
|
typedef const struct vdev_ops {
|
2008-11-20 23:01:55 +03:00
|
|
|
vdev_open_func_t *vdev_op_open;
|
|
|
|
vdev_close_func_t *vdev_op_close;
|
|
|
|
vdev_asize_func_t *vdev_op_asize;
|
|
|
|
vdev_io_start_func_t *vdev_op_io_start;
|
|
|
|
vdev_io_done_func_t *vdev_op_io_done;
|
|
|
|
vdev_state_change_func_t *vdev_op_state_change;
|
2010-05-29 00:45:14 +04:00
|
|
|
vdev_hold_func_t *vdev_op_hold;
|
|
|
|
vdev_rele_func_t *vdev_op_rele;
|
2008-11-20 23:01:55 +03:00
|
|
|
char vdev_op_type[16];
|
|
|
|
boolean_t vdev_op_leaf;
|
|
|
|
} vdev_ops_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Virtual device properties
|
|
|
|
*/
|
|
|
|
struct vdev_cache_entry {
|
|
|
|
char *ve_data;
|
|
|
|
uint64_t ve_offset;
|
2014-02-25 13:32:21 +04:00
|
|
|
clock_t ve_lastused;
|
2008-11-20 23:01:55 +03:00
|
|
|
avl_node_t ve_offset_node;
|
|
|
|
avl_node_t ve_lastused_node;
|
|
|
|
uint32_t ve_hits;
|
|
|
|
uint16_t ve_missed_update;
|
|
|
|
zio_t *ve_fill_io;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct vdev_cache {
|
|
|
|
avl_tree_t vc_offset_tree;
|
|
|
|
avl_tree_t vc_lastused_tree;
|
|
|
|
kmutex_t vc_lock;
|
|
|
|
};
|
|
|
|
|
Illumos #4045 write throttle & i/o scheduler performance work
4045 zfs write throttle & i/o scheduler performance work
1. The ZFS i/o scheduler (vdev_queue.c) now divides i/os into 5 classes: sync
read, sync write, async read, async write, and scrub/resilver. The scheduler
issues a number of concurrent i/os from each class to the device. Once a class
has been selected, an i/o is selected from this class using either an elevator
algorithem (async, scrub classes) or FIFO (sync classes). The number of
concurrent async write i/os is tuned dynamically based on i/o load, to achieve
good sync i/o latency when there is not a high load of writes, and good write
throughput when there is. See the block comment in vdev_queue.c (reproduced
below) for more details.
2. The write throttle (dsl_pool_tempreserve_space() and
txg_constrain_throughput()) is rewritten to produce much more consistent delays
when under constant load. The new write throttle is based on the amount of
dirty data, rather than guesses about future performance of the system. When
there is a lot of dirty data, each transaction (e.g. write() syscall) will be
delayed by the same small amount. This eliminates the "brick wall of wait"
that the old write throttle could hit, causing all transactions to wait several
seconds until the next txg opens. One of the keys to the new write throttle is
decrementing the amount of dirty data as i/o completes, rather than at the end
of spa_sync(). Note that the write throttle is only applied once the i/o
scheduler is issuing the maximum number of outstanding async writes. See the
block comments in dsl_pool.c and above dmu_tx_delay() (reproduced below) for
more details.
This diff has several other effects, including:
* the commonly-tuned global variable zfs_vdev_max_pending has been removed;
use per-class zfs_vdev_*_max_active values or zfs_vdev_max_active instead.
* the size of each txg (meaning the amount of dirty data written, and thus the
time it takes to write out) is now controlled differently. There is no longer
an explicit time goal; the primary determinant is amount of dirty data.
Systems that are under light or medium load will now often see that a txg is
always syncing, but the impact to performance (e.g. read latency) is minimal.
Tune zfs_dirty_data_max and zfs_dirty_data_sync to control this.
* zio_taskq_batch_pct = 75 -- Only use 75% of all CPUs for compression,
checksum, etc. This improves latency by not allowing these CPU-intensive tasks
to consume all CPU (on machines with at least 4 CPU's; the percentage is
rounded up).
--matt
APPENDIX: problems with the current i/o scheduler
The current ZFS i/o scheduler (vdev_queue.c) is deadline based. The problem
with this is that if there are always i/os pending, then certain classes of
i/os can see very long delays.
For example, if there are always synchronous reads outstanding, then no async
writes will be serviced until they become "past due". One symptom of this
situation is that each pass of the txg sync takes at least several seconds
(typically 3 seconds).
If many i/os become "past due" (their deadline is in the past), then we must
service all of these overdue i/os before any new i/os. This happens when we
enqueue a batch of async writes for the txg sync, with deadlines 2.5 seconds in
the future. If we can't complete all the i/os in 2.5 seconds (e.g. because
there were always reads pending), then these i/os will become past due. Now we
must service all the "async" writes (which could be hundreds of megabytes)
before we service any reads, introducing considerable latency to synchronous
i/os (reads or ZIL writes).
Notes on porting to ZFS on Linux:
- zio_t gained new members io_physdone and io_phys_children. Because
object caches in the Linux port call the constructor only once at
allocation time, objects may contain residual data when retrieved
from the cache. Therefore zio_create() was updated to zero out the two
new fields.
- vdev_mirror_pending() relied on the depth of the per-vdev pending queue
(vq->vq_pending_tree) to select the least-busy leaf vdev to read from.
This tree has been replaced by vq->vq_active_tree which is now used
for the same purpose.
- vdev_queue_init() used the value of zfs_vdev_max_pending to determine
the number of vdev I/O buffers to pre-allocate. That global no longer
exists, so we instead use the sum of the *_max_active values for each of
the five I/O classes described above.
- The Illumos implementation of dmu_tx_delay() delays a transaction by
sleeping in condition variable embedded in the thread
(curthread->t_delay_cv). We do not have an equivalent CV to use in
Linux, so this change replaced the delay logic with a wrapper called
zfs_sleep_until(). This wrapper could be adopted upstream and in other
downstream ports to abstract away operating system-specific delay logic.
- These tunables are added as module parameters, and descriptions added
to the zfs-module-parameters.5 man page.
spa_asize_inflation
zfs_deadman_synctime_ms
zfs_vdev_max_active
zfs_vdev_async_write_active_min_dirty_percent
zfs_vdev_async_write_active_max_dirty_percent
zfs_vdev_async_read_max_active
zfs_vdev_async_read_min_active
zfs_vdev_async_write_max_active
zfs_vdev_async_write_min_active
zfs_vdev_scrub_max_active
zfs_vdev_scrub_min_active
zfs_vdev_sync_read_max_active
zfs_vdev_sync_read_min_active
zfs_vdev_sync_write_max_active
zfs_vdev_sync_write_min_active
zfs_dirty_data_max_percent
zfs_delay_min_dirty_percent
zfs_dirty_data_max_max_percent
zfs_dirty_data_max
zfs_dirty_data_max_max
zfs_dirty_data_sync
zfs_delay_scale
The latter four have type unsigned long, whereas they are uint64_t in
Illumos. This accommodates Linux's module_param() supported types, but
means they may overflow on 32-bit architectures.
The values zfs_dirty_data_max and zfs_dirty_data_max_max are the most
likely to overflow on 32-bit systems, since they express physical RAM
sizes in bytes. In fact, Illumos initializes zfs_dirty_data_max_max to
2^32 which does overflow. To resolve that, this port instead initializes
it in arc_init() to 25% of physical RAM, and adds the tunable
zfs_dirty_data_max_max_percent to override that percentage. While this
solution doesn't completely avoid the overflow issue, it should be a
reasonable default for most systems, and the minority of affected
systems can work around the issue by overriding the defaults.
- Fixed reversed logic in comment above zfs_delay_scale declaration.
- Clarified comments in vdev_queue.c regarding when per-queue minimums take
effect.
- Replaced dmu_tx_write_limit in the dmu_tx kstat file
with dmu_tx_dirty_delay and dmu_tx_dirty_over_max. The first counts
how many times a transaction has been delayed because the pool dirty
data has exceeded zfs_delay_min_dirty_percent. The latter counts how
many times the pool dirty data has exceeded zfs_dirty_data_max (which
we expect to never happen).
- The original patch would have regressed the bug fixed in
zfsonlinux/zfs@c418410, which prevented users from setting the
zfs_vdev_aggregation_limit tuning larger than SPA_MAXBLOCKSIZE.
A similar fix is added to vdev_queue_aggregate().
- In vdev_queue_io_to_issue(), dynamically allocate 'zio_t search' on the
heap instead of the stack. In Linux we can't afford such large
structures on the stack.
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: Ned Bass <bass6@llnl.gov>
Reviewed by: Brendan Gregg <brendan.gregg@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
References:
http://www.illumos.org/issues/4045
illumos/illumos-gate@69962b5647e4a8b9b14998733b765925381b727e
Ported-by: Ned Bass <bass6@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #1913
2013-08-29 07:01:20 +04:00
|
|
|
typedef struct vdev_queue_class {
|
|
|
|
uint32_t vqc_active;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sorted by offset or timestamp, depending on if the queue is
|
|
|
|
* LBA-ordered vs FIFO.
|
|
|
|
*/
|
|
|
|
avl_tree_t vqc_queued_tree;
|
|
|
|
} vdev_queue_class_t;
|
|
|
|
|
2008-11-20 23:01:55 +03:00
|
|
|
struct vdev_queue {
|
Illumos #4045 write throttle & i/o scheduler performance work
4045 zfs write throttle & i/o scheduler performance work
1. The ZFS i/o scheduler (vdev_queue.c) now divides i/os into 5 classes: sync
read, sync write, async read, async write, and scrub/resilver. The scheduler
issues a number of concurrent i/os from each class to the device. Once a class
has been selected, an i/o is selected from this class using either an elevator
algorithem (async, scrub classes) or FIFO (sync classes). The number of
concurrent async write i/os is tuned dynamically based on i/o load, to achieve
good sync i/o latency when there is not a high load of writes, and good write
throughput when there is. See the block comment in vdev_queue.c (reproduced
below) for more details.
2. The write throttle (dsl_pool_tempreserve_space() and
txg_constrain_throughput()) is rewritten to produce much more consistent delays
when under constant load. The new write throttle is based on the amount of
dirty data, rather than guesses about future performance of the system. When
there is a lot of dirty data, each transaction (e.g. write() syscall) will be
delayed by the same small amount. This eliminates the "brick wall of wait"
that the old write throttle could hit, causing all transactions to wait several
seconds until the next txg opens. One of the keys to the new write throttle is
decrementing the amount of dirty data as i/o completes, rather than at the end
of spa_sync(). Note that the write throttle is only applied once the i/o
scheduler is issuing the maximum number of outstanding async writes. See the
block comments in dsl_pool.c and above dmu_tx_delay() (reproduced below) for
more details.
This diff has several other effects, including:
* the commonly-tuned global variable zfs_vdev_max_pending has been removed;
use per-class zfs_vdev_*_max_active values or zfs_vdev_max_active instead.
* the size of each txg (meaning the amount of dirty data written, and thus the
time it takes to write out) is now controlled differently. There is no longer
an explicit time goal; the primary determinant is amount of dirty data.
Systems that are under light or medium load will now often see that a txg is
always syncing, but the impact to performance (e.g. read latency) is minimal.
Tune zfs_dirty_data_max and zfs_dirty_data_sync to control this.
* zio_taskq_batch_pct = 75 -- Only use 75% of all CPUs for compression,
checksum, etc. This improves latency by not allowing these CPU-intensive tasks
to consume all CPU (on machines with at least 4 CPU's; the percentage is
rounded up).
--matt
APPENDIX: problems with the current i/o scheduler
The current ZFS i/o scheduler (vdev_queue.c) is deadline based. The problem
with this is that if there are always i/os pending, then certain classes of
i/os can see very long delays.
For example, if there are always synchronous reads outstanding, then no async
writes will be serviced until they become "past due". One symptom of this
situation is that each pass of the txg sync takes at least several seconds
(typically 3 seconds).
If many i/os become "past due" (their deadline is in the past), then we must
service all of these overdue i/os before any new i/os. This happens when we
enqueue a batch of async writes for the txg sync, with deadlines 2.5 seconds in
the future. If we can't complete all the i/os in 2.5 seconds (e.g. because
there were always reads pending), then these i/os will become past due. Now we
must service all the "async" writes (which could be hundreds of megabytes)
before we service any reads, introducing considerable latency to synchronous
i/os (reads or ZIL writes).
Notes on porting to ZFS on Linux:
- zio_t gained new members io_physdone and io_phys_children. Because
object caches in the Linux port call the constructor only once at
allocation time, objects may contain residual data when retrieved
from the cache. Therefore zio_create() was updated to zero out the two
new fields.
- vdev_mirror_pending() relied on the depth of the per-vdev pending queue
(vq->vq_pending_tree) to select the least-busy leaf vdev to read from.
This tree has been replaced by vq->vq_active_tree which is now used
for the same purpose.
- vdev_queue_init() used the value of zfs_vdev_max_pending to determine
the number of vdev I/O buffers to pre-allocate. That global no longer
exists, so we instead use the sum of the *_max_active values for each of
the five I/O classes described above.
- The Illumos implementation of dmu_tx_delay() delays a transaction by
sleeping in condition variable embedded in the thread
(curthread->t_delay_cv). We do not have an equivalent CV to use in
Linux, so this change replaced the delay logic with a wrapper called
zfs_sleep_until(). This wrapper could be adopted upstream and in other
downstream ports to abstract away operating system-specific delay logic.
- These tunables are added as module parameters, and descriptions added
to the zfs-module-parameters.5 man page.
spa_asize_inflation
zfs_deadman_synctime_ms
zfs_vdev_max_active
zfs_vdev_async_write_active_min_dirty_percent
zfs_vdev_async_write_active_max_dirty_percent
zfs_vdev_async_read_max_active
zfs_vdev_async_read_min_active
zfs_vdev_async_write_max_active
zfs_vdev_async_write_min_active
zfs_vdev_scrub_max_active
zfs_vdev_scrub_min_active
zfs_vdev_sync_read_max_active
zfs_vdev_sync_read_min_active
zfs_vdev_sync_write_max_active
zfs_vdev_sync_write_min_active
zfs_dirty_data_max_percent
zfs_delay_min_dirty_percent
zfs_dirty_data_max_max_percent
zfs_dirty_data_max
zfs_dirty_data_max_max
zfs_dirty_data_sync
zfs_delay_scale
The latter four have type unsigned long, whereas they are uint64_t in
Illumos. This accommodates Linux's module_param() supported types, but
means they may overflow on 32-bit architectures.
The values zfs_dirty_data_max and zfs_dirty_data_max_max are the most
likely to overflow on 32-bit systems, since they express physical RAM
sizes in bytes. In fact, Illumos initializes zfs_dirty_data_max_max to
2^32 which does overflow. To resolve that, this port instead initializes
it in arc_init() to 25% of physical RAM, and adds the tunable
zfs_dirty_data_max_max_percent to override that percentage. While this
solution doesn't completely avoid the overflow issue, it should be a
reasonable default for most systems, and the minority of affected
systems can work around the issue by overriding the defaults.
- Fixed reversed logic in comment above zfs_delay_scale declaration.
- Clarified comments in vdev_queue.c regarding when per-queue minimums take
effect.
- Replaced dmu_tx_write_limit in the dmu_tx kstat file
with dmu_tx_dirty_delay and dmu_tx_dirty_over_max. The first counts
how many times a transaction has been delayed because the pool dirty
data has exceeded zfs_delay_min_dirty_percent. The latter counts how
many times the pool dirty data has exceeded zfs_dirty_data_max (which
we expect to never happen).
- The original patch would have regressed the bug fixed in
zfsonlinux/zfs@c418410, which prevented users from setting the
zfs_vdev_aggregation_limit tuning larger than SPA_MAXBLOCKSIZE.
A similar fix is added to vdev_queue_aggregate().
- In vdev_queue_io_to_issue(), dynamically allocate 'zio_t search' on the
heap instead of the stack. In Linux we can't afford such large
structures on the stack.
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: Ned Bass <bass6@llnl.gov>
Reviewed by: Brendan Gregg <brendan.gregg@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
References:
http://www.illumos.org/issues/4045
illumos/illumos-gate@69962b5647e4a8b9b14998733b765925381b727e
Ported-by: Ned Bass <bass6@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #1913
2013-08-29 07:01:20 +04:00
|
|
|
vdev_t *vq_vdev;
|
|
|
|
vdev_queue_class_t vq_class[ZIO_PRIORITY_NUM_QUEUEABLE];
|
|
|
|
avl_tree_t vq_active_tree;
|
2015-04-11 21:51:06 +03:00
|
|
|
avl_tree_t vq_read_offset_tree;
|
|
|
|
avl_tree_t vq_write_offset_tree;
|
Illumos #4045 write throttle & i/o scheduler performance work
4045 zfs write throttle & i/o scheduler performance work
1. The ZFS i/o scheduler (vdev_queue.c) now divides i/os into 5 classes: sync
read, sync write, async read, async write, and scrub/resilver. The scheduler
issues a number of concurrent i/os from each class to the device. Once a class
has been selected, an i/o is selected from this class using either an elevator
algorithem (async, scrub classes) or FIFO (sync classes). The number of
concurrent async write i/os is tuned dynamically based on i/o load, to achieve
good sync i/o latency when there is not a high load of writes, and good write
throughput when there is. See the block comment in vdev_queue.c (reproduced
below) for more details.
2. The write throttle (dsl_pool_tempreserve_space() and
txg_constrain_throughput()) is rewritten to produce much more consistent delays
when under constant load. The new write throttle is based on the amount of
dirty data, rather than guesses about future performance of the system. When
there is a lot of dirty data, each transaction (e.g. write() syscall) will be
delayed by the same small amount. This eliminates the "brick wall of wait"
that the old write throttle could hit, causing all transactions to wait several
seconds until the next txg opens. One of the keys to the new write throttle is
decrementing the amount of dirty data as i/o completes, rather than at the end
of spa_sync(). Note that the write throttle is only applied once the i/o
scheduler is issuing the maximum number of outstanding async writes. See the
block comments in dsl_pool.c and above dmu_tx_delay() (reproduced below) for
more details.
This diff has several other effects, including:
* the commonly-tuned global variable zfs_vdev_max_pending has been removed;
use per-class zfs_vdev_*_max_active values or zfs_vdev_max_active instead.
* the size of each txg (meaning the amount of dirty data written, and thus the
time it takes to write out) is now controlled differently. There is no longer
an explicit time goal; the primary determinant is amount of dirty data.
Systems that are under light or medium load will now often see that a txg is
always syncing, but the impact to performance (e.g. read latency) is minimal.
Tune zfs_dirty_data_max and zfs_dirty_data_sync to control this.
* zio_taskq_batch_pct = 75 -- Only use 75% of all CPUs for compression,
checksum, etc. This improves latency by not allowing these CPU-intensive tasks
to consume all CPU (on machines with at least 4 CPU's; the percentage is
rounded up).
--matt
APPENDIX: problems with the current i/o scheduler
The current ZFS i/o scheduler (vdev_queue.c) is deadline based. The problem
with this is that if there are always i/os pending, then certain classes of
i/os can see very long delays.
For example, if there are always synchronous reads outstanding, then no async
writes will be serviced until they become "past due". One symptom of this
situation is that each pass of the txg sync takes at least several seconds
(typically 3 seconds).
If many i/os become "past due" (their deadline is in the past), then we must
service all of these overdue i/os before any new i/os. This happens when we
enqueue a batch of async writes for the txg sync, with deadlines 2.5 seconds in
the future. If we can't complete all the i/os in 2.5 seconds (e.g. because
there were always reads pending), then these i/os will become past due. Now we
must service all the "async" writes (which could be hundreds of megabytes)
before we service any reads, introducing considerable latency to synchronous
i/os (reads or ZIL writes).
Notes on porting to ZFS on Linux:
- zio_t gained new members io_physdone and io_phys_children. Because
object caches in the Linux port call the constructor only once at
allocation time, objects may contain residual data when retrieved
from the cache. Therefore zio_create() was updated to zero out the two
new fields.
- vdev_mirror_pending() relied on the depth of the per-vdev pending queue
(vq->vq_pending_tree) to select the least-busy leaf vdev to read from.
This tree has been replaced by vq->vq_active_tree which is now used
for the same purpose.
- vdev_queue_init() used the value of zfs_vdev_max_pending to determine
the number of vdev I/O buffers to pre-allocate. That global no longer
exists, so we instead use the sum of the *_max_active values for each of
the five I/O classes described above.
- The Illumos implementation of dmu_tx_delay() delays a transaction by
sleeping in condition variable embedded in the thread
(curthread->t_delay_cv). We do not have an equivalent CV to use in
Linux, so this change replaced the delay logic with a wrapper called
zfs_sleep_until(). This wrapper could be adopted upstream and in other
downstream ports to abstract away operating system-specific delay logic.
- These tunables are added as module parameters, and descriptions added
to the zfs-module-parameters.5 man page.
spa_asize_inflation
zfs_deadman_synctime_ms
zfs_vdev_max_active
zfs_vdev_async_write_active_min_dirty_percent
zfs_vdev_async_write_active_max_dirty_percent
zfs_vdev_async_read_max_active
zfs_vdev_async_read_min_active
zfs_vdev_async_write_max_active
zfs_vdev_async_write_min_active
zfs_vdev_scrub_max_active
zfs_vdev_scrub_min_active
zfs_vdev_sync_read_max_active
zfs_vdev_sync_read_min_active
zfs_vdev_sync_write_max_active
zfs_vdev_sync_write_min_active
zfs_dirty_data_max_percent
zfs_delay_min_dirty_percent
zfs_dirty_data_max_max_percent
zfs_dirty_data_max
zfs_dirty_data_max_max
zfs_dirty_data_sync
zfs_delay_scale
The latter four have type unsigned long, whereas they are uint64_t in
Illumos. This accommodates Linux's module_param() supported types, but
means they may overflow on 32-bit architectures.
The values zfs_dirty_data_max and zfs_dirty_data_max_max are the most
likely to overflow on 32-bit systems, since they express physical RAM
sizes in bytes. In fact, Illumos initializes zfs_dirty_data_max_max to
2^32 which does overflow. To resolve that, this port instead initializes
it in arc_init() to 25% of physical RAM, and adds the tunable
zfs_dirty_data_max_max_percent to override that percentage. While this
solution doesn't completely avoid the overflow issue, it should be a
reasonable default for most systems, and the minority of affected
systems can work around the issue by overriding the defaults.
- Fixed reversed logic in comment above zfs_delay_scale declaration.
- Clarified comments in vdev_queue.c regarding when per-queue minimums take
effect.
- Replaced dmu_tx_write_limit in the dmu_tx kstat file
with dmu_tx_dirty_delay and dmu_tx_dirty_over_max. The first counts
how many times a transaction has been delayed because the pool dirty
data has exceeded zfs_delay_min_dirty_percent. The latter counts how
many times the pool dirty data has exceeded zfs_dirty_data_max (which
we expect to never happen).
- The original patch would have regressed the bug fixed in
zfsonlinux/zfs@c418410, which prevented users from setting the
zfs_vdev_aggregation_limit tuning larger than SPA_MAXBLOCKSIZE.
A similar fix is added to vdev_queue_aggregate().
- In vdev_queue_io_to_issue(), dynamically allocate 'zio_t search' on the
heap instead of the stack. In Linux we can't afford such large
structures on the stack.
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: Ned Bass <bass6@llnl.gov>
Reviewed by: Brendan Gregg <brendan.gregg@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
References:
http://www.illumos.org/issues/4045
illumos/illumos-gate@69962b5647e4a8b9b14998733b765925381b727e
Ported-by: Ned Bass <bass6@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #1913
2013-08-29 07:01:20 +04:00
|
|
|
uint64_t vq_last_offset;
|
|
|
|
hrtime_t vq_io_complete_ts; /* time last i/o completed */
|
2013-03-22 02:47:36 +04:00
|
|
|
hrtime_t vq_io_delta_ts;
|
2014-08-06 00:57:59 +04:00
|
|
|
zio_t vq_io_search; /* used as local for stack reduction */
|
2008-11-20 23:01:55 +03:00
|
|
|
kmutex_t vq_lock;
|
FreeBSD r256956: Improve ZFS N-way mirror read performance by using load and locality information.
The existing algorithm selects a preferred leaf vdev based on offset of the zio
request modulo the number of members in the mirror. It assumes the devices are
of equal performance and that spreading the requests randomly over both drives
will be sufficient to saturate them. In practice this results in the leaf vdevs
being under utilized.
The new algorithm takes into the following additional factors:
* Load of the vdevs (number outstanding I/O requests)
* The locality of last queued I/O vs the new I/O request.
Within the locality calculation additional knowledge about the underlying vdev
is considered such as; is the device backing the vdev a rotating media device.
This results in performance increases across the board as well as significant
increases for predominantly streaming loads and for configurations which don't
have evenly performing devices.
The following are results from a setup with 3 Way Mirror with 2 x HD's and
1 x SSD from a basic test running multiple parrallel dd's.
With pre-fetch disabled (vfs.zfs.prefetch_disable=1):
== Stripe Balanced (default) ==
Read 15360MB using bs: 1048576, readers: 3, took 161 seconds @ 95 MB/s
== Load Balanced (zfslinux) ==
Read 15360MB using bs: 1048576, readers: 3, took 297 seconds @ 51 MB/s
== Load Balanced (locality freebsd) ==
Read 15360MB using bs: 1048576, readers: 3, took 54 seconds @ 284 MB/s
With pre-fetch enabled (vfs.zfs.prefetch_disable=0):
== Stripe Balanced (default) ==
Read 15360MB using bs: 1048576, readers: 3, took 91 seconds @ 168 MB/s
== Load Balanced (zfslinux) ==
Read 15360MB using bs: 1048576, readers: 3, took 108 seconds @ 142 MB/s
== Load Balanced (locality freebsd) ==
Read 15360MB using bs: 1048576, readers: 3, took 48 seconds @ 320 MB/s
In addition to the performance changes the code was also restructured, with
the help of Justin Gibbs, to provide a more logical flow which also ensures
vdevs loads are only calculated from the set of valid candidates.
The following additional sysctls where added to allow the administrator
to tune the behaviour of the load algorithm:
* vfs.zfs.vdev.mirror.rotating_inc
* vfs.zfs.vdev.mirror.rotating_seek_inc
* vfs.zfs.vdev.mirror.rotating_seek_offset
* vfs.zfs.vdev.mirror.non_rotating_inc
* vfs.zfs.vdev.mirror.non_rotating_seek_inc
These changes where based on work started by the zfsonlinux developers:
https://github.com/zfsonlinux/zfs/pull/1487
Reviewed by: gibbs, mav, will
MFC after: 2 weeks
Sponsored by: Multiplay
References:
https://github.com/freebsd/freebsd@5c7a6f5d
https://github.com/freebsd/freebsd@31b7f68d
https://github.com/freebsd/freebsd@e186f564
Performance Testing:
https://github.com/zfsonlinux/zfs/pull/4334#issuecomment-189057141
Porting notes:
- The tunables were adjusted to have ZoL-style names.
- The code was modified to use ZoL's vd_nonrot.
- Fixes were done to make cstyle.pl happy
- Merge conflicts were handled manually
- freebsd/freebsd@e186f564bc946f82c76e0b34c2f0370ed9aea022 by my
collegue Andriy Gapon has been included. It applied perfectly, but
added a cstyle regression.
- This replaces 556011dbec2d10579819078559a77630fc559112 entirely.
- A typo "IO'a" has been corrected to say "IO's"
- Descriptions of new tunables were added to man/man5/zfs-module-parameters.5.
Ported-by: Richard Yao <ryao@gentoo.org>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #4334
2016-02-13 04:47:22 +03:00
|
|
|
uint64_t vq_lastoffset;
|
2008-11-20 23:01:55 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Virtual device descriptor
|
|
|
|
*/
|
|
|
|
struct vdev {
|
|
|
|
/*
|
|
|
|
* Common to all vdev types.
|
|
|
|
*/
|
|
|
|
uint64_t vdev_id; /* child number in vdev parent */
|
|
|
|
uint64_t vdev_guid; /* unique ID for this vdev */
|
|
|
|
uint64_t vdev_guid_sum; /* self guid + all child guids */
|
2010-05-29 00:45:14 +04:00
|
|
|
uint64_t vdev_orig_guid; /* orig. guid prior to remove */
|
2008-11-20 23:01:55 +03:00
|
|
|
uint64_t vdev_asize; /* allocatable device capacity */
|
2009-07-03 02:44:48 +04:00
|
|
|
uint64_t vdev_min_asize; /* min acceptable asize */
|
2012-01-24 06:43:32 +04:00
|
|
|
uint64_t vdev_max_asize; /* max acceptable asize */
|
2008-11-20 23:01:55 +03:00
|
|
|
uint64_t vdev_ashift; /* block alignment shift */
|
|
|
|
uint64_t vdev_state; /* see VDEV_STATE_* #defines */
|
|
|
|
uint64_t vdev_prevstate; /* used when reopening a vdev */
|
|
|
|
vdev_ops_t *vdev_ops; /* vdev operations */
|
|
|
|
spa_t *vdev_spa; /* spa for this vdev */
|
|
|
|
void *vdev_tsd; /* type-specific data */
|
2010-05-29 00:45:14 +04:00
|
|
|
vnode_t *vdev_name_vp; /* vnode for pathname */
|
|
|
|
vnode_t *vdev_devid_vp; /* vnode for devid */
|
2008-11-20 23:01:55 +03:00
|
|
|
vdev_t *vdev_top; /* top-level vdev */
|
|
|
|
vdev_t *vdev_parent; /* parent vdev */
|
|
|
|
vdev_t **vdev_child; /* array of children */
|
|
|
|
uint64_t vdev_children; /* number of children */
|
|
|
|
vdev_stat_t vdev_stat; /* virtual device statistics */
|
2016-02-29 21:05:23 +03:00
|
|
|
vdev_stat_ex_t vdev_stat_ex; /* extended statistics */
|
2009-07-03 02:44:48 +04:00
|
|
|
boolean_t vdev_expanding; /* expand the vdev? */
|
2010-05-29 00:45:14 +04:00
|
|
|
boolean_t vdev_reopening; /* reopen in progress? */
|
2015-08-29 19:01:07 +03:00
|
|
|
boolean_t vdev_nonrot; /* true if solid state */
|
2009-08-18 22:43:27 +04:00
|
|
|
int vdev_open_error; /* error on last open */
|
|
|
|
kthread_t *vdev_open_thread; /* thread opening children */
|
2010-05-29 00:45:14 +04:00
|
|
|
uint64_t vdev_crtxg; /* txg when top-level was added */
|
2008-11-20 23:01:55 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Top-level vdev state.
|
|
|
|
*/
|
|
|
|
uint64_t vdev_ms_array; /* metaslab array object */
|
|
|
|
uint64_t vdev_ms_shift; /* metaslab size shift */
|
|
|
|
uint64_t vdev_ms_count; /* number of metaslabs */
|
|
|
|
metaslab_group_t *vdev_mg; /* metaslab group */
|
|
|
|
metaslab_t **vdev_ms; /* metaslab array */
|
Add FASTWRITE algorithm for synchronous writes.
Currently, ZIL blocks are spread over vdevs using hint block pointers
managed by the ZIL commit code and passed to metaslab_alloc(). Spreading
log blocks accross vdevs is important for performance: indeed, using
mutliple disks in parallel decreases the ZIL commit latency, which is
the main performance metric for synchronous writes. However, the current
implementation suffers from the following issues:
1) It would be best if the ZIL module was not aware of such low-level
details. They should be handled by the ZIO and metaslab modules;
2) Because the hint block pointer is managed per log, simultaneous
commits from multiple logs might use the same vdevs at the same time,
which is inefficient;
3) Because dmu_write() does not honor the block pointer hint, indirect
writes are not spread.
The naive solution of rotating the metaslab rotor each time a block is
allocated for the ZIL or dmu_sync() doesn't work in practice because the
first ZIL block to be written is actually allocated during the previous
commit. Consequently, when metaslab_alloc() decides the vdev for this
block, it will do so while a bunch of other allocations are happening at
the same time (from dmu_sync() and other ZILs). This means the vdev for
this block is chosen more or less at random. When the next commit
happens, there is a high chance (especially when the number of blocks
per commit is slightly less than the number of the disks) that one disk
will have to write two blocks (with a potential seek) while other disks
are sitting idle, which defeats spreading and increases the commit
latency.
This commit introduces a new concept in the metaslab allocator:
fastwrites. Basically, each top-level vdev maintains a counter
indicating the number of synchronous writes (from dmu_sync() and the
ZIL) which have been allocated but not yet completed. When the metaslab
is called with the FASTWRITE flag, it will choose the vdev with the
least amount of pending synchronous writes. If there are multiple vdevs
with the same value, the first matching vdev (starting from the rotor)
is used. Once metaslab_alloc() has decided which vdev the block is
allocated to, it updates the fastwrite counter for this vdev.
The rationale goes like this: when an allocation is done with
FASTWRITE, it "reserves" the vdev until the data is written. Until then,
all future allocations will naturally avoid this vdev, even after a full
rotation of the rotor. As a result, pending synchronous writes at a
given point in time will be nicely spread over all vdevs. This contrasts
with the previous algorithm, which is based on the implicit assumption
that blocks are written instantaneously after they're allocated.
metaslab_fastwrite_mark() and metaslab_fastwrite_unmark() are used to
manually increase or decrease fastwrite counters, respectively. They
should be used with caution, as there is no per-BP tracking of fastwrite
information, so leaks and "double-unmarks" are possible. There is,
however, an assert in the vdev teardown code which will fire if the
fastwrite counters are not zero when the pool is exported or the vdev
removed. Note that as stated above, marking is also done implictly by
metaslab_alloc().
ZIO also got a new FASTWRITE flag; when it is used, ZIO will pass it to
the metaslab when allocating (assuming ZIO does the allocation, which is
only true in the case of dmu_sync). This flag will also trigger an
unmark when zio_done() fires.
A side-effect of the new algorithm is that when a ZIL stops being used,
its last block can stay in the pending state (allocated but not yet
written) for a long time, polluting the fastwrite counters. To avoid
that, I've implemented a somewhat crude but working solution which
unmarks these pending blocks in zil_sync(), thus guaranteeing that
linguering fastwrites will get pruned at each sync event.
The best performance improvements are observed with pools using a large
number of top-level vdevs and heavy synchronous write workflows
(especially indirect writes and concurrent writes from multiple ZILs).
Real-life testing shows a 200% to 300% performance increase with
indirect writes and various commit sizes.
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue #1013
2012-06-27 17:20:20 +04:00
|
|
|
uint64_t vdev_pending_fastwrite; /* allocated fastwrites */
|
2008-11-20 23:01:55 +03:00
|
|
|
txg_list_t vdev_ms_list; /* per-txg dirty metaslab lists */
|
|
|
|
txg_list_t vdev_dtl_list; /* per-txg dirty DTL lists */
|
|
|
|
txg_node_t vdev_txg_node; /* per-txg dirty vdev linkage */
|
|
|
|
boolean_t vdev_remove_wanted; /* async remove wanted? */
|
2008-12-03 23:09:06 +03:00
|
|
|
boolean_t vdev_probe_wanted; /* async probe wanted? */
|
|
|
|
list_node_t vdev_config_dirty_node; /* config dirty list */
|
|
|
|
list_node_t vdev_state_dirty_node; /* state dirty list */
|
2008-11-20 23:01:55 +03:00
|
|
|
uint64_t vdev_deflate_ratio; /* deflation ratio (x512) */
|
|
|
|
uint64_t vdev_islog; /* is an intent log device */
|
Illumos #4101, #4102, #4103, #4105, #4106
4101 metaslab_debug should allow for fine-grained control
4102 space_maps should store more information about themselves
4103 space map object blocksize should be increased
4105 removing a mirrored log device results in a leaked object
4106 asynchronously load metaslab
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Sebastien Roy <seb@delphix.com>
Approved by: Garrett D'Amore <garrett@damore.org>
Prior to this patch, space_maps were preferred solely based on the
amount of free space left in each. Unfortunately, this heuristic didn't
contain any information about the make-up of that free space, which
meant we could keep preferring and loading a highly fragmented space map
that wouldn't actually have enough contiguous space to satisfy the
allocation; then unloading that space_map and repeating the process.
This change modifies the space_map's to store additional information
about the contiguous space in the space_map, so that we can use this
information to make a better decision about which space_map to load.
This requires reallocating all space_map objects to increase their
bonus buffer size sizes enough to fit the new metadata.
The above feature can be enabled via a new feature flag introduced by
this change: com.delphix:spacemap_histogram
In addition to the above, this patch allows the space_map block size to
be increase. Currently the block size is set to be 4K in size, which has
certain implications including the following:
* 4K sector devices will not see any compression benefit
* large space_maps require more metadata on-disk
* large space_maps require more time to load (typically random reads)
Now the space_map block size can adjust as needed up to the maximum size
set via the space_map_max_blksz variable.
A bug was fixed which resulted in potentially leaking an object when
removing a mirrored log device. The previous logic for vdev_remove() did
not deal with removing top-level vdevs that are interior vdevs (i.e.
mirror) correctly. The problem would occur when removing a mirrored log
device, and result in the DTL space map object being leaked; because
top-level vdevs don't have DTL space map objects associated with them.
References:
https://www.illumos.org/issues/4101
https://www.illumos.org/issues/4102
https://www.illumos.org/issues/4103
https://www.illumos.org/issues/4105
https://www.illumos.org/issues/4106
https://github.com/illumos/illumos-gate/commit/0713e23
Porting notes:
A handful of kmem_alloc() calls were converted to kmem_zalloc(). Also,
the KM_PUSHPAGE and TQ_PUSHPAGE flags were used as necessary.
Ported-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Prakash Surya <surya1@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2488
2013-10-02 01:25:53 +04:00
|
|
|
uint64_t vdev_removing; /* device is being removed? */
|
2016-10-14 03:59:18 +03:00
|
|
|
boolean_t vdev_ishole; /* is a hole in the namespace */
|
|
|
|
kmutex_t vdev_queue_lock; /* protects vdev_queue_depth */
|
2016-04-11 23:16:57 +03:00
|
|
|
uint64_t vdev_top_zap;
|
2008-11-20 23:01:55 +03:00
|
|
|
|
2016-10-14 03:59:18 +03:00
|
|
|
/*
|
|
|
|
* The queue depth parameters determine how many async writes are
|
|
|
|
* still pending (i.e. allocated by net yet issued to disk) per
|
|
|
|
* top-level (vdev_async_write_queue_depth) and the maximum allowed
|
|
|
|
* (vdev_max_async_write_queue_depth). These values only apply to
|
|
|
|
* top-level vdevs.
|
|
|
|
*/
|
|
|
|
uint64_t vdev_async_write_queue_depth;
|
|
|
|
uint64_t vdev_max_async_write_queue_depth;
|
|
|
|
|
2008-11-20 23:01:55 +03:00
|
|
|
/*
|
|
|
|
* Leaf vdev state.
|
|
|
|
*/
|
Illumos #4101, #4102, #4103, #4105, #4106
4101 metaslab_debug should allow for fine-grained control
4102 space_maps should store more information about themselves
4103 space map object blocksize should be increased
4105 removing a mirrored log device results in a leaked object
4106 asynchronously load metaslab
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Sebastien Roy <seb@delphix.com>
Approved by: Garrett D'Amore <garrett@damore.org>
Prior to this patch, space_maps were preferred solely based on the
amount of free space left in each. Unfortunately, this heuristic didn't
contain any information about the make-up of that free space, which
meant we could keep preferring and loading a highly fragmented space map
that wouldn't actually have enough contiguous space to satisfy the
allocation; then unloading that space_map and repeating the process.
This change modifies the space_map's to store additional information
about the contiguous space in the space_map, so that we can use this
information to make a better decision about which space_map to load.
This requires reallocating all space_map objects to increase their
bonus buffer size sizes enough to fit the new metadata.
The above feature can be enabled via a new feature flag introduced by
this change: com.delphix:spacemap_histogram
In addition to the above, this patch allows the space_map block size to
be increase. Currently the block size is set to be 4K in size, which has
certain implications including the following:
* 4K sector devices will not see any compression benefit
* large space_maps require more metadata on-disk
* large space_maps require more time to load (typically random reads)
Now the space_map block size can adjust as needed up to the maximum size
set via the space_map_max_blksz variable.
A bug was fixed which resulted in potentially leaking an object when
removing a mirrored log device. The previous logic for vdev_remove() did
not deal with removing top-level vdevs that are interior vdevs (i.e.
mirror) correctly. The problem would occur when removing a mirrored log
device, and result in the DTL space map object being leaked; because
top-level vdevs don't have DTL space map objects associated with them.
References:
https://www.illumos.org/issues/4101
https://www.illumos.org/issues/4102
https://www.illumos.org/issues/4103
https://www.illumos.org/issues/4105
https://www.illumos.org/issues/4106
https://github.com/illumos/illumos-gate/commit/0713e23
Porting notes:
A handful of kmem_alloc() calls were converted to kmem_zalloc(). Also,
the KM_PUSHPAGE and TQ_PUSHPAGE flags were used as necessary.
Ported-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Prakash Surya <surya1@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2488
2013-10-02 01:25:53 +04:00
|
|
|
range_tree_t *vdev_dtl[DTL_TYPES]; /* dirty time logs */
|
|
|
|
space_map_t *vdev_dtl_sm; /* dirty time log space map */
|
2008-11-20 23:01:55 +03:00
|
|
|
txg_node_t vdev_dtl_node; /* per-txg dirty DTL linkage */
|
Illumos #4101, #4102, #4103, #4105, #4106
4101 metaslab_debug should allow for fine-grained control
4102 space_maps should store more information about themselves
4103 space map object blocksize should be increased
4105 removing a mirrored log device results in a leaked object
4106 asynchronously load metaslab
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Sebastien Roy <seb@delphix.com>
Approved by: Garrett D'Amore <garrett@damore.org>
Prior to this patch, space_maps were preferred solely based on the
amount of free space left in each. Unfortunately, this heuristic didn't
contain any information about the make-up of that free space, which
meant we could keep preferring and loading a highly fragmented space map
that wouldn't actually have enough contiguous space to satisfy the
allocation; then unloading that space_map and repeating the process.
This change modifies the space_map's to store additional information
about the contiguous space in the space_map, so that we can use this
information to make a better decision about which space_map to load.
This requires reallocating all space_map objects to increase their
bonus buffer size sizes enough to fit the new metadata.
The above feature can be enabled via a new feature flag introduced by
this change: com.delphix:spacemap_histogram
In addition to the above, this patch allows the space_map block size to
be increase. Currently the block size is set to be 4K in size, which has
certain implications including the following:
* 4K sector devices will not see any compression benefit
* large space_maps require more metadata on-disk
* large space_maps require more time to load (typically random reads)
Now the space_map block size can adjust as needed up to the maximum size
set via the space_map_max_blksz variable.
A bug was fixed which resulted in potentially leaking an object when
removing a mirrored log device. The previous logic for vdev_remove() did
not deal with removing top-level vdevs that are interior vdevs (i.e.
mirror) correctly. The problem would occur when removing a mirrored log
device, and result in the DTL space map object being leaked; because
top-level vdevs don't have DTL space map objects associated with them.
References:
https://www.illumos.org/issues/4101
https://www.illumos.org/issues/4102
https://www.illumos.org/issues/4103
https://www.illumos.org/issues/4105
https://www.illumos.org/issues/4106
https://github.com/illumos/illumos-gate/commit/0713e23
Porting notes:
A handful of kmem_alloc() calls were converted to kmem_zalloc(). Also,
the KM_PUSHPAGE and TQ_PUSHPAGE flags were used as necessary.
Ported-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Prakash Surya <surya1@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2488
2013-10-02 01:25:53 +04:00
|
|
|
uint64_t vdev_dtl_object; /* DTL object */
|
|
|
|
uint64_t vdev_psize; /* physical device capacity */
|
2008-11-20 23:01:55 +03:00
|
|
|
uint64_t vdev_wholedisk; /* true if this is a whole disk */
|
|
|
|
uint64_t vdev_offline; /* persistent offline state */
|
|
|
|
uint64_t vdev_faulted; /* persistent faulted state */
|
|
|
|
uint64_t vdev_degraded; /* persistent degraded state */
|
|
|
|
uint64_t vdev_removed; /* persistent removed state */
|
2013-08-08 00:16:22 +04:00
|
|
|
uint64_t vdev_resilver_txg; /* persistent resilvering state */
|
2008-11-20 23:01:55 +03:00
|
|
|
uint64_t vdev_nparity; /* number of parity devices for raidz */
|
|
|
|
char *vdev_path; /* vdev path (if any) */
|
|
|
|
char *vdev_devid; /* vdev devid (if any) */
|
|
|
|
char *vdev_physpath; /* vdev device path (if any) */
|
2009-07-03 02:44:48 +04:00
|
|
|
char *vdev_fru; /* physical FRU location */
|
2008-12-03 23:09:06 +03:00
|
|
|
uint64_t vdev_not_present; /* not present during import */
|
|
|
|
uint64_t vdev_unspare; /* unspare when resilvering done */
|
|
|
|
boolean_t vdev_nowritecache; /* true if flushwritecache failed */
|
|
|
|
boolean_t vdev_checkremove; /* temporary online test */
|
|
|
|
boolean_t vdev_forcefault; /* force online fault */
|
2010-05-29 00:45:14 +04:00
|
|
|
boolean_t vdev_splitting; /* split or repair in progress */
|
|
|
|
boolean_t vdev_delayed_close; /* delayed device close? */
|
Illumos #4101, #4102, #4103, #4105, #4106
4101 metaslab_debug should allow for fine-grained control
4102 space_maps should store more information about themselves
4103 space map object blocksize should be increased
4105 removing a mirrored log device results in a leaked object
4106 asynchronously load metaslab
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Sebastien Roy <seb@delphix.com>
Approved by: Garrett D'Amore <garrett@damore.org>
Prior to this patch, space_maps were preferred solely based on the
amount of free space left in each. Unfortunately, this heuristic didn't
contain any information about the make-up of that free space, which
meant we could keep preferring and loading a highly fragmented space map
that wouldn't actually have enough contiguous space to satisfy the
allocation; then unloading that space_map and repeating the process.
This change modifies the space_map's to store additional information
about the contiguous space in the space_map, so that we can use this
information to make a better decision about which space_map to load.
This requires reallocating all space_map objects to increase their
bonus buffer size sizes enough to fit the new metadata.
The above feature can be enabled via a new feature flag introduced by
this change: com.delphix:spacemap_histogram
In addition to the above, this patch allows the space_map block size to
be increase. Currently the block size is set to be 4K in size, which has
certain implications including the following:
* 4K sector devices will not see any compression benefit
* large space_maps require more metadata on-disk
* large space_maps require more time to load (typically random reads)
Now the space_map block size can adjust as needed up to the maximum size
set via the space_map_max_blksz variable.
A bug was fixed which resulted in potentially leaking an object when
removing a mirrored log device. The previous logic for vdev_remove() did
not deal with removing top-level vdevs that are interior vdevs (i.e.
mirror) correctly. The problem would occur when removing a mirrored log
device, and result in the DTL space map object being leaked; because
top-level vdevs don't have DTL space map objects associated with them.
References:
https://www.illumos.org/issues/4101
https://www.illumos.org/issues/4102
https://www.illumos.org/issues/4103
https://www.illumos.org/issues/4105
https://www.illumos.org/issues/4106
https://github.com/illumos/illumos-gate/commit/0713e23
Porting notes:
A handful of kmem_alloc() calls were converted to kmem_zalloc(). Also,
the KM_PUSHPAGE and TQ_PUSHPAGE flags were used as necessary.
Ported-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Prakash Surya <surya1@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2488
2013-10-02 01:25:53 +04:00
|
|
|
boolean_t vdev_tmpoffline; /* device taken offline temporarily? */
|
|
|
|
boolean_t vdev_detached; /* device detached? */
|
|
|
|
boolean_t vdev_cant_read; /* vdev is failing all reads */
|
|
|
|
boolean_t vdev_cant_write; /* vdev is failing all writes */
|
|
|
|
boolean_t vdev_isspare; /* was a hot spare */
|
|
|
|
boolean_t vdev_isl2cache; /* was a l2cache device */
|
2008-11-20 23:01:55 +03:00
|
|
|
vdev_queue_t vdev_queue; /* I/O deadline schedule queue */
|
|
|
|
vdev_cache_t vdev_cache; /* physical block cache */
|
2015-05-20 07:14:01 +03:00
|
|
|
spa_aux_vdev_t *vdev_aux; /* for l2cache and spares vdevs */
|
2008-12-03 23:09:06 +03:00
|
|
|
zio_t *vdev_probe_zio; /* root of current probe */
|
2010-05-29 00:45:14 +04:00
|
|
|
vdev_aux_t vdev_label_aux; /* on-disk aux state */
|
2016-04-11 23:16:57 +03:00
|
|
|
uint64_t vdev_leaf_zap;
|
2008-11-20 23:01:55 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* For DTrace to work in userland (libzpool) context, these fields must
|
|
|
|
* remain at the end of the structure. DTrace will use the kernel's
|
|
|
|
* CTF definition for 'struct vdev', and since the size of a kmutex_t is
|
2012-12-14 03:24:15 +04:00
|
|
|
* larger in userland, the offsets for the rest of the fields would be
|
2008-11-20 23:01:55 +03:00
|
|
|
* incorrect.
|
|
|
|
*/
|
|
|
|
kmutex_t vdev_dtl_lock; /* vdev_dtl_{map,resilver} */
|
|
|
|
kmutex_t vdev_stat_lock; /* vdev_stat */
|
2008-12-03 23:09:06 +03:00
|
|
|
kmutex_t vdev_probe_lock; /* protects vdev_probe_zio */
|
2016-10-19 22:55:59 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We rate limit ZIO delay and ZIO checksum events, since they
|
|
|
|
* can flood ZED with tons of events when a drive is acting up.
|
|
|
|
*/
|
|
|
|
#define DELAYS_PER_SECOND 5
|
|
|
|
#define CHECKSUMS_PER_SECOND 5
|
|
|
|
zfs_ratelimit_t vdev_delay_rl;
|
|
|
|
zfs_ratelimit_t vdev_checksum_rl;
|
2008-11-20 23:01:55 +03:00
|
|
|
};
|
|
|
|
|
2010-05-29 00:45:14 +04:00
|
|
|
#define VDEV_RAIDZ_MAXPARITY 3
|
|
|
|
|
2009-07-03 02:44:48 +04:00
|
|
|
#define VDEV_PAD_SIZE (8 << 10)
|
|
|
|
/* 2 padding areas (vl_pad1 and vl_pad2) to skip */
|
|
|
|
#define VDEV_SKIP_SIZE VDEV_PAD_SIZE * 2
|
2008-11-20 23:01:55 +03:00
|
|
|
#define VDEV_PHYS_SIZE (112 << 10)
|
|
|
|
#define VDEV_UBERBLOCK_RING (128 << 10)
|
|
|
|
|
2014-09-23 03:42:03 +04:00
|
|
|
/* The largest uberblock we support is 8k. */
|
|
|
|
#define MAX_UBERBLOCK_SHIFT (13)
|
2008-11-20 23:01:55 +03:00
|
|
|
#define VDEV_UBERBLOCK_SHIFT(vd) \
|
2014-09-23 03:42:03 +04:00
|
|
|
MIN(MAX((vd)->vdev_top->vdev_ashift, UBERBLOCK_SHIFT), \
|
|
|
|
MAX_UBERBLOCK_SHIFT)
|
2008-11-20 23:01:55 +03:00
|
|
|
#define VDEV_UBERBLOCK_COUNT(vd) \
|
|
|
|
(VDEV_UBERBLOCK_RING >> VDEV_UBERBLOCK_SHIFT(vd))
|
|
|
|
#define VDEV_UBERBLOCK_OFFSET(vd, n) \
|
|
|
|
offsetof(vdev_label_t, vl_uberblock[(n) << VDEV_UBERBLOCK_SHIFT(vd)])
|
|
|
|
#define VDEV_UBERBLOCK_SIZE(vd) (1ULL << VDEV_UBERBLOCK_SHIFT(vd))
|
|
|
|
|
|
|
|
typedef struct vdev_phys {
|
2010-05-29 00:45:14 +04:00
|
|
|
char vp_nvlist[VDEV_PHYS_SIZE - sizeof (zio_eck_t)];
|
|
|
|
zio_eck_t vp_zbt;
|
2008-11-20 23:01:55 +03:00
|
|
|
} vdev_phys_t;
|
|
|
|
|
|
|
|
typedef struct vdev_label {
|
2009-07-03 02:44:48 +04:00
|
|
|
char vl_pad1[VDEV_PAD_SIZE]; /* 8K */
|
|
|
|
char vl_pad2[VDEV_PAD_SIZE]; /* 8K */
|
2008-11-20 23:01:55 +03:00
|
|
|
vdev_phys_t vl_vdev_phys; /* 112K */
|
|
|
|
char vl_uberblock[VDEV_UBERBLOCK_RING]; /* 128K */
|
|
|
|
} vdev_label_t; /* 256K total */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vdev_dirty() flags
|
|
|
|
*/
|
|
|
|
#define VDD_METASLAB 0x01
|
|
|
|
#define VDD_DTL 0x02
|
|
|
|
|
2013-06-11 21:12:34 +04:00
|
|
|
/* Offset of embedded boot loader region on each label */
|
|
|
|
#define VDEV_BOOT_OFFSET (2 * sizeof (vdev_label_t))
|
2008-11-20 23:01:55 +03:00
|
|
|
/*
|
2013-06-11 21:12:34 +04:00
|
|
|
* Size of embedded boot loader region on each label.
|
2008-11-20 23:01:55 +03:00
|
|
|
* The total size of the first two labels plus the boot area is 4MB.
|
|
|
|
*/
|
2013-06-11 21:12:34 +04:00
|
|
|
#define VDEV_BOOT_SIZE (7ULL << 19) /* 3.5M */
|
2008-11-20 23:01:55 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Size of label regions at the start and end of each leaf device.
|
|
|
|
*/
|
|
|
|
#define VDEV_LABEL_START_SIZE (2 * sizeof (vdev_label_t) + VDEV_BOOT_SIZE)
|
|
|
|
#define VDEV_LABEL_END_SIZE (2 * sizeof (vdev_label_t))
|
|
|
|
#define VDEV_LABELS 4
|
2012-12-14 03:24:15 +04:00
|
|
|
#define VDEV_BEST_LABEL VDEV_LABELS
|
2008-11-20 23:01:55 +03:00
|
|
|
|
|
|
|
#define VDEV_ALLOC_LOAD 0
|
|
|
|
#define VDEV_ALLOC_ADD 1
|
|
|
|
#define VDEV_ALLOC_SPARE 2
|
|
|
|
#define VDEV_ALLOC_L2CACHE 3
|
2009-07-03 02:44:48 +04:00
|
|
|
#define VDEV_ALLOC_ROOTPOOL 4
|
2010-05-29 00:45:14 +04:00
|
|
|
#define VDEV_ALLOC_SPLIT 5
|
2012-04-08 21:23:08 +04:00
|
|
|
#define VDEV_ALLOC_ATTACH 6
|
2008-11-20 23:01:55 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate or free a vdev
|
|
|
|
*/
|
2010-05-29 00:45:14 +04:00
|
|
|
extern vdev_t *vdev_alloc_common(spa_t *spa, uint_t id, uint64_t guid,
|
|
|
|
vdev_ops_t *ops);
|
2008-11-20 23:01:55 +03:00
|
|
|
extern int vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *config,
|
|
|
|
vdev_t *parent, uint_t id, int alloctype);
|
|
|
|
extern void vdev_free(vdev_t *vd);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add or remove children and parents
|
|
|
|
*/
|
|
|
|
extern void vdev_add_child(vdev_t *pvd, vdev_t *cvd);
|
|
|
|
extern void vdev_remove_child(vdev_t *pvd, vdev_t *cvd);
|
|
|
|
extern void vdev_compact_children(vdev_t *pvd);
|
|
|
|
extern vdev_t *vdev_add_parent(vdev_t *cvd, vdev_ops_t *ops);
|
|
|
|
extern void vdev_remove_parent(vdev_t *cvd);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vdev sync load and sync
|
|
|
|
*/
|
2010-05-29 00:45:14 +04:00
|
|
|
extern void vdev_load_log_state(vdev_t *nvd, vdev_t *ovd);
|
2010-08-27 01:24:34 +04:00
|
|
|
extern boolean_t vdev_log_state_valid(vdev_t *vd);
|
2008-11-20 23:01:55 +03:00
|
|
|
extern void vdev_load(vdev_t *vd);
|
Illumos #4101, #4102, #4103, #4105, #4106
4101 metaslab_debug should allow for fine-grained control
4102 space_maps should store more information about themselves
4103 space map object blocksize should be increased
4105 removing a mirrored log device results in a leaked object
4106 asynchronously load metaslab
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Sebastien Roy <seb@delphix.com>
Approved by: Garrett D'Amore <garrett@damore.org>
Prior to this patch, space_maps were preferred solely based on the
amount of free space left in each. Unfortunately, this heuristic didn't
contain any information about the make-up of that free space, which
meant we could keep preferring and loading a highly fragmented space map
that wouldn't actually have enough contiguous space to satisfy the
allocation; then unloading that space_map and repeating the process.
This change modifies the space_map's to store additional information
about the contiguous space in the space_map, so that we can use this
information to make a better decision about which space_map to load.
This requires reallocating all space_map objects to increase their
bonus buffer size sizes enough to fit the new metadata.
The above feature can be enabled via a new feature flag introduced by
this change: com.delphix:spacemap_histogram
In addition to the above, this patch allows the space_map block size to
be increase. Currently the block size is set to be 4K in size, which has
certain implications including the following:
* 4K sector devices will not see any compression benefit
* large space_maps require more metadata on-disk
* large space_maps require more time to load (typically random reads)
Now the space_map block size can adjust as needed up to the maximum size
set via the space_map_max_blksz variable.
A bug was fixed which resulted in potentially leaking an object when
removing a mirrored log device. The previous logic for vdev_remove() did
not deal with removing top-level vdevs that are interior vdevs (i.e.
mirror) correctly. The problem would occur when removing a mirrored log
device, and result in the DTL space map object being leaked; because
top-level vdevs don't have DTL space map objects associated with them.
References:
https://www.illumos.org/issues/4101
https://www.illumos.org/issues/4102
https://www.illumos.org/issues/4103
https://www.illumos.org/issues/4105
https://www.illumos.org/issues/4106
https://github.com/illumos/illumos-gate/commit/0713e23
Porting notes:
A handful of kmem_alloc() calls were converted to kmem_zalloc(). Also,
the KM_PUSHPAGE and TQ_PUSHPAGE flags were used as necessary.
Ported-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Prakash Surya <surya1@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2488
2013-10-02 01:25:53 +04:00
|
|
|
extern int vdev_dtl_load(vdev_t *vd);
|
2008-11-20 23:01:55 +03:00
|
|
|
extern void vdev_sync(vdev_t *vd, uint64_t txg);
|
|
|
|
extern void vdev_sync_done(vdev_t *vd, uint64_t txg);
|
|
|
|
extern void vdev_dirty(vdev_t *vd, int flags, void *arg, uint64_t txg);
|
Illumos #4101, #4102, #4103, #4105, #4106
4101 metaslab_debug should allow for fine-grained control
4102 space_maps should store more information about themselves
4103 space map object blocksize should be increased
4105 removing a mirrored log device results in a leaked object
4106 asynchronously load metaslab
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Sebastien Roy <seb@delphix.com>
Approved by: Garrett D'Amore <garrett@damore.org>
Prior to this patch, space_maps were preferred solely based on the
amount of free space left in each. Unfortunately, this heuristic didn't
contain any information about the make-up of that free space, which
meant we could keep preferring and loading a highly fragmented space map
that wouldn't actually have enough contiguous space to satisfy the
allocation; then unloading that space_map and repeating the process.
This change modifies the space_map's to store additional information
about the contiguous space in the space_map, so that we can use this
information to make a better decision about which space_map to load.
This requires reallocating all space_map objects to increase their
bonus buffer size sizes enough to fit the new metadata.
The above feature can be enabled via a new feature flag introduced by
this change: com.delphix:spacemap_histogram
In addition to the above, this patch allows the space_map block size to
be increase. Currently the block size is set to be 4K in size, which has
certain implications including the following:
* 4K sector devices will not see any compression benefit
* large space_maps require more metadata on-disk
* large space_maps require more time to load (typically random reads)
Now the space_map block size can adjust as needed up to the maximum size
set via the space_map_max_blksz variable.
A bug was fixed which resulted in potentially leaking an object when
removing a mirrored log device. The previous logic for vdev_remove() did
not deal with removing top-level vdevs that are interior vdevs (i.e.
mirror) correctly. The problem would occur when removing a mirrored log
device, and result in the DTL space map object being leaked; because
top-level vdevs don't have DTL space map objects associated with them.
References:
https://www.illumos.org/issues/4101
https://www.illumos.org/issues/4102
https://www.illumos.org/issues/4103
https://www.illumos.org/issues/4105
https://www.illumos.org/issues/4106
https://github.com/illumos/illumos-gate/commit/0713e23
Porting notes:
A handful of kmem_alloc() calls were converted to kmem_zalloc(). Also,
the KM_PUSHPAGE and TQ_PUSHPAGE flags were used as necessary.
Ported-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Prakash Surya <surya1@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2488
2013-10-02 01:25:53 +04:00
|
|
|
extern void vdev_dirty_leaves(vdev_t *vd, int flags, uint64_t txg);
|
2008-11-20 23:01:55 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Available vdev types.
|
|
|
|
*/
|
|
|
|
extern vdev_ops_t vdev_root_ops;
|
|
|
|
extern vdev_ops_t vdev_mirror_ops;
|
|
|
|
extern vdev_ops_t vdev_replacing_ops;
|
|
|
|
extern vdev_ops_t vdev_raidz_ops;
|
|
|
|
extern vdev_ops_t vdev_disk_ops;
|
|
|
|
extern vdev_ops_t vdev_file_ops;
|
|
|
|
extern vdev_ops_t vdev_missing_ops;
|
2010-05-29 00:45:14 +04:00
|
|
|
extern vdev_ops_t vdev_hole_ops;
|
2008-11-20 23:01:55 +03:00
|
|
|
extern vdev_ops_t vdev_spare_ops;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Common size functions
|
|
|
|
*/
|
|
|
|
extern uint64_t vdev_default_asize(vdev_t *vd, uint64_t psize);
|
2009-07-03 02:44:48 +04:00
|
|
|
extern uint64_t vdev_get_min_asize(vdev_t *vd);
|
|
|
|
extern void vdev_set_min_asize(vdev_t *vd);
|
2008-11-20 23:01:55 +03:00
|
|
|
|
|
|
|
/*
|
2013-06-11 21:12:34 +04:00
|
|
|
* Global variables
|
2008-11-20 23:01:55 +03:00
|
|
|
*/
|
2013-06-11 21:12:34 +04:00
|
|
|
/* zdb uses this tunable, so it must be declared here to make lint happy. */
|
2008-11-20 23:01:55 +03:00
|
|
|
extern int zfs_vdev_cache_size;
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* _SYS_VDEV_IMPL_H */
|