diff options
author | mm <mm@FreeBSD.org> | 2013-04-06 10:39:38 +0000 |
---|---|---|
committer | mm <mm@FreeBSD.org> | 2013-04-06 10:39:38 +0000 |
commit | 696d961cbd8bcba286545fef03c51a896b56d229 (patch) | |
tree | 557b6db8b3be2ff65382b43d2ae9edd99d502a44 /sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c | |
parent | f25063da0770fd0a9b4ed6ffdd6687e7de116255 (diff) | |
parent | 70e6431e93f13270d6907ce23de3c7da99803278 (diff) | |
download | FreeBSD-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.c | 153 |
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) { |