summaryrefslogtreecommitdiffstats
path: root/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
diff options
context:
space:
mode:
authormm <mm@FreeBSD.org>2013-04-06 10:39:38 +0000
committermm <mm@FreeBSD.org>2013-04-06 10:39:38 +0000
commit696d961cbd8bcba286545fef03c51a896b56d229 (patch)
tree557b6db8b3be2ff65382b43d2ae9edd99d502a44 /sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
parentf25063da0770fd0a9b4ed6ffdd6687e7de116255 (diff)
parent70e6431e93f13270d6907ce23de3c7da99803278 (diff)
downloadFreeBSD-src-696d961cbd8bcba286545fef03c51a896b56d229.zip
FreeBSD-src-696d961cbd8bcba286545fef03c51a896b56d229.tar.gz
MFV r248217:
Merge change from vendor to reduce diff only. ZFS dtrace probes are not supported on FreeBSD yet. Illumos ZFS issues: 3598 want to dtrace when errors are generated in zfs MFC after: 3 weeks
Diffstat (limited to 'sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c153
1 files changed, 106 insertions, 47 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
index a2ca34e..60d7a49 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
@@ -23,7 +23,7 @@
*
* Copyright (c) 2006-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
* All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
*/
/* Portions Copyright 2010 Robert Milkowski */
@@ -189,14 +189,14 @@ int
zvol_check_volsize(uint64_t volsize, uint64_t blocksize)
{
if (volsize == 0)
- return (EINVAL);
+ return (SET_ERROR(EINVAL));
if (volsize % blocksize != 0)
- return (EINVAL);
+ return (SET_ERROR(EINVAL));
#ifdef _ILP32
if (volsize - 1 > SPEC_MAXOFFSET_T)
- return (EOVERFLOW);
+ return (SET_ERROR(EOVERFLOW));
#endif
return (0);
}
@@ -207,7 +207,7 @@ zvol_check_volblocksize(uint64_t volblocksize)
if (volblocksize < SPA_MINBLOCKSIZE ||
volblocksize > SPA_MAXBLOCKSIZE ||
!ISP2(volblocksize))
- return (EDOM);
+ return (SET_ERROR(EDOM));
return (0);
}
@@ -283,7 +283,7 @@ zvol_map_block(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
/* Abort immediately if we have encountered gang blocks */
if (BP_IS_GANG(bp))
- return (EFRAGS);
+ return (SET_ERROR(EFRAGS));
/*
* See if the block is at the end of the previous extent.
@@ -422,7 +422,7 @@ zvol_replay_write(zvol_state_t *zv, lr_write_t *lr, boolean_t byteswap)
static int
zvol_replay_err(zvol_state_t *zv, lr_t *lr, boolean_t byteswap)
{
- return (ENOTSUP);
+ return (SET_ERROR(ENOTSUP));
}
/*
@@ -486,7 +486,7 @@ zvol_create_minor(const char *name)
if (zvol_minor_lookup(name) != NULL) {
mutex_exit(&spa_namespace_lock);
- return (EEXIST);
+ return (SET_ERROR(EEXIST));
}
/* lie and say we're read-only */
@@ -501,13 +501,13 @@ zvol_create_minor(const char *name)
if ((minor = zfsdev_minor_alloc()) == 0) {
dmu_objset_disown(os, FTAG);
mutex_exit(&spa_namespace_lock);
- return (ENXIO);
+ return (SET_ERROR(ENXIO));
}
if (ddi_soft_state_zalloc(zfsdev_state, minor) != DDI_SUCCESS) {
dmu_objset_disown(os, FTAG);
mutex_exit(&spa_namespace_lock);
- return (EAGAIN);
+ return (SET_ERROR(EAGAIN));
}
(void) ddi_prop_update_string(minor, zfs_dip, ZVOL_PROP_NAME,
(char *)name);
@@ -519,7 +519,7 @@ zvol_create_minor(const char *name)
ddi_soft_state_free(zfsdev_state, minor);
dmu_objset_disown(os, FTAG);
mutex_exit(&spa_namespace_lock);
- return (EAGAIN);
+ return (SET_ERROR(EAGAIN));
}
(void) snprintf(blkbuf, sizeof (blkbuf), "%u", minor);
@@ -530,7 +530,7 @@ zvol_create_minor(const char *name)
ddi_soft_state_free(zfsdev_state, minor);
dmu_objset_disown(os, FTAG);
mutex_exit(&spa_namespace_lock);
- return (EAGAIN);
+ return (SET_ERROR(EAGAIN));
}
zs = ddi_get_soft_state(zfsdev_state, minor);
@@ -604,7 +604,7 @@ zvol_remove_zv(zvol_state_t *zv)
ASSERT(MUTEX_HELD(&spa_namespace_lock));
if (zv->zv_total_opens != 0)
- return (EBUSY);
+ return (SET_ERROR(EBUSY));
ZFS_LOG(1, "ZVOL %s destroyed.", zv->zv_name);
@@ -631,7 +631,7 @@ zvol_remove_minor(const char *name)
mutex_enter(&spa_namespace_lock);
if ((zv = zvol_minor_lookup(name)) == NULL) {
mutex_exit(&spa_namespace_lock);
- return (ENXIO);
+ return (SET_ERROR(ENXIO));
}
g_topology_lock();
rc = zvol_remove_zv(zv);
@@ -714,7 +714,7 @@ zvol_prealloc(zvol_state_t *zv)
/* Check the space usage before attempting to allocate the space */
dmu_objset_space(os, &refd, &avail, &usedobjs, &availobjs);
if (avail < zv->zv_volsize)
- return (ENOSPC);
+ return (SET_ERROR(ENOSPC));
/* Free old extents if they exist */
zvol_free_extents(zv);
@@ -914,7 +914,7 @@ zvol_open(struct g_provider *pp, int flag, int count)
if (zv == NULL) {
if (locked)
mutex_exit(&spa_namespace_lock);
- return (ENXIO);
+ return (SET_ERROR(ENXIO));
}
if (zv->zv_total_opens == 0)
@@ -925,17 +925,17 @@ zvol_open(struct g_provider *pp, int flag, int count)
return (err);
}
if ((flag & FWRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
- err = EROFS;
+ err = SET_ERROR(EROFS);
goto out;
}
if (zv->zv_flags & ZVOL_EXCL) {
- err = EBUSY;
+ err = SET_ERROR(EBUSY);
goto out;
}
#ifdef FEXCL
if (flag & FEXCL) {
if (zv->zv_total_opens != 0) {
- err = EBUSY;
+ err = SET_ERROR(EBUSY);
goto out;
}
zv->zv_flags |= ZVOL_EXCL;
@@ -973,7 +973,7 @@ zvol_close(struct g_provider *pp, int flag, int count)
if (zv == NULL) {
if (locked)
mutex_exit(&spa_namespace_lock);
- return (ENXIO);
+ return (SET_ERROR(ENXIO));
}
if (zv->zv_flags & ZVOL_EXCL) {
@@ -1182,9 +1182,9 @@ zvol_dumpio_vdev(vdev_t *vd, void *addr, uint64_t offset, uint64_t size,
return (numerrors < vd->vdev_children ? 0 : EIO);
if (doread && !vdev_readable(vd))
- return (EIO);
+ return (SET_ERROR(EIO));
else if (!doread && !vdev_writeable(vd))
- return (EIO);
+ return (SET_ERROR(EIO));
dvd = vd->vdev_tsd;
ASSERT3P(dvd, !=, NULL);
@@ -1193,7 +1193,7 @@ zvol_dumpio_vdev(vdev_t *vd, void *addr, uint64_t offset, uint64_t size,
if (ddi_in_panic() || isdump) {
ASSERT(!doread);
if (doread)
- return (EIO);
+ return (SET_ERROR(EIO));
return (ldi_dump(dvd->vd_lh, addr, lbtodb(offset),
lbtodb(size)));
} else {
@@ -1214,7 +1214,7 @@ zvol_dumpio(zvol_state_t *zv, void *addr, uint64_t offset, uint64_t size,
/* Must be sector aligned, and not stradle a block boundary. */
if (P2PHASE(offset, DEV_BSIZE) || P2PHASE(size, DEV_BSIZE) ||
P2BOUNDARY(offset, size, zv->zv_volblocksize)) {
- return (EINVAL);
+ return (SET_ERROR(EINVAL));
}
ASSERT(size <= zv->zv_volblocksize);
@@ -1226,7 +1226,7 @@ zvol_dumpio(zvol_state_t *zv, void *addr, uint64_t offset, uint64_t size,
}
if (ze == NULL)
- return (EINVAL);
+ return (SET_ERROR(EINVAL));
if (!ddi_in_panic())
spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
@@ -1308,7 +1308,7 @@ zvol_strategy(struct bio *bp)
if (error) {
/* convert checksum errors into IO errors */
if (error == ECKSUM)
- error = EIO;
+ error = SET_ERROR(EIO);
break;
}
off += size;
@@ -1356,10 +1356,10 @@ zvol_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblocks)
zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL)
- return (ENXIO);
+ return (SET_ERROR(ENXIO));
if ((zv->zv_flags & ZVOL_DUMPIFIED) == 0)
- return (EINVAL);
+ return (SET_ERROR(EINVAL));
boff = ldbtob(blkno);
resid = ldbtob(nblocks);
@@ -1391,12 +1391,12 @@ zvol_read(dev_t dev, uio_t *uio, cred_t *cr)
zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL)
- return (ENXIO);
+ return (SET_ERROR(ENXIO));
volsize = zv->zv_volsize;
if (uio->uio_resid > 0 &&
(uio->uio_loffset < 0 || uio->uio_loffset >= volsize))
- return (EIO);
+ return (SET_ERROR(EIO));
if (zv->zv_flags & ZVOL_DUMPIFIED) {
error = physio(zvol_strategy, NULL, dev, B_READ,
@@ -1417,7 +1417,7 @@ zvol_read(dev_t dev, uio_t *uio, cred_t *cr)
if (error) {
/* convert checksum errors into IO errors */
if (error == ECKSUM)
- error = EIO;
+ error = SET_ERROR(EIO);
break;
}
}
@@ -1438,12 +1438,12 @@ zvol_write(dev_t dev, uio_t *uio, cred_t *cr)
zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL)
- return (ENXIO);
+ return (SET_ERROR(ENXIO));
volsize = zv->zv_volsize;
if (uio->uio_resid > 0 &&
(uio->uio_loffset < 0 || uio->uio_loffset >= volsize))
- return (EIO);
+ return (SET_ERROR(EIO));
if (zv->zv_flags & ZVOL_DUMPIFIED) {
error = physio(zvol_strategy, NULL, dev, B_WRITE,
@@ -1495,7 +1495,7 @@ zvol_getefi(void *arg, int flag, uint64_t vs, uint8_t bs)
char *ptr;
if (ddi_copyin(arg, &efi, sizeof (dk_efi_t), flag))
- return (EFAULT);
+ return (SET_ERROR(EFAULT));
ptr = (char *)(uintptr_t)efi.dki_data_64;
length = efi.dki_length;
/*
@@ -1506,7 +1506,7 @@ zvol_getefi(void *arg, int flag, uint64_t vs, uint8_t bs)
* PMBR.
*/
if (efi.dki_lba < 1 || efi.dki_lba > 2 || length <= 0)
- return (EINVAL);
+ return (SET_ERROR(EINVAL));
gpe.efi_gpe_StartingLBA = LE_64(34ULL);
gpe.efi_gpe_EndingLBA = LE_64((vs >> bs) - 1);
@@ -1531,13 +1531,13 @@ zvol_getefi(void *arg, int flag, uint64_t vs, uint8_t bs)
gpt.efi_gpt_HeaderCRC32 = LE_32(~crc);
if (ddi_copyout(&gpt, ptr, MIN(sizeof (gpt), length),
flag))
- return (EFAULT);
+ return (SET_ERROR(EFAULT));
ptr += sizeof (gpt);
length -= sizeof (gpt);
}
if (length > 0 && ddi_copyout(&gpe, ptr, MIN(sizeof (gpe),
length), flag))
- return (EFAULT);
+ return (SET_ERROR(EFAULT));
return (0);
}
@@ -1557,9 +1557,9 @@ zvol_get_volume_params(minor_t minor, uint64_t *blksize,
zv = zfsdev_get_soft_state(minor, ZSST_ZVOL);
if (zv == NULL)
- return (ENXIO);
+ return (SET_ERROR(ENXIO));
if (zv->zv_flags & ZVOL_DUMPIFIED)
- return (ENXIO);
+ return (SET_ERROR(ENXIO));
ASSERT(blksize && max_xfer_len && minor_hdl &&
objset_hdl && zil_hdl && rl_hdl && bonus_hdl);
@@ -1633,7 +1633,7 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
if (zv == NULL) {
mutex_exit(&spa_namespace_lock);
- return (ENXIO);
+ return (SET_ERROR(ENXIO));
}
ASSERT(zv->zv_total_opens > 0);
@@ -1648,7 +1648,7 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
dki.dki_maxtransfer = 1 << (SPA_MAXBLOCKSHIFT - zv->zv_min_bs);
mutex_exit(&spa_namespace_lock);
if (ddi_copyout(&dki, (void *)arg, sizeof (dki), flag))
- error = EFAULT;
+ error = SET_ERROR(EFAULT);
return (error);
case DKIOCGMEDIAINFO:
@@ -1658,7 +1658,7 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
dkm.dki_media_type = DK_UNKNOWN;
mutex_exit(&spa_namespace_lock);
if (ddi_copyout(&dkm, (void *)arg, sizeof (dkm), flag))
- error = EFAULT;
+ error = SET_ERROR(EFAULT);
return (error);
case DKIOCGETEFI:
@@ -1686,7 +1686,7 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
int wce = (zv->zv_flags & ZVOL_WCE) ? 1 : 0;
if (ddi_copyout(&wce, (void *)arg, sizeof (int),
flag))
- error = EFAULT;
+ error = SET_ERROR(EFAULT);
break;
}
case DKIOCSETWCE:
@@ -1694,7 +1694,7 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
int wce;
if (ddi_copyin((void *)arg, &wce, sizeof (int),
flag)) {
- error = EFAULT;
+ error = SET_ERROR(EFAULT);
break;
}
if (wce) {
@@ -1714,7 +1714,7 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
* commands using these (like prtvtoc) expect ENOTSUP
* since we're emulating an EFI label
*/
- error = ENOTSUP;
+ error = SET_ERROR(ENOTSUP);
break;
case DKIOCDUMPINIT:
@@ -1733,8 +1733,67 @@ zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp)
zfs_range_unlock(rl);
break;
+ case DKIOCFREE:
+ {
+ dkioc_free_t df;
+ dmu_tx_t *tx;
+
+ if (ddi_copyin((void *)arg, &df, sizeof (df), flag)) {
+ error = SET_ERROR(EFAULT);
+ break;
+ }
+
+ /*
+ * Apply Postel's Law to length-checking. If they overshoot,
+ * just blank out until the end, if there's a need to blank
+ * out anything.
+ */
+ if (df.df_start >= zv->zv_volsize)
+ break; /* No need to do anything... */
+ if (df.df_start + df.df_length > zv->zv_volsize)
+ df.df_length = DMU_OBJECT_END;
+
+ rl = zfs_range_lock(&zv->zv_znode, df.df_start, df.df_length,
+ RL_WRITER);
+ tx = dmu_tx_create(zv->zv_objset);
+ error = dmu_tx_assign(tx, TXG_WAIT);
+ if (error != 0) {
+ dmu_tx_abort(tx);
+ } else {
+ zvol_log_truncate(zv, tx, df.df_start,
+ df.df_length, B_TRUE);
+ dmu_tx_commit(tx);
+ error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ,
+ df.df_start, df.df_length);
+ }
+
+ zfs_range_unlock(rl);
+
+ if (error == 0) {
+ /*
+ * If the write-cache is disabled or 'sync' property
+ * is set to 'always' then treat this as a synchronous
+ * operation (i.e. commit to zil).
+ */
+ if (!(zv->zv_flags & ZVOL_WCE) ||
+ (zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS))
+ zil_commit(zv->zv_zilog, ZVOL_OBJ);
+
+ /*
+ * If the caller really wants synchronous writes, and
+ * can't wait for them, don't return until the write
+ * is done.
+ */
+ if (df.df_flags & DF_WAIT_SYNC) {
+ txg_wait_synced(
+ dmu_objset_pool(zv->zv_objset), 0);
+ }
+ }
+ break;
+ }
+
default:
- error = ENOTTY;
+ error = SET_ERROR(ENOTTY);
break;
}
@@ -1881,7 +1940,7 @@ zvol_dumpify(zvol_state_t *zv)
objset_t *os = zv->zv_objset;
if (zv->zv_flags & ZVOL_RDONLY)
- return (EROFS);
+ return (SET_ERROR(EROFS));
if (zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ, ZVOL_DUMPSIZE,
8, 1, &dumpsize) != 0 || dumpsize != zv->zv_volsize) {
OpenPOWER on IntegriCloud