xref: /onnv-gate/usr/src/uts/common/os/inst_sync.c (revision 12116:ea985fb42600)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12116SVikram.Hegde@Sun.COM  * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate /*
260Sstevel@tonic-gate  * Syscall to write out the instance number data structures to
270Sstevel@tonic-gate  * stable storage.
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/errno.h>
320Sstevel@tonic-gate #include <sys/t_lock.h>
330Sstevel@tonic-gate #include <sys/modctl.h>
340Sstevel@tonic-gate #include <sys/systm.h>
350Sstevel@tonic-gate #include <sys/syscall.h>
360Sstevel@tonic-gate #include <sys/vfs.h>
370Sstevel@tonic-gate #include <sys/vnode.h>
380Sstevel@tonic-gate #include <sys/cred.h>
390Sstevel@tonic-gate #include <sys/file.h>
400Sstevel@tonic-gate #include <sys/cmn_err.h>
410Sstevel@tonic-gate #include <sys/kmem.h>
420Sstevel@tonic-gate #include <sys/cladm.h>
430Sstevel@tonic-gate #include <sys/sunddi.h>
440Sstevel@tonic-gate #include <sys/dditypes.h>
450Sstevel@tonic-gate #include <sys/instance.h>
460Sstevel@tonic-gate #include <sys/debug.h>
470Sstevel@tonic-gate #include <sys/policy.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Userland sees:
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  *	int inst_sync(pathname, flags);
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  * Returns zero if instance number information was successfully
550Sstevel@tonic-gate  * written to 'pathname', -1 plus error code in errno otherwise.
560Sstevel@tonic-gate  *
570Sstevel@tonic-gate  * POC notes:
580Sstevel@tonic-gate  *
590Sstevel@tonic-gate  * -	This could be done as a case of the modctl(2) system call
600Sstevel@tonic-gate  *	though the ability to have it load and unload would disappear.
610Sstevel@tonic-gate  *
626548Swroche  * -	'flags' have either of two meanings:
636548Swroche  *	INST_SYNC_IF_REQUIRED	'pathname' will be written if there
646548Swroche  *				has been a change in the kernel's
656548Swroche  *				internal view of instance number
666548Swroche  *				information
676548Swroche  *	INST_SYNC_ALWAYS	'pathname' will be written even if
686548Swroche  *				the kernel's view hasn't changed.
690Sstevel@tonic-gate  *
700Sstevel@tonic-gate  * -	Maybe we should pass through two filenames - one to create,
710Sstevel@tonic-gate  *	and the other as the 'final' target i.e. do the rename of
720Sstevel@tonic-gate  *	/etc/instance.new -> /etc/instance in the kernel.
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate 
750Sstevel@tonic-gate static int in_sync_sys(char *pathname, uint_t flags);
760Sstevel@tonic-gate 
770Sstevel@tonic-gate static struct sysent in_sync_sysent = {
780Sstevel@tonic-gate 	2,			/* number of arguments */
790Sstevel@tonic-gate 	SE_ARGC | SE_32RVAL1,	/* c-style calling, 32-bit return value */
800Sstevel@tonic-gate 	in_sync_sys,		/* the handler */
810Sstevel@tonic-gate 	(krwlock_t *)0		/* rw lock allocated/used by framework */
820Sstevel@tonic-gate };
830Sstevel@tonic-gate 
840Sstevel@tonic-gate static struct modlsys modlsys = {
850Sstevel@tonic-gate 	&mod_syscallops, "instance binding syscall", &in_sync_sysent
860Sstevel@tonic-gate };
870Sstevel@tonic-gate 
880Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
890Sstevel@tonic-gate static struct modlsys modlsys32 = {
900Sstevel@tonic-gate 	&mod_syscallops32, "32-bit instance binding syscall", &in_sync_sysent
910Sstevel@tonic-gate };
920Sstevel@tonic-gate #endif
930Sstevel@tonic-gate 
940Sstevel@tonic-gate static struct modlinkage modlinkage = {
950Sstevel@tonic-gate 	MODREV_1,
960Sstevel@tonic-gate 	&modlsys,
970Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
980Sstevel@tonic-gate 	&modlsys32,
990Sstevel@tonic-gate #endif
1000Sstevel@tonic-gate 	NULL
1010Sstevel@tonic-gate };
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate int
_init(void)1040Sstevel@tonic-gate _init(void)
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1100Sstevel@tonic-gate _info(struct modinfo *modinfop)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate int
_fini(void)1160Sstevel@tonic-gate _fini(void)
1170Sstevel@tonic-gate {
1180Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate static int in_write_instance(struct vnode *vp);
1220Sstevel@tonic-gate 
123*12116SVikram.Hegde@Sun.COM static int inst_sync_disable = 0;
124*12116SVikram.Hegde@Sun.COM 
1250Sstevel@tonic-gate static int
in_sync_sys(char * pathname,uint_t flags)1260Sstevel@tonic-gate in_sync_sys(char *pathname, uint_t flags)
1270Sstevel@tonic-gate {
1280Sstevel@tonic-gate 	struct vnode *vp;
1290Sstevel@tonic-gate 	int error;
1300Sstevel@tonic-gate 
131*12116SVikram.Hegde@Sun.COM 	/* For debugging/testing */
132*12116SVikram.Hegde@Sun.COM 	if (inst_sync_disable)
133*12116SVikram.Hegde@Sun.COM 		return (0);
134*12116SVikram.Hegde@Sun.COM 
1350Sstevel@tonic-gate 	/*
1360Sstevel@tonic-gate 	 * We must have sufficient privilege to do this, since we lock critical
1370Sstevel@tonic-gate 	 * data structures whilst we're doing it ..
1380Sstevel@tonic-gate 	 */
1390Sstevel@tonic-gate 	if ((error = secpolicy_sys_devices(CRED())) != 0)
1400Sstevel@tonic-gate 		return (set_errno(error));
1410Sstevel@tonic-gate 
1426548Swroche 	if (flags != INST_SYNC_ALWAYS && flags != INST_SYNC_IF_REQUIRED)
1436548Swroche 		return (set_errno(EINVAL));
1446548Swroche 
1450Sstevel@tonic-gate 	/*
1460Sstevel@tonic-gate 	 * Only one process is allowed to get the state of the instance
1470Sstevel@tonic-gate 	 * number assignments on the system at any given time.
1480Sstevel@tonic-gate 	 */
1490Sstevel@tonic-gate 	e_ddi_enter_instance();
1500Sstevel@tonic-gate 
1516548Swroche 	/*
1526548Swroche 	 * Recreate the instance file only if the device tree has changed
1536548Swroche 	 * or if the caller explicitly requests so.
1546548Swroche 	 */
1556548Swroche 	if (e_ddi_instance_is_clean() && flags != INST_SYNC_ALWAYS) {
1560Sstevel@tonic-gate 		error = EALREADY;
1570Sstevel@tonic-gate 		goto end;
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	/*
1610Sstevel@tonic-gate 	 * Create an instance file for writing, giving it a mode that
1620Sstevel@tonic-gate 	 * will only permit reading.  Note that we refuse to overwrite
1630Sstevel@tonic-gate 	 * an existing file.
1640Sstevel@tonic-gate 	 */
1650Sstevel@tonic-gate 	if ((error = vn_open(pathname, UIO_USERSPACE,
1660Sstevel@tonic-gate 	    FCREAT, 0444, &vp, CRCREAT, 0)) != 0) {
1670Sstevel@tonic-gate 		if (error == EISDIR)
1680Sstevel@tonic-gate 			error = EACCES;	/* SVID compliance? */
1690Sstevel@tonic-gate 		goto end;
1700Sstevel@tonic-gate 	}
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	/*
1730Sstevel@tonic-gate 	 * So far so good.  We're singly threaded, the vnode is beckoning
1740Sstevel@tonic-gate 	 * so let's get on with it.  Any error, and we just give up and
1750Sstevel@tonic-gate 	 * hand the first error we get back to userland.
1760Sstevel@tonic-gate 	 */
1770Sstevel@tonic-gate 	error = in_write_instance(vp);
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	/*
1800Sstevel@tonic-gate 	 * If there was any sort of error, we deliberately go and
1810Sstevel@tonic-gate 	 * remove the file we just created so that any attempts to
1820Sstevel@tonic-gate 	 * use it will quickly fail.
1830Sstevel@tonic-gate 	 */
1840Sstevel@tonic-gate 	if (error)
1850Sstevel@tonic-gate 		(void) vn_remove(pathname, UIO_USERSPACE, RMFILE);
1860Sstevel@tonic-gate 	else
1870Sstevel@tonic-gate 		e_ddi_instance_set_clean();
1880Sstevel@tonic-gate end:
1890Sstevel@tonic-gate 	e_ddi_exit_instance();
1900Sstevel@tonic-gate 	return (error ? set_errno(error) : 0);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate /*
1940Sstevel@tonic-gate  * At the risk of reinventing stdio ..
1950Sstevel@tonic-gate  */
1960Sstevel@tonic-gate #define	FBUFSIZE	512
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate typedef struct _File {
1990Sstevel@tonic-gate 	char	*ptr;
2000Sstevel@tonic-gate 	int	count;
2010Sstevel@tonic-gate 	char	buf[FBUFSIZE];
2020Sstevel@tonic-gate 	vnode_t	*vp;
2030Sstevel@tonic-gate 	offset_t voffset;
2040Sstevel@tonic-gate } File;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate static int
in_write(struct vnode * vp,offset_t * vo,caddr_t buf,int count)2070Sstevel@tonic-gate in_write(struct vnode *vp, offset_t *vo, caddr_t buf, int count)
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 	int error;
2100Sstevel@tonic-gate 	ssize_t resid;
2110Sstevel@tonic-gate 	rlim64_t rlimit = *vo + count + 1;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	error = vn_rdwr(UIO_WRITE, vp, buf, count, *vo,
2140Sstevel@tonic-gate 	    UIO_SYSSPACE, 0, rlimit, CRED(), &resid);
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	*vo += (offset_t)(count - resid);
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	return (error);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate static File *
in_fvpopen(struct vnode * vp)2220Sstevel@tonic-gate in_fvpopen(struct vnode *vp)
2230Sstevel@tonic-gate {
2240Sstevel@tonic-gate 	File *fp;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	fp = kmem_zalloc(sizeof (File), KM_SLEEP);
2270Sstevel@tonic-gate 	fp->vp = vp;
2280Sstevel@tonic-gate 	fp->ptr = fp->buf;
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	return (fp);
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate static int
in_fclose(File * fp)2340Sstevel@tonic-gate in_fclose(File *fp)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate 	int error;
2370Sstevel@tonic-gate 
2385331Samw 	error = VOP_CLOSE(fp->vp, FCREAT, 1, (offset_t)0, CRED(), NULL);
2390Sstevel@tonic-gate 	VN_RELE(fp->vp);
2400Sstevel@tonic-gate 	kmem_free(fp, sizeof (File));
2410Sstevel@tonic-gate 	return (error);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate static int
in_fflush(File * fp)2450Sstevel@tonic-gate in_fflush(File *fp)
2460Sstevel@tonic-gate {
2470Sstevel@tonic-gate 	int error = 0;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	if (fp->count)
2500Sstevel@tonic-gate 		error = in_write(fp->vp, &fp->voffset, fp->buf, fp->count);
2510Sstevel@tonic-gate 	if (error == 0)
2525331Samw 		error = VOP_FSYNC(fp->vp, FSYNC, CRED(), NULL);
2530Sstevel@tonic-gate 	return (error);
2540Sstevel@tonic-gate }
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate static int
in_fputs(File * fp,char * buf)2570Sstevel@tonic-gate in_fputs(File *fp, char *buf)
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 	int error = 0;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	while (*buf) {
2620Sstevel@tonic-gate 		*fp->ptr++ = *buf++;
2630Sstevel@tonic-gate 		if (++fp->count == FBUFSIZE) {
2640Sstevel@tonic-gate 			error = in_write(fp->vp, &fp->voffset, fp->buf,
2650Sstevel@tonic-gate 			    fp->count);
2660Sstevel@tonic-gate 			if (error)
2670Sstevel@tonic-gate 				break;
2680Sstevel@tonic-gate 			fp->count = 0;
2690Sstevel@tonic-gate 			fp->ptr = fp->buf;
2700Sstevel@tonic-gate 		}
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	return (error);
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate /*
2770Sstevel@tonic-gate  * External linkage
2780Sstevel@tonic-gate  */
2790Sstevel@tonic-gate static File *in_fp;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate  * XXX what is the maximum length of the name of a driver?  Must be maximum
2830Sstevel@tonic-gate  * XXX file name length (find the correct constant and substitute for this one
2840Sstevel@tonic-gate  */
2850Sstevel@tonic-gate #define	DRVNAMELEN (1 + 256)
2860Sstevel@tonic-gate static char linebuffer[MAXPATHLEN + 1 + 1 + 1 + 1 + 10 + 1 + DRVNAMELEN];
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate /*
2890Sstevel@tonic-gate  * XXX	Maybe we should just write 'in_fprintf' instead ..
2900Sstevel@tonic-gate  */
2910Sstevel@tonic-gate static int
in_walktree(in_node_t * np,char * this)2920Sstevel@tonic-gate in_walktree(in_node_t *np, char *this)
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate 	char *next;
2950Sstevel@tonic-gate 	int error = 0;
2960Sstevel@tonic-gate 	in_drv_t *dp;
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	for (error = 0; np; np = np->in_sibling) {
2990Sstevel@tonic-gate 
300*12116SVikram.Hegde@Sun.COM 		if (np->in_drivers == NULL)
301*12116SVikram.Hegde@Sun.COM 			continue;
302*12116SVikram.Hegde@Sun.COM 
3030Sstevel@tonic-gate 		if (np->in_unit_addr[0] == '\0')
3040Sstevel@tonic-gate 			(void) sprintf(this, "/%s", np->in_node_name);
3050Sstevel@tonic-gate 		else
3060Sstevel@tonic-gate 			(void) sprintf(this, "/%s@%s", np->in_node_name,
3070Sstevel@tonic-gate 			    np->in_unit_addr);
3080Sstevel@tonic-gate 		next = this + strlen(this);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		ASSERT(np->in_drivers);
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 		for (dp = np->in_drivers; dp; dp = dp->ind_next_drv) {
3130Sstevel@tonic-gate 			uint_t inst_val = dp->ind_instance;
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 			/*
3160Sstevel@tonic-gate 			 * Flushing IN_PROVISIONAL could result in duplicate
3170Sstevel@tonic-gate 			 * instances
3180Sstevel@tonic-gate 			 * Flushing IN_UNKNOWN results in instance -1
3190Sstevel@tonic-gate 			 */
3200Sstevel@tonic-gate 			if (dp->ind_state != IN_PERMANENT)
3210Sstevel@tonic-gate 				continue;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 			(void) sprintf(next, "\" %d \"%s\"\n", inst_val,
3240Sstevel@tonic-gate 			    dp->ind_driver_name);
3250Sstevel@tonic-gate 			if (error = in_fputs(in_fp, linebuffer))
3260Sstevel@tonic-gate 				return (error);
3270Sstevel@tonic-gate 		}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 		if (np->in_child)
3300Sstevel@tonic-gate 			if (error = in_walktree(np->in_child, next))
3310Sstevel@tonic-gate 				break;
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 	return (error);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate /*
3380Sstevel@tonic-gate  * Walk the instance tree, writing out what we find.
3390Sstevel@tonic-gate  *
3400Sstevel@tonic-gate  * There's some fairly nasty sharing of buffers in this
3410Sstevel@tonic-gate  * bit of code, so be careful out there when you're
3420Sstevel@tonic-gate  * rewriting it ..
3430Sstevel@tonic-gate  */
3440Sstevel@tonic-gate static int
in_write_instance(struct vnode * vp)3450Sstevel@tonic-gate in_write_instance(struct vnode *vp)
3460Sstevel@tonic-gate {
3470Sstevel@tonic-gate 	int error;
3480Sstevel@tonic-gate 	char *cp;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	in_fp = in_fvpopen(vp);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/*
3530Sstevel@tonic-gate 	 * Place a bossy comment at the beginning of the file.
3540Sstevel@tonic-gate 	 */
3550Sstevel@tonic-gate 	error = in_fputs(in_fp,
3560Sstevel@tonic-gate 	    "#\n#\tCaution! This file contains critical kernel state\n#\n");
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	if (error == 0) {
3590Sstevel@tonic-gate 		in_node_t *root = e_ddi_instance_root();
3600Sstevel@tonic-gate 		cp = linebuffer;
3610Sstevel@tonic-gate 		*cp++ = '\"';
3620Sstevel@tonic-gate 		error = in_walktree(root->in_child, cp);
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	if (error == 0) {
3660Sstevel@tonic-gate 		if ((error = in_fflush(in_fp)) == 0)
3670Sstevel@tonic-gate 			error = in_fclose(in_fp);
3680Sstevel@tonic-gate 	} else
3690Sstevel@tonic-gate 		(void) in_fclose(in_fp);
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	return (error);
3720Sstevel@tonic-gate }
373