aboutsummaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>2000-03-13 04:59:44 +0000
committercvs2svn <cvs2svn@FreeBSD.org>2000-03-13 04:59:44 +0000
commit842f30848780866cb822fe01c4d3d4576718ddb3 (patch)
tree212d1aae25966b1cb7769409e1ae97e626a32b95 /sys/kern
parentdd3552c8a7b2b6823668c2834f667466844698de (diff)
Notes
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_random.c378
-rw-r--r--sys/kern/kern_tc.c1004
-rw-r--r--sys/kern/ksched.c264
-rw-r--r--sys/kern/link_elf_obj.c985
-rw-r--r--sys/kern/p1003_1b.c260
-rw-r--r--sys/kern/posix4_mib.c98
-rw-r--r--sys/kern/subr_acl_posix1e.c277
-rw-r--r--sys/kern/subr_clist.c696
-rw-r--r--sys/kern/subr_disklabel.c408
-rw-r--r--sys/kern/subr_param.c176
-rw-r--r--sys/kern/subr_smp.c2739
-rw-r--r--sys/kern/subr_trap.c1152
-rw-r--r--sys/kern/uipc_sockbuf.c1006
-rw-r--r--sys/kern/vfs_acl.c277
-rw-r--r--sys/kern/vfs_export.c2974
-rw-r--r--sys/kern/vfs_extattr.c3564
-rw-r--r--sys/kern/vfs_mount.c366
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, &params);
- } 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,
- &timestamp_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;
-}
-