Home | History | Annotate | Download | only in dev
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * vnode ops for the /dev/vt directory
     28  */
     29 
     30 #include <sys/types.h>
     31 #include <sys/param.h>
     32 #include <sys/sysmacros.h>
     33 #include <sys/sunndi.h>
     34 #include <fs/fs_subr.h>
     35 #include <sys/fs/dv_node.h>
     36 #include <sys/fs/sdev_impl.h>
     37 #include <sys/policy.h>
     38 #include <sys/stat.h>
     39 #include <sys/vfs_opreg.h>
     40 #include <sys/tty.h>
     41 #include <sys/vt_impl.h>
     42 #include <sys/note.h>
     43 
     44 /* warlock in this file only cares about variables shared by vt and devfs */
     45 _NOTE(SCHEME_PROTECTS_DATA("Do not care", sdev_node vattr vnode))
     46 
     47 #define	DEVVT_UID_DEFAULT	SDEV_UID_DEFAULT
     48 #define	DEVVT_GID_DEFAULT	(0)
     49 #define	DEVVT_DEVMODE_DEFAULT	(0600)
     50 #define	DEVVT_ACTIVE_NAME	"active"
     51 
     52 #define	isdigit(ch)	((ch) >= '0' && (ch) <= '9')
     53 
     54 /* attributes for VT nodes */
     55 static vattr_t devvt_vattr = {
     56 	AT_TYPE|AT_MODE|AT_UID|AT_GID,		/* va_mask */
     57 	VCHR,					/* va_type */
     58 	S_IFCHR | DEVVT_DEVMODE_DEFAULT,	/* va_mode */
     59 	DEVVT_UID_DEFAULT,			/* va_uid */
     60 	DEVVT_GID_DEFAULT,			/* va_gid */
     61 	0					/* 0 hereafter */
     62 };
     63 
     64 struct vnodeops		*devvt_vnodeops;
     65 
     66 struct vnodeops *
     67 devvt_getvnodeops(void)
     68 {
     69 	return (devvt_vnodeops);
     70 }
     71 
     72 static int
     73 devvt_str2minor(const char *nm, minor_t *mp)
     74 {
     75 	long uminor = 0;
     76 	char *endptr = NULL;
     77 
     78 	if (nm == NULL || !isdigit(*nm))
     79 		return (EINVAL);
     80 
     81 	*mp = 0;
     82 	if (ddi_strtol(nm, &endptr, 10, &uminor) != 0 ||
     83 	    *endptr != '\0' || uminor < 0) {
     84 		return (EINVAL);
     85 	}
     86 
     87 	*mp = (minor_t)uminor;
     88 	return (0);
     89 }
     90 
     91 /*ARGSUSED*/
     92 int
     93 devvt_validate(struct sdev_node *dv)
     94 {
     95 	minor_t min;
     96 	char *nm = dv->sdev_name;
     97 
     98 	ASSERT(!(dv->sdev_flags & SDEV_STALE));
     99 	ASSERT(dv->sdev_state == SDEV_READY);
    100 
    101 	/* validate only READY nodes */
    102 	if (dv->sdev_state != SDEV_READY) {
    103 		sdcmn_err(("dev fs: skipping: node not ready %s(%p)",
    104 		    nm, (void *)dv));
    105 		return (SDEV_VTOR_SKIP);
    106 	}
    107 
    108 	if (vt_wc_attached() == (major_t)-1)
    109 		return (SDEV_VTOR_INVALID);
    110 
    111 	if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
    112 		char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
    113 
    114 		(void) vt_getactive(link, MAXPATHLEN);
    115 		if (strcmp(link, dv->sdev_symlink) != 0) {
    116 			kmem_free(dv->sdev_symlink,
    117 			    strlen(dv->sdev_symlink) + 1);
    118 			dv->sdev_symlink = i_ddi_strdup(link, KM_SLEEP);
    119 			dv->sdev_attr->va_size = strlen(link);
    120 		}
    121 		kmem_free(link, MAXPATHLEN);
    122 		return (SDEV_VTOR_VALID);
    123 	} else if (devvt_str2minor(nm, &min) != 0) {
    124 		return (SDEV_VTOR_INVALID);
    125 	}
    126 
    127 	if (vt_minor_valid(min) == B_FALSE)
    128 		return (SDEV_VTOR_INVALID);
    129 
    130 	return (SDEV_VTOR_VALID);
    131 }
    132 
    133 /*
    134  * This callback is invoked from devname_lookup_func() to create
    135  * a entry when the node is not found in the cache.
    136  */
    137 /*ARGSUSED*/
    138 static int
    139 devvt_create_rvp(struct sdev_node *ddv, char *nm,
    140     void **arg, cred_t *cred, void *whatever, char *whichever)
    141 {
    142 	minor_t min;
    143 	major_t maj;
    144 	struct vattr *vap = (struct vattr *)arg;
    145 
    146 	if ((maj = vt_wc_attached()) == (major_t)-1)
    147 		return (SDEV_VTOR_INVALID);
    148 
    149 	if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
    150 		(void) vt_getactive((char *)*arg, MAXPATHLEN);
    151 		return (0);
    152 	}
    153 
    154 	if (devvt_str2minor(nm, &min) != 0)
    155 		return (-1);
    156 
    157 	if (vt_minor_valid(min) == B_FALSE)
    158 		return (-1);
    159 
    160 	*vap = devvt_vattr;
    161 	vap->va_rdev = makedevice(maj, min);
    162 
    163 	return (0);
    164 }
    165 
    166 /*ARGSUSED3*/
    167 static int
    168 devvt_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
    169     struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
    170     caller_context_t *ct, int *direntflags, pathname_t *realpnp)
    171 {
    172 	struct sdev_node *sdvp = VTOSDEV(dvp);
    173 	struct sdev_node *dv;
    174 	struct vnode *rvp = NULL;
    175 	int type, error;
    176 
    177 	if (strcmp(nm, DEVVT_ACTIVE_NAME) == 0) {
    178 		type = SDEV_VLINK;
    179 	} else {
    180 		type = SDEV_VATTR;
    181 	}
    182 
    183 /* Give warlock a more clear call graph */
    184 #ifndef __lock_lint
    185 	error = devname_lookup_func(sdvp, nm, vpp, cred,
    186 	    devvt_create_rvp, type);
    187 #else
    188 	devvt_create_rvp(0, 0, 0, 0, 0, 0);
    189 #endif
    190 
    191 	if (error == 0) {
    192 		switch ((*vpp)->v_type) {
    193 		case VCHR:
    194 			dv = VTOSDEV(VTOS(*vpp)->s_realvp);
    195 			ASSERT(VOP_REALVP(SDEVTOV(dv), &rvp, NULL) == ENOSYS);
    196 			break;
    197 		case VDIR:
    198 		case VLNK:
    199 			dv = VTOSDEV(*vpp);
    200 			break;
    201 		default:
    202 			cmn_err(CE_PANIC, "devvt_lookup: Unsupported node "
    203 			    "type: %p: %d", (void *)(*vpp), (*vpp)->v_type);
    204 			break;
    205 		}
    206 		ASSERT(SDEV_HELD(dv));
    207 	}
    208 
    209 	return (error);
    210 }
    211 
    212 static void
    213 devvt_create_snode(struct sdev_node *ddv, char *nm, struct cred *cred, int type)
    214 {
    215 	int error;
    216 	struct sdev_node *sdv = NULL;
    217 	struct vattr *vap = NULL;
    218 	major_t maj;
    219 	minor_t min;
    220 
    221 	if ((maj = vt_wc_attached()) == (major_t)-1)
    222 		return;
    223 
    224 	if (strcmp(nm, DEVVT_ACTIVE_NAME) != 0 &&
    225 	    devvt_str2minor(nm, &min) != 0)
    226 		return;
    227 
    228 	error = sdev_mknode(ddv, nm, &sdv, NULL, NULL, NULL, cred, SDEV_INIT);
    229 	if (error || !sdv) {
    230 		return;
    231 	}
    232 
    233 	mutex_enter(&sdv->sdev_lookup_lock);
    234 	SDEV_BLOCK_OTHERS(sdv, SDEV_LOOKUP);
    235 	mutex_exit(&sdv->sdev_lookup_lock);
    236 
    237 	if (type & SDEV_VATTR) {
    238 		vap = &devvt_vattr;
    239 		vap->va_rdev = makedevice(maj, min);
    240 		error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
    241 		    NULL, cred, SDEV_READY);
    242 	} else if (type & SDEV_VLINK) {
    243 		char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
    244 
    245 		(void) vt_getactive(link, MAXPATHLEN);
    246 		vap = &sdev_vattr_lnk;
    247 		vap->va_size = strlen(link);
    248 		error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
    249 		    (void *)link, cred, SDEV_READY);
    250 
    251 		kmem_free(link, MAXPATHLEN);
    252 	}
    253 
    254 	mutex_enter(&sdv->sdev_lookup_lock);
    255 	SDEV_UNBLOCK_OTHERS(sdv, SDEV_LOOKUP);
    256 	mutex_exit(&sdv->sdev_lookup_lock);
    257 
    258 }
    259 
    260 static void
    261 devvt_prunedir(struct sdev_node *ddv)
    262 {
    263 	struct vnode *vp;
    264 	struct sdev_node *dv, *next = NULL;
    265 	int (*vtor)(struct sdev_node *) = NULL;
    266 
    267 	ASSERT(ddv->sdev_flags & SDEV_VTOR);
    268 
    269 	vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
    270 	ASSERT(vtor);
    271 
    272 	for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
    273 		next = SDEV_NEXT_ENTRY(ddv, dv);
    274 
    275 		/* skip stale nodes */
    276 		if (dv->sdev_flags & SDEV_STALE)
    277 			continue;
    278 
    279 		/* validate and prune only ready nodes */
    280 		if (dv->sdev_state != SDEV_READY)
    281 			continue;
    282 
    283 		switch (vtor(dv)) {
    284 		case SDEV_VTOR_VALID:
    285 		case SDEV_VTOR_SKIP:
    286 			continue;
    287 		case SDEV_VTOR_INVALID:
    288 		case SDEV_VTOR_STALE:
    289 			sdcmn_err7(("destroy invalid "
    290 			    "node: %s(%p)\n", dv->sdev_name, (void *)dv));
    291 			break;
    292 		}
    293 		vp = SDEVTOV(dv);
    294 		if (vp->v_count > 0)
    295 			continue;
    296 		SDEV_HOLD(dv);
    297 		/* remove the cache node */
    298 		(void) sdev_cache_update(ddv, &dv, dv->sdev_name,
    299 		    SDEV_CACHE_DELETE);
    300 	}
    301 }
    302 
    303 static void
    304 devvt_cleandir(struct vnode *dvp, struct cred *cred)
    305 {
    306 	struct sdev_node *sdvp = VTOSDEV(dvp);
    307 	struct sdev_node *dv, *next = NULL;
    308 	int min, cnt;
    309 	int found = 0;
    310 
    311 	mutex_enter(&vc_lock);
    312 	cnt = VC_INSTANCES_COUNT;
    313 	mutex_exit(&vc_lock);
    314 
    315 /* We have to fool warlock this way, otherwise it will complain */
    316 #ifndef	__lock_lint
    317 	if (rw_tryupgrade(&sdvp->sdev_contents) == NULL) {
    318 		rw_exit(&sdvp->sdev_contents);
    319 		rw_enter(&sdvp->sdev_contents, RW_WRITER);
    320 	}
    321 #else
    322 	rw_enter(&sdvp->sdev_contents, RW_WRITER);
    323 #endif
    324 
    325 	/* 1. create missed nodes */
    326 	for (min = 0; min < cnt; min++) {
    327 		char nm[16];
    328 
    329 		if (vt_minor_valid(min) == B_FALSE)
    330 			continue;
    331 
    332 		(void) snprintf(nm, sizeof (nm), "%d", min);
    333 		found = 0;
    334 		for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
    335 			next = SDEV_NEXT_ENTRY(sdvp, dv);
    336 
    337 			/* skip stale nodes */
    338 			if (dv->sdev_flags & SDEV_STALE)
    339 				continue;
    340 			/* validate and prune only ready nodes */
    341 			if (dv->sdev_state != SDEV_READY)
    342 				continue;
    343 			if (strcmp(nm, dv->sdev_name) == 0) {
    344 				found = 1;
    345 				break;
    346 			}
    347 		}
    348 		if (!found) {
    349 			devvt_create_snode(sdvp, nm, cred, SDEV_VATTR);
    350 		}
    351 	}
    352 
    353 	/* 2. create active link node */
    354 	found = 0;
    355 	for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
    356 		next = SDEV_NEXT_ENTRY(sdvp, dv);
    357 
    358 		/* skip stale nodes */
    359 		if (dv->sdev_flags & SDEV_STALE)
    360 			continue;
    361 		/* validate and prune only ready nodes */
    362 		if (dv->sdev_state != SDEV_READY)
    363 			continue;
    364 		if ((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == NULL)) {
    365 			found = 1;
    366 			break;
    367 		}
    368 	}
    369 	if (!found)
    370 		devvt_create_snode(sdvp, DEVVT_ACTIVE_NAME, cred, SDEV_VLINK);
    371 
    372 	/* 3. cleanup invalid nodes */
    373 	devvt_prunedir(sdvp);
    374 
    375 #ifndef	__lock_lint
    376 	rw_downgrade(&sdvp->sdev_contents);
    377 #else
    378 	rw_exit(&sdvp->sdev_contents);
    379 #endif
    380 }
    381 
    382 /*ARGSUSED4*/
    383 static int
    384 devvt_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
    385     int *eofp, caller_context_t *ct, int flags)
    386 {
    387 	if (uiop->uio_offset == 0) {
    388 		devvt_cleandir(dvp, cred);
    389 	}
    390 
    391 	return (devname_readdir_func(dvp, uiop, cred, eofp, 0));
    392 }
    393 
    394 /*
    395  * We allow create to find existing nodes
    396  *	- if the node doesn't exist - EROFS
    397  *	- creating an existing dir read-only succeeds, otherwise EISDIR
    398  *	- exclusive creates fail - EEXIST
    399  */
    400 /*ARGSUSED2*/
    401 static int
    402 devvt_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
    403     int mode, struct vnode **vpp, struct cred *cred, int flag,
    404     caller_context_t *ct, vsecattr_t *vsecp)
    405 {
    406 	int error;
    407 	struct vnode *vp;
    408 
    409 	*vpp = NULL;
    410 
    411 	if ((error = devvt_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL,
    412 	    NULL)) != 0) {
    413 		if (error == ENOENT)
    414 			error = EROFS;
    415 		return (error);
    416 	}
    417 
    418 	if (excl == EXCL)
    419 		error = EEXIST;
    420 	else if (vp->v_type == VDIR && (mode & VWRITE))
    421 		error = EISDIR;
    422 	else
    423 		error = VOP_ACCESS(vp, mode, 0, cred, ct);
    424 
    425 	if (error) {
    426 		VN_RELE(vp);
    427 	} else
    428 		*vpp = vp;
    429 
    430 	return (error);
    431 }
    432 
    433 const fs_operation_def_t devvt_vnodeops_tbl[] = {
    434 	VOPNAME_READDIR,	{ .vop_readdir = devvt_readdir },
    435 	VOPNAME_LOOKUP,		{ .vop_lookup = devvt_lookup },
    436 	VOPNAME_CREATE,		{ .vop_create = devvt_create },
    437 	VOPNAME_REMOVE,		{ .error = fs_nosys },
    438 	VOPNAME_MKDIR,		{ .error = fs_nosys },
    439 	VOPNAME_RMDIR,		{ .error = fs_nosys },
    440 	VOPNAME_SYMLINK,	{ .error = fs_nosys },
    441 	VOPNAME_SETSECATTR,	{ .error = fs_nosys },
    442 	NULL,			NULL
    443 };
    444