Print this page
NEX-6353 The "DKIOCSOLIDSTATE failed, assuming non-SSD media" messages don't provide any useful information
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5736 implement autoreplace matching based on FRU slot number
NEX-6200 hot spares are not reactivated after reinserting into enclosure
NEX-9403 need to update FRU for spare and l2cache devices
NEX-9404 remove lofi autoreplace support from syseventd
NEX-9409 hotsparing doesn't work for vdevs without FRU
NEX-9424 zfs`vdev_online() needs better notification about state changes
Portions contributed by: Alek Pinchuk <alek@nexenta.com>
Portions contributed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-8065 ZFS doesn't notice when disk vdevs have no write cache
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
NEX-2846 Enable Automatic/Intelligent Hot Sparing capability
Reviewed by: Jeffry Molanus <jeffry.molanus@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
6494 ASSERT supported zio_types for file and disk vdevs
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Albert Lee <trisk@omniti.com>
NEX-3984 On-demand TRIM
Reviewed by: Alek Pinchuk <alek@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Conflicts:
usr/src/common/zfs/zpool_prop.c
usr/src/uts/common/sys/fs/zfs.h
NEX-3508 CLONE - Port NEX-2946 Add UNMAP/TRIM functionality to ZFS and illumos
Reviewed by: Josef Sipek <josef.sipek@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Conflicts:
usr/src/uts/common/io/scsi/targets/sd.c
usr/src/uts/common/sys/scsi/targets/sddef.h
NEX-2933 tip of nza-kernel hangs during zpool offline
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Josef Sipek <josef.sipek@nexenta.com>
NEX-1142 move rwlock to vdev to protect vdev_tsd
not just ldi handle.
This way we serialize open/close, yet allow parallel I/O.
4370 avoid transmitting holes during zfs send
4371 DMU code clean up
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
Approved by: Garrett D'Amore <garrett@damore.org>
NEX-1065 Added serialization to avoid race (fix lint)
NEX-1065 Added serialization to avoid race
between ldi notification and I/O path.
Also fixes OS-124, NEX-1051, NEX-1062.
*** 16,30 ****
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
! * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
! * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
*/
#include <sys/zfs_context.h>
#include <sys/spa_impl.h>
#include <sys/refcount.h>
--- 16,31 ----
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
+
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
! * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright (c) 2013 Joyent, Inc. All rights reserved.
+ * Copyright 2017 Nexenta Systems, Inc.
*/
#include <sys/zfs_context.h>
#include <sys/spa_impl.h>
#include <sys/refcount.h>
*** 41,100 ****
* Virtual device vector for disks.
*/
extern ldi_ident_t zfs_li;
! static void vdev_disk_close(vdev_t *);
typedef struct vdev_disk_ldi_cb {
list_node_t lcb_next;
ldi_callback_id_t lcb_id;
} vdev_disk_ldi_cb_t;
! static void
! vdev_disk_alloc(vdev_t *vd)
{
vdev_disk_t *dvd;
! dvd = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_disk_t), KM_SLEEP);
/*
* Create the LDI event callback list.
*/
list_create(&dvd->vd_ldi_cbs, sizeof (vdev_disk_ldi_cb_t),
offsetof(vdev_disk_ldi_cb_t, lcb_next));
}
static void
! vdev_disk_free(vdev_t *vd)
{
- vdev_disk_t *dvd = vd->vdev_tsd;
vdev_disk_ldi_cb_t *lcb;
if (dvd == NULL)
return;
/*
* We have already closed the LDI handle. Clean up the LDI event
* callbacks and free vd->vdev_tsd.
*/
while ((lcb = list_head(&dvd->vd_ldi_cbs)) != NULL) {
list_remove(&dvd->vd_ldi_cbs, lcb);
(void) ldi_ev_remove_callbacks(lcb->lcb_id);
kmem_free(lcb, sizeof (vdev_disk_ldi_cb_t));
}
list_destroy(&dvd->vd_ldi_cbs);
kmem_free(dvd, sizeof (vdev_disk_t));
- vd->vdev_tsd = NULL;
}
/* ARGSUSED */
static int
vdev_disk_off_notify(ldi_handle_t lh, ldi_ev_cookie_t ecookie, void *arg,
void *ev_data)
{
vdev_t *vd = (vdev_t *)arg;
- vdev_disk_t *dvd = vd->vdev_tsd;
/*
* Ignore events other than offline.
*/
if (strcmp(ldi_ev_get_type(ecookie), LDI_EV_OFFLINE) != 0)
--- 42,111 ----
* Virtual device vector for disks.
*/
extern ldi_ident_t zfs_li;
! static void vdev_disk_close_impl(vdev_t *, boolean_t);
typedef struct vdev_disk_ldi_cb {
list_node_t lcb_next;
ldi_callback_id_t lcb_id;
} vdev_disk_ldi_cb_t;
! static vdev_disk_t *
! vdev_disk_alloc(void)
{
vdev_disk_t *dvd;
! dvd = kmem_zalloc(sizeof (vdev_disk_t), KM_SLEEP);
/*
* Create the LDI event callback list.
*/
list_create(&dvd->vd_ldi_cbs, sizeof (vdev_disk_ldi_cb_t),
offsetof(vdev_disk_ldi_cb_t, lcb_next));
+ return (dvd);
}
static void
! vdev_disk_free_locked(vdev_t *vd)
{
vdev_disk_ldi_cb_t *lcb;
+ vdev_disk_t *dvd = vd->vdev_tsd;
+ ASSERT(rw_lock_held(&vd->vdev_tsd_lock));
+
if (dvd == NULL)
return;
/*
* We have already closed the LDI handle. Clean up the LDI event
* callbacks and free vd->vdev_tsd.
*/
+ vd->vdev_tsd = NULL;
while ((lcb = list_head(&dvd->vd_ldi_cbs)) != NULL) {
list_remove(&dvd->vd_ldi_cbs, lcb);
(void) ldi_ev_remove_callbacks(lcb->lcb_id);
kmem_free(lcb, sizeof (vdev_disk_ldi_cb_t));
}
list_destroy(&dvd->vd_ldi_cbs);
kmem_free(dvd, sizeof (vdev_disk_t));
}
+ static void
+ vdev_disk_free(vdev_t *vd)
+ {
+ rw_enter(&vd->vdev_tsd_lock, RW_WRITER);
+ vdev_disk_free_locked(vd);
+ rw_exit(&vd->vdev_tsd_lock);
+ }
+
/* ARGSUSED */
static int
vdev_disk_off_notify(ldi_handle_t lh, ldi_ev_cookie_t ecookie, void *arg,
void *ev_data)
{
vdev_t *vd = (vdev_t *)arg;
/*
* Ignore events other than offline.
*/
if (strcmp(ldi_ev_get_type(ecookie), LDI_EV_OFFLINE) != 0)
*** 106,117 ****
*
* We inform vdev_disk_close that it is being called from offline
* notify context so it will defer cleanup of LDI event callbacks and
* freeing of vd->vdev_tsd to the offline finalize or a reopen.
*/
! dvd->vd_ldi_offline = B_TRUE;
! vdev_disk_close(vd);
/*
* Now that the device is closed, request that the spa_async_thread
* mark the device as REMOVED and notify FMA of the removal.
*/
--- 117,127 ----
*
* We inform vdev_disk_close that it is being called from offline
* notify context so it will defer cleanup of LDI event callbacks and
* freeing of vd->vdev_tsd to the offline finalize or a reopen.
*/
! vdev_disk_close_impl(vd, B_TRUE);
/*
* Now that the device is closed, request that the spa_async_thread
* mark the device as REMOVED and notify FMA of the removal.
*/
*** 240,265 ****
dsl_pool_vnrele_taskq(vd->vdev_spa->spa_dsl_pool));
vd->vdev_devid_vp = NULL;
}
}
- /*
- * We want to be loud in DEBUG kernels when DKIOCGMEDIAINFOEXT fails, or when
- * even a fallback to DKIOCGMEDIAINFO fails.
- */
- #ifdef DEBUG
- #define VDEV_DEBUG(...) cmn_err(CE_NOTE, __VA_ARGS__)
- #else
- #define VDEV_DEBUG(...) /* Nothing... */
- #endif
-
static int
vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
uint64_t *ashift)
{
spa_t *spa = vd->vdev_spa;
! vdev_disk_t *dvd = vd->vdev_tsd;
ldi_ev_cookie_t ecookie;
vdev_disk_ldi_cb_t *lcb;
union {
struct dk_minfo_ext ude;
struct dk_minfo ud;
--- 250,265 ----
dsl_pool_vnrele_taskq(vd->vdev_spa->spa_dsl_pool));
vd->vdev_devid_vp = NULL;
}
}
static int
vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
uint64_t *ashift)
{
spa_t *spa = vd->vdev_spa;
! vdev_disk_t *dvd;
ldi_ev_cookie_t ecookie;
vdev_disk_ldi_cb_t *lcb;
union {
struct dk_minfo_ext ude;
struct dk_minfo ud;
*** 266,276 ****
} dks;
struct dk_minfo_ext *dkmext = &dks.ude;
struct dk_minfo *dkm = &dks.ud;
int error;
dev_t dev;
! int otyp;
boolean_t validate_devid = B_FALSE;
ddi_devid_t devid;
uint64_t capacity = 0, blksz = 0, pbsize;
/*
--- 266,276 ----
} dks;
struct dk_minfo_ext *dkmext = &dks.ude;
struct dk_minfo *dkm = &dks.ud;
int error;
dev_t dev;
! int otyp, vdev_ssd;
boolean_t validate_devid = B_FALSE;
ddi_devid_t devid;
uint64_t capacity = 0, blksz = 0, pbsize;
/*
*** 278,311 ****
*/
if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') {
vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
return (SET_ERROR(EINVAL));
}
!
/*
* Reopen the device if it's not currently open. Otherwise,
* just update the physical size of the device.
*/
if (dvd != NULL) {
! if (dvd->vd_ldi_offline && dvd->vd_lh == NULL) {
/*
! * If we are opening a device in its offline notify
! * context, the LDI handle was just closed. Clean
! * up the LDI event callbacks and free vd->vdev_tsd.
*/
! vdev_disk_free(vd);
! } else {
! ASSERT(vd->vdev_reopening);
goto skip_open;
}
- }
-
/*
! * Create vd->vdev_tsd.
*/
! vdev_disk_alloc(vd);
! dvd = vd->vdev_tsd;
/*
* When opening a disk device, we want to preserve the user's original
* intent. We always want to open the device by the path the user gave
* us, even if it is one of multiple paths to the same device. But we
--- 278,311 ----
*/
if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') {
vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
return (SET_ERROR(EINVAL));
}
! rw_enter(&vd->vdev_tsd_lock, RW_WRITER);
! dvd = vd->vdev_tsd;
/*
* Reopen the device if it's not currently open. Otherwise,
* just update the physical size of the device.
*/
if (dvd != NULL) {
! ASSERT(vd->vdev_reopening);
/*
! * Here vd_lh is protected by vdev_tsd_lock
*/
! ASSERT(dvd->vd_lh != NULL);
! /* This should not happen, but let's be safe */
! if (dvd->vd_lh == NULL) {
! /* What are we going to do here??? */
! rw_exit(&vd->vdev_tsd_lock);
! return (SET_ERROR(ENXIO));
! }
goto skip_open;
}
/*
! * Create dvd to be used as vd->vdev_tsd.
*/
! vd->vdev_tsd = dvd = vdev_disk_alloc();
/*
* When opening a disk device, we want to preserve the user's original
* intent. We always want to open the device by the path the user gave
* us, even if it is one of multiple paths to the same device. But we
*** 323,334 ****
*/
if (vd->vdev_devid != NULL) {
if (ddi_devid_str_decode(vd->vdev_devid, &dvd->vd_devid,
&dvd->vd_minor) != 0) {
vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
! vdev_dbgmsg(vd, "vdev_disk_open: invalid "
! "vdev_devid '%s'", vd->vdev_devid);
return (SET_ERROR(EINVAL));
}
}
error = EINVAL; /* presume failure */
--- 323,334 ----
*/
if (vd->vdev_devid != NULL) {
if (ddi_devid_str_decode(vd->vdev_devid, &dvd->vd_devid,
&dvd->vd_minor) != 0) {
vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
! vdev_disk_free_locked(vd);
! rw_exit(&vd->vdev_tsd_lock);
return (SET_ERROR(EINVAL));
}
}
error = EINVAL; /* presume failure */
*** 417,428 ****
kcred, &dvd->vd_lh, zfs_li);
}
if (error) {
vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
! vdev_dbgmsg(vd, "vdev_disk_open: failed to open [error=%d]",
! error);
return (error);
}
/*
* Now that the device has been successfully opened, update the devid
--- 417,428 ----
kcred, &dvd->vd_lh, zfs_li);
}
if (error) {
vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
! vdev_disk_free_locked(vd);
! rw_exit(&vd->vdev_tsd_lock);
return (error);
}
/*
* Now that the device has been successfully opened, update the devid
*** 432,443 ****
ldi_get_devid(dvd->vd_lh, &devid) == 0) {
if (ddi_devid_compare(devid, dvd->vd_devid) != 0) {
char *vd_devid;
vd_devid = ddi_devid_str_encode(devid, dvd->vd_minor);
! vdev_dbgmsg(vd, "vdev_disk_open: update devid from "
! "'%s' to '%s'", vd->vdev_devid, vd_devid);
spa_strfree(vd->vdev_devid);
vd->vdev_devid = spa_strdup(vd_devid);
ddi_devid_str_free(vd_devid);
}
ddi_devid_free(devid);
--- 432,443 ----
ldi_get_devid(dvd->vd_lh, &devid) == 0) {
if (ddi_devid_compare(devid, dvd->vd_devid) != 0) {
char *vd_devid;
vd_devid = ddi_devid_str_encode(devid, dvd->vd_minor);
! zfs_dbgmsg("vdev %s: update devid from %s, "
! "to %s", vd->vdev_path, vd->vdev_devid, vd_devid);
spa_strfree(vd->vdev_devid);
vd->vdev_devid = spa_strdup(vd_devid);
ddi_devid_str_free(vd_devid);
}
ddi_devid_free(devid);
*** 487,503 ****
lcb = kmem_zalloc(sizeof (vdev_disk_ldi_cb_t), KM_SLEEP);
list_insert_tail(&dvd->vd_ldi_cbs, lcb);
(void) ldi_ev_register_callbacks(dvd->vd_lh, ecookie,
&vdev_disk_dgrd_callb, (void *) vd, &lcb->lcb_id);
}
skip_open:
/*
* Determine the actual size of the device.
*/
if (ldi_get_size(dvd->vd_lh, psize) != 0) {
vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
! vdev_dbgmsg(vd, "vdev_disk_open: failed to get size");
return (SET_ERROR(EINVAL));
}
*max_psize = *psize;
--- 487,509 ----
lcb = kmem_zalloc(sizeof (vdev_disk_ldi_cb_t), KM_SLEEP);
list_insert_tail(&dvd->vd_ldi_cbs, lcb);
(void) ldi_ev_register_callbacks(dvd->vd_lh, ecookie,
&vdev_disk_dgrd_callb, (void *) vd, &lcb->lcb_id);
}
+
+ /* Reset TRIM flag, as underlying device support may have changed */
+ vd->vdev_notrim = B_FALSE;
+
skip_open:
+ ASSERT(dvd != NULL);
/*
* Determine the actual size of the device.
*/
if (ldi_get_size(dvd->vd_lh, psize) != 0) {
vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
! vdev_disk_free_locked(vd);
! rw_exit(&vd->vdev_tsd_lock);
return (SET_ERROR(EINVAL));
}
*max_psize = *psize;
*** 510,529 ****
capacity = dkmext->dki_capacity - 1;
blksz = dkmext->dki_lbsize;
pbsize = dkmext->dki_pbsize;
} else if ((error = ldi_ioctl(dvd->vd_lh, DKIOCGMEDIAINFO,
(intptr_t)dkm, FKIOCTL, kcred, NULL)) == 0) {
- VDEV_DEBUG(
- "vdev_disk_open(\"%s\"): fallback to DKIOCGMEDIAINFO\n",
- vd->vdev_path);
capacity = dkm->dki_capacity - 1;
blksz = dkm->dki_lbsize;
pbsize = blksz;
} else {
- VDEV_DEBUG("vdev_disk_open(\"%s\"): "
- "both DKIOCGMEDIAINFO{,EXT} calls failed, %d\n",
- vd->vdev_path, error);
pbsize = DEV_BSIZE;
}
*ashift = highbit64(MAX(pbsize, SPA_MINBLOCKSIZE)) - 1;
--- 516,529 ----
*** 546,571 ****
*/
(void) ldi_ioctl(dvd->vd_lh, DKIOCSETWCE, (intptr_t)&wce,
FKIOCTL, kcred, NULL);
}
/*
* Clear the nowritecache bit, so that on a vdev_reopen() we will
* try again.
*/
vd->vdev_nowritecache = B_FALSE;
return (0);
}
static void
! vdev_disk_close(vdev_t *vd)
{
! vdev_disk_t *dvd = vd->vdev_tsd;
if (vd->vdev_reopening || dvd == NULL)
! return;
if (dvd->vd_minor != NULL) {
ddi_devid_str_free(dvd->vd_minor);
dvd->vd_minor = NULL;
}
--- 546,595 ----
*/
(void) ldi_ioctl(dvd->vd_lh, DKIOCSETWCE, (intptr_t)&wce,
FKIOCTL, kcred, NULL);
}
+ if (ldi_ioctl(dvd->vd_lh, DKIOCSOLIDSTATE, (intptr_t)&vdev_ssd,
+ FKIOCTL, kcred, NULL) != 0)
+ vd->vdev_is_ssd = B_FALSE;
+ else
+ vd->vdev_is_ssd = vdev_ssd ? B_TRUE : B_FALSE;
+
/*
+ * We are done with vd_lh and vdev_tsd, release the vdev_tsd_lock
+ */
+ rw_exit(&vd->vdev_tsd_lock);
+
+ /*
* Clear the nowritecache bit, so that on a vdev_reopen() we will
* try again.
*/
vd->vdev_nowritecache = B_FALSE;
+ /*
+ * vdev open has succeeded - reset fault flags if last fault was due
+ * to a failed open since the open fault looks to have been transient
+ */
+ if (vd->vdev_removed || (vd->vdev_faulted &&
+ vd->vdev_label_aux == VDEV_AUX_OPEN_FAILED)) {
+ vd->vdev_faulted = vd->vdev_removed = 0ULL;
+ vd->vdev_label_aux = VDEV_AUX_NONE;
+ }
+
return (0);
}
static void
! vdev_disk_close_impl(vdev_t *vd, boolean_t ldi_offline)
{
! vdev_disk_t *dvd;
+ rw_enter(&vd->vdev_tsd_lock, RW_WRITER);
+ dvd = vd->vdev_tsd;
+
if (vd->vdev_reopening || dvd == NULL)
! goto out;
if (dvd->vd_minor != NULL) {
ddi_devid_str_free(dvd->vd_minor);
dvd->vd_minor = NULL;
}
*** 584,625 ****
/*
* If we closed the LDI handle due to an offline notify from LDI,
* don't free vd->vdev_tsd or unregister the callbacks here;
* the offline finalize callback or a reopen will take care of it.
*/
! if (dvd->vd_ldi_offline)
! return;
! vdev_disk_free(vd);
}
int
vdev_disk_physio(vdev_t *vd, caddr_t data,
size_t size, uint64_t offset, int flags, boolean_t isdump)
{
! vdev_disk_t *dvd = vd->vdev_tsd;
/*
* If the vdev is closed, it's likely in the REMOVED or FAULTED state.
* Nothing to be done here but return failure.
*/
! if (dvd == NULL || (dvd->vd_ldi_offline && dvd->vd_lh == NULL))
! return (EIO);
ASSERT(vd->vdev_ops == &vdev_disk_ops);
/*
* If in the context of an active crash dump, use the ldi_dump(9F)
* call instead of ldi_strategy(9F) as usual.
*/
if (isdump) {
ASSERT3P(dvd, !=, NULL);
! return (ldi_dump(dvd->vd_lh, data, lbtodb(offset),
! lbtodb(size)));
}
! return (vdev_disk_ldi_physio(dvd->vd_lh, data, size, offset, flags));
}
int
vdev_disk_ldi_physio(ldi_handle_t vd_lh, caddr_t data,
size_t size, uint64_t offset, int flags)
--- 608,661 ----
/*
* If we closed the LDI handle due to an offline notify from LDI,
* don't free vd->vdev_tsd or unregister the callbacks here;
* the offline finalize callback or a reopen will take care of it.
*/
! if (!ldi_offline)
! vdev_disk_free_locked(vd);
! out:
! rw_exit(&vd->vdev_tsd_lock);
! }
! static void
! vdev_disk_close(vdev_t *vd)
! {
! vdev_disk_close_impl(vd, B_FALSE);
}
int
vdev_disk_physio(vdev_t *vd, caddr_t data,
size_t size, uint64_t offset, int flags, boolean_t isdump)
{
! int rc = EIO;
! vdev_disk_t *dvd;
+ rw_enter(&vd->vdev_tsd_lock, RW_READER);
+ dvd = vd->vdev_tsd;
/*
* If the vdev is closed, it's likely in the REMOVED or FAULTED state.
* Nothing to be done here but return failure.
*/
! if (dvd == NULL || dvd->vd_lh == NULL)
! goto out;
ASSERT(vd->vdev_ops == &vdev_disk_ops);
/*
* If in the context of an active crash dump, use the ldi_dump(9F)
* call instead of ldi_strategy(9F) as usual.
*/
if (isdump) {
ASSERT3P(dvd, !=, NULL);
! rc = ldi_dump(dvd->vd_lh, data, lbtodb(offset), lbtodb(size));
! goto out;
}
! rc = vdev_disk_ldi_physio(dvd->vd_lh, data, size, offset, flags);
! out:
! rw_exit(&vd->vdev_tsd_lock);
! return (rc);
}
int
vdev_disk_ldi_physio(ldi_handle_t vd_lh, caddr_t data,
size_t size, uint64_t offset, int flags)
*** 698,727 ****
static void
vdev_disk_io_start(zio_t *zio)
{
vdev_t *vd = zio->io_vd;
! vdev_disk_t *dvd = vd->vdev_tsd;
vdev_buf_t *vb;
struct dk_callback *dkc;
buf_t *bp;
int error;
/*
* If the vdev is closed, it's likely in the REMOVED or FAULTED state.
* Nothing to be done here but return failure.
*/
! if (dvd == NULL || (dvd->vd_ldi_offline && dvd->vd_lh == NULL)) {
zio->io_error = ENXIO;
zio_interrupt(zio);
return;
}
if (zio->io_type == ZIO_TYPE_IOCTL) {
/* XXPOLICY */
if (!vdev_readable(vd)) {
zio->io_error = SET_ERROR(ENXIO);
zio_interrupt(zio);
return;
}
switch (zio->io_cmd) {
--- 734,767 ----
static void
vdev_disk_io_start(zio_t *zio)
{
vdev_t *vd = zio->io_vd;
! vdev_disk_t *dvd;
vdev_buf_t *vb;
struct dk_callback *dkc;
buf_t *bp;
int error;
+ rw_enter(&vd->vdev_tsd_lock, RW_READER);
+ dvd = vd->vdev_tsd;
/*
* If the vdev is closed, it's likely in the REMOVED or FAULTED state.
* Nothing to be done here but return failure.
*/
! if (dvd == NULL || dvd->vd_lh == NULL) {
zio->io_error = ENXIO;
+ rw_exit(&vd->vdev_tsd_lock);
zio_interrupt(zio);
return;
}
if (zio->io_type == ZIO_TYPE_IOCTL) {
/* XXPOLICY */
if (!vdev_readable(vd)) {
zio->io_error = SET_ERROR(ENXIO);
+ rw_exit(&vd->vdev_tsd_lock);
zio_interrupt(zio);
return;
}
switch (zio->io_cmd) {
*** 750,770 ****
--- 790,841 ----
/*
* The ioctl will be done asychronously,
* and will call vdev_disk_ioctl_done()
* upon completion.
*/
+ rw_exit(&vd->vdev_tsd_lock);
return;
}
zio->io_error = error;
break;
+ case DKIOCFREE:
+ /*
+ * We perform device support checks here instead of
+ * in zio_trim(), as zio_trim() might be invoked on
+ * top of a top-level vdev, whereas vdev_disk_io_start
+ * is guaranteed to be operating a leaf vdev.
+ */
+ if (vd->vdev_notrim &&
+ spa_get_force_trim(vd->vdev_spa) !=
+ SPA_FORCE_TRIM_ON) {
+ zio->io_error = SET_ERROR(ENOTSUP);
+ break;
+ }
+
+ /*
+ * zio->io_private contains a dkioc_free_list_t
+ * specifying which offsets are to be freed
+ */
+ ASSERT(zio->io_private != NULL);
+ error = ldi_ioctl(dvd->vd_lh, zio->io_cmd,
+ (uintptr_t)zio->io_private, FKIOCTL, kcred, NULL);
+
+ if (error == ENOTSUP || error == ENOTTY)
+ vd->vdev_notrim = B_TRUE;
+
+ zio->io_error = error;
+
+ break;
+
default:
zio->io_error = SET_ERROR(ENOTSUP);
}
+ rw_exit(&vd->vdev_tsd_lock);
zio_execute(zio);
return;
}
ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE);
*** 794,803 ****
--- 865,875 ----
bp->b_bufsize = zio->io_size;
bp->b_iodone = (int (*)())vdev_disk_io_intr;
/* ldi_strategy() will return non-zero only on programming errors */
VERIFY(ldi_strategy(dvd->vd_lh, bp) == 0);
+ rw_exit(&vd->vdev_tsd_lock);
}
static void
vdev_disk_io_done(zio_t *zio)
{
*** 808,822 ****
* the device has been removed. If this is the case, then we trigger an
* asynchronous removal of the device. Otherwise, probe the device and
* make sure it's still accessible.
*/
if (zio->io_error == EIO && !vd->vdev_remove_wanted) {
! vdev_disk_t *dvd = vd->vdev_tsd;
! int state = DKIO_NONE;
! if (ldi_ioctl(dvd->vd_lh, DKIOCSTATE, (intptr_t)&state,
! FKIOCTL, kcred, NULL) == 0 && state != DKIO_INSERTED) {
/*
* We post the resource as soon as possible, instead of
* when the async removal actually happens, because the
* DE is using this information to discard previous I/O
* errors.
--- 880,899 ----
* the device has been removed. If this is the case, then we trigger an
* asynchronous removal of the device. Otherwise, probe the device and
* make sure it's still accessible.
*/
if (zio->io_error == EIO && !vd->vdev_remove_wanted) {
! vdev_disk_t *dvd;
! int rc = EIO, state = DKIO_NONE;
! rw_enter(&vd->vdev_tsd_lock, RW_READER);
! dvd = vd->vdev_tsd;
! if (dvd != NULL && dvd->vd_lh != NULL)
! rc = ldi_ioctl(dvd->vd_lh, DKIOCSTATE,
! (intptr_t)&state, FKIOCTL, kcred, NULL);
! rw_exit(&vd->vdev_tsd_lock);
! if (rc == 0 && state != DKIO_INSERTED) {
/*
* We post the resource as soon as possible, instead of
* when the async removal actually happens, because the
* DE is using this information to discard previous I/O
* errors.