コード例 #1
0
ファイル: tlabel.c プロジェクト: apprisi/illumos-gate
/*
 * There's no protocol today to obtain the label from the server.
 * So we rely on conventions: zones, zone names, and zone paths
 * must match across TX servers and their TX clients.  Now use
 * the exported name to find the equivalent local zone and its
 * label.  Caller is responsible for doing a label_rele of the
 * returned ts_label.
 */
ts_label_t *
getflabel_cipso(vfs_t *vfsp)
{
	zone_t	*reszone;
	zone_t	*new_reszone;
	char	*nfspath, *respath;
	refstr_t	*resource_ref;
	boolean_t	treat_abs = B_FALSE;

	if (vfsp->vfs_resource == NULL)
		return (NULL);			/* error */
	resource_ref = vfs_getresource(vfsp);

	nfspath = (char *)refstr_value(resource_ref);
	respath = strchr(nfspath, ':');		/* skip server name */
	if (respath)
		respath++;			/* skip over ":" */
	if (*respath != '/') {
		/* treat path as absolute but it doesn't have leading '/' */
		treat_abs = B_TRUE;
	}

	reszone = zone_find_by_any_path(respath, treat_abs);
	if (reszone == global_zone) {
		refstr_rele(resource_ref);
		label_hold(l_admin_low);
		zone_rele(reszone);
		return (l_admin_low);
	}

	/*
	 * Skip over zonepath (not including "root"), e.g. /zone/internal
	 */
	respath += reszone->zone_rootpathlen - 7;
	if (treat_abs)
		respath--;			/* no leading '/' to skip */
	if (strncmp(respath, "/root/", 6) == 0) {
		/* Check if we now have something like "/zone/public/" */

		respath += 5;			/* skip "/root" first */
		new_reszone = zone_find_by_any_path(respath, B_FALSE);
		if (new_reszone != global_zone) {
			zone_rele(reszone);
			reszone = new_reszone;
		} else {
			zone_rele(new_reszone);
		}
	}

	refstr_rele(resource_ref);
	label_hold(reszone->zone_slabel);
	zone_rele(reszone);

	return (reszone->zone_slabel);
}
コード例 #2
0
static void
zfsctl_rename_snap(zfsctl_snapdir_t *sdp, zfs_snapentry_t *sep, const char *nm)
{
	avl_index_t where;
	vfs_t *vfsp;
	refstr_t *pathref;
	char newpath[MAXNAMELEN];
	char *tail;

	ASSERT(MUTEX_HELD(&sdp->sd_lock));
	ASSERT(sep != NULL);

	vfsp = vn_mountedvfs(sep->se_root);
	ASSERT(vfsp != NULL);

	vfs_lock_wait(vfsp);

	/*
	 * Change the name in the AVL tree.
	 */
	avl_remove(&sdp->sd_snaps, sep);
	kmem_free(sep->se_name, strlen(sep->se_name) + 1);
	sep->se_name = kmem_alloc(strlen(nm) + 1, KM_SLEEP);
	(void) strcpy(sep->se_name, nm);
	VERIFY(avl_find(&sdp->sd_snaps, sep, &where) == NULL);
	avl_insert(&sdp->sd_snaps, sep, where);

	/*
	 * Change the current mountpoint info:
	 * 	- update the tail of the mntpoint path
	 *	- update the tail of the resource path
	 */
	pathref = vfs_getmntpoint(vfsp);
	(void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
	VERIFY((tail = strrchr(newpath, '/')) != NULL);
	*(tail+1) = '\0';
	ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
	(void) strcat(newpath, nm);
	refstr_rele(pathref);
	vfs_setmntpoint(vfsp, newpath);

	pathref = vfs_getresource(vfsp);
	(void) strncpy(newpath, refstr_value(pathref), sizeof (newpath));
	VERIFY((tail = strrchr(newpath, '@')) != NULL);
	*(tail+1) = '\0';
	ASSERT3U(strlen(newpath) + strlen(nm), <, sizeof (newpath));
	(void) strcat(newpath, nm);
	refstr_rele(pathref);
	vfs_setresource(vfsp, newpath);

	vfs_unlock(vfsp);
}
コード例 #3
0
ファイル: tlabel.c プロジェクト: apprisi/illumos-gate
/*
 * Get the label if any of a zfs filesystem.  Get the dataset, then
 * get its mlslabel property, convert as needed, and return it.  If
 * there's no mlslabel or it is the default one, return NULL.
 */
static ts_label_t *
getflabel_zfs(vfs_t *vfsp)
{
	int		error;
	ts_label_t	*tsl = NULL;
	refstr_t	*resource_ref;
	bslabel_t	ds_sl;
	char		ds_hexsl[MAXNAMELEN];
	const char	*osname;

	resource_ref = vfs_getresource(vfsp);
	osname = refstr_value(resource_ref);

	error = dsl_prop_get(osname, zfs_prop_to_name(ZFS_PROP_MLSLABEL),
	    1, sizeof (ds_hexsl), &ds_hexsl, NULL);
	refstr_rele(resource_ref);

	if ((error) || (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) == 0))
		return (NULL);
	if (hexstr_to_label(ds_hexsl, &ds_sl) != 0)
		return (NULL);

	tsl = labelalloc(&ds_sl, default_doi, KM_SLEEP);
	return (tsl);
}
コード例 #4
0
void
corectl_path_rele(corectl_path_t *ccp)
{
	if (atomic_add_32_nv(&ccp->ccp_refcnt, -1) == 0) {
		refstr_rele(ccp->ccp_path);
		kmem_free(ccp, sizeof (corectl_path_t));
	}
}
コード例 #5
0
static void
corectl_path_set(corectl_path_t *ccp, const char *path)
{
	refstr_t *npath = refstr_alloc(path);

	mutex_enter(&ccp->ccp_mtx);
	refstr_rele(ccp->ccp_path);
	ccp->ccp_path = npath;
	mutex_exit(&ccp->ccp_mtx);
}
コード例 #6
0
/*ARGSUSED*/
static void
core_free_zone(zoneid_t zoneid, void *arg)
{
	struct core_globals *cg = arg;

	if (cg == NULL)
		return;
	if (cg->core_file != NULL)
		refstr_rele(cg->core_file);
	corectl_path_rele(cg->core_default_path);
	corectl_content_rele(cg->core_default_content);
	kmem_free(cg, sizeof (*cg));
}
コード例 #7
0
/*
 * Extract the volume name.
 */
static void
smb_tree_get_volname(vfs_t *vfsp, smb_tree_t *tree)
{
	refstr_t *vfs_mntpoint;
	const char *s;
	char *name;

	vfs_mntpoint = vfs_getmntpoint(vfsp);

	s = vfs_mntpoint->rs_string;
	s += strspn(s, "/");
	(void) strlcpy(tree->t_volume, s, SMB_VOLNAMELEN);

	refstr_rele(vfs_mntpoint);

	name = tree->t_volume;
	(void) strsep((char **)&name, "/");
}
コード例 #8
0
ファイル: lofs_subr.c プロジェクト: mikess/illumos-gate
/*
 * Free lfs node since no longer in use
 */
static void
freelfsnode(struct lfsnode *lfs, struct loinfo *li)
{
    struct lfsnode *prev = NULL;
    struct lfsnode *this;

    ASSERT(MUTEX_HELD(&li->li_lfslock));
    ASSERT(li->li_refct > 0);
    for (this = li->li_lfs; this != NULL; this = this->lfs_next) {
        if (this == lfs) {
            ASSERT(lfs->lfs_vfs.vfs_count == 1);
            if (prev == NULL)
                li->li_lfs = lfs->lfs_next;
            else
                prev->lfs_next = lfs->lfs_next;
            if (lfs->lfs_realrootvp != NULL) {
                VN_RELE(lfs->lfs_realrootvp);
            }
            if (lfs->lfs_vfs.vfs_mntpt != NULL)
                refstr_rele(lfs->lfs_vfs.vfs_mntpt);
            if (lfs->lfs_vfs.vfs_implp != NULL) {
                ASSERT(lfs->lfs_vfs.vfs_femhead == NULL);
                ASSERT(lfs->lfs_vfs.vfs_vskap == NULL);
                ASSERT(lfs->lfs_vfs.vfs_fstypevsp == NULL);
                kmem_free(lfs->lfs_vfs.vfs_implp,
                          sizeof (vfs_impl_t));
            }
            sema_destroy(&lfs->lfs_vfs.vfs_reflock);
            kmem_free(lfs, sizeof (struct lfsnode));
            return;
        }
        prev = this;
    }
    panic("freelfsnode");
    /*NOTREACHED*/
}
コード例 #9
0
ファイル: tlabel.c プロジェクト: apprisi/illumos-gate
/*
 * getflabel -
 *
 * Return pointer to the ts_label associated with the specified file,
 * or returns NULL if error occurs.  Caller is responsible for doing
 * a label_rele of the ts_label.
 */
ts_label_t *
getflabel(vnode_t *vp)
{
	vfs_t		*vfsp, *rvfsp;
	vnode_t		*rvp, *rvp2;
	zone_t		*zone;
	ts_label_t	*zl;
	int		err;
	boolean_t	vfs_is_held = B_FALSE;
	char		vpath[MAXPATHLEN];

	ASSERT(vp);
	vfsp = vp->v_vfsp;
	if (vfsp == NULL)
		return (NULL);

	rvp = vp;

	/*
	 * Traverse lofs mounts and fattach'es to get the real vnode
	 */
	if (VOP_REALVP(rvp, &rvp2, NULL) == 0)
		rvp = rvp2;

	rvfsp = rvp->v_vfsp;

	/* rvp/rvfsp now represent the real vnode/vfs we will be using */

	/* Go elsewhere to handle all nfs files. */
	if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "nfs", 3) == 0)
		return (getflabel_nfs(rvfsp));

	/*
	 * Fast path, for objects in a labeled zone: everything except
	 * for lofs/nfs will be just the label of that zone.
	 */
	if ((rvfsp->vfs_zone != NULL) && (rvfsp->vfs_zone != global_zone)) {
		if ((strcmp(vfssw[rvfsp->vfs_fstype].vsw_name,
		    "lofs") != 0)) {
			zone = rvfsp->vfs_zone;
			zone_hold(zone);
			goto zone_out;		/* return this label */
		}
	}

	/*
	 * Get the vnode path -- it may be missing or weird for some
	 * cases, like devices.  In those cases use the label of the
	 * current zone.
	 */
	err = vnodetopath(rootdir, rvp, vpath, sizeof (vpath), kcred);
	if ((err != 0) || (*vpath != '/')) {
		zone = curproc->p_zone;
		zone_hold(zone);
		goto zone_out;
	}

	/*
	 * For zfs filesystem, return the explicit label property if a
	 * meaningful one exists.
	 */
	if (strncmp(vfssw[rvfsp->vfs_fstype].vsw_name, "zfs", 3) == 0) {
		ts_label_t *tsl;

		tsl = getflabel_zfs(rvfsp);

		/* if label found, return it, otherwise continue... */
		if (tsl != NULL)
			return (tsl);
	}

	/*
	 * If a mountpoint exists, hold the vfs while we reference it.
	 * Otherwise if mountpoint is NULL it should not be held (e.g.,
	 * a hold/release on spec_vfs would result in an attempted free
	 * and panic.)
	 */
	if (vfsp->vfs_mntpt != NULL) {
		VFS_HOLD(vfsp);
		vfs_is_held = B_TRUE;
	}

	zone = zone_find_by_any_path(vpath, B_FALSE);

	/*
	 * If the vnode source zone is properly set to a non-global zone, or
	 * any zone if the mount is R/W, then use the label of that zone.
	 */
	if ((zone != global_zone) || ((vfsp->vfs_flag & VFS_RDONLY) != 0))
		goto zone_out;		/* return this label */

	/*
	 * Otherwise, if we're not in the global zone, use the label of
	 * our zone.
	 */
	if ((zone = curproc->p_zone) != global_zone) {
		zone_hold(zone);
		goto zone_out;		/* return this label */
	}

	/*
	 * We're in the global zone and the mount is R/W ... so the file
	 * may actually be in the global zone -- or in the root of any zone.
	 * Always build our own path for the file, to be sure it's simplified
	 * (i.e., no ".", "..", "//", and so on).
	 */

	zone_rele(zone);
	zone = zone_find_by_any_path(vpath, B_FALSE);

zone_out:
	if ((curproc->p_zone == global_zone) && (zone == global_zone)) {
		vfs_t		*nvfs;
		boolean_t	exported = B_FALSE;
		refstr_t	*mntpt_ref;
		char		*mntpt;

		/*
		 * File is in the global zone - check whether it's admin_high.
		 * If it's in a filesys that was exported from the global zone,
		 * it's admin_low by definition.  Otherwise, if it's in a
		 * filesys that's NOT exported to any zone, it's admin_high.
		 *
		 * And for these files if there wasn't a valid mount resource,
		 * the file must be admin_high (not exported, probably a global
		 * zone device).
		 */
		if (!vfs_is_held)
			goto out_high;

		mntpt_ref = vfs_getmntpoint(vfsp);
		mntpt = (char *)refstr_value(mntpt_ref);

		if ((mntpt != NULL) && (*mntpt == '/')) {
			zone_t	*to_zone;

			to_zone = zone_find_by_any_path(mntpt, B_FALSE);
			zone_rele(to_zone);
			if (to_zone != global_zone) {
				/* force admin_low */
				exported = B_TRUE;
			}
		}
		if (mntpt_ref)
			refstr_rele(mntpt_ref);

		if (!exported) {
			size_t	plen = strlen(vpath);

			vfs_list_read_lock();
			nvfs = vfsp->vfs_next;
			while (nvfs != vfsp) {
				const char	*rstr;
				size_t		rlen = 0;

				/*
				 * Skip checking this vfs if it's not lofs
				 * (the only way to export from the global
				 * zone to a zone).
				 */
				if (strncmp(vfssw[nvfs->vfs_fstype].vsw_name,
				    "lofs", 4) != 0) {
					nvfs = nvfs->vfs_next;
					continue;
				}

				rstr = refstr_value(nvfs->vfs_resource);
				if (rstr != NULL)
					rlen = strlen(rstr);

				/*
				 * Check for a match: does this vfs correspond
				 * to our global zone file path?  I.e., check
				 * if the resource string of this vfs is a
				 * prefix of our path.
				 */
				if ((rlen > 0) && (rlen <= plen) &&
				    (strncmp(rstr, vpath, rlen) == 0) &&
				    (vpath[rlen] == '/' ||
				    vpath[rlen] == '\0')) {
					/* force admin_low */
					exported = B_TRUE;
					break;
				}
				nvfs = nvfs->vfs_next;
			}
			vfs_list_unlock();
		}

		if (!exported)
			goto out_high;
	}

	if (vfs_is_held)
		VFS_RELE(vfsp);

	/*
	 * Now that we have the "home" zone for the file, return the slabel
	 * of that zone.
	 */
	zl = zone->zone_slabel;
	label_hold(zl);
	zone_rele(zone);
	return (zl);

out_high:
	if (vfs_is_held)
		VFS_RELE(vfsp);

	label_hold(l_admin_high);
	zone_rele(zone);
	return (l_admin_high);
}
コード例 #10
0
int
kadmin(int cmd, int fcn, void *mdep, cred_t *credp)
{
	int error = 0;
	char *buf;
	size_t buflen = 0;
	boolean_t invoke_cb = B_FALSE;

	/*
	 * We might be called directly by the kernel's fault-handling code, so
	 * we can't assert that the caller is in the global zone.
	 */

	/*
	 * Make sure that cmd is one of the valid <sys/uadmin.h> command codes
	 * and that we have appropriate privileges for this action.
	 */
	switch (cmd) {
	case A_FTRACE:
	case A_SHUTDOWN:
	case A_REBOOT:
	case A_REMOUNT:
	case A_FREEZE:
	case A_DUMP:
	case A_SDTTEST:
	case A_CONFIG:
		if (secpolicy_sys_config(credp, B_FALSE) != 0)
			return (EPERM);
		break;

	default:
		return (EINVAL);
	}

	/*
	 * Serialize these operations on ualock.  If it is held, the
	 * system should shutdown, reboot, or remount shortly, unless there is
	 * an error.  We need a cv rather than just a mutex because proper
	 * functioning of A_REBOOT relies on being able to interrupt blocked
	 * userland callers.
	 *
	 * We only clear ua_shutdown_thread after A_REMOUNT or A_CONFIG.
	 * Other commands should never return.
	 */
	if (cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_REMOUNT ||
	    cmd == A_CONFIG) {
		mutex_enter(&ualock);
		while (ua_shutdown_thread != NULL) {
			if (cv_wait_sig(&uacond, &ualock) == 0) {
				/*
				 * If we were interrupted, leave, and handle
				 * the signal (or exit, depending on what
				 * happened)
				 */
				mutex_exit(&ualock);
				return (EINTR);
			}
		}
		ua_shutdown_thread = curthread;
		mutex_exit(&ualock);
	}

	switch (cmd) {
	case A_SHUTDOWN:
	{
		proc_t *p = ttoproc(curthread);

		/*
		 * Release (almost) all of our own resources if we are called
		 * from a user context, however if we are calling kadmin() from
		 * a kernel context then we do not release these resources.
		 */
		if (p != &p0) {
			proc_is_exiting(p);
			if ((error = exitlwps(0)) != 0) {
				/*
				 * Another thread in this process also called
				 * exitlwps().
				 */
				mutex_enter(&ualock);
				ua_shutdown_thread = NULL;
				cv_signal(&uacond);
				mutex_exit(&ualock);
				return (error);
			}
			mutex_enter(&p->p_lock);
			p->p_flag |= SNOWAIT;
			sigfillset(&p->p_ignore);
			curthread->t_lwp->lwp_cursig = 0;
			curthread->t_lwp->lwp_extsig = 0;
			if (p->p_exec) {
				vnode_t *exec_vp = p->p_exec;
				p->p_exec = NULLVP;
				mutex_exit(&p->p_lock);
				VN_RELE(exec_vp);
			} else {
				mutex_exit(&p->p_lock);
			}

			pollcleanup();
			closeall(P_FINFO(curproc));
			relvm();

		} else {
			/*
			 * Reset t_cred if not set because much of the
			 * filesystem code depends on CRED() being valid.
			 */
			if (curthread->t_cred == NULL)
				curthread->t_cred = kcred;
		}

		/* indicate shutdown in progress */
		sys_shutdown = 1;

		/*
		 * Communcate that init shouldn't be restarted.
		 */
		zone_shutdown_global();

		killall(ALL_ZONES);
		/*
		 * If we are calling kadmin() from a kernel context then we
		 * do not release these resources.
		 */
		if (ttoproc(curthread) != &p0) {
			VN_RELE(PTOU(curproc)->u_cdir);
			if (PTOU(curproc)->u_rdir)
				VN_RELE(PTOU(curproc)->u_rdir);
			if (PTOU(curproc)->u_cwd)
				refstr_rele(PTOU(curproc)->u_cwd);

			PTOU(curproc)->u_cdir = rootdir;
			PTOU(curproc)->u_rdir = NULL;
			PTOU(curproc)->u_cwd = NULL;
		}

		/*
		 * Allow the reboot/halt/poweroff code a chance to do
		 * anything it needs to whilst we still have filesystems
		 * mounted, like loading any modules necessary for later
		 * performing the actual poweroff.
		 */
		if ((mdep != NULL) && (*(char *)mdep == '/')) {
			buf = i_convert_boot_device_name(mdep, NULL, &buflen);
			mdpreboot(cmd, fcn, buf);
		} else
			mdpreboot(cmd, fcn, mdep);

		/*
		 * Allow fsflush to finish running and then prevent it
		 * from ever running again so that vfs_unmountall() and
		 * vfs_syncall() can acquire the vfs locks they need.
		 */
		sema_p(&fsflush_sema);
		(void) callb_execute_class(CB_CL_UADMIN_PRE_VFS, NULL);

		vfs_unmountall();
		(void) VFS_MOUNTROOT(rootvfs, ROOT_UNMOUNT);
		vfs_syncall();

		dump_ereports();
		dump_messages();

		invoke_cb = B_TRUE;

		/* FALLTHROUGH */
	}

	case A_REBOOT:
		if ((mdep != NULL) && (*(char *)mdep == '/')) {
			buf = i_convert_boot_device_name(mdep, NULL, &buflen);
			mdboot(cmd, fcn, buf, invoke_cb);
		} else
			mdboot(cmd, fcn, mdep, invoke_cb);
		/* no return expected */
		break;

	case A_CONFIG:
		switch (fcn) {
		case AD_UPDATE_BOOT_CONFIG:
#ifndef	__sparc
		{
			extern void fastboot_update_config(const char *);

			fastboot_update_config(mdep);
		}
#endif

			break;
		}
		/* Let other threads enter the shutdown path now */
		mutex_enter(&ualock);
		ua_shutdown_thread = NULL;
		cv_signal(&uacond);
		mutex_exit(&ualock);
		break;

	case A_REMOUNT:
		(void) VFS_MOUNTROOT(rootvfs, ROOT_REMOUNT);
		/* Let other threads enter the shutdown path now */
		mutex_enter(&ualock);
		ua_shutdown_thread = NULL;
		cv_signal(&uacond);
		mutex_exit(&ualock);
		break;

	case A_FREEZE:
	{
		/*
		 * This is the entrypoint for all suspend/resume actions.
		 */
		extern int cpr(int, void *);

		if (modload("misc", "cpr") == -1)
			return (ENOTSUP);
		/* Let the CPR module decide what to do with mdep */
		error = cpr(fcn, mdep);
		break;
	}

	case A_FTRACE:
	{
		switch (fcn) {
		case AD_FTRACE_START:
			(void) FTRACE_START();
			break;
		case AD_FTRACE_STOP:
			(void) FTRACE_STOP();
			break;
		default:
			error = EINVAL;
		}
		break;
	}

	case A_DUMP:
	{
		if (fcn == AD_NOSYNC) {
			in_sync = 1;
			break;
		}

		panic_bootfcn = fcn;
		panic_forced = 1;

		if ((mdep != NULL) && (*(char *)mdep == '/')) {
			panic_bootstr = i_convert_boot_device_name(mdep,
			    NULL, &buflen);
		} else
			panic_bootstr = mdep;

#ifndef	__sparc
		extern void fastboot_update_and_load(int, char *);

		fastboot_update_and_load(fcn, mdep);
#endif

		panic("forced crash dump initiated at user request");
		/*NOTREACHED*/
	}

	case A_SDTTEST:
	{
		DTRACE_PROBE7(test, int, 1, int, 2, int, 3, int, 4, int, 5,
		    int, 6, int, 7);
		break;
	}

	default:
		error = EINVAL;
	}

	return (error);
}
コード例 #11
0
ファイル: ufs_filio.c プロジェクト: bahamas10/openzfs
/* ARGSUSED */
int
ufs_fioffs(
	struct vnode	*vp,
	char 		*vap,		/* must be NULL - reserved */
	struct cred	*cr)		/* credentials from ufs_ioctl */
{
	int error;
	struct ufsvfs	*ufsvfsp;
	struct ulockfs	*ulp;

	/* file system has been forcibly unmounted */
	ufsvfsp = VTOI(vp)->i_ufsvfs;
	if (ufsvfsp == NULL)
		return (EIO);

	ulp = &ufsvfsp->vfs_ulockfs;

	/*
	 * suspend the delete thread
	 *	this must be done outside the lockfs locking protocol
	 */
	vfs_lock_wait(vp->v_vfsp);
	ufs_thread_suspend(&ufsvfsp->vfs_delete);

	/* hold the mutex to prevent race with a lockfs request */
	mutex_enter(&ulp->ul_lock);
	atomic_inc_ulong(&ufs_quiesce_pend);

	if (ULOCKFS_IS_HLOCK(ulp)) {
		error = EIO;
		goto out;
	}
	if (ULOCKFS_IS_ELOCK(ulp)) {
		error = EBUSY;
		goto out;
	}
	/* wait for outstanding accesses to finish */
	if (error = ufs_quiesce(ulp))
		goto out;

	/*
	 * If logging, and the logmap was marked as not rollable,
	 * make it rollable now, and start the trans_roll thread and
	 * the reclaim thread.  The log at this point is safe to write to.
	 */
	if (ufsvfsp->vfs_log) {
		ml_unit_t	*ul = ufsvfsp->vfs_log;
		struct fs	*fsp = ufsvfsp->vfs_fs;
		int		err;

		if (ul->un_flags & LDL_NOROLL) {
			ul->un_flags &= ~LDL_NOROLL;
			logmap_start_roll(ul);
			if (!fsp->fs_ronly && (fsp->fs_reclaim &
			    (FS_RECLAIM|FS_RECLAIMING))) {
				fsp->fs_reclaim &= ~FS_RECLAIM;
				fsp->fs_reclaim |= FS_RECLAIMING;
				ufs_thread_start(&ufsvfsp->vfs_reclaim,
				    ufs_thread_reclaim, vp->v_vfsp);
				if (!fsp->fs_ronly) {
					TRANS_SBWRITE(ufsvfsp,
					    TOP_SBUPDATE_UPDATE);
					if (err =
					    geterror(ufsvfsp->vfs_bufp)) {
						refstr_t	*mntpt;
						mntpt = vfs_getmntpoint(
						    vp->v_vfsp);
						cmn_err(CE_NOTE,
						    "Filesystem Flush "
						    "Failed to update "
						    "Reclaim Status for "
						    " %s, Write failed to "
						    "update superblock, "
						    "error %d",
						    refstr_value(mntpt),
						    err);
						refstr_rele(mntpt);
					}
				}
			}
		}
	}

	/* synchronously flush dirty data and metadata */
	error = ufs_flush(vp->v_vfsp);

out:
	atomic_dec_ulong(&ufs_quiesce_pend);
	cv_broadcast(&ulp->ul_cv);
	mutex_exit(&ulp->ul_lock);
	vfs_unlock(vp->v_vfsp);

	/*
	 * allow the delete thread to continue
	 */
	ufs_thread_continue(&ufsvfsp->vfs_delete);
	return (error);
}
コード例 #12
0
static int
chdirec(vnode_t *vp, int ischroot, int do_traverse)
{
	int error;
	vnode_t *oldvp;
	proc_t *pp = curproc;
	vnode_t **vpp;
	refstr_t *cwd;
	int newcwd = 1;

	if (vp->v_type != VDIR) {
		error = ENOTDIR;
		goto bad;
	}
	if (error = VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL))
		goto bad;

	/*
	 * The VOP_ACCESS() may have covered 'vp' with a new filesystem,
	 * if 'vp' is an autoFS vnode. Traverse the mountpoint so
	 * that we don't end up with a covered current directory.
	 */
	if (vn_mountedvfs(vp) != NULL && do_traverse) {
		if (error = traverse(&vp))
			goto bad;
	}

	/*
	 * Special chroot semantics: chroot is allowed if privileged
	 * or if the target is really a loopback mount of the root (or
	 * root of the zone) as determined by comparing dev and inode
	 * numbers
	 */
	if (ischroot) {
		struct vattr tattr;
		struct vattr rattr;
		vnode_t *zonevp = curproc->p_zone->zone_rootvp;

		tattr.va_mask = AT_FSID|AT_NODEID;
		if (error = VOP_GETATTR(vp, &tattr, 0, CRED(), NULL))
			goto bad;

		rattr.va_mask = AT_FSID|AT_NODEID;
		if (error = VOP_GETATTR(zonevp, &rattr, 0, CRED(), NULL))
			goto bad;

		if ((tattr.va_fsid != rattr.va_fsid ||
		    tattr.va_nodeid != rattr.va_nodeid) &&
		    (error = secpolicy_chroot(CRED())) != 0)
			goto bad;

		vpp = &PTOU(pp)->u_rdir;
	} else {
		vpp = &PTOU(pp)->u_cdir;
	}

	if (audit_active)	/* update abs cwd/root path see c2audit.c */
		audit_chdirec(vp, vpp);

	mutex_enter(&pp->p_lock);
	/*
	 * This bit of logic prevents us from overwriting u_cwd if we are
	 * changing to the same directory.  We set the cwd to NULL so that we
	 * don't try to do the lookup on the next call to getcwd().
	 */
	if (!ischroot && *vpp != NULL && vp != NULL && VN_CMP(*vpp, vp))
		newcwd = 0;

	oldvp = *vpp;
	*vpp = vp;
	if ((cwd = PTOU(pp)->u_cwd) != NULL && newcwd)
		PTOU(pp)->u_cwd = NULL;
	mutex_exit(&pp->p_lock);

	if (cwd && newcwd)
		refstr_rele(cwd);
	if (oldvp)
		VN_RELE(oldvp);
	return (0);

bad:
	VN_RELE(vp);
	return (error);
}
コード例 #13
0
ファイル: exit.c プロジェクト: apprisi/illumos-gate
/*
 * Return value:
 *   1 - exitlwps() failed, call (or continue) lwp_exit()
 *   0 - restarting init.  Return through system call path
 */
int
proc_exit(int why, int what)
{
	kthread_t *t = curthread;
	klwp_t *lwp = ttolwp(t);
	proc_t *p = ttoproc(t);
	zone_t *z = p->p_zone;
	timeout_id_t tmp_id;
	int rv;
	proc_t *q;
	task_t *tk;
	vnode_t *exec_vp, *execdir_vp, *cdir, *rdir;
	sigqueue_t *sqp;
	lwpdir_t *lwpdir;
	uint_t lwpdir_sz;
	tidhash_t *tidhash;
	uint_t tidhash_sz;
	ret_tidhash_t *ret_tidhash;
	refstr_t *cwd;
	hrtime_t hrutime, hrstime;
	int evaporate;

	/*
	 * Stop and discard the process's lwps except for the current one,
	 * unless some other lwp beat us to it.  If exitlwps() fails then
	 * return and the calling lwp will call (or continue in) lwp_exit().
	 */
	proc_is_exiting(p);
	if (exitlwps(0) != 0)
		return (1);

	mutex_enter(&p->p_lock);
	if (p->p_ttime > 0) {
		/*
		 * Account any remaining ticks charged to this process
		 * on its way out.
		 */
		(void) task_cpu_time_incr(p->p_task, p->p_ttime);
		p->p_ttime = 0;
	}
	mutex_exit(&p->p_lock);

	DTRACE_PROC(lwp__exit);
	DTRACE_PROC1(exit, int, why);

	/*
	 * Will perform any brand specific proc exit processing, since this
	 * is always the last lwp, will also perform lwp_exit and free brand
	 * data
	 */
	if (PROC_IS_BRANDED(p)) {
		lwp_detach_brand_hdlrs(lwp);
		brand_clearbrand(p, B_FALSE);
	}

	/*
	 * Don't let init exit unless zone_start_init() failed its exec, or
	 * we are shutting down the zone or the machine.
	 *
	 * Since we are single threaded, we don't need to lock the
	 * following accesses to zone_proc_initpid.
	 */
	if (p->p_pid == z->zone_proc_initpid) {
		if (z->zone_boot_err == 0 &&
		    zone_status_get(z) < ZONE_IS_SHUTTING_DOWN &&
		    zone_status_get(global_zone) < ZONE_IS_SHUTTING_DOWN &&
		    z->zone_restart_init == B_TRUE &&
		    restart_init(what, why) == 0)
			return (0);
		/*
		 * Since we didn't or couldn't restart init, we clear
		 * the zone's init state and proceed with exit
		 * processing.
		 */
		z->zone_proc_initpid = -1;
	}

	lwp_pcb_exit();

	/*
	 * Allocate a sigqueue now, before we grab locks.
	 * It will be given to sigcld(), below.
	 * Special case:  If we will be making the process disappear
	 * without a trace because it is either:
	 *	* an exiting SSYS process, or
	 *	* a posix_spawn() vfork child who requests it,
	 * we don't bother to allocate a useless sigqueue.
	 */
	evaporate = (p->p_flag & SSYS) || ((p->p_flag & SVFORK) &&
	    why == CLD_EXITED && what == _EVAPORATE);
	if (!evaporate)
		sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);

	/*
	 * revoke any doors created by the process.
	 */
	if (p->p_door_list)
		door_exit();

	/*
	 * Release schedctl data structures.
	 */
	if (p->p_pagep)
		schedctl_proc_cleanup();

	/*
	 * make sure all pending kaio has completed.
	 */
	if (p->p_aio)
		aio_cleanup_exit();

	/*
	 * discard the lwpchan cache.
	 */
	if (p->p_lcp != NULL)
		lwpchan_destroy_cache(0);

	/*
	 * Clean up any DTrace helper actions or probes for the process.
	 */
	if (p->p_dtrace_helpers != NULL) {
		ASSERT(dtrace_helpers_cleanup != NULL);
		(*dtrace_helpers_cleanup)();
	}

	/* untimeout the realtime timers */
	if (p->p_itimer != NULL)
		timer_exit();

	if ((tmp_id = p->p_alarmid) != 0) {
		p->p_alarmid = 0;
		(void) untimeout(tmp_id);
	}

	/*
	 * Remove any fpollinfo_t's for this (last) thread from our file
	 * descriptors so closeall() can ASSERT() that they're all gone.
	 */
	pollcleanup();

	if (p->p_rprof_cyclic != CYCLIC_NONE) {
		mutex_enter(&cpu_lock);
		cyclic_remove(p->p_rprof_cyclic);
		mutex_exit(&cpu_lock);
	}

	mutex_enter(&p->p_lock);

	/*
	 * Clean up any DTrace probes associated with this process.
	 */
	if (p->p_dtrace_probes) {
		ASSERT(dtrace_fasttrap_exit_ptr != NULL);
		dtrace_fasttrap_exit_ptr(p);
	}

	while ((tmp_id = p->p_itimerid) != 0) {
		p->p_itimerid = 0;
		mutex_exit(&p->p_lock);
		(void) untimeout(tmp_id);
		mutex_enter(&p->p_lock);
	}

	lwp_cleanup();

	/*
	 * We are about to exit; prevent our resource associations from
	 * being changed.
	 */
	pool_barrier_enter();

	/*
	 * Block the process against /proc now that we have really
	 * acquired p->p_lock (to manipulate p_tlist at least).
	 */
	prbarrier(p);

	sigfillset(&p->p_ignore);
	sigemptyset(&p->p_siginfo);
	sigemptyset(&p->p_sig);
	sigemptyset(&p->p_extsig);
	sigemptyset(&t->t_sig);
	sigemptyset(&t->t_extsig);
	sigemptyset(&p->p_sigmask);
	sigdelq(p, t, 0);
	lwp->lwp_cursig = 0;
	lwp->lwp_extsig = 0;
	p->p_flag &= ~(SKILLED | SEXTKILLED);
	if (lwp->lwp_curinfo) {
		siginfofree(lwp->lwp_curinfo);
		lwp->lwp_curinfo = NULL;
	}

	t->t_proc_flag |= TP_LWPEXIT;
	ASSERT(p->p_lwpcnt == 1 && p->p_zombcnt == 0);
	prlwpexit(t);		/* notify /proc */
	lwp_hash_out(p, t->t_tid);
	prexit(p);

	p->p_lwpcnt = 0;
	p->p_tlist = NULL;
	sigqfree(p);
	term_mstate(t);
	p->p_mterm = gethrtime();

	exec_vp = p->p_exec;
	execdir_vp = p->p_execdir;
	p->p_exec = NULLVP;
	p->p_execdir = NULLVP;
	mutex_exit(&p->p_lock);

	pr_free_watched_pages(p);

	closeall(P_FINFO(p));

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

#if defined(__sparc)
	if (p->p_utraps != NULL)
		utrap_free(p);
#endif
	if (p->p_semacct)			/* IPC semaphore exit */
		semexit(p);
	rv = wstat(why, what);

	acct(rv & 0xff);
	exacct_commit_proc(p, rv);

	/*
	 * Release any resources associated with C2 auditing
	 */
	if (AU_AUDITING()) {
		/*
		 * audit exit system call
		 */
		audit_exit(why, what);
	}

	/*
	 * Free address space.
	 */
	relvm();

	if (exec_vp) {
		/*
		 * Close this executable which has been opened when the process
		 * was created by getproc().
		 */
		(void) VOP_CLOSE(exec_vp, FREAD, 1, (offset_t)0, CRED(), NULL);
		VN_RELE(exec_vp);
	}
	if (execdir_vp)
		VN_RELE(execdir_vp);

	/*
	 * Release held contracts.
	 */
	contract_exit(p);

	/*
	 * Depart our encapsulating process contract.
	 */
	if ((p->p_flag & SSYS) == 0) {
		ASSERT(p->p_ct_process);
		contract_process_exit(p->p_ct_process, p, rv);
	}

	/*
	 * Remove pool association, and block if requested by pool_do_bind.
	 */
	mutex_enter(&p->p_lock);
	ASSERT(p->p_pool->pool_ref > 0);
	atomic_add_32(&p->p_pool->pool_ref, -1);
	p->p_pool = pool_default;
	/*
	 * Now that our address space has been freed and all other threads
	 * in this process have exited, set the PEXITED pool flag.  This
	 * tells the pools subsystems to ignore this process if it was
	 * requested to rebind this process to a new pool.
	 */
	p->p_poolflag |= PEXITED;
	pool_barrier_exit();
	mutex_exit(&p->p_lock);

	mutex_enter(&pidlock);

	/*
	 * Delete this process from the newstate list of its parent. We
	 * will put it in the right place in the sigcld in the end.
	 */
	delete_ns(p->p_parent, p);

	/*
	 * Reassign the orphans to the next of kin.
	 * Don't rearrange init's orphanage.
	 */
	if ((q = p->p_orphan) != NULL && p != proc_init) {

		proc_t *nokp = p->p_nextofkin;

		for (;;) {
			q->p_nextofkin = nokp;
			if (q->p_nextorph == NULL)
				break;
			q = q->p_nextorph;
		}
		q->p_nextorph = nokp->p_orphan;
		nokp->p_orphan = p->p_orphan;
		p->p_orphan = NULL;
	}

	/*
	 * Reassign the children to init.
	 * Don't try to assign init's children to init.
	 */
	if ((q = p->p_child) != NULL && p != proc_init) {
		struct proc	*np;
		struct proc	*initp = proc_init;
		boolean_t	setzonetop = B_FALSE;

		if (!INGLOBALZONE(curproc))
			setzonetop = B_TRUE;

		pgdetach(p);

		do {
			np = q->p_sibling;
			/*
			 * Delete it from its current parent new state
			 * list and add it to init new state list
			 */
			delete_ns(q->p_parent, q);

			q->p_ppid = 1;
			q->p_pidflag &= ~(CLDNOSIGCHLD | CLDWAITPID);
			if (setzonetop) {
				mutex_enter(&q->p_lock);
				q->p_flag |= SZONETOP;
				mutex_exit(&q->p_lock);
			}
			q->p_parent = initp;

			/*
			 * Since q will be the first child,
			 * it will not have a previous sibling.
			 */
			q->p_psibling = NULL;
			if (initp->p_child) {
				initp->p_child->p_psibling = q;
			}
			q->p_sibling = initp->p_child;
			initp->p_child = q;
			if (q->p_proc_flag & P_PR_PTRACE) {
				mutex_enter(&q->p_lock);
				sigtoproc(q, NULL, SIGKILL);
				mutex_exit(&q->p_lock);
			}
			/*
			 * sigcld() will add the child to parents
			 * newstate list.
			 */
			if (q->p_stat == SZOMB)
				sigcld(q, NULL);
		} while ((q = np) != NULL);

		p->p_child = NULL;
		ASSERT(p->p_child_ns == NULL);
	}

	TRACE_1(TR_FAC_PROC, TR_PROC_EXIT, "proc_exit: %p", p);

	mutex_enter(&p->p_lock);
	CL_EXIT(curthread); /* tell the scheduler that curthread is exiting */

	/*
	 * Have our task accummulate our resource usage data before they
	 * become contaminated by p_cacct etc., and before we renounce
	 * membership of the task.
	 *
	 * We do this regardless of whether or not task accounting is active.
	 * This is to avoid having nonsense data reported for this task if
	 * task accounting is subsequently enabled. The overhead is minimal;
	 * by this point, this process has accounted for the usage of all its
	 * LWPs. We nonetheless do the work here, and under the protection of
	 * pidlock, so that the movement of the process's usage to the task
	 * happens at the same time as the removal of the process from the
	 * task, from the point of view of exacct_snapshot_task_usage().
	 */
	exacct_update_task_mstate(p);

	hrutime = mstate_aggr_state(p, LMS_USER);
	hrstime = mstate_aggr_state(p, LMS_SYSTEM);
	p->p_utime = (clock_t)NSEC_TO_TICK(hrutime) + p->p_cutime;
	p->p_stime = (clock_t)NSEC_TO_TICK(hrstime) + p->p_cstime;

	p->p_acct[LMS_USER]	+= p->p_cacct[LMS_USER];
	p->p_acct[LMS_SYSTEM]	+= p->p_cacct[LMS_SYSTEM];
	p->p_acct[LMS_TRAP]	+= p->p_cacct[LMS_TRAP];
	p->p_acct[LMS_TFAULT]	+= p->p_cacct[LMS_TFAULT];
	p->p_acct[LMS_DFAULT]	+= p->p_cacct[LMS_DFAULT];
	p->p_acct[LMS_KFAULT]	+= p->p_cacct[LMS_KFAULT];
	p->p_acct[LMS_USER_LOCK] += p->p_cacct[LMS_USER_LOCK];
	p->p_acct[LMS_SLEEP]	+= p->p_cacct[LMS_SLEEP];
	p->p_acct[LMS_WAIT_CPU]	+= p->p_cacct[LMS_WAIT_CPU];
	p->p_acct[LMS_STOPPED]	+= p->p_cacct[LMS_STOPPED];

	p->p_ru.minflt	+= p->p_cru.minflt;
	p->p_ru.majflt	+= p->p_cru.majflt;
	p->p_ru.nswap	+= p->p_cru.nswap;
	p->p_ru.inblock	+= p->p_cru.inblock;
	p->p_ru.oublock	+= p->p_cru.oublock;
	p->p_ru.msgsnd	+= p->p_cru.msgsnd;
	p->p_ru.msgrcv	+= p->p_cru.msgrcv;
	p->p_ru.nsignals += p->p_cru.nsignals;
	p->p_ru.nvcsw	+= p->p_cru.nvcsw;
	p->p_ru.nivcsw	+= p->p_cru.nivcsw;
	p->p_ru.sysc	+= p->p_cru.sysc;
	p->p_ru.ioch	+= p->p_cru.ioch;

	p->p_stat = SZOMB;
	p->p_proc_flag &= ~P_PR_PTRACE;
	p->p_wdata = what;
	p->p_wcode = (char)why;

	cdir = PTOU(p)->u_cdir;
	rdir = PTOU(p)->u_rdir;
	cwd = PTOU(p)->u_cwd;

	ASSERT(cdir != NULL || p->p_parent == &p0);

	/*
	 * Release resource controls, as they are no longer enforceable.
	 */
	rctl_set_free(p->p_rctls);

	/*
	 * Decrement tk_nlwps counter for our task.max-lwps resource control.
	 * An extended accounting record, if that facility is active, is
	 * scheduled to be written.  We cannot give up task and project
	 * membership at this point because that would allow zombies to escape
	 * from the max-processes resource controls.  Zombies stay in their
	 * current task and project until the process table slot is released
	 * in freeproc().
	 */
	tk = p->p_task;

	mutex_enter(&p->p_zone->zone_nlwps_lock);
	tk->tk_nlwps--;
	tk->tk_proj->kpj_nlwps--;
	p->p_zone->zone_nlwps--;
	mutex_exit(&p->p_zone->zone_nlwps_lock);

	/*
	 * Clear the lwp directory and the lwpid hash table
	 * now that /proc can't bother us any more.
	 * We free the memory below, after dropping p->p_lock.
	 */
	lwpdir = p->p_lwpdir;
	lwpdir_sz = p->p_lwpdir_sz;
	tidhash = p->p_tidhash;
	tidhash_sz = p->p_tidhash_sz;
	ret_tidhash = p->p_ret_tidhash;
	p->p_lwpdir = NULL;
	p->p_lwpfree = NULL;
	p->p_lwpdir_sz = 0;
	p->p_tidhash = NULL;
	p->p_tidhash_sz = 0;
	p->p_ret_tidhash = NULL;

	/*
	 * If the process has context ops installed, call the exit routine
	 * on behalf of this last remaining thread. Normally exitpctx() is
	 * called during thread_exit() or lwp_exit(), but because this is the
	 * last thread in the process, we must call it here. By the time
	 * thread_exit() is called (below), the association with the relevant
	 * process has been lost.
	 *
	 * We also free the context here.
	 */
	if (p->p_pctx) {
		kpreempt_disable();
		exitpctx(p);
		kpreempt_enable();

		freepctx(p, 0);
	}

	/*
	 * curthread's proc pointer is changed to point to the 'sched'
	 * process for the corresponding zone, except in the case when
	 * the exiting process is in fact a zsched instance, in which
	 * case the proc pointer is set to p0.  We do so, so that the
	 * process still points at the right zone when we call the VN_RELE()
	 * below.
	 *
	 * This is because curthread's original proc pointer can be freed as
	 * soon as the child sends a SIGCLD to its parent.  We use zsched so
	 * that for user processes, even in the final moments of death, the
	 * process is still associated with its zone.
	 */
	if (p != t->t_procp->p_zone->zone_zsched)
		t->t_procp = t->t_procp->p_zone->zone_zsched;
	else
		t->t_procp = &p0;

	mutex_exit(&p->p_lock);
	if (!evaporate) {
		p->p_pidflag &= ~CLDPEND;
		sigcld(p, sqp);
	} else {
		/*
		 * Do what sigcld() would do if the disposition
		 * of the SIGCHLD signal were set to be ignored.
		 */
		cv_broadcast(&p->p_srwchan_cv);
		freeproc(p);
	}
	mutex_exit(&pidlock);

	/*
	 * We don't release u_cdir and u_rdir until SZOMB is set.
	 * This protects us against dofusers().
	 */
	if (cdir)
		VN_RELE(cdir);
	if (rdir)
		VN_RELE(rdir);
	if (cwd)
		refstr_rele(cwd);

	/*
	 * task_rele() may ultimately cause the zone to go away (or
	 * may cause the last user process in a zone to go away, which
	 * signals zsched to go away).  So prior to this call, we must
	 * no longer point at zsched.
	 */
	t->t_procp = &p0;

	kmem_free(lwpdir, lwpdir_sz * sizeof (lwpdir_t));
	kmem_free(tidhash, tidhash_sz * sizeof (tidhash_t));
	while (ret_tidhash != NULL) {
		ret_tidhash_t *next = ret_tidhash->rth_next;
		kmem_free(ret_tidhash->rth_tidhash,
		    ret_tidhash->rth_tidhash_sz * sizeof (tidhash_t));
		kmem_free(ret_tidhash, sizeof (*ret_tidhash));
		ret_tidhash = next;
	}

	thread_exit();
	/* NOTREACHED */
}
コード例 #14
0
ファイル: exit.c プロジェクト: apprisi/illumos-gate
/*
 * 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);
}
コード例 #15
0
ファイル: lookup.c プロジェクト: bahamas10/openzfs
/*
 * Given a directory, return the full, resolved path.  This looks up "..",
 * searches for the given vnode in the parent, appends the component, etc.  It
 * is used to implement vnodetopath() and getcwd() when the cached path fails.
 */
static int
dirtopath(vnode_t *vrootp, vnode_t *vp, char *buf, size_t buflen, int flags,
    cred_t *cr)
{
	pathname_t pn, rpn, emptypn;
	vnode_t *cmpvp, *pvp = NULL;
	vnode_t *startvp = vp;
	int err = 0, vprivs;
	size_t complen;
	char *dbuf;
	dirent64_t *dp;
	char		*bufloc;
	size_t		dlen = DIRENT64_RECLEN(MAXPATHLEN);
	refstr_t	*mntpt;

	/* Operation only allowed on directories */
	ASSERT(vp->v_type == VDIR);

	/* We must have at least enough space for "/" */
	if (buflen < 2)
		return (ENAMETOOLONG);

	/* Start at end of string with terminating null */
	bufloc = &buf[buflen - 1];
	*bufloc = '\0';

	pn_alloc(&pn);
	pn_alloc(&rpn);
	dbuf = kmem_alloc(dlen, KM_SLEEP);
	bzero(&emptypn, sizeof (emptypn));

	/*
	 * Begin with an additional reference on vp.  This will be decremented
	 * during the loop.
	 */
	VN_HOLD(vp);

	for (;;) {
		/*
		 * Return if we've reached the root.  If the buffer is empty,
		 * return '/'.  We explicitly don't use vn_compare(), since it
		 * compares the real vnodes.  A lofs mount of '/' would produce
		 * incorrect results otherwise.
		 */
		if (VN_CMP(vrootp, vp)) {
			if (*bufloc == '\0')
				*--bufloc = '/';
			break;
		}

		/*
		 * If we've reached the VFS root, something has gone wrong.  We
		 * should have reached the root in the above check.  The only
		 * explantation is that 'vp' is not contained withing the given
		 * root, in which case we return EPERM.
		 */
		if (VN_CMP(rootdir, vp)) {
			err = EPERM;
			goto out;
		}

		/*
		 * Shortcut: see if this vnode is a mountpoint.  If so,
		 * grab the path information from the vfs_t.
		 */
		if (vp->v_flag & VROOT) {

			mntpt = vfs_getmntpoint(vp->v_vfsp);
			if ((err = pn_set(&pn, (char *)refstr_value(mntpt)))
			    == 0) {
				refstr_rele(mntpt);
				rpn.pn_path = rpn.pn_buf;

				/*
				 * Ensure the mountpoint still exists.
				 */
				VN_HOLD(vrootp);
				if (vrootp != rootdir)
					VN_HOLD(vrootp);
				if (lookuppnvp(&pn, &rpn, flags, NULL,
				    &cmpvp, vrootp, vrootp, cr) == 0) {

					if (VN_CMP(vp, cmpvp)) {
						VN_RELE(cmpvp);

						complen = strlen(rpn.pn_path);
						bufloc -= complen;
						if (bufloc < buf) {
							err = ERANGE;
							goto out;
						}
						bcopy(rpn.pn_path, bufloc,
						    complen);
						break;
					} else {
						VN_RELE(cmpvp);
					}
				}
			} else {
				refstr_rele(mntpt);
			}
		}

		/*
		 * Shortcut: see if this vnode has correct v_path. If so,
		 * we have the work done.
		 */
		mutex_enter(&vp->v_lock);
		if (vp->v_path != NULL) {

			if ((err = pn_set(&pn, vp->v_path)) == 0) {
				mutex_exit(&vp->v_lock);
				rpn.pn_path = rpn.pn_buf;

				/*
				 * Ensure the v_path pointing to correct vnode
				 */
				VN_HOLD(vrootp);
				if (vrootp != rootdir)
					VN_HOLD(vrootp);
				if (lookuppnvp(&pn, &rpn, flags, NULL,
				    &cmpvp, vrootp, vrootp, cr) == 0) {

					if (VN_CMP(vp, cmpvp)) {
						VN_RELE(cmpvp);

						complen = strlen(rpn.pn_path);
						bufloc -= complen;
						if (bufloc < buf) {
							err = ERANGE;
							goto out;
						}
						bcopy(rpn.pn_path, bufloc,
						    complen);
						break;
					} else {
						VN_RELE(cmpvp);
					}
				}
			} else {
				mutex_exit(&vp->v_lock);
			}
		} else {
			mutex_exit(&vp->v_lock);
		}

		/*
		 * Shortcuts failed, search for this vnode in its parent.  If
		 * this is a mountpoint, then get the vnode underneath.
		 */
		if (vp->v_flag & VROOT)
			vp = vn_under(vp);
		if ((err = VOP_LOOKUP(vp, "..", &pvp, &emptypn, 0, vrootp, cr,
		    NULL, NULL, NULL)) != 0)
			goto out;

		/*
		 * With extended attributes, it's possible for a directory to
		 * have a parent that is a regular file.  Check for that here.
		 */
		if (pvp->v_type != VDIR) {
			err = ENOTDIR;
			goto out;
		}

		/*
		 * If this is true, something strange has happened.  This is
		 * only true if we are the root of a filesystem, which should
		 * have been caught by the check above.
		 */
		if (VN_CMP(pvp, vp)) {
			err = ENOENT;
			goto out;
		}

		/*
		 * Check if we have read and search privilege so, that
		 * we can lookup the path in the directory
		 */
		vprivs = (flags & LOOKUP_CHECKREAD) ? VREAD | VEXEC : VEXEC;
		if ((err = VOP_ACCESS(pvp, vprivs, 0, cr, NULL)) != 0) {
			goto out;
		}

		/*
		 * Try to obtain the path component from dnlc cache
		 * before searching through the directory.
		 */
		if ((cmpvp = dnlc_reverse_lookup(vp, dbuf, dlen)) != NULL) {
			/*
			 * If we got parent vnode as a result,
			 * then the answered path is correct.
			 */
			if (VN_CMP(cmpvp, pvp)) {
				VN_RELE(cmpvp);
				complen = strlen(dbuf);
				bufloc -= complen;
				if (bufloc <= buf) {
					err = ENAMETOOLONG;
					goto out;
				}
				bcopy(dbuf, bufloc, complen);

				/* Prepend a slash to the current path */
				*--bufloc = '/';

				/* And continue with the next component */
				VN_RELE(vp);
				vp = pvp;
				pvp = NULL;
				continue;
			} else {
				VN_RELE(cmpvp);
			}
		}

		/*
		 * Search the parent directory for the entry corresponding to
		 * this vnode.
		 */
		if ((err = dirfindvp(vrootp, pvp, vp, cr, dbuf, dlen, &dp))
		    != 0)
			goto out;
		complen = strlen(dp->d_name);
		bufloc -= complen;
		if (bufloc <= buf) {
			err = ENAMETOOLONG;
			goto out;
		}
		bcopy(dp->d_name, bufloc, complen);

		/* Prepend a slash to the current path.  */
		*--bufloc = '/';

		/* And continue with the next component */
		VN_RELE(vp);
		vp = pvp;
		pvp = NULL;
	}

	/*
	 * Place the path at the beginning of the buffer.
	 */
	if (bufloc != buf)
		ovbcopy(bufloc, buf, buflen - (bufloc - buf));

out:
	/*
	 * If the error was ESTALE and the current directory to look in
	 * was the root for this lookup, the root for a mounted file
	 * system, or the starting directory for lookups, then
	 * return ENOENT instead of ESTALE.  In this case, no recovery
	 * is possible by the higher level.  If ESTALE was returned for
	 * some intermediate directory along the path, then recovery
	 * is potentially possible and retrying from the higher level
	 * will either correct the situation by purging stale cache
	 * entries or eventually get back to the point where no recovery
	 * is possible.
	 */
	if (err == ESTALE &&
	    (VN_CMP(vp, vrootp) || (vp->v_flag & VROOT) || vp == startvp))
		err = ENOENT;

	kmem_free(dbuf, dlen);
	VN_RELE(vp);
	if (pvp)
		VN_RELE(pvp);
	pn_free(&pn);
	pn_free(&rpn);

	return (err);
}
コード例 #16
0
ファイル: lookup.c プロジェクト: bahamas10/openzfs
int
dogetcwd(char *buf, size_t buflen)
{
	int ret;
	vnode_t *vp;
	vnode_t *compvp;
	refstr_t *cwd, *oldcwd;
	const char *value;
	pathname_t rpnp, pnp;
	proc_t *p = curproc;

	/*
	 * Check to see if there is a cached version of the cwd.  If so, lookup
	 * the cached value and make sure it is the same vnode.
	 */
	mutex_enter(&p->p_lock);
	if ((cwd = PTOU(p)->u_cwd) != NULL)
		refstr_hold(cwd);
	vp = PTOU(p)->u_cdir;
	VN_HOLD(vp);
	mutex_exit(&p->p_lock);

	/*
	 * Make sure we have permission to access the current directory.
	 */
	if ((ret = VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL)) != 0) {
		if (cwd != NULL)
			refstr_rele(cwd);
		VN_RELE(vp);
		return (ret);
	}

	if (cwd) {
		value = refstr_value(cwd);
		if ((ret = pn_get((char *)value, UIO_SYSSPACE, &pnp)) != 0) {
			refstr_rele(cwd);
			VN_RELE(vp);
			return (ret);
		}

		pn_alloc(&rpnp);

		if (lookuppn(&pnp, &rpnp, NO_FOLLOW, NULL, &compvp) == 0) {

			if (VN_CMP(vp, compvp) &&
			    strcmp(value, rpnp.pn_path) == 0) {
				VN_RELE(compvp);
				VN_RELE(vp);
				pn_free(&pnp);
				pn_free(&rpnp);
				if (strlen(value) + 1 > buflen) {
					refstr_rele(cwd);
					return (ENAMETOOLONG);
				}
				bcopy(value, buf, strlen(value) + 1);
				refstr_rele(cwd);
				return (0);
			}

			VN_RELE(compvp);
		}

		pn_free(&rpnp);
		pn_free(&pnp);

		refstr_rele(cwd);
	}

	ret = vnodetopath_common(NULL, vp, buf, buflen, CRED(),
	    LOOKUP_CHECKREAD);

	VN_RELE(vp);

	/*
	 * Store the new cwd and replace the existing cached copy.
	 */
	if (ret == 0)
		cwd = refstr_alloc(buf);
	else
		cwd = NULL;

	mutex_enter(&p->p_lock);
	oldcwd = PTOU(p)->u_cwd;
	PTOU(p)->u_cwd = cwd;
	mutex_exit(&p->p_lock);

	if (oldcwd)
		refstr_rele(oldcwd);

	return (ret);
}
コード例 #17
0
int
corectl(int subcode, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
{
	int error = 0;
	proc_t *p;
	refstr_t *rp;
	size_t size;
	char *path;
	core_content_t content = CC_CONTENT_INVALID;
	struct core_globals *cg;
	zone_t *zone = curproc->p_zone;

	cg = zone_getspecific(core_zone_key, zone);
	ASSERT(cg != NULL);

	switch (subcode) {
	case CC_SET_OPTIONS:
		if ((error = secpolicy_coreadm(CRED())) == 0) {
			if (arg1 & ~CC_OPTIONS)
				error = EINVAL;
			else
				cg->core_options = (uint32_t)arg1;
		}
		break;

	case CC_GET_OPTIONS:
		return (cg->core_options);

	case CC_GET_GLOBAL_PATH:
	case CC_GET_DEFAULT_PATH:
	case CC_GET_PROCESS_PATH:
		if (subcode == CC_GET_GLOBAL_PATH) {
			mutex_enter(&cg->core_lock);
			if ((rp = cg->core_file) != NULL)
				refstr_hold(rp);
			mutex_exit(&cg->core_lock);
		} else if (subcode == CC_GET_DEFAULT_PATH) {
			rp = corectl_path_value(cg->core_default_path);
		} else {
			rp = NULL;
			mutex_enter(&pidlock);
			if ((p = prfind((pid_t)arg3)) == NULL ||
			    p->p_stat == SIDL) {
				mutex_exit(&pidlock);
				error = ESRCH;
			} else {
				mutex_enter(&p->p_lock);
				mutex_exit(&pidlock);
				mutex_enter(&p->p_crlock);
				if (!hasprocperm(p->p_cred, CRED()))
					error = EPERM;
				else if (p->p_corefile != NULL)
					rp = corectl_path_value(p->p_corefile);
				mutex_exit(&p->p_crlock);
				mutex_exit(&p->p_lock);
			}
		}
		if (rp == NULL) {
			if (error == 0 && suword8((void *)arg1, 0))
				error = EFAULT;
		} else {
			error = copyoutstr(refstr_value(rp), (char *)arg1,
			    (size_t)arg2, NULL);
			refstr_rele(rp);
		}
		break;

	case CC_SET_GLOBAL_PATH:
	case CC_SET_DEFAULT_PATH:
		if ((error = secpolicy_coreadm(CRED())) != 0)
			break;

		/* FALLTHROUGH */
	case CC_SET_PROCESS_PATH:
		if ((size = MIN((size_t)arg2, MAXPATHLEN)) == 0) {
			error = EINVAL;
			break;
		}
		path = kmem_alloc(size, KM_SLEEP);
		error = copyinstr((char *)arg1, path, size, NULL);
		if (error == 0) {
			if (subcode == CC_SET_PROCESS_PATH) {
				error = set_proc_info((pid_t)arg3, path, 0);
			} else if (subcode == CC_SET_DEFAULT_PATH) {
				corectl_path_set(cg->core_default_path, path);
			} else if (*path != '\0' && *path != '/') {
				error = EINVAL;
			} else {
				refstr_t *nrp = refstr_alloc(path);

				mutex_enter(&cg->core_lock);
				rp = cg->core_file;
				if (*path == '\0')
					cg->core_file = NULL;
				else
					refstr_hold(cg->core_file = nrp);
				mutex_exit(&cg->core_lock);

				if (rp != NULL)
					refstr_rele(rp);

				refstr_rele(nrp);
			}
		}
		kmem_free(path, size);
		break;

	case CC_SET_GLOBAL_CONTENT:
	case CC_SET_DEFAULT_CONTENT:
		if ((error = secpolicy_coreadm(CRED())) != 0)
			break;

		/* FALLTHROUGH */
	case CC_SET_PROCESS_CONTENT:
		error = copyin((void *)arg1, &content, sizeof (content));
		if (error != 0)
			break;

		/*
		 * If any unknown bits are set, don't let this charade
		 * continue.
		 */
		if (content & ~CC_CONTENT_ALL) {
			error = EINVAL;
			break;
		}

		if (subcode == CC_SET_PROCESS_CONTENT) {
			error = set_proc_info((pid_t)arg2, NULL, content);
		} else if (subcode == CC_SET_DEFAULT_CONTENT) {
			corectl_content_set(cg->core_default_content, content);
		} else {
			mutex_enter(&cg->core_lock);
			cg->core_content = content;
			mutex_exit(&cg->core_lock);
		}

		break;

	case CC_GET_GLOBAL_CONTENT:
		content = cg->core_content;
		error = copyout(&content, (void *)arg1, sizeof (content));
		break;

	case CC_GET_DEFAULT_CONTENT:
		content = corectl_content_value(cg->core_default_content);
		error = copyout(&content, (void *)arg1, sizeof (content));
		break;

	case CC_GET_PROCESS_CONTENT:
		mutex_enter(&pidlock);
		if ((p = prfind((pid_t)arg2)) == NULL || p->p_stat == SIDL) {
			mutex_exit(&pidlock);
			error = ESRCH;
			break;
		}

		mutex_enter(&p->p_lock);
		mutex_exit(&pidlock);
		mutex_enter(&p->p_crlock);
		if (!hasprocperm(p->p_cred, CRED()))
			error = EPERM;
		else if (p->p_content == NULL)
			content = CC_CONTENT_NONE;
		else
			content = corectl_content_value(p->p_content);
		mutex_exit(&p->p_crlock);
		mutex_exit(&p->p_lock);

		if (error == 0)
			error = copyout(&content, (void *)arg1,
			    sizeof (content));
		break;

	default:
		error = EINVAL;
		break;
	}

	if (error)
		return (set_errno(error));
	return (0);
}