1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 5789Sahrens * Common Development and Distribution License, Version 1.0 only 6789Sahrens * (the "License"). You may not use this file except in compliance 7789Sahrens * with the License. 8789Sahrens * 9789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10789Sahrens * or http://www.opensolaris.org/os/licensing. 11789Sahrens * See the License for the specific language governing permissions 12789Sahrens * and limitations under the License. 13789Sahrens * 14789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16789Sahrens * If applicable, add the following below this CDDL HEADER, with the 17789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19789Sahrens * 20789Sahrens * CDDL HEADER END 21789Sahrens */ 22789Sahrens /* 23789Sahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28789Sahrens 29789Sahrens /* 30789Sahrens * ZFS volume emulation driver. 31789Sahrens * 32789Sahrens * Makes a DMU object look like a volume of arbitrary size, up to 2^64 bytes. 33789Sahrens * Volumes are accessed through the symbolic links named: 34789Sahrens * 35789Sahrens * /dev/zvol/dsk/<pool_name>/<dataset_name> 36789Sahrens * /dev/zvol/rdsk/<pool_name>/<dataset_name> 37789Sahrens * 38789Sahrens * These links are created by the ZFS-specific devfsadm link generator. 39789Sahrens * Volumes are persistent through reboot. No user command needs to be 40789Sahrens * run before opening and using a device. 41789Sahrens */ 42789Sahrens 43789Sahrens #include <sys/types.h> 44789Sahrens #include <sys/param.h> 45789Sahrens #include <sys/errno.h> 46789Sahrens #include <sys/aio_req.h> 47789Sahrens #include <sys/uio.h> 48789Sahrens #include <sys/buf.h> 49789Sahrens #include <sys/modctl.h> 50789Sahrens #include <sys/open.h> 51789Sahrens #include <sys/kmem.h> 52789Sahrens #include <sys/conf.h> 53789Sahrens #include <sys/cmn_err.h> 54789Sahrens #include <sys/stat.h> 55789Sahrens #include <sys/zap.h> 56789Sahrens #include <sys/spa.h> 57789Sahrens #include <sys/zio.h> 58789Sahrens #include <sys/dsl_prop.h> 59789Sahrens #include <sys/dkio.h> 60789Sahrens #include <sys/efi_partition.h> 61789Sahrens #include <sys/byteorder.h> 62789Sahrens #include <sys/pathname.h> 63789Sahrens #include <sys/ddi.h> 64789Sahrens #include <sys/sunddi.h> 65789Sahrens #include <sys/crc32.h> 66789Sahrens #include <sys/dirent.h> 67789Sahrens #include <sys/policy.h> 68789Sahrens #include <sys/fs/zfs.h> 69789Sahrens #include <sys/zfs_ioctl.h> 70789Sahrens #include <sys/mkdev.h> 71789Sahrens 72789Sahrens #include "zfs_namecheck.h" 73789Sahrens 74789Sahrens #define ZVOL_OBJ 1ULL 75789Sahrens #define ZVOL_ZAP_OBJ 2ULL 76789Sahrens 77789Sahrens static void *zvol_state; 78789Sahrens 79789Sahrens /* 80789Sahrens * This lock protects the zvol_state structure from being modified 81789Sahrens * while it's being used, e.g. an open that comes in before a create 82789Sahrens * finishes. It also protects temporary opens of the dataset so that, 83789Sahrens * e.g., an open doesn't get a spurious EBUSY. 84789Sahrens */ 85789Sahrens static kmutex_t zvol_state_lock; 86789Sahrens static uint32_t zvol_minors; 87789Sahrens 88789Sahrens /* 89789Sahrens * The in-core state of each volume. 90789Sahrens */ 91789Sahrens typedef struct zvol_state { 92789Sahrens char zv_name[MAXPATHLEN]; /* pool/dd name */ 93789Sahrens uint64_t zv_volsize; /* amount of space we advertise */ 94789Sahrens minor_t zv_minor; /* minor number */ 95789Sahrens uint8_t zv_min_bs; /* minimum addressable block shift */ 96789Sahrens uint8_t zv_readonly; /* hard readonly; like write-protect */ 97789Sahrens objset_t *zv_objset; /* objset handle */ 98789Sahrens uint32_t zv_mode; /* DS_MODE_* flags at open time */ 99789Sahrens uint32_t zv_open_count[OTYPCNT]; /* open counts */ 100789Sahrens uint32_t zv_total_opens; /* total open count */ 101789Sahrens } zvol_state_t; 102789Sahrens 103789Sahrens static void 104789Sahrens zvol_size_changed(zvol_state_t *zv, dev_t dev) 105789Sahrens { 106789Sahrens dev = makedevice(getmajor(dev), zv->zv_minor); 107789Sahrens 108789Sahrens VERIFY(ddi_prop_update_int64(dev, zfs_dip, 109789Sahrens "Size", zv->zv_volsize) == DDI_SUCCESS); 110789Sahrens VERIFY(ddi_prop_update_int64(dev, zfs_dip, 111789Sahrens "Nblocks", lbtodb(zv->zv_volsize)) == DDI_SUCCESS); 112789Sahrens } 113789Sahrens 114789Sahrens int 115*1133Seschrock zvol_check_volsize(zfs_cmd_t *zc, uint64_t blocksize) 116789Sahrens { 117789Sahrens if (zc->zc_volsize == 0) 118789Sahrens return (EINVAL); 119789Sahrens 120*1133Seschrock if (zc->zc_volsize % blocksize != 0) 121*1133Seschrock return (EINVAL); 122*1133Seschrock 123789Sahrens #ifdef _ILP32 124789Sahrens if (zc->zc_volsize - 1 > SPEC_MAXOFFSET_T) 125789Sahrens return (EOVERFLOW); 126789Sahrens #endif 127789Sahrens return (0); 128789Sahrens } 129789Sahrens 130789Sahrens int 131789Sahrens zvol_check_volblocksize(zfs_cmd_t *zc) 132789Sahrens { 133789Sahrens if (zc->zc_volblocksize < SPA_MINBLOCKSIZE || 134789Sahrens zc->zc_volblocksize > SPA_MAXBLOCKSIZE || 135789Sahrens !ISP2(zc->zc_volblocksize)) 136789Sahrens return (EDOM); 137789Sahrens 138789Sahrens return (0); 139789Sahrens } 140789Sahrens 141789Sahrens static void 142789Sahrens zvol_readonly_changed_cb(void *arg, uint64_t newval) 143789Sahrens { 144789Sahrens zvol_state_t *zv = arg; 145789Sahrens 146789Sahrens zv->zv_readonly = (uint8_t)newval; 147789Sahrens } 148789Sahrens 149789Sahrens int 150789Sahrens zvol_get_stats(zfs_cmd_t *zc, objset_t *os) 151789Sahrens { 152789Sahrens int error; 153789Sahrens dmu_object_info_t doi; 154789Sahrens 155789Sahrens error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &zc->zc_volsize); 156789Sahrens 157789Sahrens if (error) 158789Sahrens return (error); 159789Sahrens 160789Sahrens error = dmu_object_info(os, ZVOL_OBJ, &doi); 161789Sahrens 162789Sahrens if (error == 0) 163789Sahrens zc->zc_volblocksize = doi.doi_data_block_size; 164789Sahrens 165789Sahrens return (error); 166789Sahrens } 167789Sahrens 168789Sahrens /* 169789Sahrens * Find a free minor number. 170789Sahrens */ 171789Sahrens static minor_t 172789Sahrens zvol_minor_alloc(void) 173789Sahrens { 174789Sahrens minor_t minor; 175789Sahrens 176789Sahrens ASSERT(MUTEX_HELD(&zvol_state_lock)); 177789Sahrens 178789Sahrens for (minor = 1; minor <= ZVOL_MAX_MINOR; minor++) 179789Sahrens if (ddi_get_soft_state(zvol_state, minor) == NULL) 180789Sahrens return (minor); 181789Sahrens 182789Sahrens return (0); 183789Sahrens } 184789Sahrens 185789Sahrens static zvol_state_t * 186789Sahrens zvol_minor_lookup(char *name) 187789Sahrens { 188789Sahrens minor_t minor; 189789Sahrens zvol_state_t *zv; 190789Sahrens 191789Sahrens ASSERT(MUTEX_HELD(&zvol_state_lock)); 192789Sahrens 193789Sahrens for (minor = 1; minor <= ZVOL_MAX_MINOR; minor++) { 194789Sahrens zv = ddi_get_soft_state(zvol_state, minor); 195789Sahrens if (zv == NULL) 196789Sahrens continue; 197789Sahrens if (strcmp(zv->zv_name, name) == 0) 198789Sahrens break; 199789Sahrens } 200789Sahrens 201789Sahrens return (zv); 202789Sahrens } 203789Sahrens 204789Sahrens void 205789Sahrens zvol_create_cb(objset_t *os, void *arg, dmu_tx_t *tx) 206789Sahrens { 207789Sahrens zfs_cmd_t *zc = arg; 208789Sahrens int error; 209789Sahrens 210789Sahrens error = dmu_object_claim(os, ZVOL_OBJ, DMU_OT_ZVOL, zc->zc_volblocksize, 211789Sahrens DMU_OT_NONE, 0, tx); 212789Sahrens ASSERT(error == 0); 213789Sahrens 214789Sahrens error = zap_create_claim(os, ZVOL_ZAP_OBJ, DMU_OT_ZVOL_PROP, 215789Sahrens DMU_OT_NONE, 0, tx); 216789Sahrens ASSERT(error == 0); 217789Sahrens 218789Sahrens error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1, &zc->zc_volsize, tx); 219789Sahrens ASSERT(error == 0); 220789Sahrens } 221789Sahrens 222789Sahrens /* 223789Sahrens * Create a minor node for the specified volume. 224789Sahrens */ 225789Sahrens int 226789Sahrens zvol_create_minor(zfs_cmd_t *zc) 227789Sahrens { 228789Sahrens char *name = zc->zc_name; 229789Sahrens dev_t dev = zc->zc_dev; 230789Sahrens zvol_state_t *zv; 231789Sahrens objset_t *os; 232789Sahrens uint64_t volsize; 233789Sahrens minor_t minor = 0; 234789Sahrens struct pathname linkpath; 235789Sahrens int ds_mode = DS_MODE_PRIMARY; 236789Sahrens vnode_t *vp = NULL; 237789Sahrens char *devpath; 238789Sahrens size_t devpathlen = strlen(ZVOL_FULL_DEV_DIR) + 1 + strlen(name) + 1; 239789Sahrens char chrbuf[30], blkbuf[30]; 240789Sahrens int error; 241789Sahrens 242789Sahrens mutex_enter(&zvol_state_lock); 243789Sahrens 244789Sahrens if ((zv = zvol_minor_lookup(name)) != NULL) { 245789Sahrens mutex_exit(&zvol_state_lock); 246789Sahrens return (EEXIST); 247789Sahrens } 248789Sahrens 249789Sahrens if (strchr(name, '@') != 0) 250789Sahrens ds_mode |= DS_MODE_READONLY; 251789Sahrens 252789Sahrens error = dmu_objset_open(name, DMU_OST_ZVOL, ds_mode, &os); 253789Sahrens 254789Sahrens if (error) { 255789Sahrens mutex_exit(&zvol_state_lock); 256789Sahrens return (error); 257789Sahrens } 258789Sahrens 259789Sahrens error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize); 260789Sahrens 261789Sahrens if (error) { 262789Sahrens dmu_objset_close(os); 263789Sahrens mutex_exit(&zvol_state_lock); 264789Sahrens return (error); 265789Sahrens } 266789Sahrens 267789Sahrens /* 268789Sahrens * If there's an existing /dev/zvol symlink, try to use the 269789Sahrens * same minor number we used last time. 270789Sahrens */ 271789Sahrens devpath = kmem_alloc(devpathlen, KM_SLEEP); 272789Sahrens 273789Sahrens (void) sprintf(devpath, "%s/%s", ZVOL_FULL_DEV_DIR, name); 274789Sahrens 275789Sahrens error = lookupname(devpath, UIO_SYSSPACE, NO_FOLLOW, NULL, &vp); 276789Sahrens 277789Sahrens kmem_free(devpath, devpathlen); 278789Sahrens 279789Sahrens if (error == 0 && vp->v_type != VLNK) 280789Sahrens error = EINVAL; 281789Sahrens 282789Sahrens if (error == 0) { 283789Sahrens pn_alloc(&linkpath); 284789Sahrens error = pn_getsymlink(vp, &linkpath, kcred); 285789Sahrens if (error == 0) { 286789Sahrens char *ms = strstr(linkpath.pn_path, ZVOL_PSEUDO_DEV); 287789Sahrens if (ms != NULL) { 288789Sahrens ms += strlen(ZVOL_PSEUDO_DEV); 289789Sahrens minor = stoi(&ms); 290789Sahrens } 291789Sahrens } 292789Sahrens pn_free(&linkpath); 293789Sahrens } 294789Sahrens 295789Sahrens if (vp != NULL) 296789Sahrens VN_RELE(vp); 297789Sahrens 298789Sahrens /* 299789Sahrens * If we found a minor but it's already in use, we must pick a new one. 300789Sahrens */ 301789Sahrens if (minor != 0 && ddi_get_soft_state(zvol_state, minor) != NULL) 302789Sahrens minor = 0; 303789Sahrens 304789Sahrens if (minor == 0) 305789Sahrens minor = zvol_minor_alloc(); 306789Sahrens 307789Sahrens if (minor == 0) { 308789Sahrens dmu_objset_close(os); 309789Sahrens mutex_exit(&zvol_state_lock); 310789Sahrens return (ENXIO); 311789Sahrens } 312789Sahrens 313789Sahrens if (ddi_soft_state_zalloc(zvol_state, minor) != DDI_SUCCESS) { 314789Sahrens dmu_objset_close(os); 315789Sahrens mutex_exit(&zvol_state_lock); 316789Sahrens return (EAGAIN); 317789Sahrens } 318789Sahrens 319789Sahrens (void) ddi_prop_update_string(minor, zfs_dip, ZVOL_PROP_NAME, name); 320789Sahrens 321789Sahrens (void) sprintf(chrbuf, "%uc,raw", minor); 322789Sahrens 323789Sahrens if (ddi_create_minor_node(zfs_dip, chrbuf, S_IFCHR, 324789Sahrens minor, DDI_PSEUDO, 0) == DDI_FAILURE) { 325789Sahrens ddi_soft_state_free(zvol_state, minor); 326789Sahrens dmu_objset_close(os); 327789Sahrens mutex_exit(&zvol_state_lock); 328789Sahrens return (EAGAIN); 329789Sahrens } 330789Sahrens 331789Sahrens (void) sprintf(blkbuf, "%uc", minor); 332789Sahrens 333789Sahrens if (ddi_create_minor_node(zfs_dip, blkbuf, S_IFBLK, 334789Sahrens minor, DDI_PSEUDO, 0) == DDI_FAILURE) { 335789Sahrens ddi_remove_minor_node(zfs_dip, chrbuf); 336789Sahrens ddi_soft_state_free(zvol_state, minor); 337789Sahrens dmu_objset_close(os); 338789Sahrens mutex_exit(&zvol_state_lock); 339789Sahrens return (EAGAIN); 340789Sahrens } 341789Sahrens 342789Sahrens zv = ddi_get_soft_state(zvol_state, minor); 343789Sahrens 344789Sahrens (void) strcpy(zv->zv_name, name); 345789Sahrens zv->zv_min_bs = DEV_BSHIFT; 346789Sahrens zv->zv_minor = minor; 347789Sahrens zv->zv_volsize = volsize; 348789Sahrens zv->zv_objset = os; 349789Sahrens zv->zv_mode = ds_mode; 350789Sahrens 351789Sahrens zvol_size_changed(zv, dev); 352789Sahrens 353789Sahrens VERIFY(dsl_prop_register(dmu_objset_ds(zv->zv_objset), 354789Sahrens "readonly", zvol_readonly_changed_cb, zv) == 0); 355789Sahrens 356789Sahrens zvol_minors++; 357789Sahrens 358789Sahrens mutex_exit(&zvol_state_lock); 359789Sahrens 360789Sahrens return (0); 361789Sahrens } 362789Sahrens 363789Sahrens /* 364789Sahrens * Remove minor node for the specified volume. 365789Sahrens */ 366789Sahrens int 367789Sahrens zvol_remove_minor(zfs_cmd_t *zc) 368789Sahrens { 369789Sahrens zvol_state_t *zv; 370789Sahrens char namebuf[30]; 371789Sahrens 372789Sahrens mutex_enter(&zvol_state_lock); 373789Sahrens 374789Sahrens if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) { 375789Sahrens mutex_exit(&zvol_state_lock); 376789Sahrens return (ENXIO); 377789Sahrens } 378789Sahrens 379789Sahrens if (zv->zv_total_opens != 0) { 380789Sahrens mutex_exit(&zvol_state_lock); 381789Sahrens return (EBUSY); 382789Sahrens } 383789Sahrens 384789Sahrens (void) sprintf(namebuf, "%uc,raw", zv->zv_minor); 385789Sahrens ddi_remove_minor_node(zfs_dip, namebuf); 386789Sahrens 387789Sahrens (void) sprintf(namebuf, "%uc", zv->zv_minor); 388789Sahrens ddi_remove_minor_node(zfs_dip, namebuf); 389789Sahrens 390789Sahrens VERIFY(dsl_prop_unregister(dmu_objset_ds(zv->zv_objset), 391789Sahrens "readonly", zvol_readonly_changed_cb, zv) == 0); 392789Sahrens 393789Sahrens dmu_objset_close(zv->zv_objset); 394789Sahrens 395789Sahrens zv->zv_objset = NULL; 396789Sahrens 397789Sahrens ddi_soft_state_free(zvol_state, zv->zv_minor); 398789Sahrens 399789Sahrens zvol_minors--; 400789Sahrens 401789Sahrens mutex_exit(&zvol_state_lock); 402789Sahrens 403789Sahrens return (0); 404789Sahrens } 405789Sahrens 406789Sahrens int 407789Sahrens zvol_set_volsize(zfs_cmd_t *zc) 408789Sahrens { 409789Sahrens zvol_state_t *zv; 410789Sahrens dev_t dev = zc->zc_dev; 411789Sahrens dmu_tx_t *tx; 412789Sahrens int error; 413*1133Seschrock dmu_object_info_t doi; 414789Sahrens 415789Sahrens mutex_enter(&zvol_state_lock); 416789Sahrens 417789Sahrens if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) { 418789Sahrens mutex_exit(&zvol_state_lock); 419789Sahrens return (ENXIO); 420789Sahrens } 421789Sahrens 422*1133Seschrock if ((error = dmu_object_info(zv->zv_objset, ZVOL_OBJ, &doi)) != 0 || 423*1133Seschrock (error = zvol_check_volsize(zc, doi.doi_data_block_size)) != 0) { 424*1133Seschrock mutex_exit(&zvol_state_lock); 425*1133Seschrock return (error); 426*1133Seschrock } 427*1133Seschrock 428789Sahrens if (zv->zv_readonly || (zv->zv_mode & DS_MODE_READONLY)) { 429789Sahrens mutex_exit(&zvol_state_lock); 430789Sahrens return (EROFS); 431789Sahrens } 432789Sahrens 433789Sahrens tx = dmu_tx_create(zv->zv_objset); 434789Sahrens dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, 1); 435789Sahrens dmu_tx_hold_free(tx, ZVOL_OBJ, zc->zc_volsize, DMU_OBJECT_END); 436789Sahrens error = dmu_tx_assign(tx, TXG_WAIT); 437789Sahrens if (error) { 438789Sahrens dmu_tx_abort(tx); 439789Sahrens mutex_exit(&zvol_state_lock); 440789Sahrens return (error); 441789Sahrens } 442789Sahrens 443789Sahrens error = zap_update(zv->zv_objset, ZVOL_ZAP_OBJ, "size", 8, 1, 444789Sahrens &zc->zc_volsize, tx); 445789Sahrens if (error == 0) 446789Sahrens dmu_free_range(zv->zv_objset, ZVOL_OBJ, zc->zc_volsize, 447789Sahrens DMU_OBJECT_END, tx); 448789Sahrens 449789Sahrens dmu_tx_commit(tx); 450789Sahrens 451789Sahrens if (error == 0) { 452789Sahrens zv->zv_volsize = zc->zc_volsize; 453789Sahrens zvol_size_changed(zv, dev); 454789Sahrens } 455789Sahrens 456789Sahrens mutex_exit(&zvol_state_lock); 457789Sahrens 458789Sahrens return (error); 459789Sahrens } 460789Sahrens 461789Sahrens int 462789Sahrens zvol_set_volblocksize(zfs_cmd_t *zc) 463789Sahrens { 464789Sahrens zvol_state_t *zv; 465789Sahrens dmu_tx_t *tx; 466789Sahrens int error; 467789Sahrens 468789Sahrens mutex_enter(&zvol_state_lock); 469789Sahrens 470789Sahrens if ((zv = zvol_minor_lookup(zc->zc_name)) == NULL) { 471789Sahrens mutex_exit(&zvol_state_lock); 472789Sahrens return (ENXIO); 473789Sahrens } 474789Sahrens 475789Sahrens if (zv->zv_readonly || (zv->zv_mode & DS_MODE_READONLY)) { 476789Sahrens mutex_exit(&zvol_state_lock); 477789Sahrens return (EROFS); 478789Sahrens } 479789Sahrens 480789Sahrens tx = dmu_tx_create(zv->zv_objset); 481789Sahrens dmu_tx_hold_bonus(tx, ZVOL_OBJ); 482789Sahrens error = dmu_tx_assign(tx, TXG_WAIT); 483789Sahrens if (error) { 484789Sahrens dmu_tx_abort(tx); 485789Sahrens } else { 486789Sahrens error = dmu_object_set_blocksize(zv->zv_objset, ZVOL_OBJ, 487789Sahrens zc->zc_volblocksize, 0, tx); 488789Sahrens if (error == ENOTSUP) 489789Sahrens error = EBUSY; 490789Sahrens dmu_tx_commit(tx); 491789Sahrens } 492789Sahrens 493789Sahrens mutex_exit(&zvol_state_lock); 494789Sahrens 495789Sahrens return (error); 496789Sahrens } 497789Sahrens 498789Sahrens /*ARGSUSED*/ 499789Sahrens int 500789Sahrens zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr) 501789Sahrens { 502789Sahrens minor_t minor = getminor(*devp); 503789Sahrens zvol_state_t *zv; 504789Sahrens 505789Sahrens if (minor == 0) /* This is the control device */ 506789Sahrens return (0); 507789Sahrens 508789Sahrens mutex_enter(&zvol_state_lock); 509789Sahrens 510789Sahrens zv = ddi_get_soft_state(zvol_state, minor); 511789Sahrens if (zv == NULL) { 512789Sahrens mutex_exit(&zvol_state_lock); 513789Sahrens return (ENXIO); 514789Sahrens } 515789Sahrens 516789Sahrens ASSERT(zv->zv_objset != NULL); 517789Sahrens 518789Sahrens if ((flag & FWRITE) && 519789Sahrens (zv->zv_readonly || (zv->zv_mode & DS_MODE_READONLY))) { 520789Sahrens mutex_exit(&zvol_state_lock); 521789Sahrens return (EROFS); 522789Sahrens } 523789Sahrens 524789Sahrens if (zv->zv_open_count[otyp] == 0 || otyp == OTYP_LYR) { 525789Sahrens zv->zv_open_count[otyp]++; 526789Sahrens zv->zv_total_opens++; 527789Sahrens } 528789Sahrens 529789Sahrens mutex_exit(&zvol_state_lock); 530789Sahrens 531789Sahrens return (0); 532789Sahrens } 533789Sahrens 534789Sahrens /*ARGSUSED*/ 535789Sahrens int 536789Sahrens zvol_close(dev_t dev, int flag, int otyp, cred_t *cr) 537789Sahrens { 538789Sahrens minor_t minor = getminor(dev); 539789Sahrens zvol_state_t *zv; 540789Sahrens 541789Sahrens if (minor == 0) /* This is the control device */ 542789Sahrens return (0); 543789Sahrens 544789Sahrens mutex_enter(&zvol_state_lock); 545789Sahrens 546789Sahrens zv = ddi_get_soft_state(zvol_state, minor); 547789Sahrens if (zv == NULL) { 548789Sahrens mutex_exit(&zvol_state_lock); 549789Sahrens return (ENXIO); 550789Sahrens } 551789Sahrens 552789Sahrens /* 553789Sahrens * The next statement is a workaround for the following DDI bug: 554789Sahrens * 6343604 specfs race: multiple "last-close" of the same device 555789Sahrens */ 556789Sahrens if (zv->zv_total_opens == 0) { 557789Sahrens mutex_exit(&zvol_state_lock); 558789Sahrens return (0); 559789Sahrens } 560789Sahrens 561789Sahrens /* 562789Sahrens * If the open count is zero, this is a spurious close. 563789Sahrens * That indicates a bug in the kernel / DDI framework. 564789Sahrens */ 565789Sahrens ASSERT(zv->zv_open_count[otyp] != 0); 566789Sahrens ASSERT(zv->zv_total_opens != 0); 567789Sahrens 568789Sahrens /* 569789Sahrens * You may get multiple opens, but only one close. 570789Sahrens */ 571789Sahrens zv->zv_open_count[otyp]--; 572789Sahrens zv->zv_total_opens--; 573789Sahrens 574789Sahrens mutex_exit(&zvol_state_lock); 575789Sahrens 576789Sahrens return (0); 577789Sahrens } 578789Sahrens 579789Sahrens int 580789Sahrens zvol_strategy(buf_t *bp) 581789Sahrens { 582789Sahrens zvol_state_t *zv = ddi_get_soft_state(zvol_state, getminor(bp->b_edev)); 583789Sahrens uint64_t off, volsize; 584789Sahrens size_t size, resid; 585789Sahrens char *addr; 586789Sahrens int error = 0; 587789Sahrens 588789Sahrens if (zv == NULL) { 589789Sahrens bioerror(bp, ENXIO); 590789Sahrens biodone(bp); 591789Sahrens return (0); 592789Sahrens } 593789Sahrens 594789Sahrens if (getminor(bp->b_edev) == 0) { 595789Sahrens bioerror(bp, EINVAL); 596789Sahrens biodone(bp); 597789Sahrens return (0); 598789Sahrens } 599789Sahrens 600789Sahrens if (zv->zv_readonly && !(bp->b_flags & B_READ)) { 601789Sahrens bioerror(bp, EROFS); 602789Sahrens biodone(bp); 603789Sahrens return (0); 604789Sahrens } 605789Sahrens 606789Sahrens off = ldbtob(bp->b_blkno); 607789Sahrens volsize = zv->zv_volsize; 608789Sahrens 609789Sahrens ASSERT(zv->zv_objset != NULL); 610789Sahrens 611789Sahrens bp_mapin(bp); 612789Sahrens addr = bp->b_un.b_addr; 613789Sahrens resid = bp->b_bcount; 614789Sahrens 615789Sahrens while (resid != 0 && off < volsize) { 616789Sahrens 617789Sahrens size = MIN(resid, 1UL << 20); /* cap at 1MB per tx */ 618789Sahrens 619789Sahrens if (size > volsize - off) /* don't write past the end */ 620789Sahrens size = volsize - off; 621789Sahrens 622789Sahrens if (bp->b_flags & B_READ) { 623789Sahrens error = dmu_read_canfail(zv->zv_objset, ZVOL_OBJ, 624789Sahrens off, size, addr); 625789Sahrens } else { 626789Sahrens dmu_tx_t *tx = dmu_tx_create(zv->zv_objset); 627789Sahrens dmu_tx_hold_write(tx, ZVOL_OBJ, off, size); 628789Sahrens error = dmu_tx_assign(tx, TXG_WAIT); 629789Sahrens if (error) { 630789Sahrens dmu_tx_abort(tx); 631789Sahrens } else { 632789Sahrens dmu_write(zv->zv_objset, ZVOL_OBJ, 633789Sahrens off, size, addr, tx); 634789Sahrens dmu_tx_commit(tx); 635789Sahrens } 636789Sahrens } 637789Sahrens if (error) 638789Sahrens break; 639789Sahrens off += size; 640789Sahrens addr += size; 641789Sahrens resid -= size; 642789Sahrens } 643789Sahrens 644789Sahrens if ((bp->b_resid = resid) == bp->b_bcount) 645789Sahrens bioerror(bp, off > volsize ? EINVAL : error); 646789Sahrens 647789Sahrens biodone(bp); 648789Sahrens return (0); 649789Sahrens } 650789Sahrens 651789Sahrens /*ARGSUSED*/ 652789Sahrens int 653789Sahrens zvol_read(dev_t dev, uio_t *uiop, cred_t *cr) 654789Sahrens { 655789Sahrens return (physio(zvol_strategy, NULL, dev, B_READ, minphys, uiop)); 656789Sahrens } 657789Sahrens 658789Sahrens /*ARGSUSED*/ 659789Sahrens int 660789Sahrens zvol_write(dev_t dev, uio_t *uiop, cred_t *cr) 661789Sahrens { 662789Sahrens return (physio(zvol_strategy, NULL, dev, B_WRITE, minphys, uiop)); 663789Sahrens } 664789Sahrens 665789Sahrens /*ARGSUSED*/ 666789Sahrens int 667789Sahrens zvol_aread(dev_t dev, struct aio_req *aio, cred_t *cr) 668789Sahrens { 669789Sahrens return (aphysio(zvol_strategy, anocancel, dev, B_READ, minphys, aio)); 670789Sahrens } 671789Sahrens 672789Sahrens /*ARGSUSED*/ 673789Sahrens int 674789Sahrens zvol_awrite(dev_t dev, struct aio_req *aio, cred_t *cr) 675789Sahrens { 676789Sahrens return (aphysio(zvol_strategy, anocancel, dev, B_WRITE, minphys, aio)); 677789Sahrens } 678789Sahrens 679789Sahrens /* 680789Sahrens * Dirtbag ioctls to support mkfs(1M) for UFS filesystems. See dkio(7I). 681789Sahrens */ 682789Sahrens /*ARGSUSED*/ 683789Sahrens int 684789Sahrens zvol_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cr, int *rvalp) 685789Sahrens { 686789Sahrens zvol_state_t *zv; 687789Sahrens struct dk_cinfo dkc; 688789Sahrens struct dk_minfo dkm; 689789Sahrens dk_efi_t efi; 690789Sahrens efi_gpt_t gpt; 691789Sahrens efi_gpe_t gpe; 692789Sahrens struct uuid uuid = EFI_RESERVED; 693789Sahrens uint32_t crc; 694789Sahrens int error = 0; 695789Sahrens 696789Sahrens mutex_enter(&zvol_state_lock); 697789Sahrens 698789Sahrens zv = ddi_get_soft_state(zvol_state, getminor(dev)); 699789Sahrens 700789Sahrens if (zv == NULL) { 701789Sahrens mutex_exit(&zvol_state_lock); 702789Sahrens return (ENXIO); 703789Sahrens } 704789Sahrens 705789Sahrens switch (cmd) { 706789Sahrens 707789Sahrens case DKIOCINFO: 708789Sahrens bzero(&dkc, sizeof (dkc)); 709789Sahrens (void) strcpy(dkc.dki_cname, "zvol"); 710789Sahrens (void) strcpy(dkc.dki_dname, "zvol"); 711789Sahrens dkc.dki_ctype = DKC_UNKNOWN; 712789Sahrens dkc.dki_maxtransfer = 1 << 15; 713789Sahrens mutex_exit(&zvol_state_lock); 714789Sahrens if (ddi_copyout(&dkc, (void *)arg, sizeof (dkc), flag)) 715789Sahrens error = EFAULT; 716789Sahrens return (error); 717789Sahrens 718789Sahrens case DKIOCGMEDIAINFO: 719789Sahrens bzero(&dkm, sizeof (dkm)); 720789Sahrens dkm.dki_lbsize = 1U << zv->zv_min_bs; 721789Sahrens dkm.dki_capacity = zv->zv_volsize >> zv->zv_min_bs; 722789Sahrens dkm.dki_media_type = DK_UNKNOWN; 723789Sahrens mutex_exit(&zvol_state_lock); 724789Sahrens if (ddi_copyout(&dkm, (void *)arg, sizeof (dkm), flag)) 725789Sahrens error = EFAULT; 726789Sahrens return (error); 727789Sahrens 728789Sahrens case DKIOCGETEFI: 729789Sahrens if (ddi_copyin((void *)arg, &efi, sizeof (dk_efi_t), flag)) { 730789Sahrens mutex_exit(&zvol_state_lock); 731789Sahrens return (EFAULT); 732789Sahrens } 733789Sahrens 734789Sahrens bzero(&gpt, sizeof (gpt)); 735789Sahrens bzero(&gpe, sizeof (gpe)); 736789Sahrens 737789Sahrens efi.dki_data = (void *)(uintptr_t)efi.dki_data_64; 738789Sahrens 739789Sahrens if (efi.dki_length < sizeof (gpt) + sizeof (gpe)) { 740789Sahrens mutex_exit(&zvol_state_lock); 741789Sahrens return (EINVAL); 742789Sahrens } 743789Sahrens 744789Sahrens efi.dki_length = sizeof (gpt) + sizeof (gpe); 745789Sahrens 746789Sahrens gpt.efi_gpt_Signature = LE_64(EFI_SIGNATURE); 747*1133Seschrock gpt.efi_gpt_Revision = LE_32(EFI_VERSION_CURRENT); 748789Sahrens gpt.efi_gpt_HeaderSize = LE_32(sizeof (gpt)); 749789Sahrens gpt.efi_gpt_FirstUsableLBA = LE_64(0ULL); 750789Sahrens gpt.efi_gpt_LastUsableLBA = 751789Sahrens LE_64((zv->zv_volsize >> zv->zv_min_bs) - 1); 752789Sahrens gpt.efi_gpt_NumberOfPartitionEntries = LE_32(1); 753789Sahrens gpt.efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (gpe)); 754789Sahrens 755789Sahrens UUID_LE_CONVERT(gpe.efi_gpe_PartitionTypeGUID, uuid); 756789Sahrens gpe.efi_gpe_StartingLBA = gpt.efi_gpt_FirstUsableLBA; 757789Sahrens gpe.efi_gpe_EndingLBA = gpt.efi_gpt_LastUsableLBA; 758789Sahrens 759789Sahrens CRC32(crc, &gpe, sizeof (gpe), -1U, crc32_table); 760789Sahrens gpt.efi_gpt_PartitionEntryArrayCRC32 = LE_32(~crc); 761789Sahrens 762789Sahrens CRC32(crc, &gpt, sizeof (gpt), -1U, crc32_table); 763789Sahrens gpt.efi_gpt_HeaderCRC32 = LE_32(~crc); 764789Sahrens 765789Sahrens mutex_exit(&zvol_state_lock); 766789Sahrens if (ddi_copyout(&gpt, efi.dki_data, sizeof (gpt), flag) || 767789Sahrens ddi_copyout(&gpe, efi.dki_data + 1, sizeof (gpe), flag)) 768789Sahrens error = EFAULT; 769789Sahrens return (error); 770789Sahrens 771789Sahrens default: 772789Sahrens error = ENOTSUP; 773789Sahrens break; 774789Sahrens 775789Sahrens } 776789Sahrens mutex_exit(&zvol_state_lock); 777789Sahrens return (error); 778789Sahrens } 779789Sahrens 780789Sahrens int 781789Sahrens zvol_busy(void) 782789Sahrens { 783789Sahrens return (zvol_minors != 0); 784789Sahrens } 785789Sahrens 786789Sahrens void 787789Sahrens zvol_init(void) 788789Sahrens { 789789Sahrens VERIFY(ddi_soft_state_init(&zvol_state, sizeof (zvol_state_t), 1) == 0); 790789Sahrens mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL); 791789Sahrens } 792789Sahrens 793789Sahrens void 794789Sahrens zvol_fini(void) 795789Sahrens { 796789Sahrens mutex_destroy(&zvol_state_lock); 797789Sahrens ddi_soft_state_fini(&zvol_state); 798789Sahrens } 799