Пример #1
0
/*
 * New Leaf driver open entry point.  We make a vnode and go through specfs
 * in order to obtain open close exclusions guarantees.  Note that we drop
 * OTYP_LYR if it was specified - we are going through specfs and it provides
 * last close semantics (FKLYR is provided to open(9E)).  Also, since
 * spec_open will drive attach via e_ddi_hold_devi_by_dev for a makespecvp
 * vnode with no SDIP_SET on the common snode, the dev_lopen caller no longer
 * needs to call ddi_hold_installed_driver.
 */
int
dev_lopen(dev_t *devp, int flag, int otype, struct cred *cred)
{
	struct vnode	*vp;
	int		error;
	struct vnode	*cvp;

	vp = makespecvp(*devp, (otype == OTYP_BLK) ? VBLK : VCHR);
	error = VOP_OPEN(&vp, flag | FKLYR, cred, NULL);
	if (error == 0) {
		/* Pick up the (possibly) new dev_t value. */
		*devp = vp->v_rdev;

		/*
		 * Place extra hold on the common vnode, which contains the
		 * open count, so that it is not destroyed by the VN_RELE of
		 * the shadow makespecvp vnode below.
		 */
		cvp = STOV(VTOCS(vp));
		VN_HOLD(cvp);
	}

	/* release the shadow makespecvp vnode. */
	VN_RELE(vp);
	return (error);
}
Пример #2
0
/*
 * This opens and closes the appropriate device with minor number -
 * hopefully, it will cause the driver to attach and register a controller
 * with us
 */
static vnode_t *
rsmops_device_open(const char *major_name, const minor_t minor_num)
{
	major_t maj;
	vnode_t *vp;
	int ret;

	if (minor_num == (minor_t)-1) {
		return (NULL);
	}

	maj = ddi_name_to_major((char *)major_name);
	if (maj == (major_t)-1) {
		return (NULL);
	}

	vp = makespecvp(makedevice(maj, minor_num), VCHR);

	ret = VOP_OPEN(&vp, FREAD|FWRITE, CRED(), NULL);
	if (ret == 0) {
		return (vp);
	} else {
		VN_RELE(vp);
		return (NULL);
	}
}
Пример #3
0
/*
 * Leaf driver close entry point.  We make a vnode and go through specfs in
 * order to obtain open close exclusions guarantees.  Note that we drop
 * OTYP_LYR if it was specified - we are going through specfs and it provides
 * last close semantics (FLKYR is provided to close(9E)).
 */
int
dev_lclose(dev_t dev, int flag, int otype, struct cred *cred)
{
	struct vnode	*vp;
	int		error;
	struct vnode	*cvp;
	char		*funcname;
	ulong_t		offset;

	vp = makespecvp(dev, (otype == OTYP_BLK) ? VBLK : VCHR);
	error = VOP_CLOSE(vp, flag | FKLYR, 1, (offset_t)0, cred, NULL);

	/*
	 * Release the extra dev_lopen hold on the common vnode. We inline a
	 * VN_RELE(cvp) call so that we can detect more dev_lclose calls than
	 * dev_lopen calls without panic. See vn_rele.  If our inline of
	 * vn_rele called VOP_INACTIVE(cvp, CRED(), ...) we would panic on the
	 * "release the makespecvp vnode" VN_RELE(vp) that follows  - so
	 * instead we diagnose this situation.  Note that the driver has
	 * still seen a double close(9E), but that would have occurred with
	 * the old dev_close implementation too.
	 */
	cvp = STOV(VTOCS(vp));
	mutex_enter(&cvp->v_lock);
	switch (cvp->v_count) {
	default:
		cvp->v_count--;
		break;

	case 0:
		VTOS(vp)->s_commonvp = NULL;	/* avoid panic */
		/*FALLTHROUGH*/
	case 1:
		/*
		 * The following message indicates a serious problem in the
		 * identified driver, the driver should be fixed. If obtaining
		 * a panic dump is needed to diagnose the driver problem then
		 * adding "set dev_lclose_ce=3" to /etc/system will cause a
		 * panic when this occurs.
		 */
		funcname = modgetsymname((uintptr_t)caller(), &offset);
		cmn_err(dev_lclose_ce, "dev_lclose: extra close of dev_t 0x%lx "
		    "from %s`%s()", dev, mod_containing_pc(caller()),
		    funcname ? funcname : "unknown...");
		break;
	}
	mutex_exit(&cvp->v_lock);

	/* release the makespecvp vnode. */
	VN_RELE(vp);
	return (error);
}
Пример #4
0
int
t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr)
{
	int			madefp = 0;
	struct T_info_ack	inforeq;
	int			retval;
	vnode_t			*vp;
	struct strioctl		strioc;
	int			error;
	TIUSER			*ntiptr;
	int			rtries = 0;

	/*
	 * Special case for install: miniroot needs to be able to access files
	 * via NFS as though it were always in the global zone.
	 */
	if (nfs_global_client_only != 0)
		cr = kcred;

	KTLILOG(2, "t_kopen: fp %x, ", fp);
	KTLILOG(2, "rdev %x, ", rdev);
	KTLILOG(2, "flags %x\n", flags);

	*tiptr = NULL;
	error = 0;
	retval = 0;
	if (fp == NULL) {
		if (rdev == 0 || rdev == NODEV) {
			KTLILOG(1, "t_kopen: null device\n", 0);
			return (EINVAL);
		}

		/*
		 * allocate a file pointer, but
		 * no file descripter.
		 */
		if ((error = falloc(NULL, flags, &fp, NULL)) != 0) {
			KTLILOG(1, "t_kopen: falloc: %d\n", error);
			return (error);
		}

		/* Install proper cred in file */
		if (cr != fp->f_cred) {
			crhold(cr);
			crfree(fp->f_cred);
			fp->f_cred = cr;
		}

		vp = makespecvp(rdev, VCHR);

		/*
		 * this will call the streams open for us.
		 * Want to retry if error is EAGAIN, the streams open routine
		 * might fail due to temporarely out of memory.
		 */
		do {
			if ((error = VOP_OPEN(&vp, flags, cr)) == EAGAIN) {
				(void) delay(hz);
			}
		} while (error == EAGAIN && ++rtries < 5);

		if (error) {
			KTLILOG(1, "t_kopen: VOP_OPEN: %d\n", error);
			unfalloc(fp);
			VN_RELE(vp);
			return (error);
		}
		/*
		 * fp is completely initialized so drop the write lock.
		 * I actually don't need any locking on fp in here since
		 * there is no fd pointing at it.  However, since I could
		 * call closef if there is an error and closef requires
		 * the fp read locked, I will acquire the read lock here
		 * and make sure I release it before I leave this routine.
		 */
		fp->f_vnode = vp;
		mutex_exit(&fp->f_tlock);

		madefp = 1;
	} else {
		vp = fp->f_vnode;
	}

	if (vp->v_stream == NULL) {
		if (madefp)
			(void) closef(fp);
		KTLILOG(1, "t_kopen: not a streams device\n", 0);
		return (ENOSTR);
	}

	/*
	 * allocate a new transport structure
	 */
	ntiptr = kmem_alloc(TIUSERSZ, KM_SLEEP);
	ntiptr->fp = fp;
	ntiptr->flags = madefp ? MADE_FP : 0;

	KTLILOG(2, "t_kopen: vp %x, ", vp);
	KTLILOG(2, "stp %x\n", vp->v_stream);

	/*
	 * see if TIMOD is already pushed
	 */
	error = strioctl(vp, I_FIND, (intptr_t)"timod", 0, K_TO_K, cr, &retval);
	if (error) {
		kmem_free(ntiptr, TIUSERSZ);
		if (madefp)
			(void) closef(fp);
		KTLILOG(1, "t_kopen: strioctl(I_FIND, timod): %d\n", error);
		return (error);
	}

	if (retval == 0) {
tryagain:
		error = strioctl(vp, I_PUSH, (intptr_t)"timod", 0, K_TO_K, cr,
		    &retval);
		if (error) {
			switch (error) {
			case ENOSPC:
			case EAGAIN:
			case ENOSR:
				/*
				 * This probably means the master file
				 * should be tuned.
				 */
				cmn_err(CE_WARN,
				"t_kopen: I_PUSH of timod failed, error %d\n",
				    error);
				(void) delay(hz);
				error = 0;
				goto tryagain;

			default:
				kmem_free(ntiptr, TIUSERSZ);
				if (madefp)
					(void) closef(fp);
				KTLILOG(1, "t_kopen: I_PUSH (timod): %d",
				    error);
				return (error);
			}
		}
	}

	inforeq.PRIM_type = T_INFO_REQ;
	strioc.ic_cmd = TI_GETINFO;
	strioc.ic_timout = 0;
	strioc.ic_dp = (char *)&inforeq;
	strioc.ic_len = (int)sizeof (struct T_info_req);

	error = strdoioctl(vp->v_stream, &strioc, FNATIVE, K_TO_K, cr, &retval);
	if (error) {
		kmem_free(ntiptr, TIUSERSZ);
		if (madefp)
			(void) closef(fp);
		KTLILOG(1, "t_kopen: strdoioctl(T_INFO_REQ): %d\n", error);
		return (error);
	}

	if (retval) {
		if ((retval & 0xff) == TSYSERR)
			error = (retval >> 8) & 0xff;
		else
			error = t_tlitosyserr(retval & 0xff);
		kmem_free(ntiptr, TIUSERSZ);
		if (madefp)
			(void) closef(fp);
		KTLILOG(1, "t_kopen: strdoioctl(T_INFO_REQ): retval: 0x%x\n",
		    retval);
		return (error);
	}