Index: stable/10/lib/libc/gen/_once_stub.c =================================================================== --- stable/10/lib/libc/gen/_once_stub.c (revision 283926) +++ stable/10/lib/libc/gen/_once_stub.c (revision 283927) @@ -1,64 +1,64 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include "un-namespace.h" #include "libc_private.h" /* This implements pthread_once() for the single-threaded case. */ static int _libc_once(pthread_once_t *once_control, void (*init_routine)(void)) { if (once_control->state == PTHREAD_DONE_INIT) return (0); init_routine(); once_control->state = PTHREAD_DONE_INIT; return (0); } /* * This is the internal interface provided to libc. It will use * pthread_once() from the threading library in a multi-threaded * process and _libc_once() for a single-threaded library. Because * _libc_once() uses the same ABI for the values in the pthread_once_t * structure as the threading library, it is safe for a process to * switch from _libc_once() to pthread_once() when threading is * enabled. */ int _once(pthread_once_t *once_control, void (*init_routine)(void)) { if (__isthreaded) return (_pthread_once(once_control, init_routine)); return (_libc_once(once_control, init_routine)); } Index: stable/10/lib/libc/include/compat.h =================================================================== --- stable/10/lib/libc/include/compat.h (revision 283926) +++ stable/10/lib/libc/include/compat.h (revision 283927) @@ -1,57 +1,57 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ /* * This file defines compatiblity symbol versions for old system calls. It * is included in all generated system call files. */ #ifndef __LIBC_COMPAT_H__ #define __LIBC_COMPAT_H__ #define __sym_compat(sym,impl,verid) \ .symver impl, sym@verid __sym_compat(__semctl, freebsd7___semctl, FBSD_1.0); __sym_compat(msgctl, freebsd7_msgctl, FBSD_1.0); __sym_compat(shmctl, freebsd7_shmctl, FBSD_1.0); #undef __sym_compat #define __weak_reference(sym,alias) \ .weak alias;.equ alias,sym #ifndef SYSCALL_COMPAT __weak_reference(__sys_fcntl,__fcntl_compat) #endif #undef __weak_reference #endif /* __LIBC_COMPAT_H__ */ Index: stable/10/lib/libc/stdio/open_memstream.3 =================================================================== --- stable/10/lib/libc/stdio/open_memstream.3 (revision 283926) +++ stable/10/lib/libc/stdio/open_memstream.3 (revision 283927) @@ -1,155 +1,155 @@ -.\" Copyright (c) 2013 Advanced Computing Technologies LLC +.\" Copyright (c) 2013 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 28, 2014 .Dt OPEN_MEMSTREAM 3 .Os .Sh NAME .Nm open_memstream , .Nm open_wmemstream .Nd dynamic memory buffer stream open functions .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In stdio.h .Ft FILE * .Fn open_memstream "char **bufp" "size_t *sizep" .In wchar.h .Ft FILE * .Fn open_wmemstream "wchar_t **bufp" "size_t *sizep" .Sh DESCRIPTION The .Fn open_memstream and .Fn open_wmemstream functions create a write-only, seekable stream backed by a dynamically allocated memory buffer. The .Fn open_memstream function creates a byte-oriented stream, while the .Fn open_wmemstream function creates a wide-oriented stream. .Pp Each stream maintains a current position and size. Initially, the position and size are set to zero. Each write begins at the current position and advances it the number of successfully written bytes for .Fn open_memstream or wide characters for .Fn open_wmemstream . If a write moves the current position beyond the length of the buffer, the length of the buffer is extended and a null character is appended to the buffer. .Pp A stream's buffer always contains a null character at the end of the buffer that is not included in the current length. .Pp If a stream's current position is moved beyond the current length via a seek operation and a write is performed, the characters between the current length and the current position are filled with null characters before the write is performed. .Pp After a successful call to .Xr fclose 3 or .Xr fflush 3 , the pointer referenced by .Fa bufp will contain the start of the memory buffer and the variable referenced by .Fa sizep will contain the smaller of the current position and the current buffer length. .Pp After a successful call to .Xr fflush 3, the pointer referenced by .Fa bufp and the variable referenced by .Fa sizep are only valid until the next write operation or a call to .Xr fclose 3. .Pp Once a stream is closed, the allocated buffer referenced by .Fa bufp should be released via a call to .Xr free 3 when it is no longer needed. .Sh IMPLEMENTATION NOTES Internally all I/O streams are effectively byte-oriented, so using wide-oriented operations to write to a stream opened via .Fn open_wmemstream results in wide characters being expanded to a stream of multibyte characters in stdio's internal buffers. These multibyte characters are then converted back to wide characters when written into the stream. As a result, the wide-oriented streams maintain an internal multibyte character conversion state that is cleared on any seek opertion that changes the current position. This should have no effect as long as wide-oriented output operations are used on a wide-oriented stream. .Sh RETURN VALUES Upon successful completion, .Fn open_memstream and .Fn open_wmemstream return a .Tn FILE pointer. Otherwise, .Dv NULL is returned and the global variable .Va errno is set to indicate the error. .Sh ERRORS .Bl -tag -width Er .It Bq Er EINVAL The .Fa bufp or .Fa sizep argument was .Dv NULL . .It Bq Er ENOMEM Memory for the stream or buffer could not be allocated. .El .Sh SEE ALSO .Xr fclose 3 , .Xr fflush 3 , .Xr fopen 3 , .Xr free 3 , .Xr fseek 3 , .Xr sbuf 3 , .Xr stdio 3 .Sh STANDARDS The .Fn open_memstream and .Fn open_wmemstream functions conform to .St -p1003.1-2008 . Index: stable/10/lib/libc/stdio/open_memstream.c =================================================================== --- stable/10/lib/libc/stdio/open_memstream.c (revision 283926) +++ stable/10/lib/libc/stdio/open_memstream.c (revision 283927) @@ -1,209 +1,209 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include #include #include #include #include #include "un-namespace.h" /* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */ #define FPOS_MAX OFF_MAX struct memstream { char **bufp; size_t *sizep; ssize_t len; fpos_t offset; }; static int memstream_grow(struct memstream *ms, fpos_t newoff) { char *buf; ssize_t newsize; if (newoff < 0 || newoff >= SSIZE_MAX) newsize = SSIZE_MAX - 1; else newsize = newoff; if (newsize > ms->len) { buf = realloc(*ms->bufp, newsize + 1); if (buf != NULL) { #ifdef DEBUG fprintf(stderr, "MS: %p growing from %zd to %zd\n", ms, ms->len, newsize); #endif memset(buf + ms->len + 1, 0, newsize - ms->len); *ms->bufp = buf; ms->len = newsize; return (1); } return (0); } return (1); } static void memstream_update(struct memstream *ms) { assert(ms->len >= 0 && ms->offset >= 0); *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset; } static int memstream_write(void *cookie, const char *buf, int len) { struct memstream *ms; ssize_t tocopy; ms = cookie; if (!memstream_grow(ms, ms->offset + len)) return (-1); tocopy = ms->len - ms->offset; if (len < tocopy) tocopy = len; memcpy(*ms->bufp + ms->offset, buf, tocopy); ms->offset += tocopy; memstream_update(ms); #ifdef DEBUG fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, tocopy); #endif return (tocopy); } static fpos_t memstream_seek(void *cookie, fpos_t pos, int whence) { struct memstream *ms; #ifdef DEBUG fpos_t old; #endif ms = cookie; #ifdef DEBUG old = ms->offset; #endif switch (whence) { case SEEK_SET: /* _fseeko() checks for negative offsets. */ assert(pos >= 0); ms->offset = pos; break; case SEEK_CUR: /* This is only called by _ftello(). */ assert(pos == 0); break; case SEEK_END: if (pos < 0) { if (pos + ms->len < 0) { #ifdef DEBUG fprintf(stderr, "MS: bad SEEK_END: pos %jd, len %zd\n", (intmax_t)pos, ms->len); #endif errno = EINVAL; return (-1); } } else { if (FPOS_MAX - ms->len < pos) { #ifdef DEBUG fprintf(stderr, "MS: bad SEEK_END: pos %jd, len %zd\n", (intmax_t)pos, ms->len); #endif errno = EOVERFLOW; return (-1); } } ms->offset = ms->len + pos; break; } memstream_update(ms); #ifdef DEBUG fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos, whence, (intmax_t)old, (intmax_t)ms->offset); #endif return (ms->offset); } static int memstream_close(void *cookie) { free(cookie); return (0); } FILE * open_memstream(char **bufp, size_t *sizep) { struct memstream *ms; int save_errno; FILE *fp; if (bufp == NULL || sizep == NULL) { errno = EINVAL; return (NULL); } *bufp = calloc(1, 1); if (*bufp == NULL) return (NULL); ms = malloc(sizeof(*ms)); if (ms == NULL) { save_errno = errno; free(*bufp); *bufp = NULL; errno = save_errno; return (NULL); } ms->bufp = bufp; ms->sizep = sizep; ms->len = 0; ms->offset = 0; memstream_update(ms); fp = funopen(ms, NULL, memstream_write, memstream_seek, memstream_close); if (fp == NULL) { save_errno = errno; free(ms); free(*bufp); *bufp = NULL; errno = save_errno; return (NULL); } fwide(fp, -1); return (fp); } Index: stable/10/lib/libc/stdio/open_wmemstream.c =================================================================== --- stable/10/lib/libc/stdio/open_wmemstream.c (revision 283926) +++ stable/10/lib/libc/stdio/open_wmemstream.c (revision 283927) @@ -1,271 +1,271 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include #include #include #include #include #include "un-namespace.h" /* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */ #define FPOS_MAX OFF_MAX struct wmemstream { wchar_t **bufp; size_t *sizep; ssize_t len; fpos_t offset; mbstate_t mbstate; }; static int wmemstream_grow(struct wmemstream *ms, fpos_t newoff) { wchar_t *buf; ssize_t newsize; if (newoff < 0 || newoff >= SSIZE_MAX / sizeof(wchar_t)) newsize = SSIZE_MAX / sizeof(wchar_t) - 1; else newsize = newoff; if (newsize > ms->len) { buf = realloc(*ms->bufp, (newsize + 1) * sizeof(wchar_t)); if (buf != NULL) { #ifdef DEBUG fprintf(stderr, "WMS: %p growing from %zd to %zd\n", ms, ms->len, newsize); #endif wmemset(buf + ms->len + 1, 0, newsize - ms->len); *ms->bufp = buf; ms->len = newsize; return (1); } return (0); } return (1); } static void wmemstream_update(struct wmemstream *ms) { assert(ms->len >= 0 && ms->offset >= 0); *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset; } /* * Based on a starting multibyte state and an input buffer, determine * how many wchar_t's would be output. This doesn't use mbsnrtowcs() * so that it can handle embedded null characters. */ static size_t wbuflen(const mbstate_t *state, const char *buf, int len) { mbstate_t lenstate; size_t charlen, count; count = 0; lenstate = *state; while (len > 0) { charlen = mbrlen(buf, len, &lenstate); if (charlen == (size_t)-1) return (-1); if (charlen == (size_t)-2) break; if (charlen == 0) /* XXX: Not sure how else to handle this. */ charlen = 1; len -= charlen; buf += charlen; count++; } return (count); } static int wmemstream_write(void *cookie, const char *buf, int len) { struct wmemstream *ms; ssize_t consumed, wlen; size_t charlen; ms = cookie; wlen = wbuflen(&ms->mbstate, buf, len); if (wlen < 0) { errno = EILSEQ; return (-1); } if (!wmemstream_grow(ms, ms->offset + wlen)) return (-1); /* * This copies characters one at a time rather than using * mbsnrtowcs() so it can properly handle embedded null * characters. */ consumed = 0; while (len > 0 && ms->offset < ms->len) { charlen = mbrtowc(*ms->bufp + ms->offset, buf, len, &ms->mbstate); if (charlen == (size_t)-1) { if (consumed == 0) { errno = EILSEQ; return (-1); } /* Treat it as a successful short write. */ break; } if (charlen == 0) /* XXX: Not sure how else to handle this. */ charlen = 1; if (charlen == (size_t)-2) { consumed += len; len = 0; } else { consumed += charlen; buf += charlen; len -= charlen; ms->offset++; } } wmemstream_update(ms); #ifdef DEBUG fprintf(stderr, "WMS: write(%p, %d) = %zd\n", ms, len, consumed); #endif return (consumed); } static fpos_t wmemstream_seek(void *cookie, fpos_t pos, int whence) { struct wmemstream *ms; fpos_t old; ms = cookie; old = ms->offset; switch (whence) { case SEEK_SET: /* _fseeko() checks for negative offsets. */ assert(pos >= 0); ms->offset = pos; break; case SEEK_CUR: /* This is only called by _ftello(). */ assert(pos == 0); break; case SEEK_END: if (pos < 0) { if (pos + ms->len < 0) { #ifdef DEBUG fprintf(stderr, "WMS: bad SEEK_END: pos %jd, len %zd\n", (intmax_t)pos, ms->len); #endif errno = EINVAL; return (-1); } } else { if (FPOS_MAX - ms->len < pos) { #ifdef DEBUG fprintf(stderr, "WMS: bad SEEK_END: pos %jd, len %zd\n", (intmax_t)pos, ms->len); #endif errno = EOVERFLOW; return (-1); } } ms->offset = ms->len + pos; break; } /* Reset the multibyte state if a seek changes the position. */ if (ms->offset != old) memset(&ms->mbstate, 0, sizeof(ms->mbstate)); wmemstream_update(ms); #ifdef DEBUG fprintf(stderr, "WMS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos, whence, (intmax_t)old, (intmax_t)ms->offset); #endif return (ms->offset); } static int wmemstream_close(void *cookie) { free(cookie); return (0); } FILE * open_wmemstream(wchar_t **bufp, size_t *sizep) { struct wmemstream *ms; int save_errno; FILE *fp; if (bufp == NULL || sizep == NULL) { errno = EINVAL; return (NULL); } *bufp = calloc(1, sizeof(wchar_t)); if (*bufp == NULL) return (NULL); ms = malloc(sizeof(*ms)); if (ms == NULL) { save_errno = errno; free(*bufp); *bufp = NULL; errno = save_errno; return (NULL); } ms->bufp = bufp; ms->sizep = sizep; ms->len = 0; ms->offset = 0; memset(&ms->mbstate, 0, sizeof(mbstate_t)); wmemstream_update(ms); fp = funopen(ms, NULL, wmemstream_write, wmemstream_seek, wmemstream_close); if (fp == NULL) { save_errno = errno; free(ms); free(*bufp); *bufp = NULL; errno = save_errno; return (NULL); } fwide(fp, 1); return (fp); } Index: stable/10/lib/libc/sys/closefrom.2 =================================================================== --- stable/10/lib/libc/sys/closefrom.2 (revision 283926) +++ stable/10/lib/libc/sys/closefrom.2 (revision 283927) @@ -1,53 +1,53 @@ -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 12, 2009 .Dt CLOSEFROM 2 .Os .Sh NAME .Nm closefrom .Nd delete open file descriptors .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In unistd.h .Ft void .Fn closefrom "int lowfd" .Sh DESCRIPTION The .Fn closefrom system call deletes all open file descriptors greater than or equal to .Fa lowfd from the per-process object reference table. Any errors encountered while closing file descriptors are ignored. .Sh SEE ALSO .Xr close 2 .Sh HISTORY The .Fn closefrom function first appeared in .Fx 8.0 . Index: stable/10/lib/libc/sys/procctl.2 =================================================================== --- stable/10/lib/libc/sys/procctl.2 (revision 283926) +++ stable/10/lib/libc/sys/procctl.2 (revision 283927) @@ -1,436 +1,436 @@ -.\" Copyright (c) 2013 Advanced Computing Technologies LLC +.\" Copyright (c) 2013 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" All rights reserved. .\" .\" Copyright (c) 2014 The FreeBSD Foundation .\" Portions of this documentation were written by Konstantin Belousov .\" under sponsorship from the FreeBSD Foundation. .\" .\" 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$ .\" .Dd December 29, 2014 .Dt PROCCTL 2 .Os .Sh NAME .Nm procctl .Nd control processes .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In sys/procctl.h .Ft int .Fn procctl "idtype_t idtype" "id_t id" "int cmd" "void *arg" .Sh DESCRIPTION The .Fn procctl system call provides for control over processes. The .Fa idtype and .Fa id arguments specify the set of processes to control. If multiple processes match the identifier, .Nm will make a .Dq best effort to control as many of the selected processes as possible. An error is only returned if no selected processes successfully complete the request. The following identifier types are supported: .Bl -tag -width "Dv P_PGID" .It Dv P_PID Control the process with the process ID .Fa id . .It Dv P_PGID Control processes belonging to the process group with the ID .Fa id . .El .Pp The control request to perform is specified by the .Fa cmd argument. The following commands are supported: .Bl -tag -width "Dv PROC_REAP_GETPIDS" .It Dv PROC_SPROTECT Set process protection state. This is used to mark a process as protected from being killed if the system exhausts available memory and swap. The .Fa arg parameter must point to an integer containing an operation and zero or more optional flags. The following operations are supported: .Bl -tag -width "Dv PPROT_CLEAR" .It Dv PPROT_SET Mark the selected processes as protected. .It Dv PPROT_CLEAR Clear the protected state of selected processes. .El .Pp The following optional flags are supported: .Bl -tag -width "Dv PPROT_DESCE" .It Dv PPROT_DESCEND Apply the requested operation to all child processes of each selected process in addition to each selected process. .It Dv PPROT_INHERIT When used with .Dv PPROT_SET , mark all future child processes of each selected process as protected. Future child processes will also mark all of their future child processes. .El .It Dv PROC_REAP_ACQUIRE Acquires the reaper status for the current process. The status means that children orphaned by the reaper's descendants that were forked after the acquisition of the status are reparented to the reaper. After the system initialization, .Xr init 8 is the default reaper. .Pp .It Dv PROC_REAP_RELEASE Releases the reaper state for the current process. The reaper of the current process becomes the new reaper of the current process's descendants. .It Dv PROC_REAP_STATUS Provides the information about the reaper of the specified process, or the process itself when it is a reaper. The .Fa data argument must point to a .Vt procctl_reaper_status structure which is filled in by the syscall on successful return. .Bd -literal struct procctl_reaper_status { u_int rs_flags; u_int rs_children; u_int rs_descendants; pid_t rs_reaper; pid_t rs_pid; }; .Ed The .Fa rs_flags may have the following flags returned: .Bl -tag -width "Dv REAPER_STATUS_REALINIT" .It Dv REAPER_STATUS_OWNED The specified process has acquired the reaper status and has not released it. When the flag is returned, the specified process .Fa id , pid, identifies the reaper, otherwise the .Fa rs_reaper field of the structure is set to the pid of the reaper for the specified process id. .It Dv REAPER_STATUS_REALINIT The specified process is the root of the reaper tree, i.e. .Xr init 8 . .El The .Fa rs_children field returns the number of children of the reaper. The .Fa rs_descendants field returns the total number of descendants of the reaper(s), not counting descendants of the reaper in the subtree. The .Fa rs_reaper field returns the reaper pid. The .Fa rs_pid returns the pid of one reaper child if there are any descendants. .It Dv PROC_REAP_GETPIDS Queries the list of descendants of the reaper of the specified process. The request takes a pointer to a .Vt procctl_reaper_pids structure in the .Fa data parameter. .Bd -literal struct procctl_reaper_pids { u_int rp_count; struct procctl_reaper_pidinfo *rp_pids; }; .Ed When called, the .Fa rp_pids field must point to an array of .Vt procctl_reaper_pidinfo structures, to be filled in on return, and the .Fa rp_count field must specify the size of the array, into which no more than .Fa rp_count elements will be filled in by the kernel. .Pp The .Vt "struct procctl_reaper_pidinfo" structure provides some information about one of the reaper's descendants. Note that for a descendant that is not a child, it may be incorrectly identified because of a race in which the original child process exited and the exited process's pid was reused for an unrelated process. .Bd -literal struct procctl_reaper_pidinfo { pid_t pi_pid; pid_t pi_subtree; u_int pi_flags; }; .Ed The .Fa pi_pid field is the process id of the descendant. The .Fa pi_subtree field provides the pid of the child of the reaper, which is the (grand-)parent of the process. The .Fa pi_flags field returns the following flags, further describing the descendant: .Bl -tag -width "Dv REAPER_PIDINFO_VALID" .It Dv REAPER_PIDINFO_VALID Set to indicate that the .Vt procctl_reaper_pidinfo structure was filled in by the kernel. Zero-filling the .Fa rp_pids array and testing the .Dv REAPER_PIDINFO_VALID flag allows the caller to detect the end of the returned array. .It Dv REAPER_PIDINFO_CHILD The .Fa pi_pid field identifies the direct child of the reaper. .El .It Dv PROC_REAP_KILL Request to deliver a signal to some subset of the descendants of the reaper. The .Fa data parameter must point to a .Vt procctl_reaper_kill structure, which is used both for parameters and status return. .Bd -literal struct procctl_reaper_kill { int rk_sig; u_int rk_flags; pid_t rk_subtree; u_int rk_killed; pid_t rk_fpid; }; .Ed The .Fa rk_sig field specifies the signal to be delivered. Zero is not a valid signal number, unlike .Xr kill 2 . The .Fa rk_flags field further directs the operation. It is or-ed from the following flags: .Bl -tag -width "Dv REAPER_KILL_CHILDREN" .It Dv REAPER_KILL_CHILDREN Deliver the specified signal only to direct children of the reaper. .It Dv REAPER_KILL_SUBTREE Deliver the specified signal only to descendants that were forked by the direct child with pid specified in the .Fa rk_subtree field. .El If neither the .Dv REAPER_KILL_CHILDREN nor the .Dv REAPER_KILL_SUBTREE flags are specified, all current descendants of the reaper are signalled. .Pp If a signal was delivered to any process, the return value from the request is zero. In this case, the .Fa rk_killed field identifies the number of processes signalled. The .Fa rk_fpid field is set to the pid of the first process for which signal delivery failed, e.g. due to the permission problems. If no such process exist, the .Fa rk_fpid field is set to -1. .It Dv PROC_TRACE_CTL Enable or disable tracing of the specified process(es), according to the value of the integer argument. Tracing includes attachment to the process using .Xr ptrace 2 and .Xr ktrace 2 , debugging sysctls, .Xr hwpmc 4 , .Xr dtrace 1 and core dumping. Possible values for the .Fa data argument are: .Bl -tag -width "Dv PROC_TRACE_CTL_DISABLE_EXEC" .It Dv PROC_TRACE_CTL_ENABLE Enable tracing, after it was disabled by .Dv PROC_TRACE_CTL_DISABLE . Only allowed for self. .It Dv PROC_TRACE_CTL_DISABLE Disable tracing for the specified process. Tracing is re-enabled when the process changes the executing program with .Xr execve 2 syscall. A child inherits the trace settings from the parent on .Xr fork 2 . .It Dv PROC_TRACE_CTL_DISABLE_EXEC Same as .Dv PROC_TRACE_CTL_DISABLE , but the setting persist for the process even after .Xr execve 2 . .El .It Dv PROC_TRACE_STATUS Returns the current tracing status for the specified process in the integer variable pointed to by .Fa data . If tracing is disabled, .Fa data is set to -1. If tracing is enabled, but no debugger is attached by .Xr ptrace 2 syscall, .Fa data is set to 0. If a debugger is attached, .Fa data is set to the pid of the debugger process. .El .Sh NOTES Disabling tracing on a process should not be considered a security feature, as it is bypassable both by the kernel and privileged processes, and via other system mechanisms. As such, it should not be relied on to reliably protect cryptographic keying material or other confidential data. .Sh RETURN VALUES If an error occurs, a value of -1 is returned and .Va errno is set to indicate the error. .Sh ERRORS The .Fn procctl system call will fail if: .Bl -tag -width Er .It Bq Er EFAULT The .Fa arg parameter points outside the process's allocated address space. .It Bq Er EINVAL The .Fa cmd argument specifies an unsupported command. .Pp The .Fa idtype argument specifies an unsupported identifier type. .It Bq Er EPERM The calling process does not have permission to perform the requested operation on any of the selected processes. .It Bq Er ESRCH No processes matched the requested .Fa idtype and .Fa id . .It Bq Er EINVAL An invalid operation or flag was passed in .Fa arg for a .Dv PROC_SPROTECT command. .It Bq Er EPERM The .Fa idtype argument is not equal to .Dv P_PID , or .Fa id is not equal to the pid of the calling process, for .Dv PROC_REAP_ACQUIRE or .Dv PROC_REAP_RELEASE requests. .It Bq Er EINVAL Invalid or undefined flags were passed to a .Dv PROC_REAP_KILL request. .It Bq Er EINVAL An invalid or zero signal number was requested for a .Dv PROC_REAP_KILL request. .It Bq Er EINVAL The .Dv PROC_REAP_RELEASE request was issued by the .Xr init 8 process. .It Bq Er EBUSY The .Dv PROC_REAP_ACQUIRE request was issued by a process that had already acquired reaper status and has not yet released it. .It Bq Er EBUSY The .Dv PROC_TRACE_CTL request was issued for a process already being traced. .It Bq Er EPERM The .Dv PROC_TRACE_CTL request to re-enable tracing of the process ( .Dv PROC_TRACE_CTL_ENABLE ) , or to disable persistence of the .Dv PROC_TRACE_CTL_DISABLE on .Xr execve 2 was issued for a non-current process. .It Bq Er EINVAL The value of the integer .Fa data parameter for the .Dv PROC_TRACE_CTL request is invalid. .El .Sh SEE ALSO .Xr dtrace 1 , .Xr kill 2 , .Xr ktrace 2 , .Xr ptrace 2 , .Xr wait 2 , .Xr hwpmc 4 , .Xr init 8 .Sh HISTORY The .Fn procctl function appeared in .Fx 10.0 . The reaper facility is based on a similar feature of Linux and DragonflyBSD, and first appeared in .Fx 10.2 . Index: stable/10/share/man/man9/BUS_BIND_INTR.9 =================================================================== --- stable/10/share/man/man9/BUS_BIND_INTR.9 (revision 283926) +++ stable/10/share/man/man9/BUS_BIND_INTR.9 (revision 283927) @@ -1,98 +1,98 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 14, 2009 .Dt BUS_BIND_INTR 9 .Os .Sh NAME .Nm BUS_BIND_INTR , .Nm bus_bind_intr .Nd "bind an interrupt resource to a specific CPU" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft int .Fo BUS_BIND_INTR .Fa "device_t dev" "device_t child" "struct resource *irq" "int cpu" .Fc .Ft int .Fn bus_bind_intr "device_t dev" "struct resource *irq" "int cpu" .Sh DESCRIPTION The .Fn BUS_BIND_INTR method allows an interrupt resource to be pinned to a specific CPU. The interrupt resource must have an interrupt handler attached via .Xr BUS_SETUP_INTR 9 . The .Fa cpu parameter corresponds to the ID of a valid CPU in the system. Binding an interrupt restricts the .Xr cpuset 2 of any associated interrupt threads to only include the specified CPU. It may also direct the low-level interrupt handling of the interrupt to the specified CPU as well, but this behavior is platform-dependent. If the value .Dv NOCPU is used for .Fa cpu , then the interrupt will be .Dq unbound which restores any associated interrupt threads back to the default cpuset. .Pp Non-sleepable locks such as mutexes should not be held across calls to these functions. .Pp The .Fn bus_bind_intr function is a simple wrapper around .Fn BUS_BIND_INTR . .Pp Note that currently there is no attempt made to arbitrate between multiple bind requests for the same interrupt from either the same device or multiple devices. There is also no arbitration between interrupt binding requests submitted by userland via .Xr cpuset 2 and .Fn BUS_BIND_INTR . The most recent binding request is the one that will be in effect. .Sh RETURN VALUES Zero is returned on success, otherwise an appropriate error is returned. .Sh SEE ALSO .Xr BUS_SETUP_INTR 9 , .Xr cpuset 2 , .Xr device 9 .Sh HISTORY The .Fn BUS_BIND_INTR method and .Fn bus_bind_intr functions first appeared in .Fx 7.2 . Index: stable/10/share/man/man9/BUS_CHILD_DELETED.9 =================================================================== --- stable/10/share/man/man9/BUS_CHILD_DELETED.9 (revision 283926) +++ stable/10/share/man/man9/BUS_CHILD_DELETED.9 (revision 283927) @@ -1,55 +1,55 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2012 Advanced Computing Technologies LLC +.\" Copyright (c) 2012 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd August 21, 2012 .Dt BUS_CHILD_DELETED 9 .Os .Sh NAME .Nm BUS_CHILD_DELETED .Nd "notify a bus device that a child is being deleted" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn BUS_CHILD_DELETED "device_t dev" "device_t child" .Sh DESCRIPTION The .Fn BUS_CHILD_DELETED method is invoked by the new-bus framework when a device is deleted. A bus driver can provide an implementation of this method to release bus-specific resources associated with a device such as instance variables. .Sh SEE ALSO .Xr BUS_ADD_CHILD 9 , .Xr device 9 .Sh HISTORY The .Fn BUS_CHILD_DELETED method first appeared in .Fx 10.0 . Index: stable/10/share/man/man9/BUS_CHILD_DETACHED.9 =================================================================== --- stable/10/share/man/man9/BUS_CHILD_DETACHED.9 (revision 283926) +++ stable/10/share/man/man9/BUS_CHILD_DETACHED.9 (revision 283927) @@ -1,52 +1,52 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2012 Advanced Computing Technologies LLC +.\" Copyright (c) 2012 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd August 21, 2012 .Dt BUS_CHILD_DETACHED 9 .Os .Sh NAME .Nm BUS_CHILD_DETACHED .Nd "notify a bus device that a child was detached" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn BUS_CHILD_DETACHED "device_t dev" "device_t child" .Sh DESCRIPTION The .Fn BUS_CHILD_DETACHED method is invoked by the new-bus framework after a device is detached. A bus driver can provide an implementation of this method to reclaim any resources allocated on behalf of the child or to cleanup state not properly released by a .Xr DEVICE_DETACH 9 method. .Sh SEE ALSO .Xr device 9 , .Xr DEVICE_DETACH 9 Index: stable/10/share/man/man9/BUS_DESCRIBE_INTR.9 =================================================================== --- stable/10/share/man/man9/BUS_DESCRIBE_INTR.9 (revision 283926) +++ stable/10/share/man/man9/BUS_DESCRIBE_INTR.9 (revision 283927) @@ -1,104 +1,104 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 14, 2009 .Dt BUS_DESCRIBE_INTR 9 .Os .Sh NAME .Nm BUS_DESCRIBE_INTR , .Nm bus_describe_intr .Nd "associate a description with an active interrupt handler" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft int .Fo BUS_BIND_INTR .Fa "device_t dev" "device_t child" "struct resource *irq" "void *cookie" .Fa "const char *descr" .Fc .Ft int .Fo bus_describe_intr .Fa "device_t dev" "struct resource *irq" "void *cookie" "const char *fmt" .Fa ... .Fc .Sh DESCRIPTION The .Fn BUS_DESCRIBE_INTR method associates a description with an active interrupt handler. The .Fa cookie parameter must be the value returned by a successful call to .Xr BUS_SETUP_INTR 9 for the interrupt .Fa irq . .Pp The .Fn bus_describe_intr function is a simple wrapper around .Fn BUS_DESCRIBE_INTR . As a convenience, .Fn bus_describe_intr allows the caller to use .Xr printf 9 style formatting to build the description string using .Fa fmt . .Pp When an interrupt handler is established by .Xr BUS_SETUP_INTR 9 , the handler is named after the device the handler is established for. This name is then used in various places such as interrupt statistics displayed by .Xr systat 1 and .Xr vmstat 8 . For devices that use a single interrupt, the device name is sufficiently unique to identify the interrupt handler. However, for devices that use multiple interrupts it can be useful to distinguish the interrupt handlers. When a description is set for an active interrupt handler, a colon followed by the description is appended to the device name to form the interrupt handler name. .Sh RETURN VALUES Zero is returned on success, otherwise an appropriate error is returned. .Sh SEE ALSO .Xr BUS_SETUP_INTR 9 , .Xr systat 1 , .Xr vmstat 8 , .Xr device 9 , .Xr printf 9 .Sh HISTORY The .Fn BUS_DESCRIBE_INTR method and .Fn bus_describe_intr functions first appeared in .Fx 8.1 . .Sh BUGS It is not currently possible to remove a description from an active interrupt handler. Index: stable/10/share/man/man9/BUS_NEW_PASS.9 =================================================================== --- stable/10/share/man/man9/BUS_NEW_PASS.9 (revision 283926) +++ stable/10/share/man/man9/BUS_NEW_PASS.9 (revision 283927) @@ -1,56 +1,56 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 8, 2009 .Dt BUS_NEW_PASS 9 .Os .Sh NAME .Nm BUS_NEW_PASS .Nd "notify a bus that the pass level has been changed" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn BUS_NEW_PASS "device_t dev" .Sh DESCRIPTION The .Fn BUS_NEW_PASS method is called on each bus device to rescan the device tree when the pass level has been changed. This method is responsible for invoking .Xr BUS_NEW_PASS 9 on child bus devices to propagate the rescan to child devices. It is also responsible for reprobing any unattached child devices and allowing drivers for the current pass to identify new children. A default implementation is provided by .Xr bus_generic_new_pass 9 . .Sh SEE ALSO .Xr bus_generic_new_pass 9 , .Xr bus_set_pass 9 , .Xr device 9 Index: stable/10/share/man/man9/VOP_ADVISE.9 =================================================================== --- stable/10/share/man/man9/VOP_ADVISE.9 (revision 283926) +++ stable/10/share/man/man9/VOP_ADVISE.9 (revision 283927) @@ -1,88 +1,88 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2013 Advanced Computing Technologies LLC +.\" Copyright (c) 2013 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 3, 2013 .Dt VOP_ADVISE 9 .Os .Sh NAME .Nm VOP_ADVISE .Nd apply advice about use of file data .Sh SYNOPSIS .In sys/param.h .In sys/vnode.h .Ft int .Fn VOP_ADVISE "struct vnode *vp" "off_t start" "off_t end" "int advice" .Sh DESCRIPTION This call applies advice for a range of a file's data. It is used to implement the .Xr posix_fadvise system call. .Pp Its arguments are: .Bl -tag -width offset .It Fa vp The vnode of the file. .It Fa start The start of the range of file data. .It Fa end The end of the range of file data. .It Fa advice The type of operation to apply to the file data. Possible values are: .Bl -tag -width POSIX_FADV_WILLNEED .It Dv POSIX_FADV_WILLNEED Initiate an asynchronous read of the file data if it is not already resident. .It Dv POSIX_FADV_DONTNEED Decrease the in-memory priority of clean file data or discard clean file data. .El .El .Pp If the .Fa start and .Fa end offsets are both zero, then the operation should be applied to the entire file. Note that this call is advisory only and may perform the requested operation on a subset of the requested range .Pq including not performing it at all and still return success. .Sh LOCKS The file should be unlocked on entry. .Sh RETURN VALUES Zero is returned if the call is successful, otherwise an appropriate error code is returned. .Sh ERRORS .Bl -tag -width Er .It Bq Er EINVAL An invalid value was given for .Fa advice . .El .Sh SEE ALSO .Xr vnode 9 Index: stable/10/share/man/man9/VOP_ALLOCATE.9 =================================================================== --- stable/10/share/man/man9/VOP_ALLOCATE.9 (revision 283926) +++ stable/10/share/man/man9/VOP_ALLOCATE.9 (revision 283927) @@ -1,84 +1,84 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2013 Advanced Computing Technologies LLC +.\" Copyright (c) 2013 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 3, 2013 .Dt VOP_ALLOCATE 9 .Os .Sh NAME .Nm VOP_ALLOCATE .Nd allocate storage for a file .Sh SYNOPSIS .In sys/param.h .In sys/vnode.h .Ft int .Fn VOP_ALLOCATE "struct vnode *vp" "off_t *offset" "off_t *len" .Sh DESCRIPTION This call allocates storage for a range of offsets in a file. It is used to implement the .Xr posix_fallocate system call. .Pp Its arguments are: .Bl -tag -width offset .It Fa vp The vnode of the file. .It Fa offset The start of the range to allocate storage for in the file. .It Fa len The length of the range to allocate storage for in the file. .El .Pp The .Fa offset and .Fa len arguments are updated to reflect the portion of the range that still needs to be allocated on return. A partial allocation is considered a successful operation. The file's contents are not changed. .Sh LOCKS The file should be exclusively locked on entry and will still be locked on exit. .Sh RETURN VALUES Zero is returned if the call is successful, otherwise an appropriate error code is returned. .Sh ERRORS .Bl -tag -width Er .It Bq Er EFBIG An attempt was made to write a file that exceeds the process's file size limit or the maximum file size. .It Bq Er ENOSPC The file system is full. .It Bq Er EPERM An append-only flag is set on the file, but the caller is attempting to write before the current end of file. .El .Sh SEE ALSO .Xr vnode 9 , .Xr VOP_READ 9 , .Xr VOP_WRITE 9 Index: stable/10/share/man/man9/bus_adjust_resource.9 =================================================================== --- stable/10/share/man/man9/bus_adjust_resource.9 (revision 283926) +++ stable/10/share/man/man9/bus_adjust_resource.9 (revision 283927) @@ -1,101 +1,101 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2011 Advanced Computing Technologies LLC +.\" Copyright (c) 2011 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd April 29, 2011 .Dt BUS_ADJUST_RESOURCE 9 .Os .Sh NAME .Nm bus_adjust_resource .Nd adjust resource allocated from a parent bus .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Pp .In machine/bus.h .In sys/rman.h .In machine/resource.h .Ft int .Fn bus_adjust_resource "device_t dev" "int type" "struct resource *r" "u_long start" "u_long end" .Sh DESCRIPTION This function is used to ask the parent bus to adjust the resource range assigned to an allocated resource. The resource .Fa r should have been allocated by a previous call to .Xr bus_alloc_resource 9 . The new resource range must overlap the existing range of .Fa r . The .Fa type argument should match the .Fa type argument passed to .Xr bus_alloc_resource 9 when the resource was initially allocated. .Pp Note that none of the constraints of the original allocation request such as alignment or boundary restrictions are checked by .Fn bus_adjust_resource . It is the caller's responsibility to enforce any such requirements. .Sh RETURN VALUES The .Fn bus_adjust_resource method returns zero on success or an error code on failure. .Sh EXAMPLES Grow an existing memory resource by 4096 bytes. .Bd -literal struct resource *res; int error; error = bus_adjust_resource(dev, SYS_RES_MEMORY, res, rman_get_start(res), rman_get_end(res) + 0x1000); .Ed .Sh ERRORS .Fn bus_adjust_resource will fail if: .Bl -tag -width Er .It Bq Er EINVAL The .Fa dev device does not have a parent device. .It Bq Er EINVAL The .Fa r resource is a shared resource. .It Bq Er EINVAL The new address range does not overlap with the existing address range of .Fa r . .It Bq Er EBUSY The new address range conflicts with another allocated resource. .El .Sh SEE ALSO .Xr bus_alloc_resource 9 , .Xr bus_release_resource 9 , .Xr device 9 , .Xr driver 9 Index: stable/10/share/man/man9/bus_generic_new_pass.9 =================================================================== --- stable/10/share/man/man9/bus_generic_new_pass.9 (revision 283926) +++ stable/10/share/man/man9/bus_generic_new_pass.9 (revision 283927) @@ -1,57 +1,57 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 8, 2009 .Dt BUS_GENERIC_NEW_PASS 9 .Os .Sh NAME .Nm bus_generic_new_pass .Nd "generic implementation of BUS_NEW_PASS for bus devices" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn bus_generic_new_pass "device_t dev" .Sh DESCRIPTION This function provides an implementation of the .Xr BUS_NEW_PASS 9 method which can be used by bus drivers. It first invokes the .Xr DEVICE_IDENTIFY 9 method for any drivers whose pass level is equal to the new pass level. Then, for each attached child device it calls .Xr BUS_NEW_PASS 9 to rescan child busses, and for each unattached child device it calls .Xr device_probe_and_attach 9 . .Sh SEE ALSO .Xr BUS_NEW_PASS 9 , .Xr bus_set_pass 9 , .Xr device 9 , .Xr DEVICE_IDENTIFY 9 Index: stable/10/share/man/man9/bus_set_pass.9 =================================================================== --- stable/10/share/man/man9/bus_set_pass.9 (revision 283926) +++ stable/10/share/man/man9/bus_set_pass.9 (revision 283927) @@ -1,54 +1,54 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 8, 2009 .Dt BUS_SET_PASS 9 .Os .Sh NAME .Nm bus_set_pass .Nd "raise the bus pass level" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn bus_set_pass "int pass" .Sh DESCRIPTION The .Nm function is called during boot to raise the bus pass level to .Fa pass . The function will rescan the device tree for each pass level between the current pass level and the new level that has at least one associated driver. The device tree rescans are implemented by invoking the .Xr BUS_NEW_PASS 9 method on the root bus device. .Sh SEE ALSO .Xr BUS_NEW_PASS 9 , .Xr device 9 Index: stable/10/share/man/man9/refcount.9 =================================================================== --- stable/10/share/man/man9/refcount.9 (revision 283926) +++ stable/10/share/man/man9/refcount.9 (revision 283927) @@ -1,96 +1,96 @@ .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd January 20, 2009 .Dt REFCOUNT 9 .Os .Sh NAME .Nm refcount , .Nm refcount_init , .Nm refcount_acquire , .Nm refcount_release .Nd manage a simple reference counter .Sh SYNOPSIS .In sys/param.h .In sys/refcount.h .Ft void .Fn refcount_init "volatile u_int *count, u_int value" .Ft void .Fn refcount_acquire "volatile u_int *count" .Ft int .Fn refcount_release "volatile u_int *count" .Sh DESCRIPTION The .Nm functions provide an API to manage a simple reference counter. The caller provides the storage for the counter in an unsigned integer. A pointer to this integer is passed via .Fa count . Usually the counter is used to manage the lifetime of an object and is stored as a member of the object. .Pp The .Fn refcount_init function is used to set the initial value of the counter to .Fa value . It is normally used when creating a reference-counted object. .Pp The .Fn refcount_acquire function is used to acquire a new reference. The caller is responsible for ensuring that it holds a valid reference while obtaining a new reference. For example, if an object is stored on a list and the list holds a reference on the object, then holding a lock that protects the list provides sufficient protection for acquiring a new reference. .Pp The .Fn refcount_release function is used to release an existing reference. The function returns a non-zero value if the reference being released was the last reference; otherwise, it returns zero. .Pp Note that these routines do not provide any inter-CPU synchronization, data protection, or memory ordering guarantees except for managing the counter. The caller is responsible for any additional synchronization needed by consumers of any containing objects. In addition, the caller is also responsible for managing the life cycle of any containing objects including explicitly releasing any resources when the last reference is released. .Sh RETURN VALUES The .Nm refcount_release function returns non-zero when releasing the last reference and zero when releasing any other reference. .Sh HISTORY These functions were introduced in .Fx 6.0 . Index: stable/10/share/man/man9/sglist.9 =================================================================== --- stable/10/share/man/man9/sglist.9 (revision 283926) +++ stable/10/share/man/man9/sglist.9 (revision 283927) @@ -1,518 +1,518 @@ .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd January 12, 2014 .Dt SGLIST 9 .Os .Sh NAME .Nm sglist , .Nm sglist_alloc , .Nm sglist_append , .Nm sglist_append_bio , .Nm sglist_append_mbuf , .Nm sglist_append_phys , .Nm sglist_append_uio , .Nm sglist_append_user , .Nm sglist_build , .Nm sglist_clone , .Nm sglist_consume_uio , .Nm sglist_count , .Nm sglist_free , .Nm sglist_hold , .Nm sglist_init , .Nm sglist_join , .Nm sglist_length , .Nm sglist_reset , .Nm sglist_slice , .Nm sglist_split .Nd manage a scatter/gather list of physical memory addresses .Sh SYNOPSIS .In sys/types.h .In sys/sglist.h .Ft struct sglist * .Fn sglist_alloc "int nsegs" "int mflags" .Ft int .Fn sglist_append "struct sglist *sg" "void *buf" "size_t len" .Ft int .Fn sglist_append_bio "struct sglist *sg" "struct bio *bp" .Ft int .Fn sglist_append_mbuf "struct sglist *sg" "struct mbuf *m" .Ft int .Fn sglist_append_phys "struct sglist *sg" "vm_paddr_t paddr" "size_t len" .Ft int .Fn sglist_append_uio "struct sglist *sg" "struct uio *uio" .Ft int .Fn sglist_append_user "struct sglist *sg" "void *buf" "size_t len" "struct thread *td" .Ft struct sglist * .Fn sglist_build "void *buf" "size_t len" "int mflags" .Ft struct sglist * .Fn sglist_clone "struct sglist *sg" "int mflags" .Ft int .Fn sglist_consume_uio "struct sglist *sg" "struct uio *uio" "size_t resid" .Ft int .Fn sglist_count "void *buf" "size_t len" .Ft void .Fn sglist_free "struct sglist *sg" .Ft struct sglist * .Fn sglist_hold "struct sglist *sg" .Ft void .Fn sglist_init "struct sglist *sg" "int maxsegs" "struct sglist_seg *segs" .Ft int .Fn sglist_join "struct sglist *first" "struct sglist *second" .Ft size_t .Fn sglist_length "struct sglist *sg" .Ft void .Fn sglist_reset "struct sglist *sg" .Ft int .Fn sglist_slice "struct sglist *original" "struct sglist **slice" "size_t offset" "size_t length" "int mflags" .Ft int .Fn sglist_split "struct sglist *original" "struct sglist **head" "size_t length" "int mflags" .Sh DESCRIPTION The .Nm API manages physical address ranges. Each list contains one or more elements. Each element contains a starting physical address and a length. Scatter/gather lists are read-only while they are shared. If one wishes to alter an existing scatter/gather list and does not hold the sole reference to the list, then one should create a new list instead of modifying the existing list. .Pp Each scatter/gather list object contains a reference count. New lists are created with a single reference. New references are obtained by calling .Nm sglist_hold and are released by calling .Nm sglist_free . .Ss Allocating and Initializing Lists Each .Nm object consists of a header structure and a variable-length array of scatter/gather list elements. The .Nm sglist_alloc function allocates a new list that contains a header and .Fa nsegs scatter/gather list elements. The .Fa mflags argument can be set to either .Dv M_NOWAIT or .Dv M_WAITOK . .Pp The .Nm sglist_count function returns the number of scatter/gather list elements needed to describe the physical address ranges mapped by a single kernel virtual address range. The kernel virtual address range starts at .Fa buf and is .Fa len bytes long. .Pp The .Nm sglist_build function allocates a new scatter/gather list object that describes the physical address ranges mapped by a single kernel virtual address range. The kernel virtual address range starts at .Fa buf and is .Fa len bytes long. The .Fa mflags argument can be set to either .Dv M_NOWAIT or .Dv M_WAITOK . .Pp The .Nm sglist_clone function returns a copy of an existing scatter/gather list object .Fa sg . The .Fa mflags argument can be set to either .Dv M_NOWAIT or .Dv M_WAITOK . This can be used to obtain a private copy of a scatter/gather list before modifying it. .Pp The .Nm sglist_init function initializes a scatter/gather list header. The header is pointed to by .Fa sg and is initialized to manage an array of .Fa maxsegs scatter/gather list elements pointed to by .Fa segs . This can be used to initialize a scatter/gather list header whose storage is not provided by .Nm sglist_alloc . In that case, the caller should not call .Nm sglist_free to release its own reference and is responsible for ensuring all other references to the list are dropped before it releases the storage for .Fa sg and .Fa segs . .Ss Constructing Scatter/Gather Lists The .Nm API provides several routines for building a scatter/gather list to describe one or more objects. Specifically, the .Nm sglist_append family of routines can be used to append the physical address ranges described by an object to the end of a scatter/gather list. All of these routines return 0 on success or an error on failure. If a request to append an address range to a scatter/gather list fails, the scatter/gather list will remain unchanged. .Pp The .Nm sglist_append function appends the physical address ranges described by a single kernel virtual address range to the scatter/gather list .Fa sg . The kernel virtual address range starts at .Fa buf and is .Fa len bytes long. .Pp The .Nm sglist_append_bio function appends the physical address ranges described by a single bio .Fa bp to the scatter/gather list .Fa sg . .Pp The .Nm sglist_append_mbuf function appends the physical address ranges described by an entire mbuf chain .Fa m to the scatter/gather list .Fa sg . .Pp The .Nm sglist_append_phys function appends a single physical address range to the scatter/gather list .Fa sg . The physical address range starts at .Fa paddr and is .Fa len bytes long. .Pp The .Nm sglist_append_uio function appends the physical address ranges described by a .Xr uio 9 object to the scatter/gather list .Fa sg . Note that it is the caller's responsibility to ensure that the pages backing the I/O request are wired for the lifetime of .Fa sg . Note also that this routine does not modify .Fa uio . .Pp The .Nm sglist_append_user function appends the physical address ranges described by a single user virtual address range to the scatter/gather list .Fa sg . The user virtual address range is relative to the address space of the thread .Fa td . It starts at .Fa buf and is .Fa len bytes long. Note that it is the caller's responsibility to ensure that the pages backing the user buffer are wired for the lifetime of .Fa sg . .Pp The .Nm sglist_consume_uio function is a variation of .Nm sglist_append_uio . As with .Nm sglist_append_uio , it appends the physical address ranges described by .Fa uio to the scatter/gather list .Fa sg . Unlike .Nm sglist_append_uio , however, .Nm sglist_consume_uio modifies the I/O request to indicate that the appended address ranges have been processed similar to calling .Xr uiomove 9 . This routine will only append ranges that describe up to .Fa resid total bytes in length. If the available segments in the scatter/gather list are exhausted before .Fa resid bytes are processed, then the .Fa uio structure will be updated to reflect the actual number of bytes processed, and .Nm sglist_consume_io will return zero to indicate success. In effect, this function will perform partial reads or writes. The caller can compare the .Fa uio_resid member of .Fa uio before and after calling .Nm sglist_consume_uio to determine the actual number of bytes processed. .Ss Manipulating Scatter/Gather Lists The .Nm sglist_join function appends physical address ranges from the scatter/gather list .Fa second onto .Fa first and then resets .Fa second to an empty list. It returns zero on success or an error on failure. .Pp The .Nm sglist_split function splits an existing scatter/gather list into two lists. The first .Fa length bytes described by the list .Fa original are moved to a new list .Fa *head . If .Fa original describes a total address range that is smaller than .Fa length bytes, then all of the address ranges will be moved to the new list at .Fa *head and .Fa original will be an empty list. The caller may supply an existing scatter/gather list in .Fa *head . If so, the list must be empty. Otherwise, the caller may set .Fa *head to .Dv NULL in which case a new scatter/gather list will be allocated. In that case, .Fa mflags may be set to either .Dv M_NOWAIT or .Dv M_WAITOK . Note that since the .Fa original list is modified by this call, it must be a private list with no other references. The .Nm sglist_split function returns zero on success or an error on failure. .Pp The .Nm sglist_slice function generates a new scatter/gather list from a sub-range of an existing scatter/gather list .Fa original . The sub-range to extract is specified by the .Fa offset and .Fa length parameters. The new scatter/gather list is stored in .Fa *slice . As with .Fa head for .Nm sglist_join , the caller may either provide an empty scatter/gather list, or it may set .Fa *slice to .Dv NULL in which case .Nm sglist_slice will allocate a new list subject to .Fa mflags . Unlike .Nm sglist_split , .Nm sglist_slice does not modify .Fa original and does not require it to be a private list. The .Nm sglist_split function returns zero on success or an error on failure. .Ss Miscellaneous Routines The .Nm sglist_reset function clears the scatter/gather list .Fa sg so that it no longer maps any address ranges. This can allow reuse of a single scatter/gather list object for multiple requests. .Pp The .Nm sglist_length function returns the total length of the physical address ranges described by the scatter/gather list .Fa sg . .Sh RETURN VALUES The .Nm sglist_alloc , .Nm sglist_build , and .Nm sglist_clone functions return a new scatter/gather list on success or .Dv NULL on failure. .Pp The .Nm sglist_append family of functions and the .Nm sglist_consume_uio , .Nm sglist_join , .Nm sglist_slice , and .Nm sglist_split functions return zero on success or an error on failure. .Pp The .Nm sglist_count function returns a count of scatter/gather list elements. .Pp The .Nm sglist_length function returns a count of address space described by a scatter/gather list in bytes. .Sh ERRORS The .Nm sglist_append functions return the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The scatter/gather list has zero segments. .It Bq Er EFBIG There are not enough available segments in the scatter/gather list to append the specified physical address ranges. .El .Pp The .Nm sglist_consume_uio function returns the following error on failure: .Bl -tag -width Er .It Bq Er EINVAL The scatter/gather list has zero segments. .El .Pp The .Nm sglist_join function returns the following error on failure: .Bl -tag -width Er .It Bq Er EFBIG There are not enough available segments in the scatter/gather list .Fa first to append the physical address ranges from .Fa second . .El .Pp The .Nm sglist_slice function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The .Fa original scatter/gather list does not describe enough address space to cover the requested sub-range. .It Bq Er EINVAL The caller-supplied scatter/gather list in .Fa *slice is not empty. .It Bq Er ENOMEM An attempt to allocate a new scatter/gather list with .Dv M_NOWAIT set in .Fa mflags failed. .It Bq Er EFBIG There are not enough available segments in the caller-supplied scatter/gather list in .Fa *slice to describe the requested physical address ranges. .El .Pp The .Nm sglist_split function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EDOOFUS The .Fa original scatter/gather list has more than one reference. .It Bq Er EINVAL The caller-supplied scatter/gather list in .Fa *head is not empty. .It Bq Er ENOMEM An attempt to allocate a new scatter/gather list with .Dv M_NOWAIT set in .Fa mflags failed. .It Bq Er EFBIG There are not enough available segments in the caller-supplied scatter/gather list in .Fa *head to describe the requested physical address ranges. .El .Sh SEE ALSO .Xr g_bio 9 , .Xr malloc 9 , .Xr mbuf 9 , .Xr uio 9 .Sh HISTORY This API was first introduced in .Fx 8.0 . Index: stable/10/share/man/man9/shm_map.9 =================================================================== --- stable/10/share/man/man9/shm_map.9 (revision 283926) +++ stable/10/share/man/man9/shm_map.9 (revision 283927) @@ -1,186 +1,186 @@ .\" -.\" Copyright (c) 2011 Advanced Computing Technologies LLC +.\" Copyright (c) 2011 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd December 14, 2011 .Dt SHM_MAP 9 .Os .Sh NAME .Nm shm_map , shm_unmap .Nd "map shared memory objects into the kernel's address space" .Sh SYNOPSIS .In sys/types.h .In sys/mman.h .Ft int .Fn shm_map "struct file *fp" "size_t size" "off_t offset" "void **memp" .Ft int .Fn shm_unmap "struct file *fp" "void *mem" "size_t size" .Sh DESCRIPTION The .Fn shm_map and .Fn shm_unmap functions provide an API for mapping shared memory objects into the kernel. Shared memory objects are created by .Xr shm_open 2 . These objects can then be passed into the kernel via file descriptors. .Pp A shared memory object cannot be shrunk while it is mapped into the kernel. This is to avoid invalidating any pages that may be wired into the kernel's address space. Shared memory objects can still be grown while mapped into the kernel. .Pp To simplify the accounting needed to enforce the above requirement, callers of this API are required to unmap the entire region mapped by .Fn shm_map when calling .Fn shm_unmap . Unmapping only a portion of the region is not permitted. .Pp The .Fn shm_map function locates the shared memory object associated with the open file .Fa fp . It maps the region of that object described by .Fa offset and .Fa size into the kernel's address space. If it succeeds, .Fa *memp will be set to the start of the mapping. All pages for the range will be wired into memory upon successful return. .Pp The .Fn shm_unmap function unmaps a region previously mapped by .Fn shm_map . The .Fa mem argument should match the value previously returned in .Fa *memp , and the .Fa size argument should match the value passed to .Fn shm_map . .Pp Note that .Fn shm_map will not hold an extra reference on the open file .Fa fp for the lifetime of the mapping. Instead, the calling code is required to do this if it wishes to use .Fn shm_unmap on the region in the future. .Sh RETURN VALUES The .Fn shm_map and .Fn shm_unmap functions return zero on success or an error on failure. .Sh EXAMPLES The following function accepts a file descriptor for a shared memory object. It maps the first sixteen kilobytes of the object into the kernel, performs some work on that address, and then unmaps the address before returning. .Bd -literal -offset indent int shm_example(int fd) { struct file *fp; void *mem; int error; error = fget(curthread, fd, CAP_MMAP, &fp); if (error) return (error); error = shm_map(fp, 16384, 0, &mem); if (error) { fdrop(fp, curthread); return (error); } /* Do something with 'mem'. */ error = shm_unmap(fp, mem, 16384); fdrop(fp, curthread); return (error); } .Ed .Sh ERRORS The .Fn shm_map function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The open file .Fa fp is not a shared memory object. .It Bq Er EINVAL The requested region described by .Fa offset and .Fa size extends beyond the end of the shared memory object. .It Bq Er ENOMEM Insufficient address space was available. .It Bq Er EACCES The shared memory object could not be mapped due to a protection error. .It Bq Er EINVAL The shared memory object could not be mapped due to some other VM error. .El .Pp The .Fn shm_unmap function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The open file .Fa fp is not a shared memory object. .It Bq Er EINVAL The address range described by .Fa mem and .Fa size is not a valid address range. .It Bq Er EINVAL The address range described by .Fa mem and .Fa size is not backed by the shared memory object associated with the open file .Fa fp , or the address range does not cover the entire mapping of the object. .El .Sh SEE ALSO .Xr shm_open 2 .Sh HISTORY This API was first introduced in .Fx 10.0 . Index: stable/10/sys/amd64/include/vm.h =================================================================== --- stable/10/sys/amd64/include/vm.h (revision 283926) +++ stable/10/sys/amd64/include/vm.h (revision 283927) @@ -1,45 +1,45 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _MACHINE_VM_H_ #define _MACHINE_VM_H_ #include /* Memory attributes. */ #define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHEABLE) #define VM_MEMATTR_WRITE_COMBINING ((vm_memattr_t)PAT_WRITE_COMBINING) #define VM_MEMATTR_WRITE_THROUGH ((vm_memattr_t)PAT_WRITE_THROUGH) #define VM_MEMATTR_WRITE_PROTECTED ((vm_memattr_t)PAT_WRITE_PROTECTED) #define VM_MEMATTR_WRITE_BACK ((vm_memattr_t)PAT_WRITE_BACK) #define VM_MEMATTR_WEAK_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHED) #define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK #endif /* !_MACHINE_VM_H_ */ Index: stable/10/sys/boot/i386/common/edd.h =================================================================== --- stable/10/sys/boot/i386/common/edd.h (revision 283926) +++ stable/10/sys/boot/i386/common/edd.h (revision 283927) @@ -1,110 +1,110 @@ /*- - * Copyright (c) 2011 Advanced Computing Technologies LLC + * Copyright (c) 2011 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _EDD_H_ #define _EDD_H_ /* Supported interfaces for "Check Extensions Present". */ #define EDD_INTERFACE_FIXED_DISK 0x01 #define EDD_INTERFACE_EJECT 0x02 #define EDD_INTERFACE_EDD 0x04 struct edd_packet { uint16_t len; uint16_t count; uint16_t off; uint16_t seg; uint64_t lba; }; struct edd_packet_v3 { uint16_t len; uint16_t count; uint16_t off; uint16_t seg; uint64_t lba; uint64_t phys_addr; }; struct edd_params { uint16_t len; uint16_t flags; uint32_t cylinders; uint32_t heads; uint32_t sectors_per_track; uint64_t sectors; uint16_t sector_size; uint16_t edd_params_seg; uint16_t edd_params_off; } __packed; struct edd_device_path_v3 { uint16_t key; uint8_t len; uint8_t reserved[3]; char host_bus[4]; char interface[8]; uint64_t interface_path; uint64_t device_path; uint8_t reserved2[1]; uint8_t checksum; } __packed; struct edd_params_v3 { struct edd_params params; struct edd_device_path_v3 device_path; } __packed; struct edd_device_path_v4 { uint16_t key; uint8_t len; uint8_t reserved[3]; char host_bus[4]; char interface[8]; uint64_t interface_path; uint64_t device_path[2]; uint8_t reserved2[1]; uint8_t checksum; } __packed; struct edd_params_v4 { struct edd_params params; struct edd_device_path_v4 device_path; } __packed; #define EDD_FLAGS_DMA_BOUNDARY_HANDLING 0x0001 #define EDD_FLAGS_REMOVABLE_MEDIA 0x0002 #define EDD_FLAGS_WRITE_VERIFY 0x0004 #define EDD_FLAGS_MEDIA_CHANGE_NOTIFICATION 0x0008 #define EDD_FLAGS_LOCKABLE_MEDIA 0x0010 #define EDD_FLAGS_NO_MEDIA_PRESENT 0x0020 #define EDD_DEVICE_PATH_KEY 0xbedd #endif /* !_EDD_H_ */ Index: stable/10/sys/dev/pci/pci_subr.c =================================================================== --- stable/10/sys/dev/pci/pci_subr.c (revision 283926) +++ stable/10/sys/dev/pci/pci_subr.c (revision 283927) @@ -1,384 +1,384 @@ /*- - * Copyright (c) 2011 Advanced Computing Technologies LLC + * Copyright (c) 2011 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); /* * Support APIs for Host to PCI bridge drivers and drivers that * provide PCI domains. */ #include #include #include #include #include #include #include #include /* * Try to read the bus number of a host-PCI bridge using appropriate config * registers. */ int host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, uint8_t *busnum) { uint32_t id; id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); if (id == 0xffffffff) return (0); switch (id) { case 0x12258086: /* Intel 824?? */ /* XXX This is a guess */ /* *busnum = read_config(bus, slot, func, 0x41, 1); */ *busnum = bus; break; case 0x84c48086: /* Intel 82454KX/GX (Orion) */ *busnum = read_config(bus, slot, func, 0x4a, 1); break; case 0x84ca8086: /* * For the 450nx chipset, there is a whole bundle of * things pretending to be host bridges. The MIOC will * be seen first and isn't really a pci bridge (the * actual busses are attached to the PXB's). We need to * read the registers of the MIOC to figure out the * bus numbers for the PXB channels. * * Since the MIOC doesn't have a pci bus attached, we * pretend it wasn't there. */ return (0); case 0x84cb8086: switch (slot) { case 0x12: /* Intel 82454NX PXB#0, Bus#A */ *busnum = read_config(bus, 0x10, func, 0xd0, 1); break; case 0x13: /* Intel 82454NX PXB#0, Bus#B */ *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; break; case 0x14: /* Intel 82454NX PXB#1, Bus#A */ *busnum = read_config(bus, 0x10, func, 0xd3, 1); break; case 0x15: /* Intel 82454NX PXB#1, Bus#B */ *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; break; } break; /* ServerWorks -- vendor 0x1166 */ case 0x00051166: case 0x00061166: case 0x00081166: case 0x00091166: case 0x00101166: case 0x00111166: case 0x00171166: case 0x01011166: case 0x010f1014: case 0x01101166: case 0x02011166: case 0x02251166: case 0x03021014: *busnum = read_config(bus, slot, func, 0x44, 1); break; /* Compaq/HP -- vendor 0x0e11 */ case 0x60100e11: *busnum = read_config(bus, slot, func, 0xc8, 1); break; default: /* Don't know how to read bus number. */ return 0; } return 1; } #ifdef NEW_PCIB /* * Return a pointer to a pretty name for a PCI device. If the device * has a driver attached, the device's name is used, otherwise a name * is generated from the device's PCI address. */ const char * pcib_child_name(device_t child) { static char buf[64]; if (device_get_nameunit(child) != NULL) return (device_get_nameunit(child)); snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child), pci_get_bus(child), pci_get_slot(child), pci_get_function(child)); return (buf); } /* * Some Host-PCI bridge drivers know which resource ranges they can * decode and should only allocate subranges to child PCI devices. * This API provides a way to manage this. The bridge drive should * initialize this structure during attach and call * pcib_host_res_decodes() on each resource range it decodes. It can * then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper * routines for BUS_ALLOC_RESOURCE() and BUS_ADJUST_RESOURCE(). This * API assumes that resources for any decoded ranges can be safely * allocated from the parent via bus_generic_alloc_resource(). */ int pcib_host_res_init(device_t pcib, struct pcib_host_resources *hr) { hr->hr_pcib = pcib; resource_list_init(&hr->hr_rl); return (0); } int pcib_host_res_free(device_t pcib, struct pcib_host_resources *hr) { resource_list_free(&hr->hr_rl); return (0); } int pcib_host_res_decodes(struct pcib_host_resources *hr, int type, u_long start, u_long end, u_int flags) { struct resource_list_entry *rle; int rid; if (bootverbose) device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n", type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start, end); rid = resource_list_add_next(&hr->hr_rl, type, start, end, end - start + 1); if (flags & RF_PREFETCHABLE) { KASSERT(type == SYS_RES_MEMORY, ("only memory is prefetchable")); rle = resource_list_find(&hr->hr_rl, type, rid); rle->flags = RLE_PREFETCH; } return (0); } struct resource * pcib_host_res_alloc(struct pcib_host_resources *hr, device_t dev, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct resource_list_entry *rle; struct resource *r; u_long new_start, new_end; if (flags & RF_PREFETCHABLE) KASSERT(type == SYS_RES_MEMORY, ("only memory is prefetchable")); rle = resource_list_find(&hr->hr_rl, type, 0); if (rle == NULL) { /* * No decoding ranges for this resource type, just pass * the request up to the parent. */ return (bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, start, end, count, flags)); } restart: /* Try to allocate from each decoded range. */ for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { if (rle->type != type) continue; if (((flags & RF_PREFETCHABLE) != 0) != ((rle->flags & RLE_PREFETCH) != 0)) continue; new_start = ulmax(start, rle->start); new_end = ulmin(end, rle->end); if (new_start > new_end || new_start + count - 1 > new_end || new_start + count < new_start) continue; r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, new_start, new_end, count, flags); if (r != NULL) { if (bootverbose) device_printf(hr->hr_pcib, "allocated type %d (%#lx-%#lx) for rid %x of %s\n", type, rman_get_start(r), rman_get_end(r), *rid, pcib_child_name(dev)); return (r); } } /* * If we failed to find a prefetch range for a memory * resource, try again without prefetch. */ if (flags & RF_PREFETCHABLE) { flags &= ~RF_PREFETCHABLE; rle = resource_list_find(&hr->hr_rl, type, 0); goto restart; } return (NULL); } int pcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type, struct resource *r, u_long start, u_long end) { struct resource_list_entry *rle; rle = resource_list_find(&hr->hr_rl, type, 0); if (rle == NULL) { /* * No decoding ranges for this resource type, just pass * the request up to the parent. */ return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r, start, end)); } /* Only allow adjustments that stay within a decoded range. */ for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { if (rle->start <= start && rle->end >= end) return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r, start, end)); } return (ERANGE); } #ifdef PCI_RES_BUS struct pci_domain { int pd_domain; struct rman pd_bus_rman; TAILQ_ENTRY(pci_domain) pd_link; }; static TAILQ_HEAD(, pci_domain) domains = TAILQ_HEAD_INITIALIZER(domains); /* * Each PCI domain maintains its own resource manager for PCI bus * numbers in that domain. Domain objects are created on first use. * Host to PCI bridge drivers and PCI-PCI bridge drivers should * allocate their bus ranges from their domain. */ static struct pci_domain * pci_find_domain(int domain) { struct pci_domain *d; char buf[64]; int error; TAILQ_FOREACH(d, &domains, pd_link) { if (d->pd_domain == domain) return (d); } snprintf(buf, sizeof(buf), "PCI domain %d bus numbers", domain); d = malloc(sizeof(*d) + strlen(buf) + 1, M_DEVBUF, M_WAITOK | M_ZERO); d->pd_domain = domain; d->pd_bus_rman.rm_start = 0; d->pd_bus_rman.rm_end = PCI_BUSMAX; d->pd_bus_rman.rm_type = RMAN_ARRAY; strcpy((char *)(d + 1), buf); d->pd_bus_rman.rm_descr = (char *)(d + 1); error = rman_init(&d->pd_bus_rman); if (error == 0) error = rman_manage_region(&d->pd_bus_rman, 0, PCI_BUSMAX); if (error) panic("Failed to initialize PCI domain %d rman", domain); TAILQ_INSERT_TAIL(&domains, d, pd_link); return (d); } struct resource * pci_domain_alloc_bus(int domain, device_t dev, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct pci_domain *d; struct resource *res; if (domain < 0 || domain > PCI_DOMAINMAX) return (NULL); d = pci_find_domain(domain); res = rman_reserve_resource(&d->pd_bus_rman, start, end, count, flags, dev); if (res == NULL) return (NULL); rman_set_rid(res, *rid); return (res); } int pci_domain_adjust_bus(int domain, device_t dev, struct resource *r, u_long start, u_long end) { #ifdef INVARIANTS struct pci_domain *d; #endif if (domain < 0 || domain > PCI_DOMAINMAX) return (EINVAL); #ifdef INVARIANTS d = pci_find_domain(domain); KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource")); #endif return (rman_adjust_resource(r, start, end)); } int pci_domain_release_bus(int domain, device_t dev, int rid, struct resource *r) { #ifdef INVARIANTS struct pci_domain *d; #endif if (domain < 0 || domain > PCI_DOMAINMAX) return (EINVAL); #ifdef INVARIANTS d = pci_find_domain(domain); KASSERT(rman_is_region_manager(r, &d->pd_bus_rman), ("bad resource")); #endif return (rman_release_resource(r)); } #endif /* PCI_RES_BUS */ #endif /* NEW_PCIB */ Index: stable/10/sys/i386/include/vm.h =================================================================== --- stable/10/sys/i386/include/vm.h (revision 283926) +++ stable/10/sys/i386/include/vm.h (revision 283927) @@ -1,45 +1,45 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _MACHINE_VM_H_ #define _MACHINE_VM_H_ #include /* Memory attributes. */ #define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHEABLE) #define VM_MEMATTR_WRITE_COMBINING ((vm_memattr_t)PAT_WRITE_COMBINING) #define VM_MEMATTR_WRITE_THROUGH ((vm_memattr_t)PAT_WRITE_THROUGH) #define VM_MEMATTR_WRITE_PROTECTED ((vm_memattr_t)PAT_WRITE_PROTECTED) #define VM_MEMATTR_WRITE_BACK ((vm_memattr_t)PAT_WRITE_BACK) #define VM_MEMATTR_WEAK_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHED) #define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK #endif /* !_MACHINE_VM_H_ */ Index: stable/10/sys/sys/procctl.h =================================================================== --- stable/10/sys/sys/procctl.h (revision 283926) +++ stable/10/sys/sys/procctl.h (revision 283927) @@ -1,112 +1,112 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _SYS_PROCCTL_H_ #define _SYS_PROCCTL_H_ #ifndef _KERNEL #include #include #endif #define PROC_SPROTECT 1 /* set protected state */ #define PROC_REAP_ACQUIRE 2 /* reaping enable */ #define PROC_REAP_RELEASE 3 /* reaping disable */ #define PROC_REAP_STATUS 4 /* reaping status */ #define PROC_REAP_GETPIDS 5 /* get descendants */ #define PROC_REAP_KILL 6 /* kill descendants */ #define PROC_TRACE_CTL 7 /* en/dis ptrace and coredumps */ #define PROC_TRACE_STATUS 8 /* query tracing status */ /* Operations for PROC_SPROTECT (passed in integer arg). */ #define PPROT_OP(x) ((x) & 0xf) #define PPROT_SET 1 #define PPROT_CLEAR 2 /* Flags for PROC_SPROTECT (ORed in with operation). */ #define PPROT_FLAGS(x) ((x) & ~0xf) #define PPROT_DESCEND 0x10 #define PPROT_INHERIT 0x20 /* Result of PREAP_STATUS (returned by value). */ struct procctl_reaper_status { u_int rs_flags; u_int rs_children; u_int rs_descendants; pid_t rs_reaper; pid_t rs_pid; u_int rs_pad0[15]; }; /* struct procctl_reaper_status rs_flags */ #define REAPER_STATUS_OWNED 0x00000001 #define REAPER_STATUS_REALINIT 0x00000002 struct procctl_reaper_pidinfo { pid_t pi_pid; pid_t pi_subtree; u_int pi_flags; u_int pi_pad0[15]; }; #define REAPER_PIDINFO_VALID 0x00000001 #define REAPER_PIDINFO_CHILD 0x00000002 struct procctl_reaper_pids { u_int rp_count; u_int rp_pad0[15]; struct procctl_reaper_pidinfo *rp_pids; }; struct procctl_reaper_kill { int rk_sig; /* in - signal to send */ u_int rk_flags; /* in - REAPER_KILL flags */ pid_t rk_subtree; /* in - subtree, if REAPER_KILL_SUBTREE */ u_int rk_killed; /* out - count of processes sucessfully killed */ pid_t rk_fpid; /* out - first failed pid for which error is returned */ u_int rk_pad0[15]; }; #define REAPER_KILL_CHILDREN 0x00000001 #define REAPER_KILL_SUBTREE 0x00000002 #define PROC_TRACE_CTL_ENABLE 1 #define PROC_TRACE_CTL_DISABLE 2 #define PROC_TRACE_CTL_DISABLE_EXEC 3 #ifndef _KERNEL __BEGIN_DECLS int procctl(idtype_t, id_t, int, void *); __END_DECLS #endif #endif /* !_SYS_PROCCTL_H_ */ Index: stable/10/sys/vm/sg_pager.c =================================================================== --- stable/10/sys/vm/sg_pager.c (revision 283926) +++ stable/10/sys/vm/sg_pager.c (revision 283927) @@ -1,220 +1,220 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); /* * This pager manages OBJT_SG objects. These objects are backed by * a scatter/gather list of physical address ranges. */ #include #include #include #include #include #include #include #include #include #include #include #include static vm_object_t sg_pager_alloc(void *, vm_ooffset_t, vm_prot_t, vm_ooffset_t, struct ucred *); static void sg_pager_dealloc(vm_object_t); static int sg_pager_getpages(vm_object_t, vm_page_t *, int, int); static void sg_pager_putpages(vm_object_t, vm_page_t *, int, boolean_t, int *); static boolean_t sg_pager_haspage(vm_object_t, vm_pindex_t, int *, int *); struct pagerops sgpagerops = { .pgo_alloc = sg_pager_alloc, .pgo_dealloc = sg_pager_dealloc, .pgo_getpages = sg_pager_getpages, .pgo_putpages = sg_pager_putpages, .pgo_haspage = sg_pager_haspage, }; static vm_object_t sg_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff, struct ucred *cred) { struct sglist *sg; vm_object_t object; vm_pindex_t npages, pindex; int i; /* * Offset should be page aligned. */ if (foff & PAGE_MASK) return (NULL); /* * The scatter/gather list must only include page-aligned * ranges. */ npages = 0; sg = handle; for (i = 0; i < sg->sg_nseg; i++) { if ((sg->sg_segs[i].ss_paddr % PAGE_SIZE) != 0 || (sg->sg_segs[i].ss_len % PAGE_SIZE) != 0) return (NULL); npages += sg->sg_segs[i].ss_len / PAGE_SIZE; } /* * The scatter/gather list has a fixed size. Refuse requests * to map beyond that. */ size = round_page(size); pindex = OFF_TO_IDX(foff + size); if (pindex > npages) return (NULL); /* * Allocate a new object and associate it with the * scatter/gather list. It is ok for our purposes to have * multiple VM objects associated with the same scatter/gather * list because scatter/gather lists are static. This is also * simpler than ensuring a unique object per scatter/gather * list. */ object = vm_object_allocate(OBJT_SG, npages); object->handle = sglist_hold(sg); TAILQ_INIT(&object->un_pager.sgp.sgp_pglist); return (object); } static void sg_pager_dealloc(vm_object_t object) { struct sglist *sg; vm_page_t m; /* * Free up our fake pages. */ while ((m = TAILQ_FIRST(&object->un_pager.sgp.sgp_pglist)) != 0) { TAILQ_REMOVE(&object->un_pager.sgp.sgp_pglist, m, plinks.q); vm_page_putfake(m); } sg = object->handle; sglist_free(sg); } static int sg_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) { struct sglist *sg; vm_page_t m_paddr, page; vm_pindex_t offset; vm_paddr_t paddr; vm_memattr_t memattr; size_t space; int i; VM_OBJECT_ASSERT_WLOCKED(object); sg = object->handle; memattr = object->memattr; VM_OBJECT_WUNLOCK(object); offset = m[reqpage]->pindex; /* * Lookup the physical address of the requested page. An initial * value of '1' instead of '0' is used so we can assert that the * page is found since '0' can be a valid page-aligned physical * address. */ space = 0; paddr = 1; for (i = 0; i < sg->sg_nseg; i++) { if (space + sg->sg_segs[i].ss_len <= (offset * PAGE_SIZE)) { space += sg->sg_segs[i].ss_len; continue; } paddr = sg->sg_segs[i].ss_paddr + offset * PAGE_SIZE - space; break; } KASSERT(paddr != 1, ("invalid SG page index")); /* If "paddr" is a real page, perform a sanity check on "memattr". */ if ((m_paddr = vm_phys_paddr_to_vm_page(paddr)) != NULL && pmap_page_get_memattr(m_paddr) != memattr) { memattr = pmap_page_get_memattr(m_paddr); printf( "WARNING: A device driver has set \"memattr\" inconsistently.\n"); } /* Return a fake page for the requested page. */ KASSERT(!(m[reqpage]->flags & PG_FICTITIOUS), ("backing page for SG is fake")); /* Construct a new fake page. */ page = vm_page_getfake(paddr, memattr); VM_OBJECT_WLOCK(object); TAILQ_INSERT_TAIL(&object->un_pager.sgp.sgp_pglist, page, plinks.q); /* Free the original pages and insert this fake page into the object. */ for (i = 0; i < count; i++) { if (i == reqpage && vm_page_replace(page, object, offset) != m[i]) panic("sg_pager_getpages: invalid place replacement"); vm_page_lock(m[i]); vm_page_free(m[i]); vm_page_unlock(m[i]); } m[reqpage] = page; page->valid = VM_PAGE_BITS_ALL; return (VM_PAGER_OK); } static void sg_pager_putpages(vm_object_t object, vm_page_t *m, int count, boolean_t sync, int *rtvals) { panic("sg_pager_putpage called"); } static boolean_t sg_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before, int *after) { if (before != NULL) *before = 0; if (after != NULL) *after = 0; return (TRUE); } Index: stable/10/sys/x86/acpica/srat.c =================================================================== --- stable/10/sys/x86/acpica/srat.c (revision 283926) +++ stable/10/sys/x86/acpica/srat.c (revision 283927) @@ -1,391 +1,391 @@ /*- - * Copyright (c) 2010 Advanced Computing Technologies LLC + * Copyright (c) 2010 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if MAXMEMDOM > 1 struct cpu_info { int enabled:1; int has_memory:1; int domain; } cpus[MAX_APIC_ID + 1]; struct mem_affinity mem_info[VM_PHYSSEG_MAX + 1]; int num_mem; static ACPI_TABLE_SRAT *srat; static vm_paddr_t srat_physaddr; static int vm_domains[VM_PHYSSEG_MAX]; static void srat_walk_table(acpi_subtable_handler *handler, void *arg); /* * Returns true if a memory range overlaps with at least one range in * phys_avail[]. */ static int overlaps_phys_avail(vm_paddr_t start, vm_paddr_t end) { int i; for (i = 0; phys_avail[i] != 0 && phys_avail[i + 1] != 0; i += 2) { if (phys_avail[i + 1] < start) continue; if (phys_avail[i] < end) return (1); break; } return (0); } static void srat_parse_entry(ACPI_SUBTABLE_HEADER *entry, void *arg) { ACPI_SRAT_CPU_AFFINITY *cpu; ACPI_SRAT_X2APIC_CPU_AFFINITY *x2apic; ACPI_SRAT_MEM_AFFINITY *mem; int domain, i, slot; switch (entry->Type) { case ACPI_SRAT_TYPE_CPU_AFFINITY: cpu = (ACPI_SRAT_CPU_AFFINITY *)entry; domain = cpu->ProximityDomainLo | cpu->ProximityDomainHi[0] << 8 | cpu->ProximityDomainHi[1] << 16 | cpu->ProximityDomainHi[2] << 24; if (bootverbose) printf("SRAT: Found CPU APIC ID %u domain %d: %s\n", cpu->ApicId, domain, (cpu->Flags & ACPI_SRAT_CPU_ENABLED) ? "enabled" : "disabled"); if (!(cpu->Flags & ACPI_SRAT_CPU_ENABLED)) break; KASSERT(!cpus[cpu->ApicId].enabled, ("Duplicate local APIC ID %u", cpu->ApicId)); cpus[cpu->ApicId].domain = domain; cpus[cpu->ApicId].enabled = 1; break; case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: x2apic = (ACPI_SRAT_X2APIC_CPU_AFFINITY *)entry; if (bootverbose) printf("SRAT: Found CPU APIC ID %u domain %d: %s\n", x2apic->ApicId, x2apic->ProximityDomain, (x2apic->Flags & ACPI_SRAT_CPU_ENABLED) ? "enabled" : "disabled"); if (!(x2apic->Flags & ACPI_SRAT_CPU_ENABLED)) break; KASSERT(!cpus[x2apic->ApicId].enabled, ("Duplicate local APIC ID %u", x2apic->ApicId)); cpus[x2apic->ApicId].domain = x2apic->ProximityDomain; cpus[x2apic->ApicId].enabled = 1; break; case ACPI_SRAT_TYPE_MEMORY_AFFINITY: mem = (ACPI_SRAT_MEM_AFFINITY *)entry; if (bootverbose) printf( "SRAT: Found memory domain %d addr %jx len %jx: %s\n", mem->ProximityDomain, (uintmax_t)mem->BaseAddress, (uintmax_t)mem->Length, (mem->Flags & ACPI_SRAT_MEM_ENABLED) ? "enabled" : "disabled"); if (!(mem->Flags & ACPI_SRAT_MEM_ENABLED)) break; if (!overlaps_phys_avail(mem->BaseAddress, mem->BaseAddress + mem->Length)) { printf("SRAT: Ignoring memory at addr %jx\n", (uintmax_t)mem->BaseAddress); break; } if (num_mem == VM_PHYSSEG_MAX) { printf("SRAT: Too many memory regions\n"); *(int *)arg = ENXIO; break; } slot = num_mem; for (i = 0; i < num_mem; i++) { if (mem_info[i].end <= mem->BaseAddress) continue; if (mem_info[i].start < (mem->BaseAddress + mem->Length)) { printf("SRAT: Overlapping memory entries\n"); *(int *)arg = ENXIO; return; } slot = i; } for (i = num_mem; i > slot; i--) mem_info[i] = mem_info[i - 1]; mem_info[slot].start = mem->BaseAddress; mem_info[slot].end = mem->BaseAddress + mem->Length; mem_info[slot].domain = mem->ProximityDomain; num_mem++; break; } } /* * Ensure each memory domain has at least one CPU and that each CPU * has at least one memory domain. */ static int check_domains(void) { int found, i, j; for (i = 0; i < num_mem; i++) { found = 0; for (j = 0; j <= MAX_APIC_ID; j++) if (cpus[j].enabled && cpus[j].domain == mem_info[i].domain) { cpus[j].has_memory = 1; found++; } if (!found) { printf("SRAT: No CPU found for memory domain %d\n", mem_info[i].domain); return (ENXIO); } } for (i = 0; i <= MAX_APIC_ID; i++) if (cpus[i].enabled && !cpus[i].has_memory) { printf("SRAT: No memory found for CPU %d\n", i); return (ENXIO); } return (0); } /* * Check that the SRAT memory regions cover all of the regions in * phys_avail[]. */ static int check_phys_avail(void) { vm_paddr_t address; int i, j; /* j is the current offset into phys_avail[]. */ address = phys_avail[0]; j = 0; for (i = 0; i < num_mem; i++) { /* * Consume as many phys_avail[] entries as fit in this * region. */ while (address >= mem_info[i].start && address <= mem_info[i].end) { /* * If we cover the rest of this phys_avail[] entry, * advance to the next entry. */ if (phys_avail[j + 1] <= mem_info[i].end) { j += 2; if (phys_avail[j] == 0 && phys_avail[j + 1] == 0) { return (0); } address = phys_avail[j]; } else address = mem_info[i].end + 1; } } printf("SRAT: No memory region found for %jx - %jx\n", (uintmax_t)phys_avail[j], (uintmax_t)phys_avail[j + 1]); return (ENXIO); } /* * Renumber the memory domains to be compact and zero-based if not * already. Returns an error if there are too many domains. */ static int renumber_domains(void) { int i, j, slot; /* Enumerate all the domains. */ vm_ndomains = 0; for (i = 0; i < num_mem; i++) { /* See if this domain is already known. */ for (j = 0; j < vm_ndomains; j++) { if (vm_domains[j] >= mem_info[i].domain) break; } if (j < vm_ndomains && vm_domains[j] == mem_info[i].domain) continue; /* Insert the new domain at slot 'j'. */ slot = j; for (j = vm_ndomains; j > slot; j--) vm_domains[j] = vm_domains[j - 1]; vm_domains[slot] = mem_info[i].domain; vm_ndomains++; if (vm_ndomains > MAXMEMDOM) { vm_ndomains = 1; printf("SRAT: Too many memory domains\n"); return (EFBIG); } } /* Renumber each domain to its index in the sorted 'domains' list. */ for (i = 0; i < vm_ndomains; i++) { /* * If the domain is already the right value, no need * to renumber. */ if (vm_domains[i] == i) continue; /* Walk the cpu[] and mem_info[] arrays to renumber. */ for (j = 0; j < num_mem; j++) if (mem_info[j].domain == vm_domains[i]) mem_info[j].domain = i; for (j = 0; j <= MAX_APIC_ID; j++) if (cpus[j].enabled && cpus[j].domain == vm_domains[i]) cpus[j].domain = i; } KASSERT(vm_ndomains > 0, ("renumber_domains: invalid final vm_ndomains setup")); return (0); } /* * Look for an ACPI System Resource Affinity Table ("SRAT") */ static void parse_srat(void *dummy) { int error; if (resource_disabled("srat", 0)) return; srat_physaddr = acpi_find_table(ACPI_SIG_SRAT); if (srat_physaddr == 0) return; /* * Make a pass over the table to populate the cpus[] and * mem_info[] tables. */ srat = acpi_map_table(srat_physaddr, ACPI_SIG_SRAT); error = 0; srat_walk_table(srat_parse_entry, &error); acpi_unmap_table(srat); srat = NULL; if (error || check_domains() != 0 || check_phys_avail() != 0 || renumber_domains() != 0) { srat_physaddr = 0; return; } /* Point vm_phys at our memory affinity table. */ mem_affinity = mem_info; } SYSINIT(parse_srat, SI_SUB_VM - 1, SI_ORDER_FIRST, parse_srat, NULL); static void srat_walk_table(acpi_subtable_handler *handler, void *arg) { acpi_walk_subtables(srat + 1, (char *)srat + srat->Header.Length, handler, arg); } /* * Setup per-CPU ACPI IDs. */ static void srat_set_cpus(void *dummy) { struct cpu_info *cpu; struct pcpu *pc; u_int i; if (srat_physaddr == 0) return; for (i = 0; i < MAXCPU; i++) { if (CPU_ABSENT(i)) continue; pc = pcpu_find(i); KASSERT(pc != NULL, ("no pcpu data for CPU %u", i)); cpu = &cpus[pc->pc_apic_id]; if (!cpu->enabled) panic("SRAT: CPU with APIC ID %u is not known", pc->pc_apic_id); pc->pc_domain = cpu->domain; if (bootverbose) printf("SRAT: CPU %u has memory domain %d\n", i, cpu->domain); } } SYSINIT(srat_set_cpus, SI_SUB_CPU, SI_ORDER_ANY, srat_set_cpus, NULL); /* * Map a _PXM value to a VM domain ID. * * Returns the domain ID, or -1 if no domain ID was found. */ int acpi_map_pxm_to_vm_domainid(int pxm) { int i; for (i = 0; i < vm_ndomains; i++) { if (vm_domains[i] == pxm) return (i); } return (-1); } #endif /* MAXMEMDOM > 1 */ Index: stable/10/sys/x86/include/mca.h =================================================================== --- stable/10/sys/x86/include/mca.h (revision 283926) +++ stable/10/sys/x86/include/mca.h (revision 283927) @@ -1,56 +1,56 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef __X86_MCA_H__ #define __X86_MCA_H__ struct mca_record { uint64_t mr_status; uint64_t mr_addr; uint64_t mr_misc; uint64_t mr_tsc; int mr_apic_id; int mr_bank; uint64_t mr_mcg_cap; uint64_t mr_mcg_status; int mr_cpu_id; int mr_cpu_vendor_id; int mr_cpu; }; #ifdef _KERNEL void cmc_intr(void); void mca_init(void); void mca_intr(void); void mca_resume(void); #endif #endif /* !__X86_MCA_H__ */ Index: stable/10/sys/x86/pci/qpi.c =================================================================== --- stable/10/sys/x86/pci/qpi.c (revision 283926) +++ stable/10/sys/x86/pci/qpi.c (revision 283927) @@ -1,304 +1,304 @@ /*- - * Copyright (c) 2010 Advanced Computing Technologies LLC + * Copyright (c) 2010 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ /* * This driver provides a psuedo-bus to enumerate the PCI buses * present on a sytem using a QPI chipset. It creates a qpi0 bus that * is a child of nexus0 and then creates two Host-PCI bridges as a * child of that. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" struct qpi_device { int qd_pcibus; }; static MALLOC_DEFINE(M_QPI, "qpidrv", "qpi system device"); static void qpi_identify(driver_t *driver, device_t parent) { /* Check CPUID to ensure this is an i7 CPU of some sort. */ if (!(cpu_vendor_id == CPU_VENDOR_INTEL && CPUID_TO_FAMILY(cpu_id) == 0x6 && (CPUID_TO_MODEL(cpu_id) == 0x1a || CPUID_TO_MODEL(cpu_id) == 0x2c))) return; /* PCI config register access is required. */ if (pci_cfgregopen() == 0) return; /* Add a qpi bus device. */ if (BUS_ADD_CHILD(parent, 20, "qpi", -1) == NULL) panic("Failed to add qpi bus"); } static int qpi_probe(device_t dev) { device_set_desc(dev, "QPI system bus"); return (BUS_PROBE_SPECIFIC); } /* * Look for a PCI bus with the specified bus address. If one is found, * add a pcib device and return 0. Otherwise, return an error code. */ static int qpi_probe_pcib(device_t dev, int bus) { struct qpi_device *qdev; device_t child; uint32_t devid; /* * If a PCI bus already exists for this bus number, then * fail. */ if (pci_find_bsf(bus, 0, 0) != NULL) return (EEXIST); /* * Attempt to read the device id for device 0, function 0 on * the bus. A value of 0xffffffff means that the bus is not * present. */ devid = pci_cfgregread(bus, 0, 0, PCIR_DEVVENDOR, 4); if (devid == 0xffffffff) return (ENOENT); if ((devid & 0xffff) != 0x8086) { device_printf(dev, "Device at pci%d.0.0 has non-Intel vendor 0x%x\n", bus, devid & 0xffff); return (ENXIO); } child = BUS_ADD_CHILD(dev, 0, "pcib", -1); if (child == NULL) panic("%s: failed to add pci bus %d", device_get_nameunit(dev), bus); qdev = malloc(sizeof(struct qpi_device), M_QPI, M_WAITOK); qdev->qd_pcibus = bus; device_set_ivars(child, qdev); return (0); } static int qpi_attach(device_t dev) { int bus; /* * Each processor socket has a dedicated PCI bus counting down from * 255. We keep probing buses until one fails. */ for (bus = 255;; bus--) if (qpi_probe_pcib(dev, bus) != 0) break; return (bus_generic_attach(dev)); } static int qpi_print_child(device_t bus, device_t child) { struct qpi_device *qdev; int retval = 0; qdev = device_get_ivars(child); retval += bus_print_child_header(bus, child); if (qdev->qd_pcibus != -1) retval += printf(" pcibus %d", qdev->qd_pcibus); retval += bus_print_child_footer(bus, child); return (retval); } static int qpi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct qpi_device *qdev; qdev = device_get_ivars(child); switch (which) { case PCIB_IVAR_BUS: *result = qdev->qd_pcibus; break; default: return (ENOENT); } return (0); } static device_method_t qpi_methods[] = { /* Device interface */ DEVMETHOD(device_identify, qpi_identify), DEVMETHOD(device_probe, qpi_probe), DEVMETHOD(device_attach, qpi_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, qpi_print_child), DEVMETHOD(bus_add_child, bus_generic_add_child), DEVMETHOD(bus_read_ivar, qpi_read_ivar), DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), { 0, 0 } }; static devclass_t qpi_devclass; DEFINE_CLASS_0(qpi, qpi_driver, qpi_methods, 0); DRIVER_MODULE(qpi, nexus, qpi_driver, qpi_devclass, 0, 0); static int qpi_pcib_probe(device_t dev) { device_set_desc(dev, "QPI Host-PCI bridge"); return (BUS_PROBE_SPECIFIC); } static int qpi_pcib_attach(device_t dev) { device_add_child(dev, "pci", pcib_get_bus(dev)); return (bus_generic_attach(dev)); } static int qpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = pcib_get_bus(dev); return (0); default: return (ENOENT); } } #if defined(NEW_PCIB) && defined(PCI_RES_BUS) static struct resource * qpi_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { if (type == PCI_RES_BUS) return (pci_domain_alloc_bus(0, child, rid, start, end, count, flags)); return (bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); } #endif static int qpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data) { device_t bus; bus = device_get_parent(pcib); return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); } static device_method_t qpi_pcib_methods[] = { /* Device interface */ DEVMETHOD(device_probe, qpi_pcib_probe), DEVMETHOD(device_attach, qpi_pcib_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, qpi_pcib_read_ivar), #if defined(NEW_PCIB) && defined(PCI_RES_BUS) DEVMETHOD(bus_alloc_resource, qpi_pcib_alloc_resource), DEVMETHOD(bus_adjust_resource, legacy_pcib_adjust_resource), DEVMETHOD(bus_release_resource, legacy_pcib_release_resource), #else DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), #endif DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, pcib_maxslots), DEVMETHOD(pcib_read_config, legacy_pcib_read_config), DEVMETHOD(pcib_write_config, legacy_pcib_write_config), DEVMETHOD(pcib_alloc_msi, legacy_pcib_alloc_msi), DEVMETHOD(pcib_release_msi, pcib_release_msi), DEVMETHOD(pcib_alloc_msix, legacy_pcib_alloc_msix), DEVMETHOD(pcib_release_msix, pcib_release_msix), DEVMETHOD(pcib_map_msi, qpi_pcib_map_msi), DEVMETHOD_END }; static devclass_t qpi_pcib_devclass; DEFINE_CLASS_0(pcib, qpi_pcib_driver, qpi_pcib_methods, 0); DRIVER_MODULE(pcib, qpi, qpi_pcib_driver, qpi_pcib_devclass, 0, 0); Index: stable/10/sys/x86/x86/mca.c =================================================================== --- stable/10/sys/x86/x86/mca.c (revision 283926) +++ stable/10/sys/x86/x86/mca.c (revision 283927) @@ -1,1034 +1,1034 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ /* * Support for x86 machine check architecture. */ #include __FBSDID("$FreeBSD$"); #ifdef __amd64__ #define DEV_APIC #else #include "opt_apic.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Modes for mca_scan() */ enum scan_mode { POLLED, MCE, CMCI, }; #ifdef DEV_APIC /* * State maintained for each monitored MCx bank to control the * corrected machine check interrupt threshold. */ struct cmc_state { int max_threshold; int last_intr; }; #endif struct mca_internal { struct mca_record rec; int logged; STAILQ_ENTRY(mca_internal) link; }; static MALLOC_DEFINE(M_MCA, "MCA", "Machine Check Architecture"); static volatile int mca_count; /* Number of records stored. */ static int mca_banks; /* Number of per-CPU register banks. */ static SYSCTL_NODE(_hw, OID_AUTO, mca, CTLFLAG_RD, NULL, "Machine Check Architecture"); static int mca_enabled = 1; TUNABLE_INT("hw.mca.enabled", &mca_enabled); SYSCTL_INT(_hw_mca, OID_AUTO, enabled, CTLFLAG_RDTUN, &mca_enabled, 0, "Administrative toggle for machine check support"); static int amd10h_L1TP = 1; TUNABLE_INT("hw.mca.amd10h_L1TP", &amd10h_L1TP); SYSCTL_INT(_hw_mca, OID_AUTO, amd10h_L1TP, CTLFLAG_RDTUN, &amd10h_L1TP, 0, "Administrative toggle for logging of level one TLB parity (L1TP) errors"); static int intel6h_HSD131; TUNABLE_INT("hw.mca.intel6h_hsd131", &intel6h_HSD131); SYSCTL_INT(_hw_mca, OID_AUTO, intel6h_HSD131, CTLFLAG_RDTUN, &intel6h_HSD131, 0, "Administrative toggle for logging of spurious corrected errors"); int workaround_erratum383; SYSCTL_INT(_hw_mca, OID_AUTO, erratum383, CTLFLAG_RD, &workaround_erratum383, 0, "Is the workaround for Erratum 383 on AMD Family 10h processors enabled?"); static STAILQ_HEAD(, mca_internal) mca_freelist; static int mca_freecount; static STAILQ_HEAD(, mca_internal) mca_records; static struct callout mca_timer; static int mca_ticks = 3600; /* Check hourly by default. */ static struct taskqueue *mca_tq; static struct task mca_refill_task, mca_scan_task; static struct mtx mca_lock; #ifdef DEV_APIC static struct cmc_state **cmc_state; /* Indexed by cpuid, bank */ static int cmc_throttle = 60; /* Time in seconds to throttle CMCI. */ #endif static int sysctl_positive_int(SYSCTL_HANDLER_ARGS) { int error, value; value = *(int *)arg1; error = sysctl_handle_int(oidp, &value, 0, req); if (error || req->newptr == NULL) return (error); if (value <= 0) return (EINVAL); *(int *)arg1 = value; return (0); } static int sysctl_mca_records(SYSCTL_HANDLER_ARGS) { int *name = (int *)arg1; u_int namelen = arg2; struct mca_record record; struct mca_internal *rec; int i; if (namelen != 1) return (EINVAL); if (name[0] < 0 || name[0] >= mca_count) return (EINVAL); mtx_lock_spin(&mca_lock); if (name[0] >= mca_count) { mtx_unlock_spin(&mca_lock); return (EINVAL); } i = 0; STAILQ_FOREACH(rec, &mca_records, link) { if (i == name[0]) { record = rec->rec; break; } i++; } mtx_unlock_spin(&mca_lock); return (SYSCTL_OUT(req, &record, sizeof(record))); } static const char * mca_error_ttype(uint16_t mca_error) { switch ((mca_error & 0x000c) >> 2) { case 0: return ("I"); case 1: return ("D"); case 2: return ("G"); } return ("?"); } static const char * mca_error_level(uint16_t mca_error) { switch (mca_error & 0x0003) { case 0: return ("L0"); case 1: return ("L1"); case 2: return ("L2"); case 3: return ("LG"); } return ("L?"); } static const char * mca_error_request(uint16_t mca_error) { switch ((mca_error & 0x00f0) >> 4) { case 0x0: return ("ERR"); case 0x1: return ("RD"); case 0x2: return ("WR"); case 0x3: return ("DRD"); case 0x4: return ("DWR"); case 0x5: return ("IRD"); case 0x6: return ("PREFETCH"); case 0x7: return ("EVICT"); case 0x8: return ("SNOOP"); } return ("???"); } static const char * mca_error_mmtype(uint16_t mca_error) { switch ((mca_error & 0x70) >> 4) { case 0x0: return ("GEN"); case 0x1: return ("RD"); case 0x2: return ("WR"); case 0x3: return ("AC"); case 0x4: return ("MS"); } return ("???"); } static int __nonnull(1) mca_mute(const struct mca_record *rec) { /* * Skip spurious corrected parity errors generated by desktop Haswell * (see HSD131 erratum) unless reporting is enabled. * Note that these errors also have been observed with D0-stepping, * while the revision 014 desktop Haswell specification update only * talks about C0-stepping. */ if (rec->mr_cpu_vendor_id == CPU_VENDOR_INTEL && rec->mr_cpu_id == 0x306c3 && rec->mr_bank == 0 && rec->mr_status == 0x90000040000f0005 && !intel6h_HSD131) return (1); return (0); } /* Dump details about a single machine check. */ static void __nonnull(1) mca_log(const struct mca_record *rec) { uint16_t mca_error; if (mca_mute(rec)) return; printf("MCA: Bank %d, Status 0x%016llx\n", rec->mr_bank, (long long)rec->mr_status); printf("MCA: Global Cap 0x%016llx, Status 0x%016llx\n", (long long)rec->mr_mcg_cap, (long long)rec->mr_mcg_status); printf("MCA: Vendor \"%s\", ID 0x%x, APIC ID %d\n", cpu_vendor, rec->mr_cpu_id, rec->mr_apic_id); printf("MCA: CPU %d ", rec->mr_cpu); if (rec->mr_status & MC_STATUS_UC) printf("UNCOR "); else { printf("COR "); if (rec->mr_mcg_cap & MCG_CAP_CMCI_P) printf("(%lld) ", ((long long)rec->mr_status & MC_STATUS_COR_COUNT) >> 38); } if (rec->mr_status & MC_STATUS_PCC) printf("PCC "); if (rec->mr_status & MC_STATUS_OVER) printf("OVER "); mca_error = rec->mr_status & MC_STATUS_MCA_ERROR; switch (mca_error) { /* Simple error codes. */ case 0x0000: printf("no error"); break; case 0x0001: printf("unclassified error"); break; case 0x0002: printf("ucode ROM parity error"); break; case 0x0003: printf("external error"); break; case 0x0004: printf("FRC error"); break; case 0x0005: printf("internal parity error"); break; case 0x0400: printf("internal timer error"); break; default: if ((mca_error & 0xfc00) == 0x0400) { printf("internal error %x", mca_error & 0x03ff); break; } /* Compound error codes. */ /* Memory hierarchy error. */ if ((mca_error & 0xeffc) == 0x000c) { printf("%s memory error", mca_error_level(mca_error)); break; } /* TLB error. */ if ((mca_error & 0xeff0) == 0x0010) { printf("%sTLB %s error", mca_error_ttype(mca_error), mca_error_level(mca_error)); break; } /* Memory controller error. */ if ((mca_error & 0xef80) == 0x0080) { printf("%s channel ", mca_error_mmtype(mca_error)); if ((mca_error & 0x000f) != 0x000f) printf("%d", mca_error & 0x000f); else printf("??"); printf(" memory error"); break; } /* Cache error. */ if ((mca_error & 0xef00) == 0x0100) { printf("%sCACHE %s %s error", mca_error_ttype(mca_error), mca_error_level(mca_error), mca_error_request(mca_error)); break; } /* Bus and/or Interconnect error. */ if ((mca_error & 0xe800) == 0x0800) { printf("BUS%s ", mca_error_level(mca_error)); switch ((mca_error & 0x0600) >> 9) { case 0: printf("Source"); break; case 1: printf("Responder"); break; case 2: printf("Observer"); break; default: printf("???"); break; } printf(" %s ", mca_error_request(mca_error)); switch ((mca_error & 0x000c) >> 2) { case 0: printf("Memory"); break; case 2: printf("I/O"); break; case 3: printf("Other"); break; default: printf("???"); break; } if (mca_error & 0x0100) printf(" timed out"); break; } printf("unknown error %x", mca_error); break; } printf("\n"); if (rec->mr_status & MC_STATUS_ADDRV) printf("MCA: Address 0x%llx\n", (long long)rec->mr_addr); if (rec->mr_status & MC_STATUS_MISCV) printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc); } static int __nonnull(2) mca_check_status(int bank, struct mca_record *rec) { uint64_t status; u_int p[4]; status = rdmsr(MSR_MC_STATUS(bank)); if (!(status & MC_STATUS_VAL)) return (0); /* Save exception information. */ rec->mr_status = status; rec->mr_bank = bank; rec->mr_addr = 0; if (status & MC_STATUS_ADDRV) rec->mr_addr = rdmsr(MSR_MC_ADDR(bank)); rec->mr_misc = 0; if (status & MC_STATUS_MISCV) rec->mr_misc = rdmsr(MSR_MC_MISC(bank)); rec->mr_tsc = rdtsc(); rec->mr_apic_id = PCPU_GET(apic_id); rec->mr_mcg_cap = rdmsr(MSR_MCG_CAP); rec->mr_mcg_status = rdmsr(MSR_MCG_STATUS); rec->mr_cpu_id = cpu_id; rec->mr_cpu_vendor_id = cpu_vendor_id; rec->mr_cpu = PCPU_GET(cpuid); /* * Clear machine check. Don't do this for uncorrectable * errors so that the BIOS can see them. */ if (!(rec->mr_status & (MC_STATUS_PCC | MC_STATUS_UC))) { wrmsr(MSR_MC_STATUS(bank), 0); do_cpuid(0, p); } return (1); } static void mca_fill_freelist(void) { struct mca_internal *rec; int desired; /* * Ensure we have at least one record for each bank and one * record per CPU. */ desired = imax(mp_ncpus, mca_banks); mtx_lock_spin(&mca_lock); while (mca_freecount < desired) { mtx_unlock_spin(&mca_lock); rec = malloc(sizeof(*rec), M_MCA, M_WAITOK); mtx_lock_spin(&mca_lock); STAILQ_INSERT_TAIL(&mca_freelist, rec, link); mca_freecount++; } mtx_unlock_spin(&mca_lock); } static void mca_refill(void *context, int pending) { mca_fill_freelist(); } static void __nonnull(2) mca_record_entry(enum scan_mode mode, const struct mca_record *record) { struct mca_internal *rec; if (mode == POLLED) { rec = malloc(sizeof(*rec), M_MCA, M_WAITOK); mtx_lock_spin(&mca_lock); } else { mtx_lock_spin(&mca_lock); rec = STAILQ_FIRST(&mca_freelist); if (rec == NULL) { printf("MCA: Unable to allocate space for an event.\n"); mca_log(record); mtx_unlock_spin(&mca_lock); return; } STAILQ_REMOVE_HEAD(&mca_freelist, link); mca_freecount--; } rec->rec = *record; rec->logged = 0; STAILQ_INSERT_TAIL(&mca_records, rec, link); mca_count++; mtx_unlock_spin(&mca_lock); if (mode == CMCI) taskqueue_enqueue_fast(mca_tq, &mca_refill_task); } #ifdef DEV_APIC /* * Update the interrupt threshold for a CMCI. The strategy is to use * a low trigger that interrupts as soon as the first event occurs. * However, if a steady stream of events arrive, the threshold is * increased until the interrupts are throttled to once every * cmc_throttle seconds or the periodic scan. If a periodic scan * finds that the threshold is too high, it is lowered. */ static void cmci_update(enum scan_mode mode, int bank, int valid, struct mca_record *rec) { struct cmc_state *cc; uint64_t ctl; u_int delta; int count, limit; /* Fetch the current limit for this bank. */ cc = &cmc_state[PCPU_GET(cpuid)][bank]; ctl = rdmsr(MSR_MC_CTL2(bank)); count = (rec->mr_status & MC_STATUS_COR_COUNT) >> 38; delta = (u_int)(ticks - cc->last_intr); /* * If an interrupt was received less than cmc_throttle seconds * since the previous interrupt and the count from the current * event is greater than or equal to the current threshold, * double the threshold up to the max. */ if (mode == CMCI && valid) { limit = ctl & MC_CTL2_THRESHOLD; if (delta < cmc_throttle && count >= limit && limit < cc->max_threshold) { limit = min(limit << 1, cc->max_threshold); ctl &= ~MC_CTL2_THRESHOLD; ctl |= limit; wrmsr(MSR_MC_CTL2(bank), limit); } cc->last_intr = ticks; return; } /* * When the banks are polled, check to see if the threshold * should be lowered. */ if (mode != POLLED) return; /* If a CMCI occured recently, do nothing for now. */ if (delta < cmc_throttle) return; /* * Compute a new limit based on the average rate of events per * cmc_throttle seconds since the last interrupt. */ if (valid) { count = (rec->mr_status & MC_STATUS_COR_COUNT) >> 38; limit = count * cmc_throttle / delta; if (limit <= 0) limit = 1; else if (limit > cc->max_threshold) limit = cc->max_threshold; } else limit = 1; if ((ctl & MC_CTL2_THRESHOLD) != limit) { ctl &= ~MC_CTL2_THRESHOLD; ctl |= limit; wrmsr(MSR_MC_CTL2(bank), limit); } } #endif /* * This scans all the machine check banks of the current CPU to see if * there are any machine checks. Any non-recoverable errors are * reported immediately via mca_log(). The current thread must be * pinned when this is called. The 'mode' parameter indicates if we * are being called from the MC exception handler, the CMCI handler, * or the periodic poller. In the MC exception case this function * returns true if the system is restartable. Otherwise, it returns a * count of the number of valid MC records found. */ static int mca_scan(enum scan_mode mode) { struct mca_record rec; uint64_t mcg_cap, ucmask; int count, i, recoverable, valid; count = 0; recoverable = 1; ucmask = MC_STATUS_UC | MC_STATUS_PCC; /* When handling a MCE#, treat the OVER flag as non-restartable. */ if (mode == MCE) ucmask |= MC_STATUS_OVER; mcg_cap = rdmsr(MSR_MCG_CAP); for (i = 0; i < (mcg_cap & MCG_CAP_COUNT); i++) { #ifdef DEV_APIC /* * For a CMCI, only check banks this CPU is * responsible for. */ if (mode == CMCI && !(PCPU_GET(cmci_mask) & 1 << i)) continue; #endif valid = mca_check_status(i, &rec); if (valid) { count++; if (rec.mr_status & ucmask) { recoverable = 0; mtx_lock_spin(&mca_lock); mca_log(&rec); mtx_unlock_spin(&mca_lock); } mca_record_entry(mode, &rec); } #ifdef DEV_APIC /* * If this is a bank this CPU monitors via CMCI, * update the threshold. */ if (PCPU_GET(cmci_mask) & 1 << i) cmci_update(mode, i, valid, &rec); #endif } if (mode == POLLED) mca_fill_freelist(); return (mode == MCE ? recoverable : count); } /* * Scan the machine check banks on all CPUs by binding to each CPU in * turn. If any of the CPUs contained new machine check records, log * them to the console. */ static void mca_scan_cpus(void *context, int pending) { struct mca_internal *mca; struct thread *td; int count, cpu; mca_fill_freelist(); td = curthread; count = 0; thread_lock(td); CPU_FOREACH(cpu) { sched_bind(td, cpu); thread_unlock(td); count += mca_scan(POLLED); thread_lock(td); sched_unbind(td); } thread_unlock(td); if (count != 0) { mtx_lock_spin(&mca_lock); STAILQ_FOREACH(mca, &mca_records, link) { if (!mca->logged) { mca->logged = 1; mca_log(&mca->rec); } } mtx_unlock_spin(&mca_lock); } } static void mca_periodic_scan(void *arg) { taskqueue_enqueue_fast(mca_tq, &mca_scan_task); callout_reset(&mca_timer, mca_ticks * hz, mca_periodic_scan, NULL); } static int sysctl_mca_scan(SYSCTL_HANDLER_ARGS) { int error, i; i = 0; error = sysctl_handle_int(oidp, &i, 0, req); if (error) return (error); if (i) taskqueue_enqueue_fast(mca_tq, &mca_scan_task); return (0); } static void mca_createtq(void *dummy) { if (mca_banks <= 0) return; mca_tq = taskqueue_create_fast("mca", M_WAITOK, taskqueue_thread_enqueue, &mca_tq); taskqueue_start_threads(&mca_tq, 1, PI_SWI(SWI_TQ), "mca taskq"); } SYSINIT(mca_createtq, SI_SUB_CONFIGURE, SI_ORDER_ANY, mca_createtq, NULL); static void mca_startup(void *dummy) { if (mca_banks <= 0) return; callout_reset(&mca_timer, mca_ticks * hz, mca_periodic_scan, NULL); } SYSINIT(mca_startup, SI_SUB_SMP, SI_ORDER_ANY, mca_startup, NULL); #ifdef DEV_APIC static void cmci_setup(void) { int i; cmc_state = malloc((mp_maxid + 1) * sizeof(struct cmc_state *), M_MCA, M_WAITOK); for (i = 0; i <= mp_maxid; i++) cmc_state[i] = malloc(sizeof(struct cmc_state) * mca_banks, M_MCA, M_WAITOK | M_ZERO); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "cmc_throttle", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &cmc_throttle, 0, sysctl_positive_int, "I", "Interval in seconds to throttle corrected MC interrupts"); } #endif static void mca_setup(uint64_t mcg_cap) { /* * On AMD Family 10h processors, unless logging of level one TLB * parity (L1TP) errors is disabled, enable the recommended workaround * for Erratum 383. */ if (cpu_vendor_id == CPU_VENDOR_AMD && CPUID_TO_FAMILY(cpu_id) == 0x10 && amd10h_L1TP) workaround_erratum383 = 1; mca_banks = mcg_cap & MCG_CAP_COUNT; mtx_init(&mca_lock, "mca", NULL, MTX_SPIN); STAILQ_INIT(&mca_records); TASK_INIT(&mca_scan_task, 0, mca_scan_cpus, NULL); callout_init(&mca_timer, CALLOUT_MPSAFE); STAILQ_INIT(&mca_freelist); TASK_INIT(&mca_refill_task, 0, mca_refill, NULL); mca_fill_freelist(); SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "count", CTLFLAG_RD, (int *)(uintptr_t)&mca_count, 0, "Record count"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "interval", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &mca_ticks, 0, sysctl_positive_int, "I", "Periodic interval in seconds to scan for machine checks"); SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "records", CTLFLAG_RD, sysctl_mca_records, "Machine check records"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "force_scan", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0, sysctl_mca_scan, "I", "Force an immediate scan for machine checks"); #ifdef DEV_APIC if (mcg_cap & MCG_CAP_CMCI_P) cmci_setup(); #endif } #ifdef DEV_APIC /* * See if we should monitor CMCI for this bank. If CMCI_EN is already * set in MC_CTL2, then another CPU is responsible for this bank, so * ignore it. If CMCI_EN returns zero after being set, then this bank * does not support CMCI_EN. If this CPU sets CMCI_EN, then it should * now monitor this bank. */ static void cmci_monitor(int i) { struct cmc_state *cc; uint64_t ctl; KASSERT(i < mca_banks, ("CPU %d has more MC banks", PCPU_GET(cpuid))); ctl = rdmsr(MSR_MC_CTL2(i)); if (ctl & MC_CTL2_CMCI_EN) /* Already monitored by another CPU. */ return; /* Set the threshold to one event for now. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= MC_CTL2_CMCI_EN | 1; wrmsr(MSR_MC_CTL2(i), ctl); ctl = rdmsr(MSR_MC_CTL2(i)); if (!(ctl & MC_CTL2_CMCI_EN)) /* This bank does not support CMCI. */ return; cc = &cmc_state[PCPU_GET(cpuid)][i]; /* Determine maximum threshold. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= 0x7fff; wrmsr(MSR_MC_CTL2(i), ctl); ctl = rdmsr(MSR_MC_CTL2(i)); cc->max_threshold = ctl & MC_CTL2_THRESHOLD; /* Start off with a threshold of 1. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= 1; wrmsr(MSR_MC_CTL2(i), ctl); /* Mark this bank as monitored. */ PCPU_SET(cmci_mask, PCPU_GET(cmci_mask) | 1 << i); } /* * For resume, reset the threshold for any banks we monitor back to * one and throw away the timestamp of the last interrupt. */ static void cmci_resume(int i) { struct cmc_state *cc; uint64_t ctl; KASSERT(i < mca_banks, ("CPU %d has more MC banks", PCPU_GET(cpuid))); /* Ignore banks not monitored by this CPU. */ if (!(PCPU_GET(cmci_mask) & 1 << i)) return; cc = &cmc_state[PCPU_GET(cpuid)][i]; cc->last_intr = -ticks; ctl = rdmsr(MSR_MC_CTL2(i)); ctl &= ~MC_CTL2_THRESHOLD; ctl |= MC_CTL2_CMCI_EN | 1; wrmsr(MSR_MC_CTL2(i), ctl); } #endif /* * Initializes per-CPU machine check registers and enables corrected * machine check interrupts. */ static void _mca_init(int boot) { uint64_t mcg_cap; uint64_t ctl, mask; int i, skip; /* MCE is required. */ if (!mca_enabled || !(cpu_feature & CPUID_MCE)) return; if (cpu_feature & CPUID_MCA) { if (boot) PCPU_SET(cmci_mask, 0); mcg_cap = rdmsr(MSR_MCG_CAP); if (mcg_cap & MCG_CAP_CTL_P) /* Enable MCA features. */ wrmsr(MSR_MCG_CTL, MCG_CTL_ENABLE); if (PCPU_GET(cpuid) == 0 && boot) mca_setup(mcg_cap); /* * Disable logging of level one TLB parity (L1TP) errors by * the data cache as an alternative workaround for AMD Family * 10h Erratum 383. Unlike the recommended workaround, there * is no performance penalty to this workaround. However, * L1TP errors will go unreported. */ if (cpu_vendor_id == CPU_VENDOR_AMD && CPUID_TO_FAMILY(cpu_id) == 0x10 && !amd10h_L1TP) { mask = rdmsr(MSR_MC0_CTL_MASK); if ((mask & (1UL << 5)) == 0) wrmsr(MSR_MC0_CTL_MASK, mask | (1UL << 5)); } for (i = 0; i < (mcg_cap & MCG_CAP_COUNT); i++) { /* By default enable logging of all errors. */ ctl = 0xffffffffffffffffUL; skip = 0; if (cpu_vendor_id == CPU_VENDOR_INTEL) { /* * For P6 models before Nehalem MC0_CTL is * always enabled and reserved. */ if (i == 0 && CPUID_TO_FAMILY(cpu_id) == 0x6 && CPUID_TO_MODEL(cpu_id) < 0x1a) skip = 1; } else if (cpu_vendor_id == CPU_VENDOR_AMD) { /* BKDG for Family 10h: unset GartTblWkEn. */ if (i == 4 && CPUID_TO_FAMILY(cpu_id) >= 0xf) ctl &= ~(1UL << 10); } if (!skip) wrmsr(MSR_MC_CTL(i), ctl); #ifdef DEV_APIC if (mcg_cap & MCG_CAP_CMCI_P) { if (boot) cmci_monitor(i); else cmci_resume(i); } #endif /* Clear all errors. */ wrmsr(MSR_MC_STATUS(i), 0); } #ifdef DEV_APIC if (PCPU_GET(cmci_mask) != 0 && boot) lapic_enable_cmc(); #endif } load_cr4(rcr4() | CR4_MCE); } /* Must be executed on each CPU during boot. */ void mca_init(void) { _mca_init(1); } /* Must be executed on each CPU during resume. */ void mca_resume(void) { _mca_init(0); } /* * The machine check registers for the BSP cannot be initialized until * the local APIC is initialized. This happens at SI_SUB_CPU, * SI_ORDER_SECOND. */ static void mca_init_bsp(void *arg __unused) { mca_init(); } SYSINIT(mca_init_bsp, SI_SUB_CPU, SI_ORDER_ANY, mca_init_bsp, NULL); /* Called when a machine check exception fires. */ void mca_intr(void) { uint64_t mcg_status; int old_count, recoverable; if (!(cpu_feature & CPUID_MCA)) { /* * Just print the values of the old Pentium registers * and panic. */ printf("MC Type: 0x%jx Address: 0x%jx\n", (uintmax_t)rdmsr(MSR_P5_MC_TYPE), (uintmax_t)rdmsr(MSR_P5_MC_ADDR)); panic("Machine check"); } /* Scan the banks and check for any non-recoverable errors. */ old_count = mca_count; recoverable = mca_scan(MCE); mcg_status = rdmsr(MSR_MCG_STATUS); if (!(mcg_status & MCG_STATUS_RIPV)) recoverable = 0; if (!recoverable) { /* * Wait for at least one error to be logged before * panic'ing. Some errors will assert a machine check * on all CPUs, but only certain CPUs will find a valid * bank to log. */ while (mca_count == old_count) cpu_spinwait(); panic("Unrecoverable machine check exception"); } /* Clear MCIP. */ wrmsr(MSR_MCG_STATUS, mcg_status & ~MCG_STATUS_MCIP); } #ifdef DEV_APIC /* Called for a CMCI (correctable machine check interrupt). */ void cmc_intr(void) { struct mca_internal *mca; int count; /* * Serialize MCA bank scanning to prevent collisions from * sibling threads. */ count = mca_scan(CMCI); /* If we found anything, log them to the console. */ if (count != 0) { mtx_lock_spin(&mca_lock); STAILQ_FOREACH(mca, &mca_records, link) { if (!mca->logged) { mca->logged = 1; mca_log(&mca->rec); } } mtx_unlock_spin(&mca_lock); } } #endif Index: stable/10/tools/regression/lib/libc/stdio/test-open_memstream.c =================================================================== --- stable/10/tools/regression/lib/libc/stdio/test-open_memstream.c (revision 283926) +++ stable/10/tools/regression/lib/libc/stdio/test-open_memstream.c (revision 283927) @@ -1,203 +1,203 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include static char *buf; static size_t len; static void assert_stream(const char *contents) { if (strlen(contents) != len) printf("bad length %zd for \"%s\"\n", len, contents); else if (strncmp(buf, contents, strlen(contents)) != 0) printf("bad buffer \"%s\" for \"%s\"\n", buf, contents); } static void open_group_test(void) { FILE *fp; off_t eob; fp = open_memstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); fprintf(fp, "hello my world"); fflush(fp); assert_stream("hello my world"); eob = ftello(fp); rewind(fp); fprintf(fp, "good-bye"); fseeko(fp, eob, SEEK_SET); fclose(fp); assert_stream("good-bye world"); free(buf); } static void simple_tests(void) { static const char zerobuf[] = { 'f', 'o', 'o', 0, 0, 0, 0, 'b', 'a', 'r', 0 }; char c; FILE *fp; fp = open_memstream(&buf, NULL); if (fp != NULL) errx(1, "did not fail to open stream"); else if (errno != EINVAL) err(1, "incorrect error for bad length pointer"); fp = open_memstream(NULL, &len); if (fp != NULL) errx(1, "did not fail to open stream"); else if (errno != EINVAL) err(1, "incorrect error for bad buffer pointer"); fp = open_memstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); fflush(fp); assert_stream(""); if (fwide(fp, 0) >= 0) printf("stream is not byte-oriented\n"); fprintf(fp, "fo"); fflush(fp); assert_stream("fo"); fputc('o', fp); fflush(fp); assert_stream("foo"); rewind(fp); fflush(fp); assert_stream(""); fseek(fp, 0, SEEK_END); fflush(fp); assert_stream("foo"); /* * Test seeking out past the current end. Should zero-fill the * intermediate area. */ fseek(fp, 4, SEEK_END); fprintf(fp, "bar"); fflush(fp); /* * Can't use assert_stream() here since this should contain * embedded null characters. */ if (len != 10) printf("bad length %zd for zero-fill test\n", len); else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0) printf("bad buffer for zero-fill test\n"); fseek(fp, 3, SEEK_SET); fprintf(fp, " in "); fflush(fp); assert_stream("foo in "); fseek(fp, 0, SEEK_END); fflush(fp); assert_stream("foo in bar"); rewind(fp); if (fread(&c, sizeof(c), 1, fp) != 0) printf("fread did not fail\n"); else if (!ferror(fp)) printf("error indicator not set after fread\n"); else clearerr(fp); fseek(fp, 4, SEEK_SET); fprintf(fp, "bar baz"); fclose(fp); assert_stream("foo bar baz"); free(buf); } static void seek_tests(void) { FILE *fp; fp = open_memstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); #define SEEK_FAIL(offset, whence, error) do { \ errno = 0; \ if (fseeko(fp, (offset), (whence)) == 0) \ printf("fseeko(%s, %s) did not fail, set pos to %jd\n", \ __STRING(offset), __STRING(whence), \ (intmax_t)ftello(fp)); \ else if (errno != (error)) \ printf("fseeko(%s, %s) failed with %d rather than %s\n",\ __STRING(offset), __STRING(whence), errno, \ __STRING(error)); \ } while (0) #define SEEK_OK(offset, whence, result) do { \ if (fseeko(fp, (offset), (whence)) != 0) \ printf("fseeko(%s, %s) failed: %s\n", \ __STRING(offset), __STRING(whence), strerror(errno)); \ else if (ftello(fp) != (result)) \ printf("fseeko(%s, %s) seeked to %jd rather than %s\n", \ __STRING(offset), __STRING(whence), \ (intmax_t)ftello(fp), __STRING(result)); \ } while (0) SEEK_FAIL(-1, SEEK_SET, EINVAL); SEEK_FAIL(-1, SEEK_CUR, EINVAL); SEEK_FAIL(-1, SEEK_END, EINVAL); fprintf(fp, "foo"); SEEK_OK(-1, SEEK_CUR, 2); SEEK_OK(0, SEEK_SET, 0); SEEK_OK(-1, SEEK_END, 2); SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1); SEEK_FAIL(2, SEEK_CUR, EOVERFLOW); fclose(fp); } int main(int ac, char **av) { open_group_test(); simple_tests(); seek_tests(); return (0); } Index: stable/10/tools/regression/lib/libc/stdio/test-open_wmemstream.c =================================================================== --- stable/10/tools/regression/lib/libc/stdio/test-open_wmemstream.c (revision 283926) +++ stable/10/tools/regression/lib/libc/stdio/test-open_wmemstream.c (revision 283927) @@ -1,203 +1,203 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include static wchar_t *buf; static size_t len; static void assert_stream(const wchar_t *contents) { if (wcslen(contents) != len) printf("bad length %zd for \"%ls\"\n", len, contents); else if (wcsncmp(buf, contents, wcslen(contents)) != 0) printf("bad buffer \"%ls\" for \"%ls\"\n", buf, contents); } static void open_group_test(void) { FILE *fp; off_t eob; fp = open_wmemstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); fwprintf(fp, L"hello my world"); fflush(fp); assert_stream(L"hello my world"); eob = ftello(fp); rewind(fp); fwprintf(fp, L"good-bye"); fseeko(fp, eob, SEEK_SET); fclose(fp); assert_stream(L"good-bye world"); free(buf); } static void simple_tests(void) { static const wchar_t zerobuf[] = { L'f', L'o', L'o', 0, 0, 0, 0, L'b', L'a', L'r', 0 }; wchar_t c; FILE *fp; fp = open_wmemstream(&buf, NULL); if (fp != NULL) errx(1, "did not fail to open stream"); else if (errno != EINVAL) err(1, "incorrect error for bad length pointer"); fp = open_wmemstream(NULL, &len); if (fp != NULL) errx(1, "did not fail to open stream"); else if (errno != EINVAL) err(1, "incorrect error for bad buffer pointer"); fp = open_wmemstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); fflush(fp); assert_stream(L""); if (fwide(fp, 0) <= 0) printf("stream is not wide-oriented\n"); fwprintf(fp, L"fo"); fflush(fp); assert_stream(L"fo"); fputwc(L'o', fp); fflush(fp); assert_stream(L"foo"); rewind(fp); fflush(fp); assert_stream(L""); fseek(fp, 0, SEEK_END); fflush(fp); assert_stream(L"foo"); /* * Test seeking out past the current end. Should zero-fill the * intermediate area. */ fseek(fp, 4, SEEK_END); fwprintf(fp, L"bar"); fflush(fp); /* * Can't use assert_stream() here since this should contain * embedded null characters. */ if (len != 10) printf("bad length %zd for zero-fill test\n", len); else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0) printf("bad buffer for zero-fill test\n"); fseek(fp, 3, SEEK_SET); fwprintf(fp, L" in "); fflush(fp); assert_stream(L"foo in "); fseek(fp, 0, SEEK_END); fflush(fp); assert_stream(L"foo in bar"); rewind(fp); if (fread(&c, sizeof(c), 1, fp) != 0) printf("fread did not fail\n"); else if (!ferror(fp)) printf("error indicator not set after fread\n"); else clearerr(fp); fseek(fp, 4, SEEK_SET); fwprintf(fp, L"bar baz"); fclose(fp); assert_stream(L"foo bar baz"); free(buf); } static void seek_tests(void) { FILE *fp; fp = open_wmemstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); #define SEEK_FAIL(offset, whence, error) do { \ errno = 0; \ if (fseeko(fp, (offset), (whence)) == 0) \ printf("fseeko(%s, %s) did not fail, set pos to %jd\n", \ __STRING(offset), __STRING(whence), \ (intmax_t)ftello(fp)); \ else if (errno != (error)) \ printf("fseeko(%s, %s) failed with %d rather than %s\n",\ __STRING(offset), __STRING(whence), errno, \ __STRING(error)); \ } while (0) #define SEEK_OK(offset, whence, result) do { \ if (fseeko(fp, (offset), (whence)) != 0) \ printf("fseeko(%s, %s) failed: %s\n", \ __STRING(offset), __STRING(whence), strerror(errno)); \ else if (ftello(fp) != (result)) \ printf("fseeko(%s, %s) seeked to %jd rather than %s\n", \ __STRING(offset), __STRING(whence), \ (intmax_t)ftello(fp), __STRING(result)); \ } while (0) SEEK_FAIL(-1, SEEK_SET, EINVAL); SEEK_FAIL(-1, SEEK_CUR, EINVAL); SEEK_FAIL(-1, SEEK_END, EINVAL); fwprintf(fp, L"foo"); SEEK_OK(-1, SEEK_CUR, 2); SEEK_OK(0, SEEK_SET, 0); SEEK_OK(-1, SEEK_END, 2); SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1); SEEK_FAIL(2, SEEK_CUR, EOVERFLOW); fclose(fp); } int main(int ac, char **av) { open_group_test(); simple_tests(); seek_tests(); return (0); } Index: stable/10/tools/regression/netinet/arphold/arphold.c =================================================================== --- stable/10/tools/regression/netinet/arphold/arphold.c (revision 283926) +++ stable/10/tools/regression/netinet/arphold/arphold.c (revision 283927) @@ -1,163 +1,163 @@ /* - * Copyright (c) 2010 Advanced Computing Technologies LLC + * Copyright (c) 2010 Hudson River Trading LLC * Written by George Neville-Neil gnn@freebsd.org * 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. * * Description: The following is a test of the arp entry packet queues * which replaced the single packet hold entry that existed in the BSDs * since time immemorial. The test process is: * * 1) Find out the current system limit (maxhold) * 2) Using an IP address for which we do not yet have an entry * load up an ARP entry packet queue with exactly that many packets. * 3) Check the arp dropped stat to make sure that we have not dropped * any packets as yet. * 4) Add one more packet to the queue. * 5) Make sure that only one packet was dropped. * * CAVEAT: The ARP timer will flush the queue after 1 second so it is * important not to run this code in a fast loop or the test will * fail. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #define MSG_SIZE 1024 #define PORT 6969 int main(int argc, char **argv) { int sock; int maxhold; size_t size = sizeof(maxhold); struct sockaddr_in dest; char message[MSG_SIZE]; struct arpstat arpstat; size_t len = sizeof(arpstat); unsigned long dropped = 0; memset(&message, 1, sizeof(message)); if (sysctlbyname("net.link.ether.inet.maxhold", &maxhold, &size, NULL, 0) < 0) { perror("not ok 1 - sysctlbyname failed"); exit(1); } #ifdef DEBUG printf("maxhold is %d\n", maxhold); #endif /* DEBUG */ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("not ok 1 - could not open socket"); exit(1); } bzero(&dest, sizeof(dest)); if (inet_pton(AF_INET, argv[1], &dest.sin_addr.s_addr) != 1) { perror("not ok 1 - could not parse address"); exit(1); } dest.sin_len = sizeof(dest); dest.sin_family = AF_INET; dest.sin_port = htons(PORT); if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, NULL, 0) < 0) { perror("not ok 1 - could not get initial arp stats"); exit(1); } dropped = arpstat.dropped; #ifdef DEBUG printf("dropped before %ld\n", dropped); #endif /* DEBUG */ /* * Load up the queue in the ARP entry to the maximum. * We should not drop any packets at this point. */ while (maxhold > 0) { if (sendto(sock, message, sizeof(message), 0, (struct sockaddr *)&dest, sizeof(dest)) < 0) { perror("not ok 1 - could not send packet"); exit(1); } maxhold--; } if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, NULL, 0) < 0) { perror("not ok 1 - could not get new arp stats"); exit(1); } #ifdef DEBUG printf("dropped after %ld\n", arpstat.dropped); #endif /* DEBUG */ if (arpstat.dropped != dropped) { printf("not ok 1 - Failed, drops changed:" "before %ld after %ld\n", dropped, arpstat.dropped); exit(1); } dropped = arpstat.dropped; /* Now add one extra and make sure it is dropped. */ if (sendto(sock, message, sizeof(message), 0, (struct sockaddr *)&dest, sizeof(dest)) < 0) { perror("not ok 1 - could not send packet"); exit(1); } if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, NULL, 0) < 0) { perror("not ok 1 - could not get new arp stats"); exit(1); } if (arpstat.dropped != (dropped + 1)) { printf("not ok 1 - Failed to drop one packet: before" " %ld after %ld\n", dropped, arpstat.dropped); exit(1); } printf("ok\n"); return (0); } Index: stable/10/usr.bin/perror/perror.1 =================================================================== --- stable/10/usr.bin/perror/perror.1 (revision 283926) +++ stable/10/usr.bin/perror/perror.1 (revision 283927) @@ -1,50 +1,50 @@ .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: George V. Neville-Neil .\" 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$ .\" .Dd May 12, 2009 .Dt PERROR 1 .Os .Sh NAME .Nm perror .Nd "print an error number as a string" .Sh SYNOPSIS .Nm .Ar number .Sh DESCRIPTION The .Nm program takes a raw errno value and prints it as a string. .Sh SEE ALSO .Xr perror 3 .Sh HISTORY The .Nm program first appeared in .Fx 8.0 . .Sh AUTHORS .An George V. Neville-Neil Index: stable/10/usr.bin/perror/perror.c =================================================================== --- stable/10/usr.bin/perror/perror.c (revision 283926) +++ stable/10/usr.bin/perror/perror.c (revision 283927) @@ -1,72 +1,72 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: George V. Neville-Neil * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include static void usage(void); int main(int argc, char **argv) { char *cp; char *errstr; long errnum; (void) setlocale(LC_MESSAGES, ""); if (argc != 2) usage(); errno = 0; errnum = strtol(argv[1], &cp, 0); if (errno != 0) err(1, NULL); if ((errstr = strerror(errnum)) == NULL) err(1, NULL); printf("%s\n", errstr); exit(0); } static void usage(void) { fprintf(stderr, "usage: perror number\n"); exit(1); } Index: stable/10/usr.bin/procstat/procstat_rusage.c =================================================================== --- stable/10/usr.bin/procstat/procstat_rusage.c (revision 283926) +++ stable/10/usr.bin/procstat/procstat_rusage.c (revision 283927) @@ -1,161 +1,161 @@ /*- - * Copyright (c) 2012 Advanced Computing Technologies LLC + * Copyright (c) 2012 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "procstat.h" static struct { const char *ri_name; bool ri_humanize; int ri_scale; } rusage_info[] = { { "maximum RSS", true, 1 }, { "integral shared memory", true, 1 }, { "integral unshared data", true, 1 }, { "integral unshared stack", true, 1 }, { "page reclaims", false, 0 }, { "page faults", false, 0 }, { "swaps", false, 0 }, { "block reads", false, 0 }, { "block writes", false, 0 }, { "messages sent", false, 0 }, { "messages received", false, 0 }, { "signals received", false, 0 }, { "voluntary context switches", false, 0 }, { "involuntary context switches", false, 0 } }; /* xxx days hh:mm:ss.uuuuuu */ static const char * format_time(struct timeval *tv) { static char buffer[32]; int days, hours, minutes, seconds, used; minutes = tv->tv_sec / 60; seconds = tv->tv_sec % 60; hours = minutes / 60; minutes %= 60; days = hours / 24; hours %= 24; used = 0; if (days == 1) used += snprintf(buffer, sizeof(buffer), "1 day "); else if (days > 0) used += snprintf(buffer, sizeof(buffer), "%u days ", days); snprintf(buffer + used, sizeof(buffer) - used, "%02u:%02u:%02u.%06u ", hours, minutes, seconds, (unsigned int)tv->tv_usec); return (buffer); } static const char * format_value(long value, bool humanize, int scale) { static char buffer[14]; if (scale != 0) value <<= scale * 10; if (humanize) humanize_number(buffer, sizeof(buffer), value, "B", scale, HN_DECIMAL); else snprintf(buffer, sizeof(buffer), "%ld ", value); return (buffer); } static void print_prefix(struct kinfo_proc *kipp) { printf("%5d ", kipp->ki_pid); if (Hflag) printf("%6d ", kipp->ki_tid); printf("%-16s ", kipp->ki_comm); } static void print_rusage(struct kinfo_proc *kipp) { long *lp; unsigned int i; print_prefix(kipp); printf("%-14s %32s\n", "user time", format_time(&kipp->ki_rusage.ru_utime)); print_prefix(kipp); printf("%-14s %32s\n", "system time", format_time(&kipp->ki_rusage.ru_stime)); lp = &kipp->ki_rusage.ru_maxrss; for (i = 0; i < nitems(rusage_info); i++) { print_prefix(kipp); printf("%-32s %14s\n", rusage_info[i].ri_name, format_value(*lp, rusage_info[i].ri_humanize, rusage_info[i].ri_scale)); lp++; } } void procstat_rusage(struct procstat *procstat, struct kinfo_proc *kipp) { struct kinfo_proc *kip; unsigned int count, i; if (!hflag) { printf("%5s ", "PID"); if (Hflag) printf("%6s ", "TID"); printf("%-16s %-32s %14s\n", "COMM", "RESOURCE", "VALUE "); } if (!Hflag) { print_rusage(kipp); return; } kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, kipp->ki_pid, &count); if (kip == NULL) return; kinfo_proc_sort(kip, count); for (i = 0; i < count; i++) print_rusage(&kip[i]); procstat_freeprocs(procstat, kip); } Index: stable/10/usr.bin/protect/protect.1 =================================================================== --- stable/10/usr.bin/protect/protect.1 (revision 283926) +++ stable/10/usr.bin/protect/protect.1 (revision 283927) @@ -1,89 +1,89 @@ -.\" Copyright (c) 2013 Advanced Computing Technologies LLC +.\" Copyright (c) 2013 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd September 19, 2013 .Dt PROTECT 1 .Os .Sh NAME .Nm protect .Nd "protect processes from being killed when swap space is exhausted" .Sh SYNOPSIS .Nm .Op Fl i .Ar command .Nm .Op Fl cdi .Fl g Ar pgrp | Fl p Ar pid .Sh DESCRIPTION The .Nm command is used to mark processes as protected. The kernel does not kill protected processes when swap space is exhausted. Note that this protected state is not inherited by child processes by default. .Pp The options are: .Bl -tag -width XXXXXXXXXX .It Fl c Remove protection from the specified processes. .It Fl d Apply the operation to all current children of the specified processes. .It Fl i Apply the operation to all future children of the specified processes. .It Fl g Ar pgrp Apply the operation to all processes in the specified process group. .It Fl p Ar pid Apply the operation to the specified process. .It Ar command Execute .Ar command as a protected process. .El .Pp Note that only one of the .Fl p or .Fl g flags may be specified when adjusting the state of existing processes. .Sh EXIT STATUS .Ex -std .Sh EXAMPLES Mark the Xorg server as protected: .Pp .Dl "pgrep Xorg | xargs protect -p" .Pp Protect all ssh sessions and their child processes: .Pp .Dl "pgrep sshd | xargs protect -dip" .Pp Remove protection from all current and future processes: .Pp .Dl "protect -cdi -p 1" .Sh SEE ALSO .Xr procctl 2 .Sh BUGS If you protect a runaway process that allocates all memory the system will deadlock. Index: stable/10/usr.bin/protect/protect.c =================================================================== --- stable/10/usr.bin/protect/protect.c (revision 283926) +++ stable/10/usr.bin/protect/protect.c (revision 283927) @@ -1,122 +1,122 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include static void usage(void) { fprintf(stderr, "usage: protect [-i] command\n"); fprintf(stderr, " protect [-cdi] -g pgrp | -p pid\n"); exit(1); } static id_t parse_id(char *id) { static bool first = true; long value; char *ch; if (!first) { warnx("only one -g or -p flag is permitted"); usage(); } value = strtol(id, &ch, 0); if (*ch != '\0') { warnx("invalid process id"); usage(); } return (value); } int main(int argc, char *argv[]) { idtype_t idtype; id_t id; int ch, flags; bool descend, inherit, idset; idtype = P_PID; id = getpid(); flags = PPROT_SET; descend = inherit = idset = false; while ((ch = getopt(argc, argv, "cdig:p:")) != -1) switch (ch) { case 'c': flags = PPROT_CLEAR; break; case 'd': descend = true; break; case 'i': inherit = true; break; case 'g': idtype = P_PGID; id = parse_id(optarg); idset = true; break; case 'p': idtype = P_PID; id = parse_id(optarg); idset = true; break; } argc -= optind; argv += optind; if ((idset && argc != 0) || (!idset && (argc == 0 || descend))) usage(); if (descend) flags |= PPROT_DESCEND; if (inherit) flags |= PPROT_INHERIT; if (procctl(idtype, id, PROC_SPROTECT, &flags) == -1) err(1, "procctl"); if (argc != 0) { errno = 0; execvp(*argv, argv); err(errno == ENOENT ? 127 : 126, "%s", *argv); } return (0); } Index: stable/10/usr.sbin/bhyve/ioapic.c =================================================================== --- stable/10/usr.sbin/bhyve/ioapic.c (revision 283926) +++ stable/10/usr.sbin/bhyve/ioapic.c (revision 283927) @@ -1,74 +1,74 @@ /*- - * Copyright (c) 2014 Advanced Computing Technologies LLC + * Copyright (c) 2014 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include "ioapic.h" /* * Assign PCI INTx interrupts to I/O APIC pins in a round-robin * fashion. Note that we have no idea what the HPET is using, but the * HPET is also programmable whereas this is intended for hardwired * PCI interrupts. * * This assumes a single I/O APIC where pins >= 16 are permitted for * PCI devices. */ static int pci_pins; void ioapic_init(struct vmctx *ctx) { if (vm_ioapic_pincount(ctx, &pci_pins) < 0) { pci_pins = 0; return; } /* Ignore the first 16 pins. */ if (pci_pins <= 16) { pci_pins = 0; return; } pci_pins -= 16; } int ioapic_pci_alloc_irq(void) { static int last_pin; if (pci_pins == 0) return (-1); return (16 + (last_pin++ % pci_pins)); } Index: stable/10/usr.sbin/bhyve/ioapic.h =================================================================== --- stable/10/usr.sbin/bhyve/ioapic.h (revision 283926) +++ stable/10/usr.sbin/bhyve/ioapic.h (revision 283927) @@ -1,39 +1,39 @@ /*- - * Copyright (c) 2014 Advanced Computing Technologies LLC + * Copyright (c) 2014 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _IOAPIC_H_ #define _IOAPIC_H_ /* * Allocate a PCI IRQ from the I/O APIC. */ void ioapic_init(struct vmctx *ctx); int ioapic_pci_alloc_irq(void); #endif Index: stable/10/usr.sbin/bhyve/pci_irq.c =================================================================== --- stable/10/usr.sbin/bhyve/pci_irq.c (revision 283926) +++ stable/10/usr.sbin/bhyve/pci_irq.c (revision 283927) @@ -1,346 +1,346 @@ /*- - * Copyright (c) 2014 Advanced Computing Technologies LLC + * Copyright (c) 2014 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include "acpi.h" #include "inout.h" #include "pci_emul.h" #include "pci_irq.h" #include "pci_lpc.h" /* * Implement an 8 pin PCI interrupt router compatible with the router * present on Intel's ICH10 chip. */ /* Fields in each PIRQ register. */ #define PIRQ_DIS 0x80 #define PIRQ_IRQ 0x0f /* Only IRQs 3-7, 9-12, and 14-15 are permitted. */ #define PERMITTED_IRQS 0xdef8 #define IRQ_PERMITTED(irq) (((1U << (irq)) & PERMITTED_IRQS) != 0) /* IRQ count to disable an IRQ. */ #define IRQ_DISABLED 0xff static struct pirq { uint8_t reg; int use_count; int active_count; pthread_mutex_t lock; } pirqs[8]; static u_char irq_counts[16]; static int pirq_cold = 1; /* * Returns true if this pin is enabled with a valid IRQ. Setting the * register to a reserved IRQ causes interrupts to not be asserted as * if the pin was disabled. */ static bool pirq_valid_irq(int reg) { if (reg & PIRQ_DIS) return (false); return (IRQ_PERMITTED(reg & PIRQ_IRQ)); } uint8_t pirq_read(int pin) { assert(pin > 0 && pin <= nitems(pirqs)); return (pirqs[pin - 1].reg); } void pirq_write(struct vmctx *ctx, int pin, uint8_t val) { struct pirq *pirq; assert(pin > 0 && pin <= nitems(pirqs)); pirq = &pirqs[pin - 1]; pthread_mutex_lock(&pirq->lock); if (pirq->reg != (val & (PIRQ_DIS | PIRQ_IRQ))) { if (pirq->active_count != 0 && pirq_valid_irq(pirq->reg)) vm_isa_deassert_irq(ctx, pirq->reg & PIRQ_IRQ, -1); pirq->reg = val & (PIRQ_DIS | PIRQ_IRQ); if (pirq->active_count != 0 && pirq_valid_irq(pirq->reg)) vm_isa_assert_irq(ctx, pirq->reg & PIRQ_IRQ, -1); } pthread_mutex_unlock(&pirq->lock); } void pci_irq_reserve(int irq) { assert(irq >= 0 && irq < nitems(irq_counts)); assert(pirq_cold); assert(irq_counts[irq] == 0 || irq_counts[irq] == IRQ_DISABLED); irq_counts[irq] = IRQ_DISABLED; } void pci_irq_use(int irq) { assert(irq >= 0 && irq < nitems(irq_counts)); assert(pirq_cold); assert(irq_counts[irq] != IRQ_DISABLED); irq_counts[irq]++; } void pci_irq_init(struct vmctx *ctx) { int i; for (i = 0; i < nitems(pirqs); i++) { pirqs[i].reg = PIRQ_DIS; pirqs[i].use_count = 0; pirqs[i].active_count = 0; pthread_mutex_init(&pirqs[i].lock, NULL); } for (i = 0; i < nitems(irq_counts); i++) { if (IRQ_PERMITTED(i)) irq_counts[i] = 0; else irq_counts[i] = IRQ_DISABLED; } } void pci_irq_assert(struct pci_devinst *pi) { struct pirq *pirq; if (pi->pi_lintr.pirq_pin > 0) { assert(pi->pi_lintr.pirq_pin <= nitems(pirqs)); pirq = &pirqs[pi->pi_lintr.pirq_pin - 1]; pthread_mutex_lock(&pirq->lock); pirq->active_count++; if (pirq->active_count == 1 && pirq_valid_irq(pirq->reg)) { vm_isa_assert_irq(pi->pi_vmctx, pirq->reg & PIRQ_IRQ, pi->pi_lintr.ioapic_irq); pthread_mutex_unlock(&pirq->lock); return; } pthread_mutex_unlock(&pirq->lock); } vm_ioapic_assert_irq(pi->pi_vmctx, pi->pi_lintr.ioapic_irq); } void pci_irq_deassert(struct pci_devinst *pi) { struct pirq *pirq; if (pi->pi_lintr.pirq_pin > 0) { assert(pi->pi_lintr.pirq_pin <= nitems(pirqs)); pirq = &pirqs[pi->pi_lintr.pirq_pin - 1]; pthread_mutex_lock(&pirq->lock); pirq->active_count--; if (pirq->active_count == 0 && pirq_valid_irq(pirq->reg)) { vm_isa_deassert_irq(pi->pi_vmctx, pirq->reg & PIRQ_IRQ, pi->pi_lintr.ioapic_irq); pthread_mutex_unlock(&pirq->lock); return; } pthread_mutex_unlock(&pirq->lock); } vm_ioapic_deassert_irq(pi->pi_vmctx, pi->pi_lintr.ioapic_irq); } int pirq_alloc_pin(struct vmctx *ctx) { int best_count, best_irq, best_pin, irq, pin; pirq_cold = 0; /* First, find the least-used PIRQ pin. */ best_pin = 0; best_count = pirqs[0].use_count; for (pin = 1; pin < nitems(pirqs); pin++) { if (pirqs[pin].use_count < best_count) { best_pin = pin; best_count = pirqs[pin].use_count; } } pirqs[best_pin].use_count++; /* Second, route this pin to an IRQ. */ if (pirqs[best_pin].reg == PIRQ_DIS) { best_irq = -1; best_count = 0; for (irq = 0; irq < nitems(irq_counts); irq++) { if (irq_counts[irq] == IRQ_DISABLED) continue; if (best_irq == -1 || irq_counts[irq] < best_count) { best_irq = irq; best_count = irq_counts[irq]; } } assert(best_irq >= 0); irq_counts[best_irq]++; pirqs[best_pin].reg = best_irq; vm_isa_set_irq_trigger(ctx, best_irq, LEVEL_TRIGGER); } return (best_pin + 1); } int pirq_irq(int pin) { assert(pin > 0 && pin <= nitems(pirqs)); return (pirqs[pin - 1].reg & PIRQ_IRQ); } /* XXX: Generate $PIR table. */ static void pirq_dsdt(void) { char *irq_prs, *old; int irq, pin; irq_prs = NULL; for (irq = 0; irq < nitems(irq_counts); irq++) { if (!IRQ_PERMITTED(irq)) continue; if (irq_prs == NULL) asprintf(&irq_prs, "%d", irq); else { old = irq_prs; asprintf(&irq_prs, "%s,%d", old, irq); free(old); } } /* * A helper method to validate a link register's value. This * duplicates pirq_valid_irq(). */ dsdt_line(""); dsdt_line("Method (PIRV, 1, NotSerialized)"); dsdt_line("{"); dsdt_line(" If (And (Arg0, 0x%02X))", PIRQ_DIS); dsdt_line(" {"); dsdt_line(" Return (0x00)"); dsdt_line(" }"); dsdt_line(" And (Arg0, 0x%02X, Local0)", PIRQ_IRQ); dsdt_line(" If (LLess (Local0, 0x03))"); dsdt_line(" {"); dsdt_line(" Return (0x00)"); dsdt_line(" }"); dsdt_line(" If (LEqual (Local0, 0x08))"); dsdt_line(" {"); dsdt_line(" Return (0x00)"); dsdt_line(" }"); dsdt_line(" If (LEqual (Local0, 0x0D))"); dsdt_line(" {"); dsdt_line(" Return (0x00)"); dsdt_line(" }"); dsdt_line(" Return (0x01)"); dsdt_line("}"); for (pin = 0; pin < nitems(pirqs); pin++) { dsdt_line(""); dsdt_line("Device (LNK%c)", 'A' + pin); dsdt_line("{"); dsdt_line(" Name (_HID, EisaId (\"PNP0C0F\"))"); dsdt_line(" Name (_UID, 0x%02X)", pin + 1); dsdt_line(" Method (_STA, 0, NotSerialized)"); dsdt_line(" {"); dsdt_line(" If (PIRV (PIR%c))", 'A' + pin); dsdt_line(" {"); dsdt_line(" Return (0x0B)"); dsdt_line(" }"); dsdt_line(" Else"); dsdt_line(" {"); dsdt_line(" Return (0x09)"); dsdt_line(" }"); dsdt_line(" }"); dsdt_line(" Name (_PRS, ResourceTemplate ()"); dsdt_line(" {"); dsdt_line(" IRQ (Level, ActiveLow, Shared, )"); dsdt_line(" {%s}", irq_prs); dsdt_line(" })"); dsdt_line(" Name (CB%02X, ResourceTemplate ()", pin + 1); dsdt_line(" {"); dsdt_line(" IRQ (Level, ActiveLow, Shared, )"); dsdt_line(" {}"); dsdt_line(" })"); dsdt_line(" CreateWordField (CB%02X, 0x01, CIR%c)", pin + 1, 'A' + pin); dsdt_line(" Method (_CRS, 0, NotSerialized)"); dsdt_line(" {"); dsdt_line(" And (PIR%c, 0x%02X, Local0)", 'A' + pin, PIRQ_DIS | PIRQ_IRQ); dsdt_line(" If (PIRV (Local0))"); dsdt_line(" {"); dsdt_line(" ShiftLeft (0x01, Local0, CIR%c)", 'A' + pin); dsdt_line(" }"); dsdt_line(" Else"); dsdt_line(" {"); dsdt_line(" Store (0x00, CIR%c)", 'A' + pin); dsdt_line(" }"); dsdt_line(" Return (CB%02X)", pin + 1); dsdt_line(" }"); dsdt_line(" Method (_DIS, 0, NotSerialized)"); dsdt_line(" {"); dsdt_line(" Store (0x80, PIR%c)", 'A' + pin); dsdt_line(" }"); dsdt_line(" Method (_SRS, 1, NotSerialized)"); dsdt_line(" {"); dsdt_line(" CreateWordField (Arg0, 0x01, SIR%c)", 'A' + pin); dsdt_line(" FindSetRightBit (SIR%c, Local0)", 'A' + pin); dsdt_line(" Store (Decrement (Local0), PIR%c)", 'A' + pin); dsdt_line(" }"); dsdt_line("}"); } free(irq_prs); } LPC_DSDT(pirq_dsdt); Index: stable/10/usr.sbin/bhyve/pci_irq.h =================================================================== --- stable/10/usr.sbin/bhyve/pci_irq.h (revision 283926) +++ stable/10/usr.sbin/bhyve/pci_irq.h (revision 283927) @@ -1,45 +1,45 @@ /*- - * Copyright (c) 2014 Advanced Computing Technologies LLC + * Copyright (c) 2014 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef __PCI_IRQ_H__ #define __PCI_IRQ_H__ struct pci_devinst; void pci_irq_assert(struct pci_devinst *pi); void pci_irq_deassert(struct pci_devinst *pi); void pci_irq_init(struct vmctx *ctx); void pci_irq_reserve(int irq); void pci_irq_use(int irq); int pirq_alloc_pin(struct vmctx *ctx); int pirq_irq(int pin); uint8_t pirq_read(int pin); void pirq_write(struct vmctx *ctx, int pin, uint8_t val); #endif Index: stable/10/usr.sbin/bhyve/pm.c =================================================================== --- stable/10/usr.sbin/bhyve/pm.c (revision 283926) +++ stable/10/usr.sbin/bhyve/pm.c (revision 283927) @@ -1,312 +1,312 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "acpi.h" #include "inout.h" #include "mevent.h" #include "pci_irq.h" #include "pci_lpc.h" static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER; static struct mevent *power_button; static sig_t old_power_handler; /* * Reset Control register at I/O port 0xcf9. Bit 2 forces a system * reset when it transitions from 0 to 1. Bit 1 selects the type of * reset to attempt: 0 selects a "soft" reset, and 1 selects a "hard" * reset. */ static int reset_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg) { int error; static uint8_t reset_control; if (bytes != 1) return (-1); if (in) *eax = reset_control; else { reset_control = *eax; /* Treat hard and soft resets the same. */ if (reset_control & 0x4) { error = vm_suspend(ctx, VM_SUSPEND_RESET); assert(error == 0 || errno == EALREADY); } } return (0); } INOUT_PORT(reset_reg, 0xCF9, IOPORT_F_INOUT, reset_handler); /* * ACPI's SCI is a level-triggered interrupt. */ static int sci_active; static void sci_assert(struct vmctx *ctx) { if (sci_active) return; vm_isa_assert_irq(ctx, SCI_INT, SCI_INT); sci_active = 1; } static void sci_deassert(struct vmctx *ctx) { if (!sci_active) return; vm_isa_deassert_irq(ctx, SCI_INT, SCI_INT); sci_active = 0; } /* * Power Management 1 Event Registers * * The only power management event supported is a power button upon * receiving SIGTERM. */ static uint16_t pm1_enable, pm1_status; #define PM1_TMR_STS 0x0001 #define PM1_BM_STS 0x0010 #define PM1_GBL_STS 0x0020 #define PM1_PWRBTN_STS 0x0100 #define PM1_SLPBTN_STS 0x0200 #define PM1_RTC_STS 0x0400 #define PM1_WAK_STS 0x8000 #define PM1_TMR_EN 0x0001 #define PM1_GBL_EN 0x0020 #define PM1_PWRBTN_EN 0x0100 #define PM1_SLPBTN_EN 0x0200 #define PM1_RTC_EN 0x0400 static void sci_update(struct vmctx *ctx) { int need_sci; /* See if the SCI should be active or not. */ need_sci = 0; if ((pm1_enable & PM1_TMR_EN) && (pm1_status & PM1_TMR_STS)) need_sci = 1; if ((pm1_enable & PM1_GBL_EN) && (pm1_status & PM1_GBL_STS)) need_sci = 1; if ((pm1_enable & PM1_PWRBTN_EN) && (pm1_status & PM1_PWRBTN_STS)) need_sci = 1; if ((pm1_enable & PM1_SLPBTN_EN) && (pm1_status & PM1_SLPBTN_STS)) need_sci = 1; if ((pm1_enable & PM1_RTC_EN) && (pm1_status & PM1_RTC_STS)) need_sci = 1; if (need_sci) sci_assert(ctx); else sci_deassert(ctx); } static int pm1_status_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg) { if (bytes != 2) return (-1); pthread_mutex_lock(&pm_lock); if (in) *eax = pm1_status; else { /* * Writes are only permitted to clear certain bits by * writing 1 to those flags. */ pm1_status &= ~(*eax & (PM1_WAK_STS | PM1_RTC_STS | PM1_SLPBTN_STS | PM1_PWRBTN_STS | PM1_BM_STS)); sci_update(ctx); } pthread_mutex_unlock(&pm_lock); return (0); } static int pm1_enable_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg) { if (bytes != 2) return (-1); pthread_mutex_lock(&pm_lock); if (in) *eax = pm1_enable; else { /* * Only permit certain bits to be set. We never use * the global lock, but ACPI-CA whines profusely if it * can't set GBL_EN. */ pm1_enable = *eax & (PM1_PWRBTN_EN | PM1_GBL_EN); sci_update(ctx); } pthread_mutex_unlock(&pm_lock); return (0); } INOUT_PORT(pm1_status, PM1A_EVT_ADDR, IOPORT_F_INOUT, pm1_status_handler); INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler); static void power_button_handler(int signal, enum ev_type type, void *arg) { struct vmctx *ctx; ctx = arg; pthread_mutex_lock(&pm_lock); if (!(pm1_status & PM1_PWRBTN_STS)) { pm1_status |= PM1_PWRBTN_STS; sci_update(ctx); } pthread_mutex_unlock(&pm_lock); } /* * Power Management 1 Control Register * * This is mostly unimplemented except that we wish to handle writes that * set SPL_EN to handle S5 (soft power off). */ static uint16_t pm1_control; #define PM1_SCI_EN 0x0001 #define PM1_SLP_TYP 0x1c00 #define PM1_SLP_EN 0x2000 #define PM1_ALWAYS_ZERO 0xc003 static int pm1_control_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg) { int error; if (bytes != 2) return (-1); if (in) *eax = pm1_control; else { /* * Various bits are write-only or reserved, so force them * to zero in pm1_control. Always preserve SCI_EN as OSPM * can never change it. */ pm1_control = (pm1_control & PM1_SCI_EN) | (*eax & ~(PM1_SLP_EN | PM1_ALWAYS_ZERO)); /* * If SLP_EN is set, check for S5. Bhyve's _S5_ method * says that '5' should be stored in SLP_TYP for S5. */ if (*eax & PM1_SLP_EN) { if ((pm1_control & PM1_SLP_TYP) >> 10 == 5) { error = vm_suspend(ctx, VM_SUSPEND_POWEROFF); assert(error == 0 || errno == EALREADY); } } } return (0); } INOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler); SYSRES_IO(PM1A_EVT_ADDR, 8); /* * ACPI SMI Command Register * * This write-only register is used to enable and disable ACPI. */ static int smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, uint32_t *eax, void *arg) { assert(!in); if (bytes != 1) return (-1); pthread_mutex_lock(&pm_lock); switch (*eax) { case BHYVE_ACPI_ENABLE: pm1_control |= PM1_SCI_EN; if (power_button == NULL) { power_button = mevent_add(SIGTERM, EVF_SIGNAL, power_button_handler, ctx); old_power_handler = signal(SIGTERM, SIG_IGN); } break; case BHYVE_ACPI_DISABLE: pm1_control &= ~PM1_SCI_EN; if (power_button != NULL) { mevent_delete(power_button); power_button = NULL; signal(SIGTERM, old_power_handler); } break; } pthread_mutex_unlock(&pm_lock); return (0); } INOUT_PORT(smi_cmd, SMI_CMD, IOPORT_F_OUT, smi_cmd_handler); SYSRES_IO(SMI_CMD, 1); void sci_init(struct vmctx *ctx) { /* * Mark ACPI's SCI as level trigger and bump its use count * in the PIRQ router. */ pci_irq_use(SCI_INT); vm_isa_set_irq_trigger(ctx, SCI_INT, LEVEL_TRIGGER); } Index: stable/10/usr.sbin/etcupdate/etcupdate.8 =================================================================== --- stable/10/usr.sbin/etcupdate/etcupdate.8 (revision 283926) +++ stable/10/usr.sbin/etcupdate/etcupdate.8 (revision 283927) @@ -1,888 +1,888 @@ -.\" Copyright (c) 2010-2013 Advanced Computing Technologies LLC +.\" Copyright (c) 2010-2013 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 29, 2014 .Dt ETCUPDATE 8 .Os .Sh NAME .Nm etcupdate .Nd "manage updates to system files not updated by installworld" .Sh SYNOPSIS .Nm .Op Fl npBF .Op Fl d Ar workdir .Op Fl r | Fl s Ar source | Fl t Ar tarball .Op Fl A Ar patterns .Op Fl D Ar destdir .Op Fl I Ar patterns .Op Fl L Ar logfile .Op Fl M Ar options .Nm .Cm build .Op Fl B .Op Fl d Ar workdir .Op Fl s Ar source .Op Fl L Ar logfile .Op Fl M Ar options .Ar tarball .Nm .Cm diff .Op Fl d Ar workdir .Op Fl D Ar destdir .Op Fl I Ar patterns .Op Fl L Ar logfile .Nm .Cm extract .Op Fl B .Op Fl d Ar workdir .Op Fl s Ar source | Fl t Ar tarball .Op Fl L Ar logfile .Op Fl M Ar options .Nm .Cm resolve .Op Fl p .Op Fl d Ar workdir .Op Fl D Ar destdir .Op Fl L Ar logfile .Nm .Cm status .Op Fl d Ar workdir .Op Fl D Ar destdir .Sh DESCRIPTION The .Nm utility is a tool for managing updates to files that are not updated as part of .Sq make installworld such as files in .Pa /etc . It manages updates by doing a three-way merge of changes made to these files against the local versions. It is also designed to minimize the amount of user intervention with the goal of simplifying upgrades for clusters of machines. .Pp To perform a three-way merge, .Nm keeps copies of the current and previous versions of files that it manages. These copies are stored in two trees known as the .Dq current and .Dq previous trees. During a merge, .Nm compares the .Dq current and .Dq previous copies of each file to determine which changes need to be merged into the local version of each file. If a file can be updated without generating a conflict, .Nm will update the file automatically. If the local changes to a file conflict with the changes made to a file in the source tree, then a merge conflict is generated. The conflict must be resolved after the merge has finished. The .Nm utility will not perform a new merge until all conflicts from an earlier merge are resolved. .Sh MODES The .Nm utility supports several modes of operation. The mode is specified via an optional command argument. If present, the command must be the first argument on the command line. If a command is not specified, the default mode is used. .Ss Default Mode The default mode merges changes from the source tree to the destination directory. First, it updates the .Dq current and .Dq previous trees. Next, it compares the two trees merging changes into the destination directory. Finally, it displays warnings for any conditions it could not handle automatically. .Pp If the .Fl r option is not specified, then the first step taken is to update the .Dq current and .Dq previous trees. If a .Dq current tree already exists, then that tree is saved as the .Dq previous tree. An older .Dq previous tree is removed if it exists. By default the new .Dq current tree is built from a source tree. However, if a tarball is specified via the .Fl t option, then the tree is extracted from that tarball instead. .Pp Next, .Nm compares the files in the .Dq current and .Dq previous trees. If a file was removed from the .Dq current tree, then it will be removed from the destination directory only if it does not have any local modifications. If a file was added to the .Dq current tree, then it will be copied to the destination directory only if it would not clobber an existing file. If a file is changed in the .Dq current tree, then .Nm will attempt to merge the changes into the version of the file in the destination directory. If the merge encounters conflicts, then a version of the file with conflict markers will be saved for future resolution. If the merge does not encounter conflicts, then the merged version of the file will be saved in the destination directory. If .Nm is not able to safely merge in changes to a file other than a merge conflict, it will generate a warning. .Pp For each file that is updated a line will be output with a leading character to indicate the action taken. The possible actions follow: .Pp .Bl -tag -width "A" -compact -offset indent .It A Added .It C Conflict .It D Deleted .It M Merged .It U Updated .El .Pp Finally, if any warnings were encountered they are displayed after the merge has completed. .Pp Note that for certain files .Nm will perform post-install actions any time that the file is updated. Specifically, .Xr pwd_mkdb 8 is invoked if .Pa /etc/master.passwd is changed, .Xr cap_mkdb 1 is invoked to update .Pa /etc/login.conf.db if .Pa /etc/login.conf is changed, .Xr newaliases 1 is invoked if .Pa /etc/mail/aliases is changed, and .Pa /etc/rc.d/motd is invoked if .Pa /etc/motd is changed. One exception is that if .Pa /etc/mail/aliases is changed and the destination directory is not the default, then a warning will be issued instead. This is due to a limitation of the .Xr newaliases 1 command. Similarly, if .Pa /etc/motd is changed and the destination directory is not the default, then .Pa /etc/rc.d/motd will not be executed due to a limitation of that script. In this case no warning is issued as the result of .Pa /etc/rc.d/motd is merely cosmetic and will be corrected on the next reboot. .Ss Build Mode The .Cm build mode is used to build a tarball that contains a snapshot of a .Dq current tree. This tarball can be used by the default and extract modes. Using a tarball can allow .Nm to perform a merge without requiring a source tree that matches the currently installed world. The .Fa tarball argument specifies the name of the file to create. The file will be a .Xr tar 5 file compressed with .Xr bzip2 1 . .Ss Diff Mode The .Cm diff mode compares the versions of files in the destination directory to the .Dq current tree and generates a unified format diff of the changes. This can be used to determine which files have been locally modified and how. Note that .Nm does not manage files that are not maintained in the source tree such as .Pa /etc/fstab and .Pa /etc/rc.conf . .Ss Extract Mode The .Cm extract mode generates a new .Dq current tree. Unlike the default mode, it does not save any existing .Dq current tree and does not modify any existing .Dq previous tree. The new .Dq current tree can either be built from a source tree or extracted from a tarball. .Ss Resolve Mode The .Cm resolve mode is used to resolve any conflicts encountered during a merge. In this mode, .Nm iterates over any existing conflicts prompting the user for actions to take on each conflicted file. For each file, the following actions are available: .Pp .Bl -tag -width "(tf) theirs-full" -compact .It (p) postpone Ignore this conflict for now. .It (df) diff-full Show all changes made to the merged file as a unified diff. .It (e) edit Change the merged file in an editor. .It (r) resolved Install the merged version of the file into the destination directory. .It (mf) mine-full Use the version of the file in the destination directory and ignore any changes made to the file in the .Dq current tree. .It (tf) theirs-full Use the version of the file from the .Dq current tree and discard any local changes made to the file. .It (h) help Display the list of commands. .El .Ss Status Mode The .Cm status mode shows a summary of the results of the most recent merge. First it lists any files for which there are unresolved conflicts. Next it lists any warnings generated during the last merge. If the last merge did not generate any conflicts or warnings, then nothing will be output. .Sh OPTIONS The following options are available. Note that most options do not apply to all modes. .Bl -tag -width ".Fl A Ar patterns" .It Fl A Ar patterns Always install the new version of any files that match any of the patterns listed in .Ar patterns . Each pattern is evaluated as an .Xr sh 1 shell pattern. This option may be specified multiple times to specify multiple patterns. Multiple space-separated patterns may also be specified in a single option. Note that ignored files specified via the .Ev IGNORE_FILES variable or the .Fl I option will not be installed. .It Fl B Do not build generated files in a private object tree. Instead, reuse the generated files from a previously built object tree that matches the source tree. This can be useful to avoid gratuitous conflicts in .Xr sendmail 8 configuration files when bootstrapping. It can also be useful for building a tarball that matches a specific world build. .It Fl D Ar destdir Specify an alternate destination directory as the target of a merge. This is analogous to the .Dv DESTDIR variable used with .Sq make installworld . The default destination directory is an empty string which results in merges updating .Pa /etc on the local machine. .It Fl d Ar workdir Specify an alternate directory to use as the work directory. The work directory is used to store the .Dq current and .Dq previous trees as well as unresolved conflicts. The default work directory is .Pa /var/db/etcupdate . .It Fl F Ignore changes in the FreeBSD ID string when comparing files in the destination directory to files in either of the .Dq current or .Dq previous trees. In .Cm diff mode, this reduces noise due to FreeBSD ID string changes in the output. During an update this can simplify handling for harmless conflicts caused by FreeBSD ID string changes. .Pp Specifically, if a file in the destination directory is identical to the same file in the .Dq previous tree modulo the FreeBSD ID string, then the file is treated as if it was unmodified and the .Dq current version of the file will be installed. Similarly, if a file in the destination directory is identical to the same file in the .Dq current tree modulo the FreeBSD ID string, then the .Dq current version of the file will be installed to update the ID string. If the .Dq previous and .Dq current versions of the file are identical, then .Nm will not change the file in the destination directory. .Pp Due to limitations in the .Xr diff 1 command, this option may not have an effect if there are other changes in a file that are close to the FreeBSD ID string. .It Fl I Ar patterns Ignore any files that match any of the patterns listed in .Ar patterns . No warnings or other messages will be generated for those files during a merge. Each pattern is evaluated as an .Xr sh 1 shell pattern. This option may be specified multiple times to specify multiple patterns. Multiple space-separated patterns may also be specified in a single option. .It Fl L Ar logfile Specify an alternate path for the log file. The .Nm utility logs each command that it invokes along with the standard output and standard error to this file. By default the log file is stored in a file named .Pa log in the work directory. .It Fl M Ar options Pass .Ar options as additional parameters to .Xr make 1 when building a .Dq current tree. This can be used for to set the .Dv TARGET or .Dv TARGET_ARCH variables for a cross-build. .It Fl n Enable .Dq dry-run mode. Do not merge any changes to the destination directory. Instead, report what actions would be taken during a merge. Note that the existing .Dq current and .Dq previous trees will not be changed. If the .Fl r option is not specified, then a temporary .Dq current tree will be extracted to perform the comparison. .It Fl p Enable .Dq pre-world mode. Only merge changes to files that are necessary to successfully run .Sq make installworld or .Sq make installkernel . When this flag is enabled, the existing .Dq current and .Dq previous trees are left alone. Instead, a temporary tree is populated with the necessary files. This temporary tree is compared against the .Dq current tree. This allows a normal update to be run after .Sq make installworld has completed. Any conflicts generated during a .Dq pre-world update should be resolved by a .Dq pre-world .Cm resolve . .It Fl r Do not update the .Dq current and .Dq previous trees during a merge. This can be used to .Dq re-run a previous merge operation. .It Fl s Ar source Specify an alternate source tree to use when building or extracting a .Dq current tree. The default source tree is .Pa /usr/src . .It Fl t Ar tarball Extract a new .Dq current tree from a tarball previously generated by the .Cm build command rather than building the tree from a source tree. .El .Sh CONFIG FILE The .Nm utility can also be configured by setting variables in an optional configuration file named .Pa /etc/etcupdate.conf . Note that command line options override settings in the configuration file. The configuration file is executed by .Xr sh 1 , so it uses that syntax to set configuration variables. The following variables can be set: .Bl -tag -width ".Ev ALWAYS_INSTALL" .It Ev ALWAYS_INSTALL Always install files that match any of the patterns listed in this variable similar to the .Fl A option. .It Ev DESTDIR Specify an alternate destination directory similar to the .Fl D option. .It Ev EDITOR Specify a program to edit merge conflicts. .It Ev FREEBSD_ID Ignore changes in the FreeBSD ID string similar to the .Fl F option. This is enabled by setting the variable to a non-empty value. .It Ev IGNORE_FILES Ignore files that match any of the patterns listed in this variable similar to the .Fl I option. .It Ev LOGFILE Specify an alternate path for the log file similar to the .Fl L option. .It Ev MAKE_OPTIONS Pass additional options to .Xr make 1 when building a .Dq current tree similar to the .Fl M option. .It Ev SRCDIR Specify an alternate source tree similar to the .Fl s option. .It Ev WORKDIR Specify an alternate work directory similar to the .Fl d option. .El .Sh ENVIRONMENT The .Nm utility uses the program identified in the .Ev EDITOR environment variable to edit merge conflicts. If .Ev EDITOR is not set, .Xr vi 1 is used as the default editor. .Sh FILES .Bl -tag -width ".Pa /var/db/etcupdate/log" -compact .It Pa /etc/etcupdate.conf Optional config file. .It Pa /var/db/etcupdate Default work directory used to store trees and other data. .It Pa /var/db/etcupdate/log Default log file. .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES To compare the files in .Pa /etc with the stock versions: .Pp .Dl "etcupdate diff" .Pp To merge changes after an upgrade via the buildworld and installworld process: .Pp .Dl "etcupdate" .Pp To resolve any conflicts generated during a merge: .Pp .Dl "etcupdate resolve" .Ss Bootstrapping The .Nm utility may need to be bootstrapped before it can be used. The .Cm diff command will fail with an error about a missing reference tree if bootstrapping is needed. .Pp Bootstrapping .Nm requires a source tree that matches the currently installed world. The easiest way to ensure this is to bootstrap .Nm before updating the source tree to start the next world upgrade cycle. First, generate a reference tree: .Pp .Dl "etcupdate extract" .Pp Second, use the .Cm diff command to compare the reference tree to your current files in .Pa /etc . Undesired differences should be removed using an editor, .Xr patch 1 , or by copying files from the reference tree .Po located at .Pa /var/db/etcupdate/current by default .Pc . .Pp If the tree at .Pa /usr/src is already newer than the currently installed world, a new tree matching the currently installed world can be checked out to a temporary location. The reference tree for .Nm can then be generated via: .Pp .Dl "etcupdate extract -s /path/to/tree" .Pp The .Cm diff command can be used as above to remove undesired differences. Afterwards, the changes in the tree at .Pa /usr/src can be merged via a regular merge. .Sh DIAGNOSTICS The following warning messages may be generated during a merge. Note that several of these warnings cover obscure cases that should occur rarely if at all in practice. For example, if a file changes from a file to a directory in the .Dq current tree and the file was modified in the destination directory, then a warning will be triggered. In general, when a warning references a pathname, the corresponding file in the destination directory is not changed by a merge operation. .Bl -diag .It "Directory mismatch: ()" An attempt was made to create a directory at .Pa path but an existing file of type .Dq type already exists for that path name. .It "Modified link changed: ( became )" The target of a symbolic link named .Pa file was changed from .Dq old to .Dq new in the .Dq current tree. The symbolic link has been modified to point to a target that is neither .Dq old nor .Dq new in the destination directory. .It "Modified mismatch: ( vs )" A file named .Pa file of type .Dq new was modified in the .Dq current tree, but the file exists as a different type .Dq dest in the destination directory. .It "Modified changed: ( became )" A file named .Pa file changed type from .Dq old in the .Dq previous tree to type .Dq new in the .Dq current tree. The file in the destination directory of type .Dq type has been modified, so it could not be merged automatically. .It "Modified remains: " The file of type .Dq type named .Pa file has been removed from the .Dq current tree, but it has been locally modified. The modified version of the file remains in the destination directory. .It "Needs update: /etc/localtime (required manual update via tzsetup(1))" The .Fa /var/db/zoneinfo file does not exist, so .Nm was not able to refresh .Fa /etc/localtime from its source file in .Fa /usr/share/zoneinfo . Running .Xr tzsetup 1 will both refresh .Fa /etc/localtime and generate .Fa /var/db/zoneinfo permitting future updates to refresh .Fa /etc/localtime automatically. .It "Needs update: /etc/mail/aliases.db (required manual update via newaliases(1))" The file .Pa /etc/mail/aliases was updated during a merge with a non-empty destination directory. Due to a limitation of the .Xr newaliases 1 command, .Nm was not able to automatically update the corresponding aliases database. .It "New file mismatch: ( vs )" A new file named .Pa file of type .Dq new has been added to the .Dq current tree. A file of that name already exists in the destination directory, but it is of a different type .Dq dest . .It "New link conflict: ( vs )" A symbolic link named .Pa file has been added to the .Dq current tree that links to .Dq new . A symbolic link of the same name already exists in the destination directory, but it links to a different target .Dq dest . .It "Non-empty directory remains: " The directory .Pa file was removed from the .Dq current tree, but it contains additional files in the destination directory. These additional files as well as the directory remain. .It "Remove mismatch: ( became )" A file named .Pa file changed from type .Dq old in the .Dq previous tree to type .Dq new in the .Dq current tree, but it has been removed in the destination directory. .It "Removed file changed: " A file named .Pa file was modified in the .Dq current tree, but it has been removed in the destination directory. .It "Removed link changed: ( became )" The target of a symbolic link named .Pa file was changed from .Dq old to .Dq new in the .Dq current tree, but it has been removed in the destination directory. .El .Sh SEE ALSO .Xr cap_mkdb 1 , .Xr diff 1 , .Xr make 1 , .Xr newaliases 1 , .Xr sh 1 , .Xr pwd_mkdb 8 .Sh HISTORY The .Nm utility first appeared in .Fx 10.0 . .Sh AUTHORS The .Nm utility was written by .An John Baldwin Aq jhb@FreeBSD.org . .Sh BUGS Rerunning a merge does not automatically delete conflicts left over from a previous merge. Any conflicts must be resolved before the merge can be rerun. It it is not clear if this is a feature or a bug. .Pp There is no way to easily automate conflict resolution for specific files. For example, one can imagine a syntax along the lines of .Pp .Dl "etcupdate resolve tf /some/file" .Pp to resolve a specific conflict in an automated fashion. .Pp It might be nice to have something like a .Sq revert command to replace a locally modified version of a file with the stock version of the file. For example: .Pp .Dl "etcupdate revert /etc/mail/freebsd.cf" .Pp Bootstrapping .Nm often results in gratuitous diffs in .Pa /etc/mail/*.cf that cause conflicts in the first merge. If an object tree that matches the source tree is present when bootstrapping, then passing the .Fl B flag to the .Cm extract command can work around this. Index: stable/10/usr.sbin/etcupdate/etcupdate.sh =================================================================== --- stable/10/usr.sbin/etcupdate/etcupdate.sh (revision 283926) +++ stable/10/usr.sbin/etcupdate/etcupdate.sh (revision 283927) @@ -1,1794 +1,1794 @@ #!/bin/sh # -# Copyright (c) 2010-2013 Advanced Computing Technologies LLC +# Copyright (c) 2010-2013 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # This is a tool to manage updating files that are not updated as part # of 'make installworld' such as files in /etc. Unlike other tools, # this one is specifically tailored to assisting with mass upgrades. # To that end it does not require user intervention while running. # # Theory of operation: # # The most reliable way to update changes to files that have local # modifications is to perform a three-way merge between the original # unmodified file, the new version of the file, and the modified file. # This requires having all three versions of the file available when # performing an update. # # To that end, etcupdate uses a strategy where the current unmodified # tree is kept in WORKDIR/current and the previous unmodified tree is # kept in WORKDIR/old. When performing a merge, a new tree is built # if needed and then the changes are merged into DESTDIR. Any files # with unresolved conflicts after the merge are left in a tree rooted # at WORKDIR/conflicts. # # To provide extra flexibility, etcupdate can also build tarballs of # root trees that can later be used. It can also use a tarball as the # source of a new tree instead of building it from /usr/src. # Global settings. These can be adjusted by config files and in some # cases by command line options. # TODO: # - automatable conflict resolution # - a 'revert' command to make a file "stock" usage() { cat < etcupdate diff [-d workdir] [-D destdir] [-I patterns] [-L logfile] etcupdate extract [-B] [-d workdir] [-s source | -t tarball] [-L logfile] [-M options] etcupdate resolve [-p] [-d workdir] [-D destdir] [-L logfile] etcupdate status [-d workdir] [-D destdir] EOF exit 1 } # Used to write a message prepended with '>>>' to the logfile. log() { echo ">>>" "$@" >&3 } # Used for assertion conditions that should never happen. panic() { echo "PANIC:" "$@" exit 10 } # Used to write a warning message. These are saved to the WARNINGS # file with " " prepended. warn() { echo -n " " >> $WARNINGS echo "$@" >> $WARNINGS } # Output a horizontal rule using the passed-in character. Matches the # length used for Index lines in CVS and SVN diffs. # # $1 - character rule() { jot -b "$1" -s "" 67 } # Output a text description of a specified file's type. # # $1 - file pathname. file_type() { stat -f "%HT" $1 | tr "[:upper:]" "[:lower:]" } # Returns true (0) if a file exists # # $1 - file pathname. exists() { [ -e $1 -o -L $1 ] } # Returns true (0) if a file should be ignored, false otherwise. # # $1 - file pathname ignore() { local pattern - set -o noglob for pattern in $IGNORE_FILES; do set +o noglob case $1 in $pattern) return 0 ;; esac set -o noglob done # Ignore /.cshrc and /.profile if they are hardlinked to the # same file in /root. This ensures we only compare those # files once in that case. case $1 in /.cshrc|/.profile) if [ ${DESTDIR}$1 -ef ${DESTDIR}/root$1 ]; then return 0 fi ;; *) ;; esac return 1 } # Returns true (0) if the new version of a file should always be # installed rather than attempting to do a merge. # # $1 - file pathname always_install() { local pattern - set -o noglob for pattern in $ALWAYS_INSTALL; do set +o noglob case $1 in $pattern) return 0 ;; esac set -o noglob done return 1 } # Build a new tree # # $1 - directory to store new tree in build_tree() { local destdir dir file make make="make $MAKE_OPTIONS" log "Building tree at $1 with $make" mkdir -p $1/usr/obj >&3 2>&1 destdir=`realpath $1` if [ -n "$preworld" ]; then # Build a limited tree that only contains files that are # crucial to installworld. for file in $PREWORLD_FILES; do dir=`dirname /$file` mkdir -p $1/$dir >&3 2>&1 || return 1 cp -p $SRCDIR/$file $1/$file || return 1 done elif ! [ -n "$nobuild" ]; then (cd $SRCDIR; $make DESTDIR=$destdir distrib-dirs && MAKEOBJDIRPREFIX=$destdir/usr/obj $make _obj SUBDIR_OVERRIDE=etc && MAKEOBJDIRPREFIX=$destdir/usr/obj $make everything SUBDIR_OVERRIDE=etc && MAKEOBJDIRPREFIX=$destdir/usr/obj $make DESTDIR=$destdir distribution) \ >&3 2>&1 || return 1 else (cd $SRCDIR; $make DESTDIR=$destdir distrib-dirs && $make DESTDIR=$destdir distribution) >&3 2>&1 || return 1 fi chflags -R noschg $1 >&3 2>&1 || return 1 rm -rf $1/usr/obj >&3 2>&1 || return 1 # Purge auto-generated files. Only the source files need to # be updated after which these files are regenerated. rm -f $1/etc/*.db $1/etc/passwd >&3 2>&1 || return 1 # Remove empty files. These just clutter the output of 'diff'. find $1 -type f -size 0 -delete >&3 2>&1 || return 1 # Trim empty directories. find -d $1 -type d -empty -delete >&3 2>&1 || return 1 return 0 } # Generate a new NEWTREE tree. If tarball is set, then the tree is # extracted from the tarball. Otherwise the tree is built from a # source tree. extract_tree() { local files # If we have a tarball, extract that into the new directory. if [ -n "$tarball" ]; then files= if [ -n "$preworld" ]; then files="$PREWORLD_FILES" fi if ! (mkdir -p $NEWTREE && tar xf $tarball -C $NEWTREE $files) \ >&3 2>&1; then echo "Failed to extract new tree." remove_tree $NEWTREE exit 1 fi else if ! build_tree $NEWTREE; then echo "Failed to build new tree." remove_tree $NEWTREE exit 1 fi fi } # Forcefully remove a tree. Returns true (0) if the operation succeeds. # # $1 - path to tree remove_tree() { rm -rf $1 >&3 2>&1 if [ -e $1 ]; then chflags -R noschg $1 >&3 2>&1 rm -rf $1 >&3 2>&1 fi [ ! -e $1 ] } # Return values for compare() COMPARE_EQUAL=0 COMPARE_ONLYFIRST=1 COMPARE_ONLYSECOND=2 COMPARE_DIFFTYPE=3 COMPARE_DIFFLINKS=4 COMPARE_DIFFFILES=5 # Compare two files/directories/symlinks. Note that this does not # recurse into subdirectories. Instead, if two nodes are both # directories, they are assumed to be equivalent. # # Returns true (0) if the nodes are identical. If only one of the two # nodes are present, return one of the COMPARE_ONLY* constants. If # the nodes are different, return one of the COMPARE_DIFF* constants # to indicate the type of difference. # # $1 - first node # $2 - second node compare() { local first second # If the first node doesn't exist, then check for the second # node. Note that -e will fail for a symbolic link that # points to a missing target. if ! exists $1; then if exists $2; then return $COMPARE_ONLYSECOND else return $COMPARE_EQUAL fi elif ! exists $2; then return $COMPARE_ONLYFIRST fi # If the two nodes are different file types fail. first=`stat -f "%Hp" $1` second=`stat -f "%Hp" $2` if [ "$first" != "$second" ]; then return $COMPARE_DIFFTYPE fi # If both are symlinks, compare the link values. if [ -L $1 ]; then first=`readlink $1` second=`readlink $2` if [ "$first" = "$second" ]; then return $COMPARE_EQUAL else return $COMPARE_DIFFLINKS fi fi # If both are files, compare the file contents. if [ -f $1 ]; then if cmp -s $1 $2; then return $COMPARE_EQUAL else return $COMPARE_DIFFFILES fi fi # As long as the two nodes are the same type of file, consider # them equivalent. return $COMPARE_EQUAL } # Returns true (0) if the only difference between two regular files is a # change in the FreeBSD ID string. # # $1 - path of first file # $2 - path of second file fbsdid_only() { diff -qI '\$FreeBSD.*\$' $1 $2 >/dev/null 2>&1 } # This is a wrapper around compare that will return COMPARE_EQUAL if # the only difference between two regular files is a change in the # FreeBSD ID string. It only makes this adjustment if the -F flag has # been specified. # # $1 - first node # $2 - second node compare_fbsdid() { local cmp compare $1 $2 cmp=$? if [ -n "$FREEBSD_ID" -a "$cmp" -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $1 $2; then return $COMPARE_EQUAL fi return $cmp } # Returns true (0) if a directory is empty. # # $1 - pathname of the directory to check empty_dir() { local contents contents=`ls -A $1` [ -z "$contents" ] } # Returns true (0) if one directories contents are a subset of the # other. This will recurse to handle subdirectories and compares # individual files in the trees. Its purpose is to quiet spurious # directory warnings for dryrun invocations. # # $1 - first directory (sub) # $2 - second directory (super) dir_subset() { local contents file if ! [ -d $1 -a -d $2 ]; then return 1 fi # Ignore files that are present in the second directory but not # in the first. contents=`ls -A $1` for file in $contents; do if ! compare $1/$file $2/$file; then return 1 fi if [ -d $1/$file ]; then if ! dir_subset $1/$file $2/$file; then return 1 fi fi done return 0 } # Returns true (0) if a directory in the destination tree is empty. # If this is a dryrun, then this returns true as long as the contents # of the directory are a subset of the contents in the old tree # (meaning that the directory would be empty in a non-dryrun when this # was invoked) to quiet spurious warnings. # # $1 - pathname of the directory to check relative to DESTDIR. empty_destdir() { if [ -n "$dryrun" ]; then dir_subset $DESTDIR/$1 $OLDTREE/$1 return fi empty_dir $DESTDIR/$1 } # Output a diff of two directory entries with the same relative name # in different trees. Note that as with compare(), this does not # recurse into subdirectories. If the nodes are identical, nothing is # output. # # $1 - first tree # $2 - second tree # $3 - node name # $4 - label for first tree # $5 - label for second tree diffnode() { local first second file old new diffargs if [ -n "$FREEBSD_ID" ]; then diffargs="-I \\\$FreeBSD.*\\\$" else diffargs="" fi compare_fbsdid $1/$3 $2/$3 case $? in $COMPARE_EQUAL) ;; $COMPARE_ONLYFIRST) echo echo "Removed: $3" echo ;; $COMPARE_ONLYSECOND) echo echo "Added: $3" echo ;; $COMPARE_DIFFTYPE) first=`file_type $1/$3` second=`file_type $2/$3` echo echo "Node changed from a $first to a $second: $3" echo ;; $COMPARE_DIFFLINKS) first=`readlink $1/$file` second=`readlink $2/$file` echo echo "Link changed: $file" rule "=" echo "-$first" echo "+$second" echo ;; $COMPARE_DIFFFILES) echo "Index: $3" rule "=" diff -u $diffargs -L "$3 ($4)" $1/$3 -L "$3 ($5)" $2/$3 ;; esac } # Run one-off commands after an update has completed. These commands # are not tied to a specific file, so they cannot be handled by # post_install_file(). post_update() { local args # None of these commands should be run for a pre-world update. if [ -n "$preworld" ]; then return fi # If /etc/localtime exists and is not a symlink and /var/db/zoneinfo # exists, run tzsetup -r to refresh /etc/localtime. if [ -f ${DESTDIR}/etc/localtime -a \ ! -L ${DESTDIR}/etc/localtime ]; then if [ -f ${DESTDIR}/var/db/zoneinfo ]; then if [ -n "${DESTDIR}" ]; then args="-C ${DESTDIR}" else args="" fi log "tzsetup -r ${args}" if [ -z "$dryrun" ]; then tzsetup -r ${args} >&3 2>&1 fi else warn "Needs update: /etc/localtime (required" \ "manual update via tzsetup(1))" fi fi } # Create missing parent directories of a node in a target tree # preserving the owner, group, and permissions from a specified # template tree. # # $1 - template tree # $2 - target tree # $3 - pathname of the node (relative to both trees) install_dirs() { local args dir dir=`dirname $3` # Nothing to do if the parent directory exists. This also # catches the degenerate cases when the path is just a simple # filename. if [ -d ${2}$dir ]; then return 0 fi # If non-directory file exists with the desired directory # name, then fail. if exists ${2}$dir; then # If this is a dryrun and we are installing the # directory in the DESTDIR and the file in the DESTDIR # matches the file in the old tree, then fake success # to quiet spurious warnings. if [ -n "$dryrun" -a "$2" = "$DESTDIR" ]; then if compare $OLDTREE/$dir $DESTDIR/$dir; then return 0 fi fi args=`file_type ${2}$dir` warn "Directory mismatch: ${2}$dir ($args)" return 1 fi # Ensure the parent directory of the directory is present # first. if ! install_dirs $1 "$2" $dir; then return 1 fi # Format attributes from template directory as install(1) # arguments. args=`stat -f "-o %Su -g %Sg -m %0Mp%0Lp" $1/$dir` log "install -d $args ${2}$dir" if [ -z "$dryrun" ]; then install -d $args ${2}$dir >&3 2>&1 fi return 0 } # Perform post-install fixups for a file. This largely consists of # regenerating any files that depend on the newly installed file. # # $1 - pathname of the updated file (relative to DESTDIR) post_install_file() { case $1 in /etc/mail/aliases) # Grr, newaliases only works for an empty DESTDIR. if [ -z "$DESTDIR" ]; then log "newaliases" if [ -z "$dryrun" ]; then newaliases >&3 2>&1 fi else NEWALIAS_WARN=yes fi ;; /etc/login.conf) log "cap_mkdb ${DESTDIR}$1" if [ -z "$dryrun" ]; then cap_mkdb ${DESTDIR}$1 >&3 2>&1 fi ;; /etc/master.passwd) log "pwd_mkdb -p -d $DESTDIR/etc ${DESTDIR}$1" if [ -z "$dryrun" ]; then pwd_mkdb -p -d $DESTDIR/etc ${DESTDIR}$1 \ >&3 2>&1 fi ;; /etc/motd) # /etc/rc.d/motd hardcodes the /etc/motd path. # Don't warn about non-empty DESTDIR's since this # change is only cosmetic anyway. if [ -z "$DESTDIR" ]; then log "sh /etc/rc.d/motd start" if [ -z "$dryrun" ]; then sh /etc/rc.d/motd start >&3 2>&1 fi fi ;; /etc/services) log "services_mkdb -q -o $DESTDIR/var/db/services.db" \ "${DESTDIR}$1" if [ -z "$dryrun" ]; then services_mkdb -q -o $DESTDIR/var/db/services.db \ ${DESTDIR}$1 >&3 2>&1 fi ;; esac } # Install the "new" version of a file. Returns true if it succeeds # and false otherwise. # # $1 - pathname of the file to install (relative to DESTDIR) install_new() { if ! install_dirs $NEWTREE "$DESTDIR" $1; then return 1 fi log "cp -Rp ${NEWTREE}$1 ${DESTDIR}$1" if [ -z "$dryrun" ]; then cp -Rp ${NEWTREE}$1 ${DESTDIR}$1 >&3 2>&1 fi post_install_file $1 return 0 } # Install the "resolved" version of a file. Returns true if it succeeds # and false otherwise. # # $1 - pathname of the file to install (relative to DESTDIR) install_resolved() { # This should always be present since the file is already # there (it caused a conflict). However, it doesn't hurt to # just be safe. if ! install_dirs $NEWTREE "$DESTDIR" $1; then return 1 fi log "cp -Rp ${CONFLICTS}$1 ${DESTDIR}$1" cp -Rp ${CONFLICTS}$1 ${DESTDIR}$1 >&3 2>&1 post_install_file $1 return 0 } # Generate a conflict file when a "new" file conflicts with an # existing file in DESTDIR. # # $1 - pathname of the file that conflicts (relative to DESTDIR) new_conflict() { if [ -n "$dryrun" ]; then return fi install_dirs $NEWTREE $CONFLICTS $1 diff --changed-group-format='<<<<<<< (local) %<======= %>>>>>>>> (stock) ' $DESTDIR/$1 $NEWTREE/$1 > $CONFLICTS/$1 } # Remove the "old" version of a file. # # $1 - pathname of the old file to remove (relative to DESTDIR) remove_old() { log "rm -f ${DESTDIR}$1" if [ -z "$dryrun" ]; then rm -f ${DESTDIR}$1 >&3 2>&1 fi echo " D $1" } # Update a file that has no local modifications. # # $1 - pathname of the file to update (relative to DESTDIR) update_unmodified() { local new old # If the old file is a directory, then remove it with rmdir # (this should only happen if the file has changed its type # from a directory to a non-directory). If the directory # isn't empty, then fail. This will be reported as a warning # later. if [ -d $DESTDIR/$1 ]; then if empty_destdir $1; then log "rmdir ${DESTDIR}$1" if [ -z "$dryrun" ]; then rmdir ${DESTDIR}$1 >&3 2>&1 fi else return 1 fi # If both the old and new files are regular files, leave the # existing file. This avoids breaking hard links for /.cshrc # and /.profile. Otherwise, explicitly remove the old file. elif ! [ -f ${DESTDIR}$1 -a -f ${NEWTREE}$1 ]; then log "rm -f ${DESTDIR}$1" if [ -z "$dryrun" ]; then rm -f ${DESTDIR}$1 >&3 2>&1 fi fi # If the new file is a directory, note that the old file has # been removed, but don't do anything else for now. The # directory will be installed if needed when new files within # that directory are installed. if [ -d $NEWTREE/$1 ]; then if empty_dir $NEWTREE/$1; then echo " D $file" else echo " U $file" fi elif install_new $1; then echo " U $file" fi return 0 } # Update the FreeBSD ID string in a locally modified file to match the # FreeBSD ID string from the "new" version of the file. # # $1 - pathname of the file to update (relative to DESTDIR) update_freebsdid() { local new dest file # If the FreeBSD ID string is removed from the local file, # there is nothing to do. In this case, treat the file as # updated. Otherwise, if either file has more than one # FreeBSD ID string, just punt and let the user handle the # conflict manually. new=`grep -c '\$FreeBSD.*\$' ${NEWTREE}$1` dest=`grep -c '\$FreeBSD.*\$' ${DESTDIR}$1` if [ "$dest" -eq 0 ]; then return 0 fi if [ "$dest" -ne 1 -o "$dest" -ne 1 ]; then return 1 fi # If the FreeBSD ID string in the new file matches the FreeBSD ID # string in the local file, there is nothing to do. new=`grep '\$FreeBSD.*\$' ${NEWTREE}$1` dest=`grep '\$FreeBSD.*\$' ${DESTDIR}$1` if [ "$new" = "$dest" ]; then return 0 fi # Build the new file in three passes. First, copy all the # lines preceding the FreeBSD ID string from the local version # of the file. Second, append the FreeBSD ID string line from # the new version. Finally, append all the lines after the # FreeBSD ID string from the local version of the file. file=`mktemp $WORKDIR/etcupdate-XXXXXXX` awk '/\$FreeBSD.*\$/ { exit } { print }' ${DESTDIR}$1 >> $file awk '/\$FreeBSD.*\$/ { print }' ${NEWTREE}$1 >> $file awk '/\$FreeBSD.*\$/ { ok = 1; next } { if (ok) print }' \ ${DESTDIR}$1 >> $file # As an extra sanity check, fail the attempt if the updated # version of the file has any differences aside from the # FreeBSD ID string. if ! fbsdid_only ${DESTDIR}$1 $file; then rm -f $file return 1 fi log "cp $file ${DESTDIR}$1" if [ -z "$dryrun" ]; then cp $file ${DESTDIR}$1 >&3 2>&1 fi rm -f $file post_install_file $1 echo " M $1" return 0 } # Attempt to update a file that has local modifications. This routine # only handles regular files. If the 3-way merge succeeds without # conflicts, the updated file is installed. If the merge fails, the # merged version with conflict markers is left in the CONFLICTS tree. # # $1 - pathname of the file to merge (relative to DESTDIR) merge_file() { local res # Try the merge to see if there is a conflict. merge -q -p ${DESTDIR}$1 ${OLDTREE}$1 ${NEWTREE}$1 >/dev/null 2>&3 res=$? case $res in 0) # No conflicts, so just redo the merge to the # real file. log "merge ${DESTDIR}$1 ${OLDTREE}$1 ${NEWTREE}$1" if [ -z "$dryrun" ]; then merge ${DESTDIR}$1 ${OLDTREE}$1 ${NEWTREE}$1 fi post_install_file $1 echo " M $1" ;; 1) # Conflicts, save a version with conflict markers in # the conflicts directory. if [ -z "$dryrun" ]; then install_dirs $NEWTREE $CONFLICTS $1 log "cp -Rp ${DESTDIR}$1 ${CONFLICTS}$1" cp -Rp ${DESTDIR}$1 ${CONFLICTS}$1 >&3 2>&1 merge -A -q -L "yours" -L "original" -L "new" \ ${CONFLICTS}$1 ${OLDTREE}$1 ${NEWTREE}$1 fi echo " C $1" ;; *) panic "merge failed with status $res" ;; esac } # Returns true if a file contains conflict markers from a merge conflict. # # $1 - pathname of the file to resolve (relative to DESTDIR) has_conflicts() { egrep -q '^(<{7}|\|{7}|={7}|>{7}) ' $CONFLICTS/$1 } # Attempt to resolve a conflict. The user is prompted to choose an # action for each conflict. If the user edits the file, they are # prompted again for an action. The process is very similar to # resolving conflicts after an update or merge with Perforce or # Subversion. The prompts are modelled on a subset of the available # commands for resolving conflicts with Subversion. # # $1 - pathname of the file to resolve (relative to DESTDIR) resolve_conflict() { local command junk echo "Resolving conflict in '$1':" edit= while true; do # Only display the resolved command if the file # doesn't contain any conflicts. echo -n "Select: (p) postpone, (df) diff-full, (e) edit," if ! has_conflicts $1; then echo -n " (r) resolved," fi echo echo -n " (h) help for more options: " read command case $command in df) diff -u ${DESTDIR}$1 ${CONFLICTS}$1 ;; e) $EDITOR ${CONFLICTS}$1 ;; h) cat </dev/null 2>&1 fi echo " D $dir" else warn "Non-empty directory remains: $dir" fi fi } # Handle a file that exists in both the old and new trees. If the # file has not changed in the old and new trees, there is nothing to # do. If the file in the destination directory matches the new file, # there is nothing to do. If the file in the destination directory # matches the old file, then the new file should be installed. # Everything else becomes some sort of conflict with more detailed # handling. # # $1 - pathname of the file (relative to DESTDIR) handle_modified_file() { local cmp dest file new newdestcmp old file=$1 if ignore $file; then log "IGNORE: modified file $file" return fi compare $OLDTREE/$file $NEWTREE/$file cmp=$? if [ $cmp -eq $COMPARE_EQUAL ]; then return fi if [ $cmp -eq $COMPARE_ONLYFIRST -o $cmp -eq $COMPARE_ONLYSECOND ]; then panic "Changed file now missing" fi compare $NEWTREE/$file $DESTDIR/$file newdestcmp=$? if [ $newdestcmp -eq $COMPARE_EQUAL ]; then return fi # If the only change in the new file versus the destination # file is a change in the FreeBSD ID string and -F is # specified, just install the new file. if [ -n "$FREEBSD_ID" -a $newdestcmp -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $NEWTREE/$file $DESTDIR/$file; then if update_unmodified $file; then return else panic "Updating FreeBSD ID string failed" fi fi # If the local file is the same as the old file, install the # new file. If -F is specified and the only local change is # in the FreeBSD ID string, then install the new file as well. if compare_fbsdid $OLDTREE/$file $DESTDIR/$file; then if update_unmodified $file; then return fi fi # If the file was removed from the dest tree, just whine. if [ $newdestcmp -eq $COMPARE_ONLYFIRST ]; then # If the removed file matches an ALWAYS_INSTALL glob, # then just install the new version of the file. if always_install $file; then log "ALWAYS: adding $file" if ! [ -d $NEWTREE/$file ]; then if install_new $file; then echo " A $file" fi fi return fi # If the only change in the new file versus the old # file is a change in the FreeBSD ID string and -F is # specified, don't warn. if [ -n "$FREEBSD_ID" -a $cmp -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $OLDTREE/$file $NEWTREE/$file; then return fi case $cmp in $COMPARE_DIFFTYPE) old=`file_type $OLDTREE/$file` new=`file_type $NEWTREE/$file` warn "Remove mismatch: $file ($old became $new)" ;; $COMPARE_DIFFLINKS) old=`readlink $OLDTREE/$file` new=`readlink $NEWTREE/$file` warn \ "Removed link changed: $file (\"$old\" became \"$new\")" ;; $COMPARE_DIFFFILES) warn "Removed file changed: $file" ;; esac return fi # Treat the file as unmodified and force install of the new # file if it matches an ALWAYS_INSTALL glob. If the update # attempt fails, then fall through to the normal case so a # warning is generated. if always_install $file; then log "ALWAYS: updating $file" if update_unmodified $file; then return fi fi # If the only change in the new file versus the old file is a # change in the FreeBSD ID string and -F is specified, just # update the FreeBSD ID string in the local file. if [ -n "$FREEBSD_ID" -a $cmp -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $OLDTREE/$file $NEWTREE/$file; then if update_freebsdid $file; then continue fi fi # If the file changed types between the old and new trees but # the files in the new and dest tree are both of the same # type, treat it like an added file just comparing the new and # dest files. if [ $cmp -eq $COMPARE_DIFFTYPE ]; then case $newdestcmp in $COMPARE_DIFFLINKS) new=`readlink $NEWTREE/$file` dest=`readlink $DESTDIR/$file` warn \ "New link conflict: $file (\"$new\" vs \"$dest\")" return ;; $COMPARE_DIFFFILES) new_conflict $file echo " C $file" return ;; esac else # If the file has not changed types between the old # and new trees, but it is a different type in # DESTDIR, then just warn. if [ $newdestcmp -eq $COMPARE_DIFFTYPE ]; then new=`file_type $NEWTREE/$file` dest=`file_type $DESTDIR/$file` warn "Modified mismatch: $file ($new vs $dest)" return fi fi case $cmp in $COMPARE_DIFFTYPE) old=`file_type $OLDTREE/$file` new=`file_type $NEWTREE/$file` dest=`file_type $DESTDIR/$file` warn "Modified $dest changed: $file ($old became $new)" ;; $COMPARE_DIFFLINKS) old=`readlink $OLDTREE/$file` new=`readlink $NEWTREE/$file` warn \ "Modified link changed: $file (\"$old\" became \"$new\")" ;; $COMPARE_DIFFFILES) merge_file $file ;; esac } # Handle a file that has been added in the new tree. If the file does # not exist in DESTDIR, simply copy the file into DESTDIR. If the # file exists in the DESTDIR and is identical to the new version, do # nothing. Otherwise, generate a diff of the two versions of the file # and mark it as a conflict. # # $1 - pathname of the file (relative to DESTDIR) handle_added_file() { local cmp dest file new file=$1 if ignore $file; then log "IGNORE: added file $file" return fi compare $DESTDIR/$file $NEWTREE/$file cmp=$? case $cmp in $COMPARE_EQUAL) return ;; $COMPARE_ONLYFIRST) panic "Added file now missing" ;; $COMPARE_ONLYSECOND) # Ignore new directories. They will be # created as needed when non-directory nodes # are installed. if ! [ -d $NEWTREE/$file ]; then if install_new $file; then echo " A $file" fi fi return ;; esac # Treat the file as unmodified and force install of the new # file if it matches an ALWAYS_INSTALL glob. If the update # attempt fails, then fall through to the normal case so a # warning is generated. if always_install $file; then log "ALWAYS: updating $file" if update_unmodified $file; then return fi fi case $cmp in $COMPARE_DIFFTYPE) new=`file_type $NEWTREE/$file` dest=`file_type $DESTDIR/$file` warn "New file mismatch: $file ($new vs $dest)" ;; $COMPARE_DIFFLINKS) new=`readlink $NEWTREE/$file` dest=`readlink $DESTDIR/$file` warn "New link conflict: $file (\"$new\" vs \"$dest\")" ;; $COMPARE_DIFFFILES) # If the only change in the new file versus # the destination file is a change in the # FreeBSD ID string and -F is specified, just # install the new file. if [ -n "$FREEBSD_ID" ] && \ fbsdid_only $NEWTREE/$file $DESTDIR/$file; then if update_unmodified $file; then return else panic \ "Updating FreeBSD ID string failed" fi fi new_conflict $file echo " C $file" ;; esac } # Main routines for each command # Build a new tree and save it in a tarball. build_cmd() { local dir if [ $# -ne 1 ]; then echo "Missing required tarball." echo usage fi log "build command: $1" # Create a temporary directory to hold the tree dir=`mktemp -d $WORKDIR/etcupdate-XXXXXXX` if [ $? -ne 0 ]; then echo "Unable to create temporary directory." exit 1 fi if ! build_tree $dir; then echo "Failed to build tree." remove_tree $dir exit 1 fi if ! tar cfj $1 -C $dir . >&3 2>&1; then echo "Failed to create tarball." remove_tree $dir exit 1 fi remove_tree $dir } # Output a diff comparing the tree at DESTDIR to the current # unmodified tree. Note that this diff does not include files that # are present in DESTDIR but not in the unmodified tree. diff_cmd() { local file if [ $# -ne 0 ]; then usage fi # Requires an unmodified tree to diff against. if ! [ -d $NEWTREE ]; then echo "Reference tree to diff against unavailable." exit 1 fi # Unfortunately, diff alone does not quite provide the right # level of options that we want, so improvise. for file in `(cd $NEWTREE; find .) | sed -e 's/^\.//'`; do if ignore $file; then continue fi diffnode $NEWTREE "$DESTDIR" $file "stock" "local" done } # Just extract a new tree into NEWTREE either by building a tree or # extracting a tarball. This can be used to bootstrap updates by # initializing the current "stock" tree to match the currently # installed system. # # Unlike 'update', this command does not rotate or preserve an # existing NEWTREE, it just replaces any existing tree. extract_cmd() { if [ $# -ne 0 ]; then usage fi log "extract command: tarball=$tarball" if [ -d $NEWTREE ]; then if ! remove_tree $NEWTREE; then echo "Unable to remove current tree." exit 1 fi fi extract_tree } # Resolve conflicts left from an earlier merge. resolve_cmd() { local conflicts if [ $# -ne 0 ]; then usage fi if ! [ -d $CONFLICTS ]; then return fi if ! [ -d $NEWTREE ]; then echo "The current tree is not present to resolve conflicts." exit 1 fi conflicts=`(cd $CONFLICTS; find . ! -type d) | sed -e 's/^\.//'` for file in $conflicts; do resolve_conflict $file done if [ -n "$NEWALIAS_WARN" ]; then warn "Needs update: /etc/mail/aliases.db" \ "(requires manual update via newaliases(1))" echo echo "Warnings:" echo " Needs update: /etc/mail/aliases.db" \ "(requires manual update via newaliases(1))" fi } # Report a summary of the previous merge. Specifically, list any # remaining conflicts followed by any warnings from the previous # update. status_cmd() { if [ $# -ne 0 ]; then usage fi if [ -d $CONFLICTS ]; then (cd $CONFLICTS; find . ! -type d) | sed -e 's/^\./ C /' fi if [ -s $WARNINGS ]; then echo "Warnings:" cat $WARNINGS fi } # Perform an actual merge. The new tree can either already exist (if # rerunning a merge), be extracted from a tarball, or generated from a # source tree. update_cmd() { local dir if [ $# -ne 0 ]; then usage fi log "update command: rerun=$rerun tarball=$tarball preworld=$preworld" if [ `id -u` -ne 0 ]; then echo "Must be root to update a tree." exit 1 fi # Enforce a sane umask umask 022 # XXX: Should existing conflicts be ignored and removed during # a rerun? # Trim the conflicts tree. Whine if there is anything left. if [ -e $CONFLICTS ]; then find -d $CONFLICTS -type d -empty -delete >&3 2>&1 rmdir $CONFLICTS >&3 2>&1 fi if [ -d $CONFLICTS ]; then echo "Conflicts remain from previous update, aborting." exit 1 fi if [ -z "$rerun" ]; then # For a dryrun that is not a rerun, do not rotate the existing # stock tree. Instead, extract a tree to a temporary directory # and use that for the comparison. if [ -n "$dryrun" ]; then dir=`mktemp -d $WORKDIR/etcupdate-XXXXXXX` if [ $? -ne 0 ]; then echo "Unable to create temporary directory." exit 1 fi # A pre-world dryrun has already set OLDTREE to # point to the current stock tree. if [ -z "$preworld" ]; then OLDTREE=$NEWTREE fi NEWTREE=$dir # For a pre-world update, blow away any pre-existing # NEWTREE. elif [ -n "$preworld" ]; then if ! remove_tree $NEWTREE; then echo "Unable to remove pre-world tree." exit 1 fi # Rotate the existing stock tree to the old tree. elif [ -d $NEWTREE ]; then # First, delete the previous old tree if it exists. if ! remove_tree $OLDTREE; then echo "Unable to remove old tree." exit 1 fi # Move the current stock tree. if ! mv $NEWTREE $OLDTREE >&3 2>&1; then echo "Unable to rename current stock tree." exit 1 fi fi if ! [ -d $OLDTREE ]; then cat < $WORKDIR/old.files (cd $NEWTREE; find .) | sed -e 's/^\.//' | sort > $WORKDIR/new.files # Split the files up into three groups using comm. comm -23 $WORKDIR/old.files $WORKDIR/new.files > $WORKDIR/removed.files comm -13 $WORKDIR/old.files $WORKDIR/new.files > $WORKDIR/added.files comm -12 $WORKDIR/old.files $WORKDIR/new.files > $WORKDIR/both.files # Initialize conflicts and warnings handling. rm -f $WARNINGS mkdir -p $CONFLICTS # Ignore removed files for the pre-world case. A pre-world # update uses a stripped-down tree. if [ -n "$preworld" ]; then > $WORKDIR/removed.files fi # The order for the following sections is important. In the # odd case that a directory is converted into a file, the # existing subfiles need to be removed if possible before the # file is converted. Similarly, in the case that a file is # converted into a directory, the file needs to be converted # into a directory if possible before the new files are added. # First, handle removed files. for file in `cat $WORKDIR/removed.files`; do handle_removed_file $file done # For the directory pass, reverse sort the list to effect a # depth-first traversal. This is needed to ensure that if a # directory with subdirectories is removed, the entire # directory is removed if there are no local modifications. for file in `sort -r $WORKDIR/removed.files`; do handle_removed_directory $file done # Second, handle files that exist in both the old and new # trees. for file in `cat $WORKDIR/both.files`; do handle_modified_file $file done # Finally, handle newly added files. for file in `cat $WORKDIR/added.files`; do handle_added_file $file done if [ -n "$NEWALIAS_WARN" ]; then warn "Needs update: /etc/mail/aliases.db" \ "(requires manual update via newaliases(1))" fi # Run any special one-off commands after an update has completed. post_update if [ -s $WARNINGS ]; then echo "Warnings:" cat $WARNINGS fi if [ -n "$dir" ]; then if [ -z "$dryrun" -o -n "$rerun" ]; then panic "Should not have a temporary directory" fi remove_tree $dir fi } # Determine which command we are executing. A command may be # specified as the first word. If one is not specified then 'update' # is assumed as the default command. command="update" if [ $# -gt 0 ]; then case "$1" in build|diff|extract|status|resolve) command="$1" shift ;; -*) # If first arg is an option, assume the # default command. ;; *) usage ;; esac fi # Set default variable values. # The path to the source tree used to build trees. SRCDIR=/usr/src # The destination directory where the modified files live. DESTDIR= # Ignore changes in the FreeBSD ID string. FREEBSD_ID= # Files that should always have the new version of the file installed. ALWAYS_INSTALL= # Files to ignore and never update during a merge. IGNORE_FILES= # Flags to pass to 'make' when building a tree. MAKE_OPTIONS= # Include a config file if it exists. Note that command line options # override any settings in the config file. More details are in the # manual, but in general the following variables can be set: # - ALWAYS_INSTALL # - DESTDIR # - EDITOR # - FREEBSD_ID # - IGNORE_FILES # - LOGFILE # - MAKE_OPTIONS # - SRCDIR # - WORKDIR if [ -r /etc/etcupdate.conf ]; then . /etc/etcupdate.conf fi # Parse command line options tarball= rerun= always= dryrun= ignore= nobuild= preworld= while getopts "d:nprs:t:A:BD:FI:L:M:" option; do case "$option" in d) WORKDIR=$OPTARG ;; n) dryrun=YES ;; p) preworld=YES ;; r) rerun=YES ;; s) SRCDIR=$OPTARG ;; t) tarball=$OPTARG ;; A) # To allow this option to be specified # multiple times, accumulate command-line # specified patterns in an 'always' variable # and use that to overwrite ALWAYS_INSTALL # after parsing all options. Need to be # careful here with globbing expansion. set -o noglob always="$always $OPTARG" set +o noglob ;; B) nobuild=YES ;; D) DESTDIR=$OPTARG ;; F) FREEBSD_ID=YES ;; I) # To allow this option to be specified # multiple times, accumulate command-line # specified patterns in an 'ignore' variable # and use that to overwrite IGNORE_FILES after # parsing all options. Need to be careful # here with globbing expansion. set -o noglob ignore="$ignore $OPTARG" set +o noglob ;; L) LOGFILE=$OPTARG ;; M) MAKE_OPTIONS="$OPTARG" ;; *) echo usage ;; esac done shift $((OPTIND - 1)) # Allow -A command line options to override ALWAYS_INSTALL set from # the config file. set -o noglob if [ -n "$always" ]; then ALWAYS_INSTALL="$always" fi # Allow -I command line options to override IGNORE_FILES set from the # config file. if [ -n "$ignore" ]; then IGNORE_FILES="$ignore" fi set +o noglob # Where the "old" and "new" trees are stored. WORKDIR=${WORKDIR:-$DESTDIR/var/db/etcupdate} # Log file for verbose output from program that are run. The log file # is opened on fd '3'. LOGFILE=${LOGFILE:-$WORKDIR/log} # The path of the "old" tree OLDTREE=$WORKDIR/old # The path of the "new" tree NEWTREE=$WORKDIR/current # The path of the "conflicts" tree where files with merge conflicts are saved. CONFLICTS=$WORKDIR/conflicts # The path of the "warnings" file that accumulates warning notes from an update. WARNINGS=$WORKDIR/warnings # Use $EDITOR for resolving conflicts. If it is not set, default to vi. EDITOR=${EDITOR:-/usr/bin/vi} # Files that need to be updated before installworld. PREWORLD_FILES="etc/master.passwd etc/group" # Handle command-specific argument processing such as complaining # about unsupported options. Since the configuration file is always # included, do not complain about extra command line arguments that # may have been set via the config file rather than the command line. case $command in update) if [ -n "$rerun" -a -n "$tarball" ]; then echo "Only one of -r or -t can be specified." echo usage fi if [ -n "$rerun" -a -n "$preworld" ]; then echo "Only one of -p or -r can be specified." echo usage fi ;; build|diff|status) if [ -n "$dryrun" -o -n "$rerun" -o -n "$tarball" -o \ -n "$preworld" ]; then usage fi ;; resolve) if [ -n "$dryrun" -o -n "$rerun" -o -n "$tarball" ]; then usage fi ;; extract) if [ -n "$dryrun" -o -n "$rerun" -o -n "$preworld" ]; then usage fi ;; esac # Pre-world mode uses a different set of trees. It leaves the current # tree as-is so it is still present for a full etcupdate run after the # world install is complete. Instead, it installs a few critical files # into a separate tree. if [ -n "$preworld" ]; then OLDTREE=$NEWTREE NEWTREE=$WORKDIR/preworld fi # Open the log file. Don't truncate it if doing a minor operation so # that a minor operation doesn't lose log info from a major operation. if ! mkdir -p $WORKDIR 2>/dev/null; then echo "Failed to create work directory $WORKDIR" fi case $command in diff|resolve|status) exec 3>>$LOGFILE ;; *) exec 3>$LOGFILE ;; esac ${command}_cmd "$@" Index: stable/10/usr.sbin/etcupdate/tests/always_test.sh =================================================================== --- stable/10/usr.sbin/etcupdate/tests/always_test.sh (revision 283926) +++ stable/10/usr.sbin/etcupdate/tests/always_test.sh (revision 283927) @@ -1,630 +1,630 @@ #!/bin/sh # -# Copyright (c) 2010 Advanced Computing Technologies LLC +# Copyright (c) 2010 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests to test the -A flag to the 'update' command. FAILED=no WORKDIR=work usage() { echo "Usage: always.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # The various states of the comparison of a file between two trees. states="equal first second difftype difflinks difffiles" # These tests deal with ignoring certain patterns of files. We run # the test multiple times forcing the install of different patterns. build_trees() { local i rm -rf $OLD $NEW $TEST $CONFLICTS for i in $states; do for j in $states; do for k in $states; do mkdir -p $OLD/$i/$j/$k $NEW/$i/$j/$k \ $TEST/$i/$j/$k done done done # What follows are the various warning/conflict cases from the # larger regression tests. These results of many of these # tests should be changed when installation is forced. The # cases when these updates should still fail even when forced # are: 1) it should not force the removal of a modified file # and 2) it should not remove a subdirectory that contains a # modified or added file. # /first/difftype/second: File with different local type # removed. Should generate a warning. mkfifo $OLD/first/difftype/second/fifo mkdir $TEST/first/difftype/second/fifo # /first/difflinks/second: Modified link removed. Should # generate a warning. ln -s "old link" $OLD/first/difflinks/second/link ln -s "test link" $TEST/first/difflinks/second/link # /first/difffiles/second: Modified file removed. Should # generate a warning. echo "foo" > $OLD/first/difffiles/second/file echo "bar" > $TEST/first/difffiles/second/file # /second/second/difftype: Newly added file conflicts with # existing file in test tree of a different type. Should # generate a warning. mkdir $NEW/second/second/difftype/dir mkfifo $TEST/second/second/difftype/dir # /second/second/difflinks: Newly added link conflicts with # existing link in test tree. Should generate a warning. ln -s "new link" $NEW/second/second/difflinks/link ln -s "test link" $TEST/second/second/difflinks/link # /second/second/difffiles: Newly added file conflicts with # existing file in test tree. Should generate a warning. echo "new" > $NEW/second/second/difffiles/file echo "test" > $TEST/second/second/difffiles/file # /difftype/first/first: A removed file has changed type. # This should generate a warning. mkfifo $OLD/difftype/first/first/fifo mkdir $NEW/difftype/first/first/fifo # /difftype/difftype/difftype: All three files (old, new, and # test) are different types from each other. This should # generate a warning. mkfifo $OLD/difftype/difftype/difftype/one mkdir $NEW/difftype/difftype/difftype/one echo "foo" > $TEST/difftype/difftype/difftype/one mkdir $OLD/difftype/difftype/difftype/two echo "baz" > $NEW/difftype/difftype/difftype/two ln -s "bar" $TEST/difftype/difftype/difftype/two # /difftype/difftype/difflinks: A file has changed from a # non-link to a link in both the new and test trees, but the # target of the new and test links differ. This should # generate a new link conflict. mkfifo $OLD/difftype/difftype/difflinks/link ln -s "new" $NEW/difftype/difftype/difflinks/link ln -s "test" $TEST/difftype/difftype/difflinks/link # /difftype/difftype/difffile: A file has changed from a # non-regular file to a regular file in both the new and test # trees, but the contents in the new and test files differ. # This should generate a new file conflict. ln -s "old" $OLD/difftype/difftype/difffiles/file echo "foo" > $NEW/difftype/difftype/difffiles/file echo "bar" > $TEST/difftype/difftype/difffiles/file # /difflinks/first/first: A modified link is missing in the # test tree. This should generate a warning. ln -s "old" $OLD/difflinks/first/first/link ln -s "new" $NEW/difflinks/first/first/link # /difflinks/difftype/difftype: An updated link has been # changed to a different file type in the test tree. This # should generate a warning. ln -s "old" $OLD/difflinks/difftype/difftype/link ln -s "new" $NEW/difflinks/difftype/difftype/link echo "test" > $TEST/difflinks/difftype/difftype/link # /difflinks/difflinks/difflinks: An updated link has been # modified in the test tree and doesn't match either the old # or new links. This should generate a warning. ln -s "old" $OLD/difflinks/difflinks/difflinks/link ln -s "new" $NEW/difflinks/difflinks/difflinks/link ln -s "test" $TEST/difflinks/difflinks/difflinks/link # /difffiles/first/first: A removed file has been changed in # the new tree. This should generate a warning. echo "foo" > $OLD/difffiles/first/first/file echo "bar" > $NEW/difffiles/first/first/file # /difffiles/difftype/difftype: An updated regular file has # been changed to a different file type in the test tree. # This should generate a warning. echo "old" > $OLD/difffiles/difftype/difftype/file echo "new" > $NEW/difffiles/difftype/difftype/file mkfifo $TEST/difffiles/difftype/difftype/file # /difffiles/difffiles/difffiles: A modified regular file was # updated in the new tree. The changes should be merged into # to the new file if possible. If the merge fails, a conflict # should be generated. For this test we just include the # conflict case. cat > $OLD/difffiles/difffiles/difffiles/conflict < $NEW/difffiles/difffiles/difffiles/conflict < $TEST/difffiles/difffiles/difffiles/conflict < $TEST/rmdir/extra/localfile.txt # /rmdir/conflict: Do not remove a directory with a conflicted # remove file. This should generate a warning. for i in $OLD $TEST; do mkdir $i/rmdir/conflict done mkfifo $OLD/rmdir/conflict/difftype mkdir $TEST/rmdir/conflict/difftype ## Tests for converting files to directories and vice versa for i in $OLD $NEW $TEST; do for j in already old fromdir todir; do mkdir -p $i/dirchange/$j done done # /dirchange/fromdir/extradir: Convert a directory tree to a # file. The test tree includes an extra file in the directory # that is not present in the old tree. This should generate a # warning. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/extradir echo "foo" > $i/dirchange/fromdir/extradir/file done mkfifo $TEST/dirchange/fromdir/extradir/fifo ln -s "bar" $NEW/dirchange/fromdir/extradir # /dirchange/fromdir/conflict: Convert a directory tree to a # file. The test tree includes a local change that generates # a warning and prevents the removal of the directory. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/conflict done echo "foo" > $OLD/dirchange/fromdir/conflict/somefile echo "bar" > $TEST/dirchange/fromdir/conflict/somefile mkfifo $NEW/dirchange/fromdir/conflict # /dirchange/todir/difffile: Convert a file to a directory # tree. The test tree has a locally modified version of the # file so that the conversion fails with a warning. echo "foo" > $OLD/dirchange/todir/difffile mkdir $NEW/dirchange/todir/difffile echo "baz" > $NEW/dirchange/todir/difffile/file echo "bar" > $TEST/dirchange/todir/difffile # /dirchange/todir/difftype: Similar to the previous test, but # the conflict is due to a change in the file type. echo "foo" > $OLD/dirchange/todir/difftype mkdir $NEW/dirchange/todir/difftype echo "baz" > $NEW/dirchange/todir/difftype/file mkfifo $TEST/dirchange/todir/difftype } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" FAILED=yes fi } # $1 - relative path to file that should be present in TEST present() { if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be present" FAILED=yes fi } # $1 - relative path to file that should be a fifo in TEST fifo() { if ! [ -p $TEST/$1 ]; then echo "File $1 should be a FIFO" FAILED=yes fi } # $1 - relative path to file that should be a directory in TEST dir() { if ! [ -d $TEST/$1 ]; then echo "File $1 should be a directory" FAILED=yes fi } # $1 - relative path to file that should be a symlink in TEST # $2 - optional value of the link link() { local val if ! [ -L $TEST/$1 ]; then echo "File $1 should be a link" FAILED=yes elif [ $# -gt 1 ]; then val=`readlink $TEST/$1` if [ "$val" != "$2" ]; then echo "Link $1 should link to \"$2\"" FAILED=yes fi fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" FAILED=yes elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" FAILED=yes fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" FAILED=yes fi fi } # $1 - relative path to a regular file that should have a conflict # $2 - optional MD5 of the conflict file contents conflict() { local sum if ! [ -f $CONFLICTS/$1 ]; then echo "File $1 missing conflict" FAILED=yes elif [ $# -gt 1 ]; then sum=`md5 -q $CONFLICTS/$1` if [ "$sum" != "$2" ]; then echo "Conflict $1 has wrong contents" FAILED=yes fi fi } # $1 - relative path to a regular file that should not have a conflict noconflict() { if [ -f $CONFLICTS/$1 ]; then echo "File $1 should not have a conflict" FAILED=yes fi } if [ `id -u` -ne 0 ]; then echo "must be root" exit 0 fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # First run the test ignoring no patterns. build_trees $COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out cat > $WORKDIR/correct.out < \ $WORKDIR/test1.out cat > $WORKDIR/correct1.out < # 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$ # Various regression tests to run for the 'resolve' command. FAILED=no WORKDIR=work usage() { echo "Usage: conflicts.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # These tests deal with conflicts to a single file. For each test, we # generate a conflict in /etc/login.conf. Each resolve option is tested # to ensure it DTRT. build_login_conflict() { rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD/etc $NEW/etc $TEST/etc # Generate a conflict in /etc/login.conf. cat > $OLD/etc/login.conf < $NEW/etc/login.conf < $TEST/etc/login.conf </dev/null } # This is used to verify special handling for /etc/mail/aliases and # the newaliases warning. build_aliases_conflict() { rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD/etc/mail $NEW/etc/mail $TEST/etc/mail # Generate a conflict in /etc/mail/aliases cat > $OLD/etc/mail/aliases < $NEW/etc/mail/aliases < $TEST/etc/mail/aliases </dev/null } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" FAILED=yes fi } # $1 - relative path to file that should be present in TEST present() { if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be present" FAILED=yes fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" FAILED=yes elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" FAILED=yes fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" FAILED=yes fi fi } # $1 - relative path to a regular file that should have a conflict # $2 - optional MD5 of the conflict file contents conflict() { local sum if ! [ -f $CONFLICTS/$1 ]; then echo "File $1 missing conflict" FAILED=yes elif [ $# -gt 1 ]; then sum=`md5 -q $CONFLICTS/$1` if [ "$sum" != "$2" ]; then echo "Conflict $1 has wrong contents" FAILED=yes fi fi } # $1 - relative path to a regular file that should no longer have a conflict resolved() { if [ -f $CONFLICTS/$1 ]; then echo "Conflict $1 should be resolved" FAILED=yes fi } if [ `id -u` -ne 0 ]; then echo "must be root" exit 0 fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # Test each of the following resolve options: 'p', 'mf', 'tf', 'r'. build_login_conflict # Verify that 'p' doesn't do anything. echo "Checking 'p':" echo 'p' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null file /etc/login.conf "" 95de92ea3f1bb1bf4f612a8b5908cddd missing /etc/login.conf.db conflict /etc/login.conf # Verify that 'mf' removes the conflict, but does nothing else. echo "Checking 'mf':" echo 'mf' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null file /etc/login.conf "" 95de92ea3f1bb1bf4f612a8b5908cddd missing /etc/login.conf.db resolved /etc/login.conf build_login_conflict # Verify that 'tf' installs the new version of the file. echo "Checking 'tf':" echo 'tf' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null file /etc/login.conf "" 7774a0f9a3a372c7c109c32fd31c4b6b file /etc/login.conf.db resolved /etc/login.conf build_login_conflict # Verify that 'r' installs the resolved version of the file. To # simulate this, manually edit the merged file so that it doesn't # contain conflict markers. echo "Checking 'r':" cat > $CONFLICTS/etc/login.conf </dev/null file /etc/login.conf "" 966e25984b9b63da8eaac8479dcb0d4d file /etc/login.conf.db resolved /etc/login.conf build_aliases_conflict # Verify that 'p' and 'mf' do not generate the newaliases warning. echo "Checking newalias warning for 'p'": echo 'p' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -eq 0 ]; then echo "+ Extra warning" FAILED=yes fi echo "Checking newalias warning for 'mf'": echo 'mf' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -eq 0 ]; then echo "+ Extra warning" FAILED=yes fi # Verify that 'tf' and 'r' do generate the newaliases warning. build_aliases_conflict echo "Checking newalias warning for 'tf'": echo 'tf' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -ne 0 ]; then echo "- Missing warning" FAILED=yes fi build_aliases_conflict cp $TEST/etc/mail/aliases $CONFLICTS/etc/mail/aliases echo 'r' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -ne 0 ]; then echo "- Missing warning" FAILED=yes fi [ "${FAILED}" = no ] Index: stable/10/usr.sbin/etcupdate/tests/fbsdid_test.sh =================================================================== --- stable/10/usr.sbin/etcupdate/tests/fbsdid_test.sh (revision 283926) +++ stable/10/usr.sbin/etcupdate/tests/fbsdid_test.sh (revision 283927) @@ -1,394 +1,394 @@ #!/bin/sh # -# Copyright (c) 2010 Advanced Computing Technologies LLC +# Copyright (c) 2010 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests to test the -F flag to the 'update' command. FAILED=no WORKDIR=work usage() { echo "Usage: fbsdid.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # Store a FreeBSD ID string in a specified file. The first argument # is the file, the remaining arguments are the comment to use. store_id() { local file file=$1 shift echo -n '# $FreeBSD' >> $file echo -n "$@" >> $file echo '$' >> $file } # These tests deal with FreeBSD ID string conflicts. We run the test # twice, once without -F and once with -F. build_trees() { local i rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD $NEW $TEST # remove: Remove a file where the only local difference is a # change in the FreeBSD ID string. store_id $OLD/remove store_id $TEST/remove ": head/remove 12345 jhb " # old: Modify a file where the only local difference between # the old and test files is a change in the FreeBSD ID string. store_id $OLD/old ": src/old,v 1.1 jhb Exp " store_id $NEW/old ": head/old 12345 jhb " store_id $TEST/old ": head/old 12000 jhb " for i in $OLD $TEST; do cat >> $i/old <> $NEW/old <> $OLD/already <> $i/already <> $OLD/conflict <> $NEW/conflict <> $TEST/conflict <> $i/local <> $i/local <> $TEST/local <> $i/local-already <> $TEST/local-already <> $i/local-remove < $WORKDIR/test.out cat > $WORKDIR/correct.out < $WORKDIR/testF.out cat > $WORKDIR/correctF.out < $WORKDIR/testAF.out cat > $WORKDIR/correctAF.out < # 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$ # Various regression tests to test the -I flag to the 'update' command. FAILED=no WORKDIR=work usage() { echo "Usage: ignore.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # These tests deal with ignoring certain patterns of files. We run the # test multiple times ignoring different patterns. build_trees() { local i rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD $NEW $TEST for i in $OLD $NEW $TEST; do mkdir -p $i/tree done # tree: Test three different cases (add, modify, remove) that all # match the tree/* glob. echo "foo" > $NEW/tree/add for i in $OLD $TEST; do echo "old" > $i/tree/modify done echo "new" > $NEW/tree/modify for i in $OLD $TEST; do echo "old" > $i/tree/remove done # rmdir: Remove a whole tree. for i in $OLD $TEST; do mkdir $i/rmdir echo "foo" > $i/rmdir/file done } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" FAILED=yes fi } # $1 - relative path to file that should be present in TEST present() { if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be present" FAILED=yes fi } # $1 - relative path to file that should be a directory in TEST dir() { if ! [ -d $TEST/$1 ]; then echo "File $1 should be a directory" FAILED=yes fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" FAILED=yes elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" FAILED=yes fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" FAILED=yes fi fi } # $1 - relative path to a regular file that should have a conflict # $2 - optional MD5 of the conflict file contents conflict() { local sum if ! [ -f $CONFLICTS/$1 ]; then echo "File $1 missing conflict" FAILED=yes elif [ $# -gt 1 ]; then sum=`md5 -q $CONFLICTS/$1` if [ "$sum" != "$2" ]; then echo "Conflict $1 has wrong contents" FAILED=yes fi fi } # $1 - relative path to a regular file that should not have a conflict noconflict() { if [ -f $CONFLICTS/$1 ]; then echo "File $1 should not have a conflict" FAILED=yes fi } if [ `id -u` -ne 0 ]; then echo "must be root" exit 0 fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # First run the test ignoring no patterns. build_trees $COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out cat > $WORKDIR/correct.out < $WORKDIR/test1.out cat > $WORKDIR/correct1.out < \ $WORKDIR/test2.out cat > $WORKDIR/correct2.out < \ $WORKDIR/test3.out cat > $WORKDIR/correct3.out < # 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$ # Regression tests for the pre-world (-p) mode FAILED=no WORKDIR=work usage() { echo "Usage: preworld.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts SRC=$WORKDIR/src OLD=$WORKDIR/current TEST=$WORKDIR/test build_trees() { # Populate trees with pre-world files and additional files # that should not be touched. rm -rf $SRC $OLD $TEST $CONFLICTS # Create the "old" source tree as the starting point mkdir -p $OLD/etc cat >> $OLD/etc/master.passwd <> $OLD/etc/group <> $OLD/etc/inetd.conf <:/' $TEST/etc/master.passwd cat >> $TEST/etc/master.passwd <:1001:1001::0:0:John Baldwin:/home/john:/bin/tcsh messagebus:*:556:556::0:0:D-BUS Daemon User:/nonexistent:/usr/sbin/nologin polkit:*:562:562::0:0:PolicyKit User:/nonexistent:/usr/sbin/nologin haldaemon:*:560:560::0:0:HAL Daemon User:/nonexistent:/usr/sbin/nologin EOF awk '/wheel/ { printf "%s,john\n", $0; next } // { print }' \ $OLD/etc/group > $TEST/etc/group cat >> $TEST/etc/group <> $SRC/etc/inetd.conf < $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for real:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \ || FAILED=yes check_trees [ "${FAILED}" = no ] Index: stable/10/usr.sbin/etcupdate/tests/tests_test.sh =================================================================== --- stable/10/usr.sbin/etcupdate/tests/tests_test.sh (revision 283926) +++ stable/10/usr.sbin/etcupdate/tests/tests_test.sh (revision 283927) @@ -1,1021 +1,1021 @@ #!/bin/sh # -# Copyright (c) 2010 Advanced Computing Technologies LLC +# Copyright (c) 2010 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests to run for the 'update' command. FAILED=no WORKDIR=work usage() { echo "Usage: tests.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # The various states of the comparison of a file between two trees. states="equal first second difftype difflinks difffiles" build_trees() { local i j k rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD/etc $NEW/etc $TEST/etc # For an given file, there are three different pair-wise # relations between the three threes (old, new, and test): old # vs new, old vs test, and new vs test. Each of these # relations takes on one of six different states from the # 'compare()' function in etcupdate: equal, onlyfirst, # onlysecond, difftype, difflinks, difffiles. In addition, # there are special considerations for considering cases such # as a file merge that results in conflicts versus one that # does not, special treatment of directories, etc. The tests # below attempt to enumerate the three dimensional test matrix # by having the path name use the three different tree states # for the parent directories. # # Note that if the old and new files are identical (so first # compare is "equal"), then the second and third comparisons # will be the same. # # Note also that etcupdate only cares about files that are # present in at least one of the old or new trees. Thus, none # of the '*/second/second' cases are relevant. for i in $states; do for j in $states; do for k in $states; do mkdir -p $OLD/$i/$j/$k $NEW/$i/$j/$k \ $TEST/$i/$j/$k done done done # /equal/equal/equal: Everything is equal. Nothing should happen. for i in $OLD $NEW $TEST; do mkfifo $i/equal/equal/equal/fifo echo "foo" > $i/equal/equal/equal/file mkdir $i/equal/equal/equal/dir ln -s "bar" $i/equal/equal/equal/link done # /equal/first/first: The file is missing from the test # directory. Nothing should happen. for i in $OLD $NEW; do mkfifo $i/equal/first/first/fifo echo "foo" > $i/equal/first/first/file mkdir $i/equal/first/first/dir ln -s "bar" $i/equal/first/first/link done # /equal/difftype/difftype: The local file is a different # type. Nothing should happen. for i in $OLD $NEW; do mkfifo $i/equal/difftype/difftype/fifo mkdir $i/equal/difftype/difftype/fromdir done echo "bar" > $TEST/equal/difftype/difftype/fifo ln -s "test" $TEST/equal/difftype/difftype/fromdir # /equal/difflinks/difflinks: The local file is a modified # link. Nothing should happen. for i in $OLD $NEW; do ln -s "foo" $i/equal/difflinks/difflinks/link done ln -s "bar" $TEST/equal/difflinks/difflinks/link # /equal/difffiles/difffiles: The local file is a modified # file. Nothing should happen. for i in $OLD $NEW; do echo "foo" > $i/equal/difffiles/difffiles/file done echo "bar" > $TEST/equal/difffiles/difffiles/file # /first/equal/second: Remove unmodified files. The files # should all be removed. for i in $OLD $TEST; do mkfifo $i/first/equal/second/fifo echo "foo" > $i/first/equal/second/file mkdir $i/first/equal/second/emptydir ln -s "bar" $i/first/equal/second/link mkdir $i/first/equal/second/fulldir echo "foo" > $i/first/equal/second/fulldir/file done # /first/equal/*: Cannot occur. If the file is missing from # new, then new vs test will always be 'second'. # /first/first/equal: Removed files are already removed. # Nothing should happen. mkfifo $OLD/first/first/equal/fifo echo "foo" > $OLD/first/first/equal/file mkdir $OLD/first/first/equal/dir ln -s "bar" $OLD/first/first/equal/link # /first/first/*: Cannot occur. The files are missing from # both new and test. # /first/second/*: Cannot happen, if the file is in old for # old vs new, it cannot be missing for old vs test. # /first/difftype/second: File with different local type # removed. Should generate a warning. mkfifo $OLD/first/difftype/second/fifo mkdir $TEST/first/difftype/second/fifo # /first/difftype/*: Cannot happen since the file is missing # from new but present in test. # /first/difflinks/second: Modified link removed. Should # generate a warning. ln -s "old link" $OLD/first/difflinks/second/link ln -s "test link" $TEST/first/difflinks/second/link # /first/difflinks/*: Cannot happen since the file is missing # from new but present in test. # /first/difffiles/second: Modified file removed. Should # generate a warning. echo "foo" > $OLD/first/difffiles/second/file echo "bar" > $TEST/first/difffiles/second/file # /first/difffiles/*: Cannot happen since the file is missing # from new but present in test. # /second/equal/first: Added a new file that isn't present in # test. The empty directory should be ignored. echo "bar" > $NEW/second/equal/first/file mkfifo $NEW/second/equal/first/fifo ln -s "new" $NEW/second/equal/first/link mkdir $NEW/second/equal/first/emptydir mkdir $NEW/second/equal/first/fulldir echo "foo" > $NEW/second/equal/first/fulldir/file # /second/equal/*: Cannot happen since the file is missing # from test but present in new. # /second/first/*: Cannot happen since the file is missing # from old. # /second/second/equal: Newly added file is already present in # the test directory and identical to the new file. Nothing # should happen. for i in $NEW $TEST; do mkfifo $i/second/second/equal/fifo echo "foo" > $i/second/second/equal/file mkdir $i/second/second/equal/dir ln -s "bar" $i/second/second/equal/link done # /second/second/first: Cannot happen. The file is in dest in # the second test, so it can't be missing from the third test. # /second/second/second: Cannot happen. The file is in new in # the first test, so it can't be missing from the third test. # /second/second/difftype: Newly added file conflicts with # existing file in test tree of a different type. Should # generate a warning. mkdir $NEW/second/second/difftype/dir mkfifo $TEST/second/second/difftype/dir # /second/second/difflinks: Newly added link conflicts with # existing link in test tree. Should generate a warning. ln -s "new link" $NEW/second/second/difflinks/link ln -s "test link" $TEST/second/second/difflinks/link # /second/second/difffiles: Newly added file conflicts with # existing file in test tree. Should generate a warning. echo "new" > $NEW/second/second/difffiles/file echo "test" > $TEST/second/second/difffiles/file # /second/difftype/*: Cannot happen since the file is missing # from old. # /second/difflinks/*: Cannot happen since the file is missing # from old. # /second/difffiles/*: Cannot happen since the file is missing # from old. # /difftype/equal/difftype: Unmodified file has changed type. # File should be updated to the new file. In the 'todir' case # the directory won't actually be created because it is empty. for i in $OLD $TEST; do echo "foo" > $i/difftype/equal/difftype/file mkdir $i/difftype/equal/difftype/fromdir ln -s "old" $i/difftype/equal/difftype/todir done ln -s "test" $NEW/difftype/equal/difftype/file mkfifo $NEW/difftype/equal/difftype/fromdir mkdir $NEW/difftype/equal/difftype/todir # /difftype/equal/*: Cannot happen. Since the old file is a # difftype from the new file and the test file is identical to # the old file, the test file must be a difftype from the new # file. # /difftype/first/first: A removed file has changed type. # This should generate a warning. mkfifo $OLD/difftype/first/first/fifo mkdir $NEW/difftype/first/first/fifo # /difftype/first/*: Cannot happen. Since the new file exists # and the dest file is missing, the last test must be 'first'. # /difftype/second/*: Cannot happen. The old file exists in # the first test, so it cannot be missing in the second test. # /difftype/difftype/equal: A file has changed type, but the # file in the test directory already matches the new file. Do # nothing. echo "foo" > $OLD/difftype/difftype/equal/fifo mkfifo $OLD/difftype/difftype/equal/file for i in $NEW $TEST; do mkfifo $i/difftype/difftype/equal/fifo echo "bar" > $i/difftype/difftype/equal/file done # /difftype/difftype/first: Cannot happen. The dest file # exists in the second test. # /difftype/difftype/second: Cannot happen. The new file # exists in the first test. # /difftype/difftype/difftype: All three files (old, new, and # test) are different types from each other. This should # generate a warning. mkfifo $OLD/difftype/difftype/difftype/one mkdir $NEW/difftype/difftype/difftype/one echo "foo" > $TEST/difftype/difftype/difftype/one mkdir $OLD/difftype/difftype/difftype/two echo "baz" > $NEW/difftype/difftype/difftype/two ln -s "bar" $TEST/difftype/difftype/difftype/two # /difftype/difftype/difflinks: A file has changed from a # non-link to a link in both the new and test trees, but the # target of the new and test links differ. This should # generate a new link conflict. mkfifo $OLD/difftype/difftype/difflinks/link ln -s "new" $NEW/difftype/difftype/difflinks/link ln -s "test" $TEST/difftype/difftype/difflinks/link # /difftype/difftype/difffile: A file has changed from a # non-regular file to a regular file in both the new and test # trees, but the contents in the new and test files differ. # This should generate a new file conflict. ln -s "old" $OLD/difftype/difftype/difffiles/file echo "foo" > $NEW/difftype/difftype/difffiles/file echo "bar" > $TEST/difftype/difftype/difffiles/file # /difflinks/equal/difflinks: An unmodified symlink has # changed. The link should be updated. for i in $OLD $TEST; do ln -s "old" $i/difflinks/equal/difflinks/link done ln -s "new" $NEW/difflinks/equal/difflinks/link # /difflinks/equal/*: Cannot happen. Since old is identical # to test, the third test must be 'difflinks'. # /difflinks/first/first: A modified link is missing in the # test tree. This should generate a warning. ln -s "old" $OLD/difflinks/first/first/link ln -s "new" $NEW/difflinks/first/first/link # /difflinks/first/*: Cannot happen. Since the test file is # missing in the second test, it must be missing in the third # test. # /difflinks/second/*: Cannot happen. The old link is present # in the first test, so it cannot be missing in the second # test. # /difflinks/difftype/difftype: An updated link has been # changed to a different file type in the test tree. This # should generate a warning. ln -s "old" $OLD/difflinks/difftype/difftype/link ln -s "new" $NEW/difflinks/difftype/difftype/link echo "test" > $TEST/difflinks/difftype/difftype/link # /difflinks/difftype/*: Cannot happen. The old and new files # are both links and the test file is not a link, so the third # test must be 'difftype'. # /difflinks/difflinks/equal: An updated link has already been # updated to the new target in the test tree. Nothing should # happen. ln -s "old" $OLD/difflinks/difflinks/equal/link for i in $NEW $TEST; do ln -s "new" $i/difflinks/difflinks/equal/link done # /difflinks/difflinks/difflinks: An updated link has been # modified in the test tree and doesn't match either the old # or new links. This should generate a warning. ln -s "old" $OLD/difflinks/difflinks/difflinks/link ln -s "new" $NEW/difflinks/difflinks/difflinks/link ln -s "test" $TEST/difflinks/difflinks/difflinks/link # /difflinks/difflinks/*: Cannot happen. All three files are # links from the first two tests, so the third test can only # be 'equal' or 'difflink'. # /difflinks/difffiles/*: Cannot happen. The old file is a # link in the first test, so it cannot be a regular file in # the second. # /difffiles/equal/difffiles: An unmodified file has been # changed in new tree. The file should be updated to the new # version. for i in $OLD $TEST; do echo "foo" > $i/difffiles/equal/difffiles/file done echo "bar" > $NEW/difffiles/equal/difffiles/file # /difffiles/equal/*: Cannot happen. Since the old file is # identical to the test file, the third test must be # 'difffiles'. # /difffiles/first/first: A removed file has been changed in # the new tree. This should generate a warning. echo "foo" > $OLD/difffiles/first/first/file echo "bar" > $NEW/difffiles/first/first/file # /difffiles/first/*: Cannot happen. The new file is a # regular file from the first test and the test file is # missing in the second test, so the third test must be # 'first'. # /difffiles/second/*: Cannot happen. The old file is present # in the first test, so it must be present in the second test. # /difffiles/difftype/difftype: An updated regular file has # been changed to a different file type in the test tree. # This should generate a warning. echo "old" > $OLD/difffiles/difftype/difftype/file echo "new" > $NEW/difffiles/difftype/difftype/file mkfifo $TEST/difffiles/difftype/difftype/file # /difffiles/difftype/*: Cannot happen. The new file is known # to be a regular file from the first test, and the test file # is known to exist as a different file type from the second # test. The third test must be 'difftype'. # /difffiles/difflink/*: Cannot happen. The old file is known # to be a regular file from the first test, so it cannot be a # link in the second test. # /difffiles/difffiles/equal: An updated regular file has # already been updated to match the new file in the test tree. # Nothing should happen. echo "foo" > $OLD/difffiles/difffiles/equal/file for i in $NEW $TEST; do echo "bar" > $i/difffiles/difffiles/equal/file done # /difffiles/difffiles/difffiles: A modified regular file was # updated in the new tree. The changes should be merged into # to the new file if possible. If the merge fails, a conflict # should be generated. cat > $OLD/difffiles/difffiles/difffiles/simple < $NEW/difffiles/difffiles/difffiles/simple < $TEST/difffiles/difffiles/difffiles/simple < $OLD/difffiles/difffiles/difffiles/conflict < $NEW/difffiles/difffiles/difffiles/conflict < $TEST/difffiles/difffiles/difffiles/conflict < $NEW/adddir/partial/file mkfifo $TEST/adddir/partial/fifo ## Tests for removing directories mkdir -p $OLD/rmdir $NEW/rmdir $TEST/rmdir # /rmdir/extra: Do not remove a directory with an extra local file. # This should generate a warning. for i in $OLD $TEST; do mkdir $i/rmdir/extra done echo "foo" > $TEST/rmdir/extra/localfile.txt # /rmdir/conflict: Do not remove a directory with a conflicted # remove file. This should generate a warning. for i in $OLD $TEST; do mkdir $i/rmdir/conflict done mkfifo $OLD/rmdir/conflict/difftype mkdir $TEST/rmdir/conflict/difftype # /rmdir/partial: Remove a complete hierarchy when part of the # tree has already been removed locally. for i in $OLD $TEST; do mkdir -p $i/rmdir/partial/subdir mkfifo $i/rmdir/partial/subdir/fifo done echo "foo" > $OLD/rmdir/partial/subdir/file ## Tests for converting files to directories and vice versa for i in $OLD $NEW $TEST; do for j in already old fromdir todir; do mkdir -p $i/dirchange/$j done done # /dirchange/already/fromdir: Convert a directory tree to a # file without conflicts where the test tree already has the # new file. Nothing should happen. mkdir $OLD/dirchange/already/fromdir echo "blah" > $OLD/dirchange/already/fromdir/somefile for i in $NEW $TEST; do echo "bar" > $i/dirchange/already/fromdir done # /dirchange/already/todir: Convert an unmodified file to a # directory tree where the test tree already has the new # tree. Nothing should happen. echo "baz" > $OLD/dirchange/already/todir for i in $NEW $TEST; do mkdir $i/dirchange/already/todir echo "blah" > $i/dirchange/already/todir/somefile done # /dirchange/old/fromdir: Convert a directory tree to a file. # The old files are unmodified and should be changed to the new tree. for i in $OLD $TEST; do mkdir $i/dirchange/old/fromdir echo "blah" > $i/dirchange/old/fromdir/somefile done echo "bar" > $NEW/dirchange/old/fromdir # /dirchange/old/todir: Convert a file to a directory tree. # The old file is unmodified and should be changed to the new # tree. for i in $OLD $TEST; do echo "foo" > $i/dirchange/old/todir done mkdir $NEW/dirchange/old/todir echo "bar" > $NEW/dirchange/old/todir/file # /dirchange/fromdir/extradir: Convert a directory tree to a # file. The test tree includes an extra file in the directory # that is not present in the old tree. This should generate a # warning. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/extradir echo "foo" > $i/dirchange/fromdir/extradir/file done mkfifo $TEST/dirchange/fromdir/extradir/fifo ln -s "bar" $NEW/dirchange/fromdir/extradir # /dirchange/fromdir/conflict: Convert a directory tree to a # file. The test tree includes a local change that generates # a warning and prevents the removal of the directory. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/conflict done echo "foo" > $OLD/dirchange/fromdir/conflict/somefile echo "bar" > $TEST/dirchange/fromdir/conflict/somefile mkfifo $NEW/dirchange/fromdir/conflict # /dirchange/todir/difffile: Convert a file to a directory # tree. The test tree has a locally modified version of the # file so that the conversion fails with a warning. echo "foo" > $OLD/dirchange/todir/difffile mkdir $NEW/dirchange/todir/difffile echo "baz" > $NEW/dirchange/todir/difffile/file echo "bar" > $TEST/dirchange/todir/difffile # /dirchange/todir/difftype: Similar to the previous test, but # the conflict is due to a change in the file type. echo "foo" > $OLD/dirchange/todir/difftype mkdir $NEW/dirchange/todir/difftype echo "baz" > $NEW/dirchange/todir/difftype/file mkfifo $TEST/dirchange/todir/difftype ## Tests for post-install actions # - Adding /etc/master.passwd should cause pwd_mkdb to be run echo "foo:*:16000:100::0:0:& user:/home/foo:/bin/tcsh" > \ $NEW/etc/master.passwd # - Verify that updating an unmodified /etc/login.conf builds # /etc/login.conf.db. cat > $OLD/etc/login.conf < $NEW/etc/login.conf < $OLD/etc/mail/aliases < $NEW/etc/mail/aliases < $TEST/etc/mail/aliases < $OLD/etc/services < $NEW/etc/services < $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for real:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \ || failed=YES check_trees [ "${FAILED}" = no ] Index: stable/10/usr.sbin/etcupdate/tests/tzsetup_test.sh =================================================================== --- stable/10/usr.sbin/etcupdate/tests/tzsetup_test.sh (revision 283926) +++ stable/10/usr.sbin/etcupdate/tests/tzsetup_test.sh (revision 283927) @@ -1,239 +1,239 @@ #!/bin/sh # -# Copyright (c) 2013 Advanced Computing Technologies LLC +# Copyright (c) 2013 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests for the tzsetup handling in the 'update' command. FAILED=no WORKDIR=work usage() { echo "Usage: tzsetup.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test build_trees() { # Build the base tree, but not /etc/localtime itself local i j k rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD $NEW $TEST mkdir -p $TEST/etc mkdir -p $TEST/var/db mkdir -p $TEST/usr/share/zoneinfo # Create a dummy timezone file echo "foo" > $TEST/usr/share/zoneinfo/foo } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" FAILED=yes fi } # $1 - relative path to file that should be a symlink in TEST # $2 - optional value of the link link() { local val if ! [ -L $TEST/$1 ]; then echo "File $1 should be a link" FAILED=yes elif [ $# -gt 1 ]; then val=`readlink $TEST/$1` if [ "$val" != "$2" ]; then echo "Link $1 should link to \"$2\"" FAILED=yes fi fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" FAILED=yes elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" FAILED=yes fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" FAILED=yes fi fi } if [ `id -u` -ne 0 ]; then echo "must be root" exit 0 fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # First, test for /etc/localtime not existing build_trees $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for no /etc/localtime:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \ || FAILED=yes missing /etc/localtime missing /var/db/zoneinfo # Second, test for /etc/localtime being a symlink build_trees ln -s /dev/null $TEST/etc/localtime $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for symlinked /etc/localtime:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \ || FAILED=yes link /etc/localtime "/dev/null" missing /var/db/zoneinfo # Third, test for /etc/localtime as a file and a missing /var/db/zoneinfo build_trees echo "bar" > $TEST/etc/localtime $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for missing /var/db/zoneinfo:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \ || FAILED=yes file /etc/localtime "bar" missing /var/db/zoneinfo # Finally, test the case where it should update /etc/localtime build_trees echo "bar" > $TEST/etc/localtime echo "foo" > $TEST/var/db/zoneinfo $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for real update:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \ || FAILED=yes file /etc/localtime "foo" file /var/db/zoneinfo "foo" [ "${FAILED}" = no ] Index: stable/10/usr.sbin/pciconf/err.c =================================================================== --- stable/10/usr.sbin/pciconf/err.c (revision 283926) +++ stable/10/usr.sbin/pciconf/err.c (revision 283927) @@ -1,173 +1,173 @@ /*- - * Copyright (c) 2012 Advanced Computing Technologies LLC + * Copyright (c) 2012 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include "pciconf.h" struct bit_table { uint32_t mask; const char *desc; }; /* Error indicators in the PCI status register (PCIR_STATUS). */ static struct bit_table pci_status[] = { { PCIM_STATUS_MDPERR, "Master Data Parity Error" }, { PCIM_STATUS_STABORT, "Sent Target-Abort" }, { PCIM_STATUS_RTABORT, "Received Target-Abort" }, { PCIM_STATUS_RMABORT, "Received Master-Abort" }, { PCIM_STATUS_SERR, "Signalled System Error" }, { PCIM_STATUS_PERR, "Detected Parity Error" }, { 0, NULL }, }; /* Valid error indicator bits in PCIR_STATUS. */ #define PCI_ERRORS (PCIM_STATUS_MDPERR | PCIM_STATUS_STABORT | \ PCIM_STATUS_RTABORT | PCIM_STATUS_RMABORT | \ PCIM_STATUS_SERR | PCIM_STATUS_PERR) /* Error indicators in the PCI-Express device status register. */ static struct bit_table pcie_device_status[] = { { PCIEM_STA_CORRECTABLE_ERROR, "Correctable Error Detected" }, { PCIEM_STA_NON_FATAL_ERROR, "Non-Fatal Error Detected" }, { PCIEM_STA_FATAL_ERROR, "Fatal Error Detected" }, { PCIEM_STA_UNSUPPORTED_REQ, "Unsupported Request Detected" }, { 0, NULL }, }; /* Valid error indicator bits in the PCI-Express device status register. */ #define PCIE_ERRORS (PCIEM_STA_CORRECTABLE_ERROR | \ PCIEM_STA_NON_FATAL_ERROR | \ PCIEM_STA_FATAL_ERROR | \ PCIEM_STA_UNSUPPORTED_REQ) /* AER Uncorrected errors. */ static struct bit_table aer_uc[] = { { PCIM_AER_UC_TRAINING_ERROR, "Link Training Error" }, { PCIM_AER_UC_DL_PROTOCOL_ERROR, "Data Link Protocol Error" }, { PCIM_AER_UC_SURPRISE_LINK_DOWN, "Surprise Link Down Error" }, { PCIM_AER_UC_POISONED_TLP, "Poisoned TLP" }, { PCIM_AER_UC_FC_PROTOCOL_ERROR, "Flow Control Protocol Error" }, { PCIM_AER_UC_COMPLETION_TIMEOUT, "Completion Timeout" }, { PCIM_AER_UC_COMPLETER_ABORT, "Completer Abort" }, { PCIM_AER_UC_UNEXPECTED_COMPLETION, "Unexpected Completion" }, { PCIM_AER_UC_RECEIVER_OVERFLOW, "Receiver Overflow Error" }, { PCIM_AER_UC_MALFORMED_TLP, "Malformed TLP" }, { PCIM_AER_UC_ECRC_ERROR, "ECRC Error" }, { PCIM_AER_UC_UNSUPPORTED_REQUEST, "Unsupported Request" }, { PCIM_AER_UC_ACS_VIOLATION, "ACS Violation" }, { PCIM_AER_UC_INTERNAL_ERROR, "Uncorrectable Internal Error" }, { PCIM_AER_UC_MC_BLOCKED_TLP, "MC Blocked TLP" }, { PCIM_AER_UC_ATOMIC_EGRESS_BLK, "AtomicOp Egress Blocked" }, { PCIM_AER_UC_TLP_PREFIX_BLOCKED, "TLP Prefix Blocked Error" }, { 0, NULL }, }; /* AER Corrected errors. */ static struct bit_table aer_cor[] = { { PCIM_AER_COR_RECEIVER_ERROR, "Receiver Error" }, { PCIM_AER_COR_BAD_TLP, "Bad TLP" }, { PCIM_AER_COR_BAD_DLLP, "Bad DLLP" }, { PCIM_AER_COR_REPLAY_ROLLOVER, "REPLAY_NUM Rollover" }, { PCIM_AER_COR_REPLAY_TIMEOUT, "Replay Timer Timeout" }, { PCIM_AER_COR_ADVISORY_NF_ERROR, "Advisory Non-Fatal Error" }, { PCIM_AER_COR_INTERNAL_ERROR, "Corrected Internal Error" }, { PCIM_AER_COR_HEADER_LOG_OVFLOW, "Header Log Overflow" }, { 0, NULL }, }; static void print_bits(const char *header, struct bit_table *table, uint32_t mask) { int first; first = 1; for (; table->desc != NULL; table++) if (mask & table->mask) { if (first) { printf("%14s = ", header); first = 0; } else printf(" "); printf("%s\n", table->desc); mask &= ~table->mask; } if (mask != 0) { if (first) printf("%14s = ", header); else printf(" "); printf("Unknown: 0x%08x\n", mask); } } void list_errors(int fd, struct pci_conf *p) { uint32_t mask, severity; uint16_t sta, aer; uint8_t pcie; /* First check for standard PCI errors. */ sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); print_bits("PCI errors", pci_status, sta & PCI_ERRORS); /* See if this is a PCI-express device. */ pcie = pci_find_cap(fd, p, PCIY_EXPRESS); if (pcie == 0) return; /* Check for PCI-e errors. */ sta = read_config(fd, &p->pc_sel, pcie + PCIER_DEVICE_STA, 2); print_bits("PCI-e errors", pcie_device_status, sta & PCIE_ERRORS); /* See if this device supports AER. */ aer = pcie_find_cap(fd, p, PCIZ_AER); if (aer == 0) return; /* Check for uncorrected errors. */ mask = read_config(fd, &p->pc_sel, aer + PCIR_AER_UC_STATUS, 4); severity = read_config(fd, &p->pc_sel, aer + PCIR_AER_UC_SEVERITY, 4); print_bits("Fatal", aer_uc, mask & severity); print_bits("Non-fatal", aer_uc, mask & ~severity); /* Check for corrected errors. */ mask = read_config(fd, &p->pc_sel, aer + PCIR_AER_COR_STATUS, 4); print_bits("Corrected", aer_cor, mask); } Index: stable/10 =================================================================== --- stable/10 (revision 283926) +++ stable/10 (revision 283927) Property changes on: stable/10 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r281887 Index: stable/7/sys/amd64/amd64/mca.c =================================================================== --- stable/7/sys/amd64/amd64/mca.c (revision 283926) +++ stable/7/sys/amd64/amd64/mca.c (revision 283927) @@ -1,906 +1,906 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ /* * Support for x86 machine check architecture. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Modes for mca_scan() */ enum scan_mode { POLLED, MCE, CMCI, }; /* * State maintained for each monitored MCx bank to control the * corrected machine check interrupt threshold. */ struct cmc_state { int max_threshold; int last_intr; }; struct mca_internal { struct mca_record rec; int logged; STAILQ_ENTRY(mca_internal) link; }; static MALLOC_DEFINE(M_MCA, "MCA", "Machine Check Architecture"); static int mca_count; /* Number of records stored. */ SYSCTL_NODE(_hw, OID_AUTO, mca, CTLFLAG_RD, NULL, "Machine Check Architecture"); static int mca_enabled = 1; TUNABLE_INT("hw.mca.enabled", &mca_enabled); SYSCTL_INT(_hw_mca, OID_AUTO, enabled, CTLFLAG_RDTUN, &mca_enabled, 0, "Administrative toggle for machine check support"); static int amd10h_L1TP = 1; TUNABLE_INT("hw.mca.amd10h_L1TP", &amd10h_L1TP); SYSCTL_INT(_hw_mca, OID_AUTO, amd10h_L1TP, CTLFLAG_RDTUN, &amd10h_L1TP, 0, "Administrative toggle for logging of level one TLB parity (L1TP) errors"); int workaround_erratum383; SYSCTL_INT(_hw_mca, OID_AUTO, erratum383, CTLFLAG_RD, &workaround_erratum383, 0, "Is the workaround for Erratum 383 on AMD Family 10h processors enabled?"); static STAILQ_HEAD(, mca_internal) mca_records; static struct callout mca_timer; static int mca_ticks = 3600; /* Check hourly by default. */ static struct task mca_task; static struct mtx mca_lock; static struct cmc_state **cmc_state; /* Indexed by cpuid, bank */ static int cmc_banks; static int cmc_throttle = 60; /* Time in seconds to throttle CMCI. */ static int sysctl_positive_int(SYSCTL_HANDLER_ARGS) { int error, value; value = *(int *)arg1; error = sysctl_handle_int(oidp, &value, 0, req); if (error || req->newptr == NULL) return (error); if (value <= 0) return (EINVAL); *(int *)arg1 = value; return (0); } static int sysctl_mca_records(SYSCTL_HANDLER_ARGS) { int *name = (int *)arg1; u_int namelen = arg2; struct mca_record record; struct mca_internal *rec; int i; if (namelen != 1) return (EINVAL); if (name[0] < 0 || name[0] >= mca_count) return (EINVAL); mtx_lock_spin(&mca_lock); if (name[0] >= mca_count) { mtx_unlock_spin(&mca_lock); return (EINVAL); } i = 0; STAILQ_FOREACH(rec, &mca_records, link) { if (i == name[0]) { record = rec->rec; break; } i++; } mtx_unlock_spin(&mca_lock); return (SYSCTL_OUT(req, &record, sizeof(record))); } static const char * mca_error_ttype(uint16_t mca_error) { switch ((mca_error & 0x000c) >> 2) { case 0: return ("I"); case 1: return ("D"); case 2: return ("G"); } return ("?"); } static const char * mca_error_level(uint16_t mca_error) { switch (mca_error & 0x0003) { case 0: return ("L0"); case 1: return ("L1"); case 2: return ("L2"); case 3: return ("LG"); } return ("L?"); } static const char * mca_error_request(uint16_t mca_error) { switch ((mca_error & 0x00f0) >> 4) { case 0x0: return ("ERR"); case 0x1: return ("RD"); case 0x2: return ("WR"); case 0x3: return ("DRD"); case 0x4: return ("DWR"); case 0x5: return ("IRD"); case 0x6: return ("PREFETCH"); case 0x7: return ("EVICT"); case 0x8: return ("SNOOP"); } return ("???"); } static const char * mca_error_mmtype(uint16_t mca_error) { switch ((mca_error & 0x70) >> 4) { case 0x0: return ("GEN"); case 0x1: return ("RD"); case 0x2: return ("WR"); case 0x3: return ("AC"); case 0x4: return ("MS"); } return ("???"); } /* Dump details about a single machine check. */ static void __nonnull(1) mca_log(const struct mca_record *rec) { uint16_t mca_error; printf("MCA: Bank %d, Status 0x%016llx\n", rec->mr_bank, (long long)rec->mr_status); printf("MCA: Global Cap 0x%016llx, Status 0x%016llx\n", (long long)rec->mr_mcg_cap, (long long)rec->mr_mcg_status); printf("MCA: Vendor \"%s\", ID 0x%x, APIC ID %d\n", cpu_vendor, rec->mr_cpu_id, rec->mr_apic_id); printf("MCA: CPU %d ", rec->mr_cpu); if (rec->mr_status & MC_STATUS_UC) printf("UNCOR "); else { printf("COR "); if (rec->mr_mcg_cap & MCG_CAP_CMCI_P) printf("(%lld) ", ((long long)rec->mr_status & MC_STATUS_COR_COUNT) >> 38); } if (rec->mr_status & MC_STATUS_PCC) printf("PCC "); if (rec->mr_status & MC_STATUS_OVER) printf("OVER "); mca_error = rec->mr_status & MC_STATUS_MCA_ERROR; switch (mca_error) { /* Simple error codes. */ case 0x0000: printf("no error"); break; case 0x0001: printf("unclassified error"); break; case 0x0002: printf("ucode ROM parity error"); break; case 0x0003: printf("external error"); break; case 0x0004: printf("FRC error"); break; case 0x0005: printf("internal parity error"); break; case 0x0400: printf("internal timer error"); break; default: if ((mca_error & 0xfc00) == 0x0400) { printf("internal error %x", mca_error & 0x03ff); break; } /* Compound error codes. */ /* Memory hierarchy error. */ if ((mca_error & 0xeffc) == 0x000c) { printf("%s memory error", mca_error_level(mca_error)); break; } /* TLB error. */ if ((mca_error & 0xeff0) == 0x0010) { printf("%sTLB %s error", mca_error_ttype(mca_error), mca_error_level(mca_error)); break; } /* Memory controller error. */ if ((mca_error & 0xef80) == 0x0080) { printf("%s channel ", mca_error_mmtype(mca_error)); if ((mca_error & 0x000f) != 0x000f) printf("%d", mca_error & 0x000f); else printf("??"); printf(" memory error"); break; } /* Cache error. */ if ((mca_error & 0xef00) == 0x0100) { printf("%sCACHE %s %s error", mca_error_ttype(mca_error), mca_error_level(mca_error), mca_error_request(mca_error)); break; } /* Bus and/or Interconnect error. */ if ((mca_error & 0xe800) == 0x0800) { printf("BUS%s ", mca_error_level(mca_error)); switch ((mca_error & 0x0600) >> 9) { case 0: printf("Source"); break; case 1: printf("Responder"); break; case 2: printf("Observer"); break; default: printf("???"); break; } printf(" %s ", mca_error_request(mca_error)); switch ((mca_error & 0x000c) >> 2) { case 0: printf("Memory"); break; case 2: printf("I/O"); break; case 3: printf("Other"); break; default: printf("???"); break; } if (mca_error & 0x0100) printf(" timed out"); break; } printf("unknown error %x", mca_error); break; } printf("\n"); if (rec->mr_status & MC_STATUS_ADDRV) printf("MCA: Address 0x%llx\n", (long long)rec->mr_addr); if (rec->mr_status & MC_STATUS_MISCV) printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc); } static int __nonnull(2) mca_check_status(int bank, struct mca_record *rec) { uint64_t status; u_int p[4]; status = rdmsr(MSR_MC_STATUS(bank)); if (!(status & MC_STATUS_VAL)) return (0); /* Save exception information. */ rec->mr_status = status; rec->mr_bank = bank; rec->mr_addr = 0; if (status & MC_STATUS_ADDRV) rec->mr_addr = rdmsr(MSR_MC_ADDR(bank)); rec->mr_misc = 0; if (status & MC_STATUS_MISCV) rec->mr_misc = rdmsr(MSR_MC_MISC(bank)); rec->mr_tsc = rdtsc(); rec->mr_apic_id = PCPU_GET(apic_id); rec->mr_mcg_cap = rdmsr(MSR_MCG_CAP); rec->mr_mcg_status = rdmsr(MSR_MCG_STATUS); rec->mr_cpu_id = cpu_id; rec->mr_cpu_vendor_id = cpu_vendor_id; rec->mr_cpu = PCPU_GET(cpuid); /* * Clear machine check. Don't do this for uncorrectable * errors so that the BIOS can see them. */ if (!(rec->mr_status & (MC_STATUS_PCC | MC_STATUS_UC))) { wrmsr(MSR_MC_STATUS(bank), 0); do_cpuid(0, p); } return (1); } static void __nonnull(1) mca_record_entry(const struct mca_record *record) { struct mca_internal *rec; rec = malloc(sizeof(*rec), M_MCA, M_NOWAIT); if (rec == NULL) { printf("MCA: Unable to allocate space for an event.\n"); mca_log(record); return; } rec->rec = *record; rec->logged = 0; mtx_lock_spin(&mca_lock); STAILQ_INSERT_TAIL(&mca_records, rec, link); mca_count++; mtx_unlock_spin(&mca_lock); } /* * Update the interrupt threshold for a CMCI. The strategy is to use * a low trigger that interrupts as soon as the first event occurs. * However, if a steady stream of events arrive, the threshold is * increased until the interrupts are throttled to once every * cmc_throttle seconds or the periodic scan. If a periodic scan * finds that the threshold is too high, it is lowered. */ static void cmci_update(enum scan_mode mode, int bank, int valid, struct mca_record *rec) { struct cmc_state *cc; uint64_t ctl; u_int delta; int count, limit; /* Fetch the current limit for this bank. */ cc = &cmc_state[PCPU_GET(cpuid)][bank]; ctl = rdmsr(MSR_MC_CTL2(bank)); count = (rec->mr_status & MC_STATUS_COR_COUNT) >> 38; delta = (u_int)(ticks - cc->last_intr); /* * If an interrupt was received less than cmc_throttle seconds * since the previous interrupt and the count from the current * event is greater than or equal to the current threshold, * double the threshold up to the max. */ if (mode == CMCI && valid) { limit = ctl & MC_CTL2_THRESHOLD; if (delta < cmc_throttle && count >= limit && limit < cc->max_threshold) { limit = min(limit << 1, cc->max_threshold); ctl &= ~MC_CTL2_THRESHOLD; ctl |= limit; wrmsr(MSR_MC_CTL2(bank), limit); } cc->last_intr = ticks; return; } /* * When the banks are polled, check to see if the threshold * should be lowered. */ if (mode != POLLED) return; /* If a CMCI occured recently, do nothing for now. */ if (delta < cmc_throttle) return; /* * Compute a new limit based on the average rate of events per * cmc_throttle seconds since the last interrupt. */ if (valid) { count = (rec->mr_status & MC_STATUS_COR_COUNT) >> 38; limit = count * cmc_throttle / delta; if (limit <= 0) limit = 1; else if (limit > cc->max_threshold) limit = cc->max_threshold; } else limit = 1; if ((ctl & MC_CTL2_THRESHOLD) != limit) { ctl &= ~MC_CTL2_THRESHOLD; ctl |= limit; wrmsr(MSR_MC_CTL2(bank), limit); } } /* * This scans all the machine check banks of the current CPU to see if * there are any machine checks. Any non-recoverable errors are * reported immediately via mca_log(). The current thread must be * pinned when this is called. The 'mode' parameter indicates if we * are being called from the MC exception handler, the CMCI handler, * or the periodic poller. In the MC exception case this function * returns true if the system is restartable. Otherwise, it returns a * count of the number of valid MC records found. */ static int mca_scan(enum scan_mode mode) { struct mca_record rec; uint64_t mcg_cap, ucmask; int count, i, recoverable, valid; count = 0; recoverable = 1; ucmask = MC_STATUS_UC | MC_STATUS_PCC; /* When handling a MCE#, treat the OVER flag as non-restartable. */ if (mode == MCE) ucmask |= MC_STATUS_OVER; mcg_cap = rdmsr(MSR_MCG_CAP); for (i = 0; i < (mcg_cap & MCG_CAP_COUNT); i++) { /* * For a CMCI, only check banks this CPU is * responsible for. */ if (mode == CMCI && !(PCPU_GET(cmci_mask) & 1 << i)) continue; valid = mca_check_status(i, &rec); if (valid) { count++; if (rec.mr_status & ucmask) { recoverable = 0; mca_log(&rec); } mca_record_entry(&rec); } /* * If this is a bank this CPU monitors via CMCI, * update the threshold. */ if (PCPU_GET(cmci_mask) & (1 << i)) cmci_update(mode, i, valid, &rec); } return (mode == MCE ? recoverable : count); } /* * Scan the machine check banks on all CPUs by binding to each CPU in * turn. If any of the CPUs contained new machine check records, log * them to the console. */ static void mca_scan_cpus(void *context, int pending) { struct mca_internal *mca; struct thread *td; int count, cpu; td = curthread; count = 0; thread_lock(td); for (cpu = 0; cpu <= mp_maxid; cpu++) { if (CPU_ABSENT(cpu)) continue; sched_bind(td, cpu); thread_unlock(td); count += mca_scan(POLLED); thread_lock(td); sched_unbind(td); } thread_unlock(td); if (count != 0) { mtx_lock_spin(&mca_lock); STAILQ_FOREACH(mca, &mca_records, link) { if (!mca->logged) { mca->logged = 1; mtx_unlock_spin(&mca_lock); mca_log(&mca->rec); mtx_lock_spin(&mca_lock); } } mtx_unlock_spin(&mca_lock); } } static void mca_periodic_scan(void *arg) { taskqueue_enqueue(taskqueue_thread, &mca_task); callout_reset(&mca_timer, mca_ticks * hz, mca_periodic_scan, NULL); } static int sysctl_mca_scan(SYSCTL_HANDLER_ARGS) { int error, i; i = 0; error = sysctl_handle_int(oidp, &i, 0, req); if (error) return (error); if (i) taskqueue_enqueue(taskqueue_thread, &mca_task); return (0); } static void mca_startup(void *dummy) { if (!mca_enabled || !(cpu_feature & CPUID_MCA)) return; callout_reset(&mca_timer, mca_ticks * hz, mca_periodic_scan, NULL); } SYSINIT(mca_startup, SI_SUB_SMP, SI_ORDER_ANY, mca_startup, NULL); static void cmci_setup(uint64_t mcg_cap) { int i; cmc_state = malloc((mp_maxid + 1) * sizeof(struct cmc_state **), M_MCA, M_WAITOK); cmc_banks = mcg_cap & MCG_CAP_COUNT; for (i = 0; i <= mp_maxid; i++) cmc_state[i] = malloc(sizeof(struct cmc_state) * cmc_banks, M_MCA, M_WAITOK | M_ZERO); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "cmc_throttle", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &cmc_throttle, 0, sysctl_positive_int, "I", "Interval in seconds to throttle corrected MC interrupts"); } static void mca_setup(uint64_t mcg_cap) { /* * On AMD Family 10h processors, unless logging of level one TLB * parity (L1TP) errors is disabled, enable the recommended workaround * for Erratum 383. */ if (cpu_vendor_id == CPU_VENDOR_AMD && CPUID_TO_FAMILY(cpu_id) == 0x10 && amd10h_L1TP) workaround_erratum383 = 1; mtx_init(&mca_lock, "mca", NULL, MTX_SPIN); STAILQ_INIT(&mca_records); TASK_INIT(&mca_task, 0x8000, mca_scan_cpus, NULL); callout_init(&mca_timer, CALLOUT_MPSAFE); SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "count", CTLFLAG_RD, &mca_count, 0, "Record count"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "interval", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &mca_ticks, 0, sysctl_positive_int, "I", "Periodic interval in seconds to scan for machine checks"); SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "records", CTLFLAG_RD, sysctl_mca_records, "Machine check records"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "force_scan", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0, sysctl_mca_scan, "I", "Force an immediate scan for machine checks"); if (mcg_cap & MCG_CAP_CMCI_P) cmci_setup(mcg_cap); } /* * See if we should monitor CMCI for this bank. If CMCI_EN is already * set in MC_CTL2, then another CPU is responsible for this bank, so * ignore it. If CMCI_EN returns zero after being set, then this bank * does not support CMCI_EN. If this CPU sets CMCI_EN, then it should * now monitor this bank. */ static void cmci_monitor(int i) { struct cmc_state *cc; uint64_t ctl; KASSERT(i < cmc_banks, ("CPU %d has more MC banks", PCPU_GET(cpuid))); ctl = rdmsr(MSR_MC_CTL2(i)); if (ctl & MC_CTL2_CMCI_EN) /* Already monitored by another CPU. */ return; /* Set the threshold to one event for now. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= MC_CTL2_CMCI_EN | 1; wrmsr(MSR_MC_CTL2(i), ctl); ctl = rdmsr(MSR_MC_CTL2(i)); if (!(ctl & MC_CTL2_CMCI_EN)) /* This bank does not support CMCI. */ return; cc = &cmc_state[PCPU_GET(cpuid)][i]; /* Determine maximum threshold. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= 0x7fff; wrmsr(MSR_MC_CTL2(i), ctl); ctl = rdmsr(MSR_MC_CTL2(i)); cc->max_threshold = ctl & MC_CTL2_THRESHOLD; /* Start off with a threshold of 1. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= 1; wrmsr(MSR_MC_CTL2(i), ctl); /* Mark this bank as monitored. */ PCPU_SET(cmci_mask, PCPU_GET(cmci_mask) | 1 << i); } /* * For resume, reset the threshold for any banks we monitor back to * one and throw away the timestamp of the last interrupt. */ static void cmci_resume(int i) { struct cmc_state *cc; uint64_t ctl; KASSERT(i < cmc_banks, ("CPU %d has more MC banks", PCPU_GET(cpuid))); /* Ignore banks not monitored by this CPU. */ if (!(PCPU_GET(cmci_mask) & 1 << i)) return; cc = &cmc_state[PCPU_GET(cpuid)][i]; cc->last_intr = -ticks; ctl = rdmsr(MSR_MC_CTL2(i)); ctl &= ~MC_CTL2_THRESHOLD; ctl |= MC_CTL2_CMCI_EN | 1; wrmsr(MSR_MC_CTL2(i), ctl); } /* * Initializes per-CPU machine check registers and enables corrected * machine check interrupts. */ static void _mca_init(int boot) { uint64_t mcg_cap; uint64_t ctl, mask; int i, skip; /* MCE is required. */ if (!mca_enabled || !(cpu_feature & CPUID_MCE)) return; if (cpu_feature & CPUID_MCA) { if (boot) PCPU_SET(cmci_mask, 0); mcg_cap = rdmsr(MSR_MCG_CAP); if (mcg_cap & MCG_CAP_CTL_P) /* Enable MCA features. */ wrmsr(MSR_MCG_CTL, MCG_CTL_ENABLE); if (PCPU_GET(cpuid) == 0 && boot) mca_setup(mcg_cap); /* * Disable logging of level one TLB parity (L1TP) errors by * the data cache as an alternative workaround for AMD Family * 10h Erratum 383. Unlike the recommended workaround, there * is no performance penalty to this workaround. However, * L1TP errors will go unreported. */ if (cpu_vendor_id == CPU_VENDOR_AMD && CPUID_TO_FAMILY(cpu_id) == 0x10 && !amd10h_L1TP) { mask = rdmsr(MSR_MC0_CTL_MASK); if ((mask & (1UL << 5)) == 0) wrmsr(MSR_MC0_CTL_MASK, mask | (1UL << 5)); } for (i = 0; i < (mcg_cap & MCG_CAP_COUNT); i++) { /* By default enable logging of all errors. */ ctl = 0xffffffffffffffffUL; skip = 0; if (cpu_vendor_id == CPU_VENDOR_INTEL) { /* * For P6 models before Nehalem MC0_CTL is * always enabled and reserved. */ if (i == 0 && CPUID_TO_FAMILY(cpu_id) == 0x6 && CPUID_TO_MODEL(cpu_id) < 0x1a) skip = 1; } else if (cpu_vendor_id == CPU_VENDOR_AMD) { /* BKDG for Family 10h: unset GartTblWkEn. */ if (i == 4 && CPUID_TO_FAMILY(cpu_id) >= 0xf) ctl &= ~(1UL << 10); } if (!skip) wrmsr(MSR_MC_CTL(i), ctl); if (mcg_cap & MCG_CAP_CMCI_P) { if (boot) cmci_monitor(i); else cmci_resume(i); } /* Clear all errors. */ wrmsr(MSR_MC_STATUS(i), 0); } if (PCPU_GET(cmci_mask) != 0 && boot) lapic_enable_cmc(); } load_cr4(rcr4() | CR4_MCE); } /* Must be executed on each CPU during boot. */ void mca_init(void) { _mca_init(1); } /* Must be executed on each CPU during resume. */ void mca_resume(void) { _mca_init(0); } /* * The machine check registers for the BSP cannot be initialized until * the local APIC is initialized. This happens at SI_SUB_CPU, * SI_ORDER_SECOND. */ static void mca_init_bsp(void *arg __unused) { mca_init(); } SYSINIT(mca_init_bsp, SI_SUB_CPU, SI_ORDER_ANY, mca_init_bsp, NULL); /* Called when a machine check exception fires. */ int mca_intr(void) { uint64_t mcg_status; int recoverable; if (!(cpu_feature & CPUID_MCA)) { /* * Just print the values of the old Pentium registers * and panic. */ printf("MC Type: 0x%lx Address: 0x%lx\n", rdmsr(MSR_P5_MC_TYPE), rdmsr(MSR_P5_MC_ADDR)); return (0); } /* Scan the banks and check for any non-recoverable errors. */ recoverable = mca_scan(MCE); mcg_status = rdmsr(MSR_MCG_STATUS); if (!(mcg_status & MCG_STATUS_RIPV)) recoverable = 0; /* Clear MCIP. */ wrmsr(MSR_MCG_STATUS, mcg_status & ~MCG_STATUS_MCIP); return (recoverable); } /* Called for a CMCI (correctable machine check interrupt). */ void cmc_intr(void) { struct mca_internal *mca; int count; /* * Serialize MCA bank scanning to prevent collisions from * sibling threads. */ count = mca_scan(CMCI); /* If we found anything, log them to the console. */ if (count != 0) { mtx_lock_spin(&mca_lock); STAILQ_FOREACH(mca, &mca_records, link) { if (!mca->logged) { mca->logged = 1; mtx_unlock_spin(&mca_lock); mca_log(&mca->rec); mtx_lock_spin(&mca_lock); } } mtx_unlock_spin(&mca_lock); } } Index: stable/7/sys/amd64/include/mca.h =================================================================== --- stable/7/sys/amd64/include/mca.h (revision 283926) +++ stable/7/sys/amd64/include/mca.h (revision 283927) @@ -1,56 +1,56 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef __MACHINE_MCA_H__ #define __MACHINE_MCA_H__ struct mca_record { uint64_t mr_status; uint64_t mr_addr; uint64_t mr_misc; uint64_t mr_tsc; int mr_apic_id; int mr_bank; uint64_t mr_mcg_cap; uint64_t mr_mcg_status; int mr_cpu_id; int mr_cpu_vendor_id; int mr_cpu; }; #ifdef _KERNEL void cmc_intr(void); void mca_init(void); int mca_intr(void); void mca_resume(void); #endif #endif /* !__MACHINE_MCA_H__ */ Index: stable/7/sys/amd64/include/vm.h =================================================================== --- stable/7/sys/amd64/include/vm.h (revision 283926) +++ stable/7/sys/amd64/include/vm.h (revision 283927) @@ -1,45 +1,45 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _MACHINE_VM_H_ #define _MACHINE_VM_H_ #include /* Memory attributes. */ #define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHEABLE) #define VM_MEMATTR_WRITE_COMBINING ((vm_memattr_t)PAT_WRITE_COMBINING) #define VM_MEMATTR_WRITE_THROUGH ((vm_memattr_t)PAT_WRITE_THROUGH) #define VM_MEMATTR_WRITE_PROTECTED ((vm_memattr_t)PAT_WRITE_PROTECTED) #define VM_MEMATTR_WRITE_BACK ((vm_memattr_t)PAT_WRITE_BACK) #define VM_MEMATTR_UNCACHED ((vm_memattr_t)PAT_UNCACHED) #define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK #endif /* !_MACHINE_PMAP_H_ */ Index: stable/7/sys/i386/i386/mca.c =================================================================== --- stable/7/sys/i386/i386/mca.c (revision 283926) +++ stable/7/sys/i386/i386/mca.c (revision 283927) @@ -1,931 +1,931 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ /* * Support for x86 machine check architecture. */ #include __FBSDID("$FreeBSD$"); #include "opt_apic.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Modes for mca_scan() */ enum scan_mode { POLLED, MCE, CMCI, }; #ifdef DEV_APIC /* * State maintained for each monitored MCx bank to control the * corrected machine check interrupt threshold. */ struct cmc_state { int max_threshold; int last_intr; }; #endif struct mca_internal { struct mca_record rec; int logged; STAILQ_ENTRY(mca_internal) link; }; static MALLOC_DEFINE(M_MCA, "MCA", "Machine Check Architecture"); static int mca_count; /* Number of records stored. */ SYSCTL_NODE(_hw, OID_AUTO, mca, CTLFLAG_RD, NULL, "Machine Check Architecture"); static int mca_enabled = 1; TUNABLE_INT("hw.mca.enabled", &mca_enabled); SYSCTL_INT(_hw_mca, OID_AUTO, enabled, CTLFLAG_RDTUN, &mca_enabled, 0, "Administrative toggle for machine check support"); static int amd10h_L1TP = 1; TUNABLE_INT("hw.mca.amd10h_L1TP", &amd10h_L1TP); SYSCTL_INT(_hw_mca, OID_AUTO, amd10h_L1TP, CTLFLAG_RDTUN, &amd10h_L1TP, 0, "Administrative toggle for logging of level one TLB parity (L1TP) errors"); int workaround_erratum383; SYSCTL_INT(_hw_mca, OID_AUTO, erratum383, CTLFLAG_RD, &workaround_erratum383, 0, "Is the workaround for Erratum 383 on AMD Family 10h processors enabled?"); static STAILQ_HEAD(, mca_internal) mca_records; static struct callout mca_timer; static int mca_ticks = 3600; /* Check hourly by default. */ static struct task mca_task; static struct mtx mca_lock; #ifdef DEV_APIC static struct cmc_state **cmc_state; /* Indexed by cpuid, bank */ static int cmc_banks; static int cmc_throttle = 60; /* Time in seconds to throttle CMCI. */ #endif static int sysctl_positive_int(SYSCTL_HANDLER_ARGS) { int error, value; value = *(int *)arg1; error = sysctl_handle_int(oidp, &value, 0, req); if (error || req->newptr == NULL) return (error); if (value <= 0) return (EINVAL); *(int *)arg1 = value; return (0); } static int sysctl_mca_records(SYSCTL_HANDLER_ARGS) { int *name = (int *)arg1; u_int namelen = arg2; struct mca_record record; struct mca_internal *rec; int i; if (namelen != 1) return (EINVAL); if (name[0] < 0 || name[0] >= mca_count) return (EINVAL); mtx_lock_spin(&mca_lock); if (name[0] >= mca_count) { mtx_unlock_spin(&mca_lock); return (EINVAL); } i = 0; STAILQ_FOREACH(rec, &mca_records, link) { if (i == name[0]) { record = rec->rec; break; } i++; } mtx_unlock_spin(&mca_lock); return (SYSCTL_OUT(req, &record, sizeof(record))); } static const char * mca_error_ttype(uint16_t mca_error) { switch ((mca_error & 0x000c) >> 2) { case 0: return ("I"); case 1: return ("D"); case 2: return ("G"); } return ("?"); } static const char * mca_error_level(uint16_t mca_error) { switch (mca_error & 0x0003) { case 0: return ("L0"); case 1: return ("L1"); case 2: return ("L2"); case 3: return ("LG"); } return ("L?"); } static const char * mca_error_request(uint16_t mca_error) { switch ((mca_error & 0x00f0) >> 4) { case 0x0: return ("ERR"); case 0x1: return ("RD"); case 0x2: return ("WR"); case 0x3: return ("DRD"); case 0x4: return ("DWR"); case 0x5: return ("IRD"); case 0x6: return ("PREFETCH"); case 0x7: return ("EVICT"); case 0x8: return ("SNOOP"); } return ("???"); } static const char * mca_error_mmtype(uint16_t mca_error) { switch ((mca_error & 0x70) >> 4) { case 0x0: return ("GEN"); case 0x1: return ("RD"); case 0x2: return ("WR"); case 0x3: return ("AC"); case 0x4: return ("MS"); } return ("???"); } /* Dump details about a single machine check. */ static void __nonnull(1) mca_log(const struct mca_record *rec) { uint16_t mca_error; printf("MCA: Bank %d, Status 0x%016llx\n", rec->mr_bank, (long long)rec->mr_status); printf("MCA: Global Cap 0x%016llx, Status 0x%016llx\n", (long long)rec->mr_mcg_cap, (long long)rec->mr_mcg_status); printf("MCA: Vendor \"%s\", ID 0x%x, APIC ID %d\n", cpu_vendor, rec->mr_cpu_id, rec->mr_apic_id); printf("MCA: CPU %d ", rec->mr_cpu); if (rec->mr_status & MC_STATUS_UC) printf("UNCOR "); else { printf("COR "); if (rec->mr_mcg_cap & MCG_CAP_CMCI_P) printf("(%lld) ", ((long long)rec->mr_status & MC_STATUS_COR_COUNT) >> 38); } if (rec->mr_status & MC_STATUS_PCC) printf("PCC "); if (rec->mr_status & MC_STATUS_OVER) printf("OVER "); mca_error = rec->mr_status & MC_STATUS_MCA_ERROR; switch (mca_error) { /* Simple error codes. */ case 0x0000: printf("no error"); break; case 0x0001: printf("unclassified error"); break; case 0x0002: printf("ucode ROM parity error"); break; case 0x0003: printf("external error"); break; case 0x0004: printf("FRC error"); break; case 0x0005: printf("internal parity error"); break; case 0x0400: printf("internal timer error"); break; default: if ((mca_error & 0xfc00) == 0x0400) { printf("internal error %x", mca_error & 0x03ff); break; } /* Compound error codes. */ /* Memory hierarchy error. */ if ((mca_error & 0xeffc) == 0x000c) { printf("%s memory error", mca_error_level(mca_error)); break; } /* TLB error. */ if ((mca_error & 0xeff0) == 0x0010) { printf("%sTLB %s error", mca_error_ttype(mca_error), mca_error_level(mca_error)); break; } /* Memory controller error. */ if ((mca_error & 0xef80) == 0x0080) { printf("%s channel ", mca_error_mmtype(mca_error)); if ((mca_error & 0x000f) != 0x000f) printf("%d", mca_error & 0x000f); else printf("??"); printf(" memory error"); break; } /* Cache error. */ if ((mca_error & 0xef00) == 0x0100) { printf("%sCACHE %s %s error", mca_error_ttype(mca_error), mca_error_level(mca_error), mca_error_request(mca_error)); break; } /* Bus and/or Interconnect error. */ if ((mca_error & 0xe800) == 0x0800) { printf("BUS%s ", mca_error_level(mca_error)); switch ((mca_error & 0x0600) >> 9) { case 0: printf("Source"); break; case 1: printf("Responder"); break; case 2: printf("Observer"); break; default: printf("???"); break; } printf(" %s ", mca_error_request(mca_error)); switch ((mca_error & 0x000c) >> 2) { case 0: printf("Memory"); break; case 2: printf("I/O"); break; case 3: printf("Other"); break; default: printf("???"); break; } if (mca_error & 0x0100) printf(" timed out"); break; } printf("unknown error %x", mca_error); break; } printf("\n"); if (rec->mr_status & MC_STATUS_ADDRV) printf("MCA: Address 0x%llx\n", (long long)rec->mr_addr); if (rec->mr_status & MC_STATUS_MISCV) printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc); } static int __nonnull(2) mca_check_status(int bank, struct mca_record *rec) { uint64_t status; u_int p[4]; status = rdmsr(MSR_MC_STATUS(bank)); if (!(status & MC_STATUS_VAL)) return (0); /* Save exception information. */ rec->mr_status = status; rec->mr_bank = bank; rec->mr_addr = 0; if (status & MC_STATUS_ADDRV) rec->mr_addr = rdmsr(MSR_MC_ADDR(bank)); rec->mr_misc = 0; if (status & MC_STATUS_MISCV) rec->mr_misc = rdmsr(MSR_MC_MISC(bank)); rec->mr_tsc = rdtsc(); rec->mr_apic_id = PCPU_GET(apic_id); rec->mr_mcg_cap = rdmsr(MSR_MCG_CAP); rec->mr_mcg_status = rdmsr(MSR_MCG_STATUS); rec->mr_cpu_id = cpu_id; rec->mr_cpu_vendor_id = cpu_vendor_id; rec->mr_cpu = PCPU_GET(cpuid); /* * Clear machine check. Don't do this for uncorrectable * errors so that the BIOS can see them. */ if (!(rec->mr_status & (MC_STATUS_PCC | MC_STATUS_UC))) { wrmsr(MSR_MC_STATUS(bank), 0); do_cpuid(0, p); } return (1); } static void __nonnull(1) mca_record_entry(const struct mca_record *record) { struct mca_internal *rec; rec = malloc(sizeof(*rec), M_MCA, M_NOWAIT); if (rec == NULL) { printf("MCA: Unable to allocate space for an event.\n"); mca_log(record); return; } rec->rec = *record; rec->logged = 0; mtx_lock_spin(&mca_lock); STAILQ_INSERT_TAIL(&mca_records, rec, link); mca_count++; mtx_unlock_spin(&mca_lock); } #ifdef DEV_APIC /* * Update the interrupt threshold for a CMCI. The strategy is to use * a low trigger that interrupts as soon as the first event occurs. * However, if a steady stream of events arrive, the threshold is * increased until the interrupts are throttled to once every * cmc_throttle seconds or the periodic scan. If a periodic scan * finds that the threshold is too high, it is lowered. */ static void cmci_update(enum scan_mode mode, int bank, int valid, struct mca_record *rec) { struct cmc_state *cc; uint64_t ctl; u_int delta; int count, limit; /* Fetch the current limit for this bank. */ cc = &cmc_state[PCPU_GET(cpuid)][bank]; ctl = rdmsr(MSR_MC_CTL2(bank)); count = (rec->mr_status & MC_STATUS_COR_COUNT) >> 38; delta = (u_int)(ticks - cc->last_intr); /* * If an interrupt was received less than cmc_throttle seconds * since the previous interrupt and the count from the current * event is greater than or equal to the current threshold, * double the threshold up to the max. */ if (mode == CMCI && valid) { limit = ctl & MC_CTL2_THRESHOLD; if (delta < cmc_throttle && count >= limit && limit < cc->max_threshold) { limit = min(limit << 1, cc->max_threshold); ctl &= ~MC_CTL2_THRESHOLD; ctl |= limit; wrmsr(MSR_MC_CTL2(bank), limit); } cc->last_intr = ticks; return; } /* * When the banks are polled, check to see if the threshold * should be lowered. */ if (mode != POLLED) return; /* If a CMCI occured recently, do nothing for now. */ if (delta < cmc_throttle) return; /* * Compute a new limit based on the average rate of events per * cmc_throttle seconds since the last interrupt. */ if (valid) { count = (rec->mr_status & MC_STATUS_COR_COUNT) >> 38; limit = count * cmc_throttle / delta; if (limit <= 0) limit = 1; else if (limit > cc->max_threshold) limit = cc->max_threshold; } else limit = 1; if ((ctl & MC_CTL2_THRESHOLD) != limit) { ctl &= ~MC_CTL2_THRESHOLD; ctl |= limit; wrmsr(MSR_MC_CTL2(bank), limit); } } #endif /* * This scans all the machine check banks of the current CPU to see if * there are any machine checks. Any non-recoverable errors are * reported immediately via mca_log(). The current thread must be * pinned when this is called. The 'mode' parameter indicates if we * are being called from the MC exception handler, the CMCI handler, * or the periodic poller. In the MC exception case this function * returns true if the system is restartable. Otherwise, it returns a * count of the number of valid MC records found. */ static int mca_scan(enum scan_mode mode) { struct mca_record rec; uint64_t mcg_cap, ucmask; int count, i, recoverable, valid; count = 0; recoverable = 1; ucmask = MC_STATUS_UC | MC_STATUS_PCC; /* When handling a MCE#, treat the OVER flag as non-restartable. */ if (mode == MCE) ucmask |= MC_STATUS_OVER; mcg_cap = rdmsr(MSR_MCG_CAP); for (i = 0; i < (mcg_cap & MCG_CAP_COUNT); i++) { #ifdef DEV_APIC /* * For a CMCI, only check banks this CPU is * responsible for. */ if (mode == CMCI && !(PCPU_GET(cmci_mask) & 1 << i)) continue; #endif valid = mca_check_status(i, &rec); if (valid) { count++; if (rec.mr_status & ucmask) { recoverable = 0; mca_log(&rec); } mca_record_entry(&rec); } #ifdef DEV_APIC /* * If this is a bank this CPU monitors via CMCI, * update the threshold. */ if (PCPU_GET(cmci_mask) & (1 << i)) cmci_update(mode, i, valid, &rec); #endif } return (mode == MCE ? recoverable : count); } /* * Scan the machine check banks on all CPUs by binding to each CPU in * turn. If any of the CPUs contained new machine check records, log * them to the console. */ static void mca_scan_cpus(void *context, int pending) { struct mca_internal *mca; struct thread *td; int count, cpu; td = curthread; count = 0; thread_lock(td); for (cpu = 0; cpu <= mp_maxid; cpu++) { if (CPU_ABSENT(cpu)) continue; sched_bind(td, cpu); thread_unlock(td); count += mca_scan(POLLED); thread_lock(td); sched_unbind(td); } thread_unlock(td); if (count != 0) { mtx_lock_spin(&mca_lock); STAILQ_FOREACH(mca, &mca_records, link) { if (!mca->logged) { mca->logged = 1; mtx_unlock_spin(&mca_lock); mca_log(&mca->rec); mtx_lock_spin(&mca_lock); } } mtx_unlock_spin(&mca_lock); } } static void mca_periodic_scan(void *arg) { taskqueue_enqueue(taskqueue_thread, &mca_task); callout_reset(&mca_timer, mca_ticks * hz, mca_periodic_scan, NULL); } static int sysctl_mca_scan(SYSCTL_HANDLER_ARGS) { int error, i; i = 0; error = sysctl_handle_int(oidp, &i, 0, req); if (error) return (error); if (i) taskqueue_enqueue(taskqueue_thread, &mca_task); return (0); } static void mca_startup(void *dummy) { if (!mca_enabled || !(cpu_feature & CPUID_MCA)) return; callout_reset(&mca_timer, mca_ticks * hz, mca_periodic_scan, NULL); } SYSINIT(mca_startup, SI_SUB_SMP, SI_ORDER_ANY, mca_startup, NULL); #ifdef DEV_APIC static void cmci_setup(uint64_t mcg_cap) { int i; cmc_state = malloc((mp_maxid + 1) * sizeof(struct cmc_state **), M_MCA, M_WAITOK); cmc_banks = mcg_cap & MCG_CAP_COUNT; for (i = 0; i <= mp_maxid; i++) cmc_state[i] = malloc(sizeof(struct cmc_state) * cmc_banks, M_MCA, M_WAITOK | M_ZERO); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "cmc_throttle", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &cmc_throttle, 0, sysctl_positive_int, "I", "Interval in seconds to throttle corrected MC interrupts"); } #endif static void mca_setup(uint64_t mcg_cap) { /* * On AMD Family 10h processors, unless logging of level one TLB * parity (L1TP) errors is disabled, enable the recommended workaround * for Erratum 383. */ if (cpu_vendor_id == CPU_VENDOR_AMD && CPUID_TO_FAMILY(cpu_id) == 0x10 && amd10h_L1TP) workaround_erratum383 = 1; mtx_init(&mca_lock, "mca", NULL, MTX_SPIN); STAILQ_INIT(&mca_records); TASK_INIT(&mca_task, 0x8000, mca_scan_cpus, NULL); callout_init(&mca_timer, CALLOUT_MPSAFE); SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "count", CTLFLAG_RD, &mca_count, 0, "Record count"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "interval", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &mca_ticks, 0, sysctl_positive_int, "I", "Periodic interval in seconds to scan for machine checks"); SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "records", CTLFLAG_RD, sysctl_mca_records, "Machine check records"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "force_scan", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0, sysctl_mca_scan, "I", "Force an immediate scan for machine checks"); #ifdef DEV_APIC if (mcg_cap & MCG_CAP_CMCI_P) cmci_setup(mcg_cap); #endif } #ifdef DEV_APIC /* * See if we should monitor CMCI for this bank. If CMCI_EN is already * set in MC_CTL2, then another CPU is responsible for this bank, so * ignore it. If CMCI_EN returns zero after being set, then this bank * does not support CMCI_EN. If this CPU sets CMCI_EN, then it should * now monitor this bank. */ static void cmci_monitor(int i) { struct cmc_state *cc; uint64_t ctl; KASSERT(i < cmc_banks, ("CPU %d has more MC banks", PCPU_GET(cpuid))); ctl = rdmsr(MSR_MC_CTL2(i)); if (ctl & MC_CTL2_CMCI_EN) /* Already monitored by another CPU. */ return; /* Set the threshold to one event for now. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= MC_CTL2_CMCI_EN | 1; wrmsr(MSR_MC_CTL2(i), ctl); ctl = rdmsr(MSR_MC_CTL2(i)); if (!(ctl & MC_CTL2_CMCI_EN)) /* This bank does not support CMCI. */ return; cc = &cmc_state[PCPU_GET(cpuid)][i]; /* Determine maximum threshold. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= 0x7fff; wrmsr(MSR_MC_CTL2(i), ctl); ctl = rdmsr(MSR_MC_CTL2(i)); cc->max_threshold = ctl & MC_CTL2_THRESHOLD; /* Start off with a threshold of 1. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= 1; wrmsr(MSR_MC_CTL2(i), ctl); /* Mark this bank as monitored. */ PCPU_SET(cmci_mask, PCPU_GET(cmci_mask) | 1 << i); } /* * For resume, reset the threshold for any banks we monitor back to * one and throw away the timestamp of the last interrupt. */ static void cmci_resume(int i) { struct cmc_state *cc; uint64_t ctl; KASSERT(i < cmc_banks, ("CPU %d has more MC banks", PCPU_GET(cpuid))); /* Ignore banks not monitored by this CPU. */ if (!(PCPU_GET(cmci_mask) & 1 << i)) return; cc = &cmc_state[PCPU_GET(cpuid)][i]; cc->last_intr = -ticks; ctl = rdmsr(MSR_MC_CTL2(i)); ctl &= ~MC_CTL2_THRESHOLD; ctl |= MC_CTL2_CMCI_EN | 1; wrmsr(MSR_MC_CTL2(i), ctl); } #endif /* * Initializes per-CPU machine check registers and enables corrected * machine check interrupts. */ static void _mca_init(int boot) { uint64_t mcg_cap; uint64_t ctl, mask; int i, skip; /* MCE is required. */ if (!mca_enabled || !(cpu_feature & CPUID_MCE)) return; if (cpu_feature & CPUID_MCA) { if (boot) PCPU_SET(cmci_mask, 0); mcg_cap = rdmsr(MSR_MCG_CAP); if (mcg_cap & MCG_CAP_CTL_P) /* Enable MCA features. */ wrmsr(MSR_MCG_CTL, MCG_CTL_ENABLE); if (PCPU_GET(cpuid) == 0 && boot) mca_setup(mcg_cap); /* * Disable logging of level one TLB parity (L1TP) errors by * the data cache as an alternative workaround for AMD Family * 10h Erratum 383. Unlike the recommended workaround, there * is no performance penalty to this workaround. However, * L1TP errors will go unreported. */ if (cpu_vendor_id == CPU_VENDOR_AMD && CPUID_TO_FAMILY(cpu_id) == 0x10 && !amd10h_L1TP) { mask = rdmsr(MSR_MC0_CTL_MASK); if ((mask & (1UL << 5)) == 0) wrmsr(MSR_MC0_CTL_MASK, mask | (1UL << 5)); } for (i = 0; i < (mcg_cap & MCG_CAP_COUNT); i++) { /* By default enable logging of all errors. */ ctl = 0xffffffffffffffffUL; skip = 0; if (cpu_vendor_id == CPU_VENDOR_INTEL) { /* * For P6 models before Nehalem MC0_CTL is * always enabled and reserved. */ if (i == 0 && CPUID_TO_FAMILY(cpu_id) == 0x6 && CPUID_TO_MODEL(cpu_id) < 0x1a) skip = 1; } else if (cpu_vendor_id == CPU_VENDOR_AMD) { /* BKDG for Family 10h: unset GartTblWkEn. */ if (i == 4 && CPUID_TO_FAMILY(cpu_id) >= 0xf) ctl &= ~(1UL << 10); } if (!skip) wrmsr(MSR_MC_CTL(i), ctl); #ifdef DEV_APIC if (mcg_cap & MCG_CAP_CMCI_P) { if (boot) cmci_monitor(i); else cmci_resume(i); } #endif /* Clear all errors. */ wrmsr(MSR_MC_STATUS(i), 0); } #ifdef DEV_APIC if (PCPU_GET(cmci_mask) != 0 && boot) lapic_enable_cmc(); #endif } load_cr4(rcr4() | CR4_MCE); } /* Must be executed on each CPU during boot. */ void mca_init(void) { _mca_init(1); } /* Must be executed on each CPU during resume. */ void mca_resume(void) { _mca_init(0); } /* * The machine check registers for the BSP cannot be initialized until * the local APIC is initialized. This happens at SI_SUB_CPU, * SI_ORDER_SECOND. */ static void mca_init_bsp(void *arg __unused) { mca_init(); } SYSINIT(mca_init_bsp, SI_SUB_CPU, SI_ORDER_ANY, mca_init_bsp, NULL); /* Called when a machine check exception fires. */ int mca_intr(void) { uint64_t mcg_status; int recoverable; if (!(cpu_feature & CPUID_MCA)) { /* * Just print the values of the old Pentium registers * and panic. */ printf("MC Type: 0x%llx Address: 0x%llx\n", rdmsr(MSR_P5_MC_TYPE), rdmsr(MSR_P5_MC_ADDR)); return (0); } /* Scan the banks and check for any non-recoverable errors. */ recoverable = mca_scan(MCE); mcg_status = rdmsr(MSR_MCG_STATUS); if (!(mcg_status & MCG_STATUS_RIPV)) recoverable = 0; /* Clear MCIP. */ wrmsr(MSR_MCG_STATUS, mcg_status & ~MCG_STATUS_MCIP); return (recoverable); } #ifdef DEV_APIC /* Called for a CMCI (correctable machine check interrupt). */ void cmc_intr(void) { struct mca_internal *mca; int count; /* * Serialize MCA bank scanning to prevent collisions from * sibling threads. */ count = mca_scan(CMCI); /* If we found anything, log them to the console. */ if (count != 0) { mtx_lock_spin(&mca_lock); STAILQ_FOREACH(mca, &mca_records, link) { if (!mca->logged) { mca->logged = 1; mtx_unlock_spin(&mca_lock); mca_log(&mca->rec); mtx_lock_spin(&mca_lock); } } mtx_unlock_spin(&mca_lock); } } #endif Index: stable/7/sys/i386/include/mca.h =================================================================== --- stable/7/sys/i386/include/mca.h (revision 283926) +++ stable/7/sys/i386/include/mca.h (revision 283927) @@ -1,56 +1,56 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef __MACHINE_MCA_H__ #define __MACHINE_MCA_H__ struct mca_record { uint64_t mr_status; uint64_t mr_addr; uint64_t mr_misc; uint64_t mr_tsc; int mr_apic_id; int mr_bank; uint64_t mr_mcg_cap; uint64_t mr_mcg_status; int mr_cpu_id; int mr_cpu_vendor_id; int mr_cpu; }; #ifdef _KERNEL void cmc_intr(void); void mca_init(void); int mca_intr(void); void mca_resume(void); #endif #endif /* !__MACHINE_MCA_H__ */ Index: stable/7/sys/i386/include/vm.h =================================================================== --- stable/7/sys/i386/include/vm.h (revision 283926) +++ stable/7/sys/i386/include/vm.h (revision 283927) @@ -1,45 +1,45 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _MACHINE_VM_H_ #define _MACHINE_VM_H_ #include /* Memory attributes. */ #define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHEABLE) #define VM_MEMATTR_WRITE_COMBINING ((vm_memattr_t)PAT_WRITE_COMBINING) #define VM_MEMATTR_WRITE_THROUGH ((vm_memattr_t)PAT_WRITE_THROUGH) #define VM_MEMATTR_WRITE_PROTECTED ((vm_memattr_t)PAT_WRITE_PROTECTED) #define VM_MEMATTR_WRITE_BACK ((vm_memattr_t)PAT_WRITE_BACK) #define VM_MEMATTR_UNCACHED ((vm_memattr_t)PAT_UNCACHED) #define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK #endif /* !_MACHINE_PMAP_H_ */ Index: stable/7/sys/vm/sg_pager.c =================================================================== --- stable/7/sys/vm/sg_pager.c (revision 283926) +++ stable/7/sys/vm/sg_pager.c (revision 283927) @@ -1,261 +1,261 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); /* * This pager manages OBJT_SG objects. These objects are backed by * a scatter/gather list of physical address ranges. */ #include #include #include #include #include #include #include #include #include #include static void sg_pager_init(void); static vm_object_t sg_pager_alloc(void *, vm_ooffset_t, vm_prot_t, vm_ooffset_t); static void sg_pager_dealloc(vm_object_t); static int sg_pager_getpages(vm_object_t, vm_page_t *, int, int); static void sg_pager_putpages(vm_object_t, vm_page_t *, int, boolean_t, int *); static boolean_t sg_pager_haspage(vm_object_t, vm_pindex_t, int *, int *); static uma_zone_t fakepg_zone; static vm_page_t sg_pager_getfake(vm_paddr_t, vm_memattr_t); static void sg_pager_putfake(vm_page_t); struct pagerops sgpagerops = { .pgo_init = sg_pager_init, .pgo_alloc = sg_pager_alloc, .pgo_dealloc = sg_pager_dealloc, .pgo_getpages = sg_pager_getpages, .pgo_putpages = sg_pager_putpages, .pgo_haspage = sg_pager_haspage, }; static void sg_pager_init(void) { fakepg_zone = uma_zcreate("SG fakepg", sizeof(struct vm_page), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE|UMA_ZONE_VM); } static vm_object_t sg_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff) { struct sglist *sg; vm_object_t object; vm_pindex_t npages, pindex; int i; /* * Offset should be page aligned. */ if (foff & PAGE_MASK) return (NULL); /* * The scatter/gather list must only include page-aligned * ranges. */ npages = 0; sg = handle; for (i = 0; i < sg->sg_nseg; i++) { if ((sg->sg_segs[i].ss_paddr % PAGE_SIZE) != 0 || (sg->sg_segs[i].ss_len % PAGE_SIZE) != 0) return (NULL); npages += sg->sg_segs[i].ss_len / PAGE_SIZE; } /* * The scatter/gather list has a fixed size. Refuse requests * to map beyond that. */ size = round_page(size); pindex = OFF_TO_IDX(foff + size); if (pindex > npages) return (NULL); /* * Allocate a new object and associate it with the * scatter/gather list. It is ok for our purposes to have * multiple VM objects associated with the same scatter/gather * list because scatter/gather lists are static. This is also * simpler than ensuring a unique object per scatter/gather * list. */ object = vm_object_allocate(OBJT_SG, npages); object->handle = sglist_hold(sg); TAILQ_INIT(&object->un_pager.sgp.sgp_pglist); return (object); } static void sg_pager_dealloc(vm_object_t object) { struct sglist *sg; vm_page_t m; /* * Free up our fake pages. */ while ((m = TAILQ_FIRST(&object->un_pager.sgp.sgp_pglist)) != 0) { TAILQ_REMOVE(&object->un_pager.sgp.sgp_pglist, m, pageq); sg_pager_putfake(m); } sg = object->handle; sglist_free(sg); } static int sg_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) { struct sglist *sg; vm_page_t m_paddr, page; vm_pindex_t offset; vm_paddr_t paddr; vm_memattr_t memattr; size_t space; int i; VM_OBJECT_LOCK_ASSERT(object, MA_OWNED); sg = object->handle; memattr = object->memattr; VM_OBJECT_UNLOCK(object); offset = m[reqpage]->pindex; /* * Lookup the physical address of the requested page. An initial * value of '1' instead of '0' is used so we can assert that the * page is found since '0' can be a valid page-aligned physical * address. */ space = 0; paddr = 1; for (i = 0; i < sg->sg_nseg; i++) { if (space + sg->sg_segs[i].ss_len <= (offset * PAGE_SIZE)) { space += sg->sg_segs[i].ss_len; continue; } paddr = sg->sg_segs[i].ss_paddr + offset * PAGE_SIZE - space; break; } KASSERT(paddr != 1, ("invalid SG page index")); /* If "paddr" is a real page, perform a sanity check on "memattr". */ if ((m_paddr = vm_phys_paddr_to_vm_page(paddr)) != NULL && pmap_page_get_memattr(m_paddr) != memattr) { memattr = pmap_page_get_memattr(m_paddr); printf( "WARNING: A device driver has set \"memattr\" inconsistently.\n"); } /* Return a fake page for the requested page. */ KASSERT(!(m[reqpage]->flags & PG_FICTITIOUS), ("backing page for SG is fake")); /* Construct a new fake page. */ page = sg_pager_getfake(paddr, memattr); VM_OBJECT_LOCK(object); TAILQ_INSERT_TAIL(&object->un_pager.sgp.sgp_pglist, page, pageq); /* Free the original pages and insert this fake page into the object. */ vm_page_lock_queues(); for (i = 0; i < count; i++) vm_page_free(m[i]); vm_page_unlock_queues(); vm_page_insert(page, object, offset); m[reqpage] = page; page->valid = VM_PAGE_BITS_ALL; return (VM_PAGER_OK); } static void sg_pager_putpages(vm_object_t object, vm_page_t *m, int count, boolean_t sync, int *rtvals) { panic("sg_pager_putpage called"); } static boolean_t sg_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before, int *after) { if (before != NULL) *before = 0; if (after != NULL) *after = 0; return (TRUE); } /* * Create a fictitious page with the specified physical address and memory * attribute. The memory attribute is the only the machine-dependent aspect * of a fictitious page that must be initialized. */ static vm_page_t sg_pager_getfake(vm_paddr_t paddr, vm_memattr_t memattr) { vm_page_t m; m = uma_zalloc(fakepg_zone, M_WAITOK | M_ZERO); m->phys_addr = paddr; /* Fictitious pages don't use "segind". */ m->flags = PG_FICTITIOUS; /* Fictitious pages don't use "order" or "pool". */ m->oflags = VPO_BUSY; m->wire_count = 1; pmap_page_set_memattr(m, memattr); return (m); } static void sg_pager_putfake(vm_page_t m) { if (!(m->flags & PG_FICTITIOUS)) panic("sg_pager_putfake: bad page"); uma_zfree(fakepg_zone, m); } Index: stable/7/sys/x86/pci/qpi.c =================================================================== --- stable/7/sys/x86/pci/qpi.c (revision 283926) +++ stable/7/sys/x86/pci/qpi.c (revision 283927) @@ -1,319 +1,319 @@ /*- - * Copyright (c) 2010 Advanced Computing Technologies LLC + * Copyright (c) 2010 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ /* * This driver provides a psuedo-bus to enumerate the PCI buses * present on a sytem using a QPI chipset. It creates a qpi0 bus that * is a child of nexus0 and then creates two Host-PCI bridges as a * child of that. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" struct qpi_device { int qd_pcibus; }; static MALLOC_DEFINE(M_QPI, "qpidrv", "qpi system device"); static void qpi_identify(driver_t *driver, device_t parent) { /* Check CPUID to ensure this is an i7 CPU of some sort. */ if (!(cpu_vendor_id == CPU_VENDOR_INTEL && CPUID_TO_FAMILY(cpu_id) == 0x6 && (CPUID_TO_MODEL(cpu_id) == 0x1a || CPUID_TO_MODEL(cpu_id) == 0x2c))) return; /* PCI config register access is required. */ if (pci_cfgregopen() == 0) return; /* Add a qpi bus device. */ if (BUS_ADD_CHILD(parent, 20, "qpi", -1) == NULL) panic("Failed to add qpi bus"); } static int qpi_probe(device_t dev) { device_set_desc(dev, "QPI system bus"); return (BUS_PROBE_SPECIFIC); } /* * Look for a PCI bus with the specified bus address. If one is found, * add a pcib device and return 0. Otherwise, return an error code. */ static int qpi_probe_pcib(device_t dev, int bus) { struct qpi_device *qdev; device_t child; uint32_t devid; /* * If a PCI bus already exists for this bus number, then * fail. */ if (pci_find_bsf(bus, 0, 0) != NULL) return (EEXIST); /* * Attempt to read the device id for device 0, function 0 on * the bus. A value of 0xffffffff means that the bus is not * present. */ devid = pci_cfgregread(bus, 0, 0, PCIR_DEVVENDOR, 4); if (devid == 0xffffffff) return (ENOENT); if ((devid & 0xffff) != 0x8086) { device_printf(dev, "Device at pci%d.0.0 has non-Intel vendor 0x%x\n", bus, devid & 0xffff); return (ENXIO); } child = BUS_ADD_CHILD(dev, 0, "pcib", -1); if (child == NULL) panic("%s: failed to add pci bus %d", device_get_nameunit(dev), bus); qdev = malloc(sizeof(struct qpi_device), M_QPI, M_WAITOK); qdev->qd_pcibus = bus; device_set_ivars(child, qdev); return (0); } static int qpi_attach(device_t dev) { int bus; /* * Each processor socket has a dedicated PCI bus counting down from * 255. We keep probing buses until one fails. */ for (bus = 255;; bus--) if (qpi_probe_pcib(dev, bus) != 0) break; return (bus_generic_attach(dev)); } static int qpi_print_child(device_t bus, device_t child) { struct qpi_device *qdev; int retval = 0; qdev = device_get_ivars(child); retval += bus_print_child_header(bus, child); if (qdev->qd_pcibus != -1) retval += printf(" pcibus %d", qdev->qd_pcibus); retval += bus_print_child_footer(bus, child); return (retval); } static int qpi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct qpi_device *qdev; qdev = device_get_ivars(child); switch (which) { case PCIB_IVAR_BUS: *result = qdev->qd_pcibus; break; default: return (ENOENT); } return (0); } static device_method_t qpi_methods[] = { /* Device interface */ DEVMETHOD(device_identify, qpi_identify), DEVMETHOD(device_probe, qpi_probe), DEVMETHOD(device_attach, qpi_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, qpi_print_child), DEVMETHOD(bus_add_child, bus_generic_add_child), DEVMETHOD(bus_read_ivar, qpi_read_ivar), DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), { 0, 0 } }; static devclass_t qpi_devclass; DEFINE_CLASS_0(qpi, qpi_driver, qpi_methods, 0); DRIVER_MODULE(qpi, nexus, qpi_driver, qpi_devclass, 0, 0); static int qpi_pcib_probe(device_t dev) { device_set_desc(dev, "QPI Host-PCI bridge"); return (BUS_PROBE_SPECIFIC); } static int qpi_pcib_attach(device_t dev) { device_add_child(dev, "pci", pcib_get_bus(dev)); return (bus_generic_attach(dev)); } static int qpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = pcib_get_bus(dev); return (0); default: return (ENOENT); } } static uint32_t qpi_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { return (pci_cfgregread(bus, slot, func, reg, bytes)); } static void qpi_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t data, int bytes) { pci_cfgregwrite(bus, slot, func, reg, data, bytes); } static int qpi_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) { device_t bus; bus = device_get_parent(pcib); return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, irqs)); } static int qpi_pcib_alloc_msix(device_t pcib, device_t dev, int *irq) { device_t bus; bus = device_get_parent(pcib); return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); } static int qpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data) { device_t bus; bus = device_get_parent(pcib); return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); } static device_method_t qpi_pcib_methods[] = { /* Device interface */ DEVMETHOD(device_probe, qpi_pcib_probe), DEVMETHOD(device_attach, qpi_pcib_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_read_ivar, qpi_pcib_read_ivar), DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, pcib_maxslots), DEVMETHOD(pcib_read_config, qpi_pcib_read_config), DEVMETHOD(pcib_write_config, qpi_pcib_write_config), DEVMETHOD(pcib_alloc_msi, qpi_pcib_alloc_msi), DEVMETHOD(pcib_release_msi, pcib_release_msi), DEVMETHOD(pcib_alloc_msix, qpi_pcib_alloc_msix), DEVMETHOD(pcib_release_msix, pcib_release_msix), DEVMETHOD(pcib_map_msi, qpi_pcib_map_msi), {0, 0} }; static devclass_t qpi_pcib_devclass; DEFINE_CLASS_0(pcib, qpi_pcib_driver, qpi_pcib_methods, 0); DRIVER_MODULE(pcib, qpi, qpi_pcib_driver, qpi_pcib_devclass, 0, 0); Index: stable/7/sys =================================================================== --- stable/7/sys (revision 283926) +++ stable/7/sys (revision 283927) Property changes on: stable/7/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys:r281887 Index: stable/8/lib/libc/gen/_once_stub.c =================================================================== --- stable/8/lib/libc/gen/_once_stub.c (revision 283926) +++ stable/8/lib/libc/gen/_once_stub.c (revision 283927) @@ -1,64 +1,64 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include "un-namespace.h" #include "libc_private.h" /* This implements pthread_once() for the single-threaded case. */ static int _libc_once(pthread_once_t *once_control, void (*init_routine)(void)) { if (once_control->state == PTHREAD_DONE_INIT) return (0); init_routine(); once_control->state = PTHREAD_DONE_INIT; return (0); } /* * This is the internal interface provided to libc. It will use * pthread_once() from the threading library in a multi-threaded * process and _libc_once() for a single-threaded library. Because * _libc_once() uses the same ABI for the values in the pthread_once_t * structure as the threading library, it is safe for a process to * switch from _libc_once() to pthread_once() when threading is * enabled. */ int _once(pthread_once_t *once_control, void (*init_routine)(void)) { if (__isthreaded) return (_pthread_once(once_control, init_routine)); return (_libc_once(once_control, init_routine)); } Index: stable/8/lib/libc/include/compat.h =================================================================== --- stable/8/lib/libc/include/compat.h (revision 283926) +++ stable/8/lib/libc/include/compat.h (revision 283927) @@ -1,48 +1,48 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ /* * This file defines compatiblity symbol versions for old system calls. It * is included in all generated system call files. */ #ifndef __LIBC_COMPAT_H__ #define __LIBC_COMPAT_H__ #define __sym_compat(sym,impl,verid) \ .symver impl , sym @ verid __sym_compat(__semctl, freebsd7___semctl, FBSD_1.0); __sym_compat(msgctl, freebsd7_msgctl, FBSD_1.0); __sym_compat(shmctl, freebsd7_shmctl, FBSD_1.0); #undef __sym_compat #endif /* __LIBC_COMPAT_H__ */ Index: stable/8/lib/libc/sys/closefrom.2 =================================================================== --- stable/8/lib/libc/sys/closefrom.2 (revision 283926) +++ stable/8/lib/libc/sys/closefrom.2 (revision 283927) @@ -1,53 +1,53 @@ -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 12, 2009 .Dt CLOSEFROM 2 .Os .Sh NAME .Nm closefrom .Nd delete open file descriptors .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In unistd.h .Ft void .Fn closefrom "int lowfd" .Sh DESCRIPTION The .Fn closefrom system call deletes all open file descriptors greater than or equal to .Fa lowfd from the per-process object reference table. Any errors encountered while closing file descriptors are ignored. .Sh SEE ALSO .Xr close 2 .Sh HISTORY The .Fn closefrom function first appeared in .Fx 8.0 . Index: stable/8/lib/libc/sys =================================================================== --- stable/8/lib/libc/sys (revision 283926) +++ stable/8/lib/libc/sys (revision 283927) Property changes on: stable/8/lib/libc/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/lib/libc/sys:r281887 Index: stable/8/lib/libc =================================================================== --- stable/8/lib/libc (revision 283926) +++ stable/8/lib/libc (revision 283927) Property changes on: stable/8/lib/libc ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/lib/libc:r281887 Index: stable/8/share/man/man9/BUS_BIND_INTR.9 =================================================================== --- stable/8/share/man/man9/BUS_BIND_INTR.9 (revision 283926) +++ stable/8/share/man/man9/BUS_BIND_INTR.9 (revision 283927) @@ -1,96 +1,96 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 14, 2009 .Dt BUS_BIND_INTR 9 .Os .Sh NAME .Nm BUS_BIND_INTR , .Nm bus_bind_intr .Nd "bind an interrupt resource to a specific CPU" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft int .Fo BUS_BIND_INTR .Fa "device_t dev" "device_t child" "struct resource *irq" "int cpu" .Fc .Ft int .Fn bus_bind_intr "device_t dev" "struct resource *irq" "int cpu" .Sh DESCRIPTION The .Fn BUS_BIND_INTR method allows an interrupt resource to be pinned to a specific CPU. The interrupt resource must have an interrupt handler attached via .Xr BUS_SETUP_INTR 9 . The .Fa cpu parameter corresponds to the ID of a valid CPU in the system. Binding an interrupt restricts the .Xr cpuset 2 of any associated interrupt threads to only include the specified CPU. It may also direct the low-level interrupt handling of the interrupt to the specified CPU as well, but this behavior is platform-dependent. If the value .Dv NOCPU is used for .Fa cpu , then the interrupt will be .Dq unbound which restores any associated interrupt threads back to the default cpuset. .Pp Non-sleepable locks such as mutexes should not be held across calls to these functions. .Pp The .Fn bus_bind_intr function is a simple wrapper around .Fn BUS_BIND_INTR . .Pp Note that currently there is no attempt made to arbitrate between multiple bind requests for the same interrupt from either the same device or multiple devices. There is also no arbitration between interrupt binding requests submitted by userland via .Xr cpuset 2 and .Fn BUS_BIND_INTR . The most recent binding request is the one that will be in effect. .Sh SEE ALSO .Xr BUS_SETUP_INTR 9 , .Xr cpuset 2 , .Xr device 9 .Sh HISTORY The .Fn BUS_BIND_INTR method and .Fn bus_bind_intr functions first appeared in .Fx 7.2 . Index: stable/8/share/man/man9/BUS_DESCRIBE_INTR.9 =================================================================== --- stable/8/share/man/man9/BUS_DESCRIBE_INTR.9 (revision 283926) +++ stable/8/share/man/man9/BUS_DESCRIBE_INTR.9 (revision 283927) @@ -1,104 +1,104 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 14, 2009 .Dt BUS_DESCRIBE_INTR 9 .Os .Sh NAME .Nm BUS_DESCRIBE_INTR , .Nm bus_describe_intr .Nd "associate a description with an active interrupt handler" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft int .Fo BUS_BIND_INTR .Fa "device_t dev" "device_t child" "struct resource *irq" "void *cookie" .Fa "const char *descr" .Fc .Ft int .Fo bus_describe_intr .Fa "device_t dev" "struct resource *irq" "void *cookie" "const char *fmt" .Fa ... .Fc .Sh DESCRIPTION The .Fn BUS_DESCRIBE_INTR method associates a description with an active interrupt handler. The .Fa cookie parameter must be the value returned by a successful call to .Xr BUS_SETUP_INTR 9 for the interrupt .Fa irq . .Pp The .Fn bus_describe_intr function is a simple wrapper around .Fn BUS_DESCRIBE_INTR . As a convenience, .Fn bus_describe_intr allows the caller to use .Xr printf 9 style formatting to build the description string using .Fa fmt . .Pp When an interrupt handler is established by .Xr BUS_SETUP_INTR 9 , the handler is named after the device the handler is established for. This name is then used in various places such as interrupt statistics displayed by .Xr systat 1 and .Xr vmstat 8 . For devices that use a single interrupt, the device name is sufficiently unique to identify the interrupt handler. However, for devices that use multiple interrupts it can be useful to distinguish the interrupt handlers. When a description is set for an active interrupt handler, a colon followed by the description is appended to the device name to form the interrupt handler name. .Sh RETURN VALUES Zero is returned on success, otherwise an appropriate error is returned. .Sh SEE ALSO .Xr BUS_SETUP_INTR 9 , .Xr systat 1 , .Xr vmstat 8 , .Xr device 9 , .Xr printf 9 .Sh HISTORY The .Fn BUS_DESCRIBE_INTR method and .Fn bus_describe_intr functions first appeared in .Fx 8.1 . .Sh BUGS It is not currently possible to remove a description from an active interrupt handler. Index: stable/8/share/man/man9/BUS_NEW_PASS.9 =================================================================== --- stable/8/share/man/man9/BUS_NEW_PASS.9 (revision 283926) +++ stable/8/share/man/man9/BUS_NEW_PASS.9 (revision 283927) @@ -1,56 +1,56 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 8, 2009 .Dt BUS_NEW_PASS 9 .Os .Sh NAME .Nm BUS_NEW_PASS .Nd "notify a bus that the pass level has been changed" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn BUS_NEW_PASS "device_t dev" .Sh DESCRIPTION The .Fn BUS_NEW_PASS method is called on each bus device to rescan the device tree when the pass level has been changed. This method is responsible for invoking .Xr BUS_NEW_PASS 9 on child bus devices to propogate the rescan to child devices. It is also responsible for reprobing any unattached child devices and allowing drivers for the current pass to identify new children. A default implementation is provided by .Xr bus_generic_new_pass 9 . .Sh SEE ALSO .Xr bus_generic_new_pass 9 , .Xr bus_set_pass 9 , .Xr device 9 Index: stable/8/share/man/man9/bus_adjust_resource.9 =================================================================== --- stable/8/share/man/man9/bus_adjust_resource.9 (revision 283926) +++ stable/8/share/man/man9/bus_adjust_resource.9 (revision 283927) @@ -1,101 +1,101 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2011 Advanced Computing Technologies LLC +.\" Copyright (c) 2011 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd April 29, 2011 .Dt BUS_ADJUST_RESOURCE 9 .Os .Sh NAME .Nm bus_adjust_resource .Nd adjust resource allocated from a parent bus .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Pp .In machine/bus.h .In sys/rman.h .In machine/resource.h .Ft int .Fn bus_adjust_resource "device_t dev" "int type" "struct resource *r" "u_long start" "u_long end" .Sh DESCRIPTION This function is used to ask the parent bus to adjust the resource range assigned to an allocated resource. The resource .Fa r should have been allocated by a previous call to .Xr bus_alloc_resource 9 . The new resource range must overlap the existing range of .Fa r . The .Fa type argument should match the .Fa type argument passed to .Xr bus_alloc_resource 9 when the resource was initially allocated. .Pp Note that none of the constraints of the original allocation request such as alignment or boundary restrictions are checked by .Fn bus_adjust_resource . It is the caller's responsibility to enforce any such requirements. .Sh RETURN VALUES The .Fn bus_adjust_resource method returns zero on success or an error code on failure. .Sh EXAMPLES Grow an existing memory resource by 4096 bytes. .Bd -literal struct resource *res; int error; error = bus_adjust_resource(dev, SYS_RES_MEMORY, res, rman_get_start(res), rman_get_end(res) + 0x1000); .Ed .Sh ERRORS .Fn bus_adjust_resource will fail if: .Bl -tag -width Er .It Bq Er EINVAL The .Fa dev device does not have a parent device. .It Bq Er EINVAL The .Fa r resource is a shared resource. .It Bq Er EINVAL The new address range does not overlap with the existing address range of .Fa r . .It Bq Er EBUSY The new address range conflicts with another allocated resource. .El .Sh SEE ALSO .Xr bus_alloc_resource 9 , .Xr bus_release_resource 9 , .Xr device 9 , .Xr driver 9 Index: stable/8/share/man/man9/bus_generic_new_pass.9 =================================================================== --- stable/8/share/man/man9/bus_generic_new_pass.9 (revision 283926) +++ stable/8/share/man/man9/bus_generic_new_pass.9 (revision 283927) @@ -1,57 +1,57 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 8, 2009 .Dt BUS_GENERIC_NEW_PASS 9 .Os .Sh NAME .Nm bus_generic_new_pass .Nd "generic implementation of BUS_NEW_PASS for bus devices" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn bus_generic_new_pass "device_t dev" .Sh DESCRIPTION This function provides an implementation of the .Xr BUS_NEW_PASS 9 method which can be used by bus drivers. It first invokes the .Xr DEVICE_IDENTIFY 9 method for any drivers whose pass level is equal to the new pass level. Then, for each attached child device it calls .Xr BUS_NEW_PASS 9 to rescan child busses, and for each unattached child device it calls .Xr device_probe_and_attach 9 . .Sh SEE ALSO .Xr BUS_NEW_PASS 9 , .Xr bus_set_pass 9 , .Xr device 9 , .Xr DEVICE_IDENTIFY 9 Index: stable/8/share/man/man9/bus_set_pass.9 =================================================================== --- stable/8/share/man/man9/bus_set_pass.9 (revision 283926) +++ stable/8/share/man/man9/bus_set_pass.9 (revision 283927) @@ -1,54 +1,54 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 8, 2009 .Dt BUS_SET_PASS 9 .Os .Sh NAME .Nm bus_set_pass .Nd "raise the bus pass level" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn bus_set_pass "int pass" .Sh DESCRIPTION The .Nm function is called during boot to raise the bus pass level to .Fa pass . The function will rescan the device tree for each pass level between the current pass level and the new level that has at least one associated driver. The device tree rescans are implemented by invoking the .Xr BUS_NEW_PASS 9 method on the root bus device. .Sh SEE ALSO .Xr BUS_NEW_PASS 9 , .Xr device 9 Index: stable/8/share/man/man9/refcount.9 =================================================================== --- stable/8/share/man/man9/refcount.9 (revision 283926) +++ stable/8/share/man/man9/refcount.9 (revision 283927) @@ -1,96 +1,96 @@ .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd January 20, 2009 .Dt REFCOUNT 9 .Os .Sh NAME .Nm refcount , .Nm refcount_init , .Nm refcount_acquire , .Nm refcount_release .Nd manage a simple reference counter .Sh SYNOPSIS .In sys/param.h .In sys/refcount.h .Ft void .Fn refcount_init "volatile u_int *count, u_int value" .Ft void .Fn refcount_acquire "volatile u_int *count" .Ft int .Fn refcount_release "volatile u_int *count" .Sh DESCRIPTION The .Nm functions provide an API to manage a simple reference counter. The caller provides the storage for the counter in an unsigned integer. A pointer to this integer is passed via .Fa count . Usually the counter is used to manage the lifetime of an object and is stored as a member of the object. .Pp The .Fn refcount_init function is used to set the initial value of the counter to .Fa value . It is normally used when creating a reference-counted object. .Pp The .Fn refcount_acquire function is used to acquire a new reference. The caller is responsible for ensuring that it holds a valid reference while obtaining a new reference. For example, if an object is stored on a list and the list holds a reference on the object, then holding a lock that protects the list provides sufficient protection for acquiring a new reference. .Pp The .Fn refcount_release function is used to release an existing reference. The function returns a non-zero value if the reference being released was the last reference; otherwise, it returns zero. .Pp Note that these routines do not provide any inter-CPU synchronization, data protection, or memory ordering guarantees except for managing the counter. The caller is responsible for any additional synchronization needed by consumers of any containing objects. In addition, the caller is also responsible for managing the life cycle of any containing objects including explicitly releasing any resources when the last reference is released. .Sh RETURN VALUES The .Nm refcount_release function returns non-zero when releasing the last reference and zero when releasing any other reference. .Sh HISTORY These functions were introduced in .Fx 6.0 . Index: stable/8/share/man/man9/sglist.9 =================================================================== --- stable/8/share/man/man9/sglist.9 (revision 283926) +++ stable/8/share/man/man9/sglist.9 (revision 283927) @@ -1,507 +1,507 @@ .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd May 15, 2009 .Dt SGLIST 9 .Os .Sh NAME .Nm sglist , .Nm sglist_alloc , .Nm sglist_append , .Nm sglist_append_mbuf , .Nm sglist_append_phys , .Nm sglist_append_uio , .Nm sglist_append_user , .Nm sglist_build , .Nm sglist_clone , .Nm sglist_consume_uio , .Nm sglist_count , .Nm sglist_free , .Nm sglist_hold , .Nm sglist_init , .Nm sglist_join , .Nm sglist_length , .Nm sglist_reset , .Nm sglist_slice , .Nm sglist_split .Nd manage a scatter/gather list of physical memory addresses .Sh SYNOPSIS .In sys/types.h .In sys/sglist.h .Ft struct sglist * .Fn sglist_alloc "int nsegs" "int mflags" .Ft int .Fn sglist_append "struct sglist *sg" "void *buf" "size_t len" .Ft int .Fn sglist_append_mbuf "struct sglist *sg" "struct mbuf *m" .Ft int .Fn sglist_append_phys "struct sglist *sg" "vm_paddr_t paddr" "size_t len" .Ft int .Fn sglist_append_uio "struct sglist *sg" "struct uio *uio" .Ft int .Fn sglist_append_user "struct sglist *sg" "void *buf" "size_t len" "struct thread *td" .Ft struct sglist * .Fn sglist_build "void *buf" "size_t len" "int mflags" .Ft struct sglist * .Fn sglist_clone "struct sglist *sg" "int mflags" .Ft int .Fn sglist_consume_uio "struct sglist *sg" "struct uio *uio" "size_t resid" .Ft int .Fn sglist_count "void *buf" "size_t len" .Ft void .Fn sglist_free "struct sglist *sg" .Ft struct sglist * .Fn sglist_hold "struct sglist *sg" .Ft void .Fn sglist_init "struct sglist *sg" "int maxsegs" "struct sglist_seg *segs" .Ft int .Fn sglist_join "struct sglist *first" "struct sglist *second" .Ft size_t .Fn sglist_length "struct sglist *sg" .Ft void .Fn sglist_reset "struct sglist *sg" .Ft int .Fn sglist_slice "struct sglist *original" "struct sglist **slice" "size_t offset" "size_t length" "int mflags" .Ft int .Fn sglist_split "struct sglist *original" "struct sglist **head" "size_t length" "int mflags" .Sh DESCRIPTION The .Nm API manages physical address ranges. Each list contains one or more elements. Each element contains a starting physical address and a length. Scatter/gather lists are read-only while they are shared. If one wishes to alter an existing scatter/gather list and does not hold the sole reference to the list, then one should create a new list instead of modifying the existing list. .Pp Each scatter/gather list object contains a reference count. New lists are created with a single reference. New references are obtained by calling .Nm sglist_hold and are released by calling .Nm sglist_free . .Ss Allocating and Initializing Lists Each .Nm object consists of a header structure and a variable-length array of scatter/gather list elements. The .Nm sglist_alloc function allocates a new list that contains a header and .Fa nsegs scatter/gather list elements. The .Fa mflags argument can be set to either .Dv M_NOWAIT or .Dv M_WAITOK . .Pp The .Nm sglist_count function returns the number of scatter/gather list elements needed to describe the physical address ranges mapped by a single kernel virtual address range. The kernel virtual address range starts at .Fa buf and is .Fa len bytes long. .Pp The .Nm sglist_build function allocates a new scatter/gather list object that describes the physical address ranges mapped by a single kernel virtual address range. The kernel virtual address range starts at .Fa buf and is .Fa len bytes long. The .Fa mflags argument can be set to either .Dv M_NOWAIT or .Dv M_WAITOK . .Pp The .Nm sglist_clone function returns a copy of an exising scatter/gather list object .Fa sg . The .Fa mflags argument can be set to either .Dv M_NOWAIT or .Dv M_WAITOK . This can be used to obtain a private copy of a scatter/gather list before modifying it. .Pp The .Nm sglist_init function initializes a scatter/gather list header. The header is pointed to by .Fa sg and is initialized to manage an array of .Fa maxsegs scatter/gather list elements pointed to by .Fa segs . This can be used to initialize a scatter/gather list header whose storage is not provided by .Nm sglist_alloc . In that case, the caller should not call .Nm sglist_free to release its own reference and is responsible for ensuring all other references to the list are dropped before it releases the storage for .Fa sg and .Fa segs . .Ss Constructing Scatter/Gather Lists The .Nm API provides several routines for building a scatter/gather list to describe one or more objects. Specifically, the .Nm sglist_append family of routines can be used to append the physical address ranges described by an object to the end of a scatter/gather list. All of these routines return 0 on success or an error on failure. If a request to append an address range to a scatter/gather list fails, the scatter/gather list will remain unchanged. .Pp The .Nm sglist_append function appends the physical address ranges described by a single kernel virtual address range to the scatter/gather list .Fa sg . The kernel virtual address range starts at .Fa buf and is .Fa len bytes long. .Pp The .Nm sglist_append_mbuf function appends the physical address ranges described by an entire mbuf chain .Fa m to the scatter/gather list .Fa sg . .Pp The .Nm sglist_append_phys function appends a single physical address range to the scatter/gather list .Fa sg . The physical address range starts at .Fa paddr and is .Fa len bytes long. .Pp The .Nm sglist_append_uio function appends the physical address ranges described by a .Xr uio 9 object to the scatter/gather list .Fa sg . Note that it is the caller's responsibility to ensure that the pages backing the I/O request are wired for the lifetime of .Fa sg . Note also that this routine does not modify .Fa uio . .Pp The .Nm sglist_append_user function appends the physical address ranges described by a single user virtual address range to the scatter/gather list .Fa sg . The user virtual address range is relative to the address space of the thread .Fa td . It starts at .Fa buf and is .Fa len bytes long. Note that it is the caller's responsibility to ensure that the pages backing the user buffer are wired for the lifetime of .Fa sg . .Pp The .Nm sglist_consume_uio function is a variation of .Nm sglist_append_uio . As with .Nm sglist_append_uio , it appends the physical address ranges described by .Fa uio to the scatter/gather list .Fa sg . Unlike .Nm sglist_append_uio , however, .Nm sglist_consume_uio modifies the I/O request to indicate that the appended address ranges have been processed similar to calling .Xr uiomove 9 . This routine will only append ranges that describe up to .Fa resid total bytes in length. If the available segments in the scatter/gather list are exhausted before .Fa resid bytes are processed, then the .Fa uio structure will be updated to reflect the actual number of bytes processed, and .Nm sglist_consume_io will return zero to indicate success. In effect, this function will perform partial reads or writes. The caller can compare the .Fa uio_resid member of .Fa uio before and after calling .Nm sglist_consume_uio to determine the actual number of bytes processed. .Ss Manipulating Scatter/Gather Lists The .Nm sglist_join function appends physical address ranges from the scatter/gather list .Fa second onto .Fa first and then resets .Fa second to an empty list. It returns zero on success or an error on failure. .Pp The .Nm sglist_split function splits an existing scatter/gather list into two lists. The first .Fa length bytes described by the list .Fa original are moved to a new list .Fa *head . If .Fa original describes a total address range that is smaller than .Fa length bytes, then all of the address ranges will be moved to the new list at .Fa *head and .Fa original will be an empty list. The caller may supply an existing scatter/gather list in .Fa *head . If so, the list must be empty. Otherwise, the caller may set .Fa *head to .Dv NULL in which case a new scatter/gather list will be allocated. In that case, .Fa mflags may be set to either .Dv M_NOWAIT or .Dv M_WAITOK . Note that since the .Fa original list is modified by this call, it must be a private list with no other references. The .Nm sglist_split function returns zero on success or an error on failure. .Pp The .Nm sglist_slice function generates a new scatter/gather list from a sub-range of an existing scatter/gather list .Fa original . The sub-range to extract is specified by the .Fa offset and .Fa length parameters. The new scatter/gather list is stored in .Fa *slice . As with .Fa head for .Nm sglist_join , the caller may either provide an empty scatter/gather list, or it may set .Fa *slice to .Dv NULL in which case .Nm sglist_slice will allocate a new list subject to .Fa mflags . Unlike .Nm sglist_split , .Nm sglist_slice does not modify .Fa original and does not require it to be a private list. The .Nm sglist_split function returns zero on success or an error on failure. .Ss Miscellaneous Routines The .Nm sglist_reset function clears the scatter/gather list .Fa sg so that it no longer maps any address ranges. This can allow reuse of a single scatter/gather list object for multiple requests. .Pp The .Nm sglist_length function returns the total length of the physical address ranges described by the scatter/gather list .Fa sg . .Sh RETURN VALUES The .Nm sglist_alloc , .Nm sglist_build , and .Nm sglist_clone functions return a new scatter/gather list on success or .Dv NULL on failure. .Pp The .Nm sglist_append family of functions and the .Nm sglist_consume_uio , .Nm sglist_join , .Nm sglist_slice , and .Nm sglist_split functions return zero on success or an error on failure. .Pp The .Nm sglist_count function returns a count of scatter/gather list elements. .Pp The .Nm sglist_length function returns a count of address space described by a scatter/gather list in bytes. .Sh ERRORS The .Nm sglist_append functions return the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The scatter/gather list has zero segments. .It Bq Er EFBIG There are not enough available segments in the scatter/gather list to append the specified physical address ranges. .El .Pp The .Nm sglist_consume_uio function returns the following error on failure: .Bl -tag -width Er .It Bq Er EINVAL The scatter/gather list has zero segments. .El .Pp The .Nm sglist_join function returns the following error on failure: .Bl -tag -width Er .It Bq Er EFBIG There are not enough available segments in the scatter/gather list .Fa first to append the physical address ranges from .Fa second . .El .Pp The .Nm sglist_slice function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The .Fa original scatter/gather list does not describe enough address space to cover the requested sub-range. .It Bq Er EINVAL The caller-supplied scatter/gather list in .Fa *slice is not empty. .It Bq Er ENOMEM An attempt to allocate a new scatter/gather list with .Dv M_NOWAIT set in .Fa mflags failed. .It Bq Er EFBIG There are not enough available segments in the caller-supplied scatter/gather list in .Fa *slice to describe the requested physical address ranges. .El .Pp The .Nm sglist_split function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EDOOFUS The .Fa original scatter/gather list has more than one reference. .It Bq Er EINVAL The caller-supplied scatter/gather list in .Fa *head is not empty. .It Bq Er ENOMEM An attempt to allocate a new scatter/gather list with .Dv M_NOWAIT set in .Fa mflags failed. .It Bq Er EFBIG There are not enough available segments in the caller-supplied scatter/gather list in .Fa *head to describe the requested physical address ranges. .El .Sh SEE ALSO .Xr malloc 9 , .Xr mbuf 9 , .Xr uio 9 .Sh HISTORY This API was first introduced in .Fx 8.0 . Index: stable/8/share/man/man9/shm_map.9 =================================================================== --- stable/8/share/man/man9/shm_map.9 (revision 283926) +++ stable/8/share/man/man9/shm_map.9 (revision 283927) @@ -1,186 +1,186 @@ .\" -.\" Copyright (c) 2011 Advanced Computing Technologies LLC +.\" Copyright (c) 2011 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd December 14, 2011 .Dt SHM_MAP 9 .Os .Sh NAME .Nm shm_map , shm_unmap .Nd "map shared memory objects into the kernel's address space" .Sh SYNOPSIS .In sys/types.h .In sys/mman.h .Ft int .Fn shm_map "struct file *fp" "size_t size" "off_t offset" "void **memp" .Ft int .Fn shm_unmap "struct file *fp" "void *mem" "size_t size" .Sh DESCRIPTION The .Fn shm_map and .Fn shm_unmap functions provide an API for mapping shared memory objects into the kernel. Shared memory objects are created by .Xr shm_open 2 . These objects can then be passed into the kernel via file descriptors. .Pp A shared memory object cannot be shrunk while it is mapped into the kernel. This is to avoid invalidating any pages that may be wired into the kernel's address space. Shared memory objects can still be grown while mapped into the kernel. .Pp To simplify the accounting needed to enforce the above requirement, callers of this API are required to unmap the entire region mapped by .Fn shm_map when calling .Fn shm_unmap . Unmapping only a portion of the region is not permitted. .Pp The .Fn shm_map function locates the shared memory object associated with the open file .Fa fp . It maps the region of that object described by .Fa offset and .Fa size into the kernel's address space. If it succeeds, .Fa *memp will be set to the start of the mapping. All pages for the range will be wired into memory upon successful return. .Pp The .Fn shm_unmap function unmaps a region previously mapped by .Fn shm_map . The .Fa mem argument should match the value previously returned in .Fa *memp , and the .Fa size argument should match the value passed to .Fn shm_map . .Pp Note that .Fn shm_map will not hold an extra reference on the open file .Fa fp for the lifetime of the mapping. Instead, the calling code is required to do this if it wishes to use .Fn shm_unmap on the region in the future. .Sh RETURN VALUES The .Fn shm_map and .Fn shm_unmap functions return zero on success or an error on failure. .Sh EXAMPLES The following function accepts a file descriptor for a shared memory object. It maps the first sixteen kilobytes of the object into the kernel, performs some work on that address, and then unmaps the address before returning. .Bd -literal -offset indent int shm_example(int fd) { struct file *fp; void *mem; int error; error = fget(curthread, fd, CAP_MMAP, &fp); if (error) return (error); error = shm_map(fp, 16384, 0, &mem); if (error) { fdrop(fp, curthread); return (error); } /* Do something with 'mem'. */ error = shm_unmap(fp, mem, 16384); fdrop(fp, curthread); return (error); } .Ed .Sh ERRORS The .Fn shm_map function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The open file .Fa fp is not a shared memory object. .It Bq Er EINVAL The requested region described by .Fa offset and .Fa size extends beyond the end of the shared memory object. .It Bq Er ENOMEM Insufficient address space was available. .It Bq Er EACCES The shared memory object could not be mapped due to a protection error. .It Bq Er EINVAL The shared memory object could not be mapped due to some other VM error. .El .Pp The .Fn shm_unmap function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The open file .Fa fp is not a shared memory object. .It Bq Er EINVAL The address range described by .Fa mem and .Fa size is not a valid address range. .It Bq Er EINVAL The address range described by .Fa mem and .Fa size is not backed by the shared memory object associated with the open file .Fa fp , or the address range does not cover the entire mapping of the object. .El .Sh SEE ALSO .Xr shm_open 2 .Sh HISTORY This API was first introduced in .Fx 10.0 . Index: stable/8/share/man/man9 =================================================================== --- stable/8/share/man/man9 (revision 283926) +++ stable/8/share/man/man9 (revision 283927) Property changes on: stable/8/share/man/man9 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/share/man/man9:r281887 Index: stable/8/sys/amd64/include/mca.h =================================================================== --- stable/8/sys/amd64/include/mca.h (revision 283926) +++ stable/8/sys/amd64/include/mca.h (revision 283927) @@ -1,56 +1,56 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef __MACHINE_MCA_H__ #define __MACHINE_MCA_H__ struct mca_record { uint64_t mr_status; uint64_t mr_addr; uint64_t mr_misc; uint64_t mr_tsc; int mr_apic_id; int mr_bank; uint64_t mr_mcg_cap; uint64_t mr_mcg_status; int mr_cpu_id; int mr_cpu_vendor_id; int mr_cpu; }; #ifdef _KERNEL void cmc_intr(void); void mca_init(void); void mca_intr(void); void mca_resume(void); #endif #endif /* !__MACHINE_MCA_H__ */ Index: stable/8/sys/amd64/include/vm.h =================================================================== --- stable/8/sys/amd64/include/vm.h (revision 283926) +++ stable/8/sys/amd64/include/vm.h (revision 283927) @@ -1,46 +1,46 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _MACHINE_VM_H_ #define _MACHINE_VM_H_ #include /* Memory attributes. */ #define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHEABLE) #define VM_MEMATTR_WRITE_COMBINING ((vm_memattr_t)PAT_WRITE_COMBINING) #define VM_MEMATTR_WRITE_THROUGH ((vm_memattr_t)PAT_WRITE_THROUGH) #define VM_MEMATTR_WRITE_PROTECTED ((vm_memattr_t)PAT_WRITE_PROTECTED) #define VM_MEMATTR_WRITE_BACK ((vm_memattr_t)PAT_WRITE_BACK) #define VM_MEMATTR_WEAK_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHED) #define VM_MEMATTR_UNCACHED VM_MEMATTR_WEAK_UNCACHEABLE #define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK #endif /* !_MACHINE_VM_H_ */ Index: stable/8/sys/amd64 =================================================================== --- stable/8/sys/amd64 (revision 283926) +++ stable/8/sys/amd64 (revision 283927) Property changes on: stable/8/sys/amd64 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/amd64:r281887 Index: stable/8/sys/boot/i386/common/edd.h =================================================================== --- stable/8/sys/boot/i386/common/edd.h (revision 283926) +++ stable/8/sys/boot/i386/common/edd.h (revision 283927) @@ -1,110 +1,110 @@ /*- - * Copyright (c) 2011 Advanced Computing Technologies LLC + * Copyright (c) 2011 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _EDD_H_ #define _EDD_H_ /* Supported interfaces for "Check Extensions Present". */ #define EDD_INTERFACE_FIXED_DISK 0x01 #define EDD_INTERFACE_EJECT 0x02 #define EDD_INTERFACE_EDD 0x04 struct edd_packet { uint16_t len; uint16_t count; uint16_t off; uint16_t seg; uint64_t lba; }; struct edd_packet_v3 { uint16_t len; uint16_t count; uint16_t off; uint16_t seg; uint64_t lba; uint64_t phys_addr; }; struct edd_params { uint16_t len; uint16_t flags; uint32_t cylinders; uint32_t heads; uint32_t sectors_per_track; uint64_t sectors; uint16_t sector_size; uint16_t edd_params_seg; uint16_t edd_params_off; } __packed; struct edd_device_path_v3 { uint16_t key; uint8_t len; uint8_t reserved[3]; char host_bus[4]; char interface[8]; uint64_t interface_path; uint64_t device_path; uint8_t reserved2[1]; uint8_t checksum; } __packed; struct edd_params_v3 { struct edd_params params; struct edd_device_path_v3 device_path; } __packed; struct edd_device_path_v4 { uint16_t key; uint8_t len; uint8_t reserved[3]; char host_bus[4]; char interface[8]; uint64_t interface_path; uint64_t device_path[2]; uint8_t reserved2[1]; uint8_t checksum; } __packed; struct edd_params_v4 { struct edd_params params; struct edd_device_path_v4 device_path; } __packed; #define EDD_FLAGS_DMA_BOUNDARY_HANDLING 0x0001 #define EDD_FLAGS_REMOVABLE_MEDIA 0x0002 #define EDD_FLAGS_WRITE_VERIFY 0x0004 #define EDD_FLAGS_MEDIA_CHANGE_NOTIFICATION 0x0008 #define EDD_FLAGS_LOCKABLE_MEDIA 0x0010 #define EDD_FLAGS_NO_MEDIA_PRESENT 0x0020 #define EDD_DEVICE_PATH_KEY 0xbedd #endif /* !_EDD_H_ */ Index: stable/8/sys/boot =================================================================== --- stable/8/sys/boot (revision 283926) +++ stable/8/sys/boot (revision 283927) Property changes on: stable/8/sys/boot ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/boot:r281887 Index: stable/8/sys/i386/include/mca.h =================================================================== --- stable/8/sys/i386/include/mca.h (revision 283926) +++ stable/8/sys/i386/include/mca.h (revision 283927) @@ -1,56 +1,56 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef __MACHINE_MCA_H__ #define __MACHINE_MCA_H__ struct mca_record { uint64_t mr_status; uint64_t mr_addr; uint64_t mr_misc; uint64_t mr_tsc; int mr_apic_id; int mr_bank; uint64_t mr_mcg_cap; uint64_t mr_mcg_status; int mr_cpu_id; int mr_cpu_vendor_id; int mr_cpu; }; #ifdef _KERNEL void cmc_intr(void); void mca_init(void); void mca_intr(void); void mca_resume(void); #endif #endif /* !__MACHINE_MCA_H__ */ Index: stable/8/sys/i386/include/vm.h =================================================================== --- stable/8/sys/i386/include/vm.h (revision 283926) +++ stable/8/sys/i386/include/vm.h (revision 283927) @@ -1,46 +1,46 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _MACHINE_VM_H_ #define _MACHINE_VM_H_ #include /* Memory attributes. */ #define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHEABLE) #define VM_MEMATTR_WRITE_COMBINING ((vm_memattr_t)PAT_WRITE_COMBINING) #define VM_MEMATTR_WRITE_THROUGH ((vm_memattr_t)PAT_WRITE_THROUGH) #define VM_MEMATTR_WRITE_PROTECTED ((vm_memattr_t)PAT_WRITE_PROTECTED) #define VM_MEMATTR_WRITE_BACK ((vm_memattr_t)PAT_WRITE_BACK) #define VM_MEMATTR_WEAK_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHED) #define VM_MEMATTR_UNCACHED VM_MEMATTR_WEAK_UNCACHEABLE #define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK #endif /* !_MACHINE_VM_H_ */ Index: stable/8/sys/i386 =================================================================== --- stable/8/sys/i386 (revision 283926) +++ stable/8/sys/i386 (revision 283927) Property changes on: stable/8/sys/i386 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/i386:r281887 Index: stable/8/sys/vm/sg_pager.c =================================================================== --- stable/8/sys/vm/sg_pager.c (revision 283926) +++ stable/8/sys/vm/sg_pager.c (revision 283927) @@ -1,260 +1,260 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); /* * This pager manages OBJT_SG objects. These objects are backed by * a scatter/gather list of physical address ranges. */ #include #include #include #include #include #include #include #include #include static void sg_pager_init(void); static vm_object_t sg_pager_alloc(void *, vm_ooffset_t, vm_prot_t, vm_ooffset_t, struct ucred *); static void sg_pager_dealloc(vm_object_t); static int sg_pager_getpages(vm_object_t, vm_page_t *, int, int); static void sg_pager_putpages(vm_object_t, vm_page_t *, int, boolean_t, int *); static boolean_t sg_pager_haspage(vm_object_t, vm_pindex_t, int *, int *); static uma_zone_t fakepg_zone; static vm_page_t sg_pager_getfake(vm_paddr_t, vm_memattr_t); static void sg_pager_putfake(vm_page_t); struct pagerops sgpagerops = { .pgo_init = sg_pager_init, .pgo_alloc = sg_pager_alloc, .pgo_dealloc = sg_pager_dealloc, .pgo_getpages = sg_pager_getpages, .pgo_putpages = sg_pager_putpages, .pgo_haspage = sg_pager_haspage, }; static void sg_pager_init(void) { fakepg_zone = uma_zcreate("SG fakepg", sizeof(struct vm_page), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE|UMA_ZONE_VM); } static vm_object_t sg_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff, struct ucred *cred) { struct sglist *sg; vm_object_t object; vm_pindex_t npages, pindex; int i; /* * Offset should be page aligned. */ if (foff & PAGE_MASK) return (NULL); /* * The scatter/gather list must only include page-aligned * ranges. */ npages = 0; sg = handle; for (i = 0; i < sg->sg_nseg; i++) { if ((sg->sg_segs[i].ss_paddr % PAGE_SIZE) != 0 || (sg->sg_segs[i].ss_len % PAGE_SIZE) != 0) return (NULL); npages += sg->sg_segs[i].ss_len / PAGE_SIZE; } /* * The scatter/gather list has a fixed size. Refuse requests * to map beyond that. */ size = round_page(size); pindex = OFF_TO_IDX(foff + size); if (pindex > npages) return (NULL); /* * Allocate a new object and associate it with the * scatter/gather list. It is ok for our purposes to have * multiple VM objects associated with the same scatter/gather * list because scatter/gather lists are static. This is also * simpler than ensuring a unique object per scatter/gather * list. */ object = vm_object_allocate(OBJT_SG, npages); object->handle = sglist_hold(sg); TAILQ_INIT(&object->un_pager.sgp.sgp_pglist); return (object); } static void sg_pager_dealloc(vm_object_t object) { struct sglist *sg; vm_page_t m; /* * Free up our fake pages. */ while ((m = TAILQ_FIRST(&object->un_pager.sgp.sgp_pglist)) != 0) { TAILQ_REMOVE(&object->un_pager.sgp.sgp_pglist, m, pageq); sg_pager_putfake(m); } sg = object->handle; sglist_free(sg); } static int sg_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) { struct sglist *sg; vm_page_t m_paddr, page; vm_pindex_t offset; vm_paddr_t paddr; vm_memattr_t memattr; size_t space; int i; VM_OBJECT_LOCK_ASSERT(object, MA_OWNED); sg = object->handle; memattr = object->memattr; VM_OBJECT_UNLOCK(object); offset = m[reqpage]->pindex; /* * Lookup the physical address of the requested page. An initial * value of '1' instead of '0' is used so we can assert that the * page is found since '0' can be a valid page-aligned physical * address. */ space = 0; paddr = 1; for (i = 0; i < sg->sg_nseg; i++) { if (space + sg->sg_segs[i].ss_len <= (offset * PAGE_SIZE)) { space += sg->sg_segs[i].ss_len; continue; } paddr = sg->sg_segs[i].ss_paddr + offset * PAGE_SIZE - space; break; } KASSERT(paddr != 1, ("invalid SG page index")); /* If "paddr" is a real page, perform a sanity check on "memattr". */ if ((m_paddr = vm_phys_paddr_to_vm_page(paddr)) != NULL && pmap_page_get_memattr(m_paddr) != memattr) { memattr = pmap_page_get_memattr(m_paddr); printf( "WARNING: A device driver has set \"memattr\" inconsistently.\n"); } /* Return a fake page for the requested page. */ KASSERT(!(m[reqpage]->flags & PG_FICTITIOUS), ("backing page for SG is fake")); /* Construct a new fake page. */ page = sg_pager_getfake(paddr, memattr); VM_OBJECT_LOCK(object); TAILQ_INSERT_TAIL(&object->un_pager.sgp.sgp_pglist, page, pageq); /* Free the original pages and insert this fake page into the object. */ vm_page_lock_queues(); for (i = 0; i < count; i++) vm_page_free(m[i]); vm_page_unlock_queues(); vm_page_insert(page, object, offset); m[reqpage] = page; page->valid = VM_PAGE_BITS_ALL; return (VM_PAGER_OK); } static void sg_pager_putpages(vm_object_t object, vm_page_t *m, int count, boolean_t sync, int *rtvals) { panic("sg_pager_putpage called"); } static boolean_t sg_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before, int *after) { if (before != NULL) *before = 0; if (after != NULL) *after = 0; return (TRUE); } /* * Create a fictitious page with the specified physical address and memory * attribute. The memory attribute is the only the machine-dependent aspect * of a fictitious page that must be initialized. */ static vm_page_t sg_pager_getfake(vm_paddr_t paddr, vm_memattr_t memattr) { vm_page_t m; m = uma_zalloc(fakepg_zone, M_WAITOK | M_ZERO); m->phys_addr = paddr; /* Fictitious pages don't use "segind". */ m->flags = PG_FICTITIOUS; /* Fictitious pages don't use "order" or "pool". */ m->oflags = VPO_BUSY; m->wire_count = 1; pmap_page_set_memattr(m, memattr); return (m); } static void sg_pager_putfake(vm_page_t m) { if (!(m->flags & PG_FICTITIOUS)) panic("sg_pager_putfake: bad page"); uma_zfree(fakepg_zone, m); } Index: stable/8/sys/vm =================================================================== --- stable/8/sys/vm (revision 283926) +++ stable/8/sys/vm (revision 283927) Property changes on: stable/8/sys/vm ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/vm:r281887 Index: stable/8/sys/x86/pci/qpi.c =================================================================== --- stable/8/sys/x86/pci/qpi.c (revision 283926) +++ stable/8/sys/x86/pci/qpi.c (revision 283927) @@ -1,319 +1,319 @@ /*- - * Copyright (c) 2010 Advanced Computing Technologies LLC + * Copyright (c) 2010 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ /* * This driver provides a psuedo-bus to enumerate the PCI buses * present on a sytem using a QPI chipset. It creates a qpi0 bus that * is a child of nexus0 and then creates two Host-PCI bridges as a * child of that. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" struct qpi_device { int qd_pcibus; }; static MALLOC_DEFINE(M_QPI, "qpidrv", "qpi system device"); static void qpi_identify(driver_t *driver, device_t parent) { /* Check CPUID to ensure this is an i7 CPU of some sort. */ if (!(cpu_vendor_id == CPU_VENDOR_INTEL && CPUID_TO_FAMILY(cpu_id) == 0x6 && (CPUID_TO_MODEL(cpu_id) == 0x1a || CPUID_TO_MODEL(cpu_id) == 0x2c))) return; /* PCI config register access is required. */ if (pci_cfgregopen() == 0) return; /* Add a qpi bus device. */ if (BUS_ADD_CHILD(parent, 20, "qpi", -1) == NULL) panic("Failed to add qpi bus"); } static int qpi_probe(device_t dev) { device_set_desc(dev, "QPI system bus"); return (BUS_PROBE_SPECIFIC); } /* * Look for a PCI bus with the specified bus address. If one is found, * add a pcib device and return 0. Otherwise, return an error code. */ static int qpi_probe_pcib(device_t dev, int bus) { struct qpi_device *qdev; device_t child; uint32_t devid; /* * If a PCI bus already exists for this bus number, then * fail. */ if (pci_find_bsf(bus, 0, 0) != NULL) return (EEXIST); /* * Attempt to read the device id for device 0, function 0 on * the bus. A value of 0xffffffff means that the bus is not * present. */ devid = pci_cfgregread(bus, 0, 0, PCIR_DEVVENDOR, 4); if (devid == 0xffffffff) return (ENOENT); if ((devid & 0xffff) != 0x8086) { device_printf(dev, "Device at pci%d.0.0 has non-Intel vendor 0x%x\n", bus, devid & 0xffff); return (ENXIO); } child = BUS_ADD_CHILD(dev, 0, "pcib", -1); if (child == NULL) panic("%s: failed to add pci bus %d", device_get_nameunit(dev), bus); qdev = malloc(sizeof(struct qpi_device), M_QPI, M_WAITOK); qdev->qd_pcibus = bus; device_set_ivars(child, qdev); return (0); } static int qpi_attach(device_t dev) { int bus; /* * Each processor socket has a dedicated PCI bus counting down from * 255. We keep probing buses until one fails. */ for (bus = 255;; bus--) if (qpi_probe_pcib(dev, bus) != 0) break; return (bus_generic_attach(dev)); } static int qpi_print_child(device_t bus, device_t child) { struct qpi_device *qdev; int retval = 0; qdev = device_get_ivars(child); retval += bus_print_child_header(bus, child); if (qdev->qd_pcibus != -1) retval += printf(" pcibus %d", qdev->qd_pcibus); retval += bus_print_child_footer(bus, child); return (retval); } static int qpi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct qpi_device *qdev; qdev = device_get_ivars(child); switch (which) { case PCIB_IVAR_BUS: *result = qdev->qd_pcibus; break; default: return (ENOENT); } return (0); } static device_method_t qpi_methods[] = { /* Device interface */ DEVMETHOD(device_identify, qpi_identify), DEVMETHOD(device_probe, qpi_probe), DEVMETHOD(device_attach, qpi_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, qpi_print_child), DEVMETHOD(bus_add_child, bus_generic_add_child), DEVMETHOD(bus_read_ivar, qpi_read_ivar), DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), { 0, 0 } }; static devclass_t qpi_devclass; DEFINE_CLASS_0(qpi, qpi_driver, qpi_methods, 0); DRIVER_MODULE(qpi, nexus, qpi_driver, qpi_devclass, 0, 0); static int qpi_pcib_probe(device_t dev) { device_set_desc(dev, "QPI Host-PCI bridge"); return (BUS_PROBE_SPECIFIC); } static int qpi_pcib_attach(device_t dev) { device_add_child(dev, "pci", pcib_get_bus(dev)); return (bus_generic_attach(dev)); } static int qpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = pcib_get_bus(dev); return (0); default: return (ENOENT); } } static uint32_t qpi_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { return (pci_cfgregread(bus, slot, func, reg, bytes)); } static void qpi_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t data, int bytes) { pci_cfgregwrite(bus, slot, func, reg, data, bytes); } static int qpi_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) { device_t bus; bus = device_get_parent(pcib); return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, irqs)); } static int qpi_pcib_alloc_msix(device_t pcib, device_t dev, int *irq) { device_t bus; bus = device_get_parent(pcib); return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); } static int qpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data) { device_t bus; bus = device_get_parent(pcib); return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); } static device_method_t qpi_pcib_methods[] = { /* Device interface */ DEVMETHOD(device_probe, qpi_pcib_probe), DEVMETHOD(device_attach, qpi_pcib_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, qpi_pcib_read_ivar), DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, pcib_maxslots), DEVMETHOD(pcib_read_config, qpi_pcib_read_config), DEVMETHOD(pcib_write_config, qpi_pcib_write_config), DEVMETHOD(pcib_alloc_msi, qpi_pcib_alloc_msi), DEVMETHOD(pcib_release_msi, pcib_release_msi), DEVMETHOD(pcib_alloc_msix, qpi_pcib_alloc_msix), DEVMETHOD(pcib_release_msix, pcib_release_msix), DEVMETHOD(pcib_map_msi, qpi_pcib_map_msi), DEVMETHOD_END }; static devclass_t qpi_pcib_devclass; DEFINE_CLASS_0(pcib, qpi_pcib_driver, qpi_pcib_methods, 0); DRIVER_MODULE(pcib, qpi, qpi_pcib_driver, qpi_pcib_devclass, 0, 0); Index: stable/8/sys/x86/x86/mca.c =================================================================== --- stable/8/sys/x86/x86/mca.c (revision 283926) +++ stable/8/sys/x86/x86/mca.c (revision 283927) @@ -1,1033 +1,1033 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ /* * Support for x86 machine check architecture. */ #include __FBSDID("$FreeBSD$"); #ifdef __amd64__ #define DEV_APIC #else #include "opt_apic.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Modes for mca_scan() */ enum scan_mode { POLLED, MCE, CMCI, }; #ifdef DEV_APIC /* * State maintained for each monitored MCx bank to control the * corrected machine check interrupt threshold. */ struct cmc_state { int max_threshold; int last_intr; }; #endif struct mca_internal { struct mca_record rec; int logged; STAILQ_ENTRY(mca_internal) link; }; static MALLOC_DEFINE(M_MCA, "MCA", "Machine Check Architecture"); static volatile int mca_count; /* Number of records stored. */ static int mca_banks; /* Number of per-CPU register banks. */ SYSCTL_NODE(_hw, OID_AUTO, mca, CTLFLAG_RD, NULL, "Machine Check Architecture"); static int mca_enabled = 1; TUNABLE_INT("hw.mca.enabled", &mca_enabled); SYSCTL_INT(_hw_mca, OID_AUTO, enabled, CTLFLAG_RDTUN, &mca_enabled, 0, "Administrative toggle for machine check support"); static int amd10h_L1TP = 1; TUNABLE_INT("hw.mca.amd10h_L1TP", &amd10h_L1TP); SYSCTL_INT(_hw_mca, OID_AUTO, amd10h_L1TP, CTLFLAG_RDTUN, &amd10h_L1TP, 0, "Administrative toggle for logging of level one TLB parity (L1TP) errors"); static int intel6h_HSD131; TUNABLE_INT("hw.mca.intel6h_hsd131", &intel6h_HSD131); SYSCTL_INT(_hw_mca, OID_AUTO, intel6h_HSD131, CTLFLAG_RDTUN, &intel6h_HSD131, 0, "Administrative toggle for logging of spurious corrected errors"); int workaround_erratum383; SYSCTL_INT(_hw_mca, OID_AUTO, erratum383, CTLFLAG_RD, &workaround_erratum383, 0, "Is the workaround for Erratum 383 on AMD Family 10h processors enabled?"); static STAILQ_HEAD(, mca_internal) mca_freelist; static int mca_freecount; static STAILQ_HEAD(, mca_internal) mca_records; static struct callout mca_timer; static int mca_ticks = 3600; /* Check hourly by default. */ static struct taskqueue *mca_tq; static struct task mca_refill_task, mca_scan_task; static struct mtx mca_lock; #ifdef DEV_APIC static struct cmc_state **cmc_state; /* Indexed by cpuid, bank */ static int cmc_throttle = 60; /* Time in seconds to throttle CMCI. */ #endif static int sysctl_positive_int(SYSCTL_HANDLER_ARGS) { int error, value; value = *(int *)arg1; error = sysctl_handle_int(oidp, &value, 0, req); if (error || req->newptr == NULL) return (error); if (value <= 0) return (EINVAL); *(int *)arg1 = value; return (0); } static int sysctl_mca_records(SYSCTL_HANDLER_ARGS) { int *name = (int *)arg1; u_int namelen = arg2; struct mca_record record; struct mca_internal *rec; int i; if (namelen != 1) return (EINVAL); if (name[0] < 0 || name[0] >= mca_count) return (EINVAL); mtx_lock_spin(&mca_lock); if (name[0] >= mca_count) { mtx_unlock_spin(&mca_lock); return (EINVAL); } i = 0; STAILQ_FOREACH(rec, &mca_records, link) { if (i == name[0]) { record = rec->rec; break; } i++; } mtx_unlock_spin(&mca_lock); return (SYSCTL_OUT(req, &record, sizeof(record))); } static const char * mca_error_ttype(uint16_t mca_error) { switch ((mca_error & 0x000c) >> 2) { case 0: return ("I"); case 1: return ("D"); case 2: return ("G"); } return ("?"); } static const char * mca_error_level(uint16_t mca_error) { switch (mca_error & 0x0003) { case 0: return ("L0"); case 1: return ("L1"); case 2: return ("L2"); case 3: return ("LG"); } return ("L?"); } static const char * mca_error_request(uint16_t mca_error) { switch ((mca_error & 0x00f0) >> 4) { case 0x0: return ("ERR"); case 0x1: return ("RD"); case 0x2: return ("WR"); case 0x3: return ("DRD"); case 0x4: return ("DWR"); case 0x5: return ("IRD"); case 0x6: return ("PREFETCH"); case 0x7: return ("EVICT"); case 0x8: return ("SNOOP"); } return ("???"); } static const char * mca_error_mmtype(uint16_t mca_error) { switch ((mca_error & 0x70) >> 4) { case 0x0: return ("GEN"); case 0x1: return ("RD"); case 0x2: return ("WR"); case 0x3: return ("AC"); case 0x4: return ("MS"); } return ("???"); } static int __nonnull(1) mca_mute(const struct mca_record *rec) { /* * Skip spurious corrected parity errors generated by desktop Haswell * (see HSD131 erratum) unless reporting is enabled. * Note that these errors also have been observed with D0-stepping, * while the revision 014 desktop Haswell specification update only * talks about C0-stepping. */ if (rec->mr_cpu_vendor_id == CPU_VENDOR_INTEL && rec->mr_cpu_id == 0x306c3 && rec->mr_bank == 0 && rec->mr_status == 0x90000040000f0005 && !intel6h_HSD131) return (1); return (0); } /* Dump details about a single machine check. */ static void __nonnull(1) mca_log(const struct mca_record *rec) { uint16_t mca_error; if (mca_mute(rec)) return; printf("MCA: Bank %d, Status 0x%016llx\n", rec->mr_bank, (long long)rec->mr_status); printf("MCA: Global Cap 0x%016llx, Status 0x%016llx\n", (long long)rec->mr_mcg_cap, (long long)rec->mr_mcg_status); printf("MCA: Vendor \"%s\", ID 0x%x, APIC ID %d\n", cpu_vendor, rec->mr_cpu_id, rec->mr_apic_id); printf("MCA: CPU %d ", rec->mr_cpu); if (rec->mr_status & MC_STATUS_UC) printf("UNCOR "); else { printf("COR "); if (rec->mr_mcg_cap & MCG_CAP_CMCI_P) printf("(%lld) ", ((long long)rec->mr_status & MC_STATUS_COR_COUNT) >> 38); } if (rec->mr_status & MC_STATUS_PCC) printf("PCC "); if (rec->mr_status & MC_STATUS_OVER) printf("OVER "); mca_error = rec->mr_status & MC_STATUS_MCA_ERROR; switch (mca_error) { /* Simple error codes. */ case 0x0000: printf("no error"); break; case 0x0001: printf("unclassified error"); break; case 0x0002: printf("ucode ROM parity error"); break; case 0x0003: printf("external error"); break; case 0x0004: printf("FRC error"); break; case 0x0005: printf("internal parity error"); break; case 0x0400: printf("internal timer error"); break; default: if ((mca_error & 0xfc00) == 0x0400) { printf("internal error %x", mca_error & 0x03ff); break; } /* Compound error codes. */ /* Memory hierarchy error. */ if ((mca_error & 0xeffc) == 0x000c) { printf("%s memory error", mca_error_level(mca_error)); break; } /* TLB error. */ if ((mca_error & 0xeff0) == 0x0010) { printf("%sTLB %s error", mca_error_ttype(mca_error), mca_error_level(mca_error)); break; } /* Memory controller error. */ if ((mca_error & 0xef80) == 0x0080) { printf("%s channel ", mca_error_mmtype(mca_error)); if ((mca_error & 0x000f) != 0x000f) printf("%d", mca_error & 0x000f); else printf("??"); printf(" memory error"); break; } /* Cache error. */ if ((mca_error & 0xef00) == 0x0100) { printf("%sCACHE %s %s error", mca_error_ttype(mca_error), mca_error_level(mca_error), mca_error_request(mca_error)); break; } /* Bus and/or Interconnect error. */ if ((mca_error & 0xe800) == 0x0800) { printf("BUS%s ", mca_error_level(mca_error)); switch ((mca_error & 0x0600) >> 9) { case 0: printf("Source"); break; case 1: printf("Responder"); break; case 2: printf("Observer"); break; default: printf("???"); break; } printf(" %s ", mca_error_request(mca_error)); switch ((mca_error & 0x000c) >> 2) { case 0: printf("Memory"); break; case 2: printf("I/O"); break; case 3: printf("Other"); break; default: printf("???"); break; } if (mca_error & 0x0100) printf(" timed out"); break; } printf("unknown error %x", mca_error); break; } printf("\n"); if (rec->mr_status & MC_STATUS_ADDRV) printf("MCA: Address 0x%llx\n", (long long)rec->mr_addr); if (rec->mr_status & MC_STATUS_MISCV) printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc); } static int __nonnull(2) mca_check_status(int bank, struct mca_record *rec) { uint64_t status; u_int p[4]; status = rdmsr(MSR_MC_STATUS(bank)); if (!(status & MC_STATUS_VAL)) return (0); /* Save exception information. */ rec->mr_status = status; rec->mr_bank = bank; rec->mr_addr = 0; if (status & MC_STATUS_ADDRV) rec->mr_addr = rdmsr(MSR_MC_ADDR(bank)); rec->mr_misc = 0; if (status & MC_STATUS_MISCV) rec->mr_misc = rdmsr(MSR_MC_MISC(bank)); rec->mr_tsc = rdtsc(); rec->mr_apic_id = PCPU_GET(apic_id); rec->mr_mcg_cap = rdmsr(MSR_MCG_CAP); rec->mr_mcg_status = rdmsr(MSR_MCG_STATUS); rec->mr_cpu_id = cpu_id; rec->mr_cpu_vendor_id = cpu_vendor_id; rec->mr_cpu = PCPU_GET(cpuid); /* * Clear machine check. Don't do this for uncorrectable * errors so that the BIOS can see them. */ if (!(rec->mr_status & (MC_STATUS_PCC | MC_STATUS_UC))) { wrmsr(MSR_MC_STATUS(bank), 0); do_cpuid(0, p); } return (1); } static void mca_fill_freelist(void) { struct mca_internal *rec; int desired; /* * Ensure we have at least one record for each bank and one * record per CPU. */ desired = imax(mp_ncpus, mca_banks); mtx_lock_spin(&mca_lock); while (mca_freecount < desired) { mtx_unlock_spin(&mca_lock); rec = malloc(sizeof(*rec), M_MCA, M_WAITOK); mtx_lock_spin(&mca_lock); STAILQ_INSERT_TAIL(&mca_freelist, rec, link); mca_freecount++; } mtx_unlock_spin(&mca_lock); } static void mca_refill(void *context, int pending) { mca_fill_freelist(); } static void __nonnull(2) mca_record_entry(enum scan_mode mode, const struct mca_record *record) { struct mca_internal *rec; if (mode == POLLED) { rec = malloc(sizeof(*rec), M_MCA, M_WAITOK); mtx_lock_spin(&mca_lock); } else { mtx_lock_spin(&mca_lock); rec = STAILQ_FIRST(&mca_freelist); if (rec == NULL) { printf("MCA: Unable to allocate space for an event.\n"); mca_log(record); mtx_unlock_spin(&mca_lock); return; } STAILQ_REMOVE_HEAD(&mca_freelist, link); mca_freecount--; } rec->rec = *record; rec->logged = 0; STAILQ_INSERT_TAIL(&mca_records, rec, link); mca_count++; mtx_unlock_spin(&mca_lock); if (mode == CMCI) taskqueue_enqueue_fast(mca_tq, &mca_refill_task); } #ifdef DEV_APIC /* * Update the interrupt threshold for a CMCI. The strategy is to use * a low trigger that interrupts as soon as the first event occurs. * However, if a steady stream of events arrive, the threshold is * increased until the interrupts are throttled to once every * cmc_throttle seconds or the periodic scan. If a periodic scan * finds that the threshold is too high, it is lowered. */ static void cmci_update(enum scan_mode mode, int bank, int valid, struct mca_record *rec) { struct cmc_state *cc; uint64_t ctl; u_int delta; int count, limit; /* Fetch the current limit for this bank. */ cc = &cmc_state[PCPU_GET(cpuid)][bank]; ctl = rdmsr(MSR_MC_CTL2(bank)); count = (rec->mr_status & MC_STATUS_COR_COUNT) >> 38; delta = (u_int)(ticks - cc->last_intr); /* * If an interrupt was received less than cmc_throttle seconds * since the previous interrupt and the count from the current * event is greater than or equal to the current threshold, * double the threshold up to the max. */ if (mode == CMCI && valid) { limit = ctl & MC_CTL2_THRESHOLD; if (delta < cmc_throttle && count >= limit && limit < cc->max_threshold) { limit = min(limit << 1, cc->max_threshold); ctl &= ~MC_CTL2_THRESHOLD; ctl |= limit; wrmsr(MSR_MC_CTL2(bank), limit); } cc->last_intr = ticks; return; } /* * When the banks are polled, check to see if the threshold * should be lowered. */ if (mode != POLLED) return; /* If a CMCI occured recently, do nothing for now. */ if (delta < cmc_throttle) return; /* * Compute a new limit based on the average rate of events per * cmc_throttle seconds since the last interrupt. */ if (valid) { count = (rec->mr_status & MC_STATUS_COR_COUNT) >> 38; limit = count * cmc_throttle / delta; if (limit <= 0) limit = 1; else if (limit > cc->max_threshold) limit = cc->max_threshold; } else limit = 1; if ((ctl & MC_CTL2_THRESHOLD) != limit) { ctl &= ~MC_CTL2_THRESHOLD; ctl |= limit; wrmsr(MSR_MC_CTL2(bank), limit); } } #endif /* * This scans all the machine check banks of the current CPU to see if * there are any machine checks. Any non-recoverable errors are * reported immediately via mca_log(). The current thread must be * pinned when this is called. The 'mode' parameter indicates if we * are being called from the MC exception handler, the CMCI handler, * or the periodic poller. In the MC exception case this function * returns true if the system is restartable. Otherwise, it returns a * count of the number of valid MC records found. */ static int mca_scan(enum scan_mode mode) { struct mca_record rec; uint64_t mcg_cap, ucmask; int count, i, recoverable, valid; count = 0; recoverable = 1; ucmask = MC_STATUS_UC | MC_STATUS_PCC; /* When handling a MCE#, treat the OVER flag as non-restartable. */ if (mode == MCE) ucmask |= MC_STATUS_OVER; mcg_cap = rdmsr(MSR_MCG_CAP); for (i = 0; i < (mcg_cap & MCG_CAP_COUNT); i++) { #ifdef DEV_APIC /* * For a CMCI, only check banks this CPU is * responsible for. */ if (mode == CMCI && !(PCPU_GET(cmci_mask) & 1 << i)) continue; #endif valid = mca_check_status(i, &rec); if (valid) { count++; if (rec.mr_status & ucmask) { recoverable = 0; mtx_lock_spin(&mca_lock); mca_log(&rec); mtx_unlock_spin(&mca_lock); } mca_record_entry(mode, &rec); } #ifdef DEV_APIC /* * If this is a bank this CPU monitors via CMCI, * update the threshold. */ if (PCPU_GET(cmci_mask) & 1 << i) cmci_update(mode, i, valid, &rec); #endif } if (mode == POLLED) mca_fill_freelist(); return (mode == MCE ? recoverable : count); } /* * Scan the machine check banks on all CPUs by binding to each CPU in * turn. If any of the CPUs contained new machine check records, log * them to the console. */ static void mca_scan_cpus(void *context, int pending) { struct mca_internal *mca; struct thread *td; int count, cpu; mca_fill_freelist(); td = curthread; count = 0; thread_lock(td); CPU_FOREACH(cpu) { sched_bind(td, cpu); thread_unlock(td); count += mca_scan(POLLED); thread_lock(td); sched_unbind(td); } thread_unlock(td); if (count != 0) { mtx_lock_spin(&mca_lock); STAILQ_FOREACH(mca, &mca_records, link) { if (!mca->logged) { mca->logged = 1; mca_log(&mca->rec); } } mtx_unlock_spin(&mca_lock); } } static void mca_periodic_scan(void *arg) { taskqueue_enqueue_fast(mca_tq, &mca_scan_task); callout_reset(&mca_timer, mca_ticks * hz, mca_periodic_scan, NULL); } static int sysctl_mca_scan(SYSCTL_HANDLER_ARGS) { int error, i; i = 0; error = sysctl_handle_int(oidp, &i, 0, req); if (error) return (error); if (i) taskqueue_enqueue_fast(mca_tq, &mca_scan_task); return (0); } static void mca_createtq(void *dummy) { if (mca_banks <= 0) return; mca_tq = taskqueue_create_fast("mca", M_WAITOK, taskqueue_thread_enqueue, &mca_tq); taskqueue_start_threads(&mca_tq, 1, PI_SWI(SWI_TQ), "mca taskq"); } SYSINIT(mca_createtq, SI_SUB_CONFIGURE, SI_ORDER_ANY, mca_createtq, NULL); static void mca_startup(void *dummy) { if (mca_banks <= 0) return; callout_reset(&mca_timer, mca_ticks * hz, mca_periodic_scan, NULL); } SYSINIT(mca_startup, SI_SUB_SMP, SI_ORDER_ANY, mca_startup, NULL); #ifdef DEV_APIC static void cmci_setup(void) { int i; cmc_state = malloc((mp_maxid + 1) * sizeof(struct cmc_state *), M_MCA, M_WAITOK); for (i = 0; i <= mp_maxid; i++) cmc_state[i] = malloc(sizeof(struct cmc_state) * mca_banks, M_MCA, M_WAITOK | M_ZERO); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "cmc_throttle", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &cmc_throttle, 0, sysctl_positive_int, "I", "Interval in seconds to throttle corrected MC interrupts"); } #endif static void mca_setup(uint64_t mcg_cap) { /* * On AMD Family 10h processors, unless logging of level one TLB * parity (L1TP) errors is disabled, enable the recommended workaround * for Erratum 383. */ if (cpu_vendor_id == CPU_VENDOR_AMD && CPUID_TO_FAMILY(cpu_id) == 0x10 && amd10h_L1TP) workaround_erratum383 = 1; mca_banks = mcg_cap & MCG_CAP_COUNT; mtx_init(&mca_lock, "mca", NULL, MTX_SPIN); STAILQ_INIT(&mca_records); TASK_INIT(&mca_scan_task, 0, mca_scan_cpus, NULL); callout_init(&mca_timer, CALLOUT_MPSAFE); STAILQ_INIT(&mca_freelist); TASK_INIT(&mca_refill_task, 0, mca_refill, NULL); mca_fill_freelist(); SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "count", CTLFLAG_RD, (int *)(uintptr_t)&mca_count, 0, "Record count"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "interval", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &mca_ticks, 0, sysctl_positive_int, "I", "Periodic interval in seconds to scan for machine checks"); SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "records", CTLFLAG_RD, sysctl_mca_records, "Machine check records"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "force_scan", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0, sysctl_mca_scan, "I", "Force an immediate scan for machine checks"); #ifdef DEV_APIC if (mcg_cap & MCG_CAP_CMCI_P) cmci_setup(); #endif } #ifdef DEV_APIC /* * See if we should monitor CMCI for this bank. If CMCI_EN is already * set in MC_CTL2, then another CPU is responsible for this bank, so * ignore it. If CMCI_EN returns zero after being set, then this bank * does not support CMCI_EN. If this CPU sets CMCI_EN, then it should * now monitor this bank. */ static void cmci_monitor(int i) { struct cmc_state *cc; uint64_t ctl; KASSERT(i < mca_banks, ("CPU %d has more MC banks", PCPU_GET(cpuid))); ctl = rdmsr(MSR_MC_CTL2(i)); if (ctl & MC_CTL2_CMCI_EN) /* Already monitored by another CPU. */ return; /* Set the threshold to one event for now. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= MC_CTL2_CMCI_EN | 1; wrmsr(MSR_MC_CTL2(i), ctl); ctl = rdmsr(MSR_MC_CTL2(i)); if (!(ctl & MC_CTL2_CMCI_EN)) /* This bank does not support CMCI. */ return; cc = &cmc_state[PCPU_GET(cpuid)][i]; /* Determine maximum threshold. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= 0x7fff; wrmsr(MSR_MC_CTL2(i), ctl); ctl = rdmsr(MSR_MC_CTL2(i)); cc->max_threshold = ctl & MC_CTL2_THRESHOLD; /* Start off with a threshold of 1. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= 1; wrmsr(MSR_MC_CTL2(i), ctl); /* Mark this bank as monitored. */ PCPU_SET(cmci_mask, PCPU_GET(cmci_mask) | 1 << i); } /* * For resume, reset the threshold for any banks we monitor back to * one and throw away the timestamp of the last interrupt. */ static void cmci_resume(int i) { struct cmc_state *cc; uint64_t ctl; KASSERT(i < mca_banks, ("CPU %d has more MC banks", PCPU_GET(cpuid))); /* Ignore banks not monitored by this CPU. */ if (!(PCPU_GET(cmci_mask) & 1 << i)) return; cc = &cmc_state[PCPU_GET(cpuid)][i]; cc->last_intr = -ticks; ctl = rdmsr(MSR_MC_CTL2(i)); ctl &= ~MC_CTL2_THRESHOLD; ctl |= MC_CTL2_CMCI_EN | 1; wrmsr(MSR_MC_CTL2(i), ctl); } #endif /* * Initializes per-CPU machine check registers and enables corrected * machine check interrupts. */ static void _mca_init(int boot) { uint64_t mcg_cap; uint64_t ctl, mask; int i, skip; /* MCE is required. */ if (!mca_enabled || !(cpu_feature & CPUID_MCE)) return; if (cpu_feature & CPUID_MCA) { if (boot) PCPU_SET(cmci_mask, 0); mcg_cap = rdmsr(MSR_MCG_CAP); if (mcg_cap & MCG_CAP_CTL_P) /* Enable MCA features. */ wrmsr(MSR_MCG_CTL, MCG_CTL_ENABLE); if (PCPU_GET(cpuid) == 0 && boot) mca_setup(mcg_cap); /* * Disable logging of level one TLB parity (L1TP) errors by * the data cache as an alternative workaround for AMD Family * 10h Erratum 383. Unlike the recommended workaround, there * is no performance penalty to this workaround. However, * L1TP errors will go unreported. */ if (cpu_vendor_id == CPU_VENDOR_AMD && CPUID_TO_FAMILY(cpu_id) == 0x10 && !amd10h_L1TP) { mask = rdmsr(MSR_MC0_CTL_MASK); if ((mask & (1UL << 5)) == 0) wrmsr(MSR_MC0_CTL_MASK, mask | (1UL << 5)); } for (i = 0; i < (mcg_cap & MCG_CAP_COUNT); i++) { /* By default enable logging of all errors. */ ctl = 0xffffffffffffffffUL; skip = 0; if (cpu_vendor_id == CPU_VENDOR_INTEL) { /* * For P6 models before Nehalem MC0_CTL is * always enabled and reserved. */ if (i == 0 && CPUID_TO_FAMILY(cpu_id) == 0x6 && CPUID_TO_MODEL(cpu_id) < 0x1a) skip = 1; } else if (cpu_vendor_id == CPU_VENDOR_AMD) { /* BKDG for Family 10h: unset GartTblWkEn. */ if (i == 4 && CPUID_TO_FAMILY(cpu_id) >= 0xf) ctl &= ~(1UL << 10); } if (!skip) wrmsr(MSR_MC_CTL(i), ctl); #ifdef DEV_APIC if (mcg_cap & MCG_CAP_CMCI_P) { if (boot) cmci_monitor(i); else cmci_resume(i); } #endif /* Clear all errors. */ wrmsr(MSR_MC_STATUS(i), 0); } #ifdef DEV_APIC if (PCPU_GET(cmci_mask) != 0 && boot) lapic_enable_cmc(); #endif } load_cr4(rcr4() | CR4_MCE); } /* Must be executed on each CPU during boot. */ void mca_init(void) { _mca_init(1); } /* Must be executed on each CPU during resume. */ void mca_resume(void) { _mca_init(0); } /* * The machine check registers for the BSP cannot be initialized until * the local APIC is initialized. This happens at SI_SUB_CPU, * SI_ORDER_SECOND. */ static void mca_init_bsp(void *arg __unused) { mca_init(); } SYSINIT(mca_init_bsp, SI_SUB_CPU, SI_ORDER_ANY, mca_init_bsp, NULL); /* Called when a machine check exception fires. */ void mca_intr(void) { uint64_t mcg_status; int old_count, recoverable; if (!(cpu_feature & CPUID_MCA)) { /* * Just print the values of the old Pentium registers * and panic. */ printf("MC Type: 0x%jx Address: 0x%jx\n", (uintmax_t)rdmsr(MSR_P5_MC_TYPE), (uintmax_t)rdmsr(MSR_P5_MC_ADDR)); panic("Machine check"); } /* Scan the banks and check for any non-recoverable errors. */ old_count = mca_count; recoverable = mca_scan(MCE); mcg_status = rdmsr(MSR_MCG_STATUS); if (!(mcg_status & MCG_STATUS_RIPV)) recoverable = 0; if (!recoverable) { /* * Wait for at least one error to be logged before * panic'ing. Some errors will assert a machine check * on all CPUs, but only certain CPUs will find a valid * bank to log. */ while (mca_count == old_count) cpu_spinwait(); panic("Unrecoverable machine check exception"); } /* Clear MCIP. */ wrmsr(MSR_MCG_STATUS, mcg_status & ~MCG_STATUS_MCIP); } #ifdef DEV_APIC /* Called for a CMCI (correctable machine check interrupt). */ void cmc_intr(void) { struct mca_internal *mca; int count; /* * Serialize MCA bank scanning to prevent collisions from * sibling threads. */ count = mca_scan(CMCI); /* If we found anything, log them to the console. */ if (count != 0) { mtx_lock_spin(&mca_lock); STAILQ_FOREACH(mca, &mca_records, link) { if (!mca->logged) { mca->logged = 1; mca_log(&mca->rec); } } mtx_unlock_spin(&mca_lock); } } #endif Index: stable/8/sys/x86 =================================================================== --- stable/8/sys/x86 (revision 283926) +++ stable/8/sys/x86 (revision 283927) Property changes on: stable/8/sys/x86 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/x86:r281887 Index: stable/8/sys =================================================================== --- stable/8/sys (revision 283926) +++ stable/8/sys (revision 283927) Property changes on: stable/8/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys:r281887 Index: stable/8/tools/regression/file/closefrom/closefrom.c =================================================================== --- stable/8/tools/regression/file/closefrom/closefrom.c (revision 283926) +++ stable/8/tools/regression/file/closefrom/closefrom.c (revision 283927) @@ -1,274 +1,274 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); /* * Regression tests for the closefrom(2) system call. */ #include #include #include #include #include #include #include #include #include #include #include #include struct shared_info { int failed; char tag[64]; char message[0]; }; static int test = 1; static void ok(const char *descr) { printf("ok %d - %s\n", test, descr); test++; } static void fail(const char *descr, const char *fmt, ...) { va_list ap; printf("not ok %d - %s", test, descr); test++; if (fmt) { va_start(ap, fmt); printf(" # "); vprintf(fmt, ap); va_end(ap); } printf("\n"); exit(1); } #define fail_err(descr) fail((descr), "%s", strerror(errno)) static void cok(struct shared_info *info, const char *descr) { info->failed = 0; strlcpy(info->tag, descr, sizeof(info->tag)); exit(0); } static void cfail(struct shared_info *info, const char *descr, const char *fmt, ...) { va_list ap; info->failed = 1; strlcpy(info->tag, descr, sizeof(info->tag)); if (fmt) { va_start(ap, fmt); vsprintf(info->message, fmt, ap); va_end(ap); } exit(0); } #define cfail_err(info, descr) cfail((info), (descr), "%s", strerror(errno)) /* * Use kinfo_getfile() to fetch the list of file descriptors and figure out * the highest open file descriptor. */ static int highest_fd(void) { struct kinfo_file *kif; int cnt, i, highest; kif = kinfo_getfile(getpid(), &cnt); if (kif == NULL) fail_err("kinfo_getfile"); highest = INT_MIN; for (i = 0; i < cnt; i++) if (kif[i].kf_fd > highest) highest = kif[i].kf_fd; free(kif); return (highest); } static int devnull(void) { int fd; fd = open("/dev/null", O_RDONLY); if (fd < 0) fail_err("open(\"/dev/null\")"); return (fd); } int main(int __unused argc, char __unused *argv[]) { struct shared_info *info; pid_t pid; int fd, i; printf("1..15\n"); /* We better start up with fd's 0, 1, and 2 open. */ fd = devnull(); if (fd != 3) fail("open", "bad descriptor %d", fd); ok("open"); /* Make sure highest_fd() works. */ fd = highest_fd(); if (fd != 3) fail("highest_fd", "bad descriptor %d", fd); ok("highest_fd"); /* Try to use closefrom() for just closing fd 3. */ closefrom(3); fd = highest_fd(); if (fd != 2) fail("closefrom", "highest fd %d", fd); ok("closefrom"); /* Eat up 16 descriptors. */ for (i = 0; i < 16; i++) (void)devnull(); fd = highest_fd(); if (fd != 18) fail("open 16", "highest fd %d", fd); ok("open 16"); /* Close half of them. */ closefrom(11); fd = highest_fd(); if (fd != 10) fail("closefrom", "highest fd %d", fd); ok("closefrom"); /* Explicitly close descriptors 6 and 8 to create holes. */ if (close(6) < 0 || close(8) < 0) fail_err("close2 "); ok("close 2"); /* Verify that close on 6 and 8 fails with EBADF. */ if (close(6) == 0) fail("close(6)", "did not fail"); if (errno != EBADF) fail_err("close(6)"); ok("close(6)"); if (close(8) == 0) fail("close(8)", "did not fail"); if (errno != EBADF) fail_err("close(8)"); ok("close(8)"); /* Close from 4 on. */ closefrom(4); fd = highest_fd(); if (fd != 3) fail("closefrom", "highest fd %d", fd); ok("closefrom"); /* Allocate a small SHM region for IPC with our child. */ info = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); if (info == MAP_FAILED) fail_err("mmap"); ok("mmap"); /* Fork a child process to test closefrom(0). */ pid = fork(); if (pid < 0) fail_err("fork"); if (pid == 0) { /* Child. */ closefrom(0); fd = highest_fd(); if (fd >= 0) cfail(info, "closefrom(0)", "highest fd %d", fd); cok(info, "closefrom(0)"); } if (wait(NULL) < 0) fail_err("wait"); if (info->failed) fail(info->tag, "%s", info->message); ok(info->tag); /* Fork a child process to test closefrom(-1). */ pid = fork(); if (pid < 0) fail_err("fork"); if (pid == 0) { /* Child. */ closefrom(-1); fd = highest_fd(); if (fd >= 0) cfail(info, "closefrom(-1)", "highest fd %d", fd); cok(info, "closefrom(-1)"); } if (wait(NULL) < 0) fail_err("wait"); if (info->failed) fail(info->tag, "%s", info->message); ok(info->tag); /* Dup stdout to 6. */ if (dup2(1, 6) < 0) fail_err("dup2"); fd = highest_fd(); if (fd != 6) fail("dup2", "highest fd %d", fd); ok("dup2"); /* Do a closefrom() starting in a hole. */ closefrom(4); fd = highest_fd(); if (fd != 3) fail("closefrom", "highest fd %d", fd); ok("closefrom"); /* Do a closefrom() beyond our highest open fd. */ closefrom(32); fd = highest_fd(); if (fd != 3) fail("closefrom", "highest fd %d", fd); ok("closefrom"); return (0); } Index: stable/8/tools/regression/netinet/arphold/arphold.c =================================================================== --- stable/8/tools/regression/netinet/arphold/arphold.c (revision 283926) +++ stable/8/tools/regression/netinet/arphold/arphold.c (revision 283927) @@ -1,164 +1,164 @@ /* - * Copyright (c) 2010 Advanced Computing Technologies LLC + * Copyright (c) 2010 Hudson River Trading LLC * Written by George Neville-Neil gnn@freebsd.org * 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. * * Description: The following is a test of the arp entry packet queues * which replaced the single packet hold entry that existed in the BSDs * since time immemorial. The test process is: * * 1) Find out the current system limit (maxhold) * 2) Using an IP address for which we do not yet have an entry * load up an ARP entry packet queue with exactly that many packets. * 3) Check the arp dropped stat to make sure that we have not dropped * any packets as yet. * 4) Add one more packet to the queue. * 5) Make sure that only one packet was dropped. * * CAVEAT: The ARP timer will flush the queue after 1 second so it is * important not to run this code in a fast loop or the test will * fail. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #define MSG_SIZE 1024 #define PORT 6969 int main(int argc, char **argv) { int sock; int maxhold; int wait; size_t size = sizeof(maxhold); struct sockaddr_in dest; char message[MSG_SIZE]; struct arpstat arpstat; size_t len = sizeof(arpstat); unsigned long dropped = 0; memset(&message, 1, sizeof(message)); if (sysctlbyname("net.link.ether.inet.maxhold", &maxhold, &size, NULL, 0) < 0) { perror("not ok 1 - sysctlbyname failed"); exit(1); } #ifdef DEBUG printf("maxhold is %d\n", maxhold); #endif /* DEBUG */ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("not ok 1 - could not open socket"); exit(1); } bzero(&dest, sizeof(dest)); if (inet_pton(AF_INET, argv[1], &dest.sin_addr.s_addr) != 1) { perror("not ok 1 - could not parse address"); exit(1); } dest.sin_len = sizeof(dest); dest.sin_family = AF_INET; dest.sin_port = htons(PORT); if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, NULL, 0) < 0) { perror("not ok 1 - could not get initial arp stats"); exit(1); } dropped = arpstat.dropped; #ifdef DEBUG printf("dropped before %ld\n", dropped); #endif /* DEBUG */ /* * Load up the queue in the ARP entry to the maximum. * We should not drop any packets at this point. */ while (maxhold > 0) { if (sendto(sock, message, sizeof(message), 0, (struct sockaddr *)&dest, sizeof(dest)) < 0) { perror("not ok 1 - could not send packet"); exit(1); } maxhold--; } if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, NULL, 0) < 0) { perror("not ok 1 - could not get new arp stats"); exit(1); } #ifdef DEBUG printf("dropped after %ld\n", arpstat.dropped); #endif /* DEBUG */ if (arpstat.dropped != dropped) { printf("not ok 1 - Failed, drops changed:" "before %ld after %ld\n", dropped, arpstat.dropped); exit(1); } dropped = arpstat.dropped; /* Now add one extra and make sure it is dropped. */ if (sendto(sock, message, sizeof(message), 0, (struct sockaddr *)&dest, sizeof(dest)) < 0) { perror("not ok 1 - could not send packet"); exit(1); } if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, NULL, 0) < 0) { perror("not ok 1 - could not get new arp stats"); exit(1); } if (arpstat.dropped != (dropped + 1)) { printf("not ok 1 - Failed to drop one packet: before" " %ld after %ld\n", dropped, arpstat.dropped); exit(1); } printf("ok\n"); return (0); } Index: stable/8/tools/regression/usr.sbin/etcupdate/always.sh =================================================================== --- stable/8/tools/regression/usr.sbin/etcupdate/always.sh (revision 283926) +++ stable/8/tools/regression/usr.sbin/etcupdate/always.sh (revision 283927) @@ -1,612 +1,612 @@ #!/bin/sh # -# Copyright (c) 2010 Advanced Computing Technologies LLC +# Copyright (c) 2010 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests to test the -A flag to the 'update' command. WORKDIR=work usage() { echo "Usage: always.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # The various states of the comparison of a file between two trees. states="equal first second difftype difflinks difffiles" # These tests deal with ignoring certain patterns of files. We run # the test multiple times forcing the install of different patterns. build_trees() { local i rm -rf $OLD $NEW $TEST $CONFLICTS for i in $states; do for j in $states; do for k in $states; do mkdir -p $OLD/$i/$j/$k $NEW/$i/$j/$k \ $TEST/$i/$j/$k done done done # What follows are the various warning/conflict cases from the # larger regression tests. These results of many of these # tests should be changed when installation is forced. The # cases when these updates should still fail even when forced # are: 1) it should not force the removal of a modified file # and 2) it should not remove a subdirectory that contains a # modified or added file. # /first/difftype/second: File with different local type # removed. Should generate a warning. mkfifo $OLD/first/difftype/second/fifo mkdir $TEST/first/difftype/second/fifo # /first/difflinks/second: Modified link removed. Should # generate a warning. ln -s "old link" $OLD/first/difflinks/second/link ln -s "test link" $TEST/first/difflinks/second/link # /first/difffiles/second: Modified file removed. Should # generate a warning. echo "foo" > $OLD/first/difffiles/second/file echo "bar" > $TEST/first/difffiles/second/file # /second/second/difftype: Newly added file conflicts with # existing file in test tree of a different type. Should # generate a warning. mkdir $NEW/second/second/difftype/dir mkfifo $TEST/second/second/difftype/dir # /second/second/difflinks: Newly added link conflicts with # existing link in test tree. Should generate a warning. ln -s "new link" $NEW/second/second/difflinks/link ln -s "test link" $TEST/second/second/difflinks/link # /second/second/difffiles: Newly added file conflicts with # existing file in test tree. Should generate a warning. echo "new" > $NEW/second/second/difffiles/file echo "test" > $TEST/second/second/difffiles/file # /difftype/first/first: A removed file has changed type. # This should generate a warning. mkfifo $OLD/difftype/first/first/fifo mkdir $NEW/difftype/first/first/fifo # /difftype/difftype/difftype: All three files (old, new, and # test) are different types from each other. This should # generate a warning. mkfifo $OLD/difftype/difftype/difftype/one mkdir $NEW/difftype/difftype/difftype/one echo "foo" > $TEST/difftype/difftype/difftype/one mkdir $OLD/difftype/difftype/difftype/two echo "baz" > $NEW/difftype/difftype/difftype/two ln -s "bar" $TEST/difftype/difftype/difftype/two # /difftype/difftype/difflinks: A file has changed from a # non-link to a link in both the new and test trees, but the # target of the new and test links differ. This should # generate a new link conflict. mkfifo $OLD/difftype/difftype/difflinks/link ln -s "new" $NEW/difftype/difftype/difflinks/link ln -s "test" $TEST/difftype/difftype/difflinks/link # /difftype/difftype/difffile: A file has changed from a # non-regular file to a regular file in both the new and test # trees, but the contents in the new and test files differ. # This should generate a new file conflict. ln -s "old" $OLD/difftype/difftype/difffiles/file echo "foo" > $NEW/difftype/difftype/difffiles/file echo "bar" > $TEST/difftype/difftype/difffiles/file # /difflinks/first/first: A modified link is missing in the # test tree. This should generate a warning. ln -s "old" $OLD/difflinks/first/first/link ln -s "new" $NEW/difflinks/first/first/link # /difflinks/difftype/difftype: An updated link has been # changed to a different file type in the test tree. This # should generate a warning. ln -s "old" $OLD/difflinks/difftype/difftype/link ln -s "new" $NEW/difflinks/difftype/difftype/link echo "test" > $TEST/difflinks/difftype/difftype/link # /difflinks/difflinks/difflinks: An updated link has been # modified in the test tree and doesn't match either the old # or new links. This should generate a warning. ln -s "old" $OLD/difflinks/difflinks/difflinks/link ln -s "new" $NEW/difflinks/difflinks/difflinks/link ln -s "test" $TEST/difflinks/difflinks/difflinks/link # /difffiles/first/first: A removed file has been changed in # the new tree. This should generate a warning. echo "foo" > $OLD/difffiles/first/first/file echo "bar" > $NEW/difffiles/first/first/file # /difffiles/difftype/difftype: An updated regular file has # been changed to a different file type in the test tree. # This should generate a warning. echo "old" > $OLD/difffiles/difftype/difftype/file echo "new" > $NEW/difffiles/difftype/difftype/file mkfifo $TEST/difffiles/difftype/difftype/file # /difffiles/difffiles/difffiles: A modified regular file was # updated in the new tree. The changes should be merged into # to the new file if possible. If the merge fails, a conflict # should be generated. For this test we just include the # conflict case. cat > $OLD/difffiles/difffiles/difffiles/conflict < $NEW/difffiles/difffiles/difffiles/conflict < $TEST/difffiles/difffiles/difffiles/conflict < $TEST/rmdir/extra/localfile.txt # /rmdir/conflict: Do not remove a directory with a conflicted # remove file. This should generate a warning. for i in $OLD $TEST; do mkdir $i/rmdir/conflict done mkfifo $OLD/rmdir/conflict/difftype mkdir $TEST/rmdir/conflict/difftype ## Tests for converting files to directories and vice versa for i in $OLD $NEW $TEST; do for j in already old fromdir todir; do mkdir -p $i/dirchange/$j done done # /dirchange/fromdir/extradir: Convert a directory tree to a # file. The test tree includes an extra file in the directory # that is not present in the old tree. This should generate a # warning. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/extradir echo "foo" > $i/dirchange/fromdir/extradir/file done mkfifo $TEST/dirchange/fromdir/extradir/fifo ln -s "bar" $NEW/dirchange/fromdir/extradir # /dirchange/fromdir/conflict: Convert a directory tree to a # file. The test tree includes a local change that generates # a warning and prevents the removal of the directory. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/conflict done echo "foo" > $OLD/dirchange/fromdir/conflict/somefile echo "bar" > $TEST/dirchange/fromdir/conflict/somefile mkfifo $NEW/dirchange/fromdir/conflict # /dirchange/todir/difffile: Convert a file to a directory # tree. The test tree has a locally modified version of the # file so that the conversion fails with a warning. echo "foo" > $OLD/dirchange/todir/difffile mkdir $NEW/dirchange/todir/difffile echo "baz" > $NEW/dirchange/todir/difffile/file echo "bar" > $TEST/dirchange/todir/difffile # /dirchange/todir/difftype: Similar to the previous test, but # the conflict is due to a change in the file type. echo "foo" > $OLD/dirchange/todir/difftype mkdir $NEW/dirchange/todir/difftype echo "baz" > $NEW/dirchange/todir/difftype/file mkfifo $TEST/dirchange/todir/difftype } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" fi } # $1 - relative path to file that should be present in TEST present() { if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be present" fi } # $1 - relative path to file that should be a fifo in TEST fifo() { if ! [ -p $TEST/$1 ]; then echo "File $1 should be a FIFO" fi } # $1 - relative path to file that should be a directory in TEST dir() { if ! [ -d $TEST/$1 ]; then echo "File $1 should be a directory" fi } # $1 - relative path to file that should be a symlink in TEST # $2 - optional value of the link link() { local val if ! [ -L $TEST/$1 ]; then echo "File $1 should be a link" elif [ $# -gt 1 ]; then val=`readlink $TEST/$1` if [ "$val" != "$2" ]; then echo "Link $1 should link to \"$2\"" fi fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should have a conflict # $2 - optional MD5 of the conflict file contents conflict() { local sum if ! [ -f $CONFLICTS/$1 ]; then echo "File $1 missing conflict" elif [ $# -gt 1 ]; then sum=`md5 -q $CONFLICTS/$1` if [ "$sum" != "$2" ]; then echo "Conflict $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should not have a conflict noconflict() { if [ -f $CONFLICTS/$1 ]; then echo "File $1 should not have a conflict" fi } if [ `id -u` -ne 0 ]; then echo "must be root" fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # First run the test ignoring no patterns. build_trees $COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out cat > $WORKDIR/correct.out < \ $WORKDIR/test1.out cat > $WORKDIR/correct1.out < # 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$ # Various regression tests to run for the 'resolve' command. WORKDIR=work usage() { echo "Usage: conflicts.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # These tests deal with conflicts to a single file. For each test, we # generate a conflict in /etc/login.conf. Each resolve option is tested # to ensure it DTRT. build_login_conflict() { rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD/etc $NEW/etc $TEST/etc # Generate a conflict in /etc/login.conf. cat > $OLD/etc/login.conf < $NEW/etc/login.conf < $TEST/etc/login.conf </dev/null } # This is used to verify special handling for /etc/mail/aliases and # the newaliases warning. build_aliases_conflict() { rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD/etc/mail $NEW/etc/mail $TEST/etc/mail # Generate a conflict in /etc/mail/aliases cat > $OLD/etc/mail/aliases < $NEW/etc/mail/aliases < $TEST/etc/mail/aliases </dev/null } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" fi } # $1 - relative path to file that should be present in TEST present() { if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be present" fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should have a conflict # $2 - optional MD5 of the conflict file contents conflict() { local sum if ! [ -f $CONFLICTS/$1 ]; then echo "File $1 missing conflict" elif [ $# -gt 1 ]; then sum=`md5 -q $CONFLICTS/$1` if [ "$sum" != "$2" ]; then echo "Conflict $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should no longer have a conflict resolved() { if [ -f $CONFLICTS/$1 ]; then echo "Conflict $1 should be resolved" fi } if [ `id -u` -ne 0 ]; then echo "must be root" fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # Test each of the following resolve options: 'p', 'mf', 'tf', 'r'. build_login_conflict # Verify that 'p' doesn't do anything. echo "Checking 'p':" echo 'p' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null file /etc/login.conf "" 95de92ea3f1bb1bf4f612a8b5908cddd missing /etc/login.conf.db conflict /etc/login.conf # Verify that 'mf' removes the conflict, but does nothing else. echo "Checking 'mf':" echo 'mf' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null file /etc/login.conf "" 95de92ea3f1bb1bf4f612a8b5908cddd missing /etc/login.conf.db resolved /etc/login.conf build_login_conflict # Verify that 'tf' installs the new version of the file. echo "Checking 'tf':" echo 'tf' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null file /etc/login.conf "" 7774a0f9a3a372c7c109c32fd31c4b6b file /etc/login.conf.db resolved /etc/login.conf build_login_conflict # Verify that 'r' installs the resolved version of the file. To # simulate this, manually edit the merged file so that it doesn't # contain conflict markers. echo "Checking 'r':" cat > $CONFLICTS/etc/login.conf </dev/null file /etc/login.conf "" 966e25984b9b63da8eaac8479dcb0d4d file /etc/login.conf.db resolved /etc/login.conf build_aliases_conflict # Verify that 'p' and 'mf' do not generate the newaliases warning. echo "Checking newalias warning for 'p'": echo 'p' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -eq 0 ]; then echo "+ Extra warning" fi echo "Checking newalias warning for 'mf'": echo 'mf' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -eq 0 ]; then echo "+ Extra warning" fi # Verify that 'tf' and 'r' do generate the newaliases warning. build_aliases_conflict echo "Checking newalias warning for 'tf'": echo 'tf' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -ne 0 ]; then echo "- Missing warning" fi build_aliases_conflict cp $TEST/etc/mail/aliases $CONFLICTS/etc/mail/aliases echo 'r' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -ne 0 ]; then echo "- Missing warning" fi Index: stable/8/tools/regression/usr.sbin/etcupdate/fbsdid.sh =================================================================== --- stable/8/tools/regression/usr.sbin/etcupdate/fbsdid.sh (revision 283926) +++ stable/8/tools/regression/usr.sbin/etcupdate/fbsdid.sh (revision 283927) @@ -1,379 +1,379 @@ #!/bin/sh # -# Copyright (c) 2010 Advanced Computing Technologies LLC +# Copyright (c) 2010 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests to test the -F flag to the 'update' command. WORKDIR=work usage() { echo "Usage: fbsdid.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # Store a FreeBSD ID string in a specified file. The first argument # is the file, the remaining arguments are the comment to use. store_id() { local file file=$1 shift echo -n '# $FreeBSD' >> $file echo -n "$@" >> $file echo '$' >> $file } # These tests deal with FreeBSD ID string conflicts. We run the test # twice, once without -F and once with -F. build_trees() { local i rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD $NEW $TEST # remove: Remove a file where the only local difference is a # change in the FreeBSD ID string. store_id $OLD/remove store_id $TEST/remove ": head/remove 12345 jhb " # old: Modify a file where the only local difference between # the old and test files is a change in the FreeBSD ID string. store_id $OLD/old ": src/old,v 1.1 jhb Exp " store_id $NEW/old ": head/old 12345 jhb " store_id $TEST/old ": head/old 12000 jhb " for i in $OLD $TEST; do cat >> $i/old <> $NEW/old <> $OLD/already <> $i/already <> $OLD/conflict <> $NEW/conflict <> $TEST/conflict <> $i/local <> $i/local <> $TEST/local <> $i/local-already <> $TEST/local-already <> $i/local-remove < $WORKDIR/test.out cat > $WORKDIR/correct.out < $WORKDIR/testF.out cat > $WORKDIR/correctF.out < $WORKDIR/testAF.out cat > $WORKDIR/correctAF.out < # 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$ # Various regression tests to test the -I flag to the 'update' command. WORKDIR=work usage() { echo "Usage: ignore.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # These tests deal with ignoring certain patterns of files. We run the # test multiple times ignoring different patterns. build_trees() { local i rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD $NEW $TEST for i in $OLD $NEW $TEST; do mkdir -p $i/tree done # tree: Test three different cases (add, modify, remove) that all # match the tree/* glob. echo "foo" > $NEW/tree/add for i in $OLD $TEST; do echo "old" > $i/tree/modify done echo "new" > $NEW/tree/modify for i in $OLD $TEST; do echo "old" > $i/tree/remove done # rmdir: Remove a whole tree. for i in $OLD $TEST; do mkdir $i/rmdir echo "foo" > $i/rmdir/file done } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" fi } # $1 - relative path to file that should be present in TEST present() { if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be present" fi } # $1 - relative path to file that should be a directory in TEST dir() { if ! [ -d $TEST/$1 ]; then echo "File $1 should be a directory" fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should have a conflict # $2 - optional MD5 of the conflict file contents conflict() { local sum if ! [ -f $CONFLICTS/$1 ]; then echo "File $1 missing conflict" elif [ $# -gt 1 ]; then sum=`md5 -q $CONFLICTS/$1` if [ "$sum" != "$2" ]; then echo "Conflict $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should not have a conflict noconflict() { if [ -f $CONFLICTS/$1 ]; then echo "File $1 should not have a conflict" fi } if [ `id -u` -ne 0 ]; then echo "must be root" fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # First run the test ignoring no patterns. build_trees $COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out cat > $WORKDIR/correct.out < $WORKDIR/test1.out cat > $WORKDIR/correct1.out < \ $WORKDIR/test2.out cat > $WORKDIR/correct2.out < \ $WORKDIR/test3.out cat > $WORKDIR/correct3.out < # 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$ # Regression tests for the pre-world (-p) mode WORKDIR=work usage() { echo "Usage: preworld.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts SRC=$WORKDIR/src OLD=$WORKDIR/current TEST=$WORKDIR/test build_trees() { # Populate trees with pre-world files and additional files # that should not be touched. rm -rf $SRC $OLD $TEST $CONFLICTS # Create the "old" source tree as the starting point mkdir -p $OLD/etc cat >> $OLD/etc/master.passwd <> $OLD/etc/group <> $OLD/etc/inetd.conf <:/' $TEST/etc/master.passwd cat >> $TEST/etc/master.passwd <:1001:1001::0:0:John Baldwin:/home/john:/bin/tcsh messagebus:*:556:556::0:0:D-BUS Daemon User:/nonexistent:/usr/sbin/nologin polkit:*:562:562::0:0:PolicyKit User:/nonexistent:/usr/sbin/nologin haldaemon:*:560:560::0:0:HAL Daemon User:/nonexistent:/usr/sbin/nologin EOF awk '/wheel/ { printf "%s,john\n", $0; next } // { print }' \ $OLD/etc/group > $TEST/etc/group cat >> $TEST/etc/group <> $SRC/etc/inetd.conf < $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for real:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out check_trees Index: stable/8/tools/regression/usr.sbin/etcupdate/tests.sh =================================================================== --- stable/8/tools/regression/usr.sbin/etcupdate/tests.sh (revision 283926) +++ stable/8/tools/regression/usr.sbin/etcupdate/tests.sh (revision 283927) @@ -1,1004 +1,1004 @@ #!/bin/sh # -# Copyright (c) 2010 Advanced Computing Technologies LLC +# Copyright (c) 2010 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests to run for the 'update' command. WORKDIR=work usage() { echo "Usage: tests.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # The various states of the comparison of a file between two trees. states="equal first second difftype difflinks difffiles" build_trees() { local i j k rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD/etc $NEW/etc $TEST/etc # For an given file, there are three different pair-wise # relations between the three threes (old, new, and test): old # vs new, old vs test, and new vs test. Each of these # relations takes on one of six different states from the # 'compare()' function in etcupdate: equal, onlyfirst, # onlysecond, difftype, difflinks, difffiles. In addition, # there are special considerations for considering cases such # as a file merge that results in conflicts versus one that # does not, special treatment of directories, etc. The tests # below attempt to enumerate the three dimensional test matrix # by having the path name use the three different tree states # for the parent directories. # # Note that if the old and new files are identical (so first # compare is "equal"), then the second and third comparisons # will be the same. # # Note also that etcupdate only cares about files that are # present in at least one of the old or new trees. Thus, none # of the '*/second/second' cases are relevant. for i in $states; do for j in $states; do for k in $states; do mkdir -p $OLD/$i/$j/$k $NEW/$i/$j/$k \ $TEST/$i/$j/$k done done done # /equal/equal/equal: Everything is equal. Nothing should happen. for i in $OLD $NEW $TEST; do mkfifo $i/equal/equal/equal/fifo echo "foo" > $i/equal/equal/equal/file mkdir $i/equal/equal/equal/dir ln -s "bar" $i/equal/equal/equal/link done # /equal/first/first: The file is missing from the test # directory. Nothing should happen. for i in $OLD $NEW; do mkfifo $i/equal/first/first/fifo echo "foo" > $i/equal/first/first/file mkdir $i/equal/first/first/dir ln -s "bar" $i/equal/first/first/link done # /equal/difftype/difftype: The local file is a different # type. Nothing should happen. for i in $OLD $NEW; do mkfifo $i/equal/difftype/difftype/fifo mkdir $i/equal/difftype/difftype/fromdir done echo "bar" > $TEST/equal/difftype/difftype/fifo ln -s "test" $TEST/equal/difftype/difftype/fromdir # /equal/difflinks/difflinks: The local file is a modified # link. Nothing should happen. for i in $OLD $NEW; do ln -s "foo" $i/equal/difflinks/difflinks/link done ln -s "bar" $TEST/equal/difflinks/difflinks/link # /equal/difffiles/difffiles: The local file is a modified # file. Nothing should happen. for i in $OLD $NEW; do echo "foo" > $i/equal/difffiles/difffiles/file done echo "bar" > $TEST/equal/difffiles/difffiles/file # /first/equal/second: Remove unmodified files. The files # should all be removed. for i in $OLD $TEST; do mkfifo $i/first/equal/second/fifo echo "foo" > $i/first/equal/second/file mkdir $i/first/equal/second/emptydir ln -s "bar" $i/first/equal/second/link mkdir $i/first/equal/second/fulldir echo "foo" > $i/first/equal/second/fulldir/file done # /first/equal/*: Cannot occur. If the file is missing from # new, then new vs test will always be 'second'. # /first/first/equal: Removed files are already removed. # Nothing should happen. mkfifo $OLD/first/first/equal/fifo echo "foo" > $OLD/first/first/equal/file mkdir $OLD/first/first/equal/dir ln -s "bar" $OLD/first/first/equal/link # /first/first/*: Cannot occur. The files are missing from # both new and test. # /first/second/*: Cannot happen, if the file is in old for # old vs new, it cannot be missing for old vs test. # /first/difftype/second: File with different local type # removed. Should generate a warning. mkfifo $OLD/first/difftype/second/fifo mkdir $TEST/first/difftype/second/fifo # /first/difftype/*: Cannot happen since the file is missing # from new but present in test. # /first/difflinks/second: Modified link removed. Should # generate a warning. ln -s "old link" $OLD/first/difflinks/second/link ln -s "test link" $TEST/first/difflinks/second/link # /first/difflinks/*: Cannot happen since the file is missing # from new but present in test. # /first/difffiles/second: Modified file removed. Should # generate a warning. echo "foo" > $OLD/first/difffiles/second/file echo "bar" > $TEST/first/difffiles/second/file # /first/difffiles/*: Cannot happen since the file is missing # from new but present in test. # /second/equal/first: Added a new file that isn't present in # test. The empty directory should be ignored. echo "bar" > $NEW/second/equal/first/file mkfifo $NEW/second/equal/first/fifo ln -s "new" $NEW/second/equal/first/link mkdir $NEW/second/equal/first/emptydir mkdir $NEW/second/equal/first/fulldir echo "foo" > $NEW/second/equal/first/fulldir/file # /second/equal/*: Cannot happen since the file is missing # from test but present in new. # /second/first/*: Cannot happen since the file is missing # from old. # /second/second/equal: Newly added file is already present in # the test directory and identical to the new file. Nothing # should happen. for i in $NEW $TEST; do mkfifo $i/second/second/equal/fifo echo "foo" > $i/second/second/equal/file mkdir $i/second/second/equal/dir ln -s "bar" $i/second/second/equal/link done # /second/second/first: Cannot happen. The file is in dest in # the second test, so it can't be missing from the third test. # /second/second/second: Cannot happen. The file is in new in # the first test, so it can't be missing from the third test. # /second/second/difftype: Newly added file conflicts with # existing file in test tree of a different type. Should # generate a warning. mkdir $NEW/second/second/difftype/dir mkfifo $TEST/second/second/difftype/dir # /second/second/difflinks: Newly added link conflicts with # existing link in test tree. Should generate a warning. ln -s "new link" $NEW/second/second/difflinks/link ln -s "test link" $TEST/second/second/difflinks/link # /second/second/difffiles: Newly added file conflicts with # existing file in test tree. Should generate a warning. echo "new" > $NEW/second/second/difffiles/file echo "test" > $TEST/second/second/difffiles/file # /second/difftype/*: Cannot happen since the file is missing # from old. # /second/difflinks/*: Cannot happen since the file is missing # from old. # /second/difffiles/*: Cannot happen since the file is missing # from old. # /difftype/equal/difftype: Unmodified file has changed type. # File should be updated to the new file. In the 'todir' case # the directory won't actually be created because it is empty. for i in $OLD $TEST; do echo "foo" > $i/difftype/equal/difftype/file mkdir $i/difftype/equal/difftype/fromdir ln -s "old" $i/difftype/equal/difftype/todir done ln -s "test" $NEW/difftype/equal/difftype/file mkfifo $NEW/difftype/equal/difftype/fromdir mkdir $NEW/difftype/equal/difftype/todir # /difftype/equal/*: Cannot happen. Since the old file is a # difftype from the new file and the test file is identical to # the old file, the test file must be a difftype from the new # file. # /difftype/first/first: A removed file has changed type. # This should generate a warning. mkfifo $OLD/difftype/first/first/fifo mkdir $NEW/difftype/first/first/fifo # /difftype/first/*: Cannot happen. Since the new file exists # and the dest file is missing, the last test must be 'first'. # /difftype/second/*: Cannot happen. The old file exists in # the first test, so it cannot be missing in the second test. # /difftype/difftype/equal: A file has changed type, but the # file in the test directory already matches the new file. Do # nothing. echo "foo" > $OLD/difftype/difftype/equal/fifo mkfifo $OLD/difftype/difftype/equal/file for i in $NEW $TEST; do mkfifo $i/difftype/difftype/equal/fifo echo "bar" > $i/difftype/difftype/equal/file done # /difftype/difftype/first: Cannot happen. The dest file # exists in the second test. # /difftype/difftype/second: Cannot happen. The new file # exists in the first test. # /difftype/difftype/difftype: All three files (old, new, and # test) are different types from each other. This should # generate a warning. mkfifo $OLD/difftype/difftype/difftype/one mkdir $NEW/difftype/difftype/difftype/one echo "foo" > $TEST/difftype/difftype/difftype/one mkdir $OLD/difftype/difftype/difftype/two echo "baz" > $NEW/difftype/difftype/difftype/two ln -s "bar" $TEST/difftype/difftype/difftype/two # /difftype/difftype/difflinks: A file has changed from a # non-link to a link in both the new and test trees, but the # target of the new and test links differ. This should # generate a new link conflict. mkfifo $OLD/difftype/difftype/difflinks/link ln -s "new" $NEW/difftype/difftype/difflinks/link ln -s "test" $TEST/difftype/difftype/difflinks/link # /difftype/difftype/difffile: A file has changed from a # non-regular file to a regular file in both the new and test # trees, but the contents in the new and test files differ. # This should generate a new file conflict. ln -s "old" $OLD/difftype/difftype/difffiles/file echo "foo" > $NEW/difftype/difftype/difffiles/file echo "bar" > $TEST/difftype/difftype/difffiles/file # /difflinks/equal/difflinks: An unmodified symlink has # changed. The link should be updated. for i in $OLD $TEST; do ln -s "old" $i/difflinks/equal/difflinks/link done ln -s "new" $NEW/difflinks/equal/difflinks/link # /difflinks/equal/*: Cannot happen. Since old is identical # to test, the third test must be 'difflinks'. # /difflinks/first/first: A modified link is missing in the # test tree. This should generate a warning. ln -s "old" $OLD/difflinks/first/first/link ln -s "new" $NEW/difflinks/first/first/link # /difflinks/first/*: Cannot happen. Since the test file is # missing in the second test, it must be missing in the third # test. # /difflinks/second/*: Cannot happen. The old link is present # in the first test, so it cannot be missing in the second # test. # /difflinks/difftype/difftype: An updated link has been # changed to a different file type in the test tree. This # should generate a warning. ln -s "old" $OLD/difflinks/difftype/difftype/link ln -s "new" $NEW/difflinks/difftype/difftype/link echo "test" > $TEST/difflinks/difftype/difftype/link # /difflinks/difftype/*: Cannot happen. The old and new files # are both links and the test file is not a link, so the third # test must be 'difftype'. # /difflinks/difflinks/equal: An updated link has already been # updated to the new target in the test tree. Nothing should # happen. ln -s "old" $OLD/difflinks/difflinks/equal/link for i in $NEW $TEST; do ln -s "new" $i/difflinks/difflinks/equal/link done # /difflinks/difflinks/difflinks: An updated link has been # modified in the test tree and doesn't match either the old # or new links. This should generate a warning. ln -s "old" $OLD/difflinks/difflinks/difflinks/link ln -s "new" $NEW/difflinks/difflinks/difflinks/link ln -s "test" $TEST/difflinks/difflinks/difflinks/link # /difflinks/difflinks/*: Cannot happen. All three files are # links from the first two tests, so the third test can only # be 'equal' or 'difflink'. # /difflinks/difffiles/*: Cannot happen. The old file is a # link in the first test, so it cannot be a regular file in # the second. # /difffiles/equal/difffiles: An unmodified file has been # changed in new tree. The file should be updated to the new # version. for i in $OLD $TEST; do echo "foo" > $i/difffiles/equal/difffiles/file done echo "bar" > $NEW/difffiles/equal/difffiles/file # /difffiles/equal/*: Cannot happen. Since the old file is # identical to the test file, the third test must be # 'difffiles'. # /difffiles/first/first: A removed file has been changed in # the new tree. This should generate a warning. echo "foo" > $OLD/difffiles/first/first/file echo "bar" > $NEW/difffiles/first/first/file # /difffiles/first/*: Cannot happen. The new file is a # regular file from the first test and the test file is # missing in the second test, so the third test must be # 'first'. # /difffiles/second/*: Cannot happen. The old file is present # in the first test, so it must be present in the second test. # /difffiles/difftype/difftype: An updated regular file has # been changed to a different file type in the test tree. # This should generate a warning. echo "old" > $OLD/difffiles/difftype/difftype/file echo "new" > $NEW/difffiles/difftype/difftype/file mkfifo $TEST/difffiles/difftype/difftype/file # /difffiles/difftype/*: Cannot happen. The new file is known # to be a regular file from the first test, and the test file # is known to exist as a different file type from the second # test. The third test must be 'difftype'. # /difffiles/difflink/*: Cannot happen. The old file is known # to be a regular file from the first test, so it cannot be a # link in the second test. # /difffiles/difffiles/equal: An updated regular file has # already been updated to match the new file in the test tree. # Nothing should happen. echo "foo" > $OLD/difffiles/difffiles/equal/file for i in $NEW $TEST; do echo "bar" > $i/difffiles/difffiles/equal/file done # /difffiles/difffiles/difffiles: A modified regular file was # updated in the new tree. The changes should be merged into # to the new file if possible. If the merge fails, a conflict # should be generated. cat > $OLD/difffiles/difffiles/difffiles/simple < $NEW/difffiles/difffiles/difffiles/simple < $TEST/difffiles/difffiles/difffiles/simple < $OLD/difffiles/difffiles/difffiles/conflict < $NEW/difffiles/difffiles/difffiles/conflict < $TEST/difffiles/difffiles/difffiles/conflict < $NEW/adddir/partial/file mkfifo $TEST/adddir/partial/fifo ## Tests for removing directories mkdir -p $OLD/rmdir $NEW/rmdir $TEST/rmdir # /rmdir/extra: Do not remove a directory with an extra local file. # This should generate a warning. for i in $OLD $TEST; do mkdir $i/rmdir/extra done echo "foo" > $TEST/rmdir/extra/localfile.txt # /rmdir/conflict: Do not remove a directory with a conflicted # remove file. This should generate a warning. for i in $OLD $TEST; do mkdir $i/rmdir/conflict done mkfifo $OLD/rmdir/conflict/difftype mkdir $TEST/rmdir/conflict/difftype # /rmdir/partial: Remove a complete hierarchy when part of the # tree has already been removed locally. for i in $OLD $TEST; do mkdir -p $i/rmdir/partial/subdir mkfifo $i/rmdir/partial/subdir/fifo done echo "foo" > $OLD/rmdir/partial/subdir/file ## Tests for converting files to directories and vice versa for i in $OLD $NEW $TEST; do for j in already old fromdir todir; do mkdir -p $i/dirchange/$j done done # /dirchange/already/fromdir: Convert a directory tree to a # file without conflicts where the test tree already has the # new file. Nothing should happen. mkdir $OLD/dirchange/already/fromdir echo "blah" > $OLD/dirchange/already/fromdir/somefile for i in $NEW $TEST; do echo "bar" > $i/dirchange/already/fromdir done # /dirchange/already/todir: Convert an unmodified file to a # directory tree where the test tree already has the new # tree. Nothing should happen. echo "baz" > $OLD/dirchange/already/todir for i in $NEW $TEST; do mkdir $i/dirchange/already/todir echo "blah" > $i/dirchange/already/todir/somefile done # /dirchange/old/fromdir: Convert a directory tree to a file. # The old files are unmodified and should be changed to the new tree. for i in $OLD $TEST; do mkdir $i/dirchange/old/fromdir echo "blah" > $i/dirchange/old/fromdir/somefile done echo "bar" > $NEW/dirchange/old/fromdir # /dirchange/old/todir: Convert a file to a directory tree. # The old file is unmodified and should be changed to the new # tree. for i in $OLD $TEST; do echo "foo" > $i/dirchange/old/todir done mkdir $NEW/dirchange/old/todir echo "bar" > $NEW/dirchange/old/todir/file # /dirchange/fromdir/extradir: Convert a directory tree to a # file. The test tree includes an extra file in the directory # that is not present in the old tree. This should generate a # warning. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/extradir echo "foo" > $i/dirchange/fromdir/extradir/file done mkfifo $TEST/dirchange/fromdir/extradir/fifo ln -s "bar" $NEW/dirchange/fromdir/extradir # /dirchange/fromdir/conflict: Convert a directory tree to a # file. The test tree includes a local change that generates # a warning and prevents the removal of the directory. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/conflict done echo "foo" > $OLD/dirchange/fromdir/conflict/somefile echo "bar" > $TEST/dirchange/fromdir/conflict/somefile mkfifo $NEW/dirchange/fromdir/conflict # /dirchange/todir/difffile: Convert a file to a directory # tree. The test tree has a locally modified version of the # file so that the conversion fails with a warning. echo "foo" > $OLD/dirchange/todir/difffile mkdir $NEW/dirchange/todir/difffile echo "baz" > $NEW/dirchange/todir/difffile/file echo "bar" > $TEST/dirchange/todir/difffile # /dirchange/todir/difftype: Similar to the previous test, but # the conflict is due to a change in the file type. echo "foo" > $OLD/dirchange/todir/difftype mkdir $NEW/dirchange/todir/difftype echo "baz" > $NEW/dirchange/todir/difftype/file mkfifo $TEST/dirchange/todir/difftype ## Tests for post-install actions # - Adding /etc/master.passwd should cause pwd_mkdb to be run echo "foo:*:16000:100::0:0:& user:/home/foo:/bin/tcsh" > \ $NEW/etc/master.passwd # - Verify that updating an unmodified /etc/login.conf builds # /etc/login.conf.db. cat > $OLD/etc/login.conf < $NEW/etc/login.conf < $OLD/etc/mail/aliases < $NEW/etc/mail/aliases < $TEST/etc/mail/aliases < $OLD/etc/services < $NEW/etc/services < $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for real:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out check_trees Index: stable/8/tools/regression/usr.sbin/etcupdate/tzsetup.sh =================================================================== --- stable/8/tools/regression/usr.sbin/etcupdate/tzsetup.sh (revision 283926) +++ stable/8/tools/regression/usr.sbin/etcupdate/tzsetup.sh (revision 283927) @@ -1,221 +1,221 @@ #!/bin/sh # -# Copyright (c) 2013 Advanced Computing Technologies LLC +# Copyright (c) 2013 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests for the tzsetup handling in the 'update' command. WORKDIR=work usage() { echo "Usage: tzsetup.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test build_trees() { # Build the base tree, but not /etc/localtime itself local i j k rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD $NEW $TEST mkdir -p $TEST/etc mkdir -p $TEST/var/db mkdir -p $TEST/usr/share/zoneinfo # Create a dummy timezone file echo "foo" > $TEST/usr/share/zoneinfo/foo } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" fi } # $1 - relative path to file that should be a symlink in TEST # $2 - optional value of the link link() { local val if ! [ -L $TEST/$1 ]; then echo "File $1 should be a link" elif [ $# -gt 1 ]; then val=`readlink $TEST/$1` if [ "$val" != "$2" ]; then echo "Link $1 should link to \"$2\"" fi fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" fi fi } if [ `id -u` -ne 0 ]; then echo "must be root" fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # First, test for /etc/localtime not existing build_trees $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for no /etc/localtime:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out missing /etc/localtime missing /var/db/zoneinfo # Second, test for /etc/localtime being a symlink build_trees ln -s /dev/null $TEST/etc/localtime $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for symlinked /etc/localtime:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out link /etc/localtime "/dev/null" missing /var/db/zoneinfo # Third, test for /etc/localtime as a file and a missing /var/db/zoneinfo build_trees echo "bar" > $TEST/etc/localtime $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for missing /var/db/zoneinfo:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out file /etc/localtime "bar" missing /var/db/zoneinfo # Finally, test the case where it should update /etc/localtime build_trees echo "bar" > $TEST/etc/localtime echo "foo" > $TEST/var/db/zoneinfo $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for real update:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out file /etc/localtime "foo" file /var/db/zoneinfo "foo" Index: stable/8/usr.bin/perror/perror.1 =================================================================== --- stable/8/usr.bin/perror/perror.1 (revision 283926) +++ stable/8/usr.bin/perror/perror.1 (revision 283927) @@ -1,50 +1,50 @@ .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: George V. Neville-Neil .\" 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$ .\" .Dd May 12, 2009 .Dt PERROR 1 .Os .Sh NAME .Nm perror .Nd "print an error number as a string" .Sh SYNOPSIS .Nm .Ar number .Sh DESCRIPTION The .Nm program takes a raw errno value and prints it as a string. .Sh SEE ALSO .Xr perror 3 .Sh HISTORY The .Nm program first appeared in .Fx 8.0 . .Sh AUTHORS .An George V. Neville-Neil Index: stable/8/usr.bin/perror/perror.c =================================================================== --- stable/8/usr.bin/perror/perror.c (revision 283926) +++ stable/8/usr.bin/perror/perror.c (revision 283927) @@ -1,72 +1,72 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: George V. Neville-Neil * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include static void usage(void); int main(int argc, char **argv) { char *cp; char *errstr; long errnum; (void) setlocale(LC_MESSAGES, ""); if (argc != 2) usage(); errno = 0; errnum = strtol(argv[1], &cp, 0); if (errno != 0) err(1, NULL); if ((errstr = strerror(errnum)) == NULL) err(1, NULL); printf("%s\n", errstr); exit(0); } static void usage(void) { fprintf(stderr, "usage: perror number\n"); exit(1); } Index: stable/8/usr.bin/perror =================================================================== --- stable/8/usr.bin/perror (revision 283926) +++ stable/8/usr.bin/perror (revision 283927) Property changes on: stable/8/usr.bin/perror ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/usr.bin/perror:r281887 Index: stable/8/usr.sbin/etcupdate/etcupdate.8 =================================================================== --- stable/8/usr.sbin/etcupdate/etcupdate.8 (revision 283926) +++ stable/8/usr.sbin/etcupdate/etcupdate.8 (revision 283927) @@ -1,888 +1,888 @@ -.\" Copyright (c) 2010-2013 Advanced Computing Technologies LLC +.\" Copyright (c) 2010-2013 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 29, 2014 .Dt ETCUPDATE 8 .Os .Sh NAME .Nm etcupdate .Nd "manage updates to system files not updated by installworld" .Sh SYNOPSIS .Nm .Op Fl npBF .Op Fl d Ar workdir .Op Fl r | Fl s Ar source | Fl t Ar tarball .Op Fl A Ar patterns .Op Fl D Ar destdir .Op Fl I Ar patterns .Op Fl L Ar logfile .Op Fl M Ar options .Nm .Cm build .Op Fl B .Op Fl d Ar workdir .Op Fl s Ar source .Op Fl L Ar logfile .Op Fl M Ar options .Ar tarball .Nm .Cm diff .Op Fl d Ar workdir .Op Fl D Ar destdir .Op Fl I Ar patterns .Op Fl L Ar logfile .Nm .Cm extract .Op Fl B .Op Fl d Ar workdir .Op Fl s Ar source | Fl t Ar tarball .Op Fl L Ar logfile .Op Fl M Ar options .Nm .Cm resolve .Op Fl p .Op Fl d Ar workdir .Op Fl D Ar destdir .Op Fl L Ar logfile .Nm .Cm status .Op Fl d Ar workdir .Op Fl D Ar destdir .Sh DESCRIPTION The .Nm utility is a tool for managing updates to files that are not updated as part of .Sq make installworld such as files in .Pa /etc . It manages updates by doing a three-way merge of changes made to these files against the local versions. It is also designed to minimize the amount of user intervention with the goal of simplifying upgrades for clusters of machines. .Pp To perform a three-way merge, .Nm keeps copies of the current and previous versions of files that it manages. These copies are stored in two trees known as the .Dq current and .Dq previous trees. During a merge, .Nm compares the .Dq current and .Dq previous copies of each file to determine which changes need to be merged into the local version of each file. If a file can be updated without generating a conflict, .Nm will update the file automatically. If the local changes to a file conflict with the changes made to a file in the source tree, then a merge conflict is generated. The conflict must be resolved after the merge has finished. The .Nm utility will not perform a new merge until all conflicts from an earlier merge are resolved. .Sh MODES The .Nm utility supports several modes of operation. The mode is specified via an optional command argument. If present, the command must be the first argument on the command line. If a command is not specified, the default mode is used. .Ss Default Mode The default mode merges changes from the source tree to the destination directory. First, it updates the .Dq current and .Dq previous trees. Next, it compares the two trees merging changes into the destination directory. Finally, it displays warnings for any conditions it could not handle automatically. .Pp If the .Fl r option is not specified, then the first step taken is to update the .Dq current and .Dq previous trees. If a .Dq current tree already exists, then that tree is saved as the .Dq previous tree. An older .Dq previous tree is removed if it exists. By default the new .Dq current tree is built from a source tree. However, if a tarball is specified via the .Fl t option, then the tree is extracted from that tarball instead. .Pp Next, .Nm compares the files in the .Dq current and .Dq previous trees. If a file was removed from the .Dq current tree, then it will be removed from the destination directory only if it does not have any local modifications. If a file was added to the .Dq current tree, then it will be copied to the destination directory only if it would not clobber an existing file. If a file is changed in the .Dq current tree, then .Nm will attempt to merge the changes into the version of the file in the destination directory. If the merge encounters conflicts, then a version of the file with conflict markers will be saved for future resolution. If the merge does not encounter conflicts, then the merged version of the file will be saved in the destination directory. If .Nm is not able to safely merge in changes to a file other than a merge conflict, it will generate a warning. .Pp For each file that is updated a line will be output with a leading character to indicate the action taken. The possible actions follow: .Pp .Bl -tag -width "A" -compact -offset indent .It A Added .It C Conflict .It D Deleted .It M Merged .It U Updated .El .Pp Finally, if any warnings were encountered they are displayed after the merge has completed. .Pp Note that for certain files .Nm will perform post-install actions any time that the file is updated. Specifically, .Xr pwd_mkdb 8 is invoked if .Pa /etc/master.passwd is changed, .Xr cap_mkdb 1 is invoked to update .Pa /etc/login.conf.db if .Pa /etc/login.conf is changed, .Xr newaliases 1 is invoked if .Pa /etc/mail/aliases is changed, and .Pa /etc/rc.d/motd is invoked if .Pa /etc/motd is changed. One exception is that if .Pa /etc/mail/aliases is changed and the destination directory is not the default, then a warning will be issued instead. This is due to a limitation of the .Xr newaliases 1 command. Similarly, if .Pa /etc/motd is changed and the destination directory is not the default, then .Pa /etc/rc.d/motd will not be executed due to a limitation of that script. In this case no warning is issued as the result of .Pa /etc/rc.d/motd is merely cosmetic and will be corrected on the next reboot. .Ss Build Mode The .Cm build mode is used to build a tarball that contains a snapshot of a .Dq current tree. This tarball can be used by the default and extract modes. Using a tarball can allow .Nm to perform a merge without requiring a source tree that matches the currently installed world. The .Fa tarball argument specifies the name of the file to create. The file will be a .Xr tar 5 file compressed with .Xr bzip2 1 . .Ss Diff Mode The .Cm diff mode compares the versions of files in the destination directory to the .Dq current tree and generates a unified format diff of the changes. This can be used to determine which files have been locally modified and how. Note that .Nm does not manage files that are not maintained in the source tree such as .Pa /etc/fstab and .Pa /etc/rc.conf . .Ss Extract Mode The .Cm extract mode generates a new .Dq current tree. Unlike the default mode, it does not save any existing .Dq current tree and does not modify any existing .Dq previous tree. The new .Dq current tree can either be built from a source tree or extracted from a tarball. .Ss Resolve Mode The .Cm resolve mode is used to resolve any conflicts encountered during a merge. In this mode, .Nm iterates over any existing conflicts prompting the user for actions to take on each conflicted file. For each file, the following actions are available: .Pp .Bl -tag -width "(tf) theirs-full" -compact .It (p) postpone Ignore this conflict for now. .It (df) diff-full Show all changes made to the merged file as a unified diff. .It (e) edit Change the merged file in an editor. .It (r) resolved Install the merged version of the file into the destination directory. .It (mf) mine-full Use the version of the file in the destination directory and ignore any changes made to the file in the .Dq current tree. .It (tf) theirs-full Use the version of the file from the .Dq current tree and discard any local changes made to the file. .It (h) help Display the list of commands. .El .Ss Status Mode The .Cm status mode shows a summary of the results of the most recent merge. First it lists any files for which there are unresolved conflicts. Next it lists any warnings generated during the last merge. If the last merge did not generate any conflicts or warnings, then nothing will be output. .Sh OPTIONS The following options are available. Note that most options do not apply to all modes. .Bl -tag -width ".Fl A Ar patterns" .It Fl A Ar patterns Always install the new version of any files that match any of the patterns listed in .Ar patterns . Each pattern is evaluated as an .Xr sh 1 shell pattern. This option may be specified multiple times to specify multiple patterns. Multiple space-separated patterns may also be specified in a single option. Note that ignored files specified via the .Ev IGNORE_FILES variable or the .Fl I option will not be installed. .It Fl B Do not build generated files in a private object tree. Instead, reuse the generated files from a previously built object tree that matches the source tree. This can be useful to avoid gratuitous conflicts in .Xr sendmail 8 configuration files when bootstrapping. It can also be useful for building a tarball that matches a specific world build. .It Fl D Ar destdir Specify an alternate destination directory as the target of a merge. This is analogous to the .Dv DESTDIR variable used with .Sq make installworld . The default destination directory is an empty string which results in merges updating .Pa /etc on the local machine. .It Fl d Ar workdir Specify an alternate directory to use as the work directory. The work directory is used to store the .Dq current and .Dq previous trees as well as unresolved conflicts. The default work directory is .Pa /var/db/etcupdate . .It Fl F Ignore changes in the FreeBSD ID string when comparing files in the destination directory to files in either of the .Dq current or .Dq previous trees. In .Cm diff mode, this reduces noise due to FreeBSD ID string changes in the output. During an update this can simplify handling for harmless conflicts caused by FreeBSD ID string changes. .Pp Specifically, if a file in the destination directory is identical to the same file in the .Dq previous tree modulo the FreeBSD ID string, then the file is treated as if it was unmodified and the .Dq current version of the file will be installed. Similarly, if a file in the destination directory is identical to the same file in the .Dq current tree modulo the FreeBSD ID string, then the .Dq current version of the file will be installed to update the ID string. If the .Dq previous and .Dq current versions of the file are identical, then .Nm will not change the file in the destination directory. .Pp Due to limitations in the .Xr diff 1 command, this option may not have an effect if there are other changes in a file that are close to the FreeBSD ID string. .It Fl I Ar patterns Ignore any files that match any of the patterns listed in .Ar patterns . No warnings or other messages will be generated for those files during a merge. Each pattern is evaluated as an .Xr sh 1 shell pattern. This option may be specified multiple times to specify multiple patterns. Multiple space-separated patterns may also be specified in a single option. .It Fl L Ar logfile Specify an alternate path for the log file. The .Nm utility logs each command that it invokes along with the standard output and standard error to this file. By default the log file is stored in a file named .Pa log in the work directory. .It Fl M Ar options Pass .Ar options as additional parameters to .Xr make 1 when building a .Dq current tree. This can be used for to set the .Dv TARGET or .Dv TARGET_ARCH variables for a cross-build. .It Fl n Enable .Dq dry-run mode. Do not merge any changes to the destination directory. Instead, report what actions would be taken during a merge. Note that the existing .Dq current and .Dq previous trees will not be changed. If the .Fl r option is not specified, then a temporary .Dq current tree will be extracted to perform the comparison. .It Fl p Enable .Dq pre-world mode. Only merge changes to files that are necessary to successfully run .Sq make installworld or .Sq make installkernel . When this flag is enabled, the existing .Dq current and .Dq previous trees are left alone. Instead, a temporary tree is populated with the necessary files. This temporary tree is compared against the .Dq current tree. This allows a normal update to be run after .Sq make installworld has completed. Any conflicts generated during a .Dq pre-world update should be resolved by a .Dq pre-world .Cm resolve . .It Fl r Do not update the .Dq current and .Dq previous trees during a merge. This can be used to .Dq re-run a previous merge operation. .It Fl s Ar source Specify an alternate source tree to use when building or extracting a .Dq current tree. The default source tree is .Pa /usr/src . .It Fl t Ar tarball Extract a new .Dq current tree from a tarball previously generated by the .Cm build command rather than building the tree from a source tree. .El .Sh CONFIG FILE The .Nm utility can also be configured by setting variables in an optional configuration file named .Pa /etc/etcupdate.conf . Note that command line options override settings in the configuration file. The configuration file is executed by .Xr sh 1 , so it uses that syntax to set configuration variables. The following variables can be set: .Bl -tag -width ".Ev ALWAYS_INSTALL" .It Ev ALWAYS_INSTALL Always install files that match any of the patterns listed in this variable similar to the .Fl A option. .It Ev DESTDIR Specify an alternate destination directory similar to the .Fl D option. .It Ev EDITOR Specify a program to edit merge conflicts. .It Ev FREEBSD_ID Ignore changes in the FreeBSD ID string similar to the .Fl F option. This is enabled by setting the variable to a non-empty value. .It Ev IGNORE_FILES Ignore files that match any of the patterns listed in this variable similar to the .Fl I option. .It Ev LOGFILE Specify an alternate path for the log file similar to the .Fl L option. .It Ev MAKE_OPTIONS Pass additional options to .Xr make 1 when building a .Dq current tree similar to the .Fl M option. .It Ev SRCDIR Specify an alternate source tree similar to the .Fl s option. .It Ev WORKDIR Specify an alternate work directory similar to the .Fl d option. .El .Sh ENVIRONMENT The .Nm utility uses the program identified in the .Ev EDITOR environment variable to edit merge conflicts. If .Ev EDITOR is not set, .Xr vi 1 is used as the default editor. .Sh FILES .Bl -tag -width ".Pa /var/db/etcupdate/log" -compact .It Pa /etc/etcupdate.conf Optional config file. .It Pa /var/db/etcupdate Default work directory used to store trees and other data. .It Pa /var/db/etcupdate/log Default log file. .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES To compare the files in .Pa /etc with the stock versions: .Pp .Dl "etcupdate diff" .Pp To merge changes after an upgrade via the buildworld and installworld process: .Pp .Dl "etcupdate" .Pp To resolve any conflicts generated during a merge: .Pp .Dl "etcupdate resolve" .Ss Bootstrapping The .Nm utility may need to be bootstrapped before it can be used. The .Cm diff command will fail with an error about a missing reference tree if bootstrapping is needed. .Pp Bootstrapping .Nm requires a source tree that matches the currently installed world. The easiest way to ensure this is to bootstrap .Nm before updating the source tree to start the next world upgrade cycle. First, generate a reference tree: .Pp .Dl "etcupdate extract" .Pp Second, use the .Cm diff command to compare the reference tree to your current files in .Pa /etc . Undesired differences should be removed using an editor, .Xr patch 1 , or by copying files from the reference tree .Po located at .Pa /var/db/etcupdate/current by default .Pc . .Pp If the tree at .Pa /usr/src is already newer than the currently installed world, a new tree matching the currently installed world can be checked out to a temporary location. The reference tree for .Nm can then be generated via: .Pp .Dl "etcupdate extract -s /path/to/tree" .Pp The .Cm diff command can be used as above to remove undesired differences. Afterwards, the changes in the tree at .Pa /usr/src can be merged via a regular merge. .Sh DIAGNOSTICS The following warning messages may be generated during a merge. Note that several of these warnings cover obscure cases that should occur rarely if at all in practice. For example, if a file changes from a file to a directory in the .Dq current tree and the file was modified in the destination directory, then a warning will be triggered. In general, when a warning references a pathname, the corresponding file in the destination directory is not changed by a merge operation. .Bl -diag .It "Directory mismatch: ()" An attempt was made to create a directory at .Pa path but an existing file of type .Dq type already exists for that path name. .It "Modified link changed: ( became )" The target of a symbolic link named .Pa file was changed from .Dq old to .Dq new in the .Dq current tree. The symbolic link has been modified to point to a target that is neither .Dq old nor .Dq new in the destination directory. .It "Modified mismatch: ( vs )" A file named .Pa file of type .Dq new was modified in the .Dq current tree, but the file exists as a different type .Dq dest in the destination directory. .It "Modified changed: ( became )" A file named .Pa file changed type from .Dq old in the .Dq previous tree to type .Dq new in the .Dq current tree. The file in the destination directory of type .Dq type has been modified, so it could not be merged automatically. .It "Modified remains: " The file of type .Dq type named .Pa file has been removed from the .Dq current tree, but it has been locally modified. The modified version of the file remains in the destination directory. .It "Needs update: /etc/localtime (required manual update via tzsetup(1))" The .Fa /var/db/zoneinfo file does not exist, so .Nm was not able to refresh .Fa /etc/localtime from its source file in .Fa /usr/share/zoneinfo . Running .Xr tzsetup 1 will both refresh .Fa /etc/localtime and generate .Fa /var/db/zoneinfo permitting future updates to refresh .Fa /etc/localtime automatically. .It "Needs update: /etc/mail/aliases.db (required manual update via newaliases(1))" The file .Pa /etc/mail/aliases was updated during a merge with a non-empty destination directory. Due to a limitation of the .Xr newaliases 1 command, .Nm was not able to automatically update the corresponding aliases database. .It "New file mismatch: ( vs )" A new file named .Pa file of type .Dq new has been added to the .Dq current tree. A file of that name already exists in the destination directory, but it is of a different type .Dq dest . .It "New link conflict: ( vs )" A symbolic link named .Pa file has been added to the .Dq current tree that links to .Dq new . A symbolic link of the same name already exists in the destination directory, but it links to a different target .Dq dest . .It "Non-empty directory remains: " The directory .Pa file was removed from the .Dq current tree, but it contains additional files in the destination directory. These additional files as well as the directory remain. .It "Remove mismatch: ( became )" A file named .Pa file changed from type .Dq old in the .Dq previous tree to type .Dq new in the .Dq current tree, but it has been removed in the destination directory. .It "Removed file changed: " A file named .Pa file was modified in the .Dq current tree, but it has been removed in the destination directory. .It "Removed link changed: ( became )" The target of a symbolic link named .Pa file was changed from .Dq old to .Dq new in the .Dq current tree, but it has been removed in the destination directory. .El .Sh SEE ALSO .Xr cap_mkdb 1 , .Xr diff 1 , .Xr make 1 , .Xr newaliases 1 , .Xr sh 1 , .Xr pwd_mkdb 8 .Sh HISTORY The .Nm utility first appeared in .Fx 10.0 . .Sh AUTHORS The .Nm utility was written by .An John Baldwin Aq jhb@FreeBSD.org . .Sh BUGS Rerunning a merge does not automatically delete conflicts left over from a previous merge. Any conflicts must be resolved before the merge can be rerun. It it is not clear if this is a feature or a bug. .Pp There is no way to easily automate conflict resolution for specific files. For example, one can imagine a syntax along the lines of .Pp .Dl "etcupdate resolve tf /some/file" .Pp to resolve a specific conflict in an automated fashion. .Pp It might be nice to have something like a .Sq revert command to replace a locally modified version of a file with the stock version of the file. For example: .Pp .Dl "etcupdate revert /etc/mail/freebsd.cf" .Pp Bootstrapping .Nm often results in gratuitous diffs in .Pa /etc/mail/*.cf that cause conflicts in the first merge. If an object tree that matches the source tree is present when bootstrapping, then passing the .Fl B flag to the .Cm extract command can work around this. Index: stable/8/usr.sbin/etcupdate/etcupdate.sh =================================================================== --- stable/8/usr.sbin/etcupdate/etcupdate.sh (revision 283926) +++ stable/8/usr.sbin/etcupdate/etcupdate.sh (revision 283927) @@ -1,1794 +1,1794 @@ #!/bin/sh # -# Copyright (c) 2010-2013 Advanced Computing Technologies LLC +# Copyright (c) 2010-2013 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # This is a tool to manage updating files that are not updated as part # of 'make installworld' such as files in /etc. Unlike other tools, # this one is specifically tailored to assisting with mass upgrades. # To that end it does not require user intervention while running. # # Theory of operation: # # The most reliable way to update changes to files that have local # modifications is to perform a three-way merge between the original # unmodified file, the new version of the file, and the modified file. # This requires having all three versions of the file available when # performing an update. # # To that end, etcupdate uses a strategy where the current unmodified # tree is kept in WORKDIR/current and the previous unmodified tree is # kept in WORKDIR/old. When performing a merge, a new tree is built # if needed and then the changes are merged into DESTDIR. Any files # with unresolved conflicts after the merge are left in a tree rooted # at WORKDIR/conflicts. # # To provide extra flexibility, etcupdate can also build tarballs of # root trees that can later be used. It can also use a tarball as the # source of a new tree instead of building it from /usr/src. # Global settings. These can be adjusted by config files and in some # cases by command line options. # TODO: # - automatable conflict resolution # - a 'revert' command to make a file "stock" usage() { cat < etcupdate diff [-d workdir] [-D destdir] [-I patterns] [-L logfile] etcupdate extract [-B] [-d workdir] [-s source | -t tarball] [-L logfile] [-M options] etcupdate resolve [-p] [-d workdir] [-D destdir] [-L logfile] etcupdate status [-d workdir] [-D destdir] EOF exit 1 } # Used to write a message prepended with '>>>' to the logfile. log() { echo ">>>" "$@" >&3 } # Used for assertion conditions that should never happen. panic() { echo "PANIC:" "$@" exit 10 } # Used to write a warning message. These are saved to the WARNINGS # file with " " prepended. warn() { echo -n " " >> $WARNINGS echo "$@" >> $WARNINGS } # Output a horizontal rule using the passed-in character. Matches the # length used for Index lines in CVS and SVN diffs. # # $1 - character rule() { jot -b "$1" -s "" 67 } # Output a text description of a specified file's type. # # $1 - file pathname. file_type() { stat -f "%HT" $1 | tr "[:upper:]" "[:lower:]" } # Returns true (0) if a file exists # # $1 - file pathname. exists() { [ -e $1 -o -L $1 ] } # Returns true (0) if a file should be ignored, false otherwise. # # $1 - file pathname ignore() { local pattern - set -o noglob for pattern in $IGNORE_FILES; do set +o noglob case $1 in $pattern) return 0 ;; esac set -o noglob done # Ignore /.cshrc and /.profile if they are hardlinked to the # same file in /root. This ensures we only compare those # files once in that case. case $1 in /.cshrc|/.profile) if [ ${DESTDIR}$1 -ef ${DESTDIR}/root$1 ]; then return 0 fi ;; *) ;; esac return 1 } # Returns true (0) if the new version of a file should always be # installed rather than attempting to do a merge. # # $1 - file pathname always_install() { local pattern - set -o noglob for pattern in $ALWAYS_INSTALL; do set +o noglob case $1 in $pattern) return 0 ;; esac set -o noglob done return 1 } # Build a new tree # # $1 - directory to store new tree in build_tree() { local destdir dir file make make="make $MAKE_OPTIONS" log "Building tree at $1 with $make" mkdir -p $1/usr/obj >&3 2>&1 destdir=`realpath $1` if [ -n "$preworld" ]; then # Build a limited tree that only contains files that are # crucial to installworld. for file in $PREWORLD_FILES; do dir=`dirname /$file` mkdir -p $1/$dir >&3 2>&1 || return 1 cp -p $SRCDIR/$file $1/$file || return 1 done elif ! [ -n "$nobuild" ]; then (cd $SRCDIR; $make DESTDIR=$destdir distrib-dirs && MAKEOBJDIRPREFIX=$destdir/usr/obj $make _obj SUBDIR_OVERRIDE=etc && MAKEOBJDIRPREFIX=$destdir/usr/obj $make everything SUBDIR_OVERRIDE=etc && MAKEOBJDIRPREFIX=$destdir/usr/obj $make DESTDIR=$destdir distribution) \ >&3 2>&1 || return 1 else (cd $SRCDIR; $make DESTDIR=$destdir distrib-dirs && $make DESTDIR=$destdir distribution) >&3 2>&1 || return 1 fi chflags -R noschg $1 >&3 2>&1 || return 1 rm -rf $1/usr/obj >&3 2>&1 || return 1 # Purge auto-generated files. Only the source files need to # be updated after which these files are regenerated. rm -f $1/etc/*.db $1/etc/passwd >&3 2>&1 || return 1 # Remove empty files. These just clutter the output of 'diff'. find $1 -type f -size 0 -delete >&3 2>&1 || return 1 # Trim empty directories. find -d $1 -type d -empty -delete >&3 2>&1 || return 1 return 0 } # Generate a new NEWTREE tree. If tarball is set, then the tree is # extracted from the tarball. Otherwise the tree is built from a # source tree. extract_tree() { local files # If we have a tarball, extract that into the new directory. if [ -n "$tarball" ]; then files= if [ -n "$preworld" ]; then files="$PREWORLD_FILES" fi if ! (mkdir -p $NEWTREE && tar xf $tarball -C $NEWTREE $files) \ >&3 2>&1; then echo "Failed to extract new tree." remove_tree $NEWTREE exit 1 fi else if ! build_tree $NEWTREE; then echo "Failed to build new tree." remove_tree $NEWTREE exit 1 fi fi } # Forcefully remove a tree. Returns true (0) if the operation succeeds. # # $1 - path to tree remove_tree() { rm -rf $1 >&3 2>&1 if [ -e $1 ]; then chflags -R noschg $1 >&3 2>&1 rm -rf $1 >&3 2>&1 fi [ ! -e $1 ] } # Return values for compare() COMPARE_EQUAL=0 COMPARE_ONLYFIRST=1 COMPARE_ONLYSECOND=2 COMPARE_DIFFTYPE=3 COMPARE_DIFFLINKS=4 COMPARE_DIFFFILES=5 # Compare two files/directories/symlinks. Note that this does not # recurse into subdirectories. Instead, if two nodes are both # directories, they are assumed to be equivalent. # # Returns true (0) if the nodes are identical. If only one of the two # nodes are present, return one of the COMPARE_ONLY* constants. If # the nodes are different, return one of the COMPARE_DIFF* constants # to indicate the type of difference. # # $1 - first node # $2 - second node compare() { local first second # If the first node doesn't exist, then check for the second # node. Note that -e will fail for a symbolic link that # points to a missing target. if ! exists $1; then if exists $2; then return $COMPARE_ONLYSECOND else return $COMPARE_EQUAL fi elif ! exists $2; then return $COMPARE_ONLYFIRST fi # If the two nodes are different file types fail. first=`stat -f "%Hp" $1` second=`stat -f "%Hp" $2` if [ "$first" != "$second" ]; then return $COMPARE_DIFFTYPE fi # If both are symlinks, compare the link values. if [ -L $1 ]; then first=`readlink $1` second=`readlink $2` if [ "$first" = "$second" ]; then return $COMPARE_EQUAL else return $COMPARE_DIFFLINKS fi fi # If both are files, compare the file contents. if [ -f $1 ]; then if cmp -s $1 $2; then return $COMPARE_EQUAL else return $COMPARE_DIFFFILES fi fi # As long as the two nodes are the same type of file, consider # them equivalent. return $COMPARE_EQUAL } # Returns true (0) if the only difference between two regular files is a # change in the FreeBSD ID string. # # $1 - path of first file # $2 - path of second file fbsdid_only() { diff -qI '\$FreeBSD.*\$' $1 $2 >/dev/null 2>&1 } # This is a wrapper around compare that will return COMPARE_EQUAL if # the only difference between two regular files is a change in the # FreeBSD ID string. It only makes this adjustment if the -F flag has # been specified. # # $1 - first node # $2 - second node compare_fbsdid() { local cmp compare $1 $2 cmp=$? if [ -n "$FREEBSD_ID" -a "$cmp" -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $1 $2; then return $COMPARE_EQUAL fi return $cmp } # Returns true (0) if a directory is empty. # # $1 - pathname of the directory to check empty_dir() { local contents contents=`ls -A $1` [ -z "$contents" ] } # Returns true (0) if one directories contents are a subset of the # other. This will recurse to handle subdirectories and compares # individual files in the trees. Its purpose is to quiet spurious # directory warnings for dryrun invocations. # # $1 - first directory (sub) # $2 - second directory (super) dir_subset() { local contents file if ! [ -d $1 -a -d $2 ]; then return 1 fi # Ignore files that are present in the second directory but not # in the first. contents=`ls -A $1` for file in $contents; do if ! compare $1/$file $2/$file; then return 1 fi if [ -d $1/$file ]; then if ! dir_subset $1/$file $2/$file; then return 1 fi fi done return 0 } # Returns true (0) if a directory in the destination tree is empty. # If this is a dryrun, then this returns true as long as the contents # of the directory are a subset of the contents in the old tree # (meaning that the directory would be empty in a non-dryrun when this # was invoked) to quiet spurious warnings. # # $1 - pathname of the directory to check relative to DESTDIR. empty_destdir() { if [ -n "$dryrun" ]; then dir_subset $DESTDIR/$1 $OLDTREE/$1 return fi empty_dir $DESTDIR/$1 } # Output a diff of two directory entries with the same relative name # in different trees. Note that as with compare(), this does not # recurse into subdirectories. If the nodes are identical, nothing is # output. # # $1 - first tree # $2 - second tree # $3 - node name # $4 - label for first tree # $5 - label for second tree diffnode() { local first second file old new diffargs if [ -n "$FREEBSD_ID" ]; then diffargs="-I \\\$FreeBSD.*\\\$" else diffargs="" fi compare_fbsdid $1/$3 $2/$3 case $? in $COMPARE_EQUAL) ;; $COMPARE_ONLYFIRST) echo echo "Removed: $3" echo ;; $COMPARE_ONLYSECOND) echo echo "Added: $3" echo ;; $COMPARE_DIFFTYPE) first=`file_type $1/$3` second=`file_type $2/$3` echo echo "Node changed from a $first to a $second: $3" echo ;; $COMPARE_DIFFLINKS) first=`readlink $1/$file` second=`readlink $2/$file` echo echo "Link changed: $file" rule "=" echo "-$first" echo "+$second" echo ;; $COMPARE_DIFFFILES) echo "Index: $3" rule "=" diff -u $diffargs -L "$3 ($4)" $1/$3 -L "$3 ($5)" $2/$3 ;; esac } # Run one-off commands after an update has completed. These commands # are not tied to a specific file, so they cannot be handled by # post_install_file(). post_update() { local args # None of these commands should be run for a pre-world update. if [ -n "$preworld" ]; then return fi # If /etc/localtime exists and is not a symlink and /var/db/zoneinfo # exists, run tzsetup -r to refresh /etc/localtime. if [ -f ${DESTDIR}/etc/localtime -a \ ! -L ${DESTDIR}/etc/localtime ]; then if [ -f ${DESTDIR}/var/db/zoneinfo ]; then if [ -n "${DESTDIR}" ]; then args="-C ${DESTDIR}" else args="" fi log "tzsetup -r ${args}" if [ -z "$dryrun" ]; then tzsetup -r ${args} >&3 2>&1 fi else warn "Needs update: /etc/localtime (required" \ "manual update via tzsetup(1))" fi fi } # Create missing parent directories of a node in a target tree # preserving the owner, group, and permissions from a specified # template tree. # # $1 - template tree # $2 - target tree # $3 - pathname of the node (relative to both trees) install_dirs() { local args dir dir=`dirname $3` # Nothing to do if the parent directory exists. This also # catches the degenerate cases when the path is just a simple # filename. if [ -d ${2}$dir ]; then return 0 fi # If non-directory file exists with the desired directory # name, then fail. if exists ${2}$dir; then # If this is a dryrun and we are installing the # directory in the DESTDIR and the file in the DESTDIR # matches the file in the old tree, then fake success # to quiet spurious warnings. if [ -n "$dryrun" -a "$2" = "$DESTDIR" ]; then if compare $OLDTREE/$dir $DESTDIR/$dir; then return 0 fi fi args=`file_type ${2}$dir` warn "Directory mismatch: ${2}$dir ($args)" return 1 fi # Ensure the parent directory of the directory is present # first. if ! install_dirs $1 "$2" $dir; then return 1 fi # Format attributes from template directory as install(1) # arguments. args=`stat -f "-o %Su -g %Sg -m %0Mp%0Lp" $1/$dir` log "install -d $args ${2}$dir" if [ -z "$dryrun" ]; then install -d $args ${2}$dir >&3 2>&1 fi return 0 } # Perform post-install fixups for a file. This largely consists of # regenerating any files that depend on the newly installed file. # # $1 - pathname of the updated file (relative to DESTDIR) post_install_file() { case $1 in /etc/mail/aliases) # Grr, newaliases only works for an empty DESTDIR. if [ -z "$DESTDIR" ]; then log "newaliases" if [ -z "$dryrun" ]; then newaliases >&3 2>&1 fi else NEWALIAS_WARN=yes fi ;; /etc/login.conf) log "cap_mkdb ${DESTDIR}$1" if [ -z "$dryrun" ]; then cap_mkdb ${DESTDIR}$1 >&3 2>&1 fi ;; /etc/master.passwd) log "pwd_mkdb -p -d $DESTDIR/etc ${DESTDIR}$1" if [ -z "$dryrun" ]; then pwd_mkdb -p -d $DESTDIR/etc ${DESTDIR}$1 \ >&3 2>&1 fi ;; /etc/motd) # /etc/rc.d/motd hardcodes the /etc/motd path. # Don't warn about non-empty DESTDIR's since this # change is only cosmetic anyway. if [ -z "$DESTDIR" ]; then log "sh /etc/rc.d/motd start" if [ -z "$dryrun" ]; then sh /etc/rc.d/motd start >&3 2>&1 fi fi ;; /etc/services) log "services_mkdb -q -o $DESTDIR/var/db/services.db" \ "${DESTDIR}$1" if [ -z "$dryrun" ]; then services_mkdb -q -o $DESTDIR/var/db/services.db \ ${DESTDIR}$1 >&3 2>&1 fi ;; esac } # Install the "new" version of a file. Returns true if it succeeds # and false otherwise. # # $1 - pathname of the file to install (relative to DESTDIR) install_new() { if ! install_dirs $NEWTREE "$DESTDIR" $1; then return 1 fi log "cp -Rp ${NEWTREE}$1 ${DESTDIR}$1" if [ -z "$dryrun" ]; then cp -Rp ${NEWTREE}$1 ${DESTDIR}$1 >&3 2>&1 fi post_install_file $1 return 0 } # Install the "resolved" version of a file. Returns true if it succeeds # and false otherwise. # # $1 - pathname of the file to install (relative to DESTDIR) install_resolved() { # This should always be present since the file is already # there (it caused a conflict). However, it doesn't hurt to # just be safe. if ! install_dirs $NEWTREE "$DESTDIR" $1; then return 1 fi log "cp -Rp ${CONFLICTS}$1 ${DESTDIR}$1" cp -Rp ${CONFLICTS}$1 ${DESTDIR}$1 >&3 2>&1 post_install_file $1 return 0 } # Generate a conflict file when a "new" file conflicts with an # existing file in DESTDIR. # # $1 - pathname of the file that conflicts (relative to DESTDIR) new_conflict() { if [ -n "$dryrun" ]; then return fi install_dirs $NEWTREE $CONFLICTS $1 diff --changed-group-format='<<<<<<< (local) %<======= %>>>>>>>> (stock) ' $DESTDIR/$1 $NEWTREE/$1 > $CONFLICTS/$1 } # Remove the "old" version of a file. # # $1 - pathname of the old file to remove (relative to DESTDIR) remove_old() { log "rm -f ${DESTDIR}$1" if [ -z "$dryrun" ]; then rm -f ${DESTDIR}$1 >&3 2>&1 fi echo " D $1" } # Update a file that has no local modifications. # # $1 - pathname of the file to update (relative to DESTDIR) update_unmodified() { local new old # If the old file is a directory, then remove it with rmdir # (this should only happen if the file has changed its type # from a directory to a non-directory). If the directory # isn't empty, then fail. This will be reported as a warning # later. if [ -d $DESTDIR/$1 ]; then if empty_destdir $1; then log "rmdir ${DESTDIR}$1" if [ -z "$dryrun" ]; then rmdir ${DESTDIR}$1 >&3 2>&1 fi else return 1 fi # If both the old and new files are regular files, leave the # existing file. This avoids breaking hard links for /.cshrc # and /.profile. Otherwise, explicitly remove the old file. elif ! [ -f ${DESTDIR}$1 -a -f ${NEWTREE}$1 ]; then log "rm -f ${DESTDIR}$1" if [ -z "$dryrun" ]; then rm -f ${DESTDIR}$1 >&3 2>&1 fi fi # If the new file is a directory, note that the old file has # been removed, but don't do anything else for now. The # directory will be installed if needed when new files within # that directory are installed. if [ -d $NEWTREE/$1 ]; then if empty_dir $NEWTREE/$1; then echo " D $file" else echo " U $file" fi elif install_new $1; then echo " U $file" fi return 0 } # Update the FreeBSD ID string in a locally modified file to match the # FreeBSD ID string from the "new" version of the file. # # $1 - pathname of the file to update (relative to DESTDIR) update_freebsdid() { local new dest file # If the FreeBSD ID string is removed from the local file, # there is nothing to do. In this case, treat the file as # updated. Otherwise, if either file has more than one # FreeBSD ID string, just punt and let the user handle the # conflict manually. new=`grep -c '\$FreeBSD.*\$' ${NEWTREE}$1` dest=`grep -c '\$FreeBSD.*\$' ${DESTDIR}$1` if [ "$dest" -eq 0 ]; then return 0 fi if [ "$dest" -ne 1 -o "$dest" -ne 1 ]; then return 1 fi # If the FreeBSD ID string in the new file matches the FreeBSD ID # string in the local file, there is nothing to do. new=`grep '\$FreeBSD.*\$' ${NEWTREE}$1` dest=`grep '\$FreeBSD.*\$' ${DESTDIR}$1` if [ "$new" = "$dest" ]; then return 0 fi # Build the new file in three passes. First, copy all the # lines preceding the FreeBSD ID string from the local version # of the file. Second, append the FreeBSD ID string line from # the new version. Finally, append all the lines after the # FreeBSD ID string from the local version of the file. file=`mktemp $WORKDIR/etcupdate-XXXXXXX` awk '/\$FreeBSD.*\$/ { exit } { print }' ${DESTDIR}$1 >> $file awk '/\$FreeBSD.*\$/ { print }' ${NEWTREE}$1 >> $file awk '/\$FreeBSD.*\$/ { ok = 1; next } { if (ok) print }' \ ${DESTDIR}$1 >> $file # As an extra sanity check, fail the attempt if the updated # version of the file has any differences aside from the # FreeBSD ID string. if ! fbsdid_only ${DESTDIR}$1 $file; then rm -f $file return 1 fi log "cp $file ${DESTDIR}$1" if [ -z "$dryrun" ]; then cp $file ${DESTDIR}$1 >&3 2>&1 fi rm -f $file post_install_file $1 echo " M $1" return 0 } # Attempt to update a file that has local modifications. This routine # only handles regular files. If the 3-way merge succeeds without # conflicts, the updated file is installed. If the merge fails, the # merged version with conflict markers is left in the CONFLICTS tree. # # $1 - pathname of the file to merge (relative to DESTDIR) merge_file() { local res # Try the merge to see if there is a conflict. merge -q -p ${DESTDIR}$1 ${OLDTREE}$1 ${NEWTREE}$1 >/dev/null 2>&3 res=$? case $res in 0) # No conflicts, so just redo the merge to the # real file. log "merge ${DESTDIR}$1 ${OLDTREE}$1 ${NEWTREE}$1" if [ -z "$dryrun" ]; then merge ${DESTDIR}$1 ${OLDTREE}$1 ${NEWTREE}$1 fi post_install_file $1 echo " M $1" ;; 1) # Conflicts, save a version with conflict markers in # the conflicts directory. if [ -z "$dryrun" ]; then install_dirs $NEWTREE $CONFLICTS $1 log "cp -Rp ${DESTDIR}$1 ${CONFLICTS}$1" cp -Rp ${DESTDIR}$1 ${CONFLICTS}$1 >&3 2>&1 merge -A -q -L "yours" -L "original" -L "new" \ ${CONFLICTS}$1 ${OLDTREE}$1 ${NEWTREE}$1 fi echo " C $1" ;; *) panic "merge failed with status $res" ;; esac } # Returns true if a file contains conflict markers from a merge conflict. # # $1 - pathname of the file to resolve (relative to DESTDIR) has_conflicts() { egrep -q '^(<{7}|\|{7}|={7}|>{7}) ' $CONFLICTS/$1 } # Attempt to resolve a conflict. The user is prompted to choose an # action for each conflict. If the user edits the file, they are # prompted again for an action. The process is very similar to # resolving conflicts after an update or merge with Perforce or # Subversion. The prompts are modelled on a subset of the available # commands for resolving conflicts with Subversion. # # $1 - pathname of the file to resolve (relative to DESTDIR) resolve_conflict() { local command junk echo "Resolving conflict in '$1':" edit= while true; do # Only display the resolved command if the file # doesn't contain any conflicts. echo -n "Select: (p) postpone, (df) diff-full, (e) edit," if ! has_conflicts $1; then echo -n " (r) resolved," fi echo echo -n " (h) help for more options: " read command case $command in df) diff -u ${DESTDIR}$1 ${CONFLICTS}$1 ;; e) $EDITOR ${CONFLICTS}$1 ;; h) cat </dev/null 2>&1 fi echo " D $dir" else warn "Non-empty directory remains: $dir" fi fi } # Handle a file that exists in both the old and new trees. If the # file has not changed in the old and new trees, there is nothing to # do. If the file in the destination directory matches the new file, # there is nothing to do. If the file in the destination directory # matches the old file, then the new file should be installed. # Everything else becomes some sort of conflict with more detailed # handling. # # $1 - pathname of the file (relative to DESTDIR) handle_modified_file() { local cmp dest file new newdestcmp old file=$1 if ignore $file; then log "IGNORE: modified file $file" return fi compare $OLDTREE/$file $NEWTREE/$file cmp=$? if [ $cmp -eq $COMPARE_EQUAL ]; then return fi if [ $cmp -eq $COMPARE_ONLYFIRST -o $cmp -eq $COMPARE_ONLYSECOND ]; then panic "Changed file now missing" fi compare $NEWTREE/$file $DESTDIR/$file newdestcmp=$? if [ $newdestcmp -eq $COMPARE_EQUAL ]; then return fi # If the only change in the new file versus the destination # file is a change in the FreeBSD ID string and -F is # specified, just install the new file. if [ -n "$FREEBSD_ID" -a $newdestcmp -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $NEWTREE/$file $DESTDIR/$file; then if update_unmodified $file; then return else panic "Updating FreeBSD ID string failed" fi fi # If the local file is the same as the old file, install the # new file. If -F is specified and the only local change is # in the FreeBSD ID string, then install the new file as well. if compare_fbsdid $OLDTREE/$file $DESTDIR/$file; then if update_unmodified $file; then return fi fi # If the file was removed from the dest tree, just whine. if [ $newdestcmp -eq $COMPARE_ONLYFIRST ]; then # If the removed file matches an ALWAYS_INSTALL glob, # then just install the new version of the file. if always_install $file; then log "ALWAYS: adding $file" if ! [ -d $NEWTREE/$file ]; then if install_new $file; then echo " A $file" fi fi return fi # If the only change in the new file versus the old # file is a change in the FreeBSD ID string and -F is # specified, don't warn. if [ -n "$FREEBSD_ID" -a $cmp -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $OLDTREE/$file $NEWTREE/$file; then return fi case $cmp in $COMPARE_DIFFTYPE) old=`file_type $OLDTREE/$file` new=`file_type $NEWTREE/$file` warn "Remove mismatch: $file ($old became $new)" ;; $COMPARE_DIFFLINKS) old=`readlink $OLDTREE/$file` new=`readlink $NEWTREE/$file` warn \ "Removed link changed: $file (\"$old\" became \"$new\")" ;; $COMPARE_DIFFFILES) warn "Removed file changed: $file" ;; esac return fi # Treat the file as unmodified and force install of the new # file if it matches an ALWAYS_INSTALL glob. If the update # attempt fails, then fall through to the normal case so a # warning is generated. if always_install $file; then log "ALWAYS: updating $file" if update_unmodified $file; then return fi fi # If the only change in the new file versus the old file is a # change in the FreeBSD ID string and -F is specified, just # update the FreeBSD ID string in the local file. if [ -n "$FREEBSD_ID" -a $cmp -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $OLDTREE/$file $NEWTREE/$file; then if update_freebsdid $file; then continue fi fi # If the file changed types between the old and new trees but # the files in the new and dest tree are both of the same # type, treat it like an added file just comparing the new and # dest files. if [ $cmp -eq $COMPARE_DIFFTYPE ]; then case $newdestcmp in $COMPARE_DIFFLINKS) new=`readlink $NEWTREE/$file` dest=`readlink $DESTDIR/$file` warn \ "New link conflict: $file (\"$new\" vs \"$dest\")" return ;; $COMPARE_DIFFFILES) new_conflict $file echo " C $file" return ;; esac else # If the file has not changed types between the old # and new trees, but it is a different type in # DESTDIR, then just warn. if [ $newdestcmp -eq $COMPARE_DIFFTYPE ]; then new=`file_type $NEWTREE/$file` dest=`file_type $DESTDIR/$file` warn "Modified mismatch: $file ($new vs $dest)" return fi fi case $cmp in $COMPARE_DIFFTYPE) old=`file_type $OLDTREE/$file` new=`file_type $NEWTREE/$file` dest=`file_type $DESTDIR/$file` warn "Modified $dest changed: $file ($old became $new)" ;; $COMPARE_DIFFLINKS) old=`readlink $OLDTREE/$file` new=`readlink $NEWTREE/$file` warn \ "Modified link changed: $file (\"$old\" became \"$new\")" ;; $COMPARE_DIFFFILES) merge_file $file ;; esac } # Handle a file that has been added in the new tree. If the file does # not exist in DESTDIR, simply copy the file into DESTDIR. If the # file exists in the DESTDIR and is identical to the new version, do # nothing. Otherwise, generate a diff of the two versions of the file # and mark it as a conflict. # # $1 - pathname of the file (relative to DESTDIR) handle_added_file() { local cmp dest file new file=$1 if ignore $file; then log "IGNORE: added file $file" return fi compare $DESTDIR/$file $NEWTREE/$file cmp=$? case $cmp in $COMPARE_EQUAL) return ;; $COMPARE_ONLYFIRST) panic "Added file now missing" ;; $COMPARE_ONLYSECOND) # Ignore new directories. They will be # created as needed when non-directory nodes # are installed. if ! [ -d $NEWTREE/$file ]; then if install_new $file; then echo " A $file" fi fi return ;; esac # Treat the file as unmodified and force install of the new # file if it matches an ALWAYS_INSTALL glob. If the update # attempt fails, then fall through to the normal case so a # warning is generated. if always_install $file; then log "ALWAYS: updating $file" if update_unmodified $file; then return fi fi case $cmp in $COMPARE_DIFFTYPE) new=`file_type $NEWTREE/$file` dest=`file_type $DESTDIR/$file` warn "New file mismatch: $file ($new vs $dest)" ;; $COMPARE_DIFFLINKS) new=`readlink $NEWTREE/$file` dest=`readlink $DESTDIR/$file` warn "New link conflict: $file (\"$new\" vs \"$dest\")" ;; $COMPARE_DIFFFILES) # If the only change in the new file versus # the destination file is a change in the # FreeBSD ID string and -F is specified, just # install the new file. if [ -n "$FREEBSD_ID" ] && \ fbsdid_only $NEWTREE/$file $DESTDIR/$file; then if update_unmodified $file; then return else panic \ "Updating FreeBSD ID string failed" fi fi new_conflict $file echo " C $file" ;; esac } # Main routines for each command # Build a new tree and save it in a tarball. build_cmd() { local dir if [ $# -ne 1 ]; then echo "Missing required tarball." echo usage fi log "build command: $1" # Create a temporary directory to hold the tree dir=`mktemp -d $WORKDIR/etcupdate-XXXXXXX` if [ $? -ne 0 ]; then echo "Unable to create temporary directory." exit 1 fi if ! build_tree $dir; then echo "Failed to build tree." remove_tree $dir exit 1 fi if ! tar cfj $1 -C $dir . >&3 2>&1; then echo "Failed to create tarball." remove_tree $dir exit 1 fi remove_tree $dir } # Output a diff comparing the tree at DESTDIR to the current # unmodified tree. Note that this diff does not include files that # are present in DESTDIR but not in the unmodified tree. diff_cmd() { local file if [ $# -ne 0 ]; then usage fi # Requires an unmodified tree to diff against. if ! [ -d $NEWTREE ]; then echo "Reference tree to diff against unavailable." exit 1 fi # Unfortunately, diff alone does not quite provide the right # level of options that we want, so improvise. for file in `(cd $NEWTREE; find .) | sed -e 's/^\.//'`; do if ignore $file; then continue fi diffnode $NEWTREE "$DESTDIR" $file "stock" "local" done } # Just extract a new tree into NEWTREE either by building a tree or # extracting a tarball. This can be used to bootstrap updates by # initializing the current "stock" tree to match the currently # installed system. # # Unlike 'update', this command does not rotate or preserve an # existing NEWTREE, it just replaces any existing tree. extract_cmd() { if [ $# -ne 0 ]; then usage fi log "extract command: tarball=$tarball" if [ -d $NEWTREE ]; then if ! remove_tree $NEWTREE; then echo "Unable to remove current tree." exit 1 fi fi extract_tree } # Resolve conflicts left from an earlier merge. resolve_cmd() { local conflicts if [ $# -ne 0 ]; then usage fi if ! [ -d $CONFLICTS ]; then return fi if ! [ -d $NEWTREE ]; then echo "The current tree is not present to resolve conflicts." exit 1 fi conflicts=`(cd $CONFLICTS; find . ! -type d) | sed -e 's/^\.//'` for file in $conflicts; do resolve_conflict $file done if [ -n "$NEWALIAS_WARN" ]; then warn "Needs update: /etc/mail/aliases.db" \ "(requires manual update via newaliases(1))" echo echo "Warnings:" echo " Needs update: /etc/mail/aliases.db" \ "(requires manual update via newaliases(1))" fi } # Report a summary of the previous merge. Specifically, list any # remaining conflicts followed by any warnings from the previous # update. status_cmd() { if [ $# -ne 0 ]; then usage fi if [ -d $CONFLICTS ]; then (cd $CONFLICTS; find . ! -type d) | sed -e 's/^\./ C /' fi if [ -s $WARNINGS ]; then echo "Warnings:" cat $WARNINGS fi } # Perform an actual merge. The new tree can either already exist (if # rerunning a merge), be extracted from a tarball, or generated from a # source tree. update_cmd() { local dir if [ $# -ne 0 ]; then usage fi log "update command: rerun=$rerun tarball=$tarball preworld=$preworld" if [ `id -u` -ne 0 ]; then echo "Must be root to update a tree." exit 1 fi # Enforce a sane umask umask 022 # XXX: Should existing conflicts be ignored and removed during # a rerun? # Trim the conflicts tree. Whine if there is anything left. if [ -e $CONFLICTS ]; then find -d $CONFLICTS -type d -empty -delete >&3 2>&1 rmdir $CONFLICTS >&3 2>&1 fi if [ -d $CONFLICTS ]; then echo "Conflicts remain from previous update, aborting." exit 1 fi if [ -z "$rerun" ]; then # For a dryrun that is not a rerun, do not rotate the existing # stock tree. Instead, extract a tree to a temporary directory # and use that for the comparison. if [ -n "$dryrun" ]; then dir=`mktemp -d $WORKDIR/etcupdate-XXXXXXX` if [ $? -ne 0 ]; then echo "Unable to create temporary directory." exit 1 fi # A pre-world dryrun has already set OLDTREE to # point to the current stock tree. if [ -z "$preworld" ]; then OLDTREE=$NEWTREE fi NEWTREE=$dir # For a pre-world update, blow away any pre-existing # NEWTREE. elif [ -n "$preworld" ]; then if ! remove_tree $NEWTREE; then echo "Unable to remove pre-world tree." exit 1 fi # Rotate the existing stock tree to the old tree. elif [ -d $NEWTREE ]; then # First, delete the previous old tree if it exists. if ! remove_tree $OLDTREE; then echo "Unable to remove old tree." exit 1 fi # Move the current stock tree. if ! mv $NEWTREE $OLDTREE >&3 2>&1; then echo "Unable to rename current stock tree." exit 1 fi fi if ! [ -d $OLDTREE ]; then cat < $WORKDIR/old.files (cd $NEWTREE; find .) | sed -e 's/^\.//' | sort > $WORKDIR/new.files # Split the files up into three groups using comm. comm -23 $WORKDIR/old.files $WORKDIR/new.files > $WORKDIR/removed.files comm -13 $WORKDIR/old.files $WORKDIR/new.files > $WORKDIR/added.files comm -12 $WORKDIR/old.files $WORKDIR/new.files > $WORKDIR/both.files # Initialize conflicts and warnings handling. rm -f $WARNINGS mkdir -p $CONFLICTS # Ignore removed files for the pre-world case. A pre-world # update uses a stripped-down tree. if [ -n "$preworld" ]; then > $WORKDIR/removed.files fi # The order for the following sections is important. In the # odd case that a directory is converted into a file, the # existing subfiles need to be removed if possible before the # file is converted. Similarly, in the case that a file is # converted into a directory, the file needs to be converted # into a directory if possible before the new files are added. # First, handle removed files. for file in `cat $WORKDIR/removed.files`; do handle_removed_file $file done # For the directory pass, reverse sort the list to effect a # depth-first traversal. This is needed to ensure that if a # directory with subdirectories is removed, the entire # directory is removed if there are no local modifications. for file in `sort -r $WORKDIR/removed.files`; do handle_removed_directory $file done # Second, handle files that exist in both the old and new # trees. for file in `cat $WORKDIR/both.files`; do handle_modified_file $file done # Finally, handle newly added files. for file in `cat $WORKDIR/added.files`; do handle_added_file $file done if [ -n "$NEWALIAS_WARN" ]; then warn "Needs update: /etc/mail/aliases.db" \ "(requires manual update via newaliases(1))" fi # Run any special one-off commands after an update has completed. post_update if [ -s $WARNINGS ]; then echo "Warnings:" cat $WARNINGS fi if [ -n "$dir" ]; then if [ -z "$dryrun" -o -n "$rerun" ]; then panic "Should not have a temporary directory" fi remove_tree $dir fi } # Determine which command we are executing. A command may be # specified as the first word. If one is not specified then 'update' # is assumed as the default command. command="update" if [ $# -gt 0 ]; then case "$1" in build|diff|extract|status|resolve) command="$1" shift ;; -*) # If first arg is an option, assume the # default command. ;; *) usage ;; esac fi # Set default variable values. # The path to the source tree used to build trees. SRCDIR=/usr/src # The destination directory where the modified files live. DESTDIR= # Ignore changes in the FreeBSD ID string. FREEBSD_ID= # Files that should always have the new version of the file installed. ALWAYS_INSTALL= # Files to ignore and never update during a merge. IGNORE_FILES= # Flags to pass to 'make' when building a tree. MAKE_OPTIONS= # Include a config file if it exists. Note that command line options # override any settings in the config file. More details are in the # manual, but in general the following variables can be set: # - ALWAYS_INSTALL # - DESTDIR # - EDITOR # - FREEBSD_ID # - IGNORE_FILES # - LOGFILE # - MAKE_OPTIONS # - SRCDIR # - WORKDIR if [ -r /etc/etcupdate.conf ]; then . /etc/etcupdate.conf fi # Parse command line options tarball= rerun= always= dryrun= ignore= nobuild= preworld= while getopts "d:nprs:t:A:BD:FI:L:M:" option; do case "$option" in d) WORKDIR=$OPTARG ;; n) dryrun=YES ;; p) preworld=YES ;; r) rerun=YES ;; s) SRCDIR=$OPTARG ;; t) tarball=$OPTARG ;; A) # To allow this option to be specified # multiple times, accumulate command-line # specified patterns in an 'always' variable # and use that to overwrite ALWAYS_INSTALL # after parsing all options. Need to be # careful here with globbing expansion. set -o noglob always="$always $OPTARG" set +o noglob ;; B) nobuild=YES ;; D) DESTDIR=$OPTARG ;; F) FREEBSD_ID=YES ;; I) # To allow this option to be specified # multiple times, accumulate command-line # specified patterns in an 'ignore' variable # and use that to overwrite IGNORE_FILES after # parsing all options. Need to be careful # here with globbing expansion. set -o noglob ignore="$ignore $OPTARG" set +o noglob ;; L) LOGFILE=$OPTARG ;; M) MAKE_OPTIONS="$OPTARG" ;; *) echo usage ;; esac done shift $((OPTIND - 1)) # Allow -A command line options to override ALWAYS_INSTALL set from # the config file. set -o noglob if [ -n "$always" ]; then ALWAYS_INSTALL="$always" fi # Allow -I command line options to override IGNORE_FILES set from the # config file. if [ -n "$ignore" ]; then IGNORE_FILES="$ignore" fi set +o noglob # Where the "old" and "new" trees are stored. WORKDIR=${WORKDIR:-$DESTDIR/var/db/etcupdate} # Log file for verbose output from program that are run. The log file # is opened on fd '3'. LOGFILE=${LOGFILE:-$WORKDIR/log} # The path of the "old" tree OLDTREE=$WORKDIR/old # The path of the "new" tree NEWTREE=$WORKDIR/current # The path of the "conflicts" tree where files with merge conflicts are saved. CONFLICTS=$WORKDIR/conflicts # The path of the "warnings" file that accumulates warning notes from an update. WARNINGS=$WORKDIR/warnings # Use $EDITOR for resolving conflicts. If it is not set, default to vi. EDITOR=${EDITOR:-/usr/bin/vi} # Files that need to be updated before installworld. PREWORLD_FILES="etc/master.passwd etc/group" # Handle command-specific argument processing such as complaining # about unsupported options. Since the configuration file is always # included, do not complain about extra command line arguments that # may have been set via the config file rather than the command line. case $command in update) if [ -n "$rerun" -a -n "$tarball" ]; then echo "Only one of -r or -t can be specified." echo usage fi if [ -n "$rerun" -a -n "$preworld" ]; then echo "Only one of -p or -r can be specified." echo usage fi ;; build|diff|status) if [ -n "$dryrun" -o -n "$rerun" -o -n "$tarball" -o \ -n "$preworld" ]; then usage fi ;; resolve) if [ -n "$dryrun" -o -n "$rerun" -o -n "$tarball" ]; then usage fi ;; extract) if [ -n "$dryrun" -o -n "$rerun" -o -n "$preworld" ]; then usage fi ;; esac # Pre-world mode uses a different set of trees. It leaves the current # tree as-is so it is still present for a full etcupdate run after the # world install is complete. Instead, it installs a few critical files # into a separate tree. if [ -n "$preworld" ]; then OLDTREE=$NEWTREE NEWTREE=$WORKDIR/preworld fi # Open the log file. Don't truncate it if doing a minor operation so # that a minor operation doesn't lose log info from a major operation. if ! mkdir -p $WORKDIR 2>/dev/null; then echo "Failed to create work directory $WORKDIR" fi case $command in diff|resolve|status) exec 3>>$LOGFILE ;; *) exec 3>$LOGFILE ;; esac ${command}_cmd "$@" Index: stable/8/usr.sbin/etcupdate =================================================================== --- stable/8/usr.sbin/etcupdate (revision 283926) +++ stable/8/usr.sbin/etcupdate (revision 283927) Property changes on: stable/8/usr.sbin/etcupdate ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/usr.sbin/etcupdate:r281887 Index: stable/8/usr.sbin/pciconf/err.c =================================================================== --- stable/8/usr.sbin/pciconf/err.c (revision 283926) +++ stable/8/usr.sbin/pciconf/err.c (revision 283927) @@ -1,173 +1,173 @@ /*- - * Copyright (c) 2012 Advanced Computing Technologies LLC + * Copyright (c) 2012 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include "pciconf.h" struct bit_table { uint32_t mask; const char *desc; }; /* Error indicators in the PCI status register (PCIR_STATUS). */ static struct bit_table pci_status[] = { { PCIM_STATUS_MDPERR, "Master Data Parity Error" }, { PCIM_STATUS_STABORT, "Sent Target-Abort" }, { PCIM_STATUS_RTABORT, "Received Target-Abort" }, { PCIM_STATUS_RMABORT, "Received Master-Abort" }, { PCIM_STATUS_SERR, "Signalled System Error" }, { PCIM_STATUS_PERR, "Detected Parity Error" }, { 0, NULL }, }; /* Valid error indicator bits in PCIR_STATUS. */ #define PCI_ERRORS (PCIM_STATUS_MDPERR | PCIM_STATUS_STABORT | \ PCIM_STATUS_RTABORT | PCIM_STATUS_RMABORT | \ PCIM_STATUS_SERR | PCIM_STATUS_PERR) /* Error indicators in the PCI-Express device status register. */ static struct bit_table pcie_device_status[] = { { PCIEM_STA_CORRECTABLE_ERROR, "Correctable Error Detected" }, { PCIEM_STA_NON_FATAL_ERROR, "Non-Fatal Error Detected" }, { PCIEM_STA_FATAL_ERROR, "Fatal Error Detected" }, { PCIEM_STA_UNSUPPORTED_REQ, "Unsupported Request Detected" }, { 0, NULL }, }; /* Valid error indicator bits in the PCI-Express device status register. */ #define PCIE_ERRORS (PCIEM_STA_CORRECTABLE_ERROR | \ PCIEM_STA_NON_FATAL_ERROR | \ PCIEM_STA_FATAL_ERROR | \ PCIEM_STA_UNSUPPORTED_REQ) /* AER Uncorrected errors. */ static struct bit_table aer_uc[] = { { PCIM_AER_UC_TRAINING_ERROR, "Link Training Error" }, { PCIM_AER_UC_DL_PROTOCOL_ERROR, "Data Link Protocol Error" }, { PCIM_AER_UC_SURPRISE_LINK_DOWN, "Surprise Link Down Error" }, { PCIM_AER_UC_POISONED_TLP, "Poisoned TLP" }, { PCIM_AER_UC_FC_PROTOCOL_ERROR, "Flow Control Protocol Error" }, { PCIM_AER_UC_COMPLETION_TIMEOUT, "Completion Timeout" }, { PCIM_AER_UC_COMPLETER_ABORT, "Completer Abort" }, { PCIM_AER_UC_UNEXPECTED_COMPLETION, "Unexpected Completion" }, { PCIM_AER_UC_RECEIVER_OVERFLOW, "Receiver Overflow Error" }, { PCIM_AER_UC_MALFORMED_TLP, "Malformed TLP" }, { PCIM_AER_UC_ECRC_ERROR, "ECRC Error" }, { PCIM_AER_UC_UNSUPPORTED_REQUEST, "Unsupported Request" }, { PCIM_AER_UC_ACS_VIOLATION, "ACS Violation" }, { PCIM_AER_UC_INTERNAL_ERROR, "Uncorrectable Internal Error" }, { PCIM_AER_UC_MC_BLOCKED_TLP, "MC Blocked TLP" }, { PCIM_AER_UC_ATOMIC_EGRESS_BLK, "AtomicOp Egress Blocked" }, { PCIM_AER_UC_TLP_PREFIX_BLOCKED, "TLP Prefix Blocked Error" }, { 0, NULL }, }; /* AER Corrected errors. */ static struct bit_table aer_cor[] = { { PCIM_AER_COR_RECEIVER_ERROR, "Receiver Error" }, { PCIM_AER_COR_BAD_TLP, "Bad TLP" }, { PCIM_AER_COR_BAD_DLLP, "Bad DLLP" }, { PCIM_AER_COR_REPLAY_ROLLOVER, "REPLAY_NUM Rollover" }, { PCIM_AER_COR_REPLAY_TIMEOUT, "Replay Timer Timeout" }, { PCIM_AER_COR_ADVISORY_NF_ERROR, "Advisory Non-Fatal Error" }, { PCIM_AER_COR_INTERNAL_ERROR, "Corrected Internal Error" }, { PCIM_AER_COR_HEADER_LOG_OVFLOW, "Header Log Overflow" }, { 0, NULL }, }; static void print_bits(const char *header, struct bit_table *table, uint32_t mask) { int first; first = 1; for (; table->desc != NULL; table++) if (mask & table->mask) { if (first) { printf("%14s = ", header); first = 0; } else printf(" "); printf("%s\n", table->desc); mask &= ~table->mask; } if (mask != 0) { if (first) printf("%14s = ", header); else printf(" "); printf("Unknown: 0x%08x\n", mask); } } void list_errors(int fd, struct pci_conf *p) { uint32_t mask, severity; uint16_t sta, aer; uint8_t pcie; /* First check for standard PCI errors. */ sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); print_bits("PCI errors", pci_status, sta & PCI_ERRORS); /* See if this is a PCI-express device. */ pcie = pci_find_cap(fd, p, PCIY_EXPRESS); if (pcie == 0) return; /* Check for PCI-e errors. */ sta = read_config(fd, &p->pc_sel, pcie + PCIER_DEVICE_STA, 2); print_bits("PCI-e errors", pcie_device_status, sta & PCIE_ERRORS); /* See if this device supports AER. */ aer = pcie_find_cap(fd, p, PCIZ_AER); if (aer == 0) return; /* Check for uncorrected errors. */ mask = read_config(fd, &p->pc_sel, aer + PCIR_AER_UC_STATUS, 4); severity = read_config(fd, &p->pc_sel, aer + PCIR_AER_UC_SEVERITY, 4); print_bits("Fatal", aer_uc, mask & severity); print_bits("Non-fatal", aer_uc, mask & ~severity); /* Check for corrected errors. */ mask = read_config(fd, &p->pc_sel, aer + PCIR_AER_COR_STATUS, 4); print_bits("Corrected", aer_cor, mask); } Index: stable/8/usr.sbin/pciconf =================================================================== --- stable/8/usr.sbin/pciconf (revision 283926) +++ stable/8/usr.sbin/pciconf (revision 283927) Property changes on: stable/8/usr.sbin/pciconf ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/usr.sbin/pciconf:r281887 Index: stable/9/lib/libc/gen/_once_stub.c =================================================================== --- stable/9/lib/libc/gen/_once_stub.c (revision 283926) +++ stable/9/lib/libc/gen/_once_stub.c (revision 283927) @@ -1,64 +1,64 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include "un-namespace.h" #include "libc_private.h" /* This implements pthread_once() for the single-threaded case. */ static int _libc_once(pthread_once_t *once_control, void (*init_routine)(void)) { if (once_control->state == PTHREAD_DONE_INIT) return (0); init_routine(); once_control->state = PTHREAD_DONE_INIT; return (0); } /* * This is the internal interface provided to libc. It will use * pthread_once() from the threading library in a multi-threaded * process and _libc_once() for a single-threaded library. Because * _libc_once() uses the same ABI for the values in the pthread_once_t * structure as the threading library, it is safe for a process to * switch from _libc_once() to pthread_once() when threading is * enabled. */ int _once(pthread_once_t *once_control, void (*init_routine)(void)) { if (__isthreaded) return (_pthread_once(once_control, init_routine)); return (_libc_once(once_control, init_routine)); } Index: stable/9/lib/libc/include/compat.h =================================================================== --- stable/9/lib/libc/include/compat.h (revision 283926) +++ stable/9/lib/libc/include/compat.h (revision 283927) @@ -1,48 +1,48 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ /* * This file defines compatiblity symbol versions for old system calls. It * is included in all generated system call files. */ #ifndef __LIBC_COMPAT_H__ #define __LIBC_COMPAT_H__ #define __sym_compat(sym,impl,verid) \ .symver impl, sym@verid __sym_compat(__semctl, freebsd7___semctl, FBSD_1.0); __sym_compat(msgctl, freebsd7_msgctl, FBSD_1.0); __sym_compat(shmctl, freebsd7_shmctl, FBSD_1.0); #undef __sym_compat #endif /* __LIBC_COMPAT_H__ */ Index: stable/9/lib/libc/stdio/open_memstream.3 =================================================================== --- stable/9/lib/libc/stdio/open_memstream.3 (revision 283926) +++ stable/9/lib/libc/stdio/open_memstream.3 (revision 283927) @@ -1,155 +1,155 @@ -.\" Copyright (c) 2013 Advanced Computing Technologies LLC +.\" Copyright (c) 2013 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 28, 2014 .Dt OPEN_MEMSTREAM 3 .Os .Sh NAME .Nm open_memstream , .Nm open_wmemstream .Nd dynamic memory buffer stream open functions .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In stdio.h .Ft FILE * .Fn open_memstream "char **bufp" "size_t *sizep" .In wchar.h .Ft FILE * .Fn open_wmemstream "wchar_t **bufp" "size_t *sizep" .Sh DESCRIPTION The .Fn open_memstream and .Fn open_wmemstream functions create a write-only, seekable stream backed by a dynamically allocated memory buffer. The .Fn open_memstream function creates a byte-oriented stream, while the .Fn open_wmemstream function creates a wide-oriented stream. .Pp Each stream maintains a current position and size. Initially, the position and size are set to zero. Each write begins at the current position and advances it the number of successfully written bytes for .Fn open_memstream or wide characters for .Fn open_wmemstream . If a write moves the current position beyond the length of the buffer, the length of the buffer is extended and a null character is appended to the buffer. .Pp A stream's buffer always contains a null character at the end of the buffer that is not included in the current length. .Pp If a stream's current position is moved beyond the current length via a seek operation and a write is performed, the characters between the current length and the current position are filled with null characters before the write is performed. .Pp After a successful call to .Xr fclose 3 or .Xr fflush 3 , the pointer referenced by .Fa bufp will contain the start of the memory buffer and the variable referenced by .Fa sizep will contain the smaller of the current position and the current buffer length. .Pp After a successful call to .Xr fflush 3, the pointer referenced by .Fa bufp and the variable referenced by .Fa sizep are only valid until the next write operation or a call to .Xr fclose 3. .Pp Once a stream is closed, the allocated buffer referenced by .Fa bufp should be released via a call to .Xr free 3 when it is no longer needed. .Sh IMPLEMENTATION NOTES Internally all I/O streams are effectively byte-oriented, so using wide-oriented operations to write to a stream opened via .Fn open_wmemstream results in wide characters being expanded to a stream of multibyte characters in stdio's internal buffers. These multibyte characters are then converted back to wide characters when written into the stream. As a result, the wide-oriented streams maintain an internal multibyte character conversion state that is cleared on any seek opertion that changes the current position. This should have no effect as long as wide-oriented output operations are used on a wide-oriented stream. .Sh RETURN VALUES Upon successful completion, .Fn open_memstream and .Fn open_wmemstream return a .Tn FILE pointer. Otherwise, .Dv NULL is returned and the global variable .Va errno is set to indicate the error. .Sh ERRORS .Bl -tag -width Er .It Bq Er EINVAL The .Fa bufp or .Fa sizep argument was .Dv NULL . .It Bq Er ENOMEM Memory for the stream or buffer could not be allocated. .El .Sh SEE ALSO .Xr fclose 3 , .Xr fflush 3 , .Xr fopen 3 , .Xr free 3 , .Xr fseek 3 , .Xr sbuf 3 , .Xr stdio 3 .Sh STANDARDS The .Fn open_memstream and .Fn open_wmemstream functions conform to .St -p1003.1-2008 . Property changes on: stable/9/lib/libc/stdio/open_memstream.3 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/lib/libc/stdio/open_memstream.3:r281887 Index: stable/9/lib/libc/stdio/open_memstream.c =================================================================== --- stable/9/lib/libc/stdio/open_memstream.c (revision 283926) +++ stable/9/lib/libc/stdio/open_memstream.c (revision 283927) @@ -1,209 +1,209 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include #include #include #include #include #include "un-namespace.h" /* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */ #define FPOS_MAX OFF_MAX struct memstream { char **bufp; size_t *sizep; ssize_t len; fpos_t offset; }; static int memstream_grow(struct memstream *ms, fpos_t newoff) { char *buf; ssize_t newsize; if (newoff < 0 || newoff >= SSIZE_MAX) newsize = SSIZE_MAX - 1; else newsize = newoff; if (newsize > ms->len) { buf = realloc(*ms->bufp, newsize + 1); if (buf != NULL) { #ifdef DEBUG fprintf(stderr, "MS: %p growing from %zd to %zd\n", ms, ms->len, newsize); #endif memset(buf + ms->len + 1, 0, newsize - ms->len); *ms->bufp = buf; ms->len = newsize; return (1); } return (0); } return (1); } static void memstream_update(struct memstream *ms) { assert(ms->len >= 0 && ms->offset >= 0); *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset; } static int memstream_write(void *cookie, const char *buf, int len) { struct memstream *ms; ssize_t tocopy; ms = cookie; if (!memstream_grow(ms, ms->offset + len)) return (-1); tocopy = ms->len - ms->offset; if (len < tocopy) tocopy = len; memcpy(*ms->bufp + ms->offset, buf, tocopy); ms->offset += tocopy; memstream_update(ms); #ifdef DEBUG fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, tocopy); #endif return (tocopy); } static fpos_t memstream_seek(void *cookie, fpos_t pos, int whence) { struct memstream *ms; #ifdef DEBUG fpos_t old; #endif ms = cookie; #ifdef DEBUG old = ms->offset; #endif switch (whence) { case SEEK_SET: /* _fseeko() checks for negative offsets. */ assert(pos >= 0); ms->offset = pos; break; case SEEK_CUR: /* This is only called by _ftello(). */ assert(pos == 0); break; case SEEK_END: if (pos < 0) { if (pos + ms->len < 0) { #ifdef DEBUG fprintf(stderr, "MS: bad SEEK_END: pos %jd, len %zd\n", (intmax_t)pos, ms->len); #endif errno = EINVAL; return (-1); } } else { if (FPOS_MAX - ms->len < pos) { #ifdef DEBUG fprintf(stderr, "MS: bad SEEK_END: pos %jd, len %zd\n", (intmax_t)pos, ms->len); #endif errno = EOVERFLOW; return (-1); } } ms->offset = ms->len + pos; break; } memstream_update(ms); #ifdef DEBUG fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos, whence, (intmax_t)old, (intmax_t)ms->offset); #endif return (ms->offset); } static int memstream_close(void *cookie) { free(cookie); return (0); } FILE * open_memstream(char **bufp, size_t *sizep) { struct memstream *ms; int save_errno; FILE *fp; if (bufp == NULL || sizep == NULL) { errno = EINVAL; return (NULL); } *bufp = calloc(1, 1); if (*bufp == NULL) return (NULL); ms = malloc(sizeof(*ms)); if (ms == NULL) { save_errno = errno; free(*bufp); *bufp = NULL; errno = save_errno; return (NULL); } ms->bufp = bufp; ms->sizep = sizep; ms->len = 0; ms->offset = 0; memstream_update(ms); fp = funopen(ms, NULL, memstream_write, memstream_seek, memstream_close); if (fp == NULL) { save_errno = errno; free(ms); free(*bufp); *bufp = NULL; errno = save_errno; return (NULL); } fwide(fp, -1); return (fp); } Index: stable/9/lib/libc/stdio/open_wmemstream.c =================================================================== --- stable/9/lib/libc/stdio/open_wmemstream.c (revision 283926) +++ stable/9/lib/libc/stdio/open_wmemstream.c (revision 283927) @@ -1,271 +1,271 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include #include #include #include #include #include "un-namespace.h" /* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */ #define FPOS_MAX OFF_MAX struct wmemstream { wchar_t **bufp; size_t *sizep; ssize_t len; fpos_t offset; mbstate_t mbstate; }; static int wmemstream_grow(struct wmemstream *ms, fpos_t newoff) { wchar_t *buf; ssize_t newsize; if (newoff < 0 || newoff >= SSIZE_MAX / sizeof(wchar_t)) newsize = SSIZE_MAX / sizeof(wchar_t) - 1; else newsize = newoff; if (newsize > ms->len) { buf = realloc(*ms->bufp, (newsize + 1) * sizeof(wchar_t)); if (buf != NULL) { #ifdef DEBUG fprintf(stderr, "WMS: %p growing from %zd to %zd\n", ms, ms->len, newsize); #endif wmemset(buf + ms->len + 1, 0, newsize - ms->len); *ms->bufp = buf; ms->len = newsize; return (1); } return (0); } return (1); } static void wmemstream_update(struct wmemstream *ms) { assert(ms->len >= 0 && ms->offset >= 0); *ms->sizep = ms->len < ms->offset ? ms->len : ms->offset; } /* * Based on a starting multibyte state and an input buffer, determine * how many wchar_t's would be output. This doesn't use mbsnrtowcs() * so that it can handle embedded null characters. */ static size_t wbuflen(const mbstate_t *state, const char *buf, int len) { mbstate_t lenstate; size_t charlen, count; count = 0; lenstate = *state; while (len > 0) { charlen = mbrlen(buf, len, &lenstate); if (charlen == (size_t)-1) return (-1); if (charlen == (size_t)-2) break; if (charlen == 0) /* XXX: Not sure how else to handle this. */ charlen = 1; len -= charlen; buf += charlen; count++; } return (count); } static int wmemstream_write(void *cookie, const char *buf, int len) { struct wmemstream *ms; ssize_t consumed, wlen; size_t charlen; ms = cookie; wlen = wbuflen(&ms->mbstate, buf, len); if (wlen < 0) { errno = EILSEQ; return (-1); } if (!wmemstream_grow(ms, ms->offset + wlen)) return (-1); /* * This copies characters one at a time rather than using * mbsnrtowcs() so it can properly handle embedded null * characters. */ consumed = 0; while (len > 0 && ms->offset < ms->len) { charlen = mbrtowc(*ms->bufp + ms->offset, buf, len, &ms->mbstate); if (charlen == (size_t)-1) { if (consumed == 0) { errno = EILSEQ; return (-1); } /* Treat it as a successful short write. */ break; } if (charlen == 0) /* XXX: Not sure how else to handle this. */ charlen = 1; if (charlen == (size_t)-2) { consumed += len; len = 0; } else { consumed += charlen; buf += charlen; len -= charlen; ms->offset++; } } wmemstream_update(ms); #ifdef DEBUG fprintf(stderr, "WMS: write(%p, %d) = %zd\n", ms, len, consumed); #endif return (consumed); } static fpos_t wmemstream_seek(void *cookie, fpos_t pos, int whence) { struct wmemstream *ms; fpos_t old; ms = cookie; old = ms->offset; switch (whence) { case SEEK_SET: /* _fseeko() checks for negative offsets. */ assert(pos >= 0); ms->offset = pos; break; case SEEK_CUR: /* This is only called by _ftello(). */ assert(pos == 0); break; case SEEK_END: if (pos < 0) { if (pos + ms->len < 0) { #ifdef DEBUG fprintf(stderr, "WMS: bad SEEK_END: pos %jd, len %zd\n", (intmax_t)pos, ms->len); #endif errno = EINVAL; return (-1); } } else { if (FPOS_MAX - ms->len < pos) { #ifdef DEBUG fprintf(stderr, "WMS: bad SEEK_END: pos %jd, len %zd\n", (intmax_t)pos, ms->len); #endif errno = EOVERFLOW; return (-1); } } ms->offset = ms->len + pos; break; } /* Reset the multibyte state if a seek changes the position. */ if (ms->offset != old) memset(&ms->mbstate, 0, sizeof(ms->mbstate)); wmemstream_update(ms); #ifdef DEBUG fprintf(stderr, "WMS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos, whence, (intmax_t)old, (intmax_t)ms->offset); #endif return (ms->offset); } static int wmemstream_close(void *cookie) { free(cookie); return (0); } FILE * open_wmemstream(wchar_t **bufp, size_t *sizep) { struct wmemstream *ms; int save_errno; FILE *fp; if (bufp == NULL || sizep == NULL) { errno = EINVAL; return (NULL); } *bufp = calloc(1, sizeof(wchar_t)); if (*bufp == NULL) return (NULL); ms = malloc(sizeof(*ms)); if (ms == NULL) { save_errno = errno; free(*bufp); *bufp = NULL; errno = save_errno; return (NULL); } ms->bufp = bufp; ms->sizep = sizep; ms->len = 0; ms->offset = 0; memset(&ms->mbstate, 0, sizeof(mbstate_t)); wmemstream_update(ms); fp = funopen(ms, NULL, wmemstream_write, wmemstream_seek, wmemstream_close); if (fp == NULL) { save_errno = errno; free(ms); free(*bufp); *bufp = NULL; errno = save_errno; return (NULL); } fwide(fp, 1); return (fp); } Index: stable/9/lib/libc/sys/closefrom.2 =================================================================== --- stable/9/lib/libc/sys/closefrom.2 (revision 283926) +++ stable/9/lib/libc/sys/closefrom.2 (revision 283927) @@ -1,53 +1,53 @@ -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 12, 2009 .Dt CLOSEFROM 2 .Os .Sh NAME .Nm closefrom .Nd delete open file descriptors .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In unistd.h .Ft void .Fn closefrom "int lowfd" .Sh DESCRIPTION The .Fn closefrom system call deletes all open file descriptors greater than or equal to .Fa lowfd from the per-process object reference table. Any errors encountered while closing file descriptors are ignored. .Sh SEE ALSO .Xr close 2 .Sh HISTORY The .Fn closefrom function first appeared in .Fx 8.0 . Index: stable/9/lib/libc/sys/procctl.2 =================================================================== --- stable/9/lib/libc/sys/procctl.2 (revision 283926) +++ stable/9/lib/libc/sys/procctl.2 (revision 283927) @@ -1,142 +1,142 @@ -.\" Copyright (c) 2013 Advanced Computing Technologies LLC +.\" Copyright (c) 2013 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd September 19, 2013 .Dt PROCCTL 2 .Os .Sh NAME .Nm procctl .Nd control processes .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In sys/procctl.h .Ft int .Fn procctl "idtype_t idtype" "id_t id" "int cmd" "void *arg" .Sh DESCRIPTION The .Fn procctl system call provides for control over processes. The .Fa idtype and .Fa id arguments specify the set of processes to control. If multiple processes match the identifier, .Nm will make a .Dq best effort to control as many of the selected processes as possible. An error is only returned if no selected processes successfully complete the request. The following identifier types are supported: .Bl -tag -width "Dv P_PGID" .It Dv P_PID Control the process with the process ID .Fa id . .It Dv P_PGID Control processes belonging to the process group with the ID .Fa id . .El .Pp The control request to perform is specified by the .Fa cmd argument. The following commands are supported: .Bl -tag -width "Dv PROC_SPROTECT" .It Dv PROC_SPROTECT Set process protection state. This is used to mark a process as protected from being killed if the system exhausts available memory and swap. The .Fa arg parameter must point to an integer containing an operation and zero or more optional flags. The following operations are supported: .Bl -tag -width "Dv PPROT_CLEAR" .It Dv PPROT_SET Mark the selected processes as protected. .It Dv PPROT_CLEAR Clear the protected state of selected processes. .El .Pp The following optional flags are supported: .Bl -tag -width "Dv PPROT_DESCE" .It Dv PPROT_DESCEND Apply the requested operation to all child processes of each selected process in addition to each selected process. .It Dv PPROT_INHERIT When used with .Dv PPROT_SET , mark all future child processes of each selected process as protected. Future child processes will also mark all of their future child processes. .El .El .Sh RETURN VALUES If an error occurs, a value of -1 is returned and .Va errno is set to indicate the error. .Sh ERRORS The .Fn procctl system call will fail if: .Bl -tag -width Er .It Bq Er EFAULT The .Fa arg points outside the process's allocated address space. .It Bq Er EINVAL The .Fa cmd argument specifies an unsupported command. .Pp The .Fa idtype argument specifies an unsupported identifier type. .It Bq Er EPERM The calling process does not have permission to perform the requested operation on any of the selected processes. .It Bq Er ESRCH No processes matched the requested .Fa idtype and .Fa id . .It Bq Er EINVAL An invalid operation or flag was passed in .Fa arg for a .Dv PROC_SPROTECT command. .El .Sh SEE ALSO .Xr ptrace 2 .Sh HISTORY The .Fn procctl function appeared in .Fx 10 . Index: stable/9/lib/libc/sys =================================================================== --- stable/9/lib/libc/sys (revision 283926) +++ stable/9/lib/libc/sys (revision 283927) Property changes on: stable/9/lib/libc/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/lib/libc/sys:r281887 Index: stable/9/lib/libc =================================================================== --- stable/9/lib/libc (revision 283926) +++ stable/9/lib/libc (revision 283927) Property changes on: stable/9/lib/libc ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/lib/libc:r281887 Index: stable/9/share/man/man9/BUS_BIND_INTR.9 =================================================================== --- stable/9/share/man/man9/BUS_BIND_INTR.9 (revision 283926) +++ stable/9/share/man/man9/BUS_BIND_INTR.9 (revision 283927) @@ -1,98 +1,98 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 14, 2009 .Dt BUS_BIND_INTR 9 .Os .Sh NAME .Nm BUS_BIND_INTR , .Nm bus_bind_intr .Nd "bind an interrupt resource to a specific CPU" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft int .Fo BUS_BIND_INTR .Fa "device_t dev" "device_t child" "struct resource *irq" "int cpu" .Fc .Ft int .Fn bus_bind_intr "device_t dev" "struct resource *irq" "int cpu" .Sh DESCRIPTION The .Fn BUS_BIND_INTR method allows an interrupt resource to be pinned to a specific CPU. The interrupt resource must have an interrupt handler attached via .Xr BUS_SETUP_INTR 9 . The .Fa cpu parameter corresponds to the ID of a valid CPU in the system. Binding an interrupt restricts the .Xr cpuset 2 of any associated interrupt threads to only include the specified CPU. It may also direct the low-level interrupt handling of the interrupt to the specified CPU as well, but this behavior is platform-dependent. If the value .Dv NOCPU is used for .Fa cpu , then the interrupt will be .Dq unbound which restores any associated interrupt threads back to the default cpuset. .Pp Non-sleepable locks such as mutexes should not be held across calls to these functions. .Pp The .Fn bus_bind_intr function is a simple wrapper around .Fn BUS_BIND_INTR . .Pp Note that currently there is no attempt made to arbitrate between multiple bind requests for the same interrupt from either the same device or multiple devices. There is also no arbitration between interrupt binding requests submitted by userland via .Xr cpuset 2 and .Fn BUS_BIND_INTR . The most recent binding request is the one that will be in effect. .Sh RETURN VALUES Zero is returned on success, otherwise an appropriate error is returned. .Sh SEE ALSO .Xr BUS_SETUP_INTR 9 , .Xr cpuset 2 , .Xr device 9 .Sh HISTORY The .Fn BUS_BIND_INTR method and .Fn bus_bind_intr functions first appeared in .Fx 7.2 . Index: stable/9/share/man/man9/BUS_CHILD_DELETED.9 =================================================================== --- stable/9/share/man/man9/BUS_CHILD_DELETED.9 (revision 283926) +++ stable/9/share/man/man9/BUS_CHILD_DELETED.9 (revision 283927) @@ -1,55 +1,55 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2012 Advanced Computing Technologies LLC +.\" Copyright (c) 2012 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd August 21, 2012 .Dt BUS_CHILD_DELETED 9 .Os .Sh NAME .Nm BUS_CHILD_DELETED .Nd "notify a bus device that a child is being deleted" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn BUS_CHILD_DELETED "device_t dev" "device_t child" .Sh DESCRIPTION The .Fn BUS_CHILD_DELETED method is invoked by the new-bus framework when a device is deleted. A bus driver can provide an implementation of this method to release bus-specific resources associated with a device such as instance variables. .Sh SEE ALSO .Xr BUS_ADD_CHILD 9 , .Xr device 9 .Sh HISTORY The .Fn BUS_CHILD_DELETED method first appeared in .Fx 10.0 . Index: stable/9/share/man/man9/BUS_DESCRIBE_INTR.9 =================================================================== --- stable/9/share/man/man9/BUS_DESCRIBE_INTR.9 (revision 283926) +++ stable/9/share/man/man9/BUS_DESCRIBE_INTR.9 (revision 283927) @@ -1,104 +1,104 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 14, 2009 .Dt BUS_DESCRIBE_INTR 9 .Os .Sh NAME .Nm BUS_DESCRIBE_INTR , .Nm bus_describe_intr .Nd "associate a description with an active interrupt handler" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft int .Fo BUS_BIND_INTR .Fa "device_t dev" "device_t child" "struct resource *irq" "void *cookie" .Fa "const char *descr" .Fc .Ft int .Fo bus_describe_intr .Fa "device_t dev" "struct resource *irq" "void *cookie" "const char *fmt" .Fa ... .Fc .Sh DESCRIPTION The .Fn BUS_DESCRIBE_INTR method associates a description with an active interrupt handler. The .Fa cookie parameter must be the value returned by a successful call to .Xr BUS_SETUP_INTR 9 for the interrupt .Fa irq . .Pp The .Fn bus_describe_intr function is a simple wrapper around .Fn BUS_DESCRIBE_INTR . As a convenience, .Fn bus_describe_intr allows the caller to use .Xr printf 9 style formatting to build the description string using .Fa fmt . .Pp When an interrupt handler is established by .Xr BUS_SETUP_INTR 9 , the handler is named after the device the handler is established for. This name is then used in various places such as interrupt statistics displayed by .Xr systat 1 and .Xr vmstat 8 . For devices that use a single interrupt, the device name is sufficiently unique to identify the interrupt handler. However, for devices that use multiple interrupts it can be useful to distinguish the interrupt handlers. When a description is set for an active interrupt handler, a colon followed by the description is appended to the device name to form the interrupt handler name. .Sh RETURN VALUES Zero is returned on success, otherwise an appropriate error is returned. .Sh SEE ALSO .Xr BUS_SETUP_INTR 9 , .Xr systat 1 , .Xr vmstat 8 , .Xr device 9 , .Xr printf 9 .Sh HISTORY The .Fn BUS_DESCRIBE_INTR method and .Fn bus_describe_intr functions first appeared in .Fx 8.1 . .Sh BUGS It is not currently possible to remove a description from an active interrupt handler. Index: stable/9/share/man/man9/BUS_NEW_PASS.9 =================================================================== --- stable/9/share/man/man9/BUS_NEW_PASS.9 (revision 283926) +++ stable/9/share/man/man9/BUS_NEW_PASS.9 (revision 283927) @@ -1,56 +1,56 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 8, 2009 .Dt BUS_NEW_PASS 9 .Os .Sh NAME .Nm BUS_NEW_PASS .Nd "notify a bus that the pass level has been changed" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn BUS_NEW_PASS "device_t dev" .Sh DESCRIPTION The .Fn BUS_NEW_PASS method is called on each bus device to rescan the device tree when the pass level has been changed. This method is responsible for invoking .Xr BUS_NEW_PASS 9 on child bus devices to propagate the rescan to child devices. It is also responsible for reprobing any unattached child devices and allowing drivers for the current pass to identify new children. A default implementation is provided by .Xr bus_generic_new_pass 9 . .Sh SEE ALSO .Xr bus_generic_new_pass 9 , .Xr bus_set_pass 9 , .Xr device 9 Index: stable/9/share/man/man9/bus_adjust_resource.9 =================================================================== --- stable/9/share/man/man9/bus_adjust_resource.9 (revision 283926) +++ stable/9/share/man/man9/bus_adjust_resource.9 (revision 283927) @@ -1,101 +1,101 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2011 Advanced Computing Technologies LLC +.\" Copyright (c) 2011 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd April 29, 2011 .Dt BUS_ADJUST_RESOURCE 9 .Os .Sh NAME .Nm bus_adjust_resource .Nd adjust resource allocated from a parent bus .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Pp .In machine/bus.h .In sys/rman.h .In machine/resource.h .Ft int .Fn bus_adjust_resource "device_t dev" "int type" "struct resource *r" "u_long start" "u_long end" .Sh DESCRIPTION This function is used to ask the parent bus to adjust the resource range assigned to an allocated resource. The resource .Fa r should have been allocated by a previous call to .Xr bus_alloc_resource 9 . The new resource range must overlap the existing range of .Fa r . The .Fa type argument should match the .Fa type argument passed to .Xr bus_alloc_resource 9 when the resource was initially allocated. .Pp Note that none of the constraints of the original allocation request such as alignment or boundary restrictions are checked by .Fn bus_adjust_resource . It is the caller's responsibility to enforce any such requirements. .Sh RETURN VALUES The .Fn bus_adjust_resource method returns zero on success or an error code on failure. .Sh EXAMPLES Grow an existing memory resource by 4096 bytes. .Bd -literal struct resource *res; int error; error = bus_adjust_resource(dev, SYS_RES_MEMORY, res, rman_get_start(res), rman_get_end(res) + 0x1000); .Ed .Sh ERRORS .Fn bus_adjust_resource will fail if: .Bl -tag -width Er .It Bq Er EINVAL The .Fa dev device does not have a parent device. .It Bq Er EINVAL The .Fa r resource is a shared resource. .It Bq Er EINVAL The new address range does not overlap with the existing address range of .Fa r . .It Bq Er EBUSY The new address range conflicts with another allocated resource. .El .Sh SEE ALSO .Xr bus_alloc_resource 9 , .Xr bus_release_resource 9 , .Xr device 9 , .Xr driver 9 Index: stable/9/share/man/man9/bus_generic_new_pass.9 =================================================================== --- stable/9/share/man/man9/bus_generic_new_pass.9 (revision 283926) +++ stable/9/share/man/man9/bus_generic_new_pass.9 (revision 283927) @@ -1,57 +1,57 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 8, 2009 .Dt BUS_GENERIC_NEW_PASS 9 .Os .Sh NAME .Nm bus_generic_new_pass .Nd "generic implementation of BUS_NEW_PASS for bus devices" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn bus_generic_new_pass "device_t dev" .Sh DESCRIPTION This function provides an implementation of the .Xr BUS_NEW_PASS 9 method which can be used by bus drivers. It first invokes the .Xr DEVICE_IDENTIFY 9 method for any drivers whose pass level is equal to the new pass level. Then, for each attached child device it calls .Xr BUS_NEW_PASS 9 to rescan child busses, and for each unattached child device it calls .Xr device_probe_and_attach 9 . .Sh SEE ALSO .Xr BUS_NEW_PASS 9 , .Xr bus_set_pass 9 , .Xr device 9 , .Xr DEVICE_IDENTIFY 9 Index: stable/9/share/man/man9/bus_set_pass.9 =================================================================== --- stable/9/share/man/man9/bus_set_pass.9 (revision 283926) +++ stable/9/share/man/man9/bus_set_pass.9 (revision 283927) @@ -1,54 +1,54 @@ .\" -*- nroff -*- .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd June 8, 2009 .Dt BUS_SET_PASS 9 .Os .Sh NAME .Nm bus_set_pass .Nd "raise the bus pass level" .Sh SYNOPSIS .In sys/param.h .In sys/bus.h .Ft void .Fn bus_set_pass "int pass" .Sh DESCRIPTION The .Nm function is called during boot to raise the bus pass level to .Fa pass . The function will rescan the device tree for each pass level between the current pass level and the new level that has at least one associated driver. The device tree rescans are implemented by invoking the .Xr BUS_NEW_PASS 9 method on the root bus device. .Sh SEE ALSO .Xr BUS_NEW_PASS 9 , .Xr device 9 Index: stable/9/share/man/man9/refcount.9 =================================================================== --- stable/9/share/man/man9/refcount.9 (revision 283926) +++ stable/9/share/man/man9/refcount.9 (revision 283927) @@ -1,96 +1,96 @@ .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd January 20, 2009 .Dt REFCOUNT 9 .Os .Sh NAME .Nm refcount , .Nm refcount_init , .Nm refcount_acquire , .Nm refcount_release .Nd manage a simple reference counter .Sh SYNOPSIS .In sys/param.h .In sys/refcount.h .Ft void .Fn refcount_init "volatile u_int *count, u_int value" .Ft void .Fn refcount_acquire "volatile u_int *count" .Ft int .Fn refcount_release "volatile u_int *count" .Sh DESCRIPTION The .Nm functions provide an API to manage a simple reference counter. The caller provides the storage for the counter in an unsigned integer. A pointer to this integer is passed via .Fa count . Usually the counter is used to manage the lifetime of an object and is stored as a member of the object. .Pp The .Fn refcount_init function is used to set the initial value of the counter to .Fa value . It is normally used when creating a reference-counted object. .Pp The .Fn refcount_acquire function is used to acquire a new reference. The caller is responsible for ensuring that it holds a valid reference while obtaining a new reference. For example, if an object is stored on a list and the list holds a reference on the object, then holding a lock that protects the list provides sufficient protection for acquiring a new reference. .Pp The .Fn refcount_release function is used to release an existing reference. The function returns a non-zero value if the reference being released was the last reference; otherwise, it returns zero. .Pp Note that these routines do not provide any inter-CPU synchronization, data protection, or memory ordering guarantees except for managing the counter. The caller is responsible for any additional synchronization needed by consumers of any containing objects. In addition, the caller is also responsible for managing the life cycle of any containing objects including explicitly releasing any resources when the last reference is released. .Sh RETURN VALUES The .Nm refcount_release function returns non-zero when releasing the last reference and zero when releasing any other reference. .Sh HISTORY These functions were introduced in .Fx 6.0 . Index: stable/9/share/man/man9/sglist.9 =================================================================== --- stable/9/share/man/man9/sglist.9 (revision 283926) +++ stable/9/share/man/man9/sglist.9 (revision 283927) @@ -1,518 +1,518 @@ .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd January 12, 2014 .Dt SGLIST 9 .Os .Sh NAME .Nm sglist , .Nm sglist_alloc , .Nm sglist_append , .Nm sglist_append_bio , .Nm sglist_append_mbuf , .Nm sglist_append_phys , .Nm sglist_append_uio , .Nm sglist_append_user , .Nm sglist_build , .Nm sglist_clone , .Nm sglist_consume_uio , .Nm sglist_count , .Nm sglist_free , .Nm sglist_hold , .Nm sglist_init , .Nm sglist_join , .Nm sglist_length , .Nm sglist_reset , .Nm sglist_slice , .Nm sglist_split .Nd manage a scatter/gather list of physical memory addresses .Sh SYNOPSIS .In sys/types.h .In sys/sglist.h .Ft struct sglist * .Fn sglist_alloc "int nsegs" "int mflags" .Ft int .Fn sglist_append "struct sglist *sg" "void *buf" "size_t len" .Ft int .Fn sglist_append_bio "struct sglist *sg" "struct bio *bp" .Ft int .Fn sglist_append_mbuf "struct sglist *sg" "struct mbuf *m" .Ft int .Fn sglist_append_phys "struct sglist *sg" "vm_paddr_t paddr" "size_t len" .Ft int .Fn sglist_append_uio "struct sglist *sg" "struct uio *uio" .Ft int .Fn sglist_append_user "struct sglist *sg" "void *buf" "size_t len" "struct thread *td" .Ft struct sglist * .Fn sglist_build "void *buf" "size_t len" "int mflags" .Ft struct sglist * .Fn sglist_clone "struct sglist *sg" "int mflags" .Ft int .Fn sglist_consume_uio "struct sglist *sg" "struct uio *uio" "size_t resid" .Ft int .Fn sglist_count "void *buf" "size_t len" .Ft void .Fn sglist_free "struct sglist *sg" .Ft struct sglist * .Fn sglist_hold "struct sglist *sg" .Ft void .Fn sglist_init "struct sglist *sg" "int maxsegs" "struct sglist_seg *segs" .Ft int .Fn sglist_join "struct sglist *first" "struct sglist *second" .Ft size_t .Fn sglist_length "struct sglist *sg" .Ft void .Fn sglist_reset "struct sglist *sg" .Ft int .Fn sglist_slice "struct sglist *original" "struct sglist **slice" "size_t offset" "size_t length" "int mflags" .Ft int .Fn sglist_split "struct sglist *original" "struct sglist **head" "size_t length" "int mflags" .Sh DESCRIPTION The .Nm API manages physical address ranges. Each list contains one or more elements. Each element contains a starting physical address and a length. Scatter/gather lists are read-only while they are shared. If one wishes to alter an existing scatter/gather list and does not hold the sole reference to the list, then one should create a new list instead of modifying the existing list. .Pp Each scatter/gather list object contains a reference count. New lists are created with a single reference. New references are obtained by calling .Nm sglist_hold and are released by calling .Nm sglist_free . .Ss Allocating and Initializing Lists Each .Nm object consists of a header structure and a variable-length array of scatter/gather list elements. The .Nm sglist_alloc function allocates a new list that contains a header and .Fa nsegs scatter/gather list elements. The .Fa mflags argument can be set to either .Dv M_NOWAIT or .Dv M_WAITOK . .Pp The .Nm sglist_count function returns the number of scatter/gather list elements needed to describe the physical address ranges mapped by a single kernel virtual address range. The kernel virtual address range starts at .Fa buf and is .Fa len bytes long. .Pp The .Nm sglist_build function allocates a new scatter/gather list object that describes the physical address ranges mapped by a single kernel virtual address range. The kernel virtual address range starts at .Fa buf and is .Fa len bytes long. The .Fa mflags argument can be set to either .Dv M_NOWAIT or .Dv M_WAITOK . .Pp The .Nm sglist_clone function returns a copy of an existing scatter/gather list object .Fa sg . The .Fa mflags argument can be set to either .Dv M_NOWAIT or .Dv M_WAITOK . This can be used to obtain a private copy of a scatter/gather list before modifying it. .Pp The .Nm sglist_init function initializes a scatter/gather list header. The header is pointed to by .Fa sg and is initialized to manage an array of .Fa maxsegs scatter/gather list elements pointed to by .Fa segs . This can be used to initialize a scatter/gather list header whose storage is not provided by .Nm sglist_alloc . In that case, the caller should not call .Nm sglist_free to release its own reference and is responsible for ensuring all other references to the list are dropped before it releases the storage for .Fa sg and .Fa segs . .Ss Constructing Scatter/Gather Lists The .Nm API provides several routines for building a scatter/gather list to describe one or more objects. Specifically, the .Nm sglist_append family of routines can be used to append the physical address ranges described by an object to the end of a scatter/gather list. All of these routines return 0 on success or an error on failure. If a request to append an address range to a scatter/gather list fails, the scatter/gather list will remain unchanged. .Pp The .Nm sglist_append function appends the physical address ranges described by a single kernel virtual address range to the scatter/gather list .Fa sg . The kernel virtual address range starts at .Fa buf and is .Fa len bytes long. .Pp The .Nm sglist_append_bio function appends the physical address ranges described by a single bio .Fa bp to the scatter/gather list .Fa sg . .Pp The .Nm sglist_append_mbuf function appends the physical address ranges described by an entire mbuf chain .Fa m to the scatter/gather list .Fa sg . .Pp The .Nm sglist_append_phys function appends a single physical address range to the scatter/gather list .Fa sg . The physical address range starts at .Fa paddr and is .Fa len bytes long. .Pp The .Nm sglist_append_uio function appends the physical address ranges described by a .Xr uio 9 object to the scatter/gather list .Fa sg . Note that it is the caller's responsibility to ensure that the pages backing the I/O request are wired for the lifetime of .Fa sg . Note also that this routine does not modify .Fa uio . .Pp The .Nm sglist_append_user function appends the physical address ranges described by a single user virtual address range to the scatter/gather list .Fa sg . The user virtual address range is relative to the address space of the thread .Fa td . It starts at .Fa buf and is .Fa len bytes long. Note that it is the caller's responsibility to ensure that the pages backing the user buffer are wired for the lifetime of .Fa sg . .Pp The .Nm sglist_consume_uio function is a variation of .Nm sglist_append_uio . As with .Nm sglist_append_uio , it appends the physical address ranges described by .Fa uio to the scatter/gather list .Fa sg . Unlike .Nm sglist_append_uio , however, .Nm sglist_consume_uio modifies the I/O request to indicate that the appended address ranges have been processed similar to calling .Xr uiomove 9 . This routine will only append ranges that describe up to .Fa resid total bytes in length. If the available segments in the scatter/gather list are exhausted before .Fa resid bytes are processed, then the .Fa uio structure will be updated to reflect the actual number of bytes processed, and .Nm sglist_consume_io will return zero to indicate success. In effect, this function will perform partial reads or writes. The caller can compare the .Fa uio_resid member of .Fa uio before and after calling .Nm sglist_consume_uio to determine the actual number of bytes processed. .Ss Manipulating Scatter/Gather Lists The .Nm sglist_join function appends physical address ranges from the scatter/gather list .Fa second onto .Fa first and then resets .Fa second to an empty list. It returns zero on success or an error on failure. .Pp The .Nm sglist_split function splits an existing scatter/gather list into two lists. The first .Fa length bytes described by the list .Fa original are moved to a new list .Fa *head . If .Fa original describes a total address range that is smaller than .Fa length bytes, then all of the address ranges will be moved to the new list at .Fa *head and .Fa original will be an empty list. The caller may supply an existing scatter/gather list in .Fa *head . If so, the list must be empty. Otherwise, the caller may set .Fa *head to .Dv NULL in which case a new scatter/gather list will be allocated. In that case, .Fa mflags may be set to either .Dv M_NOWAIT or .Dv M_WAITOK . Note that since the .Fa original list is modified by this call, it must be a private list with no other references. The .Nm sglist_split function returns zero on success or an error on failure. .Pp The .Nm sglist_slice function generates a new scatter/gather list from a sub-range of an existing scatter/gather list .Fa original . The sub-range to extract is specified by the .Fa offset and .Fa length parameters. The new scatter/gather list is stored in .Fa *slice . As with .Fa head for .Nm sglist_join , the caller may either provide an empty scatter/gather list, or it may set .Fa *slice to .Dv NULL in which case .Nm sglist_slice will allocate a new list subject to .Fa mflags . Unlike .Nm sglist_split , .Nm sglist_slice does not modify .Fa original and does not require it to be a private list. The .Nm sglist_split function returns zero on success or an error on failure. .Ss Miscellaneous Routines The .Nm sglist_reset function clears the scatter/gather list .Fa sg so that it no longer maps any address ranges. This can allow reuse of a single scatter/gather list object for multiple requests. .Pp The .Nm sglist_length function returns the total length of the physical address ranges described by the scatter/gather list .Fa sg . .Sh RETURN VALUES The .Nm sglist_alloc , .Nm sglist_build , and .Nm sglist_clone functions return a new scatter/gather list on success or .Dv NULL on failure. .Pp The .Nm sglist_append family of functions and the .Nm sglist_consume_uio , .Nm sglist_join , .Nm sglist_slice , and .Nm sglist_split functions return zero on success or an error on failure. .Pp The .Nm sglist_count function returns a count of scatter/gather list elements. .Pp The .Nm sglist_length function returns a count of address space described by a scatter/gather list in bytes. .Sh ERRORS The .Nm sglist_append functions return the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The scatter/gather list has zero segments. .It Bq Er EFBIG There are not enough available segments in the scatter/gather list to append the specified physical address ranges. .El .Pp The .Nm sglist_consume_uio function returns the following error on failure: .Bl -tag -width Er .It Bq Er EINVAL The scatter/gather list has zero segments. .El .Pp The .Nm sglist_join function returns the following error on failure: .Bl -tag -width Er .It Bq Er EFBIG There are not enough available segments in the scatter/gather list .Fa first to append the physical address ranges from .Fa second . .El .Pp The .Nm sglist_slice function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The .Fa original scatter/gather list does not describe enough address space to cover the requested sub-range. .It Bq Er EINVAL The caller-supplied scatter/gather list in .Fa *slice is not empty. .It Bq Er ENOMEM An attempt to allocate a new scatter/gather list with .Dv M_NOWAIT set in .Fa mflags failed. .It Bq Er EFBIG There are not enough available segments in the caller-supplied scatter/gather list in .Fa *slice to describe the requested physical address ranges. .El .Pp The .Nm sglist_split function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EDOOFUS The .Fa original scatter/gather list has more than one reference. .It Bq Er EINVAL The caller-supplied scatter/gather list in .Fa *head is not empty. .It Bq Er ENOMEM An attempt to allocate a new scatter/gather list with .Dv M_NOWAIT set in .Fa mflags failed. .It Bq Er EFBIG There are not enough available segments in the caller-supplied scatter/gather list in .Fa *head to describe the requested physical address ranges. .El .Sh SEE ALSO .Xr g_bio 9 , .Xr malloc 9 , .Xr mbuf 9 , .Xr uio 9 .Sh HISTORY This API was first introduced in .Fx 8.0 . Index: stable/9/share/man/man9/shm_map.9 =================================================================== --- stable/9/share/man/man9/shm_map.9 (revision 283926) +++ stable/9/share/man/man9/shm_map.9 (revision 283927) @@ -1,186 +1,186 @@ .\" -.\" Copyright (c) 2011 Advanced Computing Technologies LLC +.\" Copyright (c) 2011 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd December 14, 2011 .Dt SHM_MAP 9 .Os .Sh NAME .Nm shm_map , shm_unmap .Nd "map shared memory objects into the kernel's address space" .Sh SYNOPSIS .In sys/types.h .In sys/mman.h .Ft int .Fn shm_map "struct file *fp" "size_t size" "off_t offset" "void **memp" .Ft int .Fn shm_unmap "struct file *fp" "void *mem" "size_t size" .Sh DESCRIPTION The .Fn shm_map and .Fn shm_unmap functions provide an API for mapping shared memory objects into the kernel. Shared memory objects are created by .Xr shm_open 2 . These objects can then be passed into the kernel via file descriptors. .Pp A shared memory object cannot be shrunk while it is mapped into the kernel. This is to avoid invalidating any pages that may be wired into the kernel's address space. Shared memory objects can still be grown while mapped into the kernel. .Pp To simplify the accounting needed to enforce the above requirement, callers of this API are required to unmap the entire region mapped by .Fn shm_map when calling .Fn shm_unmap . Unmapping only a portion of the region is not permitted. .Pp The .Fn shm_map function locates the shared memory object associated with the open file .Fa fp . It maps the region of that object described by .Fa offset and .Fa size into the kernel's address space. If it succeeds, .Fa *memp will be set to the start of the mapping. All pages for the range will be wired into memory upon successful return. .Pp The .Fn shm_unmap function unmaps a region previously mapped by .Fn shm_map . The .Fa mem argument should match the value previously returned in .Fa *memp , and the .Fa size argument should match the value passed to .Fn shm_map . .Pp Note that .Fn shm_map will not hold an extra reference on the open file .Fa fp for the lifetime of the mapping. Instead, the calling code is required to do this if it wishes to use .Fn shm_unmap on the region in the future. .Sh RETURN VALUES The .Fn shm_map and .Fn shm_unmap functions return zero on success or an error on failure. .Sh EXAMPLES The following function accepts a file descriptor for a shared memory object. It maps the first sixteen kilobytes of the object into the kernel, performs some work on that address, and then unmaps the address before returning. .Bd -literal -offset indent int shm_example(int fd) { struct file *fp; void *mem; int error; error = fget(curthread, fd, CAP_MMAP, &fp); if (error) return (error); error = shm_map(fp, 16384, 0, &mem); if (error) { fdrop(fp, curthread); return (error); } /* Do something with 'mem'. */ error = shm_unmap(fp, mem, 16384); fdrop(fp, curthread); return (error); } .Ed .Sh ERRORS The .Fn shm_map function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The open file .Fa fp is not a shared memory object. .It Bq Er EINVAL The requested region described by .Fa offset and .Fa size extends beyond the end of the shared memory object. .It Bq Er ENOMEM Insufficient address space was available. .It Bq Er EACCES The shared memory object could not be mapped due to a protection error. .It Bq Er EINVAL The shared memory object could not be mapped due to some other VM error. .El .Pp The .Fn shm_unmap function returns the following errors on failure: .Bl -tag -width Er .It Bq Er EINVAL The open file .Fa fp is not a shared memory object. .It Bq Er EINVAL The address range described by .Fa mem and .Fa size is not a valid address range. .It Bq Er EINVAL The address range described by .Fa mem and .Fa size is not backed by the shared memory object associated with the open file .Fa fp , or the address range does not cover the entire mapping of the object. .El .Sh SEE ALSO .Xr shm_open 2 .Sh HISTORY This API was first introduced in .Fx 10.0 . Index: stable/9/share/man/man9 =================================================================== --- stable/9/share/man/man9 (revision 283926) +++ stable/9/share/man/man9 (revision 283927) Property changes on: stable/9/share/man/man9 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/share/man/man9:r281887 Index: stable/9/sys/amd64/include/vm.h =================================================================== --- stable/9/sys/amd64/include/vm.h (revision 283926) +++ stable/9/sys/amd64/include/vm.h (revision 283927) @@ -1,46 +1,46 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _MACHINE_VM_H_ #define _MACHINE_VM_H_ #include /* Memory attributes. */ #define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHEABLE) #define VM_MEMATTR_WRITE_COMBINING ((vm_memattr_t)PAT_WRITE_COMBINING) #define VM_MEMATTR_WRITE_THROUGH ((vm_memattr_t)PAT_WRITE_THROUGH) #define VM_MEMATTR_WRITE_PROTECTED ((vm_memattr_t)PAT_WRITE_PROTECTED) #define VM_MEMATTR_WRITE_BACK ((vm_memattr_t)PAT_WRITE_BACK) #define VM_MEMATTR_WEAK_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHED) #define VM_MEMATTR_UNCACHED VM_MEMATTR_WEAK_UNCACHEABLE #define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK #endif /* !_MACHINE_VM_H_ */ Index: stable/9/sys/boot/i386/common/edd.h =================================================================== --- stable/9/sys/boot/i386/common/edd.h (revision 283926) +++ stable/9/sys/boot/i386/common/edd.h (revision 283927) @@ -1,110 +1,110 @@ /*- - * Copyright (c) 2011 Advanced Computing Technologies LLC + * Copyright (c) 2011 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _EDD_H_ #define _EDD_H_ /* Supported interfaces for "Check Extensions Present". */ #define EDD_INTERFACE_FIXED_DISK 0x01 #define EDD_INTERFACE_EJECT 0x02 #define EDD_INTERFACE_EDD 0x04 struct edd_packet { uint16_t len; uint16_t count; uint16_t off; uint16_t seg; uint64_t lba; }; struct edd_packet_v3 { uint16_t len; uint16_t count; uint16_t off; uint16_t seg; uint64_t lba; uint64_t phys_addr; }; struct edd_params { uint16_t len; uint16_t flags; uint32_t cylinders; uint32_t heads; uint32_t sectors_per_track; uint64_t sectors; uint16_t sector_size; uint16_t edd_params_seg; uint16_t edd_params_off; } __packed; struct edd_device_path_v3 { uint16_t key; uint8_t len; uint8_t reserved[3]; char host_bus[4]; char interface[8]; uint64_t interface_path; uint64_t device_path; uint8_t reserved2[1]; uint8_t checksum; } __packed; struct edd_params_v3 { struct edd_params params; struct edd_device_path_v3 device_path; } __packed; struct edd_device_path_v4 { uint16_t key; uint8_t len; uint8_t reserved[3]; char host_bus[4]; char interface[8]; uint64_t interface_path; uint64_t device_path[2]; uint8_t reserved2[1]; uint8_t checksum; } __packed; struct edd_params_v4 { struct edd_params params; struct edd_device_path_v4 device_path; } __packed; #define EDD_FLAGS_DMA_BOUNDARY_HANDLING 0x0001 #define EDD_FLAGS_REMOVABLE_MEDIA 0x0002 #define EDD_FLAGS_WRITE_VERIFY 0x0004 #define EDD_FLAGS_MEDIA_CHANGE_NOTIFICATION 0x0008 #define EDD_FLAGS_LOCKABLE_MEDIA 0x0010 #define EDD_FLAGS_NO_MEDIA_PRESENT 0x0020 #define EDD_DEVICE_PATH_KEY 0xbedd #endif /* !_EDD_H_ */ Index: stable/9/sys/boot =================================================================== --- stable/9/sys/boot (revision 283926) +++ stable/9/sys/boot (revision 283927) Property changes on: stable/9/sys/boot ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/boot:r281887 Index: stable/9/sys/dev/pci/pci_subr.c =================================================================== --- stable/9/sys/dev/pci/pci_subr.c (revision 283926) +++ stable/9/sys/dev/pci/pci_subr.c (revision 283927) @@ -1,285 +1,285 @@ /*- - * Copyright (c) 2011 Advanced Computing Technologies LLC + * Copyright (c) 2011 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); /* * Support APIs for Host to PCI bridge drivers and drivers that * provide PCI domains. */ #include #include #include #include #include #include #include /* * Try to read the bus number of a host-PCI bridge using appropriate config * registers. */ int host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, uint8_t *busnum) { uint32_t id; id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); if (id == 0xffffffff) return (0); switch (id) { case 0x12258086: /* Intel 824?? */ /* XXX This is a guess */ /* *busnum = read_config(bus, slot, func, 0x41, 1); */ *busnum = bus; break; case 0x84c48086: /* Intel 82454KX/GX (Orion) */ *busnum = read_config(bus, slot, func, 0x4a, 1); break; case 0x84ca8086: /* * For the 450nx chipset, there is a whole bundle of * things pretending to be host bridges. The MIOC will * be seen first and isn't really a pci bridge (the * actual busses are attached to the PXB's). We need to * read the registers of the MIOC to figure out the * bus numbers for the PXB channels. * * Since the MIOC doesn't have a pci bus attached, we * pretend it wasn't there. */ return (0); case 0x84cb8086: switch (slot) { case 0x12: /* Intel 82454NX PXB#0, Bus#A */ *busnum = read_config(bus, 0x10, func, 0xd0, 1); break; case 0x13: /* Intel 82454NX PXB#0, Bus#B */ *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; break; case 0x14: /* Intel 82454NX PXB#1, Bus#A */ *busnum = read_config(bus, 0x10, func, 0xd3, 1); break; case 0x15: /* Intel 82454NX PXB#1, Bus#B */ *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; break; } break; /* ServerWorks -- vendor 0x1166 */ case 0x00051166: case 0x00061166: case 0x00081166: case 0x00091166: case 0x00101166: case 0x00111166: case 0x00171166: case 0x01011166: case 0x010f1014: case 0x01101166: case 0x02011166: case 0x02251166: case 0x03021014: *busnum = read_config(bus, slot, func, 0x44, 1); break; /* Compaq/HP -- vendor 0x0e11 */ case 0x60100e11: *busnum = read_config(bus, slot, func, 0xc8, 1); break; default: /* Don't know how to read bus number. */ return 0; } return 1; } #ifdef NEW_PCIB /* * Return a pointer to a pretty name for a PCI device. If the device * has a driver attached, the device's name is used, otherwise a name * is generated from the device's PCI address. */ const char * pcib_child_name(device_t child) { static char buf[64]; if (device_get_nameunit(child) != NULL) return (device_get_nameunit(child)); snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", pci_get_domain(child), pci_get_bus(child), pci_get_slot(child), pci_get_function(child)); return (buf); } /* * Some Host-PCI bridge drivers know which resource ranges they can * decode and should only allocate subranges to child PCI devices. * This API provides a way to manage this. The bridge drive should * initialize this structure during attach and call * pcib_host_res_decodes() on each resource range it decodes. It can * then use pcib_host_res_alloc() and pcib_host_res_adjust() as helper * routines for BUS_ALLOC_RESOURCE() and BUS_ADJUST_RESOURCE(). This * API assumes that resources for any decoded ranges can be safely * allocated from the parent via bus_generic_alloc_resource(). */ int pcib_host_res_init(device_t pcib, struct pcib_host_resources *hr) { hr->hr_pcib = pcib; resource_list_init(&hr->hr_rl); return (0); } int pcib_host_res_free(device_t pcib, struct pcib_host_resources *hr) { resource_list_free(&hr->hr_rl); return (0); } int pcib_host_res_decodes(struct pcib_host_resources *hr, int type, u_long start, u_long end, u_int flags) { struct resource_list_entry *rle; int rid; if (bootverbose) device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n", type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start, end); rid = resource_list_add_next(&hr->hr_rl, type, start, end, end - start + 1); if (flags & RF_PREFETCHABLE) { KASSERT(type == SYS_RES_MEMORY, ("only memory is prefetchable")); rle = resource_list_find(&hr->hr_rl, type, rid); rle->flags = RLE_PREFETCH; } return (0); } struct resource * pcib_host_res_alloc(struct pcib_host_resources *hr, device_t dev, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct resource_list_entry *rle; struct resource *r; u_long new_start, new_end; if (flags & RF_PREFETCHABLE) KASSERT(type == SYS_RES_MEMORY, ("only memory is prefetchable")); rle = resource_list_find(&hr->hr_rl, type, 0); if (rle == NULL) { /* * No decoding ranges for this resource type, just pass * the request up to the parent. */ return (bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, start, end, count, flags)); } restart: /* Try to allocate from each decoded range. */ for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { if (rle->type != type) continue; if (((flags & RF_PREFETCHABLE) != 0) != ((rle->flags & RLE_PREFETCH) != 0)) continue; new_start = ulmax(start, rle->start); new_end = ulmin(end, rle->end); if (new_start > new_end || new_start + count - 1 > new_end || new_start + count < new_start) continue; r = bus_generic_alloc_resource(hr->hr_pcib, dev, type, rid, new_start, new_end, count, flags); if (r != NULL) { if (bootverbose) device_printf(hr->hr_pcib, "allocated type %d (%#lx-%#lx) for rid %x of %s\n", type, rman_get_start(r), rman_get_end(r), *rid, pcib_child_name(dev)); return (r); } } /* * If we failed to find a prefetch range for a memory * resource, try again without prefetch. */ if (flags & RF_PREFETCHABLE) { flags &= ~RF_PREFETCHABLE; rle = resource_list_find(&hr->hr_rl, type, 0); goto restart; } return (NULL); } int pcib_host_res_adjust(struct pcib_host_resources *hr, device_t dev, int type, struct resource *r, u_long start, u_long end) { struct resource_list_entry *rle; rle = resource_list_find(&hr->hr_rl, type, 0); if (rle == NULL) { /* * No decoding ranges for this resource type, just pass * the request up to the parent. */ return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r, start, end)); } /* Only allow adjustments that stay within a decoded range. */ for (; rle != NULL; rle = STAILQ_NEXT(rle, link)) { if (rle->start <= start && rle->end >= end) return (bus_generic_adjust_resource(hr->hr_pcib, dev, type, r, start, end)); } return (ERANGE); } #endif /* NEW_PCIB */ Index: stable/9/sys/dev =================================================================== --- stable/9/sys/dev (revision 283926) +++ stable/9/sys/dev (revision 283927) Property changes on: stable/9/sys/dev ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/dev:r281887 Index: stable/9/sys/i386/include/vm.h =================================================================== --- stable/9/sys/i386/include/vm.h (revision 283926) +++ stable/9/sys/i386/include/vm.h (revision 283927) @@ -1,46 +1,46 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _MACHINE_VM_H_ #define _MACHINE_VM_H_ #include /* Memory attributes. */ #define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHEABLE) #define VM_MEMATTR_WRITE_COMBINING ((vm_memattr_t)PAT_WRITE_COMBINING) #define VM_MEMATTR_WRITE_THROUGH ((vm_memattr_t)PAT_WRITE_THROUGH) #define VM_MEMATTR_WRITE_PROTECTED ((vm_memattr_t)PAT_WRITE_PROTECTED) #define VM_MEMATTR_WRITE_BACK ((vm_memattr_t)PAT_WRITE_BACK) #define VM_MEMATTR_WEAK_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHED) #define VM_MEMATTR_UNCACHED VM_MEMATTR_WEAK_UNCACHEABLE #define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK #endif /* !_MACHINE_VM_H_ */ Index: stable/9/sys/sys/procctl.h =================================================================== --- stable/9/sys/sys/procctl.h (revision 283926) +++ stable/9/sys/sys/procctl.h (revision 283927) @@ -1,55 +1,55 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef _SYS_PROCCTL_H_ #define _SYS_PROCCTL_H_ #define PROC_SPROTECT 1 /* set protected state */ /* Operations for PROC_SPROTECT (passed in integer arg). */ #define PPROT_OP(x) ((x) & 0xf) #define PPROT_SET 1 #define PPROT_CLEAR 2 /* Flags for PROC_SPROTECT (ORed in with operation). */ #define PPROT_FLAGS(x) ((x) & ~0xf) #define PPROT_DESCEND 0x10 #define PPROT_INHERIT 0x20 #ifndef _KERNEL #include #include __BEGIN_DECLS int procctl(idtype_t, id_t, int, void *); __END_DECLS #endif #endif /* !_SYS_PROCCTL_H_ */ Index: stable/9/sys/sys =================================================================== --- stable/9/sys/sys (revision 283926) +++ stable/9/sys/sys (revision 283927) Property changes on: stable/9/sys/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/sys:r281887 Index: stable/9/sys/vm/sg_pager.c =================================================================== --- stable/9/sys/vm/sg_pager.c (revision 283926) +++ stable/9/sys/vm/sg_pager.c (revision 283927) @@ -1,216 +1,216 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); /* * This pager manages OBJT_SG objects. These objects are backed by * a scatter/gather list of physical address ranges. */ #include #include #include #include #include #include #include #include #include #include static vm_object_t sg_pager_alloc(void *, vm_ooffset_t, vm_prot_t, vm_ooffset_t, struct ucred *); static void sg_pager_dealloc(vm_object_t); static int sg_pager_getpages(vm_object_t, vm_page_t *, int, int); static void sg_pager_putpages(vm_object_t, vm_page_t *, int, boolean_t, int *); static boolean_t sg_pager_haspage(vm_object_t, vm_pindex_t, int *, int *); struct pagerops sgpagerops = { .pgo_alloc = sg_pager_alloc, .pgo_dealloc = sg_pager_dealloc, .pgo_getpages = sg_pager_getpages, .pgo_putpages = sg_pager_putpages, .pgo_haspage = sg_pager_haspage, }; static vm_object_t sg_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff, struct ucred *cred) { struct sglist *sg; vm_object_t object; vm_pindex_t npages, pindex; int i; /* * Offset should be page aligned. */ if (foff & PAGE_MASK) return (NULL); /* * The scatter/gather list must only include page-aligned * ranges. */ npages = 0; sg = handle; for (i = 0; i < sg->sg_nseg; i++) { if ((sg->sg_segs[i].ss_paddr % PAGE_SIZE) != 0 || (sg->sg_segs[i].ss_len % PAGE_SIZE) != 0) return (NULL); npages += sg->sg_segs[i].ss_len / PAGE_SIZE; } /* * The scatter/gather list has a fixed size. Refuse requests * to map beyond that. */ size = round_page(size); pindex = OFF_TO_IDX(foff + size); if (pindex > npages) return (NULL); /* * Allocate a new object and associate it with the * scatter/gather list. It is ok for our purposes to have * multiple VM objects associated with the same scatter/gather * list because scatter/gather lists are static. This is also * simpler than ensuring a unique object per scatter/gather * list. */ object = vm_object_allocate(OBJT_SG, npages); object->handle = sglist_hold(sg); TAILQ_INIT(&object->un_pager.sgp.sgp_pglist); return (object); } static void sg_pager_dealloc(vm_object_t object) { struct sglist *sg; vm_page_t m; /* * Free up our fake pages. */ while ((m = TAILQ_FIRST(&object->un_pager.sgp.sgp_pglist)) != 0) { TAILQ_REMOVE(&object->un_pager.sgp.sgp_pglist, m, pageq); vm_page_putfake(m); } sg = object->handle; sglist_free(sg); } static int sg_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage) { struct sglist *sg; vm_page_t m_paddr, page; vm_pindex_t offset; vm_paddr_t paddr; vm_memattr_t memattr; size_t space; int i; VM_OBJECT_LOCK_ASSERT(object, MA_OWNED); sg = object->handle; memattr = object->memattr; VM_OBJECT_UNLOCK(object); offset = m[reqpage]->pindex; /* * Lookup the physical address of the requested page. An initial * value of '1' instead of '0' is used so we can assert that the * page is found since '0' can be a valid page-aligned physical * address. */ space = 0; paddr = 1; for (i = 0; i < sg->sg_nseg; i++) { if (space + sg->sg_segs[i].ss_len <= (offset * PAGE_SIZE)) { space += sg->sg_segs[i].ss_len; continue; } paddr = sg->sg_segs[i].ss_paddr + offset * PAGE_SIZE - space; break; } KASSERT(paddr != 1, ("invalid SG page index")); /* If "paddr" is a real page, perform a sanity check on "memattr". */ if ((m_paddr = vm_phys_paddr_to_vm_page(paddr)) != NULL && pmap_page_get_memattr(m_paddr) != memattr) { memattr = pmap_page_get_memattr(m_paddr); printf( "WARNING: A device driver has set \"memattr\" inconsistently.\n"); } /* Return a fake page for the requested page. */ KASSERT(!(m[reqpage]->flags & PG_FICTITIOUS), ("backing page for SG is fake")); /* Construct a new fake page. */ page = vm_page_getfake(paddr, memattr); VM_OBJECT_LOCK(object); TAILQ_INSERT_TAIL(&object->un_pager.sgp.sgp_pglist, page, pageq); /* Free the original pages and insert this fake page into the object. */ for (i = 0; i < count; i++) { vm_page_lock(m[i]); vm_page_free(m[i]); vm_page_unlock(m[i]); } vm_page_insert(page, object, offset); m[reqpage] = page; page->valid = VM_PAGE_BITS_ALL; return (VM_PAGER_OK); } static void sg_pager_putpages(vm_object_t object, vm_page_t *m, int count, boolean_t sync, int *rtvals) { panic("sg_pager_putpage called"); } static boolean_t sg_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before, int *after) { if (before != NULL) *before = 0; if (after != NULL) *after = 0; return (TRUE); } Index: stable/9/sys/x86/acpica/srat.c =================================================================== --- stable/9/sys/x86/acpica/srat.c (revision 283926) +++ stable/9/sys/x86/acpica/srat.c (revision 283927) @@ -1,365 +1,365 @@ /*- - * Copyright (c) 2010 Advanced Computing Technologies LLC + * Copyright (c) 2010 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include "opt_vm.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #if VM_NDOMAIN > 1 struct cpu_info { int enabled:1; int has_memory:1; int domain; } cpus[MAX_APIC_ID + 1]; struct mem_affinity mem_info[VM_PHYSSEG_MAX + 1]; int num_mem; static ACPI_TABLE_SRAT *srat; static vm_paddr_t srat_physaddr; static void srat_walk_table(acpi_subtable_handler *handler, void *arg); /* * Returns true if a memory range overlaps with at least one range in * phys_avail[]. */ static int overlaps_phys_avail(vm_paddr_t start, vm_paddr_t end) { int i; for (i = 0; phys_avail[i] != 0 && phys_avail[i + 1] != 0; i += 2) { if (phys_avail[i + 1] < start) continue; if (phys_avail[i] < end) return (1); break; } return (0); } static void srat_parse_entry(ACPI_SUBTABLE_HEADER *entry, void *arg) { ACPI_SRAT_CPU_AFFINITY *cpu; ACPI_SRAT_X2APIC_CPU_AFFINITY *x2apic; ACPI_SRAT_MEM_AFFINITY *mem; int domain, i, slot; switch (entry->Type) { case ACPI_SRAT_TYPE_CPU_AFFINITY: cpu = (ACPI_SRAT_CPU_AFFINITY *)entry; domain = cpu->ProximityDomainLo | cpu->ProximityDomainHi[0] << 8 | cpu->ProximityDomainHi[1] << 16 | cpu->ProximityDomainHi[2] << 24; if (bootverbose) printf("SRAT: Found CPU APIC ID %u domain %d: %s\n", cpu->ApicId, domain, (cpu->Flags & ACPI_SRAT_CPU_ENABLED) ? "enabled" : "disabled"); if (!(cpu->Flags & ACPI_SRAT_CPU_ENABLED)) break; KASSERT(!cpus[cpu->ApicId].enabled, ("Duplicate local APIC ID %u", cpu->ApicId)); cpus[cpu->ApicId].domain = domain; cpus[cpu->ApicId].enabled = 1; break; case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: x2apic = (ACPI_SRAT_X2APIC_CPU_AFFINITY *)entry; if (bootverbose) printf("SRAT: Found CPU APIC ID %u domain %d: %s\n", x2apic->ApicId, x2apic->ProximityDomain, (x2apic->Flags & ACPI_SRAT_CPU_ENABLED) ? "enabled" : "disabled"); if (!(x2apic->Flags & ACPI_SRAT_CPU_ENABLED)) break; KASSERT(!cpus[x2apic->ApicId].enabled, ("Duplicate local APIC ID %u", x2apic->ApicId)); cpus[x2apic->ApicId].domain = x2apic->ProximityDomain; cpus[x2apic->ApicId].enabled = 1; break; case ACPI_SRAT_TYPE_MEMORY_AFFINITY: mem = (ACPI_SRAT_MEM_AFFINITY *)entry; if (bootverbose) printf( "SRAT: Found memory domain %d addr %jx len %jx: %s\n", mem->ProximityDomain, (uintmax_t)mem->BaseAddress, (uintmax_t)mem->Length, (mem->Flags & ACPI_SRAT_MEM_ENABLED) ? "enabled" : "disabled"); if (!(mem->Flags & ACPI_SRAT_MEM_ENABLED)) break; if (!overlaps_phys_avail(mem->BaseAddress, mem->BaseAddress + mem->Length)) { printf("SRAT: Ignoring memory at addr %jx\n", (uintmax_t)mem->BaseAddress); break; } if (num_mem == VM_PHYSSEG_MAX) { printf("SRAT: Too many memory regions\n"); *(int *)arg = ENXIO; break; } slot = num_mem; for (i = 0; i < num_mem; i++) { if (mem_info[i].end <= mem->BaseAddress) continue; if (mem_info[i].start < (mem->BaseAddress + mem->Length)) { printf("SRAT: Overlapping memory entries\n"); *(int *)arg = ENXIO; return; } slot = i; } for (i = num_mem; i > slot; i--) mem_info[i] = mem_info[i - 1]; mem_info[slot].start = mem->BaseAddress; mem_info[slot].end = mem->BaseAddress + mem->Length; mem_info[slot].domain = mem->ProximityDomain; num_mem++; break; } } /* * Ensure each memory domain has at least one CPU and that each CPU * has at least one memory domain. */ static int check_domains(void) { int found, i, j; for (i = 0; i < num_mem; i++) { found = 0; for (j = 0; j <= MAX_APIC_ID; j++) if (cpus[j].enabled && cpus[j].domain == mem_info[i].domain) { cpus[j].has_memory = 1; found++; } if (!found) { printf("SRAT: No CPU found for memory domain %d\n", mem_info[i].domain); return (ENXIO); } } for (i = 0; i <= MAX_APIC_ID; i++) if (cpus[i].enabled && !cpus[i].has_memory) { printf("SRAT: No memory found for CPU %d\n", i); return (ENXIO); } return (0); } /* * Check that the SRAT memory regions cover all of the regions in * phys_avail[]. */ static int check_phys_avail(void) { vm_paddr_t address; int i, j; /* j is the current offset into phys_avail[]. */ address = phys_avail[0]; j = 0; for (i = 0; i < num_mem; i++) { /* * Consume as many phys_avail[] entries as fit in this * region. */ while (address >= mem_info[i].start && address <= mem_info[i].end) { /* * If we cover the rest of this phys_avail[] entry, * advance to the next entry. */ if (phys_avail[j + 1] <= mem_info[i].end) { j += 2; if (phys_avail[j] == 0 && phys_avail[j + 1] == 0) { return (0); } address = phys_avail[j]; } else address = mem_info[i].end + 1; } } printf("SRAT: No memory region found for %jx - %jx\n", (uintmax_t)phys_avail[j], (uintmax_t)phys_avail[j + 1]); return (ENXIO); } /* * Renumber the memory domains to be compact and zero-based if not * already. Returns an error if there are too many domains. */ static int renumber_domains(void) { int domains[VM_PHYSSEG_MAX]; int ndomain, i, j, slot; /* Enumerate all the domains. */ ndomain = 0; for (i = 0; i < num_mem; i++) { /* See if this domain is already known. */ for (j = 0; j < ndomain; j++) { if (domains[j] >= mem_info[i].domain) break; } if (j < ndomain && domains[j] == mem_info[i].domain) continue; /* Insert the new domain at slot 'j'. */ slot = j; for (j = ndomain; j > slot; j--) domains[j] = domains[j - 1]; domains[slot] = mem_info[i].domain; ndomain++; if (ndomain > VM_NDOMAIN) { printf("SRAT: Too many memory domains\n"); return (EFBIG); } } /* Renumber each domain to its index in the sorted 'domains' list. */ for (i = 0; i < ndomain; i++) { /* * If the domain is already the right value, no need * to renumber. */ if (domains[i] == i) continue; /* Walk the cpu[] and mem_info[] arrays to renumber. */ for (j = 0; j < num_mem; j++) if (mem_info[j].domain == domains[i]) mem_info[j].domain = i; for (j = 0; j <= MAX_APIC_ID; j++) if (cpus[j].enabled && cpus[j].domain == domains[i]) cpus[j].domain = i; } return (0); } /* * Look for an ACPI System Resource Affinity Table ("SRAT") */ static void parse_srat(void *dummy) { int error; if (resource_disabled("srat", 0)) return; srat_physaddr = acpi_find_table(ACPI_SIG_SRAT); if (srat_physaddr == 0) return; /* * Make a pass over the table to populate the cpus[] and * mem_info[] tables. */ srat = acpi_map_table(srat_physaddr, ACPI_SIG_SRAT); error = 0; srat_walk_table(srat_parse_entry, &error); acpi_unmap_table(srat); srat = NULL; if (error || check_domains() != 0 || check_phys_avail() != 0 || renumber_domains() != 0) { srat_physaddr = 0; return; } /* Point vm_phys at our memory affinity table. */ mem_affinity = mem_info; } SYSINIT(parse_srat, SI_SUB_VM - 1, SI_ORDER_FIRST, parse_srat, NULL); static void srat_walk_table(acpi_subtable_handler *handler, void *arg) { acpi_walk_subtables(srat + 1, (char *)srat + srat->Header.Length, handler, arg); } /* * Setup per-CPU ACPI IDs. */ static void srat_set_cpus(void *dummy) { struct cpu_info *cpu; struct pcpu *pc; u_int i; if (srat_physaddr == 0) return; for (i = 0; i < MAXCPU; i++) { if (CPU_ABSENT(i)) continue; pc = pcpu_find(i); KASSERT(pc != NULL, ("no pcpu data for CPU %u", i)); cpu = &cpus[pc->pc_apic_id]; if (!cpu->enabled) panic("SRAT: CPU with APIC ID %u is not known", pc->pc_apic_id); pc->pc_domain = cpu->domain; if (bootverbose) printf("SRAT: CPU %u has memory domain %d\n", i, cpu->domain); } } SYSINIT(srat_set_cpus, SI_SUB_CPU, SI_ORDER_ANY, srat_set_cpus, NULL); #endif /* VM_NDOMAIN > 1 */ Index: stable/9/sys/x86/include/mca.h =================================================================== --- stable/9/sys/x86/include/mca.h (revision 283926) +++ stable/9/sys/x86/include/mca.h (revision 283927) @@ -1,56 +1,56 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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$ */ #ifndef __X86_MCA_H__ #define __X86_MCA_H__ struct mca_record { uint64_t mr_status; uint64_t mr_addr; uint64_t mr_misc; uint64_t mr_tsc; int mr_apic_id; int mr_bank; uint64_t mr_mcg_cap; uint64_t mr_mcg_status; int mr_cpu_id; int mr_cpu_vendor_id; int mr_cpu; }; #ifdef _KERNEL void cmc_intr(void); void mca_init(void); void mca_intr(void); void mca_resume(void); #endif #endif /* !__X86_MCA_H__ */ Index: stable/9/sys/x86/pci/qpi.c =================================================================== --- stable/9/sys/x86/pci/qpi.c (revision 283926) +++ stable/9/sys/x86/pci/qpi.c (revision 283927) @@ -1,319 +1,319 @@ /*- - * Copyright (c) 2010 Advanced Computing Technologies LLC + * Copyright (c) 2010 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ /* * This driver provides a psuedo-bus to enumerate the PCI buses * present on a sytem using a QPI chipset. It creates a qpi0 bus that * is a child of nexus0 and then creates two Host-PCI bridges as a * child of that. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" struct qpi_device { int qd_pcibus; }; static MALLOC_DEFINE(M_QPI, "qpidrv", "qpi system device"); static void qpi_identify(driver_t *driver, device_t parent) { /* Check CPUID to ensure this is an i7 CPU of some sort. */ if (!(cpu_vendor_id == CPU_VENDOR_INTEL && CPUID_TO_FAMILY(cpu_id) == 0x6 && (CPUID_TO_MODEL(cpu_id) == 0x1a || CPUID_TO_MODEL(cpu_id) == 0x2c))) return; /* PCI config register access is required. */ if (pci_cfgregopen() == 0) return; /* Add a qpi bus device. */ if (BUS_ADD_CHILD(parent, 20, "qpi", -1) == NULL) panic("Failed to add qpi bus"); } static int qpi_probe(device_t dev) { device_set_desc(dev, "QPI system bus"); return (BUS_PROBE_SPECIFIC); } /* * Look for a PCI bus with the specified bus address. If one is found, * add a pcib device and return 0. Otherwise, return an error code. */ static int qpi_probe_pcib(device_t dev, int bus) { struct qpi_device *qdev; device_t child; uint32_t devid; /* * If a PCI bus already exists for this bus number, then * fail. */ if (pci_find_bsf(bus, 0, 0) != NULL) return (EEXIST); /* * Attempt to read the device id for device 0, function 0 on * the bus. A value of 0xffffffff means that the bus is not * present. */ devid = pci_cfgregread(bus, 0, 0, PCIR_DEVVENDOR, 4); if (devid == 0xffffffff) return (ENOENT); if ((devid & 0xffff) != 0x8086) { device_printf(dev, "Device at pci%d.0.0 has non-Intel vendor 0x%x\n", bus, devid & 0xffff); return (ENXIO); } child = BUS_ADD_CHILD(dev, 0, "pcib", -1); if (child == NULL) panic("%s: failed to add pci bus %d", device_get_nameunit(dev), bus); qdev = malloc(sizeof(struct qpi_device), M_QPI, M_WAITOK); qdev->qd_pcibus = bus; device_set_ivars(child, qdev); return (0); } static int qpi_attach(device_t dev) { int bus; /* * Each processor socket has a dedicated PCI bus counting down from * 255. We keep probing buses until one fails. */ for (bus = 255;; bus--) if (qpi_probe_pcib(dev, bus) != 0) break; return (bus_generic_attach(dev)); } static int qpi_print_child(device_t bus, device_t child) { struct qpi_device *qdev; int retval = 0; qdev = device_get_ivars(child); retval += bus_print_child_header(bus, child); if (qdev->qd_pcibus != -1) retval += printf(" pcibus %d", qdev->qd_pcibus); retval += bus_print_child_footer(bus, child); return (retval); } static int qpi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct qpi_device *qdev; qdev = device_get_ivars(child); switch (which) { case PCIB_IVAR_BUS: *result = qdev->qd_pcibus; break; default: return (ENOENT); } return (0); } static device_method_t qpi_methods[] = { /* Device interface */ DEVMETHOD(device_identify, qpi_identify), DEVMETHOD(device_probe, qpi_probe), DEVMETHOD(device_attach, qpi_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, qpi_print_child), DEVMETHOD(bus_add_child, bus_generic_add_child), DEVMETHOD(bus_read_ivar, qpi_read_ivar), DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), { 0, 0 } }; static devclass_t qpi_devclass; DEFINE_CLASS_0(qpi, qpi_driver, qpi_methods, 0); DRIVER_MODULE(qpi, nexus, qpi_driver, qpi_devclass, 0, 0); static int qpi_pcib_probe(device_t dev) { device_set_desc(dev, "QPI Host-PCI bridge"); return (BUS_PROBE_SPECIFIC); } static int qpi_pcib_attach(device_t dev) { device_add_child(dev, "pci", pcib_get_bus(dev)); return (bus_generic_attach(dev)); } static int qpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = pcib_get_bus(dev); return (0); default: return (ENOENT); } } static uint32_t qpi_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { return (pci_cfgregread(bus, slot, func, reg, bytes)); } static void qpi_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t data, int bytes) { pci_cfgregwrite(bus, slot, func, reg, data, bytes); } static int qpi_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) { device_t bus; bus = device_get_parent(pcib); return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, irqs)); } static int qpi_pcib_alloc_msix(device_t pcib, device_t dev, int *irq) { device_t bus; bus = device_get_parent(pcib); return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); } static int qpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data) { device_t bus; bus = device_get_parent(pcib); return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); } static device_method_t qpi_pcib_methods[] = { /* Device interface */ DEVMETHOD(device_probe, qpi_pcib_probe), DEVMETHOD(device_attach, qpi_pcib_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, qpi_pcib_read_ivar), DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, pcib_maxslots), DEVMETHOD(pcib_read_config, qpi_pcib_read_config), DEVMETHOD(pcib_write_config, qpi_pcib_write_config), DEVMETHOD(pcib_alloc_msi, qpi_pcib_alloc_msi), DEVMETHOD(pcib_release_msi, pcib_release_msi), DEVMETHOD(pcib_alloc_msix, qpi_pcib_alloc_msix), DEVMETHOD(pcib_release_msix, pcib_release_msix), DEVMETHOD(pcib_map_msi, qpi_pcib_map_msi), DEVMETHOD_END }; static devclass_t qpi_pcib_devclass; DEFINE_CLASS_0(pcib, qpi_pcib_driver, qpi_pcib_methods, 0); DRIVER_MODULE(pcib, qpi, qpi_pcib_driver, qpi_pcib_devclass, 0, 0); Index: stable/9/sys/x86/x86/mca.c =================================================================== --- stable/9/sys/x86/x86/mca.c (revision 283926) +++ stable/9/sys/x86/x86/mca.c (revision 283927) @@ -1,1034 +1,1034 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ /* * Support for x86 machine check architecture. */ #include __FBSDID("$FreeBSD$"); #ifdef __amd64__ #define DEV_APIC #else #include "opt_apic.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Modes for mca_scan() */ enum scan_mode { POLLED, MCE, CMCI, }; #ifdef DEV_APIC /* * State maintained for each monitored MCx bank to control the * corrected machine check interrupt threshold. */ struct cmc_state { int max_threshold; int last_intr; }; #endif struct mca_internal { struct mca_record rec; int logged; STAILQ_ENTRY(mca_internal) link; }; static MALLOC_DEFINE(M_MCA, "MCA", "Machine Check Architecture"); static volatile int mca_count; /* Number of records stored. */ static int mca_banks; /* Number of per-CPU register banks. */ static SYSCTL_NODE(_hw, OID_AUTO, mca, CTLFLAG_RD, NULL, "Machine Check Architecture"); static int mca_enabled = 1; TUNABLE_INT("hw.mca.enabled", &mca_enabled); SYSCTL_INT(_hw_mca, OID_AUTO, enabled, CTLFLAG_RDTUN, &mca_enabled, 0, "Administrative toggle for machine check support"); static int amd10h_L1TP = 1; TUNABLE_INT("hw.mca.amd10h_L1TP", &amd10h_L1TP); SYSCTL_INT(_hw_mca, OID_AUTO, amd10h_L1TP, CTLFLAG_RDTUN, &amd10h_L1TP, 0, "Administrative toggle for logging of level one TLB parity (L1TP) errors"); static int intel6h_HSD131; TUNABLE_INT("hw.mca.intel6h_hsd131", &intel6h_HSD131); SYSCTL_INT(_hw_mca, OID_AUTO, intel6h_HSD131, CTLFLAG_RDTUN, &intel6h_HSD131, 0, "Administrative toggle for logging of spurious corrected errors"); int workaround_erratum383; SYSCTL_INT(_hw_mca, OID_AUTO, erratum383, CTLFLAG_RD, &workaround_erratum383, 0, "Is the workaround for Erratum 383 on AMD Family 10h processors enabled?"); static STAILQ_HEAD(, mca_internal) mca_freelist; static int mca_freecount; static STAILQ_HEAD(, mca_internal) mca_records; static struct callout mca_timer; static int mca_ticks = 3600; /* Check hourly by default. */ static struct taskqueue *mca_tq; static struct task mca_refill_task, mca_scan_task; static struct mtx mca_lock; #ifdef DEV_APIC static struct cmc_state **cmc_state; /* Indexed by cpuid, bank */ static int cmc_throttle = 60; /* Time in seconds to throttle CMCI. */ #endif static int sysctl_positive_int(SYSCTL_HANDLER_ARGS) { int error, value; value = *(int *)arg1; error = sysctl_handle_int(oidp, &value, 0, req); if (error || req->newptr == NULL) return (error); if (value <= 0) return (EINVAL); *(int *)arg1 = value; return (0); } static int sysctl_mca_records(SYSCTL_HANDLER_ARGS) { int *name = (int *)arg1; u_int namelen = arg2; struct mca_record record; struct mca_internal *rec; int i; if (namelen != 1) return (EINVAL); if (name[0] < 0 || name[0] >= mca_count) return (EINVAL); mtx_lock_spin(&mca_lock); if (name[0] >= mca_count) { mtx_unlock_spin(&mca_lock); return (EINVAL); } i = 0; STAILQ_FOREACH(rec, &mca_records, link) { if (i == name[0]) { record = rec->rec; break; } i++; } mtx_unlock_spin(&mca_lock); return (SYSCTL_OUT(req, &record, sizeof(record))); } static const char * mca_error_ttype(uint16_t mca_error) { switch ((mca_error & 0x000c) >> 2) { case 0: return ("I"); case 1: return ("D"); case 2: return ("G"); } return ("?"); } static const char * mca_error_level(uint16_t mca_error) { switch (mca_error & 0x0003) { case 0: return ("L0"); case 1: return ("L1"); case 2: return ("L2"); case 3: return ("LG"); } return ("L?"); } static const char * mca_error_request(uint16_t mca_error) { switch ((mca_error & 0x00f0) >> 4) { case 0x0: return ("ERR"); case 0x1: return ("RD"); case 0x2: return ("WR"); case 0x3: return ("DRD"); case 0x4: return ("DWR"); case 0x5: return ("IRD"); case 0x6: return ("PREFETCH"); case 0x7: return ("EVICT"); case 0x8: return ("SNOOP"); } return ("???"); } static const char * mca_error_mmtype(uint16_t mca_error) { switch ((mca_error & 0x70) >> 4) { case 0x0: return ("GEN"); case 0x1: return ("RD"); case 0x2: return ("WR"); case 0x3: return ("AC"); case 0x4: return ("MS"); } return ("???"); } static int __nonnull(1) mca_mute(const struct mca_record *rec) { /* * Skip spurious corrected parity errors generated by desktop Haswell * (see HSD131 erratum) unless reporting is enabled. * Note that these errors also have been observed with D0-stepping, * while the revision 014 desktop Haswell specification update only * talks about C0-stepping. */ if (rec->mr_cpu_vendor_id == CPU_VENDOR_INTEL && rec->mr_cpu_id == 0x306c3 && rec->mr_bank == 0 && rec->mr_status == 0x90000040000f0005 && !intel6h_HSD131) return (1); return (0); } /* Dump details about a single machine check. */ static void __nonnull(1) mca_log(const struct mca_record *rec) { uint16_t mca_error; if (mca_mute(rec)) return; printf("MCA: Bank %d, Status 0x%016llx\n", rec->mr_bank, (long long)rec->mr_status); printf("MCA: Global Cap 0x%016llx, Status 0x%016llx\n", (long long)rec->mr_mcg_cap, (long long)rec->mr_mcg_status); printf("MCA: Vendor \"%s\", ID 0x%x, APIC ID %d\n", cpu_vendor, rec->mr_cpu_id, rec->mr_apic_id); printf("MCA: CPU %d ", rec->mr_cpu); if (rec->mr_status & MC_STATUS_UC) printf("UNCOR "); else { printf("COR "); if (rec->mr_mcg_cap & MCG_CAP_CMCI_P) printf("(%lld) ", ((long long)rec->mr_status & MC_STATUS_COR_COUNT) >> 38); } if (rec->mr_status & MC_STATUS_PCC) printf("PCC "); if (rec->mr_status & MC_STATUS_OVER) printf("OVER "); mca_error = rec->mr_status & MC_STATUS_MCA_ERROR; switch (mca_error) { /* Simple error codes. */ case 0x0000: printf("no error"); break; case 0x0001: printf("unclassified error"); break; case 0x0002: printf("ucode ROM parity error"); break; case 0x0003: printf("external error"); break; case 0x0004: printf("FRC error"); break; case 0x0005: printf("internal parity error"); break; case 0x0400: printf("internal timer error"); break; default: if ((mca_error & 0xfc00) == 0x0400) { printf("internal error %x", mca_error & 0x03ff); break; } /* Compound error codes. */ /* Memory hierarchy error. */ if ((mca_error & 0xeffc) == 0x000c) { printf("%s memory error", mca_error_level(mca_error)); break; } /* TLB error. */ if ((mca_error & 0xeff0) == 0x0010) { printf("%sTLB %s error", mca_error_ttype(mca_error), mca_error_level(mca_error)); break; } /* Memory controller error. */ if ((mca_error & 0xef80) == 0x0080) { printf("%s channel ", mca_error_mmtype(mca_error)); if ((mca_error & 0x000f) != 0x000f) printf("%d", mca_error & 0x000f); else printf("??"); printf(" memory error"); break; } /* Cache error. */ if ((mca_error & 0xef00) == 0x0100) { printf("%sCACHE %s %s error", mca_error_ttype(mca_error), mca_error_level(mca_error), mca_error_request(mca_error)); break; } /* Bus and/or Interconnect error. */ if ((mca_error & 0xe800) == 0x0800) { printf("BUS%s ", mca_error_level(mca_error)); switch ((mca_error & 0x0600) >> 9) { case 0: printf("Source"); break; case 1: printf("Responder"); break; case 2: printf("Observer"); break; default: printf("???"); break; } printf(" %s ", mca_error_request(mca_error)); switch ((mca_error & 0x000c) >> 2) { case 0: printf("Memory"); break; case 2: printf("I/O"); break; case 3: printf("Other"); break; default: printf("???"); break; } if (mca_error & 0x0100) printf(" timed out"); break; } printf("unknown error %x", mca_error); break; } printf("\n"); if (rec->mr_status & MC_STATUS_ADDRV) printf("MCA: Address 0x%llx\n", (long long)rec->mr_addr); if (rec->mr_status & MC_STATUS_MISCV) printf("MCA: Misc 0x%llx\n", (long long)rec->mr_misc); } static int __nonnull(2) mca_check_status(int bank, struct mca_record *rec) { uint64_t status; u_int p[4]; status = rdmsr(MSR_MC_STATUS(bank)); if (!(status & MC_STATUS_VAL)) return (0); /* Save exception information. */ rec->mr_status = status; rec->mr_bank = bank; rec->mr_addr = 0; if (status & MC_STATUS_ADDRV) rec->mr_addr = rdmsr(MSR_MC_ADDR(bank)); rec->mr_misc = 0; if (status & MC_STATUS_MISCV) rec->mr_misc = rdmsr(MSR_MC_MISC(bank)); rec->mr_tsc = rdtsc(); rec->mr_apic_id = PCPU_GET(apic_id); rec->mr_mcg_cap = rdmsr(MSR_MCG_CAP); rec->mr_mcg_status = rdmsr(MSR_MCG_STATUS); rec->mr_cpu_id = cpu_id; rec->mr_cpu_vendor_id = cpu_vendor_id; rec->mr_cpu = PCPU_GET(cpuid); /* * Clear machine check. Don't do this for uncorrectable * errors so that the BIOS can see them. */ if (!(rec->mr_status & (MC_STATUS_PCC | MC_STATUS_UC))) { wrmsr(MSR_MC_STATUS(bank), 0); do_cpuid(0, p); } return (1); } static void mca_fill_freelist(void) { struct mca_internal *rec; int desired; /* * Ensure we have at least one record for each bank and one * record per CPU. */ desired = imax(mp_ncpus, mca_banks); mtx_lock_spin(&mca_lock); while (mca_freecount < desired) { mtx_unlock_spin(&mca_lock); rec = malloc(sizeof(*rec), M_MCA, M_WAITOK); mtx_lock_spin(&mca_lock); STAILQ_INSERT_TAIL(&mca_freelist, rec, link); mca_freecount++; } mtx_unlock_spin(&mca_lock); } static void mca_refill(void *context, int pending) { mca_fill_freelist(); } static void __nonnull(2) mca_record_entry(enum scan_mode mode, const struct mca_record *record) { struct mca_internal *rec; if (mode == POLLED) { rec = malloc(sizeof(*rec), M_MCA, M_WAITOK); mtx_lock_spin(&mca_lock); } else { mtx_lock_spin(&mca_lock); rec = STAILQ_FIRST(&mca_freelist); if (rec == NULL) { printf("MCA: Unable to allocate space for an event.\n"); mca_log(record); mtx_unlock_spin(&mca_lock); return; } STAILQ_REMOVE_HEAD(&mca_freelist, link); mca_freecount--; } rec->rec = *record; rec->logged = 0; STAILQ_INSERT_TAIL(&mca_records, rec, link); mca_count++; mtx_unlock_spin(&mca_lock); if (mode == CMCI) taskqueue_enqueue_fast(mca_tq, &mca_refill_task); } #ifdef DEV_APIC /* * Update the interrupt threshold for a CMCI. The strategy is to use * a low trigger that interrupts as soon as the first event occurs. * However, if a steady stream of events arrive, the threshold is * increased until the interrupts are throttled to once every * cmc_throttle seconds or the periodic scan. If a periodic scan * finds that the threshold is too high, it is lowered. */ static void cmci_update(enum scan_mode mode, int bank, int valid, struct mca_record *rec) { struct cmc_state *cc; uint64_t ctl; u_int delta; int count, limit; /* Fetch the current limit for this bank. */ cc = &cmc_state[PCPU_GET(cpuid)][bank]; ctl = rdmsr(MSR_MC_CTL2(bank)); count = (rec->mr_status & MC_STATUS_COR_COUNT) >> 38; delta = (u_int)(ticks - cc->last_intr); /* * If an interrupt was received less than cmc_throttle seconds * since the previous interrupt and the count from the current * event is greater than or equal to the current threshold, * double the threshold up to the max. */ if (mode == CMCI && valid) { limit = ctl & MC_CTL2_THRESHOLD; if (delta < cmc_throttle && count >= limit && limit < cc->max_threshold) { limit = min(limit << 1, cc->max_threshold); ctl &= ~MC_CTL2_THRESHOLD; ctl |= limit; wrmsr(MSR_MC_CTL2(bank), limit); } cc->last_intr = ticks; return; } /* * When the banks are polled, check to see if the threshold * should be lowered. */ if (mode != POLLED) return; /* If a CMCI occured recently, do nothing for now. */ if (delta < cmc_throttle) return; /* * Compute a new limit based on the average rate of events per * cmc_throttle seconds since the last interrupt. */ if (valid) { count = (rec->mr_status & MC_STATUS_COR_COUNT) >> 38; limit = count * cmc_throttle / delta; if (limit <= 0) limit = 1; else if (limit > cc->max_threshold) limit = cc->max_threshold; } else limit = 1; if ((ctl & MC_CTL2_THRESHOLD) != limit) { ctl &= ~MC_CTL2_THRESHOLD; ctl |= limit; wrmsr(MSR_MC_CTL2(bank), limit); } } #endif /* * This scans all the machine check banks of the current CPU to see if * there are any machine checks. Any non-recoverable errors are * reported immediately via mca_log(). The current thread must be * pinned when this is called. The 'mode' parameter indicates if we * are being called from the MC exception handler, the CMCI handler, * or the periodic poller. In the MC exception case this function * returns true if the system is restartable. Otherwise, it returns a * count of the number of valid MC records found. */ static int mca_scan(enum scan_mode mode) { struct mca_record rec; uint64_t mcg_cap, ucmask; int count, i, recoverable, valid; count = 0; recoverable = 1; ucmask = MC_STATUS_UC | MC_STATUS_PCC; /* When handling a MCE#, treat the OVER flag as non-restartable. */ if (mode == MCE) ucmask |= MC_STATUS_OVER; mcg_cap = rdmsr(MSR_MCG_CAP); for (i = 0; i < (mcg_cap & MCG_CAP_COUNT); i++) { #ifdef DEV_APIC /* * For a CMCI, only check banks this CPU is * responsible for. */ if (mode == CMCI && !(PCPU_GET(cmci_mask) & 1 << i)) continue; #endif valid = mca_check_status(i, &rec); if (valid) { count++; if (rec.mr_status & ucmask) { recoverable = 0; mtx_lock_spin(&mca_lock); mca_log(&rec); mtx_unlock_spin(&mca_lock); } mca_record_entry(mode, &rec); } #ifdef DEV_APIC /* * If this is a bank this CPU monitors via CMCI, * update the threshold. */ if (PCPU_GET(cmci_mask) & 1 << i) cmci_update(mode, i, valid, &rec); #endif } if (mode == POLLED) mca_fill_freelist(); return (mode == MCE ? recoverable : count); } /* * Scan the machine check banks on all CPUs by binding to each CPU in * turn. If any of the CPUs contained new machine check records, log * them to the console. */ static void mca_scan_cpus(void *context, int pending) { struct mca_internal *mca; struct thread *td; int count, cpu; mca_fill_freelist(); td = curthread; count = 0; thread_lock(td); CPU_FOREACH(cpu) { sched_bind(td, cpu); thread_unlock(td); count += mca_scan(POLLED); thread_lock(td); sched_unbind(td); } thread_unlock(td); if (count != 0) { mtx_lock_spin(&mca_lock); STAILQ_FOREACH(mca, &mca_records, link) { if (!mca->logged) { mca->logged = 1; mca_log(&mca->rec); } } mtx_unlock_spin(&mca_lock); } } static void mca_periodic_scan(void *arg) { taskqueue_enqueue_fast(mca_tq, &mca_scan_task); callout_reset(&mca_timer, mca_ticks * hz, mca_periodic_scan, NULL); } static int sysctl_mca_scan(SYSCTL_HANDLER_ARGS) { int error, i; i = 0; error = sysctl_handle_int(oidp, &i, 0, req); if (error) return (error); if (i) taskqueue_enqueue_fast(mca_tq, &mca_scan_task); return (0); } static void mca_createtq(void *dummy) { if (mca_banks <= 0) return; mca_tq = taskqueue_create_fast("mca", M_WAITOK, taskqueue_thread_enqueue, &mca_tq); taskqueue_start_threads(&mca_tq, 1, PI_SWI(SWI_TQ), "mca taskq"); } SYSINIT(mca_createtq, SI_SUB_CONFIGURE, SI_ORDER_ANY, mca_createtq, NULL); static void mca_startup(void *dummy) { if (mca_banks <= 0) return; callout_reset(&mca_timer, mca_ticks * hz, mca_periodic_scan, NULL); } SYSINIT(mca_startup, SI_SUB_SMP, SI_ORDER_ANY, mca_startup, NULL); #ifdef DEV_APIC static void cmci_setup(void) { int i; cmc_state = malloc((mp_maxid + 1) * sizeof(struct cmc_state *), M_MCA, M_WAITOK); for (i = 0; i <= mp_maxid; i++) cmc_state[i] = malloc(sizeof(struct cmc_state) * mca_banks, M_MCA, M_WAITOK | M_ZERO); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "cmc_throttle", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &cmc_throttle, 0, sysctl_positive_int, "I", "Interval in seconds to throttle corrected MC interrupts"); } #endif static void mca_setup(uint64_t mcg_cap) { /* * On AMD Family 10h processors, unless logging of level one TLB * parity (L1TP) errors is disabled, enable the recommended workaround * for Erratum 383. */ if (cpu_vendor_id == CPU_VENDOR_AMD && CPUID_TO_FAMILY(cpu_id) == 0x10 && amd10h_L1TP) workaround_erratum383 = 1; mca_banks = mcg_cap & MCG_CAP_COUNT; mtx_init(&mca_lock, "mca", NULL, MTX_SPIN); STAILQ_INIT(&mca_records); TASK_INIT(&mca_scan_task, 0, mca_scan_cpus, NULL); callout_init(&mca_timer, CALLOUT_MPSAFE); STAILQ_INIT(&mca_freelist); TASK_INIT(&mca_refill_task, 0, mca_refill, NULL); mca_fill_freelist(); SYSCTL_ADD_INT(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "count", CTLFLAG_RD, (int *)(uintptr_t)&mca_count, 0, "Record count"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "interval", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &mca_ticks, 0, sysctl_positive_int, "I", "Periodic interval in seconds to scan for machine checks"); SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "records", CTLFLAG_RD, sysctl_mca_records, "Machine check records"); SYSCTL_ADD_PROC(NULL, SYSCTL_STATIC_CHILDREN(_hw_mca), OID_AUTO, "force_scan", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0, sysctl_mca_scan, "I", "Force an immediate scan for machine checks"); #ifdef DEV_APIC if (mcg_cap & MCG_CAP_CMCI_P) cmci_setup(); #endif } #ifdef DEV_APIC /* * See if we should monitor CMCI for this bank. If CMCI_EN is already * set in MC_CTL2, then another CPU is responsible for this bank, so * ignore it. If CMCI_EN returns zero after being set, then this bank * does not support CMCI_EN. If this CPU sets CMCI_EN, then it should * now monitor this bank. */ static void cmci_monitor(int i) { struct cmc_state *cc; uint64_t ctl; KASSERT(i < mca_banks, ("CPU %d has more MC banks", PCPU_GET(cpuid))); ctl = rdmsr(MSR_MC_CTL2(i)); if (ctl & MC_CTL2_CMCI_EN) /* Already monitored by another CPU. */ return; /* Set the threshold to one event for now. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= MC_CTL2_CMCI_EN | 1; wrmsr(MSR_MC_CTL2(i), ctl); ctl = rdmsr(MSR_MC_CTL2(i)); if (!(ctl & MC_CTL2_CMCI_EN)) /* This bank does not support CMCI. */ return; cc = &cmc_state[PCPU_GET(cpuid)][i]; /* Determine maximum threshold. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= 0x7fff; wrmsr(MSR_MC_CTL2(i), ctl); ctl = rdmsr(MSR_MC_CTL2(i)); cc->max_threshold = ctl & MC_CTL2_THRESHOLD; /* Start off with a threshold of 1. */ ctl &= ~MC_CTL2_THRESHOLD; ctl |= 1; wrmsr(MSR_MC_CTL2(i), ctl); /* Mark this bank as monitored. */ PCPU_SET(cmci_mask, PCPU_GET(cmci_mask) | 1 << i); } /* * For resume, reset the threshold for any banks we monitor back to * one and throw away the timestamp of the last interrupt. */ static void cmci_resume(int i) { struct cmc_state *cc; uint64_t ctl; KASSERT(i < mca_banks, ("CPU %d has more MC banks", PCPU_GET(cpuid))); /* Ignore banks not monitored by this CPU. */ if (!(PCPU_GET(cmci_mask) & 1 << i)) return; cc = &cmc_state[PCPU_GET(cpuid)][i]; cc->last_intr = -ticks; ctl = rdmsr(MSR_MC_CTL2(i)); ctl &= ~MC_CTL2_THRESHOLD; ctl |= MC_CTL2_CMCI_EN | 1; wrmsr(MSR_MC_CTL2(i), ctl); } #endif /* * Initializes per-CPU machine check registers and enables corrected * machine check interrupts. */ static void _mca_init(int boot) { uint64_t mcg_cap; uint64_t ctl, mask; int i, skip; /* MCE is required. */ if (!mca_enabled || !(cpu_feature & CPUID_MCE)) return; if (cpu_feature & CPUID_MCA) { if (boot) PCPU_SET(cmci_mask, 0); mcg_cap = rdmsr(MSR_MCG_CAP); if (mcg_cap & MCG_CAP_CTL_P) /* Enable MCA features. */ wrmsr(MSR_MCG_CTL, MCG_CTL_ENABLE); if (PCPU_GET(cpuid) == 0 && boot) mca_setup(mcg_cap); /* * Disable logging of level one TLB parity (L1TP) errors by * the data cache as an alternative workaround for AMD Family * 10h Erratum 383. Unlike the recommended workaround, there * is no performance penalty to this workaround. However, * L1TP errors will go unreported. */ if (cpu_vendor_id == CPU_VENDOR_AMD && CPUID_TO_FAMILY(cpu_id) == 0x10 && !amd10h_L1TP) { mask = rdmsr(MSR_MC0_CTL_MASK); if ((mask & (1UL << 5)) == 0) wrmsr(MSR_MC0_CTL_MASK, mask | (1UL << 5)); } for (i = 0; i < (mcg_cap & MCG_CAP_COUNT); i++) { /* By default enable logging of all errors. */ ctl = 0xffffffffffffffffUL; skip = 0; if (cpu_vendor_id == CPU_VENDOR_INTEL) { /* * For P6 models before Nehalem MC0_CTL is * always enabled and reserved. */ if (i == 0 && CPUID_TO_FAMILY(cpu_id) == 0x6 && CPUID_TO_MODEL(cpu_id) < 0x1a) skip = 1; } else if (cpu_vendor_id == CPU_VENDOR_AMD) { /* BKDG for Family 10h: unset GartTblWkEn. */ if (i == 4 && CPUID_TO_FAMILY(cpu_id) >= 0xf) ctl &= ~(1UL << 10); } if (!skip) wrmsr(MSR_MC_CTL(i), ctl); #ifdef DEV_APIC if (mcg_cap & MCG_CAP_CMCI_P) { if (boot) cmci_monitor(i); else cmci_resume(i); } #endif /* Clear all errors. */ wrmsr(MSR_MC_STATUS(i), 0); } #ifdef DEV_APIC if (PCPU_GET(cmci_mask) != 0 && boot) lapic_enable_cmc(); #endif } load_cr4(rcr4() | CR4_MCE); } /* Must be executed on each CPU during boot. */ void mca_init(void) { _mca_init(1); } /* Must be executed on each CPU during resume. */ void mca_resume(void) { _mca_init(0); } /* * The machine check registers for the BSP cannot be initialized until * the local APIC is initialized. This happens at SI_SUB_CPU, * SI_ORDER_SECOND. */ static void mca_init_bsp(void *arg __unused) { mca_init(); } SYSINIT(mca_init_bsp, SI_SUB_CPU, SI_ORDER_ANY, mca_init_bsp, NULL); /* Called when a machine check exception fires. */ void mca_intr(void) { uint64_t mcg_status; int old_count, recoverable; if (!(cpu_feature & CPUID_MCA)) { /* * Just print the values of the old Pentium registers * and panic. */ printf("MC Type: 0x%jx Address: 0x%jx\n", (uintmax_t)rdmsr(MSR_P5_MC_TYPE), (uintmax_t)rdmsr(MSR_P5_MC_ADDR)); panic("Machine check"); } /* Scan the banks and check for any non-recoverable errors. */ old_count = mca_count; recoverable = mca_scan(MCE); mcg_status = rdmsr(MSR_MCG_STATUS); if (!(mcg_status & MCG_STATUS_RIPV)) recoverable = 0; if (!recoverable) { /* * Wait for at least one error to be logged before * panic'ing. Some errors will assert a machine check * on all CPUs, but only certain CPUs will find a valid * bank to log. */ while (mca_count == old_count) cpu_spinwait(); panic("Unrecoverable machine check exception"); } /* Clear MCIP. */ wrmsr(MSR_MCG_STATUS, mcg_status & ~MCG_STATUS_MCIP); } #ifdef DEV_APIC /* Called for a CMCI (correctable machine check interrupt). */ void cmc_intr(void) { struct mca_internal *mca; int count; /* * Serialize MCA bank scanning to prevent collisions from * sibling threads. */ count = mca_scan(CMCI); /* If we found anything, log them to the console. */ if (count != 0) { mtx_lock_spin(&mca_lock); STAILQ_FOREACH(mca, &mca_records, link) { if (!mca->logged) { mca->logged = 1; mca_log(&mca->rec); } } mtx_unlock_spin(&mca_lock); } } #endif Index: stable/9/sys =================================================================== --- stable/9/sys (revision 283926) +++ stable/9/sys (revision 283927) Property changes on: stable/9/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys:r281887 Index: stable/9/tools/regression/file/closefrom/closefrom.c =================================================================== --- stable/9/tools/regression/file/closefrom/closefrom.c (revision 283926) +++ stable/9/tools/regression/file/closefrom/closefrom.c (revision 283927) @@ -1,274 +1,274 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); /* * Regression tests for the closefrom(2) system call. */ #include #include #include #include #include #include #include #include #include #include #include #include struct shared_info { int failed; char tag[64]; char message[0]; }; static int test = 1; static void ok(const char *descr) { printf("ok %d - %s\n", test, descr); test++; } static void fail(const char *descr, const char *fmt, ...) { va_list ap; printf("not ok %d - %s", test, descr); test++; if (fmt) { va_start(ap, fmt); printf(" # "); vprintf(fmt, ap); va_end(ap); } printf("\n"); exit(1); } #define fail_err(descr) fail((descr), "%s", strerror(errno)) static void cok(struct shared_info *info, const char *descr) { info->failed = 0; strlcpy(info->tag, descr, sizeof(info->tag)); exit(0); } static void cfail(struct shared_info *info, const char *descr, const char *fmt, ...) { va_list ap; info->failed = 1; strlcpy(info->tag, descr, sizeof(info->tag)); if (fmt) { va_start(ap, fmt); vsprintf(info->message, fmt, ap); va_end(ap); } exit(0); } #define cfail_err(info, descr) cfail((info), (descr), "%s", strerror(errno)) /* * Use kinfo_getfile() to fetch the list of file descriptors and figure out * the highest open file descriptor. */ static int highest_fd(void) { struct kinfo_file *kif; int cnt, i, highest; kif = kinfo_getfile(getpid(), &cnt); if (kif == NULL) fail_err("kinfo_getfile"); highest = INT_MIN; for (i = 0; i < cnt; i++) if (kif[i].kf_fd > highest) highest = kif[i].kf_fd; free(kif); return (highest); } static int devnull(void) { int fd; fd = open("/dev/null", O_RDONLY); if (fd < 0) fail_err("open(\"/dev/null\")"); return (fd); } int main(int __unused argc, char __unused *argv[]) { struct shared_info *info; pid_t pid; int fd, i; printf("1..15\n"); /* We better start up with fd's 0, 1, and 2 open. */ fd = devnull(); if (fd != 3) fail("open", "bad descriptor %d", fd); ok("open"); /* Make sure highest_fd() works. */ fd = highest_fd(); if (fd != 3) fail("highest_fd", "bad descriptor %d", fd); ok("highest_fd"); /* Try to use closefrom() for just closing fd 3. */ closefrom(3); fd = highest_fd(); if (fd != 2) fail("closefrom", "highest fd %d", fd); ok("closefrom"); /* Eat up 16 descriptors. */ for (i = 0; i < 16; i++) (void)devnull(); fd = highest_fd(); if (fd != 18) fail("open 16", "highest fd %d", fd); ok("open 16"); /* Close half of them. */ closefrom(11); fd = highest_fd(); if (fd != 10) fail("closefrom", "highest fd %d", fd); ok("closefrom"); /* Explicitly close descriptors 6 and 8 to create holes. */ if (close(6) < 0 || close(8) < 0) fail_err("close2 "); ok("close 2"); /* Verify that close on 6 and 8 fails with EBADF. */ if (close(6) == 0) fail("close(6)", "did not fail"); if (errno != EBADF) fail_err("close(6)"); ok("close(6)"); if (close(8) == 0) fail("close(8)", "did not fail"); if (errno != EBADF) fail_err("close(8)"); ok("close(8)"); /* Close from 4 on. */ closefrom(4); fd = highest_fd(); if (fd != 3) fail("closefrom", "highest fd %d", fd); ok("closefrom"); /* Allocate a small SHM region for IPC with our child. */ info = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); if (info == MAP_FAILED) fail_err("mmap"); ok("mmap"); /* Fork a child process to test closefrom(0). */ pid = fork(); if (pid < 0) fail_err("fork"); if (pid == 0) { /* Child. */ closefrom(0); fd = highest_fd(); if (fd >= 0) cfail(info, "closefrom(0)", "highest fd %d", fd); cok(info, "closefrom(0)"); } if (wait(NULL) < 0) fail_err("wait"); if (info->failed) fail(info->tag, "%s", info->message); ok(info->tag); /* Fork a child process to test closefrom(-1). */ pid = fork(); if (pid < 0) fail_err("fork"); if (pid == 0) { /* Child. */ closefrom(-1); fd = highest_fd(); if (fd >= 0) cfail(info, "closefrom(-1)", "highest fd %d", fd); cok(info, "closefrom(-1)"); } if (wait(NULL) < 0) fail_err("wait"); if (info->failed) fail(info->tag, "%s", info->message); ok(info->tag); /* Dup stdout to 6. */ if (dup2(1, 6) < 0) fail_err("dup2"); fd = highest_fd(); if (fd != 6) fail("dup2", "highest fd %d", fd); ok("dup2"); /* Do a closefrom() starting in a hole. */ closefrom(4); fd = highest_fd(); if (fd != 3) fail("closefrom", "highest fd %d", fd); ok("closefrom"); /* Do a closefrom() beyond our highest open fd. */ closefrom(32); fd = highest_fd(); if (fd != 3) fail("closefrom", "highest fd %d", fd); ok("closefrom"); return (0); } Index: stable/9/tools/regression/lib/libc/stdio/test-open_memstream.c =================================================================== --- stable/9/tools/regression/lib/libc/stdio/test-open_memstream.c (revision 283926) +++ stable/9/tools/regression/lib/libc/stdio/test-open_memstream.c (revision 283927) @@ -1,203 +1,203 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include static char *buf; static size_t len; static void assert_stream(const char *contents) { if (strlen(contents) != len) printf("bad length %zd for \"%s\"\n", len, contents); else if (strncmp(buf, contents, strlen(contents)) != 0) printf("bad buffer \"%s\" for \"%s\"\n", buf, contents); } static void open_group_test(void) { FILE *fp; off_t eob; fp = open_memstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); fprintf(fp, "hello my world"); fflush(fp); assert_stream("hello my world"); eob = ftello(fp); rewind(fp); fprintf(fp, "good-bye"); fseeko(fp, eob, SEEK_SET); fclose(fp); assert_stream("good-bye world"); free(buf); } static void simple_tests(void) { static const char zerobuf[] = { 'f', 'o', 'o', 0, 0, 0, 0, 'b', 'a', 'r', 0 }; char c; FILE *fp; fp = open_memstream(&buf, NULL); if (fp != NULL) errx(1, "did not fail to open stream"); else if (errno != EINVAL) err(1, "incorrect error for bad length pointer"); fp = open_memstream(NULL, &len); if (fp != NULL) errx(1, "did not fail to open stream"); else if (errno != EINVAL) err(1, "incorrect error for bad buffer pointer"); fp = open_memstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); fflush(fp); assert_stream(""); if (fwide(fp, 0) >= 0) printf("stream is not byte-oriented\n"); fprintf(fp, "fo"); fflush(fp); assert_stream("fo"); fputc('o', fp); fflush(fp); assert_stream("foo"); rewind(fp); fflush(fp); assert_stream(""); fseek(fp, 0, SEEK_END); fflush(fp); assert_stream("foo"); /* * Test seeking out past the current end. Should zero-fill the * intermediate area. */ fseek(fp, 4, SEEK_END); fprintf(fp, "bar"); fflush(fp); /* * Can't use assert_stream() here since this should contain * embedded null characters. */ if (len != 10) printf("bad length %zd for zero-fill test\n", len); else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0) printf("bad buffer for zero-fill test\n"); fseek(fp, 3, SEEK_SET); fprintf(fp, " in "); fflush(fp); assert_stream("foo in "); fseek(fp, 0, SEEK_END); fflush(fp); assert_stream("foo in bar"); rewind(fp); if (fread(&c, sizeof(c), 1, fp) != 0) printf("fread did not fail\n"); else if (!ferror(fp)) printf("error indicator not set after fread\n"); else clearerr(fp); fseek(fp, 4, SEEK_SET); fprintf(fp, "bar baz"); fclose(fp); assert_stream("foo bar baz"); free(buf); } static void seek_tests(void) { FILE *fp; fp = open_memstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); #define SEEK_FAIL(offset, whence, error) do { \ errno = 0; \ if (fseeko(fp, (offset), (whence)) == 0) \ printf("fseeko(%s, %s) did not fail, set pos to %jd\n", \ __STRING(offset), __STRING(whence), \ (intmax_t)ftello(fp)); \ else if (errno != (error)) \ printf("fseeko(%s, %s) failed with %d rather than %s\n",\ __STRING(offset), __STRING(whence), errno, \ __STRING(error)); \ } while (0) #define SEEK_OK(offset, whence, result) do { \ if (fseeko(fp, (offset), (whence)) != 0) \ printf("fseeko(%s, %s) failed: %s\n", \ __STRING(offset), __STRING(whence), strerror(errno)); \ else if (ftello(fp) != (result)) \ printf("fseeko(%s, %s) seeked to %jd rather than %s\n", \ __STRING(offset), __STRING(whence), \ (intmax_t)ftello(fp), __STRING(result)); \ } while (0) SEEK_FAIL(-1, SEEK_SET, EINVAL); SEEK_FAIL(-1, SEEK_CUR, EINVAL); SEEK_FAIL(-1, SEEK_END, EINVAL); fprintf(fp, "foo"); SEEK_OK(-1, SEEK_CUR, 2); SEEK_OK(0, SEEK_SET, 0); SEEK_OK(-1, SEEK_END, 2); SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1); SEEK_FAIL(2, SEEK_CUR, EOVERFLOW); fclose(fp); } int main(int ac, char **av) { open_group_test(); simple_tests(); seek_tests(); return (0); } Index: stable/9/tools/regression/lib/libc/stdio/test-open_wmemstream.c =================================================================== --- stable/9/tools/regression/lib/libc/stdio/test-open_wmemstream.c (revision 283926) +++ stable/9/tools/regression/lib/libc/stdio/test-open_wmemstream.c (revision 283927) @@ -1,203 +1,203 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include static wchar_t *buf; static size_t len; static void assert_stream(const wchar_t *contents) { if (wcslen(contents) != len) printf("bad length %zd for \"%ls\"\n", len, contents); else if (wcsncmp(buf, contents, wcslen(contents)) != 0) printf("bad buffer \"%ls\" for \"%ls\"\n", buf, contents); } static void open_group_test(void) { FILE *fp; off_t eob; fp = open_wmemstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); fwprintf(fp, L"hello my world"); fflush(fp); assert_stream(L"hello my world"); eob = ftello(fp); rewind(fp); fwprintf(fp, L"good-bye"); fseeko(fp, eob, SEEK_SET); fclose(fp); assert_stream(L"good-bye world"); free(buf); } static void simple_tests(void) { static const wchar_t zerobuf[] = { L'f', L'o', L'o', 0, 0, 0, 0, L'b', L'a', L'r', 0 }; wchar_t c; FILE *fp; fp = open_wmemstream(&buf, NULL); if (fp != NULL) errx(1, "did not fail to open stream"); else if (errno != EINVAL) err(1, "incorrect error for bad length pointer"); fp = open_wmemstream(NULL, &len); if (fp != NULL) errx(1, "did not fail to open stream"); else if (errno != EINVAL) err(1, "incorrect error for bad buffer pointer"); fp = open_wmemstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); fflush(fp); assert_stream(L""); if (fwide(fp, 0) <= 0) printf("stream is not wide-oriented\n"); fwprintf(fp, L"fo"); fflush(fp); assert_stream(L"fo"); fputwc(L'o', fp); fflush(fp); assert_stream(L"foo"); rewind(fp); fflush(fp); assert_stream(L""); fseek(fp, 0, SEEK_END); fflush(fp); assert_stream(L"foo"); /* * Test seeking out past the current end. Should zero-fill the * intermediate area. */ fseek(fp, 4, SEEK_END); fwprintf(fp, L"bar"); fflush(fp); /* * Can't use assert_stream() here since this should contain * embedded null characters. */ if (len != 10) printf("bad length %zd for zero-fill test\n", len); else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0) printf("bad buffer for zero-fill test\n"); fseek(fp, 3, SEEK_SET); fwprintf(fp, L" in "); fflush(fp); assert_stream(L"foo in "); fseek(fp, 0, SEEK_END); fflush(fp); assert_stream(L"foo in bar"); rewind(fp); if (fread(&c, sizeof(c), 1, fp) != 0) printf("fread did not fail\n"); else if (!ferror(fp)) printf("error indicator not set after fread\n"); else clearerr(fp); fseek(fp, 4, SEEK_SET); fwprintf(fp, L"bar baz"); fclose(fp); assert_stream(L"foo bar baz"); free(buf); } static void seek_tests(void) { FILE *fp; fp = open_wmemstream(&buf, &len); if (fp == NULL) err(1, "failed to open stream"); #define SEEK_FAIL(offset, whence, error) do { \ errno = 0; \ if (fseeko(fp, (offset), (whence)) == 0) \ printf("fseeko(%s, %s) did not fail, set pos to %jd\n", \ __STRING(offset), __STRING(whence), \ (intmax_t)ftello(fp)); \ else if (errno != (error)) \ printf("fseeko(%s, %s) failed with %d rather than %s\n",\ __STRING(offset), __STRING(whence), errno, \ __STRING(error)); \ } while (0) #define SEEK_OK(offset, whence, result) do { \ if (fseeko(fp, (offset), (whence)) != 0) \ printf("fseeko(%s, %s) failed: %s\n", \ __STRING(offset), __STRING(whence), strerror(errno)); \ else if (ftello(fp) != (result)) \ printf("fseeko(%s, %s) seeked to %jd rather than %s\n", \ __STRING(offset), __STRING(whence), \ (intmax_t)ftello(fp), __STRING(result)); \ } while (0) SEEK_FAIL(-1, SEEK_SET, EINVAL); SEEK_FAIL(-1, SEEK_CUR, EINVAL); SEEK_FAIL(-1, SEEK_END, EINVAL); fwprintf(fp, L"foo"); SEEK_OK(-1, SEEK_CUR, 2); SEEK_OK(0, SEEK_SET, 0); SEEK_OK(-1, SEEK_END, 2); SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1); SEEK_FAIL(2, SEEK_CUR, EOVERFLOW); fclose(fp); } int main(int ac, char **av) { open_group_test(); simple_tests(); seek_tests(); return (0); } Index: stable/9/tools/regression/lib/libc =================================================================== --- stable/9/tools/regression/lib/libc (revision 283926) +++ stable/9/tools/regression/lib/libc (revision 283927) Property changes on: stable/9/tools/regression/lib/libc ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/tools/regression/lib/libc:r281887 Index: stable/9/tools/regression/netinet/arphold/arphold.c =================================================================== --- stable/9/tools/regression/netinet/arphold/arphold.c (revision 283926) +++ stable/9/tools/regression/netinet/arphold/arphold.c (revision 283927) @@ -1,164 +1,164 @@ /* - * Copyright (c) 2010 Advanced Computing Technologies LLC + * Copyright (c) 2010 Hudson River Trading LLC * Written by George Neville-Neil gnn@freebsd.org * 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. * * Description: The following is a test of the arp entry packet queues * which replaced the single packet hold entry that existed in the BSDs * since time immemorial. The test process is: * * 1) Find out the current system limit (maxhold) * 2) Using an IP address for which we do not yet have an entry * load up an ARP entry packet queue with exactly that many packets. * 3) Check the arp dropped stat to make sure that we have not dropped * any packets as yet. * 4) Add one more packet to the queue. * 5) Make sure that only one packet was dropped. * * CAVEAT: The ARP timer will flush the queue after 1 second so it is * important not to run this code in a fast loop or the test will * fail. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #define MSG_SIZE 1024 #define PORT 6969 int main(int argc, char **argv) { int sock; int maxhold; int wait; size_t size = sizeof(maxhold); struct sockaddr_in dest; char message[MSG_SIZE]; struct arpstat arpstat; size_t len = sizeof(arpstat); unsigned long dropped = 0; memset(&message, 1, sizeof(message)); if (sysctlbyname("net.link.ether.inet.maxhold", &maxhold, &size, NULL, 0) < 0) { perror("not ok 1 - sysctlbyname failed"); exit(1); } #ifdef DEBUG printf("maxhold is %d\n", maxhold); #endif /* DEBUG */ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("not ok 1 - could not open socket"); exit(1); } bzero(&dest, sizeof(dest)); if (inet_pton(AF_INET, argv[1], &dest.sin_addr.s_addr) != 1) { perror("not ok 1 - could not parse address"); exit(1); } dest.sin_len = sizeof(dest); dest.sin_family = AF_INET; dest.sin_port = htons(PORT); if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, NULL, 0) < 0) { perror("not ok 1 - could not get initial arp stats"); exit(1); } dropped = arpstat.dropped; #ifdef DEBUG printf("dropped before %ld\n", dropped); #endif /* DEBUG */ /* * Load up the queue in the ARP entry to the maximum. * We should not drop any packets at this point. */ while (maxhold > 0) { if (sendto(sock, message, sizeof(message), 0, (struct sockaddr *)&dest, sizeof(dest)) < 0) { perror("not ok 1 - could not send packet"); exit(1); } maxhold--; } if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, NULL, 0) < 0) { perror("not ok 1 - could not get new arp stats"); exit(1); } #ifdef DEBUG printf("dropped after %ld\n", arpstat.dropped); #endif /* DEBUG */ if (arpstat.dropped != dropped) { printf("not ok 1 - Failed, drops changed:" "before %ld after %ld\n", dropped, arpstat.dropped); exit(1); } dropped = arpstat.dropped; /* Now add one extra and make sure it is dropped. */ if (sendto(sock, message, sizeof(message), 0, (struct sockaddr *)&dest, sizeof(dest)) < 0) { perror("not ok 1 - could not send packet"); exit(1); } if (sysctlbyname("net.link.ether.arp.stats", &arpstat, &len, NULL, 0) < 0) { perror("not ok 1 - could not get new arp stats"); exit(1); } if (arpstat.dropped != (dropped + 1)) { printf("not ok 1 - Failed to drop one packet: before" " %ld after %ld\n", dropped, arpstat.dropped); exit(1); } printf("ok\n"); return (0); } Index: stable/9/tools/regression/netinet =================================================================== --- stable/9/tools/regression/netinet (revision 283926) +++ stable/9/tools/regression/netinet (revision 283927) Property changes on: stable/9/tools/regression/netinet ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/tools/regression/netinet:r281887 Index: stable/9/tools/regression/usr.sbin/etcupdate/always.sh =================================================================== --- stable/9/tools/regression/usr.sbin/etcupdate/always.sh (revision 283926) +++ stable/9/tools/regression/usr.sbin/etcupdate/always.sh (revision 283927) @@ -1,612 +1,612 @@ #!/bin/sh # -# Copyright (c) 2010 Advanced Computing Technologies LLC +# Copyright (c) 2010 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests to test the -A flag to the 'update' command. WORKDIR=work usage() { echo "Usage: always.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # The various states of the comparison of a file between two trees. states="equal first second difftype difflinks difffiles" # These tests deal with ignoring certain patterns of files. We run # the test multiple times forcing the install of different patterns. build_trees() { local i rm -rf $OLD $NEW $TEST $CONFLICTS for i in $states; do for j in $states; do for k in $states; do mkdir -p $OLD/$i/$j/$k $NEW/$i/$j/$k \ $TEST/$i/$j/$k done done done # What follows are the various warning/conflict cases from the # larger regression tests. These results of many of these # tests should be changed when installation is forced. The # cases when these updates should still fail even when forced # are: 1) it should not force the removal of a modified file # and 2) it should not remove a subdirectory that contains a # modified or added file. # /first/difftype/second: File with different local type # removed. Should generate a warning. mkfifo $OLD/first/difftype/second/fifo mkdir $TEST/first/difftype/second/fifo # /first/difflinks/second: Modified link removed. Should # generate a warning. ln -s "old link" $OLD/first/difflinks/second/link ln -s "test link" $TEST/first/difflinks/second/link # /first/difffiles/second: Modified file removed. Should # generate a warning. echo "foo" > $OLD/first/difffiles/second/file echo "bar" > $TEST/first/difffiles/second/file # /second/second/difftype: Newly added file conflicts with # existing file in test tree of a different type. Should # generate a warning. mkdir $NEW/second/second/difftype/dir mkfifo $TEST/second/second/difftype/dir # /second/second/difflinks: Newly added link conflicts with # existing link in test tree. Should generate a warning. ln -s "new link" $NEW/second/second/difflinks/link ln -s "test link" $TEST/second/second/difflinks/link # /second/second/difffiles: Newly added file conflicts with # existing file in test tree. Should generate a warning. echo "new" > $NEW/second/second/difffiles/file echo "test" > $TEST/second/second/difffiles/file # /difftype/first/first: A removed file has changed type. # This should generate a warning. mkfifo $OLD/difftype/first/first/fifo mkdir $NEW/difftype/first/first/fifo # /difftype/difftype/difftype: All three files (old, new, and # test) are different types from each other. This should # generate a warning. mkfifo $OLD/difftype/difftype/difftype/one mkdir $NEW/difftype/difftype/difftype/one echo "foo" > $TEST/difftype/difftype/difftype/one mkdir $OLD/difftype/difftype/difftype/two echo "baz" > $NEW/difftype/difftype/difftype/two ln -s "bar" $TEST/difftype/difftype/difftype/two # /difftype/difftype/difflinks: A file has changed from a # non-link to a link in both the new and test trees, but the # target of the new and test links differ. This should # generate a new link conflict. mkfifo $OLD/difftype/difftype/difflinks/link ln -s "new" $NEW/difftype/difftype/difflinks/link ln -s "test" $TEST/difftype/difftype/difflinks/link # /difftype/difftype/difffile: A file has changed from a # non-regular file to a regular file in both the new and test # trees, but the contents in the new and test files differ. # This should generate a new file conflict. ln -s "old" $OLD/difftype/difftype/difffiles/file echo "foo" > $NEW/difftype/difftype/difffiles/file echo "bar" > $TEST/difftype/difftype/difffiles/file # /difflinks/first/first: A modified link is missing in the # test tree. This should generate a warning. ln -s "old" $OLD/difflinks/first/first/link ln -s "new" $NEW/difflinks/first/first/link # /difflinks/difftype/difftype: An updated link has been # changed to a different file type in the test tree. This # should generate a warning. ln -s "old" $OLD/difflinks/difftype/difftype/link ln -s "new" $NEW/difflinks/difftype/difftype/link echo "test" > $TEST/difflinks/difftype/difftype/link # /difflinks/difflinks/difflinks: An updated link has been # modified in the test tree and doesn't match either the old # or new links. This should generate a warning. ln -s "old" $OLD/difflinks/difflinks/difflinks/link ln -s "new" $NEW/difflinks/difflinks/difflinks/link ln -s "test" $TEST/difflinks/difflinks/difflinks/link # /difffiles/first/first: A removed file has been changed in # the new tree. This should generate a warning. echo "foo" > $OLD/difffiles/first/first/file echo "bar" > $NEW/difffiles/first/first/file # /difffiles/difftype/difftype: An updated regular file has # been changed to a different file type in the test tree. # This should generate a warning. echo "old" > $OLD/difffiles/difftype/difftype/file echo "new" > $NEW/difffiles/difftype/difftype/file mkfifo $TEST/difffiles/difftype/difftype/file # /difffiles/difffiles/difffiles: A modified regular file was # updated in the new tree. The changes should be merged into # to the new file if possible. If the merge fails, a conflict # should be generated. For this test we just include the # conflict case. cat > $OLD/difffiles/difffiles/difffiles/conflict < $NEW/difffiles/difffiles/difffiles/conflict < $TEST/difffiles/difffiles/difffiles/conflict < $TEST/rmdir/extra/localfile.txt # /rmdir/conflict: Do not remove a directory with a conflicted # remove file. This should generate a warning. for i in $OLD $TEST; do mkdir $i/rmdir/conflict done mkfifo $OLD/rmdir/conflict/difftype mkdir $TEST/rmdir/conflict/difftype ## Tests for converting files to directories and vice versa for i in $OLD $NEW $TEST; do for j in already old fromdir todir; do mkdir -p $i/dirchange/$j done done # /dirchange/fromdir/extradir: Convert a directory tree to a # file. The test tree includes an extra file in the directory # that is not present in the old tree. This should generate a # warning. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/extradir echo "foo" > $i/dirchange/fromdir/extradir/file done mkfifo $TEST/dirchange/fromdir/extradir/fifo ln -s "bar" $NEW/dirchange/fromdir/extradir # /dirchange/fromdir/conflict: Convert a directory tree to a # file. The test tree includes a local change that generates # a warning and prevents the removal of the directory. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/conflict done echo "foo" > $OLD/dirchange/fromdir/conflict/somefile echo "bar" > $TEST/dirchange/fromdir/conflict/somefile mkfifo $NEW/dirchange/fromdir/conflict # /dirchange/todir/difffile: Convert a file to a directory # tree. The test tree has a locally modified version of the # file so that the conversion fails with a warning. echo "foo" > $OLD/dirchange/todir/difffile mkdir $NEW/dirchange/todir/difffile echo "baz" > $NEW/dirchange/todir/difffile/file echo "bar" > $TEST/dirchange/todir/difffile # /dirchange/todir/difftype: Similar to the previous test, but # the conflict is due to a change in the file type. echo "foo" > $OLD/dirchange/todir/difftype mkdir $NEW/dirchange/todir/difftype echo "baz" > $NEW/dirchange/todir/difftype/file mkfifo $TEST/dirchange/todir/difftype } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" fi } # $1 - relative path to file that should be present in TEST present() { if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be present" fi } # $1 - relative path to file that should be a fifo in TEST fifo() { if ! [ -p $TEST/$1 ]; then echo "File $1 should be a FIFO" fi } # $1 - relative path to file that should be a directory in TEST dir() { if ! [ -d $TEST/$1 ]; then echo "File $1 should be a directory" fi } # $1 - relative path to file that should be a symlink in TEST # $2 - optional value of the link link() { local val if ! [ -L $TEST/$1 ]; then echo "File $1 should be a link" elif [ $# -gt 1 ]; then val=`readlink $TEST/$1` if [ "$val" != "$2" ]; then echo "Link $1 should link to \"$2\"" fi fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should have a conflict # $2 - optional MD5 of the conflict file contents conflict() { local sum if ! [ -f $CONFLICTS/$1 ]; then echo "File $1 missing conflict" elif [ $# -gt 1 ]; then sum=`md5 -q $CONFLICTS/$1` if [ "$sum" != "$2" ]; then echo "Conflict $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should not have a conflict noconflict() { if [ -f $CONFLICTS/$1 ]; then echo "File $1 should not have a conflict" fi } if [ `id -u` -ne 0 ]; then echo "must be root" fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # First run the test ignoring no patterns. build_trees $COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out cat > $WORKDIR/correct.out < \ $WORKDIR/test1.out cat > $WORKDIR/correct1.out < # 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$ # Various regression tests to run for the 'resolve' command. WORKDIR=work usage() { echo "Usage: conflicts.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # These tests deal with conflicts to a single file. For each test, we # generate a conflict in /etc/login.conf. Each resolve option is tested # to ensure it DTRT. build_login_conflict() { rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD/etc $NEW/etc $TEST/etc # Generate a conflict in /etc/login.conf. cat > $OLD/etc/login.conf < $NEW/etc/login.conf < $TEST/etc/login.conf </dev/null } # This is used to verify special handling for /etc/mail/aliases and # the newaliases warning. build_aliases_conflict() { rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD/etc/mail $NEW/etc/mail $TEST/etc/mail # Generate a conflict in /etc/mail/aliases cat > $OLD/etc/mail/aliases < $NEW/etc/mail/aliases < $TEST/etc/mail/aliases </dev/null } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" fi } # $1 - relative path to file that should be present in TEST present() { if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be present" fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should have a conflict # $2 - optional MD5 of the conflict file contents conflict() { local sum if ! [ -f $CONFLICTS/$1 ]; then echo "File $1 missing conflict" elif [ $# -gt 1 ]; then sum=`md5 -q $CONFLICTS/$1` if [ "$sum" != "$2" ]; then echo "Conflict $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should no longer have a conflict resolved() { if [ -f $CONFLICTS/$1 ]; then echo "Conflict $1 should be resolved" fi } if [ `id -u` -ne 0 ]; then echo "must be root" fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # Test each of the following resolve options: 'p', 'mf', 'tf', 'r'. build_login_conflict # Verify that 'p' doesn't do anything. echo "Checking 'p':" echo 'p' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null file /etc/login.conf "" 95de92ea3f1bb1bf4f612a8b5908cddd missing /etc/login.conf.db conflict /etc/login.conf # Verify that 'mf' removes the conflict, but does nothing else. echo "Checking 'mf':" echo 'mf' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null file /etc/login.conf "" 95de92ea3f1bb1bf4f612a8b5908cddd missing /etc/login.conf.db resolved /etc/login.conf build_login_conflict # Verify that 'tf' installs the new version of the file. echo "Checking 'tf':" echo 'tf' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null file /etc/login.conf "" 7774a0f9a3a372c7c109c32fd31c4b6b file /etc/login.conf.db resolved /etc/login.conf build_login_conflict # Verify that 'r' installs the resolved version of the file. To # simulate this, manually edit the merged file so that it doesn't # contain conflict markers. echo "Checking 'r':" cat > $CONFLICTS/etc/login.conf </dev/null file /etc/login.conf "" 966e25984b9b63da8eaac8479dcb0d4d file /etc/login.conf.db resolved /etc/login.conf build_aliases_conflict # Verify that 'p' and 'mf' do not generate the newaliases warning. echo "Checking newalias warning for 'p'": echo 'p' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -eq 0 ]; then echo "+ Extra warning" fi echo "Checking newalias warning for 'mf'": echo 'mf' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -eq 0 ]; then echo "+ Extra warning" fi # Verify that 'tf' and 'r' do generate the newaliases warning. build_aliases_conflict echo "Checking newalias warning for 'tf'": echo 'tf' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -ne 0 ]; then echo "- Missing warning" fi build_aliases_conflict cp $TEST/etc/mail/aliases $CONFLICTS/etc/mail/aliases echo 'r' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias if [ $? -ne 0 ]; then echo "- Missing warning" fi Index: stable/9/tools/regression/usr.sbin/etcupdate/fbsdid.sh =================================================================== --- stable/9/tools/regression/usr.sbin/etcupdate/fbsdid.sh (revision 283926) +++ stable/9/tools/regression/usr.sbin/etcupdate/fbsdid.sh (revision 283927) @@ -1,379 +1,379 @@ #!/bin/sh # -# Copyright (c) 2010 Advanced Computing Technologies LLC +# Copyright (c) 2010 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests to test the -F flag to the 'update' command. WORKDIR=work usage() { echo "Usage: fbsdid.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # Store a FreeBSD ID string in a specified file. The first argument # is the file, the remaining arguments are the comment to use. store_id() { local file file=$1 shift echo -n '# $FreeBSD' >> $file echo -n "$@" >> $file echo '$' >> $file } # These tests deal with FreeBSD ID string conflicts. We run the test # twice, once without -F and once with -F. build_trees() { local i rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD $NEW $TEST # remove: Remove a file where the only local difference is a # change in the FreeBSD ID string. store_id $OLD/remove store_id $TEST/remove ": head/remove 12345 jhb " # old: Modify a file where the only local difference between # the old and test files is a change in the FreeBSD ID string. store_id $OLD/old ": src/old,v 1.1 jhb Exp " store_id $NEW/old ": head/old 12345 jhb " store_id $TEST/old ": head/old 12000 jhb " for i in $OLD $TEST; do cat >> $i/old <> $NEW/old <> $OLD/already <> $i/already <> $OLD/conflict <> $NEW/conflict <> $TEST/conflict <> $i/local <> $i/local <> $TEST/local <> $i/local-already <> $TEST/local-already <> $i/local-remove < $WORKDIR/test.out cat > $WORKDIR/correct.out < $WORKDIR/testF.out cat > $WORKDIR/correctF.out < $WORKDIR/testAF.out cat > $WORKDIR/correctAF.out < # 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$ # Various regression tests to test the -I flag to the 'update' command. WORKDIR=work usage() { echo "Usage: ignore.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # These tests deal with ignoring certain patterns of files. We run the # test multiple times ignoring different patterns. build_trees() { local i rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD $NEW $TEST for i in $OLD $NEW $TEST; do mkdir -p $i/tree done # tree: Test three different cases (add, modify, remove) that all # match the tree/* glob. echo "foo" > $NEW/tree/add for i in $OLD $TEST; do echo "old" > $i/tree/modify done echo "new" > $NEW/tree/modify for i in $OLD $TEST; do echo "old" > $i/tree/remove done # rmdir: Remove a whole tree. for i in $OLD $TEST; do mkdir $i/rmdir echo "foo" > $i/rmdir/file done } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" fi } # $1 - relative path to file that should be present in TEST present() { if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be present" fi } # $1 - relative path to file that should be a directory in TEST dir() { if ! [ -d $TEST/$1 ]; then echo "File $1 should be a directory" fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should have a conflict # $2 - optional MD5 of the conflict file contents conflict() { local sum if ! [ -f $CONFLICTS/$1 ]; then echo "File $1 missing conflict" elif [ $# -gt 1 ]; then sum=`md5 -q $CONFLICTS/$1` if [ "$sum" != "$2" ]; then echo "Conflict $1 has wrong contents" fi fi } # $1 - relative path to a regular file that should not have a conflict noconflict() { if [ -f $CONFLICTS/$1 ]; then echo "File $1 should not have a conflict" fi } if [ `id -u` -ne 0 ]; then echo "must be root" fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # First run the test ignoring no patterns. build_trees $COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out cat > $WORKDIR/correct.out < $WORKDIR/test1.out cat > $WORKDIR/correct1.out < \ $WORKDIR/test2.out cat > $WORKDIR/correct2.out < \ $WORKDIR/test3.out cat > $WORKDIR/correct3.out < # 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$ # Regression tests for the pre-world (-p) mode WORKDIR=work usage() { echo "Usage: preworld.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts SRC=$WORKDIR/src OLD=$WORKDIR/current TEST=$WORKDIR/test build_trees() { # Populate trees with pre-world files and additional files # that should not be touched. rm -rf $SRC $OLD $TEST $CONFLICTS # Create the "old" source tree as the starting point mkdir -p $OLD/etc cat >> $OLD/etc/master.passwd <> $OLD/etc/group <> $OLD/etc/inetd.conf <:/' $TEST/etc/master.passwd cat >> $TEST/etc/master.passwd <:1001:1001::0:0:John Baldwin:/home/john:/bin/tcsh messagebus:*:556:556::0:0:D-BUS Daemon User:/nonexistent:/usr/sbin/nologin polkit:*:562:562::0:0:PolicyKit User:/nonexistent:/usr/sbin/nologin haldaemon:*:560:560::0:0:HAL Daemon User:/nonexistent:/usr/sbin/nologin EOF awk '/wheel/ { printf "%s,john\n", $0; next } // { print }' \ $OLD/etc/group > $TEST/etc/group cat >> $TEST/etc/group <> $SRC/etc/inetd.conf < $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for real:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out check_trees Index: stable/9/tools/regression/usr.sbin/etcupdate/tests.sh =================================================================== --- stable/9/tools/regression/usr.sbin/etcupdate/tests.sh (revision 283926) +++ stable/9/tools/regression/usr.sbin/etcupdate/tests.sh (revision 283927) @@ -1,1004 +1,1004 @@ #!/bin/sh # -# Copyright (c) 2010 Advanced Computing Technologies LLC +# Copyright (c) 2010 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests to run for the 'update' command. WORKDIR=work usage() { echo "Usage: tests.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test # The various states of the comparison of a file between two trees. states="equal first second difftype difflinks difffiles" build_trees() { local i j k rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD/etc $NEW/etc $TEST/etc # For an given file, there are three different pair-wise # relations between the three threes (old, new, and test): old # vs new, old vs test, and new vs test. Each of these # relations takes on one of six different states from the # 'compare()' function in etcupdate: equal, onlyfirst, # onlysecond, difftype, difflinks, difffiles. In addition, # there are special considerations for considering cases such # as a file merge that results in conflicts versus one that # does not, special treatment of directories, etc. The tests # below attempt to enumerate the three dimensional test matrix # by having the path name use the three different tree states # for the parent directories. # # Note that if the old and new files are identical (so first # compare is "equal"), then the second and third comparisons # will be the same. # # Note also that etcupdate only cares about files that are # present in at least one of the old or new trees. Thus, none # of the '*/second/second' cases are relevant. for i in $states; do for j in $states; do for k in $states; do mkdir -p $OLD/$i/$j/$k $NEW/$i/$j/$k \ $TEST/$i/$j/$k done done done # /equal/equal/equal: Everything is equal. Nothing should happen. for i in $OLD $NEW $TEST; do mkfifo $i/equal/equal/equal/fifo echo "foo" > $i/equal/equal/equal/file mkdir $i/equal/equal/equal/dir ln -s "bar" $i/equal/equal/equal/link done # /equal/first/first: The file is missing from the test # directory. Nothing should happen. for i in $OLD $NEW; do mkfifo $i/equal/first/first/fifo echo "foo" > $i/equal/first/first/file mkdir $i/equal/first/first/dir ln -s "bar" $i/equal/first/first/link done # /equal/difftype/difftype: The local file is a different # type. Nothing should happen. for i in $OLD $NEW; do mkfifo $i/equal/difftype/difftype/fifo mkdir $i/equal/difftype/difftype/fromdir done echo "bar" > $TEST/equal/difftype/difftype/fifo ln -s "test" $TEST/equal/difftype/difftype/fromdir # /equal/difflinks/difflinks: The local file is a modified # link. Nothing should happen. for i in $OLD $NEW; do ln -s "foo" $i/equal/difflinks/difflinks/link done ln -s "bar" $TEST/equal/difflinks/difflinks/link # /equal/difffiles/difffiles: The local file is a modified # file. Nothing should happen. for i in $OLD $NEW; do echo "foo" > $i/equal/difffiles/difffiles/file done echo "bar" > $TEST/equal/difffiles/difffiles/file # /first/equal/second: Remove unmodified files. The files # should all be removed. for i in $OLD $TEST; do mkfifo $i/first/equal/second/fifo echo "foo" > $i/first/equal/second/file mkdir $i/first/equal/second/emptydir ln -s "bar" $i/first/equal/second/link mkdir $i/first/equal/second/fulldir echo "foo" > $i/first/equal/second/fulldir/file done # /first/equal/*: Cannot occur. If the file is missing from # new, then new vs test will always be 'second'. # /first/first/equal: Removed files are already removed. # Nothing should happen. mkfifo $OLD/first/first/equal/fifo echo "foo" > $OLD/first/first/equal/file mkdir $OLD/first/first/equal/dir ln -s "bar" $OLD/first/first/equal/link # /first/first/*: Cannot occur. The files are missing from # both new and test. # /first/second/*: Cannot happen, if the file is in old for # old vs new, it cannot be missing for old vs test. # /first/difftype/second: File with different local type # removed. Should generate a warning. mkfifo $OLD/first/difftype/second/fifo mkdir $TEST/first/difftype/second/fifo # /first/difftype/*: Cannot happen since the file is missing # from new but present in test. # /first/difflinks/second: Modified link removed. Should # generate a warning. ln -s "old link" $OLD/first/difflinks/second/link ln -s "test link" $TEST/first/difflinks/second/link # /first/difflinks/*: Cannot happen since the file is missing # from new but present in test. # /first/difffiles/second: Modified file removed. Should # generate a warning. echo "foo" > $OLD/first/difffiles/second/file echo "bar" > $TEST/first/difffiles/second/file # /first/difffiles/*: Cannot happen since the file is missing # from new but present in test. # /second/equal/first: Added a new file that isn't present in # test. The empty directory should be ignored. echo "bar" > $NEW/second/equal/first/file mkfifo $NEW/second/equal/first/fifo ln -s "new" $NEW/second/equal/first/link mkdir $NEW/second/equal/first/emptydir mkdir $NEW/second/equal/first/fulldir echo "foo" > $NEW/second/equal/first/fulldir/file # /second/equal/*: Cannot happen since the file is missing # from test but present in new. # /second/first/*: Cannot happen since the file is missing # from old. # /second/second/equal: Newly added file is already present in # the test directory and identical to the new file. Nothing # should happen. for i in $NEW $TEST; do mkfifo $i/second/second/equal/fifo echo "foo" > $i/second/second/equal/file mkdir $i/second/second/equal/dir ln -s "bar" $i/second/second/equal/link done # /second/second/first: Cannot happen. The file is in dest in # the second test, so it can't be missing from the third test. # /second/second/second: Cannot happen. The file is in new in # the first test, so it can't be missing from the third test. # /second/second/difftype: Newly added file conflicts with # existing file in test tree of a different type. Should # generate a warning. mkdir $NEW/second/second/difftype/dir mkfifo $TEST/second/second/difftype/dir # /second/second/difflinks: Newly added link conflicts with # existing link in test tree. Should generate a warning. ln -s "new link" $NEW/second/second/difflinks/link ln -s "test link" $TEST/second/second/difflinks/link # /second/second/difffiles: Newly added file conflicts with # existing file in test tree. Should generate a warning. echo "new" > $NEW/second/second/difffiles/file echo "test" > $TEST/second/second/difffiles/file # /second/difftype/*: Cannot happen since the file is missing # from old. # /second/difflinks/*: Cannot happen since the file is missing # from old. # /second/difffiles/*: Cannot happen since the file is missing # from old. # /difftype/equal/difftype: Unmodified file has changed type. # File should be updated to the new file. In the 'todir' case # the directory won't actually be created because it is empty. for i in $OLD $TEST; do echo "foo" > $i/difftype/equal/difftype/file mkdir $i/difftype/equal/difftype/fromdir ln -s "old" $i/difftype/equal/difftype/todir done ln -s "test" $NEW/difftype/equal/difftype/file mkfifo $NEW/difftype/equal/difftype/fromdir mkdir $NEW/difftype/equal/difftype/todir # /difftype/equal/*: Cannot happen. Since the old file is a # difftype from the new file and the test file is identical to # the old file, the test file must be a difftype from the new # file. # /difftype/first/first: A removed file has changed type. # This should generate a warning. mkfifo $OLD/difftype/first/first/fifo mkdir $NEW/difftype/first/first/fifo # /difftype/first/*: Cannot happen. Since the new file exists # and the dest file is missing, the last test must be 'first'. # /difftype/second/*: Cannot happen. The old file exists in # the first test, so it cannot be missing in the second test. # /difftype/difftype/equal: A file has changed type, but the # file in the test directory already matches the new file. Do # nothing. echo "foo" > $OLD/difftype/difftype/equal/fifo mkfifo $OLD/difftype/difftype/equal/file for i in $NEW $TEST; do mkfifo $i/difftype/difftype/equal/fifo echo "bar" > $i/difftype/difftype/equal/file done # /difftype/difftype/first: Cannot happen. The dest file # exists in the second test. # /difftype/difftype/second: Cannot happen. The new file # exists in the first test. # /difftype/difftype/difftype: All three files (old, new, and # test) are different types from each other. This should # generate a warning. mkfifo $OLD/difftype/difftype/difftype/one mkdir $NEW/difftype/difftype/difftype/one echo "foo" > $TEST/difftype/difftype/difftype/one mkdir $OLD/difftype/difftype/difftype/two echo "baz" > $NEW/difftype/difftype/difftype/two ln -s "bar" $TEST/difftype/difftype/difftype/two # /difftype/difftype/difflinks: A file has changed from a # non-link to a link in both the new and test trees, but the # target of the new and test links differ. This should # generate a new link conflict. mkfifo $OLD/difftype/difftype/difflinks/link ln -s "new" $NEW/difftype/difftype/difflinks/link ln -s "test" $TEST/difftype/difftype/difflinks/link # /difftype/difftype/difffile: A file has changed from a # non-regular file to a regular file in both the new and test # trees, but the contents in the new and test files differ. # This should generate a new file conflict. ln -s "old" $OLD/difftype/difftype/difffiles/file echo "foo" > $NEW/difftype/difftype/difffiles/file echo "bar" > $TEST/difftype/difftype/difffiles/file # /difflinks/equal/difflinks: An unmodified symlink has # changed. The link should be updated. for i in $OLD $TEST; do ln -s "old" $i/difflinks/equal/difflinks/link done ln -s "new" $NEW/difflinks/equal/difflinks/link # /difflinks/equal/*: Cannot happen. Since old is identical # to test, the third test must be 'difflinks'. # /difflinks/first/first: A modified link is missing in the # test tree. This should generate a warning. ln -s "old" $OLD/difflinks/first/first/link ln -s "new" $NEW/difflinks/first/first/link # /difflinks/first/*: Cannot happen. Since the test file is # missing in the second test, it must be missing in the third # test. # /difflinks/second/*: Cannot happen. The old link is present # in the first test, so it cannot be missing in the second # test. # /difflinks/difftype/difftype: An updated link has been # changed to a different file type in the test tree. This # should generate a warning. ln -s "old" $OLD/difflinks/difftype/difftype/link ln -s "new" $NEW/difflinks/difftype/difftype/link echo "test" > $TEST/difflinks/difftype/difftype/link # /difflinks/difftype/*: Cannot happen. The old and new files # are both links and the test file is not a link, so the third # test must be 'difftype'. # /difflinks/difflinks/equal: An updated link has already been # updated to the new target in the test tree. Nothing should # happen. ln -s "old" $OLD/difflinks/difflinks/equal/link for i in $NEW $TEST; do ln -s "new" $i/difflinks/difflinks/equal/link done # /difflinks/difflinks/difflinks: An updated link has been # modified in the test tree and doesn't match either the old # or new links. This should generate a warning. ln -s "old" $OLD/difflinks/difflinks/difflinks/link ln -s "new" $NEW/difflinks/difflinks/difflinks/link ln -s "test" $TEST/difflinks/difflinks/difflinks/link # /difflinks/difflinks/*: Cannot happen. All three files are # links from the first two tests, so the third test can only # be 'equal' or 'difflink'. # /difflinks/difffiles/*: Cannot happen. The old file is a # link in the first test, so it cannot be a regular file in # the second. # /difffiles/equal/difffiles: An unmodified file has been # changed in new tree. The file should be updated to the new # version. for i in $OLD $TEST; do echo "foo" > $i/difffiles/equal/difffiles/file done echo "bar" > $NEW/difffiles/equal/difffiles/file # /difffiles/equal/*: Cannot happen. Since the old file is # identical to the test file, the third test must be # 'difffiles'. # /difffiles/first/first: A removed file has been changed in # the new tree. This should generate a warning. echo "foo" > $OLD/difffiles/first/first/file echo "bar" > $NEW/difffiles/first/first/file # /difffiles/first/*: Cannot happen. The new file is a # regular file from the first test and the test file is # missing in the second test, so the third test must be # 'first'. # /difffiles/second/*: Cannot happen. The old file is present # in the first test, so it must be present in the second test. # /difffiles/difftype/difftype: An updated regular file has # been changed to a different file type in the test tree. # This should generate a warning. echo "old" > $OLD/difffiles/difftype/difftype/file echo "new" > $NEW/difffiles/difftype/difftype/file mkfifo $TEST/difffiles/difftype/difftype/file # /difffiles/difftype/*: Cannot happen. The new file is known # to be a regular file from the first test, and the test file # is known to exist as a different file type from the second # test. The third test must be 'difftype'. # /difffiles/difflink/*: Cannot happen. The old file is known # to be a regular file from the first test, so it cannot be a # link in the second test. # /difffiles/difffiles/equal: An updated regular file has # already been updated to match the new file in the test tree. # Nothing should happen. echo "foo" > $OLD/difffiles/difffiles/equal/file for i in $NEW $TEST; do echo "bar" > $i/difffiles/difffiles/equal/file done # /difffiles/difffiles/difffiles: A modified regular file was # updated in the new tree. The changes should be merged into # to the new file if possible. If the merge fails, a conflict # should be generated. cat > $OLD/difffiles/difffiles/difffiles/simple < $NEW/difffiles/difffiles/difffiles/simple < $TEST/difffiles/difffiles/difffiles/simple < $OLD/difffiles/difffiles/difffiles/conflict < $NEW/difffiles/difffiles/difffiles/conflict < $TEST/difffiles/difffiles/difffiles/conflict < $NEW/adddir/partial/file mkfifo $TEST/adddir/partial/fifo ## Tests for removing directories mkdir -p $OLD/rmdir $NEW/rmdir $TEST/rmdir # /rmdir/extra: Do not remove a directory with an extra local file. # This should generate a warning. for i in $OLD $TEST; do mkdir $i/rmdir/extra done echo "foo" > $TEST/rmdir/extra/localfile.txt # /rmdir/conflict: Do not remove a directory with a conflicted # remove file. This should generate a warning. for i in $OLD $TEST; do mkdir $i/rmdir/conflict done mkfifo $OLD/rmdir/conflict/difftype mkdir $TEST/rmdir/conflict/difftype # /rmdir/partial: Remove a complete hierarchy when part of the # tree has already been removed locally. for i in $OLD $TEST; do mkdir -p $i/rmdir/partial/subdir mkfifo $i/rmdir/partial/subdir/fifo done echo "foo" > $OLD/rmdir/partial/subdir/file ## Tests for converting files to directories and vice versa for i in $OLD $NEW $TEST; do for j in already old fromdir todir; do mkdir -p $i/dirchange/$j done done # /dirchange/already/fromdir: Convert a directory tree to a # file without conflicts where the test tree already has the # new file. Nothing should happen. mkdir $OLD/dirchange/already/fromdir echo "blah" > $OLD/dirchange/already/fromdir/somefile for i in $NEW $TEST; do echo "bar" > $i/dirchange/already/fromdir done # /dirchange/already/todir: Convert an unmodified file to a # directory tree where the test tree already has the new # tree. Nothing should happen. echo "baz" > $OLD/dirchange/already/todir for i in $NEW $TEST; do mkdir $i/dirchange/already/todir echo "blah" > $i/dirchange/already/todir/somefile done # /dirchange/old/fromdir: Convert a directory tree to a file. # The old files are unmodified and should be changed to the new tree. for i in $OLD $TEST; do mkdir $i/dirchange/old/fromdir echo "blah" > $i/dirchange/old/fromdir/somefile done echo "bar" > $NEW/dirchange/old/fromdir # /dirchange/old/todir: Convert a file to a directory tree. # The old file is unmodified and should be changed to the new # tree. for i in $OLD $TEST; do echo "foo" > $i/dirchange/old/todir done mkdir $NEW/dirchange/old/todir echo "bar" > $NEW/dirchange/old/todir/file # /dirchange/fromdir/extradir: Convert a directory tree to a # file. The test tree includes an extra file in the directory # that is not present in the old tree. This should generate a # warning. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/extradir echo "foo" > $i/dirchange/fromdir/extradir/file done mkfifo $TEST/dirchange/fromdir/extradir/fifo ln -s "bar" $NEW/dirchange/fromdir/extradir # /dirchange/fromdir/conflict: Convert a directory tree to a # file. The test tree includes a local change that generates # a warning and prevents the removal of the directory. for i in $OLD $TEST; do mkdir $i/dirchange/fromdir/conflict done echo "foo" > $OLD/dirchange/fromdir/conflict/somefile echo "bar" > $TEST/dirchange/fromdir/conflict/somefile mkfifo $NEW/dirchange/fromdir/conflict # /dirchange/todir/difffile: Convert a file to a directory # tree. The test tree has a locally modified version of the # file so that the conversion fails with a warning. echo "foo" > $OLD/dirchange/todir/difffile mkdir $NEW/dirchange/todir/difffile echo "baz" > $NEW/dirchange/todir/difffile/file echo "bar" > $TEST/dirchange/todir/difffile # /dirchange/todir/difftype: Similar to the previous test, but # the conflict is due to a change in the file type. echo "foo" > $OLD/dirchange/todir/difftype mkdir $NEW/dirchange/todir/difftype echo "baz" > $NEW/dirchange/todir/difftype/file mkfifo $TEST/dirchange/todir/difftype ## Tests for post-install actions # - Adding /etc/master.passwd should cause pwd_mkdb to be run echo "foo:*:16000:100::0:0:& user:/home/foo:/bin/tcsh" > \ $NEW/etc/master.passwd # - Verify that updating an unmodified /etc/login.conf builds # /etc/login.conf.db. cat > $OLD/etc/login.conf < $NEW/etc/login.conf < $OLD/etc/mail/aliases < $NEW/etc/mail/aliases < $TEST/etc/mail/aliases < $OLD/etc/services < $NEW/etc/services < $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for real:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out check_trees Index: stable/9/tools/regression/usr.sbin/etcupdate/tzsetup.sh =================================================================== --- stable/9/tools/regression/usr.sbin/etcupdate/tzsetup.sh (revision 283926) +++ stable/9/tools/regression/usr.sbin/etcupdate/tzsetup.sh (revision 283927) @@ -1,221 +1,221 @@ #!/bin/sh # -# Copyright (c) 2013 Advanced Computing Technologies LLC +# Copyright (c) 2013 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # Various regression tests for the tzsetup handling in the 'update' command. WORKDIR=work usage() { echo "Usage: tzsetup.sh [-s script] [-w workdir]" exit 1 } # Allow the user to specify an alternate work directory or script. COMMAND=etcupdate while getopts "s:w:" option; do case $option in s) COMMAND="sh $OPTARG" ;; w) WORKDIR=$OPTARG ;; *) echo usage ;; esac done shift $((OPTIND - 1)) if [ $# -ne 0 ]; then usage fi CONFLICTS=$WORKDIR/conflicts OLD=$WORKDIR/old NEW=$WORKDIR/current TEST=$WORKDIR/test build_trees() { # Build the base tree, but not /etc/localtime itself local i j k rm -rf $OLD $NEW $TEST $CONFLICTS mkdir -p $OLD $NEW $TEST mkdir -p $TEST/etc mkdir -p $TEST/var/db mkdir -p $TEST/usr/share/zoneinfo # Create a dummy timezone file echo "foo" > $TEST/usr/share/zoneinfo/foo } # $1 - relative path to file that should be missing from TEST missing() { if [ -e $TEST/$1 -o -L $TEST/$1 ]; then echo "File $1 should be missing" fi } # $1 - relative path to file that should be a symlink in TEST # $2 - optional value of the link link() { local val if ! [ -L $TEST/$1 ]; then echo "File $1 should be a link" elif [ $# -gt 1 ]; then val=`readlink $TEST/$1` if [ "$val" != "$2" ]; then echo "Link $1 should link to \"$2\"" fi fi } # $1 - relative path to regular file that should be present in TEST # $2 - optional string that should match file contents # $3 - optional MD5 of the flie contents, overrides $2 if present file() { local contents sum if ! [ -f $TEST/$1 ]; then echo "File $1 should be a regular file" elif [ $# -eq 2 ]; then contents=`cat $TEST/$1` if [ "$contents" != "$2" ]; then echo "File $1 has wrong contents" fi elif [ $# -eq 3 ]; then sum=`md5 -q $TEST/$1` if [ "$sum" != "$3" ]; then echo "File $1 has wrong contents" fi fi } if [ `id -u` -ne 0 ]; then echo "must be root" fi if [ -r /etc/etcupdate.conf ]; then echo "WARNING: /etc/etcupdate.conf settings may break some tests." fi # First, test for /etc/localtime not existing build_trees $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for no /etc/localtime:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out missing /etc/localtime missing /var/db/zoneinfo # Second, test for /etc/localtime being a symlink build_trees ln -s /dev/null $TEST/etc/localtime $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for symlinked /etc/localtime:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out link /etc/localtime "/dev/null" missing /var/db/zoneinfo # Third, test for /etc/localtime as a file and a missing /var/db/zoneinfo build_trees echo "bar" > $TEST/etc/localtime $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for missing /var/db/zoneinfo:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out file /etc/localtime "bar" missing /var/db/zoneinfo # Finally, test the case where it should update /etc/localtime build_trees echo "bar" > $TEST/etc/localtime echo "foo" > $TEST/var/db/zoneinfo $COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out cat > $WORKDIR/correct.out < $WORKDIR/test.out echo "Differences for real update:" diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out file /etc/localtime "foo" file /var/db/zoneinfo "foo" Index: stable/9/usr.bin/perror/perror.1 =================================================================== --- stable/9/usr.bin/perror/perror.1 (revision 283926) +++ stable/9/usr.bin/perror/perror.1 (revision 283927) @@ -1,50 +1,50 @@ .\" -.\" Copyright (c) 2009 Advanced Computing Technologies LLC +.\" Copyright (c) 2009 Hudson River Trading LLC .\" Written by: George V. Neville-Neil .\" 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$ .\" .Dd May 12, 2009 .Dt PERROR 1 .Os .Sh NAME .Nm perror .Nd "print an error number as a string" .Sh SYNOPSIS .Nm .Ar number .Sh DESCRIPTION The .Nm program takes a raw errno value and prints it as a string. .Sh SEE ALSO .Xr perror 3 .Sh HISTORY The .Nm program first appeared in .Fx 8.0 . .Sh AUTHORS .An George V. Neville-Neil Index: stable/9/usr.bin/perror/perror.c =================================================================== --- stable/9/usr.bin/perror/perror.c (revision 283926) +++ stable/9/usr.bin/perror/perror.c (revision 283927) @@ -1,72 +1,72 @@ /*- - * Copyright (c) 2009 Advanced Computing Technologies LLC + * Copyright (c) 2009 Hudson River Trading LLC * Written by: George V. Neville-Neil * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include static void usage(void); int main(int argc, char **argv) { char *cp; char *errstr; long errnum; (void) setlocale(LC_MESSAGES, ""); if (argc != 2) usage(); errno = 0; errnum = strtol(argv[1], &cp, 0); if (errno != 0) err(1, NULL); if ((errstr = strerror(errnum)) == NULL) err(1, NULL); printf("%s\n", errstr); exit(0); } static void usage(void) { fprintf(stderr, "usage: perror number\n"); exit(1); } Index: stable/9/usr.bin/procstat/procstat_rusage.c =================================================================== --- stable/9/usr.bin/procstat/procstat_rusage.c (revision 283926) +++ stable/9/usr.bin/procstat/procstat_rusage.c (revision 283927) @@ -1,161 +1,161 @@ /*- - * Copyright (c) 2012 Advanced Computing Technologies LLC + * Copyright (c) 2012 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "procstat.h" static struct { const char *ri_name; bool ri_humanize; int ri_scale; } rusage_info[] = { { "maximum RSS", true, 1 }, { "integral shared memory", true, 1 }, { "integral unshared data", true, 1 }, { "integral unshared stack", true, 1 }, { "page reclaims", false, 0 }, { "page faults", false, 0 }, { "swaps", false, 0 }, { "block reads", false, 0 }, { "block writes", false, 0 }, { "messages sent", false, 0 }, { "messages received", false, 0 }, { "signals received", false, 0 }, { "voluntary context switches", false, 0 }, { "involuntary context switches", false, 0 } }; /* xxx days hh:mm:ss.uuuuuu */ static const char * format_time(struct timeval *tv) { static char buffer[32]; int days, hours, minutes, seconds, used; minutes = tv->tv_sec / 60; seconds = tv->tv_sec % 60; hours = minutes / 60; minutes %= 60; days = hours / 24; hours %= 24; used = 0; if (days == 1) used += snprintf(buffer, sizeof(buffer), "1 day "); else if (days > 0) used += snprintf(buffer, sizeof(buffer), "%u days ", days); snprintf(buffer + used, sizeof(buffer) - used, "%02u:%02u:%02u.%06u ", hours, minutes, seconds, (unsigned int)tv->tv_usec); return (buffer); } static const char * format_value(long value, bool humanize, int scale) { static char buffer[14]; if (scale != 0) value <<= scale * 10; if (humanize) humanize_number(buffer, sizeof(buffer), value, "B", scale, HN_DECIMAL); else snprintf(buffer, sizeof(buffer), "%ld ", value); return (buffer); } static void print_prefix(struct kinfo_proc *kipp) { printf("%5d ", kipp->ki_pid); if (Hflag) printf("%6d ", kipp->ki_tid); printf("%-16s ", kipp->ki_comm); } static void print_rusage(struct kinfo_proc *kipp) { long *lp; unsigned int i; print_prefix(kipp); printf("%-14s %32s\n", "user time", format_time(&kipp->ki_rusage.ru_utime)); print_prefix(kipp); printf("%-14s %32s\n", "system time", format_time(&kipp->ki_rusage.ru_stime)); lp = &kipp->ki_rusage.ru_maxrss; for (i = 0; i < nitems(rusage_info); i++) { print_prefix(kipp); printf("%-32s %14s\n", rusage_info[i].ri_name, format_value(*lp, rusage_info[i].ri_humanize, rusage_info[i].ri_scale)); lp++; } } void procstat_rusage(struct procstat *procstat, struct kinfo_proc *kipp) { struct kinfo_proc *kip; unsigned int count, i; if (!hflag) { printf("%5s ", "PID"); if (Hflag) printf("%6s ", "TID"); printf("%-16s %-32s %14s\n", "COMM", "RESOURCE", "VALUE "); } if (!Hflag) { print_rusage(kipp); return; } kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, kipp->ki_pid, &count); if (kip == NULL) return; kinfo_proc_sort(kip, count); for (i = 0; i < count; i++) print_rusage(&kip[i]); procstat_freeprocs(procstat, kip); } Index: stable/9/usr.bin/procstat =================================================================== --- stable/9/usr.bin/procstat (revision 283926) +++ stable/9/usr.bin/procstat (revision 283927) Property changes on: stable/9/usr.bin/procstat ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/usr.bin/procstat:r281887 Index: stable/9/usr.bin/protect/protect.1 =================================================================== --- stable/9/usr.bin/protect/protect.1 (revision 283926) +++ stable/9/usr.bin/protect/protect.1 (revision 283927) @@ -1,89 +1,89 @@ -.\" Copyright (c) 2013 Advanced Computing Technologies LLC +.\" Copyright (c) 2013 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd September 19, 2013 .Dt PROTECT 1 .Os .Sh NAME .Nm protect .Nd "protect processes from being killed when swap space is exhausted" .Sh SYNOPSIS .Nm .Op Fl i .Ar command .Nm .Op Fl cdi .Fl g Ar pgrp | Fl p Ar pid .Sh DESCRIPTION The .Nm command is used to mark processes as protected. The kernel does not kill protected processes when swap space is exhausted. Note that this protected state is not inherited by child processes by default. .Pp The options are: .Bl -tag -width XXXXXXXXXX .It Fl c Remove protection from the specified processes. .It Fl d Apply the operation to all current children of the specified processes. .It Fl i Apply the operation to all future children of the specified processes. .It Fl g Ar pgrp Apply the operation to all processes in the specified process group. .It Fl p Ar pid Apply the operation to the specified process. .It Ar command Execute .Ar command as a protected process. .El .Pp Note that only one of the .Fl p or .Fl g flags may be specified when adjusting the state of existing processes. .Sh EXIT STATUS .Ex -std .Sh EXAMPLES Mark the Xorg server as protected: .Pp .Dl "pgrep Xorg | xargs protect -p" .Pp Protect all ssh sessions and their child processes: .Pp .Dl "pgrep sshd | xargs protect -dip" .Pp Remove protection from all current and future processes: .Pp .Dl "protect -cdi -p 1" .Sh SEE ALSO .Xr procctl 2 .Sh BUGS If you protect a runaway process that allocates all memory the system will deadlock. Index: stable/9/usr.bin/protect/protect.c =================================================================== --- stable/9/usr.bin/protect/protect.c (revision 283926) +++ stable/9/usr.bin/protect/protect.c (revision 283927) @@ -1,122 +1,122 @@ /*- - * Copyright (c) 2013 Advanced Computing Technologies LLC + * Copyright (c) 2013 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include static void usage(void) { fprintf(stderr, "usage: protect [-i] command\n"); fprintf(stderr, " protect [-cdi] -g pgrp | -p pid\n"); exit(1); } static id_t parse_id(char *id) { static bool first = true; long value; char *ch; if (!first) { warnx("only one -g or -p flag is permitted"); usage(); } value = strtol(id, &ch, 0); if (*ch != '\0') { warnx("invalid process id"); usage(); } return (value); } int main(int argc, char *argv[]) { idtype_t idtype; id_t id; int ch, flags; bool descend, inherit, idset; idtype = P_PID; id = getpid(); flags = PPROT_SET; descend = inherit = idset = false; while ((ch = getopt(argc, argv, "cdig:p:")) != -1) switch (ch) { case 'c': flags = PPROT_CLEAR; break; case 'd': descend = true; break; case 'i': inherit = true; break; case 'g': idtype = P_PGID; id = parse_id(optarg); idset = true; break; case 'p': idtype = P_PID; id = parse_id(optarg); idset = true; break; } argc -= optind; argv += optind; if ((idset && argc != 0) || (!idset && (argc == 0 || descend))) usage(); if (descend) flags |= PPROT_DESCEND; if (inherit) flags |= PPROT_INHERIT; if (procctl(idtype, id, PROC_SPROTECT, &flags) == -1) err(1, "procctl"); if (argc != 0) { errno = 0; execvp(*argv, argv); err(errno == ENOENT ? 127 : 126, "%s", *argv); } return (0); } Index: stable/9/usr.bin/protect =================================================================== --- stable/9/usr.bin/protect (revision 283926) +++ stable/9/usr.bin/protect (revision 283927) Property changes on: stable/9/usr.bin/protect ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/usr.bin/protect:r281887 Index: stable/9/usr.sbin/etcupdate/etcupdate.8 =================================================================== --- stable/9/usr.sbin/etcupdate/etcupdate.8 (revision 283926) +++ stable/9/usr.sbin/etcupdate/etcupdate.8 (revision 283927) @@ -1,888 +1,888 @@ -.\" Copyright (c) 2010-2013 Advanced Computing Technologies LLC +.\" Copyright (c) 2010-2013 Hudson River Trading LLC .\" Written by: John H. Baldwin .\" 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$ .\" .Dd October 29, 2014 .Dt ETCUPDATE 8 .Os .Sh NAME .Nm etcupdate .Nd "manage updates to system files not updated by installworld" .Sh SYNOPSIS .Nm .Op Fl npBF .Op Fl d Ar workdir .Op Fl r | Fl s Ar source | Fl t Ar tarball .Op Fl A Ar patterns .Op Fl D Ar destdir .Op Fl I Ar patterns .Op Fl L Ar logfile .Op Fl M Ar options .Nm .Cm build .Op Fl B .Op Fl d Ar workdir .Op Fl s Ar source .Op Fl L Ar logfile .Op Fl M Ar options .Ar tarball .Nm .Cm diff .Op Fl d Ar workdir .Op Fl D Ar destdir .Op Fl I Ar patterns .Op Fl L Ar logfile .Nm .Cm extract .Op Fl B .Op Fl d Ar workdir .Op Fl s Ar source | Fl t Ar tarball .Op Fl L Ar logfile .Op Fl M Ar options .Nm .Cm resolve .Op Fl p .Op Fl d Ar workdir .Op Fl D Ar destdir .Op Fl L Ar logfile .Nm .Cm status .Op Fl d Ar workdir .Op Fl D Ar destdir .Sh DESCRIPTION The .Nm utility is a tool for managing updates to files that are not updated as part of .Sq make installworld such as files in .Pa /etc . It manages updates by doing a three-way merge of changes made to these files against the local versions. It is also designed to minimize the amount of user intervention with the goal of simplifying upgrades for clusters of machines. .Pp To perform a three-way merge, .Nm keeps copies of the current and previous versions of files that it manages. These copies are stored in two trees known as the .Dq current and .Dq previous trees. During a merge, .Nm compares the .Dq current and .Dq previous copies of each file to determine which changes need to be merged into the local version of each file. If a file can be updated without generating a conflict, .Nm will update the file automatically. If the local changes to a file conflict with the changes made to a file in the source tree, then a merge conflict is generated. The conflict must be resolved after the merge has finished. The .Nm utility will not perform a new merge until all conflicts from an earlier merge are resolved. .Sh MODES The .Nm utility supports several modes of operation. The mode is specified via an optional command argument. If present, the command must be the first argument on the command line. If a command is not specified, the default mode is used. .Ss Default Mode The default mode merges changes from the source tree to the destination directory. First, it updates the .Dq current and .Dq previous trees. Next, it compares the two trees merging changes into the destination directory. Finally, it displays warnings for any conditions it could not handle automatically. .Pp If the .Fl r option is not specified, then the first step taken is to update the .Dq current and .Dq previous trees. If a .Dq current tree already exists, then that tree is saved as the .Dq previous tree. An older .Dq previous tree is removed if it exists. By default the new .Dq current tree is built from a source tree. However, if a tarball is specified via the .Fl t option, then the tree is extracted from that tarball instead. .Pp Next, .Nm compares the files in the .Dq current and .Dq previous trees. If a file was removed from the .Dq current tree, then it will be removed from the destination directory only if it does not have any local modifications. If a file was added to the .Dq current tree, then it will be copied to the destination directory only if it would not clobber an existing file. If a file is changed in the .Dq current tree, then .Nm will attempt to merge the changes into the version of the file in the destination directory. If the merge encounters conflicts, then a version of the file with conflict markers will be saved for future resolution. If the merge does not encounter conflicts, then the merged version of the file will be saved in the destination directory. If .Nm is not able to safely merge in changes to a file other than a merge conflict, it will generate a warning. .Pp For each file that is updated a line will be output with a leading character to indicate the action taken. The possible actions follow: .Pp .Bl -tag -width "A" -compact -offset indent .It A Added .It C Conflict .It D Deleted .It M Merged .It U Updated .El .Pp Finally, if any warnings were encountered they are displayed after the merge has completed. .Pp Note that for certain files .Nm will perform post-install actions any time that the file is updated. Specifically, .Xr pwd_mkdb 8 is invoked if .Pa /etc/master.passwd is changed, .Xr cap_mkdb 1 is invoked to update .Pa /etc/login.conf.db if .Pa /etc/login.conf is changed, .Xr newaliases 1 is invoked if .Pa /etc/mail/aliases is changed, and .Pa /etc/rc.d/motd is invoked if .Pa /etc/motd is changed. One exception is that if .Pa /etc/mail/aliases is changed and the destination directory is not the default, then a warning will be issued instead. This is due to a limitation of the .Xr newaliases 1 command. Similarly, if .Pa /etc/motd is changed and the destination directory is not the default, then .Pa /etc/rc.d/motd will not be executed due to a limitation of that script. In this case no warning is issued as the result of .Pa /etc/rc.d/motd is merely cosmetic and will be corrected on the next reboot. .Ss Build Mode The .Cm build mode is used to build a tarball that contains a snapshot of a .Dq current tree. This tarball can be used by the default and extract modes. Using a tarball can allow .Nm to perform a merge without requiring a source tree that matches the currently installed world. The .Fa tarball argument specifies the name of the file to create. The file will be a .Xr tar 5 file compressed with .Xr bzip2 1 . .Ss Diff Mode The .Cm diff mode compares the versions of files in the destination directory to the .Dq current tree and generates a unified format diff of the changes. This can be used to determine which files have been locally modified and how. Note that .Nm does not manage files that are not maintained in the source tree such as .Pa /etc/fstab and .Pa /etc/rc.conf . .Ss Extract Mode The .Cm extract mode generates a new .Dq current tree. Unlike the default mode, it does not save any existing .Dq current tree and does not modify any existing .Dq previous tree. The new .Dq current tree can either be built from a source tree or extracted from a tarball. .Ss Resolve Mode The .Cm resolve mode is used to resolve any conflicts encountered during a merge. In this mode, .Nm iterates over any existing conflicts prompting the user for actions to take on each conflicted file. For each file, the following actions are available: .Pp .Bl -tag -width "(tf) theirs-full" -compact .It (p) postpone Ignore this conflict for now. .It (df) diff-full Show all changes made to the merged file as a unified diff. .It (e) edit Change the merged file in an editor. .It (r) resolved Install the merged version of the file into the destination directory. .It (mf) mine-full Use the version of the file in the destination directory and ignore any changes made to the file in the .Dq current tree. .It (tf) theirs-full Use the version of the file from the .Dq current tree and discard any local changes made to the file. .It (h) help Display the list of commands. .El .Ss Status Mode The .Cm status mode shows a summary of the results of the most recent merge. First it lists any files for which there are unresolved conflicts. Next it lists any warnings generated during the last merge. If the last merge did not generate any conflicts or warnings, then nothing will be output. .Sh OPTIONS The following options are available. Note that most options do not apply to all modes. .Bl -tag -width ".Fl A Ar patterns" .It Fl A Ar patterns Always install the new version of any files that match any of the patterns listed in .Ar patterns . Each pattern is evaluated as an .Xr sh 1 shell pattern. This option may be specified multiple times to specify multiple patterns. Multiple space-separated patterns may also be specified in a single option. Note that ignored files specified via the .Ev IGNORE_FILES variable or the .Fl I option will not be installed. .It Fl B Do not build generated files in a private object tree. Instead, reuse the generated files from a previously built object tree that matches the source tree. This can be useful to avoid gratuitous conflicts in .Xr sendmail 8 configuration files when bootstrapping. It can also be useful for building a tarball that matches a specific world build. .It Fl D Ar destdir Specify an alternate destination directory as the target of a merge. This is analogous to the .Dv DESTDIR variable used with .Sq make installworld . The default destination directory is an empty string which results in merges updating .Pa /etc on the local machine. .It Fl d Ar workdir Specify an alternate directory to use as the work directory. The work directory is used to store the .Dq current and .Dq previous trees as well as unresolved conflicts. The default work directory is .Pa /var/db/etcupdate . .It Fl F Ignore changes in the FreeBSD ID string when comparing files in the destination directory to files in either of the .Dq current or .Dq previous trees. In .Cm diff mode, this reduces noise due to FreeBSD ID string changes in the output. During an update this can simplify handling for harmless conflicts caused by FreeBSD ID string changes. .Pp Specifically, if a file in the destination directory is identical to the same file in the .Dq previous tree modulo the FreeBSD ID string, then the file is treated as if it was unmodified and the .Dq current version of the file will be installed. Similarly, if a file in the destination directory is identical to the same file in the .Dq current tree modulo the FreeBSD ID string, then the .Dq current version of the file will be installed to update the ID string. If the .Dq previous and .Dq current versions of the file are identical, then .Nm will not change the file in the destination directory. .Pp Due to limitations in the .Xr diff 1 command, this option may not have an effect if there are other changes in a file that are close to the FreeBSD ID string. .It Fl I Ar patterns Ignore any files that match any of the patterns listed in .Ar patterns . No warnings or other messages will be generated for those files during a merge. Each pattern is evaluated as an .Xr sh 1 shell pattern. This option may be specified multiple times to specify multiple patterns. Multiple space-separated patterns may also be specified in a single option. .It Fl L Ar logfile Specify an alternate path for the log file. The .Nm utility logs each command that it invokes along with the standard output and standard error to this file. By default the log file is stored in a file named .Pa log in the work directory. .It Fl M Ar options Pass .Ar options as additional parameters to .Xr make 1 when building a .Dq current tree. This can be used for to set the .Dv TARGET or .Dv TARGET_ARCH variables for a cross-build. .It Fl n Enable .Dq dry-run mode. Do not merge any changes to the destination directory. Instead, report what actions would be taken during a merge. Note that the existing .Dq current and .Dq previous trees will not be changed. If the .Fl r option is not specified, then a temporary .Dq current tree will be extracted to perform the comparison. .It Fl p Enable .Dq pre-world mode. Only merge changes to files that are necessary to successfully run .Sq make installworld or .Sq make installkernel . When this flag is enabled, the existing .Dq current and .Dq previous trees are left alone. Instead, a temporary tree is populated with the necessary files. This temporary tree is compared against the .Dq current tree. This allows a normal update to be run after .Sq make installworld has completed. Any conflicts generated during a .Dq pre-world update should be resolved by a .Dq pre-world .Cm resolve . .It Fl r Do not update the .Dq current and .Dq previous trees during a merge. This can be used to .Dq re-run a previous merge operation. .It Fl s Ar source Specify an alternate source tree to use when building or extracting a .Dq current tree. The default source tree is .Pa /usr/src . .It Fl t Ar tarball Extract a new .Dq current tree from a tarball previously generated by the .Cm build command rather than building the tree from a source tree. .El .Sh CONFIG FILE The .Nm utility can also be configured by setting variables in an optional configuration file named .Pa /etc/etcupdate.conf . Note that command line options override settings in the configuration file. The configuration file is executed by .Xr sh 1 , so it uses that syntax to set configuration variables. The following variables can be set: .Bl -tag -width ".Ev ALWAYS_INSTALL" .It Ev ALWAYS_INSTALL Always install files that match any of the patterns listed in this variable similar to the .Fl A option. .It Ev DESTDIR Specify an alternate destination directory similar to the .Fl D option. .It Ev EDITOR Specify a program to edit merge conflicts. .It Ev FREEBSD_ID Ignore changes in the FreeBSD ID string similar to the .Fl F option. This is enabled by setting the variable to a non-empty value. .It Ev IGNORE_FILES Ignore files that match any of the patterns listed in this variable similar to the .Fl I option. .It Ev LOGFILE Specify an alternate path for the log file similar to the .Fl L option. .It Ev MAKE_OPTIONS Pass additional options to .Xr make 1 when building a .Dq current tree similar to the .Fl M option. .It Ev SRCDIR Specify an alternate source tree similar to the .Fl s option. .It Ev WORKDIR Specify an alternate work directory similar to the .Fl d option. .El .Sh ENVIRONMENT The .Nm utility uses the program identified in the .Ev EDITOR environment variable to edit merge conflicts. If .Ev EDITOR is not set, .Xr vi 1 is used as the default editor. .Sh FILES .Bl -tag -width ".Pa /var/db/etcupdate/log" -compact .It Pa /etc/etcupdate.conf Optional config file. .It Pa /var/db/etcupdate Default work directory used to store trees and other data. .It Pa /var/db/etcupdate/log Default log file. .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES To compare the files in .Pa /etc with the stock versions: .Pp .Dl "etcupdate diff" .Pp To merge changes after an upgrade via the buildworld and installworld process: .Pp .Dl "etcupdate" .Pp To resolve any conflicts generated during a merge: .Pp .Dl "etcupdate resolve" .Ss Bootstrapping The .Nm utility may need to be bootstrapped before it can be used. The .Cm diff command will fail with an error about a missing reference tree if bootstrapping is needed. .Pp Bootstrapping .Nm requires a source tree that matches the currently installed world. The easiest way to ensure this is to bootstrap .Nm before updating the source tree to start the next world upgrade cycle. First, generate a reference tree: .Pp .Dl "etcupdate extract" .Pp Second, use the .Cm diff command to compare the reference tree to your current files in .Pa /etc . Undesired differences should be removed using an editor, .Xr patch 1 , or by copying files from the reference tree .Po located at .Pa /var/db/etcupdate/current by default .Pc . .Pp If the tree at .Pa /usr/src is already newer than the currently installed world, a new tree matching the currently installed world can be checked out to a temporary location. The reference tree for .Nm can then be generated via: .Pp .Dl "etcupdate extract -s /path/to/tree" .Pp The .Cm diff command can be used as above to remove undesired differences. Afterwards, the changes in the tree at .Pa /usr/src can be merged via a regular merge. .Sh DIAGNOSTICS The following warning messages may be generated during a merge. Note that several of these warnings cover obscure cases that should occur rarely if at all in practice. For example, if a file changes from a file to a directory in the .Dq current tree and the file was modified in the destination directory, then a warning will be triggered. In general, when a warning references a pathname, the corresponding file in the destination directory is not changed by a merge operation. .Bl -diag .It "Directory mismatch: ()" An attempt was made to create a directory at .Pa path but an existing file of type .Dq type already exists for that path name. .It "Modified link changed: ( became )" The target of a symbolic link named .Pa file was changed from .Dq old to .Dq new in the .Dq current tree. The symbolic link has been modified to point to a target that is neither .Dq old nor .Dq new in the destination directory. .It "Modified mismatch: ( vs )" A file named .Pa file of type .Dq new was modified in the .Dq current tree, but the file exists as a different type .Dq dest in the destination directory. .It "Modified changed: ( became )" A file named .Pa file changed type from .Dq old in the .Dq previous tree to type .Dq new in the .Dq current tree. The file in the destination directory of type .Dq type has been modified, so it could not be merged automatically. .It "Modified remains: " The file of type .Dq type named .Pa file has been removed from the .Dq current tree, but it has been locally modified. The modified version of the file remains in the destination directory. .It "Needs update: /etc/localtime (required manual update via tzsetup(1))" The .Fa /var/db/zoneinfo file does not exist, so .Nm was not able to refresh .Fa /etc/localtime from its source file in .Fa /usr/share/zoneinfo . Running .Xr tzsetup 1 will both refresh .Fa /etc/localtime and generate .Fa /var/db/zoneinfo permitting future updates to refresh .Fa /etc/localtime automatically. .It "Needs update: /etc/mail/aliases.db (required manual update via newaliases(1))" The file .Pa /etc/mail/aliases was updated during a merge with a non-empty destination directory. Due to a limitation of the .Xr newaliases 1 command, .Nm was not able to automatically update the corresponding aliases database. .It "New file mismatch: ( vs )" A new file named .Pa file of type .Dq new has been added to the .Dq current tree. A file of that name already exists in the destination directory, but it is of a different type .Dq dest . .It "New link conflict: ( vs )" A symbolic link named .Pa file has been added to the .Dq current tree that links to .Dq new . A symbolic link of the same name already exists in the destination directory, but it links to a different target .Dq dest . .It "Non-empty directory remains: " The directory .Pa file was removed from the .Dq current tree, but it contains additional files in the destination directory. These additional files as well as the directory remain. .It "Remove mismatch: ( became )" A file named .Pa file changed from type .Dq old in the .Dq previous tree to type .Dq new in the .Dq current tree, but it has been removed in the destination directory. .It "Removed file changed: " A file named .Pa file was modified in the .Dq current tree, but it has been removed in the destination directory. .It "Removed link changed: ( became )" The target of a symbolic link named .Pa file was changed from .Dq old to .Dq new in the .Dq current tree, but it has been removed in the destination directory. .El .Sh SEE ALSO .Xr cap_mkdb 1 , .Xr diff 1 , .Xr make 1 , .Xr newaliases 1 , .Xr sh 1 , .Xr pwd_mkdb 8 .Sh HISTORY The .Nm utility first appeared in .Fx 10.0 . .Sh AUTHORS The .Nm utility was written by .An John Baldwin Aq jhb@FreeBSD.org . .Sh BUGS Rerunning a merge does not automatically delete conflicts left over from a previous merge. Any conflicts must be resolved before the merge can be rerun. It it is not clear if this is a feature or a bug. .Pp There is no way to easily automate conflict resolution for specific files. For example, one can imagine a syntax along the lines of .Pp .Dl "etcupdate resolve tf /some/file" .Pp to resolve a specific conflict in an automated fashion. .Pp It might be nice to have something like a .Sq revert command to replace a locally modified version of a file with the stock version of the file. For example: .Pp .Dl "etcupdate revert /etc/mail/freebsd.cf" .Pp Bootstrapping .Nm often results in gratuitous diffs in .Pa /etc/mail/*.cf that cause conflicts in the first merge. If an object tree that matches the source tree is present when bootstrapping, then passing the .Fl B flag to the .Cm extract command can work around this. Index: stable/9/usr.sbin/etcupdate/etcupdate.sh =================================================================== --- stable/9/usr.sbin/etcupdate/etcupdate.sh (revision 283926) +++ stable/9/usr.sbin/etcupdate/etcupdate.sh (revision 283927) @@ -1,1794 +1,1794 @@ #!/bin/sh # -# Copyright (c) 2010-2013 Advanced Computing Technologies LLC +# Copyright (c) 2010-2013 Hudson River Trading LLC # Written by: John H. Baldwin # 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$ # This is a tool to manage updating files that are not updated as part # of 'make installworld' such as files in /etc. Unlike other tools, # this one is specifically tailored to assisting with mass upgrades. # To that end it does not require user intervention while running. # # Theory of operation: # # The most reliable way to update changes to files that have local # modifications is to perform a three-way merge between the original # unmodified file, the new version of the file, and the modified file. # This requires having all three versions of the file available when # performing an update. # # To that end, etcupdate uses a strategy where the current unmodified # tree is kept in WORKDIR/current and the previous unmodified tree is # kept in WORKDIR/old. When performing a merge, a new tree is built # if needed and then the changes are merged into DESTDIR. Any files # with unresolved conflicts after the merge are left in a tree rooted # at WORKDIR/conflicts. # # To provide extra flexibility, etcupdate can also build tarballs of # root trees that can later be used. It can also use a tarball as the # source of a new tree instead of building it from /usr/src. # Global settings. These can be adjusted by config files and in some # cases by command line options. # TODO: # - automatable conflict resolution # - a 'revert' command to make a file "stock" usage() { cat < etcupdate diff [-d workdir] [-D destdir] [-I patterns] [-L logfile] etcupdate extract [-B] [-d workdir] [-s source | -t tarball] [-L logfile] [-M options] etcupdate resolve [-p] [-d workdir] [-D destdir] [-L logfile] etcupdate status [-d workdir] [-D destdir] EOF exit 1 } # Used to write a message prepended with '>>>' to the logfile. log() { echo ">>>" "$@" >&3 } # Used for assertion conditions that should never happen. panic() { echo "PANIC:" "$@" exit 10 } # Used to write a warning message. These are saved to the WARNINGS # file with " " prepended. warn() { echo -n " " >> $WARNINGS echo "$@" >> $WARNINGS } # Output a horizontal rule using the passed-in character. Matches the # length used for Index lines in CVS and SVN diffs. # # $1 - character rule() { jot -b "$1" -s "" 67 } # Output a text description of a specified file's type. # # $1 - file pathname. file_type() { stat -f "%HT" $1 | tr "[:upper:]" "[:lower:]" } # Returns true (0) if a file exists # # $1 - file pathname. exists() { [ -e $1 -o -L $1 ] } # Returns true (0) if a file should be ignored, false otherwise. # # $1 - file pathname ignore() { local pattern - set -o noglob for pattern in $IGNORE_FILES; do set +o noglob case $1 in $pattern) return 0 ;; esac set -o noglob done # Ignore /.cshrc and /.profile if they are hardlinked to the # same file in /root. This ensures we only compare those # files once in that case. case $1 in /.cshrc|/.profile) if [ ${DESTDIR}$1 -ef ${DESTDIR}/root$1 ]; then return 0 fi ;; *) ;; esac return 1 } # Returns true (0) if the new version of a file should always be # installed rather than attempting to do a merge. # # $1 - file pathname always_install() { local pattern - set -o noglob for pattern in $ALWAYS_INSTALL; do set +o noglob case $1 in $pattern) return 0 ;; esac set -o noglob done return 1 } # Build a new tree # # $1 - directory to store new tree in build_tree() { local destdir dir file make make="make $MAKE_OPTIONS" log "Building tree at $1 with $make" mkdir -p $1/usr/obj >&3 2>&1 destdir=`realpath $1` if [ -n "$preworld" ]; then # Build a limited tree that only contains files that are # crucial to installworld. for file in $PREWORLD_FILES; do dir=`dirname /$file` mkdir -p $1/$dir >&3 2>&1 || return 1 cp -p $SRCDIR/$file $1/$file || return 1 done elif ! [ -n "$nobuild" ]; then (cd $SRCDIR; $make DESTDIR=$destdir distrib-dirs && MAKEOBJDIRPREFIX=$destdir/usr/obj $make _obj SUBDIR_OVERRIDE=etc && MAKEOBJDIRPREFIX=$destdir/usr/obj $make everything SUBDIR_OVERRIDE=etc && MAKEOBJDIRPREFIX=$destdir/usr/obj $make DESTDIR=$destdir distribution) \ >&3 2>&1 || return 1 else (cd $SRCDIR; $make DESTDIR=$destdir distrib-dirs && $make DESTDIR=$destdir distribution) >&3 2>&1 || return 1 fi chflags -R noschg $1 >&3 2>&1 || return 1 rm -rf $1/usr/obj >&3 2>&1 || return 1 # Purge auto-generated files. Only the source files need to # be updated after which these files are regenerated. rm -f $1/etc/*.db $1/etc/passwd >&3 2>&1 || return 1 # Remove empty files. These just clutter the output of 'diff'. find $1 -type f -size 0 -delete >&3 2>&1 || return 1 # Trim empty directories. find -d $1 -type d -empty -delete >&3 2>&1 || return 1 return 0 } # Generate a new NEWTREE tree. If tarball is set, then the tree is # extracted from the tarball. Otherwise the tree is built from a # source tree. extract_tree() { local files # If we have a tarball, extract that into the new directory. if [ -n "$tarball" ]; then files= if [ -n "$preworld" ]; then files="$PREWORLD_FILES" fi if ! (mkdir -p $NEWTREE && tar xf $tarball -C $NEWTREE $files) \ >&3 2>&1; then echo "Failed to extract new tree." remove_tree $NEWTREE exit 1 fi else if ! build_tree $NEWTREE; then echo "Failed to build new tree." remove_tree $NEWTREE exit 1 fi fi } # Forcefully remove a tree. Returns true (0) if the operation succeeds. # # $1 - path to tree remove_tree() { rm -rf $1 >&3 2>&1 if [ -e $1 ]; then chflags -R noschg $1 >&3 2>&1 rm -rf $1 >&3 2>&1 fi [ ! -e $1 ] } # Return values for compare() COMPARE_EQUAL=0 COMPARE_ONLYFIRST=1 COMPARE_ONLYSECOND=2 COMPARE_DIFFTYPE=3 COMPARE_DIFFLINKS=4 COMPARE_DIFFFILES=5 # Compare two files/directories/symlinks. Note that this does not # recurse into subdirectories. Instead, if two nodes are both # directories, they are assumed to be equivalent. # # Returns true (0) if the nodes are identical. If only one of the two # nodes are present, return one of the COMPARE_ONLY* constants. If # the nodes are different, return one of the COMPARE_DIFF* constants # to indicate the type of difference. # # $1 - first node # $2 - second node compare() { local first second # If the first node doesn't exist, then check for the second # node. Note that -e will fail for a symbolic link that # points to a missing target. if ! exists $1; then if exists $2; then return $COMPARE_ONLYSECOND else return $COMPARE_EQUAL fi elif ! exists $2; then return $COMPARE_ONLYFIRST fi # If the two nodes are different file types fail. first=`stat -f "%Hp" $1` second=`stat -f "%Hp" $2` if [ "$first" != "$second" ]; then return $COMPARE_DIFFTYPE fi # If both are symlinks, compare the link values. if [ -L $1 ]; then first=`readlink $1` second=`readlink $2` if [ "$first" = "$second" ]; then return $COMPARE_EQUAL else return $COMPARE_DIFFLINKS fi fi # If both are files, compare the file contents. if [ -f $1 ]; then if cmp -s $1 $2; then return $COMPARE_EQUAL else return $COMPARE_DIFFFILES fi fi # As long as the two nodes are the same type of file, consider # them equivalent. return $COMPARE_EQUAL } # Returns true (0) if the only difference between two regular files is a # change in the FreeBSD ID string. # # $1 - path of first file # $2 - path of second file fbsdid_only() { diff -qI '\$FreeBSD.*\$' $1 $2 >/dev/null 2>&1 } # This is a wrapper around compare that will return COMPARE_EQUAL if # the only difference between two regular files is a change in the # FreeBSD ID string. It only makes this adjustment if the -F flag has # been specified. # # $1 - first node # $2 - second node compare_fbsdid() { local cmp compare $1 $2 cmp=$? if [ -n "$FREEBSD_ID" -a "$cmp" -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $1 $2; then return $COMPARE_EQUAL fi return $cmp } # Returns true (0) if a directory is empty. # # $1 - pathname of the directory to check empty_dir() { local contents contents=`ls -A $1` [ -z "$contents" ] } # Returns true (0) if one directories contents are a subset of the # other. This will recurse to handle subdirectories and compares # individual files in the trees. Its purpose is to quiet spurious # directory warnings for dryrun invocations. # # $1 - first directory (sub) # $2 - second directory (super) dir_subset() { local contents file if ! [ -d $1 -a -d $2 ]; then return 1 fi # Ignore files that are present in the second directory but not # in the first. contents=`ls -A $1` for file in $contents; do if ! compare $1/$file $2/$file; then return 1 fi if [ -d $1/$file ]; then if ! dir_subset $1/$file $2/$file; then return 1 fi fi done return 0 } # Returns true (0) if a directory in the destination tree is empty. # If this is a dryrun, then this returns true as long as the contents # of the directory are a subset of the contents in the old tree # (meaning that the directory would be empty in a non-dryrun when this # was invoked) to quiet spurious warnings. # # $1 - pathname of the directory to check relative to DESTDIR. empty_destdir() { if [ -n "$dryrun" ]; then dir_subset $DESTDIR/$1 $OLDTREE/$1 return fi empty_dir $DESTDIR/$1 } # Output a diff of two directory entries with the same relative name # in different trees. Note that as with compare(), this does not # recurse into subdirectories. If the nodes are identical, nothing is # output. # # $1 - first tree # $2 - second tree # $3 - node name # $4 - label for first tree # $5 - label for second tree diffnode() { local first second file old new diffargs if [ -n "$FREEBSD_ID" ]; then diffargs="-I \\\$FreeBSD.*\\\$" else diffargs="" fi compare_fbsdid $1/$3 $2/$3 case $? in $COMPARE_EQUAL) ;; $COMPARE_ONLYFIRST) echo echo "Removed: $3" echo ;; $COMPARE_ONLYSECOND) echo echo "Added: $3" echo ;; $COMPARE_DIFFTYPE) first=`file_type $1/$3` second=`file_type $2/$3` echo echo "Node changed from a $first to a $second: $3" echo ;; $COMPARE_DIFFLINKS) first=`readlink $1/$file` second=`readlink $2/$file` echo echo "Link changed: $file" rule "=" echo "-$first" echo "+$second" echo ;; $COMPARE_DIFFFILES) echo "Index: $3" rule "=" diff -u $diffargs -L "$3 ($4)" $1/$3 -L "$3 ($5)" $2/$3 ;; esac } # Run one-off commands after an update has completed. These commands # are not tied to a specific file, so they cannot be handled by # post_install_file(). post_update() { local args # None of these commands should be run for a pre-world update. if [ -n "$preworld" ]; then return fi # If /etc/localtime exists and is not a symlink and /var/db/zoneinfo # exists, run tzsetup -r to refresh /etc/localtime. if [ -f ${DESTDIR}/etc/localtime -a \ ! -L ${DESTDIR}/etc/localtime ]; then if [ -f ${DESTDIR}/var/db/zoneinfo ]; then if [ -n "${DESTDIR}" ]; then args="-C ${DESTDIR}" else args="" fi log "tzsetup -r ${args}" if [ -z "$dryrun" ]; then tzsetup -r ${args} >&3 2>&1 fi else warn "Needs update: /etc/localtime (required" \ "manual update via tzsetup(1))" fi fi } # Create missing parent directories of a node in a target tree # preserving the owner, group, and permissions from a specified # template tree. # # $1 - template tree # $2 - target tree # $3 - pathname of the node (relative to both trees) install_dirs() { local args dir dir=`dirname $3` # Nothing to do if the parent directory exists. This also # catches the degenerate cases when the path is just a simple # filename. if [ -d ${2}$dir ]; then return 0 fi # If non-directory file exists with the desired directory # name, then fail. if exists ${2}$dir; then # If this is a dryrun and we are installing the # directory in the DESTDIR and the file in the DESTDIR # matches the file in the old tree, then fake success # to quiet spurious warnings. if [ -n "$dryrun" -a "$2" = "$DESTDIR" ]; then if compare $OLDTREE/$dir $DESTDIR/$dir; then return 0 fi fi args=`file_type ${2}$dir` warn "Directory mismatch: ${2}$dir ($args)" return 1 fi # Ensure the parent directory of the directory is present # first. if ! install_dirs $1 "$2" $dir; then return 1 fi # Format attributes from template directory as install(1) # arguments. args=`stat -f "-o %Su -g %Sg -m %0Mp%0Lp" $1/$dir` log "install -d $args ${2}$dir" if [ -z "$dryrun" ]; then install -d $args ${2}$dir >&3 2>&1 fi return 0 } # Perform post-install fixups for a file. This largely consists of # regenerating any files that depend on the newly installed file. # # $1 - pathname of the updated file (relative to DESTDIR) post_install_file() { case $1 in /etc/mail/aliases) # Grr, newaliases only works for an empty DESTDIR. if [ -z "$DESTDIR" ]; then log "newaliases" if [ -z "$dryrun" ]; then newaliases >&3 2>&1 fi else NEWALIAS_WARN=yes fi ;; /etc/login.conf) log "cap_mkdb ${DESTDIR}$1" if [ -z "$dryrun" ]; then cap_mkdb ${DESTDIR}$1 >&3 2>&1 fi ;; /etc/master.passwd) log "pwd_mkdb -p -d $DESTDIR/etc ${DESTDIR}$1" if [ -z "$dryrun" ]; then pwd_mkdb -p -d $DESTDIR/etc ${DESTDIR}$1 \ >&3 2>&1 fi ;; /etc/motd) # /etc/rc.d/motd hardcodes the /etc/motd path. # Don't warn about non-empty DESTDIR's since this # change is only cosmetic anyway. if [ -z "$DESTDIR" ]; then log "sh /etc/rc.d/motd start" if [ -z "$dryrun" ]; then sh /etc/rc.d/motd start >&3 2>&1 fi fi ;; /etc/services) log "services_mkdb -q -o $DESTDIR/var/db/services.db" \ "${DESTDIR}$1" if [ -z "$dryrun" ]; then services_mkdb -q -o $DESTDIR/var/db/services.db \ ${DESTDIR}$1 >&3 2>&1 fi ;; esac } # Install the "new" version of a file. Returns true if it succeeds # and false otherwise. # # $1 - pathname of the file to install (relative to DESTDIR) install_new() { if ! install_dirs $NEWTREE "$DESTDIR" $1; then return 1 fi log "cp -Rp ${NEWTREE}$1 ${DESTDIR}$1" if [ -z "$dryrun" ]; then cp -Rp ${NEWTREE}$1 ${DESTDIR}$1 >&3 2>&1 fi post_install_file $1 return 0 } # Install the "resolved" version of a file. Returns true if it succeeds # and false otherwise. # # $1 - pathname of the file to install (relative to DESTDIR) install_resolved() { # This should always be present since the file is already # there (it caused a conflict). However, it doesn't hurt to # just be safe. if ! install_dirs $NEWTREE "$DESTDIR" $1; then return 1 fi log "cp -Rp ${CONFLICTS}$1 ${DESTDIR}$1" cp -Rp ${CONFLICTS}$1 ${DESTDIR}$1 >&3 2>&1 post_install_file $1 return 0 } # Generate a conflict file when a "new" file conflicts with an # existing file in DESTDIR. # # $1 - pathname of the file that conflicts (relative to DESTDIR) new_conflict() { if [ -n "$dryrun" ]; then return fi install_dirs $NEWTREE $CONFLICTS $1 diff --changed-group-format='<<<<<<< (local) %<======= %>>>>>>>> (stock) ' $DESTDIR/$1 $NEWTREE/$1 > $CONFLICTS/$1 } # Remove the "old" version of a file. # # $1 - pathname of the old file to remove (relative to DESTDIR) remove_old() { log "rm -f ${DESTDIR}$1" if [ -z "$dryrun" ]; then rm -f ${DESTDIR}$1 >&3 2>&1 fi echo " D $1" } # Update a file that has no local modifications. # # $1 - pathname of the file to update (relative to DESTDIR) update_unmodified() { local new old # If the old file is a directory, then remove it with rmdir # (this should only happen if the file has changed its type # from a directory to a non-directory). If the directory # isn't empty, then fail. This will be reported as a warning # later. if [ -d $DESTDIR/$1 ]; then if empty_destdir $1; then log "rmdir ${DESTDIR}$1" if [ -z "$dryrun" ]; then rmdir ${DESTDIR}$1 >&3 2>&1 fi else return 1 fi # If both the old and new files are regular files, leave the # existing file. This avoids breaking hard links for /.cshrc # and /.profile. Otherwise, explicitly remove the old file. elif ! [ -f ${DESTDIR}$1 -a -f ${NEWTREE}$1 ]; then log "rm -f ${DESTDIR}$1" if [ -z "$dryrun" ]; then rm -f ${DESTDIR}$1 >&3 2>&1 fi fi # If the new file is a directory, note that the old file has # been removed, but don't do anything else for now. The # directory will be installed if needed when new files within # that directory are installed. if [ -d $NEWTREE/$1 ]; then if empty_dir $NEWTREE/$1; then echo " D $file" else echo " U $file" fi elif install_new $1; then echo " U $file" fi return 0 } # Update the FreeBSD ID string in a locally modified file to match the # FreeBSD ID string from the "new" version of the file. # # $1 - pathname of the file to update (relative to DESTDIR) update_freebsdid() { local new dest file # If the FreeBSD ID string is removed from the local file, # there is nothing to do. In this case, treat the file as # updated. Otherwise, if either file has more than one # FreeBSD ID string, just punt and let the user handle the # conflict manually. new=`grep -c '\$FreeBSD.*\$' ${NEWTREE}$1` dest=`grep -c '\$FreeBSD.*\$' ${DESTDIR}$1` if [ "$dest" -eq 0 ]; then return 0 fi if [ "$dest" -ne 1 -o "$dest" -ne 1 ]; then return 1 fi # If the FreeBSD ID string in the new file matches the FreeBSD ID # string in the local file, there is nothing to do. new=`grep '\$FreeBSD.*\$' ${NEWTREE}$1` dest=`grep '\$FreeBSD.*\$' ${DESTDIR}$1` if [ "$new" = "$dest" ]; then return 0 fi # Build the new file in three passes. First, copy all the # lines preceding the FreeBSD ID string from the local version # of the file. Second, append the FreeBSD ID string line from # the new version. Finally, append all the lines after the # FreeBSD ID string from the local version of the file. file=`mktemp $WORKDIR/etcupdate-XXXXXXX` awk '/\$FreeBSD.*\$/ { exit } { print }' ${DESTDIR}$1 >> $file awk '/\$FreeBSD.*\$/ { print }' ${NEWTREE}$1 >> $file awk '/\$FreeBSD.*\$/ { ok = 1; next } { if (ok) print }' \ ${DESTDIR}$1 >> $file # As an extra sanity check, fail the attempt if the updated # version of the file has any differences aside from the # FreeBSD ID string. if ! fbsdid_only ${DESTDIR}$1 $file; then rm -f $file return 1 fi log "cp $file ${DESTDIR}$1" if [ -z "$dryrun" ]; then cp $file ${DESTDIR}$1 >&3 2>&1 fi rm -f $file post_install_file $1 echo " M $1" return 0 } # Attempt to update a file that has local modifications. This routine # only handles regular files. If the 3-way merge succeeds without # conflicts, the updated file is installed. If the merge fails, the # merged version with conflict markers is left in the CONFLICTS tree. # # $1 - pathname of the file to merge (relative to DESTDIR) merge_file() { local res # Try the merge to see if there is a conflict. merge -q -p ${DESTDIR}$1 ${OLDTREE}$1 ${NEWTREE}$1 >/dev/null 2>&3 res=$? case $res in 0) # No conflicts, so just redo the merge to the # real file. log "merge ${DESTDIR}$1 ${OLDTREE}$1 ${NEWTREE}$1" if [ -z "$dryrun" ]; then merge ${DESTDIR}$1 ${OLDTREE}$1 ${NEWTREE}$1 fi post_install_file $1 echo " M $1" ;; 1) # Conflicts, save a version with conflict markers in # the conflicts directory. if [ -z "$dryrun" ]; then install_dirs $NEWTREE $CONFLICTS $1 log "cp -Rp ${DESTDIR}$1 ${CONFLICTS}$1" cp -Rp ${DESTDIR}$1 ${CONFLICTS}$1 >&3 2>&1 merge -A -q -L "yours" -L "original" -L "new" \ ${CONFLICTS}$1 ${OLDTREE}$1 ${NEWTREE}$1 fi echo " C $1" ;; *) panic "merge failed with status $res" ;; esac } # Returns true if a file contains conflict markers from a merge conflict. # # $1 - pathname of the file to resolve (relative to DESTDIR) has_conflicts() { egrep -q '^(<{7}|\|{7}|={7}|>{7}) ' $CONFLICTS/$1 } # Attempt to resolve a conflict. The user is prompted to choose an # action for each conflict. If the user edits the file, they are # prompted again for an action. The process is very similar to # resolving conflicts after an update or merge with Perforce or # Subversion. The prompts are modelled on a subset of the available # commands for resolving conflicts with Subversion. # # $1 - pathname of the file to resolve (relative to DESTDIR) resolve_conflict() { local command junk echo "Resolving conflict in '$1':" edit= while true; do # Only display the resolved command if the file # doesn't contain any conflicts. echo -n "Select: (p) postpone, (df) diff-full, (e) edit," if ! has_conflicts $1; then echo -n " (r) resolved," fi echo echo -n " (h) help for more options: " read command case $command in df) diff -u ${DESTDIR}$1 ${CONFLICTS}$1 ;; e) $EDITOR ${CONFLICTS}$1 ;; h) cat </dev/null 2>&1 fi echo " D $dir" else warn "Non-empty directory remains: $dir" fi fi } # Handle a file that exists in both the old and new trees. If the # file has not changed in the old and new trees, there is nothing to # do. If the file in the destination directory matches the new file, # there is nothing to do. If the file in the destination directory # matches the old file, then the new file should be installed. # Everything else becomes some sort of conflict with more detailed # handling. # # $1 - pathname of the file (relative to DESTDIR) handle_modified_file() { local cmp dest file new newdestcmp old file=$1 if ignore $file; then log "IGNORE: modified file $file" return fi compare $OLDTREE/$file $NEWTREE/$file cmp=$? if [ $cmp -eq $COMPARE_EQUAL ]; then return fi if [ $cmp -eq $COMPARE_ONLYFIRST -o $cmp -eq $COMPARE_ONLYSECOND ]; then panic "Changed file now missing" fi compare $NEWTREE/$file $DESTDIR/$file newdestcmp=$? if [ $newdestcmp -eq $COMPARE_EQUAL ]; then return fi # If the only change in the new file versus the destination # file is a change in the FreeBSD ID string and -F is # specified, just install the new file. if [ -n "$FREEBSD_ID" -a $newdestcmp -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $NEWTREE/$file $DESTDIR/$file; then if update_unmodified $file; then return else panic "Updating FreeBSD ID string failed" fi fi # If the local file is the same as the old file, install the # new file. If -F is specified and the only local change is # in the FreeBSD ID string, then install the new file as well. if compare_fbsdid $OLDTREE/$file $DESTDIR/$file; then if update_unmodified $file; then return fi fi # If the file was removed from the dest tree, just whine. if [ $newdestcmp -eq $COMPARE_ONLYFIRST ]; then # If the removed file matches an ALWAYS_INSTALL glob, # then just install the new version of the file. if always_install $file; then log "ALWAYS: adding $file" if ! [ -d $NEWTREE/$file ]; then if install_new $file; then echo " A $file" fi fi return fi # If the only change in the new file versus the old # file is a change in the FreeBSD ID string and -F is # specified, don't warn. if [ -n "$FREEBSD_ID" -a $cmp -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $OLDTREE/$file $NEWTREE/$file; then return fi case $cmp in $COMPARE_DIFFTYPE) old=`file_type $OLDTREE/$file` new=`file_type $NEWTREE/$file` warn "Remove mismatch: $file ($old became $new)" ;; $COMPARE_DIFFLINKS) old=`readlink $OLDTREE/$file` new=`readlink $NEWTREE/$file` warn \ "Removed link changed: $file (\"$old\" became \"$new\")" ;; $COMPARE_DIFFFILES) warn "Removed file changed: $file" ;; esac return fi # Treat the file as unmodified and force install of the new # file if it matches an ALWAYS_INSTALL glob. If the update # attempt fails, then fall through to the normal case so a # warning is generated. if always_install $file; then log "ALWAYS: updating $file" if update_unmodified $file; then return fi fi # If the only change in the new file versus the old file is a # change in the FreeBSD ID string and -F is specified, just # update the FreeBSD ID string in the local file. if [ -n "$FREEBSD_ID" -a $cmp -eq $COMPARE_DIFFFILES ] && \ fbsdid_only $OLDTREE/$file $NEWTREE/$file; then if update_freebsdid $file; then continue fi fi # If the file changed types between the old and new trees but # the files in the new and dest tree are both of the same # type, treat it like an added file just comparing the new and # dest files. if [ $cmp -eq $COMPARE_DIFFTYPE ]; then case $newdestcmp in $COMPARE_DIFFLINKS) new=`readlink $NEWTREE/$file` dest=`readlink $DESTDIR/$file` warn \ "New link conflict: $file (\"$new\" vs \"$dest\")" return ;; $COMPARE_DIFFFILES) new_conflict $file echo " C $file" return ;; esac else # If the file has not changed types between the old # and new trees, but it is a different type in # DESTDIR, then just warn. if [ $newdestcmp -eq $COMPARE_DIFFTYPE ]; then new=`file_type $NEWTREE/$file` dest=`file_type $DESTDIR/$file` warn "Modified mismatch: $file ($new vs $dest)" return fi fi case $cmp in $COMPARE_DIFFTYPE) old=`file_type $OLDTREE/$file` new=`file_type $NEWTREE/$file` dest=`file_type $DESTDIR/$file` warn "Modified $dest changed: $file ($old became $new)" ;; $COMPARE_DIFFLINKS) old=`readlink $OLDTREE/$file` new=`readlink $NEWTREE/$file` warn \ "Modified link changed: $file (\"$old\" became \"$new\")" ;; $COMPARE_DIFFFILES) merge_file $file ;; esac } # Handle a file that has been added in the new tree. If the file does # not exist in DESTDIR, simply copy the file into DESTDIR. If the # file exists in the DESTDIR and is identical to the new version, do # nothing. Otherwise, generate a diff of the two versions of the file # and mark it as a conflict. # # $1 - pathname of the file (relative to DESTDIR) handle_added_file() { local cmp dest file new file=$1 if ignore $file; then log "IGNORE: added file $file" return fi compare $DESTDIR/$file $NEWTREE/$file cmp=$? case $cmp in $COMPARE_EQUAL) return ;; $COMPARE_ONLYFIRST) panic "Added file now missing" ;; $COMPARE_ONLYSECOND) # Ignore new directories. They will be # created as needed when non-directory nodes # are installed. if ! [ -d $NEWTREE/$file ]; then if install_new $file; then echo " A $file" fi fi return ;; esac # Treat the file as unmodified and force install of the new # file if it matches an ALWAYS_INSTALL glob. If the update # attempt fails, then fall through to the normal case so a # warning is generated. if always_install $file; then log "ALWAYS: updating $file" if update_unmodified $file; then return fi fi case $cmp in $COMPARE_DIFFTYPE) new=`file_type $NEWTREE/$file` dest=`file_type $DESTDIR/$file` warn "New file mismatch: $file ($new vs $dest)" ;; $COMPARE_DIFFLINKS) new=`readlink $NEWTREE/$file` dest=`readlink $DESTDIR/$file` warn "New link conflict: $file (\"$new\" vs \"$dest\")" ;; $COMPARE_DIFFFILES) # If the only change in the new file versus # the destination file is a change in the # FreeBSD ID string and -F is specified, just # install the new file. if [ -n "$FREEBSD_ID" ] && \ fbsdid_only $NEWTREE/$file $DESTDIR/$file; then if update_unmodified $file; then return else panic \ "Updating FreeBSD ID string failed" fi fi new_conflict $file echo " C $file" ;; esac } # Main routines for each command # Build a new tree and save it in a tarball. build_cmd() { local dir if [ $# -ne 1 ]; then echo "Missing required tarball." echo usage fi log "build command: $1" # Create a temporary directory to hold the tree dir=`mktemp -d $WORKDIR/etcupdate-XXXXXXX` if [ $? -ne 0 ]; then echo "Unable to create temporary directory." exit 1 fi if ! build_tree $dir; then echo "Failed to build tree." remove_tree $dir exit 1 fi if ! tar cfj $1 -C $dir . >&3 2>&1; then echo "Failed to create tarball." remove_tree $dir exit 1 fi remove_tree $dir } # Output a diff comparing the tree at DESTDIR to the current # unmodified tree. Note that this diff does not include files that # are present in DESTDIR but not in the unmodified tree. diff_cmd() { local file if [ $# -ne 0 ]; then usage fi # Requires an unmodified tree to diff against. if ! [ -d $NEWTREE ]; then echo "Reference tree to diff against unavailable." exit 1 fi # Unfortunately, diff alone does not quite provide the right # level of options that we want, so improvise. for file in `(cd $NEWTREE; find .) | sed -e 's/^\.//'`; do if ignore $file; then continue fi diffnode $NEWTREE "$DESTDIR" $file "stock" "local" done } # Just extract a new tree into NEWTREE either by building a tree or # extracting a tarball. This can be used to bootstrap updates by # initializing the current "stock" tree to match the currently # installed system. # # Unlike 'update', this command does not rotate or preserve an # existing NEWTREE, it just replaces any existing tree. extract_cmd() { if [ $# -ne 0 ]; then usage fi log "extract command: tarball=$tarball" if [ -d $NEWTREE ]; then if ! remove_tree $NEWTREE; then echo "Unable to remove current tree." exit 1 fi fi extract_tree } # Resolve conflicts left from an earlier merge. resolve_cmd() { local conflicts if [ $# -ne 0 ]; then usage fi if ! [ -d $CONFLICTS ]; then return fi if ! [ -d $NEWTREE ]; then echo "The current tree is not present to resolve conflicts." exit 1 fi conflicts=`(cd $CONFLICTS; find . ! -type d) | sed -e 's/^\.//'` for file in $conflicts; do resolve_conflict $file done if [ -n "$NEWALIAS_WARN" ]; then warn "Needs update: /etc/mail/aliases.db" \ "(requires manual update via newaliases(1))" echo echo "Warnings:" echo " Needs update: /etc/mail/aliases.db" \ "(requires manual update via newaliases(1))" fi } # Report a summary of the previous merge. Specifically, list any # remaining conflicts followed by any warnings from the previous # update. status_cmd() { if [ $# -ne 0 ]; then usage fi if [ -d $CONFLICTS ]; then (cd $CONFLICTS; find . ! -type d) | sed -e 's/^\./ C /' fi if [ -s $WARNINGS ]; then echo "Warnings:" cat $WARNINGS fi } # Perform an actual merge. The new tree can either already exist (if # rerunning a merge), be extracted from a tarball, or generated from a # source tree. update_cmd() { local dir if [ $# -ne 0 ]; then usage fi log "update command: rerun=$rerun tarball=$tarball preworld=$preworld" if [ `id -u` -ne 0 ]; then echo "Must be root to update a tree." exit 1 fi # Enforce a sane umask umask 022 # XXX: Should existing conflicts be ignored and removed during # a rerun? # Trim the conflicts tree. Whine if there is anything left. if [ -e $CONFLICTS ]; then find -d $CONFLICTS -type d -empty -delete >&3 2>&1 rmdir $CONFLICTS >&3 2>&1 fi if [ -d $CONFLICTS ]; then echo "Conflicts remain from previous update, aborting." exit 1 fi if [ -z "$rerun" ]; then # For a dryrun that is not a rerun, do not rotate the existing # stock tree. Instead, extract a tree to a temporary directory # and use that for the comparison. if [ -n "$dryrun" ]; then dir=`mktemp -d $WORKDIR/etcupdate-XXXXXXX` if [ $? -ne 0 ]; then echo "Unable to create temporary directory." exit 1 fi # A pre-world dryrun has already set OLDTREE to # point to the current stock tree. if [ -z "$preworld" ]; then OLDTREE=$NEWTREE fi NEWTREE=$dir # For a pre-world update, blow away any pre-existing # NEWTREE. elif [ -n "$preworld" ]; then if ! remove_tree $NEWTREE; then echo "Unable to remove pre-world tree." exit 1 fi # Rotate the existing stock tree to the old tree. elif [ -d $NEWTREE ]; then # First, delete the previous old tree if it exists. if ! remove_tree $OLDTREE; then echo "Unable to remove old tree." exit 1 fi # Move the current stock tree. if ! mv $NEWTREE $OLDTREE >&3 2>&1; then echo "Unable to rename current stock tree." exit 1 fi fi if ! [ -d $OLDTREE ]; then cat < $WORKDIR/old.files (cd $NEWTREE; find .) | sed -e 's/^\.//' | sort > $WORKDIR/new.files # Split the files up into three groups using comm. comm -23 $WORKDIR/old.files $WORKDIR/new.files > $WORKDIR/removed.files comm -13 $WORKDIR/old.files $WORKDIR/new.files > $WORKDIR/added.files comm -12 $WORKDIR/old.files $WORKDIR/new.files > $WORKDIR/both.files # Initialize conflicts and warnings handling. rm -f $WARNINGS mkdir -p $CONFLICTS # Ignore removed files for the pre-world case. A pre-world # update uses a stripped-down tree. if [ -n "$preworld" ]; then > $WORKDIR/removed.files fi # The order for the following sections is important. In the # odd case that a directory is converted into a file, the # existing subfiles need to be removed if possible before the # file is converted. Similarly, in the case that a file is # converted into a directory, the file needs to be converted # into a directory if possible before the new files are added. # First, handle removed files. for file in `cat $WORKDIR/removed.files`; do handle_removed_file $file done # For the directory pass, reverse sort the list to effect a # depth-first traversal. This is needed to ensure that if a # directory with subdirectories is removed, the entire # directory is removed if there are no local modifications. for file in `sort -r $WORKDIR/removed.files`; do handle_removed_directory $file done # Second, handle files that exist in both the old and new # trees. for file in `cat $WORKDIR/both.files`; do handle_modified_file $file done # Finally, handle newly added files. for file in `cat $WORKDIR/added.files`; do handle_added_file $file done if [ -n "$NEWALIAS_WARN" ]; then warn "Needs update: /etc/mail/aliases.db" \ "(requires manual update via newaliases(1))" fi # Run any special one-off commands after an update has completed. post_update if [ -s $WARNINGS ]; then echo "Warnings:" cat $WARNINGS fi if [ -n "$dir" ]; then if [ -z "$dryrun" -o -n "$rerun" ]; then panic "Should not have a temporary directory" fi remove_tree $dir fi } # Determine which command we are executing. A command may be # specified as the first word. If one is not specified then 'update' # is assumed as the default command. command="update" if [ $# -gt 0 ]; then case "$1" in build|diff|extract|status|resolve) command="$1" shift ;; -*) # If first arg is an option, assume the # default command. ;; *) usage ;; esac fi # Set default variable values. # The path to the source tree used to build trees. SRCDIR=/usr/src # The destination directory where the modified files live. DESTDIR= # Ignore changes in the FreeBSD ID string. FREEBSD_ID= # Files that should always have the new version of the file installed. ALWAYS_INSTALL= # Files to ignore and never update during a merge. IGNORE_FILES= # Flags to pass to 'make' when building a tree. MAKE_OPTIONS= # Include a config file if it exists. Note that command line options # override any settings in the config file. More details are in the # manual, but in general the following variables can be set: # - ALWAYS_INSTALL # - DESTDIR # - EDITOR # - FREEBSD_ID # - IGNORE_FILES # - LOGFILE # - MAKE_OPTIONS # - SRCDIR # - WORKDIR if [ -r /etc/etcupdate.conf ]; then . /etc/etcupdate.conf fi # Parse command line options tarball= rerun= always= dryrun= ignore= nobuild= preworld= while getopts "d:nprs:t:A:BD:FI:L:M:" option; do case "$option" in d) WORKDIR=$OPTARG ;; n) dryrun=YES ;; p) preworld=YES ;; r) rerun=YES ;; s) SRCDIR=$OPTARG ;; t) tarball=$OPTARG ;; A) # To allow this option to be specified # multiple times, accumulate command-line # specified patterns in an 'always' variable # and use that to overwrite ALWAYS_INSTALL # after parsing all options. Need to be # careful here with globbing expansion. set -o noglob always="$always $OPTARG" set +o noglob ;; B) nobuild=YES ;; D) DESTDIR=$OPTARG ;; F) FREEBSD_ID=YES ;; I) # To allow this option to be specified # multiple times, accumulate command-line # specified patterns in an 'ignore' variable # and use that to overwrite IGNORE_FILES after # parsing all options. Need to be careful # here with globbing expansion. set -o noglob ignore="$ignore $OPTARG" set +o noglob ;; L) LOGFILE=$OPTARG ;; M) MAKE_OPTIONS="$OPTARG" ;; *) echo usage ;; esac done shift $((OPTIND - 1)) # Allow -A command line options to override ALWAYS_INSTALL set from # the config file. set -o noglob if [ -n "$always" ]; then ALWAYS_INSTALL="$always" fi # Allow -I command line options to override IGNORE_FILES set from the # config file. if [ -n "$ignore" ]; then IGNORE_FILES="$ignore" fi set +o noglob # Where the "old" and "new" trees are stored. WORKDIR=${WORKDIR:-$DESTDIR/var/db/etcupdate} # Log file for verbose output from program that are run. The log file # is opened on fd '3'. LOGFILE=${LOGFILE:-$WORKDIR/log} # The path of the "old" tree OLDTREE=$WORKDIR/old # The path of the "new" tree NEWTREE=$WORKDIR/current # The path of the "conflicts" tree where files with merge conflicts are saved. CONFLICTS=$WORKDIR/conflicts # The path of the "warnings" file that accumulates warning notes from an update. WARNINGS=$WORKDIR/warnings # Use $EDITOR for resolving conflicts. If it is not set, default to vi. EDITOR=${EDITOR:-/usr/bin/vi} # Files that need to be updated before installworld. PREWORLD_FILES="etc/master.passwd etc/group" # Handle command-specific argument processing such as complaining # about unsupported options. Since the configuration file is always # included, do not complain about extra command line arguments that # may have been set via the config file rather than the command line. case $command in update) if [ -n "$rerun" -a -n "$tarball" ]; then echo "Only one of -r or -t can be specified." echo usage fi if [ -n "$rerun" -a -n "$preworld" ]; then echo "Only one of -p or -r can be specified." echo usage fi ;; build|diff|status) if [ -n "$dryrun" -o -n "$rerun" -o -n "$tarball" -o \ -n "$preworld" ]; then usage fi ;; resolve) if [ -n "$dryrun" -o -n "$rerun" -o -n "$tarball" ]; then usage fi ;; extract) if [ -n "$dryrun" -o -n "$rerun" -o -n "$preworld" ]; then usage fi ;; esac # Pre-world mode uses a different set of trees. It leaves the current # tree as-is so it is still present for a full etcupdate run after the # world install is complete. Instead, it installs a few critical files # into a separate tree. if [ -n "$preworld" ]; then OLDTREE=$NEWTREE NEWTREE=$WORKDIR/preworld fi # Open the log file. Don't truncate it if doing a minor operation so # that a minor operation doesn't lose log info from a major operation. if ! mkdir -p $WORKDIR 2>/dev/null; then echo "Failed to create work directory $WORKDIR" fi case $command in diff|resolve|status) exec 3>>$LOGFILE ;; *) exec 3>$LOGFILE ;; esac ${command}_cmd "$@" Index: stable/9/usr.sbin/etcupdate =================================================================== --- stable/9/usr.sbin/etcupdate (revision 283926) +++ stable/9/usr.sbin/etcupdate (revision 283927) Property changes on: stable/9/usr.sbin/etcupdate ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/usr.sbin/etcupdate:r281887 Index: stable/9/usr.sbin/pciconf/err.c =================================================================== --- stable/9/usr.sbin/pciconf/err.c (revision 283926) +++ stable/9/usr.sbin/pciconf/err.c (revision 283927) @@ -1,173 +1,173 @@ /*- - * Copyright (c) 2012 Advanced Computing Technologies LLC + * Copyright (c) 2012 Hudson River Trading LLC * Written by: John H. Baldwin * 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. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include "pciconf.h" struct bit_table { uint32_t mask; const char *desc; }; /* Error indicators in the PCI status register (PCIR_STATUS). */ static struct bit_table pci_status[] = { { PCIM_STATUS_MDPERR, "Master Data Parity Error" }, { PCIM_STATUS_STABORT, "Sent Target-Abort" }, { PCIM_STATUS_RTABORT, "Received Target-Abort" }, { PCIM_STATUS_RMABORT, "Received Master-Abort" }, { PCIM_STATUS_SERR, "Signalled System Error" }, { PCIM_STATUS_PERR, "Detected Parity Error" }, { 0, NULL }, }; /* Valid error indicator bits in PCIR_STATUS. */ #define PCI_ERRORS (PCIM_STATUS_MDPERR | PCIM_STATUS_STABORT | \ PCIM_STATUS_RTABORT | PCIM_STATUS_RMABORT | \ PCIM_STATUS_SERR | PCIM_STATUS_PERR) /* Error indicators in the PCI-Express device status register. */ static struct bit_table pcie_device_status[] = { { PCIEM_STA_CORRECTABLE_ERROR, "Correctable Error Detected" }, { PCIEM_STA_NON_FATAL_ERROR, "Non-Fatal Error Detected" }, { PCIEM_STA_FATAL_ERROR, "Fatal Error Detected" }, { PCIEM_STA_UNSUPPORTED_REQ, "Unsupported Request Detected" }, { 0, NULL }, }; /* Valid error indicator bits in the PCI-Express device status register. */ #define PCIE_ERRORS (PCIEM_STA_CORRECTABLE_ERROR | \ PCIEM_STA_NON_FATAL_ERROR | \ PCIEM_STA_FATAL_ERROR | \ PCIEM_STA_UNSUPPORTED_REQ) /* AER Uncorrected errors. */ static struct bit_table aer_uc[] = { { PCIM_AER_UC_TRAINING_ERROR, "Link Training Error" }, { PCIM_AER_UC_DL_PROTOCOL_ERROR, "Data Link Protocol Error" }, { PCIM_AER_UC_SURPRISE_LINK_DOWN, "Surprise Link Down Error" }, { PCIM_AER_UC_POISONED_TLP, "Poisoned TLP" }, { PCIM_AER_UC_FC_PROTOCOL_ERROR, "Flow Control Protocol Error" }, { PCIM_AER_UC_COMPLETION_TIMEOUT, "Completion Timeout" }, { PCIM_AER_UC_COMPLETER_ABORT, "Completer Abort" }, { PCIM_AER_UC_UNEXPECTED_COMPLETION, "Unexpected Completion" }, { PCIM_AER_UC_RECEIVER_OVERFLOW, "Receiver Overflow Error" }, { PCIM_AER_UC_MALFORMED_TLP, "Malformed TLP" }, { PCIM_AER_UC_ECRC_ERROR, "ECRC Error" }, { PCIM_AER_UC_UNSUPPORTED_REQUEST, "Unsupported Request" }, { PCIM_AER_UC_ACS_VIOLATION, "ACS Violation" }, { PCIM_AER_UC_INTERNAL_ERROR, "Uncorrectable Internal Error" }, { PCIM_AER_UC_MC_BLOCKED_TLP, "MC Blocked TLP" }, { PCIM_AER_UC_ATOMIC_EGRESS_BLK, "AtomicOp Egress Blocked" }, { PCIM_AER_UC_TLP_PREFIX_BLOCKED, "TLP Prefix Blocked Error" }, { 0, NULL }, }; /* AER Corrected errors. */ static struct bit_table aer_cor[] = { { PCIM_AER_COR_RECEIVER_ERROR, "Receiver Error" }, { PCIM_AER_COR_BAD_TLP, "Bad TLP" }, { PCIM_AER_COR_BAD_DLLP, "Bad DLLP" }, { PCIM_AER_COR_REPLAY_ROLLOVER, "REPLAY_NUM Rollover" }, { PCIM_AER_COR_REPLAY_TIMEOUT, "Replay Timer Timeout" }, { PCIM_AER_COR_ADVISORY_NF_ERROR, "Advisory Non-Fatal Error" }, { PCIM_AER_COR_INTERNAL_ERROR, "Corrected Internal Error" }, { PCIM_AER_COR_HEADER_LOG_OVFLOW, "Header Log Overflow" }, { 0, NULL }, }; static void print_bits(const char *header, struct bit_table *table, uint32_t mask) { int first; first = 1; for (; table->desc != NULL; table++) if (mask & table->mask) { if (first) { printf("%14s = ", header); first = 0; } else printf(" "); printf("%s\n", table->desc); mask &= ~table->mask; } if (mask != 0) { if (first) printf("%14s = ", header); else printf(" "); printf("Unknown: 0x%08x\n", mask); } } void list_errors(int fd, struct pci_conf *p) { uint32_t mask, severity; uint16_t sta, aer; uint8_t pcie; /* First check for standard PCI errors. */ sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); print_bits("PCI errors", pci_status, sta & PCI_ERRORS); /* See if this is a PCI-express device. */ pcie = pci_find_cap(fd, p, PCIY_EXPRESS); if (pcie == 0) return; /* Check for PCI-e errors. */ sta = read_config(fd, &p->pc_sel, pcie + PCIER_DEVICE_STA, 2); print_bits("PCI-e errors", pcie_device_status, sta & PCIE_ERRORS); /* See if this device supports AER. */ aer = pcie_find_cap(fd, p, PCIZ_AER); if (aer == 0) return; /* Check for uncorrected errors. */ mask = read_config(fd, &p->pc_sel, aer + PCIR_AER_UC_STATUS, 4); severity = read_config(fd, &p->pc_sel, aer + PCIR_AER_UC_SEVERITY, 4); print_bits("Fatal", aer_uc, mask & severity); print_bits("Non-fatal", aer_uc, mask & ~severity); /* Check for corrected errors. */ mask = read_config(fd, &p->pc_sel, aer + PCIR_AER_COR_STATUS, 4); print_bits("Corrected", aer_cor, mask); } Index: stable/9/usr.sbin/pciconf =================================================================== --- stable/9/usr.sbin/pciconf (revision 283926) +++ stable/9/usr.sbin/pciconf (revision 283927) Property changes on: stable/9/usr.sbin/pciconf ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/usr.sbin/pciconf:r281887