summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ObsoleteFiles.inc2
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Tools.cpp2
-rw-r--r--lib/libc/gen/fnmatch.c4
-rw-r--r--lib/libc/gen/glob.c4
-rw-r--r--lib/libc/locale/collate.h3
-rw-r--r--lib/libc/locale/collcmp.c23
-rw-r--r--lib/libc/regex/regcomp.c11
-rw-r--r--lib/libc/stdio/vfscanf.c6
-rw-r--r--lib/libc/sys/aio_fsync.230
-rw-r--r--lib/libc/sys/aio_mlock.213
-rw-r--r--lib/libc/sys/aio_read.213
-rw-r--r--lib/libc/sys/aio_write.213
-rw-r--r--lib/libc/sys/lio_listio.251
-rw-r--r--lib/libc/sys/mq_notify.236
-rw-r--r--lib/libc/sys/timer_create.241
-rw-r--r--lib/libcxxrt/Version.map16
-rw-r--r--libexec/rtld-elf/rtld.c2
-rw-r--r--release/Makefile3
-rw-r--r--share/man/man3/Makefile1
-rw-r--r--share/man/man3/sigevent.3127
-rw-r--r--share/man/man3/siginfo.312
-rw-r--r--share/man/man4/aio.451
-rw-r--r--share/man/man4/ddb.47
-rw-r--r--share/man/man4/mpr.431
-rw-r--r--share/man/man4/mps.4224
-rw-r--r--share/man/man9/Makefile1
-rw-r--r--share/man/man9/pci.915
-rw-r--r--share/man/man9/rman.922
-rw-r--r--sys/boot/efi/boot1/boot1.c2
-rwxr-xr-xsys/boot/efi/boot1/generate-fat.sh2
-rw-r--r--sys/cam/scsi/scsi_all.c1
-rw-r--r--sys/conf/files13
-rw-r--r--sys/dev/acpica/Osd/OsdSynch.c34
-rw-r--r--sys/dev/acpica/acpi.c40
-rw-r--r--sys/dev/acpica/acpi_cpu.c26
-rw-r--r--sys/dev/acpica/acpi_pcib_acpi.c35
-rw-r--r--sys/dev/acpica/acpivar.h3
-rw-r--r--sys/dev/an/if_an.c6
-rw-r--r--sys/dev/ciss/ciss.c29
-rw-r--r--sys/dev/e1000/if_em.c3
-rw-r--r--sys/dev/e1000/if_igb.c6
-rw-r--r--sys/dev/e1000/if_igb.h4
-rw-r--r--sys/dev/e1000/if_lem.c3
-rw-r--r--sys/dev/hptmv/hptproc.c15
-rw-r--r--sys/dev/ixgb/if_ixgb.c3
-rw-r--r--sys/dev/ixgbe/if_ix.c3
-rw-r--r--sys/dev/ixgbe/if_ixv.c3
-rw-r--r--sys/dev/ixgbe/ixgbe_phy.c15
-rw-r--r--sys/dev/ixl/if_ixl.c3
-rw-r--r--sys/dev/ixl/if_ixlv.c3
-rw-r--r--sys/dev/mpr/mpr.c11
-rw-r--r--sys/dev/mpr/mpr_sas.c22
-rw-r--r--sys/dev/mpr/mprvar.h4
-rw-r--r--sys/dev/mps/mps.c11
-rw-r--r--sys/dev/mps/mps_sas.c21
-rw-r--r--sys/dev/mps/mpsvar.h4
-rw-r--r--sys/dev/pci/pci.c16
-rw-r--r--sys/dev/pci/pcivar.h1
-rw-r--r--sys/dev/vmware/vmxnet3/if_vmx.c31
-rw-r--r--sys/geom/mirror/g_mirror.c17
-rw-r--r--sys/geom/uzip/g_uzip.c614
-rw-r--r--sys/geom/uzip/g_uzip.h37
-rw-r--r--sys/geom/uzip/g_uzip_cloop.h55
-rw-r--r--sys/geom/uzip/g_uzip_dapi.h42
-rw-r--r--sys/geom/uzip/g_uzip_lzma.c128
-rw-r--r--sys/geom/uzip/g_uzip_lzma.h32
-rw-r--r--sys/geom/uzip/g_uzip_softc.h56
-rw-r--r--sys/geom/uzip/g_uzip_wrkthr.c72
-rw-r--r--sys/geom/uzip/g_uzip_wrkthr.h30
-rw-r--r--sys/geom/uzip/g_uzip_zlib.c145
-rw-r--r--sys/geom/uzip/g_uzip_zlib.h33
-rw-r--r--sys/kern/kern_event.c7
-rw-r--r--sys/kern/kern_time.c17
-rw-r--r--sys/kern/sys_process.c2
-rw-r--r--sys/kern/vfs_subr.c8
-rw-r--r--sys/kern/vfs_syscalls.c2
-rw-r--r--sys/modules/geom/geom_uzip/Makefile17
-rw-r--r--sys/nlm/nlm_prot_impl.c6
-rw-r--r--sys/sys/ktrace.h2
-rw-r--r--sys/sys/rman.h1
-rw-r--r--sys/vm/vm_fault.c9
-rw-r--r--sys/vm/vm_object.c4
-rw-r--r--usr.bin/ar/ar.19
-rw-r--r--usr.bin/ar/ar.c3
-rw-r--r--usr.bin/bsdiff/bspatch/bspatch.c4
-rw-r--r--usr.bin/gcore/elfcore.c16
-rw-r--r--usr.bin/kdump/kdump.c25
-rw-r--r--usr.bin/mail/collect.c4
-rw-r--r--usr.bin/mail/quit.c3
-rw-r--r--usr.bin/mail/v7.local.c5
-rw-r--r--usr.bin/mkuzip/Makefile7
-rw-r--r--usr.bin/mkuzip/mkuz_blk.c45
-rw-r--r--usr.bin/mkuzip/mkuz_blk.h48
-rw-r--r--usr.bin/mkuzip/mkuz_blk_chain.h35
-rw-r--r--usr.bin/mkuzip/mkuz_blockcache.c148
-rw-r--r--usr.bin/mkuzip/mkuz_blockcache.h31
-rw-r--r--usr.bin/mkuzip/mkuz_cfg.h40
-rw-r--r--usr.bin/mkuzip/mkuz_cloop.h50
-rw-r--r--usr.bin/mkuzip/mkuz_conveyor.c129
-rw-r--r--usr.bin/mkuzip/mkuz_conveyor.h52
-rw-r--r--usr.bin/mkuzip/mkuz_format.h37
-rw-r--r--usr.bin/mkuzip/mkuz_fqueue.c214
-rw-r--r--usr.bin/mkuzip/mkuz_fqueue.h51
-rw-r--r--usr.bin/mkuzip/mkuz_lzma.c121
-rw-r--r--usr.bin/mkuzip/mkuz_lzma.h42
-rw-r--r--usr.bin/mkuzip/mkuz_time.c45
-rw-r--r--usr.bin/mkuzip/mkuz_time.h41
-rw-r--r--usr.bin/mkuzip/mkuz_zlib.c87
-rw-r--r--usr.bin/mkuzip/mkuz_zlib.h36
-rw-r--r--usr.bin/mkuzip/mkuzip.895
-rw-r--r--usr.bin/mkuzip/mkuzip.c384
-rw-r--r--usr.bin/mkuzip/mkuzip.h33
-rw-r--r--usr.bin/sed/process.c2
-rw-r--r--usr.bin/tr/tr.14
-rw-r--r--usr.bin/tr/tr.c7
-rw-r--r--usr.bin/ul/ul.c241
-rw-r--r--usr.sbin/bhyve/pci_ahci.c12
-rw-r--r--usr.sbin/pw/rm_r.c3
-rwxr-xr-xusr.sbin/pw/tests/pw_userdel.sh9
119 files changed, 3956 insertions, 635 deletions
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index 85a3815..da7a43c 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -38,6 +38,8 @@
# xargs -n1 | sort | uniq -d;
# done
+# 20160723: stale MLINK removed
+OLD_FILES+=usr/share/man/man9/rman_await_resource.9.gz
# 20160216: Remove obsolete unbound-control-setup
OLD_FILES+=usr/sbin/unbound-control-setup
# 20151222: liblzma header
diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp
index 86d046b..d077654 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp
+++ b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp
@@ -5848,12 +5848,12 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_pie))
CmdArgs.push_back("-pie");
+ CmdArgs.push_back("--eh-frame-hdr");
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-Bstatic");
} else {
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
- CmdArgs.push_back("--eh-frame-hdr");
if (Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back("-Bshareable");
} else {
diff --git a/lib/libc/gen/fnmatch.c b/lib/libc/gen/fnmatch.c
index db0bf89..db15494 100644
--- a/lib/libc/gen/fnmatch.c
+++ b/lib/libc/gen/fnmatch.c
@@ -304,8 +304,8 @@ rangematch(pattern, test, flags, newp, patmbs)
if (table->__collate_load_error ?
c <= test && test <= c2 :
- __collate_range_cmp(table, c, test) <= 0
- && __collate_range_cmp(table, test, c2) <= 0
+ __wcollate_range_cmp(c, test) <= 0
+ && __wcollate_range_cmp(test, c2) <= 0
)
ok = 1;
} else if (c == test)
diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c
index 95a3a06..6c86297 100644
--- a/lib/libc/gen/glob.c
+++ b/lib/libc/gen/glob.c
@@ -836,8 +836,8 @@ match(Char *name, Char *pat, Char *patend)
if ((*pat & M_MASK) == M_RNG) {
if (table->__collate_load_error ?
CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
- __collate_range_cmp(table, CHAR(c), CHAR(k)) <= 0
- && __collate_range_cmp(table, CHAR(k), CHAR(pat[1])) <= 0
+ __wcollate_range_cmp(CHAR(c), CHAR(k)) <= 0
+ && __wcollate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0
)
ok = 1;
pat += 2;
diff --git a/lib/libc/locale/collate.h b/lib/libc/locale/collate.h
index ad034d4..496e0ac 100644
--- a/lib/libc/locale/collate.h
+++ b/lib/libc/locale/collate.h
@@ -72,7 +72,8 @@ u_char *__collate_strdup(u_char *);
u_char *__collate_substitute(struct xlocale_collate *, const u_char *);
int __collate_load_tables(const char *);
void __collate_lookup(struct xlocale_collate *, const u_char *, int *, int *, int *);
-int __collate_range_cmp(struct xlocale_collate *, int, int);
+int __collate_range_cmp(char, char);
+int __wcollate_range_cmp(wchar_t, wchar_t);
#ifdef COLLATE_DEBUG
void __collate_print_tables(void);
#endif
diff --git a/lib/libc/locale/collcmp.c b/lib/libc/locale/collcmp.c
index aa17afd..ce71a71 100644
--- a/lib/libc/locale/collcmp.c
+++ b/lib/libc/locale/collcmp.c
@@ -33,20 +33,31 @@
__FBSDID("$FreeBSD$");
#include <string.h>
-#include <xlocale.h>
+#include <wchar.h>
#include "collate.h"
/*
* Compare two characters using collate
*/
-int __collate_range_cmp(struct xlocale_collate *table, int c1, int c2)
+int __collate_range_cmp(char c1, char c2)
{
- static char s1[2], s2[2];
+ char s1[2], s2[2];
s1[0] = c1;
+ s1[1] = '\0';
s2[0] = c2;
- struct _xlocale l = {{0}};
- l.components[XLC_COLLATE] = (struct xlocale_component *)table;
- return (strcoll_l(s1, s2, &l));
+ s2[1] = '\0';
+ return (strcoll(s1, s2));
+}
+
+int __wcollate_range_cmp(wchar_t c1, wchar_t c2)
+{
+ wchar_t s1[2], s2[2];
+
+ s1[0] = c1;
+ s1[1] = L'\0';
+ s2[0] = c2;
+ s2[1] = L'\0';
+ return (wcscoll(s1, s2));
}
diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c
index ae92f6a..9211f65 100644
--- a/lib/libc/regex/regcomp.c
+++ b/lib/libc/regex/regcomp.c
@@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$");
#include <limits.h>
#include <stdlib.h>
#include <regex.h>
-#include <runetype.h>
#include <wchar.h>
#include <wctype.h>
@@ -817,14 +816,14 @@ p_b_term(struct parse *p, cset *cs)
if (start == finish)
CHadd(p, cs, start);
else {
- if (table->__collate_load_error) {
- (void)REQUIRE((uch)start <= (uch)finish, REG_ERANGE);
+ if (table->__collate_load_error || MB_CUR_MAX > 1) {
+ (void)REQUIRE(start <= finish, REG_ERANGE);
CHaddrange(p, cs, start, finish);
} else {
- (void)REQUIRE(__collate_range_cmp(table, start, finish) <= 0, REG_ERANGE);
+ (void)REQUIRE(__wcollate_range_cmp(start, finish) <= 0, REG_ERANGE);
for (i = 0; i <= UCHAR_MAX; i++) {
- if ( __collate_range_cmp(table, start, i) <= 0
- && __collate_range_cmp(table, i, finish) <= 0
+ if ( __wcollate_range_cmp(start, i) <= 0
+ && __wcollate_range_cmp(i, finish) <= 0
)
CHadd(p, cs, i);
}
diff --git a/lib/libc/stdio/vfscanf.c b/lib/libc/stdio/vfscanf.c
index b537263..66dca1a 100644
--- a/lib/libc/stdio/vfscanf.c
+++ b/lib/libc/stdio/vfscanf.c
@@ -873,7 +873,7 @@ doswitch:
n = *fmt;
if (n == ']'
|| (table->__collate_load_error ? n < c :
- __collate_range_cmp (table, n, c) < 0
+ __collate_range_cmp(n, c) < 0
)
) {
c = '-';
@@ -887,8 +887,8 @@ doswitch:
} while (c < n);
} else {
for (i = 0; i < 256; i ++)
- if ( __collate_range_cmp (table, c, i) < 0
- && __collate_range_cmp (table, i, n) <= 0
+ if (__collate_range_cmp(c, i) <= 0 &&
+ __collate_range_cmp(i, n) <= 0
)
tab[i] = v;
}
diff --git a/lib/libc/sys/aio_fsync.2 b/lib/libc/sys/aio_fsync.2
index e05bff4..7eb1a3b 100644
--- a/lib/libc/sys/aio_fsync.2
+++ b/lib/libc/sys/aio_fsync.2
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 27, 2013
+.Dd July 15, 2016
.Dt AIO_FSYNC 2
.Os
.Sh NAME
@@ -71,6 +71,29 @@ while it is in progress.
.Pp
If the request could not be enqueued (generally due to invalid arguments),
the call returns without having enqueued the request.
+.Pp
+The
+.Fa iocb->aio_sigevent
+structure can be used to request notification of the request's
+completion as described in
+.Xr aio 4 .
+.Sh RESTRICTIONS
+The asynchronous I/O Control Block structure pointed to by
+.Fa iocb
+must remain valid until the
+operation has completed.
+For this reason, use of auto (stack) variables
+for these objects is discouraged.
+.Pp
+The asynchronous I/O control buffer
+.Fa iocb
+should be zeroed before the
+.Fn aio_fsync
+call to avoid passing bogus context information to the kernel.
+.Pp
+Modifications of the Asynchronous I/O Control Block structure or the
+buffer contents after the request has been enqueued, but before the
+request has completed, are not allowed.
.Sh RETURN VALUES
.Rv -std aio_fsync
.Sh ERRORS
@@ -80,6 +103,10 @@ system call will fail if:
.Bl -tag -width Er
.It Bq Er EAGAIN
The request was not queued because of system resource limitations.
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa iocb->aio_sigevent.sigev_notify
+is invalid or not supported.
.It Bq Er ENOSYS
The
.Fn aio_fsync
@@ -138,6 +165,7 @@ system calls.
.Xr aio_waitcomplete 2 ,
.Xr aio_write 2 ,
.Xr fsync 2 ,
+.Xr sigevent 3 ,
.Xr siginfo 3 ,
.Xr aio 4
.Sh STANDARDS
diff --git a/lib/libc/sys/aio_mlock.2 b/lib/libc/sys/aio_mlock.2
index 386393f..03e2df7 100644
--- a/lib/libc/sys/aio_mlock.2
+++ b/lib/libc/sys/aio_mlock.2
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 3, 2013
+.Dd July 15, 2016
.Dt AIO_MLOCK 2
.Os
.Sh NAME
@@ -64,6 +64,12 @@ If the request could not be enqueued (generally due to
.Xr aio 4
limits),
then the call returns without having enqueued the request.
+.Pp
+The
+.Fa iocb->aio_sigevent
+structure can be used to request notification of the request's
+completion as described in
+.Xr aio 4 .
.Sh RESTRICTIONS
The Asynchronous I/O Control Block structure pointed to by
.Fa iocb
@@ -92,6 +98,10 @@ system call will fail if:
.Bl -tag -width Er
.It Bq Er EAGAIN
The request was not queued because of system resource limitations.
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa iocb->aio_sigevent.sigev_notify
+is invalid or not supported.
.It Bq Er ENOSYS
The
.Fn aio_mlock
@@ -116,6 +126,7 @@ if the request was explicitly cancelled via a call to
.Xr aio_error 2 ,
.Xr aio_return 2 ,
.Xr mlock 2 ,
+.Xr sigevent 3 ,
.Xr aio 4
.Sh PORTABILITY
The
diff --git a/lib/libc/sys/aio_read.2 b/lib/libc/sys/aio_read.2
index ddf4f76..69960d5 100644
--- a/lib/libc/sys/aio_read.2
+++ b/lib/libc/sys/aio_read.2
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 17, 1998
+.Dd July 15, 2016
.Dt AIO_READ 2
.Os
.Sh NAME
@@ -79,6 +79,12 @@ If the request is successfully enqueued, the value of
.Fa iocb->aio_offset
can be modified during the request as context, so this value must
not be referenced after the request is enqueued.
+.Pp
+The
+.Fa iocb->aio_sigevent
+structure can be used to request notification of the request's
+completion as described in
+.Xr aio 4 .
.Sh RESTRICTIONS
The Asynchronous I/O Control Block structure pointed to by
.Fa iocb
@@ -115,6 +121,10 @@ system call will fail if:
.Bl -tag -width Er
.It Bq Er EAGAIN
The request was not queued because of system resource limitations.
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa iocb->aio_sigevent.sigev_notify
+is invalid or not supported.
.It Bq Er ENOSYS
The
.Fn aio_read
@@ -191,6 +201,7 @@ would be invalid.
.Xr aio_suspend 2 ,
.Xr aio_waitcomplete 2 ,
.Xr aio_write 2 ,
+.Xr sigevent 3 ,
.Xr siginfo 3 ,
.Xr aio 4
.Sh STANDARDS
diff --git a/lib/libc/sys/aio_write.2 b/lib/libc/sys/aio_write.2
index 291fd71..076ce50 100644
--- a/lib/libc/sys/aio_write.2
+++ b/lib/libc/sys/aio_write.2
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 2, 1999
+.Dd July 15, 2016
.Dt AIO_WRITE 2
.Os
.Sh NAME
@@ -85,6 +85,12 @@ If the request is successfully enqueued, the value of
.Fa iocb->aio_offset
can be modified during the request as context, so this value must not
be referenced after the request is enqueued.
+.Pp
+The
+.Fa iocb->aio_sigevent
+structure can be used to request notification of the request's
+completion as described in
+.Xr aio 4 .
.Sh RESTRICTIONS
The Asynchronous I/O Control Block structure pointed to by
.Fa iocb
@@ -119,6 +125,10 @@ system call will fail if:
.Bl -tag -width Er
.It Bq Er EAGAIN
The request was not queued because of system resource limitations.
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa iocb->aio_sigevent.sigev_notify
+is invalid or not supported.
.It Bq Er ENOSYS
The
.Fn aio_write
@@ -186,6 +196,7 @@ would be invalid.
.Xr aio_return 2 ,
.Xr aio_suspend 2 ,
.Xr aio_waitcomplete 2 ,
+.Xr sigevent 3 ,
.Xr siginfo 3 ,
.Xr aio 4
.Sh STANDARDS
diff --git a/lib/libc/sys/lio_listio.2 b/lib/libc/sys/lio_listio.2
index 0ffbcdd..ae228f7 100644
--- a/lib/libc/sys/lio_listio.2
+++ b/lib/libc/sys/lio_listio.2
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 12, 2003
+.Dd July 15, 2016
.Dt LIO_LISTIO 2
.Os
.Sh NAME
@@ -83,14 +83,52 @@ If
.Fa mode
is
.Dv LIO_NOWAIT ,
-the requests are processed asynchronously, and the signal specified by
.Fa sig
-is sent when all operations have completed.
+can be used to request asynchronous notification when all operations have
+completed.
If
.Fa sig
is
.Dv NULL ,
-the calling process is not notified of I/O completion.
+no notification is sent.
+.Pp
+For
+.Dv SIGEV_KEVENT
+notifications,
+the posted kevent will contain:
+.Bl -column ".Va filter"
+.It Sy Member Ta Sy Value
+.It Va ident Ta Fa list
+.It Va filter Ta Dv EVFILT_LIO
+.It Va udata Ta
+value stored in
+.Fa sig->sigev_value
+.El
+.Pp
+For
+.Dv SIGEV_SIGNO
+and
+.Dv SIGEV_THREAD_ID
+notifications,
+the information for the queued signal will include
+.Dv SI_ASYNCIO
+in the
+.Va si_code
+field and the value stored in
+.Fa sig->sigev_value
+in the
+.Va si_value
+field.
+.Pp
+For
+.Dv SIGEV_THREAD
+notifications,
+the value stored in
+.Fa sig->sigev_value
+is passed to the
+.Fa sig->sigev_notify_function
+as described in
+.Xr sigevent 3 .
.Pp
The order in which the requests are carried out is not specified;
in particular, there is no guarantee that they will be executed in
@@ -136,6 +174,10 @@ or
.Fa nent
is greater than
.Dv AIO_LISTIO_MAX .
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa sig->sigev_notify
+is invalid or not supported.
.It Bq Er EINTR
A signal interrupted the system call before it could be completed.
.It Bq Er EIO
@@ -166,6 +208,7 @@ structure individually by calling
.Xr aio_write 2 ,
.Xr read 2 ,
.Xr write 2 ,
+.Xr sigevent 3 ,
.Xr siginfo 3 ,
.Xr aio 4
.Sh STANDARDS
diff --git a/lib/libc/sys/mq_notify.2 b/lib/libc/sys/mq_notify.2
index 1e3a5ad..4418c60 100644
--- a/lib/libc/sys/mq_notify.2
+++ b/lib/libc/sys/mq_notify.2
@@ -37,7 +37,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 29, 2005
+.Dd July 15, 2016
.Dt MQ_NOTIFY 2
.Os
.Sh NAME
@@ -77,18 +77,27 @@ is
.Dv SIGEV_NONE ,
then no signal will be posted, but the error status and the return status
for the operation will be set appropriately.
-If
-.Fa notification->sigev_notify
-is
-.Dv SIGEV_SIGNAL ,
-then the signal specified in
+For
+.Dv SIGEV_SIGNO
+and
+.Dv SIGEV_THREAD_ID
+notifications,
+the signal specified in
.Fa notification->sigev_signo
-will be sent to the process.
-The signal will be queued to the process and the value specified in
+will be sent to the calling process
+.Pq Dv SIGEV_SIGNO
+or to the thread whose LWP ID is
+.Fa notification->sigev_notify_thread_id
+.Pq Dv SIGEV_THREAD_ID .
+The information for the queued signal will include:
+.Bl -column ".Va si_value"
+.It Sy Member Ta Sy Value
+.It Va si_code Ta Dv SI_MESGQ
+.It Va si_value Ta
+the value stored in
.Fa notification->sigev_value
-will be the
-.Va si_value
-component of the generated signal.
+.It Va si_mqd Ta Fa mqdes
+.El
.Pp
If
.Fa notification
@@ -123,11 +132,16 @@ The
argument is not a valid message queue descriptor.
.It Bq Er EBUSY
Process is already registered for notification by the message queue.
+.It Bq Er EINVAL
+The asynchronous notification method in
+.Fa notification->sigev_notify
+is invalid or not supported.
.El
.Sh SEE ALSO
.Xr mq_open 2 ,
.Xr mq_send 2 ,
.Xr mq_timedsend 2 ,
+.Xr sigevent 3 ,
.Xr siginfo 3
.Sh STANDARDS
The
diff --git a/lib/libc/sys/timer_create.2 b/lib/libc/sys/timer_create.2
index 3355159..1dd0cd5 100644
--- a/lib/libc/sys/timer_create.2
+++ b/lib/libc/sys/timer_create.2
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 12, 2009
+.Dd July 15, 2016
.Dt TIMER_CREATE 2
.Os
.Sh NAME
@@ -74,6 +74,36 @@ structure.
This structure,
allocated by the application, defines the asynchronous notification to occur
when the timer expires.
+.Pp
+If
+.Fa evp->sigev_notify
+is
+.Dv SIGEV_SIGNO
+or
+.Dv SIGEV_THREAD_ID ,
+the signal specified in
+.Fa evp->sigev_signo
+will be sent to the calling process
+.Pq Dv SIGEV_SIGNO
+or to the thread whose LWP ID is
+.Fa evp->sigev_notify_thread_id
+.Pq Dv SIGEV_THREAD_ID .
+The information for the queued signal will include:
+.Bl -column ".Va si_value"
+.It Sy Member Ta Sy Value
+.It Va si_code Ta Dv SI_TIMER
+.It Va si_value Ta
+the value stored in
+.Fa evp->sigev_value
+.It Va si_timerid Ta timer ID
+.It Va si_overrun Ta timer overrun count
+.It Va si_errno Ta
+If timer overrun is
+.Brq Dv DELAYTIMER_MAX ,
+an error code defined in
+.In errno.h
+.El
+.Pp
If the
.Fa evp
argument is
@@ -88,12 +118,14 @@ member having the value
.Dv SIGEV_SIGNAL ,
the
.Va sigev_signo
-having a default signal number, and the
+having a default signal number
+.Pq Dv SIGALRM ,
+and the
.Va sigev_value
member having
the value of the timer ID.
.Pp
-The implementations supports a
+This implementation supports a
.Fa clock_id
of
.Dv CLOCK_REALTIME
@@ -144,6 +176,8 @@ The calling process has already created all of the timers it is allowed by
this implementation.
.It Bq Er EINVAL
The specified clock ID is not supported.
+.It Bq Er EINVAL
+The specified asynchronous notification method is not supported.
.It Bq Er EFAULT
Any arguments point outside the allocated address space or there is a
memory protection fault.
@@ -152,6 +186,7 @@ memory protection fault.
.Xr clock_getres 2 ,
.Xr timer_delete 2 ,
.Xr timer_getoverrun 2 ,
+.Xr sigevent 3 ,
.Xr siginfo 3
.Sh STANDARDS
The
diff --git a/lib/libcxxrt/Version.map b/lib/libcxxrt/Version.map
index 9767542..bb62ed1 100644
--- a/lib/libcxxrt/Version.map
+++ b/lib/libcxxrt/Version.map
@@ -209,19 +209,19 @@ CXXABI_1.3 {
"typeinfo name for void*";
"typeinfo name for unsigned int*";
"typeinfo name for float*";
- # C++11 typeinfo not understood by our linker
+ # C++11 typeinfo name not understood by our linker
# std::nullptr_t
- _ZTSDn;_ZTIPDn;_ZTIPKDn;
+ _ZTSDn;_ZTSPDn;_ZTSPKDn;
# char16_t
- _ZTSDi;_ZTIPDi;_ZTIPKDi;
+ _ZTSDi;_ZTSPDi;_ZTSPKDi;
# char32_t
- _ZTSDs;_ZTIPDs;_ZTIPKDs;
+ _ZTSDs;_ZTSPDs;_ZTSPKDs;
# IEEE 754r decimal floating point
- _ZTSDd;_ZTIPDd;_ZTIPKDd;
- _ZTSDe;_ZTIPDe;_ZTIPKDe;
- _ZTSDf;_ZTIPDf;_ZTIPKDf;
+ _ZTSDd;_ZTSPDd;_ZTSPKDd;
+ _ZTSDe;_ZTSPDe;_ZTSPKDe;
+ _ZTSDf;_ZTSPDf;_ZTSPKDf;
# IEEE 754r half-precision floating point
- _ZTSDh;_ZTIPDh;_ZTIPKDh;
+ _ZTSDh;_ZTSPDh;_ZTSPKDh;
"typeinfo name for __cxxabiv1::__array_type_info";
"typeinfo name for __cxxabiv1::__class_type_info";
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index b97a4e6..8d0938b 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -3181,7 +3181,7 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve,
handle == RTLD_SELF) { /* ... caller included */
if (handle == RTLD_NEXT)
obj = globallist_next(obj);
- TAILQ_FOREACH_FROM(obj, &obj_list, next) {
+ for (; obj != NULL; obj = TAILQ_NEXT(obj, next)) {
if (obj->marker)
continue;
res = symlook_obj(&req, obj);
diff --git a/release/Makefile b/release/Makefile
index d37f2a5..11e10b5 100644
--- a/release/Makefile
+++ b/release/Makefile
@@ -137,6 +137,9 @@ CLEANFILES+= ${I}.xz
CLEANFILES+= pkg-stage
.endif
CLEANDIRS= dist ftp disc1 bootonly dvd
+.if !defined(NODOC)
+CLEANDIRS+= reldoc rdoc
+.endif
beforeclean:
chflags -R noschg .
.include <bsd.obj.mk>
diff --git a/share/man/man3/Makefile b/share/man/man3/Makefile
index 6e4d790..eba80b6 100644
--- a/share/man/man3/Makefile
+++ b/share/man/man3/Makefile
@@ -13,6 +13,7 @@ MAN= assert.3 \
offsetof.3 \
${PTHREAD_MAN} \
queue.3 \
+ sigevent.3 \
siginfo.3 \
stdarg.3 \
sysexits.3 \
diff --git a/share/man/man3/sigevent.3 b/share/man/man3/sigevent.3
new file mode 100644
index 0000000..493691e
--- /dev/null
+++ b/share/man/man3/sigevent.3
@@ -0,0 +1,127 @@
+.\" -*- nroff -*-
+.\"
+.\" Copyright (c) 2016 John H. Baldwin <jhb@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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 15, 2016
+.Dt SIGEVENT 3
+.Os
+.Sh NAME
+.Nm sigevent
+.Nd "asynchronous event notification"
+.Sh SYNOPSIS
+.In signal.h
+.Sh DESCRIPTION
+Some operations permit threads to request asychronous notification of events
+via a
+.Vt struct sigevent
+structure.
+This structure contains several fields that describe the requested notification:
+.Bl -column ".Vt void (*)(union sigval)" ".Va sigev_notify_kevent_flags"
+.It Sy Type Ta Sy Member Ta Sy Description
+.It Vt int Ta sigev_notify Ta notification method
+.It Vt int Ta sigev_signo Ta signal number
+.It Vt union sigval Ta sigev_value Ta signal value
+.It Vt int Ta sigev_notify_kqueue Ta
+.Xr kqueue 2
+file descriptor
+.It Vt unsigned short Ta sigev_notify_kevent_flags Ta kevent flags
+.It Vt lwpid_t Ta sigev_notify_thread_id Ta LWP ID
+.It Vt void (*)(union sigval) Ta sigev_notify_function Ta
+callback function pointer
+.It Vt pthread_attr_t * Ta sigev_notify_attributes Ta
+callback thread attributes
+.El
+.Pp
+The
+.Va sigev_notify
+field specifies the notification method used when the event triggers:
+.Bl -tag -width ".Dv SIGEV_THREAD_ID"
+.It Dv SIGEV_NONE
+No notification is sent.
+.It Dv SIGEV_SIGNAL
+The signal
+.Va sigev_signo
+is queued as a real-time signal to the calling process.
+The value stored in
+.Va sigev_value
+will be present in the
+.Va si_value
+of the
+.Vt siginfo_t
+structure of the queued signal.
+.It Dv SIGEV_THREAD
+The notification function in
+.Va sigev_notify_function
+is called in a separate thread context.
+The thread is created with the attributes specified in
+.Va *sigev_notify_attributes .
+The value stored in
+.Va sigev_value
+is passed as the sole argument to
+.Va sigev_notify_function .
+If
+.Va sigev_notify_attributes
+is
+.Dv NULL ,
+the thread is created with default attributes.
+.It Dv SIGEV_KEVENT
+A new kevent is posted to the kqueue
+.Va sigev_notify_kqueue .
+The
+.Va udata
+member of the kevent structure contains the value stored in
+.Va sigev_value .
+The meaning of other fields in the kevent are specific to the type of triggered
+event.
+.It Dv SIGEV_THREAD_ID
+The signal
+.Va sigev_signo
+is queued to the thread whose LWP ID is
+.Va sigev_notify_thread_id .
+The value stored in
+.Va sigev_value
+will be present in the
+.Va si_value
+of the
+.Vt siginfo_t
+structure of the queued signal.
+.El
+.Sh NOTES
+Note that programs wishing to use
+.Dv SIGEV_THREAD
+notifications must link against the
+.Lb librt .
+.Sh SEE ALSO
+.Xr aio_read 2 ,
+.Xr mq_notify 2 ,
+.Xr timer_create 2 ,
+.Xr siginfo 3
+.Sh STANDARDS
+The
+.Vt struct sigevent
+type conforms to
+.St -p1003.1-2004 .
diff --git a/share/man/man3/siginfo.3 b/share/man/man3/siginfo.3
index 2255766..d1f2b40 100644
--- a/share/man/man3/siginfo.3
+++ b/share/man/man3/siginfo.3
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 14, 2012
+.Dd July 14, 2016
.Dt SIGINFO 3
.Os
.Sh NAME
@@ -54,7 +54,7 @@ In either case, the system returns the information in a structure of type
.Vt siginfo_t ,
which includes the following information:
.Bl -column ".Vt union signal" ".Va si_overrun"
-.It Sy "Type Member Description"
+.It Sy Type Ta Sy Member Ta Sy Description
.It Vt int Ta Va si_signo Ta
signal number
.It Vt int Ta Va si_errno Ta
@@ -107,7 +107,7 @@ for use as values of
that are signal-specific or non-signal-specific reasons why the signal was
generated:
.Bl -column ".Dv SIGPOLL" ".Dv CLD_CONTINUED"
-.It Sy "Signal Code Reason"
+.It Sy Signal Ta Sy Code Ta Sy Reason
.It Dv SIGILL Ta Dv ILL_ILLOPC Ta
illegal opcode
.It Ta Dv ILL_ILLOPN Ta
@@ -206,7 +206,7 @@ signal sent by
.Pp
In addition, the following signal-specific information is available:
.Bl -column ".Dv SIGPOLL" ".Dv CLD_CONTINUED"
-.It Sy "Signal Member Value"
+.It Sy Signal Ta Sy Member Ta Sy Value
.It Dv SIGILL Ta Va si_addr Ta
address of faulting instruction
.It Ta Va si_trapno Ta
@@ -240,8 +240,8 @@ or
.El
.Pp
Finally, the following code-specific information is available:
-.Bl -column ".Dv SI_QUEUE" ".Va si_overrun"
-.It Sy "Code Member Value"
+.Bl -column ".Dv SI_ASYNCIO" ".Va si_overrun"
+.It Sy Code Ta Sy Member Ta Sy Value
.It Dv SI_USER Ta Va si_pid Ta
the process ID that sent the signal
.It Ta Va si_uid Ta
diff --git a/share/man/man4/aio.4 b/share/man/man4/aio.4
index 8e773d9..eb9bfff 100644
--- a/share/man/man4/aio.4
+++ b/share/man/man4/aio.4
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 24, 2002
+.Dd July 15, 2016
.Dt AIO 4
.Os
.Sh NAME
@@ -45,6 +45,54 @@ The
facility provides system calls for asynchronous I/O.
It is available both as a kernel option for static inclusion and as a
dynamic kernel module.
+.Pp
+Asynchronous I/O control buffers should be zeroed before initializing
+individual fields.
+This ensures all fields are initialized.
+.Pp
+All asynchronous I/O control buffers contain a
+.Vt sigevent
+structure in the
+.Va aio_sigevent
+field which can be used to request notification when an operation completes.
+.Pp
+For
+.Dv SIGEV_KEVENT
+notifications,
+the posted kevent will contain:
+.Bl -column ".Va filter"
+.It Sy Member Ta Sy Value
+.It Va ident Ta asynchronous I/O control buffer pointer
+.It Va filter Ta Dv EVFILT_AIO
+.It Va udata Ta
+value stored in
+.Va aio_sigevent.sigev_value
+.El
+.Pp
+For
+.Dv SIGEV_SIGNO
+and
+.Dv SIGEV_THREAD_ID
+notifications,
+the information for the queued signal will include
+.Dv SI_ASYNCIO
+in the
+.Va si_code
+field and the value stored in
+.Va sigevent.sigev_value
+in the
+.Va si_value
+field.
+.Pp
+For
+.Dv SIGEV_THREAD
+notifications,
+the value stored in
+.Va aio_sigevent.sigev_value
+is passed to the
+.Va aio_sigevent.sigev_notify_function
+as described in
+.Xr sigevent 3 .
.Sh SEE ALSO
.Xr aio_cancel 2 ,
.Xr aio_error 2 ,
@@ -54,6 +102,7 @@ dynamic kernel module.
.Xr aio_waitcomplete 2 ,
.Xr aio_write 2 ,
.Xr lio_listio 2 ,
+.Xr sigevent 3 ,
.Xr config 8 ,
.Xr kldload 8 ,
.Xr kldunload 8
diff --git a/share/man/man4/ddb.4 b/share/man/man4/ddb.4
index 8bcbaea..7a7759c 100644
--- a/share/man/man4/ddb.4
+++ b/share/man/man4/ddb.4
@@ -60,7 +60,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 5, 2015
+.Dd July 13, 2016
.Dt DDB 4
.Os
.Sh NAME
@@ -547,6 +547,11 @@ modifier will alter the display to show VM map
addresses for the process and not show other information.
.\"
.Pp
+.It Ic show Cm all trace
+.It Ic alltrace
+.Xc
+Show a stack trace for every thread in the system.
+.Pp
.It Ic show Cm all ttys
Show all TTY's within the system.
Output is similar to
diff --git a/share/man/man4/mpr.4 b/share/man/man4/mpr.4
index ff500c2..370d659 100644
--- a/share/man/man4/mpr.4
+++ b/share/man/man4/mpr.4
@@ -29,7 +29,7 @@
.\" 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 DAMAGES.
-.\"
+.\"
.\" mpr driver man page.
.\"
.\" Author: Ken Merry <ken@FreeBSD.org>
@@ -38,7 +38,7 @@
.\" $Id$
.\" $FreeBSD$
.\"
-.Dd April 29, 2016
+.Dd July 6, 2016
.Dt MPR 4
.Os
.Sh NAME
@@ -156,6 +156,29 @@ The current number of active I/O commands is shown in the
dev.mpr.X.io_cmds_active
.Xr sysctl 8
variable.
+.Ed
+.Pp
+To set the maximum number of pages that will be used per I/O for all adapters,
+set this tunable in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+hw.mpr.max_io_pages=NNNN
+.Ed
+.Pp
+To set the maximum number of pages that will be used per I/O for a specific
+adapter, set this tunable in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+dev.mpr.X.max_io_pages=NNNN
+.Ed
+.Pp
+The default max_io_pages value is -1, meaning that the maximum I/O size that
+will be used per I/O will be calculated using the IOCFacts values stored in
+the controller.
+The lowest value that the driver will use for max_io_pages is 1, otherwise
+IOCFacts will be used to calculate the maximum I/O size.
+The smaller I/O size calculated from either max_io_pages or IOCFacts will be the
+maximum I/O size used by the driver.
.Pp
The highest number of active I/O commands seen since boot is stored in the
dev.mpr.X.io_cmds_highwater
@@ -220,7 +243,7 @@ SATA disks that take several seconds to spin up and fail the SATA Identify
command might not be discovered by the driver.
This problem can sometimes be overcome by increasing the value of the spinup
wait time in
-.Xr loader.conf 5 :
+.Xr loader.conf 5
with the
.Bd -literal -offset indent
hw.mpr.spinup_wait_time=NNNN
@@ -250,7 +273,7 @@ hw.mpr.X.debug_level
.Pp
tunable, either in
.Xr loader.conf 5
-or by using
+or by using
.Xr sysctl 8 .
These bits have the described effects:
.Bd -literal -offset indent
diff --git a/share/man/man4/mps.4 b/share/man/man4/mps.4
index 7e910b1..99af107 100644
--- a/share/man/man4/mps.4
+++ b/share/man/man4/mps.4
@@ -1,5 +1,8 @@
.\"
.\" Copyright (c) 2010 Spectra Logic Corporation
+.\" Copyright (c) 2014 LSI Corp
+.\" Copyright (c) 2016 Avago Technologies
+.\" Copyright (c) 2016 Broadcom Ltd.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -30,25 +33,27 @@
.\" mps driver man page.
.\"
.\" Author: Ken Merry <ken@FreeBSD.org>
+.\" Author: Stephen McConnell <slm@FreeBSD.org>
.\"
.\" $Id: //depot/SpectraBSD/head/share/man/man4/mps.4#6 $
.\" $FreeBSD$
.\"
-.Dd December 9, 2015
+.Dd July 5, 2016
.Dt MPS 4
.Os
.Sh NAME
.Nm mps
-.Nd LSI Fusion-MPT 2 Serial Attached SCSI driver
+.Nd "LSI Fusion-MPT 2 IT/IR 6Gb/s Serial Attached SCSI/SATA driver"
.Sh SYNOPSIS
-To compile this driver into your kernel,
-place the following lines in your kernel configuration file:
+To compile this driver into the kernel, place these lines in the kernel
+configuration file:
.Bd -ragged -offset indent
+.Cd "device pci"
.Cd "device scbus"
.Cd "device mps"
.Ed
.Pp
-Or, to load the driver as a module at boot, place the following line in
+The driver can be loaded as a module at boot time by placing this line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
mps_load="YES"
@@ -56,35 +61,30 @@ mps_load="YES"
.Sh DESCRIPTION
The
.Nm
-driver provides support for LSI Logic Fusion-MPT 2
+driver provides support for Broadcom Ltd./Avago Tech (LSI)
+Fusion-MPT 2 IT/IR
.Tn SAS
controllers and WarpDrive solid state storage cards.
.Sh HARDWARE
-The
+These controllers are supported by the
.Nm
-driver supports the following hardware:
+driver:
.Pp
.Bl -bullet -compact
.It
-LSI Logic SAS2004 (4 Port
-.Tn SAS )
+Broadcom Ltd./Avago Tech (LSI) SAS 2004 (4 Port SAS)
.It
-LSI Logic SAS2008 (8 Port
-.Tn SAS )
+Broadcom Ltd./Avago Tech (LSI) SAS 2008 (8 Port SAS)
.It
-LSI Logic SAS2108 (8 Port
-.Tn SAS )
+Broadcom Ltd./Avago Tech (LSI) SAS 2108 (8 Port SAS)
.It
-LSI Logic SAS2116 (16 Port
-.Tn SAS )
+Broadcom Ltd./Avago Tech (LSI) SAS 2116 (16 Port SAS)
.It
-LSI Logic SAS2208 (8 Port
-.Tn SAS )
+Broadcom Ltd./Avago Tech (LSI) SAS 2208 (8 Port SAS)
.It
-LSI Logic SAS2308 (8 Port
-.Tn SAS )
+Broadcom Ltd./Avago Tech (LSI) SAS 2308 (8 Port SAS)
.It
-LSI Logic SSS6200 Solid State Storage
+Broadcom Ltd./Avago Tech (LSI) SSS6200 Solid State Storage
.It
Intel Integrated RAID Module RMS25JB040
.It
@@ -95,9 +95,12 @@ Intel Integrated RAID Module RMS25KB040
Intel Integrated RAID Module RMS25KB080
.El
.Sh CONFIGURATION
+.Pp
+In all tunable descriptions below, X represents the adapter number.
+.Pp
To disable MSI interrupts for all
.Nm
-driver instances, set the following tunable value in
+driver instances, set this tunable value in
.Xr loader.conf 5 :
.Bd -literal -offset indent
hw.mps.disable_msi=1
@@ -105,17 +108,15 @@ hw.mps.disable_msi=1
.Pp
To disable MSI interrupts for a specific
.Nm
-driver instance, set the following tunable value in
+driver instance, set this tunable value in
.Xr loader.conf 5 :
.Bd -literal -offset indent
dev.mps.X.disable_msi=1
.Ed
.Pp
-where X is the adapter number.
-.Pp
To disable MSI-X interrupts for all
.Nm
-driver instances, set the following tunable value in
+driver instances, set this tunable value in
.Xr loader.conf 5 :
.Bd -literal -offset indent
hw.mps.disable_msix=1
@@ -123,84 +124,157 @@ hw.mps.disable_msix=1
.Pp
To disable MSI-X interrupts for a specific
.Nm
-driver instance, set the following tunable value in
+driver instance, set this tunable value in
.Xr loader.conf 5 :
.Bd -literal -offset indent
dev.mps.X.disable_msix=1
.Ed
.Pp
-where X is the adapter number.
-.Pp
-To set the maximum number of DMA chains allocated for all adapters,
-set the following variable in
+To set the maximum number of DMA chains allocated for all adapters, set this
+tunable in
.Xr loader.conf 5 :
.Bd -literal -offset indent
hw.mps.max_chains=NNNN
.Ed
.Pp
To set the maximum number of DMA chains allocated for a specific adapter,
-set the following variable in
+set this tunable in
.Xr loader.conf 5 :
.Bd -literal -offset indent
dev.mps.X.max_chains=NNNN
.Ed
.Pp
-This variable may also be viewed via
-.Xr sysctl 8
-to see the maximum set for a given adapter.
+The default max_chains value is 2048.
.Pp
-The current number of free chain frames may be seen via the
+The current number of free chain frames is stored in the
dev.mps.X.chain_free
.Xr sysctl 8
variable.
.Pp
-The lowest number of free chain frames may be seen via the
+The lowest number of free chain frames seen since boot is stored in the
dev.mps.X.chain_free_lowwater
.Xr sysctl 8
variable.
.Pp
+The number of times that chain frame allocations have failed since boot is
+stored in the
+dev.mps.X.chain_alloc_fail
+.Xr sysctl 8
+variable.
+This can be used to determine whether the max_chains tunable should be
+increased to help performance.
+.Pp
The current number of active I/O commands is shown in the
dev.mps.X.io_cmds_active
.Xr sysctl 8
variable.
+.Ed
+.Pp
+To set the maximum number of pages that will be used per I/O for all adapters,
+set this tunable in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+hw.mps.max_io_pages=NNNN
+.Ed
.Pp
-The maximum number of active I/O command seen since boot is shown in the
+To set the maximum number of pages that will be used per I/O for a specific
+adapter, set this tunable in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+dev.mps.X.max_io_pages=NNNN
+.Ed
+.Pp
+The default max_io_pages value is -1, meaning that the maximum I/O size that
+will be used per I/O will be calculated using the IOCFacts values stored in
+the controller.
+The lowest value that the driver will use for max_io_pages is 1, otherwise
+IOCFacts will be used to calculate the maximum I/O size.
+The smaller I/O size calculated from either max_io_pages or IOCFacts will be the
+maximum I/O size used by the driver.
+.Pp
+The highest number of active I/O commands seen since boot is stored in the
dev.mps.X.io_cmds_highwater
.Xr sysctl 8
variable.
.Pp
+Devices can be excluded from
+.Nm
+control for all adapters by setting this tunable in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+hw.mps.exclude_ids=Y
+.Ed
+.Pp
+Y represents the target ID of the device.
+If more than one device is to be excluded, target IDs are separated by commas.
+.Pp
+Devices can be excluded from
+.Nm
+control for a specific adapter by setting this tunable in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+dev.mps.X.exclude_ids=Y
+.Ed
+.Pp
+Y represents the target ID of the device.
+If more than one device is to be excluded, target IDs are separated by commas.
+.Pp
The adapter can issue the
.Sy StartStopUnit
-SCSI command to SATA direct-access devices during shutdown, to allow the
-device to quiesce before being powered down.
+SCSI command to SATA direct-access devices during shutdown.
+This allows the device to quiesce powering down.
To control this feature for all adapters, set the
.Bd -literal -offset indent
hw.mps.enable_ssu
.Ed
.Pp
-tunable value in
+tunable in
.Xr loader.conf 5
-to one of the following values:
+to one of these values:
.Bl -tag -width 6n -offset indent
.It 0
Do not send SSU to either HDDs or SSDs.
.It 1
-Send SSU to SSDs, but not to HDDs; this is the default value.
+Send SSU to SSDs, but not to HDDs.
+This is the default value.
.It 2
Send SSU to HDDs, but not to SSDs.
.It 3
Send SSU to both HDDs and SSDs.
.El
.Pp
-To control the feature for a specific adapter, set the following tunable
-value in
+To control the feature for a specific adapter, set this tunable value in
.Xr loader.conf 5 :
.Bd -literal -offset indent
dev.mps.X.enable_ssu
.Ed
.Pp
-where X is the adapter number.
-The same set of values are valid as for all adapters.
+The same set of values are valid when setting this tunable for all adapters.
+.Pp
+SATA disks that take several seconds to spin up and fail the SATA Identify
+command might not be discovered by the driver.
+This problem can sometimes be overcome by increasing the value of the spinup
+wait time in
+.Xr loader.conf 5
+with the
+.Bd -literal -offset indent
+hw.mps.spinup_wait_time=NNNN
+.Ed
+.Pp
+tunable.
+NNNN represents the number of seconds to wait for SATA devices to spin up when
+the device fails the initial SATA Identify command.
+.Pp
+Spinup wait times can be set for specific adapters in
+.Xr loader.conf 5 :
+with the
+.Bd -literal -offset indent
+dev.mps.X.spinup_wait_time=NNNN
+.Ed
+.Pp
+tunable.
+NNNN is the number of seconds to wait for SATA devices to spin up when they fail
+the initial SATA Identify command.
.Sh DEBUGGING
To enable debugging prints from the
.Nm
@@ -209,25 +283,30 @@ driver, set the
hw.mps.X.debug_level
.Ed
.Pp
-variable, where X is the adapter number, either in
+tunable, either in
.Xr loader.conf 5
-or via
+or by using
.Xr sysctl 8 .
-The following bits have the described effects:
-.Bl -tag -width 6n -offset indent
-.It 0x01
-Enable informational prints.
-.It 0x02
-Enable tracing prints.
-.It 0x04
-Enable prints for driver faults.
-.It 0x08
-Enable prints for controller events.
-.El
+These bits have the described effects:
+.Bd -literal -offset indent
+0x0001 Enable informational prints (set by default).
+0x0002 Enable prints for driver faults (set by default).
+0x0004 Enable prints for controller events.
+0x0008 Enable prints for controller logging.
+0x0010 Enable prints for tracing recovery operations.
+0x0020 Enable prints for parameter errors and programming bugs.
+0x0040 Enable prints for system initialization operations.
+0x0080 Enable prints for more detailed information.
+0x0100 Enable prints for user-generated commands (IOCTL).
+0x0200 Enable prints for device mapping.
+0x0400 Enable prints for tracing through driver functions.
+.Ed
.Sh SEE ALSO
+.Xr cam 4 ,
.Xr cd 4 ,
.Xr ch 4 ,
.Xr da 4 ,
+.Xr mpr 4 ,
.Xr mpt 4 ,
.Xr pci 4 ,
.Xr sa 4 ,
@@ -238,24 +317,17 @@ Enable prints for controller events.
.Sh HISTORY
The
.Nm
-driver first appeared in
-.Fx 9.0 .
+driver first appeared in FreeBSD 9.3.
.Sh AUTHORS
-.An -nosplit
The
.Nm
driver was originally written by
-.An Scott Long Aq scottl@FreeBSD.org .
-It has been improved and tested by LSI Logic Corporation.
+.An -nosplit
+.An Scott Long Aq Mt scottl@FreeBSD.org .
+It has been improved and tested by LSI Corporation,
+Avago Technologies (formally LSI), and Broadcom Ltd. (formally Avago).
+.Pp
This man page was written by
-.An Ken Merry Aq ken@FreeBSD.org .
-.Sh BUGS
-This driver has a couple of known shortcomings:
-.Bl -bullet -compact
-.It
-No userland utility available (e.g.,
-.Xr mptutil 8 ) .
-.It
-The driver probes devices sequentially.
-If your system has a large number of devices, the probe will take a while.
-.El
+.An Ken Merry Aq Mt ken@FreeBSD.org
+with additional input from
+.An Stephen McConnell Aq Mt slm@FreeBSD.org .
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index 322c022..44d6a83 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -1074,7 +1074,6 @@ MLINKS+=resource_int_value.9 resource_long_value.9 \
resource_int_value.9 resource_string_value.9
MLINKS+=rman.9 rman_activate_resource.9 \
rman.9 rman_adjust_resource.9 \
- rman.9 rman_await_resource.9 \
rman.9 rman_deactivate_resource.9 \
rman.9 rman_fini.9 \
rman.9 rman_first_free_region.9 \
diff --git a/share/man/man9/pci.9 b/share/man/man9/pci.9
index e3535cf..cddefb1 100644
--- a/share/man/man9/pci.9
+++ b/share/man/man9/pci.9
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 23, 2015
+.Dd June 24, 2016
.Dt PCI 9
.Os
.Sh NAME
@@ -43,6 +43,7 @@
.Nm pci_find_extcap ,
.Nm pci_find_htcap ,
.Nm pci_find_pcie_root_port ,
+.Nm pci_get_max_payload ,
.Nm pci_get_max_read_req ,
.Nm pci_get_powerstate ,
.Nm pci_get_vpd_ident ,
@@ -95,6 +96,8 @@
.Ft device_t
.Fn pci_find_pcie_root_port "device_t dev"
.Ft int
+.Fn pci_get_max_payload "device_t dev"
+.Ft int
.Fn pci_get_max_read_req "device_t dev"
.Ft int
.Fn pci_get_powerstate "device_t dev"
@@ -436,6 +439,16 @@ or
.Xr bus_activate_resource 9 .
.Pp
The
+.Fn pci_get_max_payload
+function returns the current maximum TLP payload size in bytes for a
+PCI-express device.
+If the
+.Fa dev
+device is not a PCI-express device,
+.Fn pci_get_max_payload
+returns zero.
+.Pp
+The
.Fn pci_get_max_read_req
function returns the current maximum read request size in bytes for a
PCI-express device.
diff --git a/share/man/man9/rman.9 b/share/man/man9/rman.9
index 4c8ef29..9a58d93 100644
--- a/share/man/man9/rman.9
+++ b/share/man/man9/rman.9
@@ -25,14 +25,13 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 15, 2014
+.Dd May 19, 2016
.Dt RMAN 9
.Os
.Sh NAME
.Nm rman ,
.Nm rman_activate_resource ,
.Nm rman_adjust_resource ,
-.Nm rman_await_resource ,
.Nm rman_deactivate_resource ,
.Nm rman_fini ,
.Nm rman_init ,
@@ -67,8 +66,6 @@
.Ft int
.Fn rman_adjust_resource "struct resource *r" "u_long start" "u_long end"
.Ft int
-.Fn rman_await_resource "struct resource *r" "int pri2" "int timo"
-.Ft int
.Fn rman_deactivate_resource "struct resource *r"
.Ft int
.Fn rman_fini "struct rman *rm"
@@ -387,23 +384,6 @@ flag.
If other consumers are waiting for this range, it will wakeup their threads.
.Pp
The
-.Fn rman_await_resource
-function performs an asynchronous wait for a resource
-.Fa r
-to become inactive, that is, for the
-.Dv RF_ACTIVE
-flag to be cleared.
-It is used to enable cooperative sharing of a resource
-which can only be safely used by one thread at a time.
-The arguments
-.Fa pri
-and
-.Fa timo
-are passed to the
-.Fn rman_await_resource
-function.
-.Pp
-The
.Fn rman_get_start ,
.Fn rman_get_end ,
.Fn rman_get_size ,
diff --git a/sys/boot/efi/boot1/boot1.c b/sys/boot/efi/boot1/boot1.c
index 1161b0a..90491fe 100644
--- a/sys/boot/efi/boot1/boot1.c
+++ b/sys/boot/efi/boot1/boot1.c
@@ -629,7 +629,7 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
case EFI_BUFFER_TOO_SMALL:
(void)bs->FreePool(handles);
if ((status = bs->AllocatePool(EfiLoaderData, hsize,
- (void **)&handles) != EFI_SUCCESS)) {
+ (void **)&handles)) != EFI_SUCCESS) {
panic("Failed to allocate %zu handles (%lu)", hsize /
sizeof(*handles), EFI_ERROR_CODE(status));
}
diff --git a/sys/boot/efi/boot1/generate-fat.sh b/sys/boot/efi/boot1/generate-fat.sh
index 2688da3..1392f81 100755
--- a/sys/boot/efi/boot1/generate-fat.sh
+++ b/sys/boot/efi/boot1/generate-fat.sh
@@ -41,6 +41,8 @@ mkdir -p stub/efi/boot
# Make a dummy file for boot1
echo 'Boot1 START' | dd of=stub/efi/boot/$FILENAME cbs=$BOOT1_SIZE count=1 conv=block
+# Provide a fallback startup.nsh
+echo $FILENAME > stub/efi/boot/startup.nsh
umount stub
mdconfig -d -u $DEVICE
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c
index 12be402..6c04fae 100644
--- a/sys/cam/scsi/scsi_all.c
+++ b/sys/cam/scsi/scsi_all.c
@@ -8539,6 +8539,7 @@ scsi_persistent_reserve_out(struct ccb_scsiio *csio, uint32_t retries,
scsi_cmd->opcode = PERSISTENT_RES_OUT;
scsi_cmd->action = service_action;
scsi_cmd->scope_type = scope | res_type;
+ scsi_ulto4b(dxfer_len, scsi_cmd->length);
cam_fill_csio(csio,
retries,
diff --git a/sys/conf/files b/sys/conf/files
index e8c8a3a..51d9fde 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2915,21 +2915,24 @@ geom/shsec/g_shsec.c optional geom_shsec
geom/stripe/g_stripe.c optional geom_stripe
geom/uncompress/g_uncompress.c optional geom_uncompress
contrib/xz-embedded/freebsd/xz_malloc.c \
- optional xz_embedded | geom_uncompress \
+ optional xz_embedded | geom_uncompress | geom_uzip \
compile-with "${NORMAL_C} -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/"
contrib/xz-embedded/linux/lib/xz/xz_crc32.c \
- optional xz_embedded | geom_uncompress \
+ optional xz_embedded | geom_uncompress | geom_uzip \
compile-with "${NORMAL_C} -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/"
contrib/xz-embedded/linux/lib/xz/xz_dec_bcj.c \
- optional xz_embedded | geom_uncompress \
+ optional xz_embedded | geom_uncompress | geom_uzip \
compile-with "${NORMAL_C} -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/"
contrib/xz-embedded/linux/lib/xz/xz_dec_lzma2.c \
- optional xz_embedded | geom_uncompress \
+ optional xz_embedded | geom_uncompress | geom_uzip \
compile-with "${NORMAL_C} -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/"
contrib/xz-embedded/linux/lib/xz/xz_dec_stream.c \
- optional xz_embedded | geom_uncompress \
+ optional xz_embedded | geom_uncompress | geom_uzip \
compile-with "${NORMAL_C} -I$S/contrib/xz-embedded/freebsd/ -I$S/contrib/xz-embedded/linux/lib/xz/ -I$S/contrib/xz-embedded/linux/include/linux/"
geom/uzip/g_uzip.c optional geom_uzip
+geom/uzip/g_uzip_lzma.c optional geom_uzip
+geom/uzip/g_uzip_wrkthr.c optional geom_uzip
+geom/uzip/g_uzip_zlib.c optional geom_uzip
geom/vinum/geom_vinum.c optional geom_vinum
geom/vinum/geom_vinum_create.c optional geom_vinum
geom/vinum/geom_vinum_drive.c optional geom_vinum
diff --git a/sys/dev/acpica/Osd/OsdSynch.c b/sys/dev/acpica/Osd/OsdSynch.c
index 99a69ec..db29239 100644
--- a/sys/dev/acpica/Osd/OsdSynch.c
+++ b/sys/dev/acpica/Osd/OsdSynch.c
@@ -188,6 +188,23 @@ AcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout)
}
break;
default:
+ if (cold) {
+ /*
+ * Just spin polling the semaphore once a
+ * millisecond.
+ */
+ while (!ACPISEM_AVAIL(as, Units)) {
+ if (Timeout == 0) {
+ status = AE_TIME;
+ break;
+ }
+ Timeout--;
+ mtx_unlock(&as->as_lock);
+ DELAY(1000);
+ mtx_lock(&as->as_lock);
+ }
+ break;
+ }
tmo = timeout2hz(Timeout);
while (!ACPISEM_AVAIL(as, Units)) {
prevtick = ticks;
@@ -381,6 +398,23 @@ AcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout)
}
break;
default:
+ if (cold) {
+ /*
+ * Just spin polling the mutex once a
+ * millisecond.
+ */
+ while (!ACPIMTX_AVAIL(am)) {
+ if (Timeout == 0) {
+ status = AE_TIME;
+ break;
+ }
+ Timeout--;
+ mtx_unlock(&am->am_lock);
+ DELAY(1000);
+ mtx_lock(&am->am_lock);
+ }
+ break;
+ }
tmo = timeout2hz(Timeout);
while (!ACPIMTX_AVAIL(am)) {
prevtick = ticks;
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 08a967f..c671ef9 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -2451,6 +2451,46 @@ acpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res)
return (AE_OK);
}
+ACPI_STATUS
+acpi_EvaluateOSC(ACPI_HANDLE handle, uint8_t *uuid, int revision, int count,
+ uint32_t *caps_in, uint32_t *caps_out, bool query)
+{
+ ACPI_OBJECT arg[4], *ret;
+ ACPI_OBJECT_LIST arglist;
+ ACPI_BUFFER buf;
+ ACPI_STATUS status;
+
+ arglist.Pointer = arg;
+ arglist.Count = 4;
+ arg[0].Type = ACPI_TYPE_BUFFER;
+ arg[0].Buffer.Length = ACPI_UUID_LENGTH;
+ arg[0].Buffer.Pointer = uuid;
+ arg[1].Type = ACPI_TYPE_INTEGER;
+ arg[1].Integer.Value = revision;
+ arg[2].Type = ACPI_TYPE_INTEGER;
+ arg[2].Integer.Value = count;
+ arg[3].Type = ACPI_TYPE_BUFFER;
+ arg[3].Buffer.Length = count * sizeof(*caps_in);
+ arg[3].Buffer.Pointer = (uint8_t *)caps_in;
+ caps_in[0] = query ? 1 : 0;
+ buf.Pointer = NULL;
+ buf.Length = ACPI_ALLOCATE_BUFFER;
+ status = AcpiEvaluateObjectTyped(handle, "_OSC", &arglist, &buf,
+ ACPI_TYPE_BUFFER);
+ if (ACPI_FAILURE(status))
+ return (status);
+ if (caps_out != NULL) {
+ ret = buf.Pointer;
+ if (ret->Buffer.Length != count * sizeof(*caps_out)) {
+ AcpiOsFree(buf.Pointer);
+ return (AE_BUFFER_OVERFLOW);
+ }
+ bcopy(ret->Buffer.Pointer, caps_out, ret->Buffer.Length);
+ }
+ AcpiOsFree(buf.Pointer);
+ return (status);
+}
+
/*
* Set interrupt model.
*/
diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c
index fc60bc8c..cad61cc 100644
--- a/sys/dev/acpica/acpi_cpu.c
+++ b/sys/dev/acpica/acpi_cpu.c
@@ -275,7 +275,7 @@ static int
acpi_cpu_attach(device_t dev)
{
ACPI_BUFFER buf;
- ACPI_OBJECT arg[4], *obj;
+ ACPI_OBJECT arg, *obj;
ACPI_OBJECT_LIST arglist;
struct pcpu *pcpu_data;
struct acpi_cpu_softc *sc;
@@ -359,31 +359,19 @@ acpi_cpu_attach(device_t dev)
* Intel Processor Vendor-Specific ACPI Interface Specification.
*/
if (sc->cpu_features) {
- arglist.Pointer = arg;
- arglist.Count = 4;
- arg[0].Type = ACPI_TYPE_BUFFER;
- arg[0].Buffer.Length = sizeof(cpu_oscuuid);
- arg[0].Buffer.Pointer = cpu_oscuuid; /* UUID */
- arg[1].Type = ACPI_TYPE_INTEGER;
- arg[1].Integer.Value = 1; /* revision */
- arg[2].Type = ACPI_TYPE_INTEGER;
- arg[2].Integer.Value = 1; /* count */
- arg[3].Type = ACPI_TYPE_BUFFER;
- arg[3].Buffer.Length = sizeof(cap_set); /* Capabilities buffer */
- arg[3].Buffer.Pointer = (uint8_t *)cap_set;
- cap_set[0] = 0; /* status */
cap_set[1] = sc->cpu_features;
- status = AcpiEvaluateObject(sc->cpu_handle, "_OSC", &arglist, NULL);
+ status = acpi_EvaluateOSC(sc->cpu_handle, cpu_oscuuid, 1, 2, cap_set,
+ cap_set, false);
if (ACPI_SUCCESS(status)) {
if (cap_set[0] != 0)
device_printf(dev, "_OSC returned status %#x\n", cap_set[0]);
}
else {
- arglist.Pointer = arg;
+ arglist.Pointer = &arg;
arglist.Count = 1;
- arg[0].Type = ACPI_TYPE_BUFFER;
- arg[0].Buffer.Length = sizeof(cap_set);
- arg[0].Buffer.Pointer = (uint8_t *)cap_set;
+ arg.Type = ACPI_TYPE_BUFFER;
+ arg.Buffer.Length = sizeof(cap_set);
+ arg.Buffer.Pointer = (uint8_t *)cap_set;
cap_set[0] = 1; /* revision */
cap_set[1] = 1; /* number of capabilities integers */
cap_set[2] = sc->cpu_features;
diff --git a/sys/dev/acpica/acpi_pcib_acpi.c b/sys/dev/acpica/acpi_pcib_acpi.c
index 490f277..da72b40 100644
--- a/sys/dev/acpica/acpi_pcib_acpi.c
+++ b/sys/dev/acpica/acpi_pcib_acpi.c
@@ -295,6 +295,39 @@ first_decoded_bus(struct acpi_hpcib_softc *sc, u_long *startp)
}
#endif
+static void
+acpi_pcib_osc(struct acpi_hpcib_softc *sc)
+{
+ ACPI_STATUS status;
+ uint32_t cap_set[3];
+
+ static uint8_t pci_host_bridge_uuid[ACPI_UUID_LENGTH] = {
+ 0x5b, 0x4d, 0xdb, 0x33, 0xf7, 0x1f, 0x1c, 0x40,
+ 0x96, 0x57, 0x74, 0x41, 0xc0, 0x3d, 0xd7, 0x66
+ };
+
+ /* Support Field: Extended PCI Config Space, MSI */
+ cap_set[1] = 0x11;
+
+ /* Control Field */
+ cap_set[2] = 0;
+
+ status = acpi_EvaluateOSC(sc->ap_handle, pci_host_bridge_uuid, 1,
+ nitems(cap_set), cap_set, cap_set, false);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_NOT_FOUND)
+ return;
+ device_printf(sc->ap_dev, "_OSC failed: %s\n",
+ AcpiFormatException(status));
+ return;
+ }
+
+ if (cap_set[0] != 0) {
+ device_printf(sc->ap_dev, "_OSC returned error %#x\n",
+ cap_set[0]);
+ }
+}
+
static int
acpi_pcib_acpi_attach(device_t dev)
{
@@ -321,6 +354,8 @@ acpi_pcib_acpi_attach(device_t dev)
if (!acpi_DeviceIsPresent(dev))
return (ENXIO);
+ acpi_pcib_osc(sc);
+
/*
* Get our segment number by evaluating _SEG.
* It's OK for this to not exist.
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index 81b8a61..4d08f33 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -335,6 +335,9 @@ ACPI_STATUS acpi_FindIndexedResource(ACPI_BUFFER *buf, int index,
ACPI_RESOURCE **resp);
ACPI_STATUS acpi_AppendBufferResource(ACPI_BUFFER *buf,
ACPI_RESOURCE *res);
+ACPI_STATUS acpi_EvaluateOSC(ACPI_HANDLE handle, uint8_t *uuid,
+ int revision, int count, uint32_t *caps_in,
+ uint32_t *caps_out, bool query);
ACPI_STATUS acpi_OverrideInterruptLevel(UINT32 InterruptNumber);
ACPI_STATUS acpi_SetIntrModel(int model);
int acpi_ReqSleepState(struct acpi_softc *sc, int state);
diff --git a/sys/dev/an/if_an.c b/sys/dev/an/if_an.c
index ee40c69..b5b9881 100644
--- a/sys/dev/an/if_an.c
+++ b/sys/dev/an/if_an.c
@@ -3777,6 +3777,9 @@ flashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
return ENOBUFS;
break;
case AIROFLSHGCHR: /* Get char from aux */
+ if (l_ioctl->len > sizeof(sc->areq)) {
+ return -EINVAL;
+ }
AN_UNLOCK(sc);
status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
AN_LOCK(sc);
@@ -3788,6 +3791,9 @@ flashcard(struct ifnet *ifp, struct aironet_ioctl *l_ioctl)
else
return -1;
case AIROFLSHPCHR: /* Send char to card. */
+ if (l_ioctl->len > sizeof(sc->areq)) {
+ return -EINVAL;
+ }
AN_UNLOCK(sc);
status = copyin(l_ioctl->data, &sc->areq, l_ioctl->len);
AN_LOCK(sc);
diff --git a/sys/dev/ciss/ciss.c b/sys/dev/ciss/ciss.c
index cafb6e7..bfeec60 100644
--- a/sys/dev/ciss/ciss.c
+++ b/sys/dev/ciss/ciss.c
@@ -345,21 +345,22 @@ static struct
{ 0x103C, 0x1928, CISS_BOARD_SA5, "HP Smart Array P230i" },
{ 0x103C, 0x1929, CISS_BOARD_SA5, "HP Smart Array P530" },
{ 0x103C, 0x192A, CISS_BOARD_SA5, "HP Smart Array P531" },
- { 0x103C, 0x21BD, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21BE, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21BF, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21C0, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21C2, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21C3, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21C5, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21C6, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21C7, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21C8, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21CA, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21CB, CISS_BOARD_SA5, "HP Smart Array TBD" },
+ { 0x103C, 0x21BD, CISS_BOARD_SA5, "HP Smart Array P244br" },
+ { 0x103C, 0x21BE, CISS_BOARD_SA5, "HP Smart Array P741m" },
+ { 0x103C, 0x21BF, CISS_BOARD_SA5, "HP Smart Array H240ar" },
+ { 0x103C, 0x21C0, CISS_BOARD_SA5, "HP Smart Array P440ar" },
+ { 0x103C, 0x21C1, CISS_BOARD_SA5, "HP Smart Array P840ar" },
+ { 0x103C, 0x21C2, CISS_BOARD_SA5, "HP Smart Array P440" },
+ { 0x103C, 0x21C3, CISS_BOARD_SA5, "HP Smart Array P441" },
+ { 0x103C, 0x21C5, CISS_BOARD_SA5, "HP Smart Array P841" },
+ { 0x103C, 0x21C6, CISS_BOARD_SA5, "HP Smart Array H244br" },
+ { 0x103C, 0x21C7, CISS_BOARD_SA5, "HP Smart Array H240" },
+ { 0x103C, 0x21C8, CISS_BOARD_SA5, "HP Smart Array H241" },
+ { 0x103C, 0x21CA, CISS_BOARD_SA5, "HP Smart Array P246br" },
+ { 0x103C, 0x21CB, CISS_BOARD_SA5, "HP Smart Array P840" },
{ 0x103C, 0x21CC, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21CD, CISS_BOARD_SA5, "HP Smart Array TBD" },
- { 0x103C, 0x21CE, CISS_BOARD_SA5, "HP Smart Array TBD" },
+ { 0x103C, 0x21CD, CISS_BOARD_SA5, "HP Smart Array P240nr" },
+ { 0x103C, 0x21CE, CISS_BOARD_SA5, "HP Smart Array H240nr" },
{ 0, 0, 0, NULL }
};
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index a81cf58..6711c06 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -1220,7 +1220,8 @@ em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
ifp->if_mtu = ifr->ifr_mtu;
adapter->hw.mac.max_frame_size =
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
- em_init_locked(adapter);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ em_init_locked(adapter);
EM_CORE_UNLOCK(adapter);
break;
}
diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
index 48ef637..cb2fb65 100644
--- a/sys/dev/e1000/if_igb.c
+++ b/sys/dev/e1000/if_igb.c
@@ -659,7 +659,8 @@ igb_attach(device_t dev)
return (0);
err_late:
- igb_detach(dev);
+ if (igb_detach(dev) == 0) /* igb_detach() already did the cleanup */
+ return(error);
igb_free_transmit_structures(adapter);
igb_free_receive_structures(adapter);
igb_release_hw_control(adapter);
@@ -1082,7 +1083,8 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
ifp->if_mtu = ifr->ifr_mtu;
adapter->max_frame_size =
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
- igb_init_locked(adapter);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ igb_init_locked(adapter);
IGB_CORE_UNLOCK(adapter);
break;
}
diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h
index f23bb0f..116f145 100644
--- a/sys/dev/e1000/if_igb.h
+++ b/sys/dev/e1000/if_igb.h
@@ -35,6 +35,10 @@
#ifndef _IF_IGB_H_
#define _IF_IGB_H_
+#ifdef ALTQ
+#define IGB_LEGACY_TX
+#endif
+
#include <sys/param.h>
#include <sys/systm.h>
diff --git a/sys/dev/e1000/if_lem.c b/sys/dev/e1000/if_lem.c
index b8310a1..574d1e0 100644
--- a/sys/dev/e1000/if_lem.c
+++ b/sys/dev/e1000/if_lem.c
@@ -1047,7 +1047,8 @@ lem_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
ifp->if_mtu = ifr->ifr_mtu;
adapter->max_frame_size =
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
- lem_init_locked(adapter);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ lem_init_locked(adapter);
EM_CORE_UNLOCK(adapter);
break;
}
diff --git a/sys/dev/hptmv/hptproc.c b/sys/dev/hptmv/hptproc.c
index 93eff51..946a224 100644
--- a/sys/dev/hptmv/hptproc.c
+++ b/sys/dev/hptmv/hptproc.c
@@ -290,7 +290,9 @@ hpt_set_info(int length)
/*
* map buffer to kernel.
*/
- if (piop->nInBufferSize+piop->nOutBufferSize > PAGE_SIZE) {
+ if (piop->nInBufferSize > PAGE_SIZE ||
+ piop->nOutBufferSize > PAGE_SIZE ||
+ piop->nInBufferSize+piop->nOutBufferSize > PAGE_SIZE) {
KdPrintE(("User buffer too large\n"));
return -EINVAL;
}
@@ -301,8 +303,13 @@ hpt_set_info(int length)
return -EINVAL;
}
- if (piop->nInBufferSize)
- copyin((void*)(ULONG_PTR)piop->lpInBuffer, ke_area, piop->nInBufferSize);
+ if (piop->nInBufferSize) {
+ if (copyin((void*)(ULONG_PTR)piop->lpInBuffer, ke_area, piop->nInBufferSize) != 0) {
+ KdPrintE(("Failed to copyin from lpInBuffer\n"));
+ free(ke_area, M_DEVBUF);
+ return -EFAULT;
+ }
+ }
/*
* call kernel handler.
@@ -324,7 +331,7 @@ hpt_set_info(int length)
else KdPrintW(("Kernel_ioctl(): return %d\n", err));
free(ke_area, M_DEVBUF);
- return -EINVAL;
+ return -EINVAL;
} else {
KdPrintW(("Wrong signature: %x\n", piop->Magic));
return -EINVAL;
diff --git a/sys/dev/ixgb/if_ixgb.c b/sys/dev/ixgb/if_ixgb.c
index f01e673..4c48cf1 100644
--- a/sys/dev/ixgb/if_ixgb.c
+++ b/sys/dev/ixgb/if_ixgb.c
@@ -538,7 +538,8 @@ ixgb_ioctl(struct ifnet * ifp, IOCTL_CMD_TYPE command, caddr_t data)
adapter->hw.max_frame_size =
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN;
- ixgb_init_locked(adapter);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ ixgb_init_locked(adapter);
IXGB_UNLOCK(adapter);
}
break;
diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index 43ace37..427f545 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -870,7 +870,8 @@ ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
ifp->if_mtu = ifr->ifr_mtu;
adapter->max_frame_size =
ifp->if_mtu + IXGBE_MTU_HDR;
- ixgbe_init_locked(adapter);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ ixgbe_init_locked(adapter);
#ifdef PCI_IOV
ixgbe_recalculate_max_frame(adapter);
#endif
diff --git a/sys/dev/ixgbe/if_ixv.c b/sys/dev/ixgbe/if_ixv.c
index 914f742..38bb1b8 100644
--- a/sys/dev/ixgbe/if_ixv.c
+++ b/sys/dev/ixgbe/if_ixv.c
@@ -587,7 +587,8 @@ ixv_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
ifp->if_mtu = ifr->ifr_mtu;
adapter->max_frame_size =
ifp->if_mtu + IXGBE_MTU_HDR;
- ixv_init_locked(adapter);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ ixv_init_locked(adapter);
IXGBE_CORE_UNLOCK(adapter);
}
break;
diff --git a/sys/dev/ixgbe/ixgbe_phy.c b/sys/dev/ixgbe/ixgbe_phy.c
index 8b0d165..7696e20 100644
--- a/sys/dev/ixgbe/ixgbe_phy.c
+++ b/sys/dev/ixgbe/ixgbe_phy.c
@@ -1532,21 +1532,18 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
hw->phy.type = ixgbe_phy_sfp_intel;
break;
default:
- if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
- hw->phy.type =
- ixgbe_phy_sfp_passive_unknown;
- else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
- hw->phy.type =
- ixgbe_phy_sfp_active_unknown;
- else
- hw->phy.type = ixgbe_phy_sfp_unknown;
+ hw->phy.type = ixgbe_phy_sfp_unknown;
break;
}
}
/* Allow any DA cable vendor */
if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE |
- IXGBE_SFF_DA_ACTIVE_CABLE)) {
+ IXGBE_SFF_DA_ACTIVE_CABLE)) {
+ if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
+ hw->phy.type = ixgbe_phy_sfp_passive_unknown;
+ else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
+ hw->phy.type = ixgbe_phy_sfp_active_unknown;
status = IXGBE_SUCCESS;
goto out;
}
diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c
index b89c64c..e646360 100644
--- a/sys/dev/ixl/if_ixl.c
+++ b/sys/dev/ixl/if_ixl.c
@@ -1024,7 +1024,8 @@ ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
vsi->max_frame_size =
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
+ ETHER_VLAN_ENCAP_LEN;
- ixl_init_locked(pf);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ ixl_init_locked(pf);
IXL_PF_UNLOCK(pf);
}
break;
diff --git a/sys/dev/ixl/if_ixlv.c b/sys/dev/ixl/if_ixlv.c
index 2e041df..d0cefa0 100644
--- a/sys/dev/ixl/if_ixlv.c
+++ b/sys/dev/ixl/if_ixlv.c
@@ -675,7 +675,8 @@ ixlv_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
vsi->max_frame_size =
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
+ ETHER_VLAN_ENCAP_LEN;
- ixlv_init_locked(sc);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ ixlv_init_locked(sc);
}
mtx_unlock(&sc->mtx);
break;
diff --git a/sys/dev/mpr/mpr.c b/sys/dev/mpr/mpr.c
index f5fe216..7d45274 100644
--- a/sys/dev/mpr/mpr.c
+++ b/sys/dev/mpr/mpr.c
@@ -1373,6 +1373,7 @@ mpr_get_tunables(struct mpr_softc *sc)
sc->disable_msix = 0;
sc->disable_msi = 0;
sc->max_chains = MPR_CHAIN_FRAMES;
+ sc->max_io_pages = MPR_MAXIO_PAGES;
sc->enable_ssu = MPR_SSU_ENABLE_SSD_DISABLE_HDD;
sc->spinup_wait_time = DEFAULT_SPINUP_WAIT;
@@ -1383,6 +1384,7 @@ mpr_get_tunables(struct mpr_softc *sc)
TUNABLE_INT_FETCH("hw.mpr.disable_msix", &sc->disable_msix);
TUNABLE_INT_FETCH("hw.mpr.disable_msi", &sc->disable_msi);
TUNABLE_INT_FETCH("hw.mpr.max_chains", &sc->max_chains);
+ TUNABLE_INT_FETCH("hw.mpr.max_io_pages", &sc->max_io_pages);
TUNABLE_INT_FETCH("hw.mpr.enable_ssu", &sc->enable_ssu);
TUNABLE_INT_FETCH("hw.mpr.spinup_wait_time", &sc->spinup_wait_time);
@@ -1403,6 +1405,10 @@ mpr_get_tunables(struct mpr_softc *sc)
device_get_unit(sc->mpr_dev));
TUNABLE_INT_FETCH(tmpstr, &sc->max_chains);
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_io_pages",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->max_io_pages);
+
bzero(sc->exclude_ids, sizeof(sc->exclude_ids));
snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.exclude_ids",
device_get_unit(sc->mpr_dev));
@@ -1488,6 +1494,11 @@ mpr_setup_sysctl(struct mpr_softc *sc)
&sc->max_chains, 0,"maximum chain frames that will be allocated");
SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "max_io_pages", CTLFLAG_RD,
+ &sc->max_io_pages, 0,"maximum pages to allow per I/O (if <1 use "
+ "IOCFacts)");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "enable_ssu", CTLFLAG_RW, &sc->enable_ssu, 0,
"enable SSU to SATA SSD/HDD at shutdown");
diff --git a/sys/dev/mpr/mpr_sas.c b/sys/dev/mpr/mpr_sas.c
index 45c0bbd..d44e502 100644
--- a/sys/dev/mpr/mpr_sas.c
+++ b/sys/dev/mpr/mpr_sas.c
@@ -971,6 +971,8 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb)
case XPT_PATH_INQ:
{
struct ccb_pathinq *cpi = &ccb->cpi;
+ struct mpr_softc *sc = sassc->sc;
+ uint8_t sges_per_frame;
cpi->version_num = 1;
cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
@@ -999,13 +1001,23 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb)
cpi->transport_version = 0;
cpi->protocol = PROTO_SCSI;
cpi->protocol_version = SCSI_REV_SPC;
-#if __FreeBSD_version >= 800001
+
/*
- * XXXSLM-probably need to base this number on max SGL's and
- * page size.
+ * Max IO Size is Page Size * the following:
+ * ((SGEs per frame - 1 for chain element) *
+ * Max Chain Depth) + 1 for no chain needed in last frame
+ *
+ * If user suggests a Max IO size to use, use the smaller of the
+ * user's value and the calculated value as long as the user's
+ * value is larger than 0. The user's value is in pages.
*/
- cpi->maxio = 256 * 1024;
-#endif
+ sges_per_frame = (sc->chain_frame_size /
+ sizeof(MPI2_IEEE_SGE_SIMPLE64)) - 1;
+ cpi->maxio = (sges_per_frame * sc->facts->MaxChainDepth) + 1;
+ cpi->maxio *= PAGE_SIZE;
+ if ((sc->max_io_pages > 0) && (sc->max_io_pages * PAGE_SIZE <
+ cpi->maxio))
+ cpi->maxio = sc->max_io_pages * PAGE_SIZE;
mprsas_set_ccbstatus(ccb, CAM_REQ_CMP);
break;
}
diff --git a/sys/dev/mpr/mprvar.h b/sys/dev/mpr/mprvar.h
index c2e8917..51ab8d0 100644
--- a/sys/dev/mpr/mprvar.h
+++ b/sys/dev/mpr/mprvar.h
@@ -33,7 +33,7 @@
#ifndef _MPRVAR_H
#define _MPRVAR_H
-#define MPR_DRIVER_VERSION "13.00.00.00-fbsd"
+#define MPR_DRIVER_VERSION "13.01.00.00-fbsd"
#define MPR_DB_MAX_WAIT 2500
@@ -41,6 +41,7 @@
#define MPR_EVT_REPLY_FRAMES 32
#define MPR_REPLY_FRAMES MPR_REQ_FRAMES
#define MPR_CHAIN_FRAMES 2048
+#define MPR_MAXIO_PAGES (-1)
#define MPR_SENSE_LEN SSD_FULL_SIZE
#define MPR_MSI_COUNT 1
#define MPR_SGE64_SIZE 12
@@ -264,6 +265,7 @@ struct mpr_softc {
int io_cmds_highwater;
int chain_free;
int max_chains;
+ int max_io_pages;
int chain_free_lowwater;
uint32_t chain_frame_size;
uint16_t chain_seg_size;
diff --git a/sys/dev/mps/mps.c b/sys/dev/mps/mps.c
index 2cdc39d..7b98426 100644
--- a/sys/dev/mps/mps.c
+++ b/sys/dev/mps/mps.c
@@ -1350,6 +1350,7 @@ mps_get_tunables(struct mps_softc *sc)
sc->disable_msix = 0;
sc->disable_msi = 0;
sc->max_chains = MPS_CHAIN_FRAMES;
+ sc->max_io_pages = MPS_MAXIO_PAGES;
sc->enable_ssu = MPS_SSU_ENABLE_SSD_DISABLE_HDD;
sc->spinup_wait_time = DEFAULT_SPINUP_WAIT;
@@ -1360,6 +1361,7 @@ mps_get_tunables(struct mps_softc *sc)
TUNABLE_INT_FETCH("hw.mps.disable_msix", &sc->disable_msix);
TUNABLE_INT_FETCH("hw.mps.disable_msi", &sc->disable_msi);
TUNABLE_INT_FETCH("hw.mps.max_chains", &sc->max_chains);
+ TUNABLE_INT_FETCH("hw.mps.max_io_pages", &sc->max_io_pages);
TUNABLE_INT_FETCH("hw.mps.enable_ssu", &sc->enable_ssu);
TUNABLE_INT_FETCH("hw.mps.spinup_wait_time", &sc->spinup_wait_time);
@@ -1380,6 +1382,10 @@ mps_get_tunables(struct mps_softc *sc)
device_get_unit(sc->mps_dev));
TUNABLE_INT_FETCH(tmpstr, &sc->max_chains);
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_io_pages",
+ device_get_unit(sc->mps_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->max_io_pages);
+
bzero(sc->exclude_ids, sizeof(sc->exclude_ids));
snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.exclude_ids",
device_get_unit(sc->mps_dev));
@@ -1465,6 +1471,11 @@ mps_setup_sysctl(struct mps_softc *sc)
&sc->max_chains, 0,"maximum chain frames that will be allocated");
SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "max_io_pages", CTLFLAG_RD,
+ &sc->max_io_pages, 0,"maximum pages to allow per I/O (if <1 use "
+ "IOCFacts)");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "enable_ssu", CTLFLAG_RW, &sc->enable_ssu, 0,
"enable SSU to SATA SSD/HDD at shutdown");
diff --git a/sys/dev/mps/mps_sas.c b/sys/dev/mps/mps_sas.c
index 0ab0889..02ec8d1 100644
--- a/sys/dev/mps/mps_sas.c
+++ b/sys/dev/mps/mps_sas.c
@@ -928,6 +928,8 @@ mpssas_action(struct cam_sim *sim, union ccb *ccb)
case XPT_PATH_INQ:
{
struct ccb_pathinq *cpi = &ccb->cpi;
+ struct mps_softc *sc = sassc->sc;
+ uint8_t sges_per_frame;
cpi->version_num = 1;
cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
@@ -951,12 +953,23 @@ mpssas_action(struct cam_sim *sim, union ccb *ccb)
cpi->transport_version = 0;
cpi->protocol = PROTO_SCSI;
cpi->protocol_version = SCSI_REV_SPC;
-#if __FreeBSD_version >= 800001
+
/*
- * XXX KDM where does this number come from?
+ * Max IO Size is Page Size * the following:
+ * ((SGEs per frame - 1 for chain element) *
+ * Max Chain Depth) + 1 for no chain needed in last frame
+ *
+ * If user suggests a Max IO size to use, use the smaller of the
+ * user's value and the calculated value as long as the user's
+ * value is larger than 0. The user's value is in pages.
*/
- cpi->maxio = 256 * 1024;
-#endif
+ sges_per_frame = ((sc->facts->IOCRequestFrameSize * 4) /
+ sizeof(MPI2_SGE_SIMPLE64)) - 1;
+ cpi->maxio = (sges_per_frame * sc->facts->MaxChainDepth) + 1;
+ cpi->maxio *= PAGE_SIZE;
+ if ((sc->max_io_pages > 0) && (sc->max_io_pages * PAGE_SIZE <
+ cpi->maxio))
+ cpi->maxio = sc->max_io_pages * PAGE_SIZE;
mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
break;
}
diff --git a/sys/dev/mps/mpsvar.h b/sys/dev/mps/mpsvar.h
index 62778c0..0d62b7d 100644
--- a/sys/dev/mps/mpsvar.h
+++ b/sys/dev/mps/mpsvar.h
@@ -33,7 +33,7 @@
#ifndef _MPSVAR_H
#define _MPSVAR_H
-#define MPS_DRIVER_VERSION "21.00.00.00-fbsd"
+#define MPS_DRIVER_VERSION "21.01.00.00-fbsd"
#define MPS_DB_MAX_WAIT 2500
@@ -41,6 +41,7 @@
#define MPS_EVT_REPLY_FRAMES 32
#define MPS_REPLY_FRAMES MPS_REQ_FRAMES
#define MPS_CHAIN_FRAMES 2048
+#define MPS_MAXIO_PAGES (-1)
#define MPS_SENSE_LEN SSD_FULL_SIZE
#define MPS_MSI_COUNT 1
#define MPS_SGE64_SIZE 12
@@ -280,6 +281,7 @@ struct mps_softc {
int io_cmds_highwater;
int chain_free;
int max_chains;
+ int max_io_pages;
int chain_free_lowwater;
u_int enable_ssu;
int spinup_wait_time;
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index a1e0ac8..4ceb075 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1881,6 +1881,22 @@ pci_ht_map_msi(device_t dev, uint64_t addr)
}
int
+pci_get_max_payload(device_t dev)
+{
+ struct pci_devinfo *dinfo = device_get_ivars(dev);
+ int cap;
+ uint16_t val;
+
+ cap = dinfo->cfg.pcie.pcie_location;
+ if (cap == 0)
+ return (0);
+ val = pci_read_config(dev, cap + PCIER_DEVICE_CTL, 2);
+ val &= PCIEM_CTL_MAX_PAYLOAD;
+ val >>= 5;
+ return (1 << (val + 7));
+}
+
+int
pci_get_max_read_req(device_t dev)
{
struct pci_devinfo *dinfo = device_get_ivars(dev);
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index 14132bf..5c589ac 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -534,6 +534,7 @@ int pci_msix_device_blacklisted(device_t dev);
void pci_ht_map_msi(device_t dev, uint64_t addr);
device_t pci_find_pcie_root_port(device_t dev);
+int pci_get_max_payload(device_t dev);
int pci_get_max_read_req(device_t dev);
void pci_restore_state(device_t dev);
void pci_save_state(device_t dev);
diff --git a/sys/dev/vmware/vmxnet3/if_vmx.c b/sys/dev/vmware/vmxnet3/if_vmx.c
index 0629f2b..9acb36e 100644
--- a/sys/dev/vmware/vmxnet3/if_vmx.c
+++ b/sys/dev/vmware/vmxnet3/if_vmx.c
@@ -128,6 +128,7 @@ static int vmxnet3_alloc_queue_data(struct vmxnet3_softc *);
static void vmxnet3_free_queue_data(struct vmxnet3_softc *);
static int vmxnet3_alloc_mcast_table(struct vmxnet3_softc *);
static void vmxnet3_init_shared_data(struct vmxnet3_softc *);
+static void vmxnet3_init_hwassist(struct vmxnet3_softc *);
static void vmxnet3_reinit_interface(struct vmxnet3_softc *);
static void vmxnet3_reinit_rss_shared_data(struct vmxnet3_softc *);
static void vmxnet3_reinit_shared_data(struct vmxnet3_softc *);
@@ -1584,6 +1585,24 @@ vmxnet3_init_shared_data(struct vmxnet3_softc *sc)
}
static void
+vmxnet3_init_hwassist(struct vmxnet3_softc *sc)
+{
+ struct ifnet *ifp = sc->vmx_ifp;
+ uint64_t hwassist;
+
+ hwassist = 0;
+ if (ifp->if_capenable & IFCAP_TXCSUM)
+ hwassist |= VMXNET3_CSUM_OFFLOAD;
+ if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
+ hwassist |= VMXNET3_CSUM_OFFLOAD_IPV6;
+ if (ifp->if_capenable & IFCAP_TSO4)
+ hwassist |= CSUM_IP_TSO;
+ if (ifp->if_capenable & IFCAP_TSO6)
+ hwassist |= CSUM_IP6_TSO;
+ ifp->if_hwassist = hwassist;
+}
+
+static void
vmxnet3_reinit_interface(struct vmxnet3_softc *sc)
{
struct ifnet *ifp;
@@ -1594,15 +1613,7 @@ vmxnet3_reinit_interface(struct vmxnet3_softc *sc)
bcopy(IF_LLADDR(sc->vmx_ifp), sc->vmx_lladdr, ETHER_ADDR_LEN);
vmxnet3_set_lladdr(sc);
- ifp->if_hwassist = 0;
- if (ifp->if_capenable & IFCAP_TXCSUM)
- ifp->if_hwassist |= VMXNET3_CSUM_OFFLOAD;
- if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
- ifp->if_hwassist |= VMXNET3_CSUM_OFFLOAD_IPV6;
- if (ifp->if_capenable & IFCAP_TSO4)
- ifp->if_hwassist |= CSUM_IP_TSO;
- if (ifp->if_capenable & IFCAP_TSO6)
- ifp->if_hwassist |= CSUM_IP6_TSO;
+ vmxnet3_init_hwassist(sc);
}
static void
@@ -3284,6 +3295,8 @@ vmxnet3_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (reinit && (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
vmxnet3_init_locked(sc);
+ } else {
+ vmxnet3_init_hwassist(sc);
}
VMXNET3_CORE_UNLOCK(sc);
diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c
index 13b0842..747d1f5 100644
--- a/sys/geom/mirror/g_mirror.c
+++ b/sys/geom/mirror/g_mirror.c
@@ -2127,8 +2127,21 @@ g_mirror_destroy_provider(struct g_mirror_softc *sc)
g_topology_lock();
g_error_provider(sc->sc_provider, ENXIO);
mtx_lock(&sc->sc_queue_mtx);
- while ((bp = bioq_takefirst(&sc->sc_queue)) != NULL)
- g_io_deliver(bp, ENXIO);
+ while ((bp = bioq_takefirst(&sc->sc_queue)) != NULL) {
+ /*
+ * Abort any pending I/O that wasn't generated by us.
+ * Synchronization requests and requests destined for individual
+ * mirror components can be destroyed immediately.
+ */
+ if (bp->bio_to == sc->sc_provider &&
+ bp->bio_from->geom != sc->sc_sync.ds_geom) {
+ g_io_deliver(bp, ENXIO);
+ } else {
+ if ((bp->bio_cflags & G_MIRROR_BIO_FLAG_SYNC) != 0)
+ free(bp->bio_data, M_MIRROR);
+ g_destroy_bio(bp);
+ }
+ }
mtx_unlock(&sc->sc_queue_mtx);
G_MIRROR_DEBUG(0, "Device %s: provider %s destroyed.", sc->sc_name,
sc->sc_provider->name);
diff --git a/sys/geom/uzip/g_uzip.c b/sys/geom/uzip/g_uzip.c
index 6c79662..1486800 100644
--- a/sys/geom/uzip/g_uzip.c
+++ b/sys/geom/uzip/g_uzip.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2004 Max Khon
* Copyright (c) 2014 Juniper Networks, Inc.
+ * Copyright (c) 2006-2016 Maxim Sobolev <sobomax@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,91 +39,129 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
+#include <sys/kthread.h>
#include <geom/geom.h>
-#include <net/zlib.h>
-FEATURE(geom_uzip, "GEOM uzip read-only compressed disks support");
+#include <geom/uzip/g_uzip.h>
+#include <geom/uzip/g_uzip_cloop.h>
+#include <geom/uzip/g_uzip_softc.h>
+#include <geom/uzip/g_uzip_dapi.h>
+#include <geom/uzip/g_uzip_zlib.h>
+#include <geom/uzip/g_uzip_lzma.h>
+#include <geom/uzip/g_uzip_wrkthr.h>
+
+#include "opt_geom.h"
+
+MALLOC_DEFINE(M_GEOM_UZIP, "geom_uzip", "GEOM UZIP data structures");
+
+FEATURE(geom_uzip, "GEOM read-only compressed disks support");
+
+struct g_uzip_blk {
+ uint64_t offset;
+ uint32_t blen;
+ unsigned char last:1;
+ unsigned char padded:1;
+#define BLEN_UNDEF UINT32_MAX
+};
+
+#ifndef ABS
+#define ABS(a) ((a) < 0 ? -(a) : (a))
+#endif
+
+#define BLK_IN_RANGE(mcn, bcn, ilen) \
+ (((bcn) != BLEN_UNDEF) && ( \
+ ((ilen) >= 0 && (mcn >= bcn) && (mcn <= ((intmax_t)(bcn) + (ilen)))) || \
+ ((ilen) < 0 && (mcn <= bcn) && (mcn >= ((intmax_t)(bcn) + (ilen)))) \
+ ))
-#undef GEOM_UZIP_DEBUG
#ifdef GEOM_UZIP_DEBUG
-#define DPRINTF(a) printf a
+# define GEOM_UZIP_DBG_DEFAULT 3
#else
-#define DPRINTF(a)
+# define GEOM_UZIP_DBG_DEFAULT 0
#endif
-static MALLOC_DEFINE(M_GEOM_UZIP, "geom_uzip", "GEOM UZIP data structures");
+#define GUZ_DBG_ERR 1
+#define GUZ_DBG_INFO 2
+#define GUZ_DBG_IO 3
+#define GUZ_DBG_TOC 4
+
+#define GUZ_DEV_SUFX ".uzip"
+#define GUZ_DEV_NAME(p) (p GUZ_DEV_SUFX)
+
+static char g_uzip_attach_to[MAXPATHLEN] = {"*"};
+static char g_uzip_noattach_to[MAXPATHLEN] = {GUZ_DEV_NAME("*")};
+TUNABLE_STR("kern.geom.uzip.attach_to", g_uzip_attach_to,
+ sizeof(g_uzip_attach_to));
+TUNABLE_STR("kern.geom.uzip.noattach_to", g_uzip_noattach_to,
+ sizeof(g_uzip_noattach_to));
+
+SYSCTL_DECL(_kern_geom);
+SYSCTL_NODE(_kern_geom, OID_AUTO, uzip, CTLFLAG_RW, 0, "GEOM_UZIP stuff");
+static u_int g_uzip_debug = GEOM_UZIP_DBG_DEFAULT;
+SYSCTL_UINT(_kern_geom_uzip, OID_AUTO, debug, CTLFLAG_RWTUN, &g_uzip_debug, 0,
+ "Debug level (0-4)");
+static u_int g_uzip_debug_block = BLEN_UNDEF;
+SYSCTL_UINT(_kern_geom_uzip, OID_AUTO, debug_block, CTLFLAG_RWTUN,
+ &g_uzip_debug_block, 0, "Debug operations around specific cluster#");
+
+#define DPRINTF(lvl, a) \
+ if ((lvl) <= g_uzip_debug) { \
+ printf a; \
+ }
+#define DPRINTF_BLK(lvl, cn, a) \
+ if ((lvl) <= g_uzip_debug || \
+ BLK_IN_RANGE(cn, g_uzip_debug_block, 8) || \
+ BLK_IN_RANGE(cn, g_uzip_debug_block, -8)) { \
+ printf a; \
+ }
+#define DPRINTF_BRNG(lvl, bcn, ecn, a) \
+ KASSERT(bcn < ecn, ("DPRINTF_BRNG: invalid range (%ju, %ju)", \
+ (uintmax_t)bcn, (uintmax_t)ecn)); \
+ if (((lvl) <= g_uzip_debug) || \
+ BLK_IN_RANGE(g_uzip_debug_block, bcn, \
+ (intmax_t)ecn - (intmax_t)bcn)) { \
+ printf a; \
+ }
#define UZIP_CLASS_NAME "UZIP"
/*
* Maximum allowed valid block size (to prevent foot-shooting)
*/
-#define MAX_BLKSZ (MAXPHYS - MAXPHYS / 1000 - 12)
-
-/*
- * Integer values (block size, number of blocks, offsets)
- * are stored in big-endian (network) order on disk and struct cloop_header
- * and in native order in struct g_uzip_softc
- */
+#define MAX_BLKSZ (MAXPHYS)
-#define CLOOP_MAGIC_LEN 128
static char CLOOP_MAGIC_START[] = "#!/bin/sh\n";
-struct cloop_header {
- char magic[CLOOP_MAGIC_LEN]; /* cloop magic */
- uint32_t blksz; /* block size */
- uint32_t nblocks; /* number of blocks */
-};
-
-struct g_uzip_softc {
- uint32_t blksz; /* block size */
- uint32_t nblocks; /* number of blocks */
- uint64_t *offsets;
-
- struct mtx last_mtx;
- uint32_t last_blk; /* last blk no */
- char *last_buf; /* last blk data */
- int req_total; /* total requests */
- int req_cached; /* cached requests */
-};
-
-static void g_uzip_done(struct bio *bp);
+static void g_uzip_read_done(struct bio *bp);
+static void g_uzip_do(struct g_uzip_softc *, struct bio *bp);
static void
g_uzip_softc_free(struct g_uzip_softc *sc, struct g_geom *gp)
{
if (gp != NULL) {
- DPRINTF(("%s: %d requests, %d cached\n",
+ DPRINTF(GUZ_DBG_INFO, ("%s: %d requests, %d cached\n",
gp->name, sc->req_total, sc->req_cached));
}
- if (sc->offsets != NULL) {
- free(sc->offsets, M_GEOM_UZIP);
- sc->offsets = NULL;
+
+ mtx_lock(&sc->queue_mtx);
+ sc->wrkthr_flags |= GUZ_SHUTDOWN;
+ wakeup(sc);
+ while (!(sc->wrkthr_flags & GUZ_EXITING)) {
+ msleep(sc->procp, &sc->queue_mtx, PRIBIO, "guzfree",
+ hz / 10);
}
+ mtx_unlock(&sc->queue_mtx);
+
+ sc->dcp->free(sc->dcp);
+ free(sc->toc, M_GEOM_UZIP);
+ mtx_destroy(&sc->queue_mtx);
mtx_destroy(&sc->last_mtx);
free(sc->last_buf, M_GEOM_UZIP);
free(sc, M_GEOM_UZIP);
}
-static void *
-z_alloc(void *nil, u_int type, u_int size)
-{
- void *ptr;
-
- ptr = malloc(type * size, M_GEOM_UZIP, M_NOWAIT);
-
- return (ptr);
-}
-
-static void
-z_free(void *nil, void *ptr)
-{
-
- free(ptr, M_GEOM_UZIP);
-}
-
static int
g_uzip_cached(struct g_geom *gp, struct bio *bp)
{
@@ -144,8 +183,9 @@ g_uzip_cached(struct g_geom *gp, struct bio *bp)
sc->req_cached++;
mtx_unlock(&sc->last_mtx);
- DPRINTF(("%s/%s: %p: offset=%jd: got %jd bytes from cache\n",
- __func__, gp->name, bp, (intmax_t)ofs, (intmax_t)usz));
+ DPRINTF(GUZ_DBG_IO, ("%s/%s: %p: offset=%jd: got %jd bytes "
+ "from cache\n", __func__, gp->name, bp, (intmax_t)ofs,
+ (intmax_t)usz));
bp->bio_completed += usz;
bp->bio_resid -= usz;
@@ -160,6 +200,19 @@ g_uzip_cached(struct g_geom *gp, struct bio *bp)
return (0);
}
+#define BLK_ENDS(sc, bi) ((sc)->toc[(bi)].offset + \
+ (sc)->toc[(bi)].blen)
+
+#define BLK_IS_CONT(sc, bi) (BLK_ENDS((sc), (bi) - 1) == \
+ (sc)->toc[(bi)].offset)
+#define BLK_IS_NIL(sc, bi) ((sc)->toc[(bi)].blen == 0)
+
+#define TOFF_2_BOFF(sc, pp, bi) ((sc)->toc[(bi)].offset - \
+ (sc)->toc[(bi)].offset % (pp)->sectorsize)
+#define TLEN_2_BLEN(sc, pp, bp, ei) ((BLK_ENDS((sc), (ei)) - \
+ (bp)->bio_offset + (pp)->sectorsize - 1) / \
+ (pp)->sectorsize * (pp)->sectorsize)
+
static int
g_uzip_request(struct g_geom *gp, struct bio *bp)
{
@@ -167,21 +220,14 @@ g_uzip_request(struct g_geom *gp, struct bio *bp)
struct bio *bp2;
struct g_consumer *cp;
struct g_provider *pp;
- off_t ofs;
- size_t start_blk, end_blk;
+ off_t ofs, start_blk_ofs;
+ size_t i, start_blk, end_blk, zsize;
if (g_uzip_cached(gp, bp) != 0)
return (1);
sc = gp->softc;
- bp2 = g_clone_bio(bp);
- if (bp2 == NULL) {
- g_io_deliver(bp, ENOMEM);
- return (1);
- }
- bp2->bio_done = g_uzip_done;
-
cp = LIST_FIRST(&gp->consumer);
pp = cp->provider;
@@ -191,23 +237,68 @@ g_uzip_request(struct g_geom *gp, struct bio *bp)
end_blk = (ofs + bp->bio_resid + sc->blksz - 1) / sc->blksz;
KASSERT(end_blk <= sc->nblocks, ("end_blk out of range"));
- DPRINTF(("%s/%s: %p: start=%u (%jd), end=%u (%jd)\n",
- __func__, gp->name, bp,
- (u_int)start_blk, (intmax_t)sc->offsets[start_blk],
- (u_int)end_blk, (intmax_t)sc->offsets[end_blk]));
+ for (; BLK_IS_NIL(sc, start_blk) && start_blk < end_blk; start_blk++) {
+ /* Fill in any leading Nil blocks */
+ start_blk_ofs = ofs % sc->blksz;
+ zsize = MIN(sc->blksz - start_blk_ofs, bp->bio_resid);
+ DPRINTF_BLK(GUZ_DBG_IO, start_blk, ("%s/%s: %p/%ju: "
+ "filling %ju zero bytes\n", __func__, gp->name, gp,
+ (uintmax_t)bp->bio_completed, (uintmax_t)zsize));
+ bzero(bp->bio_data + bp->bio_completed, zsize);
+ bp->bio_completed += zsize;
+ bp->bio_resid -= zsize;
+ ofs += zsize;
+ }
- bp2->bio_offset = sc->offsets[start_blk] -
- sc->offsets[start_blk] % pp->sectorsize;
- while (1) {
- bp2->bio_length = sc->offsets[end_blk] - bp2->bio_offset;
- bp2->bio_length = (bp2->bio_length + pp->sectorsize - 1) /
- pp->sectorsize * pp->sectorsize;
- if (bp2->bio_length <= MAXPHYS)
+ if (start_blk == end_blk) {
+ KASSERT(bp->bio_resid == 0, ("bp->bio_resid is invalid"));
+ /*
+ * No non-Nil data is left, complete request immediately.
+ */
+ DPRINTF(GUZ_DBG_IO, ("%s/%s: %p: all done returning %ju "
+ "bytes\n", __func__, gp->name, gp,
+ (uintmax_t)bp->bio_completed));
+ g_io_deliver(bp, 0);
+ return (1);
+ }
+
+ for (i = start_blk + 1; i < end_blk; i++) {
+ /* Trim discontinuous areas if any */
+ if (!BLK_IS_CONT(sc, i)) {
+ end_blk = i;
break;
+ }
+ }
+
+ DPRINTF_BRNG(GUZ_DBG_IO, start_blk, end_blk, ("%s/%s: %p: "
+ "start=%u (%ju[%jd]), end=%u (%ju)\n", __func__, gp->name, bp,
+ (u_int)start_blk, (uintmax_t)sc->toc[start_blk].offset,
+ (intmax_t)sc->toc[start_blk].blen,
+ (u_int)end_blk, (uintmax_t)BLK_ENDS(sc, end_blk - 1)));
+ bp2 = g_clone_bio(bp);
+ if (bp2 == NULL) {
+ g_io_deliver(bp, ENOMEM);
+ return (1);
+ }
+ bp2->bio_done = g_uzip_read_done;
+
+ bp2->bio_offset = TOFF_2_BOFF(sc, pp, start_blk);
+ while (1) {
+ bp2->bio_length = TLEN_2_BLEN(sc, pp, bp2, end_blk - 1);
+ if (bp2->bio_length <= MAXPHYS) {
+ break;
+ }
+ if (end_blk == (start_blk + 1)) {
+ break;
+ }
end_blk--;
}
+ DPRINTF(GUZ_DBG_IO, ("%s/%s: bp2->bio_length = %jd, "
+ "bp2->bio_offset = %jd\n", __func__, gp->name,
+ (intmax_t)bp2->bio_length, (intmax_t)bp2->bio_offset));
+
bp2->bio_data = malloc(bp2->bio_length, M_GEOM_UZIP, M_NOWAIT);
if (bp2->bio_data == NULL) {
g_destroy_bio(bp2);
@@ -215,8 +306,8 @@ g_uzip_request(struct g_geom *gp, struct bio *bp)
return (1);
}
- DPRINTF(("%s/%s: %p: reading %jd bytes from offset %jd\n",
- __func__, gp->name, bp,
+ DPRINTF_BRNG(GUZ_DBG_IO, start_blk, end_blk, ("%s/%s: %p: "
+ "reading %jd bytes from offset %jd\n", __func__, gp->name, bp,
(intmax_t)bp2->bio_length, (intmax_t)bp2->bio_offset));
g_io_request(bp2, cp);
@@ -224,21 +315,45 @@ g_uzip_request(struct g_geom *gp, struct bio *bp)
}
static void
-g_uzip_done(struct bio *bp)
+g_uzip_read_done(struct bio *bp)
+{
+ struct bio *bp2;
+ struct g_geom *gp;
+ struct g_uzip_softc *sc;
+
+ bp2 = bp->bio_parent;
+ gp = bp2->bio_to->geom;
+ sc = gp->softc;
+
+ mtx_lock(&sc->queue_mtx);
+ bioq_disksort(&sc->bio_queue, bp);
+ mtx_unlock(&sc->queue_mtx);
+ wakeup(sc);
+}
+
+static int
+g_uzip_memvcmp(const void *memory, unsigned char val, size_t size)
+{
+ const u_char *mm;
+
+ mm = (const u_char *)memory;
+ return (*mm == val) && memcmp(mm, mm + 1, size - 1) == 0;
+}
+
+static void
+g_uzip_do(struct g_uzip_softc *sc, struct bio *bp)
{
- z_stream zs;
struct bio *bp2;
struct g_provider *pp;
struct g_consumer *cp;
struct g_geom *gp;
- struct g_uzip_softc *sc;
char *data, *data2;
off_t ofs;
- size_t blk, blkofs, len, ulen;
+ size_t blk, blkofs, len, ulen, firstblk;
+ int err;
bp2 = bp->bio_parent;
gp = bp2->bio_to->geom;
- sc = gp->softc;
cp = LIST_FIRST(&gp->consumer);
pp = cp->provider;
@@ -253,46 +368,62 @@ g_uzip_done(struct bio *bp)
goto done;
}
- zs.zalloc = z_alloc;
- zs.zfree = z_free;
- if (inflateInit(&zs) != Z_OK) {
- bp2->bio_error = EILSEQ;
- goto done;
- }
-
ofs = bp2->bio_offset + bp2->bio_completed;
- blk = ofs / sc->blksz;
+ firstblk = blk = ofs / sc->blksz;
blkofs = ofs % sc->blksz;
- data = bp->bio_data + sc->offsets[blk] % pp->sectorsize;
+ data = bp->bio_data + sc->toc[blk].offset % pp->sectorsize;
data2 = bp2->bio_data + bp2->bio_completed;
while (bp->bio_completed && bp2->bio_resid) {
+ if (blk > firstblk && !BLK_IS_CONT(sc, blk)) {
+ DPRINTF_BLK(GUZ_DBG_IO, blk, ("%s/%s: %p: backref'ed "
+ "cluster #%u requested, looping around\n",
+ __func__, gp->name, bp2, (u_int)blk));
+ goto done;
+ }
ulen = MIN(sc->blksz - blkofs, bp2->bio_resid);
- len = sc->offsets[blk + 1] - sc->offsets[blk];
- DPRINTF(("%s/%s: %p/%ju: data2=%p, ulen=%u, data=%p, len=%u\n",
- __func__, gp->name, gp, bp->bio_completed,
- data2, (u_int)ulen, data, (u_int)len));
+ len = sc->toc[blk].blen;
+ DPRINTF(GUZ_DBG_IO, ("%s/%s: %p/%ju: data2=%p, ulen=%u, "
+ "data=%p, len=%u\n", __func__, gp->name, gp,
+ bp->bio_completed, data2, (u_int)ulen, data, (u_int)len));
if (len == 0) {
/* All zero block: no cache update */
+zero_block:
bzero(data2, ulen);
} else if (len <= bp->bio_completed) {
- zs.next_in = data;
- zs.avail_in = len;
- zs.next_out = sc->last_buf;
- zs.avail_out = sc->blksz;
mtx_lock(&sc->last_mtx);
- if (inflate(&zs, Z_FINISH) != Z_STREAM_END) {
+ err = sc->dcp->decompress(sc->dcp, gp->name, data,
+ len, sc->last_buf);
+ if (err != 0 && sc->toc[blk].last != 0) {
+ /*
+ * Last block decompression has failed, check
+ * if it's just zero padding.
+ */
+ if (g_uzip_memvcmp(data, '\0', len) == 0) {
+ sc->toc[blk].blen = 0;
+ sc->last_blk = -1;
+ mtx_unlock(&sc->last_mtx);
+ len = 0;
+ goto zero_block;
+ }
+ }
+ if (err != 0) {
sc->last_blk = -1;
mtx_unlock(&sc->last_mtx);
- inflateEnd(&zs);
bp2->bio_error = EILSEQ;
+ DPRINTF(GUZ_DBG_ERR, ("%s/%s: decompress"
+ "(%p, %ju, %ju) failed\n", __func__,
+ gp->name, sc->dcp, (uintmax_t)blk,
+ (uintmax_t)len));
goto done;
}
sc->last_blk = blk;
memcpy(data2, sc->last_buf + blkofs, ulen);
mtx_unlock(&sc->last_mtx);
- if (inflateReset(&zs) != Z_OK) {
- inflateEnd(&zs);
+ err = sc->dcp->rewind(sc->dcp, gp->name);
+ if (err != 0) {
bp2->bio_error = EILSEQ;
+ DPRINTF(GUZ_DBG_ERR, ("%s/%s: rewind(%p) "
+ "failed\n", __func__, gp->name, sc->dcp));
goto done;
}
data += len;
@@ -307,9 +438,6 @@ g_uzip_done(struct bio *bp)
blk++;
}
- if (inflateEnd(&zs) != Z_OK)
- bp2->bio_error = EILSEQ;
-
done:
/* Finish processing the request. */
free(bp->bio_data, M_GEOM_UZIP);
@@ -330,9 +458,9 @@ g_uzip_start(struct bio *bp)
pp = bp->bio_to;
gp = pp->geom;
- DPRINTF(("%s/%s: %p: cmd=%d, offset=%jd, length=%jd, buffer=%p\n",
- __func__, gp->name, bp, bp->bio_cmd, (intmax_t)bp->bio_offset,
- (intmax_t)bp->bio_length, bp->bio_data));
+ DPRINTF(GUZ_DBG_IO, ("%s/%s: %p: cmd=%d, offset=%jd, length=%jd, "
+ "buffer=%p\n", __func__, gp->name, bp, bp->bio_cmd,
+ (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length, bp->bio_data));
sc = gp->softc;
sc->req_total++;
@@ -383,6 +511,7 @@ g_uzip_spoiled(struct g_consumer *cp)
{
struct g_geom *gp;
+ G_VALID_CONSUMER(cp);
gp = cp->geom;
g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, gp->name);
g_topology_assert();
@@ -392,6 +521,114 @@ g_uzip_spoiled(struct g_consumer *cp)
g_wither_geom(gp, ENXIO);
}
+static int
+g_uzip_parse_toc(struct g_uzip_softc *sc, struct g_provider *pp,
+ struct g_geom *gp)
+{
+ uint32_t i, j, backref_to;
+ uint64_t max_offset, min_offset;
+ struct g_uzip_blk *last_blk;
+
+ min_offset = sizeof(struct cloop_header) +
+ (sc->nblocks + 1) * sizeof(uint64_t);
+ max_offset = sc->toc[0].offset - 1;
+ last_blk = &sc->toc[0];
+ for (i = 0; i < sc->nblocks; i++) {
+ /* First do some bounds checking */
+ if ((sc->toc[i].offset < min_offset) ||
+ (sc->toc[i].offset > pp->mediasize)) {
+ goto error_offset;
+ }
+ DPRINTF_BLK(GUZ_DBG_IO, i, ("%s: cluster #%u "
+ "offset=%ju max_offset=%ju\n", gp->name,
+ (u_int)i, (uintmax_t)sc->toc[i].offset,
+ (uintmax_t)max_offset));
+ backref_to = BLEN_UNDEF;
+ if (sc->toc[i].offset < max_offset) {
+ /*
+ * For the backref'ed blocks search already parsed
+ * TOC entries for the matching offset and copy the
+ * size from matched entry.
+ */
+ for (j = 0; j <= i; j++) {
+ if (sc->toc[j].offset == sc->toc[i].offset &&
+ !BLK_IS_NIL(sc, j)) {
+ break;
+ }
+ if (j != i) {
+ continue;
+ }
+ DPRINTF(GUZ_DBG_ERR, ("%s: cannot match "
+ "backref'ed offset at cluster #%u\n",
+ gp->name, i));
+ return (-1);
+ }
+ sc->toc[i].blen = sc->toc[j].blen;
+ backref_to = j;
+ } else {
+ last_blk = &sc->toc[i];
+ /*
+ * For the "normal blocks" seek forward until we hit
+ * block whose offset is larger than ours and assume
+ * it's going to be the next one.
+ */
+ for (j = i + 1; j < sc->nblocks; j++) {
+ if (sc->toc[j].offset > max_offset) {
+ break;
+ }
+ }
+ sc->toc[i].blen = sc->toc[j].offset -
+ sc->toc[i].offset;
+ if (BLK_ENDS(sc, i) > pp->mediasize) {
+ DPRINTF(GUZ_DBG_ERR, ("%s: cluster #%u "
+ "extends past media boundary (%ju > %ju)\n",
+ gp->name, (u_int)i,
+ (uintmax_t)BLK_ENDS(sc, i),
+ (intmax_t)pp->mediasize));
+ return (-1);
+ }
+ KASSERT(max_offset <= sc->toc[i].offset, (
+ "%s: max_offset is incorrect: %ju",
+ gp->name, (uintmax_t)max_offset));
+ max_offset = BLK_ENDS(sc, i) - 1;
+ }
+ DPRINTF_BLK(GUZ_DBG_TOC, i, ("%s: cluster #%u, original %u "
+ "bytes, in %u bytes", gp->name, i, sc->blksz,
+ sc->toc[i].blen));
+ if (backref_to != BLEN_UNDEF) {
+ DPRINTF_BLK(GUZ_DBG_TOC, i, (" (->#%u)",
+ (u_int)backref_to));
+ }
+ DPRINTF_BLK(GUZ_DBG_TOC, i, ("\n"));
+ }
+ last_blk->last = 1;
+ /* Do a second pass to validate block lengths */
+ for (i = 0; i < sc->nblocks; i++) {
+ if (sc->toc[i].blen > sc->dcp->max_blen) {
+ if (sc->toc[i].last == 0) {
+ DPRINTF(GUZ_DBG_ERR, ("%s: cluster #%u "
+ "length (%ju) exceeds "
+ "max_blen (%ju)\n", gp->name, i,
+ (uintmax_t)sc->toc[i].blen,
+ (uintmax_t)sc->dcp->max_blen));
+ return (-1);
+ }
+ DPRINTF(GUZ_DBG_INFO, ("%s: cluster #%u extra "
+ "padding is detected, trimmed to %ju\n",
+ gp->name, i, (uintmax_t)sc->dcp->max_blen));
+ sc->toc[i].blen = sc->dcp->max_blen;
+ sc->toc[i].padded = 1;
+ }
+ }
+ return (0);
+
+error_offset:
+ DPRINTF(GUZ_DBG_ERR, ("%s: cluster #%u: invalid offset %ju, "
+ "min_offset=%ju mediasize=%jd\n", gp->name, (u_int)i,
+ sc->toc[i].offset, min_offset, pp->mediasize));
+ return (-1);
+}
+
static struct g_geom *
g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags)
{
@@ -403,6 +640,10 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags)
struct g_geom *gp;
struct g_provider *pp2;
struct g_uzip_softc *sc;
+ enum {
+ G_UZIP = 1,
+ G_ULZMA
+ } type;
g_trace(G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name);
g_topology_assert();
@@ -411,21 +652,25 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags)
if (pp->acw > 0)
return (NULL);
+ if ((fnmatch(g_uzip_attach_to, pp->name, 0) != 0) ||
+ (fnmatch(g_uzip_noattach_to, pp->name, 0) == 0)) {
+ DPRINTF(GUZ_DBG_INFO, ("%s(%s,%s), ignoring\n", __func__,
+ mp->name, pp->name));
+ return (NULL);
+ }
+
buf = NULL;
/*
* Create geom instance.
*/
- gp = g_new_geomf(mp, "%s.uzip", pp->name);
+ gp = g_new_geomf(mp, GUZ_DEV_NAME("%s"), pp->name);
cp = g_new_consumer(gp);
error = g_attach(cp, pp);
if (error == 0)
error = g_access(cp, 1, 0, 0);
if (error) {
- g_detach(cp);
- g_destroy_consumer(cp);
- g_destroy_geom(gp);
- return (NULL);
+ goto e1;
}
g_topology_unlock();
@@ -433,22 +678,47 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags)
* Read cloop header, look for CLOOP magic, perform
* other validity checks.
*/
- DPRINTF(("%s: media sectorsize %u, mediasize %jd\n",
+ DPRINTF(GUZ_DBG_INFO, ("%s: media sectorsize %u, mediasize %jd\n",
gp->name, pp->sectorsize, (intmax_t)pp->mediasize));
buf = g_read_data(cp, 0, pp->sectorsize, NULL);
if (buf == NULL)
- goto err;
+ goto e2;
header = (struct cloop_header *) buf;
if (strncmp(header->magic, CLOOP_MAGIC_START,
sizeof(CLOOP_MAGIC_START) - 1) != 0) {
- DPRINTF(("%s: no CLOOP magic\n", gp->name));
- goto err;
- }
- if (header->magic[0x0b] != 'V' || header->magic[0x0c] < '2') {
- DPRINTF(("%s: image version too old\n", gp->name));
- goto err;
+ DPRINTF(GUZ_DBG_ERR, ("%s: no CLOOP magic\n", gp->name));
+ goto e3;
}
+ switch (header->magic[CLOOP_OFS_COMPR]) {
+ case CLOOP_COMP_LZMA:
+ case CLOOP_COMP_LZMA_DDP:
+ type = G_ULZMA;
+ if (header->magic[CLOOP_OFS_VERSN] < CLOOP_MINVER_LZMA) {
+ DPRINTF(GUZ_DBG_ERR, ("%s: image version too old\n",
+ gp->name));
+ goto e3;
+ }
+ DPRINTF(GUZ_DBG_INFO, ("%s: GEOM_UZIP_LZMA image found\n",
+ gp->name));
+ break;
+ case CLOOP_COMP_LIBZ:
+ case CLOOP_COMP_LIBZ_DDP:
+ type = G_UZIP;
+ if (header->magic[CLOOP_OFS_VERSN] < CLOOP_MINVER_ZLIB) {
+ DPRINTF(GUZ_DBG_ERR, ("%s: image version too old\n",
+ gp->name));
+ goto e3;
+ }
+ DPRINTF(GUZ_DBG_INFO, ("%s: GEOM_UZIP_ZLIB image found\n",
+ gp->name));
+ break;
+ default:
+ DPRINTF(GUZ_DBG_ERR, ("%s: unsupported image type\n",
+ gp->name));
+ goto e3;
+ }
+
/*
* Initialize softc and read offsets.
*/
@@ -459,7 +729,7 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags)
if (sc->blksz % 512 != 0) {
printf("%s: block size (%u) should be multiple of 512.\n",
gp->name, sc->blksz);
- goto err;
+ goto e4;
}
if (sc->blksz > MAX_BLKSZ) {
printf("%s: block size (%u) should not be larger than %d.\n",
@@ -470,15 +740,17 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags)
total_offsets * sizeof(uint64_t) > pp->mediasize) {
printf("%s: media too small for %u blocks\n",
gp->name, sc->nblocks);
- goto err;
+ goto e4;
}
- sc->offsets = malloc(
- total_offsets * sizeof(uint64_t), M_GEOM_UZIP, M_WAITOK);
+ sc->toc = malloc(total_offsets * sizeof(struct g_uzip_blk),
+ M_GEOM_UZIP, M_WAITOK | M_ZERO);
offsets_read = MIN(total_offsets,
(pp->sectorsize - sizeof(*header)) / sizeof(uint64_t));
- for (i = 0; i < offsets_read; i++)
- sc->offsets[i] = be64toh(((uint64_t *) (header + 1))[i]);
- DPRINTF(("%s: %u offsets in the first sector\n",
+ for (i = 0; i < offsets_read; i++) {
+ sc->toc[i].offset = be64toh(((uint64_t *) (header + 1))[i]);
+ sc->toc[i].blen = BLEN_UNDEF;
+ }
+ DPRINTF(GUZ_DBG_INFO, ("%s: %u offsets in the first sector\n",
gp->name, offsets_read));
for (blk = 1; offsets_read < total_offsets; blk++) {
uint32_t nread;
@@ -487,25 +759,65 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags)
buf = g_read_data(
cp, blk * pp->sectorsize, pp->sectorsize, NULL);
if (buf == NULL)
- goto err;
+ goto e5;
nread = MIN(total_offsets - offsets_read,
pp->sectorsize / sizeof(uint64_t));
- DPRINTF(("%s: %u offsets read from sector %d\n",
+ DPRINTF(GUZ_DBG_TOC, ("%s: %u offsets read from sector %d\n",
gp->name, nread, blk));
for (i = 0; i < nread; i++) {
- sc->offsets[offsets_read + i] =
+ sc->toc[offsets_read + i].offset =
be64toh(((uint64_t *) buf)[i]);
+ sc->toc[offsets_read + i].blen = BLEN_UNDEF;
}
offsets_read += nread;
}
free(buf, M_GEOM);
- DPRINTF(("%s: done reading offsets\n", gp->name));
+ buf = NULL;
+ offsets_read -= 1;
+ DPRINTF(GUZ_DBG_INFO, ("%s: done reading %u block offsets from %u "
+ "sectors\n", gp->name, offsets_read, blk));
+ if (sc->nblocks != offsets_read) {
+ DPRINTF(GUZ_DBG_ERR, ("%s: read %s offsets than expected "
+ "blocks\n", gp->name,
+ sc->nblocks < offsets_read ? "more" : "less"));
+ goto e5;
+ }
+
+ if (type == G_UZIP) {
+ sc->dcp = g_uzip_zlib_ctor(sc->blksz);
+ } else {
+ sc->dcp = g_uzip_lzma_ctor(sc->blksz);
+ }
+ if (sc->dcp == NULL) {
+ goto e5;
+ }
+
+ /*
+ * "Fake" last+1 block, to make it easier for the TOC parser to
+ * iterate without making the last element a special case.
+ */
+ sc->toc[sc->nblocks].offset = pp->mediasize;
+ /* Massage TOC (table of contents), make sure it is sound */
+ if (g_uzip_parse_toc(sc, pp, gp) != 0) {
+ DPRINTF(GUZ_DBG_ERR, ("%s: TOC error\n", gp->name));
+ goto e6;
+ }
mtx_init(&sc->last_mtx, "geom_uzip cache", NULL, MTX_DEF);
+ mtx_init(&sc->queue_mtx, "geom_uzip wrkthread", NULL, MTX_DEF);
+ bioq_init(&sc->bio_queue);
sc->last_blk = -1;
sc->last_buf = malloc(sc->blksz, M_GEOM_UZIP, M_WAITOK);
sc->req_total = 0;
sc->req_cached = 0;
+ sc->uzip_do = &g_uzip_do;
+
+ error = kproc_create(g_uzip_wrkthr, sc, &sc->procp, 0, 0, "%s",
+ gp->name);
+ if (error != 0) {
+ goto e7;
+ }
+
g_topology_lock();
pp2 = g_new_providerf(gp, "%s", gp->name);
pp2->sectorsize = 512;
@@ -515,22 +827,31 @@ g_uzip_taste(struct g_class *mp, struct g_provider *pp, int flags)
g_error_provider(pp2, 0);
g_access(cp, -1, 0, 0);
- DPRINTF(("%s: taste ok (%d, %jd), (%d, %d), %x\n",
- gp->name,
- pp2->sectorsize, (intmax_t)pp2->mediasize,
+ DPRINTF(GUZ_DBG_INFO, ("%s: taste ok (%d, %jd), (%d, %d), %x\n",
+ gp->name, pp2->sectorsize, (intmax_t)pp2->mediasize,
pp2->stripeoffset, pp2->stripesize, pp2->flags));
- DPRINTF(("%s: %u x %u blocks\n", gp->name, sc->nblocks, sc->blksz));
+ DPRINTF(GUZ_DBG_INFO, ("%s: %u x %u blocks\n", gp->name, sc->nblocks,
+ sc->blksz));
return (gp);
-err:
- g_topology_lock();
- g_access(cp, -1, 0, 0);
- if (buf != NULL)
+e7:
+ free(sc->last_buf, M_GEOM);
+ mtx_destroy(&sc->queue_mtx);
+ mtx_destroy(&sc->last_mtx);
+e6:
+ sc->dcp->free(sc->dcp);
+e5:
+ free(sc->toc, M_GEOM);
+e4:
+ free(gp->softc, M_GEOM_UZIP);
+e3:
+ if (buf != NULL) {
free(buf, M_GEOM);
- if (gp->softc != NULL) {
- g_uzip_softc_free(gp->softc, NULL);
- gp->softc = NULL;
}
+e2:
+ g_topology_lock();
+ g_access(cp, -1, 0, 0);
+e1:
g_detach(cp);
g_destroy_consumer(cp);
g_destroy_geom(gp);
@@ -547,7 +868,8 @@ g_uzip_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
g_topology_assert();
if (gp->softc == NULL) {
- DPRINTF(("%s(%s): gp->softc == NULL\n", __func__, gp->name));
+ DPRINTF(GUZ_DBG_ERR, ("%s(%s): gp->softc == NULL\n", __func__,
+ gp->name));
return (ENXIO);
}
diff --git a/sys/geom/uzip/g_uzip.h b/sys/geom/uzip/g_uzip.h
new file mode 100644
index 0000000..6decc41
--- /dev/null
+++ b/sys/geom/uzip/g_uzip.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2004 Max Khon
+ * Copyright (c) 2014 Juniper Networks, Inc.
+ * Copyright (c) 2006-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+#ifndef __GEOM_G_UZIP_H__
+#define __GEOM_G_UZIP_H__
+
+MALLOC_DECLARE(M_GEOM_UZIP);
+
+#define DEFINE_RAW_METHOD(func, rval, args...) typedef rval (*func##_t)(args)
+
+#endif /* __GEOM_G_UZIP_H__ */
diff --git a/sys/geom/uzip/g_uzip_cloop.h b/sys/geom/uzip/g_uzip_cloop.h
new file mode 100644
index 0000000..219a7b6
--- /dev/null
+++ b/sys/geom/uzip/g_uzip_cloop.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+/* CLOOP format and related constants */
+
+/*
+ * Integer values (block size, number of blocks, offsets)
+ * are stored in big-endian (network) order on disk.
+ */
+
+#define CLOOP_MAGIC_LEN 128
+#define CLOOP_OFS_COMPR 0x0b
+#define CLOOP_OFS_VERSN (CLOOP_OFS_COMPR + 1)
+
+#define CLOOP_MAJVER_2 '2'
+#define CLOOP_MAJVER_3 '3'
+
+#define CLOOP_COMP_LIBZ 'V'
+#define CLOOP_COMP_LIBZ_DDP 'v'
+#define CLOOP_COMP_LZMA 'L'
+#define CLOOP_COMP_LZMA_DDP 'l'
+
+#define CLOOP_MINVER_LZMA CLOOP_MAJVER_3
+#define CLOOP_MINVER_ZLIB CLOOP_MAJVER_2
+
+struct cloop_header {
+ char magic[CLOOP_MAGIC_LEN]; /* cloop magic */
+ uint32_t blksz; /* block size */
+ uint32_t nblocks; /* number of blocks */
+};
diff --git a/sys/geom/uzip/g_uzip_dapi.h b/sys/geom/uzip/g_uzip_dapi.h
new file mode 100644
index 0000000..8c7b3e8
--- /dev/null
+++ b/sys/geom/uzip/g_uzip_dapi.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2006-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+struct g_uzip_dapi;
+
+DEFINE_RAW_METHOD(g_uzip_dapi_decompress, int, struct g_uzip_dapi *,
+ const char *, void *, size_t, void *);
+DEFINE_RAW_METHOD(g_uzip_dapi_free, void, struct g_uzip_dapi *);
+DEFINE_RAW_METHOD(g_uzip_dapi_rewind, int, struct g_uzip_dapi *, const char *);
+
+struct g_uzip_dapi {
+ g_uzip_dapi_decompress_t decompress;
+ g_uzip_dapi_free_t free;
+ g_uzip_dapi_rewind_t rewind;
+ void *pvt;
+ int max_blen;
+};
diff --git a/sys/geom/uzip/g_uzip_lzma.c b/sys/geom/uzip/g_uzip_lzma.c
new file mode 100644
index 0000000..9efb087
--- /dev/null
+++ b/sys/geom/uzip/g_uzip_lzma.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2004 Max Khon
+ * Copyright (c) 2014 Juniper Networks, Inc.
+ * Copyright (c) 2006-2016 Maxim Sobolev <sobomax@FreeBSD.org>
+ * Copyright (c) 2010-2012 Aleksandr Rybalko
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+
+#include <contrib/xz-embedded/linux/include/linux/xz.h>
+
+#include <geom/uzip/g_uzip.h>
+#include <geom/uzip/g_uzip_dapi.h>
+#include <geom/uzip/g_uzip_lzma.h>
+
+struct g_uzip_lzma {
+ struct g_uzip_dapi pub;
+ uint32_t blksz;
+ /* XZ decoder structs */
+ struct xz_buf b;
+ struct xz_dec *s;
+};
+
+static int g_uzip_lzma_nop(struct g_uzip_dapi *, const char *);
+
+static void
+g_uzip_lzma_free(struct g_uzip_dapi *lzpp)
+{
+ struct g_uzip_lzma *lzp;
+
+ lzp = (struct g_uzip_lzma *)lzpp->pvt;
+ if (lzp->s != NULL) {
+ xz_dec_end(lzp->s);
+ lzp->s = NULL;
+ }
+
+ free(lzp, M_GEOM_UZIP);
+}
+
+static int
+g_uzip_lzma_decompress(struct g_uzip_dapi *lzpp, const char *gp_name,
+ void *ibp, size_t ilen, void *obp)
+{
+ struct g_uzip_lzma *lzp;
+ int err;
+
+ lzp = (struct g_uzip_lzma *)lzpp->pvt;
+
+ lzp->b.in = ibp;
+ lzp->b.out = obp;
+ lzp->b.in_pos = lzp->b.out_pos = 0;
+ lzp->b.in_size = ilen;
+ lzp->b.out_size = lzp->blksz;
+ err = (xz_dec_run(lzp->s, &lzp->b) != XZ_STREAM_END) ? 1 : 0;
+ /* TODO decoder recovery, if needed */
+ if (err != 0) {
+ printf("%s: ibp=%p, obp=%p, in_pos=%jd, out_pos=%jd, "
+ "in_size=%jd, out_size=%jd\n", __func__, ibp, obp,
+ (intmax_t)lzp->b.in_pos, (intmax_t)lzp->b.out_pos,
+ (intmax_t)lzp->b.in_size, (intmax_t)lzp->b.out_size);
+ }
+
+ return (err);
+}
+
+static int
+LZ4_compressBound(int isize)
+{
+
+ return (isize + (isize / 255) + 16);
+}
+
+struct g_uzip_dapi *
+g_uzip_lzma_ctor(uint32_t blksz)
+{
+ struct g_uzip_lzma *lzp;
+
+ lzp = malloc(sizeof(struct g_uzip_lzma), M_GEOM_UZIP, M_WAITOK);
+ xz_crc32_init();
+ lzp->s = xz_dec_init(XZ_SINGLE, 0);
+ if (lzp->s == NULL) {
+ goto e1;
+ }
+ lzp->blksz = blksz;
+ lzp->pub.max_blen = LZ4_compressBound(blksz);
+ lzp->pub.decompress = &g_uzip_lzma_decompress;
+ lzp->pub.free = &g_uzip_lzma_free;
+ lzp->pub.rewind = &g_uzip_lzma_nop;
+ lzp->pub.pvt = lzp;
+ return (&lzp->pub);
+e1:
+ free(lzp, M_GEOM_UZIP);
+ return (NULL);
+}
+
+static int
+g_uzip_lzma_nop(struct g_uzip_dapi *zpp, const char *gp_name)
+{
+
+ return (0);
+}
diff --git a/sys/geom/uzip/g_uzip_lzma.h b/sys/geom/uzip/g_uzip_lzma.h
new file mode 100644
index 0000000..f9f8a27
--- /dev/null
+++ b/sys/geom/uzip/g_uzip_lzma.h
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2004 Max Khon
+ * Copyright (c) 2014 Juniper Networks, Inc.
+ * Copyright (c) 2006-2016 Maxim Sobolev <sobomax@FreeBSD.org>
+ * Copyright (c) 2010-2012 Aleksandr Rybalko
+ * 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$
+ */
+
+struct g_uzip_dapi *g_uzip_lzma_ctor(uint32_t);
diff --git a/sys/geom/uzip/g_uzip_softc.h b/sys/geom/uzip/g_uzip_softc.h
new file mode 100644
index 0000000..1d12ac0
--- /dev/null
+++ b/sys/geom/uzip/g_uzip_softc.h
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2004 Max Khon
+ * Copyright (c) 2014 Juniper Networks, Inc.
+ * Copyright (c) 2006-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+struct g_uzip_softc;
+struct bio;
+
+DEFINE_RAW_METHOD(g_uzip_do, void, struct g_uzip_softc *, struct bio *);
+
+struct g_uzip_softc {
+ uint32_t blksz; /* block size */
+ uint32_t nblocks; /* number of blocks */
+ struct g_uzip_blk *toc; /* table of contents */
+
+ struct mtx last_mtx;
+ uint32_t last_blk; /* last blk no */
+ char *last_buf; /* last blk data */
+ int req_total; /* total requests */
+ int req_cached; /* cached requests */
+ struct g_uzip_dapi *dcp; /* decompressor instance */
+
+ g_uzip_do_t uzip_do;
+
+ struct proc *procp;
+ struct bio_queue_head bio_queue;
+ struct mtx queue_mtx;
+ unsigned wrkthr_flags;
+#define GUZ_SHUTDOWN (0x1 << 0)
+#define GUZ_EXITING (0x1 << 1)
+};
diff --git a/sys/geom/uzip/g_uzip_wrkthr.c b/sys/geom/uzip/g_uzip_wrkthr.c
new file mode 100644
index 0000000..2afe075
--- /dev/null
+++ b/sys/geom/uzip/g_uzip_wrkthr.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2006-2016 Maxim Sobolev <sobomax@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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/bio.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+
+#include <geom/uzip/g_uzip.h>
+#include <geom/uzip/g_uzip_softc.h>
+#include <geom/uzip/g_uzip_wrkthr.h>
+
+void
+g_uzip_wrkthr(void *arg)
+{
+ struct g_uzip_softc *sc;
+ struct bio *bp;
+
+ sc = (struct g_uzip_softc *)arg;
+ thread_lock(curthread);
+ sched_prio(curthread, PRIBIO);
+ thread_unlock(curthread);
+
+ for (;;) {
+ mtx_lock(&sc->queue_mtx);
+ if (sc->wrkthr_flags & GUZ_SHUTDOWN) {
+ sc->wrkthr_flags |= GUZ_EXITING;
+ mtx_unlock(&sc->queue_mtx);
+ kproc_exit(0);
+ }
+ bp = bioq_takefirst(&sc->bio_queue);
+ if (!bp) {
+ msleep(sc, &sc->queue_mtx, PRIBIO | PDROP,
+ "wrkwait", 0);
+ continue;
+ }
+ mtx_unlock(&sc->queue_mtx);
+ sc->uzip_do(sc, bp);
+ }
+}
diff --git a/sys/geom/uzip/g_uzip_wrkthr.h b/sys/geom/uzip/g_uzip_wrkthr.h
new file mode 100644
index 0000000..8492378
--- /dev/null
+++ b/sys/geom/uzip/g_uzip_wrkthr.h
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2006-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+void g_uzip_wrkthr(void *);
+
diff --git a/sys/geom/uzip/g_uzip_zlib.c b/sys/geom/uzip/g_uzip_zlib.c
new file mode 100644
index 0000000..de50392
--- /dev/null
+++ b/sys/geom/uzip/g_uzip_zlib.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2004 Max Khon
+ * Copyright (c) 2014 Juniper Networks, Inc.
+ * Copyright (c) 2006-2016 Maxim Sobolev <sobomax@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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <net/zlib.h>
+
+#include <geom/uzip/g_uzip.h>
+#include <geom/uzip/g_uzip_dapi.h>
+#include <geom/uzip/g_uzip_zlib.h>
+
+struct g_uzip_zlib {
+ uint32_t blksz;
+ struct g_uzip_dapi pub;
+ /* Zlib decoder structs */
+ z_stream zs;
+};
+
+static void *z_alloc(void *, u_int, u_int);
+static void z_free(void *, void *);
+static int g_uzip_zlib_rewind(struct g_uzip_dapi *, const char *);
+
+static void
+g_uzip_zlib_free(struct g_uzip_dapi *zpp)
+{
+ struct g_uzip_zlib *zp;
+
+ zp = (struct g_uzip_zlib *)zpp->pvt;
+ inflateEnd(&zp->zs);
+ free(zp, M_GEOM_UZIP);
+}
+
+static int
+g_uzip_zlib_decompress(struct g_uzip_dapi *zpp, const char *gp_name, void *ibp,
+ size_t ilen, void *obp)
+{
+ int err;
+ struct g_uzip_zlib *zp;
+
+ zp = (struct g_uzip_zlib *)zpp->pvt;
+
+ zp->zs.next_in = ibp;
+ zp->zs.avail_in = ilen;
+ zp->zs.next_out = obp;
+ zp->zs.avail_out = zp->blksz;
+
+ err = (inflate(&zp->zs, Z_FINISH) != Z_STREAM_END) ? 1 : 0;
+ if (err != 0) {
+ printf("%s: UZIP(zlib) inflate() failed\n", gp_name);
+ }
+ return (err);
+}
+
+static int
+g_uzip_zlib_rewind(struct g_uzip_dapi *zpp, const char *gp_name)
+{
+ int err;
+ struct g_uzip_zlib *zp;
+
+ zp = (struct g_uzip_zlib *)zpp->pvt;
+
+ err = 0;
+ if (inflateReset(&zp->zs) != Z_OK) {
+ printf("%s: UZIP(zlib) decoder reset failed\n", gp_name);
+ err = 1;
+ }
+ return (err);
+}
+
+static int
+z_compressBound(int len)
+{
+
+ return (len + (len >> 12) + (len >> 14) + 11);
+}
+
+struct g_uzip_dapi *
+g_uzip_zlib_ctor(uint32_t blksz)
+{
+ struct g_uzip_zlib *zp;
+
+ zp = malloc(sizeof(struct g_uzip_zlib), M_GEOM_UZIP, M_WAITOK);
+ zp->zs.zalloc = z_alloc;
+ zp->zs.zfree = z_free;
+ if (inflateInit(&zp->zs) != Z_OK) {
+ goto e1;
+ }
+ zp->blksz = blksz;
+ zp->pub.max_blen = z_compressBound(blksz);
+ zp->pub.decompress = &g_uzip_zlib_decompress;
+ zp->pub.free = &g_uzip_zlib_free;
+ zp->pub.rewind = &g_uzip_zlib_rewind;
+ zp->pub.pvt = (void *)zp;
+ return (&zp->pub);
+e1:
+ free(zp, M_GEOM_UZIP);
+ return (NULL);
+}
+
+static void *
+z_alloc(void *nil, u_int type, u_int size)
+{
+ void *ptr;
+
+ ptr = malloc(type * size, M_GEOM_UZIP, M_NOWAIT);
+
+ return (ptr);
+}
+
+static void
+z_free(void *nil, void *ptr)
+{
+
+ free(ptr, M_GEOM_UZIP);
+}
diff --git a/sys/geom/uzip/g_uzip_zlib.h b/sys/geom/uzip/g_uzip_zlib.h
new file mode 100644
index 0000000..7a767b8
--- /dev/null
+++ b/sys/geom/uzip/g_uzip_zlib.h
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2004 Max Khon
+ * Copyright (c) 2014 Juniper Networks, Inc.
+ * Copyright (c) 2006-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+struct g_geom;
+
+struct g_uzip_dapi *g_uzip_zlib_ctor(uint32_t);
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index a0c4fa4..e4bf40b 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1083,8 +1083,11 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int wa
findkn:
if (fops->f_isfd) {
KASSERT(td != NULL, ("td is NULL"));
- error = fget(td, kev->ident,
- cap_rights_init(&rights, CAP_EVENT), &fp);
+ if (kev->ident > INT_MAX)
+ error = EBADF;
+ else
+ error = fget(td, kev->ident,
+ cap_rights_init(&rights, CAP_EVENT), &fp);
if (error)
goto done;
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index 6ae0fb1..7f481b3 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -32,6 +32,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_ktrace.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/limits.h>
@@ -54,6 +56,9 @@ __FBSDID("$FreeBSD$");
#include <sys/timers.h>
#include <sys/timetc.h>
#include <sys/vnode.h>
+#ifdef KTRACE
+#include <sys/ktrace.h>
+#endif
#include <vm/vm.h>
#include <vm/vm_extern.h>
@@ -699,6 +704,10 @@ kern_getitimer(struct thread *td, u_int which, struct itimerval *aitv)
*aitv = p->p_stats->p_timer[which];
PROC_ITIMUNLOCK(p);
}
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_STRUCT))
+ ktritimerval(aitv);
+#endif
return (0);
}
@@ -740,6 +749,10 @@ kern_setitimer(struct thread *td, u_int which, struct itimerval *aitv,
if (which > ITIMER_PROF)
return (EINVAL);
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_STRUCT))
+ ktritimerval(aitv);
+#endif
if (itimerfix(&aitv->it_value) ||
aitv->it_value.tv_sec > INT32_MAX / 2)
return (EINVAL);
@@ -784,6 +797,10 @@ kern_setitimer(struct thread *td, u_int which, struct itimerval *aitv,
p->p_stats->p_timer[which] = *aitv;
PROC_ITIMUNLOCK(p);
}
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_STRUCT))
+ ktritimerval(oitv);
+#endif
return (0);
}
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index bbfe321..96e0181 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -389,7 +389,6 @@ ptrace_vm_entry(struct thread *td, struct proc *p, struct ptrace_vm_entry *pve)
} while (0);
vm_map_unlock_read(map);
- vmspace_free(vm);
pve->pve_fsid = VNOVAL;
pve->pve_fileid = VNOVAL;
@@ -434,6 +433,7 @@ ptrace_vm_entry(struct thread *td, struct proc *p, struct ptrace_vm_entry *pve)
free(freepath, M_TEMP);
}
}
+ vmspace_free(vm);
if (error == 0)
CTR3(KTR_PTRACE, "PT_VM_ENTRY: pid %d, entry %d, start %p",
p->p_pid, pve->pve_entry, pve->pve_start);
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index e0e7205..5c48b81 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -2934,7 +2934,13 @@ vgonel(struct vnode *vp)
TAILQ_EMPTY(&vp->v_bufobj.bo_clean.bv_hd) &&
vp->v_bufobj.bo_clean.bv_cnt == 0,
("vp %p bufobj not invalidated", vp));
- vp->v_bufobj.bo_flag |= BO_DEAD;
+
+ /*
+ * For VMIO bufobj, BO_DEAD is set in vm_object_terminate()
+ * after the object's page queue is flushed.
+ */
+ if (vp->v_bufobj.bo_object == NULL)
+ vp->v_bufobj.bo_flag |= BO_DEAD;
BO_UNLOCK(&vp->v_bufobj);
/*
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index bef5829..f2ddf66 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -1269,6 +1269,8 @@ kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
case S_IFCHR:
case S_IFBLK:
error = priv_check(td, PRIV_VFS_MKNOD_DEV);
+ if (error == 0 && dev == VNOVAL)
+ error = EINVAL;
break;
case S_IFMT:
error = priv_check(td, PRIV_VFS_MKNOD_BAD);
diff --git a/sys/modules/geom/geom_uzip/Makefile b/sys/modules/geom/geom_uzip/Makefile
index 3efeb80..bd6ecd3 100644
--- a/sys/modules/geom/geom_uzip/Makefile
+++ b/sys/modules/geom/geom_uzip/Makefile
@@ -3,7 +3,22 @@
.PATH: ${.CURDIR}/../../../geom/uzip ${.CURDIR}/../../../net
KMOD= geom_uzip
-SRCS= g_uzip.c
+SRCS= g_uzip.c g_uzip_zlib.c g_uzip_lzma.c g_uzip_wrkthr.c
+SRCS+= g_uzip.h g_uzip_dapi.h g_uzip_lzma.h g_uzip_zlib.h g_uzip_softc.h \
+ g_uzip_wrkthr.h
#CFLAGS= -g -DINVARIANT_SUPPORT -DINVARIANTS
+SRCS+= opt_geom.h
+
+.PATH: ${.CURDIR}/../../../contrib/xz-embedded/freebsd/ \
+ ${.CURDIR}/../../../contrib/xz-embedded/linux/lib/xz/ \
+ ${.CURDIR}/../../../contrib/xz-embedded/linux/include/linux/ \
+ ${.CURDIR}/../../../net
+
+CFLAGS+= -I${.CURDIR}/../../../contrib/xz-embedded/freebsd \
+ -I${.CURDIR}/../../../contrib/xz-embedded/linux/lib/xz/
+SRCS+= xz_crc32.c xz_dec_bcj.c xz_dec_lzma2.c xz_dec_stream.c \
+ xz_malloc.c
+SRCS+= xz.h xz_config.h xz_lzma2.h xz_malloc.h xz_private.h xz_stream.h
+
.include <bsd.kmod.mk>
diff --git a/sys/nlm/nlm_prot_impl.c b/sys/nlm/nlm_prot_impl.c
index 74fae87..915538b 100644
--- a/sys/nlm/nlm_prot_impl.c
+++ b/sys/nlm/nlm_prot_impl.c
@@ -1439,6 +1439,12 @@ nlm_register_services(SVCPOOL *pool, int addr_count, char **addrs)
return (EINVAL);
}
+ if (addr_count < 0 || addr_count > 256 ) {
+ NLM_ERR("NLM: too many service addresses (%d) given, "
+ "max 256 - can't start server\n", addr_count);
+ return (EINVAL);
+ }
+
xprts = malloc(addr_count * sizeof(SVCXPRT *), M_NLM, M_WAITOK|M_ZERO);
for (i = 0; i < version_count; i++) {
for (j = 0; j < addr_count; j++) {
diff --git a/sys/sys/ktrace.h b/sys/sys/ktrace.h
index e9cfa6e..e63a41a 100644
--- a/sys/sys/ktrace.h
+++ b/sys/sys/ktrace.h
@@ -270,6 +270,8 @@ void ktrcapfail(enum ktr_cap_fail_type, const cap_rights_t *,
const cap_rights_t *);
#define ktrcaprights(s) \
ktrstruct("caprights", (s), sizeof(cap_rights_t))
+#define ktritimerval(s) \
+ ktrstruct("itimerval", (s), sizeof(struct itimerval))
#define ktrsockaddr(s) \
ktrstruct("sockaddr", (s), ((struct sockaddr *)(s))->sa_len)
#define ktrstat(s) \
diff --git a/sys/sys/rman.h b/sys/sys/rman.h
index d98dac7..bb63816 100644
--- a/sys/sys/rman.h
+++ b/sys/sys/rman.h
@@ -117,7 +117,6 @@ TAILQ_HEAD(rman_head, rman);
int rman_activate_resource(struct resource *r);
int rman_adjust_resource(struct resource *r, u_long start, u_long end);
-int rman_await_resource(struct resource *r, int pri, int timo);
int rman_first_free_region(struct rman *rm, u_long *start, u_long *end);
bus_space_handle_t rman_get_bushandle(struct resource *);
bus_space_tag_t rman_get_bustag(struct resource *);
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index d65cda2..909f57f 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -353,6 +353,15 @@ RetryFault:;
KASSERT((fault_flags & VM_FAULT_WIRE) == 0,
("!wired && VM_FAULT_WIRE"));
+ /*
+ * Try to avoid lock contention on the top-level object through
+ * special-case handling of some types of page faults, specifically,
+ * those that are both (1) mapping an existing page from the top-
+ * level object and (2) not having to mark that object as containing
+ * dirty pages. Under these conditions, a read lock on the top-level
+ * object suffices, allowing multiple page faults of a similar type to
+ * run in parallel on the same top-level object.
+ */
if (fs.vp == NULL /* avoid locked vnode leak */ &&
(fault_flags & (VM_FAULT_WIRE | VM_FAULT_DIRTY)) == 0 &&
/* avoid calling vm_object_set_writeable_dirty() */
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
index 5ea59b3..b2a7013 100644
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -737,6 +737,10 @@ vm_object_terminate(vm_object_t object)
vinvalbuf(vp, V_SAVE, 0, 0);
+ BO_LOCK(&vp->v_bufobj);
+ vp->v_bufobj.bo_flag |= BO_DEAD;
+ BO_UNLOCK(&vp->v_bufobj);
+
VM_OBJECT_WLOCK(object);
}
diff --git a/usr.bin/ar/ar.1 b/usr.bin/ar/ar.1
index 079d262..ed8266c 100644
--- a/usr.bin/ar/ar.1
+++ b/usr.bin/ar/ar.1
@@ -23,7 +23,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 24, 2015
+.Dd July 25, 2016
.Dt AR 1
.Os
.Sh NAME
@@ -205,7 +205,12 @@ When used in combination with the
.Fl r
or
.Fl q
-option, insert 0's instead of the real mtime, uid and gid values
+option,
+with the
+.Fl s
+option without other options, or when invoked as
+.Nm ranlib ,
+insert 0's instead of the real mtime, uid and gid values
and 0644 instead of file mode from the members named by arguments
.Ar .
This ensures that checksums on the resulting archives are reproducible
diff --git a/usr.bin/ar/ar.c b/usr.bin/ar/ar.c
index 0c69315..0ab06a0 100644
--- a/usr.bin/ar/ar.c
+++ b/usr.bin/ar/ar.c
@@ -283,7 +283,8 @@ main(int argc, char **argv)
}
/* Set determinstic mode for -D, and by default without -U. */
- if (Dflag || (Uflag == 0 && (bsdar->mode == 'q' || bsdar->mode == 'r')))
+ if (Dflag || (Uflag == 0 && (bsdar->mode == 'q' || bsdar->mode == 'r' ||
+ (bsdar->mode == '\0' && bsdar->options & AR_S))))
bsdar->options |= AR_D;
if (bsdar->options & AR_A)
diff --git a/usr.bin/bsdiff/bspatch/bspatch.c b/usr.bin/bsdiff/bspatch/bspatch.c
index d2af3ca..92bc75b 100644
--- a/usr.bin/bsdiff/bspatch/bspatch.c
+++ b/usr.bin/bsdiff/bspatch/bspatch.c
@@ -155,6 +155,10 @@ int main(int argc,char * argv[])
};
/* Sanity-check */
+ if ((ctrl[0] < 0) || (ctrl[1] < 0))
+ errx(1,"Corrupt patch\n");
+
+ /* Sanity-check */
if(newpos+ctrl[0]>newsize)
errx(1,"Corrupt patch\n");
diff --git a/usr.bin/gcore/elfcore.c b/usr.bin/gcore/elfcore.c
index 5303f66..ad7f052 100644
--- a/usr.bin/gcore/elfcore.c
+++ b/usr.bin/gcore/elfcore.c
@@ -123,6 +123,7 @@ static vm_map_entry_t readmap(pid_t);
static void *procstat_sysctl(void *, int, size_t, size_t *sizep);
static pid_t g_pid; /* Pid being dumped, global for elf_detach */
+static int g_status; /* proc status after ptrace attach */
static int
elf_ident(int efd, pid_t pid __unused, char *binfile __unused)
@@ -156,9 +157,18 @@ elf_ident(int efd, pid_t pid __unused, char *binfile __unused)
static void
elf_detach(void)
{
+ int sig;
- if (g_pid != 0)
- ptrace(PT_DETACH, g_pid, (caddr_t)1, 0);
+ if (g_pid != 0) {
+ /*
+ * Forward any pending signals. SIGSTOP is generated by ptrace
+ * itself, so ignore it.
+ */
+ sig = WIFSTOPPED(g_status) ? WSTOPSIG(g_status) : 0;
+ if (sig == SIGSTOP)
+ sig = 0;
+ ptrace(PT_DETACH, g_pid, (caddr_t)1, sig);
+ }
}
/*
@@ -184,7 +194,7 @@ elf_coredump(int efd __unused, int fd, pid_t pid)
ptrace(PT_ATTACH, pid, NULL, 0);
if (errno)
err(1, "PT_ATTACH");
- if (waitpid(pid, NULL, 0) == -1)
+ if (waitpid(pid, &g_status, 0) == -1)
err(1, "waitpid");
/* Get the program's memory map. */
diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c
index f7d7bba..9ac8b5b 100644
--- a/usr.bin/kdump/kdump.c
+++ b/usr.bin/kdump/kdump.c
@@ -106,6 +106,7 @@ void ktruser_malloc(void *);
void ktruser_rtld(int, void *);
void ktruser(int, void *);
void ktrcaprights(cap_rights_t *);
+void ktritimerval(struct itimerval *it);
void ktrsockaddr(struct sockaddr *);
void ktrstat(struct stat *);
void ktrstruct(char *, size_t);
@@ -1616,6 +1617,24 @@ ktrcaprights(cap_rights_t *rightsp)
printf("\n");
}
+static void
+ktrtimeval(struct timeval *tv)
+{
+
+ printf("{%ld, %ld}", (long)tv->tv_sec, tv->tv_usec);
+}
+
+void
+ktritimerval(struct itimerval *it)
+{
+
+ printf("itimerval { .interval = ");
+ ktrtimeval(&it->it_interval);
+ printf(", .value = ");
+ ktrtimeval(&it->it_value);
+ printf(" }\n");
+}
+
void
ktrsockaddr(struct sockaddr *sa)
{
@@ -1799,6 +1818,7 @@ ktrstruct(char *buf, size_t buflen)
size_t namelen, datalen;
int i;
cap_rights_t rights;
+ struct itimerval it;
struct stat sb;
struct sockaddr_storage ss;
@@ -1823,6 +1843,11 @@ ktrstruct(char *buf, size_t buflen)
goto invalid;
memcpy(&rights, data, datalen);
ktrcaprights(&rights);
+ } else if (strcmp(name, "itimerval") == 0) {
+ if (datalen != sizeof(struct itimerval))
+ goto invalid;
+ memcpy(&it, data, datalen);
+ ktritimerval(&it);
} else if (strcmp(name, "stat") == 0) {
if (datalen != sizeof(struct stat))
goto invalid;
diff --git a/usr.bin/mail/collect.c b/usr.bin/mail/collect.c
index ef72e9f..ff55e07 100644
--- a/usr.bin/mail/collect.c
+++ b/usr.bin/mail/collect.c
@@ -339,9 +339,9 @@ cont:
int nullfd, tempfd, rc;
char tempname2[PATHSIZE];
- if ((nullfd = open("/dev/null", O_RDONLY, 0))
+ if ((nullfd = open(_PATH_DEVNULL, O_RDONLY, 0))
== -1) {
- warn("/dev/null");
+ warn(_PATH_DEVNULL);
break;
}
diff --git a/usr.bin/mail/quit.c b/usr.bin/mail/quit.c
index a960755..4b9bcda 100644
--- a/usr.bin/mail/quit.c
+++ b/usr.bin/mail/quit.c
@@ -228,7 +228,8 @@ quit(void)
return;
}
(void)Fclose(obuf);
- (void)close(open(mbox, O_CREAT | O_TRUNC | O_WRONLY, 0600));
+ if ((fd = open(mbox, O_CREAT | O_TRUNC | O_WRONLY, 0600)) >= 0)
+ (void)close(fd);
if ((obuf = Fopen(mbox, "r+")) == NULL) {
warn("%s", mbox);
(void)Fclose(ibuf);
diff --git a/usr.bin/mail/v7.local.c b/usr.bin/mail/v7.local.c
index 8fc2f64..0da7b3b 100644
--- a/usr.bin/mail/v7.local.c
+++ b/usr.bin/mail/v7.local.c
@@ -68,9 +68,12 @@ findmail(char *user, char *buf, int buflen)
void
demail(void)
{
+ int fd;
if (value("keep") != NULL || rm(mailname) < 0)
- (void)close(open(mailname, O_CREAT | O_TRUNC | O_WRONLY, 0600));
+ if ((fd = open(mailname, O_CREAT | O_TRUNC | O_WRONLY, 0600)) >=
+ 0)
+ (void)close(fd);
}
/*
diff --git a/usr.bin/mkuzip/Makefile b/usr.bin/mkuzip/Makefile
index c5eac20..7f4a57a 100644
--- a/usr.bin/mkuzip/Makefile
+++ b/usr.bin/mkuzip/Makefile
@@ -2,9 +2,10 @@
PROG= mkuzip
MAN= mkuzip.8
+SRCS= mkuzip.c mkuz_blockcache.c mkuz_lzma.c mkuz_zlib.c mkuz_conveyor.c \
+ mkuz_blk.c mkuz_fqueue.c mkuz_time.c
-DPADD= ${LIBZ}
-LDADD= -lz
-
+DPADD= ${LIBZ} ${LIBMD} ${LIBLZMA} ${LIBPTHREAD}
+LDADD= -lz -lmd -llzma -lpthread
.include <bsd.prog.mk>
diff --git a/usr.bin/mkuzip/mkuz_blk.c b/usr.bin/mkuzip/mkuz_blk.c
new file mode 100644
index 0000000..cfc5273
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_blk.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "mkuzip.h"
+#include "mkuz_blk.h"
+
+struct mkuz_blk *
+mkuz_blk_ctor(size_t blen)
+{
+ struct mkuz_blk *rval;
+
+ rval = mkuz_safe_zmalloc(sizeof(struct mkuz_blk) + blen);
+ rval->alen = blen;
+ rval->br_offset = OFFSET_UNDEF;
+ return (rval);
+}
diff --git a/usr.bin/mkuzip/mkuz_blk.h b/usr.bin/mkuzip/mkuz_blk.h
new file mode 100644
index 0000000..8e80a10c
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_blk.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+#define OFFSET_UNDEF UINT64_MAX
+
+struct mkuz_blk_info {
+ uint64_t offset;
+ size_t len;
+ uint32_t blkno;
+ unsigned char digest[16];
+};
+
+#define MKUZ_BLK_EOF (void *)0x1
+#define MKUZ_BLK_MORE (void *)0x2
+
+struct mkuz_blk {
+ struct mkuz_blk_info info;
+ size_t alen;
+ uint64_t br_offset;
+ unsigned char data[];
+};
+
+struct mkuz_blk *mkuz_blk_ctor(size_t);
diff --git a/usr.bin/mkuzip/mkuz_blk_chain.h b/usr.bin/mkuzip/mkuz_blk_chain.h
new file mode 100644
index 0000000..556803f
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_blk_chain.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+struct mkuz_blk;
+struct mkuz_bchain_link;
+
+struct mkuz_bchain_link {
+ struct mkuz_blk *this;
+ struct mkuz_bchain_link *prev;
+};
diff --git a/usr.bin/mkuzip/mkuz_blockcache.c b/usr.bin/mkuzip/mkuz_blockcache.c
new file mode 100644
index 0000000..a369eeb
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_blockcache.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016 Maxim Sobolev <sobomax@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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if defined(MKUZ_DEBUG)
+# include <assert.h>
+# include <stdio.h>
+#endif
+
+#include "mkuz_blockcache.h"
+#include "mkuz_blk.h"
+
+struct mkuz_blkcache_itm {
+ struct mkuz_blk_info hit;
+ struct mkuz_blkcache_itm *next;
+};
+
+static struct mkuz_blkcache {
+ struct mkuz_blkcache_itm first[256];
+} blkcache;
+
+static int
+verify_match(int fd, const struct mkuz_blk *cbp, struct mkuz_blkcache_itm *bcep)
+{
+ void *vbuf;
+ ssize_t rlen;
+ int rval;
+
+ rval = -1;
+ vbuf = malloc(cbp->info.len);
+ if (vbuf == NULL) {
+ goto e0;
+ }
+ if (lseek(fd, bcep->hit.offset, SEEK_SET) < 0) {
+ goto e1;
+ }
+ rlen = read(fd, vbuf, cbp->info.len);
+ if (rlen < 0 || (unsigned)rlen != cbp->info.len) {
+ goto e2;
+ }
+ rval = (memcmp(cbp->data, vbuf, cbp->info.len) == 0) ? 1 : 0;
+e2:
+ lseek(fd, cbp->info.offset, SEEK_SET);
+e1:
+ free(vbuf);
+e0:
+ return (rval);
+}
+
+#define I2J(x) ((intmax_t)(x))
+#define U2J(x) ((uintmax_t)(x))
+
+static unsigned char
+digest_fold(const unsigned char *mdigest)
+{
+ int i;
+ unsigned char rval;
+
+ rval = mdigest[0];
+ for (i = 1; i < 16; i++) {
+ rval = rval ^ mdigest[i];
+ }
+ return (rval);
+}
+
+struct mkuz_blk_info *
+mkuz_blkcache_regblock(int fd, const struct mkuz_blk *bp)
+{
+ struct mkuz_blkcache_itm *bcep;
+ int rval;
+ unsigned char h;
+
+#if defined(MKUZ_DEBUG)
+ assert((unsigned)lseek(fd, 0, SEEK_CUR) == bp->info.offset);
+#endif
+ h = digest_fold(bp->info.digest);
+ if (blkcache.first[h].hit.len == 0) {
+ bcep = &blkcache.first[h];
+ } else {
+ for (bcep = &blkcache.first[h]; bcep != NULL; bcep = bcep->next) {
+ if (bcep->hit.len != bp->info.len)
+ continue;
+ if (memcmp(bp->info.digest, bcep->hit.digest,
+ sizeof(bp->info.digest)) == 0) {
+ break;
+ }
+ }
+ if (bcep != NULL) {
+ rval = verify_match(fd, bp, bcep);
+ if (rval == 1) {
+#if defined(MKUZ_DEBUG)
+ fprintf(stderr, "cache hit %jd, %jd, %jd, %jd\n",
+ I2J(bcep->hit.blkno), I2J(bcep->hit.offset),
+ I2J(bp->info.offset), I2J(bp->info.len));
+#endif
+ return (&bcep->hit);
+ }
+ if (rval == 0) {
+#if defined(MKUZ_DEBUG)
+ fprintf(stderr, "block MD5 collision, you should try lottery, "
+ "man!\n");
+#endif
+ return (NULL);
+ }
+ warn("verify_match");
+ return (NULL);
+ }
+ bcep = malloc(sizeof(struct mkuz_blkcache_itm));
+ if (bcep == NULL)
+ return (NULL);
+ memset(bcep, '\0', sizeof(struct mkuz_blkcache_itm));
+ bcep->next = blkcache.first[h].next;
+ blkcache.first[h].next = bcep;
+ }
+ bcep->hit = bp->info;
+ return (NULL);
+}
diff --git a/usr.bin/mkuzip/mkuz_blockcache.h b/usr.bin/mkuzip/mkuz_blockcache.h
new file mode 100644
index 0000000..58eaea0
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_blockcache.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+struct mkuz_blk;
+
+struct mkuz_blk_info *mkuz_blkcache_regblock(int, const struct mkuz_blk *);
diff --git a/usr.bin/mkuzip/mkuz_cfg.h b/usr.bin/mkuzip/mkuz_cfg.h
new file mode 100644
index 0000000..fc183e3
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_cfg.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+struct mkuz_conveyor;
+
+struct mkuz_cfg {
+ int fdr;
+ int fdw;
+ int verbose;
+ int no_zcomp;
+ int en_dedup;
+ int nworkers;
+ int blksz;
+ const struct mkuz_format *handler;
+};
diff --git a/usr.bin/mkuzip/mkuz_cloop.h b/usr.bin/mkuzip/mkuz_cloop.h
new file mode 100644
index 0000000..4ed7c50
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_cloop.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+/* CLOOP format and related constants */
+
+/*
+ * Integer values (block size, number of blocks, offsets)
+ * are stored in big-endian (network) order on disk.
+ */
+
+#define CLOOP_MAGIC_LEN 128
+#define CLOOP_OFS_COMPR 0x0b
+#define CLOOP_OFS_VERSN (CLOOP_OFS_COMPR + 1)
+
+#define CLOOP_MAJVER_2 '2'
+#define CLOOP_MAJVER_3 '3'
+
+#define CLOOP_COMP_LIBZ 'V'
+#define CLOOP_COMP_LZMA 'L'
+
+struct cloop_header {
+ char magic[CLOOP_MAGIC_LEN]; /* cloop magic */
+ uint32_t blksz; /* block size */
+ uint32_t nblocks; /* number of blocks */
+};
diff --git a/usr.bin/mkuzip/mkuz_conveyor.c b/usr.bin/mkuzip/mkuz_conveyor.c
new file mode 100644
index 0000000..856d445
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_conveyor.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <err.h>
+#include <inttypes.h>
+#include <md5.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#if defined(MKUZ_DEBUG)
+# include <stdio.h>
+#endif
+
+#include "mkuz_conveyor.h"
+#include "mkuz_cfg.h"
+#include "mkuzip.h"
+#include "mkuz_format.h"
+#include "mkuz_blk.h"
+#include "mkuz_fqueue.h"
+#include "mkuz_blk_chain.h"
+
+static void compute_digest(struct mkuz_blk *);
+
+struct cw_args {
+ struct mkuz_conveyor *cvp;
+ struct mkuz_cfg *cfp;
+};
+
+static void *
+cworker(void *p)
+{
+ struct cw_args *cwp;
+ struct mkuz_cfg *cfp;
+ struct mkuz_blk *oblk, *iblk;
+ struct mkuz_conveyor *cvp;
+ void *c_ctx;
+
+ cwp = (struct cw_args *)p;
+ cfp = cwp->cfp;
+ cvp = cwp->cvp;
+ free(cwp);
+ c_ctx = cfp->handler->f_init(cfp->blksz);
+ for (;;) {
+ iblk = mkuz_fqueue_deq(cvp->wrk_queue);
+ if (iblk == MKUZ_BLK_EOF) {
+ /* Let other threads to see the EOF block */
+ mkuz_fqueue_enq(cvp->wrk_queue, iblk);
+ break;
+ }
+ if (cfp->no_zcomp == 0 &&
+ mkuz_memvcmp(iblk->data, '\0', iblk->info.len) != 0) {
+ /* All zeroes block */
+ oblk = mkuz_blk_ctor(0);
+ } else {
+ oblk = cfp->handler->f_compress(c_ctx, iblk);
+ if (cfp->en_dedup != 0) {
+ compute_digest(oblk);
+ }
+ }
+ oblk->info.blkno = iblk->info.blkno;
+ mkuz_fqueue_enq(cvp->results, oblk);
+ free(iblk);
+ }
+ return (NULL);
+}
+
+static void
+compute_digest(struct mkuz_blk *bp)
+{
+ MD5_CTX mcontext;
+
+ MD5Init(&mcontext);
+ MD5Update(&mcontext, bp->data, bp->info.len);
+ MD5Final(bp->info.digest, &mcontext);
+}
+
+struct mkuz_conveyor *
+mkuz_conveyor_ctor(struct mkuz_cfg *cfp)
+{
+ struct mkuz_conveyor *cp;
+ struct cw_args *cwp;
+ int i, r;
+
+ cp = mkuz_safe_zmalloc(sizeof(struct mkuz_conveyor) +
+ (sizeof(pthread_t) * cfp->nworkers));
+
+ cp->wrk_queue = mkuz_fqueue_ctor(1);
+ cp->results = mkuz_fqueue_ctor(1);
+
+ for (i = 0; i < cfp->nworkers; i++) {
+ cwp = mkuz_safe_zmalloc(sizeof(struct cw_args));
+ cwp->cfp = cfp;
+ cwp->cvp = cp;
+ r = pthread_create(&cp->wthreads[i], NULL, cworker, (void *)cwp);
+ if (r != 0) {
+ errx(1, "mkuz_conveyor_ctor: pthread_create() failed");
+ /* Not reached */
+ }
+ }
+ return (cp);
+}
diff --git a/usr.bin/mkuzip/mkuz_conveyor.h b/usr.bin/mkuzip/mkuz_conveyor.h
new file mode 100644
index 0000000..21328e7
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_conveyor.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+struct mkuz_fifo_queue;
+
+#define ITEMS_PER_WORKER 4
+
+#define MAX_WORKERS_AUTO 24
+
+struct mkuz_conveyor {
+ /*
+ * Work items are places in here, and picked up by workers in a FIFO
+ * fashion.
+ */
+ struct mkuz_fifo_queue *wrk_queue;
+ /*
+ * Results are dropped into this FIFO and consumer is buzzed to pick them
+ * up
+ */
+ struct mkuz_fifo_queue *results;
+
+ pthread_t wthreads[];
+};
+
+struct mkuz_cfg;
+
+struct mkuz_conveyor *mkuz_conveyor_ctor(struct mkuz_cfg *);
diff --git a/usr.bin/mkuzip/mkuz_format.h b/usr.bin/mkuzip/mkuz_format.h
new file mode 100644
index 0000000..817c012
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_format.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+DEFINE_RAW_METHOD(f_init, void *, uint32_t);
+DEFINE_RAW_METHOD(f_compress, struct mkuz_blk *, void *, const struct mkuz_blk *);
+
+struct mkuz_format {
+ const char *magic;
+ const char *default_sufx;
+ f_init_t f_init;
+ f_compress_t f_compress;
+};
diff --git a/usr.bin/mkuzip/mkuz_fqueue.c b/usr.bin/mkuzip/mkuz_fqueue.c
new file mode 100644
index 0000000..db47a05
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_fqueue.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#if defined(MKUZ_DEBUG)
+# include <assert.h>
+#endif
+
+#include "mkuzip.h"
+#include "mkuz_fqueue.h"
+#include "mkuz_conveyor.h"
+#include "mkuz_blk.h"
+#include "mkuz_blk_chain.h"
+
+struct mkuz_fifo_queue *
+mkuz_fqueue_ctor(int wakeup_len)
+{
+ struct mkuz_fifo_queue *fqp;
+
+ fqp = mkuz_safe_zmalloc(sizeof(struct mkuz_fifo_queue));
+ fqp->wakeup_len = wakeup_len;
+ if (pthread_mutex_init(&fqp->mtx, NULL) != 0) {
+ errx(1, "pthread_mutex_init() failed");
+ }
+ if (pthread_cond_init(&fqp->cvar, NULL) != 0) {
+ errx(1, "pthread_cond_init() failed");
+ }
+ return (fqp);
+}
+
+void
+mkuz_fqueue_enq(struct mkuz_fifo_queue *fqp, struct mkuz_blk *bp)
+{
+ struct mkuz_bchain_link *ip;
+
+ ip = mkuz_safe_zmalloc(sizeof(struct mkuz_bchain_link));
+ ip->this = bp;
+
+ pthread_mutex_lock(&fqp->mtx);
+ if (fqp->first != NULL) {
+ fqp->first->prev = ip;
+ } else {
+ fqp->last = ip;
+ }
+ fqp->first = ip;
+ fqp->length += 1;
+ if (fqp->length >= fqp->wakeup_len) {
+ pthread_cond_signal(&fqp->cvar);
+ }
+ pthread_mutex_unlock(&fqp->mtx);
+}
+
+#if defined(NOTYET)
+int
+mkuz_fqueue_enq_all(struct mkuz_fifo_queue *fqp, struct mkuz_bchain_link *cip_f,
+ struct mkuz_bchain_link *cip_l, int clen)
+{
+ int rval;
+
+ pthread_mutex_lock(&fqp->mtx);
+ if (fqp->first != NULL) {
+ fqp->first->prev = cip_l;
+ } else {
+ fqp->last = cip_l;
+ }
+ fqp->first = cip_f;
+ fqp->length += clen;
+ rval = fqp->length;
+ if (fqp->length >= fqp->wakeup_len) {
+ pthread_cond_signal(&fqp->cvar);
+ }
+ pthread_mutex_unlock(&fqp->mtx);
+ return (rval);
+}
+#endif
+
+static int
+mkuz_fqueue_check(struct mkuz_fifo_queue *fqp, cmp_cb_t cmp_cb, void *cap)
+{
+ struct mkuz_bchain_link *ip;
+
+ for (ip = fqp->last; ip != NULL; ip = ip->prev) {
+ if (cmp_cb(ip->this, cap)) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+struct mkuz_blk *
+mkuz_fqueue_deq_when(struct mkuz_fifo_queue *fqp, cmp_cb_t cmp_cb, void *cap)
+{
+ struct mkuz_bchain_link *ip, *newlast, *newfirst, *mip;
+ struct mkuz_blk *bp;
+
+ pthread_mutex_lock(&fqp->mtx);
+ while (fqp->last == NULL || !mkuz_fqueue_check(fqp, cmp_cb, cap)) {
+ pthread_cond_wait(&fqp->cvar, &fqp->mtx);
+ }
+ if (cmp_cb(fqp->last->this, cap)) {
+ mip = fqp->last;
+ fqp->last = mip->prev;
+ if (fqp->last == NULL) {
+#if defined(MKUZ_DEBUG)
+ assert(fqp->length == 1);
+#endif
+ fqp->first = NULL;
+ }
+ } else {
+#if defined(MKUZ_DEBUG)
+ assert(fqp->length > 1);
+#endif
+ newfirst = newlast = fqp->last;
+ mip = NULL;
+ for (ip = fqp->last->prev; ip != NULL; ip = ip->prev) {
+ if (cmp_cb(ip->this, cap)) {
+ mip = ip;
+ continue;
+ }
+ newfirst->prev = ip;
+ newfirst = ip;
+ }
+ newfirst->prev = NULL;
+ fqp->first = newfirst;
+ fqp->last = newlast;
+ }
+ fqp->length -= 1;
+ pthread_mutex_unlock(&fqp->mtx);
+ bp = mip->this;
+ free(mip);
+
+ return bp;
+}
+
+struct mkuz_blk *
+mkuz_fqueue_deq(struct mkuz_fifo_queue *fqp)
+{
+ struct mkuz_bchain_link *ip;
+ struct mkuz_blk *bp;
+
+ pthread_mutex_lock(&fqp->mtx);
+ while (fqp->last == NULL) {
+ pthread_cond_wait(&fqp->cvar, &fqp->mtx);
+ }
+#if defined(MKUZ_DEBUG)
+ assert(fqp->length > 0);
+#endif
+ ip = fqp->last;
+ fqp->last = ip->prev;
+ if (fqp->last == NULL) {
+#if defined(MKUZ_DEBUG)
+ assert(fqp->length == 1);
+#endif
+ fqp->first = NULL;
+ }
+ fqp->length -= 1;
+ pthread_mutex_unlock(&fqp->mtx);
+ bp = ip->this;
+ free(ip);
+
+ return bp;
+}
+
+#if defined(NOTYET)
+struct mkuz_bchain_link *
+mkuz_fqueue_deq_all(struct mkuz_fifo_queue *fqp, int *rclen)
+{
+ struct mkuz_bchain_link *rchain;
+
+ pthread_mutex_lock(&fqp->mtx);
+ while (fqp->last == NULL) {
+ pthread_cond_wait(&fqp->cvar, &fqp->mtx);
+ }
+#if defined(MKUZ_DEBUG)
+ assert(fqp->length > 0);
+#endif
+ rchain = fqp->last;
+ fqp->first = fqp->last = NULL;
+ *rclen = fqp->length;
+ fqp->length = 0;
+ pthread_mutex_unlock(&fqp->mtx);
+ return (rchain);
+}
+#endif
diff --git a/usr.bin/mkuzip/mkuz_fqueue.h b/usr.bin/mkuzip/mkuz_fqueue.h
new file mode 100644
index 0000000..4b34216f
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_fqueue.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+struct mkuz_fifo_queue {
+ pthread_mutex_t mtx;
+ pthread_cond_t cvar;
+ struct mkuz_bchain_link *first;
+ struct mkuz_bchain_link *last;
+ int length;
+ int wakeup_len;
+};
+
+struct mkuz_blk;
+struct mkuz_bchain_link;
+
+DEFINE_RAW_METHOD(cmp_cb, int, const struct mkuz_blk *, void *);
+
+struct mkuz_fifo_queue *mkuz_fqueue_ctor(int);
+void mkuz_fqueue_enq(struct mkuz_fifo_queue *, struct mkuz_blk *);
+struct mkuz_blk *mkuz_fqueue_deq(struct mkuz_fifo_queue *);
+struct mkuz_blk *mkuz_fqueue_deq_when(struct mkuz_fifo_queue *, cmp_cb_t, void *);
+#if defined(NOTYET)
+struct mkuz_bchain_link *mkuz_fqueue_deq_all(struct mkuz_fifo_queue *, int *);
+int mkuz_fqueue_enq_all(struct mkuz_fifo_queue *, struct mkuz_bchain_link *,
+ struct mkuz_bchain_link *, int);
+#endif
diff --git a/usr.bin/mkuzip/mkuz_lzma.c b/usr.bin/mkuzip/mkuz_lzma.c
new file mode 100644
index 0000000..8810d2e
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_lzma.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@FreeBSD.org>
+ * Copyright (c) 2011 Aleksandr Rybalko <ray@ddteam.net>
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <err.h>
+#include <stdint.h>
+
+#include <lzma.h>
+
+#include "mkuzip.h"
+#include "mkuz_lzma.h"
+#include "mkuz_blk.h"
+
+#define USED_BLOCKSIZE DEV_BSIZE
+
+struct mkuz_lzma {
+ lzma_filter filters[2];
+ lzma_options_lzma opt_lzma;
+ lzma_stream strm;
+ uint32_t blksz;
+};
+
+static const lzma_stream lzma_stream_init = LZMA_STREAM_INIT;
+
+void *
+mkuz_lzma_init(uint32_t blksz)
+{
+ struct mkuz_lzma *ulp;
+
+ if (blksz % USED_BLOCKSIZE != 0) {
+ errx(1, "cluster size should be multiple of %d",
+ USED_BLOCKSIZE);
+ /* Not reached */
+ }
+ if (blksz > MAXPHYS) {
+ errx(1, "cluster size is too large");
+ /* Not reached */
+ }
+ ulp = mkuz_safe_zmalloc(sizeof(struct mkuz_lzma));
+
+ /* Init lzma encoder */
+ ulp->strm = lzma_stream_init;
+ if (lzma_lzma_preset(&ulp->opt_lzma, LZMA_PRESET_DEFAULT))
+ errx(1, "Error loading LZMA preset");
+
+ ulp->filters[0].id = LZMA_FILTER_LZMA2;
+ ulp->filters[0].options = &ulp->opt_lzma;
+ ulp->filters[1].id = LZMA_VLI_UNKNOWN;
+
+ ulp->blksz = blksz;
+
+ return (void *)ulp;
+}
+
+struct mkuz_blk *
+mkuz_lzma_compress(void *p, const struct mkuz_blk *iblk)
+{
+ lzma_ret ret;
+ struct mkuz_blk *rval;
+ struct mkuz_lzma *ulp;
+
+ ulp = (struct mkuz_lzma *)p;
+
+ rval = mkuz_blk_ctor(ulp->blksz * 2);
+
+ ret = lzma_stream_encoder(&ulp->strm, ulp->filters, LZMA_CHECK_CRC32);
+ if (ret != LZMA_OK) {
+ if (ret == LZMA_MEMLIMIT_ERROR)
+ errx(1, "can't compress data: LZMA_MEMLIMIT_ERROR");
+
+ errx(1, "can't compress data: LZMA compressor ERROR");
+ }
+
+ ulp->strm.next_in = iblk->data;
+ ulp->strm.avail_in = ulp->blksz;
+ ulp->strm.next_out = rval->data;
+ ulp->strm.avail_out = rval->alen;
+
+ ret = lzma_code(&ulp->strm, LZMA_FINISH);
+
+ if (ret != LZMA_STREAM_END) {
+ /* Error */
+ errx(1, "lzma_code FINISH failed, code=%d, pos(in=%zd, "
+ "out=%zd)", ret, (ulp->blksz - ulp->strm.avail_in),
+ (ulp->blksz * 2 - ulp->strm.avail_out));
+ }
+
+#if 0
+ lzma_end(&ulp->strm);
+#endif
+
+ rval->info.len = rval->alen - ulp->strm.avail_out;
+ return (rval);
+}
diff --git a/usr.bin/mkuzip/mkuz_lzma.h b/usr.bin/mkuzip/mkuz_lzma.h
new file mode 100644
index 0000000..bba4542
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_lzma.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@FreeBSD.org>
+ * Copyright (c) 2011 Aleksandr Rybalko <ray@ddteam.net>
+ * 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$
+ */
+
+/* Format L3.0, since we move to XZ API */
+#define CLOOP_MAGIC_LZMA \
+ "#!/bin/sh\n" \
+ "#L3.0\n" \
+ "n=uncompress\n" \
+ "m=geom_$n\n" \
+ "(kldstat -m $m 2>&-||kldload $m)>&-&&" \
+ "mount_cd9660 /dev/`mdconfig -af $0`.$n $1\n" \
+ "exit $?\n"
+#define DEFAULT_SUFX_LZMA ".ulzma"
+
+void *mkuz_lzma_init(uint32_t);
+struct mkuz_blk *mkuz_lzma_compress(void *, const struct mkuz_blk *);
diff --git a/usr.bin/mkuzip/mkuz_time.c b/usr.bin/mkuzip/mkuz_time.c
new file mode 100644
index 0000000..a221957
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_time.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <math.h>
+#include <stdint.h>
+#include <time.h>
+
+#include "mkuz_time.h"
+
+double
+getdtime(void)
+{
+ struct timespec tp;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1)
+ return (-1);
+
+ return timespec2dtime(&tp);
+}
diff --git a/usr.bin/mkuzip/mkuz_time.h b/usr.bin/mkuzip/mkuz_time.h
new file mode 100644
index 0000000..670eec2
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_time.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _RTPP_TIME_H_
+#define _RTPP_TIME_H_
+
+#define SEC(x) ((x)->tv_sec)
+#define NSEC(x) ((x)->tv_nsec)
+
+#define timespec2dtime(s) ((double)SEC(s) + \
+ (double)NSEC(s) / 1000000000.0)
+
+/* Function prototypes */
+double getdtime(void);
+
+#endif
diff --git a/usr.bin/mkuzip/mkuz_zlib.c b/usr.bin/mkuzip/mkuz_zlib.c
new file mode 100644
index 0000000..4b191f9
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_zlib.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <err.h>
+#include <stdint.h>
+
+#include <zlib.h>
+
+#include "mkuzip.h"
+#include "mkuz_zlib.h"
+#include "mkuz_blk.h"
+
+struct mkuz_zlib {
+ uLongf oblen;
+ uint32_t blksz;
+};
+
+void *
+mkuz_zlib_init(uint32_t blksz)
+{
+ struct mkuz_zlib *zp;
+
+ if (blksz % DEV_BSIZE != 0) {
+ errx(1, "cluster size should be multiple of %d",
+ DEV_BSIZE);
+ /* Not reached */
+ }
+ if (compressBound(blksz) > MAXPHYS) {
+ errx(1, "cluster size is too large");
+ /* Not reached */
+ }
+ zp = mkuz_safe_zmalloc(sizeof(struct mkuz_zlib));
+ zp->oblen = compressBound(blksz);
+ zp->blksz = blksz;
+
+ return (void *)zp;
+}
+
+struct mkuz_blk *
+mkuz_zlib_compress(void *p, const struct mkuz_blk *iblk)
+{
+ uLongf destlen_z;
+ struct mkuz_blk *rval;
+ struct mkuz_zlib *zp;
+
+ zp = (struct mkuz_zlib *)p;
+
+ rval = mkuz_blk_ctor(zp->oblen);
+
+ destlen_z = rval->alen;
+ if (compress2(rval->data, &destlen_z, iblk->data, zp->blksz,
+ Z_BEST_COMPRESSION) != Z_OK) {
+ errx(1, "can't compress data: compress2() "
+ "failed");
+ /* Not reached */
+ }
+
+ rval->info.len = (uint32_t)destlen_z;
+ return (rval);
+}
diff --git a/usr.bin/mkuzip/mkuz_zlib.h b/usr.bin/mkuzip/mkuz_zlib.h
new file mode 100644
index 0000000..55e57a6
--- /dev/null
+++ b/usr.bin/mkuzip/mkuz_zlib.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+#define DEFAULT_SUFX_ZLIB ".uzip"
+
+#define CLOOP_MAGIC_ZLIB "#!/bin/sh\n#V2.0 Format\n" \
+ "(kldstat -qm g_uzip||kldload geom_uzip)>&-&&" \
+ "mount_cd9660 /dev/`mdconfig -af $0`.uzip $1\nexit $?\n"
+
+void *mkuz_zlib_init(uint32_t);
+struct mkuz_blk *mkuz_zlib_compress(void *, const struct mkuz_blk *);
diff --git a/usr.bin/mkuzip/mkuzip.8 b/usr.bin/mkuzip/mkuzip.8
index e6aeb4b..6920e1b 100644
--- a/usr.bin/mkuzip/mkuzip.8
+++ b/usr.bin/mkuzip/mkuzip.8
@@ -1,9 +1,27 @@
-.\" ----------------------------------------------------------------------------
-.\" "THE BEER-WARE LICENSE" (Revision 42):
-.\" <sobomax@FreeBSD.org> wrote this file. As long as you retain this notice you
-.\" can do whatever you want with this stuff. If we meet some day, and you think
-.\" this stuff is worth it, you can buy me a beer in return. Maxim Sobolev
-.\" ----------------------------------------------------------------------------
+.\"-
+.\" Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
.\"
.\" $FreeBSD$
.\"
@@ -20,6 +38,7 @@ class
.Op Fl v
.Op Fl o Ar outfile
.Op Fl s Ar cluster_size
+.Op Fl j Ar compression_jobs
.Ar infile
.Sh DESCRIPTION
The
@@ -39,7 +58,9 @@ works in two phases:
An
.Ar infile
image is split into clusters; each cluster is compressed using
-.Xr zlib 3 .
+.Xr zlib 3
+or
+.Xr lzma 3 .
.It
The resulting set of compressed clusters along with headers that allow
locating each individual cluster is written to the output file.
@@ -51,7 +72,23 @@ The options are:
Name of the output file
.Ar outfile .
The default is to use the input name with the suffix
-.Pa .uzip .
+.Pa .uzip
+for the
+.Xr zlib 3
+compression or
+.Pa .ulzma
+for the
+.Xr lzma 3 .
+.It Fl L
+Use
+.Xr lzma 3
+compression algorithm instead of the default
+.Xr zlib 3 .
+The
+.Xr lzma 3
+provides noticeable better compression levels on the same data set
+at the expense of much slower compression speed (10-20x) and somewhat slower
+decompression (2-3x).
.It Fl s Ar cluster_size
Split the image into clusters of
.Ar cluster_size
@@ -61,6 +98,39 @@ The
should be a multiple of 512 bytes.
.It Fl v
Display verbose messages.
+.It Fl Z
+Disable zero-blocks detection and elimination.
+When this option is set, the
+.Nm
+would compress empty blocks (i.e. clusters that consist of only zero bytes)
+just as it would any other block.
+When the option is not set, the
+.Nm
+detects such blocks and skips them from the output.
+Setting
+.Fl Z
+results is slight increase of compressed image size, typically less than 0.1%
+of a final size of the compressed image.
+.It Fl d
+Enable de-duplication.
+When the option is enabled the
+.Nm
+detects identical blocks in the input and replaces each subsequent occurence
+of such block with pointer to the very first one in the output.
+Setting this option results is moderate decrease of compressed image size,
+typically around 3-5% of a final size of the compressed image.
+.It Fl S
+Print summary about the compression ratio as well as output
+file size after file has been processed.
+.It Fl j Ar compression_jobs
+Specify the number of compression jobs that
+.Nm
+runs in parallel to speed up compression.
+When option is not specified the number of jobs set to be equal
+to the value of
+.Va hw.ncpu
+.Xr sysctl 8
+variable.
.El
.Sh NOTES
The compression ratio largely depends on the cluster size used.
@@ -92,11 +162,20 @@ disk device using
and automatically mount it using
.Xr mount_cd9660 8
on the mount point provided as the first argument to the script.
+.Pp
+The de-duplication is a
+.Fx
+specific feature and while it does not require any changes to on-disk
+compressed image format, however it did require some matching changes to the
+.Xr geom_uzip 4
+to handle resulting images correctly.
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr gzip 1 ,
+.Xr xz 1 ,
.Xr zlib 3 ,
+.Xr lzma 3 ,
.Xr geom 4 ,
.Xr geom_uzip 4 ,
.Xr md 4 ,
diff --git a/usr.bin/mkuzip/mkuzip.c b/usr.bin/mkuzip/mkuzip.c
index 08c8ed0..6288f4e 100644
--- a/usr.bin/mkuzip/mkuzip.c
+++ b/usr.bin/mkuzip/mkuzip.c
@@ -1,68 +1,138 @@
/*
- * ----------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * <sobomax@FreeBSD.ORG> wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return. Maxim Sobolev
- * ----------------------------------------------------------------------------
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@FreeBSD.org>
+ * All rights reserved.
*
- * $FreeBSD$
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/types.h>
#include <sys/disk.h>
#include <sys/endian.h>
#include <sys/param.h>
+#include <sys/sysctl.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <netinet/in.h>
-#include <zlib.h>
+#include <assert.h>
+#include <ctype.h>
#include <err.h>
#include <fcntl.h>
+#include <pthread.h>
#include <signal.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#define CLSTSIZE 16384
-#define DEFAULT_SUFX ".uzip"
-
-#define CLOOP_MAGIC_LEN 128
-static char CLOOP_MAGIC_START[] = "#!/bin/sh\n#V2.0 Format\n"
- "(kldstat -qm g_uzip||kldload geom_uzip)>&-&&"
- "mount_cd9660 /dev/`mdconfig -af $0`.uzip $1\nexit $?\n";
-
-static char *readblock(int, char *, u_int32_t);
+#include "mkuzip.h"
+#include "mkuz_cloop.h"
+#include "mkuz_blockcache.h"
+#include "mkuz_zlib.h"
+#include "mkuz_lzma.h"
+#include "mkuz_blk.h"
+#include "mkuz_cfg.h"
+#include "mkuz_conveyor.h"
+#include "mkuz_format.h"
+#include "mkuz_fqueue.h"
+#include "mkuz_time.h"
+
+#define DEFAULT_CLSTSIZE 16384
+
+static struct mkuz_format uzip_fmt = {
+ .magic = CLOOP_MAGIC_ZLIB,
+ .default_sufx = DEFAULT_SUFX_ZLIB,
+ .f_init = &mkuz_zlib_init,
+ .f_compress = &mkuz_zlib_compress
+};
+
+static struct mkuz_format ulzma_fmt = {
+ .magic = CLOOP_MAGIC_LZMA,
+ .default_sufx = DEFAULT_SUFX_LZMA,
+ .f_init = &mkuz_lzma_init,
+ .f_compress = &mkuz_lzma_compress
+};
+
+static struct mkuz_blk *readblock(int, u_int32_t);
static void usage(void);
-static void *safe_malloc(size_t);
static void cleanup(void);
static char *cleanfile = NULL;
+static int
+cmp_blkno(const struct mkuz_blk *bp, void *p)
+{
+ uint32_t *ap;
+
+ ap = (uint32_t *)p;
+
+ return (bp->info.blkno == *ap);
+}
+
int main(int argc, char **argv)
{
- char *iname, *oname, *obuf, *ibuf;
+ struct mkuz_cfg cfs;
+ char *iname, *oname;
uint64_t *toc;
- int fdr, fdw, i, opt, verbose, tmp;
+ int i, io, opt, tmp;
+ struct {
+ int en;
+ FILE *f;
+ } summary;
struct iovec iov[2];
struct stat sb;
- uLongf destlen;
- uint64_t offset;
- struct cloop_header {
- char magic[CLOOP_MAGIC_LEN]; /* cloop magic */
- uint32_t blksz; /* block size */
- uint32_t nblocks; /* number of blocks */
- } hdr;
+ uint64_t offset, last_offset;
+ struct cloop_header hdr;
+ struct mkuz_conveyor *cvp;
+ void *c_ctx;
+ struct mkuz_blk_info *chit;
+ size_t ncpusz, ncpu;
+ double st, et;
+
+ st = getdtime();
+
+ ncpusz = sizeof(size_t);
+ if (sysctlbyname("hw.ncpu", &ncpu, &ncpusz, NULL, 0) < 0) {
+ ncpu = 1;
+ } else if (ncpu > MAX_WORKERS_AUTO) {
+ ncpu = MAX_WORKERS_AUTO;
+ }
memset(&hdr, 0, sizeof(hdr));
- hdr.blksz = CLSTSIZE;
- strcpy(hdr.magic, CLOOP_MAGIC_START);
+ cfs.blksz = DEFAULT_CLSTSIZE;
oname = NULL;
- verbose = 0;
-
- while((opt = getopt(argc, argv, "o:s:v")) != -1) {
+ cfs.verbose = 0;
+ cfs.no_zcomp = 0;
+ cfs.en_dedup = 0;
+ summary.en = 0;
+ summary.f = stderr;
+ cfs.handler = &uzip_fmt;
+ cfs.nworkers = ncpu;
+ struct mkuz_blk *iblk, *oblk;
+
+ while((opt = getopt(argc, argv, "o:s:vZdLSj:")) != -1) {
switch(opt) {
case 'o':
oname = optarg;
@@ -75,20 +145,38 @@ int main(int argc, char **argv)
optarg);
/* Not reached */
}
- if (tmp % DEV_BSIZE != 0) {
- errx(1, "cluster size should be multiple of %d",
- DEV_BSIZE);
- /* Not reached */
- }
- if (compressBound(tmp) > MAXPHYS) {
- errx(1, "cluster size is too large");
- /* Not reached */
- }
- hdr.blksz = tmp;
+ cfs.blksz = tmp;
break;
case 'v':
- verbose = 1;
+ cfs.verbose = 1;
+ break;
+
+ case 'Z':
+ cfs.no_zcomp = 1;
+ break;
+
+ case 'd':
+ cfs.en_dedup = 1;
+ break;
+
+ case 'L':
+ cfs.handler = &ulzma_fmt;
+ break;
+
+ case 'S':
+ summary.en = 1;
+ summary.f = stdout;
+ break;
+
+ case 'j':
+ tmp = atoi(optarg);
+ if (tmp <= 0) {
+ errx(1, "invalid number of compression threads"
+ " specified: %s", optarg);
+ /* Not reached */
+ }
+ cfs.nworkers = tmp;
break;
default:
@@ -104,18 +192,25 @@ int main(int argc, char **argv)
/* Not reached */
}
+ strcpy(hdr.magic, cfs.handler->magic);
+
+ if (cfs.en_dedup != 0) {
+ hdr.magic[CLOOP_OFS_VERSN] = CLOOP_MAJVER_3;
+ hdr.magic[CLOOP_OFS_COMPR] =
+ tolower(hdr.magic[CLOOP_OFS_COMPR]);
+ }
+
+ c_ctx = cfs.handler->f_init(cfs.blksz);
+
iname = argv[0];
if (oname == NULL) {
- asprintf(&oname, "%s%s", iname, DEFAULT_SUFX);
+ asprintf(&oname, "%s%s", iname, cfs.handler->default_sufx);
if (oname == NULL) {
err(1, "can't allocate memory");
/* Not reached */
}
}
- obuf = safe_malloc(compressBound(hdr.blksz));
- ibuf = safe_malloc(hdr.blksz);
-
signal(SIGHUP, exit);
signal(SIGINT, exit);
signal(SIGTERM, exit);
@@ -123,19 +218,19 @@ int main(int argc, char **argv)
signal(SIGXFSZ, exit);
atexit(cleanup);
- fdr = open(iname, O_RDONLY);
- if (fdr < 0) {
+ cfs.fdr = open(iname, O_RDONLY);
+ if (cfs.fdr < 0) {
err(1, "open(%s)", iname);
/* Not reached */
}
- if (fstat(fdr, &sb) != 0) {
+ if (fstat(cfs.fdr, &sb) != 0) {
err(1, "fstat(%s)", iname);
/* Not reached */
}
if (S_ISCHR(sb.st_mode)) {
off_t ms;
- if (ioctl(fdr, DIOCGMEDIASIZE, &ms) < 0) {
+ if (ioctl(cfs.fdr, DIOCGMEDIASIZE, &ms) < 0) {
err(1, "ioctl(DIOCGMEDIASIZE)");
/* Not reached */
}
@@ -145,18 +240,18 @@ int main(int argc, char **argv)
iname);
exit(1);
}
- hdr.nblocks = sb.st_size / hdr.blksz;
- if ((sb.st_size % hdr.blksz) != 0) {
- if (verbose != 0)
+ hdr.nblocks = sb.st_size / cfs.blksz;
+ if ((sb.st_size % cfs.blksz) != 0) {
+ if (cfs.verbose != 0)
fprintf(stderr, "file size is not multiple "
- "of %d, padding data\n", hdr.blksz);
+ "of %d, padding data\n", cfs.blksz);
hdr.nblocks++;
}
- toc = safe_malloc((hdr.nblocks + 1) * sizeof(*toc));
+ toc = mkuz_safe_malloc((hdr.nblocks + 1) * sizeof(*toc));
- fdw = open(oname, O_WRONLY | O_TRUNC | O_CREAT,
+ cfs.fdw = open(oname, (cfs.en_dedup ? O_RDWR : O_WRONLY) | O_TRUNC | O_CREAT,
S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
- if (fdw < 0) {
+ if (cfs.fdw < 0) {
err(1, "open(%s)", oname);
/* Not reached */
}
@@ -170,90 +265,156 @@ int main(int argc, char **argv)
offset = iov[0].iov_len + iov[1].iov_len;
/* Reserve space for header */
- lseek(fdw, offset, SEEK_SET);
+ lseek(cfs.fdw, offset, SEEK_SET);
- if (verbose != 0)
+ if (cfs.verbose != 0) {
fprintf(stderr, "data size %ju bytes, number of clusters "
"%u, index length %zu bytes\n", sb.st_size,
hdr.nblocks, iov[1].iov_len);
+ }
- for(i = 0; i == 0 || ibuf != NULL; i++) {
- ibuf = readblock(fdr, ibuf, hdr.blksz);
- if (ibuf != NULL) {
- destlen = compressBound(hdr.blksz);
- if (compress2(obuf, &destlen, ibuf, hdr.blksz,
- Z_BEST_COMPRESSION) != Z_OK) {
- errx(1, "can't compress data: compress2() "
- "failed");
- /* Not reached */
+ cvp = mkuz_conveyor_ctor(&cfs);
+
+ last_offset = 0;
+ iblk = oblk = NULL;
+ for(i = io = 0; iblk != MKUZ_BLK_EOF; i++) {
+ iblk = readblock(cfs.fdr, cfs.blksz);
+ mkuz_fqueue_enq(cvp->wrk_queue, iblk);
+ if (iblk != MKUZ_BLK_EOF &&
+ (i < (cfs.nworkers * ITEMS_PER_WORKER))) {
+ continue;
+ }
+drain:
+ oblk = mkuz_fqueue_deq_when(cvp->results, cmp_blkno, &io);
+ assert(oblk->info.blkno == (unsigned)io);
+ oblk->info.offset = offset;
+ chit = NULL;
+ if (cfs.en_dedup != 0 && oblk->info.len > 0) {
+ chit = mkuz_blkcache_regblock(cfs.fdw, oblk);
+ /*
+ * There should be at least one non-empty block
+ * between us and the backref'ed offset, otherwise
+ * we won't be able to parse that sequence correctly
+ * as it would be indistinguishible from another
+ * empty block.
+ */
+ if (chit != NULL && chit->offset == last_offset) {
+ chit = NULL;
}
- if (verbose != 0)
- fprintf(stderr, "cluster #%d, in %u bytes, "
- "out %lu bytes\n", i, hdr.blksz, destlen);
+ }
+ if (chit != NULL) {
+ toc[io] = htobe64(chit->offset);
+ oblk->info.len = 0;
} else {
- destlen = DEV_BSIZE - (offset % DEV_BSIZE);
- memset(obuf, 0, destlen);
- if (verbose != 0)
- fprintf(stderr, "padding data with %lu bytes so "
- "that file size is multiple of %d\n", destlen,
- DEV_BSIZE);
+ if (oblk->info.len > 0 && write(cfs.fdw, oblk->data,
+ oblk->info.len) < 0) {
+ err(1, "write(%s)", oname);
+ /* Not reached */
+ }
+ toc[io] = htobe64(offset);
+ last_offset = offset;
+ offset += oblk->info.len;
}
- if (write(fdw, obuf, destlen) < 0) {
- err(1, "write(%s)", oname);
- /* Not reached */
+ if (cfs.verbose != 0) {
+ fprintf(stderr, "cluster #%d, in %u bytes, "
+ "out len=%lu offset=%lu", io, cfs.blksz,
+ (u_long)oblk->info.len, (u_long)be64toh(toc[io]));
+ if (chit != NULL) {
+ fprintf(stderr, " (backref'ed to #%d)",
+ chit->blkno);
+ }
+ fprintf(stderr, "\n");
+ }
+ free(oblk);
+ io += 1;
+ if (iblk == MKUZ_BLK_EOF) {
+ if (io < i)
+ goto drain;
+ /* Last block, see if we need to add some padding */
+ if ((offset % DEV_BSIZE) == 0)
+ continue;
+ oblk = mkuz_blk_ctor(DEV_BSIZE - (offset % DEV_BSIZE));
+ oblk->info.blkno = io;
+ oblk->info.len = oblk->alen;
+ if (cfs.verbose != 0) {
+ fprintf(stderr, "padding data with %lu bytes "
+ "so that file size is multiple of %d\n",
+ (u_long)oblk->alen, DEV_BSIZE);
+ }
+ mkuz_fqueue_enq(cvp->results, oblk);
+ goto drain;
}
- toc[i] = htobe64(offset);
- offset += destlen;
}
- close(fdr);
- if (verbose != 0)
- fprintf(stderr, "compressed data to %ju bytes, saved %lld "
- "bytes, %.2f%% decrease.\n", offset, (long long)(sb.st_size - offset),
- 100.0 * (long long)(sb.st_size - offset) / (float)sb.st_size);
+ close(cfs.fdr);
+
+ if (cfs.verbose != 0 || summary.en != 0) {
+ et = getdtime();
+ fprintf(summary.f, "compressed data to %ju bytes, saved %lld "
+ "bytes, %.2f%% decrease, %.2f bytes/sec.\n", offset,
+ (long long)(sb.st_size - offset),
+ 100.0 * (long long)(sb.st_size - offset) /
+ (float)sb.st_size, (float)sb.st_size / (et - st));
+ }
/* Convert to big endian */
- hdr.blksz = htonl(hdr.blksz);
+ hdr.blksz = htonl(cfs.blksz);
hdr.nblocks = htonl(hdr.nblocks);
/* Write headers into pre-allocated space */
- lseek(fdw, 0, SEEK_SET);
- if (writev(fdw, iov, 2) < 0) {
+ lseek(cfs.fdw, 0, SEEK_SET);
+ if (writev(cfs.fdw, iov, 2) < 0) {
err(1, "writev(%s)", oname);
/* Not reached */
}
cleanfile = NULL;
- close(fdw);
+ close(cfs.fdw);
exit(0);
}
-static char *
-readblock(int fd, char *ibuf, u_int32_t clstsize)
+static struct mkuz_blk *
+readblock(int fd, u_int32_t clstsize)
{
int numread;
+ struct mkuz_blk *rval;
+ static int blockcnt;
+ off_t cpos;
- bzero(ibuf, clstsize);
- numread = read(fd, ibuf, clstsize);
+ rval = mkuz_blk_ctor(clstsize);
+
+ rval->info.blkno = blockcnt;
+ blockcnt += 1;
+ cpos = lseek(fd, 0, SEEK_CUR);
+ if (cpos < 0) {
+ err(1, "readblock: lseek() failed");
+ /* Not reached */
+ }
+ rval->info.offset = cpos;
+
+ numread = read(fd, rval->data, clstsize);
if (numread < 0) {
- err(1, "read() failed");
+ err(1, "readblock: read() failed");
/* Not reached */
}
if (numread == 0) {
- return NULL;
+ free(rval);
+ return MKUZ_BLK_EOF;
}
- return ibuf;
+ rval->info.len = numread;
+ return rval;
}
static void
usage(void)
{
- fprintf(stderr, "usage: mkuzip [-v] [-o outfile] [-s cluster_size] infile\n");
+ fprintf(stderr, "usage: mkuzip [-vZdLS] [-o outfile] [-s cluster_size] "
+ "[-j ncompr] infile\n");
exit(1);
}
-static void *
-safe_malloc(size_t size)
+void *
+mkuz_safe_malloc(size_t size)
{
void *retval;
@@ -265,6 +426,16 @@ safe_malloc(size_t size)
return retval;
}
+void *
+mkuz_safe_zmalloc(size_t size)
+{
+ void *retval;
+
+ retval = mkuz_safe_malloc(size);
+ bzero(retval, size);
+ return retval;
+}
+
static void
cleanup(void)
{
@@ -272,3 +443,12 @@ cleanup(void)
if (cleanfile != NULL)
unlink(cleanfile);
}
+
+int
+mkuz_memvcmp(const void *memory, unsigned char val, size_t size)
+{
+ const u_char *mm;
+
+ mm = (const u_char *)memory;
+ return (*mm == val) && memcmp(mm, mm + 1, size - 1) == 0;
+}
diff --git a/usr.bin/mkuzip/mkuzip.h b/usr.bin/mkuzip/mkuzip.h
new file mode 100644
index 0000000..f41507c
--- /dev/null
+++ b/usr.bin/mkuzip/mkuzip.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2004-2016 Maxim Sobolev <sobomax@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.
+ *
+ * $FreeBSD$
+ */
+
+#define DEFINE_RAW_METHOD(func, rval, args...) typedef rval (*func##_t)(args)
+
+void *mkuz_safe_malloc(size_t);
+void *mkuz_safe_zmalloc(size_t);
+int mkuz_memvcmp(const void *, unsigned char, size_t);
diff --git a/usr.bin/sed/process.c b/usr.bin/sed/process.c
index 891a7ce..4945ac6 100644
--- a/usr.bin/sed/process.c
+++ b/usr.bin/sed/process.c
@@ -440,7 +440,7 @@ substitute(struct s_command *cp)
regexec_e(re, ps, REG_NOTBOL, 0, le, psl));
/* Did not find the requested number of matches. */
- if (n > 1)
+ if (n > 0)
return (0);
/* Copy the trailing retained string. */
diff --git a/usr.bin/tr/tr.1 b/usr.bin/tr/tr.1
index 37e68f3..2aee69c 100644
--- a/usr.bin/tr/tr.1
+++ b/usr.bin/tr/tr.1
@@ -334,6 +334,10 @@ should be used instead of explicit character ranges like
and
.Dq Li A-Z .
.Pp
+.Dq Li [=equiv=]
+expression and collation for ranges
+are implemented for single byte locales only.
+.Pp
System V has historically implemented character ranges using the syntax
.Dq Li [c-c]
instead of the
diff --git a/usr.bin/tr/tr.c b/usr.bin/tr/tr.c
index 6eea2cb..d54e74c 100644
--- a/usr.bin/tr/tr.c
+++ b/usr.bin/tr/tr.c
@@ -272,10 +272,11 @@ endloop:
if (Cflag && !iswrune(cnt))
continue;
if (cmap_lookup(map, cnt) == OOBCH) {
- if (next(&s2))
+ if (next(&s2)) {
cmap_add(map, cnt, s2.lastch);
- if (sflag)
- cset_add(squeeze, s2.lastch);
+ if (sflag)
+ cset_add(squeeze, s2.lastch);
+ }
} else
cmap_add(map, cnt, cnt);
if ((s2.state == EOS || s2.state == INFINITE) &&
diff --git a/usr.bin/ul/ul.c b/usr.bin/ul/ul.c
index 7aecf6c..34a86be 100644
--- a/usr.bin/ul/ul.c
+++ b/usr.bin/ul/ul.c
@@ -78,7 +78,9 @@ struct CHAR {
int c_width; /* width or -1 if multi-column char. filler */
} ;
-static struct CHAR obuf[MAXBUF];
+static struct CHAR sobuf[MAXBUF]; /* static output buffer */
+static struct CHAR *obuf = sobuf;
+static int buflen = MAXBUF;
static int col, maxcol;
static int mode;
static int halfpos;
@@ -155,6 +157,9 @@ main(int argc, char **argv)
else
filter(f);
}
+ if (obuf != sobuf) {
+ free(obuf);
+ }
exit(0);
}
@@ -170,128 +175,148 @@ filter(FILE *f)
{
wint_t c;
int i, w;
-
- while ((c = getwc(f)) != WEOF && col < MAXBUF) switch(c) {
-
- case '\b':
- if (col > 0)
- col--;
- continue;
-
- case '\t':
- col = (col+8) & ~07;
- if (col > maxcol)
- maxcol = col;
- continue;
-
- case '\r':
- col = 0;
- continue;
-
- case SO:
- mode |= ALTSET;
- continue;
-
- case SI:
- mode &= ~ALTSET;
- continue;
-
- case IESC:
- switch (c = getwc(f)) {
-
- case HREV:
- if (halfpos == 0) {
- mode |= SUPERSC;
- halfpos--;
- } else if (halfpos > 0) {
- mode &= ~SUBSC;
- halfpos--;
- } else {
- halfpos = 0;
- reverse();
+ int copy;
+
+ copy = 0;
+
+ while ((c = getwc(f)) != WEOF) {
+ if (col == buflen) {
+ if (obuf == sobuf) {
+ obuf = NULL;
+ copy = 1;
+ }
+ obuf = realloc(obuf, sizeof(*obuf) * 2 * buflen);
+ if (obuf == NULL) {
+ obuf = sobuf;
+ break;
+ } else if (copy) {
+ memcpy(obuf, sobuf, sizeof(*obuf) * buflen);
+ copy = 0;
}
+ bzero((char *)(obuf + buflen), sizeof(*obuf) * buflen);
+ buflen *= 2;
+ }
+ switch(c) {
+ case '\b':
+ if (col > 0)
+ col--;
continue;
- case HFWD:
- if (halfpos == 0) {
- mode |= SUBSC;
- halfpos++;
- } else if (halfpos < 0) {
- mode &= ~SUPERSC;
- halfpos++;
- } else {
- halfpos = 0;
- fwd();
- }
+ case '\t':
+ col = (col+8) & ~07;
+ if (col > maxcol)
+ maxcol = col;
continue;
- case FREV:
- reverse();
+ case '\r':
+ col = 0;
continue;
- default:
- errx(1, "unknown escape sequence in input: %o, %o", IESC, c);
- }
- continue;
+ case SO:
+ mode |= ALTSET;
+ continue;
- case '_':
- if (obuf[col].c_char || obuf[col].c_width < 0) {
- while (col > 0 && obuf[col].c_width < 0)
- col--;
- w = obuf[col].c_width;
- for (i = 0; i < w; i++)
- obuf[col++].c_mode |= UNDERL | mode;
+ case SI:
+ mode &= ~ALTSET;
+ continue;
+
+ case IESC:
+ switch (c = getwc(f)) {
+
+ case HREV:
+ if (halfpos == 0) {
+ mode |= SUPERSC;
+ halfpos--;
+ } else if (halfpos > 0) {
+ mode &= ~SUBSC;
+ halfpos--;
+ } else {
+ halfpos = 0;
+ reverse();
+ }
+ continue;
+
+ case HFWD:
+ if (halfpos == 0) {
+ mode |= SUBSC;
+ halfpos++;
+ } else if (halfpos < 0) {
+ mode &= ~SUPERSC;
+ halfpos++;
+ } else {
+ halfpos = 0;
+ fwd();
+ }
+ continue;
+
+ case FREV:
+ reverse();
+ continue;
+
+ default:
+ errx(1, "unknown escape sequence in input: %o, %o", IESC, c);
+ }
+ continue;
+
+ case '_':
+ if (obuf[col].c_char || obuf[col].c_width < 0) {
+ while (col > 0 && obuf[col].c_width < 0)
+ col--;
+ w = obuf[col].c_width;
+ for (i = 0; i < w; i++)
+ obuf[col++].c_mode |= UNDERL | mode;
+ if (col > maxcol)
+ maxcol = col;
+ continue;
+ }
+ obuf[col].c_char = '_';
+ obuf[col].c_width = 1;
+ /* FALLTHROUGH */
+ case ' ':
+ col++;
if (col > maxcol)
maxcol = col;
continue;
- }
- obuf[col].c_char = '_';
- obuf[col].c_width = 1;
- /* FALLTHROUGH */
- case ' ':
- col++;
- if (col > maxcol)
- maxcol = col;
- continue;
- case '\n':
- flushln();
- continue;
+ case '\n':
+ flushln();
+ continue;
- case '\f':
- flushln();
- putwchar('\f');
- continue;
+ case '\f':
+ flushln();
+ putwchar('\f');
+ continue;
- default:
- if ((w = wcwidth(c)) <= 0) /* non printing */
+ default:
+ if ((w = wcwidth(c)) <= 0) /* non printing */
+ continue;
+ if (obuf[col].c_char == '\0') {
+ obuf[col].c_char = c;
+ for (i = 0; i < w; i++)
+ obuf[col + i].c_mode = mode;
+ obuf[col].c_width = w;
+ for (i = 1; i < w; i++)
+ obuf[col + i].c_width = -1;
+ } else if (obuf[col].c_char == '_') {
+ obuf[col].c_char = c;
+ for (i = 0; i < w; i++)
+ obuf[col + i].c_mode |= UNDERL|mode;
+ obuf[col].c_width = w;
+ for (i = 1; i < w; i++)
+ obuf[col + i].c_width = -1;
+ } else if ((wint_t)obuf[col].c_char == c) {
+ for (i = 0; i < w; i++)
+ obuf[col + i].c_mode |= BOLD|mode;
+ } else {
+ w = obuf[col].c_width;
+ for (i = 0; i < w; i++)
+ obuf[col + i].c_mode = mode;
+ }
+ col += w;
+ if (col > maxcol)
+ maxcol = col;
continue;
- if (obuf[col].c_char == '\0') {
- obuf[col].c_char = c;
- for (i = 0; i < w; i++)
- obuf[col + i].c_mode = mode;
- obuf[col].c_width = w;
- for (i = 1; i < w; i++)
- obuf[col + i].c_width = -1;
- } else if (obuf[col].c_char == '_') {
- obuf[col].c_char = c;
- for (i = 0; i < w; i++)
- obuf[col + i].c_mode |= UNDERL|mode;
- obuf[col].c_width = w;
- for (i = 1; i < w; i++)
- obuf[col + i].c_width = -1;
- } else if ((wint_t)obuf[col].c_char == c) {
- for (i = 0; i < w; i++)
- obuf[col + i].c_mode |= BOLD|mode;
- } else {
- w = obuf[col].c_width;
- for (i = 0; i < w; i++)
- obuf[col + i].c_mode = mode;
}
- col += w;
- if (col > maxcol)
- maxcol = col;
- continue;
}
if (ferror(f))
err(1, NULL);
@@ -409,7 +434,7 @@ static void
initbuf(void)
{
- bzero((char *)obuf, sizeof (obuf)); /* depends on NORMAL == 0 */
+ bzero((char *)obuf, buflen * sizeof(*obuf)); /* depends on NORMAL == 0 */
col = 0;
maxcol = 0;
mode &= ALTSET;
diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c
index 738f391..cec2cd7 100644
--- a/usr.sbin/bhyve/pci_ahci.c
+++ b/usr.sbin/bhyve/pci_ahci.c
@@ -788,7 +788,15 @@ next:
done += 8;
if (elen == 0) {
if (done >= len) {
- ahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);
+ if (ncq) {
+ if (first)
+ ahci_write_fis_d2h_ncq(p, slot);
+ ahci_write_fis_sdb(p, slot, cfis,
+ ATA_S_READY | ATA_S_DSC);
+ } else {
+ ahci_write_fis_d2h(p, slot, cfis,
+ ATA_S_READY | ATA_S_DSC);
+ }
p->pending &= ~(1 << slot);
ahci_check_stopped(p);
if (!first)
@@ -1672,7 +1680,7 @@ ahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
case ATA_SEND_FPDMA_QUEUED:
if ((cfis[13] & 0x1f) == ATA_SFPDMA_DSM &&
cfis[17] == 0 && cfis[16] == ATA_DSM_TRIM &&
- cfis[11] == 0 && cfis[13] == 1) {
+ cfis[11] == 0 && cfis[3] == 1) {
ahci_handle_dsm_trim(p, slot, cfis, 0);
break;
}
diff --git a/usr.sbin/pw/rm_r.c b/usr.sbin/pw/rm_r.c
index 172c7b0..45fc5d1 100644
--- a/usr.sbin/pw/rm_r.c
+++ b/usr.sbin/pw/rm_r.c
@@ -50,6 +50,9 @@ rm_r(int rootfd, const char *path, uid_t uid)
path++;
dirfd = openat(rootfd, path, O_DIRECTORY);
+ if (dirfd == -1) {
+ return;
+ }
d = fdopendir(dirfd);
while ((e = readdir(d)) != NULL) {
diff --git a/usr.sbin/pw/tests/pw_userdel.sh b/usr.sbin/pw/tests/pw_userdel.sh
index f608029..d03501a 100755
--- a/usr.sbin/pw/tests/pw_userdel.sh
+++ b/usr.sbin/pw/tests/pw_userdel.sh
@@ -59,9 +59,18 @@ delete_numeric_name_body() {
${PW} userdel -n 4001
}
+atf_test_case home_not_a_dir
+home_not_a_dir_body() {
+ populate_root_etc_skel
+ touch ${HOME}/foo
+ atf_check ${RPW} useradd foo -d /foo
+ atf_check ${RPW} userdel foo -r
+}
+
atf_init_test_cases() {
atf_add_test_case rmuser_seperate_group
atf_add_test_case user_do_not_try_to_delete_root_if_user_unknown
atf_add_test_case delete_files
atf_add_test_case delete_numeric_name
+ atf_add_test_case home_not_a_dir
}
OpenPOWER on IntegriCloud