Esempio n. 1
0
int
smbfsinit(int fstyp, char *name)
{
	int		error;

	error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops);
	if (error != 0) {
		zcmn_err(GLOBAL_ZONEID, CE_WARN,
		    "smbfsinit: bad vfs ops template");
		return (error);
	}

	error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops);
	if (error != 0) {
		(void) vfs_freevfsops_by_type(fstyp);
		zcmn_err(GLOBAL_ZONEID, CE_WARN,
		    "smbfsinit: bad vnode ops template");
		return (error);
	}

	smbfsfstyp = fstyp;

	return (0);
}
Esempio n. 2
0
/*
 * Converts a utf8 string to a C string.
 * allocs a new string if not supplied
 */
char *
utf8_to_str(utf8string *str, uint_t *lenp, char *s)
{
    char	*sp;
    char	*u8p;
    int	len;
    int	 i;

    ASSERT(lenp != NULL);

    if (str == NULL)
        return (NULL);

    u8p = str->utf8string_val;
    len = str->utf8string_len;
    if (len <= 0 || u8p == NULL) {
        if (s)
            *s = '\0';
        return (NULL);
    }

    sp = s;
    if (sp == NULL) {
        sp = calloc(1, len + 1);
        if (sp == NULL)
            return (NULL);
    }

    /*
     * At least check for embedded nulls
     */
    for (i = 0; i < len; i++) {
        sp[i] = u8p[i];
        if (u8p[i] == '\0') {
#ifdef	DEBUG
            zcmn_err(getzoneid(), CE_WARN,
                     "Embedded NULL in UTF-8 string");
#endif
            if (s == NULL)
                free(sp);
            return (NULL);
        }
    }
    sp[len] = '\0';
    *lenp = len + 1;

    return (sp);
}
/*
 * We have seen a case that the fh passed in is for "." which
 * should be a VROOT node, however, the fh is different from the
 * root fh stored in the mntinfo4_t. The invalid fh might be
 * from a misbehaved server and will panic the client system at
 * a later time. To avoid the panic, we drop the bad fh, use
 * the root fh from mntinfo4_t, and print an error message
 * for attention.
 */
nfs4_sharedfh_t *
badrootfh_check(nfs4_sharedfh_t *fh, nfs4_fname_t *nm, mntinfo4_t *mi,
    int *wasbad)
{
	char *s;

	*wasbad = 0;
	s = fn_name(nm);
	ASSERT(strcmp(s, "..") != 0);

	if ((s[0] == '.' && s[1] == '\0') && fh &&
	    !SFH4_SAME(mi->mi_rootfh, fh)) {
#ifdef DEBUG
		nfs4_fhandle_t fhandle;

		zcmn_err(mi->mi_zone->zone_id, CE_WARN,
		    "Server %s returns a different "
		    "root filehandle for the path %s:",
		    mi->mi_curr_serv->sv_hostname,
		    mi->mi_curr_serv->sv_path);

		/* print the bad fh */
		fhandle.fh_len = fh->sfh_fh.nfs_fh4_len;
		bcopy(fh->sfh_fh.nfs_fh4_val, fhandle.fh_buf,
		    fhandle.fh_len);
		nfs4_printfhandle(&fhandle);

		/* print mi_rootfh */
		fhandle.fh_len = mi->mi_rootfh->sfh_fh.nfs_fh4_len;
		bcopy(mi->mi_rootfh->sfh_fh.nfs_fh4_val, fhandle.fh_buf,
		    fhandle.fh_len);
		nfs4_printfhandle(&fhandle);
#endif
		/* use mi_rootfh instead; fh will be rele by the caller */
		fh = mi->mi_rootfh;
		*wasbad = 1;
	}

	kmem_free(s, MAXNAMELEN);
	return (fh);
}
int
nfs4_rnode_init(void)
{
	ulong_t nrnode4_max;
	int i;

	/*
	 * Compute the size of the rnode4 hash table
	 */
	if (nrnode <= 0)
		nrnode = ncsize;
	nrnode4_max =
	    (ulong_t)((kmem_maxavail() >> 2) / sizeof (struct rnode4));
	if (nrnode > nrnode4_max || (nrnode == 0 && ncsize == 0)) {
		zcmn_err(GLOBAL_ZONEID, CE_NOTE,
		    "setting nrnode to max value of %ld", nrnode4_max);
		nrnode = nrnode4_max;
	}
	rtable4size = 1 << highbit(nrnode / rnode4_hashlen);
	rtable4mask = rtable4size - 1;

	/*
	 * Allocate and initialize the hash buckets
	 */
	rtable4 = kmem_alloc(rtable4size * sizeof (*rtable4), KM_SLEEP);
	for (i = 0; i < rtable4size; i++) {
		rtable4[i].r_hashf = (rnode4_t *)(&rtable4[i]);
		rtable4[i].r_hashb = (rnode4_t *)(&rtable4[i]);
		rw_init(&rtable4[i].r_lock, NULL, RW_DEFAULT, NULL);
	}

	rnode4_cache = kmem_cache_create("rnode4_cache", sizeof (rnode4_t),
	    0, NULL, NULL, nfs4_reclaim, NULL, NULL, 0);

	return (0);
}
Esempio n. 5
0
/*
 * Called by proc_exit() when a zone's init exits, presumably because
 * it failed.  As long as the given zone is still in the "running"
 * state, we will re-exec() init, but first we need to reset things
 * which are usually inherited across exec() but will break init's
 * assumption that it is being exec()'d from a virgin process.  Most
 * importantly this includes closing all file descriptors (exec only
 * closes those marked close-on-exec) and resetting signals (exec only
 * resets handled signals, and we need to clear any signals which
 * killed init).  Anything else that exec(2) says would be inherited,
 * but would affect the execution of init, needs to be reset.
 */
static int
restart_init(int what, int why)
{
	kthread_t *t = curthread;
	klwp_t *lwp = ttolwp(t);
	proc_t *p = ttoproc(t);
	user_t *up = PTOU(p);

	vnode_t *oldcd, *oldrd;
	int i, err;
	char reason_buf[64];

	/*
	 * Let zone admin (and global zone admin if this is for a non-global
	 * zone) know that init has failed and will be restarted.
	 */
	zcmn_err(p->p_zone->zone_id, CE_WARN,
	    "init(1M) %s: restarting automatically",
	    exit_reason(reason_buf, sizeof (reason_buf), what, why));

	if (!INGLOBALZONE(p)) {
		cmn_err(CE_WARN, "init(1M) for zone %s (pid %d) %s: "
		    "restarting automatically",
		    p->p_zone->zone_name, p->p_pid, reason_buf);
	}

	/*
	 * Remove any fpollinfo_t's for this (last) thread from our file
	 * descriptors so closeall() can ASSERT() that they're all gone.
	 * Then close all open file descriptors in the process.
	 */
	pollcleanup();
	closeall(P_FINFO(p));

	/*
	 * Grab p_lock and begin clearing miscellaneous global process
	 * state that needs to be reset before we exec the new init(1M).
	 */

	mutex_enter(&p->p_lock);
	prbarrier(p);

	p->p_flag &= ~(SKILLED | SEXTKILLED | SEXITING | SDOCORE);
	up->u_cmask = CMASK;

	sigemptyset(&t->t_hold);
	sigemptyset(&t->t_sig);
	sigemptyset(&t->t_extsig);

	sigemptyset(&p->p_sig);
	sigemptyset(&p->p_extsig);

	sigdelq(p, t, 0);
	sigdelq(p, NULL, 0);

	if (p->p_killsqp) {
		siginfofree(p->p_killsqp);
		p->p_killsqp = NULL;
	}

	/*
	 * Reset any signals that are ignored back to the default disposition.
	 * Other u_signal members will be cleared when exec calls sigdefault().
	 */
	for (i = 1; i < NSIG; i++) {
		if (up->u_signal[i - 1] == SIG_IGN) {
			up->u_signal[i - 1] = SIG_DFL;
			sigemptyset(&up->u_sigmask[i - 1]);
		}
	}

	/*
	 * Clear the current signal, any signal info associated with it, and
	 * any signal information from contracts and/or contract templates.
	 */
	lwp->lwp_cursig = 0;
	lwp->lwp_extsig = 0;
	if (lwp->lwp_curinfo != NULL) {
		siginfofree(lwp->lwp_curinfo);
		lwp->lwp_curinfo = NULL;
	}
	lwp_ctmpl_clear(lwp);

	/*
	 * Reset both the process root directory and the current working
	 * directory to the root of the zone just as we do during boot.
	 */
	VN_HOLD(p->p_zone->zone_rootvp);
	oldrd = up->u_rdir;
	up->u_rdir = p->p_zone->zone_rootvp;

	VN_HOLD(p->p_zone->zone_rootvp);
	oldcd = up->u_cdir;
	up->u_cdir = p->p_zone->zone_rootvp;

	if (up->u_cwd != NULL) {
		refstr_rele(up->u_cwd);
		up->u_cwd = NULL;
	}

	mutex_exit(&p->p_lock);

	if (oldrd != NULL)
		VN_RELE(oldrd);
	if (oldcd != NULL)
		VN_RELE(oldcd);

	/* Free the controlling tty.  (freectty() always assumes curproc.) */
	ASSERT(p == curproc);
	(void) freectty(B_TRUE);

	/*
	 * Now exec() the new init(1M) on top of the current process.  If we
	 * succeed, the caller will treat this like a successful system call.
	 * If we fail, we issue messages and the caller will proceed with exit.
	 */
	err = exec_init(p->p_zone->zone_initname, NULL);

	if (err == 0)
		return (0);

	zcmn_err(p->p_zone->zone_id, CE_WARN,
	    "failed to restart init(1M) (err=%d): system reboot required", err);

	if (!INGLOBALZONE(p)) {
		cmn_err(CE_WARN, "failed to restart init(1M) for zone %s "
		    "(pid %d, err=%d): zoneadm(1M) boot required",
		    p->p_zone->zone_name, p->p_pid, err);
	}

	return (-1);
}
Esempio n. 6
0
/*
 * Construct a stack for init containing the arguments to it, then
 * pass control to exec_common.
 */
int
exec_init(const char *initpath, const char *args)
{
	caddr32_t ucp;
	caddr32_t *uap;
	caddr32_t *argv;
	caddr32_t exec_fnamep;
	char *scratchargs;
	int i, sarg;
	size_t argvlen, alen;
	boolean_t in_arg;
	int argc = 0;
	int error = 0, count = 0;
	proc_t *p = ttoproc(curthread);
	klwp_t *lwp = ttolwp(curthread);
	int brand_action;

	if (args == NULL)
		args = "";

	alen = strlen(initpath) + 1 + strlen(args) + 1;
	scratchargs = kmem_alloc(alen, KM_SLEEP);
	(void) snprintf(scratchargs, alen, "%s %s", initpath, args);

	/*
	 * We do a quick two state parse of the string to sort out how big
	 * argc should be.
	 */
	in_arg = B_FALSE;
	for (i = 0; i < strlen(scratchargs); i++) {
		if (scratchargs[i] == ' ' || scratchargs[i] == '\0') {
			if (in_arg) {
				in_arg = B_FALSE;
				argc++;
			}
		} else {
			in_arg = B_TRUE;
		}
	}
	argvlen = sizeof (caddr32_t) * (argc + 1);
	argv = kmem_zalloc(argvlen, KM_SLEEP);

	/*
	 * We pull off a bit of a hack here.  We work our way through the
	 * args string, putting nulls at the ends of space delimited tokens
	 * (boot args don't support quoting at this time).  Then we just
	 * copy the whole mess to userland in one go.  In other words, we
	 * transform this: "init -s -r\0" into this on the stack:
	 *
	 *	-0x00 \0
	 *	-0x01 r
	 *	-0x02 -  <--------.
	 *	-0x03 \0	  |
	 *	-0x04 s		  |
	 *	-0x05 -  <------. |
	 *	-0x06 \0	| |
	 *	-0x07 t		| |
	 *	-0x08 i 	| |
	 *	-0x09 n		| |
	 *	-0x0a i  <---.  | |
	 *	-0x10 NULL   |  | |	(argv[3])
	 *	-0x14   -----|--|-'	(argv[2])
	 *	-0x18  ------|--'	(argv[1])
	 *	-0x1c -------'		(argv[0])
	 *
	 * Since we know the value of ucp at the beginning of this process,
	 * we can trivially compute the argv[] array which we also need to
	 * place in userland: argv[i] = ucp - sarg(i), where ucp is the
	 * stack ptr, and sarg is the string index of the start of the
	 * argument.
	 */
	ucp = (caddr32_t)(uintptr_t)p->p_usrstack;

	argc = 0;
	in_arg = B_FALSE;
	sarg = 0;

	for (i = 0; i < alen; i++) {
		if (scratchargs[i] == ' ' || scratchargs[i] == '\0') {
			if (in_arg == B_TRUE) {
				in_arg = B_FALSE;
				scratchargs[i] = '\0';
				argv[argc++] = ucp - (alen - sarg);
			}
		} else if (in_arg == B_FALSE) {
			in_arg = B_TRUE;
			sarg = i;
		}
	}
	ucp -= alen;
	error |= copyout(scratchargs, (caddr_t)(uintptr_t)ucp, alen);

	uap = (caddr32_t *)P2ALIGN((uintptr_t)ucp, sizeof (caddr32_t));
	uap--;	/* advance to be below the word we're in */
	uap -= (argc + 1);	/* advance argc words down, plus one for NULL */
	error |= copyout(argv, uap, argvlen);

	if (error != 0) {
		zcmn_err(p->p_zone->zone_id, CE_WARN,
		    "Could not construct stack for init.\n");
		kmem_free(argv, argvlen);
		kmem_free(scratchargs, alen);
		return (EFAULT);
	}

	exec_fnamep = argv[0];
	kmem_free(argv, argvlen);
	kmem_free(scratchargs, alen);

	/*
	 * Point at the arguments.
	 */
	lwp->lwp_ap = lwp->lwp_arg;
	lwp->lwp_arg[0] = (uintptr_t)exec_fnamep;
	lwp->lwp_arg[1] = (uintptr_t)uap;
	lwp->lwp_arg[2] = NULL;
	curthread->t_post_sys = 1;
	curthread->t_sysnum = SYS_execve;

	/*
	 * If we are executing init from zsched, we may have inherited its
	 * parent process's signal mask.  Clear it now so that we behave in
	 * the same way as when started from the global zone.
	 */
	sigemptyset(&curthread->t_hold);

	brand_action = ZONE_IS_BRANDED(p->p_zone) ? EBA_BRAND : EBA_NONE;
again:
	error = exec_common((const char *)(uintptr_t)exec_fnamep,
	    (const char **)(uintptr_t)uap, NULL, brand_action);

	/*
	 * Normally we would just set lwp_argsaved and t_post_sys and
	 * let post_syscall reset lwp_ap for us.  Unfortunately,
	 * exec_init isn't always called from a system call.  Instead
	 * of making a mess of trap_cleanup, we just reset the args
	 * pointer here.
	 */
	reset_syscall_args();

	switch (error) {
	case 0:
		return (0);

	case ENOENT:
		zcmn_err(p->p_zone->zone_id, CE_WARN,
		    "exec(%s) failed (file not found).\n", initpath);
		return (ENOENT);

	case EAGAIN:
	case EINTR:
		++count;
		if (count < 5) {
			zcmn_err(p->p_zone->zone_id, CE_WARN,
			    "exec(%s) failed with errno %d.  Retrying...\n",
			    initpath, error);
			goto again;
		}
	}

	zcmn_err(p->p_zone->zone_id, CE_WARN,
	    "exec(%s) failed with errno %d.", initpath, error);
	return (error);
}
void
r4_do_attrcache(vnode_t *vp, nfs4_ga_res_t *garp, int newnode,
    hrtime_t t, cred_t *cr, int index)
{
	int is_stub;
	vattr_t *attr;
	/*
	 * Don't add to attrcache if time overflow, but
	 * no need to check because either attr is null or the time
	 * values in it were processed by nfs4_time_ntov(), which checks
	 * for time overflows.
	 */
	attr = garp ? &garp->n4g_va : NULL;

	if (attr) {
		if (!newnode) {
			rw_exit(&rtable4[index].r_lock);
#ifdef DEBUG
			if (vp->v_type != attr->va_type &&
			    vp->v_type != VNON && attr->va_type != VNON) {
				zcmn_err(VTOMI4(vp)->mi_zone->zone_id, CE_WARN,
				    "makenfs4node: type (%d) doesn't "
				    "match type of found node at %p (%d)",
				    attr->va_type, (void *)vp, vp->v_type);
			}
#endif
			nfs4_attr_cache(vp, garp, t, cr, TRUE, NULL);
		} else {
			rnode4_t *rp = VTOR4(vp);

			vp->v_type = attr->va_type;
			vp->v_rdev = attr->va_rdev;

			/*
			 * Turn this object into a "stub" object if we
			 * crossed an underlying server fs boundary.
			 * To make this check, during mount we save the
			 * fsid of the server object being mounted.
			 * Here we compare this object's server fsid
			 * with the fsid we saved at mount.  If they
			 * are different, we crossed server fs boundary.
			 *
			 * The stub type is set (or not) at rnode
			 * creation time and it never changes for life
			 * of the rnode.
			 *
			 * The stub type is also set during RO failover,
			 * nfs4_remap_file().
			 *
			 * This stub will be for a mirror-mount.
			 *
			 * We don't bother with taking r_state_lock to
			 * set the stub type because this is a new rnode
			 * and we're holding the hash bucket r_lock RW_WRITER.
			 * No other thread could have obtained access
			 * to this rnode.
			 */
			is_stub = 0;
			if (garp->n4g_fsid_valid) {
				fattr4_fsid ga_fsid = garp->n4g_fsid;
				servinfo4_t *svp = rp->r_server;

				rp->r_srv_fsid = ga_fsid;

				(void) nfs_rw_enter_sig(&svp->sv_lock,
				    RW_READER, 0);
				if (!FATTR4_FSID_EQ(&ga_fsid, &svp->sv_fsid))
					is_stub = 1;
				nfs_rw_exit(&svp->sv_lock);
			}

			if (is_stub)
				r4_stub_mirrormount(rp);
			else
				r4_stub_none(rp);

			/* Can not cache partial attr */
			if (attr->va_mask == AT_ALL)
				nfs4_attrcache_noinval(vp, garp, t);
			else
				PURGE_ATTRCACHE4(vp);

			rw_exit(&rtable4[index].r_lock);
		}
	} else {
		if (newnode) {
			PURGE_ATTRCACHE4(vp);
		}
		rw_exit(&rtable4[index].r_lock);
	}
}