1*10588SEric.Taylor@Sun.COM /* 2*10588SEric.Taylor@Sun.COM * CDDL HEADER START 3*10588SEric.Taylor@Sun.COM * 4*10588SEric.Taylor@Sun.COM * The contents of this file are subject to the terms of the 5*10588SEric.Taylor@Sun.COM * Common Development and Distribution License (the "License"). 6*10588SEric.Taylor@Sun.COM * You may not use this file except in compliance with the License. 7*10588SEric.Taylor@Sun.COM * 8*10588SEric.Taylor@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10588SEric.Taylor@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*10588SEric.Taylor@Sun.COM * See the License for the specific language governing permissions 11*10588SEric.Taylor@Sun.COM * and limitations under the License. 12*10588SEric.Taylor@Sun.COM * 13*10588SEric.Taylor@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*10588SEric.Taylor@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10588SEric.Taylor@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*10588SEric.Taylor@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*10588SEric.Taylor@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*10588SEric.Taylor@Sun.COM * 19*10588SEric.Taylor@Sun.COM * CDDL HEADER END 20*10588SEric.Taylor@Sun.COM */ 21*10588SEric.Taylor@Sun.COM /* 22*10588SEric.Taylor@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*10588SEric.Taylor@Sun.COM * Use is subject to license terms. 24*10588SEric.Taylor@Sun.COM */ 25*10588SEric.Taylor@Sun.COM 26*10588SEric.Taylor@Sun.COM /* vnode ops for the /dev/zvol directory */ 27*10588SEric.Taylor@Sun.COM 28*10588SEric.Taylor@Sun.COM #include <sys/types.h> 29*10588SEric.Taylor@Sun.COM #include <sys/param.h> 30*10588SEric.Taylor@Sun.COM #include <sys/sysmacros.h> 31*10588SEric.Taylor@Sun.COM #include <sys/ddi.h> 32*10588SEric.Taylor@Sun.COM #include <sys/sunndi.h> 33*10588SEric.Taylor@Sun.COM #include <sys/sunldi.h> 34*10588SEric.Taylor@Sun.COM #include <fs/fs_subr.h> 35*10588SEric.Taylor@Sun.COM #include <sys/fs/dv_node.h> 36*10588SEric.Taylor@Sun.COM #include <sys/fs/sdev_impl.h> 37*10588SEric.Taylor@Sun.COM #include <sys/zfs_ioctl.h> 38*10588SEric.Taylor@Sun.COM #include <sys/policy.h> 39*10588SEric.Taylor@Sun.COM #include <sys/stat.h> 40*10588SEric.Taylor@Sun.COM #include <sys/vfs_opreg.h> 41*10588SEric.Taylor@Sun.COM 42*10588SEric.Taylor@Sun.COM struct vnodeops *devzvol_vnodeops; 43*10588SEric.Taylor@Sun.COM static uint64_t devzvol_gen = 0; 44*10588SEric.Taylor@Sun.COM static uint64_t devzvol_zclist; 45*10588SEric.Taylor@Sun.COM static size_t devzvol_zclist_size; 46*10588SEric.Taylor@Sun.COM static ldi_ident_t devzvol_li; 47*10588SEric.Taylor@Sun.COM static ldi_handle_t devzvol_lh; 48*10588SEric.Taylor@Sun.COM static kmutex_t devzvol_mtx; 49*10588SEric.Taylor@Sun.COM static int devzvol_isopen; 50*10588SEric.Taylor@Sun.COM 51*10588SEric.Taylor@Sun.COM /* 52*10588SEric.Taylor@Sun.COM * we need to use ddi_mod* since fs/dev gets loaded early on in 53*10588SEric.Taylor@Sun.COM * startup(), and linking fs/dev to fs/zfs would drag in a lot of 54*10588SEric.Taylor@Sun.COM * other stuff (like drv/random) before the rest of the system is 55*10588SEric.Taylor@Sun.COM * ready to go 56*10588SEric.Taylor@Sun.COM */ 57*10588SEric.Taylor@Sun.COM ddi_modhandle_t zfs_mod; 58*10588SEric.Taylor@Sun.COM int (*szcm)(char *); 59*10588SEric.Taylor@Sun.COM int (*szn2m)(char *, minor_t *); 60*10588SEric.Taylor@Sun.COM 61*10588SEric.Taylor@Sun.COM int 62*10588SEric.Taylor@Sun.COM sdev_zvol_create_minor(char *dsname) 63*10588SEric.Taylor@Sun.COM { 64*10588SEric.Taylor@Sun.COM return ((*szcm)(dsname)); 65*10588SEric.Taylor@Sun.COM } 66*10588SEric.Taylor@Sun.COM 67*10588SEric.Taylor@Sun.COM int 68*10588SEric.Taylor@Sun.COM sdev_zvol_name2minor(char *dsname, minor_t *minor) 69*10588SEric.Taylor@Sun.COM { 70*10588SEric.Taylor@Sun.COM return ((*szn2m)(dsname, minor)); 71*10588SEric.Taylor@Sun.COM } 72*10588SEric.Taylor@Sun.COM 73*10588SEric.Taylor@Sun.COM int 74*10588SEric.Taylor@Sun.COM devzvol_open_zfs() 75*10588SEric.Taylor@Sun.COM { 76*10588SEric.Taylor@Sun.COM int rc; 77*10588SEric.Taylor@Sun.COM 78*10588SEric.Taylor@Sun.COM devzvol_li = ldi_ident_from_anon(); 79*10588SEric.Taylor@Sun.COM if (ldi_open_by_name("/dev/zfs", FREAD | FWRITE, kcred, 80*10588SEric.Taylor@Sun.COM &devzvol_lh, devzvol_li)) 81*10588SEric.Taylor@Sun.COM return (-1); 82*10588SEric.Taylor@Sun.COM if (zfs_mod == NULL && ((zfs_mod = ddi_modopen("fs/zfs", 83*10588SEric.Taylor@Sun.COM KRTLD_MODE_FIRST, &rc)) == NULL)) { 84*10588SEric.Taylor@Sun.COM return (rc); 85*10588SEric.Taylor@Sun.COM } 86*10588SEric.Taylor@Sun.COM ASSERT(szcm == NULL && szn2m == NULL); 87*10588SEric.Taylor@Sun.COM if ((szcm = (int (*)(char *)) 88*10588SEric.Taylor@Sun.COM ddi_modsym(zfs_mod, "zvol_create_minor", &rc)) == NULL) { 89*10588SEric.Taylor@Sun.COM cmn_err(CE_WARN, "couldn't resolve zvol_create_minor"); 90*10588SEric.Taylor@Sun.COM return (rc); 91*10588SEric.Taylor@Sun.COM } 92*10588SEric.Taylor@Sun.COM if ((szn2m = (int(*)(char *, minor_t *)) 93*10588SEric.Taylor@Sun.COM ddi_modsym(zfs_mod, "zvol_name2minor", &rc)) == NULL) { 94*10588SEric.Taylor@Sun.COM cmn_err(CE_WARN, "couldn't resolve zvol_name2minor"); 95*10588SEric.Taylor@Sun.COM return (rc); 96*10588SEric.Taylor@Sun.COM } 97*10588SEric.Taylor@Sun.COM return (0); 98*10588SEric.Taylor@Sun.COM } 99*10588SEric.Taylor@Sun.COM 100*10588SEric.Taylor@Sun.COM void 101*10588SEric.Taylor@Sun.COM devzvol_close_zfs() 102*10588SEric.Taylor@Sun.COM { 103*10588SEric.Taylor@Sun.COM szcm = NULL; 104*10588SEric.Taylor@Sun.COM szn2m = NULL; 105*10588SEric.Taylor@Sun.COM (void) ldi_close(devzvol_lh, FREAD|FWRITE, kcred); 106*10588SEric.Taylor@Sun.COM ldi_ident_release(devzvol_li); 107*10588SEric.Taylor@Sun.COM if (zfs_mod != NULL) { 108*10588SEric.Taylor@Sun.COM (void) ddi_modclose(zfs_mod); 109*10588SEric.Taylor@Sun.COM zfs_mod = NULL; 110*10588SEric.Taylor@Sun.COM } 111*10588SEric.Taylor@Sun.COM } 112*10588SEric.Taylor@Sun.COM 113*10588SEric.Taylor@Sun.COM int 114*10588SEric.Taylor@Sun.COM devzvol_handle_ioctl(int cmd, zfs_cmd_t *zc, size_t *alloc_size) 115*10588SEric.Taylor@Sun.COM { 116*10588SEric.Taylor@Sun.COM uint64_t cookie; 117*10588SEric.Taylor@Sun.COM int size = 8000; 118*10588SEric.Taylor@Sun.COM int unused; 119*10588SEric.Taylor@Sun.COM int rc; 120*10588SEric.Taylor@Sun.COM 121*10588SEric.Taylor@Sun.COM if (cmd != ZFS_IOC_POOL_CONFIGS) 122*10588SEric.Taylor@Sun.COM mutex_enter(&devzvol_mtx); 123*10588SEric.Taylor@Sun.COM if (devzvol_isopen == 0) { 124*10588SEric.Taylor@Sun.COM if ((rc = devzvol_open_zfs()) == 0) { 125*10588SEric.Taylor@Sun.COM devzvol_isopen++; 126*10588SEric.Taylor@Sun.COM } else { 127*10588SEric.Taylor@Sun.COM if (cmd != ZFS_IOC_POOL_CONFIGS) 128*10588SEric.Taylor@Sun.COM mutex_exit(&devzvol_mtx); 129*10588SEric.Taylor@Sun.COM return (ENXIO); 130*10588SEric.Taylor@Sun.COM } 131*10588SEric.Taylor@Sun.COM } 132*10588SEric.Taylor@Sun.COM cookie = zc->zc_cookie; 133*10588SEric.Taylor@Sun.COM again: 134*10588SEric.Taylor@Sun.COM zc->zc_nvlist_dst = (uint64_t)(intptr_t)kmem_alloc(size, 135*10588SEric.Taylor@Sun.COM KM_SLEEP); 136*10588SEric.Taylor@Sun.COM zc->zc_nvlist_dst_size = size; 137*10588SEric.Taylor@Sun.COM rc = ldi_ioctl(devzvol_lh, cmd, (intptr_t)zc, FKIOCTL, kcred, 138*10588SEric.Taylor@Sun.COM &unused); 139*10588SEric.Taylor@Sun.COM if (rc == ENOMEM) { 140*10588SEric.Taylor@Sun.COM int newsize; 141*10588SEric.Taylor@Sun.COM newsize = zc->zc_nvlist_dst_size; 142*10588SEric.Taylor@Sun.COM ASSERT(newsize > size); 143*10588SEric.Taylor@Sun.COM kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, size); 144*10588SEric.Taylor@Sun.COM size = newsize; 145*10588SEric.Taylor@Sun.COM zc->zc_cookie = cookie; 146*10588SEric.Taylor@Sun.COM goto again; 147*10588SEric.Taylor@Sun.COM } 148*10588SEric.Taylor@Sun.COM if (alloc_size == NULL) 149*10588SEric.Taylor@Sun.COM kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, size); 150*10588SEric.Taylor@Sun.COM else 151*10588SEric.Taylor@Sun.COM *alloc_size = size; 152*10588SEric.Taylor@Sun.COM if (cmd != ZFS_IOC_POOL_CONFIGS) 153*10588SEric.Taylor@Sun.COM mutex_exit(&devzvol_mtx); 154*10588SEric.Taylor@Sun.COM return (rc); 155*10588SEric.Taylor@Sun.COM } 156*10588SEric.Taylor@Sun.COM 157*10588SEric.Taylor@Sun.COM /* figures out if the objset exists and returns its type */ 158*10588SEric.Taylor@Sun.COM int 159*10588SEric.Taylor@Sun.COM devzvol_objset_check(char *dsname, dmu_objset_type_t *type) 160*10588SEric.Taylor@Sun.COM { 161*10588SEric.Taylor@Sun.COM boolean_t ispool; 162*10588SEric.Taylor@Sun.COM zfs_cmd_t *zc; 163*10588SEric.Taylor@Sun.COM int rc; 164*10588SEric.Taylor@Sun.COM 165*10588SEric.Taylor@Sun.COM zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 166*10588SEric.Taylor@Sun.COM (void) strlcpy(zc->zc_name, dsname, MAXPATHLEN); 167*10588SEric.Taylor@Sun.COM 168*10588SEric.Taylor@Sun.COM ispool = (strchr(dsname, '/') == NULL) ? B_TRUE : B_FALSE; 169*10588SEric.Taylor@Sun.COM if (!ispool && sdev_zvol_name2minor(dsname, NULL) == 0) { 170*10588SEric.Taylor@Sun.COM sdcmn_err13(("found cached minor node")); 171*10588SEric.Taylor@Sun.COM if (type) 172*10588SEric.Taylor@Sun.COM *type = DMU_OST_ZVOL; 173*10588SEric.Taylor@Sun.COM kmem_free(zc, sizeof (zfs_cmd_t)); 174*10588SEric.Taylor@Sun.COM return (0); 175*10588SEric.Taylor@Sun.COM } 176*10588SEric.Taylor@Sun.COM rc = devzvol_handle_ioctl(ispool ? ZFS_IOC_POOL_STATS : 177*10588SEric.Taylor@Sun.COM ZFS_IOC_OBJSET_STATS, zc, NULL); 178*10588SEric.Taylor@Sun.COM if (type && rc == 0) 179*10588SEric.Taylor@Sun.COM *type = (ispool) ? DMU_OST_ZFS : 180*10588SEric.Taylor@Sun.COM zc->zc_objset_stats.dds_type; 181*10588SEric.Taylor@Sun.COM kmem_free(zc, sizeof (zfs_cmd_t)); 182*10588SEric.Taylor@Sun.COM return (rc); 183*10588SEric.Taylor@Sun.COM } 184*10588SEric.Taylor@Sun.COM 185*10588SEric.Taylor@Sun.COM /* 186*10588SEric.Taylor@Sun.COM * returns what the zfs dataset name should be, given the /dev/zvol 187*10588SEric.Taylor@Sun.COM * path and an optional name; otherwise NULL 188*10588SEric.Taylor@Sun.COM */ 189*10588SEric.Taylor@Sun.COM char * 190*10588SEric.Taylor@Sun.COM devzvol_make_dsname(const char *path, const char *name) 191*10588SEric.Taylor@Sun.COM { 192*10588SEric.Taylor@Sun.COM char *dsname; 193*10588SEric.Taylor@Sun.COM const char *ptr; 194*10588SEric.Taylor@Sun.COM int dslen; 195*10588SEric.Taylor@Sun.COM 196*10588SEric.Taylor@Sun.COM if (strcmp(path, ZVOL_DIR) == 0) 197*10588SEric.Taylor@Sun.COM return (NULL); 198*10588SEric.Taylor@Sun.COM if (name && (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)) 199*10588SEric.Taylor@Sun.COM return (NULL); 200*10588SEric.Taylor@Sun.COM ptr = path + strlen(ZVOL_DIR); 201*10588SEric.Taylor@Sun.COM if (strncmp(ptr, "/dsk", 4) == 0) 202*10588SEric.Taylor@Sun.COM ptr += strlen("/dsk"); 203*10588SEric.Taylor@Sun.COM else if (strncmp(ptr, "/rdsk", 5) == 0) 204*10588SEric.Taylor@Sun.COM ptr += strlen("/rdsk"); 205*10588SEric.Taylor@Sun.COM else 206*10588SEric.Taylor@Sun.COM return (NULL); 207*10588SEric.Taylor@Sun.COM if (*ptr == '/') 208*10588SEric.Taylor@Sun.COM ptr++; 209*10588SEric.Taylor@Sun.COM 210*10588SEric.Taylor@Sun.COM dslen = strlen(ptr); 211*10588SEric.Taylor@Sun.COM if (dslen) 212*10588SEric.Taylor@Sun.COM dslen++; /* plus null */ 213*10588SEric.Taylor@Sun.COM if (name) 214*10588SEric.Taylor@Sun.COM dslen += strlen(name) + 1; /* plus slash */ 215*10588SEric.Taylor@Sun.COM dsname = kmem_zalloc(dslen, KM_SLEEP); 216*10588SEric.Taylor@Sun.COM if (*ptr) { 217*10588SEric.Taylor@Sun.COM (void) strlcpy(dsname, ptr, dslen); 218*10588SEric.Taylor@Sun.COM if (name) 219*10588SEric.Taylor@Sun.COM (void) strlcat(dsname, "/", dslen); 220*10588SEric.Taylor@Sun.COM } 221*10588SEric.Taylor@Sun.COM if (name) 222*10588SEric.Taylor@Sun.COM (void) strlcat(dsname, name, dslen); 223*10588SEric.Taylor@Sun.COM return (dsname); 224*10588SEric.Taylor@Sun.COM } 225*10588SEric.Taylor@Sun.COM 226*10588SEric.Taylor@Sun.COM /* 227*10588SEric.Taylor@Sun.COM * check if the zvol's sdev_node is still valid, which means make 228*10588SEric.Taylor@Sun.COM * sure the zvol is still valid. zvol minors aren't proactively 229*10588SEric.Taylor@Sun.COM * destroyed when the zvol is destroyed, so we use a validator to clean 230*10588SEric.Taylor@Sun.COM * these up (in other words, when such nodes are encountered during 231*10588SEric.Taylor@Sun.COM * subsequent lookup() and readdir() operations) so that only valid 232*10588SEric.Taylor@Sun.COM * nodes are returned. The ordering between devname_lookup_func and 233*10588SEric.Taylor@Sun.COM * devzvol_validate is a little inefficient in the case of invalid 234*10588SEric.Taylor@Sun.COM * or stale nodes because devname_lookup_func calls 235*10588SEric.Taylor@Sun.COM * devzvol_create_{dir, link}, then the validator says it's invalid, 236*10588SEric.Taylor@Sun.COM * and then the node gets cleaned up. 237*10588SEric.Taylor@Sun.COM */ 238*10588SEric.Taylor@Sun.COM int 239*10588SEric.Taylor@Sun.COM devzvol_validate(struct sdev_node *dv) 240*10588SEric.Taylor@Sun.COM { 241*10588SEric.Taylor@Sun.COM dmu_objset_type_t do_type; 242*10588SEric.Taylor@Sun.COM char *dsname; 243*10588SEric.Taylor@Sun.COM char *nm = dv->sdev_name; 244*10588SEric.Taylor@Sun.COM int rc; 245*10588SEric.Taylor@Sun.COM 246*10588SEric.Taylor@Sun.COM sdcmn_err13(("validating ('%s' '%s')", dv->sdev_path, nm)); 247*10588SEric.Taylor@Sun.COM /* 248*10588SEric.Taylor@Sun.COM * validate only READY nodes; if someone is sitting on the 249*10588SEric.Taylor@Sun.COM * directory of a dataset that just got destroyed we could 250*10588SEric.Taylor@Sun.COM * get a zombie node which we just skip. 251*10588SEric.Taylor@Sun.COM */ 252*10588SEric.Taylor@Sun.COM if (dv->sdev_state != SDEV_READY) { 253*10588SEric.Taylor@Sun.COM sdcmn_err13(("skipping '%s'", nm)); 254*10588SEric.Taylor@Sun.COM return (SDEV_VTOR_SKIP); 255*10588SEric.Taylor@Sun.COM } 256*10588SEric.Taylor@Sun.COM 257*10588SEric.Taylor@Sun.COM if ((strcmp(dv->sdev_path, ZVOL_DIR "/dsk") == 0) || 258*10588SEric.Taylor@Sun.COM (strcmp(dv->sdev_path, ZVOL_DIR "/rdsk") == 0)) 259*10588SEric.Taylor@Sun.COM return (SDEV_VTOR_VALID); 260*10588SEric.Taylor@Sun.COM dsname = devzvol_make_dsname(dv->sdev_path, NULL); 261*10588SEric.Taylor@Sun.COM if (dsname == NULL) 262*10588SEric.Taylor@Sun.COM return (SDEV_VTOR_INVALID); 263*10588SEric.Taylor@Sun.COM 264*10588SEric.Taylor@Sun.COM rc = devzvol_objset_check(dsname, &do_type); 265*10588SEric.Taylor@Sun.COM sdcmn_err13((" '%s' rc %d", dsname, rc)); 266*10588SEric.Taylor@Sun.COM if (rc != 0) { 267*10588SEric.Taylor@Sun.COM kmem_free(dsname, strlen(dsname) + 1); 268*10588SEric.Taylor@Sun.COM return (SDEV_VTOR_INVALID); 269*10588SEric.Taylor@Sun.COM } 270*10588SEric.Taylor@Sun.COM sdcmn_err13((" v_type %d do_type %d", 271*10588SEric.Taylor@Sun.COM SDEVTOV(dv)->v_type, do_type)); 272*10588SEric.Taylor@Sun.COM if ((SDEVTOV(dv)->v_type == VLNK && do_type != DMU_OST_ZVOL) || 273*10588SEric.Taylor@Sun.COM (SDEVTOV(dv)->v_type == VDIR && do_type == DMU_OST_ZVOL)) { 274*10588SEric.Taylor@Sun.COM kmem_free(dsname, strlen(dsname) + 1); 275*10588SEric.Taylor@Sun.COM return (SDEV_VTOR_STALE); 276*10588SEric.Taylor@Sun.COM } 277*10588SEric.Taylor@Sun.COM if (SDEVTOV(dv)->v_type == VLNK) { 278*10588SEric.Taylor@Sun.COM char *ptr, *link; 279*10588SEric.Taylor@Sun.COM long val = 0; 280*10588SEric.Taylor@Sun.COM minor_t lminor, ominor; 281*10588SEric.Taylor@Sun.COM 282*10588SEric.Taylor@Sun.COM rc = sdev_getlink(SDEVTOV(dv), &link); 283*10588SEric.Taylor@Sun.COM ASSERT(rc == 0); 284*10588SEric.Taylor@Sun.COM 285*10588SEric.Taylor@Sun.COM ptr = strrchr(link, ':') + 1; 286*10588SEric.Taylor@Sun.COM rc = ddi_strtol(ptr, NULL, 10, &val); 287*10588SEric.Taylor@Sun.COM kmem_free(link, strlen(link) + 1); 288*10588SEric.Taylor@Sun.COM ASSERT(rc == 0 && val != 0); 289*10588SEric.Taylor@Sun.COM lminor = (minor_t)val; 290*10588SEric.Taylor@Sun.COM if (sdev_zvol_name2minor(dsname, &ominor) < 0 || 291*10588SEric.Taylor@Sun.COM ominor != lminor) { 292*10588SEric.Taylor@Sun.COM kmem_free(dsname, strlen(dsname) + 1); 293*10588SEric.Taylor@Sun.COM return (SDEV_VTOR_STALE); 294*10588SEric.Taylor@Sun.COM } 295*10588SEric.Taylor@Sun.COM } 296*10588SEric.Taylor@Sun.COM kmem_free(dsname, strlen(dsname) + 1); 297*10588SEric.Taylor@Sun.COM return (SDEV_VTOR_VALID); 298*10588SEric.Taylor@Sun.COM } 299*10588SEric.Taylor@Sun.COM 300*10588SEric.Taylor@Sun.COM /* 301*10588SEric.Taylor@Sun.COM * creates directories as needed in response to a readdir 302*10588SEric.Taylor@Sun.COM */ 303*10588SEric.Taylor@Sun.COM void 304*10588SEric.Taylor@Sun.COM devzvol_create_pool_dirs(struct vnode *dvp) 305*10588SEric.Taylor@Sun.COM { 306*10588SEric.Taylor@Sun.COM zfs_cmd_t *zc; 307*10588SEric.Taylor@Sun.COM nvlist_t *nv = NULL; 308*10588SEric.Taylor@Sun.COM nvpair_t *elem = NULL; 309*10588SEric.Taylor@Sun.COM size_t size; 310*10588SEric.Taylor@Sun.COM int pools = 0; 311*10588SEric.Taylor@Sun.COM int rc; 312*10588SEric.Taylor@Sun.COM 313*10588SEric.Taylor@Sun.COM sdcmn_err13(("devzvol_create_pool_dirs")); 314*10588SEric.Taylor@Sun.COM zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 315*10588SEric.Taylor@Sun.COM mutex_enter(&devzvol_mtx); 316*10588SEric.Taylor@Sun.COM zc->zc_cookie = devzvol_gen; 317*10588SEric.Taylor@Sun.COM 318*10588SEric.Taylor@Sun.COM rc = devzvol_handle_ioctl(ZFS_IOC_POOL_CONFIGS, zc, &size); 319*10588SEric.Taylor@Sun.COM switch (rc) { 320*10588SEric.Taylor@Sun.COM case 0: 321*10588SEric.Taylor@Sun.COM /* new generation */ 322*10588SEric.Taylor@Sun.COM ASSERT(devzvol_gen != zc->zc_cookie); 323*10588SEric.Taylor@Sun.COM devzvol_gen = zc->zc_cookie; 324*10588SEric.Taylor@Sun.COM if (devzvol_zclist) 325*10588SEric.Taylor@Sun.COM kmem_free((void *)(uintptr_t)devzvol_zclist, 326*10588SEric.Taylor@Sun.COM devzvol_zclist_size); 327*10588SEric.Taylor@Sun.COM devzvol_zclist = zc->zc_nvlist_dst; 328*10588SEric.Taylor@Sun.COM devzvol_zclist_size = size; 329*10588SEric.Taylor@Sun.COM break; 330*10588SEric.Taylor@Sun.COM case EEXIST: 331*10588SEric.Taylor@Sun.COM /* 332*10588SEric.Taylor@Sun.COM * no change in the configuration; still need 333*10588SEric.Taylor@Sun.COM * to do lookups in case we did a lookup in 334*10588SEric.Taylor@Sun.COM * zvol/rdsk but not zvol/dsk (or vice versa) 335*10588SEric.Taylor@Sun.COM */ 336*10588SEric.Taylor@Sun.COM kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, 337*10588SEric.Taylor@Sun.COM size); 338*10588SEric.Taylor@Sun.COM break; 339*10588SEric.Taylor@Sun.COM default: 340*10588SEric.Taylor@Sun.COM kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, 341*10588SEric.Taylor@Sun.COM size); 342*10588SEric.Taylor@Sun.COM goto out; 343*10588SEric.Taylor@Sun.COM } 344*10588SEric.Taylor@Sun.COM rc = nvlist_unpack((char *)(uintptr_t)devzvol_zclist, 345*10588SEric.Taylor@Sun.COM devzvol_zclist_size, &nv, 0); 346*10588SEric.Taylor@Sun.COM if (rc) { 347*10588SEric.Taylor@Sun.COM ASSERT(rc == 0); 348*10588SEric.Taylor@Sun.COM kmem_free((void *)(uintptr_t)devzvol_zclist, 349*10588SEric.Taylor@Sun.COM devzvol_zclist_size); 350*10588SEric.Taylor@Sun.COM devzvol_gen = 0; 351*10588SEric.Taylor@Sun.COM devzvol_zclist = NULL; 352*10588SEric.Taylor@Sun.COM devzvol_zclist_size = 0; 353*10588SEric.Taylor@Sun.COM goto out; 354*10588SEric.Taylor@Sun.COM } 355*10588SEric.Taylor@Sun.COM mutex_exit(&devzvol_mtx); 356*10588SEric.Taylor@Sun.COM while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) { 357*10588SEric.Taylor@Sun.COM struct vnode *vp; 358*10588SEric.Taylor@Sun.COM ASSERT(dvp->v_count > 0); 359*10588SEric.Taylor@Sun.COM rc = VOP_LOOKUP(dvp, nvpair_name(elem), &vp, NULL, 0, 360*10588SEric.Taylor@Sun.COM NULL, kcred, NULL, 0, NULL); 361*10588SEric.Taylor@Sun.COM /* should either work, or not be visible from a zone */ 362*10588SEric.Taylor@Sun.COM ASSERT(rc == 0 || rc == ENOENT); 363*10588SEric.Taylor@Sun.COM if (rc == 0) 364*10588SEric.Taylor@Sun.COM VN_RELE(vp); 365*10588SEric.Taylor@Sun.COM pools++; 366*10588SEric.Taylor@Sun.COM } 367*10588SEric.Taylor@Sun.COM nvlist_free(nv); 368*10588SEric.Taylor@Sun.COM mutex_enter(&devzvol_mtx); 369*10588SEric.Taylor@Sun.COM if (pools == 0) { 370*10588SEric.Taylor@Sun.COM /* clean up so zfs can be unloaded */ 371*10588SEric.Taylor@Sun.COM devzvol_close_zfs(); 372*10588SEric.Taylor@Sun.COM devzvol_isopen--; 373*10588SEric.Taylor@Sun.COM } 374*10588SEric.Taylor@Sun.COM out: 375*10588SEric.Taylor@Sun.COM mutex_exit(&devzvol_mtx); 376*10588SEric.Taylor@Sun.COM kmem_free(zc, sizeof (zfs_cmd_t)); 377*10588SEric.Taylor@Sun.COM } 378*10588SEric.Taylor@Sun.COM 379*10588SEric.Taylor@Sun.COM /*ARGSUSED3*/ 380*10588SEric.Taylor@Sun.COM static int 381*10588SEric.Taylor@Sun.COM devzvol_create_dir(struct sdev_node *ddv, char *nm, void **arg, 382*10588SEric.Taylor@Sun.COM cred_t *cred, void *whatever, char *whichever) 383*10588SEric.Taylor@Sun.COM { 384*10588SEric.Taylor@Sun.COM timestruc_t now; 385*10588SEric.Taylor@Sun.COM struct vattr *vap = (struct vattr *)arg; 386*10588SEric.Taylor@Sun.COM 387*10588SEric.Taylor@Sun.COM sdcmn_err13(("create_dir (%s) (%s) '%s'", ddv->sdev_name, 388*10588SEric.Taylor@Sun.COM ddv->sdev_path, nm)); 389*10588SEric.Taylor@Sun.COM ASSERT(strncmp(ddv->sdev_path, ZVOL_DIR, 390*10588SEric.Taylor@Sun.COM strlen(ZVOL_DIR)) == 0); 391*10588SEric.Taylor@Sun.COM *vap = *sdev_getdefault_attr(VDIR); 392*10588SEric.Taylor@Sun.COM gethrestime(&now); 393*10588SEric.Taylor@Sun.COM vap->va_atime = now; 394*10588SEric.Taylor@Sun.COM vap->va_mtime = now; 395*10588SEric.Taylor@Sun.COM vap->va_ctime = now; 396*10588SEric.Taylor@Sun.COM return (0); 397*10588SEric.Taylor@Sun.COM } 398*10588SEric.Taylor@Sun.COM 399*10588SEric.Taylor@Sun.COM /*ARGSUSED3*/ 400*10588SEric.Taylor@Sun.COM static int 401*10588SEric.Taylor@Sun.COM devzvol_create_link(struct sdev_node *ddv, char *nm, 402*10588SEric.Taylor@Sun.COM void **arg, cred_t *cred, void *whatever, char *whichever) 403*10588SEric.Taylor@Sun.COM { 404*10588SEric.Taylor@Sun.COM minor_t minor; 405*10588SEric.Taylor@Sun.COM char *pathname = (char *)*arg; 406*10588SEric.Taylor@Sun.COM int rc; 407*10588SEric.Taylor@Sun.COM char *dsname; 408*10588SEric.Taylor@Sun.COM char *x; 409*10588SEric.Taylor@Sun.COM char str[MAXNAMELEN]; 410*10588SEric.Taylor@Sun.COM sdcmn_err13(("create_link (%s) (%s) '%s'", ddv->sdev_name, 411*10588SEric.Taylor@Sun.COM ddv->sdev_path, nm)); 412*10588SEric.Taylor@Sun.COM dsname = devzvol_make_dsname(ddv->sdev_path, nm); 413*10588SEric.Taylor@Sun.COM rc = sdev_zvol_create_minor(dsname); 414*10588SEric.Taylor@Sun.COM if ((rc != 0 && rc != EEXIST && rc != EBUSY) || 415*10588SEric.Taylor@Sun.COM sdev_zvol_name2minor(dsname, &minor)) { 416*10588SEric.Taylor@Sun.COM sdcmn_err13(("devzvol_create_link %d", rc)); 417*10588SEric.Taylor@Sun.COM kmem_free(dsname, strlen(dsname) + 1); 418*10588SEric.Taylor@Sun.COM return (-1); 419*10588SEric.Taylor@Sun.COM } 420*10588SEric.Taylor@Sun.COM kmem_free(dsname, strlen(dsname) + 1); 421*10588SEric.Taylor@Sun.COM 422*10588SEric.Taylor@Sun.COM /* 423*10588SEric.Taylor@Sun.COM * This is a valid zvol; create a symlink that points to the 424*10588SEric.Taylor@Sun.COM * minor which was created under /devices/pseudo/zfs@0 425*10588SEric.Taylor@Sun.COM */ 426*10588SEric.Taylor@Sun.COM *pathname = '\0'; 427*10588SEric.Taylor@Sun.COM for (x = ddv->sdev_path; x = strchr(x, '/'); x++) 428*10588SEric.Taylor@Sun.COM (void) strcat(pathname, "../"); 429*10588SEric.Taylor@Sun.COM (void) snprintf(str, sizeof (str), ZVOL_PSEUDO_DEV "%u", minor); 430*10588SEric.Taylor@Sun.COM (void) strncat(pathname, str, MAXPATHLEN); 431*10588SEric.Taylor@Sun.COM if (strncmp(ddv->sdev_path, ZVOL_FULL_RDEV_DIR, 432*10588SEric.Taylor@Sun.COM strlen(ZVOL_FULL_RDEV_DIR)) == 0) 433*10588SEric.Taylor@Sun.COM (void) strcat(pathname, ",raw"); 434*10588SEric.Taylor@Sun.COM return (0); 435*10588SEric.Taylor@Sun.COM } 436*10588SEric.Taylor@Sun.COM 437*10588SEric.Taylor@Sun.COM /* Clean zvol sdev_nodes that are no longer valid. */ 438*10588SEric.Taylor@Sun.COM static void 439*10588SEric.Taylor@Sun.COM devzvol_prunedir(struct sdev_node *ddv) 440*10588SEric.Taylor@Sun.COM { 441*10588SEric.Taylor@Sun.COM struct sdev_node *dv; 442*10588SEric.Taylor@Sun.COM 443*10588SEric.Taylor@Sun.COM ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 444*10588SEric.Taylor@Sun.COM 445*10588SEric.Taylor@Sun.COM sdcmn_err13(("prunedir '%s'", ddv->sdev_name)); 446*10588SEric.Taylor@Sun.COM ASSERT(strncmp(ddv->sdev_path, ZVOL_DIR, strlen(ZVOL_DIR)) == 0); 447*10588SEric.Taylor@Sun.COM if (rw_tryupgrade(&ddv->sdev_contents) == 0) { 448*10588SEric.Taylor@Sun.COM rw_exit(&ddv->sdev_contents); 449*10588SEric.Taylor@Sun.COM rw_enter(&ddv->sdev_contents, RW_WRITER); 450*10588SEric.Taylor@Sun.COM } 451*10588SEric.Taylor@Sun.COM 452*10588SEric.Taylor@Sun.COM dv = SDEV_FIRST_ENTRY(ddv); 453*10588SEric.Taylor@Sun.COM while (dv) { 454*10588SEric.Taylor@Sun.COM sdcmn_err13(("sdev_name '%s'", dv->sdev_name)); 455*10588SEric.Taylor@Sun.COM /* skip stale nodes */ 456*10588SEric.Taylor@Sun.COM if (dv->sdev_flags & SDEV_STALE) { 457*10588SEric.Taylor@Sun.COM sdcmn_err13((" stale")); 458*10588SEric.Taylor@Sun.COM dv = SDEV_NEXT_ENTRY(ddv, dv); 459*10588SEric.Taylor@Sun.COM continue; 460*10588SEric.Taylor@Sun.COM } 461*10588SEric.Taylor@Sun.COM 462*10588SEric.Taylor@Sun.COM switch (devzvol_validate(dv)) { 463*10588SEric.Taylor@Sun.COM case SDEV_VTOR_VALID: 464*10588SEric.Taylor@Sun.COM case SDEV_VTOR_SKIP: 465*10588SEric.Taylor@Sun.COM dv = SDEV_NEXT_ENTRY(ddv, dv); 466*10588SEric.Taylor@Sun.COM continue; 467*10588SEric.Taylor@Sun.COM case SDEV_VTOR_INVALID: 468*10588SEric.Taylor@Sun.COM sdcmn_err7(("prunedir: destroy invalid " 469*10588SEric.Taylor@Sun.COM "node: %s\n", dv->sdev_name)); 470*10588SEric.Taylor@Sun.COM break; 471*10588SEric.Taylor@Sun.COM } 472*10588SEric.Taylor@Sun.COM 473*10588SEric.Taylor@Sun.COM if ((SDEVTOV(dv)->v_type == VDIR) && 474*10588SEric.Taylor@Sun.COM (sdev_cleandir(dv, NULL, 0) != 0)) { 475*10588SEric.Taylor@Sun.COM dv = SDEV_NEXT_ENTRY(ddv, dv); 476*10588SEric.Taylor@Sun.COM continue; 477*10588SEric.Taylor@Sun.COM } 478*10588SEric.Taylor@Sun.COM SDEV_HOLD(dv); 479*10588SEric.Taylor@Sun.COM /* remove the cache node */ 480*10588SEric.Taylor@Sun.COM if (sdev_cache_update(ddv, &dv, dv->sdev_name, 481*10588SEric.Taylor@Sun.COM SDEV_CACHE_DELETE) == 0) 482*10588SEric.Taylor@Sun.COM dv = SDEV_FIRST_ENTRY(ddv); 483*10588SEric.Taylor@Sun.COM else 484*10588SEric.Taylor@Sun.COM dv = SDEV_NEXT_ENTRY(ddv, dv); 485*10588SEric.Taylor@Sun.COM } 486*10588SEric.Taylor@Sun.COM rw_downgrade(&ddv->sdev_contents); 487*10588SEric.Taylor@Sun.COM } 488*10588SEric.Taylor@Sun.COM 489*10588SEric.Taylor@Sun.COM /*ARGSUSED*/ 490*10588SEric.Taylor@Sun.COM static int 491*10588SEric.Taylor@Sun.COM devzvol_lookup(struct vnode *dvp, char *nm, struct vnode **vpp, 492*10588SEric.Taylor@Sun.COM struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred, 493*10588SEric.Taylor@Sun.COM caller_context_t *ct, int *direntflags, pathname_t *realpnp) 494*10588SEric.Taylor@Sun.COM { 495*10588SEric.Taylor@Sun.COM enum vtype expected_type = VDIR; 496*10588SEric.Taylor@Sun.COM struct sdev_node *parent = VTOSDEV(dvp); 497*10588SEric.Taylor@Sun.COM char *dsname; 498*10588SEric.Taylor@Sun.COM dmu_objset_type_t do_type; 499*10588SEric.Taylor@Sun.COM int error; 500*10588SEric.Taylor@Sun.COM 501*10588SEric.Taylor@Sun.COM sdcmn_err13(("devzvol_lookup '%s' '%s'", parent->sdev_path, nm)); 502*10588SEric.Taylor@Sun.COM *vpp = NULL; 503*10588SEric.Taylor@Sun.COM /* execute access is required to search the directory */ 504*10588SEric.Taylor@Sun.COM if ((error = VOP_ACCESS(dvp, VEXEC, 0, cred, ct)) != 0) 505*10588SEric.Taylor@Sun.COM return (error); 506*10588SEric.Taylor@Sun.COM 507*10588SEric.Taylor@Sun.COM rw_enter(&parent->sdev_contents, RW_READER); 508*10588SEric.Taylor@Sun.COM if (!SDEV_IS_GLOBAL(parent)) { 509*10588SEric.Taylor@Sun.COM rw_exit(&parent->sdev_contents); 510*10588SEric.Taylor@Sun.COM return (prof_lookup(dvp, nm, vpp, cred)); 511*10588SEric.Taylor@Sun.COM } 512*10588SEric.Taylor@Sun.COM 513*10588SEric.Taylor@Sun.COM dsname = devzvol_make_dsname(parent->sdev_path, nm); 514*10588SEric.Taylor@Sun.COM rw_exit(&parent->sdev_contents); 515*10588SEric.Taylor@Sun.COM sdcmn_err13(("rvp dsname %s", dsname ? dsname : "(null)")); 516*10588SEric.Taylor@Sun.COM if (dsname) { 517*10588SEric.Taylor@Sun.COM error = devzvol_objset_check(dsname, &do_type); 518*10588SEric.Taylor@Sun.COM if (error != 0) { 519*10588SEric.Taylor@Sun.COM error = ENOENT; 520*10588SEric.Taylor@Sun.COM goto out; 521*10588SEric.Taylor@Sun.COM } 522*10588SEric.Taylor@Sun.COM if (do_type == DMU_OST_ZVOL) 523*10588SEric.Taylor@Sun.COM expected_type = VLNK; 524*10588SEric.Taylor@Sun.COM } 525*10588SEric.Taylor@Sun.COM /* 526*10588SEric.Taylor@Sun.COM * the callbacks expect: 527*10588SEric.Taylor@Sun.COM * 528*10588SEric.Taylor@Sun.COM * parent->sdev_path nm 529*10588SEric.Taylor@Sun.COM * /dev/zvol {r}dsk 530*10588SEric.Taylor@Sun.COM * /dev/zvol/{r}dsk <pool name> 531*10588SEric.Taylor@Sun.COM * /dev/zvol/{r}dsk/<dataset name> <last ds component> 532*10588SEric.Taylor@Sun.COM * 533*10588SEric.Taylor@Sun.COM * sdev_name is always last path component of sdev_path 534*10588SEric.Taylor@Sun.COM */ 535*10588SEric.Taylor@Sun.COM if (expected_type == VDIR) { 536*10588SEric.Taylor@Sun.COM error = devname_lookup_func(parent, nm, vpp, cred, 537*10588SEric.Taylor@Sun.COM devzvol_create_dir, SDEV_VATTR); 538*10588SEric.Taylor@Sun.COM } else { 539*10588SEric.Taylor@Sun.COM error = devname_lookup_func(parent, nm, vpp, cred, 540*10588SEric.Taylor@Sun.COM devzvol_create_link, SDEV_VLINK); 541*10588SEric.Taylor@Sun.COM } 542*10588SEric.Taylor@Sun.COM sdcmn_err13(("devzvol_lookup %d %d", expected_type, error)); 543*10588SEric.Taylor@Sun.COM ASSERT(error || ((*vpp)->v_type == expected_type)); 544*10588SEric.Taylor@Sun.COM out: 545*10588SEric.Taylor@Sun.COM if (dsname) 546*10588SEric.Taylor@Sun.COM kmem_free(dsname, strlen(dsname) + 1); 547*10588SEric.Taylor@Sun.COM sdcmn_err13(("devzvol_lookup %d", error)); 548*10588SEric.Taylor@Sun.COM return (error); 549*10588SEric.Taylor@Sun.COM } 550*10588SEric.Taylor@Sun.COM 551*10588SEric.Taylor@Sun.COM /* 552*10588SEric.Taylor@Sun.COM * We allow create to find existing nodes 553*10588SEric.Taylor@Sun.COM * - if the node doesn't exist - EROFS 554*10588SEric.Taylor@Sun.COM * - creating an existing dir read-only succeeds, otherwise EISDIR 555*10588SEric.Taylor@Sun.COM * - exclusive creates fail - EEXIST 556*10588SEric.Taylor@Sun.COM */ 557*10588SEric.Taylor@Sun.COM /*ARGSUSED2*/ 558*10588SEric.Taylor@Sun.COM static int 559*10588SEric.Taylor@Sun.COM devzvol_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl, 560*10588SEric.Taylor@Sun.COM int mode, struct vnode **vpp, struct cred *cred, int flag, 561*10588SEric.Taylor@Sun.COM caller_context_t *ct, vsecattr_t *vsecp) 562*10588SEric.Taylor@Sun.COM { 563*10588SEric.Taylor@Sun.COM int error; 564*10588SEric.Taylor@Sun.COM struct vnode *vp; 565*10588SEric.Taylor@Sun.COM 566*10588SEric.Taylor@Sun.COM *vpp = NULL; 567*10588SEric.Taylor@Sun.COM 568*10588SEric.Taylor@Sun.COM error = devzvol_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL, 569*10588SEric.Taylor@Sun.COM NULL); 570*10588SEric.Taylor@Sun.COM if (error == 0) { 571*10588SEric.Taylor@Sun.COM if (excl == EXCL) 572*10588SEric.Taylor@Sun.COM error = EEXIST; 573*10588SEric.Taylor@Sun.COM else if (vp->v_type == VDIR && (mode & VWRITE)) 574*10588SEric.Taylor@Sun.COM error = EISDIR; 575*10588SEric.Taylor@Sun.COM else 576*10588SEric.Taylor@Sun.COM error = VOP_ACCESS(vp, mode, 0, cred, ct); 577*10588SEric.Taylor@Sun.COM 578*10588SEric.Taylor@Sun.COM if (error) { 579*10588SEric.Taylor@Sun.COM VN_RELE(vp); 580*10588SEric.Taylor@Sun.COM } else 581*10588SEric.Taylor@Sun.COM *vpp = vp; 582*10588SEric.Taylor@Sun.COM } else if (error == ENOENT) { 583*10588SEric.Taylor@Sun.COM error = EROFS; 584*10588SEric.Taylor@Sun.COM } 585*10588SEric.Taylor@Sun.COM 586*10588SEric.Taylor@Sun.COM return (error); 587*10588SEric.Taylor@Sun.COM } 588*10588SEric.Taylor@Sun.COM 589*10588SEric.Taylor@Sun.COM void sdev_iter_snapshots(struct vnode *dvp, char *name); 590*10588SEric.Taylor@Sun.COM 591*10588SEric.Taylor@Sun.COM void 592*10588SEric.Taylor@Sun.COM sdev_iter_datasets(struct vnode *dvp, int arg, char *name) 593*10588SEric.Taylor@Sun.COM { 594*10588SEric.Taylor@Sun.COM zfs_cmd_t *zc; 595*10588SEric.Taylor@Sun.COM int rc; 596*10588SEric.Taylor@Sun.COM 597*10588SEric.Taylor@Sun.COM sdcmn_err13(("iter name is '%s' (arg %x)", name, arg)); 598*10588SEric.Taylor@Sun.COM zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); 599*10588SEric.Taylor@Sun.COM (void) strcpy(zc->zc_name, name); 600*10588SEric.Taylor@Sun.COM 601*10588SEric.Taylor@Sun.COM while ((rc = devzvol_handle_ioctl(arg, zc, B_FALSE)) == 0) { 602*10588SEric.Taylor@Sun.COM struct vnode *vpp; 603*10588SEric.Taylor@Sun.COM char *ptr; 604*10588SEric.Taylor@Sun.COM 605*10588SEric.Taylor@Sun.COM sdcmn_err13((" name %s", zc->zc_name)); 606*10588SEric.Taylor@Sun.COM if (strchr(zc->zc_name, '$') || strchr(zc->zc_name, '%')) 607*10588SEric.Taylor@Sun.COM goto skip; 608*10588SEric.Taylor@Sun.COM ptr = strrchr(zc->zc_name, '/') + 1; 609*10588SEric.Taylor@Sun.COM rc = devzvol_lookup(dvp, ptr, &vpp, NULL, 0, NULL, 610*10588SEric.Taylor@Sun.COM kcred, NULL, NULL, NULL); 611*10588SEric.Taylor@Sun.COM if (rc == 0) { 612*10588SEric.Taylor@Sun.COM VN_RELE(vpp); 613*10588SEric.Taylor@Sun.COM } else if (rc == ENOENT) { 614*10588SEric.Taylor@Sun.COM goto skip; 615*10588SEric.Taylor@Sun.COM } else { 616*10588SEric.Taylor@Sun.COM /* EBUSY == problem with zvols's dmu holds? */ 617*10588SEric.Taylor@Sun.COM ASSERT(0); 618*10588SEric.Taylor@Sun.COM goto skip; 619*10588SEric.Taylor@Sun.COM } 620*10588SEric.Taylor@Sun.COM if (arg == ZFS_IOC_DATASET_LIST_NEXT && 621*10588SEric.Taylor@Sun.COM zc->zc_objset_stats.dds_type != DMU_OST_ZFS) 622*10588SEric.Taylor@Sun.COM sdev_iter_snapshots(dvp, zc->zc_name); 623*10588SEric.Taylor@Sun.COM skip: 624*10588SEric.Taylor@Sun.COM (void) strcpy(zc->zc_name, name); 625*10588SEric.Taylor@Sun.COM } 626*10588SEric.Taylor@Sun.COM kmem_free(zc, sizeof (zfs_cmd_t)); 627*10588SEric.Taylor@Sun.COM } 628*10588SEric.Taylor@Sun.COM 629*10588SEric.Taylor@Sun.COM void 630*10588SEric.Taylor@Sun.COM sdev_iter_snapshots(struct vnode *dvp, char *name) 631*10588SEric.Taylor@Sun.COM { 632*10588SEric.Taylor@Sun.COM sdev_iter_datasets(dvp, ZFS_IOC_SNAPSHOT_LIST_NEXT, name); 633*10588SEric.Taylor@Sun.COM } 634*10588SEric.Taylor@Sun.COM 635*10588SEric.Taylor@Sun.COM /*ARGSUSED4*/ 636*10588SEric.Taylor@Sun.COM static int 637*10588SEric.Taylor@Sun.COM devzvol_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, 638*10588SEric.Taylor@Sun.COM int *eofp, caller_context_t *ct_unused, int flags_unused) 639*10588SEric.Taylor@Sun.COM { 640*10588SEric.Taylor@Sun.COM struct sdev_node *sdvp = VTOSDEV(dvp); 641*10588SEric.Taylor@Sun.COM char *ptr; 642*10588SEric.Taylor@Sun.COM 643*10588SEric.Taylor@Sun.COM sdcmn_err13(("zv readdir of '%s' %s'", sdvp->sdev_path, 644*10588SEric.Taylor@Sun.COM sdvp->sdev_name)); 645*10588SEric.Taylor@Sun.COM 646*10588SEric.Taylor@Sun.COM if (strcmp(sdvp->sdev_path, ZVOL_DIR) == 0) { 647*10588SEric.Taylor@Sun.COM struct vnode *vp; 648*10588SEric.Taylor@Sun.COM 649*10588SEric.Taylor@Sun.COM rw_exit(&sdvp->sdev_contents); 650*10588SEric.Taylor@Sun.COM (void) devname_lookup_func(sdvp, "dsk", &vp, cred, 651*10588SEric.Taylor@Sun.COM devzvol_create_dir, SDEV_VATTR); 652*10588SEric.Taylor@Sun.COM VN_RELE(vp); 653*10588SEric.Taylor@Sun.COM (void) devname_lookup_func(sdvp, "rdsk", &vp, cred, 654*10588SEric.Taylor@Sun.COM devzvol_create_dir, SDEV_VATTR); 655*10588SEric.Taylor@Sun.COM VN_RELE(vp); 656*10588SEric.Taylor@Sun.COM rw_enter(&sdvp->sdev_contents, RW_READER); 657*10588SEric.Taylor@Sun.COM return (devname_readdir_func(dvp, uiop, cred, eofp, 0)); 658*10588SEric.Taylor@Sun.COM } 659*10588SEric.Taylor@Sun.COM if (uiop->uio_offset == 0) 660*10588SEric.Taylor@Sun.COM devzvol_prunedir(sdvp); 661*10588SEric.Taylor@Sun.COM ptr = sdvp->sdev_path + strlen(ZVOL_DIR); 662*10588SEric.Taylor@Sun.COM if ((strcmp(ptr, "/dsk") == 0) || (strcmp(ptr, "/rdsk") == 0)) { 663*10588SEric.Taylor@Sun.COM rw_exit(&sdvp->sdev_contents); 664*10588SEric.Taylor@Sun.COM devzvol_create_pool_dirs(dvp); 665*10588SEric.Taylor@Sun.COM rw_enter(&sdvp->sdev_contents, RW_READER); 666*10588SEric.Taylor@Sun.COM return (devname_readdir_func(dvp, uiop, cred, eofp, 0)); 667*10588SEric.Taylor@Sun.COM } 668*10588SEric.Taylor@Sun.COM 669*10588SEric.Taylor@Sun.COM ptr = strchr(ptr + 1, '/') + 1; 670*10588SEric.Taylor@Sun.COM rw_exit(&sdvp->sdev_contents); 671*10588SEric.Taylor@Sun.COM sdev_iter_datasets(dvp, ZFS_IOC_DATASET_LIST_NEXT, ptr); 672*10588SEric.Taylor@Sun.COM rw_enter(&sdvp->sdev_contents, RW_READER); 673*10588SEric.Taylor@Sun.COM return (devname_readdir_func(dvp, uiop, cred, eofp, 0)); 674*10588SEric.Taylor@Sun.COM } 675*10588SEric.Taylor@Sun.COM 676*10588SEric.Taylor@Sun.COM const fs_operation_def_t devzvol_vnodeops_tbl[] = { 677*10588SEric.Taylor@Sun.COM VOPNAME_READDIR, { .vop_readdir = devzvol_readdir }, 678*10588SEric.Taylor@Sun.COM VOPNAME_LOOKUP, { .vop_lookup = devzvol_lookup }, 679*10588SEric.Taylor@Sun.COM VOPNAME_CREATE, { .vop_create = devzvol_create }, 680*10588SEric.Taylor@Sun.COM VOPNAME_RENAME, { .error = fs_nosys }, 681*10588SEric.Taylor@Sun.COM VOPNAME_MKDIR, { .error = fs_nosys }, 682*10588SEric.Taylor@Sun.COM VOPNAME_RMDIR, { .error = fs_nosys }, 683*10588SEric.Taylor@Sun.COM VOPNAME_REMOVE, { .error = fs_nosys }, 684*10588SEric.Taylor@Sun.COM VOPNAME_SYMLINK, { .error = fs_nosys }, 685*10588SEric.Taylor@Sun.COM NULL, NULL 686*10588SEric.Taylor@Sun.COM }; 687