4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Syscall to write out the instance number data structures to
30 #include <sys/types.h>
31 #include <sys/errno.h>
32 #include <sys/t_lock.h>
33 #include <sys/modctl.h>
34 #include <sys/systm.h>
35 #include <sys/syscall.h>
37 #include <sys/vnode.h>
40 #include <sys/cmn_err.h>
42 #include <sys/cladm.h>
43 #include <sys/sunddi.h>
44 #include <sys/dditypes.h>
45 #include <sys/instance.h>
46 #include <sys/debug.h>
47 #include <sys/policy.h>
52 * int inst_sync(pathname, flags);
54 * Returns zero if instance number information was successfully
55 * written to 'pathname', -1 plus error code in errno otherwise.
59 * - This could be done as a case of the modctl(2) system call
60 * though the ability to have it load and unload would disappear.
62 * - 'flags' have either of two meanings:
63 * INST_SYNC_IF_REQUIRED 'pathname' will be written if there
64 * has been a change in the kernel's
65 * internal view of instance number
67 * INST_SYNC_ALWAYS 'pathname' will be written even if
68 * the kernel's view hasn't changed.
70 * - Maybe we should pass through two filenames - one to create,
71 * and the other as the 'final' target i.e. do the rename of
72 * /etc/instance.new -> /etc/instance in the kernel.
75 static int in_sync_sys(char *pathname
, uint_t flags
);
77 static struct sysent in_sync_sysent
= {
78 2, /* number of arguments */
79 SE_ARGC
| SE_32RVAL1
, /* c-style calling, 32-bit return value */
80 in_sync_sys
, /* the handler */
81 (krwlock_t
*)0 /* rw lock allocated/used by framework */
84 static struct modlsys modlsys
= {
85 &mod_syscallops
, "instance binding syscall", &in_sync_sysent
88 #ifdef _SYSCALL32_IMPL
89 static struct modlsys modlsys32
= {
90 &mod_syscallops32
, "32-bit instance binding syscall", &in_sync_sysent
94 static struct modlinkage modlinkage
= {
97 #ifdef _SYSCALL32_IMPL
106 return (mod_install(&modlinkage
));
110 _info(struct modinfo
*modinfop
)
112 return (mod_info(&modlinkage
, modinfop
));
118 return (mod_remove(&modlinkage
));
121 static int in_write_instance(struct vnode
*vp
);
123 static int inst_sync_disable
= 0;
126 in_sync_sys(char *pathname
, uint_t flags
)
131 /* For debugging/testing */
132 if (inst_sync_disable
)
136 * We must have sufficient privilege to do this, since we lock critical
137 * data structures whilst we're doing it ..
139 if ((error
= secpolicy_sys_devices(CRED())) != 0)
140 return (set_errno(error
));
142 if (flags
!= INST_SYNC_ALWAYS
&& flags
!= INST_SYNC_IF_REQUIRED
)
143 return (set_errno(EINVAL
));
146 * Only one process is allowed to get the state of the instance
147 * number assignments on the system at any given time.
149 e_ddi_enter_instance();
152 * Recreate the instance file only if the device tree has changed
153 * or if the caller explicitly requests so.
155 if (e_ddi_instance_is_clean() && flags
!= INST_SYNC_ALWAYS
) {
161 * Create an instance file for writing, giving it a mode that
162 * will only permit reading. Note that we refuse to overwrite
165 if ((error
= vn_open(pathname
, UIO_USERSPACE
,
166 FCREAT
, 0444, &vp
, CRCREAT
, 0)) != 0) {
168 error
= EACCES
; /* SVID compliance? */
173 * So far so good. We're singly threaded, the vnode is beckoning
174 * so let's get on with it. Any error, and we just give up and
175 * hand the first error we get back to userland.
177 error
= in_write_instance(vp
);
180 * If there was any sort of error, we deliberately go and
181 * remove the file we just created so that any attempts to
182 * use it will quickly fail.
185 (void) vn_remove(pathname
, UIO_USERSPACE
, RMFILE
);
187 e_ddi_instance_set_clean();
189 e_ddi_exit_instance();
190 return (error
? set_errno(error
) : 0);
194 * At the risk of reinventing stdio ..
198 typedef struct _File
{
207 in_write(struct vnode
*vp
, offset_t
*vo
, caddr_t buf
, int count
)
211 rlim64_t rlimit
= *vo
+ count
+ 1;
213 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, count
, *vo
,
214 UIO_SYSSPACE
, 0, rlimit
, CRED(), &resid
);
216 *vo
+= (offset_t
)(count
- resid
);
222 in_fvpopen(struct vnode
*vp
)
226 fp
= kmem_zalloc(sizeof (File
), KM_SLEEP
);
238 error
= VOP_CLOSE(fp
->vp
, FCREAT
, 1, (offset_t
)0, CRED(), NULL
);
240 kmem_free(fp
, sizeof (File
));
250 error
= in_write(fp
->vp
, &fp
->voffset
, fp
->buf
, fp
->count
);
252 error
= VOP_FSYNC(fp
->vp
, FSYNC
, CRED(), NULL
);
257 in_fputs(File
*fp
, char *buf
)
263 if (++fp
->count
== FBUFSIZE
) {
264 error
= in_write(fp
->vp
, &fp
->voffset
, fp
->buf
,
282 * XXX what is the maximum length of the name of a driver? Must be maximum
283 * XXX file name length (find the correct constant and substitute for this one
285 #define DRVNAMELEN (1 + 256)
286 static char linebuffer
[MAXPATHLEN
+ 1 + 1 + 1 + 1 + 10 + 1 + DRVNAMELEN
];
289 * XXX Maybe we should just write 'in_fprintf' instead ..
292 in_walktree(in_node_t
*np
, char *this)
298 for (error
= 0; np
; np
= np
->in_sibling
) {
300 if (np
->in_drivers
== NULL
)
303 if (np
->in_unit_addr
[0] == '\0')
304 (void) sprintf(this, "/%s", np
->in_node_name
);
306 (void) sprintf(this, "/%s@%s", np
->in_node_name
,
308 next
= this + strlen(this);
310 ASSERT(np
->in_drivers
);
312 for (dp
= np
->in_drivers
; dp
; dp
= dp
->ind_next_drv
) {
313 uint_t inst_val
= dp
->ind_instance
;
316 * Flushing IN_PROVISIONAL could result in duplicate
318 * Flushing IN_UNKNOWN results in instance -1
320 if (dp
->ind_state
!= IN_PERMANENT
)
323 (void) sprintf(next
, "\" %d \"%s\"\n", inst_val
,
324 dp
->ind_driver_name
);
325 if (error
= in_fputs(in_fp
, linebuffer
))
330 if (error
= in_walktree(np
->in_child
, next
))
338 * Walk the instance tree, writing out what we find.
340 * There's some fairly nasty sharing of buffers in this
341 * bit of code, so be careful out there when you're
345 in_write_instance(struct vnode
*vp
)
350 in_fp
= in_fvpopen(vp
);
353 * Place a bossy comment at the beginning of the file.
355 error
= in_fputs(in_fp
,
356 "#\n#\tCaution! This file contains critical kernel state\n#\n");
359 in_node_t
*root
= e_ddi_instance_root();
362 error
= in_walktree(root
->in_child
, cp
);
366 if ((error
= in_fflush(in_fp
)) == 0)
367 error
= in_fclose(in_fp
);
369 (void) in_fclose(in_fp
);