1b127ac41SPhilip Kirk /* 2b127ac41SPhilip Kirk * CDDL HEADER START 3b127ac41SPhilip Kirk * 4b127ac41SPhilip Kirk * The contents of this file are subject to the terms of the 5b127ac41SPhilip Kirk * Common Development and Distribution License (the "License"). 6b127ac41SPhilip Kirk * You may not use this file except in compliance with the License. 7b127ac41SPhilip Kirk * 8b127ac41SPhilip Kirk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9b127ac41SPhilip Kirk * or http://www.opensolaris.org/os/licensing. 10b127ac41SPhilip Kirk * See the License for the specific language governing permissions 11b127ac41SPhilip Kirk * and limitations under the License. 12b127ac41SPhilip Kirk * 13b127ac41SPhilip Kirk * When distributing Covered Code, include this CDDL HEADER in each 14b127ac41SPhilip Kirk * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15b127ac41SPhilip Kirk * If applicable, add the following below this CDDL HEADER, with the 16b127ac41SPhilip Kirk * fields enclosed by brackets "[]" replaced with your own identifying 17b127ac41SPhilip Kirk * information: Portions Copyright [yyyy] [name of copyright owner] 18b127ac41SPhilip Kirk * 19b127ac41SPhilip Kirk * CDDL HEADER END 20b127ac41SPhilip Kirk */ 21b127ac41SPhilip Kirk /* 22b127ac41SPhilip Kirk * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23b127ac41SPhilip Kirk * Use is subject to license terms. 24b127ac41SPhilip Kirk */ 25b127ac41SPhilip Kirk 26b127ac41SPhilip Kirk /* 27b127ac41SPhilip Kirk * vnode ops for the /dev/ipnet directory 28b127ac41SPhilip Kirk * The lookup is based on the ipnetif nodes held 29b127ac41SPhilip Kirk * in the ipnet module. We also override readdir 30b127ac41SPhilip Kirk * in order to delete ipnet nodes no longer in use. 31b127ac41SPhilip Kirk */ 32b127ac41SPhilip Kirk 33b127ac41SPhilip Kirk #include <sys/types.h> 34b127ac41SPhilip Kirk #include <sys/param.h> 35b127ac41SPhilip Kirk #include <sys/sysmacros.h> 36b127ac41SPhilip Kirk #include <sys/sunndi.h> 37b127ac41SPhilip Kirk #include <fs/fs_subr.h> 38b127ac41SPhilip Kirk #include <sys/fs/dv_node.h> 39b127ac41SPhilip Kirk #include <sys/fs/sdev_impl.h> 40b127ac41SPhilip Kirk #include <sys/policy.h> 41b127ac41SPhilip Kirk #include <inet/ipnet.h> 42b127ac41SPhilip Kirk #include <sys/zone.h> 43b127ac41SPhilip Kirk 44b127ac41SPhilip Kirk struct vnodeops *devipnet_vnodeops; 45b127ac41SPhilip Kirk 46b127ac41SPhilip Kirk static void 47b127ac41SPhilip Kirk devipnet_fill_vattr(struct vattr *vap, dev_t dev) 48b127ac41SPhilip Kirk { 49b127ac41SPhilip Kirk timestruc_t now; 50b127ac41SPhilip Kirk 51b127ac41SPhilip Kirk *vap = sdev_vattr_chr; 52b127ac41SPhilip Kirk vap->va_rdev = dev; 53b127ac41SPhilip Kirk vap->va_mode |= 0666; 54b127ac41SPhilip Kirk 55b127ac41SPhilip Kirk gethrestime(&now); 56b127ac41SPhilip Kirk vap->va_atime = now; 57b127ac41SPhilip Kirk vap->va_mtime = now; 58b127ac41SPhilip Kirk vap->va_ctime = now; 59b127ac41SPhilip Kirk } 60b127ac41SPhilip Kirk 61b127ac41SPhilip Kirk /* 62b127ac41SPhilip Kirk * Check if an ipnet sdev_node is still valid. 63b127ac41SPhilip Kirk */ 64b127ac41SPhilip Kirk int 65b127ac41SPhilip Kirk devipnet_validate(struct sdev_node *dv) 66b127ac41SPhilip Kirk { 67b127ac41SPhilip Kirk dev_t dev; 68b127ac41SPhilip Kirk 69b127ac41SPhilip Kirk dev = ipnet_if_getdev(dv->sdev_name, getzoneid()); 70b127ac41SPhilip Kirk if (dev == (dev_t)-1) 71b127ac41SPhilip Kirk return (SDEV_VTOR_INVALID); 72b127ac41SPhilip Kirk if (getminor(SDEVTOV(dv)->v_rdev) != getminor(dev)) 73b127ac41SPhilip Kirk return (SDEV_VTOR_STALE); 74b127ac41SPhilip Kirk return (SDEV_VTOR_VALID); 75b127ac41SPhilip Kirk } 76b127ac41SPhilip Kirk 77b127ac41SPhilip Kirk /* 78b127ac41SPhilip Kirk * This callback is invoked from devname_lookup_func() to create 79b127ac41SPhilip Kirk * an ipnet entry when the node is not found in the cache. 80b127ac41SPhilip Kirk */ 81b127ac41SPhilip Kirk /*ARGSUSED*/ 82b127ac41SPhilip Kirk static int 83b127ac41SPhilip Kirk devipnet_create_rvp(struct sdev_node *ddv, char *nm, 84b127ac41SPhilip Kirk void **arg, cred_t *cred, void *whatever, char *whichever) 85b127ac41SPhilip Kirk { 86b127ac41SPhilip Kirk dev_t dev; 87b127ac41SPhilip Kirk struct vattr *vap = (struct vattr *)arg; 88b127ac41SPhilip Kirk int err = 0; 89b127ac41SPhilip Kirk 90b127ac41SPhilip Kirk if ((dev = ipnet_if_getdev(nm, getzoneid())) == (dev_t)-1) 91b127ac41SPhilip Kirk err = ENOENT; 92b127ac41SPhilip Kirk else 93b127ac41SPhilip Kirk devipnet_fill_vattr(vap, dev); 94b127ac41SPhilip Kirk 95b127ac41SPhilip Kirk return (err); 96b127ac41SPhilip Kirk } 97b127ac41SPhilip Kirk 98b127ac41SPhilip Kirk /* 99b127ac41SPhilip Kirk * Lookup for /dev/ipnet directory 100b127ac41SPhilip Kirk * If the entry does not exist, the devipnet_create_rvp() callback 101b127ac41SPhilip Kirk * is invoked to create it. Nodes do not persist across reboot. 102b127ac41SPhilip Kirk */ 103b127ac41SPhilip Kirk /*ARGSUSED3*/ 104b127ac41SPhilip Kirk static int 105b127ac41SPhilip Kirk devipnet_lookup(struct vnode *dvp, char *nm, struct vnode **vpp, 106b127ac41SPhilip Kirk struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred, 107b127ac41SPhilip Kirk caller_context_t *ct, int *direntflags, pathname_t *realpnp) 108b127ac41SPhilip Kirk { 109b127ac41SPhilip Kirk struct sdev_node *sdvp = VTOSDEV(dvp); 110b127ac41SPhilip Kirk struct sdev_node *dv; 111b127ac41SPhilip Kirk struct vnode *rvp = NULL; 112b127ac41SPhilip Kirk int error; 113b127ac41SPhilip Kirk 114b127ac41SPhilip Kirk error = devname_lookup_func(sdvp, nm, vpp, cred, devipnet_create_rvp, 115b127ac41SPhilip Kirk SDEV_VATTR); 116b127ac41SPhilip Kirk 117b127ac41SPhilip Kirk if (error == 0) { 118b127ac41SPhilip Kirk switch ((*vpp)->v_type) { 119b127ac41SPhilip Kirk case VCHR: 120b127ac41SPhilip Kirk dv = VTOSDEV(VTOS(*vpp)->s_realvp); 121b127ac41SPhilip Kirk ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS); 122b127ac41SPhilip Kirk break; 123b127ac41SPhilip Kirk case VDIR: 124b127ac41SPhilip Kirk dv = VTOSDEV(*vpp); 125b127ac41SPhilip Kirk break; 126b127ac41SPhilip Kirk default: 127b127ac41SPhilip Kirk cmn_err(CE_PANIC, "devipnet_lookup: Unsupported node " 128b127ac41SPhilip Kirk "type: %p: %d", (void *)(*vpp), (*vpp)->v_type); 129b127ac41SPhilip Kirk break; 130b127ac41SPhilip Kirk } 131b127ac41SPhilip Kirk ASSERT(SDEV_HELD(dv)); 132b127ac41SPhilip Kirk } 133b127ac41SPhilip Kirk 134b127ac41SPhilip Kirk return (error); 135b127ac41SPhilip Kirk } 136b127ac41SPhilip Kirk 137b127ac41SPhilip Kirk static void 138b127ac41SPhilip Kirk devipnet_filldir_entry(const char *name, void *arg, dev_t dev) 139b127ac41SPhilip Kirk { 140b127ac41SPhilip Kirk struct sdev_node *ddv = arg; 141b127ac41SPhilip Kirk struct vattr vattr; 142b127ac41SPhilip Kirk struct sdev_node *dv; 143b127ac41SPhilip Kirk 144b127ac41SPhilip Kirk ASSERT(RW_WRITE_HELD(&ddv->sdev_contents)); 145b127ac41SPhilip Kirk 146b127ac41SPhilip Kirk if ((dv = sdev_cache_lookup(ddv, (char *)name)) == NULL) { 147b127ac41SPhilip Kirk devipnet_fill_vattr(&vattr, dev); 148b127ac41SPhilip Kirk if (sdev_mknode(ddv, (char *)name, &dv, &vattr, NULL, NULL, 149b127ac41SPhilip Kirk kcred, SDEV_READY) != 0) 150b127ac41SPhilip Kirk return; 151b127ac41SPhilip Kirk } 152b127ac41SPhilip Kirk SDEV_SIMPLE_RELE(dv); 153b127ac41SPhilip Kirk } 154b127ac41SPhilip Kirk 155b127ac41SPhilip Kirk static void 156b127ac41SPhilip Kirk devipnet_filldir(struct sdev_node *ddv) 157b127ac41SPhilip Kirk { 158b127ac41SPhilip Kirk sdev_node_t *dv, *next; 159b127ac41SPhilip Kirk 160b127ac41SPhilip Kirk ASSERT(RW_READ_HELD(&ddv->sdev_contents)); 161b127ac41SPhilip Kirk if (rw_tryupgrade(&ddv->sdev_contents) == NULL) { 162b127ac41SPhilip Kirk rw_exit(&ddv->sdev_contents); 163b127ac41SPhilip Kirk rw_enter(&ddv->sdev_contents, RW_WRITER); 164*9e5aa9d8SRobert Mustacchi /* 165*9e5aa9d8SRobert Mustacchi * We've been made a zombie while we weren't looking. We'll bail 166*9e5aa9d8SRobert Mustacchi * if that's the case. 167*9e5aa9d8SRobert Mustacchi */ 168*9e5aa9d8SRobert Mustacchi if (ddv->sdev_state == SDEV_ZOMBIE) { 169*9e5aa9d8SRobert Mustacchi rw_exit(&ddv->sdev_contents); 170*9e5aa9d8SRobert Mustacchi return; 171*9e5aa9d8SRobert Mustacchi } 172b127ac41SPhilip Kirk } 173b127ac41SPhilip Kirk 174b127ac41SPhilip Kirk for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) { 175b127ac41SPhilip Kirk next = SDEV_NEXT_ENTRY(ddv, dv); 176b127ac41SPhilip Kirk 177b127ac41SPhilip Kirk /* validate and prune only ready nodes */ 178b127ac41SPhilip Kirk if (dv->sdev_state != SDEV_READY) 179b127ac41SPhilip Kirk continue; 180b127ac41SPhilip Kirk switch (devipnet_validate(dv)) { 181b127ac41SPhilip Kirk case SDEV_VTOR_VALID: 182b127ac41SPhilip Kirk case SDEV_VTOR_SKIP: 183b127ac41SPhilip Kirk continue; 184b127ac41SPhilip Kirk case SDEV_VTOR_INVALID: 185b127ac41SPhilip Kirk case SDEV_VTOR_STALE: 186b127ac41SPhilip Kirk sdcmn_err12(("devipnet_filldir: destroy invalid " 187b127ac41SPhilip Kirk "node: %s(%p)\n", dv->sdev_name, (void *)dv)); 188b127ac41SPhilip Kirk break; 189b127ac41SPhilip Kirk } 190b127ac41SPhilip Kirk 191b127ac41SPhilip Kirk if (SDEVTOV(dv)->v_count > 0) 192b127ac41SPhilip Kirk continue; 193b127ac41SPhilip Kirk SDEV_HOLD(dv); 194b127ac41SPhilip Kirk /* remove the cache node */ 195b127ac41SPhilip Kirk (void) sdev_cache_update(ddv, &dv, dv->sdev_name, 196b127ac41SPhilip Kirk SDEV_CACHE_DELETE); 197*9e5aa9d8SRobert Mustacchi SDEV_RELE(dv); 198b127ac41SPhilip Kirk } 199b127ac41SPhilip Kirk 200b127ac41SPhilip Kirk ipnet_walk_if(devipnet_filldir_entry, ddv, getzoneid()); 201b127ac41SPhilip Kirk 202b127ac41SPhilip Kirk rw_downgrade(&ddv->sdev_contents); 203b127ac41SPhilip Kirk } 204b127ac41SPhilip Kirk 205b127ac41SPhilip Kirk /* 206b127ac41SPhilip Kirk * Display all instantiated ipnet device nodes. 207b127ac41SPhilip Kirk */ 208b127ac41SPhilip Kirk /* ARGSUSED */ 209b127ac41SPhilip Kirk static int 210b127ac41SPhilip Kirk devipnet_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, 211b127ac41SPhilip Kirk int *eofp, caller_context_t *ct, int flags) 212b127ac41SPhilip Kirk { 213b127ac41SPhilip Kirk struct sdev_node *sdvp = VTOSDEV(dvp); 214b127ac41SPhilip Kirk 215b127ac41SPhilip Kirk if (uiop->uio_offset == 0) 216b127ac41SPhilip Kirk devipnet_filldir(sdvp); 217b127ac41SPhilip Kirk 218b127ac41SPhilip Kirk return (devname_readdir_func(dvp, uiop, cred, eofp, 0)); 219b127ac41SPhilip Kirk } 220b127ac41SPhilip Kirk 221b127ac41SPhilip Kirk /* 222b127ac41SPhilip Kirk * We override lookup and readdir to build entries based on the 223b127ac41SPhilip Kirk * in kernel ipnet table. 224b127ac41SPhilip Kirk */ 225b127ac41SPhilip Kirk const fs_operation_def_t devipnet_vnodeops_tbl[] = { 226b127ac41SPhilip Kirk VOPNAME_READDIR, { .vop_readdir = devipnet_readdir }, 227b127ac41SPhilip Kirk VOPNAME_LOOKUP, { .vop_lookup = devipnet_lookup }, 228b127ac41SPhilip Kirk VOPNAME_CREATE, { .error = fs_nosys }, 229b127ac41SPhilip Kirk VOPNAME_REMOVE, { .error = fs_nosys }, 230b127ac41SPhilip Kirk VOPNAME_MKDIR, { .error = fs_nosys }, 231b127ac41SPhilip Kirk VOPNAME_RMDIR, { .error = fs_nosys }, 232b127ac41SPhilip Kirk VOPNAME_SYMLINK, { .error = fs_nosys }, 233b127ac41SPhilip Kirk VOPNAME_SETSECATTR, { .error = fs_nosys }, 234b127ac41SPhilip Kirk NULL, NULL 235b127ac41SPhilip Kirk }; 236