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 2009 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 vattr;
    218 	struct vattr *vap = &vattr;
    219 	major_t maj;
    220 	minor_t min;
    221 
    222 	if ((maj = vt_wc_attached()) == (major_t)-1)
    223 		return;
    224 
    225 	if (strcmp(nm, DEVVT_ACTIVE_NAME) != 0 &&
    226 	    devvt_str2minor(nm, &min) != 0)
    227 		return;
    228 
    229 	error = sdev_mknode(ddv, nm, &sdv, NULL, NULL, NULL, cred, SDEV_INIT);
    230 	if (error || !sdv) {
    231 		return;
    232 	}
    233 
    234 	mutex_enter(&sdv->sdev_lookup_lock);
    235 	SDEV_BLOCK_OTHERS(sdv, SDEV_LOOKUP);
    236 	mutex_exit(&sdv->sdev_lookup_lock);
    237 
    238 	if (type & SDEV_VATTR) {
    239 		*vap = devvt_vattr;
    240 		vap->va_rdev = makedevice(maj, min);
    241 		error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
    242 		    NULL, cred, SDEV_READY);
    243 	} else if (type & SDEV_VLINK) {
    244 		char *link = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
    245 
    246 		(void) vt_getactive(link, MAXPATHLEN);
    247 		*vap = sdev_vattr_lnk;
    248 		vap->va_size = strlen(link);
    249 		error = sdev_mknode(ddv, nm, &sdv, vap, NULL,
    250 		    (void *)link, cred, SDEV_READY);
    251 
    252 		kmem_free(link, MAXPATHLEN);
    253 	}
    254 
    255 	mutex_enter(&sdv->sdev_lookup_lock);
    256 	SDEV_UNBLOCK_OTHERS(sdv, SDEV_LOOKUP);
    257 	mutex_exit(&sdv->sdev_lookup_lock);
    258 
    259 }
    260 
    261 static void
    262 devvt_prunedir(struct sdev_node *ddv)
    263 {
    264 	struct vnode *vp;
    265 	struct sdev_node *dv, *next = NULL;
    266 	int (*vtor)(struct sdev_node *) = NULL;
    267 
    268 	ASSERT(ddv->sdev_flags & SDEV_VTOR);
    269 
    270 	vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
    271 	ASSERT(vtor);
    272 
    273 	for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
    274 		next = SDEV_NEXT_ENTRY(ddv, dv);
    275 
    276 		/* skip stale nodes */
    277 		if (dv->sdev_flags & SDEV_STALE)
    278 			continue;
    279 
    280 		/* validate and prune only ready nodes */
    281 		if (dv->sdev_state != SDEV_READY)
    282 			continue;
    283 
    284 		switch (vtor(dv)) {
    285 		case SDEV_VTOR_VALID:
    286 		case SDEV_VTOR_SKIP:
    287 			continue;
    288 		case SDEV_VTOR_INVALID:
    289 		case SDEV_VTOR_STALE:
    290 			sdcmn_err7(("destroy invalid "
    291 			    "node: %s(%p)\n", dv->sdev_name, (void *)dv));
    292 			break;
    293 		}
    294 		vp = SDEVTOV(dv);
    295 		if (vp->v_count > 0)
    296 			continue;
    297 		SDEV_HOLD(dv);
    298 		/* remove the cache node */
    299 		(void) sdev_cache_update(ddv, &dv, dv->sdev_name,
    300 		    SDEV_CACHE_DELETE);
    301 	}
    302 }
    303 
    304 static void
    305 devvt_cleandir(struct vnode *dvp, struct cred *cred)
    306 {
    307 	struct sdev_node *sdvp = VTOSDEV(dvp);
    308 	struct sdev_node *dv, *next = NULL;
    309 	int min, cnt;
    310 	int found = 0;
    311 
    312 	mutex_enter(&vc_lock);
    313 	cnt = VC_INSTANCES_COUNT;
    314 	mutex_exit(&vc_lock);
    315 
    316 /* We have to fool warlock this way, otherwise it will complain */
    317 #ifndef	__lock_lint
    318 	if (rw_tryupgrade(&sdvp->sdev_contents) == NULL) {
    319 		rw_exit(&sdvp->sdev_contents);
    320 		rw_enter(&sdvp->sdev_contents, RW_WRITER);
    321 	}
    322 #else
    323 	rw_enter(&sdvp->sdev_contents, RW_WRITER);
    324 #endif
    325 
    326 	/* 1. create missed nodes */
    327 	for (min = 0; min < cnt; min++) {
    328 		char nm[16];
    329 
    330 		if (vt_minor_valid(min) == B_FALSE)
    331 			continue;
    332 
    333 		(void) snprintf(nm, sizeof (nm), "%d", min);
    334 		found = 0;
    335 		for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
    336 			next = SDEV_NEXT_ENTRY(sdvp, dv);
    337 
    338 			/* skip stale nodes */
    339 			if (dv->sdev_flags & SDEV_STALE)
    340 				continue;
    341 			/* validate and prune only ready nodes */
    342 			if (dv->sdev_state != SDEV_READY)
    343 				continue;
    344 			if (strcmp(nm, dv->sdev_name) == 0) {
    345 				found = 1;
    346 				break;
    347 			}
    348 		}
    349 		if (!found) {
    350 			devvt_create_snode(sdvp, nm, cred, SDEV_VATTR);
    351 		}
    352 	}
    353 
    354 	/* 2. create active link node */
    355 	found = 0;
    356 	for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
    357 		next = SDEV_NEXT_ENTRY(sdvp, dv);
    358 
    359 		/* skip stale nodes */
    360 		if (dv->sdev_flags & SDEV_STALE)
    361 			continue;
    362 		/* validate and prune only ready nodes */
    363 		if (dv->sdev_state != SDEV_READY)
    364 			continue;
    365 		if ((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == NULL)) {
    366 			found = 1;
    367 			break;
    368 		}
    369 	}
    370 	if (!found)
    371 		devvt_create_snode(sdvp, DEVVT_ACTIVE_NAME, cred, SDEV_VLINK);
    372 
    373 	/* 3. cleanup invalid nodes */
    374 	devvt_prunedir(sdvp);
    375 
    376 #ifndef	__lock_lint
    377 	rw_downgrade(&sdvp->sdev_contents);
    378 #else
    379 	rw_exit(&sdvp->sdev_contents);
    380 #endif
    381 }
    382 
    383 /*ARGSUSED4*/
    384 static int
    385 devvt_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
    386     int *eofp, caller_context_t *ct, int flags)
    387 {
    388 	if (uiop->uio_offset == 0) {
    389 		devvt_cleandir(dvp, cred);
    390 	}
    391 
    392 	return (devname_readdir_func(dvp, uiop, cred, eofp, 0));
    393 }
    394 
    395 /*
    396  * We allow create to find existing nodes
    397  *	- if the node doesn't exist - EROFS
    398  *	- creating an existing dir read-only succeeds, otherwise EISDIR
    399  *	- exclusive creates fail - EEXIST
    400  */
    401 /*ARGSUSED2*/
    402 static int
    403 devvt_create(struct vnode *dvp, char *nm, struct vattr *vap, vcexcl_t excl,
    404     int mode, struct vnode **vpp, struct cred *cred, int flag,
    405     caller_context_t *ct, vsecattr_t *vsecp)
    406 {
    407 	int error;
    408 	struct vnode *vp;
    409 
    410 	*vpp = NULL;
    411 
    412 	if ((error = devvt_lookup(dvp, nm, &vp, NULL, 0, NULL, cred, ct, NULL,
    413 	    NULL)) != 0) {
    414 		if (error == ENOENT)
    415 			error = EROFS;
    416 		return (error);
    417 	}
    418 
    419 	if (excl == EXCL)
    420 		error = EEXIST;
    421 	else if (vp->v_type == VDIR && (mode & VWRITE))
    422 		error = EISDIR;
    423 	else
    424 		error = VOP_ACCESS(vp, mode, 0, cred, ct);
    425 
    426 	if (error) {
    427 		VN_RELE(vp);
    428 	} else
    429 		*vpp = vp;
    430 
    431 	return (error);
    432 }
    433 
    434 const fs_operation_def_t devvt_vnodeops_tbl[] = {
    435 	VOPNAME_READDIR,	{ .vop_readdir = devvt_readdir },
    436 	VOPNAME_LOOKUP,		{ .vop_lookup = devvt_lookup },
    437 	VOPNAME_CREATE,		{ .vop_create = devvt_create },
    438 	VOPNAME_REMOVE,		{ .error = fs_nosys },
    439 	VOPNAME_MKDIR,		{ .error = fs_nosys },
    440 	VOPNAME_RMDIR,		{ .error = fs_nosys },
    441 	VOPNAME_SYMLINK,	{ .error = fs_nosys },
    442 	VOPNAME_SETSECATTR,	{ .error = fs_nosys },
    443 	NULL,			NULL
    444 };
    445