1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 22f80ce222SChris Kirby * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23b77b9231SDan McDonald * 24b77b9231SDan McDonald * Portions Copyright 2010 Robert Milkowski 25b77b9231SDan McDonald * 26b77b9231SDan McDonald * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 27*1c9272b8SStephen Blinick * Copyright (c) 2012, 2016 by Delphix. All rights reserved. 28810e43b2SBill Pijewski * Copyright (c) 2013, Joyent, Inc. All rights reserved. 29c3d26abcSMatthew Ahrens * Copyright (c) 2014 Integros [integros.com] 30fa9e4066Sahrens */ 31fa9e4066Sahrens 32fa9e4066Sahrens /* 33fa9e4066Sahrens * ZFS volume emulation driver. 34fa9e4066Sahrens * 35fa9e4066Sahrens * Makes a DMU object look like a volume of arbitrary size, up to 2^64 bytes. 36fa9e4066Sahrens * Volumes are accessed through the symbolic links named: 37fa9e4066Sahrens * 38fa9e4066Sahrens * /dev/zvol/dsk/<pool_name>/<dataset_name> 39fa9e4066Sahrens * /dev/zvol/rdsk/<pool_name>/<dataset_name> 40fa9e4066Sahrens * 41681d9761SEric Taylor * These links are created by the /dev filesystem (sdev_zvolops.c). 42fa9e4066Sahrens * Volumes are persistent through reboot. No user command needs to be 43fa9e4066Sahrens * run before opening and using a device. 44fa9e4066Sahrens */ 45fa9e4066Sahrens 46fa9e4066Sahrens #include <sys/types.h> 47fa9e4066Sahrens #include <sys/param.h> 48fa9e4066Sahrens #include <sys/errno.h> 49fa9e4066Sahrens #include <sys/uio.h> 50fa9e4066Sahrens #include <sys/buf.h> 51fa9e4066Sahrens #include <sys/modctl.h> 52fa9e4066Sahrens #include <sys/open.h> 53fa9e4066Sahrens #include <sys/kmem.h> 54fa9e4066Sahrens #include <sys/conf.h> 55fa9e4066Sahrens #include <sys/cmn_err.h> 56fa9e4066Sahrens #include <sys/stat.h> 57fa9e4066Sahrens #include <sys/zap.h> 58fa9e4066Sahrens #include <sys/spa.h> 59810e43b2SBill Pijewski #include <sys/spa_impl.h> 60fa9e4066Sahrens #include <sys/zio.h> 61e7cbe64fSgw #include <sys/dmu_traverse.h> 62e7cbe64fSgw #include <sys/dnode.h> 63e7cbe64fSgw #include <sys/dsl_dataset.h> 64fa9e4066Sahrens #include <sys/dsl_prop.h> 65fa9e4066Sahrens #include <sys/dkio.h> 66fa9e4066Sahrens #include <sys/efi_partition.h> 67fa9e4066Sahrens #include <sys/byteorder.h> 68fa9e4066Sahrens #include <sys/pathname.h> 69fa9e4066Sahrens #include <sys/ddi.h> 70fa9e4066Sahrens #include <sys/sunddi.h> 71fa9e4066Sahrens #include <sys/crc32.h> 72fa9e4066Sahrens #include <sys/dirent.h> 73fa9e4066Sahrens #include <sys/policy.h> 74fa9e4066Sahrens #include <sys/fs/zfs.h> 75fa9e4066Sahrens #include <sys/zfs_ioctl.h> 76fa9e4066Sahrens #include <sys/mkdev.h> 7722ac5be4Sperrin #include <sys/zil.h> 78c5c6ffa0Smaybee #include <sys/refcount.h> 79c2e6a7d6Sperrin #include <sys/zfs_znode.h> 80c2e6a7d6Sperrin #include <sys/zfs_rlock.h> 81e7cbe64fSgw #include <sys/vdev_disk.h> 82e7cbe64fSgw #include <sys/vdev_impl.h> 83810e43b2SBill Pijewski #include <sys/vdev_raidz.h> 84e7cbe64fSgw #include <sys/zvol.h> 85e7cbe64fSgw #include <sys/dumphdr.h> 861209a471SNeil Perrin #include <sys/zil_impl.h> 8780901aeaSGeorge Wilson #include <sys/dbuf.h> 88810e43b2SBill Pijewski #include <sys/dmu_tx.h> 89810e43b2SBill Pijewski #include <sys/zfeature.h> 90810e43b2SBill Pijewski #include <sys/zio_checksum.h> 91fa9e4066Sahrens 92fa9e4066Sahrens #include "zfs_namecheck.h" 93fa9e4066Sahrens 94c99e4bdcSChris Kirby void *zfsdev_state; 95503ad85cSMatthew Ahrens static char *zvol_tag = "zvol_tag"; 96fa9e4066Sahrens 97e7cbe64fSgw #define ZVOL_DUMPSIZE "dumpsize" 98e7cbe64fSgw 99fa9e4066Sahrens /* 100c99e4bdcSChris Kirby * This lock protects the zfsdev_state structure from being modified 101fa9e4066Sahrens * while it's being used, e.g. an open that comes in before a create 102fa9e4066Sahrens * finishes. It also protects temporary opens of the dataset so that, 103fa9e4066Sahrens * e.g., an open doesn't get a spurious EBUSY. 104fa9e4066Sahrens */ 105c99e4bdcSChris Kirby kmutex_t zfsdev_state_lock; 106fa9e4066Sahrens static uint32_t zvol_minors; 107fa9e4066Sahrens 108e7cbe64fSgw typedef struct zvol_extent { 10988b7b0f2SMatthew Ahrens list_node_t ze_node; 110e7cbe64fSgw dva_t ze_dva; /* dva associated with this extent */ 11188b7b0f2SMatthew Ahrens uint64_t ze_nblks; /* number of blocks in extent */ 112e7cbe64fSgw } zvol_extent_t; 113e7cbe64fSgw 114fa9e4066Sahrens /* 115fa9e4066Sahrens * The in-core state of each volume. 116fa9e4066Sahrens */ 117fa9e4066Sahrens typedef struct zvol_state { 118fa9e4066Sahrens char zv_name[MAXPATHLEN]; /* pool/dd name */ 119fa9e4066Sahrens uint64_t zv_volsize; /* amount of space we advertise */ 12067bd71c6Sperrin uint64_t zv_volblocksize; /* volume block size */ 121fa9e4066Sahrens minor_t zv_minor; /* minor number */ 122fa9e4066Sahrens uint8_t zv_min_bs; /* minimum addressable block shift */ 123701f66c4SEric Taylor uint8_t zv_flags; /* readonly, dumpified, etc. */ 124fa9e4066Sahrens objset_t *zv_objset; /* objset handle */ 125fa9e4066Sahrens uint32_t zv_open_count[OTYPCNT]; /* open counts */ 126fa9e4066Sahrens uint32_t zv_total_opens; /* total open count */ 12722ac5be4Sperrin zilog_t *zv_zilog; /* ZIL handle */ 12888b7b0f2SMatthew Ahrens list_t zv_extents; /* List of extents for dump */ 129c2e6a7d6Sperrin znode_t zv_znode; /* for range locking */ 13094d1a210STim Haley dmu_buf_t *zv_dbuf; /* bonus handle */ 131fa9e4066Sahrens } zvol_state_t; 132fa9e4066Sahrens 133e7cbe64fSgw /* 134e7cbe64fSgw * zvol specific flags 135e7cbe64fSgw */ 136e7cbe64fSgw #define ZVOL_RDONLY 0x1 137e7cbe64fSgw #define ZVOL_DUMPIFIED 0x2 138c7f714e2SEric Taylor #define ZVOL_EXCL 0x4 139701f66c4SEric Taylor #define ZVOL_WCE 0x8 140e7cbe64fSgw 14167bd71c6Sperrin /* 14267bd71c6Sperrin * zvol maximum transfer in one DMU tx. 14367bd71c6Sperrin */ 14467bd71c6Sperrin int zvol_maxphys = DMU_MAX_ACCESS/2; 14567bd71c6Sperrin 146893c83baSGeorge Wilson /* 147893c83baSGeorge Wilson * Toggle unmap functionality. 148893c83baSGeorge Wilson */ 149893c83baSGeorge Wilson boolean_t zvol_unmap_enabled = B_TRUE; 150893c83baSGeorge Wilson 151*1c9272b8SStephen Blinick /* 152*1c9272b8SStephen Blinick * If true, unmaps requested as synchronous are executed synchronously, 153*1c9272b8SStephen Blinick * otherwise all unmaps are asynchronous. 154*1c9272b8SStephen Blinick */ 155*1c9272b8SStephen Blinick boolean_t zvol_unmap_sync_enabled = B_FALSE; 156*1c9272b8SStephen Blinick 15792241e0bSTom Erickson extern int zfs_set_prop_nvlist(const char *, zprop_source_t, 1584445fffbSMatthew Ahrens nvlist_t *, nvlist_t *); 159681d9761SEric Taylor static int zvol_remove_zv(zvol_state_t *); 160feb08c6bSbillm static int zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio); 161e7cbe64fSgw static int zvol_dumpify(zvol_state_t *zv); 162e7cbe64fSgw static int zvol_dump_fini(zvol_state_t *zv); 163e7cbe64fSgw static int zvol_dump_init(zvol_state_t *zv, boolean_t resize); 16467bd71c6Sperrin 165fa9e4066Sahrens static void 166c61ea566SGeorge Wilson zvol_size_changed(zvol_state_t *zv, uint64_t volsize) 167fa9e4066Sahrens { 168c61ea566SGeorge Wilson dev_t dev = makedevice(ddi_driver_major(zfs_dip), zv->zv_minor); 169fa9e4066Sahrens 170c61ea566SGeorge Wilson zv->zv_volsize = volsize; 171fa9e4066Sahrens VERIFY(ddi_prop_update_int64(dev, zfs_dip, 172681d9761SEric Taylor "Size", volsize) == DDI_SUCCESS); 173fa9e4066Sahrens VERIFY(ddi_prop_update_int64(dev, zfs_dip, 174681d9761SEric Taylor "Nblocks", lbtodb(volsize)) == DDI_SUCCESS); 175e7cbe64fSgw 176e7cbe64fSgw /* Notify specfs to invalidate the cached size */ 177e7cbe64fSgw spec_size_invalidate(dev, VBLK); 178e7cbe64fSgw spec_size_invalidate(dev, VCHR); 179fa9e4066Sahrens } 180fa9e4066Sahrens 181fa9e4066Sahrens int 182e9dbad6fSeschrock zvol_check_volsize(uint64_t volsize, uint64_t blocksize) 183fa9e4066Sahrens { 184e9dbad6fSeschrock if (volsize == 0) 185be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 186fa9e4066Sahrens 187e9dbad6fSeschrock if (volsize % blocksize != 0) 188be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1895c5460e9Seschrock 190fa9e4066Sahrens #ifdef _ILP32 191e9dbad6fSeschrock if (volsize - 1 > SPEC_MAXOFFSET_T) 192be6fd75aSMatthew Ahrens return (SET_ERROR(EOVERFLOW)); 193fa9e4066Sahrens #endif 194fa9e4066Sahrens return (0); 195fa9e4066Sahrens } 196fa9e4066Sahrens 197fa9e4066Sahrens int 198e9dbad6fSeschrock zvol_check_volblocksize(uint64_t volblocksize) 199fa9e4066Sahrens { 200e9dbad6fSeschrock if (volblocksize < SPA_MINBLOCKSIZE || 201b5152584SMatthew Ahrens volblocksize > SPA_OLD_MAXBLOCKSIZE || 202e9dbad6fSeschrock !ISP2(volblocksize)) 203be6fd75aSMatthew Ahrens return (SET_ERROR(EDOM)); 204fa9e4066Sahrens 205fa9e4066Sahrens return (0); 206fa9e4066Sahrens } 207fa9e4066Sahrens 208fa9e4066Sahrens int 209a2eea2e1Sahrens zvol_get_stats(objset_t *os, nvlist_t *nv) 210fa9e4066Sahrens { 211fa9e4066Sahrens int error; 212fa9e4066Sahrens dmu_object_info_t doi; 213a2eea2e1Sahrens uint64_t val; 214fa9e4066Sahrens 215a2eea2e1Sahrens error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &val); 216fa9e4066Sahrens if (error) 217fa9e4066Sahrens return (error); 218fa9e4066Sahrens 219a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VOLSIZE, val); 220a2eea2e1Sahrens 221fa9e4066Sahrens error = dmu_object_info(os, ZVOL_OBJ, &doi); 222fa9e4066Sahrens 223a2eea2e1Sahrens if (error == 0) { 224a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VOLBLOCKSIZE, 225a2eea2e1Sahrens doi.doi_data_block_size); 226a2eea2e1Sahrens } 227fa9e4066Sahrens 228fa9e4066Sahrens return (error); 229fa9e4066Sahrens } 230fa9e4066Sahrens 231fa9e4066Sahrens static zvol_state_t * 232e9dbad6fSeschrock zvol_minor_lookup(const char *name) 233fa9e4066Sahrens { 234fa9e4066Sahrens minor_t minor; 235fa9e4066Sahrens zvol_state_t *zv; 236fa9e4066Sahrens 237c99e4bdcSChris Kirby ASSERT(MUTEX_HELD(&zfsdev_state_lock)); 238fa9e4066Sahrens 239c99e4bdcSChris Kirby for (minor = 1; minor <= ZFSDEV_MAX_MINOR; minor++) { 240c99e4bdcSChris Kirby zv = zfsdev_get_soft_state(minor, ZSST_ZVOL); 241fa9e4066Sahrens if (zv == NULL) 242fa9e4066Sahrens continue; 243fa9e4066Sahrens if (strcmp(zv->zv_name, name) == 0) 244f80ce222SChris Kirby return (zv); 245fa9e4066Sahrens } 246fa9e4066Sahrens 247f80ce222SChris Kirby return (NULL); 248fa9e4066Sahrens } 249fa9e4066Sahrens 250e7cbe64fSgw /* extent mapping arg */ 251e7cbe64fSgw struct maparg { 25288b7b0f2SMatthew Ahrens zvol_state_t *ma_zv; 25388b7b0f2SMatthew Ahrens uint64_t ma_blks; 254e7cbe64fSgw }; 255e7cbe64fSgw 256e7cbe64fSgw /*ARGSUSED*/ 257e7cbe64fSgw static int 2581b912ec7SGeorge Wilson zvol_map_block(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 2597802d7bfSMatthew Ahrens const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg) 260e7cbe64fSgw { 26188b7b0f2SMatthew Ahrens struct maparg *ma = arg; 26288b7b0f2SMatthew Ahrens zvol_extent_t *ze; 26388b7b0f2SMatthew Ahrens int bs = ma->ma_zv->zv_volblocksize; 264e7cbe64fSgw 265a2cdcdd2SPaul Dagnelie if (bp == NULL || BP_IS_HOLE(bp) || 26643466aaeSMax Grossman zb->zb_object != ZVOL_OBJ || zb->zb_level != 0) 26788b7b0f2SMatthew Ahrens return (0); 268e7cbe64fSgw 2695d7b4d43SMatthew Ahrens VERIFY(!BP_IS_EMBEDDED(bp)); 2705d7b4d43SMatthew Ahrens 27188b7b0f2SMatthew Ahrens VERIFY3U(ma->ma_blks, ==, zb->zb_blkid); 27288b7b0f2SMatthew Ahrens ma->ma_blks++; 273e7cbe64fSgw 27488b7b0f2SMatthew Ahrens /* Abort immediately if we have encountered gang blocks */ 27588b7b0f2SMatthew Ahrens if (BP_IS_GANG(bp)) 276be6fd75aSMatthew Ahrens return (SET_ERROR(EFRAGS)); 277e7cbe64fSgw 27888b7b0f2SMatthew Ahrens /* 27988b7b0f2SMatthew Ahrens * See if the block is at the end of the previous extent. 28088b7b0f2SMatthew Ahrens */ 28188b7b0f2SMatthew Ahrens ze = list_tail(&ma->ma_zv->zv_extents); 28288b7b0f2SMatthew Ahrens if (ze && 28388b7b0f2SMatthew Ahrens DVA_GET_VDEV(BP_IDENTITY(bp)) == DVA_GET_VDEV(&ze->ze_dva) && 28488b7b0f2SMatthew Ahrens DVA_GET_OFFSET(BP_IDENTITY(bp)) == 28588b7b0f2SMatthew Ahrens DVA_GET_OFFSET(&ze->ze_dva) + ze->ze_nblks * bs) { 28688b7b0f2SMatthew Ahrens ze->ze_nblks++; 28788b7b0f2SMatthew Ahrens return (0); 288e7cbe64fSgw } 289e7cbe64fSgw 29088b7b0f2SMatthew Ahrens dprintf_bp(bp, "%s", "next blkptr:"); 291e7cbe64fSgw 29288b7b0f2SMatthew Ahrens /* start a new extent */ 29388b7b0f2SMatthew Ahrens ze = kmem_zalloc(sizeof (zvol_extent_t), KM_SLEEP); 29488b7b0f2SMatthew Ahrens ze->ze_dva = bp->blk_dva[0]; /* structure assignment */ 29588b7b0f2SMatthew Ahrens ze->ze_nblks = 1; 29688b7b0f2SMatthew Ahrens list_insert_tail(&ma->ma_zv->zv_extents, ze); 29788b7b0f2SMatthew Ahrens return (0); 29888b7b0f2SMatthew Ahrens } 299e7cbe64fSgw 30088b7b0f2SMatthew Ahrens static void 30188b7b0f2SMatthew Ahrens zvol_free_extents(zvol_state_t *zv) 30288b7b0f2SMatthew Ahrens { 30388b7b0f2SMatthew Ahrens zvol_extent_t *ze; 304e7cbe64fSgw 30588b7b0f2SMatthew Ahrens while (ze = list_head(&zv->zv_extents)) { 30688b7b0f2SMatthew Ahrens list_remove(&zv->zv_extents, ze); 30788b7b0f2SMatthew Ahrens kmem_free(ze, sizeof (zvol_extent_t)); 308e7cbe64fSgw } 30988b7b0f2SMatthew Ahrens } 310e7cbe64fSgw 31188b7b0f2SMatthew Ahrens static int 31288b7b0f2SMatthew Ahrens zvol_get_lbas(zvol_state_t *zv) 31388b7b0f2SMatthew Ahrens { 3143adc9019SEric Taylor objset_t *os = zv->zv_objset; 31588b7b0f2SMatthew Ahrens struct maparg ma; 31688b7b0f2SMatthew Ahrens int err; 31788b7b0f2SMatthew Ahrens 31888b7b0f2SMatthew Ahrens ma.ma_zv = zv; 31988b7b0f2SMatthew Ahrens ma.ma_blks = 0; 32088b7b0f2SMatthew Ahrens zvol_free_extents(zv); 32188b7b0f2SMatthew Ahrens 3223adc9019SEric Taylor /* commit any in-flight changes before traversing the dataset */ 3233adc9019SEric Taylor txg_wait_synced(dmu_objset_pool(os), 0); 3243adc9019SEric Taylor err = traverse_dataset(dmu_objset_ds(os), 0, 32588b7b0f2SMatthew Ahrens TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA, zvol_map_block, &ma); 32688b7b0f2SMatthew Ahrens if (err || ma.ma_blks != (zv->zv_volsize / zv->zv_volblocksize)) { 32788b7b0f2SMatthew Ahrens zvol_free_extents(zv); 32888b7b0f2SMatthew Ahrens return (err ? err : EIO); 329e7cbe64fSgw } 33088b7b0f2SMatthew Ahrens 331e7cbe64fSgw return (0); 332e7cbe64fSgw } 333e7cbe64fSgw 334ecd6cf80Smarks /* ARGSUSED */ 335fa9e4066Sahrens void 336ecd6cf80Smarks zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx) 337fa9e4066Sahrens { 338da6c28aaSamw zfs_creat_t *zct = arg; 339da6c28aaSamw nvlist_t *nvprops = zct->zct_props; 340fa9e4066Sahrens int error; 341e9dbad6fSeschrock uint64_t volblocksize, volsize; 342fa9e4066Sahrens 343ecd6cf80Smarks VERIFY(nvlist_lookup_uint64(nvprops, 344e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE), &volsize) == 0); 345ecd6cf80Smarks if (nvlist_lookup_uint64(nvprops, 346e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &volblocksize) != 0) 347e9dbad6fSeschrock volblocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE); 348e9dbad6fSeschrock 349e9dbad6fSeschrock /* 350e7cbe64fSgw * These properties must be removed from the list so the generic 351e9dbad6fSeschrock * property setting step won't apply to them. 352e9dbad6fSeschrock */ 353ecd6cf80Smarks VERIFY(nvlist_remove_all(nvprops, 354e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLSIZE)) == 0); 355ecd6cf80Smarks (void) nvlist_remove_all(nvprops, 356e9dbad6fSeschrock zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE)); 357e9dbad6fSeschrock 358e9dbad6fSeschrock error = dmu_object_claim(os, ZVOL_OBJ, DMU_OT_ZVOL, volblocksize, 359fa9e4066Sahrens DMU_OT_NONE, 0, tx); 360fa9e4066Sahrens ASSERT(error == 0); 361fa9e4066Sahrens 362fa9e4066Sahrens error = zap_create_claim(os, ZVOL_ZAP_OBJ, DMU_OT_ZVOL_PROP, 363fa9e4066Sahrens DMU_OT_NONE, 0, tx); 364fa9e4066Sahrens ASSERT(error == 0); 365fa9e4066Sahrens 366e9dbad6fSeschrock error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize, tx); 367fa9e4066Sahrens ASSERT(error == 0); 368fa9e4066Sahrens } 369fa9e4066Sahrens 370b77b9231SDan McDonald /* 371b77b9231SDan McDonald * Replay a TX_TRUNCATE ZIL transaction if asked. TX_TRUNCATE is how we 372b77b9231SDan McDonald * implement DKIOCFREE/free-long-range. 373b77b9231SDan McDonald */ 374b77b9231SDan McDonald static int 375b77b9231SDan McDonald zvol_replay_truncate(zvol_state_t *zv, lr_truncate_t *lr, boolean_t byteswap) 376b77b9231SDan McDonald { 377b77b9231SDan McDonald uint64_t offset, length; 378b77b9231SDan McDonald 379b77b9231SDan McDonald if (byteswap) 380b77b9231SDan McDonald byteswap_uint64_array(lr, sizeof (*lr)); 381b77b9231SDan McDonald 382b77b9231SDan McDonald offset = lr->lr_offset; 383b77b9231SDan McDonald length = lr->lr_length; 384b77b9231SDan McDonald 385b77b9231SDan McDonald return (dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, offset, length)); 386b77b9231SDan McDonald } 387b77b9231SDan McDonald 38822ac5be4Sperrin /* 38922ac5be4Sperrin * Replay a TX_WRITE ZIL transaction that didn't get committed 39022ac5be4Sperrin * after a system failure 39122ac5be4Sperrin */ 39222ac5be4Sperrin static int 39322ac5be4Sperrin zvol_replay_write(zvol_state_t *zv, lr_write_t *lr, boolean_t byteswap) 39422ac5be4Sperrin { 39522ac5be4Sperrin objset_t *os = zv->zv_objset; 39622ac5be4Sperrin char *data = (char *)(lr + 1); /* data follows lr_write_t */ 397b24ab676SJeff Bonwick uint64_t offset, length; 39822ac5be4Sperrin dmu_tx_t *tx; 39922ac5be4Sperrin int error; 40022ac5be4Sperrin 40122ac5be4Sperrin if (byteswap) 40222ac5be4Sperrin byteswap_uint64_array(lr, sizeof (*lr)); 40322ac5be4Sperrin 404b24ab676SJeff Bonwick offset = lr->lr_offset; 405b24ab676SJeff Bonwick length = lr->lr_length; 406b24ab676SJeff Bonwick 407b24ab676SJeff Bonwick /* If it's a dmu_sync() block, write the whole block */ 408b24ab676SJeff Bonwick if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) { 409b24ab676SJeff Bonwick uint64_t blocksize = BP_GET_LSIZE(&lr->lr_blkptr); 410b24ab676SJeff Bonwick if (length < blocksize) { 411b24ab676SJeff Bonwick offset -= offset % blocksize; 412b24ab676SJeff Bonwick length = blocksize; 413b24ab676SJeff Bonwick } 414b24ab676SJeff Bonwick } 415975c32a0SNeil Perrin 41622ac5be4Sperrin tx = dmu_tx_create(os); 417b24ab676SJeff Bonwick dmu_tx_hold_write(tx, ZVOL_OBJ, offset, length); 4181209a471SNeil Perrin error = dmu_tx_assign(tx, TXG_WAIT); 41922ac5be4Sperrin if (error) { 42022ac5be4Sperrin dmu_tx_abort(tx); 42122ac5be4Sperrin } else { 422b24ab676SJeff Bonwick dmu_write(os, ZVOL_OBJ, offset, length, data, tx); 42322ac5be4Sperrin dmu_tx_commit(tx); 42422ac5be4Sperrin } 42522ac5be4Sperrin 42622ac5be4Sperrin return (error); 42722ac5be4Sperrin } 42822ac5be4Sperrin 42922ac5be4Sperrin /* ARGSUSED */ 43022ac5be4Sperrin static int 43122ac5be4Sperrin zvol_replay_err(zvol_state_t *zv, lr_t *lr, boolean_t byteswap) 43222ac5be4Sperrin { 433be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 43422ac5be4Sperrin } 43522ac5be4Sperrin 43622ac5be4Sperrin /* 43722ac5be4Sperrin * Callback vectors for replaying records. 438b77b9231SDan McDonald * Only TX_WRITE and TX_TRUNCATE are needed for zvol. 43922ac5be4Sperrin */ 44022ac5be4Sperrin zil_replay_func_t *zvol_replay_vector[TX_MAX_TYPE] = { 44122ac5be4Sperrin zvol_replay_err, /* 0 no such transaction type */ 44222ac5be4Sperrin zvol_replay_err, /* TX_CREATE */ 44322ac5be4Sperrin zvol_replay_err, /* TX_MKDIR */ 44422ac5be4Sperrin zvol_replay_err, /* TX_MKXATTR */ 44522ac5be4Sperrin zvol_replay_err, /* TX_SYMLINK */ 44622ac5be4Sperrin zvol_replay_err, /* TX_REMOVE */ 44722ac5be4Sperrin zvol_replay_err, /* TX_RMDIR */ 44822ac5be4Sperrin zvol_replay_err, /* TX_LINK */ 44922ac5be4Sperrin zvol_replay_err, /* TX_RENAME */ 45022ac5be4Sperrin zvol_replay_write, /* TX_WRITE */ 451b77b9231SDan McDonald zvol_replay_truncate, /* TX_TRUNCATE */ 45222ac5be4Sperrin zvol_replay_err, /* TX_SETATTR */ 45322ac5be4Sperrin zvol_replay_err, /* TX_ACL */ 454975c32a0SNeil Perrin zvol_replay_err, /* TX_CREATE_ACL */ 455975c32a0SNeil Perrin zvol_replay_err, /* TX_CREATE_ATTR */ 456975c32a0SNeil Perrin zvol_replay_err, /* TX_CREATE_ACL_ATTR */ 457975c32a0SNeil Perrin zvol_replay_err, /* TX_MKDIR_ACL */ 458975c32a0SNeil Perrin zvol_replay_err, /* TX_MKDIR_ATTR */ 459975c32a0SNeil Perrin zvol_replay_err, /* TX_MKDIR_ACL_ATTR */ 460975c32a0SNeil Perrin zvol_replay_err, /* TX_WRITE2 */ 46122ac5be4Sperrin }; 46222ac5be4Sperrin 463681d9761SEric Taylor int 464681d9761SEric Taylor zvol_name2minor(const char *name, minor_t *minor) 465681d9761SEric Taylor { 466681d9761SEric Taylor zvol_state_t *zv; 467681d9761SEric Taylor 468c99e4bdcSChris Kirby mutex_enter(&zfsdev_state_lock); 469681d9761SEric Taylor zv = zvol_minor_lookup(name); 470681d9761SEric Taylor if (minor && zv) 471681d9761SEric Taylor *minor = zv->zv_minor; 472c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 473681d9761SEric Taylor return (zv ? 0 : -1); 474681d9761SEric Taylor } 475681d9761SEric Taylor 476e7cbe64fSgw /* 477e7cbe64fSgw * Create a minor node (plus a whole lot more) for the specified volume. 478fa9e4066Sahrens */ 479fa9e4066Sahrens int 480681d9761SEric Taylor zvol_create_minor(const char *name) 481fa9e4066Sahrens { 482c99e4bdcSChris Kirby zfs_soft_state_t *zs; 483fa9e4066Sahrens zvol_state_t *zv; 484fa9e4066Sahrens objset_t *os; 48567bd71c6Sperrin dmu_object_info_t doi; 486fa9e4066Sahrens minor_t minor = 0; 487fa9e4066Sahrens char chrbuf[30], blkbuf[30]; 488fa9e4066Sahrens int error; 489fa9e4066Sahrens 490c99e4bdcSChris Kirby mutex_enter(&zfsdev_state_lock); 491fa9e4066Sahrens 4921195e687SMark J Musante if (zvol_minor_lookup(name) != NULL) { 493c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 494be6fd75aSMatthew Ahrens return (SET_ERROR(EEXIST)); 495fa9e4066Sahrens } 496fa9e4066Sahrens 497503ad85cSMatthew Ahrens /* lie and say we're read-only */ 4986e0cbcaaSMatthew Ahrens error = dmu_objset_own(name, DMU_OST_ZVOL, B_TRUE, FTAG, &os); 499fa9e4066Sahrens 500fa9e4066Sahrens if (error) { 501c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 502fa9e4066Sahrens return (error); 503fa9e4066Sahrens } 504fa9e4066Sahrens 505c99e4bdcSChris Kirby if ((minor = zfsdev_minor_alloc()) == 0) { 5066e0cbcaaSMatthew Ahrens dmu_objset_disown(os, FTAG); 507c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 508be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 509fa9e4066Sahrens } 510fa9e4066Sahrens 511c99e4bdcSChris Kirby if (ddi_soft_state_zalloc(zfsdev_state, minor) != DDI_SUCCESS) { 5126e0cbcaaSMatthew Ahrens dmu_objset_disown(os, FTAG); 513c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 514be6fd75aSMatthew Ahrens return (SET_ERROR(EAGAIN)); 515fa9e4066Sahrens } 516e9dbad6fSeschrock (void) ddi_prop_update_string(minor, zfs_dip, ZVOL_PROP_NAME, 517e9dbad6fSeschrock (char *)name); 518fa9e4066Sahrens 519681d9761SEric Taylor (void) snprintf(chrbuf, sizeof (chrbuf), "%u,raw", minor); 520fa9e4066Sahrens 521fa9e4066Sahrens if (ddi_create_minor_node(zfs_dip, chrbuf, S_IFCHR, 522fa9e4066Sahrens minor, DDI_PSEUDO, 0) == DDI_FAILURE) { 523c99e4bdcSChris Kirby ddi_soft_state_free(zfsdev_state, minor); 5246e0cbcaaSMatthew Ahrens dmu_objset_disown(os, FTAG); 525c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 526be6fd75aSMatthew Ahrens return (SET_ERROR(EAGAIN)); 527fa9e4066Sahrens } 528fa9e4066Sahrens 529681d9761SEric Taylor (void) snprintf(blkbuf, sizeof (blkbuf), "%u", minor); 530fa9e4066Sahrens 531fa9e4066Sahrens if (ddi_create_minor_node(zfs_dip, blkbuf, S_IFBLK, 532fa9e4066Sahrens minor, DDI_PSEUDO, 0) == DDI_FAILURE) { 533fa9e4066Sahrens ddi_remove_minor_node(zfs_dip, chrbuf); 534c99e4bdcSChris Kirby ddi_soft_state_free(zfsdev_state, minor); 5356e0cbcaaSMatthew Ahrens dmu_objset_disown(os, FTAG); 536c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 537be6fd75aSMatthew Ahrens return (SET_ERROR(EAGAIN)); 538fa9e4066Sahrens } 539fa9e4066Sahrens 540c99e4bdcSChris Kirby zs = ddi_get_soft_state(zfsdev_state, minor); 541c99e4bdcSChris Kirby zs->zss_type = ZSST_ZVOL; 542c99e4bdcSChris Kirby zv = zs->zss_data = kmem_zalloc(sizeof (zvol_state_t), KM_SLEEP); 543681d9761SEric Taylor (void) strlcpy(zv->zv_name, name, MAXPATHLEN); 544fa9e4066Sahrens zv->zv_min_bs = DEV_BSHIFT; 545fa9e4066Sahrens zv->zv_minor = minor; 546fa9e4066Sahrens zv->zv_objset = os; 547f9af39baSGeorge Wilson if (dmu_objset_is_snapshot(os) || !spa_writeable(dmu_objset_spa(os))) 548681d9761SEric Taylor zv->zv_flags |= ZVOL_RDONLY; 549c2e6a7d6Sperrin mutex_init(&zv->zv_znode.z_range_lock, NULL, MUTEX_DEFAULT, NULL); 550c2e6a7d6Sperrin avl_create(&zv->zv_znode.z_range_avl, zfs_range_compare, 551c2e6a7d6Sperrin sizeof (rl_t), offsetof(rl_t, r_node)); 55288b7b0f2SMatthew Ahrens list_create(&zv->zv_extents, sizeof (zvol_extent_t), 55388b7b0f2SMatthew Ahrens offsetof(zvol_extent_t, ze_node)); 55467bd71c6Sperrin /* get and cache the blocksize */ 55567bd71c6Sperrin error = dmu_object_info(os, ZVOL_OBJ, &doi); 55667bd71c6Sperrin ASSERT(error == 0); 55767bd71c6Sperrin zv->zv_volblocksize = doi.doi_data_block_size; 55822ac5be4Sperrin 559f9af39baSGeorge Wilson if (spa_writeable(dmu_objset_spa(os))) { 560f9af39baSGeorge Wilson if (zil_replay_disable) 561f9af39baSGeorge Wilson zil_destroy(dmu_objset_zil(os), B_FALSE); 562f9af39baSGeorge Wilson else 563f9af39baSGeorge Wilson zil_replay(os, zv, zvol_replay_vector); 564f9af39baSGeorge Wilson } 5656e0cbcaaSMatthew Ahrens dmu_objset_disown(os, FTAG); 566681d9761SEric Taylor zv->zv_objset = NULL; 567fa9e4066Sahrens 568fa9e4066Sahrens zvol_minors++; 569fa9e4066Sahrens 570c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 571fa9e4066Sahrens 572fa9e4066Sahrens return (0); 573fa9e4066Sahrens } 574fa9e4066Sahrens 575fa9e4066Sahrens /* 576fa9e4066Sahrens * Remove minor node for the specified volume. 577fa9e4066Sahrens */ 578681d9761SEric Taylor static int 579681d9761SEric Taylor zvol_remove_zv(zvol_state_t *zv) 580681d9761SEric Taylor { 581681d9761SEric Taylor char nmbuf[20]; 582c99e4bdcSChris Kirby minor_t minor = zv->zv_minor; 583681d9761SEric Taylor 584c99e4bdcSChris Kirby ASSERT(MUTEX_HELD(&zfsdev_state_lock)); 585681d9761SEric Taylor if (zv->zv_total_opens != 0) 586be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 587681d9761SEric Taylor 588c99e4bdcSChris Kirby (void) snprintf(nmbuf, sizeof (nmbuf), "%u,raw", minor); 589681d9761SEric Taylor ddi_remove_minor_node(zfs_dip, nmbuf); 590681d9761SEric Taylor 591c99e4bdcSChris Kirby (void) snprintf(nmbuf, sizeof (nmbuf), "%u", minor); 592681d9761SEric Taylor ddi_remove_minor_node(zfs_dip, nmbuf); 593681d9761SEric Taylor 594681d9761SEric Taylor avl_destroy(&zv->zv_znode.z_range_avl); 595681d9761SEric Taylor mutex_destroy(&zv->zv_znode.z_range_lock); 596681d9761SEric Taylor 597c99e4bdcSChris Kirby kmem_free(zv, sizeof (zvol_state_t)); 598c99e4bdcSChris Kirby 599c99e4bdcSChris Kirby ddi_soft_state_free(zfsdev_state, minor); 600681d9761SEric Taylor 601681d9761SEric Taylor zvol_minors--; 602681d9761SEric Taylor return (0); 603681d9761SEric Taylor } 604681d9761SEric Taylor 605fa9e4066Sahrens int 606e9dbad6fSeschrock zvol_remove_minor(const char *name) 607fa9e4066Sahrens { 608fa9e4066Sahrens zvol_state_t *zv; 609681d9761SEric Taylor int rc; 610fa9e4066Sahrens 611c99e4bdcSChris Kirby mutex_enter(&zfsdev_state_lock); 612e9dbad6fSeschrock if ((zv = zvol_minor_lookup(name)) == NULL) { 613c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 614be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 615fa9e4066Sahrens } 616681d9761SEric Taylor rc = zvol_remove_zv(zv); 617c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 618681d9761SEric Taylor return (rc); 619681d9761SEric Taylor } 620fa9e4066Sahrens 621681d9761SEric Taylor int 622681d9761SEric Taylor zvol_first_open(zvol_state_t *zv) 623681d9761SEric Taylor { 624681d9761SEric Taylor objset_t *os; 625681d9761SEric Taylor uint64_t volsize; 626681d9761SEric Taylor int error; 627681d9761SEric Taylor uint64_t readonly; 628fa9e4066Sahrens 629681d9761SEric Taylor /* lie and say we're read-only */ 630681d9761SEric Taylor error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, B_TRUE, 631681d9761SEric Taylor zvol_tag, &os); 632681d9761SEric Taylor if (error) 633681d9761SEric Taylor return (error); 634fa9e4066Sahrens 635c61ea566SGeorge Wilson zv->zv_objset = os; 636681d9761SEric Taylor error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize); 637681d9761SEric Taylor if (error) { 638681d9761SEric Taylor ASSERT(error == 0); 639681d9761SEric Taylor dmu_objset_disown(os, zvol_tag); 640681d9761SEric Taylor return (error); 641681d9761SEric Taylor } 642c61ea566SGeorge Wilson 64394d1a210STim Haley error = dmu_bonus_hold(os, ZVOL_OBJ, zvol_tag, &zv->zv_dbuf); 64494d1a210STim Haley if (error) { 64594d1a210STim Haley dmu_objset_disown(os, zvol_tag); 64694d1a210STim Haley return (error); 64794d1a210STim Haley } 648c61ea566SGeorge Wilson 649c61ea566SGeorge Wilson zvol_size_changed(zv, volsize); 650681d9761SEric Taylor zv->zv_zilog = zil_open(os, zvol_get_data); 651fa9e4066Sahrens 652681d9761SEric Taylor VERIFY(dsl_prop_get_integer(zv->zv_name, "readonly", &readonly, 653681d9761SEric Taylor NULL) == 0); 654f9af39baSGeorge Wilson if (readonly || dmu_objset_is_snapshot(os) || 655f9af39baSGeorge Wilson !spa_writeable(dmu_objset_spa(os))) 656681d9761SEric Taylor zv->zv_flags |= ZVOL_RDONLY; 657681d9761SEric Taylor else 658681d9761SEric Taylor zv->zv_flags &= ~ZVOL_RDONLY; 659681d9761SEric Taylor return (error); 660681d9761SEric Taylor } 661fa9e4066Sahrens 662681d9761SEric Taylor void 663681d9761SEric Taylor zvol_last_close(zvol_state_t *zv) 664681d9761SEric Taylor { 66522ac5be4Sperrin zil_close(zv->zv_zilog); 66622ac5be4Sperrin zv->zv_zilog = NULL; 6672e2c1355SMatthew Ahrens 66894d1a210STim Haley dmu_buf_rele(zv->zv_dbuf, zvol_tag); 66994d1a210STim Haley zv->zv_dbuf = NULL; 6702e2c1355SMatthew Ahrens 6712e2c1355SMatthew Ahrens /* 6722e2c1355SMatthew Ahrens * Evict cached data 6732e2c1355SMatthew Ahrens */ 6742e2c1355SMatthew Ahrens if (dsl_dataset_is_dirty(dmu_objset_ds(zv->zv_objset)) && 6752e2c1355SMatthew Ahrens !(zv->zv_flags & ZVOL_RDONLY)) 6762e2c1355SMatthew Ahrens txg_wait_synced(dmu_objset_pool(zv->zv_objset), 0); 6773b2aab18SMatthew Ahrens dmu_objset_evict_dbufs(zv->zv_objset); 6782e2c1355SMatthew Ahrens 679503ad85cSMatthew Ahrens dmu_objset_disown(zv->zv_objset, zvol_tag); 680fa9e4066Sahrens zv->zv_objset = NULL; 681fa9e4066Sahrens } 682fa9e4066Sahrens 683e7cbe64fSgw int 684e7cbe64fSgw zvol_prealloc(zvol_state_t *zv) 685e7cbe64fSgw { 686e7cbe64fSgw objset_t *os = zv->zv_objset; 687e7cbe64fSgw dmu_tx_t *tx; 688e7cbe64fSgw uint64_t refd, avail, usedobjs, availobjs; 689e7cbe64fSgw uint64_t resid = zv->zv_volsize; 690e7cbe64fSgw uint64_t off = 0; 691e7cbe64fSgw 692e7cbe64fSgw /* Check the space usage before attempting to allocate the space */ 693e7cbe64fSgw dmu_objset_space(os, &refd, &avail, &usedobjs, &availobjs); 694e7cbe64fSgw if (avail < zv->zv_volsize) 695be6fd75aSMatthew Ahrens return (SET_ERROR(ENOSPC)); 696e7cbe64fSgw 697e7cbe64fSgw /* Free old extents if they exist */ 698e7cbe64fSgw zvol_free_extents(zv); 699e7cbe64fSgw 700e7cbe64fSgw while (resid != 0) { 701e7cbe64fSgw int error; 702b5152584SMatthew Ahrens uint64_t bytes = MIN(resid, SPA_OLD_MAXBLOCKSIZE); 703e7cbe64fSgw 704e7cbe64fSgw tx = dmu_tx_create(os); 705e7cbe64fSgw dmu_tx_hold_write(tx, ZVOL_OBJ, off, bytes); 706e7cbe64fSgw error = dmu_tx_assign(tx, TXG_WAIT); 707e7cbe64fSgw if (error) { 708e7cbe64fSgw dmu_tx_abort(tx); 709cdb0ab79Smaybee (void) dmu_free_long_range(os, ZVOL_OBJ, 0, off); 710e7cbe64fSgw return (error); 711e7cbe64fSgw } 71282c9918fSTim Haley dmu_prealloc(os, ZVOL_OBJ, off, bytes, tx); 713e7cbe64fSgw dmu_tx_commit(tx); 714e7cbe64fSgw off += bytes; 715e7cbe64fSgw resid -= bytes; 716e7cbe64fSgw } 717e7cbe64fSgw txg_wait_synced(dmu_objset_pool(os), 0); 718e7cbe64fSgw 719e7cbe64fSgw return (0); 720e7cbe64fSgw } 721e7cbe64fSgw 7223b2aab18SMatthew Ahrens static int 723681d9761SEric Taylor zvol_update_volsize(objset_t *os, uint64_t volsize) 724e7cbe64fSgw { 725e7cbe64fSgw dmu_tx_t *tx; 726e7cbe64fSgw int error; 727e7cbe64fSgw 728c99e4bdcSChris Kirby ASSERT(MUTEX_HELD(&zfsdev_state_lock)); 729e7cbe64fSgw 730681d9761SEric Taylor tx = dmu_tx_create(os); 731e7cbe64fSgw dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL); 7324bb73804SMatthew Ahrens dmu_tx_mark_netfree(tx); 733e7cbe64fSgw error = dmu_tx_assign(tx, TXG_WAIT); 734e7cbe64fSgw if (error) { 735e7cbe64fSgw dmu_tx_abort(tx); 736e7cbe64fSgw return (error); 737e7cbe64fSgw } 738e7cbe64fSgw 739681d9761SEric Taylor error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, 740e7cbe64fSgw &volsize, tx); 741e7cbe64fSgw dmu_tx_commit(tx); 742e7cbe64fSgw 743e7cbe64fSgw if (error == 0) 744681d9761SEric Taylor error = dmu_free_long_range(os, 745cdb0ab79Smaybee ZVOL_OBJ, volsize, DMU_OBJECT_END); 746681d9761SEric Taylor return (error); 747681d9761SEric Taylor } 748e7cbe64fSgw 749681d9761SEric Taylor void 750681d9761SEric Taylor zvol_remove_minors(const char *name) 751681d9761SEric Taylor { 752681d9761SEric Taylor zvol_state_t *zv; 753681d9761SEric Taylor char *namebuf; 754681d9761SEric Taylor minor_t minor; 755681d9761SEric Taylor 756681d9761SEric Taylor namebuf = kmem_zalloc(strlen(name) + 2, KM_SLEEP); 757681d9761SEric Taylor (void) strncpy(namebuf, name, strlen(name)); 758681d9761SEric Taylor (void) strcat(namebuf, "/"); 759c99e4bdcSChris Kirby mutex_enter(&zfsdev_state_lock); 760c99e4bdcSChris Kirby for (minor = 1; minor <= ZFSDEV_MAX_MINOR; minor++) { 761681d9761SEric Taylor 762c99e4bdcSChris Kirby zv = zfsdev_get_soft_state(minor, ZSST_ZVOL); 763681d9761SEric Taylor if (zv == NULL) 764681d9761SEric Taylor continue; 765681d9761SEric Taylor if (strncmp(namebuf, zv->zv_name, strlen(namebuf)) == 0) 766681d9761SEric Taylor (void) zvol_remove_zv(zv); 767e7cbe64fSgw } 768681d9761SEric Taylor kmem_free(namebuf, strlen(name) + 2); 769681d9761SEric Taylor 770c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 771e7cbe64fSgw } 772e7cbe64fSgw 773c61ea566SGeorge Wilson static int 7743b2aab18SMatthew Ahrens zvol_update_live_volsize(zvol_state_t *zv, uint64_t volsize) 775fa9e4066Sahrens { 776e7cbe64fSgw uint64_t old_volsize = 0ULL; 7773b2aab18SMatthew Ahrens int error = 0; 778fa9e4066Sahrens 779c61ea566SGeorge Wilson ASSERT(MUTEX_HELD(&zfsdev_state_lock)); 780c61ea566SGeorge Wilson 781e7cbe64fSgw /* 782e7cbe64fSgw * Reinitialize the dump area to the new size. If we 783681d9761SEric Taylor * failed to resize the dump area then restore it back to 784c61ea566SGeorge Wilson * its original size. We must set the new volsize prior 785c61ea566SGeorge Wilson * to calling dumpvp_resize() to ensure that the devices' 786c61ea566SGeorge Wilson * size(9P) is not visible by the dump subsystem. 787e7cbe64fSgw */ 7883b2aab18SMatthew Ahrens old_volsize = zv->zv_volsize; 7893b2aab18SMatthew Ahrens zvol_size_changed(zv, volsize); 7903b2aab18SMatthew Ahrens 7913b2aab18SMatthew Ahrens if (zv->zv_flags & ZVOL_DUMPIFIED) { 7923b2aab18SMatthew Ahrens if ((error = zvol_dumpify(zv)) != 0 || 7933b2aab18SMatthew Ahrens (error = dumpvp_resize()) != 0) { 7943b2aab18SMatthew Ahrens int dumpify_error; 7953b2aab18SMatthew Ahrens 7963b2aab18SMatthew Ahrens (void) zvol_update_volsize(zv->zv_objset, old_volsize); 7973b2aab18SMatthew Ahrens zvol_size_changed(zv, old_volsize); 7983b2aab18SMatthew Ahrens dumpify_error = zvol_dumpify(zv); 7993b2aab18SMatthew Ahrens error = dumpify_error ? dumpify_error : error; 800681d9761SEric Taylor } 801fa9e4066Sahrens } 802fa9e4066Sahrens 803573ca77eSGeorge Wilson /* 804573ca77eSGeorge Wilson * Generate a LUN expansion event. 805573ca77eSGeorge Wilson */ 8063b2aab18SMatthew Ahrens if (error == 0) { 807573ca77eSGeorge Wilson sysevent_id_t eid; 808573ca77eSGeorge Wilson nvlist_t *attr; 809573ca77eSGeorge Wilson char *physpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 810573ca77eSGeorge Wilson 811681d9761SEric Taylor (void) snprintf(physpath, MAXPATHLEN, "%s%u", ZVOL_PSEUDO_DEV, 812573ca77eSGeorge Wilson zv->zv_minor); 813573ca77eSGeorge Wilson 814573ca77eSGeorge Wilson VERIFY(nvlist_alloc(&attr, NV_UNIQUE_NAME, KM_SLEEP) == 0); 815573ca77eSGeorge Wilson VERIFY(nvlist_add_string(attr, DEV_PHYS_PATH, physpath) == 0); 816573ca77eSGeorge Wilson 817573ca77eSGeorge Wilson (void) ddi_log_sysevent(zfs_dip, SUNW_VENDOR, EC_DEV_STATUS, 818573ca77eSGeorge Wilson ESC_DEV_DLE, attr, &eid, DDI_SLEEP); 819573ca77eSGeorge Wilson 820573ca77eSGeorge Wilson nvlist_free(attr); 821573ca77eSGeorge Wilson kmem_free(physpath, MAXPATHLEN); 822573ca77eSGeorge Wilson } 823c61ea566SGeorge Wilson return (error); 824c61ea566SGeorge Wilson } 825573ca77eSGeorge Wilson 826c61ea566SGeorge Wilson int 827c61ea566SGeorge Wilson zvol_set_volsize(const char *name, uint64_t volsize) 828c61ea566SGeorge Wilson { 829c61ea566SGeorge Wilson zvol_state_t *zv = NULL; 830c61ea566SGeorge Wilson objset_t *os; 831c61ea566SGeorge Wilson int error; 832c61ea566SGeorge Wilson dmu_object_info_t doi; 833c61ea566SGeorge Wilson uint64_t readonly; 8343b2aab18SMatthew Ahrens boolean_t owned = B_FALSE; 8353b2aab18SMatthew Ahrens 8363b2aab18SMatthew Ahrens error = dsl_prop_get_integer(name, 8373b2aab18SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_READONLY), &readonly, NULL); 8383b2aab18SMatthew Ahrens if (error != 0) 8393b2aab18SMatthew Ahrens return (error); 8403b2aab18SMatthew Ahrens if (readonly) 841be6fd75aSMatthew Ahrens return (SET_ERROR(EROFS)); 842c61ea566SGeorge Wilson 843c61ea566SGeorge Wilson mutex_enter(&zfsdev_state_lock); 844c61ea566SGeorge Wilson zv = zvol_minor_lookup(name); 8453b2aab18SMatthew Ahrens 8463b2aab18SMatthew Ahrens if (zv == NULL || zv->zv_objset == NULL) { 8473b2aab18SMatthew Ahrens if ((error = dmu_objset_own(name, DMU_OST_ZVOL, B_FALSE, 8483b2aab18SMatthew Ahrens FTAG, &os)) != 0) { 8493b2aab18SMatthew Ahrens mutex_exit(&zfsdev_state_lock); 8503b2aab18SMatthew Ahrens return (error); 8513b2aab18SMatthew Ahrens } 8523b2aab18SMatthew Ahrens owned = B_TRUE; 8533b2aab18SMatthew Ahrens if (zv != NULL) 8543b2aab18SMatthew Ahrens zv->zv_objset = os; 8553b2aab18SMatthew Ahrens } else { 8563b2aab18SMatthew Ahrens os = zv->zv_objset; 857c61ea566SGeorge Wilson } 858c61ea566SGeorge Wilson 859c61ea566SGeorge Wilson if ((error = dmu_object_info(os, ZVOL_OBJ, &doi)) != 0 || 8603b2aab18SMatthew Ahrens (error = zvol_check_volsize(volsize, doi.doi_data_block_size)) != 0) 861c61ea566SGeorge Wilson goto out; 862c61ea566SGeorge Wilson 8633b2aab18SMatthew Ahrens error = zvol_update_volsize(os, volsize); 864c61ea566SGeorge Wilson 8653b2aab18SMatthew Ahrens if (error == 0 && zv != NULL) 8663b2aab18SMatthew Ahrens error = zvol_update_live_volsize(zv, volsize); 867bb0ade09Sahrens out: 8683b2aab18SMatthew Ahrens if (owned) { 8693b2aab18SMatthew Ahrens dmu_objset_disown(os, FTAG); 8703b2aab18SMatthew Ahrens if (zv != NULL) 8713b2aab18SMatthew Ahrens zv->zv_objset = NULL; 8723b2aab18SMatthew Ahrens } 873c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 874fa9e4066Sahrens return (error); 875fa9e4066Sahrens } 876fa9e4066Sahrens 877fa9e4066Sahrens /*ARGSUSED*/ 878fa9e4066Sahrens int 879fa9e4066Sahrens zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr) 880fa9e4066Sahrens { 881fa9e4066Sahrens zvol_state_t *zv; 882681d9761SEric Taylor int err = 0; 883fa9e4066Sahrens 884c99e4bdcSChris Kirby mutex_enter(&zfsdev_state_lock); 885fa9e4066Sahrens 886c99e4bdcSChris Kirby zv = zfsdev_get_soft_state(getminor(*devp), ZSST_ZVOL); 887fa9e4066Sahrens if (zv == NULL) { 888c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 889be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 890fa9e4066Sahrens } 891fa9e4066Sahrens 892681d9761SEric Taylor if (zv->zv_total_opens == 0) 893681d9761SEric Taylor err = zvol_first_open(zv); 894681d9761SEric Taylor if (err) { 895c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 896681d9761SEric Taylor return (err); 897681d9761SEric Taylor } 898681d9761SEric Taylor if ((flag & FWRITE) && (zv->zv_flags & ZVOL_RDONLY)) { 899be6fd75aSMatthew Ahrens err = SET_ERROR(EROFS); 900681d9761SEric Taylor goto out; 901fa9e4066Sahrens } 902c7f714e2SEric Taylor if (zv->zv_flags & ZVOL_EXCL) { 903be6fd75aSMatthew Ahrens err = SET_ERROR(EBUSY); 904681d9761SEric Taylor goto out; 905c7f714e2SEric Taylor } 906c7f714e2SEric Taylor if (flag & FEXCL) { 907c7f714e2SEric Taylor if (zv->zv_total_opens != 0) { 908be6fd75aSMatthew Ahrens err = SET_ERROR(EBUSY); 909681d9761SEric Taylor goto out; 910c7f714e2SEric Taylor } 911c7f714e2SEric Taylor zv->zv_flags |= ZVOL_EXCL; 912c7f714e2SEric Taylor } 913fa9e4066Sahrens 914fa9e4066Sahrens if (zv->zv_open_count[otyp] == 0 || otyp == OTYP_LYR) { 915fa9e4066Sahrens zv->zv_open_count[otyp]++; 916fa9e4066Sahrens zv->zv_total_opens++; 917fa9e4066Sahrens } 918c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 919fa9e4066Sahrens 920681d9761SEric Taylor return (err); 921681d9761SEric Taylor out: 922681d9761SEric Taylor if (zv->zv_total_opens == 0) 923681d9761SEric Taylor zvol_last_close(zv); 924c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 925681d9761SEric Taylor return (err); 926fa9e4066Sahrens } 927fa9e4066Sahrens 928fa9e4066Sahrens /*ARGSUSED*/ 929fa9e4066Sahrens int 930fa9e4066Sahrens zvol_close(dev_t dev, int flag, int otyp, cred_t *cr) 931fa9e4066Sahrens { 932fa9e4066Sahrens minor_t minor = getminor(dev); 933fa9e4066Sahrens zvol_state_t *zv; 934681d9761SEric Taylor int error = 0; 935fa9e4066Sahrens 936c99e4bdcSChris Kirby mutex_enter(&zfsdev_state_lock); 937fa9e4066Sahrens 938c99e4bdcSChris Kirby zv = zfsdev_get_soft_state(minor, ZSST_ZVOL); 939fa9e4066Sahrens if (zv == NULL) { 940c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 941be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 942fa9e4066Sahrens } 943fa9e4066Sahrens 944c7f714e2SEric Taylor if (zv->zv_flags & ZVOL_EXCL) { 945c7f714e2SEric Taylor ASSERT(zv->zv_total_opens == 1); 946c7f714e2SEric Taylor zv->zv_flags &= ~ZVOL_EXCL; 947fa9e4066Sahrens } 948fa9e4066Sahrens 949fa9e4066Sahrens /* 950fa9e4066Sahrens * If the open count is zero, this is a spurious close. 951fa9e4066Sahrens * That indicates a bug in the kernel / DDI framework. 952fa9e4066Sahrens */ 953fa9e4066Sahrens ASSERT(zv->zv_open_count[otyp] != 0); 954fa9e4066Sahrens ASSERT(zv->zv_total_opens != 0); 955fa9e4066Sahrens 956fa9e4066Sahrens /* 957fa9e4066Sahrens * You may get multiple opens, but only one close. 958fa9e4066Sahrens */ 959fa9e4066Sahrens zv->zv_open_count[otyp]--; 960fa9e4066Sahrens zv->zv_total_opens--; 961fa9e4066Sahrens 962681d9761SEric Taylor if (zv->zv_total_opens == 0) 963681d9761SEric Taylor zvol_last_close(zv); 964fa9e4066Sahrens 965c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 966681d9761SEric Taylor return (error); 967fa9e4066Sahrens } 968fa9e4066Sahrens 969feb08c6bSbillm static void 970b24ab676SJeff Bonwick zvol_get_done(zgd_t *zgd, int error) 97167bd71c6Sperrin { 972b24ab676SJeff Bonwick if (zgd->zgd_db) 973b24ab676SJeff Bonwick dmu_buf_rele(zgd->zgd_db, zgd); 974b24ab676SJeff Bonwick 975b24ab676SJeff Bonwick zfs_range_unlock(zgd->zgd_rl); 976b24ab676SJeff Bonwick 977b24ab676SJeff Bonwick if (error == 0 && zgd->zgd_bp) 978b24ab676SJeff Bonwick zil_add_block(zgd->zgd_zilog, zgd->zgd_bp); 97967bd71c6Sperrin 98067bd71c6Sperrin kmem_free(zgd, sizeof (zgd_t)); 98167bd71c6Sperrin } 98267bd71c6Sperrin 98367bd71c6Sperrin /* 98467bd71c6Sperrin * Get data to generate a TX_WRITE intent log record. 98567bd71c6Sperrin */ 986feb08c6bSbillm static int 98767bd71c6Sperrin zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio) 98867bd71c6Sperrin { 98967bd71c6Sperrin zvol_state_t *zv = arg; 99067bd71c6Sperrin objset_t *os = zv->zv_objset; 991b24ab676SJeff Bonwick uint64_t object = ZVOL_OBJ; 992b24ab676SJeff Bonwick uint64_t offset = lr->lr_offset; 993b24ab676SJeff Bonwick uint64_t size = lr->lr_length; /* length of user data */ 994b24ab676SJeff Bonwick blkptr_t *bp = &lr->lr_blkptr; 99567bd71c6Sperrin dmu_buf_t *db; 99667bd71c6Sperrin zgd_t *zgd; 99767bd71c6Sperrin int error; 99867bd71c6Sperrin 999b24ab676SJeff Bonwick ASSERT(zio != NULL); 1000b24ab676SJeff Bonwick ASSERT(size != 0); 1001b24ab676SJeff Bonwick 1002b24ab676SJeff Bonwick zgd = kmem_zalloc(sizeof (zgd_t), KM_SLEEP); 1003b24ab676SJeff Bonwick zgd->zgd_zilog = zv->zv_zilog; 1004b24ab676SJeff Bonwick zgd->zgd_rl = zfs_range_lock(&zv->zv_znode, offset, size, RL_READER); 1005feb08c6bSbillm 1006c2e6a7d6Sperrin /* 1007c2e6a7d6Sperrin * Write records come in two flavors: immediate and indirect. 1008c2e6a7d6Sperrin * For small writes it's cheaper to store the data with the 1009c2e6a7d6Sperrin * log record (immediate); for large writes it's cheaper to 1010c2e6a7d6Sperrin * sync the data and get a pointer to it (indirect) so that 1011c2e6a7d6Sperrin * we don't have to write the data twice. 1012c2e6a7d6Sperrin */ 1013b24ab676SJeff Bonwick if (buf != NULL) { /* immediate write */ 1014b24ab676SJeff Bonwick error = dmu_read(os, object, offset, size, buf, 1015b24ab676SJeff Bonwick DMU_READ_NO_PREFETCH); 1016b24ab676SJeff Bonwick } else { 1017b24ab676SJeff Bonwick size = zv->zv_volblocksize; 1018b24ab676SJeff Bonwick offset = P2ALIGN(offset, size); 101947cb52daSJeff Bonwick error = dmu_buf_hold(os, object, offset, zgd, &db, 102047cb52daSJeff Bonwick DMU_READ_NO_PREFETCH); 1021b24ab676SJeff Bonwick if (error == 0) { 102280901aeaSGeorge Wilson blkptr_t *obp = dmu_buf_get_blkptr(db); 102380901aeaSGeorge Wilson if (obp) { 102480901aeaSGeorge Wilson ASSERT(BP_IS_HOLE(bp)); 102580901aeaSGeorge Wilson *bp = *obp; 102680901aeaSGeorge Wilson } 102780901aeaSGeorge Wilson 1028b24ab676SJeff Bonwick zgd->zgd_db = db; 1029b24ab676SJeff Bonwick zgd->zgd_bp = bp; 103067bd71c6Sperrin 1031b24ab676SJeff Bonwick ASSERT(db->db_offset == offset); 1032b24ab676SJeff Bonwick ASSERT(db->db_size == size); 103367bd71c6Sperrin 1034b24ab676SJeff Bonwick error = dmu_sync(zio, lr->lr_common.lrc_txg, 1035b24ab676SJeff Bonwick zvol_get_done, zgd); 1036975c32a0SNeil Perrin 1037b24ab676SJeff Bonwick if (error == 0) 1038b24ab676SJeff Bonwick return (0); 1039b24ab676SJeff Bonwick } 1040975c32a0SNeil Perrin } 1041975c32a0SNeil Perrin 1042b24ab676SJeff Bonwick zvol_get_done(zgd, error); 1043b24ab676SJeff Bonwick 104467bd71c6Sperrin return (error); 104567bd71c6Sperrin } 104667bd71c6Sperrin 1047a24e15ceSperrin /* 1048a24e15ceSperrin * zvol_log_write() handles synchronous writes using TX_WRITE ZIL transactions. 104922ac5be4Sperrin * 105022ac5be4Sperrin * We store data in the log buffers if it's small enough. 105167bd71c6Sperrin * Otherwise we will later flush the data out via dmu_sync(). 105222ac5be4Sperrin */ 105367bd71c6Sperrin ssize_t zvol_immediate_write_sz = 32768; 105422ac5be4Sperrin 1055feb08c6bSbillm static void 1056510b6c0eSNeil Perrin zvol_log_write(zvol_state_t *zv, dmu_tx_t *tx, offset_t off, ssize_t resid, 1057510b6c0eSNeil Perrin boolean_t sync) 105822ac5be4Sperrin { 1059feb08c6bSbillm uint32_t blocksize = zv->zv_volblocksize; 10601209a471SNeil Perrin zilog_t *zilog = zv->zv_zilog; 1061510b6c0eSNeil Perrin boolean_t slogging; 1062e09fa4daSNeil Perrin ssize_t immediate_write_sz; 1063510b6c0eSNeil Perrin 1064b24ab676SJeff Bonwick if (zil_replaying(zilog, tx)) 10651209a471SNeil Perrin return; 10661209a471SNeil Perrin 1067e09fa4daSNeil Perrin immediate_write_sz = (zilog->zl_logbias == ZFS_LOGBIAS_THROUGHPUT) 1068e09fa4daSNeil Perrin ? 0 : zvol_immediate_write_sz; 1069e09fa4daSNeil Perrin 1070e09fa4daSNeil Perrin slogging = spa_has_slogs(zilog->zl_spa) && 1071e09fa4daSNeil Perrin (zilog->zl_logbias == ZFS_LOGBIAS_LATENCY); 1072feb08c6bSbillm 1073510b6c0eSNeil Perrin while (resid) { 1074510b6c0eSNeil Perrin itx_t *itx; 1075510b6c0eSNeil Perrin lr_write_t *lr; 1076510b6c0eSNeil Perrin ssize_t len; 1077510b6c0eSNeil Perrin itx_wr_state_t write_state; 1078510b6c0eSNeil Perrin 1079510b6c0eSNeil Perrin /* 1080510b6c0eSNeil Perrin * Unlike zfs_log_write() we can be called with 1081510b6c0eSNeil Perrin * upto DMU_MAX_ACCESS/2 (5MB) writes. 1082510b6c0eSNeil Perrin */ 1083e09fa4daSNeil Perrin if (blocksize > immediate_write_sz && !slogging && 1084510b6c0eSNeil Perrin resid >= blocksize && off % blocksize == 0) { 1085510b6c0eSNeil Perrin write_state = WR_INDIRECT; /* uses dmu_sync */ 1086510b6c0eSNeil Perrin len = blocksize; 1087510b6c0eSNeil Perrin } else if (sync) { 1088510b6c0eSNeil Perrin write_state = WR_COPIED; 1089510b6c0eSNeil Perrin len = MIN(ZIL_MAX_LOG_DATA, resid); 1090510b6c0eSNeil Perrin } else { 1091510b6c0eSNeil Perrin write_state = WR_NEED_COPY; 1092510b6c0eSNeil Perrin len = MIN(ZIL_MAX_LOG_DATA, resid); 1093510b6c0eSNeil Perrin } 1094510b6c0eSNeil Perrin 1095510b6c0eSNeil Perrin itx = zil_itx_create(TX_WRITE, sizeof (*lr) + 1096510b6c0eSNeil Perrin (write_state == WR_COPIED ? len : 0)); 1097feb08c6bSbillm lr = (lr_write_t *)&itx->itx_lr; 1098510b6c0eSNeil Perrin if (write_state == WR_COPIED && dmu_read(zv->zv_objset, 10997bfdf011SNeil Perrin ZVOL_OBJ, off, len, lr + 1, DMU_READ_NO_PREFETCH) != 0) { 1100b24ab676SJeff Bonwick zil_itx_destroy(itx); 1101510b6c0eSNeil Perrin itx = zil_itx_create(TX_WRITE, sizeof (*lr)); 1102510b6c0eSNeil Perrin lr = (lr_write_t *)&itx->itx_lr; 1103510b6c0eSNeil Perrin write_state = WR_NEED_COPY; 1104510b6c0eSNeil Perrin } 1105510b6c0eSNeil Perrin 1106510b6c0eSNeil Perrin itx->itx_wr_state = write_state; 1107510b6c0eSNeil Perrin if (write_state == WR_NEED_COPY) 1108510b6c0eSNeil Perrin itx->itx_sod += len; 1109feb08c6bSbillm lr->lr_foid = ZVOL_OBJ; 1110feb08c6bSbillm lr->lr_offset = off; 1111510b6c0eSNeil Perrin lr->lr_length = len; 1112b24ab676SJeff Bonwick lr->lr_blkoff = 0; 1113feb08c6bSbillm BP_ZERO(&lr->lr_blkptr); 1114feb08c6bSbillm 1115510b6c0eSNeil Perrin itx->itx_private = zv; 1116510b6c0eSNeil Perrin itx->itx_sync = sync; 1117510b6c0eSNeil Perrin 11185002558fSNeil Perrin zil_itx_assign(zilog, itx, tx); 1119510b6c0eSNeil Perrin 1120510b6c0eSNeil Perrin off += len; 1121510b6c0eSNeil Perrin resid -= len; 112222ac5be4Sperrin } 112322ac5be4Sperrin } 112422ac5be4Sperrin 112588b7b0f2SMatthew Ahrens static int 1126810e43b2SBill Pijewski zvol_dumpio_vdev(vdev_t *vd, void *addr, uint64_t offset, uint64_t origoffset, 1127810e43b2SBill Pijewski uint64_t size, boolean_t doread, boolean_t isdump) 1128e7cbe64fSgw { 1129e7cbe64fSgw vdev_disk_t *dvd; 1130e7cbe64fSgw int c; 1131e7cbe64fSgw int numerrors = 0; 1132e7cbe64fSgw 1133810e43b2SBill Pijewski if (vd->vdev_ops == &vdev_mirror_ops || 1134810e43b2SBill Pijewski vd->vdev_ops == &vdev_replacing_ops || 1135810e43b2SBill Pijewski vd->vdev_ops == &vdev_spare_ops) { 1136810e43b2SBill Pijewski for (c = 0; c < vd->vdev_children; c++) { 1137810e43b2SBill Pijewski int err = zvol_dumpio_vdev(vd->vdev_child[c], 1138810e43b2SBill Pijewski addr, offset, origoffset, size, doread, isdump); 1139810e43b2SBill Pijewski if (err != 0) { 1140810e43b2SBill Pijewski numerrors++; 1141810e43b2SBill Pijewski } else if (doread) { 1142810e43b2SBill Pijewski break; 1143810e43b2SBill Pijewski } 1144e7cbe64fSgw } 1145e7cbe64fSgw } 1146e7cbe64fSgw 1147810e43b2SBill Pijewski if (!vd->vdev_ops->vdev_op_leaf && vd->vdev_ops != &vdev_raidz_ops) 1148e7cbe64fSgw return (numerrors < vd->vdev_children ? 0 : EIO); 1149e7cbe64fSgw 1150dc0bb255SEric Taylor if (doread && !vdev_readable(vd)) 1151be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 1152dc0bb255SEric Taylor else if (!doread && !vdev_writeable(vd)) 1153be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 1154e7cbe64fSgw 1155810e43b2SBill Pijewski if (vd->vdev_ops == &vdev_raidz_ops) { 1156810e43b2SBill Pijewski return (vdev_raidz_physio(vd, 1157810e43b2SBill Pijewski addr, size, offset, origoffset, doread, isdump)); 1158810e43b2SBill Pijewski } 1159810e43b2SBill Pijewski 1160e7cbe64fSgw offset += VDEV_LABEL_START_SIZE; 1161e7cbe64fSgw 1162e7cbe64fSgw if (ddi_in_panic() || isdump) { 116388b7b0f2SMatthew Ahrens ASSERT(!doread); 116488b7b0f2SMatthew Ahrens if (doread) 1165be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 1166810e43b2SBill Pijewski dvd = vd->vdev_tsd; 1167810e43b2SBill Pijewski ASSERT3P(dvd, !=, NULL); 1168e7cbe64fSgw return (ldi_dump(dvd->vd_lh, addr, lbtodb(offset), 1169e7cbe64fSgw lbtodb(size))); 1170e7cbe64fSgw } else { 1171810e43b2SBill Pijewski dvd = vd->vdev_tsd; 1172810e43b2SBill Pijewski ASSERT3P(dvd, !=, NULL); 1173810e43b2SBill Pijewski return (vdev_disk_ldi_physio(dvd->vd_lh, addr, size, 1174810e43b2SBill Pijewski offset, doread ? B_READ : B_WRITE)); 1175e7cbe64fSgw } 1176e7cbe64fSgw } 1177e7cbe64fSgw 117888b7b0f2SMatthew Ahrens static int 117988b7b0f2SMatthew Ahrens zvol_dumpio(zvol_state_t *zv, void *addr, uint64_t offset, uint64_t size, 118088b7b0f2SMatthew Ahrens boolean_t doread, boolean_t isdump) 1181e7cbe64fSgw { 1182e7cbe64fSgw vdev_t *vd; 1183e7cbe64fSgw int error; 118488b7b0f2SMatthew Ahrens zvol_extent_t *ze; 1185e7cbe64fSgw spa_t *spa = dmu_objset_spa(zv->zv_objset); 1186e7cbe64fSgw 118788b7b0f2SMatthew Ahrens /* Must be sector aligned, and not stradle a block boundary. */ 118888b7b0f2SMatthew Ahrens if (P2PHASE(offset, DEV_BSIZE) || P2PHASE(size, DEV_BSIZE) || 118988b7b0f2SMatthew Ahrens P2BOUNDARY(offset, size, zv->zv_volblocksize)) { 1190be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 119188b7b0f2SMatthew Ahrens } 119288b7b0f2SMatthew Ahrens ASSERT(size <= zv->zv_volblocksize); 1193e7cbe64fSgw 119488b7b0f2SMatthew Ahrens /* Locate the extent this belongs to */ 119588b7b0f2SMatthew Ahrens ze = list_head(&zv->zv_extents); 119688b7b0f2SMatthew Ahrens while (offset >= ze->ze_nblks * zv->zv_volblocksize) { 119788b7b0f2SMatthew Ahrens offset -= ze->ze_nblks * zv->zv_volblocksize; 119888b7b0f2SMatthew Ahrens ze = list_next(&zv->zv_extents, ze); 119988b7b0f2SMatthew Ahrens } 120024cc0e1cSGeorge Wilson 12013b2aab18SMatthew Ahrens if (ze == NULL) 1202be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 12033b2aab18SMatthew Ahrens 120424cc0e1cSGeorge Wilson if (!ddi_in_panic()) 120524cc0e1cSGeorge Wilson spa_config_enter(spa, SCL_STATE, FTAG, RW_READER); 120624cc0e1cSGeorge Wilson 120788b7b0f2SMatthew Ahrens vd = vdev_lookup_top(spa, DVA_GET_VDEV(&ze->ze_dva)); 120888b7b0f2SMatthew Ahrens offset += DVA_GET_OFFSET(&ze->ze_dva); 1209810e43b2SBill Pijewski error = zvol_dumpio_vdev(vd, addr, offset, DVA_GET_OFFSET(&ze->ze_dva), 1210810e43b2SBill Pijewski size, doread, isdump); 121124cc0e1cSGeorge Wilson 121224cc0e1cSGeorge Wilson if (!ddi_in_panic()) 121324cc0e1cSGeorge Wilson spa_config_exit(spa, SCL_STATE, FTAG); 121424cc0e1cSGeorge Wilson 1215e7cbe64fSgw return (error); 1216e7cbe64fSgw } 1217e7cbe64fSgw 1218fa9e4066Sahrens int 1219fa9e4066Sahrens zvol_strategy(buf_t *bp) 1220fa9e4066Sahrens { 1221c99e4bdcSChris Kirby zfs_soft_state_t *zs = NULL; 1222c99e4bdcSChris Kirby zvol_state_t *zv; 1223fa9e4066Sahrens uint64_t off, volsize; 122488b7b0f2SMatthew Ahrens size_t resid; 1225fa9e4066Sahrens char *addr; 122622ac5be4Sperrin objset_t *os; 1227c2e6a7d6Sperrin rl_t *rl; 1228fa9e4066Sahrens int error = 0; 122988b7b0f2SMatthew Ahrens boolean_t doread = bp->b_flags & B_READ; 1230810e43b2SBill Pijewski boolean_t is_dumpified; 1231510b6c0eSNeil Perrin boolean_t sync; 1232fa9e4066Sahrens 1233c99e4bdcSChris Kirby if (getminor(bp->b_edev) == 0) { 1234be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 1235c99e4bdcSChris Kirby } else { 1236c99e4bdcSChris Kirby zs = ddi_get_soft_state(zfsdev_state, getminor(bp->b_edev)); 1237c99e4bdcSChris Kirby if (zs == NULL) 1238be6fd75aSMatthew Ahrens error = SET_ERROR(ENXIO); 1239c99e4bdcSChris Kirby else if (zs->zss_type != ZSST_ZVOL) 1240be6fd75aSMatthew Ahrens error = SET_ERROR(EINVAL); 1241fa9e4066Sahrens } 1242fa9e4066Sahrens 1243c99e4bdcSChris Kirby if (error) { 1244c99e4bdcSChris Kirby bioerror(bp, error); 1245fa9e4066Sahrens biodone(bp); 1246fa9e4066Sahrens return (0); 1247fa9e4066Sahrens } 1248fa9e4066Sahrens 1249c99e4bdcSChris Kirby zv = zs->zss_data; 1250c99e4bdcSChris Kirby 1251681d9761SEric Taylor if (!(bp->b_flags & B_READ) && (zv->zv_flags & ZVOL_RDONLY)) { 1252fa9e4066Sahrens bioerror(bp, EROFS); 1253fa9e4066Sahrens biodone(bp); 1254fa9e4066Sahrens return (0); 1255fa9e4066Sahrens } 1256fa9e4066Sahrens 1257fa9e4066Sahrens off = ldbtob(bp->b_blkno); 1258fa9e4066Sahrens volsize = zv->zv_volsize; 1259fa9e4066Sahrens 126022ac5be4Sperrin os = zv->zv_objset; 126122ac5be4Sperrin ASSERT(os != NULL); 1262fa9e4066Sahrens 1263fa9e4066Sahrens bp_mapin(bp); 1264fa9e4066Sahrens addr = bp->b_un.b_addr; 1265fa9e4066Sahrens resid = bp->b_bcount; 1266fa9e4066Sahrens 126788b7b0f2SMatthew Ahrens if (resid > 0 && (off < 0 || off >= volsize)) { 126888b7b0f2SMatthew Ahrens bioerror(bp, EIO); 126988b7b0f2SMatthew Ahrens biodone(bp); 127088b7b0f2SMatthew Ahrens return (0); 127188b7b0f2SMatthew Ahrens } 127273ec3d9cSgw 1273810e43b2SBill Pijewski is_dumpified = zv->zv_flags & ZVOL_DUMPIFIED; 127455da60b9SMark J Musante sync = ((!(bp->b_flags & B_ASYNC) && 127555da60b9SMark J Musante !(zv->zv_flags & ZVOL_WCE)) || 127655da60b9SMark J Musante (zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS)) && 1277810e43b2SBill Pijewski !doread && !is_dumpified; 1278510b6c0eSNeil Perrin 1279a24e15ceSperrin /* 1280a24e15ceSperrin * There must be no buffer changes when doing a dmu_sync() because 1281a24e15ceSperrin * we can't change the data whilst calculating the checksum. 1282a24e15ceSperrin */ 1283c2e6a7d6Sperrin rl = zfs_range_lock(&zv->zv_znode, off, resid, 128488b7b0f2SMatthew Ahrens doread ? RL_READER : RL_WRITER); 1285fa9e4066Sahrens 1286e7cbe64fSgw while (resid != 0 && off < volsize) { 128788b7b0f2SMatthew Ahrens size_t size = MIN(resid, zvol_maxphys); 1288810e43b2SBill Pijewski if (is_dumpified) { 1289e7cbe64fSgw size = MIN(size, P2END(off, zv->zv_volblocksize) - off); 129088b7b0f2SMatthew Ahrens error = zvol_dumpio(zv, addr, off, size, 129188b7b0f2SMatthew Ahrens doread, B_FALSE); 129288b7b0f2SMatthew Ahrens } else if (doread) { 12937bfdf011SNeil Perrin error = dmu_read(os, ZVOL_OBJ, off, size, addr, 12947bfdf011SNeil Perrin DMU_READ_PREFETCH); 1295fa9e4066Sahrens } else { 129622ac5be4Sperrin dmu_tx_t *tx = dmu_tx_create(os); 1297fa9e4066Sahrens dmu_tx_hold_write(tx, ZVOL_OBJ, off, size); 1298fa9e4066Sahrens error = dmu_tx_assign(tx, TXG_WAIT); 1299fa9e4066Sahrens if (error) { 1300fa9e4066Sahrens dmu_tx_abort(tx); 1301fa9e4066Sahrens } else { 130222ac5be4Sperrin dmu_write(os, ZVOL_OBJ, off, size, addr, tx); 1303510b6c0eSNeil Perrin zvol_log_write(zv, tx, off, size, sync); 1304fa9e4066Sahrens dmu_tx_commit(tx); 1305fa9e4066Sahrens } 1306fa9e4066Sahrens } 1307b87f3af3Sperrin if (error) { 1308b87f3af3Sperrin /* convert checksum errors into IO errors */ 1309b87f3af3Sperrin if (error == ECKSUM) 1310be6fd75aSMatthew Ahrens error = SET_ERROR(EIO); 1311fa9e4066Sahrens break; 1312b87f3af3Sperrin } 1313fa9e4066Sahrens off += size; 1314fa9e4066Sahrens addr += size; 1315fa9e4066Sahrens resid -= size; 1316fa9e4066Sahrens } 1317c2e6a7d6Sperrin zfs_range_unlock(rl); 1318fa9e4066Sahrens 1319fa9e4066Sahrens if ((bp->b_resid = resid) == bp->b_bcount) 1320fa9e4066Sahrens bioerror(bp, off > volsize ? EINVAL : error); 1321fa9e4066Sahrens 1322510b6c0eSNeil Perrin if (sync) 13235002558fSNeil Perrin zil_commit(zv->zv_zilog, ZVOL_OBJ); 1324feb08c6bSbillm biodone(bp); 132522ac5be4Sperrin 1326fa9e4066Sahrens return (0); 1327fa9e4066Sahrens } 1328fa9e4066Sahrens 132967bd71c6Sperrin /* 133067bd71c6Sperrin * Set the buffer count to the zvol maximum transfer. 133167bd71c6Sperrin * Using our own routine instead of the default minphys() 133267bd71c6Sperrin * means that for larger writes we write bigger buffers on X86 133367bd71c6Sperrin * (128K instead of 56K) and flush the disk write cache less often 133467bd71c6Sperrin * (every zvol_maxphys - currently 1MB) instead of minphys (currently 133567bd71c6Sperrin * 56K on X86 and 128K on sparc). 133667bd71c6Sperrin */ 133767bd71c6Sperrin void 133867bd71c6Sperrin zvol_minphys(struct buf *bp) 133967bd71c6Sperrin { 134067bd71c6Sperrin if (bp->b_bcount > zvol_maxphys) 134167bd71c6Sperrin bp->b_bcount = zvol_maxphys; 134267bd71c6Sperrin } 134367bd71c6Sperrin 1344e7cbe64fSgw int 1345e7cbe64fSgw zvol_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblocks) 1346e7cbe64fSgw { 1347e7cbe64fSgw minor_t minor = getminor(dev); 1348e7cbe64fSgw zvol_state_t *zv; 1349e7cbe64fSgw int error = 0; 1350e7cbe64fSgw uint64_t size; 1351e7cbe64fSgw uint64_t boff; 1352e7cbe64fSgw uint64_t resid; 1353e7cbe64fSgw 1354c99e4bdcSChris Kirby zv = zfsdev_get_soft_state(minor, ZSST_ZVOL); 1355e7cbe64fSgw if (zv == NULL) 1356be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 1357e7cbe64fSgw 13583b2aab18SMatthew Ahrens if ((zv->zv_flags & ZVOL_DUMPIFIED) == 0) 1359be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 13603b2aab18SMatthew Ahrens 1361e7cbe64fSgw boff = ldbtob(blkno); 1362e7cbe64fSgw resid = ldbtob(nblocks); 136388b7b0f2SMatthew Ahrens 136488b7b0f2SMatthew Ahrens VERIFY3U(boff + resid, <=, zv->zv_volsize); 136588b7b0f2SMatthew Ahrens 1366e7cbe64fSgw while (resid) { 1367e7cbe64fSgw size = MIN(resid, P2END(boff, zv->zv_volblocksize) - boff); 136888b7b0f2SMatthew Ahrens error = zvol_dumpio(zv, addr, boff, size, B_FALSE, B_TRUE); 1369e7cbe64fSgw if (error) 1370e7cbe64fSgw break; 1371e7cbe64fSgw boff += size; 1372e7cbe64fSgw addr += size; 1373e7cbe64fSgw resid -= size; 1374e7cbe64fSgw } 1375e7cbe64fSgw 1376e7cbe64fSgw return (error); 1377e7cbe64fSgw } 1378e7cbe64fSgw 1379fa9e4066Sahrens /*ARGSUSED*/ 1380fa9e4066Sahrens int 1381feb08c6bSbillm zvol_read(dev_t dev, uio_t *uio, cred_t *cr) 1382fa9e4066Sahrens { 1383c7ca1008Sgw minor_t minor = getminor(dev); 1384c7ca1008Sgw zvol_state_t *zv; 138573ec3d9cSgw uint64_t volsize; 1386c2e6a7d6Sperrin rl_t *rl; 1387feb08c6bSbillm int error = 0; 1388fa9e4066Sahrens 1389c99e4bdcSChris Kirby zv = zfsdev_get_soft_state(minor, ZSST_ZVOL); 1390c7ca1008Sgw if (zv == NULL) 1391be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 1392c7ca1008Sgw 139373ec3d9cSgw volsize = zv->zv_volsize; 139473ec3d9cSgw if (uio->uio_resid > 0 && 139573ec3d9cSgw (uio->uio_loffset < 0 || uio->uio_loffset >= volsize)) 1396be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 139773ec3d9cSgw 139888b7b0f2SMatthew Ahrens if (zv->zv_flags & ZVOL_DUMPIFIED) { 139988b7b0f2SMatthew Ahrens error = physio(zvol_strategy, NULL, dev, B_READ, 140088b7b0f2SMatthew Ahrens zvol_minphys, uio); 140188b7b0f2SMatthew Ahrens return (error); 140288b7b0f2SMatthew Ahrens } 140388b7b0f2SMatthew Ahrens 1404c2e6a7d6Sperrin rl = zfs_range_lock(&zv->zv_znode, uio->uio_loffset, uio->uio_resid, 1405c2e6a7d6Sperrin RL_READER); 140673ec3d9cSgw while (uio->uio_resid > 0 && uio->uio_loffset < volsize) { 1407feb08c6bSbillm uint64_t bytes = MIN(uio->uio_resid, DMU_MAX_ACCESS >> 1); 1408fa9e4066Sahrens 140973ec3d9cSgw /* don't read past the end */ 141073ec3d9cSgw if (bytes > volsize - uio->uio_loffset) 141173ec3d9cSgw bytes = volsize - uio->uio_loffset; 141273ec3d9cSgw 1413feb08c6bSbillm error = dmu_read_uio(zv->zv_objset, ZVOL_OBJ, uio, bytes); 1414b87f3af3Sperrin if (error) { 1415b87f3af3Sperrin /* convert checksum errors into IO errors */ 1416b87f3af3Sperrin if (error == ECKSUM) 1417be6fd75aSMatthew Ahrens error = SET_ERROR(EIO); 1418feb08c6bSbillm break; 1419b87f3af3Sperrin } 1420feb08c6bSbillm } 1421c2e6a7d6Sperrin zfs_range_unlock(rl); 1422feb08c6bSbillm return (error); 1423fa9e4066Sahrens } 1424fa9e4066Sahrens 1425fa9e4066Sahrens /*ARGSUSED*/ 1426fa9e4066Sahrens int 1427feb08c6bSbillm zvol_write(dev_t dev, uio_t *uio, cred_t *cr) 1428fa9e4066Sahrens { 1429c7ca1008Sgw minor_t minor = getminor(dev); 1430c7ca1008Sgw zvol_state_t *zv; 143173ec3d9cSgw uint64_t volsize; 1432c2e6a7d6Sperrin rl_t *rl; 1433feb08c6bSbillm int error = 0; 1434510b6c0eSNeil Perrin boolean_t sync; 1435feb08c6bSbillm 1436c99e4bdcSChris Kirby zv = zfsdev_get_soft_state(minor, ZSST_ZVOL); 1437c7ca1008Sgw if (zv == NULL) 1438be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 1439c7ca1008Sgw 144073ec3d9cSgw volsize = zv->zv_volsize; 144173ec3d9cSgw if (uio->uio_resid > 0 && 144273ec3d9cSgw (uio->uio_loffset < 0 || uio->uio_loffset >= volsize)) 1443be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 144473ec3d9cSgw 1445e7cbe64fSgw if (zv->zv_flags & ZVOL_DUMPIFIED) { 1446e7cbe64fSgw error = physio(zvol_strategy, NULL, dev, B_WRITE, 1447e7cbe64fSgw zvol_minphys, uio); 1448e7cbe64fSgw return (error); 1449e7cbe64fSgw } 1450e7cbe64fSgw 145155da60b9SMark J Musante sync = !(zv->zv_flags & ZVOL_WCE) || 145255da60b9SMark J Musante (zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS); 1453510b6c0eSNeil Perrin 1454c2e6a7d6Sperrin rl = zfs_range_lock(&zv->zv_znode, uio->uio_loffset, uio->uio_resid, 1455c2e6a7d6Sperrin RL_WRITER); 145673ec3d9cSgw while (uio->uio_resid > 0 && uio->uio_loffset < volsize) { 1457feb08c6bSbillm uint64_t bytes = MIN(uio->uio_resid, DMU_MAX_ACCESS >> 1); 1458feb08c6bSbillm uint64_t off = uio->uio_loffset; 1459feb08c6bSbillm dmu_tx_t *tx = dmu_tx_create(zv->zv_objset); 146073ec3d9cSgw 146173ec3d9cSgw if (bytes > volsize - off) /* don't write past the end */ 146273ec3d9cSgw bytes = volsize - off; 146373ec3d9cSgw 1464feb08c6bSbillm dmu_tx_hold_write(tx, ZVOL_OBJ, off, bytes); 1465feb08c6bSbillm error = dmu_tx_assign(tx, TXG_WAIT); 1466feb08c6bSbillm if (error) { 1467feb08c6bSbillm dmu_tx_abort(tx); 1468feb08c6bSbillm break; 1469feb08c6bSbillm } 147094d1a210STim Haley error = dmu_write_uio_dbuf(zv->zv_dbuf, uio, bytes, tx); 1471feb08c6bSbillm if (error == 0) 1472510b6c0eSNeil Perrin zvol_log_write(zv, tx, off, bytes, sync); 1473feb08c6bSbillm dmu_tx_commit(tx); 1474feb08c6bSbillm 1475feb08c6bSbillm if (error) 1476feb08c6bSbillm break; 1477feb08c6bSbillm } 1478c2e6a7d6Sperrin zfs_range_unlock(rl); 1479510b6c0eSNeil Perrin if (sync) 14805002558fSNeil Perrin zil_commit(zv->zv_zilog, ZVOL_OBJ); 1481feb08c6bSbillm return (error); 1482fa9e4066Sahrens } 1483fa9e4066Sahrens 1484c7f714e2SEric Taylor int 1485c7f714e2SEric Taylor zvol_getefi(void *arg, int flag, uint64_t vs, uint8_t bs) 1486c7f714e2SEric Taylor { 1487c7f714e2SEric Taylor struct uuid uuid = EFI_RESERVED; 1488c7f714e2SEric Taylor efi_gpe_t gpe = { 0 }; 1489c7f714e2SEric Taylor uint32_t crc; 1490c7f714e2SEric Taylor dk_efi_t efi; 1491c7f714e2SEric Taylor int length; 1492c7f714e2SEric Taylor char *ptr; 1493c7f714e2SEric Taylor 1494c7f714e2SEric Taylor if (ddi_copyin(arg, &efi, sizeof (dk_efi_t), flag)) 1495be6fd75aSMatthew Ahrens return (SET_ERROR(EFAULT)); 1496c7f714e2SEric Taylor ptr = (char *)(uintptr_t)efi.dki_data_64; 1497c7f714e2SEric Taylor length = efi.dki_length; 1498c7f714e2SEric Taylor /* 1499c7f714e2SEric Taylor * Some clients may attempt to request a PMBR for the 1500c7f714e2SEric Taylor * zvol. Currently this interface will return EINVAL to 1501c7f714e2SEric Taylor * such requests. These requests could be supported by 1502c7f714e2SEric Taylor * adding a check for lba == 0 and consing up an appropriate 1503c7f714e2SEric Taylor * PMBR. 1504c7f714e2SEric Taylor */ 1505c7f714e2SEric Taylor if (efi.dki_lba < 1 || efi.dki_lba > 2 || length <= 0) 1506be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1507c7f714e2SEric Taylor 1508c7f714e2SEric Taylor gpe.efi_gpe_StartingLBA = LE_64(34ULL); 1509c7f714e2SEric Taylor gpe.efi_gpe_EndingLBA = LE_64((vs >> bs) - 1); 1510c7f714e2SEric Taylor UUID_LE_CONVERT(gpe.efi_gpe_PartitionTypeGUID, uuid); 1511c7f714e2SEric Taylor 1512c7f714e2SEric Taylor if (efi.dki_lba == 1) { 1513c7f714e2SEric Taylor efi_gpt_t gpt = { 0 }; 1514c7f714e2SEric Taylor 1515c7f714e2SEric Taylor gpt.efi_gpt_Signature = LE_64(EFI_SIGNATURE); 1516c7f714e2SEric Taylor gpt.efi_gpt_Revision = LE_32(EFI_VERSION_CURRENT); 1517c7f714e2SEric Taylor gpt.efi_gpt_HeaderSize = LE_32(sizeof (gpt)); 1518c7f714e2SEric Taylor gpt.efi_gpt_MyLBA = LE_64(1ULL); 1519c7f714e2SEric Taylor gpt.efi_gpt_FirstUsableLBA = LE_64(34ULL); 1520c7f714e2SEric Taylor gpt.efi_gpt_LastUsableLBA = LE_64((vs >> bs) - 1); 1521c7f714e2SEric Taylor gpt.efi_gpt_PartitionEntryLBA = LE_64(2ULL); 1522c7f714e2SEric Taylor gpt.efi_gpt_NumberOfPartitionEntries = LE_32(1); 1523c7f714e2SEric Taylor gpt.efi_gpt_SizeOfPartitionEntry = 1524c7f714e2SEric Taylor LE_32(sizeof (efi_gpe_t)); 1525c7f714e2SEric Taylor CRC32(crc, &gpe, sizeof (gpe), -1U, crc32_table); 1526c7f714e2SEric Taylor gpt.efi_gpt_PartitionEntryArrayCRC32 = LE_32(~crc); 1527c7f714e2SEric Taylor CRC32(crc, &gpt, sizeof (gpt), -1U, crc32_table); 1528c7f714e2SEric Taylor gpt.efi_gpt_HeaderCRC32 = LE_32(~crc); 1529c7f714e2SEric Taylor if (ddi_copyout(&gpt, ptr, MIN(sizeof (gpt), length), 1530c7f714e2SEric Taylor flag)) 1531be6fd75aSMatthew Ahrens return (SET_ERROR(EFAULT)); 1532c7f714e2SEric Taylor ptr += sizeof (gpt); 1533c7f714e2SEric Taylor length -= sizeof (gpt); 1534c7f714e2SEric Taylor } 1535c7f714e2SEric Taylor if (length > 0 && ddi_copyout(&gpe, ptr, MIN(sizeof (gpe), 1536c7f714e2SEric Taylor length), flag)) 1537be6fd75aSMatthew Ahrens return (SET_ERROR(EFAULT)); 1538c7f714e2SEric Taylor return (0); 1539c7f714e2SEric Taylor } 1540c7f714e2SEric Taylor 15413fb517f7SJames Moore /* 15423fb517f7SJames Moore * BEGIN entry points to allow external callers access to the volume. 15433fb517f7SJames Moore */ 15443fb517f7SJames Moore /* 15453fb517f7SJames Moore * Return the volume parameters needed for access from an external caller. 15463fb517f7SJames Moore * These values are invariant as long as the volume is held open. 15473fb517f7SJames Moore */ 15483fb517f7SJames Moore int 15493fb517f7SJames Moore zvol_get_volume_params(minor_t minor, uint64_t *blksize, 15503fb517f7SJames Moore uint64_t *max_xfer_len, void **minor_hdl, void **objset_hdl, void **zil_hdl, 15513fb517f7SJames Moore void **rl_hdl, void **bonus_hdl) 15523fb517f7SJames Moore { 15533fb517f7SJames Moore zvol_state_t *zv; 15543fb517f7SJames Moore 1555c99e4bdcSChris Kirby zv = zfsdev_get_soft_state(minor, ZSST_ZVOL); 1556c99e4bdcSChris Kirby if (zv == NULL) 1557be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 15583fb517f7SJames Moore if (zv->zv_flags & ZVOL_DUMPIFIED) 1559be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 15603fb517f7SJames Moore 15613fb517f7SJames Moore ASSERT(blksize && max_xfer_len && minor_hdl && 15623fb517f7SJames Moore objset_hdl && zil_hdl && rl_hdl && bonus_hdl); 15633fb517f7SJames Moore 15643fb517f7SJames Moore *blksize = zv->zv_volblocksize; 15653fb517f7SJames Moore *max_xfer_len = (uint64_t)zvol_maxphys; 15663fb517f7SJames Moore *minor_hdl = zv; 15673fb517f7SJames Moore *objset_hdl = zv->zv_objset; 15683fb517f7SJames Moore *zil_hdl = zv->zv_zilog; 15693fb517f7SJames Moore *rl_hdl = &zv->zv_znode; 15703fb517f7SJames Moore *bonus_hdl = zv->zv_dbuf; 15713fb517f7SJames Moore return (0); 15723fb517f7SJames Moore } 15733fb517f7SJames Moore 15743fb517f7SJames Moore /* 15753fb517f7SJames Moore * Return the current volume size to an external caller. 15763fb517f7SJames Moore * The size can change while the volume is open. 15773fb517f7SJames Moore */ 15783fb517f7SJames Moore uint64_t 15793fb517f7SJames Moore zvol_get_volume_size(void *minor_hdl) 15803fb517f7SJames Moore { 15813fb517f7SJames Moore zvol_state_t *zv = minor_hdl; 15823fb517f7SJames Moore 15833fb517f7SJames Moore return (zv->zv_volsize); 15843fb517f7SJames Moore } 15853fb517f7SJames Moore 15863fb517f7SJames Moore /* 15873fb517f7SJames Moore * Return the current WCE setting to an external caller. 15883fb517f7SJames Moore * The WCE setting can change while the volume is open. 15893fb517f7SJames Moore */ 15903fb517f7SJames Moore int 15913fb517f7SJames Moore zvol_get_volume_wce(void *minor_hdl) 15923fb517f7SJames Moore { 15933fb517f7SJames Moore zvol_state_t *zv = minor_hdl; 15943fb517f7SJames Moore 15953fb517f7SJames Moore return ((zv->zv_flags & ZVOL_WCE) ? 1 : 0); 15963fb517f7SJames Moore } 15973fb517f7SJames Moore 15983fb517f7SJames Moore /* 15993fb517f7SJames Moore * Entry point for external callers to zvol_log_write 16003fb517f7SJames Moore */ 16013fb517f7SJames Moore void 16023fb517f7SJames Moore zvol_log_write_minor(void *minor_hdl, dmu_tx_t *tx, offset_t off, ssize_t resid, 16033fb517f7SJames Moore boolean_t sync) 16043fb517f7SJames Moore { 16053fb517f7SJames Moore zvol_state_t *zv = minor_hdl; 16063fb517f7SJames Moore 16073fb517f7SJames Moore zvol_log_write(zv, tx, off, resid, sync); 16083fb517f7SJames Moore } 16093fb517f7SJames Moore /* 16103fb517f7SJames Moore * END entry points to allow external callers access to the volume. 16113fb517f7SJames Moore */ 16123fb517f7SJames Moore 1613b77b9231SDan McDonald /* 1614b77b9231SDan McDonald * Log a DKIOCFREE/free-long-range to the ZIL with TX_TRUNCATE. 1615b77b9231SDan McDonald */ 1616b77b9231SDan McDonald static void 1617b77b9231SDan McDonald zvol_log_truncate(zvol_state_t *zv, dmu_tx_t *tx, uint64_t off, uint64_t len, 1618b77b9231SDan McDonald boolean_t sync) 1619b77b9231SDan McDonald { 1620b77b9231SDan McDonald itx_t *itx; 1621b77b9231SDan McDonald lr_truncate_t *lr; 1622b77b9231SDan McDonald zilog_t *zilog = zv->zv_zilog; 1623b77b9231SDan McDonald 1624b77b9231SDan McDonald if (zil_replaying(zilog, tx)) 1625b77b9231SDan McDonald return; 1626b77b9231SDan McDonald 1627b77b9231SDan McDonald itx = zil_itx_create(TX_TRUNCATE, sizeof (*lr)); 1628b77b9231SDan McDonald lr = (lr_truncate_t *)&itx->itx_lr; 1629b77b9231SDan McDonald lr->lr_foid = ZVOL_OBJ; 1630b77b9231SDan McDonald lr->lr_offset = off; 1631b77b9231SDan McDonald lr->lr_length = len; 1632b77b9231SDan McDonald 1633b77b9231SDan McDonald itx->itx_sync = sync; 1634b77b9231SDan McDonald zil_itx_assign(zilog, itx, tx); 1635b77b9231SDan McDonald } 1636b77b9231SDan McDonald 1637fa9e4066Sahrens /* 1638fa9e4066Sahrens * Dirtbag ioctls to support mkfs(1M) for UFS filesystems. See dkio(7I). 1639b77b9231SDan McDonald * Also a dirtbag dkio ioctl for unmap/free-block functionality. 1640fa9e4066Sahrens */ 1641fa9e4066Sahrens /*ARGSUSED*/ 1642fa9e4066Sahrens int 1643fa9e4066Sahrens zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 1644fa9e4066Sahrens { 1645fa9e4066Sahrens zvol_state_t *zv; 1646af2c4821Smaybee struct dk_callback *dkc; 1647fa9e4066Sahrens int error = 0; 1648e7cbe64fSgw rl_t *rl; 1649fa9e4066Sahrens 1650c99e4bdcSChris Kirby mutex_enter(&zfsdev_state_lock); 1651fa9e4066Sahrens 1652c99e4bdcSChris Kirby zv = zfsdev_get_soft_state(getminor(dev), ZSST_ZVOL); 1653fa9e4066Sahrens 1654fa9e4066Sahrens if (zv == NULL) { 1655c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 1656be6fd75aSMatthew Ahrens return (SET_ERROR(ENXIO)); 1657fa9e4066Sahrens } 1658701f66c4SEric Taylor ASSERT(zv->zv_total_opens > 0); 1659fa9e4066Sahrens 1660fa9e4066Sahrens switch (cmd) { 1661fa9e4066Sahrens 1662fa9e4066Sahrens case DKIOCINFO: 1663a0b60564SGeorge Wilson { 1664a0b60564SGeorge Wilson struct dk_cinfo dki; 1665a0b60564SGeorge Wilson 1666af2c4821Smaybee bzero(&dki, sizeof (dki)); 1667af2c4821Smaybee (void) strcpy(dki.dki_cname, "zvol"); 1668af2c4821Smaybee (void) strcpy(dki.dki_dname, "zvol"); 1669af2c4821Smaybee dki.dki_ctype = DKC_UNKNOWN; 16703adc9019SEric Taylor dki.dki_unit = getminor(dev); 1671b5152584SMatthew Ahrens dki.dki_maxtransfer = 1672b5152584SMatthew Ahrens 1 << (SPA_OLD_MAXBLOCKSHIFT - zv->zv_min_bs); 1673c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 1674af2c4821Smaybee if (ddi_copyout(&dki, (void *)arg, sizeof (dki), flag)) 1675be6fd75aSMatthew Ahrens error = SET_ERROR(EFAULT); 1676fa9e4066Sahrens return (error); 1677a0b60564SGeorge Wilson } 1678fa9e4066Sahrens 1679fa9e4066Sahrens case DKIOCGMEDIAINFO: 1680a0b60564SGeorge Wilson { 1681a0b60564SGeorge Wilson struct dk_minfo dkm; 1682a0b60564SGeorge Wilson 1683fa9e4066Sahrens bzero(&dkm, sizeof (dkm)); 1684fa9e4066Sahrens dkm.dki_lbsize = 1U << zv->zv_min_bs; 1685fa9e4066Sahrens dkm.dki_capacity = zv->zv_volsize >> zv->zv_min_bs; 1686fa9e4066Sahrens dkm.dki_media_type = DK_UNKNOWN; 1687c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 1688fa9e4066Sahrens if (ddi_copyout(&dkm, (void *)arg, sizeof (dkm), flag)) 1689be6fd75aSMatthew Ahrens error = SET_ERROR(EFAULT); 1690fa9e4066Sahrens return (error); 1691a0b60564SGeorge Wilson } 1692a0b60564SGeorge Wilson 1693a0b60564SGeorge Wilson case DKIOCGMEDIAINFOEXT: 1694a0b60564SGeorge Wilson { 1695a0b60564SGeorge Wilson struct dk_minfo_ext dkmext; 1696a0b60564SGeorge Wilson 1697a0b60564SGeorge Wilson bzero(&dkmext, sizeof (dkmext)); 1698a0b60564SGeorge Wilson dkmext.dki_lbsize = 1U << zv->zv_min_bs; 1699a0b60564SGeorge Wilson dkmext.dki_pbsize = zv->zv_volblocksize; 1700a0b60564SGeorge Wilson dkmext.dki_capacity = zv->zv_volsize >> zv->zv_min_bs; 1701a0b60564SGeorge Wilson dkmext.dki_media_type = DK_UNKNOWN; 1702a0b60564SGeorge Wilson mutex_exit(&zfsdev_state_lock); 1703a0b60564SGeorge Wilson if (ddi_copyout(&dkmext, (void *)arg, sizeof (dkmext), flag)) 1704a0b60564SGeorge Wilson error = SET_ERROR(EFAULT); 1705a0b60564SGeorge Wilson return (error); 1706a0b60564SGeorge Wilson } 1707fa9e4066Sahrens 1708fa9e4066Sahrens case DKIOCGETEFI: 1709a0b60564SGeorge Wilson { 1710a0b60564SGeorge Wilson uint64_t vs = zv->zv_volsize; 1711a0b60564SGeorge Wilson uint8_t bs = zv->zv_min_bs; 1712fa9e4066Sahrens 1713a0b60564SGeorge Wilson mutex_exit(&zfsdev_state_lock); 1714a0b60564SGeorge Wilson error = zvol_getefi((void *)arg, flag, vs, bs); 1715a0b60564SGeorge Wilson return (error); 1716a0b60564SGeorge Wilson } 1717fa9e4066Sahrens 1718feb08c6bSbillm case DKIOCFLUSHWRITECACHE: 1719af2c4821Smaybee dkc = (struct dk_callback *)arg; 1720c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 17215002558fSNeil Perrin zil_commit(zv->zv_zilog, ZVOL_OBJ); 1722af2c4821Smaybee if ((flag & FKIOCTL) && dkc != NULL && dkc->dkc_callback) { 1723af2c4821Smaybee (*dkc->dkc_callback)(dkc->dkc_cookie, error); 1724af2c4821Smaybee error = 0; 1725af2c4821Smaybee } 1726701f66c4SEric Taylor return (error); 1727701f66c4SEric Taylor 1728701f66c4SEric Taylor case DKIOCGETWCE: 1729a0b60564SGeorge Wilson { 1730a0b60564SGeorge Wilson int wce = (zv->zv_flags & ZVOL_WCE) ? 1 : 0; 1731a0b60564SGeorge Wilson if (ddi_copyout(&wce, (void *)arg, sizeof (int), 1732a0b60564SGeorge Wilson flag)) 1733a0b60564SGeorge Wilson error = SET_ERROR(EFAULT); 1734a0b60564SGeorge Wilson break; 1735a0b60564SGeorge Wilson } 1736a0b60564SGeorge Wilson case DKIOCSETWCE: 1737a0b60564SGeorge Wilson { 1738a0b60564SGeorge Wilson int wce; 1739a0b60564SGeorge Wilson if (ddi_copyin((void *)arg, &wce, sizeof (int), 1740a0b60564SGeorge Wilson flag)) { 1741a0b60564SGeorge Wilson error = SET_ERROR(EFAULT); 1742701f66c4SEric Taylor break; 1743701f66c4SEric Taylor } 1744a0b60564SGeorge Wilson if (wce) { 1745a0b60564SGeorge Wilson zv->zv_flags |= ZVOL_WCE; 1746a0b60564SGeorge Wilson mutex_exit(&zfsdev_state_lock); 1747a0b60564SGeorge Wilson } else { 1748a0b60564SGeorge Wilson zv->zv_flags &= ~ZVOL_WCE; 1749a0b60564SGeorge Wilson mutex_exit(&zfsdev_state_lock); 1750a0b60564SGeorge Wilson zil_commit(zv->zv_zilog, ZVOL_OBJ); 1751701f66c4SEric Taylor } 1752a0b60564SGeorge Wilson return (0); 1753a0b60564SGeorge Wilson } 1754feb08c6bSbillm 1755b6130eadSmaybee case DKIOCGGEOM: 1756b6130eadSmaybee case DKIOCGVTOC: 1757e7cbe64fSgw /* 1758e7cbe64fSgw * commands using these (like prtvtoc) expect ENOTSUP 1759e7cbe64fSgw * since we're emulating an EFI label 1760e7cbe64fSgw */ 1761be6fd75aSMatthew Ahrens error = SET_ERROR(ENOTSUP); 1762b6130eadSmaybee break; 1763b6130eadSmaybee 1764e7cbe64fSgw case DKIOCDUMPINIT: 1765e7cbe64fSgw rl = zfs_range_lock(&zv->zv_znode, 0, zv->zv_volsize, 1766e7cbe64fSgw RL_WRITER); 1767e7cbe64fSgw error = zvol_dumpify(zv); 1768e7cbe64fSgw zfs_range_unlock(rl); 1769e7cbe64fSgw break; 1770e7cbe64fSgw 1771e7cbe64fSgw case DKIOCDUMPFINI: 177206d5ae10SEric Taylor if (!(zv->zv_flags & ZVOL_DUMPIFIED)) 177306d5ae10SEric Taylor break; 1774e7cbe64fSgw rl = zfs_range_lock(&zv->zv_znode, 0, zv->zv_volsize, 1775e7cbe64fSgw RL_WRITER); 1776e7cbe64fSgw error = zvol_dump_fini(zv); 1777e7cbe64fSgw zfs_range_unlock(rl); 1778e7cbe64fSgw break; 1779e7cbe64fSgw 1780b77b9231SDan McDonald case DKIOCFREE: 1781b77b9231SDan McDonald { 1782b77b9231SDan McDonald dkioc_free_t df; 1783b77b9231SDan McDonald dmu_tx_t *tx; 1784b77b9231SDan McDonald 1785893c83baSGeorge Wilson if (!zvol_unmap_enabled) 1786893c83baSGeorge Wilson break; 1787893c83baSGeorge Wilson 1788b77b9231SDan McDonald if (ddi_copyin((void *)arg, &df, sizeof (df), flag)) { 1789be6fd75aSMatthew Ahrens error = SET_ERROR(EFAULT); 1790b77b9231SDan McDonald break; 1791b77b9231SDan McDonald } 1792b77b9231SDan McDonald 1793b77b9231SDan McDonald /* 1794b77b9231SDan McDonald * Apply Postel's Law to length-checking. If they overshoot, 1795b77b9231SDan McDonald * just blank out until the end, if there's a need to blank 1796b77b9231SDan McDonald * out anything. 1797b77b9231SDan McDonald */ 1798b77b9231SDan McDonald if (df.df_start >= zv->zv_volsize) 1799b77b9231SDan McDonald break; /* No need to do anything... */ 1800574e2414SGeorge Wilson 1801574e2414SGeorge Wilson mutex_exit(&zfsdev_state_lock); 1802b77b9231SDan McDonald 1803b77b9231SDan McDonald rl = zfs_range_lock(&zv->zv_znode, df.df_start, df.df_length, 1804b77b9231SDan McDonald RL_WRITER); 1805b77b9231SDan McDonald tx = dmu_tx_create(zv->zv_objset); 18064bb73804SMatthew Ahrens dmu_tx_mark_netfree(tx); 1807b77b9231SDan McDonald error = dmu_tx_assign(tx, TXG_WAIT); 1808b77b9231SDan McDonald if (error != 0) { 1809b77b9231SDan McDonald dmu_tx_abort(tx); 1810b77b9231SDan McDonald } else { 1811b77b9231SDan McDonald zvol_log_truncate(zv, tx, df.df_start, 1812b77b9231SDan McDonald df.df_length, B_TRUE); 1813c08b1637SJosef 'Jeff' Sipek dmu_tx_commit(tx); 1814b77b9231SDan McDonald error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, 1815b77b9231SDan McDonald df.df_start, df.df_length); 1816b77b9231SDan McDonald } 1817b77b9231SDan McDonald 1818b77b9231SDan McDonald zfs_range_unlock(rl); 1819b77b9231SDan McDonald 1820*1c9272b8SStephen Blinick /* 1821*1c9272b8SStephen Blinick * If the write-cache is disabled, 'sync' property 1822*1c9272b8SStephen Blinick * is set to 'always', or if the caller is asking for 1823*1c9272b8SStephen Blinick * a synchronous free, commit this operation to the zil. 1824*1c9272b8SStephen Blinick * This will sync any previous uncommitted writes to the 1825*1c9272b8SStephen Blinick * zvol object. 1826*1c9272b8SStephen Blinick * Can be overridden by the zvol_unmap_sync_enabled tunable. 1827*1c9272b8SStephen Blinick */ 1828*1c9272b8SStephen Blinick if ((error == 0) && zvol_unmap_sync_enabled && 1829*1c9272b8SStephen Blinick (!(zv->zv_flags & ZVOL_WCE) || 1830*1c9272b8SStephen Blinick (zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS) || 1831*1c9272b8SStephen Blinick (df.df_flags & DF_WAIT_SYNC))) { 1832*1c9272b8SStephen Blinick zil_commit(zv->zv_zilog, ZVOL_OBJ); 1833b77b9231SDan McDonald } 1834*1c9272b8SStephen Blinick 1835574e2414SGeorge Wilson return (error); 1836b77b9231SDan McDonald } 1837b77b9231SDan McDonald 1838fa9e4066Sahrens default: 1839be6fd75aSMatthew Ahrens error = SET_ERROR(ENOTTY); 1840fa9e4066Sahrens break; 1841fa9e4066Sahrens 1842fa9e4066Sahrens } 1843c99e4bdcSChris Kirby mutex_exit(&zfsdev_state_lock); 1844fa9e4066Sahrens return (error); 1845fa9e4066Sahrens } 1846fa9e4066Sahrens 1847fa9e4066Sahrens int 1848fa9e4066Sahrens zvol_busy(void) 1849fa9e4066Sahrens { 1850fa9e4066Sahrens return (zvol_minors != 0); 1851fa9e4066Sahrens } 1852fa9e4066Sahrens 1853fa9e4066Sahrens void 1854fa9e4066Sahrens zvol_init(void) 1855fa9e4066Sahrens { 1856c99e4bdcSChris Kirby VERIFY(ddi_soft_state_init(&zfsdev_state, sizeof (zfs_soft_state_t), 1857c99e4bdcSChris Kirby 1) == 0); 1858c99e4bdcSChris Kirby mutex_init(&zfsdev_state_lock, NULL, MUTEX_DEFAULT, NULL); 1859fa9e4066Sahrens } 1860fa9e4066Sahrens 1861fa9e4066Sahrens void 1862fa9e4066Sahrens zvol_fini(void) 1863fa9e4066Sahrens { 1864c99e4bdcSChris Kirby mutex_destroy(&zfsdev_state_lock); 1865c99e4bdcSChris Kirby ddi_soft_state_fini(&zfsdev_state); 1866fa9e4066Sahrens } 1867e7cbe64fSgw 1868810e43b2SBill Pijewski /*ARGSUSED*/ 1869810e43b2SBill Pijewski static int 1870810e43b2SBill Pijewski zfs_mvdev_dump_feature_check(void *arg, dmu_tx_t *tx) 1871810e43b2SBill Pijewski { 1872810e43b2SBill Pijewski spa_t *spa = dmu_tx_pool(tx)->dp_spa; 1873810e43b2SBill Pijewski 18742acef22dSMatthew Ahrens if (spa_feature_is_active(spa, SPA_FEATURE_MULTI_VDEV_CRASH_DUMP)) 1875810e43b2SBill Pijewski return (1); 1876810e43b2SBill Pijewski return (0); 1877810e43b2SBill Pijewski } 1878810e43b2SBill Pijewski 1879810e43b2SBill Pijewski /*ARGSUSED*/ 1880810e43b2SBill Pijewski static void 1881810e43b2SBill Pijewski zfs_mvdev_dump_activate_feature_sync(void *arg, dmu_tx_t *tx) 1882810e43b2SBill Pijewski { 1883810e43b2SBill Pijewski spa_t *spa = dmu_tx_pool(tx)->dp_spa; 1884810e43b2SBill Pijewski 18852acef22dSMatthew Ahrens spa_feature_incr(spa, SPA_FEATURE_MULTI_VDEV_CRASH_DUMP, tx); 1886810e43b2SBill Pijewski } 1887810e43b2SBill Pijewski 1888e7cbe64fSgw static int 1889e7cbe64fSgw zvol_dump_init(zvol_state_t *zv, boolean_t resize) 1890e7cbe64fSgw { 1891e7cbe64fSgw dmu_tx_t *tx; 1892810e43b2SBill Pijewski int error; 1893e7cbe64fSgw objset_t *os = zv->zv_objset; 1894810e43b2SBill Pijewski spa_t *spa = dmu_objset_spa(os); 1895810e43b2SBill Pijewski vdev_t *vd = spa->spa_root_vdev; 1896e7cbe64fSgw nvlist_t *nv = NULL; 1897810e43b2SBill Pijewski uint64_t version = spa_version(spa); 1898b10bba72SGeorge Wilson uint64_t checksum, compress, refresrv, vbs, dedup; 1899e7cbe64fSgw 1900c99e4bdcSChris Kirby ASSERT(MUTEX_HELD(&zfsdev_state_lock)); 1901810e43b2SBill Pijewski ASSERT(vd->vdev_ops == &vdev_root_ops); 1902810e43b2SBill Pijewski 1903681d9761SEric Taylor error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, 0, 1904681d9761SEric Taylor DMU_OBJECT_END); 1905b10bba72SGeorge Wilson if (error != 0) 1906b10bba72SGeorge Wilson return (error); 1907681d9761SEric Taylor /* wait for dmu_free_long_range to actually free the blocks */ 1908681d9761SEric Taylor txg_wait_synced(dmu_objset_pool(zv->zv_objset), 0); 1909e7cbe64fSgw 1910810e43b2SBill Pijewski /* 1911810e43b2SBill Pijewski * If the pool on which the dump device is being initialized has more 1912810e43b2SBill Pijewski * than one child vdev, check that the MULTI_VDEV_CRASH_DUMP feature is 1913810e43b2SBill Pijewski * enabled. If so, bump that feature's counter to indicate that the 1914810e43b2SBill Pijewski * feature is active. We also check the vdev type to handle the 1915810e43b2SBill Pijewski * following case: 1916810e43b2SBill Pijewski * # zpool create test raidz disk1 disk2 disk3 1917810e43b2SBill Pijewski * Now have spa_root_vdev->vdev_children == 1 (the raidz vdev), 1918810e43b2SBill Pijewski * the raidz vdev itself has 3 children. 1919810e43b2SBill Pijewski */ 1920810e43b2SBill Pijewski if (vd->vdev_children > 1 || vd->vdev_ops == &vdev_raidz_ops) { 1921810e43b2SBill Pijewski if (!spa_feature_is_enabled(spa, 19222acef22dSMatthew Ahrens SPA_FEATURE_MULTI_VDEV_CRASH_DUMP)) 1923810e43b2SBill Pijewski return (SET_ERROR(ENOTSUP)); 1924810e43b2SBill Pijewski (void) dsl_sync_task(spa_name(spa), 1925810e43b2SBill Pijewski zfs_mvdev_dump_feature_check, 19267d46dc6cSMatthew Ahrens zfs_mvdev_dump_activate_feature_sync, NULL, 19277d46dc6cSMatthew Ahrens 2, ZFS_SPACE_CHECK_RESERVED); 1928810e43b2SBill Pijewski } 1929810e43b2SBill Pijewski 1930b10bba72SGeorge Wilson if (!resize) { 1931b10bba72SGeorge Wilson error = dsl_prop_get_integer(zv->zv_name, 1932b10bba72SGeorge Wilson zfs_prop_to_name(ZFS_PROP_COMPRESSION), &compress, NULL); 1933b10bba72SGeorge Wilson if (error == 0) { 1934b10bba72SGeorge Wilson error = dsl_prop_get_integer(zv->zv_name, 1935b10bba72SGeorge Wilson zfs_prop_to_name(ZFS_PROP_CHECKSUM), &checksum, 1936b10bba72SGeorge Wilson NULL); 1937b10bba72SGeorge Wilson } 1938b10bba72SGeorge Wilson if (error == 0) { 1939b10bba72SGeorge Wilson error = dsl_prop_get_integer(zv->zv_name, 1940b10bba72SGeorge Wilson zfs_prop_to_name(ZFS_PROP_REFRESERVATION), 1941b10bba72SGeorge Wilson &refresrv, NULL); 1942b10bba72SGeorge Wilson } 1943b10bba72SGeorge Wilson if (error == 0) { 1944b10bba72SGeorge Wilson error = dsl_prop_get_integer(zv->zv_name, 1945b10bba72SGeorge Wilson zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), &vbs, 1946b10bba72SGeorge Wilson NULL); 1947b10bba72SGeorge Wilson } 1948b10bba72SGeorge Wilson if (version >= SPA_VERSION_DEDUP && error == 0) { 1949b10bba72SGeorge Wilson error = dsl_prop_get_integer(zv->zv_name, 1950b10bba72SGeorge Wilson zfs_prop_to_name(ZFS_PROP_DEDUP), &dedup, NULL); 1951b10bba72SGeorge Wilson } 1952b10bba72SGeorge Wilson } 1953b10bba72SGeorge Wilson if (error != 0) 1954b10bba72SGeorge Wilson return (error); 1955b10bba72SGeorge Wilson 1956e7cbe64fSgw tx = dmu_tx_create(os); 1957e7cbe64fSgw dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL); 1958681d9761SEric Taylor dmu_tx_hold_bonus(tx, ZVOL_OBJ); 1959e7cbe64fSgw error = dmu_tx_assign(tx, TXG_WAIT); 1960b10bba72SGeorge Wilson if (error != 0) { 1961e7cbe64fSgw dmu_tx_abort(tx); 1962e7cbe64fSgw return (error); 1963e7cbe64fSgw } 1964e7cbe64fSgw 1965e7cbe64fSgw /* 1966e7cbe64fSgw * If we are resizing the dump device then we only need to 1967e7cbe64fSgw * update the refreservation to match the newly updated 1968e7cbe64fSgw * zvolsize. Otherwise, we save off the original state of the 1969e7cbe64fSgw * zvol so that we can restore them if the zvol is ever undumpified. 1970e7cbe64fSgw */ 1971e7cbe64fSgw if (resize) { 1972e7cbe64fSgw error = zap_update(os, ZVOL_ZAP_OBJ, 1973e7cbe64fSgw zfs_prop_to_name(ZFS_PROP_REFRESERVATION), 8, 1, 1974e7cbe64fSgw &zv->zv_volsize, tx); 1975e7cbe64fSgw } else { 1976b10bba72SGeorge Wilson error = zap_update(os, ZVOL_ZAP_OBJ, 1977e7cbe64fSgw zfs_prop_to_name(ZFS_PROP_COMPRESSION), 8, 1, 1978e7cbe64fSgw &compress, tx); 1979b10bba72SGeorge Wilson if (error == 0) { 1980b10bba72SGeorge Wilson error = zap_update(os, ZVOL_ZAP_OBJ, 1981b10bba72SGeorge Wilson zfs_prop_to_name(ZFS_PROP_CHECKSUM), 8, 1, 1982b10bba72SGeorge Wilson &checksum, tx); 1983b10bba72SGeorge Wilson } 1984b10bba72SGeorge Wilson if (error == 0) { 1985b10bba72SGeorge Wilson error = zap_update(os, ZVOL_ZAP_OBJ, 1986b10bba72SGeorge Wilson zfs_prop_to_name(ZFS_PROP_REFRESERVATION), 8, 1, 1987b10bba72SGeorge Wilson &refresrv, tx); 1988b10bba72SGeorge Wilson } 1989b10bba72SGeorge Wilson if (error == 0) { 1990b10bba72SGeorge Wilson error = zap_update(os, ZVOL_ZAP_OBJ, 1991b10bba72SGeorge Wilson zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 8, 1, 1992b10bba72SGeorge Wilson &vbs, tx); 1993b10bba72SGeorge Wilson } 1994b10bba72SGeorge Wilson if (error == 0) { 1995b10bba72SGeorge Wilson error = dmu_object_set_blocksize( 1996b10bba72SGeorge Wilson os, ZVOL_OBJ, SPA_OLD_MAXBLOCKSIZE, 0, tx); 1997b10bba72SGeorge Wilson } 1998b10bba72SGeorge Wilson if (version >= SPA_VERSION_DEDUP && error == 0) { 1999b10bba72SGeorge Wilson error = zap_update(os, ZVOL_ZAP_OBJ, 20008d265e66SGeorge Wilson zfs_prop_to_name(ZFS_PROP_DEDUP), 8, 1, 20018d265e66SGeorge Wilson &dedup, tx); 20028d265e66SGeorge Wilson } 2003681d9761SEric Taylor if (error == 0) 2004b5152584SMatthew Ahrens zv->zv_volblocksize = SPA_OLD_MAXBLOCKSIZE; 2005e7cbe64fSgw } 2006e7cbe64fSgw dmu_tx_commit(tx); 2007e7cbe64fSgw 2008e7cbe64fSgw /* 2009e7cbe64fSgw * We only need update the zvol's property if we are initializing 2010e7cbe64fSgw * the dump area for the first time. 2011e7cbe64fSgw */ 2012b10bba72SGeorge Wilson if (error == 0 && !resize) { 2013b10bba72SGeorge Wilson /* 2014b10bba72SGeorge Wilson * If MULTI_VDEV_CRASH_DUMP is active, use the NOPARITY checksum 2015b10bba72SGeorge Wilson * function. Otherwise, use the old default -- OFF. 2016b10bba72SGeorge Wilson */ 2017b10bba72SGeorge Wilson checksum = spa_feature_is_active(spa, 2018b10bba72SGeorge Wilson SPA_FEATURE_MULTI_VDEV_CRASH_DUMP) ? ZIO_CHECKSUM_NOPARITY : 2019b10bba72SGeorge Wilson ZIO_CHECKSUM_OFF; 2020b10bba72SGeorge Wilson 2021e7cbe64fSgw VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2022e7cbe64fSgw VERIFY(nvlist_add_uint64(nv, 2023e7cbe64fSgw zfs_prop_to_name(ZFS_PROP_REFRESERVATION), 0) == 0); 2024e7cbe64fSgw VERIFY(nvlist_add_uint64(nv, 2025e7cbe64fSgw zfs_prop_to_name(ZFS_PROP_COMPRESSION), 2026e7cbe64fSgw ZIO_COMPRESS_OFF) == 0); 2027e7cbe64fSgw VERIFY(nvlist_add_uint64(nv, 2028e7cbe64fSgw zfs_prop_to_name(ZFS_PROP_CHECKSUM), 2029810e43b2SBill Pijewski checksum) == 0); 20308d265e66SGeorge Wilson if (version >= SPA_VERSION_DEDUP) { 20318d265e66SGeorge Wilson VERIFY(nvlist_add_uint64(nv, 20328d265e66SGeorge Wilson zfs_prop_to_name(ZFS_PROP_DEDUP), 20338d265e66SGeorge Wilson ZIO_CHECKSUM_OFF) == 0); 20348d265e66SGeorge Wilson } 2035e7cbe64fSgw 203692241e0bSTom Erickson error = zfs_set_prop_nvlist(zv->zv_name, ZPROP_SRC_LOCAL, 203792241e0bSTom Erickson nv, NULL); 2038e7cbe64fSgw nvlist_free(nv); 2039e7cbe64fSgw } 2040e7cbe64fSgw 2041e7cbe64fSgw /* Allocate the space for the dump */ 2042b10bba72SGeorge Wilson if (error == 0) 2043b10bba72SGeorge Wilson error = zvol_prealloc(zv); 2044e7cbe64fSgw return (error); 2045e7cbe64fSgw } 2046e7cbe64fSgw 2047e7cbe64fSgw static int 2048e7cbe64fSgw zvol_dumpify(zvol_state_t *zv) 2049e7cbe64fSgw { 2050e7cbe64fSgw int error = 0; 2051e7cbe64fSgw uint64_t dumpsize = 0; 2052e7cbe64fSgw dmu_tx_t *tx; 2053e7cbe64fSgw objset_t *os = zv->zv_objset; 2054e7cbe64fSgw 2055681d9761SEric Taylor if (zv->zv_flags & ZVOL_RDONLY) 2056be6fd75aSMatthew Ahrens return (SET_ERROR(EROFS)); 2057e7cbe64fSgw 2058e7cbe64fSgw if (zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ, ZVOL_DUMPSIZE, 2059e7cbe64fSgw 8, 1, &dumpsize) != 0 || dumpsize != zv->zv_volsize) { 20604445fffbSMatthew Ahrens boolean_t resize = (dumpsize > 0); 2061e7cbe64fSgw 2062e7cbe64fSgw if ((error = zvol_dump_init(zv, resize)) != 0) { 2063e7cbe64fSgw (void) zvol_dump_fini(zv); 2064e7cbe64fSgw return (error); 2065e7cbe64fSgw } 2066e7cbe64fSgw } 2067e7cbe64fSgw 2068e7cbe64fSgw /* 2069e7cbe64fSgw * Build up our lba mapping. 2070e7cbe64fSgw */ 2071e7cbe64fSgw error = zvol_get_lbas(zv); 2072e7cbe64fSgw if (error) { 2073e7cbe64fSgw (void) zvol_dump_fini(zv); 2074e7cbe64fSgw return (error); 2075e7cbe64fSgw } 2076e7cbe64fSgw 2077e7cbe64fSgw tx = dmu_tx_create(os); 2078e7cbe64fSgw dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL); 2079e7cbe64fSgw error = dmu_tx_assign(tx, TXG_WAIT); 2080e7cbe64fSgw if (error) { 2081e7cbe64fSgw dmu_tx_abort(tx); 2082e7cbe64fSgw (void) zvol_dump_fini(zv); 2083e7cbe64fSgw return (error); 2084e7cbe64fSgw } 2085e7cbe64fSgw 2086e7cbe64fSgw zv->zv_flags |= ZVOL_DUMPIFIED; 2087e7cbe64fSgw error = zap_update(os, ZVOL_ZAP_OBJ, ZVOL_DUMPSIZE, 8, 1, 2088e7cbe64fSgw &zv->zv_volsize, tx); 2089e7cbe64fSgw dmu_tx_commit(tx); 2090e7cbe64fSgw 2091e7cbe64fSgw if (error) { 2092e7cbe64fSgw (void) zvol_dump_fini(zv); 2093e7cbe64fSgw return (error); 2094e7cbe64fSgw } 2095e7cbe64fSgw 2096e7cbe64fSgw txg_wait_synced(dmu_objset_pool(os), 0); 2097e7cbe64fSgw return (0); 2098e7cbe64fSgw } 2099e7cbe64fSgw 2100e7cbe64fSgw static int 2101e7cbe64fSgw zvol_dump_fini(zvol_state_t *zv) 2102e7cbe64fSgw { 2103e7cbe64fSgw dmu_tx_t *tx; 2104e7cbe64fSgw objset_t *os = zv->zv_objset; 2105e7cbe64fSgw nvlist_t *nv; 2106e7cbe64fSgw int error = 0; 2107afee20e4SGeorge Wilson uint64_t checksum, compress, refresrv, vbs, dedup; 21088d265e66SGeorge Wilson uint64_t version = spa_version(dmu_objset_spa(zv->zv_objset)); 2109e7cbe64fSgw 2110b7e50089Smaybee /* 2111b7e50089Smaybee * Attempt to restore the zvol back to its pre-dumpified state. 2112b7e50089Smaybee * This is a best-effort attempt as it's possible that not all 2113b7e50089Smaybee * of these properties were initialized during the dumpify process 2114b7e50089Smaybee * (i.e. error during zvol_dump_init). 2115b7e50089Smaybee */ 2116b7e50089Smaybee 2117e7cbe64fSgw tx = dmu_tx_create(os); 2118e7cbe64fSgw dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL); 2119e7cbe64fSgw error = dmu_tx_assign(tx, TXG_WAIT); 2120e7cbe64fSgw if (error) { 2121e7cbe64fSgw dmu_tx_abort(tx); 2122e7cbe64fSgw return (error); 2123e7cbe64fSgw } 2124b7e50089Smaybee (void) zap_remove(os, ZVOL_ZAP_OBJ, ZVOL_DUMPSIZE, tx); 2125b7e50089Smaybee dmu_tx_commit(tx); 2126e7cbe64fSgw 2127e7cbe64fSgw (void) zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ, 2128e7cbe64fSgw zfs_prop_to_name(ZFS_PROP_CHECKSUM), 8, 1, &checksum); 2129e7cbe64fSgw (void) zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ, 2130e7cbe64fSgw zfs_prop_to_name(ZFS_PROP_COMPRESSION), 8, 1, &compress); 2131e7cbe64fSgw (void) zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ, 2132e7cbe64fSgw zfs_prop_to_name(ZFS_PROP_REFRESERVATION), 8, 1, &refresrv); 213388b7b0f2SMatthew Ahrens (void) zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ, 213488b7b0f2SMatthew Ahrens zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE), 8, 1, &vbs); 2135e7cbe64fSgw 2136e7cbe64fSgw VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2137e7cbe64fSgw (void) nvlist_add_uint64(nv, 2138e7cbe64fSgw zfs_prop_to_name(ZFS_PROP_CHECKSUM), checksum); 2139e7cbe64fSgw (void) nvlist_add_uint64(nv, 2140e7cbe64fSgw zfs_prop_to_name(ZFS_PROP_COMPRESSION), compress); 2141e7cbe64fSgw (void) nvlist_add_uint64(nv, 2142e7cbe64fSgw zfs_prop_to_name(ZFS_PROP_REFRESERVATION), refresrv); 21438d265e66SGeorge Wilson if (version >= SPA_VERSION_DEDUP && 21448d265e66SGeorge Wilson zap_lookup(zv->zv_objset, ZVOL_ZAP_OBJ, 21458d265e66SGeorge Wilson zfs_prop_to_name(ZFS_PROP_DEDUP), 8, 1, &dedup) == 0) { 21468d265e66SGeorge Wilson (void) nvlist_add_uint64(nv, 21478d265e66SGeorge Wilson zfs_prop_to_name(ZFS_PROP_DEDUP), dedup); 21488d265e66SGeorge Wilson } 214992241e0bSTom Erickson (void) zfs_set_prop_nvlist(zv->zv_name, ZPROP_SRC_LOCAL, 215092241e0bSTom Erickson nv, NULL); 2151e7cbe64fSgw nvlist_free(nv); 2152e7cbe64fSgw 2153b7e50089Smaybee zvol_free_extents(zv); 2154b7e50089Smaybee zv->zv_flags &= ~ZVOL_DUMPIFIED; 2155b7e50089Smaybee (void) dmu_free_long_range(os, ZVOL_OBJ, 0, DMU_OBJECT_END); 2156681d9761SEric Taylor /* wait for dmu_free_long_range to actually free the blocks */ 2157681d9761SEric Taylor txg_wait_synced(dmu_objset_pool(zv->zv_objset), 0); 2158681d9761SEric Taylor tx = dmu_tx_create(os); 2159681d9761SEric Taylor dmu_tx_hold_bonus(tx, ZVOL_OBJ); 2160681d9761SEric Taylor error = dmu_tx_assign(tx, TXG_WAIT); 2161681d9761SEric Taylor if (error) { 2162681d9761SEric Taylor dmu_tx_abort(tx); 2163681d9761SEric Taylor return (error); 2164681d9761SEric Taylor } 2165b24ab676SJeff Bonwick if (dmu_object_set_blocksize(os, ZVOL_OBJ, vbs, 0, tx) == 0) 2166b24ab676SJeff Bonwick zv->zv_volblocksize = vbs; 2167681d9761SEric Taylor dmu_tx_commit(tx); 2168b7e50089Smaybee 2169e7cbe64fSgw return (0); 2170e7cbe64fSgw } 2171