| Commit message (Collapse) | Author | Age | Files | Lines |
| ... | |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- Fix the NEEDS_CSUM and DATA_VALID checksum flags. The NEEDS_CSUM
checksum is incomplete (partial) so offer a fallback for the driver
to calculate the checksum. Simplify DATA_VALID because we know
the host has validated the checksum.
- Default 4K mbuf clusters for mergeable buffers. May need to
scale this down to 2K clusters in certain configurations such
many queue pairs, big queues (like 4096 in GCP), and low memory.
- Use the MTU when calculated the receive mbuf cluster size
when not doing TSO/LRO. This will need more adjustment once
the MTU feature is supported.
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27906
|
| |
|
|
|
| |
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27905
|
| |
|
|
|
|
|
|
|
|
|
| |
Very basic support to get packets flowing on modern QEMU but still
several conformance issues remain that will be addressed in later
commits.
First of many passes at cleaning up various accumulated cruft
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27904
|
| |
|
|
|
| |
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27903
|
| |
|
|
|
|
|
|
|
|
|
| |
Rework the header file changes from 2cc8a52 to use our
canonical upstream, Linux.
geom_disk already checks DISKFLAG_CANDELETE for BIO_DELETE
so remove an unnecessary check.
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27902
|
| |
|
|
|
| |
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27901
|
| |
|
|
|
| |
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27900
|
| |
|
|
|
| |
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27899
|
| |
|
|
|
| |
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27898
|
| |
|
|
|
|
|
|
|
| |
This only supports the legacy virtqueue format that is now called
"Split Virtqueues". Support for the new "Packed Virtqueues" described
in v1.1 is left for a later date.
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27857
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Use the existing legacy PCI driver as the basis for shared code
between the legacy and modern PCI drivers. The existing virtio_pci
kernel module will contain both the legacy and modern drivers.
Changes to the virtqueue and each device driver (network, block, etc)
for V1 support come in later commits.
Update the MMIO driver to reflect the VirtIO bus method changes, but
the modern compliance can be improved on later.
Note that the modern PCI driver requires bus_map_resource() to be
implemented, which is not the case on all archs.
The hw.virtio.pci.transitional tunable default value is zero so
transitional devices will continue to be driven via the legacy
driver.
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27856
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
And subsequent fix 576b099a.
By adding the mergable header to the vtnet_rx_header structure, the size
was increased by 2 bytes, breaking the alignment of this structure as
described the in preceding comments.
Furthermore, the mergable header does not belong the structure. With the
mergable feature, the header is placed in line with the data, so there is
no need for a separate segment, and misleading to follow the mergable
header with any padding.
The V1 header is effectively identical to mergable header, and the driver
has long supported the mergable feature. Revert this so the later changes
that add V1 support can show how V1 is derived from the existing mergable
buffers support, and to facilitate a later MFC.
Reviewed by: grehan (mentor)
Differential Revision: https://reviews.freebsd.org/D27855
|
| |
|
|
|
|
|
| |
See 3d65fd97e85ab807f3b for a detailed explanation.
PR: 252453
MFC after: 1 week
|
| |
|
|
|
|
|
| |
This is alreaady defined by each architecture as that is the only place
we can know what the correct page shift should be.
Sponsored by: Innovate UK
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
This caused us to write to the low half of the feature word twice, once with
the high bits and once with the low bits. Common legacy device implementations
seem to be fairly lenient about being able to write to the feature bits
multiple times, but Arm's models use a stricter implementation that will ignore
the second write. This fixes using vtnet(4) on those models.
Reported by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Pointy hat: jrtc27
Notes:
svn path=/head/; revision=368761
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Replace MAXPHYS by runtime variable maxphys. It is initialized from
MAXPHYS by default, but can be also adjusted with the tunable kern.maxphys.
Make b_pages[] array in struct buf flexible. Size b_pages[] for buffer
cache buffers exactly to atop(maxbcachebuf) (currently it is sized to
atop(MAXPHYS)), and b_pages[] for pbufs is sized to atop(maxphys) + 1.
The +1 for pbufs allow several pbuf consumers, among them vmapbuf(),
to use unaligned buffers still sized to maxphys, esp. when such
buffers come from userspace (*). Overall, we save significant amount
of otherwise wasted memory in b_pages[] for buffer cache buffers,
while bumping MAXPHYS to desired high value.
Eliminate all direct uses of the MAXPHYS constant in kernel and driver
sources, except a place which initialize maxphys. Some random (and
arguably weird) uses of MAXPHYS, e.g. in linuxolator, are converted
straight. Some drivers, which use MAXPHYS to size embeded structures,
get private MAXPHYS-like constant; their convertion is out of scope
for this work.
Changes to cam/, dev/ahci, dev/ata, dev/mpr, dev/mpt, dev/mvs,
dev/siis, where either submitted by, or based on changes by mav.
Suggested by: mav (*)
Reviewed by: imp, mav, imp, mckusick, scottl (intermediate versions)
Tested by: pho
Sponsored by: The FreeBSD Foundation
Differential revision: https://reviews.freebsd.org/D27225
Notes:
svn path=/head/; revision=368124
|
| |
|
|
| |
Notes:
svn path=/head/; revision=365091
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
PowerPC support was fixed in r357596 by changing PCI bustag to BE as
part of the solution, but this caused regression on mips. This change
implements byte swapping of virtio PCI config area in the driver,
leaving lower layer untouched.
Submittnd by: Fernando Valle <fernando.valle@eldorado.org.br>
Reported by: arichardson
Reviewed by: alfredo, arichardson
Sponsored by: Eldorado Research Institute (eldorado.org.br)
Differential Revision: https://reviews.freebsd.org/D25416
Notes:
svn path=/head/; revision=363646
|
| |
|
|
|
|
|
|
|
|
| |
This register is only defined for the legacy v1 interface so only write
to it when interacting with a legacy device.
Sponsored by: Innovate UK
Notes:
svn path=/head/; revision=363390
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
If the hypervisor advertises support for the DISCARD command then the
guest can perform TRIM commands, freeing space on the backing store.
If VIRTIO_BLK_F_DISCARD is enabled, advertise DISKFLAG_CANDELETE
Tested with FreeBSD guests on bhyve and KVM
Reviewed by: jhb
Tested by: freqlabs
MFC after: 1 month
Relnotes: yes
Sponsored by: Klara Inc.
Differential Revision: https://reviews.freebsd.org/D21708
Notes:
svn path=/head/; revision=363255
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Since the two functions are similar, introduce a common function
(vtnet_rx_vq_process()) to share common code.
This also improves locking, by ensuring vrxs_rescheduled is accessed
under the RXQ lock, and taskqueue_enqueue() is not called under the
lock (therefore avoiding a spurious duplicate lock warning).
Reported by: jrtc27
MFC after: 2 weeks
Notes:
svn path=/head/; revision=362204
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
For legacy devices that don't support MrgRxBuf (such as bhyve pre-r358180),
r361944 failed to update the receive handler to account for the additional
padding introduced by the unused num_buffers field that is now always present
in struct vtnet_rx_header. Thus, calculate the padding dynamically based on
vtnet_hdr_size.
PR: 247242
Reported by: thj
Tested by: thj
Notes:
svn path=/head/; revision=362186
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The nm_register callback needs to call nm_set_native_flags()
or nm_clear_native_flags() once the device has been stopped.
However, in the current implementation this is not true,
as the device is stopped by vtnet_init_locked(). This causes
race conditions where the driver crashes as soon as it
dequeues netmap buffers assuming they are mbufs (or the other
way around).
To fix the issue, we extend vtnet_init_locked() with a second
argument that, if not zero, will set/clear the netmap flags.
This results in a huge simplification of the nm_register
callback itself.
Also, use netmap_reset() to check if a ring is going to be
re-initialized in netmap mode.
MFC after: 1 week
Notes:
svn path=/head/; revision=362183
|
| |
|
|
|
|
|
|
|
|
|
|
| |
This function returns NULL if the ring identified by
queue id and direction is in netmap mode. Otherwise
return the corresponding kring.
Use this function to replace vtnet_netmap_queue_on().
MFC after: 1 week
Notes:
svn path=/head/; revision=362076
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The non-legacy interface always defines num_buffers in the header,
regardless of whether VIRTIO_NET_F_MRG_RXBUF, just leaving it unused. We
also need to ensure our virtqueue doesn't filter out VIRTIO_F_VERSION_1
during negotiation, as it supports non-legacy transports just fine. This
fixes network packet transmission on TinyEMU.
Reviewed by: br, brooks (mentor), jhb (mentor)
Approved by: br, brooks (mentor), jhb (mentor)
Differential Revision: https://reviews.freebsd.org/D25132
Notes:
svn path=/head/; revision=361944
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The feature bits are exposed as a 32-bit register with 2 banks, so we
should negotiate both halves. Notably, VIRTIO_F_VERSION_1 is in the
upper half, and will be used in an upcoming commit.
The PCI bus driver also has this bug, but the legacy BAR layout did not
include selector registers and is rather different from the modern
layout, so it remains solely as legacy.
Reviewed by: br, brooks (mentor), jhb (mentor)
Approved by: br, brooks (mentor), jhb (mentor)
Differential Revision: https://reviews.freebsd.org/D25131
Notes:
svn path=/head/; revision=361943
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The new index tracks the next netmap slot that is going
to be enqueued into the virtqueue. The index is necessary
to prevent the receive VQ and the netmap rx ring from going
out of sync, considering that we never enqueue N slots, but
at most N-1. This change fixes a bug that causes the VQ
and the netmap ring to go out of sync after N-1 packets
have been received.
MFC after: 1 week
Notes:
svn path=/head/; revision=361758
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The netmap_rx_irq() function normally wakes up user-space threads
waiting for more packets. In this case, it is not necessary to
call it under the driver queue lock. However, if the interface is
attached to a VALE switch, netmap_rx_irq() ends up calling rxsync
on the interface (see netmap_bwrap_intr_notify()). Although
concurrent rxsyncs are serialized through the kring lock
(see nm_kr_tryget()), the lock acquire operation is not blocking.
As a result, it may happen that netmap_rx_irq() is called on
an RX ring while another instance is running, causing the
second call to fail, and received packets stall in the receive VQ.
We fix this issue by calling netmap_irx_irq() under the VQ lock.
MFC after: 1 week
Notes:
svn path=/head/; revision=361745
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The netmap_rx_irq() function may return NM_IRQ_RESCHED to inform the
driver that more work is pending, and that netmap expects netmap_rx_irq()
to be called again as soon as possible.
This change implements this behaviour in the vtnet driver.
MFC after: 1 week
Notes:
svn path=/head/; revision=361744
|
| |
|
|
|
|
|
|
|
|
| |
This fixes -Wshift-count-overflow warnings/errors on architectures using
32-bit physical addresses.
Reported by: lwhsu
Notes:
svn path=/head/; revision=360789
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
The bus is independent of the device, so all devices can be attached to
either a PCI bus or an MMIO bus. For example, QEMU's virtio-rng-device
gives the MMIO variant of virtio-rng-pci, and is now detected.
Reviewed by: andrew, br, brooks (mentor)
Approved by: andrew, br, brooks (mentor)
Differential Revision: https://reviews.freebsd.org/D24730
Notes:
svn path=/head/; revision=360723
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The non-legacy virtio MMIO specification drops the use of PFNs and
replaces them with physical addresses. Whilst many implementations are
so-called transitional devices, also implementing the legacy
specification, TinyEMU[1] does not. Device-specific configuration
registers have also changed to being little-endian, and must be accessed
using a single aligned access for registers up to 32 bits, and two
32-bit aligned accesses for 64-bit registers.
[1] https://bellard.org/tinyemu/
Reviewed by: br, brooks (mentor)
Approved by: br, brooks (mentor)
Differential Revision: https://reviews.freebsd.org/D24681
Notes:
svn path=/head/; revision=360722
|
| |
|
|
|
|
|
|
| |
The sbuf API has evolved since 8, as have many others. The other API sweeps
didn't make the changes conditional, so this is now noise.
Notes:
svn path=/head/; revision=358494
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
r357614 added CTLFLAG_NEEDGIANT to make it easier to find nodes that are
still not MPSAFE (or already are but aren’t properly marked).
Use it in preparation for a general review of all nodes.
This is non-functional change that adds annotations to SYSCTL_NODE and
SYSCTL_PROC nodes using one of the soon-to-be-required flags.
Mark all obvious cases as MPSAFE. All entries that haven't been marked
as MPSAFE before are by default marked as NEEDGIANT
Approved by: kib (mentor, blanket)
Commented by: kib, gallatin, melifaro
Differential Revision: https://reviews.freebsd.org/D23718
Notes:
svn path=/head/; revision=358333
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
switch over to opt-in instead of opt-out for epoch.
Instead of IFF_NEEDSEPOCH, provide IFF_KNOWSEPOCH. If driver marks
itself with IFF_KNOWSEPOCH, then ether_input() would not enter epoch
when processing its packets.
Now this will create recursive entrance in epoch in >90% network
drivers, but will guarantee safeness of the transition.
Mark several tested drivers as IFF_KNOWSEPOCH.
Reviewed by: hselasky, jeff, bz, gallatin
Differential Revision: https://reviews.freebsd.org/D23674
Notes:
svn path=/head/; revision=358301
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
When we register an interrupt handler we need to pass the intr_type along in
bus_setup_intr().
The interrupt type matters because it is used to decide if we need to enter
NET_EPOCH. That meant that vtmmio-based if_vtnet did not, which led to panics
with INVARIANTS set.
Sponsored by: Axiado
Notes:
svn path=/head/; revision=358178
|
| |
|
|
|
|
|
|
|
|
| |
incoming packets in taskqueue context.
Reviewed by: hselasky
Differential Revision: https://reviews.freebsd.org/D23518
Notes:
svn path=/head/; revision=357772
|
| |
|
|
|
|
|
|
|
|
|
| |
BIO_READ and BIO_WRITE, we've handled this expanded syntax poorly in
drivers when the driver doesn't support a particular command. Do a
sweep and fix that.
Reported by: imp
Notes:
svn path=/head/; revision=357647
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
In legacy VirtIO drivers, the header must be PCI endianness (little) and the
device-specific region is encoded in the native endian of the guest.
This patch makes the access (read/write) to VirtIO header using the little
endian order. Other read and write access are native endianness. This also
sets the device's IO region as big endian if on big endian machine.
PR: 205178
Submitted by: Andre Silva <afscoelho@gmail.com>
Reported by: Kenneth Salerno <kennethsalerno@yahoo.com>
Reviewed by: bryanv, bdragon, luporl, alfredo
Approved by: jhibbits (mentor)
Differential Revision: https://reviews.freebsd.org/D23401
Notes:
svn path=/head/; revision=357596
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This bus does not really have a concept of the initiator ID, so use
a guaranteed dummy one that won't conflict with any real target.
This change fixes a problem with virtio_scsi on GCE where disks get
sequential target IDs starting from one. If there are seven or more
disks, then a disk with the target ID of seven would not be discovered
by FreeBSD as that ID was reserved as the initiator ID -- see
scsi_scan_bus().
Discussed with: bryanv
MFC after: 2 weeks
Sponsored by: Panzura
Notes:
svn path=/head/; revision=357040
|
| |
|
|
|
|
|
| |
Reported by: rlibby
Notes:
svn path=/head/; revision=356639
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The patch could be simplier, using only the second chunk to
vtnet_rxq_eof(), that passes full mbufs to pfil(9). Packet
filter would m_free() them in case of returning PFIL_DROPPED.
However, we pretend to be a hardware driver, so we first try
to pass a memory buffer via PFIL_MEMPTR feature. This is mostly
done for debugging purposes, so that one can experiment in bhyve
with packet filters utilizing same features as a true driver.
Notes:
svn path=/head/; revision=356613
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Don't wait until the vtnet_debugnet_init() call happens, because at that
point we might already have allocated something from
vtnet_tx_header_zone.
Some systems showed this panic:
vtnet0: link state changed to UP
panic: keg vtnet_tx_hdr initialization after use.
cpuid = 5
time = 1578427700
KDB: stack backtrace:
db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe004db427f0
vpanic() at vpanic+0x17e/frame 0xfffffe004db42850
panic() at panic+0x43/frame 0xfffffe004db428b0
uma_zone_reserve() at uma_zone_reserve+0xf6/frame 0xfffffe004db428f0
vtnet_debugnet_init() at vtnet_debugnet_init+0x77/frame 0xfffffe004db42930
debugnet_any_ifnet_update() at debugnet_any_ifnet_update+0x42/frame 0xfffffe004db42980
do_link_state_change() at do_link_state_change+0x1b3/frame 0xfffffe004db429d0
taskqueue_run_locked() at taskqueue_run_locked+0x178/frame 0xfffffe004db42a30
taskqueue_run() at taskqueue_run+0x4d/frame 0xfffffe004db42a50
ithread_loop() at ithread_loop+0x1d6/frame 0xfffffe004db42ab0
fork_exit() at fork_exit+0x80/frame 0xfffffe004db42af0
fork_trampoline() at fork_trampoline+0xe/frame 0xfffffe004db42af0
--- trap 0, rip = 0, rsp = 0, rbp = 0 ---
KDB: enter: panic
[ thread pid 12 tid 100011 ]
Stopped at kdb_enter+0x37: movq $0,0x1084eb6(%rip)
db>
Reviewed by: cem, markj
Differential Revision: https://reviews.freebsd.org/D23073
Notes:
svn path=/head/; revision=356484
|
| |
|
|
|
|
|
|
|
|
| |
After r356194, source deregistration no longer races with concurrent use.
Reviewed by: bryanv, markm
Differential Revision: https://reviews.freebsd.org/D22490
Notes:
svn path=/head/; revision=356195
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is a 32-bit structure embedded in each vm_page, consisting mostly
of page queue state. The use of a structure makes it easy to store a
snapshot of a page's queue state in a stack variable and use cmpset
loops to update that state without requiring the page lock.
This change merely adds the structure and updates references to atomic
state fields. No functional change intended.
Reviewed by: alc, jeff, kib
Sponsored by: Netflix, Intel
Differential Revision: https://reviews.freebsd.org/D22650
Notes:
svn path=/head/; revision=355586
|
| |
|
|
| |
Notes:
svn path=/head/; revision=353802
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This patch is part of an effort to make bhyve networking (in particular TCP)
faster. The key strategy to enhance TCP throughput is to let the whole packet
datapath work with TSO/LRO packets (up to 64KB each), so that the per-packet
overhead is amortized over a large number of bytes.
This capability is supported in the guest by means of the vtnet(4) driver,
which is able to handle TSO/LRO packets leveraging the virtio-net header
(see struct virtio_net_hdr and struct virtio_net_hdr_mrg_rxbuf).
A bhyve VM exchanges packets with the host through a network backend,
which can be vale(4) or if_tap(4).
While vale(4) supports TSO/LRO packets, if_tap(4) does not.
This patch extends if_tap(4) with the ability to understand the virtio-net
header, so that a tapX interface can process TSO/LRO packets.
A couple of ioctl commands have been added to configure and probe the
virtio-net header. Once the virtio-net header is set, the tapX interface
acquires all the IFCAP capabilities necessary for TSO/LRO.
Reviewed by: kevans
Differential Revision: https://reviews.freebsd.org/D21263
Notes:
svn path=/head/; revision=353741
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Debugnet is a simplistic and specialized panic- or debug-time reliable
datagram transport. It can drive a single connection at a time and is
currently unidirectional (debug/panic machine transmit to remote server
only).
It is mostly a verbatim code lift from netdump(4). Netdump(4) remains
the only consumer (until the rest of this patch series lands).
The INET-specific logic has been extracted somewhat more thoroughly than
previously in netdump(4), into debugnet_inet.c. UDP-layer logic and up, as
much as possible as is protocol-independent, remains in debugnet.c. The
separation is not perfect and future improvement is welcome. Supporting
INET6 is a long-term goal.
Much of the diff is "gratuitous" renaming from 'netdump_' or 'nd_' to
'debugnet_' or 'dn_' -- sorry. I thought keeping the netdump name on the
generic module would be more confusing than the refactoring.
The only functional change here is the mbuf allocation / tracking. Instead
of initiating solely on netdump-configured interface(s) at dumpon(8)
configuration time, we watch for any debugnet-enabled NIC for link
activation and query it for mbuf parameters at that time. If they exceed
the existing high-water mark allocation, we re-allocate and track the new
high-water mark. Otherwise, we leave the pre-panic mbuf allocation alone.
In a future patch in this series, this will allow initiating netdump from
panic ddb(4) without pre-panic configuration.
No other functional change intended.
Reviewed by: markj (earlier version)
Some discussion with: emaste, jhb
Objection from: marius
Differential Revision: https://reviews.freebsd.org/D21421
Notes:
svn path=/head/; revision=353685
|
| |
|
|
| |
Notes:
svn path=/head/; revision=352407
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
- Remove a dead variable from the amd64 pmap_extract_and_hold().
- Fix grammar in the vm_page_wire man page.
Reported by: alc
Reviewed by: alc, kib
Sponsored by: Netflix
Differential Revision: https://reviews.freebsd.org/D21639
Notes:
svn path=/head/; revision=352406
|