Esempio n. 1
0
/* ARGSUSED */
static int
pppt_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
{
	int rc = 0;

	PPPT_GLOBAL_LOCK();

	switch (pppt_global.global_svc_state) {
	case PSS_ENABLED:
		pppt_global.global_svc_state = PSS_DISABLING;
		PPPT_GLOBAL_UNLOCK();
		pppt_disable_svc();
		PPPT_GLOBAL_LOCK();
		pppt_global.global_svc_state = PSS_DISABLED;
		/*
		 * release the door to the daemon
		 */
		mutex_enter(&pppt_global.global_door_lock);
		if (pppt_global.global_door != NULL) {
			door_ki_rele(pppt_global.global_door);
			pppt_global.global_door = NULL;
		}
		mutex_exit(&pppt_global.global_door_lock);
		break;
	default:
		rc = EFAULT;
		break;
	}

	PPPT_GLOBAL_UNLOCK();

	return (rc);
}
Esempio n. 2
0
void
nfscmd_args(uint_t did)
{
	mutex_enter(&nfscmd_lock);
	if (nfscmd_dh)
		door_ki_rele(nfscmd_dh);
	nfscmd_dh = door_ki_lookup(did);
	mutex_exit(&nfscmd_lock);
}
Esempio n. 3
0
void
mountd_args(uint_t did)
{
	mutex_enter(&mountd_lock);
	if (mountd_dh)
		door_ki_rele(mountd_dh);
	mountd_dh = door_ki_lookup(did);
	mutex_exit(&mountd_lock);
}
Esempio n. 4
0
static uint64_t
allocids(int flag, int nuids, int ngids)
{
	rval_t r;
	uid_t su = 0;
	gid_t sg = 0;
	struct door_info di;
	door_handle_t dh;
	int err;
	zone_t *zone = crgetzone(CRED());

	dh = idmap_get_door(zone);

	if (dh == NULL)
		return (set_errno(EPERM));

	if ((err = door_ki_info(dh, &di)) != 0) {
		door_ki_rele(dh);
		return (set_errno(err));
	}

	door_ki_rele(dh);

	if (curproc->p_pid != di.di_target)
		return (set_errno(EPERM));

	if (flag)
		idmap_purge_cache(zone);

	if (nuids < 0 || ngids < 0)
		return (set_errno(EINVAL));

	if (flag != 0 || nuids > 0)
		err = eph_uid_alloc(zone, flag, &su, nuids);
	if (err == 0 && (flag != 0 || ngids > 0))
		err = eph_gid_alloc(zone, flag, &sg, ngids);

	if (err != 0)
		return (set_errno(EOVERFLOW));

	r.r_val1 = su;
	r.r_val2 = sg;
	return (r.r_vals);
}
Esempio n. 5
0
/*
 * iscsi_door_unbind
 *
 * This function releases the current door handle.
 */
void
iscsi_door_unbind(void)
{
	rw_enter(&iscsi_door_lock, RW_WRITER);
	if (iscsi_door_handle != NULL) {
		door_ki_rele(iscsi_door_handle);
		iscsi_door_handle = NULL;
	}
	rw_exit(&iscsi_door_lock);
}
Esempio n. 6
0
void
klpd_rele(klpd_reg_t *p)
{
	if (atomic_dec_32_nv(&p->klpd_ref) == 0) {
		if (p->klpd_refp != NULL)
			klpd_unlink(p);
		if (p->klpd_cred != NULL)
			crfree(p->klpd_cred);
		door_ki_rele(p->klpd_door);
		kmem_free(p, sizeof (*p));
	}
}
Esempio n. 7
0
static int
idmap_unreg(int did)
{
	door_handle_t dh = door_ki_lookup(did);
	int res;
	zone_t *zone;

	if (dh == NULL)
		return (set_errno(EINVAL));

	zone = crgetzone(CRED());
	res = idmap_unreg_dh(zone, dh);
	door_ki_rele(dh);

	if (res != 0)
		return (set_errno(res));
	return (0);
}
Esempio n. 8
0
/*
 * log_event_upcall_lookup - Establish door connection with user event
 *				daemon (syseventd)
 */
static int
log_event_upcall_lookup()
{
	int	error;

	if (event_door) {	/* Release our previous hold (if any) */
		door_ki_rele(event_door);
	}

	event_door = NULL;

	/*
	 * Locate the door used for upcalls
	 */
	if ((error =
	    door_ki_open(logevent_door_upcall_filename, &event_door)) != 0) {
		return (error);
	}

	return (0);
}
Esempio n. 9
0
/*
 * iscsi_door_bind
 *
 * This function tries to connect the iscsi_door.  If it succeeds
 * it keeps the vnode.
 */
boolean_t
iscsi_door_bind(
	int		did
)
{
	door_handle_t	new_handle;

	new_handle = door_ki_lookup(did);
	if (new_handle == NULL) {
		/* The lookup failed. */
		return (B_FALSE);
	}

	/* The new handle is stored.  If we had one, it is released. */
	rw_enter(&iscsi_door_lock, RW_WRITER);
	if (iscsi_door_handle != NULL) {
		door_ki_rele(iscsi_door_handle);
	}
	iscsi_door_handle = new_handle;
	rw_exit(&iscsi_door_lock);

	return (B_TRUE);
}
Esempio n. 10
0
/*ARGSUSED*/
static void
autofs_zone_destructor(zoneid_t zoneid, void *arg)
{
	struct autofs_globals *fngp = arg;
	vnode_t *vp;

	if (fngp == NULL)
		return;
	ASSERT(fngp->fng_fnnode_count == 1);
	ASSERT(fngp->fng_unmount_threads == 0);

	if (fngp->fng_autofs_daemon_dh != NULL)
		door_ki_rele(fngp->fng_autofs_daemon_dh);
	/*
	 * vn_alloc() initialized the rootnode with a count of 1; we need to
	 * make this 0 to placate auto_freefnnode().
	 */
	vp = fntovn(fngp->fng_rootfnnodep);
	ASSERT(vp->v_count == 1);
	vp->v_count--;
	auto_freefnnode(fngp->fng_rootfnnodep);
	mutex_destroy(&fngp->fng_unmount_threads_lock);
	kmem_free(fngp, sizeof (*fngp));
}
Esempio n. 11
0
int
klpd_unreg(int did, idtype_t type, id_t id)
{
	door_handle_t dh;
	int res = 0;
	proc_t *p;
	pid_t pid;
	projid_t proj;
	kproject_t *kpp = NULL;
	credklpd_t *ckp;

	switch (type) {
	case P_PID:
		pid = (pid_t)id;
		break;
	case P_PROJID:
		proj = (projid_t)id;
		kpp = project_hold_by_id(proj, crgetzone(CRED()),
		    PROJECT_HOLD_FIND);
		if (kpp == NULL)
			return (set_errno(ESRCH));
		break;
	default:
		return (set_errno(ENOTSUP));
	}

	dh = door_ki_lookup(did);
	if (dh == NULL) {
		if (kpp != NULL)
			project_rele(kpp);
		return (set_errno(EINVAL));
	}

	if (kpp != NULL) {
		mutex_enter(&klpd_mutex);
		if (kpp->kpj_klpd == NULL)
			res = ESRCH;
		else
			klpd_freelist(&kpp->kpj_klpd);
		mutex_exit(&klpd_mutex);
		project_rele(kpp);
		goto out;
	} else if ((int)pid > 0) {
		mutex_enter(&pidlock);
		p = prfind(pid);
		if (p == NULL) {
			mutex_exit(&pidlock);
			door_ki_rele(dh);
			return (set_errno(ESRCH));
		}
		mutex_enter(&p->p_crlock);
		mutex_exit(&pidlock);
	} else if (pid == 0) {
		p = curproc;
		mutex_enter(&p->p_crlock);
	} else {
		res = klpd_unreg_dh(dh);
		goto out;
	}

	ckp = crgetcrklpd(p->p_cred);
	if (ckp != NULL) {
		crklpd_setreg(ckp, NULL);
	} else {
		res = ESRCH;
	}
	mutex_exit(&p->p_crlock);

out:
	door_ki_rele(dh);

	if (res != 0)
		return (set_errno(res));
	return (0);
}
Esempio n. 12
0
/*
 * Callup to the mountd to get access information in the kernel.
 */
static bool_t
nfsauth_retrieve(struct exportinfo *exi, char *req_netid, int flavor,
    struct netbuf *addr, int *access, uid_t clnt_uid, gid_t clnt_gid,
    uint_t clnt_gids_cnt, const gid_t *clnt_gids, uid_t *srv_uid,
    gid_t *srv_gid, uint_t *srv_gids_cnt, gid_t **srv_gids)
{
	varg_t			  varg = {0};
	nfsauth_res_t		  res = {0};
	XDR			  xdrs;
	size_t			  absz;
	caddr_t			  abuf;
	int			  last = 0;
	door_arg_t		  da;
	door_info_t		  di;
	door_handle_t		  dh;
	uint_t			  ntries = 0;

	/*
	 * No entry in the cache for this client/flavor
	 * so we need to call the nfsauth service in the
	 * mount daemon.
	 */

	varg.vers = V_PROTO;
	varg.arg_u.arg.cmd = NFSAUTH_ACCESS;
	varg.arg_u.arg.areq.req_client.n_len = addr->len;
	varg.arg_u.arg.areq.req_client.n_bytes = addr->buf;
	varg.arg_u.arg.areq.req_netid = req_netid;
	varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path;
	varg.arg_u.arg.areq.req_flavor = flavor;
	varg.arg_u.arg.areq.req_clnt_uid = clnt_uid;
	varg.arg_u.arg.areq.req_clnt_gid = clnt_gid;
	varg.arg_u.arg.areq.req_clnt_gids.len = clnt_gids_cnt;
	varg.arg_u.arg.areq.req_clnt_gids.val = (gid_t *)clnt_gids;

	DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg);

	/*
	 * Setup the XDR stream for encoding the arguments. Notice that
	 * in addition to the args having variable fields (req_netid and
	 * req_path), the argument data structure is itself versioned,
	 * so we need to make sure we can size the arguments buffer
	 * appropriately to encode all the args. If we can't get sizing
	 * info _or_ properly encode the arguments, there's really no
	 * point in continuting, so we fail the request.
	 */
	if ((absz = xdr_sizeof(xdr_varg, &varg)) == 0) {
		*access = NFSAUTH_DENIED;
		return (FALSE);
	}

	abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP);
	xdrmem_create(&xdrs, abuf, absz, XDR_ENCODE);
	if (!xdr_varg(&xdrs, &varg)) {
		XDR_DESTROY(&xdrs);
		goto fail;
	}
	XDR_DESTROY(&xdrs);

	/*
	 * Prepare the door arguments
	 *
	 * We don't know the size of the message the daemon
	 * will pass back to us.  By setting rbuf to NULL,
	 * we force the door code to allocate a buf of the
	 * appropriate size.  We must set rsize > 0, however,
	 * else the door code acts as if no response was
	 * expected and doesn't pass the data to us.
	 */
	da.data_ptr = (char *)abuf;
	da.data_size = absz;
	da.desc_ptr = NULL;
	da.desc_num = 0;
	da.rbuf = NULL;
	da.rsize = 1;

retry:
	mutex_enter(&mountd_lock);
	dh = mountd_dh;
	if (dh != NULL)
		door_ki_hold(dh);
	mutex_exit(&mountd_lock);

	if (dh == NULL) {
		/*
		 * The rendezvous point has not been established yet!
		 * This could mean that either mountd(1m) has not yet
		 * been started or that _this_ routine nuked the door
		 * handle after receiving an EINTR for a REVOKED door.
		 *
		 * Returning NFSAUTH_DROP will cause the NFS client
		 * to retransmit the request, so let's try to be more
		 * rescillient and attempt for ntries before we bail.
		 */
		if (++ntries % NFSAUTH_DR_TRYCNT) {
			delay(hz);
			goto retry;
		}

		kmem_free(abuf, absz);

		sys_log("nfsauth: mountd has not established door");
		*access = NFSAUTH_DROP;
		return (FALSE);
	}

	ntries = 0;

	/*
	 * Now that we've got what we need, place the call.
	 */
	switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) {
	case 0:				/* Success */
		door_ki_rele(dh);

		if (da.data_ptr == NULL && da.data_size == 0) {
			/*
			 * The door_return that contained the data
			 * failed! We're here because of the 2nd
			 * door_return (w/o data) such that we can
			 * get control of the thread (and exit
			 * gracefully).
			 */
			DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil,
			    door_arg_t *, &da);
			goto fail;
		}

		break;

	case EAGAIN:
		/*
		 * Server out of resources; back off for a bit
		 */
		door_ki_rele(dh);
		delay(hz);
		goto retry;
		/* NOTREACHED */

	case EINTR:
		if (!door_ki_info(dh, &di)) {
			door_ki_rele(dh);

			if (di.di_attributes & DOOR_REVOKED) {
				/*
				 * The server barfed and revoked
				 * the (existing) door on us; we
				 * want to wait to give smf(5) a
				 * chance to restart mountd(1m)
				 * and establish a new door handle.
				 */
				mutex_enter(&mountd_lock);
				if (dh == mountd_dh) {
					door_ki_rele(mountd_dh);
					mountd_dh = NULL;
				}
				mutex_exit(&mountd_lock);
				delay(hz);
				goto retry;
			}
			/*
			 * If the door was _not_ revoked on us,
			 * then more than likely we took an INTR,
			 * so we need to fail the operation.
			 */
			goto fail;
		}
		/*
		 * The only failure that can occur from getting
		 * the door info is EINVAL, so we let the code
		 * below handle it.
		 */
		/* FALLTHROUGH */

	case EBADF:
	case EINVAL:
	default:
		/*
		 * If we have a stale door handle, give smf a last
		 * chance to start it by sleeping for a little bit.
		 * If we're still hosed, we'll fail the call.
		 *
		 * Since we're going to reacquire the door handle
		 * upon the retry, we opt to sleep for a bit and
		 * _not_ to clear mountd_dh. If mountd restarted
		 * and was able to set mountd_dh, we should see
		 * the new instance; if not, we won't get caught
		 * up in the retry/DELAY loop.
		 */
		door_ki_rele(dh);
		if (!last) {
			delay(hz);
			last++;
			goto retry;
		}
		sys_log("nfsauth: stale mountd door handle");
		goto fail;
	}
Esempio n. 13
0
/*
 * nfscmd_send(arg, result)
 *
 * Send a command to the daemon listening on the door. The result is
 * returned in the result pointer if the function return value is
 * NFSCMD_ERR_SUCCESS. Otherwise it is the error value.
 */
int
nfscmd_send(nfscmd_arg_t *arg, nfscmd_res_t *res)
{
	door_handle_t	dh;
	door_arg_t	da;
	door_info_t	di;
	int		ntries = 0;
	int		last = 0;

retry:
	mutex_enter(&nfscmd_lock);
	dh = nfscmd_dh;
	if (dh != NULL)
		door_ki_hold(dh);
	mutex_exit(&nfscmd_lock);

	if (dh == NULL) {
		/*
		 * The rendezvous point has not been established yet !
		 * This could mean that either mountd(1m) has not yet
		 * been started or that _this_ routine nuked the door
		 * handle after receiving an EINTR for a REVOKED door.
		 *
		 * Returning NFSAUTH_DROP will cause the NFS client
		 * to retransmit the request, so let's try to be more
		 * rescillient and attempt for ntries before we bail.
		 */
		if (++ntries % NFSCMD_DR_TRYCNT) {
			delay(hz);
			goto retry;
		}
		return (NFSCMD_ERR_DROP);
	}

	da.data_ptr = (char *)arg;
	da.data_size = sizeof (nfscmd_arg_t);
	da.desc_ptr = NULL;
	da.desc_num = 0;
	da.rbuf = (char *)res;
	da.rsize = sizeof (nfscmd_res_t);

	switch (door_ki_upcall(dh, &da)) {
	case 0:
		/* Success */
		break;
	case EAGAIN:
		/* Need to retry a couple of times */
		door_ki_rele(dh);
		delay(hz);
		goto retry;
		/* NOTREACHED */
	case EINTR:
		if (!door_ki_info(dh, &di)) {
			if (di.di_attributes & DOOR_REVOKED) {
				/*
				 * The server barfed and revoked
				 * the (existing) door on us; we
				 * want to wait to give smf(5) a
				 * chance to restart mountd(1m)
				 * and establish a new door handle.
				 */
				mutex_enter(&nfscmd_lock);
				if (dh == nfscmd_dh)
					nfscmd_dh = NULL;
				mutex_exit(&nfscmd_lock);
				door_ki_rele(dh);
				delay(hz);
				goto retry;
			}
			/*
			 * If the door was _not_ revoked on us,
			 * then more than likely we took an INTR,
			 * so we need to fail the operation.
			 */
			door_ki_rele(dh);
		}
		/*
		 * The only failure that can occur from getting
		 * the door info is EINVAL, so we let the code
		 * below handle it.
		 */
		/* FALLTHROUGH */

	case EBADF:
	case EINVAL:
	default:
		/*
		 * If we have a stale door handle, give smf a last
		 * chance to start it by sleeping for a little bit.
		 * If we're still hosed, we'll fail the call.
		 *
		 * Since we're going to reacquire the door handle
		 * upon the retry, we opt to sleep for a bit and
		 * _not_ to clear mountd_dh. If mountd restarted
		 * and was able to set mountd_dh, we should see
		 * the new instance; if not, we won't get caught
		 * up in the retry/DELAY loop.
		 */
		door_ki_rele(dh);
		if (!last) {
			delay(hz);
			last++;
			goto retry;
		}
		res->error = NFSCMD_ERR_FAIL;
		break;
	}
	return (res->error);
}
Esempio n. 14
0
/*
 * Get the access information from the cache or callup to the mountd
 * to get and cache the access information in the kernel.
 */
int
nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor)
{
	struct netbuf		  addr;
	struct netbuf		 *claddr;
	struct auth_cache	**head;
	struct auth_cache	 *ap;
	int			  access;
	varg_t			  varg = {0};
	nfsauth_res_t		  res = {0};
	XDR			  xdrs_a;
	XDR			  xdrs_r;
	size_t			  absz;
	caddr_t			  abuf;
	size_t			  rbsz = (size_t)(BYTES_PER_XDR_UNIT * 2);
	char			  result[BYTES_PER_XDR_UNIT * 2] = {0};
	caddr_t			  rbuf = (caddr_t)&result;
	int			  last = 0;
	door_arg_t		  da;
	door_info_t		  di;
	door_handle_t		  dh;
	uint_t			  ntries = 0;

	/*
	 * Now check whether this client already
	 * has an entry for this flavor in the cache
	 * for this export.
	 * Get the caller's address, mask off the
	 * parts of the address that do not identify
	 * the host (port number, etc), and then hash
	 * it to find the chain of cache entries.
	 */

	claddr = svc_getrpccaller(req->rq_xprt);
	addr = *claddr;
	addr.buf = kmem_alloc(addr.len, KM_SLEEP);
	bcopy(claddr->buf, addr.buf, claddr->len);
	addrmask(&addr, svc_getaddrmask(req->rq_xprt));
	head = &exi->exi_cache[hash(&addr)];

	rw_enter(&exi->exi_cache_lock, RW_READER);
	for (ap = *head; ap; ap = ap->auth_next) {
		if (EQADDR(&addr, &ap->auth_addr) && flavor == ap->auth_flavor)
			break;
	}
	if (ap) {				/* cache hit */
		access = ap->auth_access;
		ap->auth_time = gethrestime_sec();
		nfsauth_cache_hit++;
	}

	rw_exit(&exi->exi_cache_lock);

	if (ap) {
		kmem_free(addr.buf, addr.len);
		return (access);
	}

	nfsauth_cache_miss++;

	/*
	 * No entry in the cache for this client/flavor
	 * so we need to call the nfsauth service in the
	 * mount daemon.
	 */
retry:
	mutex_enter(&mountd_lock);
	dh = mountd_dh;
	if (dh)
		door_ki_hold(dh);
	mutex_exit(&mountd_lock);

	if (dh == NULL) {
		/*
		 * The rendezvous point has not been established yet !
		 * This could mean that either mountd(1m) has not yet
		 * been started or that _this_ routine nuked the door
		 * handle after receiving an EINTR for a REVOKED door.
		 *
		 * Returning NFSAUTH_DROP will cause the NFS client
		 * to retransmit the request, so let's try to be more
		 * rescillient and attempt for ntries before we bail.
		 */
		if (++ntries % NFSAUTH_DR_TRYCNT) {
			delay(hz);
			goto retry;
		}
		sys_log("nfsauth: mountd has not established door");
		kmem_free(addr.buf, addr.len);
		return (NFSAUTH_DROP);
	}
	ntries = 0;
	varg.vers = V_PROTO;
	varg.arg_u.arg.cmd = NFSAUTH_ACCESS;
	varg.arg_u.arg.areq.req_client.n_len = addr.len;
	varg.arg_u.arg.areq.req_client.n_bytes = addr.buf;
	varg.arg_u.arg.areq.req_netid = svc_getnetid(req->rq_xprt);
	varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path;
	varg.arg_u.arg.areq.req_flavor = flavor;

	/*
	 * Setup the XDR stream for encoding the arguments. Notice that
	 * in addition to the args having variable fields (req_netid and
	 * req_path), the argument data structure is itself versioned,
	 * so we need to make sure we can size the arguments buffer
	 * appropriately to encode all the args. If we can't get sizing
	 * info _or_ properly encode the arguments, there's really no
	 * point in continuting, so we fail the request.
	 */
	DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg);
	if ((absz = xdr_sizeof(xdr_varg, (void *)&varg)) == 0) {
		door_ki_rele(dh);
		kmem_free(addr.buf, addr.len);
		return (NFSAUTH_DENIED);
	}
	abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP);
	xdrmem_create(&xdrs_a, abuf, absz, XDR_ENCODE);
	if (!xdr_varg(&xdrs_a, &varg)) {
		door_ki_rele(dh);
		goto fail;
	}
	XDR_DESTROY(&xdrs_a);

	/*
	 * The result (nfsauth_res_t) is always two int's, so we don't
	 * have to dynamically size (or allocate) the results buffer.
	 * Now that we've got what we need, we prep the door arguments
	 * and place the call.
	 */
	da.data_ptr = (char *)abuf;
	da.data_size = absz;
	da.desc_ptr = NULL;
	da.desc_num = 0;
	da.rbuf = (char *)rbuf;
	da.rsize = rbsz;

	switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) {
		case 0:				/* Success */
			if (da.data_ptr != da.rbuf && da.data_size == 0) {
				/*
				 * The door_return that contained the data
				 * failed ! We're here because of the 2nd
				 * door_return (w/o data) such that we can
				 * get control of the thread (and exit
				 * gracefully).
				 */
				DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil,
				    door_arg_t *, &da);
				door_ki_rele(dh);
				goto fail;

			} else if (rbuf != da.rbuf) {
Esempio n. 15
0
/*
 * This function is not MultiThread safe. The caller has to make sure only one
 * thread calls this function.
 */
void
smb_kshare_door_fini(door_handle_t dhdl)
{
	if (dhdl)
		door_ki_rele(dhdl);
}
Esempio n. 16
0
/* ARGSUSED */
static int
pppt_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred,
    int *retval)
{
	int				rc;
	void				*buf;
	size_t				buf_size;
	pppt_iocdata_t			iocd;
	door_handle_t			new_handle;

	if (drv_priv(cred) != 0) {
		return (EPERM);
	}

	rc = ddi_copyin((void *)argp, &iocd, sizeof (iocd), flag);
	if (rc)
		return (EFAULT);

	if (iocd.pppt_version != PPPT_VERSION_1)
		return (EINVAL);

	switch (cmd) {
	case PPPT_MESSAGE:

		/* XXX limit buf_size ? */
		buf_size = (size_t)iocd.pppt_buf_size;
		buf = kmem_alloc(buf_size, KM_SLEEP);
		if (buf == NULL)
			return (ENOMEM);

		rc = ddi_copyin((void *)(unsigned long)iocd.pppt_buf,
		    buf, buf_size, flag);
		if (rc) {
			kmem_free(buf, buf_size);
			return (EFAULT);
		}

		stmf_ic_rx_msg(buf, buf_size);

		kmem_free(buf, buf_size);
		break;
	case PPPT_INSTALL_DOOR:

		new_handle = door_ki_lookup((int)iocd.pppt_door_fd);
		if (new_handle == NULL)
			return (EINVAL);

		mutex_enter(&pppt_global.global_door_lock);
		ASSERT(pppt_global.global_svc_state == PSS_ENABLED);
		if (pppt_global.global_door != NULL) {
			/*
			 * There can only be one door installed
			 */
			mutex_exit(&pppt_global.global_door_lock);
			door_ki_rele(new_handle);
			return (EBUSY);
		}
		pppt_global.global_door = new_handle;
		mutex_exit(&pppt_global.global_door_lock);
		break;
	}

	return (rc);
}
Esempio n. 17
0
/*
 * log_event_upcall - Perform the upcall to syseventd for event buffer delivery.
 * 			Check for rebinding errors
 * 			This buffer is reused to by the syseventd door_return
 *			to hold the result code
 */
static int
log_event_upcall(log_event_upcall_arg_t *arg)
{
	int error;
	size_t size;
	sysevent_t *ev;
	door_arg_t darg, save_arg;
	int retry;
	int neagain = 0;
	int neintr = 0;
	int nticks = LOG_EVENT_MIN_PAUSE;

	/* Initialize door args */
	ev = (sysevent_t *)&arg->buf;
	size = sizeof (log_event_upcall_arg_t) + SE_PAYLOAD_SZ(ev);

	darg.rbuf = (char *)arg;
	darg.data_ptr = (char *)arg;
	darg.rsize = size;
	darg.data_size = size;
	darg.desc_ptr = NULL;
	darg.desc_num = 0;

	LOG_DEBUG1((CE_CONT, "log_event_upcall: 0x%llx\n",
	    (longlong_t)SE_SEQ((sysevent_t *)&arg->buf)));

	save_arg = darg;
	for (retry = 0; ; retry++) {

		mutex_enter(&event_door_mutex);
		if (event_door == NULL) {
			mutex_exit(&event_door_mutex);

			return (EBADF);
		}

		if ((error = door_ki_upcall_limited(event_door, &darg, NULL,
		    SIZE_MAX, 0)) == 0) {
			mutex_exit(&event_door_mutex);
			break;
		}

		/*
		 * EBADF is handled outside the switch below because we need to
		 * hold event_door_mutex a bit longer
		 */
		if (error == EBADF) {
			/* Server died */
			door_ki_rele(event_door);
			event_door = NULL;

			mutex_exit(&event_door_mutex);
			return (error);
		}

		mutex_exit(&event_door_mutex);

		/*
		 * The EBADF case is already handled above with event_door_mutex
		 * held
		 */
		switch (error) {
		case EINTR:
			neintr++;
			log_event_pause(2);
			darg = save_arg;
			break;
		case EAGAIN:
			/* cannot deliver upcall - process may be forking */
			neagain++;
			log_event_pause(nticks);
			nticks <<= 1;
			if (nticks > LOG_EVENT_MAX_PAUSE)
				nticks = LOG_EVENT_MAX_PAUSE;
			darg = save_arg;
			break;
		default:
			cmn_err(CE_CONT,
			    "log_event_upcall: door_ki_upcall error %d\n",
			    error);
			return (error);
		}
	}

	if (neagain > 0 || neintr > 0) {
		LOG_DEBUG((CE_CONT, "upcall: eagain=%d eintr=%d nticks=%d\n",
		    neagain, neintr, nticks));
	}

	LOG_DEBUG1((CE_CONT, "log_event_upcall:\n\t"
	    "error=%d rptr1=%p rptr2=%p dptr2=%p ret1=%x ret2=%x\n",
	    error, (void *)arg, (void *)darg.rbuf,
	    (void *)darg.data_ptr,
	    *((int *)(darg.rbuf)), *((int *)(darg.data_ptr))));

	if (!error) {
		/*
		 * upcall was successfully executed. Check return code.
		 */
		error = *((int *)(darg.rbuf));
	}

	return (error);
}