diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 2000-03-13 04:59:44 +0000 |
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 2000-03-13 04:59:44 +0000 |
| commit | 842f30848780866cb822fe01c4d3d4576718ddb3 (patch) | |
| tree | 212d1aae25966b1cb7769409e1ae97e626a32b95 /sys/kern | |
| parent | dd3552c8a7b2b6823668c2834f667466844698de (diff) | |
Notes
Diffstat (limited to 'sys/kern')
| -rw-r--r-- | sys/kern/kern_random.c | 378 | ||||
| -rw-r--r-- | sys/kern/kern_tc.c | 1004 | ||||
| -rw-r--r-- | sys/kern/ksched.c | 264 | ||||
| -rw-r--r-- | sys/kern/link_elf_obj.c | 985 | ||||
| -rw-r--r-- | sys/kern/p1003_1b.c | 260 | ||||
| -rw-r--r-- | sys/kern/posix4_mib.c | 98 | ||||
| -rw-r--r-- | sys/kern/subr_acl_posix1e.c | 277 | ||||
| -rw-r--r-- | sys/kern/subr_clist.c | 696 | ||||
| -rw-r--r-- | sys/kern/subr_disklabel.c | 408 | ||||
| -rw-r--r-- | sys/kern/subr_param.c | 176 | ||||
| -rw-r--r-- | sys/kern/subr_smp.c | 2739 | ||||
| -rw-r--r-- | sys/kern/subr_trap.c | 1152 | ||||
| -rw-r--r-- | sys/kern/uipc_sockbuf.c | 1006 | ||||
| -rw-r--r-- | sys/kern/vfs_acl.c | 277 | ||||
| -rw-r--r-- | sys/kern/vfs_export.c | 2974 | ||||
| -rw-r--r-- | sys/kern/vfs_extattr.c | 3564 | ||||
| -rw-r--r-- | sys/kern/vfs_mount.c | 366 |
17 files changed, 0 insertions, 16624 deletions
diff --git a/sys/kern/kern_random.c b/sys/kern/kern_random.c deleted file mode 100644 index ef63742579e0..000000000000 --- a/sys/kern/kern_random.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * random_machdep.c -- A strong random number generator - * - * $FreeBSD$ - * - * Version 0.95, last modified 18-Oct-95 - * - * Copyright Theodore Ts'o, 1994, 1995. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/select.h> -#include <sys/poll.h> -#include <sys/md5.h> - -#include <machine/random.h> - -#include <i386/isa/icu.h> - -#define MAX_BLKDEV 4 - -/* - * The pool is stirred with a primitive polynomial of degree 128 - * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1. - * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1. - */ -#define POOLWORDS 128 /* Power of 2 - note that this is 32-bit words */ -#define POOLBITS (POOLWORDS*32) - -#if POOLWORDS == 128 -#define TAP1 99 /* The polynomial taps */ -#define TAP2 59 -#define TAP3 31 -#define TAP4 9 -#define TAP5 7 -#elif POOLWORDS == 64 -#define TAP1 62 /* The polynomial taps */ -#define TAP2 38 -#define TAP3 10 -#define TAP4 6 -#define TAP5 1 -#else -#error No primitive polynomial available for chosen POOLWORDS -#endif - -#define WRITEBUFFER 512 /* size in bytes */ - -/* There is actually only one of these, globally. */ -struct random_bucket { - u_int add_ptr; - u_int entropy_count; - int input_rotate; - u_int32_t *pool; - struct selinfo rsel; -}; - -/* There is one of these per entropy source */ -struct timer_rand_state { - u_long last_time; - int last_delta; - int nbits; -}; - -static struct random_bucket random_state; -static u_int32_t random_pool[POOLWORDS]; -static struct timer_rand_state keyboard_timer_state; -static struct timer_rand_state extract_timer_state; -static struct timer_rand_state irq_timer_state[ICU_LEN]; -#ifdef notyet -static struct timer_rand_state blkdev_timer_state[MAX_BLKDEV]; -#endif -static struct wait_queue *random_wait; - -#ifndef MIN -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#endif - -void -rand_initialize(void) -{ - random_state.add_ptr = 0; - random_state.entropy_count = 0; - random_state.pool = random_pool; - random_wait = NULL; - random_state.rsel.si_flags = 0; - random_state.rsel.si_pid = 0; -} - -/* - * This function adds an int into the entropy "pool". It does not - * update the entropy estimate. The caller must do this if appropriate. - * - * The pool is stirred with a primitive polynomial of degree 128 - * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1. - * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1. - * - * We rotate the input word by a changing number of bits, to help - * assure that all bits in the entropy get toggled. Otherwise, if we - * consistently feed the entropy pool small numbers (like ticks and - * scancodes, for example), the upper bits of the entropy pool don't - * get affected. --- TYT, 10/11/95 - */ -static __inline void -add_entropy_word(struct random_bucket *r, const u_int32_t input) -{ - u_int i; - u_int32_t w; - - w = (input << r->input_rotate) | (input >> (32 - r->input_rotate)); - i = r->add_ptr = (r->add_ptr - 1) & (POOLWORDS-1); - if (i) - r->input_rotate = (r->input_rotate + 7) & 31; - else - /* - * At the beginning of the pool, add an extra 7 bits - * rotation, so that successive passes spread the - * input bits across the pool evenly. - */ - r->input_rotate = (r->input_rotate + 14) & 31; - - /* XOR in the various taps */ - w ^= r->pool[(i+TAP1)&(POOLWORDS-1)]; - w ^= r->pool[(i+TAP2)&(POOLWORDS-1)]; - w ^= r->pool[(i+TAP3)&(POOLWORDS-1)]; - w ^= r->pool[(i+TAP4)&(POOLWORDS-1)]; - w ^= r->pool[(i+TAP5)&(POOLWORDS-1)]; - w ^= r->pool[i]; - /* Rotate w left 1 bit (stolen from SHA) and store */ - r->pool[i] = (w << 1) | (w >> 31); -} - -/* - * This function adds entropy to the entropy "pool" by using timing - * delays. It uses the timer_rand_state structure to make an estimate - * of how any bits of entropy this call has added to the pool. - * - * The number "num" is also added to the pool - it should somehow describe - * the type of event which just happened. This is currently 0-255 for - * keyboard scan codes, and 256 upwards for interrupts. - * On the i386, this is assumed to be at most 16 bits, and the high bits - * are used for a high-resolution timer. - */ -static void -add_timer_randomness(struct random_bucket *r, struct timer_rand_state *state, - u_int num) -{ - int delta, delta2; - u_int nbits; - u_int32_t time; - - num ^= timecounter->tc_get_timecount(timecounter) << 16; - r->entropy_count += 2; - - time = ticks; - - add_entropy_word(r, (u_int32_t) num); - add_entropy_word(r, time); - - /* - * Calculate number of bits of randomness we probably - * added. We take into account the first and second order - * deltas in order to make our estimate. - */ - delta = time - state->last_time; - state->last_time = time; - - delta2 = delta - state->last_delta; - state->last_delta = delta; - - if (delta < 0) delta = -delta; - if (delta2 < 0) delta2 = -delta2; - delta = MIN(delta, delta2) >> 1; - for (nbits = 0; delta; nbits++) - delta >>= 1; - - r->entropy_count += nbits; - - /* Prevent overflow */ - if (r->entropy_count > POOLBITS) - r->entropy_count = POOLBITS; - - if (r->entropy_count >= 8) - selwakeup(&random_state.rsel); -} - -void -add_keyboard_randomness(u_char scancode) -{ - add_timer_randomness(&random_state, &keyboard_timer_state, scancode); -} - -void -add_interrupt_randomness(void *vsc) -{ - int intr; - struct random_softc *sc = vsc; - - (sc->sc_handler)(sc->sc_arg); - intr = sc->sc_intr; - add_timer_randomness(&random_state, &irq_timer_state[intr], intr); -} - -#ifdef notused -void -add_blkdev_randomness(int major) -{ - if (major >= MAX_BLKDEV) - return; - - add_timer_randomness(&random_state, &blkdev_timer_state[major], - 0x200+major); -} -#endif /* notused */ - -#if POOLWORDS % 16 -#error extract_entropy() assumes that POOLWORDS is a multiple of 16 words. -#endif -/* - * This function extracts randomness from the "entropy pool", and - * returns it in a buffer. This function computes how many remaining - * bits of entropy are left in the pool, but it does not restrict the - * number of bytes that are actually obtained. - */ -static __inline int -extract_entropy(struct random_bucket *r, char *buf, int nbytes) -{ - int ret, i; - u_int32_t tmp[4]; - - add_timer_randomness(r, &extract_timer_state, nbytes); - - /* Redundant, but just in case... */ - if (r->entropy_count > POOLBITS) - r->entropy_count = POOLBITS; - /* Why is this here? Left in from Ted Ts'o. Perhaps to limit time. */ - if (nbytes > 32768) - nbytes = 32768; - - ret = nbytes; - if (r->entropy_count / 8 >= nbytes) - r->entropy_count -= nbytes*8; - else - r->entropy_count = 0; - - while (nbytes) { - /* Hash the pool to get the output */ - tmp[0] = 0x67452301; - tmp[1] = 0xefcdab89; - tmp[2] = 0x98badcfe; - tmp[3] = 0x10325476; - for (i = 0; i < POOLWORDS; i += 16) - MD5Transform(tmp, (char *)(r->pool+i)); - /* Modify pool so next hash will produce different results */ - add_entropy_word(r, tmp[0]); - add_entropy_word(r, tmp[1]); - add_entropy_word(r, tmp[2]); - add_entropy_word(r, tmp[3]); - /* - * Run the MD5 Transform one more time, since we want - * to add at least minimal obscuring of the inputs to - * add_entropy_word(). --- TYT - */ - MD5Transform(tmp, (char *)(r->pool)); - - /* Copy data to destination buffer */ - i = MIN(nbytes, 16); - bcopy(tmp, buf, i); - nbytes -= i; - buf += i; - } - - /* Wipe data from memory */ - bzero(tmp, sizeof(tmp)); - - return ret; -} - -#ifdef notused /* XXX NOT the exported kernel interface */ -/* - * This function is the exported kernel interface. It returns some - * number of good random numbers, suitable for seeding TCP sequence - * numbers, etc. - */ -void -get_random_bytes(void *buf, u_int nbytes) -{ - extract_entropy(&random_state, (char *) buf, nbytes); -} -#endif /* notused */ - -u_int -read_random(void *buf, u_int nbytes) -{ - if ((nbytes * 8) > random_state.entropy_count) - nbytes = random_state.entropy_count / 8; - - return extract_entropy(&random_state, (char *)buf, nbytes); -} - -u_int -read_random_unlimited(void *buf, u_int nbytes) -{ - return extract_entropy(&random_state, (char *)buf, nbytes); -} - -#ifdef notused -u_int -write_random(const char *buf, u_int nbytes) -{ - u_int i; - u_int32_t word, *p; - - for (i = nbytes, p = (u_int32_t *)buf; - i >= sizeof(u_int32_t); - i-= sizeof(u_int32_t), p++) - add_entropy_word(&random_state, *p); - if (i) { - word = 0; - bcopy(p, &word, i); - add_entropy_word(&random_state, word); - } - return nbytes; -} -#endif /* notused */ - -int -random_poll(dev_t dev, int events, struct proc *p) -{ - int s; - int revents = 0; - - s = splhigh(); - if (events & (POLLIN | POLLRDNORM)) { - if (random_state.entropy_count >= 8) - revents |= events & (POLLIN | POLLRDNORM); - else - selrecord(p, &random_state.rsel); - } - splx(s); - if (events & (POLLOUT | POLLWRNORM)) - revents |= events & (POLLOUT | POLLWRNORM); /* heh */ - - return (revents); -} - diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c deleted file mode 100644 index 6166e1cb2518..000000000000 --- a/sys/kern/kern_tc.c +++ /dev/null @@ -1,1004 +0,0 @@ -/*- - * Copyright (c) 1997, 1998 Poul-Henning Kamp <phk@FreeBSD.org> - * Copyright (c) 1982, 1986, 1991, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 - * $FreeBSD$ - */ - -#include "opt_ntp.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/dkstat.h> -#include <sys/callout.h> -#include <sys/kernel.h> -#include <sys/proc.h> -#include <sys/malloc.h> -#include <sys/resourcevar.h> -#include <sys/signalvar.h> -#include <sys/timex.h> -#include <sys/timepps.h> -#include <vm/vm.h> -#include <sys/lock.h> -#include <vm/pmap.h> -#include <vm/vm_map.h> -#include <sys/sysctl.h> - -#include <machine/cpu.h> -#include <machine/limits.h> - -#ifdef GPROF -#include <sys/gmon.h> -#endif - -#if defined(SMP) && defined(BETTER_CLOCK) -#include <machine/smp.h> -#endif - -/* - * Number of timecounters used to implement stable storage - */ -#ifndef NTIMECOUNTER -#define NTIMECOUNTER 5 -#endif - -static MALLOC_DEFINE(M_TIMECOUNTER, "timecounter", - "Timecounter stable storage"); - -static void initclocks __P((void *dummy)); -SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL) - -static void tco_forward __P((int force)); -static void tco_setscales __P((struct timecounter *tc)); -static __inline unsigned tco_delta __P((struct timecounter *tc)); - -/* Some of these don't belong here, but it's easiest to concentrate them. */ -#if defined(SMP) && defined(BETTER_CLOCK) -long cp_time[CPUSTATES]; -#else -static long cp_time[CPUSTATES]; -#endif - -long tk_cancc; -long tk_nin; -long tk_nout; -long tk_rawcc; - -time_t time_second; - -struct timeval boottime; -SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, CTLFLAG_RD, - &boottime, timeval, "System boottime"); - -/* - * Which update policy to use. - * 0 - every tick, bad hardware may fail with "calcru negative..." - * 1 - more resistent to the above hardware, but less efficient. - */ -static int tco_method; - -/* - * Implement a dummy timecounter which we can use until we get a real one - * in the air. This allows the console and other early stuff to use - * timeservices. - */ - -static unsigned -dummy_get_timecount(struct timecounter *tc) -{ - static unsigned now; - return (++now); -} - -static struct timecounter dummy_timecounter = { - dummy_get_timecount, - 0, - ~0u, - 1000000, - "dummy" -}; - -struct timecounter *timecounter = &dummy_timecounter; - -/* - * Clock handling routines. - * - * This code is written to operate with two timers that run independently of - * each other. - * - * The main timer, running hz times per second, is used to trigger interval - * timers, timeouts and rescheduling as needed. - * - * The second timer handles kernel and user profiling, - * and does resource use estimation. If the second timer is programmable, - * it is randomized to avoid aliasing between the two clocks. For example, - * the randomization prevents an adversary from always giving up the cpu - * just before its quantum expires. Otherwise, it would never accumulate - * cpu ticks. The mean frequency of the second timer is stathz. - * - * If no second timer exists, stathz will be zero; in this case we drive - * profiling and statistics off the main clock. This WILL NOT be accurate; - * do not do it unless absolutely necessary. - * - * The statistics clock may (or may not) be run at a higher rate while - * profiling. This profile clock runs at profhz. We require that profhz - * be an integral multiple of stathz. - * - * If the statistics clock is running fast, it must be divided by the ratio - * profhz/stathz for statistics. (For profiling, every tick counts.) - * - * Time-of-day is maintained using a "timecounter", which may or may - * not be related to the hardware generating the above mentioned - * interrupts. - */ - -int stathz; -int profhz; -static int profprocs; -int ticks; -static int psdiv, pscnt; /* prof => stat divider */ -int psratio; /* ratio: prof / stat */ - -/* - * Initialize clock frequencies and start both clocks running. - */ -/* ARGSUSED*/ -static void -initclocks(dummy) - void *dummy; -{ - register int i; - - /* - * Set divisors to 1 (normal case) and let the machine-specific - * code do its bit. - */ - psdiv = pscnt = 1; - cpu_initclocks(); - - /* - * Compute profhz/stathz, and fix profhz if needed. - */ - i = stathz ? stathz : hz; - if (profhz == 0) - profhz = i; - psratio = profhz / i; -} - -/* - * The real-time timer, interrupting hz times per second. - */ -void -hardclock(frame) - register struct clockframe *frame; -{ - register struct proc *p; - - p = curproc; - if (p) { - register struct pstats *pstats; - - /* - * Run current process's virtual and profile time, as needed. - */ - pstats = p->p_stats; - if (CLKF_USERMODE(frame) && - timevalisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) && - itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0) - psignal(p, SIGVTALRM); - if (timevalisset(&pstats->p_timer[ITIMER_PROF].it_value) && - itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0) - psignal(p, SIGPROF); - } - -#if defined(SMP) && defined(BETTER_CLOCK) - forward_hardclock(pscnt); -#endif - - /* - * If no separate statistics clock is available, run it from here. - */ - if (stathz == 0) - statclock(frame); - - tco_forward(0); - ticks++; - - /* - * Process callouts at a very low cpu priority, so we don't keep the - * relatively high clock interrupt priority any longer than necessary. - */ - if (TAILQ_FIRST(&callwheel[ticks & callwheelmask]) != NULL) { - if (CLKF_BASEPRI(frame)) { - /* - * Save the overhead of a software interrupt; - * it will happen as soon as we return, so do it now. - */ - (void)splsoftclock(); - softclock(); - } else - setsoftclock(); - } else if (softticks + 1 == ticks) - ++softticks; -} - -/* - * Compute number of ticks in the specified amount of time. - */ -int -tvtohz(tv) - struct timeval *tv; -{ - register unsigned long ticks; - register long sec, usec; - - /* - * If the number of usecs in the whole seconds part of the time - * difference fits in a long, then the total number of usecs will - * fit in an unsigned long. Compute the total and convert it to - * ticks, rounding up and adding 1 to allow for the current tick - * to expire. Rounding also depends on unsigned long arithmetic - * to avoid overflow. - * - * Otherwise, if the number of ticks in the whole seconds part of - * the time difference fits in a long, then convert the parts to - * ticks separately and add, using similar rounding methods and - * overflow avoidance. This method would work in the previous - * case but it is slightly slower and assumes that hz is integral. - * - * Otherwise, round the time difference down to the maximum - * representable value. - * - * If ints have 32 bits, then the maximum value for any timeout in - * 10ms ticks is 248 days. - */ - sec = tv->tv_sec; - usec = tv->tv_usec; - if (usec < 0) { - sec--; - usec += 1000000; - } - if (sec < 0) { -#ifdef DIAGNOSTIC - if (usec > 0) { - sec++; - usec -= 1000000; - } - printf("tvotohz: negative time difference %ld sec %ld usec\n", - sec, usec); -#endif - ticks = 1; - } else if (sec <= LONG_MAX / 1000000) - ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1)) - / tick + 1; - else if (sec <= LONG_MAX / hz) - ticks = sec * hz - + ((unsigned long)usec + (tick - 1)) / tick + 1; - else - ticks = LONG_MAX; - if (ticks > INT_MAX) - ticks = INT_MAX; - return ((int)ticks); -} - -/* - * Start profiling on a process. - * - * Kernel profiling passes proc0 which never exits and hence - * keeps the profile clock running constantly. - */ -void -startprofclock(p) - register struct proc *p; -{ - int s; - - if ((p->p_flag & P_PROFIL) == 0) { - p->p_flag |= P_PROFIL; - if (++profprocs == 1 && stathz != 0) { - s = splstatclock(); - psdiv = pscnt = psratio; - setstatclockrate(profhz); - splx(s); - } - } -} - -/* - * Stop profiling on a process. - */ -void -stopprofclock(p) - register struct proc *p; -{ - int s; - - if (p->p_flag & P_PROFIL) { - p->p_flag &= ~P_PROFIL; - if (--profprocs == 0 && stathz != 0) { - s = splstatclock(); - psdiv = pscnt = 1; - setstatclockrate(stathz); - splx(s); - } - } -} - -/* - * Statistics clock. Grab profile sample, and if divider reaches 0, - * do process and kernel statistics. Most of the statistics are only - * used by user-level statistics programs. The main exceptions are - * p->p_uticks, p->p_sticks, p->p_iticks, and p->p_estcpu. - */ -void -statclock(frame) - register struct clockframe *frame; -{ -#ifdef GPROF - register struct gmonparam *g; - int i; -#endif - register struct proc *p; - struct pstats *pstats; - long rss; - struct rusage *ru; - struct vmspace *vm; - - if (curproc != NULL && CLKF_USERMODE(frame)) { - /* - * Came from user mode; CPU was in user state. - * If this process is being profiled, record the tick. - */ - p = curproc; - if (p->p_flag & P_PROFIL) - addupc_intr(p, CLKF_PC(frame), 1); -#if defined(SMP) && defined(BETTER_CLOCK) - if (stathz != 0) - forward_statclock(pscnt); -#endif - if (--pscnt > 0) - return; - /* - * Charge the time as appropriate. - */ - p->p_uticks++; - if (p->p_nice > NZERO) - cp_time[CP_NICE]++; - else - cp_time[CP_USER]++; - } else { -#ifdef GPROF - /* - * Kernel statistics are just like addupc_intr, only easier. - */ - g = &_gmonparam; - if (g->state == GMON_PROF_ON) { - i = CLKF_PC(frame) - g->lowpc; - if (i < g->textsize) { - i /= HISTFRACTION * sizeof(*g->kcount); - g->kcount[i]++; - } - } -#endif -#if defined(SMP) && defined(BETTER_CLOCK) - if (stathz != 0) - forward_statclock(pscnt); -#endif - if (--pscnt > 0) - return; - /* - * Came from kernel mode, so we were: - * - handling an interrupt, - * - doing syscall or trap work on behalf of the current - * user process, or - * - spinning in the idle loop. - * Whichever it is, charge the time as appropriate. - * Note that we charge interrupts to the current process, - * regardless of whether they are ``for'' that process, - * so that we know how much of its real time was spent - * in ``non-process'' (i.e., interrupt) work. - */ - p = curproc; - if (CLKF_INTR(frame)) { - if (p != NULL) - p->p_iticks++; - cp_time[CP_INTR]++; - } else if (p != NULL) { - p->p_sticks++; - cp_time[CP_SYS]++; - } else - cp_time[CP_IDLE]++; - } - pscnt = psdiv; - - if (p != NULL) { - schedclock(p); - - /* Update resource usage integrals and maximums. */ - if ((pstats = p->p_stats) != NULL && - (ru = &pstats->p_ru) != NULL && - (vm = p->p_vmspace) != NULL) { - ru->ru_ixrss += pgtok(vm->vm_tsize); - ru->ru_idrss += pgtok(vm->vm_dsize); - ru->ru_isrss += pgtok(vm->vm_ssize); - rss = pgtok(vmspace_resident_count(vm)); - if (ru->ru_maxrss < rss) - ru->ru_maxrss = rss; - } - } -} - -/* - * Return information about system clocks. - */ -static int -sysctl_kern_clockrate SYSCTL_HANDLER_ARGS -{ - struct clockinfo clkinfo; - /* - * Construct clockinfo structure. - */ - clkinfo.hz = hz; - clkinfo.tick = tick; - clkinfo.tickadj = tickadj; - clkinfo.profhz = profhz; - clkinfo.stathz = stathz ? stathz : hz; - return (sysctl_handle_opaque(oidp, &clkinfo, sizeof clkinfo, req)); -} - -SYSCTL_PROC(_kern, KERN_CLOCKRATE, clockrate, CTLTYPE_STRUCT|CTLFLAG_RD, - 0, 0, sysctl_kern_clockrate, "S,clockinfo",""); - -static __inline unsigned -tco_delta(struct timecounter *tc) -{ - - return ((tc->tc_get_timecount(tc) - tc->tc_offset_count) & - tc->tc_counter_mask); -} - -/* - * We have eight functions for looking at the clock, four for - * microseconds and four for nanoseconds. For each there is fast - * but less precise version "get{nano|micro}[up]time" which will - * return a time which is up to 1/HZ previous to the call, whereas - * the raw version "{nano|micro}[up]time" will return a timestamp - * which is as precise as possible. The "up" variants return the - * time relative to system boot, these are well suited for time - * interval measurements. - */ - -void -getmicrotime(struct timeval *tvp) -{ - struct timecounter *tc; - - if (!tco_method) { - tc = timecounter; - *tvp = tc->tc_microtime; - } else { - microtime(tvp); - } -} - -void -getnanotime(struct timespec *tsp) -{ - struct timecounter *tc; - - if (!tco_method) { - tc = timecounter; - *tsp = tc->tc_nanotime; - } else { - nanotime(tsp); - } -} - -void -microtime(struct timeval *tv) -{ - struct timecounter *tc; - - tc = timecounter; - tv->tv_sec = tc->tc_offset_sec; - tv->tv_usec = tc->tc_offset_micro; - tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32; - tv->tv_usec += boottime.tv_usec; - tv->tv_sec += boottime.tv_sec; - while (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } -} - -void -nanotime(struct timespec *ts) -{ - unsigned count; - u_int64_t delta; - struct timecounter *tc; - - tc = timecounter; - ts->tv_sec = tc->tc_offset_sec; - count = tco_delta(tc); - delta = tc->tc_offset_nano; - delta += ((u_int64_t)count * tc->tc_scale_nano_f); - delta >>= 32; - delta += ((u_int64_t)count * tc->tc_scale_nano_i); - delta += boottime.tv_usec * 1000; - ts->tv_sec += boottime.tv_sec; - while (delta >= 1000000000) { - delta -= 1000000000; - ts->tv_sec++; - } - ts->tv_nsec = delta; -} - -void -getmicrouptime(struct timeval *tvp) -{ - struct timecounter *tc; - - if (!tco_method) { - tc = timecounter; - tvp->tv_sec = tc->tc_offset_sec; - tvp->tv_usec = tc->tc_offset_micro; - } else { - microuptime(tvp); - } -} - -void -getnanouptime(struct timespec *tsp) -{ - struct timecounter *tc; - - if (!tco_method) { - tc = timecounter; - tsp->tv_sec = tc->tc_offset_sec; - tsp->tv_nsec = tc->tc_offset_nano >> 32; - } else { - nanouptime(tsp); - } -} - -void -microuptime(struct timeval *tv) -{ - struct timecounter *tc; - - tc = timecounter; - tv->tv_sec = tc->tc_offset_sec; - tv->tv_usec = tc->tc_offset_micro; - tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32; - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } -} - -void -nanouptime(struct timespec *ts) -{ - unsigned count; - u_int64_t delta; - struct timecounter *tc; - - tc = timecounter; - ts->tv_sec = tc->tc_offset_sec; - count = tco_delta(tc); - delta = tc->tc_offset_nano; - delta += ((u_int64_t)count * tc->tc_scale_nano_f); - delta >>= 32; - delta += ((u_int64_t)count * tc->tc_scale_nano_i); - if (delta >= 1000000000) { - delta -= 1000000000; - ts->tv_sec++; - } - ts->tv_nsec = delta; -} - -static void -tco_setscales(struct timecounter *tc) -{ - u_int64_t scale; - - scale = 1000000000LL << 32; - scale += tc->tc_adjustment; - scale /= tc->tc_tweak->tc_frequency; - tc->tc_scale_micro = scale / 1000; - tc->tc_scale_nano_f = scale & 0xffffffff; - tc->tc_scale_nano_i = scale >> 32; -} - -void -update_timecounter(struct timecounter *tc) -{ - tco_setscales(tc); -} - -void -init_timecounter(struct timecounter *tc) -{ - struct timespec ts1; - struct timecounter *t1, *t2, *t3; - int i; - - tc->tc_adjustment = 0; - tc->tc_tweak = tc; - tco_setscales(tc); - tc->tc_offset_count = tc->tc_get_timecount(tc); - if (timecounter == &dummy_timecounter) - tc->tc_avail = tc; - else { - tc->tc_avail = timecounter->tc_tweak->tc_avail; - timecounter->tc_tweak->tc_avail = tc; - } - MALLOC(t1, struct timecounter *, sizeof *t1, M_TIMECOUNTER, M_WAITOK); - tc->tc_other = t1; - *t1 = *tc; - t2 = t1; - for (i = 1; i < NTIMECOUNTER; i++) { - MALLOC(t3, struct timecounter *, sizeof *t3, - M_TIMECOUNTER, M_WAITOK); - *t3 = *tc; - t3->tc_other = t2; - t2 = t3; - } - t1->tc_other = t3; - tc = t1; - - printf("Timecounter \"%s\" frequency %lu Hz\n", - tc->tc_name, (u_long)tc->tc_frequency); - - /* XXX: For now always start using the counter. */ - tc->tc_offset_count = tc->tc_get_timecount(tc); - nanouptime(&ts1); - tc->tc_offset_nano = (u_int64_t)ts1.tv_nsec << 32; - tc->tc_offset_micro = ts1.tv_nsec / 1000; - tc->tc_offset_sec = ts1.tv_sec; - timecounter = tc; -} - -void -set_timecounter(struct timespec *ts) -{ - struct timespec ts2; - - nanouptime(&ts2); - boottime.tv_sec = ts->tv_sec - ts2.tv_sec; - boottime.tv_usec = (ts->tv_nsec - ts2.tv_nsec) / 1000; - if (boottime.tv_usec < 0) { - boottime.tv_usec += 1000000; - boottime.tv_sec--; - } - /* fiddle all the little crinkly bits around the fiords... */ - tco_forward(1); -} - -static void -switch_timecounter(struct timecounter *newtc) -{ - int s; - struct timecounter *tc; - struct timespec ts; - - s = splclock(); - tc = timecounter; - if (newtc->tc_tweak == tc->tc_tweak) { - splx(s); - return; - } - newtc = newtc->tc_tweak->tc_other; - nanouptime(&ts); - newtc->tc_offset_sec = ts.tv_sec; - newtc->tc_offset_nano = (u_int64_t)ts.tv_nsec << 32; - newtc->tc_offset_micro = ts.tv_nsec / 1000; - newtc->tc_offset_count = newtc->tc_get_timecount(newtc); - tco_setscales(newtc); - timecounter = newtc; - splx(s); -} - -static struct timecounter * -sync_other_counter(void) -{ - struct timecounter *tc, *tcn, *tco; - unsigned delta; - - tco = timecounter; - tc = tco->tc_other; - tcn = tc->tc_other; - *tc = *tco; - tc->tc_other = tcn; - delta = tco_delta(tc); - tc->tc_offset_count += delta; - tc->tc_offset_count &= tc->tc_counter_mask; - tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_f; - tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_i << 32; - return (tc); -} - -static void -tco_forward(int force) -{ - struct timecounter *tc, *tco; - struct timeval tvt; - - tco = timecounter; - tc = sync_other_counter(); - /* - * We may be inducing a tiny error here, the tc_poll_pps() may - * process a latched count which happens after the tco_delta() - * in sync_other_counter(), which would extend the previous - * counters parameters into the domain of this new one. - * Since the timewindow is very small for this, the error is - * going to be only a few weenieseconds (as Dave Mills would - * say), so lets just not talk more about it, OK ? - */ - if (tco->tc_poll_pps) - tco->tc_poll_pps(tco); - if (timedelta != 0) { - tvt = boottime; - tvt.tv_usec += tickdelta; - if (tvt.tv_usec >= 1000000) { - tvt.tv_sec++; - tvt.tv_usec -= 1000000; - } else if (tvt.tv_usec < 0) { - tvt.tv_sec--; - tvt.tv_usec += 1000000; - } - boottime = tvt; - timedelta -= tickdelta; - } - - while (tc->tc_offset_nano >= 1000000000ULL << 32) { - tc->tc_offset_nano -= 1000000000ULL << 32; - tc->tc_offset_sec++; - ntp_update_second(tc); /* XXX only needed if xntpd runs */ - tco_setscales(tc); - force++; - } - - if (tco_method && !force) - return; - - tc->tc_offset_micro = (tc->tc_offset_nano / 1000) >> 32; - - /* Figure out the wall-clock time */ - tc->tc_nanotime.tv_sec = tc->tc_offset_sec + boottime.tv_sec; - tc->tc_nanotime.tv_nsec = - (tc->tc_offset_nano >> 32) + boottime.tv_usec * 1000; - tc->tc_microtime.tv_usec = tc->tc_offset_micro + boottime.tv_usec; - if (tc->tc_nanotime.tv_nsec >= 1000000000) { - tc->tc_nanotime.tv_nsec -= 1000000000; - tc->tc_microtime.tv_usec -= 1000000; - tc->tc_nanotime.tv_sec++; - } - time_second = tc->tc_microtime.tv_sec = tc->tc_nanotime.tv_sec; - - timecounter = tc; -} - -SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, ""); - -SYSCTL_INT(_kern_timecounter, OID_AUTO, method, CTLFLAG_RW, &tco_method, 0, - "This variable determines the method used for updating timecounters. " - "If the default algorithm (0) fails with \"calcru negative...\" messages " - "try the alternate algorithm (1) which handles bad hardware better." - -); - -static int -sysctl_kern_timecounter_hardware SYSCTL_HANDLER_ARGS -{ - char newname[32]; - struct timecounter *newtc, *tc; - int error; - - tc = timecounter->tc_tweak; - strncpy(newname, tc->tc_name, sizeof(newname)); - error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req); - if (error == 0 && req->newptr != NULL && - strcmp(newname, tc->tc_name) != 0) { - for (newtc = tc->tc_avail; newtc != tc; - newtc = newtc->tc_avail) { - if (strcmp(newname, newtc->tc_name) == 0) { - /* Warm up new timecounter. */ - (void)newtc->tc_get_timecount(newtc); - - switch_timecounter(newtc); - return (0); - } - } - return (EINVAL); - } - return (error); -} - -SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW, - 0, 0, sysctl_kern_timecounter_hardware, "A", ""); - - -int -pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) -{ - pps_params_t *app; - struct pps_fetch_args *fapi; -#ifdef PPS_SYNC - struct pps_kcbind_args *kapi; -#endif - - switch (cmd) { - case PPS_IOC_CREATE: - return (0); - case PPS_IOC_DESTROY: - return (0); - case PPS_IOC_SETPARAMS: - app = (pps_params_t *)data; - if (app->mode & ~pps->ppscap) - return (EINVAL); - pps->ppsparam = *app; - return (0); - case PPS_IOC_GETPARAMS: - app = (pps_params_t *)data; - *app = pps->ppsparam; - app->api_version = PPS_API_VERS_1; - return (0); - case PPS_IOC_GETCAP: - *(int*)data = pps->ppscap; - return (0); - case PPS_IOC_FETCH: - fapi = (struct pps_fetch_args *)data; - if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC) - return (EINVAL); - if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec) - return (EOPNOTSUPP); - pps->ppsinfo.current_mode = pps->ppsparam.mode; - fapi->pps_info_buf = pps->ppsinfo; - return (0); - case PPS_IOC_KCBIND: -#ifdef PPS_SYNC - kapi = (struct pps_kcbind_args *)data; - /* XXX Only root should be able to do this */ - if (kapi->tsformat && kapi->tsformat != PPS_TSFMT_TSPEC) - return (EINVAL); - if (kapi->kernel_consumer != PPS_KC_HARDPPS) - return (EINVAL); - if (kapi->edge & ~pps->ppscap) - return (EINVAL); - pps->kcmode = kapi->edge; - return (0); -#else - return (EOPNOTSUPP); -#endif - default: - return (ENOTTY); - } -} - -void -pps_init(struct pps_state *pps) -{ - pps->ppscap |= PPS_TSFMT_TSPEC; - if (pps->ppscap & PPS_CAPTUREASSERT) - pps->ppscap |= PPS_OFFSETASSERT; - if (pps->ppscap & PPS_CAPTURECLEAR) - pps->ppscap |= PPS_OFFSETCLEAR; -} - -void -pps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int event) -{ - struct timespec ts, *tsp, *osp; - u_int64_t delta; - unsigned tcount, *pcount; - int foff, fhard; - pps_seq_t *pseq; - - /* Things would be easier with arrays... */ - if (event == PPS_CAPTUREASSERT) { - tsp = &pps->ppsinfo.assert_timestamp; - osp = &pps->ppsparam.assert_offset; - foff = pps->ppsparam.mode & PPS_OFFSETASSERT; - fhard = pps->kcmode & PPS_CAPTUREASSERT; - pcount = &pps->ppscount[0]; - pseq = &pps->ppsinfo.assert_sequence; - } else { - tsp = &pps->ppsinfo.clear_timestamp; - osp = &pps->ppsparam.clear_offset; - foff = pps->ppsparam.mode & PPS_OFFSETCLEAR; - fhard = pps->kcmode & PPS_CAPTURECLEAR; - pcount = &pps->ppscount[1]; - pseq = &pps->ppsinfo.clear_sequence; - } - - /* The timecounter changed: bail */ - if (!pps->ppstc || - pps->ppstc->tc_name != tc->tc_name || - tc->tc_name != timecounter->tc_name) { - pps->ppstc = tc; - *pcount = count; - return; - } - - /* Nothing really happened */ - if (*pcount == count) - return; - - *pcount = count; - - /* Convert the count to timespec */ - ts.tv_sec = tc->tc_offset_sec; - tcount = count - tc->tc_offset_count; - tcount &= tc->tc_counter_mask; - delta = tc->tc_offset_nano; - delta += ((u_int64_t)tcount * tc->tc_scale_nano_f); - delta >>= 32; - delta += ((u_int64_t)tcount * tc->tc_scale_nano_i); - delta += boottime.tv_usec * 1000; - ts.tv_sec += boottime.tv_sec; - while (delta >= 1000000000) { - delta -= 1000000000; - ts.tv_sec++; - } - ts.tv_nsec = delta; - - (*pseq)++; - *tsp = ts; - - if (foff) { - timespecadd(tsp, osp); - if (tsp->tv_nsec < 0) { - tsp->tv_nsec += 1000000000; - tsp->tv_sec -= 1; - } - } -#ifdef PPS_SYNC - if (fhard) { - /* magic, at its best... */ - tcount = count - pps->ppscount[2]; - pps->ppscount[2] = count; - tcount &= tc->tc_counter_mask; - delta = ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_f); - delta >>= 32; - delta += ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_i); - hardpps(tsp, delta); - } -#endif -} diff --git a/sys/kern/ksched.c b/sys/kern/ksched.c deleted file mode 100644 index 8f297b21ecab..000000000000 --- a/sys/kern/ksched.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 1996, 1997 - * HD Associates, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by HD Associates, Inc - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* ksched: Soft real time scheduling based on "rtprio". - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/kernel.h> -#include <sys/resource.h> -#include <machine/cpu.h> /* For need_resched */ - -#include <posix4/posix4.h> - -/* ksched: Real-time extension to support POSIX priority scheduling. - */ - -struct ksched { - struct timespec rr_interval; -}; - -int ksched_attach(struct ksched **p) -{ - struct ksched *ksched= p31b_malloc(sizeof(*ksched)); - - ksched->rr_interval.tv_sec = 0; - ksched->rr_interval.tv_nsec = 1000000000L / roundrobin_interval(); - - *p = ksched; - return 0; -} - -int ksched_detach(struct ksched *p) -{ - p31b_free(p); - - return 0; -} - -/* - * XXX About priorities - * - * POSIX 1003.1b requires that numerically higher priorities be of - * higher priority. It also permits sched_setparam to be - * implementation defined for SCHED_OTHER. I don't like - * the notion of inverted priorites for normal processes when - * you can use "setpriority" for that. - * - * I'm rejecting sched_setparam for SCHED_OTHER with EINVAL. - */ - -/* Macros to convert between the unix (lower numerically is higher priority) - * and POSIX 1003.1b (higher numerically is higher priority) - */ - -#define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P)) -#define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P)) - -/* These improve readability a bit for me: - */ -#define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX) -#define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN) - -static __inline int -getscheduler(register_t *ret, struct ksched *ksched, struct proc *p) -{ - int e = 0; - - switch (p->p_rtprio.type) - { - case RTP_PRIO_FIFO: - *ret = SCHED_FIFO; - break; - - case RTP_PRIO_REALTIME: - *ret = SCHED_RR; - break; - - default: - *ret = SCHED_OTHER; - break; - } - - return e; -} - -int ksched_setparam(register_t *ret, struct ksched *ksched, - struct proc *p, const struct sched_param *param) -{ - register_t policy; - int e; - - e = getscheduler(&policy, ksched, p); - - if (e == 0) - { - if (policy == SCHED_OTHER) - e = EINVAL; - else - e = ksched_setscheduler(ret, ksched, p, policy, param); - } - - return e; -} - -int ksched_getparam(register_t *ret, struct ksched *ksched, - struct proc *p, struct sched_param *param) -{ - if (RTP_PRIO_IS_REALTIME(p->p_rtprio.type)) - param->sched_priority = rtpprio_to_p4prio(p->p_rtprio.prio); - - return 0; -} - -/* - * XXX The priority and scheduler modifications should - * be moved into published interfaces in kern/kern_sync. - * - * The permissions to modify process p were checked in "p31b_proc()". - * - */ -int ksched_setscheduler(register_t *ret, struct ksched *ksched, - struct proc *p, int policy, const struct sched_param *param) -{ - int e = 0; - struct rtprio rtp; - - switch(policy) - { - case SCHED_RR: - case SCHED_FIFO: - - if (param->sched_priority >= P1B_PRIO_MIN && - param->sched_priority <= P1B_PRIO_MAX) - { - rtp.prio = p4prio_to_rtpprio(param->sched_priority); - rtp.type = (policy == SCHED_FIFO) - ? RTP_PRIO_FIFO : RTP_PRIO_REALTIME; - - p->p_rtprio = rtp; - need_resched(); - } - else - e = EPERM; - - - break; - - case SCHED_OTHER: - { - rtp.type = RTP_PRIO_NORMAL; - rtp.prio = p4prio_to_rtpprio(param->sched_priority); - p->p_rtprio = rtp; - - /* XXX Simply revert to whatever we had for last - * normal scheduler priorities. - * This puts a requirement - * on the scheduling code: You must leave the - * scheduling info alone. - */ - need_resched(); - } - break; - } - - return e; -} - -int ksched_getscheduler(register_t *ret, struct ksched *ksched, struct proc *p) -{ - return getscheduler(ret, ksched, p); -} - -/* ksched_yield: Yield the CPU. - */ -int ksched_yield(register_t *ret, struct ksched *ksched) -{ - need_resched(); - return 0; -} - -int ksched_get_priority_max(register_t*ret, struct ksched *ksched, int policy) -{ - int e = 0; - - switch (policy) - { - case SCHED_FIFO: - case SCHED_RR: - *ret = RTP_PRIO_MAX; - break; - - case SCHED_OTHER: - *ret = PRIO_MAX; - break; - - default: - e = EINVAL; - } - - return e; -} - -int ksched_get_priority_min(register_t *ret, struct ksched *ksched, int policy) -{ - int e = 0; - - switch (policy) - { - case SCHED_FIFO: - case SCHED_RR: - *ret = P1B_PRIO_MIN; - break; - - case SCHED_OTHER: - *ret = PRIO_MIN; - break; - - default: - e = EINVAL; - } - - return e; -} - -int ksched_rr_get_interval(register_t *ret, struct ksched *ksched, - struct proc *p, struct timespec *timespec) -{ - *timespec = ksched->rr_interval; - - return 0; -} diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c deleted file mode 100644 index daf3b3072702..000000000000 --- a/sys/kern/link_elf_obj.c +++ /dev/null @@ -1,985 +0,0 @@ -/*- - * Copyright (c) 1998 Doug Rabson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/proc.h> -#include <sys/namei.h> -#include <sys/fcntl.h> -#include <sys/vnode.h> -#include <sys/linker.h> -#include <machine/elf.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_zone.h> -#include <sys/lock.h> -#ifdef SPARSE_MAPPING -#include <vm/vm_object.h> -#include <vm/vm_kern.h> -#include <vm/vm_extern.h> -#endif -#include <vm/pmap.h> -#include <vm/vm_map.h> - -static int link_elf_load_module(const char*, linker_file_t*); -static int link_elf_load_file(const char*, linker_file_t*); -static int link_elf_lookup_symbol(linker_file_t, const char*, - c_linker_sym_t*); -static int link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*); -static int link_elf_search_symbol(linker_file_t, caddr_t value, - c_linker_sym_t* sym, long* diffp); - -static void link_elf_unload_file(linker_file_t); -static void link_elf_unload_module(linker_file_t); - -static struct linker_class_ops link_elf_class_ops = { - link_elf_load_module, -}; - -static struct linker_file_ops link_elf_file_ops = { - link_elf_lookup_symbol, - link_elf_symbol_values, - link_elf_search_symbol, - link_elf_unload_file, -}; - -static struct linker_file_ops link_elf_module_ops = { - link_elf_lookup_symbol, - link_elf_symbol_values, - link_elf_search_symbol, - link_elf_unload_module, -}; -typedef struct elf_file { - caddr_t address; /* Relocation address */ -#ifdef SPARSE_MAPPING - vm_object_t object; /* VM object to hold file pages */ -#endif - const Elf_Dyn* dynamic; /* Symbol table etc. */ - Elf_Off nbuckets; /* DT_HASH info */ - Elf_Off nchains; - const Elf_Off* buckets; - const Elf_Off* chains; - caddr_t hash; - caddr_t strtab; /* DT_STRTAB */ - int strsz; /* DT_STRSZ */ - const Elf_Sym* symtab; /* DT_SYMTAB */ - Elf_Addr* got; /* DT_PLTGOT */ - const Elf_Rel* pltrel; /* DT_JMPREL */ - int pltrelsize; /* DT_PLTRELSZ */ - const Elf_Rela* pltrela; /* DT_JMPREL */ - int pltrelasize; /* DT_PLTRELSZ */ - const Elf_Rel* rel; /* DT_REL */ - int relsize; /* DT_RELSZ */ - const Elf_Rela* rela; /* DT_RELA */ - int relasize; /* DT_RELASZ */ - caddr_t modptr; - const Elf_Sym* ddbsymtab; /* The symbol table we are using */ - long ddbsymcnt; /* Number of symbols */ - caddr_t ddbstrtab; /* String table */ - long ddbstrcnt; /* number of bytes in string table */ - caddr_t symbase; /* malloc'ed symbold base */ - caddr_t strbase; /* malloc'ed string base */ -} *elf_file_t; - -static int parse_dynamic(linker_file_t lf); -static int load_dependancies(linker_file_t lf); -static int relocate_file(linker_file_t lf); -static int parse_module_symbols(linker_file_t lf); - -/* - * The kernel symbol table starts here. - */ -extern struct _dynamic _DYNAMIC; - -static void -link_elf_init(void* arg) -{ -#ifdef __ELF__ - Elf_Dyn *dp; - caddr_t modptr, baseptr, sizeptr; - elf_file_t ef; - char *modname; -#endif - -#if ELF_TARG_CLASS == ELFCLASS32 - linker_add_class("elf32", NULL, &link_elf_class_ops); -#else - linker_add_class("elf64", NULL, &link_elf_class_ops); -#endif - -#ifdef __ELF__ - dp = (Elf_Dyn*) &_DYNAMIC; - if (dp) { - ef = malloc(sizeof(struct elf_file), M_LINKER, M_NOWAIT); - if (ef == NULL) - panic("link_elf_init: Can't create linker structures for kernel"); - bzero(ef, sizeof(*ef)); - - ef->address = 0; -#ifdef SPARSE_MAPPING - ef->object = 0; -#endif - ef->dynamic = dp; - modname = NULL; - modptr = preload_search_by_type("elf kernel"); - if (modptr) - modname = (char *)preload_search_info(modptr, MODINFO_NAME); - if (modname == NULL) - modname = "kernel"; - linker_kernel_file = linker_make_file(modname, ef, &link_elf_file_ops); - if (linker_kernel_file == NULL) - panic("link_elf_init: Can't create linker structures for kernel"); - parse_dynamic(linker_kernel_file); - linker_kernel_file->address = (caddr_t) KERNBASE; - linker_kernel_file->size = -(intptr_t)linker_kernel_file->address; - - if (modptr) { - ef->modptr = modptr; - baseptr = preload_search_info(modptr, MODINFO_ADDR); - if (baseptr) - linker_kernel_file->address = *(caddr_t *)baseptr; - sizeptr = preload_search_info(modptr, MODINFO_SIZE); - if (sizeptr) - linker_kernel_file->size = *(size_t *)sizeptr; - } - (void)parse_module_symbols(linker_kernel_file); - linker_current_file = linker_kernel_file; - linker_kernel_file->flags |= LINKER_FILE_LINKED; - } -#endif -} - -SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); - -static int -parse_module_symbols(linker_file_t lf) -{ - elf_file_t ef = lf->priv; - caddr_t pointer; - caddr_t ssym, esym, base; - caddr_t strtab; - int strcnt; - Elf_Sym* symtab; - int symcnt; - - if (ef->modptr == NULL) - return 0; - pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM); - if (pointer == NULL) - return 0; - ssym = *(caddr_t *)pointer; - pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_ESYM); - if (pointer == NULL) - return 0; - esym = *(caddr_t *)pointer; - - base = ssym; - - symcnt = *(long *)base; - base += sizeof(long); - symtab = (Elf_Sym *)base; - base += roundup(symcnt, sizeof(long)); - - if (base > esym || base < ssym) { - printf("Symbols are corrupt!\n"); - return EINVAL; - } - - strcnt = *(long *)base; - base += sizeof(long); - strtab = base; - base += roundup(strcnt, sizeof(long)); - - if (base > esym || base < ssym) { - printf("Symbols are corrupt!\n"); - return EINVAL; - } - - ef->ddbsymtab = symtab; - ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); - ef->ddbstrtab = strtab; - ef->ddbstrcnt = strcnt; - - return 0; -} - -static int -parse_dynamic(linker_file_t lf) -{ - elf_file_t ef = lf->priv; - const Elf_Dyn *dp; - int plttype = DT_REL; - - for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { - switch (dp->d_tag) { - case DT_HASH: - { - /* From src/libexec/rtld-elf/rtld.c */ - const Elf_Off *hashtab = (const Elf_Off *) - (ef->address + dp->d_un.d_ptr); - ef->nbuckets = hashtab[0]; - ef->nchains = hashtab[1]; - ef->buckets = hashtab + 2; - ef->chains = ef->buckets + ef->nbuckets; - break; - } - case DT_STRTAB: - ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr); - break; - case DT_STRSZ: - ef->strsz = dp->d_un.d_val; - break; - case DT_SYMTAB: - ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr); - break; - case DT_SYMENT: - if (dp->d_un.d_val != sizeof(Elf_Sym)) - return ENOEXEC; - break; - case DT_PLTGOT: - ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr); - break; - case DT_REL: - ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); - break; - case DT_RELSZ: - ef->relsize = dp->d_un.d_val; - break; - case DT_RELENT: - if (dp->d_un.d_val != sizeof(Elf_Rel)) - return ENOEXEC; - break; - case DT_JMPREL: - ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr); - break; - case DT_PLTRELSZ: - ef->pltrelsize = dp->d_un.d_val; - break; - case DT_RELA: - ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr); - break; - case DT_RELASZ: - ef->relasize = dp->d_un.d_val; - break; - case DT_RELAENT: - if (dp->d_un.d_val != sizeof(Elf_Rela)) - return ENOEXEC; - break; - case DT_PLTREL: - plttype = dp->d_un.d_val; - if (plttype != DT_REL && plttype != DT_RELA) - return ENOEXEC; - break; - } - } - - if (plttype == DT_RELA) { - ef->pltrela = (const Elf_Rela *) ef->pltrel; - ef->pltrel = NULL; - ef->pltrelasize = ef->pltrelsize; - ef->pltrelsize = 0; - } - - ef->ddbsymtab = ef->symtab; - ef->ddbsymcnt = ef->nchains; - ef->ddbstrtab = ef->strtab; - ef->ddbstrcnt = ef->strsz; - - return 0; -} - -static void -link_elf_error(const char *s) -{ - printf("kldload: %s\n", s); -} - -static int -link_elf_load_module(const char *filename, linker_file_t *result) -{ - caddr_t modptr, baseptr, sizeptr, dynptr; - char *type; - elf_file_t ef; - linker_file_t lf; - int error; - vm_offset_t dp; - - /* Look to see if we have the module preloaded */ - modptr = preload_search_by_name(filename); - if (modptr == NULL) - return (link_elf_load_file(filename, result)); - - /* It's preloaded, check we can handle it and collect information */ - type = (char *)preload_search_info(modptr, MODINFO_TYPE); - baseptr = preload_search_info(modptr, MODINFO_ADDR); - sizeptr = preload_search_info(modptr, MODINFO_SIZE); - dynptr = preload_search_info(modptr, MODINFO_METADATA|MODINFOMD_DYNAMIC); - if (type == NULL || strcmp(type, "elf module") != 0) - return (EFTYPE); - if (baseptr == NULL || sizeptr == NULL || dynptr == NULL) - return (EINVAL); - - ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK); - if (ef == NULL) - return (ENOMEM); - bzero(ef, sizeof(*ef)); - ef->modptr = modptr; - ef->address = *(caddr_t *)baseptr; -#ifdef SPARSE_MAPPING - ef->object = 0; -#endif - dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; - ef->dynamic = (Elf_Dyn *)dp; - lf = linker_make_file(filename, ef, &link_elf_module_ops); - if (lf == NULL) { - free(ef, M_LINKER); - return ENOMEM; - } - lf->address = ef->address; - lf->size = *(size_t *)sizeptr; - - error = parse_dynamic(lf); - if (error) { - linker_file_unload(lf); - return error; - } - error = load_dependancies(lf); - if (error) { - linker_file_unload(lf); - return error; - } - error = relocate_file(lf); - if (error) { - linker_file_unload(lf); - return error; - } - (void)parse_module_symbols(lf); - lf->flags |= LINKER_FILE_LINKED; - *result = lf; - return (0); -} - -static int -link_elf_load_file(const char* filename, linker_file_t* result) -{ - struct nameidata nd; - struct proc* p = curproc; /* XXX */ - Elf_Ehdr *hdr; - caddr_t firstpage; - int nbytes, i; - Elf_Phdr *phdr; - Elf_Phdr *phlimit; - Elf_Phdr *segs[2]; - int nsegs; - Elf_Phdr *phdyn; - Elf_Phdr *phphdr; - caddr_t mapbase; - size_t mapsize; - Elf_Off base_offset; - Elf_Addr base_vaddr; - Elf_Addr base_vlimit; - int error = 0; - int resid; - elf_file_t ef; - linker_file_t lf; - char *pathname; - Elf_Shdr *shdr; - int symtabindex; - int symstrindex; - int symcnt; - int strcnt; - - shdr = NULL; - lf = NULL; - - pathname = linker_search_path(filename); - if (pathname == NULL) - return ENOENT; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, pathname, p); - error = vn_open(&nd, FREAD, 0); - free(pathname, M_LINKER); - if (error) - return error; - NDFREE(&nd, NDF_ONLY_PNBUF); - - /* - * Read the elf header from the file. - */ - firstpage = malloc(PAGE_SIZE, M_LINKER, M_WAITOK); - if (firstpage == NULL) { - error = ENOMEM; - goto out; - } - hdr = (Elf_Ehdr *)firstpage; - error = vn_rdwr(UIO_READ, nd.ni_vp, firstpage, PAGE_SIZE, 0, - UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); - nbytes = PAGE_SIZE - resid; - if (error) - goto out; - - if (!IS_ELF(*hdr)) { - error = ENOEXEC; - goto out; - } - - if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS - || hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { - link_elf_error("Unsupported file layout"); - error = ENOEXEC; - goto out; - } - if (hdr->e_ident[EI_VERSION] != EV_CURRENT - || hdr->e_version != EV_CURRENT) { - link_elf_error("Unsupported file version"); - error = ENOEXEC; - goto out; - } - if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) { - link_elf_error("Unsupported file type"); - error = ENOEXEC; - goto out; - } - if (hdr->e_machine != ELF_TARG_MACH) { - link_elf_error("Unsupported machine"); - error = ENOEXEC; - goto out; - } - - /* - * We rely on the program header being in the first page. This is - * not strictly required by the ABI specification, but it seems to - * always true in practice. And, it simplifies things considerably. - */ - if (!((hdr->e_phentsize == sizeof(Elf_Phdr)) && - (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= PAGE_SIZE) && - (hdr->e_phoff + hdr->e_phnum*sizeof(Elf_Phdr) <= nbytes))) - link_elf_error("Unreadable program headers"); - - /* - * Scan the program header entries, and save key information. - * - * We rely on there being exactly two load segments, text and data, - * in that order. - */ - phdr = (Elf_Phdr *) (firstpage + hdr->e_phoff); - phlimit = phdr + hdr->e_phnum; - nsegs = 0; - phdyn = NULL; - phphdr = NULL; - while (phdr < phlimit) { - switch (phdr->p_type) { - - case PT_LOAD: - if (nsegs == 2) { - link_elf_error("Too many sections"); - error = ENOEXEC; - goto out; - } - segs[nsegs] = phdr; - ++nsegs; - break; - - case PT_PHDR: - phphdr = phdr; - break; - - case PT_DYNAMIC: - phdyn = phdr; - break; - } - - ++phdr; - } - if (phdyn == NULL) { - link_elf_error("Object is not dynamically-linked"); - error = ENOEXEC; - goto out; - } - - /* - * Allocate the entire address space of the object, to stake out our - * contiguous region, and to establish the base address for relocation. - */ - base_offset = trunc_page(segs[0]->p_offset); - base_vaddr = trunc_page(segs[0]->p_vaddr); - base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz); - mapsize = base_vlimit - base_vaddr; - - ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK); - bzero(ef, sizeof(*ef)); -#ifdef SPARSE_MAPPING - ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT); - if (ef->object == NULL) { - free(ef, M_LINKER); - error = ENOMEM; - goto out; - } - vm_object_reference(ef->object); - ef->address = (caddr_t) vm_map_min(kernel_map); - error = vm_map_find(kernel_map, ef->object, 0, - (vm_offset_t *) &ef->address, - mapsize, 1, - VM_PROT_ALL, VM_PROT_ALL, 0); - if (error) { - vm_object_deallocate(ef->object); - free(ef, M_LINKER); - goto out; - } -#else - ef->address = malloc(mapsize, M_LINKER, M_WAITOK); -#endif - mapbase = ef->address; - - /* - * Read the text and data sections and zero the bss. - */ - for (i = 0; i < 2; i++) { - caddr_t segbase = mapbase + segs[i]->p_vaddr - base_vaddr; - error = vn_rdwr(UIO_READ, nd.ni_vp, - segbase, segs[i]->p_filesz, segs[i]->p_offset, - UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); - if (error) { -#ifdef SPARSE_MAPPING - vm_map_remove(kernel_map, (vm_offset_t) ef->address, - (vm_offset_t) ef->address - + (ef->object->size << PAGE_SHIFT)); - vm_object_deallocate(ef->object); -#else - free(ef->address, M_LINKER); -#endif - free(ef, M_LINKER); - goto out; - } - bzero(segbase + segs[i]->p_filesz, - segs[i]->p_memsz - segs[i]->p_filesz); - -#ifdef SPARSE_MAPPING - /* - * Wire down the pages - */ - vm_map_pageable(kernel_map, - (vm_offset_t) segbase, - (vm_offset_t) segbase + segs[i]->p_memsz, - FALSE); -#endif - } - - ef->dynamic = (const Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr); - - lf = linker_make_file(filename, ef, &link_elf_file_ops); - if (lf == NULL) { -#ifdef SPARSE_MAPPING - vm_map_remove(kernel_map, (vm_offset_t) ef->address, - (vm_offset_t) ef->address - + (ef->object->size << PAGE_SHIFT)); - vm_object_deallocate(ef->object); -#else - free(ef->address, M_LINKER); -#endif - free(ef, M_LINKER); - error = ENOMEM; - goto out; - } - lf->address = ef->address; - lf->size = mapsize; - - error = parse_dynamic(lf); - if (error) - goto out; - error = load_dependancies(lf); - if (error) - goto out; - error = relocate_file(lf); - if (error) - goto out; - - /* Try and load the symbol table if it's present. (you can strip it!) */ - nbytes = hdr->e_shnum * hdr->e_shentsize; - if (nbytes == 0 || hdr->e_shoff == 0) - goto nosyms; - shdr = malloc(nbytes, M_LINKER, M_WAITOK); - if (shdr == NULL) { - error = ENOMEM; - goto out; - } - bzero(shdr, nbytes); - error = vn_rdwr(UIO_READ, nd.ni_vp, - (caddr_t)shdr, nbytes, hdr->e_shoff, - UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); - if (error) - goto out; - symtabindex = -1; - symstrindex = -1; - for (i = 0; i < hdr->e_shnum; i++) { - if (shdr[i].sh_type == SHT_SYMTAB) { - symtabindex = i; - symstrindex = shdr[i].sh_link; - } - } - if (symtabindex < 0 || symstrindex < 0) - goto nosyms; - - symcnt = shdr[symtabindex].sh_size; - ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK); - strcnt = shdr[symstrindex].sh_size; - ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK); - - if (ef->symbase == NULL || ef->strbase == NULL) { - error = ENOMEM; - goto out; - } - error = vn_rdwr(UIO_READ, nd.ni_vp, - ef->symbase, symcnt, shdr[symtabindex].sh_offset, - UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); - if (error) - goto out; - error = vn_rdwr(UIO_READ, nd.ni_vp, - ef->strbase, strcnt, shdr[symstrindex].sh_offset, - UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); - if (error) - goto out; - - ef->ddbsymcnt = symcnt / sizeof(Elf_Sym); - ef->ddbsymtab = (const Elf_Sym *)ef->symbase; - ef->ddbstrcnt = strcnt; - ef->ddbstrtab = ef->strbase; - - lf->flags |= LINKER_FILE_LINKED; - -nosyms: - - *result = lf; - -out: - if (error && lf) - linker_file_unload(lf); - if (shdr) - free(shdr, M_LINKER); - if (firstpage) - free(firstpage, M_LINKER); - VOP_UNLOCK(nd.ni_vp, 0, p); - vn_close(nd.ni_vp, FREAD, p->p_ucred, p); - - return error; -} - -static void -link_elf_unload_file(linker_file_t file) -{ - elf_file_t ef = file->priv; - - if (ef) { -#ifdef SPARSE_MAPPING - if (ef->object) { - vm_map_remove(kernel_map, (vm_offset_t) ef->address, - (vm_offset_t) ef->address - + (ef->object->size << PAGE_SHIFT)); - vm_object_deallocate(ef->object); - } -#else - if (ef->address) - free(ef->address, M_LINKER); -#endif - if (ef->symbase) - free(ef->symbase, M_LINKER); - if (ef->strbase) - free(ef->strbase, M_LINKER); - free(ef, M_LINKER); - } -} - -static void -link_elf_unload_module(linker_file_t file) -{ - elf_file_t ef = file->priv; - - if (ef) - free(ef, M_LINKER); - if (file->filename) - preload_delete_name(file->filename); -} - -static int -load_dependancies(linker_file_t lf) -{ - elf_file_t ef = lf->priv; - linker_file_t lfdep; - char* name; - const Elf_Dyn *dp; - int error = 0; - - /* - * All files are dependant on /kernel. - */ - if (linker_kernel_file) { - linker_kernel_file->refs++; - linker_file_add_dependancy(lf, linker_kernel_file); - } - - for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { - if (dp->d_tag == DT_NEEDED) { - name = ef->strtab + dp->d_un.d_val; - - error = linker_load_file(name, &lfdep); - if (error) - goto out; - error = linker_file_add_dependancy(lf, lfdep); - if (error) - goto out; - } - } - -out: - return error; -} - -static const char * -symbol_name(elf_file_t ef, Elf_Word r_info) -{ - const Elf_Sym *ref; - - if (ELF_R_SYM(r_info)) { - ref = ef->symtab + ELF_R_SYM(r_info); - return ef->strtab + ref->st_name; - } else - return NULL; -} - -static int -relocate_file(linker_file_t lf) -{ - elf_file_t ef = lf->priv; - const Elf_Rel *rellim; - const Elf_Rel *rel; - const Elf_Rela *relalim; - const Elf_Rela *rela; - const char *symname; - - /* Perform relocations without addend if there are any: */ - rel = ef->rel; - if (rel) { - rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize); - while (rel < rellim) { - symname = symbol_name(ef, rel->r_info); - if (elf_reloc(lf, rel, ELF_RELOC_REL, symname)) { - printf("link_elf: symbol %s undefined\n", symname); - return ENOENT; - } - rel++; - } - } - - /* Perform relocations with addend if there are any: */ - rela = ef->rela; - if (rela) { - relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize); - while (rela < relalim) { - symname = symbol_name(ef, rela->r_info); - if (elf_reloc(lf, rela, ELF_RELOC_RELA, symname)) { - printf("link_elf: symbol %s undefined\n", symname); - return ENOENT; - } - rela++; - } - } - - /* Perform PLT relocations without addend if there are any: */ - rel = ef->pltrel; - if (rel) { - rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize); - while (rel < rellim) { - symname = symbol_name(ef, rel->r_info); - if (elf_reloc(lf, rel, ELF_RELOC_REL, symname)) { - printf("link_elf: symbol %s undefined\n", symname); - return ENOENT; - } - rel++; - } - } - - /* Perform relocations with addend if there are any: */ - rela = ef->pltrela; - if (rela) { - relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize); - while (rela < relalim) { - symname = symbol_name(ef, rela->r_info); - if (elf_reloc(lf, rela, ELF_RELOC_RELA, symname)) { - printf("link_elf: symbol %s undefined\n", symname); - return ENOENT; - } - rela++; - } - } - - return 0; -} - -/* - * Hash function for symbol table lookup. Don't even think about changing - * this. It is specified by the System V ABI. - */ -static unsigned long -elf_hash(const char *name) -{ - const unsigned char *p = (const unsigned char *) name; - unsigned long h = 0; - unsigned long g; - - while (*p != '\0') { - h = (h << 4) + *p++; - if ((g = h & 0xf0000000) != 0) - h ^= g >> 24; - h &= ~g; - } - return h; -} - -int -link_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym) -{ - elf_file_t ef = lf->priv; - unsigned long symnum; - const Elf_Sym* symp; - const char *strp; - unsigned long hash; - int i; - - /* First, search hashed global symbols */ - hash = elf_hash(name); - symnum = ef->buckets[hash % ef->nbuckets]; - - while (symnum != STN_UNDEF) { - if (symnum >= ef->nchains) { - printf("link_elf_lookup_symbol: corrupt symbol table\n"); - return ENOENT; - } - - symp = ef->symtab + symnum; - if (symp->st_name == 0) { - printf("link_elf_lookup_symbol: corrupt symbol table\n"); - return ENOENT; - } - - strp = ef->strtab + symp->st_name; - - if (strcmp(name, strp) == 0) { - if (symp->st_shndx != SHN_UNDEF || - (symp->st_value != 0 && - ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { - *sym = (c_linker_sym_t) symp; - return 0; - } else - return ENOENT; - } - - symnum = ef->chains[symnum]; - } - - /* If we have not found it, look at the full table (if loaded) */ - if (ef->symtab == ef->ddbsymtab) - return ENOENT; - - /* Exhaustive search */ - for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { - strp = ef->ddbstrtab + symp->st_name; - if (strcmp(name, strp) == 0) { - if (symp->st_shndx != SHN_UNDEF || - (symp->st_value != 0 && - ELF_ST_TYPE(symp->st_info) == STT_FUNC)) { - *sym = (c_linker_sym_t) symp; - return 0; - } else - return ENOENT; - } - } - - return ENOENT; -} - -static int -link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, linker_symval_t* symval) -{ - elf_file_t ef = lf->priv; - const Elf_Sym* es = (const Elf_Sym*) sym; - - if (es >= ef->symtab && ((es - ef->symtab) < ef->nchains)) { - symval->name = ef->strtab + es->st_name; - symval->value = (caddr_t) ef->address + es->st_value; - symval->size = es->st_size; - return 0; - } - if (ef->symtab == ef->ddbsymtab) - return ENOENT; - if (es >= ef->ddbsymtab && ((es - ef->ddbsymtab) < ef->ddbsymcnt)) { - symval->name = ef->ddbstrtab + es->st_name; - symval->value = (caddr_t) ef->address + es->st_value; - symval->size = es->st_size; - return 0; - } - return ENOENT; -} - -static int -link_elf_search_symbol(linker_file_t lf, caddr_t value, - c_linker_sym_t* sym, long* diffp) -{ - elf_file_t ef = lf->priv; - u_long off = (uintptr_t) (void *) value; - u_long diff = off; - u_long st_value; - const Elf_Sym* es; - const Elf_Sym* best = 0; - int i; - - for (i = 0, es = ef->ddbsymtab; i < ef->ddbsymcnt; i++, es++) { - if (es->st_name == 0) - continue; - st_value = es->st_value + (uintptr_t) (void *) ef->address; - if (off >= st_value) { - if (off - st_value < diff) { - diff = off - st_value; - best = es; - if (diff == 0) - break; - } else if (off - st_value == diff) { - best = es; - } - } - } - if (best == 0) - *diffp = off; - else - *diffp = diff; - *sym = (c_linker_sym_t) best; - - return 0; -} diff --git a/sys/kern/p1003_1b.c b/sys/kern/p1003_1b.c deleted file mode 100644 index 36f4bc24153d..000000000000 --- a/sys/kern/p1003_1b.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) 1996, 1997, 1998 - * HD Associates, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by HD Associates, Inc - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -/* p1003_1b: Real Time common code. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/sysent.h> -#include <sys/proc.h> -#include <sys/syslog.h> -#include <sys/module.h> -#include <sys/sysproto.h> -#include <sys/sysctl.h> - -#include <posix4/posix4.h> - -MALLOC_DEFINE(M_P31B, "p1003.1b", "Posix 1003.1B"); - -/* p31b_proc: Return a proc struct corresponding to a pid to operate on. - * - * Enforce permission policy. - * - * The policy is the same as for sending signals except there - * is no notion of process groups. - * - * pid == 0 means my process. - * - * This is disabled until I've got a permission gate in again: - * only root can do this. - */ - -#if 0 -/* - * This is stolen from CANSIGNAL in kern_sig: - * - * Can process p, with pcred pc, do "write flavor" operations to process q? - */ -#define CAN_AFFECT(p, pc, q) \ - ((pc)->pc_ucred->cr_uid == 0 || \ - (pc)->p_ruid == (q)->p_cred->p_ruid || \ - (pc)->pc_ucred->cr_uid == (q)->p_cred->p_ruid || \ - (pc)->p_ruid == (q)->p_ucred->cr_uid || \ - (pc)->pc_ucred->cr_uid == (q)->p_ucred->cr_uid) -#else -#define CAN_AFFECT(p, pc, q) ((pc)->pc_ucred->cr_uid == 0) -#endif - -/* - * p31b_proc: Look up a proc from a PID. If proc is 0 it is - * my own proc. - */ -int p31b_proc(struct proc *p, pid_t pid, struct proc **pp) -{ - int ret = 0; - struct proc *other_proc = 0; - - if (pid == 0) - other_proc = p; - else - other_proc = pfind(pid); - - if (other_proc) - { - /* Enforce permission policy. - */ - if (CAN_AFFECT(p, p->p_cred, other_proc)) - *pp = other_proc; - else - ret = EPERM; - } - else - ret = ESRCH; - - return ret; -} - -/* The system calls return ENOSYS if an entry is called that is - * not run-time supported. I am also logging since some programs - * start to use this when they shouldn't. That will be removed if annoying. - */ -int -syscall_not_present(struct proc *p, const char *s, struct nosys_args *uap) -{ - log(LOG_ERR, "cmd %s pid %d tried to use non-present %s\n", - p->p_comm, p->p_pid, s); - - /* a " return nosys(p, uap); " here causes a core dump. - */ - - return ENOSYS; -} - -#if !defined(_KPOSIX_PRIORITY_SCHEDULING) - -/* Not configured but loadable via a module: - */ - -static int sched_attach(void) -{ - return 0; -} - -SYSCALL_NOT_PRESENT_GEN(sched_setparam) -SYSCALL_NOT_PRESENT_GEN(sched_getparam) -SYSCALL_NOT_PRESENT_GEN(sched_setscheduler) -SYSCALL_NOT_PRESENT_GEN(sched_getscheduler) -SYSCALL_NOT_PRESENT_GEN(sched_yield) -SYSCALL_NOT_PRESENT_GEN(sched_get_priority_max) -SYSCALL_NOT_PRESENT_GEN(sched_get_priority_min) -SYSCALL_NOT_PRESENT_GEN(sched_rr_get_interval) - -#else - -/* Configured in kernel version: - */ -static struct ksched *ksched; - -static int sched_attach(void) -{ - int ret = ksched_attach(&ksched); - - if (ret == 0) - p31b_setcfg(CTL_P1003_1B_PRIORITY_SCHEDULING, 1); - - return ret; -} - -int sched_setparam(struct proc *p, - struct sched_setparam_args *uap) -{ - int e; - - struct sched_param sched_param; - copyin(uap->param, &sched_param, sizeof(sched_param)); - - (void) (0 - || (e = p31b_proc(p, uap->pid, &p)) - || (e = ksched_setparam(&p->p_retval[0], ksched, p, - (const struct sched_param *)&sched_param)) - ); - - return e; -} - -int sched_getparam(struct proc *p, - struct sched_getparam_args *uap) -{ - int e; - struct sched_param sched_param; - - (void) (0 - || (e = p31b_proc(p, uap->pid, &p)) - || (e = ksched_getparam(&p->p_retval[0], ksched, p, &sched_param)) - ); - - if (!e) - copyout(&sched_param, uap->param, sizeof(sched_param)); - - return e; -} -int sched_setscheduler(struct proc *p, - struct sched_setscheduler_args *uap) -{ - int e; - - struct sched_param sched_param; - copyin(uap->param, &sched_param, sizeof(sched_param)); - - (void) (0 - || (e = p31b_proc(p, uap->pid, &p)) - || (e = ksched_setscheduler(&p->p_retval[0], - ksched, p, uap->policy, - (const struct sched_param *)&sched_param)) - ); - - return e; -} -int sched_getscheduler(struct proc *p, - struct sched_getscheduler_args *uap) -{ - int e; - (void) (0 - || (e = p31b_proc(p, uap->pid, &p)) - || (e = ksched_getscheduler(&p->p_retval[0], ksched, p)) - ); - - return e; -} -int sched_yield(struct proc *p, - struct sched_yield_args *uap) -{ - return ksched_yield(&p->p_retval[0], ksched); -} -int sched_get_priority_max(struct proc *p, - struct sched_get_priority_max_args *uap) -{ - return ksched_get_priority_max(&p->p_retval[0], - ksched, uap->policy); -} -int sched_get_priority_min(struct proc *p, - struct sched_get_priority_min_args *uap) -{ - return ksched_get_priority_min(&p->p_retval[0], - ksched, uap->policy); -} -int sched_rr_get_interval(struct proc *p, - struct sched_rr_get_interval_args *uap) -{ - int e; - - (void) (0 - || (e = p31b_proc(p, uap->pid, &p)) - || (e = ksched_rr_get_interval(&p->p_retval[0], ksched, - p, uap->interval)) - ); - - return e; -} - -#endif - -static void p31binit(void *notused) -{ - (void) sched_attach(); - p31b_setcfg(CTL_P1003_1B_PAGESIZE, PAGE_SIZE); -} - -SYSINIT(p31b, SI_SUB_P1003_1B, SI_ORDER_FIRST, p31binit, NULL); diff --git a/sys/kern/posix4_mib.c b/sys/kern/posix4_mib.c deleted file mode 100644 index ba4a853ea66d..000000000000 --- a/sys/kern/posix4_mib.c +++ /dev/null @@ -1,98 +0,0 @@ -/*- - * Copyright (c) 1998 - * HD Associates, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by HD Associates, Inc - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/queue.h> -#include <sys/sysctl.h> -#include <posix4/posix4.h> - -static int facility[CTL_P1003_1B_MAXID - 1]; - -/* OID_AUTO isn't working with sysconf(3). I guess I'd have to - * modify it to do a lookup by name from the index. - * For now I've left it a top-level sysctl. - */ - -#if 1 - -SYSCTL_DECL(_p1003_1b); - -#define P1B_SYSCTL(num, name) \ -SYSCTL_INT(_p1003_1b, num, \ - name, CTLFLAG_RD, facility + num - 1, 0, ""); - -#else - -SYSCTL_DECL(_kern_p1003_1b); - -#define P1B_SYSCTL(num, name) \ -SYSCTL_INT(_kern_p1003_1b, OID_AUTO, \ - name, CTLFLAG_RD, facility + num - 1, 0, ""); -SYSCTL_NODE(_kern, OID_AUTO, p1003_1b, CTLFLAG_RW, 0, "P1003.1B"); - -#endif - -P1B_SYSCTL(CTL_P1003_1B_ASYNCHRONOUS_IO, asynchronous_io); -P1B_SYSCTL(CTL_P1003_1B_MAPPED_FILES, mapped_files); -P1B_SYSCTL(CTL_P1003_1B_MEMLOCK, memlock); -P1B_SYSCTL(CTL_P1003_1B_MEMLOCK_RANGE, memlock_range); -P1B_SYSCTL(CTL_P1003_1B_MEMORY_PROTECTION, memory_protection); -P1B_SYSCTL(CTL_P1003_1B_MESSAGE_PASSING, message_passing); -P1B_SYSCTL(CTL_P1003_1B_PRIORITIZED_IO, prioritized_io); -P1B_SYSCTL(CTL_P1003_1B_PRIORITY_SCHEDULING, priority_scheduling); -P1B_SYSCTL(CTL_P1003_1B_REALTIME_SIGNALS, realtime_signals); -P1B_SYSCTL(CTL_P1003_1B_SEMAPHORES, semaphores); -P1B_SYSCTL(CTL_P1003_1B_FSYNC, fsync); -P1B_SYSCTL(CTL_P1003_1B_SHARED_MEMORY_OBJECTS, shared_memory_objects); -P1B_SYSCTL(CTL_P1003_1B_SYNCHRONIZED_IO, synchronized_io); -P1B_SYSCTL(CTL_P1003_1B_TIMERS, timers); -P1B_SYSCTL(CTL_P1003_1B_AIO_LISTIO_MAX, aio_listio_max); -P1B_SYSCTL(CTL_P1003_1B_AIO_MAX, aio_max); -P1B_SYSCTL(CTL_P1003_1B_AIO_PRIO_DELTA_MAX, aio_prio_delta_max); -P1B_SYSCTL(CTL_P1003_1B_DELAYTIMER_MAX, delaytimer_max); -P1B_SYSCTL(CTL_P1003_1B_MQ_OPEN_MAX, mq_open_max); -P1B_SYSCTL(CTL_P1003_1B_PAGESIZE, pagesize); -P1B_SYSCTL(CTL_P1003_1B_RTSIG_MAX, rtsig_max); -P1B_SYSCTL(CTL_P1003_1B_SEM_NSEMS_MAX, sem_nsems_max); -P1B_SYSCTL(CTL_P1003_1B_SEM_VALUE_MAX, sem_value_max); -P1B_SYSCTL(CTL_P1003_1B_SIGQUEUE_MAX, sigqueue_max); -P1B_SYSCTL(CTL_P1003_1B_TIMER_MAX, timer_max); - -/* p31b_setcfg: Set the configuration - */ -void p31b_setcfg(int num, int value) -{ - if (num >= 1 && num < CTL_P1003_1B_MAXID) - facility[num - 1] = value; -} diff --git a/sys/kern/subr_acl_posix1e.c b/sys/kern/subr_acl_posix1e.c deleted file mode 100644 index bd4a52f52def..000000000000 --- a/sys/kern/subr_acl_posix1e.c +++ /dev/null @@ -1,277 +0,0 @@ -/*- - * Copyright (c) 1999, 2000 Robert N. M. Watson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * Generic routines to support file system ACLs, at a syntactic level - * Semantics are the responsibility of the underlying file system - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sysproto.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/vnode.h> -#include <sys/lock.h> -#include <sys/namei.h> -#include <sys/file.h> -#include <sys/proc.h> -#include <sys/sysent.h> -#include <sys/errno.h> -#include <sys/stat.h> -#include <sys/acl.h> -#include <vm/vm_zone.h> - -static MALLOC_DEFINE(M_ACL, "acl", "access control list"); - -static int vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp); -static int vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp); -static int vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp); - -/* - * These calls wrap the real vnode operations, and are called by the - * syscall code once the syscall has converted the path or file - * descriptor to a vnode (unlocked). The aclp pointer is assumed - * still to point to userland, so this should not be consumed within - * the kernel except by syscall code. Other code should directly - * invoke VOP_{SET,GET}ACL. - */ - -/* - * Given a vnode, set its ACL. - */ -static int -vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp) -{ - struct acl inkernacl; - int error; - - error = copyin(aclp, &inkernacl, sizeof(struct acl)); - if (error) - return(error); - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - error = VOP_SETACL(vp, type, &inkernacl, p->p_ucred, p); - VOP_UNLOCK(vp, 0, p); - return(error); -} - -/* - * Given a vnode, get its ACL. - */ -static int -vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp) -{ - struct acl inkernelacl; - int error; - - error = VOP_GETACL(vp, type, &inkernelacl, p->p_ucred, p); - if (error == 0) - error = copyout(&inkernelacl, aclp, sizeof(struct acl)); - return (error); -} - -/* - * Given a vnode, delete its ACL. - */ -static int -vacl_delete(struct proc *p, struct vnode *vp, acl_type_t type) -{ - int error; - - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - error = VOP_SETACL(vp, ACL_TYPE_DEFAULT, 0, p->p_ucred, p); - VOP_UNLOCK(vp, 0, p); - return (error); -} - -/* - * Given a vnode, check whether an ACL is appropriate for it - */ -static int -vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp) -{ - struct acl inkernelacl; - int error; - - error = copyin(aclp, &inkernelacl, sizeof(struct acl)); - if (error) - return(error); - error = VOP_ACLCHECK(vp, type, &inkernelacl, p->p_ucred, p); - return (error); -} - -/* - * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. - * Don't need to lock, as the vacl_ code will get/release any locks - * required. - */ - -/* - * Given a file path, get an ACL for it - */ -int -__acl_get_file(struct proc *p, struct __acl_get_file_args *uap) -{ - struct nameidata nd; - int error; - - /* what flags are required here -- possible not LOCKLEAF? */ - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - error = namei(&nd); - if (error) - return(error); - error = vacl_get_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); - NDFREE(&nd, 0); - return (error); -} - -/* - * Given a file path, set an ACL for it - */ -int -__acl_set_file(struct proc *p, struct __acl_set_file_args *uap) -{ - struct nameidata nd; - int error; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - error = namei(&nd); - if (error) - return(error); - error = vacl_set_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); - NDFREE(&nd, 0); - return (error); -} - -/* - * Given a file descriptor, get an ACL for it - */ -int -__acl_get_fd(struct proc *p, struct __acl_get_fd_args *uap) -{ - struct file *fp; - int error; - - error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); - if (error) - return(error); - return vacl_get_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), - SCARG(uap, aclp)); -} - -/* - * Given a file descriptor, set an ACL for it - */ -int -__acl_set_fd(struct proc *p, struct __acl_set_fd_args *uap) -{ - struct file *fp; - int error; - - error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); - if (error) - return(error); - return vacl_set_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), - SCARG(uap, aclp)); -} - -/* - * Given a file path, delete an ACL from it. - */ -int -__acl_delete_file(struct proc *p, struct __acl_delete_file_args *uap) -{ - struct nameidata nd; - int error; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - error = namei(&nd); - if (error) - return(error); - error = vacl_delete(p, nd.ni_vp, SCARG(uap, type)); - NDFREE(&nd, 0); - return (error); -} - -/* - * Given a file path, delete an ACL from it. - */ -int -__acl_delete_fd(struct proc *p, struct __acl_delete_fd_args *uap) -{ - struct file *fp; - int error; - - error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); - if (error) - return(error); - error = vacl_delete(p, (struct vnode *)fp->f_data, SCARG(uap, type)); - return (error); -} - -/* - * Given a file path, check an ACL for it - */ -int -__acl_aclcheck_file(struct proc *p, struct __acl_aclcheck_file_args *uap) -{ - struct nameidata nd; - int error; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - error = namei(&nd); - if (error) - return(error); - error = vacl_aclcheck(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); - NDFREE(&nd, 0); - return (error); -} - -/* - * Given a file descriptor, check an ACL for it - */ -int -__acl_aclcheck_fd(struct proc *p, struct __acl_aclcheck_fd_args *uap) -{ - struct file *fp; - int error; - - error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); - if (error) - return(error); - return vacl_aclcheck(p, (struct vnode *)fp->f_data, SCARG(uap, type), - SCARG(uap, aclp)); -} diff --git a/sys/kern/subr_clist.c b/sys/kern/subr_clist.c deleted file mode 100644 index a7d1daf79e8e..000000000000 --- a/sys/kern/subr_clist.c +++ /dev/null @@ -1,696 +0,0 @@ -/* - * Copyright (c) 1994, David Greenman - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * clist support routines - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/tty.h> -#include <sys/clist.h> - -static void clist_init __P((void *)); -SYSINIT(clist, SI_SUB_CLIST, SI_ORDER_FIRST, clist_init, NULL) - -static struct cblock *cfreelist = 0; -int cfreecount = 0; -static int cslushcount; -static int ctotcount; - -#ifndef INITIAL_CBLOCKS -#define INITIAL_CBLOCKS 50 -#endif - -static struct cblock *cblock_alloc __P((void)); -static void cblock_alloc_cblocks __P((int number)); -static void cblock_free __P((struct cblock *cblockp)); -static void cblock_free_cblocks __P((int number)); - -#include "opt_ddb.h" -#ifdef DDB -#include <ddb/ddb.h> - -DB_SHOW_COMMAND(cbstat, cbstat) -{ - int cbsize = CBSIZE; - - printf( - "tot = %d (active = %d, free = %d (reserved = %d, slush = %d))\n", - ctotcount * cbsize, ctotcount * cbsize - cfreecount, cfreecount, - cfreecount - cslushcount * cbsize, cslushcount * cbsize); -} -#endif /* DDB */ - -/* - * Called from init_main.c - */ -/* ARGSUSED*/ -static void -clist_init(dummy) - void *dummy; -{ - /* - * Allocate an initial base set of cblocks as a 'slush'. - * We allocate non-slush cblocks with each initial ttyopen() and - * deallocate them with each ttyclose(). - * We should adjust the slush allocation. This can't be done in - * the i/o routines because they are sometimes called from - * interrupt handlers when it may be unsafe to call malloc(). - */ - cblock_alloc_cblocks(cslushcount = INITIAL_CBLOCKS); -} - -/* - * Remove a cblock from the cfreelist queue and return a pointer - * to it. - */ -static __inline struct cblock * -cblock_alloc() -{ - struct cblock *cblockp; - - cblockp = cfreelist; - if (cblockp == NULL) - panic("clist reservation botch"); - cfreelist = cblockp->c_next; - cblockp->c_next = NULL; - cfreecount -= CBSIZE; - return (cblockp); -} - -/* - * Add a cblock to the cfreelist queue. - */ -static __inline void -cblock_free(cblockp) - struct cblock *cblockp; -{ - if (isset(cblockp->c_quote, CBQSIZE * NBBY - 1)) - bzero(cblockp->c_quote, sizeof cblockp->c_quote); - cblockp->c_next = cfreelist; - cfreelist = cblockp; - cfreecount += CBSIZE; -} - -/* - * Allocate some cblocks for the cfreelist queue. - */ -static void -cblock_alloc_cblocks(number) - int number; -{ - int i; - struct cblock *cbp; - - for (i = 0; i < number; ++i) { - cbp = malloc(sizeof *cbp, M_TTYS, M_NOWAIT); - if (cbp == NULL) { - printf( -"clist_alloc_cblocks: M_NOWAIT malloc failed, trying M_WAITOK\n"); - cbp = malloc(sizeof *cbp, M_TTYS, M_WAITOK); - } - /* - * Freed cblocks have zero quotes and garbage elsewhere. - * Set the may-have-quote bit to force zeroing the quotes. - */ - setbit(cbp->c_quote, CBQSIZE * NBBY - 1); - cblock_free(cbp); - } - ctotcount += number; -} - -/* - * Set the cblock allocation policy for a a clist. - * Must be called in process context at spltty(). - */ -void -clist_alloc_cblocks(clistp, ccmax, ccreserved) - struct clist *clistp; - int ccmax; - int ccreserved; -{ - int dcbr; - - /* - * Allow for wasted space at the head. - */ - if (ccmax != 0) - ccmax += CBSIZE - 1; - if (ccreserved != 0) - ccreserved += CBSIZE - 1; - - clistp->c_cbmax = roundup(ccmax, CBSIZE) / CBSIZE; - dcbr = roundup(ccreserved, CBSIZE) / CBSIZE - clistp->c_cbreserved; - if (dcbr >= 0) - cblock_alloc_cblocks(dcbr); - else { - if (clistp->c_cbreserved + dcbr < clistp->c_cbcount) - dcbr = clistp->c_cbcount - clistp->c_cbreserved; - cblock_free_cblocks(-dcbr); - } - clistp->c_cbreserved += dcbr; -} - -/* - * Free some cblocks from the cfreelist queue back to the - * system malloc pool. - */ -static void -cblock_free_cblocks(number) - int number; -{ - int i; - - for (i = 0; i < number; ++i) - free(cblock_alloc(), M_TTYS); - ctotcount -= number; -} - -/* - * Free the cblocks reserved for a clist. - * Must be called at spltty(). - */ -void -clist_free_cblocks(clistp) - struct clist *clistp; -{ - if (clistp->c_cbcount != 0) - panic("freeing active clist cblocks"); - cblock_free_cblocks(clistp->c_cbreserved); - clistp->c_cbmax = 0; - clistp->c_cbreserved = 0; -} - -/* - * Get a character from the head of a clist. - */ -int -getc(clistp) - struct clist *clistp; -{ - int chr = -1; - int s; - struct cblock *cblockp; - - s = spltty(); - - /* If there are characters in the list, get one */ - if (clistp->c_cc) { - cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND); - chr = (u_char)*clistp->c_cf; - - /* - * If this char is quoted, set the flag. - */ - if (isset(cblockp->c_quote, clistp->c_cf - (char *)cblockp->c_info)) - chr |= TTY_QUOTE; - - /* - * Advance to next character. - */ - clistp->c_cf++; - clistp->c_cc--; - /* - * If we have advanced the 'first' character pointer - * past the end of this cblock, advance to the next one. - * If there are no more characters, set the first and - * last pointers to NULL. In either case, free the - * current cblock. - */ - if ((clistp->c_cf >= (char *)(cblockp+1)) || (clistp->c_cc == 0)) { - if (clistp->c_cc > 0) { - clistp->c_cf = cblockp->c_next->c_info; - } else { - clistp->c_cf = clistp->c_cl = NULL; - } - cblock_free(cblockp); - if (--clistp->c_cbcount >= clistp->c_cbreserved) - ++cslushcount; - } - } - - splx(s); - return (chr); -} - -/* - * Copy 'amount' of chars, beginning at head of clist 'clistp' to - * destination linear buffer 'dest'. Return number of characters - * actually copied. - */ -int -q_to_b(clistp, dest, amount) - struct clist *clistp; - char *dest; - int amount; -{ - struct cblock *cblockp; - struct cblock *cblockn; - char *dest_orig = dest; - int numc; - int s; - - s = spltty(); - - while (clistp && amount && (clistp->c_cc > 0)) { - cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND); - cblockn = cblockp + 1; /* pointer arithmetic! */ - numc = min(amount, (char *)cblockn - clistp->c_cf); - numc = min(numc, clistp->c_cc); - bcopy(clistp->c_cf, dest, numc); - amount -= numc; - clistp->c_cf += numc; - clistp->c_cc -= numc; - dest += numc; - /* - * If this cblock has been emptied, advance to the next - * one. If there are no more characters, set the first - * and last pointer to NULL. In either case, free the - * current cblock. - */ - if ((clistp->c_cf >= (char *)cblockn) || (clistp->c_cc == 0)) { - if (clistp->c_cc > 0) { - clistp->c_cf = cblockp->c_next->c_info; - } else { - clistp->c_cf = clistp->c_cl = NULL; - } - cblock_free(cblockp); - if (--clistp->c_cbcount >= clistp->c_cbreserved) - ++cslushcount; - } - } - - splx(s); - return (dest - dest_orig); -} - -/* - * Flush 'amount' of chars, beginning at head of clist 'clistp'. - */ -void -ndflush(clistp, amount) - struct clist *clistp; - int amount; -{ - struct cblock *cblockp; - struct cblock *cblockn; - int numc; - int s; - - s = spltty(); - - while (amount && (clistp->c_cc > 0)) { - cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND); - cblockn = cblockp + 1; /* pointer arithmetic! */ - numc = min(amount, (char *)cblockn - clistp->c_cf); - numc = min(numc, clistp->c_cc); - amount -= numc; - clistp->c_cf += numc; - clistp->c_cc -= numc; - /* - * If this cblock has been emptied, advance to the next - * one. If there are no more characters, set the first - * and last pointer to NULL. In either case, free the - * current cblock. - */ - if ((clistp->c_cf >= (char *)cblockn) || (clistp->c_cc == 0)) { - if (clistp->c_cc > 0) { - clistp->c_cf = cblockp->c_next->c_info; - } else { - clistp->c_cf = clistp->c_cl = NULL; - } - cblock_free(cblockp); - if (--clistp->c_cbcount >= clistp->c_cbreserved) - ++cslushcount; - } - } - - splx(s); -} - -/* - * Add a character to the end of a clist. Return -1 is no - * more clists, or 0 for success. - */ -int -putc(chr, clistp) - int chr; - struct clist *clistp; -{ - struct cblock *cblockp; - int s; - - s = spltty(); - - if (clistp->c_cl == NULL) { - if (clistp->c_cbreserved < 1) { - splx(s); - printf("putc to a clist with no reserved cblocks\n"); - return (-1); /* nothing done */ - } - cblockp = cblock_alloc(); - clistp->c_cbcount = 1; - clistp->c_cf = clistp->c_cl = cblockp->c_info; - clistp->c_cc = 0; - } else { - cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND); - if (((intptr_t)clistp->c_cl & CROUND) == 0) { - struct cblock *prev = (cblockp - 1); - - if (clistp->c_cbcount >= clistp->c_cbreserved) { - if (clistp->c_cbcount >= clistp->c_cbmax - || cslushcount <= 0) { - splx(s); - return (-1); - } - --cslushcount; - } - cblockp = cblock_alloc(); - clistp->c_cbcount++; - prev->c_next = cblockp; - clistp->c_cl = cblockp->c_info; - } - } - - /* - * If this character is quoted, set the quote bit, if not, clear it. - */ - if (chr & TTY_QUOTE) { - setbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info); - /* - * Use one of the spare quote bits to record that something - * may be quoted. - */ - setbit(cblockp->c_quote, CBQSIZE * NBBY - 1); - } else - clrbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info); - - *clistp->c_cl++ = chr; - clistp->c_cc++; - - splx(s); - return (0); -} - -/* - * Copy data from linear buffer to clist chain. Return the - * number of characters not copied. - */ -int -b_to_q(src, amount, clistp) - char *src; - int amount; - struct clist *clistp; -{ - struct cblock *cblockp; - char *firstbyte, *lastbyte; - u_char startmask, endmask; - int startbit, endbit, num_between, numc; - int s; - - /* - * Avoid allocating an initial cblock and then not using it. - * c_cc == 0 must imply c_cbount == 0. - */ - if (amount <= 0) - return (amount); - - s = spltty(); - - /* - * If there are no cblocks assigned to this clist yet, - * then get one. - */ - if (clistp->c_cl == NULL) { - if (clistp->c_cbreserved < 1) { - splx(s); - printf("b_to_q to a clist with no reserved cblocks.\n"); - return (amount); /* nothing done */ - } - cblockp = cblock_alloc(); - clistp->c_cbcount = 1; - clistp->c_cf = clistp->c_cl = cblockp->c_info; - clistp->c_cc = 0; - } else { - cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND); - } - - while (amount) { - /* - * Get another cblock if needed. - */ - if (((intptr_t)clistp->c_cl & CROUND) == 0) { - struct cblock *prev = cblockp - 1; - - if (clistp->c_cbcount >= clistp->c_cbreserved) { - if (clistp->c_cbcount >= clistp->c_cbmax - || cslushcount <= 0) { - splx(s); - return (amount); - } - --cslushcount; - } - cblockp = cblock_alloc(); - clistp->c_cbcount++; - prev->c_next = cblockp; - clistp->c_cl = cblockp->c_info; - } - - /* - * Copy a chunk of the linear buffer up to the end - * of this cblock. - */ - numc = min(amount, (char *)(cblockp + 1) - clistp->c_cl); - bcopy(src, clistp->c_cl, numc); - - /* - * Clear quote bits if they aren't known to be clear. - * The following could probably be made into a seperate - * "bitzero()" routine, but why bother? - */ - if (isset(cblockp->c_quote, CBQSIZE * NBBY - 1)) { - startbit = clistp->c_cl - (char *)cblockp->c_info; - endbit = startbit + numc - 1; - - firstbyte = (u_char *)cblockp->c_quote + (startbit / NBBY); - lastbyte = (u_char *)cblockp->c_quote + (endbit / NBBY); - - /* - * Calculate mask of bits to preserve in first and - * last bytes. - */ - startmask = NBBY - (startbit % NBBY); - startmask = 0xff >> startmask; - endmask = (endbit % NBBY); - endmask = 0xff << (endmask + 1); - - if (firstbyte != lastbyte) { - *firstbyte &= startmask; - *lastbyte &= endmask; - - num_between = lastbyte - firstbyte - 1; - if (num_between) - bzero(firstbyte + 1, num_between); - } else { - *firstbyte &= (startmask | endmask); - } - } - - /* - * ...and update pointer for the next chunk. - */ - src += numc; - clistp->c_cl += numc; - clistp->c_cc += numc; - amount -= numc; - /* - * If we go through the loop again, it's always - * for data in the next cblock, so by adding one (cblock), - * (which makes the pointer 1 beyond the end of this - * cblock) we prepare for the assignment of 'prev' - * above. - */ - cblockp += 1; - - } - - splx(s); - return (amount); -} - -/* - * Get the next character in the clist. Store it at dst. Don't - * advance any clist pointers, but return a pointer to the next - * character position. - */ -char * -nextc(clistp, cp, dst) - struct clist *clistp; - char *cp; - int *dst; -{ - struct cblock *cblockp; - - ++cp; - /* - * See if the next character is beyond the end of - * the clist. - */ - if (clistp->c_cc && (cp != clistp->c_cl)) { - /* - * If the next character is beyond the end of this - * cblock, advance to the next cblock. - */ - if (((intptr_t)cp & CROUND) == 0) - cp = ((struct cblock *)cp - 1)->c_next->c_info; - cblockp = (struct cblock *)((intptr_t)cp & ~CROUND); - - /* - * Get the character. Set the quote flag if this character - * is quoted. - */ - *dst = (u_char)*cp | (isset(cblockp->c_quote, cp - (char *)cblockp->c_info) ? TTY_QUOTE : 0); - - return (cp); - } - - return (NULL); -} - -/* - * "Unput" a character from a clist. - */ -int -unputc(clistp) - struct clist *clistp; -{ - struct cblock *cblockp = 0, *cbp = 0; - int s; - int chr = -1; - - - s = spltty(); - - if (clistp->c_cc) { - --clistp->c_cc; - --clistp->c_cl; - - chr = (u_char)*clistp->c_cl; - - cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND); - - /* - * Set quote flag if this character was quoted. - */ - if (isset(cblockp->c_quote, (u_char *)clistp->c_cl - cblockp->c_info)) - chr |= TTY_QUOTE; - - /* - * If all of the characters have been unput in this - * cblock, then find the previous one and free this - * one. - */ - if (clistp->c_cc && (clistp->c_cl <= (char *)cblockp->c_info)) { - cbp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND); - - while (cbp->c_next != cblockp) - cbp = cbp->c_next; - - /* - * When the previous cblock is at the end, the 'last' - * pointer always points (invalidly) one past. - */ - clistp->c_cl = (char *)(cbp+1); - cblock_free(cblockp); - if (--clistp->c_cbcount >= clistp->c_cbreserved) - ++cslushcount; - cbp->c_next = NULL; - } - } - - /* - * If there are no more characters on the list, then - * free the last cblock. - */ - if ((clistp->c_cc == 0) && clistp->c_cl) { - cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND); - cblock_free(cblockp); - if (--clistp->c_cbcount >= clistp->c_cbreserved) - ++cslushcount; - clistp->c_cf = clistp->c_cl = NULL; - } - - splx(s); - return (chr); -} - -/* - * Move characters in source clist to destination clist, - * preserving quote bits. - */ -void -catq(src_clistp, dest_clistp) - struct clist *src_clistp, *dest_clistp; -{ - int chr, s; - - s = spltty(); - /* - * If the destination clist is empty (has no cblocks atttached), - * and there are no possible complications with the resource counters, - * then we simply assign the current clist to the destination. - */ - if (!dest_clistp->c_cf - && src_clistp->c_cbcount <= src_clistp->c_cbmax - && src_clistp->c_cbcount <= dest_clistp->c_cbmax) { - dest_clistp->c_cf = src_clistp->c_cf; - dest_clistp->c_cl = src_clistp->c_cl; - src_clistp->c_cf = src_clistp->c_cl = NULL; - - dest_clistp->c_cc = src_clistp->c_cc; - src_clistp->c_cc = 0; - dest_clistp->c_cbcount = src_clistp->c_cbcount; - src_clistp->c_cbcount = 0; - - splx(s); - return; - } - - splx(s); - - /* - * XXX This should probably be optimized to more than one - * character at a time. - */ - while ((chr = getc(src_clistp)) != -1) - putc(chr, dest_clistp); -} diff --git a/sys/kern/subr_disklabel.c b/sys/kern/subr_disklabel.c deleted file mode 100644 index 9184f2ff0e2a..000000000000 --- a/sys/kern/subr_disklabel.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/conf.h> -#include <sys/disklabel.h> -#include <sys/diskslice.h> -#include <sys/syslog.h> - -/* - * Seek sort for disks. - * - * The buf_queue keep two queues, sorted in ascending block order. The first - * queue holds those requests which are positioned after the current block - * (in the first request); the second, which starts at queue->switch_point, - * holds requests which came in after their block number was passed. Thus - * we implement a one way scan, retracting after reaching the end of the drive - * to the first request on the second queue, at which time it becomes the - * first queue. - * - * A one-way scan is natural because of the way UNIX read-ahead blocks are - * allocated. - */ - -void -bufqdisksort(bufq, bp) - struct buf_queue_head *bufq; - struct buf *bp; -{ - struct buf *bq; - struct buf *bn; - struct buf *be; - - be = TAILQ_LAST(&bufq->queue, buf_queue); - /* - * If the queue is empty or we are an - * ordered transaction, then it's easy. - */ - if ((bq = bufq_first(bufq)) == NULL - || (bp->b_flags & B_ORDERED) != 0) { - bufq_insert_tail(bufq, bp); - return; - } else if (bufq->insert_point != NULL) { - - /* - * A certain portion of the list is - * "locked" to preserve ordering, so - * we can only insert after the insert - * point. - */ - bq = bufq->insert_point; - } else { - - /* - * If we lie before the last removed (currently active) - * request, and are not inserting ourselves into the - * "locked" portion of the list, then we must add ourselves - * to the second request list. - */ - if (bp->b_pblkno < bufq->last_pblkno) { - - bq = bufq->switch_point; - /* - * If we are starting a new secondary list, - * then it's easy. - */ - if (bq == NULL) { - bufq->switch_point = bp; - bufq_insert_tail(bufq, bp); - return; - } - /* - * If we lie ahead of the current switch point, - * insert us before the switch point and move - * the switch point. - */ - if (bp->b_pblkno < bq->b_pblkno) { - bufq->switch_point = bp; - TAILQ_INSERT_BEFORE(bq, bp, b_act); - return; - } - } else { - if (bufq->switch_point != NULL) - be = TAILQ_PREV(bufq->switch_point, - buf_queue, b_act); - /* - * If we lie between last_pblkno and bq, - * insert before bq. - */ - if (bp->b_pblkno < bq->b_pblkno) { - TAILQ_INSERT_BEFORE(bq, bp, b_act); - return; - } - } - } - - /* - * Request is at/after our current position in the list. - * Optimize for sequential I/O by seeing if we go at the tail. - */ - if (bp->b_pblkno > be->b_pblkno) { - TAILQ_INSERT_AFTER(&bufq->queue, be, bp, b_act); - return; - } - - /* Otherwise, insertion sort */ - while ((bn = TAILQ_NEXT(bq, b_act)) != NULL) { - - /* - * We want to go after the current request if it is the end - * of the first request list, or if the next request is a - * larger cylinder than our request. - */ - if (bn == bufq->switch_point - || bp->b_pblkno < bn->b_pblkno) - break; - bq = bn; - } - TAILQ_INSERT_AFTER(&bufq->queue, bq, bp, b_act); -} - - -/* - * Attempt to read a disk label from a device using the indicated strategy - * routine. The label must be partly set up before this: secpercyl, secsize - * and anything required in the strategy routine (e.g., dummy bounds for the - * partition containing the label) must be filled in before calling us. - * Returns NULL on success and an error string on failure. - */ -char * -readdisklabel(dev, lp) - dev_t dev; - register struct disklabel *lp; -{ - register struct buf *bp; - struct disklabel *dlp; - char *msg = NULL; - - bp = geteblk((int)lp->d_secsize); - bp->b_dev = dev; - bp->b_blkno = LABELSECTOR * ((int)lp->d_secsize/DEV_BSIZE); - bp->b_bcount = lp->d_secsize; - bp->b_flags &= ~B_INVAL; - bp->b_flags |= B_READ; - BUF_STRATEGY(bp, 1); - if (biowait(bp)) - msg = "I/O error"; - else for (dlp = (struct disklabel *)bp->b_data; - dlp <= (struct disklabel *)((char *)bp->b_data + - lp->d_secsize - sizeof(*dlp)); - dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { - if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { - if (msg == NULL) - msg = "no disk label"; - } else if (dlp->d_npartitions > MAXPARTITIONS || - dkcksum(dlp) != 0) - msg = "disk label corrupted"; - else { - *lp = *dlp; - msg = NULL; - break; - } - } - bp->b_flags |= B_INVAL | B_AGE; - brelse(bp); - return (msg); -} - -/* - * Check new disk label for sensibility before setting it. - */ -int -setdisklabel(olp, nlp, openmask) - register struct disklabel *olp, *nlp; - u_long openmask; -{ - register int i; - register struct partition *opp, *npp; - - /* - * Check it is actually a disklabel we are looking at. - */ - if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || - dkcksum(nlp) != 0) - return (EINVAL); - /* - * For each partition that we think is open, - */ - while ((i = ffs((long)openmask)) != 0) { - i--; - /* - * Check it is not changing.... - */ - openmask &= ~(1 << i); - if (nlp->d_npartitions <= i) - return (EBUSY); - opp = &olp->d_partitions[i]; - npp = &nlp->d_partitions[i]; - if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) - return (EBUSY); - /* - * Copy internally-set partition information - * if new label doesn't include it. XXX - * (If we are using it then we had better stay the same type) - * This is possibly dubious, as someone else noted (XXX) - */ - if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { - npp->p_fstype = opp->p_fstype; - npp->p_fsize = opp->p_fsize; - npp->p_frag = opp->p_frag; - npp->p_cpg = opp->p_cpg; - } - } - nlp->d_checksum = 0; - nlp->d_checksum = dkcksum(nlp); - *olp = *nlp; - return (0); -} - -/* - * Write disk label back to device after modification. - */ -int -writedisklabel(dev, lp) - dev_t dev; - register struct disklabel *lp; -{ - struct buf *bp; - struct disklabel *dlp; - int error = 0; - - if (lp->d_partitions[RAW_PART].p_offset != 0) - return (EXDEV); /* not quite right */ - bp = geteblk((int)lp->d_secsize); - bp->b_dev = dkmodpart(dev, RAW_PART); - bp->b_blkno = LABELSECTOR * ((int)lp->d_secsize/DEV_BSIZE); - bp->b_bcount = lp->d_secsize; -#if 1 - /* - * We read the label first to see if it's there, - * in which case we will put ours at the same offset into the block.. - * (I think this is stupid [Julian]) - * Note that you can't write a label out over a corrupted label! - * (also stupid.. how do you write the first one? by raw writes?) - */ - bp->b_flags &= ~B_INVAL; - bp->b_flags |= B_READ; - BUF_STRATEGY(bp, 1); - error = biowait(bp); - if (error) - goto done; - for (dlp = (struct disklabel *)bp->b_data; - dlp <= (struct disklabel *) - ((char *)bp->b_data + lp->d_secsize - sizeof(*dlp)); - dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { - if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && - dkcksum(dlp) == 0) { - *dlp = *lp; - bp->b_flags &= ~(B_DONE | B_READ); - bp->b_flags |= B_WRITE; -#ifdef __alpha__ - alpha_fix_srm_checksum(bp); -#endif - BUF_STRATEGY(bp, 1); - error = biowait(bp); - goto done; - } - } - error = ESRCH; -done: -#else - bzero(bp->b_data, lp->d_secsize); - dlp = (struct disklabel *)bp->b_data; - *dlp = *lp; - bp->b_flags &= ~B_INVAL; - bp->b_flags |= B_WRITE; - BUF_STRATEGY(bp, 1); - error = biowait(bp); -#endif - bp->b_flags |= B_INVAL | B_AGE; - brelse(bp); - return (error); -} - -/* - * Compute checksum for disk label. - */ -u_int -dkcksum(lp) - register struct disklabel *lp; -{ - register u_short *start, *end; - register u_short sum = 0; - - start = (u_short *)lp; - end = (u_short *)&lp->d_partitions[lp->d_npartitions]; - while (start < end) - sum ^= *start++; - return (sum); -} - -/* - * Disk error is the preface to plaintive error messages - * about failing disk transfers. It prints messages of the form - -hp0g: hard error reading fsbn 12345 of 12344-12347 (hp0 bn %d cn %d tn %d sn %d) - - * if the offset of the error in the transfer and a disk label - * are both available. blkdone should be -1 if the position of the error - * is unknown; the disklabel pointer may be null from drivers that have not - * been converted to use them. The message is printed with printf - * if pri is LOG_PRINTF, otherwise it uses log at the specified priority. - * The message should be completed (with at least a newline) with printf - * or addlog, respectively. There is no trailing space. - */ -void -diskerr(bp, what, pri, blkdone, lp) - register struct buf *bp; - char *what; - int pri, blkdone; - register struct disklabel *lp; -{ - int unit = dkunit(bp->b_dev); - int slice = dkslice(bp->b_dev); - int part = dkpart(bp->b_dev); - register int (*pr) __P((const char *, ...)); - char partname[2]; - char *sname; - daddr_t sn; - - if (pri != LOG_PRINTF) { - log(pri, "%s", ""); - pr = addlog; - } else - pr = printf; - sname = dsname(bp->b_dev, unit, slice, part, partname); - (*pr)("%s%s: %s %sing fsbn ", sname, partname, what, - bp->b_flags & B_READ ? "read" : "writ"); - sn = bp->b_blkno; - if (bp->b_bcount <= DEV_BSIZE) - (*pr)("%ld", (long)sn); - else { - if (blkdone >= 0) { - sn += blkdone; - (*pr)("%ld of ", (long)sn); - } - (*pr)("%ld-%ld", (long)bp->b_blkno, - (long)(bp->b_blkno + (bp->b_bcount - 1) / DEV_BSIZE)); - } - if (lp && (blkdone >= 0 || bp->b_bcount <= lp->d_secsize)) { -#ifdef tahoe - sn *= DEV_BSIZE / lp->d_secsize; /* XXX */ -#endif - sn += lp->d_partitions[part].p_offset; - /* - * XXX should add slice offset and not print the slice, - * but we don't know the slice pointer. - * XXX should print bp->b_pblkno so that this will work - * independent of slices, labels and bad sector remapping, - * but some drivers don't set bp->b_pblkno. - */ - (*pr)(" (%s bn %ld; cn %ld", sname, (long)sn, - (long)(sn / lp->d_secpercyl)); - sn %= (long)lp->d_secpercyl; - (*pr)(" tn %ld sn %ld)", (long)(sn / lp->d_nsectors), - (long)(sn % lp->d_nsectors)); - } -} diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c deleted file mode 100644 index 7ae2ade9bdca..000000000000 --- a/sys/kern/subr_param.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 1980, 1986, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)param.c 8.3 (Berkeley) 8/20/94 - * $FreeBSD$ - */ - -#include <stddef.h> - -#include "opt_sysvipc.h" -#include "opt_param.h" - -#include <sys/param.h> - -#ifdef SYSVSHM -#include <machine/vmparam.h> -#include <sys/shm.h> -#endif -#ifdef SYSVSEM -#include <sys/sem.h> -#endif -#ifdef SYSVMSG -#include <sys/msg.h> -#endif - -/* - * System parameter formulae. - * - * This file is copied into each directory where we compile - * the kernel; it should be modified there to suit local taste - * if necessary. - * - * Compiled with -DMAXUSERS=xx - */ - -#ifndef HZ -#define HZ 100 -#endif -int hz = HZ; -int tick = 1000000 / HZ; -int tickadj = howmany(30000, 60 * HZ); /* can adjust 30ms in 60s */ -#define NPROC (20 + 16 * MAXUSERS) -#ifndef MAXFILES -#define MAXFILES (NPROC*2) -#endif -int maxproc = NPROC; /* maximum # of processes */ -int maxprocperuid = NPROC-1; /* maximum # of processes per user */ -int maxfiles = MAXFILES; /* system wide open files limit */ -int maxfilesperproc = MAXFILES; /* per-process open files limit */ -int ncallout = 16 + NPROC + MAXFILES; /* maximum # of timer events */ -int mbuf_wait = 32; /* mbuf sleep time in ticks */ - -/* maximum # of sf_bufs (sendfile(2) zero-copy virtual buffers) */ -#ifndef NSFBUFS -#define NSFBUFS (512 + MAXUSERS * 16) -#endif -int nsfbufs = NSFBUFS; - -/* - * Values in support of System V compatible shared memory. XXX - */ -#ifdef SYSVSHM -#ifndef SHMMAX -#define SHMMAX (SHMMAXPGS*PAGE_SIZE) -#endif -#ifndef SHMMIN -#define SHMMIN 1 -#endif -#ifndef SHMMNI -#define SHMMNI 32 /* <= SHMMMNI in shm.h */ -#endif -#ifndef SHMSEG -#define SHMSEG 8 -#endif -#ifndef SHMALL -#define SHMALL (SHMMAXPGS) -#endif - -struct shminfo shminfo = { - SHMMAX, - SHMMIN, - SHMMNI, - SHMSEG, - SHMALL -}; -#endif - -/* - * Values in support of System V compatible semaphores. - */ - -#ifdef SYSVSEM - -struct seminfo seminfo = { - SEMMAP, /* # of entries in semaphore map */ - SEMMNI, /* # of semaphore identifiers */ - SEMMNS, /* # of semaphores in system */ - SEMMNU, /* # of undo structures in system */ - SEMMSL, /* max # of semaphores per id */ - SEMOPM, /* max # of operations per semop call */ - SEMUME, /* max # of undo entries per process */ - SEMUSZ, /* size in bytes of undo structure */ - SEMVMX, /* semaphore maximum value */ - SEMAEM /* adjust on exit max value */ -}; -#endif - -/* - * Values in support of System V compatible messages. - */ - -#ifdef SYSVMSG - -struct msginfo msginfo = { - MSGMAX, /* max chars in a message */ - MSGMNI, /* # of message queue identifiers */ - MSGMNB, /* max chars in a queue */ - MSGTQL, /* max messages in system */ - MSGSSZ, /* size of a message segment */ - /* (must be small power of 2 greater than 4) */ - MSGSEG /* number of message segments */ -}; -#endif - -/* - * These may be set to nonzero here or by patching. - * If they are nonzero at bootstrap time then they are - * initialized to values dependent on the memory size. - */ -#ifdef NBUF -int nbuf = NBUF; -#else -int nbuf = 0; -#endif -int nswbuf = 0; - -/* - * These have to be allocated somewhere; allocating - * them here forces loader errors if this file is omitted - * (if they've been externed everywhere else; hah!). - */ -struct buf *swbuf; diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c deleted file mode 100644 index 8e349a9800e4..000000000000 --- a/sys/kern/subr_smp.c +++ /dev/null @@ -1,2739 +0,0 @@ -/* - * Copyright (c) 1996, by Steve Passe - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. The name of the developer may NOT be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include "opt_smp.h" -#include "opt_cpu.h" -#include "opt_user_ldt.h" - -#ifdef SMP -#include <machine/smptests.h> -#else -#error -#endif - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/proc.h> -#include <sys/sysctl.h> -#include <sys/malloc.h> -#include <sys/memrange.h> -#ifdef BETTER_CLOCK -#include <sys/dkstat.h> -#endif -#include <sys/cons.h> /* cngetc() */ - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/pmap.h> -#include <vm/vm_kern.h> -#include <vm/vm_extern.h> -#ifdef BETTER_CLOCK -#include <sys/lock.h> -#include <vm/vm_map.h> -#include <sys/user.h> -#ifdef GPROF -#include <sys/gmon.h> -#endif -#endif - -#include <machine/smp.h> -#include <machine/apic.h> -#include <machine/atomic.h> -#include <machine/cpufunc.h> -#include <machine/mpapic.h> -#include <machine/psl.h> -#include <machine/segments.h> -#include <machine/smptests.h> /** TEST_DEFAULT_CONFIG, TEST_TEST1 */ -#include <machine/tss.h> -#include <machine/specialreg.h> -#include <machine/globaldata.h> - -#if defined(APIC_IO) -#include <machine/md_var.h> /* setidt() */ -#include <i386/isa/icu.h> /* IPIs */ -#include <i386/isa/intr_machdep.h> /* IPIs */ -#endif /* APIC_IO */ - -#if defined(TEST_DEFAULT_CONFIG) -#define MPFPS_MPFB1 TEST_DEFAULT_CONFIG -#else -#define MPFPS_MPFB1 mpfps->mpfb1 -#endif /* TEST_DEFAULT_CONFIG */ - -#define WARMBOOT_TARGET 0 -#define WARMBOOT_OFF (KERNBASE + 0x0467) -#define WARMBOOT_SEG (KERNBASE + 0x0469) - -#ifdef PC98 -#define BIOS_BASE (0xe8000) -#define BIOS_SIZE (0x18000) -#else -#define BIOS_BASE (0xf0000) -#define BIOS_SIZE (0x10000) -#endif -#define BIOS_COUNT (BIOS_SIZE/4) - -#define CMOS_REG (0x70) -#define CMOS_DATA (0x71) -#define BIOS_RESET (0x0f) -#define BIOS_WARM (0x0a) - -#define PROCENTRY_FLAG_EN 0x01 -#define PROCENTRY_FLAG_BP 0x02 -#define IOAPICENTRY_FLAG_EN 0x01 - - -/* MP Floating Pointer Structure */ -typedef struct MPFPS { - char signature[4]; - void *pap; - u_char length; - u_char spec_rev; - u_char checksum; - u_char mpfb1; - u_char mpfb2; - u_char mpfb3; - u_char mpfb4; - u_char mpfb5; -} *mpfps_t; - -/* MP Configuration Table Header */ -typedef struct MPCTH { - char signature[4]; - u_short base_table_length; - u_char spec_rev; - u_char checksum; - u_char oem_id[8]; - u_char product_id[12]; - void *oem_table_pointer; - u_short oem_table_size; - u_short entry_count; - void *apic_address; - u_short extended_table_length; - u_char extended_table_checksum; - u_char reserved; -} *mpcth_t; - - -typedef struct PROCENTRY { - u_char type; - u_char apic_id; - u_char apic_version; - u_char cpu_flags; - u_long cpu_signature; - u_long feature_flags; - u_long reserved1; - u_long reserved2; -} *proc_entry_ptr; - -typedef struct BUSENTRY { - u_char type; - u_char bus_id; - char bus_type[6]; -} *bus_entry_ptr; - -typedef struct IOAPICENTRY { - u_char type; - u_char apic_id; - u_char apic_version; - u_char apic_flags; - void *apic_address; -} *io_apic_entry_ptr; - -typedef struct INTENTRY { - u_char type; - u_char int_type; - u_short int_flags; - u_char src_bus_id; - u_char src_bus_irq; - u_char dst_apic_id; - u_char dst_apic_int; -} *int_entry_ptr; - -/* descriptions of MP basetable entries */ -typedef struct BASETABLE_ENTRY { - u_char type; - u_char length; - char name[16]; -} basetable_entry; - -/* - * this code MUST be enabled here and in mpboot.s. - * it follows the very early stages of AP boot by placing values in CMOS ram. - * it NORMALLY will never be needed and thus the primitive method for enabling. - * -#define CHECK_POINTS - */ - -#if defined(CHECK_POINTS) && !defined(PC98) -#define CHECK_READ(A) (outb(CMOS_REG, (A)), inb(CMOS_DATA)) -#define CHECK_WRITE(A,D) (outb(CMOS_REG, (A)), outb(CMOS_DATA, (D))) - -#define CHECK_INIT(D); \ - CHECK_WRITE(0x34, (D)); \ - CHECK_WRITE(0x35, (D)); \ - CHECK_WRITE(0x36, (D)); \ - CHECK_WRITE(0x37, (D)); \ - CHECK_WRITE(0x38, (D)); \ - CHECK_WRITE(0x39, (D)); - -#define CHECK_PRINT(S); \ - printf("%s: %d, %d, %d, %d, %d, %d\n", \ - (S), \ - CHECK_READ(0x34), \ - CHECK_READ(0x35), \ - CHECK_READ(0x36), \ - CHECK_READ(0x37), \ - CHECK_READ(0x38), \ - CHECK_READ(0x39)); - -#else /* CHECK_POINTS */ - -#define CHECK_INIT(D) -#define CHECK_PRINT(S) - -#endif /* CHECK_POINTS */ - -/* - * Values to send to the POST hardware. - */ -#define MP_BOOTADDRESS_POST 0x10 -#define MP_PROBE_POST 0x11 -#define MPTABLE_PASS1_POST 0x12 - -#define MP_START_POST 0x13 -#define MP_ENABLE_POST 0x14 -#define MPTABLE_PASS2_POST 0x15 - -#define START_ALL_APS_POST 0x16 -#define INSTALL_AP_TRAMP_POST 0x17 -#define START_AP_POST 0x18 - -#define MP_ANNOUNCE_POST 0x19 - - -/** XXX FIXME: where does this really belong, isa.h/isa.c perhaps? */ -int current_postcode; - -/** XXX FIXME: what system files declare these??? */ -extern struct region_descriptor r_gdt, r_idt; - -int bsp_apic_ready = 0; /* flags useability of BSP apic */ -int mp_ncpus; /* # of CPUs, including BSP */ -int mp_naps; /* # of Applications processors */ -int mp_nbusses; /* # of busses */ -int mp_napics; /* # of IO APICs */ -int boot_cpu_id; /* designated BSP */ -vm_offset_t cpu_apic_address; -vm_offset_t io_apic_address[NAPICID]; /* NAPICID is more than enough */ -extern int nkpt; - -u_int32_t cpu_apic_versions[NCPU]; -u_int32_t io_apic_versions[NAPIC]; - -#ifdef APIC_INTR_DIAGNOSTIC -int apic_itrace_enter[32]; -int apic_itrace_tryisrlock[32]; -int apic_itrace_gotisrlock[32]; -int apic_itrace_active[32]; -int apic_itrace_masked[32]; -int apic_itrace_noisrlock[32]; -int apic_itrace_masked2[32]; -int apic_itrace_unmask[32]; -int apic_itrace_noforward[32]; -int apic_itrace_leave[32]; -int apic_itrace_enter2[32]; -int apic_itrace_doreti[32]; -int apic_itrace_splz[32]; -int apic_itrace_eoi[32]; -#ifdef APIC_INTR_DIAGNOSTIC_IRQ -unsigned short apic_itrace_debugbuffer[32768]; -int apic_itrace_debugbuffer_idx; -struct simplelock apic_itrace_debuglock; -#endif -#endif - -#ifdef APIC_INTR_REORDER -struct { - volatile int *location; - int bit; -} apic_isrbit_location[32]; -#endif - -struct apic_intmapinfo int_to_apicintpin[APIC_INTMAPSIZE]; - -/* - * APIC ID logical/physical mapping structures. - * We oversize these to simplify boot-time config. - */ -int cpu_num_to_apic_id[NAPICID]; -int io_num_to_apic_id[NAPICID]; -int apic_id_to_logical[NAPICID]; - - -/* Bitmap of all available CPUs */ -u_int all_cpus; - -/* AP uses this during bootstrap. Do not staticize. */ -char *bootSTK; -static int bootAP; - -/* Hotwire a 0->4MB V==P mapping */ -extern pt_entry_t *KPTphys; - -/* SMP page table page */ -extern pt_entry_t *SMPpt; - -struct pcb stoppcbs[NCPU]; - -int smp_started; /* has the system started? */ - -/* - * Local data and functions. - */ - -static int mp_capable; -static u_int boot_address; -static u_int base_memory; - -static int picmode; /* 0: virtual wire mode, 1: PIC mode */ -static mpfps_t mpfps; -static int search_for_sig(u_int32_t target, int count); -static void mp_enable(u_int boot_addr); - -static int mptable_pass1(void); -static int mptable_pass2(void); -static void default_mp_table(int type); -static void fix_mp_table(void); -static void setup_apic_irq_mapping(void); -static void init_locks(void); -static int start_all_aps(u_int boot_addr); -static void install_ap_tramp(u_int boot_addr); -static int start_ap(int logicalCpu, u_int boot_addr); -static int apic_int_is_bus_type(int intr, int bus_type); - -/* - * Calculate usable address in base memory for AP trampoline code. - */ -u_int -mp_bootaddress(u_int basemem) -{ - POSTCODE(MP_BOOTADDRESS_POST); - - base_memory = basemem * 1024; /* convert to bytes */ - - boot_address = base_memory & ~0xfff; /* round down to 4k boundary */ - if ((base_memory - boot_address) < bootMP_size) - boot_address -= 4096; /* not enough, lower by 4k */ - - return boot_address; -} - - -/* - * Look for an Intel MP spec table (ie, SMP capable hardware). - */ -int -mp_probe(void) -{ - int x; - u_long segment; - u_int32_t target; - - POSTCODE(MP_PROBE_POST); - - /* see if EBDA exists */ - if ((segment = (u_long) * (u_short *) (KERNBASE + 0x40e)) != 0) { - /* search first 1K of EBDA */ - target = (u_int32_t) (segment << 4); - if ((x = search_for_sig(target, 1024 / 4)) >= 0) - goto found; - } else { - /* last 1K of base memory, effective 'top of base' passed in */ - target = (u_int32_t) (base_memory - 0x400); - if ((x = search_for_sig(target, 1024 / 4)) >= 0) - goto found; - } - - /* search the BIOS */ - target = (u_int32_t) BIOS_BASE; - if ((x = search_for_sig(target, BIOS_COUNT)) >= 0) - goto found; - - /* nothing found */ - mpfps = (mpfps_t)0; - mp_capable = 0; - return 0; - -found: - /* calculate needed resources */ - mpfps = (mpfps_t)x; - if (mptable_pass1()) - panic("you must reconfigure your kernel"); - - /* flag fact that we are running multiple processors */ - mp_capable = 1; - return 1; -} - - -/* - * Startup the SMP processors. - */ -void -mp_start(void) -{ - POSTCODE(MP_START_POST); - - /* look for MP capable motherboard */ - if (mp_capable) - mp_enable(boot_address); - else - panic("MP hardware not found!"); -} - - -/* - * Print various information about the SMP system hardware and setup. - */ -void -mp_announce(void) -{ - int x; - - POSTCODE(MP_ANNOUNCE_POST); - - printf("FreeBSD/SMP: Multiprocessor motherboard\n"); - printf(" cpu0 (BSP): apic id: %2d", CPU_TO_ID(0)); - printf(", version: 0x%08x", cpu_apic_versions[0]); - printf(", at 0x%08x\n", cpu_apic_address); - for (x = 1; x <= mp_naps; ++x) { - printf(" cpu%d (AP): apic id: %2d", x, CPU_TO_ID(x)); - printf(", version: 0x%08x", cpu_apic_versions[x]); - printf(", at 0x%08x\n", cpu_apic_address); - } - -#if defined(APIC_IO) - for (x = 0; x < mp_napics; ++x) { - printf(" io%d (APIC): apic id: %2d", x, IO_TO_ID(x)); - printf(", version: 0x%08x", io_apic_versions[x]); - printf(", at 0x%08x\n", io_apic_address[x]); - } -#else - printf(" Warning: APIC I/O disabled\n"); -#endif /* APIC_IO */ -} - -/* - * AP cpu's call this to sync up protected mode. - */ -void -init_secondary(void) -{ - int gsel_tss; - int x, myid = bootAP; - - gdt_segs[GPRIV_SEL].ssd_base = (int) &SMP_prvspace[myid]; - gdt_segs[GPROC0_SEL].ssd_base = - (int) &SMP_prvspace[myid].globaldata.gd_common_tss; - SMP_prvspace[myid].globaldata.gd_prvspace = &SMP_prvspace[myid]; - - for (x = 0; x < NGDT; x++) { - ssdtosd(&gdt_segs[x], &gdt[myid * NGDT + x].sd); - } - - r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; - r_gdt.rd_base = (int) &gdt[myid * NGDT]; - lgdt(&r_gdt); /* does magic intra-segment return */ - - lidt(&r_idt); - - lldt(_default_ldt); -#ifdef USER_LDT - currentldt = _default_ldt; -#endif - - gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); - gdt[myid * NGDT + GPROC0_SEL].sd.sd_type = SDT_SYS386TSS; - common_tss.tss_esp0 = 0; /* not used until after switch */ - common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); - common_tss.tss_ioopt = (sizeof common_tss) << 16; - tss_gdt = &gdt[myid * NGDT + GPROC0_SEL].sd; - common_tssd = *tss_gdt; - ltr(gsel_tss); - - load_cr0(0x8005003b); /* XXX! */ - - pmap_set_opt(); -} - - -#if defined(APIC_IO) -/* - * Final configuration of the BSP's local APIC: - * - disable 'pic mode'. - * - disable 'virtual wire mode'. - * - enable NMI. - */ -void -bsp_apic_configure(void) -{ - u_char byte; - u_int32_t temp; - - /* leave 'pic mode' if necessary */ - if (picmode) { - outb(0x22, 0x70); /* select IMCR */ - byte = inb(0x23); /* current contents */ - byte |= 0x01; /* mask external INTR */ - outb(0x23, byte); /* disconnect 8259s/NMI */ - } - - /* mask lint0 (the 8259 'virtual wire' connection) */ - temp = lapic.lvt_lint0; - temp |= APIC_LVT_M; /* set the mask */ - lapic.lvt_lint0 = temp; - - /* setup lint1 to handle NMI */ - temp = lapic.lvt_lint1; - temp &= ~APIC_LVT_M; /* clear the mask */ - lapic.lvt_lint1 = temp; - - if (bootverbose) - apic_dump("bsp_apic_configure()"); -} -#endif /* APIC_IO */ - - -/******************************************************************* - * local functions and data - */ - -/* - * start the SMP system - */ -static void -mp_enable(u_int boot_addr) -{ - int x; -#if defined(APIC_IO) - int apic; - u_int ux; -#endif /* APIC_IO */ - - POSTCODE(MP_ENABLE_POST); - - /* turn on 4MB of V == P addressing so we can get to MP table */ - *(int *)PTD = PG_V | PG_RW | ((uintptr_t)(void *)KPTphys & PG_FRAME); - invltlb(); - - /* examine the MP table for needed info, uses physical addresses */ - x = mptable_pass2(); - - *(int *)PTD = 0; - invltlb(); - - /* can't process default configs till the CPU APIC is pmapped */ - if (x) - default_mp_table(x); - - /* post scan cleanup */ - fix_mp_table(); - setup_apic_irq_mapping(); - -#if defined(APIC_IO) - - /* fill the LOGICAL io_apic_versions table */ - for (apic = 0; apic < mp_napics; ++apic) { - ux = io_apic_read(apic, IOAPIC_VER); - io_apic_versions[apic] = ux; - } - - /* program each IO APIC in the system */ - for (apic = 0; apic < mp_napics; ++apic) - if (io_apic_setup(apic) < 0) - panic("IO APIC setup failure"); - - /* install a 'Spurious INTerrupt' vector */ - setidt(XSPURIOUSINT_OFFSET, Xspuriousint, - SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - - /* install an inter-CPU IPI for TLB invalidation */ - setidt(XINVLTLB_OFFSET, Xinvltlb, - SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - -#ifdef BETTER_CLOCK - /* install an inter-CPU IPI for reading processor state */ - setidt(XCPUCHECKSTATE_OFFSET, Xcpucheckstate, - SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); -#endif - - /* install an inter-CPU IPI for all-CPU rendezvous */ - setidt(XRENDEZVOUS_OFFSET, Xrendezvous, - SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - - /* install an inter-CPU IPI for forcing an additional software trap */ - setidt(XCPUAST_OFFSET, Xcpuast, - SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - - /* install an inter-CPU IPI for interrupt forwarding */ - setidt(XFORWARD_IRQ_OFFSET, Xforward_irq, - SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - - /* install an inter-CPU IPI for CPU stop/restart */ - setidt(XCPUSTOP_OFFSET, Xcpustop, - SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - -#if defined(TEST_TEST1) - /* install a "fake hardware INTerrupt" vector */ - setidt(XTEST1_OFFSET, Xtest1, - SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); -#endif /** TEST_TEST1 */ - -#endif /* APIC_IO */ - - /* initialize all SMP locks */ - init_locks(); - - /* start each Application Processor */ - start_all_aps(boot_addr); - - /* - * The init process might be started on a different CPU now, - * and the boot CPU might not call prepare_usermode to get - * cr0 correctly configured. Thus we initialize cr0 here. - */ - load_cr0(rcr0() | CR0_WP | CR0_AM); -} - - -/* - * look for the MP spec signature - */ - -/* string defined by the Intel MP Spec as identifying the MP table */ -#define MP_SIG 0x5f504d5f /* _MP_ */ -#define NEXT(X) ((X) += 4) -static int -search_for_sig(u_int32_t target, int count) -{ - int x; - u_int32_t *addr = (u_int32_t *) (KERNBASE + target); - - for (x = 0; x < count; NEXT(x)) - if (addr[x] == MP_SIG) - /* make array index a byte index */ - return (target + (x * sizeof(u_int32_t))); - - return -1; -} - - -static basetable_entry basetable_entry_types[] = -{ - {0, 20, "Processor"}, - {1, 8, "Bus"}, - {2, 8, "I/O APIC"}, - {3, 8, "I/O INT"}, - {4, 8, "Local INT"} -}; - -typedef struct BUSDATA { - u_char bus_id; - enum busTypes bus_type; -} bus_datum; - -typedef struct INTDATA { - u_char int_type; - u_short int_flags; - u_char src_bus_id; - u_char src_bus_irq; - u_char dst_apic_id; - u_char dst_apic_int; - u_char int_vector; -} io_int, local_int; - -typedef struct BUSTYPENAME { - u_char type; - char name[7]; -} bus_type_name; - -static bus_type_name bus_type_table[] = -{ - {CBUS, "CBUS"}, - {CBUSII, "CBUSII"}, - {EISA, "EISA"}, - {MCA, "MCA"}, - {UNKNOWN_BUSTYPE, "---"}, - {ISA, "ISA"}, - {MCA, "MCA"}, - {UNKNOWN_BUSTYPE, "---"}, - {UNKNOWN_BUSTYPE, "---"}, - {UNKNOWN_BUSTYPE, "---"}, - {UNKNOWN_BUSTYPE, "---"}, - {UNKNOWN_BUSTYPE, "---"}, - {PCI, "PCI"}, - {UNKNOWN_BUSTYPE, "---"}, - {UNKNOWN_BUSTYPE, "---"}, - {UNKNOWN_BUSTYPE, "---"}, - {UNKNOWN_BUSTYPE, "---"}, - {XPRESS, "XPRESS"}, - {UNKNOWN_BUSTYPE, "---"} -}; -/* from MP spec v1.4, table 5-1 */ -static int default_data[7][5] = -{ -/* nbus, id0, type0, id1, type1 */ - {1, 0, ISA, 255, 255}, - {1, 0, EISA, 255, 255}, - {1, 0, EISA, 255, 255}, - {1, 0, MCA, 255, 255}, - {2, 0, ISA, 1, PCI}, - {2, 0, EISA, 1, PCI}, - {2, 0, MCA, 1, PCI} -}; - - -/* the bus data */ -static bus_datum bus_data[NBUS]; - -/* the IO INT data, one entry per possible APIC INTerrupt */ -static io_int io_apic_ints[NINTR]; - -static int nintrs; - -static int processor_entry __P((proc_entry_ptr entry, int cpu)); -static int bus_entry __P((bus_entry_ptr entry, int bus)); -static int io_apic_entry __P((io_apic_entry_ptr entry, int apic)); -static int int_entry __P((int_entry_ptr entry, int intr)); -static int lookup_bus_type __P((char *name)); - - -/* - * 1st pass on motherboard's Intel MP specification table. - * - * initializes: - * mp_ncpus = 1 - * - * determines: - * cpu_apic_address (common to all CPUs) - * io_apic_address[N] - * mp_naps - * mp_nbusses - * mp_napics - * nintrs - */ -static int -mptable_pass1(void) -{ - int x; - mpcth_t cth; - int totalSize; - void* position; - int count; - int type; - int mustpanic; - - POSTCODE(MPTABLE_PASS1_POST); - - mustpanic = 0; - - /* clear various tables */ - for (x = 0; x < NAPICID; ++x) { - io_apic_address[x] = ~0; /* IO APIC address table */ - } - - /* init everything to empty */ - mp_naps = 0; - mp_nbusses = 0; - mp_napics = 0; - nintrs = 0; - - /* check for use of 'default' configuration */ - if (MPFPS_MPFB1 != 0) { - /* use default addresses */ - cpu_apic_address = DEFAULT_APIC_BASE; - io_apic_address[0] = DEFAULT_IO_APIC_BASE; - - /* fill in with defaults */ - mp_naps = 2; /* includes BSP */ - mp_nbusses = default_data[MPFPS_MPFB1 - 1][0]; -#if defined(APIC_IO) - mp_napics = 1; - nintrs = 16; -#endif /* APIC_IO */ - } - else { - if ((cth = mpfps->pap) == 0) - panic("MP Configuration Table Header MISSING!"); - - cpu_apic_address = (vm_offset_t) cth->apic_address; - - /* walk the table, recording info of interest */ - totalSize = cth->base_table_length - sizeof(struct MPCTH); - position = (u_char *) cth + sizeof(struct MPCTH); - count = cth->entry_count; - - while (count--) { - switch (type = *(u_char *) position) { - case 0: /* processor_entry */ - if (((proc_entry_ptr)position)->cpu_flags - & PROCENTRY_FLAG_EN) - ++mp_naps; - break; - case 1: /* bus_entry */ - ++mp_nbusses; - break; - case 2: /* io_apic_entry */ - if (((io_apic_entry_ptr)position)->apic_flags - & IOAPICENTRY_FLAG_EN) - io_apic_address[mp_napics++] = - (vm_offset_t)((io_apic_entry_ptr) - position)->apic_address; - break; - case 3: /* int_entry */ - ++nintrs; - break; - case 4: /* int_entry */ - break; - default: - panic("mpfps Base Table HOSED!"); - /* NOTREACHED */ - } - - totalSize -= basetable_entry_types[type].length; - (u_char*)position += basetable_entry_types[type].length; - } - } - - /* qualify the numbers */ - if (mp_naps > NCPU) { - printf("Warning: only using %d of %d available CPUs!\n", - NCPU, mp_naps); - mp_naps = NCPU; - } - if (mp_nbusses > NBUS) { - printf("found %d busses, increase NBUS\n", mp_nbusses); - mustpanic = 1; - } - if (mp_napics > NAPIC) { - printf("found %d apics, increase NAPIC\n", mp_napics); - mustpanic = 1; - } - if (nintrs > NINTR) { - printf("found %d intrs, increase NINTR\n", nintrs); - mustpanic = 1; - } - - /* - * Count the BSP. - * This is also used as a counter while starting the APs. - */ - mp_ncpus = 1; - - --mp_naps; /* subtract the BSP */ - - return mustpanic; -} - - -/* - * 2nd pass on motherboard's Intel MP specification table. - * - * sets: - * boot_cpu_id - * ID_TO_IO(N), phy APIC ID to log CPU/IO table - * CPU_TO_ID(N), logical CPU to APIC ID table - * IO_TO_ID(N), logical IO to APIC ID table - * bus_data[N] - * io_apic_ints[N] - */ -static int -mptable_pass2(void) -{ - int x; - mpcth_t cth; - int totalSize; - void* position; - int count; - int type; - int apic, bus, cpu, intr; - - POSTCODE(MPTABLE_PASS2_POST); - - /* clear various tables */ - for (x = 0; x < NAPICID; ++x) { - ID_TO_IO(x) = -1; /* phy APIC ID to log CPU/IO table */ - CPU_TO_ID(x) = -1; /* logical CPU to APIC ID table */ - IO_TO_ID(x) = -1; /* logical IO to APIC ID table */ - } - - /* clear bus data table */ - for (x = 0; x < NBUS; ++x) - bus_data[x].bus_id = 0xff; - - /* clear IO APIC INT table */ - for (x = 0; x < NINTR; ++x) { - io_apic_ints[x].int_type = 0xff; - io_apic_ints[x].int_vector = 0xff; - } - - /* setup the cpu/apic mapping arrays */ - boot_cpu_id = -1; - - /* record whether PIC or virtual-wire mode */ - picmode = (mpfps->mpfb2 & 0x80) ? 1 : 0; - - /* check for use of 'default' configuration */ - if (MPFPS_MPFB1 != 0) - return MPFPS_MPFB1; /* return default configuration type */ - - if ((cth = mpfps->pap) == 0) - panic("MP Configuration Table Header MISSING!"); - - /* walk the table, recording info of interest */ - totalSize = cth->base_table_length - sizeof(struct MPCTH); - position = (u_char *) cth + sizeof(struct MPCTH); - count = cth->entry_count; - apic = bus = intr = 0; - cpu = 1; /* pre-count the BSP */ - - while (count--) { - switch (type = *(u_char *) position) { - case 0: - if (processor_entry(position, cpu)) - ++cpu; - break; - case 1: - if (bus_entry(position, bus)) - ++bus; - break; - case 2: - if (io_apic_entry(position, apic)) - ++apic; - break; - case 3: - if (int_entry(position, intr)) - ++intr; - break; - case 4: - /* int_entry(position); */ - break; - default: - panic("mpfps Base Table HOSED!"); - /* NOTREACHED */ - } - - totalSize -= basetable_entry_types[type].length; - (u_char *) position += basetable_entry_types[type].length; - } - - if (boot_cpu_id == -1) - panic("NO BSP found!"); - - /* report fact that its NOT a default configuration */ - return 0; -} - - -void -assign_apic_irq(int apic, int intpin, int irq) -{ - int x; - - if (int_to_apicintpin[irq].ioapic != -1) - panic("assign_apic_irq: inconsistent table"); - - int_to_apicintpin[irq].ioapic = apic; - int_to_apicintpin[irq].int_pin = intpin; - int_to_apicintpin[irq].apic_address = ioapic[apic]; - int_to_apicintpin[irq].redirindex = IOAPIC_REDTBL + 2 * intpin; - - for (x = 0; x < nintrs; x++) { - if ((io_apic_ints[x].int_type == 0 || - io_apic_ints[x].int_type == 3) && - io_apic_ints[x].int_vector == 0xff && - io_apic_ints[x].dst_apic_id == IO_TO_ID(apic) && - io_apic_ints[x].dst_apic_int == intpin) - io_apic_ints[x].int_vector = irq; - } -} - -void -revoke_apic_irq(int irq) -{ - int x; - int oldapic; - int oldintpin; - - if (int_to_apicintpin[irq].ioapic == -1) - panic("assign_apic_irq: inconsistent table"); - - oldapic = int_to_apicintpin[irq].ioapic; - oldintpin = int_to_apicintpin[irq].int_pin; - - int_to_apicintpin[irq].ioapic = -1; - int_to_apicintpin[irq].int_pin = 0; - int_to_apicintpin[irq].apic_address = NULL; - int_to_apicintpin[irq].redirindex = 0; - - for (x = 0; x < nintrs; x++) { - if ((io_apic_ints[x].int_type == 0 || - io_apic_ints[x].int_type == 3) && - io_apic_ints[x].int_vector == 0xff && - io_apic_ints[x].dst_apic_id == IO_TO_ID(oldapic) && - io_apic_ints[x].dst_apic_int == oldintpin) - io_apic_ints[x].int_vector = 0xff; - } -} - -/* - * parse an Intel MP specification table - */ -static void -fix_mp_table(void) -{ - int x; - int id; - int bus_0 = 0; /* Stop GCC warning */ - int bus_pci = 0; /* Stop GCC warning */ - int num_pci_bus; - - /* - * Fix mis-numbering of the PCI bus and its INT entries if the BIOS - * did it wrong. The MP spec says that when more than 1 PCI bus - * exists the BIOS must begin with bus entries for the PCI bus and use - * actual PCI bus numbering. This implies that when only 1 PCI bus - * exists the BIOS can choose to ignore this ordering, and indeed many - * MP motherboards do ignore it. This causes a problem when the PCI - * sub-system makes requests of the MP sub-system based on PCI bus - * numbers. So here we look for the situation and renumber the - * busses and associated INTs in an effort to "make it right". - */ - - /* find bus 0, PCI bus, count the number of PCI busses */ - for (num_pci_bus = 0, x = 0; x < mp_nbusses; ++x) { - if (bus_data[x].bus_id == 0) { - bus_0 = x; - } - if (bus_data[x].bus_type == PCI) { - ++num_pci_bus; - bus_pci = x; - } - } - /* - * bus_0 == slot of bus with ID of 0 - * bus_pci == slot of last PCI bus encountered - */ - - /* check the 1 PCI bus case for sanity */ - if (num_pci_bus == 1) { - - /* if it is number 0 all is well */ - if (bus_data[bus_pci].bus_id == 0) - return; - - /* mis-numbered, swap with whichever bus uses slot 0 */ - - /* swap the bus entry types */ - bus_data[bus_pci].bus_type = bus_data[bus_0].bus_type; - bus_data[bus_0].bus_type = PCI; - - /* swap each relavant INTerrupt entry */ - id = bus_data[bus_pci].bus_id; - for (x = 0; x < nintrs; ++x) { - if (io_apic_ints[x].src_bus_id == id) { - io_apic_ints[x].src_bus_id = 0; - } - else if (io_apic_ints[x].src_bus_id == 0) { - io_apic_ints[x].src_bus_id = id; - } - } - } -} - - -/* Assign low level interrupt handlers */ -static void -setup_apic_irq_mapping(void) -{ - int x; - int int_vector; - - /* Clear array */ - for (x = 0; x < APIC_INTMAPSIZE; x++) { - int_to_apicintpin[x].ioapic = -1; - int_to_apicintpin[x].int_pin = 0; - int_to_apicintpin[x].apic_address = NULL; - int_to_apicintpin[x].redirindex = 0; - } - - /* First assign ISA/EISA interrupts */ - for (x = 0; x < nintrs; x++) { - int_vector = io_apic_ints[x].src_bus_irq; - if (int_vector < APIC_INTMAPSIZE && - io_apic_ints[x].int_vector == 0xff && - int_to_apicintpin[int_vector].ioapic == -1 && - (apic_int_is_bus_type(x, ISA) || - apic_int_is_bus_type(x, EISA)) && - io_apic_ints[x].int_type == 0) { - assign_apic_irq(ID_TO_IO(io_apic_ints[x].dst_apic_id), - io_apic_ints[x].dst_apic_int, - int_vector); - } - } - - /* Assign interrupts on first 24 intpins on IOAPIC #0 */ - for (x = 0; x < nintrs; x++) { - int_vector = io_apic_ints[x].dst_apic_int; - if (int_vector < APIC_INTMAPSIZE && - io_apic_ints[x].dst_apic_id == IO_TO_ID(0) && - io_apic_ints[x].int_vector == 0xff && - int_to_apicintpin[int_vector].ioapic == -1 && - (io_apic_ints[x].int_type == 0 || - io_apic_ints[x].int_type == 3)) { - assign_apic_irq(0, - io_apic_ints[x].dst_apic_int, - int_vector); - } - } - /* - * Assign interrupts for remaining intpins. - * Skip IOAPIC #0 intpin 0 if the type is ExtInt, since this indicates - * that an entry for ISA/EISA irq 0 exist, and a fallback to mixed mode - * due to 8254 interrupts not being delivered can reuse that low level - * interrupt handler. - */ - int_vector = 0; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; - for (x = 0; x < nintrs && int_vector < APIC_INTMAPSIZE; x++) { - if ((io_apic_ints[x].int_type == 0 || - (io_apic_ints[x].int_type == 3 && - (io_apic_ints[x].dst_apic_id != IO_TO_ID(0) || - io_apic_ints[x].dst_apic_int != 0))) && - io_apic_ints[x].int_vector == 0xff) { - assign_apic_irq(ID_TO_IO(io_apic_ints[x].dst_apic_id), - io_apic_ints[x].dst_apic_int, - int_vector); - int_vector++; - while (int_vector < APIC_INTMAPSIZE && - int_to_apicintpin[int_vector].ioapic != -1) - int_vector++; - } - } -} - - -static int -processor_entry(proc_entry_ptr entry, int cpu) -{ - /* check for usability */ - if (!(entry->cpu_flags & PROCENTRY_FLAG_EN)) - return 0; - - /* check for BSP flag */ - if (entry->cpu_flags & PROCENTRY_FLAG_BP) { - boot_cpu_id = entry->apic_id; - CPU_TO_ID(0) = entry->apic_id; - ID_TO_CPU(entry->apic_id) = 0; - return 0; /* its already been counted */ - } - - /* add another AP to list, if less than max number of CPUs */ - else if (cpu < NCPU) { - CPU_TO_ID(cpu) = entry->apic_id; - ID_TO_CPU(entry->apic_id) = cpu; - return 1; - } - - return 0; -} - - -static int -bus_entry(bus_entry_ptr entry, int bus) -{ - int x; - char c, name[8]; - - /* encode the name into an index */ - for (x = 0; x < 6; ++x) { - if ((c = entry->bus_type[x]) == ' ') - break; - name[x] = c; - } - name[x] = '\0'; - - if ((x = lookup_bus_type(name)) == UNKNOWN_BUSTYPE) - panic("unknown bus type: '%s'", name); - - bus_data[bus].bus_id = entry->bus_id; - bus_data[bus].bus_type = x; - - return 1; -} - - -static int -io_apic_entry(io_apic_entry_ptr entry, int apic) -{ - if (!(entry->apic_flags & IOAPICENTRY_FLAG_EN)) - return 0; - - IO_TO_ID(apic) = entry->apic_id; - ID_TO_IO(entry->apic_id) = apic; - - return 1; -} - - -static int -lookup_bus_type(char *name) -{ - int x; - - for (x = 0; x < MAX_BUSTYPE; ++x) - if (strcmp(bus_type_table[x].name, name) == 0) - return bus_type_table[x].type; - - return UNKNOWN_BUSTYPE; -} - - -static int -int_entry(int_entry_ptr entry, int intr) -{ - int apic; - - io_apic_ints[intr].int_type = entry->int_type; - io_apic_ints[intr].int_flags = entry->int_flags; - io_apic_ints[intr].src_bus_id = entry->src_bus_id; - io_apic_ints[intr].src_bus_irq = entry->src_bus_irq; - if (entry->dst_apic_id == 255) { - /* This signal goes to all IO APICS. Select an IO APIC - with sufficient number of interrupt pins */ - for (apic = 0; apic < mp_napics; apic++) - if (((io_apic_read(apic, IOAPIC_VER) & - IOART_VER_MAXREDIR) >> MAXREDIRSHIFT) >= - entry->dst_apic_int) - break; - if (apic < mp_napics) - io_apic_ints[intr].dst_apic_id = IO_TO_ID(apic); - else - io_apic_ints[intr].dst_apic_id = entry->dst_apic_id; - } else - io_apic_ints[intr].dst_apic_id = entry->dst_apic_id; - io_apic_ints[intr].dst_apic_int = entry->dst_apic_int; - - return 1; -} - - -static int -apic_int_is_bus_type(int intr, int bus_type) -{ - int bus; - - for (bus = 0; bus < mp_nbusses; ++bus) - if ((bus_data[bus].bus_id == io_apic_ints[intr].src_bus_id) - && ((int) bus_data[bus].bus_type == bus_type)) - return 1; - - return 0; -} - - -/* - * Given a traditional ISA INT mask, return an APIC mask. - */ -u_int -isa_apic_mask(u_int isa_mask) -{ - int isa_irq; - int apic_pin; - -#if defined(SKIP_IRQ15_REDIRECT) - if (isa_mask == (1 << 15)) { - printf("skipping ISA IRQ15 redirect\n"); - return isa_mask; - } -#endif /* SKIP_IRQ15_REDIRECT */ - - isa_irq = ffs(isa_mask); /* find its bit position */ - if (isa_irq == 0) /* doesn't exist */ - return 0; - --isa_irq; /* make it zero based */ - - apic_pin = isa_apic_irq(isa_irq); /* look for APIC connection */ - if (apic_pin == -1) - return 0; - - return (1 << apic_pin); /* convert pin# to a mask */ -} - - -/* - * Determine which APIC pin an ISA/EISA INT is attached to. - */ -#define INTTYPE(I) (io_apic_ints[(I)].int_type) -#define INTPIN(I) (io_apic_ints[(I)].dst_apic_int) -#define INTIRQ(I) (io_apic_ints[(I)].int_vector) -#define INTAPIC(I) (ID_TO_IO(io_apic_ints[(I)].dst_apic_id)) - -#define SRCBUSIRQ(I) (io_apic_ints[(I)].src_bus_irq) -int -isa_apic_irq(int isa_irq) -{ - int intr; - - for (intr = 0; intr < nintrs; ++intr) { /* check each record */ - if (INTTYPE(intr) == 0) { /* standard INT */ - if (SRCBUSIRQ(intr) == isa_irq) { - if (apic_int_is_bus_type(intr, ISA) || - apic_int_is_bus_type(intr, EISA)) - return INTIRQ(intr); /* found */ - } - } - } - return -1; /* NOT found */ -} - - -/* - * Determine which APIC pin a PCI INT is attached to. - */ -#define SRCBUSID(I) (io_apic_ints[(I)].src_bus_id) -#define SRCBUSDEVICE(I) ((io_apic_ints[(I)].src_bus_irq >> 2) & 0x1f) -#define SRCBUSLINE(I) (io_apic_ints[(I)].src_bus_irq & 0x03) -int -pci_apic_irq(int pciBus, int pciDevice, int pciInt) -{ - int intr; - - --pciInt; /* zero based */ - - for (intr = 0; intr < nintrs; ++intr) /* check each record */ - if ((INTTYPE(intr) == 0) /* standard INT */ - && (SRCBUSID(intr) == pciBus) - && (SRCBUSDEVICE(intr) == pciDevice) - && (SRCBUSLINE(intr) == pciInt)) /* a candidate IRQ */ - if (apic_int_is_bus_type(intr, PCI)) - return INTIRQ(intr); /* exact match */ - - return -1; /* NOT found */ -} - -int -next_apic_irq(int irq) -{ - int intr, ointr; - int bus, bustype; - - bus = 0; - bustype = 0; - for (intr = 0; intr < nintrs; intr++) { - if (INTIRQ(intr) != irq || INTTYPE(intr) != 0) - continue; - bus = SRCBUSID(intr); - bustype = apic_bus_type(bus); - if (bustype != ISA && - bustype != EISA && - bustype != PCI) - continue; - break; - } - if (intr >= nintrs) { - return -1; - } - for (ointr = intr + 1; ointr < nintrs; ointr++) { - if (INTTYPE(ointr) != 0) - continue; - if (bus != SRCBUSID(ointr)) - continue; - if (bustype == PCI) { - if (SRCBUSDEVICE(intr) != SRCBUSDEVICE(ointr)) - continue; - if (SRCBUSLINE(intr) != SRCBUSLINE(ointr)) - continue; - } - if (bustype == ISA || bustype == EISA) { - if (SRCBUSIRQ(intr) != SRCBUSIRQ(ointr)) - continue; - } - if (INTPIN(intr) == INTPIN(ointr)) - continue; - break; - } - if (ointr >= nintrs) { - return -1; - } - return INTIRQ(ointr); -} -#undef SRCBUSLINE -#undef SRCBUSDEVICE -#undef SRCBUSID -#undef SRCBUSIRQ - -#undef INTPIN -#undef INTIRQ -#undef INTAPIC -#undef INTTYPE - - -/* - * Reprogram the MB chipset to NOT redirect an ISA INTerrupt. - * - * XXX FIXME: - * Exactly what this means is unclear at this point. It is a solution - * for motherboards that redirect the MBIRQ0 pin. Generically a motherboard - * could route any of the ISA INTs to upper (>15) IRQ values. But most would - * NOT be redirected via MBIRQ0, thus "undirect()ing" them would NOT be an - * option. - */ -int -undirect_isa_irq(int rirq) -{ -#if defined(READY) - if (bootverbose) - printf("Freeing redirected ISA irq %d.\n", rirq); - /** FIXME: tickle the MB redirector chip */ - return ???; -#else - if (bootverbose) - printf("Freeing (NOT implemented) redirected ISA irq %d.\n", rirq); - return 0; -#endif /* READY */ -} - - -/* - * Reprogram the MB chipset to NOT redirect a PCI INTerrupt - */ -int -undirect_pci_irq(int rirq) -{ -#if defined(READY) - if (bootverbose) - printf("Freeing redirected PCI irq %d.\n", rirq); - - /** FIXME: tickle the MB redirector chip */ - return ???; -#else - if (bootverbose) - printf("Freeing (NOT implemented) redirected PCI irq %d.\n", - rirq); - return 0; -#endif /* READY */ -} - - -/* - * given a bus ID, return: - * the bus type if found - * -1 if NOT found - */ -int -apic_bus_type(int id) -{ - int x; - - for (x = 0; x < mp_nbusses; ++x) - if (bus_data[x].bus_id == id) - return bus_data[x].bus_type; - - return -1; -} - - -/* - * given a LOGICAL APIC# and pin#, return: - * the associated src bus ID if found - * -1 if NOT found - */ -int -apic_src_bus_id(int apic, int pin) -{ - int x; - - /* search each of the possible INTerrupt sources */ - for (x = 0; x < nintrs; ++x) - if ((apic == ID_TO_IO(io_apic_ints[x].dst_apic_id)) && - (pin == io_apic_ints[x].dst_apic_int)) - return (io_apic_ints[x].src_bus_id); - - return -1; /* NOT found */ -} - - -/* - * given a LOGICAL APIC# and pin#, return: - * the associated src bus IRQ if found - * -1 if NOT found - */ -int -apic_src_bus_irq(int apic, int pin) -{ - int x; - - for (x = 0; x < nintrs; x++) - if ((apic == ID_TO_IO(io_apic_ints[x].dst_apic_id)) && - (pin == io_apic_ints[x].dst_apic_int)) - return (io_apic_ints[x].src_bus_irq); - - return -1; /* NOT found */ -} - - -/* - * given a LOGICAL APIC# and pin#, return: - * the associated INTerrupt type if found - * -1 if NOT found - */ -int -apic_int_type(int apic, int pin) -{ - int x; - - /* search each of the possible INTerrupt sources */ - for (x = 0; x < nintrs; ++x) - if ((apic == ID_TO_IO(io_apic_ints[x].dst_apic_id)) && - (pin == io_apic_ints[x].dst_apic_int)) - return (io_apic_ints[x].int_type); - - return -1; /* NOT found */ -} - -int -apic_irq(int apic, int pin) -{ - int x; - int res; - - for (x = 0; x < nintrs; ++x) - if ((apic == ID_TO_IO(io_apic_ints[x].dst_apic_id)) && - (pin == io_apic_ints[x].dst_apic_int)) { - res = io_apic_ints[x].int_vector; - if (res == 0xff) - return -1; - if (apic != int_to_apicintpin[res].ioapic) - panic("apic_irq: inconsistent table"); - if (pin != int_to_apicintpin[res].int_pin) - panic("apic_irq inconsistent table (2)"); - return res; - } - return -1; -} - - -/* - * given a LOGICAL APIC# and pin#, return: - * the associated trigger mode if found - * -1 if NOT found - */ -int -apic_trigger(int apic, int pin) -{ - int x; - - /* search each of the possible INTerrupt sources */ - for (x = 0; x < nintrs; ++x) - if ((apic == ID_TO_IO(io_apic_ints[x].dst_apic_id)) && - (pin == io_apic_ints[x].dst_apic_int)) - return ((io_apic_ints[x].int_flags >> 2) & 0x03); - - return -1; /* NOT found */ -} - - -/* - * given a LOGICAL APIC# and pin#, return: - * the associated 'active' level if found - * -1 if NOT found - */ -int -apic_polarity(int apic, int pin) -{ - int x; - - /* search each of the possible INTerrupt sources */ - for (x = 0; x < nintrs; ++x) - if ((apic == ID_TO_IO(io_apic_ints[x].dst_apic_id)) && - (pin == io_apic_ints[x].dst_apic_int)) - return (io_apic_ints[x].int_flags & 0x03); - - return -1; /* NOT found */ -} - - -/* - * set data according to MP defaults - * FIXME: probably not complete yet... - */ -static void -default_mp_table(int type) -{ - int ap_cpu_id; -#if defined(APIC_IO) - u_int32_t ux; - int io_apic_id; - int pin; -#endif /* APIC_IO */ - -#if 0 - printf(" MP default config type: %d\n", type); - switch (type) { - case 1: - printf(" bus: ISA, APIC: 82489DX\n"); - break; - case 2: - printf(" bus: EISA, APIC: 82489DX\n"); - break; - case 3: - printf(" bus: EISA, APIC: 82489DX\n"); - break; - case 4: - printf(" bus: MCA, APIC: 82489DX\n"); - break; - case 5: - printf(" bus: ISA+PCI, APIC: Integrated\n"); - break; - case 6: - printf(" bus: EISA+PCI, APIC: Integrated\n"); - break; - case 7: - printf(" bus: MCA+PCI, APIC: Integrated\n"); - break; - default: - printf(" future type\n"); - break; - /* NOTREACHED */ - } -#endif /* 0 */ - - boot_cpu_id = (lapic.id & APIC_ID_MASK) >> 24; - ap_cpu_id = (boot_cpu_id == 0) ? 1 : 0; - - /* BSP */ - CPU_TO_ID(0) = boot_cpu_id; - ID_TO_CPU(boot_cpu_id) = 0; - - /* one and only AP */ - CPU_TO_ID(1) = ap_cpu_id; - ID_TO_CPU(ap_cpu_id) = 1; - -#if defined(APIC_IO) - /* one and only IO APIC */ - io_apic_id = (io_apic_read(0, IOAPIC_ID) & APIC_ID_MASK) >> 24; - - /* - * sanity check, refer to MP spec section 3.6.6, last paragraph - * necessary as some hardware isn't properly setting up the IO APIC - */ -#if defined(REALLY_ANAL_IOAPICID_VALUE) - if (io_apic_id != 2) { -#else - if ((io_apic_id == 0) || (io_apic_id == 1) || (io_apic_id == 15)) { -#endif /* REALLY_ANAL_IOAPICID_VALUE */ - ux = io_apic_read(0, IOAPIC_ID); /* get current contents */ - ux &= ~APIC_ID_MASK; /* clear the ID field */ - ux |= 0x02000000; /* set it to '2' */ - io_apic_write(0, IOAPIC_ID, ux); /* write new value */ - ux = io_apic_read(0, IOAPIC_ID); /* re-read && test */ - if ((ux & APIC_ID_MASK) != 0x02000000) - panic("can't control IO APIC ID, reg: 0x%08x", ux); - io_apic_id = 2; - } - IO_TO_ID(0) = io_apic_id; - ID_TO_IO(io_apic_id) = 0; -#endif /* APIC_IO */ - - /* fill out bus entries */ - switch (type) { - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - bus_data[0].bus_id = default_data[type - 1][1]; - bus_data[0].bus_type = default_data[type - 1][2]; - bus_data[1].bus_id = default_data[type - 1][3]; - bus_data[1].bus_type = default_data[type - 1][4]; - break; - - /* case 4: case 7: MCA NOT supported */ - default: /* illegal/reserved */ - panic("BAD default MP config: %d", type); - /* NOTREACHED */ - } - -#if defined(APIC_IO) - /* general cases from MP v1.4, table 5-2 */ - for (pin = 0; pin < 16; ++pin) { - io_apic_ints[pin].int_type = 0; - io_apic_ints[pin].int_flags = 0x05; /* edge/active-hi */ - io_apic_ints[pin].src_bus_id = 0; - io_apic_ints[pin].src_bus_irq = pin; /* IRQ2 caught below */ - io_apic_ints[pin].dst_apic_id = io_apic_id; - io_apic_ints[pin].dst_apic_int = pin; /* 1-to-1 */ - } - - /* special cases from MP v1.4, table 5-2 */ - if (type == 2) { - io_apic_ints[2].int_type = 0xff; /* N/C */ - io_apic_ints[13].int_type = 0xff; /* N/C */ -#if !defined(APIC_MIXED_MODE) - /** FIXME: ??? */ - panic("sorry, can't support type 2 default yet"); -#endif /* APIC_MIXED_MODE */ - } - else - io_apic_ints[2].src_bus_irq = 0; /* ISA IRQ0 is on APIC INT 2 */ - - if (type == 7) - io_apic_ints[0].int_type = 0xff; /* N/C */ - else - io_apic_ints[0].int_type = 3; /* vectored 8259 */ -#endif /* APIC_IO */ -} - - -/* - * initialize all the SMP locks - */ - -/* critical region around IO APIC, apic_imen */ -struct simplelock imen_lock; - -/* critical region around splxx(), cpl, cml, cil, ipending */ -struct simplelock cpl_lock; - -/* Make FAST_INTR() routines sequential */ -struct simplelock fast_intr_lock; - -/* critical region around INTR() routines */ -struct simplelock intr_lock; - -/* lock regions protected in UP kernel via cli/sti */ -struct simplelock mpintr_lock; - -/* lock region used by kernel profiling */ -struct simplelock mcount_lock; - -#ifdef USE_COMLOCK -/* locks com (tty) data/hardware accesses: a FASTINTR() */ -struct simplelock com_lock; -#endif /* USE_COMLOCK */ - -#ifdef USE_CLOCKLOCK -/* lock regions around the clock hardware */ -struct simplelock clock_lock; -#endif /* USE_CLOCKLOCK */ - -/* lock around the MP rendezvous */ -static struct simplelock smp_rv_lock; - -static void -init_locks(void) -{ - /* - * Get the initial mp_lock with a count of 1 for the BSP. - * This uses a LOGICAL cpu ID, ie BSP == 0. - */ - mp_lock = 0x00000001; - - /* ISR uses its own "giant lock" */ - isr_lock = FREE_LOCK; - -#if defined(APIC_INTR_DIAGNOSTIC) && defined(APIC_INTR_DIAGNOSTIC_IRQ) - s_lock_init((struct simplelock*)&apic_itrace_debuglock); -#endif - - s_lock_init((struct simplelock*)&mpintr_lock); - - s_lock_init((struct simplelock*)&mcount_lock); - - s_lock_init((struct simplelock*)&fast_intr_lock); - s_lock_init((struct simplelock*)&intr_lock); - s_lock_init((struct simplelock*)&imen_lock); - s_lock_init((struct simplelock*)&cpl_lock); - s_lock_init(&smp_rv_lock); - -#ifdef USE_COMLOCK - s_lock_init((struct simplelock*)&com_lock); -#endif /* USE_COMLOCK */ -#ifdef USE_CLOCKLOCK - s_lock_init((struct simplelock*)&clock_lock); -#endif /* USE_CLOCKLOCK */ -} - - -/* Wait for all APs to be fully initialized */ -extern int wait_ap(unsigned int); - -/* - * start each AP in our list - */ -static int -start_all_aps(u_int boot_addr) -{ - int x, i, pg; - u_char mpbiosreason; - u_long mpbioswarmvec; - struct globaldata *gd; - char *stack; - - POSTCODE(START_ALL_APS_POST); - - /* initialize BSP's local APIC */ - apic_initialize(); - bsp_apic_ready = 1; - - /* install the AP 1st level boot code */ - install_ap_tramp(boot_addr); - - - /* save the current value of the warm-start vector */ - mpbioswarmvec = *((u_long *) WARMBOOT_OFF); -#ifndef PC98 - outb(CMOS_REG, BIOS_RESET); - mpbiosreason = inb(CMOS_DATA); -#endif - - /* record BSP in CPU map */ - all_cpus = 1; - - /* set up 0 -> 4MB P==V mapping for AP boot */ - *(int *)PTD = PG_V | PG_RW | ((uintptr_t)(void *)KPTphys & PG_FRAME); - invltlb(); - - /* start each AP */ - for (x = 1; x <= mp_naps; ++x) { - - /* This is a bit verbose, it will go away soon. */ - - /* first page of AP's private space */ - pg = x * i386_btop(sizeof(struct privatespace)); - - /* allocate a new private data page */ - gd = (struct globaldata *)kmem_alloc(kernel_map, PAGE_SIZE); - - /* wire it into the private page table page */ - SMPpt[pg] = (pt_entry_t)(PG_V | PG_RW | vtophys(gd)); - - /* allocate and set up an idle stack data page */ - stack = (char *)kmem_alloc(kernel_map, UPAGES*PAGE_SIZE); - for (i = 0; i < UPAGES; i++) - SMPpt[pg + 5 + i] = (pt_entry_t) - (PG_V | PG_RW | vtophys(PAGE_SIZE * i + stack)); - - SMPpt[pg + 1] = 0; /* *prv_CMAP1 */ - SMPpt[pg + 2] = 0; /* *prv_CMAP2 */ - SMPpt[pg + 3] = 0; /* *prv_CMAP3 */ - SMPpt[pg + 4] = 0; /* *prv_PMAP1 */ - - /* prime data page for it to use */ - gd->gd_cpuid = x; - gd->gd_cpu_lockid = x << 24; - gd->gd_prv_CMAP1 = &SMPpt[pg + 1]; - gd->gd_prv_CMAP2 = &SMPpt[pg + 2]; - gd->gd_prv_CMAP3 = &SMPpt[pg + 3]; - gd->gd_prv_PMAP1 = &SMPpt[pg + 4]; - gd->gd_prv_CADDR1 = SMP_prvspace[x].CPAGE1; - gd->gd_prv_CADDR2 = SMP_prvspace[x].CPAGE2; - gd->gd_prv_CADDR3 = SMP_prvspace[x].CPAGE3; - gd->gd_prv_PADDR1 = (unsigned *)SMP_prvspace[x].PPAGE1; - - /* setup a vector to our boot code */ - *((volatile u_short *) WARMBOOT_OFF) = WARMBOOT_TARGET; - *((volatile u_short *) WARMBOOT_SEG) = (boot_addr >> 4); -#ifndef PC98 - outb(CMOS_REG, BIOS_RESET); - outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */ -#endif - - bootSTK = &SMP_prvspace[x].idlestack[UPAGES*PAGE_SIZE]; - bootAP = x; - - /* attempt to start the Application Processor */ - CHECK_INIT(99); /* setup checkpoints */ - if (!start_ap(x, boot_addr)) { - printf("AP #%d (PHY# %d) failed!\n", x, CPU_TO_ID(x)); - CHECK_PRINT("trace"); /* show checkpoints */ - /* better panic as the AP may be running loose */ - printf("panic y/n? [y] "); - if (cngetc() != 'n') - panic("bye-bye"); - } - CHECK_PRINT("trace"); /* show checkpoints */ - - /* record its version info */ - cpu_apic_versions[x] = cpu_apic_versions[0]; - - all_cpus |= (1 << x); /* record AP in CPU map */ - } - - /* build our map of 'other' CPUs */ - other_cpus = all_cpus & ~(1 << cpuid); - - /* fill in our (BSP) APIC version */ - cpu_apic_versions[0] = lapic.version; - - /* restore the warmstart vector */ - *(u_long *) WARMBOOT_OFF = mpbioswarmvec; -#ifndef PC98 - outb(CMOS_REG, BIOS_RESET); - outb(CMOS_DATA, mpbiosreason); -#endif - - /* - * Set up the idle context for the BSP. Similar to above except - * that some was done by locore, some by pmap.c and some is implicit - * because the BSP is cpu#0 and the page is initially zero, and also - * because we can refer to variables by name on the BSP.. - */ - - /* Allocate and setup BSP idle stack */ - stack = (char *)kmem_alloc(kernel_map, UPAGES * PAGE_SIZE); - for (i = 0; i < UPAGES; i++) - SMPpt[5 + i] = (pt_entry_t) - (PG_V | PG_RW | vtophys(PAGE_SIZE * i + stack)); - - *(int *)PTD = 0; - pmap_set_opt(); - - /* number of APs actually started */ - return mp_ncpus - 1; -} - - -/* - * load the 1st level AP boot code into base memory. - */ - -/* targets for relocation */ -extern void bigJump(void); -extern void bootCodeSeg(void); -extern void bootDataSeg(void); -extern void MPentry(void); -extern u_int MP_GDT; -extern u_int mp_gdtbase; - -static void -install_ap_tramp(u_int boot_addr) -{ - int x; - int size = *(int *) ((u_long) & bootMP_size); - u_char *src = (u_char *) ((u_long) bootMP); - u_char *dst = (u_char *) boot_addr + KERNBASE; - u_int boot_base = (u_int) bootMP; - u_int8_t *dst8; - u_int16_t *dst16; - u_int32_t *dst32; - - POSTCODE(INSTALL_AP_TRAMP_POST); - - for (x = 0; x < size; ++x) - *dst++ = *src++; - - /* - * modify addresses in code we just moved to basemem. unfortunately we - * need fairly detailed info about mpboot.s for this to work. changes - * to mpboot.s might require changes here. - */ - - /* boot code is located in KERNEL space */ - dst = (u_char *) boot_addr + KERNBASE; - - /* modify the lgdt arg */ - dst32 = (u_int32_t *) (dst + ((u_int) & mp_gdtbase - boot_base)); - *dst32 = boot_addr + ((u_int) & MP_GDT - boot_base); - - /* modify the ljmp target for MPentry() */ - dst32 = (u_int32_t *) (dst + ((u_int) bigJump - boot_base) + 1); - *dst32 = ((u_int) MPentry - KERNBASE); - - /* modify the target for boot code segment */ - dst16 = (u_int16_t *) (dst + ((u_int) bootCodeSeg - boot_base)); - dst8 = (u_int8_t *) (dst16 + 1); - *dst16 = (u_int) boot_addr & 0xffff; - *dst8 = ((u_int) boot_addr >> 16) & 0xff; - - /* modify the target for boot data segment */ - dst16 = (u_int16_t *) (dst + ((u_int) bootDataSeg - boot_base)); - dst8 = (u_int8_t *) (dst16 + 1); - *dst16 = (u_int) boot_addr & 0xffff; - *dst8 = ((u_int) boot_addr >> 16) & 0xff; -} - - -/* - * this function starts the AP (application processor) identified - * by the APIC ID 'physicalCpu'. It does quite a "song and dance" - * to accomplish this. This is necessary because of the nuances - * of the different hardware we might encounter. It ain't pretty, - * but it seems to work. - */ -static int -start_ap(int logical_cpu, u_int boot_addr) -{ - int physical_cpu; - int vector; - int cpus; - u_long icr_lo, icr_hi; - - POSTCODE(START_AP_POST); - - /* get the PHYSICAL APIC ID# */ - physical_cpu = CPU_TO_ID(logical_cpu); - - /* calculate the vector */ - vector = (boot_addr >> 12) & 0xff; - - /* used as a watchpoint to signal AP startup */ - cpus = mp_ncpus; - - /* - * first we do an INIT/RESET IPI this INIT IPI might be run, reseting - * and running the target CPU. OR this INIT IPI might be latched (P5 - * bug), CPU waiting for STARTUP IPI. OR this INIT IPI might be - * ignored. - */ - - /* setup the address for the target AP */ - icr_hi = lapic.icr_hi & ~APIC_ID_MASK; - icr_hi |= (physical_cpu << 24); - lapic.icr_hi = icr_hi; - - /* do an INIT IPI: assert RESET */ - icr_lo = lapic.icr_lo & 0xfff00000; - lapic.icr_lo = icr_lo | 0x0000c500; - - /* wait for pending status end */ - while (lapic.icr_lo & APIC_DELSTAT_MASK) - /* spin */ ; - - /* do an INIT IPI: deassert RESET */ - lapic.icr_lo = icr_lo | 0x00008500; - - /* wait for pending status end */ - u_sleep(10000); /* wait ~10mS */ - while (lapic.icr_lo & APIC_DELSTAT_MASK) - /* spin */ ; - - /* - * next we do a STARTUP IPI: the previous INIT IPI might still be - * latched, (P5 bug) this 1st STARTUP would then terminate - * immediately, and the previously started INIT IPI would continue. OR - * the previous INIT IPI has already run. and this STARTUP IPI will - * run. OR the previous INIT IPI was ignored. and this STARTUP IPI - * will run. - */ - - /* do a STARTUP IPI */ - lapic.icr_lo = icr_lo | 0x00000600 | vector; - while (lapic.icr_lo & APIC_DELSTAT_MASK) - /* spin */ ; - u_sleep(200); /* wait ~200uS */ - - /* - * finally we do a 2nd STARTUP IPI: this 2nd STARTUP IPI should run IF - * the previous STARTUP IPI was cancelled by a latched INIT IPI. OR - * this STARTUP IPI will be ignored, as only ONE STARTUP IPI is - * recognized after hardware RESET or INIT IPI. - */ - - lapic.icr_lo = icr_lo | 0x00000600 | vector; - while (lapic.icr_lo & APIC_DELSTAT_MASK) - /* spin */ ; - u_sleep(200); /* wait ~200uS */ - - /* wait for it to start */ - set_apic_timer(5000000);/* == 5 seconds */ - while (read_apic_timer()) - if (mp_ncpus > cpus) - return 1; /* return SUCCESS */ - - return 0; /* return FAILURE */ -} - - -/* - * Flush the TLB on all other CPU's - * - * XXX: Needs to handshake and wait for completion before proceding. - */ -void -smp_invltlb(void) -{ -#if defined(APIC_IO) - if (smp_started && invltlb_ok) - all_but_self_ipi(XINVLTLB_OFFSET); -#endif /* APIC_IO */ -} - -void -invlpg(u_int addr) -{ - __asm __volatile("invlpg (%0)"::"r"(addr):"memory"); - - /* send a message to the other CPUs */ - smp_invltlb(); -} - -void -invltlb(void) -{ - u_long temp; - - /* - * This should be implemented as load_cr3(rcr3()) when load_cr3() is - * inlined. - */ - __asm __volatile("movl %%cr3, %0; movl %0, %%cr3":"=r"(temp) :: "memory"); - - /* send a message to the other CPUs */ - smp_invltlb(); -} - - -/* - * When called the executing CPU will send an IPI to all other CPUs - * requesting that they halt execution. - * - * Usually (but not necessarily) called with 'other_cpus' as its arg. - * - * - Signals all CPUs in map to stop. - * - Waits for each to stop. - * - * Returns: - * -1: error - * 0: NA - * 1: ok - * - * XXX FIXME: this is not MP-safe, needs a lock to prevent multiple CPUs - * from executing at same time. - */ -int -stop_cpus(u_int map) -{ - if (!smp_started) - return 0; - - /* send the Xcpustop IPI to all CPUs in map */ - selected_apic_ipi(map, XCPUSTOP_OFFSET, APIC_DELMODE_FIXED); - - while ((stopped_cpus & map) != map) - /* spin */ ; - - return 1; -} - - -/* - * Called by a CPU to restart stopped CPUs. - * - * Usually (but not necessarily) called with 'stopped_cpus' as its arg. - * - * - Signals all CPUs in map to restart. - * - Waits for each to restart. - * - * Returns: - * -1: error - * 0: NA - * 1: ok - */ -int -restart_cpus(u_int map) -{ - if (!smp_started) - return 0; - - started_cpus = map; /* signal other cpus to restart */ - - while ((stopped_cpus & map) != 0) /* wait for each to clear its bit */ - /* spin */ ; - - return 1; -} - -int smp_active = 0; /* are the APs allowed to run? */ -SYSCTL_INT(_machdep, OID_AUTO, smp_active, CTLFLAG_RW, &smp_active, 0, ""); - -/* XXX maybe should be hw.ncpu */ -static int smp_cpus = 1; /* how many cpu's running */ -SYSCTL_INT(_machdep, OID_AUTO, smp_cpus, CTLFLAG_RD, &smp_cpus, 0, ""); - -int invltlb_ok = 0; /* throttle smp_invltlb() till safe */ -SYSCTL_INT(_machdep, OID_AUTO, invltlb_ok, CTLFLAG_RW, &invltlb_ok, 0, ""); - -/* Warning: Do not staticize. Used from swtch.s */ -int do_page_zero_idle = 1; /* bzero pages for fun and profit in idleloop */ -SYSCTL_INT(_machdep, OID_AUTO, do_page_zero_idle, CTLFLAG_RW, - &do_page_zero_idle, 0, ""); - -/* Is forwarding of a interrupt to the CPU holding the ISR lock enabled ? */ -int forward_irq_enabled = 1; -SYSCTL_INT(_machdep, OID_AUTO, forward_irq_enabled, CTLFLAG_RW, - &forward_irq_enabled, 0, ""); - -/* Enable forwarding of a signal to a process running on a different CPU */ -static int forward_signal_enabled = 1; -SYSCTL_INT(_machdep, OID_AUTO, forward_signal_enabled, CTLFLAG_RW, - &forward_signal_enabled, 0, ""); - -/* Enable forwarding of roundrobin to all other cpus */ -static int forward_roundrobin_enabled = 1; -SYSCTL_INT(_machdep, OID_AUTO, forward_roundrobin_enabled, CTLFLAG_RW, - &forward_roundrobin_enabled, 0, ""); - -/* - * This is called once the rest of the system is up and running and we're - * ready to let the AP's out of the pen. - */ -void ap_init(void); - -void -ap_init() -{ - u_int apic_id; - - /* BSP may have changed PTD while we're waiting for the lock */ - cpu_invltlb(); - - smp_cpus++; - -#if defined(I586_CPU) && !defined(NO_F00F_HACK) - lidt(&r_idt); -#endif - - /* Build our map of 'other' CPUs. */ - other_cpus = all_cpus & ~(1 << cpuid); - - printf("SMP: AP CPU #%d Launched!\n", cpuid); - - /* XXX FIXME: i386 specific, and redundant: Setup the FPU. */ - load_cr0((rcr0() & ~CR0_EM) | CR0_MP | CR0_NE | CR0_TS); - - /* set up FPU state on the AP */ - npxinit(__INITIAL_NPXCW__); - - /* A quick check from sanity claus */ - apic_id = (apic_id_to_logical[(lapic.id & 0x0f000000) >> 24]); - if (cpuid != apic_id) { - printf("SMP: cpuid = %d\n", cpuid); - printf("SMP: apic_id = %d\n", apic_id); - printf("PTD[MPPTDI] = %p\n", (void *)PTD[MPPTDI]); - panic("cpuid mismatch! boom!!"); - } - - /* Init local apic for irq's */ - apic_initialize(); - - /* Set memory range attributes for this CPU to match the BSP */ - mem_range_AP_init(); - - /* - * Activate smp_invltlb, although strictly speaking, this isn't - * quite correct yet. We should have a bitfield for cpus willing - * to accept TLB flush IPI's or something and sync them. - */ - if (smp_cpus == mp_ncpus) { - invltlb_ok = 1; - smp_started = 1; /* enable IPI's, tlb shootdown, freezes etc */ - smp_active = 1; /* historic */ - } -} - -#ifdef BETTER_CLOCK - -#define CHECKSTATE_USER 0 -#define CHECKSTATE_SYS 1 -#define CHECKSTATE_INTR 2 - -/* Do not staticize. Used from apic_vector.s */ -struct proc* checkstate_curproc[NCPU]; -int checkstate_cpustate[NCPU]; -u_long checkstate_pc[NCPU]; - -extern long cp_time[CPUSTATES]; - -#define PC_TO_INDEX(pc, prof) \ - ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \ - (u_quad_t)((prof)->pr_scale)) >> 16) & ~1) - -static void -addupc_intr_forwarded(struct proc *p, int id, int *astmap) -{ - int i; - struct uprof *prof; - u_long pc; - - pc = checkstate_pc[id]; - prof = &p->p_stats->p_prof; - if (pc >= prof->pr_off && - (i = PC_TO_INDEX(pc, prof)) < prof->pr_size) { - if ((p->p_flag & P_OWEUPC) == 0) { - prof->pr_addr = pc; - prof->pr_ticks = 1; - p->p_flag |= P_OWEUPC; - } - *astmap |= (1 << id); - } -} - -static void -forwarded_statclock(int id, int pscnt, int *astmap) -{ - struct pstats *pstats; - long rss; - struct rusage *ru; - struct vmspace *vm; - int cpustate; - struct proc *p; -#ifdef GPROF - register struct gmonparam *g; - int i; -#endif - - p = checkstate_curproc[id]; - cpustate = checkstate_cpustate[id]; - - switch (cpustate) { - case CHECKSTATE_USER: - if (p->p_flag & P_PROFIL) - addupc_intr_forwarded(p, id, astmap); - if (pscnt > 1) - return; - p->p_uticks++; - if (p->p_nice > NZERO) - cp_time[CP_NICE]++; - else - cp_time[CP_USER]++; - break; - case CHECKSTATE_SYS: -#ifdef GPROF - /* - * Kernel statistics are just like addupc_intr, only easier. - */ - g = &_gmonparam; - if (g->state == GMON_PROF_ON) { - i = checkstate_pc[id] - g->lowpc; - if (i < g->textsize) { - i /= HISTFRACTION * sizeof(*g->kcount); - g->kcount[i]++; - } - } -#endif - if (pscnt > 1) - return; - - if (!p) - cp_time[CP_IDLE]++; - else { - p->p_sticks++; - cp_time[CP_SYS]++; - } - break; - case CHECKSTATE_INTR: - default: -#ifdef GPROF - /* - * Kernel statistics are just like addupc_intr, only easier. - */ - g = &_gmonparam; - if (g->state == GMON_PROF_ON) { - i = checkstate_pc[id] - g->lowpc; - if (i < g->textsize) { - i /= HISTFRACTION * sizeof(*g->kcount); - g->kcount[i]++; - } - } -#endif - if (pscnt > 1) - return; - if (p) - p->p_iticks++; - cp_time[CP_INTR]++; - } - if (p != NULL) { - schedclock(p); - - /* Update resource usage integrals and maximums. */ - if ((pstats = p->p_stats) != NULL && - (ru = &pstats->p_ru) != NULL && - (vm = p->p_vmspace) != NULL) { - ru->ru_ixrss += pgtok(vm->vm_tsize); - ru->ru_idrss += pgtok(vm->vm_dsize); - ru->ru_isrss += pgtok(vm->vm_ssize); - rss = pgtok(vmspace_resident_count(vm)); - if (ru->ru_maxrss < rss) - ru->ru_maxrss = rss; - } - } -} - -void -forward_statclock(int pscnt) -{ - int map; - int id; - int i; - - /* Kludge. We don't yet have separate locks for the interrupts - * and the kernel. This means that we cannot let the other processors - * handle complex interrupts while inhibiting them from entering - * the kernel in a non-interrupt context. - * - * What we can do, without changing the locking mechanisms yet, - * is letting the other processors handle a very simple interrupt - * (wich determines the processor states), and do the main - * work ourself. - */ - - if (!smp_started || !invltlb_ok || cold || panicstr) - return; - - /* Step 1: Probe state (user, cpu, interrupt, spinlock, idle ) */ - - map = other_cpus & ~stopped_cpus ; - checkstate_probed_cpus = 0; - if (map != 0) - selected_apic_ipi(map, - XCPUCHECKSTATE_OFFSET, APIC_DELMODE_FIXED); - - i = 0; - while (checkstate_probed_cpus != map) { - /* spin */ - i++; - if (i == 100000) { -#ifdef BETTER_CLOCK_DIAGNOSTIC - printf("forward_statclock: checkstate %x\n", - checkstate_probed_cpus); -#endif - break; - } - } - - /* - * Step 2: walk through other processors processes, update ticks and - * profiling info. - */ - - map = 0; - for (id = 0; id < mp_ncpus; id++) { - if (id == cpuid) - continue; - if (((1 << id) & checkstate_probed_cpus) == 0) - continue; - forwarded_statclock(id, pscnt, &map); - } - if (map != 0) { - checkstate_need_ast |= map; - selected_apic_ipi(map, XCPUAST_OFFSET, APIC_DELMODE_FIXED); - i = 0; - while ((checkstate_need_ast & map) != 0) { - /* spin */ - i++; - if (i > 100000) { -#ifdef BETTER_CLOCK_DIAGNOSTIC - printf("forward_statclock: dropped ast 0x%x\n", - checkstate_need_ast & map); -#endif - break; - } - } - } -} - -void -forward_hardclock(int pscnt) -{ - int map; - int id; - struct proc *p; - struct pstats *pstats; - int i; - - /* Kludge. We don't yet have separate locks for the interrupts - * and the kernel. This means that we cannot let the other processors - * handle complex interrupts while inhibiting them from entering - * the kernel in a non-interrupt context. - * - * What we can do, without changing the locking mechanisms yet, - * is letting the other processors handle a very simple interrupt - * (wich determines the processor states), and do the main - * work ourself. - */ - - if (!smp_started || !invltlb_ok || cold || panicstr) - return; - - /* Step 1: Probe state (user, cpu, interrupt, spinlock, idle) */ - - map = other_cpus & ~stopped_cpus ; - checkstate_probed_cpus = 0; - if (map != 0) - selected_apic_ipi(map, - XCPUCHECKSTATE_OFFSET, APIC_DELMODE_FIXED); - - i = 0; - while (checkstate_probed_cpus != map) { - /* spin */ - i++; - if (i == 100000) { -#ifdef BETTER_CLOCK_DIAGNOSTIC - printf("forward_hardclock: checkstate %x\n", - checkstate_probed_cpus); -#endif - break; - } - } - - /* - * Step 2: walk through other processors processes, update virtual - * timer and profiling timer. If stathz == 0, also update ticks and - * profiling info. - */ - - map = 0; - for (id = 0; id < mp_ncpus; id++) { - if (id == cpuid) - continue; - if (((1 << id) & checkstate_probed_cpus) == 0) - continue; - p = checkstate_curproc[id]; - if (p) { - pstats = p->p_stats; - if (checkstate_cpustate[id] == CHECKSTATE_USER && - timevalisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) && - itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0) { - psignal(p, SIGVTALRM); - map |= (1 << id); - } - if (timevalisset(&pstats->p_timer[ITIMER_PROF].it_value) && - itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0) { - psignal(p, SIGPROF); - map |= (1 << id); - } - } - if (stathz == 0) { - forwarded_statclock( id, pscnt, &map); - } - } - if (map != 0) { - checkstate_need_ast |= map; - selected_apic_ipi(map, XCPUAST_OFFSET, APIC_DELMODE_FIXED); - i = 0; - while ((checkstate_need_ast & map) != 0) { - /* spin */ - i++; - if (i > 100000) { -#ifdef BETTER_CLOCK_DIAGNOSTIC - printf("forward_hardclock: dropped ast 0x%x\n", - checkstate_need_ast & map); -#endif - break; - } - } - } -} - -#endif /* BETTER_CLOCK */ - -void -forward_signal(struct proc *p) -{ - int map; - int id; - int i; - - /* Kludge. We don't yet have separate locks for the interrupts - * and the kernel. This means that we cannot let the other processors - * handle complex interrupts while inhibiting them from entering - * the kernel in a non-interrupt context. - * - * What we can do, without changing the locking mechanisms yet, - * is letting the other processors handle a very simple interrupt - * (wich determines the processor states), and do the main - * work ourself. - */ - - if (!smp_started || !invltlb_ok || cold || panicstr) - return; - if (!forward_signal_enabled) - return; - while (1) { - if (p->p_stat != SRUN) - return; - id = p->p_oncpu; - if (id == 0xff) - return; - map = (1<<id); - checkstate_need_ast |= map; - selected_apic_ipi(map, XCPUAST_OFFSET, APIC_DELMODE_FIXED); - i = 0; - while ((checkstate_need_ast & map) != 0) { - /* spin */ - i++; - if (i > 100000) { -#if 0 - printf("forward_signal: dropped ast 0x%x\n", - checkstate_need_ast & map); -#endif - break; - } - } - if (id == p->p_oncpu) - return; - } -} - -void -forward_roundrobin(void) -{ - u_int map; - int i; - - if (!smp_started || !invltlb_ok || cold || panicstr) - return; - if (!forward_roundrobin_enabled) - return; - resched_cpus |= other_cpus; - map = other_cpus & ~stopped_cpus ; -#if 1 - selected_apic_ipi(map, XCPUAST_OFFSET, APIC_DELMODE_FIXED); -#else - (void) all_but_self_ipi(XCPUAST_OFFSET); -#endif - i = 0; - while ((checkstate_need_ast & map) != 0) { - /* spin */ - i++; - if (i > 100000) { -#if 0 - printf("forward_roundrobin: dropped ast 0x%x\n", - checkstate_need_ast & map); -#endif - break; - } - } -} - - -#ifdef APIC_INTR_REORDER -/* - * Maintain mapping from softintr vector to isr bit in local apic. - */ -void -set_lapic_isrloc(int intr, int vector) -{ - if (intr < 0 || intr > 32) - panic("set_apic_isrloc: bad intr argument: %d",intr); - if (vector < ICU_OFFSET || vector > 255) - panic("set_apic_isrloc: bad vector argument: %d",vector); - apic_isrbit_location[intr].location = &lapic.isr0 + ((vector>>5)<<2); - apic_isrbit_location[intr].bit = (1<<(vector & 31)); -} -#endif - -/* - * All-CPU rendezvous. CPUs are signalled, all execute the setup function - * (if specified), rendezvous, execute the action function (if specified), - * rendezvous again, execute the teardown function (if specified), and then - * resume. - * - * Note that the supplied external functions _must_ be reentrant and aware - * that they are running in parallel and in an unknown lock context. - */ -static void (*smp_rv_setup_func)(void *arg); -static void (*smp_rv_action_func)(void *arg); -static void (*smp_rv_teardown_func)(void *arg); -static void *smp_rv_func_arg; -static volatile int smp_rv_waiters[2]; - -void -smp_rendezvous_action(void) -{ - /* setup function */ - if (smp_rv_setup_func != NULL) - smp_rv_setup_func(smp_rv_func_arg); - /* spin on entry rendezvous */ - atomic_add_int(&smp_rv_waiters[0], 1); - while (smp_rv_waiters[0] < mp_ncpus) - ; - /* action function */ - if (smp_rv_action_func != NULL) - smp_rv_action_func(smp_rv_func_arg); - /* spin on exit rendezvous */ - atomic_add_int(&smp_rv_waiters[1], 1); - while (smp_rv_waiters[1] < mp_ncpus) - ; - /* teardown function */ - if (smp_rv_teardown_func != NULL) - smp_rv_teardown_func(smp_rv_func_arg); -} - -void -smp_rendezvous(void (* setup_func)(void *), - void (* action_func)(void *), - void (* teardown_func)(void *), - void *arg) -{ - u_int efl; - - /* obtain rendezvous lock */ - s_lock(&smp_rv_lock); /* XXX sleep here? NOWAIT flag? */ - - /* set static function pointers */ - smp_rv_setup_func = setup_func; - smp_rv_action_func = action_func; - smp_rv_teardown_func = teardown_func; - smp_rv_func_arg = arg; - smp_rv_waiters[0] = 0; - smp_rv_waiters[1] = 0; - - /* disable interrupts on this CPU, save interrupt status */ - efl = read_eflags(); - write_eflags(efl & ~PSL_I); - - /* signal other processors, which will enter the IPI with interrupts off */ - all_but_self_ipi(XRENDEZVOUS_OFFSET); - - /* call executor function */ - smp_rendezvous_action(); - - /* restore interrupt flag */ - write_eflags(efl); - - /* release lock */ - s_unlock(&smp_rv_lock); -} diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c deleted file mode 100644 index a8b73cf6a02b..000000000000 --- a/sys/kern/subr_trap.c +++ /dev/null @@ -1,1152 +0,0 @@ -/*- - * Copyright (C) 1994, David Greenman - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the University of Utah, and William Jolitz. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 - * $FreeBSD$ - */ - -/* - * 386 Trap and System call handling - */ - -#include "opt_cpu.h" -#include "opt_ddb.h" -#include "opt_ktrace.h" -#include "opt_clock.h" -#include "opt_trap.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/pioctl.h> -#include <sys/kernel.h> -#include <sys/resourcevar.h> -#include <sys/signalvar.h> -#include <sys/syscall.h> -#include <sys/sysent.h> -#include <sys/uio.h> -#include <sys/vmmeter.h> -#ifdef KTRACE -#include <sys/ktrace.h> -#endif - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <sys/lock.h> -#include <vm/pmap.h> -#include <vm/vm_kern.h> -#include <vm/vm_map.h> -#include <vm/vm_page.h> -#include <vm/vm_extern.h> - -#include <machine/cpu.h> -#include <machine/ipl.h> -#include <machine/md_var.h> -#include <machine/pcb.h> -#ifdef SMP -#include <machine/smp.h> -#endif -#include <machine/tss.h> - -#include <i386/isa/intr_machdep.h> - -#ifdef POWERFAIL_NMI -#include <sys/syslog.h> -#include <machine/clock.h> -#endif - -#include <machine/vm86.h> - -#include <ddb/ddb.h> - -#include "isa.h" -#include "npx.h" - -int (*pmath_emulate) __P((struct trapframe *)); - -extern void trap __P((struct trapframe frame)); -extern int trapwrite __P((unsigned addr)); -extern void syscall __P((struct trapframe frame)); - -static int trap_pfault __P((struct trapframe *, int, vm_offset_t)); -static void trap_fatal __P((struct trapframe *, vm_offset_t)); -void dblfault_handler __P((void)); - -extern inthand_t IDTVEC(syscall); - -#define MAX_TRAP_MSG 28 -static char *trap_msg[] = { - "", /* 0 unused */ - "privileged instruction fault", /* 1 T_PRIVINFLT */ - "", /* 2 unused */ - "breakpoint instruction fault", /* 3 T_BPTFLT */ - "", /* 4 unused */ - "", /* 5 unused */ - "arithmetic trap", /* 6 T_ARITHTRAP */ - "system forced exception", /* 7 T_ASTFLT */ - "", /* 8 unused */ - "general protection fault", /* 9 T_PROTFLT */ - "trace trap", /* 10 T_TRCTRAP */ - "", /* 11 unused */ - "page fault", /* 12 T_PAGEFLT */ - "", /* 13 unused */ - "alignment fault", /* 14 T_ALIGNFLT */ - "", /* 15 unused */ - "", /* 16 unused */ - "", /* 17 unused */ - "integer divide fault", /* 18 T_DIVIDE */ - "non-maskable interrupt trap", /* 19 T_NMI */ - "overflow trap", /* 20 T_OFLOW */ - "FPU bounds check fault", /* 21 T_BOUND */ - "FPU device not available", /* 22 T_DNA */ - "double fault", /* 23 T_DOUBLEFLT */ - "FPU operand fetch fault", /* 24 T_FPOPFLT */ - "invalid TSS fault", /* 25 T_TSSFLT */ - "segment not present fault", /* 26 T_SEGNPFLT */ - "stack fault", /* 27 T_STKFLT */ - "machine check trap", /* 28 T_MCHK */ -}; - -static __inline void userret __P((struct proc *p, struct trapframe *frame, - u_quad_t oticks)); - -#if defined(I586_CPU) && !defined(NO_F00F_HACK) -extern int has_f00f_bug; -#endif - -static __inline void -userret(p, frame, oticks) - struct proc *p; - struct trapframe *frame; - u_quad_t oticks; -{ - int sig, s; - - while ((sig = CURSIG(p)) != 0) - postsig(sig); - -#if 0 - if (!want_resched && - (p->p_priority <= p->p_usrpri) && - (p->p_rtprio.type == RTP_PRIO_NORMAL)) { - int newpriority; - p->p_estcpu += 1; - newpriority = PUSER + p->p_estcpu / 4 + 2 * p->p_nice; - newpriority = min(newpriority, MAXPRI); - p->p_usrpri = newpriority; - } -#endif - - p->p_priority = p->p_usrpri; - if (want_resched) { - /* - * Since we are curproc, clock will normally just change - * our priority without moving us from one queue to another - * (since the running process is not on a queue.) - * If that happened after we setrunqueue ourselves but before we - * mi_switch()'ed, we might not be on the queue indicated by - * our priority. - */ - s = splhigh(); - setrunqueue(p); - p->p_stats->p_ru.ru_nivcsw++; - mi_switch(); - splx(s); - while ((sig = CURSIG(p)) != 0) - postsig(sig); - } - /* - * Charge system time if profiling. - */ - if (p->p_flag & P_PROFIL) - addupc_task(p, frame->tf_eip, - (u_int)(p->p_sticks - oticks) * psratio); - - curpriority = p->p_priority; -} - -/* - * Exception, fault, and trap interface to the FreeBSD kernel. - * This common code is called from assembly language IDT gate entry - * routines that prepare a suitable stack frame, and restore this - * frame after the exception has been processed. - */ - -void -trap(frame) - struct trapframe frame; -{ - struct proc *p = curproc; - u_quad_t sticks = 0; - int i = 0, ucode = 0, type, code; - vm_offset_t eva; - - if (!(frame.tf_eflags & PSL_I)) { - /* - * Buggy application or kernel code has disabled interrupts - * and then trapped. Enabling interrupts now is wrong, but - * it is better than running with interrupts disabled until - * they are accidentally enabled later. - */ - type = frame.tf_trapno; - if (ISPL(frame.tf_cs) == SEL_UPL || (frame.tf_eflags & PSL_VM)) - printf( - "pid %ld (%s): trap %d with interrupts disabled\n", - (long)curproc->p_pid, curproc->p_comm, type); - else if (type != T_BPTFLT && type != T_TRCTRAP) - /* - * XXX not quite right, since this may be for a - * multiple fault in user mode. - */ - printf("kernel trap %d with interrupts disabled\n", - type); - enable_intr(); - } - - eva = 0; - if (frame.tf_trapno == T_PAGEFLT) { - /* - * For some Cyrix CPUs, %cr2 is clobbered by interrupts. - * This problem is worked around by using an interrupt - * gate for the pagefault handler. We are finally ready - * to read %cr2 and then must reenable interrupts. - * - * XXX this should be in the switch statement, but the - * NO_FOOF_HACK and VM86 goto and ifdefs obfuscate the - * flow of control too much for this to be obviously - * correct. - */ - eva = rcr2(); - enable_intr(); - } - -#if defined(I586_CPU) && !defined(NO_F00F_HACK) -restart: -#endif - type = frame.tf_trapno; - code = frame.tf_err; - - if (in_vm86call) { - if (frame.tf_eflags & PSL_VM && - (type == T_PROTFLT || type == T_STKFLT)) { - i = vm86_emulate((struct vm86frame *)&frame); - if (i != 0) - /* - * returns to original process - */ - vm86_trap((struct vm86frame *)&frame); - return; - } - switch (type) { - /* - * these traps want either a process context, or - * assume a normal userspace trap. - */ - case T_PROTFLT: - case T_SEGNPFLT: - trap_fatal(&frame, eva); - return; - case T_TRCTRAP: - type = T_BPTFLT; /* kernel breakpoint */ - /* FALL THROUGH */ - } - goto kernel_trap; /* normal kernel trap handling */ - } - - if ((ISPL(frame.tf_cs) == SEL_UPL) || (frame.tf_eflags & PSL_VM)) { - /* user trap */ - - sticks = p->p_sticks; - p->p_md.md_regs = &frame; - - switch (type) { - case T_PRIVINFLT: /* privileged instruction fault */ - ucode = type; - i = SIGILL; - break; - - case T_BPTFLT: /* bpt instruction fault */ - case T_TRCTRAP: /* trace trap */ - frame.tf_eflags &= ~PSL_T; - i = SIGTRAP; - break; - - case T_ARITHTRAP: /* arithmetic trap */ - ucode = code; - i = SIGFPE; - break; - - case T_ASTFLT: /* Allow process switch */ - astoff(); - cnt.v_soft++; - if (p->p_flag & P_OWEUPC) { - p->p_flag &= ~P_OWEUPC; - addupc_task(p, p->p_stats->p_prof.pr_addr, - p->p_stats->p_prof.pr_ticks); - } - goto out; - - /* - * The following two traps can happen in - * vm86 mode, and, if so, we want to handle - * them specially. - */ - case T_PROTFLT: /* general protection fault */ - case T_STKFLT: /* stack fault */ - if (frame.tf_eflags & PSL_VM) { - i = vm86_emulate((struct vm86frame *)&frame); - if (i == 0) - goto out; - break; - } - /* FALL THROUGH */ - - case T_SEGNPFLT: /* segment not present fault */ - case T_TSSFLT: /* invalid TSS fault */ - case T_DOUBLEFLT: /* double fault */ - default: - ucode = code + BUS_SEGM_FAULT ; - i = SIGBUS; - break; - - case T_PAGEFLT: /* page fault */ - i = trap_pfault(&frame, TRUE, eva); - if (i == -1) - return; -#if defined(I586_CPU) && !defined(NO_F00F_HACK) - if (i == -2) - goto restart; -#endif - if (i == 0) - goto out; - - ucode = T_PAGEFLT; - break; - - case T_DIVIDE: /* integer divide fault */ - ucode = FPE_INTDIV; - i = SIGFPE; - break; - -#if NISA > 0 - case T_NMI: -#ifdef POWERFAIL_NMI - goto handle_powerfail; -#else /* !POWERFAIL_NMI */ -#ifdef DDB - /* NMI can be hooked up to a pushbutton for debugging */ - printf ("NMI ... going to debugger\n"); - if (kdb_trap (type, 0, &frame)) - return; -#endif /* DDB */ - /* machine/parity/power fail/"kitchen sink" faults */ - if (isa_nmi(code) == 0) return; - panic("NMI indicates hardware failure"); -#endif /* POWERFAIL_NMI */ -#endif /* NISA > 0 */ - - case T_OFLOW: /* integer overflow fault */ - ucode = FPE_INTOVF; - i = SIGFPE; - break; - - case T_BOUND: /* bounds check fault */ - ucode = FPE_FLTSUB; - i = SIGFPE; - break; - - case T_DNA: -#if NNPX > 0 - /* if a transparent fault (due to context switch "late") */ - if (npxdna()) - return; -#endif - if (!pmath_emulate) { - i = SIGFPE; - ucode = FPE_FPU_NP_TRAP; - break; - } - i = (*pmath_emulate)(&frame); - if (i == 0) { - if (!(frame.tf_eflags & PSL_T)) - return; - frame.tf_eflags &= ~PSL_T; - i = SIGTRAP; - } - /* else ucode = emulator_only_knows() XXX */ - break; - - case T_FPOPFLT: /* FPU operand fetch fault */ - ucode = T_FPOPFLT; - i = SIGILL; - break; - } - } else { -kernel_trap: - /* kernel trap */ - - switch (type) { - case T_PAGEFLT: /* page fault */ - (void) trap_pfault(&frame, FALSE, eva); - return; - - case T_DNA: -#if NNPX > 0 - /* - * The kernel is apparently using npx for copying. - * XXX this should be fatal unless the kernel has - * registered such use. - */ - if (npxdna()) - return; -#endif - break; - - case T_PROTFLT: /* general protection fault */ - case T_SEGNPFLT: /* segment not present fault */ - /* - * Invalid segment selectors and out of bounds - * %eip's and %esp's can be set up in user mode. - * This causes a fault in kernel mode when the - * kernel tries to return to user mode. We want - * to get this fault so that we can fix the - * problem here and not have to check all the - * selectors and pointers when the user changes - * them. - */ -#define MAYBE_DORETI_FAULT(where, whereto) \ - do { \ - if (frame.tf_eip == (int)where) { \ - frame.tf_eip = (int)whereto; \ - return; \ - } \ - } while (0) - - if (intr_nesting_level == 0) { - /* - * Invalid %fs's and %gs's can be created using - * procfs or PT_SETREGS or by invalidating the - * underlying LDT entry. This causes a fault - * in kernel mode when the kernel attempts to - * switch contexts. Lose the bad context - * (XXX) so that we can continue, and generate - * a signal. - */ - if (frame.tf_eip == (int)cpu_switch_load_gs) { - curpcb->pcb_gs = 0; - psignal(p, SIGBUS); - return; - } - MAYBE_DORETI_FAULT(doreti_iret, - doreti_iret_fault); - MAYBE_DORETI_FAULT(doreti_popl_ds, - doreti_popl_ds_fault); - MAYBE_DORETI_FAULT(doreti_popl_es, - doreti_popl_es_fault); - MAYBE_DORETI_FAULT(doreti_popl_fs, - doreti_popl_fs_fault); - if (curpcb && curpcb->pcb_onfault) { - frame.tf_eip = (int)curpcb->pcb_onfault; - return; - } - } - break; - - case T_TSSFLT: - /* - * PSL_NT can be set in user mode and isn't cleared - * automatically when the kernel is entered. This - * causes a TSS fault when the kernel attempts to - * `iret' because the TSS link is uninitialized. We - * want to get this fault so that we can fix the - * problem here and not every time the kernel is - * entered. - */ - if (frame.tf_eflags & PSL_NT) { - frame.tf_eflags &= ~PSL_NT; - return; - } - break; - - case T_TRCTRAP: /* trace trap */ - if (frame.tf_eip == (int)IDTVEC(syscall)) { - /* - * We've just entered system mode via the - * syscall lcall. Continue single stepping - * silently until the syscall handler has - * saved the flags. - */ - return; - } - if (frame.tf_eip == (int)IDTVEC(syscall) + 1) { - /* - * The syscall handler has now saved the - * flags. Stop single stepping it. - */ - frame.tf_eflags &= ~PSL_T; - return; - } - /* - * Ignore debug register trace traps due to - * accesses in the user's address space, which - * can happen under several conditions such as - * if a user sets a watchpoint on a buffer and - * then passes that buffer to a system call. - * We still want to get TRCTRAPS for addresses - * in kernel space because that is useful when - * debugging the kernel. - */ - if (user_dbreg_trap()) { - /* - * Reset breakpoint bits because the - * processor doesn't - */ - load_dr6(rdr6() & 0xfffffff0); - return; - } - /* - * Fall through (TRCTRAP kernel mode, kernel address) - */ - case T_BPTFLT: - /* - * If DDB is enabled, let it handle the debugger trap. - * Otherwise, debugger traps "can't happen". - */ -#ifdef DDB - if (kdb_trap (type, 0, &frame)) - return; -#endif - break; - -#if NISA > 0 - case T_NMI: -#ifdef POWERFAIL_NMI -#ifndef TIMER_FREQ -# define TIMER_FREQ 1193182 -#endif - handle_powerfail: - { - static unsigned lastalert = 0; - - if(time_second - lastalert > 10) - { - log(LOG_WARNING, "NMI: power fail\n"); - sysbeep(TIMER_FREQ/880, hz); - lastalert = time_second; - } - return; - } -#else /* !POWERFAIL_NMI */ -#ifdef DDB - /* NMI can be hooked up to a pushbutton for debugging */ - printf ("NMI ... going to debugger\n"); - if (kdb_trap (type, 0, &frame)) - return; -#endif /* DDB */ - /* machine/parity/power fail/"kitchen sink" faults */ - if (isa_nmi(code) == 0) return; - /* FALL THROUGH */ -#endif /* POWERFAIL_NMI */ -#endif /* NISA > 0 */ - } - - trap_fatal(&frame, eva); - return; - } - - /* Translate fault for emulators (e.g. Linux) */ - if (*p->p_sysent->sv_transtrap) - i = (*p->p_sysent->sv_transtrap)(i, type); - - trapsignal(p, i, ucode); - -#ifdef DEBUG - if (type <= MAX_TRAP_MSG) { - uprintf("fatal process exception: %s", - trap_msg[type]); - if ((type == T_PAGEFLT) || (type == T_PROTFLT)) - uprintf(", fault VA = 0x%lx", (u_long)eva); - uprintf("\n"); - } -#endif - -out: - userret(p, &frame, sticks); -} - -#ifdef notyet -/* - * This version doesn't allow a page fault to user space while - * in the kernel. The rest of the kernel needs to be made "safe" - * before this can be used. I think the only things remaining - * to be made safe are the iBCS2 code and the process tracing/ - * debugging code. - */ -static int -trap_pfault(frame, usermode, eva) - struct trapframe *frame; - int usermode; - vm_offset_t eva; -{ - vm_offset_t va; - struct vmspace *vm = NULL; - vm_map_t map = 0; - int rv = 0; - vm_prot_t ftype; - struct proc *p = curproc; - - if (frame->tf_err & PGEX_W) - ftype = VM_PROT_READ | VM_PROT_WRITE; - else - ftype = VM_PROT_READ; - - va = trunc_page(eva); - if (va < VM_MIN_KERNEL_ADDRESS) { - vm_offset_t v; - vm_page_t mpte; - - if (p == NULL || - (!usermode && va < VM_MAXUSER_ADDRESS && - (intr_nesting_level != 0 || curpcb == NULL || - curpcb->pcb_onfault == NULL))) { - trap_fatal(frame, eva); - return (-1); - } - - /* - * This is a fault on non-kernel virtual memory. - * vm is initialized above to NULL. If curproc is NULL - * or curproc->p_vmspace is NULL the fault is fatal. - */ - vm = p->p_vmspace; - if (vm == NULL) - goto nogo; - - map = &vm->vm_map; - - /* - * Keep swapout from messing with us during this - * critical time. - */ - ++p->p_lock; - - /* - * Grow the stack if necessary - */ - /* grow_stack returns false only if va falls into - * a growable stack region and the stack growth - * fails. It returns true if va was not within - * a growable stack region, or if the stack - * growth succeeded. - */ - if (!grow_stack (p, va)) { - rv = KERN_FAILURE; - --p->p_lock; - goto nogo; - } - - /* Fault in the user page: */ - rv = vm_fault(map, va, ftype, - (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY - : VM_FAULT_NORMAL); - - --p->p_lock; - } else { - /* - * Don't allow user-mode faults in kernel address space. - */ - if (usermode) - goto nogo; - - /* - * Since we know that kernel virtual address addresses - * always have pte pages mapped, we just have to fault - * the page. - */ - rv = vm_fault(kernel_map, va, ftype, VM_FAULT_NORMAL); - } - - if (rv == KERN_SUCCESS) - return (0); -nogo: - if (!usermode) { - if (intr_nesting_level == 0 && curpcb && curpcb->pcb_onfault) { - frame->tf_eip = (int)curpcb->pcb_onfault; - return (0); - } - trap_fatal(frame, eva); - return (-1); - } - - /* kludge to pass faulting virtual address to sendsig */ - frame->tf_err = eva; - - return((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); -} -#endif - -int -trap_pfault(frame, usermode, eva) - struct trapframe *frame; - int usermode; - vm_offset_t eva; -{ - vm_offset_t va; - struct vmspace *vm = NULL; - vm_map_t map = 0; - int rv = 0; - vm_prot_t ftype; - struct proc *p = curproc; - - va = trunc_page(eva); - if (va >= KERNBASE) { - /* - * Don't allow user-mode faults in kernel address space. - * An exception: if the faulting address is the invalid - * instruction entry in the IDT, then the Intel Pentium - * F00F bug workaround was triggered, and we need to - * treat it is as an illegal instruction, and not a page - * fault. - */ -#if defined(I586_CPU) && !defined(NO_F00F_HACK) - if ((eva == (unsigned int)&idt[6]) && has_f00f_bug) { - frame->tf_trapno = T_PRIVINFLT; - return -2; - } -#endif - if (usermode) - goto nogo; - - map = kernel_map; - } else { - /* - * This is a fault on non-kernel virtual memory. - * vm is initialized above to NULL. If curproc is NULL - * or curproc->p_vmspace is NULL the fault is fatal. - */ - if (p != NULL) - vm = p->p_vmspace; - - if (vm == NULL) - goto nogo; - - map = &vm->vm_map; - } - - if (frame->tf_err & PGEX_W) - ftype = VM_PROT_READ | VM_PROT_WRITE; - else - ftype = VM_PROT_READ; - - if (map != kernel_map) { - /* - * Keep swapout from messing with us during this - * critical time. - */ - ++p->p_lock; - - /* - * Grow the stack if necessary - */ - /* grow_stack returns false only if va falls into - * a growable stack region and the stack growth - * fails. It returns true if va was not within - * a growable stack region, or if the stack - * growth succeeded. - */ - if (!grow_stack (p, va)) { - rv = KERN_FAILURE; - --p->p_lock; - goto nogo; - } - - /* Fault in the user page: */ - rv = vm_fault(map, va, ftype, - (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY - : VM_FAULT_NORMAL); - - --p->p_lock; - } else { - /* - * Don't have to worry about process locking or stacks in the kernel. - */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); - } - - if (rv == KERN_SUCCESS) - return (0); -nogo: - if (!usermode) { - if (intr_nesting_level == 0 && curpcb && curpcb->pcb_onfault) { - frame->tf_eip = (int)curpcb->pcb_onfault; - return (0); - } - trap_fatal(frame, eva); - return (-1); - } - - /* kludge to pass faulting virtual address to sendsig */ - frame->tf_err = eva; - - return((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); -} - -static void -trap_fatal(frame, eva) - struct trapframe *frame; - vm_offset_t eva; -{ - int code, type, ss, esp; - struct soft_segment_descriptor softseg; - - code = frame->tf_err; - type = frame->tf_trapno; - sdtossd(&gdt[IDXSEL(frame->tf_cs & 0xffff)].sd, &softseg); - - if (type <= MAX_TRAP_MSG) - printf("\n\nFatal trap %d: %s while in %s mode\n", - type, trap_msg[type], - frame->tf_eflags & PSL_VM ? "vm86" : - ISPL(frame->tf_cs) == SEL_UPL ? "user" : "kernel"); -#ifdef SMP - /* three seperate prints in case of a trap on an unmapped page */ - printf("mp_lock = %08x; ", mp_lock); - printf("cpuid = %d; ", cpuid); - printf("lapic.id = %08x\n", lapic.id); -#endif - if (type == T_PAGEFLT) { - printf("fault virtual address = 0x%x\n", eva); - printf("fault code = %s %s, %s\n", - code & PGEX_U ? "user" : "supervisor", - code & PGEX_W ? "write" : "read", - code & PGEX_P ? "protection violation" : "page not present"); - } - printf("instruction pointer = 0x%x:0x%x\n", - frame->tf_cs & 0xffff, frame->tf_eip); - if ((ISPL(frame->tf_cs) == SEL_UPL) || (frame->tf_eflags & PSL_VM)) { - ss = frame->tf_ss & 0xffff; - esp = frame->tf_esp; - } else { - ss = GSEL(GDATA_SEL, SEL_KPL); - esp = (int)&frame->tf_esp; - } - printf("stack pointer = 0x%x:0x%x\n", ss, esp); - printf("frame pointer = 0x%x:0x%x\n", ss, frame->tf_ebp); - printf("code segment = base 0x%x, limit 0x%x, type 0x%x\n", - softseg.ssd_base, softseg.ssd_limit, softseg.ssd_type); - printf(" = DPL %d, pres %d, def32 %d, gran %d\n", - softseg.ssd_dpl, softseg.ssd_p, softseg.ssd_def32, - softseg.ssd_gran); - printf("processor eflags = "); - if (frame->tf_eflags & PSL_T) - printf("trace trap, "); - if (frame->tf_eflags & PSL_I) - printf("interrupt enabled, "); - if (frame->tf_eflags & PSL_NT) - printf("nested task, "); - if (frame->tf_eflags & PSL_RF) - printf("resume, "); - if (frame->tf_eflags & PSL_VM) - printf("vm86, "); - printf("IOPL = %d\n", (frame->tf_eflags & PSL_IOPL) >> 12); - printf("current process = "); - if (curproc) { - printf("%lu (%s)\n", - (u_long)curproc->p_pid, curproc->p_comm ? - curproc->p_comm : ""); - } else { - printf("Idle\n"); - } - printf("interrupt mask = "); - if ((cpl & net_imask) == net_imask) - printf("net "); - if ((cpl & tty_imask) == tty_imask) - printf("tty "); - if ((cpl & bio_imask) == bio_imask) - printf("bio "); - if ((cpl & cam_imask) == cam_imask) - printf("cam "); - if (cpl == 0) - printf("none"); -#ifdef SMP -/** - * XXX FIXME: - * we probably SHOULD have stopped the other CPUs before now! - * another CPU COULD have been touching cpl at this moment... - */ - printf(" <- SMP: XXX"); -#endif - printf("\n"); - -#ifdef KDB - if (kdb_trap(&psl)) - return; -#endif -#ifdef DDB - if ((debugger_on_panic || db_active) && kdb_trap(type, 0, frame)) - return; -#endif - printf("trap number = %d\n", type); - if (type <= MAX_TRAP_MSG) - panic(trap_msg[type]); - else - panic("unknown/reserved trap"); -} - -/* - * Double fault handler. Called when a fault occurs while writing - * a frame for a trap/exception onto the stack. This usually occurs - * when the stack overflows (such is the case with infinite recursion, - * for example). - * - * XXX Note that the current PTD gets replaced by IdlePTD when the - * task switch occurs. This means that the stack that was active at - * the time of the double fault is not available at <kstack> unless - * the machine was idle when the double fault occurred. The downside - * of this is that "trace <ebp>" in ddb won't work. - */ -void -dblfault_handler() -{ - printf("\nFatal double fault:\n"); - printf("eip = 0x%x\n", common_tss.tss_eip); - printf("esp = 0x%x\n", common_tss.tss_esp); - printf("ebp = 0x%x\n", common_tss.tss_ebp); -#ifdef SMP - /* three seperate prints in case of a trap on an unmapped page */ - printf("mp_lock = %08x; ", mp_lock); - printf("cpuid = %d; ", cpuid); - printf("lapic.id = %08x\n", lapic.id); -#endif - panic("double fault"); -} - -/* - * Compensate for 386 brain damage (missing URKR). - * This is a little simpler than the pagefault handler in trap() because - * it the page tables have already been faulted in and high addresses - * are thrown out early for other reasons. - */ -int trapwrite(addr) - unsigned addr; -{ - struct proc *p; - vm_offset_t va; - struct vmspace *vm; - int rv; - - va = trunc_page((vm_offset_t)addr); - /* - * XXX - MAX is END. Changed > to >= for temp. fix. - */ - if (va >= VM_MAXUSER_ADDRESS) - return (1); - - p = curproc; - vm = p->p_vmspace; - - ++p->p_lock; - - if (!grow_stack (p, va)) { - --p->p_lock; - return (1); - } - - /* - * fault the data page - */ - rv = vm_fault(&vm->vm_map, va, VM_PROT_READ|VM_PROT_WRITE, VM_FAULT_DIRTY); - - --p->p_lock; - - if (rv != KERN_SUCCESS) - return 1; - - return (0); -} - -/* - * System call request from POSIX system call gate interface to kernel. - * Like trap(), argument is call by reference. - */ -void -syscall(frame) - struct trapframe frame; -{ - caddr_t params; - int i; - struct sysent *callp; - struct proc *p = curproc; - u_quad_t sticks; - int error; - int args[8]; - u_int code; - -#ifdef DIAGNOSTIC - if (ISPL(frame.tf_cs) != SEL_UPL) - panic("syscall"); -#endif - sticks = p->p_sticks; - p->p_md.md_regs = &frame; - params = (caddr_t)frame.tf_esp + sizeof(int); - code = frame.tf_eax; - if (p->p_sysent->sv_prepsyscall) { - (*p->p_sysent->sv_prepsyscall)(&frame, args, &code, ¶ms); - } else { - /* - * Need to check if this is a 32 bit or 64 bit syscall. - */ - if (code == SYS_syscall) { - /* - * Code is first argument, followed by actual args. - */ - code = fuword(params); - params += sizeof(int); - } else if (code == SYS___syscall) { - /* - * Like syscall, but code is a quad, so as to maintain - * quad alignment for the rest of the arguments. - */ - code = fuword(params); - params += sizeof(quad_t); - } - } - - if (p->p_sysent->sv_mask) - code &= p->p_sysent->sv_mask; - - if (code >= p->p_sysent->sv_size) - callp = &p->p_sysent->sv_table[0]; - else - callp = &p->p_sysent->sv_table[code]; - - if (params && (i = callp->sy_narg * sizeof(int)) && - (error = copyin(params, (caddr_t)args, (u_int)i))) { -#ifdef KTRACE - if (KTRPOINT(p, KTR_SYSCALL)) - ktrsyscall(p->p_tracep, code, callp->sy_narg, args); -#endif - goto bad; - } -#ifdef KTRACE - if (KTRPOINT(p, KTR_SYSCALL)) - ktrsyscall(p->p_tracep, code, callp->sy_narg, args); -#endif - p->p_retval[0] = 0; - p->p_retval[1] = frame.tf_edx; - - STOPEVENT(p, S_SCE, callp->sy_narg); - - error = (*callp->sy_call)(p, args); - - switch (error) { - - case 0: - /* - * Reinitialize proc pointer `p' as it may be different - * if this is a child returning from fork syscall. - */ - p = curproc; - frame.tf_eax = p->p_retval[0]; - frame.tf_edx = p->p_retval[1]; - frame.tf_eflags &= ~PSL_C; - break; - - case ERESTART: - /* - * Reconstruct pc, assuming lcall $X,y is 7 bytes, - * int 0x80 is 2 bytes. We saved this in tf_err. - */ - frame.tf_eip -= frame.tf_err; - break; - - case EJUSTRETURN: - break; - - default: -bad: - if (p->p_sysent->sv_errsize) { - if (error >= p->p_sysent->sv_errsize) - error = -1; /* XXX */ - else - error = p->p_sysent->sv_errtbl[error]; - } - frame.tf_eax = error; - frame.tf_eflags |= PSL_C; - break; - } - - if ((frame.tf_eflags & PSL_T) && !(frame.tf_eflags & PSL_VM)) { - /* Traced syscall. */ - frame.tf_eflags &= ~PSL_T; - trapsignal(p, SIGTRAP, 0); - } - - userret(p, &frame, sticks); - -#ifdef KTRACE - if (KTRPOINT(p, KTR_SYSRET)) - ktrsysret(p->p_tracep, code, error, p->p_retval[0]); -#endif - - /* - * This works because errno is findable through the - * register set. If we ever support an emulation where this - * is not the case, this code will need to be revisited. - */ - STOPEVENT(p, S_SCX, code); - -} - -/* - * Simplified back end of syscall(), used when returning from fork() - * directly into user mode. - */ -void -fork_return(p, frame) - struct proc *p; - struct trapframe frame; -{ - frame.tf_eax = 0; /* Child returns zero */ - frame.tf_eflags &= ~PSL_C; /* success */ - frame.tf_edx = 1; - - userret(p, &frame, 0); -#ifdef KTRACE - if (KTRPOINT(p, KTR_SYSRET)) - ktrsysret(p->p_tracep, SYS_fork, 0, 0); -#endif -} diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c deleted file mode 100644 index 93d1fdacec5a..000000000000 --- a/sys/kern/uipc_sockbuf.c +++ /dev/null @@ -1,1006 +0,0 @@ -/* - * Copyright (c) 1982, 1986, 1988, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)uipc_socket2.c 8.1 (Berkeley) 6/10/93 - * $FreeBSD$ - */ - -#include "opt_param.h" -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/domain.h> -#include <sys/file.h> /* for maxfiles */ -#include <sys/kernel.h> -#include <sys/proc.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/protosw.h> -#include <sys/resourcevar.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/signalvar.h> -#include <sys/sysctl.h> -#include <sys/aio.h> /* for aio_swake proto */ - -int maxsockets; - -/* - * Primitive routines for operating on sockets and socket buffers - */ - -u_long sb_max = SB_MAX; /* XXX should be static */ - -static u_long sb_efficiency = 8; /* parameter for sbreserve() */ - -/* - * Procedures to manipulate state flags of socket - * and do appropriate wakeups. Normal sequence from the - * active (originating) side is that soisconnecting() is - * called during processing of connect() call, - * resulting in an eventual call to soisconnected() if/when the - * connection is established. When the connection is torn down - * soisdisconnecting() is called during processing of disconnect() call, - * and soisdisconnected() is called when the connection to the peer - * is totally severed. The semantics of these routines are such that - * connectionless protocols can call soisconnected() and soisdisconnected() - * only, bypassing the in-progress calls when setting up a ``connection'' - * takes no time. - * - * From the passive side, a socket is created with - * two queues of sockets: so_incomp for connections in progress - * and so_comp for connections already made and awaiting user acceptance. - * As a protocol is preparing incoming connections, it creates a socket - * structure queued on so_incomp by calling sonewconn(). When the connection - * is established, soisconnected() is called, and transfers the - * socket structure to so_comp, making it available to accept(). - * - * If a socket is closed with sockets on either - * so_incomp or so_comp, these sockets are dropped. - * - * If higher level protocols are implemented in - * the kernel, the wakeups done here will sometimes - * cause software-interrupt process scheduling. - */ - -void -soisconnecting(so) - register struct socket *so; -{ - - so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); - so->so_state |= SS_ISCONNECTING; -} - -void -soisconnected(so) - register struct socket *so; -{ - register struct socket *head = so->so_head; - - so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); - so->so_state |= SS_ISCONNECTED; - if (head && (so->so_state & SS_INCOMP)) { - TAILQ_REMOVE(&head->so_incomp, so, so_list); - head->so_incqlen--; - so->so_state &= ~SS_INCOMP; - TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); - so->so_state |= SS_COMP; - sorwakeup(head); - wakeup_one(&head->so_timeo); - } else { - wakeup(&so->so_timeo); - sorwakeup(so); - sowwakeup(so); - } -} - -void -soisdisconnecting(so) - register struct socket *so; -{ - - so->so_state &= ~SS_ISCONNECTING; - so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); - wakeup((caddr_t)&so->so_timeo); - sowwakeup(so); - sorwakeup(so); -} - -void -soisdisconnected(so) - register struct socket *so; -{ - - so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); - so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED); - wakeup((caddr_t)&so->so_timeo); - sowwakeup(so); - sorwakeup(so); -} - -/* - * Return a random connection that hasn't been serviced yet and - * is eligible for discard. There is a one in qlen chance that - * we will return a null, saying that there are no dropable - * requests. In this case, the protocol specific code should drop - * the new request. This insures fairness. - * - * This may be used in conjunction with protocol specific queue - * congestion routines. - */ -struct socket * -sodropablereq(head) - register struct socket *head; -{ - register struct socket *so; - unsigned int i, j, qlen; - static int rnd; - static struct timeval old_runtime; - static unsigned int cur_cnt, old_cnt; - struct timeval tv; - - getmicrouptime(&tv); - if ((i = (tv.tv_sec - old_runtime.tv_sec)) != 0) { - old_runtime = tv; - old_cnt = cur_cnt / i; - cur_cnt = 0; - } - - so = TAILQ_FIRST(&head->so_incomp); - if (!so) - return (so); - - qlen = head->so_incqlen; - if (++cur_cnt > qlen || old_cnt > qlen) { - rnd = (314159 * rnd + 66329) & 0xffff; - j = ((qlen + 1) * rnd) >> 16; - - while (j-- && so) - so = TAILQ_NEXT(so, so_list); - } - - return (so); -} - -/* - * When an attempt at a new connection is noted on a socket - * which accepts connections, sonewconn is called. If the - * connection is possible (subject to space constraints, etc.) - * then we allocate a new structure, propoerly linked into the - * data structure of the original socket, and return this. - * Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED. - */ -struct socket * -sonewconn(head, connstatus) - register struct socket *head; - int connstatus; -{ - - return (sonewconn3(head, connstatus, NULL)); -} - -struct socket * -sonewconn3(head, connstatus, p) - register struct socket *head; - int connstatus; - struct proc *p; -{ - register struct socket *so; - - if (head->so_qlen > 3 * head->so_qlimit / 2) - return ((struct socket *)0); - so = soalloc(0); - if (so == NULL) - return ((struct socket *)0); - so->so_head = head; - so->so_type = head->so_type; - so->so_options = head->so_options &~ SO_ACCEPTCONN; - so->so_linger = head->so_linger; - so->so_state = head->so_state | SS_NOFDREF; - so->so_proto = head->so_proto; - so->so_timeo = head->so_timeo; - so->so_cred = p ? p->p_ucred : head->so_cred; - crhold(so->so_cred); - if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) || - (*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) { - sodealloc(so); - return ((struct socket *)0); - } - - if (connstatus) { - TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); - so->so_state |= SS_COMP; - } else { - TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list); - so->so_state |= SS_INCOMP; - head->so_incqlen++; - } - head->so_qlen++; - if (connstatus) { - sorwakeup(head); - wakeup((caddr_t)&head->so_timeo); - so->so_state |= connstatus; - } - return (so); -} - -/* - * Socantsendmore indicates that no more data will be sent on the - * socket; it would normally be applied to a socket when the user - * informs the system that no more data is to be sent, by the protocol - * code (in case PRU_SHUTDOWN). Socantrcvmore indicates that no more data - * will be received, and will normally be applied to the socket by a - * protocol when it detects that the peer will send no more data. - * Data queued for reading in the socket may yet be read. - */ - -void -socantsendmore(so) - struct socket *so; -{ - - so->so_state |= SS_CANTSENDMORE; - sowwakeup(so); -} - -void -socantrcvmore(so) - struct socket *so; -{ - - so->so_state |= SS_CANTRCVMORE; - sorwakeup(so); -} - -/* - * Wait for data to arrive at/drain from a socket buffer. - */ -int -sbwait(sb) - struct sockbuf *sb; -{ - - sb->sb_flags |= SB_WAIT; - return (tsleep((caddr_t)&sb->sb_cc, - (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "sbwait", - sb->sb_timeo)); -} - -/* - * Lock a sockbuf already known to be locked; - * return any error returned from sleep (EINTR). - */ -int -sb_lock(sb) - register struct sockbuf *sb; -{ - int error; - - while (sb->sb_flags & SB_LOCK) { - sb->sb_flags |= SB_WANT; - error = tsleep((caddr_t)&sb->sb_flags, - (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK|PCATCH, - "sblock", 0); - if (error) - return (error); - } - sb->sb_flags |= SB_LOCK; - return (0); -} - -/* - * Wakeup processes waiting on a socket buffer. - * Do asynchronous notification via SIGIO - * if the socket has the SS_ASYNC flag set. - */ -void -sowakeup(so, sb) - register struct socket *so; - register struct sockbuf *sb; -{ - selwakeup(&sb->sb_sel); - sb->sb_flags &= ~SB_SEL; - if (sb->sb_flags & SB_WAIT) { - sb->sb_flags &= ~SB_WAIT; - wakeup((caddr_t)&sb->sb_cc); - } - if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL) - pgsigio(so->so_sigio, SIGIO, 0); - if (sb->sb_flags & SB_UPCALL) - (*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT); - if (sb->sb_flags & SB_AIO) - aio_swake(so, sb); -} - -/* - * Socket buffer (struct sockbuf) utility routines. - * - * Each socket contains two socket buffers: one for sending data and - * one for receiving data. Each buffer contains a queue of mbufs, - * information about the number of mbufs and amount of data in the - * queue, and other fields allowing select() statements and notification - * on data availability to be implemented. - * - * Data stored in a socket buffer is maintained as a list of records. - * Each record is a list of mbufs chained together with the m_next - * field. Records are chained together with the m_nextpkt field. The upper - * level routine soreceive() expects the following conventions to be - * observed when placing information in the receive buffer: - * - * 1. If the protocol requires each message be preceded by the sender's - * name, then a record containing that name must be present before - * any associated data (mbuf's must be of type MT_SONAME). - * 2. If the protocol supports the exchange of ``access rights'' (really - * just additional data associated with the message), and there are - * ``rights'' to be received, then a record containing this data - * should be present (mbuf's must be of type MT_RIGHTS). - * 3. If a name or rights record exists, then it must be followed by - * a data record, perhaps of zero length. - * - * Before using a new socket structure it is first necessary to reserve - * buffer space to the socket, by calling sbreserve(). This should commit - * some of the available buffer space in the system buffer pool for the - * socket (currently, it does nothing but enforce limits). The space - * should be released by calling sbrelease() when the socket is destroyed. - */ - -int -soreserve(so, sndcc, rcvcc) - register struct socket *so; - u_long sndcc, rcvcc; -{ - struct proc *p = curproc; - - if (sbreserve(&so->so_snd, sndcc, so, p) == 0) - goto bad; - if (sbreserve(&so->so_rcv, rcvcc, so, p) == 0) - goto bad2; - if (so->so_rcv.sb_lowat == 0) - so->so_rcv.sb_lowat = 1; - if (so->so_snd.sb_lowat == 0) - so->so_snd.sb_lowat = MCLBYTES; - if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat) - so->so_snd.sb_lowat = so->so_snd.sb_hiwat; - return (0); -bad2: - sbrelease(&so->so_snd, so); -bad: - return (ENOBUFS); -} - -/* - * Allot mbufs to a sockbuf. - * Attempt to scale mbmax so that mbcnt doesn't become limiting - * if buffering efficiency is near the normal case. - */ -int -sbreserve(sb, cc, so, p) - struct sockbuf *sb; - u_long cc; - struct socket *so; - struct proc *p; -{ - rlim_t delta; - - /* - * p will only be NULL when we're in an interrupt - * (e.g. in tcp_input()) - */ - if ((u_quad_t)cc > (u_quad_t)sb_max * MCLBYTES / (MSIZE + MCLBYTES)) - return (0); - delta = (rlim_t)cc - sb->sb_hiwat; - if (p && delta >= 0 && chgsbsize(so->so_cred->cr_uid, 0) + delta > - p->p_rlimit[RLIMIT_SBSIZE].rlim_cur) - return (0); - (void)chgsbsize(so->so_cred->cr_uid, delta); - sb->sb_hiwat = cc; - sb->sb_mbmax = min(cc * sb_efficiency, sb_max); - if (sb->sb_lowat > sb->sb_hiwat) - sb->sb_lowat = sb->sb_hiwat; - return (1); -} - -/* - * Free mbufs held by a socket, and reserved mbuf space. - */ -void -sbrelease(sb, so) - struct sockbuf *sb; - struct socket *so; -{ - - sbflush(sb); - (void)chgsbsize(so->so_cred->cr_uid, -(rlim_t)sb->sb_hiwat); - sb->sb_hiwat = sb->sb_mbmax = 0; -} - -/* - * Routines to add and remove - * data from an mbuf queue. - * - * The routines sbappend() or sbappendrecord() are normally called to - * append new mbufs to a socket buffer, after checking that adequate - * space is available, comparing the function sbspace() with the amount - * of data to be added. sbappendrecord() differs from sbappend() in - * that data supplied is treated as the beginning of a new record. - * To place a sender's address, optional access rights, and data in a - * socket receive buffer, sbappendaddr() should be used. To place - * access rights and data in a socket receive buffer, sbappendrights() - * should be used. In either case, the new data begins a new record. - * Note that unlike sbappend() and sbappendrecord(), these routines check - * for the caller that there will be enough space to store the data. - * Each fails if there is not enough space, or if it cannot find mbufs - * to store additional information in. - * - * Reliable protocols may use the socket send buffer to hold data - * awaiting acknowledgement. Data is normally copied from a socket - * send buffer in a protocol with m_copy for output to a peer, - * and then removing the data from the socket buffer with sbdrop() - * or sbdroprecord() when the data is acknowledged by the peer. - */ - -/* - * Append mbuf chain m to the last record in the - * socket buffer sb. The additional space associated - * the mbuf chain is recorded in sb. Empty mbufs are - * discarded and mbufs are compacted where possible. - */ -void -sbappend(sb, m) - struct sockbuf *sb; - struct mbuf *m; -{ - register struct mbuf *n; - - if (m == 0) - return; - n = sb->sb_mb; - if (n) { - while (n->m_nextpkt) - n = n->m_nextpkt; - do { - if (n->m_flags & M_EOR) { - sbappendrecord(sb, m); /* XXXXXX!!!! */ - return; - } - } while (n->m_next && (n = n->m_next)); - } - sbcompress(sb, m, n); -} - -#ifdef SOCKBUF_DEBUG -void -sbcheck(sb) - register struct sockbuf *sb; -{ - register struct mbuf *m; - register struct mbuf *n = 0; - register u_long len = 0, mbcnt = 0; - - for (m = sb->sb_mb; m; m = n) { - n = m->m_nextpkt; - for (; m; m = m->m_next) { - len += m->m_len; - mbcnt += MSIZE; - if (m->m_flags & M_EXT) /*XXX*/ /* pretty sure this is bogus */ - mbcnt += m->m_ext.ext_size; - } - } - if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { - printf("cc %ld != %ld || mbcnt %ld != %ld\n", len, sb->sb_cc, - mbcnt, sb->sb_mbcnt); - panic("sbcheck"); - } -} -#endif - -/* - * As above, except the mbuf chain - * begins a new record. - */ -void -sbappendrecord(sb, m0) - register struct sockbuf *sb; - register struct mbuf *m0; -{ - register struct mbuf *m; - - if (m0 == 0) - return; - m = sb->sb_mb; - if (m) - while (m->m_nextpkt) - m = m->m_nextpkt; - /* - * Put the first mbuf on the queue. - * Note this permits zero length records. - */ - sballoc(sb, m0); - if (m) - m->m_nextpkt = m0; - else - sb->sb_mb = m0; - m = m0->m_next; - m0->m_next = 0; - if (m && (m0->m_flags & M_EOR)) { - m0->m_flags &= ~M_EOR; - m->m_flags |= M_EOR; - } - sbcompress(sb, m, m0); -} - -/* - * As above except that OOB data - * is inserted at the beginning of the sockbuf, - * but after any other OOB data. - */ -void -sbinsertoob(sb, m0) - register struct sockbuf *sb; - register struct mbuf *m0; -{ - register struct mbuf *m; - register struct mbuf **mp; - - if (m0 == 0) - return; - for (mp = &sb->sb_mb; *mp ; mp = &((*mp)->m_nextpkt)) { - m = *mp; - again: - switch (m->m_type) { - - case MT_OOBDATA: - continue; /* WANT next train */ - - case MT_CONTROL: - m = m->m_next; - if (m) - goto again; /* inspect THIS train further */ - } - break; - } - /* - * Put the first mbuf on the queue. - * Note this permits zero length records. - */ - sballoc(sb, m0); - m0->m_nextpkt = *mp; - *mp = m0; - m = m0->m_next; - m0->m_next = 0; - if (m && (m0->m_flags & M_EOR)) { - m0->m_flags &= ~M_EOR; - m->m_flags |= M_EOR; - } - sbcompress(sb, m, m0); -} - -/* - * Append address and data, and optionally, control (ancillary) data - * to the receive queue of a socket. If present, - * m0 must include a packet header with total length. - * Returns 0 if no space in sockbuf or insufficient mbufs. - */ -int -sbappendaddr(sb, asa, m0, control) - register struct sockbuf *sb; - struct sockaddr *asa; - struct mbuf *m0, *control; -{ - register struct mbuf *m, *n; - int space = asa->sa_len; - -if (m0 && (m0->m_flags & M_PKTHDR) == 0) -panic("sbappendaddr"); - if (m0) - space += m0->m_pkthdr.len; - for (n = control; n; n = n->m_next) { - space += n->m_len; - if (n->m_next == 0) /* keep pointer to last control buf */ - break; - } - if (space > sbspace(sb)) - return (0); - if (asa->sa_len > MLEN) - return (0); - MGET(m, M_DONTWAIT, MT_SONAME); - if (m == 0) - return (0); - m->m_len = asa->sa_len; - bcopy((caddr_t)asa, mtod(m, caddr_t), asa->sa_len); - if (n) - n->m_next = m0; /* concatenate data to control */ - else - control = m0; - m->m_next = control; - for (n = m; n; n = n->m_next) - sballoc(sb, n); - n = sb->sb_mb; - if (n) { - while (n->m_nextpkt) - n = n->m_nextpkt; - n->m_nextpkt = m; - } else - sb->sb_mb = m; - return (1); -} - -int -sbappendcontrol(sb, m0, control) - struct sockbuf *sb; - struct mbuf *control, *m0; -{ - register struct mbuf *m, *n; - int space = 0; - - if (control == 0) - panic("sbappendcontrol"); - for (m = control; ; m = m->m_next) { - space += m->m_len; - if (m->m_next == 0) - break; - } - n = m; /* save pointer to last control buffer */ - for (m = m0; m; m = m->m_next) - space += m->m_len; - if (space > sbspace(sb)) - return (0); - n->m_next = m0; /* concatenate data to control */ - for (m = control; m; m = m->m_next) - sballoc(sb, m); - n = sb->sb_mb; - if (n) { - while (n->m_nextpkt) - n = n->m_nextpkt; - n->m_nextpkt = control; - } else - sb->sb_mb = control; - return (1); -} - -/* - * Compress mbuf chain m into the socket - * buffer sb following mbuf n. If n - * is null, the buffer is presumed empty. - */ -void -sbcompress(sb, m, n) - register struct sockbuf *sb; - register struct mbuf *m, *n; -{ - register int eor = 0; - register struct mbuf *o; - - while (m) { - eor |= m->m_flags & M_EOR; - if (m->m_len == 0 && - (eor == 0 || - (((o = m->m_next) || (o = n)) && - o->m_type == m->m_type))) { - m = m_free(m); - continue; - } - if (n && (n->m_flags & (M_EXT | M_EOR)) == 0 && - (n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] && - n->m_type == m->m_type) { - bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len, - (unsigned)m->m_len); - n->m_len += m->m_len; - sb->sb_cc += m->m_len; - m = m_free(m); - continue; - } - if (n) - n->m_next = m; - else - sb->sb_mb = m; - sballoc(sb, m); - n = m; - m->m_flags &= ~M_EOR; - m = m->m_next; - n->m_next = 0; - } - if (eor) { - if (n) - n->m_flags |= eor; - else - printf("semi-panic: sbcompress\n"); - } -} - -/* - * Free all mbufs in a sockbuf. - * Check that all resources are reclaimed. - */ -void -sbflush(sb) - register struct sockbuf *sb; -{ - - if (sb->sb_flags & SB_LOCK) - panic("sbflush: locked"); - while (sb->sb_mbcnt) { - /* - * Don't call sbdrop(sb, 0) if the leading mbuf is non-empty: - * we would loop forever. Panic instead. - */ - if (!sb->sb_cc && (sb->sb_mb == NULL || sb->sb_mb->m_len)) - break; - sbdrop(sb, (int)sb->sb_cc); - } - if (sb->sb_cc || sb->sb_mb || sb->sb_mbcnt) - panic("sbflush: cc %ld || mb %p || mbcnt %ld", sb->sb_cc, (void *)sb->sb_mb, sb->sb_mbcnt); -} - -/* - * Drop data from (the front of) a sockbuf. - */ -void -sbdrop(sb, len) - register struct sockbuf *sb; - register int len; -{ - register struct mbuf *m, *mn; - struct mbuf *next; - - next = (m = sb->sb_mb) ? m->m_nextpkt : 0; - while (len > 0) { - if (m == 0) { - if (next == 0) - panic("sbdrop"); - m = next; - next = m->m_nextpkt; - continue; - } - if (m->m_len > len) { - m->m_len -= len; - m->m_data += len; - sb->sb_cc -= len; - break; - } - len -= m->m_len; - sbfree(sb, m); - MFREE(m, mn); - m = mn; - } - while (m && m->m_len == 0) { - sbfree(sb, m); - MFREE(m, mn); - m = mn; - } - if (m) { - sb->sb_mb = m; - m->m_nextpkt = next; - } else - sb->sb_mb = next; -} - -/* - * Drop a record off the front of a sockbuf - * and move the next record to the front. - */ -void -sbdroprecord(sb) - register struct sockbuf *sb; -{ - register struct mbuf *m, *mn; - - m = sb->sb_mb; - if (m) { - sb->sb_mb = m->m_nextpkt; - do { - sbfree(sb, m); - MFREE(m, mn); - m = mn; - } while (m); - } -} - -/* - * Create a "control" mbuf containing the specified data - * with the specified type for presentation on a socket buffer. - */ -struct mbuf * -sbcreatecontrol(p, size, type, level) - caddr_t p; - register int size; - int type, level; -{ - register struct cmsghdr *cp; - struct mbuf *m; - - if (CMSG_SPACE((u_int)size) > MLEN) - return ((struct mbuf *) NULL); - if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL) - return ((struct mbuf *) NULL); - cp = mtod(m, struct cmsghdr *); - /* XXX check size? */ - (void)memcpy(CMSG_DATA(cp), p, size); - m->m_len = CMSG_SPACE(size); - cp->cmsg_len = CMSG_LEN(size); - cp->cmsg_level = level; - cp->cmsg_type = type; - return (m); -} - -/* - * Some routines that return EOPNOTSUPP for entry points that are not - * supported by a protocol. Fill in as needed. - */ -int -pru_accept_notsupp(struct socket *so, struct sockaddr **nam) -{ - return EOPNOTSUPP; -} - -int -pru_connect_notsupp(struct socket *so, struct sockaddr *nam, struct proc *p) -{ - return EOPNOTSUPP; -} - -int -pru_connect2_notsupp(struct socket *so1, struct socket *so2) -{ - return EOPNOTSUPP; -} - -int -pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data, - struct ifnet *ifp, struct proc *p) -{ - return EOPNOTSUPP; -} - -int -pru_listen_notsupp(struct socket *so, struct proc *p) -{ - return EOPNOTSUPP; -} - -int -pru_rcvd_notsupp(struct socket *so, int flags) -{ - return EOPNOTSUPP; -} - -int -pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags) -{ - return EOPNOTSUPP; -} - -/* - * This isn't really a ``null'' operation, but it's the default one - * and doesn't do anything destructive. - */ -int -pru_sense_null(struct socket *so, struct stat *sb) -{ - sb->st_blksize = so->so_snd.sb_hiwat; - return 0; -} - -/* - * Make a copy of a sockaddr in a malloced buffer of type M_SONAME. - */ -struct sockaddr * -dup_sockaddr(sa, canwait) - struct sockaddr *sa; - int canwait; -{ - struct sockaddr *sa2; - - MALLOC(sa2, struct sockaddr *, sa->sa_len, M_SONAME, - canwait ? M_WAITOK : M_NOWAIT); - if (sa2) - bcopy(sa, sa2, sa->sa_len); - return sa2; -} - -/* - * Create an external-format (``xsocket'') structure using the information - * in the kernel-format socket structure pointed to by so. This is done - * to reduce the spew of irrelevant information over this interface, - * to isolate user code from changes in the kernel structure, and - * potentially to provide information-hiding if we decide that - * some of this information should be hidden from users. - */ -void -sotoxsocket(struct socket *so, struct xsocket *xso) -{ - xso->xso_len = sizeof *xso; - xso->xso_so = so; - xso->so_type = so->so_type; - xso->so_options = so->so_options; - xso->so_linger = so->so_linger; - xso->so_state = so->so_state; - xso->so_pcb = so->so_pcb; - xso->xso_protocol = so->so_proto->pr_protocol; - xso->xso_family = so->so_proto->pr_domain->dom_family; - xso->so_qlen = so->so_qlen; - xso->so_incqlen = so->so_incqlen; - xso->so_qlimit = so->so_qlimit; - xso->so_timeo = so->so_timeo; - xso->so_error = so->so_error; - xso->so_pgid = so->so_sigio ? so->so_sigio->sio_pgid : 0; - xso->so_oobmark = so->so_oobmark; - sbtoxsockbuf(&so->so_snd, &xso->so_snd); - sbtoxsockbuf(&so->so_rcv, &xso->so_rcv); - xso->so_uid = so->so_cred->cr_uid; -} - -/* - * This does the same for sockbufs. Note that the xsockbuf structure, - * since it is always embedded in a socket, does not include a self - * pointer nor a length. We make this entry point public in case - * some other mechanism needs it. - */ -void -sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb) -{ - xsb->sb_cc = sb->sb_cc; - xsb->sb_hiwat = sb->sb_hiwat; - xsb->sb_mbcnt = sb->sb_mbcnt; - xsb->sb_mbmax = sb->sb_mbmax; - xsb->sb_lowat = sb->sb_lowat; - xsb->sb_flags = sb->sb_flags; - xsb->sb_timeo = sb->sb_timeo; -} - -/* - * Here is the definition of some of the basic objects in the kern.ipc - * branch of the MIB. - */ -SYSCTL_NODE(_kern, KERN_IPC, ipc, CTLFLAG_RW, 0, "IPC"); - -/* This takes the place of kern.maxsockbuf, which moved to kern.ipc. */ -static int dummy; -SYSCTL_INT(_kern, KERN_DUMMY, dummy, CTLFLAG_RW, &dummy, 0, ""); - -SYSCTL_INT(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLFLAG_RW, - &sb_max, 0, "Maximum socket buffer size"); -SYSCTL_INT(_kern_ipc, OID_AUTO, maxsockets, CTLFLAG_RD, - &maxsockets, 0, "Maximum number of sockets avaliable"); -SYSCTL_INT(_kern_ipc, KIPC_SOCKBUF_WASTE, sockbuf_waste_factor, CTLFLAG_RW, - &sb_efficiency, 0, ""); - -/* - * Initialise maxsockets - */ -static void init_maxsockets(void *ignored) -{ - TUNABLE_INT_FETCH("kern.ipc.maxsockets", 0, maxsockets); - maxsockets = imax(maxsockets, imax(maxfiles, nmbclusters)); -} -SYSINIT(param, SI_SUB_TUNABLES, SI_ORDER_ANY, init_maxsockets, NULL); diff --git a/sys/kern/vfs_acl.c b/sys/kern/vfs_acl.c deleted file mode 100644 index bd4a52f52def..000000000000 --- a/sys/kern/vfs_acl.c +++ /dev/null @@ -1,277 +0,0 @@ -/*- - * Copyright (c) 1999, 2000 Robert N. M. Watson - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * Generic routines to support file system ACLs, at a syntactic level - * Semantics are the responsibility of the underlying file system - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sysproto.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/vnode.h> -#include <sys/lock.h> -#include <sys/namei.h> -#include <sys/file.h> -#include <sys/proc.h> -#include <sys/sysent.h> -#include <sys/errno.h> -#include <sys/stat.h> -#include <sys/acl.h> -#include <vm/vm_zone.h> - -static MALLOC_DEFINE(M_ACL, "acl", "access control list"); - -static int vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp); -static int vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp); -static int vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp); - -/* - * These calls wrap the real vnode operations, and are called by the - * syscall code once the syscall has converted the path or file - * descriptor to a vnode (unlocked). The aclp pointer is assumed - * still to point to userland, so this should not be consumed within - * the kernel except by syscall code. Other code should directly - * invoke VOP_{SET,GET}ACL. - */ - -/* - * Given a vnode, set its ACL. - */ -static int -vacl_set_acl(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp) -{ - struct acl inkernacl; - int error; - - error = copyin(aclp, &inkernacl, sizeof(struct acl)); - if (error) - return(error); - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - error = VOP_SETACL(vp, type, &inkernacl, p->p_ucred, p); - VOP_UNLOCK(vp, 0, p); - return(error); -} - -/* - * Given a vnode, get its ACL. - */ -static int -vacl_get_acl(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp) -{ - struct acl inkernelacl; - int error; - - error = VOP_GETACL(vp, type, &inkernelacl, p->p_ucred, p); - if (error == 0) - error = copyout(&inkernelacl, aclp, sizeof(struct acl)); - return (error); -} - -/* - * Given a vnode, delete its ACL. - */ -static int -vacl_delete(struct proc *p, struct vnode *vp, acl_type_t type) -{ - int error; - - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - error = VOP_SETACL(vp, ACL_TYPE_DEFAULT, 0, p->p_ucred, p); - VOP_UNLOCK(vp, 0, p); - return (error); -} - -/* - * Given a vnode, check whether an ACL is appropriate for it - */ -static int -vacl_aclcheck(struct proc *p, struct vnode *vp, acl_type_t type, - struct acl *aclp) -{ - struct acl inkernelacl; - int error; - - error = copyin(aclp, &inkernelacl, sizeof(struct acl)); - if (error) - return(error); - error = VOP_ACLCHECK(vp, type, &inkernelacl, p->p_ucred, p); - return (error); -} - -/* - * syscalls -- convert the path/fd to a vnode, and call vacl_whatever. - * Don't need to lock, as the vacl_ code will get/release any locks - * required. - */ - -/* - * Given a file path, get an ACL for it - */ -int -__acl_get_file(struct proc *p, struct __acl_get_file_args *uap) -{ - struct nameidata nd; - int error; - - /* what flags are required here -- possible not LOCKLEAF? */ - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - error = namei(&nd); - if (error) - return(error); - error = vacl_get_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); - NDFREE(&nd, 0); - return (error); -} - -/* - * Given a file path, set an ACL for it - */ -int -__acl_set_file(struct proc *p, struct __acl_set_file_args *uap) -{ - struct nameidata nd; - int error; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - error = namei(&nd); - if (error) - return(error); - error = vacl_set_acl(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); - NDFREE(&nd, 0); - return (error); -} - -/* - * Given a file descriptor, get an ACL for it - */ -int -__acl_get_fd(struct proc *p, struct __acl_get_fd_args *uap) -{ - struct file *fp; - int error; - - error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); - if (error) - return(error); - return vacl_get_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), - SCARG(uap, aclp)); -} - -/* - * Given a file descriptor, set an ACL for it - */ -int -__acl_set_fd(struct proc *p, struct __acl_set_fd_args *uap) -{ - struct file *fp; - int error; - - error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); - if (error) - return(error); - return vacl_set_acl(p, (struct vnode *)fp->f_data, SCARG(uap, type), - SCARG(uap, aclp)); -} - -/* - * Given a file path, delete an ACL from it. - */ -int -__acl_delete_file(struct proc *p, struct __acl_delete_file_args *uap) -{ - struct nameidata nd; - int error; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - error = namei(&nd); - if (error) - return(error); - error = vacl_delete(p, nd.ni_vp, SCARG(uap, type)); - NDFREE(&nd, 0); - return (error); -} - -/* - * Given a file path, delete an ACL from it. - */ -int -__acl_delete_fd(struct proc *p, struct __acl_delete_fd_args *uap) -{ - struct file *fp; - int error; - - error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); - if (error) - return(error); - error = vacl_delete(p, (struct vnode *)fp->f_data, SCARG(uap, type)); - return (error); -} - -/* - * Given a file path, check an ACL for it - */ -int -__acl_aclcheck_file(struct proc *p, struct __acl_aclcheck_file_args *uap) -{ - struct nameidata nd; - int error; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - error = namei(&nd); - if (error) - return(error); - error = vacl_aclcheck(p, nd.ni_vp, SCARG(uap, type), SCARG(uap, aclp)); - NDFREE(&nd, 0); - return (error); -} - -/* - * Given a file descriptor, check an ACL for it - */ -int -__acl_aclcheck_fd(struct proc *p, struct __acl_aclcheck_fd_args *uap) -{ - struct file *fp; - int error; - - error = getvnode(p->p_fd, SCARG(uap, filedes), &fp); - if (error) - return(error); - return vacl_aclcheck(p, (struct vnode *)fp->f_data, SCARG(uap, type), - SCARG(uap, aclp)); -} diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c deleted file mode 100644 index 7d61a1864a23..000000000000 --- a/sys/kern/vfs_export.c +++ /dev/null @@ -1,2974 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)vfs_subr.c 8.31 (Berkeley) 5/26/95 - * $FreeBSD$ - */ - -/* - * External virtual filesystem routines - */ -#include "opt_ddb.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/conf.h> -#include <sys/dirent.h> -#include <sys/domain.h> -#include <sys/eventhandler.h> -#include <sys/fcntl.h> -#include <sys/kernel.h> -#include <sys/kthread.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/namei.h> -#include <sys/proc.h> -#include <sys/reboot.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/sysctl.h> -#include <sys/vmmeter.h> -#include <sys/vnode.h> - -#include <machine/limits.h> - -#include <vm/vm.h> -#include <vm/vm_object.h> -#include <vm/vm_extern.h> -#include <vm/pmap.h> -#include <vm/vm_map.h> -#include <vm/vm_page.h> -#include <vm/vm_pager.h> -#include <vm/vnode_pager.h> -#include <vm/vm_zone.h> - -static MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure"); - -static void insmntque __P((struct vnode *vp, struct mount *mp)); -static void vclean __P((struct vnode *vp, int flags, struct proc *p)); -static void vfree __P((struct vnode *)); -static unsigned long numvnodes; -SYSCTL_INT(_debug, OID_AUTO, numvnodes, CTLFLAG_RD, &numvnodes, 0, ""); - -enum vtype iftovt_tab[16] = { - VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, - VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD, -}; -int vttoif_tab[9] = { - 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, - S_IFSOCK, S_IFIFO, S_IFMT, -}; - -static TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */ -struct tobefreelist vnode_tobefree_list; /* vnode free list */ - -static u_long wantfreevnodes = 25; -SYSCTL_INT(_debug, OID_AUTO, wantfreevnodes, CTLFLAG_RW, &wantfreevnodes, 0, ""); -static u_long freevnodes = 0; -SYSCTL_INT(_debug, OID_AUTO, freevnodes, CTLFLAG_RD, &freevnodes, 0, ""); - -static int reassignbufcalls; -SYSCTL_INT(_vfs, OID_AUTO, reassignbufcalls, CTLFLAG_RW, &reassignbufcalls, 0, ""); -static int reassignbufloops; -SYSCTL_INT(_vfs, OID_AUTO, reassignbufloops, CTLFLAG_RW, &reassignbufloops, 0, ""); -static int reassignbufsortgood; -SYSCTL_INT(_vfs, OID_AUTO, reassignbufsortgood, CTLFLAG_RW, &reassignbufsortgood, 0, ""); -static int reassignbufsortbad; -SYSCTL_INT(_vfs, OID_AUTO, reassignbufsortbad, CTLFLAG_RW, &reassignbufsortbad, 0, ""); -static int reassignbufmethod = 1; -SYSCTL_INT(_vfs, OID_AUTO, reassignbufmethod, CTLFLAG_RW, &reassignbufmethod, 0, ""); - -#ifdef ENABLE_VFS_IOOPT -int vfs_ioopt = 0; -SYSCTL_INT(_vfs, OID_AUTO, ioopt, CTLFLAG_RW, &vfs_ioopt, 0, ""); -#endif - -struct mntlist mountlist = TAILQ_HEAD_INITIALIZER(mountlist); /* mounted fs */ -struct simplelock mountlist_slock; -struct simplelock mntvnode_slock; -int nfs_mount_type = -1; -#ifndef NULL_SIMPLELOCKS -static struct simplelock mntid_slock; -static struct simplelock vnode_free_list_slock; -static struct simplelock spechash_slock; -#endif -struct nfs_public nfs_pub; /* publicly exported FS */ -static vm_zone_t vnode_zone; - -/* - * The workitem queue. - */ -#define SYNCER_MAXDELAY 32 -static int syncer_maxdelay = SYNCER_MAXDELAY; /* maximum delay time */ -time_t syncdelay = 30; /* max time to delay syncing data */ -time_t filedelay = 30; /* time to delay syncing files */ -SYSCTL_INT(_kern, OID_AUTO, filedelay, CTLFLAG_RW, &filedelay, 0, ""); -time_t dirdelay = 29; /* time to delay syncing directories */ -SYSCTL_INT(_kern, OID_AUTO, dirdelay, CTLFLAG_RW, &dirdelay, 0, ""); -time_t metadelay = 28; /* time to delay syncing metadata */ -SYSCTL_INT(_kern, OID_AUTO, metadelay, CTLFLAG_RW, &metadelay, 0, ""); -static int rushjob; /* number of slots to run ASAP */ -static int stat_rush_requests; /* number of times I/O speeded up */ -SYSCTL_INT(_debug, OID_AUTO, rush_requests, CTLFLAG_RW, &stat_rush_requests, 0, ""); - -static int syncer_delayno = 0; -static long syncer_mask; -LIST_HEAD(synclist, vnode); -static struct synclist *syncer_workitem_pending; - -int desiredvnodes; -SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RW, - &desiredvnodes, 0, "Maximum number of vnodes"); - -static void vfs_free_addrlist __P((struct netexport *nep)); -static int vfs_free_netcred __P((struct radix_node *rn, void *w)); -static int vfs_hang_addrlist __P((struct mount *mp, struct netexport *nep, - struct export_args *argp)); - -/* - * Initialize the vnode management data structures. - */ -void -vntblinit() -{ - - desiredvnodes = maxproc + cnt.v_page_count / 4; - simple_lock_init(&mntvnode_slock); - simple_lock_init(&mntid_slock); - simple_lock_init(&spechash_slock); - TAILQ_INIT(&vnode_free_list); - TAILQ_INIT(&vnode_tobefree_list); - simple_lock_init(&vnode_free_list_slock); - vnode_zone = zinit("VNODE", sizeof (struct vnode), 0, 0, 5); - /* - * Initialize the filesystem syncer. - */ - syncer_workitem_pending = hashinit(syncer_maxdelay, M_VNODE, - &syncer_mask); - syncer_maxdelay = syncer_mask + 1; -} - -/* - * Mark a mount point as busy. Used to synchronize access and to delay - * unmounting. Interlock is not released on failure. - */ -int -vfs_busy(mp, flags, interlkp, p) - struct mount *mp; - int flags; - struct simplelock *interlkp; - struct proc *p; -{ - int lkflags; - - if (mp->mnt_kern_flag & MNTK_UNMOUNT) { - if (flags & LK_NOWAIT) - return (ENOENT); - mp->mnt_kern_flag |= MNTK_MWAIT; - if (interlkp) { - simple_unlock(interlkp); - } - /* - * Since all busy locks are shared except the exclusive - * lock granted when unmounting, the only place that a - * wakeup needs to be done is at the release of the - * exclusive lock at the end of dounmount. - */ - tsleep((caddr_t)mp, PVFS, "vfs_busy", 0); - if (interlkp) { - simple_lock(interlkp); - } - return (ENOENT); - } - lkflags = LK_SHARED | LK_NOPAUSE; - if (interlkp) - lkflags |= LK_INTERLOCK; - if (lockmgr(&mp->mnt_lock, lkflags, interlkp, p)) - panic("vfs_busy: unexpected lock failure"); - return (0); -} - -/* - * Free a busy filesystem. - */ -void -vfs_unbusy(mp, p) - struct mount *mp; - struct proc *p; -{ - - lockmgr(&mp->mnt_lock, LK_RELEASE, NULL, p); -} - -/* - * Lookup a filesystem type, and if found allocate and initialize - * a mount structure for it. - * - * Devname is usually updated by mount(8) after booting. - */ -int -vfs_rootmountalloc(fstypename, devname, mpp) - char *fstypename; - char *devname; - struct mount **mpp; -{ - struct proc *p = curproc; /* XXX */ - struct vfsconf *vfsp; - struct mount *mp; - - if (fstypename == NULL) - return (ENODEV); - for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) - if (!strcmp(vfsp->vfc_name, fstypename)) - break; - if (vfsp == NULL) - return (ENODEV); - mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); - bzero((char *)mp, (u_long)sizeof(struct mount)); - lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE); - (void)vfs_busy(mp, LK_NOWAIT, 0, p); - LIST_INIT(&mp->mnt_vnodelist); - mp->mnt_vfc = vfsp; - mp->mnt_op = vfsp->vfc_vfsops; - mp->mnt_flag = MNT_RDONLY; - mp->mnt_vnodecovered = NULLVP; - vfsp->vfc_refcount++; - mp->mnt_iosize_max = DFLTPHYS; - mp->mnt_stat.f_type = vfsp->vfc_typenum; - mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; - strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); - mp->mnt_stat.f_mntonname[0] = '/'; - mp->mnt_stat.f_mntonname[1] = 0; - (void) copystr(devname, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 0); - *mpp = mp; - return (0); -} - -/* - * Find an appropriate filesystem to use for the root. If a filesystem - * has not been preselected, walk through the list of known filesystems - * trying those that have mountroot routines, and try them until one - * works or we have tried them all. - */ -#ifdef notdef /* XXX JH */ -int -lite2_vfs_mountroot() -{ - struct vfsconf *vfsp; - extern int (*lite2_mountroot) __P((void)); - int error; - - if (lite2_mountroot != NULL) - return ((*lite2_mountroot)()); - for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { - if (vfsp->vfc_mountroot == NULL) - continue; - if ((error = (*vfsp->vfc_mountroot)()) == 0) - return (0); - printf("%s_mountroot failed: %d\n", vfsp->vfc_name, error); - } - return (ENODEV); -} -#endif - -/* - * Lookup a mount point by filesystem identifier. - */ -struct mount * -vfs_getvfs(fsid) - fsid_t *fsid; -{ - register struct mount *mp; - - simple_lock(&mountlist_slock); - TAILQ_FOREACH(mp, &mountlist, mnt_list) { - if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] && - mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) { - simple_unlock(&mountlist_slock); - return (mp); - } - } - simple_unlock(&mountlist_slock); - return ((struct mount *) 0); -} - -/* - * Get a new unique fsid. Try to make its val[0] unique mod 2^16, since - * this value may be used to create fake device numbers for stat(), and - * some emulators only support 16-bit device numbers. - * - * Keep in mind that several mounts may be running in parallel. Starting - * the search one past where the previous search terminated (mod 0x10) is - * both a micro-optimization and (incomplete) defense against returning - * the same fsid to different mounts. - */ -void -vfs_getnewfsid(mp) - struct mount *mp; -{ - static u_int mntid_base; - fsid_t tfsid; - u_int i; - int mtype, mynor; - - simple_lock(&mntid_slock); - mtype = mp->mnt_vfc->vfc_typenum; - tfsid.val[1] = mtype; - for (i = 0; ; i++) { - /* - * mtype needs to be uniquely encoded in the minor number - * so that uniqueness of the full fsid implies uniqueness - * of the device number. We are short of bits and only - * guarantee uniqueness of the device number mod 2^16 if - * mtype is always < 16 and there are never more than - * 16 mounts per vfs type. - */ - mynor = ((mntid_base++ & 0xFFFFF) << 4) | (mtype & 0xF); - if (i < 0x10) - mynor &= 0xFF; - tfsid.val[0] = makeudev(255, mynor); - if (vfs_getvfs(&tfsid) == NULL) - break; - } - mp->mnt_stat.f_fsid.val[0] = tfsid.val[0]; - mp->mnt_stat.f_fsid.val[1] = tfsid.val[1]; - simple_unlock(&mntid_slock); -} - -/* - * Knob to control the precision of file timestamps: - * - * 0 = seconds only; nanoseconds zeroed. - * 1 = seconds and nanoseconds, accurate within 1/HZ. - * 2 = seconds and nanoseconds, truncated to microseconds. - * >=3 = seconds and nanoseconds, maximum precision. - */ -enum { TSP_SEC, TSP_HZ, TSP_USEC, TSP_NSEC }; - -static int timestamp_precision = TSP_SEC; -SYSCTL_INT(_vfs, OID_AUTO, timestamp_precision, CTLFLAG_RW, - ×tamp_precision, 0, ""); - -/* - * Get a current timestamp. - */ -void -vfs_timestamp(tsp) - struct timespec *tsp; -{ - struct timeval tv; - - switch (timestamp_precision) { - case TSP_SEC: - tsp->tv_sec = time_second; - tsp->tv_nsec = 0; - break; - case TSP_HZ: - getnanotime(tsp); - break; - case TSP_USEC: - microtime(&tv); - TIMEVAL_TO_TIMESPEC(&tv, tsp); - break; - case TSP_NSEC: - default: - nanotime(tsp); - break; - } -} - -/* - * Set vnode attributes to VNOVAL - */ -void -vattr_null(vap) - register struct vattr *vap; -{ - - vap->va_type = VNON; - vap->va_size = VNOVAL; - vap->va_bytes = VNOVAL; - vap->va_mode = VNOVAL; - vap->va_nlink = VNOVAL; - vap->va_uid = VNOVAL; - vap->va_gid = VNOVAL; - vap->va_fsid = VNOVAL; - vap->va_fileid = VNOVAL; - vap->va_blocksize = VNOVAL; - vap->va_rdev = VNOVAL; - vap->va_atime.tv_sec = VNOVAL; - vap->va_atime.tv_nsec = VNOVAL; - vap->va_mtime.tv_sec = VNOVAL; - vap->va_mtime.tv_nsec = VNOVAL; - vap->va_ctime.tv_sec = VNOVAL; - vap->va_ctime.tv_nsec = VNOVAL; - vap->va_flags = VNOVAL; - vap->va_gen = VNOVAL; - vap->va_vaflags = 0; -} - -/* - * Routines having to do with the management of the vnode table. - */ -extern vop_t **dead_vnodeop_p; - -/* - * Return the next vnode from the free list. - */ -int -getnewvnode(tag, mp, vops, vpp) - enum vtagtype tag; - struct mount *mp; - vop_t **vops; - struct vnode **vpp; -{ - int s; - struct proc *p = curproc; /* XXX */ - struct vnode *vp, *tvp, *nvp; - vm_object_t object; - TAILQ_HEAD(freelst, vnode) vnode_tmp_list; - - /* - * We take the least recently used vnode from the freelist - * if we can get it and it has no cached pages, and no - * namecache entries are relative to it. - * Otherwise we allocate a new vnode - */ - - s = splbio(); - simple_lock(&vnode_free_list_slock); - TAILQ_INIT(&vnode_tmp_list); - - for (vp = TAILQ_FIRST(&vnode_tobefree_list); vp; vp = nvp) { - nvp = TAILQ_NEXT(vp, v_freelist); - TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist); - if (vp->v_flag & VAGE) { - TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); - } else { - TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); - } - vp->v_flag &= ~(VTBFREE|VAGE); - vp->v_flag |= VFREE; - if (vp->v_usecount) - panic("tobe free vnode isn't"); - freevnodes++; - } - - if (wantfreevnodes && freevnodes < wantfreevnodes) { - vp = NULL; - } else if (!wantfreevnodes && freevnodes <= desiredvnodes) { - /* - * XXX: this is only here to be backwards compatible - */ - vp = NULL; - } else { - for (vp = TAILQ_FIRST(&vnode_free_list); vp; vp = nvp) { - nvp = TAILQ_NEXT(vp, v_freelist); - if (!simple_lock_try(&vp->v_interlock)) - continue; - if (vp->v_usecount) - panic("free vnode isn't"); - - object = vp->v_object; - if (object && (object->resident_page_count || object->ref_count)) { - printf("object inconsistant state: RPC: %d, RC: %d\n", - object->resident_page_count, object->ref_count); - /* Don't recycle if it's caching some pages */ - TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); - TAILQ_INSERT_TAIL(&vnode_tmp_list, vp, v_freelist); - continue; - } else if (LIST_FIRST(&vp->v_cache_src)) { - /* Don't recycle if active in the namecache */ - simple_unlock(&vp->v_interlock); - continue; - } else { - break; - } - } - } - - for (tvp = TAILQ_FIRST(&vnode_tmp_list); tvp; tvp = nvp) { - nvp = TAILQ_NEXT(tvp, v_freelist); - TAILQ_REMOVE(&vnode_tmp_list, tvp, v_freelist); - TAILQ_INSERT_TAIL(&vnode_free_list, tvp, v_freelist); - simple_unlock(&tvp->v_interlock); - } - - if (vp) { - vp->v_flag |= VDOOMED; - TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); - freevnodes--; - simple_unlock(&vnode_free_list_slock); - cache_purge(vp); - vp->v_lease = NULL; - if (vp->v_type != VBAD) { - vgonel(vp, p); - } else { - simple_unlock(&vp->v_interlock); - } - -#ifdef INVARIANTS - { - int s; - - if (vp->v_data) - panic("cleaned vnode isn't"); - s = splbio(); - if (vp->v_numoutput) - panic("Clean vnode has pending I/O's"); - splx(s); - } -#endif - vp->v_flag = 0; - vp->v_lastw = 0; - vp->v_lasta = 0; - vp->v_cstart = 0; - vp->v_clen = 0; - vp->v_socket = 0; - vp->v_writecount = 0; /* XXX */ - } else { - simple_unlock(&vnode_free_list_slock); - vp = (struct vnode *) zalloc(vnode_zone); - bzero((char *) vp, sizeof *vp); - simple_lock_init(&vp->v_interlock); - vp->v_dd = vp; - cache_purge(vp); - LIST_INIT(&vp->v_cache_src); - TAILQ_INIT(&vp->v_cache_dst); - numvnodes++; - } - - TAILQ_INIT(&vp->v_cleanblkhd); - TAILQ_INIT(&vp->v_dirtyblkhd); - vp->v_type = VNON; - vp->v_tag = tag; - vp->v_op = vops; - insmntque(vp, mp); - *vpp = vp; - vp->v_usecount = 1; - vp->v_data = 0; - splx(s); - - vfs_object_create(vp, p, p->p_ucred); - return (0); -} - -/* - * Move a vnode from one mount queue to another. - */ -static void -insmntque(vp, mp) - register struct vnode *vp; - register struct mount *mp; -{ - - simple_lock(&mntvnode_slock); - /* - * Delete from old mount point vnode list, if on one. - */ - if (vp->v_mount != NULL) - LIST_REMOVE(vp, v_mntvnodes); - /* - * Insert into list of vnodes for the new mount point, if available. - */ - if ((vp->v_mount = mp) == NULL) { - simple_unlock(&mntvnode_slock); - return; - } - LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes); - simple_unlock(&mntvnode_slock); -} - -/* - * Update outstanding I/O count and do wakeup if requested. - */ -void -vwakeup(bp) - register struct buf *bp; -{ - register struct vnode *vp; - - bp->b_flags &= ~B_WRITEINPROG; - if ((vp = bp->b_vp)) { - vp->v_numoutput--; - if (vp->v_numoutput < 0) - panic("vwakeup: neg numoutput"); - if ((vp->v_numoutput == 0) && (vp->v_flag & VBWAIT)) { - vp->v_flag &= ~VBWAIT; - wakeup((caddr_t) &vp->v_numoutput); - } - } -} - -/* - * Flush out and invalidate all buffers associated with a vnode. - * Called with the underlying object locked. - */ -int -vinvalbuf(vp, flags, cred, p, slpflag, slptimeo) - register struct vnode *vp; - int flags; - struct ucred *cred; - struct proc *p; - int slpflag, slptimeo; -{ - register struct buf *bp; - struct buf *nbp, *blist; - int s, error; - vm_object_t object; - - if (flags & V_SAVE) { - s = splbio(); - while (vp->v_numoutput) { - vp->v_flag |= VBWAIT; - error = tsleep((caddr_t)&vp->v_numoutput, - slpflag | (PRIBIO + 1), "vinvlbuf", slptimeo); - if (error) { - splx(s); - return (error); - } - } - if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) { - splx(s); - if ((error = VOP_FSYNC(vp, cred, MNT_WAIT, p)) != 0) - return (error); - s = splbio(); - if (vp->v_numoutput > 0 || - !TAILQ_EMPTY(&vp->v_dirtyblkhd)) - panic("vinvalbuf: dirty bufs"); - } - splx(s); - } - s = splbio(); - for (;;) { - blist = TAILQ_FIRST(&vp->v_cleanblkhd); - if (!blist) - blist = TAILQ_FIRST(&vp->v_dirtyblkhd); - if (!blist) - break; - - for (bp = blist; bp; bp = nbp) { - nbp = TAILQ_NEXT(bp, b_vnbufs); - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) { - error = BUF_TIMELOCK(bp, - LK_EXCLUSIVE | LK_SLEEPFAIL, - "vinvalbuf", slpflag, slptimeo); - if (error == ENOLCK) - break; - splx(s); - return (error); - } - /* - * XXX Since there are no node locks for NFS, I - * believe there is a slight chance that a delayed - * write will occur while sleeping just above, so - * check for it. Note that vfs_bio_awrite expects - * buffers to reside on a queue, while VOP_BWRITE and - * brelse do not. - */ - if (((bp->b_flags & (B_DELWRI | B_INVAL)) == B_DELWRI) && - (flags & V_SAVE)) { - - if (bp->b_vp == vp) { - if (bp->b_flags & B_CLUSTEROK) { - BUF_UNLOCK(bp); - vfs_bio_awrite(bp); - } else { - bremfree(bp); - bp->b_flags |= B_ASYNC; - VOP_BWRITE(bp->b_vp, bp); - } - } else { - bremfree(bp); - (void) VOP_BWRITE(bp->b_vp, bp); - } - break; - } - bremfree(bp); - bp->b_flags |= (B_INVAL | B_NOCACHE | B_RELBUF); - bp->b_flags &= ~B_ASYNC; - brelse(bp); - } - } - - while (vp->v_numoutput > 0) { - vp->v_flag |= VBWAIT; - tsleep(&vp->v_numoutput, PVM, "vnvlbv", 0); - } - - splx(s); - - /* - * Destroy the copy in the VM cache, too. - */ - simple_lock(&vp->v_interlock); - object = vp->v_object; - if (object != NULL) { - vm_object_page_remove(object, 0, 0, - (flags & V_SAVE) ? TRUE : FALSE); - } - simple_unlock(&vp->v_interlock); - - if (!TAILQ_EMPTY(&vp->v_dirtyblkhd) || !TAILQ_EMPTY(&vp->v_cleanblkhd)) - panic("vinvalbuf: flush failed"); - return (0); -} - -/* - * Truncate a file's buffer and pages to a specified length. This - * is in lieu of the old vinvalbuf mechanism, which performed unneeded - * sync activity. - */ -int -vtruncbuf(vp, cred, p, length, blksize) - register struct vnode *vp; - struct ucred *cred; - struct proc *p; - off_t length; - int blksize; -{ - register struct buf *bp; - struct buf *nbp; - int s, anyfreed; - int trunclbn; - - /* - * Round up to the *next* lbn. - */ - trunclbn = (length + blksize - 1) / blksize; - - s = splbio(); -restart: - anyfreed = 1; - for (;anyfreed;) { - anyfreed = 0; - for (bp = TAILQ_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) { - nbp = TAILQ_NEXT(bp, b_vnbufs); - if (bp->b_lblkno >= trunclbn) { - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) { - BUF_LOCK(bp, LK_EXCLUSIVE|LK_SLEEPFAIL); - goto restart; - } else { - bremfree(bp); - bp->b_flags |= (B_INVAL | B_RELBUF); - bp->b_flags &= ~B_ASYNC; - brelse(bp); - anyfreed = 1; - } - if (nbp && - (((nbp->b_xflags & BX_VNCLEAN) == 0) || - (nbp->b_vp != vp) || - (nbp->b_flags & B_DELWRI))) { - goto restart; - } - } - } - - for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { - nbp = TAILQ_NEXT(bp, b_vnbufs); - if (bp->b_lblkno >= trunclbn) { - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) { - BUF_LOCK(bp, LK_EXCLUSIVE|LK_SLEEPFAIL); - goto restart; - } else { - bremfree(bp); - bp->b_flags |= (B_INVAL | B_RELBUF); - bp->b_flags &= ~B_ASYNC; - brelse(bp); - anyfreed = 1; - } - if (nbp && - (((nbp->b_xflags & BX_VNDIRTY) == 0) || - (nbp->b_vp != vp) || - (nbp->b_flags & B_DELWRI) == 0)) { - goto restart; - } - } - } - } - - if (length > 0) { -restartsync: - for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { - nbp = TAILQ_NEXT(bp, b_vnbufs); - if ((bp->b_flags & B_DELWRI) && (bp->b_lblkno < 0)) { - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) { - BUF_LOCK(bp, LK_EXCLUSIVE|LK_SLEEPFAIL); - goto restart; - } else { - bremfree(bp); - if (bp->b_vp == vp) { - bp->b_flags |= B_ASYNC; - } else { - bp->b_flags &= ~B_ASYNC; - } - VOP_BWRITE(bp->b_vp, bp); - } - goto restartsync; - } - - } - } - - while (vp->v_numoutput > 0) { - vp->v_flag |= VBWAIT; - tsleep(&vp->v_numoutput, PVM, "vbtrunc", 0); - } - - splx(s); - - vnode_pager_setsize(vp, length); - - return (0); -} - -/* - * Associate a buffer with a vnode. - */ -void -bgetvp(vp, bp) - register struct vnode *vp; - register struct buf *bp; -{ - int s; - - KASSERT(bp->b_vp == NULL, ("bgetvp: not free")); - - vhold(vp); - bp->b_vp = vp; - bp->b_dev = vn_todev(vp); - /* - * Insert onto list for new vnode. - */ - s = splbio(); - bp->b_xflags |= BX_VNCLEAN; - bp->b_xflags &= ~BX_VNDIRTY; - TAILQ_INSERT_TAIL(&vp->v_cleanblkhd, bp, b_vnbufs); - splx(s); -} - -/* - * Disassociate a buffer from a vnode. - */ -void -brelvp(bp) - register struct buf *bp; -{ - struct vnode *vp; - struct buflists *listheadp; - int s; - - KASSERT(bp->b_vp != NULL, ("brelvp: NULL")); - - /* - * Delete from old vnode list, if on one. - */ - vp = bp->b_vp; - s = splbio(); - if (bp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) { - if (bp->b_xflags & BX_VNDIRTY) - listheadp = &vp->v_dirtyblkhd; - else - listheadp = &vp->v_cleanblkhd; - TAILQ_REMOVE(listheadp, bp, b_vnbufs); - bp->b_xflags &= ~(BX_VNDIRTY | BX_VNCLEAN); - } - if ((vp->v_flag & VONWORKLST) && TAILQ_EMPTY(&vp->v_dirtyblkhd)) { - vp->v_flag &= ~VONWORKLST; - LIST_REMOVE(vp, v_synclist); - } - splx(s); - bp->b_vp = (struct vnode *) 0; - vdrop(vp); -} - -/* - * The workitem queue. - * - * It is useful to delay writes of file data and filesystem metadata - * for tens of seconds so that quickly created and deleted files need - * not waste disk bandwidth being created and removed. To realize this, - * we append vnodes to a "workitem" queue. When running with a soft - * updates implementation, most pending metadata dependencies should - * not wait for more than a few seconds. Thus, mounted on block devices - * are delayed only about a half the time that file data is delayed. - * Similarly, directory updates are more critical, so are only delayed - * about a third the time that file data is delayed. Thus, there are - * SYNCER_MAXDELAY queues that are processed round-robin at a rate of - * one each second (driven off the filesystem syncer process). The - * syncer_delayno variable indicates the next queue that is to be processed. - * Items that need to be processed soon are placed in this queue: - * - * syncer_workitem_pending[syncer_delayno] - * - * A delay of fifteen seconds is done by placing the request fifteen - * entries later in the queue: - * - * syncer_workitem_pending[(syncer_delayno + 15) & syncer_mask] - * - */ - -/* - * Add an item to the syncer work queue. - */ -static void -vn_syncer_add_to_worklist(struct vnode *vp, int delay) -{ - int s, slot; - - s = splbio(); - - if (vp->v_flag & VONWORKLST) { - LIST_REMOVE(vp, v_synclist); - } - - if (delay > syncer_maxdelay - 2) - delay = syncer_maxdelay - 2; - slot = (syncer_delayno + delay) & syncer_mask; - - LIST_INSERT_HEAD(&syncer_workitem_pending[slot], vp, v_synclist); - vp->v_flag |= VONWORKLST; - splx(s); -} - -struct proc *updateproc; -static void sched_sync __P((void)); -static struct kproc_desc up_kp = { - "syncer", - sched_sync, - &updateproc -}; -SYSINIT(syncer, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, &up_kp) - -/* - * System filesystem synchronizer daemon. - */ -void -sched_sync(void) -{ - struct synclist *slp; - struct vnode *vp; - long starttime; - int s; - struct proc *p = updateproc; - - EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_kproc, p, - SHUTDOWN_PRI_LAST); - - for (;;) { - kproc_suspend_loop(p); - - starttime = time_second; - - /* - * Push files whose dirty time has expired. Be careful - * of interrupt race on slp queue. - */ - s = splbio(); - slp = &syncer_workitem_pending[syncer_delayno]; - syncer_delayno += 1; - if (syncer_delayno == syncer_maxdelay) - syncer_delayno = 0; - splx(s); - - while ((vp = LIST_FIRST(slp)) != NULL) { - if (VOP_ISLOCKED(vp, NULL) == 0) { - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - (void) VOP_FSYNC(vp, p->p_ucred, MNT_LAZY, p); - VOP_UNLOCK(vp, 0, p); - } - s = splbio(); - if (LIST_FIRST(slp) == vp) { - /* - * Note: v_tag VT_VFS vps can remain on the - * worklist too with no dirty blocks, but - * since sync_fsync() moves it to a different - * slot we are safe. - */ - if (TAILQ_EMPTY(&vp->v_dirtyblkhd) && - !vn_isdisk(vp, NULL)) - panic("sched_sync: fsync failed vp %p tag %d", vp, vp->v_tag); - /* - * Put us back on the worklist. The worklist - * routine will remove us from our current - * position and then add us back in at a later - * position. - */ - vn_syncer_add_to_worklist(vp, syncdelay); - } - splx(s); - } - - /* - * Do soft update processing. - */ - if (bioops.io_sync) - (*bioops.io_sync)(NULL); - - /* - * The variable rushjob allows the kernel to speed up the - * processing of the filesystem syncer process. A rushjob - * value of N tells the filesystem syncer to process the next - * N seconds worth of work on its queue ASAP. Currently rushjob - * is used by the soft update code to speed up the filesystem - * syncer process when the incore state is getting so far - * ahead of the disk that the kernel memory pool is being - * threatened with exhaustion. - */ - if (rushjob > 0) { - rushjob -= 1; - continue; - } - /* - * If it has taken us less than a second to process the - * current work, then wait. Otherwise start right over - * again. We can still lose time if any single round - * takes more than two seconds, but it does not really - * matter as we are just trying to generally pace the - * filesystem activity. - */ - if (time_second == starttime) - tsleep(&lbolt, PPAUSE, "syncer", 0); - } -} - -/* - * Request the syncer daemon to speed up its work. - * We never push it to speed up more than half of its - * normal turn time, otherwise it could take over the cpu. - */ -int -speedup_syncer() -{ - int s; - - s = splhigh(); - if (updateproc->p_wchan == &lbolt) - setrunnable(updateproc); - splx(s); - if (rushjob < syncdelay / 2) { - rushjob += 1; - stat_rush_requests += 1; - return (1); - } - return(0); -} - -/* - * Associate a p-buffer with a vnode. - * - * Also sets B_PAGING flag to indicate that vnode is not fully associated - * with the buffer. i.e. the bp has not been linked into the vnode or - * ref-counted. - */ -void -pbgetvp(vp, bp) - register struct vnode *vp; - register struct buf *bp; -{ - - KASSERT(bp->b_vp == NULL, ("pbgetvp: not free")); - - bp->b_vp = vp; - bp->b_flags |= B_PAGING; - bp->b_dev = vn_todev(vp); -} - -/* - * Disassociate a p-buffer from a vnode. - */ -void -pbrelvp(bp) - register struct buf *bp; -{ - - KASSERT(bp->b_vp != NULL, ("pbrelvp: NULL")); - -#if !defined(MAX_PERF) - /* XXX REMOVE ME */ - if (bp->b_vnbufs.tqe_next != NULL) { - panic( - "relpbuf(): b_vp was probably reassignbuf()d %p %x", - bp, - (int)bp->b_flags - ); - } -#endif - bp->b_vp = (struct vnode *) 0; - bp->b_flags &= ~B_PAGING; -} - -void -pbreassignbuf(bp, newvp) - struct buf *bp; - struct vnode *newvp; -{ -#if !defined(MAX_PERF) - if ((bp->b_flags & B_PAGING) == 0) { - panic( - "pbreassignbuf() on non phys bp %p", - bp - ); - } -#endif - bp->b_vp = newvp; -} - -/* - * Reassign a buffer from one vnode to another. - * Used to assign file specific control information - * (indirect blocks) to the vnode to which they belong. - */ -void -reassignbuf(bp, newvp) - register struct buf *bp; - register struct vnode *newvp; -{ - struct buflists *listheadp; - int delay; - int s; - - if (newvp == NULL) { - printf("reassignbuf: NULL"); - return; - } - ++reassignbufcalls; - -#if !defined(MAX_PERF) - /* - * B_PAGING flagged buffers cannot be reassigned because their vp - * is not fully linked in. - */ - if (bp->b_flags & B_PAGING) - panic("cannot reassign paging buffer"); -#endif - - s = splbio(); - /* - * Delete from old vnode list, if on one. - */ - if (bp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) { - if (bp->b_xflags & BX_VNDIRTY) - listheadp = &bp->b_vp->v_dirtyblkhd; - else - listheadp = &bp->b_vp->v_cleanblkhd; - TAILQ_REMOVE(listheadp, bp, b_vnbufs); - bp->b_xflags &= ~(BX_VNDIRTY | BX_VNCLEAN); - if (bp->b_vp != newvp) { - vdrop(bp->b_vp); - bp->b_vp = NULL; /* for clarification */ - } - } - /* - * If dirty, put on list of dirty buffers; otherwise insert onto list - * of clean buffers. - */ - if (bp->b_flags & B_DELWRI) { - struct buf *tbp; - - listheadp = &newvp->v_dirtyblkhd; - if ((newvp->v_flag & VONWORKLST) == 0) { - switch (newvp->v_type) { - case VDIR: - delay = dirdelay; - break; - case VCHR: - case VBLK: - if (newvp->v_specmountpoint != NULL) { - delay = metadelay; - break; - } - /* fall through */ - default: - delay = filedelay; - } - vn_syncer_add_to_worklist(newvp, delay); - } - bp->b_xflags |= BX_VNDIRTY; - tbp = TAILQ_FIRST(listheadp); - if (tbp == NULL || - bp->b_lblkno == 0 || - (bp->b_lblkno > 0 && tbp->b_lblkno < 0) || - (bp->b_lblkno > 0 && bp->b_lblkno < tbp->b_lblkno)) { - TAILQ_INSERT_HEAD(listheadp, bp, b_vnbufs); - ++reassignbufsortgood; - } else if (bp->b_lblkno < 0) { - TAILQ_INSERT_TAIL(listheadp, bp, b_vnbufs); - ++reassignbufsortgood; - } else if (reassignbufmethod == 1) { - /* - * New sorting algorithm, only handle sequential case, - * otherwise append to end (but before metadata) - */ - if ((tbp = gbincore(newvp, bp->b_lblkno - 1)) != NULL && - (tbp->b_xflags & BX_VNDIRTY)) { - /* - * Found the best place to insert the buffer - */ - TAILQ_INSERT_AFTER(listheadp, tbp, bp, b_vnbufs); - ++reassignbufsortgood; - } else { - /* - * Missed, append to end, but before meta-data. - * We know that the head buffer in the list is - * not meta-data due to prior conditionals. - * - * Indirect effects: NFS second stage write - * tends to wind up here, giving maximum - * distance between the unstable write and the - * commit rpc. - */ - tbp = TAILQ_LAST(listheadp, buflists); - while (tbp && tbp->b_lblkno < 0) - tbp = TAILQ_PREV(tbp, buflists, b_vnbufs); - TAILQ_INSERT_AFTER(listheadp, tbp, bp, b_vnbufs); - ++reassignbufsortbad; - } - } else { - /* - * Old sorting algorithm, scan queue and insert - */ - struct buf *ttbp; - while ((ttbp = TAILQ_NEXT(tbp, b_vnbufs)) && - (ttbp->b_lblkno < bp->b_lblkno)) { - ++reassignbufloops; - tbp = ttbp; - } - TAILQ_INSERT_AFTER(listheadp, tbp, bp, b_vnbufs); - } - } else { - bp->b_xflags |= BX_VNCLEAN; - TAILQ_INSERT_TAIL(&newvp->v_cleanblkhd, bp, b_vnbufs); - if ((newvp->v_flag & VONWORKLST) && - TAILQ_EMPTY(&newvp->v_dirtyblkhd)) { - newvp->v_flag &= ~VONWORKLST; - LIST_REMOVE(newvp, v_synclist); - } - } - if (bp->b_vp != newvp) { - bp->b_vp = newvp; - vhold(bp->b_vp); - } - splx(s); -} - -/* - * Create a vnode for a block device. - * Used for mounting the root file system. - */ -int -bdevvp(dev, vpp) - dev_t dev; - struct vnode **vpp; -{ - register struct vnode *vp; - struct vnode *nvp; - int error; - - if (dev == NODEV) { - *vpp = NULLVP; - return (ENXIO); - } - error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); - if (error) { - *vpp = NULLVP; - return (error); - } - vp = nvp; - vp->v_type = VBLK; - addalias(vp, dev); - *vpp = vp; - return (0); -} - -/* - * Add vnode to the alias list hung off the dev_t. - * - * The reason for this gunk is that multiple vnodes can reference - * the same physical device, so checking vp->v_usecount to see - * how many users there are is inadequate; the v_usecount for - * the vnodes need to be accumulated. vcount() does that. - */ -void -addaliasu(nvp, nvp_rdev) - struct vnode *nvp; - udev_t nvp_rdev; -{ - - if (nvp->v_type != VBLK && nvp->v_type != VCHR) - panic("addaliasu on non-special vnode"); - addalias(nvp, udev2dev(nvp_rdev, nvp->v_type == VBLK ? 1 : 0)); -} - -void -addalias(nvp, dev) - struct vnode *nvp; - dev_t dev; -{ - - if (nvp->v_type != VBLK && nvp->v_type != VCHR) - panic("addalias on non-special vnode"); - - nvp->v_rdev = dev; - simple_lock(&spechash_slock); - SLIST_INSERT_HEAD(&dev->si_hlist, nvp, v_specnext); - simple_unlock(&spechash_slock); -} - -/* - * Grab a particular vnode from the free list, increment its - * reference count and lock it. The vnode lock bit is set if the - * vnode is being eliminated in vgone. The process is awakened - * when the transition is completed, and an error returned to - * indicate that the vnode is no longer usable (possibly having - * been changed to a new file system type). - */ -int -vget(vp, flags, p) - register struct vnode *vp; - int flags; - struct proc *p; -{ - int error; - - /* - * If the vnode is in the process of being cleaned out for - * another use, we wait for the cleaning to finish and then - * return failure. Cleaning is determined by checking that - * the VXLOCK flag is set. - */ - if ((flags & LK_INTERLOCK) == 0) { - simple_lock(&vp->v_interlock); - } - if (vp->v_flag & VXLOCK) { - vp->v_flag |= VXWANT; - simple_unlock(&vp->v_interlock); - tsleep((caddr_t)vp, PINOD, "vget", 0); - return (ENOENT); - } - - vp->v_usecount++; - - if (VSHOULDBUSY(vp)) - vbusy(vp); - if (flags & LK_TYPE_MASK) { - if ((error = vn_lock(vp, flags | LK_INTERLOCK, p)) != 0) { - /* - * must expand vrele here because we do not want - * to call VOP_INACTIVE if the reference count - * drops back to zero since it was never really - * active. We must remove it from the free list - * before sleeping so that multiple processes do - * not try to recycle it. - */ - simple_lock(&vp->v_interlock); - vp->v_usecount--; - if (VSHOULDFREE(vp)) - vfree(vp); - simple_unlock(&vp->v_interlock); - } - return (error); - } - simple_unlock(&vp->v_interlock); - return (0); -} - -void -vref(struct vnode *vp) -{ - simple_lock(&vp->v_interlock); - vp->v_usecount++; - simple_unlock(&vp->v_interlock); -} - -/* - * Vnode put/release. - * If count drops to zero, call inactive routine and return to freelist. - */ -void -vrele(vp) - struct vnode *vp; -{ - struct proc *p = curproc; /* XXX */ - - KASSERT(vp != NULL, ("vrele: null vp")); - - simple_lock(&vp->v_interlock); - - if (vp->v_usecount > 1) { - - vp->v_usecount--; - simple_unlock(&vp->v_interlock); - - return; - } - - if (vp->v_usecount == 1) { - - vp->v_usecount--; - if (VSHOULDFREE(vp)) - vfree(vp); - /* - * If we are doing a vput, the node is already locked, and we must - * call VOP_INACTIVE with the node locked. So, in the case of - * vrele, we explicitly lock the vnode before calling VOP_INACTIVE. - */ - if (vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK, p) == 0) { - VOP_INACTIVE(vp, p); - } - - } else { -#ifdef DIAGNOSTIC - vprint("vrele: negative ref count", vp); - simple_unlock(&vp->v_interlock); -#endif - panic("vrele: negative ref cnt"); - } -} - -void -vput(vp) - struct vnode *vp; -{ - struct proc *p = curproc; /* XXX */ - - KASSERT(vp != NULL, ("vput: null vp")); - - simple_lock(&vp->v_interlock); - - if (vp->v_usecount > 1) { - - vp->v_usecount--; - VOP_UNLOCK(vp, LK_INTERLOCK, p); - return; - - } - - if (vp->v_usecount == 1) { - - vp->v_usecount--; - if (VSHOULDFREE(vp)) - vfree(vp); - /* - * If we are doing a vput, the node is already locked, and we must - * call VOP_INACTIVE with the node locked. So, in the case of - * vrele, we explicitly lock the vnode before calling VOP_INACTIVE. - */ - simple_unlock(&vp->v_interlock); - VOP_INACTIVE(vp, p); - - } else { -#ifdef DIAGNOSTIC - vprint("vput: negative ref count", vp); -#endif - panic("vput: negative ref cnt"); - } -} - -/* - * Somebody doesn't want the vnode recycled. - */ -void -vhold(vp) - register struct vnode *vp; -{ - int s; - - s = splbio(); - vp->v_holdcnt++; - if (VSHOULDBUSY(vp)) - vbusy(vp); - splx(s); -} - -/* - * One less who cares about this vnode. - */ -void -vdrop(vp) - register struct vnode *vp; -{ - int s; - - s = splbio(); - if (vp->v_holdcnt <= 0) - panic("vdrop: holdcnt"); - vp->v_holdcnt--; - if (VSHOULDFREE(vp)) - vfree(vp); - splx(s); -} - -/* - * Remove any vnodes in the vnode table belonging to mount point mp. - * - * If MNT_NOFORCE is specified, there should not be any active ones, - * return error if any are found (nb: this is a user error, not a - * system error). If MNT_FORCE is specified, detach any active vnodes - * that are found. - */ -#ifdef DIAGNOSTIC -static int busyprt = 0; /* print out busy vnodes */ -SYSCTL_INT(_debug, OID_AUTO, busyprt, CTLFLAG_RW, &busyprt, 0, ""); -#endif - -int -vflush(mp, skipvp, flags) - struct mount *mp; - struct vnode *skipvp; - int flags; -{ - struct proc *p = curproc; /* XXX */ - struct vnode *vp, *nvp; - int busy = 0; - - simple_lock(&mntvnode_slock); -loop: - for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) { - /* - * Make sure this vnode wasn't reclaimed in getnewvnode(). - * Start over if it has (it won't be on the list anymore). - */ - if (vp->v_mount != mp) - goto loop; - nvp = LIST_NEXT(vp, v_mntvnodes); - /* - * Skip over a selected vnode. - */ - if (vp == skipvp) - continue; - - simple_lock(&vp->v_interlock); - /* - * Skip over a vnodes marked VSYSTEM. - */ - if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) { - simple_unlock(&vp->v_interlock); - continue; - } - /* - * If WRITECLOSE is set, only flush out regular file vnodes - * open for writing. - */ - if ((flags & WRITECLOSE) && - (vp->v_writecount == 0 || vp->v_type != VREG)) { - simple_unlock(&vp->v_interlock); - continue; - } - - /* - * With v_usecount == 0, all we need to do is clear out the - * vnode data structures and we are done. - */ - if (vp->v_usecount == 0) { - simple_unlock(&mntvnode_slock); - vgonel(vp, p); - simple_lock(&mntvnode_slock); - continue; - } - - /* - * If FORCECLOSE is set, forcibly close the vnode. For block - * or character devices, revert to an anonymous device. For - * all other files, just kill them. - */ - if (flags & FORCECLOSE) { - simple_unlock(&mntvnode_slock); - if (vp->v_type != VBLK && vp->v_type != VCHR) { - vgonel(vp, p); - } else { - vclean(vp, 0, p); - vp->v_op = spec_vnodeop_p; - insmntque(vp, (struct mount *) 0); - } - simple_lock(&mntvnode_slock); - continue; - } -#ifdef DIAGNOSTIC - if (busyprt) - vprint("vflush: busy vnode", vp); -#endif - simple_unlock(&vp->v_interlock); - busy++; - } - simple_unlock(&mntvnode_slock); - if (busy) - return (EBUSY); - return (0); -} - -/* - * Disassociate the underlying file system from a vnode. - */ -static void -vclean(vp, flags, p) - struct vnode *vp; - int flags; - struct proc *p; -{ - int active; - vm_object_t obj; - - /* - * Check to see if the vnode is in use. If so we have to reference it - * before we clean it out so that its count cannot fall to zero and - * generate a race against ourselves to recycle it. - */ - if ((active = vp->v_usecount)) - vp->v_usecount++; - - /* - * Prevent the vnode from being recycled or brought into use while we - * clean it out. - */ - if (vp->v_flag & VXLOCK) - panic("vclean: deadlock"); - vp->v_flag |= VXLOCK; - /* - * Even if the count is zero, the VOP_INACTIVE routine may still - * have the object locked while it cleans it out. The VOP_LOCK - * ensures that the VOP_INACTIVE routine is done with its work. - * For active vnodes, it ensures that no other activity can - * occur while the underlying object is being cleaned out. - */ - VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, p); - - /* - * Clean out any buffers associated with the vnode. - */ - vinvalbuf(vp, V_SAVE, NOCRED, p, 0, 0); - if ((obj = vp->v_object) != NULL) { - if (obj->ref_count == 0) { - /* - * vclean() may be called twice. The first time removes the - * primary reference to the object, the second time goes - * one further and is a special-case to terminate the object. - */ - vm_object_terminate(obj); - } else { - /* - * Woe to the process that tries to page now :-). - */ - vm_pager_deallocate(obj); - } - } - - /* - * If purging an active vnode, it must be closed and - * deactivated before being reclaimed. Note that the - * VOP_INACTIVE will unlock the vnode. - */ - if (active) { - if (flags & DOCLOSE) - VOP_CLOSE(vp, FNONBLOCK, NOCRED, p); - VOP_INACTIVE(vp, p); - } else { - /* - * Any other processes trying to obtain this lock must first - * wait for VXLOCK to clear, then call the new lock operation. - */ - VOP_UNLOCK(vp, 0, p); - } - /* - * Reclaim the vnode. - */ - if (VOP_RECLAIM(vp, p)) - panic("vclean: cannot reclaim"); - - if (active) { - /* - * Inline copy of vrele() since VOP_INACTIVE - * has already been called. - */ - simple_lock(&vp->v_interlock); - if (--vp->v_usecount <= 0) { -#ifdef DIAGNOSTIC - if (vp->v_usecount < 0 || vp->v_writecount != 0) { - vprint("vclean: bad ref count", vp); - panic("vclean: ref cnt"); - } -#endif - vfree(vp); - } - simple_unlock(&vp->v_interlock); - } - - cache_purge(vp); - if (vp->v_vnlock) { - FREE(vp->v_vnlock, M_VNODE); - vp->v_vnlock = NULL; - } - - if (VSHOULDFREE(vp)) - vfree(vp); - - /* - * Done with purge, notify sleepers of the grim news. - */ - vp->v_op = dead_vnodeop_p; - vn_pollgone(vp); - vp->v_tag = VT_NON; - vp->v_flag &= ~VXLOCK; - if (vp->v_flag & VXWANT) { - vp->v_flag &= ~VXWANT; - wakeup((caddr_t) vp); - } -} - -/* - * Eliminate all activity associated with the requested vnode - * and with all vnodes aliased to the requested vnode. - */ -int -vop_revoke(ap) - struct vop_revoke_args /* { - struct vnode *a_vp; - int a_flags; - } */ *ap; -{ - struct vnode *vp, *vq; - dev_t dev; - - KASSERT((ap->a_flags & REVOKEALL) != 0, ("vop_revoke")); - - vp = ap->a_vp; - /* - * If a vgone (or vclean) is already in progress, - * wait until it is done and return. - */ - if (vp->v_flag & VXLOCK) { - vp->v_flag |= VXWANT; - simple_unlock(&vp->v_interlock); - tsleep((caddr_t)vp, PINOD, "vop_revokeall", 0); - return (0); - } - dev = vp->v_rdev; - for (;;) { - simple_lock(&spechash_slock); - vq = SLIST_FIRST(&dev->si_hlist); - simple_unlock(&spechash_slock); - if (!vq) - break; - vgone(vq); - } - return (0); -} - -/* - * Recycle an unused vnode to the front of the free list. - * Release the passed interlock if the vnode will be recycled. - */ -int -vrecycle(vp, inter_lkp, p) - struct vnode *vp; - struct simplelock *inter_lkp; - struct proc *p; -{ - - simple_lock(&vp->v_interlock); - if (vp->v_usecount == 0) { - if (inter_lkp) { - simple_unlock(inter_lkp); - } - vgonel(vp, p); - return (1); - } - simple_unlock(&vp->v_interlock); - return (0); -} - -/* - * Eliminate all activity associated with a vnode - * in preparation for reuse. - */ -void -vgone(vp) - register struct vnode *vp; -{ - struct proc *p = curproc; /* XXX */ - - simple_lock(&vp->v_interlock); - vgonel(vp, p); -} - -/* - * vgone, with the vp interlock held. - */ -void -vgonel(vp, p) - struct vnode *vp; - struct proc *p; -{ - int s; - - /* - * If a vgone (or vclean) is already in progress, - * wait until it is done and return. - */ - if (vp->v_flag & VXLOCK) { - vp->v_flag |= VXWANT; - simple_unlock(&vp->v_interlock); - tsleep((caddr_t)vp, PINOD, "vgone", 0); - return; - } - - /* - * Clean out the filesystem specific data. - */ - vclean(vp, DOCLOSE, p); - simple_lock(&vp->v_interlock); - - /* - * Delete from old mount point vnode list, if on one. - */ - if (vp->v_mount != NULL) - insmntque(vp, (struct mount *)0); - /* - * If special device, remove it from special device alias list - * if it is on one. - */ - if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_rdev != NULL) { - simple_lock(&spechash_slock); - SLIST_REMOVE(&vp->v_hashchain, vp, vnode, v_specnext); - freedev(vp->v_rdev); - simple_unlock(&spechash_slock); - vp->v_rdev = NULL; - } - - /* - * If it is on the freelist and not already at the head, - * move it to the head of the list. The test of the back - * pointer and the reference count of zero is because - * it will be removed from the free list by getnewvnode, - * but will not have its reference count incremented until - * after calling vgone. If the reference count were - * incremented first, vgone would (incorrectly) try to - * close the previous instance of the underlying object. - */ - if (vp->v_usecount == 0 && !(vp->v_flag & VDOOMED)) { - s = splbio(); - simple_lock(&vnode_free_list_slock); - if (vp->v_flag & VFREE) { - TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); - } else if (vp->v_flag & VTBFREE) { - TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist); - vp->v_flag &= ~VTBFREE; - freevnodes++; - } else - freevnodes++; - vp->v_flag |= VFREE; - TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); - simple_unlock(&vnode_free_list_slock); - splx(s); - } - - vp->v_type = VBAD; - simple_unlock(&vp->v_interlock); -} - -/* - * Lookup a vnode by device number. - */ -int -vfinddev(dev, type, vpp) - dev_t dev; - enum vtype type; - struct vnode **vpp; -{ - struct vnode *vp; - - simple_lock(&spechash_slock); - SLIST_FOREACH(vp, &dev->si_hlist, v_specnext) { - if (type == vp->v_type) { - *vpp = vp; - simple_unlock(&spechash_slock); - return (1); - } - } - simple_unlock(&spechash_slock); - return (0); -} - -/* - * Calculate the total number of references to a special device. - */ -int -vcount(vp) - struct vnode *vp; -{ - struct vnode *vq; - int count; - - count = 0; - simple_lock(&spechash_slock); - SLIST_FOREACH(vq, &vp->v_hashchain, v_specnext) - count += vq->v_usecount; - simple_unlock(&spechash_slock); - return (count); -} - -/* - * Same as above, but using the dev_t as argument - */ - -int -count_dev(dev) - dev_t dev; -{ - struct vnode *vp; - - vp = SLIST_FIRST(&dev->si_hlist); - if (vp == NULL) - return (0); - return(vcount(vp)); -} - -/* - * Print out a description of a vnode. - */ -static char *typename[] = -{"VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD"}; - -void -vprint(label, vp) - char *label; - struct vnode *vp; -{ - char buf[96]; - - if (label != NULL) - printf("%s: %p: ", label, (void *)vp); - else - printf("%p: ", (void *)vp); - printf("type %s, usecount %d, writecount %d, refcount %d,", - typename[vp->v_type], vp->v_usecount, vp->v_writecount, - vp->v_holdcnt); - buf[0] = '\0'; - if (vp->v_flag & VROOT) - strcat(buf, "|VROOT"); - if (vp->v_flag & VTEXT) - strcat(buf, "|VTEXT"); - if (vp->v_flag & VSYSTEM) - strcat(buf, "|VSYSTEM"); - if (vp->v_flag & VXLOCK) - strcat(buf, "|VXLOCK"); - if (vp->v_flag & VXWANT) - strcat(buf, "|VXWANT"); - if (vp->v_flag & VBWAIT) - strcat(buf, "|VBWAIT"); - if (vp->v_flag & VDOOMED) - strcat(buf, "|VDOOMED"); - if (vp->v_flag & VFREE) - strcat(buf, "|VFREE"); - if (vp->v_flag & VOBJBUF) - strcat(buf, "|VOBJBUF"); - if (buf[0] != '\0') - printf(" flags (%s)", &buf[1]); - if (vp->v_data == NULL) { - printf("\n"); - } else { - printf("\n\t"); - VOP_PRINT(vp); - } -} - -#ifdef DDB -#include <ddb/ddb.h> -/* - * List all of the locked vnodes in the system. - * Called when debugging the kernel. - */ -DB_SHOW_COMMAND(lockedvnodes, lockedvnodes) -{ - struct proc *p = curproc; /* XXX */ - struct mount *mp, *nmp; - struct vnode *vp; - - printf("Locked vnodes\n"); - simple_lock(&mountlist_slock); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { - nmp = TAILQ_NEXT(mp, mnt_list); - continue; - } - LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { - if (VOP_ISLOCKED(vp, NULL)) - vprint((char *)0, vp); - } - simple_lock(&mountlist_slock); - nmp = TAILQ_NEXT(mp, mnt_list); - vfs_unbusy(mp, p); - } - simple_unlock(&mountlist_slock); -} -#endif - -/* - * Top level filesystem related information gathering. - */ -static int sysctl_ovfs_conf __P(SYSCTL_HANDLER_ARGS); - -static int -vfs_sysctl SYSCTL_HANDLER_ARGS -{ - int *name = (int *)arg1 - 1; /* XXX */ - u_int namelen = arg2 + 1; /* XXX */ - struct vfsconf *vfsp; - -#if 1 || defined(COMPAT_PRELITE2) - /* Resolve ambiguity between VFS_VFSCONF and VFS_GENERIC. */ - if (namelen == 1) - return (sysctl_ovfs_conf(oidp, arg1, arg2, req)); -#endif - -#ifdef notyet - /* all sysctl names at this level are at least name and field */ - if (namelen < 2) - return (ENOTDIR); /* overloaded */ - if (name[0] != VFS_GENERIC) { - for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) - if (vfsp->vfc_typenum == name[0]) - break; - if (vfsp == NULL) - return (EOPNOTSUPP); - return ((*vfsp->vfc_vfsops->vfs_sysctl)(&name[1], namelen - 1, - oldp, oldlenp, newp, newlen, p)); - } -#endif - switch (name[1]) { - case VFS_MAXTYPENUM: - if (namelen != 2) - return (ENOTDIR); - return (SYSCTL_OUT(req, &maxvfsconf, sizeof(int))); - case VFS_CONF: - if (namelen != 3) - return (ENOTDIR); /* overloaded */ - for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) - if (vfsp->vfc_typenum == name[2]) - break; - if (vfsp == NULL) - return (EOPNOTSUPP); - return (SYSCTL_OUT(req, vfsp, sizeof *vfsp)); - } - return (EOPNOTSUPP); -} - -SYSCTL_NODE(_vfs, VFS_GENERIC, generic, CTLFLAG_RD, vfs_sysctl, - "Generic filesystem"); - -#if 1 || defined(COMPAT_PRELITE2) - -static int -sysctl_ovfs_conf SYSCTL_HANDLER_ARGS -{ - int error; - struct vfsconf *vfsp; - struct ovfsconf ovfs; - - for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) { - ovfs.vfc_vfsops = vfsp->vfc_vfsops; /* XXX used as flag */ - strcpy(ovfs.vfc_name, vfsp->vfc_name); - ovfs.vfc_index = vfsp->vfc_typenum; - ovfs.vfc_refcount = vfsp->vfc_refcount; - ovfs.vfc_flags = vfsp->vfc_flags; - error = SYSCTL_OUT(req, &ovfs, sizeof ovfs); - if (error) - return error; - } - return 0; -} - -#endif /* 1 || COMPAT_PRELITE2 */ - -#if 0 -#define KINFO_VNODESLOP 10 -/* - * Dump vnode list (via sysctl). - * Copyout address of vnode followed by vnode. - */ -/* ARGSUSED */ -static int -sysctl_vnode SYSCTL_HANDLER_ARGS -{ - struct proc *p = curproc; /* XXX */ - struct mount *mp, *nmp; - struct vnode *nvp, *vp; - int error; - -#define VPTRSZ sizeof (struct vnode *) -#define VNODESZ sizeof (struct vnode) - - req->lock = 0; - if (!req->oldptr) /* Make an estimate */ - return (SYSCTL_OUT(req, 0, - (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ))); - - simple_lock(&mountlist_slock); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { - nmp = TAILQ_NEXT(mp, mnt_list); - continue; - } -again: - simple_lock(&mntvnode_slock); - for (vp = LIST_FIRST(&mp->mnt_vnodelist); - vp != NULL; - vp = nvp) { - /* - * Check that the vp is still associated with - * this filesystem. RACE: could have been - * recycled onto the same filesystem. - */ - if (vp->v_mount != mp) { - simple_unlock(&mntvnode_slock); - goto again; - } - nvp = LIST_NEXT(vp, v_mntvnodes); - simple_unlock(&mntvnode_slock); - if ((error = SYSCTL_OUT(req, &vp, VPTRSZ)) || - (error = SYSCTL_OUT(req, vp, VNODESZ))) - return (error); - simple_lock(&mntvnode_slock); - } - simple_unlock(&mntvnode_slock); - simple_lock(&mountlist_slock); - nmp = TAILQ_NEXT(mp, mnt_list); - vfs_unbusy(mp, p); - } - simple_unlock(&mountlist_slock); - - return (0); -} -#endif - -/* - * XXX - * Exporting the vnode list on large systems causes them to crash. - * Exporting the vnode list on medium systems causes sysctl to coredump. - */ -#if 0 -SYSCTL_PROC(_kern, KERN_VNODE, vnode, CTLTYPE_OPAQUE|CTLFLAG_RD, - 0, 0, sysctl_vnode, "S,vnode", ""); -#endif - -/* - * Check to see if a filesystem is mounted on a block device. - */ -int -vfs_mountedon(vp) - struct vnode *vp; -{ - - if (vp->v_specmountpoint != NULL) - return (EBUSY); - return (0); -} - -/* - * Unmount all filesystems. The list is traversed in reverse order - * of mounting to avoid dependencies. - */ -void -vfs_unmountall() -{ - struct mount *mp; - struct proc *p; - int error; - - if (curproc != NULL) - p = curproc; - else - p = initproc; /* XXX XXX should this be proc0? */ - /* - * Since this only runs when rebooting, it is not interlocked. - */ - while(!TAILQ_EMPTY(&mountlist)) { - mp = TAILQ_LAST(&mountlist, mntlist); - error = dounmount(mp, MNT_FORCE, p); - if (error) { - TAILQ_REMOVE(&mountlist, mp, mnt_list); - printf("unmount of %s failed (", - mp->mnt_stat.f_mntonname); - if (error == EBUSY) - printf("BUSY)\n"); - else - printf("%d)\n", error); - } else { - /* The unmount has removed mp from the mountlist */ - } - } -} - -/* - * Build hash lists of net addresses and hang them off the mount point. - * Called by ufs_mount() to set up the lists of export addresses. - */ -static int -vfs_hang_addrlist(mp, nep, argp) - struct mount *mp; - struct netexport *nep; - struct export_args *argp; -{ - register struct netcred *np; - register struct radix_node_head *rnh; - register int i; - struct radix_node *rn; - struct sockaddr *saddr, *smask = 0; - struct domain *dom; - int error; - - if (argp->ex_addrlen == 0) { - if (mp->mnt_flag & MNT_DEFEXPORTED) - return (EPERM); - np = &nep->ne_defexported; - np->netc_exflags = argp->ex_flags; - np->netc_anon = argp->ex_anon; - np->netc_anon.cr_ref = 1; - mp->mnt_flag |= MNT_DEFEXPORTED; - return (0); - } - i = sizeof(struct netcred) + argp->ex_addrlen + argp->ex_masklen; - np = (struct netcred *) malloc(i, M_NETADDR, M_WAITOK); - bzero((caddr_t) np, i); - saddr = (struct sockaddr *) (np + 1); - if ((error = copyin(argp->ex_addr, (caddr_t) saddr, argp->ex_addrlen))) - goto out; - if (saddr->sa_len > argp->ex_addrlen) - saddr->sa_len = argp->ex_addrlen; - if (argp->ex_masklen) { - smask = (struct sockaddr *) ((caddr_t) saddr + argp->ex_addrlen); - error = copyin(argp->ex_mask, (caddr_t) smask, argp->ex_masklen); - if (error) - goto out; - if (smask->sa_len > argp->ex_masklen) - smask->sa_len = argp->ex_masklen; - } - i = saddr->sa_family; - if ((rnh = nep->ne_rtable[i]) == 0) { - /* - * Seems silly to initialize every AF when most are not used, - * do so on demand here - */ - for (dom = domains; dom; dom = dom->dom_next) - if (dom->dom_family == i && dom->dom_rtattach) { - dom->dom_rtattach((void **) &nep->ne_rtable[i], - dom->dom_rtoffset); - break; - } - if ((rnh = nep->ne_rtable[i]) == 0) { - error = ENOBUFS; - goto out; - } - } - rn = (*rnh->rnh_addaddr) ((caddr_t) saddr, (caddr_t) smask, rnh, - np->netc_rnodes); - if (rn == 0 || np != (struct netcred *) rn) { /* already exists */ - error = EPERM; - goto out; - } - np->netc_exflags = argp->ex_flags; - np->netc_anon = argp->ex_anon; - np->netc_anon.cr_ref = 1; - return (0); -out: - free(np, M_NETADDR); - return (error); -} - -/* ARGSUSED */ -static int -vfs_free_netcred(rn, w) - struct radix_node *rn; - void *w; -{ - register struct radix_node_head *rnh = (struct radix_node_head *) w; - - (*rnh->rnh_deladdr) (rn->rn_key, rn->rn_mask, rnh); - free((caddr_t) rn, M_NETADDR); - return (0); -} - -/* - * Free the net address hash lists that are hanging off the mount points. - */ -static void -vfs_free_addrlist(nep) - struct netexport *nep; -{ - register int i; - register struct radix_node_head *rnh; - - for (i = 0; i <= AF_MAX; i++) - if ((rnh = nep->ne_rtable[i])) { - (*rnh->rnh_walktree) (rnh, vfs_free_netcred, - (caddr_t) rnh); - free((caddr_t) rnh, M_RTABLE); - nep->ne_rtable[i] = 0; - } -} - -int -vfs_export(mp, nep, argp) - struct mount *mp; - struct netexport *nep; - struct export_args *argp; -{ - int error; - - if (argp->ex_flags & MNT_DELEXPORT) { - if (mp->mnt_flag & MNT_EXPUBLIC) { - vfs_setpublicfs(NULL, NULL, NULL); - mp->mnt_flag &= ~MNT_EXPUBLIC; - } - vfs_free_addrlist(nep); - mp->mnt_flag &= ~(MNT_EXPORTED | MNT_DEFEXPORTED); - } - if (argp->ex_flags & MNT_EXPORTED) { - if (argp->ex_flags & MNT_EXPUBLIC) { - if ((error = vfs_setpublicfs(mp, nep, argp)) != 0) - return (error); - mp->mnt_flag |= MNT_EXPUBLIC; - } - if ((error = vfs_hang_addrlist(mp, nep, argp))) - return (error); - mp->mnt_flag |= MNT_EXPORTED; - } - return (0); -} - - -/* - * Set the publicly exported filesystem (WebNFS). Currently, only - * one public filesystem is possible in the spec (RFC 2054 and 2055) - */ -int -vfs_setpublicfs(mp, nep, argp) - struct mount *mp; - struct netexport *nep; - struct export_args *argp; -{ - int error; - struct vnode *rvp; - char *cp; - - /* - * mp == NULL -> invalidate the current info, the FS is - * no longer exported. May be called from either vfs_export - * or unmount, so check if it hasn't already been done. - */ - if (mp == NULL) { - if (nfs_pub.np_valid) { - nfs_pub.np_valid = 0; - if (nfs_pub.np_index != NULL) { - FREE(nfs_pub.np_index, M_TEMP); - nfs_pub.np_index = NULL; - } - } - return (0); - } - - /* - * Only one allowed at a time. - */ - if (nfs_pub.np_valid != 0 && mp != nfs_pub.np_mount) - return (EBUSY); - - /* - * Get real filehandle for root of exported FS. - */ - bzero((caddr_t)&nfs_pub.np_handle, sizeof(nfs_pub.np_handle)); - nfs_pub.np_handle.fh_fsid = mp->mnt_stat.f_fsid; - - if ((error = VFS_ROOT(mp, &rvp))) - return (error); - - if ((error = VFS_VPTOFH(rvp, &nfs_pub.np_handle.fh_fid))) - return (error); - - vput(rvp); - - /* - * If an indexfile was specified, pull it in. - */ - if (argp->ex_indexfile != NULL) { - MALLOC(nfs_pub.np_index, char *, MAXNAMLEN + 1, M_TEMP, - M_WAITOK); - error = copyinstr(argp->ex_indexfile, nfs_pub.np_index, - MAXNAMLEN, (size_t *)0); - if (!error) { - /* - * Check for illegal filenames. - */ - for (cp = nfs_pub.np_index; *cp; cp++) { - if (*cp == '/') { - error = EINVAL; - break; - } - } - } - if (error) { - FREE(nfs_pub.np_index, M_TEMP); - return (error); - } - } - - nfs_pub.np_mount = mp; - nfs_pub.np_valid = 1; - return (0); -} - -struct netcred * -vfs_export_lookup(mp, nep, nam) - register struct mount *mp; - struct netexport *nep; - struct sockaddr *nam; -{ - register struct netcred *np; - register struct radix_node_head *rnh; - struct sockaddr *saddr; - - np = NULL; - if (mp->mnt_flag & MNT_EXPORTED) { - /* - * Lookup in the export list first. - */ - if (nam != NULL) { - saddr = nam; - rnh = nep->ne_rtable[saddr->sa_family]; - if (rnh != NULL) { - np = (struct netcred *) - (*rnh->rnh_matchaddr)((caddr_t)saddr, - rnh); - if (np && np->netc_rnodes->rn_flags & RNF_ROOT) - np = NULL; - } - } - /* - * If no address match, use the default if it exists. - */ - if (np == NULL && mp->mnt_flag & MNT_DEFEXPORTED) - np = &nep->ne_defexported; - } - return (np); -} - -/* - * perform msync on all vnodes under a mount point - * the mount point must be locked. - */ -void -vfs_msync(struct mount *mp, int flags) { - struct vnode *vp, *nvp; - struct vm_object *obj; - int anyio, tries; - - tries = 5; -loop: - anyio = 0; - for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) { - - nvp = LIST_NEXT(vp, v_mntvnodes); - - if (vp->v_mount != mp) { - goto loop; - } - - if (vp->v_flag & VXLOCK) /* XXX: what if MNT_WAIT? */ - continue; - - if (flags != MNT_WAIT) { - obj = vp->v_object; - if (obj == NULL || (obj->flags & OBJ_MIGHTBEDIRTY) == 0) - continue; - if (VOP_ISLOCKED(vp, NULL)) - continue; - } - - simple_lock(&vp->v_interlock); - if (vp->v_object && - (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) { - if (!vget(vp, - LK_INTERLOCK | LK_EXCLUSIVE | LK_RETRY | LK_NOOBJ, curproc)) { - if (vp->v_object) { - vm_object_page_clean(vp->v_object, 0, 0, flags == MNT_WAIT ? OBJPC_SYNC : OBJPC_NOSYNC); - anyio = 1; - } - vput(vp); - } - } else { - simple_unlock(&vp->v_interlock); - } - } - if (anyio && (--tries > 0)) - goto loop; -} - -/* - * Create the VM object needed for VMIO and mmap support. This - * is done for all VREG files in the system. Some filesystems might - * afford the additional metadata buffering capability of the - * VMIO code by making the device node be VMIO mode also. - * - * vp must be locked when vfs_object_create is called. - */ -int -vfs_object_create(vp, p, cred) - struct vnode *vp; - struct proc *p; - struct ucred *cred; -{ - struct vattr vat; - vm_object_t object; - int error = 0; - - if (!vn_isdisk(vp, NULL) && vn_canvmio(vp) == FALSE) - return 0; - -retry: - if ((object = vp->v_object) == NULL) { - if (vp->v_type == VREG || vp->v_type == VDIR) { - if ((error = VOP_GETATTR(vp, &vat, cred, p)) != 0) - goto retn; - object = vnode_pager_alloc(vp, vat.va_size, 0, 0); - } else if (devsw(vp->v_rdev) != NULL) { - /* - * This simply allocates the biggest object possible - * for a disk vnode. This should be fixed, but doesn't - * cause any problems (yet). - */ - object = vnode_pager_alloc(vp, IDX_TO_OFF(INT_MAX), 0, 0); - } else { - goto retn; - } - /* - * Dereference the reference we just created. This assumes - * that the object is associated with the vp. - */ - object->ref_count--; - vp->v_usecount--; - } else { - if (object->flags & OBJ_DEAD) { - VOP_UNLOCK(vp, 0, p); - tsleep(object, PVM, "vodead", 0); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - goto retry; - } - } - - KASSERT(vp->v_object != NULL, ("vfs_object_create: NULL object")); - vp->v_flag |= VOBJBUF; - -retn: - return error; -} - -static void -vfree(vp) - struct vnode *vp; -{ - int s; - - s = splbio(); - simple_lock(&vnode_free_list_slock); - if (vp->v_flag & VTBFREE) { - TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist); - vp->v_flag &= ~VTBFREE; - } - if (vp->v_flag & VAGE) { - TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist); - } else { - TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); - } - freevnodes++; - simple_unlock(&vnode_free_list_slock); - vp->v_flag &= ~VAGE; - vp->v_flag |= VFREE; - splx(s); -} - -void -vbusy(vp) - struct vnode *vp; -{ - int s; - - s = splbio(); - simple_lock(&vnode_free_list_slock); - if (vp->v_flag & VTBFREE) { - TAILQ_REMOVE(&vnode_tobefree_list, vp, v_freelist); - vp->v_flag &= ~VTBFREE; - } else { - TAILQ_REMOVE(&vnode_free_list, vp, v_freelist); - freevnodes--; - } - simple_unlock(&vnode_free_list_slock); - vp->v_flag &= ~(VFREE|VAGE); - splx(s); -} - -/* - * Record a process's interest in events which might happen to - * a vnode. Because poll uses the historic select-style interface - * internally, this routine serves as both the ``check for any - * pending events'' and the ``record my interest in future events'' - * functions. (These are done together, while the lock is held, - * to avoid race conditions.) - */ -int -vn_pollrecord(vp, p, events) - struct vnode *vp; - struct proc *p; - short events; -{ - simple_lock(&vp->v_pollinfo.vpi_lock); - if (vp->v_pollinfo.vpi_revents & events) { - /* - * This leaves events we are not interested - * in available for the other process which - * which presumably had requested them - * (otherwise they would never have been - * recorded). - */ - events &= vp->v_pollinfo.vpi_revents; - vp->v_pollinfo.vpi_revents &= ~events; - - simple_unlock(&vp->v_pollinfo.vpi_lock); - return events; - } - vp->v_pollinfo.vpi_events |= events; - selrecord(p, &vp->v_pollinfo.vpi_selinfo); - simple_unlock(&vp->v_pollinfo.vpi_lock); - return 0; -} - -/* - * Note the occurrence of an event. If the VN_POLLEVENT macro is used, - * it is possible for us to miss an event due to race conditions, but - * that condition is expected to be rare, so for the moment it is the - * preferred interface. - */ -void -vn_pollevent(vp, events) - struct vnode *vp; - short events; -{ - simple_lock(&vp->v_pollinfo.vpi_lock); - if (vp->v_pollinfo.vpi_events & events) { - /* - * We clear vpi_events so that we don't - * call selwakeup() twice if two events are - * posted before the polling process(es) is - * awakened. This also ensures that we take at - * most one selwakeup() if the polling process - * is no longer interested. However, it does - * mean that only one event can be noticed at - * a time. (Perhaps we should only clear those - * event bits which we note?) XXX - */ - vp->v_pollinfo.vpi_events = 0; /* &= ~events ??? */ - vp->v_pollinfo.vpi_revents |= events; - selwakeup(&vp->v_pollinfo.vpi_selinfo); - } - simple_unlock(&vp->v_pollinfo.vpi_lock); -} - -/* - * Wake up anyone polling on vp because it is being revoked. - * This depends on dead_poll() returning POLLHUP for correct - * behavior. - */ -void -vn_pollgone(vp) - struct vnode *vp; -{ - simple_lock(&vp->v_pollinfo.vpi_lock); - if (vp->v_pollinfo.vpi_events) { - vp->v_pollinfo.vpi_events = 0; - selwakeup(&vp->v_pollinfo.vpi_selinfo); - } - simple_unlock(&vp->v_pollinfo.vpi_lock); -} - - - -/* - * Routine to create and manage a filesystem syncer vnode. - */ -#define sync_close ((int (*) __P((struct vop_close_args *)))nullop) -static int sync_fsync __P((struct vop_fsync_args *)); -static int sync_inactive __P((struct vop_inactive_args *)); -static int sync_reclaim __P((struct vop_reclaim_args *)); -#define sync_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock) -#define sync_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock) -static int sync_print __P((struct vop_print_args *)); -#define sync_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked) - -static vop_t **sync_vnodeop_p; -static struct vnodeopv_entry_desc sync_vnodeop_entries[] = { - { &vop_default_desc, (vop_t *) vop_eopnotsupp }, - { &vop_close_desc, (vop_t *) sync_close }, /* close */ - { &vop_fsync_desc, (vop_t *) sync_fsync }, /* fsync */ - { &vop_inactive_desc, (vop_t *) sync_inactive }, /* inactive */ - { &vop_reclaim_desc, (vop_t *) sync_reclaim }, /* reclaim */ - { &vop_lock_desc, (vop_t *) sync_lock }, /* lock */ - { &vop_unlock_desc, (vop_t *) sync_unlock }, /* unlock */ - { &vop_print_desc, (vop_t *) sync_print }, /* print */ - { &vop_islocked_desc, (vop_t *) sync_islocked }, /* islocked */ - { NULL, NULL } -}; -static struct vnodeopv_desc sync_vnodeop_opv_desc = - { &sync_vnodeop_p, sync_vnodeop_entries }; - -VNODEOP_SET(sync_vnodeop_opv_desc); - -/* - * Create a new filesystem syncer vnode for the specified mount point. - */ -int -vfs_allocate_syncvnode(mp) - struct mount *mp; -{ - struct vnode *vp; - static long start, incr, next; - int error; - - /* Allocate a new vnode */ - if ((error = getnewvnode(VT_VFS, mp, sync_vnodeop_p, &vp)) != 0) { - mp->mnt_syncer = NULL; - return (error); - } - vp->v_type = VNON; - /* - * Place the vnode onto the syncer worklist. We attempt to - * scatter them about on the list so that they will go off - * at evenly distributed times even if all the filesystems - * are mounted at once. - */ - next += incr; - if (next == 0 || next > syncer_maxdelay) { - start /= 2; - incr /= 2; - if (start == 0) { - start = syncer_maxdelay / 2; - incr = syncer_maxdelay; - } - next = start; - } - vn_syncer_add_to_worklist(vp, syncdelay > 0 ? next % syncdelay : 0); - mp->mnt_syncer = vp; - return (0); -} - -/* - * Do a lazy sync of the filesystem. - */ -static int -sync_fsync(ap) - struct vop_fsync_args /* { - struct vnode *a_vp; - struct ucred *a_cred; - int a_waitfor; - struct proc *a_p; - } */ *ap; -{ - struct vnode *syncvp = ap->a_vp; - struct mount *mp = syncvp->v_mount; - struct proc *p = ap->a_p; - int asyncflag; - - /* - * We only need to do something if this is a lazy evaluation. - */ - if (ap->a_waitfor != MNT_LAZY) - return (0); - - /* - * Move ourselves to the back of the sync list. - */ - vn_syncer_add_to_worklist(syncvp, syncdelay); - - /* - * Walk the list of vnodes pushing all that are dirty and - * not already on the sync list. - */ - simple_lock(&mountlist_slock); - if (vfs_busy(mp, LK_EXCLUSIVE | LK_NOWAIT, &mountlist_slock, p) != 0) { - simple_unlock(&mountlist_slock); - return (0); - } - asyncflag = mp->mnt_flag & MNT_ASYNC; - mp->mnt_flag &= ~MNT_ASYNC; - vfs_msync(mp, MNT_NOWAIT); - VFS_SYNC(mp, MNT_LAZY, ap->a_cred, p); - if (asyncflag) - mp->mnt_flag |= MNT_ASYNC; - vfs_unbusy(mp, p); - return (0); -} - -/* - * The syncer vnode is no referenced. - */ -static int -sync_inactive(ap) - struct vop_inactive_args /* { - struct vnode *a_vp; - struct proc *a_p; - } */ *ap; -{ - - vgone(ap->a_vp); - return (0); -} - -/* - * The syncer vnode is no longer needed and is being decommissioned. - * - * Modifications to the worklist must be protected at splbio(). - */ -static int -sync_reclaim(ap) - struct vop_reclaim_args /* { - struct vnode *a_vp; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - int s; - - s = splbio(); - vp->v_mount->mnt_syncer = NULL; - if (vp->v_flag & VONWORKLST) { - LIST_REMOVE(vp, v_synclist); - vp->v_flag &= ~VONWORKLST; - } - splx(s); - - return (0); -} - -/* - * Print out a syncer vnode. - */ -static int -sync_print(ap) - struct vop_print_args /* { - struct vnode *a_vp; - } */ *ap; -{ - struct vnode *vp = ap->a_vp; - - printf("syncer vnode"); - if (vp->v_vnlock != NULL) - lockmgr_printinfo(vp->v_vnlock); - printf("\n"); - return (0); -} - -/* - * extract the dev_t from a VBLK or VCHR - */ -dev_t -vn_todev(vp) - struct vnode *vp; -{ - if (vp->v_type != VBLK && vp->v_type != VCHR) - return (NODEV); - return (vp->v_rdev); -} - -/* - * Check if vnode represents a disk device - */ -int -vn_isdisk(vp, errp) - struct vnode *vp; - int *errp; -{ - if (vp->v_type != VBLK && vp->v_type != VCHR) { - if (errp != NULL) - *errp = ENOTBLK; - return (0); - } - if (!devsw(vp->v_rdev)) { - if (errp != NULL) - *errp = ENXIO; - return (0); - } - if (!(devsw(vp->v_rdev)->d_flags & D_DISK)) { - if (errp != NULL) - *errp = ENOTBLK; - return (0); - } - if (errp != NULL) - *errp = 0; - return (1); -} - -void -NDFREE(ndp, flags) - struct nameidata *ndp; - const uint flags; -{ - if (!(flags & NDF_NO_FREE_PNBUF) && - (ndp->ni_cnd.cn_flags & HASBUF)) { - zfree(namei_zone, ndp->ni_cnd.cn_pnbuf); - ndp->ni_cnd.cn_flags &= ~HASBUF; - } - if (!(flags & NDF_NO_DVP_UNLOCK) && - (ndp->ni_cnd.cn_flags & LOCKPARENT) && - ndp->ni_dvp != ndp->ni_vp) - VOP_UNLOCK(ndp->ni_dvp, 0, ndp->ni_cnd.cn_proc); - if (!(flags & NDF_NO_DVP_RELE) && - (ndp->ni_cnd.cn_flags & (LOCKPARENT|WANTPARENT))) { - vrele(ndp->ni_dvp); - ndp->ni_dvp = NULL; - } - if (!(flags & NDF_NO_VP_UNLOCK) && - (ndp->ni_cnd.cn_flags & LOCKLEAF) && ndp->ni_vp) - VOP_UNLOCK(ndp->ni_vp, 0, ndp->ni_cnd.cn_proc); - if (!(flags & NDF_NO_VP_RELE) && - ndp->ni_vp) { - vrele(ndp->ni_vp); - ndp->ni_vp = NULL; - } - if (!(flags & NDF_NO_STARTDIR_RELE) && - (ndp->ni_cnd.cn_flags & SAVESTART)) { - vrele(ndp->ni_startdir); - ndp->ni_startdir = NULL; - } -} diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c deleted file mode 100644 index 142a2c339422..000000000000 --- a/sys/kern/vfs_extattr.c +++ /dev/null @@ -1,3564 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * (c) UNIX System Laboratories, Inc. - * All or some portions of this file are derived from material licensed - * to the University of California by American Telephone and Telegraph - * Co. or Unix System Laboratories, Inc. and are reproduced herein with - * the permission of UNIX System Laboratories, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94 - * $FreeBSD$ - */ - -/* For 4.3 integer FS ID compatibility */ -#include "opt_compat.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/sysent.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/sysproto.h> -#include <sys/namei.h> -#include <sys/filedesc.h> -#include <sys/kernel.h> -#include <sys/fcntl.h> -#include <sys/file.h> -#include <sys/linker.h> -#include <sys/stat.h> -#include <sys/unistd.h> -#include <sys/vnode.h> -#include <sys/proc.h> -#include <sys/dirent.h> -#include <sys/extattr.h> - -#include <machine/limits.h> -#include <miscfs/union/union.h> -#include <sys/sysctl.h> -#include <vm/vm.h> -#include <vm/vm_object.h> -#include <vm/vm_zone.h> - -static int change_dir __P((struct nameidata *ndp, struct proc *p)); -static void checkdirs __P((struct vnode *olddp)); -static int chroot_refuse_vdir_fds __P((struct filedesc *fdp)); -static int getutimes __P((const struct timeval *, struct timespec *)); -static int setfown __P((struct proc *, struct vnode *, uid_t, gid_t)); -static int setfmode __P((struct proc *, struct vnode *, int)); -static int setfflags __P((struct proc *, struct vnode *, int)); -static int setutimes __P((struct proc *, struct vnode *, - const struct timespec *, int)); -static int usermount = 0; /* if 1, non-root can mount fs. */ - -int (*union_dircheckp) __P((struct proc *, struct vnode **, struct file *)); - -SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, ""); - -/* - * Virtual File System System Calls - */ - -/* - * Mount a file system. - */ -#ifndef _SYS_SYSPROTO_H_ -struct mount_args { - char *type; - char *path; - int flags; - caddr_t data; -}; -#endif -/* ARGSUSED */ -int -mount(p, uap) - struct proc *p; - register struct mount_args /* { - syscallarg(char *) type; - syscallarg(char *) path; - syscallarg(int) flags; - syscallarg(caddr_t) data; - } */ *uap; -{ - struct vnode *vp; - struct mount *mp; - struct vfsconf *vfsp; - int error, flag = 0, flag2 = 0; - struct vattr va; -#ifdef COMPAT_43 - u_long fstypenum; -#endif - struct nameidata nd; - char fstypename[MFSNAMELEN]; - - if (usermount == 0 && (error = suser(p))) - return (error); - /* - * Do not allow NFS export by non-root users. - */ - if (SCARG(uap, flags) & MNT_EXPORTED) { - error = suser(p); - if (error) - return (error); - } - /* - * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users - */ - if (suser_xxx(p->p_ucred, 0, 0)) - SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; - /* - * Get vnode to be covered - */ - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; - if (SCARG(uap, flags) & MNT_UPDATE) { - if ((vp->v_flag & VROOT) == 0) { - vput(vp); - return (EINVAL); - } - mp = vp->v_mount; - flag = mp->mnt_flag; - flag2 = mp->mnt_kern_flag; - /* - * We only allow the filesystem to be reloaded if it - * is currently mounted read-only. - */ - if ((SCARG(uap, flags) & MNT_RELOAD) && - ((mp->mnt_flag & MNT_RDONLY) == 0)) { - vput(vp); - return (EOPNOTSUPP); /* Needs translation */ - } - mp->mnt_flag |= - SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); - /* - * Only root, or the user that did the original mount is - * permitted to update it. - */ - if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && - (error = suser(p))) { - vput(vp); - return (error); - } - if (vfs_busy(mp, LK_NOWAIT, 0, p)) { - vput(vp); - return (EBUSY); - } - VOP_UNLOCK(vp, 0, p); - goto update; - } - /* - * If the user is not root, ensure that they own the directory - * onto which we are attempting to mount. - */ - if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || - (va.va_uid != p->p_ucred->cr_uid && - (error = suser(p)))) { - vput(vp); - return (error); - } - if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) - return (error); - if (vp->v_type != VDIR) { - vput(vp); - return (ENOTDIR); - } -#ifdef COMPAT_43 - /* - * Historically filesystem types were identified by number. If we - * get an integer for the filesystem type instead of a string, we - * check to see if it matches one of the historic filesystem types. - */ - fstypenum = (uintptr_t)SCARG(uap, type); - if (fstypenum < maxvfsconf) { - for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) - if (vfsp->vfc_typenum == fstypenum) - break; - if (vfsp == NULL) { - vput(vp); - return (ENODEV); - } - strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); - } else -#endif /* COMPAT_43 */ - if ((error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) != 0) { - vput(vp); - return (error); - } - for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) - if (!strcmp(vfsp->vfc_name, fstypename)) - break; - if (vfsp == NULL) { - linker_file_t lf; - - /* Refuse to load modules if securelevel raised */ - if (securelevel > 0) { - vput(vp); - return EPERM; - } - /* Only load modules for root (very important!) */ - if ((error = suser(p)) != 0) { - vput(vp); - return error; - } - error = linker_load_file(fstypename, &lf); - if (error || lf == NULL) { - vput(vp); - if (lf == NULL) - error = ENODEV; - return error; - } - lf->userrefs++; - /* lookup again, see if the VFS was loaded */ - for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) - if (!strcmp(vfsp->vfc_name, fstypename)) - break; - if (vfsp == NULL) { - lf->userrefs--; - linker_file_unload(lf); - vput(vp); - return (ENODEV); - } - } - simple_lock(&vp->v_interlock); - if ((vp->v_flag & VMOUNT) != 0 || - vp->v_mountedhere != NULL) { - simple_unlock(&vp->v_interlock); - vput(vp); - return (EBUSY); - } - vp->v_flag |= VMOUNT; - simple_unlock(&vp->v_interlock); - - /* - * Allocate and initialize the filesystem. - */ - mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK); - bzero((char *)mp, (u_long)sizeof(struct mount)); - lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE); - (void)vfs_busy(mp, LK_NOWAIT, 0, p); - mp->mnt_op = vfsp->vfc_vfsops; - mp->mnt_vfc = vfsp; - vfsp->vfc_refcount++; - mp->mnt_stat.f_type = vfsp->vfc_typenum; - mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; - strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); - mp->mnt_vnodecovered = vp; - mp->mnt_stat.f_owner = p->p_ucred->cr_uid; - mp->mnt_iosize_max = DFLTPHYS; - VOP_UNLOCK(vp, 0, p); -update: - /* - * Set the mount level flags. - */ - if (SCARG(uap, flags) & MNT_RDONLY) - mp->mnt_flag |= MNT_RDONLY; - else if (mp->mnt_flag & MNT_RDONLY) - mp->mnt_kern_flag |= MNTK_WANTRDWR; - mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | - MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME | - MNT_NOSYMFOLLOW | MNT_IGNORE | - MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR); - mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | - MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE | - MNT_NOSYMFOLLOW | MNT_IGNORE | - MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR); - /* - * Mount the filesystem. - * XXX The final recipients of VFS_MOUNT just overwrite the ndp they - * get. No freeing of cn_pnbuf. - */ - error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); - if (mp->mnt_flag & MNT_UPDATE) { - vrele(vp); - if (mp->mnt_kern_flag & MNTK_WANTRDWR) - mp->mnt_flag &= ~MNT_RDONLY; - mp->mnt_flag &=~ (MNT_UPDATE | MNT_RELOAD | MNT_FORCE); - mp->mnt_kern_flag &=~ MNTK_WANTRDWR; - if (error) { - mp->mnt_flag = flag; - mp->mnt_kern_flag = flag2; - } - if ((mp->mnt_flag & MNT_RDONLY) == 0) { - if (mp->mnt_syncer == NULL) - error = vfs_allocate_syncvnode(mp); - } else { - if (mp->mnt_syncer != NULL) - vrele(mp->mnt_syncer); - mp->mnt_syncer = NULL; - } - vfs_unbusy(mp, p); - return (error); - } - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - /* - * Put the new filesystem on the mount list after root. - */ - cache_purge(vp); - if (!error) { - simple_lock(&vp->v_interlock); - vp->v_flag &= ~VMOUNT; - vp->v_mountedhere = mp; - simple_unlock(&vp->v_interlock); - simple_lock(&mountlist_slock); - TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); - simple_unlock(&mountlist_slock); - checkdirs(vp); - VOP_UNLOCK(vp, 0, p); - if ((mp->mnt_flag & MNT_RDONLY) == 0) - error = vfs_allocate_syncvnode(mp); - vfs_unbusy(mp, p); - if ((error = VFS_START(mp, 0, p)) != 0) - vrele(vp); - } else { - simple_lock(&vp->v_interlock); - vp->v_flag &= ~VMOUNT; - simple_unlock(&vp->v_interlock); - mp->mnt_vfc->vfc_refcount--; - vfs_unbusy(mp, p); - free((caddr_t)mp, M_MOUNT); - vput(vp); - } - return (error); -} - -/* - * Scan all active processes to see if any of them have a current - * or root directory onto which the new filesystem has just been - * mounted. If so, replace them with the new mount point. - */ -static void -checkdirs(olddp) - struct vnode *olddp; -{ - struct filedesc *fdp; - struct vnode *newdp; - struct proc *p; - - if (olddp->v_usecount == 1) - return; - if (VFS_ROOT(olddp->v_mountedhere, &newdp)) - panic("mount: lost mount"); - LIST_FOREACH(p, &allproc, p_list) { - fdp = p->p_fd; - if (fdp->fd_cdir == olddp) { - vrele(fdp->fd_cdir); - VREF(newdp); - fdp->fd_cdir = newdp; - } - if (fdp->fd_rdir == olddp) { - vrele(fdp->fd_rdir); - VREF(newdp); - fdp->fd_rdir = newdp; - } - } - if (rootvnode == olddp) { - vrele(rootvnode); - VREF(newdp); - rootvnode = newdp; - } - vput(newdp); -} - -/* - * Unmount a file system. - * - * Note: unmount takes a path to the vnode mounted on as argument, - * not special file (as before). - */ -#ifndef _SYS_SYSPROTO_H_ -struct unmount_args { - char *path; - int flags; -}; -#endif -/* ARGSUSED */ -int -unmount(p, uap) - struct proc *p; - register struct unmount_args /* { - syscallarg(char *) path; - syscallarg(int) flags; - } */ *uap; -{ - register struct vnode *vp; - struct mount *mp; - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); - mp = vp->v_mount; - - /* - * Only root, or the user that did the original mount is - * permitted to unmount this filesystem. - */ - if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && - (error = suser(p))) { - vput(vp); - return (error); - } - - /* - * Don't allow unmounting the root file system. - */ - if (mp->mnt_flag & MNT_ROOTFS) { - vput(vp); - return (EINVAL); - } - - /* - * Must be the root of the filesystem - */ - if ((vp->v_flag & VROOT) == 0) { - vput(vp); - return (EINVAL); - } - vput(vp); - return (dounmount(mp, SCARG(uap, flags), p)); -} - -/* - * Do the actual file system unmount. - */ -int -dounmount(mp, flags, p) - register struct mount *mp; - int flags; - struct proc *p; -{ - struct vnode *coveredvp; - int error; - int async_flag; - - simple_lock(&mountlist_slock); - mp->mnt_kern_flag |= MNTK_UNMOUNT; - lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p); - - if (mp->mnt_flag & MNT_EXPUBLIC) - vfs_setpublicfs(NULL, NULL, NULL); - - vfs_msync(mp, MNT_WAIT); - async_flag = mp->mnt_flag & MNT_ASYNC; - mp->mnt_flag &=~ MNT_ASYNC; - cache_purgevfs(mp); /* remove cache entries for this file sys */ - if (mp->mnt_syncer != NULL) - vrele(mp->mnt_syncer); - if (((mp->mnt_flag & MNT_RDONLY) || - (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || - (flags & MNT_FORCE)) - error = VFS_UNMOUNT(mp, flags, p); - simple_lock(&mountlist_slock); - if (error) { - if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL) - (void) vfs_allocate_syncvnode(mp); - mp->mnt_kern_flag &= ~MNTK_UNMOUNT; - mp->mnt_flag |= async_flag; - lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE, - &mountlist_slock, p); - if (mp->mnt_kern_flag & MNTK_MWAIT) - wakeup((caddr_t)mp); - return (error); - } - TAILQ_REMOVE(&mountlist, mp, mnt_list); - if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { - coveredvp->v_mountedhere = (struct mount *)0; - vrele(coveredvp); - } - mp->mnt_vfc->vfc_refcount--; - if (!LIST_EMPTY(&mp->mnt_vnodelist)) - panic("unmount: dangling vnode"); - lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p); - if (mp->mnt_kern_flag & MNTK_MWAIT) - wakeup((caddr_t)mp); - free((caddr_t)mp, M_MOUNT); - return (0); -} - -/* - * Sync each mounted filesystem. - */ -#ifndef _SYS_SYSPROTO_H_ -struct sync_args { - int dummy; -}; -#endif - -#ifdef DEBUG -static int syncprt = 0; -SYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, ""); -#endif - -/* ARGSUSED */ -int -sync(p, uap) - struct proc *p; - struct sync_args *uap; -{ - register struct mount *mp, *nmp; - int asyncflag; - - simple_lock(&mountlist_slock); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { - nmp = TAILQ_NEXT(mp, mnt_list); - continue; - } - if ((mp->mnt_flag & MNT_RDONLY) == 0) { - asyncflag = mp->mnt_flag & MNT_ASYNC; - mp->mnt_flag &= ~MNT_ASYNC; - vfs_msync(mp, MNT_NOWAIT); - VFS_SYNC(mp, MNT_NOWAIT, - ((p != NULL) ? p->p_ucred : NOCRED), p); - mp->mnt_flag |= asyncflag; - } - simple_lock(&mountlist_slock); - nmp = TAILQ_NEXT(mp, mnt_list); - vfs_unbusy(mp, p); - } - simple_unlock(&mountlist_slock); -#if 0 -/* - * XXX don't call vfs_bufstats() yet because that routine - * was not imported in the Lite2 merge. - */ -#ifdef DIAGNOSTIC - if (syncprt) - vfs_bufstats(); -#endif /* DIAGNOSTIC */ -#endif - return (0); -} - -/* XXX PRISON: could be per prison flag */ -static int prison_quotas; -#if 0 -SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, ""); -#endif - -/* - * Change filesystem quotas. - */ -#ifndef _SYS_SYSPROTO_H_ -struct quotactl_args { - char *path; - int cmd; - int uid; - caddr_t arg; -}; -#endif -/* ARGSUSED */ -int -quotactl(p, uap) - struct proc *p; - register struct quotactl_args /* { - syscallarg(char *) path; - syscallarg(int) cmd; - syscallarg(int) uid; - syscallarg(caddr_t) arg; - } */ *uap; -{ - register struct mount *mp; - int error; - struct nameidata nd; - - if (p->p_prison && !prison_quotas) - return (EPERM); - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - mp = nd.ni_vp->v_mount; - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); - return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), - SCARG(uap, arg), p)); -} - -/* - * Get filesystem statistics. - */ -#ifndef _SYS_SYSPROTO_H_ -struct statfs_args { - char *path; - struct statfs *buf; -}; -#endif -/* ARGSUSED */ -int -statfs(p, uap) - struct proc *p; - register struct statfs_args /* { - syscallarg(char *) path; - syscallarg(struct statfs *) buf; - } */ *uap; -{ - register struct mount *mp; - register struct statfs *sp; - int error; - struct nameidata nd; - struct statfs sb; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - mp = nd.ni_vp->v_mount; - sp = &mp->mnt_stat; - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); - error = VFS_STATFS(mp, sp, p); - if (error) - return (error); - sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - if (suser_xxx(p->p_ucred, 0, 0)) { - bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); - sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; - sp = &sb; - } - return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); -} - -/* - * Get filesystem statistics. - */ -#ifndef _SYS_SYSPROTO_H_ -struct fstatfs_args { - int fd; - struct statfs *buf; -}; -#endif -/* ARGSUSED */ -int -fstatfs(p, uap) - struct proc *p; - register struct fstatfs_args /* { - syscallarg(int) fd; - syscallarg(struct statfs *) buf; - } */ *uap; -{ - struct file *fp; - struct mount *mp; - register struct statfs *sp; - int error; - struct statfs sb; - - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) - return (error); - mp = ((struct vnode *)fp->f_data)->v_mount; - sp = &mp->mnt_stat; - error = VFS_STATFS(mp, sp, p); - if (error) - return (error); - sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - if (suser_xxx(p->p_ucred, 0, 0)) { - bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); - sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; - sp = &sb; - } - return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); -} - -/* - * Get statistics on all filesystems. - */ -#ifndef _SYS_SYSPROTO_H_ -struct getfsstat_args { - struct statfs *buf; - long bufsize; - int flags; -}; -#endif -int -getfsstat(p, uap) - struct proc *p; - register struct getfsstat_args /* { - syscallarg(struct statfs *) buf; - syscallarg(long) bufsize; - syscallarg(int) flags; - } */ *uap; -{ - register struct mount *mp, *nmp; - register struct statfs *sp; - caddr_t sfsp; - long count, maxcount, error; - - maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); - sfsp = (caddr_t)SCARG(uap, buf); - count = 0; - simple_lock(&mountlist_slock); - for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { - if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { - nmp = TAILQ_NEXT(mp, mnt_list); - continue; - } - if (sfsp && count < maxcount) { - sp = &mp->mnt_stat; - /* - * If MNT_NOWAIT or MNT_LAZY is specified, do not - * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY - * overrides MNT_WAIT. - */ - if (((SCARG(uap, flags) & (MNT_LAZY|MNT_NOWAIT)) == 0 || - (SCARG(uap, flags) & MNT_WAIT)) && - (error = VFS_STATFS(mp, sp, p))) { - simple_lock(&mountlist_slock); - nmp = TAILQ_NEXT(mp, mnt_list); - vfs_unbusy(mp, p); - continue; - } - sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); - if (error) { - vfs_unbusy(mp, p); - return (error); - } - sfsp += sizeof(*sp); - } - count++; - simple_lock(&mountlist_slock); - nmp = TAILQ_NEXT(mp, mnt_list); - vfs_unbusy(mp, p); - } - simple_unlock(&mountlist_slock); - if (sfsp && count > maxcount) - p->p_retval[0] = maxcount; - else - p->p_retval[0] = count; - return (0); -} - -/* - * Change current working directory to a given file descriptor. - */ -#ifndef _SYS_SYSPROTO_H_ -struct fchdir_args { - int fd; -}; -#endif -/* ARGSUSED */ -int -fchdir(p, uap) - struct proc *p; - struct fchdir_args /* { - syscallarg(int) fd; - } */ *uap; -{ - register struct filedesc *fdp = p->p_fd; - struct vnode *vp, *tdp; - struct mount *mp; - struct file *fp; - int error; - - if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0) - return (error); - vp = (struct vnode *)fp->f_data; - VREF(vp); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - if (vp->v_type != VDIR) - error = ENOTDIR; - else - error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); - while (!error && (mp = vp->v_mountedhere) != NULL) { - if (vfs_busy(mp, 0, 0, p)) - continue; - error = VFS_ROOT(mp, &tdp); - vfs_unbusy(mp, p); - if (error) - break; - vput(vp); - vp = tdp; - } - if (error) { - vput(vp); - return (error); - } - VOP_UNLOCK(vp, 0, p); - vrele(fdp->fd_cdir); - fdp->fd_cdir = vp; - return (0); -} - -/* - * Change current working directory (``.''). - */ -#ifndef _SYS_SYSPROTO_H_ -struct chdir_args { - char *path; -}; -#endif -/* ARGSUSED */ -int -chdir(p, uap) - struct proc *p; - struct chdir_args /* { - syscallarg(char *) path; - } */ *uap; -{ - register struct filedesc *fdp = p->p_fd; - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = change_dir(&nd, p)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(fdp->fd_cdir); - fdp->fd_cdir = nd.ni_vp; - return (0); -} - -/* - * Helper function for raised chroot(2) security function: Refuse if - * any filedescriptors are open directories. - */ -static int -chroot_refuse_vdir_fds(fdp) - struct filedesc *fdp; -{ - struct vnode *vp; - struct file *fp; - int error; - int fd; - - for (fd = 0; fd < fdp->fd_nfiles ; fd++) { - error = getvnode(fdp, fd, &fp); - if (error) - continue; - vp = (struct vnode *)fp->f_data; - if (vp->v_type != VDIR) - continue; - return(EPERM); - } - return (0); -} - -/* - * This sysctl determines if we will allow a process to chroot(2) if it - * has a directory open: - * 0: disallowed for all processes. - * 1: allowed for processes that were not already chroot(2)'ed. - * 2: allowed for all processes. - */ - -static int chroot_allow_open_directories = 1; - -SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW, - &chroot_allow_open_directories, 0, ""); - -/* - * Change notion of root (``/'') directory. - */ -#ifndef _SYS_SYSPROTO_H_ -struct chroot_args { - char *path; -}; -#endif -/* ARGSUSED */ -int -chroot(p, uap) - struct proc *p; - struct chroot_args /* { - syscallarg(char *) path; - } */ *uap; -{ - register struct filedesc *fdp = p->p_fd; - int error; - struct nameidata nd; - - error = suser_xxx(0, p, PRISON_ROOT); - if (error) - return (error); - if (chroot_allow_open_directories == 0 || - (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) - error = chroot_refuse_vdir_fds(fdp); - if (error) - return (error); - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = change_dir(&nd, p)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(fdp->fd_rdir); - fdp->fd_rdir = nd.ni_vp; - if (!fdp->fd_jdir) { - fdp->fd_jdir = nd.ni_vp; - VREF(fdp->fd_jdir); - } - return (0); -} - -/* - * Common routine for chroot and chdir. - */ -static int -change_dir(ndp, p) - register struct nameidata *ndp; - struct proc *p; -{ - struct vnode *vp; - int error; - - error = namei(ndp); - if (error) - return (error); - vp = ndp->ni_vp; - if (vp->v_type != VDIR) - error = ENOTDIR; - else - error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); - if (error) - vput(vp); - else - VOP_UNLOCK(vp, 0, p); - return (error); -} - -/* - * Check permissions, allocate an open file structure, - * and call the device open routine if any. - */ -#ifndef _SYS_SYSPROTO_H_ -struct open_args { - char *path; - int flags; - int mode; -}; -#endif -int -open(p, uap) - struct proc *p; - register struct open_args /* { - syscallarg(char *) path; - syscallarg(int) flags; - syscallarg(int) mode; - } */ *uap; -{ - register struct filedesc *fdp = p->p_fd; - register struct file *fp; - register struct vnode *vp; - int cmode, flags, oflags; - struct file *nfp; - int type, indx, error; - struct flock lf; - struct nameidata nd; - - oflags = SCARG(uap, flags); - if ((oflags & O_ACCMODE) == O_ACCMODE) - return (EINVAL); - flags = FFLAGS(oflags); - error = falloc(p, &nfp, &indx); - if (error) - return (error); - fp = nfp; - cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - p->p_dupfd = -indx - 1; /* XXX check for fdopen */ - error = vn_open(&nd, flags, cmode); - if (error) { - ffree(fp); - if ((error == ENODEV || error == ENXIO) && - p->p_dupfd >= 0 && /* XXX from fdopen */ - (error = - dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { - p->p_retval[0] = indx; - return (0); - } - if (error == ERESTART) - error = EINTR; - fdp->fd_ofiles[indx] = NULL; - return (error); - } - p->p_dupfd = 0; - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; - - fp->f_data = (caddr_t)vp; - fp->f_flag = flags & FMASK; - fp->f_ops = &vnops; - fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE); - if (flags & (O_EXLOCK | O_SHLOCK)) { - lf.l_whence = SEEK_SET; - lf.l_start = 0; - lf.l_len = 0; - if (flags & O_EXLOCK) - lf.l_type = F_WRLCK; - else - lf.l_type = F_RDLCK; - type = F_FLOCK; - if ((flags & FNONBLOCK) == 0) - type |= F_WAIT; - VOP_UNLOCK(vp, 0, p); - if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) { - (void) vn_close(vp, fp->f_flag, fp->f_cred, p); - ffree(fp); - fdp->fd_ofiles[indx] = NULL; - return (error); - } - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - fp->f_flag |= FHASLOCK; - } - /* assert that vn_open created a backing object if one is needed */ - KASSERT(!vn_canvmio(vp) || vp->v_object != NULL, - ("open: vmio vnode has no backing object after vn_open")); - VOP_UNLOCK(vp, 0, p); - p->p_retval[0] = indx; - return (0); -} - -#ifdef COMPAT_43 -/* - * Create a file. - */ -#ifndef _SYS_SYSPROTO_H_ -struct ocreat_args { - char *path; - int mode; -}; -#endif -int -ocreat(p, uap) - struct proc *p; - register struct ocreat_args /* { - syscallarg(char *) path; - syscallarg(int) mode; - } */ *uap; -{ - struct open_args /* { - syscallarg(char *) path; - syscallarg(int) flags; - syscallarg(int) mode; - } */ nuap; - - SCARG(&nuap, path) = SCARG(uap, path); - SCARG(&nuap, mode) = SCARG(uap, mode); - SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; - return (open(p, &nuap)); -} -#endif /* COMPAT_43 */ - -/* - * Create a special file. - */ -#ifndef _SYS_SYSPROTO_H_ -struct mknod_args { - char *path; - int mode; - int dev; -}; -#endif -/* ARGSUSED */ -int -mknod(p, uap) - struct proc *p; - register struct mknod_args /* { - syscallarg(char *) path; - syscallarg(int) mode; - syscallarg(int) dev; - } */ *uap; -{ - register struct vnode *vp; - struct vattr vattr; - int error; - int whiteout = 0; - struct nameidata nd; - - switch (SCARG(uap, mode) & S_IFMT) { - case S_IFCHR: - case S_IFBLK: - error = suser(p); - break; - default: - error = suser_xxx(0, p, PRISON_ROOT); - break; - } - if (error) - return (error); - bwillwrite(); - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - if (vp != NULL) - error = EEXIST; - else { - VATTR_NULL(&vattr); - vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; - vattr.va_rdev = SCARG(uap, dev); - whiteout = 0; - - switch (SCARG(uap, mode) & S_IFMT) { - case S_IFMT: /* used by badsect to flag bad sectors */ - vattr.va_type = VBAD; - break; - case S_IFCHR: - vattr.va_type = VCHR; - break; - case S_IFBLK: - vattr.va_type = VBLK; - break; - case S_IFWHT: - whiteout = 1; - break; - default: - error = EINVAL; - break; - } - } - if (!error) { - VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - if (whiteout) - error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); - else { - error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, - &nd.ni_cnd, &vattr); - if (error == 0) - vput(nd.ni_vp); - } - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_dvp); - } else { - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - if (vp) - vrele(vp); - } - ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod"); - ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod"); - return (error); -} - -/* - * Create a named pipe. - */ -#ifndef _SYS_SYSPROTO_H_ -struct mkfifo_args { - char *path; - int mode; -}; -#endif -/* ARGSUSED */ -int -mkfifo(p, uap) - struct proc *p; - register struct mkfifo_args /* { - syscallarg(char *) path; - syscallarg(int) mode; - } */ *uap; -{ - struct vattr vattr; - int error; - struct nameidata nd; - - bwillwrite(); - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - if (nd.ni_vp != NULL) { - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - vrele(nd.ni_vp); - return (EEXIST); - } - VATTR_NULL(&vattr); - vattr.va_type = VFIFO; - vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; - VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); - if (error == 0) - vput(nd.ni_vp); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_dvp); - return (error); -} - -/* - * Make a hard file link. - */ -#ifndef _SYS_SYSPROTO_H_ -struct link_args { - char *path; - char *link; -}; -#endif -/* ARGSUSED */ -int -link(p, uap) - struct proc *p; - register struct link_args /* { - syscallarg(char *) path; - syscallarg(char *) link; - } */ *uap; -{ - register struct vnode *vp; - struct nameidata nd; - int error; - - bwillwrite(); - NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; - if (vp->v_type == VDIR) - error = EPERM; /* POSIX */ - else { - NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p); - error = namei(&nd); - if (!error) { - if (nd.ni_vp != NULL) { - if (nd.ni_vp) - vrele(nd.ni_vp); - error = EEXIST; - } else { - VOP_LEASE(nd.ni_dvp, p, p->p_ucred, - LEASE_WRITE); - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); - } - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - } - } - vrele(vp); - ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link"); - ASSERT_VOP_UNLOCKED(nd.ni_vp, "link"); - return (error); -} - -/* - * Make a symbolic link. - */ -#ifndef _SYS_SYSPROTO_H_ -struct symlink_args { - char *path; - char *link; -}; -#endif -/* ARGSUSED */ -int -symlink(p, uap) - struct proc *p; - register struct symlink_args /* { - syscallarg(char *) path; - syscallarg(char *) link; - } */ *uap; -{ - struct vattr vattr; - char *path; - int error; - struct nameidata nd; - - path = zalloc(namei_zone); - if ((error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) != 0) - goto out; - bwillwrite(); - NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p); - if ((error = namei(&nd)) != 0) - goto out; - if (nd.ni_vp) { - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - vrele(nd.ni_vp); - error = EEXIST; - goto out; - } - VATTR_NULL(&vattr); - vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; - VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); - NDFREE(&nd, NDF_ONLY_PNBUF); - if (error == 0) - vput(nd.ni_vp); - vput(nd.ni_dvp); - ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink"); - ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink"); -out: - zfree(namei_zone, path); - return (error); -} - -/* - * Delete a whiteout from the filesystem. - */ -/* ARGSUSED */ -int -undelete(p, uap) - struct proc *p; - register struct undelete_args /* { - syscallarg(char *) path; - } */ *uap; -{ - int error; - struct nameidata nd; - - bwillwrite(); - NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, - SCARG(uap, path), p); - error = namei(&nd); - if (error) - return (error); - - if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == nd.ni_vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - if (nd.ni_vp) - vrele(nd.ni_vp); - return (EEXIST); - } - - VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_dvp); - ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete"); - ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete"); - return (error); -} - -/* - * Delete a name from the filesystem. - */ -#ifndef _SYS_SYSPROTO_H_ -struct unlink_args { - char *path; -}; -#endif -/* ARGSUSED */ -int -unlink(p, uap) - struct proc *p; - struct unlink_args /* { - syscallarg(char *) path; - } */ *uap; -{ - register struct vnode *vp; - int error; - struct nameidata nd; - - bwillwrite(); - NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - - if (vp->v_type == VDIR) - error = EPERM; /* POSIX */ - else { - /* - * The root of a mounted filesystem cannot be deleted. - * - * XXX: can this only be a VDIR case? - */ - if (vp->v_flag & VROOT) - error = EBUSY; - } - - if (!error) { - VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd); - } - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - if (vp != NULLVP) - vput(vp); - ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink"); - ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink"); - return (error); -} - -/* - * Reposition read/write file offset. - */ -#ifndef _SYS_SYSPROTO_H_ -struct lseek_args { - int fd; - int pad; - off_t offset; - int whence; -}; -#endif -int -lseek(p, uap) - struct proc *p; - register struct lseek_args /* { - syscallarg(int) fd; - syscallarg(int) pad; - syscallarg(off_t) offset; - syscallarg(int) whence; - } */ *uap; -{ - struct ucred *cred = p->p_ucred; - register struct filedesc *fdp = p->p_fd; - register struct file *fp; - struct vattr vattr; - int error; - - if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) - return (EBADF); - if (fp->f_type != DTYPE_VNODE) - return (ESPIPE); - switch (SCARG(uap, whence)) { - case L_INCR: - fp->f_offset += SCARG(uap, offset); - break; - case L_XTND: - error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p); - if (error) - return (error); - fp->f_offset = SCARG(uap, offset) + vattr.va_size; - break; - case L_SET: - fp->f_offset = SCARG(uap, offset); - break; - default: - return (EINVAL); - } - *(off_t *)(p->p_retval) = fp->f_offset; - return (0); -} - -#if defined(COMPAT_43) || defined(COMPAT_SUNOS) -/* - * Reposition read/write file offset. - */ -#ifndef _SYS_SYSPROTO_H_ -struct olseek_args { - int fd; - long offset; - int whence; -}; -#endif -int -olseek(p, uap) - struct proc *p; - register struct olseek_args /* { - syscallarg(int) fd; - syscallarg(long) offset; - syscallarg(int) whence; - } */ *uap; -{ - struct lseek_args /* { - syscallarg(int) fd; - syscallarg(int) pad; - syscallarg(off_t) offset; - syscallarg(int) whence; - } */ nuap; - int error; - - SCARG(&nuap, fd) = SCARG(uap, fd); - SCARG(&nuap, offset) = SCARG(uap, offset); - SCARG(&nuap, whence) = SCARG(uap, whence); - error = lseek(p, &nuap); - return (error); -} -#endif /* COMPAT_43 */ - -/* - * Check access permissions. - */ -#ifndef _SYS_SYSPROTO_H_ -struct access_args { - char *path; - int flags; -}; -#endif -int -access(p, uap) - struct proc *p; - register struct access_args /* { - syscallarg(char *) path; - syscallarg(int) flags; - } */ *uap; -{ - register struct ucred *cred = p->p_ucred; - register struct vnode *vp; - int error, flags, t_gid, t_uid; - struct nameidata nd; - - t_uid = cred->cr_uid; - t_gid = cred->cr_groups[0]; - cred->cr_uid = p->p_cred->p_ruid; - cred->cr_groups[0] = p->p_cred->p_rgid; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - goto out1; - vp = nd.ni_vp; - - /* Flags == 0 means only check for existence. */ - if (SCARG(uap, flags)) { - flags = 0; - if (SCARG(uap, flags) & R_OK) - flags |= VREAD; - if (SCARG(uap, flags) & W_OK) - flags |= VWRITE; - if (SCARG(uap, flags) & X_OK) - flags |= VEXEC; - if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) - error = VOP_ACCESS(vp, flags, cred, p); - } - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(vp); -out1: - cred->cr_uid = t_uid; - cred->cr_groups[0] = t_gid; - return (error); -} - -#if defined(COMPAT_43) || defined(COMPAT_SUNOS) -/* - * Get file status; this version follows links. - */ -#ifndef _SYS_SYSPROTO_H_ -struct ostat_args { - char *path; - struct ostat *ub; -}; -#endif -/* ARGSUSED */ -int -ostat(p, uap) - struct proc *p; - register struct ostat_args /* { - syscallarg(char *) path; - syscallarg(struct ostat *) ub; - } */ *uap; -{ - struct stat sb; - struct ostat osb; - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = vn_stat(nd.ni_vp, &sb, p); - vput(nd.ni_vp); - if (error) - return (error); - cvtstat(&sb, &osb); - error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); - return (error); -} - -/* - * Get file status; this version does not follow links. - */ -#ifndef _SYS_SYSPROTO_H_ -struct olstat_args { - char *path; - struct ostat *ub; -}; -#endif -/* ARGSUSED */ -int -olstat(p, uap) - struct proc *p; - register struct olstat_args /* { - syscallarg(char *) path; - syscallarg(struct ostat *) ub; - } */ *uap; -{ - struct vnode *vp; - struct stat sb; - struct ostat osb; - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - error = vn_stat(vp, &sb, p); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(vp); - if (error) - return (error); - cvtstat(&sb, &osb); - error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); - return (error); -} - -/* - * Convert from an old to a new stat structure. - */ -void -cvtstat(st, ost) - struct stat *st; - struct ostat *ost; -{ - - ost->st_dev = st->st_dev; - ost->st_ino = st->st_ino; - ost->st_mode = st->st_mode; - ost->st_nlink = st->st_nlink; - ost->st_uid = st->st_uid; - ost->st_gid = st->st_gid; - ost->st_rdev = st->st_rdev; - if (st->st_size < (quad_t)1 << 32) - ost->st_size = st->st_size; - else - ost->st_size = -2; - ost->st_atime = st->st_atime; - ost->st_mtime = st->st_mtime; - ost->st_ctime = st->st_ctime; - ost->st_blksize = st->st_blksize; - ost->st_blocks = st->st_blocks; - ost->st_flags = st->st_flags; - ost->st_gen = st->st_gen; -} -#endif /* COMPAT_43 || COMPAT_SUNOS */ - -/* - * Get file status; this version follows links. - */ -#ifndef _SYS_SYSPROTO_H_ -struct stat_args { - char *path; - struct stat *ub; -}; -#endif -/* ARGSUSED */ -int -stat(p, uap) - struct proc *p; - register struct stat_args /* { - syscallarg(char *) path; - syscallarg(struct stat *) ub; - } */ *uap; -{ - struct stat sb; - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - error = vn_stat(nd.ni_vp, &sb, p); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_vp); - if (error) - return (error); - error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); - return (error); -} - -/* - * Get file status; this version does not follow links. - */ -#ifndef _SYS_SYSPROTO_H_ -struct lstat_args { - char *path; - struct stat *ub; -}; -#endif -/* ARGSUSED */ -int -lstat(p, uap) - struct proc *p; - register struct lstat_args /* { - syscallarg(char *) path; - syscallarg(struct stat *) ub; - } */ *uap; -{ - int error; - struct vnode *vp; - struct stat sb; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - error = vn_stat(vp, &sb, p); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(vp); - if (error) - return (error); - error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); - return (error); -} - -void -cvtnstat(sb, nsb) - struct stat *sb; - struct nstat *nsb; -{ - nsb->st_dev = sb->st_dev; - nsb->st_ino = sb->st_ino; - nsb->st_mode = sb->st_mode; - nsb->st_nlink = sb->st_nlink; - nsb->st_uid = sb->st_uid; - nsb->st_gid = sb->st_gid; - nsb->st_rdev = sb->st_rdev; - nsb->st_atimespec = sb->st_atimespec; - nsb->st_mtimespec = sb->st_mtimespec; - nsb->st_ctimespec = sb->st_ctimespec; - nsb->st_size = sb->st_size; - nsb->st_blocks = sb->st_blocks; - nsb->st_blksize = sb->st_blksize; - nsb->st_flags = sb->st_flags; - nsb->st_gen = sb->st_gen; - nsb->st_qspare[0] = sb->st_qspare[0]; - nsb->st_qspare[1] = sb->st_qspare[1]; -} - -#ifndef _SYS_SYSPROTO_H_ -struct nstat_args { - char *path; - struct nstat *ub; -}; -#endif -/* ARGSUSED */ -int -nstat(p, uap) - struct proc *p; - register struct nstat_args /* { - syscallarg(char *) path; - syscallarg(struct nstat *) ub; - } */ *uap; -{ - struct stat sb; - struct nstat nsb; - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = vn_stat(nd.ni_vp, &sb, p); - vput(nd.ni_vp); - if (error) - return (error); - cvtnstat(&sb, &nsb); - error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb)); - return (error); -} - -/* - * Get file status; this version does not follow links. - */ -#ifndef _SYS_SYSPROTO_H_ -struct lstat_args { - char *path; - struct stat *ub; -}; -#endif -/* ARGSUSED */ -int -nlstat(p, uap) - struct proc *p; - register struct nlstat_args /* { - syscallarg(char *) path; - syscallarg(struct nstat *) ub; - } */ *uap; -{ - int error; - struct vnode *vp; - struct stat sb; - struct nstat nsb; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); - error = vn_stat(vp, &sb, p); - vput(vp); - if (error) - return (error); - cvtnstat(&sb, &nsb); - error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb)); - return (error); -} - -/* - * Get configurable pathname variables. - */ -#ifndef _SYS_SYSPROTO_H_ -struct pathconf_args { - char *path; - int name; -}; -#endif -/* ARGSUSED */ -int -pathconf(p, uap) - struct proc *p; - register struct pathconf_args /* { - syscallarg(char *) path; - syscallarg(int) name; - } */ *uap; -{ - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), p->p_retval); - vput(nd.ni_vp); - return (error); -} - -/* - * Return target name of a symbolic link. - */ -#ifndef _SYS_SYSPROTO_H_ -struct readlink_args { - char *path; - char *buf; - int count; -}; -#endif -/* ARGSUSED */ -int -readlink(p, uap) - struct proc *p; - register struct readlink_args /* { - syscallarg(char *) path; - syscallarg(char *) buf; - syscallarg(int) count; - } */ *uap; -{ - register struct vnode *vp; - struct iovec aiov; - struct uio auio; - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; - if (vp->v_type != VLNK) - error = EINVAL; - else { - aiov.iov_base = SCARG(uap, buf); - aiov.iov_len = SCARG(uap, count); - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_offset = 0; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_procp = p; - auio.uio_resid = SCARG(uap, count); - error = VOP_READLINK(vp, &auio, p->p_ucred); - } - vput(vp); - p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; - return (error); -} - -static int -setfflags(p, vp, flags) - struct proc *p; - struct vnode *vp; - int flags; -{ - int error; - struct vattr vattr; - - /* - * Prevent non-root users from setting flags on devices. When - * a device is reused, users can retain ownership of the device - * if they are allowed to set flags and programs assume that - * chown can't fail when done as root. - */ - if ((vp->v_type == VCHR || vp->v_type == VBLK) && - ((error = suser_xxx(p->p_ucred, p, PRISON_ROOT)) != 0)) - return (error); - - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - VATTR_NULL(&vattr); - vattr.va_flags = flags; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - VOP_UNLOCK(vp, 0, p); - return (error); -} - -/* - * Change flags of a file given a path name. - */ -#ifndef _SYS_SYSPROTO_H_ -struct chflags_args { - char *path; - int flags; -}; -#endif -/* ARGSUSED */ -int -chflags(p, uap) - struct proc *p; - register struct chflags_args /* { - syscallarg(char *) path; - syscallarg(int) flags; - } */ *uap; -{ - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = setfflags(p, nd.ni_vp, SCARG(uap, flags)); - vrele(nd.ni_vp); - return error; -} - -/* - * Change flags of a file given a file descriptor. - */ -#ifndef _SYS_SYSPROTO_H_ -struct fchflags_args { - int fd; - int flags; -}; -#endif -/* ARGSUSED */ -int -fchflags(p, uap) - struct proc *p; - register struct fchflags_args /* { - syscallarg(int) fd; - syscallarg(int) flags; - } */ *uap; -{ - struct file *fp; - int error; - - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) - return (error); - return setfflags(p, (struct vnode *) fp->f_data, SCARG(uap, flags)); -} - -static int -setfmode(p, vp, mode) - struct proc *p; - struct vnode *vp; - int mode; -{ - int error; - struct vattr vattr; - - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - VATTR_NULL(&vattr); - vattr.va_mode = mode & ALLPERMS; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - VOP_UNLOCK(vp, 0, p); - return error; -} - -/* - * Change mode of a file given path name. - */ -#ifndef _SYS_SYSPROTO_H_ -struct chmod_args { - char *path; - int mode; -}; -#endif -/* ARGSUSED */ -int -chmod(p, uap) - struct proc *p; - register struct chmod_args /* { - syscallarg(char *) path; - syscallarg(int) mode; - } */ *uap; -{ - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = setfmode(p, nd.ni_vp, SCARG(uap, mode)); - vrele(nd.ni_vp); - return error; -} - -/* - * Change mode of a file given path name (don't follow links.) - */ -#ifndef _SYS_SYSPROTO_H_ -struct lchmod_args { - char *path; - int mode; -}; -#endif -/* ARGSUSED */ -int -lchmod(p, uap) - struct proc *p; - register struct lchmod_args /* { - syscallarg(char *) path; - syscallarg(int) mode; - } */ *uap; -{ - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = setfmode(p, nd.ni_vp, SCARG(uap, mode)); - vrele(nd.ni_vp); - return error; -} - -/* - * Change mode of a file given a file descriptor. - */ -#ifndef _SYS_SYSPROTO_H_ -struct fchmod_args { - int fd; - int mode; -}; -#endif -/* ARGSUSED */ -int -fchmod(p, uap) - struct proc *p; - register struct fchmod_args /* { - syscallarg(int) fd; - syscallarg(int) mode; - } */ *uap; -{ - struct file *fp; - int error; - - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) - return (error); - return setfmode(p, (struct vnode *)fp->f_data, SCARG(uap, mode)); -} - -static int -setfown(p, vp, uid, gid) - struct proc *p; - struct vnode *vp; - uid_t uid; - gid_t gid; -{ - int error; - struct vattr vattr; - - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - VATTR_NULL(&vattr); - vattr.va_uid = uid; - vattr.va_gid = gid; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - VOP_UNLOCK(vp, 0, p); - return error; -} - -/* - * Set ownership given a path name. - */ -#ifndef _SYS_SYSPROTO_H_ -struct chown_args { - char *path; - int uid; - int gid; -}; -#endif -/* ARGSUSED */ -int -chown(p, uap) - struct proc *p; - register struct chown_args /* { - syscallarg(char *) path; - syscallarg(int) uid; - syscallarg(int) gid; - } */ *uap; -{ - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = setfown(p, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid)); - vrele(nd.ni_vp); - return (error); -} - -/* - * Set ownership given a path name, do not cross symlinks. - */ -#ifndef _SYS_SYSPROTO_H_ -struct lchown_args { - char *path; - int uid; - int gid; -}; -#endif -/* ARGSUSED */ -int -lchown(p, uap) - struct proc *p; - register struct lchown_args /* { - syscallarg(char *) path; - syscallarg(int) uid; - syscallarg(int) gid; - } */ *uap; -{ - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = setfown(p, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid)); - vrele(nd.ni_vp); - return (error); -} - -/* - * Set ownership given a file descriptor. - */ -#ifndef _SYS_SYSPROTO_H_ -struct fchown_args { - int fd; - int uid; - int gid; -}; -#endif -/* ARGSUSED */ -int -fchown(p, uap) - struct proc *p; - register struct fchown_args /* { - syscallarg(int) fd; - syscallarg(int) uid; - syscallarg(int) gid; - } */ *uap; -{ - struct file *fp; - int error; - - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) - return (error); - return setfown(p, (struct vnode *)fp->f_data, - SCARG(uap, uid), SCARG(uap, gid)); -} - -static int -getutimes(usrtvp, tsp) - const struct timeval *usrtvp; - struct timespec *tsp; -{ - struct timeval tv[2]; - int error; - - if (usrtvp == NULL) { - microtime(&tv[0]); - TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]); - tsp[1] = tsp[0]; - } else { - if ((error = copyin(usrtvp, tv, sizeof (tv))) != 0) - return (error); - TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]); - TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]); - } - return 0; -} - -static int -setutimes(p, vp, ts, nullflag) - struct proc *p; - struct vnode *vp; - const struct timespec *ts; - int nullflag; -{ - int error; - struct vattr vattr; - - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - VATTR_NULL(&vattr); - vattr.va_atime = ts[0]; - vattr.va_mtime = ts[1]; - if (nullflag) - vattr.va_vaflags |= VA_UTIMES_NULL; - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - VOP_UNLOCK(vp, 0, p); - return error; -} - -/* - * Set the access and modification times of a file. - */ -#ifndef _SYS_SYSPROTO_H_ -struct utimes_args { - char *path; - struct timeval *tptr; -}; -#endif -/* ARGSUSED */ -int -utimes(p, uap) - struct proc *p; - register struct utimes_args /* { - syscallarg(char *) path; - syscallarg(struct timeval *) tptr; - } */ *uap; -{ - struct timespec ts[2]; - struct timeval *usrtvp; - int error; - struct nameidata nd; - - usrtvp = SCARG(uap, tptr); - if ((error = getutimes(usrtvp, ts)) != 0) - return (error); - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = setutimes(p, nd.ni_vp, ts, usrtvp == NULL); - vrele(nd.ni_vp); - return (error); -} - -/* - * Set the access and modification times of a file. - */ -#ifndef _SYS_SYSPROTO_H_ -struct lutimes_args { - char *path; - struct timeval *tptr; -}; -#endif -/* ARGSUSED */ -int -lutimes(p, uap) - struct proc *p; - register struct lutimes_args /* { - syscallarg(char *) path; - syscallarg(struct timeval *) tptr; - } */ *uap; -{ - struct timespec ts[2]; - struct timeval *usrtvp; - int error; - struct nameidata nd; - - usrtvp = SCARG(uap, tptr); - if ((error = getutimes(usrtvp, ts)) != 0) - return (error); - NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = setutimes(p, nd.ni_vp, ts, usrtvp == NULL); - vrele(nd.ni_vp); - return (error); -} - -/* - * Set the access and modification times of a file. - */ -#ifndef _SYS_SYSPROTO_H_ -struct futimes_args { - int fd; - struct timeval *tptr; -}; -#endif -/* ARGSUSED */ -int -futimes(p, uap) - struct proc *p; - register struct futimes_args /* { - syscallarg(int ) fd; - syscallarg(struct timeval *) tptr; - } */ *uap; -{ - struct timespec ts[2]; - struct file *fp; - struct timeval *usrtvp; - int error; - - usrtvp = SCARG(uap, tptr); - if ((error = getutimes(usrtvp, ts)) != 0) - return (error); - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) - return (error); - return setutimes(p, (struct vnode *)fp->f_data, ts, usrtvp == NULL); -} - -/* - * Truncate a file given its path name. - */ -#ifndef _SYS_SYSPROTO_H_ -struct truncate_args { - char *path; - int pad; - off_t length; -}; -#endif -/* ARGSUSED */ -int -truncate(p, uap) - struct proc *p; - register struct truncate_args /* { - syscallarg(char *) path; - syscallarg(int) pad; - syscallarg(off_t) length; - } */ *uap; -{ - register struct vnode *vp; - struct vattr vattr; - int error; - struct nameidata nd; - - if (uap->length < 0) - return(EINVAL); - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - if (vp->v_type == VDIR) - error = EISDIR; - else if ((error = vn_writechk(vp)) == 0 && - (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { - VATTR_NULL(&vattr); - vattr.va_size = SCARG(uap, length); - error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); - } - vput(vp); - return (error); -} - -/* - * Truncate a file given a file descriptor. - */ -#ifndef _SYS_SYSPROTO_H_ -struct ftruncate_args { - int fd; - int pad; - off_t length; -}; -#endif -/* ARGSUSED */ -int -ftruncate(p, uap) - struct proc *p; - register struct ftruncate_args /* { - syscallarg(int) fd; - syscallarg(int) pad; - syscallarg(off_t) length; - } */ *uap; -{ - struct vattr vattr; - struct vnode *vp; - struct file *fp; - int error; - - if (uap->length < 0) - return(EINVAL); - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) - return (error); - if ((fp->f_flag & FWRITE) == 0) - return (EINVAL); - vp = (struct vnode *)fp->f_data; - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - if (vp->v_type == VDIR) - error = EISDIR; - else if ((error = vn_writechk(vp)) == 0) { - VATTR_NULL(&vattr); - vattr.va_size = SCARG(uap, length); - error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); - } - VOP_UNLOCK(vp, 0, p); - return (error); -} - -#if defined(COMPAT_43) || defined(COMPAT_SUNOS) -/* - * Truncate a file given its path name. - */ -#ifndef _SYS_SYSPROTO_H_ -struct otruncate_args { - char *path; - long length; -}; -#endif -/* ARGSUSED */ -int -otruncate(p, uap) - struct proc *p; - register struct otruncate_args /* { - syscallarg(char *) path; - syscallarg(long) length; - } */ *uap; -{ - struct truncate_args /* { - syscallarg(char *) path; - syscallarg(int) pad; - syscallarg(off_t) length; - } */ nuap; - - SCARG(&nuap, path) = SCARG(uap, path); - SCARG(&nuap, length) = SCARG(uap, length); - return (truncate(p, &nuap)); -} - -/* - * Truncate a file given a file descriptor. - */ -#ifndef _SYS_SYSPROTO_H_ -struct oftruncate_args { - int fd; - long length; -}; -#endif -/* ARGSUSED */ -int -oftruncate(p, uap) - struct proc *p; - register struct oftruncate_args /* { - syscallarg(int) fd; - syscallarg(long) length; - } */ *uap; -{ - struct ftruncate_args /* { - syscallarg(int) fd; - syscallarg(int) pad; - syscallarg(off_t) length; - } */ nuap; - - SCARG(&nuap, fd) = SCARG(uap, fd); - SCARG(&nuap, length) = SCARG(uap, length); - return (ftruncate(p, &nuap)); -} -#endif /* COMPAT_43 || COMPAT_SUNOS */ - -/* - * Sync an open file. - */ -#ifndef _SYS_SYSPROTO_H_ -struct fsync_args { - int fd; -}; -#endif -/* ARGSUSED */ -int -fsync(p, uap) - struct proc *p; - struct fsync_args /* { - syscallarg(int) fd; - } */ *uap; -{ - register struct vnode *vp; - struct file *fp; - int error; - - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) - return (error); - vp = (struct vnode *)fp->f_data; - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - if (vp->v_object) - vm_object_page_clean(vp->v_object, 0, 0, 0); - if ((error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p)) == 0 && - vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP) && - bioops.io_fsync) - error = (*bioops.io_fsync)(vp); - VOP_UNLOCK(vp, 0, p); - return (error); -} - -/* - * Rename files. Source and destination must either both be directories, - * or both not be directories. If target is a directory, it must be empty. - */ -#ifndef _SYS_SYSPROTO_H_ -struct rename_args { - char *from; - char *to; -}; -#endif -/* ARGSUSED */ -int -rename(p, uap) - struct proc *p; - register struct rename_args /* { - syscallarg(char *) from; - syscallarg(char *) to; - } */ *uap; -{ - register struct vnode *tvp, *fvp, *tdvp; - struct nameidata fromnd, tond; - int error; - - bwillwrite(); - NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, - SCARG(uap, from), p); - if ((error = namei(&fromnd)) != 0) - return (error); - fvp = fromnd.ni_vp; - NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ, - UIO_USERSPACE, SCARG(uap, to), p); - if (fromnd.ni_vp->v_type == VDIR) - tond.ni_cnd.cn_flags |= WILLBEDIR; - if ((error = namei(&tond)) != 0) { - /* Translate error code for rename("dir1", "dir2/."). */ - if (error == EISDIR && fvp->v_type == VDIR) - error = EINVAL; - NDFREE(&fromnd, NDF_ONLY_PNBUF); - vrele(fromnd.ni_dvp); - vrele(fvp); - goto out1; - } - tdvp = tond.ni_dvp; - tvp = tond.ni_vp; - if (tvp != NULL) { - if (fvp->v_type == VDIR && tvp->v_type != VDIR) { - error = ENOTDIR; - goto out; - } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { - error = EISDIR; - goto out; - } - } - if (fvp == tdvp) - error = EINVAL; - /* - * If source is the same as the destination (that is the - * same inode number with the same name in the same directory), - * then there is nothing to do. - */ - if (fvp == tvp && fromnd.ni_dvp == tdvp && - fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && - !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, - fromnd.ni_cnd.cn_namelen)) - error = -1; -out: - if (!error) { - VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); - if (fromnd.ni_dvp != tdvp) { - VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - } - if (tvp) { - VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); - } - error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, - tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); - NDFREE(&fromnd, NDF_ONLY_PNBUF); - NDFREE(&tond, NDF_ONLY_PNBUF); - } else { - NDFREE(&fromnd, NDF_ONLY_PNBUF); - NDFREE(&tond, NDF_ONLY_PNBUF); - if (tdvp == tvp) - vrele(tdvp); - else - vput(tdvp); - if (tvp) - vput(tvp); - vrele(fromnd.ni_dvp); - vrele(fvp); - } - vrele(tond.ni_startdir); - ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename"); - ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename"); - ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename"); - ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename"); -out1: - if (fromnd.ni_startdir) - vrele(fromnd.ni_startdir); - if (error == -1) - return (0); - return (error); -} - -/* - * Make a directory file. - */ -#ifndef _SYS_SYSPROTO_H_ -struct mkdir_args { - char *path; - int mode; -}; -#endif -/* ARGSUSED */ -int -mkdir(p, uap) - struct proc *p; - register struct mkdir_args /* { - syscallarg(char *) path; - syscallarg(int) mode; - } */ *uap; -{ - register struct vnode *vp; - struct vattr vattr; - int error; - struct nameidata nd; - - bwillwrite(); - NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); - nd.ni_cnd.cn_flags |= WILLBEDIR; - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - if (vp != NULL) { - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - vrele(vp); - return (EEXIST); - } - VATTR_NULL(&vattr); - vattr.va_type = VDIR; - vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; - VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_dvp); - if (!error) - vput(nd.ni_vp); - ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir"); - ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir"); - return (error); -} - -/* - * Remove a directory file. - */ -#ifndef _SYS_SYSPROTO_H_ -struct rmdir_args { - char *path; -}; -#endif -/* ARGSUSED */ -int -rmdir(p, uap) - struct proc *p; - struct rmdir_args /* { - syscallarg(char *) path; - } */ *uap; -{ - register struct vnode *vp; - int error; - struct nameidata nd; - - bwillwrite(); - NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, - SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - if (vp->v_type != VDIR) { - error = ENOTDIR; - goto out; - } - /* - * No rmdir "." please. - */ - if (nd.ni_dvp == vp) { - error = EINVAL; - goto out; - } - /* - * The root of a mounted filesystem cannot be deleted. - */ - if (vp->v_flag & VROOT) - error = EBUSY; - else { - VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); - } -out: - NDFREE(&nd, NDF_ONLY_PNBUF); - if (nd.ni_dvp == vp) - vrele(nd.ni_dvp); - else - vput(nd.ni_dvp); - if (vp != NULLVP) - vput(vp); - ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir"); - ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir"); - return (error); -} - -#ifdef COMPAT_43 -/* - * Read a block of directory entries in a file system independent format. - */ -#ifndef _SYS_SYSPROTO_H_ -struct ogetdirentries_args { - int fd; - char *buf; - u_int count; - long *basep; -}; -#endif -int -ogetdirentries(p, uap) - struct proc *p; - register struct ogetdirentries_args /* { - syscallarg(int) fd; - syscallarg(char *) buf; - syscallarg(u_int) count; - syscallarg(long *) basep; - } */ *uap; -{ - struct vnode *vp; - struct file *fp; - struct uio auio, kuio; - struct iovec aiov, kiov; - struct dirent *dp, *edp; - caddr_t dirbuf; - int error, eofflag, readcnt; - long loff; - - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) - return (error); - if ((fp->f_flag & FREAD) == 0) - return (EBADF); - vp = (struct vnode *)fp->f_data; -unionread: - if (vp->v_type != VDIR) - return (EINVAL); - aiov.iov_base = SCARG(uap, buf); - aiov.iov_len = SCARG(uap, count); - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_procp = p; - auio.uio_resid = SCARG(uap, count); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - loff = auio.uio_offset = fp->f_offset; -# if (BYTE_ORDER != LITTLE_ENDIAN) - if (vp->v_mount->mnt_maxsymlinklen <= 0) { - error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, - NULL, NULL); - fp->f_offset = auio.uio_offset; - } else -# endif - { - kuio = auio; - kuio.uio_iov = &kiov; - kuio.uio_segflg = UIO_SYSSPACE; - kiov.iov_len = SCARG(uap, count); - MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); - kiov.iov_base = dirbuf; - error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, - NULL, NULL); - fp->f_offset = kuio.uio_offset; - if (error == 0) { - readcnt = SCARG(uap, count) - kuio.uio_resid; - edp = (struct dirent *)&dirbuf[readcnt]; - for (dp = (struct dirent *)dirbuf; dp < edp; ) { -# if (BYTE_ORDER == LITTLE_ENDIAN) - /* - * The expected low byte of - * dp->d_namlen is our dp->d_type. - * The high MBZ byte of dp->d_namlen - * is our dp->d_namlen. - */ - dp->d_type = dp->d_namlen; - dp->d_namlen = 0; -# else - /* - * The dp->d_type is the high byte - * of the expected dp->d_namlen, - * so must be zero'ed. - */ - dp->d_type = 0; -# endif - if (dp->d_reclen > 0) { - dp = (struct dirent *) - ((char *)dp + dp->d_reclen); - } else { - error = EIO; - break; - } - } - if (dp >= edp) - error = uiomove(dirbuf, readcnt, &auio); - } - FREE(dirbuf, M_TEMP); - } - VOP_UNLOCK(vp, 0, p); - if (error) - return (error); - if (SCARG(uap, count) == auio.uio_resid) { - if (union_dircheckp) { - error = union_dircheckp(p, &vp, fp); - if (error == -1) - goto unionread; - if (error) - return (error); - } - if ((vp->v_flag & VROOT) && - (vp->v_mount->mnt_flag & MNT_UNION)) { - struct vnode *tvp = vp; - vp = vp->v_mount->mnt_vnodecovered; - VREF(vp); - fp->f_data = (caddr_t) vp; - fp->f_offset = 0; - vrele(tvp); - goto unionread; - } - } - error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), - sizeof(long)); - p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; - return (error); -} -#endif /* COMPAT_43 */ - -/* - * Read a block of directory entries in a file system independent format. - */ -#ifndef _SYS_SYSPROTO_H_ -struct getdirentries_args { - int fd; - char *buf; - u_int count; - long *basep; -}; -#endif -int -getdirentries(p, uap) - struct proc *p; - register struct getdirentries_args /* { - syscallarg(int) fd; - syscallarg(char *) buf; - syscallarg(u_int) count; - syscallarg(long *) basep; - } */ *uap; -{ - struct vnode *vp; - struct file *fp; - struct uio auio; - struct iovec aiov; - long loff; - int error, eofflag; - - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) - return (error); - if ((fp->f_flag & FREAD) == 0) - return (EBADF); - vp = (struct vnode *)fp->f_data; -unionread: - if (vp->v_type != VDIR) - return (EINVAL); - aiov.iov_base = SCARG(uap, buf); - aiov.iov_len = SCARG(uap, count); - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_procp = p; - auio.uio_resid = SCARG(uap, count); - /* vn_lock(vp, LK_SHARED | LK_RETRY, p); */ - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - loff = auio.uio_offset = fp->f_offset; - error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL); - fp->f_offset = auio.uio_offset; - VOP_UNLOCK(vp, 0, p); - if (error) - return (error); - if (SCARG(uap, count) == auio.uio_resid) { - if (union_dircheckp) { - error = union_dircheckp(p, &vp, fp); - if (error == -1) - goto unionread; - if (error) - return (error); - } - if ((vp->v_flag & VROOT) && - (vp->v_mount->mnt_flag & MNT_UNION)) { - struct vnode *tvp = vp; - vp = vp->v_mount->mnt_vnodecovered; - VREF(vp); - fp->f_data = (caddr_t) vp; - fp->f_offset = 0; - vrele(tvp); - goto unionread; - } - } - if (SCARG(uap, basep) != NULL) { - error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), - sizeof(long)); - } - p->p_retval[0] = SCARG(uap, count) - auio.uio_resid; - return (error); -} -#ifndef _SYS_SYSPROTO_H_ -struct getdents_args { - int fd; - char *buf; - size_t count; -}; -#endif -int -getdents(p, uap) - struct proc *p; - register struct getdents_args /* { - syscallarg(int) fd; - syscallarg(char *) buf; - syscallarg(u_int) count; - } */ *uap; -{ - struct getdirentries_args ap; - ap.fd = uap->fd; - ap.buf = uap->buf; - ap.count = uap->count; - ap.basep = NULL; - return getdirentries(p, &ap); -} - -/* - * Set the mode mask for creation of filesystem nodes. - */ -#ifndef _SYS_SYSPROTO_H_ -struct umask_args { - int newmask; -}; -#endif -int -umask(p, uap) - struct proc *p; - struct umask_args /* { - syscallarg(int) newmask; - } */ *uap; -{ - register struct filedesc *fdp; - - fdp = p->p_fd; - p->p_retval[0] = fdp->fd_cmask; - fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; - return (0); -} - -/* - * Void all references to file by ripping underlying filesystem - * away from vnode. - */ -#ifndef _SYS_SYSPROTO_H_ -struct revoke_args { - char *path; -}; -#endif -/* ARGSUSED */ -int -revoke(p, uap) - struct proc *p; - register struct revoke_args /* { - syscallarg(char *) path; - } */ *uap; -{ - register struct vnode *vp; - struct vattr vattr; - int error; - struct nameidata nd; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); - if (vp->v_type != VCHR && vp->v_type != VBLK) { - error = EINVAL; - goto out; - } - if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0) - goto out; - if (p->p_ucred->cr_uid != vattr.va_uid && - (error = suser_xxx(0, p, PRISON_ROOT))) - goto out; - if (vcount(vp) > 1) - VOP_REVOKE(vp, REVOKEALL); -out: - vrele(vp); - return (error); -} - -/* - * Convert a user file descriptor to a kernel file entry. - */ -int -getvnode(fdp, fd, fpp) - struct filedesc *fdp; - int fd; - struct file **fpp; -{ - struct file *fp; - - if ((u_int)fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[fd]) == NULL) - return (EBADF); - if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) - return (EINVAL); - *fpp = fp; - return (0); -} -/* - * Get (NFS) file handle - */ -#ifndef _SYS_SYSPROTO_H_ -struct getfh_args { - char *fname; - fhandle_t *fhp; -}; -#endif -int -getfh(p, uap) - struct proc *p; - register struct getfh_args *uap; -{ - struct nameidata nd; - fhandle_t fh; - register struct vnode *vp; - int error; - - /* - * Must be super user - */ - error = suser(p); - if (error) - return (error); - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); - error = namei(&nd); - if (error) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; - bzero(&fh, sizeof(fh)); - fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; - error = VFS_VPTOFH(vp, &fh.fh_fid); - vput(vp); - if (error) - return (error); - error = copyout(&fh, uap->fhp, sizeof (fh)); - return (error); -} - -/* - * syscall for the rpc.lockd to use to translate a NFS file handle into - * an open descriptor. - * - * warning: do not remove the suser() call or this becomes one giant - * security hole. - */ -#ifndef _SYS_SYSPROTO_H_ -struct fhopen_args { - const struct fhandle *u_fhp; - int flags; -}; -#endif -int -fhopen(p, uap) - struct proc *p; - struct fhopen_args /* { - syscallarg(const struct fhandle *) u_fhp; - syscallarg(int) flags; - } */ *uap; -{ - struct mount *mp; - struct vnode *vp; - struct fhandle fhp; - struct vattr vat; - struct vattr *vap = &vat; - struct flock lf; - struct file *fp; - register struct filedesc *fdp = p->p_fd; - int fmode, mode, error, type; - struct file *nfp; - int indx; - - /* - * Must be super user - */ - error = suser(p); - if (error) - return (error); - - fmode = FFLAGS(SCARG(uap, flags)); - /* why not allow a non-read/write open for our lockd? */ - if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT)) - return (EINVAL); - error = copyin(SCARG(uap,u_fhp), &fhp, sizeof(fhp)); - if (error) - return(error); - /* find the mount point */ - mp = vfs_getvfs(&fhp.fh_fsid); - if (mp == NULL) - return (ESTALE); - /* now give me my vnode, it gets returned to me locked */ - error = VFS_FHTOVP(mp, &fhp.fh_fid, &vp); - if (error) - return (error); - /* - * from now on we have to make sure not - * to forget about the vnode - * any error that causes an abort must vput(vp) - * just set error = err and 'goto bad;'. - */ - - /* - * from vn_open - */ - if (vp->v_type == VLNK) { - error = EMLINK; - goto bad; - } - if (vp->v_type == VSOCK) { - error = EOPNOTSUPP; - goto bad; - } - mode = 0; - if (fmode & (FWRITE | O_TRUNC)) { - if (vp->v_type == VDIR) { - error = EISDIR; - goto bad; - } - error = vn_writechk(vp); - if (error) - goto bad; - mode |= VWRITE; - } - if (fmode & FREAD) - mode |= VREAD; - if (mode) { - error = VOP_ACCESS(vp, mode, p->p_ucred, p); - if (error) - goto bad; - } - if (fmode & O_TRUNC) { - VOP_UNLOCK(vp, 0, p); /* XXX */ - VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ - VATTR_NULL(vap); - vap->va_size = 0; - error = VOP_SETATTR(vp, vap, p->p_ucred, p); - if (error) - goto bad; - } - error = VOP_OPEN(vp, fmode, p->p_ucred, p); - if (error) - goto bad; - /* - * Make sure that a VM object is created for VMIO support. - */ - if (vn_canvmio(vp) == TRUE) { - if ((error = vfs_object_create(vp, p, p->p_ucred)) != 0) - goto bad; - } - if (fmode & FWRITE) - vp->v_writecount++; - - /* - * end of vn_open code - */ - - if ((error = falloc(p, &nfp, &indx)) != 0) - goto bad; - fp = nfp; - nfp->f_data = (caddr_t)vp; - nfp->f_flag = fmode & FMASK; - nfp->f_ops = &vnops; - nfp->f_type = DTYPE_VNODE; - if (fmode & (O_EXLOCK | O_SHLOCK)) { - lf.l_whence = SEEK_SET; - lf.l_start = 0; - lf.l_len = 0; - if (fmode & O_EXLOCK) - lf.l_type = F_WRLCK; - else - lf.l_type = F_RDLCK; - type = F_FLOCK; - if ((fmode & FNONBLOCK) == 0) - type |= F_WAIT; - VOP_UNLOCK(vp, 0, p); - if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) { - (void) vn_close(vp, fp->f_flag, fp->f_cred, p); - ffree(fp); - fdp->fd_ofiles[indx] = NULL; - return (error); - } - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - fp->f_flag |= FHASLOCK; - } - if ((vp->v_type == VREG) && (vp->v_object == NULL)) - vfs_object_create(vp, p, p->p_ucred); - - VOP_UNLOCK(vp, 0, p); - p->p_retval[0] = indx; - return (0); - -bad: - vput(vp); - return (error); -} - -#ifndef _SYS_SYSPROTO_H_ -struct fhstat_args { - struct fhandle *u_fhp; - struct stat *sb; -}; -#endif -int -fhstat(p, uap) - struct proc *p; - register struct fhstat_args /* { - syscallarg(struct fhandle *) u_fhp; - syscallarg(struct stat *) sb; - } */ *uap; -{ - struct stat sb; - fhandle_t fh; - struct mount *mp; - struct vnode *vp; - int error; - - /* - * Must be super user - */ - error = suser(p); - if (error) - return (error); - - error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t)); - if (error) - return (error); - - if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) - return (ESTALE); - if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) - return (error); - error = vn_stat(vp, &sb, p); - vput(vp); - if (error) - return (error); - error = copyout(&sb, SCARG(uap, sb), sizeof(sb)); - return (error); -} - -#ifndef _SYS_SYSPROTO_H_ -struct fhstatfs_args { - struct fhandle *u_fhp; - struct statfs *buf; -}; -#endif -int -fhstatfs(p, uap) - struct proc *p; - struct fhstatfs_args /* { - syscallarg(struct fhandle) *u_fhp; - syscallarg(struct statfs) *buf; - } */ *uap; -{ - struct statfs *sp; - struct mount *mp; - struct vnode *vp; - struct statfs sb; - fhandle_t fh; - int error; - - /* - * Must be super user - */ - if ((error = suser(p))) - return (error); - - if ((error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t))) != 0) - return (error); - - if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) - return (ESTALE); - if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) - return (error); - mp = vp->v_mount; - sp = &mp->mnt_stat; - vput(vp); - if ((error = VFS_STATFS(mp, sp, p)) != 0) - return (error); - sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - if (suser_xxx(p->p_ucred, 0, 0)) { - bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); - sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; - sp = &sb; - } - return (copyout(sp, SCARG(uap, buf), sizeof(*sp))); -} - -/* - * Syscall to push extended attribute configuration information into the - * VFS. Accepts a path, which it converts to a mountpoint, as well as - * a command (int cmd), and attribute name and misc data. For now, the - * attribute name is left in userspace for consumption by the VFS_op. - * It will probably be changed to be copied into sysspace by the - * syscall in the future, once issues with various consumers of the - * attribute code have raised their hands. - * - * Currently this is used only by UFS Extended Attributes. - */ -int -extattrctl(p, uap) - struct proc *p; - struct extattrctl_args *uap; -{ - struct nameidata nd; - struct mount *mp; - int error; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - mp = nd.ni_vp->v_mount; - NDFREE(&nd, 0); - return (VFS_EXTATTRCTL(mp, SCARG(uap, cmd), SCARG(uap, attrname), - SCARG(uap, arg), p)); -} - -/* - * Syscall to set a named extended attribute on a file or directory. - * Accepts attribute name, and a uio structure pointing to the data to set. - * The uio is consumed in the style of writev(). The real work happens - * in VOP_SETEXTATTR(). - */ -int -extattr_set_file(p, uap) - struct proc *p; - struct extattr_set_file_args *uap; -{ - struct nameidata nd; - struct uio auio; - struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV]; - char attrname[EXTATTR_MAXNAMELEN]; - u_int iovlen, cnt; - int error, i; - - error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); - if (error) - return (error); - NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, SCARG(uap, path), - p); - if ((error = namei(&nd)) != 0) - return(error); - iovlen = uap->iovcnt * sizeof(struct iovec); - if (uap->iovcnt > UIO_SMALLIOV) { - if (uap->iovcnt > UIO_MAXIOV) { - error = EINVAL; - goto done; - } - MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); - needfree = iov; - } else - iov = aiov; - auio.uio_iov = iov; - auio.uio_iovcnt = uap->iovcnt; - auio.uio_rw = UIO_WRITE; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_procp = p; - auio.uio_offset = 0; - if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))) - goto done; - auio.uio_resid = 0; - for (i = 0; i < uap->iovcnt; i++) { - if (iov->iov_len > INT_MAX - auio.uio_resid) { - error = EINVAL; - goto done; - } - auio.uio_resid += iov->iov_len; - iov++; - } - cnt = auio.uio_resid; - error = VOP_SETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred, - p); - if (auio.uio_resid != cnt && (error == ERESTART || - error == EINTR || error == EWOULDBLOCK)) - error = 0; - cnt -= auio.uio_resid; - p->p_retval[0] = cnt; -done: - if (needfree) - FREE(needfree, M_IOV); - NDFREE(&nd, 0); - return (error); -} - -/* - * Syscall to get a named extended attribute on a file or directory. - * Accepts attribute name, and a uio structure pointing to a buffer for the - * data. The uio is consumed in the style of readv(). The real work - * happens in VOP_GETEXTATTR(); - */ -int -extattr_get_file(p, uap) - struct proc *p; - struct extattr_get_file_args *uap; -{ - struct nameidata nd; - struct uio auio; - struct iovec *iov, *needfree, aiov[UIO_SMALLIOV]; - char attrname[EXTATTR_MAXNAMELEN]; - u_int iovlen, cnt; - int error, i; - - error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); - if (error) - return (error); - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); - if ((error = namei(&nd)) != 0) - return (error); - iovlen = uap->iovcnt * sizeof (struct iovec); - if (uap->iovcnt > UIO_SMALLIOV) { - if (uap->iovcnt > UIO_MAXIOV) { - NDFREE(&nd, 0); - return (EINVAL); - } - MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); - needfree = iov; - } else { - iov = aiov; - needfree = NULL; - } - auio.uio_iov = iov; - auio.uio_iovcnt = uap->iovcnt; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_USERSPACE; - auio.uio_procp = p; - auio.uio_offset = 0; - if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))) - goto done; - auio.uio_resid = 0; - for (i = 0; i < uap->iovcnt; i++) { - if (iov->iov_len > INT_MAX - auio.uio_resid) { - error = EINVAL; - goto done; - } - auio.uio_resid += iov->iov_len; - iov++; - } - cnt = auio.uio_resid; - error = VOP_GETEXTATTR(nd.ni_vp, attrname, &auio, p->p_cred->pc_ucred, - p); - if (auio.uio_resid != cnt && (error == ERESTART || - error == EINTR || error == EWOULDBLOCK)) - error = 0; - cnt -= auio.uio_resid; - p->p_retval[0] = cnt; -done: - if (needfree) - FREE(needfree, M_IOV); - NDFREE(&nd, 0); - return(error); -} - -/* - * Syscall to delete a named extended attribute from a file or directory. - * Accepts attribute name. The real work happens in VOP_SETEXTATTR(). - */ -int -extattr_delete_file(p, uap) - struct proc *p; - struct extattr_delete_file_args *uap; -{ - struct nameidata nd; - char attrname[EXTATTR_MAXNAMELEN]; - int error; - - error = copyin(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN); - if (error) - return(error); - NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, SCARG(uap, path), - p); - if ((error = namei(&nd)) != 0) - return(error); - error = VOP_SETEXTATTR(nd.ni_vp, attrname, NULL, p->p_cred->pc_ucred, - p); - NDFREE(&nd, 0); - return(error); -} diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c deleted file mode 100644 index 8aaa4824cb4f..000000000000 --- a/sys/kern/vfs_mount.c +++ /dev/null @@ -1,366 +0,0 @@ -/*- - * Copyright (c) 1999 Michael Smith - * All rights reserved. - * Copyright (c) 1999 Poul-Henning Kamp - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * Locate and mount the root filesystem. - * - * The root filesystem is detailed in the kernel environment variable - * vfs.root.mountfrom, which is expected to be in the general format - * - * <vfsname>:[<path>] - * vfsname := the name of a VFS known to the kernel and capable - * of being mounted as root - * path := disk device name or other data used by the filesystem - * to locate its physical store - * - */ - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/vnode.h> -#include <sys/mount.h> -#include <sys/malloc.h> -#include <sys/reboot.h> -#include <sys/diskslice.h> -#include <sys/disklabel.h> -#include <sys/conf.h> -#include <sys/cons.h> - -MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount structure"); - -#define ROOTNAME "root_device" - -struct vnode *rootvnode; - -/* - * The root specifiers we will try if RB_CDROM is specified. - */ -static char *cdrom_rootdevnames[] = { - "cd9660:cd0a", - "cd9660:acd0a", - "cd9660:wcd0a", - NULL -}; - -static void vfs_mountroot(void *junk); -static int vfs_mountroot_try(char *mountfrom); -static int vfs_mountroot_ask(void); -static void gets(char *cp); - -/* legacy find-root code */ -char *rootdevnames[2] = {NULL, NULL}; -static int setrootbyname(char *name); - -SYSINIT(mountroot, SI_SUB_MOUNT_ROOT, SI_ORDER_SECOND, vfs_mountroot, NULL); - -/* - * Find and mount the root filesystem - */ -static void -vfs_mountroot(void *junk) -{ - int i; - - /* - * The root filesystem information is compiled in, and we are - * booted with instructions to use it. - */ -#ifdef ROOTDEVNAME - if ((boothowto & RB_DFLTROOT) && - !vfs_mountroot_try(ROOTDEVNAME)) - return; -#endif - /* - * We are booted with instructions to prompt for the root filesystem, - * or to use the compiled-in default when it doesn't exist. - */ - if (boothowto & (RB_DFLTROOT | RB_ASKNAME)) { - if (!vfs_mountroot_ask()) - return; - } - - /* - * We've been given the generic "use CDROM as root" flag. This is - * necessary because one media may be used in many different - * devices, so we need to search for them. - */ - if (boothowto & RB_CDROM) { - for (i = 0; cdrom_rootdevnames[i] != NULL; i++) { - if (!vfs_mountroot_try(cdrom_rootdevnames[i])) - return; - } - } - - /* - * Try to use the value read by the loader from /etc/fstab, or - * supplied via some other means. This is the preferred - * mechanism. - */ - if (!vfs_mountroot_try(getenv("vfs.root.mountfrom"))) - return; - - /* - * Try values that may have been computed by the machine-dependant - * legacy code. - */ - if (!vfs_mountroot_try(rootdevnames[0])) - return; - if (!vfs_mountroot_try(rootdevnames[1])) - return; - - /* - * If we have a compiled-in default, and haven't already tried it, try - * it now. - */ -#ifdef ROOTDEVNAME - if (!(boothowto & RB_DFLTROOT)) - if (!vfs_mountroot_try(ROOTDEVNAME)) - return; -#endif - - /* - * Everything so far has failed, prompt on the console if we haven't - * already tried that. - */ - if (!(boothowto & (RB_DFLTROOT | RB_ASKNAME)) && !vfs_mountroot_ask()) - return; - panic("Root mount failed, startup aborted."); -} - -/* - * Mount (mountfrom) as the root filesystem. - */ -static int -vfs_mountroot_try(char *mountfrom) -{ - struct mount *mp; - char *vfsname, *path; - int error; - char patt[32]; - int s; - - vfsname = NULL; - path = NULL; - mp = NULL; - error = EINVAL; - - if (mountfrom == NULL) - return(error); /* don't complain */ - - s = splcam(); /* Overkill, but annoying without it */ - printf("Mounting root from %s\n", mountfrom); - splx(s); - - /* parse vfs name and path */ - vfsname = malloc(MFSNAMELEN, M_MOUNT, M_WAITOK); - path = malloc(MNAMELEN, M_MOUNT, M_WAITOK); - vfsname[0] = path[0] = 0; - sprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN); - if (sscanf(mountfrom, patt, vfsname, path) < 1) - goto done; - - /* allocate a root mount */ - error = vfs_rootmountalloc(vfsname, path[0] != 0 ? path : ROOTNAME, - &mp); - if (error != 0) { - printf("Can't allocate root mount for filesystem '%s': %d\n", - vfsname, error); - goto done; - } - mp->mnt_flag |= MNT_ROOTFS; - - /* do our best to set rootdev */ - if ((path[0] != 0) && setrootbyname(path)) - printf("setrootbyname failed\n"); - - /* If the root device is a type "memory disk", mount RW */ - if (rootdev != NODEV && devsw(rootdev) && - (devsw(rootdev)->d_flags & D_MEMDISK)) - mp->mnt_flag &= ~MNT_RDONLY; - - error = VFS_MOUNT(mp, NULL, NULL, NULL, curproc); - -done: - if (vfsname != NULL) - free(vfsname, M_MOUNT); - if (path != NULL) - free(path, M_MOUNT); - if (error != 0) { - if (mp != NULL) { - vfs_unbusy(mp, curproc); - free(mp, M_MOUNT); - } - printf("Root mount failed: %d\n", error); - } else { - - /* register with list of mounted filesystems */ - simple_lock(&mountlist_slock); - TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list); - simple_unlock(&mountlist_slock); - - /* sanity check system clock against root filesystem timestamp */ - inittodr(mp->mnt_time); - vfs_unbusy(mp, curproc); - } - return(error); -} - -/* - * Spin prompting on the console for a suitable root filesystem - */ -static int -vfs_mountroot_ask(void) -{ - char name[128]; - int i; - dev_t dev; - - for(;;) { - printf("\nManual root filesystem specification:\n"); - printf(" <fstype>:<device> Mount <device> using filesystem <fstype>\n"); - printf(" eg. ufs:/dev/da0s1a\n"); - printf(" ? List valid disk boot devices\n"); - printf(" <empty line> Abort manual input\n"); - printf("\nmountroot> "); - gets(name); - if (name[0] == 0) - return(1); - if (name[0] == '?') { - printf("Possibly valid devices for 'ufs' root:\n"); - for (i = 0; i < NUMCDEVSW; i++) { - dev = makedev(i, 0); - if (devsw(dev) != NULL) - printf(" \"%s\"", devsw(dev)->d_name); - } - printf("\n"); - continue; - } - if (!vfs_mountroot_try(name)) - return(0); - } -} - -static void -gets(char *cp) -{ - char *lp; - int c; - - lp = cp; - for (;;) { - printf("%c", c = cngetc() & 0177); - switch (c) { - case -1: - case '\n': - case '\r': - *lp++ = '\0'; - return; - case '\b': - case '\177': - if (lp > cp) { - printf(" \b"); - lp--; - } - continue; - case '#': - lp--; - if (lp < cp) - lp = cp; - continue; - case '@': - case 'u' & 037: - lp = cp; - printf("%c", '\n'); - continue; - default: - *lp++ = c; - } - } -} - -/* - * Set rootdev to match (name), given that we expect it to - * refer to a disk-like device. - */ -static int -setrootbyname(char *name) -{ - char *cp; - int cd, unit, slice, part; - dev_t dev; - - slice = 0; - part = 0; - cp = rindex(name, '/'); - if (cp != NULL) { - name = cp + 1; - } - cp = name; - while (cp != '\0' && (*cp < '0' || *cp > '9')) - cp++; - if (cp == name) { - printf("missing device name\n"); - return(1); - } - if (*cp == '\0') { - printf("missing unit number\n"); - return(1); - } - unit = *cp - '0'; - *cp++ = '\0'; - for (cd = 0; cd < NUMCDEVSW; cd++) { - dev = makedev(cd, 0); - if (devsw(dev) != NULL && - strcmp(devsw(dev)->d_name, name) == 0) - goto gotit; - } - printf("no such device '%s'\n", name); - return (2); -gotit: - while (*cp >= '0' && *cp <= '9') - unit += 10 * unit + *cp++ - '0'; - if (*cp == 's' && cp[1] >= '0' && cp[1] <= '9') { - slice = cp[1] - '0' + 1; - cp += 2; - } - if (*cp >= 'a' && *cp <= 'h') { - part = *cp - 'a'; - cp++; - } - if (*cp != '\0') { - printf("junk after name\n"); - return (1); - } - rootdev = makedev(cd, dkmakeminor(unit, slice, part)); - return 0; -} - |
