diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-08-21 13:47:02 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-09-21 10:29:41 +0200 |
commit | bcdce02d9bc8150e1d191ed5ca9da45b7604964a (patch) | |
tree | 3b2faf509db7672ee1fc98857736470be97e7ed8 /freebsd/sys | |
parent | Update to FreeBSD head 2018-04-01 (diff) | |
download | rtems-libbsd-bcdce02d9bc8150e1d191ed5ca9da45b7604964a.tar.bz2 |
Update to FreeBSD head 2018-06-01
Git mirror commit fb63610a69b0eb7f69a201ba05c4c1a7a2739cf9.
Update #3472.
Diffstat (limited to 'freebsd/sys')
265 files changed, 15112 insertions, 6034 deletions
diff --git a/freebsd/sys/arm/at91/at91_mci.c b/freebsd/sys/arm/at91/at91_mci.c index 6f5ace83..c25983b7 100644 --- a/freebsd/sys/arm/at91/at91_mci.c +++ b/freebsd/sys/arm/at91/at91_mci.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Bernd Walter. All rights reserved. - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * Copyright (c) 2010 Greg Ansley. All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/freebsd/sys/arm/at91/at91_mcireg.h b/freebsd/sys/arm/at91/at91_mcireg.h index eec67857..80acf48d 100644 --- a/freebsd/sys/arm/at91/at91_mcireg.h +++ b/freebsd/sys/arm/at91/at91_mcireg.h @@ -2,7 +2,7 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Berndt Walter. All rights reserved. - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/freebsd/sys/arm/at91/at91_pdcreg.h b/freebsd/sys/arm/at91/at91_pdcreg.h index 88389e00..659804bd 100644 --- a/freebsd/sys/arm/at91/at91_pdcreg.h +++ b/freebsd/sys/arm/at91/at91_pdcreg.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/freebsd/sys/arm/ti/am335x/am335x_prcm.c b/freebsd/sys/arm/ti/am335x/am335x_prcm.c index 83faafbd..eb27555e 100644 --- a/freebsd/sys/arm/ti/am335x/am335x_prcm.c +++ b/freebsd/sys/arm/ti/am335x/am335x_prcm.c @@ -138,6 +138,7 @@ struct am335x_prcm_softc { struct resource * res[2]; bus_space_tag_t bst; bus_space_handle_t bsh; + int attach_done; }; static struct resource_spec am335x_prcm_spec[] = { @@ -426,7 +427,6 @@ static int am335x_prcm_attach(device_t dev) { struct am335x_prcm_softc *sc = device_get_softc(dev); - unsigned int sysclk, fclk; if (am335x_prcm_sc) return (ENXIO); @@ -444,6 +444,24 @@ am335x_prcm_attach(device_t dev) ti_cpu_reset = am335x_prcm_reset; #endif /* __rtems__ */ + return (0); +} + +static void +am335x_prcm_new_pass(device_t dev) +{ + struct am335x_prcm_softc *sc = device_get_softc(dev); + unsigned int sysclk, fclk; + + sc = device_get_softc(dev); + if (sc->attach_done || + bus_current_pass < (BUS_PASS_TIMER + BUS_PASS_ORDER_EARLY)) { + bus_generic_new_pass(dev); + return; + } + + sc->attach_done = 1; + if (am335x_clk_get_sysclk_freq(NULL, &sysclk) != 0) sysclk = 0; if (am335x_clk_get_arm_fclk_freq(NULL, &fclk) != 0) @@ -451,15 +469,24 @@ am335x_prcm_attach(device_t dev) if (sysclk && fclk) device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n", sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000); - else + else { device_printf(dev, "can't read frequencies yet (SCM device not ready?)\n"); + goto fail; + } - return (0); + return; + +fail: + device_detach(dev); + return; } static device_method_t am335x_prcm_methods[] = { DEVMETHOD(device_probe, am335x_prcm_probe), DEVMETHOD(device_attach, am335x_prcm_attach), + + /* Bus interface */ + DEVMETHOD(bus_new_pass, am335x_prcm_new_pass), { 0, 0 } }; @@ -472,7 +499,7 @@ static driver_t am335x_prcm_driver = { static devclass_t am335x_prcm_devclass; EARLY_DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver, - am335x_prcm_devclass, 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_EARLY); + am335x_prcm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(am335x_prcm, 1); MODULE_DEPEND(am335x_prcm, ti_scm, 1, 1, 1); diff --git a/freebsd/sys/arm/ti/ti_hwmods.c b/freebsd/sys/arm/ti/ti_hwmods.c index 0e703472..450679a7 100644 --- a/freebsd/sys/arm/ti/ti_hwmods.c +++ b/freebsd/sys/arm/ti/ti_hwmods.c @@ -112,7 +112,7 @@ ti_hwmods_get_clock(device_t dev) if ((node = ofw_bus_get_node(dev)) == 0) return (INVALID_CLK_IDENT); - if ((len = OF_getprop_alloc(node, "ti,hwmods", 1, (void**)&name)) <= 0) + if ((len = OF_getprop_alloc(node, "ti,hwmods", (void**)&name)) <= 0) return (INVALID_CLK_IDENT); buf = name; @@ -150,7 +150,7 @@ int ti_hwmods_contains(device_t dev, const char *hwmod) if ((node = ofw_bus_get_node(dev)) == 0) return (0); - if ((len = OF_getprop_alloc(node, "ti,hwmods", 1, (void**)&name)) <= 0) + if ((len = OF_getprop_alloc(node, "ti,hwmods", (void**)&name)) <= 0) return (0); buf = name; @@ -184,7 +184,7 @@ ti_hwmods_get_unit(device_t dev, const char *hwmod) if ((node = ofw_bus_get_node(dev)) == 0) return (0); - if ((len = OF_getprop_alloc(node, "ti,hwmods", 1, (void**)&name)) <= 0) + if ((len = OF_getprop_alloc(node, "ti,hwmods", (void**)&name)) <= 0) return (0); buf = name; diff --git a/freebsd/sys/cam/nvme/nvme_all.h b/freebsd/sys/cam/nvme/nvme_all.h index fa229846..e31c1e5e 100644 --- a/freebsd/sys/cam/nvme/nvme_all.h +++ b/freebsd/sys/cam/nvme/nvme_all.h @@ -2,7 +2,6 @@ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2015 Netflix, Inc - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/freebsd/sys/contrib/ck/include/ck_backoff.h b/freebsd/sys/contrib/ck/include/ck_backoff.h new file mode 100644 index 00000000..82a4f215 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_backoff.h @@ -0,0 +1,57 @@ +/* + * Copyright 2009-2015 Samy Al Bahra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_BACKOFF_H +#define CK_BACKOFF_H + +#include <ck_cc.h> +#include <ck_pr.h> + +#ifndef CK_BACKOFF_CEILING +#define CK_BACKOFF_CEILING ((1 << 20) - 1) +#endif + +#define CK_BACKOFF_INITIALIZER (1 << 9) + +typedef unsigned int ck_backoff_t; + +/* + * This is a exponential back-off implementation. + */ +CK_CC_INLINE static void +ck_backoff_eb(unsigned int *c) +{ + unsigned int i, ceiling; + + ceiling = *c; + for (i = 0; i < ceiling; i++) + ck_pr_barrier(); + + *c = ceiling <<= ceiling < CK_BACKOFF_CEILING; + return; +} + +#endif /* CK_BACKOFF_H */ diff --git a/freebsd/sys/contrib/ck/include/ck_cc.h b/freebsd/sys/contrib/ck/include/ck_cc.h new file mode 100644 index 00000000..9a152a3c --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_cc.h @@ -0,0 +1,173 @@ +/* + * Copyright 2009-2015 Samy Al Bahra. + * Copyright 2014 Paul Khuong. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_CC_H +#define CK_CC_H + +#if defined(__GNUC__) || defined(__SUNPRO_C) +#include "gcc/ck_cc.h" +#endif + +#ifndef CK_CC_RESTRICT +#define CK_CC_RESTRICT +#endif + +#ifndef CK_CC_INLINE +#define CK_CC_INLINE inline +#endif + +#ifndef CK_CC_FORCE_INLINE +#define CK_CC_FORCE_INLINE inline +#endif + +#define CK_CC_DECONST_PTR(X) ((void *)(uintptr_t)(X)) + +/* + * Container function. + * This relies on (compiler) implementation-defined behavior. + */ +#define CK_CC_CONTAINER(F, T, M, N) \ + CK_CC_INLINE static T * \ + N(F *p) \ + { \ + F *n = p; \ + return (T *)(void *)(((char *)n) - ((size_t)&((T *)0)->M)); \ + } + +#define CK_CC_PAD(x) union { char pad[x]; } + +#ifndef CK_CC_ALIASED +#define CK_CC_ALIASED +#endif + +#ifndef CK_CC_UNUSED +#define CK_CC_UNUSED +#endif + +#ifndef CK_CC_USED +#define CK_CC_USED +#endif + +#ifndef CK_CC_IMM +#define CK_CC_IMM +#endif + +#ifndef CK_CC_PACKED +#define CK_CC_PACKED +#endif + +#ifndef CK_CC_WEAKREF +#define CK_CC_WEAKREF +#endif + +#ifndef CK_CC_ALIGN +#define CK_CC_ALIGN(X) +#endif + +#ifndef CK_CC_CACHELINE +#define CK_CC_CACHELINE +#endif + +#ifndef CK_CC_LIKELY +#define CK_CC_LIKELY(x) x +#endif + +#ifndef CK_CC_UNLIKELY +#define CK_CC_UNLIKELY(x) x +#endif + +#ifndef CK_CC_TYPEOF +#define CK_CC_TYPEOF(X, DEFAULT) (DEFAULT) +#endif + +#define CK_F_CC_FFS_G(L, T) \ +CK_CC_INLINE static int \ +ck_cc_##L(T v) \ +{ \ + unsigned int i; \ + \ + if (v == 0) \ + return 0; \ + \ + for (i = 1; (v & 1) == 0; i++, v >>= 1); \ + return i; \ +} + +#ifndef CK_F_CC_FFS +#define CK_F_CC_FFS +CK_F_CC_FFS_G(ffs, unsigned int) +#endif /* CK_F_CC_FFS */ + +#ifndef CK_F_CC_FFSL +#define CK_F_CC_FFSL +CK_F_CC_FFS_G(ffsl, unsigned long) +#endif /* CK_F_CC_FFSL */ + +#ifndef CK_F_CC_FFSLL +#define CK_F_CC_FFSLL +CK_F_CC_FFS_G(ffsll, unsigned long long) +#endif /* CK_F_CC_FFSLL */ + +#undef CK_F_CC_FFS_G + +#ifndef CK_F_CC_CTZ +#define CK_F_CC_CTZ +CK_CC_INLINE static int +ck_cc_ctz(unsigned int x) +{ + unsigned int i; + + if (x == 0) + return 0; + + for (i = 0; (x & 1) == 0; i++, x >>= 1); + return i; +} +#endif + +#ifndef CK_F_CC_POPCOUNT +#define CK_F_CC_POPCOUNT +CK_CC_INLINE static int +ck_cc_popcount(unsigned int x) +{ + unsigned int acc; + + for (acc = 0; x != 0; x >>= 1) + acc += x & 1; + + return acc; +} +#endif + + +#ifdef __cplusplus +#define CK_CPP_CAST(type, arg) static_cast<type>(arg) +#else +#define CK_CPP_CAST(type, arg) arg +#endif + +#endif /* CK_CC_H */ diff --git a/freebsd/sys/contrib/ck/include/ck_epoch.h b/freebsd/sys/contrib/ck/include/ck_epoch.h new file mode 100644 index 00000000..58f3d28a --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_epoch.h @@ -0,0 +1,281 @@ +/* + * Copyright 2011-2015 Samy Al Bahra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_EPOCH_H +#define CK_EPOCH_H + +/* + * The implementation here is inspired from the work described in: + * Fraser, K. 2004. Practical Lock-Freedom. PhD Thesis, University + * of Cambridge Computing Laboratory. + */ + +#include <ck_cc.h> +#include <ck_md.h> +#include <ck_pr.h> +#include <ck_stack.h> +#include <ck_stdbool.h> + +#ifndef CK_EPOCH_LENGTH +#define CK_EPOCH_LENGTH 4 +#endif + +/* + * This is used for sense detection with-respect to concurrent + * epoch sections. + */ +#define CK_EPOCH_SENSE (2) + +struct ck_epoch_entry; +typedef struct ck_epoch_entry ck_epoch_entry_t; +typedef void ck_epoch_cb_t(ck_epoch_entry_t *); + +/* + * This should be embedded into objects you wish to be the target of + * ck_epoch_cb_t functions (with ck_epoch_call). + */ +struct ck_epoch_entry { + ck_epoch_cb_t *function; + ck_stack_entry_t stack_entry; +}; + +/* + * A section object may be passed to every begin-end pair to allow for + * forward progress guarantees with-in prolonged active sections. + */ +struct ck_epoch_section { + unsigned int bucket; +}; +typedef struct ck_epoch_section ck_epoch_section_t; + +/* + * Return pointer to ck_epoch_entry container object. + */ +#define CK_EPOCH_CONTAINER(T, M, N) \ + CK_CC_CONTAINER(struct ck_epoch_entry, T, M, N) + +struct ck_epoch_ref { + unsigned int epoch; + unsigned int count; +}; + +struct ck_epoch_record { + ck_stack_entry_t record_next; + struct ck_epoch *global; + unsigned int state; + unsigned int epoch; + unsigned int active; + struct { + struct ck_epoch_ref bucket[CK_EPOCH_SENSE]; + } local CK_CC_CACHELINE; + unsigned int n_pending; + unsigned int n_peak; + unsigned int n_dispatch; + void *ct; + ck_stack_t pending[CK_EPOCH_LENGTH]; +} CK_CC_CACHELINE; +typedef struct ck_epoch_record ck_epoch_record_t; + +struct ck_epoch { + unsigned int epoch; + unsigned int n_free; + ck_stack_t records; +}; +typedef struct ck_epoch ck_epoch_t; + +/* + * Internal functions. + */ +void _ck_epoch_addref(ck_epoch_record_t *, ck_epoch_section_t *); +bool _ck_epoch_delref(ck_epoch_record_t *, ck_epoch_section_t *); + +CK_CC_FORCE_INLINE static void * +ck_epoch_record_ct(const ck_epoch_record_t *record) +{ + + return ck_pr_load_ptr(&record->ct); +} + +/* + * Marks the beginning of an epoch-protected section. + */ +CK_CC_FORCE_INLINE static void +ck_epoch_begin(ck_epoch_record_t *record, ck_epoch_section_t *section) +{ + struct ck_epoch *epoch = record->global; + + /* + * Only observe new epoch if thread is not recursing into a read + * section. + */ + if (record->active == 0) { + unsigned int g_epoch; + + /* + * It is possible for loads to be re-ordered before the store + * is committed into the caller's epoch and active fields. + * For this reason, store to load serialization is necessary. + */ +#if defined(CK_MD_TSO) + ck_pr_fas_uint(&record->active, 1); + ck_pr_fence_atomic_load(); +#else + ck_pr_store_uint(&record->active, 1); + ck_pr_fence_memory(); +#endif + + /* + * This load is allowed to be re-ordered prior to setting + * active flag due to monotonic nature of the global epoch. + * However, stale values lead to measurable performance + * degradation in some torture tests so we disallow early load + * of global epoch. + */ + g_epoch = ck_pr_load_uint(&epoch->epoch); + ck_pr_store_uint(&record->epoch, g_epoch); + } else { + ck_pr_store_uint(&record->active, record->active + 1); + } + + if (section != NULL) + _ck_epoch_addref(record, section); + + return; +} + +/* + * Marks the end of an epoch-protected section. Returns true if no more + * sections exist for the caller. + */ +CK_CC_FORCE_INLINE static bool +ck_epoch_end(ck_epoch_record_t *record, ck_epoch_section_t *section) +{ + + ck_pr_fence_release(); + ck_pr_store_uint(&record->active, record->active - 1); + + if (section != NULL) + return _ck_epoch_delref(record, section); + + return record->active == 0; +} + +/* + * Defers the execution of the function pointed to by the "cb" + * argument until an epoch counter loop. This allows for a + * non-blocking deferral. + * + * We can get away without a fence here due to the monotonic nature + * of the epoch counter. Worst case, this will result in some delays + * before object destruction. + */ +CK_CC_FORCE_INLINE static void +ck_epoch_call(ck_epoch_record_t *record, + ck_epoch_entry_t *entry, + ck_epoch_cb_t *function) +{ + struct ck_epoch *epoch = record->global; + unsigned int e = ck_pr_load_uint(&epoch->epoch); + unsigned int offset = e & (CK_EPOCH_LENGTH - 1); + + record->n_pending++; + entry->function = function; + ck_stack_push_spnc(&record->pending[offset], &entry->stack_entry); + return; +} + +/* + * Same as ck_epoch_call, but allows for records to be shared and is reentrant. + */ +CK_CC_FORCE_INLINE static void +ck_epoch_call_strict(ck_epoch_record_t *record, + ck_epoch_entry_t *entry, + ck_epoch_cb_t *function) +{ + struct ck_epoch *epoch = record->global; + unsigned int e = ck_pr_load_uint(&epoch->epoch); + unsigned int offset = e & (CK_EPOCH_LENGTH - 1); + + ck_pr_inc_uint(&record->n_pending); + entry->function = function; + + /* Store fence is implied by push operation. */ + ck_stack_push_upmc(&record->pending[offset], &entry->stack_entry); + return; +} + +/* + * This callback is used for synchronize_wait to allow for custom blocking + * behavior. + */ +typedef void ck_epoch_wait_cb_t(ck_epoch_t *, ck_epoch_record_t *, + void *); + +/* + * Return latest epoch value. This operation provides load ordering. + */ +CK_CC_FORCE_INLINE static unsigned int +ck_epoch_value(const ck_epoch_t *ep) +{ + + ck_pr_fence_load(); + return ck_pr_load_uint(&ep->epoch); +} + +void ck_epoch_init(ck_epoch_t *); + +/* + * Attempts to recycle an unused epoch record. If one is successfully + * allocated, the record context pointer is also updated. + */ +ck_epoch_record_t *ck_epoch_recycle(ck_epoch_t *, void *); + +/* + * Registers an epoch record. An optional context pointer may be passed that + * is retrievable with ck_epoch_record_ct. + */ +void ck_epoch_register(ck_epoch_t *, ck_epoch_record_t *, void *); + +/* + * Marks a record as available for re-use by a subsequent recycle operation. + * Note that the record cannot be physically destroyed. + */ +void ck_epoch_unregister(ck_epoch_record_t *); + +bool ck_epoch_poll(ck_epoch_record_t *); +bool ck_epoch_poll_deferred(struct ck_epoch_record *record, ck_stack_t *deferred); +void ck_epoch_synchronize(ck_epoch_record_t *); +void ck_epoch_synchronize_wait(ck_epoch_t *, ck_epoch_wait_cb_t *, void *); +void ck_epoch_barrier(ck_epoch_record_t *); +void ck_epoch_barrier_wait(ck_epoch_record_t *, ck_epoch_wait_cb_t *, void *); + +/* + * Reclaim entries associated with a record. This is safe to call only on + * the caller's record or records that are using call_strict. + */ +void ck_epoch_reclaim(ck_epoch_record_t *); + +#endif /* CK_EPOCH_H */ diff --git a/freebsd/sys/contrib/ck/include/ck_limits.h b/freebsd/sys/contrib/ck/include/ck_limits.h new file mode 100644 index 00000000..c8749550 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_limits.h @@ -0,0 +1,48 @@ +/* + * Copyright 2010-2015 Samy Al Bahra. + * 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. + */ + +#if defined(__linux__) && defined(__KERNEL__) +#include <linux/kernel.h> + +#ifndef UINT8_MAX +#define UINT8_MAX ((u8)(~0U)) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX USHRT_MAX +#endif +#ifndef UINT32_MAX +#define UINT32_MAX UINT_MAX +#endif +#ifndef UINT64_MAX +#define UINT64_MAX ULLONG_MAX +#endif + +#elif defined(__FreeBSD__) && defined(_KERNEL) +#include <sys/stdint.h> +#include <sys/limits.h> +#else +#include <limits.h> +#endif /* __linux__ && __KERNEL__ */ diff --git a/freebsd/sys/contrib/ck/include/ck_md.h b/freebsd/sys/contrib/ck/include/ck_md.h new file mode 100644 index 00000000..3a69584e --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_md.h @@ -0,0 +1,136 @@ +/* + * Copyright 2018 Samy Al Bahra. + * 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: head/sys/contrib/ck/include/ck_md.h 329388 2018-02-16 17:50:06Z cog +net $ + */ + +/* + * This header file is meant for use of Concurrency Kit in the FreeBSD kernel. + */ + +#ifndef CK_MD_H +#define CK_MD_H + +#include <sys/param.h> + +#ifndef __rtems__ +#ifndef _KERNEL +#error This header file is meant for the FreeBSD kernel. +#endif /* _KERNEL */ +#endif /* __rtems__ */ + +#ifndef CK_MD_CACHELINE +/* + * FreeBSD's CACHE_LINE macro is a compile-time maximum cache-line size for an + * architecture, defined to be 128 bytes by default on x86*. Even in presence + * of adjacent sector prefetch, this doesn't make sense from a modeling + * perspective. + */ +#if defined(__amd64__) || defined(__i386__) +#define CK_MD_CACHELINE (64) +#else +#define CK_MD_CACHELINE (CACHE_LINE_SIZE) +#endif /* !__amd64__ && !__i386__ */ +#endif /* CK_MD_CACHELINE */ + +#ifndef CK_MD_PAGESIZE +#define CK_MD_PAGESIZE (PAGE_SIZE) +#endif + +/* + * Once FreeBSD has a mechanism to detect RTM, this can be enabled and RTM + * facilities can be called. These facilities refer to TSX. + */ +#ifndef CK_MD_RTM_DISABLE +#define CK_MD_RTM_DISABLE +#endif /* CK_MD_RTM_DISABLE */ + +/* + * Do not enable pointer-packing-related (VMA) optimizations in kernel-space. + */ +#ifndef CK_MD_POINTER_PACK_DISABLE +#define CK_MD_POINTER_PACK_DISABLE +#endif /* CK_MD_POINTER_PACK_DISABLE */ + +/* + * The following would be used for pointer-packing tricks, disabled for the + * kernel. + */ +#ifndef CK_MD_VMA_BITS_UNKNOWN +#define CK_MD_VMA_BITS_UNKNOWN +#endif /* CK_MD_VMA_BITS_UNKNOWN */ + +/* + * Do not enable double operations in kernel-space. + */ +#ifndef CK_PR_DISABLE_DOUBLE +#define CK_PR_DISABLE_DOUBLE +#endif /* CK_PR_DISABLE_DOUBLE */ + +/* + * If building for a uni-processor target, then enable the uniprocessor + * feature flag. This, among other things, will remove the lock prefix. + */ +#ifndef SMP +#define CK_MD_UMP +#endif /* SMP */ + +/* + * Disable the use of compiler builtin functions. + */ +#define CK_MD_CC_BUILTIN_DISABLE 1 + +/* + * CK expects those, which are normally defined by the build system. + */ +#if defined(__i386__) && !defined(__x86__) +#define __x86__ +/* + * If x86 becomes more relevant, we may want to consider importing in + * __mbk() to avoid potential issues around false sharing. + */ +#define CK_MD_TSO +#define CK_MD_SSE_DISABLE 1 +#elif defined(__amd64__) +#define CK_MD_TSO +#elif defined(__sparc64__) && !defined(__sparcv9__) +#define __sparcv9__ +#define CK_MD_TSO +#elif defined(__powerpc64__) && !defined(__ppc64__) +#define __ppc64__ +#elif defined(__powerpc__) && !defined(__ppc__) +#define __ppc__ +#endif + +/* If no memory model has been defined, assume RMO. */ +#if !defined(CK_MD_RMO) && !defined(CK_MD_TSO) && !defined(CK_MD_PSO) +#define CK_MD_RMO +#endif + +#define CK_VERSION "0.7.0" +#define CK_GIT_SHA "db5db44" + +#endif /* CK_MD_H */ diff --git a/freebsd/sys/contrib/ck/include/ck_pr.h b/freebsd/sys/contrib/ck/include/ck_pr.h new file mode 100644 index 00000000..7fa57a8e --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_pr.h @@ -0,0 +1,1225 @@ +/* + * Copyright 2009-2015 Samy Al Bahra. + * Copyright 2011 David Joseph. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_PR_H +#define CK_PR_H + +#include <ck_cc.h> +#include <ck_limits.h> +#include <ck_md.h> +#include <ck_stdint.h> +#include <ck_stdbool.h> + +#ifndef CK_USE_CC_BUILTINS +#if defined(__x86_64__) +#include "gcc/x86_64/ck_pr.h" +#elif defined(__x86__) +#include "gcc/x86/ck_pr.h" +#elif defined(__sparcv9__) +#include "gcc/sparcv9/ck_pr.h" +#elif defined(__ppc64__) +#include "gcc/ppc64/ck_pr.h" +#elif defined(__s390x__) +#include "gcc/s390x/ck_pr.h" +#elif defined(__ppc__) +#include "gcc/ppc/ck_pr.h" +#elif defined(__arm__) +#if __ARM_ARCH >= 6 +#include "gcc/arm/ck_pr.h" +#else +#include "gcc/arm/ck_pr_armv4.h" +#endif +#elif defined(__aarch64__) +#include "gcc/aarch64/ck_pr.h" +#elif !defined(__GNUC__) +#error Your platform is unsupported +#endif +#endif /* !CK_USE_CC_BUILTINS */ + +#if defined(__GNUC__) +#include "gcc/ck_pr.h" +#endif + +#define CK_PR_FENCE_EMIT(T) \ + CK_CC_INLINE static void \ + ck_pr_fence_##T(void) \ + { \ + ck_pr_fence_strict_##T(); \ + return; \ + } +#define CK_PR_FENCE_NOOP(T) \ + CK_CC_INLINE static void \ + ck_pr_fence_##T(void) \ + { \ + ck_pr_barrier(); \ + return; \ + } + +/* + * None of the currently supported platforms allow for data-dependent + * load ordering. + */ +CK_PR_FENCE_NOOP(load_depends) +#define ck_pr_fence_strict_load_depends ck_pr_fence_load_depends + +/* + * In memory models where atomic operations do not have serializing + * effects, atomic read-modify-write operations are modeled as stores. + */ +#if defined(CK_MD_RMO) +/* + * Only stores to the same location have a global + * ordering. + */ +CK_PR_FENCE_EMIT(atomic) +CK_PR_FENCE_EMIT(atomic_load) +CK_PR_FENCE_EMIT(atomic_store) +CK_PR_FENCE_EMIT(store_atomic) +CK_PR_FENCE_EMIT(load_atomic) +CK_PR_FENCE_EMIT(load_store) +CK_PR_FENCE_EMIT(store_load) +CK_PR_FENCE_EMIT(load) +CK_PR_FENCE_EMIT(store) +CK_PR_FENCE_EMIT(memory) +CK_PR_FENCE_EMIT(acquire) +CK_PR_FENCE_EMIT(release) +CK_PR_FENCE_EMIT(acqrel) +CK_PR_FENCE_EMIT(lock) +CK_PR_FENCE_EMIT(unlock) +#elif defined(CK_MD_PSO) +/* + * Anything can be re-ordered with respect to stores. + * Otherwise, loads are executed in-order. + */ +CK_PR_FENCE_EMIT(atomic) +CK_PR_FENCE_NOOP(atomic_load) +CK_PR_FENCE_EMIT(atomic_store) +CK_PR_FENCE_EMIT(store_atomic) +CK_PR_FENCE_NOOP(load_atomic) +CK_PR_FENCE_EMIT(load_store) +CK_PR_FENCE_EMIT(store_load) +CK_PR_FENCE_NOOP(load) +CK_PR_FENCE_EMIT(store) +CK_PR_FENCE_EMIT(memory) +CK_PR_FENCE_EMIT(acquire) +CK_PR_FENCE_EMIT(release) +CK_PR_FENCE_EMIT(acqrel) +CK_PR_FENCE_EMIT(lock) +CK_PR_FENCE_EMIT(unlock) +#elif defined(CK_MD_TSO) +/* + * Only loads are re-ordered and only with respect to + * prior stores. Atomic operations are serializing. + */ +CK_PR_FENCE_NOOP(atomic) +CK_PR_FENCE_NOOP(atomic_load) +CK_PR_FENCE_NOOP(atomic_store) +CK_PR_FENCE_NOOP(store_atomic) +CK_PR_FENCE_NOOP(load_atomic) +CK_PR_FENCE_NOOP(load_store) +CK_PR_FENCE_EMIT(store_load) +CK_PR_FENCE_NOOP(load) +CK_PR_FENCE_NOOP(store) +CK_PR_FENCE_EMIT(memory) +CK_PR_FENCE_NOOP(acquire) +CK_PR_FENCE_NOOP(release) +CK_PR_FENCE_NOOP(acqrel) +CK_PR_FENCE_NOOP(lock) +CK_PR_FENCE_NOOP(unlock) +#else +#error "No memory model has been defined." +#endif /* CK_MD_TSO */ + +#undef CK_PR_FENCE_EMIT +#undef CK_PR_FENCE_NOOP + +#ifndef CK_F_PR_RFO +#define CK_F_PR_RFO +CK_CC_INLINE static void +ck_pr_rfo(const void *m) +{ + + (void)m; + return; +} +#endif /* CK_F_PR_RFO */ + +#define CK_PR_STORE_SAFE(DST, VAL, TYPE) \ + ck_pr_md_store_##TYPE( \ + ((void)sizeof(*(DST) = (VAL)), (DST)), \ + (VAL)) + +#define ck_pr_store_ptr(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), ptr) +#define ck_pr_store_char(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), char) +#ifndef CK_PR_DISABLE_DOUBLE +#define ck_pr_store_double(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), double) +#endif +#define ck_pr_store_uint(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), uint) +#define ck_pr_store_int(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), int) +#define ck_pr_store_32(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), 32) +#define ck_pr_store_16(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), 16) +#define ck_pr_store_8(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), 8) + +#define ck_pr_store_ptr_unsafe(DST, VAL) ck_pr_md_store_ptr((DST), (VAL)) + +#ifdef CK_F_PR_LOAD_64 +#define ck_pr_store_64(DST, VAL) CK_PR_STORE_SAFE((DST), (VAL), 64) +#endif /* CK_F_PR_LOAD_64 */ + +#define CK_PR_LOAD_PTR_SAFE(SRC) (CK_CC_TYPEOF(*(SRC), (void *)))ck_pr_md_load_ptr((SRC)) +#define ck_pr_load_ptr(SRC) CK_PR_LOAD_PTR_SAFE((SRC)) + +#define CK_PR_LOAD_SAFE(SRC, TYPE) ck_pr_md_load_##TYPE((SRC)) +#define ck_pr_load_char(SRC) CK_PR_LOAD_SAFE((SRC), char) +#ifndef CK_PR_DISABLE_DOUBLE +#define ck_pr_load_double(SRC) CK_PR_LOAD_SAFE((SRC), double) +#endif +#define ck_pr_load_uint(SRC) CK_PR_LOAD_SAFE((SRC), uint) +#define ck_pr_load_int(SRC) CK_PR_LOAD_SAFE((SRC), int) +#define ck_pr_load_32(SRC) CK_PR_LOAD_SAFE((SRC), 32) +#define ck_pr_load_16(SRC) CK_PR_LOAD_SAFE((SRC), 16) +#define ck_pr_load_8(SRC) CK_PR_LOAD_SAFE((SRC), 8) + +#ifdef CK_F_PR_LOAD_64 +#define ck_pr_load_64(SRC) CK_PR_LOAD_SAFE((SRC), 64) +#endif /* CK_F_PR_LOAD_64 */ + +#define CK_PR_BIN(K, S, M, T, P, C) \ + CK_CC_INLINE static void \ + ck_pr_##K##_##S(M *target, T value) \ + { \ + T previous; \ + C punt; \ + punt = ck_pr_md_load_##S(target); \ + previous = (T)punt; \ + while (ck_pr_cas_##S##_value(target, \ + (C)previous, \ + (C)(previous P value), \ + &previous) == false) \ + ck_pr_stall(); \ + \ + return; \ + } + +#define CK_PR_BIN_S(K, S, T, P) CK_PR_BIN(K, S, T, T, P, T) + +#if defined(CK_F_PR_LOAD_CHAR) && defined(CK_F_PR_CAS_CHAR_VALUE) + +#ifndef CK_F_PR_ADD_CHAR +#define CK_F_PR_ADD_CHAR +CK_PR_BIN_S(add, char, char, +) +#endif /* CK_F_PR_ADD_CHAR */ + +#ifndef CK_F_PR_SUB_CHAR +#define CK_F_PR_SUB_CHAR +CK_PR_BIN_S(sub, char, char, -) +#endif /* CK_F_PR_SUB_CHAR */ + +#ifndef CK_F_PR_AND_CHAR +#define CK_F_PR_AND_CHAR +CK_PR_BIN_S(and, char, char, &) +#endif /* CK_F_PR_AND_CHAR */ + +#ifndef CK_F_PR_XOR_CHAR +#define CK_F_PR_XOR_CHAR +CK_PR_BIN_S(xor, char, char, ^) +#endif /* CK_F_PR_XOR_CHAR */ + +#ifndef CK_F_PR_OR_CHAR +#define CK_F_PR_OR_CHAR +CK_PR_BIN_S(or, char, char, |) +#endif /* CK_F_PR_OR_CHAR */ + +#endif /* CK_F_PR_LOAD_CHAR && CK_F_PR_CAS_CHAR_VALUE */ + +#if defined(CK_F_PR_LOAD_INT) && defined(CK_F_PR_CAS_INT_VALUE) + +#ifndef CK_F_PR_ADD_INT +#define CK_F_PR_ADD_INT +CK_PR_BIN_S(add, int, int, +) +#endif /* CK_F_PR_ADD_INT */ + +#ifndef CK_F_PR_SUB_INT +#define CK_F_PR_SUB_INT +CK_PR_BIN_S(sub, int, int, -) +#endif /* CK_F_PR_SUB_INT */ + +#ifndef CK_F_PR_AND_INT +#define CK_F_PR_AND_INT +CK_PR_BIN_S(and, int, int, &) +#endif /* CK_F_PR_AND_INT */ + +#ifndef CK_F_PR_XOR_INT +#define CK_F_PR_XOR_INT +CK_PR_BIN_S(xor, int, int, ^) +#endif /* CK_F_PR_XOR_INT */ + +#ifndef CK_F_PR_OR_INT +#define CK_F_PR_OR_INT +CK_PR_BIN_S(or, int, int, |) +#endif /* CK_F_PR_OR_INT */ + +#endif /* CK_F_PR_LOAD_INT && CK_F_PR_CAS_INT_VALUE */ + +#if defined(CK_F_PR_LOAD_DOUBLE) && defined(CK_F_PR_CAS_DOUBLE_VALUE) && \ + !defined(CK_PR_DISABLE_DOUBLE) + +#ifndef CK_F_PR_ADD_DOUBLE +#define CK_F_PR_ADD_DOUBLE +CK_PR_BIN_S(add, double, double, +) +#endif /* CK_F_PR_ADD_DOUBLE */ + +#ifndef CK_F_PR_SUB_DOUBLE +#define CK_F_PR_SUB_DOUBLE +CK_PR_BIN_S(sub, double, double, -) +#endif /* CK_F_PR_SUB_DOUBLE */ + +#endif /* CK_F_PR_LOAD_DOUBLE && CK_F_PR_CAS_DOUBLE_VALUE && !CK_PR_DISABLE_DOUBLE */ + +#if defined(CK_F_PR_LOAD_UINT) && defined(CK_F_PR_CAS_UINT_VALUE) + +#ifndef CK_F_PR_ADD_UINT +#define CK_F_PR_ADD_UINT +CK_PR_BIN_S(add, uint, unsigned int, +) +#endif /* CK_F_PR_ADD_UINT */ + +#ifndef CK_F_PR_SUB_UINT +#define CK_F_PR_SUB_UINT +CK_PR_BIN_S(sub, uint, unsigned int, -) +#endif /* CK_F_PR_SUB_UINT */ + +#ifndef CK_F_PR_AND_UINT +#define CK_F_PR_AND_UINT +CK_PR_BIN_S(and, uint, unsigned int, &) +#endif /* CK_F_PR_AND_UINT */ + +#ifndef CK_F_PR_XOR_UINT +#define CK_F_PR_XOR_UINT +CK_PR_BIN_S(xor, uint, unsigned int, ^) +#endif /* CK_F_PR_XOR_UINT */ + +#ifndef CK_F_PR_OR_UINT +#define CK_F_PR_OR_UINT +CK_PR_BIN_S(or, uint, unsigned int, |) +#endif /* CK_F_PR_OR_UINT */ + +#endif /* CK_F_PR_LOAD_UINT && CK_F_PR_CAS_UINT_VALUE */ + +#if defined(CK_F_PR_LOAD_PTR) && defined(CK_F_PR_CAS_PTR_VALUE) + +#ifndef CK_F_PR_ADD_PTR +#define CK_F_PR_ADD_PTR +CK_PR_BIN(add, ptr, void, uintptr_t, +, void *) +#endif /* CK_F_PR_ADD_PTR */ + +#ifndef CK_F_PR_SUB_PTR +#define CK_F_PR_SUB_PTR +CK_PR_BIN(sub, ptr, void, uintptr_t, -, void *) +#endif /* CK_F_PR_SUB_PTR */ + +#ifndef CK_F_PR_AND_PTR +#define CK_F_PR_AND_PTR +CK_PR_BIN(and, ptr, void, uintptr_t, &, void *) +#endif /* CK_F_PR_AND_PTR */ + +#ifndef CK_F_PR_XOR_PTR +#define CK_F_PR_XOR_PTR +CK_PR_BIN(xor, ptr, void, uintptr_t, ^, void *) +#endif /* CK_F_PR_XOR_PTR */ + +#ifndef CK_F_PR_OR_PTR +#define CK_F_PR_OR_PTR +CK_PR_BIN(or, ptr, void, uintptr_t, |, void *) +#endif /* CK_F_PR_OR_PTR */ + +#endif /* CK_F_PR_LOAD_PTR && CK_F_PR_CAS_PTR_VALUE */ + +#if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_CAS_64_VALUE) + +#ifndef CK_F_PR_ADD_64 +#define CK_F_PR_ADD_64 +CK_PR_BIN_S(add, 64, uint64_t, +) +#endif /* CK_F_PR_ADD_64 */ + +#ifndef CK_F_PR_SUB_64 +#define CK_F_PR_SUB_64 +CK_PR_BIN_S(sub, 64, uint64_t, -) +#endif /* CK_F_PR_SUB_64 */ + +#ifndef CK_F_PR_AND_64 +#define CK_F_PR_AND_64 +CK_PR_BIN_S(and, 64, uint64_t, &) +#endif /* CK_F_PR_AND_64 */ + +#ifndef CK_F_PR_XOR_64 +#define CK_F_PR_XOR_64 +CK_PR_BIN_S(xor, 64, uint64_t, ^) +#endif /* CK_F_PR_XOR_64 */ + +#ifndef CK_F_PR_OR_64 +#define CK_F_PR_OR_64 +CK_PR_BIN_S(or, 64, uint64_t, |) +#endif /* CK_F_PR_OR_64 */ + +#endif /* CK_F_PR_LOAD_64 && CK_F_PR_CAS_64_VALUE */ + +#if defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_CAS_32_VALUE) + +#ifndef CK_F_PR_ADD_32 +#define CK_F_PR_ADD_32 +CK_PR_BIN_S(add, 32, uint32_t, +) +#endif /* CK_F_PR_ADD_32 */ + +#ifndef CK_F_PR_SUB_32 +#define CK_F_PR_SUB_32 +CK_PR_BIN_S(sub, 32, uint32_t, -) +#endif /* CK_F_PR_SUB_32 */ + +#ifndef CK_F_PR_AND_32 +#define CK_F_PR_AND_32 +CK_PR_BIN_S(and, 32, uint32_t, &) +#endif /* CK_F_PR_AND_32 */ + +#ifndef CK_F_PR_XOR_32 +#define CK_F_PR_XOR_32 +CK_PR_BIN_S(xor, 32, uint32_t, ^) +#endif /* CK_F_PR_XOR_32 */ + +#ifndef CK_F_PR_OR_32 +#define CK_F_PR_OR_32 +CK_PR_BIN_S(or, 32, uint32_t, |) +#endif /* CK_F_PR_OR_32 */ + +#endif /* CK_F_PR_LOAD_32 && CK_F_PR_CAS_32_VALUE */ + +#if defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_CAS_16_VALUE) + +#ifndef CK_F_PR_ADD_16 +#define CK_F_PR_ADD_16 +CK_PR_BIN_S(add, 16, uint16_t, +) +#endif /* CK_F_PR_ADD_16 */ + +#ifndef CK_F_PR_SUB_16 +#define CK_F_PR_SUB_16 +CK_PR_BIN_S(sub, 16, uint16_t, -) +#endif /* CK_F_PR_SUB_16 */ + +#ifndef CK_F_PR_AND_16 +#define CK_F_PR_AND_16 +CK_PR_BIN_S(and, 16, uint16_t, &) +#endif /* CK_F_PR_AND_16 */ + +#ifndef CK_F_PR_XOR_16 +#define CK_F_PR_XOR_16 +CK_PR_BIN_S(xor, 16, uint16_t, ^) +#endif /* CK_F_PR_XOR_16 */ + +#ifndef CK_F_PR_OR_16 +#define CK_F_PR_OR_16 +CK_PR_BIN_S(or, 16, uint16_t, |) +#endif /* CK_F_PR_OR_16 */ + +#endif /* CK_F_PR_LOAD_16 && CK_F_PR_CAS_16_VALUE */ + +#if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_CAS_8_VALUE) + +#ifndef CK_F_PR_ADD_8 +#define CK_F_PR_ADD_8 +CK_PR_BIN_S(add, 8, uint8_t, +) +#endif /* CK_F_PR_ADD_8 */ + +#ifndef CK_F_PR_SUB_8 +#define CK_F_PR_SUB_8 +CK_PR_BIN_S(sub, 8, uint8_t, -) +#endif /* CK_F_PR_SUB_8 */ + +#ifndef CK_F_PR_AND_8 +#define CK_F_PR_AND_8 +CK_PR_BIN_S(and, 8, uint8_t, &) +#endif /* CK_F_PR_AND_8 */ + +#ifndef CK_F_PR_XOR_8 +#define CK_F_PR_XOR_8 +CK_PR_BIN_S(xor, 8, uint8_t, ^) +#endif /* CK_F_PR_XOR_8 */ + +#ifndef CK_F_PR_OR_8 +#define CK_F_PR_OR_8 +CK_PR_BIN_S(or, 8, uint8_t, |) +#endif /* CK_F_PR_OR_8 */ + +#endif /* CK_F_PR_LOAD_8 && CK_F_PR_CAS_8_VALUE */ + +#undef CK_PR_BIN_S +#undef CK_PR_BIN + +#define CK_PR_BTX(K, S, M, T, P, C, R) \ + CK_CC_INLINE static bool \ + ck_pr_##K##_##S(M *target, unsigned int offset) \ + { \ + T previous; \ + C punt; \ + punt = ck_pr_md_load_##S(target); \ + previous = (T)punt; \ + while (ck_pr_cas_##S##_value(target, (C)previous, \ + (C)(previous P (R ((T)1 << offset))), &previous) == false) \ + ck_pr_stall(); \ + return ((previous >> offset) & 1); \ + } + +#define CK_PR_BTX_S(K, S, T, P, R) CK_PR_BTX(K, S, T, T, P, T, R) + +#if defined(CK_F_PR_LOAD_INT) && defined(CK_F_PR_CAS_INT_VALUE) + +#ifndef CK_F_PR_BTC_INT +#define CK_F_PR_BTC_INT +CK_PR_BTX_S(btc, int, int, ^,) +#endif /* CK_F_PR_BTC_INT */ + +#ifndef CK_F_PR_BTR_INT +#define CK_F_PR_BTR_INT +CK_PR_BTX_S(btr, int, int, &, ~) +#endif /* CK_F_PR_BTR_INT */ + +#ifndef CK_F_PR_BTS_INT +#define CK_F_PR_BTS_INT +CK_PR_BTX_S(bts, int, int, |,) +#endif /* CK_F_PR_BTS_INT */ + +#endif /* CK_F_PR_LOAD_INT && CK_F_PR_CAS_INT_VALUE */ + +#if defined(CK_F_PR_LOAD_UINT) && defined(CK_F_PR_CAS_UINT_VALUE) + +#ifndef CK_F_PR_BTC_UINT +#define CK_F_PR_BTC_UINT +CK_PR_BTX_S(btc, uint, unsigned int, ^,) +#endif /* CK_F_PR_BTC_UINT */ + +#ifndef CK_F_PR_BTR_UINT +#define CK_F_PR_BTR_UINT +CK_PR_BTX_S(btr, uint, unsigned int, &, ~) +#endif /* CK_F_PR_BTR_UINT */ + +#ifndef CK_F_PR_BTS_UINT +#define CK_F_PR_BTS_UINT +CK_PR_BTX_S(bts, uint, unsigned int, |,) +#endif /* CK_F_PR_BTS_UINT */ + +#endif /* CK_F_PR_LOAD_UINT && CK_F_PR_CAS_UINT_VALUE */ + +#if defined(CK_F_PR_LOAD_PTR) && defined(CK_F_PR_CAS_PTR_VALUE) + +#ifndef CK_F_PR_BTC_PTR +#define CK_F_PR_BTC_PTR +CK_PR_BTX(btc, ptr, void, uintptr_t, ^, void *,) +#endif /* CK_F_PR_BTC_PTR */ + +#ifndef CK_F_PR_BTR_PTR +#define CK_F_PR_BTR_PTR +CK_PR_BTX(btr, ptr, void, uintptr_t, &, void *, ~) +#endif /* CK_F_PR_BTR_PTR */ + +#ifndef CK_F_PR_BTS_PTR +#define CK_F_PR_BTS_PTR +CK_PR_BTX(bts, ptr, void, uintptr_t, |, void *,) +#endif /* CK_F_PR_BTS_PTR */ + +#endif /* CK_F_PR_LOAD_PTR && CK_F_PR_CAS_PTR_VALUE */ + +#if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_CAS_64_VALUE) + +#ifndef CK_F_PR_BTC_64 +#define CK_F_PR_BTC_64 +CK_PR_BTX_S(btc, 64, uint64_t, ^,) +#endif /* CK_F_PR_BTC_64 */ + +#ifndef CK_F_PR_BTR_64 +#define CK_F_PR_BTR_64 +CK_PR_BTX_S(btr, 64, uint64_t, &, ~) +#endif /* CK_F_PR_BTR_64 */ + +#ifndef CK_F_PR_BTS_64 +#define CK_F_PR_BTS_64 +CK_PR_BTX_S(bts, 64, uint64_t, |,) +#endif /* CK_F_PR_BTS_64 */ + +#endif /* CK_F_PR_LOAD_64 && CK_F_PR_CAS_64_VALUE */ + +#if defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_CAS_32_VALUE) + +#ifndef CK_F_PR_BTC_32 +#define CK_F_PR_BTC_32 +CK_PR_BTX_S(btc, 32, uint32_t, ^,) +#endif /* CK_F_PR_BTC_32 */ + +#ifndef CK_F_PR_BTR_32 +#define CK_F_PR_BTR_32 +CK_PR_BTX_S(btr, 32, uint32_t, &, ~) +#endif /* CK_F_PR_BTR_32 */ + +#ifndef CK_F_PR_BTS_32 +#define CK_F_PR_BTS_32 +CK_PR_BTX_S(bts, 32, uint32_t, |,) +#endif /* CK_F_PR_BTS_32 */ + +#endif /* CK_F_PR_LOAD_32 && CK_F_PR_CAS_32_VALUE */ + +#if defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_CAS_16_VALUE) + +#ifndef CK_F_PR_BTC_16 +#define CK_F_PR_BTC_16 +CK_PR_BTX_S(btc, 16, uint16_t, ^,) +#endif /* CK_F_PR_BTC_16 */ + +#ifndef CK_F_PR_BTR_16 +#define CK_F_PR_BTR_16 +CK_PR_BTX_S(btr, 16, uint16_t, &, ~) +#endif /* CK_F_PR_BTR_16 */ + +#ifndef CK_F_PR_BTS_16 +#define CK_F_PR_BTS_16 +CK_PR_BTX_S(bts, 16, uint16_t, |,) +#endif /* CK_F_PR_BTS_16 */ + +#endif /* CK_F_PR_LOAD_16 && CK_F_PR_CAS_16_VALUE */ + +#undef CK_PR_BTX_S +#undef CK_PR_BTX + +#define CK_PR_UNARY(K, X, S, M, T) \ + CK_CC_INLINE static void \ + ck_pr_##K##_##S(M *target) \ + { \ + ck_pr_##X##_##S(target, (T)1); \ + return; \ + } + +#define CK_PR_UNARY_Z(K, S, M, T, P, C, Z) \ + CK_CC_INLINE static void \ + ck_pr_##K##_##S##_zero(M *target, bool *zero) \ + { \ + T previous; \ + C punt; \ + punt = (C)ck_pr_md_load_##S(target); \ + previous = (T)punt; \ + while (ck_pr_cas_##S##_value(target, \ + (C)previous, \ + (C)(previous P 1), \ + &previous) == false) \ + ck_pr_stall(); \ + *zero = previous == (T)Z; \ + return; \ + } + +#define CK_PR_UNARY_S(K, X, S, M) CK_PR_UNARY(K, X, S, M, M) +#define CK_PR_UNARY_Z_S(K, S, M, P, Z) CK_PR_UNARY_Z(K, S, M, M, P, M, Z) + +#if defined(CK_F_PR_LOAD_CHAR) && defined(CK_F_PR_CAS_CHAR_VALUE) + +#ifndef CK_F_PR_INC_CHAR +#define CK_F_PR_INC_CHAR +CK_PR_UNARY_S(inc, add, char, char) +#endif /* CK_F_PR_INC_CHAR */ + +#ifndef CK_F_PR_INC_CHAR_ZERO +#define CK_F_PR_INC_CHAR_ZERO +CK_PR_UNARY_Z_S(inc, char, char, +, -1) +#endif /* CK_F_PR_INC_CHAR_ZERO */ + +#ifndef CK_F_PR_DEC_CHAR +#define CK_F_PR_DEC_CHAR +CK_PR_UNARY_S(dec, sub, char, char) +#endif /* CK_F_PR_DEC_CHAR */ + +#ifndef CK_F_PR_DEC_CHAR_ZERO +#define CK_F_PR_DEC_CHAR_ZERO +CK_PR_UNARY_Z_S(dec, char, char, -, 1) +#endif /* CK_F_PR_DEC_CHAR_ZERO */ + +#endif /* CK_F_PR_LOAD_CHAR && CK_F_PR_CAS_CHAR_VALUE */ + +#if defined(CK_F_PR_LOAD_INT) && defined(CK_F_PR_CAS_INT_VALUE) + +#ifndef CK_F_PR_INC_INT +#define CK_F_PR_INC_INT +CK_PR_UNARY_S(inc, add, int, int) +#endif /* CK_F_PR_INC_INT */ + +#ifndef CK_F_PR_INC_INT_ZERO +#define CK_F_PR_INC_INT_ZERO +CK_PR_UNARY_Z_S(inc, int, int, +, -1) +#endif /* CK_F_PR_INC_INT_ZERO */ + +#ifndef CK_F_PR_DEC_INT +#define CK_F_PR_DEC_INT +CK_PR_UNARY_S(dec, sub, int, int) +#endif /* CK_F_PR_DEC_INT */ + +#ifndef CK_F_PR_DEC_INT_ZERO +#define CK_F_PR_DEC_INT_ZERO +CK_PR_UNARY_Z_S(dec, int, int, -, 1) +#endif /* CK_F_PR_DEC_INT_ZERO */ + +#endif /* CK_F_PR_LOAD_INT && CK_F_PR_CAS_INT_VALUE */ + +#if defined(CK_F_PR_LOAD_DOUBLE) && defined(CK_F_PR_CAS_DOUBLE_VALUE) && \ + !defined(CK_PR_DISABLE_DOUBLE) + +#ifndef CK_F_PR_INC_DOUBLE +#define CK_F_PR_INC_DOUBLE +CK_PR_UNARY_S(inc, add, double, double) +#endif /* CK_F_PR_INC_DOUBLE */ + +#ifndef CK_F_PR_DEC_DOUBLE +#define CK_F_PR_DEC_DOUBLE +CK_PR_UNARY_S(dec, sub, double, double) +#endif /* CK_F_PR_DEC_DOUBLE */ + +#endif /* CK_F_PR_LOAD_DOUBLE && CK_F_PR_CAS_DOUBLE_VALUE && !CK_PR_DISABLE_DOUBLE */ + +#if defined(CK_F_PR_LOAD_UINT) && defined(CK_F_PR_CAS_UINT_VALUE) + +#ifndef CK_F_PR_INC_UINT +#define CK_F_PR_INC_UINT +CK_PR_UNARY_S(inc, add, uint, unsigned int) +#endif /* CK_F_PR_INC_UINT */ + +#ifndef CK_F_PR_INC_UINT_ZERO +#define CK_F_PR_INC_UINT_ZERO +CK_PR_UNARY_Z_S(inc, uint, unsigned int, +, UINT_MAX) +#endif /* CK_F_PR_INC_UINT_ZERO */ + +#ifndef CK_F_PR_DEC_UINT +#define CK_F_PR_DEC_UINT +CK_PR_UNARY_S(dec, sub, uint, unsigned int) +#endif /* CK_F_PR_DEC_UINT */ + +#ifndef CK_F_PR_DEC_UINT_ZERO +#define CK_F_PR_DEC_UINT_ZERO +CK_PR_UNARY_Z_S(dec, uint, unsigned int, -, 1) +#endif /* CK_F_PR_DEC_UINT_ZERO */ + +#endif /* CK_F_PR_LOAD_UINT && CK_F_PR_CAS_UINT_VALUE */ + +#if defined(CK_F_PR_LOAD_PTR) && defined(CK_F_PR_CAS_PTR_VALUE) + +#ifndef CK_F_PR_INC_PTR +#define CK_F_PR_INC_PTR +CK_PR_UNARY(inc, add, ptr, void, uintptr_t) +#endif /* CK_F_PR_INC_PTR */ + +#ifndef CK_F_PR_INC_PTR_ZERO +#define CK_F_PR_INC_PTR_ZERO +CK_PR_UNARY_Z(inc, ptr, void, uintptr_t, +, void *, UINT_MAX) +#endif /* CK_F_PR_INC_PTR_ZERO */ + +#ifndef CK_F_PR_DEC_PTR +#define CK_F_PR_DEC_PTR +CK_PR_UNARY(dec, sub, ptr, void, uintptr_t) +#endif /* CK_F_PR_DEC_PTR */ + +#ifndef CK_F_PR_DEC_PTR_ZERO +#define CK_F_PR_DEC_PTR_ZERO +CK_PR_UNARY_Z(dec, ptr, void, uintptr_t, -, void *, 1) +#endif /* CK_F_PR_DEC_PTR_ZERO */ + +#endif /* CK_F_PR_LOAD_PTR && CK_F_PR_CAS_PTR_VALUE */ + +#if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_CAS_64_VALUE) + +#ifndef CK_F_PR_INC_64 +#define CK_F_PR_INC_64 +CK_PR_UNARY_S(inc, add, 64, uint64_t) +#endif /* CK_F_PR_INC_64 */ + +#ifndef CK_F_PR_INC_64_ZERO +#define CK_F_PR_INC_64_ZERO +CK_PR_UNARY_Z_S(inc, 64, uint64_t, +, UINT64_MAX) +#endif /* CK_F_PR_INC_64_ZERO */ + +#ifndef CK_F_PR_DEC_64 +#define CK_F_PR_DEC_64 +CK_PR_UNARY_S(dec, sub, 64, uint64_t) +#endif /* CK_F_PR_DEC_64 */ + +#ifndef CK_F_PR_DEC_64_ZERO +#define CK_F_PR_DEC_64_ZERO +CK_PR_UNARY_Z_S(dec, 64, uint64_t, -, 1) +#endif /* CK_F_PR_DEC_64_ZERO */ + +#endif /* CK_F_PR_LOAD_64 && CK_F_PR_CAS_64_VALUE */ + +#if defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_CAS_32_VALUE) + +#ifndef CK_F_PR_INC_32 +#define CK_F_PR_INC_32 +CK_PR_UNARY_S(inc, add, 32, uint32_t) +#endif /* CK_F_PR_INC_32 */ + +#ifndef CK_F_PR_INC_32_ZERO +#define CK_F_PR_INC_32_ZERO +CK_PR_UNARY_Z_S(inc, 32, uint32_t, +, UINT32_MAX) +#endif /* CK_F_PR_INC_32_ZERO */ + +#ifndef CK_F_PR_DEC_32 +#define CK_F_PR_DEC_32 +CK_PR_UNARY_S(dec, sub, 32, uint32_t) +#endif /* CK_F_PR_DEC_32 */ + +#ifndef CK_F_PR_DEC_32_ZERO +#define CK_F_PR_DEC_32_ZERO +CK_PR_UNARY_Z_S(dec, 32, uint32_t, -, 1) +#endif /* CK_F_PR_DEC_32_ZERO */ + +#endif /* CK_F_PR_LOAD_32 && CK_F_PR_CAS_32_VALUE */ + +#if defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_CAS_16_VALUE) + +#ifndef CK_F_PR_INC_16 +#define CK_F_PR_INC_16 +CK_PR_UNARY_S(inc, add, 16, uint16_t) +#endif /* CK_F_PR_INC_16 */ + +#ifndef CK_F_PR_INC_16_ZERO +#define CK_F_PR_INC_16_ZERO +CK_PR_UNARY_Z_S(inc, 16, uint16_t, +, UINT16_MAX) +#endif /* CK_F_PR_INC_16_ZERO */ + +#ifndef CK_F_PR_DEC_16 +#define CK_F_PR_DEC_16 +CK_PR_UNARY_S(dec, sub, 16, uint16_t) +#endif /* CK_F_PR_DEC_16 */ + +#ifndef CK_F_PR_DEC_16_ZERO +#define CK_F_PR_DEC_16_ZERO +CK_PR_UNARY_Z_S(dec, 16, uint16_t, -, 1) +#endif /* CK_F_PR_DEC_16_ZERO */ + +#endif /* CK_F_PR_LOAD_16 && CK_F_PR_CAS_16_VALUE */ + +#if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_CAS_8_VALUE) + +#ifndef CK_F_PR_INC_8 +#define CK_F_PR_INC_8 +CK_PR_UNARY_S(inc, add, 8, uint8_t) +#endif /* CK_F_PR_INC_8 */ + +#ifndef CK_F_PR_INC_8_ZERO +#define CK_F_PR_INC_8_ZERO +CK_PR_UNARY_Z_S(inc, 8, uint8_t, +, UINT8_MAX) +#endif /* CK_F_PR_INC_8_ZERO */ + +#ifndef CK_F_PR_DEC_8 +#define CK_F_PR_DEC_8 +CK_PR_UNARY_S(dec, sub, 8, uint8_t) +#endif /* CK_F_PR_DEC_8 */ + +#ifndef CK_F_PR_DEC_8_ZERO +#define CK_F_PR_DEC_8_ZERO +CK_PR_UNARY_Z_S(dec, 8, uint8_t, -, 1) +#endif /* CK_F_PR_DEC_8_ZERO */ + +#endif /* CK_F_PR_LOAD_8 && CK_F_PR_CAS_8_VALUE */ + +#undef CK_PR_UNARY_Z_S +#undef CK_PR_UNARY_S +#undef CK_PR_UNARY_Z +#undef CK_PR_UNARY + +#define CK_PR_N(K, S, M, T, P, C) \ + CK_CC_INLINE static void \ + ck_pr_##K##_##S(M *target) \ + { \ + T previous; \ + C punt; \ + punt = (C)ck_pr_md_load_##S(target); \ + previous = (T)punt; \ + while (ck_pr_cas_##S##_value(target, \ + (C)previous, \ + (C)(P previous), \ + &previous) == false) \ + ck_pr_stall(); \ + \ + return; \ + } + +#define CK_PR_N_Z(S, M, T, C) \ + CK_CC_INLINE static void \ + ck_pr_neg_##S##_zero(M *target, bool *zero) \ + { \ + T previous; \ + C punt; \ + punt = (C)ck_pr_md_load_##S(target); \ + previous = (T)punt; \ + while (ck_pr_cas_##S##_value(target, \ + (C)previous, \ + (C)(-previous), \ + &previous) == false) \ + ck_pr_stall(); \ + \ + *zero = previous == 0; \ + return; \ + } + +#define CK_PR_N_S(K, S, M, P) CK_PR_N(K, S, M, M, P, M) +#define CK_PR_N_Z_S(S, M) CK_PR_N_Z(S, M, M, M) + +#if defined(CK_F_PR_LOAD_CHAR) && defined(CK_F_PR_CAS_CHAR_VALUE) + +#ifndef CK_F_PR_NOT_CHAR +#define CK_F_PR_NOT_CHAR +CK_PR_N_S(not, char, char, ~) +#endif /* CK_F_PR_NOT_CHAR */ + +#ifndef CK_F_PR_NEG_CHAR +#define CK_F_PR_NEG_CHAR +CK_PR_N_S(neg, char, char, -) +#endif /* CK_F_PR_NEG_CHAR */ + +#ifndef CK_F_PR_NEG_CHAR_ZERO +#define CK_F_PR_NEG_CHAR_ZERO +CK_PR_N_Z_S(char, char) +#endif /* CK_F_PR_NEG_CHAR_ZERO */ + +#endif /* CK_F_PR_LOAD_CHAR && CK_F_PR_CAS_CHAR_VALUE */ + +#if defined(CK_F_PR_LOAD_INT) && defined(CK_F_PR_CAS_INT_VALUE) + +#ifndef CK_F_PR_NOT_INT +#define CK_F_PR_NOT_INT +CK_PR_N_S(not, int, int, ~) +#endif /* CK_F_PR_NOT_INT */ + +#ifndef CK_F_PR_NEG_INT +#define CK_F_PR_NEG_INT +CK_PR_N_S(neg, int, int, -) +#endif /* CK_F_PR_NEG_INT */ + +#ifndef CK_F_PR_NEG_INT_ZERO +#define CK_F_PR_NEG_INT_ZERO +CK_PR_N_Z_S(int, int) +#endif /* CK_F_PR_NEG_INT_ZERO */ + +#endif /* CK_F_PR_LOAD_INT && CK_F_PR_CAS_INT_VALUE */ + +#if defined(CK_F_PR_LOAD_DOUBLE) && defined(CK_F_PR_CAS_DOUBLE_VALUE) && \ + !defined(CK_PR_DISABLE_DOUBLE) + +#ifndef CK_F_PR_NEG_DOUBLE +#define CK_F_PR_NEG_DOUBLE +CK_PR_N_S(neg, double, double, -) +#endif /* CK_F_PR_NEG_DOUBLE */ + +#endif /* CK_F_PR_LOAD_DOUBLE && CK_F_PR_CAS_DOUBLE_VALUE && !CK_PR_DISABLE_DOUBLE */ + +#if defined(CK_F_PR_LOAD_UINT) && defined(CK_F_PR_CAS_UINT_VALUE) + +#ifndef CK_F_PR_NOT_UINT +#define CK_F_PR_NOT_UINT +CK_PR_N_S(not, uint, unsigned int, ~) +#endif /* CK_F_PR_NOT_UINT */ + +#ifndef CK_F_PR_NEG_UINT +#define CK_F_PR_NEG_UINT +CK_PR_N_S(neg, uint, unsigned int, -) +#endif /* CK_F_PR_NEG_UINT */ + +#ifndef CK_F_PR_NEG_UINT_ZERO +#define CK_F_PR_NEG_UINT_ZERO +CK_PR_N_Z_S(uint, unsigned int) +#endif /* CK_F_PR_NEG_UINT_ZERO */ + +#endif /* CK_F_PR_LOAD_UINT && CK_F_PR_CAS_UINT_VALUE */ + +#if defined(CK_F_PR_LOAD_PTR) && defined(CK_F_PR_CAS_PTR_VALUE) + +#ifndef CK_F_PR_NOT_PTR +#define CK_F_PR_NOT_PTR +CK_PR_N(not, ptr, void, uintptr_t, ~, void *) +#endif /* CK_F_PR_NOT_PTR */ + +#ifndef CK_F_PR_NEG_PTR +#define CK_F_PR_NEG_PTR +CK_PR_N(neg, ptr, void, uintptr_t, -, void *) +#endif /* CK_F_PR_NEG_PTR */ + +#ifndef CK_F_PR_NEG_PTR_ZERO +#define CK_F_PR_NEG_PTR_ZERO +CK_PR_N_Z(ptr, void, uintptr_t, void *) +#endif /* CK_F_PR_NEG_PTR_ZERO */ + +#endif /* CK_F_PR_LOAD_PTR && CK_F_PR_CAS_PTR_VALUE */ + +#if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_CAS_64_VALUE) + +#ifndef CK_F_PR_NOT_64 +#define CK_F_PR_NOT_64 +CK_PR_N_S(not, 64, uint64_t, ~) +#endif /* CK_F_PR_NOT_64 */ + +#ifndef CK_F_PR_NEG_64 +#define CK_F_PR_NEG_64 +CK_PR_N_S(neg, 64, uint64_t, -) +#endif /* CK_F_PR_NEG_64 */ + +#ifndef CK_F_PR_NEG_64_ZERO +#define CK_F_PR_NEG_64_ZERO +CK_PR_N_Z_S(64, uint64_t) +#endif /* CK_F_PR_NEG_64_ZERO */ + +#endif /* CK_F_PR_LOAD_64 && CK_F_PR_CAS_64_VALUE */ + +#if defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_CAS_32_VALUE) + +#ifndef CK_F_PR_NOT_32 +#define CK_F_PR_NOT_32 +CK_PR_N_S(not, 32, uint32_t, ~) +#endif /* CK_F_PR_NOT_32 */ + +#ifndef CK_F_PR_NEG_32 +#define CK_F_PR_NEG_32 +CK_PR_N_S(neg, 32, uint32_t, -) +#endif /* CK_F_PR_NEG_32 */ + +#ifndef CK_F_PR_NEG_32_ZERO +#define CK_F_PR_NEG_32_ZERO +CK_PR_N_Z_S(32, uint32_t) +#endif /* CK_F_PR_NEG_32_ZERO */ + +#endif /* CK_F_PR_LOAD_32 && CK_F_PR_CAS_32_VALUE */ + +#if defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_CAS_16_VALUE) + +#ifndef CK_F_PR_NOT_16 +#define CK_F_PR_NOT_16 +CK_PR_N_S(not, 16, uint16_t, ~) +#endif /* CK_F_PR_NOT_16 */ + +#ifndef CK_F_PR_NEG_16 +#define CK_F_PR_NEG_16 +CK_PR_N_S(neg, 16, uint16_t, -) +#endif /* CK_F_PR_NEG_16 */ + +#ifndef CK_F_PR_NEG_16_ZERO +#define CK_F_PR_NEG_16_ZERO +CK_PR_N_Z_S(16, uint16_t) +#endif /* CK_F_PR_NEG_16_ZERO */ + +#endif /* CK_F_PR_LOAD_16 && CK_F_PR_CAS_16_VALUE */ + +#if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_CAS_8_VALUE) + +#ifndef CK_F_PR_NOT_8 +#define CK_F_PR_NOT_8 +CK_PR_N_S(not, 8, uint8_t, ~) +#endif /* CK_F_PR_NOT_8 */ + +#ifndef CK_F_PR_NEG_8 +#define CK_F_PR_NEG_8 +CK_PR_N_S(neg, 8, uint8_t, -) +#endif /* CK_F_PR_NEG_8 */ + +#ifndef CK_F_PR_NEG_8_ZERO +#define CK_F_PR_NEG_8_ZERO +CK_PR_N_Z_S(8, uint8_t) +#endif /* CK_F_PR_NEG_8_ZERO */ + +#endif /* CK_F_PR_LOAD_8 && CK_F_PR_CAS_8_VALUE */ + +#undef CK_PR_N_Z_S +#undef CK_PR_N_S +#undef CK_PR_N_Z +#undef CK_PR_N + +#define CK_PR_FAA(S, M, T, C) \ + CK_CC_INLINE static C \ + ck_pr_faa_##S(M *target, T delta) \ + { \ + T previous; \ + C punt; \ + punt = (C)ck_pr_md_load_##S(target); \ + previous = (T)punt; \ + while (ck_pr_cas_##S##_value(target, \ + (C)previous, \ + (C)(previous + delta), \ + &previous) == false) \ + ck_pr_stall(); \ + \ + return ((C)previous); \ + } + +#define CK_PR_FAS(S, M, C) \ + CK_CC_INLINE static C \ + ck_pr_fas_##S(M *target, C update) \ + { \ + C previous; \ + previous = ck_pr_md_load_##S(target); \ + while (ck_pr_cas_##S##_value(target, \ + previous, \ + update, \ + &previous) == false) \ + ck_pr_stall(); \ + \ + return (previous); \ + } + +#define CK_PR_FAA_S(S, M) CK_PR_FAA(S, M, M, M) +#define CK_PR_FAS_S(S, M) CK_PR_FAS(S, M, M) + +#if defined(CK_F_PR_LOAD_CHAR) && defined(CK_F_PR_CAS_CHAR_VALUE) + +#ifndef CK_F_PR_FAA_CHAR +#define CK_F_PR_FAA_CHAR +CK_PR_FAA_S(char, char) +#endif /* CK_F_PR_FAA_CHAR */ + +#ifndef CK_F_PR_FAS_CHAR +#define CK_F_PR_FAS_CHAR +CK_PR_FAS_S(char, char) +#endif /* CK_F_PR_FAS_CHAR */ + +#endif /* CK_F_PR_LOAD_CHAR && CK_F_PR_CAS_CHAR_VALUE */ + +#if defined(CK_F_PR_LOAD_INT) && defined(CK_F_PR_CAS_INT_VALUE) + +#ifndef CK_F_PR_FAA_INT +#define CK_F_PR_FAA_INT +CK_PR_FAA_S(int, int) +#endif /* CK_F_PR_FAA_INT */ + +#ifndef CK_F_PR_FAS_INT +#define CK_F_PR_FAS_INT +CK_PR_FAS_S(int, int) +#endif /* CK_F_PR_FAS_INT */ + +#endif /* CK_F_PR_LOAD_INT && CK_F_PR_CAS_INT_VALUE */ + +#if defined(CK_F_PR_LOAD_DOUBLE) && defined(CK_F_PR_CAS_DOUBLE_VALUE) && \ + !defined(CK_PR_DISABLE_DOUBLE) + +#ifndef CK_F_PR_FAA_DOUBLE +#define CK_F_PR_FAA_DOUBLE +CK_PR_FAA_S(double, double) +#endif /* CK_F_PR_FAA_DOUBLE */ + +#ifndef CK_F_PR_FAS_DOUBLE +#define CK_F_PR_FAS_DOUBLE +CK_PR_FAS_S(double, double) +#endif /* CK_F_PR_FAS_DOUBLE */ + +#endif /* CK_F_PR_LOAD_DOUBLE && CK_F_PR_CAS_DOUBLE_VALUE && !CK_PR_DISABLE_DOUBLE */ + +#if defined(CK_F_PR_LOAD_UINT) && defined(CK_F_PR_CAS_UINT_VALUE) + +#ifndef CK_F_PR_FAA_UINT +#define CK_F_PR_FAA_UINT +CK_PR_FAA_S(uint, unsigned int) +#endif /* CK_F_PR_FAA_UINT */ + +#ifndef CK_F_PR_FAS_UINT +#define CK_F_PR_FAS_UINT +CK_PR_FAS_S(uint, unsigned int) +#endif /* CK_F_PR_FAS_UINT */ + +#endif /* CK_F_PR_LOAD_UINT && CK_F_PR_CAS_UINT_VALUE */ + +#if defined(CK_F_PR_LOAD_PTR) && defined(CK_F_PR_CAS_PTR_VALUE) + +#ifndef CK_F_PR_FAA_PTR +#define CK_F_PR_FAA_PTR +CK_PR_FAA(ptr, void, uintptr_t, void *) +#endif /* CK_F_PR_FAA_PTR */ + +#ifndef CK_F_PR_FAS_PTR +#define CK_F_PR_FAS_PTR +CK_PR_FAS(ptr, void, void *) +#endif /* CK_F_PR_FAS_PTR */ + +#endif /* CK_F_PR_LOAD_PTR && CK_F_PR_CAS_PTR_VALUE */ + +#if defined(CK_F_PR_LOAD_64) && defined(CK_F_PR_CAS_64_VALUE) + +#ifndef CK_F_PR_FAA_64 +#define CK_F_PR_FAA_64 +CK_PR_FAA_S(64, uint64_t) +#endif /* CK_F_PR_FAA_64 */ + +#ifndef CK_F_PR_FAS_64 +#define CK_F_PR_FAS_64 +CK_PR_FAS_S(64, uint64_t) +#endif /* CK_F_PR_FAS_64 */ + +#endif /* CK_F_PR_LOAD_64 && CK_F_PR_CAS_64_VALUE */ + +#if defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_CAS_32_VALUE) + +#ifndef CK_F_PR_FAA_32 +#define CK_F_PR_FAA_32 +CK_PR_FAA_S(32, uint32_t) +#endif /* CK_F_PR_FAA_32 */ + +#ifndef CK_F_PR_FAS_32 +#define CK_F_PR_FAS_32 +CK_PR_FAS_S(32, uint32_t) +#endif /* CK_F_PR_FAS_32 */ + +#endif /* CK_F_PR_LOAD_32 && CK_F_PR_CAS_32_VALUE */ + +#if defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_CAS_16_VALUE) + +#ifndef CK_F_PR_FAA_16 +#define CK_F_PR_FAA_16 +CK_PR_FAA_S(16, uint16_t) +#endif /* CK_F_PR_FAA_16 */ + +#ifndef CK_F_PR_FAS_16 +#define CK_F_PR_FAS_16 +CK_PR_FAS_S(16, uint16_t) +#endif /* CK_F_PR_FAS_16 */ + +#endif /* CK_F_PR_LOAD_16 && CK_F_PR_CAS_16_VALUE */ + +#if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_CAS_8_VALUE) + +#ifndef CK_F_PR_FAA_8 +#define CK_F_PR_FAA_8 +CK_PR_FAA_S(8, uint8_t) +#endif /* CK_F_PR_FAA_8 */ + +#ifndef CK_F_PR_FAS_8 +#define CK_F_PR_FAS_8 +CK_PR_FAS_S(8, uint8_t) +#endif /* CK_F_PR_FAS_8 */ + +#endif /* CK_F_PR_LOAD_8 && CK_F_PR_CAS_8_VALUE */ + +#undef CK_PR_FAA_S +#undef CK_PR_FAS_S +#undef CK_PR_FAA +#undef CK_PR_FAS + +#endif /* CK_PR_H */ diff --git a/freebsd/sys/contrib/ck/include/ck_queue.h b/freebsd/sys/contrib/ck/include/ck_queue.h new file mode 100644 index 00000000..faf96a17 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_queue.h @@ -0,0 +1,428 @@ +/* + * Copyright 2012-2015 Samy Al Bahra. + * 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. + */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD$ + */ + +#ifndef CK_QUEUE_H +#define CK_QUEUE_H + +#include <ck_pr.h> + +/* + * This file defines three types of data structures: singly-linked lists, + * singly-linked tail queues and lists. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * It is safe to use _FOREACH/_FOREACH_SAFE in the presence of concurrent + * modifications to the list. Writers to these lists must, on the other hand, + * implement writer-side synchronization. The _SWAP operations are not atomic. + * This facility is currently unsupported on architectures such as the Alpha + * which require load-depend memory fences. + * + * CK_SLIST CK_LIST CK_STAILQ + * _HEAD + + + + * _HEAD_INITIALIZER + + + + * _ENTRY + + + + * _INIT + + + + * _EMPTY + + + + * _FIRST + + + + * _NEXT + + + + * _FOREACH + + + + * _FOREACH_SAFE + + + + * _INSERT_HEAD + + + + * _INSERT_BEFORE - + - + * _INSERT_AFTER + + + + * _INSERT_TAIL - - + + * _REMOVE_AFTER + - + + * _REMOVE_HEAD + - + + * _REMOVE + + + + * _SWAP + + + + * _MOVE + + + + */ + +/* + * Singly-linked List declarations. + */ +#define CK_SLIST_HEAD(name, type) \ +struct name { \ + struct type *cslh_first; /* first element */ \ +} + +#define CK_SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define CK_SLIST_ENTRY(type) \ +struct { \ + struct type *csle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define CK_SLIST_EMPTY(head) \ + (ck_pr_load_ptr(&(head)->cslh_first) == NULL) + +#define CK_SLIST_FIRST(head) \ + (ck_pr_load_ptr(&(head)->cslh_first)) + +#define CK_SLIST_NEXT(elm, field) \ + ck_pr_load_ptr(&((elm)->field.csle_next)) + +#define CK_SLIST_FOREACH(var, head, field) \ + for ((var) = CK_SLIST_FIRST((head)); \ + (var) && (ck_pr_fence_load(), 1); \ + (var) = CK_SLIST_NEXT((var), field)) + +#define CK_SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = CK_SLIST_FIRST(head); \ + (var) && (ck_pr_fence_load(), (tvar) = CK_SLIST_NEXT(var, field), 1);\ + (var) = (tvar)) + +#define CK_SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &(head)->cslh_first; \ + ((var) = ck_pr_load_ptr(varp)) != NULL && (ck_pr_fence_load(), 1); \ + (varp) = &(var)->field.csle_next) + +#define CK_SLIST_INIT(head) do { \ + ck_pr_store_ptr(&(head)->cslh_first, NULL); \ + ck_pr_fence_store(); \ +} while (0) + +#define CK_SLIST_INSERT_AFTER(a, b, field) do { \ + (b)->field.csle_next = (a)->field.csle_next; \ + ck_pr_fence_store(); \ + ck_pr_store_ptr(&(a)->field.csle_next, b); \ +} while (0) + +#define CK_SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.csle_next = (head)->cslh_first; \ + ck_pr_fence_store(); \ + ck_pr_store_ptr(&(head)->cslh_first, elm); \ +} while (0) + +#define CK_SLIST_REMOVE_AFTER(elm, field) do { \ + ck_pr_store_ptr(&(elm)->field.csle_next, \ + (elm)->field.csle_next->field.csle_next); \ +} while (0) + +#define CK_SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->cslh_first == (elm)) { \ + CK_SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->cslh_first; \ + while (curelm->field.csle_next != (elm)) \ + curelm = curelm->field.csle_next; \ + CK_SLIST_REMOVE_AFTER(curelm, field); \ + } \ +} while (0) + +#define CK_SLIST_REMOVE_HEAD(head, field) do { \ + ck_pr_store_ptr(&(head)->cslh_first, \ + (head)->cslh_first->field.csle_next); \ +} while (0) + +#define CK_SLIST_MOVE(head1, head2, field) do { \ + ck_pr_store_ptr(&(head1)->cslh_first, (head2)->cslh_first); \ +} while (0) + +/* + * This operation is not applied atomically. + */ +#define CK_SLIST_SWAP(a, b, type) do { \ + struct type *swap_first = (a)->cslh_first; \ + (a)->cslh_first = (b)->cslh_first; \ + (b)->cslh_first = swap_first; \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define CK_STAILQ_HEAD(name, type) \ +struct name { \ + struct type *cstqh_first;/* first element */ \ + struct type **cstqh_last;/* addr of last next element */ \ +} + +#define CK_STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).cstqh_first } + +#define CK_STAILQ_ENTRY(type) \ +struct { \ + struct type *cstqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define CK_STAILQ_CONCAT(head1, head2) do { \ + if ((head2)->cstqh_first != NULL) { \ + ck_pr_store_ptr((head1)->cstqh_last, (head2)->cstqh_first); \ + ck_pr_fence_store(); \ + (head1)->cstqh_last = (head2)->cstqh_last; \ + CK_STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define CK_STAILQ_EMPTY(head) (ck_pr_load_ptr(&(head)->cstqh_first) == NULL) + +#define CK_STAILQ_FIRST(head) (ck_pr_load_ptr(&(head)->cstqh_first)) + +#define CK_STAILQ_FOREACH(var, head, field) \ + for((var) = CK_STAILQ_FIRST((head)); \ + (var) && (ck_pr_fence_load(), 1); \ + (var) = CK_STAILQ_NEXT((var), field)) + +#define CK_STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = CK_STAILQ_FIRST((head)); \ + (var) && (ck_pr_fence_load(), (tvar) = \ + CK_STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define CK_STAILQ_INIT(head) do { \ + ck_pr_store_ptr(&(head)->cstqh_first, NULL); \ + ck_pr_fence_store(); \ + (head)->cstqh_last = &(head)->cstqh_first; \ +} while (0) + +#define CK_STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + (elm)->field.cstqe_next = (tqelm)->field.cstqe_next; \ + ck_pr_fence_store(); \ + ck_pr_store_ptr(&(tqelm)->field.cstqe_next, elm); \ + if ((elm)->field.cstqe_next == NULL) \ + (head)->cstqh_last = &(elm)->field.cstqe_next; \ +} while (0) + +#define CK_STAILQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cstqe_next = (head)->cstqh_first; \ + ck_pr_fence_store(); \ + ck_pr_store_ptr(&(head)->cstqh_first, elm); \ + if ((elm)->field.cstqe_next == NULL) \ + (head)->cstqh_last = &(elm)->field.cstqe_next; \ +} while (0) + +#define CK_STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cstqe_next = NULL; \ + ck_pr_fence_store(); \ + ck_pr_store_ptr((head)->cstqh_last, (elm)); \ + (head)->cstqh_last = &(elm)->field.cstqe_next; \ +} while (0) + +#define CK_STAILQ_NEXT(elm, field) \ + (ck_pr_load_ptr(&(elm)->field.cstqe_next)) + +#define CK_STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->cstqh_first == (elm)) { \ + CK_STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->cstqh_first; \ + while (curelm->field.cstqe_next != (elm)) \ + curelm = curelm->field.cstqe_next; \ + CK_STAILQ_REMOVE_AFTER(head, curelm, field); \ + } \ +} while (0) + +#define CK_STAILQ_REMOVE_AFTER(head, elm, field) do { \ + ck_pr_store_ptr(&(elm)->field.cstqe_next, \ + (elm)->field.cstqe_next->field.cstqe_next); \ + if ((elm)->field.cstqe_next == NULL) \ + (head)->cstqh_last = &(elm)->field.cstqe_next; \ +} while (0) + +#define CK_STAILQ_REMOVE_HEAD(head, field) do { \ + ck_pr_store_ptr(&(head)->cstqh_first, \ + (head)->cstqh_first->field.cstqe_next); \ + if ((head)->cstqh_first == NULL) \ + (head)->cstqh_last = &(head)->cstqh_first; \ +} while (0) + +#define CK_STAILQ_MOVE(head1, head2, field) do { \ + ck_pr_store_ptr(&(head1)->cstqh_first, (head2)->cstqh_first); \ + (head1)->cstqh_last = (head2)->cstqh_last; \ + if ((head2)->cstqh_last == &(head2)->cstqh_first) \ + (head1)->cstqh_last = &(head1)->cstqh_first; \ +} while (0) + +/* + * This operation is not applied atomically. + */ +#define CK_STAILQ_SWAP(head1, head2, type) do { \ + struct type *swap_first = CK_STAILQ_FIRST(head1); \ + struct type **swap_last = (head1)->cstqh_last; \ + CK_STAILQ_FIRST(head1) = CK_STAILQ_FIRST(head2); \ + (head1)->cstqh_last = (head2)->cstqh_last; \ + CK_STAILQ_FIRST(head2) = swap_first; \ + (head2)->cstqh_last = swap_last; \ + if (CK_STAILQ_EMPTY(head1)) \ + (head1)->cstqh_last = &(head1)->cstqh_first; \ + if (CK_STAILQ_EMPTY(head2)) \ + (head2)->cstqh_last = &(head2)->cstqh_first; \ +} while (0) + +/* + * List declarations. + */ +#define CK_LIST_HEAD(name, type) \ +struct name { \ + struct type *clh_first; /* first element */ \ +} + +#define CK_LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define CK_LIST_ENTRY(type) \ +struct { \ + struct type *cle_next; /* next element */ \ + struct type **cle_prev; /* address of previous next element */ \ +} + +#define CK_LIST_FIRST(head) ck_pr_load_ptr(&(head)->clh_first) +#define CK_LIST_EMPTY(head) (CK_LIST_FIRST(head) == NULL) +#define CK_LIST_NEXT(elm, field) ck_pr_load_ptr(&(elm)->field.cle_next) + +#define CK_LIST_FOREACH(var, head, field) \ + for ((var) = CK_LIST_FIRST((head)); \ + (var) && (ck_pr_fence_load(), 1); \ + (var) = CK_LIST_NEXT((var), field)) + +#define CK_LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = CK_LIST_FIRST((head)); \ + (var) && (ck_pr_fence_load(), (tvar) = CK_LIST_NEXT((var), field), 1);\ + (var) = (tvar)) + +#define CK_LIST_INIT(head) do { \ + ck_pr_store_ptr(&(head)->clh_first, NULL); \ + ck_pr_fence_store(); \ +} while (0) + +#define CK_LIST_INSERT_AFTER(listelm, elm, field) do { \ + (elm)->field.cle_next = (listelm)->field.cle_next; \ + (elm)->field.cle_prev = &(listelm)->field.cle_next; \ + ck_pr_fence_store(); \ + if ((listelm)->field.cle_next != NULL) \ + (listelm)->field.cle_next->field.cle_prev = &(elm)->field.cle_next;\ + ck_pr_store_ptr(&(listelm)->field.cle_next, elm); \ +} while (0) + +#define CK_LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.cle_prev = (listelm)->field.cle_prev; \ + (elm)->field.cle_next = (listelm); \ + ck_pr_fence_store(); \ + ck_pr_store_ptr((listelm)->field.cle_prev, (elm)); \ + (listelm)->field.cle_prev = &(elm)->field.cle_next; \ +} while (0) + +#define CK_LIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cle_next = (head)->clh_first; \ + ck_pr_fence_store(); \ + if ((elm)->field.cle_next != NULL) \ + (head)->clh_first->field.cle_prev = &(elm)->field.cle_next; \ + ck_pr_store_ptr(&(head)->clh_first, elm); \ + (elm)->field.cle_prev = &(head)->clh_first; \ +} while (0) + +#define CK_LIST_REMOVE(elm, field) do { \ + ck_pr_store_ptr((elm)->field.cle_prev, (elm)->field.cle_next); \ + if ((elm)->field.cle_next != NULL) \ + (elm)->field.cle_next->field.cle_prev = (elm)->field.cle_prev; \ +} while (0) + +#define CK_LIST_MOVE(head1, head2, field) do { \ + ck_pr_store_ptr(&(head1)->clh_first, (head2)->clh_first); \ + if ((head1)->clh_first != NULL) \ + (head1)->clh_first->field.cle_prev = &(head1)->clh_first; \ +} while (0) + +/* + * This operation is not applied atomically. + */ +#define CK_LIST_SWAP(head1, head2, type, field) do { \ + struct type *swap_tmp = (head1)->clh_first; \ + (head1)->clh_first = (head2)->clh_first; \ + (head2)->clh_first = swap_tmp; \ + if ((swap_tmp = (head1)->clh_first) != NULL) \ + swap_tmp->field.cle_prev = &(head1)->clh_first; \ + if ((swap_tmp = (head2)->clh_first) != NULL) \ + swap_tmp->field.cle_prev = &(head2)->clh_first; \ +} while (0) + +#endif /* CK_QUEUE_H */ diff --git a/freebsd/sys/contrib/ck/include/ck_stack.h b/freebsd/sys/contrib/ck/include/ck_stack.h new file mode 100644 index 00000000..eb2b685f --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_stack.h @@ -0,0 +1,357 @@ +/* + * Copyright 2009-2015 Samy Al Bahra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_STACK_H +#define CK_STACK_H + +#include <ck_cc.h> +#include <ck_pr.h> +#include <ck_stdbool.h> +#include <ck_stddef.h> + +struct ck_stack_entry { + struct ck_stack_entry *next; +}; +typedef struct ck_stack_entry ck_stack_entry_t; + +struct ck_stack { + struct ck_stack_entry *head; + char *generation CK_CC_PACKED; +} CK_CC_ALIASED; +typedef struct ck_stack ck_stack_t; + +#define CK_STACK_INITIALIZER { NULL, NULL } + +#ifndef CK_F_STACK_PUSH_UPMC +#define CK_F_STACK_PUSH_UPMC +/* + * Stack producer operation safe for multiple unique producers and multiple consumers. + */ +CK_CC_INLINE static void +ck_stack_push_upmc(struct ck_stack *target, struct ck_stack_entry *entry) +{ + struct ck_stack_entry *stack; + + stack = ck_pr_load_ptr(&target->head); + entry->next = stack; + ck_pr_fence_store(); + + while (ck_pr_cas_ptr_value(&target->head, stack, entry, &stack) == false) { + entry->next = stack; + ck_pr_fence_store(); + } + + return; +} +#endif /* CK_F_STACK_PUSH_UPMC */ + +#ifndef CK_F_STACK_TRYPUSH_UPMC +#define CK_F_STACK_TRYPUSH_UPMC +/* + * Stack producer operation for multiple unique producers and multiple consumers. + * Returns true on success and false on failure. + */ +CK_CC_INLINE static bool +ck_stack_trypush_upmc(struct ck_stack *target, struct ck_stack_entry *entry) +{ + struct ck_stack_entry *stack; + + stack = ck_pr_load_ptr(&target->head); + entry->next = stack; + ck_pr_fence_store(); + + return ck_pr_cas_ptr(&target->head, stack, entry); +} +#endif /* CK_F_STACK_TRYPUSH_UPMC */ + +#ifndef CK_F_STACK_POP_UPMC +#define CK_F_STACK_POP_UPMC +/* + * Stack consumer operation safe for multiple unique producers and multiple consumers. + */ +CK_CC_INLINE static struct ck_stack_entry * +ck_stack_pop_upmc(struct ck_stack *target) +{ + struct ck_stack_entry *entry, *next; + + entry = ck_pr_load_ptr(&target->head); + if (entry == NULL) + return NULL; + + ck_pr_fence_load(); + next = entry->next; + while (ck_pr_cas_ptr_value(&target->head, entry, next, &entry) == false) { + if (entry == NULL) + break; + + ck_pr_fence_load(); + next = entry->next; + } + + return entry; +} +#endif + +#ifndef CK_F_STACK_TRYPOP_UPMC +#define CK_F_STACK_TRYPOP_UPMC +/* + * Stack production operation for multiple unique producers and multiple consumers. + * Returns true on success and false on failure. The value pointed to by the second + * argument is set to a valid ck_stack_entry_t reference if true is returned. If + * false is returned, then the value pointed to by the second argument is undefined. + */ +CK_CC_INLINE static bool +ck_stack_trypop_upmc(struct ck_stack *target, struct ck_stack_entry **r) +{ + struct ck_stack_entry *entry; + + entry = ck_pr_load_ptr(&target->head); + if (entry == NULL) + return false; + + ck_pr_fence_load(); + if (ck_pr_cas_ptr(&target->head, entry, entry->next) == true) { + *r = entry; + return true; + } + + return false; +} +#endif /* CK_F_STACK_TRYPOP_UPMC */ + +#ifndef CK_F_STACK_BATCH_POP_UPMC +#define CK_F_STACK_BATCH_POP_UPMC +/* + * Pop all items off the stack. + */ +CK_CC_INLINE static struct ck_stack_entry * +ck_stack_batch_pop_upmc(struct ck_stack *target) +{ + struct ck_stack_entry *entry; + + entry = ck_pr_fas_ptr(&target->head, NULL); + ck_pr_fence_load(); + return entry; +} +#endif /* CK_F_STACK_BATCH_POP_UPMC */ + +#ifndef CK_F_STACK_PUSH_MPMC +#define CK_F_STACK_PUSH_MPMC +/* + * Stack producer operation safe for multiple producers and multiple consumers. + */ +CK_CC_INLINE static void +ck_stack_push_mpmc(struct ck_stack *target, struct ck_stack_entry *entry) +{ + + ck_stack_push_upmc(target, entry); + return; +} +#endif /* CK_F_STACK_PUSH_MPMC */ + +#ifndef CK_F_STACK_TRYPUSH_MPMC +#define CK_F_STACK_TRYPUSH_MPMC +/* + * Stack producer operation safe for multiple producers and multiple consumers. + */ +CK_CC_INLINE static bool +ck_stack_trypush_mpmc(struct ck_stack *target, struct ck_stack_entry *entry) +{ + + return ck_stack_trypush_upmc(target, entry); +} +#endif /* CK_F_STACK_TRYPUSH_MPMC */ + +#ifdef CK_F_PR_CAS_PTR_2_VALUE +#ifndef CK_F_STACK_POP_MPMC +#define CK_F_STACK_POP_MPMC +/* + * Stack consumer operation safe for multiple producers and multiple consumers. + */ +CK_CC_INLINE static struct ck_stack_entry * +ck_stack_pop_mpmc(struct ck_stack *target) +{ + struct ck_stack original, update; + + original.generation = ck_pr_load_ptr(&target->generation); + ck_pr_fence_load(); + original.head = ck_pr_load_ptr(&target->head); + if (original.head == NULL) + return NULL; + + /* Order with respect to next pointer. */ + ck_pr_fence_load(); + + update.generation = original.generation + 1; + update.head = original.head->next; + + while (ck_pr_cas_ptr_2_value(target, &original, &update, &original) == false) { + if (original.head == NULL) + return NULL; + + update.generation = original.generation + 1; + + /* Order with respect to next pointer. */ + ck_pr_fence_load(); + update.head = original.head->next; + } + + return original.head; +} +#endif /* CK_F_STACK_POP_MPMC */ + +#ifndef CK_F_STACK_TRYPOP_MPMC +#define CK_F_STACK_TRYPOP_MPMC +CK_CC_INLINE static bool +ck_stack_trypop_mpmc(struct ck_stack *target, struct ck_stack_entry **r) +{ + struct ck_stack original, update; + + original.generation = ck_pr_load_ptr(&target->generation); + ck_pr_fence_load(); + original.head = ck_pr_load_ptr(&target->head); + if (original.head == NULL) + return false; + + update.generation = original.generation + 1; + ck_pr_fence_load(); + update.head = original.head->next; + + if (ck_pr_cas_ptr_2_value(target, &original, &update, &original) == true) { + *r = original.head; + return true; + } + + return false; +} +#endif /* CK_F_STACK_TRYPOP_MPMC */ +#endif /* CK_F_PR_CAS_PTR_2_VALUE */ + +#ifndef CK_F_STACK_BATCH_POP_MPMC +#define CK_F_STACK_BATCH_POP_MPMC +/* + * This is equivalent to the UP/MC version as NULL does not need a + * a generation count. + */ +CK_CC_INLINE static struct ck_stack_entry * +ck_stack_batch_pop_mpmc(struct ck_stack *target) +{ + + return ck_stack_batch_pop_upmc(target); +} +#endif /* CK_F_STACK_BATCH_POP_MPMC */ + +#ifndef CK_F_STACK_PUSH_MPNC +#define CK_F_STACK_PUSH_MPNC +/* + * Stack producer operation safe with no concurrent consumers. + */ +CK_CC_INLINE static void +ck_stack_push_mpnc(struct ck_stack *target, struct ck_stack_entry *entry) +{ + struct ck_stack_entry *stack; + + entry->next = NULL; + ck_pr_fence_store_atomic(); + stack = ck_pr_fas_ptr(&target->head, entry); + ck_pr_store_ptr(&entry->next, stack); + ck_pr_fence_store(); + + return; +} +#endif /* CK_F_STACK_PUSH_MPNC */ + +/* + * Stack producer operation for single producer and no concurrent consumers. + */ +CK_CC_INLINE static void +ck_stack_push_spnc(struct ck_stack *target, struct ck_stack_entry *entry) +{ + + entry->next = target->head; + target->head = entry; + return; +} + +/* + * Stack consumer operation for no concurrent producers and single consumer. + */ +CK_CC_INLINE static struct ck_stack_entry * +ck_stack_pop_npsc(struct ck_stack *target) +{ + struct ck_stack_entry *n; + + if (target->head == NULL) + return NULL; + + n = target->head; + target->head = n->next; + + return n; +} + +/* + * Pop all items off a stack. + */ +CK_CC_INLINE static struct ck_stack_entry * +ck_stack_batch_pop_npsc(struct ck_stack *target) +{ + struct ck_stack_entry *n; + + n = target->head; + target->head = NULL; + + return n; +} + +/* + * Stack initialization function. Guarantees initialization across processors. + */ +CK_CC_INLINE static void +ck_stack_init(struct ck_stack *stack) +{ + + stack->head = NULL; + stack->generation = NULL; + return; +} + +/* Defines a container_of functions for */ +#define CK_STACK_CONTAINER(T, M, N) CK_CC_CONTAINER(ck_stack_entry_t, T, M, N) + +#define CK_STACK_ISEMPTY(m) ((m)->head == NULL) +#define CK_STACK_FIRST(s) ((s)->head) +#define CK_STACK_NEXT(m) ((m)->next) +#define CK_STACK_FOREACH(stack, entry) \ + for ((entry) = CK_STACK_FIRST(stack); \ + (entry) != NULL; \ + (entry) = CK_STACK_NEXT(entry)) +#define CK_STACK_FOREACH_SAFE(stack, entry, T) \ + for ((entry) = CK_STACK_FIRST(stack); \ + (entry) != NULL && ((T) = (entry)->next, 1); \ + (entry) = (T)) + +#endif /* CK_STACK_H */ diff --git a/freebsd/sys/contrib/ck/include/ck_stdbool.h b/freebsd/sys/contrib/ck/include/ck_stdbool.h new file mode 100644 index 00000000..b9a79829 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_stdbool.h @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Olivier Houchard. + * 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. + */ + +#if defined(__FreeBSD__) && defined(_KERNEL) +#include <sys/types.h> +#else +#include <stdbool.h> +#endif diff --git a/freebsd/sys/contrib/ck/include/ck_stddef.h b/freebsd/sys/contrib/ck/include/ck_stddef.h new file mode 100644 index 00000000..6019ea95 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_stddef.h @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Olivier Houchard. + * 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. + */ + +#if defined(__FreeBSD__) && defined(_KERNEL) +#include <sys/stddef.h> +#else +#include <stddef.h> +#endif diff --git a/freebsd/sys/contrib/ck/include/ck_stdint.h b/freebsd/sys/contrib/ck/include/ck_stdint.h new file mode 100644 index 00000000..8f416a92 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_stdint.h @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2015 Samy Al Bahra. + * 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. + */ + +#if defined(__linux__) && defined(__KERNEL__) +#include <linux/kernel.h> +#include <linux/types.h> +#elif defined(__FreeBSD__) && defined(_KERNEL) +#include <sys/stdint.h> +#else +#include <stdint.h> +#endif /* __linux__ && __KERNEL__ */ diff --git a/freebsd/sys/contrib/ck/include/ck_string.h b/freebsd/sys/contrib/ck/include/ck_string.h new file mode 100644 index 00000000..8d2c2525 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/ck_string.h @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Olivier Houchard. + * 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. + */ + +#if defined(__FreeBSD__) && defined(_KERNEL) +#include <sys/systm.h> +#else +#include <string.h> +#endif diff --git a/freebsd/sys/contrib/ck/include/gcc/aarch64/ck_f_pr.h b/freebsd/sys/contrib/ck/include/gcc/aarch64/ck_f_pr.h new file mode 100644 index 00000000..93ecee07 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/aarch64/ck_f_pr.h @@ -0,0 +1,167 @@ +/* DO NOT EDIT. This is auto-generated from feature.sh */ +#define CK_F_PR_ADD_16 +#define CK_F_PR_ADD_32 +#define CK_F_PR_ADD_64 +#define CK_F_PR_ADD_8 +#define CK_F_PR_ADD_CHAR +#define CK_F_PR_ADD_INT +#define CK_F_PR_ADD_PTR +#define CK_F_PR_ADD_SHORT +#define CK_F_PR_ADD_UINT +#define CK_F_PR_AND_16 +#define CK_F_PR_AND_32 +#define CK_F_PR_AND_64 +#define CK_F_PR_AND_8 +#define CK_F_PR_AND_CHAR +#define CK_F_PR_AND_INT +#define CK_F_PR_AND_PTR +#define CK_F_PR_AND_SHORT +#define CK_F_PR_AND_UINT +#define CK_F_PR_BARRIER +#define CK_F_PR_CAS_16 +#define CK_F_PR_CAS_16_VALUE +#define CK_F_PR_CAS_32 +#define CK_F_PR_CAS_32_VALUE +#define CK_F_PR_CAS_64 +#define CK_F_PR_CAS_64_VALUE +#define CK_F_PR_CAS_64_2 +#define CK_F_PR_CAS_64_2_VALUE +#define CK_F_PR_CAS_DOUBLE +#define CK_F_PR_CAS_DOUBLE_VALUE +#define CK_F_PR_CAS_8 +#define CK_F_PR_CAS_8_VALUE +#define CK_F_PR_CAS_CHAR +#define CK_F_PR_CAS_CHAR_VALUE +#define CK_F_PR_CAS_INT +#define CK_F_PR_CAS_INT_VALUE +#define CK_F_PR_CAS_PTR +#define CK_F_PR_CAS_PTR_2 +#define CK_F_PR_CAS_PTR_2_VALUE +#define CK_F_PR_CAS_PTR_VALUE +#define CK_F_PR_CAS_SHORT +#define CK_F_PR_CAS_SHORT_VALUE +#define CK_F_PR_CAS_UINT +#define CK_F_PR_CAS_UINT_VALUE +#define CK_F_PR_DEC_16 +#define CK_F_PR_DEC_32 +#define CK_F_PR_DEC_64 +#define CK_F_PR_DEC_8 +#define CK_F_PR_DEC_CHAR +#define CK_F_PR_DEC_INT +#define CK_F_PR_DEC_PTR +#define CK_F_PR_DEC_SHORT +#define CK_F_PR_DEC_UINT +#define CK_F_PR_FAA_16 +#define CK_F_PR_FAA_32 +#define CK_F_PR_FAA_64 +#define CK_F_PR_FAA_8 +#define CK_F_PR_FAA_CHAR +#define CK_F_PR_FAA_INT +#define CK_F_PR_FAA_PTR +#define CK_F_PR_FAA_SHORT +#define CK_F_PR_FAA_UINT +#define CK_F_PR_FAS_16 +#define CK_F_PR_FAS_32 +#define CK_F_PR_FAS_64 +#define CK_F_PR_FAS_8 +#define CK_F_PR_FAS_CHAR +#define CK_F_PR_FAS_INT +#define CK_F_PR_FAS_PTR +#define CK_F_PR_FAS_SHORT +#define CK_F_PR_FAS_UINT +#define CK_F_PR_FENCE_ATOMIC +#define CK_F_PR_FENCE_ATOMIC_LOAD +#define CK_F_PR_FENCE_ATOMIC_STORE +#define CK_F_PR_FENCE_LOAD +#define CK_F_PR_FENCE_LOAD_ATOMIC +#define CK_F_PR_FENCE_LOAD_DEPENDS +#define CK_F_PR_FENCE_LOAD_STORE +#define CK_F_PR_FENCE_MEMORY +#define CK_F_PR_FENCE_STORE +#define CK_F_PR_FENCE_STORE_ATOMIC +#define CK_F_PR_FENCE_STORE_LOAD +#define CK_F_PR_FENCE_STRICT_ATOMIC +#define CK_F_PR_FENCE_STRICT_ATOMIC_LOAD +#define CK_F_PR_FENCE_STRICT_ATOMIC_STORE +#define CK_F_PR_FENCE_STRICT_LOAD +#define CK_F_PR_FENCE_STRICT_LOAD_ATOMIC +#define CK_F_PR_FENCE_STRICT_LOAD_STORE +#define CK_F_PR_FENCE_STRICT_MEMORY +#define CK_F_PR_FENCE_STRICT_STORE +#define CK_F_PR_FENCE_STRICT_STORE_ATOMIC +#define CK_F_PR_FENCE_STRICT_STORE_LOAD +#define CK_F_PR_INC_16 +#define CK_F_PR_INC_32 +#define CK_F_PR_INC_64 +#define CK_F_PR_INC_8 +#define CK_F_PR_INC_CHAR +#define CK_F_PR_INC_INT +#define CK_F_PR_INC_PTR +#define CK_F_PR_INC_SHORT +#define CK_F_PR_INC_UINT +#define CK_F_PR_LOAD_16 +#define CK_F_PR_LOAD_32 +#define CK_F_PR_LOAD_64 +#define CK_F_PR_LOAD_DOUBLE +#define CK_F_PR_LOAD_8 +#define CK_F_PR_LOAD_CHAR +#define CK_F_PR_LOAD_INT +#define CK_F_PR_LOAD_PTR +#define CK_F_PR_LOAD_SHORT +#define CK_F_PR_LOAD_UINT +#define CK_F_PR_NEG_16 +#define CK_F_PR_NEG_32 +#define CK_F_PR_NEG_64 +#define CK_F_PR_NEG_8 +#define CK_F_PR_NEG_CHAR +#define CK_F_PR_NEG_INT +#define CK_F_PR_NEG_PTR +#define CK_F_PR_NEG_SHORT +#define CK_F_PR_NEG_UINT +#define CK_F_PR_NOT_16 +#define CK_F_PR_NOT_32 +#define CK_F_PR_NOT_64 +#define CK_F_PR_NOT_8 +#define CK_F_PR_NOT_CHAR +#define CK_F_PR_NOT_INT +#define CK_F_PR_NOT_PTR +#define CK_F_PR_NOT_SHORT +#define CK_F_PR_NOT_UINT +#define CK_F_PR_OR_16 +#define CK_F_PR_OR_32 +#define CK_F_PR_OR_64 +#define CK_F_PR_OR_8 +#define CK_F_PR_OR_CHAR +#define CK_F_PR_OR_INT +#define CK_F_PR_OR_PTR +#define CK_F_PR_OR_SHORT +#define CK_F_PR_OR_UINT +#define CK_F_PR_STALL +#define CK_F_PR_STORE_16 +#define CK_F_PR_STORE_32 +#define CK_F_PR_STORE_64 +#define CK_F_PR_STORE_DOUBLE +#define CK_F_PR_STORE_8 +#define CK_F_PR_STORE_CHAR +#define CK_F_PR_STORE_INT +#define CK_F_PR_STORE_PTR +#define CK_F_PR_STORE_SHORT +#define CK_F_PR_STORE_UINT +#define CK_F_PR_SUB_16 +#define CK_F_PR_SUB_32 +#define CK_F_PR_SUB_64 +#define CK_F_PR_SUB_8 +#define CK_F_PR_SUB_CHAR +#define CK_F_PR_SUB_INT +#define CK_F_PR_SUB_PTR +#define CK_F_PR_SUB_SHORT +#define CK_F_PR_SUB_UINT +#define CK_F_PR_XOR_16 +#define CK_F_PR_XOR_32 +#define CK_F_PR_XOR_64 +#define CK_F_PR_XOR_8 +#define CK_F_PR_XOR_CHAR +#define CK_F_PR_XOR_INT +#define CK_F_PR_XOR_PTR +#define CK_F_PR_XOR_SHORT +#define CK_F_PR_XOR_UINT diff --git a/freebsd/sys/contrib/ck/include/gcc/aarch64/ck_pr.h b/freebsd/sys/contrib/ck/include/gcc/aarch64/ck_pr.h new file mode 100644 index 00000000..e739c4d5 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/aarch64/ck_pr.h @@ -0,0 +1,227 @@ +/* + * Copyright 2009-2016 Samy Al Bahra. + * Copyright 2013-2016 Olivier Houchard. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_PR_AARCH64_H +#define CK_PR_AARCH64_H + +#ifndef CK_PR_H +#error Do not include this file directly, use ck_pr.h +#endif + +#include <ck_cc.h> +#include <ck_md.h> + +/* + * The following represent supported atomic operations. + * These operations may be emulated. + */ +#include "ck_f_pr.h" + +/* + * Minimum interface requirement met. + */ +#define CK_F_PR + +CK_CC_INLINE static void +ck_pr_stall(void) +{ + + __asm__ __volatile__("" ::: "memory"); + return; +} + +#define CK_DMB_SY __asm __volatile("dmb ish" : : "r" (0) : "memory") +#define CK_DMB_LD __asm __volatile("dmb ishld" : : "r" (0) : "memory") +#define CK_DMB_ST __asm __volatile("dmb ishst" : : "r" (0) : "memory") + +#define CK_PR_FENCE(T, I) \ + CK_CC_INLINE static void \ + ck_pr_fence_strict_##T(void) \ + { \ + I; \ + } + +CK_PR_FENCE(atomic, CK_DMB_ST) +CK_PR_FENCE(atomic_store, CK_DMB_ST) +CK_PR_FENCE(atomic_load, CK_DMB_SY) +CK_PR_FENCE(store_atomic, CK_DMB_ST) +CK_PR_FENCE(load_atomic, CK_DMB_SY) +CK_PR_FENCE(store, CK_DMB_ST) +CK_PR_FENCE(store_load, CK_DMB_SY) +CK_PR_FENCE(load, CK_DMB_LD) +CK_PR_FENCE(load_store, CK_DMB_SY) +CK_PR_FENCE(memory, CK_DMB_SY) +CK_PR_FENCE(acquire, CK_DMB_SY) +CK_PR_FENCE(release, CK_DMB_SY) +CK_PR_FENCE(acqrel, CK_DMB_SY) +CK_PR_FENCE(lock, CK_DMB_SY) +CK_PR_FENCE(unlock, CK_DMB_SY) + +#undef CK_PR_FENCE + +#undef CK_DMB_SI +#undef CK_DMB_LD +#undef CK_DMB_ST + +#define CK_PR_LOAD(S, M, T, I) \ + CK_CC_INLINE static T \ + ck_pr_md_load_##S(const M *target) \ + { \ + long r = 0; \ + __asm__ __volatile__(I " %w0, [%1];" \ + : "=r" (r) \ + : "r" (target) \ + : "memory"); \ + return ((T)r); \ + } +#define CK_PR_LOAD_64(S, M, T, I) \ + CK_CC_INLINE static T \ + ck_pr_md_load_##S(const M *target) \ + { \ + long r = 0; \ + __asm__ __volatile__(I " %0, [%1];" \ + : "=r" (r) \ + : "r" (target) \ + : "memory"); \ + return ((T)r); \ + } + + +CK_PR_LOAD_64(ptr, void, void *, "ldr") + +#define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, I) +#define CK_PR_LOAD_S_64(S, T, I) CK_PR_LOAD_64(S, T, T, I) + +CK_PR_LOAD_S_64(64, uint64_t, "ldr") +CK_PR_LOAD_S(32, uint32_t, "ldr") +CK_PR_LOAD_S(16, uint16_t, "ldrh") +CK_PR_LOAD_S(8, uint8_t, "ldrb") +CK_PR_LOAD_S(uint, unsigned int, "ldr") +CK_PR_LOAD_S(int, int, "ldr") +CK_PR_LOAD_S(short, short, "ldrh") +CK_PR_LOAD_S(char, char, "ldrb") +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_LOAD_S_64(double, double, "ldr") +#endif + +#undef CK_PR_LOAD_S +#undef CK_PR_LOAD_S_64 +#undef CK_PR_LOAD +#undef CK_PR_LAOD_64 + +#define CK_PR_STORE(S, M, T, I) \ + CK_CC_INLINE static void \ + ck_pr_md_store_##S(M *target, T v) \ + { \ + __asm__ __volatile__(I " %w1, [%0]" \ + : \ + : "r" (target), \ + "r" (v) \ + : "memory"); \ + return; \ + } +#define CK_PR_STORE_64(S, M, T, I) \ + CK_CC_INLINE static void \ + ck_pr_md_store_##S(M *target, T v) \ + { \ + __asm__ __volatile__(I " %1, [%0]" \ + : \ + : "r" (target), \ + "r" (v) \ + : "memory"); \ + return; \ + } + +CK_PR_STORE_64(ptr, void, const void *, "str") + +#define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, I) +#define CK_PR_STORE_S_64(S, T, I) CK_PR_STORE_64(S, T, T, I) + +CK_PR_STORE_S_64(64, uint64_t, "str") +CK_PR_STORE_S(32, uint32_t, "str") +CK_PR_STORE_S(16, uint16_t, "strh") +CK_PR_STORE_S(8, uint8_t, "strb") +CK_PR_STORE_S(uint, unsigned int, "str") +CK_PR_STORE_S(int, int, "str") +CK_PR_STORE_S(short, short, "strh") +CK_PR_STORE_S(char, char, "strb") +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_STORE_S_64(double, double, "str") +#endif + +#undef CK_PR_STORE_S +#undef CK_PR_STORE_S_64 +#undef CK_PR_STORE +#undef CK_PR_STORE_64 + +#ifdef CK_MD_LSE_ENABLE +#include "ck_pr_lse.h" +#else +#include "ck_pr_llsc.h" +#endif + +/* + * ck_pr_neg_*() functions can only be implemented via LL/SC, as there are no + * LSE alternatives. + */ +#define CK_PR_NEG(N, M, T, W, R) \ + CK_CC_INLINE static void \ + ck_pr_neg_##N(M *target) \ + { \ + T previous = 0; \ + T tmp = 0; \ + __asm__ __volatile__("1:" \ + "ldxr" W " %" R "0, [%2];" \ + "neg %" R "0, %" R "0;" \ + "stxr" W " %w1, %" R "0, [%2];" \ + "cbnz %w1, 1b;" \ + : "=&r" (previous), \ + "=&r" (tmp) \ + : "r" (target) \ + : "memory", "cc"); \ + return; \ + } + +CK_PR_NEG(ptr, void, void *, "", "") +CK_PR_NEG(64, uint64_t, uint64_t, "", "") + +#define CK_PR_NEG_S(S, T, W) \ + CK_PR_NEG(S, T, T, W, "w") \ + +CK_PR_NEG_S(32, uint32_t, "") +CK_PR_NEG_S(uint, unsigned int, "") +CK_PR_NEG_S(int, int, "") +CK_PR_NEG_S(16, uint16_t, "h") +CK_PR_NEG_S(8, uint8_t, "b") +CK_PR_NEG_S(short, short, "h") +CK_PR_NEG_S(char, char, "b") + +#undef CK_PR_NEG_S +#undef CK_PR_NEG + +#endif /* CK_PR_AARCH64_H */ + diff --git a/freebsd/sys/contrib/ck/include/gcc/arm/ck_f_pr.h b/freebsd/sys/contrib/ck/include/gcc/arm/ck_f_pr.h new file mode 100644 index 00000000..c508f855 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/arm/ck_f_pr.h @@ -0,0 +1,162 @@ +/* DO NOT EDIT. This is auto-generated from feature.sh */ +#define CK_F_PR_ADD_16 +#define CK_F_PR_ADD_32 +#define CK_F_PR_ADD_8 +#define CK_F_PR_ADD_CHAR +#define CK_F_PR_ADD_INT +#define CK_F_PR_ADD_PTR +#define CK_F_PR_ADD_SHORT +#define CK_F_PR_ADD_UINT +#define CK_F_PR_AND_16 +#define CK_F_PR_AND_32 +#define CK_F_PR_AND_8 +#define CK_F_PR_AND_CHAR +#define CK_F_PR_AND_INT +#define CK_F_PR_AND_PTR +#define CK_F_PR_AND_SHORT +#define CK_F_PR_AND_UINT +#define CK_F_PR_BARRIER +#define CK_F_PR_CAS_16 +#define CK_F_PR_CAS_16_VALUE +#define CK_F_PR_CAS_32 +#define CK_F_PR_CAS_32_VALUE +#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) +#define CK_F_PR_CAS_64 +#define CK_F_PR_CAS_64_VALUE +#define CK_F_PR_CAS_DOUBLE +#define CK_F_PR_CAS_DOUBLE_VALUE +#endif +#define CK_F_PR_CAS_8 +#define CK_F_PR_CAS_8_VALUE +#define CK_F_PR_CAS_CHAR +#define CK_F_PR_CAS_CHAR_VALUE +#define CK_F_PR_CAS_INT +#define CK_F_PR_CAS_INT_VALUE +#define CK_F_PR_CAS_PTR +#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) +#define CK_F_PR_CAS_PTR_2 +#define CK_F_PR_CAS_PTR_2_VALUE +#endif +#define CK_F_PR_CAS_PTR_VALUE +#define CK_F_PR_CAS_SHORT +#define CK_F_PR_CAS_SHORT_VALUE +#define CK_F_PR_CAS_UINT +#define CK_F_PR_CAS_UINT_VALUE +#define CK_F_PR_DEC_16 +#define CK_F_PR_DEC_32 +#define CK_F_PR_DEC_8 +#define CK_F_PR_DEC_CHAR +#define CK_F_PR_DEC_INT +#define CK_F_PR_DEC_PTR +#define CK_F_PR_DEC_SHORT +#define CK_F_PR_DEC_UINT +#define CK_F_PR_FAA_16 +#define CK_F_PR_FAA_32 +#define CK_F_PR_FAA_8 +#define CK_F_PR_FAA_CHAR +#define CK_F_PR_FAA_INT +#define CK_F_PR_FAA_PTR +#define CK_F_PR_FAA_SHORT +#define CK_F_PR_FAA_UINT +#define CK_F_PR_FAS_16 +#define CK_F_PR_FAS_32 +#define CK_F_PR_FAS_8 +#define CK_F_PR_FAS_CHAR +#define CK_F_PR_FAS_INT +#define CK_F_PR_FAS_PTR +#define CK_F_PR_FAS_SHORT +#define CK_F_PR_FAS_UINT +#define CK_F_PR_FENCE_ATOMIC +#define CK_F_PR_FENCE_ATOMIC_LOAD +#define CK_F_PR_FENCE_ATOMIC_STORE +#define CK_F_PR_FENCE_LOAD +#define CK_F_PR_FENCE_LOAD_ATOMIC +#define CK_F_PR_FENCE_LOAD_DEPENDS +#define CK_F_PR_FENCE_LOAD_STORE +#define CK_F_PR_FENCE_MEMORY +#define CK_F_PR_FENCE_STORE +#define CK_F_PR_FENCE_STORE_ATOMIC +#define CK_F_PR_FENCE_STORE_LOAD +#define CK_F_PR_FENCE_STRICT_ATOMIC +#define CK_F_PR_FENCE_STRICT_ATOMIC_LOAD +#define CK_F_PR_FENCE_STRICT_ATOMIC_STORE +#define CK_F_PR_FENCE_STRICT_LOAD +#define CK_F_PR_FENCE_STRICT_LOAD_ATOMIC +#define CK_F_PR_FENCE_STRICT_LOAD_STORE +#define CK_F_PR_FENCE_STRICT_MEMORY +#define CK_F_PR_FENCE_STRICT_STORE +#define CK_F_PR_FENCE_STRICT_STORE_ATOMIC +#define CK_F_PR_FENCE_STRICT_STORE_LOAD +#define CK_F_PR_INC_16 +#define CK_F_PR_INC_32 +#define CK_F_PR_INC_8 +#define CK_F_PR_INC_CHAR +#define CK_F_PR_INC_INT +#define CK_F_PR_INC_PTR +#define CK_F_PR_INC_SHORT +#define CK_F_PR_INC_UINT +#define CK_F_PR_LOAD_16 +#define CK_F_PR_LOAD_32 +#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) +#define CK_F_PR_LOAD_64 +#define CK_F_PR_LOAD_DOUBLE +#endif +#define CK_F_PR_LOAD_8 +#define CK_F_PR_LOAD_CHAR +#define CK_F_PR_LOAD_INT +#define CK_F_PR_LOAD_PTR +#define CK_F_PR_LOAD_SHORT +#define CK_F_PR_LOAD_UINT +#define CK_F_PR_NEG_16 +#define CK_F_PR_NEG_32 +#define CK_F_PR_NEG_8 +#define CK_F_PR_NEG_CHAR +#define CK_F_PR_NEG_INT +#define CK_F_PR_NEG_PTR +#define CK_F_PR_NEG_SHORT +#define CK_F_PR_NEG_UINT +#define CK_F_PR_NOT_16 +#define CK_F_PR_NOT_32 +#define CK_F_PR_NOT_8 +#define CK_F_PR_NOT_CHAR +#define CK_F_PR_NOT_INT +#define CK_F_PR_NOT_PTR +#define CK_F_PR_NOT_SHORT +#define CK_F_PR_NOT_UINT +#define CK_F_PR_OR_16 +#define CK_F_PR_OR_32 +#define CK_F_PR_OR_8 +#define CK_F_PR_OR_CHAR +#define CK_F_PR_OR_INT +#define CK_F_PR_OR_PTR +#define CK_F_PR_OR_SHORT +#define CK_F_PR_OR_UINT +#define CK_F_PR_STALL +#define CK_F_PR_STORE_16 +#define CK_F_PR_STORE_32 +#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) +#define CK_F_PR_STORE_64 +#define CK_F_PR_STORE_DOUBLE +#endif +#define CK_F_PR_STORE_8 +#define CK_F_PR_STORE_CHAR +#define CK_F_PR_STORE_INT +#define CK_F_PR_STORE_PTR +#define CK_F_PR_STORE_SHORT +#define CK_F_PR_STORE_UINT +#define CK_F_PR_SUB_16 +#define CK_F_PR_SUB_32 +#define CK_F_PR_SUB_8 +#define CK_F_PR_SUB_CHAR +#define CK_F_PR_SUB_INT +#define CK_F_PR_SUB_PTR +#define CK_F_PR_SUB_SHORT +#define CK_F_PR_SUB_UINT +#define CK_F_PR_XOR_16 +#define CK_F_PR_XOR_32 +#define CK_F_PR_XOR_8 +#define CK_F_PR_XOR_CHAR +#define CK_F_PR_XOR_INT +#define CK_F_PR_XOR_PTR +#define CK_F_PR_XOR_SHORT +#define CK_F_PR_XOR_UINT diff --git a/freebsd/sys/contrib/ck/include/gcc/arm/ck_pr.h b/freebsd/sys/contrib/ck/include/gcc/arm/ck_pr.h new file mode 100644 index 00000000..b1f36997 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/arm/ck_pr.h @@ -0,0 +1,563 @@ +/* + * Copyright 2009-2015 Samy Al Bahra. + * Copyright 2013-2015 Olivier Houchard. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_PR_ARM_H +#define CK_PR_ARM_H + +#ifndef CK_PR_H +#error Do not include this file directly, use ck_pr.h +#endif + +#include <ck_cc.h> +#include <ck_md.h> + +/* + * The following represent supported atomic operations. + * These operations may be emulated. + */ +#include "ck_f_pr.h" + +/* + * Minimum interface requirement met. + */ +#define CK_F_PR + +CK_CC_INLINE static void +ck_pr_stall(void) +{ + + __asm__ __volatile__("" ::: "memory"); + return; +} + +#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) +#define CK_ISB __asm __volatile("isb" : : "r" (0) : "memory") +#define CK_DMB __asm __volatile("dmb" : : "r" (0) : "memory") +#define CK_DSB __asm __volatile("dsb" : : "r" (0) : "memory") +/* FreeBSD's toolchain doesn't accept dmb st, so use the opcode instead */ +#if defined(__FreeBSD__) && !defined(__rtems__) +#define CK_DMB_ST __asm __volatile(".word 0xf57ff05e" : : "r" (0) : "memory") +#else +#define CK_DMB_ST __asm __volatile("dmb st" : : "r" (0) : "memory") +#endif /* __FreeBSD__ */ +#else +/* armv6 doesn't have dsb/dmb/isb, and no way to wait only for stores */ +#define CK_ISB \ + __asm __volatile("mcr p15, 0, %0, c7, c5, 4" : : "r" (0) : "memory") +#define CK_DSB \ + __asm __volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (0) : "memory") +#define CK_DMB \ + __asm __volatile("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory") +#define CK_DMB_ST CK_DMB +#endif + +#define CK_PR_FENCE(T, I) \ + CK_CC_INLINE static void \ + ck_pr_fence_strict_##T(void) \ + { \ + I; \ + } + +CK_PR_FENCE(atomic, CK_DMB_ST) +CK_PR_FENCE(atomic_store, CK_DMB_ST) +CK_PR_FENCE(atomic_load, CK_DMB_ST) +CK_PR_FENCE(store_atomic, CK_DMB_ST) +CK_PR_FENCE(load_atomic, CK_DMB) +CK_PR_FENCE(store, CK_DMB_ST) +CK_PR_FENCE(store_load, CK_DMB) +CK_PR_FENCE(load, CK_DMB) +CK_PR_FENCE(load_store, CK_DMB) +CK_PR_FENCE(memory, CK_DMB) +CK_PR_FENCE(acquire, CK_DMB) +CK_PR_FENCE(release, CK_DMB) +CK_PR_FENCE(acqrel, CK_DMB) +CK_PR_FENCE(lock, CK_DMB) +CK_PR_FENCE(unlock, CK_DMB) + +#undef CK_PR_FENCE + +#undef CK_ISB +#undef CK_DSB +#undef CK_DMB +#undef CK_DMB_ST + +#define CK_PR_LOAD(S, M, T, C, I) \ + CK_CC_INLINE static T \ + ck_pr_md_load_##S(const M *target) \ + { \ + long r = 0; \ + __asm__ __volatile__(I " %0, [%1];" \ + : "=r" (r) \ + : "r" (target) \ + : "memory"); \ + return ((T)r); \ + } + +CK_PR_LOAD(ptr, void, void *, uint32_t, "ldr") + +#define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) + +CK_PR_LOAD_S(32, uint32_t, "ldr") +CK_PR_LOAD_S(16, uint16_t, "ldrh") +CK_PR_LOAD_S(8, uint8_t, "ldrb") +CK_PR_LOAD_S(uint, unsigned int, "ldr") +CK_PR_LOAD_S(int, int, "ldr") +CK_PR_LOAD_S(short, short, "ldrh") +CK_PR_LOAD_S(char, char, "ldrb") + +#undef CK_PR_LOAD_S +#undef CK_PR_LOAD + +#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) + +#define CK_PR_DOUBLE_LOAD(T, N) \ +CK_CC_INLINE static T \ +ck_pr_md_load_##N(const T *target) \ +{ \ + register T ret; \ + \ + __asm __volatile("ldrexd %0, [%1]" \ + : "=&r" (ret) \ + : "r" (target) \ + : "memory", "cc"); \ + return (ret); \ +} + +CK_PR_DOUBLE_LOAD(uint64_t, 64) +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_DOUBLE_LOAD(double, double) +#endif +#undef CK_PR_DOUBLE_LOAD +#endif + +#define CK_PR_STORE(S, M, T, C, I) \ + CK_CC_INLINE static void \ + ck_pr_md_store_##S(M *target, T v) \ + { \ + __asm__ __volatile__(I " %1, [%0]" \ + : \ + : "r" (target), \ + "r" (v) \ + : "memory"); \ + return; \ + } + +CK_PR_STORE(ptr, void, const void *, uint32_t, "str") + +#define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) + +CK_PR_STORE_S(32, uint32_t, "str") +CK_PR_STORE_S(16, uint16_t, "strh") +CK_PR_STORE_S(8, uint8_t, "strb") +CK_PR_STORE_S(uint, unsigned int, "str") +CK_PR_STORE_S(int, int, "str") +CK_PR_STORE_S(short, short, "strh") +CK_PR_STORE_S(char, char, "strb") + +#undef CK_PR_STORE_S +#undef CK_PR_STORE + +#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) + +#define CK_PR_DOUBLE_STORE(T, N) \ +CK_CC_INLINE static void \ +ck_pr_md_store_##N(const T *target, T value) \ +{ \ + T tmp; \ + uint32_t flag; \ + __asm __volatile("1: \n" \ + "ldrexd %0, [%2]\n" \ + "strexd %1, %3, [%2]\n" \ + "teq %1, #0\n" \ + "it ne \n" \ + "bne 1b\n" \ + : "=&r" (tmp), "=&r" (flag) \ + : "r" (target), "r" (value) \ + : "memory", "cc"); \ +} + +CK_PR_DOUBLE_STORE(uint64_t, 64) +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_DOUBLE_STORE(double, double) +#endif + +#undef CK_PR_DOUBLE_STORE + +#define CK_PR_DOUBLE_CAS_VALUE(T, N) \ +CK_CC_INLINE static bool \ +ck_pr_cas_##N##_value(T *target, T compare, T set, T *value) \ +{ \ + T previous; \ + int tmp; \ + \ + __asm__ __volatile__("1:" \ + "ldrexd %0, [%4];" \ + "cmp %Q0, %Q2;" \ + "ittt eq;" \ + "cmpeq %R0, %R2;" \ + "strexdeq %1, %3, [%4];" \ + "cmpeq %1, #1;" \ + "beq 1b;" \ + :"=&r" (previous), "=&r" (tmp) \ + : "r" (compare), "r" (set) , \ + "r"(target) \ + : "memory", "cc"); \ + *value = previous; \ + return (*value == compare); \ +} + +CK_PR_DOUBLE_CAS_VALUE(uint64_t, 64) +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_DOUBLE_CAS_VALUE(double, double) +#endif + +#undef CK_PR_DOUBLE_CAS_VALUE + +CK_CC_INLINE static bool +ck_pr_cas_ptr_2_value(void *target, void *compare, void *set, void *value) +{ + uint32_t *_compare = CK_CPP_CAST(uint32_t *, compare); + uint32_t *_set = CK_CPP_CAST(uint32_t *, set); + uint64_t __compare = ((uint64_t)_compare[0]) | ((uint64_t)_compare[1] << 32); + uint64_t __set = ((uint64_t)_set[0]) | ((uint64_t)_set[1] << 32); + + return (ck_pr_cas_64_value(CK_CPP_CAST(uint64_t *, target), + __compare, + __set, + CK_CPP_CAST(uint64_t *, value))); +} + +#define CK_PR_DOUBLE_CAS(T, N) \ +CK_CC_INLINE static bool \ +ck_pr_cas_##N(T *target, T compare, T set) \ +{ \ + int ret; \ + T tmp; \ + \ + __asm__ __volatile__("1:" \ + "mov %0, #0;" \ + "ldrexd %1, [%4];" \ + "cmp %Q1, %Q2;" \ + "itttt eq;" \ + "cmpeq %R1, %R2;" \ + "strexdeq %1, %3, [%4];" \ + "moveq %0, #1;" \ + "cmpeq %1, #1;" \ + "beq 1b;" \ + : "=&r" (ret), "=&r" (tmp) \ + : "r" (compare), "r" (set) , \ + "r"(target) \ + : "memory", "cc"); \ + \ + return (ret); \ +} + +CK_PR_DOUBLE_CAS(uint64_t, 64) +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_DOUBLE_CAS(double, double) +#endif + +CK_CC_INLINE static bool +ck_pr_cas_ptr_2(void *target, void *compare, void *set) +{ + uint32_t *_compare = CK_CPP_CAST(uint32_t *, compare); + uint32_t *_set = CK_CPP_CAST(uint32_t *, set); + uint64_t __compare = ((uint64_t)_compare[0]) | ((uint64_t)_compare[1] << 32); + uint64_t __set = ((uint64_t)_set[0]) | ((uint64_t)_set[1] << 32); + return (ck_pr_cas_64(CK_CPP_CAST(uint64_t *, target), + __compare, + __set)); +} + +#endif + +CK_CC_INLINE static bool +ck_pr_cas_ptr_value(void *target, void *compare, void *set, void *value) +{ + void *previous, *tmp; + __asm__ __volatile__("1:" + "ldrex %0, [%2];" + "cmp %0, %4;" + "itt eq;" + "strexeq %1, %3, [%2];" + "cmpeq %1, #1;" + "beq 1b;" + : "=&r" (previous), + "=&r" (tmp) + : "r" (target), + "r" (set), + "r" (compare) + : "memory", "cc"); + *(void **)value = previous; + return (previous == compare); +} + +CK_CC_INLINE static bool +ck_pr_cas_ptr(void *target, void *compare, void *set) +{ + void *previous, *tmp; + __asm__ __volatile__("1:" + "ldrex %0, [%2];" + "cmp %0, %4;" + "itt eq;" + "strexeq %1, %3, [%2];" + "cmpeq %1, #1;" + "beq 1b;" + : "=&r" (previous), + "=&r" (tmp) + : "r" (target), + "r" (set), + "r" (compare) + : "memory", "cc"); + return (previous == compare); +} + +#define CK_PR_CAS(N, T, W) \ + CK_CC_INLINE static bool \ + ck_pr_cas_##N##_value(T *target, T compare, T set, T *value) \ + { \ + T previous = 0, tmp = 0; \ + __asm__ __volatile__("1:" \ + "ldrex" W " %0, [%2];" \ + "cmp %0, %4;" \ + "itt eq;" \ + "strex" W "eq %1, %3, [%2];" \ + "cmpeq %1, #1;" \ + "beq 1b;" \ + /* \ + * Using "+&" instead of "=&" to avoid bogus \ + * clang warnings. \ + */ \ + : "+&r" (previous), \ + "+&r" (tmp) \ + : "r" (target), \ + "r" (set), \ + "r" (compare) \ + : "memory", "cc"); \ + *value = previous; \ + return (previous == compare); \ + } \ + CK_CC_INLINE static bool \ + ck_pr_cas_##N(T *target, T compare, T set) \ + { \ + T previous = 0, tmp = 0; \ + __asm__ __volatile__("1:" \ + "ldrex" W " %0, [%2];" \ + "cmp %0, %4;" \ + "itt eq;" \ + "strex" W "eq %1, %3, [%2];" \ + "cmpeq %1, #1;" \ + "beq 1b;" \ + : "+&r" (previous), \ + "+&r" (tmp) \ + : "r" (target), \ + "r" (set), \ + "r" (compare) \ + : "memory", "cc"); \ + return (previous == compare); \ + } + +CK_PR_CAS(32, uint32_t, "") +CK_PR_CAS(uint, unsigned int, "") +CK_PR_CAS(int, int, "") +CK_PR_CAS(16, uint16_t, "h") +CK_PR_CAS(8, uint8_t, "b") +CK_PR_CAS(short, short, "h") +CK_PR_CAS(char, char, "b") + + +#undef CK_PR_CAS + +#define CK_PR_FAS(N, M, T, W) \ + CK_CC_INLINE static T \ + ck_pr_fas_##N(M *target, T v) \ + { \ + T previous = 0; \ + T tmp = 0; \ + __asm__ __volatile__("1:" \ + "ldrex" W " %0, [%2];" \ + "strex" W " %1, %3, [%2];" \ + "cmp %1, #0;" \ + "bne 1b;" \ + : "+&r" (previous), \ + "+&r" (tmp) \ + : "r" (target), \ + "r" (v) \ + : "memory", "cc"); \ + return (previous); \ + } + +CK_PR_FAS(32, uint32_t, uint32_t, "") +CK_PR_FAS(ptr, void, void *, "") +CK_PR_FAS(int, int, int, "") +CK_PR_FAS(uint, unsigned int, unsigned int, "") +CK_PR_FAS(16, uint16_t, uint16_t, "h") +CK_PR_FAS(8, uint8_t, uint8_t, "b") +CK_PR_FAS(short, short, short, "h") +CK_PR_FAS(char, char, char, "b") + + +#undef CK_PR_FAS + +#define CK_PR_UNARY(O, N, M, T, I, W) \ + CK_CC_INLINE static void \ + ck_pr_##O##_##N(M *target) \ + { \ + T previous = 0; \ + T tmp = 0; \ + __asm__ __volatile__("1:" \ + "ldrex" W " %0, [%2];" \ + I ";" \ + "strex" W " %1, %0, [%2];" \ + "cmp %1, #0;" \ + "bne 1b;" \ + : "+&r" (previous), \ + "+&r" (tmp) \ + : "r" (target) \ + : "memory", "cc"); \ + return; \ + } + +CK_PR_UNARY(inc, ptr, void, void *, "add %0, %0, #1", "") +CK_PR_UNARY(dec, ptr, void, void *, "sub %0, %0, #1", "") +CK_PR_UNARY(not, ptr, void, void *, "mvn %0, %0", "") +CK_PR_UNARY(neg, ptr, void, void *, "neg %0, %0", "") + +#define CK_PR_UNARY_S(S, T, W) \ + CK_PR_UNARY(inc, S, T, T, "add %0, %0, #1", W) \ + CK_PR_UNARY(dec, S, T, T, "sub %0, %0, #1", W) \ + CK_PR_UNARY(not, S, T, T, "mvn %0, %0", W) \ + CK_PR_UNARY(neg, S, T, T, "neg %0, %0", W) \ + +CK_PR_UNARY_S(32, uint32_t, "") +CK_PR_UNARY_S(uint, unsigned int, "") +CK_PR_UNARY_S(int, int, "") +CK_PR_UNARY_S(16, uint16_t, "h") +CK_PR_UNARY_S(8, uint8_t, "b") +CK_PR_UNARY_S(short, short, "h") +CK_PR_UNARY_S(char, char, "b") + +#undef CK_PR_UNARY_S +#undef CK_PR_UNARY + +#define CK_PR_BINARY(O, N, M, T, I, W) \ + CK_CC_INLINE static void \ + ck_pr_##O##_##N(M *target, T delta) \ + { \ + T previous = 0; \ + T tmp = 0; \ + __asm__ __volatile__("1:" \ + "ldrex" W " %0, [%2];" \ + I " %0, %0, %3;" \ + "strex" W " %1, %0, [%2];" \ + "cmp %1, #0;" \ + "bne 1b;" \ + : "+&r" (previous), \ + "+&r" (tmp) \ + : "r" (target), \ + "r" (delta) \ + : "memory", "cc"); \ + return; \ + } + +CK_PR_BINARY(and, ptr, void, uintptr_t, "and", "") +CK_PR_BINARY(add, ptr, void, uintptr_t, "add", "") +CK_PR_BINARY(or, ptr, void, uintptr_t, "orr", "") +CK_PR_BINARY(sub, ptr, void, uintptr_t, "sub", "") +CK_PR_BINARY(xor, ptr, void, uintptr_t, "eor", "") + +#define CK_PR_BINARY_S(S, T, W) \ + CK_PR_BINARY(and, S, T, T, "and", W) \ + CK_PR_BINARY(add, S, T, T, "add", W) \ + CK_PR_BINARY(or, S, T, T, "orr", W) \ + CK_PR_BINARY(sub, S, T, T, "sub", W) \ + CK_PR_BINARY(xor, S, T, T, "eor", W) + +CK_PR_BINARY_S(32, uint32_t, "") +CK_PR_BINARY_S(uint, unsigned int, "") +CK_PR_BINARY_S(int, int, "") +CK_PR_BINARY_S(16, uint16_t, "h") +CK_PR_BINARY_S(8, uint8_t, "b") +CK_PR_BINARY_S(short, short, "h") +CK_PR_BINARY_S(char, char, "b") + +#undef CK_PR_BINARY_S +#undef CK_PR_BINARY + +CK_CC_INLINE static void * +ck_pr_faa_ptr(void *target, uintptr_t delta) +{ + uintptr_t previous, r, tmp; + + __asm__ __volatile__("1:" + "ldrex %0, [%3];" + "add %1, %4, %0;" + "strex %2, %1, [%3];" + "cmp %2, #0;" + "bne 1b;" + : "=&r" (previous), + "=&r" (r), + "=&r" (tmp) + : "r" (target), + "r" (delta) + : "memory", "cc"); + + return (void *)(previous); +} + +#define CK_PR_FAA(S, T, W) \ + CK_CC_INLINE static T \ + ck_pr_faa_##S(T *target, T delta) \ + { \ + T previous = 0, r = 0, tmp = 0; \ + __asm__ __volatile__("1:" \ + "ldrex" W " %0, [%3];" \ + "add %1, %4, %0;" \ + "strex" W " %2, %1, [%3];" \ + "cmp %2, #0;" \ + "bne 1b;" \ + : "+&r" (previous), \ + "+&r" (r), \ + "+&r" (tmp) \ + : "r" (target), \ + "r" (delta) \ + : "memory", "cc"); \ + return (previous); \ + } + +CK_PR_FAA(32, uint32_t, "") +CK_PR_FAA(uint, unsigned int, "") +CK_PR_FAA(int, int, "") +CK_PR_FAA(16, uint16_t, "h") +CK_PR_FAA(8, uint8_t, "b") +CK_PR_FAA(short, short, "h") +CK_PR_FAA(char, char, "b") + +#undef CK_PR_FAA + +#endif /* CK_PR_ARM_H */ + diff --git a/freebsd/sys/contrib/ck/include/gcc/ck_cc.h b/freebsd/sys/contrib/ck/include/gcc/ck_cc.h new file mode 100644 index 00000000..6ebc59cb --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/ck_cc.h @@ -0,0 +1,141 @@ +/* + * Copyright 2009-2015 Samy Al Bahra. + * Copyright 2014 Paul Khuong. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_GCC_CC_H +#define CK_GCC_CC_H + +#include <ck_md.h> + +#ifdef __SUNPRO_C +#define CK_CC_UNUSED +#define CK_CC_USED +#define CK_CC_IMM +#define CK_CC_IMM_U32 +#else +#define CK_CC_UNUSED __attribute__((unused)) +#define CK_CC_USED __attribute__((used)) +#define CK_CC_IMM "i" +#if defined(__x86_64__) || defined(__x86__) +#define CK_CC_IMM_U32 "Z" +#define CK_CC_IMM_S32 "e" +#else +#define CK_CC_IMM_U32 CK_CC_IMM +#define CK_CC_IMM_S32 CK_CC_IMM +#endif /* __x86_64__ || __x86__ */ +#endif + +#ifdef __OPTIMIZE__ +#define CK_CC_INLINE CK_CC_UNUSED inline +#else +#define CK_CC_INLINE CK_CC_UNUSED +#endif + +#define CK_CC_FORCE_INLINE CK_CC_UNUSED __attribute__((always_inline)) inline +#define CK_CC_RESTRICT __restrict__ + +/* + * Packed attribute. + */ +#define CK_CC_PACKED __attribute__((packed)) + +/* + * Weak reference. + */ +#define CK_CC_WEAKREF __attribute__((weakref)) + +/* + * Alignment attribute. + */ +#define CK_CC_ALIGN(B) __attribute__((aligned(B))) + +/* + * Cache align. + */ +#define CK_CC_CACHELINE CK_CC_ALIGN(CK_MD_CACHELINE) + +/* + * These are functions which should be avoided. + */ +#ifdef __freestanding__ +#pragma GCC poison malloc free +#endif + +/* + * Branch execution hints. + */ +#define CK_CC_LIKELY(x) (__builtin_expect(!!(x), 1)) +#define CK_CC_UNLIKELY(x) (__builtin_expect(!!(x), 0)) + +/* + * Some compilers are overly strict regarding aliasing semantics. + * Unfortunately, in many cases it makes more sense to pay aliasing + * cost rather than overly expensive register spillage. + */ +#define CK_CC_ALIASED __attribute__((__may_alias__)) + +/* + * Compile-time typeof + */ +#define CK_CC_TYPEOF(X, DEFAULT) __typeof__(X) + +/* + * Portability wrappers for bitwise operations. + */ +#ifndef CK_MD_CC_BUILTIN_DISABLE +#define CK_F_CC_FFS +CK_CC_INLINE static int +ck_cc_ffs(unsigned int x) +{ + + return __builtin_ffsl(x); +} + +#define CK_F_CC_FFSL +CK_CC_INLINE static int +ck_cc_ffsl(unsigned long x) +{ + + return __builtin_ffsll(x); +} + +#define CK_F_CC_CTZ +CK_CC_INLINE static int +ck_cc_ctz(unsigned int x) +{ + + return __builtin_ctz(x); +} + +#define CK_F_CC_POPCOUNT +CK_CC_INLINE static int +ck_cc_popcount(unsigned int x) +{ + + return __builtin_popcount(x); +} +#endif /* CK_MD_CC_BUILTIN_DISABLE */ +#endif /* CK_GCC_CC_H */ diff --git a/freebsd/sys/contrib/ck/include/gcc/ck_f_pr.h b/freebsd/sys/contrib/ck/include/gcc/ck_f_pr.h new file mode 100644 index 00000000..0ef0d108 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/ck_f_pr.h @@ -0,0 +1,105 @@ +/* DO NOT EDIT. This is auto-generated from feature.sh */ +#define CK_F_PR_ADD_16 +#define CK_F_PR_ADD_32 +#define CK_F_PR_ADD_64 +#define CK_F_PR_ADD_8 +#define CK_F_PR_ADD_CHAR +#define CK_F_PR_ADD_INT +#define CK_F_PR_ADD_PTR +#define CK_F_PR_ADD_UINT +#define CK_F_PR_AND_16 +#define CK_F_PR_AND_32 +#define CK_F_PR_AND_64 +#define CK_F_PR_AND_8 +#define CK_F_PR_AND_CHAR +#define CK_F_PR_AND_INT +#define CK_F_PR_AND_PTR +#define CK_F_PR_AND_UINT +#define CK_F_PR_CAS_16 +#define CK_F_PR_CAS_16_VALUE +#define CK_F_PR_CAS_32 +#define CK_F_PR_CAS_32_VALUE +#define CK_F_PR_CAS_64 +#define CK_F_PR_CAS_64_VALUE +#define CK_F_PR_CAS_8 +#define CK_F_PR_CAS_8_VALUE +#define CK_F_PR_CAS_CHAR +#define CK_F_PR_CAS_CHAR_VALUE +#define CK_F_PR_CAS_INT +#define CK_F_PR_CAS_INT_VALUE +#define CK_F_PR_CAS_PTR +#define CK_F_PR_CAS_PTR_VALUE +#define CK_F_PR_CAS_UINT +#define CK_F_PR_CAS_UINT_VALUE +#define CK_F_PR_DEC_16 +#define CK_F_PR_DEC_32 +#define CK_F_PR_DEC_64 +#define CK_F_PR_DEC_8 +#define CK_F_PR_DEC_CHAR +#define CK_F_PR_DEC_INT +#define CK_F_PR_DEC_PTR +#define CK_F_PR_DEC_UINT +#define CK_F_PR_FAA_16 +#define CK_F_PR_FAA_32 +#define CK_F_PR_FAA_64 +#define CK_F_PR_FAA_8 +#define CK_F_PR_FAA_CHAR +#define CK_F_PR_FAA_INT +#define CK_F_PR_FAA_PTR +#define CK_F_PR_FAA_UINT +#define CK_F_PR_FENCE_LOAD +#define CK_F_PR_FENCE_LOAD_DEPENDS +#define CK_F_PR_FENCE_MEMORY +#define CK_F_PR_FENCE_STORE +#define CK_F_PR_FENCE_STRICT_LOAD +#define CK_F_PR_FENCE_STRICT_MEMORY +#define CK_F_PR_FENCE_STRICT_STORE +#define CK_F_PR_INC_16 +#define CK_F_PR_INC_32 +#define CK_F_PR_INC_64 +#define CK_F_PR_INC_8 +#define CK_F_PR_INC_CHAR +#define CK_F_PR_INC_INT +#define CK_F_PR_INC_PTR +#define CK_F_PR_INC_UINT +#define CK_F_PR_LOAD_16 +#define CK_F_PR_LOAD_32 +#define CK_F_PR_LOAD_64 +#define CK_F_PR_LOAD_8 +#define CK_F_PR_LOAD_CHAR +#define CK_F_PR_LOAD_INT +#define CK_F_PR_LOAD_PTR +#define CK_F_PR_LOAD_UINT +#define CK_F_PR_OR_16 +#define CK_F_PR_OR_32 +#define CK_F_PR_OR_64 +#define CK_F_PR_OR_8 +#define CK_F_PR_OR_CHAR +#define CK_F_PR_OR_INT +#define CK_F_PR_OR_PTR +#define CK_F_PR_OR_UINT +#define CK_F_PR_STALL +#define CK_F_PR_STORE_16 +#define CK_F_PR_STORE_32 +#define CK_F_PR_STORE_64 +#define CK_F_PR_STORE_8 +#define CK_F_PR_STORE_CHAR +#define CK_F_PR_STORE_INT +#define CK_F_PR_STORE_PTR +#define CK_F_PR_STORE_UINT +#define CK_F_PR_SUB_16 +#define CK_F_PR_SUB_32 +#define CK_F_PR_SUB_64 +#define CK_F_PR_SUB_8 +#define CK_F_PR_SUB_CHAR +#define CK_F_PR_SUB_INT +#define CK_F_PR_SUB_PTR +#define CK_F_PR_SUB_UINT +#define CK_F_PR_XOR_16 +#define CK_F_PR_XOR_32 +#define CK_F_PR_XOR_64 +#define CK_F_PR_XOR_8 +#define CK_F_PR_XOR_CHAR +#define CK_F_PR_XOR_INT +#define CK_F_PR_XOR_PTR +#define CK_F_PR_XOR_UINT diff --git a/freebsd/sys/contrib/ck/include/gcc/ck_pr.h b/freebsd/sys/contrib/ck/include/gcc/ck_pr.h new file mode 100644 index 00000000..108e983a --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/ck_pr.h @@ -0,0 +1,297 @@ +/* + * Copyright 2010 Samy Al Bahra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_PR_GCC_H +#define CK_PR_GCC_H + +#ifndef CK_PR_H +#error Do not include this file directly, use ck_pr.h +#endif + +#include <ck_cc.h> + +CK_CC_INLINE static void +ck_pr_barrier(void) +{ + + __asm__ __volatile__("" ::: "memory"); + return; +} + +#ifndef CK_F_PR +#define CK_F_PR + +#include <ck_stdbool.h> +#include <ck_stdint.h> + +/* + * The following represent supported atomic operations. + * These operations may be emulated. + */ +#include "ck_f_pr.h" + +#define CK_PR_ACCESS(x) (*(volatile __typeof__(x) *)&(x)) + +#define CK_PR_LOAD(S, M, T) \ + CK_CC_INLINE static T \ + ck_pr_md_load_##S(const M *target) \ + { \ + T r; \ + ck_pr_barrier(); \ + r = CK_PR_ACCESS(*(const T *)target); \ + ck_pr_barrier(); \ + return (r); \ + } \ + CK_CC_INLINE static void \ + ck_pr_md_store_##S(M *target, T v) \ + { \ + ck_pr_barrier(); \ + CK_PR_ACCESS(*(T *)target) = v; \ + ck_pr_barrier(); \ + return; \ + } + +CK_CC_INLINE static void * +ck_pr_md_load_ptr(const void *target) +{ + void *r; + + ck_pr_barrier(); + r = CK_CC_DECONST_PTR(*(volatile void *const*)(target)); + ck_pr_barrier(); + + return r; +} + +CK_CC_INLINE static void +ck_pr_md_store_ptr(void *target, const void *v) +{ + + ck_pr_barrier(); + *(volatile void **)target = CK_CC_DECONST_PTR(v); + ck_pr_barrier(); + return; +} + +#define CK_PR_LOAD_S(S, T) CK_PR_LOAD(S, T, T) + +CK_PR_LOAD_S(char, char) +CK_PR_LOAD_S(uint, unsigned int) +CK_PR_LOAD_S(int, int) +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_LOAD_S(double, double) +#endif +CK_PR_LOAD_S(64, uint64_t) +CK_PR_LOAD_S(32, uint32_t) +CK_PR_LOAD_S(16, uint16_t) +CK_PR_LOAD_S(8, uint8_t) + +#undef CK_PR_LOAD_S +#undef CK_PR_LOAD + +CK_CC_INLINE static void +ck_pr_stall(void) +{ + + ck_pr_barrier(); +} + +/* + * Load and store fences are equivalent to full fences in the GCC port. + */ +#define CK_PR_FENCE(T) \ + CK_CC_INLINE static void \ + ck_pr_fence_strict_##T(void) \ + { \ + __sync_synchronize(); \ + } + +CK_PR_FENCE(atomic) +CK_PR_FENCE(atomic_atomic) +CK_PR_FENCE(atomic_load) +CK_PR_FENCE(atomic_store) +CK_PR_FENCE(store_atomic) +CK_PR_FENCE(load_atomic) +CK_PR_FENCE(load) +CK_PR_FENCE(load_load) +CK_PR_FENCE(load_store) +CK_PR_FENCE(store) +CK_PR_FENCE(store_store) +CK_PR_FENCE(store_load) +CK_PR_FENCE(memory) +CK_PR_FENCE(acquire) +CK_PR_FENCE(release) +CK_PR_FENCE(acqrel) +CK_PR_FENCE(lock) +CK_PR_FENCE(unlock) + +#undef CK_PR_FENCE + +/* + * Atomic compare and swap. + */ +#define CK_PR_CAS(S, M, T) \ + CK_CC_INLINE static bool \ + ck_pr_cas_##S(M *target, T compare, T set) \ + { \ + bool z; \ + z = __sync_bool_compare_and_swap((T *)target, compare, set); \ + return z; \ + } + +CK_PR_CAS(ptr, void, void *) + +#define CK_PR_CAS_S(S, T) CK_PR_CAS(S, T, T) + +CK_PR_CAS_S(char, char) +CK_PR_CAS_S(int, int) +CK_PR_CAS_S(uint, unsigned int) +CK_PR_CAS_S(64, uint64_t) +CK_PR_CAS_S(32, uint32_t) +CK_PR_CAS_S(16, uint16_t) +CK_PR_CAS_S(8, uint8_t) + +#undef CK_PR_CAS_S +#undef CK_PR_CAS + +/* + * Compare and swap, set *v to old value of target. + */ +CK_CC_INLINE static bool +ck_pr_cas_ptr_value(void *target, void *compare, void *set, void *v) +{ + set = __sync_val_compare_and_swap((void **)target, compare, set); + *(void **)v = set; + return (set == compare); +} + +#define CK_PR_CAS_O(S, T) \ + CK_CC_INLINE static bool \ + ck_pr_cas_##S##_value(T *target, T compare, T set, T *v) \ + { \ + set = __sync_val_compare_and_swap(target, compare, set);\ + *v = set; \ + return (set == compare); \ + } + +CK_PR_CAS_O(char, char) +CK_PR_CAS_O(int, int) +CK_PR_CAS_O(uint, unsigned int) +CK_PR_CAS_O(64, uint64_t) +CK_PR_CAS_O(32, uint32_t) +CK_PR_CAS_O(16, uint16_t) +CK_PR_CAS_O(8, uint8_t) + +#undef CK_PR_CAS_O + +/* + * Atomic fetch-and-add operations. + */ +#define CK_PR_FAA(S, M, T) \ + CK_CC_INLINE static T \ + ck_pr_faa_##S(M *target, T d) \ + { \ + d = __sync_fetch_and_add((T *)target, d); \ + return (d); \ + } + +CK_PR_FAA(ptr, void, void *) + +#define CK_PR_FAA_S(S, T) CK_PR_FAA(S, T, T) + +CK_PR_FAA_S(char, char) +CK_PR_FAA_S(uint, unsigned int) +CK_PR_FAA_S(int, int) +CK_PR_FAA_S(64, uint64_t) +CK_PR_FAA_S(32, uint32_t) +CK_PR_FAA_S(16, uint16_t) +CK_PR_FAA_S(8, uint8_t) + +#undef CK_PR_FAA_S +#undef CK_PR_FAA + +/* + * Atomic store-only binary operations. + */ +#define CK_PR_BINARY(K, S, M, T) \ + CK_CC_INLINE static void \ + ck_pr_##K##_##S(M *target, T d) \ + { \ + d = __sync_fetch_and_##K((T *)target, d); \ + return; \ + } + +#define CK_PR_BINARY_S(K, S, T) CK_PR_BINARY(K, S, T, T) + +#define CK_PR_GENERATE(K) \ + CK_PR_BINARY(K, ptr, void, void *) \ + CK_PR_BINARY_S(K, char, char) \ + CK_PR_BINARY_S(K, int, int) \ + CK_PR_BINARY_S(K, uint, unsigned int) \ + CK_PR_BINARY_S(K, 64, uint64_t) \ + CK_PR_BINARY_S(K, 32, uint32_t) \ + CK_PR_BINARY_S(K, 16, uint16_t) \ + CK_PR_BINARY_S(K, 8, uint8_t) + +CK_PR_GENERATE(add) +CK_PR_GENERATE(sub) +CK_PR_GENERATE(and) +CK_PR_GENERATE(or) +CK_PR_GENERATE(xor) + +#undef CK_PR_GENERATE +#undef CK_PR_BINARY_S +#undef CK_PR_BINARY + +#define CK_PR_UNARY(S, M, T) \ + CK_CC_INLINE static void \ + ck_pr_inc_##S(M *target) \ + { \ + ck_pr_add_##S(target, (T)1); \ + return; \ + } \ + CK_CC_INLINE static void \ + ck_pr_dec_##S(M *target) \ + { \ + ck_pr_sub_##S(target, (T)1); \ + return; \ + } + +#define CK_PR_UNARY_S(S, M) CK_PR_UNARY(S, M, M) + +CK_PR_UNARY(ptr, void, void *) +CK_PR_UNARY_S(char, char) +CK_PR_UNARY_S(int, int) +CK_PR_UNARY_S(uint, unsigned int) +CK_PR_UNARY_S(64, uint64_t) +CK_PR_UNARY_S(32, uint32_t) +CK_PR_UNARY_S(16, uint16_t) +CK_PR_UNARY_S(8, uint8_t) + +#undef CK_PR_UNARY_S +#undef CK_PR_UNARY +#endif /* !CK_F_PR */ +#endif /* CK_PR_GCC_H */ diff --git a/freebsd/sys/contrib/ck/include/gcc/ppc/ck_f_pr.h b/freebsd/sys/contrib/ck/include/gcc/ppc/ck_f_pr.h new file mode 100644 index 00000000..0aec33e4 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/ppc/ck_f_pr.h @@ -0,0 +1,79 @@ +/* DO NOT EDIT. This is auto-generated from feature.sh */ +#define CK_F_PR_ADD_32 +#define CK_F_PR_ADD_INT +#define CK_F_PR_ADD_PTR +#define CK_F_PR_ADD_UINT +#define CK_F_PR_AND_32 +#define CK_F_PR_AND_INT +#define CK_F_PR_AND_PTR +#define CK_F_PR_AND_UINT +#define CK_F_PR_CAS_32 +#define CK_F_PR_CAS_32_VALUE +#define CK_F_PR_CAS_INT +#define CK_F_PR_CAS_INT_VALUE +#define CK_F_PR_CAS_PTR +#define CK_F_PR_CAS_PTR_VALUE +#define CK_F_PR_CAS_UINT +#define CK_F_PR_CAS_UINT_VALUE +#define CK_F_PR_DEC_32 +#define CK_F_PR_DEC_INT +#define CK_F_PR_DEC_PTR +#define CK_F_PR_DEC_UINT +#define CK_F_PR_FAA_32 +#define CK_F_PR_FAA_INT +#define CK_F_PR_FAA_PTR +#define CK_F_PR_FAA_UINT +#define CK_F_PR_FAS_32 +#define CK_F_PR_FAS_INT +#define CK_F_PR_FAS_PTR +#define CK_F_PR_FAS_UINT +#define CK_F_PR_FENCE_LOAD +#define CK_F_PR_FENCE_LOAD_DEPENDS +#define CK_F_PR_FENCE_MEMORY +#define CK_F_PR_FENCE_STORE +#define CK_F_PR_FENCE_STRICT_LOAD +#define CK_F_PR_FENCE_STRICT_LOAD_DEPENDS +#define CK_F_PR_FENCE_STRICT_MEMORY +#define CK_F_PR_FENCE_STRICT_STORE +#define CK_F_PR_INC_32 +#define CK_F_PR_INC_INT +#define CK_F_PR_INC_PTR +#define CK_F_PR_INC_UINT +#define CK_F_PR_LOAD_16 +#define CK_F_PR_LOAD_32 +#define CK_F_PR_LOAD_8 +#define CK_F_PR_LOAD_CHAR +#define CK_F_PR_LOAD_INT +#define CK_F_PR_LOAD_PTR +#define CK_F_PR_LOAD_SHORT +#define CK_F_PR_LOAD_UINT +#define CK_F_PR_NEG_32 +#define CK_F_PR_NEG_INT +#define CK_F_PR_NEG_PTR +#define CK_F_PR_NEG_UINT +#define CK_F_PR_NOT_32 +#define CK_F_PR_NOT_INT +#define CK_F_PR_NOT_PTR +#define CK_F_PR_NOT_UINT +#define CK_F_PR_OR_32 +#define CK_F_PR_OR_INT +#define CK_F_PR_OR_PTR +#define CK_F_PR_OR_UINT +#define CK_F_PR_STALL +#define CK_F_PR_STORE_16 +#define CK_F_PR_STORE_32 +#define CK_F_PR_STORE_8 +#define CK_F_PR_STORE_CHAR +#define CK_F_PR_STORE_INT +#define CK_F_PR_STORE_PTR +#define CK_F_PR_STORE_SHORT +#define CK_F_PR_STORE_UINT +#define CK_F_PR_SUB_32 +#define CK_F_PR_SUB_INT +#define CK_F_PR_SUB_PTR +#define CK_F_PR_SUB_UINT +#define CK_F_PR_XOR_32 +#define CK_F_PR_XOR_INT +#define CK_F_PR_XOR_PTR +#define CK_F_PR_XOR_UINT + diff --git a/freebsd/sys/contrib/ck/include/gcc/ppc/ck_pr.h b/freebsd/sys/contrib/ck/include/gcc/ppc/ck_pr.h new file mode 100644 index 00000000..cd7935dd --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/ppc/ck_pr.h @@ -0,0 +1,327 @@ +/* + * Copyright 2009-2015 Samy Al Bahra. + * Copyright 2012 João Fernandes. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_PR_PPC_H +#define CK_PR_PPC_H + +#ifndef CK_PR_H +#error Do not include this file directly, use ck_pr.h +#endif + +#include <ck_cc.h> +#include <ck_md.h> + +/* + * The following represent supported atomic operations. + * These operations may be emulated. + */ +#include "ck_f_pr.h" + +/* + * Minimum interface requirement met. + */ +#define CK_F_PR + +/* + * This bounces the hardware thread from low to medium + * priority. I am unsure of the benefits of this approach + * but it is used by the Linux kernel. + */ +CK_CC_INLINE static void +ck_pr_stall(void) +{ + + __asm__ __volatile__("or 1, 1, 1;" + "or 2, 2, 2;" ::: "memory"); + return; +} + +#define CK_PR_FENCE(T, I) \ + CK_CC_INLINE static void \ + ck_pr_fence_strict_##T(void) \ + { \ + __asm__ __volatile__(I ::: "memory"); \ + } + +CK_PR_FENCE(atomic, "lwsync") +CK_PR_FENCE(atomic_store, "lwsync") +CK_PR_FENCE(atomic_load, "sync") +CK_PR_FENCE(store_atomic, "lwsync") +CK_PR_FENCE(load_atomic, "lwsync") +CK_PR_FENCE(store, "lwsync") +CK_PR_FENCE(store_load, "sync") +CK_PR_FENCE(load, "lwsync") +CK_PR_FENCE(load_store, "lwsync") +CK_PR_FENCE(memory, "sync") +CK_PR_FENCE(acquire, "lwsync") +CK_PR_FENCE(release, "lwsync") +CK_PR_FENCE(acqrel, "lwsync") +CK_PR_FENCE(lock, "lwsync") +CK_PR_FENCE(unlock, "lwsync") + +#undef CK_PR_FENCE + +#define CK_PR_LOAD(S, M, T, C, I) \ + CK_CC_INLINE static T \ + ck_pr_md_load_##S(const M *target) \ + { \ + T r; \ + __asm__ __volatile__(I "%U1%X1 %0, %1" \ + : "=r" (r) \ + : "m" (*(const C *)target) \ + : "memory"); \ + return (r); \ + } + +CK_PR_LOAD(ptr, void, void *, uint32_t, "lwz") + +#define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) + +CK_PR_LOAD_S(32, uint32_t, "lwz") +CK_PR_LOAD_S(16, uint16_t, "lhz") +CK_PR_LOAD_S(8, uint8_t, "lbz") +CK_PR_LOAD_S(uint, unsigned int, "lwz") +CK_PR_LOAD_S(int, int, "lwz") +CK_PR_LOAD_S(short, short, "lhz") +CK_PR_LOAD_S(char, char, "lbz") + +#undef CK_PR_LOAD_S +#undef CK_PR_LOAD + +#define CK_PR_STORE(S, M, T, C, I) \ + CK_CC_INLINE static void \ + ck_pr_md_store_##S(M *target, T v) \ + { \ + __asm__ __volatile__(I "%U0%X0 %1, %0" \ + : "=m" (*(C *)target) \ + : "r" (v) \ + : "memory"); \ + return; \ + } + +CK_PR_STORE(ptr, void, const void *, uint32_t, "stw") + +#define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) + +CK_PR_STORE_S(32, uint32_t, "stw") +CK_PR_STORE_S(16, uint16_t, "sth") +CK_PR_STORE_S(8, uint8_t, "stb") +CK_PR_STORE_S(uint, unsigned int, "stw") +CK_PR_STORE_S(int, int, "stw") +CK_PR_STORE_S(short, short, "sth") +CK_PR_STORE_S(char, char, "stb") + +#undef CK_PR_STORE_S +#undef CK_PR_STORE + +#define CK_PR_CAS(N, T, M) \ + CK_CC_INLINE static bool \ + ck_pr_cas_##N##_value(M *target, T compare, T set, M *value) \ + { \ + T previous; \ + __asm__ __volatile__("1:" \ + "lwarx %0, 0, %1;" \ + "cmpw 0, %0, %3;" \ + "bne- 2f;" \ + "stwcx. %2, 0, %1;" \ + "bne- 1b;" \ + "2:" \ + : "=&r" (previous) \ + : "r" (target), \ + "r" (set), \ + "r" (compare) \ + : "memory", "cc"); \ + *(T *)value = previous; \ + return (previous == compare); \ + } \ + CK_CC_INLINE static bool \ + ck_pr_cas_##N(M *target, T compare, T set) \ + { \ + T previous; \ + __asm__ __volatile__("1:" \ + "lwarx %0, 0, %1;" \ + "cmpw 0, %0, %3;" \ + "bne- 2f;" \ + "stwcx. %2, 0, %1;" \ + "bne- 1b;" \ + "2:" \ + : "=&r" (previous) \ + : "r" (target), \ + "r" (set), \ + "r" (compare) \ + : "memory", "cc"); \ + return (previous == compare); \ + } + +CK_PR_CAS(ptr, void *, void) +#define CK_PR_CAS_S(a, b) CK_PR_CAS(a, b, b) +CK_PR_CAS_S(32, uint32_t) +CK_PR_CAS_S(uint, unsigned int) +CK_PR_CAS_S(int, int) + +#undef CK_PR_CAS_S +#undef CK_PR_CAS + +#define CK_PR_FAS(N, M, T, W) \ + CK_CC_INLINE static T \ + ck_pr_fas_##N(M *target, T v) \ + { \ + T previous; \ + __asm__ __volatile__("1:" \ + "l" W "arx %0, 0, %1;" \ + "st" W "cx. %2, 0, %1;" \ + "bne- 1b;" \ + : "=&r" (previous) \ + : "r" (target), \ + "r" (v) \ + : "memory", "cc"); \ + return (previous); \ + } + +CK_PR_FAS(32, uint32_t, uint32_t, "w") +CK_PR_FAS(ptr, void, void *, "w") +CK_PR_FAS(int, int, int, "w") +CK_PR_FAS(uint, unsigned int, unsigned int, "w") + +#undef CK_PR_FAS + +#define CK_PR_UNARY(O, N, M, T, I, W) \ + CK_CC_INLINE static void \ + ck_pr_##O##_##N(M *target) \ + { \ + T previous; \ + __asm__ __volatile__("1:" \ + "l" W "arx %0, 0, %1;" \ + I ";" \ + "st" W "cx. %0, 0, %1;" \ + "bne- 1b;" \ + : "=&r" (previous) \ + : "r" (target) \ + : "memory", "cc"); \ + return; \ + } + +CK_PR_UNARY(inc, ptr, void, void *, "addic %0, %0, 1", "w") +CK_PR_UNARY(dec, ptr, void, void *, "addic %0, %0, -1", "w") +CK_PR_UNARY(not, ptr, void, void *, "not %0, %0", "w") +CK_PR_UNARY(neg, ptr, void, void *, "neg %0, %0", "w") + +#define CK_PR_UNARY_S(S, T, W) \ + CK_PR_UNARY(inc, S, T, T, "addic %0, %0, 1", W) \ + CK_PR_UNARY(dec, S, T, T, "addic %0, %0, -1", W) \ + CK_PR_UNARY(not, S, T, T, "not %0, %0", W) \ + CK_PR_UNARY(neg, S, T, T, "neg %0, %0", W) + +CK_PR_UNARY_S(32, uint32_t, "w") +CK_PR_UNARY_S(uint, unsigned int, "w") +CK_PR_UNARY_S(int, int, "w") + +#undef CK_PR_UNARY_S +#undef CK_PR_UNARY + +#define CK_PR_BINARY(O, N, M, T, I, W) \ + CK_CC_INLINE static void \ + ck_pr_##O##_##N(M *target, T delta) \ + { \ + T previous; \ + __asm__ __volatile__("1:" \ + "l" W "arx %0, 0, %1;" \ + I " %0, %2, %0;" \ + "st" W "cx. %0, 0, %1;" \ + "bne- 1b;" \ + : "=&r" (previous) \ + : "r" (target), \ + "r" (delta) \ + : "memory", "cc"); \ + return; \ + } + +CK_PR_BINARY(and, ptr, void, uintptr_t, "and", "w") +CK_PR_BINARY(add, ptr, void, uintptr_t, "add", "w") +CK_PR_BINARY(or, ptr, void, uintptr_t, "or", "w") +CK_PR_BINARY(sub, ptr, void, uintptr_t, "sub", "w") +CK_PR_BINARY(xor, ptr, void, uintptr_t, "xor", "w") + +#define CK_PR_BINARY_S(S, T, W) \ + CK_PR_BINARY(and, S, T, T, "and", W) \ + CK_PR_BINARY(add, S, T, T, "add", W) \ + CK_PR_BINARY(or, S, T, T, "or", W) \ + CK_PR_BINARY(sub, S, T, T, "subf", W) \ + CK_PR_BINARY(xor, S, T, T, "xor", W) + +CK_PR_BINARY_S(32, uint32_t, "w") +CK_PR_BINARY_S(uint, unsigned int, "w") +CK_PR_BINARY_S(int, int, "w") + +#undef CK_PR_BINARY_S +#undef CK_PR_BINARY + +CK_CC_INLINE static void * +ck_pr_faa_ptr(void *target, uintptr_t delta) +{ + uintptr_t previous, r; + + __asm__ __volatile__("1:" + "lwarx %0, 0, %2;" + "add %1, %3, %0;" + "stwcx. %1, 0, %2;" + "bne- 1b;" + : "=&r" (previous), + "=&r" (r) + : "r" (target), + "r" (delta) + : "memory", "cc"); + + return (void *)(previous); +} + +#define CK_PR_FAA(S, T, W) \ + CK_CC_INLINE static T \ + ck_pr_faa_##S(T *target, T delta) \ + { \ + T previous, r; \ + __asm__ __volatile__("1:" \ + "l" W "arx %0, 0, %2;" \ + "add %1, %3, %0;" \ + "st" W "cx. %1, 0, %2;" \ + "bne- 1b;" \ + : "=&r" (previous), \ + "=&r" (r) \ + : "r" (target), \ + "r" (delta) \ + : "memory", "cc"); \ + return (previous); \ + } + +CK_PR_FAA(32, uint32_t, "w") +CK_PR_FAA(uint, unsigned int, "w") +CK_PR_FAA(int, int, "w") + +#undef CK_PR_FAA + +#endif /* CK_PR_PPC_H */ + diff --git a/freebsd/sys/contrib/ck/include/gcc/ppc64/ck_f_pr.h b/freebsd/sys/contrib/ck/include/gcc/ppc64/ck_f_pr.h new file mode 100644 index 00000000..cd54a289 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/ppc64/ck_f_pr.h @@ -0,0 +1,97 @@ +/* DO NOT EDIT. This is auto-generated from feature.sh */ +#define CK_F_PR_ADD_32 +#define CK_F_PR_ADD_64 +#define CK_F_PR_ADD_INT +#define CK_F_PR_ADD_PTR +#define CK_F_PR_ADD_UINT +#define CK_F_PR_AND_32 +#define CK_F_PR_AND_64 +#define CK_F_PR_AND_INT +#define CK_F_PR_AND_PTR +#define CK_F_PR_AND_UINT +#define CK_F_PR_CAS_32 +#define CK_F_PR_CAS_32_VALUE +#define CK_F_PR_CAS_64 +#define CK_F_PR_CAS_64_VALUE +#define CK_F_PR_CAS_INT +#define CK_F_PR_CAS_INT_VALUE +#define CK_F_PR_CAS_PTR +#define CK_F_PR_CAS_PTR_VALUE +#define CK_F_PR_CAS_UINT +#define CK_F_PR_CAS_UINT_VALUE +#define CK_F_PR_DEC_32 +#define CK_F_PR_DEC_64 +#define CK_F_PR_DEC_INT +#define CK_F_PR_DEC_PTR +#define CK_F_PR_DEC_UINT +#define CK_F_PR_FAA_32 +#define CK_F_PR_FAA_64 +#define CK_F_PR_FAA_INT +#define CK_F_PR_FAA_PTR +#define CK_F_PR_FAA_UINT +#define CK_F_PR_FAS_32 +#define CK_F_PR_FAS_64 +#define CK_F_PR_FAS_INT +#define CK_F_PR_FAS_PTR +#define CK_F_PR_FAS_UINT +#define CK_F_PR_FAS_DOUBLE +#define CK_F_PR_FENCE_LOAD +#define CK_F_PR_FENCE_LOAD_DEPENDS +#define CK_F_PR_FENCE_MEMORY +#define CK_F_PR_FENCE_STORE +#define CK_F_PR_FENCE_STRICT_LOAD +#define CK_F_PR_FENCE_STRICT_LOAD_DEPENDS +#define CK_F_PR_FENCE_STRICT_MEMORY +#define CK_F_PR_FENCE_STRICT_STORE +#define CK_F_PR_INC_32 +#define CK_F_PR_INC_64 +#define CK_F_PR_INC_INT +#define CK_F_PR_INC_PTR +#define CK_F_PR_INC_UINT +#define CK_F_PR_LOAD_16 +#define CK_F_PR_LOAD_32 +#define CK_F_PR_LOAD_64 +#define CK_F_PR_LOAD_8 +#define CK_F_PR_LOAD_CHAR +#define CK_F_PR_LOAD_DOUBLE +#define CK_F_PR_LOAD_INT +#define CK_F_PR_LOAD_PTR +#define CK_F_PR_LOAD_SHORT +#define CK_F_PR_LOAD_UINT +#define CK_F_PR_NEG_32 +#define CK_F_PR_NEG_64 +#define CK_F_PR_NEG_INT +#define CK_F_PR_NEG_PTR +#define CK_F_PR_NEG_UINT +#define CK_F_PR_NOT_32 +#define CK_F_PR_NOT_64 +#define CK_F_PR_NOT_INT +#define CK_F_PR_NOT_PTR +#define CK_F_PR_NOT_UINT +#define CK_F_PR_OR_32 +#define CK_F_PR_OR_64 +#define CK_F_PR_OR_INT +#define CK_F_PR_OR_PTR +#define CK_F_PR_OR_UINT +#define CK_F_PR_STALL +#define CK_F_PR_STORE_16 +#define CK_F_PR_STORE_32 +#define CK_F_PR_STORE_64 +#define CK_F_PR_STORE_8 +#define CK_F_PR_STORE_CHAR +#define CK_F_PR_STORE_DOUBLE +#define CK_F_PR_STORE_INT +#define CK_F_PR_STORE_PTR +#define CK_F_PR_STORE_SHORT +#define CK_F_PR_STORE_UINT +#define CK_F_PR_SUB_32 +#define CK_F_PR_SUB_64 +#define CK_F_PR_SUB_INT +#define CK_F_PR_SUB_PTR +#define CK_F_PR_SUB_UINT +#define CK_F_PR_XOR_32 +#define CK_F_PR_XOR_64 +#define CK_F_PR_XOR_INT +#define CK_F_PR_XOR_PTR +#define CK_F_PR_XOR_UINT + diff --git a/freebsd/sys/contrib/ck/include/gcc/ppc64/ck_pr.h b/freebsd/sys/contrib/ck/include/gcc/ppc64/ck_pr.h new file mode 100644 index 00000000..3f5e5db0 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/ppc64/ck_pr.h @@ -0,0 +1,427 @@ +/* + * Copyright 2009-2015 Samy Al Bahra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_PR_PPC64_H +#define CK_PR_PPC64_H + +#ifndef CK_PR_H +#error Do not include this file directly, use ck_pr.h +#endif + +#include <ck_cc.h> +#include <ck_md.h> + +/* + * The following represent supported atomic operations. + * These operations may be emulated. + */ +#include "ck_f_pr.h" + +/* + * Minimum interface requirement met. + */ +#define CK_F_PR + +/* + * This bounces the hardware thread from low to medium + * priority. I am unsure of the benefits of this approach + * but it is used by the Linux kernel. + */ +CK_CC_INLINE static void +ck_pr_stall(void) +{ + + __asm__ __volatile__("or 1, 1, 1;" + "or 2, 2, 2;" ::: "memory"); + return; +} + +#define CK_PR_FENCE(T, I) \ + CK_CC_INLINE static void \ + ck_pr_fence_strict_##T(void) \ + { \ + __asm__ __volatile__(I ::: "memory"); \ + } + +/* + * These are derived from: + * http://www.ibm.com/developerworks/systems/articles/powerpc.html + */ +CK_PR_FENCE(atomic, "lwsync") +CK_PR_FENCE(atomic_store, "lwsync") +CK_PR_FENCE(atomic_load, "sync") +CK_PR_FENCE(store_atomic, "lwsync") +CK_PR_FENCE(load_atomic, "lwsync") +CK_PR_FENCE(store, "lwsync") +CK_PR_FENCE(store_load, "sync") +CK_PR_FENCE(load, "lwsync") +CK_PR_FENCE(load_store, "lwsync") +CK_PR_FENCE(memory, "sync") +CK_PR_FENCE(acquire, "lwsync") +CK_PR_FENCE(release, "lwsync") +CK_PR_FENCE(acqrel, "lwsync") +CK_PR_FENCE(lock, "lwsync") +CK_PR_FENCE(unlock, "lwsync") + +#undef CK_PR_FENCE + +#define CK_PR_LOAD(S, M, T, C, I) \ + CK_CC_INLINE static T \ + ck_pr_md_load_##S(const M *target) \ + { \ + T r; \ + __asm__ __volatile__(I "%U1%X1 %0, %1" \ + : "=r" (r) \ + : "m" (*(const C *)target) \ + : "memory"); \ + return (r); \ + } + +CK_PR_LOAD(ptr, void, void *, uint64_t, "ld") + +#define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) + +CK_PR_LOAD_S(64, uint64_t, "ld") +CK_PR_LOAD_S(32, uint32_t, "lwz") +CK_PR_LOAD_S(16, uint16_t, "lhz") +CK_PR_LOAD_S(8, uint8_t, "lbz") +CK_PR_LOAD_S(uint, unsigned int, "lwz") +CK_PR_LOAD_S(int, int, "lwz") +CK_PR_LOAD_S(short, short, "lhz") +CK_PR_LOAD_S(char, char, "lbz") +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_LOAD_S(double, double, "ld") +#endif + +#undef CK_PR_LOAD_S +#undef CK_PR_LOAD + +#define CK_PR_STORE(S, M, T, C, I) \ + CK_CC_INLINE static void \ + ck_pr_md_store_##S(M *target, T v) \ + { \ + __asm__ __volatile__(I "%U0%X0 %1, %0" \ + : "=m" (*(C *)target) \ + : "r" (v) \ + : "memory"); \ + return; \ + } + +CK_PR_STORE(ptr, void, const void *, uint64_t, "std") + +#define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) + +CK_PR_STORE_S(64, uint64_t, "std") +CK_PR_STORE_S(32, uint32_t, "stw") +CK_PR_STORE_S(16, uint16_t, "sth") +CK_PR_STORE_S(8, uint8_t, "stb") +CK_PR_STORE_S(uint, unsigned int, "stw") +CK_PR_STORE_S(int, int, "stw") +CK_PR_STORE_S(short, short, "sth") +CK_PR_STORE_S(char, char, "stb") +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_STORE_S(double, double, "std") +#endif + +#undef CK_PR_STORE_S +#undef CK_PR_STORE + +CK_CC_INLINE static bool +ck_pr_cas_64_value(uint64_t *target, uint64_t compare, uint64_t set, uint64_t *value) +{ + uint64_t previous; + + __asm__ __volatile__("1:" + "ldarx %0, 0, %1;" + "cmpd 0, %0, %3;" + "bne- 2f;" + "stdcx. %2, 0, %1;" + "bne- 1b;" + "2:" + : "=&r" (previous) + : "r" (target), + "r" (set), + "r" (compare) + : "memory", "cc"); + + *value = previous; + return (previous == compare); +} + +CK_CC_INLINE static bool +ck_pr_cas_ptr_value(void *target, void *compare, void *set, void *value) +{ + void *previous; + + __asm__ __volatile__("1:" + "ldarx %0, 0, %1;" + "cmpd 0, %0, %3;" + "bne- 2f;" + "stdcx. %2, 0, %1;" + "bne- 1b;" + "2:" + : "=&r" (previous) + : "r" (target), + "r" (set), + "r" (compare) + : "memory", "cc"); + + ck_pr_md_store_ptr(value, previous); + return (previous == compare); +} + +CK_CC_INLINE static bool +ck_pr_cas_64(uint64_t *target, uint64_t compare, uint64_t set) +{ + uint64_t previous; + + __asm__ __volatile__("1:" + "ldarx %0, 0, %1;" + "cmpd 0, %0, %3;" + "bne- 2f;" + "stdcx. %2, 0, %1;" + "bne- 1b;" + "2:" + : "=&r" (previous) + : "r" (target), + "r" (set), + "r" (compare) + : "memory", "cc"); + + return (previous == compare); +} + +CK_CC_INLINE static bool +ck_pr_cas_ptr(void *target, void *compare, void *set) +{ + void *previous; + + __asm__ __volatile__("1:" + "ldarx %0, 0, %1;" + "cmpd 0, %0, %3;" + "bne- 2f;" + "stdcx. %2, 0, %1;" + "bne- 1b;" + "2:" + : "=&r" (previous) + : "r" (target), + "r" (set), + "r" (compare) + : "memory", "cc"); + + return (previous == compare); +} + +#define CK_PR_CAS(N, T) \ + CK_CC_INLINE static bool \ + ck_pr_cas_##N##_value(T *target, T compare, T set, T *value) \ + { \ + T previous; \ + __asm__ __volatile__("1:" \ + "lwarx %0, 0, %1;" \ + "cmpw 0, %0, %3;" \ + "bne- 2f;" \ + "stwcx. %2, 0, %1;" \ + "bne- 1b;" \ + "2:" \ + : "=&r" (previous) \ + : "r" (target), \ + "r" (set), \ + "r" (compare) \ + : "memory", "cc"); \ + *value = previous; \ + return (previous == compare); \ + } \ + CK_CC_INLINE static bool \ + ck_pr_cas_##N(T *target, T compare, T set) \ + { \ + T previous; \ + __asm__ __volatile__("1:" \ + "lwarx %0, 0, %1;" \ + "cmpw 0, %0, %3;" \ + "bne- 2f;" \ + "stwcx. %2, 0, %1;" \ + "bne- 1b;" \ + "2:" \ + : "=&r" (previous) \ + : "r" (target), \ + "r" (set), \ + "r" (compare) \ + : "memory", "cc"); \ + return (previous == compare); \ + } + +CK_PR_CAS(32, uint32_t) +CK_PR_CAS(uint, unsigned int) +CK_PR_CAS(int, int) + +#undef CK_PR_CAS + +#define CK_PR_FAS(N, M, T, W) \ + CK_CC_INLINE static T \ + ck_pr_fas_##N(M *target, T v) \ + { \ + T previous; \ + __asm__ __volatile__("1:" \ + "l" W "arx %0, 0, %1;" \ + "st" W "cx. %2, 0, %1;" \ + "bne- 1b;" \ + : "=&r" (previous) \ + : "r" (target), \ + "r" (v) \ + : "memory", "cc"); \ + return (previous); \ + } + +CK_PR_FAS(64, uint64_t, uint64_t, "d") +CK_PR_FAS(32, uint32_t, uint32_t, "w") +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_FAS(double, double, double, "d") +#endif +CK_PR_FAS(ptr, void, void *, "d") +CK_PR_FAS(int, int, int, "w") +CK_PR_FAS(uint, unsigned int, unsigned int, "w") + +#undef CK_PR_FAS + +#define CK_PR_UNARY(O, N, M, T, I, W) \ + CK_CC_INLINE static void \ + ck_pr_##O##_##N(M *target) \ + { \ + T previous; \ + __asm__ __volatile__("1:" \ + "l" W "arx %0, 0, %1;" \ + I ";" \ + "st" W "cx. %0, 0, %1;" \ + "bne- 1b;" \ + : "=&r" (previous) \ + : "r" (target) \ + : "memory", "cc"); \ + return; \ + } + +CK_PR_UNARY(inc, ptr, void, void *, "addic %0, %0, 1", "d") +CK_PR_UNARY(dec, ptr, void, void *, "addic %0, %0, -1", "d") +CK_PR_UNARY(not, ptr, void, void *, "not %0, %0", "d") +CK_PR_UNARY(neg, ptr, void, void *, "neg %0, %0", "d") + +#define CK_PR_UNARY_S(S, T, W) \ + CK_PR_UNARY(inc, S, T, T, "addic %0, %0, 1", W) \ + CK_PR_UNARY(dec, S, T, T, "addic %0, %0, -1", W) \ + CK_PR_UNARY(not, S, T, T, "not %0, %0", W) \ + CK_PR_UNARY(neg, S, T, T, "neg %0, %0", W) + +CK_PR_UNARY_S(64, uint64_t, "d") +CK_PR_UNARY_S(32, uint32_t, "w") +CK_PR_UNARY_S(uint, unsigned int, "w") +CK_PR_UNARY_S(int, int, "w") + +#undef CK_PR_UNARY_S +#undef CK_PR_UNARY + +#define CK_PR_BINARY(O, N, M, T, I, W) \ + CK_CC_INLINE static void \ + ck_pr_##O##_##N(M *target, T delta) \ + { \ + T previous; \ + __asm__ __volatile__("1:" \ + "l" W "arx %0, 0, %1;" \ + I " %0, %2, %0;" \ + "st" W "cx. %0, 0, %1;" \ + "bne- 1b;" \ + : "=&r" (previous) \ + : "r" (target), \ + "r" (delta) \ + : "memory", "cc"); \ + return; \ + } + +CK_PR_BINARY(and, ptr, void, uintptr_t, "and", "d") +CK_PR_BINARY(add, ptr, void, uintptr_t, "add", "d") +CK_PR_BINARY(or, ptr, void, uintptr_t, "or", "d") +CK_PR_BINARY(sub, ptr, void, uintptr_t, "sub", "d") +CK_PR_BINARY(xor, ptr, void, uintptr_t, "xor", "d") + +#define CK_PR_BINARY_S(S, T, W) \ + CK_PR_BINARY(and, S, T, T, "and", W) \ + CK_PR_BINARY(add, S, T, T, "add", W) \ + CK_PR_BINARY(or, S, T, T, "or", W) \ + CK_PR_BINARY(sub, S, T, T, "subf", W) \ + CK_PR_BINARY(xor, S, T, T, "xor", W) + +CK_PR_BINARY_S(64, uint64_t, "d") +CK_PR_BINARY_S(32, uint32_t, "w") +CK_PR_BINARY_S(uint, unsigned int, "w") +CK_PR_BINARY_S(int, int, "w") + +#undef CK_PR_BINARY_S +#undef CK_PR_BINARY + +CK_CC_INLINE static void * +ck_pr_faa_ptr(void *target, uintptr_t delta) +{ + uintptr_t previous, r; + + __asm__ __volatile__("1:" + "ldarx %0, 0, %2;" + "add %1, %3, %0;" + "stdcx. %1, 0, %2;" + "bne- 1b;" + : "=&r" (previous), + "=&r" (r) + : "r" (target), + "r" (delta) + : "memory", "cc"); + + return (void *)(previous); +} + +#define CK_PR_FAA(S, T, W) \ + CK_CC_INLINE static T \ + ck_pr_faa_##S(T *target, T delta) \ + { \ + T previous, r; \ + __asm__ __volatile__("1:" \ + "l" W "arx %0, 0, %2;" \ + "add %1, %3, %0;" \ + "st" W "cx. %1, 0, %2;" \ + "bne- 1b;" \ + : "=&r" (previous), \ + "=&r" (r) \ + : "r" (target), \ + "r" (delta) \ + : "memory", "cc"); \ + return (previous); \ + } + +CK_PR_FAA(64, uint64_t, "d") +CK_PR_FAA(32, uint32_t, "w") +CK_PR_FAA(uint, unsigned int, "w") +CK_PR_FAA(int, int, "w") + +#undef CK_PR_FAA + +#endif /* CK_PR_PPC64_H */ diff --git a/freebsd/sys/contrib/ck/include/gcc/sparcv9/ck_f_pr.h b/freebsd/sys/contrib/ck/include/gcc/sparcv9/ck_f_pr.h new file mode 100644 index 00000000..0398680e --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/sparcv9/ck_f_pr.h @@ -0,0 +1,26 @@ +#define CK_F_PR_CAS_64 +#define CK_F_PR_CAS_64_VALUE +#define CK_F_PR_CAS_PTR +#define CK_F_PR_CAS_PTR_VALUE +#define CK_F_PR_FAS_32 +#define CK_F_PR_FAS_UINT +#define CK_F_PR_FAS_INT +#define CK_F_PR_CAS_32 +#define CK_F_PR_CAS_32_VALUE +#define CK_F_PR_CAS_UINT +#define CK_F_PR_CAS_INT +#define CK_F_PR_CAS_UINT_VALUE +#define CK_F_PR_CAS_INT_VALUE +#define CK_F_PR_STORE_64 +#define CK_F_PR_STORE_32 +#define CK_F_PR_STORE_DOUBLE +#define CK_F_PR_STORE_UINT +#define CK_F_PR_STORE_INT +#define CK_F_PR_STORE_PTR +#define CK_F_PR_LOAD_64 +#define CK_F_PR_LOAD_32 +#define CK_F_PR_LOAD_DOUBLE +#define CK_F_PR_LOAD_UINT +#define CK_F_PR_LOAD_INT +#define CK_F_PR_LOAD_PTR + diff --git a/freebsd/sys/contrib/ck/include/gcc/sparcv9/ck_pr.h b/freebsd/sys/contrib/ck/include/gcc/sparcv9/ck_pr.h new file mode 100644 index 00000000..7dc71725 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/sparcv9/ck_pr.h @@ -0,0 +1,228 @@ +/* + * Copyright 2009, 2010 Samy Al Bahra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_PR_SPARCV9_H +#define CK_PR_SPARCV9_H + +#ifndef CK_PR_H +#error Do not include this file directly, use ck_pr.h +#endif + +#include <ck_cc.h> +#include <ck_md.h> + +/* + * The following represent supported atomic operations. + * These operations may be emulated. + */ +#include "ck_f_pr.h" + +/* + * Minimum interface requirement met. + */ +#define CK_F_PR + +/* + * Order loads at the least. + */ +CK_CC_INLINE static void +ck_pr_stall(void) +{ + + __asm__ __volatile__("membar #LoadLoad" ::: "memory"); + return; +} + +#define CK_PR_FENCE(T, I) \ + CK_CC_INLINE static void \ + ck_pr_fence_strict_##T(void) \ + { \ + __asm__ __volatile__(I ::: "memory"); \ + } + +/* + * Atomic operations are treated as both load and store + * operations on SPARCv9. + */ +CK_PR_FENCE(atomic, "membar #StoreStore") +CK_PR_FENCE(atomic_store, "membar #StoreStore") +CK_PR_FENCE(atomic_load, "membar #StoreLoad") +CK_PR_FENCE(store_atomic, "membar #StoreStore") +CK_PR_FENCE(load_atomic, "membar #LoadStore") +CK_PR_FENCE(store, "membar #StoreStore") +CK_PR_FENCE(store_load, "membar #StoreLoad") +CK_PR_FENCE(load, "membar #LoadLoad") +CK_PR_FENCE(load_store, "membar #LoadStore") +CK_PR_FENCE(memory, "membar #MemIssue") +CK_PR_FENCE(acquire, "membar #LoadLoad | #LoadStore") +CK_PR_FENCE(release, "membar #LoadStore | #StoreStore") +CK_PR_FENCE(acqrel, "membar #LoadLoad | #LoadStore | #StoreStore") +CK_PR_FENCE(lock, "membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad") +CK_PR_FENCE(unlock, "membar #LoadStore | #StoreStore") + +#undef CK_PR_FENCE + +#define CK_PR_LOAD(S, M, T, C, I) \ + CK_CC_INLINE static T \ + ck_pr_md_load_##S(const M *target) \ + { \ + T r; \ + __asm__ __volatile__(I " [%1], %0" \ + : "=&r" (r) \ + : "r" (target) \ + : "memory"); \ + return (r); \ + } + +CK_PR_LOAD(ptr, void, void *, uint64_t, "ldx") + +#define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) + +CK_PR_LOAD_S(64, uint64_t, "ldx") +CK_PR_LOAD_S(32, uint32_t, "lduw") +CK_PR_LOAD_S(uint, unsigned int, "lduw") +CK_PR_LOAD_S(double, double, "ldx") +CK_PR_LOAD_S(int, int, "ldsw") + +#undef CK_PR_LOAD_S +#undef CK_PR_LOAD + +#define CK_PR_STORE(S, M, T, C, I) \ + CK_CC_INLINE static void \ + ck_pr_md_store_##S(M *target, T v) \ + { \ + __asm__ __volatile__(I " %0, [%1]" \ + : \ + : "r" (v), \ + "r" (target) \ + : "memory"); \ + return; \ + } + +CK_PR_STORE(ptr, void, const void *, uint64_t, "stx") + +#define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) + +CK_PR_STORE_S(8, uint8_t, "stub") +CK_PR_STORE_S(64, uint64_t, "stx") +CK_PR_STORE_S(32, uint32_t, "stuw") +CK_PR_STORE_S(uint, unsigned int, "stuw") +CK_PR_STORE_S(double, double, "stx") +CK_PR_STORE_S(int, int, "stsw") + +#undef CK_PR_STORE_S +#undef CK_PR_STORE + +CK_CC_INLINE static bool +ck_pr_cas_64_value(uint64_t *target, uint64_t compare, uint64_t set, uint64_t *value) +{ + + __asm__ __volatile__("casx [%1], %2, %0" + : "+&r" (set) + : "r" (target), + "r" (compare) + : "memory"); + + *value = set; + return (compare == set); +} + +CK_CC_INLINE static bool +ck_pr_cas_64(uint64_t *target, uint64_t compare, uint64_t set) +{ + + __asm__ __volatile__("casx [%1], %2, %0" + : "+&r" (set) + : "r" (target), + "r" (compare) + : "memory"); + + return (compare == set); +} + +CK_CC_INLINE static bool +ck_pr_cas_ptr(void *target, void *compare, void *set) +{ + + return ck_pr_cas_64(target, (uint64_t)compare, (uint64_t)set); +} + +CK_CC_INLINE static bool +ck_pr_cas_ptr_value(void *target, void *compare, void *set, void *previous) +{ + + return ck_pr_cas_64_value(target, (uint64_t)compare, (uint64_t)set, previous); +} + +#define CK_PR_CAS(N, T) \ + CK_CC_INLINE static bool \ + ck_pr_cas_##N##_value(T *target, T compare, T set, T *value) \ + { \ + __asm__ __volatile__("cas [%1], %2, %0" \ + : "+&r" (set) \ + : "r" (target), \ + "r" (compare) \ + : "memory"); \ + *value = set; \ + return (compare == set); \ + } \ + CK_CC_INLINE static bool \ + ck_pr_cas_##N(T *target, T compare, T set) \ + { \ + __asm__ __volatile__("cas [%1], %2, %0" \ + : "+&r" (set) \ + : "r" (target), \ + "r" (compare) \ + : "memory"); \ + return (compare == set); \ + } + +CK_PR_CAS(32, uint32_t) +CK_PR_CAS(uint, unsigned int) +CK_PR_CAS(int, int) + +#undef CK_PR_CAS + +#define CK_PR_FAS(N, T) \ + CK_CC_INLINE static T \ + ck_pr_fas_##N(T *target, T update) \ + { \ + \ + __asm__ __volatile__("swap [%1], %0" \ + : "+&r" (update) \ + : "r" (target) \ + : "memory"); \ + return (update); \ + } + +CK_PR_FAS(int, int) +CK_PR_FAS(uint, unsigned int) +CK_PR_FAS(32, uint32_t) + +#undef CK_PR_FAS + +#endif /* CK_PR_SPARCV9_H */ + diff --git a/freebsd/sys/contrib/ck/include/gcc/x86/ck_f_pr.h b/freebsd/sys/contrib/ck/include/gcc/x86/ck_f_pr.h new file mode 100644 index 00000000..f82c66b0 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/x86/ck_f_pr.h @@ -0,0 +1,152 @@ +/* DO NOT EDIT. This is auto-generated from feature.sh */ +#define CK_F_PR_ADD_16 +#define CK_F_PR_ADD_32 +#define CK_F_PR_ADD_8 +#define CK_F_PR_ADD_CHAR +#define CK_F_PR_ADD_INT +#define CK_F_PR_ADD_PTR +#define CK_F_PR_ADD_UINT +#define CK_F_PR_AND_16 +#define CK_F_PR_AND_32 +#define CK_F_PR_AND_8 +#define CK_F_PR_AND_CHAR +#define CK_F_PR_AND_INT +#define CK_F_PR_AND_PTR +#define CK_F_PR_AND_UINT +#define CK_F_PR_BTC_16 +#define CK_F_PR_BTC_32 +#define CK_F_PR_BTC_INT +#define CK_F_PR_BTC_PTR +#define CK_F_PR_BTC_UINT +#define CK_F_PR_BTR_16 +#define CK_F_PR_BTR_32 +#define CK_F_PR_BTR_INT +#define CK_F_PR_BTR_PTR +#define CK_F_PR_BTR_UINT +#define CK_F_PR_BTS_16 +#define CK_F_PR_BTS_32 +#define CK_F_PR_BTS_INT +#define CK_F_PR_BTS_PTR +#define CK_F_PR_BTS_UINT +#define CK_F_PR_CAS_16 +#define CK_F_PR_CAS_16_VALUE +#define CK_F_PR_CAS_32 +#define CK_F_PR_CAS_32_VALUE +#define CK_F_PR_CAS_8 +#define CK_F_PR_CAS_8_VALUE +#define CK_F_PR_CAS_CHAR +#define CK_F_PR_CAS_CHAR_VALUE +#define CK_F_PR_CAS_INT +#define CK_F_PR_CAS_INT_VALUE +#define CK_F_PR_CAS_PTR +#define CK_F_PR_CAS_PTR_VALUE +#define CK_F_PR_CAS_UINT +#define CK_F_PR_CAS_UINT_VALUE +#define CK_F_PR_DEC_16 +#define CK_F_PR_DEC_16_ZERO +#define CK_F_PR_DEC_32 +#define CK_F_PR_DEC_32_ZERO +#define CK_F_PR_DEC_8 +#define CK_F_PR_DEC_8_ZERO +#define CK_F_PR_DEC_CHAR +#define CK_F_PR_DEC_CHAR_ZERO +#define CK_F_PR_DEC_INT +#define CK_F_PR_DEC_INT_ZERO +#define CK_F_PR_DEC_PTR +#define CK_F_PR_DEC_PTR_ZERO +#define CK_F_PR_DEC_UINT +#define CK_F_PR_DEC_UINT_ZERO +#define CK_F_PR_FAA_16 +#define CK_F_PR_FAA_32 +#define CK_F_PR_FAA_8 +#define CK_F_PR_FAA_CHAR +#define CK_F_PR_FAA_INT +#define CK_F_PR_FAA_PTR +#define CK_F_PR_FAA_UINT +#define CK_F_PR_FAS_16 +#define CK_F_PR_FAS_32 +#define CK_F_PR_FAS_8 +#define CK_F_PR_FAS_CHAR +#define CK_F_PR_FAS_INT +#define CK_F_PR_FAS_PTR +#define CK_F_PR_FAS_UINT +#define CK_F_PR_FENCE_LOAD +#define CK_F_PR_FENCE_LOAD_DEPENDS +#define CK_F_PR_FENCE_MEMORY +#define CK_F_PR_FENCE_STORE +#define CK_F_PR_FENCE_STRICT_LOAD +#define CK_F_PR_FENCE_STRICT_LOAD_DEPENDS +#define CK_F_PR_FENCE_STRICT_MEMORY +#define CK_F_PR_FENCE_STRICT_STORE +#define CK_F_PR_INC_16 +#define CK_F_PR_INC_16_ZERO +#define CK_F_PR_INC_32 +#define CK_F_PR_INC_32_ZERO +#define CK_F_PR_INC_8 +#define CK_F_PR_INC_8_ZERO +#define CK_F_PR_INC_CHAR +#define CK_F_PR_INC_CHAR_ZERO +#define CK_F_PR_INC_INT +#define CK_F_PR_INC_INT_ZERO +#define CK_F_PR_INC_PTR +#define CK_F_PR_INC_PTR_ZERO +#define CK_F_PR_INC_UINT +#define CK_F_PR_INC_UINT_ZERO +#define CK_F_PR_LOAD_16 +#define CK_F_PR_LOAD_32 +#define CK_F_PR_LOAD_8 +#define CK_F_PR_LOAD_CHAR +#define CK_F_PR_LOAD_INT +#define CK_F_PR_LOAD_PTR +#define CK_F_PR_LOAD_UINT +#define CK_F_PR_NEG_16 +#define CK_F_PR_NEG_16_ZERO +#define CK_F_PR_NEG_32 +#define CK_F_PR_NEG_32_ZERO +#define CK_F_PR_NEG_8 +#define CK_F_PR_NEG_8_ZERO +#define CK_F_PR_NEG_CHAR +#define CK_F_PR_NEG_CHAR_ZERO +#define CK_F_PR_NEG_INT +#define CK_F_PR_NEG_INT_ZERO +#define CK_F_PR_NEG_PTR +#define CK_F_PR_NEG_PTR_ZERO +#define CK_F_PR_NEG_UINT +#define CK_F_PR_NEG_UINT_ZERO +#define CK_F_PR_NOT_16 +#define CK_F_PR_NOT_32 +#define CK_F_PR_NOT_8 +#define CK_F_PR_NOT_CHAR +#define CK_F_PR_NOT_INT +#define CK_F_PR_NOT_PTR +#define CK_F_PR_NOT_UINT +#define CK_F_PR_OR_16 +#define CK_F_PR_OR_32 +#define CK_F_PR_OR_8 +#define CK_F_PR_OR_CHAR +#define CK_F_PR_OR_INT +#define CK_F_PR_OR_PTR +#define CK_F_PR_OR_UINT +#define CK_F_PR_STALL +#define CK_F_PR_STORE_16 +#define CK_F_PR_STORE_32 +#define CK_F_PR_STORE_8 +#define CK_F_PR_STORE_CHAR +#define CK_F_PR_STORE_INT +#define CK_F_PR_STORE_PTR +#define CK_F_PR_STORE_UINT +#define CK_F_PR_SUB_16 +#define CK_F_PR_SUB_32 +#define CK_F_PR_SUB_8 +#define CK_F_PR_SUB_CHAR +#define CK_F_PR_SUB_INT +#define CK_F_PR_SUB_PTR +#define CK_F_PR_SUB_UINT +#define CK_F_PR_XOR_16 +#define CK_F_PR_XOR_32 +#define CK_F_PR_XOR_8 +#define CK_F_PR_XOR_CHAR +#define CK_F_PR_XOR_INT +#define CK_F_PR_XOR_PTR +#define CK_F_PR_XOR_UINT + diff --git a/freebsd/sys/contrib/ck/include/gcc/x86/ck_pr.h b/freebsd/sys/contrib/ck/include/gcc/x86/ck_pr.h new file mode 100644 index 00000000..3e36376f --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/x86/ck_pr.h @@ -0,0 +1,408 @@ +/* + * Copyright 2009-2015 Samy Al Bahra. + * Copyright 2011 Devon H. O'Dell <devon.odell@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_PR_X86_H +#define CK_PR_X86_H + +#ifndef CK_PR_H +#error Do not include this file directly, use ck_pr.h +#endif + +#include <ck_cc.h> +#include <ck_md.h> +#include <ck_stdint.h> + +/* + * The following represent supported atomic operations. + * These operations may be emulated. + */ +#include "ck_f_pr.h" + +/* Minimum requirements for the CK_PR interface are met. */ +#define CK_F_PR + +/* + * Prevent speculative execution in busy-wait loops (P4 <=) or "predefined + * delay". + */ +CK_CC_INLINE static void +ck_pr_stall(void) +{ + __asm__ __volatile__("pause" ::: "memory"); + return; +} + +#ifdef CK_MD_UMP +#define CK_PR_LOCK_PREFIX +#define CK_PR_FENCE(T, I) \ + CK_CC_INLINE static void \ + ck_pr_fence_strict_##T(void) \ + { \ + __asm__ __volatile__("" ::: "memory"); \ + return; \ + } +#else +#define CK_PR_LOCK_PREFIX "lock " +#define CK_PR_FENCE(T, I) \ + CK_CC_INLINE static void \ + ck_pr_fence_strict_##T(void) \ + { \ + __asm__ __volatile__(I ::: "memory"); \ + return; \ + } +#endif /* CK_MD_UMP */ + +#if defined(CK_MD_SSE_DISABLE) +/* If SSE is disabled, then use atomic operations for serialization. */ +#define CK_MD_X86_MFENCE "lock addl $0, (%%esp)" +#define CK_MD_X86_SFENCE CK_MD_X86_MFENCE +#define CK_MD_X86_LFENCE CK_MD_X86_MFENCE +#else +#define CK_MD_X86_SFENCE "sfence" +#define CK_MD_X86_LFENCE "lfence" +#define CK_MD_X86_MFENCE "mfence" +#endif /* !CK_MD_SSE_DISABLE */ + +CK_PR_FENCE(atomic, "") +CK_PR_FENCE(atomic_store, "") +CK_PR_FENCE(atomic_load, "") +CK_PR_FENCE(store_atomic, "") +CK_PR_FENCE(load_atomic, "") +CK_PR_FENCE(load, CK_MD_X86_LFENCE) +CK_PR_FENCE(load_store, CK_MD_X86_MFENCE) +CK_PR_FENCE(store, CK_MD_X86_SFENCE) +CK_PR_FENCE(store_load, CK_MD_X86_MFENCE) +CK_PR_FENCE(memory, CK_MD_X86_MFENCE) +CK_PR_FENCE(release, CK_MD_X86_MFENCE) +CK_PR_FENCE(acquire, CK_MD_X86_MFENCE) +CK_PR_FENCE(acqrel, CK_MD_X86_MFENCE) +CK_PR_FENCE(lock, CK_MD_X86_MFENCE) +CK_PR_FENCE(unlock, CK_MD_X86_MFENCE) + +#undef CK_PR_FENCE + +/* + * Atomic fetch-and-store operations. + */ +#define CK_PR_FAS(S, M, T, C, I) \ + CK_CC_INLINE static T \ + ck_pr_fas_##S(M *target, T v) \ + { \ + __asm__ __volatile__(I " %0, %1" \ + : "+m" (*(C *)target), \ + "+q" (v) \ + : \ + : "memory"); \ + return v; \ + } + +CK_PR_FAS(ptr, void, void *, char, "xchgl") + +#define CK_PR_FAS_S(S, T, I) CK_PR_FAS(S, T, T, T, I) + +CK_PR_FAS_S(char, char, "xchgb") +CK_PR_FAS_S(uint, unsigned int, "xchgl") +CK_PR_FAS_S(int, int, "xchgl") +CK_PR_FAS_S(32, uint32_t, "xchgl") +CK_PR_FAS_S(16, uint16_t, "xchgw") +CK_PR_FAS_S(8, uint8_t, "xchgb") + +#undef CK_PR_FAS_S +#undef CK_PR_FAS + +#define CK_PR_LOAD(S, M, T, C, I) \ + CK_CC_INLINE static T \ + ck_pr_md_load_##S(const M *target) \ + { \ + T r; \ + __asm__ __volatile__(I " %1, %0" \ + : "=q" (r) \ + : "m" (*(const C *)target) \ + : "memory"); \ + return (r); \ + } + +CK_PR_LOAD(ptr, void, void *, char, "movl") + +#define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) + +CK_PR_LOAD_S(char, char, "movb") +CK_PR_LOAD_S(uint, unsigned int, "movl") +CK_PR_LOAD_S(int, int, "movl") +CK_PR_LOAD_S(32, uint32_t, "movl") +CK_PR_LOAD_S(16, uint16_t, "movw") +CK_PR_LOAD_S(8, uint8_t, "movb") + +#undef CK_PR_LOAD_S +#undef CK_PR_LOAD + +#define CK_PR_STORE(S, M, T, C, I) \ + CK_CC_INLINE static void \ + ck_pr_md_store_##S(M *target, T v) \ + { \ + __asm__ __volatile__(I " %1, %0" \ + : "=m" (*(C *)target) \ + : CK_CC_IMM "q" (v) \ + : "memory"); \ + return; \ + } + +CK_PR_STORE(ptr, void, const void *, char, "movl") + +#define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I) + +CK_PR_STORE_S(char, char, "movb") +CK_PR_STORE_S(uint, unsigned int, "movl") +CK_PR_STORE_S(int, int, "movl") +CK_PR_STORE_S(32, uint32_t, "movl") +CK_PR_STORE_S(16, uint16_t, "movw") +CK_PR_STORE_S(8, uint8_t, "movb") + +#undef CK_PR_STORE_S +#undef CK_PR_STORE + +/* + * Atomic fetch-and-add operations. + */ +#define CK_PR_FAA(S, M, T, C, I) \ + CK_CC_INLINE static T \ + ck_pr_faa_##S(M *target, T d) \ + { \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0" \ + : "+m" (*(C *)target), \ + "+q" (d) \ + : \ + : "memory", "cc"); \ + return (d); \ + } + +CK_PR_FAA(ptr, void, uintptr_t, char, "xaddl") + +#define CK_PR_FAA_S(S, T, I) CK_PR_FAA(S, T, T, T, I) + +CK_PR_FAA_S(char, char, "xaddb") +CK_PR_FAA_S(uint, unsigned int, "xaddl") +CK_PR_FAA_S(int, int, "xaddl") +CK_PR_FAA_S(32, uint32_t, "xaddl") +CK_PR_FAA_S(16, uint16_t, "xaddw") +CK_PR_FAA_S(8, uint8_t, "xaddb") + +#undef CK_PR_FAA_S +#undef CK_PR_FAA + +/* + * Atomic store-only unary operations. + */ +#define CK_PR_UNARY(K, S, T, C, I) \ + CK_PR_UNARY_R(K, S, T, C, I) \ + CK_PR_UNARY_V(K, S, T, C, I) + +#define CK_PR_UNARY_R(K, S, T, C, I) \ + CK_CC_INLINE static void \ + ck_pr_##K##_##S(T *target) \ + { \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0" \ + : "+m" (*(C *)target) \ + : \ + : "memory", "cc"); \ + return; \ + } + +#define CK_PR_UNARY_V(K, S, T, C, I) \ + CK_CC_INLINE static void \ + ck_pr_##K##_##S##_zero(T *target, bool *r) \ + { \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0; setz %1" \ + : "+m" (*(C *)target), \ + "=m" (*r) \ + : \ + : "memory", "cc"); \ + return; \ + } + + +#define CK_PR_UNARY_S(K, S, T, I) CK_PR_UNARY(K, S, T, T, I) + +#define CK_PR_GENERATE(K) \ + CK_PR_UNARY(K, ptr, void, char, #K "l") \ + CK_PR_UNARY_S(K, char, char, #K "b") \ + CK_PR_UNARY_S(K, int, int, #K "l") \ + CK_PR_UNARY_S(K, uint, unsigned int, #K "l") \ + CK_PR_UNARY_S(K, 32, uint32_t, #K "l") \ + CK_PR_UNARY_S(K, 16, uint16_t, #K "w") \ + CK_PR_UNARY_S(K, 8, uint8_t, #K "b") + +CK_PR_GENERATE(inc) +CK_PR_GENERATE(dec) +CK_PR_GENERATE(neg) + +/* not does not affect condition flags. */ +#undef CK_PR_UNARY_V +#define CK_PR_UNARY_V(a, b, c, d, e) +CK_PR_GENERATE(not) + +#undef CK_PR_GENERATE +#undef CK_PR_UNARY_S +#undef CK_PR_UNARY_V +#undef CK_PR_UNARY_R +#undef CK_PR_UNARY + +/* + * Atomic store-only binary operations. + */ +#define CK_PR_BINARY(K, S, M, T, C, I) \ + CK_CC_INLINE static void \ + ck_pr_##K##_##S(M *target, T d) \ + { \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0" \ + : "+m" (*(C *)target) \ + : CK_CC_IMM "q" (d) \ + : "memory", "cc"); \ + return; \ + } + +#define CK_PR_BINARY_S(K, S, T, I) CK_PR_BINARY(K, S, T, T, T, I) + +#define CK_PR_GENERATE(K) \ + CK_PR_BINARY(K, ptr, void, uintptr_t, char, #K "l") \ + CK_PR_BINARY_S(K, char, char, #K "b") \ + CK_PR_BINARY_S(K, int, int, #K "l") \ + CK_PR_BINARY_S(K, uint, unsigned int, #K "l") \ + CK_PR_BINARY_S(K, 32, uint32_t, #K "l") \ + CK_PR_BINARY_S(K, 16, uint16_t, #K "w") \ + CK_PR_BINARY_S(K, 8, uint8_t, #K "b") + +CK_PR_GENERATE(add) +CK_PR_GENERATE(sub) +CK_PR_GENERATE(and) +CK_PR_GENERATE(or) +CK_PR_GENERATE(xor) + +#undef CK_PR_GENERATE +#undef CK_PR_BINARY_S +#undef CK_PR_BINARY + +/* + * Atomic compare and swap. + */ +#define CK_PR_CAS(S, M, T, C, I) \ + CK_CC_INLINE static bool \ + ck_pr_cas_##S(M *target, T compare, T set) \ + { \ + bool z; \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %2, %0; setz %1" \ + : "+m" (*(C *)target), \ + "=a" (z) \ + : "q" (set), \ + "a" (compare) \ + : "memory", "cc"); \ + return z; \ + } + +CK_PR_CAS(ptr, void, void *, char, "cmpxchgl") + +#define CK_PR_CAS_S(S, T, I) CK_PR_CAS(S, T, T, T, I) + +CK_PR_CAS_S(char, char, "cmpxchgb") +CK_PR_CAS_S(int, int, "cmpxchgl") +CK_PR_CAS_S(uint, unsigned int, "cmpxchgl") +CK_PR_CAS_S(32, uint32_t, "cmpxchgl") +CK_PR_CAS_S(16, uint16_t, "cmpxchgw") +CK_PR_CAS_S(8, uint8_t, "cmpxchgb") + +#undef CK_PR_CAS_S +#undef CK_PR_CAS + +/* + * Compare and swap, set *v to old value of target. + */ +#define CK_PR_CAS_O(S, M, T, C, I, R) \ + CK_CC_INLINE static bool \ + ck_pr_cas_##S##_value(M *target, T compare, T set, M *v) \ + { \ + bool z; \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX "cmpxchg" I " %3, %0;" \ + "mov %% " R ", %2;" \ + "setz %1;" \ + : "+m" (*(C *)target), \ + "=a" (z), \ + "=m" (*(C *)v) \ + : "q" (set), \ + "a" (compare) \ + : "memory", "cc"); \ + return (bool)z; \ + } + +CK_PR_CAS_O(ptr, void, void *, char, "l", "eax") + +#define CK_PR_CAS_O_S(S, T, I, R) \ + CK_PR_CAS_O(S, T, T, T, I, R) + +CK_PR_CAS_O_S(char, char, "b", "al") +CK_PR_CAS_O_S(int, int, "l", "eax") +CK_PR_CAS_O_S(uint, unsigned int, "l", "eax") +CK_PR_CAS_O_S(32, uint32_t, "l", "eax") +CK_PR_CAS_O_S(16, uint16_t, "w", "ax") +CK_PR_CAS_O_S(8, uint8_t, "b", "al") + +#undef CK_PR_CAS_O_S +#undef CK_PR_CAS_O + +/* + * Atomic bit test operations. + */ +#define CK_PR_BT(K, S, T, P, C, I) \ + CK_CC_INLINE static bool \ + ck_pr_##K##_##S(T *target, unsigned int b) \ + { \ + bool c; \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I "; setc %1" \ + : "+m" (*(C *)target), \ + "=q" (c) \ + : "q" ((P)b) \ + : "memory", "cc"); \ + return (bool)c; \ + } + +#define CK_PR_BT_S(K, S, T, I) CK_PR_BT(K, S, T, T, T, I) + +#define CK_PR_GENERATE(K) \ + CK_PR_BT(K, ptr, void, uint32_t, char, #K "l %2, %0") \ + CK_PR_BT_S(K, uint, unsigned int, #K "l %2, %0") \ + CK_PR_BT_S(K, int, int, #K "l %2, %0") \ + CK_PR_BT_S(K, 32, uint32_t, #K "l %2, %0") \ + CK_PR_BT_S(K, 16, uint16_t, #K "w %w2, %0") + +CK_PR_GENERATE(btc) +CK_PR_GENERATE(bts) +CK_PR_GENERATE(btr) + +#undef CK_PR_GENERATE +#undef CK_PR_BT + +#endif /* CK_PR_X86_H */ + diff --git a/freebsd/sys/contrib/ck/include/gcc/x86_64/ck_f_pr.h b/freebsd/sys/contrib/ck/include/gcc/x86_64/ck_f_pr.h new file mode 100644 index 00000000..545f5fd6 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/x86_64/ck_f_pr.h @@ -0,0 +1,202 @@ +/* DO NOT EDIT. This is auto-generated from feature.sh */ +#define CK_F_PR_ADD_16 +#define CK_F_PR_ADD_32 +#define CK_F_PR_ADD_64 +#define CK_F_PR_ADD_8 +#define CK_F_PR_ADD_CHAR +#define CK_F_PR_ADD_INT +#define CK_F_PR_ADD_PTR +#define CK_F_PR_ADD_UINT +#define CK_F_PR_AND_16 +#define CK_F_PR_AND_32 +#define CK_F_PR_AND_64 +#define CK_F_PR_AND_8 +#define CK_F_PR_AND_CHAR +#define CK_F_PR_AND_INT +#define CK_F_PR_AND_PTR +#define CK_F_PR_AND_UINT +#define CK_F_PR_BTC_16 +#define CK_F_PR_BTC_32 +#define CK_F_PR_BTC_64 +#define CK_F_PR_BTC_INT +#define CK_F_PR_BTC_PTR +#define CK_F_PR_BTC_UINT +#define CK_F_PR_BTR_16 +#define CK_F_PR_BTR_32 +#define CK_F_PR_BTR_64 +#define CK_F_PR_BTR_INT +#define CK_F_PR_BTR_PTR +#define CK_F_PR_BTR_UINT +#define CK_F_PR_BTS_16 +#define CK_F_PR_BTS_32 +#define CK_F_PR_BTS_64 +#define CK_F_PR_BTS_INT +#define CK_F_PR_BTS_PTR +#define CK_F_PR_BTS_UINT +#define CK_F_PR_CAS_16 +#define CK_F_PR_CAS_16_8 +#define CK_F_PR_CAS_16_8_VALUE +#define CK_F_PR_CAS_16_VALUE +#define CK_F_PR_CAS_32 +#define CK_F_PR_CAS_32_4 +#define CK_F_PR_CAS_32_4_VALUE +#define CK_F_PR_CAS_32_VALUE +#define CK_F_PR_CAS_64 +#define CK_F_PR_CAS_64_2 +#define CK_F_PR_CAS_64_2_VALUE +#define CK_F_PR_CAS_64_VALUE +#define CK_F_PR_CAS_8 +#define CK_F_PR_CAS_8_16 +#define CK_F_PR_CAS_8_16_VALUE +#define CK_F_PR_CAS_8_VALUE +#define CK_F_PR_CAS_CHAR +#define CK_F_PR_CAS_CHAR_16 +#define CK_F_PR_CAS_CHAR_16_VALUE +#define CK_F_PR_CAS_CHAR_VALUE +#define CK_F_PR_CAS_INT +#define CK_F_PR_CAS_INT_4 +#define CK_F_PR_CAS_INT_4_VALUE +#define CK_F_PR_CAS_INT_VALUE +#define CK_F_PR_CAS_PTR +#define CK_F_PR_CAS_PTR_2 +#define CK_F_PR_CAS_PTR_2_VALUE +#define CK_F_PR_CAS_PTR_VALUE +#define CK_F_PR_CAS_DOUBLE +#define CK_F_PR_CAS_DOUBLE_2 +#define CK_F_PR_CAS_DOUBLE_VALUE +#define CK_F_PR_CAS_UINT +#define CK_F_PR_CAS_UINT_4 +#define CK_F_PR_CAS_UINT_4_VALUE +#define CK_F_PR_CAS_UINT_VALUE +#define CK_F_PR_DEC_16 +#define CK_F_PR_DEC_16_ZERO +#define CK_F_PR_DEC_32 +#define CK_F_PR_DEC_32_ZERO +#define CK_F_PR_DEC_64 +#define CK_F_PR_DEC_64_ZERO +#define CK_F_PR_DEC_8 +#define CK_F_PR_DEC_8_ZERO +#define CK_F_PR_DEC_CHAR +#define CK_F_PR_DEC_CHAR_ZERO +#define CK_F_PR_DEC_INT +#define CK_F_PR_DEC_INT_ZERO +#define CK_F_PR_DEC_PTR +#define CK_F_PR_DEC_PTR_ZERO +#define CK_F_PR_DEC_UINT +#define CK_F_PR_DEC_UINT_ZERO +#define CK_F_PR_FAA_16 +#define CK_F_PR_FAA_32 +#define CK_F_PR_FAA_64 +#define CK_F_PR_FAA_8 +#define CK_F_PR_FAA_CHAR +#define CK_F_PR_FAA_INT +#define CK_F_PR_FAA_PTR +#define CK_F_PR_FAA_UINT +#define CK_F_PR_FAS_16 +#define CK_F_PR_FAS_32 +#define CK_F_PR_FAS_64 +#define CK_F_PR_FAS_8 +#define CK_F_PR_FAS_CHAR +#define CK_F_PR_FAS_INT +#define CK_F_PR_FAS_PTR +#define CK_F_PR_FAS_UINT +#define CK_F_PR_FAS_DOUBLE +#define CK_F_PR_FENCE_LOAD +#define CK_F_PR_FENCE_LOAD_DEPENDS +#define CK_F_PR_FENCE_MEMORY +#define CK_F_PR_FENCE_STORE +#define CK_F_PR_FENCE_STRICT_LOAD +#define CK_F_PR_FENCE_STRICT_LOAD_DEPENDS +#define CK_F_PR_FENCE_STRICT_MEMORY +#define CK_F_PR_FENCE_STRICT_STORE +#define CK_F_PR_INC_16 +#define CK_F_PR_INC_16_ZERO +#define CK_F_PR_INC_32 +#define CK_F_PR_INC_32_ZERO +#define CK_F_PR_INC_64 +#define CK_F_PR_INC_64_ZERO +#define CK_F_PR_INC_8 +#define CK_F_PR_INC_8_ZERO +#define CK_F_PR_INC_CHAR +#define CK_F_PR_INC_CHAR_ZERO +#define CK_F_PR_INC_INT +#define CK_F_PR_INC_INT_ZERO +#define CK_F_PR_INC_PTR +#define CK_F_PR_INC_PTR_ZERO +#define CK_F_PR_INC_UINT +#define CK_F_PR_INC_UINT_ZERO +#define CK_F_PR_LOAD_16 +#define CK_F_PR_LOAD_16_8 +#define CK_F_PR_LOAD_32 +#define CK_F_PR_LOAD_32_4 +#define CK_F_PR_LOAD_64 +#define CK_F_PR_LOAD_64_2 +#define CK_F_PR_LOAD_8 +#define CK_F_PR_LOAD_8_16 +#define CK_F_PR_LOAD_CHAR +#define CK_F_PR_LOAD_CHAR_16 +#define CK_F_PR_LOAD_INT +#define CK_F_PR_LOAD_INT_4 +#define CK_F_PR_LOAD_PTR +#define CK_F_PR_LOAD_PTR_2 +#define CK_F_PR_LOAD_DOUBLE +#define CK_F_PR_LOAD_UINT +#define CK_F_PR_LOAD_UINT_4 +#define CK_F_PR_NEG_16 +#define CK_F_PR_NEG_16_ZERO +#define CK_F_PR_NEG_32 +#define CK_F_PR_NEG_32_ZERO +#define CK_F_PR_NEG_64 +#define CK_F_PR_NEG_64_ZERO +#define CK_F_PR_NEG_8 +#define CK_F_PR_NEG_8_ZERO +#define CK_F_PR_NEG_CHAR +#define CK_F_PR_NEG_CHAR_ZERO +#define CK_F_PR_NEG_INT +#define CK_F_PR_NEG_INT_ZERO +#define CK_F_PR_NEG_PTR +#define CK_F_PR_NEG_PTR_ZERO +#define CK_F_PR_NEG_UINT +#define CK_F_PR_NEG_UINT_ZERO +#define CK_F_PR_NOT_16 +#define CK_F_PR_NOT_32 +#define CK_F_PR_NOT_64 +#define CK_F_PR_NOT_8 +#define CK_F_PR_NOT_CHAR +#define CK_F_PR_NOT_INT +#define CK_F_PR_NOT_PTR +#define CK_F_PR_NOT_UINT +#define CK_F_PR_OR_16 +#define CK_F_PR_OR_32 +#define CK_F_PR_OR_64 +#define CK_F_PR_OR_8 +#define CK_F_PR_OR_CHAR +#define CK_F_PR_OR_INT +#define CK_F_PR_OR_PTR +#define CK_F_PR_OR_UINT +#define CK_F_PR_STORE_16 +#define CK_F_PR_STORE_32 +#define CK_F_PR_STORE_64 +#define CK_F_PR_STORE_8 +#define CK_F_PR_STORE_CHAR +#define CK_F_PR_STORE_INT +#define CK_F_PR_STORE_DOUBLE +#define CK_F_PR_STORE_PTR +#define CK_F_PR_STORE_UINT +#define CK_F_PR_SUB_16 +#define CK_F_PR_SUB_32 +#define CK_F_PR_SUB_64 +#define CK_F_PR_SUB_8 +#define CK_F_PR_SUB_CHAR +#define CK_F_PR_SUB_INT +#define CK_F_PR_SUB_PTR +#define CK_F_PR_SUB_UINT +#define CK_F_PR_XOR_16 +#define CK_F_PR_XOR_32 +#define CK_F_PR_XOR_64 +#define CK_F_PR_XOR_8 +#define CK_F_PR_XOR_CHAR +#define CK_F_PR_XOR_INT +#define CK_F_PR_XOR_PTR +#define CK_F_PR_XOR_UINT + diff --git a/freebsd/sys/contrib/ck/include/gcc/x86_64/ck_pr.h b/freebsd/sys/contrib/ck/include/gcc/x86_64/ck_pr.h new file mode 100644 index 00000000..4de13329 --- /dev/null +++ b/freebsd/sys/contrib/ck/include/gcc/x86_64/ck_pr.h @@ -0,0 +1,606 @@ +/* + * Copyright 2009-2015 Samy Al Bahra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef CK_PR_X86_64_H +#define CK_PR_X86_64_H + +#ifndef CK_PR_H +#error Do not include this file directly, use ck_pr.h +#endif + +#include <ck_cc.h> +#include <ck_md.h> +#include <ck_stdint.h> + +/* + * The following represent supported atomic operations. + * These operations may be emulated. + */ +#include "ck_f_pr.h" + +/* + * Support for TSX extensions. + */ +#ifdef CK_MD_RTM_ENABLE +#include "ck_pr_rtm.h" +#endif + +/* Minimum requirements for the CK_PR interface are met. */ +#define CK_F_PR + +#ifdef CK_MD_UMP +#define CK_PR_LOCK_PREFIX +#else +#define CK_PR_LOCK_PREFIX "lock " +#endif + +/* + * Prevent speculative execution in busy-wait loops (P4 <=) or "predefined + * delay". + */ +CK_CC_INLINE static void +ck_pr_stall(void) +{ + __asm__ __volatile__("pause" ::: "memory"); + return; +} + +#define CK_PR_FENCE(T, I) \ + CK_CC_INLINE static void \ + ck_pr_fence_strict_##T(void) \ + { \ + __asm__ __volatile__(I ::: "memory"); \ + } + +/* Atomic operations are always serializing. */ +CK_PR_FENCE(atomic, "") +CK_PR_FENCE(atomic_store, "") +CK_PR_FENCE(atomic_load, "") +CK_PR_FENCE(store_atomic, "") +CK_PR_FENCE(load_atomic, "") + +/* Traditional fence interface. */ +CK_PR_FENCE(load, "lfence") +CK_PR_FENCE(load_store, "mfence") +CK_PR_FENCE(store, "sfence") +CK_PR_FENCE(store_load, "mfence") +CK_PR_FENCE(memory, "mfence") + +/* Below are stdatomic-style fences. */ + +/* + * Provides load-store and store-store ordering. However, Intel specifies that + * the WC memory model is relaxed. It is likely an sfence *is* sufficient (in + * particular, stores are not re-ordered with respect to prior loads and it is + * really just the stores that are subject to re-ordering). However, we take + * the conservative route as the manuals are too ambiguous for my taste. + */ +CK_PR_FENCE(release, "mfence") + +/* + * Provides load-load and load-store ordering. The lfence instruction ensures + * all prior load operations are complete before any subsequent instructions + * actually begin execution. However, the manual also ends up going to describe + * WC memory as a relaxed model. + */ +CK_PR_FENCE(acquire, "mfence") + +CK_PR_FENCE(acqrel, "mfence") +CK_PR_FENCE(lock, "mfence") +CK_PR_FENCE(unlock, "mfence") + +#undef CK_PR_FENCE + +/* + * Read for ownership. Older compilers will generate the 32-bit + * 3DNow! variant which is binary compatible with x86-64 variant + * of prefetchw. + */ +#ifndef CK_F_PR_RFO +#define CK_F_PR_RFO +CK_CC_INLINE static void +ck_pr_rfo(const void *m) +{ + + __asm__ __volatile__("prefetchw (%0)" + : + : "r" (m) + : "memory"); + + return; +} +#endif /* CK_F_PR_RFO */ + +/* + * Atomic fetch-and-store operations. + */ +#define CK_PR_FAS(S, M, T, C, I) \ + CK_CC_INLINE static T \ + ck_pr_fas_##S(M *target, T v) \ + { \ + __asm__ __volatile__(I " %0, %1" \ + : "+m" (*(C *)target), \ + "+q" (v) \ + : \ + : "memory"); \ + return v; \ + } + +CK_PR_FAS(ptr, void, void *, char, "xchgq") + +#define CK_PR_FAS_S(S, T, I) CK_PR_FAS(S, T, T, T, I) + +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_FAS_S(double, double, "xchgq") +#endif +CK_PR_FAS_S(char, char, "xchgb") +CK_PR_FAS_S(uint, unsigned int, "xchgl") +CK_PR_FAS_S(int, int, "xchgl") +CK_PR_FAS_S(64, uint64_t, "xchgq") +CK_PR_FAS_S(32, uint32_t, "xchgl") +CK_PR_FAS_S(16, uint16_t, "xchgw") +CK_PR_FAS_S(8, uint8_t, "xchgb") + +#undef CK_PR_FAS_S +#undef CK_PR_FAS + +/* + * Atomic load-from-memory operations. + */ +#define CK_PR_LOAD(S, M, T, C, I) \ + CK_CC_INLINE static T \ + ck_pr_md_load_##S(const M *target) \ + { \ + T r; \ + __asm__ __volatile__(I " %1, %0" \ + : "=q" (r) \ + : "m" (*(const C *)target) \ + : "memory"); \ + return (r); \ + } + +CK_PR_LOAD(ptr, void, void *, char, "movq") + +#define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I) + +CK_PR_LOAD_S(char, char, "movb") +CK_PR_LOAD_S(uint, unsigned int, "movl") +CK_PR_LOAD_S(int, int, "movl") +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_LOAD_S(double, double, "movq") +#endif +CK_PR_LOAD_S(64, uint64_t, "movq") +CK_PR_LOAD_S(32, uint32_t, "movl") +CK_PR_LOAD_S(16, uint16_t, "movw") +CK_PR_LOAD_S(8, uint8_t, "movb") + +#undef CK_PR_LOAD_S +#undef CK_PR_LOAD + +CK_CC_INLINE static void +ck_pr_load_64_2(const uint64_t target[2], uint64_t v[2]) +{ + __asm__ __volatile__("movq %%rdx, %%rcx;" + "movq %%rax, %%rbx;" + CK_PR_LOCK_PREFIX "cmpxchg16b %2;" + : "=a" (v[0]), + "=d" (v[1]) + : "m" (*(const uint64_t *)target) + : "rbx", "rcx", "memory", "cc"); + return; +} + +CK_CC_INLINE static void +ck_pr_load_ptr_2(const void *t, void *v) +{ + ck_pr_load_64_2(CK_CPP_CAST(const uint64_t *, t), + CK_CPP_CAST(uint64_t *, v)); + return; +} + +#define CK_PR_LOAD_2(S, W, T) \ + CK_CC_INLINE static void \ + ck_pr_md_load_##S##_##W(const T t[2], T v[2]) \ + { \ + ck_pr_load_64_2((const uint64_t *)(const void *)t, \ + (uint64_t *)(void *)v); \ + return; \ + } + +CK_PR_LOAD_2(char, 16, char) +CK_PR_LOAD_2(int, 4, int) +CK_PR_LOAD_2(uint, 4, unsigned int) +CK_PR_LOAD_2(32, 4, uint32_t) +CK_PR_LOAD_2(16, 8, uint16_t) +CK_PR_LOAD_2(8, 16, uint8_t) + +#undef CK_PR_LOAD_2 + +/* + * Atomic store-to-memory operations. + */ +#define CK_PR_STORE_IMM(S, M, T, C, I, K) \ + CK_CC_INLINE static void \ + ck_pr_md_store_##S(M *target, T v) \ + { \ + __asm__ __volatile__(I " %1, %0" \ + : "=m" (*(C *)target) \ + : K "q" (v) \ + : "memory"); \ + return; \ + } + +#define CK_PR_STORE(S, M, T, C, I) \ + CK_CC_INLINE static void \ + ck_pr_md_store_##S(M *target, T v) \ + { \ + __asm__ __volatile__(I " %1, %0" \ + : "=m" (*(C *)target) \ + : "q" (v) \ + : "memory"); \ + return; \ + } + +CK_PR_STORE_IMM(ptr, void, const void *, char, "movq", CK_CC_IMM_U32) +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_STORE(double, double, double, double, "movq") +#endif + +#define CK_PR_STORE_S(S, T, I, K) CK_PR_STORE_IMM(S, T, T, T, I, K) + +CK_PR_STORE_S(char, char, "movb", CK_CC_IMM_S32) +CK_PR_STORE_S(int, int, "movl", CK_CC_IMM_S32) +CK_PR_STORE_S(uint, unsigned int, "movl", CK_CC_IMM_U32) +CK_PR_STORE_S(64, uint64_t, "movq", CK_CC_IMM_U32) +CK_PR_STORE_S(32, uint32_t, "movl", CK_CC_IMM_U32) +CK_PR_STORE_S(16, uint16_t, "movw", CK_CC_IMM_U32) +CK_PR_STORE_S(8, uint8_t, "movb", CK_CC_IMM_U32) + +#undef CK_PR_STORE_S +#undef CK_PR_STORE_IMM +#undef CK_PR_STORE + +/* + * Atomic fetch-and-add operations. + */ +#define CK_PR_FAA(S, M, T, C, I) \ + CK_CC_INLINE static T \ + ck_pr_faa_##S(M *target, T d) \ + { \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0" \ + : "+m" (*(C *)target), \ + "+q" (d) \ + : \ + : "memory", "cc"); \ + return (d); \ + } + +CK_PR_FAA(ptr, void, uintptr_t, char, "xaddq") + +#define CK_PR_FAA_S(S, T, I) CK_PR_FAA(S, T, T, T, I) + +CK_PR_FAA_S(char, char, "xaddb") +CK_PR_FAA_S(uint, unsigned int, "xaddl") +CK_PR_FAA_S(int, int, "xaddl") +CK_PR_FAA_S(64, uint64_t, "xaddq") +CK_PR_FAA_S(32, uint32_t, "xaddl") +CK_PR_FAA_S(16, uint16_t, "xaddw") +CK_PR_FAA_S(8, uint8_t, "xaddb") + +#undef CK_PR_FAA_S +#undef CK_PR_FAA + +/* + * Atomic store-only unary operations. + */ +#define CK_PR_UNARY(K, S, T, C, I) \ + CK_PR_UNARY_R(K, S, T, C, I) \ + CK_PR_UNARY_V(K, S, T, C, I) + +#define CK_PR_UNARY_R(K, S, T, C, I) \ + CK_CC_INLINE static void \ + ck_pr_##K##_##S(T *target) \ + { \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0" \ + : "+m" (*(C *)target) \ + : \ + : "memory", "cc"); \ + return; \ + } + +#define CK_PR_UNARY_V(K, S, T, C, I) \ + CK_CC_INLINE static void \ + ck_pr_##K##_##S##_zero(T *target, bool *r) \ + { \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0; setz %1" \ + : "+m" (*(C *)target), \ + "=m" (*r) \ + : \ + : "memory", "cc"); \ + return; \ + } + + +#define CK_PR_UNARY_S(K, S, T, I) CK_PR_UNARY(K, S, T, T, I) + +#define CK_PR_GENERATE(K) \ + CK_PR_UNARY(K, ptr, void, char, #K "q") \ + CK_PR_UNARY_S(K, char, char, #K "b") \ + CK_PR_UNARY_S(K, int, int, #K "l") \ + CK_PR_UNARY_S(K, uint, unsigned int, #K "l") \ + CK_PR_UNARY_S(K, 64, uint64_t, #K "q") \ + CK_PR_UNARY_S(K, 32, uint32_t, #K "l") \ + CK_PR_UNARY_S(K, 16, uint16_t, #K "w") \ + CK_PR_UNARY_S(K, 8, uint8_t, #K "b") + +CK_PR_GENERATE(inc) +CK_PR_GENERATE(dec) +CK_PR_GENERATE(neg) + +/* not does not affect condition flags. */ +#undef CK_PR_UNARY_V +#define CK_PR_UNARY_V(a, b, c, d, e) +CK_PR_GENERATE(not) + +#undef CK_PR_GENERATE +#undef CK_PR_UNARY_S +#undef CK_PR_UNARY_V +#undef CK_PR_UNARY_R +#undef CK_PR_UNARY + +/* + * Atomic store-only binary operations. + */ +#define CK_PR_BINARY(K, S, M, T, C, I, O) \ + CK_CC_INLINE static void \ + ck_pr_##K##_##S(M *target, T d) \ + { \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0" \ + : "+m" (*(C *)target) \ + : O "q" (d) \ + : "memory", "cc"); \ + return; \ + } + +#define CK_PR_BINARY_S(K, S, T, I, O) CK_PR_BINARY(K, S, T, T, T, I, O) + +#define CK_PR_GENERATE(K) \ + CK_PR_BINARY(K, ptr, void, uintptr_t, char, #K "q", CK_CC_IMM_U32) \ + CK_PR_BINARY_S(K, char, char, #K "b", CK_CC_IMM_S32) \ + CK_PR_BINARY_S(K, int, int, #K "l", CK_CC_IMM_S32) \ + CK_PR_BINARY_S(K, uint, unsigned int, #K "l", CK_CC_IMM_U32) \ + CK_PR_BINARY_S(K, 64, uint64_t, #K "q", CK_CC_IMM_U32) \ + CK_PR_BINARY_S(K, 32, uint32_t, #K "l", CK_CC_IMM_U32) \ + CK_PR_BINARY_S(K, 16, uint16_t, #K "w", CK_CC_IMM_U32) \ + CK_PR_BINARY_S(K, 8, uint8_t, #K "b", CK_CC_IMM_U32) + +CK_PR_GENERATE(add) +CK_PR_GENERATE(sub) +CK_PR_GENERATE(and) +CK_PR_GENERATE(or) +CK_PR_GENERATE(xor) + +#undef CK_PR_GENERATE +#undef CK_PR_BINARY_S +#undef CK_PR_BINARY + +/* + * Atomic compare and swap. + */ +#define CK_PR_CAS(S, M, T, C, I) \ + CK_CC_INLINE static bool \ + ck_pr_cas_##S(M *target, T compare, T set) \ + { \ + bool z; \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I " %2, %0; setz %1" \ + : "+m" (*(C *)target), \ + "=a" (z) \ + : "q" (set), \ + "a" (compare) \ + : "memory", "cc"); \ + return z; \ + } + +CK_PR_CAS(ptr, void, void *, char, "cmpxchgq") + +#define CK_PR_CAS_S(S, T, I) CK_PR_CAS(S, T, T, T, I) + +CK_PR_CAS_S(char, char, "cmpxchgb") +CK_PR_CAS_S(int, int, "cmpxchgl") +CK_PR_CAS_S(uint, unsigned int, "cmpxchgl") +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_CAS_S(double, double, "cmpxchgq") +#endif +CK_PR_CAS_S(64, uint64_t, "cmpxchgq") +CK_PR_CAS_S(32, uint32_t, "cmpxchgl") +CK_PR_CAS_S(16, uint16_t, "cmpxchgw") +CK_PR_CAS_S(8, uint8_t, "cmpxchgb") + +#undef CK_PR_CAS_S +#undef CK_PR_CAS + +/* + * Compare and swap, set *v to old value of target. + */ +#define CK_PR_CAS_O(S, M, T, C, I, R) \ + CK_CC_INLINE static bool \ + ck_pr_cas_##S##_value(M *target, T compare, T set, M *v) \ + { \ + bool z; \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX "cmpxchg" I " %3, %0;" \ + "mov %% " R ", %2;" \ + "setz %1;" \ + : "+m" (*(C *)target), \ + "=a" (z), \ + "=m" (*(C *)v) \ + : "q" (set), \ + "a" (compare) \ + : "memory", "cc"); \ + return z; \ + } + +CK_PR_CAS_O(ptr, void, void *, char, "q", "rax") + +#define CK_PR_CAS_O_S(S, T, I, R) \ + CK_PR_CAS_O(S, T, T, T, I, R) + +CK_PR_CAS_O_S(char, char, "b", "al") +CK_PR_CAS_O_S(int, int, "l", "eax") +CK_PR_CAS_O_S(uint, unsigned int, "l", "eax") +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_CAS_O_S(double, double, "q", "rax") +#endif +CK_PR_CAS_O_S(64, uint64_t, "q", "rax") +CK_PR_CAS_O_S(32, uint32_t, "l", "eax") +CK_PR_CAS_O_S(16, uint16_t, "w", "ax") +CK_PR_CAS_O_S(8, uint8_t, "b", "al") + +#undef CK_PR_CAS_O_S +#undef CK_PR_CAS_O + +/* + * Contrary to C-interface, alignment requirements are that of uint64_t[2]. + */ +CK_CC_INLINE static bool +ck_pr_cas_64_2(uint64_t target[2], uint64_t compare[2], uint64_t set[2]) +{ + bool z; + + __asm__ __volatile__("movq 0(%4), %%rax;" + "movq 8(%4), %%rdx;" + CK_PR_LOCK_PREFIX "cmpxchg16b %0; setz %1" + : "+m" (*target), + "=q" (z) + : "b" (set[0]), + "c" (set[1]), + "q" (compare) + : "memory", "cc", "%rax", "%rdx"); + return z; +} + +CK_CC_INLINE static bool +ck_pr_cas_ptr_2(void *t, void *c, void *s) +{ + return ck_pr_cas_64_2(CK_CPP_CAST(uint64_t *, t), + CK_CPP_CAST(uint64_t *, c), + CK_CPP_CAST(uint64_t *, s)); +} + +CK_CC_INLINE static bool +ck_pr_cas_64_2_value(uint64_t target[2], + uint64_t compare[2], + uint64_t set[2], + uint64_t v[2]) +{ + bool z; + + __asm__ __volatile__(CK_PR_LOCK_PREFIX "cmpxchg16b %0;" + "setz %3" + : "+m" (*target), + "=a" (v[0]), + "=d" (v[1]), + "=q" (z) + : "a" (compare[0]), + "d" (compare[1]), + "b" (set[0]), + "c" (set[1]) + : "memory", "cc"); + return z; +} + +CK_CC_INLINE static bool +ck_pr_cas_ptr_2_value(void *t, void *c, void *s, void *v) +{ + return ck_pr_cas_64_2_value(CK_CPP_CAST(uint64_t *,t), + CK_CPP_CAST(uint64_t *,c), + CK_CPP_CAST(uint64_t *,s), + CK_CPP_CAST(uint64_t *,v)); +} + +#define CK_PR_CAS_V(S, W, T) \ +CK_CC_INLINE static bool \ +ck_pr_cas_##S##_##W(T t[W], T c[W], T s[W]) \ +{ \ + return ck_pr_cas_64_2((uint64_t *)(void *)t, \ + (uint64_t *)(void *)c, \ + (uint64_t *)(void *)s); \ +} \ +CK_CC_INLINE static bool \ +ck_pr_cas_##S##_##W##_value(T *t, T c[W], T s[W], T *v) \ +{ \ + return ck_pr_cas_64_2_value((uint64_t *)(void *)t, \ + (uint64_t *)(void *)c, \ + (uint64_t *)(void *)s, \ + (uint64_t *)(void *)v); \ +} + +#ifndef CK_PR_DISABLE_DOUBLE +CK_PR_CAS_V(double, 2, double) +#endif +CK_PR_CAS_V(char, 16, char) +CK_PR_CAS_V(int, 4, int) +CK_PR_CAS_V(uint, 4, unsigned int) +CK_PR_CAS_V(32, 4, uint32_t) +CK_PR_CAS_V(16, 8, uint16_t) +CK_PR_CAS_V(8, 16, uint8_t) + +#undef CK_PR_CAS_V + +/* + * Atomic bit test operations. + */ +#define CK_PR_BT(K, S, T, P, C, I) \ + CK_CC_INLINE static bool \ + ck_pr_##K##_##S(T *target, unsigned int b) \ + { \ + bool c; \ + __asm__ __volatile__(CK_PR_LOCK_PREFIX I "; setc %1" \ + : "+m" (*(C *)target), \ + "=q" (c) \ + : "q" ((P)b) \ + : "memory", "cc"); \ + return c; \ + } + +#define CK_PR_BT_S(K, S, T, I) CK_PR_BT(K, S, T, T, T, I) + +#define CK_PR_GENERATE(K) \ + CK_PR_BT(K, ptr, void, uint64_t, char, #K "q %2, %0") \ + CK_PR_BT_S(K, uint, unsigned int, #K "l %2, %0") \ + CK_PR_BT_S(K, int, int, #K "l %2, %0") \ + CK_PR_BT_S(K, 64, uint64_t, #K "q %2, %0") \ + CK_PR_BT_S(K, 32, uint32_t, #K "l %2, %0") \ + CK_PR_BT_S(K, 16, uint16_t, #K "w %w2, %0") + +CK_PR_GENERATE(btc) +CK_PR_GENERATE(bts) +CK_PR_GENERATE(btr) + +#undef CK_PR_GENERATE +#undef CK_PR_BT + +#endif /* CK_PR_X86_64_H */ + diff --git a/freebsd/sys/contrib/ck/src/ck_epoch.c b/freebsd/sys/contrib/ck/src/ck_epoch.c new file mode 100644 index 00000000..be0f201d --- /dev/null +++ b/freebsd/sys/contrib/ck/src/ck_epoch.c @@ -0,0 +1,597 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/* + * Copyright 2011-2015 Samy Al Bahra. + * 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. + */ + +/* + * The implementation here is inspired from the work described in: + * Fraser, K. 2004. Practical Lock-Freedom. PhD Thesis, University + * of Cambridge Computing Laboratory. + */ + +#include <ck_backoff.h> +#include <ck_cc.h> +#include <ck_epoch.h> +#include <ck_pr.h> +#include <ck_stack.h> +#include <ck_stdbool.h> +#include <ck_string.h> + +/* + * Only three distinct values are used for reclamation, but reclamation occurs + * at e+2 rather than e+1. Any thread in a "critical section" would have + * acquired some snapshot (e) of the global epoch value (e_g) and set an active + * flag. Any hazardous references will only occur after a full memory barrier. + * For example, assume an initial e_g value of 1, e value of 0 and active value + * of 0. + * + * ck_epoch_begin(...) + * e = e_g + * active = 1 + * memory_barrier(); + * + * Any serialized reads may observe e = 0 or e = 1 with active = 0, or e = 0 or + * e = 1 with active = 1. The e_g value can only go from 1 to 2 if every thread + * has already observed the value of "1" (or the value we are incrementing + * from). This guarantees us that for any given value e_g, any threads with-in + * critical sections (referred to as "active" threads from here on) would have + * an e value of e_g-1 or e_g. This also means that hazardous references may be + * shared in both e_g-1 and e_g even if they are logically deleted in e_g. + * + * For example, assume all threads have an e value of e_g. Another thread may + * increment to e_g to e_g+1. Older threads may have a reference to an object + * which is only deleted in e_g+1. It could be that reader threads are + * executing some hash table look-ups, while some other writer thread (which + * causes epoch counter tick) actually deletes the same items that reader + * threads are looking up (this writer thread having an e value of e_g+1). + * This is possible if the writer thread re-observes the epoch after the + * counter tick. + * + * Psuedo-code for writer: + * ck_epoch_begin() + * ht_delete(x) + * ck_epoch_end() + * ck_epoch_begin() + * ht_delete(x) + * ck_epoch_end() + * + * Psuedo-code for reader: + * for (;;) { + * x = ht_lookup(x) + * ck_pr_inc(&x->value); + * } + * + * Of course, it is also possible for references logically deleted at e_g-1 to + * still be accessed at e_g as threads are "active" at the same time + * (real-world time) mutating shared objects. + * + * Now, if the epoch counter is ticked to e_g+1, then no new hazardous + * references could exist to objects logically deleted at e_g-1. The reason for + * this is that at e_g+1, all epoch read-side critical sections started at + * e_g-1 must have been completed. If any epoch read-side critical sections at + * e_g-1 were still active, then we would never increment to e_g+1 (active != 0 + * ^ e != e_g). Additionally, e_g may still have hazardous references to + * objects logically deleted at e_g-1 which means objects logically deleted at + * e_g-1 cannot be deleted at e_g+1 unless all threads have observed e_g+1 + * (since it is valid for active threads to be at e_g and threads at e_g still + * require safe memory accesses). + * + * However, at e_g+2, all active threads must be either at e_g+1 or e_g+2. + * Though e_g+2 may share hazardous references with e_g+1, and e_g+1 shares + * hazardous references to e_g, no active threads are at e_g or e_g-1. This + * means no hazardous references could exist to objects deleted at e_g-1 (at + * e_g+2). + * + * To summarize these important points, + * 1) Active threads will always have a value of e_g or e_g-1. + * 2) Items that are logically deleted e_g or e_g-1 cannot be physically + * deleted. + * 3) Objects logically deleted at e_g-1 can be physically destroyed at e_g+2 + * or at e_g+1 if no threads are at e_g. + * + * Last but not least, if we are at e_g+2, then no active thread is at e_g + * which means it is safe to apply modulo-3 arithmetic to e_g value in order to + * re-use e_g to represent the e_g+3 state. This means it is sufficient to + * represent e_g using only the values 0, 1 or 2. Every time a thread re-visits + * a e_g (which can be determined with a non-empty deferral list) it can assume + * objects in the e_g deferral list involved at least three e_g transitions and + * are thus, safe, for physical deletion. + * + * Blocking semantics for epoch reclamation have additional restrictions. + * Though we only require three deferral lists, reasonable blocking semantics + * must be able to more gracefully handle bursty write work-loads which could + * easily cause e_g wrap-around if modulo-3 arithmetic is used. This allows for + * easy-to-trigger live-lock situations. The work-around to this is to not + * apply modulo arithmetic to e_g but only to deferral list indexing. + */ +#define CK_EPOCH_GRACE 3U + +enum { + CK_EPOCH_STATE_USED = 0, + CK_EPOCH_STATE_FREE = 1 +}; + +CK_STACK_CONTAINER(struct ck_epoch_record, record_next, + ck_epoch_record_container) +CK_STACK_CONTAINER(struct ck_epoch_entry, stack_entry, + ck_epoch_entry_container) + +#define CK_EPOCH_SENSE_MASK (CK_EPOCH_SENSE - 1) + +bool +_ck_epoch_delref(struct ck_epoch_record *record, + struct ck_epoch_section *section) +{ + struct ck_epoch_ref *current, *other; + unsigned int i = section->bucket; + + current = &record->local.bucket[i]; + current->count--; + + if (current->count > 0) + return false; + + /* + * If the current bucket no longer has any references, then + * determine whether we have already transitioned into a newer + * epoch. If so, then make sure to update our shared snapshot + * to allow for forward progress. + * + * If no other active bucket exists, then the record will go + * inactive in order to allow for forward progress. + */ + other = &record->local.bucket[(i + 1) & CK_EPOCH_SENSE_MASK]; + if (other->count > 0 && + ((int)(current->epoch - other->epoch) < 0)) { + /* + * The other epoch value is actually the newest, + * transition to it. + */ + ck_pr_store_uint(&record->epoch, other->epoch); + } + + return true; +} + +void +_ck_epoch_addref(struct ck_epoch_record *record, + struct ck_epoch_section *section) +{ + struct ck_epoch *global = record->global; + struct ck_epoch_ref *ref; + unsigned int epoch, i; + + epoch = ck_pr_load_uint(&global->epoch); + i = epoch & CK_EPOCH_SENSE_MASK; + ref = &record->local.bucket[i]; + + if (ref->count++ == 0) { +#ifndef CK_MD_TSO + struct ck_epoch_ref *previous; + + /* + * The system has already ticked. If another non-zero bucket + * exists, make sure to order our observations with respect + * to it. Otherwise, it is possible to acquire a reference + * from the previous epoch generation. + * + * On TSO architectures, the monoticity of the global counter + * and load-{store, load} ordering are sufficient to guarantee + * this ordering. + */ + previous = &record->local.bucket[(i + 1) & + CK_EPOCH_SENSE_MASK]; + if (previous->count > 0) + ck_pr_fence_acqrel(); +#endif /* !CK_MD_TSO */ + + /* + * If this is this is a new reference into the current + * bucket then cache the associated epoch value. + */ + ref->epoch = epoch; + } + + section->bucket = i; + return; +} + +void +ck_epoch_init(struct ck_epoch *global) +{ + + ck_stack_init(&global->records); + global->epoch = 1; + global->n_free = 0; + ck_pr_fence_store(); + return; +} + +struct ck_epoch_record * +ck_epoch_recycle(struct ck_epoch *global, void *ct) +{ + struct ck_epoch_record *record; + ck_stack_entry_t *cursor; + unsigned int state; + + if (ck_pr_load_uint(&global->n_free) == 0) + return NULL; + + CK_STACK_FOREACH(&global->records, cursor) { + record = ck_epoch_record_container(cursor); + + if (ck_pr_load_uint(&record->state) == CK_EPOCH_STATE_FREE) { + /* Serialize with respect to deferral list clean-up. */ + ck_pr_fence_load(); + state = ck_pr_fas_uint(&record->state, + CK_EPOCH_STATE_USED); + if (state == CK_EPOCH_STATE_FREE) { + ck_pr_dec_uint(&global->n_free); + ck_pr_store_ptr(&record->ct, ct); + + /* + * The context pointer is ordered by a + * subsequent protected section. + */ + return record; + } + } + } + + return NULL; +} + +void +ck_epoch_register(struct ck_epoch *global, struct ck_epoch_record *record, + void *ct) +{ + size_t i; + + record->global = global; + record->state = CK_EPOCH_STATE_USED; + record->active = 0; + record->epoch = 0; + record->n_dispatch = 0; + record->n_peak = 0; + record->n_pending = 0; + record->ct = ct; + memset(&record->local, 0, sizeof record->local); + + for (i = 0; i < CK_EPOCH_LENGTH; i++) + ck_stack_init(&record->pending[i]); + + ck_pr_fence_store(); + ck_stack_push_upmc(&global->records, &record->record_next); + return; +} + +void +ck_epoch_unregister(struct ck_epoch_record *record) +{ + struct ck_epoch *global = record->global; + size_t i; + + record->active = 0; + record->epoch = 0; + record->n_dispatch = 0; + record->n_peak = 0; + record->n_pending = 0; + memset(&record->local, 0, sizeof record->local); + + for (i = 0; i < CK_EPOCH_LENGTH; i++) + ck_stack_init(&record->pending[i]); + + ck_pr_store_ptr(&record->ct, NULL); + ck_pr_fence_store(); + ck_pr_store_uint(&record->state, CK_EPOCH_STATE_FREE); + ck_pr_inc_uint(&global->n_free); + return; +} + +static struct ck_epoch_record * +ck_epoch_scan(struct ck_epoch *global, + struct ck_epoch_record *cr, + unsigned int epoch, + bool *af) +{ + ck_stack_entry_t *cursor; + + if (cr == NULL) { + cursor = CK_STACK_FIRST(&global->records); + *af = false; + } else { + cursor = &cr->record_next; + *af = true; + } + + while (cursor != NULL) { + unsigned int state, active; + + cr = ck_epoch_record_container(cursor); + + state = ck_pr_load_uint(&cr->state); + if (state & CK_EPOCH_STATE_FREE) { + cursor = CK_STACK_NEXT(cursor); + continue; + } + + active = ck_pr_load_uint(&cr->active); + *af |= active; + + if (active != 0 && ck_pr_load_uint(&cr->epoch) != epoch) + return cr; + + cursor = CK_STACK_NEXT(cursor); + } + + return NULL; +} + +static void +ck_epoch_dispatch(struct ck_epoch_record *record, unsigned int e, ck_stack_t *deferred) +{ + unsigned int epoch = e & (CK_EPOCH_LENGTH - 1); + ck_stack_entry_t *head, *next, *cursor; + unsigned int n_pending, n_peak; + unsigned int i = 0; + + head = ck_stack_batch_pop_upmc(&record->pending[epoch]); + for (cursor = head; cursor != NULL; cursor = next) { + struct ck_epoch_entry *entry = + ck_epoch_entry_container(cursor); + + next = CK_STACK_NEXT(cursor); + if (deferred != NULL) + ck_stack_push_spnc(deferred, &entry->stack_entry); + else + entry->function(entry); + i++; + } + + n_peak = ck_pr_load_uint(&record->n_peak); + n_pending = ck_pr_load_uint(&record->n_pending); + + /* We don't require accuracy around peak calculation. */ + if (n_pending > n_peak) + ck_pr_store_uint(&record->n_peak, n_peak); + + if (i > 0) { + ck_pr_add_uint(&record->n_dispatch, i); + ck_pr_sub_uint(&record->n_pending, i); + } + + return; +} + +/* + * Reclaim all objects associated with a record. + */ +void +ck_epoch_reclaim(struct ck_epoch_record *record) +{ + unsigned int epoch; + + for (epoch = 0; epoch < CK_EPOCH_LENGTH; epoch++) + ck_epoch_dispatch(record, epoch, NULL); + + return; +} + +CK_CC_FORCE_INLINE static void +epoch_block(struct ck_epoch *global, struct ck_epoch_record *cr, + ck_epoch_wait_cb_t *cb, void *ct) +{ + + if (cb != NULL) + cb(global, cr, ct); + + return; +} + +/* + * This function must not be called with-in read section. + */ +void +ck_epoch_synchronize_wait(struct ck_epoch *global, + ck_epoch_wait_cb_t *cb, void *ct) +{ + struct ck_epoch_record *cr; + unsigned int delta, epoch, goal, i; + bool active; + + ck_pr_fence_memory(); + + /* + * The observation of the global epoch must be ordered with respect to + * all prior operations. The re-ordering of loads is permitted given + * monoticity of global epoch counter. + * + * If UINT_MAX concurrent mutations were to occur then it is possible + * to encounter an ABA-issue. If this is a concern, consider tuning + * write-side concurrency. + */ + delta = epoch = ck_pr_load_uint(&global->epoch); + goal = epoch + CK_EPOCH_GRACE; + + for (i = 0, cr = NULL; i < CK_EPOCH_GRACE - 1; cr = NULL, i++) { + bool r; + + /* + * Determine whether all threads have observed the current + * epoch with respect to the updates on invocation. + */ + while (cr = ck_epoch_scan(global, cr, delta, &active), + cr != NULL) { + unsigned int e_d; + + ck_pr_stall(); + + /* + * Another writer may have already observed a grace + * period. + */ + e_d = ck_pr_load_uint(&global->epoch); + if (e_d == delta) { + epoch_block(global, cr, cb, ct); + continue; + } + + /* + * If the epoch has been updated, we may have already + * met our goal. + */ + delta = e_d; + if ((goal > epoch) & (delta >= goal)) + goto leave; + + epoch_block(global, cr, cb, ct); + + /* + * If the epoch has been updated, then a grace period + * requires that all threads are observed idle at the + * same epoch. + */ + cr = NULL; + } + + /* + * If we have observed all threads as inactive, then we assume + * we are at a grace period. + */ + if (active == false) + break; + + /* + * Increment current epoch. CAS semantics are used to eliminate + * increment operations for synchronization that occurs for the + * same global epoch value snapshot. + * + * If we can guarantee there will only be one active barrier or + * epoch tick at a given time, then it is sufficient to use an + * increment operation. In a multi-barrier workload, however, + * it is possible to overflow the epoch value if we apply + * modulo-3 arithmetic. + */ + r = ck_pr_cas_uint_value(&global->epoch, delta, delta + 1, + &delta); + + /* Order subsequent thread active checks. */ + ck_pr_fence_atomic_load(); + + /* + * If CAS has succeeded, then set delta to latest snapshot. + * Otherwise, we have just acquired latest snapshot. + */ + delta = delta + r; + } + + /* + * A majority of use-cases will not require full barrier semantics. + * However, if non-temporal instructions are used, full barrier + * semantics are necessary. + */ +leave: + ck_pr_fence_memory(); + return; +} + +void +ck_epoch_synchronize(struct ck_epoch_record *record) +{ + + ck_epoch_synchronize_wait(record->global, NULL, NULL); + return; +} + +void +ck_epoch_barrier(struct ck_epoch_record *record) +{ + + ck_epoch_synchronize(record); + ck_epoch_reclaim(record); + return; +} + +void +ck_epoch_barrier_wait(struct ck_epoch_record *record, ck_epoch_wait_cb_t *cb, + void *ct) +{ + + ck_epoch_synchronize_wait(record->global, cb, ct); + ck_epoch_reclaim(record); + return; +} + +/* + * It may be worth it to actually apply these deferral semantics to an epoch + * that was observed at ck_epoch_call time. The problem is that the latter + * would require a full fence. + * + * ck_epoch_call will dispatch to the latest epoch snapshot that was observed. + * There are cases where it will fail to reclaim as early as it could. If this + * becomes a problem, we could actually use a heap for epoch buckets but that + * is far from ideal too. + */ +bool +ck_epoch_poll_deferred(struct ck_epoch_record *record, ck_stack_t *deferred) +{ + bool active; + unsigned int epoch; + struct ck_epoch_record *cr = NULL; + struct ck_epoch *global = record->global; + + epoch = ck_pr_load_uint(&global->epoch); + + /* Serialize epoch snapshots with respect to global epoch. */ + ck_pr_fence_memory(); + cr = ck_epoch_scan(global, cr, epoch, &active); + if (cr != NULL) { + record->epoch = epoch; + return false; + } + + /* We are at a grace period if all threads are inactive. */ + if (active == false) { + record->epoch = epoch; + for (epoch = 0; epoch < CK_EPOCH_LENGTH; epoch++) + ck_epoch_dispatch(record, epoch, deferred); + + return true; + } + + /* If an active thread exists, rely on epoch observation. */ + (void)ck_pr_cas_uint(&global->epoch, epoch, epoch + 1); + + ck_epoch_dispatch(record, epoch + 1, deferred); + return true; +} + +bool +ck_epoch_poll(struct ck_epoch_record *record) +{ + + return ck_epoch_poll_deferred(record, NULL); +} diff --git a/freebsd/sys/dev/bce/if_bce.c b/freebsd/sys/dev/bce/if_bce.c index a2e4c804..61c9708d 100644 --- a/freebsd/sys/dev/bce/if_bce.c +++ b/freebsd/sys/dev/bce/if_bce.c @@ -531,7 +531,8 @@ MODULE_DEPEND(bce, miibus, 1, 1, 1); DRIVER_MODULE(bce, pci, bce_driver, bce_devclass, NULL, NULL); DRIVER_MODULE(miibus, bce, miibus_driver, miibus_devclass, NULL, NULL); - +MODULE_PNP_INFO("U16:vendor;U16:device;U16:#;U16:#;D:#", pci, bce, + bce_devs, sizeof(bce_devs[0]), nitems(bce_devs) - 1); /****************************************************************************/ /* Tunable device values */ @@ -8118,7 +8119,7 @@ bce_set_rx_mode(struct bce_softc *sc) DBPRINT(sc, BCE_INFO_MISC, "Enabling selective multicast mode.\n"); if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = ether_crc32_le(LLADDR((struct sockaddr_dl *) diff --git a/freebsd/sys/dev/bfe/if_bfe.c b/freebsd/sys/dev/bfe/if_bfe.c index 63825a99..c07d87fb 100644 --- a/freebsd/sys/dev/bfe/if_bfe.c +++ b/freebsd/sys/dev/bfe/if_bfe.c @@ -1111,7 +1111,7 @@ bfe_set_rx_mode(struct bfe_softc *sc) else { val &= ~BFE_RXCONF_ALLMULTI; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; bfe_cam_write(sc, diff --git a/freebsd/sys/dev/bge/if_bge.c b/freebsd/sys/dev/bge/if_bge.c index 956ee52f..aba0b05d 100644 --- a/freebsd/sys/dev/bge/if_bge.c +++ b/freebsd/sys/dev/bge/if_bge.c @@ -102,6 +102,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/tcp.h> +#include <netinet/netdump/netdump.h> #include <machine/bus.h> #include <machine/resource.h> @@ -428,8 +429,9 @@ static int bge_encap(struct bge_softc *, struct mbuf **, uint32_t *); static void bge_intr(void *); static int bge_msi_intr(void *); static void bge_intr_task(void *, int); -static void bge_start_locked(if_t); static void bge_start(if_t); +static void bge_start_locked(if_t); +static void bge_start_tx(struct bge_softc *, uint32_t); static int bge_ioctl(if_t, u_long, caddr_t); static void bge_init_locked(struct bge_softc *); static void bge_init(void *); @@ -519,6 +521,8 @@ static void bge_add_sysctl_stats(struct bge_softc *, struct sysctl_ctx_list *, struct sysctl_oid_list *); static int bge_sysctl_stats(SYSCTL_HANDLER_ARGS); +NETDUMP_DEFINE(bge); + static device_method_t bge_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bge_probe), @@ -3943,8 +3947,12 @@ again: if (error) { ether_ifdetach(ifp); device_printf(sc->bge_dev, "couldn't set up irq\n"); + goto fail; } + /* Attach driver netdump methods. */ + NETDUMP_SET(ifp, bge); + fail: if (error) bge_detach(dev); @@ -5391,22 +5399,26 @@ bge_start_locked(if_t ifp) if_bpfmtap(ifp, m_head); } - if (count > 0) { - bus_dmamap_sync(sc->bge_cdata.bge_tx_ring_tag, - sc->bge_cdata.bge_tx_ring_map, BUS_DMASYNC_PREWRITE); - /* Transmit. */ + if (count > 0) + bge_start_tx(sc, prodidx); +} + +static void +bge_start_tx(struct bge_softc *sc, uint32_t prodidx) +{ + + bus_dmamap_sync(sc->bge_cdata.bge_tx_ring_tag, + sc->bge_cdata.bge_tx_ring_map, BUS_DMASYNC_PREWRITE); + /* Transmit. */ + bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, prodidx); + /* 5700 b2 errata */ + if (sc->bge_chiprev == BGE_CHIPREV_5700_BX) bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, prodidx); - /* 5700 b2 errata */ - if (sc->bge_chiprev == BGE_CHIPREV_5700_BX) - bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, prodidx); - sc->bge_tx_prodidx = prodidx; + sc->bge_tx_prodidx = prodidx; - /* - * Set a timeout in case the chip goes out to lunch. - */ - sc->bge_timer = BGE_TX_TIMEOUT; - } + /* Set a timeout in case the chip goes out to lunch. */ + sc->bge_timer = BGE_TX_TIMEOUT; } /* @@ -6798,3 +6810,74 @@ bge_get_counter(if_t ifp, ift_counter cnt) return (if_get_counter_default(ifp, cnt)); } } + +#ifdef NETDUMP +static void +bge_netdump_init(if_t ifp, int *nrxr, int *ncl, int *clsize) +{ + struct bge_softc *sc; + + sc = if_getsoftc(ifp); + BGE_LOCK(sc); + *nrxr = sc->bge_return_ring_cnt; + *ncl = NETDUMP_MAX_IN_FLIGHT; + if ((sc->bge_flags & BGE_FLAG_JUMBO_STD) != 0 && + (if_getmtu(sc->bge_ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN + + ETHER_VLAN_ENCAP_LEN > (MCLBYTES - ETHER_ALIGN))) + *clsize = MJUM9BYTES; + else + *clsize = MCLBYTES; + BGE_UNLOCK(sc); +} + +static void +bge_netdump_event(if_t ifp __unused, enum netdump_ev event __unused) +{ +} + +static int +bge_netdump_transmit(if_t ifp, struct mbuf *m) +{ + struct bge_softc *sc; + uint32_t prodidx; + int error; + + sc = if_getsoftc(ifp); + if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING) + return (1); + + prodidx = sc->bge_tx_prodidx; + error = bge_encap(sc, &m, &prodidx); + if (error == 0) + bge_start_tx(sc, prodidx); + return (error); +} + +static int +bge_netdump_poll(if_t ifp, int count) +{ + struct bge_softc *sc; + uint32_t rx_prod, tx_cons; + + sc = if_getsoftc(ifp); + if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING) + return (1); + + bus_dmamap_sync(sc->bge_cdata.bge_status_tag, + sc->bge_cdata.bge_status_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + rx_prod = sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx; + tx_cons = sc->bge_ldata.bge_status_block->bge_idx[0].bge_tx_cons_idx; + + bus_dmamap_sync(sc->bge_cdata.bge_status_tag, + sc->bge_cdata.bge_status_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + (void)bge_rxeof(sc, rx_prod, 0); + bge_txeof(sc, tx_cons); + return (0); +} +#endif /* NETDUMP */ diff --git a/freebsd/sys/dev/dc/if_dc.c b/freebsd/sys/dev/dc/if_dc.c index 3339b83d..ac34a20a 100644 --- a/freebsd/sys/dev/dc/if_dc.c +++ b/freebsd/sys/dev/dc/if_dc.c @@ -999,7 +999,7 @@ dc_setfilt_21143(struct dc_softc *sc) DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = dc_mchash_le(sc, @@ -1077,7 +1077,7 @@ dc_setfilt_admtek(struct dc_softc *sc) /* Now program new ones. */ if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; if (DC_IS_CENTAUR(sc)) @@ -1150,7 +1150,7 @@ dc_setfilt_asix(struct dc_softc *sc) /* now program new ones */ if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = dc_mchash_be(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); @@ -1211,7 +1211,7 @@ dc_setfilt_uli(struct dc_softc *sc) /* Now build perfect filters. */ mcnt = 0; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; if (mcnt >= DC_ULI_FILTER_NPERF) { @@ -1296,7 +1296,7 @@ dc_setfilt_xircom(struct dc_softc *sc) DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = dc_mchash_le(sc, diff --git a/freebsd/sys/dev/dwc/if_dwc.c b/freebsd/sys/dev/dwc/if_dwc.c index badbd807..895fdfe5 100644 --- a/freebsd/sys/dev/dwc/if_dwc.c +++ b/freebsd/sys/dev/dwc/if_dwc.c @@ -702,7 +702,7 @@ dwc_setup_rxfilter(struct dwc_softc *sc) for (i = 0; i < nhash; i++) hash[i] = 0; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) diff --git a/freebsd/sys/dev/e1000/e1000_80003es2lan.c b/freebsd/sys/dev/e1000/e1000_80003es2lan.c index 50175d2a..6b05840f 100644 --- a/freebsd/sys/dev/e1000/e1000_80003es2lan.c +++ b/freebsd/sys/dev/e1000/e1000_80003es2lan.c @@ -62,7 +62,6 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw); static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw); static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw); -static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex); static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw); static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw); @@ -71,7 +70,6 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 data); static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw); -static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); static s32 e1000_read_mac_addr_80003es2lan(struct e1000_hw *hw); static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw); @@ -302,7 +300,7 @@ static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw) DEBUGFUNC("e1000_acquire_phy_80003es2lan"); mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; - return e1000_acquire_swfw_sync_80003es2lan(hw, mask); + return e1000_acquire_swfw_sync(hw, mask); } /** @@ -318,7 +316,7 @@ static void e1000_release_phy_80003es2lan(struct e1000_hw *hw) DEBUGFUNC("e1000_release_phy_80003es2lan"); mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; - e1000_release_swfw_sync_80003es2lan(hw, mask); + e1000_release_swfw_sync(hw, mask); } /** @@ -336,7 +334,7 @@ static s32 e1000_acquire_mac_csr_80003es2lan(struct e1000_hw *hw) mask = E1000_SWFW_CSR_SM; - return e1000_acquire_swfw_sync_80003es2lan(hw, mask); + return e1000_acquire_swfw_sync(hw, mask); } /** @@ -353,7 +351,7 @@ static void e1000_release_mac_csr_80003es2lan(struct e1000_hw *hw) mask = E1000_SWFW_CSR_SM; - e1000_release_swfw_sync_80003es2lan(hw, mask); + e1000_release_swfw_sync(hw, mask); } /** @@ -368,14 +366,14 @@ static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw) DEBUGFUNC("e1000_acquire_nvm_80003es2lan"); - ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); + ret_val = e1000_acquire_swfw_sync(hw, E1000_SWFW_EEP_SM); if (ret_val) return ret_val; ret_val = e1000_acquire_nvm_generic(hw); if (ret_val) - e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); + e1000_release_swfw_sync(hw, E1000_SWFW_EEP_SM); return ret_val; } @@ -391,78 +389,7 @@ static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw) DEBUGFUNC("e1000_release_nvm_80003es2lan"); e1000_release_nvm_generic(hw); - e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); -} - -/** - * e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore - * @hw: pointer to the HW structure - * @mask: specifies which semaphore to acquire - * - * Acquire the SW/FW semaphore to access the PHY or NVM. The mask - * will also specify which port we're acquiring the lock for. - **/ -static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) -{ - u32 swfw_sync; - u32 swmask = mask; - u32 fwmask = mask << 16; - s32 i = 0; - s32 timeout = 50; - - DEBUGFUNC("e1000_acquire_swfw_sync_80003es2lan"); - - while (i < timeout) { - if (e1000_get_hw_semaphore_generic(hw)) - return -E1000_ERR_SWFW_SYNC; - - swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); - if (!(swfw_sync & (fwmask | swmask))) - break; - - /* Firmware currently using resource (fwmask) - * or other software thread using resource (swmask) - */ - e1000_put_hw_semaphore_generic(hw); - msec_delay_irq(5); - i++; - } - - if (i == timeout) { - DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n"); - return -E1000_ERR_SWFW_SYNC; - } - - swfw_sync |= swmask; - E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); - - e1000_put_hw_semaphore_generic(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore - * @hw: pointer to the HW structure - * @mask: specifies which semaphore to acquire - * - * Release the SW/FW semaphore used to access the PHY or NVM. The mask - * will also specify which port we're releasing the lock for. - **/ -static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) -{ - u32 swfw_sync; - - DEBUGFUNC("e1000_release_swfw_sync_80003es2lan"); - - while (e1000_get_hw_semaphore_generic(hw) != E1000_SUCCESS) - ; /* Empty */ - - swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); - swfw_sync &= ~mask; - E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); - - e1000_put_hw_semaphore_generic(hw); + e1000_release_swfw_sync(hw, E1000_SWFW_EEP_SM); } /** diff --git a/freebsd/sys/dev/e1000/e1000_82571.c b/freebsd/sys/dev/e1000/e1000_82571.c index fdef7284..f84baf92 100644 --- a/freebsd/sys/dev/e1000/e1000_82571.c +++ b/freebsd/sys/dev/e1000/e1000_82571.c @@ -73,11 +73,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw); static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data); static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); -static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw); static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); -static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); -static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw); static s32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw); static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw); static s32 e1000_set_d0_lplu_state_82574(struct e1000_hw *hw, @@ -128,8 +125,8 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) phy->ops.get_cable_length = e1000_get_cable_length_igp_2; phy->ops.read_reg = e1000_read_phy_reg_igp; phy->ops.write_reg = e1000_write_phy_reg_igp; - phy->ops.acquire = e1000_get_hw_semaphore_82571; - phy->ops.release = e1000_put_hw_semaphore_82571; + phy->ops.acquire = e1000_get_hw_semaphore; + phy->ops.release = e1000_put_hw_semaphore; break; case e1000_82573: phy->type = e1000_phy_m88; @@ -141,12 +138,11 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) phy->ops.get_cable_length = e1000_get_cable_length_m88; phy->ops.read_reg = e1000_read_phy_reg_m88; phy->ops.write_reg = e1000_write_phy_reg_m88; - phy->ops.acquire = e1000_get_hw_semaphore_82571; - phy->ops.release = e1000_put_hw_semaphore_82571; + phy->ops.acquire = e1000_get_hw_semaphore; + phy->ops.release = e1000_put_hw_semaphore; break; case e1000_82574: case e1000_82583: - E1000_MUTEX_INIT(&hw->dev_spec._82571.swflag_mutex); phy->type = e1000_phy_bm; phy->ops.get_cfg_done = e1000_get_cfg_done_generic; @@ -509,99 +505,21 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw) } /** - * e1000_get_hw_semaphore_82571 - Acquire hardware semaphore - * @hw: pointer to the HW structure - * - * Acquire the HW semaphore to access the PHY or NVM - **/ -static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw) -{ - u32 swsm; - s32 sw_timeout = hw->nvm.word_size + 1; - s32 fw_timeout = hw->nvm.word_size + 1; - s32 i = 0; - - DEBUGFUNC("e1000_get_hw_semaphore_82571"); - - /* If we have timedout 3 times on trying to acquire - * the inter-port SMBI semaphore, there is old code - * operating on the other port, and it is not - * releasing SMBI. Modify the number of times that - * we try for the semaphore to interwork with this - * older code. - */ - if (hw->dev_spec._82571.smb_counter > 2) - sw_timeout = 1; - - /* Get the SW semaphore */ - while (i < sw_timeout) { - swsm = E1000_READ_REG(hw, E1000_SWSM); - if (!(swsm & E1000_SWSM_SMBI)) - break; - - usec_delay(50); - i++; - } - - if (i == sw_timeout) { - DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); - hw->dev_spec._82571.smb_counter++; - } - /* Get the FW semaphore. */ - for (i = 0; i < fw_timeout; i++) { - swsm = E1000_READ_REG(hw, E1000_SWSM); - E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI); - - /* Semaphore acquired if bit latched */ - if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI) - break; - - usec_delay(50); - } - - if (i == fw_timeout) { - /* Release semaphores */ - e1000_put_hw_semaphore_82571(hw); - DEBUGOUT("Driver can't access the NVM\n"); - return -E1000_ERR_NVM; - } - - return E1000_SUCCESS; -} - -/** - * e1000_put_hw_semaphore_82571 - Release hardware semaphore - * @hw: pointer to the HW structure - * - * Release hardware semaphore used to access the PHY or NVM - **/ -static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) -{ - u32 swsm; - - DEBUGFUNC("e1000_put_hw_semaphore_generic"); - - swsm = E1000_READ_REG(hw, E1000_SWSM); - - swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); - - E1000_WRITE_REG(hw, E1000_SWSM, swsm); -} - -/** - * e1000_get_hw_semaphore_82573 - Acquire hardware semaphore + * e1000_get_hw_semaphore_82574 - Acquire hardware semaphore * @hw: pointer to the HW structure * * Acquire the HW semaphore during reset. * **/ -static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw) +static s32 +e1000_get_hw_semaphore_82574(struct e1000_hw *hw) { u32 extcnf_ctrl; s32 i = 0; - + /* XXX assert that mutex is held */ DEBUGFUNC("e1000_get_hw_semaphore_82573"); + ASSERT_CTX_LOCK_HELD(hw); extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); do { extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; @@ -617,7 +535,7 @@ static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw) if (i == MDIO_OWNERSHIP_TIMEOUT) { /* Release semaphores */ - e1000_put_hw_semaphore_82573(hw); + e1000_put_hw_semaphore_82574(hw); DEBUGOUT("Driver can't access the PHY\n"); return -E1000_ERR_PHY; } @@ -626,17 +544,18 @@ static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw) } /** - * e1000_put_hw_semaphore_82573 - Release hardware semaphore + * e1000_put_hw_semaphore_82574 - Release hardware semaphore * @hw: pointer to the HW structure * * Release hardware semaphore used during reset. * **/ -static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw) +static void +e1000_put_hw_semaphore_82574(struct e1000_hw *hw) { u32 extcnf_ctrl; - DEBUGFUNC("e1000_put_hw_semaphore_82573"); + DEBUGFUNC("e1000_put_hw_semaphore_82574"); extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); extcnf_ctrl &= ~E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; @@ -644,41 +563,6 @@ static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw) } /** - * e1000_get_hw_semaphore_82574 - Acquire hardware semaphore - * @hw: pointer to the HW structure - * - * Acquire the HW semaphore to access the PHY or NVM. - * - **/ -static s32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw) -{ - s32 ret_val; - - DEBUGFUNC("e1000_get_hw_semaphore_82574"); - - E1000_MUTEX_LOCK(&hw->dev_spec._82571.swflag_mutex); - ret_val = e1000_get_hw_semaphore_82573(hw); - if (ret_val) - E1000_MUTEX_UNLOCK(&hw->dev_spec._82571.swflag_mutex); - return ret_val; -} - -/** - * e1000_put_hw_semaphore_82574 - Release hardware semaphore - * @hw: pointer to the HW structure - * - * Release hardware semaphore used to access the PHY or NVM - * - **/ -static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw) -{ - DEBUGFUNC("e1000_put_hw_semaphore_82574"); - - e1000_put_hw_semaphore_82573(hw); - E1000_MUTEX_UNLOCK(&hw->dev_spec._82571.swflag_mutex); -} - -/** * e1000_set_d0_lplu_state_82574 - Set Low Power Linkup D0 state * @hw: pointer to the HW structure * @active: TRUE to enable LPLU, FALSE to disable @@ -749,7 +633,7 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw) DEBUGFUNC("e1000_acquire_nvm_82571"); - ret_val = e1000_get_hw_semaphore_82571(hw); + ret_val = e1000_get_hw_semaphore(hw); if (ret_val) return ret_val; @@ -762,7 +646,7 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw) } if (ret_val) - e1000_put_hw_semaphore_82571(hw); + e1000_put_hw_semaphore(hw); return ret_val; } @@ -778,7 +662,7 @@ static void e1000_release_nvm_82571(struct e1000_hw *hw) DEBUGFUNC("e1000_release_nvm_82571"); e1000_release_nvm_generic(hw); - e1000_put_hw_semaphore_82571(hw); + e1000_put_hw_semaphore(hw); } /** @@ -1095,8 +979,6 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) */ switch (hw->mac.type) { case e1000_82573: - ret_val = e1000_get_hw_semaphore_82573(hw); - break; case e1000_82574: case e1000_82583: ret_val = e1000_get_hw_semaphore_82574(hw); @@ -1113,10 +995,6 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) /* Must release MDIO ownership and mutex after MAC reset. */ switch (hw->mac.type) { case e1000_82573: - /* Release mutex only if the hw semaphore is acquired */ - if (!ret_val) - e1000_put_hw_semaphore_82573(hw); - break; case e1000_82574: case e1000_82583: /* Release mutex only if the hw semaphore is acquired */ @@ -1124,6 +1002,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) e1000_put_hw_semaphore_82574(hw); break; default: + /* we didn't get the semaphore no need to put it */ break; } diff --git a/freebsd/sys/dev/e1000/e1000_82575.c b/freebsd/sys/dev/e1000/e1000_82575.c index bffa1117..0de11ef5 100644 --- a/freebsd/sys/dev/e1000/e1000_82575.c +++ b/freebsd/sys/dev/e1000/e1000_82575.c @@ -82,11 +82,9 @@ static s32 e1000_valid_led_default_82575(struct e1000_hw *hw, u16 *data); static s32 e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, u16 data); static void e1000_clear_hw_cntrs_82575(struct e1000_hw *hw); -static s32 e1000_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask); static s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed, u16 *duplex); static s32 e1000_get_phy_id_82575(struct e1000_hw *hw); -static void e1000_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask); static bool e1000_sgmii_active_82575(struct e1000_hw *hw); static s32 e1000_reset_init_script_82575(struct e1000_hw *hw); static s32 e1000_read_mac_addr_82575(struct e1000_hw *hw); @@ -514,12 +512,8 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw) /* link info */ mac->ops.get_link_up_info = e1000_get_link_up_info_82575; /* acquire SW_FW sync */ - mac->ops.acquire_swfw_sync = e1000_acquire_swfw_sync_82575; - mac->ops.release_swfw_sync = e1000_release_swfw_sync_82575; - if (mac->type >= e1000_i210) { - mac->ops.acquire_swfw_sync = e1000_acquire_swfw_sync_i210; - mac->ops.release_swfw_sync = e1000_release_swfw_sync_i210; - } + mac->ops.acquire_swfw_sync = e1000_acquire_swfw_sync; + mac->ops.release_swfw_sync = e1000_release_swfw_sync; /* set lan id for port to determine which phy lock to use */ hw->mac.ops.set_lan_id(hw); @@ -991,7 +985,7 @@ static s32 e1000_acquire_nvm_82575(struct e1000_hw *hw) DEBUGFUNC("e1000_acquire_nvm_82575"); - ret_val = e1000_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); + ret_val = e1000_acquire_swfw_sync(hw, E1000_SWFW_EEP_SM); if (ret_val) goto out; @@ -1022,7 +1016,7 @@ static s32 e1000_acquire_nvm_82575(struct e1000_hw *hw) ret_val = e1000_acquire_nvm_generic(hw); if (ret_val) - e1000_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); + e1000_release_swfw_sync(hw, E1000_SWFW_EEP_SM); out: return ret_val; @@ -1041,83 +1035,7 @@ static void e1000_release_nvm_82575(struct e1000_hw *hw) e1000_release_nvm_generic(hw); - e1000_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); -} - -/** - * e1000_acquire_swfw_sync_82575 - Acquire SW/FW semaphore - * @hw: pointer to the HW structure - * @mask: specifies which semaphore to acquire - * - * Acquire the SW/FW semaphore to access the PHY or NVM. The mask - * will also specify which port we're acquiring the lock for. - **/ -static s32 e1000_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask) -{ - u32 swfw_sync; - u32 swmask = mask; - u32 fwmask = mask << 16; - s32 ret_val = E1000_SUCCESS; - s32 i = 0, timeout = 200; - - DEBUGFUNC("e1000_acquire_swfw_sync_82575"); - - while (i < timeout) { - if (e1000_get_hw_semaphore_generic(hw)) { - ret_val = -E1000_ERR_SWFW_SYNC; - goto out; - } - - swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); - if (!(swfw_sync & (fwmask | swmask))) - break; - - /* - * Firmware currently using resource (fwmask) - * or other software thread using resource (swmask) - */ - e1000_put_hw_semaphore_generic(hw); - msec_delay_irq(5); - i++; - } - - if (i == timeout) { - DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n"); - ret_val = -E1000_ERR_SWFW_SYNC; - goto out; - } - - swfw_sync |= swmask; - E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); - - e1000_put_hw_semaphore_generic(hw); - -out: - return ret_val; -} - -/** - * e1000_release_swfw_sync_82575 - Release SW/FW semaphore - * @hw: pointer to the HW structure - * @mask: specifies which semaphore to acquire - * - * Release the SW/FW semaphore used to access the PHY or NVM. The mask - * will also specify which port we're releasing the lock for. - **/ -static void e1000_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask) -{ - u32 swfw_sync; - - DEBUGFUNC("e1000_release_swfw_sync_82575"); - - while (e1000_get_hw_semaphore_generic(hw) != E1000_SUCCESS) - ; /* Empty */ - - swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); - swfw_sync &= ~mask; - E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); - - e1000_put_hw_semaphore_generic(hw); + e1000_release_swfw_sync(hw, E1000_SWFW_EEP_SM); } /** diff --git a/freebsd/sys/dev/e1000/e1000_hw.h b/freebsd/sys/dev/e1000/e1000_hw.h index 2c17a022..7e4e7f1a 100644 --- a/freebsd/sys/dev/e1000/e1000_hw.h +++ b/freebsd/sys/dev/e1000/e1000_hw.h @@ -944,7 +944,6 @@ struct e1000_dev_spec_82543 { struct e1000_dev_spec_82571 { bool laa_is_present; u32 smb_counter; - E1000_MUTEX swflag_mutex; }; struct e1000_dev_spec_80003es2lan { @@ -968,8 +967,6 @@ enum e1000_ulp_state { struct e1000_dev_spec_ich8lan { bool kmrn_lock_loss_workaround_enabled; struct e1000_shadow_ram shadow_ram[E1000_SHADOW_RAM_WORDS]; - E1000_MUTEX nvm_mutex; - E1000_MUTEX swflag_mutex; bool nvm_k1_enabled; bool disable_k1_off; bool eee_disable; diff --git a/freebsd/sys/dev/e1000/e1000_i210.c b/freebsd/sys/dev/e1000/e1000_i210.c index 5f09e4d2..5ee48810 100644 --- a/freebsd/sys/dev/e1000/e1000_i210.c +++ b/freebsd/sys/dev/e1000/e1000_i210.c @@ -40,7 +40,6 @@ static s32 e1000_acquire_nvm_i210(struct e1000_hw *hw); static void e1000_release_nvm_i210(struct e1000_hw *hw); -static s32 e1000_get_hw_semaphore_i210(struct e1000_hw *hw); static s32 e1000_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); static s32 e1000_pool_flash_update_done_i210(struct e1000_hw *hw); @@ -61,7 +60,7 @@ static s32 e1000_acquire_nvm_i210(struct e1000_hw *hw) DEBUGFUNC("e1000_acquire_nvm_i210"); - ret_val = e1000_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); + ret_val = e1000_acquire_swfw_sync(hw, E1000_SWFW_EEP_SM); return ret_val; } @@ -77,152 +76,7 @@ static void e1000_release_nvm_i210(struct e1000_hw *hw) { DEBUGFUNC("e1000_release_nvm_i210"); - e1000_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); -} - -/** - * e1000_acquire_swfw_sync_i210 - Acquire SW/FW semaphore - * @hw: pointer to the HW structure - * @mask: specifies which semaphore to acquire - * - * Acquire the SW/FW semaphore to access the PHY or NVM. The mask - * will also specify which port we're acquiring the lock for. - **/ -s32 e1000_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask) -{ - u32 swfw_sync; - u32 swmask = mask; - u32 fwmask = mask << 16; - s32 ret_val = E1000_SUCCESS; - s32 i = 0, timeout = 200; /* FIXME: find real value to use here */ - - DEBUGFUNC("e1000_acquire_swfw_sync_i210"); - - while (i < timeout) { - if (e1000_get_hw_semaphore_i210(hw)) { - ret_val = -E1000_ERR_SWFW_SYNC; - goto out; - } - - swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); - if (!(swfw_sync & (fwmask | swmask))) - break; - - /* - * Firmware currently using resource (fwmask) - * or other software thread using resource (swmask) - */ - e1000_put_hw_semaphore_generic(hw); - msec_delay_irq(5); - i++; - } - - if (i == timeout) { - DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n"); - ret_val = -E1000_ERR_SWFW_SYNC; - goto out; - } - - swfw_sync |= swmask; - E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); - - e1000_put_hw_semaphore_generic(hw); - -out: - return ret_val; -} - -/** - * e1000_release_swfw_sync_i210 - Release SW/FW semaphore - * @hw: pointer to the HW structure - * @mask: specifies which semaphore to acquire - * - * Release the SW/FW semaphore used to access the PHY or NVM. The mask - * will also specify which port we're releasing the lock for. - **/ -void e1000_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask) -{ - u32 swfw_sync; - - DEBUGFUNC("e1000_release_swfw_sync_i210"); - - while (e1000_get_hw_semaphore_i210(hw) != E1000_SUCCESS) - ; /* Empty */ - - swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); - swfw_sync &= ~mask; - E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); - - e1000_put_hw_semaphore_generic(hw); -} - -/** - * e1000_get_hw_semaphore_i210 - Acquire hardware semaphore - * @hw: pointer to the HW structure - * - * Acquire the HW semaphore to access the PHY or NVM - **/ -static s32 e1000_get_hw_semaphore_i210(struct e1000_hw *hw) -{ - u32 swsm; - s32 timeout = hw->nvm.word_size + 1; - s32 i = 0; - - DEBUGFUNC("e1000_get_hw_semaphore_i210"); - - /* Get the SW semaphore */ - while (i < timeout) { - swsm = E1000_READ_REG(hw, E1000_SWSM); - if (!(swsm & E1000_SWSM_SMBI)) - break; - - usec_delay(50); - i++; - } - - if (i == timeout) { - /* In rare circumstances, the SW semaphore may already be held - * unintentionally. Clear the semaphore once before giving up. - */ - if (hw->dev_spec._82575.clear_semaphore_once) { - hw->dev_spec._82575.clear_semaphore_once = FALSE; - e1000_put_hw_semaphore_generic(hw); - for (i = 0; i < timeout; i++) { - swsm = E1000_READ_REG(hw, E1000_SWSM); - if (!(swsm & E1000_SWSM_SMBI)) - break; - - usec_delay(50); - } - } - - /* If we do not have the semaphore here, we have to give up. */ - if (i == timeout) { - DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); - return -E1000_ERR_NVM; - } - } - - /* Get the FW semaphore. */ - for (i = 0; i < timeout; i++) { - swsm = E1000_READ_REG(hw, E1000_SWSM); - E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI); - - /* Semaphore acquired if bit latched */ - if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI) - break; - - usec_delay(50); - } - - if (i == timeout) { - /* Release semaphores */ - e1000_put_hw_semaphore_generic(hw); - DEBUGOUT("Driver can't access the NVM\n"); - return -E1000_ERR_NVM; - } - - return E1000_SUCCESS; + e1000_release_swfw_sync(hw, E1000_SWFW_EEP_SM); } /** diff --git a/freebsd/sys/dev/e1000/e1000_i210.h b/freebsd/sys/dev/e1000/e1000_i210.h index c08a0dd7..ed6262b5 100644 --- a/freebsd/sys/dev/e1000/e1000_i210.h +++ b/freebsd/sys/dev/e1000/e1000_i210.h @@ -44,8 +44,6 @@ s32 e1000_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); s32 e1000_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); -s32 e1000_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask); -void e1000_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask); s32 e1000_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 *data); s32 e1000_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, diff --git a/freebsd/sys/dev/e1000/e1000_ich8lan.c b/freebsd/sys/dev/e1000/e1000_ich8lan.c index bcd82c47..cbddadd7 100644 --- a/freebsd/sys/dev/e1000/e1000_ich8lan.c +++ b/freebsd/sys/dev/e1000/e1000_ich8lan.c @@ -699,9 +699,6 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) dev_spec->shadow_ram[i].value = 0xFFFF; } - E1000_MUTEX_INIT(&dev_spec->nvm_mutex); - E1000_MUTEX_INIT(&dev_spec->swflag_mutex); - /* Function Pointers */ nvm->ops.acquire = e1000_acquire_nvm_ich8lan; nvm->ops.release = e1000_release_nvm_ich8lan; @@ -1854,7 +1851,7 @@ static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw) { DEBUGFUNC("e1000_acquire_nvm_ich8lan"); - E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex); + ASSERT_CTX_LOCK_HELD(hw); return E1000_SUCCESS; } @@ -1869,9 +1866,7 @@ static void e1000_release_nvm_ich8lan(struct e1000_hw *hw) { DEBUGFUNC("e1000_release_nvm_ich8lan"); - E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex); - - return; + ASSERT_CTX_LOCK_HELD(hw); } /** @@ -1888,7 +1883,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) DEBUGFUNC("e1000_acquire_swflag_ich8lan"); - E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex); + ASSERT_CTX_LOCK_HELD(hw); while (timeout) { extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); @@ -1929,9 +1924,6 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) } out: - if (ret_val) - E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); - return ret_val; } @@ -1956,10 +1948,6 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) } else { DEBUGOUT("Semaphore unexpectedly released by sw/fw/hw\n"); } - - E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); - - return; } /** @@ -5034,8 +5022,6 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) E1000_WRITE_REG(hw, E1000_FEXTNVM3, reg); } - if (!ret_val) - E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex); if (ctrl & E1000_CTRL_PHY_RST) { ret_val = hw->phy.ops.get_cfg_done(hw); diff --git a/freebsd/sys/dev/e1000/e1000_mac.c b/freebsd/sys/dev/e1000/e1000_mac.c index 581659be..7a46ca5a 100644 --- a/freebsd/sys/dev/e1000/e1000_mac.c +++ b/freebsd/sys/dev/e1000/e1000_mac.c @@ -1710,76 +1710,6 @@ s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw E1000_UNUSED } /** - * e1000_get_hw_semaphore_generic - Acquire hardware semaphore - * @hw: pointer to the HW structure - * - * Acquire the HW semaphore to access the PHY or NVM - **/ -s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw) -{ - u32 swsm; - s32 timeout = hw->nvm.word_size + 1; - s32 i = 0; - - DEBUGFUNC("e1000_get_hw_semaphore_generic"); - - /* Get the SW semaphore */ - while (i < timeout) { - swsm = E1000_READ_REG(hw, E1000_SWSM); - if (!(swsm & E1000_SWSM_SMBI)) - break; - - usec_delay(50); - i++; - } - - if (i == timeout) { - DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); - return -E1000_ERR_NVM; - } - - /* Get the FW semaphore. */ - for (i = 0; i < timeout; i++) { - swsm = E1000_READ_REG(hw, E1000_SWSM); - E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI); - - /* Semaphore acquired if bit latched */ - if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI) - break; - - usec_delay(50); - } - - if (i == timeout) { - /* Release semaphores */ - e1000_put_hw_semaphore_generic(hw); - DEBUGOUT("Driver can't access the NVM\n"); - return -E1000_ERR_NVM; - } - - return E1000_SUCCESS; -} - -/** - * e1000_put_hw_semaphore_generic - Release hardware semaphore - * @hw: pointer to the HW structure - * - * Release hardware semaphore used to access the PHY or NVM - **/ -void e1000_put_hw_semaphore_generic(struct e1000_hw *hw) -{ - u32 swsm; - - DEBUGFUNC("e1000_put_hw_semaphore_generic"); - - swsm = E1000_READ_REG(hw, E1000_SWSM); - - swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); - - E1000_WRITE_REG(hw, E1000_SWSM, swsm); -} - -/** * e1000_get_auto_rd_done_generic - Check for auto read completion * @hw: pointer to the HW structure * @@ -2254,3 +2184,181 @@ s32 e1000_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg, return E1000_SUCCESS; } + +/** + * e1000_get_hw_semaphore - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM + **/ +s32 e1000_get_hw_semaphore(struct e1000_hw *hw) +{ + u32 swsm; + s32 fw_timeout = hw->nvm.word_size + 1; + s32 sw_timeout = hw->nvm.word_size + 1; + s32 i = 0; + + DEBUGFUNC("e1000_get_hw_semaphore"); + + /* _82571 */ + /* If we have timedout 3 times on trying to acquire + * the inter-port SMBI semaphore, there is old code + * operating on the other port, and it is not + * releasing SMBI. Modify the number of times that + * we try for the semaphore to interwork with this + * older code. + */ + if (hw->dev_spec._82571.smb_counter > 2) + sw_timeout = 1; + + + /* Get the SW semaphore */ + while (i < sw_timeout) { + swsm = E1000_READ_REG(hw, E1000_SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + usec_delay(50); + i++; + } + + if (i == sw_timeout) { + DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); + hw->dev_spec._82571.smb_counter++; + } + + /* In rare circumstances, the SW semaphore may already be held + * unintentionally. Clear the semaphore once before giving up. + */ + if (hw->dev_spec._82575.clear_semaphore_once) { + hw->dev_spec._82575.clear_semaphore_once = FALSE; + e1000_put_hw_semaphore(hw); + for (i = 0; i < fw_timeout; i++) { + swsm = E1000_READ_REG(hw, E1000_SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + usec_delay(50); + } + } + + /* Get the FW semaphore. */ + for (i = 0; i < fw_timeout; i++) { + swsm = E1000_READ_REG(hw, E1000_SWSM); + E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI) + break; + + usec_delay(50); + } + + if (i == fw_timeout) { + /* Release semaphores */ + e1000_put_hw_semaphore(hw); + DEBUGOUT("Driver can't access the NVM\n"); + return -E1000_ERR_NVM; + } + + return E1000_SUCCESS; +} + +/** + * e1000_put_hw_semaphore - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + **/ +void e1000_put_hw_semaphore(struct e1000_hw *hw) +{ + u32 swsm; + + DEBUGFUNC("e1000_put_hw_semaphore"); + + swsm = E1000_READ_REG(hw, E1000_SWSM); + + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + + E1000_WRITE_REG(hw, E1000_SWSM, swsm); +} + + +/** + * e1000_acquire_swfw_sync - Acquire SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Acquire the SW/FW semaphore to access the PHY or NVM. The mask + * will also specify which port we're acquiring the lock for. + **/ +s32 +e1000_acquire_swfw_sync(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + u32 swmask = mask; + u32 fwmask = mask << 16; + s32 ret_val = E1000_SUCCESS; + s32 i = 0, timeout = 200; + + DEBUGFUNC("e1000_acquire_swfw_sync"); + ASSERT_NO_LOCKS(); + while (i < timeout) { + if (e1000_get_hw_semaphore(hw)) { + ret_val = -E1000_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); + if (!(swfw_sync & (fwmask | swmask))) + break; + + /* + * Firmware currently using resource (fwmask) + * or other software thread using resource (swmask) + */ + e1000_put_hw_semaphore(hw); + msec_delay_irq(5); + i++; + } + + if (i == timeout) { + DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n"); + ret_val = -E1000_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync |= swmask; + E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); + + e1000_put_hw_semaphore(hw); + +out: + return ret_val; +} + +/** + * e1000_release_swfw_sync - Release SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Release the SW/FW semaphore used to access the PHY or NVM. The mask + * will also specify which port we're releasing the lock for. + **/ +void +e1000_release_swfw_sync(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + + DEBUGFUNC("e1000_release_swfw_sync"); + + while (e1000_get_hw_semaphore(hw) != E1000_SUCCESS) + ; /* Empty */ + + swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); + swfw_sync &= ~mask; + E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); + + e1000_put_hw_semaphore(hw); +} + diff --git a/freebsd/sys/dev/e1000/e1000_mac.h b/freebsd/sys/dev/e1000/e1000_mac.h index cb8da246..66f94595 100644 --- a/freebsd/sys/dev/e1000/e1000_mac.h +++ b/freebsd/sys/dev/e1000/e1000_mac.h @@ -61,7 +61,6 @@ s32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw); s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw); void e1000_set_lan_id_single_port(struct e1000_hw *hw); void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw); -s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw); s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed, u16 *duplex); s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw, @@ -86,11 +85,15 @@ void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw); void e1000_clear_vfta_generic(struct e1000_hw *hw); void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count); void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw); -void e1000_put_hw_semaphore_generic(struct e1000_hw *hw); s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw); void e1000_reset_adaptive_generic(struct e1000_hw *hw); void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop); void e1000_update_adaptive_generic(struct e1000_hw *hw); void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value); +s32 e1000_get_hw_semaphore(struct e1000_hw *hw); +void e1000_put_hw_semaphore(struct e1000_hw *hw); +s32 e1000_acquire_swfw_sync(struct e1000_hw *hw, u16 mask); +void e1000_release_swfw_sync(struct e1000_hw *hw, u16 mask); + #endif diff --git a/freebsd/sys/dev/e1000/e1000_osdep.h b/freebsd/sys/dev/e1000/e1000_osdep.h index d9f956f3..55348785 100644 --- a/freebsd/sys/dev/e1000/e1000_osdep.h +++ b/freebsd/sys/dev/e1000/e1000_osdep.h @@ -40,6 +40,7 @@ #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> +#include <sys/proc.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/mbuf.h> @@ -48,6 +49,14 @@ #include <sys/malloc.h> #include <sys/kernel.h> #include <sys/bus.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_var.h> +#include <net/iflib.h> + + + #include <machine/bus.h> #include <sys/rman.h> #include <machine/resource.h> @@ -59,11 +68,40 @@ #define ASSERT(x) if(!(x)) panic("EM: x") +#define us_scale(x) max(1, (x/(1000000/hz))) +static inline int +ms_scale(int x) { + if (hz == 1000) { + return (x); + } else if (hz > 1000) { + return (x*(hz/1000)); + } else { + return (max(1, x/(1000/hz))); + } +} + +static inline void +safe_pause_us(int x) { + if (cold) { + DELAY(x); + } else { + pause("e1000_delay", max(1, x/(1000000/hz))); + } +} + +static inline void +safe_pause_ms(int x) { + if (cold) { + DELAY(x*1000); + } else { + pause("e1000_delay", ms_scale(x)); + } +} -#define usec_delay(x) DELAY(x) +#define usec_delay(x) safe_pause_us(x) #define usec_delay_irq(x) usec_delay(x) -#define msec_delay(x) DELAY(1000*(x)) -#define msec_delay_irq(x) DELAY(1000*(x)) +#define msec_delay(x) safe_pause_ms(x) +#define msec_delay_irq(x) msec_delay(x) /* Enable/disable debugging statements in shared code */ #define DBG 0 @@ -82,16 +120,6 @@ #define CMD_MEM_WRT_INVALIDATE 0x0010 /* BIT_4 */ #define PCI_COMMAND_REGISTER PCIR_COMMAND -/* Mutex used in the shared code */ -#define E1000_MUTEX struct mtx -#define E1000_MUTEX_INIT(mutex) mtx_init((mutex), #mutex, \ - MTX_NETWORK_LOCK, \ - MTX_DEF | MTX_DUPOK) -#define E1000_MUTEX_DESTROY(mutex) mtx_destroy(mutex) -#define E1000_MUTEX_LOCK(mutex) mtx_lock(mutex) -#define E1000_MUTEX_TRYLOCK(mutex) mtx_trylock(mutex) -#define E1000_MUTEX_UNLOCK(mutex) mtx_unlock(mutex) - typedef uint64_t u64; typedef uint32_t u32; typedef uint16_t u16; @@ -117,6 +145,12 @@ typedef int8_t s8; #endif #endif /*__FreeBSD_version < 800000 */ +#ifdef INVARIANTS +#define ASSERT_CTX_LOCK_HELD(hw) (sx_assert(iflib_ctx_lock_get(((struct e1000_osdep *)hw->back)->ctx), SX_XLOCKED)) +#else +#define ASSERT_CTX_LOCK_HELD(hw) +#endif + #if defined(__i386__) || defined(__amd64__) static __inline void prefetch(void *x) @@ -136,6 +170,7 @@ struct e1000_osdep bus_space_tag_t flash_bus_space_tag; bus_space_handle_t flash_bus_space_handle; device_t dev; + if_ctx_t ctx; }; #define E1000_REGISTER(hw, reg) (((hw)->mac.type >= e1000_82543) \ @@ -217,5 +252,22 @@ struct e1000_osdep bus_space_write_2(((struct e1000_osdep *)(hw)->back)->flash_bus_space_tag, \ ((struct e1000_osdep *)(hw)->back)->flash_bus_space_handle, reg, value) + +#if defined(INVARIANTS) +#include <sys/proc.h> + +#define ASSERT_NO_LOCKS() \ + do { \ + int unknown_locks = curthread->td_locks - mtx_owned(&Giant); \ + if (unknown_locks > 0) { \ + WITNESS_WARN(WARN_GIANTOK|WARN_SLEEPOK|WARN_PANIC, NULL, "unexpected non-sleepable lock"); \ + } \ + MPASS(curthread->td_rw_rlocks == 0); \ + MPASS(curthread->td_lk_slocks == 0); \ + } while (0) +#else +#define ASSERT_NO_LOCKS() +#endif + #endif /* _FREEBSD_OS_H_ */ diff --git a/freebsd/sys/dev/e1000/em_txrx.c b/freebsd/sys/dev/e1000/em_txrx.c index 92b4a5f4..8157c9ce 100644 --- a/freebsd/sys/dev/e1000/em_txrx.c +++ b/freebsd/sys/dev/e1000/em_txrx.c @@ -70,25 +70,25 @@ static int em_determine_rsstype(u32 pkt_info); extern int em_intr(void *arg); struct if_txrx em_txrx = { - em_isc_txd_encap, - em_isc_txd_flush, - em_isc_txd_credits_update, - em_isc_rxd_available, - em_isc_rxd_pkt_get, - em_isc_rxd_refill, - em_isc_rxd_flush, - em_intr + .ift_txd_encap = em_isc_txd_encap, + .ift_txd_flush = em_isc_txd_flush, + .ift_txd_credits_update = em_isc_txd_credits_update, + .ift_rxd_available = em_isc_rxd_available, + .ift_rxd_pkt_get = em_isc_rxd_pkt_get, + .ift_rxd_refill = em_isc_rxd_refill, + .ift_rxd_flush = em_isc_rxd_flush, + .ift_legacy_intr = em_intr }; struct if_txrx lem_txrx = { - em_isc_txd_encap, - em_isc_txd_flush, - em_isc_txd_credits_update, - lem_isc_rxd_available, - lem_isc_rxd_pkt_get, - lem_isc_rxd_refill, - em_isc_rxd_flush, - em_intr + .ift_txd_encap = em_isc_txd_encap, + .ift_txd_flush = em_isc_txd_flush, + .ift_txd_credits_update = em_isc_txd_credits_update, + .ift_rxd_available = lem_isc_rxd_available, + .ift_rxd_pkt_get = lem_isc_rxd_pkt_get, + .ift_rxd_refill = lem_isc_rxd_refill, + .ift_rxd_flush = em_isc_rxd_flush, + .ift_legacy_intr = em_intr }; extern if_shared_ctx_t em_sctx; @@ -403,7 +403,7 @@ em_isc_txd_encap(void *arg, if_pkt_info_t pi) * needs End Of Packet (EOP) * and Report Status (RS) */ - if (txd_flags) { + if (txd_flags && nsegs) { txr->tx_rsq[txr->tx_rs_pidx] = pidx_last; DPRINTF(iflib_get_dev(sc->ctx), "setting to RS on %d rs_pidx %d first: %d\n", pidx_last, txr->tx_rs_pidx, first); txr->tx_rs_pidx = (txr->tx_rs_pidx+1) & (ntxd-1); diff --git a/freebsd/sys/dev/e1000/if_em.c b/freebsd/sys/dev/e1000/if_em.c index 5150eaea..72711a6e 100644 --- a/freebsd/sys/dev/e1000/if_em.c +++ b/freebsd/sys/dev/e1000/if_em.c @@ -738,7 +738,7 @@ em_if_attach_pre(if_ctx_t ctx) return (ENXIO); } - adapter->ctx = ctx; + adapter->ctx = adapter->osdep.ctx = ctx; adapter->dev = adapter->osdep.dev = dev; scctx = adapter->shared = iflib_get_softc_ctx(ctx); adapter->media = iflib_get_media(ctx); @@ -1686,13 +1686,6 @@ em_if_timer(if_ctx_t ctx, uint16_t qid) return; iflib_admin_intr_deferred(ctx); - /* Reset LAA into RAR[0] on 82571 */ - if ((adapter->hw.mac.type == e1000_82571) && - e1000_get_laa_state_82571(&adapter->hw)) - e1000_rar_set(&adapter->hw, adapter->hw.mac.addr, 0); - - if (adapter->hw.mac.type < em_mac_min) - lem_smartspeed(adapter); /* Mask to use in the irq trigger */ if (adapter->intr_type == IFLIB_INTR_MSIX) { @@ -1803,6 +1796,14 @@ em_if_update_admin_status(if_ctx_t ctx) } em_update_stats_counters(adapter); + /* Reset LAA into RAR[0] on 82571 */ + if ((adapter->hw.mac.type == e1000_82571) && + e1000_get_laa_state_82571(&adapter->hw)) + e1000_rar_set(&adapter->hw, adapter->hw.mac.addr, 0); + + if (adapter->hw.mac.type < em_mac_min) + lem_smartspeed(adapter); + E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_LINK | E1000_IMS_LSC); } diff --git a/freebsd/sys/dev/e1000/igb_txrx.c b/freebsd/sys/dev/e1000/igb_txrx.c index 05b2fff2..3a56a496 100644 --- a/freebsd/sys/dev/e1000/igb_txrx.c +++ b/freebsd/sys/dev/e1000/igb_txrx.c @@ -64,14 +64,14 @@ extern void igb_if_enable_intr(if_ctx_t ctx); extern int em_intr(void *arg); struct if_txrx igb_txrx = { - igb_isc_txd_encap, - igb_isc_txd_flush, - igb_isc_txd_credits_update, - igb_isc_rxd_available, - igb_isc_rxd_pkt_get, - igb_isc_rxd_refill, - igb_isc_rxd_flush, - em_intr + .ift_txd_encap = igb_isc_txd_encap, + .ift_txd_flush = igb_isc_txd_flush, + .ift_txd_credits_update = igb_isc_txd_credits_update, + .ift_rxd_available = igb_isc_rxd_available, + .ift_rxd_pkt_get = igb_isc_rxd_pkt_get, + .ift_rxd_refill = igb_isc_rxd_refill, + .ift_rxd_flush = igb_isc_rxd_flush, + .ift_legacy_intr = em_intr }; extern if_shared_ctx_t em_sctx; diff --git a/freebsd/sys/dev/evdev/uinput.c b/freebsd/sys/dev/evdev/uinput.c index f1f812cc..3b332d1f 100644 --- a/freebsd/sys/dev/evdev/uinput.c +++ b/freebsd/sys/dev/evdev/uinput.c @@ -606,6 +606,15 @@ uinput_ioctl_sub(struct uinput_cdev_state *state, u_long cmd, caddr_t data) evdev_set_phys(state->ucs_evdev, buf); return (0); + case UI_SET_BSDUNIQ: + if (state->ucs_state == UINPUT_RUNNING) + return (EINVAL); + ret = copyinstr(*(void **)data, buf, sizeof(buf), NULL); + if (ret != 0) + return (ret); + evdev_set_serial(state->ucs_evdev, buf); + return (0); + case UI_SET_SWBIT: if (state->ucs_state == UINPUT_RUNNING || intdata > SW_MAX || intdata < 0) diff --git a/freebsd/sys/dev/evdev/uinput.h b/freebsd/sys/dev/evdev/uinput.h index dd4b0a82..d15b8945 100644 --- a/freebsd/sys/dev/evdev/uinput.h +++ b/freebsd/sys/dev/evdev/uinput.h @@ -90,6 +90,13 @@ struct uinput_abs_setup { #define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase) #define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase) +/* + * FreeBSD specific. Set unique identifier of input device. + * Name and magic are chosen to reduce chances of clashing + * with possible future Linux extensions. + */ +#define UI_SET_BSDUNIQ _IO(UINPUT_IOCTL_BASE, 109) + #define EV_UINPUT 0x0101 #define UI_FF_UPLOAD 1 #define UI_FF_ERASE 2 diff --git a/freebsd/sys/dev/fdt/fdt_common.c b/freebsd/sys/dev/fdt/fdt_common.c index de4a44b9..ff32dc0a 100644 --- a/freebsd/sys/dev/fdt/fdt_common.c +++ b/freebsd/sys/dev/fdt/fdt_common.c @@ -61,7 +61,6 @@ __FBSDID("$FreeBSD$"); #endif #define FDT_COMPAT_LEN 255 -#define FDT_TYPE_LEN 64 #define FDT_REG_CELLS 4 #define FDT_RANGES_SIZE 48 @@ -74,8 +73,6 @@ vm_offset_t fdt_immr_size; struct fdt_ic_list fdt_ic_list_head = SLIST_HEAD_INITIALIZER(fdt_ic_list_head); -static int fdt_is_compatible(phandle_t, const char *); - static int fdt_get_range_by_busaddr(phandle_t node, u_long addr, u_long *base, u_long *size) @@ -218,7 +215,7 @@ fdt_immr_addr(vm_offset_t immr_va) * Try to access the SOC node directly i.e. through /aliases/. */ if ((node = OF_finddevice("soc")) != -1) - if (fdt_is_compatible(node, "simple-bus")) + if (ofw_bus_node_is_compatible(node, "simple-bus")) goto moveon; /* * Find the node the long way. @@ -239,45 +236,6 @@ moveon: return (r); } -/* - * This routine is an early-usage version of the ofw_bus_is_compatible() when - * the ofw_bus I/F is not available (like early console routines and similar). - * Note the buffer has to be on the stack since malloc() is usually not - * available in such cases either. - */ -static int -fdt_is_compatible(phandle_t node, const char *compatstr) -{ - char buf[FDT_COMPAT_LEN]; - char *compat; - int len, onelen, l, rv; - - if ((len = OF_getproplen(node, "compatible")) <= 0) - return (0); - - compat = (char *)&buf; - bzero(compat, FDT_COMPAT_LEN); - - if (OF_getprop(node, "compatible", compat, FDT_COMPAT_LEN) < 0) - return (0); - - onelen = strlen(compatstr); - rv = 0; - while (len > 0) { - if (strncasecmp(compat, compatstr, onelen) == 0) { - /* Found it. */ - rv = 1; - break; - } - /* Slide to the next sub-string. */ - l = strlen(compat) + 1; - compat += l; - len -= l; - } - - return (rv); -} - int fdt_is_compatible_strict(phandle_t node, const char *compatible) { @@ -306,7 +264,7 @@ fdt_find_compatible(phandle_t start, const char *compat, int strict) * matching 'compatible' property. */ for (child = OF_child(start); child != 0; child = OF_peer(child)) - if (fdt_is_compatible(child, compat)) { + if (ofw_bus_node_is_compatible(child, compat)) { if (strict) if (!fdt_is_compatible_strict(child, compat)) continue; @@ -325,7 +283,7 @@ fdt_depth_search_compatible(phandle_t start, const char *compat, int strict) * matching 'compatible' property. */ for (node = OF_child(start); node != 0; node = OF_peer(node)) { - if (fdt_is_compatible(node, compat) && + if (ofw_bus_node_is_compatible(node, compat) && (strict == 0 || fdt_is_compatible_strict(node, compat))) { return (node); } @@ -337,46 +295,6 @@ fdt_depth_search_compatible(phandle_t start, const char *compat, int strict) } int -fdt_is_enabled(phandle_t node) -{ - char *stat; - int ena, len; - - len = OF_getprop_alloc(node, "status", sizeof(char), - (void **)&stat); - - if (len <= 0) - /* It is OK if no 'status' property. */ - return (1); - - /* Anything other than 'okay' means disabled. */ - ena = 0; - if (strncmp((char *)stat, "okay", len) == 0) - ena = 1; - - OF_prop_free(stat); - return (ena); -} - -int -fdt_is_type(phandle_t node, const char *typestr) -{ - char type[FDT_TYPE_LEN]; - - if (OF_getproplen(node, "device_type") <= 0) - return (0); - - if (OF_getprop(node, "device_type", type, FDT_TYPE_LEN) < 0) - return (0); - - if (strncasecmp(type, typestr, FDT_TYPE_LEN) == 0) - /* This fits. */ - return (1); - - return (0); -} - -int fdt_parent_addr_cells(phandle_t node) { pcell_t addr_cells; @@ -389,19 +307,6 @@ fdt_parent_addr_cells(phandle_t node) return ((int)fdt32_to_cpu(addr_cells)); } -int -fdt_pm_is_enabled(phandle_t node) -{ - int ret; - - ret = 1; - -#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) - ret = fdt_pm(node); -#endif - return (ret); -} - u_long fdt_data_get(void *data, int cells) { @@ -477,59 +382,6 @@ fdt_regsize(phandle_t node, u_long *base, u_long *size) } int -fdt_reg_to_rl(phandle_t node, struct resource_list *rl) -{ - u_long end, count, start; - pcell_t *reg, *regptr; - pcell_t addr_cells, size_cells; - int tuple_size, tuples; - int i, rv; - long busaddr, bussize; - - if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) - return (ENXIO); - if (fdt_get_range(OF_parent(node), 0, &busaddr, &bussize)) { - busaddr = 0; - bussize = 0; - } - - tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); - tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)®); - debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); - debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); - if (tuples <= 0) - /* No 'reg' property in this node. */ - return (0); - - regptr = reg; - for (i = 0; i < tuples; i++) { - - rv = fdt_data_to_res(reg, addr_cells, size_cells, &start, - &count); - if (rv != 0) { - resource_list_free(rl); - goto out; - } - reg += addr_cells + size_cells; - - /* Calculate address range relative to base. */ - start += busaddr; - end = start + count - 1; - - debugf("reg addr start = %lx, end = %lx, count = %lx\n", start, - end, count); - - resource_list_add(rl, SYS_RES_MEMORY, i, start, end, - count); - } - rv = 0; - -out: - OF_prop_free(regptr); - return (rv); -} - -int fdt_get_phyaddr(phandle_t node, device_t dev, int *phy_addr, void **phy_sc) { phandle_t phy_node; @@ -650,6 +502,47 @@ out: } int +fdt_get_reserved_mem(struct mem_region *reserved, int *mreserved) +{ + pcell_t reg[FDT_REG_CELLS]; + phandle_t child, root; + int addr_cells, size_cells; + int i, rv; + + root = OF_finddevice("/reserved-memory"); + if (root == -1) { + return (ENXIO); + } + + if ((rv = fdt_addrsize_cells(root, &addr_cells, &size_cells)) != 0) + return (rv); + + if (addr_cells + size_cells > FDT_REG_CELLS) + panic("Too many address and size cells %d %d", addr_cells, + size_cells); + + i = 0; + for (child = OF_child(root); child != 0; child = OF_peer(child)) { + if (!OF_hasprop(child, "no-map")) + continue; + + rv = OF_getprop(child, "reg", reg, sizeof(reg)); + if (rv <= 0) + /* XXX: Does a no-map of a dynamic range make sense? */ + continue; + + fdt_data_to_res(reg, addr_cells, size_cells, + (u_long *)&reserved[i].mr_start, + (u_long *)&reserved[i].mr_size); + i++; + } + + *mreserved = i; + + return (0); +} + +int fdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint64_t *memsize) { pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS]; @@ -715,17 +608,6 @@ out: } int -fdt_get_unit(device_t dev) -{ - const char * name; - - name = ofw_bus_get_name(dev); - name = strchr(name, '@') + 1; - - return (strtol(name,NULL,0)); -} - -int fdt_get_chosen_bootargs(char *bootargs, size_t max_size) { phandle_t chosen; diff --git a/freebsd/sys/dev/fdt/fdt_common.h b/freebsd/sys/dev/fdt/fdt_common.h index 91522df5..3bf4df41 100644 --- a/freebsd/sys/dev/fdt/fdt_common.h +++ b/freebsd/sys/dev/fdt/fdt_common.h @@ -39,7 +39,7 @@ #include <contrib/libfdt/libfdt_env.h> #include <dev/ofw/ofw_bus.h> -#define FDT_MEM_REGIONS 8 +#define FDT_MEM_REGIONS 16 #define DI_MAX_INTR_NUM 32 @@ -85,19 +85,14 @@ int fdt_data_to_res(pcell_t *, int, int, u_long *, u_long *); phandle_t fdt_find_compatible(phandle_t, const char *, int); phandle_t fdt_depth_search_compatible(phandle_t, const char *, int); int fdt_get_mem_regions(struct mem_region *, int *, uint64_t *); +int fdt_get_reserved_mem(struct mem_region *, int *); int fdt_get_reserved_regions(struct mem_region *, int *); int fdt_get_phyaddr(phandle_t, device_t, int *, void **); int fdt_get_range(phandle_t, int, u_long *, u_long *); int fdt_immr_addr(vm_offset_t); int fdt_regsize(phandle_t, u_long *, u_long *); int fdt_is_compatible_strict(phandle_t, const char *); -int fdt_is_enabled(phandle_t); -int fdt_pm_is_enabled(phandle_t); -int fdt_is_type(phandle_t, const char *); int fdt_parent_addr_cells(phandle_t); -int fdt_reg_to_rl(phandle_t, struct resource_list *); -int fdt_pm(phandle_t); -int fdt_get_unit(device_t); int fdt_get_chosen_bootargs(char *bootargs, size_t max_size); #endif /* _FDT_COMMON_H_ */ diff --git a/freebsd/sys/dev/ffec/if_ffec.c b/freebsd/sys/dev/ffec/if_ffec.c index 1d842286..03dca1a9 100644 --- a/freebsd/sys/dev/ffec/if_ffec.c +++ b/freebsd/sys/dev/ffec/if_ffec.c @@ -1093,7 +1093,7 @@ ffec_setup_rxfilter(struct ffec_softc *sc) else { ghash = 0; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; /* 6 bits from MSB in LE CRC32 are used for hash. */ diff --git a/freebsd/sys/dev/gpio/ofw_gpiobus.c b/freebsd/sys/dev/gpio/ofw_gpiobus.c index 1a87121c..ac0ea9bf 100644 --- a/freebsd/sys/dev/gpio/ofw_gpiobus.c +++ b/freebsd/sys/dev/gpio/ofw_gpiobus.c @@ -370,7 +370,7 @@ ofw_gpiobus_parse_gpios_impl(device_t consumer, phandle_t cnode, char *pname, pcell_t *gpios; phandle_t gpio; - ncells = OF_getencprop_alloc(cnode, pname, sizeof(*gpios), + ncells = OF_getencprop_alloc_multi(cnode, pname, sizeof(*gpios), (void **)&gpios); if (ncells == -1) { device_printf(consumer, diff --git a/freebsd/sys/dev/mmc/mmcreg.h b/freebsd/sys/dev/mmc/mmcreg.h index 5f58ce3f..4b1f8a0e 100644 --- a/freebsd/sys/dev/mmc/mmcreg.h +++ b/freebsd/sys/dev/mmc/mmcreg.h @@ -162,34 +162,35 @@ struct mmc_command { #define R1_STATE_PRG 7 #define R1_STATE_DIS 8 -/* R4 response (SDIO) */ -#define R4_IO_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x3) -#define R4_IO_MEM_PRESENT (0x1<<27) -#define R4_IO_OCR_MASK 0x00fffff0 +/* R4 responses (SDIO) */ +#define R4_IO_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x3) +#define R4_IO_MEM_PRESENT (0x1 << 27) +#define R4_IO_OCR_MASK 0x00fffff0 /* * R5 responses * * Types (per SD 2.0 standard) - *e : error bit - *s : status bit - *r : detected and set for the actual command response - *x : Detected and set during command execution. The host can get - * the status by issuing a command with R1 response. + * e : error bit + * s : status bit + * r : detected and set for the actual command response + * x : Detected and set during command execution. The host can get + * the status by issuing a command with R1 response. * * Clear Condition (per SD 2.0 standard) - *a : according to the card current state. - *b : always related to the previous command. reception of a valid - * command will clear it (with a delay of one command). - *c : clear by read + * a : according to the card current state. + * b : always related to the previous command. reception of a valid + * command will clear it (with a delay of one command). + * c : clear by read */ -#define R5_COM_CRC_ERROR (1u << 15)/* er, b */ -#define R5_ILLEGAL_COMMAND (1u << 14)/* er, b */ -#define R5_IO_CURRENT_STATE_MASK (3u << 12)/* s, b */ -#define R5_IO_CURRENT_STATE(x) (((x) & R5_IO_CURRENT_STATE_MASK) >> 12) -#define R5_ERROR (1u << 11)/* erx, c */ -#define R5_FUNCTION_NUMBER (1u << 9)/* er, c */ -#define R5_OUT_OF_RANGE (1u << 8)/* er, c */ +#define R5_COM_CRC_ERROR (1u << 15) /* er, b */ +#define R5_ILLEGAL_COMMAND (1u << 14) /* er, b */ +#define R5_IO_CURRENT_STATE_MASK (3u << 12) /* s, b */ +#define R5_IO_CURRENT_STATE(x) (((x) & R5_IO_CURRENT_STATE_MASK) >> 12) +#define R5_ERROR (1u << 11) /* erx, c */ +#define R5_FUNCTION_NUMBER (1u << 9) /* er, c */ +#define R5_OUT_OF_RANGE (1u << 8) /* er, c */ + struct mmc_data { size_t len; /* size of the data */ size_t xfer_len; @@ -227,7 +228,7 @@ struct mmc_request { #define SD_SEND_RELATIVE_ADDR 3 #define MMC_SET_DSR 4 #define MMC_SLEEP_AWAKE 5 -#define IO_SEND_OP_COND 5 +#define IO_SEND_OP_COND 5 #define MMC_SWITCH_FUNC 6 #define MMC_SWITCH_FUNC_CMDS 0 #define MMC_SWITCH_FUNC_SET 1 @@ -318,30 +319,30 @@ struct mmc_request { /* Class 9: I/O cards (sd) */ #define SD_IO_RW_DIRECT 52 /* CMD52 arguments */ -#define SD_ARG_CMD52_READ (0<<31) -#define SD_ARG_CMD52_WRITE (1<<31) -#define SD_ARG_CMD52_FUNC_SHIFT 28 -#define SD_ARG_CMD52_FUNC_MASK 0x7 -#define SD_ARG_CMD52_EXCHANGE (1<<27) -#define SD_ARG_CMD52_REG_SHIFT 9 -#define SD_ARG_CMD52_REG_MASK 0x1ffff -#define SD_ARG_CMD52_DATA_SHIFT 0 -#define SD_ARG_CMD52_DATA_MASK 0xff -#define SD_R5_DATA(resp) ((resp)[0] & 0xff) +#define SD_ARG_CMD52_READ (0 << 31) +#define SD_ARG_CMD52_WRITE (1 << 31) +#define SD_ARG_CMD52_FUNC_SHIFT 28 +#define SD_ARG_CMD52_FUNC_MASK 0x7 +#define SD_ARG_CMD52_EXCHANGE (1 << 27) +#define SD_ARG_CMD52_REG_SHIFT 9 +#define SD_ARG_CMD52_REG_MASK 0x1ffff +#define SD_ARG_CMD52_DATA_SHIFT 0 +#define SD_ARG_CMD52_DATA_MASK 0xff +#define SD_R5_DATA(resp) ((resp)[0] & 0xff) #define SD_IO_RW_EXTENDED 53 /* CMD53 arguments */ -#define SD_ARG_CMD53_READ (0<<31) -#define SD_ARG_CMD53_WRITE (1<<31) -#define SD_ARG_CMD53_FUNC_SHIFT 28 -#define SD_ARG_CMD53_FUNC_MASK 0x7 -#define SD_ARG_CMD53_BLOCK_MODE (1<<27) -#define SD_ARG_CMD53_INCREMENT (1<<26) -#define SD_ARG_CMD53_REG_SHIFT 9 -#define SD_ARG_CMD53_REG_MASK 0x1ffff -#define SD_ARG_CMD53_LENGTH_SHIFT 0 -#define SD_ARG_CMD53_LENGTH_MASK 0x1ff -#define SD_ARG_CMD53_LENGTH_MAX 64 /* XXX should be 511? */ +#define SD_ARG_CMD53_READ (0 << 31) +#define SD_ARG_CMD53_WRITE (1 << 31) +#define SD_ARG_CMD53_FUNC_SHIFT 28 +#define SD_ARG_CMD53_FUNC_MASK 0x7 +#define SD_ARG_CMD53_BLOCK_MODE (1 << 27) +#define SD_ARG_CMD53_INCREMENT (1 << 26) +#define SD_ARG_CMD53_REG_SHIFT 9 +#define SD_ARG_CMD53_REG_MASK 0x1ffff +#define SD_ARG_CMD53_LENGTH_SHIFT 0 +#define SD_ARG_CMD53_LENGTH_MASK 0x1ff +#define SD_ARG_CMD53_LENGTH_MAX 64 /* XXX should be 511? */ /* Class 10: Switch function commands */ #define SD_SWITCH_FUNC 6 @@ -364,6 +365,8 @@ struct mmc_request { /* * EXT_CSD fields */ +#define EXT_CSD_FLUSH_CACHE 32 /* W/E */ +#define EXT_CSD_CACHE_CTRL 33 /* R/W/E */ #define EXT_CSD_EXT_PART_ATTR 52 /* R/W, 2 bytes */ #define EXT_CSD_ENH_START_ADDR 136 /* R/W, 4 bytes */ #define EXT_CSD_ENH_SIZE_MULT 140 /* R/W, 3 bytes */ @@ -397,12 +400,19 @@ struct mmc_request { #define EXT_CSD_PWR_CL_200_360 237 /* RO */ #define EXT_CSD_PWR_CL_52_195_DDR 238 /* RO */ #define EXT_CSD_PWR_CL_52_360_DDR 239 /* RO */ +#define EXT_CSD_CACHE_FLUSH_POLICY 249 /* RO */ #define EXT_CSD_GEN_CMD6_TIME 248 /* RO */ +#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ #define EXT_CSD_PWR_CL_200_360_DDR 253 /* RO */ /* * EXT_CSD field definitions */ +#define EXT_CSD_FLUSH_CACHE_FLUSH 0x01 +#define EXT_CSD_FLUSH_CACHE_BARRIER 0x02 + +#define EXT_CSD_CACHE_CTRL_CACHE_EN 0x01 + #define EXT_CSD_EXT_PART_ATTR_DEFAULT 0x0 #define EXT_CSD_EXT_PART_ATTR_SYSTEMCODE 0x1 #define EXT_CSD_EXT_PART_ATTR_NPERSISTENT 0x2 @@ -482,6 +492,8 @@ struct mmc_request { #define EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN 0x10 #define EXT_CSD_SEC_FEATURE_SUPPORT_SANITIZE 0x40 +#define EXT_CSD_CACHE_FLUSH_POLICY_FIFO 0x01 + /* * Vendor specific EXT_CSD fields */ @@ -533,50 +545,50 @@ struct mmc_request { /* * SDIO Direct & Extended I/O */ -#define SD_IO_RW_WR (1u << 31) -#define SD_IO_RW_FUNC(x) (((x) & 0x7) << 28) -#define SD_IO_RW_RAW (1u << 27) -#define SD_IO_RW_INCR (1u << 26) -#define SD_IO_RW_ADR(x) (((x) & 0x1FFFF) << 9) -#define SD_IO_RW_DAT(x) (((x) & 0xFF) << 0) -#define SD_IO_RW_LEN(x) (((x) & 0xFF) << 0) +#define SD_IO_RW_WR (1u << 31) +#define SD_IO_RW_FUNC(x) (((x) & 0x7) << 28) +#define SD_IO_RW_RAW (1u << 27) +#define SD_IO_RW_INCR (1u << 26) +#define SD_IO_RW_ADR(x) (((x) & 0x1FFFF) << 9) +#define SD_IO_RW_DAT(x) (((x) & 0xFF) << 0) +#define SD_IO_RW_LEN(x) (((x) & 0xFF) << 0) -#define SD_IOE_RW_LEN(x) (((x) & 0x1FF) << 0) -#define SD_IOE_RW_BLK (1u << 27) +#define SD_IOE_RW_LEN(x) (((x) & 0x1FF) << 0) +#define SD_IOE_RW_BLK (1u << 27) /* Card Common Control Registers (CCCR) */ -#define SD_IO_CCCR_START 0x00000 -#define SD_IO_CCCR_SIZE 0x100 -#define SD_IO_CCCR_FN_ENABLE 0x02 -#define SD_IO_CCCR_FN_READY 0x03 -#define SD_IO_CCCR_INT_ENABLE 0x04 -#define SD_IO_CCCR_INT_PENDING 0x05 -#define SD_IO_CCCR_CTL 0x06 -#define CCCR_CTL_RES (1<<3) -#define SD_IO_CCCR_BUS_WIDTH 0x07 -#define CCCR_BUS_WIDTH_4 (1<<1) -#define CCCR_BUS_WIDTH_1 (1<<0) -#define SD_IO_CCCR_CARDCAP 0x08 -#define SD_IO_CCCR_CISPTR 0x09 /* XXX 9-10, 10-11, or 9-12 */ +#define SD_IO_CCCR_START 0x00000 +#define SD_IO_CCCR_SIZE 0x100 +#define SD_IO_CCCR_FN_ENABLE 0x02 +#define SD_IO_CCCR_FN_READY 0x03 +#define SD_IO_CCCR_INT_ENABLE 0x04 +#define SD_IO_CCCR_INT_PENDING 0x05 +#define SD_IO_CCCR_CTL 0x06 +#define CCCR_CTL_RES (1 << 3) +#define SD_IO_CCCR_BUS_WIDTH 0x07 +#define CCCR_BUS_WIDTH_4 (1 << 1) +#define CCCR_BUS_WIDTH_1 (1 << 0) +#define SD_IO_CCCR_CARDCAP 0x08 +#define SD_IO_CCCR_CISPTR 0x09 /* XXX 9-10, 10-11, or 9-12 */ /* Function Basic Registers (FBR) */ -#define SD_IO_FBR_START 0x00100 -#define SD_IO_FBR_SIZE 0x00700 +#define SD_IO_FBR_START 0x00100 +#define SD_IO_FBR_SIZE 0x00700 /* Card Information Structure (CIS) */ -#define SD_IO_CIS_START 0x01000 -#define SD_IO_CIS_SIZE 0x17000 +#define SD_IO_CIS_START 0x01000 +#define SD_IO_CIS_SIZE 0x17000 /* CIS tuple codes (based on PC Card 16) */ -#define SD_IO_CISTPL_VERS_1 0x15 -#define SD_IO_CISTPL_MANFID 0x20 -#define SD_IO_CISTPL_FUNCID 0x21 -#define SD_IO_CISTPL_FUNCE 0x22 -#define SD_IO_CISTPL_END 0xff +#define SD_IO_CISTPL_VERS_1 0x15 +#define SD_IO_CISTPL_MANFID 0x20 +#define SD_IO_CISTPL_FUNCID 0x21 +#define SD_IO_CISTPL_FUNCE 0x22 +#define SD_IO_CISTPL_END 0xff /* CISTPL_FUNCID codes */ /* OpenBSD incorrectly defines 0x0c as FUNCTION_WLAN */ -/* #define SDMMC_FUNCTION_WLAN 0x0c */ +/* #define SDMMC_FUNCTION_WLAN 0x0c */ /* OCR bits */ diff --git a/freebsd/sys/dev/mmc/mmcsd.c b/freebsd/sys/dev/mmc/mmcsd.c index 94e6e73f..263da55d 100644 --- a/freebsd/sys/dev/mmc/mmcsd.c +++ b/freebsd/sys/dev/mmc/mmcsd.c @@ -71,7 +71,9 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/module.h> #include <sys/mutex.h> +#include <sys/priv.h> #include <sys/slicer.h> +#include <sys/sysctl.h> #include <sys/time.h> #include <geom/geom.h> @@ -142,6 +144,8 @@ struct mmcsd_softc { uint32_t flags; #define MMCSD_INAND_CMD38 0x0001 #define MMCSD_USE_TRIM 0x0002 +#define MMCSD_FLUSH_CACHE 0x0004 +#define MMCSD_DIRTY 0x0008 uint32_t cmd6_time; /* Generic switch timeout [us] */ uint32_t part_time; /* Partition switch timeout [us] */ off_t enh_base; /* Enhanced user data area slice base ... */ @@ -166,12 +170,19 @@ static const char * const errmsg[] = "NO MEMORY" }; +static SYSCTL_NODE(_hw, OID_AUTO, mmcsd, CTLFLAG_RD, NULL, "mmcsd driver"); + +static int mmcsd_cache = 1; +SYSCTL_INT(_hw_mmcsd, OID_AUTO, cache, CTLFLAG_RDTUN, &mmcsd_cache, 0, + "Device R/W cache enabled if present"); + #define LOG_PPS 5 /* Log no more than 5 errors per second. */ /* bus entry points */ static int mmcsd_attach(device_t dev); static int mmcsd_detach(device_t dev); static int mmcsd_probe(device_t dev); +static int mmcsd_shutdown(device_t dev); #ifndef __rtems__ /* disk routines */ @@ -181,7 +192,6 @@ static int mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, static int mmcsd_getattr(struct bio *); static int mmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data, int fflag, struct thread *td); -static int mmcsd_open(struct disk *dp); static void mmcsd_strategy(struct bio *bp); static void mmcsd_task(void *arg); #endif /* __rtems__ */ @@ -197,8 +207,12 @@ static int mmcsd_bus_bit_width(device_t dev); static daddr_t mmcsd_delete(struct mmcsd_part *part, struct bio *bp); #endif /* __rtems__ */ static const char *mmcsd_errmsg(int e); +#ifndef __rtems__ +static int mmcsd_flush_cache(struct mmcsd_softc *sc); +#endif /* __rtems__ */ +static const char *mmcsd_errmsg(int e); static int mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, - int fflag); + int fflag, struct thread *td); static int mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag); static uintmax_t mmcsd_pretty_size(off_t size, char *unit); @@ -523,6 +537,31 @@ mmcsd_attach(device_t dev) rev = ext_csd[EXT_CSD_REV]; /* + * With revision 1.5 (MMC v4.5, EXT_CSD_REV == 6) and later, take + * advantage of the device R/W cache if present and useage is not + * disabled. + */ + if (rev >= 6 && mmcsd_cache != 0) { + size = ext_csd[EXT_CSD_CACHE_SIZE] | + ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 | + ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 | + ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24; + if (bootverbose) + device_printf(dev, "cache size %juKB\n", size); + if (size > 0) { + MMCBUS_ACQUIRE_BUS(mmcbus, dev); + err = mmc_switch(mmcbus, dev, sc->rca, + EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CACHE_CTRL, + EXT_CSD_CACHE_CTRL_CACHE_EN, sc->cmd6_time, true); + MMCBUS_RELEASE_BUS(mmcbus, dev); + if (err != MMC_ERR_NONE) + device_printf(dev, "failed to enable cache\n"); + else + sc->flags |= MMCSD_FLUSH_CACHE; + } + } + + /* * Ignore user-creatable enhanced user data area and general purpose * partitions partitions as long as partitioning hasn't been finished. */ @@ -734,7 +773,6 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt, #ifndef __rtems__ d = part->disk = disk_alloc(); - d->d_open = mmcsd_open; d->d_close = mmcsd_close; d->d_strategy = mmcsd_strategy; d->d_ioctl = mmcsd_ioctl_disk; @@ -748,6 +786,8 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt, d->d_stripesize = sc->erase_sector * d->d_sectorsize; d->d_unit = cnt; d->d_flags = DISKFLAG_CANDELETE; + if ((sc->flags & MMCSD_FLUSH_CACHE) != 0) + d->d_flags |= DISKFLAG_CANFLUSHCACHE; d->d_delmaxsize = mmc_get_erase_sector(dev) * d->d_sectorsize; strlcpy(d->d_ident, mmc_get_card_sn_string(dev), sizeof(d->d_ident)); @@ -908,6 +948,22 @@ mmcsd_detach(device_t dev) free(part, M_DEVBUF); } } + if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) + device_printf(dev, "failed to flush cache\n"); +#else /* __rtems__ */ + BSD_PANIC("FIXME"); +#endif /* __rtems__ */ + return (0); +} + +static int +mmcsd_shutdown(device_t dev) +{ +#ifndef __rtems__ + struct mmcsd_softc *sc = device_get_softc(dev); + + if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) + device_printf(dev, "failed to flush cache\n"); #else /* __rtems__ */ BSD_PANIC("FIXME"); #endif /* __rtems__ */ @@ -947,6 +1003,8 @@ mmcsd_suspend(device_t dev) MMCSD_IOCTL_UNLOCK(part); } } + if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) + device_printf(dev, "failed to flush cache\n"); #else /* __rtems__ */ BSD_PANIC("FIXME"); #endif /* __rtems__ */ @@ -989,16 +1047,15 @@ mmcsd_resume(device_t dev) #ifndef __rtems__ static int -mmcsd_open(struct disk *dp __unused) -{ - - return (0); -} - -static int -mmcsd_close(struct disk *dp __unused) +mmcsd_close(struct disk *dp) { + struct mmcsd_softc *sc; + if ((dp->d_flags & DISKFLAG_OPEN) != 0) { + sc = ((struct mmcsd_part *)dp->d_drv1)->sc; + if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) + device_printf(sc->dev, "failed to flush cache\n"); + } return (0); } @@ -1022,24 +1079,25 @@ mmcsd_strategy(struct bio *bp) static int mmcsd_ioctl_rpmb(struct cdev *dev, u_long cmd, caddr_t data, - int fflag, struct thread *td __unused) + int fflag, struct thread *td) { - return (mmcsd_ioctl(dev->si_drv1, cmd, data, fflag)); + return (mmcsd_ioctl(dev->si_drv1, cmd, data, fflag, td)); } #ifndef __rtems__ static int mmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data, int fflag, - struct thread *td __unused) + struct thread *td) { - return (mmcsd_ioctl(disk->d_drv1, cmd, data, fflag)); + return (mmcsd_ioctl(disk->d_drv1, cmd, data, fflag, td)); } #endif /* __rtems__ */ static int -mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag) +mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag, + struct thread *td) { struct mmc_ioc_cmd *mic; struct mmc_ioc_multi_cmd *mimc; @@ -1049,6 +1107,10 @@ mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag) if ((fflag & FREAD) == 0) return (EBADF); + err = priv_check(td, PRIV_DRIVER); + if (err != 0) + return (err); + err = 0; switch (cmd) { case MMC_IOC_CMD: @@ -1190,6 +1252,8 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag) if (err != MMC_ERR_NONE) goto switch_back; } + if (mic->write_flag != 0) + sc->flags |= MMCSD_DIRTY; if (mic->is_acmd != 0) (void)mmc_wait_for_app_cmd(mmcbus, dev, rca, &cmd, 0); else @@ -1405,6 +1469,7 @@ mmcsd_rw(struct mmcsd_part *part, struct bio *bp) else cmd.opcode = MMC_READ_SINGLE_BLOCK; } else { + sc->flags |= MMCSD_DIRTY; if (numblocks > 1) cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK; else @@ -1590,13 +1655,18 @@ mmcsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, device_t dev, mmcbus; int err; - /* length zero is special and really means flush buffers to media */ - if (!length) - return (0); - disk = arg; part = disk->d_drv1; sc = part->sc; + + /* length zero is special and really means flush buffers to media */ + if (length == 0) { + err = mmcsd_flush_cache(sc); + if (err != MMC_ERR_NONE) + return (EIO); + return (0); + } + dev = sc->dev; mmcbus = sc->mmcbus; @@ -1646,6 +1716,14 @@ mmcsd_task(void *arg) "mmcsd disk jobqueue", 0); } while (bp == NULL); MMCSD_DISK_UNLOCK(part); + if (__predict_false(bp->bio_cmd == BIO_FLUSH)) { + if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) { + bp->bio_error = EIO; + bp->bio_flags |= BIO_ERROR; + } + biodone(bp); + continue; + } if (bp->bio_cmd != BIO_READ && part->ro) { bp->bio_error = EROFS; bp->bio_resid = bp->bio_bcount; @@ -1704,10 +1782,37 @@ mmcsd_bus_bit_width(device_t dev) return (8); } +#ifndef __rtems__ +static int +mmcsd_flush_cache(struct mmcsd_softc *sc) +{ + device_t dev, mmcbus; + int err; + + if ((sc->flags & MMCSD_FLUSH_CACHE) == 0) + return (MMC_ERR_NONE); + + dev = sc->dev; + mmcbus = sc->mmcbus; + MMCBUS_ACQUIRE_BUS(mmcbus, dev); + if ((sc->flags & MMCSD_DIRTY) == 0) { + MMCBUS_RELEASE_BUS(mmcbus, dev); + return (MMC_ERR_NONE); + } + err = mmc_switch(mmcbus, dev, sc->rca, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_FLUSH_CACHE, EXT_CSD_FLUSH_CACHE_FLUSH, 60 * 1000, true); + if (err == MMC_ERR_NONE) + sc->flags &= ~MMCSD_DIRTY; + MMCBUS_RELEASE_BUS(mmcbus, dev); + return (err); +} +#endif /* __rtems__ */ + static device_method_t mmcsd_methods[] = { DEVMETHOD(device_probe, mmcsd_probe), DEVMETHOD(device_attach, mmcsd_attach), DEVMETHOD(device_detach, mmcsd_detach), + DEVMETHOD(device_shutdown, mmcsd_shutdown), DEVMETHOD(device_suspend, mmcsd_suspend), DEVMETHOD(device_resume, mmcsd_resume), DEVMETHOD_END diff --git a/freebsd/sys/dev/nvme/nvme.h b/freebsd/sys/dev/nvme/nvme.h index b51b4a97..169f22d1 100644 --- a/freebsd/sys/dev/nvme/nvme.h +++ b/freebsd/sys/dev/nvme/nvme.h @@ -115,7 +115,7 @@ #define NVME_CMD_FUSE_SHIFT (8) #define NVME_CMD_FUSE_MASK (0x3) -#define NVME_CMD_SET_OPC(opc) (htole16(((opc) & NVME_CMD_OPC_MASK) << NVME_CMD_OPC_SHIFT)) +#define NVME_CMD_SET_OPC(opc) (htole16(((uint16_t)(opc) & NVME_CMD_OPC_MASK) << NVME_CMD_OPC_SHIFT)) #define NVME_STATUS_P_SHIFT (0) #define NVME_STATUS_P_MASK (0x1) @@ -1091,6 +1091,12 @@ struct nvme_firmware_page { _Static_assert(sizeof(struct nvme_firmware_page) == 512, "bad size for nvme_firmware_page"); +struct nvme_ns_list { + uint32_t ns[1024]; +} __packed __aligned(4); + +_Static_assert(sizeof(struct nvme_ns_list) == 4096, "bad size for nvme_ns_list"); + struct intel_log_temp_stats { uint64_t current; @@ -1470,6 +1476,15 @@ void nvme_firmware_page_swapbytes(struct nvme_firmware_page *s) } static inline +void nvme_ns_list_swapbytes(struct nvme_ns_list *s) +{ + int i; + + for (i = 0; i < 1024; i++) + s->ns[i] = le32toh(s->ns[i]); +} + +static inline void intel_log_temp_stats_swapbytes(struct intel_log_temp_stats *s) { diff --git a/freebsd/sys/dev/ofw/ofw_bus_subr.c b/freebsd/sys/dev/ofw/ofw_bus_subr.c index 8406988f..5038bb03 100644 --- a/freebsd/sys/dev/ofw/ofw_bus_subr.c +++ b/freebsd/sys/dev/ofw/ofw_bus_subr.c @@ -59,12 +59,12 @@ ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *obd, phandle_t node) if (obd == NULL) return (ENOMEM); /* The 'name' property is considered mandatory. */ - if ((OF_getprop_alloc(node, "name", 1, (void **)&obd->obd_name)) == -1) + if ((OF_getprop_alloc(node, "name", (void **)&obd->obd_name)) == -1) return (EINVAL); - OF_getprop_alloc(node, "compatible", 1, (void **)&obd->obd_compat); - OF_getprop_alloc(node, "device_type", 1, (void **)&obd->obd_type); - OF_getprop_alloc(node, "model", 1, (void **)&obd->obd_model); - OF_getprop_alloc(node, "status", 1, (void **)&obd->obd_status); + OF_getprop_alloc(node, "compatible", (void **)&obd->obd_compat); + OF_getprop_alloc(node, "device_type", (void **)&obd->obd_type); + OF_getprop_alloc(node, "model", (void **)&obd->obd_model); + OF_getprop_alloc(node, "status", (void **)&obd->obd_status); obd->obd_node = node; return (0); } @@ -321,10 +321,10 @@ ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz) addrc = 2; ii->opi_addrc = addrc * sizeof(pcell_t); - ii->opi_imapsz = OF_getencprop_alloc(node, "interrupt-map", 1, + ii->opi_imapsz = OF_getencprop_alloc(node, "interrupt-map", (void **)&ii->opi_imap); if (ii->opi_imapsz > 0) { - msksz = OF_getencprop_alloc(node, "interrupt-map-mask", 1, + msksz = OF_getencprop_alloc(node, "interrupt-map-mask", (void **)&ii->opi_imapmsk); /* * Failure to get the mask is ignored; a full mask is used @@ -451,7 +451,8 @@ ofw_bus_msimap(phandle_t node, uint16_t pci_rid, phandle_t *msi_parent, int err, i; /* TODO: This should be OF_searchprop_alloc if we had it */ - len = OF_getencprop_alloc(node, "msi-map", sizeof(*map), (void **)&map); + len = OF_getencprop_alloc_multi(node, "msi-map", sizeof(*map), + (void **)&map); if (len < 0) { if (msi_parent != NULL) { *msi_parent = 0; @@ -491,9 +492,9 @@ ofw_bus_msimap(phandle_t node, uint16_t pci_rid, phandle_t *msi_parent, return (err); } -int -ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, - struct resource_list *rl) +static int +ofw_bus_reg_to_rl_helper(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, + struct resource_list *rl, const char *reg_source) { uint64_t phys, size; ssize_t i, j, rid, nreg, ret; @@ -504,11 +505,12 @@ ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, * This may be just redundant when having ofw_bus_devinfo * but makes this routine independent of it. */ - ret = OF_getprop_alloc(node, "name", sizeof(*name), (void **)&name); + ret = OF_getprop_alloc(node, "name", (void **)&name); if (ret == -1) name = NULL; - ret = OF_getencprop_alloc(node, "reg", sizeof(*reg), (void **)®); + ret = OF_getencprop_alloc_multi(node, reg_source, sizeof(*reg), + (void **)®); nreg = (ret == -1) ? 0 : ret; if (nreg % (acells + scells) != 0) { @@ -539,6 +541,23 @@ ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, return (0); } +int +ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, + struct resource_list *rl) +{ + + return (ofw_bus_reg_to_rl_helper(dev, node, acells, scells, rl, "reg")); +} + +int +ofw_bus_assigned_addresses_to_rl(device_t dev, phandle_t node, pcell_t acells, + pcell_t scells, struct resource_list *rl) +{ + + return (ofw_bus_reg_to_rl_helper(dev, node, acells, scells, + rl, "assigned-addresses")); +} + /* * Get interrupt parent for given node. * Returns 0 if interrupt parent doesn't exist. @@ -569,7 +588,7 @@ ofw_bus_intr_to_rl(device_t dev, phandle_t node, int err, i, irqnum, nintr, rid; boolean_t extended; - nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr), + nintr = OF_getencprop_alloc_multi(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { iparent = ofw_bus_find_iparent(node); @@ -592,7 +611,7 @@ ofw_bus_intr_to_rl(device_t dev, phandle_t node, } extended = false; } else { - nintr = OF_getencprop_alloc(node, "interrupts-extended", + nintr = OF_getencprop_alloc_multi(node, "interrupts-extended", sizeof(*intr), (void **)&intr); if (nintr <= 0) return (0); @@ -635,7 +654,7 @@ ofw_bus_intr_by_rid(device_t dev, phandle_t node, int wanted_rid, int err, i, nintr, rid; boolean_t extended; - nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr), + nintr = OF_getencprop_alloc_multi(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { iparent = ofw_bus_find_iparent(node); @@ -658,7 +677,7 @@ ofw_bus_intr_by_rid(device_t dev, phandle_t node, int wanted_rid, } extended = false; } else { - nintr = OF_getencprop_alloc(node, "interrupts-extended", + nintr = OF_getencprop_alloc_multi(node, "interrupts-extended", sizeof(*intr), (void **)&intr); if (nintr <= 0) return (ESRCH); @@ -705,7 +724,7 @@ ofw_bus_find_child(phandle_t start, const char *child_name) phandle_t child; for (child = OF_child(start); child != 0; child = OF_peer(child)) { - ret = OF_getprop_alloc(child, "name", sizeof(*name), (void **)&name); + ret = OF_getprop_alloc(child, "name", (void **)&name); if (ret == -1) continue; if (strcmp(name, child_name) == 0) { @@ -806,7 +825,7 @@ ofw_bus_parse_xref_list_internal(phandle_t node, const char *list_name, int rv, i, j, nelems, cnt; elems = NULL; - nelems = OF_getencprop_alloc(node, list_name, sizeof(*elems), + nelems = OF_getencprop_alloc_multi(node, list_name, sizeof(*elems), (void **)&elems); if (nelems <= 0) return (ENOENT); @@ -901,7 +920,7 @@ ofw_bus_find_string_index(phandle_t node, const char *list_name, int rv, i, cnt, nelems; elems = NULL; - nelems = OF_getprop_alloc(node, list_name, 1, (void **)&elems); + nelems = OF_getprop_alloc(node, list_name, (void **)&elems); if (nelems <= 0) return (ENOENT); @@ -932,7 +951,7 @@ ofw_bus_string_list_to_array(phandle_t node, const char *list_name, int i, cnt, nelems, len; elems = NULL; - nelems = OF_getprop_alloc(node, list_name, 1, (void **)&elems); + nelems = OF_getprop_alloc(node, list_name, (void **)&elems); if (nelems <= 0) return (nelems); diff --git a/freebsd/sys/dev/ofw/ofw_bus_subr.h b/freebsd/sys/dev/ofw/ofw_bus_subr.h index 04f5a75b..7bf66a10 100644 --- a/freebsd/sys/dev/ofw/ofw_bus_subr.h +++ b/freebsd/sys/dev/ofw/ofw_bus_subr.h @@ -95,6 +95,8 @@ int ofw_bus_msimap(phandle_t, uint16_t, phandle_t *, uint32_t *); /* Routines for parsing device-tree data into resource lists. */ int ofw_bus_reg_to_rl(device_t, phandle_t, pcell_t, pcell_t, struct resource_list *); +int ofw_bus_assigned_addresses_to_rl(device_t, phandle_t, pcell_t, pcell_t, + struct resource_list *); int ofw_bus_intr_to_rl(device_t, phandle_t, struct resource_list *, int *); int ofw_bus_intr_by_rid(device_t, phandle_t, int, phandle_t *, int *, pcell_t **); diff --git a/freebsd/sys/dev/ofw/ofw_fdt.c b/freebsd/sys/dev/ofw/ofw_fdt.c index 8878b5c9..b1bbadee 100644 --- a/freebsd/sys/dev/ofw/ofw_fdt.c +++ b/freebsd/sys/dev/ofw/ofw_fdt.c @@ -134,7 +134,7 @@ sysctl_register_fdt_oid(void *arg) CTLTYPE_OPAQUE | CTLFLAG_RD, NULL, 0, sysctl_handle_dtb, "", "Device Tree Blob"); } -SYSINIT(dtb_oid, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_fdt_oid, 0); +SYSINIT(dtb_oid, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_fdt_oid, NULL); static int ofw_fdt_init(ofw_t ofw, void *data) diff --git a/freebsd/sys/dev/ofw/openfirm.c b/freebsd/sys/dev/ofw/openfirm.c index 406e8dd6..9cc7dbdc 100644 --- a/freebsd/sys/dev/ofw/openfirm.c +++ b/freebsd/sys/dev/ofw/openfirm.c @@ -442,7 +442,7 @@ OF_searchprop(phandle_t node, const char *propname, void *buf, size_t len) } ssize_t -OF_searchencprop(phandle_t node, const char *propname, void *buf, size_t len) +OF_searchencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len) { ssize_t rv; @@ -454,11 +454,35 @@ OF_searchencprop(phandle_t node, const char *propname, void *buf, size_t len) /* * Store the value of a property of a package into newly allocated memory + * (using the M_OFWPROP malloc pool and M_WAITOK). + */ +ssize_t +OF_getprop_alloc(phandle_t package, const char *propname, void **buf) +{ + int len; + + *buf = NULL; + if ((len = OF_getproplen(package, propname)) == -1) + return (-1); + + if (len > 0) { + *buf = malloc(len, M_OFWPROP, M_WAITOK); + if (OF_getprop(package, propname, *buf, len) == -1) { + free(*buf, M_OFWPROP); + *buf = NULL; + return (-1); + } + } + return (len); +} + +/* + * Store the value of a property of a package into newly allocated memory * (using the M_OFWPROP malloc pool and M_WAITOK). elsz is the size of a * single element, the number of elements is return in number. */ ssize_t -OF_getprop_alloc(phandle_t package, const char *propname, int elsz, void **buf) +OF_getprop_alloc_multi(phandle_t package, const char *propname, int elsz, void **buf) { int len; @@ -467,30 +491,41 @@ OF_getprop_alloc(phandle_t package, const char *propname, int elsz, void **buf) len % elsz != 0) return (-1); - *buf = malloc(len, M_OFWPROP, M_WAITOK); - if (OF_getprop(package, propname, *buf, len) == -1) { - free(*buf, M_OFWPROP); - *buf = NULL; - return (-1); + if (len > 0) { + *buf = malloc(len, M_OFWPROP, M_WAITOK); + if (OF_getprop(package, propname, *buf, len) == -1) { + free(*buf, M_OFWPROP); + *buf = NULL; + return (-1); + } } return (len / elsz); } ssize_t -OF_getencprop_alloc(phandle_t package, const char *name, int elsz, void **buf) +OF_getencprop_alloc(phandle_t package, const char *name, void **buf) +{ + ssize_t ret; + + ret = OF_getencprop_alloc_multi(package, name, sizeof(pcell_t), + buf); + if (ret < 0) + return (ret); + else + return (ret * sizeof(pcell_t)); +} + +ssize_t +OF_getencprop_alloc_multi(phandle_t package, const char *name, int elsz, + void **buf) { ssize_t retval; pcell_t *cell; int i; - retval = OF_getprop_alloc(package, name, elsz, buf); + retval = OF_getprop_alloc_multi(package, name, elsz, buf); if (retval == -1) return (-1); - if (retval * elsz % 4 != 0) { - free(*buf, M_OFWPROP); - *buf = NULL; - return (-1); - } cell = *buf; for (i = 0; i < retval * elsz / 4; i++) diff --git a/freebsd/sys/dev/ofw/openfirm.h b/freebsd/sys/dev/ofw/openfirm.h index e1701164..f043197a 100644 --- a/freebsd/sys/dev/ofw/openfirm.h +++ b/freebsd/sys/dev/ofw/openfirm.h @@ -114,10 +114,14 @@ int OF_hasprop(phandle_t node, const char *propname); ssize_t OF_searchprop(phandle_t node, const char *propname, void *buf, size_t len); ssize_t OF_searchencprop(phandle_t node, const char *propname, - void *buf, size_t len); + pcell_t *buf, size_t len); ssize_t OF_getprop_alloc(phandle_t node, const char *propname, + void **buf); +ssize_t OF_getprop_alloc_multi(phandle_t node, const char *propname, int elsz, void **buf); ssize_t OF_getencprop_alloc(phandle_t node, const char *propname, + void **buf); +ssize_t OF_getencprop_alloc_multi(phandle_t node, const char *propname, int elsz, void **buf); void OF_prop_free(void *buf); int OF_nextprop(phandle_t node, const char *propname, char *buf, diff --git a/freebsd/sys/dev/pci/pci_pci.c b/freebsd/sys/dev/pci/pci_pci.c index 20364cf9..ec52e1fb 100644 --- a/freebsd/sys/dev/pci/pci_pci.c +++ b/freebsd/sys/dev/pci/pci_pci.c @@ -2547,6 +2547,22 @@ pcib_enable_ari(struct pcib_softc *sc, uint32_t pcie_pos) int pcib_maxslots(device_t dev) { +#if !defined(__amd64__) && !defined(__i386__) + uint32_t pcie_pos; + uint16_t val; + + /* + * If this is a PCIe rootport or downstream switch port, there's only + * one slot permitted. + */ + if (pci_find_cap(dev, PCIY_EXPRESS, &pcie_pos) == 0) { + val = pci_read_config(dev, pcie_pos + PCIER_FLAGS, 2); + val &= PCIEM_FLAGS_TYPE; + if (val == PCIEM_TYPE_ROOT_PORT || + val == PCIEM_TYPE_DOWNSTREAM_PORT) + return (0); + } +#endif return (PCI_SLOTMAX); } @@ -2560,7 +2576,7 @@ pcib_ari_maxslots(device_t dev) if (sc->flags & PCIB_ENABLE_ARI) return (PCIE_ARI_SLOTMAX); else - return (PCI_SLOTMAX); + return (pcib_maxslots(dev)); } static int diff --git a/freebsd/sys/dev/pci/pci_user.c b/freebsd/sys/dev/pci/pci_user.c index e6297bd7..c9d500a8 100644 --- a/freebsd/sys/dev/pci/pci_user.c +++ b/freebsd/sys/dev/pci/pci_user.c @@ -32,7 +32,6 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_bus.h> /* XXX trim includes */ -#include <rtems/bsd/local/opt_compat.h> #include <sys/param.h> #include <sys/systm.h> @@ -68,8 +67,6 @@ __FBSDID("$FreeBSD$"); static d_open_t pci_open; static d_close_t pci_close; -static int pci_conf_match(struct pci_match_conf *matches, int num_matches, - struct pci_conf *match_buf); static d_ioctl_t pci_ioctl; struct cdevsw pcicdev = { @@ -109,7 +106,7 @@ pci_close(struct cdev *dev, int flag, int devtype, struct thread *td) * This function returns 1 on failure, 0 on success. */ static int -pci_conf_match(struct pci_match_conf *matches, int num_matches, +pci_conf_match_native(struct pci_match_conf *matches, int num_matches, struct pci_conf *match_buf) { int i; @@ -278,9 +275,6 @@ struct pci_conf_io32 { #define PCIOCREAD_OLD _IOWR('p', 2, struct pci_io_old) #define PCIOCWRITE_OLD _IOWR('p', 3, struct pci_io_old) -static int pci_conf_match_old(struct pci_match_conf_old *matches, - int num_matches, struct pci_conf *match_buf); - static int pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches, struct pci_conf *match_buf) @@ -408,7 +402,44 @@ pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches, return (1); } #endif /* COMPAT_FREEBSD32 */ -#endif /* PRE7_COMPAT */ +#endif /* !PRE7_COMPAT */ + +union pci_conf_union { + struct pci_conf pc; +#ifdef PRE7_COMPAT + struct pci_conf_old pco; +#ifdef COMPAT_FREEBSD32 + struct pci_conf_old32 pco32; +#endif +#endif +}; + +static int +pci_conf_match(u_long cmd, struct pci_match_conf *matches, int num_matches, + struct pci_conf *match_buf) +{ + + switch (cmd) { + case PCIOCGETCONF: + return (pci_conf_match_native( + (struct pci_match_conf *)matches, num_matches, match_buf)); +#ifdef PRE7_COMPAT + case PCIOCGETCONF_OLD: + return (pci_conf_match_old( + (struct pci_match_conf_old *)matches, num_matches, + match_buf)); +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF_OLD32: + return (pci_conf_match_old32( + (struct pci_match_conf_old32 *)matches, num_matches, + match_buf)); +#endif +#endif + default: + /* programmer error */ + return (0); + } +} static int pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio) @@ -493,11 +524,184 @@ pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio) return (0); } +static size_t +pci_match_conf_size(u_long cmd) +{ + + switch (cmd) { + case PCIOCGETCONF: + return (sizeof(struct pci_match_conf)); +#ifdef PRE7_COMPAT + case PCIOCGETCONF_OLD: + return (sizeof(struct pci_match_conf_old)); +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF_OLD32: + return (sizeof(struct pci_match_conf_old32)); +#endif +#endif + default: + /* programmer error */ + return (0); + } +} + +static size_t +pci_conf_size(u_long cmd) +{ + + switch (cmd) { + case PCIOCGETCONF: + return (sizeof(struct pci_conf)); +#ifdef PRE7_COMPAT + case PCIOCGETCONF_OLD: + return (sizeof(struct pci_conf_old)); +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF_OLD32: + return (sizeof(struct pci_conf_old32)); +#endif +#endif + default: + /* programmer error */ + return (0); + } +} + +static void +pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd) +{ +#if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) + struct pci_conf_io32 *cio32; +#endif + + switch (cmd) { + case PCIOCGETCONF: +#ifdef PRE7_COMPAT + case PCIOCGETCONF_OLD: +#endif + *cio = *(struct pci_conf_io *)data; + return; + +#if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) + case PCIOCGETCONF_OLD32: + cio32 = (struct pci_conf_io32 *)data; + cio->pat_buf_len = cio32->pat_buf_len; + cio->num_patterns = cio32->num_patterns; + cio->patterns = (void *)(uintptr_t)cio32->patterns; + cio->match_buf_len = cio32->match_buf_len; + cio->num_matches = cio32->num_matches; + cio->matches = (void *)(uintptr_t)cio32->matches; + cio->offset = cio32->offset; + cio->generation = cio32->generation; + cio->status = cio32->status; + return; +#endif + + default: + /* programmer error */ + return; + } +} + +static void +pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data, + u_long cmd) +{ + struct pci_conf_io *d_cio; +#if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) + struct pci_conf_io32 *cio32; +#endif + + switch (cmd) { + case PCIOCGETCONF: +#ifdef PRE7_COMPAT + case PCIOCGETCONF_OLD: +#endif + d_cio = (struct pci_conf_io *)data; + d_cio->status = cio->status; + d_cio->generation = cio->generation; + d_cio->offset = cio->offset; + d_cio->num_matches = cio->num_matches; + return; + +#if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) + case PCIOCGETCONF_OLD32: + cio32 = (struct pci_conf_io32 *)data; + + cio32->status = cio->status; + cio32->generation = cio->generation; + cio32->offset = cio->offset; + cio32->num_matches = cio->num_matches; + return; +#endif + + default: + /* programmer error */ + return; + } +} + +static void +pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup, + u_long cmd) +{ + + memset(pcup, 0, sizeof(*pcup)); + + switch (cmd) { + case PCIOCGETCONF: + pcup->pc = *pcp; + return; + +#ifdef PRE7_COMPAT +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF_OLD32: + pcup->pco32.pc_sel.pc_bus = pcp->pc_sel.pc_bus; + pcup->pco32.pc_sel.pc_dev = pcp->pc_sel.pc_dev; + pcup->pco32.pc_sel.pc_func = pcp->pc_sel.pc_func; + pcup->pco32.pc_hdr = pcp->pc_hdr; + pcup->pco32.pc_subvendor = pcp->pc_subvendor; + pcup->pco32.pc_subdevice = pcp->pc_subdevice; + pcup->pco32.pc_vendor = pcp->pc_vendor; + pcup->pco32.pc_device = pcp->pc_device; + pcup->pco32.pc_class = pcp->pc_class; + pcup->pco32.pc_subclass = pcp->pc_subclass; + pcup->pco32.pc_progif = pcp->pc_progif; + pcup->pco32.pc_revid = pcp->pc_revid; + strlcpy(pcup->pco32.pd_name, pcp->pd_name, + sizeof(pcup->pco32.pd_name)); + pcup->pco32.pd_unit = (uint32_t)pcp->pd_unit; + return; + +#endif /* COMPAT_FREEBSD32 */ + case PCIOCGETCONF_OLD: + pcup->pco.pc_sel.pc_bus = pcp->pc_sel.pc_bus; + pcup->pco.pc_sel.pc_dev = pcp->pc_sel.pc_dev; + pcup->pco.pc_sel.pc_func = pcp->pc_sel.pc_func; + pcup->pco.pc_hdr = pcp->pc_hdr; + pcup->pco.pc_subvendor = pcp->pc_subvendor; + pcup->pco.pc_subdevice = pcp->pc_subdevice; + pcup->pco.pc_vendor = pcp->pc_vendor; + pcup->pco.pc_device = pcp->pc_device; + pcup->pco.pc_class = pcp->pc_class; + pcup->pco.pc_subclass = pcp->pc_subclass; + pcup->pco.pc_progif = pcp->pc_progif; + pcup->pco.pc_revid = pcp->pc_revid; + strlcpy(pcup->pco.pd_name, pcp->pd_name, + sizeof(pcup->pco.pd_name)); + pcup->pco.pd_unit = pcp->pd_unit; + return; +#endif /* PRE7_COMPAT */ + + default: + /* programmer error */ + return; + } +} + static int pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) { device_t pcidev; - void *confdata; const char *name; struct devlist *devlist_head; struct pci_conf_io *cio = NULL; @@ -507,31 +711,25 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t struct pci_list_vpd_io *lvio; struct pci_match_conf *pattern_buf; struct pci_map *pm; - size_t confsz, iolen, pbufsz; + size_t confsz, iolen; int error, ionum, i, num_patterns; + union pci_conf_union pcu; #ifdef PRE7_COMPAT -#ifdef COMPAT_FREEBSD32 - struct pci_conf_io32 *cio32 = NULL; - struct pci_conf_old32 conf_old32; - struct pci_match_conf_old32 *pattern_buf_old32 = NULL; -#endif - struct pci_conf_old conf_old; struct pci_io iodata; struct pci_io_old *io_old; - struct pci_match_conf_old *pattern_buf_old = NULL; io_old = NULL; #endif if (!(flag & FWRITE)) { switch (cmd) { + case PCIOCGETCONF: #ifdef PRE7_COMPAT + case PCIOCGETCONF_OLD: #ifdef COMPAT_FREEBSD32 case PCIOCGETCONF_OLD32: #endif - case PCIOCGETCONF_OLD: #endif - case PCIOCGETCONF: case PCIOCGETBAR: case PCIOCLISTVPD: break; @@ -540,39 +738,18 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t } } - switch (cmd) { -#ifdef PRE7_COMPAT -#ifdef COMPAT_FREEBSD32 - case PCIOCGETCONF_OLD32: - cio32 = (struct pci_conf_io32 *)data; - cio = malloc(sizeof(struct pci_conf_io), M_TEMP, M_WAITOK); - cio->pat_buf_len = cio32->pat_buf_len; - cio->num_patterns = cio32->num_patterns; - cio->patterns = (void *)(uintptr_t)cio32->patterns; - cio->match_buf_len = cio32->match_buf_len; - cio->num_matches = cio32->num_matches; - cio->matches = (void *)(uintptr_t)cio32->matches; - cio->offset = cio32->offset; - cio->generation = cio32->generation; - cio->status = cio32->status; - cio32->num_matches = 0; - break; -#endif - case PCIOCGETCONF_OLD: -#endif - case PCIOCGETCONF: - cio = (struct pci_conf_io *)data; - } switch (cmd) { + case PCIOCGETCONF: #ifdef PRE7_COMPAT + case PCIOCGETCONF_OLD: #ifdef COMPAT_FREEBSD32 case PCIOCGETCONF_OLD32: #endif - case PCIOCGETCONF_OLD: #endif - case PCIOCGETCONF: - + cio = malloc(sizeof(struct pci_conf_io), M_TEMP, + M_WAITOK | M_ZERO); + pci_conf_io_init(cio, data, cmd); pattern_buf = NULL; num_patterns = 0; dinfo = NULL; @@ -611,17 +788,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t * multiple of sizeof(struct pci_conf) in case the user * didn't specify a multiple of that size. */ -#ifdef PRE7_COMPAT -#ifdef COMPAT_FREEBSD32 - if (cmd == PCIOCGETCONF_OLD32) - confsz = sizeof(struct pci_conf_old32); - else -#endif - if (cmd == PCIOCGETCONF_OLD) - confsz = sizeof(struct pci_conf_old); - else -#endif - confsz = sizeof(struct pci_conf); + confsz = pci_conf_size(cmd); iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz), pci_numdevs * confsz); @@ -650,18 +817,8 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t * it's far more likely to just catch folks that * updated their kernel but not their userland. */ -#ifdef PRE7_COMPAT -#ifdef COMPAT_FREEBSD32 - if (cmd == PCIOCGETCONF_OLD32) - pbufsz = sizeof(struct pci_match_conf_old32); - else -#endif - if (cmd == PCIOCGETCONF_OLD) - pbufsz = sizeof(struct pci_match_conf_old); - else -#endif - pbufsz = sizeof(struct pci_match_conf); - if (cio->num_patterns * pbufsz != cio->pat_buf_len) { + if (cio->num_patterns * pci_match_conf_size(cmd) != + cio->pat_buf_len) { /* The user made a mistake, return an error. */ cio->status = PCI_GETCONF_ERROR; error = EINVAL; @@ -671,28 +828,10 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t /* * Allocate a buffer to hold the patterns. */ -#ifdef PRE7_COMPAT -#ifdef COMPAT_FREEBSD32 - if (cmd == PCIOCGETCONF_OLD32) { - pattern_buf_old32 = malloc(cio->pat_buf_len, - M_TEMP, M_WAITOK); - error = copyin(cio->patterns, - pattern_buf_old32, cio->pat_buf_len); - } else -#endif /* COMPAT_FREEBSD32 */ - if (cmd == PCIOCGETCONF_OLD) { - pattern_buf_old = malloc(cio->pat_buf_len, - M_TEMP, M_WAITOK); - error = copyin(cio->patterns, - pattern_buf_old, cio->pat_buf_len); - } else -#endif /* PRE7_COMPAT */ - { - pattern_buf = malloc(cio->pat_buf_len, M_TEMP, - M_WAITOK); - error = copyin(cio->patterns, pattern_buf, - cio->pat_buf_len); - } + pattern_buf = malloc(cio->pat_buf_len, M_TEMP, + M_WAITOK); + error = copyin(cio->patterns, pattern_buf, + cio->pat_buf_len); if (error != 0) { error = EINVAL; goto getconfexit; @@ -735,27 +874,9 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t dinfo->conf.pd_unit = 0; } -#ifdef PRE7_COMPAT - if ( -#ifdef COMPAT_FREEBSD32 - (cmd == PCIOCGETCONF_OLD32 && - (pattern_buf_old32 == NULL || - pci_conf_match_old32(pattern_buf_old32, - num_patterns, &dinfo->conf) == 0)) || -#endif - (cmd == PCIOCGETCONF_OLD && - (pattern_buf_old == NULL || - pci_conf_match_old(pattern_buf_old, num_patterns, - &dinfo->conf) == 0)) || - (cmd == PCIOCGETCONF && - (pattern_buf == NULL || - pci_conf_match(pattern_buf, num_patterns, - &dinfo->conf) == 0))) { -#else if (pattern_buf == NULL || - pci_conf_match(pattern_buf, num_patterns, + pci_conf_match(cmd, pattern_buf, num_patterns, &dinfo->conf) == 0) { -#endif /* * If we've filled up the user's buffer, * break out at this point. Since we've @@ -769,79 +890,8 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t break; } -#ifdef PRE7_COMPAT -#ifdef COMPAT_FREEBSD32 - if (cmd == PCIOCGETCONF_OLD32) { - memset(&conf_old32, 0, - sizeof(conf_old32)); - conf_old32.pc_sel.pc_bus = - dinfo->conf.pc_sel.pc_bus; - conf_old32.pc_sel.pc_dev = - dinfo->conf.pc_sel.pc_dev; - conf_old32.pc_sel.pc_func = - dinfo->conf.pc_sel.pc_func; - conf_old32.pc_hdr = dinfo->conf.pc_hdr; - conf_old32.pc_subvendor = - dinfo->conf.pc_subvendor; - conf_old32.pc_subdevice = - dinfo->conf.pc_subdevice; - conf_old32.pc_vendor = - dinfo->conf.pc_vendor; - conf_old32.pc_device = - dinfo->conf.pc_device; - conf_old32.pc_class = - dinfo->conf.pc_class; - conf_old32.pc_subclass = - dinfo->conf.pc_subclass; - conf_old32.pc_progif = - dinfo->conf.pc_progif; - conf_old32.pc_revid = - dinfo->conf.pc_revid; - strncpy(conf_old32.pd_name, - dinfo->conf.pd_name, - sizeof(conf_old32.pd_name)); - conf_old32.pd_name[PCI_MAXNAMELEN] = 0; - conf_old32.pd_unit = - (uint32_t)dinfo->conf.pd_unit; - confdata = &conf_old32; - } else -#endif /* COMPAT_FREEBSD32 */ - if (cmd == PCIOCGETCONF_OLD) { - memset(&conf_old, 0, sizeof(conf_old)); - conf_old.pc_sel.pc_bus = - dinfo->conf.pc_sel.pc_bus; - conf_old.pc_sel.pc_dev = - dinfo->conf.pc_sel.pc_dev; - conf_old.pc_sel.pc_func = - dinfo->conf.pc_sel.pc_func; - conf_old.pc_hdr = dinfo->conf.pc_hdr; - conf_old.pc_subvendor = - dinfo->conf.pc_subvendor; - conf_old.pc_subdevice = - dinfo->conf.pc_subdevice; - conf_old.pc_vendor = - dinfo->conf.pc_vendor; - conf_old.pc_device = - dinfo->conf.pc_device; - conf_old.pc_class = - dinfo->conf.pc_class; - conf_old.pc_subclass = - dinfo->conf.pc_subclass; - conf_old.pc_progif = - dinfo->conf.pc_progif; - conf_old.pc_revid = - dinfo->conf.pc_revid; - strncpy(conf_old.pd_name, - dinfo->conf.pd_name, - sizeof(conf_old.pd_name)); - conf_old.pd_name[PCI_MAXNAMELEN] = 0; - conf_old.pd_unit = - dinfo->conf.pd_unit; - confdata = &conf_old; - } else -#endif /* PRE7_COMPAT */ - confdata = &dinfo->conf; - error = copyout(confdata, + pci_conf_for_copyout(&dinfo->conf, &pcu, cmd); + error = copyout(&pcu, (caddr_t)cio->matches + confsz * cio->num_matches, confsz); if (error) @@ -874,23 +924,9 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t cio->status = PCI_GETCONF_MORE_DEVS; getconfexit: -#ifdef PRE7_COMPAT -#ifdef COMPAT_FREEBSD32 - if (cmd == PCIOCGETCONF_OLD32) { - cio32->status = cio->status; - cio32->generation = cio->generation; - cio32->offset = cio->offset; - cio32->num_matches = cio->num_matches; - free(cio, M_TEMP); - } - if (pattern_buf_old32 != NULL) - free(pattern_buf_old32, M_TEMP); -#endif - if (pattern_buf_old != NULL) - free(pattern_buf_old, M_TEMP); -#endif - if (pattern_buf != NULL) - free(pattern_buf, M_TEMP); + pci_conf_io_update_data(cio, data, cmd); + free(cio, M_TEMP); + free(pattern_buf, M_TEMP); break; diff --git a/freebsd/sys/dev/re/if_re.c b/freebsd/sys/dev/re/if_re.c index c8bb6db7..5aa24349 100644 --- a/freebsd/sys/dev/re/if_re.c +++ b/freebsd/sys/dev/re/if_re.c @@ -141,6 +141,8 @@ __FBSDID("$FreeBSD$"); #include <net/bpf.h> +#include <netinet/netdump/netdump.h> + #include <machine/bus.h> #include <machine/resource.h> #include <sys/bus.h> @@ -281,6 +283,7 @@ static void re_tick (void *); static void re_int_task (void *, int); static void re_start (struct ifnet *); static void re_start_locked (struct ifnet *); +static void re_start_tx (struct rl_softc *); static int re_ioctl (struct ifnet *, u_long, caddr_t); static void re_init (void *); static void re_init_locked (struct rl_softc *); @@ -309,6 +312,8 @@ static void re_setwol (struct rl_softc *); static void re_clrwol (struct rl_softc *); static void re_set_linkspeed (struct rl_softc *); +NETDUMP_DEFINE(re); + #ifdef DEV_NETMAP /* see ixgbe.c for details */ #include <dev/netmap/if_re_netmap.h> MODULE_DEPEND(re, netmap, 1, 1, 1); @@ -682,7 +687,7 @@ re_set_rxmode(struct rl_softc *sc) } if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = ether_crc32_be(LLADDR((struct sockaddr_dl *) @@ -1739,8 +1744,11 @@ re_attach(device_t dev) if (error) { device_printf(dev, "couldn't set up irq\n"); ether_ifdetach(ifp); + goto fail; } + NETDUMP_SET(ifp, re); + fail: if (error) re_detach(dev); @@ -2935,7 +2943,7 @@ re_start_locked(struct ifnet *ifp) #ifdef DEV_NETMAP /* XXX is this necessary ? */ if (ifp->if_capenable & IFCAP_NETMAP) { - struct netmap_kring *kring = &NA(ifp)->tx_rings[0]; + struct netmap_kring *kring = NA(ifp)->tx_rings[0]; if (sc->rl_ldata.rl_tx_prodidx != kring->nr_hwcur) { /* kick the tx unit */ CSR_WRITE_1(sc, sc->rl_txstart, RL_TXSTART_START); @@ -2983,8 +2991,14 @@ re_start_locked(struct ifnet *ifp) return; } - /* Flush the TX descriptors */ + re_start_tx(sc); +} +static void +re_start_tx(struct rl_softc *sc) +{ + + /* Flush the TX descriptors */ bus_dmamap_sync(sc->rl_ldata.rl_tx_list_tag, sc->rl_ldata.rl_tx_list_map, BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); @@ -4080,3 +4094,59 @@ sysctl_hw_re_int_mod(SYSCTL_HANDLER_ARGS) return (sysctl_int_range(oidp, arg1, arg2, req, RL_TIMER_MIN, RL_TIMER_MAX)); } + +#ifdef NETDUMP +static void +re_netdump_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize) +{ + struct rl_softc *sc; + + sc = if_getsoftc(ifp); + RL_LOCK(sc); + *nrxr = sc->rl_ldata.rl_rx_desc_cnt; + *ncl = NETDUMP_MAX_IN_FLIGHT; + *clsize = (ifp->if_mtu > RL_MTU && + (sc->rl_flags & RL_FLAG_JUMBOV2) != 0) ? MJUM9BYTES : MCLBYTES; + RL_UNLOCK(sc); +} + +static void +re_netdump_event(struct ifnet *ifp __unused, enum netdump_ev event __unused) +{ +} + +static int +re_netdump_transmit(struct ifnet *ifp, struct mbuf *m) +{ + struct rl_softc *sc; + int error; + + sc = if_getsoftc(ifp); + if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING || (sc->rl_flags & RL_FLAG_LINK) == 0) + return (EBUSY); + + error = re_encap(sc, &m); + if (error == 0) + re_start_tx(sc); + return (error); +} + +static int +re_netdump_poll(struct ifnet *ifp, int count) +{ + struct rl_softc *sc; + int error; + + sc = if_getsoftc(ifp); + if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0 || + (sc->rl_flags & RL_FLAG_LINK) == 0) + return (EBUSY); + + re_txeof(sc); + error = re_rxeof(sc, NULL); + if (error != 0 && error != EAGAIN) + return (error); + return (0); +} +#endif /* NETDUMP */ diff --git a/freebsd/sys/dev/rtwn/if_rtwn_rx.c b/freebsd/sys/dev/rtwn/if_rtwn_rx.c index fb260596..512292ce 100644 --- a/freebsd/sys/dev/rtwn/if_rtwn_rx.c +++ b/freebsd/sys/dev/rtwn/if_rtwn_rx.c @@ -389,7 +389,7 @@ rtwn_set_multi(struct rtwn_softc *sc) TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { ifp = vap->iv_ifp; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { caddr_t dl; uint8_t pos; diff --git a/freebsd/sys/dev/tsec/if_tsec.c b/freebsd/sys/dev/tsec/if_tsec.c index e07c21ce..c18c950f 100644 --- a/freebsd/sys/dev/tsec/if_tsec.c +++ b/freebsd/sys/dev/tsec/if_tsec.c @@ -1943,7 +1943,7 @@ tsec_setup_multicast(struct tsec_softc *sc) } if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; diff --git a/freebsd/sys/dev/usb/input/ukbd.c b/freebsd/sys/dev/usb/input/ukbd.c index 5cb2636c..76fe76b6 100644 --- a/freebsd/sys/dev/usb/input/ukbd.c +++ b/freebsd/sys/dev/usb/input/ukbd.c @@ -41,7 +41,6 @@ __FBSDID("$FreeBSD$"); * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf */ -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_kbd.h> #include <rtems/bsd/local/opt_ukbd.h> #include <rtems/bsd/local/opt_evdev.h> diff --git a/freebsd/sys/dev/usb/input/usb_rdesc.h b/freebsd/sys/dev/usb/input/usb_rdesc.h index 00eea122..889381e8 100644 --- a/freebsd/sys/dev/usb/input/usb_rdesc.h +++ b/freebsd/sys/dev/usb/input/usb_rdesc.h @@ -276,3 +276,31 @@ 0x81, 0x01, /* INPUT (Constant) */\ 0xc0 /* END COLLECTION */\ +/* Fixed report descriptor for Super Nintendo gamepads */ +#define UHID_SNES_REPORT_DESCR(...) \ + 0x05, 0x01, /* Usage Page (Desktop), */\ + 0x09, 0x04, /* Usage (Joystik), */\ + 0xA1, 0x01, /* Collection (Application), */\ + 0xA1, 0x02, /* Collection (Logical), */\ + 0x14, /* Logical Minimum (0), */\ + 0x75, 0x08, /* Report Size (8), */\ + 0x95, 0x03, /* Report Count (3), */\ + 0x81, 0x01, /* Input (Constant), */\ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */\ + 0x95, 0x02, /* Report Count (2), */\ + 0x09, 0x30, /* Usage (X), */\ + 0x09, 0x31, /* Usage (Y), */\ + 0x81, 0x02, /* Input (Variable), */\ + 0x75, 0x01, /* Report Size (1), */\ + 0x95, 0x04, /* Report Count (4), */\ + 0x81, 0x01, /* Input (Constant), */\ + 0x25, 0x01, /* Logical Maximum (1), */\ + 0x95, 0x0A, /* Report Count (10), */\ + 0x05, 0x09, /* Usage Page (Button), */\ + 0x19, 0x01, /* Usage Minimum (01h), */\ + 0x29, 0x0A, /* Usage Maximum (0Ah), */\ + 0x81, 0x02, /* Input (Variable), */\ + 0x95, 0x0A, /* Report Count (10), */\ + 0x81, 0x01, /* Input (Constant), */\ + 0xC0, /* End Collection, */\ + 0xC0 /* End Collection */ diff --git a/freebsd/sys/dev/usb/net/if_aue.c b/freebsd/sys/dev/usb/net/if_aue.c index 69951b70..5454e2aa 100644 --- a/freebsd/sys/dev/usb/net/if_aue.c +++ b/freebsd/sys/dev/usb/net/if_aue.c @@ -557,7 +557,7 @@ aue_setmulti(struct usb_ether *ue) /* now program new ones */ if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = ether_crc32_le(LLADDR((struct sockaddr_dl *) diff --git a/freebsd/sys/dev/usb/net/if_axe.c b/freebsd/sys/dev/usb/net/if_axe.c index b77292ba..cf54e96e 100644 --- a/freebsd/sys/dev/usb/net/if_axe.c +++ b/freebsd/sys/dev/usb/net/if_axe.c @@ -504,7 +504,7 @@ axe_setmulti(struct usb_ether *ue) rxmode &= ~AXE_RXCMD_ALLMULTI; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; diff --git a/freebsd/sys/dev/usb/net/if_axge.c b/freebsd/sys/dev/usb/net/if_axge.c index 575571e4..f8ed34ae 100644 --- a/freebsd/sys/dev/usb/net/if_axge.c +++ b/freebsd/sys/dev/usb/net/if_axge.c @@ -788,7 +788,7 @@ axge_rxfilter(struct usb_ether *ue) rxmode |= RCR_ACPT_MCAST; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = ether_crc32_be(LLADDR((struct sockaddr_dl *) diff --git a/freebsd/sys/dev/usb/net/if_cue.c b/freebsd/sys/dev/usb/net/if_cue.c index 63846a01..f184fa24 100644 --- a/freebsd/sys/dev/usb/net/if_cue.c +++ b/freebsd/sys/dev/usb/net/if_cue.c @@ -330,7 +330,7 @@ cue_setmulti(struct usb_ether *ue) /* now program new ones */ if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; diff --git a/freebsd/sys/dev/usb/net/if_kue.c b/freebsd/sys/dev/usb/net/if_kue.c index 255a83bb..35fd3fcf 100644 --- a/freebsd/sys/dev/usb/net/if_kue.c +++ b/freebsd/sys/dev/usb/net/if_kue.c @@ -379,7 +379,7 @@ kue_setmulti(struct usb_ether *ue) sc->sc_rxfilt &= ~KUE_RXFILT_ALLMULTI; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; diff --git a/freebsd/sys/dev/usb/net/if_mos.c b/freebsd/sys/dev/usb/net/if_mos.c index ad7bfcce..3dd0e5ef 100644 --- a/freebsd/sys/dev/usb/net/if_mos.c +++ b/freebsd/sys/dev/usb/net/if_mos.c @@ -608,7 +608,7 @@ mos_setmulti(struct usb_ether *ue) /* get all new ones */ if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) { allmulti = 1; continue; diff --git a/freebsd/sys/dev/usb/net/if_rue.c b/freebsd/sys/dev/usb/net/if_rue.c index 7b062755..810a98c8 100644 --- a/freebsd/sys/dev/usb/net/if_rue.c +++ b/freebsd/sys/dev/usb/net/if_rue.c @@ -502,7 +502,7 @@ rue_setmulti(struct usb_ether *ue) /* now program new ones */ if_maddr_rlock(ifp); - TAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) + CK_STAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; diff --git a/freebsd/sys/dev/usb/net/if_smsc.c b/freebsd/sys/dev/usb/net/if_smsc.c index 88ecb618..87e181d8 100644 --- a/freebsd/sys/dev/usb/net/if_smsc.c +++ b/freebsd/sys/dev/usb/net/if_smsc.c @@ -454,7 +454,7 @@ smsc_miibus_readreg(device_t dev, int phy, int reg) goto done; } - addr = (phy << 11) | (reg << 6) | SMSC_MII_READ; + addr = (phy << 11) | (reg << 6) | SMSC_MII_READ | SMSC_MII_BUSY; smsc_write_reg(sc, SMSC_MII_ADDR, addr); if (smsc_wait_for_bits(sc, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) @@ -507,7 +507,7 @@ smsc_miibus_writereg(device_t dev, int phy, int reg, int val) val = htole32(val); smsc_write_reg(sc, SMSC_MII_DATA, val); - addr = (phy << 11) | (reg << 6) | SMSC_MII_WRITE; + addr = (phy << 11) | (reg << 6) | SMSC_MII_WRITE | SMSC_MII_BUSY; smsc_write_reg(sc, SMSC_MII_ADDR, addr); if (smsc_wait_for_bits(sc, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) @@ -716,14 +716,14 @@ smsc_setmulti(struct usb_ether *ue) /* Take the lock of the mac address list before hashing each of them */ if_maddr_rlock(ifp); - if (!TAILQ_EMPTY(&ifp->if_multiaddrs)) { + if (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) { /* We are filtering on a set of address so calculate hashes of each * of the address and set the corresponding bits in the register. */ sc->sc_mac_csr |= SMSC_MAC_CSR_HPFILT; sc->sc_mac_csr &= ~(SMSC_MAC_CSR_PRMS | SMSC_MAC_CSR_MCPAS); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; @@ -1308,7 +1308,7 @@ smsc_phy_init(struct smsc_softc *sc) do { uether_pause(&sc->sc_ue, hz / 100); bmcr = smsc_miibus_readreg(sc->sc_ue.ue_dev, sc->sc_phyno, MII_BMCR); - } while ((bmcr & MII_BMCR) && ((ticks - start_ticks) < max_ticks)); + } while ((bmcr & BMCR_RESET) && ((ticks - start_ticks) < max_ticks)); if (((usb_ticks_t)(ticks - start_ticks)) >= max_ticks) { smsc_err_printf(sc, "PHY reset timed-out"); diff --git a/freebsd/sys/dev/usb/net/if_udav.c b/freebsd/sys/dev/usb/net/if_udav.c index 21019265..a4e683ac 100644 --- a/freebsd/sys/dev/usb/net/if_udav.c +++ b/freebsd/sys/dev/usb/net/if_udav.c @@ -524,7 +524,7 @@ udav_setmulti(struct usb_ether *ue) /* now program new ones */ if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; diff --git a/freebsd/sys/dev/usb/net/if_ure.c b/freebsd/sys/dev/usb/net/if_ure.c index 0e45a6c9..8a88feae 100644 --- a/freebsd/sys/dev/usb/net/if_ure.c +++ b/freebsd/sys/dev/usb/net/if_ure.c @@ -797,7 +797,7 @@ ure_rxfilter(struct usb_ether *ue) rxmode |= URE_RCR_AM; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = ether_crc32_be(LLADDR((struct sockaddr_dl *) diff --git a/freebsd/sys/dev/usb/net/usb_ethernet.c b/freebsd/sys/dev/usb/net/usb_ethernet.c index 842e7987..9ce60eff 100644 --- a/freebsd/sys/dev/usb/net/usb_ethernet.c +++ b/freebsd/sys/dev/usb/net/usb_ethernet.c @@ -192,6 +192,17 @@ error: return (error); } +void +uether_ifattach_wait(struct usb_ether *ue) +{ + + UE_LOCK(ue); + usb_proc_mwait(&ue->ue_tq, + &ue->ue_sync_task[0].hdr, + &ue->ue_sync_task[1].hdr); + UE_UNLOCK(ue); +} + static void ue_attach_post_task(struct usb_proc_msg *_task) { diff --git a/freebsd/sys/dev/usb/net/usb_ethernet.h b/freebsd/sys/dev/usb/net/usb_ethernet.h index c7afc650..9839db16 100644 --- a/freebsd/sys/dev/usb/net/usb_ethernet.h +++ b/freebsd/sys/dev/usb/net/usb_ethernet.h @@ -113,6 +113,7 @@ struct ifnet *uether_getifp(struct usb_ether *); struct mii_data *uether_getmii(struct usb_ether *); void *uether_getsc(struct usb_ether *); int uether_ifattach(struct usb_ether *); +void uether_ifattach_wait(struct usb_ether *); void uether_ifdetach(struct usb_ether *); int uether_ifmedia_upd(struct ifnet *); void uether_init(void *); diff --git a/freebsd/sys/dev/usb/serial/uchcom.c b/freebsd/sys/dev/usb/serial/uchcom.c index 1e741ccd..24cb8433 100644 --- a/freebsd/sys/dev/usb/serial/uchcom.c +++ b/freebsd/sys/dev/usb/serial/uchcom.c @@ -124,11 +124,11 @@ SYSCTL_INT(_hw_usb_uchcom, OID_AUTO, debug, CTLFLAG_RWTUN, #define UCHCOM_REG_BPS_MOD 0x14 #define UCHCOM_REG_BPS_PAD 0x0F #define UCHCOM_REG_BREAK1 0x05 -#define UCHCOM_REG_BREAK2 0x18 #define UCHCOM_REG_LCR1 0x18 #define UCHCOM_REG_LCR2 0x25 #define UCHCOM_VER_20 0x20 +#define UCHCOM_VER_30 0x30 #define UCHCOM_BASE_UNKNOWN 0 #define UCHCOM_BPS_MOD_BASE 20000000 @@ -137,12 +137,14 @@ SYSCTL_INT(_hw_usb_uchcom, OID_AUTO, debug, CTLFLAG_RWTUN, #define UCHCOM_DTR_MASK 0x20 #define UCHCOM_RTS_MASK 0x40 -#define UCHCOM_BRK1_MASK 0x01 -#define UCHCOM_BRK2_MASK 0x40 +#define UCHCOM_BRK_MASK 0x01 #define UCHCOM_LCR1_MASK 0xAF #define UCHCOM_LCR2_MASK 0x07 -#define UCHCOM_LCR1_PARENB 0x80 +#define UCHCOM_LCR1_RX 0x80 +#define UCHCOM_LCR1_TX 0x40 +#define UCHCOM_LCR1_PARENB 0x08 +#define UCHCOM_LCR1_CS8 0x03 #define UCHCOM_LCR2_PAREVEN 0x07 #define UCHCOM_LCR2_PARODD 0x06 #define UCHCOM_LCR2_PARMARK 0x05 @@ -324,13 +326,17 @@ uchcom_attach(device_t dev) sc->sc_udev = uaa->device; - switch (uaa->info.bcdDevice) { - case UCHCOM_REV_CH340: + switch (uaa->info.idProduct) { + case USB_PRODUCT_WCH2_CH341SER: device_printf(dev, "CH340 detected\n"); break; - default: + case USB_PRODUCT_WCH2_CH341SER_2: device_printf(dev, "CH341 detected\n"); break; + default: + device_printf(dev, "New CH340/CH341 product 0x%04x detected\n", + uaa->info.idProduct); + break; } iface_index = UCHCOM_IFACE_INDEX; @@ -414,6 +420,8 @@ uchcom_ctrl_write(struct uchcom_softc *sc, uint8_t reqno, USETW(req.wIndex, index); USETW(req.wLength, 0); + DPRINTF("WR REQ 0x%02X VAL 0x%04X IDX 0x%04X\n", + reqno, value, index); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000); } @@ -430,6 +438,8 @@ uchcom_ctrl_read(struct uchcom_softc *sc, uint8_t reqno, USETW(req.wIndex, index); USETW(req.wLength, buflen); + DPRINTF("RD REQ 0x%02X VAL 0x%04X IDX 0x%04X LEN %d\n", + reqno, value, index, buflen); ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, buf, USB_SHORT_XFER_OK, 1000); } @@ -504,6 +514,7 @@ static void uchcom_update_version(struct uchcom_softc *sc) { uchcom_get_version(sc, &sc->sc_version); + DPRINTF("Chip version: 0x%02x\n", sc->sc_version); } static void @@ -549,17 +560,17 @@ uchcom_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) uint8_t brk1; uint8_t brk2; - uchcom_read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_BREAK2, &brk2); + uchcom_read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_LCR1, &brk2); if (onoff) { /* on - clear bits */ - brk1 &= ~UCHCOM_BRK1_MASK; - brk2 &= ~UCHCOM_BRK2_MASK; + brk1 &= ~UCHCOM_BRK_MASK; + brk2 &= ~UCHCOM_LCR1_TX; } else { /* off - set bits */ - brk1 |= UCHCOM_BRK1_MASK; - brk2 |= UCHCOM_BRK2_MASK; + brk1 |= UCHCOM_BRK_MASK; + brk2 |= UCHCOM_LCR1_TX; } - uchcom_write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_BREAK2, brk2); + uchcom_write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_LCR1, brk2); } static int @@ -611,8 +622,12 @@ uchcom_set_baudrate(struct uchcom_softc *sc, uint32_t rate) if (uchcom_calc_divider_settings(&dv, rate)) return; + /* + * According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE, + * otherwise the chip will buffer data. + */ uchcom_write_reg(sc, - UCHCOM_REG_BPS_PRE, dv.dv_prescaler, + UCHCOM_REG_BPS_PRE, dv.dv_prescaler | 0x80, UCHCOM_REG_BPS_DIV, dv.dv_div); uchcom_write_reg(sc, UCHCOM_REG_BPS_MOD, dv.dv_mod, @@ -678,6 +693,10 @@ uchcom_pre_param(struct ucom_softc *ucom, struct termios *t) default: return (EIO); } + if ((t->c_cflag & CSTOPB) != 0) + return (EIO); + if ((t->c_cflag & PARENB) != 0) + return (EIO); if (uchcom_calc_divider_settings(&dv, t->c_ospeed)) { return (EIO); @@ -690,11 +709,26 @@ uchcom_cfg_param(struct ucom_softc *ucom, struct termios *t) { struct uchcom_softc *sc = ucom->sc_parent; - uchcom_get_version(sc, 0); + uchcom_get_version(sc, NULL); uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0, 0); uchcom_set_baudrate(sc, t->c_ospeed); - uchcom_read_reg(sc, 0x18, 0, 0x25, 0); - uchcom_write_reg(sc, 0x18, 0x50, 0x25, 0x00); + if (sc->sc_version < UCHCOM_VER_30) { + uchcom_read_reg(sc, UCHCOM_REG_LCR1, NULL, + UCHCOM_REG_LCR2, NULL); + uchcom_write_reg(sc, UCHCOM_REG_LCR1, 0x50, + UCHCOM_REG_LCR2, 0x00); + } else { + /* + * Set up line control: + * - enable transmit and receive + * - set 8n1 mode + * To do: support other sizes, parity, stop bits. + */ + uchcom_write_reg(sc, + UCHCOM_REG_LCR1, + UCHCOM_LCR1_RX | UCHCOM_LCR1_TX | UCHCOM_LCR1_CS8, + UCHCOM_REG_LCR2, 0x00); + } uchcom_update_status(sc); uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0x501f, 0xd90a); uchcom_set_baudrate(sc, t->c_ospeed); diff --git a/freebsd/sys/dev/usb/serial/umodem.c b/freebsd/sys/dev/usb/serial/umodem.c index ac1e35c8..76c7dfe2 100644 --- a/freebsd/sys/dev/usb/serial/umodem.c +++ b/freebsd/sys/dev/usb/serial/umodem.c @@ -459,6 +459,8 @@ umodem_attach(device_t dev) mtx_unlock(&sc->sc_mtx); } + ucom_set_usb_mode(&sc->sc_super_ucom, uaa->usb_mode); + error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, &umodem_callback, &sc->sc_mtx); if (error) { diff --git a/freebsd/sys/dev/usb/serial/usb_serial.c b/freebsd/sys/dev/usb/serial/usb_serial.c index 46a18d63..a3f9b5de 100644 --- a/freebsd/sys/dev/usb/serial/usb_serial.c +++ b/freebsd/sys/dev/usb/serial/usb_serial.c @@ -109,6 +109,12 @@ static int ucom_pps_mode; SYSCTL_INT(_hw_usb_ucom, OID_AUTO, pps_mode, CTLFLAG_RWTUN, &ucom_pps_mode, 0, "pulse capture mode: 0/1/2=disabled/CTS/DCD; add 0x10 to invert"); + +static int ucom_device_mode_console = 1; + +SYSCTL_INT(_hw_usb_ucom, OID_AUTO, device_mode_console, CTLFLAG_RW, + &ucom_device_mode_console, 0, + "set to 1 to mark terminals as consoles when in device mode"); #endif /* __rtems__ */ #ifdef USB_DEBUG @@ -203,6 +209,7 @@ ucom_init(void *arg) } SYSINIT(ucom_init, SI_SUB_KLD - 1, SI_ORDER_ANY, ucom_init, NULL); +#ifndef __rtems__ static void ucom_uninit(void *arg) { @@ -218,6 +225,7 @@ ucom_uninit(void *arg) mtx_destroy(&ucom_mtx); } SYSUNINIT(ucom_uninit, SI_SUB_KLD - 3, SI_ORDER_ANY, ucom_uninit, NULL); +#endif /* __rtems__ */ /* * Mark a unit number (the X in cuaUX) as in use. @@ -294,7 +302,7 @@ ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc, } ssc->sc_subunits = subunits; ssc->sc_flag = UCOM_FLAG_ATTACHED | - UCOM_FLAG_FREE_UNIT; + UCOM_FLAG_FREE_UNIT | (ssc->sc_flag & UCOM_FLAG_DEVICE_MODE); if (callback->ucom_free == NULL) ssc->sc_flag |= UCOM_FLAG_WAIT_REFS; @@ -394,6 +402,24 @@ ucom_drain_all(void *arg) mtx_unlock(&ucom_mtx); } +static cn_probe_t ucom_cnprobe; +static cn_init_t ucom_cninit; +static cn_term_t ucom_cnterm; +static cn_getc_t ucom_cngetc; +static cn_putc_t ucom_cnputc; +static cn_grab_t ucom_cngrab; +static cn_ungrab_t ucom_cnungrab; + +const struct consdev_ops ucom_cnops = { + .cn_probe = ucom_cnprobe, + .cn_init = ucom_cninit, + .cn_term = ucom_cnterm, + .cn_getc = ucom_cngetc, + .cn_putc = ucom_cnputc, + .cn_grab = ucom_cngrab, + .cn_ungrab = ucom_cnungrab, +}; + static int ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) { @@ -458,6 +484,26 @@ ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) UCOM_MTX_UNLOCK(ucom_cons_softc); } +#ifndef __rtems__ + if ((ssc->sc_flag & UCOM_FLAG_DEVICE_MODE) != 0 && + ucom_device_mode_console > 0 && + ucom_cons_softc == NULL) { + struct consdev *cp; + + cp = malloc(sizeof(struct consdev), M_USBDEV, + M_WAITOK|M_ZERO); + cp->cn_ops = &ucom_cnops; + cp->cn_arg = NULL; + cp->cn_pri = CN_NORMAL; + strlcpy(cp->cn_name, "tty", sizeof(cp->cn_name)); + strlcat(cp->cn_name, buf, sizeof(cp->cn_name)); + + sc->sc_consdev = cp; + + cnadd(cp); + } +#endif /* __rtems__ */ + return (0); } @@ -468,6 +514,14 @@ ucom_detach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc) DPRINTF("sc = %p, tp = %p\n", sc, sc->sc_tty); +#ifndef __rtems__ + if (sc->sc_consdev != NULL) { + cnremove(sc->sc_consdev); + free(sc->sc_consdev, M_USBDEV); + sc->sc_consdev = NULL; + } +#endif /* __rtems__ */ + if (sc->sc_flag & UCOM_FLAG_CONSOLE) { UCOM_MTX_LOCK(ucom_cons_softc); ucom_close(ucom_cons_softc->sc_tty); @@ -541,6 +595,20 @@ ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev) } } +void +ucom_set_usb_mode(struct ucom_super_softc *ssc, enum usb_hc_mode usb_mode) +{ + + switch (usb_mode) { + case USB_MODE_DEVICE: + ssc->sc_flag |= UCOM_FLAG_DEVICE_MODE; + break; + default: + ssc->sc_flag &= ~UCOM_FLAG_DEVICE_MODE; + break; + } +} + static void ucom_queue_command(struct ucom_softc *sc, usb_proc_callback_t *fn, struct termios *pt, @@ -1547,14 +1615,6 @@ ucom_free(void *xsc) mtx_unlock(&ucom_mtx); } -static cn_probe_t ucom_cnprobe; -static cn_init_t ucom_cninit; -static cn_term_t ucom_cnterm; -static cn_getc_t ucom_cngetc; -static cn_putc_t ucom_cnputc; -static cn_grab_t ucom_cngrab; -static cn_ungrab_t ucom_cnungrab; - CONSOLE_DRIVER(ucom); static void diff --git a/freebsd/sys/dev/usb/serial/usb_serial.h b/freebsd/sys/dev/usb/serial/usb_serial.h index 9a5e043e..2bcc388d 100644 --- a/freebsd/sys/dev/usb/serial/usb_serial.h +++ b/freebsd/sys/dev/usb/serial/usb_serial.h @@ -165,6 +165,9 @@ struct ucom_softc { const struct ucom_callback *sc_callback; struct ucom_super_softc *sc_super; struct tty *sc_tty; +#ifndef __rtems__ + struct consdev *sc_consdev; +#endif /* __rtems__ */ struct mtx *sc_mtx; void *sc_parent; int sc_subunit; @@ -183,6 +186,7 @@ struct ucom_softc { #define UCOM_FLAG_FREE_UNIT 0x0200 /* set if we must free the unit */ #define UCOM_FLAG_INWAKEUP 0x0400 /* set if we are in the tsw_inwakeup callback */ #define UCOM_FLAG_LSRTXIDLE 0x0800 /* set if sc_lsr bits ULSR_TSRE+TXRDY work */ +#define UCOM_FLAG_DEVICE_MODE 0x1000 /* set if we're an USB device, not a host */ uint8_t sc_lsr; uint8_t sc_msr; uint8_t sc_mcr; @@ -211,6 +215,7 @@ int ucom_attach(struct ucom_super_softc *, const struct ucom_callback *callback, struct mtx *); void ucom_detach(struct ucom_super_softc *, struct ucom_softc *); void ucom_set_pnpinfo_usb(struct ucom_super_softc *, device_t); +void ucom_set_usb_mode(struct ucom_super_softc *, enum usb_hc_mode); void ucom_status_change(struct ucom_softc *); uint8_t ucom_get_data(struct ucom_softc *, struct usb_page_cache *, uint32_t, uint32_t, uint32_t *); diff --git a/freebsd/sys/dev/usb/serial/uslcom.c b/freebsd/sys/dev/usb/serial/uslcom.c index 45835b82..4128802d 100644 --- a/freebsd/sys/dev/usb/serial/uslcom.c +++ b/freebsd/sys/dev/usb/serial/uslcom.c @@ -66,7 +66,7 @@ SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RWTUN, &uslcom_debug, 0, "Debug level"); #endif -#define USLCOM_BULK_BUF_SIZE 1024 +#define USLCOM_BULK_BUF_SIZE 1024 #define USLCOM_CONFIG_INDEX 0 /* Request types */ @@ -75,13 +75,13 @@ SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RWTUN, /* Request codes */ #define USLCOM_IFC_ENABLE 0x00 -#define USLCOM_SET_BAUDDIV 0x01 +#define USLCOM_SET_BAUDDIV 0x01 #define USLCOM_SET_LINE_CTL 0x03 #define USLCOM_SET_BREAK 0x05 #define USLCOM_SET_MHS 0x07 #define USLCOM_GET_MDMSTS 0x08 #define USLCOM_SET_FLOW 0x13 -#define USLCOM_SET_BAUDRATE 0x1e +#define USLCOM_SET_BAUDRATE 0x1e #define USLCOM_VENDOR_SPECIFIC 0xff /* USLCOM_IFC_ENABLE values */ @@ -89,7 +89,7 @@ SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RWTUN, #define USLCOM_IFC_ENABLE_EN 0x01 /* USLCOM_SET_MHS/USLCOM_GET_MDMSTS values */ -#define USLCOM_MHS_DTR_ON 0x0001 +#define USLCOM_MHS_DTR_ON 0x0001 #define USLCOM_MHS_DTR_SET 0x0100 #define USLCOM_MHS_RTS_ON 0x0002 #define USLCOM_MHS_RTS_SET 0x0200 @@ -114,11 +114,11 @@ SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RWTUN, #define USLCOM_SET_BREAK_ON 0x01 /* USLCOM_SET_FLOW values - 1st word */ -#define USLCOM_FLOW_DTR_ON 0x00000001 /* DTR static active */ -#define USLCOM_FLOW_CTS_HS 0x00000008 /* CTS handshake */ +#define USLCOM_FLOW_DTR_ON 0x00000001 /* DTR static active */ +#define USLCOM_FLOW_CTS_HS 0x00000008 /* CTS handshake */ /* USLCOM_SET_FLOW values - 2nd word */ -#define USLCOM_FLOW_RTS_ON 0x00000040 /* RTS static active */ -#define USLCOM_FLOW_RTS_HS 0x00000080 /* RTS handshake */ +#define USLCOM_FLOW_RTS_ON 0x00000040 /* RTS static active */ +#define USLCOM_FLOW_RTS_HS 0x00000080 /* RTS handshake */ /* USLCOM_VENDOR_SPECIFIC values */ #define USLCOM_GET_PARTNUM 0x370B @@ -148,10 +148,10 @@ struct uslcom_softc { struct usb_device *sc_udev; struct mtx sc_mtx; - uint8_t sc_msr; - uint8_t sc_lsr; - uint8_t sc_iface_no; - uint8_t sc_partnum; + uint8_t sc_msr; + uint8_t sc_lsr; + uint8_t sc_iface_no; + uint8_t sc_partnum; }; static device_probe_t uslcom_probe; @@ -163,18 +163,18 @@ static usb_callback_t uslcom_write_callback; static usb_callback_t uslcom_read_callback; static usb_callback_t uslcom_control_callback; -static void uslcom_free(struct ucom_softc *); -static void uslcom_open(struct ucom_softc *); -static void uslcom_close(struct ucom_softc *); +static void uslcom_free(struct ucom_softc *); static uint8_t uslcom_get_partnum(struct uslcom_softc *); -static void uslcom_set_dtr(struct ucom_softc *, uint8_t); -static void uslcom_set_rts(struct ucom_softc *, uint8_t); -static void uslcom_set_break(struct ucom_softc *, uint8_t); +static void uslcom_cfg_open(struct ucom_softc *); +static void uslcom_cfg_close(struct ucom_softc *); +static void uslcom_cfg_set_dtr(struct ucom_softc *, uint8_t); +static void uslcom_cfg_set_rts(struct ucom_softc *, uint8_t); +static void uslcom_cfg_set_break(struct ucom_softc *, uint8_t); +static void uslcom_cfg_param(struct ucom_softc *, struct termios *); +static void uslcom_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *); static int uslcom_ioctl(struct ucom_softc *, uint32_t, caddr_t, int, - struct thread *); + struct thread *); static int uslcom_pre_param(struct ucom_softc *, struct termios *); -static void uslcom_param(struct ucom_softc *, struct termios *); -static void uslcom_get_status(struct ucom_softc *, uint8_t *, uint8_t *); static void uslcom_start_read(struct ucom_softc *); static void uslcom_stop_read(struct ucom_softc *); static void uslcom_start_write(struct ucom_softc *); @@ -182,7 +182,6 @@ static void uslcom_stop_write(struct ucom_softc *); static void uslcom_poll(struct ucom_softc *ucom); static const struct usb_config uslcom_config[USLCOM_N_TRANSFER] = { - [USLCOM_BULK_DT_WR] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, @@ -212,15 +211,15 @@ static const struct usb_config uslcom_config[USLCOM_N_TRANSFER] = { }; static struct ucom_callback uslcom_callback = { - .ucom_cfg_open = &uslcom_open, - .ucom_cfg_close = &uslcom_close, - .ucom_cfg_get_status = &uslcom_get_status, - .ucom_cfg_set_dtr = &uslcom_set_dtr, - .ucom_cfg_set_rts = &uslcom_set_rts, - .ucom_cfg_set_break = &uslcom_set_break, - .ucom_ioctl = &uslcom_ioctl, - .ucom_cfg_param = &uslcom_param, + .ucom_cfg_get_status = &uslcom_cfg_get_status, + .ucom_cfg_set_dtr = &uslcom_cfg_set_dtr, + .ucom_cfg_set_rts = &uslcom_cfg_set_rts, + .ucom_cfg_set_break = &uslcom_cfg_set_break, + .ucom_cfg_open = &uslcom_cfg_open, + .ucom_cfg_close = &uslcom_cfg_close, + .ucom_cfg_param = &uslcom_cfg_param, .ucom_pre_param = &uslcom_pre_param, + .ucom_ioctl = &uslcom_ioctl, .ucom_start_read = &uslcom_start_read, .ucom_stop_read = &uslcom_stop_read, .ucom_start_write = &uslcom_start_write, @@ -501,7 +500,7 @@ uslcom_free(struct ucom_softc *ucom) } static void -uslcom_open(struct ucom_softc *ucom) +uslcom_cfg_open(struct ucom_softc *ucom) { struct uslcom_softc *sc = ucom->sc_parent; struct usb_device_request req; @@ -512,7 +511,7 @@ uslcom_open(struct ucom_softc *ucom) USETW(req.wIndex, sc->sc_iface_no); USETW(req.wLength, 0); - if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000)) { DPRINTF("UART enable failed (ignored)\n"); } @@ -522,7 +521,7 @@ uslcom_open(struct ucom_softc *ucom) } static void -uslcom_close(struct ucom_softc *ucom) +uslcom_cfg_close(struct ucom_softc *ucom) { struct uslcom_softc *sc = ucom->sc_parent; struct usb_device_request req; @@ -536,7 +535,7 @@ uslcom_close(struct ucom_softc *ucom) USETW(req.wIndex, sc->sc_iface_no); USETW(req.wLength, 0); - if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000)) { DPRINTF("UART disable failed (ignored)\n"); } @@ -565,13 +564,13 @@ uslcom_get_partnum(struct uslcom_softc *sc) } static void -uslcom_set_dtr(struct ucom_softc *ucom, uint8_t onoff) +uslcom_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff) { - struct uslcom_softc *sc = ucom->sc_parent; + struct uslcom_softc *sc = ucom->sc_parent; struct usb_device_request req; uint16_t ctl; - DPRINTF("onoff = %d\n", onoff); + DPRINTF("onoff = %d\n", onoff); ctl = onoff ? USLCOM_MHS_DTR_ON : 0; ctl |= USLCOM_MHS_DTR_SET; @@ -582,20 +581,20 @@ uslcom_set_dtr(struct ucom_softc *ucom, uint8_t onoff) USETW(req.wIndex, sc->sc_iface_no); USETW(req.wLength, 0); - if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000)) { DPRINTF("Setting DTR failed (ignored)\n"); } } static void -uslcom_set_rts(struct ucom_softc *ucom, uint8_t onoff) +uslcom_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff) { - struct uslcom_softc *sc = ucom->sc_parent; + struct uslcom_softc *sc = ucom->sc_parent; struct usb_device_request req; uint16_t ctl; - DPRINTF("onoff = %d\n", onoff); + DPRINTF("onoff = %d\n", onoff); ctl = onoff ? USLCOM_MHS_RTS_ON : 0; ctl |= USLCOM_MHS_RTS_SET; @@ -606,7 +605,7 @@ uslcom_set_rts(struct ucom_softc *ucom, uint8_t onoff) USETW(req.wIndex, sc->sc_iface_no); USETW(req.wLength, 0); - if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000)) { DPRINTF("Setting DTR failed (ignored)\n"); } @@ -615,13 +614,28 @@ uslcom_set_rts(struct ucom_softc *ucom, uint8_t onoff) static int uslcom_pre_param(struct ucom_softc *ucom, struct termios *t) { - if (t->c_ospeed <= 0 || t->c_ospeed > 921600) + struct uslcom_softc *sc = ucom->sc_parent; + uint32_t maxspeed; + + switch (sc->sc_partnum) { + case USLCOM_PARTNUM_CP2104: + case USLCOM_PARTNUM_CP2105: + maxspeed = 2000000; + break; + case USLCOM_PARTNUM_CP2101: + case USLCOM_PARTNUM_CP2102: + case USLCOM_PARTNUM_CP2103: + default: + maxspeed = 921600; + break; + } + if (t->c_ospeed <= 0 || t->c_ospeed > maxspeed) return (EINVAL); return (0); } static void -uslcom_param(struct ucom_softc *ucom, struct termios *t) +uslcom_cfg_param(struct ucom_softc *ucom, struct termios *t) { struct uslcom_softc *sc = ucom->sc_parent; struct usb_device_request req; @@ -637,9 +651,9 @@ uslcom_param(struct ucom_softc *ucom, struct termios *t) USETW(req.wIndex, sc->sc_iface_no); USETW(req.wLength, sizeof(baudrate)); - if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, &baudrate, 0, 1000)) { - DPRINTF("Set baudrate failed (ignored)\n"); + printf("Set baudrate failed (ignored)\n"); } if (t->c_cflag & CSTOPB) @@ -674,11 +688,11 @@ uslcom_param(struct ucom_softc *ucom, struct termios *t) USETW(req.wIndex, sc->sc_iface_no); USETW(req.wLength, 0); - if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000)) { DPRINTF("Set format failed (ignored)\n"); } - + if (t->c_cflag & CRTSCTS) { flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON | USLCOM_FLOW_CTS_HS); flowctrl[1] = htole32(USLCOM_FLOW_RTS_HS); @@ -694,14 +708,14 @@ uslcom_param(struct ucom_softc *ucom, struct termios *t) USETW(req.wIndex, sc->sc_iface_no); USETW(req.wLength, sizeof(flowctrl)); - if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, flowctrl, 0, 1000)) { DPRINTF("Set flowcontrol failed (ignored)\n"); } } static void -uslcom_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) +uslcom_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) { struct uslcom_softc *sc = ucom->sc_parent; @@ -713,9 +727,9 @@ uslcom_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr) } static void -uslcom_set_break(struct ucom_softc *ucom, uint8_t onoff) +uslcom_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) { - struct uslcom_softc *sc = ucom->sc_parent; + struct uslcom_softc *sc = ucom->sc_parent; struct usb_device_request req; uint16_t brk = onoff ? USLCOM_SET_BREAK_ON : USLCOM_SET_BREAK_OFF; @@ -725,7 +739,7 @@ uslcom_set_break(struct ucom_softc *ucom, uint8_t onoff) USETW(req.wIndex, sc->sc_iface_no); USETW(req.wLength, 0); - if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000)) { DPRINTF("Set BREAK failed (ignored)\n"); } @@ -754,7 +768,7 @@ uslcom_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data, USETW(req.wIndex, sc->sc_iface_no); USETW(req.wLength, sizeof(latch)); - if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, &latch, 0, 1000)) { DPRINTF("Get LATCH failed\n"); error = EIO; @@ -773,7 +787,7 @@ uslcom_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data, USETW(req.wIndex, (*(int *)data)); USETW(req.wLength, 0); - if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, + if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, &req, NULL, 0, 1000)) { DPRINTF("Set LATCH failed\n"); error = EIO; @@ -888,7 +902,7 @@ uslcom_control_callback(struct usb_xfer *xfer, usb_error_t error) USETW(req.wValue, 0); USETW(req.wIndex, sc->sc_iface_no); USETW(req.wLength, sizeof(buf)); - + usbd_xfer_set_frames(xfer, 2); usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); usbd_xfer_set_frame_len(xfer, 1, sizeof(buf)); diff --git a/freebsd/sys/dev/usb/usb_device.c b/freebsd/sys/dev/usb/usb_device.c index 5f1cf409..5d6b9d0f 100644 --- a/freebsd/sys/dev/usb/usb_device.c +++ b/freebsd/sys/dev/usb/usb_device.c @@ -120,7 +120,7 @@ static void usb_cdev_free(struct usb_device *); #ifdef USB_TEMPLATE int usb_template = USB_TEMPLATE; #else -int usb_template; +int usb_template = -1; #endif #ifndef __rtems__ diff --git a/freebsd/sys/dev/usb/usb_ioctl.h b/freebsd/sys/dev/usb/usb_ioctl.h index 7cf90649..fcd31e31 100644 --- a/freebsd/sys/dev/usb/usb_ioctl.h +++ b/freebsd/sys/dev/usb/usb_ioctl.h @@ -69,6 +69,7 @@ enum { USB_TEMP_PHONE, /* USB Phone */ USB_TEMP_SERIALNET, /* USB CDC Ethernet and Modem */ USB_TEMP_MIDI, /* USB MIDI */ + USB_TEMP_MULTI, /* USB Ethernet, serial, and storage */ USB_TEMP_MAX, }; diff --git a/freebsd/sys/dev/usb/usb_request.c b/freebsd/sys/dev/usb/usb_request.c index 6be241c2..cb69ce0e 100644 --- a/freebsd/sys/dev/usb/usb_request.c +++ b/freebsd/sys/dev/usb/usb_request.c @@ -1157,7 +1157,11 @@ usbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf, *s == '+' || *s == ' ' || *s == '.' || - *s == ',') { + *s == ',' || + *s == ':' || + *s == '/' || + *s == '(' || + *s == ')') { /* allowed */ s++; } diff --git a/freebsd/sys/dev/usb/wlan/if_rsu.c b/freebsd/sys/dev/usb/wlan/if_rsu.c index 179de4e5..1cb504cc 100644 --- a/freebsd/sys/dev/usb/wlan/if_rsu.c +++ b/freebsd/sys/dev/usb/wlan/if_rsu.c @@ -890,7 +890,7 @@ rsu_set_multi(struct rsu_softc *sc) TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { ifp = vap->iv_ifp; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { caddr_t dl; uint8_t pos; diff --git a/freebsd/sys/dev/usb/wlan/if_zyd.c b/freebsd/sys/dev/usb/wlan/if_zyd.c index dee03bdd..1835b58b 100644 --- a/freebsd/sys/dev/usb/wlan/if_zyd.c +++ b/freebsd/sys/dev/usb/wlan/if_zyd.c @@ -2002,7 +2002,7 @@ zyd_set_multi(struct zyd_softc *sc) TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { ifp = vap->iv_ifp; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; v = ((uint8_t *)LLADDR((struct sockaddr_dl *) diff --git a/freebsd/sys/i386/include/machine/md_var.h b/freebsd/sys/i386/include/machine/md_var.h index 38d2a828..53e1861c 100644 --- a/freebsd/sys/i386/include/machine/md_var.h +++ b/freebsd/sys/i386/include/machine/md_var.h @@ -45,14 +45,19 @@ extern int szfreebsd4_sigcode; #endif #ifdef COMPAT_43 extern int szosigcode; +extern int sz_lcall_tramp; #endif extern uint32_t *vm_page_dump; +extern vm_offset_t proc0kstack; +extern uintptr_t setidt_disp; struct segment_descriptor; union savefpu; -void bcopyb(const void *from, void *to, size_t len); +int cp_slow0(vm_offset_t uva, size_t len, bool write, + void (*f)(vm_offset_t, void *), void *arg); void cpu_switch_load_gs(void) __asm(__STRING(cpu_switch_load_gs)); +void copyout_init_tramp(void); void doreti_iret(void) __asm(__STRING(doreti_iret)); void doreti_iret_fault(void) __asm(__STRING(doreti_iret_fault)); void doreti_popl_ds(void) __asm(__STRING(doreti_popl_ds)); @@ -71,6 +76,7 @@ void ppro_reenable_apic(void); void set_fsbase(struct thread *td, uint32_t base); void set_gsbase(struct thread *td, uint32_t base); void setidt(int idx, alias_for_inthand_t *func, int typ, int dpl, int selec); +void setidt_nodisp(int idx, uintptr_t func, int typ, int dpl, int selec); union savefpu *get_pcb_user_save_td(struct thread *td); union savefpu *get_pcb_user_save_pcb(struct pcb *pcb); diff --git a/freebsd/sys/kern/init_main.c b/freebsd/sys/kern/init_main.c index 86bc11fc..42afff5e 100644 --- a/freebsd/sys/kern/init_main.c +++ b/freebsd/sys/kern/init_main.c @@ -722,7 +722,9 @@ start_init(void *dummy) vm_offset_t addr; struct execve_args args; int options, error; - char *var, *path, *next, *s; + size_t pathlen; + char *var, *path; + char *free_init_path, *tmp_init_path; char *ucp, **uap, *arg0, *arg1; struct thread *td; struct proc *p; @@ -751,17 +753,12 @@ start_init(void *dummy) strlcpy(init_path, var, sizeof(init_path)); freeenv(var); } + free_init_path = tmp_init_path = strdup(init_path, M_TEMP); - for (path = init_path; *path != '\0'; path = next) { - while (*path == ':') - path++; - if (*path == '\0') - break; - for (next = path; *next != '\0' && *next != ':'; next++) - /* nothing */ ; + while ((path = strsep(&tmp_init_path, ":")) != NULL) { + pathlen = strlen(path) + 1; if (bootverbose) - printf("start_init: trying %.*s\n", (int)(next - path), - path); + printf("start_init: trying %s\n", path); /* * Move out the boot flag argument. @@ -793,9 +790,8 @@ start_init(void *dummy) /* * Move out the file name (also arg 0). */ - (void)subyte(--ucp, 0); - for (s = next - 1; s >= path; s--) - (void)subyte(--ucp, *s); + ucp -= pathlen; + copyout(path, ucp, pathlen); arg0 = ucp; /* @@ -821,13 +817,14 @@ start_init(void *dummy) * to user mode as init! */ if ((error = sys_execve(td, &args)) == EJUSTRETURN) { + free(free_init_path, M_TEMP); TSEXIT(); return; } if (error != ENOENT) - printf("exec %.*s: error %d\n", (int)(next - path), - path, error); + printf("exec %s: error %d\n", path, error); } + free(free_init_path, M_TEMP); printf("init: not found in path %s\n", init_path); panic("no init"); } diff --git a/freebsd/sys/kern/kern_conf.c b/freebsd/sys/kern/kern_conf.c index f62e8e4d..8605cc43 100644 --- a/freebsd/sys/kern/kern_conf.c +++ b/freebsd/sys/kern/kern_conf.c @@ -902,11 +902,11 @@ make_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode, { struct cdev *dev; va_list ap; - int res; + int res __unused; va_start(ap, fmt); res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt, - ap); + ap); va_end(ap); KASSERT(res == 0 && dev != NULL, ("make_dev: failed make_dev_credv (error=%d)", res)); @@ -920,7 +920,7 @@ make_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, { struct cdev *dev; va_list ap; - int res; + int res __unused; va_start(ap, fmt); res = make_dev_credv(0, &dev, devsw, unit, cr, uid, gid, mode, fmt, ap); @@ -1034,7 +1034,7 @@ make_dev_alias(struct cdev *pdev, const char *fmt, ...) { struct cdev *dev; va_list ap; - int res; + int res __unused; va_start(ap, fmt); res = make_dev_alias_v(MAKEDEV_WAITOK, &dev, pdev, fmt, ap); diff --git a/freebsd/sys/kern/kern_event.c b/freebsd/sys/kern/kern_event.c index 905ef23c..33fca549 100644 --- a/freebsd/sys/kern/kern_event.c +++ b/freebsd/sys/kern/kern_event.c @@ -33,7 +33,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_ktrace.h> #include <rtems/bsd/local/opt_kqueue.h> @@ -791,7 +790,7 @@ static void filt_timerdetach(struct knote *kn) { struct kq_timer_cb_data *kc; - unsigned int old; + unsigned int old __unused; kc = kn->kn_ptr.p_v; callout_drain(&kc->c); @@ -1409,7 +1408,6 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int wa struct file *fp; struct knote *kn, *tkn; struct knlist *knl; - cap_rights_t rights; int error, filt, event; int haskqglobal, filedesc_unlock; @@ -1445,8 +1443,7 @@ findkn: if (kev->ident > INT_MAX) error = EBADF; else - error = fget(td, kev->ident, - cap_rights_init(&rights, CAP_EVENT), &fp); + error = fget(td, kev->ident, &cap_event_rights, &fp); if (error) goto done; diff --git a/freebsd/sys/kern/kern_intr.c b/freebsd/sys/kern/kern_intr.c index aa896467..8f6c2a6d 100644 --- a/freebsd/sys/kern/kern_intr.c +++ b/freebsd/sys/kern/kern_intr.c @@ -63,9 +63,6 @@ __FBSDID("$FreeBSD$"); #ifndef __rtems__ #include <machine/md_var.h> #else /* __rtems__ */ - #ifdef INTR_FILTER - #error INTR_FILTER is currently not suppported with RTEMS - #endif #include <machine/rtems-bsd-thread.h> #define RTEMSBSD_SWI_WAKEUP_EVENT RTEMS_EVENT_31 #undef ticks @@ -115,26 +112,13 @@ static struct mtx event_lock; MTX_SYSINIT(intr_event_list, &event_lock, "intr event list", MTX_DEF); static void intr_event_update(struct intr_event *ie); -#ifdef INTR_FILTER -static int intr_event_schedule_thread(struct intr_event *ie, - struct intr_thread *ithd); -static int intr_filter_loop(struct intr_event *ie, - struct trapframe *frame, struct intr_thread **ithd); -static struct intr_thread *ithread_create(const char *name, - struct intr_handler *ih); -#else static int intr_event_schedule_thread(struct intr_event *ie); static struct intr_thread *ithread_create(const char *name); -#endif #ifndef __rtems__ static void ithread_destroy(struct intr_thread *ithread); #endif /* __rtems__ */ static void ithread_execute_handlers(struct proc *p, struct intr_event *ie); -#ifdef INTR_FILTER -static void priv_ithread_execute_handler(struct proc *p, - struct intr_handler *ih); -#endif static void ithread_loop(void *); static void ithread_update(struct intr_thread *ithd); #ifndef __rtems__ @@ -534,7 +518,6 @@ intr_event_destroy(struct intr_event *ie) } #endif /* __rtems__ */ -#ifndef INTR_FILTER static struct intr_thread * ithread_create(const char *name) { @@ -565,36 +548,6 @@ ithread_create(const char *name) CTR2(KTR_INTR, "%s: created %s", __func__, name); return (ithd); } -#else -#ifndef __rtems__ -static struct intr_thread * -ithread_create(const char *name, struct intr_handler *ih) -{ -#ifdef __rtems__ - struct proc *intrproc; -#endif /* __rtems__ */ - struct intr_thread *ithd; - struct thread *td; - int error; - - ithd = malloc(sizeof(struct intr_thread), M_ITHREAD, M_WAITOK | M_ZERO); - - error = kproc_kthread_add(ithread_loop, ih, &intrproc, - &td, RFSTOPPED | RFHIGHPID, - 0, "intr", "%s", name); - if (error) - panic("kproc_create() failed with %d", error); - thread_lock(td); - sched_class(td, PRI_ITHD); - TD_SET_IWAIT(td); - thread_unlock(td); - td->td_pflags |= TDP_ITHREAD; - ithd->it_thread = td; - CTR2(KTR_INTR, "%s: created %s", __func__, name); - return (ithd); -} -#endif /* __rtems__ */ -#endif #ifndef __rtems__ static void @@ -614,7 +567,6 @@ ithread_destroy(struct intr_thread *ithread) } #endif /* __rtems__ */ -#ifndef INTR_FILTER int intr_event_add_handler(struct intr_event *ie, const char *name, driver_filter_t filter, driver_intr_t handler, void *arg, u_char pri, @@ -688,92 +640,6 @@ intr_event_add_handler(struct intr_event *ie, const char *name, *cookiep = ih; return (0); } -#else -#ifndef __rtems__ -int -intr_event_add_handler(struct intr_event *ie, const char *name, - driver_filter_t filter, driver_intr_t handler, void *arg, u_char pri, - enum intr_type flags, void **cookiep) -{ - struct intr_handler *ih, *temp_ih; - struct intr_thread *it; - - if (ie == NULL || name == NULL || (handler == NULL && filter == NULL)) - return (EINVAL); - - /* Allocate and populate an interrupt handler structure. */ - ih = malloc(sizeof(struct intr_handler), M_ITHREAD, M_WAITOK | M_ZERO); - ih->ih_filter = filter; - ih->ih_handler = handler; - ih->ih_argument = arg; - strlcpy(ih->ih_name, name, sizeof(ih->ih_name)); - ih->ih_event = ie; - ih->ih_pri = pri; - if (flags & INTR_EXCL) - ih->ih_flags = IH_EXCLUSIVE; - if (flags & INTR_MPSAFE) - ih->ih_flags |= IH_MPSAFE; - if (flags & INTR_ENTROPY) - ih->ih_flags |= IH_ENTROPY; - - /* We can only have one exclusive handler in a event. */ - mtx_lock(&ie->ie_lock); - if (!TAILQ_EMPTY(&ie->ie_handlers)) { - if ((flags & INTR_EXCL) || - (TAILQ_FIRST(&ie->ie_handlers)->ih_flags & IH_EXCLUSIVE)) { - mtx_unlock(&ie->ie_lock); - free(ih, M_ITHREAD); - return (EINVAL); - } - } - - /* For filtered handlers, create a private ithread to run on. */ - if (filter != NULL && handler != NULL) { - mtx_unlock(&ie->ie_lock); - it = ithread_create("intr: newborn", ih); - mtx_lock(&ie->ie_lock); - it->it_event = ie; - ih->ih_thread = it; - ithread_update(it); /* XXX - do we really need this?!?!? */ - } else { /* Create the global per-event thread if we need one. */ - while (ie->ie_thread == NULL && handler != NULL) { - if (ie->ie_flags & IE_ADDING_THREAD) - msleep(ie, &ie->ie_lock, 0, "ithread", 0); - else { - ie->ie_flags |= IE_ADDING_THREAD; - mtx_unlock(&ie->ie_lock); - it = ithread_create("intr: newborn", ih); - mtx_lock(&ie->ie_lock); - ie->ie_flags &= ~IE_ADDING_THREAD; - ie->ie_thread = it; - it->it_event = ie; - ithread_update(it); - wakeup(ie); - } - } - } - - /* Add the new handler to the event in priority order. */ - TAILQ_FOREACH(temp_ih, &ie->ie_handlers, ih_next) { - if (temp_ih->ih_pri > ih->ih_pri) - break; - } - if (temp_ih == NULL) - TAILQ_INSERT_TAIL(&ie->ie_handlers, ih, ih_next); - else - TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next); - intr_event_update(ie); - - CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name, - ie->ie_name); - mtx_unlock(&ie->ie_lock); - - if (cookiep != NULL) - *cookiep = ih; - return (0); -} -#endif /* __rtems__ */ -#endif #ifndef __rtems__ /* @@ -892,7 +758,6 @@ _intr_drain(int irq) #endif /* __rtems__ */ -#ifndef INTR_FILTER #ifndef __rtems__ int intr_event_remove_handler(void *cookie) @@ -997,9 +862,6 @@ intr_event_schedule_thread(struct intr_event *ie) struct intr_thread *it; struct thread *td; struct thread *ctd; -#ifndef __rtems__ - struct proc *p; -#endif /* __rtems__ */ /* * If no ithread or no handlers, then we have a stray interrupt. @@ -1011,9 +873,6 @@ intr_event_schedule_thread(struct intr_event *ie) ctd = curthread; it = ie->ie_thread; td = it->it_thread; -#ifndef __rtems__ - p = td->td_proc; -#endif /* __rtems__ */ /* * If any of the handlers for this ithread claim to be good @@ -1026,7 +885,7 @@ intr_event_schedule_thread(struct intr_event *ie) } #ifndef __rtems__ - KASSERT(p != NULL, ("ithread %s has no process", ie->ie_name)); + KASSERT(td->td_proc != NULL, ("ithread %s has no process", ie->ie_name)); #endif /* __rtems__ */ /* @@ -1042,13 +901,13 @@ intr_event_schedule_thread(struct intr_event *ie) thread_lock(td); #ifndef __rtems__ if (TD_AWAITING_INTR(td)) { - CTR3(KTR_INTR, "%s: schedule pid %d (%s)", __func__, p->p_pid, + CTR3(KTR_INTR, "%s: schedule pid %d (%s)", __func__, td->td_proc->p_pid, td->td_name); TD_CLR_IWAIT(td); sched_add(td, SRQ_INTR); } else { CTR5(KTR_INTR, "%s: pid %d (%s): it_need %d, state %d", - __func__, p->p_pid, td->td_name, it->it_need, td->td_state); + __func__, td->td_proc->p_pid, td->td_name, it->it_need, td->td_state); } #else /* __rtems__ */ /* Send event to wake the thread up. @@ -1061,174 +920,6 @@ intr_event_schedule_thread(struct intr_event *ie) return (0); } -#else -#ifndef __rtems__ -int -intr_event_remove_handler(void *cookie) -{ - struct intr_handler *handler = (struct intr_handler *)cookie; - struct intr_event *ie; - struct intr_thread *it; -#ifdef INVARIANTS - struct intr_handler *ih; -#endif -#ifdef notyet - int dead; -#endif - - if (handler == NULL) - return (EINVAL); - ie = handler->ih_event; - KASSERT(ie != NULL, - ("interrupt handler \"%s\" has a NULL interrupt event", - handler->ih_name)); - mtx_lock(&ie->ie_lock); - CTR3(KTR_INTR, "%s: removing %s from %s", __func__, handler->ih_name, - ie->ie_name); -#ifdef INVARIANTS - TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) - if (ih == handler) - goto ok; - mtx_unlock(&ie->ie_lock); - panic("interrupt handler \"%s\" not found in interrupt event \"%s\"", - ih->ih_name, ie->ie_name); -ok: -#endif - /* - * If there are no ithreads (per event and per handler), then - * just remove the handler and return. - * XXX: Note that an INTR_FAST handler might be running on another CPU! - */ - if (ie->ie_thread == NULL && handler->ih_thread == NULL) { - TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next); - mtx_unlock(&ie->ie_lock); - free(handler, M_ITHREAD); - return (0); - } - - /* Private or global ithread? */ - it = (handler->ih_thread) ? handler->ih_thread : ie->ie_thread; - /* - * If the interrupt thread is already running, then just mark this - * handler as being dead and let the ithread do the actual removal. - * - * During a cold boot while cold is set, msleep() does not sleep, - * so we have to remove the handler here rather than letting the - * thread do it. - */ - thread_lock(it->it_thread); - if (!TD_AWAITING_INTR(it->it_thread) && !cold) { - handler->ih_flags |= IH_DEAD; - - /* - * Ensure that the thread will process the handler list - * again and remove this handler if it has already passed - * it on the list. - * - * The release part of the following store ensures - * that the update of ih_flags is ordered before the - * it_need setting. See the comment before - * atomic_cmpset_acq(&ithd->it_need, ...) operation in - * the ithread_execute_handlers(). - */ - atomic_store_rel_int(&it->it_need, 1); - } else - TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next); - thread_unlock(it->it_thread); - while (handler->ih_flags & IH_DEAD) - msleep(handler, &ie->ie_lock, 0, "iev_rmh", 0); - /* - * At this point, the handler has been disconnected from the event, - * so we can kill the private ithread if any. - */ - if (handler->ih_thread) { - ithread_destroy(handler->ih_thread); - handler->ih_thread = NULL; - } - intr_event_update(ie); -#ifdef notyet - /* - * XXX: This could be bad in the case of ppbus(8). Also, I think - * this could lead to races of stale data when servicing an - * interrupt. - */ - dead = 1; - TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) { - if (handler != NULL) { - dead = 0; - break; - } - } - if (dead) { - ithread_destroy(ie->ie_thread); - ie->ie_thread = NULL; - } -#endif - mtx_unlock(&ie->ie_lock); - free(handler, M_ITHREAD); - return (0); -} - -static int -intr_event_schedule_thread(struct intr_event *ie, struct intr_thread *it) -{ - struct intr_entropy entropy; - struct thread *td; - struct thread *ctd; -#ifndef __rtems__ - struct proc *p; -#endif /* __rtems__ */ - - /* - * If no ithread or no handlers, then we have a stray interrupt. - */ - if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers) || it == NULL) - return (EINVAL); - - ctd = curthread; - td = it->it_thread; -#ifndef __rtems__ - p = td->td_proc; -#endif /* __rtems__ */ - - /* - * If any of the handlers for this ithread claim to be good - * sources of entropy, then gather some. - */ - if (ie->ie_flags & IE_ENTROPY) { - entropy.event = (uintptr_t)ie; - entropy.td = ctd; - random_harvest_queue(&entropy, sizeof(entropy), 2, RANDOM_INTERRUPT); - } - - KASSERT(p != NULL, ("ithread %s has no process", ie->ie_name)); - - /* - * Set it_need to tell the thread to keep running if it is already - * running. Then, lock the thread and see if we actually need to - * put it on the runqueue. - * - * Use store_rel to arrange that the store to ih_need in - * swi_sched() is before the store to it_need and prepare for - * transfer of this order to loads in the ithread. - */ - atomic_store_rel_int(&it->it_need, 1); - thread_lock(td); - if (TD_AWAITING_INTR(td)) { - CTR3(KTR_INTR, "%s: schedule pid %d (%s)", __func__, p->p_pid, - td->td_name); - TD_CLR_IWAIT(td); - sched_add(td, SRQ_INTR); - } else { - CTR5(KTR_INTR, "%s: pid %d (%s): it_need %d, state %d", - __func__, p->p_pid, td->td_name, it->it_need, td->td_state); - } - thread_unlock(td); - - return (0); -} -#endif /* __rtems__ */ -#endif /* * Allow interrupt event binding for software interrupt handlers -- a no-op, @@ -1283,7 +974,7 @@ swi_sched(void *cookie, int flags) struct intr_handler *ih = (struct intr_handler *)cookie; struct intr_event *ie = ih->ih_event; struct intr_entropy entropy; - int error; + int error __unused; CTR3(KTR_INTR, "swi_sched: %s %s need=%d", ie->ie_name, ih->ih_name, ih->ih_need); @@ -1303,11 +994,7 @@ swi_sched(void *cookie, int flags) #ifndef __rtems__ VM_CNT_INC(v_soft); #endif /* __rtems__ */ -#ifdef INTR_FILTER - error = intr_event_schedule_thread(ie, ie->ie_thread); -#else error = intr_event_schedule_thread(ie); -#endif KASSERT(error == 0, ("stray software interrupt")); } } @@ -1326,38 +1013,6 @@ swi_remove(void *cookie) return (intr_event_remove_handler(cookie)); } -#ifdef INTR_FILTER -static void -priv_ithread_execute_handler(struct proc *p, struct intr_handler *ih) -{ - struct intr_event *ie; - - ie = ih->ih_event; - /* - * If this handler is marked for death, remove it from - * the list of handlers and wake up the sleeper. - */ - if (ih->ih_flags & IH_DEAD) { - mtx_lock(&ie->ie_lock); - TAILQ_REMOVE(&ie->ie_handlers, ih, ih_next); - ih->ih_flags &= ~IH_DEAD; - wakeup(ih); - mtx_unlock(&ie->ie_lock); - return; - } - - /* Execute this handler. */ - CTR6(KTR_INTR, "%s: pid %d exec %p(%p) for %s flg=%x", - __func__, p->p_pid, (void *)ih->ih_handler, ih->ih_argument, - ih->ih_name, ih->ih_flags); - - if (!(ih->ih_flags & IH_MPSAFE)) - mtx_lock(&Giant); - ih->ih_handler(ih->ih_argument); - if (!(ih->ih_flags & IH_MPSAFE)) - mtx_unlock(&Giant); -} -#endif #endif /* __rtems__ */ /* @@ -1461,7 +1116,6 @@ ithread_execute_handlers(struct proc *p, struct intr_event *ie) ie->ie_post_ithread(ie->ie_source); } -#ifndef INTR_FILTER /* * This is the main code for interrupt threads. */ @@ -1571,7 +1225,7 @@ intr_event_handle(struct intr_event *ie, struct trapframe *frame) struct intr_handler *ih; struct trapframe *oldframe; struct thread *td; - int error, ret, thread; + int ret, thread; td = curthread; @@ -1644,233 +1298,15 @@ intr_event_handle(struct intr_event *ie, struct trapframe *frame) /* Schedule the ithread if needed. */ if (thread) { - error = intr_event_schedule_thread(ie); - KASSERT(error == 0, ("bad stray interrupt")); - } - critical_exit(); - td->td_intr_nesting_level--; - return (0); -} -#endif /* __rtems__ */ -#else -#ifndef __rtems__ -/* - * This is the main code for interrupt threads. - */ -static void -ithread_loop(void *arg) -{ - struct intr_thread *ithd; - struct intr_handler *ih; - struct intr_event *ie; - struct thread *td; - struct proc *p; - int priv; - int wake; - - td = curthread; - p = td->td_proc; - ih = (struct intr_handler *)arg; - priv = (ih->ih_thread != NULL) ? 1 : 0; - ithd = (priv) ? ih->ih_thread : ih->ih_event->ie_thread; - KASSERT(ithd->it_thread == td, - ("%s: ithread and proc linkage out of sync", __func__)); - ie = ithd->it_event; - ie->ie_count = 0; - wake = 0; - - /* - * As long as we have interrupts outstanding, go through the - * list of handlers, giving each one a go at it. - */ - for (;;) { - /* - * If we are an orphaned thread, then just die. - */ - if (ithd->it_flags & IT_DEAD) { - CTR3(KTR_INTR, "%s: pid %d (%s) exiting", __func__, - p->p_pid, td->td_name); - free(ithd, M_ITHREAD); - kthread_exit(); - } + int error __unused; - /* - * Service interrupts. If another interrupt arrives while - * we are running, it will set it_need to note that we - * should make another pass. - * - * The load_acq part of the following cmpset ensures - * that the load of ih_need in ithread_execute_handlers() - * is ordered after the load of it_need here. - */ - while (atomic_cmpset_acq_int(&ithd->it_need, 1, 0) != 0) { - if (priv) - priv_ithread_execute_handler(p, ih); - else - ithread_execute_handlers(p, ie); - } - WITNESS_WARN(WARN_PANIC, NULL, "suspending ithread"); - mtx_assert(&Giant, MA_NOTOWNED); - - /* - * Processed all our interrupts. Now get the sched - * lock. This may take a while and it_need may get - * set again, so we have to check it again. - */ - thread_lock(td); - if (atomic_load_acq_int(&ithd->it_need) == 0 && - (ithd->it_flags & (IT_DEAD | IT_WAIT)) == 0) { - TD_SET_IWAIT(td); - ie->ie_count = 0; - mi_switch(SW_VOL | SWT_IWAIT, NULL); - } - if (ithd->it_flags & IT_WAIT) { - wake = 1; - ithd->it_flags &= ~IT_WAIT; - } - thread_unlock(td); - if (wake) { - wakeup(ithd); - wake = 0; - } - } -} - -/* - * Main loop for interrupt filter. - * - * Some architectures (i386, amd64 and arm) require the optional frame - * parameter, and use it as the main argument for fast handler execution - * when ih_argument == NULL. - * - * Return value: - * o FILTER_STRAY: No filter recognized the event, and no - * filter-less handler is registered on this - * line. - * o FILTER_HANDLED: A filter claimed the event and served it. - * o FILTER_SCHEDULE_THREAD: No filter claimed the event, but there's at - * least one filter-less handler on this line. - * o FILTER_HANDLED | - * FILTER_SCHEDULE_THREAD: A filter claimed the event, and asked for - * scheduling the per-handler ithread. - * - * In case an ithread has to be scheduled, in *ithd there will be a - * pointer to a struct intr_thread containing the thread to be - * scheduled. - */ - -static int -intr_filter_loop(struct intr_event *ie, struct trapframe *frame, - struct intr_thread **ithd) -{ - struct intr_handler *ih; - void *arg; - int ret, thread_only; - - ret = 0; - thread_only = 0; - TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) { - /* - * Execute fast interrupt handlers directly. - * To support clock handlers, if a handler registers - * with a NULL argument, then we pass it a pointer to - * a trapframe as its argument. - */ - arg = ((ih->ih_argument == NULL) ? frame : ih->ih_argument); - - CTR5(KTR_INTR, "%s: exec %p/%p(%p) for %s", __func__, - ih->ih_filter, ih->ih_handler, arg, ih->ih_name); - - if (ih->ih_filter != NULL) - ret = ih->ih_filter(arg); - else { - thread_only = 1; - continue; - } - KASSERT(ret == FILTER_STRAY || - ((ret & (FILTER_SCHEDULE_THREAD | FILTER_HANDLED)) != 0 && - (ret & ~(FILTER_SCHEDULE_THREAD | FILTER_HANDLED)) == 0), - ("%s: incorrect return value %#x from %s", __func__, ret, - ih->ih_name)); - if (ret & FILTER_STRAY) - continue; - else { - *ithd = ih->ih_thread; - return (ret); - } - } - - /* - * No filters handled the interrupt and we have at least - * one handler without a filter. In this case, we schedule - * all of the filter-less handlers to run in the ithread. - */ - if (thread_only) { - *ithd = ie->ie_thread; - return (FILTER_SCHEDULE_THREAD); - } - return (FILTER_STRAY); -} - -/* - * Main interrupt handling body. - * - * Input: - * o ie: the event connected to this interrupt. - * o frame: some archs (i.e. i386) pass a frame to some. - * handlers as their main argument. - * Return value: - * o 0: everything ok. - * o EINVAL: stray interrupt. - */ -int -intr_event_handle(struct intr_event *ie, struct trapframe *frame) -{ - struct intr_thread *ithd; - struct trapframe *oldframe; - struct thread *td; - int thread; - - ithd = NULL; - td = curthread; - - if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers)) - return (EINVAL); - - td->td_intr_nesting_level++; - thread = 0; - critical_enter(); - oldframe = td->td_intr_frame; - td->td_intr_frame = frame; - thread = intr_filter_loop(ie, frame, &ithd); - if (thread & FILTER_HANDLED) { - if (ie->ie_post_filter != NULL) - ie->ie_post_filter(ie->ie_source); - } else { - if (ie->ie_pre_ithread != NULL) - ie->ie_pre_ithread(ie->ie_source); + error = intr_event_schedule_thread(ie); + KASSERT(error == 0, ("bad stray interrupt")); } - td->td_intr_frame = oldframe; critical_exit(); - - /* Interrupt storm logic */ - if (thread & FILTER_STRAY) { - ie->ie_count++; - if (ie->ie_count < intr_storm_threshold) - printf("Interrupt stray detection not present\n"); - } - - /* Schedule an ithread if needed. */ - if (thread & FILTER_SCHEDULE_THREAD) { - if (intr_event_schedule_thread(ie, ithd) != 0) - panic("%s: impossible stray interrupt", __func__); - } td->td_intr_nesting_level--; return (0); } -#endif /* __rtems__ */ -#endif -#ifndef __rtems__ #ifdef DDB /* diff --git a/freebsd/sys/kern/kern_linker.c b/freebsd/sys/kern/kern_linker.c index c19071a6..197ee5bb 100644 --- a/freebsd/sys/kern/kern_linker.c +++ b/freebsd/sys/kern/kern_linker.c @@ -168,7 +168,7 @@ linker_init(void *arg) TAILQ_INIT(&linker_files); } -SYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0); +SYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, NULL); static void linker_stop_class_add(void *arg) @@ -426,7 +426,7 @@ linker_init_kernel_modules(void) } SYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, - 0); + NULL); #ifndef __rtems__ static int @@ -1700,7 +1700,7 @@ fail: /* woohoo! we made it! */ } -SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); +SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, NULL); /* * Handle preload files that failed to load any modules. @@ -1735,7 +1735,7 @@ linker_preload_finish(void *arg) * becomes runnable in SI_SUB_KTHREAD_INIT, so go slightly before that. */ SYSINIT(preload_finish, SI_SUB_KTHREAD_INIT - 100, SI_ORDER_MIDDLE, - linker_preload_finish, 0); + linker_preload_finish, NULL); /* * Search for a not-loaded module by name. diff --git a/freebsd/sys/kern/kern_mbuf.c b/freebsd/sys/kern/kern_mbuf.c index 78e3528f..13467dfe 100644 --- a/freebsd/sys/kern/kern_mbuf.c +++ b/freebsd/sys/kern/kern_mbuf.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/domain.h> #include <sys/eventhandler.h> #include <sys/kernel.h> +#include <sys/limits.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/protosw.h> @@ -393,6 +394,199 @@ mbuf_init(void *dummy) } SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbuf_init, NULL); +#ifdef NETDUMP +/* + * netdump makes use of a pre-allocated pool of mbufs and clusters. When + * netdump is configured, we initialize a set of UMA cache zones which return + * items from this pool. At panic-time, the regular UMA zone pointers are + * overwritten with those of the cache zones so that drivers may allocate and + * free mbufs and clusters without attempting to allocate physical memory. + * + * We keep mbufs and clusters in a pair of mbuf queues. In particular, for + * the purpose of caching clusters, we treat them as mbufs. + */ +static struct mbufq nd_mbufq = + { STAILQ_HEAD_INITIALIZER(nd_mbufq.mq_head), 0, INT_MAX }; +static struct mbufq nd_clustq = + { STAILQ_HEAD_INITIALIZER(nd_clustq.mq_head), 0, INT_MAX }; + +static int nd_clsize; +static uma_zone_t nd_zone_mbuf; +static uma_zone_t nd_zone_clust; +static uma_zone_t nd_zone_pack; + +static int +nd_buf_import(void *arg, void **store, int count, int domain __unused, + int flags) +{ + struct mbufq *q; + struct mbuf *m; + int i; + + q = arg; + + for (i = 0; i < count; i++) { + m = mbufq_dequeue(q); + if (m == NULL) + break; + trash_init(m, q == &nd_mbufq ? MSIZE : nd_clsize, flags); + store[i] = m; + } + return (i); +} + +static void +nd_buf_release(void *arg, void **store, int count) +{ + struct mbufq *q; + struct mbuf *m; + int i; + + q = arg; + + for (i = 0; i < count; i++) { + m = store[i]; + (void)mbufq_enqueue(q, m); + } +} + +static int +nd_pack_import(void *arg __unused, void **store, int count, int domain __unused, + int flags __unused) +{ + struct mbuf *m; + void *clust; + int i; + + for (i = 0; i < count; i++) { + m = m_get(MT_DATA, M_NOWAIT); + if (m == NULL) + break; + clust = uma_zalloc(nd_zone_clust, M_NOWAIT); + if (clust == NULL) { + m_free(m); + break; + } + mb_ctor_clust(clust, nd_clsize, m, 0); + store[i] = m; + } + return (i); +} + +static void +nd_pack_release(void *arg __unused, void **store, int count) +{ + struct mbuf *m; + void *clust; + int i; + + for (i = 0; i < count; i++) { + m = store[i]; + clust = m->m_ext.ext_buf; + uma_zfree(nd_zone_clust, clust); + uma_zfree(nd_zone_mbuf, m); + } +} + +/* + * Free the pre-allocated mbufs and clusters reserved for netdump, and destroy + * the corresponding UMA cache zones. + */ +void +netdump_mbuf_drain(void) +{ + struct mbuf *m; + void *item; + + if (nd_zone_mbuf != NULL) { + uma_zdestroy(nd_zone_mbuf); + nd_zone_mbuf = NULL; + } + if (nd_zone_clust != NULL) { + uma_zdestroy(nd_zone_clust); + nd_zone_clust = NULL; + } + if (nd_zone_pack != NULL) { + uma_zdestroy(nd_zone_pack); + nd_zone_pack = NULL; + } + + while ((m = mbufq_dequeue(&nd_mbufq)) != NULL) + m_free(m); + while ((item = mbufq_dequeue(&nd_clustq)) != NULL) + uma_zfree(m_getzone(nd_clsize), item); +} + +/* + * Callback invoked immediately prior to starting a netdump. + */ +void +netdump_mbuf_dump(void) +{ + + /* + * All cluster zones return buffers of the size requested by the + * drivers. It's up to the driver to reinitialize the zones if the + * MTU of a netdump-enabled interface changes. + */ + printf("netdump: overwriting mbuf zone pointers\n"); + zone_mbuf = nd_zone_mbuf; + zone_clust = nd_zone_clust; + zone_pack = nd_zone_pack; + zone_jumbop = nd_zone_clust; + zone_jumbo9 = nd_zone_clust; + zone_jumbo16 = nd_zone_clust; +} + +/* + * Reinitialize the netdump mbuf+cluster pool and cache zones. + */ +void +netdump_mbuf_reinit(int nmbuf, int nclust, int clsize) +{ + struct mbuf *m; + void *item; + + netdump_mbuf_drain(); + + nd_clsize = clsize; + + nd_zone_mbuf = uma_zcache_create("netdump_" MBUF_MEM_NAME, + MSIZE, mb_ctor_mbuf, mb_dtor_mbuf, +#ifdef INVARIANTS + trash_init, trash_fini, +#else + NULL, NULL, +#endif + nd_buf_import, nd_buf_release, + &nd_mbufq, UMA_ZONE_NOBUCKET); + + nd_zone_clust = uma_zcache_create("netdump_" MBUF_CLUSTER_MEM_NAME, + clsize, mb_ctor_clust, +#ifdef INVARIANTS + trash_dtor, trash_init, trash_fini, +#else + NULL, NULL, NULL, +#endif + nd_buf_import, nd_buf_release, + &nd_clustq, UMA_ZONE_NOBUCKET); + + nd_zone_pack = uma_zcache_create("netdump_" MBUF_PACKET_MEM_NAME, + MCLBYTES, mb_ctor_pack, mb_dtor_pack, NULL, NULL, + nd_pack_import, nd_pack_release, + NULL, UMA_ZONE_NOBUCKET); + + while (nmbuf-- > 0) { + m = m_get(MT_DATA, M_WAITOK); + uma_zfree(nd_zone_mbuf, m); + } + while (nclust-- > 0) { + item = uma_zalloc(m_getzone(nd_clsize), M_WAITOK); + uma_zfree(nd_zone_clust, item); + } +} +#endif /* NETDUMP */ + /* * UMA backend page allocator for the jumbo frame zones. * @@ -702,18 +896,18 @@ mb_free_ext(struct mbuf *m) case EXT_MOD_TYPE: case EXT_DISPOSABLE: KASSERT(mref->m_ext.ext_free != NULL, - ("%s: ext_free not set", __func__)); + ("%s: ext_free not set", __func__)); mref->m_ext.ext_free(mref); uma_zfree(zone_mbuf, mref); break; case EXT_EXTREF: KASSERT(m->m_ext.ext_free != NULL, - ("%s: ext_free not set", __func__)); + ("%s: ext_free not set", __func__)); m->m_ext.ext_free(m); break; default: KASSERT(m->m_ext.ext_type == 0, - ("%s: unknown ext_type", __func__)); + ("%s: unknown ext_type", __func__)); } } diff --git a/freebsd/sys/kern/kern_mib.c b/freebsd/sys/kern/kern_mib.c index 3fd48334..cacf497d 100644 --- a/freebsd/sys/kern/kern_mib.c +++ b/freebsd/sys/kern/kern_mib.c @@ -42,7 +42,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_posix.h> #include <rtems/bsd/local/opt_config.h> @@ -100,11 +99,6 @@ SYSCTL_ROOT_NODE(OID_AUTO, regression, CTLFLAG_RW, 0, "Regression test MIB"); #endif -#ifdef EXT_RESOURCES -SYSCTL_ROOT_NODE(OID_AUTO, clock, CTLFLAG_RW, 0, - "Clocks"); -#endif - SYSCTL_STRING(_kern, OID_AUTO, ident, CTLFLAG_RD|CTLFLAG_MPSAFE, kern_ident, 0, "Kernel identifier"); diff --git a/freebsd/sys/kern/kern_module.c b/freebsd/sys/kern/kern_module.c index 58a2f83a..81686061 100644 --- a/freebsd/sys/kern/kern_module.c +++ b/freebsd/sys/kern/kern_module.c @@ -28,8 +28,6 @@ * SUCH DAMAGE. */ -#include <rtems/bsd/local/opt_compat.h> - #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -99,7 +97,7 @@ module_init(void *arg) #endif /* __rtems__ */ } -SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0); +SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, NULL); #ifndef __rtems__ static void diff --git a/freebsd/sys/kern/kern_synch.c b/freebsd/sys/kern/kern_synch.c index 59f00ed4..9c0d1206 100644 --- a/freebsd/sys/kern/kern_synch.c +++ b/freebsd/sys/kern/kern_synch.c @@ -117,7 +117,7 @@ sleepinit(void *unused) * vmem tries to lock the sleepq mutexes when free'ing kva, so make sure * it is available. */ -SYSINIT(sleepinit, SI_SUB_KMEM, SI_ORDER_ANY, sleepinit, 0); +SYSINIT(sleepinit, SI_SUB_KMEM, SI_ORDER_ANY, sleepinit, NULL); /* * General sleep call. Suspends the current thread until a wakeup is @@ -160,6 +160,7 @@ _sleep(void *ident, struct lock_object *lock, int priority, KASSERT(ident != NULL, ("_sleep: NULL ident")); #ifndef __rtems__ KASSERT(TD_IS_RUNNING(td), ("_sleep: curthread not running")); + KASSERT(td->td_epochnest == 0, ("sleeping in an epoch section")); if (priority & PDROP) KASSERT(lock != NULL && lock != &Giant.lock_object, ("PDROP requires a non-Giant lock")); @@ -465,8 +466,9 @@ mi_switch(int flags, struct thread *newtd) CTR4(KTR_PROC, "mi_switch: old thread %ld (td_sched %p, pid %ld, %s)", td->td_tid, td_get_sched(td), td->td_proc->p_pid, td->td_name); #ifdef KDTRACE_HOOKS - if ((flags & SW_PREEMPT) != 0 || ((flags & SW_INVOL) != 0 && - (flags & SW_TYPE_MASK) == SWT_NEEDRESCHED)) + if (__predict_false(sdt_probes_enabled) && + ((flags & SW_PREEMPT) != 0 || ((flags & SW_INVOL) != 0 && + (flags & SW_TYPE_MASK) == SWT_NEEDRESCHED))) SDT_PROBE0(sched, , , preempt); #endif sched_switch(td, newtd, flags); diff --git a/freebsd/sys/kern/kern_sysctl.c b/freebsd/sys/kern/kern_sysctl.c index 8b27a5c6..b4e9711f 100644 --- a/freebsd/sys/kern/kern_sysctl.c +++ b/freebsd/sys/kern/kern_sysctl.c @@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_capsicum.h> -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_ktrace.h> #include <sys/param.h> @@ -928,7 +927,7 @@ sysctl_register_all(void *arg) sysctl_register_oid(*oidp); SYSCTL_WUNLOCK(); } -SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_FIRST, sysctl_register_all, 0); +SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_FIRST, sysctl_register_all, NULL); /* * "Staff-functions" diff --git a/freebsd/sys/kern/subr_bus.c b/freebsd/sys/kern/subr_bus.c index 8076e7e3..0626ec0a 100644 --- a/freebsd/sys/kern/subr_bus.c +++ b/freebsd/sys/kern/subr_bus.c @@ -1863,6 +1863,8 @@ make_device(device_t parent, const char *name, int unit) return (NULL); } } + if (parent != NULL && device_has_quiet_children(parent)) + dev->flags |= DF_QUIET | DF_QUIET_CHILDREN; dev->ivars = NULL; dev->softc = NULL; @@ -2688,6 +2690,15 @@ device_quiet(device_t dev) } /** + * @brief Set the DF_QUIET_CHILDREN flag for the device + */ +void +device_quiet_children(device_t dev) +{ + dev->flags |= DF_QUIET_CHILDREN; +} + +/** * @brief Clear the DF_QUIET flag for the device */ void @@ -2697,6 +2708,15 @@ device_verbose(device_t dev) } /** + * @brief Return non-zero if the DF_QUIET_CHIDLREN flag is set on the device + */ +int +device_has_quiet_children(device_t dev) +{ + return ((dev->flags & DF_QUIET_CHILDREN) != 0); +} + +/** * @brief Return non-zero if the DF_QUIET flag is set on the device */ int @@ -3760,7 +3780,11 @@ bus_generic_detach(device_t dev) if (dev->state != DS_ATTACHED) return (EBUSY); - TAILQ_FOREACH(child, &dev->children, link) { + /* + * Detach children in the reverse order. + * See bus_generic_suspend for details. + */ + TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) { if ((error = device_detach(child)) != 0) return (error); } @@ -3780,7 +3804,11 @@ bus_generic_shutdown(device_t dev) { device_t child; - TAILQ_FOREACH(child, &dev->children, link) { + /* + * Shut down children in the reverse order. + * See bus_generic_suspend for details. + */ + TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) { device_shutdown(child); } @@ -3833,15 +3861,23 @@ int bus_generic_suspend(device_t dev) { int error; - device_t child, child2; + device_t child; - TAILQ_FOREACH(child, &dev->children, link) { + /* + * Suspend children in the reverse order. + * For most buses all children are equal, so the order does not matter. + * Other buses, such as acpi, carefully order their child devices to + * express implicit dependencies between them. For such buses it is + * safer to bring down devices in the reverse order. + */ + TAILQ_FOREACH_REVERSE(child, &dev->children, device_list, link) { error = BUS_SUSPEND_CHILD(dev, child); - if (error) { - for (child2 = TAILQ_FIRST(&dev->children); - child2 && child2 != child; - child2 = TAILQ_NEXT(child2, link)) - BUS_RESUME_CHILD(dev, child2); + if (error != 0) { + child = TAILQ_NEXT(child, link); + if (child != NULL) { + TAILQ_FOREACH_FROM(child, &dev->children, link) + BUS_RESUME_CHILD(dev, child); + } return (error); } } @@ -5285,8 +5321,9 @@ sysctl_devices(SYSCTL_HANDLER_ARGS) u_int namelen = arg2; int index; device_t dev; - struct u_device udev; /* XXX this is a bit big */ + struct u_device *udev; int error; + char *walker, *ep; if (namelen != 2) return (EINVAL); @@ -5307,24 +5344,45 @@ sysctl_devices(SYSCTL_HANDLER_ARGS) return (ENOENT); /* - * Populate the return array. + * Populate the return item, careful not to overflow the buffer. */ - bzero(&udev, sizeof(udev)); - udev.dv_handle = (uintptr_t)dev; - udev.dv_parent = (uintptr_t)dev->parent; - if (dev->nameunit != NULL) - strlcpy(udev.dv_name, dev->nameunit, sizeof(udev.dv_name)); - if (dev->desc != NULL) - strlcpy(udev.dv_desc, dev->desc, sizeof(udev.dv_desc)); - if (dev->driver != NULL && dev->driver->name != NULL) - strlcpy(udev.dv_drivername, dev->driver->name, - sizeof(udev.dv_drivername)); - bus_child_pnpinfo_str(dev, udev.dv_pnpinfo, sizeof(udev.dv_pnpinfo)); - bus_child_location_str(dev, udev.dv_location, sizeof(udev.dv_location)); - udev.dv_devflags = dev->devflags; - udev.dv_flags = dev->flags; - udev.dv_state = dev->state; - error = SYSCTL_OUT(req, &udev, sizeof(udev)); + udev = malloc(sizeof(*udev), M_BUS, M_WAITOK | M_ZERO); + if (udev == NULL) + return (ENOMEM); + udev->dv_handle = (uintptr_t)dev; + udev->dv_parent = (uintptr_t)dev->parent; + udev->dv_devflags = dev->devflags; + udev->dv_flags = dev->flags; + udev->dv_state = dev->state; + walker = udev->dv_fields; + ep = walker + sizeof(udev->dv_fields); +#define CP(src) \ + if ((src) == NULL) \ + *walker++ = '\0'; \ + else { \ + strlcpy(walker, (src), ep - walker); \ + walker += strlen(walker) + 1; \ + } \ + if (walker >= ep) \ + break; + + do { + CP(dev->nameunit); + CP(dev->desc); + CP(dev->driver != NULL ? dev->driver->name : NULL); + bus_child_pnpinfo_str(dev, walker, ep - walker); + walker += strlen(walker) + 1; + if (walker >= ep) + break; + bus_child_location_str(dev, walker, ep - walker); + walker += strlen(walker) + 1; + if (walker >= ep) + break; + *walker++ = '\0'; + } while (0); +#undef CP + error = SYSCTL_OUT(req, udev, sizeof(*udev)); + free(udev, M_BUS); return (error); } diff --git a/freebsd/sys/kern/subr_gtaskqueue.c b/freebsd/sys/kern/subr_gtaskqueue.c new file mode 100644 index 00000000..aa5c922d --- /dev/null +++ b/freebsd/sys/kern/subr_gtaskqueue.c @@ -0,0 +1,1059 @@ +#include <machine/rtems-bsd-kernel-space.h> + +/*- + * Copyright (c) 2000 Doug Rabson + * Copyright (c) 2014 Jeff Roberson + * Copyright (c) 2016 Matthew Macy + * 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 <sys/systm.h> +#include <sys/bus.h> +#include <sys/cpuset.h> +#include <sys/interrupt.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/libkern.h> +#include <sys/limits.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/proc.h> +#include <sys/sched.h> +#include <sys/smp.h> +#include <sys/gtaskqueue.h> +#include <rtems/bsd/sys/unistd.h> +#include <machine/stdarg.h> +#ifdef __rtems__ +#include <machine/rtems-bsd-thread.h> +#endif /* __rtems__ */ + +static MALLOC_DEFINE(M_GTASKQUEUE, "gtaskqueue", "Group Task Queues"); +static void gtaskqueue_thread_enqueue(void *); +static void gtaskqueue_thread_loop(void *arg); + +TASKQGROUP_DEFINE(softirq, mp_ncpus, 1); +TASKQGROUP_DEFINE(config, 1, 1); + +struct gtaskqueue_busy { + struct gtask *tb_running; + TAILQ_ENTRY(gtaskqueue_busy) tb_link; +}; + +static struct gtask * const TB_DRAIN_WAITER = (struct gtask *)0x1; + +struct gtaskqueue { + STAILQ_HEAD(, gtask) tq_queue; + gtaskqueue_enqueue_fn tq_enqueue; + void *tq_context; + char *tq_name; + TAILQ_HEAD(, gtaskqueue_busy) tq_active; + struct mtx tq_mutex; + struct thread **tq_threads; + int tq_tcount; + int tq_spin; + int tq_flags; + int tq_callouts; + taskqueue_callback_fn tq_callbacks[TASKQUEUE_NUM_CALLBACKS]; + void *tq_cb_contexts[TASKQUEUE_NUM_CALLBACKS]; +}; + +#define TQ_FLAGS_ACTIVE (1 << 0) +#define TQ_FLAGS_BLOCKED (1 << 1) +#define TQ_FLAGS_UNLOCKED_ENQUEUE (1 << 2) + +#define DT_CALLOUT_ARMED (1 << 0) + +#define TQ_LOCK(tq) \ + do { \ + if ((tq)->tq_spin) \ + mtx_lock_spin(&(tq)->tq_mutex); \ + else \ + mtx_lock(&(tq)->tq_mutex); \ + } while (0) +#define TQ_ASSERT_LOCKED(tq) mtx_assert(&(tq)->tq_mutex, MA_OWNED) + +#define TQ_UNLOCK(tq) \ + do { \ + if ((tq)->tq_spin) \ + mtx_unlock_spin(&(tq)->tq_mutex); \ + else \ + mtx_unlock(&(tq)->tq_mutex); \ + } while (0) +#define TQ_ASSERT_UNLOCKED(tq) mtx_assert(&(tq)->tq_mutex, MA_NOTOWNED) + +#ifdef INVARIANTS +static void +gtask_dump(struct gtask *gtask) +{ + printf("gtask: %p ta_flags=%x ta_priority=%d ta_func=%p ta_context=%p\n", + gtask, gtask->ta_flags, gtask->ta_priority, gtask->ta_func, gtask->ta_context); +} +#endif + +static __inline int +TQ_SLEEP(struct gtaskqueue *tq, void *p, struct mtx *m, int pri, const char *wm, + int t) +{ + if (tq->tq_spin) + return (msleep_spin(p, m, wm, t)); + return (msleep(p, m, pri, wm, t)); +} + +static struct gtaskqueue * +_gtaskqueue_create(const char *name, int mflags, + taskqueue_enqueue_fn enqueue, void *context, + int mtxflags, const char *mtxname __unused) +{ + struct gtaskqueue *queue; + char *tq_name; + + tq_name = malloc(TASKQUEUE_NAMELEN, M_GTASKQUEUE, mflags | M_ZERO); + if (!tq_name) + return (NULL); + + snprintf(tq_name, TASKQUEUE_NAMELEN, "%s", (name) ? name : "taskqueue"); + + queue = malloc(sizeof(struct gtaskqueue), M_GTASKQUEUE, mflags | M_ZERO); + if (!queue) { + free(tq_name, M_GTASKQUEUE); + return (NULL); + } + + STAILQ_INIT(&queue->tq_queue); + TAILQ_INIT(&queue->tq_active); + queue->tq_enqueue = enqueue; + queue->tq_context = context; + queue->tq_name = tq_name; + queue->tq_spin = (mtxflags & MTX_SPIN) != 0; + queue->tq_flags |= TQ_FLAGS_ACTIVE; + if (enqueue == gtaskqueue_thread_enqueue) + queue->tq_flags |= TQ_FLAGS_UNLOCKED_ENQUEUE; + mtx_init(&queue->tq_mutex, tq_name, NULL, mtxflags); + + return (queue); +} + + +/* + * Signal a taskqueue thread to terminate. + */ +static void +gtaskqueue_terminate(struct thread **pp, struct gtaskqueue *tq) +{ + + while (tq->tq_tcount > 0 || tq->tq_callouts > 0) { + wakeup(tq); + TQ_SLEEP(tq, pp, &tq->tq_mutex, PWAIT, "taskqueue_destroy", 0); + } +} + +static void +gtaskqueue_free(struct gtaskqueue *queue) +{ + + TQ_LOCK(queue); + queue->tq_flags &= ~TQ_FLAGS_ACTIVE; + gtaskqueue_terminate(queue->tq_threads, queue); + KASSERT(TAILQ_EMPTY(&queue->tq_active), ("Tasks still running?")); + KASSERT(queue->tq_callouts == 0, ("Armed timeout tasks")); + mtx_destroy(&queue->tq_mutex); + free(queue->tq_threads, M_GTASKQUEUE); + free(queue->tq_name, M_GTASKQUEUE); + free(queue, M_GTASKQUEUE); +} + +int +grouptaskqueue_enqueue(struct gtaskqueue *queue, struct gtask *gtask) +{ +#ifdef INVARIANTS + if (queue == NULL) { + gtask_dump(gtask); + panic("queue == NULL"); + } +#endif + TQ_LOCK(queue); + if (gtask->ta_flags & TASK_ENQUEUED) { + TQ_UNLOCK(queue); + return (0); + } + STAILQ_INSERT_TAIL(&queue->tq_queue, gtask, ta_link); + gtask->ta_flags |= TASK_ENQUEUED; + TQ_UNLOCK(queue); + if ((queue->tq_flags & TQ_FLAGS_BLOCKED) == 0) + queue->tq_enqueue(queue->tq_context); + return (0); +} + +static void +gtaskqueue_task_nop_fn(void *context) +{ +} + +/* + * Block until all currently queued tasks in this taskqueue + * have begun execution. Tasks queued during execution of + * this function are ignored. + */ +static void +gtaskqueue_drain_tq_queue(struct gtaskqueue *queue) +{ + struct gtask t_barrier; + + if (STAILQ_EMPTY(&queue->tq_queue)) + return; + + /* + * Enqueue our barrier after all current tasks, but with + * the highest priority so that newly queued tasks cannot + * pass it. Because of the high priority, we can not use + * taskqueue_enqueue_locked directly (which drops the lock + * anyway) so just insert it at tail while we have the + * queue lock. + */ + GTASK_INIT(&t_barrier, 0, USHRT_MAX, gtaskqueue_task_nop_fn, &t_barrier); + STAILQ_INSERT_TAIL(&queue->tq_queue, &t_barrier, ta_link); + t_barrier.ta_flags |= TASK_ENQUEUED; + + /* + * Once the barrier has executed, all previously queued tasks + * have completed or are currently executing. + */ + while (t_barrier.ta_flags & TASK_ENQUEUED) + TQ_SLEEP(queue, &t_barrier, &queue->tq_mutex, PWAIT, "-", 0); +} + +/* + * Block until all currently executing tasks for this taskqueue + * complete. Tasks that begin execution during the execution + * of this function are ignored. + */ +static void +gtaskqueue_drain_tq_active(struct gtaskqueue *queue) +{ + struct gtaskqueue_busy tb_marker, *tb_first; + + if (TAILQ_EMPTY(&queue->tq_active)) + return; + + /* Block taskq_terminate().*/ + queue->tq_callouts++; + + /* + * Wait for all currently executing taskqueue threads + * to go idle. + */ + tb_marker.tb_running = TB_DRAIN_WAITER; + TAILQ_INSERT_TAIL(&queue->tq_active, &tb_marker, tb_link); + while (TAILQ_FIRST(&queue->tq_active) != &tb_marker) + TQ_SLEEP(queue, &tb_marker, &queue->tq_mutex, PWAIT, "-", 0); + TAILQ_REMOVE(&queue->tq_active, &tb_marker, tb_link); + + /* + * Wakeup any other drain waiter that happened to queue up + * without any intervening active thread. + */ + tb_first = TAILQ_FIRST(&queue->tq_active); + if (tb_first != NULL && tb_first->tb_running == TB_DRAIN_WAITER) + wakeup(tb_first); + + /* Release taskqueue_terminate(). */ + queue->tq_callouts--; + if ((queue->tq_flags & TQ_FLAGS_ACTIVE) == 0) + wakeup_one(queue->tq_threads); +} + +void +gtaskqueue_block(struct gtaskqueue *queue) +{ + + TQ_LOCK(queue); + queue->tq_flags |= TQ_FLAGS_BLOCKED; + TQ_UNLOCK(queue); +} + +void +gtaskqueue_unblock(struct gtaskqueue *queue) +{ + + TQ_LOCK(queue); + queue->tq_flags &= ~TQ_FLAGS_BLOCKED; + if (!STAILQ_EMPTY(&queue->tq_queue)) + queue->tq_enqueue(queue->tq_context); + TQ_UNLOCK(queue); +} + +static void +gtaskqueue_run_locked(struct gtaskqueue *queue) +{ + struct gtaskqueue_busy tb; + struct gtaskqueue_busy *tb_first; + struct gtask *gtask; + + KASSERT(queue != NULL, ("tq is NULL")); + TQ_ASSERT_LOCKED(queue); + tb.tb_running = NULL; + + while (STAILQ_FIRST(&queue->tq_queue)) { + TAILQ_INSERT_TAIL(&queue->tq_active, &tb, tb_link); + + /* + * Carefully remove the first task from the queue and + * clear its TASK_ENQUEUED flag + */ + gtask = STAILQ_FIRST(&queue->tq_queue); + KASSERT(gtask != NULL, ("task is NULL")); + STAILQ_REMOVE_HEAD(&queue->tq_queue, ta_link); + gtask->ta_flags &= ~TASK_ENQUEUED; + tb.tb_running = gtask; + TQ_UNLOCK(queue); + + KASSERT(gtask->ta_func != NULL, ("task->ta_func is NULL")); + gtask->ta_func(gtask->ta_context); + + TQ_LOCK(queue); + tb.tb_running = NULL; + wakeup(gtask); + + TAILQ_REMOVE(&queue->tq_active, &tb, tb_link); + tb_first = TAILQ_FIRST(&queue->tq_active); + if (tb_first != NULL && + tb_first->tb_running == TB_DRAIN_WAITER) + wakeup(tb_first); + } +} + +static int +task_is_running(struct gtaskqueue *queue, struct gtask *gtask) +{ + struct gtaskqueue_busy *tb; + + TQ_ASSERT_LOCKED(queue); + TAILQ_FOREACH(tb, &queue->tq_active, tb_link) { + if (tb->tb_running == gtask) + return (1); + } + return (0); +} + +static int +gtaskqueue_cancel_locked(struct gtaskqueue *queue, struct gtask *gtask) +{ + + if (gtask->ta_flags & TASK_ENQUEUED) + STAILQ_REMOVE(&queue->tq_queue, gtask, gtask, ta_link); + gtask->ta_flags &= ~TASK_ENQUEUED; + return (task_is_running(queue, gtask) ? EBUSY : 0); +} + +int +gtaskqueue_cancel(struct gtaskqueue *queue, struct gtask *gtask) +{ + int error; + + TQ_LOCK(queue); + error = gtaskqueue_cancel_locked(queue, gtask); + TQ_UNLOCK(queue); + + return (error); +} + +void +gtaskqueue_drain(struct gtaskqueue *queue, struct gtask *gtask) +{ + + if (!queue->tq_spin) + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__); + + TQ_LOCK(queue); + while ((gtask->ta_flags & TASK_ENQUEUED) || task_is_running(queue, gtask)) + TQ_SLEEP(queue, gtask, &queue->tq_mutex, PWAIT, "-", 0); + TQ_UNLOCK(queue); +} + +void +gtaskqueue_drain_all(struct gtaskqueue *queue) +{ + + if (!queue->tq_spin) + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__); + + TQ_LOCK(queue); + gtaskqueue_drain_tq_queue(queue); + gtaskqueue_drain_tq_active(queue); + TQ_UNLOCK(queue); +} + +static int +_gtaskqueue_start_threads(struct gtaskqueue **tqp, int count, int pri, + cpuset_t *mask, const char *name, va_list ap) +{ + char ktname[MAXCOMLEN + 1]; + struct thread *td; + struct gtaskqueue *tq; + int i, error; + + if (count <= 0) + return (EINVAL); + + vsnprintf(ktname, sizeof(ktname), name, ap); + tq = *tqp; + + tq->tq_threads = malloc(sizeof(struct thread *) * count, M_GTASKQUEUE, + M_NOWAIT | M_ZERO); + if (tq->tq_threads == NULL) { + printf("%s: no memory for %s threads\n", __func__, ktname); + return (ENOMEM); + } + + for (i = 0; i < count; i++) { + if (count == 1) + error = kthread_add(gtaskqueue_thread_loop, tqp, NULL, + &tq->tq_threads[i], RFSTOPPED, 0, "%s", ktname); + else + error = kthread_add(gtaskqueue_thread_loop, tqp, NULL, + &tq->tq_threads[i], RFSTOPPED, 0, + "%s_%d", ktname, i); + if (error) { + /* should be ok to continue, taskqueue_free will dtrt */ + printf("%s: kthread_add(%s): error %d", __func__, + ktname, error); + tq->tq_threads[i] = NULL; /* paranoid */ + } else + tq->tq_tcount++; + } + for (i = 0; i < count; i++) { + if (tq->tq_threads[i] == NULL) + continue; + td = tq->tq_threads[i]; + if (mask) { +#ifndef __rtems__ + error = cpuset_setthread(td->td_tid, mask); + /* + * Failing to pin is rarely an actual fatal error; + * it'll just affect performance. + */ + if (error) + printf("%s: curthread=%llu: can't pin; " + "error=%d\n", + __func__, + (unsigned long long) td->td_tid, + error); +#else /* __rtems__ */ + rtems_status_code sc; + + sc = rtems_task_set_affinity(rtems_bsd_get_task_id(td), + sizeof(*mask), mask); + if (sc != RTEMS_SUCCESSFUL) + printf("%s: cannot set affinity\n", __func__); +#endif /* __rtems__ */ + } +#ifndef __rtems__ + thread_lock(td); + sched_prio(td, pri); + sched_add(td, SRQ_BORING); + thread_unlock(td); +#endif /* __rtems__ */ + } + + return (0); +} + +static int +gtaskqueue_start_threads(struct gtaskqueue **tqp, int count, int pri, + const char *name, ...) +{ + va_list ap; + int error; + + va_start(ap, name); + error = _gtaskqueue_start_threads(tqp, count, pri, NULL, name, ap); + va_end(ap); + return (error); +} + +static inline void +gtaskqueue_run_callback(struct gtaskqueue *tq, + enum taskqueue_callback_type cb_type) +{ + taskqueue_callback_fn tq_callback; + + TQ_ASSERT_UNLOCKED(tq); + tq_callback = tq->tq_callbacks[cb_type]; + if (tq_callback != NULL) + tq_callback(tq->tq_cb_contexts[cb_type]); +} + +static void +gtaskqueue_thread_loop(void *arg) +{ + struct gtaskqueue **tqp, *tq; + + tqp = arg; + tq = *tqp; + gtaskqueue_run_callback(tq, TASKQUEUE_CALLBACK_TYPE_INIT); + TQ_LOCK(tq); + while ((tq->tq_flags & TQ_FLAGS_ACTIVE) != 0) { + /* XXX ? */ + gtaskqueue_run_locked(tq); + /* + * Because taskqueue_run() can drop tq_mutex, we need to + * check if the TQ_FLAGS_ACTIVE flag wasn't removed in the + * meantime, which means we missed a wakeup. + */ + if ((tq->tq_flags & TQ_FLAGS_ACTIVE) == 0) + break; + TQ_SLEEP(tq, tq, &tq->tq_mutex, 0, "-", 0); + } + gtaskqueue_run_locked(tq); + /* + * This thread is on its way out, so just drop the lock temporarily + * in order to call the shutdown callback. This allows the callback + * to look at the taskqueue, even just before it dies. + */ + TQ_UNLOCK(tq); + gtaskqueue_run_callback(tq, TASKQUEUE_CALLBACK_TYPE_SHUTDOWN); + TQ_LOCK(tq); + + /* rendezvous with thread that asked us to terminate */ + tq->tq_tcount--; + wakeup_one(tq->tq_threads); + TQ_UNLOCK(tq); + kthread_exit(); +} + +static void +gtaskqueue_thread_enqueue(void *context) +{ + struct gtaskqueue **tqp, *tq; + + tqp = context; + tq = *tqp; + wakeup_one(tq); +} + + +static struct gtaskqueue * +gtaskqueue_create_fast(const char *name, int mflags, + taskqueue_enqueue_fn enqueue, void *context) +{ + return _gtaskqueue_create(name, mflags, enqueue, context, + MTX_SPIN, "fast_taskqueue"); +} + + +struct taskqgroup_cpu { + LIST_HEAD(, grouptask) tgc_tasks; + struct gtaskqueue *tgc_taskq; + int tgc_cnt; + int tgc_cpu; +}; + +struct taskqgroup { + struct taskqgroup_cpu tqg_queue[MAXCPU]; + struct mtx tqg_lock; + const char * tqg_name; + int tqg_adjusting; + int tqg_stride; + int tqg_cnt; +}; + +struct taskq_bind_task { + struct gtask bt_task; + int bt_cpuid; +}; + +static void +taskqgroup_cpu_create(struct taskqgroup *qgroup, int idx, int cpu) +{ + struct taskqgroup_cpu *qcpu; + + qcpu = &qgroup->tqg_queue[idx]; + LIST_INIT(&qcpu->tgc_tasks); + qcpu->tgc_taskq = gtaskqueue_create_fast(NULL, M_WAITOK, + taskqueue_thread_enqueue, &qcpu->tgc_taskq); + gtaskqueue_start_threads(&qcpu->tgc_taskq, 1, PI_SOFT, + "%s_%d", qgroup->tqg_name, idx); + qcpu->tgc_cpu = cpu; +} + +static void +taskqgroup_cpu_remove(struct taskqgroup *qgroup, int idx) +{ + + gtaskqueue_free(qgroup->tqg_queue[idx].tgc_taskq); +} + +/* + * Find the taskq with least # of tasks that doesn't currently have any + * other queues from the uniq identifier. + */ +static int +taskqgroup_find(struct taskqgroup *qgroup, void *uniq) +{ + struct grouptask *n; + int i, idx, mincnt; + int strict; + + mtx_assert(&qgroup->tqg_lock, MA_OWNED); + if (qgroup->tqg_cnt == 0) + return (0); + idx = -1; + mincnt = INT_MAX; + /* + * Two passes; First scan for a queue with the least tasks that + * does not already service this uniq id. If that fails simply find + * the queue with the least total tasks; + */ + for (strict = 1; mincnt == INT_MAX; strict = 0) { + for (i = 0; i < qgroup->tqg_cnt; i++) { + if (qgroup->tqg_queue[i].tgc_cnt > mincnt) + continue; + if (strict) { + LIST_FOREACH(n, + &qgroup->tqg_queue[i].tgc_tasks, gt_list) + if (n->gt_uniq == uniq) + break; + if (n != NULL) + continue; + } + mincnt = qgroup->tqg_queue[i].tgc_cnt; + idx = i; + } + } + if (idx == -1) + panic("taskqgroup_find: Failed to pick a qid."); + + return (idx); +} + +#ifndef __rtems__ +/* + * smp_started is unusable since it is not set for UP kernels or even for + * SMP kernels when there is 1 CPU. This is usually handled by adding a + * (mp_ncpus == 1) test, but that would be broken here since we need to + * to synchronize with the SI_SUB_SMP ordering. Even in the pure SMP case + * smp_started only gives a fuzzy ordering relative to SI_SUB_SMP. + * + * So maintain our own flag. It must be set after all CPUs are started + * and before SI_SUB_SMP:SI_ORDER_ANY so that the SYSINIT for delayed + * adjustment is properly delayed. SI_ORDER_FOURTH is clearly before + * SI_ORDER_ANY and unclearly after the CPUs are started. It would be + * simpler for adjustment to pass a flag indicating if it is delayed. + */ + +static int tqg_smp_started; + +static void +tqg_record_smp_started(void *arg) +{ + tqg_smp_started = 1; +} + +SYSINIT(tqg_record_smp_started, SI_SUB_SMP, SI_ORDER_FOURTH, + tqg_record_smp_started, NULL); +#else /* __rtems__ */ +#define tqg_smp_started 1 +#endif /* __rtems__ */ + +void +taskqgroup_attach(struct taskqgroup *qgroup, struct grouptask *gtask, + void *uniq, int irq, const char *name) +{ +#ifndef __rtems__ + cpuset_t mask; + int qid, error; +#else /* __rtems__ */ + int qid; +#endif /* __rtems__ */ + + gtask->gt_uniq = uniq; + snprintf(gtask->gt_name, GROUPTASK_NAMELEN, "%s", name ? name : "grouptask"); + gtask->gt_irq = irq; + gtask->gt_cpu = -1; + mtx_lock(&qgroup->tqg_lock); + qid = taskqgroup_find(qgroup, uniq); + qgroup->tqg_queue[qid].tgc_cnt++; + LIST_INSERT_HEAD(&qgroup->tqg_queue[qid].tgc_tasks, gtask, gt_list); + gtask->gt_taskqueue = qgroup->tqg_queue[qid].tgc_taskq; +#ifndef __rtems__ + if (irq != -1 && tqg_smp_started) { + gtask->gt_cpu = qgroup->tqg_queue[qid].tgc_cpu; + CPU_ZERO(&mask); + CPU_SET(qgroup->tqg_queue[qid].tgc_cpu, &mask); + mtx_unlock(&qgroup->tqg_lock); + error = intr_setaffinity(irq, CPU_WHICH_IRQ, &mask); + if (error) + printf("%s: setaffinity failed for %s: %d\n", __func__, gtask->gt_name, error); + } else +#else /* __rtems__ */ + BSD_ASSERT(irq == -1); +#endif /* __rtems__ */ + mtx_unlock(&qgroup->tqg_lock); +} + +static void +taskqgroup_attach_deferred(struct taskqgroup *qgroup, struct grouptask *gtask) +{ +#ifndef __rtems__ + cpuset_t mask; + int qid, cpu, error; +#else /* __rtems__ */ + int qid; +#endif /* __rtems__ */ + + mtx_lock(&qgroup->tqg_lock); + qid = taskqgroup_find(qgroup, gtask->gt_uniq); +#ifndef __rtems__ + cpu = qgroup->tqg_queue[qid].tgc_cpu; + if (gtask->gt_irq != -1) { + mtx_unlock(&qgroup->tqg_lock); + + CPU_ZERO(&mask); + CPU_SET(cpu, &mask); + error = intr_setaffinity(gtask->gt_irq, CPU_WHICH_IRQ, &mask); + mtx_lock(&qgroup->tqg_lock); + if (error) + printf("%s: %s setaffinity failed: %d\n", __func__, gtask->gt_name, error); + + } +#else /* __rtems__ */ + BSD_ASSERT(gtask->gt_irq == -1); +#endif /* __rtems__ */ + qgroup->tqg_queue[qid].tgc_cnt++; + + LIST_INSERT_HEAD(&qgroup->tqg_queue[qid].tgc_tasks, gtask, + gt_list); + MPASS(qgroup->tqg_queue[qid].tgc_taskq != NULL); + gtask->gt_taskqueue = qgroup->tqg_queue[qid].tgc_taskq; + mtx_unlock(&qgroup->tqg_lock); +} + +int +taskqgroup_attach_cpu(struct taskqgroup *qgroup, struct grouptask *gtask, + void *uniq, int cpu, int irq, const char *name) +{ +#ifndef __rtems__ + cpuset_t mask; + int i, qid, error; +#else /* __rtems__ */ + int i, qid; +#endif /* __rtems__ */ + + qid = -1; + gtask->gt_uniq = uniq; + snprintf(gtask->gt_name, GROUPTASK_NAMELEN, "%s", name ? name : "grouptask"); + gtask->gt_irq = irq; + gtask->gt_cpu = cpu; + mtx_lock(&qgroup->tqg_lock); + if (tqg_smp_started) { + for (i = 0; i < qgroup->tqg_cnt; i++) + if (qgroup->tqg_queue[i].tgc_cpu == cpu) { + qid = i; + break; + } + if (qid == -1) { + mtx_unlock(&qgroup->tqg_lock); + printf("%s: qid not found for %s cpu=%d\n", __func__, gtask->gt_name, cpu); + return (EINVAL); + } + } else + qid = 0; + qgroup->tqg_queue[qid].tgc_cnt++; + LIST_INSERT_HEAD(&qgroup->tqg_queue[qid].tgc_tasks, gtask, gt_list); + gtask->gt_taskqueue = qgroup->tqg_queue[qid].tgc_taskq; +#ifndef __rtems__ + cpu = qgroup->tqg_queue[qid].tgc_cpu; +#endif /* __rtems__ */ + mtx_unlock(&qgroup->tqg_lock); + +#ifndef __rtems__ + CPU_ZERO(&mask); + CPU_SET(cpu, &mask); + if (irq != -1 && tqg_smp_started) { + error = intr_setaffinity(irq, CPU_WHICH_IRQ, &mask); + if (error) + printf("%s: setaffinity failed: %d\n", __func__, error); + } +#else /* __rtems__ */ + BSD_ASSERT(irq == -1); +#endif /* __rtems__ */ + return (0); +} + +static int +taskqgroup_attach_cpu_deferred(struct taskqgroup *qgroup, struct grouptask *gtask) +{ +#ifndef __rtems__ + cpuset_t mask; + int i, qid, irq, cpu, error; +#else /* __rtems__ */ + int i, qid, irq, cpu; +#endif /* __rtems__ */ + + qid = -1; + irq = gtask->gt_irq; + cpu = gtask->gt_cpu; + MPASS(tqg_smp_started); + mtx_lock(&qgroup->tqg_lock); + for (i = 0; i < qgroup->tqg_cnt; i++) + if (qgroup->tqg_queue[i].tgc_cpu == cpu) { + qid = i; + break; + } + if (qid == -1) { + mtx_unlock(&qgroup->tqg_lock); + printf("%s: qid not found for %s cpu=%d\n", __func__, gtask->gt_name, cpu); + return (EINVAL); + } + qgroup->tqg_queue[qid].tgc_cnt++; + LIST_INSERT_HEAD(&qgroup->tqg_queue[qid].tgc_tasks, gtask, gt_list); + MPASS(qgroup->tqg_queue[qid].tgc_taskq != NULL); + gtask->gt_taskqueue = qgroup->tqg_queue[qid].tgc_taskq; + mtx_unlock(&qgroup->tqg_lock); + +#ifndef __rtems__ + CPU_ZERO(&mask); + CPU_SET(cpu, &mask); + + if (irq != -1) { + error = intr_setaffinity(irq, CPU_WHICH_IRQ, &mask); + if (error) + printf("%s: setaffinity failed: %d\n", __func__, error); + } +#else /* __rtems__ */ + BSD_ASSERT(irq == -1); +#endif /* __rtems__ */ + return (0); +} + +void +taskqgroup_detach(struct taskqgroup *qgroup, struct grouptask *gtask) +{ + int i; + + mtx_lock(&qgroup->tqg_lock); + for (i = 0; i < qgroup->tqg_cnt; i++) + if (qgroup->tqg_queue[i].tgc_taskq == gtask->gt_taskqueue) + break; + if (i == qgroup->tqg_cnt) + panic("taskqgroup_detach: task %s not in group\n", gtask->gt_name); + qgroup->tqg_queue[i].tgc_cnt--; + LIST_REMOVE(gtask, gt_list); + mtx_unlock(&qgroup->tqg_lock); + gtask->gt_taskqueue = NULL; +} + +static void +taskqgroup_binder(void *ctx) +{ + struct taskq_bind_task *gtask = (struct taskq_bind_task *)ctx; + cpuset_t mask; +#ifndef __rtems__ + int error; +#else /* __rtems__ */ + rtems_status_code sc; +#endif /* __rtems__ */ + + CPU_ZERO(&mask); + CPU_SET(gtask->bt_cpuid, &mask); +#ifndef __rtems__ + error = cpuset_setthread(curthread->td_tid, &mask); + thread_lock(curthread); + sched_bind(curthread, gtask->bt_cpuid); + thread_unlock(curthread); + + if (error) + printf("%s: setaffinity failed: %d\n", __func__, + error); +#else /* __rtems__ */ + sc = rtems_task_set_affinity(RTEMS_SELF, sizeof(mask), &mask); + if (sc != RTEMS_SUCCESSFUL) + printf("%s: cannot set affinity\n", __func__); +#endif /* __rtems__ */ + free(gtask, M_DEVBUF); +} + +static void +taskqgroup_bind(struct taskqgroup *qgroup) +{ + struct taskq_bind_task *gtask; + int i; + + /* + * Bind taskqueue threads to specific CPUs, if they have been assigned + * one. + */ + if (qgroup->tqg_cnt == 1) + return; + + for (i = 0; i < qgroup->tqg_cnt; i++) { + gtask = malloc(sizeof (*gtask), M_DEVBUF, M_WAITOK); + GTASK_INIT(>ask->bt_task, 0, 0, taskqgroup_binder, gtask); + gtask->bt_cpuid = qgroup->tqg_queue[i].tgc_cpu; + grouptaskqueue_enqueue(qgroup->tqg_queue[i].tgc_taskq, + >ask->bt_task); + } +} + +static int +_taskqgroup_adjust(struct taskqgroup *qgroup, int cnt, int stride) +{ + LIST_HEAD(, grouptask) gtask_head = LIST_HEAD_INITIALIZER(NULL); + struct grouptask *gtask; + int i, k, old_cnt, old_cpu, cpu; + + mtx_assert(&qgroup->tqg_lock, MA_OWNED); + + if (cnt < 1 || cnt * stride > mp_ncpus || !tqg_smp_started) { + printf("%s: failed cnt: %d stride: %d " + "mp_ncpus: %d tqg_smp_started: %d\n", + __func__, cnt, stride, mp_ncpus, tqg_smp_started); + return (EINVAL); + } + if (qgroup->tqg_adjusting) { + printf("%s failed: adjusting\n", __func__); + return (EBUSY); + } + qgroup->tqg_adjusting = 1; + old_cnt = qgroup->tqg_cnt; + old_cpu = 0; + if (old_cnt < cnt) + old_cpu = qgroup->tqg_queue[old_cnt].tgc_cpu; + mtx_unlock(&qgroup->tqg_lock); + /* + * Set up queue for tasks added before boot. + */ + if (old_cnt == 0) { + LIST_SWAP(>ask_head, &qgroup->tqg_queue[0].tgc_tasks, + grouptask, gt_list); + qgroup->tqg_queue[0].tgc_cnt = 0; + } + + /* + * If new taskq threads have been added. + */ + cpu = old_cpu; + for (i = old_cnt; i < cnt; i++) { + taskqgroup_cpu_create(qgroup, i, cpu); + + for (k = 0; k < stride; k++) + cpu = CPU_NEXT(cpu); + } + mtx_lock(&qgroup->tqg_lock); + qgroup->tqg_cnt = cnt; + qgroup->tqg_stride = stride; + + /* + * Adjust drivers to use new taskqs. + */ + for (i = 0; i < old_cnt; i++) { + while ((gtask = LIST_FIRST(&qgroup->tqg_queue[i].tgc_tasks))) { + LIST_REMOVE(gtask, gt_list); + qgroup->tqg_queue[i].tgc_cnt--; + LIST_INSERT_HEAD(>ask_head, gtask, gt_list); + } + } + mtx_unlock(&qgroup->tqg_lock); + + while ((gtask = LIST_FIRST(>ask_head))) { + LIST_REMOVE(gtask, gt_list); + if (gtask->gt_cpu == -1) + taskqgroup_attach_deferred(qgroup, gtask); + else if (taskqgroup_attach_cpu_deferred(qgroup, gtask)) + taskqgroup_attach_deferred(qgroup, gtask); + } + +#ifdef INVARIANTS + mtx_lock(&qgroup->tqg_lock); + for (i = 0; i < qgroup->tqg_cnt; i++) { + MPASS(qgroup->tqg_queue[i].tgc_taskq != NULL); + LIST_FOREACH(gtask, &qgroup->tqg_queue[i].tgc_tasks, gt_list) + MPASS(gtask->gt_taskqueue != NULL); + } + mtx_unlock(&qgroup->tqg_lock); +#endif + /* + * If taskq thread count has been reduced. + */ + for (i = cnt; i < old_cnt; i++) + taskqgroup_cpu_remove(qgroup, i); + + taskqgroup_bind(qgroup); + + mtx_lock(&qgroup->tqg_lock); + qgroup->tqg_adjusting = 0; + + return (0); +} + +int +taskqgroup_adjust(struct taskqgroup *qgroup, int cnt, int stride) +{ + int error; + + mtx_lock(&qgroup->tqg_lock); + error = _taskqgroup_adjust(qgroup, cnt, stride); + mtx_unlock(&qgroup->tqg_lock); + + return (error); +} + +struct taskqgroup * +taskqgroup_create(const char *name) +{ + struct taskqgroup *qgroup; + + qgroup = malloc(sizeof(*qgroup), M_GTASKQUEUE, M_WAITOK | M_ZERO); + mtx_init(&qgroup->tqg_lock, "taskqgroup", NULL, MTX_DEF); + qgroup->tqg_name = name; + LIST_INIT(&qgroup->tqg_queue[0].tgc_tasks); + + return (qgroup); +} + +void +taskqgroup_destroy(struct taskqgroup *qgroup) +{ + +} + +void +taskqgroup_config_gtask_init(void *ctx, struct grouptask *gtask, gtask_fn_t *fn, + const char *name) +{ + + GROUPTASK_INIT(gtask, 0, fn, ctx); + taskqgroup_attach(qgroup_config, gtask, gtask, -1, name); +} + +void +taskqgroup_config_gtask_deinit(struct grouptask *gtask) +{ + taskqgroup_detach(qgroup_config, gtask); +} diff --git a/freebsd/sys/kern/subr_lock.c b/freebsd/sys/kern/subr_lock.c index 4f577b65..c2587cd0 100644 --- a/freebsd/sys/kern/subr_lock.c +++ b/freebsd/sys/kern/subr_lock.c @@ -171,8 +171,10 @@ void lock_delay_default_init(struct lock_delay_config *lc) { - lc->base = lock_roundup_2(mp_ncpus) / 4; - lc->max = lc->base * 1024; + lc->base = 1; + lc->max = lock_roundup_2(mp_ncpus) * 256; + if (lc->max > 32678) + lc->max = 32678; } #endif /* __rtems__ */ diff --git a/freebsd/sys/kern/subr_pcpu.c b/freebsd/sys/kern/subr_pcpu.c index 67a1f528..1b866e3a 100644 --- a/freebsd/sys/kern/subr_pcpu.c +++ b/freebsd/sys/kern/subr_pcpu.c @@ -130,7 +130,7 @@ dpcpu_startup(void *dummy __unused) TAILQ_INSERT_HEAD(&dpcpu_head, df, df_link); sx_init(&dpcpu_lock, "dpcpu alloc lock"); } -SYSINIT(dpcpu, SI_SUB_KLD, SI_ORDER_FIRST, dpcpu_startup, 0); +SYSINIT(dpcpu, SI_SUB_KLD, SI_ORDER_FIRST, dpcpu_startup, NULL); #endif /* __rtems__ */ /* diff --git a/freebsd/sys/kern/subr_prf.c b/freebsd/sys/kern/subr_prf.c index 12a0825d..4c45bcfe 100644 --- a/freebsd/sys/kern/subr_prf.c +++ b/freebsd/sys/kern/subr_prf.c @@ -687,6 +687,7 @@ kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_lis int stop = 0, retval = 0; num = 0; + q = NULL; if (!func) d = (char *) arg; else diff --git a/freebsd/sys/kern/subr_sleepqueue.c b/freebsd/sys/kern/subr_sleepqueue.c index b9de1580..65bd8dcc 100644 --- a/freebsd/sys/kern/subr_sleepqueue.c +++ b/freebsd/sys/kern/subr_sleepqueue.c @@ -433,7 +433,7 @@ sleepq_set_timeout_sbt(void *wchan, sbintime_t sbt, sbintime_t pr, int flags) { #ifndef __rtems__ - struct sleepqueue_chain *sc; + struct sleepqueue_chain *sc __unused; struct thread *td; sbintime_t pr1; @@ -982,7 +982,7 @@ sleepq_type(void *wchan) static int sleepq_resume_thread(struct sleepqueue *sq, struct thread *td, int pri) { - struct sleepqueue_chain *sc; + struct sleepqueue_chain *sc __unused; #ifdef __rtems__ Thread_Control *thread; ISR_lock_Context lock_context; @@ -1022,7 +1022,6 @@ sleepq_resume_thread(struct sleepqueue *sq, struct thread *td, int pri) td->td_sleepqueue = LIST_FIRST(&sq->sq_free); LIST_REMOVE(td->td_sleepqueue, sq_hash); #ifdef __rtems__ - (void)sc; thread = td->td_thread; _ISR_lock_ISR_disable(&lock_context); _Thread_Wait_acquire_default_critical(thread, &lock_context); @@ -1228,7 +1227,7 @@ sleepq_remove_matching(struct sleepqueue *sq, int queue, static void sleepq_timeout(void *arg) { - struct sleepqueue_chain *sc; + struct sleepqueue_chain *sc __unused; struct sleepqueue *sq; struct thread *td; void *wchan; diff --git a/freebsd/sys/kern/subr_uio.c b/freebsd/sys/kern/subr_uio.c index 58db0ffc..c14aea8d 100644 --- a/freebsd/sys/kern/subr_uio.c +++ b/freebsd/sys/kern/subr_uio.c @@ -222,9 +222,9 @@ uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault) int error; #endif /* __rtems__ */ - error = 0; - #ifndef __rtems__ + save = error = 0; + KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, ("uiomove: mode")); KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread, @@ -290,7 +290,7 @@ uiomove_faultflag(void *cp, int n, struct uio *uio, int nofault) } out: #ifndef __rtems__ - if (uio->uio_segflg == UIO_USERSPACE) + if (save) curthread_pflags_restore(save); #endif /* __rtems__ */ return (error); diff --git a/freebsd/sys/kern/sys_generic.c b/freebsd/sys/kern/sys_generic.c index 0d5193c7..9e41f0f6 100644 --- a/freebsd/sys/kern/sys_generic.c +++ b/freebsd/sys/kern/sys_generic.c @@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_capsicum.h> -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_ktrace.h> #include <sys/param.h> @@ -201,9 +200,7 @@ struct read_args { }; #endif int -sys_read(td, uap) - struct thread *td; - struct read_args *uap; +sys_read(struct thread *td, struct read_args *uap) { struct uio auio; struct iovec aiov; @@ -296,10 +293,9 @@ int kern_readv(struct thread *td, int fd, struct uio *auio) { struct file *fp; - cap_rights_t rights; int error; - error = fget_read(td, fd, cap_rights_init(&rights, CAP_READ), &fp); + error = fget_read(td, fd, &cap_read_rights, &fp); if (error) return (error); error = dofileread(td, fd, fp, auio, (off_t)-1, 0); @@ -333,17 +329,12 @@ sys_preadv(struct thread *td, struct preadv_args *uap) } int -kern_preadv(td, fd, auio, offset) - struct thread *td; - int fd; - struct uio *auio; - off_t offset; +kern_preadv(struct thread *td, int fd, struct uio *auio, off_t offset) { struct file *fp; - cap_rights_t rights; int error; - error = fget_read(td, fd, cap_rights_init(&rights, CAP_PREAD), &fp); + error = fget_read(td, fd, &cap_pread_rights, &fp); if (error) return (error); if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) @@ -362,13 +353,8 @@ kern_preadv(td, fd, auio, offset) * from a file using the passed in uio, offset, and flags. */ static int -dofileread(td, fd, fp, auio, offset, flags) - struct thread *td; - int fd; - struct file *fp; - struct uio *auio; - off_t offset; - int flags; +dofileread(struct thread *td, int fd, struct file *fp, struct uio *auio, + off_t offset, int flags) { ssize_t cnt; int error; @@ -415,9 +401,7 @@ struct write_args { }; #endif int -sys_write(td, uap) - struct thread *td; - struct write_args *uap; +sys_write(struct thread *td, struct write_args *uap) { struct uio auio; struct iovec aiov; @@ -511,10 +495,9 @@ int kern_writev(struct thread *td, int fd, struct uio *auio) { struct file *fp; - cap_rights_t rights; int error; - error = fget_write(td, fd, cap_rights_init(&rights, CAP_WRITE), &fp); + error = fget_write(td, fd, &cap_write_rights, &fp); if (error) return (error); error = dofilewrite(td, fd, fp, auio, (off_t)-1, 0); @@ -548,17 +531,12 @@ sys_pwritev(struct thread *td, struct pwritev_args *uap) } int -kern_pwritev(td, fd, auio, offset) - struct thread *td; - struct uio *auio; - int fd; - off_t offset; +kern_pwritev(struct thread *td, int fd, struct uio *auio, off_t offset) { struct file *fp; - cap_rights_t rights; int error; - error = fget_write(td, fd, cap_rights_init(&rights, CAP_PWRITE), &fp); + error = fget_write(td, fd, &cap_pwrite_rights, &fp); if (error) return (error); if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) @@ -577,13 +555,8 @@ kern_pwritev(td, fd, auio, offset) * a file using the passed in uio, offset, and flags. */ static int -dofilewrite(td, fd, fp, auio, offset, flags) - struct thread *td; - int fd; - struct file *fp; - struct uio *auio; - off_t offset; - int flags; +dofilewrite(struct thread *td, int fd, struct file *fp, struct uio *auio, + off_t offset, int flags) { ssize_t cnt; int error; @@ -632,19 +605,15 @@ dofilewrite(td, fd, fp, auio, offset, flags) * descriptor isn't writable. */ int -kern_ftruncate(td, fd, length) - struct thread *td; - int fd; - off_t length; +kern_ftruncate(struct thread *td, int fd, off_t length) { struct file *fp; - cap_rights_t rights; int error; AUDIT_ARG_FD(fd); if (length < 0) return (EINVAL); - error = fget(td, fd, cap_rights_init(&rights, CAP_FTRUNCATE), &fp); + error = fget(td, fd, &cap_ftruncate_rights, &fp); if (error) return (error); AUDIT_ARG_FILE(td->td_proc, fp); @@ -665,9 +634,7 @@ struct ftruncate_args { }; #endif int -sys_ftruncate(td, uap) - struct thread *td; - struct ftruncate_args *uap; +sys_ftruncate(struct thread *td, struct ftruncate_args *uap) { return (kern_ftruncate(td, uap->fd, uap->length)); @@ -681,9 +648,7 @@ struct oftruncate_args { }; #endif int -oftruncate(td, uap) - struct thread *td; - struct oftruncate_args *uap; +oftruncate(struct thread *td, struct oftruncate_args *uap) { return (kern_ftruncate(td, uap->fd, uap->length)); @@ -772,9 +737,6 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data) { struct file *fp; struct filedesc *fdp; -#ifndef CAPABILITIES - cap_rights_t rights; -#endif int error, tmp, locked; AUDIT_ARG_FD(fd); @@ -813,7 +775,7 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data) locked = LA_UNLOCKED; } #else - error = fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp); + error = fget(td, fd, &cap_ioctl_rights, &fp); if (error != 0) { fp = NULL; goto out; @@ -1284,11 +1246,8 @@ selsetbits(fd_mask **ibits, fd_mask **obits, int idx, fd_mask bit, int events) static __inline int getselfd_cap(struct filedesc *fdp, int fd, struct file **fpp) { - cap_rights_t rights; - cap_rights_init(&rights, CAP_EVENT); - - return (fget_unlocked(fdp, fd, &rights, fpp, NULL)); + return (fget_unlocked(fdp, fd, &cap_event_rights, fpp, NULL)); } /* @@ -1342,10 +1301,7 @@ selrescan(struct thread *td, fd_mask **ibits, fd_mask **obits) * each selinfo. */ static int -selscan(td, ibits, obits, nfd) - struct thread *td; - fd_mask **ibits, **obits; - int nfd; +selscan(struct thread *td, fd_mask **ibits, fd_mask **obits, int nfd) { struct filedesc *fdp; struct file *fp; @@ -1573,9 +1529,6 @@ pollrescan(struct thread *td) struct filedesc *fdp; struct file *fp; struct pollfd *fd; -#ifdef CAPABILITIES - cap_rights_t rights; -#endif int n; n = 0; @@ -1600,8 +1553,7 @@ pollrescan(struct thread *td) #endif /* __rtems__ */ #ifdef CAPABILITIES if (fp == NULL || - cap_check(cap_rights(fdp, fd->fd), - cap_rights_init(&rights, CAP_EVENT)) != 0) + cap_check(cap_rights(fdp, fd->fd), &cap_event_rights) != 0) #else if (fp == NULL) #endif @@ -1630,11 +1582,7 @@ pollrescan(struct thread *td) static int -pollout(td, fds, ufds, nfd) - struct thread *td; - struct pollfd *fds; - struct pollfd *ufds; - u_int nfd; +pollout(struct thread *td, struct pollfd *fds, struct pollfd *ufds, u_int nfd) { int error = 0; u_int i = 0; @@ -1655,10 +1603,7 @@ pollout(td, fds, ufds, nfd) } static int -pollscan(td, fds, nfd) - struct thread *td; - struct pollfd *fds; - u_int nfd; +pollscan(struct thread *td, struct pollfd *fds, u_int nfd) { #ifndef __rtems__ struct filedesc *fdp = td->td_proc->p_fd; @@ -1666,9 +1611,6 @@ pollscan(td, fds, nfd) struct filedesc *fdp = NULL; #endif /* __rtems__ */ struct file *fp; -#ifdef CAPABILITIES - cap_rights_t rights; -#endif int i, n = 0; FILEDESC_SLOCK(fdp); @@ -1690,8 +1632,7 @@ pollscan(td, fds, nfd) #endif /* __rtems__ */ #ifdef CAPABILITIES if (fp == NULL || - cap_check(cap_rights(fdp, fds->fd), - cap_rights_init(&rights, CAP_EVENT)) != 0) + cap_check(cap_rights(fdp, fds->fd), &cap_event_rights) != 0) #else if (fp == NULL) #endif @@ -1822,8 +1763,7 @@ selfdfree(struct seltd *stp, struct selfd *sfp) /* Drain the waiters tied to all the selfd belonging the specified selinfo. */ void -seldrain(sip) - struct selinfo *sip; +seldrain(struct selinfo *sip) { /* @@ -1841,9 +1781,7 @@ seldrain(sip) * Record a select request. */ void -selrecord(selector, sip) - struct thread *selector; - struct selinfo *sip; +selrecord(struct thread *selector, struct selinfo *sip) { struct selfd *sfp; struct seltd *stp; @@ -1892,17 +1830,14 @@ selrecord(selector, sip) /* Wake up a selecting thread. */ void -selwakeup(sip) - struct selinfo *sip; +selwakeup(struct selinfo *sip) { doselwakeup(sip, -1); } /* Wake up a selecting thread, and set its priority. */ void -selwakeuppri(sip, pri) - struct selinfo *sip; - int pri; +selwakeuppri(struct selinfo *sip, int pri) { doselwakeup(sip, pri); } @@ -1911,9 +1846,7 @@ selwakeuppri(sip, pri) * Do a wakeup when a selectable event occurs. */ static void -doselwakeup(sip, pri) - struct selinfo *sip; - int pri; +doselwakeup(struct selinfo *sip, int pri) { struct selfd *sfp; struct selfd *sfn; diff --git a/freebsd/sys/kern/sys_pipe.c b/freebsd/sys/kern/sys_pipe.c index cc5b123c..e527495a 100755 --- a/freebsd/sys/kern/sys_pipe.c +++ b/freebsd/sys/kern/sys_pipe.c @@ -93,8 +93,6 @@ * in the structure may have changed. */ -#include <rtems/bsd/local/opt_compat.h> - #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); diff --git a/freebsd/sys/kern/tty.c b/freebsd/sys/kern/tty.c index 1350c1d9..f4a2b01f 100644 --- a/freebsd/sys/kern/tty.c +++ b/freebsd/sys/kern/tty.c @@ -35,7 +35,6 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_capsicum.h> -#include <rtems/bsd/local/opt_compat.h> #include <sys/param.h> #include <sys/capsicum.h> diff --git a/freebsd/sys/kern/tty_inq.c b/freebsd/sys/kern/tty_inq.c index b470cb5a..8d557a55 100644 --- a/freebsd/sys/kern/tty_inq.c +++ b/freebsd/sys/kern/tty_inq.c @@ -330,7 +330,7 @@ ttyinq_write(struct ttyinq *ti, const void *buf, size_t nbytes, int quote) int ttyinq_write_nofrag(struct ttyinq *ti, const void *buf, size_t nbytes, int quote) { - size_t ret; + size_t ret __unused; if (ttyinq_bytesleft(ti) < nbytes) return (-1); diff --git a/freebsd/sys/kern/tty_outq.c b/freebsd/sys/kern/tty_outq.c index 121e9975..1643fe40 100644 --- a/freebsd/sys/kern/tty_outq.c +++ b/freebsd/sys/kern/tty_outq.c @@ -326,7 +326,7 @@ ttyoutq_write(struct ttyoutq *to, const void *buf, size_t nbytes) int ttyoutq_write_nofrag(struct ttyoutq *to, const void *buf, size_t nbytes) { - size_t ret; + size_t ret __unused; if (ttyoutq_bytesleft(to) < nbytes) return (-1); diff --git a/freebsd/sys/kern/uipc_mbuf.c b/freebsd/sys/kern/uipc_mbuf.c index 7bf531e0..185d14a0 100644 --- a/freebsd/sys/kern/uipc_mbuf.c +++ b/freebsd/sys/kern/uipc_mbuf.c @@ -1635,9 +1635,6 @@ m_unshare(struct mbuf *m0, int how) mprev->m_len += m->m_len; mprev->m_next = m->m_next; /* unlink from chain */ m_free(m); /* reclaim mbuf */ -#if 0 - newipsecstat.ips_mbcoalesced++; -#endif } else { mprev = m; } @@ -1667,9 +1664,6 @@ m_unshare(struct mbuf *m0, int how) mprev->m_len += m->m_len; mprev->m_next = m->m_next; /* unlink from chain */ m_free(m); /* reclaim mbuf */ -#if 0 - newipsecstat.ips_clcoalesced++; -#endif continue; } diff --git a/freebsd/sys/kern/uipc_sockbuf.c b/freebsd/sys/kern/uipc_sockbuf.c index 0c4ace6b..ec493c04 100644 --- a/freebsd/sys/kern/uipc_sockbuf.c +++ b/freebsd/sys/kern/uipc_sockbuf.c @@ -466,6 +466,7 @@ sbsetopt(struct socket *so, int cmd, u_long cc) u_int *hiwat, *lowat; int error; + sb = NULL; SOCK_LOCK(so); if (SOLISTENING(so)) { switch (cmd) { diff --git a/freebsd/sys/kern/uipc_socket.c b/freebsd/sys/kern/uipc_socket.c index 43763026..e82642e4 100644 --- a/freebsd/sys/kern/uipc_socket.c +++ b/freebsd/sys/kern/uipc_socket.c @@ -109,7 +109,6 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_inet.h> #include <rtems/bsd/local/opt_inet6.h> -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_sctp.h> #include <sys/param.h> diff --git a/freebsd/sys/kern/uipc_syscalls.c b/freebsd/sys/kern/uipc_syscalls.c index 6f3c95c0..0872aa62 100644 --- a/freebsd/sys/kern/uipc_syscalls.c +++ b/freebsd/sys/kern/uipc_syscalls.c @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_capsicum.h> #include <rtems/bsd/local/opt_inet.h> #include <rtems/bsd/local/opt_inet6.h> -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_ktrace.h> #include <sys/param.h> @@ -300,12 +299,16 @@ kern_bindat(struct thread *td, int dirfd, int fd, struct sockaddr *sa) { struct socket *so; struct file *fp; - cap_rights_t rights; int error; +#ifdef CAPABILITY_MODE + if (IN_CAPABILITY_MODE(td) && (dirfd == AT_FDCWD)) + return (ECAPMODE); +#endif + AUDIT_ARG_FD(fd); AUDIT_ARG_SOCKADDR(td, dirfd, sa); - error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_BIND), + error = getsock_cap(td, fd, &cap_bind_rights, &fp, NULL, NULL); if (error != 0) return (error); @@ -364,11 +367,10 @@ kern_listen(struct thread *td, int s, int backlog) { struct socket *so; struct file *fp; - cap_rights_t rights; int error; AUDIT_ARG_FD(s); - error = getsock_cap(td, s, cap_rights_init(&rights, CAP_LISTEN), + error = getsock_cap(td, s, &cap_listen_rights, &fp, NULL, NULL); if (error == 0) { so = fp->f_data; @@ -493,7 +495,6 @@ kern_accept4(struct thread *td, int s, struct sockaddr **name, struct sockaddr *sa = NULL; struct socket *head, *so; struct filecaps fcaps; - cap_rights_t rights; u_int fflag; pid_t pgid; int error, fd, tmp; @@ -502,7 +503,7 @@ kern_accept4(struct thread *td, int s, struct sockaddr **name, *name = NULL; AUDIT_ARG_FD(s); - error = getsock_cap(td, s, cap_rights_init(&rights, CAP_ACCEPT), + error = getsock_cap(td, s, &cap_accept_rights, &headfp, &fflag, &fcaps); if (error != 0) return (error); @@ -692,12 +693,16 @@ kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa) { struct socket *so; struct file *fp; - cap_rights_t rights; int error, interrupted = 0; +#ifdef CAPABILITY_MODE + if (IN_CAPABILITY_MODE(td) && (dirfd == AT_FDCWD)) + return (ECAPMODE); +#endif + AUDIT_ARG_FD(fd); AUDIT_ARG_SOCKADDR(td, dirfd, sa); - error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_CONNECT), + error = getsock_cap(td, fd, &cap_connect_rights, &fp, NULL, NULL); if (error != 0) return (error); @@ -986,7 +991,7 @@ kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags, struct iovec *iov; struct socket *so; #ifndef __rtems__ - cap_rights_t rights; + cap_rights_t *rights; #endif /* __rtems__ */ #ifdef KTRACE struct uio *ktruio = NULL; @@ -996,13 +1001,14 @@ kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags, AUDIT_ARG_FD(s); #ifndef __rtems__ + rights = &cap_send_rights; cap_rights_init(&rights, CAP_SEND); if (mp->msg_name != NULL) { AUDIT_ARG_SOCKADDR(td, AT_FDCWD, mp->msg_name); - cap_rights_set(&rights, CAP_CONNECT); + rights = &cap_send_connect_rights; } #endif /* __rtems__ */ - error = getsock_cap(td, s, &rights, &fp, NULL, NULL); + error = getsock_cap(td, s, rights, &fp, NULL, NULL); if (error != 0) { m_freem(control); return (error); @@ -1259,7 +1265,6 @@ kern_recvit(struct thread *td, int s, struct msghdr *mp, enum uio_seg fromseg, struct file *fp; struct socket *so; struct sockaddr *fromsa = NULL; - cap_rights_t rights; #ifdef KTRACE struct uio *ktruio = NULL; #endif @@ -1270,7 +1275,7 @@ kern_recvit(struct thread *td, int s, struct msghdr *mp, enum uio_seg fromseg, *controlp = NULL; AUDIT_ARG_FD(s); - error = getsock_cap(td, s, cap_rights_init(&rights, CAP_RECV), + error = getsock_cap(td, s, &cap_recv_rights, &fp, NULL, NULL); if (error != 0) return (error); @@ -1613,11 +1618,10 @@ kern_shutdown(struct thread *td, int s, int how) { struct socket *so; struct file *fp; - cap_rights_t rights; int error; AUDIT_ARG_FD(s); - error = getsock_cap(td, s, cap_rights_init(&rights, CAP_SHUTDOWN), + error = getsock_cap(td, s, &cap_shutdown_rights, &fp, NULL, NULL); if (error == 0) { so = fp->f_data; @@ -1696,7 +1700,6 @@ kern_setsockopt(struct thread *td, int s, int level, int name, void *val, struct socket *so; struct file *fp; struct sockopt sopt; - cap_rights_t rights; int error; if (val == NULL && valsize != 0) @@ -1721,7 +1724,7 @@ kern_setsockopt(struct thread *td, int s, int level, int name, void *val, } AUDIT_ARG_FD(s); - error = getsock_cap(td, s, cap_rights_init(&rights, CAP_SETSOCKOPT), + error = getsock_cap(td, s, &cap_setsockopt_rights, &fp, NULL, NULL); if (error == 0) { so = fp->f_data; @@ -1792,7 +1795,6 @@ kern_getsockopt(struct thread *td, int s, int level, int name, void *val, struct socket *so; struct file *fp; struct sockopt sopt; - cap_rights_t rights; int error; if (val == NULL) @@ -1817,7 +1819,7 @@ kern_getsockopt(struct thread *td, int s, int level, int name, void *val, } AUDIT_ARG_FD(s); - error = getsock_cap(td, s, cap_rights_init(&rights, CAP_GETSOCKOPT), + error = getsock_cap(td, s, &cap_getsockopt_rights, &fp, NULL, NULL); if (error == 0) { so = fp->f_data; @@ -1892,12 +1894,11 @@ kern_getsockname(struct thread *td, int fd, struct sockaddr **sa, { struct socket *so; struct file *fp; - cap_rights_t rights; socklen_t len; int error; AUDIT_ARG_FD(fd); - error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_GETSOCKNAME), + error = getsock_cap(td, fd, &cap_getsockname_rights, &fp, NULL, NULL); if (error != 0) return (error); @@ -2008,12 +2009,11 @@ kern_getpeername(struct thread *td, int fd, struct sockaddr **sa, { struct socket *so; struct file *fp; - cap_rights_t rights; socklen_t len; int error; AUDIT_ARG_FD(fd); - error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_GETPEERNAME), + error = getsock_cap(td, fd, &cap_getpeername_rights, &fp, NULL, NULL); if (error != 0) return (error); diff --git a/freebsd/sys/kern/uipc_usrreq.c b/freebsd/sys/kern/uipc_usrreq.c index 7849be9d..688682d4 100644 --- a/freebsd/sys/kern/uipc_usrreq.c +++ b/freebsd/sys/kern/uipc_usrreq.c @@ -4,9 +4,9 @@ * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1982, 1986, 1989, 1991, 1993 - * The Regents of the University of California. - * Copyright (c) 2004-2009 Robert N. M. Watson - * All rights reserved. + * The Regents of the University of California. All Rights Reserved. + * Copyright (c) 2004-2009 Robert N. M. Watson All Rights Reserved. + * Copyright (c) 2018 Matthew Macy * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -204,12 +204,40 @@ SYSCTL_INT(_net_local, OID_AUTO, deferred, CTLFLAG_RD, /* * Locking and synchronization: * - * Two types of locks exist in the local domain socket implementation: a - * a global linkage rwlock and per-unpcb mutexes. The linkage lock protects - * the socket count, global generation number, stream/datagram global lists and - * interconnection of unpcbs, the v_socket and unp_vnode pointers, and can be - * held exclusively over the acquisition of multiple unpcb locks to prevent - * deadlock. + * Three types of locks exist in the local domain socket implementation: a + * a global linkage rwlock, the mtxpool lock, and per-unpcb mutexes. + * The linkage lock protects the socket count, global generation number, + * and stream/datagram global lists. + * + * The mtxpool lock protects the vnode from being modified while referenced. + * Lock ordering requires that it be acquired before any unpcb locks. + * + * The unpcb lock (unp_mtx) protects all fields in the unpcb. Of particular + * note is that this includes the unp_conn field. So long as the unpcb lock + * is held the reference to the unpcb pointed to by unp_conn is valid. If we + * require that the unpcb pointed to by unp_conn remain live in cases where + * we need to drop the unp_mtx as when we need to acquire the lock for a + * second unpcb the caller must first acquire an additional reference on the + * second unpcb and then revalidate any state (typically check that unp_conn + * is non-NULL) upon requiring the initial unpcb lock. The lock ordering + * between unpcbs is the conventional ascending address order. Two helper + * routines exist for this: + * + * - unp_pcb_lock2(unp, unp2) - which just acquires the two locks in the + * safe ordering. + * + * - unp_pcb_owned_lock2(unp, unp2, freed) - the lock for unp is held + * when called. If unp is unlocked and unp2 is subsequently freed + * freed will be set to 1. + * + * The helper routines for references are: + * + * - unp_pcb_hold(unp): Can be called any time we currently hold a valid + * reference to unp. + * + * - unp_pcb_rele(unp): The caller must hold the unp lock. If we are + * releasing the last reference, detach must have been called thus + * unp->unp_socket be NULL. * * UNIX domain sockets each have an unpcb hung off of their so_pcb pointer, * allocated in pru_attach() and freed in pru_detach(). The validity of that @@ -223,15 +251,8 @@ SYSCTL_INT(_net_local, OID_AUTO, deferred, CTLFLAG_RD, * to the unpcb is held. Typically, this reference will be from the socket, * or from another unpcb when the referring unpcb's lock is held (in order * that the reference not be invalidated during use). For example, to follow - * unp->unp_conn->unp_socket, you need unlock the lock on unp, not unp_conn, - * as unp_socket remains valid as long as the reference to unp_conn is valid. - * - * Fields of unpcbss are locked using a per-unpcb lock, unp_mtx. Individual - * atomic reads without the lock may be performed "lockless", but more - * complex reads and read-modify-writes require the mutex to be held. No - * lock order is defined between unpcb locks -- multiple unpcb locks may be - * acquired at the same time only when holding the linkage rwlock - * exclusively, which prevents deadlocks. + * unp->unp_conn->unp_socket, you need to hold a lock on unp_conn to guarantee + * that detach is not run clearing unp_socket. * * Blocking with UNIX domain sockets is a tricky issue: unlike most network * protocols, bind() is a non-atomic operation, and connect() requires @@ -270,13 +291,19 @@ static struct mtx unp_defers_lock; #define UNP_DEFERRED_LOCK() mtx_lock(&unp_defers_lock) #define UNP_DEFERRED_UNLOCK() mtx_unlock(&unp_defers_lock) +#define UNP_REF_LIST_LOCK() UNP_DEFERRED_LOCK(); +#define UNP_REF_LIST_UNLOCK() UNP_DEFERRED_UNLOCK(); + #define UNP_PCB_LOCK_INIT(unp) mtx_init(&(unp)->unp_mtx, \ - "unp_mtx", "unp_mtx", \ - MTX_DUPOK|MTX_DEF|MTX_RECURSE) + "unp", "unp", \ + MTX_DUPOK|MTX_DEF) #define UNP_PCB_LOCK_DESTROY(unp) mtx_destroy(&(unp)->unp_mtx) #define UNP_PCB_LOCK(unp) mtx_lock(&(unp)->unp_mtx) +#define UNP_PCB_TRYLOCK(unp) mtx_trylock(&(unp)->unp_mtx) #define UNP_PCB_UNLOCK(unp) mtx_unlock(&(unp)->unp_mtx) +#define UNP_PCB_OWNED(unp) mtx_owned(&(unp)->unp_mtx) #define UNP_PCB_LOCK_ASSERT(unp) mtx_assert(&(unp)->unp_mtx, MA_OWNED) +#define UNP_PCB_UNLOCK_ASSERT(unp) mtx_assert(&(unp)->unp_mtx, MA_NOTOWNED) static int uipc_connect2(struct socket *, struct socket *); static int uipc_ctloutput(struct socket *, struct sockopt *); @@ -308,6 +335,77 @@ static struct mbuf *unp_addsockcred(struct thread *, struct mbuf *); static void unp_process_defers(void * __unused, int); #endif /* __rtems__ */ + +static void +unp_pcb_hold(struct unpcb *unp) +{ + MPASS(unp->unp_refcount); + refcount_acquire(&unp->unp_refcount); +} + +static int +unp_pcb_rele(struct unpcb *unp) +{ + int freed; + + UNP_PCB_LOCK_ASSERT(unp); + MPASS(unp->unp_refcount); + if ((freed = refcount_release(&unp->unp_refcount))) { + /* we got here with having detached? */ + MPASS(unp->unp_socket == NULL); + UNP_PCB_UNLOCK(unp); + UNP_PCB_LOCK_DESTROY(unp); + uma_zfree(unp_zone, unp); + } + return (freed); +} + +static void +unp_pcb_lock2(struct unpcb *unp, struct unpcb *unp2) +{ + MPASS(unp != unp2); + UNP_PCB_UNLOCK_ASSERT(unp); + UNP_PCB_UNLOCK_ASSERT(unp2); + if ((uintptr_t)unp2 > (uintptr_t)unp) { + UNP_PCB_LOCK(unp); + UNP_PCB_LOCK(unp2); + } else { + UNP_PCB_LOCK(unp2); + UNP_PCB_LOCK(unp); + } +} + +static __noinline void +unp_pcb_owned_lock2_slowpath(struct unpcb *unp, struct unpcb **unp2p, int *freed) + +{ + struct unpcb *unp2; + + unp2 = *unp2p; + unp_pcb_hold((unp2)); + UNP_PCB_UNLOCK((unp)); + UNP_PCB_LOCK((unp2)); + UNP_PCB_LOCK((unp)); + *freed = unp_pcb_rele((unp2)); + if (*freed) + *unp2p = NULL; +} + +#define unp_pcb_owned_lock2(unp, unp2, freed) do { \ + freed = 0; \ + UNP_PCB_LOCK_ASSERT((unp)); \ + UNP_PCB_UNLOCK_ASSERT((unp2)); \ + MPASS(unp != unp2); \ + if (__predict_true(UNP_PCB_TRYLOCK((unp2)))) \ + break; \ + else if ((uintptr_t)(unp2) > (uintptr_t)(unp)) \ + UNP_PCB_LOCK((unp2)); \ + else { \ + unp_pcb_owned_lock2_slowpath((unp), &(unp2), &freed); \ + } \ +} while (0) + + /* * Definitions of protocols supported in the LOCAL domain. */ @@ -365,17 +463,16 @@ uipc_abort(struct socket *so) unp = sotounpcb(so); KASSERT(unp != NULL, ("uipc_abort: unp == NULL")); + UNP_PCB_UNLOCK_ASSERT(unp); - UNP_LINK_WLOCK(); UNP_PCB_LOCK(unp); unp2 = unp->unp_conn; if (unp2 != NULL) { - UNP_PCB_LOCK(unp2); + unp_pcb_hold(unp2); + UNP_PCB_UNLOCK(unp); unp_drop(unp2); - UNP_PCB_UNLOCK(unp2); - } - UNP_PCB_UNLOCK(unp); - UNP_LINK_WUNLOCK(); + } else + UNP_PCB_UNLOCK(unp); } static int @@ -636,7 +733,6 @@ restart: #endif /* __rtems__ */ soun = (struct sockaddr_un *)sodupsockaddr(nam, M_WAITOK); - UNP_LINK_WLOCK(); UNP_PCB_LOCK(unp); #ifndef __rtems__ VOP_UNP_BIND(vp, unp); @@ -645,7 +741,6 @@ restart: unp->unp_addr = soun; unp->unp_flags &= ~UNP_BINDING; UNP_PCB_UNLOCK(unp); - UNP_LINK_WUNLOCK(); #ifndef __rtems__ VOP_UNLOCK(vp, 0); vn_finished_write(mp); @@ -676,9 +771,7 @@ uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) int error; KASSERT(td == curthread, ("uipc_connect: td != curthread")); - UNP_LINK_WLOCK(); error = unp_connect(so, nam, td); - UNP_LINK_WUNLOCK(); return (error); } @@ -689,9 +782,7 @@ uipc_connectat(int fd, struct socket *so, struct sockaddr *nam, int error; KASSERT(td == curthread, ("uipc_connectat: td != curthread")); - UNP_LINK_WLOCK(); error = unp_connectat(fd, so, nam, td); - UNP_LINK_WUNLOCK(); return (error); } @@ -701,30 +792,53 @@ uipc_close(struct socket *so) struct unpcb *unp, *unp2; #ifndef __rtems__ struct vnode *vp = NULL; + struct mtx *vplock; #else /* __rtems__ */ IMFS_generic_t *vp = NULL; #endif /* __rtems__ */ - + int freed; unp = sotounpcb(so); KASSERT(unp != NULL, ("uipc_close: unp == NULL")); - UNP_LINK_WLOCK(); + +#ifndef __rtems__ + vplock = NULL; +#endif /* __rtems__ */ + if ((vp = unp->unp_vnode) != NULL) { +#ifndef __rtems__ + vplock = mtx_pool_find(mtxpool_sleep, vp); + mtx_lock(vplock); +#endif /* __rtems__ */ + } UNP_PCB_LOCK(unp); - unp2 = unp->unp_conn; - if (unp2 != NULL) { - UNP_PCB_LOCK(unp2); - unp_disconnect(unp, unp2); - UNP_PCB_UNLOCK(unp2); + if (vp && unp->unp_vnode == NULL) { +#ifndef __rtems__ + mtx_unlock(vplock); +#endif /* __rtems__ */ + vp = NULL; } - if (SOLISTENING(so) && ((vp = unp->unp_vnode) != NULL)) { + if (vp != NULL) { VOP_UNP_DETACH(vp); unp->unp_vnode = NULL; } - UNP_PCB_UNLOCK(unp); - UNP_LINK_WUNLOCK(); + unp2 = unp->unp_conn; + unp_pcb_hold(unp); + if (__predict_false(unp == unp2)) { + unp_disconnect(unp, unp2); + } else if (unp2 != NULL) { + unp_pcb_hold(unp2); + unp_pcb_owned_lock2(unp, unp2, freed); + unp_disconnect(unp, unp2); + if (unp_pcb_rele(unp2) == 0) + UNP_PCB_UNLOCK(unp2); + } + if (unp_pcb_rele(unp) == 0) + UNP_PCB_UNLOCK(unp); #ifndef __rtems__ - if (vp) + if (vp) { + mtx_unlock(vplock); vrele(vp); + } #endif /* __rtems__ */ } @@ -734,17 +848,18 @@ uipc_connect2(struct socket *so1, struct socket *so2) struct unpcb *unp, *unp2; int error; - UNP_LINK_WLOCK(); unp = so1->so_pcb; KASSERT(unp != NULL, ("uipc_connect2: unp == NULL")); - UNP_PCB_LOCK(unp); unp2 = so2->so_pcb; KASSERT(unp2 != NULL, ("uipc_connect2: unp2 == NULL")); - UNP_PCB_LOCK(unp2); + if (unp != unp2) + unp_pcb_lock2(unp, unp2); + else + UNP_PCB_LOCK(unp); error = unp_connect2(so1, so2, PRU_CONNECT2); - UNP_PCB_UNLOCK(unp2); + if (unp != unp2) + UNP_PCB_UNLOCK(unp2); UNP_PCB_UNLOCK(unp); - UNP_LINK_WUNLOCK(); return (error); } @@ -752,6 +867,9 @@ static void uipc_detach(struct socket *so) { struct unpcb *unp, *unp2; +#ifndef __rtems__ + struct mtx *vplock; +#endif /* __rtems__ */ struct sockaddr_un *saved_unp_addr; #ifndef __rtems__ struct vnode *vp; @@ -766,6 +884,7 @@ uipc_detach(struct socket *so) vp = NULL; #ifndef __rtems__ + vplock = NULL; local_unp_rights = 0; #endif /* __rtems__ */ @@ -773,52 +892,87 @@ uipc_detach(struct socket *so) LIST_REMOVE(unp, unp_link); unp->unp_gencnt = ++unp_gencnt; --unp_count; + UNP_LINK_WUNLOCK(); + + UNP_PCB_UNLOCK_ASSERT(unp); + restart: + if ((vp = unp->unp_vnode) != NULL) { +#ifndef __rtems__ + vplock = mtx_pool_find(mtxpool_sleep, vp); + mtx_lock(vplock); +#endif /* __rtems__ */ + } UNP_PCB_LOCK(unp); - if ((unp->unp_flags & UNP_NASCENT) != 0) + if (unp->unp_vnode != vp && + unp->unp_vnode != NULL) { +#ifndef __rtems__ + if (vplock) + mtx_unlock(vplock); +#endif /* __rtems__ */ + UNP_PCB_UNLOCK(unp); + goto restart; + } + if ((unp->unp_flags & UNP_NASCENT) != 0) { goto teardown; - + } if ((vp = unp->unp_vnode) != NULL) { VOP_UNP_DETACH(vp); unp->unp_vnode = NULL; } - unp2 = unp->unp_conn; + if (__predict_false(unp == unp->unp_conn)) { + unp_disconnect(unp, unp); + unp2 = NULL; + goto connect_self; + } + if ((unp2 = unp->unp_conn) != NULL) { + unp_pcb_owned_lock2(unp, unp2, freeunp); + if (freeunp) + unp2 = NULL; + } + unp_pcb_hold(unp); if (unp2 != NULL) { - UNP_PCB_LOCK(unp2); + unp_pcb_hold(unp2); unp_disconnect(unp, unp2); - UNP_PCB_UNLOCK(unp2); + if (unp_pcb_rele(unp2) == 0) + UNP_PCB_UNLOCK(unp2); } - - /* - * We hold the linkage lock exclusively, so it's OK to acquire - * multiple pcb locks at a time. - */ + connect_self: + UNP_PCB_UNLOCK(unp); + UNP_REF_LIST_LOCK(); while (!LIST_EMPTY(&unp->unp_refs)) { struct unpcb *ref = LIST_FIRST(&unp->unp_refs); - UNP_PCB_LOCK(ref); + unp_pcb_hold(ref); + UNP_REF_LIST_UNLOCK(); + + MPASS(ref != unp); + UNP_PCB_UNLOCK_ASSERT(ref); unp_drop(ref); - UNP_PCB_UNLOCK(ref); + UNP_REF_LIST_LOCK(); } + + UNP_REF_LIST_UNLOCK(); + UNP_PCB_LOCK(unp); + freeunp = unp_pcb_rele(unp); + MPASS(freeunp == 0); #ifndef __rtems__ local_unp_rights = unp_rights; #endif /* __rtems__ */ teardown: - UNP_LINK_WUNLOCK(); unp->unp_socket->so_pcb = NULL; saved_unp_addr = unp->unp_addr; unp->unp_addr = NULL; - unp->unp_refcount--; - freeunp = (unp->unp_refcount == 0); + unp->unp_socket = NULL; + freeunp = unp_pcb_rele(unp); if (saved_unp_addr != NULL) free(saved_unp_addr, M_SONAME); - if (freeunp) { - UNP_PCB_LOCK_DESTROY(unp); - uma_zfree(unp_zone, unp); - } else + if (!freeunp) UNP_PCB_UNLOCK(unp); #ifndef __rtems__ - if (vp) + if (vp) { + mtx_unlock(vplock); vrele(vp); + } if (local_unp_rights) taskqueue_enqueue_timeout(taskqueue_thread, &unp_gc_task, -1); #endif /* __rtems__ */ @@ -828,20 +982,32 @@ static int uipc_disconnect(struct socket *so) { struct unpcb *unp, *unp2; + int freed; unp = sotounpcb(so); KASSERT(unp != NULL, ("uipc_disconnect: unp == NULL")); - UNP_LINK_WLOCK(); UNP_PCB_LOCK(unp); - unp2 = unp->unp_conn; - if (unp2 != NULL) { - UNP_PCB_LOCK(unp2); - unp_disconnect(unp, unp2); - UNP_PCB_UNLOCK(unp2); + if ((unp2 = unp->unp_conn) == NULL) { + UNP_PCB_UNLOCK(unp); + return (0); } - UNP_PCB_UNLOCK(unp); - UNP_LINK_WUNLOCK(); + if (unp == unp2) { + if (unp_pcb_rele(unp) == 0) + UNP_PCB_UNLOCK(unp); + } + unp_pcb_owned_lock2(unp, unp2, freed); + if (__predict_false(freed)) { + UNP_PCB_UNLOCK(unp); + return (0); + } + unp_pcb_hold(unp2); + unp_pcb_hold(unp); + unp_disconnect(unp, unp2); + if (unp_pcb_rele(unp) == 0) + UNP_PCB_UNLOCK(unp); + if (unp_pcb_rele(unp2) == 0) + UNP_PCB_UNLOCK(unp2); return (0); } @@ -960,13 +1126,35 @@ uipc_rcvd(struct socket *so, int flags) } static int +connect_internal(struct socket *so, struct sockaddr *nam, struct thread *td) +{ + int error; + struct unpcb *unp; + + unp = so->so_pcb; + if (unp->unp_conn != NULL) + return (EISCONN); + error = unp_connect(so, nam, td); + if (error) + return (error); + UNP_PCB_LOCK(unp); + if (unp->unp_conn == NULL) { + UNP_PCB_UNLOCK(unp); + if (error == 0) + error = ENOTCONN; + } + return (error); +} + + +static int uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct thread *td) { struct unpcb *unp, *unp2; struct socket *so2; u_int mbcnt, sbcc; - int error = 0; + int freed, error; unp = sotounpcb(so); KASSERT(unp != NULL, ("%s: unp == NULL", __func__)); @@ -974,6 +1162,7 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, so->so_type == SOCK_SEQPACKET, ("%s: socktype %d", __func__, so->so_type)); + freed = error = 0; if (flags & PRUS_OOB) { error = EOPNOTSUPP; goto release; @@ -981,53 +1170,72 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, #ifndef __rtems__ if (control != NULL && (error = unp_internalize(&control, td))) goto release; -#else /* __rtems__ */ - if (control != NULL) { - error = ENOSYS; - goto release; - } #endif /* __rtems__ */ - if ((nam != NULL) || (flags & PRUS_EOF)) - UNP_LINK_WLOCK(); - else - UNP_LINK_RLOCK(); + + unp2 = NULL; switch (so->so_type) { case SOCK_DGRAM: { const struct sockaddr *from; - unp2 = unp->unp_conn; if (nam != NULL) { - UNP_LINK_WLOCK_ASSERT(); - if (unp2 != NULL) { - error = EISCONN; + /* + * We return with UNP_PCB_LOCK_HELD so we know that + * the reference is live if the pointer is valid. + */ + if ((error = connect_internal(so, nam, td))) + break; + MPASS(unp->unp_conn != NULL); + unp2 = unp->unp_conn; + } else { + UNP_PCB_LOCK(unp); + + /* + * Because connect() and send() are non-atomic in a sendto() + * with a target address, it's possible that the socket will + * have disconnected before the send() can run. In that case + * return the slightly counter-intuitive but otherwise + * correct error that the socket is not connected. + */ + if ((unp2 = unp->unp_conn) == NULL) { + UNP_PCB_UNLOCK(unp); + error = ENOTCONN; break; } - error = unp_connect(so, nam, td); - if (error) + } + if (__predict_false(unp == unp2)) { + if (unp->unp_socket == NULL) { + error = ENOTCONN; break; - unp2 = unp->unp_conn; + } + goto connect_self; + } + unp_pcb_owned_lock2(unp, unp2, freed); + if (__predict_false(freed)) { + UNP_PCB_UNLOCK(unp); + error = ENOTCONN; + break; } - /* - * Because connect() and send() are non-atomic in a sendto() - * with a target address, it's possible that the socket will - * have disconnected before the send() can run. In that case - * return the slightly counter-intuitive but otherwise - * correct error that the socket is not connected. + * The socket referencing unp2 may have been closed + * or unp may have been disconnected if the unp lock + * was dropped to acquire unp2. */ - if (unp2 == NULL) { + if (__predict_false(unp->unp_conn == NULL) || + unp2->unp_socket == NULL) { + UNP_PCB_UNLOCK(unp); + if (unp_pcb_rele(unp2) == 0) + UNP_PCB_UNLOCK(unp2); error = ENOTCONN; break; } - /* Lockless read. */ + connect_self: if (unp2->unp_flags & UNP_WANTCRED) #ifndef __rtems__ control = unp_addsockcred(td, control); #else /* __rtems__ */ control = NULL; #endif /* __rtems__ */ - UNP_PCB_LOCK(unp); if (unp->unp_addr != NULL) from = (struct sockaddr *)unp->unp_addr; else @@ -1043,12 +1251,10 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, SOCKBUF_UNLOCK(&so2->so_rcv); error = ENOBUFS; } - if (nam != NULL) { - UNP_LINK_WLOCK_ASSERT(); - UNP_PCB_LOCK(unp2); + if (nam != NULL) unp_disconnect(unp, unp2); + if (__predict_true(unp != unp2)) UNP_PCB_UNLOCK(unp2); - } UNP_PCB_UNLOCK(unp); break; } @@ -1057,42 +1263,37 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, case SOCK_STREAM: if ((so->so_state & SS_ISCONNECTED) == 0) { if (nam != NULL) { - UNP_LINK_WLOCK_ASSERT(); - error = unp_connect(so, nam, td); - if (error) - break; /* XXX */ - } else { + if ((error = connect_internal(so, nam, td))) + break; + } else { error = ENOTCONN; break; } - } - - /* Lockless read. */ - if (so->so_snd.sb_state & SBS_CANTSENDMORE) { + } else if ((unp2 = unp->unp_conn) == NULL) { + error = ENOTCONN; + break; + } else if (so->so_snd.sb_state & SBS_CANTSENDMORE) { error = EPIPE; break; + } else { + UNP_PCB_LOCK(unp); + if ((unp2 = unp->unp_conn) == NULL) { + UNP_PCB_UNLOCK(unp); + error = ENOTCONN; + break; + } } - - /* - * Because connect() and send() are non-atomic in a sendto() - * with a target address, it's possible that the socket will - * have disconnected before the send() can run. In that case - * return the slightly counter-intuitive but otherwise - * correct error that the socket is not connected. - * - * Locking here must be done carefully: the linkage lock - * prevents interconnections between unpcbs from changing, so - * we can traverse from unp to unp2 without acquiring unp's - * lock. Socket buffer locks follow unpcb locks, so we can - * acquire both remote and lock socket buffer locks. - */ - unp2 = unp->unp_conn; - if (unp2 == NULL) { + unp_pcb_owned_lock2(unp, unp2, freed); + UNP_PCB_UNLOCK(unp); + if (__predict_false(freed)) { + error = ENOTCONN; + break; + } + if ((so2 = unp2->unp_socket) == NULL) { + UNP_PCB_UNLOCK(unp2); error = ENOTCONN; break; } - so2 = unp2->unp_socket; - UNP_PCB_LOCK(unp2); SOCKBUF_LOCK(&so2->so_rcv); if (unp2->unp_flags & UNP_WANTCRED) { #ifndef __rtems__ @@ -1167,12 +1368,6 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, unp_shutdown(unp); UNP_PCB_UNLOCK(unp); } - - if ((nam != NULL) || (flags & PRUS_EOF)) - UNP_LINK_WUNLOCK(); - else - UNP_LINK_RUNLOCK(); - if (control != NULL && error != 0) #ifndef __rtems__ unp_dispose_mbuf(control); @@ -1249,12 +1444,10 @@ uipc_shutdown(struct socket *so) unp = sotounpcb(so); KASSERT(unp != NULL, ("uipc_shutdown: unp == NULL")); - UNP_LINK_WLOCK(); UNP_PCB_LOCK(unp); socantsendmore(so); unp_shutdown(unp); UNP_PCB_UNLOCK(unp); - UNP_LINK_WUNLOCK(); return (0); } @@ -1470,16 +1663,13 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, #ifndef __rtems__ cap_rights_t rights; #endif /* __rtems__ */ - int error, len; + int error, len, freed; +#ifndef __rtems__ + struct mtx *vplock; +#endif /* __rtems__ */ if (nam->sa_family != AF_UNIX) return (EAFNOSUPPORT); - - UNP_LINK_WLOCK_ASSERT(); - - unp = sotounpcb(so); - KASSERT(unp != NULL, ("unp_connect: unp == NULL")); - if (nam->sa_len > sizeof(struct sockaddr_un)) return (EINVAL); len = nam->sa_len - offsetof(struct sockaddr_un, sun_path); @@ -1490,12 +1680,12 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, buf[len] = 0; #endif /* __rtems__ */ + unp = sotounpcb(so); UNP_PCB_LOCK(unp); if (unp->unp_flags & UNP_CONNECTING) { UNP_PCB_UNLOCK(unp); return (EALREADY); } - UNP_LINK_WUNLOCK(); unp->unp_flags |= UNP_CONNECTING; UNP_PCB_UNLOCK(unp); @@ -1548,12 +1738,9 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, unp = sotounpcb(so); KASSERT(unp != NULL, ("unp_connect: unp == NULL")); - /* - * Lock linkage lock for two reasons: make sure v_socket is stable, - * and to protect simultaneous locking of multiple pcbs. - */ - UNP_LINK_WLOCK(); #ifndef __rtems__ + vplock = mtx_pool_find(mtxpool_sleep, vp); + mtx_lock(vplock); VOP_UNP_CONNECT(vp, &unp2); if (unp2 == NULL) { error = ECONNREFUSED; @@ -1572,8 +1759,6 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, error = EPROTOTYPE; goto bad2; } - UNP_PCB_LOCK(unp); - UNP_PCB_LOCK(unp2); if (so->so_proto->pr_flags & PR_CONNREQUIRED) { if (so2->so_options & SO_ACCEPTCONN) { CURVNET_SET(so2->so_vnet); @@ -1583,10 +1768,10 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, so2 = NULL; if (so2 == NULL) { error = ECONNREFUSED; - goto bad3; + goto bad2; } unp3 = sotounpcb(so2); - UNP_PCB_LOCK(unp3); + unp_pcb_lock2(unp2, unp3); if (unp2->unp_addr != NULL) { bcopy(unp2->unp_addr, sa, unp2->unp_addr->sun_len); unp3->unp_addr = (struct sockaddr_un *) sa; @@ -1613,28 +1798,40 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, unp3->unp_flags |= UNP_WANTCRED; UNP_PCB_UNLOCK(unp2); unp2 = unp3; + unp_pcb_owned_lock2(unp2, unp, freed); + if (__predict_false(freed)) { + UNP_PCB_UNLOCK(unp2); + error = ECONNREFUSED; + goto bad2; + } #ifdef MAC mac_socketpeer_set_from_socket(so, so2); mac_socketpeer_set_from_socket(so2, so); #endif + } else { + if (unp == unp2) + UNP_PCB_LOCK(unp); + else + unp_pcb_lock2(unp, unp2); } - KASSERT(unp2 != NULL && so2 != NULL && unp2->unp_socket == so2 && sotounpcb(so2) == unp2, ("%s: unp2 %p so2 %p", __func__, unp2, so2)); error = unp_connect2(so, so2, PRU_CONNECT); -bad3: - UNP_PCB_UNLOCK(unp2); + if (unp != unp2) + UNP_PCB_UNLOCK(unp2); UNP_PCB_UNLOCK(unp); bad2: - UNP_LINK_WUNLOCK(); +#ifndef __rtems__ + mtx_unlock(vplock); +#endif /* __rtems__ */ bad: #ifndef __rtems__ - if (vp != NULL) + if (vp != NULL) { vput(vp); + } #endif /* __rtems__ */ free(sa, M_SONAME); - UNP_LINK_WLOCK(); UNP_PCB_LOCK(unp); unp->unp_flags &= ~UNP_CONNECTING; UNP_PCB_UNLOCK(unp); @@ -1652,7 +1849,6 @@ unp_connect2(struct socket *so, struct socket *so2, int req) unp2 = sotounpcb(so2); KASSERT(unp2 != NULL, ("unp_connect2: unp2 == NULL")); - UNP_LINK_WLOCK_ASSERT(); UNP_PCB_LOCK_ASSERT(unp); UNP_PCB_LOCK_ASSERT(unp2); @@ -1660,10 +1856,13 @@ unp_connect2(struct socket *so, struct socket *so2, int req) return (EPROTOTYPE); unp2->unp_flags &= ~UNP_NASCENT; unp->unp_conn = unp2; - + unp_pcb_hold(unp2); + unp_pcb_hold(unp); switch (so->so_type) { case SOCK_DGRAM: + UNP_REF_LIST_LOCK(); LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink); + UNP_REF_LIST_UNLOCK(); soisconnected(so); break; @@ -1687,31 +1886,47 @@ unp_connect2(struct socket *so, struct socket *so2, int req) static void unp_disconnect(struct unpcb *unp, struct unpcb *unp2) { - struct socket *so; + struct socket *so, *so2; + int freed __unused; KASSERT(unp2 != NULL, ("unp_disconnect: unp2 == NULL")); - UNP_LINK_WLOCK_ASSERT(); UNP_PCB_LOCK_ASSERT(unp); UNP_PCB_LOCK_ASSERT(unp2); + if (unp->unp_conn == NULL && unp2->unp_conn == NULL) + return; + + MPASS(unp->unp_conn == unp2); unp->unp_conn = NULL; + so = unp->unp_socket; + so2 = unp2->unp_socket; switch (unp->unp_socket->so_type) { case SOCK_DGRAM: + UNP_REF_LIST_LOCK(); LIST_REMOVE(unp, unp_reflink); - so = unp->unp_socket; - SOCK_LOCK(so); - so->so_state &= ~SS_ISCONNECTED; - SOCK_UNLOCK(so); + UNP_REF_LIST_UNLOCK(); + if (so) { + SOCK_LOCK(so); + so->so_state &= ~SS_ISCONNECTED; + SOCK_UNLOCK(so); + } break; case SOCK_STREAM: case SOCK_SEQPACKET: - soisdisconnected(unp->unp_socket); + if (so) + soisdisconnected(so); + MPASS(unp2->unp_conn == unp); unp2->unp_conn = NULL; - soisdisconnected(unp2->unp_socket); + if (so2) + soisdisconnected(so2); break; } + freed = unp_pcb_rele(unp); + MPASS(freed == 0); + freed = unp_pcb_rele(unp2); + MPASS(freed == 0); } /* @@ -1795,7 +2010,7 @@ unp_pcblist(SYSCTL_HANDLER_ARGS) continue; } unp_list[i++] = unp; - unp->unp_refcount++; + unp_pcb_hold(unp); } UNP_PCB_UNLOCK(unp); } @@ -1807,8 +2022,9 @@ unp_pcblist(SYSCTL_HANDLER_ARGS) for (i = 0; i < n; i++) { unp = unp_list[i]; UNP_PCB_LOCK(unp); - unp->unp_refcount--; - if (unp->unp_refcount != 0 && unp->unp_gencnt <= gencnt) { + freeunp = unp_pcb_rele(unp); + + if (freeunp == 0 && unp->unp_gencnt <= gencnt) { xu->xu_len = sizeof *xu; xu->xu_unpp = unp; /* @@ -1835,14 +2051,8 @@ unp_pcblist(SYSCTL_HANDLER_ARGS) sotoxsocket(unp->unp_socket, &xu->xu_socket); UNP_PCB_UNLOCK(unp); error = SYSCTL_OUT(req, xu, sizeof *xu); - } else { - freeunp = (unp->unp_refcount == 0); + } else if (freeunp == 0) UNP_PCB_UNLOCK(unp); - if (freeunp) { - UNP_PCB_LOCK_DESTROY(unp); - uma_zfree(unp_zone, unp); - } - } } free(xu, M_TEMP); if (!error) { @@ -1879,7 +2089,6 @@ unp_shutdown(struct unpcb *unp) struct unpcb *unp2; struct socket *so; - UNP_LINK_WLOCK_ASSERT(); UNP_PCB_LOCK_ASSERT(unp); unp2 = unp->unp_conn; @@ -1896,22 +2105,30 @@ unp_drop(struct unpcb *unp) { struct socket *so = unp->unp_socket; struct unpcb *unp2; - - UNP_LINK_WLOCK_ASSERT(); - UNP_PCB_LOCK_ASSERT(unp); + int freed; /* * Regardless of whether the socket's peer dropped the connection * with this socket by aborting or disconnecting, POSIX requires * that ECONNRESET is returned. */ - so->so_error = ECONNRESET; + /* acquire a reference so that unp isn't freed from underneath us */ + + UNP_PCB_LOCK(unp); + if (so) + so->so_error = ECONNRESET; unp2 = unp->unp_conn; - if (unp2 == NULL) - return; - UNP_PCB_LOCK(unp2); - unp_disconnect(unp, unp2); - UNP_PCB_UNLOCK(unp2); + if (unp2 == unp) { + unp_disconnect(unp, unp2); + } else if (unp2 != NULL) { + unp_pcb_hold(unp2); + unp_pcb_owned_lock2(unp, unp2, freed); + unp_disconnect(unp, unp2); + if (unp_pcb_rele(unp2) == 0) + UNP_PCB_UNLOCK(unp2); + } + if (unp_pcb_rele(unp) == 0) + UNP_PCB_UNLOCK(unp); } #ifndef __rtems__ @@ -2053,7 +2270,7 @@ unp_init(void) return; #endif unp_zone = uma_zcreate("unpcb", sizeof(struct unpcb), NULL, NULL, - NULL, NULL, UMA_ALIGN_PTR, 0); + NULL, NULL, UMA_ALIGN_CACHE, 0); if (unp_zone == NULL) panic("unp_init"); uma_zone_set_max(unp_zone, maxsockets); @@ -2639,13 +2856,15 @@ vfs_unp_reclaim(struct vnode *vp) { struct unpcb *unp; int active; + struct mtx *vplock; ASSERT_VOP_ELOCKED(vp, "vfs_unp_reclaim"); KASSERT(vp->v_type == VSOCK, ("vfs_unp_reclaim: vp->v_type != VSOCK")); active = 0; - UNP_LINK_WLOCK(); + vplock = mtx_pool_find(mtxpool_sleep, vp); + mtx_lock(vplock); VOP_UNP_CONNECT(vp, &unp); if (unp == NULL) goto done; @@ -2656,8 +2875,8 @@ vfs_unp_reclaim(struct vnode *vp) active = 1; } UNP_PCB_UNLOCK(unp); -done: - UNP_LINK_WUNLOCK(); + done: + mtx_unlock(vplock); if (active) vunref(vp); } diff --git a/freebsd/sys/mips/include/machine/cpufunc.h b/freebsd/sys/mips/include/machine/cpufunc.h index a83d22bf..7cfc548c 100644 --- a/freebsd/sys/mips/include/machine/cpufunc.h +++ b/freebsd/sys/mips/include/machine/cpufunc.h @@ -108,6 +108,12 @@ mips_wbflush(void) #endif } +static __inline void +breakpoint(void) +{ + __asm __volatile ("break"); +} + #ifdef _KERNEL /* * XXX @@ -279,6 +285,8 @@ MIPS_RW32_COP0(entrylo0, MIPS_COP_0_TLB_LO0); MIPS_RW32_COP0(entrylo1, MIPS_COP_0_TLB_LO1); #endif MIPS_RW32_COP0(prid, MIPS_COP_0_PRID); +MIPS_RW32_COP0_SEL(cinfo, MIPS_COP_0_PRID, 6); +MIPS_RW32_COP0_SEL(tinfo, MIPS_COP_0_PRID, 7); /* XXX 64-bit? */ MIPS_RW32_COP0_SEL(ebase, MIPS_COP_0_PRID, 1); @@ -363,12 +371,6 @@ get_intr_mask(void) return (mips_rd_status() & MIPS_SR_INT_MASK); } -static __inline void -breakpoint(void) -{ - __asm __volatile ("break"); -} - #if defined(__GNUC__) && !defined(__mips_o32) #define mips3_ld(a) (*(const volatile uint64_t *)(a)) #define mips3_sd(a, v) (*(volatile uint64_t *)(a) = (v)) diff --git a/freebsd/sys/net/altq/altq_subr.c b/freebsd/sys/net/altq/altq_subr.c index 6a385560..47a353fc 100644 --- a/freebsd/sys/net/altq/altq_subr.c +++ b/freebsd/sys/net/altq/altq_subr.c @@ -436,8 +436,8 @@ tbr_timeout(arg) VNET_LIST_RLOCK_NOSLEEP(); VNET_FOREACH(vnet_iter) { CURVNET_SET(vnet_iter); - for (ifp = TAILQ_FIRST(&V_ifnet); ifp; - ifp = TAILQ_NEXT(ifp, if_link)) { + for (ifp = CK_STAILQ_FIRST(&V_ifnet); ifp; + ifp = CK_STAILQ_NEXT(ifp, if_link)) { /* read from if_snd unlocked */ if (!TBR_IS_ENABLED(&ifp->if_snd)) continue; diff --git a/freebsd/sys/net/bpf.c b/freebsd/sys/net/bpf.c index 24927e8b..57aff5b8 100644 --- a/freebsd/sys/net/bpf.c +++ b/freebsd/sys/net/bpf.c @@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_bpf.h> -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_ddb.h> #include <rtems/bsd/local/opt_netgraph.h> @@ -106,6 +105,10 @@ __FBSDID("$FreeBSD$"); MALLOC_DEFINE(M_BPF, "BPF", "BPF data"); +static struct bpf_if_ext dead_bpf_if = { + .bif_dlist = LIST_HEAD_INITIALIZER() +}; + struct bpf_if { #define bif_next bif_ext.bif_next #define bif_dlist bif_ext.bif_dlist @@ -167,6 +170,9 @@ struct bpf_dltlist32 { #define BIOCSETFNR32 _IOW('B', 130, struct bpf_program32) #endif +#define BPF_LOCK() sx_xlock(&bpf_sx) +#define BPF_UNLOCK() sx_xunlock(&bpf_sx) +#define BPF_LOCK_ASSERT() sx_assert(&bpf_sx, SA_XLOCKED) /* * bpf_iflist is a list of BPF interface structures, each corresponding to a * specific DLT. The same network interface might have several BPF interface @@ -174,7 +180,7 @@ struct bpf_dltlist32 { * frames, ethernet frames, etc). */ static LIST_HEAD(, bpf_if) bpf_iflist, bpf_freelist; -static struct mtx bpf_mtx; /* bpf global lock */ +static struct sx bpf_sx; /* bpf global lock */ static int bpf_bpfd_cnt; static void bpf_attachd(struct bpf_d *, struct bpf_if *); @@ -2752,7 +2758,7 @@ bpfdetach(struct ifnet *ifp) */ BPFIF_WLOCK(bp); bp->bif_flags |= BPFIF_FLAG_DYING; - *bp->bif_bpf = NULL; + *bp->bif_bpf = (struct bpf_if *)&dead_bpf_if; BPFIF_WUNLOCK(bp); CTR4(KTR_NET, "%s: sheduling free for encap %d (%p) for if %p", @@ -3090,7 +3096,7 @@ bpf_drvinit(void *unused) int rv; #endif /* __rtems__ */ - mtx_init(&bpf_mtx, "bpf global lock", NULL, MTX_DEF); + sx_init(&bpf_sx, "bpf global lock"); LIST_INIT(&bpf_iflist); LIST_INIT(&bpf_freelist); @@ -3253,13 +3259,13 @@ bpf_stats_sysctl(SYSCTL_HANDLER_ARGS) SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,bpf_drvinit,NULL); #else /* !DEV_BPF && !NETGRAPH_BPF */ + /* * NOP stubs to allow bpf-using drivers to load and function. * * A 'better' implementation would allow the core bpf functionality * to be loaded at runtime. */ -static struct bpf_if bp_null; void bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) @@ -3287,7 +3293,7 @@ void bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) { - *driverp = &bp_null; + *driverp = (struct bpf_if *)&dead_bpf_if; } void diff --git a/freebsd/sys/net/bpfdesc.h b/freebsd/sys/net/bpfdesc.h index 695d3d40..95093cff 100644 --- a/freebsd/sys/net/bpfdesc.h +++ b/freebsd/sys/net/bpfdesc.h @@ -125,9 +125,6 @@ struct bpf_d { #define BPF_PID_REFRESH_CUR(bd) do { } while (0) #endif /* __rtems__ */ -#define BPF_LOCK() mtx_lock(&bpf_mtx) -#define BPF_UNLOCK() mtx_unlock(&bpf_mtx) -#define BPF_LOCK_ASSERT() mtx_assert(&bpf_mtx, MA_OWNED) /* * External representation of the bpf descriptor */ diff --git a/freebsd/sys/net/bridgestp.c b/freebsd/sys/net/bridgestp.c index 472b9634..49e772b3 100644 --- a/freebsd/sys/net/bridgestp.c +++ b/freebsd/sys/net/bridgestp.c @@ -2045,7 +2045,7 @@ bstp_reinit(struct bstp_state *bs) * bridges in the same STP domain. */ IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if (ifp->if_type != IFT_ETHER) continue; /* Not Ethernet */ diff --git a/freebsd/sys/net/dlt.h b/freebsd/sys/net/dlt.h index dc818521..639e5a7f 100644 --- a/freebsd/sys/net/dlt.h +++ b/freebsd/sys/net/dlt.h @@ -122,9 +122,9 @@ /* * 18 is used for DLT_PFSYNC in OpenBSD, NetBSD, DragonFly BSD and - * Mac OS X; don't use it for anything else. (FreeBSD uses 121, - * which collides with DLT_HHDLC, even though it doesn't use 18 - * for anything and doesn't appear to have ever used it for anything.) + * macOS; don't use it for anything else. (FreeBSD uses 121, which + * collides with DLT_HHDLC, even though it doesn't use 18 for + * anything and doesn't appear to have ever used it for anything.) * * We define it as 18 on those platforms; it is, unfortunately, used * for DLT_CIP in Suse 6.3, so we don't define it as DLT_PFSYNC @@ -342,7 +342,7 @@ * * FreeBSD's libpcap won't map a link-layer header type of 18 - i.e., * DLT_PFSYNC files from OpenBSD and possibly older versions of NetBSD, - * DragonFly BSD, and OS X - to DLT_PFSYNC, so code built with FreeBSD's + * DragonFly BSD, and macOS - to DLT_PFSYNC, so code built with FreeBSD's * libpcap won't treat those files as DLT_PFSYNC files. * * Other libpcaps won't map a link-layer header type of 121 to DLT_PFSYNC; @@ -948,14 +948,14 @@ * the pseudo-header is: * * struct dl_ipnetinfo { - * u_int8_t dli_version; - * u_int8_t dli_family; - * u_int16_t dli_htype; - * u_int32_t dli_pktlen; - * u_int32_t dli_ifindex; - * u_int32_t dli_grifindex; - * u_int32_t dli_zsrc; - * u_int32_t dli_zdst; + * uint8_t dli_version; + * uint8_t dli_family; + * uint16_t dli_htype; + * uint32_t dli_pktlen; + * uint32_t dli_ifindex; + * uint32_t dli_grifindex; + * uint32_t dli_zsrc; + * uint32_t dli_zdst; * }; * * dli_version is 2 for the current version of the pseudo-header. @@ -1231,7 +1231,7 @@ * So I'll just give them one; hopefully this will show up in a * libpcap release in time for them to get this into 10.10 Big Sur * or whatever Mavericks' successor is called. LINKTYPE_PKTAP - * will be 258 *even on OS X*; that is *intentional*, so that + * will be 258 *even on macOS*; that is *intentional*, so that * PKTAP files look the same on *all* OSes (different OSes can have * different numerical values for a given DLT_, but *MUST NOT* have * different values for what goes in a file, as files can be moved @@ -1243,9 +1243,9 @@ * and that will continue to be DLT_USER2 on Darwin-based OSes. That way, * binary compatibility with Mavericks is preserved for programs using * this version of libpcap. This does mean that if you were using - * DLT_USER2 for some capture device on OS X, you can't do so with + * DLT_USER2 for some capture device on macOS, you can't do so with * this version of libpcap, just as you can't with Apple's libpcap - - * on OS X, they define DLT_PKTAP to be DLT_USER2, so programs won't + * on macOS, they define DLT_PKTAP to be DLT_USER2, so programs won't * be able to distinguish between PKTAP and whatever you were using * DLT_USER2 for. * @@ -1305,6 +1305,66 @@ #define DLT_RDS 265 /* + * USB packets, beginning with a Darwin (macOS, etc.) header. + */ +#define DLT_USB_DARWIN 266 + +/* + * OpenBSD DLT_OPENFLOW. + */ +#define DLT_OPENFLOW 267 + +/* + * SDLC frames containing SNA PDUs. + */ +#define DLT_SDLC 268 + +/* + * per "Selvig, Bjorn" <b.selvig@ti.com> used for + * TI protocol sniffer. + */ +#define DLT_TI_LLN_SNIFFER 269 + +/* + * per: Erik de Jong <erikdejong at gmail.com> for + * https://github.com/eriknl/LoRaTap/releases/tag/v0.1 + */ +#define DLT_LORATAP 270 + +/* + * per: Stefanha at gmail.com for + * http://lists.sandelman.ca/pipermail/tcpdump-workers/2017-May/000772.html + * and: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vsockmon.h + * for: http://qemu-project.org/Features/VirtioVsock + */ +#define DLT_VSOCK 271 + +/* + * Nordic Semiconductor Bluetooth LE sniffer. + */ +#define DLT_NORDIC_BLE 272 + +/* + * Excentis DOCSIS 3.1 RF sniffer (XRA-31) + * per: bruno.verstuyft at excentis.com + * http://www.xra31.com/xra-header + */ +#define DLT_DOCSIS31_XRA31 273 + +/* + * mPackets, as specified by IEEE 802.3br Figure 99-4, starting + * with the preamble and always ending with a CRC field. + */ +#define DLT_ETHERNET_MPACKET 274 + +/* + * DisplayPort AUX channel monitoring data as specified by VESA + * DisplayPort(DP) Standard preceeded by a pseudo-header. + * per dirk.eibach at gdsys.cc + */ +#define DLT_DISPLAYPORT_AUX 275 + +/* * In case the code that includes this file (directly or indirectly) * has also included OS files that happen to define DLT_MATCHING_MAX, * with a different value (perhaps because that OS hasn't picked up @@ -1314,7 +1374,7 @@ #ifdef DLT_MATCHING_MAX #undef DLT_MATCHING_MAX #endif -#define DLT_MATCHING_MAX 265 /* highest value in the "matching" range */ +#define DLT_MATCHING_MAX 275 /* highest value in the "matching" range */ /* * DLT and savefile link type values are split into a class and diff --git a/freebsd/sys/net/fddi.h b/freebsd/sys/net/fddi.h deleted file mode 100644 index 0badcc3c..00000000 --- a/freebsd/sys/net/fddi.h +++ /dev/null @@ -1,107 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * Copyright (c) 1995 Matt Thomas (thomas@lkg.dec.com) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)if_fddi.h 8.1 (Berkeley) 6/10/93 - * $FreeBSD$ - */ - -#ifndef _NETINET_IF_FDDI_H_ -#define _NETINET_IF_FDDI_H_ - -#define FDDIIPMTU 4352 -#define FDDIMTU 4470 -#define FDDIMIN 3 - -#define FDDIFC_C 0x80 /* 0b10000000 */ -#define FDDIFC_L 0x40 /* 0b01000000 */ -#define FDDIFC_F 0x30 /* 0b00110000 */ -#define FDDIFC_Z 0x0F /* 0b00001111 */ -#define FDDIFC_CLFF 0xF0 /* Class/Length/Format bits */ -#define FDDIFC_ZZZZ 0x0F /* Control bits */ - -/* - * FDDI Frame Control values. (48-bit addressing only). - */ -#define FDDIFC_VOID 0x40 /* Void frame */ -#define FDDIFC_NRT 0x80 /* Nonrestricted token */ -#define FDDIFC_RT 0xc0 /* Restricted token */ -#define FDDIFC_MAC_BEACON 0xc2 /* MAC Beacon frame */ -#define FDDIFC_MAC_CLAIM 0xc3 /* MAC Claim frame */ -#define FDDIFC_LLC_ASYNC 0x50 -#define FDDIFC_LLC_PRIO0 0 -#define FDDIFC_LLC_PRIO1 1 -#define FDDIFC_LLC_PRIO2 2 -#define FDDIFC_LLC_PRIO3 3 -#define FDDIFC_LLC_PRIO4 4 -#define FDDIFC_LLC_PRIO5 5 -#define FDDIFC_LLC_PRIO6 6 -#define FDDIFC_LLC_PRIO7 7 -#define FDDIFC_LLC_SYNC 0xd0 -#define FDDIFC_IMP_ASYNC 0x60 /* Implementor Async. */ -#define FDDIFC_IMP_SYNC 0xe0 /* Implementor Synch. */ -#define FDDIFC_SMT 0x40 -#define FDDIFC_SMT_INFO 0x41 /* SMT Info */ -#define FDDIFC_SMT_NSA 0x4F /* SMT Next station adrs */ -#define FDDIFC_MAC 0xc0 /* MAC frame */ - -#define FDDI_ADDR_LEN 6 -#define FDDI_HDR_LEN (sizeof(struct fddi_header)) - -/* - * Structure of an 100Mb/s FDDI header. - */ -struct fddi_header { - u_char fddi_fc; - u_char fddi_dhost[FDDI_ADDR_LEN]; - u_char fddi_shost[FDDI_ADDR_LEN]; -}; - -#if defined(_KERNEL) -#define fddi_ipmulticast_min ether_ipmulticast_min -#define fddi_ipmulticast_max ether_ipmulticast_max -#define fddi_addmulti ether_addmulti -#define fddi_delmulti ether_delmulti -#define fddi_sprintf ether_sprintf - -#define FDDI_BPF_UNSUPPORTED 0 -#define FDDI_BPF_SUPPORTED 1 - -void fddi_ifattach(struct ifnet *, const u_int8_t *, int); -void fddi_ifdetach(struct ifnet *, int); -int fddi_ioctl(struct ifnet *, u_long, caddr_t); - -#endif /* _KERNEL */ -#endif /* _NET_FDDI_H_ */ diff --git a/freebsd/sys/net/if.c b/freebsd/sys/net/if.c index bbf2ddd0..d4c18b46 100644 --- a/freebsd/sys/net/if.c +++ b/freebsd/sys/net/if.c @@ -34,7 +34,6 @@ * $FreeBSD$ */ -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_inet6.h> #include <rtems/bsd/local/opt_inet.h> @@ -44,6 +43,7 @@ #include <sys/malloc.h> #include <sys/sbuf.h> #include <sys/bus.h> +#include <sys/epoch.h> #include <sys/mbuf.h> #include <sys/systm.h> #include <sys/priv.h> @@ -90,6 +90,7 @@ #include <netinet/ip_carp.h> #ifdef INET #include <netinet/if_ether.h> +#include <netinet/netdump/netdump.h> #endif /* INET */ #ifdef INET6 #include <netinet6/in6_var.h> @@ -106,6 +107,13 @@ _Static_assert(sizeof(((struct ifreq *)0)->ifr_name) == offsetof(struct ifreq, ifr_ifru), "gap between ifr_name and ifr_ifru"); +#ifndef __rtems__ +__read_mostly epoch_t net_epoch_preempt; +__read_mostly epoch_t net_epoch; +#else /* __rtems__ */ +EPOCH_DEFINE(_bsd_net_epoch_preempt, EPOCH_PREEMPT); +EPOCH_DEFINE(_bsd_net_epoch, 0); +#endif /* __rtems__ */ #ifdef COMPAT_FREEBSD32 #include <sys/mount.h> #include <compat/freebsd32/freebsd32.h> @@ -144,7 +152,37 @@ struct ifreq32 { CTASSERT(sizeof(struct ifreq) == sizeof(struct ifreq32)); CTASSERT(__offsetof(struct ifreq, ifr_ifru) == __offsetof(struct ifreq32, ifr_ifru)); -#endif + +struct ifgroupreq32 { + char ifgr_name[IFNAMSIZ]; + u_int ifgr_len; + union { + char ifgru_group[IFNAMSIZ]; + uint32_t ifgru_groups; + } ifgr_ifgru; +}; + +struct ifmediareq32 { + char ifm_name[IFNAMSIZ]; + int ifm_current; + int ifm_mask; + int ifm_status; + int ifm_active; + int ifm_count; + uint32_t ifm_ulist; /* (int *) */ +}; +#define SIOCGIFMEDIA32 _IOC_NEWTYPE(SIOCGIFMEDIA, struct ifmediareq32) +#define SIOCGIFXMEDIA32 _IOC_NEWTYPE(SIOCGIFXMEDIA, struct ifmediareq32) + +#define _CASE_IOC_IFGROUPREQ_32(cmd) \ + case _IOC_NEWTYPE((cmd), struct ifgroupreq32): +#else /* !COMPAT_FREEBSD32 */ +#define _CASE_IOC_IFGROUPREQ_32(cmd) +#endif /* !COMPAT_FREEBSD32 */ + +#define CASE_IOC_IFGROUPREQ(cmd) \ + _CASE_IOC_IFGROUPREQ_32(cmd) \ + case (cmd) union ifreq_union { struct ifreq ifr; @@ -153,6 +191,13 @@ union ifreq_union { #endif }; +union ifgroupreq_union { + struct ifgroupreq ifgr; +#ifdef COMPAT_FREEBSD32 + struct ifgroupreq32 ifgr32; +#endif +}; + SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); @@ -185,7 +230,6 @@ static MALLOC_DEFINE(M_IFDESCR, "ifdescr", "ifnet descriptions"); static struct sx ifdescr_sx; SX_SYSINIT(ifdescr_sx, &ifdescr_sx, "ifnet descr"); -void (*bridge_linkstate_p)(struct ifnet *ifp); void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); void (*lagg_linkstate_p)(struct ifnet *ifp, int state); /* These are external hooks for CARP. */ @@ -219,8 +263,7 @@ struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL; static void if_attachdomain(void *); static void if_attachdomain1(struct ifnet *); static int ifconf(u_long, caddr_t); -static void if_freemulti(struct ifmultiaddr *); -static void if_grow(void); +static void *if_grow(void); static void if_input_default(struct ifnet *, struct mbuf *); static int if_requestencap_default(struct ifnet *, struct if_encap_req *); static void if_route(struct ifnet *, int flag, int fam); @@ -309,9 +352,7 @@ ifnet_byindex(u_short idx) { struct ifnet *ifp; - IFNET_RLOCK_NOSLEEP(); ifp = ifnet_byindex_locked(idx); - IFNET_RUNLOCK_NOSLEEP(); return (ifp); } @@ -336,12 +377,11 @@ ifnet_byindex_ref(u_short idx) * failure. */ static u_short -ifindex_alloc(void) +ifindex_alloc(void **old) { u_short idx; IFNET_WLOCK_ASSERT(); -retry: /* * Try to find an empty slot below V_if_index. If we fail, take the * next slot. @@ -353,8 +393,8 @@ retry: /* Catch if_index overflow. */ if (idx >= V_if_indexlim) { - if_grow(); - goto retry; + *old = if_grow(); + return (USHRT_MAX); } if (idx > V_if_index) V_if_index = idx; @@ -383,21 +423,10 @@ ifindex_free(u_short idx) } static void -ifnet_setbyindex_locked(u_short idx, struct ifnet *ifp) -{ - - IFNET_WLOCK_ASSERT(); - - V_ifindex_table[idx] = ifp; -} - -static void ifnet_setbyindex(u_short idx, struct ifnet *ifp) { - IFNET_WLOCK(); - ifnet_setbyindex_locked(idx, ifp); - IFNET_WUNLOCK(); + V_ifindex_table[idx] = ifp; } struct ifaddr * @@ -424,12 +453,15 @@ ifaddr_byindex(u_short idx) static void vnet_if_init(const void *unused __unused) { + void *old; - TAILQ_INIT(&V_ifnet); - TAILQ_INIT(&V_ifg_head); + CK_STAILQ_INIT(&V_ifnet); + CK_STAILQ_INIT(&V_ifg_head); IFNET_WLOCK(); - if_grow(); /* create initial table */ + old = if_grow(); /* create initial table */ IFNET_WUNLOCK(); + epoch_wait_preempt(net_epoch_preempt); + free(old, M_IFNET); vnet_if_clone_init(); } VNET_SYSINIT(vnet_if_init, SI_SUB_INIT_IF, SI_ORDER_SECOND, vnet_if_init, @@ -440,9 +472,9 @@ static void vnet_if_uninit(const void *unused __unused) { - VNET_ASSERT(TAILQ_EMPTY(&V_ifnet), ("%s:%d tailq &V_ifnet=%p " + VNET_ASSERT(CK_STAILQ_EMPTY(&V_ifnet), ("%s:%d tailq &V_ifnet=%p " "not empty", __func__, __LINE__, &V_ifnet)); - VNET_ASSERT(TAILQ_EMPTY(&V_ifg_head), ("%s:%d tailq &V_ifg_head=%p " + VNET_ASSERT(CK_STAILQ_EMPTY(&V_ifg_head), ("%s:%d tailq &V_ifg_head=%p " "not empty", __func__, __LINE__, &V_ifg_head)); free((caddr_t)V_ifindex_table, M_IFNET); @@ -456,7 +488,7 @@ vnet_if_return(const void *unused __unused) struct ifnet *ifp, *nifp; /* Return all inherited interfaces to their parent vnets. */ - TAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) { + CK_STAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) { if (ifp->if_home_vnet != ifp->if_vnet) if_vmove(ifp, ifp->if_home_vnet); } @@ -465,13 +497,16 @@ VNET_SYSUNINIT(vnet_if_return, SI_SUB_VNET_DONE, SI_ORDER_ANY, vnet_if_return, NULL); #endif -static void + +static void * if_grow(void) { int oldlim; u_int n; struct ifnet **e; + void *old; + old = NULL; IFNET_WLOCK_ASSERT(); oldlim = V_if_indexlim; IFNET_WUNLOCK(); @@ -480,14 +515,15 @@ if_grow(void) IFNET_WLOCK(); if (V_if_indexlim != oldlim) { free(e, M_IFNET); - return; + return (NULL); } if (V_ifindex_table != NULL) { memcpy((caddr_t)e, (caddr_t)V_ifindex_table, n/2); - free((caddr_t)V_ifindex_table, M_IFNET); + old = V_ifindex_table; } V_if_indexlim <<= 1; V_ifindex_table = e; + return (old); } /* @@ -500,11 +536,19 @@ if_alloc(u_char type) { struct ifnet *ifp; u_short idx; + void *old; ifp = malloc(sizeof(struct ifnet), M_IFNET, M_WAITOK|M_ZERO); + restart: IFNET_WLOCK(); - idx = ifindex_alloc(); - ifnet_setbyindex_locked(idx, IFNET_HOLD); + idx = ifindex_alloc(&old); + if (__predict_false(idx == USHRT_MAX)) { + IFNET_WUNLOCK(); + epoch_wait_preempt(net_epoch_preempt); + free(old, M_IFNET); + goto restart; + } + ifnet_setbyindex(idx, IFNET_HOLD); IFNET_WUNLOCK(); ifp->if_index = idx; ifp->if_type = type; @@ -525,9 +569,9 @@ if_alloc(u_char type) TASK_INIT(&ifp->if_linktask, 0, do_link_state_change, ifp); ifp->if_afdata_initialized = 0; IF_AFDATA_LOCK_INIT(ifp); - TAILQ_INIT(&ifp->if_addrhead); - TAILQ_INIT(&ifp->if_multiaddrs); - TAILQ_INIT(&ifp->if_groups); + CK_STAILQ_INIT(&ifp->if_addrhead); + CK_STAILQ_INIT(&ifp->if_multiaddrs); + CK_STAILQ_INIT(&ifp->if_groups); #ifdef MAC mac_ifnet_init(ifp); #endif @@ -573,6 +617,15 @@ if_free_internal(struct ifnet *ifp) free(ifp, M_IFNET); } +static void +if_destroy(epoch_context_t ctx) +{ + struct ifnet *ifp; + + ifp = __containerof(ctx, struct ifnet, if_epoch_ctx); + if_free_internal(ifp); +} + /* * Deregister an interface and free the associated storage. */ @@ -591,7 +644,7 @@ if_free(struct ifnet *ifp) IFNET_WUNLOCK(); if (refcount_release(&ifp->if_refcount)) - if_free_internal(ifp); + epoch_call(net_epoch_preempt, &ifp->if_epoch_ctx, if_destroy); CURVNET_RESTORE(); } @@ -614,7 +667,7 @@ if_rele(struct ifnet *ifp) if (!refcount_release(&ifp->if_refcount)) return; - if_free_internal(ifp); + epoch_call(net_epoch_preempt, &ifp->if_epoch_ctx, if_destroy); } void @@ -795,7 +848,7 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc) sdl->sdl_len = masklen; while (namelen != 0) sdl->sdl_data[--namelen] = 0xff; - TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); + CK_STAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); /* Reliably crash if used uninitialized. */ ifp->if_broadcastaddr = NULL; @@ -837,7 +890,7 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc) * of the interface. */ for (ifa = ifp->if_addr; ifa != NULL; - ifa = TAILQ_NEXT(ifa, ifa_link)) { + ifa = CK_STAILQ_NEXT(ifa, ifa_link)) { if (ifa->ifa_addr->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)ifa->ifa_addr; sdl->sdl_index = ifp->if_index; @@ -847,7 +900,7 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc) #endif IFNET_WLOCK(); - TAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link); + CK_STAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link); #ifdef VIMAGE curvnet->vnet_ifcnt++; #endif @@ -864,12 +917,24 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc) rt_ifannouncemsg(ifp, IFAN_ARRIVAL); } +#ifndef __rtems__ +static void +if_epochalloc(void *dummy __unused) +{ + + net_epoch_preempt = epoch_alloc(EPOCH_PREEMPT); + net_epoch = epoch_alloc(0); +} +SYSINIT(ifepochalloc, SI_SUB_TASKQ + 1, SI_ORDER_ANY, + if_epochalloc, NULL); +#endif /* __rtems__ */ + static void if_attachdomain(void *dummy) { struct ifnet *ifp; - TAILQ_FOREACH(ifp, &V_ifnet, if_link) + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) if_attachdomain1(ifp); } SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND, @@ -911,8 +976,8 @@ if_purgeaddrs(struct ifnet *ifp) { struct ifaddr *ifa, *next; - /* XXX cannot hold IF_ADDR_WLOCK over called functions. */ - TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { + NET_EPOCH_ENTER(); + CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { if (ifa->ifa_addr->sa_family == AF_LINK) continue; #ifdef INET @@ -937,10 +1002,11 @@ if_purgeaddrs(struct ifnet *ifp) } #endif /* INET6 */ IF_ADDR_WLOCK(ifp); - TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); + CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_free(ifa); } + NET_EPOCH_EXIT(); } /* @@ -951,11 +1017,13 @@ static void if_purgemaddrs(struct ifnet *ifp) { struct ifmultiaddr *ifma; - struct ifmultiaddr *next; IF_ADDR_WLOCK(ifp); - TAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) + while (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) { + ifma = CK_STAILQ_FIRST(&ifp->if_multiaddrs); + CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); if_delmulti_locked(ifp, ifma, 1); + } IF_ADDR_WUNLOCK(ifp); } @@ -1002,9 +1070,9 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp) ifp->if_vnet->vnet_state < SI_SUB_VNET_DONE) ? 1 : 0; #endif IFNET_WLOCK(); - TAILQ_FOREACH(iter, &V_ifnet, if_link) + CK_STAILQ_FOREACH(iter, &V_ifnet, if_link) if (iter == ifp) { - TAILQ_REMOVE(&V_ifnet, ifp, if_link); + CK_STAILQ_REMOVE(&V_ifnet, ifp, ifnet, if_link); found = 1; break; } @@ -1032,7 +1100,7 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp) #ifdef VIMAGE curvnet->vnet_ifcnt--; #endif - + epoch_wait_preempt(net_epoch_preempt); /* * In any case (destroy or vmove) detach us from the groups * and remove/wait for pending events on the taskq. @@ -1125,9 +1193,9 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp) /* We can now free link ifaddr. */ IF_ADDR_WLOCK(ifp); - if (!TAILQ_EMPTY(&ifp->if_addrhead)) { - ifa = TAILQ_FIRST(&ifp->if_addrhead); - TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); + if (!CK_STAILQ_EMPTY(&ifp->if_addrhead)) { + ifa = CK_STAILQ_FIRST(&ifp->if_addrhead); + CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_free(ifa); } else @@ -1172,6 +1240,7 @@ if_vmove(struct ifnet *ifp, struct vnet *new_vnet) { struct if_clone *ifc; u_int bif_dlt, bif_hdrlen; + void *old; int rc; /* @@ -1212,10 +1281,16 @@ if_vmove(struct ifnet *ifp, struct vnet *new_vnet) * Switch to the context of the target vnet. */ CURVNET_SET_QUIET(new_vnet); - + restart: IFNET_WLOCK(); - ifp->if_index = ifindex_alloc(); - ifnet_setbyindex_locked(ifp->if_index, ifp); + ifp->if_index = ifindex_alloc(&old); + if (__predict_false(ifp->if_index == USHRT_MAX)) { + IFNET_WUNLOCK(); + epoch_wait_preempt(net_epoch_preempt); + free(old, M_IFNET); + goto restart; + } + ifnet_setbyindex(ifp->if_index, ifp); IFNET_WUNLOCK(); if_attach_internal(ifp, 1, ifc); @@ -1352,7 +1427,7 @@ if_addgroup(struct ifnet *ifp, const char *groupname) return (EINVAL); IFNET_WLOCK(); - TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) + CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) if (!strcmp(ifgl->ifgl_group->ifg_group, groupname)) { IFNET_WUNLOCK(); return (EEXIST); @@ -1371,7 +1446,7 @@ if_addgroup(struct ifnet *ifp, const char *groupname) return (ENOMEM); } - TAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) + CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) if (!strcmp(ifg->ifg_group, groupname)) break; @@ -1385,8 +1460,8 @@ if_addgroup(struct ifnet *ifp, const char *groupname) } strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group)); ifg->ifg_refcnt = 0; - TAILQ_INIT(&ifg->ifg_members); - TAILQ_INSERT_TAIL(&V_ifg_head, ifg, ifg_next); + CK_STAILQ_INIT(&ifg->ifg_members); + CK_STAILQ_INSERT_TAIL(&V_ifg_head, ifg, ifg_next); new = 1; } @@ -1395,8 +1470,8 @@ if_addgroup(struct ifnet *ifp, const char *groupname) ifgm->ifgm_ifp = ifp; IF_ADDR_WLOCK(ifp); - TAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next); - TAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next); + CK_STAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next); + CK_STAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next); IF_ADDR_WUNLOCK(ifp); IFNET_WUNLOCK(); @@ -1416,9 +1491,10 @@ if_delgroup(struct ifnet *ifp, const char *groupname) { struct ifg_list *ifgl; struct ifg_member *ifgm; + int freeifgl; IFNET_WLOCK(); - TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) + CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) if (!strcmp(ifgl->ifgl_group->ifg_group, groupname)) break; if (ifgl == NULL) { @@ -1426,27 +1502,30 @@ if_delgroup(struct ifnet *ifp, const char *groupname) return (ENOENT); } + freeifgl = 0; IF_ADDR_WLOCK(ifp); - TAILQ_REMOVE(&ifp->if_groups, ifgl, ifgl_next); + CK_STAILQ_REMOVE(&ifp->if_groups, ifgl, ifg_list, ifgl_next); IF_ADDR_WUNLOCK(ifp); - TAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) + CK_STAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) if (ifgm->ifgm_ifp == ifp) break; - if (ifgm != NULL) { - TAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifgm_next); - free(ifgm, M_TEMP); - } + if (ifgm != NULL) + CK_STAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifg_member, ifgm_next); if (--ifgl->ifgl_group->ifg_refcnt == 0) { - TAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_next); - IFNET_WUNLOCK(); + CK_STAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_group, ifg_next); + freeifgl = 1; + } + IFNET_WUNLOCK(); + + epoch_wait_preempt(net_epoch_preempt); + if (freeifgl) { EVENTHANDLER_INVOKE(group_detach_event, ifgl->ifgl_group); free(ifgl->ifgl_group, M_TEMP); - } else - IFNET_WUNLOCK(); - + } + free(ifgm, M_TEMP); free(ifgl, M_TEMP); EVENTHANDLER_INVOKE(group_change_event, groupname); @@ -1463,38 +1542,39 @@ if_delgroups(struct ifnet *ifp) struct ifg_list *ifgl; struct ifg_member *ifgm; char groupname[IFNAMSIZ]; + int ifglfree; IFNET_WLOCK(); - while (!TAILQ_EMPTY(&ifp->if_groups)) { - ifgl = TAILQ_FIRST(&ifp->if_groups); + while (!CK_STAILQ_EMPTY(&ifp->if_groups)) { + ifgl = CK_STAILQ_FIRST(&ifp->if_groups); strlcpy(groupname, ifgl->ifgl_group->ifg_group, IFNAMSIZ); IF_ADDR_WLOCK(ifp); - TAILQ_REMOVE(&ifp->if_groups, ifgl, ifgl_next); + CK_STAILQ_REMOVE(&ifp->if_groups, ifgl, ifg_list, ifgl_next); IF_ADDR_WUNLOCK(ifp); - TAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) + CK_STAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) if (ifgm->ifgm_ifp == ifp) break; - if (ifgm != NULL) { - TAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, + if (ifgm != NULL) + CK_STAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifg_member, ifgm_next); - free(ifgm, M_TEMP); + ifglfree = 0; + if (--ifgl->ifgl_group->ifg_refcnt == 0) { + CK_STAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_group, ifg_next); + ifglfree = 1; } - if (--ifgl->ifgl_group->ifg_refcnt == 0) { - TAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_next); - IFNET_WUNLOCK(); + IFNET_WUNLOCK(); + epoch_wait_preempt(net_epoch_preempt); + free(ifgm, M_TEMP); + if (ifglfree) { EVENTHANDLER_INVOKE(group_detach_event, - ifgl->ifgl_group); + ifgl->ifgl_group); free(ifgl->ifgl_group, M_TEMP); - } else - IFNET_WUNLOCK(); - - free(ifgl, M_TEMP); - + } EVENTHANDLER_INVOKE(group_change_event, groupname); IFNET_WLOCK(); @@ -1502,31 +1582,56 @@ if_delgroups(struct ifnet *ifp) IFNET_WUNLOCK(); } +static char * +ifgr_group_get(void *ifgrp) +{ + union ifgroupreq_union *ifgrup; + + ifgrup = ifgrp; +#ifdef COMPAT_FREEBSD32 + if (SV_CURPROC_FLAG(SV_ILP32)) + return (&ifgrup->ifgr32.ifgr_ifgru.ifgru_group[0]); +#endif + return (&ifgrup->ifgr.ifgr_ifgru.ifgru_group[0]); +} + +static struct ifg_req * +ifgr_groups_get(void *ifgrp) +{ + union ifgroupreq_union *ifgrup; + + ifgrup = ifgrp; +#ifdef COMPAT_FREEBSD32 + if (SV_CURPROC_FLAG(SV_ILP32)) + return ((struct ifg_req *)(uintptr_t) + ifgrup->ifgr32.ifgr_ifgru.ifgru_groups); +#endif + return (ifgrup->ifgr.ifgr_ifgru.ifgru_groups); +} + /* - * Stores all groups from an interface in memory pointed - * to by data + * Stores all groups from an interface in memory pointed to by ifgr. */ static int -if_getgroup(struct ifgroupreq *data, struct ifnet *ifp) +if_getgroup(struct ifgroupreq *ifgr, struct ifnet *ifp) { int len, error; struct ifg_list *ifgl; struct ifg_req ifgrq, *ifgp; - struct ifgroupreq *ifgr = data; if (ifgr->ifgr_len == 0) { IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) + CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) ifgr->ifgr_len += sizeof(struct ifg_req); IF_ADDR_RUNLOCK(ifp); return (0); } len = ifgr->ifgr_len; - ifgp = ifgr->ifgr_groups; + ifgp = ifgr_groups_get(ifgr); /* XXX: wire */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) { + CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) { if (len < sizeof(ifgrq)) { IF_ADDR_RUNLOCK(ifp); return (EINVAL); @@ -1547,19 +1652,18 @@ if_getgroup(struct ifgroupreq *data, struct ifnet *ifp) } /* - * Stores all members of a group in memory pointed to by data + * Stores all members of a group in memory pointed to by igfr */ static int -if_getgroupmembers(struct ifgroupreq *data) +if_getgroupmembers(struct ifgroupreq *ifgr) { - struct ifgroupreq *ifgr = data; struct ifg_group *ifg; struct ifg_member *ifgm; struct ifg_req ifgrq, *ifgp; int len, error; IFNET_RLOCK(); - TAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) + CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) if (!strcmp(ifg->ifg_group, ifgr->ifgr_name)) break; if (ifg == NULL) { @@ -1568,15 +1672,15 @@ if_getgroupmembers(struct ifgroupreq *data) } if (ifgr->ifgr_len == 0) { - TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) + CK_STAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) ifgr->ifgr_len += sizeof(ifgrq); IFNET_RUNLOCK(); return (0); } len = ifgr->ifgr_len; - ifgp = ifgr->ifgr_groups; - TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) { + ifgp = ifgr_groups_get(ifgr); + CK_STAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) { if (len < sizeof(ifgrq)) { IFNET_RUNLOCK(); return (EINVAL); @@ -1736,19 +1840,28 @@ ifa_ref(struct ifaddr *ifa) refcount_acquire(&ifa->ifa_refcnt); } +static void +ifa_destroy(epoch_context_t ctx) +{ + struct ifaddr *ifa; + + ifa = __containerof(ctx, struct ifaddr, ifa_epoch_ctx); + counter_u64_free(ifa->ifa_opackets); + counter_u64_free(ifa->ifa_ipackets); + counter_u64_free(ifa->ifa_obytes); + counter_u64_free(ifa->ifa_ibytes); + free(ifa, M_IFADDR); +} + void ifa_free(struct ifaddr *ifa) { - if (refcount_release(&ifa->ifa_refcnt)) { - counter_u64_free(ifa->ifa_opackets); - counter_u64_free(ifa->ifa_ipackets); - counter_u64_free(ifa->ifa_obytes); - counter_u64_free(ifa->ifa_ibytes); - free(ifa, M_IFADDR); - } + if (refcount_release(&ifa->ifa_refcnt)) + epoch_call(net_epoch_preempt, &ifa->ifa_epoch_ctx, ifa_destroy); } + static int ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa, struct sockaddr *ia) @@ -1770,9 +1883,10 @@ ifa_maintain_loopback_route(int cmd, const char *otype, struct ifaddr *ifa, error = rtrequest1_fib(cmd, &info, NULL, ifp->if_fib); - if (error != 0) - log(LOG_DEBUG, "%s: %s failed for interface %s: %u\n", - __func__, otype, if_name(ifp), error); + if (error != 0 && + !(cmd == RTM_ADD && error == EEXIST) && + !(cmd == RTM_DELETE && error == ENOENT)) + if_printf(ifp, "%s failed: %d\n", otype, error); return (error); } @@ -1815,22 +1929,18 @@ ifa_switch_loopback_route(struct ifaddr *ifa, struct sockaddr *ia) * Locate an interface based on a complete address. */ /*ARGSUSED*/ -static struct ifaddr * -ifa_ifwithaddr_internal(const struct sockaddr *addr, int getref) +struct ifaddr * +ifa_ifwithaddr(const struct sockaddr *addr) { struct ifnet *ifp; struct ifaddr *ifa; - IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + MPASS(in_epoch()); + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; if (sa_equal(addr, ifa->ifa_addr)) { - if (getref) - ifa_ref(ifa); - IF_ADDR_RUNLOCK(ifp); goto done; } /* IP6 doesn't have broadcast */ @@ -1838,32 +1948,24 @@ ifa_ifwithaddr_internal(const struct sockaddr *addr, int getref) ifa->ifa_broadaddr && ifa->ifa_broadaddr->sa_len != 0 && sa_equal(ifa->ifa_broadaddr, addr)) { - if (getref) - ifa_ref(ifa); - IF_ADDR_RUNLOCK(ifp); goto done; } } - IF_ADDR_RUNLOCK(ifp); } ifa = NULL; done: - IFNET_RUNLOCK_NOSLEEP(); return (ifa); } -struct ifaddr * -ifa_ifwithaddr(const struct sockaddr *addr) -{ - - return (ifa_ifwithaddr_internal(addr, 1)); -} - int ifa_ifwithaddr_check(const struct sockaddr *addr) { + int rc; - return (ifa_ifwithaddr_internal(addr, 0) != NULL); + NET_EPOCH_ENTER(); + rc = (ifa_ifwithaddr(addr) != NULL); + NET_EPOCH_EXIT(); + return (rc); } /* @@ -1876,28 +1978,23 @@ ifa_ifwithbroadaddr(const struct sockaddr *addr, int fibnum) struct ifnet *ifp; struct ifaddr *ifa; - IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + MPASS(in_epoch()); + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum)) continue; - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && ifa->ifa_broadaddr->sa_len != 0 && sa_equal(ifa->ifa_broadaddr, addr)) { - ifa_ref(ifa); - IF_ADDR_RUNLOCK(ifp); goto done; } } - IF_ADDR_RUNLOCK(ifp); } ifa = NULL; done: - IFNET_RUNLOCK_NOSLEEP(); return (ifa); } @@ -1911,28 +2008,23 @@ ifa_ifwithdstaddr(const struct sockaddr *addr, int fibnum) struct ifnet *ifp; struct ifaddr *ifa; - IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + MPASS(in_epoch()); + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if ((ifp->if_flags & IFF_POINTOPOINT) == 0) continue; if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum)) continue; - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != addr->sa_family) continue; if (ifa->ifa_dstaddr != NULL && sa_equal(addr, ifa->ifa_dstaddr)) { - ifa_ref(ifa); - IF_ADDR_RUNLOCK(ifp); goto done; } } - IF_ADDR_RUNLOCK(ifp); } ifa = NULL; done: - IFNET_RUNLOCK_NOSLEEP(); return (ifa); } @@ -1949,6 +2041,7 @@ ifa_ifwithnet(const struct sockaddr *addr, int ignore_ptp, int fibnum) u_int af = addr->sa_family; const char *addr_data = addr->sa_data, *cplim; + MPASS(in_epoch()); /* * AF_LINK addresses can be looked up directly by their index number, * so do that if we can. @@ -1965,12 +2058,10 @@ ifa_ifwithnet(const struct sockaddr *addr, int ignore_ptp, int fibnum) * on ifa_maybe once we find one, as we release the IF_ADDR_RLOCK() that * kept it stable when we move onto the next interface. */ - IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum)) continue; - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { const char *cp, *cp2, *cp3; if (ifa->ifa_addr->sa_family != af) @@ -1987,7 +2078,6 @@ next: continue; */ if (ifa->ifa_dstaddr != NULL && sa_equal(addr, ifa->ifa_dstaddr)) { - ifa_ref(ifa); IF_ADDR_RUNLOCK(ifp); goto done; } @@ -2021,21 +2111,14 @@ next: continue; ifa_preferred(ifa_maybe, ifa) || rn_refines((caddr_t)ifa->ifa_netmask, (caddr_t)ifa_maybe->ifa_netmask)) { - if (ifa_maybe != NULL) - ifa_free(ifa_maybe); ifa_maybe = ifa; - ifa_ref(ifa_maybe); } } } - IF_ADDR_RUNLOCK(ifp); } ifa = ifa_maybe; ifa_maybe = NULL; done: - IFNET_RUNLOCK_NOSLEEP(); - if (ifa_maybe != NULL) - ifa_free(ifa_maybe); return (ifa); } @@ -2054,8 +2137,8 @@ ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp) if (af >= AF_MAX) return (NULL); - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + MPASS(in_epoch()); + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != af) continue; if (ifa_maybe == NULL) @@ -2084,9 +2167,6 @@ ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp) } ifa = ifa_maybe; done: - if (ifa != NULL) - ifa_ref(ifa); - IF_ADDR_RUNLOCK(ifp); return (ifa); } @@ -2122,14 +2202,19 @@ link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == NULL) || ((ifp = ifa->ifa_ifp) == NULL) || ((dst = rt_key(rt)) == NULL)) return; + NET_EPOCH_ENTER(); ifa = ifaof_ifpforaddr(dst, ifp); if (ifa) { oifa = rt->rt_ifa; + if (oifa != ifa) { + ifa_free(oifa); + ifa_ref(ifa); + } rt->rt_ifa = ifa; - ifa_free(oifa); if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) ifa->ifa_rtrequest(cmd, rt, info); } + NET_EPOCH_EXIT(); } struct sockaddr_dl * @@ -2177,7 +2262,7 @@ if_unroute(struct ifnet *ifp, int flag, int fam) ifp->if_flags &= ~flag; getmicrotime(&ifp->if_lastchange); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) pfctlinput(PRC_IFDOWN, ifa->ifa_addr); ifp->if_qflush(ifp); @@ -2200,7 +2285,7 @@ if_route(struct ifnet *ifp, int flag, int fam) ifp->if_flags |= flag; getmicrotime(&ifp->if_lastchange); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) pfctlinput(PRC_IFUP, ifa->ifa_addr); if (ifp->if_carp) @@ -2255,7 +2340,7 @@ do_link_state_change(void *arg, int pending) if (ifp->if_carp) (*carp_linkstate_p)(ifp); if (ifp->if_bridge) - (*bridge_linkstate_p)(ifp); + ifp->if_bridge_linkstate(ifp); if (ifp->if_lagg) (*lagg_linkstate_p)(ifp, link_state); @@ -2266,7 +2351,7 @@ do_link_state_change(void *arg, int pending) if (pending > 1) if_printf(ifp, "%d link states coalesced\n", pending); if (log_link_state_change) - log(LOG_NOTICE, "%s: link state changed to %s\n", ifp->if_xname, + if_printf(ifp, "link state changed to %s\n", (link_state == LINK_STATE_UP) ? "UP" : "DOWN" ); EVENTHANDLER_INVOKE(ifnet_link_event, ifp, link_state); CURVNET_RESTORE(); @@ -2332,7 +2417,7 @@ ifunit_ref(const char *name) struct ifnet *ifp; IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0 && !(ifp->if_flags & IFF_DYING)) break; @@ -2349,7 +2434,7 @@ ifunit(const char *name) struct ifnet *ifp; IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0) break; } @@ -2358,13 +2443,13 @@ ifunit(const char *name) } static void * -ifr_buffer_get_buffer(struct thread *td, void *data) +ifr_buffer_get_buffer(void *data) { union ifreq_union *ifrup; ifrup = data; #ifdef COMPAT_FREEBSD32 - if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) + if (SV_CURPROC_FLAG(SV_ILP32)) return ((void *)(uintptr_t) ifrup->ifr32.ifr_ifru.ifru_buffer.buffer); #endif @@ -2372,13 +2457,13 @@ ifr_buffer_get_buffer(struct thread *td, void *data) } static void -ifr_buffer_set_buffer_null(struct thread *td, void *data) +ifr_buffer_set_buffer_null(void *data) { union ifreq_union *ifrup; ifrup = data; #ifdef COMPAT_FREEBSD32 - if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) + if (SV_CURPROC_FLAG(SV_ILP32)) ifrup->ifr32.ifr_ifru.ifru_buffer.buffer = 0; else #endif @@ -2386,26 +2471,26 @@ ifr_buffer_set_buffer_null(struct thread *td, void *data) } static size_t -ifr_buffer_get_length(struct thread *td, void *data) +ifr_buffer_get_length(void *data) { union ifreq_union *ifrup; ifrup = data; #ifdef COMPAT_FREEBSD32 - if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) + if (SV_CURPROC_FLAG(SV_ILP32)) return (ifrup->ifr32.ifr_ifru.ifru_buffer.length); #endif return (ifrup->ifr.ifr_ifru.ifru_buffer.length); } static void -ifr_buffer_set_length(struct thread *td, void *data, size_t len) +ifr_buffer_set_length(void *data, size_t len) { union ifreq_union *ifrup; ifrup = data; #ifdef COMPAT_FREEBSD32 - if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) + if (SV_CURPROC_FLAG(SV_ILP32)) ifrup->ifr32.ifr_ifru.ifru_buffer.length = len; else #endif @@ -2486,12 +2571,12 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) else { /* space for terminating nul */ descrlen = strlen(ifp->if_description) + 1; - if (ifr_buffer_get_length(td, ifr) < descrlen) - ifr_buffer_set_buffer_null(td, ifr); + if (ifr_buffer_get_length(ifr) < descrlen) + ifr_buffer_set_buffer_null(ifr); else error = copyout(ifp->if_description, - ifr_buffer_get_buffer(td, ifr), descrlen); - ifr_buffer_set_length(td, ifr, descrlen); + ifr_buffer_get_buffer(ifr), descrlen); + ifr_buffer_set_length(ifr, descrlen); } sx_sunlock(&ifdescr_sx); break; @@ -2507,15 +2592,15 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) * length parameter is supposed to count the * terminating nul in. */ - if (ifr_buffer_get_length(td, ifr) > ifdescr_maxlen) + if (ifr_buffer_get_length(ifr) > ifdescr_maxlen) return (ENAMETOOLONG); - else if (ifr_buffer_get_length(td, ifr) == 0) + else if (ifr_buffer_get_length(ifr) == 0) descrbuf = NULL; else { - descrbuf = malloc(ifr_buffer_get_length(td, ifr), + descrbuf = malloc(ifr_buffer_get_length(ifr), M_IFDESCR, M_WAITOK | M_ZERO); - error = copyin(ifr_buffer_get_buffer(td, ifr), descrbuf, - ifr_buffer_get_length(td, ifr) - 1); + error = copyin(ifr_buffer_get_buffer(ifr), descrbuf, + ifr_buffer_get_length(ifr) - 1); if (error) { free(descrbuf, M_IFDESCR); break; @@ -2569,8 +2654,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) else if (ifp->if_pcount == 0) ifp->if_flags &= ~IFF_PROMISC; if (log_promisc_mode_change) - log(LOG_INFO, "%s: permanently promiscuous mode %s\n", - ifp->if_xname, + if_printf(ifp, "permanently promiscuous mode %s\n", ((new_flags & IFF_PPROMISC) ? "enabled" : "disabled")); } @@ -2633,8 +2717,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) rt_ifannouncemsg(ifp, IFAN_DEPARTURE); EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); - log(LOG_INFO, "%s: changing name to '%s'\n", - ifp->if_xname, new_name); + if_printf(ifp, "changing name to '%s'\n", new_name); IF_ADDR_WLOCK(ifp); strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname)); @@ -2709,6 +2792,9 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) if (error == 0) { getmicrotime(&ifp->if_lastchange); rt_ifmsg(ifp); +#ifdef INET + NETDUMP_REINIT(ifp); +#endif } /* * If the link MTU changed, do network layer specific procedure. @@ -2805,34 +2891,28 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) error = if_gethwaddr(ifp, ifr); break; - case SIOCAIFGROUP: - { - struct ifgroupreq *ifgr = (struct ifgroupreq *)ifr; - + CASE_IOC_IFGROUPREQ(SIOCAIFGROUP): error = priv_check(td, PRIV_NET_ADDIFGROUP); if (error) return (error); - if ((error = if_addgroup(ifp, ifgr->ifgr_group))) + if ((error = if_addgroup(ifp, + ifgr_group_get((struct ifgroupreq *)data)))) return (error); break; - } - case SIOCGIFGROUP: - if ((error = if_getgroup((struct ifgroupreq *)ifr, ifp))) + CASE_IOC_IFGROUPREQ(SIOCGIFGROUP): + if ((error = if_getgroup((struct ifgroupreq *)data, ifp))) return (error); break; - case SIOCDIFGROUP: - { - struct ifgroupreq *ifgr = (struct ifgroupreq *)ifr; - + CASE_IOC_IFGROUPREQ(SIOCDIFGROUP): error = priv_check(td, PRIV_NET_DELIFGROUP); if (error) return (error); - if ((error = if_delgroup(ifp, ifgr->ifgr_group))) + if ((error = if_delgroup(ifp, + ifgr_group_get((struct ifgroupreq *)data)))) return (error); break; - } #ifdef __rtems__ case RTEMS_SIOSIFINPUT: @@ -2868,12 +2948,48 @@ struct ifconf32 { #define SIOCGIFCONF32 _IOWR('i', 36, struct ifconf32) #endif +#ifdef COMPAT_FREEBSD32 +static void +ifmr_init(struct ifmediareq *ifmr, caddr_t data) +{ + struct ifmediareq32 *ifmr32; + + ifmr32 = (struct ifmediareq32 *)data; + memcpy(ifmr->ifm_name, ifmr32->ifm_name, + sizeof(ifmr->ifm_name)); + ifmr->ifm_current = ifmr32->ifm_current; + ifmr->ifm_mask = ifmr32->ifm_mask; + ifmr->ifm_status = ifmr32->ifm_status; + ifmr->ifm_active = ifmr32->ifm_active; + ifmr->ifm_count = ifmr32->ifm_count; + ifmr->ifm_ulist = (int *)(uintptr_t)ifmr32->ifm_ulist; +} + +static void +ifmr_update(const struct ifmediareq *ifmr, caddr_t data) +{ + struct ifmediareq32 *ifmr32; + + ifmr32 = (struct ifmediareq32 *)data; + ifmr32->ifm_current = ifmr->ifm_current; + ifmr32->ifm_mask = ifmr->ifm_mask; + ifmr32->ifm_status = ifmr->ifm_status; + ifmr32->ifm_active = ifmr->ifm_active; + ifmr32->ifm_count = ifmr->ifm_count; +} +#endif + /* * Interface ioctls. */ int ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) { +#ifdef COMPAT_FREEBSD32 + caddr_t saved_data = NULL; + struct ifmediareq ifmr; +#endif + struct ifmediareq *ifmrp; struct ifnet *ifp; struct ifreq *ifr; int error; @@ -2918,8 +3034,21 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) } #endif } - ifr = (struct ifreq *)data; + ifmrp = NULL; +#ifdef COMPAT_FREEBSD32 + switch (cmd) { + case SIOCGIFMEDIA32: + case SIOCGIFXMEDIA32: + ifmrp = &ifmr; + ifmr_init(ifmrp, data); + cmd = _IOC_NEWTYPE(cmd, struct ifmediareq); + saved_data = data; + data = (caddr_t)ifmrp; + } +#endif + + ifr = (struct ifreq *)data; switch (cmd) { #ifdef VIMAGE case SIOCSIFRVNET: @@ -2927,8 +3056,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) if (error == 0) error = if_vmove_reclaim(td, ifr->ifr_name, ifr->ifr_jid); - CURVNET_RESTORE(); - return (error); + goto out_noref; #endif case SIOCIFCREATE: case SIOCIFCREATE2: @@ -2937,23 +3065,21 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) error = if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name), cmd == SIOCIFCREATE2 ? ifr_data_get_ptr(ifr) : NULL); - CURVNET_RESTORE(); - return (error); + goto out_noref; case SIOCIFDESTROY: error = priv_check(td, PRIV_NET_IFDESTROY); if (error == 0) error = if_clone_destroy(ifr->ifr_name); - CURVNET_RESTORE(); - return (error); + goto out_noref; case SIOCIFGCLONERS: error = if_clone_list((struct if_clonereq *)data); - CURVNET_RESTORE(); - return (error); - case SIOCGIFGMEMB: + goto out_noref; + + CASE_IOC_IFGROUPREQ(SIOCGIFGMEMB): error = if_getgroupmembers((struct ifgroupreq *)data); - CURVNET_RESTORE(); - return (error); + goto out_noref; + #if defined(INET) || defined(INET6) case SIOCSVH: case SIOCGVH: @@ -2961,29 +3087,24 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) error = EPROTONOSUPPORT; else error = (*carp_ioctl_p)(ifr, cmd, td); - CURVNET_RESTORE(); - return (error); + goto out_noref; #endif } ifp = ifunit_ref(ifr->ifr_name); if (ifp == NULL) { - CURVNET_RESTORE(); - return (ENXIO); + error = ENXIO; + goto out_noref; } error = ifhwioctl(cmd, ifp, data, td); - if (error != ENOIOCTL) { - if_rele(ifp); - CURVNET_RESTORE(); - return (error); - } + if (error != ENOIOCTL) + goto out_ref; oif_flags = ifp->if_flags; if (so->so_proto == NULL) { - if_rele(ifp); - CURVNET_RESTORE(); - return (EOPNOTSUPP); + error = EOPNOTSUPP; + goto out_ref; } /* @@ -3008,7 +3129,19 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) in6_if_up(ifp); #endif } + +out_ref: if_rele(ifp); +out_noref: +#ifdef COMPAT_FREEBSD32 + if (ifmrp != NULL) { + KASSERT((cmd == SIOCGIFMEDIA || cmd == SIOCGIFXMEDIA), + ("ifmrp non-NULL, but cmd is not an ifmedia req 0x%lx", + cmd)); + data = saved_data; + ifmr_update(ifmrp, data); + } +#endif CURVNET_RESTORE(); return (error); } @@ -3103,8 +3236,7 @@ ifpromisc(struct ifnet *ifp, int pswitch) /* If promiscuous mode status has changed, log a message */ if (error == 0 && ((ifp->if_flags ^ oldflags) & IFF_PROMISC) && log_promisc_mode_change) - log(LOG_INFO, "%s: promiscuous mode %s\n", - ifp->if_xname, + if_printf(ifp, "promiscuous mode %s\n", (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled"); return (error); } @@ -3143,14 +3275,14 @@ again: valid_len = 0; IFNET_RLOCK(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { int addrs; /* - * Zero the ifr_name buffer to make sure we don't - * disclose the contents of the stack. + * Zero the ifr to make sure we don't disclose the contents + * of the stack. */ - memset(ifr.ifr_name, 0, sizeof(ifr.ifr_name)); + memset(&ifr, 0, sizeof(ifr)); if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)) >= sizeof(ifr.ifr_name)) { @@ -3161,14 +3293,20 @@ again: addrs = 0; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { struct sockaddr *sa = ifa->ifa_addr; if (prison_if(curthread->td_ucred, sa) != 0) continue; addrs++; if (sa->sa_len <= sizeof(*sa)) { - ifr.ifr_addr = *sa; + if (sa->sa_len < sizeof(*sa)) { + memset(&ifr.ifr_ifru.ifru_addr, 0, + sizeof(ifr.ifr_ifru.ifru_addr)); + memcpy(&ifr.ifr_ifru.ifru_addr, sa, + sa->sa_len); + } else + ifr.ifr_ifru.ifru_addr = *sa; sbuf_bcat(sb, &ifr, sizeof(ifr)); max_len += sizeof(ifr); } else { @@ -3184,7 +3322,6 @@ again: } IF_ADDR_RUNLOCK(ifp); if (addrs == 0) { - bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); sbuf_bcat(sb, &ifr, sizeof(ifr)); max_len += sizeof(ifr); @@ -3228,7 +3365,7 @@ if_findmulti(struct ifnet *ifp, const struct sockaddr *sa) IF_ADDR_LOCK_ASSERT(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (sa->sa_family == AF_LINK) { if (sa_dl_equal(ifma->ifma_addr, sa)) break; @@ -3295,8 +3432,11 @@ if_allocmulti(struct ifnet *ifp, struct sockaddr *sa, struct sockaddr *llsa, * counting, notifying the driver, handling routing messages, and releasing * any dependent link layer state. */ +#ifdef MCAST_VERBOSE +extern void kdb_backtrace(void); +#endif static void -if_freemulti(struct ifmultiaddr *ifma) +if_freemulti_internal(struct ifmultiaddr *ifma) { KASSERT(ifma->ifma_refcount == 0, ("if_freemulti: refcount %d", @@ -3304,10 +3444,33 @@ if_freemulti(struct ifmultiaddr *ifma) if (ifma->ifma_lladdr != NULL) free(ifma->ifma_lladdr, M_IFMADDR); +#ifdef MCAST_VERBOSE + kdb_backtrace(); + printf("%s freeing ifma: %p\n", __func__, ifma); +#endif free(ifma->ifma_addr, M_IFMADDR); free(ifma, M_IFMADDR); } +static void +if_destroymulti(epoch_context_t ctx) +{ + struct ifmultiaddr *ifma; + + ifma = __containerof(ctx, struct ifmultiaddr, ifma_epoch_ctx); + if_freemulti_internal(ifma); +} + +void +if_freemulti(struct ifmultiaddr *ifma) +{ + KASSERT(ifma->ifma_refcount == 0, ("if_freemulti_epoch: refcount %d", + ifma->ifma_refcount)); + + epoch_call(net_epoch_preempt, &ifma->ifma_epoch_ctx, if_destroymulti); +} + + /* * Register an additional multicast address with a network interface. * @@ -3335,6 +3498,12 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa, struct sockaddr_dl sdl; int error; +#ifdef INET + IN_MULTI_LIST_UNLOCK_ASSERT(); +#endif +#ifdef INET6 + IN6_MULTI_LIST_UNLOCK_ASSERT(); +#endif /* * If the address is already present, return a new reference to it; * otherwise, allocate storage and set up a new address. @@ -3395,7 +3564,7 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa, error = ENOMEM; goto free_llsa_out; } - TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma, + CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma, ifma_link); } else ll_ifma->ifma_refcount++; @@ -3407,7 +3576,7 @@ if_addmulti(struct ifnet *ifp, struct sockaddr *sa, * referenced link layer address. Add the primary address to the * ifnet address list. */ - TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); + CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); if (retifma != NULL) *retifma = ifma; @@ -3459,7 +3628,7 @@ if_delmulti(struct ifnet *ifp, struct sockaddr *sa) struct ifnet *oifp; IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(oifp, &V_ifnet, if_link) + CK_STAILQ_FOREACH(oifp, &V_ifnet, if_link) if (ifp == oifp) break; if (ifp != oifp) @@ -3499,11 +3668,17 @@ if_delallmulti(struct ifnet *ifp) struct ifmultiaddr *next; IF_ADDR_WLOCK(ifp); - TAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) + CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) if_delmulti_locked(ifp, ifma, 0); IF_ADDR_WUNLOCK(ifp); } +void +if_delmulti_ifma(struct ifmultiaddr *ifma) +{ + if_delmulti_ifma_flags(ifma, 0); +} + /* * Delete a multicast group membership by group membership pointer. * Network-layer protocol domains must use this routine. @@ -3511,11 +3686,14 @@ if_delallmulti(struct ifnet *ifp) * It is safe to call this routine if the ifp disappeared. */ void -if_delmulti_ifma(struct ifmultiaddr *ifma) +if_delmulti_ifma_flags(struct ifmultiaddr *ifma, int flags) { struct ifnet *ifp; int lastref; - + MCDPRINTF("%s freeing ifma: %p\n", __func__, ifma); +#ifdef INET + IN_MULTI_LIST_UNLOCK_ASSERT(); +#endif ifp = ifma->ifma_ifp; #ifdef DIAGNOSTIC if (ifp == NULL) { @@ -3524,13 +3702,11 @@ if_delmulti_ifma(struct ifmultiaddr *ifma) struct ifnet *oifp; IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(oifp, &V_ifnet, if_link) + CK_STAILQ_FOREACH(oifp, &V_ifnet, if_link) if (ifp == oifp) break; - if (ifp != oifp) { - printf("%s: ifnet %p disappeared\n", __func__, ifp); + if (ifp != oifp) ifp = NULL; - } IFNET_RUNLOCK_NOSLEEP(); } #endif @@ -3540,7 +3716,7 @@ if_delmulti_ifma(struct ifmultiaddr *ifma) if (ifp != NULL) IF_ADDR_WLOCK(ifp); - lastref = if_delmulti_locked(ifp, ifma, 0); + lastref = if_delmulti_locked(ifp, ifma, flags); if (ifp != NULL) { /* @@ -3574,6 +3750,7 @@ if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching) } ifp = ifma->ifma_ifp; + MCDPRINTF("%s freeing %p from %s \n", __func__, ifma, ifp ? ifp->if_xname : ""); /* * If the ifnet is detaching, null out references to ifnet, @@ -3599,6 +3776,9 @@ if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching) if (--ifma->ifma_refcount > 0) return 0; + if (ifp != NULL && detaching == 0) + CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); + /* * If this ifma is a network-layer ifma, a link-layer ifma may * have been associated with it. Release it first if so. @@ -3611,18 +3791,21 @@ if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching) ll_ifma->ifma_ifp = NULL; /* XXX */ if (--ll_ifma->ifma_refcount == 0) { if (ifp != NULL) { - TAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, + CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link); } if_freemulti(ll_ifma); } } +#ifdef INVARIANTS + if (ifp) { + struct ifmultiaddr *ifmatmp; - if (ifp != NULL) - TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); - + CK_STAILQ_FOREACH(ifmatmp, &ifp->if_multiaddrs, ifma_link) + MPASS(ifma != ifmatmp); + } +#endif if_freemulti(ifma); - /* * The last reference to this instance of struct ifmultiaddr * was released; the hardware should be notified of this change. @@ -3644,38 +3827,36 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) struct sockaddr_dl *sdl; struct ifaddr *ifa; struct ifreq ifr; + int rc; - IF_ADDR_RLOCK(ifp); + rc = 0; + NET_EPOCH_ENTER(); ifa = ifp->if_addr; if (ifa == NULL) { - IF_ADDR_RUNLOCK(ifp); - return (EINVAL); + rc = EINVAL; + goto out; } - ifa_ref(ifa); - IF_ADDR_RUNLOCK(ifp); + sdl = (struct sockaddr_dl *)ifa->ifa_addr; if (sdl == NULL) { - ifa_free(ifa); - return (EINVAL); + rc = EINVAL; + goto out; } if (len != sdl->sdl_alen) { /* don't allow length to change */ - ifa_free(ifa); - return (EINVAL); + rc = EINVAL; + goto out; } switch (ifp->if_type) { case IFT_ETHER: - case IFT_FDDI: case IFT_XETHER: case IFT_L2VLAN: case IFT_BRIDGE: - case IFT_ARCNET: case IFT_IEEE8023ADLAG: bcopy(lladdr, LLADDR(sdl), len); - ifa_free(ifa); break; default: - ifa_free(ifa); - return (ENODEV); + rc = ENODEV; + goto out; } /* @@ -3683,6 +3864,7 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) * to re-init it in order to reprogram its * address filter. */ + NET_EPOCH_EXIT(); if ((ifp->if_flags & IFF_UP) != 0) { if (ifp->if_ioctl) { ifp->if_flags &= ~IFF_UP; @@ -3697,6 +3879,9 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) } EVENTHANDLER_INVOKE(iflladdr_event, ifp); return (0); + out: + NET_EPOCH_EXIT(); + return (rc); } /* @@ -3777,16 +3962,16 @@ if_initname(struct ifnet *ifp, const char *name, int unit) } int -if_printf(struct ifnet *ifp, const char * fmt, ...) +if_printf(struct ifnet *ifp, const char *fmt, ...) { + char if_fmt[256]; va_list ap; - int retval; - retval = printf("%s: ", ifp->if_xname); + snprintf(if_fmt, sizeof(if_fmt), "%s: %s", ifp->if_xname, fmt); va_start(ap, fmt); - retval += vprintf(fmt, ap); + vlog(LOG_INFO, if_fmt, ap); va_end(ap); - return (retval); + return (0); } void @@ -4149,7 +4334,7 @@ if_setupmultiaddr(if_t ifp, void *mta, int *cnt, int max) uint8_t *lmta = (uint8_t *)mta; int mcnt = 0; - TAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; @@ -4184,7 +4369,7 @@ if_multiaddr_count(if_t ifp, int max) count = 0; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; count++; @@ -4202,7 +4387,7 @@ if_multi_apply(struct ifnet *ifp, int (*filter)(void *, struct ifmultiaddr *, in int cnt = 0; if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) cnt += filter(arg, ifma, cnt); if_maddr_runlock(ifp); return (cnt); diff --git a/freebsd/sys/net/if_arc.h b/freebsd/sys/net/if_arc.h deleted file mode 100644 index 8bed38b8..00000000 --- a/freebsd/sys/net/if_arc.h +++ /dev/null @@ -1,145 +0,0 @@ -/* $NetBSD: if_arc.h,v 1.13 1999/11/19 20:41:19 thorpej Exp $ */ -/* $FreeBSD$ */ - -/*- - * SPDX-License-Identifier: BSD-3-Clause - * - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: NetBSD: if_ether.h,v 1.10 1994/06/29 06:37:55 cgd Exp - * @(#)if_ether.h 8.1 (Berkeley) 6/10/93 - */ - -#ifndef _NET_IF_ARC_H_ -#define _NET_IF_ARC_H_ - -/* - * Arcnet address - 1 octets - * don't know who uses this. - */ -struct arc_addr { - u_int8_t arc_addr_octet[1]; -} __packed; - -/* - * Structure of a 2.5MB/s Arcnet header. - * as given to interface code. - */ -struct arc_header { - u_int8_t arc_shost; - u_int8_t arc_dhost; - u_int8_t arc_type; - /* - * only present for newstyle encoding with LL fragmentation. - * Don't use sizeof(anything), use ARC_HDR{,NEW}LEN instead. - */ - u_int8_t arc_flag; - u_int16_t arc_seqid; - - /* - * only present in exception packets (arc_flag == 0xff) - */ - u_int8_t arc_type2; /* same as arc_type */ - u_int8_t arc_flag2; /* real flag value */ - u_int16_t arc_seqid2; /* real seqid value */ -} __packed; - -#define ARC_ADDR_LEN 1 - -#define ARC_HDRLEN 3 -#define ARC_HDRNEWLEN 6 -#define ARC_HDRNEWLEN_EXC 10 - -/* these lengths are data link layer length - 2 * ARC_ADDR_LEN */ -#define ARC_MIN_LEN 1 -#define ARC_MIN_FORBID_LEN 254 -#define ARC_MAX_FORBID_LEN 256 -#define ARC_MAX_LEN 508 -#define ARC_MAX_DATA 504 - -/* RFC 1051 */ -#define ARCTYPE_IP_OLD 240 /* IP protocol */ -#define ARCTYPE_ARP_OLD 241 /* address resolution protocol */ - -/* RFC 1201 */ -#define ARCTYPE_IP 212 /* IP protocol */ -#define ARCTYPE_ARP 213 /* address resolution protocol */ -#define ARCTYPE_REVARP 214 /* reverse addr resolution protocol */ - -#define ARCTYPE_ATALK 221 /* Appletalk */ -#define ARCTYPE_BANIAN 247 /* Banyan Vines */ -#define ARCTYPE_IPX 250 /* Novell IPX */ - -#define ARCTYPE_INET6 0xc4 /* IPng */ -#define ARCTYPE_DIAGNOSE 0x80 /* as per ANSI/ATA 878.1 */ - -#define ARCMTU 507 -#define ARCMIN 0 - -#define ARC_PHDS_MAXMTU 60480 - -struct arccom { - struct ifnet *ac_ifp; /* network-visible interface */ - - u_int16_t ac_seqid; /* seq. id used by PHDS encap. */ - - u_int8_t arc_shost; - u_int8_t arc_dhost; - u_int8_t arc_type; - - u_int8_t dummy0; - u_int16_t dummy1; - int sflag, fsflag, rsflag; - struct mbuf *curr_frag; - - struct ac_frag { - u_int8_t af_maxflag; /* from first packet */ - u_int8_t af_lastseen; /* last split flag seen */ - u_int16_t af_seqid; - struct mbuf *af_packet; - } ac_fragtab[256]; /* indexed by sender ll address */ -}; - -#ifdef _KERNEL -extern u_int8_t arcbroadcastaddr; -extern int arc_ipmtu; /* XXX new ip only, no RFC 1051! */ - -void arc_ifattach(struct ifnet *, u_int8_t); -void arc_ifdetach(struct ifnet *); -void arc_storelladdr(struct ifnet *, u_int8_t); -int arc_isphds(u_int8_t); -void arc_input(struct ifnet *, struct mbuf *); -int arc_output(struct ifnet *, struct mbuf *, - const struct sockaddr *, struct route *); -int arc_ioctl(struct ifnet *, u_long, caddr_t); - -void arc_frag_init(struct ifnet *); -struct mbuf * arc_frag_next(struct ifnet *); -#endif - -#endif /* _NET_IF_ARC_H_ */ diff --git a/freebsd/sys/net/if_arcsubr.c b/freebsd/sys/net/if_arcsubr.c deleted file mode 100644 index 9f0a03d5..00000000 --- a/freebsd/sys/net/if_arcsubr.c +++ /dev/null @@ -1,833 +0,0 @@ -#include <machine/rtems-bsd-kernel-space.h> - -/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */ -/* $FreeBSD$ */ - -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) 1994, 1995 Ignatios Souvatzis - * Copyright (c) 1982, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp - * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 - * - */ -#include <rtems/bsd/local/opt_inet.h> -#include <rtems/bsd/local/opt_inet6.h> - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/sockio.h> -#include <sys/errno.h> -#include <sys/syslog.h> - -#include <machine/cpu.h> - -#include <net/if.h> -#include <net/if_var.h> -#include <net/netisr.h> -#include <net/route.h> -#include <net/if_dl.h> -#include <net/if_types.h> -#include <net/if_arc.h> -#include <net/if_arp.h> -#include <net/bpf.h> -#include <net/if_llatbl.h> - -#if defined(INET) || defined(INET6) -#include <netinet/in.h> -#include <netinet/in_var.h> -#include <netinet/if_ether.h> -#endif - -#ifdef INET6 -#include <netinet6/nd6.h> -#endif - -#define ARCNET_ALLOW_BROKEN_ARP - -static struct mbuf *arc_defrag(struct ifnet *, struct mbuf *); -static int arc_resolvemulti(struct ifnet *, struct sockaddr **, - struct sockaddr *); - -u_int8_t arcbroadcastaddr = 0; - -#define ARC_LLADDR(ifp) (*(u_int8_t *)IF_LLADDR(ifp)) - -#define senderr(e) { error = (e); goto bad;} -#define SIN(s) ((const struct sockaddr_in *)(s)) - -/* - * ARCnet output routine. - * Encapsulate a packet of type family for the local net. - * Assumes that ifp is actually pointer to arccom structure. - */ -int -arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, - struct route *ro) -{ - struct arc_header *ah; - int error; - u_int8_t atype, adst; - int loop_copy = 0; - int isphds; -#if defined(INET) || defined(INET6) - int is_gw = 0; -#endif - - if (!((ifp->if_flags & IFF_UP) && - (ifp->if_drv_flags & IFF_DRV_RUNNING))) - return(ENETDOWN); /* m, m1 aren't initialized yet */ - - error = 0; -#if defined(INET) || defined(INET6) - if (ro != NULL) - is_gw = (ro->ro_flags & RT_HAS_GW) != 0; -#endif - - switch (dst->sa_family) { -#ifdef INET - case AF_INET: - - /* - * For now, use the simple IP addr -> ARCnet addr mapping - */ - if (m->m_flags & (M_BCAST|M_MCAST)) - adst = arcbroadcastaddr; /* ARCnet broadcast address */ - else if (ifp->if_flags & IFF_NOARP) - adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF; - else { - error = arpresolve(ifp, is_gw, m, dst, &adst, NULL, - NULL); - if (error) - return (error == EWOULDBLOCK ? 0 : error); - } - - atype = (ifp->if_flags & IFF_LINK0) ? - ARCTYPE_IP_OLD : ARCTYPE_IP; - break; - case AF_ARP: - { - struct arphdr *ah; - ah = mtod(m, struct arphdr *); - ah->ar_hrd = htons(ARPHRD_ARCNET); - - loop_copy = -1; /* if this is for us, don't do it */ - - switch(ntohs(ah->ar_op)) { - case ARPOP_REVREQUEST: - case ARPOP_REVREPLY: - atype = ARCTYPE_REVARP; - break; - case ARPOP_REQUEST: - case ARPOP_REPLY: - default: - atype = ARCTYPE_ARP; - break; - } - - if (m->m_flags & M_BCAST) - bcopy(ifp->if_broadcastaddr, &adst, ARC_ADDR_LEN); - else - bcopy(ar_tha(ah), &adst, ARC_ADDR_LEN); - - } - break; -#endif -#ifdef INET6 - case AF_INET6: - if ((m->m_flags & M_MCAST) != 0) - adst = arcbroadcastaddr; /* ARCnet broadcast address */ - else { - error = nd6_resolve(ifp, is_gw, m, dst, &adst, NULL, - NULL); - if (error != 0) - return (error == EWOULDBLOCK ? 0 : error); - } - atype = ARCTYPE_INET6; - break; -#endif - case AF_UNSPEC: - { - const struct arc_header *ah; - - loop_copy = -1; - ah = (const struct arc_header *)dst->sa_data; - adst = ah->arc_dhost; - atype = ah->arc_type; - - if (atype == ARCTYPE_ARP) { - atype = (ifp->if_flags & IFF_LINK0) ? - ARCTYPE_ARP_OLD: ARCTYPE_ARP; - -#ifdef ARCNET_ALLOW_BROKEN_ARP - /* - * XXX It's not clear per RFC826 if this is needed, but - * "assigned numbers" say this is wrong. - * However, e.g., AmiTCP 3.0Beta used it... we make this - * switchable for emergency cases. Not perfect, but... - */ - if (ifp->if_flags & IFF_LINK2) - mtod(m, struct arphdr *)->ar_pro = atype - 1; -#endif - } - break; - } - default: - if_printf(ifp, "can't handle af%d\n", dst->sa_family); - senderr(EAFNOSUPPORT); - } - - isphds = arc_isphds(atype); - M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_NOWAIT); - if (m == NULL) - senderr(ENOBUFS); - ah = mtod(m, struct arc_header *); - ah->arc_type = atype; - ah->arc_dhost = adst; - ah->arc_shost = ARC_LLADDR(ifp); - if (isphds) { - ah->arc_flag = 0; - ah->arc_seqid = 0; - } - - if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { - if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { - struct mbuf *n = m_copym(m, 0, M_COPYALL, M_NOWAIT); - - (void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN); - } else if (ah->arc_dhost == ah->arc_shost) { - (void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN); - return (0); /* XXX */ - } - } - - BPF_MTAP(ifp, m); - - error = ifp->if_transmit(ifp, m); - - return (error); - -bad: - if (m) - m_freem(m); - return (error); -} - -void -arc_frag_init(struct ifnet *ifp) -{ - struct arccom *ac; - - ac = (struct arccom *)ifp->if_l2com; - ac->curr_frag = 0; -} - -struct mbuf * -arc_frag_next(struct ifnet *ifp) -{ - struct arccom *ac; - struct mbuf *m; - struct arc_header *ah; - - ac = (struct arccom *)ifp->if_l2com; - if ((m = ac->curr_frag) == NULL) { - int tfrags; - - /* dequeue new packet */ - IF_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) - return 0; - - ah = mtod(m, struct arc_header *); - if (!arc_isphds(ah->arc_type)) - return m; - - ++ac->ac_seqid; /* make the seqid unique */ - tfrags = howmany(m->m_pkthdr.len, ARC_MAX_DATA); - ac->fsflag = 2 * tfrags - 3; - ac->sflag = 0; - ac->rsflag = ac->fsflag; - ac->arc_dhost = ah->arc_dhost; - ac->arc_shost = ah->arc_shost; - ac->arc_type = ah->arc_type; - - m_adj(m, ARC_HDRNEWLEN); - ac->curr_frag = m; - } - - /* split out next fragment and return it */ - if (ac->sflag < ac->fsflag) { - /* we CAN'T have short packets here */ - ac->curr_frag = m_split(m, ARC_MAX_DATA, M_NOWAIT); - if (ac->curr_frag == 0) { - m_freem(m); - return 0; - } - - M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT); - if (m == NULL) { - m_freem(ac->curr_frag); - ac->curr_frag = 0; - return 0; - } - - ah = mtod(m, struct arc_header *); - ah->arc_flag = ac->rsflag; - ah->arc_seqid = ac->ac_seqid; - - ac->sflag += 2; - ac->rsflag = ac->sflag; - } else if ((m->m_pkthdr.len >= - ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) && - (m->m_pkthdr.len <= - ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) { - ac->curr_frag = 0; - - M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_NOWAIT); - if (m == NULL) - return 0; - - ah = mtod(m, struct arc_header *); - ah->arc_flag = 0xFF; - ah->arc_seqid = 0xFFFF; - ah->arc_type2 = ac->arc_type; - ah->arc_flag2 = ac->sflag; - ah->arc_seqid2 = ac->ac_seqid; - } else { - ac->curr_frag = 0; - - M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT); - if (m == NULL) - return 0; - - ah = mtod(m, struct arc_header *); - ah->arc_flag = ac->sflag; - ah->arc_seqid = ac->ac_seqid; - } - - ah->arc_dhost = ac->arc_dhost; - ah->arc_shost = ac->arc_shost; - ah->arc_type = ac->arc_type; - - return m; -} - -/* - * Defragmenter. Returns mbuf if last packet found, else - * NULL. frees incoming mbuf as necessary. - */ - -static __inline struct mbuf * -arc_defrag(struct ifnet *ifp, struct mbuf *m) -{ - struct arc_header *ah, *ah1; - struct arccom *ac; - struct ac_frag *af; - struct mbuf *m1; - char *s; - int newflen; - u_char src,dst,typ; - - ac = (struct arccom *)ifp->if_l2com; - - if (m->m_len < ARC_HDRNEWLEN) { - m = m_pullup(m, ARC_HDRNEWLEN); - if (m == NULL) { - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - return NULL; - } - } - - ah = mtod(m, struct arc_header *); - typ = ah->arc_type; - - if (!arc_isphds(typ)) - return m; - - src = ah->arc_shost; - dst = ah->arc_dhost; - - if (ah->arc_flag == 0xff) { - m_adj(m, 4); - - if (m->m_len < ARC_HDRNEWLEN) { - m = m_pullup(m, ARC_HDRNEWLEN); - if (m == NULL) { - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - return NULL; - } - } - - ah = mtod(m, struct arc_header *); - } - - af = &ac->ac_fragtab[src]; - m1 = af->af_packet; - s = "debug code error"; - - if (ah->arc_flag & 1) { - /* - * first fragment. We always initialize, which is - * about the right thing to do, as we only want to - * accept one fragmented packet per src at a time. - */ - if (m1 != NULL) - m_freem(m1); - - af->af_packet = m; - m1 = m; - af->af_maxflag = ah->arc_flag; - af->af_lastseen = 0; - af->af_seqid = ah->arc_seqid; - - return NULL; - /* notreached */ - } else { - /* check for unfragmented packet */ - if (ah->arc_flag == 0) - return m; - - /* do we have a first packet from that src? */ - if (m1 == NULL) { - s = "no first frag"; - goto outofseq; - } - - ah1 = mtod(m1, struct arc_header *); - - if (ah->arc_seqid != ah1->arc_seqid) { - s = "seqid differs"; - goto outofseq; - } - - if (typ != ah1->arc_type) { - s = "type differs"; - goto outofseq; - } - - if (dst != ah1->arc_dhost) { - s = "dest host differs"; - goto outofseq; - } - - /* typ, seqid and dst are ok here. */ - - if (ah->arc_flag == af->af_lastseen) { - m_freem(m); - return NULL; - } - - if (ah->arc_flag == af->af_lastseen + 2) { - /* ok, this is next fragment */ - af->af_lastseen = ah->arc_flag; - m_adj(m,ARC_HDRNEWLEN); - - /* - * m_cat might free the first mbuf (with pkthdr) - * in 2nd chain; therefore: - */ - - newflen = m->m_pkthdr.len; - - m_cat(m1,m); - - m1->m_pkthdr.len += newflen; - - /* is it the last one? */ - if (af->af_lastseen > af->af_maxflag) { - af->af_packet = NULL; - return(m1); - } else - return NULL; - } - s = "other reason"; - /* if all else fails, it is out of sequence, too */ - } -outofseq: - if (m1) { - m_freem(m1); - af->af_packet = NULL; - } - - if (m) - m_freem(m); - - log(LOG_INFO,"%s: got out of seq. packet: %s\n", - ifp->if_xname, s); - - return NULL; -} - -/* - * return 1 if Packet Header Definition Standard, else 0. - * For now: old IP, old ARP aren't obviously. Lacking correct information, - * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS. - * (Apple and Novell corporations were involved, among others, in PHDS work). - * Easiest is to assume that everybody else uses that, too. - */ -int -arc_isphds(u_int8_t type) -{ - return (type != ARCTYPE_IP_OLD && - type != ARCTYPE_ARP_OLD && - type != ARCTYPE_DIAGNOSE); -} - -/* - * Process a received Arcnet packet; - * the packet is in the mbuf chain m with - * the ARCnet header. - */ -void -arc_input(struct ifnet *ifp, struct mbuf *m) -{ - struct arc_header *ah; - int isr; - u_int8_t atype; - - if ((ifp->if_flags & IFF_UP) == 0) { - m_freem(m); - return; - } - - /* possibly defragment: */ - m = arc_defrag(ifp, m); - if (m == NULL) - return; - - BPF_MTAP(ifp, m); - - ah = mtod(m, struct arc_header *); - /* does this belong to us? */ - if ((ifp->if_flags & IFF_PROMISC) == 0 - && ah->arc_dhost != arcbroadcastaddr - && ah->arc_dhost != ARC_LLADDR(ifp)) { - m_freem(m); - return; - } - - if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); - - if (ah->arc_dhost == arcbroadcastaddr) { - m->m_flags |= M_BCAST|M_MCAST; - if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1); - } - - atype = ah->arc_type; - switch (atype) { -#ifdef INET - case ARCTYPE_IP: - m_adj(m, ARC_HDRNEWLEN); - isr = NETISR_IP; - break; - - case ARCTYPE_IP_OLD: - m_adj(m, ARC_HDRLEN); - isr = NETISR_IP; - break; - - case ARCTYPE_ARP: - if (ifp->if_flags & IFF_NOARP) { - /* Discard packet if ARP is disabled on interface */ - m_freem(m); - return; - } - m_adj(m, ARC_HDRNEWLEN); - isr = NETISR_ARP; -#ifdef ARCNET_ALLOW_BROKEN_ARP - mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); -#endif - break; - - case ARCTYPE_ARP_OLD: - if (ifp->if_flags & IFF_NOARP) { - /* Discard packet if ARP is disabled on interface */ - m_freem(m); - return; - } - m_adj(m, ARC_HDRLEN); - isr = NETISR_ARP; -#ifdef ARCNET_ALLOW_BROKEN_ARP - mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); -#endif - break; -#endif -#ifdef INET6 - case ARCTYPE_INET6: - m_adj(m, ARC_HDRNEWLEN); - isr = NETISR_IPV6; - break; -#endif - default: - m_freem(m); - return; - } - M_SETFIB(m, ifp->if_fib); - netisr_dispatch(isr, m); -} - -/* - * Register (new) link level address. - */ -void -arc_storelladdr(struct ifnet *ifp, u_int8_t lla) -{ - ARC_LLADDR(ifp) = lla; -} - -/* - * Perform common duties while attaching to interface list - */ -void -arc_ifattach(struct ifnet *ifp, u_int8_t lla) -{ - struct ifaddr *ifa; - struct sockaddr_dl *sdl; - struct arccom *ac; - - if_attach(ifp); - ifp->if_addrlen = 1; - ifp->if_hdrlen = ARC_HDRLEN; - ifp->if_mtu = 1500; - ifp->if_resolvemulti = arc_resolvemulti; - if (ifp->if_baudrate == 0) - ifp->if_baudrate = 2500000; - ifa = ifp->if_addr; - KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); - sdl = (struct sockaddr_dl *)ifa->ifa_addr; - sdl->sdl_type = IFT_ARCNET; - sdl->sdl_alen = ifp->if_addrlen; - - if (ifp->if_flags & IFF_BROADCAST) - ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI; - - ac = (struct arccom *)ifp->if_l2com; - ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */ - if (lla == 0) { - /* XXX this message isn't entirely clear, to me -- cgd */ - log(LOG_ERR,"%s: link address 0 reserved for broadcasts. Please change it and ifconfig %s down up\n", - ifp->if_xname, ifp->if_xname); - } - arc_storelladdr(ifp, lla); - - ifp->if_broadcastaddr = &arcbroadcastaddr; - - bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN); -} - -void -arc_ifdetach(struct ifnet *ifp) -{ - bpfdetach(ifp); - if_detach(ifp); -} - -int -arc_ioctl(struct ifnet *ifp, u_long command, caddr_t data) -{ - struct ifaddr *ifa = (struct ifaddr *) data; - struct ifreq *ifr = (struct ifreq *) data; - int error = 0; - - switch (command) { - case SIOCSIFADDR: - ifp->if_flags |= IFF_UP; - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - ifp->if_init(ifp->if_softc); /* before arpwhohas */ - arp_ifinit(ifp, ifa); - break; -#endif - default: - ifp->if_init(ifp->if_softc); - break; - } - break; - - case SIOCGIFADDR: - ifr->ifr_addr.sa_data[0] = ARC_LLADDR(ifp); - break; - - case SIOCADDMULTI: - case SIOCDELMULTI: - if (ifr == NULL) - error = EAFNOSUPPORT; - else { - switch (ifr->ifr_addr.sa_family) { - case AF_INET: - case AF_INET6: - error = 0; - break; - default: - error = EAFNOSUPPORT; - break; - } - } - break; - - case SIOCSIFMTU: - /* - * Set the interface MTU. - * mtu can't be larger than ARCMTU for RFC1051 - * and can't be larger than ARC_PHDS_MTU - */ - if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) || - ifr->ifr_mtu > ARC_PHDS_MAXMTU) - error = EINVAL; - else - ifp->if_mtu = ifr->ifr_mtu; - break; - } - - return (error); -} - -/* based on ether_resolvemulti() */ -int -arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, - struct sockaddr *sa) -{ - struct sockaddr_dl *sdl; -#ifdef INET - struct sockaddr_in *sin; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; -#endif - - switch(sa->sa_family) { - case AF_LINK: - /* - * No mapping needed. Just check that it's a valid MC address. - */ - sdl = (struct sockaddr_dl *)sa; - if (*LLADDR(sdl) != arcbroadcastaddr) - return EADDRNOTAVAIL; - *llsa = NULL; - return 0; -#ifdef INET - case AF_INET: - sin = (struct sockaddr_in *)sa; - if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) - return EADDRNOTAVAIL; - sdl = link_init_sdl(ifp, *llsa, IFT_ETHER); - sdl->sdl_alen = ARC_ADDR_LEN; - *LLADDR(sdl) = 0; - *llsa = (struct sockaddr *)sdl; - return 0; -#endif -#ifdef INET6 - case AF_INET6: - sin6 = (struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* - * An IP6 address of 0 means listen to all - * of the Ethernet multicast address used for IP6. - * (This is used for multicast routers.) - */ - ifp->if_flags |= IFF_ALLMULTI; - *llsa = NULL; - return 0; - } - if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) - return EADDRNOTAVAIL; - sdl = link_init_sdl(ifp, *llsa, IFT_ETHER); - sdl->sdl_alen = ARC_ADDR_LEN; - *LLADDR(sdl) = 0; - *llsa = (struct sockaddr *)sdl; - return 0; -#endif - - default: - /* - * Well, the text isn't quite right, but it's the name - * that counts... - */ - return EAFNOSUPPORT; - } -} - -static MALLOC_DEFINE(M_ARCCOM, "arccom", "ARCNET interface internals"); - -static void* -arc_alloc(u_char type, struct ifnet *ifp) -{ - struct arccom *ac; - - ac = malloc(sizeof(struct arccom), M_ARCCOM, M_WAITOK | M_ZERO); - ac->ac_ifp = ifp; - - return (ac); -} - -static void -arc_free(void *com, u_char type) -{ - - free(com, M_ARCCOM); -} - -static int -arc_modevent(module_t mod, int type, void *data) -{ - - switch (type) { - case MOD_LOAD: - if_register_com_alloc(IFT_ARCNET, arc_alloc, arc_free); - break; - case MOD_UNLOAD: - if_deregister_com_alloc(IFT_ARCNET); - break; - default: - return EOPNOTSUPP; - } - - return (0); -} - -static moduledata_t arc_mod = { - "arcnet", - arc_modevent, - 0 -}; - -DECLARE_MODULE(arcnet, arc_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); -MODULE_VERSION(arcnet, 1); diff --git a/freebsd/sys/net/if_arp.h b/freebsd/sys/net/if_arp.h index 1a66c89c..070dbafe 100644 --- a/freebsd/sys/net/if_arp.h +++ b/freebsd/sys/net/if_arp.h @@ -49,7 +49,6 @@ struct arphdr { u_short ar_hrd; /* format of hardware address */ #define ARPHRD_ETHER 1 /* ethernet hardware format */ #define ARPHRD_IEEE802 6 /* token-ring hardware format */ -#define ARPHRD_ARCNET 7 /* arcnet hardware format */ #define ARPHRD_FRELAY 15 /* frame relay hardware format */ #define ARPHRD_IEEE1394 24 /* firewire hardware format */ #define ARPHRD_INFINIBAND 32 /* infiniband hardware format */ diff --git a/freebsd/sys/net/if_bridge.c b/freebsd/sys/net/if_bridge.c index 248cd45a..3e774934 100644 --- a/freebsd/sys/net/if_bridge.c +++ b/freebsd/sys/net/if_bridge.c @@ -74,8 +74,8 @@ * * - Currently only supports Ethernet-like interfaces (Ethernet, * 802.11, VLANs on Ethernet, etc.) Figure out a nice way - * to bridge other types of interfaces (FDDI-FDDI, and maybe - * consider heterogeneous bridges). + * to bridge other types of interfaces (maybe consider + * heterogeneous bridges). */ #include <sys/cdefs.h> @@ -342,7 +342,6 @@ static int bridge_fragment(struct ifnet *, struct mbuf **mp, static void bridge_linkstate(struct ifnet *ifp); static void bridge_linkcheck(struct bridge_softc *sc); -extern void (*bridge_linkstate_p)(struct ifnet *ifp); /* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */ #define VLANTAGOF(_m) \ @@ -558,10 +557,7 @@ bridge_modevent(module_t mod, int type, void *data) bridge_rtnode_zone = uma_zcreate("bridge_rtnode", sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); - bridge_input_p = bridge_input; - bridge_output_p = bridge_output; bridge_dn_p = bridge_dummynet; - bridge_linkstate_p = bridge_linkstate; bridge_detach_cookie = EVENTHANDLER_REGISTER( ifnet_departure_event, bridge_ifdetach, NULL, EVENTHANDLER_PRI_ANY); @@ -570,10 +566,7 @@ bridge_modevent(module_t mod, int type, void *data) EVENTHANDLER_DEREGISTER(ifnet_departure_event, bridge_detach_cookie); uma_zdestroy(bridge_rtnode_zone); - bridge_input_p = NULL; - bridge_output_p = NULL; bridge_dn_p = NULL; - bridge_linkstate_p = NULL; break; default: return (EOPNOTSUPP); @@ -1043,6 +1036,9 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, KASSERT(bif->bif_addrcnt == 0, ("%s: %d bridge routes referenced", __func__, bif->bif_addrcnt)); + ifs->if_bridge_output = NULL; + ifs->if_bridge_input = NULL; + ifs->if_bridge_linkstate = NULL; BRIDGE_UNLOCK(sc); if (!gone) { switch (ifs->if_type) { @@ -1200,6 +1196,9 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) } ifs->if_bridge = sc; + ifs->if_bridge_output = bridge_output; + ifs->if_bridge_input = bridge_input; + ifs->if_bridge_linkstate = bridge_linkstate; bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp); /* * XXX: XLOCK HERE!?! diff --git a/freebsd/sys/net/if_bridgevar.h b/freebsd/sys/net/if_bridgevar.h index 84ff8d21..f4f61706 100644 --- a/freebsd/sys/net/if_bridgevar.h +++ b/freebsd/sys/net/if_bridgevar.h @@ -309,23 +309,20 @@ struct ifbpstpconf { (_sc)->sc_iflist_xcnt--; \ } while (0) -#define BRIDGE_INPUT(_ifp, _m) do { \ - KASSERT(bridge_input_p != NULL, \ +#define BRIDGE_INPUT(_ifp, _m) do { \ + KASSERT((_ifp)->if_bridge_input != NULL, \ ("%s: if_bridge not loaded!", __func__)); \ - _m = (*bridge_input_p)(_ifp, _m); \ + _m = (*(_ifp)->if_bridge_input)(_ifp, _m); \ if (_m != NULL) \ _ifp = _m->m_pkthdr.rcvif; \ } while (0) #define BRIDGE_OUTPUT(_ifp, _m, _err) do { \ - KASSERT(bridge_output_p != NULL, \ + KASSERT((_ifp)->if_bridge_output != NULL, \ ("%s: if_bridge not loaded!", __func__)); \ - _err = (*bridge_output_p)(_ifp, _m, NULL, NULL); \ + _err = (*(_ifp)->if_bridge_output)(_ifp, _m, NULL, NULL); \ } while (0) -extern struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *); -extern int (*bridge_output_p)(struct ifnet *, struct mbuf *, - struct sockaddr *, struct rtentry *); extern void (*bridge_dn_p)(struct mbuf *, struct ifnet *); #endif /* _KERNEL */ diff --git a/freebsd/sys/net/if_clone.c b/freebsd/sys/net/if_clone.c index 295bddf4..5a9c20c2 100644 --- a/freebsd/sys/net/if_clone.c +++ b/freebsd/sys/net/if_clone.c @@ -69,6 +69,7 @@ struct if_clone { char ifc_name[IFCLOSIZ]; /* (c) Name of device, e.g. `gif' */ struct unrhdr *ifc_unrhdr; /* (c) alloc_unr(9) header */ int ifc_maxunit; /* (c) maximum unit number */ + int ifc_flags; long ifc_refcnt; /* (i) Reference count. */ LIST_HEAD(, ifnet) ifc_iflist; /* (i) List of cloned interfaces */ struct mtx ifc_mtx; /* Mutex to protect members. */ @@ -234,7 +235,8 @@ if_clone_createif(struct if_clone *ifc, char *name, size_t len, caddr_t params) if (ifp == NULL) panic("%s: lookup failed for %s", __func__, name); - if_addgroup(ifp, ifc->ifc_name); + if ((ifc->ifc_flags & IFC_NOGROUP) == 0) + if_addgroup(ifp, ifc->ifc_name); IF_CLONE_LOCK(ifc); IFC_IFLIST_INSERT(ifc, ifp); @@ -321,8 +323,8 @@ if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp) CURVNET_RESTORE(); return (ENXIO); /* ifp is not on the list. */ } - - if_delgroup(ifp, ifc->ifc_name); + if ((ifc->ifc_flags & IFC_NOGROUP) == 0) + if_delgroup(ifp, ifc->ifc_name); if (ifc->ifc_type == SIMPLE) err = ifc_simple_destroy(ifc, ifp); @@ -330,7 +332,8 @@ if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp) err = (*ifc->ifc_destroy)(ifc, ifp); if (err != 0) { - if_addgroup(ifp, ifc->ifc_name); + if ((ifc->ifc_flags & IFC_NOGROUP) == 0) + if_addgroup(ifp, ifc->ifc_name); IF_CLONE_LOCK(ifc); IFC_IFLIST_INSERT(ifc, ifp); @@ -415,7 +418,7 @@ if_clone_simple(const char *name, ifcs_create_t create, ifcs_destroy_t destroy, for (unit = 0; unit < minifs; unit++) { char name[IFNAMSIZ]; - int error; + int error __unused; snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); error = if_clone_createif(ifc, name, IFNAMSIZ, NULL); @@ -555,9 +558,10 @@ if_clone_findifc(struct ifnet *ifp) void if_clone_addgroup(struct ifnet *ifp, struct if_clone *ifc) { - - if_addgroup(ifp, ifc->ifc_name); - IF_CLONE_REMREF(ifc); + if ((ifc->ifc_flags & IFC_NOGROUP) == 0) { + if_addgroup(ifp, ifc->ifc_name); + IF_CLONE_REMREF(ifc); + } } /* @@ -734,3 +738,21 @@ ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp) return (0); } + +const char * +ifc_name(struct if_clone *ifc) +{ + return (ifc->ifc_name); +} + +void +ifc_flags_set(struct if_clone *ifc, int flags) +{ + ifc->ifc_flags = flags; +} + +int +ifc_flags_get(struct if_clone *ifc) +{ + return (ifc->ifc_flags); +} diff --git a/freebsd/sys/net/if_clone.h b/freebsd/sys/net/if_clone.h index f26ab63b..5dceacf6 100644 --- a/freebsd/sys/net/if_clone.h +++ b/freebsd/sys/net/if_clone.h @@ -37,6 +37,8 @@ #ifdef _KERNEL +#define IFC_NOGROUP 0x1 + struct if_clone; /* Methods. */ @@ -59,6 +61,9 @@ void if_clone_detach(struct if_clone *); int ifc_name2unit(const char *name, int *unit); int ifc_alloc_unit(struct if_clone *, int *); void ifc_free_unit(struct if_clone *, int); +const char *ifc_name(struct if_clone *); +void ifc_flags_set(struct if_clone *, int flags); +int ifc_flags_get(struct if_clone *); #ifdef _SYS_EVENTHANDLER_H_ /* Interface clone event. */ diff --git a/freebsd/sys/net/if_epair.c b/freebsd/sys/net/if_epair.c index 106c0a43..d727bc2c 100644 --- a/freebsd/sys/net/if_epair.c +++ b/freebsd/sys/net/if_epair.c @@ -55,10 +55,14 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/hash.h> +#include <sys/jail.h> #include <sys/kernel.h> +#include <sys/libkern.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/module.h> +#include <sys/proc.h> #include <sys/refcount.h> #include <sys/queue.h> #include <sys/smp.h> @@ -253,7 +257,7 @@ static void epair_nh_sintr(struct mbuf *m) { struct ifnet *ifp; - struct epair_softc *sc; + struct epair_softc *sc __unused; ifp = m->m_pkthdr.rcvif; (*ifp->if_input)(ifp, m); @@ -298,7 +302,7 @@ epair_nh_drainedcpu(u_int cpuid) IFQ_LOCK(&ifp->if_snd); if (IFQ_IS_EMPTY(&ifp->if_snd)) { - struct epair_softc *sc; + struct epair_softc *sc __unused; STAILQ_REMOVE(&epair_dpcpu->epair_ifp_drain_list, elm, epair_ifp_drain, ifp_next); @@ -339,7 +343,7 @@ epair_remove_ifp_from_draining(struct ifnet *ifp) STAILQ_FOREACH_SAFE(elm, &epair_dpcpu->epair_ifp_drain_list, ifp_next, tvar) { if (ifp == elm->ifp) { - struct epair_softc *sc; + struct epair_softc *sc __unused; STAILQ_REMOVE( &epair_dpcpu->epair_ifp_drain_list, elm, @@ -715,6 +719,9 @@ epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) struct ifnet *ifp; char *dp; int error, unit, wildcard; + uint64_t hostid; + uint32_t key[3]; + uint32_t hash; uint8_t eaddr[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */ /* @@ -726,14 +733,12 @@ epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) if (params) { scb = (struct epair_softc *)params; ifp = scb->ifp; - /* Assign a hopefully unique, locally administered etheraddr. */ - eaddr[0] = 0x02; - eaddr[3] = (ifp->if_index >> 8) & 0xff; - eaddr[4] = ifp->if_index & 0xff; + /* Copy epairNa etheraddr and change the last byte. */ + memcpy(eaddr, scb->oifp->if_hw_addr, ETHER_ADDR_LEN); eaddr[5] = 0x0b; ether_ifattach(ifp, eaddr); /* Correctly set the name for the cloner list. */ - strlcpy(name, scb->ifp->if_xname, len); + strlcpy(name, ifp->if_xname, len); return (0); } @@ -837,10 +842,21 @@ epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) ifp->if_init = epair_init; if_setsendqlen(ifp, ifqmaxlen); if_setsendqready(ifp); - /* Assign a hopefully unique, locally administered etheraddr. */ + + /* + * Calculate the etheraddr hashing the hostid and the + * interface index. The result would be hopefully unique + */ + getcredhostid(curthread->td_ucred, (unsigned long *)&hostid); + if (hostid == 0) + arc4rand(&hostid, sizeof(hostid), 0); + key[0] = (uint32_t)ifp->if_index; + key[1] = (uint32_t)(hostid & 0xffffffff); + key[2] = (uint32_t)((hostid >> 32) & 0xfffffffff); + hash = jenkins_hash32(key, 3, 0); + eaddr[0] = 0x02; - eaddr[3] = (ifp->if_index >> 8) & 0xff; - eaddr[4] = ifp->if_index & 0xff; + memcpy(&eaddr[1], &hash, 4); eaddr[5] = 0x0a; ether_ifattach(ifp, eaddr); sca->if_qflush = ifp->if_qflush; diff --git a/freebsd/sys/net/if_ethersubr.c b/freebsd/sys/net/if_ethersubr.c index 78ff2385..3893d331 100644 --- a/freebsd/sys/net/if_ethersubr.c +++ b/freebsd/sys/net/if_ethersubr.c @@ -104,9 +104,6 @@ void (*ng_ether_detach_p)(struct ifnet *ifp); void (*vlan_input_p)(struct ifnet *, struct mbuf *); /* if_bridge(4) support */ -struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *); -int (*bridge_output_p)(struct ifnet *, struct mbuf *, - struct sockaddr *, struct rtentry *); void (*bridge_dn_p)(struct mbuf *, struct ifnet *); /* if_lagg(4) support */ @@ -518,7 +515,7 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m) } eh = mtod(m, struct ether_header *); etype = ntohs(eh->ether_type); - random_harvest_queue(m, sizeof(*m), 2, RANDOM_NET_ETHER); + random_harvest_queue_ether(m, sizeof(*m), 2); CURVNET_SET_QUIET(ifp->if_vnet); @@ -1130,10 +1127,13 @@ ether_ioctl(struct ifnet *ifp, u_long command, caddr_t data) if (error != 0) break; if (ifr->ifr_lan_pcp > 7 && - ifr->ifr_lan_pcp != IFNET_PCP_NONE) + ifr->ifr_lan_pcp != IFNET_PCP_NONE) { error = EINVAL; - else + } else { ifp->if_pcp = ifr->ifr_lan_pcp; + /* broadcast event about PCP change */ + EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_PCP); + } break; case SIOCGLANPCP: diff --git a/freebsd/sys/net/if_fddisubr.c b/freebsd/sys/net/if_fddisubr.c deleted file mode 100644 index c011346e..00000000 --- a/freebsd/sys/net/if_fddisubr.c +++ /dev/null @@ -1,669 +0,0 @@ -#include <machine/rtems-bsd-kernel-space.h> - -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) 1995, 1996 - * Matt Thomas <matt@3am-software.com>. All rights reserved. - * Copyright (c) 1982, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp - * $FreeBSD$ - */ - -#include <rtems/bsd/local/opt_inet.h> -#include <rtems/bsd/local/opt_inet6.h> - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/module.h> -#include <sys/socket.h> -#include <sys/sockio.h> - -#include <net/if.h> -#include <net/if_var.h> -#include <net/if_dl.h> -#include <net/if_llc.h> -#include <net/if_types.h> -#include <net/if_llatbl.h> - -#include <net/ethernet.h> -#include <net/netisr.h> -#include <net/route.h> -#include <net/bpf.h> -#include <net/fddi.h> - -#if defined(INET) || defined(INET6) -#include <netinet/in.h> -#include <netinet/in_var.h> -#include <netinet/if_ether.h> -#endif -#ifdef INET6 -#include <netinet6/nd6.h> -#endif - -#ifdef DECNET -#include <netdnet/dn.h> -#endif - -#include <security/mac/mac_framework.h> - -static const u_char fddibroadcastaddr[FDDI_ADDR_LEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - -static int fddi_resolvemulti(struct ifnet *, struct sockaddr **, - struct sockaddr *); -static int fddi_output(struct ifnet *, struct mbuf *, const struct sockaddr *, - struct route *); -static void fddi_input(struct ifnet *ifp, struct mbuf *m); - -#define senderr(e) do { error = (e); goto bad; } while (0) - -/* - * FDDI output routine. - * Encapsulate a packet of type family for the local net. - * Use trailer local net encapsulation if enough data in first - * packet leaves a multiple of 512 bytes of data in remainder. - */ -static int -fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, - struct route *ro) -{ - u_int16_t type; - int loop_copy = 0, error = 0, hdrcmplt = 0; - u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN]; - struct fddi_header *fh; -#if defined(INET) || defined(INET6) - int is_gw = 0; -#endif - -#ifdef MAC - error = mac_ifnet_check_transmit(ifp, m); - if (error) - senderr(error); -#endif - - if (ifp->if_flags & IFF_MONITOR) - senderr(ENETDOWN); - if (!((ifp->if_flags & IFF_UP) && - (ifp->if_drv_flags & IFF_DRV_RUNNING))) - senderr(ENETDOWN); - getmicrotime(&ifp->if_lastchange); - -#if defined(INET) || defined(INET6) - if (ro != NULL) - is_gw = (ro->ro_flags & RT_HAS_GW) != 0; -#endif - - switch (dst->sa_family) { -#ifdef INET - case AF_INET: { - error = arpresolve(ifp, is_gw, m, dst, edst, NULL, NULL); - if (error) - return (error == EWOULDBLOCK ? 0 : error); - type = htons(ETHERTYPE_IP); - break; - } - case AF_ARP: - { - struct arphdr *ah; - ah = mtod(m, struct arphdr *); - ah->ar_hrd = htons(ARPHRD_ETHER); - - loop_copy = -1; /* if this is for us, don't do it */ - - switch (ntohs(ah->ar_op)) { - case ARPOP_REVREQUEST: - case ARPOP_REVREPLY: - type = htons(ETHERTYPE_REVARP); - break; - case ARPOP_REQUEST: - case ARPOP_REPLY: - default: - type = htons(ETHERTYPE_ARP); - break; - } - - if (m->m_flags & M_BCAST) - bcopy(ifp->if_broadcastaddr, edst, FDDI_ADDR_LEN); - else - bcopy(ar_tha(ah), edst, FDDI_ADDR_LEN); - - } - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL, NULL); - if (error) - return (error == EWOULDBLOCK ? 0 : error); - type = htons(ETHERTYPE_IPV6); - break; -#endif /* INET6 */ - case pseudo_AF_HDRCMPLT: - { - const struct ether_header *eh; - - hdrcmplt = 1; - eh = (const struct ether_header *)dst->sa_data; - bcopy(eh->ether_shost, esrc, FDDI_ADDR_LEN); - /* FALLTHROUGH */ - } - - case AF_UNSPEC: - { - const struct ether_header *eh; - - loop_copy = -1; - eh = (const struct ether_header *)dst->sa_data; - bcopy(eh->ether_dhost, edst, FDDI_ADDR_LEN); - if (*edst & 1) - m->m_flags |= (M_BCAST|M_MCAST); - type = eh->ether_type; - break; - } - - case AF_IMPLINK: - { - fh = mtod(m, struct fddi_header *); - error = EPROTONOSUPPORT; - switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { - case FDDIFC_LLC_ASYNC: { - /* legal priorities are 0 through 7 */ - if ((fh->fddi_fc & FDDIFC_Z) > 7) - goto bad; - break; - } - case FDDIFC_LLC_SYNC: { - /* FDDIFC_Z bits reserved, must be zero */ - if (fh->fddi_fc & FDDIFC_Z) - goto bad; - break; - } - case FDDIFC_SMT: { - /* FDDIFC_Z bits must be non zero */ - if ((fh->fddi_fc & FDDIFC_Z) == 0) - goto bad; - break; - } - default: { - /* anything else is too dangerous */ - goto bad; - } - } - error = 0; - if (fh->fddi_dhost[0] & 1) - m->m_flags |= (M_BCAST|M_MCAST); - goto queue_it; - } - default: - if_printf(ifp, "can't handle af%d\n", dst->sa_family); - senderr(EAFNOSUPPORT); - } - - /* - * Add LLC header. - */ - if (type != 0) { - struct llc *l; - M_PREPEND(m, LLC_SNAPFRAMELEN, M_NOWAIT); - if (m == NULL) - senderr(ENOBUFS); - l = mtod(m, struct llc *); - l->llc_control = LLC_UI; - l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; - l->llc_snap.org_code[0] = - l->llc_snap.org_code[1] = - l->llc_snap.org_code[2] = 0; - l->llc_snap.ether_type = htons(type); - } - - /* - * Add local net header. If no space in first mbuf, - * allocate another. - */ - M_PREPEND(m, FDDI_HDR_LEN, M_NOWAIT); - if (m == NULL) - senderr(ENOBUFS); - fh = mtod(m, struct fddi_header *); - fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; - bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN); - queue_it: - if (hdrcmplt) - bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN); - else - bcopy(IF_LLADDR(ifp), (caddr_t)fh->fddi_shost, - FDDI_ADDR_LEN); - - /* - * If a simplex interface, and the packet is being sent to our - * Ethernet address or a broadcast address, loopback a copy. - * XXX To make a simplex device behave exactly like a duplex - * device, we should copy in the case of sending to our own - * ethernet address (thus letting the original actually appear - * on the wire). However, we don't do that here for security - * reasons and compatibility with the original behavior. - */ - if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { - if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { - struct mbuf *n; - n = m_copym(m, 0, M_COPYALL, M_NOWAIT); - (void) if_simloop(ifp, n, dst->sa_family, - FDDI_HDR_LEN); - } else if (bcmp(fh->fddi_dhost, fh->fddi_shost, - FDDI_ADDR_LEN) == 0) { - (void) if_simloop(ifp, m, dst->sa_family, - FDDI_HDR_LEN); - return (0); /* XXX */ - } - } - - error = (ifp->if_transmit)(ifp, m); - if (error) - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - - return (error); - -bad: - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - if (m) - m_freem(m); - return (error); -} - -/* - * Process a received FDDI packet. - */ -static void -fddi_input(ifp, m) - struct ifnet *ifp; - struct mbuf *m; -{ - int isr; - struct llc *l; - struct fddi_header *fh; - - /* - * Do consistency checks to verify assumptions - * made by code past this point. - */ - if ((m->m_flags & M_PKTHDR) == 0) { - if_printf(ifp, "discard frame w/o packet header\n"); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - m_freem(m); - return; - } - if (m->m_pkthdr.rcvif == NULL) { - if_printf(ifp, "discard frame w/o interface pointer\n"); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - m_freem(m); - return; - } - - m = m_pullup(m, FDDI_HDR_LEN); - if (m == NULL) { - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - goto dropanyway; - } - fh = mtod(m, struct fddi_header *); - - /* - * Discard packet if interface is not up. - */ - if (!((ifp->if_flags & IFF_UP) && - (ifp->if_drv_flags & IFF_DRV_RUNNING))) - goto dropanyway; - - /* - * Give bpf a chance at the packet. - */ - BPF_MTAP(ifp, m); - - /* - * Interface marked for monitoring; discard packet. - */ - if (ifp->if_flags & IFF_MONITOR) { - m_freem(m); - return; - } - -#ifdef MAC - mac_ifnet_create_mbuf(ifp, m); -#endif - - /* - * Update interface statistics. - */ - if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); - getmicrotime(&ifp->if_lastchange); - - /* - * Discard non local unicast packets when interface - * is in promiscuous mode. - */ - if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) && - (bcmp(IF_LLADDR(ifp), (caddr_t)fh->fddi_dhost, - FDDI_ADDR_LEN) != 0)) - goto dropanyway; - - /* - * Set mbuf flags for bcast/mcast. - */ - if (fh->fddi_dhost[0] & 1) { - if (bcmp(ifp->if_broadcastaddr, fh->fddi_dhost, - FDDI_ADDR_LEN) == 0) - m->m_flags |= M_BCAST; - else - m->m_flags |= M_MCAST; - if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1); - } - -#ifdef M_LINK0 - /* - * If this has a LLC priority of 0, then mark it so upper - * layers have a hint that it really came via a FDDI/Ethernet - * bridge. - */ - if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) - m->m_flags |= M_LINK0; -#endif - - /* Strip off FDDI header. */ - m_adj(m, FDDI_HDR_LEN); - - m = m_pullup(m, LLC_SNAPFRAMELEN); - if (m == NULL) { - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); - goto dropanyway; - } - l = mtod(m, struct llc *); - - switch (l->llc_dsap) { - case LLC_SNAP_LSAP: - { - u_int16_t type; - if ((l->llc_control != LLC_UI) || - (l->llc_ssap != LLC_SNAP_LSAP)) { - if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); - goto dropanyway; - } - if (l->llc_snap.org_code[0] != 0 || - l->llc_snap.org_code[1] != 0 || - l->llc_snap.org_code[2] != 0) { - if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); - goto dropanyway; - } - - type = ntohs(l->llc_snap.ether_type); - m_adj(m, LLC_SNAPFRAMELEN); - - switch (type) { -#ifdef INET - case ETHERTYPE_IP: - isr = NETISR_IP; - break; - - case ETHERTYPE_ARP: - if (ifp->if_flags & IFF_NOARP) - goto dropanyway; - isr = NETISR_ARP; - break; -#endif -#ifdef INET6 - case ETHERTYPE_IPV6: - isr = NETISR_IPV6; - break; -#endif -#ifdef DECNET - case ETHERTYPE_DECNET: - isr = NETISR_DECNET; - break; -#endif - default: - /* printf("fddi_input: unknown protocol 0x%x\n", type); */ - if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); - goto dropanyway; - } - break; - } - - default: - /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ - if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1); - goto dropanyway; - } - M_SETFIB(m, ifp->if_fib); - netisr_dispatch(isr, m); - return; - -dropanyway: - if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); - if (m) - m_freem(m); - return; -} - -/* - * Perform common duties while attaching to interface list - */ -void -fddi_ifattach(ifp, lla, bpf) - struct ifnet *ifp; - const u_int8_t *lla; - int bpf; -{ - struct ifaddr *ifa; - struct sockaddr_dl *sdl; - - ifp->if_type = IFT_FDDI; - ifp->if_addrlen = FDDI_ADDR_LEN; - ifp->if_hdrlen = 21; - - if_attach(ifp); /* Must be called before additional assignments */ - - ifp->if_mtu = FDDIMTU; - ifp->if_output = fddi_output; - ifp->if_input = fddi_input; - ifp->if_resolvemulti = fddi_resolvemulti; - ifp->if_broadcastaddr = fddibroadcastaddr; - ifp->if_baudrate = 100000000; -#ifdef IFF_NOTRAILERS - ifp->if_flags |= IFF_NOTRAILERS; -#endif - ifa = ifp->if_addr; - KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); - - sdl = (struct sockaddr_dl *)ifa->ifa_addr; - sdl->sdl_type = IFT_FDDI; - sdl->sdl_alen = ifp->if_addrlen; - bcopy(lla, LLADDR(sdl), ifp->if_addrlen); - - if (bpf) - bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN); - - return; -} - -void -fddi_ifdetach(ifp, bpf) - struct ifnet *ifp; - int bpf; -{ - - if (bpf) - bpfdetach(ifp); - - if_detach(ifp); - - return; -} - -int -fddi_ioctl (ifp, command, data) - struct ifnet *ifp; - u_long command; - caddr_t data; -{ - struct ifaddr *ifa; - struct ifreq *ifr; - int error; - - ifa = (struct ifaddr *) data; - ifr = (struct ifreq *) data; - error = 0; - - switch (command) { - case SIOCSIFADDR: - ifp->if_flags |= IFF_UP; - - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: /* before arpwhohas */ - ifp->if_init(ifp->if_softc); - arp_ifinit(ifp, ifa); - break; -#endif - default: - ifp->if_init(ifp->if_softc); - break; - } - break; - case SIOCGIFADDR: - bcopy(IF_LLADDR(ifp), &ifr->ifr_addr.sa_data[0], - FDDI_ADDR_LEN); - break; - case SIOCSIFMTU: - /* - * Set the interface MTU. - */ - if (ifr->ifr_mtu > FDDIMTU) { - error = EINVAL; - } else { - ifp->if_mtu = ifr->ifr_mtu; - } - break; - default: - error = EINVAL; - break; - } - - return (error); -} - -static int -fddi_resolvemulti(ifp, llsa, sa) - struct ifnet *ifp; - struct sockaddr **llsa; - struct sockaddr *sa; -{ - struct sockaddr_dl *sdl; -#ifdef INET - struct sockaddr_in *sin; -#endif -#ifdef INET6 - struct sockaddr_in6 *sin6; -#endif - u_char *e_addr; - - switch(sa->sa_family) { - case AF_LINK: - /* - * No mapping needed. Just check that it's a valid MC address. - */ - sdl = (struct sockaddr_dl *)sa; - e_addr = LLADDR(sdl); - if ((e_addr[0] & 1) != 1) - return (EADDRNOTAVAIL); - *llsa = NULL; - return (0); - -#ifdef INET - case AF_INET: - sin = (struct sockaddr_in *)sa; - if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) - return (EADDRNOTAVAIL); - sdl = link_init_sdl(ifp, *llsa, IFT_FDDI); - sdl->sdl_nlen = 0; - sdl->sdl_alen = FDDI_ADDR_LEN; - sdl->sdl_slen = 0; - e_addr = LLADDR(sdl); - ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); - *llsa = (struct sockaddr *)sdl; - return (0); -#endif -#ifdef INET6 - case AF_INET6: - sin6 = (struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* - * An IP6 address of 0 means listen to all - * of the Ethernet multicast address used for IP6. - * (This is used for multicast routers.) - */ - ifp->if_flags |= IFF_ALLMULTI; - *llsa = NULL; - return (0); - } - if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) - return (EADDRNOTAVAIL); - sdl = link_init_sdl(ifp, *llsa, IFT_FDDI); - sdl->sdl_nlen = 0; - sdl->sdl_alen = FDDI_ADDR_LEN; - sdl->sdl_slen = 0; - e_addr = LLADDR(sdl); - ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); - *llsa = (struct sockaddr *)sdl; - return (0); -#endif - - default: - /* - * Well, the text isn't quite right, but it's the name - * that counts... - */ - return (EAFNOSUPPORT); - } - - return (0); -} - -static moduledata_t fddi_mod = { - "fddi", /* module name */ - NULL, /* event handler */ - 0 /* extra data */ -}; - -DECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); -MODULE_VERSION(fddi, 1); diff --git a/freebsd/sys/net/if_ipsec.c b/freebsd/sys/net/if_ipsec.c index 91afe2ab..eaeecd5a 100644 --- a/freebsd/sys/net/if_ipsec.c +++ b/freebsd/sys/net/if_ipsec.c @@ -440,7 +440,7 @@ ipsec_if_input(struct mbuf *m, struct secasvar *sav, uint32_t af) m->m_pkthdr.rcvif = ifp; IPSEC_SC_RUNLOCK(); - /* m_clrprotoflags(m); */ + m_clrprotoflags(m); M_SETFIB(m, ifp->if_fib); BPF_MTAP2(ifp, &af, sizeof(af), m); if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); diff --git a/freebsd/sys/net/if_lagg.c b/freebsd/sys/net/if_lagg.c index 36c8095a..578078c2 100644 --- a/freebsd/sys/net/if_lagg.c +++ b/freebsd/sys/net/if_lagg.c @@ -75,6 +75,18 @@ __FBSDID("$FreeBSD$"); #include <net/if_lagg.h> #include <net/ieee8023ad_lacp.h> +#define LAGG_RLOCK() epoch_enter_preempt(net_epoch_preempt) +#define LAGG_RUNLOCK() epoch_exit_preempt(net_epoch_preempt) +#define LAGG_RLOCK_ASSERT() MPASS(in_epoch()) +#define LAGG_UNLOCK_ASSERT() MPASS(!in_epoch()) + +#define LAGG_SX_INIT(_sc) sx_init(&(_sc)->sc_sx, "if_lagg sx") +#define LAGG_SX_DESTROY(_sc) sx_destroy(&(_sc)->sc_sx) +#define LAGG_XLOCK(_sc) sx_xlock(&(_sc)->sc_sx) +#define LAGG_XUNLOCK(_sc) sx_xunlock(&(_sc)->sc_sx) +#define LAGG_SXLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_LOCKED) +#define LAGG_XLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_XLOCKED) + /* Special flags we should propagate to the lagg ports. */ static struct { int flag; @@ -336,14 +348,11 @@ lagg_proto_detach(struct lagg_softc *sc) lagg_proto pr; LAGG_XLOCK_ASSERT(sc); - LAGG_WLOCK_ASSERT(sc); pr = sc->sc_proto; sc->sc_proto = LAGG_PROTO_NONE; if (lagg_protos[pr].pr_detach != NULL) lagg_protos[pr].pr_detach(sc); - else - LAGG_WUNLOCK(sc); } static int @@ -439,10 +448,10 @@ lagg_register_vlan(void *arg, struct ifnet *ifp, u_int16_t vtag) if (ifp->if_softc != arg) /* Not our event */ return; - LAGG_SLOCK(sc); - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + LAGG_RLOCK(); + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) EVENTHANDLER_INVOKE(vlan_config, lp->lp_ifp, vtag); - LAGG_SUNLOCK(sc); + LAGG_RUNLOCK(); } /* @@ -458,10 +467,10 @@ lagg_unregister_vlan(void *arg, struct ifnet *ifp, u_int16_t vtag) if (ifp->if_softc != arg) /* Not our event */ return; - LAGG_SLOCK(sc); - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + LAGG_RLOCK(); + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) EVENTHANDLER_INVOKE(vlan_unconfig, lp->lp_ifp, vtag); - LAGG_SUNLOCK(sc); + LAGG_RUNLOCK(); } static int @@ -477,7 +486,6 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params) free(sc, M_DEVBUF); return (ENOSPC); } - LAGG_LOCK_INIT(sc); LAGG_SX_INIT(sc); LAGG_XLOCK(sc); @@ -490,7 +498,7 @@ lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params) lagg_proto_attach(sc, LAGG_PROTO_DEFAULT); - SLIST_INIT(&sc->sc_ports); + CK_SLIST_INIT(&sc->sc_ports); /* Initialise pseudo media types */ ifmedia_init(&sc->sc_media, 0, lagg_media_change, @@ -548,13 +556,11 @@ lagg_clone_destroy(struct ifnet *ifp) EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); /* Shutdown and remove lagg ports */ - while ((lp = SLIST_FIRST(&sc->sc_ports)) != NULL) + while ((lp = CK_SLIST_FIRST(&sc->sc_ports)) != NULL) lagg_port_destroy(lp, 1); /* Unhook the aggregation protocol */ - LAGG_WLOCK(sc); lagg_proto_detach(sc); - LAGG_UNLOCK_ASSERT(sc); LAGG_XUNLOCK(sc); ifmedia_removeall(&sc->sc_media); @@ -566,7 +572,6 @@ lagg_clone_destroy(struct ifnet *ifp) LAGG_LIST_UNLOCK(); LAGG_SX_DESTROY(sc); - LAGG_LOCK_DESTROY(sc); free(sc, M_DEVBUF); } @@ -582,7 +587,7 @@ lagg_capabilities(struct lagg_softc *sc) /* Get common enabled capabilities for the lagg ports */ ena = ~0; - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) ena &= lp->lp_ifp->if_capenable; ena = (ena == ~0 ? 0 : ena); @@ -592,7 +597,7 @@ lagg_capabilities(struct lagg_softc *sc) */ do { pena = ena; - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { lagg_setcaps(lp, ena); ena &= lp->lp_ifp->if_capenable; } @@ -602,7 +607,7 @@ lagg_capabilities(struct lagg_softc *sc) cap = ~0; hwa = ~(uint64_t)0; memset(&hw_tsomax, 0, sizeof(hw_tsomax)); - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { cap &= lp->lp_ifp->if_capabilities; hwa &= lp->lp_ifp->if_hwassist; if_hw_tsomax_common(lp->lp_ifp, &hw_tsomax); @@ -653,7 +658,7 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) return (EPROTONOSUPPORT); /* Allow the first Ethernet member to define the MTU */ - if (SLIST_EMPTY(&sc->sc_ports)) + if (CK_SLIST_EMPTY(&sc->sc_ports)) sc->sc_ifp->if_mtu = ifp->if_mtu; else if (sc->sc_ifp->if_mtu != ifp->if_mtu) { if_printf(sc->sc_ifp, "invalid MTU for %s\n", @@ -690,19 +695,16 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) bcopy(IF_LLADDR(ifp), lp->lp_lladdr, ETHER_ADDR_LEN); lp->lp_ifcapenable = ifp->if_capenable; - if (SLIST_EMPTY(&sc->sc_ports)) { - LAGG_WLOCK(sc); + if (CK_SLIST_EMPTY(&sc->sc_ports)) { bcopy(IF_LLADDR(ifp), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); lagg_proto_lladdr(sc); - LAGG_WUNLOCK(sc); EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); } else { if_setlladdr(ifp, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); } lagg_setflags(lp, 1); - LAGG_WLOCK(sc); - if (SLIST_EMPTY(&sc->sc_ports)) + if (CK_SLIST_EMPTY(&sc->sc_ports)) sc->sc_primary = lp; /* Change the interface type */ @@ -725,28 +727,27 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp) * is predictable and `ifconfig laggN create ...` command * will lead to the same result each time. */ - SLIST_FOREACH(tlp, &sc->sc_ports, lp_entries) { + LAGG_RLOCK(); + CK_SLIST_FOREACH(tlp, &sc->sc_ports, lp_entries) { if (tlp->lp_ifp->if_index < ifp->if_index && ( - SLIST_NEXT(tlp, lp_entries) == NULL || - SLIST_NEXT(tlp, lp_entries)->lp_ifp->if_index > + CK_SLIST_NEXT(tlp, lp_entries) == NULL || + ((struct lagg_port*)CK_SLIST_NEXT(tlp, lp_entries))->lp_ifp->if_index > ifp->if_index)) break; } + LAGG_RUNLOCK(); if (tlp != NULL) - SLIST_INSERT_AFTER(tlp, lp, lp_entries); + CK_SLIST_INSERT_AFTER(tlp, lp, lp_entries); else - SLIST_INSERT_HEAD(&sc->sc_ports, lp, lp_entries); + CK_SLIST_INSERT_HEAD(&sc->sc_ports, lp, lp_entries); sc->sc_count++; lagg_setmulti(lp); - LAGG_WUNLOCK(sc); if ((error = lagg_proto_addport(sc, lp)) != 0) { /* Remove the port, without calling pr_delport. */ - LAGG_WLOCK(sc); lagg_port_destroy(lp, 0); - LAGG_UNLOCK_ASSERT(sc); return (error); } @@ -766,7 +767,7 @@ lagg_port_checkstacking(struct lagg_softc *sc) int m = 0; LAGG_SXLOCK_ASSERT(sc); - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { if (lp->lp_flags & LAGG_PORT_STACK) { sc_ptr = (struct lagg_softc *)lp->lp_ifp->if_softc; m = MAX(m, lagg_port_checkstacking(sc_ptr)); @@ -777,6 +778,19 @@ lagg_port_checkstacking(struct lagg_softc *sc) } #endif +static void +lagg_port_destroy_cb(epoch_context_t ec) +{ + struct lagg_port *lp; + struct ifnet *ifp; + + lp = __containerof(ec, struct lagg_port, lp_epoch_ctx); + ifp = lp->lp_ifp; + + if_rele(ifp); + free(lp, M_DEVBUF); +} + static int lagg_port_destroy(struct lagg_port *lp, int rundelport) { @@ -788,11 +802,8 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport) LAGG_XLOCK_ASSERT(sc); - if (rundelport) { - LAGG_WLOCK(sc); + if (rundelport) lagg_proto_delport(sc, lp); - } else - LAGG_WLOCK_ASSERT(sc); if (lp->lp_detaching == 0) lagg_clrmulti(lp); @@ -811,14 +822,14 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport) } /* Finally, remove the port from the lagg */ - SLIST_REMOVE(&sc->sc_ports, lp, lagg_port, lp_entries); + CK_SLIST_REMOVE(&sc->sc_ports, lp, lagg_port, lp_entries); sc->sc_count--; /* Update the primary interface */ if (lp == sc->sc_primary) { uint8_t lladdr[ETHER_ADDR_LEN]; - if ((lp0 = SLIST_FIRST(&sc->sc_ports)) == NULL) + if ((lp0 = CK_SLIST_FIRST(&sc->sc_ports)) == NULL) bzero(&lladdr, ETHER_ADDR_LEN); else bcopy(lp0->lp_lladdr, lladdr, ETHER_ADDR_LEN); @@ -826,19 +837,16 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport) if (sc->sc_destroying == 0) { bcopy(lladdr, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); lagg_proto_lladdr(sc); - LAGG_WUNLOCK(sc); EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); - } else - LAGG_WUNLOCK(sc); + } /* * Update lladdr for each port (new primary needs update * as well, to switch from old lladdr to its 'real' one) */ - SLIST_FOREACH(lp_ptr, &sc->sc_ports, lp_entries) + CK_SLIST_FOREACH(lp_ptr, &sc->sc_ports, lp_entries) if_setlladdr(lp_ptr->lp_ifp, lladdr, ETHER_ADDR_LEN); - } else - LAGG_WUNLOCK(sc); + } if (lp->lp_ifflags) if_printf(ifp, "%s: lp_ifflags unclean\n", __func__); @@ -849,9 +857,11 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport) if_setlladdr(ifp, lp->lp_lladdr, ETHER_ADDR_LEN); } - if_rele(ifp); - free(lp, M_DEVBUF); - + /* + * free port and release it's ifnet reference after a grace period has + * elapsed. + */ + epoch_call(net_epoch_preempt, &lp->lp_epoch_ctx, lagg_port_destroy_cb); /* Update lagg capabilities */ lagg_capabilities(sc); lagg_linkstate(sc); @@ -880,15 +890,15 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } - LAGG_SLOCK(sc); + LAGG_RLOCK(); if ((lp = ifp->if_lagg) == NULL || lp->lp_softc != sc) { error = ENOENT; - LAGG_SUNLOCK(sc); + LAGG_RUNLOCK(); break; } lagg_port2req(lp, rp); - LAGG_SUNLOCK(sc); + LAGG_RUNLOCK(); break; case SIOCSIFCAP: @@ -944,17 +954,16 @@ lagg_get_counter(struct ifnet *ifp, ift_counter cnt) struct lagg_softc *sc; struct lagg_port *lp; struct ifnet *lpifp; - struct rm_priotracker tracker; uint64_t newval, oldval, vsum; /* Revise this when we've got non-generic counters. */ KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt)); sc = (struct lagg_softc *)ifp->if_softc; - LAGG_RLOCK(sc, &tracker); vsum = 0; - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + LAGG_RLOCK(); + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { /* Saved attached value */ oldval = lp->port_counters.val[cnt]; /* current value */ @@ -963,6 +972,7 @@ lagg_get_counter(struct ifnet *ifp, ift_counter cnt) /* Calculate diff and save new */ vsum += newval - oldval; } + LAGG_RUNLOCK(); /* * Add counter data which might be added by upper @@ -975,7 +985,6 @@ lagg_get_counter(struct ifnet *ifp, ift_counter cnt) */ vsum += sc->detached_counters.val[cnt]; - LAGG_RUNLOCK(sc, &tracker); return (vsum); } @@ -1081,7 +1090,7 @@ lagg_init(void *xsc) * This might be if_setlladdr() notification * that lladdr has been changed. */ - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { if (memcmp(IF_LLADDR(ifp), IF_LLADDR(lp->lp_ifp), ETHER_ADDR_LEN) != 0) if_setlladdr(lp->lp_ifp, IF_LLADDR(ifp), ETHER_ADDR_LEN); @@ -1126,7 +1135,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) switch (cmd) { case SIOCGLAGG: - LAGG_SLOCK(sc); + LAGG_XLOCK(sc); buflen = sc->sc_count * sizeof(struct lagg_reqport); outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); ra->ra_proto = sc->sc_proto; @@ -1134,7 +1143,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) count = 0; buf = outbuf; len = min(ra->ra_size, buflen); - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { if (len < sizeof(rpbuf)) break; @@ -1144,7 +1153,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) buf += sizeof(rpbuf); len -= sizeof(rpbuf); } - LAGG_SUNLOCK(sc); + LAGG_XUNLOCK(sc); ra->ra_ports = count; ra->ra_size = count * sizeof(rpbuf); error = copyout(outbuf, ra->ra_port, ra->ra_size); @@ -1160,14 +1169,13 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } LAGG_XLOCK(sc); - LAGG_WLOCK(sc); lagg_proto_detach(sc); - LAGG_UNLOCK_ASSERT(sc); + LAGG_UNLOCK_ASSERT(); lagg_proto_attach(sc, ra->ra_proto); LAGG_XUNLOCK(sc); break; case SIOCGLAGGOPTS: - LAGG_SLOCK(sc); + LAGG_XLOCK(sc); ro->ro_opts = sc->sc_opts; if (sc->sc_proto == LAGG_PROTO_LACP) { struct lacp_softc *lsc; @@ -1185,13 +1193,13 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) ro->ro_active = sc->sc_active; } else { ro->ro_active = 0; - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) ro->ro_active += LAGG_PORTACTIVE(lp); } ro->ro_bkt = sc->sc_bkt; ro->ro_flapping = sc->sc_flapping; ro->ro_flowid_shift = sc->flowid_shift; - LAGG_SUNLOCK(sc); + LAGG_XUNLOCK(sc); break; case SIOCSLAGGOPTS: if (sc->sc_proto == LAGG_PROTO_ROUNDROBIN) { @@ -1298,14 +1306,14 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; case SIOCGLAGGFLAGS: rf->rf_flags = 0; - LAGG_SLOCK(sc); + LAGG_XLOCK(sc); if (sc->sc_flags & MBUF_HASHFLAG_L2) rf->rf_flags |= LAGG_F_HASHL2; if (sc->sc_flags & MBUF_HASHFLAG_L3) rf->rf_flags |= LAGG_F_HASHL3; if (sc->sc_flags & MBUF_HASHFLAG_L4) rf->rf_flags |= LAGG_F_HASHL4; - LAGG_SUNLOCK(sc); + LAGG_XUNLOCK(sc); break; case SIOCSLAGGHASH: error = priv_check(td, PRIV_NET_LAGG); @@ -1332,17 +1340,17 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } - LAGG_SLOCK(sc); + LAGG_RLOCK(); if ((lp = (struct lagg_port *)tpif->if_lagg) == NULL || lp->lp_softc != sc) { error = ENOENT; - LAGG_SUNLOCK(sc); + LAGG_RUNLOCK(); if_rele(tpif); break; } lagg_port2req(lp, rp); - LAGG_SUNLOCK(sc); + LAGG_RUNLOCK(); if_rele(tpif); break; case SIOCSLAGGPORT: @@ -1407,7 +1415,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCSIFFLAGS: /* Set flags on ports too */ LAGG_XLOCK(sc); - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { lagg_setflags(lp, 1); } @@ -1432,12 +1440,12 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; case SIOCADDMULTI: case SIOCDELMULTI: - LAGG_WLOCK(sc); - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + LAGG_XLOCK(sc); + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { lagg_clrmulti(lp); lagg_setmulti(lp); } - LAGG_WUNLOCK(sc); + LAGG_XUNLOCK(sc); error = 0; break; case SIOCSIFMEDIA: @@ -1447,7 +1455,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCSIFCAP: LAGG_XLOCK(sc); - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { if (lp->lp_ioctl != NULL) (*lp->lp_ioctl)(lp->lp_ifp, cmd, data); } @@ -1525,9 +1533,8 @@ lagg_setmulti(struct lagg_port *lp) struct ifmultiaddr *ifma; int error; - LAGG_WLOCK_ASSERT(sc); IF_ADDR_WLOCK(scifp); - TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; mc = malloc(sizeof(struct lagg_mc), M_DEVBUF, M_NOWAIT); @@ -1556,7 +1563,7 @@ lagg_clrmulti(struct lagg_port *lp) { struct lagg_mc *mc; - LAGG_WLOCK_ASSERT(lp->lp_softc); + LAGG_XLOCK_ASSERT(lp->lp_softc); while ((mc = SLIST_FIRST(&lp->lp_mc_head)) != NULL) { SLIST_REMOVE(&lp->lp_mc_head, mc, lagg_mc, mc_entries); if (mc->mc_ifma && lp->lp_detaching == 0) @@ -1636,16 +1643,12 @@ static int lagg_transmit(struct ifnet *ifp, struct mbuf *m) { struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc; - int error, len, mcast; - struct rm_priotracker tracker; - - len = m->m_pkthdr.len; - mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1 : 0; + int error; - LAGG_RLOCK(sc, &tracker); + LAGG_RLOCK(); /* We need a Tx algorithm and at least one port */ if (sc->sc_proto == LAGG_PROTO_NONE || sc->sc_count == 0) { - LAGG_RUNLOCK(sc, &tracker); + LAGG_RUNLOCK(); m_freem(m); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); return (ENXIO); @@ -1654,7 +1657,7 @@ lagg_transmit(struct ifnet *ifp, struct mbuf *m) ETHER_BPF_MTAP(ifp, m); error = lagg_proto_start(sc, m); - LAGG_RUNLOCK(sc, &tracker); + LAGG_RUNLOCK(); if (error != 0) if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); @@ -1676,33 +1679,25 @@ lagg_input(struct ifnet *ifp, struct mbuf *m) struct lagg_port *lp = ifp->if_lagg; struct lagg_softc *sc = lp->lp_softc; struct ifnet *scifp = sc->sc_ifp; - struct rm_priotracker tracker; - LAGG_RLOCK(sc, &tracker); + LAGG_RLOCK(); if ((scifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || - (lp->lp_flags & LAGG_PORT_DISABLED) || + lp->lp_detaching != 0 || sc->sc_proto == LAGG_PROTO_NONE) { - LAGG_RUNLOCK(sc, &tracker); + LAGG_RUNLOCK(); m_freem(m); return (NULL); } ETHER_BPF_MTAP(scifp, m); - if (lp->lp_detaching != 0) { + m = lagg_proto_input(sc, lp, m); + if (m != NULL && (scifp->if_flags & IFF_MONITOR) != 0) { m_freem(m); m = NULL; - } else - m = lagg_proto_input(sc, lp, m); - - if (m != NULL) { - if (scifp->if_flags & IFF_MONITOR) { - m_freem(m); - m = NULL; - } } - LAGG_RUNLOCK(sc, &tracker); + LAGG_RUNLOCK(); return (m); } @@ -1727,12 +1722,12 @@ lagg_media_status(struct ifnet *ifp, struct ifmediareq *imr) imr->ifm_status = IFM_AVALID; imr->ifm_active = IFM_ETHER | IFM_AUTO; - LAGG_SLOCK(sc); - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + LAGG_RLOCK(); + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { if (LAGG_PORTACTIVE(lp)) imr->ifm_status |= IFM_ACTIVE; } - LAGG_SUNLOCK(sc); + LAGG_RUNLOCK(); } static void @@ -1745,12 +1740,14 @@ lagg_linkstate(struct lagg_softc *sc) LAGG_XLOCK_ASSERT(sc); /* Our link is considered up if at least one of our ports is active */ - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + LAGG_RLOCK(); + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { if (lp->lp_ifp->if_link_state == LINK_STATE_UP) { new_link = LINK_STATE_UP; break; } } + LAGG_RUNLOCK(); if_link_state_change(sc->sc_ifp, new_link); /* Update if_baudrate to reflect the max possible speed */ @@ -1763,8 +1760,10 @@ lagg_linkstate(struct lagg_softc *sc) case LAGG_PROTO_LOADBALANCE: case LAGG_PROTO_BROADCAST: speed = 0; - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + LAGG_RLOCK(); + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) speed += lp->lp_ifp->if_baudrate; + LAGG_RUNLOCK(); sc->sc_ifp->if_baudrate = speed; break; case LAGG_PROTO_LACP: @@ -1805,20 +1804,22 @@ lagg_link_active(struct lagg_softc *sc, struct lagg_port *lp) rval = lp; goto found; } - if ((lp_next = SLIST_NEXT(lp, lp_entries)) != NULL && + if ((lp_next = CK_SLIST_NEXT(lp, lp_entries)) != NULL && LAGG_PORTACTIVE(lp_next)) { rval = lp_next; goto found; } -search: - SLIST_FOREACH(lp_next, &sc->sc_ports, lp_entries) { + search: + LAGG_RLOCK(); + CK_SLIST_FOREACH(lp_next, &sc->sc_ports, lp_entries) { if (LAGG_PORTACTIVE(lp_next)) { + LAGG_RUNLOCK(); rval = lp_next; goto found; } } - + LAGG_RUNLOCK(); found: return (rval); } @@ -1859,10 +1860,10 @@ lagg_rr_start(struct lagg_softc *sc, struct mbuf *m) p = atomic_fetchadd_32(&sc->sc_seq, 1); p %= sc->sc_count; - lp = SLIST_FIRST(&sc->sc_ports); + lp = CK_SLIST_FIRST(&sc->sc_ports); while (p--) - lp = SLIST_NEXT(lp, lp_entries); + lp = CK_SLIST_NEXT(lp, lp_entries); /* * Check the port's link state. This will return the next active @@ -1900,7 +1901,8 @@ lagg_bcast_start(struct lagg_softc *sc, struct mbuf *m) struct lagg_port *lp, *last = NULL; struct mbuf *m0; - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { + LAGG_RLOCK(); + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { if (!LAGG_PORTACTIVE(lp)) continue; @@ -1920,6 +1922,8 @@ lagg_bcast_start(struct lagg_softc *sc, struct mbuf *m) } last = lp; } + LAGG_RUNLOCK(); + if (last == NULL) { m_freem(m); return (ENOENT); @@ -2003,11 +2007,12 @@ lagg_lb_attach(struct lagg_softc *sc) struct lagg_port *lp; struct lagg_lb *lb; + LAGG_XLOCK_ASSERT(sc); lb = malloc(sizeof(struct lagg_lb), M_DEVBUF, M_WAITOK | M_ZERO); lb->lb_key = m_ether_tcpip_hash_init(); sc->sc_psc = lb; - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) lagg_lb_port_create(lp); } @@ -2017,7 +2022,6 @@ lagg_lb_detach(struct lagg_softc *sc) struct lagg_lb *lb; lb = (struct lagg_lb *)sc->sc_psc; - LAGG_WUNLOCK(sc); if (lb != NULL) free(lb, M_DEVBUF); } @@ -2030,7 +2034,8 @@ lagg_lb_porttable(struct lagg_softc *sc, struct lagg_port *lp) int i = 0; bzero(&lb->lb_ports, sizeof(lb->lb_ports)); - SLIST_FOREACH(lp_next, &sc->sc_ports, lp_entries) { + LAGG_RLOCK(); + CK_SLIST_FOREACH(lp_next, &sc->sc_ports, lp_entries) { if (lp_next == lp) continue; if (i >= LAGG_MAX_PORTS) @@ -2040,6 +2045,7 @@ lagg_lb_porttable(struct lagg_softc *sc, struct lagg_port *lp) sc->sc_ifname, lp_next->lp_ifp->if_xname, i); lb->lb_ports[i++] = lp_next; } + LAGG_RUNLOCK(); return (0); } @@ -2106,7 +2112,8 @@ lagg_lacp_attach(struct lagg_softc *sc) struct lagg_port *lp; lacp_attach(sc); - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + LAGG_XLOCK_ASSERT(sc); + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) lacp_port_create(lp); } @@ -2116,13 +2123,12 @@ lagg_lacp_detach(struct lagg_softc *sc) struct lagg_port *lp; void *psc; - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + LAGG_XLOCK_ASSERT(sc); + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) lacp_port_destroy(lp); psc = sc->sc_psc; sc->sc_psc = NULL; - LAGG_WUNLOCK(sc); - lacp_detach(psc); } @@ -2134,11 +2140,11 @@ lagg_lacp_lladdr(struct lagg_softc *sc) LAGG_SXLOCK_ASSERT(sc); /* purge all the lacp ports */ - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) lacp_port_destroy(lp); /* add them back in */ - SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) + CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) lacp_port_create(lp); } diff --git a/freebsd/sys/net/if_lagg.h b/freebsd/sys/net/if_lagg.h index 201d909a..f1e2d8f4 100644 --- a/freebsd/sys/net/if_lagg.h +++ b/freebsd/sys/net/if_lagg.h @@ -42,9 +42,8 @@ #define LAGG_PORT_ACTIVE 0x00000004 /* port is active */ #define LAGG_PORT_COLLECTING 0x00000008 /* port is receiving frames */ #define LAGG_PORT_DISTRIBUTING 0x00000010 /* port is sending frames */ -#define LAGG_PORT_DISABLED 0x00000020 /* port is disabled */ #define LAGG_PORT_BITS "\20\01MASTER\02STACK\03ACTIVE\04COLLECTING" \ - "\05DISTRIBUTING\06DISABLED" + "\05DISTRIBUTING" /* Supported lagg PROTOs */ typedef enum { @@ -218,7 +217,7 @@ struct lagg_softc { uint32_t sc_flags; int sc_destroying; /* destroying lagg */ - SLIST_HEAD(__tplhd, lagg_port) sc_ports; /* list of interfaces */ + CK_SLIST_HEAD(__tplhd, lagg_port) sc_ports; /* list of interfaces */ SLIST_ENTRY(lagg_softc) sc_entries; eventhandler_tag vlan_attach; @@ -252,29 +251,10 @@ struct lagg_port { const struct sockaddr *, struct route *); struct lagg_counters port_counters; /* ifp counters copy */ - SLIST_ENTRY(lagg_port) lp_entries; + CK_SLIST_ENTRY(lagg_port) lp_entries; + struct epoch_context lp_epoch_ctx; }; -#define LAGG_LOCK_INIT(_sc) rm_init(&(_sc)->sc_mtx, "if_lagg rmlock") -#define LAGG_LOCK_DESTROY(_sc) rm_destroy(&(_sc)->sc_mtx) -#define LAGG_RLOCK(_sc, _p) rm_rlock(&(_sc)->sc_mtx, (_p)) -#define LAGG_WLOCK(_sc) rm_wlock(&(_sc)->sc_mtx) -#define LAGG_RUNLOCK(_sc, _p) rm_runlock(&(_sc)->sc_mtx, (_p)) -#define LAGG_WUNLOCK(_sc) rm_wunlock(&(_sc)->sc_mtx) -#define LAGG_RLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_RLOCKED) -#define LAGG_WLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_WLOCKED) -#define LAGG_UNLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_UNLOCKED) - -#define LAGG_SX_INIT(_sc) sx_init(&(_sc)->sc_sx, "if_lagg sx") -#define LAGG_SX_DESTROY(_sc) sx_destroy(&(_sc)->sc_sx) -#define LAGG_SLOCK(_sc) sx_slock(&(_sc)->sc_sx) -#define LAGG_XLOCK(_sc) sx_xlock(&(_sc)->sc_sx) -#define LAGG_SUNLOCK(_sc) sx_sunlock(&(_sc)->sc_sx) -#define LAGG_XUNLOCK(_sc) sx_xunlock(&(_sc)->sc_sx) -#define LAGG_SXLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_LOCKED) -#define LAGG_SLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_SLOCKED) -#define LAGG_XLOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_sx, SA_XLOCKED) - extern struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *); extern void (*lagg_linkstate_p)(struct ifnet *, int ); diff --git a/freebsd/sys/net/if_llatbl.c b/freebsd/sys/net/if_llatbl.c index d98153b9..d6e9dbaf 100644 --- a/freebsd/sys/net/if_llatbl.c +++ b/freebsd/sys/net/if_llatbl.c @@ -148,7 +148,7 @@ htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg) error = 0; for (i = 0; i < llt->llt_hsize; i++) { - LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { + CK_LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { error = f(llt, lle, farg); if (error != 0) break; @@ -175,7 +175,7 @@ htable_link_entry(struct lltable *llt, struct llentry *lle) lle->lle_tbl = llt; lle->lle_head = lleh; lle->la_flags |= LLE_LINKED; - LIST_INSERT_HEAD(lleh, lle, lle_next); + CK_LIST_INSERT_HEAD(lleh, lle, lle_next); } static void @@ -184,7 +184,7 @@ htable_unlink_entry(struct llentry *lle) if ((lle->la_flags & LLE_LINKED) != 0) { IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp); - LIST_REMOVE(lle, lle_next); + CK_LIST_REMOVE(lle, lle_next); lle->la_flags &= ~(LLE_VALID | LLE_LINKED); #if 0 lle->lle_tbl = NULL; @@ -209,7 +209,7 @@ htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg) if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) { LLE_WLOCK(lle); - LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain); + CK_LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain); } return (0); @@ -226,7 +226,7 @@ htable_prefix_free(struct lltable *llt, const struct sockaddr *addr, pmd.addr = addr; pmd.mask = mask; pmd.flags = flags; - LIST_INIT(&pmd.dchain); + CK_LIST_INIT(&pmd.dchain); IF_AFDATA_WLOCK(llt->llt_ifp); /* Push matching lles to chain */ @@ -235,7 +235,7 @@ htable_prefix_free(struct lltable *llt, const struct sockaddr *addr, llentries_unlink(llt, &pmd.dchain); IF_AFDATA_WUNLOCK(llt->llt_ifp); - LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next) + CK_LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next) lltable_free_entry(llt, lle); } @@ -252,7 +252,7 @@ llentries_unlink(struct lltable *llt, struct llentries *head) { struct llentry *lle, *next; - LIST_FOREACH_SAFE(lle, head, lle_chain, next) + CK_LIST_FOREACH_SAFE(lle, head, lle_chain, next) llt->llt_unlink_entry(lle); } @@ -498,7 +498,7 @@ lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg) dchain = (struct llentries *)farg; LLE_WLOCK(lle); - LIST_INSERT_HEAD(dchain, lle, lle_chain); + CK_LIST_INSERT_HEAD(dchain, lle, lle_chain); return (0); } @@ -516,14 +516,14 @@ lltable_free(struct lltable *llt) lltable_unlink(llt); - LIST_INIT(&dchain); + CK_LIST_INIT(&dchain); IF_AFDATA_WLOCK(llt->llt_ifp); /* Push all lles to @dchain */ lltable_foreach_lle(llt, lltable_free_cb, &dchain); llentries_unlink(llt, &dchain); IF_AFDATA_WUNLOCK(llt->llt_ifp); - LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) { + CK_LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) { if (callout_stop(&lle->lle_timer) > 0) LLE_REMREF(lle); llentry_free(lle); @@ -546,7 +546,7 @@ lltable_drain(int af) continue; for (i=0; i < llt->llt_hsize; i++) { - LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { + CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { LLE_WLOCK(lle); if (lle->la_hold) { m_freem(lle->la_hold); @@ -622,7 +622,7 @@ lltable_allocate_htbl(uint32_t hsize) M_LLTABLE, M_WAITOK | M_ZERO); for (i = 0; i < llt->llt_hsize; i++) - LIST_INIT(&llt->lle_head[i]); + CK_LIST_INIT(&llt->lle_head[i]); /* Set some default callbacks */ llt->llt_link_entry = htable_link_entry; @@ -848,7 +848,7 @@ llatbl_lle_show(struct llentry_sa *la) lle = &la->base; db_printf("lle=%p\n", lle); - db_printf(" lle_next=%p\n", lle->lle_next.le_next); + db_printf(" lle_next=%p\n", lle->lle_next.cle_next); db_printf(" lle_lock=%p\n", &lle->lle_lock); db_printf(" lle_tbl=%p\n", lle->lle_tbl); db_printf(" lle_head=%p\n", lle->lle_head); @@ -919,7 +919,7 @@ llatbl_llt_show(struct lltable *llt) llt, llt->llt_af, llt->llt_ifp); for (i = 0; i < llt->llt_hsize; i++) { - LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { + CK_LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { llatbl_lle_show((struct llentry_sa *)lle); if (db_pager_quit) diff --git a/freebsd/sys/net/if_llatbl.h b/freebsd/sys/net/if_llatbl.h index 9cec4ac7..74301284 100644 --- a/freebsd/sys/net/if_llatbl.h +++ b/freebsd/sys/net/if_llatbl.h @@ -34,13 +34,15 @@ __FBSDID("$FreeBSD$"); #include <sys/_rwlock.h> #include <netinet/in.h> +#include <sys/epoch.h> +#include <sys/ck.h> struct ifnet; struct sysctl_req; struct rt_msghdr; struct rt_addrinfo; struct llentry; -LIST_HEAD(llentries, llentry); +CK_LIST_HEAD(llentries, llentry); #define LLE_MAX_LINKHDR 24 /* Full IB header */ /* @@ -48,7 +50,7 @@ LIST_HEAD(llentries, llentry); * a shared lock */ struct llentry { - LIST_ENTRY(llentry) lle_next; + CK_LIST_ENTRY(llentry) lle_next; union { struct in_addr addr4; struct in6_addr addr6; @@ -76,10 +78,11 @@ struct llentry { int lle_refcnt; char *ll_addr; /* link-layer address */ - LIST_ENTRY(llentry) lle_chain; /* chain of deleted items */ + CK_LIST_ENTRY(llentry) lle_chain; /* chain of deleted items */ struct callout lle_timer; struct rwlock lle_lock; struct mtx req_mtx; + struct epoch_context lle_epoch_ctx; }; #define LLE_WLOCK(lle) rw_wlock(&(lle)->lle_lock) diff --git a/freebsd/sys/net/if_loop.c b/freebsd/sys/net/if_loop.c index bae46891..988b9f9d 100644 --- a/freebsd/sys/net/if_loop.c +++ b/freebsd/sys/net/if_loop.c @@ -138,7 +138,7 @@ lo_clone_create(struct if_clone *ifc, int unit, caddr_t params) ifp->if_output = looutput; ifp->if_snd.ifq_maxlen = ifqmaxlen; ifp->if_capabilities = ifp->if_capenable = - IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6; + IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 | IFCAP_LINKSTATE; ifp->if_hwassist = LO_CSUM_FEATURES | LO_CSUM_FEATURES6; if_attach(ifp); bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); @@ -415,6 +415,8 @@ loioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; case SIOCSIFFLAGS: + if_link_state_change(ifp, (ifp->if_flags & IFF_UP) ? + LINK_STATE_UP: LINK_STATE_DOWN); break; case SIOCSIFCAP: diff --git a/freebsd/sys/net/if_media.c b/freebsd/sys/net/if_media.c index cceb0079..867f7fc3 100644 --- a/freebsd/sys/net/if_media.c +++ b/freebsd/sys/net/if_media.c @@ -401,18 +401,6 @@ struct ifmedia_description ifm_subtype_ethernet_descriptions[] = struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; -struct ifmedia_description ifm_subtype_tokenring_descriptions[] = - IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; - -struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = - IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; - -struct ifmedia_description ifm_subtype_fddi_descriptions[] = - IFM_SUBTYPE_FDDI_DESCRIPTIONS; - -struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = - IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS; - struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; @@ -448,16 +436,6 @@ struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { NULL, }, { - &ifm_subtype_tokenring_descriptions[0], - &ifm_subtype_tokenring_option_descriptions[0], - NULL, - }, - { - &ifm_subtype_fddi_descriptions[0], - &ifm_subtype_fddi_option_descriptions[0], - NULL, - }, - { &ifm_subtype_ieee80211_descriptions[0], &ifm_subtype_ieee80211_option_descriptions[0], &ifm_subtype_ieee80211_mode_descriptions[0] diff --git a/freebsd/sys/net/if_media.h b/freebsd/sys/net/if_media.h index ecc2b418..97cd6552 100644 --- a/freebsd/sys/net/if_media.h +++ b/freebsd/sys/net/if_media.h @@ -217,32 +217,6 @@ uint64_t ifmedia_baudrate(int); #define IFM_ETH_XSHIFT 6 /* shift XTYPE next to TMASK */ /* - * Token ring - */ -#define IFM_TOKEN 0x00000040 -#define IFM_TOK_STP4 3 /* Shielded twisted pair 4m - DB9 */ -#define IFM_TOK_STP16 4 /* Shielded twisted pair 16m - DB9 */ -#define IFM_TOK_UTP4 5 /* Unshielded twisted pair 4m - RJ45 */ -#define IFM_TOK_UTP16 6 /* Unshielded twisted pair 16m - RJ45 */ -#define IFM_TOK_STP100 7 /* Shielded twisted pair 100m - DB9 */ -#define IFM_TOK_UTP100 8 /* Unshielded twisted pair 100m - RJ45 */ -#define IFM_TOK_ETR 0x00000200 /* Early token release */ -#define IFM_TOK_SRCRT 0x00000400 /* Enable source routing features */ -#define IFM_TOK_ALLR 0x00000800 /* All routes / Single route bcast */ -#define IFM_TOK_DTR 0x00002000 /* Dedicated token ring */ -#define IFM_TOK_CLASSIC 0x00004000 /* Classic token ring */ -#define IFM_TOK_AUTO 0x00008000 /* Automatic Dedicate/Classic token ring */ - -/* - * FDDI - */ -#define IFM_FDDI 0x00000060 -#define IFM_FDDI_SMF 3 /* Single-mode fiber */ -#define IFM_FDDI_MMF 4 /* Multi-mode fiber */ -#define IFM_FDDI_UTP 5 /* CDDI / UTP */ -#define IFM_FDDI_DA 0x00000100 /* Dual attach / single attach */ - -/* * IEEE 802.11 Wireless */ #define IFM_IEEE80211 0x00000080 @@ -393,8 +367,6 @@ struct ifmedia_description { #define IFM_TYPE_DESCRIPTIONS { \ { IFM_ETHER, "Ethernet" }, \ - { IFM_TOKEN, "Token ring" }, \ - { IFM_FDDI, "FDDI" }, \ { IFM_IEEE80211, "IEEE 802.11 Wireless Ethernet" }, \ { IFM_ATM, "ATM" }, \ { 0, NULL }, \ @@ -511,55 +483,6 @@ struct ifmedia_description { { 0, NULL }, \ } -#define IFM_SUBTYPE_TOKENRING_DESCRIPTIONS { \ - { IFM_TOK_STP4, "DB9/4Mbit" }, \ - { IFM_TOK_STP16, "DB9/16Mbit" }, \ - { IFM_TOK_UTP4, "UTP/4Mbit" }, \ - { IFM_TOK_UTP16, "UTP/16Mbit" }, \ - { IFM_TOK_STP100, "STP/100Mbit" }, \ - { IFM_TOK_UTP100, "UTP/100Mbit" }, \ - { 0, NULL }, \ -} - -#define IFM_SUBTYPE_TOKENRING_ALIASES { \ - { IFM_TOK_STP4, "4STP" }, \ - { IFM_TOK_STP16, "16STP" }, \ - { IFM_TOK_UTP4, "4UTP" }, \ - { IFM_TOK_UTP16, "16UTP" }, \ - { IFM_TOK_STP100, "100STP" }, \ - { IFM_TOK_UTP100, "100UTP" }, \ - { 0, NULL }, \ -} - -#define IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS { \ - { IFM_TOK_ETR, "EarlyTokenRelease" }, \ - { IFM_TOK_SRCRT, "SourceRouting" }, \ - { IFM_TOK_ALLR, "AllRoutes" }, \ - { IFM_TOK_DTR, "Dedicated" }, \ - { IFM_TOK_CLASSIC,"Classic" }, \ - { IFM_TOK_AUTO, " " }, \ - { 0, NULL }, \ -} - -#define IFM_SUBTYPE_FDDI_DESCRIPTIONS { \ - { IFM_FDDI_SMF, "Single-mode" }, \ - { IFM_FDDI_MMF, "Multi-mode" }, \ - { IFM_FDDI_UTP, "UTP" }, \ - { 0, NULL }, \ -} - -#define IFM_SUBTYPE_FDDI_ALIASES { \ - { IFM_FDDI_SMF, "SMF" }, \ - { IFM_FDDI_MMF, "MMF" }, \ - { IFM_FDDI_UTP, "CDDI" }, \ - { 0, NULL }, \ -} - -#define IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS { \ - { IFM_FDDI_DA, "Dual-attach" }, \ - { 0, NULL }, \ -} - #define IFM_SUBTYPE_IEEE80211_DESCRIPTIONS { \ { IFM_IEEE80211_FH1, "FH/1Mbps" }, \ { IFM_IEEE80211_FH2, "FH/2Mbps" }, \ @@ -797,15 +720,6 @@ struct ifmedia_baudrate { { IFM_ETHER | IFM_25G_ACC, IF_Gbps(25ULL) }, \ { IFM_ETHER | IFM_25G_AOC, IF_Gbps(25ULL) }, \ \ - { IFM_TOKEN | IFM_TOK_STP4, IF_Mbps(4) }, \ - { IFM_TOKEN | IFM_TOK_STP16, IF_Mbps(16) }, \ - { IFM_TOKEN | IFM_TOK_UTP4, IF_Mbps(4) }, \ - { IFM_TOKEN | IFM_TOK_UTP16, IF_Mbps(16) }, \ - \ - { IFM_FDDI | IFM_FDDI_SMF, IF_Mbps(100) }, \ - { IFM_FDDI | IFM_FDDI_MMF, IF_Mbps(100) }, \ - { IFM_FDDI | IFM_FDDI_UTP, IF_Mbps(100) }, \ - \ { IFM_IEEE80211 | IFM_IEEE80211_FH1, IF_Mbps(1) }, \ { IFM_IEEE80211 | IFM_IEEE80211_FH2, IF_Mbps(2) }, \ { IFM_IEEE80211 | IFM_IEEE80211_DS2, IF_Mbps(2) }, \ @@ -842,10 +756,6 @@ struct ifmedia_status_description { #define IFM_STATUS_DESCRIPTIONS { \ { IFM_ETHER, IFM_AVALID, IFM_ACTIVE, \ { "no carrier", "active" } }, \ - { IFM_FDDI, IFM_AVALID, IFM_ACTIVE, \ - { "no ring", "inserted" } }, \ - { IFM_TOKEN, IFM_AVALID, IFM_ACTIVE, \ - { "no ring", "inserted" } }, \ { IFM_IEEE80211, IFM_AVALID, IFM_ACTIVE, \ { "no network", "active" } }, \ { IFM_ATM, IFM_AVALID, IFM_ACTIVE, \ diff --git a/freebsd/sys/net/if_spppsubr.c b/freebsd/sys/net/if_spppsubr.c index 1f85c00f..f5b78dec 100644 --- a/freebsd/sys/net/if_spppsubr.c +++ b/freebsd/sys/net/if_spppsubr.c @@ -4839,7 +4839,7 @@ sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, u_long *srcmask) */ si = NULL; if_addr_rlock(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_INET) { si = (struct sockaddr_in *)ifa->ifa_addr; sm = (struct sockaddr_in *)ifa->ifa_netmask; @@ -4881,7 +4881,7 @@ sppp_set_ip_addr(struct sppp *sp, u_long src) */ si = NULL; if_addr_rlock(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == AF_INET) { si = (struct sockaddr_in *)ifa->ifa_addr; if (si != NULL) { @@ -4943,7 +4943,7 @@ sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src, struct in6_addr *dst, */ si = NULL; if_addr_rlock(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_INET6) { si = (struct sockaddr_in6 *)ifa->ifa_addr; sm = (struct sockaddr_in6 *)ifa->ifa_netmask; @@ -4998,7 +4998,7 @@ sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src) sin6 = NULL; if_addr_rlock(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == AF_INET6) { sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; if (sin6 && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { diff --git a/freebsd/sys/net/if_stf.c b/freebsd/sys/net/if_stf.c index 2aab358c..1d16b2d7 100644 --- a/freebsd/sys/net/if_stf.c +++ b/freebsd/sys/net/if_stf.c @@ -278,7 +278,7 @@ static int stf_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) { struct stf_softc *sc = ifp->if_softc; - int err; + int err __unused; err = encap_detach(sc->encap_cookie); KASSERT(err == 0, ("Unexpected error detaching encap_cookie")); @@ -386,7 +386,7 @@ stf_getsrcifa6(struct ifnet *ifp, struct in6_addr *addr, struct in6_addr *mask) struct in_addr in; if_addr_rlock(ifp); - TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) { if (ia->ifa_addr->sa_family != AF_INET6) continue; sin6 = (struct sockaddr_in6 *)ia->ifa_addr; @@ -563,7 +563,7 @@ stf_checkaddr4(struct stf_softc *sc, struct in_addr *in, struct ifnet *inifp) * reject packets with broadcast */ IN_IFADDR_RLOCK(&in_ifa_tracker); - TAILQ_FOREACH(ia4, &V_in_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia4, &V_in_ifaddrhead, ia_link) { if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) continue; if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { diff --git a/freebsd/sys/net/if_tap.c b/freebsd/sys/net/if_tap.c index ce143f9f..c918a14e 100644 --- a/freebsd/sys/net/if_tap.c +++ b/freebsd/sys/net/if_tap.c @@ -39,7 +39,6 @@ * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ */ -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_inet.h> #include <sys/param.h> @@ -80,7 +79,6 @@ #include <net/if_tapvar.h> #include <net/if_tap.h> - #define CDEV_NAME "tap" #define TAPDEBUG if (tapdebug) printf @@ -551,7 +549,7 @@ tapclose(struct cdev *dev, int foo, int bar, struct thread *td) if (ifp->if_drv_flags & IFF_DRV_RUNNING) { ifp->if_drv_flags &= ~IFF_DRV_RUNNING; mtx_unlock(&tp->tap_mtx); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { rtinit(ifa, (int)RTM_DELETE, 0); } if_purgeaddrs(ifp); diff --git a/freebsd/sys/net/if_tun.c b/freebsd/sys/net/if_tun.c index 598a5c14..e4a0b02f 100644 --- a/freebsd/sys/net/if_tun.c +++ b/freebsd/sys/net/if_tun.c @@ -476,7 +476,7 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td) ifp->if_drv_flags &= ~IFF_DRV_RUNNING; mtx_unlock(&tp->tun_mtx); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { /* deal w/IPv4 PtP destination; unlocked read */ if (ifa->ifa_addr->sa_family == AF_INET) { rtinit(ifa, (int)RTM_DELETE, @@ -518,7 +518,7 @@ tuninit(struct ifnet *ifp) #ifdef INET if_addr_rlock(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *si; diff --git a/freebsd/sys/net/if_var.h b/freebsd/sys/net/if_var.h index a131c496..f8e18f7e 100644 --- a/freebsd/sys/net/if_var.h +++ b/freebsd/sys/net/if_var.h @@ -70,27 +70,29 @@ struct route; /* if_output */ struct vnet; struct ifmedia; struct netmap_adapter; +struct netdump_methods; #ifdef _KERNEL #include <sys/mbuf.h> /* ifqueue only? */ #include <sys/buf_ring.h> #include <net/vnet.h> #endif /* _KERNEL */ +#include <sys/ck.h> #include <sys/counter.h> +#include <sys/epoch.h> #include <sys/lock.h> /* XXX */ #include <sys/mutex.h> /* struct ifqueue */ #include <sys/rwlock.h> /* XXX */ #include <sys/sx.h> /* XXX */ #include <sys/_task.h> /* if_link_task */ - #define IF_DUNIT_NONE -1 #include <net/altq/if_altq.h> -TAILQ_HEAD(ifnethead, ifnet); /* we use TAILQs so that the order of */ -TAILQ_HEAD(ifaddrhead, ifaddr); /* instantiation is preserved in the list */ -TAILQ_HEAD(ifmultihead, ifmultiaddr); -TAILQ_HEAD(ifgrouphead, ifg_group); +CK_STAILQ_HEAD(ifnethead, ifnet); /* we use TAILQs so that the order of */ +CK_STAILQ_HEAD(ifaddrhead, ifaddr); /* instantiation is preserved in the list */ +CK_STAILQ_HEAD(ifmultihead, ifmultiaddr); +CK_STAILQ_HEAD(ifgrouphead, ifg_group); #ifdef _KERNEL VNET_DECLARE(struct pfil_head, link_pfil_hook); /* packet filter hooks */ @@ -103,6 +105,15 @@ VNET_DECLARE(struct hhook_head *, ipsec_hhh_in[HHOOK_IPSEC_COUNT]); VNET_DECLARE(struct hhook_head *, ipsec_hhh_out[HHOOK_IPSEC_COUNT]); #define V_ipsec_hhh_in VNET(ipsec_hhh_in) #define V_ipsec_hhh_out VNET(ipsec_hhh_out) +#ifndef __rtems__ +extern epoch_t net_epoch_preempt; +extern epoch_t net_epoch; +#else /* __rtems__ */ +extern struct epoch _bsd_net_epoch_preempt; +#define net_epoch_preempt &_bsd_net_epoch_preempt +extern struct epoch _bsd_net_epoch; +#define net_epoch &_bsd_net_epoch +#endif /* __rtems__ */ #endif /* _KERNEL */ typedef enum { @@ -234,9 +245,9 @@ typedef void (if_snd_tag_free_t)(struct m_snd_tag *); */ struct ifnet { /* General book keeping of interface lists. */ - TAILQ_ENTRY(ifnet) if_link; /* all struct ifnets are chained */ + CK_STAILQ_ENTRY(ifnet) if_link; /* all struct ifnets are chained (CK_) */ LIST_ENTRY(ifnet) if_clones; /* interfaces of a cloner */ - TAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if */ + CK_STAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if (CK_) */ /* protected by if_addr_lock */ u_char if_alloctype; /* if_type at time of allocation */ @@ -276,7 +287,7 @@ struct ifnet { struct task if_linktask; /* task for link change events */ /* Addresses of different protocol families assigned to this if. */ - struct rwlock if_addr_lock; /* lock to protect address lists */ + struct mtx if_addr_lock; /* lock to protect address lists */ /* * if_addrhead is the list of all addresses associated to * an interface. @@ -293,7 +304,7 @@ struct ifnet { struct ifaddr *if_addr; /* pointer to link-level address */ void *if_hw_addr; /* hardware link-level address */ const u_int8_t *if_broadcastaddr; /* linklevel broadcast bytestring */ - struct rwlock if_afdata_lock; + struct mtx if_afdata_lock; void *if_afdata[AF_MAX]; int if_afdata_initialized; @@ -317,6 +328,10 @@ struct ifnet { struct route *); void (*if_input) /* input routine (from h/w driver) */ (struct ifnet *, struct mbuf *); + struct mbuf *(*if_bridge_input)(struct ifnet *, struct mbuf *); + int (*if_bridge_output)(struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *); + void (*if_bridge_linkstate)(struct ifnet *ifp); if_start_fn_t if_start; /* initiate output routine */ if_ioctl_fn_t if_ioctl; /* ioctl routine */ if_init_fn_t if_init; /* Init routine */ @@ -370,6 +385,14 @@ struct ifnet { #ifndef __rtems__ /* + * Netdump hooks to be called while dumping. + */ + struct netdump_methods *if_netdump_methods; +#endif /* __rtems__ */ + struct epoch_context if_epoch_ctx; + +#ifndef __rtems__ + /* * Spare fields to be added before branching a stable branch, so * that structure can be enhanced without changing the kernel * binary interface. @@ -396,14 +419,18 @@ struct rtems_ifinputreq { /* * Locks for address lists on the network interface. */ -#define IF_ADDR_LOCK_INIT(if) rw_init(&(if)->if_addr_lock, "if_addr_lock") -#define IF_ADDR_LOCK_DESTROY(if) rw_destroy(&(if)->if_addr_lock) -#define IF_ADDR_WLOCK(if) rw_wlock(&(if)->if_addr_lock) -#define IF_ADDR_WUNLOCK(if) rw_wunlock(&(if)->if_addr_lock) -#define IF_ADDR_RLOCK(if) rw_rlock(&(if)->if_addr_lock) -#define IF_ADDR_RUNLOCK(if) rw_runlock(&(if)->if_addr_lock) -#define IF_ADDR_LOCK_ASSERT(if) rw_assert(&(if)->if_addr_lock, RA_LOCKED) -#define IF_ADDR_WLOCK_ASSERT(if) rw_assert(&(if)->if_addr_lock, RA_WLOCKED) +#define IF_ADDR_LOCK_INIT(if) mtx_init(&(if)->if_addr_lock, "if_addr_lock", NULL, MTX_DEF) +#define IF_ADDR_LOCK_DESTROY(if) mtx_destroy(&(if)->if_addr_lock) +#define IF_ADDR_RLOCK(if) epoch_enter_preempt(net_epoch_preempt); +#define IF_ADDR_RUNLOCK(if) epoch_exit_preempt(net_epoch_preempt); + +#define IF_ADDR_WLOCK(if) mtx_lock(&(if)->if_addr_lock) +#define IF_ADDR_WUNLOCK(if) mtx_unlock(&(if)->if_addr_lock) +#define IF_ADDR_LOCK_ASSERT(if) MPASS(in_epoch() || mtx_owned(&(if)->if_addr_lock)) +#define IF_ADDR_WLOCK_ASSERT(if) mtx_assert(&(if)->if_addr_lock, MA_OWNED) +#define NET_EPOCH_ENTER() epoch_enter_preempt(net_epoch_preempt) +#define NET_EPOCH_EXIT() epoch_exit_preempt(net_epoch_preempt) + /* * Function variations on locking macros intended to be used by loadable @@ -435,6 +462,8 @@ EVENTHANDLER_DECLARE(ifnet_link_event, ifnet_link_event_handler_t); /* Interface up/down event */ #define IFNET_EVENT_UP 0 #define IFNET_EVENT_DOWN 1 +#define IFNET_EVENT_PCP 2 /* priority code point, PCP */ + typedef void (*ifnet_event_fn)(void *, struct ifnet *ifp, int event); EVENTHANDLER_DECLARE(ifnet_event, ifnet_event_fn); #endif /* _SYS_EVENTHANDLER_H_ */ @@ -446,18 +475,18 @@ struct ifg_group { char ifg_group[IFNAMSIZ]; u_int ifg_refcnt; void *ifg_pf_kif; - TAILQ_HEAD(, ifg_member) ifg_members; - TAILQ_ENTRY(ifg_group) ifg_next; + CK_STAILQ_HEAD(, ifg_member) ifg_members; /* (CK_) */ + CK_STAILQ_ENTRY(ifg_group) ifg_next; /* (CK_) */ }; struct ifg_member { - TAILQ_ENTRY(ifg_member) ifgm_next; + CK_STAILQ_ENTRY(ifg_member) ifgm_next; /* (CK_) */ struct ifnet *ifgm_ifp; }; struct ifg_list { struct ifg_group *ifgl_group; - TAILQ_ENTRY(ifg_list) ifgl_next; + CK_STAILQ_ENTRY(ifg_list) ifgl_next; /* (CK_) */ }; #ifdef _SYS_EVENTHANDLER_H_ @@ -473,21 +502,21 @@ EVENTHANDLER_DECLARE(group_change_event, group_change_event_handler_t); #endif /* _SYS_EVENTHANDLER_H_ */ #define IF_AFDATA_LOCK_INIT(ifp) \ - rw_init(&(ifp)->if_afdata_lock, "if_afdata") + mtx_init(&(ifp)->if_afdata_lock, "if_afdata", NULL, MTX_DEF) -#define IF_AFDATA_WLOCK(ifp) rw_wlock(&(ifp)->if_afdata_lock) -#define IF_AFDATA_RLOCK(ifp) rw_rlock(&(ifp)->if_afdata_lock) -#define IF_AFDATA_WUNLOCK(ifp) rw_wunlock(&(ifp)->if_afdata_lock) -#define IF_AFDATA_RUNLOCK(ifp) rw_runlock(&(ifp)->if_afdata_lock) +#define IF_AFDATA_WLOCK(ifp) mtx_lock(&(ifp)->if_afdata_lock) +#define IF_AFDATA_RLOCK(ifp) epoch_enter_preempt(net_epoch_preempt) +#define IF_AFDATA_WUNLOCK(ifp) mtx_unlock(&(ifp)->if_afdata_lock) +#define IF_AFDATA_RUNLOCK(ifp) epoch_exit_preempt(net_epoch_preempt) #define IF_AFDATA_LOCK(ifp) IF_AFDATA_WLOCK(ifp) #define IF_AFDATA_UNLOCK(ifp) IF_AFDATA_WUNLOCK(ifp) -#define IF_AFDATA_TRYLOCK(ifp) rw_try_wlock(&(ifp)->if_afdata_lock) -#define IF_AFDATA_DESTROY(ifp) rw_destroy(&(ifp)->if_afdata_lock) +#define IF_AFDATA_TRYLOCK(ifp) mtx_trylock(&(ifp)->if_afdata_lock) +#define IF_AFDATA_DESTROY(ifp) mtx_destroy(&(ifp)->if_afdata_lock) -#define IF_AFDATA_LOCK_ASSERT(ifp) rw_assert(&(ifp)->if_afdata_lock, RA_LOCKED) -#define IF_AFDATA_RLOCK_ASSERT(ifp) rw_assert(&(ifp)->if_afdata_lock, RA_RLOCKED) -#define IF_AFDATA_WLOCK_ASSERT(ifp) rw_assert(&(ifp)->if_afdata_lock, RA_WLOCKED) -#define IF_AFDATA_UNLOCK_ASSERT(ifp) rw_assert(&(ifp)->if_afdata_lock, RA_UNLOCKED) +#define IF_AFDATA_LOCK_ASSERT(ifp) MPASS(in_epoch() || mtx_owned(&(ifp)->if_afdata_lock)) +#define IF_AFDATA_RLOCK_ASSERT(ifp) MPASS(in_epoch()); +#define IF_AFDATA_WLOCK_ASSERT(ifp) mtx_assert(&(ifp)->if_afdata_lock, MA_OWNED) +#define IF_AFDATA_UNLOCK_ASSERT(ifp) mtx_assert(&(ifp)->if_afdata_lock, MA_NOTOWNED) /* * 72 was chosen below because it is the size of a TCP/IP @@ -515,7 +544,7 @@ struct ifaddr { struct sockaddr *ifa_netmask; /* used to determine subnet */ struct ifnet *ifa_ifp; /* back-pointer to interface */ struct carp_softc *ifa_carp; /* pointer to CARP data */ - TAILQ_ENTRY(ifaddr) ifa_link; /* queue macro glue */ + CK_STAILQ_ENTRY(ifaddr) ifa_link; /* queue macro glue */ void (*ifa_rtrequest) /* check or clean routes (+ or -)'d */ (int, struct rtentry *, struct rt_addrinfo *); u_short ifa_flags; /* mostly rt_flags for cloning */ @@ -527,6 +556,7 @@ struct ifaddr { counter_u64_t ifa_opackets; counter_u64_t ifa_ibytes; counter_u64_t ifa_obytes; + struct epoch_context ifa_epoch_ctx; }; struct ifaddr * ifa_alloc(size_t size, int flags); @@ -538,13 +568,14 @@ void ifa_ref(struct ifaddr *ifa); * structure except that it keeps track of multicast addresses. */ struct ifmultiaddr { - TAILQ_ENTRY(ifmultiaddr) ifma_link; /* queue macro glue */ + CK_STAILQ_ENTRY(ifmultiaddr) ifma_link; /* queue macro glue */ struct sockaddr *ifma_addr; /* address this membership is for */ struct sockaddr *ifma_lladdr; /* link-layer translation, if any */ struct ifnet *ifma_ifp; /* back-pointer to interface */ u_int ifma_refcount; /* reference count */ void *ifma_protospec; /* protocol-specific state, if any */ struct ifmultiaddr *ifma_llifma; /* pointer to ifma for ifma_lladdr */ + struct epoch_context ifma_epoch_ctx; }; extern struct rwlock ifnet_rwlock; @@ -565,16 +596,16 @@ extern struct sx ifnet_sxlock; * write, but also whether it was acquired with sleep support or not. */ #define IFNET_RLOCK_ASSERT() sx_assert(&ifnet_sxlock, SA_SLOCKED) -#define IFNET_RLOCK_NOSLEEP_ASSERT() rw_assert(&ifnet_rwlock, RA_RLOCKED) +#define IFNET_RLOCK_NOSLEEP_ASSERT() MPASS(in_epoch()) #define IFNET_WLOCK_ASSERT() do { \ sx_assert(&ifnet_sxlock, SA_XLOCKED); \ rw_assert(&ifnet_rwlock, RA_WLOCKED); \ } while (0) #define IFNET_RLOCK() sx_slock(&ifnet_sxlock) -#define IFNET_RLOCK_NOSLEEP() rw_rlock(&ifnet_rwlock) +#define IFNET_RLOCK_NOSLEEP() epoch_enter_preempt(net_epoch_preempt) #define IFNET_RUNLOCK() sx_sunlock(&ifnet_sxlock) -#define IFNET_RUNLOCK_NOSLEEP() rw_runlock(&ifnet_rwlock) +#define IFNET_RUNLOCK_NOSLEEP() epoch_exit_preempt(net_epoch_preempt) /* * Look up an ifnet given its index; the _ref variant also acquires a @@ -602,6 +633,12 @@ VNET_DECLARE(struct ifnet *, loif); /* first loopback interface */ #define V_if_index VNET(if_index) #define V_loif VNET(loif) +#ifdef MCAST_VERBOSE +#define MCDPRINTF printf +#else +#define MCDPRINTF(...) +#endif + int if_addgroup(struct ifnet *, const char *); int if_delgroup(struct ifnet *, const char *); int if_addmulti(struct ifnet *, struct sockaddr *, struct ifmultiaddr **); @@ -611,12 +648,14 @@ void if_attach(struct ifnet *); void if_dead(struct ifnet *); int if_delmulti(struct ifnet *, struct sockaddr *); void if_delmulti_ifma(struct ifmultiaddr *); +void if_delmulti_ifma_flags(struct ifmultiaddr *, int flags); void if_detach(struct ifnet *); void if_purgeaddrs(struct ifnet *); void if_delallmulti(struct ifnet *); void if_down(struct ifnet *); struct ifmultiaddr * if_findmulti(struct ifnet *, const struct sockaddr *); +void if_freemulti(struct ifmultiaddr *ifma); void if_free(struct ifnet *); void if_initname(struct ifnet *, const char *, int); void if_link_state_change(struct ifnet *, int); diff --git a/freebsd/sys/net/if_vlan.c b/freebsd/sys/net/if_vlan.c index 79294427..26f6bbde 100644 --- a/freebsd/sys/net/if_vlan.c +++ b/freebsd/sys/net/if_vlan.c @@ -611,7 +611,7 @@ vlan_setmulti(struct ifnet *ifp) /* Now program new ones. */ IF_ADDR_WLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT); @@ -1949,6 +1949,8 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } ifv->ifv_pcp = ifr->ifr_vlan_pcp; vlan_tag_recalculate(ifv); + /* broadcast event about PCP change */ + EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_PCP); break; case SIOCSIFCAP: diff --git a/freebsd/sys/net/iflib.h b/freebsd/sys/net/iflib.h index 02319322..140c488b 100644 --- a/freebsd/sys/net/iflib.h +++ b/freebsd/sys/net/iflib.h @@ -36,6 +36,8 @@ #include <sys/nv.h> #include <sys/gtaskqueue.h> +struct if_clone; + /* * The value type for indexing, limits max descriptors * to 65535 can be conditionally redefined to uint32_t @@ -57,6 +59,8 @@ struct if_shared_ctx; typedef struct if_shared_ctx *if_shared_ctx_t; struct if_int_delay_info; typedef struct if_int_delay_info *if_int_delay_info_t; +struct if_pseudo; +typedef struct if_pseudo *if_pseudo_t; /* * File organization: @@ -194,6 +198,9 @@ typedef struct if_softc_ctx { int isc_vectors; int isc_nrxqsets; int isc_ntxqsets; + uint8_t isc_min_tx_latency; /* disable doorbell update batching */ + uint8_t isc_rx_mvec_enable; /* generate mvecs on rx */ + uint32_t isc_txrx_budget_bytes_max; int isc_msix_bar; /* can be model specific - initialize in attach_pre */ int isc_tx_nsegments; /* can be model specific - initialize in attach_pre */ int isc_ntxd[8]; @@ -214,6 +221,7 @@ typedef struct if_softc_ctx { int isc_rss_table_mask; int isc_nrxqsets_max; int isc_ntxqsets_max; + uint32_t isc_tx_qdepth; iflib_intr_mode_t isc_intr; uint16_t isc_max_frame_size; /* set at init time by driver */ @@ -259,6 +267,7 @@ struct if_shared_ctx { int isc_rx_process_limit; int isc_tx_reclaim_thresh; int isc_flags; + const char *isc_name; }; typedef struct iflib_dma_info { @@ -320,7 +329,39 @@ typedef enum { * Driver needs frames padded to some minimum length */ #define IFLIB_NEED_ETHER_PAD 0x100 - +/* + * Packets can be freed immediately after encap + */ +#define IFLIB_TXD_ENCAP_PIO 0x00200 +/* + * Use RX completion handler + */ +#define IFLIB_RX_COMPLETION 0x00400 +/* + * Skip refilling cluster free lists + */ +#define IFLIB_SKIP_CLREFILL 0x00800 +/* + * Don't reset on hang + */ +#define IFLIB_NO_HANG_RESET 0x01000 +/* + * Don't need/want most of the niceties of + * queue management + */ +#define IFLIB_PSEUDO 0x02000 +/* + * No DMA support needed / wanted + */ +#define IFLIB_VIRTUAL 0x04000 +/* + * autogenerate a MAC address + */ +#define IFLIB_GEN_MAC 0x08000 +/* + * Interface needs admin task to ignore interface up/down status + */ +#define IFLIB_ADMIN_ALWAYS_RUN 0x10000 /* @@ -363,18 +404,18 @@ int iflib_device_deregister(if_ctx_t); -int iflib_irq_alloc(if_ctx_t, if_irq_t, int, driver_filter_t, void *filter_arg, driver_intr_t, void *arg, char *name); +int iflib_irq_alloc(if_ctx_t, if_irq_t, int, driver_filter_t, void *filter_arg, driver_intr_t, void *arg, const char *name); int iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid, - iflib_intr_type_t type, driver_filter_t *filter, - void *filter_arg, int qid, char *name); -void iflib_softirq_alloc_generic(if_ctx_t ctx, if_irq_t irq, iflib_intr_type_t type, void *arg, int qid, char *name); + iflib_intr_type_t type, driver_filter_t *filter, + void *filter_arg, int qid, const char *name); +void iflib_softirq_alloc_generic(if_ctx_t ctx, if_irq_t irq, iflib_intr_type_t type, void *arg, int qid, const char *name); void iflib_irq_free(if_ctx_t ctx, if_irq_t irq); void iflib_io_tqg_attach(struct grouptask *gt, void *uniq, int cpu, char *name); -void iflib_config_gtask_init(if_ctx_t ctx, struct grouptask *gtask, - gtask_fn_t *fn, char *name); +void iflib_config_gtask_init(void *ctx, struct grouptask *gtask, + gtask_fn_t *fn, const char *name); void iflib_config_gtask_deinit(struct grouptask *gtask); @@ -396,7 +437,7 @@ int iflib_dma_alloc_multi(if_ctx_t ctx, int *sizes, iflib_dma_info_t *dmalist, i void iflib_dma_free_multi(iflib_dma_info_t *dmalist, int count); -struct mtx *iflib_ctx_lock_get(if_ctx_t); +struct sx *iflib_ctx_lock_get(if_ctx_t); struct mtx *iflib_qset_lock_get(if_ctx_t, uint16_t); void iflib_led_create(if_ctx_t ctx); @@ -404,4 +445,9 @@ void iflib_led_create(if_ctx_t ctx); void iflib_add_int_delay_sysctl(if_ctx_t, const char *, const char *, if_int_delay_info_t, int, int); +/* + * Pseudo device support + */ +if_pseudo_t iflib_clone_register(if_shared_ctx_t); +void iflib_clone_deregister(if_pseudo_t); #endif /* __IFLIB_H_ */ diff --git a/freebsd/sys/net/pfvar.h b/freebsd/sys/net/pfvar.h index dfff0b87..824b8ec3 100644 --- a/freebsd/sys/net/pfvar.h +++ b/freebsd/sys/net/pfvar.h @@ -38,8 +38,11 @@ #include <sys/param.h> #include <sys/queue.h> #include <sys/counter.h> +#include <sys/cpuset.h> #include <sys/malloc.h> #include <sys/refcount.h> +#include <sys/lock.h> +#include <sys/rmlock.h> #include <sys/tree.h> #include <vm/uma.h> @@ -147,14 +150,15 @@ extern struct mtx pf_unlnkdrules_mtx; #define PF_UNLNKDRULES_LOCK() mtx_lock(&pf_unlnkdrules_mtx) #define PF_UNLNKDRULES_UNLOCK() mtx_unlock(&pf_unlnkdrules_mtx) -extern struct rwlock pf_rules_lock; -#define PF_RULES_RLOCK() rw_rlock(&pf_rules_lock) -#define PF_RULES_RUNLOCK() rw_runlock(&pf_rules_lock) -#define PF_RULES_WLOCK() rw_wlock(&pf_rules_lock) -#define PF_RULES_WUNLOCK() rw_wunlock(&pf_rules_lock) -#define PF_RULES_ASSERT() rw_assert(&pf_rules_lock, RA_LOCKED) -#define PF_RULES_RASSERT() rw_assert(&pf_rules_lock, RA_RLOCKED) -#define PF_RULES_WASSERT() rw_assert(&pf_rules_lock, RA_WLOCKED) +extern struct rmlock pf_rules_lock; +#define PF_RULES_RLOCK_TRACKER struct rm_priotracker _pf_rules_tracker +#define PF_RULES_RLOCK() rm_rlock(&pf_rules_lock, &_pf_rules_tracker) +#define PF_RULES_RUNLOCK() rm_runlock(&pf_rules_lock, &_pf_rules_tracker) +#define PF_RULES_WLOCK() rm_wlock(&pf_rules_lock) +#define PF_RULES_WUNLOCK() rm_wunlock(&pf_rules_lock) +#define PF_RULES_ASSERT() rm_assert(&pf_rules_lock, RA_LOCKED) +#define PF_RULES_RASSERT() rm_assert(&pf_rules_lock, RA_RLOCKED) +#define PF_RULES_WASSERT() rm_assert(&pf_rules_lock, RA_WLOCKED) extern struct sx pf_end_lock; @@ -1638,6 +1642,7 @@ void pfr_detach_table(struct pfr_ktable *); int pfr_clr_tables(struct pfr_table *, int *, int); int pfr_add_tables(struct pfr_table *, int, int *, int); int pfr_del_tables(struct pfr_table *, int, int *, int); +int pfr_table_count(struct pfr_table *, int); int pfr_get_tables(struct pfr_table *, struct pfr_table *, int *, int); int pfr_get_tstats(struct pfr_table *, struct pfr_tstats *, int *, int); int pfr_clr_tstats(struct pfr_table *, int, int *, int); diff --git a/freebsd/sys/net/route.c b/freebsd/sys/net/route.c index ade738a2..c2348e31 100644 --- a/freebsd/sys/net/route.c +++ b/freebsd/sys/net/route.c @@ -238,7 +238,7 @@ route_init(void) if (rt_numfibs == 0) rt_numfibs = 1; } -SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, 0); +SYSINIT(route_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, route_init, NULL); static int rtentry_zinit(void *mem, int size, int how) @@ -626,12 +626,12 @@ rtredirect_fib(struct sockaddr *dst, struct rib_head *rnh; ifa = NULL; + NET_EPOCH_ENTER(); rnh = rt_tables_get_rnh(fibnum, dst->sa_family); if (rnh == NULL) { error = EAFNOSUPPORT; goto out; } - /* verify the gateway is directly reachable */ if ((ifa = ifa_ifwithnet(gateway, 0, fibnum)) == NULL) { error = ENETUNREACH; @@ -685,6 +685,7 @@ rtredirect_fib(struct sockaddr *dst, info.rti_info[RTAX_DST] = dst; info.rti_info[RTAX_GATEWAY] = gateway; info.rti_info[RTAX_NETMASK] = netmask; + ifa_ref(ifa); info.rti_ifa = ifa; info.rti_flags = flags; error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); @@ -719,7 +720,8 @@ rtredirect_fib(struct sockaddr *dst, done: if (rt) RTFREE_LOCKED(rt); -out: + out: + NET_EPOCH_EXIT(); if (error) V_rtstat.rts_badredirect++; else if (stat != NULL) @@ -730,8 +732,6 @@ out: info.rti_info[RTAX_NETMASK] = netmask; info.rti_info[RTAX_AUTHOR] = src; rt_missmsg_fib(RTM_REDIRECT, &info, flags, error, fibnum); - if (ifa != NULL) - ifa_free(ifa); } /* @@ -762,6 +762,7 @@ ifa_ifwithroute(int flags, const struct sockaddr *dst, struct sockaddr *gateway, struct ifaddr *ifa; int not_found = 0; + MPASS(in_epoch()); if ((flags & RTF_GATEWAY) == 0) { /* * If we are adding a route to an interface, @@ -790,7 +791,7 @@ ifa_ifwithroute(int flags, const struct sockaddr *dst, struct sockaddr *gateway, rt = rtalloc1_fib(gateway, 0, flags, fibnum); if (rt == NULL) - return (NULL); + goto out; /* * dismiss a gateway that is reachable only * through the default router @@ -809,21 +810,19 @@ ifa_ifwithroute(int flags, const struct sockaddr *dst, struct sockaddr *gateway, } if (!not_found && rt->rt_ifa != NULL) { ifa = rt->rt_ifa; - ifa_ref(ifa); } RT_REMREF(rt); RT_UNLOCK(rt); if (not_found || ifa == NULL) - return (NULL); + goto out; } if (ifa->ifa_addr->sa_family != dst->sa_family) { struct ifaddr *oifa = ifa; ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp); if (ifa == NULL) ifa = oifa; - else - ifa_free(oifa); } + out: return (ifa); } @@ -933,7 +932,7 @@ rt_exportinfo(struct rtentry *rt, struct rt_addrinfo *info, int flags) info->rti_flags = rt->rt_flags; info->rti_ifp = rt->rt_ifp; info->rti_ifa = rt->rt_ifa; - + ifa_ref(info->rti_ifa); if (flags & NHR_REF) { /* Do 'traditional' refcouting */ if_ref(info->rti_ifp); @@ -1309,17 +1308,19 @@ int rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) { struct ifaddr *ifa; - int error = 0; + int needref, error; /* * ifp may be specified by sockaddr_dl * when protocol address is ambiguous. */ + error = 0; + needref = (info->rti_ifa == NULL); + NET_EPOCH_ENTER(); if (info->rti_ifp == NULL && ifpaddr != NULL && ifpaddr->sa_family == AF_LINK && (ifa = ifa_ifwithnet(ifpaddr, 0, fibnum)) != NULL) { info->rti_ifp = ifa->ifa_ifp; - ifa_free(ifa); } if (info->rti_ifa == NULL && ifaaddr != NULL) info->rti_ifa = ifa_ifwithaddr(ifaaddr); @@ -1337,11 +1338,13 @@ rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum) info->rti_ifa = ifa_ifwithroute(flags, sa, sa, fibnum); } - if ((ifa = info->rti_ifa) != NULL) { + if (needref && info->rti_ifa != NULL) { if (info->rti_ifp == NULL) - info->rti_ifp = ifa->ifa_ifp; + info->rti_ifp = info->rti_ifa->ifa_ifp; + ifa_ref(info->rti_ifa); } else error = ENETUNREACH; + NET_EPOCH_EXIT(); return (error); } @@ -1618,12 +1621,9 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, error = rt_getifa_fib(info, fibnum); if (error) return (error); - } else - ifa_ref(info->rti_ifa); - ifa = info->rti_ifa; + } rt = uma_zalloc(V_rtzone, M_NOWAIT); if (rt == NULL) { - ifa_free(ifa); return (ENOBUFS); } rt->rt_flags = RTF_UP | flags; @@ -1632,7 +1632,6 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, * Add the gateway. Possibly re-malloc-ing the storage for it. */ if ((error = rt_setgate(rt, dst, gateway)) != 0) { - ifa_free(ifa); uma_zfree(V_rtzone, rt); return (error); } @@ -1655,6 +1654,8 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, * This moved from below so that rnh->rnh_addaddr() can * examine the ifa and ifa->ifa_ifp if it so desires. */ + ifa = info->rti_ifa; + ifa_ref(ifa); rt->rt_ifa = ifa; rt->rt_ifp = ifa->ifa_ifp; rt->rt_weight = 1; @@ -1819,6 +1820,7 @@ rtrequest1_fib_change(struct rib_head *rnh, struct rt_addrinfo *info, if (rt->rt_ifa->ifa_rtrequest != NULL) rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, info); ifa_free(rt->rt_ifa); + rt->rt_ifa = NULL; } /* Update gateway address */ if (info->rti_info[RTAX_GATEWAY] != NULL) { @@ -1870,8 +1872,10 @@ rtrequest1_fib_change(struct rib_head *rnh, struct rt_addrinfo *info, } bad: RT_UNLOCK(rt); - if (free_ifa != 0) + if (free_ifa != 0) { ifa_free(info->rti_ifa); + info->rti_ifa = NULL; + } return (error); } @@ -2090,6 +2094,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum) * Do the actual request */ bzero((caddr_t)&info, sizeof(info)); + ifa_ref(ifa); info.rti_ifa = ifa; info.rti_flags = flags | (ifa->ifa_flags & ~IFA_RTSELF) | RTF_PINNED; diff --git a/freebsd/sys/net/rtsock.c b/freebsd/sys/net/rtsock.c index 900413a0..c0c5c5c2 100644 --- a/freebsd/sys/net/rtsock.c +++ b/freebsd/sys/net/rtsock.c @@ -33,7 +33,6 @@ * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 * $FreeBSD$ */ -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_mpath.h> #include <rtems/bsd/local/opt_inet.h> #include <rtems/bsd/local/opt_inet6.h> @@ -467,7 +466,7 @@ rtm_get_jailed(struct rt_addrinfo *info, struct ifnet *ifp, * that belongs to the jail. */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { struct sockaddr *sa; sa = ifa->ifa_addr; if (sa->sa_family != AF_INET) @@ -509,7 +508,7 @@ rtm_get_jailed(struct rt_addrinfo *info, struct ifnet *ifp, * that belongs to the jail. */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { struct sockaddr *sa; sa = ifa->ifa_addr; if (sa->sa_family != AF_INET6) @@ -797,12 +796,14 @@ route_output(struct mbuf *m, struct socket *so, ...) rt->rt_ifp->if_type == IFT_PROPVIRTUAL) { struct ifaddr *ifa; + NET_EPOCH_ENTER(); ifa = ifa_ifwithnet(info.rti_info[RTAX_DST], 1, RT_ALL_FIBS); if (ifa != NULL) rt_maskedcopy(ifa->ifa_addr, &laddr, ifa->ifa_netmask); + NET_EPOCH_EXIT(); } else rt_maskedcopy(rt->rt_ifa->ifa_addr, &laddr, @@ -1424,7 +1425,10 @@ rt_newmaddrmsg(int cmd, struct ifmultiaddr *ifma) bzero((caddr_t)&info, sizeof(info)); info.rti_info[RTAX_IFA] = ifma->ifma_addr; - info.rti_info[RTAX_IFP] = ifp ? ifp->if_addr->ifa_addr : NULL; + if (ifp && ifp->if_addr) + info.rti_info[RTAX_IFP] = ifp->if_addr->ifa_addr; + else + info.rti_info[RTAX_IFP] = NULL; /* * If a link-layer address is present, present it as a ``gateway'' * (similarly to how ARP entries, e.g., are presented). @@ -1746,7 +1750,7 @@ sysctl_iflist(int af, struct walkarg *w) bzero((caddr_t)&info, sizeof(info)); bzero(&ifd, sizeof(ifd)); IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if (w->w_arg && w->w_arg != ifp->if_index) continue; if_data_copy(ifp, &ifd); @@ -1767,7 +1771,7 @@ sysctl_iflist(int af, struct walkarg *w) if (error) goto done; } - while ((ifa = TAILQ_NEXT(ifa, ifa_link)) != NULL) { + while ((ifa = CK_STAILQ_NEXT(ifa, ifa_link)) != NULL) { if (af && af != ifa->ifa_addr->sa_family) continue; if (prison_if(w->w_req->td->td_ucred, @@ -1816,13 +1820,13 @@ sysctl_ifmalist(int af, struct walkarg *w) bzero((caddr_t)&info, sizeof(info)); IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if (w->w_arg && w->w_arg != ifp->if_index) continue; ifa = ifp->if_addr; info.rti_info[RTAX_IFP] = ifa ? ifa->ifa_addr : NULL; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (af && af != ifma->ifma_addr->sa_family) continue; if (prison_if(w->w_req->td->td_ucred, diff --git a/freebsd/sys/netinet/cc/cc_newreno.c b/freebsd/sys/netinet/cc/cc_newreno.c index b7f59520..4d5f8644 100644 --- a/freebsd/sys/netinet/cc/cc_newreno.c +++ b/freebsd/sys/netinet/cc/cc_newreno.c @@ -83,7 +83,7 @@ static MALLOC_DEFINE(M_NEWRENO, "newreno data", #define CAST_PTR_INT(X) (*((int*)(X))) -static int newreno_cb_init(struct cc_var *ccv); +static void newreno_cb_destroy(struct cc_var *ccv); static void newreno_ack_received(struct cc_var *ccv, uint16_t type); static void newreno_after_idle(struct cc_var *ccv); static void newreno_cong_signal(struct cc_var *ccv, uint32_t type); @@ -97,7 +97,7 @@ static VNET_DEFINE(uint32_t, newreno_beta_ecn) = 80; struct cc_algo newreno_cc_algo = { .name = "newreno", - .cb_init = newreno_cb_init, + .cb_destroy = newreno_cb_destroy, .ack_received = newreno_ack_received, .after_idle = newreno_after_idle, .cong_signal = newreno_cong_signal, @@ -110,18 +110,28 @@ struct newreno { uint32_t beta_ecn; }; -int -newreno_cb_init(struct cc_var *ccv) +static inline struct newreno * +newreno_malloc(struct cc_var *ccv) { - struct newreno *nreno; + struct newreno *nreno; - nreno = malloc(sizeof(struct newreno), M_NEWRENO, M_NOWAIT|M_ZERO); + nreno = malloc(sizeof(struct newreno), M_NEWRENO, M_NOWAIT); if (nreno != NULL) { + /* NB: nreno is not zeroed, so initialise all fields. */ nreno->beta = V_newreno_beta; nreno->beta_ecn = V_newreno_beta_ecn; + ccv->cc_data = nreno; } - return (0); + return (nreno); +} + +static void +newreno_cb_destroy(struct cc_var *ccv) +{ + + if (ccv->cc_data != NULL) + free(ccv->cc_data, M_NEWRENO); } static void @@ -226,20 +236,18 @@ static void newreno_cong_signal(struct cc_var *ccv, uint32_t type) { struct newreno *nreno; - uint32_t cwin, factor; + uint32_t beta, beta_ecn, cwin, factor; u_int mss; - factor = V_newreno_beta; - nreno = ccv->cc_data; - if (nreno != NULL) { - if (V_cc_do_abe) - factor = (type == CC_ECN ? nreno->beta_ecn: nreno->beta); - else - factor = nreno->beta; - } - cwin = CCV(ccv, snd_cwnd); mss = CCV(ccv, t_maxseg); + nreno = ccv->cc_data; + beta = (nreno == NULL) ? V_newreno_beta : nreno->beta; + beta_ecn = (nreno == NULL) ? V_newreno_beta_ecn : nreno->beta_ecn; + if (V_cc_do_abe && type == CC_ECN) + factor = beta_ecn; + else + factor = beta; /* Catch algos which mistakenly leak private signal types. */ KASSERT((type & CC_SIGPRIVMASK) == 0, @@ -255,8 +263,8 @@ newreno_cong_signal(struct cc_var *ccv, uint32_t type) V_cc_do_abe && V_cc_abe_frlossreduce)) { CCV(ccv, snd_ssthresh) = ((uint64_t)CCV(ccv, snd_ssthresh) * - (uint64_t)nreno->beta) / - (100ULL * (uint64_t)nreno->beta_ecn); + (uint64_t)beta) / + (100ULL * (uint64_t)beta_ecn); } if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) CCV(ccv, snd_ssthresh) = cwin; @@ -280,7 +288,6 @@ static void newreno_post_recovery(struct cc_var *ccv) { int pipe; - pipe = 0; if (IN_FASTRECOVERY(CCV(ccv, t_flags))) { /* @@ -304,7 +311,7 @@ newreno_post_recovery(struct cc_var *ccv) } } -int +static int newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf) { struct newreno *nreno; @@ -315,9 +322,15 @@ newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf) nreno = ccv->cc_data; opt = buf; - + switch (sopt->sopt_dir) { case SOPT_SET: + /* We cannot set without cc_data memory. */ + if (nreno == NULL) { + nreno = newreno_malloc(ccv); + if (nreno == NULL) + return (ENOMEM); + } switch (opt->name) { case CC_NEWRENO_BETA: nreno->beta = opt->val; @@ -330,17 +343,21 @@ newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf) default: return (ENOPROTOOPT); } + break; case SOPT_GET: switch (opt->name) { case CC_NEWRENO_BETA: - opt->val = nreno->beta; + opt->val = (nreno == NULL) ? + V_newreno_beta : nreno->beta; break; case CC_NEWRENO_BETA_ECN: - opt->val = nreno->beta_ecn; + opt->val = (nreno == NULL) ? + V_newreno_beta_ecn : nreno->beta_ecn; break; default: return (ENOPROTOOPT); } + break; default: return (EINVAL); } @@ -351,6 +368,7 @@ newreno_ctl_output(struct cc_var *ccv, struct sockopt *sopt, void *buf) static int newreno_beta_handler(SYSCTL_HANDLER_ARGS) { + if (req->newptr != NULL ) { if (arg1 == &VNET_NAME(newreno_beta_ecn) && !V_cc_do_abe) return (EACCES); diff --git a/freebsd/sys/netinet/if_ether.c b/freebsd/sys/netinet/if_ether.c index 699af2e4..0d608180 100644 --- a/freebsd/sys/netinet/if_ether.c +++ b/freebsd/sys/netinet/if_ether.c @@ -364,7 +364,7 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip, struct ifaddr *ifa; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET) continue; @@ -696,14 +696,6 @@ arpintr(struct mbuf *m) hlen = ETHER_ADDR_LEN; /* RFC 826 */ layer = "ethernet"; break; - case ARPHRD_IEEE802: - hlen = 6; /* RFC 1390, FDDI_ADDR_LEN */ - layer = "fddi"; - break; - case ARPHRD_ARCNET: - hlen = 1; /* RFC 1201, ARC_ADDR_LEN */ - layer = "arcnet"; - break; case ARPHRD_INFINIBAND: hlen = 20; /* RFC 4391, INFINIBAND_ALEN */ layer = "infiniband"; @@ -896,7 +888,7 @@ in_arpinput(struct mbuf *m) * as a dummy address for the rest of the function. */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_INET && (ifa->ifa_carp == NULL || (*carp_iamatch_p)(ifa, &enaddr))) { @@ -911,7 +903,7 @@ in_arpinput(struct mbuf *m) * If bridging, fall back to using any inet address. */ IN_IFADDR_RLOCK(&in_ifa_tracker); - if (!bridged || (ia = TAILQ_FIRST(&V_in_ifaddrhead)) == NULL) { + if (!bridged || (ia = CK_STAILQ_FIRST(&V_in_ifaddrhead)) == NULL) { IN_IFADDR_RUNLOCK(&in_ifa_tracker); goto drop; } @@ -1455,7 +1447,7 @@ arp_handle_ifllchange(struct ifnet *ifp) { struct ifaddr *ifa; - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == AF_INET) arp_ifinit(ifp, ifa); } diff --git a/freebsd/sys/netinet/igmp.c b/freebsd/sys/netinet/igmp.c index cf319470..a4b99f62 100644 --- a/freebsd/sys/netinet/igmp.c +++ b/freebsd/sys/netinet/igmp.c @@ -138,7 +138,7 @@ static int igmp_v3_enqueue_group_record(struct mbufq *, struct in_multi *, const int, const int, const int); static int igmp_v3_enqueue_filter_change(struct mbufq *, struct in_multi *); -static void igmp_v3_process_group_timers(struct igmp_ifsoftc *, +static void igmp_v3_process_group_timers(struct in_multi_head *, struct mbufq *, struct mbufq *, struct in_multi *, const int); static int igmp_v3_merge_state_changes(struct in_multi *, @@ -164,12 +164,12 @@ static const struct netisr_handler igmp_nh = { * themselves are not virtualized. * * Locking: - * * The permitted lock order is: IN_MULTI_LOCK, IGMP_LOCK, IF_ADDR_LOCK. + * * The permitted lock order is: IN_MULTI_LIST_LOCK, IGMP_LOCK, IF_ADDR_LOCK. * Any may be taken independently; if any are held at the same * time, the above lock order must be followed. * * All output is delegated to the netisr. * Now that Giant has been eliminated, the netisr may be inlined. - * * IN_MULTI_LOCK covers in_multi. + * * IN_MULTI_LIST_LOCK covers in_multi. * * IGMP_LOCK covers igmp_ifsoftc and any global variables in this file, * including the output queue. * * IF_ADDR_LOCK covers if_multiaddrs, which is used for a variety of @@ -443,7 +443,7 @@ sysctl_igmp_ifinfo(SYSCTL_HANDLER_ARGS) if (error) return (error); - IN_MULTI_LOCK(); + IN_MULTI_LIST_LOCK(); IGMP_LOCK(); if (name[0] <= 0 || name[0] > V_if_index) { @@ -477,7 +477,7 @@ sysctl_igmp_ifinfo(SYSCTL_HANDLER_ARGS) out_locked: IGMP_UNLOCK(); - IN_MULTI_UNLOCK(); + IN_MULTI_LIST_UNLOCK(); return (error); } @@ -588,7 +588,6 @@ igi_alloc_locked(/*const*/ struct ifnet *ifp) igi->igi_qi = IGMP_QI_INIT; igi->igi_qri = IGMP_QRI_INIT; igi->igi_uri = IGMP_URI_INIT; - SLIST_INIT(&igi->igi_relinmhead); mbufq_init(&igi->igi_gq, IGMP_MAX_RESPONSE_PACKETS); LIST_INSERT_HEAD(&V_igi_head, igi, igi_link); @@ -613,44 +612,37 @@ void igmp_ifdetach(struct ifnet *ifp) { struct igmp_ifsoftc *igi; - struct ifmultiaddr *ifma; - struct in_multi *inm, *tinm; - + struct ifmultiaddr *ifma, *next; + struct in_multi *inm; + struct in_multi_head inm_free_tmp; CTR3(KTR_IGMPV3, "%s: called for ifp %p(%s)", __func__, ifp, ifp->if_xname); + SLIST_INIT(&inm_free_tmp); IGMP_LOCK(); igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp; if (igi->igi_version == IGMP_VERSION_3) { - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + IF_ADDR_WLOCK(ifp); + restart: + CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { if (ifma->ifma_addr->sa_family != AF_INET || ifma->ifma_protospec == NULL) continue; -#if 0 - KASSERT(ifma->ifma_protospec != NULL, - ("%s: ifma_protospec is NULL", __func__)); -#endif inm = (struct in_multi *)ifma->ifma_protospec; - if (inm->inm_state == IGMP_LEAVING_MEMBER) { - SLIST_INSERT_HEAD(&igi->igi_relinmhead, - inm, inm_nrele); - } + if (inm->inm_state == IGMP_LEAVING_MEMBER) + inm_rele_locked(&inm_free_tmp, inm); inm_clear_recorded(inm); + if (__predict_false(ifma_restart)) { + ifma_restart = false; + goto restart; + } } - IF_ADDR_RUNLOCK(ifp); - /* - * Free the in_multi reference(s) for this IGMP lifecycle. - */ - SLIST_FOREACH_SAFE(inm, &igi->igi_relinmhead, inm_nrele, - tinm) { - SLIST_REMOVE_HEAD(&igi->igi_relinmhead, inm_nrele); - inm_release_locked(inm); - } + IF_ADDR_WUNLOCK(ifp); + inm_release_list_deferred(&inm_free_tmp); } - IGMP_UNLOCK(); + } /* @@ -686,11 +678,6 @@ igi_delete_locked(const struct ifnet *ifp) mbufq_drain(&igi->igi_gq); LIST_REMOVE(igi, igi_link); - - KASSERT(SLIST_EMPTY(&igi->igi_relinmhead), - ("%s: there are dangling in_multi references", - __func__)); - free(igi, M_IGMP); return; } @@ -724,7 +711,7 @@ igmp_input_v1_query(struct ifnet *ifp, const struct ip *ip, } IGMPSTAT_INC(igps_rcv_gen_queries); - IN_MULTI_LOCK(); + IN_MULTI_LIST_LOCK(); IGMP_LOCK(); igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp; @@ -749,7 +736,7 @@ igmp_input_v1_query(struct ifnet *ifp, const struct ip *ip, * except those which are already running. */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_INET || ifma->ifma_protospec == NULL) continue; @@ -780,7 +767,7 @@ igmp_input_v1_query(struct ifnet *ifp, const struct ip *ip, out_locked: IGMP_UNLOCK(); - IN_MULTI_UNLOCK(); + IN_MULTI_LIST_UNLOCK(); return (0); } @@ -818,7 +805,7 @@ igmp_input_v2_query(struct ifnet *ifp, const struct ip *ip, IGMPSTAT_INC(igps_rcv_group_queries); } - IN_MULTI_LOCK(); + IN_MULTI_LIST_LOCK(); IGMP_LOCK(); igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp; @@ -850,7 +837,7 @@ igmp_input_v2_query(struct ifnet *ifp, const struct ip *ip, CTR2(KTR_IGMPV3, "process v2 general query on ifp %p(%s)", ifp, ifp->if_xname); IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_INET || ifma->ifma_protospec == NULL) continue; @@ -874,7 +861,7 @@ igmp_input_v2_query(struct ifnet *ifp, const struct ip *ip, out_locked: IGMP_UNLOCK(); - IN_MULTI_UNLOCK(); + IN_MULTI_LIST_UNLOCK(); return (0); } @@ -901,7 +888,7 @@ igmp_v2_update_group(struct in_multi *inm, const int timer) CTR4(KTR_IGMPV3, "0x%08x: %s/%s timer=%d", __func__, ntohl(inm->inm_addr.s_addr), inm->inm_ifp->if_xname, timer); - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); switch (inm->inm_state) { case IGMP_NOT_MEMBER: @@ -1013,7 +1000,7 @@ igmp_input_v3_query(struct ifnet *ifp, const struct ip *ip, IGMPSTAT_INC(igps_rcv_gsr_queries); } - IN_MULTI_LOCK(); + IN_MULTI_LIST_LOCK(); IGMP_LOCK(); igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp; @@ -1094,7 +1081,7 @@ igmp_input_v3_query(struct ifnet *ifp, const struct ip *ip, out_locked: IGMP_UNLOCK(); - IN_MULTI_UNLOCK(); + IN_MULTI_LIST_UNLOCK(); return (0); } @@ -1111,7 +1098,7 @@ igmp_input_v3_group_query(struct in_multi *inm, struct igmp_ifsoftc *igi, int retval; uint16_t nsrc; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); IGMP_LOCK_ASSERT(); retval = 0; @@ -1233,11 +1220,11 @@ igmp_input_v1_report(struct ifnet *ifp, /*const*/ struct ip *ip, * Replace 0.0.0.0 with the subnet address if told to do so. */ if (V_igmp_recvifkludge && in_nullhost(ip->ip_src)) { + NET_EPOCH_ENTER(); IFP_TO_IA(ifp, ia, &in_ifa_tracker); - if (ia != NULL) { + if (ia != NULL) ip->ip_src.s_addr = htonl(ia->ia_subnet); - ifa_free(&ia->ia_ifa); - } + NET_EPOCH_EXIT(); } CTR3(KTR_IGMPV3, "process v1 report 0x%08x on ifp %p(%s)", @@ -1248,7 +1235,7 @@ igmp_input_v1_report(struct ifnet *ifp, /*const*/ struct ip *ip, * If we are a member of this group, and our membership should be * reported, stop our group timer and transition to the 'lazy' state. */ - IN_MULTI_LOCK(); + IN_MULTI_LIST_LOCK(); inm = inm_lookup(ifp, igmp->igmp_group); if (inm != NULL) { struct igmp_ifsoftc *igi; @@ -1307,7 +1294,7 @@ igmp_input_v1_report(struct ifnet *ifp, /*const*/ struct ip *ip, } out_locked: - IN_MULTI_UNLOCK(); + IN_MULTI_LIST_UNLOCK(); return (0); } @@ -1330,24 +1317,23 @@ igmp_input_v2_report(struct ifnet *ifp, /*const*/ struct ip *ip, * leave requires knowing that we are the only member of a * group. */ + NET_EPOCH_ENTER(); IFP_TO_IA(ifp, ia, &in_ifa_tracker); if (ia != NULL && in_hosteq(ip->ip_src, IA_SIN(ia)->sin_addr)) { - ifa_free(&ia->ia_ifa); + NET_EPOCH_EXIT(); return (0); } IGMPSTAT_INC(igps_rcv_reports); if (ifp->if_flags & IFF_LOOPBACK) { - if (ia != NULL) - ifa_free(&ia->ia_ifa); + NET_EPOCH_EXIT(); return (0); } if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) || !in_hosteq(igmp->igmp_group, ip->ip_dst)) { - if (ia != NULL) - ifa_free(&ia->ia_ifa); + NET_EPOCH_EXIT(); IGMPSTAT_INC(igps_rcv_badreports); return (EINVAL); } @@ -1363,8 +1349,7 @@ igmp_input_v2_report(struct ifnet *ifp, /*const*/ struct ip *ip, if (ia != NULL) ip->ip_src.s_addr = htonl(ia->ia_subnet); } - if (ia != NULL) - ifa_free(&ia->ia_ifa); + NET_EPOCH_EXIT(); CTR3(KTR_IGMPV3, "process v2 report 0x%08x on ifp %p(%s)", ntohl(igmp->igmp_group.s_addr), ifp, ifp->if_xname); @@ -1375,7 +1360,7 @@ igmp_input_v2_report(struct ifnet *ifp, /*const*/ struct ip *ip, * reported, and our group timer is pending or about to be reset, * stop our group timer by transitioning to the 'lazy' state. */ - IN_MULTI_LOCK(); + IN_MULTI_LIST_LOCK(); inm = inm_lookup(ifp, igmp->igmp_group); if (inm != NULL) { struct igmp_ifsoftc *igi; @@ -1420,7 +1405,7 @@ igmp_input_v2_report(struct ifnet *ifp, /*const*/ struct ip *ip, } out_locked: - IN_MULTI_UNLOCK(); + IN_MULTI_LIST_UNLOCK(); return (0); } @@ -1647,8 +1632,9 @@ igmp_fasttimo_vnet(void) struct mbufq qrq; /* Query response packets */ struct ifnet *ifp; struct igmp_ifsoftc *igi; - struct ifmultiaddr *ifma; + struct ifmultiaddr *ifma, *next; struct in_multi *inm; + struct in_multi_head inm_free_tmp; int loop, uri_fasthz; loop = 0; @@ -1664,7 +1650,8 @@ igmp_fasttimo_vnet(void) !V_state_change_timers_running) return; - IN_MULTI_LOCK(); + SLIST_INIT(&inm_free_tmp); + IN_MULTI_LIST_LOCK(); IGMP_LOCK(); /* @@ -1709,8 +1696,9 @@ igmp_fasttimo_vnet(void) mbufq_init(&scq, IGMP_MAX_STATE_CHANGE_PACKETS); } - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + IF_ADDR_WLOCK(ifp); + restart: + CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { if (ifma->ifma_addr->sa_family != AF_INET || ifma->ifma_protospec == NULL) continue; @@ -1722,16 +1710,18 @@ igmp_fasttimo_vnet(void) igi->igi_version); break; case IGMP_VERSION_3: - igmp_v3_process_group_timers(igi, &qrq, + igmp_v3_process_group_timers(&inm_free_tmp, &qrq, &scq, inm, uri_fasthz); break; } + if (__predict_false(ifma_restart)) { + ifma_restart = false; + goto restart; + } } - IF_ADDR_RUNLOCK(ifp); + IF_ADDR_WUNLOCK(ifp); if (igi->igi_version == IGMP_VERSION_3) { - struct in_multi *tinm; - igmp_dispatch_queue(&qrq, 0, loop); igmp_dispatch_queue(&scq, 0, loop); @@ -1739,18 +1729,13 @@ igmp_fasttimo_vnet(void) * Free the in_multi reference(s) for this * IGMP lifecycle. */ - SLIST_FOREACH_SAFE(inm, &igi->igi_relinmhead, - inm_nrele, tinm) { - SLIST_REMOVE_HEAD(&igi->igi_relinmhead, - inm_nrele); - inm_release_locked(inm); - } + inm_release_list_deferred(&inm_free_tmp); } } out_locked: IGMP_UNLOCK(); - IN_MULTI_UNLOCK(); + IN_MULTI_LIST_UNLOCK(); } /* @@ -1762,7 +1747,7 @@ igmp_v1v2_process_group_timer(struct in_multi *inm, const int version) { int report_timer_expired; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); IGMP_LOCK_ASSERT(); if (inm->inm_timer == 0) { @@ -1804,14 +1789,14 @@ igmp_v1v2_process_group_timer(struct in_multi *inm, const int version) * Note: Unlocked read from igi. */ static void -igmp_v3_process_group_timers(struct igmp_ifsoftc *igi, +igmp_v3_process_group_timers(struct in_multi_head *inmh, struct mbufq *qrq, struct mbufq *scq, struct in_multi *inm, const int uri_fasthz) { int query_response_timer_expired; int state_change_retransmit_timer_expired; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); IGMP_LOCK_ASSERT(); query_response_timer_expired = 0; @@ -1861,7 +1846,7 @@ igmp_v3_process_group_timers(struct igmp_ifsoftc *igi, * immediate transmission. */ if (query_response_timer_expired) { - int retval; + int retval __unused; retval = igmp_v3_enqueue_group_record(qrq, inm, 0, 1, (inm->inm_state == IGMP_SG_QUERY_PENDING_MEMBER)); @@ -1909,8 +1894,7 @@ igmp_v3_process_group_timers(struct igmp_ifsoftc *igi, if (inm->inm_state == IGMP_LEAVING_MEMBER && inm->inm_scrv == 0) { inm->inm_state = IGMP_NOT_MEMBER; - SLIST_INSERT_HEAD(&igi->igi_relinmhead, - inm, inm_nrele); + inm_rele_locked(inmh, inm); } } break; @@ -1931,7 +1915,7 @@ static void igmp_v3_suppress_group_record(struct in_multi *inm) { - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); KASSERT(inm->inm_igi->igi_version == IGMP_VERSION_3, ("%s: not IGMPv3 mode on link", __func__)); @@ -2005,13 +1989,15 @@ igmp_v3_cancel_link_timers(struct igmp_ifsoftc *igi) { struct ifmultiaddr *ifma; struct ifnet *ifp; - struct in_multi *inm, *tinm; + struct in_multi *inm; + struct in_multi_head inm_free_tmp; CTR3(KTR_IGMPV3, "%s: cancel v3 timers on ifp %p(%s)", __func__, igi->igi_ifp, igi->igi_ifp->if_xname); - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); IGMP_LOCK_ASSERT(); + SLIST_INIT(&inm_free_tmp); /* * Stop the v3 General Query Response on this link stone dead. @@ -2026,7 +2012,7 @@ igmp_v3_cancel_link_timers(struct igmp_ifsoftc *igi) */ ifp = igi->igi_ifp; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_INET || ifma->ifma_protospec == NULL) continue; @@ -2052,7 +2038,7 @@ igmp_v3_cancel_link_timers(struct igmp_ifsoftc *igi) * message is sent upstream to the old querier -- * transition to NOT would lose the leave and race. */ - SLIST_INSERT_HEAD(&igi->igi_relinmhead, inm, inm_nrele); + inm_rele_locked(&inm_free_tmp, inm); /* FALLTHROUGH */ case IGMP_G_QUERY_PENDING_MEMBER: case IGMP_SG_QUERY_PENDING_MEMBER: @@ -2071,10 +2057,8 @@ igmp_v3_cancel_link_timers(struct igmp_ifsoftc *igi) mbufq_drain(&inm->inm_scq); } IF_ADDR_RUNLOCK(ifp); - SLIST_FOREACH_SAFE(inm, &igi->igi_relinmhead, inm_nrele, tinm) { - SLIST_REMOVE_HEAD(&igi->igi_relinmhead, inm_nrele); - inm_release_locked(inm); - } + + inm_release_list_deferred(&inm_free_tmp); } /* @@ -2201,7 +2185,7 @@ igmp_v1v2_queue_report(struct in_multi *inm, const int type) struct ip *ip; struct mbuf *m; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); IGMP_LOCK_ASSERT(); ifp = inm->inm_ifp; @@ -2278,10 +2262,8 @@ igmp_change_state(struct in_multi *inm) struct ifnet *ifp; int error; - IN_MULTI_LOCK_ASSERT(); - error = 0; - + IN_MULTI_LOCK_ASSERT(); /* * Try to detect if the upper layer just asked us to change state * for an interface which has now gone away. @@ -2381,9 +2363,10 @@ igmp_initial_join(struct in_multi *inm, struct igmp_ifsoftc *igi) * group around for the final INCLUDE {} enqueue. */ if (igi->igi_version == IGMP_VERSION_3 && - inm->inm_state == IGMP_LEAVING_MEMBER) - inm_release_locked(inm); - + inm->inm_state == IGMP_LEAVING_MEMBER) { + MPASS(inm->inm_refcount > 1); + inm_rele_locked(NULL, inm); + } inm->inm_state = IGMP_REPORTING_MEMBER; switch (igi->igi_version) { @@ -2475,7 +2458,7 @@ igmp_handle_state_change(struct in_multi *inm, struct igmp_ifsoftc *igi) ifp = inm->inm_ifp; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); IGMP_LOCK_ASSERT(); KASSERT(igi && igi->igi_ifp == ifp, ("%s: inconsistent ifp", __func__)); @@ -2533,7 +2516,7 @@ igmp_final_leave(struct in_multi *inm, struct igmp_ifsoftc *igi) __func__, ntohl(inm->inm_addr.s_addr), inm->inm_ifp, inm->inm_ifp->if_xname); - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); IGMP_LOCK_ASSERT(); switch (inm->inm_state) { @@ -2579,7 +2562,7 @@ igmp_final_leave(struct in_multi *inm, struct igmp_ifsoftc *igi) inm->inm_state = IGMP_NOT_MEMBER; inm->inm_sctimer = 0; } else { - int retval; + int retval __unused; inm_acquire_locked(inm); @@ -2652,7 +2635,7 @@ igmp_v3_enqueue_group_record(struct mbufq *mq, struct in_multi *inm, struct ifnet *ifp; struct ip_msource *ims, *nims; struct mbuf *m0, *m, *md; - int error, is_filter_list_change; + int is_filter_list_change; int minrec0len, m0srcs, msrcs, nbytes, off; int record_has_sources; int now; @@ -2660,9 +2643,8 @@ igmp_v3_enqueue_group_record(struct mbufq *mq, struct in_multi *inm, in_addr_t naddr; uint8_t mode; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); - error = 0; ifp = inm->inm_ifp; is_filter_list_change = 0; m = NULL; @@ -3020,7 +3002,7 @@ igmp_v3_enqueue_filter_change(struct mbufq *mq, struct in_multi *inm) uint8_t mode, now, then; rectype_t crt, drt, nrt; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); if (inm->inm_nsrc == 0 || (inm->inm_st[0].iss_asm > 0 && inm->inm_st[1].iss_asm > 0)) @@ -3223,7 +3205,7 @@ igmp_v3_merge_state_changes(struct in_multi *inm, struct mbufq *scq) domerge = 0; recslen = 0; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); IGMP_LOCK_ASSERT(); /* @@ -3320,9 +3302,9 @@ igmp_v3_dispatch_general_query(struct igmp_ifsoftc *igi) struct ifmultiaddr *ifma; struct ifnet *ifp; struct in_multi *inm; - int retval, loop; + int retval __unused, loop; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); IGMP_LOCK_ASSERT(); KASSERT(igi->igi_version == IGMP_VERSION_3, @@ -3340,7 +3322,7 @@ igmp_v3_dispatch_general_query(struct igmp_ifsoftc *igi) ifp = igi->igi_ifp; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_INET || ifma->ifma_protospec == NULL) continue; @@ -3544,11 +3526,11 @@ igmp_v3_encap_report(struct ifnet *ifp, struct mbuf *m) if (m->m_flags & M_IGMP_LOOP) { struct in_ifaddr *ia; + NET_EPOCH_ENTER(); IFP_TO_IA(ifp, ia, &in_ifa_tracker); - if (ia != NULL) { + if (ia != NULL) ip->ip_src = ia->ia_addr.sin_addr; - ifa_free(&ia->ia_ifa); - } + NET_EPOCH_EXIT(); } ip->ip_dst.s_addr = htonl(INADDR_ALLRPTS_GROUP); @@ -3634,7 +3616,6 @@ DB_SHOW_COMMAND(igi_list, db_show_igi_list) db_printf(" qi %u\n", igi->igi_qi); db_printf(" qri %u\n", igi->igi_qri); db_printf(" uri %u\n", igi->igi_uri); - /* SLIST_HEAD(,in_multi) igi_relinmhead */ /* struct mbufq igi_gq; */ db_printf("\n"); } diff --git a/freebsd/sys/netinet/igmp_var.h b/freebsd/sys/netinet/igmp_var.h index 4f9db06c..11f086f8 100644 --- a/freebsd/sys/netinet/igmp_var.h +++ b/freebsd/sys/netinet/igmp_var.h @@ -214,7 +214,6 @@ struct igmp_ifsoftc { uint32_t igi_qi; /* IGMPv3 Query Interval (s) */ uint32_t igi_qri; /* IGMPv3 Query Response Interval (s) */ uint32_t igi_uri; /* IGMPv3 Unsolicited Report Interval (s) */ - SLIST_HEAD(,in_multi) igi_relinmhead; /* released groups */ struct mbufq igi_gq; /* general query responses queue */ }; diff --git a/freebsd/sys/netinet/in.c b/freebsd/sys/netinet/in.c index 28c257aa..7233f9a2 100644 --- a/freebsd/sys/netinet/in.c +++ b/freebsd/sys/netinet/in.c @@ -104,7 +104,7 @@ in_localaddr(struct in_addr in) struct in_ifaddr *ia; IN_IFADDR_RLOCK(&in_ifa_tracker); - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if ((i & ia->ia_subnetmask) == ia->ia_subnet) { IN_IFADDR_RUNLOCK(&in_ifa_tracker); return (1); @@ -145,7 +145,7 @@ in_ifhasaddr(struct ifnet *ifp, struct in_addr in) struct in_ifaddr *ia; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET) continue; ia = (struct in_ifaddr *)ifa; @@ -282,7 +282,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, * first one on the interface, if possible. */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET) continue; ia = (struct in_ifaddr *)ifa; @@ -290,7 +290,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, break; } if (ifa == NULL) - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_INET) { ia = (struct in_ifaddr *)ifa; if (prison_check_ip4(td->td_ucred, @@ -381,7 +381,7 @@ in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) iaIsFirst = true; ia = NULL; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { struct in_ifaddr *it; if (ifa->ifa_addr->sa_family != AF_INET) @@ -459,12 +459,12 @@ in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) /* if_addrhead is already referenced by ifa_alloc() */ IF_ADDR_WLOCK(ifp); - TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); + CK_STAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_ref(ifa); /* in_ifaddrhead */ IN_IFADDR_WLOCK(); - TAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link); + CK_STAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link); LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), ia, ia_hash); IN_IFADDR_WUNLOCK(); @@ -537,12 +537,12 @@ fail1: (*carp_detach_p)(&ia->ia_ifa, false); IF_ADDR_WLOCK(ifp); - TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); + CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_free(&ia->ia_ifa); /* if_addrhead */ IN_IFADDR_WLOCK(); - TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link); + CK_STAILQ_REMOVE(&V_in_ifaddrhead, ia, in_ifaddr, ia_link); LIST_REMOVE(ia, ia_hash); IN_IFADDR_WUNLOCK(); ifa_free(&ia->ia_ifa); /* in_ifaddrhead */ @@ -576,7 +576,7 @@ in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) iaIsLast = true; ia = NULL; IF_ADDR_WLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { struct in_ifaddr *it; if (ifa->ifa_addr->sa_family != AF_INET) @@ -601,12 +601,12 @@ in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) return (EADDRNOTAVAIL); } - TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); + CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_free(&ia->ia_ifa); /* if_addrhead */ IN_IFADDR_WLOCK(); - TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link); + CK_STAILQ_REMOVE(&V_in_ifaddrhead, ia, in_ifaddr, ia_link); LIST_REMOVE(ia, ia_hash); IN_IFADDR_WUNLOCK(); @@ -636,12 +636,10 @@ in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td) struct in_ifinfo *ii; ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]); - IN_MULTI_LOCK(); if (ii->ii_allhosts) { - (void)in_leavegroup_locked(ii->ii_allhosts, NULL); + (void)in_leavegroup(ii->ii_allhosts, NULL); ii->ii_allhosts = NULL; } - IN_MULTI_UNLOCK(); } IF_ADDR_WLOCK(ifp); @@ -682,7 +680,7 @@ in_addprefix(struct in_ifaddr *target, int flags) IN_IFADDR_RLOCK(&in_ifa_tracker); /* Look for an existing address with the same prefix, mask, and fib */ - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (rtinitflags(ia)) { p = ia->ia_dstaddr.sin_addr; @@ -842,7 +840,7 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags) } IN_IFADDR_RLOCK(&in_ifa_tracker); - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (rtinitflags(ia)) { p = ia->ia_dstaddr.sin_addr; @@ -918,10 +916,10 @@ in_ifscrub_all(void) struct ifaliasreq ifr; IFNET_RLOCK(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { /* Cannot lock here - lock recursion. */ /* IF_ADDR_RLOCK(ifp); */ - TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { + CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { if (ifa->ifa_addr->sa_family != AF_INET) continue; @@ -982,7 +980,7 @@ in_broadcast(struct in_addr in, struct ifnet *ifp) * with a broadcast address. */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_INET && in_ifaddr_broadcast(in, (struct in_ifaddr *)ifa)) { found = 1; @@ -998,11 +996,12 @@ in_broadcast(struct in_addr in, struct ifnet *ifp) void in_ifdetach(struct ifnet *ifp) { - + IN_MULTI_LOCK(); in_pcbpurgeif0(&V_ripcbinfo, ifp); in_pcbpurgeif0(&V_udbinfo, ifp); in_pcbpurgeif0(&V_ulitecbinfo, ifp); in_purgemaddrs(ifp); + IN_MULTI_UNLOCK(); } /* @@ -1015,12 +1014,12 @@ in_ifdetach(struct ifnet *ifp) static void in_purgemaddrs(struct ifnet *ifp) { - LIST_HEAD(,in_multi) purgeinms; - struct in_multi *inm, *tinm; - struct ifmultiaddr *ifma; + struct in_multi_head purgeinms; + struct in_multi *inm; + struct ifmultiaddr *ifma, *next; - LIST_INIT(&purgeinms); - IN_MULTI_LOCK(); + SLIST_INIT(&purgeinms); + IN_MULTI_LIST_LOCK(); /* * Extract list of in_multi associated with the detaching ifp @@ -1028,27 +1027,24 @@ in_purgemaddrs(struct ifnet *ifp) * We need to do this as IF_ADDR_LOCK() may be re-acquired * by code further down. */ - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + IF_ADDR_WLOCK(ifp); + restart: + CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { if (ifma->ifma_addr->sa_family != AF_INET || ifma->ifma_protospec == NULL) continue; -#if 0 - KASSERT(ifma->ifma_protospec != NULL, - ("%s: ifma_protospec is NULL", __func__)); -#endif inm = (struct in_multi *)ifma->ifma_protospec; - LIST_INSERT_HEAD(&purgeinms, inm, inm_link); + inm_rele_locked(&purgeinms, inm); + if (__predict_false(ifma_restart)) { + ifma_restart = true; + goto restart; + } } - IF_ADDR_RUNLOCK(ifp); + IF_ADDR_WUNLOCK(ifp); - LIST_FOREACH_SAFE(inm, &purgeinms, inm_link, tinm) { - LIST_REMOVE(inm, inm_link); - inm_release_locked(inm); - } + inm_release_list_deferred(&purgeinms); igmp_ifdetach(ifp); - - IN_MULTI_UNLOCK(); + IN_MULTI_LIST_UNLOCK(); } struct in_llentry { @@ -1063,9 +1059,11 @@ struct in_llentry { * Do actual deallocation of @lle. */ static void -in_lltable_destroy_lle_unlocked(struct llentry *lle) +in_lltable_destroy_lle_unlocked(epoch_context_t ctx) { + struct llentry *lle; + lle = __containerof(ctx, struct llentry, lle_epoch_ctx); LLE_LOCK_DESTROY(lle); LLE_REQ_DESTROY(lle); free(lle, M_LLTABLE); @@ -1093,7 +1091,7 @@ in_lltable_destroy_lle(struct llentry *lle) { LLE_WUNLOCK(lle); - in_lltable_destroy_lle_unlocked(lle); + epoch_call(net_epoch_preempt, &lle->lle_epoch_ctx, in_lltable_destroy_lle_unlocked); } static struct llentry * @@ -1160,7 +1158,6 @@ in_lltable_match_prefix(const struct sockaddr *saddr, static void in_lltable_free_entry(struct lltable *llt, struct llentry *lle) { - struct ifnet *ifp; size_t pkts_dropped; LLE_WLOCK_ASSERT(lle); @@ -1168,8 +1165,7 @@ in_lltable_free_entry(struct lltable *llt, struct llentry *lle) /* Unlink entry from table if not already */ if ((lle->la_flags & LLE_LINKED) != 0) { - ifp = llt->llt_ifp; - IF_AFDATA_WLOCK_ASSERT(ifp); + IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp); lltable_unlink_entry(llt, lle); } @@ -1304,7 +1300,7 @@ in_lltable_find_dst(struct lltable *llt, struct in_addr dst) hashidx = in_lltable_hash_dst(dst, llt->llt_hsize); lleh = &llt->lle_head[hashidx]; - LIST_FOREACH(lle, lleh, lle_next) { + CK_LIST_FOREACH(lle, lleh, lle_next) { if (lle->la_flags & LLE_DELETED) continue; if (lle->r_l3addr.addr4.s_addr == dst.s_addr) @@ -1360,7 +1356,7 @@ in_lltable_alloc(struct lltable *llt, u_int flags, const struct sockaddr *l3addr linkhdrsize = LLE_MAX_LINKHDR; if (lltable_calc_llheader(ifp, AF_INET, IF_LLADDR(ifp), linkhdr, &linkhdrsize, &lladdr_off) != 0) { - in_lltable_destroy_lle_unlocked(lle); + epoch_call(net_epoch_preempt, &lle->lle_epoch_ctx, in_lltable_destroy_lle_unlocked); return (NULL); } lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, @@ -1420,52 +1416,51 @@ in_lltable_dump_entry(struct lltable *llt, struct llentry *lle, int error; bzero(&arpc, sizeof(arpc)); - /* skip deleted entries */ - if ((lle->la_flags & LLE_DELETED) == LLE_DELETED) - return (0); - /* Skip if jailed and not a valid IP of the prison. */ - lltable_fill_sa_entry(lle,(struct sockaddr *)&arpc.sin); - if (prison_if(wr->td->td_ucred, - (struct sockaddr *)&arpc.sin) != 0) - return (0); - /* - * produce a msg made of: - * struct rt_msghdr; - * struct sockaddr_in; (IPv4) - * struct sockaddr_dl; - */ - arpc.rtm.rtm_msglen = sizeof(arpc); - arpc.rtm.rtm_version = RTM_VERSION; - arpc.rtm.rtm_type = RTM_GET; - arpc.rtm.rtm_flags = RTF_UP; - arpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; - - /* publish */ - if (lle->la_flags & LLE_PUB) - arpc.rtm.rtm_flags |= RTF_ANNOUNCE; - - sdl = &arpc.sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_len = sizeof(*sdl); - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = ifp->if_type; - if ((lle->la_flags & LLE_VALID) == LLE_VALID) { - sdl->sdl_alen = ifp->if_addrlen; - bcopy(lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); - } else { - sdl->sdl_alen = 0; - bzero(LLADDR(sdl), ifp->if_addrlen); - } + /* skip deleted entries */ + if ((lle->la_flags & LLE_DELETED) == LLE_DELETED) + return (0); + /* Skip if jailed and not a valid IP of the prison. */ + lltable_fill_sa_entry(lle,(struct sockaddr *)&arpc.sin); + if (prison_if(wr->td->td_ucred, (struct sockaddr *)&arpc.sin) != 0) + return (0); + /* + * produce a msg made of: + * struct rt_msghdr; + * struct sockaddr_in; (IPv4) + * struct sockaddr_dl; + */ + arpc.rtm.rtm_msglen = sizeof(arpc); + arpc.rtm.rtm_version = RTM_VERSION; + arpc.rtm.rtm_type = RTM_GET; + arpc.rtm.rtm_flags = RTF_UP; + arpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; + + /* publish */ + if (lle->la_flags & LLE_PUB) + arpc.rtm.rtm_flags |= RTF_ANNOUNCE; + + sdl = &arpc.sdl; + sdl->sdl_family = AF_LINK; + sdl->sdl_len = sizeof(*sdl); + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = ifp->if_type; + if ((lle->la_flags & LLE_VALID) == LLE_VALID) { + sdl->sdl_alen = ifp->if_addrlen; + bcopy(lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); + } else { + sdl->sdl_alen = 0; + bzero(LLADDR(sdl), ifp->if_addrlen); + } - arpc.rtm.rtm_rmx.rmx_expire = - lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; - arpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); - if (lle->la_flags & LLE_STATIC) - arpc.rtm.rtm_flags |= RTF_STATIC; - if (lle->la_flags & LLE_IFADDR) - arpc.rtm.rtm_flags |= RTF_PINNED; - arpc.rtm.rtm_index = ifp->if_index; - error = SYSCTL_OUT(wr, &arpc, sizeof(arpc)); + arpc.rtm.rtm_rmx.rmx_expire = + lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; + arpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); + if (lle->la_flags & LLE_STATIC) + arpc.rtm.rtm_flags |= RTF_STATIC; + if (lle->la_flags & LLE_IFADDR) + arpc.rtm.rtm_flags |= RTF_PINNED; + arpc.rtm.rtm_index = ifp->if_index; + error = SYSCTL_OUT(wr, &arpc, sizeof(arpc)); return (error); } diff --git a/freebsd/sys/netinet/in_mcast.c b/freebsd/sys/netinet/in_mcast.c index 41beed9b..ea4779fc 100644 --- a/freebsd/sys/netinet/in_mcast.c +++ b/freebsd/sys/netinet/in_mcast.c @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/ktr.h> #include <sys/taskqueue.h> +#include <sys/gtaskqueue.h> #include <sys/tree.h> #include <net/if.h> @@ -61,6 +62,8 @@ __FBSDID("$FreeBSD$"); #include <net/route.h> #include <net/vnet.h> +#include <net/ethernet.h> + #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/in_fib.h> @@ -93,17 +96,25 @@ static MALLOC_DEFINE(M_IPMSOURCE, "ip_msource", /* * Locking: - * - Lock order is: Giant, INP_WLOCK, IN_MULTI_LOCK, IGMP_LOCK, IF_ADDR_LOCK. + * - Lock order is: Giant, INP_WLOCK, IN_MULTI_LIST_LOCK, IGMP_LOCK, IF_ADDR_LOCK. * - The IF_ADDR_LOCK is implicitly taken by inm_lookup() earlier, however * it can be taken by code in net/if.c also. * - ip_moptions and in_mfilter are covered by the INP_WLOCK. * - * struct in_multi is covered by IN_MULTI_LOCK. There isn't strictly + * struct in_multi is covered by IN_MULTI_LIST_LOCK. There isn't strictly * any need for in_multi itself to be virtualized -- it is bound to an ifp * anyway no matter what happens. */ -struct mtx in_multi_mtx; -MTX_SYSINIT(in_multi_mtx, &in_multi_mtx, "in_multi_mtx", MTX_DEF); +struct mtx in_multi_list_mtx; +MTX_SYSINIT(in_multi_mtx, &in_multi_list_mtx, "in_multi_list_mtx", MTX_DEF); + +struct mtx in_multi_free_mtx; +MTX_SYSINIT(in_multi_free_mtx, &in_multi_free_mtx, "in_multi_free_mtx", MTX_DEF); + +struct sx in_multi_sx; +SX_SYSINIT(in_multi_sx, &in_multi_sx, "in_multi_sx"); + +int ifma_restart; /* * Functions with non-static linkage defined in this file should be @@ -153,10 +164,9 @@ static int inm_is_ifp_detached(const struct in_multi *); static int inm_merge(struct in_multi *, /*const*/ struct in_mfilter *); static void inm_purge(struct in_multi *); static void inm_reap(struct in_multi *); +static void inm_release(struct in_multi *); static struct ip_moptions * inp_findmoptions(struct inpcb *); -static void inp_freemoptions_internal(struct ip_moptions *); -static void inp_gcmoptions(void *, int); static int inp_get_source_filters(struct inpcb *, struct sockopt *); static int inp_join_group(struct inpcb *, struct sockopt *); static int inp_leave_group(struct inpcb *, struct sockopt *); @@ -189,10 +199,6 @@ static SYSCTL_NODE(_net_inet_ip_mcast, OID_AUTO, filters, CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_ip_mcast_filters, "Per-interface stack-wide source filters"); -static STAILQ_HEAD(, ip_moptions) imo_gc_list = - STAILQ_HEAD_INITIALIZER(imo_gc_list); -static struct task imo_gc_task = TASK_INITIALIZER(0, inp_gcmoptions, NULL); - #ifdef KTR /* * Inline function which wraps assertions for a valid ifp. @@ -218,6 +224,93 @@ inm_is_ifp_detached(const struct in_multi *inm) } #endif +static struct grouptask free_gtask; +static struct in_multi_head inm_free_list; +static void inm_release_task(void *arg __unused); +static void inm_init(void) +{ + SLIST_INIT(&inm_free_list); + taskqgroup_config_gtask_init(NULL, &free_gtask, inm_release_task, "inm release task"); +} + +SYSINIT(inm_init, SI_SUB_SMP + 1, SI_ORDER_FIRST, + inm_init, NULL); + + +void +inm_release_list_deferred(struct in_multi_head *inmh) +{ + + if (SLIST_EMPTY(inmh)) + return; + mtx_lock(&in_multi_free_mtx); + SLIST_CONCAT(&inm_free_list, inmh, in_multi, inm_nrele); + mtx_unlock(&in_multi_free_mtx); + GROUPTASK_ENQUEUE(&free_gtask); +} + +void +inm_disconnect(struct in_multi *inm) +{ + struct ifnet *ifp; + struct ifmultiaddr *ifma, *ll_ifma; + + ifp = inm->inm_ifp; + IF_ADDR_WLOCK_ASSERT(ifp); + ifma = inm->inm_ifma; + + if_ref(ifp); + CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); + MCDPRINTF("removed ifma: %p from %s\n", ifma, ifp->if_xname); + if ((ll_ifma = ifma->ifma_llifma) != NULL) { + MPASS(ifma != ll_ifma); + ifma->ifma_llifma = NULL; + MPASS(ll_ifma->ifma_llifma == NULL); + MPASS(ll_ifma->ifma_ifp == ifp); + if (--ll_ifma->ifma_refcount == 0) { + CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link); + MCDPRINTF("removed ll_ifma: %p from %s\n", ll_ifma, ifp->if_xname); + if_freemulti(ll_ifma); + ifma_restart = true; + } + } +} + +void +inm_release_deferred(struct in_multi *inm) +{ + struct in_multi_head tmp; + + IN_MULTI_LIST_LOCK_ASSERT(); + MPASS(inm->inm_refcount > 0); + if (--inm->inm_refcount == 0) { + SLIST_INIT(&tmp); + inm_disconnect(inm); + inm->inm_ifma->ifma_protospec = NULL; + SLIST_INSERT_HEAD(&tmp, inm, inm_nrele); + inm_release_list_deferred(&tmp); + } +} + +static void +inm_release_task(void *arg __unused) +{ + struct in_multi_head inm_free_tmp; + struct in_multi *inm, *tinm; + + SLIST_INIT(&inm_free_tmp); + mtx_lock(&in_multi_free_mtx); + SLIST_CONCAT(&inm_free_tmp, &inm_free_list, in_multi, inm_nrele); + mtx_unlock(&in_multi_free_mtx); + IN_MULTI_LOCK(); + SLIST_FOREACH_SAFE(inm, &inm_free_tmp, inm_nrele, tinm) { + SLIST_REMOVE_HEAD(&inm_free_tmp, inm_nrele); + MPASS(inm); + inm_release(inm); + } + IN_MULTI_UNLOCK(); +} + /* * Initialize an in_mfilter structure to a known state at t0, t1 * with an empty source filter list. @@ -234,7 +327,7 @@ imf_init(struct in_mfilter *imf, const int st0, const int st1) /* * Function for looking up an in_multi record for an IPv4 multicast address * on a given interface. ifp must be valid. If no record found, return NULL. - * The IN_MULTI_LOCK and IF_ADDR_LOCK on ifp must be held. + * The IN_MULTI_LIST_LOCK and IF_ADDR_LOCK on ifp must be held. */ struct in_multi * inm_lookup_locked(struct ifnet *ifp, const struct in_addr ina) @@ -242,17 +335,18 @@ inm_lookup_locked(struct ifnet *ifp, const struct in_addr ina) struct ifmultiaddr *ifma; struct in_multi *inm; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); IF_ADDR_LOCK_ASSERT(ifp); inm = NULL; - TAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) { - if (ifma->ifma_addr->sa_family == AF_INET) { - inm = (struct in_multi *)ifma->ifma_protospec; - if (inm->inm_addr.s_addr == ina.s_addr) - break; - inm = NULL; - } + CK_STAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) { + if (ifma->ifma_addr->sa_family != AF_INET || + ifma->ifma_protospec == NULL) + continue; + inm = (struct in_multi *)ifma->ifma_protospec; + if (inm->inm_addr.s_addr == ina.s_addr) + break; + inm = NULL; } return (inm); } @@ -266,7 +360,7 @@ inm_lookup(struct ifnet *ifp, const struct in_addr ina) { struct in_multi *inm; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); IF_ADDR_RLOCK(ifp); inm = inm_lookup_locked(ifp, ina); IF_ADDR_RUNLOCK(ifp); @@ -453,7 +547,7 @@ in_getmulti(struct ifnet *ifp, const struct in_addr *group, IN_MULTI_LOCK_ASSERT(); ii = (struct in_ifinfo *)ifp->if_afdata[AF_INET]; - + IN_MULTI_LIST_LOCK(); inm = inm_lookup(ifp, *group); if (inm != NULL) { /* @@ -462,11 +556,13 @@ in_getmulti(struct ifnet *ifp, const struct in_addr *group, */ KASSERT(inm->inm_refcount >= 1, ("%s: bad refcount %d", __func__, inm->inm_refcount)); - ++inm->inm_refcount; + inm_acquire_locked(inm); *pinm = inm; - return (0); } - + IN_MULTI_LIST_UNLOCK(); + if (inm != NULL) + return (0); + memset(&gsin, 0, sizeof(gsin)); gsin.sin_family = AF_INET; gsin.sin_len = sizeof(struct sockaddr_in); @@ -481,6 +577,7 @@ in_getmulti(struct ifnet *ifp, const struct in_addr *group, return (error); /* XXX ifma_protospec must be covered by IF_ADDR_LOCK */ + IN_MULTI_LIST_LOCK(); IF_ADDR_WLOCK(ifp); /* @@ -506,10 +603,9 @@ in_getmulti(struct ifnet *ifp, const struct in_addr *group, __func__, ifma, inm, inet_ntoa_r(*group, addrbuf)); } #endif - ++inm->inm_refcount; + inm_acquire_locked(inm); *pinm = inm; - IF_ADDR_WUNLOCK(ifp); - return (0); + goto out_locked; } IF_ADDR_WLOCK_ASSERT(ifp); @@ -524,6 +620,7 @@ in_getmulti(struct ifnet *ifp, const struct in_addr *group, inm = malloc(sizeof(*inm), M_IPMADDR, M_NOWAIT | M_ZERO); if (inm == NULL) { IF_ADDR_WUNLOCK(ifp); + IN_MULTI_LIST_UNLOCK(); if_delmulti_ifma(ifma); return (ENOMEM); } @@ -541,8 +638,9 @@ in_getmulti(struct ifnet *ifp, const struct in_addr *group, ifma->ifma_protospec = inm; *pinm = inm; - + out_locked: IF_ADDR_WUNLOCK(ifp); + IN_MULTI_LIST_UNLOCK(); return (0); } @@ -552,36 +650,33 @@ in_getmulti(struct ifnet *ifp, const struct in_addr *group, * If the refcount drops to 0, free the in_multi record and * delete the underlying link-layer membership. */ -void -inm_release_locked(struct in_multi *inm) +static void +inm_release(struct in_multi *inm) { struct ifmultiaddr *ifma; - - IN_MULTI_LOCK_ASSERT(); + struct ifnet *ifp; CTR2(KTR_IGMPV3, "%s: refcount is %d", __func__, inm->inm_refcount); - - if (--inm->inm_refcount > 0) { - CTR2(KTR_IGMPV3, "%s: refcount is now %d", __func__, - inm->inm_refcount); - return; - } - + MPASS(inm->inm_refcount == 0); CTR2(KTR_IGMPV3, "%s: freeing inm %p", __func__, inm); ifma = inm->inm_ifma; + ifp = inm->inm_ifp; /* XXX this access is not covered by IF_ADDR_LOCK */ CTR2(KTR_IGMPV3, "%s: purging ifma %p", __func__, ifma); - KASSERT(ifma->ifma_protospec == inm, - ("%s: ifma_protospec != inm", __func__)); - ifma->ifma_protospec = NULL; - - inm_purge(inm); - - free(inm, M_IPMADDR); - - if_delmulti_ifma(ifma); + if (ifp != NULL) { + CURVNET_SET(ifp->if_vnet); + inm_purge(inm); + free(inm, M_IPMADDR); + if_delmulti_ifma_flags(ifma, 1); + CURVNET_RESTORE(); + if_rele(ifp); + } else { + inm_purge(inm); + free(inm, M_IPMADDR); + if_delmulti_ifma_flags(ifma, 1); + } } /* @@ -594,7 +689,7 @@ inm_clear_recorded(struct in_multi *inm) { struct ip_msource *ims; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) { if (ims->ims_stp) { @@ -634,7 +729,7 @@ inm_record_source(struct in_multi *inm, const in_addr_t naddr) struct ip_msource find; struct ip_msource *ims, *nims; - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); find.ims_haddr = ntohl(naddr); ims = RB_FIND(ip_msource_tree, &inm->inm_srcs, &find); @@ -961,6 +1056,7 @@ inm_merge(struct in_multi *inm, /*const*/ struct in_mfilter *imf) schanged = 0; error = 0; nsrc1 = nsrc0 = 0; + IN_MULTI_LIST_LOCK_ASSERT(); /* * Update the source filters first, as this may fail. @@ -1167,6 +1263,7 @@ in_joingroup_locked(struct ifnet *ifp, const struct in_addr *gina, int error; IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_UNLOCK_ASSERT(); CTR4(KTR_IGMPV3, "%s: join 0x%08x on %p(%s))", __func__, ntohl(gina->s_addr), ifp, ifp->if_xname); @@ -1188,7 +1285,7 @@ in_joingroup_locked(struct ifnet *ifp, const struct in_addr *gina, CTR1(KTR_IGMPV3, "%s: in_getmulti() failure", __func__); return (error); } - + IN_MULTI_LIST_LOCK(); CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); error = inm_merge(inm, imf); if (error) { @@ -1203,13 +1300,15 @@ in_joingroup_locked(struct ifnet *ifp, const struct in_addr *gina, goto out_inm_release; } -out_inm_release: + out_inm_release: if (error) { + CTR2(KTR_IGMPV3, "%s: dropping ref on %p", __func__, inm); - inm_release_locked(inm); + inm_release_deferred(inm); } else { *pinm = inm; } + IN_MULTI_LIST_UNLOCK(); return (error); } @@ -1251,6 +1350,7 @@ in_leavegroup_locked(struct in_multi *inm, /*const*/ struct in_mfilter *imf) error = 0; IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_UNLOCK_ASSERT(); CTR5(KTR_IGMPV3, "%s: leave inm %p, 0x%08x/%s, imf %p", __func__, inm, ntohl(inm->inm_addr.s_addr), @@ -1274,18 +1374,22 @@ in_leavegroup_locked(struct in_multi *inm, /*const*/ struct in_mfilter *imf) * the transaction, it MUST NOT fail. */ CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); + IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); KASSERT(error == 0, ("%s: failed to merge inm state", __func__)); CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); CURVNET_SET(inm->inm_ifp->if_vnet); error = igmp_change_state(inm); + IF_ADDR_WLOCK(inm->inm_ifp); + inm_release_deferred(inm); + IF_ADDR_WUNLOCK(inm->inm_ifp); + IN_MULTI_LIST_UNLOCK(); CURVNET_RESTORE(); if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); CTR2(KTR_IGMPV3, "%s: dropping ref on %p", __func__, inm); - inm_release_locked(inm); return (error); } @@ -1317,18 +1421,6 @@ in_addmulti(struct in_addr *ap, struct ifnet *ifp) } /* - * Leave an IPv4 multicast group, assumed to be in exclusive (*,G) mode. - * This KPI is for legacy kernel consumers only. - */ -void -in_delmulti(struct in_multi *inm) -{ - - (void)in_leavegroup(inm, NULL); -} -/*#endif*/ - -/* * Block or unblock an ASM multicast source on an inpcb. * This implements the delta-based API described in RFC 3678. * @@ -1489,7 +1581,7 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) * Begin state merge transaction at IGMP layer. */ IN_MULTI_LOCK(); - + IN_MULTI_LIST_LOCK(); CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); error = inm_merge(inm, imf); if (error) { @@ -1505,7 +1597,7 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) out_in_multi_locked: IN_MULTI_UNLOCK(); - + IN_MULTI_UNLOCK(); out_imf_rollback: if (error) imf_rollback(imf); @@ -1571,37 +1663,31 @@ inp_findmoptions(struct inpcb *inp) return (imo); } -/* - * Discard the IP multicast options (and source filters). To minimize - * the amount of work done while holding locks such as the INP's - * pcbinfo lock (which is used in the receive path), the free - * operation is performed asynchronously in a separate task. - * - * SMPng: NOTE: assumes INP write lock is held. - */ -void -inp_freemoptions(struct ip_moptions *imo) -{ - - KASSERT(imo != NULL, ("%s: ip_moptions is NULL", __func__)); - IN_MULTI_LOCK(); - STAILQ_INSERT_TAIL(&imo_gc_list, imo, imo_link); - IN_MULTI_UNLOCK(); - taskqueue_enqueue(taskqueue_thread, &imo_gc_task); -} - static void -inp_freemoptions_internal(struct ip_moptions *imo) +inp_gcmoptions(epoch_context_t ctx) { + struct ip_moptions *imo; struct in_mfilter *imf; + struct in_multi *inm; + struct ifnet *ifp; size_t idx, nmships; + imo = __containerof(ctx, struct ip_moptions, imo_epoch_ctx); + nmships = imo->imo_num_memberships; for (idx = 0; idx < nmships; ++idx) { imf = imo->imo_mfilters ? &imo->imo_mfilters[idx] : NULL; if (imf) imf_leave(imf); - (void)in_leavegroup(imo->imo_membership[idx], imf); + inm = imo->imo_membership[idx]; + ifp = inm->inm_ifp; + if (ifp != NULL) { + CURVNET_SET(ifp->if_vnet); + (void)in_leavegroup(inm, imf); + CURVNET_RESTORE(); + } else { + (void)in_leavegroup(inm, imf); + } if (imf) imf_purge(imf); } @@ -1612,20 +1698,18 @@ inp_freemoptions_internal(struct ip_moptions *imo) free(imo, M_IPMOPTS); } -static void -inp_gcmoptions(void *context, int pending) +/* + * Discard the IP multicast options (and source filters). To minimize + * the amount of work done while holding locks such as the INP's + * pcbinfo lock (which is used in the receive path), the free + * operation is deferred to the epoch callback task. + */ +void +inp_freemoptions(struct ip_moptions *imo) { - struct ip_moptions *imo; - - IN_MULTI_LOCK(); - while (!STAILQ_EMPTY(&imo_gc_list)) { - imo = STAILQ_FIRST(&imo_gc_list); - STAILQ_REMOVE_HEAD(&imo_gc_list, imo_link); - IN_MULTI_UNLOCK(); - inp_freemoptions_internal(imo); - IN_MULTI_LOCK(); - } - IN_MULTI_UNLOCK(); + if (imo == NULL) + return; + epoch_call(net_epoch_preempt, &imo->imo_epoch_ctx, inp_gcmoptions); } /* @@ -1794,12 +1878,12 @@ inp_getmoptions(struct inpcb *inp, struct sockopt *sopt) mreqn.imr_address = imo->imo_multicast_addr; } else if (ifp != NULL) { mreqn.imr_ifindex = ifp->if_index; + NET_EPOCH_ENTER(); IFP_TO_IA(ifp, ia, &in_ifa_tracker); - if (ia != NULL) { + if (ia != NULL) mreqn.imr_address = IA_SIN(ia)->sin_addr; - ifa_free(&ia->ia_ifa); - } + NET_EPOCH_EXIT(); } } INP_WUNLOCK(inp); @@ -1907,7 +1991,7 @@ inp_lookup_mcast_ifp(const struct inpcb *inp, mifp = NULL; IN_IFADDR_RLOCK(&in_ifa_tracker); - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { mifp = ia->ia_ifp; if (!(mifp->if_flags & IFF_LOOPBACK) && (mifp->if_flags & IFF_MULTICAST)) { @@ -2165,6 +2249,8 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at IGMP layer. */ + in_pcbref(inp); + INP_WUNLOCK(inp); IN_MULTI_LOCK(); if (is_new) { @@ -2173,20 +2259,23 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: in_joingroup_locked failed", __func__); - IN_MULTI_UNLOCK(); + IN_MULTI_LIST_UNLOCK(); goto out_imo_free; } imo->imo_membership[idx] = inm; } else { CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); + IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", - __func__); + __func__); + IN_MULTI_LIST_UNLOCK(); goto out_in_multi_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); error = igmp_change_state(inm); + IN_MULTI_LIST_UNLOCK(); if (error) { CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); @@ -2197,8 +2286,9 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) out_in_multi_locked: IN_MULTI_UNLOCK(); - - INP_WLOCK_ASSERT(inp); + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) + return (ENXIO); if (error) { imf_rollback(imf); if (is_new) @@ -2387,6 +2477,8 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at IGMP layer. */ + in_pcbref(inp); + INP_WUNLOCK(inp); IN_MULTI_LOCK(); if (is_final) { @@ -2397,6 +2489,7 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) (void)in_leavegroup_locked(inm, imf); } else { CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); + IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", @@ -2406,6 +2499,7 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); error = igmp_change_state(inm); + IN_MULTI_LIST_UNLOCK(); if (error) { CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); @@ -2415,6 +2509,9 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) out_in_multi_locked: IN_MULTI_UNLOCK(); + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) + return (ENXIO); if (error) imf_rollback(imf); @@ -2641,6 +2738,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) INP_WLOCK_ASSERT(inp); IN_MULTI_LOCK(); + IN_MULTI_LIST_LOCK(); /* * Begin state merge transaction at IGMP layer. @@ -2649,11 +2747,13 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) error = inm_merge(inm, imf); if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); + IN_MULTI_LIST_UNLOCK(); goto out_in_multi_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); error = igmp_change_state(inm); + IN_MULTI_LIST_UNLOCK(); if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); @@ -2885,10 +2985,10 @@ sysctl_ip_mcast_filters(SYSCTL_HANDLER_ARGS) if (retval) return (retval); - IN_MULTI_LOCK(); + IN_MULTI_LIST_LOCK(); IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_INET || ifma->ifma_protospec == NULL) continue; @@ -2918,7 +3018,7 @@ sysctl_ip_mcast_filters(SYSCTL_HANDLER_ARGS) } IF_ADDR_RUNLOCK(ifp); - IN_MULTI_UNLOCK(); + IN_MULTI_LIST_UNLOCK(); return (retval); } diff --git a/freebsd/sys/netinet/in_pcb.c b/freebsd/sys/netinet/in_pcb.c index 0d388132..f89487b6 100644 --- a/freebsd/sys/netinet/in_pcb.c +++ b/freebsd/sys/netinet/in_pcb.c @@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$"); #include <sys/domain.h> #include <sys/protosw.h> #include <sys/rmlock.h> +#include <sys/smp.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/sockio.h> @@ -93,6 +94,9 @@ __FBSDID("$FreeBSD$"); #include <netinet/in_pcb.h> #include <netinet/ip_var.h> #include <netinet/tcp_var.h> +#ifdef TCPHPTS +#include <netinet/tcp_hpts.h> +#endif #include <netinet/udp.h> #include <netinet/udp_var.h> #endif @@ -590,7 +594,7 @@ in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, INP_LOCK_ASSERT(inp); INP_HASH_LOCK_ASSERT(pcbinfo); - if (TAILQ_EMPTY(&V_in_ifaddrhead)) /* XXX broken! */ + if (CK_STAILQ_EMPTY(&V_in_ifaddrhead)) /* XXX broken! */ return (EADDRNOTAVAIL); laddr.s_addr = *laddrp; if (nam != NULL && laddr.s_addr != INADDR_ANY) @@ -802,7 +806,6 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, int error; KASSERT(laddr != NULL, ("%s: laddr NULL", __func__)); - /* * Bypass source address selection and use the primary jail IP * if requested. @@ -835,15 +838,18 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, * network and try to find a corresponding interface to take * the source address from. */ + NET_EPOCH_ENTER(); if (sro.ro_rt == NULL || sro.ro_rt->rt_ifp == NULL) { struct in_ifaddr *ia; struct ifnet *ifp; ia = ifatoia(ifa_ifwithdstaddr((struct sockaddr *)sin, inp->inp_socket->so_fibnum)); - if (ia == NULL) + if (ia == NULL) { ia = ifatoia(ifa_ifwithnet((struct sockaddr *)sin, 0, inp->inp_socket->so_fibnum)); + + } if (ia == NULL) { error = ENETUNREACH; goto done; @@ -851,15 +857,13 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, if (cred == NULL || !prison_flag(cred, PR_IP4)) { laddr->s_addr = ia->ia_addr.sin_addr.s_addr; - ifa_free(&ia->ia_ifa); goto done; } ifp = ia->ia_ifp; - ifa_free(&ia->ia_ifa); ia = NULL; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { sa = ifa->ifa_addr; if (sa->sa_family != AF_INET) @@ -918,7 +922,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, ia = NULL; ifp = sro.ro_rt->rt_ifp; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { sa = ifa->ifa_addr; if (sa->sa_family != AF_INET) continue; @@ -972,7 +976,6 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, goto done; } laddr->s_addr = ia->ia_addr.sin_addr.s_addr; - ifa_free(&ia->ia_ifa); goto done; } @@ -981,10 +984,9 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, struct ifnet *ifp; ifp = ia->ia_ifp; - ifa_free(&ia->ia_ifa); ia = NULL; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { sa = ifa->ifa_addr; if (sa->sa_family != AF_INET) @@ -1010,6 +1012,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, } done: + NET_EPOCH_EXIT(); if (sro.ro_rt != NULL) RTFREE(sro.ro_rt); return (error); @@ -1063,7 +1066,7 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, faddr = sin->sin_addr; fport = sin->sin_port; - if (!TAILQ_EMPTY(&V_in_ifaddrhead)) { + if (!CK_STAILQ_EMPTY(&V_in_ifaddrhead)) { /* * If the destination address is INADDR_ANY, * use the primary local address. @@ -1074,16 +1077,16 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, if (faddr.s_addr == INADDR_ANY) { IN_IFADDR_RLOCK(&in_ifa_tracker); faddr = - IA_SIN(TAILQ_FIRST(&V_in_ifaddrhead))->sin_addr; + IA_SIN(CK_STAILQ_FIRST(&V_in_ifaddrhead))->sin_addr; IN_IFADDR_RUNLOCK(&in_ifa_tracker); if (cred != NULL && (error = prison_get_ip4(cred, &faddr)) != 0) return (error); } else if (faddr.s_addr == (u_long)INADDR_BROADCAST) { IN_IFADDR_RLOCK(&in_ifa_tracker); - if (TAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags & + if (CK_STAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags & IFF_BROADCAST) - faddr = satosin(&TAILQ_FIRST( + faddr = satosin(&CK_STAILQ_FIRST( &V_in_ifaddrhead)->ia_broadaddr)->sin_addr; IN_IFADDR_RUNLOCK(&in_ifa_tracker); } @@ -1104,7 +1107,7 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam, if (imo->imo_multicast_ifp != NULL) { ifp = imo->imo_multicast_ifp; IN_IFADDR_RLOCK(&in_ifa_tracker); - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if ((ia->ia_ifp == ifp) && (cred == NULL || prison_check_ip4(cred, @@ -1236,9 +1239,28 @@ in_pcbrele_rlocked(struct inpcb *inp) } return (0); } - + KASSERT(inp->inp_socket == NULL, ("%s: inp_socket != NULL", __func__)); - +#ifdef TCPHPTS + if (inp->inp_in_hpts || inp->inp_in_input) { + struct tcp_hpts_entry *hpts; + /* + * We should not be on the hpts at + * this point in any form. we must + * get the lock to be sure. + */ + hpts = tcp_hpts_lock(inp); + if (inp->inp_in_hpts) + panic("Hpts:%p inp:%p at free still on hpts", + hpts, inp); + mtx_unlock(&hpts->p_mtx); + hpts = tcp_input_lock(inp); + if (inp->inp_in_input) + panic("Hpts:%p inp:%p at free still on input hpts", + hpts, inp); + mtx_unlock(&hpts->p_mtx); + } +#endif INP_RUNLOCK(inp); pcbinfo = inp->inp_pcbinfo; uma_zfree(pcbinfo->ipi_zone, inp); @@ -1267,7 +1289,26 @@ in_pcbrele_wlocked(struct inpcb *inp) } KASSERT(inp->inp_socket == NULL, ("%s: inp_socket != NULL", __func__)); - +#ifdef TCPHPTS + if (inp->inp_in_hpts || inp->inp_in_input) { + struct tcp_hpts_entry *hpts; + /* + * We should not be on the hpts at + * this point in any form. we must + * get the lock to be sure. + */ + hpts = tcp_hpts_lock(inp); + if (inp->inp_in_hpts) + panic("Hpts:%p inp:%p at free still on hpts", + hpts, inp); + mtx_unlock(&hpts->p_mtx); + hpts = tcp_input_lock(inp); + if (inp->inp_in_input) + panic("Hpts:%p inp:%p at free still on input hpts", + hpts, inp); + mtx_unlock(&hpts->p_mtx); + } +#endif INP_WUNLOCK(inp); pcbinfo = inp->inp_pcbinfo; uma_zfree(pcbinfo->ipi_zone, inp); @@ -1284,6 +1325,28 @@ in_pcbrele(struct inpcb *inp) return (in_pcbrele_wlocked(inp)); } +void +in_pcblist_rele_rlocked(epoch_context_t ctx) +{ + struct in_pcblist *il; + struct inpcb *inp; + struct inpcbinfo *pcbinfo; + int i, n; + + il = __containerof(ctx, struct in_pcblist, il_epoch_ctx); + pcbinfo = il->il_pcbinfo; + n = il->il_count; + INP_INFO_WLOCK(pcbinfo); + for (i = 0; i < n; i++) { + inp = il->il_inp_list[i]; + INP_RLOCK(inp); + if (!in_pcbrele_rlocked(inp)) + INP_RUNLOCK(inp); + } + INP_INFO_WUNLOCK(pcbinfo); + free(il, M_TEMP); +} + /* * Unconditionally schedule an inpcb to be freed by decrementing its * reference count, which should occur only after the inpcb has been detached @@ -1298,8 +1361,21 @@ in_pcbfree(struct inpcb *inp) { struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; +#ifdef INET6 + struct ip6_moptions *im6o = NULL; +#endif +#ifdef INET + struct ip_moptions *imo = NULL; +#endif KASSERT(inp->inp_socket == NULL, ("%s: inp_socket != NULL", __func__)); + KASSERT((inp->inp_flags2 & INP_FREED) == 0, + ("%s: called twice for pcb %p", __func__, inp)); + if (inp->inp_flags2 & INP_FREED) { + INP_WUNLOCK(inp); + return; + } + #ifdef INVARIANTS if (pcbinfo == &V_tcbinfo) { INP_INFO_LOCK_ASSERT(pcbinfo); @@ -1309,6 +1385,10 @@ in_pcbfree(struct inpcb *inp) #endif INP_WLOCK_ASSERT(inp); +#ifdef INET + imo = inp->inp_moptions; + inp->inp_moptions = NULL; +#endif /* XXXRW: Do as much as possible here. */ #if defined(IPSEC) || defined(IPSEC_SUPPORT) if (inp->inp_sp != NULL) @@ -1321,16 +1401,12 @@ in_pcbfree(struct inpcb *inp) #ifdef INET6 if (inp->inp_vflag & INP_IPV6PROTO) { ip6_freepcbopts(inp->in6p_outputopts); - if (inp->in6p_moptions != NULL) - ip6_freemoptions(inp->in6p_moptions); + im6o = inp->in6p_moptions; + inp->in6p_moptions = NULL; } #endif if (inp->inp_options) (void)m_free(inp->inp_options); -#ifdef INET - if (inp->inp_moptions != NULL) - inp_freemoptions(inp->inp_moptions); -#endif RO_INVALIDATE_CACHE(&inp->inp_route); inp->inp_vflag = 0; @@ -1339,6 +1415,12 @@ in_pcbfree(struct inpcb *inp) #ifdef MAC mac_inpcb_destroy(inp); #endif +#ifdef INET6 + ip6_freemoptions(im6o); +#endif +#ifdef INET + inp_freemoptions(imo); +#endif if (!in_pcbrele_wlocked(inp)) INP_WUNLOCK(inp); } @@ -1492,11 +1574,14 @@ in_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) /* * Drop multicast group membership if we joined * through the interface being detached. + * + * XXX This can all be deferred to an epoch_call */ for (i = 0, gap = 0; i < imo->imo_num_memberships; i++) { if (imo->imo_membership[i]->inm_ifp == ifp) { - in_delmulti(imo->imo_membership[i]); + IN_MULTI_LOCK_ASSERT(); + in_leavegroup_locked(imo->imo_membership[i], NULL); gap++; } else if (gap != 0) imo->imo_membership[i - gap] = diff --git a/freebsd/sys/netinet/in_pcb.h b/freebsd/sys/netinet/in_pcb.h index 574ab407..d00dd456 100644 --- a/freebsd/sys/netinet/in_pcb.h +++ b/freebsd/sys/netinet/in_pcb.h @@ -41,6 +41,7 @@ #define _NETINET_IN_PCB_H_ #include <sys/queue.h> +#include <sys/epoch.h> #include <sys/_lock.h> #include <sys/_mutex.h> #include <sys/_rwlock.h> @@ -156,6 +157,7 @@ struct in_conninfo { * from the global list. * * Key: + * (b) - Protected by the hpts lock. * (c) - Constant after initialization * (g) - Protected by the pcbgroup lock * (i) - Protected by the inpcb lock @@ -164,6 +166,51 @@ struct in_conninfo { * (h) - Protected by the pcbhash lock for the inpcb * (s) - Protected by another subsystem's locks * (x) - Undefined locking + * + * Notes on the tcp_hpts: + * + * First Hpts lock order is + * 1) INP_WLOCK() + * 2) HPTS_LOCK() i.e. hpts->pmtx + * + * To insert a TCB on the hpts you *must* be holding the INP_WLOCK(). + * You may check the inp->inp_in_hpts flag without the hpts lock. + * The hpts is the only one that will clear this flag holding + * only the hpts lock. This means that in your tcp_output() + * routine when you test for the inp_in_hpts flag to be 1 + * it may be transitioning to 0 (by the hpts). + * That's ok since that will just mean an extra call to tcp_output + * that most likely will find the call you executed + * (when the mis-match occured) will have put the TCB back + * on the hpts and it will return. If your + * call did not add the inp back to the hpts then you will either + * over-send or the cwnd will block you from sending more. + * + * Note you should also be holding the INP_WLOCK() when you + * call the remove from the hpts as well. Though usually + * you are either doing this from a timer, where you need and have + * the INP_WLOCK() or from destroying your TCB where again + * you should already have the INP_WLOCK(). + * + * The inp_hpts_cpu, inp_hpts_cpu_set, inp_input_cpu and + * inp_input_cpu_set fields are controlled completely by + * the hpts. Do not ever set these. The inp_hpts_cpu_set + * and inp_input_cpu_set fields indicate if the hpts has + * setup the respective cpu field. It is advised if this + * field is 0, to enqueue the packet with the appropriate + * hpts_immediate() call. If the _set field is 1, then + * you may compare the inp_*_cpu field to the curcpu and + * may want to again insert onto the hpts if these fields + * are not equal (i.e. you are not on the expected CPU). + * + * A note on inp_hpts_calls and inp_input_calls, these + * flags are set when the hpts calls either the output + * or do_segment routines respectively. If the routine + * being called wants to use this, then it needs to + * clear the flag before returning. The hpts will not + * clear the flag. The flags can be used to tell if + * the hpts is the function calling the respective + * routine. * * A few other notes: * @@ -190,14 +237,45 @@ struct inpcb { LIST_ENTRY(inpcb) inp_pcbgrouphash; /* (g/i) hash list */ struct rwlock inp_lock; /* Cache line #2 (amd64) */ -#define inp_start_zero inp_refcount +#define inp_start_zero inp_hpts #define inp_zero_size (sizeof(struct inpcb) - \ offsetof(struct inpcb, inp_start_zero)) + TAILQ_ENTRY(inpcb) inp_hpts; /* pacing out queue next lock(b) */ + + uint32_t inp_hpts_request; /* Current hpts request, zero if + * fits in the pacing window (i&b). */ + /* + * Note the next fields are protected by a + * different lock (hpts-lock). This means that + * they must correspond in size to the smallest + * protectable bit field (uint8_t on x86, and + * other platfomrs potentially uint32_t?). Also + * since CPU switches can occur at different times the two + * fields can *not* be collapsed into a signal bit field. + */ +#if defined(__amd64__) || defined(__i386__) + volatile uint8_t inp_in_hpts; /* on output hpts (lock b) */ + volatile uint8_t inp_in_input; /* on input hpts (lock b) */ +#else + volatile uint32_t inp_in_hpts; /* on output hpts (lock b) */ + volatile uint32_t inp_in_input; /* on input hpts (lock b) */ +#endif + volatile uint16_t inp_hpts_cpu; /* Lock (i) */ u_int inp_refcount; /* (i) refcount */ int inp_flags; /* (i) generic IP/datagram flags */ int inp_flags2; /* (i) generic IP/datagram flags #2*/ + volatile uint16_t inp_input_cpu; /* Lock (i) */ + volatile uint8_t inp_hpts_cpu_set :1, /* on output hpts (i) */ + inp_input_cpu_set : 1, /* on input hpts (i) */ + inp_hpts_calls :1, /* (i) from output hpts */ + inp_input_calls :1, /* (i) from input hpts */ + inp_spare_bits2 : 4; + uint8_t inp_spare_byte; /* Compiler hole */ void *inp_ppcb; /* (i) pointer to per-protocol pcb */ struct socket *inp_socket; /* (i) back pointer to socket */ + uint32_t inp_hptsslot; /* Hpts wheel slot this tcb is Lock(i&b) */ + uint32_t inp_hpts_drop_reas; /* reason we are dropping the PCB (lock i&b) */ + TAILQ_ENTRY(inpcb) inp_input; /* pacing in queue next lock(b) */ struct inpcbinfo *inp_pcbinfo; /* (c) PCB list info */ struct inpcbgroup *inp_pcbgroup; /* (g/i) PCB group list */ LIST_ENTRY(inpcb) inp_pcbgroup_wild; /* (g/i/h) group wildcard entry */ @@ -330,6 +408,13 @@ struct inpcbport { u_short phd_port; }; +struct in_pcblist { + int il_count; + struct epoch_context il_epoch_ctx; + struct inpcbinfo *il_pcbinfo; + struct inpcb *il_inp_list[0]; +}; + /*- * Global data structure for each high-level protocol (UDP, TCP, ...) in both * IPv4 and IPv6. Holds inpcb lists and information for managing them. @@ -638,6 +723,7 @@ short inp_so_options(const struct inpcb *inp); #define INP_RECVRSSBUCKETID 0x00000200 /* populate recv datagram with bucket id */ #define INP_RATE_LIMIT_CHANGED 0x00000400 /* rate limit needs attention */ #define INP_ORIGDSTADDR 0x00000800 /* receive IP dst address/port */ +#define INP_CANNOT_DO_ECN 0x00001000 /* The stack does not do ECN */ /* * Flags passed to in_pcblookup*() functions. @@ -751,6 +837,7 @@ void in_pcbrehash_mbuf(struct inpcb *, struct mbuf *); int in_pcbrele(struct inpcb *); int in_pcbrele_rlocked(struct inpcb *); int in_pcbrele_wlocked(struct inpcb *); +void in_pcblist_rele_rlocked(epoch_context_t ctx); void in_losing(struct inpcb *); void in_pcbsetsolabel(struct socket *so); int in_getpeeraddr(struct socket *so, struct sockaddr **nam); diff --git a/freebsd/sys/netinet/in_proto.c b/freebsd/sys/netinet/in_proto.c index f1dec6c5..a563c950 100644 --- a/freebsd/sys/netinet/in_proto.c +++ b/freebsd/sys/netinet/in_proto.c @@ -229,7 +229,6 @@ struct protosw inetsw[] = { .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, .pr_input = encap4_input, .pr_ctloutput = rip_ctloutput, - .pr_init = encap_init, .pr_usrreqs = &rip_usrreqs }, { @@ -239,7 +238,6 @@ struct protosw inetsw[] = { .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, .pr_input = encap4_input, .pr_ctloutput = rip_ctloutput, - .pr_init = encap_init, .pr_usrreqs = &rip_usrreqs }, { @@ -249,7 +247,6 @@ struct protosw inetsw[] = { .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, .pr_input = encap4_input, .pr_ctloutput = rip_ctloutput, - .pr_init = encap_init, .pr_usrreqs = &rip_usrreqs }, { @@ -259,7 +256,6 @@ struct protosw inetsw[] = { .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, .pr_input = encap4_input, .pr_ctloutput = rip_ctloutput, - .pr_init = encap_init, .pr_usrreqs = &rip_usrreqs }, # ifdef INET6 @@ -270,7 +266,6 @@ struct protosw inetsw[] = { .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, .pr_input = encap4_input, .pr_ctloutput = rip_ctloutput, - .pr_init = encap_init, .pr_usrreqs = &rip_usrreqs }, #endif diff --git a/freebsd/sys/netinet/in_var.h b/freebsd/sys/netinet/in_var.h index ff722fc9..5b7a464b 100644 --- a/freebsd/sys/netinet/in_var.h +++ b/freebsd/sys/netinet/in_var.h @@ -55,6 +55,7 @@ struct in_aliasreq { struct igmp_ifsoftc; struct in_multi; struct lltable; +SLIST_HEAD(in_multi_head, in_multi); /* * IPv4 per-interface state. @@ -79,7 +80,7 @@ struct in_ifaddr { u_long ia_subnet; /* subnet address */ u_long ia_subnetmask; /* mask of subnet */ LIST_ENTRY(in_ifaddr) ia_hash; /* entry in bucket of inet addresses */ - TAILQ_ENTRY(in_ifaddr) ia_link; /* list of internet addresses */ + CK_STAILQ_ENTRY(in_ifaddr) ia_link; /* list of internet addresses */ struct sockaddr_in ia_addr; /* reserve space for interface name */ struct sockaddr_in ia_dstaddr; /* reserve space for broadcast addr */ #define ia_broadaddr ia_dstaddr @@ -106,7 +107,7 @@ extern u_char inetctlerrmap[]; /* * Hash table for IP addresses. */ -TAILQ_HEAD(in_ifaddrhead, in_ifaddr); +CK_STAILQ_HEAD(in_ifaddrhead, in_ifaddr); LIST_HEAD(in_ifaddrhashhead, in_ifaddr); VNET_DECLARE(struct in_ifaddrhashhead *, in_ifaddrhashtbl); @@ -171,12 +172,10 @@ do { \ /* struct rm_priotracker *t; */ \ do { \ IN_IFADDR_RLOCK((t)); \ - for ((ia) = TAILQ_FIRST(&V_in_ifaddrhead); \ + for ((ia) = CK_STAILQ_FIRST(&V_in_ifaddrhead); \ (ia) != NULL && (ia)->ia_ifp != (ifp); \ - (ia) = TAILQ_NEXT((ia), ia_link)) \ + (ia) = CK_STAILQ_NEXT((ia), ia_link)) \ continue; \ - if ((ia) != NULL) \ - ifa_ref(&(ia)->ia_ifa); \ IN_IFADDR_RUNLOCK((t)); \ } while (0) @@ -329,21 +328,53 @@ SYSCTL_DECL(_net_inet_raw); * consumers of IN_*_MULTI() macros should acquire the locks before * calling them; users of the in_{add,del}multi() functions should not. */ -extern struct mtx in_multi_mtx; -#define IN_MULTI_LOCK() mtx_lock(&in_multi_mtx) -#define IN_MULTI_UNLOCK() mtx_unlock(&in_multi_mtx) -#define IN_MULTI_LOCK_ASSERT() mtx_assert(&in_multi_mtx, MA_OWNED) -#define IN_MULTI_UNLOCK_ASSERT() mtx_assert(&in_multi_mtx, MA_NOTOWNED) +extern struct mtx in_multi_list_mtx; +extern struct sx in_multi_sx; + +#define IN_MULTI_LIST_LOCK() mtx_lock(&in_multi_list_mtx) +#define IN_MULTI_LIST_UNLOCK() mtx_unlock(&in_multi_list_mtx) +#define IN_MULTI_LIST_LOCK_ASSERT() mtx_assert(&in_multi_list_mtx, MA_OWNED) +#define IN_MULTI_LIST_UNLOCK_ASSERT() mtx_assert(&in_multi_list_mtx, MA_NOTOWNED) + +#define IN_MULTI_LOCK() sx_xlock(&in_multi_sx) +#define IN_MULTI_UNLOCK() sx_xunlock(&in_multi_sx) +#define IN_MULTI_LOCK_ASSERT() sx_assert(&in_multi_sx, SA_XLOCKED) +#define IN_MULTI_UNLOCK_ASSERT() sx_assert(&in_multi_sx, SA_XUNLOCKED) + +void inm_disconnect(struct in_multi *inm); +extern int ifma_restart; /* Acquire an in_multi record. */ static __inline void inm_acquire_locked(struct in_multi *inm) { - IN_MULTI_LOCK_ASSERT(); + IN_MULTI_LIST_LOCK_ASSERT(); ++inm->inm_refcount; } +static __inline void +inm_acquire(struct in_multi *inm) +{ + IN_MULTI_LIST_LOCK(); + inm_acquire_locked(inm); + IN_MULTI_LIST_UNLOCK(); +} + +static __inline void +inm_rele_locked(struct in_multi_head *inmh, struct in_multi *inm) +{ + MPASS(inm->inm_refcount > 0); + IN_MULTI_LIST_LOCK_ASSERT(); + + if (--inm->inm_refcount == 0) { + MPASS(inmh != NULL); + inm_disconnect(inm); + inm->inm_ifma->ifma_protospec = NULL; + SLIST_INSERT_HEAD(inmh, inm, inm_nrele); + } +} + /* * Return values for imo_multi_filter(). */ @@ -364,11 +395,10 @@ void inm_commit(struct in_multi *); void inm_clear_recorded(struct in_multi *); void inm_print(const struct in_multi *); int inm_record_source(struct in_multi *inm, const in_addr_t); -void inm_release(struct in_multi *); -void inm_release_locked(struct in_multi *); +void inm_release_deferred(struct in_multi *); +void inm_release_list_deferred(struct in_multi_head *); struct in_multi * - in_addmulti(struct in_addr *, struct ifnet *); -void in_delmulti(struct in_multi *); +in_addmulti(struct in_addr *, struct ifnet *); int in_joingroup(struct ifnet *, const struct in_addr *, /*const*/ struct in_mfilter *, struct in_multi **); int in_joingroup_locked(struct ifnet *, const struct in_addr *, diff --git a/freebsd/sys/netinet/ip_carp.c b/freebsd/sys/netinet/ip_carp.c index e2bd0a0a..6f5160e0 100644 --- a/freebsd/sys/netinet/ip_carp.c +++ b/freebsd/sys/netinet/ip_carp.c @@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$"); #include <sys/counter.h> #include <net/ethernet.h> -#include <net/fddi.h> #include <net/if.h> #include <net/if_var.h> #include <net/if_dl.h> @@ -213,11 +212,13 @@ static VNET_DEFINE(int, carp_senderr_adj) = CARP_MAXSKEW; static VNET_DEFINE(int, carp_ifdown_adj) = CARP_MAXSKEW; #define V_carp_ifdown_adj VNET(carp_ifdown_adj) +static int carp_allow_sysctl(SYSCTL_HANDLER_ARGS); static int carp_demote_adj_sysctl(SYSCTL_HANDLER_ARGS); SYSCTL_NODE(_net_inet, IPPROTO_CARP, carp, CTLFLAG_RW, 0, "CARP"); -SYSCTL_INT(_net_inet_carp, OID_AUTO, allow, CTLFLAG_VNET | CTLFLAG_RW, - &VNET_NAME(carp_allow), 0, "Accept incoming CARP packets"); +SYSCTL_PROC(_net_inet_carp, OID_AUTO, allow, + CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW, 0, 0, carp_allow_sysctl, "I", + "Accept incoming CARP packets"); SYSCTL_INT(_net_inet_carp, OID_AUTO, preempt, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(carp_preempt), 0, "High-priority backup preemption mode"); SYSCTL_INT(_net_inet_carp, OID_AUTO, log, CTLFLAG_VNET | CTLFLAG_RW, @@ -277,8 +278,7 @@ SYSCTL_VNET_PCPUSTAT(_net_inet_carp, OID_AUTO, stats, struct carpstats, } while (0) #define IFNET_FOREACH_IFA(ifp, ifa) \ - IF_ADDR_LOCK_ASSERT(ifp); \ - TAILQ_FOREACH((ifa), &(ifp)->if_addrhead, ifa_link) \ + CK_STAILQ_FOREACH((ifa), &(ifp)->if_addrhead, ifa_link) \ if ((ifa)->ifa_carp != NULL) #define CARP_FOREACH_IFA(sc, ifa) \ @@ -879,7 +879,7 @@ carp_best_ifa(int af, struct ifnet *ifp) return (NULL); best = NULL; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == af && (best == NULL || ifa_preferred(best, ifa))) best = ifa; @@ -1161,7 +1161,7 @@ carp_iamatch6(struct ifnet *ifp, struct in6_addr *taddr) ifa = NULL; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (!IN6_ARE_ADDR_EQUAL(taddr, IFA_IN6(ifa))) @@ -1294,7 +1294,8 @@ carp_setrun(struct carp_softc *sc, sa_family_t af) if ((sc->sc_carpdev->if_flags & IFF_UP) == 0 || sc->sc_carpdev->if_link_state != LINK_STATE_UP || - (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0)) + (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) || + !V_carp_allow) return; switch (sc->sc_state) { @@ -1408,7 +1409,7 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) break; } in6m = NULL; - if ((error = in6_mc_join(ifp, &in6, NULL, &in6m, 0)) != 0) { + if ((error = in6_joingroup(ifp, &in6, NULL, &in6m, 0)) != 0) { free(im6o->im6o_membership, M_CARP); break; } @@ -1423,13 +1424,13 @@ carp_multicast_setup(struct carp_if *cif, sa_family_t sa) in6.s6_addr32[3] = 0; in6.s6_addr8[12] = 0xff; if ((error = in6_setscope(&in6, ifp, NULL)) != 0) { - in6_mc_leave(im6o->im6o_membership[0], NULL); + in6_leavegroup(im6o->im6o_membership[0], NULL); free(im6o->im6o_membership, M_CARP); break; } in6m = NULL; - if ((error = in6_mc_join(ifp, &in6, NULL, &in6m, 0)) != 0) { - in6_mc_leave(im6o->im6o_membership[0], NULL); + if ((error = in6_joingroup(ifp, &in6, NULL, &in6m, 0)) != 0) { + in6_leavegroup(im6o->im6o_membership[0], NULL); free(im6o->im6o_membership, M_CARP); break; } @@ -1472,8 +1473,8 @@ carp_multicast_cleanup(struct carp_if *cif, sa_family_t sa) if (cif->cif_naddrs6 == 0) { struct ip6_moptions *im6o = &cif->cif_im6o; - in6_mc_leave(im6o->im6o_membership[0], NULL); - in6_mc_leave(im6o->im6o_membership[1], NULL); + in6_leavegroup(im6o->im6o_membership[0], NULL); + in6_leavegroup(im6o->im6o_membership[1], NULL); KASSERT(im6o->im6o_mfilters == NULL, ("%s: im6o_mfilters != NULL", __func__)); free(im6o->im6o_membership, M_CARP); @@ -1528,18 +1529,6 @@ carp_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa) eh->ether_shost[5] = sc->sc_vhid; } break; - case IFT_FDDI: { - struct fddi_header *fh; - - fh = mtod(m, struct fddi_header *); - fh->fddi_shost[0] = 0; - fh->fddi_shost[1] = 0; - fh->fddi_shost[2] = 0x5e; - fh->fddi_shost[3] = 0; - fh->fddi_shost[4] = 1; - fh->fddi_shost[5] = sc->sc_vhid; - } - break; default: printf("%s: carp is not supported for the %d interface type\n", ifp->if_xname, ifp->if_type); @@ -1721,7 +1710,6 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td) case IFT_ETHER: case IFT_L2VLAN: case IFT_BRIDGE: - case IFT_FDDI: break; default: error = EOPNOTSUPP; @@ -2057,7 +2045,8 @@ carp_sc_state(struct carp_softc *sc) CARP_LOCK_ASSERT(sc); if (sc->sc_carpdev->if_link_state != LINK_STATE_UP || - !(sc->sc_carpdev->if_flags & IFF_UP)) { + !(sc->sc_carpdev->if_flags & IFF_UP) || + !V_carp_allow) { callout_stop(&sc->sc_ad_tmo); #ifdef INET callout_stop(&sc->sc_md_tmo); @@ -2088,6 +2077,33 @@ carp_demote_adj(int adj, char *reason) } static int +carp_allow_sysctl(SYSCTL_HANDLER_ARGS) +{ + int new, error; + struct carp_softc *sc; + + new = V_carp_allow; + error = sysctl_handle_int(oidp, &new, 0, req); + if (error || !req->newptr) + return (error); + + if (V_carp_allow != new) { + V_carp_allow = new; + + mtx_lock(&carp_mtx); + LIST_FOREACH(sc, &carp_list, sc_next) { + CARP_LOCK(sc); + if (curvnet == sc->sc_carpdev->if_vnet) + carp_sc_state(sc); + CARP_UNLOCK(sc); + } + mtx_unlock(&carp_mtx); + } + + return (0); +} + +static int carp_demote_adj_sysctl(SYSCTL_HANDLER_ARGS) { int new, error; diff --git a/freebsd/sys/netinet/ip_divert.c b/freebsd/sys/netinet/ip_divert.c index 53a0445e..84f39023 100644 --- a/freebsd/sys/netinet/ip_divert.c +++ b/freebsd/sys/netinet/ip_divert.c @@ -76,7 +76,6 @@ __FBSDID("$FreeBSD$"); #endif #include <security/mac/mac_framework.h> - /* * Divert sockets */ @@ -237,7 +236,7 @@ divert_packet(struct mbuf *m, int incoming) /* Find IP address for receive interface */ ifp = m->m_pkthdr.rcvif; if_addr_rlock(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET) continue; divsrc.sin_addr = @@ -471,13 +470,15 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin, bzero(sin->sin_zero, sizeof(sin->sin_zero)); sin->sin_port = 0; + NET_EPOCH_ENTER(); ifa = ifa_ifwithaddr((struct sockaddr *) sin); if (ifa == NULL) { error = EADDRNOTAVAIL; + NET_EPOCH_EXIT(); goto cantsend; } m->m_pkthdr.rcvif = ifa->ifa_ifp; - ifa_free(ifa); + NET_EPOCH_EXIT(); } #ifdef MAC mac_socket_create_mbuf(so, m); @@ -553,6 +554,7 @@ div_detach(struct socket *so) KASSERT(inp != NULL, ("div_detach: inp == NULL")); INP_INFO_WLOCK(&V_divcbinfo); INP_WLOCK(inp); + /* XXX defer destruction to epoch_call */ in_pcbdetach(inp); in_pcbfree(inp); INP_INFO_WUNLOCK(&V_divcbinfo); @@ -632,6 +634,7 @@ static int div_pcblist(SYSCTL_HANDLER_ARGS) { int error, i, n; + struct in_pcblist *il; struct inpcb *inp, **inp_list; inp_gen_t gencnt; struct xinpgen xig; @@ -671,9 +674,8 @@ div_pcblist(SYSCTL_HANDLER_ARGS) if (error) return error; - inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); - if (inp_list == NULL) - return ENOMEM; + il = malloc(sizeof(struct in_pcblist) + n * sizeof(struct inpcb *), M_TEMP, M_WAITOK|M_ZERO_INVARIANTS); + inp_list = il->il_inp_list; INP_INFO_RLOCK(&V_divcbinfo); for (inp = LIST_FIRST(V_divcbinfo.ipi_listhead), i = 0; inp && i < n; @@ -702,14 +704,9 @@ div_pcblist(SYSCTL_HANDLER_ARGS) } else INP_RUNLOCK(inp); } - INP_INFO_WLOCK(&V_divcbinfo); - for (i = 0; i < n; i++) { - inp = inp_list[i]; - INP_RLOCK(inp); - if (!in_pcbrele_rlocked(inp)) - INP_RUNLOCK(inp); - } - INP_INFO_WUNLOCK(&V_divcbinfo); + il->il_count = n; + il->il_pcbinfo = &V_divcbinfo; + epoch_call(net_epoch_preempt, &il->il_epoch_ctx, in_pcblist_rele_rlocked); if (!error) { /* @@ -726,7 +723,6 @@ div_pcblist(SYSCTL_HANDLER_ARGS) INP_INFO_RUNLOCK(&V_divcbinfo); error = SYSCTL_OUT(req, &xig, sizeof xig); } - free(inp_list, M_TEMP); return error; } @@ -806,6 +802,7 @@ div_modevent(module_t mod, int type, void *unused) break; } ip_divert_ptr = NULL; + /* XXX defer to epoch_call ? */ err = pf_proto_unregister(PF_INET, IPPROTO_DIVERT, SOCK_RAW); INP_INFO_WUNLOCK(&V_divcbinfo); #ifndef VIMAGE diff --git a/freebsd/sys/netinet/ip_encap.c b/freebsd/sys/netinet/ip_encap.c index d0866b00..52cd0b40 100644 --- a/freebsd/sys/netinet/ip_encap.c +++ b/freebsd/sys/netinet/ip_encap.c @@ -110,15 +110,6 @@ static struct mtx encapmtx; MTX_SYSINIT(encapmtx, &encapmtx, "encapmtx", MTX_DEF); static LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(encaptab); -/* - * We currently keey encap_init() for source code compatibility reasons -- - * it's referenced by KAME pieces in netinet6. - */ -void -encap_init(void) -{ -} - #ifdef INET int encap4_input(struct mbuf **mp, int *offp, int proto) diff --git a/freebsd/sys/netinet/ip_encap.h b/freebsd/sys/netinet/ip_encap.h index bbbee390..ef232189 100644 --- a/freebsd/sys/netinet/ip_encap.h +++ b/freebsd/sys/netinet/ip_encap.h @@ -50,7 +50,6 @@ struct encaptab { void *arg; /* passed via m->m_pkthdr.aux */ }; -void encap_init(void); int encap4_input(struct mbuf **, int *, int); int encap6_input(struct mbuf **, int *, int); const struct encaptab *encap_attach(int, int, const struct sockaddr *, diff --git a/freebsd/sys/netinet/ip_icmp.c b/freebsd/sys/netinet/ip_icmp.c index b03fea56..3fc59a14 100644 --- a/freebsd/sys/netinet/ip_icmp.c +++ b/freebsd/sys/netinet/ip_icmp.c @@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/tcpip.h> #include <netinet/icmp_var.h> + #ifdef INET #include <machine/in_cksum.h> @@ -407,6 +408,7 @@ icmp_input(struct mbuf **mp, int *offp, int proto) inet_ntoa_r(ip->ip_dst, dstbuf), icmplen); } #endif + NET_EPOCH_ENTER(); if (icmplen < ICMP_MINLEN) { ICMPSTAT_INC(icps_tooshort); goto freeit; @@ -414,6 +416,7 @@ icmp_input(struct mbuf **mp, int *offp, int proto) i = hlen + min(icmplen, ICMP_ADVLENMIN); if (m->m_len < i && (m = m_pullup(m, i)) == NULL) { ICMPSTAT_INC(icps_tooshort); + NET_EPOCH_EXIT(); return (IPPROTO_DONE); } ip = mtod(m, struct ip *); @@ -531,6 +534,7 @@ icmp_input(struct mbuf **mp, int *offp, int proto) if (m->m_len < i && (m = m_pullup(m, i)) == NULL) { /* This should actually not happen */ ICMPSTAT_INC(icps_tooshort); + NET_EPOCH_EXIT(); return (IPPROTO_DONE); } ip = mtod(m, struct ip *); @@ -606,10 +610,8 @@ icmp_input(struct mbuf **mp, int *offp, int proto) (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif); if (ia == NULL) break; - if (ia->ia_ifp == NULL) { - ifa_free(&ia->ia_ifa); + if (ia->ia_ifp == NULL) break; - } icp->icmp_type = ICMP_MASKREPLY; if (V_icmpmaskfake == 0) icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; @@ -621,11 +623,11 @@ icmp_input(struct mbuf **mp, int *offp, int proto) else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; } - ifa_free(&ia->ia_ifa); reflect: ICMPSTAT_INC(icps_reflect); ICMPSTAT_INC(icps_outhist[icp->icmp_type]); icmp_reflect(m); + NET_EPOCH_EXIT(); return (IPPROTO_DONE); case ICMP_REDIRECT: @@ -702,11 +704,13 @@ reflect: } raw: + NET_EPOCH_EXIT(); *mp = m; rip_input(mp, offp, proto); return (IPPROTO_DONE); freeit: + NET_EPOCH_EXIT(); m_freem(m); return (IPPROTO_DONE); } @@ -762,7 +766,7 @@ icmp_reflect(struct mbuf *m) ifp = m->m_pkthdr.rcvif; if (ifp != NULL && ifp->if_flags & IFF_BROADCAST) { IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET) continue; ia = ifatoia(ifa); @@ -783,7 +787,7 @@ icmp_reflect(struct mbuf *m) */ if (V_icmp_rfi && ifp != NULL) { IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET) continue; ia = ifatoia(ifa); @@ -801,7 +805,7 @@ icmp_reflect(struct mbuf *m) */ if (V_reply_src[0] != '\0' && (ifp = ifunit(V_reply_src))) { IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET) continue; ia = ifatoia(ifa); diff --git a/freebsd/sys/netinet/ip_input.c b/freebsd/sys/netinet/ip_input.c index 2c8bf427..343eec5e 100644 --- a/freebsd/sys/netinet/ip_input.c +++ b/freebsd/sys/netinet/ip_input.c @@ -306,7 +306,7 @@ ip_init(void) struct protosw *pr; int i; - TAILQ_INIT(&V_in_ifaddrhead); + CK_STAILQ_INIT(&V_in_ifaddrhead); V_in_ifaddrhashtbl = hashinit(INADDR_NHASH, M_IFADDR, &V_in_ifaddrhmask); /* Initialize IP reassembly queue. */ @@ -401,7 +401,7 @@ ip_destroy(void *unused __unused) /* Make sure the IPv4 routes are gone as well. */ IFNET_RLOCK(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) rt_flushifroutes_af(ifp, AF_INET); IFNET_RUNLOCK(); @@ -652,7 +652,7 @@ passin: * we receive might be for us (and let the upper layers deal * with it). */ - if (TAILQ_EMPTY(&V_in_ifaddrhead) && + if (CK_STAILQ_EMPTY(&V_in_ifaddrhead) && (m->m_flags & (M_MCAST|M_BCAST)) == 0) goto ours; @@ -709,7 +709,7 @@ passin: */ if (ifp != NULL && ifp->if_flags & IFF_BROADCAST) { IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET) continue; ia = ifatoia(ifa); @@ -979,9 +979,9 @@ ip_forward(struct mbuf *m, int srcrt) #else in_rtalloc_ign(&ro, 0, M_GETFIB(m)); #endif + NET_EPOCH_ENTER(); if (ro.ro_rt != NULL) { ia = ifatoia(ro.ro_rt->rt_ifa); - ifa_ref(&ia->ia_ifa); } else ia = NULL; /* @@ -1027,7 +1027,7 @@ ip_forward(struct mbuf *m, int srcrt) m_freem(mcopy); if (error != EINPROGRESS) IPSTAT_INC(ips_cantforward); - return; + goto out; } /* No IPsec processing required */ } @@ -1080,16 +1080,12 @@ ip_forward(struct mbuf *m, int srcrt) else { if (mcopy) m_freem(mcopy); - if (ia != NULL) - ifa_free(&ia->ia_ifa); - return; + goto out; } } - if (mcopy == NULL) { - if (ia != NULL) - ifa_free(&ia->ia_ifa); - return; - } + if (mcopy == NULL) + goto out; + switch (error) { @@ -1131,13 +1127,11 @@ ip_forward(struct mbuf *m, int srcrt) case ENOBUFS: case EACCES: /* ipfw denied packet */ m_freem(mcopy); - if (ia != NULL) - ifa_free(&ia->ia_ifa); - return; + goto out; } - if (ia != NULL) - ifa_free(&ia->ia_ifa); icmp_error(mcopy, type, code, dest.s_addr, mtu); + out: + NET_EPOCH_EXIT(); } #define CHECK_SO_CT(sp, ct) \ diff --git a/freebsd/sys/netinet/ip_mroute.c b/freebsd/sys/netinet/ip_mroute.c index 3bf4fa91..ac901601 100644 --- a/freebsd/sys/netinet/ip_mroute.c +++ b/freebsd/sys/netinet/ip_mroute.c @@ -880,13 +880,15 @@ add_vif(struct vifctl *vifcp) ifp = NULL; } else { sin.sin_addr = vifcp->vifc_lcl_addr; + NET_EPOCH_ENTER(); ifa = ifa_ifwithaddr((struct sockaddr *)&sin); if (ifa == NULL) { + NET_EPOCH_EXIT(); VIF_UNLOCK(); return EADDRNOTAVAIL; } ifp = ifa->ifa_ifp; - ifa_free(ifa); + NET_EPOCH_EXIT(); } if ((vifcp->vifc_flags & VIFF_TUNNEL) != 0) { @@ -1682,7 +1684,7 @@ send_packet(struct vif *vifp, struct mbuf *m) { struct ip_moptions imo; struct in_multi *imm[2]; - int error; + int error __unused; VIF_LOCK_ASSERT(); diff --git a/freebsd/sys/netinet/ip_options.c b/freebsd/sys/netinet/ip_options.c index d85aecf3..cc2f3eed 100644 --- a/freebsd/sys/netinet/ip_options.c +++ b/freebsd/sys/netinet/ip_options.c @@ -112,6 +112,7 @@ ip_dooptions(struct mbuf *m, int pass) struct nhop4_extended nh_ext; struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; + NET_EPOCH_ENTER(); /* Ignore or reject packets with IP options. */ if (V_ip_doopts == 0) return 0; @@ -226,6 +227,7 @@ dropit: #endif IPSTAT_INC(ips_cantforward); m_freem(m); + NET_EPOCH_EXIT(); return (1); } } @@ -252,7 +254,6 @@ dropit: memcpy(cp + off, &(IA_SIN(ia)->sin_addr), sizeof(struct in_addr)); - ifa_free(&ia->ia_ifa); } else { /* XXX MRT 0 for routing */ if (fib4_lookup_nh_ext(M_GETFIB(m), @@ -300,7 +301,6 @@ dropit: if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) != NULL) { memcpy(cp + off, &(IA_SIN(ia)->sin_addr), sizeof(struct in_addr)); - ifa_free(&ia->ia_ifa); } else if (fib4_lookup_nh_ext(M_GETFIB(m), ipaddr.sin_addr, 0, 0, &nh_ext) == 0) { memcpy(cp + off, &nh_ext.nh_src, @@ -355,7 +355,6 @@ dropit: continue; (void)memcpy(sin, &IA_SIN(ia)->sin_addr, sizeof(struct in_addr)); - ifa_free(&ia->ia_ifa); cp[IPOPT_OFFSET] += sizeof(struct in_addr); off += sizeof(struct in_addr); break; @@ -383,12 +382,14 @@ dropit: cp[IPOPT_OFFSET] += sizeof(uint32_t); } } + NET_EPOCH_EXIT(); if (forward && V_ipforwarding) { ip_forward(m, 1); return (1); } return (0); bad: + NET_EPOCH_EXIT(); icmp_error(m, type, code, 0, 0); IPSTAT_INC(ips_badoptions); return (1); diff --git a/freebsd/sys/netinet/ip_output.c b/freebsd/sys/netinet/ip_output.c index 21b3919a..792f2311 100644 --- a/freebsd/sys/netinet/ip_output.c +++ b/freebsd/sys/netinet/ip_output.c @@ -227,7 +227,6 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, struct route iproute; struct rtentry *rte; /* cache for ro->ro_rt */ uint32_t fibnum; - int have_ia_ref; #if defined(IPSEC) || defined(IPSEC_SUPPORT) int no_route_but_check_spd = 0; #endif @@ -283,6 +282,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, dst->sin_len = sizeof(*dst); dst->sin_addr = ip->ip_dst; } + NET_EPOCH_ENTER(); again: /* * Validate route against routing table additions; @@ -308,7 +308,6 @@ again: rte = NULL; } ia = NULL; - have_ia_ref = 0; /* * If routing to interface only, short circuit routing lookup. * The use of an all-ones broadcast address implies this; an @@ -324,7 +323,6 @@ again: error = ENETUNREACH; goto bad; } - have_ia_ref = 1; ip->ip_dst.s_addr = INADDR_BROADCAST; dst->sin_addr = ip->ip_dst; ifp = ia->ia_ifp; @@ -339,7 +337,6 @@ again: error = ENETUNREACH; goto bad; } - have_ia_ref = 1; ifp = ia->ia_ifp; ip->ip_ttl = 1; isbroadcast = ifp->if_flags & IFF_BROADCAST ? @@ -352,8 +349,6 @@ again: */ ifp = imo->imo_multicast_ifp; IFP_TO_IA(ifp, ia, &in_ifa_tracker); - if (ia) - have_ia_ref = 1; isbroadcast = 0; /* fool gcc */ } else { /* @@ -581,8 +576,6 @@ sendit: case -1: /* Need to try again */ /* Reset everything for a new round */ RO_RTFREE(ro); - if (have_ia_ref) - ifa_free(&ia->ia_ifa); ro->ro_prepend = NULL; rte = NULL; gw = dst; @@ -737,10 +730,9 @@ done: * calling RTFREE on it again. */ ro->ro_rt = NULL; - if (have_ia_ref) - ifa_free(&ia->ia_ifa); + NET_EPOCH_EXIT(); return (error); -bad: + bad: m_freem(m); goto done; } diff --git a/freebsd/sys/netinet/ip_var.h b/freebsd/sys/netinet/ip_var.h index 9e7ee591..f874628a 100644 --- a/freebsd/sys/netinet/ip_var.h +++ b/freebsd/sys/netinet/ip_var.h @@ -36,6 +36,7 @@ #define _NETINET_IP_VAR_H_ #include <sys/queue.h> +#include <sys/epoch.h> /* * Overlay for ip header used by other protocols (tcp, udp). @@ -95,7 +96,7 @@ struct ip_moptions { u_short imo_max_memberships; /* max memberships this socket */ struct in_multi **imo_membership; /* group memberships */ struct in_mfilter *imo_mfilters; /* source filters */ - STAILQ_ENTRY(ip_moptions) imo_link; + struct epoch_context imo_epoch_ctx; }; struct ipstat { @@ -175,6 +176,7 @@ struct ip; struct inpcb; struct route; struct sockopt; +struct inpcbinfo; VNET_DECLARE(int, ip_defttl); /* default IP ttl */ VNET_DECLARE(int, ipforwarding); /* ip forwarding */ diff --git a/freebsd/sys/netinet/netdump/netdump.h b/freebsd/sys/netinet/netdump/netdump.h new file mode 100644 index 00000000..12a527ee --- /dev/null +++ b/freebsd/sys/netinet/netdump/netdump.h @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 2005-2014 Sandvine Incorporated + * Copyright (c) 2000 Darrell Anderson <anderson@cs.duke.edu> + * 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 _NETINET_NETDUMP_H_ +#define _NETINET_NETDUMP_H_ + +#include <sys/types.h> +#include <sys/disk.h> +#include <sys/ioccom.h> + +#include <net/if.h> +#include <netinet/in.h> + +#define NETDUMP_PORT 20023 /* Server UDP port for heralds. */ +#define NETDUMP_ACKPORT 20024 /* Client UDP port for acks. */ + +#define NETDUMP_HERALD 1 /* Broadcast before starting a dump. */ +#define NETDUMP_FINISHED 2 /* Send after finishing a dump. */ +#define NETDUMP_VMCORE 3 /* Contains dump data. */ +#define NETDUMP_KDH 4 /* Contains kernel dump header. */ +#define NETDUMP_EKCD_KEY 5 /* Contains kernel dump key. */ + +#define NETDUMP_DATASIZE 4096 /* Arbitrary packet size limit. */ + +struct netdump_msg_hdr { + uint32_t mh_type; /* Netdump message type. */ + uint32_t mh_seqno; /* Match acks with msgs. */ + uint64_t mh_offset; /* vmcore offset (bytes). */ + uint32_t mh_len; /* Attached data (bytes). */ + uint32_t mh__pad; +} __packed; + +struct netdump_ack { + uint32_t na_seqno; /* Match acks with msgs. */ +} __packed; + +struct netdump_conf { +#ifndef __rtems__ + struct diocskerneldump_arg ndc_kda; +#endif /* __rtems__ */ + char ndc_iface[IFNAMSIZ]; + struct in_addr ndc_server; + struct in_addr ndc_client; + struct in_addr ndc_gateway; +}; + +#define _PATH_NETDUMP "/dev/netdump" + +#define NETDUMPGCONF _IOR('n', 1, struct netdump_conf) +#define NETDUMPSCONF _IOW('n', 2, struct netdump_conf) + +#ifdef _KERNEL +#ifdef NETDUMP + +#define NETDUMP_MAX_IN_FLIGHT 64 + +enum netdump_ev { + NETDUMP_START, + NETDUMP_END, +}; + +struct ifnet; +struct mbuf; + +void netdump_reinit(struct ifnet *); + +typedef void netdump_init_t(struct ifnet *, int *nrxr, int *ncl, int *clsize); +typedef void netdump_event_t(struct ifnet *, enum netdump_ev); +typedef int netdump_transmit_t(struct ifnet *, struct mbuf *); +typedef int netdump_poll_t(struct ifnet *, int); + +struct netdump_methods { + netdump_init_t *nd_init; + netdump_event_t *nd_event; + netdump_transmit_t *nd_transmit; + netdump_poll_t *nd_poll; +}; + +#define NETDUMP_DEFINE(driver) \ + static netdump_init_t driver##_netdump_init; \ + static netdump_event_t driver##_netdump_event; \ + static netdump_transmit_t driver##_netdump_transmit; \ + static netdump_poll_t driver##_netdump_poll; \ + \ + static struct netdump_methods driver##_netdump_methods = { \ + .nd_init = driver##_netdump_init, \ + .nd_event = driver##_netdump_event, \ + .nd_transmit = driver##_netdump_transmit, \ + .nd_poll = driver##_netdump_poll, \ + } + +#define NETDUMP_REINIT(ifp) netdump_reinit(ifp) + +#define NETDUMP_SET(ifp, driver) \ + (ifp)->if_netdump_methods = &driver##_netdump_methods + +#else /* !NETDUMP */ + +#define NETDUMP_DEFINE(driver) +#define NETDUMP_REINIT(ifp) +#define NETDUMP_SET(ifp, driver) + +#endif /* NETDUMP */ +#endif /* _KERNEL */ + +#endif /* _NETINET_NETDUMP_H_ */ diff --git a/freebsd/sys/netinet/raw_ip.c b/freebsd/sys/netinet/raw_ip.c index 0ed185ae..7dea3ec1 100644 --- a/freebsd/sys/netinet/raw_ip.c +++ b/freebsd/sys/netinet/raw_ip.c @@ -745,7 +745,7 @@ rip_ctlinput(int cmd, struct sockaddr *sa, void *vip) switch (cmd) { case PRC_IFDOWN: IN_IFADDR_RLOCK(&in_ifa_tracker); - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (ia->ia_ifa.ifa_addr == sa && (ia->ia_flags & IFA_ROUTE)) { ifa_ref(&ia->ia_ifa); @@ -771,7 +771,7 @@ rip_ctlinput(int cmd, struct sockaddr *sa, void *vip) case PRC_IFUP: IN_IFADDR_RLOCK(&in_ifa_tracker); - TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { if (ia->ia_ifa.ifa_addr == sa) break; } @@ -853,6 +853,7 @@ rip_detach(struct socket *so) ip_rsvp_force_done(so); if (so == V_ip_rsvpd) ip_rsvp_done(); + /* XXX defer to epoch_call */ in_pcbdetach(inp); in_pcbfree(inp); INP_INFO_WUNLOCK(&V_ripcbinfo); @@ -930,7 +931,7 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct thread *td) inp = sotoinpcb(so); KASSERT(inp != NULL, ("rip_bind: inp == NULL")); - if (TAILQ_EMPTY(&V_ifnet) || + if (CK_STAILQ_EMPTY(&V_ifnet) || (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) || (addr->sin_addr.s_addr && (inp->inp_flags & INP_BINDANY) == 0 && @@ -955,7 +956,7 @@ rip_connect(struct socket *so, struct sockaddr *nam, struct thread *td) if (nam->sa_len != sizeof(*addr)) return (EINVAL); - if (TAILQ_EMPTY(&V_ifnet)) + if (CK_STAILQ_EMPTY(&V_ifnet)) return (EADDRNOTAVAIL); if (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK) return (EAFNOSUPPORT); @@ -1022,6 +1023,7 @@ static int rip_pcblist(SYSCTL_HANDLER_ARGS) { int error, i, n; + struct in_pcblist *il; struct inpcb *inp, **inp_list; inp_gen_t gencnt; struct xinpgen xig; @@ -1056,9 +1058,8 @@ rip_pcblist(SYSCTL_HANDLER_ARGS) if (error) return (error); - inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); - if (inp_list == NULL) - return (ENOMEM); + il = malloc(sizeof(struct in_pcblist) + n * sizeof(struct inpcb *), M_TEMP, M_WAITOK|M_ZERO_INVARIANTS); + inp_list = il->il_inp_list; INP_INFO_RLOCK(&V_ripcbinfo); for (inp = LIST_FIRST(V_ripcbinfo.ipi_listhead), i = 0; inp && i < n; @@ -1087,14 +1088,9 @@ rip_pcblist(SYSCTL_HANDLER_ARGS) } else INP_RUNLOCK(inp); } - INP_INFO_WLOCK(&V_ripcbinfo); - for (i = 0; i < n; i++) { - inp = inp_list[i]; - INP_RLOCK(inp); - if (!in_pcbrele_rlocked(inp)) - INP_RUNLOCK(inp); - } - INP_INFO_WUNLOCK(&V_ripcbinfo); + il->il_count = n; + il->il_pcbinfo = &V_ripcbinfo; + epoch_call(net_epoch_preempt, &il->il_epoch_ctx, in_pcblist_rele_rlocked); if (!error) { /* @@ -1110,7 +1106,6 @@ rip_pcblist(SYSCTL_HANDLER_ARGS) INP_INFO_RUNLOCK(&V_ripcbinfo); error = SYSCTL_OUT(req, &xig, sizeof xig); } - free(inp_list, M_TEMP); return (error); } diff --git a/freebsd/sys/netinet/sctp_bsd_addr.c b/freebsd/sys/netinet/sctp_bsd_addr.c index 7e2ef189..94c23bff 100644 --- a/freebsd/sys/netinet/sctp_bsd_addr.c +++ b/freebsd/sys/netinet/sctp_bsd_addr.c @@ -209,13 +209,13 @@ sctp_init_ifns_for_vrf(int vrfid) #endif IFNET_RLOCK(); - TAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_link) { + CK_STAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_link) { if (sctp_is_desired_interface_type(ifn) == 0) { /* non desired type */ continue; } IF_ADDR_RLOCK(ifn); - TAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) { if (ifa->ifa_addr == NULL) { continue; } @@ -362,11 +362,11 @@ void struct ifaddr *ifa; IFNET_RLOCK(); - TAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_link) { + CK_STAILQ_FOREACH(ifn, &MODULE_GLOBAL(ifnet), if_link) { if (!(*pred) (ifn)) { continue; } - TAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) { sctp_addr_change(ifa, add ? RTM_ADD : RTM_DELETE); } } @@ -389,10 +389,7 @@ sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, m_freem(m); return (NULL); } - } - if (SCTP_BUF_NEXT(m)) { - sctp_m_freem(SCTP_BUF_NEXT(m)); - SCTP_BUF_NEXT(m) = NULL; + KASSERT(SCTP_BUF_NEXT(m) == NULL, ("%s: no chain allowed", __FUNCTION__)); } #ifdef SCTP_MBUF_LOGGING if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { diff --git a/freebsd/sys/netinet/sctp_indata.c b/freebsd/sys/netinet/sctp_indata.c index 3325dd03..98b397a2 100644 --- a/freebsd/sys/netinet/sctp_indata.c +++ b/freebsd/sys/netinet/sctp_indata.c @@ -1673,9 +1673,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, struct sctp_nets *net, uint32_t *high_tsn, int *abort_flag, int *break_flag, int last_chunk, uint8_t chk_type) { - /* Process a data chunk */ - /* struct sctp_tmit_chunk *chk; */ - struct sctp_tmit_chunk *chk; + struct sctp_tmit_chunk *chk = NULL; /* make gcc happy */ uint32_t tsn, fsn, gap, mid; struct mbuf *dmbuf; int the_len; @@ -3623,7 +3621,9 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, SCTP_SO_NOT_LOCKED); } /* Make sure to flag we had a FR */ - tp1->whoTo->net_ack++; + if (tp1->whoTo != NULL) { + tp1->whoTo->net_ack++; + } continue; } } diff --git a/freebsd/sys/netinet/sctp_input.c b/freebsd/sys/netinet/sctp_input.c index 9a74ef4b..ee206551 100644 --- a/freebsd/sys/netinet/sctp_input.c +++ b/freebsd/sys/netinet/sctp_input.c @@ -2618,7 +2618,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, (sizeof(uint32_t)))); diff = now; timevalsub(&diff, &time_expires); - if (diff.tv_sec > UINT32_MAX / 1000000) { + if ((uint32_t)diff.tv_sec > UINT32_MAX / 1000000) { staleness = UINT32_MAX; } else { staleness = diff.tv_sec * 1000000; diff --git a/freebsd/sys/netinet/sctp_os_bsd.h b/freebsd/sys/netinet/sctp_os_bsd.h index c9eaa069..d8d9e6e8 100644 --- a/freebsd/sys/netinet/sctp_os_bsd.h +++ b/freebsd/sys/netinet/sctp_os_bsd.h @@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$"); /* * includes */ -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_inet6.h> #include <rtems/bsd/local/opt_inet.h> #include <rtems/bsd/local/opt_sctp.h> diff --git a/freebsd/sys/netinet/sctp_output.c b/freebsd/sys/netinet/sctp_output.c index 9dd2e0fa..bdef958c 100644 --- a/freebsd/sys/netinet/sctp_output.c +++ b/freebsd/sys/netinet/sctp_output.c @@ -7452,7 +7452,7 @@ dont_do_it: /* Not enough room for a chunk header, get some */ struct mbuf *m; - m = sctp_get_mbuf_for_msg(1, 0, M_NOWAIT, 0, MT_DATA); + m = sctp_get_mbuf_for_msg(1, 0, M_NOWAIT, 1, MT_DATA); if (m == NULL) { /* * we're in trouble here. _PREPEND below will free @@ -11032,9 +11032,8 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, struct sctp_chunkhdr *ch; #if defined(INET) || defined(INET6) struct udphdr *udp; - int ret; #endif - int len, cause_len, padding_len; + int ret, len, cause_len, padding_len; #ifdef INET struct sockaddr_in *src_sin, *dst_sin; struct ip *ip; @@ -11261,9 +11260,13 @@ sctp_send_resp_msg(struct sockaddr *src, struct sockaddr *dst, SCTP_LTRACE_ERR_RET_PKT(mout, NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); return; } + SCTPDBG(SCTP_DEBUG_OUTPUT3, "return from send is %d\n", ret); SCTP_STAT_INCR(sctps_sendpackets); SCTP_STAT_INCR_COUNTER64(sctps_outpackets); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); + if (ret) { + SCTP_STAT_INCR(sctps_senderrors); + } return; } diff --git a/freebsd/sys/netinet/sctp_usrreq.c b/freebsd/sys/netinet/sctp_usrreq.c index 05ddee01..071d44c2 100644 --- a/freebsd/sys/netinet/sctp_usrreq.c +++ b/freebsd/sys/netinet/sctp_usrreq.c @@ -206,7 +206,7 @@ sctp_notify(struct sctp_inpcb *inp, #endif /* no need to unlock here, since the TCB is gone */ } else if (icmp_code == ICMP_UNREACH_NEEDFRAG) { - if ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0) { + if (net->dest_state & SCTP_ADDR_NO_PMTUD) { SCTP_TCB_UNLOCK(stcb); return; } @@ -707,22 +707,10 @@ sctp_disconnect(struct socket *so) if (SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT) { /* Left with Data unread */ - struct mbuf *err; - - err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); - if (err) { - /* - * Fill in the user - * initiated abort - */ - struct sctp_paramhdr *ph; + struct mbuf *op_err; - ph = mtod(err, struct sctp_paramhdr *); - SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); - ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); - ph->param_length = htons(SCTP_BUF_LEN(err)); - } - sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED); + op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, ""); + sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); SCTP_STAT_INCR_COUNTER32(sctps_aborted); } SCTP_INP_RUNLOCK(inp); diff --git a/freebsd/sys/netinet/sctputil.c b/freebsd/sys/netinet/sctputil.c index 5511df64..aad1e19d 100644 --- a/freebsd/sys/netinet/sctputil.c +++ b/freebsd/sys/netinet/sctputil.c @@ -74,6 +74,7 @@ extern const struct sctp_ss_functions sctp_ss_functions[]; void sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.sb.stcb = stcb; @@ -90,11 +91,13 @@ sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr) sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.close.inp = (void *)inp; @@ -114,11 +117,13 @@ sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc) sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void rto_logging(struct sctp_nets *net, int from) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; memset(&sctp_clog, 0, sizeof(sctp_clog)); @@ -131,11 +136,13 @@ rto_logging(struct sctp_nets *net, int from) sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16_t stream, int from) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.strlog.stcb = stcb; @@ -151,11 +158,13 @@ sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16 sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_nagle_event(struct sctp_tcb *stcb, int action) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.nagle.stcb = (void *)stcb; @@ -170,11 +179,13 @@ sctp_log_nagle_event(struct sctp_tcb *stcb, int action) sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.sack.cumack = cumack; @@ -189,11 +200,13 @@ sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; memset(&sctp_clog, 0, sizeof(sctp_clog)); @@ -207,11 +220,13 @@ sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from) sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int from) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; memset(&sctp_clog, 0, sizeof(sctp_clog)); @@ -225,12 +240,14 @@ sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int fr sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } #ifdef SCTP_MBUF_LOGGING void sctp_log_mb(struct mbuf *m, int from) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.mb.mp = m; @@ -251,6 +268,7 @@ sctp_log_mb(struct mbuf *m, int from) sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void @@ -267,6 +285,7 @@ sctp_log_mbc(struct mbuf *m, int from) void sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, int from) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; if (control == NULL) { @@ -291,11 +310,13 @@ sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_rea sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t from) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.cwnd.net = net; @@ -326,11 +347,13 @@ sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; memset(&sctp_clog, 0, sizeof(sctp_clog)); @@ -370,11 +393,13 @@ sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from) sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int burst, uint8_t from) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; memset(&sctp_clog, 0, sizeof(sctp_clog)); @@ -397,11 +422,13 @@ sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int b sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t overhead) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.rwnd.rwnd = peers_rwnd; @@ -415,11 +442,13 @@ sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t ove sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint32_t overhead, uint32_t a_rwndval) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.rwnd.rwnd = peers_rwnd; @@ -433,12 +462,14 @@ sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint3 sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } #ifdef SCTP_MBCNT_LOGGING static void sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mbcnt_q, uint32_t mbcnt) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.mbcnt.total_queue_size = total_oq; @@ -452,21 +483,25 @@ sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mb sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } #endif void sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d) { +#if defined(SCTP_LOCAL_TRACE_BUF) SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_MISC_EVENT, from, a, b, c, d); +#endif } void sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.wake.stcb = (void *)stcb; @@ -508,11 +543,13 @@ sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from) sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } void sctp_log_block(uint8_t from, struct sctp_association *asoc, size_t sendlen) { +#if defined(SCTP_LOCAL_TRACE_BUF) struct sctp_cwnd_log sctp_clog; sctp_clog.x.blk.onsb = asoc->total_output_queue_size; @@ -529,6 +566,7 @@ sctp_log_block(uint8_t from, struct sctp_association *asoc, size_t sendlen) sctp_clog.x.misc.log2, sctp_clog.x.misc.log3, sctp_clog.x.misc.log4); +#endif } int @@ -760,8 +798,8 @@ sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb) } /* - * a list of sizes based on typical mtu's, used only if next hop size not - * returned. + * A list of sizes based on typical mtu's, used only if next hop size not + * returned. These values MUST be multiples of 4 and MUST be ordered. */ static uint32_t sctp_mtu_sizes[] = { 68, @@ -770,29 +808,32 @@ static uint32_t sctp_mtu_sizes[] = { 512, 544, 576, - 1006, + 1004, 1492, 1500, 1536, - 2002, + 2000, 2048, 4352, 4464, 8166, - 17914, + 17912, 32000, - 65535 + 65532 }; /* - * Return the largest MTU smaller than val. If there is no - * entry, just return val. + * Return the largest MTU in sctp_mtu_sizes smaller than val. + * If val is smaller than the minimum, just return the largest + * multiple of 4 smaller or equal to val. + * Ensure that the result is a multiple of 4. */ uint32_t sctp_get_prev_mtu(uint32_t val) { uint32_t i; + val &= 0xfffffffc; if (val <= sctp_mtu_sizes[0]) { return (val); } @@ -801,12 +842,16 @@ sctp_get_prev_mtu(uint32_t val) break; } } + KASSERT((sctp_mtu_sizes[i - 1] & 0x00000003) == 0, + ("sctp_mtu_sizes[%u] not a multiple of 4", i - 1)); return (sctp_mtu_sizes[i - 1]); } /* - * Return the smallest MTU larger than val. If there is no - * entry, just return val. + * Return the smallest MTU in sctp_mtu_sizes larger than val. + * If val is larger than the maximum, just return the largest multiple of 4 smaller + * or equal to val. + * Ensure that the result is a multiple of 4. */ uint32_t sctp_get_next_mtu(uint32_t val) @@ -814,8 +859,11 @@ sctp_get_next_mtu(uint32_t val) /* select another MTU that is just bigger than this one */ uint32_t i; + val &= 0xfffffffc; for (i = 0; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) { if (val < sctp_mtu_sizes[i]) { + KASSERT((sctp_mtu_sizes[i] & 0x00000003) == 0, + ("sctp_mtu_sizes[%u] not a multiple of 4", i)); return (sctp_mtu_sizes[i]); } } @@ -2662,6 +2710,13 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, notif_len = (unsigned int)sizeof(struct sctp_assoc_change); if (abort != NULL) { abort_len = ntohs(abort->ch.chunk_length); + /* + * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be + * contiguous. + */ + if (abort_len > SCTP_CHUNK_BUFFER_SIZE) { + abort_len = SCTP_CHUNK_BUFFER_SIZE; + } } else { abort_len = 0; } @@ -3567,6 +3622,13 @@ sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_erro } if (chunk != NULL) { chunk_len = ntohs(chunk->ch.chunk_length); + /* + * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be + * contiguous. + */ + if (chunk_len > SCTP_CHUNK_BUFFER_SIZE) { + chunk_len = SCTP_CHUNK_BUFFER_SIZE; + } } else { chunk_len = 0; } diff --git a/freebsd/sys/netinet/tcp_hpts.h b/freebsd/sys/netinet/tcp_hpts.h new file mode 100644 index 00000000..c52a1d78 --- /dev/null +++ b/freebsd/sys/netinet/tcp_hpts.h @@ -0,0 +1,304 @@ +/*- + * Copyright (c) 2016-2018 Netflix Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __tcp_hpts_h__ +#define __tcp_hpts_h__ + +/* + * The hpts uses a 102400 wheel. The wheel + * defines the time in 10 usec increments (102400 x 10). + * This gives a range of 10usec - 1024ms to place + * an entry within. If the user requests more than + * 1.024 second, a remaineder is attached and the hpts + * when seeing the remainder will re-insert the + * inpcb forward in time from where it is until + * the remainder is zero. + */ + +#define NUM_OF_HPTSI_SLOTS 102400 + +TAILQ_HEAD(hptsh, inpcb); + +/* Number of useconds in a hpts tick */ +#define HPTS_TICKS_PER_USEC 10 +#define HPTS_MS_TO_SLOTS(x) (x * 100) +#define HPTS_USEC_TO_SLOTS(x) ((x+9) /10) +#define HPTS_USEC_IN_SEC 1000000 +#define HPTS_MSEC_IN_SEC 1000 +#define HPTS_USEC_IN_MSEC 1000 + +#define DEFAULT_HPTS_LOG 3072 + +/* + * Log flags consist of + * 7f 7f 1 1 bits + * p_cpu | p_num | INPUT_ACTIVE | HPTS_ACTIVE + * + * So for example cpu 10, number 10 would with + * input active would show up as: + * p_flags = 0001010 0001010 1 0 + * <or> + * p_flags = 0x142a + */ +#define HPTS_HPTS_ACTIVE 0x01 +#define HPTS_INPUT_ACTIVE 0x02 + +#define HPTSLOG_IMMEDIATE 1 +#define HPTSLOG_INSERT_NORMAL 2 +#define HPTSLOG_INSERT_SLEEPER 3 +#define HPTSLOG_SLEEP_AFTER 4 +#define HPTSLOG_SLEEP_BEFORE 5 +#define HPTSLOG_INSERTED 6 +#define HPTSLOG_WAKEUP_HPTS 7 +#define HPTSLOG_SETTORUN 8 +#define HPTSLOG_HPTSI 9 +#define HPTSLOG_TOLONG 10 +#define HPTSLOG_AWAKENS 11 +#define HPTSLOG_TIMESOUT 12 +#define HPTSLOG_SLEEPSET 13 +#define HPTSLOG_WAKEUP_INPUT 14 +#define HPTSLOG_RESCHEDULE 15 +#define HPTSLOG_AWAKE 16 +#define HPTSLOG_INP_DONE 17 + +struct hpts_log { + struct inpcb *inp; + int32_t event; + uint32_t cts; + int32_t line; + uint32_t ticknow; + uint32_t t_paceslot; + uint32_t t_hptsreq; + uint32_t p_curtick; + uint32_t p_prevtick; + uint32_t slot_req; + uint32_t p_on_queue_cnt; + uint32_t p_nxt_slot; + uint32_t p_cur_slot; + uint32_t p_hpts_sleep_time; + uint16_t p_flags; + uint8_t p_onhpts; + uint8_t p_oninput; + uint8_t is_notempty; +}; + +struct hpts_diag { + uint32_t p_hpts_active; + uint32_t p_nxt_slot; + uint32_t p_cur_slot; + uint32_t slot_req; + uint32_t inp_hptsslot; + uint32_t slot_now; + uint32_t have_slept; + uint32_t hpts_sleep_time; + uint32_t yet_to_sleep; + uint32_t need_new_to; + int32_t co_ret; + uint8_t p_on_min_sleep; +}; + +#ifdef _KERNEL +/* Each hpts has its own p_mtx which is used for locking */ +struct tcp_hpts_entry { + /* Cache line 0x00 */ + struct mtx p_mtx; /* Mutex for hpts */ + uint32_t p_hpts_active; /* Flag that says hpts is awake */ + uint32_t p_curtick; /* Current tick in 10 us the hpts is at */ + uint32_t p_prevtick; /* Previous tick in 10 us the hpts ran */ + uint32_t p_cur_slot; /* Current slot in wheel hpts is draining */ + uint32_t p_nxt_slot; /* The next slot outside the current range of + * slots that the hpts is running on. */ + int32_t p_on_queue_cnt; /* Count on queue in this hpts */ + uint32_t enobuf_cnt; + uint16_t p_log_at; + uint8_t p_direct_wake :1, /* boolean */ + p_log_wrapped :1, /* boolean */ + p_on_min_sleep:1; /* boolean */ + uint8_t p_fill; + /* Cache line 0x40 */ + void *p_inp; + struct hptsh p_input; /* For the tcp-input runner */ + /* Hptsi wheel */ + struct hptsh *p_hptss; + struct hpts_log *p_log; + uint32_t p_logsize; + int32_t p_on_inqueue_cnt; /* Count on input queue in this hpts */ + uint32_t hit_no_enobuf; + uint32_t p_dyn_adjust; + uint32_t p_hpts_sleep_time; /* Current sleep interval having a max + * of 255ms */ + uint32_t p_delayed_by; /* How much were we delayed by */ + /* Cache line 0x80 */ + struct sysctl_ctx_list hpts_ctx; + struct sysctl_oid *hpts_root; + struct intr_event *ie; + void *ie_cookie; + uint16_t p_num; /* The hpts number one per cpu */ + uint16_t p_cpu; /* The hpts CPU */ + /* There is extra space in here */ + /* Cache line 0x100 */ + struct callout co __aligned(CACHE_LINE_SIZE); +} __aligned(CACHE_LINE_SIZE); + +struct tcp_hptsi { + struct proc *rp_proc; /* Process structure for hpts */ + struct tcp_hpts_entry **rp_ent; /* Array of hptss */ + uint32_t rp_num_hptss; /* Number of hpts threads */ +}; + +#endif + +#define HPTS_REMOVE_INPUT 0x01 +#define HPTS_REMOVE_OUTPUT 0x02 +#define HPTS_REMOVE_ALL (HPTS_REMOVE_INPUT | HPTS_REMOVE_OUTPUT) + +/* + * When using the hpts, a TCP stack must make sure + * that once a INP_DROPPED flag is applied to a INP + * that it does not expect tcp_output() to ever be + * called by the hpts. The hpts will *not* call + * any output (or input) functions on a TCB that + * is in the DROPPED state. + * + * This implies final ACK's and RST's that might + * be sent when a TCB is still around must be + * sent from a routine like tcp_respond(). + */ +#define DEFAULT_MIN_SLEEP 250 /* How many usec's is default for hpts sleep + * this determines min granularity of the + * hpts. If 0, granularity is 10useconds at + * the cost of more CPU (context switching). */ +#ifdef _KERNEL +#define HPTS_MTX_ASSERT(hpts) mtx_assert(&(hpts)->p_mtx, MA_OWNED) +struct tcp_hpts_entry *tcp_hpts_lock(struct inpcb *inp); +struct tcp_hpts_entry *tcp_input_lock(struct inpcb *inp); +int __tcp_queue_to_hpts_immediate(struct inpcb *inp, int32_t line); +#define tcp_queue_to_hpts_immediate(a)__tcp_queue_to_hpts_immediate(a, __LINE__) + +struct tcp_hpts_entry *tcp_cur_hpts(struct inpcb *inp); +#define tcp_hpts_remove(a, b) __tcp_hpts_remove(a, b, __LINE__) +void __tcp_hpts_remove(struct inpcb *inp, int32_t flags, int32_t line); + +/* + * To insert a TCB on the hpts you *must* be holding the + * INP_WLOCK(). The hpts insert code will then acqurire + * the hpts's lock and insert the TCB on the requested + * slot possibly waking up the hpts if you are requesting + * a time earlier than what the hpts is sleeping to (if + * the hpts is sleeping). You may check the inp->inp_in_hpts + * flag without the hpts lock. The hpts is the only one + * that will clear this flag holding only the hpts lock. This + * means that in your tcp_output() routine when you test for + * it to be 1 (so you wont call output) it may be transitioning + * to 0 (by the hpts). That will be fine since that will just + * mean an extra call to tcp_output that most likely will find + * the call you executed (when the mis-match occured) will have + * put the TCB back on the hpts and it will return. If your + * call did not add it back to the hpts then you will either + * over-send or the cwnd will block you from sending more. + * + * Note you should also be holding the INP_WLOCK() when you + * call the remove from the hpts as well. Thoug usually + * you are either doing this from a timer, where you need + * that INP_WLOCK() or from destroying your TCB where again + * you should already have the INP_WLOCK(). + */ +uint32_t __tcp_hpts_insert(struct inpcb *inp, uint32_t slot, int32_t line); +#define tcp_hpts_insert(a, b) __tcp_hpts_insert(a, b, __LINE__) + +uint32_t +tcp_hpts_insert_diag(struct inpcb *inp, uint32_t slot, int32_t line, struct hpts_diag *diag); + +int + __tcp_queue_to_input_locked(struct inpcb *inp, struct tcp_hpts_entry *hpts, int32_t line); +#define tcp_queue_to_input_locked(a, b) __tcp_queue_to_input_locked(a, b, __LINE__); +void +tcp_queue_pkt_to_input(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th, + int32_t tlen, int32_t drop_hdrlen, uint8_t iptos, uint8_t ti_locked); +int +__tcp_queue_to_input(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th, + int32_t tlen, int32_t drop_hdrlen, uint8_t iptos, uint8_t ti_locked, int32_t line); +#define tcp_queue_to_input(a, b, c, d, e, f, g) __tcp_queue_to_input(a, b, c, d, e, f, g, __LINE__) + +uint16_t tcp_hpts_delayedby(struct inpcb *inp); + +void __tcp_set_hpts(struct inpcb *inp, int32_t line); +#define tcp_set_hpts(a) __tcp_set_hpts(a, __LINE__) + +void __tcp_set_inp_to_drop(struct inpcb *inp, uint16_t reason, int32_t line); +#define tcp_set_inp_to_drop(a, b) __tcp_set_inp_to_drop(a, b, __LINE__) + +extern int32_t tcp_min_hptsi_time; + +static __inline uint32_t +tcp_tv_to_hptstick(struct timeval *sv) +{ + return ((sv->tv_sec * 100000) + (sv->tv_usec / 10)); +} + +static __inline uint32_t +tcp_gethptstick(struct timeval *sv) +{ + struct timeval tv; + + if (sv == NULL) + sv = &tv; + microuptime(sv); + return (tcp_tv_to_hptstick(sv)); +} + +static __inline uint32_t +tcp_tv_to_usectick(struct timeval *sv) +{ + return ((uint32_t) ((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec)); +} + +static __inline uint32_t +tcp_tv_to_mssectick(struct timeval *sv) +{ + return ((uint32_t) ((sv->tv_sec * HPTS_MSEC_IN_SEC) + (sv->tv_usec/HPTS_USEC_IN_MSEC))); +} + +static __inline void +tcp_hpts_unlock(struct tcp_hpts_entry *hpts) +{ + mtx_unlock(&hpts->p_mtx); +} + +static __inline uint32_t +tcp_get_usecs(struct timeval *tv) +{ + struct timeval tvd; + + if (tv == NULL) + tv = &tvd; + microuptime(tv); + return (tcp_tv_to_usectick(tv)); +} + +#endif /* _KERNEL */ +#endif /* __tcp_hpts_h__ */ diff --git a/freebsd/sys/netinet/tcp_input.c b/freebsd/sys/netinet/tcp_input.c index 7c907da9..20bea2de 100644 --- a/freebsd/sys/netinet/tcp_input.c +++ b/freebsd/sys/netinet/tcp_input.c @@ -1684,6 +1684,9 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, to.to_tsecr -= tp->ts_offset; if (TSTMP_GT(to.to_tsecr, tcp_ts_getticks())) to.to_tsecr = 0; + else if (tp->t_flags & TF_PREVVALID && + tp->t_badrxtwin != 0 && SEQ_LT(to.to_tsecr, tp->t_badrxtwin)) + cc_cong_signal(tp, th, CC_RTO_ERR); } /* * Process options only when we get SYN/ACK back. The SYN case @@ -1796,9 +1799,10 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, TCPSTAT_INC(tcps_predack); /* - * "bad retransmit" recovery. + * "bad retransmit" recovery without timestamps. */ - if (tp->t_rxtshift == 1 && + if ((to.to_flags & TOF_TS) == 0 && + tp->t_rxtshift == 1 && tp->t_flags & TF_PREVVALID && (int)(ticks - tp->t_badrxtwin) < 0) { cc_cong_signal(tp, th, CC_RTO_ERR); @@ -2789,8 +2793,10 @@ process_ACK: * original cwnd and ssthresh, and proceed to transmit where * we left off. */ - if (tp->t_rxtshift == 1 && tp->t_flags & TF_PREVVALID && - (int)(ticks - tp->t_badrxtwin) < 0) + if (tp->t_rxtshift == 1 && + tp->t_flags & TF_PREVVALID && + tp->t_badrxtwin && + SEQ_LT(to.to_tsecr, tp->t_badrxtwin)) cc_cong_signal(tp, th, CC_RTO_ERR); /* diff --git a/freebsd/sys/netinet/tcp_offload.c b/freebsd/sys/netinet/tcp_offload.c index 41302db1..f3ab3b50 100644 --- a/freebsd/sys/netinet/tcp_offload.c +++ b/freebsd/sys/netinet/tcp_offload.c @@ -170,6 +170,17 @@ tcp_offload_ctloutput(struct tcpcb *tp, int sopt_dir, int sopt_name) } void +tcp_offload_tcp_info(struct tcpcb *tp, struct tcp_info *ti) +{ + struct toedev *tod = tp->tod; + + KASSERT(tod != NULL, ("%s: tp->tod is NULL, tp %p", __func__, tp)); + INP_WLOCK_ASSERT(tp->t_inpcb); + + tod->tod_tcp_info(tod, tp, ti); +} + +void tcp_offload_detach(struct tcpcb *tp) { struct toedev *tod = tp->tod; diff --git a/freebsd/sys/netinet/tcp_offload.h b/freebsd/sys/netinet/tcp_offload.h index 8485fa29..f755ce7e 100644 --- a/freebsd/sys/netinet/tcp_offload.h +++ b/freebsd/sys/netinet/tcp_offload.h @@ -45,6 +45,7 @@ void tcp_offload_input(struct tcpcb *, struct mbuf *); int tcp_offload_output(struct tcpcb *); void tcp_offload_rcvd(struct tcpcb *); void tcp_offload_ctloutput(struct tcpcb *, int, int); +void tcp_offload_tcp_info(struct tcpcb *, struct tcp_info *); void tcp_offload_detach(struct tcpcb *); #endif diff --git a/freebsd/sys/netinet/tcp_output.c b/freebsd/sys/netinet/tcp_output.c index 8762407f..bdbfe984 100644 --- a/freebsd/sys/netinet/tcp_output.c +++ b/freebsd/sys/netinet/tcp_output.c @@ -208,7 +208,7 @@ tcp_output(struct tcpcb *tp) #if defined(IPSEC) || defined(IPSEC_SUPPORT) unsigned ipsec_optlen = 0; #endif - int idle, sendalot; + int idle, sendalot, curticks; int sack_rxmit, sack_bytes_rxmt; struct sackhole *p; int tso, mtu; @@ -810,9 +810,12 @@ send: /* Timestamps. */ if ((tp->t_flags & TF_RCVD_TSTMP) || ((flags & TH_SYN) && (tp->t_flags & TF_REQ_TSTMP))) { - to.to_tsval = tcp_ts_getticks() + tp->ts_offset; + curticks = tcp_ts_getticks(); + to.to_tsval = curticks + tp->ts_offset; to.to_tsecr = tp->ts_recent; to.to_flags |= TOF_TS; + if (tp->t_rxtshift == 1) + tp->t_badrxtwin = curticks; } /* Set receive buffer autosizing timestamp. */ @@ -1313,10 +1316,6 @@ send: } #endif - /* We're getting ready to send; log now. */ - TCP_LOG_EVENT(tp, th, &so->so_rcv, &so->so_snd, TCP_LOG_OUT, ERRNO_UNK, - len, NULL, false); - /* * Enable TSO and specify the size of the segments. * The TCP pseudo header checksum is always provided. @@ -1365,6 +1364,10 @@ send: #endif /* TCPDEBUG */ TCP_PROBE3(debug__output, tp, th, m); + /* We're getting ready to send; log now. */ + TCP_LOG_EVENT(tp, th, &so->so_rcv, &so->so_snd, TCP_LOG_OUT, ERRNO_UNK, + len, NULL, false); + /* * Fill in IP length and desired time to live and * send to IP level. There should be a better way @@ -1588,8 +1591,6 @@ timer: SOCKBUF_UNLOCK_ASSERT(&so->so_snd); /* Check gotos. */ switch (error) { case EACCES: - tp->t_softerror = error; - return (0); case EPERM: tp->t_softerror = error; return (error); diff --git a/freebsd/sys/netinet/tcp_seq.h b/freebsd/sys/netinet/tcp_seq.h index b29ae2aa..b6e682ec 100644 --- a/freebsd/sys/netinet/tcp_seq.h +++ b/freebsd/sys/netinet/tcp_seq.h @@ -47,10 +47,10 @@ #define SEQ_MIN(a, b) ((SEQ_LT(a, b)) ? (a) : (b)) #define SEQ_MAX(a, b) ((SEQ_GT(a, b)) ? (a) : (b)) -#define WIN_LT(a,b) ((short)(ntohs(a)-ntohs(b)) < 0) -#define WIN_LEQ(a,b) ((short)(ntohs(a)-ntohs(b)) <= 0) -#define WIN_GT(a,b) ((short)(ntohs(a)-ntohs(b)) > 0) -#define WIN_GEQ(a,b) ((short)(ntohs(a)-ntohs(b)) >= 0) +#define WIN_LT(a,b) (ntohs(a) < ntohs(b)) +#define WIN_LEQ(a,b) (ntohs(a) <= ntohs(b)) +#define WIN_GT(a,b) (ntohs(a) > ntohs(b)) +#define WIN_GEQ(a,b) (ntohs(a) >= ntohs(b)) #define WIN_MIN(a, b) ((WIN_LT(a, b)) ? (a) : (b)) #define WIN_MAX(a, b) ((WIN_GT(a, b)) ? (a) : (b)) diff --git a/freebsd/sys/netinet/tcp_subr.c b/freebsd/sys/netinet/tcp_subr.c index 1b19aecb..787213b0 100644 --- a/freebsd/sys/netinet/tcp_subr.c +++ b/freebsd/sys/netinet/tcp_subr.c @@ -40,7 +40,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_inet.h> #include <rtems/bsd/local/opt_inet6.h> #include <rtems/bsd/local/opt_ipsec.h> @@ -106,6 +105,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/tcp_var.h> #include <netinet/tcp_log_buf.h> #include <netinet/tcp_syncache.h> +#include <netinet/tcp_hpts.h> #include <netinet/cc/cc.h> #ifdef INET6 #include <netinet6/tcp6_var.h> @@ -239,6 +239,9 @@ VNET_DEFINE(uma_zone_t, sack_hole_zone); VNET_DEFINE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST+1]); #endif +static int tcp_default_fb_init(struct tcpcb *tp); +static void tcp_default_fb_fini(struct tcpcb *tp, int tcb_is_purged); +static int tcp_default_handoff_ok(struct tcpcb *tp); static struct inpcb *tcp_notify(struct inpcb *, int); static struct inpcb *tcp_mtudisc_notify(struct inpcb *, int); static void tcp_mtudisc(struct inpcb *, int); @@ -247,21 +250,17 @@ static char * tcp_log_addr(struct in_conninfo *inc, struct tcphdr *th, static struct tcp_function_block tcp_def_funcblk = { - "default", - tcp_output, - tcp_do_segment, - tcp_default_ctloutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - 0 + .tfb_tcp_block_name = "freebsd", + .tfb_tcp_output = tcp_output, + .tfb_tcp_do_segment = tcp_do_segment, + .tfb_tcp_ctloutput = tcp_default_ctloutput, + .tfb_tcp_handoff_ok = tcp_default_handoff_ok, + .tfb_tcp_fb_init = tcp_default_fb_init, + .tfb_tcp_fb_fini = tcp_default_fb_fini, }; int t_functions_inited = 0; +static int tcp_fb_cnt = 0; struct tcp_funchead t_functions; static struct tcp_function_block *tcp_func_set_ptr = &tcp_def_funcblk; @@ -334,6 +333,88 @@ find_and_ref_tcp_fb(struct tcp_function_block *blk) return(rblk); } +static struct tcp_function_block * +find_and_ref_tcp_default_fb(void) +{ + struct tcp_function_block *rblk; + + rw_rlock(&tcp_function_lock); + rblk = tcp_func_set_ptr; + refcount_acquire(&rblk->tfb_refcnt); + rw_runlock(&tcp_function_lock); + return (rblk); +} + +void +tcp_switch_back_to_default(struct tcpcb *tp) +{ + struct tcp_function_block *tfb; + + KASSERT(tp->t_fb != &tcp_def_funcblk, + ("%s: called by the built-in default stack", __func__)); + + /* + * Release the old stack. This function will either find a new one + * or panic. + */ + if (tp->t_fb->tfb_tcp_fb_fini != NULL) + (*tp->t_fb->tfb_tcp_fb_fini)(tp, 0); + refcount_release(&tp->t_fb->tfb_refcnt); + + /* + * Now, we'll find a new function block to use. + * Start by trying the current user-selected + * default, unless this stack is the user-selected + * default. + */ + tfb = find_and_ref_tcp_default_fb(); + if (tfb == tp->t_fb) { + refcount_release(&tfb->tfb_refcnt); + tfb = NULL; + } + /* Does the stack accept this connection? */ + if (tfb != NULL && tfb->tfb_tcp_handoff_ok != NULL && + (*tfb->tfb_tcp_handoff_ok)(tp)) { + refcount_release(&tfb->tfb_refcnt); + tfb = NULL; + } + /* Try to use that stack. */ + if (tfb != NULL) { + /* Initialize the new stack. If it succeeds, we are done. */ + tp->t_fb = tfb; + if (tp->t_fb->tfb_tcp_fb_init == NULL || + (*tp->t_fb->tfb_tcp_fb_init)(tp) == 0) + return; + + /* + * Initialization failed. Release the reference count on + * the stack. + */ + refcount_release(&tfb->tfb_refcnt); + } + + /* + * If that wasn't feasible, use the built-in default + * stack which is not allowed to reject anyone. + */ + tfb = find_and_ref_tcp_fb(&tcp_def_funcblk); + if (tfb == NULL) { + /* there always should be a default */ + panic("Can't refer to tcp_def_funcblk"); + } + if (tfb->tfb_tcp_handoff_ok != NULL) { + if ((*tfb->tfb_tcp_handoff_ok) (tp)) { + /* The default stack cannot say no */ + panic("Default stack rejects a new session?"); + } + } + tp->t_fb = tfb; + if (tp->t_fb->tfb_tcp_fb_init != NULL && + (*tp->t_fb->tfb_tcp_fb_init)(tp)) { + /* The default stack cannot fail */ + panic("Default stack initialization failed"); + } +} static int sysctl_net_inet_default_tcp_functions(SYSCTL_HANDLER_ARGS) @@ -433,14 +514,14 @@ SYSCTL_PROC(_net_inet_tcp, OID_AUTO, functions_available, "list available TCP Function sets"); /* - * Exports one (struct tcp_function_id) for each non-alias. + * Exports one (struct tcp_function_info) for each alias/name. */ static int -sysctl_net_inet_list_func_ids(SYSCTL_HANDLER_ARGS) +sysctl_net_inet_list_func_info(SYSCTL_HANDLER_ARGS) { - int error, cnt; + int cnt, error; struct tcp_function *f; - struct tcp_function_id tfi; + struct tcp_function_info tfi; /* * We don't allow writes. @@ -459,20 +540,31 @@ sysctl_net_inet_list_func_ids(SYSCTL_HANDLER_ARGS) } /* - * Walk the list, comparing the name of the function entry and - * function block to determine which is an alias. - * If exporting the list, copy out matching entries. Otherwise, - * just record the total length. + * Walk the list and copy out matching entries. If INVARIANTS + * is compiled in, also walk the list to verify the length of + * the list matches what we have recorded. */ - cnt = 0; rw_rlock(&tcp_function_lock); + + cnt = 0; +#ifndef INVARIANTS + if (req->oldptr == NULL) { + cnt = tcp_fb_cnt; + goto skip_loop; + } +#endif TAILQ_FOREACH(f, &t_functions, tf_next) { - if (strncmp(f->tf_name, f->tf_fb->tfb_tcp_block_name, - TCP_FUNCTION_NAME_LEN_MAX)) - continue; +#ifdef INVARIANTS + cnt++; +#endif if (req->oldptr != NULL) { + tfi.tfi_refcnt = f->tf_fb->tfb_refcnt; tfi.tfi_id = f->tf_fb->tfb_id; - (void)strncpy(tfi.tfi_name, f->tf_name, + (void)strncpy(tfi.tfi_alias, f->tf_name, + TCP_FUNCTION_NAME_LEN_MAX); + tfi.tfi_alias[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0'; + (void)strncpy(tfi.tfi_name, + f->tf_fb->tfb_tcp_block_name, TCP_FUNCTION_NAME_LEN_MAX); tfi.tfi_name[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0'; error = SYSCTL_OUT(req, &tfi, sizeof(tfi)); @@ -481,23 +573,110 @@ sysctl_net_inet_list_func_ids(SYSCTL_HANDLER_ARGS) * mechanism we use to accumulate length * information if the buffer was too short. */ - } else - cnt++; + } } + KASSERT(cnt == tcp_fb_cnt, + ("%s: cnt (%d) != tcp_fb_cnt (%d)", __func__, cnt, tcp_fb_cnt)); +#ifndef INVARIANTS +skip_loop: +#endif rw_runlock(&tcp_function_lock); if (req->oldptr == NULL) error = SYSCTL_OUT(req, NULL, - (cnt + 1) * sizeof(struct tcp_function_id)); + (cnt + 1) * sizeof(struct tcp_function_info)); return (error); } -SYSCTL_PROC(_net_inet_tcp, OID_AUTO, function_ids, +SYSCTL_PROC(_net_inet_tcp, OID_AUTO, function_info, CTLTYPE_OPAQUE | CTLFLAG_SKIP | CTLFLAG_RD | CTLFLAG_MPSAFE, - NULL, 0, sysctl_net_inet_list_func_ids, "S,tcp_function_id", + NULL, 0, sysctl_net_inet_list_func_info, "S,tcp_function_info", "List TCP function block name-to-ID mappings"); /* + * tfb_tcp_handoff_ok() function for the default stack. + * Note that we'll basically try to take all comers. + */ +static int +tcp_default_handoff_ok(struct tcpcb *tp) +{ + + return (0); +} + +/* + * tfb_tcp_fb_init() function for the default stack. + * + * This handles making sure we have appropriate timers set if you are + * transitioning a socket that has some amount of setup done. + * + * The init() fuction from the default can *never* return non-zero i.e. + * it is required to always succeed since it is the stack of last resort! + */ +static int +tcp_default_fb_init(struct tcpcb *tp) +{ + + struct socket *so; + + INP_WLOCK_ASSERT(tp->t_inpcb); + + KASSERT(tp->t_state >= 0 && tp->t_state < TCPS_TIME_WAIT, + ("%s: connection %p in unexpected state %d", __func__, tp, + tp->t_state)); + + /* + * Nothing to do for ESTABLISHED or LISTEN states. And, we don't + * know what to do for unexpected states (which includes TIME_WAIT). + */ + if (tp->t_state <= TCPS_LISTEN || tp->t_state >= TCPS_TIME_WAIT) + return (0); + + /* + * Make sure some kind of transmission timer is set if there is + * outstanding data. + */ + so = tp->t_inpcb->inp_socket; + if ((!TCPS_HAVEESTABLISHED(tp->t_state) || sbavail(&so->so_snd) || + tp->snd_una != tp->snd_max) && !(tcp_timer_active(tp, TT_REXMT) || + tcp_timer_active(tp, TT_PERSIST))) { + /* + * If the session has established and it looks like it should + * be in the persist state, set the persist timer. Otherwise, + * set the retransmit timer. + */ + if (TCPS_HAVEESTABLISHED(tp->t_state) && tp->snd_wnd == 0 && + (int32_t)(tp->snd_nxt - tp->snd_una) < + (int32_t)sbavail(&so->so_snd)) + tcp_setpersist(tp); + else + tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur); + } + + /* All non-embryonic sessions get a keepalive timer. */ + if (!tcp_timer_active(tp, TT_KEEP)) + tcp_timer_activate(tp, TT_KEEP, + TCPS_HAVEESTABLISHED(tp->t_state) ? TP_KEEPIDLE(tp) : + TP_KEEPINIT(tp)); + + return (0); +} + +/* + * tfb_tcp_fb_fini() function for the default stack. + * + * This changes state as necessary (or prudent) to prepare for another stack + * to assume responsibility for the connection. + */ +static void +tcp_default_fb_fini(struct tcpcb *tp, int tcb_is_purged) +{ + + INP_WLOCK_ASSERT(tp->t_inpcb); + return; +} + +/* * Target size of TCP PCB hash tables. Must be a power of two. * * Note that this can be overridden by the kernel environment @@ -660,6 +839,7 @@ register_tcp_functions_as_names(struct tcp_function_block *blk, int wait, (void)strncpy(n->tf_name, names[i], TCP_FUNCTION_NAME_LEN_MAX); n->tf_name[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0'; TAILQ_INSERT_TAIL(&t_functions, n, tf_next); + tcp_fb_cnt++; rw_wunlock(&tcp_function_lock); } return(0); @@ -676,6 +856,7 @@ cleanup: if (!strncmp(n->tf_name, names[i], TCP_FUNCTION_NAME_LEN_MAX)) { TAILQ_REMOVE(&t_functions, n, tf_next); + tcp_fb_cnt--; n->tf_fb = NULL; free(n, M_TCPFUNCTIONS); break; @@ -721,11 +902,28 @@ register_tcp_functions(struct tcp_function_block *blk, int wait) return (register_tcp_functions_as_name(blk, NULL, wait)); } +/* + * Deregister all names associated with a function block. This + * functionally removes the function block from use within the system. + * + * When called with a true quiesce argument, mark the function block + * as being removed so no more stacks will use it and determine + * whether the removal would succeed. + * + * When called with a false quiesce argument, actually attempt the + * removal. + * + * When called with a force argument, attempt to switch all TCBs to + * use the default stack instead of returning EBUSY. + * + * Returns 0 on success (or if the removal would succeed, or an error + * code on failure. + */ int -deregister_tcp_functions(struct tcp_function_block *blk) +deregister_tcp_functions(struct tcp_function_block *blk, bool quiesce, + bool force) { struct tcp_function *f; - int error=ENOENT; if (strcmp(blk->tfb_tcp_block_name, "default") == 0) { /* You can't un-register the default */ @@ -737,21 +935,64 @@ deregister_tcp_functions(struct tcp_function_block *blk) rw_wunlock(&tcp_function_lock); return (EBUSY); } + /* Mark the block so no more stacks can use it. */ + blk->tfb_flags |= TCP_FUNC_BEING_REMOVED; + /* + * If TCBs are still attached to the stack, attempt to switch them + * to the default stack. + */ + if (force && blk->tfb_refcnt) { + struct inpcb *inp; + struct tcpcb *tp; + VNET_ITERATOR_DECL(vnet_iter); + + rw_wunlock(&tcp_function_lock); + + VNET_LIST_RLOCK(); + /* XXX handle */ + VNET_FOREACH(vnet_iter) { + CURVNET_SET(vnet_iter); + INP_INFO_WLOCK(&V_tcbinfo); + LIST_FOREACH(inp, V_tcbinfo.ipi_listhead, inp_list) { + INP_WLOCK(inp); + if (inp->inp_flags & INP_TIMEWAIT) { + INP_WUNLOCK(inp); + continue; + } + tp = intotcpcb(inp); + if (tp == NULL || tp->t_fb != blk) { + INP_WUNLOCK(inp); + continue; + } + tcp_switch_back_to_default(tp); + INP_WUNLOCK(inp); + } + INP_INFO_WUNLOCK(&V_tcbinfo); + CURVNET_RESTORE(); + } + VNET_LIST_RUNLOCK(); + + rw_wlock(&tcp_function_lock); + } if (blk->tfb_refcnt) { - /* Still tcb attached, mark it. */ - blk->tfb_flags |= TCP_FUNC_BEING_REMOVED; - rw_wunlock(&tcp_function_lock); + /* TCBs still attached. */ + rw_wunlock(&tcp_function_lock); return (EBUSY); } + if (quiesce) { + /* Skip removal. */ + rw_wunlock(&tcp_function_lock); + return (0); + } + /* Remove any function names that map to this function block. */ while (find_tcp_fb_locked(blk, &f) != NULL) { - /* Found */ TAILQ_REMOVE(&t_functions, f, tf_next); + tcp_fb_cnt--; f->tf_fb = NULL; free(f, M_TCPFUNCTIONS); - error = 0; } rw_wunlock(&tcp_function_lock); - return (error); + return (0); } void @@ -1498,6 +1739,7 @@ tcp_ccalgounload(struct cc_algo *unload_algo) tmpalgo = CC_ALGO(tp); /* NewReno does not require any init. */ CC_ALGO(tp) = &newreno_cc_algo; + /* XXX defer to epoch_call */ if (tmpalgo->cb_destroy != NULL) tmpalgo->cb_destroy(tp->ccv); } @@ -1545,7 +1787,7 @@ tcp_discardcb(struct tcpcb *tp) #ifdef INET6 int isipv6 = (inp->inp_vflag & INP_IPV6) != 0; #endif /* INET6 */ - int released; + int released __unused; INP_WLOCK_ASSERT(inp); @@ -1868,6 +2110,7 @@ static int tcp_pcblist(SYSCTL_HANDLER_ARGS) { int error, i, m, n, pcb_count; + struct in_pcblist *il; struct inpcb *inp, **inp_list; inp_gen_t gencnt; struct xinpgen xig; @@ -1914,7 +2157,8 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS) if (error) return (error); - inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); + il = malloc(sizeof(struct in_pcblist) + n * sizeof(struct inpcb *), M_TEMP, M_WAITOK|M_ZERO_INVARIANTS); + inp_list = il->il_inp_list; INP_INFO_WLOCK(&V_tcbinfo); for (inp = LIST_FIRST(V_tcbinfo.ipi_listhead), i = 0; @@ -1957,14 +2201,10 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS) } else INP_RUNLOCK(inp); } - INP_INFO_RLOCK(&V_tcbinfo); - for (i = 0; i < n; i++) { - inp = inp_list[i]; - INP_RLOCK(inp); - if (!in_pcbrele_rlocked(inp)) - INP_RUNLOCK(inp); - } - INP_INFO_RUNLOCK(&V_tcbinfo); + + il->il_count = n; + il->il_pcbinfo = &V_tcbinfo; + epoch_call(net_epoch_preempt, &il->il_epoch_ctx, in_pcblist_rele_rlocked); if (!error) { /* @@ -1981,7 +2221,6 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS) INP_LIST_RUNLOCK(&V_tcbinfo); error = SYSCTL_OUT(req, &xig, sizeof xig); } - free(inp_list, M_TEMP); return (error); } diff --git a/freebsd/sys/netinet/tcp_syncache.c b/freebsd/sys/netinet/tcp_syncache.c index 27e0e25f..e163aa54 100644 --- a/freebsd/sys/netinet/tcp_syncache.c +++ b/freebsd/sys/netinet/tcp_syncache.c @@ -862,6 +862,12 @@ syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m) (*tp->t_fb->tfb_tcp_fb_fini)(tp, 0); refcount_release(&tp->t_fb->tfb_refcnt); tp->t_fb = rblk; + /* + * XXXrrs this is quite dangerous, it is possible + * for the new function to fail to init. We also + * are not asking if the handoff_is_ok though at + * the very start thats probalbly ok. + */ if (tp->t_fb->tfb_tcp_fb_init) { (*tp->t_fb->tfb_tcp_fb_init)(tp); } diff --git a/freebsd/sys/netinet/tcp_timer.c b/freebsd/sys/netinet/tcp_timer.c index 69bd052b..422e5122 100644 --- a/freebsd/sys/netinet/tcp_timer.c +++ b/freebsd/sys/netinet/tcp_timer.c @@ -664,8 +664,7 @@ tcp_timer_rexmt(void * xtp) tcp_inpinfo_lock_del(inp, tp); goto out; } - tp = tcp_drop(tp, tp->t_softerror ? - tp->t_softerror : ETIMEDOUT); + tp = tcp_drop(tp, ETIMEDOUT); tcp_inpinfo_lock_del(inp, tp); goto out; } @@ -696,7 +695,12 @@ tcp_timer_rexmt(void * xtp) tp->t_flags |= TF_WASCRECOVERY; else tp->t_flags &= ~TF_WASCRECOVERY; - tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); + if ((tp->t_flags & TF_RCVD_TSTMP) == 0) + tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); + /* In the event that we've negotiated timestamps + * badrxtwin will be set to the value that we set + * the retransmitted packet's to_tsval to by tcp_output + */ tp->t_flags |= TF_PREVVALID; } else tp->t_flags &= ~TF_PREVVALID; diff --git a/freebsd/sys/netinet/tcp_timewait.c b/freebsd/sys/netinet/tcp_timewait.c index aa26cb37..afadf7cd 100644 --- a/freebsd/sys/netinet/tcp_timewait.c +++ b/freebsd/sys/netinet/tcp_timewait.c @@ -647,7 +647,7 @@ tcp_tw_2msl_stop(struct tcptw *tw, int reuse) { struct ucred *cred; struct inpcb *inp; - int released; + int released __unused; INP_INFO_RLOCK_ASSERT(&V_tcbinfo); diff --git a/freebsd/sys/netinet/tcp_usrreq.c b/freebsd/sys/netinet/tcp_usrreq.c index c93b2d4a..bf2cff4c 100644 --- a/freebsd/sys/netinet/tcp_usrreq.c +++ b/freebsd/sys/netinet/tcp_usrreq.c @@ -96,6 +96,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/tcpip.h> #include <netinet/cc/cc.h> #include <netinet/tcp_fastopen.h> +#include <netinet/tcp_hpts.h> #ifdef TCPPCAP #include <netinet/tcp_pcap.h> #endif @@ -1097,7 +1098,9 @@ tcp_usr_abort(struct socket *so) !(inp->inp_flags & INP_DROPPED)) { tp = intotcpcb(inp); TCPDEBUG1(); - tcp_drop(tp, ECONNABORTED); + tp = tcp_drop(tp, ECONNABORTED); + if (tp == NULL) + goto dropped; TCPDEBUG2(PRU_ABORT); TCP_PROBE2(debug__user, tp, PRU_ABORT); } @@ -1108,6 +1111,7 @@ tcp_usr_abort(struct socket *so) inp->inp_flags |= INP_SOCKREF; } INP_WUNLOCK(inp); +dropped: INP_INFO_RUNLOCK(&V_tcbinfo); } @@ -1395,11 +1399,15 @@ tcp_fill_info(struct tcpcb *tp, struct tcp_info *ti) ti->tcpi_snd_nxt = tp->snd_nxt; ti->tcpi_snd_mss = tp->t_maxseg; ti->tcpi_rcv_mss = tp->t_maxseg; - if (tp->t_flags & TF_TOE) - ti->tcpi_options |= TCPI_OPT_TOE; ti->tcpi_snd_rexmitpack = tp->t_sndrexmitpack; ti->tcpi_rcv_ooopack = tp->t_rcvoopack; ti->tcpi_snd_zerowin = tp->t_sndzerowin; +#ifdef TCP_OFFLOAD + if (tp->t_flags & TF_TOE) { + ti->tcpi_options |= TCPI_OPT_TOE; + tcp_offload_tcp_info(tp, ti); + } +#endif } /* @@ -1516,22 +1524,41 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt) */ (*tp->t_fb->tfb_tcp_fb_fini)(tp, 0); } +#ifdef TCPHPTS + /* Assure that we are not on any hpts */ + tcp_hpts_remove(tp->t_inpcb, HPTS_REMOVE_ALL); +#endif + if (blk->tfb_tcp_fb_init) { + error = (*blk->tfb_tcp_fb_init)(tp); + if (error) { + refcount_release(&blk->tfb_refcnt); + if (tp->t_fb->tfb_tcp_fb_init) { + if((*tp->t_fb->tfb_tcp_fb_init)(tp) != 0) { + /* Fall back failed, drop the connection */ + INP_WUNLOCK(inp); + soabort(so); + return(error); + } + } + goto err_out; + } + } refcount_release(&tp->t_fb->tfb_refcnt); tp->t_fb = blk; - if (tp->t_fb->tfb_tcp_fb_init) { - (*tp->t_fb->tfb_tcp_fb_init)(tp); - } #ifdef TCP_OFFLOAD if (tp->t_flags & TF_TOE) { tcp_offload_ctloutput(tp, sopt->sopt_dir, sopt->sopt_name); } #endif +err_out: INP_WUNLOCK(inp); return (error); } else if ((sopt->sopt_dir == SOPT_GET) && (sopt->sopt_name == TCP_FUNCTION_BLK)) { - strcpy(fsn.function_set_name, tp->t_fb->tfb_tcp_block_name); + strncpy(fsn.function_set_name, tp->t_fb->tfb_tcp_block_name, + TCP_FUNCTION_NAME_LEN_MAX); + fsn.function_set_name[TCP_FUNCTION_NAME_LEN_MAX - 1] = '\0'; fsn.pcbcnt = tp->t_fb->tfb_refcnt; INP_WUNLOCK(inp); error = sooptcopyout(sopt, &fsn, sizeof fsn); diff --git a/freebsd/sys/netinet/tcp_var.h b/freebsd/sys/netinet/tcp_var.h index f09bd19c..adaaff61 100644 --- a/freebsd/sys/netinet/tcp_var.h +++ b/freebsd/sys/netinet/tcp_var.h @@ -83,123 +83,123 @@ STAILQ_HEAD(tcp_log_stailq, tcp_log_mem); /* * Tcp control block, one per tcp; fields: - * Organized for 16 byte cacheline efficiency. + * Organized for 64 byte cacheline efficiency based + * on common tcp_input/tcp_output processing. */ struct tcpcb { - struct tsegqe_head t_segq; /* segment reassembly queue */ - int t_segqlen; /* segment reassembly queue length */ - int t_dupacks; /* consecutive dup acks recd */ - - struct tcp_timer *t_timers; /* All the TCP timers in one struct */ - + /* Cache line 1 */ struct inpcb *t_inpcb; /* back pointer to internet pcb */ - int t_state; /* state of this connection */ + struct tcp_function_block *t_fb;/* TCP function call block */ + void *t_fb_ptr; /* Pointer to t_fb specific data */ + uint32_t t_maxseg:24, /* maximum segment size */ + t_logstate:8; /* State of "black box" logging */ + uint32_t t_state:4, /* state of this connection */ + bits_spare : 24; u_int t_flags; - - struct vnet *t_vnet; /* back pointer to parent vnet */ - tcp_seq snd_una; /* sent but unacknowledged */ tcp_seq snd_max; /* highest sequence number sent; * used to recognize retransmits */ tcp_seq snd_nxt; /* send next */ tcp_seq snd_up; /* send urgent pointer */ - - tcp_seq snd_wl1; /* window update seg seq number */ - tcp_seq snd_wl2; /* window update seg ack number */ - tcp_seq iss; /* initial send sequence number */ - tcp_seq irs; /* initial receive sequence number */ - + uint32_t snd_wnd; /* send window */ + uint32_t snd_cwnd; /* congestion-controlled window */ + uint32_t cl1_spare; /* Spare to round out CL 1 */ + /* Cache line 2 */ + u_int32_t ts_offset; /* our timestamp offset */ + u_int32_t rfbuf_ts; /* recv buffer autoscaling timestamp */ + int rcv_numsacks; /* # distinct sack blks present */ + u_int t_tsomax; /* TSO total burst length limit in bytes */ + u_int t_tsomaxsegcount; /* TSO maximum segment count */ + u_int t_tsomaxsegsize; /* TSO maximum segment size in bytes */ tcp_seq rcv_nxt; /* receive next */ tcp_seq rcv_adv; /* advertised window */ uint32_t rcv_wnd; /* receive window */ + u_int t_flags2; /* More tcpcb flags storage */ + int t_srtt; /* smoothed round-trip time */ + int t_rttvar; /* variance in round-trip time */ + u_int32_t ts_recent; /* timestamp echo data */ + u_char snd_scale; /* window scaling for send window */ + u_char rcv_scale; /* window scaling for recv window */ + u_char snd_limited; /* segments limited transmitted */ + u_char request_r_scale; /* pending window scaling */ + tcp_seq last_ack_sent; + u_int t_rcvtime; /* inactivity time */ + /* Cache line 3 */ tcp_seq rcv_up; /* receive urgent pointer */ - - uint32_t snd_wnd; /* send window */ - uint32_t snd_cwnd; /* congestion-controlled window */ + int t_segqlen; /* segment reassembly queue length */ + struct tsegqe_head t_segq; /* segment reassembly queue */ + struct mbuf *t_in_pkt; + struct mbuf *t_tail_pkt; + struct tcp_timer *t_timers; /* All the TCP timers in one struct */ + struct vnet *t_vnet; /* back pointer to parent vnet */ uint32_t snd_ssthresh; /* snd_cwnd size threshold for * for slow start exponential to * linear switch */ + tcp_seq snd_wl1; /* window update seg seq number */ + /* Cache line 4 */ + tcp_seq snd_wl2; /* window update seg ack number */ + + tcp_seq irs; /* initial receive sequence number */ + tcp_seq iss; /* initial send sequence number */ + u_int t_acktime; + u_int ts_recent_age; /* when last updated */ tcp_seq snd_recover; /* for use in NewReno Fast Recovery */ + uint16_t cl4_spare; /* Spare to adjust CL 4 */ + char t_oobflags; /* have some */ + char t_iobc; /* input character */ + int t_rxtcur; /* current retransmit value (ticks) */ - u_int t_rcvtime; /* inactivity time */ - u_int t_starttime; /* time connection was established */ + int t_rxtshift; /* log(2) of rexmt exp. backoff */ u_int t_rtttime; /* RTT measurement start time */ + tcp_seq t_rtseq; /* sequence number being timed */ + u_int t_starttime; /* time connection was established */ - int t_rxtcur; /* current retransmit value (ticks) */ - u_int t_maxseg; /* maximum segment size */ u_int t_pmtud_saved_maxseg; /* pre-blackhole MSS */ - int t_srtt; /* smoothed round-trip time */ - int t_rttvar; /* variance in round-trip time */ - - int t_rxtshift; /* log(2) of rexmt exp. backoff */ u_int t_rttmin; /* minimum rtt allowed */ + u_int t_rttbest; /* best rtt we've seen */ - u_long t_rttupdated; /* number of times rtt sampled */ - uint32_t max_sndwnd; /* largest window peer has offered */ int t_softerror; /* possible error not yet reported */ -/* out-of-band data */ - char t_oobflags; /* have some */ - char t_iobc; /* input character */ -/* RFC 1323 variables */ - u_char snd_scale; /* window scaling for send window */ - u_char rcv_scale; /* window scaling for recv window */ - u_char request_r_scale; /* pending window scaling */ - u_int32_t ts_recent; /* timestamp echo data */ - u_int ts_recent_age; /* when last updated */ - u_int32_t ts_offset; /* our timestamp offset */ - - tcp_seq last_ack_sent; -/* experimental */ + uint32_t max_sndwnd; /* largest window peer has offered */ + /* Cache line 5 */ uint32_t snd_cwnd_prev; /* cwnd prior to retransmit */ uint32_t snd_ssthresh_prev; /* ssthresh prior to retransmit */ tcp_seq snd_recover_prev; /* snd_recover prior to retransmit */ int t_sndzerowin; /* zero-window updates sent */ - u_int t_badrxtwin; /* window for retransmit recovery */ - u_char snd_limited; /* segments limited transmitted */ -/* SACK related state */ + u_long t_rttupdated; /* number of times rtt sampled */ int snd_numholes; /* number of holes seen by sender */ + u_int t_badrxtwin; /* window for retransmit recovery */ TAILQ_HEAD(sackhole_head, sackhole) snd_holes; /* SACK scoreboard (sorted) */ tcp_seq snd_fack; /* last seq number(+1) sack'd by rcv'r*/ - int rcv_numsacks; /* # distinct sack blks present */ - struct sackblk sackblks[MAX_SACK_BLKS]; /* seq nos. of sack blocks */ tcp_seq sack_newdata; /* New data xmitted in this recovery episode starts at this seq number */ + struct sackblk sackblks[MAX_SACK_BLKS]; /* seq nos. of sack blocks */ struct sackhint sackhint; /* SACK scoreboard hint */ int t_rttlow; /* smallest observerved RTT */ - u_int32_t rfbuf_ts; /* recv buffer autoscaling timestamp */ int rfbuf_cnt; /* recv buffer autoscaling byte count */ struct toedev *tod; /* toedev handling this connection */ int t_sndrexmitpack; /* retransmit packets sent */ int t_rcvoopack; /* out-of-order packets received */ void *t_toe; /* TOE pcb pointer */ - int t_bytes_acked; /* # bytes acked during current RTT */ struct cc_algo *cc_algo; /* congestion control algorithm */ struct cc_var *ccv; /* congestion control specific vars */ struct osd *osd; /* storage for Khelp module data */ - + int t_bytes_acked; /* # bytes acked during current RTT */ u_int t_keepinit; /* time to establish connection */ u_int t_keepidle; /* time before keepalive probes begin */ u_int t_keepintvl; /* interval between keepalives */ u_int t_keepcnt; /* number of keepalives before close */ - - u_int t_tsomax; /* TSO total burst length limit in bytes */ - u_int t_tsomaxsegcount; /* TSO maximum segment count */ - u_int t_tsomaxsegsize; /* TSO maximum segment size in bytes */ - u_int t_flags2; /* More tcpcb flags storage */ - int t_logstate; /* State of "black box" logging */ - struct tcp_log_stailq t_logs; /* Log buffer */ + int t_dupacks; /* consecutive dup acks recd */ int t_lognum; /* Number of log entries */ - uint32_t t_logsn; /* Log "serial number" */ + struct tcp_log_stailq t_logs; /* Log buffer */ struct tcp_log_id_node *t_lin; struct tcp_log_id_bucket *t_lib; const char *t_output_caller; /* Function that called tcp_output */ - struct tcp_function_block *t_fb;/* TCP function call block */ - void *t_fb_ptr; /* Pointer to t_fb specific data */ + uint32_t t_logsn; /* Log "serial number" */ uint8_t t_tfo_client_cookie_len; /* TCP Fast Open client cookie length */ unsigned int *t_tfo_pending; /* TCP Fast Open server pending counter */ union { @@ -257,14 +257,19 @@ struct tcptemp { struct tcp_function_block { char tfb_tcp_block_name[TCP_FUNCTION_NAME_LEN_MAX]; int (*tfb_tcp_output)(struct tcpcb *); + int (*tfb_tcp_output_wtime)(struct tcpcb *, const struct timeval *); void (*tfb_tcp_do_segment)(struct mbuf *, struct tcphdr *, struct socket *, struct tcpcb *, int, int, uint8_t, int); + void (*tfb_tcp_hpts_do_segment)(struct mbuf *, struct tcphdr *, + struct socket *, struct tcpcb *, + int, int, uint8_t, + int, int, struct timeval *); int (*tfb_tcp_ctloutput)(struct socket *so, struct sockopt *sopt, struct inpcb *inp, struct tcpcb *tp); /* Optional memory allocation/free routine */ - void (*tfb_tcp_fb_init)(struct tcpcb *); + int (*tfb_tcp_fb_init)(struct tcpcb *); void (*tfb_tcp_fb_fini)(struct tcpcb *, int); /* Optional timers, must define all if you define one */ int (*tfb_tcp_timer_stop_all)(struct tcpcb *); @@ -274,6 +279,7 @@ struct tcp_function_block { void (*tfb_tcp_timer_stop)(struct tcpcb *, uint32_t); void (*tfb_tcp_rexmit_tmr)(struct tcpcb *); int (*tfb_tcp_handoff_ok)(struct tcpcb *); + void (*tfb_tcp_mtu_chg)(struct tcpcb *); volatile uint32_t tfb_refcnt; uint32_t tfb_flags; uint8_t tfb_id; @@ -688,11 +694,14 @@ void tcp_inptoxtp(const struct inpcb *, struct xtcpcb *); #endif /* - * TCP function name-to-id mapping exported to user-land via sysctl(3). + * TCP function information (name-to-id mapping, aliases, and refcnt) + * exported to user-land via sysctl(3). */ -struct tcp_function_id { +struct tcp_function_info { + uint32_t tfi_refcnt; uint8_t tfi_id; char tfi_name[TCP_FUNCTION_NAME_LEN_MAX]; + char tfi_alias[TCP_FUNCTION_NAME_LEN_MAX]; }; /* @@ -848,9 +857,12 @@ int register_tcp_functions_as_names(struct tcp_function_block *blk, int wait, const char *names[], int *num_names); int register_tcp_functions_as_name(struct tcp_function_block *blk, const char *name, int wait); -int deregister_tcp_functions(struct tcp_function_block *blk); +int deregister_tcp_functions(struct tcp_function_block *blk, bool quiesce, + bool force); struct tcp_function_block *find_and_ref_tcp_functions(struct tcp_function_set *fs); -struct tcp_function_block *find_and_ref_tcp_fb(struct tcp_function_block *blk); +void tcp_switch_back_to_default(struct tcpcb *tp); +struct tcp_function_block * +find_and_ref_tcp_fb(struct tcp_function_block *fs); int tcp_default_ctloutput(struct socket *so, struct sockopt *sopt, struct inpcb *inp, struct tcpcb *tp); uint32_t tcp_maxmtu(struct in_conninfo *, struct tcp_ifcap *); diff --git a/freebsd/sys/netinet/toecore.h b/freebsd/sys/netinet/toecore.h index 633984a6..f2374d70 100644 --- a/freebsd/sys/netinet/toecore.h +++ b/freebsd/sys/netinet/toecore.h @@ -38,6 +38,7 @@ struct tcpopt; struct tcphdr; struct in_conninfo; +struct tcp_info; struct toedev { TAILQ_ENTRY(toedev) link; /* glue for toedev_list */ @@ -101,6 +102,10 @@ struct toedev { /* TCP socket option */ void (*tod_ctloutput)(struct toedev *, struct tcpcb *, int, int); + + /* Update software state */ + void (*tod_tcp_info)(struct toedev *, struct tcpcb *, + struct tcp_info *); }; #include <sys/eventhandler.h> diff --git a/freebsd/sys/netinet/udp_usrreq.c b/freebsd/sys/netinet/udp_usrreq.c index da2dbe98..178a8d5e 100644 --- a/freebsd/sys/netinet/udp_usrreq.c +++ b/freebsd/sys/netinet/udp_usrreq.c @@ -842,6 +842,7 @@ udp_pcblist(SYSCTL_HANDLER_ARGS) { int error, i, n; struct inpcb *inp, **inp_list; + struct in_pcblist *il; inp_gen_t gencnt; struct xinpgen xig; @@ -879,10 +880,8 @@ udp_pcblist(SYSCTL_HANDLER_ARGS) error = SYSCTL_OUT(req, &xig, sizeof xig); if (error) return (error); - - inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK); - if (inp_list == NULL) - return (ENOMEM); + il = malloc(sizeof(struct in_pcblist) + n * sizeof(struct inpcb *), M_TEMP, M_WAITOK|M_ZERO_INVARIANTS); + inp_list = il->il_inp_list; INP_INFO_RLOCK(&V_udbinfo); for (inp = LIST_FIRST(V_udbinfo.ipi_listhead), i = 0; inp && i < n; @@ -911,14 +910,9 @@ udp_pcblist(SYSCTL_HANDLER_ARGS) } else INP_RUNLOCK(inp); } - INP_INFO_WLOCK(&V_udbinfo); - for (i = 0; i < n; i++) { - inp = inp_list[i]; - INP_RLOCK(inp); - if (!in_pcbrele_rlocked(inp)) - INP_RUNLOCK(inp); - } - INP_INFO_WUNLOCK(&V_udbinfo); + il->il_count = n; + il->il_pcbinfo = &V_udbinfo; + epoch_call(net_epoch_preempt, &il->il_epoch_ctx, in_pcblist_rele_rlocked); if (!error) { /* @@ -934,7 +928,6 @@ udp_pcblist(SYSCTL_HANDLER_ARGS) INP_INFO_RUNLOCK(&V_udbinfo); error = SYSCTL_OUT(req, &xig, sizeof xig); } - free(inp_list, M_TEMP); return (error); } @@ -1578,6 +1571,7 @@ udp_abort(struct socket *so) static int udp_attach(struct socket *so, int proto, struct thread *td) { + static uint32_t udp_flowid; struct inpcb *inp; struct inpcbinfo *pcbinfo; int error; @@ -1598,6 +1592,8 @@ udp_attach(struct socket *so, int proto, struct thread *td) inp = sotoinpcb(so); inp->inp_vflag |= INP_IPV4; inp->inp_ip_ttl = V_ip_defttl; + inp->inp_flowid = atomic_fetchadd_int(&udp_flowid, 1); + inp->inp_flowtype = M_HASHTYPE_OPAQUE; error = udp_newudpcb(inp); if (error) { @@ -1723,6 +1719,7 @@ udp_detach(struct socket *so) INP_WLOCK(inp); up = intoudpcb(inp); KASSERT(up != NULL, ("%s: up == NULL", __func__)); + /* XXX defer to epoch_call */ inp->inp_ppcb = NULL; in_pcbdetach(inp); in_pcbfree(inp); diff --git a/freebsd/sys/netinet6/icmp6.c b/freebsd/sys/netinet6/icmp6.c index 77876599..4d06ca16 100644 --- a/freebsd/sys/netinet6/icmp6.c +++ b/freebsd/sys/netinet6/icmp6.c @@ -385,15 +385,6 @@ icmp6_error(struct mbuf *m, int type, int code, int param) icmp6->icmp6_code = code; icmp6->icmp6_pptr = htonl((u_int32_t)param); - /* - * icmp6_reflect() is designed to be in the input path. - * icmp6_error() can be called from both input and output path, - * and if we are in output path rcvif could contain bogus value. - * clear m->m_pkthdr.rcvif for safety, we should have enough scope - * information in ip header (nip6). - */ - m->m_pkthdr.rcvif = NULL; - ICMP6STAT_INC(icp6s_outhist[type]); icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - ICMPv6 */ @@ -1700,10 +1691,10 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m, struct ifnet **ifpp, } IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { addrsofif = 0; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ifa6 = (struct in6_ifaddr *)ifa; @@ -1784,12 +1775,12 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6, struct icmp6_nodeinfo *nni6, return (0); /* needless to copy */ IFNET_RLOCK_NOSLEEP(); - ifp = ifp0 ? ifp0 : TAILQ_FIRST(&V_ifnet); + ifp = ifp0 ? ifp0 : CK_STAILQ_FIRST(&V_ifnet); again: - for (; ifp; ifp = TAILQ_NEXT(ifp, if_link)) { + for (; ifp; ifp = CK_STAILQ_NEXT(ifp, if_link)) { IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ifa6 = (struct in6_ifaddr *)ifa; @@ -2197,7 +2188,7 @@ icmp6_reflect(struct mbuf *m, size_t off) */ m->m_flags &= ~(M_BCAST|M_MCAST); - + m->m_pkthdr.rcvif = NULL; ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL); if (outif) icmp6_ifoutstat_inc(outif, type, code); diff --git a/freebsd/sys/netinet6/in6.c b/freebsd/sys/netinet6/in6.c index a5d84d85..3ed80c9c 100644 --- a/freebsd/sys/netinet6/in6.c +++ b/freebsd/sys/netinet6/in6.c @@ -67,7 +67,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <rtems/bsd/local/opt_compat.h> #include <rtems/bsd/local/opt_inet.h> #include <rtems/bsd/local/opt_inet6.h> @@ -82,6 +81,7 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/priv.h> #include <sys/proc.h> +#include <sys/protosw.h> #include <sys/time.h> #include <sys/kernel.h> #include <sys/lock.h> @@ -114,6 +114,7 @@ __FBSDID("$FreeBSD$"); #include <netinet6/in6_fib.h> #include <netinet6/in6_pcb.h> + /* * struct in6_ifreq and struct ifreq must be type punnable for common members * of ifr_ifru to allow accessors to be shared. @@ -690,7 +691,6 @@ aifaddr_out: * The failure means address duplication was detected. */ } - EVENTHANDLER_INVOKE(ifaddr_event, ifp); break; } @@ -737,6 +737,30 @@ out: } +static struct in6_multi_mship * +in6_joingroup_legacy(struct ifnet *ifp, const struct in6_addr *mcaddr, + int *errorp, int delay) +{ + struct in6_multi_mship *imm; + int error; + + imm = malloc(sizeof(*imm), M_IP6MADDR, M_NOWAIT); + if (imm == NULL) { + *errorp = ENOBUFS; + return (NULL); + } + + delay = (delay * PR_FASTHZ) / hz; + + error = in6_joingroup(ifp, mcaddr, NULL, &imm->i6mm_maddr, delay); + if (error) { + *errorp = error; + free(imm, M_IP6MADDR); + return (NULL); + } + + return (imm); +} /* * Join necessary multicast groups. Factored out from in6_update_ifa(). * This entire work should only be done once, for the default FIB. @@ -773,7 +797,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra, */ delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz); } - imm = in6_joingroup(ifp, &mltaddr, &error, delay); + imm = in6_joingroup_legacy(ifp, &mltaddr, &error, delay); if (imm == NULL) { nd6log((LOG_WARNING, "%s: in6_joingroup failed for %s on %s " "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &mltaddr), @@ -790,7 +814,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra, if ((error = in6_setscope(&mltaddr, ifp, NULL)) != 0) goto cleanup; /* XXX: should not fail */ - imm = in6_joingroup(ifp, &mltaddr, &error, 0); + imm = in6_joingroup_legacy(ifp, &mltaddr, &error, 0); if (imm == NULL) { nd6log((LOG_WARNING, "%s: in6_joingroup failed for %s on %s " "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &mltaddr), @@ -812,7 +836,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra, } if (in6_nigroup(ifp, NULL, -1, &mltaddr) == 0) { /* XXX jinmei */ - imm = in6_joingroup(ifp, &mltaddr, &error, delay); + imm = in6_joingroup_legacy(ifp, &mltaddr, &error, delay); if (imm == NULL) nd6log((LOG_WARNING, "%s: in6_joingroup failed for %s on %s " @@ -824,7 +848,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra, } if (V_icmp6_nodeinfo_oldmcprefix && in6_nigroup_oldmcprefix(ifp, NULL, -1, &mltaddr) == 0) { - imm = in6_joingroup(ifp, &mltaddr, &error, delay); + imm = in6_joingroup_legacy(ifp, &mltaddr, &error, delay); if (imm == NULL) nd6log((LOG_WARNING, "%s: in6_joingroup failed for %s on %s " @@ -843,7 +867,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra, if ((error = in6_setscope(&mltaddr, ifp, NULL)) != 0) goto cleanup; /* XXX: should not fail */ - imm = in6_joingroup(ifp, &mltaddr, &error, 0); + imm = in6_joingroup_legacy(ifp, &mltaddr, &error, 0); if (imm == NULL) { nd6log((LOG_WARNING, "%s: in6_joingroup failed for %s on %s " "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, @@ -1099,13 +1123,13 @@ in6_alloc_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, int flags) ia->ia_ifp = ifp; ifa_ref(&ia->ia_ifa); /* if_addrhead */ IF_ADDR_WLOCK(ifp); - TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); + CK_STAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_ref(&ia->ia_ifa); /* in6_ifaddrhead */ IN6_IFADDR_WLOCK(); - TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link); - LIST_INSERT_HEAD(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia, ia6_hash); + CK_STAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link); + CK_LIST_INSERT_HEAD(IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia, ia6_hash); IN6_IFADDR_WUNLOCK(); return (ia); @@ -1278,7 +1302,9 @@ in6_purgeaddr(struct ifaddr *ifa) /* Leave multicast groups. */ while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { LIST_REMOVE(imm, i6mm_chain); - in6_leavegroup(imm); + if (imm->i6mm_maddr != NULL) + in6_leavegroup(imm->i6mm_maddr, NULL); + free(imm, M_IP6MADDR); } plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ if ((ia->ia_flags & IFA_ROUTE) && plen == 128) { @@ -1301,7 +1327,7 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) int remove_lle; IF_ADDR_WLOCK(ifp); - TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); + CK_STAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifaddr, ifa_link); IF_ADDR_WUNLOCK(ifp); ifa_free(&ia->ia_ifa); /* if_addrhead */ @@ -1311,8 +1337,8 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) * cleanup. */ IN6_IFADDR_WLOCK(); - TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link); - LIST_REMOVE(ia, ia6_hash); + CK_STAILQ_REMOVE(&V_in6_ifaddrhead, ia, in6_ifaddr, ia_link); + CK_LIST_REMOVE(ia, ia6_hash); IN6_IFADDR_WUNLOCK(); /* @@ -1366,7 +1392,7 @@ in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia, */ if (hostIsNew != 0) { IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ifacount++; @@ -1377,7 +1403,7 @@ in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia, if (ifacount <= 1 && ifp->if_ioctl) { error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); if (error) - return (error); + goto done; } /* @@ -1417,7 +1443,7 @@ in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia, ia->ia_flags |= IFA_RTSELF; error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags); if (error) - return (error); + goto done; ia->ia_flags |= IFA_ROUTE; } @@ -1430,6 +1456,11 @@ in6_notify_ifa(struct ifnet *ifp, struct in6_ifaddr *ia, if (error == 0) ia->ia_flags |= IFA_RTSELF; } +done: + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, + "Invoking IPv6 network device address event may sleep"); + + EVENTHANDLER_INVOKE(ifaddr_event, ifp); return (error); } @@ -1444,7 +1475,7 @@ in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags) struct ifaddr *ifa; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { @@ -1472,7 +1503,7 @@ in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid) struct in6_ifaddr *ia; IN6_IFADDR_RLOCK(&in6_ifa_tracker); - LIST_FOREACH(ia, IN6ADDR_HASH(addr), ia6_hash) { + CK_LIST_FOREACH(ia, IN6ADDR_HASH(addr), ia6_hash) { if (IN6_ARE_ADDR_EQUAL(IA6_IN6(ia), addr)) { if (zoneid != 0 && zoneid != ia->ia_addr.sin6_scope_id) @@ -1495,7 +1526,7 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, const struct in6_addr *addr) struct ifaddr *ifa; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) { @@ -1520,7 +1551,7 @@ in6ifa_llaonifp(struct ifnet *ifp) if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) return (NULL); IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; @@ -1626,7 +1657,7 @@ in6_localaddr(struct in6_addr *in6) return 1; IN6_IFADDR_RLOCK(&in6_ifa_tracker); - TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr, &ia->ia_prefixmask.sin6_addr)) { IN6_IFADDR_RUNLOCK(&in6_ifa_tracker); @@ -1649,7 +1680,7 @@ in6_localip(struct in6_addr *in6) struct in6_ifaddr *ia; IN6_IFADDR_RLOCK(&in6_ifa_tracker); - LIST_FOREACH(ia, IN6ADDR_HASH(in6), ia6_hash) { + CK_LIST_FOREACH(ia, IN6ADDR_HASH(in6), ia6_hash) { if (IN6_ARE_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr)) { IN6_IFADDR_RUNLOCK(&in6_ifa_tracker); return (1); @@ -1675,7 +1706,7 @@ in6_ifhasaddr(struct ifnet *ifp, struct in6_addr *addr) in6_setscope(&in6, ifp, NULL); IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ia6 = (struct in6_ifaddr *)ifa; @@ -1696,7 +1727,7 @@ in6_is_addr_deprecated(struct sockaddr_in6 *sa6) struct in6_ifaddr *ia; IN6_IFADDR_RLOCK(&in6_ifa_tracker); - LIST_FOREACH(ia, IN6ADDR_HASH(&sa6->sin6_addr), ia6_hash) { + CK_LIST_FOREACH(ia, IN6ADDR_HASH(&sa6->sin6_addr), ia6_hash) { if (IN6_ARE_ADDR_EQUAL(IA6_IN6(ia), &sa6->sin6_addr)) { if (ia->ia6_flags & IN6_IFF_DEPRECATED) { IN6_IFADDR_RUNLOCK(&in6_ifa_tracker); @@ -1802,7 +1833,7 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) * If none, return one of global addresses assigned other ifs. */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) @@ -1839,7 +1870,7 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) return (besta); } - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) @@ -1886,7 +1917,7 @@ in6_if_up(struct ifnet *ifp) struct in6_ifaddr *ia; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; @@ -1946,7 +1977,7 @@ in6_setmaxmtu(void) struct ifnet *ifp; IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { /* this function can be called during ifnet initialization */ if (!ifp->if_afdata[AF_INET6]) continue; @@ -1977,12 +2008,8 @@ in6_if2idlen(struct ifnet *ifp) case IFT_BRIDGE: /* bridge(4) only does Ethernet-like links */ case IFT_INFINIBAND: return (64); - case IFT_FDDI: /* RFC2467 */ - return (64); case IFT_PPP: /* RFC2472 */ return (64); - case IFT_ARCNET: /* RFC2497 */ - return (64); case IFT_FRELAY: /* RFC2590 */ return (64); case IFT_IEEE1394: /* RFC3146 */ @@ -2022,9 +2049,11 @@ struct in6_llentry { * Do actual deallocation of @lle. */ static void -in6_lltable_destroy_lle_unlocked(struct llentry *lle) +in6_lltable_destroy_lle_unlocked(epoch_context_t ctx) { + struct llentry *lle; + lle = __containerof(ctx, struct llentry, lle_epoch_ctx); LLE_LOCK_DESTROY(lle); LLE_REQ_DESTROY(lle); free(lle, M_LLTABLE); @@ -2039,7 +2068,7 @@ in6_lltable_destroy_lle(struct llentry *lle) { LLE_WUNLOCK(lle); - in6_lltable_destroy_lle_unlocked(lle); + epoch_call(net_epoch_preempt, &lle->lle_epoch_ctx, in6_lltable_destroy_lle_unlocked); } static struct llentry * @@ -2142,11 +2171,13 @@ in6_lltable_rtcheck(struct ifnet *ifp, * Create an ND6 cache for an IPv6 neighbor * that is not covered by our own prefix. */ + NET_EPOCH_ENTER(); ifa = ifaof_ifpforaddr(l3addr, ifp); if (ifa != NULL) { - ifa_free(ifa); + NET_EPOCH_EXIT(); return 0; } + NET_EPOCH_EXIT(); log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", ip6_sprintf(ip6buf, &sin6->sin6_addr)); return EINVAL; @@ -2208,7 +2239,7 @@ in6_lltable_find_dst(struct lltable *llt, const struct in6_addr *dst) hashidx = in6_lltable_hash_dst(dst, llt->llt_hsize); lleh = &llt->lle_head[hashidx]; - LIST_FOREACH(lle, lleh, lle_next) { + CK_LIST_FOREACH(lle, lleh, lle_next) { if (lle->la_flags & LLE_DELETED) continue; if (IN6_ARE_ADDR_EQUAL(&lle->r_l3addr.addr6, dst)) @@ -2263,7 +2294,7 @@ in6_lltable_alloc(struct lltable *llt, u_int flags, linkhdrsize = LLE_MAX_LINKHDR; if (lltable_calc_llheader(ifp, AF_INET6, IF_LLADDR(ifp), linkhdr, &linkhdrsize, &lladdr_off) != 0) { - in6_lltable_destroy_lle_unlocked(lle); + epoch_call(net_epoch_preempt, &lle->lle_epoch_ctx, in6_lltable_destroy_lle_unlocked); return (NULL); } lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, @@ -2328,62 +2359,58 @@ in6_lltable_dump_entry(struct lltable *llt, struct llentry *lle, int error; bzero(&ndpc, sizeof(ndpc)); - /* skip deleted entries */ - if ((lle->la_flags & LLE_DELETED) == LLE_DELETED) - return (0); - /* Skip if jailed and not a valid IP of the prison. */ - lltable_fill_sa_entry(lle, - (struct sockaddr *)&ndpc.sin6); - if (prison_if(wr->td->td_ucred, - (struct sockaddr *)&ndpc.sin6) != 0) - return (0); - /* - * produce a msg made of: - * struct rt_msghdr; - * struct sockaddr_in6 (IPv6) - * struct sockaddr_dl; - */ - ndpc.rtm.rtm_msglen = sizeof(ndpc); - ndpc.rtm.rtm_version = RTM_VERSION; - ndpc.rtm.rtm_type = RTM_GET; - ndpc.rtm.rtm_flags = RTF_UP; - ndpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; - if (V_deembed_scopeid) - sa6_recoverscope(&ndpc.sin6); - - /* publish */ - if (lle->la_flags & LLE_PUB) - ndpc.rtm.rtm_flags |= RTF_ANNOUNCE; - - sdl = &ndpc.sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_len = sizeof(*sdl); - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = ifp->if_type; - if ((lle->la_flags & LLE_VALID) == LLE_VALID) { - sdl->sdl_alen = ifp->if_addrlen; - bcopy(lle->ll_addr, LLADDR(sdl), - ifp->if_addrlen); - } else { - sdl->sdl_alen = 0; - bzero(LLADDR(sdl), ifp->if_addrlen); - } - if (lle->la_expire != 0) - ndpc.rtm.rtm_rmx.rmx_expire = lle->la_expire + - lle->lle_remtime / hz + - time_second - time_uptime; - ndpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); - if (lle->la_flags & LLE_STATIC) - ndpc.rtm.rtm_flags |= RTF_STATIC; - if (lle->la_flags & LLE_IFADDR) - ndpc.rtm.rtm_flags |= RTF_PINNED; - if (lle->ln_router != 0) - ndpc.rtm.rtm_flags |= RTF_GATEWAY; - ndpc.rtm.rtm_rmx.rmx_pksent = lle->la_asked; - /* Store state in rmx_weight value */ - ndpc.rtm.rtm_rmx.rmx_state = lle->ln_state; - ndpc.rtm.rtm_index = ifp->if_index; - error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc)); + /* skip deleted entries */ + if ((lle->la_flags & LLE_DELETED) == LLE_DELETED) + return (0); + /* Skip if jailed and not a valid IP of the prison. */ + lltable_fill_sa_entry(lle, (struct sockaddr *)&ndpc.sin6); + if (prison_if(wr->td->td_ucred, (struct sockaddr *)&ndpc.sin6) != 0) + return (0); + /* + * produce a msg made of: + * struct rt_msghdr; + * struct sockaddr_in6 (IPv6) + * struct sockaddr_dl; + */ + ndpc.rtm.rtm_msglen = sizeof(ndpc); + ndpc.rtm.rtm_version = RTM_VERSION; + ndpc.rtm.rtm_type = RTM_GET; + ndpc.rtm.rtm_flags = RTF_UP; + ndpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; + if (V_deembed_scopeid) + sa6_recoverscope(&ndpc.sin6); + + /* publish */ + if (lle->la_flags & LLE_PUB) + ndpc.rtm.rtm_flags |= RTF_ANNOUNCE; + + sdl = &ndpc.sdl; + sdl->sdl_family = AF_LINK; + sdl->sdl_len = sizeof(*sdl); + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = ifp->if_type; + if ((lle->la_flags & LLE_VALID) == LLE_VALID) { + sdl->sdl_alen = ifp->if_addrlen; + bcopy(lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); + } else { + sdl->sdl_alen = 0; + bzero(LLADDR(sdl), ifp->if_addrlen); + } + if (lle->la_expire != 0) + ndpc.rtm.rtm_rmx.rmx_expire = lle->la_expire + + lle->lle_remtime / hz + time_second - time_uptime; + ndpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); + if (lle->la_flags & LLE_STATIC) + ndpc.rtm.rtm_flags |= RTF_STATIC; + if (lle->la_flags & LLE_IFADDR) + ndpc.rtm.rtm_flags |= RTF_PINNED; + if (lle->ln_router != 0) + ndpc.rtm.rtm_flags |= RTF_GATEWAY; + ndpc.rtm.rtm_rmx.rmx_pksent = lle->la_asked; + /* Store state in rmx_weight value */ + ndpc.rtm.rtm_rmx.rmx_state = lle->ln_state; + ndpc.rtm.rtm_index = ifp->if_index; + error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc)); return (error); } diff --git a/freebsd/sys/netinet6/in6_ifattach.c b/freebsd/sys/netinet6/in6_ifattach.c index 1ce489f5..81182b4e 100644 --- a/freebsd/sys/netinet6/in6_ifattach.c +++ b/freebsd/sys/netinet6/in6_ifattach.c @@ -255,7 +255,7 @@ in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; sdl = (struct sockaddr_dl *)ifa->ifa_addr; @@ -280,7 +280,6 @@ found: case IFT_BRIDGE: case IFT_ETHER: case IFT_L2VLAN: - case IFT_FDDI: case IFT_ATM: case IFT_IEEE1394: /* IEEE802/EUI64 cases - what others? */ @@ -323,26 +322,6 @@ found: } break; - case IFT_ARCNET: - if (addrlen != 1) { - IF_ADDR_RUNLOCK(ifp); - return -1; - } - if (!addr[0]) { - IF_ADDR_RUNLOCK(ifp); - return -1; - } - - bzero(&in6->s6_addr[8], 8); - in6->s6_addr[15] = addr[0]; - - /* - * due to insufficient bitwidth, we mark it local. - */ - in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ - in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ - break; - case IFT_GIF: case IFT_STF: /* @@ -411,7 +390,7 @@ get_ifid(struct ifnet *ifp0, struct ifnet *altifp, /* next, try to get it from some other hardware interface */ IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if (ifp == ifp0) continue; if (in6_get_hw_ifid(ifp, in6) != 0) @@ -782,7 +761,7 @@ _in6_ifdetach(struct ifnet *ifp, int purgeulp) * nuke any of IPv6 addresses we have * XXX: all addresses should be already removed */ - TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { + CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; in6_purgeaddr(ifa); @@ -857,7 +836,7 @@ in6_tmpaddrtimer(void *arg) V_ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, curvnet); bzero(nullbuf, sizeof(nullbuf)); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if (ifp->if_afdata[AF_INET6] == NULL) continue; ndi = ND_IFINFO(ifp); @@ -877,36 +856,35 @@ in6_tmpaddrtimer(void *arg) static void in6_purgemaddrs(struct ifnet *ifp) { - LIST_HEAD(,in6_multi) purgeinms; - struct in6_multi *inm, *tinm; - struct ifmultiaddr *ifma; + struct in6_multi_head purgeinms; + struct in6_multi *inm; + struct ifmultiaddr *ifma, *next; - LIST_INIT(&purgeinms); + SLIST_INIT(&purgeinms); IN6_MULTI_LOCK(); - + IN6_MULTI_LIST_LOCK(); + IF_ADDR_WLOCK(ifp); /* * Extract list of in6_multi associated with the detaching ifp * which the PF_INET6 layer is about to release. - * We need to do this as IF_ADDR_LOCK() may be re-acquired - * by code further down. */ - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + restart: + CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { if (ifma->ifma_addr->sa_family != AF_INET6 || ifma->ifma_protospec == NULL) continue; inm = (struct in6_multi *)ifma->ifma_protospec; - LIST_INSERT_HEAD(&purgeinms, inm, in6m_entry); - } - IF_ADDR_RUNLOCK(ifp); - - LIST_FOREACH_SAFE(inm, &purgeinms, in6m_entry, tinm) { - LIST_REMOVE(inm, in6m_entry); - in6m_release_locked(inm); + in6m_rele_locked(&purgeinms, inm); + if (__predict_false(ifma6_restart)) { + ifma6_restart = false; + goto restart; + } } + IF_ADDR_WUNLOCK(ifp); mld_ifdetach(ifp); - + IN6_MULTI_LIST_UNLOCK(); IN6_MULTI_UNLOCK(); + in6m_release_list_deferred(&purgeinms); } void diff --git a/freebsd/sys/netinet6/in6_mcast.c b/freebsd/sys/netinet6/in6_mcast.c index a634b18b..32660c89 100644 --- a/freebsd/sys/netinet6/in6_mcast.c +++ b/freebsd/sys/netinet6/in6_mcast.c @@ -43,13 +43,13 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/gtaskqueue.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> -#include <sys/protosw.h> #include <sys/sysctl.h> #include <sys/priv.h> #include <sys/ktr.h> @@ -61,8 +61,12 @@ __FBSDID("$FreeBSD$"); #include <net/route.h> #include <net/vnet.h> + #include <netinet/in.h> +#include <netinet/udp.h> #include <netinet/in_var.h> +#include <netinet/ip_var.h> +#include <netinet/udp_var.h> #include <netinet6/in6_fib.h> #include <netinet6/in6_var.h> #include <netinet/ip6.h> @@ -91,7 +95,7 @@ typedef union sockunion sockunion_t; static MALLOC_DEFINE(M_IN6MFILTER, "in6_mfilter", "IPv6 multicast PCB-layer source filter"); -static MALLOC_DEFINE(M_IP6MADDR, "in6_multi", "IPv6 multicast group"); +MALLOC_DEFINE(M_IP6MADDR, "in6_multi", "IPv6 multicast group"); static MALLOC_DEFINE(M_IP6MOPTS, "ip6_moptions", "IPv6 multicast options"); static MALLOC_DEFINE(M_IP6MSOURCE, "ip6_msource", "IPv6 multicast MLD-layer source filter"); @@ -109,8 +113,16 @@ RB_GENERATE(ip6_msource_tree, ip6_msource, im6s_link, ip6_msource_cmp); * any need for in6_multi itself to be virtualized -- it is bound to an ifp * anyway no matter what happens. */ -struct mtx in6_multi_mtx; -MTX_SYSINIT(in6_multi_mtx, &in6_multi_mtx, "in6_multi_mtx", MTX_DEF); +struct mtx in6_multi_list_mtx; +MTX_SYSINIT(in6_multi_mtx, &in6_multi_list_mtx, "in6_multi_list_mtx", MTX_DEF); + +struct mtx in6_multi_free_mtx; +MTX_SYSINIT(in6_multi_free_mtx, &in6_multi_free_mtx, "in6_multi_free_mtx", MTX_DEF); + +struct sx in6_multi_sx; +SX_SYSINIT(in6_multi_sx, &in6_multi_sx, "in6_multi_sx"); + + static void im6f_commit(struct in6_mfilter *); static int im6f_get_source(struct in6_mfilter *imf, @@ -132,7 +144,7 @@ static struct in6_msource * const struct sockaddr *); static void im6s_merge(struct ip6_msource *ims, const struct in6_msource *lims, const int rollback); -static int in6_mc_get(struct ifnet *, const struct in6_addr *, +static int in6_getmulti(struct ifnet *, const struct in6_addr *, struct in6_multi **); static int in6m_get_source(struct in6_multi *inm, const struct in6_addr *addr, const int noalloc, @@ -180,6 +192,7 @@ static SYSCTL_NODE(_net_inet6_ip6_mcast, OID_AUTO, filters, CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_ip6_mcast_filters, "Per-interface stack-wide source filters"); +int ifma6_restart = 0; #ifdef KTR /* * Inline function which wraps assertions for a valid ifp. @@ -391,7 +404,7 @@ im6o_mc_filter(const struct ip6_moptions *imo, const struct ifnet *ifp, * Return 0 if successful, otherwise return an appropriate error code. */ static int -in6_mc_get(struct ifnet *ifp, const struct in6_addr *group, +in6_getmulti(struct ifnet *ifp, const struct in6_addr *group, struct in6_multi **pinm) { struct sockaddr_in6 gsin6; @@ -407,8 +420,8 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group, * re-acquire around the call. */ IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK(); IF_ADDR_WLOCK(ifp); - inm = in6m_lookup_locked(ifp, group); if (inm != NULL) { /* @@ -417,7 +430,7 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group, */ KASSERT(inm->in6m_refcount >= 1, ("%s: bad refcount %d", __func__, inm->in6m_refcount)); - ++inm->in6m_refcount; + in6m_acquire_locked(inm); *pinm = inm; goto out_locked; } @@ -431,10 +444,12 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group, * Check if a link-layer group is already associated * with this network-layer group on the given ifnet. */ + IN6_MULTI_LIST_UNLOCK(); IF_ADDR_WUNLOCK(ifp); error = if_addmulti(ifp, (struct sockaddr *)&gsin6, &ifma); if (error != 0) return (error); + IN6_MULTI_LIST_LOCK(); IF_ADDR_WLOCK(ifp); /* @@ -457,7 +472,7 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group, panic("%s: ifma %p is inconsistent with %p (%p)", __func__, ifma, inm, group); #endif - ++inm->in6m_refcount; + in6m_acquire_locked(inm); *pinm = inm; goto out_locked; } @@ -474,6 +489,7 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group, */ inm = malloc(sizeof(*inm), M_IP6MADDR, M_NOWAIT | M_ZERO); if (inm == NULL) { + IN6_MULTI_LIST_UNLOCK(); IF_ADDR_WUNLOCK(ifp); if_delmulti_ifma(ifma); return (ENOMEM); @@ -493,7 +509,8 @@ in6_mc_get(struct ifnet *ifp, const struct in6_addr *group, ifma->ifma_protospec = inm; *pinm = inm; -out_locked: + out_locked: + IN6_MULTI_LIST_UNLOCK(); IF_ADDR_WUNLOCK(ifp); return (error); } @@ -504,36 +521,139 @@ out_locked: * If the refcount drops to 0, free the in6_multi record and * delete the underlying link-layer membership. */ -void -in6m_release_locked(struct in6_multi *inm) +static void +in6m_release(struct in6_multi *inm) { struct ifmultiaddr *ifma; - - IN6_MULTI_LOCK_ASSERT(); + struct ifnet *ifp; CTR2(KTR_MLD, "%s: refcount is %d", __func__, inm->in6m_refcount); - if (--inm->in6m_refcount > 0) { - CTR2(KTR_MLD, "%s: refcount is now %d", __func__, - inm->in6m_refcount); - return; - } - + MPASS(inm->in6m_refcount == 0); CTR2(KTR_MLD, "%s: freeing inm %p", __func__, inm); ifma = inm->in6m_ifma; + ifp = inm->in6m_ifp; + MPASS(ifma->ifma_llifma == NULL); /* XXX this access is not covered by IF_ADDR_LOCK */ CTR2(KTR_MLD, "%s: purging ifma %p", __func__, ifma); - KASSERT(ifma->ifma_protospec == inm, - ("%s: ifma_protospec != inm", __func__)); - ifma->ifma_protospec = NULL; + KASSERT(ifma->ifma_protospec == NULL, + ("%s: ifma_protospec != NULL", __func__)); - in6m_purge(inm); + if (ifp != NULL) { + CURVNET_SET(ifp->if_vnet); + in6m_purge(inm); + free(inm, M_IP6MADDR); + if_delmulti_ifma_flags(ifma, 1); + CURVNET_RESTORE(); + if_rele(ifp); + } else { + in6m_purge(inm); + free(inm, M_IP6MADDR); + if_delmulti_ifma_flags(ifma, 1); + } +} + +static struct grouptask free_gtask; +static struct in6_multi_head in6m_free_list; +static void in6m_release_task(void *arg __unused); +static void in6m_init(void) +{ + SLIST_INIT(&in6m_free_list); + taskqgroup_config_gtask_init(NULL, &free_gtask, in6m_release_task, "in6m release task"); +} - free(inm, M_IP6MADDR); +SYSINIT(in6m_init, SI_SUB_SMP + 1, SI_ORDER_FIRST, + in6m_init, NULL); - if_delmulti_ifma(ifma); + +void +in6m_release_list_deferred(struct in6_multi_head *inmh) +{ + if (SLIST_EMPTY(inmh)) + return; + mtx_lock(&in6_multi_free_mtx); + SLIST_CONCAT(&in6m_free_list, inmh, in6_multi, in6m_nrele); + mtx_unlock(&in6_multi_free_mtx); + GROUPTASK_ENQUEUE(&free_gtask); +} + +void +in6m_disconnect(struct in6_multi *inm) +{ + struct ifnet *ifp; + struct ifaddr *ifa; + struct in6_ifaddr *ifa6; + struct in6_multi_mship *imm, *imm_tmp; + struct ifmultiaddr *ifma, *ll_ifma; + + ifp = inm->in6m_ifp; + IF_ADDR_WLOCK_ASSERT(ifp); + ifma = inm->in6m_ifma; + + if_ref(ifp); + CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); + MCDPRINTF("removed ifma: %p from %s\n", ifma, ifp->if_xname); + if ((ll_ifma = ifma->ifma_llifma) != NULL) { + MPASS(ifma != ll_ifma); + ifma->ifma_llifma = NULL; + MPASS(ll_ifma->ifma_llifma == NULL); + MPASS(ll_ifma->ifma_ifp == ifp); + if (--ll_ifma->ifma_refcount == 0) { + ifma6_restart = true; + CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link); + MCDPRINTF("removed ll_ifma: %p from %s\n", ll_ifma, ifp->if_xname); + if_freemulti(ll_ifma); + } + } + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + ifa6 = (void *)ifa; + LIST_FOREACH_SAFE(imm, &ifa6->ia6_memberships, + i6mm_chain, imm_tmp) { + if (inm == imm->i6mm_maddr) { + LIST_REMOVE(imm, i6mm_chain); + free(imm, M_IP6MADDR); + } + } + } +} + +void +in6m_release_deferred(struct in6_multi *inm) +{ + struct in6_multi_head tmp; + + IN6_MULTI_LIST_LOCK_ASSERT(); + KASSERT(inm->in6m_refcount > 0, ("refcount == %d inm: %p", inm->in6m_refcount, inm)); + if (--inm->in6m_refcount == 0) { + in6m_disconnect(inm); + SLIST_INIT(&tmp); + inm->in6m_ifma->ifma_protospec = NULL; + MPASS(inm->in6m_ifma->ifma_llifma == NULL); + SLIST_INSERT_HEAD(&tmp, inm, in6m_nrele); + in6m_release_list_deferred(&tmp); + } +} + +static void +in6m_release_task(void *arg __unused) +{ + struct in6_multi_head in6m_free_tmp; + struct in6_multi *inm, *tinm; + + SLIST_INIT(&in6m_free_tmp); + mtx_lock(&in6_multi_free_mtx); + SLIST_CONCAT(&in6m_free_tmp, &in6m_free_list, in6_multi, in6m_nrele); + mtx_unlock(&in6_multi_free_mtx); + IN6_MULTI_LOCK(); + SLIST_FOREACH_SAFE(inm, &in6m_free_tmp, in6m_nrele, tinm) { + SLIST_REMOVE_HEAD(&in6m_free_tmp, in6m_nrele); + in6m_release(inm); + } + IN6_MULTI_UNLOCK(); } /* @@ -546,7 +666,7 @@ in6m_clear_recorded(struct in6_multi *inm) { struct ip6_msource *ims; - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); RB_FOREACH(ims, ip6_msource_tree, &inm->in6m_srcs) { if (ims->im6s_stp) { @@ -586,7 +706,7 @@ in6m_record_source(struct in6_multi *inm, const struct in6_addr *addr) struct ip6_msource find; struct ip6_msource *ims, *nims; - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); find.im6s_addr = *addr; ims = RB_FIND(ip6_msource_tree, &inm->in6m_srcs, &find); @@ -913,6 +1033,7 @@ in6m_merge(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf) schanged = 0; error = 0; nsrc1 = nsrc0 = 0; + IN6_MULTI_LIST_LOCK_ASSERT(); /* * Update the source filters first, as this may fail. @@ -1089,65 +1210,16 @@ in6m_purge(struct in6_multi *inm) * * SMPng: Assume no mc locks held by caller. */ -struct in6_multi_mship * -in6_joingroup(struct ifnet *ifp, struct in6_addr *mcaddr, - int *errorp, int delay) -{ - struct in6_multi_mship *imm; - int error; - - imm = malloc(sizeof(*imm), M_IP6MADDR, M_NOWAIT); - if (imm == NULL) { - *errorp = ENOBUFS; - return (NULL); - } - - delay = (delay * PR_FASTHZ) / hz; - - error = in6_mc_join(ifp, mcaddr, NULL, &imm->i6mm_maddr, delay); - if (error) { - *errorp = error; - free(imm, M_IP6MADDR); - return (NULL); - } - - return (imm); -} - -/* - * Leave a multicast address w/o sources. - * KAME compatibility entry point. - * - * SMPng: Assume no mc locks held by caller. - */ -int -in6_leavegroup(struct in6_multi_mship *imm) -{ - - if (imm->i6mm_maddr != NULL) - in6_mc_leave(imm->i6mm_maddr, NULL); - free(imm, M_IP6MADDR); - return 0; -} - -/* - * Join a multicast group; unlocked entry point. - * - * SMPng: XXX: in6_mc_join() is called from in6_control() when upper - * locks are not held. Fortunately, ifp is unlikely to have been detached - * at this point, so we assume it's OK to recurse. - */ int -in6_mc_join(struct ifnet *ifp, const struct in6_addr *mcaddr, +in6_joingroup(struct ifnet *ifp, const struct in6_addr *mcaddr, /*const*/ struct in6_mfilter *imf, struct in6_multi **pinm, const int delay) { int error; IN6_MULTI_LOCK(); - error = in6_mc_join_locked(ifp, mcaddr, imf, pinm, delay); + error = in6_joingroup_locked(ifp, mcaddr, NULL, pinm, delay); IN6_MULTI_UNLOCK(); - return (error); } @@ -1161,12 +1233,13 @@ in6_mc_join(struct ifnet *ifp, const struct in6_addr *mcaddr, * code is returned. */ int -in6_mc_join_locked(struct ifnet *ifp, const struct in6_addr *mcaddr, +in6_joingroup_locked(struct ifnet *ifp, const struct in6_addr *mcaddr, /*const*/ struct in6_mfilter *imf, struct in6_multi **pinm, const int delay) { struct in6_mfilter timf; struct in6_multi *inm; + struct ifmultiaddr *ifma; int error; #ifdef KTR char ip6tbuf[INET6_ADDRSTRLEN]; @@ -1187,6 +1260,7 @@ in6_mc_join_locked(struct ifnet *ifp, const struct in6_addr *mcaddr, #endif IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_UNLOCK_ASSERT(); CTR4(KTR_MLD, "%s: join %s on %p(%s))", __func__, ip6_sprintf(ip6tbuf, mcaddr), ifp, if_name(ifp)); @@ -1202,13 +1276,13 @@ in6_mc_join_locked(struct ifnet *ifp, const struct in6_addr *mcaddr, im6f_init(&timf, MCAST_UNDEFINED, MCAST_EXCLUDE); imf = &timf; } - - error = in6_mc_get(ifp, mcaddr, &inm); + error = in6_getmulti(ifp, mcaddr, &inm); if (error) { - CTR1(KTR_MLD, "%s: in6_mc_get() failure", __func__); + CTR1(KTR_MLD, "%s: in6_getmulti() failure", __func__); return (error); } + IN6_MULTI_LIST_LOCK(); CTR1(KTR_MLD, "%s: merge inm state", __func__); error = in6m_merge(inm, imf); if (error) { @@ -1226,11 +1300,19 @@ in6_mc_join_locked(struct ifnet *ifp, const struct in6_addr *mcaddr, out_in6m_release: if (error) { CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm); - in6m_release_locked(inm); + IF_ADDR_RLOCK(ifp); + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_protospec == inm) { + ifma->ifma_protospec = NULL; + break; + } + } + in6m_release_deferred(inm); + IF_ADDR_RUNLOCK(ifp); } else { *pinm = inm; } - + IN6_MULTI_LIST_UNLOCK(); return (error); } @@ -1238,14 +1320,13 @@ out_in6m_release: * Leave a multicast group; unlocked entry point. */ int -in6_mc_leave(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf) +in6_leavegroup(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf) { int error; IN6_MULTI_LOCK(); - error = in6_mc_leave_locked(inm, imf); + error = in6_leavegroup_locked(inm, imf); IN6_MULTI_UNLOCK(); - return (error); } @@ -1263,9 +1344,10 @@ in6_mc_leave(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf) * makes a state change downcall into MLD. */ int -in6_mc_leave_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf) +in6_leavegroup_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf) { struct in6_mfilter timf; + struct ifnet *ifp; int error; #ifdef KTR char ip6tbuf[INET6_ADDRSTRLEN]; @@ -1296,6 +1378,9 @@ in6_mc_leave_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf) * to be allocated, and there is no opportunity to roll back * the transaction, it MUST NOT fail. */ + + ifp = inm->in6m_ifp; + IN6_MULTI_LIST_LOCK(); CTR1(KTR_MLD, "%s: merge inm state", __func__); error = in6m_merge(inm, imf); KASSERT(error == 0, ("%s: failed to merge inm state", __func__)); @@ -1306,11 +1391,17 @@ in6_mc_leave_locked(struct in6_multi *inm, /*const*/ struct in6_mfilter *imf) CTR1(KTR_MLD, "%s: failed mld downcall", __func__); CTR2(KTR_MLD, "%s: dropping ref on %p", __func__, inm); - in6m_release_locked(inm); + if (ifp) + IF_ADDR_WLOCK(ifp); + in6m_release_deferred(inm); + if (ifp) + IF_ADDR_WUNLOCK(ifp); + IN6_MULTI_LIST_UNLOCK(); return (error); } + /* * Block or unblock an ASM multicast source on an inpcb. * This implements the delta-based API described in RFC 3678. @@ -1448,8 +1539,7 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at MLD layer. */ - IN6_MULTI_LOCK(); - + IN6_MULTI_LIST_LOCK(); CTR1(KTR_MLD, "%s: merge inm state", __func__); error = in6m_merge(inm, imf); if (error) @@ -1461,7 +1551,7 @@ in6p_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_MLD, "%s: failed mld downcall", __func__); } - IN6_MULTI_UNLOCK(); + IN6_MULTI_LIST_UNLOCK(); out_im6f_rollback: if (error) @@ -1530,22 +1620,36 @@ in6p_findmoptions(struct inpcb *inp) * Discard the IPv6 multicast options (and source filters). * * SMPng: NOTE: assumes INP write lock is held. + * + * XXX can all be safely deferred to epoch_call + * */ -void -ip6_freemoptions(struct ip6_moptions *imo) + +static void +inp_gcmoptions(epoch_context_t ctx) { + struct ip6_moptions *imo; struct in6_mfilter *imf; + struct in6_multi *inm; + struct ifnet *ifp; size_t idx, nmships; - KASSERT(imo != NULL, ("%s: ip6_moptions is NULL", __func__)); + imo = __containerof(ctx, struct ip6_moptions, imo6_epoch_ctx); nmships = imo->im6o_num_memberships; for (idx = 0; idx < nmships; ++idx) { imf = imo->im6o_mfilters ? &imo->im6o_mfilters[idx] : NULL; if (imf) im6f_leave(imf); - /* XXX this will thrash the lock(s) */ - (void)in6_mc_leave(imo->im6o_membership[idx], imf); + inm = imo->im6o_membership[idx]; + ifp = inm->in6m_ifp; + if (ifp != NULL) { + CURVNET_SET(ifp->if_vnet); + (void)in6_leavegroup(inm, imf); + CURVNET_RESTORE(); + } else { + (void)in6_leavegroup(inm, imf); + } if (imf) im6f_purge(imf); } @@ -1556,6 +1660,14 @@ ip6_freemoptions(struct ip6_moptions *imo) free(imo, M_IP6MOPTS); } +void +ip6_freemoptions(struct ip6_moptions *imo) +{ + if (imo == NULL) + return; + epoch_call(net_epoch_preempt, &imo->imo6_epoch_ctx, inp_gcmoptions); +} + /* * Atomically get source filters on a socket for an IPv6 multicast group. * Called with INP lock held; returns with lock released. @@ -2036,10 +2148,12 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at MLD layer. */ + in_pcbref(inp); + INP_WUNLOCK(inp); IN6_MULTI_LOCK(); if (is_new) { - error = in6_mc_join_locked(ifp, &gsa->sin6.sin6_addr, imf, + error = in6_joingroup_locked(ifp, &gsa->sin6.sin6_addr, imf, &inm, 0); if (error) { IN6_MULTI_UNLOCK(); @@ -2048,6 +2162,7 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) imo->im6o_membership[idx] = inm; } else { CTR1(KTR_MLD, "%s: merge inm state", __func__); + IN6_MULTI_LIST_LOCK(); error = in6m_merge(inm, imf); if (error) CTR1(KTR_MLD, "%s: failed to merge inm state", @@ -2059,10 +2174,13 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_MLD, "%s: failed mld downcall", __func__); } + IN6_MULTI_LIST_UNLOCK(); } IN6_MULTI_UNLOCK(); - INP_WLOCK_ASSERT(inp); + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) + return (ENXIO); if (error) { im6f_rollback(imf); if (is_new) @@ -2277,6 +2395,8 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at MLD layer. */ + in_pcbref(inp); + INP_WUNLOCK(inp); IN6_MULTI_LOCK(); if (is_final) { @@ -2284,9 +2404,10 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) * Give up the multicast address record to which * the membership points. */ - (void)in6_mc_leave_locked(inm, imf); + (void)in6_leavegroup_locked(inm, imf); } else { CTR1(KTR_MLD, "%s: merge inm state", __func__); + IN6_MULTI_LIST_LOCK(); error = in6m_merge(inm, imf); if (error) CTR1(KTR_MLD, "%s: failed to merge inm state", @@ -2298,9 +2419,13 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_MLD, "%s: failed mld downcall", __func__); } + IN6_MULTI_LIST_UNLOCK(); } IN6_MULTI_UNLOCK(); + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) + return (ENXIO); if (error) im6f_rollback(imf); @@ -2507,7 +2632,7 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) goto out_im6f_rollback; INP_WLOCK_ASSERT(inp); - IN6_MULTI_LOCK(); + IN6_MULTI_LIST_LOCK(); /* * Begin state merge transaction at MLD layer. @@ -2523,7 +2648,7 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_MLD, "%s: failed mld downcall", __func__); } - IN6_MULTI_UNLOCK(); + IN6_MULTI_LIST_UNLOCK(); out_im6f_rollback: if (error) @@ -2714,9 +2839,9 @@ sysctl_ip6_mcast_filters(SYSCTL_HANDLER_ARGS) return (retval); IN6_MULTI_LOCK(); - + IN6_MULTI_LIST_LOCK(); IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_INET6 || ifma->ifma_protospec == NULL) continue; @@ -2746,6 +2871,7 @@ sysctl_ip6_mcast_filters(SYSCTL_HANDLER_ARGS) } IF_ADDR_RUNLOCK(ifp); + IN6_MULTI_LIST_UNLOCK(); IN6_MULTI_UNLOCK(); return (retval); diff --git a/freebsd/sys/netinet6/in6_pcb.c b/freebsd/sys/netinet6/in6_pcb.c index a4bbd6a9..488cca86 100644 --- a/freebsd/sys/netinet6/in6_pcb.c +++ b/freebsd/sys/netinet6/in6_pcb.c @@ -134,7 +134,7 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, INP_WLOCK_ASSERT(inp); INP_HASH_WLOCK_ASSERT(pcbinfo); - if (TAILQ_EMPTY(&V_in6_ifaddrhead)) /* XXX broken! */ + if (CK_STAILQ_EMPTY(&V_in6_ifaddrhead)) /* XXX broken! */ return (EADDRNOTAVAIL); if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) return (EINVAL); @@ -176,9 +176,11 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct ifaddr *ifa; sin6->sin6_port = 0; /* yech... */ + NET_EPOCH_ENTER(); if ((ifa = ifa_ifwithaddr((struct sockaddr *)sin6)) == NULL && (inp->inp_flags & INP_BINDANY) == 0) { + NET_EPOCH_EXIT(); return (EADDRNOTAVAIL); } @@ -191,11 +193,10 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, if (ifa != NULL && ((struct in6_ifaddr *)ifa)->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) { - ifa_free(ifa); + NET_EPOCH_EXIT(); return (EADDRNOTAVAIL); } - if (ifa != NULL) - ifa_free(ifa); + NET_EPOCH_EXIT(); } if (lport) { struct inpcb *t; @@ -363,7 +364,7 @@ in6_pcbladdr(struct inpcb *inp, struct sockaddr *nam, if ((error = sa6_embedscope(sin6, V_ip6_use_defzone)) != 0) return(error); - if (!TAILQ_EMPTY(&V_in6_ifaddrhead)) { + if (!CK_STAILQ_EMPTY(&V_in6_ifaddrhead)) { /* * If the destination address is UNSPECIFIED addr, * use the loopback addr, e.g ::1. @@ -819,8 +820,7 @@ in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp) for (i = 0; i < im6o->im6o_num_memberships; i++) { if (im6o->im6o_membership[i]->in6m_ifp == ifp) { - in6_mc_leave(im6o->im6o_membership[i], - NULL); + in6_leavegroup(im6o->im6o_membership[i], NULL); gap++; } else if (gap != 0) { im6o->im6o_membership[i - gap] = diff --git a/freebsd/sys/netinet6/in6_proto.c b/freebsd/sys/netinet6/in6_proto.c index 55fbbe80..756ea48b 100644 --- a/freebsd/sys/netinet6/in6_proto.c +++ b/freebsd/sys/netinet6/in6_proto.c @@ -284,7 +284,6 @@ struct protosw inet6sw[] = { .pr_input = encap6_input, .pr_output = rip6_output, .pr_ctloutput = rip6_ctloutput, - .pr_init = encap_init, .pr_usrreqs = &rip6_usrreqs }, #endif /* INET */ @@ -296,7 +295,6 @@ struct protosw inet6sw[] = { .pr_input = encap6_input, .pr_output = rip6_output, .pr_ctloutput = rip6_ctloutput, - .pr_init = encap_init, .pr_usrreqs = &rip6_usrreqs }, { @@ -307,7 +305,6 @@ struct protosw inet6sw[] = { .pr_input = encap6_input, .pr_output = rip6_output, .pr_ctloutput = rip6_ctloutput, - .pr_init = encap_init, .pr_usrreqs = &rip6_usrreqs }, { diff --git a/freebsd/sys/netinet6/in6_src.c b/freebsd/sys/netinet6/in6_src.c index 5b110274..92f7df4e 100644 --- a/freebsd/sys/netinet6/in6_src.c +++ b/freebsd/sys/netinet6/in6_src.c @@ -311,7 +311,7 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock, return (error); IN6_IFADDR_RLOCK(&in6_ifa_tracker); - TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { int new_scope = -1, new_matchlen = -1; struct in6_addrpolicy *new_policy = NULL; u_int32_t srczone, osrczone, dstzone; diff --git a/freebsd/sys/netinet6/in6_var.h b/freebsd/sys/netinet6/in6_var.h index 2e22d962..6b4fe1ab 100644 --- a/freebsd/sys/netinet6/in6_var.h +++ b/freebsd/sys/netinet6/in6_var.h @@ -100,6 +100,7 @@ struct nd_ifinfo; struct scope6_id; struct lltable; struct mld_ifsoftc; +struct in6_multi; struct in6_ifextra { counter_u64_t *in6_ifstat; @@ -113,6 +114,10 @@ struct in6_ifextra { #define LLTABLE6(ifp) (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->lltable) #ifdef _KERNEL + +SLIST_HEAD(in6_multi_head, in6_multi); +MALLOC_DECLARE(M_IP6MADDR); + struct in6_ifaddr { struct ifaddr ia_ifa; /* protocol-independent info */ #define ia_ifp ia_ifa.ifa_ifp @@ -122,7 +127,7 @@ struct in6_ifaddr { struct sockaddr_in6 ia_dstaddr; /* space for destination addr */ struct sockaddr_in6 ia_prefixmask; /* prefix mask */ u_int32_t ia_plen; /* prefix length */ - TAILQ_ENTRY(in6_ifaddr) ia_link; /* list of IPv6 addresses */ + CK_STAILQ_ENTRY(in6_ifaddr) ia_link; /* list of IPv6 addresses */ int ia6_flags; struct in6_addrlifetime ia6_lifetime; @@ -137,12 +142,12 @@ struct in6_ifaddr { /* multicast addresses joined from the kernel */ LIST_HEAD(, in6_multi_mship) ia6_memberships; /* entry in bucket of inet6 addresses */ - LIST_ENTRY(in6_ifaddr) ia6_hash; + CK_LIST_ENTRY(in6_ifaddr) ia6_hash; }; /* List of in6_ifaddr's. */ -TAILQ_HEAD(in6_ifaddrhead, in6_ifaddr); -LIST_HEAD(in6_ifaddrlisthead, in6_ifaddr); +CK_STAILQ_HEAD(in6_ifaddrhead, in6_ifaddr); +CK_LIST_HEAD(in6_ifaddrlisthead, in6_ifaddr); #endif /* _KERNEL */ /* control structure to manage address selection policy */ @@ -630,7 +635,6 @@ struct in6_multi_mship { * w/o breaking the ABI for ifmcstat. */ struct in6_multi { - LIST_ENTRY(in6_multi) in6m_entry; /* list glue */ struct in6_addr in6m_addr; /* IPv6 multicast address */ struct ifnet *in6m_ifp; /* back pointer to ifnet */ struct ifmultiaddr *in6m_ifma; /* back pointer to ifmultiaddr */ @@ -666,6 +670,8 @@ struct in6_multi { } in6m_st[2]; /* state at t0, t1 */ }; +void in6m_disconnect(struct in6_multi *inm); +extern int ifma6_restart; /* * Helper function to derive the filter mode on a source entry * from its internal counters. Predicates are: @@ -694,11 +700,19 @@ im6s_get_mode(const struct in6_multi *inm, const struct ip6_msource *ims, * consumers of IN_*_MULTI() macros should acquire the locks before * calling them; users of the in_{add,del}multi() functions should not. */ -extern struct mtx in6_multi_mtx; -#define IN6_MULTI_LOCK() mtx_lock(&in6_multi_mtx) -#define IN6_MULTI_UNLOCK() mtx_unlock(&in6_multi_mtx) -#define IN6_MULTI_LOCK_ASSERT() mtx_assert(&in6_multi_mtx, MA_OWNED) -#define IN6_MULTI_UNLOCK_ASSERT() mtx_assert(&in6_multi_mtx, MA_NOTOWNED) +extern struct mtx in6_multi_list_mtx; +extern struct sx in6_multi_sx; + +#define IN6_MULTI_LIST_LOCK() mtx_lock(&in6_multi_list_mtx) +#define IN6_MULTI_LIST_UNLOCK() mtx_unlock(&in6_multi_list_mtx) +#define IN6_MULTI_LIST_LOCK_ASSERT() mtx_assert(&in6_multi_list_mtx, MA_OWNED) +#define IN6_MULTI_LIST_UNLOCK_ASSERT() mtx_assert(&in6_multi_list_mtx, MA_NOTOWNED) + +#define IN6_MULTI_LOCK() sx_xlock(&in6_multi_sx) +#define IN6_MULTI_UNLOCK() sx_xunlock(&in6_multi_sx) +#define IN6_MULTI_LOCK_ASSERT() sx_assert(&in6_multi_sx, SA_XLOCKED) +#define IN6_MULTI_UNLOCK_ASSERT() sx_assert(&in6_multi_sx, SA_XUNLOCKED) + /* * Look up an in6_multi record for an IPv6 multicast address @@ -713,13 +727,12 @@ in6m_lookup_locked(struct ifnet *ifp, const struct in6_addr *mcaddr) struct ifmultiaddr *ifma; struct in6_multi *inm; - IN6_MULTI_LOCK_ASSERT(); - IF_ADDR_LOCK_ASSERT(ifp); - inm = NULL; - TAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) { + CK_STAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) { if (ifma->ifma_addr->sa_family == AF_INET6) { inm = (struct in6_multi *)ifma->ifma_protospec; + if (inm == NULL) + continue; if (IN6_ARE_ADDR_EQUAL(&inm->in6m_addr, mcaddr)) break; inm = NULL; @@ -738,11 +751,11 @@ in6m_lookup(struct ifnet *ifp, const struct in6_addr *mcaddr) { struct in6_multi *inm; - IN6_MULTI_LOCK(); + IN6_MULTI_LIST_LOCK(); IF_ADDR_RLOCK(ifp); inm = in6m_lookup_locked(ifp, mcaddr); IF_ADDR_RUNLOCK(ifp); - IN6_MULTI_UNLOCK(); + IN6_MULTI_LIST_UNLOCK(); return (inm); } @@ -752,36 +765,55 @@ static __inline void in6m_acquire_locked(struct in6_multi *inm) { - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); ++inm->in6m_refcount; } +static __inline void +in6m_acquire(struct in6_multi *inm) +{ + IN6_MULTI_LIST_LOCK(); + in6m_acquire_locked(inm); + IN6_MULTI_LIST_UNLOCK(); +} + +static __inline void +in6m_rele_locked(struct in6_multi_head *inmh, struct in6_multi *inm) +{ + KASSERT(inm->in6m_refcount > 0, ("refcount == %d inm: %p", inm->in6m_refcount, inm)); + IN6_MULTI_LIST_LOCK_ASSERT(); + + if (--inm->in6m_refcount == 0) { + in6m_disconnect(inm); + inm->in6m_ifma->ifma_protospec = NULL; + MPASS(inm->in6m_ifma->ifma_llifma == NULL); + SLIST_INSERT_HEAD(inmh, inm, in6m_nrele); + } +} + struct ip6_moptions; struct sockopt; +struct inpcbinfo; /* Multicast KPIs. */ int im6o_mc_filter(const struct ip6_moptions *, const struct ifnet *, const struct sockaddr *, const struct sockaddr *); -int in6_mc_join(struct ifnet *, const struct in6_addr *, +int in6_joingroup(struct ifnet *, const struct in6_addr *, struct in6_mfilter *, struct in6_multi **, int); -int in6_mc_join_locked(struct ifnet *, const struct in6_addr *, +int in6_joingroup_locked(struct ifnet *, const struct in6_addr *, struct in6_mfilter *, struct in6_multi **, int); -int in6_mc_leave(struct in6_multi *, struct in6_mfilter *); -int in6_mc_leave_locked(struct in6_multi *, struct in6_mfilter *); +int in6_leavegroup(struct in6_multi *, struct in6_mfilter *); +int in6_leavegroup_locked(struct in6_multi *, struct in6_mfilter *); void in6m_clear_recorded(struct in6_multi *); void in6m_commit(struct in6_multi *); void in6m_print(const struct in6_multi *); int in6m_record_source(struct in6_multi *, const struct in6_addr *); -void in6m_release_locked(struct in6_multi *); +void in6m_release_deferred(struct in6_multi *); +void in6m_release_list_deferred(struct in6_multi_head *); void ip6_freemoptions(struct ip6_moptions *); int ip6_getmoptions(struct inpcb *, struct sockopt *); int ip6_setmoptions(struct inpcb *, struct sockopt *); -/* Legacy KAME multicast KPIs. */ -struct in6_multi_mship * - in6_joingroup(struct ifnet *, struct in6_addr *, int *, int); -int in6_leavegroup(struct in6_multi_mship *); - /* flags to in6_update_ifa */ #define IN6_IFAUPDATE_DADDELAY 0x1 /* first time to configure an address */ diff --git a/freebsd/sys/netinet6/ip6_fastfwd.c b/freebsd/sys/netinet6/ip6_fastfwd.c index 056f9315..f63c51bf 100644 --- a/freebsd/sys/netinet6/ip6_fastfwd.c +++ b/freebsd/sys/netinet6/ip6_fastfwd.c @@ -99,7 +99,8 @@ ip6_tryforward(struct mbuf *m) * Fallback conditions to ip6_input for slow path processing. */ ip6 = mtod(m, struct ip6_hdr *); - if (ip6->ip6_nxt == IPPROTO_HOPOPTS || + if ((m->m_flags & (M_BCAST | M_MCAST)) != 0 || + ip6->ip6_nxt == IPPROTO_HOPOPTS || IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst) || IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src) || @@ -196,12 +197,19 @@ passin: in6_ifstat_inc(rcvif, ifs6_in_noroute); goto dropin; } + if (!PFIL_HOOKED(&V_inet6_pfil_hook)) { + if (m->m_pkthdr.len > nh.nh_mtu) { + in6_ifstat_inc(nh.nh_ifp, ifs6_in_toobig); + icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, nh.nh_mtu); + m = NULL; + goto dropout; + } + goto passout; + } /* * Outgoing packet firewall processing. */ - if (!PFIL_HOOKED(&V_inet6_pfil_hook)) - goto passout; if (pfil_run_hooks(&V_inet6_pfil_hook, &m, nh.nh_ifp, PFIL_OUT, PFIL_FWD, NULL) != 0 || m == NULL) goto dropout; diff --git a/freebsd/sys/netinet6/ip6_input.c b/freebsd/sys/netinet6/ip6_input.c index 7e1007e3..77e32da8 100644 --- a/freebsd/sys/netinet6/ip6_input.c +++ b/freebsd/sys/netinet6/ip6_input.c @@ -224,7 +224,7 @@ ip6_init(void) TUNABLE_INT_FETCH("net.inet6.ip6.accept_rtadv", &V_ip6_accept_rtadv); TUNABLE_INT_FETCH("net.inet6.ip6.no_radr", &V_ip6_no_radr); - TAILQ_INIT(&V_in6_ifaddrhead); + CK_STAILQ_INIT(&V_in6_ifaddrhead); V_in6_ifaddrhashtbl = hashinit(IN6ADDR_NHASH, M_IFADDR, &V_in6_ifaddrhmask); @@ -379,10 +379,10 @@ ip6_destroy(void *unused __unused) /* Cleanup addresses. */ IFNET_RLOCK(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { /* Cannot lock here - lock recursion. */ /* IF_ADDR_LOCK(ifp); */ - TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { + CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; diff --git a/freebsd/sys/netinet6/ip6_var.h b/freebsd/sys/netinet6/ip6_var.h index 42c235d1..74b5f89c 100644 --- a/freebsd/sys/netinet6/ip6_var.h +++ b/freebsd/sys/netinet6/ip6_var.h @@ -66,6 +66,8 @@ #ifndef _NETINET6_IP6_VAR_H_ #define _NETINET6_IP6_VAR_H_ +#include <sys/epoch.h> + /* * IP6 reassembly queue structure. Each fragment * being reassembled is attached to one of these structures. @@ -121,6 +123,7 @@ struct ip6_moptions { u_short im6o_max_memberships; /* max memberships this socket */ struct in6_multi **im6o_membership; /* group memberships */ struct in6_mfilter *im6o_mfilters; /* source filters */ + struct epoch_context imo6_epoch_ctx; }; /* diff --git a/freebsd/sys/netinet6/mld6.c b/freebsd/sys/netinet6/mld6.c index c1dff0c3..0c82d5ff 100644 --- a/freebsd/sys/netinet6/mld6.c +++ b/freebsd/sys/netinet6/mld6.c @@ -126,7 +126,7 @@ static int mld_v1_input_query(struct ifnet *, const struct ip6_hdr *, /*const*/ struct mld_hdr *); static int mld_v1_input_report(struct ifnet *, const struct ip6_hdr *, /*const*/ struct mld_hdr *); -static void mld_v1_process_group_timer(struct mld_ifsoftc *, +static void mld_v1_process_group_timer(struct in6_multi_head *, struct in6_multi *); static void mld_v1_process_querier_timers(struct mld_ifsoftc *); static int mld_v1_transmit_report(struct in6_multi *, const int); @@ -144,7 +144,7 @@ static int mld_v2_input_query(struct ifnet *, const struct ip6_hdr *, struct mbuf *, const int, const int); static int mld_v2_merge_state_changes(struct in6_multi *, struct mbufq *); -static void mld_v2_process_group_timers(struct mld_ifsoftc *, +static void mld_v2_process_group_timers(struct in6_multi_head *, struct mbufq *, struct mbufq *, struct in6_multi *, const int); static int mld_v2_process_group_query(struct in6_multi *, @@ -379,6 +379,7 @@ sysctl_mld_ifinfo(SYSCTL_HANDLER_ARGS) return (error); IN6_MULTI_LOCK(); + IN6_MULTI_LIST_LOCK(); MLD_LOCK(); if (name[0] <= 0 || name[0] > V_if_index) { @@ -411,6 +412,7 @@ sysctl_mld_ifinfo(SYSCTL_HANDLER_ARGS) out_locked: MLD_UNLOCK(); + IN6_MULTI_LIST_UNLOCK(); IN6_MULTI_UNLOCK(); return (error); } @@ -510,7 +512,6 @@ mli_alloc_locked(/*const*/ struct ifnet *ifp) mli->mli_qi = MLD_QI_INIT; mli->mli_qri = MLD_QRI_INIT; mli->mli_uri = MLD_URI_INIT; - SLIST_INIT(&mli->mli_relinmhead); mbufq_init(&mli->mli_gq, MLD_MAX_RESPONSE_PACKETS); LIST_INSERT_HEAD(&V_mli_head, mli, mli_link); @@ -537,38 +538,41 @@ void mld_ifdetach(struct ifnet *ifp) { struct mld_ifsoftc *mli; - struct ifmultiaddr *ifma; - struct in6_multi *inm, *tinm; + struct ifmultiaddr *ifma, *next; + struct in6_multi *inm; + struct in6_multi_head inmh; CTR3(KTR_MLD, "%s: called for ifp %p(%s)", __func__, ifp, if_name(ifp)); - IN6_MULTI_LOCK_ASSERT(); + SLIST_INIT(&inmh); + IN6_MULTI_LIST_LOCK_ASSERT(); MLD_LOCK(); mli = MLD_IFINFO(ifp); if (mli->mli_version == MLD_VERSION_2) { - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + IF_ADDR_WLOCK(ifp); + restart: + CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { if (ifma->ifma_addr->sa_family != AF_INET6 || ifma->ifma_protospec == NULL) continue; inm = (struct in6_multi *)ifma->ifma_protospec; if (inm->in6m_state == MLD_LEAVING_MEMBER) { - SLIST_INSERT_HEAD(&mli->mli_relinmhead, - inm, in6m_nrele); + in6m_rele_locked(&inmh, inm); + ifma->ifma_protospec = NULL; } in6m_clear_recorded(inm); + if (__predict_false(ifma6_restart)) { + ifma6_restart = false; + goto restart; + } } - IF_ADDR_RUNLOCK(ifp); - SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead, in6m_nrele, - tinm) { - SLIST_REMOVE_HEAD(&mli->mli_relinmhead, in6m_nrele); - in6m_release_locked(inm); - } + IF_ADDR_WUNLOCK(ifp); } MLD_UNLOCK(); + in6m_release_list_deferred(&inmh); } /* @@ -608,10 +612,6 @@ mli_delete_locked(const struct ifnet *ifp) LIST_REMOVE(mli, mli_link); - KASSERT(SLIST_EMPTY(&mli->mli_relinmhead), - ("%s: there are dangling in_multi references", - __func__)); - free(mli, M_MLD); return; } @@ -682,7 +682,7 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, in6_setscope(&mld->mld_addr, ifp, NULL); } - IN6_MULTI_LOCK(); + IN6_MULTI_LIST_LOCK(); MLD_LOCK(); /* @@ -703,8 +703,8 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, * interface, kick the report timer. */ CTR2(KTR_MLD, "process v1 general query on ifp %p(%s)", - ifp, if_name(ifp)); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + ifp, if_name(ifp)); + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_INET6 || ifma->ifma_protospec == NULL) continue; @@ -730,7 +730,7 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, IF_ADDR_RUNLOCK(ifp); MLD_UNLOCK(); - IN6_MULTI_UNLOCK(); + IN6_MULTI_LIST_UNLOCK(); return (0); } @@ -761,7 +761,7 @@ mld_v1_update_group(struct in6_multi *inm, const int timer) ip6_sprintf(ip6tbuf, &inm->in6m_addr), if_name(inm->in6m_ifp), timer); - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); switch (inm->in6m_state) { case MLD_NOT_MEMBER: @@ -884,7 +884,7 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, in6_setscope(&mld->mld_addr, ifp, NULL); } - IN6_MULTI_LOCK(); + IN6_MULTI_LIST_LOCK(); MLD_LOCK(); mli = MLD_IFINFO(ifp); @@ -967,7 +967,7 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6, out_locked: MLD_UNLOCK(); - IN6_MULTI_UNLOCK(); + IN6_MULTI_LIST_UNLOCK(); return (0); } @@ -985,7 +985,7 @@ mld_v2_process_group_query(struct in6_multi *inm, struct mld_ifsoftc *mli, int retval; uint16_t nsrc; - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); MLD_LOCK_ASSERT(); retval = 0; @@ -1170,7 +1170,7 @@ mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6, if (!IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) in6_setscope(&mld->mld_addr, ifp, NULL); - IN6_MULTI_LOCK(); + IN6_MULTI_LIST_LOCK(); MLD_LOCK(); IF_ADDR_RLOCK(ifp); @@ -1222,7 +1222,7 @@ mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6, out_locked: IF_ADDR_RUNLOCK(ifp); MLD_UNLOCK(); - IN6_MULTI_UNLOCK(); + IN6_MULTI_LIST_UNLOCK(); /* XXX Clear embedded scope ID as userland won't expect it. */ in6_clearscope(&mld->mld_addr); @@ -1333,8 +1333,9 @@ mld_fasttimo_vnet(void) struct mbufq qrq; /* Query response packets */ struct ifnet *ifp; struct mld_ifsoftc *mli; - struct ifmultiaddr *ifma; + struct ifmultiaddr *ifma, *next; struct in6_multi *inm, *tinm; + struct in6_multi_head inmh; int uri_fasthz; uri_fasthz = 0; @@ -1349,7 +1350,8 @@ mld_fasttimo_vnet(void) !V_state_change_timers_running6) return; - IN6_MULTI_LOCK(); + SLIST_INIT(&inmh); + IN6_MULTI_LIST_LOCK(); MLD_LOCK(); /* @@ -1393,23 +1395,28 @@ mld_fasttimo_vnet(void) mbufq_init(&scq, MLD_MAX_STATE_CHANGE_PACKETS); } - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + IF_ADDR_WLOCK(ifp); + restart: + CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { if (ifma->ifma_addr->sa_family != AF_INET6 || ifma->ifma_protospec == NULL) continue; inm = (struct in6_multi *)ifma->ifma_protospec; switch (mli->mli_version) { case MLD_VERSION_1: - mld_v1_process_group_timer(mli, inm); + mld_v1_process_group_timer(&inmh, inm); break; case MLD_VERSION_2: - mld_v2_process_group_timers(mli, &qrq, + mld_v2_process_group_timers(&inmh, &qrq, &scq, inm, uri_fasthz); break; } + if (__predict_false(ifma6_restart)) { + ifma6_restart = false; + goto restart; + } } - IF_ADDR_RUNLOCK(ifp); + IF_ADDR_WUNLOCK(ifp); switch (mli->mli_version) { case MLD_VERSION_1: @@ -1421,9 +1428,8 @@ mld_fasttimo_vnet(void) * IF_ADDR_LOCK internally as well as * ip6_output() to transmit a packet. */ - SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead, - in6m_nrele, tinm) { - SLIST_REMOVE_HEAD(&mli->mli_relinmhead, + SLIST_FOREACH_SAFE(inm, &inmh, in6m_nrele, tinm) { + SLIST_REMOVE_HEAD(&inmh, in6m_nrele); (void)mld_v1_transmit_report(inm, MLD_LISTENER_REPORT); @@ -1437,19 +1443,14 @@ mld_fasttimo_vnet(void) * Free the in_multi reference(s) for * this lifecycle. */ - SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead, - in6m_nrele, tinm) { - SLIST_REMOVE_HEAD(&mli->mli_relinmhead, - in6m_nrele); - in6m_release_locked(inm); - } + in6m_release_list_deferred(&inmh); break; } } out_locked: MLD_UNLOCK(); - IN6_MULTI_UNLOCK(); + IN6_MULTI_LIST_UNLOCK(); } /* @@ -1457,11 +1458,11 @@ out_locked: * Will update the global pending timer flags. */ static void -mld_v1_process_group_timer(struct mld_ifsoftc *mli, struct in6_multi *inm) +mld_v1_process_group_timer(struct in6_multi_head *inmh, struct in6_multi *inm) { int report_timer_expired; - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); MLD_LOCK_ASSERT(); if (inm->in6m_timer == 0) { @@ -1484,8 +1485,7 @@ mld_v1_process_group_timer(struct mld_ifsoftc *mli, struct in6_multi *inm) case MLD_REPORTING_MEMBER: if (report_timer_expired) { inm->in6m_state = MLD_IDLE_MEMBER; - SLIST_INSERT_HEAD(&mli->mli_relinmhead, inm, - in6m_nrele); + in6m_rele_locked(inmh, inm); } break; case MLD_G_QUERY_PENDING_MEMBER: @@ -1501,7 +1501,7 @@ mld_v1_process_group_timer(struct mld_ifsoftc *mli, struct in6_multi *inm) * Note: Unlocked read from mli. */ static void -mld_v2_process_group_timers(struct mld_ifsoftc *mli, +mld_v2_process_group_timers(struct in6_multi_head *inmh, struct mbufq *qrq, struct mbufq *scq, struct in6_multi *inm, const int uri_fasthz) { @@ -1511,7 +1511,7 @@ mld_v2_process_group_timers(struct mld_ifsoftc *mli, char ip6tbuf[INET6_ADDRSTRLEN]; #endif - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); MLD_LOCK_ASSERT(); query_response_timer_expired = 0; @@ -1609,8 +1609,7 @@ mld_v2_process_group_timers(struct mld_ifsoftc *mli, if (inm->in6m_state == MLD_LEAVING_MEMBER && inm->in6m_scrv == 0) { inm->in6m_state = MLD_NOT_MEMBER; - SLIST_INSERT_HEAD(&mli->mli_relinmhead, - inm, in6m_nrele); + in6m_rele_locked(inmh, inm); } } break; @@ -1654,14 +1653,16 @@ mld_set_version(struct mld_ifsoftc *mli, const int version) static void mld_v2_cancel_link_timers(struct mld_ifsoftc *mli) { - struct ifmultiaddr *ifma; + struct ifmultiaddr *ifma, *next; struct ifnet *ifp; - struct in6_multi *inm, *tinm; + struct in6_multi *inm; + struct in6_multi_head inmh; CTR3(KTR_MLD, "%s: cancel v2 timers on ifp %p(%s)", __func__, mli->mli_ifp, if_name(mli->mli_ifp)); - IN6_MULTI_LOCK_ASSERT(); + SLIST_INIT(&inmh); + IN6_MULTI_LIST_LOCK_ASSERT(); MLD_LOCK_ASSERT(); /* @@ -1677,8 +1678,9 @@ mld_v2_cancel_link_timers(struct mld_ifsoftc *mli) ifp = mli->mli_ifp; - IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + IF_ADDR_WLOCK(ifp); + restart: + CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) { if (ifma->ifma_addr->sa_family != AF_INET6) continue; inm = (struct in6_multi *)ifma->ifma_protospec; @@ -1696,8 +1698,8 @@ mld_v2_cancel_link_timers(struct mld_ifsoftc *mli) * version, we need to release the final * reference held for issuing the INCLUDE {}. */ - SLIST_INSERT_HEAD(&mli->mli_relinmhead, inm, - in6m_nrele); + in6m_rele_locked(&inmh, inm); + ifma->ifma_protospec = NULL; /* FALLTHROUGH */ case MLD_G_QUERY_PENDING_MEMBER: case MLD_SG_QUERY_PENDING_MEMBER: @@ -1713,12 +1715,13 @@ mld_v2_cancel_link_timers(struct mld_ifsoftc *mli) mbufq_drain(&inm->in6m_scq); break; } + if (__predict_false(ifma6_restart)) { + ifma6_restart = false; + goto restart; + } } - IF_ADDR_RUNLOCK(ifp); - SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead, in6m_nrele, tinm) { - SLIST_REMOVE_HEAD(&mli->mli_relinmhead, in6m_nrele); - in6m_release_locked(inm); - } + IF_ADDR_WUNLOCK(ifp); + in6m_release_list_deferred(&inmh); } /* @@ -1790,7 +1793,7 @@ mld_v1_transmit_report(struct in6_multi *in6m, const int type) struct mbuf *mh, *md; struct mld_hdr *mld; - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); MLD_LOCK_ASSERT(); ifp = in6m->in6m_ifp; @@ -1881,7 +1884,7 @@ mld_change_state(struct in6_multi *inm, const int delay) struct ifnet *ifp; int error; - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); error = 0; @@ -1965,7 +1968,7 @@ mld_initial_join(struct in6_multi *inm, struct mld_ifsoftc *mli, ifp = inm->in6m_ifp; - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); MLD_LOCK_ASSERT(); KASSERT(mli && mli->mli_ifp == ifp, ("%s: inconsistent ifp", __func__)); @@ -1995,7 +1998,7 @@ mld_initial_join(struct in6_multi *inm, struct mld_ifsoftc *mli, */ if (mli->mli_version == MLD_VERSION_2 && inm->in6m_state == MLD_LEAVING_MEMBER) - in6m_release_locked(inm); + in6m_release_deferred(inm); inm->in6m_state = MLD_REPORTING_MEMBER; @@ -2108,7 +2111,7 @@ mld_handle_state_change(struct in6_multi *inm, struct mld_ifsoftc *mli) ifp = inm->in6m_ifp; - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); MLD_LOCK_ASSERT(); KASSERT(mli && mli->mli_ifp == ifp, @@ -2171,7 +2174,7 @@ mld_final_leave(struct in6_multi *inm, struct mld_ifsoftc *mli) __func__, ip6_sprintf(ip6tbuf, &inm->in6m_addr), inm->in6m_ifp, if_name(inm->in6m_ifp)); - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); MLD_LOCK_ASSERT(); switch (inm->in6m_state) { @@ -2298,7 +2301,7 @@ mld_v2_enqueue_group_record(struct mbufq *mq, struct in6_multi *inm, char ip6tbuf[INET6_ADDRSTRLEN]; #endif - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); ifp = inm->in6m_ifp; is_filter_list_change = 0; @@ -2681,7 +2684,7 @@ mld_v2_enqueue_filter_change(struct mbufq *mq, struct in6_multi *inm) char ip6tbuf[INET6_ADDRSTRLEN]; #endif - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); if (inm->in6m_nsrc == 0 || (inm->in6m_st[0].iss_asm > 0 && inm->in6m_st[1].iss_asm > 0)) @@ -2881,7 +2884,7 @@ mld_v2_merge_state_changes(struct in6_multi *inm, struct mbufq *scq) domerge = 0; recslen = 0; - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); MLD_LOCK_ASSERT(); /* @@ -2980,7 +2983,7 @@ mld_v2_dispatch_general_query(struct mld_ifsoftc *mli) struct in6_multi *inm; int retval; - IN6_MULTI_LOCK_ASSERT(); + IN6_MULTI_LIST_LOCK_ASSERT(); MLD_LOCK_ASSERT(); KASSERT(mli->mli_version == MLD_VERSION_2, @@ -2998,7 +3001,7 @@ mld_v2_dispatch_general_query(struct mld_ifsoftc *mli) ifp = mli->mli_ifp; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_INET6 || ifma->ifma_protospec == NULL) continue; diff --git a/freebsd/sys/netinet6/mld6_var.h b/freebsd/sys/netinet6/mld6_var.h index 0aeac367..166c2055 100644 --- a/freebsd/sys/netinet6/mld6_var.h +++ b/freebsd/sys/netinet6/mld6_var.h @@ -136,7 +136,6 @@ struct mld_ifsoftc { uint32_t mli_qi; /* MLDv2 Query Interval (s) */ uint32_t mli_qri; /* MLDv2 Query Response Interval (s) */ uint32_t mli_uri; /* MLDv2 Unsolicited Report Interval (s) */ - SLIST_HEAD(,in6_multi) mli_relinmhead; /* released groups */ struct mbufq mli_gq; /* queue of general query responses */ }; diff --git a/freebsd/sys/netinet6/nd6.c b/freebsd/sys/netinet6/nd6.c index a00d5421..6a36803f 100644 --- a/freebsd/sys/netinet6/nd6.c +++ b/freebsd/sys/netinet6/nd6.c @@ -60,10 +60,8 @@ __FBSDID("$FreeBSD$"); #include <net/if.h> #include <net/if_var.h> -#include <net/if_arc.h> #include <net/if_dl.h> #include <net/if_types.h> -#include <net/fddi.h> #include <net/route.h> #include <net/vnet.h> @@ -305,7 +303,7 @@ nd6_ifdetach(struct ifnet *ifp, struct nd_ifinfo *nd) struct ifaddr *ifa, *next; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { + CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, next) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -337,18 +335,7 @@ nd6_setmtu0(struct ifnet *ifp, struct nd_ifinfo *ndi) u_int32_t omaxmtu; omaxmtu = ndi->maxmtu; - - switch (ifp->if_type) { - case IFT_ARCNET: - ndi->maxmtu = MIN(ARC_PHDS_MAXMTU, ifp->if_mtu); /* RFC2497 */ - break; - case IFT_FDDI: - ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); /* RFC2467 */ - break; - default: - ndi->maxmtu = ifp->if_mtu; - break; - } + ndi->maxmtu = ifp->if_mtu; /* * Decreasing the interface MTU under IPV6 minimum MTU may cause @@ -937,7 +924,7 @@ nd6_timer(void *arg) * XXXRW: in6_ifaddrhead locking. */ addrloop: - TAILQ_FOREACH_SAFE(ia6, &V_in6_ifaddrhead, ia_link, nia6) { + CK_STAILQ_FOREACH_SAFE(ia6, &V_in6_ifaddrhead, ia_link, nia6) { /* check address lifetime */ if (IFA6_IS_INVALID(ia6)) { int regen = 0; @@ -1083,7 +1070,7 @@ regen_tmpaddr(struct in6_ifaddr *ia6) ifp = ia6->ia_ifa.ifa_ifp; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { struct in6_ifaddr *it6; if (ifa->ifa_addr->sa_family != AF_INET6) @@ -1359,7 +1346,7 @@ restart: */ if (ifp->if_flags & IFF_POINTOPOINT) { IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != addr->sin6_family) continue; if (ifa->ifa_dstaddr != NULL && @@ -1702,7 +1689,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) * See RFC 4862, Section 5.4.5. */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; ia = (struct in6_ifaddr *)ifa; @@ -1732,7 +1719,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) if (V_ip6_dad_count > 0 && (ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD) == 0) { IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) @@ -1760,7 +1747,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) * assign one. */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) @@ -1804,7 +1791,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) while ((pr = LIST_FIRST(&prl)) != NULL) { LIST_REMOVE(pr, ndpr_entry); /* XXXRW: in6_ifaddrhead locking. */ - TAILQ_FOREACH_SAFE(ia, &V_in6_ifaddrhead, ia_link, + CK_STAILQ_FOREACH_SAFE(ia, &V_in6_ifaddrhead, ia_link, ia_next) { if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; @@ -2148,7 +2135,7 @@ nd6_slowtimo(void *arg) callout_reset(&V_nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, nd6_slowtimo, curvnet); IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) { + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { if (ifp->if_afdata[AF_INET6] == NULL) continue; nd6if = ND_IFINFO(ifp); @@ -2274,7 +2261,6 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m, if (m != NULL && m->m_flags & M_MCAST) { switch (ifp->if_type) { case IFT_ETHER: - case IFT_FDDI: case IFT_L2VLAN: case IFT_BRIDGE: ETHER_MAP_IPV6_MULTICAST(&dst6->sin6_addr, @@ -2526,15 +2512,13 @@ nd6_need_cache(struct ifnet *ifp) { /* * XXX: we currently do not make neighbor cache on any interface - * other than ARCnet, Ethernet, FDDI and GIF. + * other than Ethernet and GIF. * * RFC2893 says: * - unidirectional tunnels needs no ND */ switch (ifp->if_type) { - case IFT_ARCNET: case IFT_ETHER: - case IFT_FDDI: case IFT_IEEE1394: case IFT_L2VLAN: case IFT_INFINIBAND: diff --git a/freebsd/sys/netinet6/nd6_nbr.c b/freebsd/sys/netinet6/nd6_nbr.c index e5b37877..d4ab38af 100644 --- a/freebsd/sys/netinet6/nd6_nbr.c +++ b/freebsd/sys/netinet6/nd6_nbr.c @@ -1092,9 +1092,7 @@ caddr_t nd6_ifptomac(struct ifnet *ifp) { switch (ifp->if_type) { - case IFT_ARCNET: case IFT_ETHER: - case IFT_FDDI: case IFT_IEEE1394: case IFT_L2VLAN: case IFT_INFINIBAND: @@ -1468,7 +1466,6 @@ nd6_dad_duplicated(struct ifaddr *ifa, struct dadq *dp) */ switch (ifp->if_type) { case IFT_ETHER: - case IFT_FDDI: case IFT_ATM: case IFT_IEEE1394: case IFT_INFINIBAND: diff --git a/freebsd/sys/netinet6/nd6_rtr.c b/freebsd/sys/netinet6/nd6_rtr.c index 642faa1a..fab7c7c2 100644 --- a/freebsd/sys/netinet6/nd6_rtr.c +++ b/freebsd/sys/netinet6/nd6_rtr.c @@ -480,7 +480,7 @@ nd6_rtmsg(int cmd, struct rtentry *rt) ifp = rt->rt_ifp; if (ifp != NULL) { IF_ADDR_RLOCK(ifp); - ifa = TAILQ_FIRST(&ifp->if_addrhead); + ifa = CK_STAILQ_FIRST(&ifp->if_addrhead); info.rti_info[RTAX_IFP] = ifa->ifa_addr; ifa_ref(ifa); IF_ADDR_RUNLOCK(ifp); @@ -1349,7 +1349,7 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, * "address". */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { struct in6_ifaddr *ifa6; u_int32_t remaininglifetime; @@ -1721,7 +1721,7 @@ restart: * The precise detection logic is same as the one for prefixes. */ IN6_IFADDR_RLOCK(&in6_ifa_tracker); - TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF)) continue; @@ -1738,7 +1738,7 @@ restart: break; } if (ifa) { - TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; @@ -1756,7 +1756,7 @@ restart: } } } else { - TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { + CK_STAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) continue; @@ -1910,7 +1910,7 @@ nd6_prefix_onlink(struct nd_prefix *pr) if (ifa == NULL) { /* XXX: freebsd does not have ifa_ifwithaf */ IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == AF_INET6) { ifa_ref(ifa); break; diff --git a/freebsd/sys/netinet6/raw_ip6.c b/freebsd/sys/netinet6/raw_ip6.c index a4843380..c05399b3 100644 --- a/freebsd/sys/netinet6/raw_ip6.c +++ b/freebsd/sys/netinet6/raw_ip6.c @@ -736,23 +736,25 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td) return (EINVAL); if ((error = prison_check_ip6(td->td_ucred, &addr->sin6_addr)) != 0) return (error); - if (TAILQ_EMPTY(&V_ifnet) || addr->sin6_family != AF_INET6) + if (CK_STAILQ_EMPTY(&V_ifnet) || addr->sin6_family != AF_INET6) return (EADDRNOTAVAIL); if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0) return (error); + NET_EPOCH_ENTER(); if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) && - (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL) + (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL) { + NET_EPOCH_EXIT(); return (EADDRNOTAVAIL); + } if (ifa != NULL && ((struct in6_ifaddr *)ifa)->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY| IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) { - ifa_free(ifa); + NET_EPOCH_EXIT(); return (EADDRNOTAVAIL); } - if (ifa != NULL) - ifa_free(ifa); + NET_EPOCH_EXIT(); INP_INFO_WLOCK(&V_ripcbinfo); INP_WLOCK(inp); inp->in6p_laddr = addr->sin6_addr; @@ -774,7 +776,7 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) if (nam->sa_len != sizeof(*addr)) return (EINVAL); - if (TAILQ_EMPTY(&V_ifnet)) + if (CK_STAILQ_EMPTY(&V_ifnet)) return (EADDRNOTAVAIL); if (addr->sin6_family != AF_INET6) return (EAFNOSUPPORT); diff --git a/freebsd/sys/netinet6/sctp6_usrreq.c b/freebsd/sys/netinet6/sctp6_usrreq.c index a79e6f53..fd963fb3 100644 --- a/freebsd/sys/netinet6/sctp6_usrreq.c +++ b/freebsd/sys/netinet6/sctp6_usrreq.c @@ -225,7 +225,7 @@ sctp6_notify(struct sctp_inpcb *inp, } break; case ICMP6_PACKET_TOO_BIG: - if ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0) { + if (net->dest_state & SCTP_ADDR_NO_PMTUD) { SCTP_TCB_UNLOCK(stcb); break; } diff --git a/freebsd/sys/netipsec/ipsec.h b/freebsd/sys/netipsec/ipsec.h index ac9361a8..936e7bca 100644 --- a/freebsd/sys/netipsec/ipsec.h +++ b/freebsd/sys/netipsec/ipsec.h @@ -219,8 +219,9 @@ struct ipsecstat { uint64_t ips_out_inval; /* output: generic error */ uint64_t ips_out_bundlesa; /* output: bundled SA processed */ - uint64_t ips_mbcoalesced; /* mbufs coalesced during clone */ - uint64_t ips_clcoalesced; /* clusters coalesced during clone */ + uint64_t ips_spdcache_hits; /* SPD cache hits */ + uint64_t ips_spdcache_misses; /* SPD cache misses */ + uint64_t ips_clcopied; /* clusters copied during clone */ uint64_t ips_mbinserted; /* mbufs inserted during makespace */ /* diff --git a/freebsd/sys/netipsec/ipsec_mbuf.c b/freebsd/sys/netipsec/ipsec_mbuf.c index 66d53514..f8e73c9e 100644 --- a/freebsd/sys/netipsec/ipsec_mbuf.c +++ b/freebsd/sys/netipsec/ipsec_mbuf.c @@ -257,10 +257,11 @@ m_striphdr(struct mbuf *m, int skip, int hlen) /* The header was at the beginning of the mbuf */ IPSECSTAT_INC(ips_input_front); m_adj(m1, hlen); - if ((m1->m_flags & M_PKTHDR) == 0) + if (m1 != m) m->m_pkthdr.len -= hlen; } else if (roff + hlen >= m1->m_len) { struct mbuf *mo; + int adjlen; /* * Part or all of the header is at the end of this mbuf, @@ -269,11 +270,13 @@ m_striphdr(struct mbuf *m, int skip, int hlen) */ IPSECSTAT_INC(ips_input_end); if (roff + hlen > m1->m_len) { + adjlen = roff + hlen - m1->m_len; + /* Adjust the next mbuf by the remainder */ - m_adj(m1->m_next, roff + hlen - m1->m_len); + m_adj(m1->m_next, adjlen); /* The second mbuf is guaranteed not to have a pkthdr... */ - m->m_pkthdr.len -= (roff + hlen - m1->m_len); + m->m_pkthdr.len -= adjlen; } /* Now, let's unlink the mbuf chain for a second...*/ @@ -281,9 +284,10 @@ m_striphdr(struct mbuf *m, int skip, int hlen) m1->m_next = NULL; /* ...and trim the end of the first part of the chain...sick */ - m_adj(m1, -(m1->m_len - roff)); - if ((m1->m_flags & M_PKTHDR) == 0) - m->m_pkthdr.len -= (m1->m_len - roff); + adjlen = m1->m_len - roff; + m_adj(m1, -adjlen); + if (m1 != m) + m->m_pkthdr.len -= adjlen; /* Finally, let's relink */ m1->m_next = mo; diff --git a/freebsd/sys/netipsec/key.c b/freebsd/sys/netipsec/key.c index 31269058..fbf12f41 100644 --- a/freebsd/sys/netipsec/key.c +++ b/freebsd/sys/netipsec/key.c @@ -175,6 +175,48 @@ static VNET_DEFINE(u_long, sphash_mask); #define SPHASH_HASHVAL(id) (key_u32hash(id) & V_sphash_mask) #define SPHASH_HASH(id) &V_sphashtbl[SPHASH_HASHVAL(id)] +/* SPD cache */ +struct spdcache_entry { + struct secpolicyindex spidx; /* secpolicyindex */ + struct secpolicy *sp; /* cached policy to be used */ + + LIST_ENTRY(spdcache_entry) chain; +}; +LIST_HEAD(spdcache_entry_list, spdcache_entry); + +#define SPDCACHE_MAX_ENTRIES_PER_HASH 8 + +static VNET_DEFINE(u_int, key_spdcache_maxentries) = 0; +#define V_key_spdcache_maxentries VNET(key_spdcache_maxentries) +static VNET_DEFINE(u_int, key_spdcache_threshold) = 32; +#define V_key_spdcache_threshold VNET(key_spdcache_threshold) +static VNET_DEFINE(unsigned long, spd_size) = 0; +#define V_spd_size VNET(spd_size) + +#define SPDCACHE_ENABLED() (V_key_spdcache_maxentries != 0) +#define SPDCACHE_ACTIVE() \ + (SPDCACHE_ENABLED() && V_spd_size >= V_key_spdcache_threshold) + +static VNET_DEFINE(struct spdcache_entry_list *, spdcachehashtbl); +static VNET_DEFINE(u_long, spdcachehash_mask); +#define V_spdcachehashtbl VNET(spdcachehashtbl) +#define V_spdcachehash_mask VNET(spdcachehash_mask) + +#define SPDCACHE_HASHVAL(idx) \ + (key_addrprotohash(&(idx)->src, &(idx)->dst, &(idx)->ul_proto) & \ + V_spdcachehash_mask) + +/* Each cache line is protected by a mutex */ +static VNET_DEFINE(struct mtx *, spdcache_lock); +#define V_spdcache_lock VNET(spdcache_lock) + +#define SPDCACHE_LOCK_INIT(a) \ + mtx_init(&V_spdcache_lock[a], "spdcache", \ + "fast ipsec SPD cache", MTX_DEF|MTX_DUPOK) +#define SPDCACHE_LOCK_DESTROY(a) mtx_destroy(&V_spdcache_lock[a]) +#define SPDCACHE_LOCK(a) mtx_lock(&V_spdcache_lock[a]); +#define SPDCACHE_UNLOCK(a) mtx_unlock(&V_spdcache_lock[a]); + /* SAD */ TAILQ_HEAD(secashead_queue, secashead); LIST_HEAD(secashead_list, secashead); @@ -200,8 +242,9 @@ static VNET_DEFINE(u_long, sahaddrhash_mask); #define SAHHASH_NHASH_LOG2 7 #define SAHHASH_NHASH (1 << SAHHASH_NHASH_LOG2) -#define SAHADDRHASH_HASHVAL(saidx) \ - (key_saidxhash(saidx) & V_sahaddrhash_mask) +#define SAHADDRHASH_HASHVAL(idx) \ + (key_addrprotohash(&(idx)->src, &(idx)->dst, &(idx)->proto) & \ + V_sahaddrhash_mask) #define SAHADDRHASH_HASH(saidx) \ &V_sahaddrhashtbl[SAHADDRHASH_HASHVAL(saidx)] @@ -217,33 +260,34 @@ static VNET_DEFINE(u_long, savhash_mask); #define SAVHASH_HASH(spi) &V_savhashtbl[SAVHASH_HASHVAL(spi)] static uint32_t -key_saidxhash(const struct secasindex *saidx) +key_addrprotohash(const union sockaddr_union *src, + const union sockaddr_union *dst, const uint8_t *proto) { uint32_t hval; - hval = fnv_32_buf(&saidx->proto, sizeof(saidx->proto), + hval = fnv_32_buf(proto, sizeof(*proto), FNV1_32_INIT); - switch (saidx->dst.sa.sa_family) { + switch (dst->sa.sa_family) { #ifdef INET case AF_INET: - hval = fnv_32_buf(&saidx->src.sin.sin_addr, + hval = fnv_32_buf(&src->sin.sin_addr, sizeof(in_addr_t), hval); - hval = fnv_32_buf(&saidx->dst.sin.sin_addr, + hval = fnv_32_buf(&dst->sin.sin_addr, sizeof(in_addr_t), hval); break; #endif #ifdef INET6 case AF_INET6: - hval = fnv_32_buf(&saidx->src.sin6.sin6_addr, + hval = fnv_32_buf(&src->sin6.sin6_addr, sizeof(struct in6_addr), hval); - hval = fnv_32_buf(&saidx->dst.sin6.sin6_addr, + hval = fnv_32_buf(&dst->sin6.sin6_addr, sizeof(struct in6_addr), hval); break; #endif default: hval = 0; ipseclog((LOG_DEBUG, "%s: unknown address family %d", - __func__, saidx->dst.sa.sa_family)); + __func__, dst->sa.sa_family)); } return (hval); } @@ -292,8 +336,9 @@ static VNET_DEFINE(u_long, acqseqhash_mask); #define ACQHASH_NHASH_LOG2 7 #define ACQHASH_NHASH (1 << ACQHASH_NHASH_LOG2) -#define ACQADDRHASH_HASHVAL(saidx) \ - (key_saidxhash(saidx) & V_acqaddrhash_mask) +#define ACQADDRHASH_HASHVAL(idx) \ + (key_addrprotohash(&(idx)->src, &(idx)->dst, &(idx)->proto) & \ + V_acqaddrhash_mask) #define ACQSEQHASH_HASHVAL(seq) \ (key_u32hash(seq) & V_acqseqhash_mask) #define ACQADDRHASH_HASH(saidx) \ @@ -465,6 +510,17 @@ SYSCTL_INT(_net_key, KEYCTL_AH_KEYMIN, ah_keymin, SYSCTL_INT(_net_key, KEYCTL_PREFERED_OLDSA, preferred_oldsa, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(key_preferred_oldsa), 0, ""); +static SYSCTL_NODE(_net_key, OID_AUTO, spdcache, CTLFLAG_RW, 0, "SPD cache"); + +SYSCTL_UINT(_net_key_spdcache, OID_AUTO, maxentries, + CTLFLAG_VNET | CTLFLAG_RDTUN, &VNET_NAME(key_spdcache_maxentries), 0, + "Maximum number of entries in the SPD cache" + " (power of 2, 0 to disable)"); + +SYSCTL_UINT(_net_key_spdcache, OID_AUTO, threshold, + CTLFLAG_VNET | CTLFLAG_RDTUN, &VNET_NAME(key_spdcache_threshold), 0, + "Number of SPs that make the SPD cache active"); + #define __LIST_CHAINED(elm) \ (!((elm)->chain.le_next == NULL && (elm)->chain.le_prev == NULL)) @@ -475,6 +531,7 @@ MALLOC_DEFINE(M_IPSEC_SR, "ipsecrequest", "ipsec security request"); MALLOC_DEFINE(M_IPSEC_MISC, "ipsec-misc", "ipsec miscellaneous"); MALLOC_DEFINE(M_IPSEC_SAQ, "ipsec-saq", "ipsec sa acquire"); MALLOC_DEFINE(M_IPSEC_SAR, "ipsec-reg", "ipsec sa acquire"); +MALLOC_DEFINE(M_IPSEC_SPDCACHE, "ipsec-spdcache", "ipsec SPD cache"); static VNET_DEFINE(uma_zone_t, key_lft_zone); #define V_key_lft_zone VNET(key_lft_zone) @@ -576,6 +633,7 @@ static struct callout key_timer; #endif static void key_unlink(struct secpolicy *); +static struct secpolicy *key_do_allocsp(struct secpolicyindex *spidx, u_int dir); static struct secpolicy *key_getsp(struct secpolicyindex *); static struct secpolicy *key_getspbyid(u_int32_t); static struct mbuf *key_gather_mbuf(struct mbuf *, @@ -696,6 +754,16 @@ static struct mbuf *key_setlifetime(struct seclifetime *, uint16_t); static struct mbuf *key_setkey(struct seckey *, uint16_t); static int xform_init(struct secasvar *, u_short); +static void spdcache_init(void); +static void spdcache_clear(void); +static struct spdcache_entry *spdcache_entry_alloc( + const struct secpolicyindex *spidx, + struct secpolicy *policy); +static void spdcache_entry_free(struct spdcache_entry *entry); +#ifdef VIMAGE +static void spdcache_destroy(void); +#endif + #define DBG_IPSEC_INITREF(t, p) do { \ refcount_init(&(p)->refcnt, 1); \ KEYDBG(KEY_STAMP, \ @@ -801,14 +869,8 @@ key_checksockaddrs(struct sockaddr *src, struct sockaddr *dst) return (0); } -/* - * allocating a SP for OUTBOUND or INBOUND packet. - * Must call key_freesp() later. - * OUT: NULL: not found - * others: found and return the pointer. - */ struct secpolicy * -key_allocsp(struct secpolicyindex *spidx, u_int dir) +key_do_allocsp(struct secpolicyindex *spidx, u_int dir) { SPTREE_RLOCK_TRACKER; struct secpolicy *sp; @@ -825,7 +887,73 @@ key_allocsp(struct secpolicyindex *spidx, u_int dir) } } SPTREE_RUNLOCK(); + return (sp); +} + + +/* + * allocating a SP for OUTBOUND or INBOUND packet. + * Must call key_freesp() later. + * OUT: NULL: not found + * others: found and return the pointer. + */ +struct secpolicy * +key_allocsp(struct secpolicyindex *spidx, u_int dir) +{ + struct spdcache_entry *entry, *lastentry, *tmpentry; + struct secpolicy *sp; + uint32_t hashv; + int nb_entries; + + if (!SPDCACHE_ACTIVE()) { + sp = key_do_allocsp(spidx, dir); + goto out; + } + + hashv = SPDCACHE_HASHVAL(spidx); + SPDCACHE_LOCK(hashv); + nb_entries = 0; + LIST_FOREACH_SAFE(entry, &V_spdcachehashtbl[hashv], chain, tmpentry) { + /* Removed outdated entries */ + if (entry->sp != NULL && + entry->sp->state == IPSEC_SPSTATE_DEAD) { + LIST_REMOVE(entry, chain); + spdcache_entry_free(entry); + continue; + } + + nb_entries++; + if (!key_cmpspidx_exactly(&entry->spidx, spidx)) { + lastentry = entry; + continue; + } + + sp = entry->sp; + if (entry->sp != NULL) + SP_ADDREF(sp); + + /* IPSECSTAT_INC(ips_spdcache_hits); */ + + SPDCACHE_UNLOCK(hashv); + goto out; + } + + /* IPSECSTAT_INC(ips_spdcache_misses); */ + sp = key_do_allocsp(spidx, dir); + entry = spdcache_entry_alloc(spidx, sp); + if (entry != NULL) { + if (nb_entries >= SPDCACHE_MAX_ENTRIES_PER_HASH) { + LIST_REMOVE(lastentry, chain); + spdcache_entry_free(lastentry); + } + + LIST_INSERT_HEAD(&V_spdcachehashtbl[hashv], entry, chain); + } + + SPDCACHE_UNLOCK(hashv); + +out: if (sp != NULL) { /* found a SPD entry */ sp->lastused = time_second; KEYDBG(IPSEC_STAMP, @@ -1109,9 +1237,12 @@ key_unlink(struct secpolicy *sp) } sp->state = IPSEC_SPSTATE_DEAD; TAILQ_REMOVE(&V_sptree[sp->spidx.dir], sp, chain); + V_spd_size--; LIST_REMOVE(sp, idhash); V_sp_genid++; SPTREE_WUNLOCK(); + if (SPDCACHE_ENABLED()) + spdcache_clear(); key_freesp(&sp); } @@ -1134,6 +1265,7 @@ key_insertsp(struct secpolicy *newsp) done: LIST_INSERT_HEAD(SPHASH_HASH(newsp->id), newsp, idhash); newsp->state = IPSEC_SPSTATE_ALIVE; + V_spd_size++; V_sp_genid++; } @@ -1209,9 +1341,12 @@ key_unregister_ifnet(struct secpolicy **spp, u_int count) spp[i]->state = IPSEC_SPSTATE_DEAD; TAILQ_REMOVE(&V_sptree_ifnet[spp[i]->spidx.dir], spp[i], chain); + V_spd_size--; LIST_REMOVE(spp[i], idhash); } SPTREE_WUNLOCK(); + if (SPDCACHE_ENABLED()) + spdcache_clear(); for (i = 0; i < count; i++) { m = key_setdumpsp(spp[i], SADB_X_SPDDELETE, 0, 0); @@ -1941,6 +2076,8 @@ key_spdadd(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp) } key_insertsp(newsp); SPTREE_WUNLOCK(); + if (SPDCACHE_ENABLED()) + spdcache_clear(); KEYDBG(KEY_STAMP, printf("%s: SP(%p)\n", __func__, newsp)); @@ -2395,7 +2532,10 @@ key_spdflush(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp) LIST_REMOVE(sp, idhash); } V_sp_genid++; + V_spd_size = 0; SPTREE_WUNLOCK(); + if (SPDCACHE_ENABLED()) + spdcache_clear(); sp = TAILQ_FIRST(&drainq); while (sp != NULL) { nextsp = TAILQ_NEXT(sp, chain); @@ -4072,7 +4212,8 @@ key_cmpspidx_exactly(struct secpolicyindex *spidx0, if (spidx0->prefs != spidx1->prefs || spidx0->prefd != spidx1->prefd - || spidx0->ul_proto != spidx1->ul_proto) + || spidx0->ul_proto != spidx1->ul_proto + || spidx0->dir != spidx1->dir) return 0; return key_sockaddrcmp(&spidx0->src.sa, &spidx1->src.sa, 1) == 0 && @@ -4340,12 +4481,15 @@ key_flush_spd(time_t now) continue; } TAILQ_REMOVE(&V_sptree[sp->spidx.dir], sp, chain); + V_spd_size--; LIST_REMOVE(sp, idhash); sp->state = IPSEC_SPSTATE_DEAD; sp = nextsp; } V_sp_genid++; SPTREE_WUNLOCK(); + if (SPDCACHE_ENABLED()) + spdcache_clear(); sp = LIST_FIRST(&drainq); while (sp != NULL) { @@ -8069,6 +8213,96 @@ key_validate_ext(const struct sadb_ext *ext, int len) } void +spdcache_init(void) +{ + int i; + + TUNABLE_INT_FETCH("net.key.spdcache.maxentries", + &V_key_spdcache_maxentries); + TUNABLE_INT_FETCH("net.key.spdcache.threshold", + &V_key_spdcache_threshold); + + if (V_key_spdcache_maxentries) { + V_key_spdcache_maxentries = MAX(V_key_spdcache_maxentries, + SPDCACHE_MAX_ENTRIES_PER_HASH); + V_spdcachehashtbl = hashinit(V_key_spdcache_maxentries / + SPDCACHE_MAX_ENTRIES_PER_HASH, + M_IPSEC_SPDCACHE, &V_spdcachehash_mask); + V_key_spdcache_maxentries = (V_spdcachehash_mask + 1) + * SPDCACHE_MAX_ENTRIES_PER_HASH; + + V_spdcache_lock = malloc(sizeof(struct mtx) * + (V_spdcachehash_mask + 1), + M_IPSEC_SPDCACHE, M_WAITOK|M_ZERO); + + for (i = 0; i < V_spdcachehash_mask + 1; ++i) + SPDCACHE_LOCK_INIT(i); + } +} + +struct spdcache_entry * +spdcache_entry_alloc(const struct secpolicyindex *spidx, struct secpolicy *sp) +{ + struct spdcache_entry *entry; + + entry = malloc(sizeof(struct spdcache_entry), + M_IPSEC_SPDCACHE, M_NOWAIT|M_ZERO); + if (entry == NULL) + return NULL; + + if (sp != NULL) + SP_ADDREF(sp); + + entry->spidx = *spidx; + entry->sp = sp; + + return (entry); +} + +void +spdcache_entry_free(struct spdcache_entry *entry) +{ + + if (entry->sp != NULL) + key_freesp(&entry->sp); + free(entry, M_IPSEC_SPDCACHE); +} + +void +spdcache_clear(void) +{ + struct spdcache_entry *entry; + int i; + + for (i = 0; i < V_spdcachehash_mask + 1; ++i) { + SPDCACHE_LOCK(i); + while (!LIST_EMPTY(&V_spdcachehashtbl[i])) { + entry = LIST_FIRST(&V_spdcachehashtbl[i]); + LIST_REMOVE(entry, chain); + spdcache_entry_free(entry); + } + SPDCACHE_UNLOCK(i); + } +} + +#ifdef VIMAGE +void +spdcache_destroy(void) +{ + int i; + + if (SPDCACHE_ENABLED()) { + spdcache_clear(); + hashdestroy(V_spdcachehashtbl, M_IPSEC_SPDCACHE, V_spdcachehash_mask); + + for (i = 0; i < V_spdcachehash_mask + 1; ++i) + SPDCACHE_LOCK_DESTROY(i); + + free(V_spdcache_lock, M_IPSEC_SPDCACHE); + } +} +#endif +void key_init(void) { int i; @@ -8092,6 +8326,8 @@ key_init(void) V_acqseqhashtbl = hashinit(ACQHASH_NHASH, M_IPSEC_SAQ, &V_acqseqhash_mask); + spdcache_init(); + for (i = 0; i <= SADB_SATYPE_MAX; i++) LIST_INIT(&V_regtree[i]); @@ -8147,6 +8383,7 @@ key_destroy(void) for (i = 0; i < V_sphash_mask + 1; i++) LIST_INIT(&V_sphashtbl[i]); SPTREE_WUNLOCK(); + spdcache_destroy(); sp = TAILQ_FIRST(&drainq); while (sp != NULL) { diff --git a/freebsd/sys/netpfil/pf/if_pfsync.c b/freebsd/sys/netpfil/pf/if_pfsync.c index 3ed1b3bb..9b457818 100644 --- a/freebsd/sys/netpfil/pf/if_pfsync.c +++ b/freebsd/sys/netpfil/pf/if_pfsync.c @@ -589,6 +589,8 @@ pfsync_input(struct mbuf **mp, int *offp __unused, int proto __unused) int rv; uint16_t count; + PF_RULES_RLOCK_TRACKER; + *mp = NULL; V_pfsyncstats.pfsyncs_ipackets++; diff --git a/freebsd/sys/netpfil/pf/pf.c b/freebsd/sys/netpfil/pf/pf.c index 1aab6f49..3cc4ff11 100644 --- a/freebsd/sys/netpfil/pf/pf.c +++ b/freebsd/sys/netpfil/pf/pf.c @@ -371,11 +371,14 @@ u_long pf_hashmask; u_long pf_srchashmask; static u_long pf_hashsize; static u_long pf_srchashsize; +u_long pf_ioctl_maxcount = 65535; SYSCTL_ULONG(_net_pf, OID_AUTO, states_hashsize, CTLFLAG_RDTUN, &pf_hashsize, 0, "Size of pf(4) states hashtable"); SYSCTL_ULONG(_net_pf, OID_AUTO, source_nodes_hashsize, CTLFLAG_RDTUN, &pf_srchashsize, 0, "Size of pf(4) source nodes hashtable"); +SYSCTL_ULONG(_net_pf, OID_AUTO, request_maxcount, CTLFLAG_RDTUN, + &pf_ioctl_maxcount, 0, "Maximum number of tables, addresses, ... in a single ioctl() call"); VNET_DEFINE(void *, pf_swi_cookie); @@ -5736,8 +5739,7 @@ bad: /* * FreeBSD supports cksum offloads for the following drivers. - * em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4), - * ti(4), txp(4), xl(4) + * em(4), fxp(4), lge(4), ndis(4), nge(4), re(4), ti(4), txp(4), xl(4) * * CSUM_DATA_VALID | CSUM_PSEUDO_HDR : * network driver performed cksum including pseudo header, need to verify @@ -5884,6 +5886,8 @@ pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb * struct pf_pdesc pd; int off, dirndx, pqid = 0; + PF_RULES_RLOCK_TRACKER; + M_ASSERTPKTHDR(m); if (!V_pf_status.running) @@ -6271,6 +6275,7 @@ pf_test6(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb struct pf_pdesc pd; int off, terminal = 0, dirndx, rh_cnt = 0, pqid = 0; + PF_RULES_RLOCK_TRACKER; M_ASSERTPKTHDR(m); if (!V_pf_status.running) diff --git a/freebsd/sys/netpfil/pf/pf_if.c b/freebsd/sys/netpfil/pf/pf_if.c index e224e6a7..2ac76ff2 100644 --- a/freebsd/sys/netpfil/pf/pf_if.c +++ b/freebsd/sys/netpfil/pf/pf_if.c @@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$"); #include <sys/eventhandler.h> #include <sys/lock.h> #include <sys/mbuf.h> -#include <sys/rwlock.h> #include <sys/socket.h> #include <net/if.h> @@ -131,9 +130,9 @@ pfi_initialize_vnet(void) PF_RULES_WUNLOCK(); IFNET_RLOCK(); - TAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) + CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) pfi_attach_ifgroup(ifg); - TAILQ_FOREACH(ifp, &V_ifnet, if_link) + CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) pfi_attach_ifnet(ifp); IFNET_RUNLOCK(); } @@ -302,7 +301,7 @@ pfi_kif_match(struct pfi_kif *rule_kif, struct pfi_kif *packet_kif) if (rule_kif->pfik_group != NULL) /* XXXGL: locking? */ - TAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next) + CK_STAILQ_FOREACH(p, &packet_kif->pfik_ifp->if_groups, ifgl_next) if (p->ifgl_group == rule_kif->pfik_group) return (1); @@ -468,7 +467,7 @@ pfi_kif_update(struct pfi_kif *kif) /* again for all groups kif is member of */ if (kif->pfik_ifp != NULL) { IF_ADDR_RLOCK(kif->pfik_ifp); - TAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next) + CK_STAILQ_FOREACH(ifgl, &kif->pfik_ifp->if_groups, ifgl_next) pfi_kif_update((struct pfi_kif *) ifgl->ifgl_group->ifg_pf_kif); IF_ADDR_RUNLOCK(kif->pfik_ifp); @@ -508,7 +507,7 @@ pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags) pfi_instance_add(kif->pfik_ifp, net, flags); else if (kif->pfik_group != NULL) { IFNET_RLOCK_NOSLEEP(); - TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next) + CK_STAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next) pfi_instance_add(ifgm->ifgm_ifp, net, flags); IFNET_RUNLOCK_NOSLEEP(); } @@ -527,7 +526,7 @@ pfi_instance_add(struct ifnet *ifp, int net, int flags) int net2, af; IF_ADDR_RLOCK(ifp); - TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) { + CK_STAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) { if (ia->ifa_addr == NULL) continue; af = ia->ifa_addr->sa_family; @@ -670,7 +669,7 @@ pfi_update_status(const char *name, struct pf_status *pfs) struct pfi_kif *p; struct pfi_kif_cmp key; struct ifg_member p_member, *ifgm; - TAILQ_HEAD(, ifg_member) ifg_members; + CK_STAILQ_HEAD(, ifg_member) ifg_members; int i, j, k; strlcpy(key.pfik_name, name, sizeof(key.pfik_name)); @@ -685,14 +684,14 @@ pfi_update_status(const char *name, struct pf_status *pfs) /* build a temporary list for p only */ bzero(&p_member, sizeof(p_member)); p_member.ifgm_ifp = p->pfik_ifp; - TAILQ_INIT(&ifg_members); - TAILQ_INSERT_TAIL(&ifg_members, &p_member, ifgm_next); + CK_STAILQ_INIT(&ifg_members); + CK_STAILQ_INSERT_TAIL(&ifg_members, &p_member, ifgm_next); } if (pfs) { bzero(pfs->pcounters, sizeof(pfs->pcounters)); bzero(pfs->bcounters, sizeof(pfs->bcounters)); } - TAILQ_FOREACH(ifgm, &ifg_members, ifgm_next) { + CK_STAILQ_FOREACH(ifgm, &ifg_members, ifgm_next) { if (ifgm->ifgm_ifp == NULL || ifgm->ifgm_ifp->if_pf_kif == NULL) continue; p = (struct pfi_kif *)ifgm->ifgm_ifp->if_pf_kif; diff --git a/freebsd/sys/netpfil/pf/pf_ioctl.c b/freebsd/sys/netpfil/pf/pf_ioctl.c index 9be57273..837ad31c 100644 --- a/freebsd/sys/netpfil/pf/pf_ioctl.c +++ b/freebsd/sys/netpfil/pf/pf_ioctl.c @@ -61,7 +61,6 @@ __FBSDID("$FreeBSD$"); #include <sys/mbuf.h> #include <sys/module.h> #include <sys/proc.h> -#include <sys/rwlock.h> #include <sys/smp.h> #include <sys/socket.h> #include <sys/sysctl.h> @@ -204,7 +203,7 @@ VNET_DEFINE(int, pf_vnet_active); int pf_end_threads; struct proc *pf_purge_proc; -struct rwlock pf_rules_lock; +struct rmlock pf_rules_lock; struct sx pf_ioctl_lock; struct sx pf_end_lock; @@ -218,6 +217,8 @@ pfsync_defer_t *pfsync_defer_ptr = NULL; /* pflog */ pflog_packet_t *pflog_packet_ptr = NULL; +extern u_long pf_ioctl_maxcount; + static void pfattach_vnet(void) { @@ -995,6 +996,7 @@ static int pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) { int error = 0; + PF_RULES_RLOCK_TRACKER; /* XXX keep in sync with switch() below */ if (securelevel_gt(td->td_ucred, 2)) @@ -2542,13 +2544,16 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } - totlen = io->pfrio_size * sizeof(struct pfr_table); - pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table), - M_TEMP, M_WAITOK); - if (! pfrts) { + + if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_table))) { error = ENOMEM; break; } + + totlen = io->pfrio_size * sizeof(struct pfr_table); + pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table), + M_TEMP, M_WAITOK); error = copyin(io->pfrio_buffer, pfrts, totlen); if (error) { free(pfrts, M_TEMP); @@ -2571,13 +2576,16 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } - totlen = io->pfrio_size * sizeof(struct pfr_table); - pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table), - M_TEMP, M_WAITOK); - if (! pfrts) { + + if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_table))) { error = ENOMEM; break; } + + totlen = io->pfrio_size * sizeof(struct pfr_table); + pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table), + M_TEMP, M_WAITOK); error = copyin(io->pfrio_buffer, pfrts, totlen); if (error) { free(pfrts, M_TEMP); @@ -2594,20 +2602,25 @@ DIOCCHANGEADDR_error: case DIOCRGETTABLES: { struct pfioc_table *io = (struct pfioc_table *)addr; struct pfr_table *pfrts; - size_t totlen; + size_t totlen, n; if (io->pfrio_esize != sizeof(struct pfr_table)) { error = ENODEV; break; } + PF_RULES_RLOCK(); + n = pfr_table_count(&io->pfrio_table, io->pfrio_flags); + io->pfrio_size = min(io->pfrio_size, n); + totlen = io->pfrio_size * sizeof(struct pfr_table); + pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table), - M_TEMP, M_WAITOK); - if (! pfrts) { + M_TEMP, M_NOWAIT); + if (pfrts == NULL) { error = ENOMEM; + PF_RULES_RUNLOCK(); break; } - PF_RULES_RLOCK(); error = pfr_get_tables(&io->pfrio_table, pfrts, &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); PF_RULES_RUNLOCK(); @@ -2620,20 +2633,24 @@ DIOCCHANGEADDR_error: case DIOCRGETTSTATS: { struct pfioc_table *io = (struct pfioc_table *)addr; struct pfr_tstats *pfrtstats; - size_t totlen; + size_t totlen, n; if (io->pfrio_esize != sizeof(struct pfr_tstats)) { error = ENODEV; break; } + PF_RULES_WLOCK(); + n = pfr_table_count(&io->pfrio_table, io->pfrio_flags); + io->pfrio_size = min(io->pfrio_size, n); + totlen = io->pfrio_size * sizeof(struct pfr_tstats); pfrtstats = mallocarray(io->pfrio_size, - sizeof(struct pfr_tstats), M_TEMP, M_WAITOK); - if (! pfrtstats) { + sizeof(struct pfr_tstats), M_TEMP, M_NOWAIT); + if (pfrtstats == NULL) { error = ENOMEM; + PF_RULES_WUNLOCK(); break; } - PF_RULES_WLOCK(); error = pfr_get_tstats(&io->pfrio_table, pfrtstats, &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL); PF_RULES_WUNLOCK(); @@ -2646,25 +2663,31 @@ DIOCCHANGEADDR_error: case DIOCRCLRTSTATS: { struct pfioc_table *io = (struct pfioc_table *)addr; struct pfr_table *pfrts; - size_t totlen; + size_t totlen, n; if (io->pfrio_esize != sizeof(struct pfr_table)) { error = ENODEV; break; } + + PF_RULES_WLOCK(); + n = pfr_table_count(&io->pfrio_table, io->pfrio_flags); + io->pfrio_size = min(io->pfrio_size, n); + totlen = io->pfrio_size * sizeof(struct pfr_table); pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table), - M_TEMP, M_WAITOK); - if (! pfrts) { + M_TEMP, M_NOWAIT); + if (pfrts == NULL) { error = ENOMEM; + PF_RULES_WUNLOCK(); break; } error = copyin(io->pfrio_buffer, pfrts, totlen); if (error) { free(pfrts, M_TEMP); + PF_RULES_WUNLOCK(); break; } - PF_RULES_WLOCK(); error = pfr_clr_tstats(pfrts, io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL); PF_RULES_WUNLOCK(); @@ -2675,25 +2698,31 @@ DIOCCHANGEADDR_error: case DIOCRSETTFLAGS: { struct pfioc_table *io = (struct pfioc_table *)addr; struct pfr_table *pfrts; - size_t totlen; + size_t totlen, n; if (io->pfrio_esize != sizeof(struct pfr_table)) { error = ENODEV; break; } + + PF_RULES_WLOCK(); + n = pfr_table_count(&io->pfrio_table, io->pfrio_flags); + io->pfrio_size = min(io->pfrio_size, n); + totlen = io->pfrio_size * sizeof(struct pfr_table); pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table), - M_TEMP, M_WAITOK); - if (! pfrts) { + M_TEMP, M_NOWAIT); + if (pfrts == NULL) { error = ENOMEM; + PF_RULES_WUNLOCK(); break; } error = copyin(io->pfrio_buffer, pfrts, totlen); if (error) { free(pfrts, M_TEMP); + PF_RULES_WUNLOCK(); break; } - PF_RULES_WLOCK(); error = pfr_set_tflags(pfrts, io->pfrio_size, io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange, &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL); @@ -2725,9 +2754,15 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } + if (io->pfrio_size < 0 || + io->pfrio_size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) { + error = EINVAL; + break; + } totlen = io->pfrio_size * sizeof(struct pfr_addr); pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr), - M_TEMP, M_WAITOK); + M_TEMP, M_NOWAIT); if (! pfras) { error = ENOMEM; break; @@ -2757,9 +2792,15 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } + if (io->pfrio_size < 0 || + io->pfrio_size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) { + error = EINVAL; + break; + } totlen = io->pfrio_size * sizeof(struct pfr_addr); pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr), - M_TEMP, M_WAITOK); + M_TEMP, M_NOWAIT); if (! pfras) { error = ENOMEM; break; @@ -2789,10 +2830,19 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } + if (io->pfrio_size < 0 || io->pfrio_size2 < 0) { + error = EINVAL; + break; + } count = max(io->pfrio_size, io->pfrio_size2); + if (count > pf_ioctl_maxcount || + WOULD_OVERFLOW(count, sizeof(struct pfr_addr))) { + error = EINVAL; + break; + } totlen = count * sizeof(struct pfr_addr); pfras = mallocarray(count, sizeof(struct pfr_addr), M_TEMP, - M_WAITOK); + M_NOWAIT); if (! pfras) { error = ENOMEM; break; @@ -2823,9 +2873,15 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } + if (io->pfrio_size < 0 || + io->pfrio_size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) { + error = EINVAL; + break; + } totlen = io->pfrio_size * sizeof(struct pfr_addr); pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr), - M_TEMP, M_WAITOK); + M_TEMP, M_NOWAIT); if (! pfras) { error = ENOMEM; break; @@ -2849,9 +2905,15 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } + if (io->pfrio_size < 0 || + io->pfrio_size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_astats))) { + error = EINVAL; + break; + } totlen = io->pfrio_size * sizeof(struct pfr_astats); pfrastats = mallocarray(io->pfrio_size, - sizeof(struct pfr_astats), M_TEMP, M_WAITOK); + sizeof(struct pfr_astats), M_TEMP, M_NOWAIT); if (! pfrastats) { error = ENOMEM; break; @@ -2875,9 +2937,15 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } + if (io->pfrio_size < 0 || + io->pfrio_size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) { + error = EINVAL; + break; + } totlen = io->pfrio_size * sizeof(struct pfr_addr); pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr), - M_TEMP, M_WAITOK); + M_TEMP, M_NOWAIT); if (! pfras) { error = ENOMEM; break; @@ -2907,9 +2975,15 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } + if (io->pfrio_size < 0 || + io->pfrio_size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) { + error = EINVAL; + break; + } totlen = io->pfrio_size * sizeof(struct pfr_addr); pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr), - M_TEMP, M_WAITOK); + M_TEMP, M_NOWAIT); if (! pfras) { error = ENOMEM; break; @@ -2939,9 +3013,15 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } + if (io->pfrio_size < 0 || + io->pfrio_size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) { + error = EINVAL; + break; + } totlen = io->pfrio_size * sizeof(struct pfr_addr); pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr), - M_TEMP, M_WAITOK); + M_TEMP, M_NOWAIT); if (! pfras) { error = ENOMEM; break; @@ -2986,9 +3066,15 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } + if (io->size < 0 || + io->size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) { + error = EINVAL; + break; + } totlen = sizeof(struct pfioc_trans_e) * io->size; ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e), - M_TEMP, M_WAITOK); + M_TEMP, M_NOWAIT); if (! ioes) { error = ENOMEM; break; @@ -3057,9 +3143,15 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } + if (io->size < 0 || + io->size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) { + error = EINVAL; + break; + } totlen = sizeof(struct pfioc_trans_e) * io->size; ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e), - M_TEMP, M_WAITOK); + M_TEMP, M_NOWAIT); if (! ioes) { error = ENOMEM; break; @@ -3128,10 +3220,18 @@ DIOCCHANGEADDR_error: error = ENODEV; break; } + + if (io->size < 0 || + io->size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) { + error = EINVAL; + break; + } + totlen = sizeof(struct pfioc_trans_e) * io->size; ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e), - M_TEMP, M_WAITOK); - if (! ioes) { + M_TEMP, M_NOWAIT); + if (ioes == NULL) { error = ENOMEM; break; } @@ -3334,13 +3434,21 @@ DIOCCHANGEADDR_error: break; } + if (io->pfiio_size < 0 || + io->pfiio_size > pf_ioctl_maxcount || + WOULD_OVERFLOW(io->pfiio_size, sizeof(struct pfi_kif))) { + error = EINVAL; + break; + } + bufsiz = io->pfiio_size * sizeof(struct pfi_kif); ifstore = mallocarray(io->pfiio_size, sizeof(struct pfi_kif), - M_TEMP, M_WAITOK); - if (! ifstore) { + M_TEMP, M_NOWAIT); + if (ifstore == NULL) { error = ENOMEM; break; } + PF_RULES_RLOCK(); pfi_get_ifaces(io->pfiio_name, ifstore, &io->pfiio_size); PF_RULES_RUNLOCK(); @@ -3828,7 +3936,7 @@ pf_load(void) { int error; - rw_init(&pf_rules_lock, "pf rulesets"); + rm_init(&pf_rules_lock, "pf rulesets"); sx_init(&pf_ioctl_lock, "pf ioctl"); sx_init(&pf_end_lock, "pf end thread"); @@ -3901,7 +4009,7 @@ pf_unload(void) pfi_cleanup(); - rw_destroy(&pf_rules_lock); + rm_destroy(&pf_rules_lock); sx_destroy(&pf_ioctl_lock); sx_destroy(&pf_end_lock); } diff --git a/freebsd/sys/netpfil/pf/pf_lb.c b/freebsd/sys/netpfil/pf/pf_lb.c index 7ce27a07..1fd02a0b 100644 --- a/freebsd/sys/netpfil/pf/pf_lb.c +++ b/freebsd/sys/netpfil/pf/pf_lb.c @@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/lock.h> #include <sys/mbuf.h> -#include <sys/rwlock.h> #include <sys/socket.h> #include <sys/sysctl.h> diff --git a/freebsd/sys/netpfil/pf/pf_norm.c b/freebsd/sys/netpfil/pf/pf_norm.c index 4f0966ed..61da5e4f 100644 --- a/freebsd/sys/netpfil/pf/pf_norm.c +++ b/freebsd/sys/netpfil/pf/pf_norm.c @@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$"); #include <sys/mbuf.h> #include <sys/mutex.h> #include <sys/refcount.h> -#include <sys/rwlock.h> #include <sys/socket.h> #include <net/if.h> diff --git a/freebsd/sys/netpfil/pf/pf_osfp.c b/freebsd/sys/netpfil/pf/pf_osfp.c index 1ee16df5..b87d39bd 100644 --- a/freebsd/sys/netpfil/pf/pf_osfp.c +++ b/freebsd/sys/netpfil/pf/pf_osfp.c @@ -29,7 +29,6 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/lock.h> #include <sys/mbuf.h> -#include <sys/rwlock.h> #include <sys/socket.h> #include <netinet/in.h> diff --git a/freebsd/sys/netpfil/pf/pf_table.c b/freebsd/sys/netpfil/pf/pf_table.c index 06916204..04a275d9 100644 --- a/freebsd/sys/netpfil/pf/pf_table.c +++ b/freebsd/sys/netpfil/pf/pf_table.c @@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$"); #include <sys/mbuf.h> #include <sys/mutex.h> #include <sys/refcount.h> -#include <sys/rwlock.h> #include <sys/socket.h> #include <vm/uma.h> @@ -179,7 +178,6 @@ static struct pfr_ktable *pfr_lookup_table(struct pfr_table *); static void pfr_clean_node_mask(struct pfr_ktable *, struct pfr_kentryworkq *); -static int pfr_table_count(struct pfr_table *, int); static int pfr_skip_table(struct pfr_table *, struct pfr_ktable *, int); static struct pfr_kentry @@ -1690,7 +1688,7 @@ pfr_fix_anchor(char *anchor) return (0); } -static int +int pfr_table_count(struct pfr_table *filter, int flags) { struct pf_ruleset *rs; diff --git a/freebsd/sys/opencrypto/cryptodev.c b/freebsd/sys/opencrypto/cryptodev.c index 3a9ed6e3..162a247c 100644 --- a/freebsd/sys/opencrypto/cryptodev.c +++ b/freebsd/sys/opencrypto/cryptodev.c @@ -43,8 +43,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <rtems/bsd/local/opt_compat.h> - #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> diff --git a/freebsd/sys/opencrypto/cryptosoft.c b/freebsd/sys/opencrypto/cryptosoft.c index 55e98b13..69993ae0 100644 --- a/freebsd/sys/opencrypto/cryptosoft.c +++ b/freebsd/sys/opencrypto/cryptosoft.c @@ -86,7 +86,7 @@ static int swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, int flags) { - unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN], *idat; + unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN]; unsigned char *ivp, *nivp, iv2[EALG_MAX_BLOCK_LEN]; struct enc_xform *exf; int i, j, k, blks, ind, count, ivlen; @@ -251,11 +251,13 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, } while (uio->uio_iov[ind].iov_len >= k + blks && i > 0) { + uint8_t *idat; size_t nb, rem; nb = blks; - rem = uio->uio_iov[ind].iov_len - k; - idat = (char *)uio->uio_iov[ind].iov_base + k; + rem = MIN((size_t)i, + uio->uio_iov[ind].iov_len - (size_t)k); + idat = (uint8_t *)uio->uio_iov[ind].iov_base + k; if (exf->reinit) { if ((crd->crd_flags & CRD_F_ENCRYPT) != 0 && @@ -298,7 +300,6 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, ivp = nivp; } - idat += nb; count += nb; k += nb; i -= nb; diff --git a/freebsd/sys/powerpc/include/machine/spr.h b/freebsd/sys/powerpc/include/machine/spr.h index 24ae5fe9..f4769c86 100644 --- a/freebsd/sys/powerpc/include/machine/spr.h +++ b/freebsd/sys/powerpc/include/machine/spr.h @@ -97,6 +97,7 @@ #define SPR_RTCL_R 0x005 /* .6. 601 RTC Lower - Read */ #define SPR_LR 0x008 /* 468 Link Register */ #define SPR_CTR 0x009 /* 468 Count Register */ +#define SPR_DSCR 0x011 /* Data Stream Control Register */ #define SPR_DSISR 0x012 /* .68 DSI exception source */ #define DSISR_DIRECT 0x80000000 /* Direct-store error exception */ #define DSISR_NOTFOUND 0x40000000 /* Translation not found */ @@ -120,6 +121,20 @@ #define SPR_EIE 0x050 /* ..8 Exception Interrupt ??? */ #define SPR_EID 0x051 /* ..8 Exception Interrupt ??? */ #define SPR_NRI 0x052 /* ..8 Exception Interrupt ??? */ +#define SPR_FSCR 0x099 /* Facility Status and Control Register */ +#define FSCR_IC_MASK 0xFF00000000000000ULL /* FSCR[0:7] is Interrupt Cause */ +#define FSCR_IC_FP 0x0000000000000000ULL /* FP unavailable */ +#define FSCR_IC_VSX 0x0100000000000000ULL /* VSX unavailable */ +#define FSCR_IC_DSCR 0x0200000000000000ULL /* Access to the DSCR at SPRs 3 or 17 */ +#define FSCR_IC_PM 0x0300000000000000ULL /* Read or write access of a Performance Monitor SPR in group A */ +#define FSCR_IC_BHRB 0x0400000000000000ULL /* Execution of a BHRB Instruction */ +#define FSCR_IC_HTM 0x0500000000000000ULL /* Access to a Transactional Memory */ +/* Reserved 0x0600000000000000ULL */ +#define FSCR_IC_EBB 0x0700000000000000ULL /* Access to Event-Based Branch */ +#define FSCR_IC_TAR 0x0800000000000000ULL /* Access to Target Address Register */ +#define FSCR_IC_STOP 0x0900000000000000ULL /* Access to the 'stop' instruction in privileged non-hypervisor state */ +#define FSCR_IC_MSG 0x0A00000000000000ULL /* Access to 'msgsndp' or 'msgclrp' instructions */ +#define FSCR_IC_SCV 0x0C00000000000000ULL /* Execution of a 'scv' instruction */ #define SPR_USPRG0 0x100 /* 4.. User SPR General 0 */ #define SPR_VRSAVE 0x100 /* .6. AltiVec VRSAVE */ #define SPR_SPRG0 0x110 /* 468 SPR General 0 */ @@ -200,14 +215,6 @@ #define FSL_E300C3 0x8085 #define FSL_E300C4 0x8086 -#define SPR_LPCR 0x13e /* Logical Partitioning Control */ -#define LPCR_LPES 0x008 /* Bit 60 */ -#define LPCR_PECE_DRBL (1ULL << 16) /* Directed Privileged Doorbell */ -#define LPCR_PECE_HDRBL (1ULL << 15) /* Directed Hypervisor Doorbell */ -#define LPCR_PECE_EXT (1ULL << 14) /* External exceptions */ -#define LPCR_PECE_DECR (1ULL << 13) /* Decrementer exceptions */ -#define LPCR_PECE_ME (1ULL << 12) /* Machine Check and Hypervisor */ - /* Maintenance exceptions */ #define LPCR_PECE_WAKESET (LPCR_PECE_EXT | LPCR_PECE_DECR | LPCR_PECE_ME) #define SPR_EPCR 0x133 @@ -224,10 +231,20 @@ #define EPCR_PMGS 0x00200000 #define SPR_SPEFSCR 0x200 /* ..8 Signal Processing Engine FSCR. */ +#define SPR_HSRR0 0x13a +#define SPR_HSRR1 0x13b #define SPR_LPCR 0x13e /* Logical Partitioning Control */ -#define LPCR_LPES 0x008 /* Bit 60 */ +#define LPCR_LPES 0x008 /* Bit 60 */ +#define LPCR_HVICE 0x002 /* Hypervisor Virtualization Interrupt (Arch 3.0) */ +#define LPCR_PECE_DRBL (1ULL << 16) /* Directed Privileged Doorbell */ +#define LPCR_PECE_HDRBL (1ULL << 15) /* Directed Hypervisor Doorbell */ +#define LPCR_PECE_EXT (1ULL << 14) /* External exceptions */ +#define LPCR_PECE_DECR (1ULL << 13) /* Decrementer exceptions */ +#define LPCR_PECE_ME (1ULL << 12) /* Machine Check and Hypervisor */ + /* Maintenance exceptions */ #define SPR_LPID 0x13f /* Logical Partitioning Control */ +#define SPR_PTCR 0x1d0 /* Partition Table Control Register */ #define SPR_IBAT0U 0x210 /* .68 Instruction BAT Reg 0 Upper */ #define SPR_IBAT0U 0x210 /* .6. Instruction BAT Reg 0 Upper */ #define SPR_IBAT0L 0x211 /* .6. Instruction BAT Reg 0 Lower */ @@ -366,6 +383,7 @@ #define SPR_MD_CAM 0x338 /* ..8 IMMU CAM entry read */ #define SPR_MD_RAM0 0x339 /* ..8 IMMU RAM entry read reg 0 */ #define SPR_MD_RAM1 0x33a /* ..8 IMMU RAM entry read reg 1 */ +#define SPR_PSSCR 0x357 /* Processor Stop Status and Control Register (ISA 3.0) */ #define SPR_UMMCR2 0x3a0 /* .6. User Monitor Mode Control Register 2 */ #define SPR_UMMCR0 0x3a8 /* .6. User Monitor Mode Control Register 0 */ #define SPR_USIA 0x3ab /* .6. User Sampled Instruction Address */ diff --git a/freebsd/sys/sys/buf.h b/freebsd/sys/sys/buf.h index c9b2eeae..a099a972 100644 --- a/freebsd/sys/sys/buf.h +++ b/freebsd/sys/sys/buf.h @@ -479,6 +479,7 @@ buf_track(struct buf *bp, const char *location) #define GB_UNMAPPED 0x0008 /* Do not mmap buffer pages. */ #define GB_KVAALLOC 0x0010 /* But allocate KVA. */ #define GB_CKHASH 0x0020 /* If reading, calc checksum hash */ +#define GB_NOSPARSE 0x0040 /* Do not instantiate holes */ #ifdef _KERNEL extern int nbuf; /* The number of buffer headers */ @@ -540,6 +541,8 @@ struct buf * getpbuf(int *); struct buf *incore(struct bufobj *, daddr_t); struct buf *gbincore(struct bufobj *, daddr_t); struct buf *getblk(struct vnode *, daddr_t, int, int, int, int); +int getblkx(struct vnode *vp, daddr_t blkno, int size, int slpflag, + int slptimeo, int flags, struct buf **bpp); struct buf *geteblk(int, int); int bufwait(struct buf *); int bufwrite(struct buf *); diff --git a/freebsd/sys/sys/buf_ring.h b/freebsd/sys/sys/buf_ring.h index 0b633238..e8c69341 100644 --- a/freebsd/sys/sys/buf_ring.h +++ b/freebsd/sys/sys/buf_ring.h @@ -34,10 +34,6 @@ #include <machine/cpu.h> -#if defined(INVARIANTS) && !defined(DEBUG_BUFRING) -#define DEBUG_BUFRING 1 -#endif - #ifdef DEBUG_BUFRING #include <sys/lock.h> #include <sys/mutex.h> @@ -69,6 +65,12 @@ buf_ring_enqueue(struct buf_ring *br, void *buf) uint32_t prod_head, prod_next, cons_tail; #ifdef DEBUG_BUFRING int i; + + /* + * Note: It is possible to encounter an mbuf that was removed + * via drbr_peek(), and then re-added via drbr_putback() and + * trigger a spurious panic. + */ for (i = br->br_cons_head; i != br->br_prod_head; i = ((i + 1) & br->br_cons_mask)) if(br->br_ring[i] == buf) diff --git a/freebsd/sys/sys/bus.h b/freebsd/sys/sys/bus.h index d1d6bbb9..f3c54f36 100644 --- a/freebsd/sys/sys/bus.h +++ b/freebsd/sys/sys/bus.h @@ -46,7 +46,7 @@ */ struct u_businfo { int ub_version; /**< @brief interface version */ -#define BUS_USER_VERSION 1 +#define BUS_USER_VERSION 2 int ub_generation; /**< @brief generation count */ }; @@ -63,20 +63,23 @@ typedef enum device_state { /** * @brief Device information exported to userspace. + * The strings are placed one after the other, separated by NUL characters. + * Fields should be added after the last one and order maintained for compatibility */ +#define BUS_USER_BUFFER (3*1024) struct u_device { uintptr_t dv_handle; uintptr_t dv_parent; - - char dv_name[32]; /**< @brief Name of device in tree. */ - char dv_desc[32]; /**< @brief Driver description */ - char dv_drivername[32]; /**< @brief Driver name */ - char dv_pnpinfo[128]; /**< @brief Plug and play info */ - char dv_location[128]; /**< @brief Where is the device? */ uint32_t dv_devflags; /**< @brief API Flags for device */ uint16_t dv_flags; /**< @brief flags for dev state */ device_state_t dv_state; /**< @brief State of attachment */ - /* XXX more driver info? */ + char dv_fields[BUS_USER_BUFFER]; /**< @brief NUL terminated fields */ + /* name (name of the device in tree) */ + /* desc (driver description) */ + /* drivername (Name of driver without unit number) */ + /* pnpinfo (Plug and play information from bus) */ + /* location (Location of device on parent */ + /* NUL */ }; /* Flags exported via dv_flags. */ @@ -89,6 +92,7 @@ struct u_device { #define DF_EXTERNALSOFTC 0x40 /* softc not allocated by us */ #define DF_REBID 0x80 /* Can rebid after attach */ #define DF_SUSPENDED 0x100 /* Device is suspended. */ +#define DF_QUIET_CHILDREN 0x200 /* Default to quiet for all my children */ /** * @brief Device request structure used for ioctl's. @@ -584,6 +588,7 @@ device_state_t device_get_state(device_t dev); int device_get_unit(device_t dev); struct sysctl_ctx_list *device_get_sysctl_ctx(device_t dev); struct sysctl_oid *device_get_sysctl_tree(device_t dev); +int device_has_quiet_children(device_t dev); int device_is_alive(device_t dev); /* did probe succeed? */ int device_is_attached(device_t dev); /* did attach succeed? */ int device_is_enabled(device_t dev); @@ -597,6 +602,7 @@ int device_probe_and_attach(device_t dev); int device_probe_child(device_t bus, device_t dev); int device_quiesce(device_t dev); void device_quiet(device_t dev); +void device_quiet_children(device_t dev); void device_set_desc(device_t dev, const char* desc); void device_set_desc_copy(device_t dev, const char* desc); int device_set_devclass(device_t dev, const char *classname); diff --git a/freebsd/sys/sys/capsicum.h b/freebsd/sys/sys/capsicum.h index 847b4478..bf97d0b2 100644 --- a/freebsd/sys/sys/capsicum.h +++ b/freebsd/sys/sys/capsicum.h @@ -344,12 +344,115 @@ bool cap_rights_is_valid(const cap_rights_t *rights); cap_rights_t *cap_rights_merge(cap_rights_t *dst, const cap_rights_t *src); cap_rights_t *cap_rights_remove(cap_rights_t *dst, const cap_rights_t *src); bool cap_rights_contains(const cap_rights_t *big, const cap_rights_t *little); +void __cap_rights_sysinit(void *arg); __END_DECLS +struct cap_rights_init_args { + cap_rights_t *cria_rights; + uint64_t cria_value1; + uint64_t cria_value2; + uint64_t cria_value3; + uint64_t cria_value4; + uint64_t cria_value5; +}; + +#define CAP_RIGHTS_SYSINIT0(name, rights) \ + static struct cap_rights_init_args name##_args = { \ + &(rights) \ + }; \ + SYSINIT(name##_cap_rights_sysinit, SI_SUB_COPYRIGHT+1, SI_ORDER_ANY, \ + __cap_rights_sysinit, &name##_args); + +#define CAP_RIGHTS_SYSINIT1(name, rights, value1) \ + static struct cap_rights_init_args name##_args = { \ + &(rights), \ + (value1) \ + }; \ + SYSINIT(name##_cap_rights_sysinit, SI_SUB_COPYRIGHT+1, SI_ORDER_ANY, \ + __cap_rights_sysinit, &name##_args); + +#define CAP_RIGHTS_SYSINIT2(name, rights, value1, value2) \ + static struct cap_rights_init_args name##_args = { \ + &(rights), \ + (value1), \ + (value2) \ + }; \ + SYSINIT(name##_cap_rights_sysinit, SI_SUB_COPYRIGHT, SI_ORDER_ANY, \ + __cap_rights_sysinit, &name##_args); + +#define CAP_RIGHTS_SYSINIT3(name, rights, value1, value2, value3) \ + static struct cap_rights_init_args name##_args = { \ + &(rights), \ + (value1), \ + (value2), \ + (value3) \ + }; \ + SYSINIT(name##_cap_rights_sysinit, SI_SUB_COPYRIGHT, SI_ORDER_ANY, \ + __cap_rights_sysinit, &name##_args); + +#define CAP_RIGHTS_SYSINIT4(name, rights, value1, value2, value3, value4) \ + static struct cap_rights_init_args name##_args = { \ + &(rights), \ + (value1), \ + (value2), \ + (value3), \ + (value4) \ + }; \ + SYSINIT(name##_cap_rights_sysinit, SI_SUB_COPYRIGHT, SI_ORDER_ANY, \ + __cap_rights_sysinit, &name##_args); + +#define CAP_RIGHTS_DEFINE1(name, value) \ + __read_mostly cap_rights_t name; \ + CAP_RIGHTS_SYSINIT1(name, name, value); #ifdef _KERNEL #include <sys/systm.h> +extern cap_rights_t cap_accept_rights; +extern cap_rights_t cap_bind_rights; +extern cap_rights_t cap_connect_rights; +extern cap_rights_t cap_event_rights; +extern cap_rights_t cap_fchdir_rights; +extern cap_rights_t cap_fchflags_rights; +extern cap_rights_t cap_fchmod_rights; +extern cap_rights_t cap_fchown_rights; +extern cap_rights_t cap_fcntl_rights; +extern cap_rights_t cap_fexecve_rights; +extern cap_rights_t cap_flock_rights; +extern cap_rights_t cap_fpathconf_rights; +extern cap_rights_t cap_fstat_rights; +extern cap_rights_t cap_fstatfs_rights; +extern cap_rights_t cap_fsync_rights; +extern cap_rights_t cap_ftruncate_rights; +extern cap_rights_t cap_futimes_rights; +extern cap_rights_t cap_getpeername_rights; +extern cap_rights_t cap_getsockopt_rights; +extern cap_rights_t cap_getsockname_rights; +extern cap_rights_t cap_ioctl_rights; +extern cap_rights_t cap_linkat_source_rights; +extern cap_rights_t cap_linkat_target_rights; +extern cap_rights_t cap_listen_rights; +extern cap_rights_t cap_mkdirat_rights; +extern cap_rights_t cap_mkfifoat_rights; +extern cap_rights_t cap_mknodat_rights; +extern cap_rights_t cap_mmap_rights; +extern cap_rights_t cap_no_rights; +extern cap_rights_t cap_pdgetpid_rights; +extern cap_rights_t cap_pdkill_rights; +extern cap_rights_t cap_pread_rights; +extern cap_rights_t cap_pwrite_rights; +extern cap_rights_t cap_read_rights; +extern cap_rights_t cap_recv_rights; +extern cap_rights_t cap_renameat_source_rights; +extern cap_rights_t cap_renameat_target_rights; +extern cap_rights_t cap_seek_rights; +extern cap_rights_t cap_send_rights; +extern cap_rights_t cap_send_connect_rights; +extern cap_rights_t cap_setsockopt_rights; +extern cap_rights_t cap_shutdown_rights; +extern cap_rights_t cap_symlinkat_rights; +extern cap_rights_t cap_unlinkat_rights; +extern cap_rights_t cap_write_rights; #define IN_CAPABILITY_MODE(td) (((td)->td_ucred->cr_flags & CRED_FLAG_CAPMODE) != 0) @@ -363,20 +466,20 @@ int cap_check(const cap_rights_t *havep, const cap_rights_t *needp); /* * Convert capability rights into VM access flags. */ -u_char cap_rights_to_vmprot(cap_rights_t *havep); +u_char cap_rights_to_vmprot(const cap_rights_t *havep); /* * For the purposes of procstat(1) and similar tools, allow kern_descrip.c to * extract the rights from a capability. */ -cap_rights_t *cap_rights_fde(struct filedescent *fde); -cap_rights_t *cap_rights(struct filedesc *fdp, int fd); +const cap_rights_t *cap_rights_fde(const struct filedescent *fde); +const cap_rights_t *cap_rights(struct filedesc *fdp, int fd); int cap_ioctl_check(struct filedesc *fdp, int fd, u_long cmd); int cap_fcntl_check_fde(struct filedescent *fde, int cmd); int cap_fcntl_check(struct filedesc *fdp, int fd, int cmd); -extern int trap_enotcap; +extern bool trap_enotcap; #else /* !_KERNEL */ diff --git a/freebsd/sys/sys/ck.h b/freebsd/sys/sys/ck.h new file mode 100644 index 00000000..3bfce70c --- /dev/null +++ b/freebsd/sys/sys/ck.h @@ -0,0 +1,13 @@ +/* + * $FreeBSD$ + */ +#ifdef _KERNEL +#include <ck_queue.h> +#include <ck_epoch.h> +#else +#include <sys/queue.h> +#define CK_STAILQ_HEAD STAILQ_HEAD +#define CK_STAILQ_ENTRY STAILQ_ENTRY +#define CK_LIST_HEAD LIST_HEAD +#define CK_LIST_ENTRY LIST_ENTRY +#endif diff --git a/freebsd/sys/sys/conf.h b/freebsd/sys/sys/conf.h index 3980eba2..4ace162f 100644 --- a/freebsd/sys/sys/conf.h +++ b/freebsd/sys/sys/conf.h @@ -121,6 +121,8 @@ struct cdev { struct bio; struct buf; +struct dumperinfo; +struct kerneldumpheader; struct thread; struct uio; struct knote; @@ -151,6 +153,9 @@ typedef int dumper_t( vm_offset_t _physical, /* Physical address of virtual. */ off_t _offset, /* Byte-offset to write at. */ size_t _length); /* Number of bytes to dump. */ +typedef int dumper_start_t(struct dumperinfo *di); +typedef int dumper_hdr_t(struct dumperinfo *di, struct kerneldumpheader *kdh, + void *key, uint32_t keylen); #endif /* _KERNEL */ @@ -360,13 +365,18 @@ struct kerneldumpheader; struct dumperinfo { dumper_t *dumper; /* Dumping function. */ + dumper_start_t *dumper_start; /* Dumper callback for dump_start(). */ + dumper_hdr_t *dumper_hdr; /* Dumper callback for writing headers. */ void *priv; /* Private parts. */ u_int blocksize; /* Size of block in bytes. */ u_int maxiosize; /* Max size allowed for an individual I/O */ off_t mediaoffset; /* Initial offset in bytes. */ off_t mediasize; /* Space available in bytes. */ + + /* MI kernel dump state. */ void *blockbuf; /* Buffer for padding shorter dump blocks */ off_t dumpoff; /* Offset of ongoing kernel dump. */ + off_t origdumpoff; /* Starting dump offset. */ struct kerneldumpcrypto *kdcrypto; /* Kernel dump crypto. */ struct kerneldumpcomp *kdcomp; /* Kernel dump compression. */ }; @@ -381,6 +391,7 @@ int doadump(boolean_t); int set_dumper(struct dumperinfo *di, const char *devname, struct thread *td, uint8_t compression, uint8_t encryption, const uint8_t *key, uint32_t encryptedkeysize, const uint8_t *encryptedkey); +int clear_dumper(struct thread *td); int dump_start(struct dumperinfo *di, struct kerneldumpheader *kdh); int dump_append(struct dumperinfo *, void *, vm_offset_t, size_t); diff --git a/freebsd/sys/sys/cons.h b/freebsd/sys/sys/cons.h index aded0459..04784646 100644 --- a/freebsd/sys/sys/cons.h +++ b/freebsd/sys/sys/cons.h @@ -66,6 +66,8 @@ struct consdev_ops { /* grab console for exclusive kernel use */ cn_ungrab_t *cn_ungrab; /* ungrab console */ + cn_init_t *cn_resume; + /* set up console after sleep, optional */ }; struct consdev { @@ -105,8 +107,9 @@ extern struct tty *constty; /* Temporary virtual console. */ }; \ DATA_SET(cons_set, name) -#define CONSOLE_DRIVER(name) \ +#define CONSOLE_DRIVER(name, ...) \ static const struct consdev_ops name##_consdev_ops = { \ + /* Mandatory methods. */ \ .cn_probe = name##_cnprobe, \ .cn_init = name##_cninit, \ .cn_term = name##_cnterm, \ @@ -114,6 +117,8 @@ extern struct tty *constty; /* Temporary virtual console. */ .cn_putc = name##_cnputc, \ .cn_grab = name##_cngrab, \ .cn_ungrab = name##_cnungrab, \ + /* Optional fields. */ \ + __VA_ARGS__ \ }; \ CONSOLE_DEVICE(name##_consdev, name##_consdev_ops, NULL) @@ -126,6 +131,7 @@ void cnremove(struct consdev *); void cnselect(struct consdev *); void cngrab(void); void cnungrab(void); +void cnresume(void); int cncheckc(void); int cngetc(void); void cngets(char *, size_t, int); diff --git a/freebsd/sys/sys/filedesc.h b/freebsd/sys/sys/filedesc.h index 5a0b2db1..a3224f42 100644 --- a/freebsd/sys/sys/filedesc.h +++ b/freebsd/sys/sys/filedesc.h @@ -174,7 +174,7 @@ enum { struct thread; void filecaps_init(struct filecaps *fcaps); -int filecaps_copy(const struct filecaps *src, struct filecaps *dst, +bool filecaps_copy(const struct filecaps *src, struct filecaps *dst, bool locked); void filecaps_move(struct filecaps *src, struct filecaps *dst); #ifndef __rtems__ @@ -266,18 +266,19 @@ int fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, struct file **fpp, seq_t *seqp); #else /* __rtems__ */ static inline int -fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, - struct file **fpp, seq_t *seqp) +do_fget_unlocked(struct filedesc *fdp, int fd, struct file **fpp, seq_t *seqp) { struct file *fp; (void)fdp; - (void)needrightsp; (void)seqp; fp = rtems_bsd_get_file(fd); *fpp = fp; return (fp != NULL ? 0 : EBADF); } + +#define fget_unlocked(fdp, fd, needrightsp, fpp, seqp) \ + do_fget_unlocked(fdp, fd, fpp, seqp) #endif /* __rtems__ */ #ifndef __rtems__ diff --git a/freebsd/sys/sys/gtaskqueue.h b/freebsd/sys/sys/gtaskqueue.h index 41094603..c06ef503 100644 --- a/freebsd/sys/sys/gtaskqueue.h +++ b/freebsd/sys/sys/gtaskqueue.h @@ -54,13 +54,16 @@ void gtaskqueue_drain_all(struct gtaskqueue *queue); int grouptaskqueue_enqueue(struct gtaskqueue *queue, struct gtask *task); void taskqgroup_attach(struct taskqgroup *qgroup, struct grouptask *grptask, - void *uniq, int irq, char *name); + void *uniq, int irq, const char *name); int taskqgroup_attach_cpu(struct taskqgroup *qgroup, struct grouptask *grptask, - void *uniq, int cpu, int irq, char *name); + void *uniq, int cpu, int irq, const char *name); void taskqgroup_detach(struct taskqgroup *qgroup, struct grouptask *gtask); -struct taskqgroup *taskqgroup_create(char *name); +struct taskqgroup *taskqgroup_create(const char *name); void taskqgroup_destroy(struct taskqgroup *qgroup); int taskqgroup_adjust(struct taskqgroup *qgroup, int cnt, int stride); +void taskqgroup_config_gtask_init(void *ctx, struct grouptask *gtask, gtask_fn_t *fn, + const char *name); +void taskqgroup_config_gtask_deinit(struct grouptask *gtask); #define TASK_ENQUEUED 0x1 #define TASK_SKIP_WAKEUP 0x2 diff --git a/freebsd/sys/sys/jail.h b/freebsd/sys/sys/jail.h index 3bbbf5e0..c42964fe 100644 --- a/freebsd/sys/sys/jail.h +++ b/freebsd/sys/sys/jail.h @@ -216,7 +216,10 @@ struct prison_racct { #define PR_IP6 0x04000000 /* IPv6 restricted or disabled */ /* by this jail or an ancestor */ -/* Flags for pr_allow */ +/* + * Flags for pr_allow + * Bits not noted here may be used for dynamic allow.mount.xxxfs. + */ #define PR_ALLOW_SET_HOSTNAME 0x00000001 #define PR_ALLOW_SYSVIPC 0x00000002 #define PR_ALLOW_RAW_SOCKETS 0x00000004 @@ -224,17 +227,9 @@ struct prison_racct { #define PR_ALLOW_MOUNT 0x00000010 #define PR_ALLOW_QUOTAS 0x00000020 #define PR_ALLOW_SOCKET_AF 0x00000040 -#define PR_ALLOW_MOUNT_DEVFS 0x00000080 -#define PR_ALLOW_MOUNT_NULLFS 0x00000100 -#define PR_ALLOW_MOUNT_ZFS 0x00000200 -#define PR_ALLOW_MOUNT_PROCFS 0x00000400 -#define PR_ALLOW_MOUNT_TMPFS 0x00000800 -#define PR_ALLOW_MOUNT_FDESCFS 0x00001000 -#define PR_ALLOW_MOUNT_LINPROCFS 0x00002000 -#define PR_ALLOW_MOUNT_LINSYSFS 0x00004000 #define PR_ALLOW_RESERVED_PORTS 0x00008000 #define PR_ALLOW_KMEM_ACCESS 0x00010000 /* reserved, not used yet */ -#define PR_ALLOW_ALL 0x0001ffff +#define PR_ALLOW_ALL_STATIC 0x0001807f /* * OSD methods @@ -364,6 +359,7 @@ struct ucred; struct mount; struct sockaddr; struct statfs; +struct vfsconf; int jailed(struct ucred *cred); int jailed_without_vnet(struct ucred *); void getcredhostname(struct ucred *, char *, size_t); @@ -421,6 +417,7 @@ int prison_if(struct ucred *cred, struct sockaddr *sa); char *prison_name(struct prison *, struct prison *); int prison_priv_check(struct ucred *cred, int priv); int sysctl_jail_param(SYSCTL_HANDLER_ARGS); +void prison_add_vfs(struct vfsconf *vfsp); void prison_racct_foreach(void (*callback)(struct racct *racct, void *arg2, void *arg3), void (*pre)(void), void (*post)(void), void *arg2, void *arg3); diff --git a/freebsd/sys/sys/linker.h b/freebsd/sys/sys/linker.h index 6d560574..21c5a41e 100644 --- a/freebsd/sys/sys/linker.h +++ b/freebsd/sys/sys/linker.h @@ -273,11 +273,16 @@ extern int kld_debug; typedef int elf_lookup_fn(linker_file_t, Elf_Size, int, Elf_Addr *); /* Support functions */ -int elf_reloc(linker_file_t _lf, Elf_Addr base, const void *_rel, int _type, elf_lookup_fn _lu); -int elf_reloc_local(linker_file_t _lf, Elf_Addr base, const void *_rel, int _type, elf_lookup_fn _lu); +int elf_reloc(linker_file_t _lf, Elf_Addr base, const void *_rel, + int _type, elf_lookup_fn _lu); +int elf_reloc_ifunc(linker_file_t _lf, Elf_Addr base, const void *_rel, + int _type, elf_lookup_fn _lu); +int elf_reloc_local(linker_file_t _lf, Elf_Addr base, const void *_rel, + int _type, elf_lookup_fn _lu); Elf_Addr elf_relocaddr(linker_file_t _lf, Elf_Addr addr); const Elf_Sym *elf_get_sym(linker_file_t _lf, Elf_Size _symidx); const char *elf_get_symname(linker_file_t _lf, Elf_Size _symidx); +void link_elf_ireloc(caddr_t kmdp); typedef struct linker_ctf { const uint8_t *ctftab; /* Decompressed CTF data. */ diff --git a/freebsd/sys/sys/lockstat.h b/freebsd/sys/sys/lockstat.h index 6167a7d1..9a6674fa 100644 --- a/freebsd/sys/sys/lockstat.h +++ b/freebsd/sys/sys/lockstat.h @@ -70,7 +70,7 @@ SDT_PROBE_DECLARE(lockstat, , , thread__spin); #define LOCKSTAT_WRITER 0 #define LOCKSTAT_READER 1 -extern volatile int lockstat_enabled; +extern volatile bool lockstat_enabled; #ifdef KDTRACE_HOOKS diff --git a/freebsd/sys/sys/malloc.h b/freebsd/sys/sys/malloc.h index 1920ff69..8c66fe81 100644 --- a/freebsd/sys/sys/malloc.h +++ b/freebsd/sys/sys/malloc.h @@ -59,6 +59,13 @@ #define M_MAGIC 877983977 /* time when first defined :-) */ +#ifdef INVARIANTS +#define M_ZERO_INVARIANTS M_ZERO +#else +#define M_ZERO_INVARIANTS 0 +#endif + + /* * Two malloc type structures are present: malloc_type, which is used by a * type owner to declare the type, and malloc_type_internal, which holds diff --git a/freebsd/sys/sys/mbuf.h b/freebsd/sys/sys/mbuf.h index 4a91b794..4d2a3223 100644 --- a/freebsd/sys/sys/mbuf.h +++ b/freebsd/sys/sys/mbuf.h @@ -196,6 +196,11 @@ struct pkthdr { #define lro_nsegs tso_segsz #define csum_phsum PH_per.sixteen[2] #define csum_data PH_per.thirtytwo[1] +#define pace_thoff PH_loc.sixteen[0] +#define pace_tlen PH_loc.sixteen[1] +#define pace_drphdrlen PH_loc.sixteen[2] +#define pace_tos PH_loc.eight[6] +#define pace_lock PH_loc.eight[7] /* * Description of external storage mapped into mbuf; valid only if M_EXT is @@ -1375,5 +1380,12 @@ mbuf_tstmp2timespec(struct mbuf *m, struct timespec *ts) } #endif +#ifdef NETDUMP +/* Invoked from the netdump client code. */ +void netdump_mbuf_drain(void); +void netdump_mbuf_dump(void); +void netdump_mbuf_reinit(int nmbuf, int nclust, int clsize); +#endif + #endif /* _KERNEL */ #endif /* !_SYS_MBUF_H_ */ diff --git a/freebsd/sys/sys/module.h b/freebsd/sys/sys/module.h index c3f8dc3c..6799b179 100644 --- a/freebsd/sys/sys/module.h +++ b/freebsd/sys/sys/module.h @@ -141,7 +141,7 @@ struct mod_pnp_match_info #define DECLARE_MODULE_WITH_MAXVER(name, data, sub, order, maxver) \ MODULE_DEPEND(name, kernel, __FreeBSD_version, \ - __FreeBSD_version, maxver); \ + __FreeBSD_version, maxver); \ MODULE_METADATA(_md_##name, MDT_MODULE, &data, __XSTRING(name));\ SYSINIT(name##module, sub, order, module_register_init, &data); \ struct __hack @@ -156,7 +156,7 @@ struct mod_pnp_match_info * Use it for modules that use kernel interfaces that are not stable * even on STABLE/X branches. */ -#define DECLARE_MODULE_TIED(name, data, sub, order) \ +#define DECLARE_MODULE_TIED(name, data, sub, order) \ DECLARE_MODULE_WITH_MAXVER(name, data, sub, order, __FreeBSD_version) #define MODULE_VERSION_CONCAT(module, version) _##module##_version diff --git a/freebsd/sys/sys/mount.h b/freebsd/sys/sys/mount.h index 9d499004..c4f4bebf 100644 --- a/freebsd/sys/sys/mount.h +++ b/freebsd/sys/sys/mount.h @@ -516,6 +516,7 @@ struct vfsconf { int vfc_typenum; /* historic filesystem type number */ int vfc_refcount; /* number mounted of this type */ int vfc_flags; /* permanent flags */ + int vfc_prison_flag; /* prison allow.mount.* flag */ struct vfsoptdecl *vfc_opts; /* mount options */ TAILQ_ENTRY(vfsconf) vfc_list; /* list of vfscons */ }; @@ -851,7 +852,8 @@ vfs_statfs_t __vfs_statfs; */ #define VFS_VERSION_00 0x19660120 #define VFS_VERSION_01 0x20121030 -#define VFS_VERSION VFS_VERSION_01 +#define VFS_VERSION_02 0x20180504 +#define VFS_VERSION VFS_VERSION_02 #define VFS_SET(vfsops, fsname, flags) \ static struct vfsconf fsname ## _vfsconf = { \ diff --git a/freebsd/sys/sys/proc.h b/freebsd/sys/sys/proc.h index cef3ae2e..36ed69cc 100644 --- a/freebsd/sys/sys/proc.h +++ b/freebsd/sys/sys/proc.h @@ -76,6 +76,18 @@ /* + * A section object may be passed to every begin-end pair to allow for + * forward progress guarantees with-in prolonged active sections. + * + * We can't include ck_epoch.h so we define our own variant here and + * then CTASSERT that it's the same size in subr_epoch.c + */ +struct epoch_section { + unsigned int bucket; +}; +typedef struct epoch_section epoch_section_t; + +/* * One structure allocated per session. * * List of locks @@ -263,7 +275,8 @@ struct thread { u_char td_lend_user_pri; /* (t) Lend user pri. */ /* Cleared during fork1() */ -#define td_startzero td_flags +#define td_startzero td_epochnest + u_char td_epochnest; /* (k) Epoch nest counter. */ int td_flags; /* (t) TDF_* flags. */ int td_inhibitors; /* (t) Why can not run. */ int td_pflags; /* (k) Private thread (TDP_*) flags. */ @@ -280,6 +293,7 @@ struct thread { u_char td_tsqueue; /* (t) Turnstile queue blocked on. */ short td_locks; /* (k) Debug: count of non-spin locks */ short td_rw_rlocks; /* (k) Count of rwlock read locks. */ + short td_sx_slocks; /* (k) Count of sx shared locks. */ short td_lk_slocks; /* (k) Count of lockmgr shared locks. */ short td_stopsched; /* (k) Scheduler stopped. */ struct turnstile *td_blocked; /* (t) Lock thread is blocked on. */ @@ -340,6 +354,7 @@ struct thread { u_char td_pri_class; /* (t) Scheduling class. */ u_char td_user_pri; /* (t) User pri from estcpu and nice. */ u_char td_base_user_pri; /* (t) Base user pri */ + u_char td_pre_epoch_prio; /* (k) User pri on entry to epoch */ uintptr_t td_rb_list; /* (k) Robust list head. */ uintptr_t td_rbp_list; /* (k) Robust priv list head. */ uintptr_t td_rb_inact; /* (k) Current in-action mutex loc. */ @@ -369,6 +384,7 @@ struct thread { #ifndef __rtems__ #define td_retval td_uretoff.tdu_retval u_int td_cowgen; /* (k) Generation of COW pointers. */ + /* LP64 hole */ struct callout td_slpcallout; /* (h) Callout for sleep. */ struct trapframe *td_frame; /* (k) */ struct vm_object *td_kstack_obj;/* (a) Kstack object. */ @@ -380,16 +396,20 @@ struct thread { struct lpohead td_lprof[2]; /* (a) lock profiling objects. */ struct kdtrace_thread *td_dtrace; /* (*) DTrace-specific data. */ int td_errno; /* Error returned by last syscall. */ + /* LP64 hole */ struct vnet *td_vnet; /* (k) Effective vnet. */ const char *td_vnet_lpush; /* (k) Debugging vnet push / pop. */ struct trapframe *td_intr_frame;/* (k) Frame of the current irq */ struct proc *td_rfppwait_p; /* (k) The vforked child */ struct vm_page **td_ma; /* (k) uio pages held */ int td_ma_cnt; /* (k) size of *td_ma */ + /* LP64 hole */ void *td_emuldata; /* Emulator state data */ int td_lastcpu; /* (t) Last cpu we were on. */ int td_oncpu; /* (t) Which cpu we are on. */ void *td_lkpi_task; /* LinuxKPI task struct pointer */ + TAILQ_ENTRY(thread) td_epochq; /* (t) Epoch queue. */ + epoch_section_t td_epoch_section; /* (t) epoch section object */ #endif /* __rtems__ */ }; @@ -485,6 +505,7 @@ do { \ #define TDB_EXIT 0x00000400 /* Exiting LWP indicator for ptrace() */ #define TDB_VFORK 0x00000800 /* vfork indicator for ptrace() */ #define TDB_FSTP 0x00001000 /* The thread is PT_ATTACH leader */ +#define TDB_STEP 0x00002000 /* (x86) PSL_T set for PT_STEP */ /* * "Private" flags kept in td_pflags: @@ -669,6 +690,7 @@ struct proc { u_int p_treeflag; /* (e) P_TREE flags */ int p_pendingexits; /* (c) Count of pending thread exits. */ struct filemon *p_filemon; /* (c) filemon-specific data. */ + int p_pdeathsig; /* (c) Signal from parent on exit. */ /* End area that is zeroed on creation. */ #define p_endzero p_magic @@ -713,7 +735,7 @@ struct proc { struct racct *p_racct; /* (b) Resource accounting. */ int p_throttled; /* (c) Flag for racct pcpu throttling */ /* - * An orphan is the child that has beed re-parented to the + * An orphan is the child that has been re-parented to the * debugger as a result of attaching to it. Need to keep * track of them for parent to be able to collect the exit * status of what used to be children. diff --git a/freebsd/sys/sys/random.h b/freebsd/sys/sys/random.h index 69d377f5..c717a686 100644 --- a/freebsd/sys/sys/random.h +++ b/freebsd/sys/sys/random.h @@ -116,9 +116,38 @@ enum random_entropy_source { #define RANDOM_CACHED_SKIP_START 256 #if defined(DEV_RANDOM) -void random_harvest_queue(const void *, u_int, u_int, enum random_entropy_source); -void random_harvest_fast(const void *, u_int, u_int, enum random_entropy_source); -void random_harvest_direct(const void *, u_int, u_int, enum random_entropy_source); +extern u_int hc_source_mask; +void random_harvest_queue_(const void *, u_int, u_int, enum random_entropy_source); +void random_harvest_fast_(const void *, u_int, u_int); +void random_harvest_direct_(const void *, u_int, u_int, enum random_entropy_source); + +static __inline void +random_harvest_queue(const void *entropy, u_int size, u_int bits, + enum random_entropy_source origin) +{ + + if (hc_source_mask & (1 << origin)) + random_harvest_queue_(entropy, size, bits, origin); +} + +static __inline void +random_harvest_fast(const void *entropy, u_int size, u_int bits, + enum random_entropy_source origin) +{ + + if (hc_source_mask & (1 << origin)) + random_harvest_fast_(entropy, size, bits); +} + +static __inline void +random_harvest_direct(const void *entropy, u_int size, u_int bits, + enum random_entropy_source origin) +{ + + if (hc_source_mask & (1 << origin)) + random_harvest_direct_(entropy, size, bits, origin); +} + void random_harvest_register_source(enum random_entropy_source); void random_harvest_deregister_source(enum random_entropy_source); #else @@ -135,6 +164,13 @@ void random_harvest_deregister_source(enum random_entropy_source); #define random_harvest_fast_uma(a, b, c, d) do {} while (0) #endif /* defined(RANDOM_ENABLE_UMA) */ +#if defined(RANDOM_ENABLE_ETHER) +#define random_harvest_queue_ether(a, b, c) random_harvest_queue(a, b, c, RANDOM_NET_ETHER) +#else /* !defined(RANDOM_ENABLE_ETHER) */ +#define random_harvest_queue_ether(a, b, c) do {} while (0) +#endif /* defined(RANDOM_ENABLE_ETHER) */ + + #endif /* _KERNEL */ #define GRND_NONBLOCK 0x1 diff --git a/freebsd/sys/sys/resourcevar.h b/freebsd/sys/sys/resourcevar.h index b84bc432..9301c3e0 100644 --- a/freebsd/sys/sys/resourcevar.h +++ b/freebsd/sys/sys/resourcevar.h @@ -143,7 +143,6 @@ rtems_bsd_chgsbsize(u_int *hiwat, u_int to) #endif /* __rtems__ */ int chgptscnt(struct uidinfo *uip, int diff, rlim_t maxval); int chgumtxcnt(struct uidinfo *uip, int diff, rlim_t maxval); -int fuswintr(void *base); int kern_proc_setrlimit(struct thread *td, struct proc *p, u_int which, struct rlimit *limp); struct plimit @@ -167,7 +166,6 @@ void rufetchcalc(struct proc *p, struct rusage *ru, struct timeval *up, struct timeval *sp); void rufetchtd(struct thread *td, struct rusage *ru); void ruxagg(struct proc *p, struct thread *td); -int suswintr(void *base, int word); struct uidinfo *uifind(uid_t uid); void uifree(struct uidinfo *uip); diff --git a/freebsd/sys/sys/stdint.h b/freebsd/sys/sys/stdint.h index 98915f72..44384d24 100644 --- a/freebsd/sys/sys/stdint.h +++ b/freebsd/sys/sys/stdint.h @@ -36,8 +36,10 @@ #ifndef __rtems__ #include <machine/_stdint.h> -#endif /* __rtems__ */ #include <sys/_stdint.h> +#else /* __rtems__ */ +#include <stdint.h> +#endif /* __rtems__ */ #ifndef __rtems__ typedef __int_least8_t int_least8_t; diff --git a/freebsd/sys/sys/sx.h b/freebsd/sys/sys/sx.h index 33143057..566137bd 100644 --- a/freebsd/sys/sys/sx.h +++ b/freebsd/sys/sys/sx.h @@ -77,12 +77,14 @@ #define SX_LOCK_SHARED_WAITERS 0x02 #define SX_LOCK_EXCLUSIVE_WAITERS 0x04 #define SX_LOCK_RECURSED 0x08 +#define SX_LOCK_WRITE_SPINNER 0x10 #define SX_LOCK_FLAGMASK \ (SX_LOCK_SHARED | SX_LOCK_SHARED_WAITERS | \ - SX_LOCK_EXCLUSIVE_WAITERS | SX_LOCK_RECURSED) + SX_LOCK_EXCLUSIVE_WAITERS | SX_LOCK_RECURSED | SX_LOCK_WRITE_SPINNER) +#define SX_LOCK_WAITERS (SX_LOCK_SHARED_WAITERS | SX_LOCK_EXCLUSIVE_WAITERS) #define SX_OWNER(x) ((x) & ~SX_LOCK_FLAGMASK) -#define SX_SHARERS_SHIFT 4 +#define SX_SHARERS_SHIFT 5 #define SX_SHARERS(x) (SX_OWNER(x) >> SX_SHARERS_SHIFT) #define SX_SHARERS_LOCK(x) \ ((x) << SX_SHARERS_SHIFT | SX_LOCK_SHARED) diff --git a/freebsd/sys/sys/sysctl.h b/freebsd/sys/sys/sysctl.h index 874d226f..995baf64 100644 --- a/freebsd/sys/sys/sysctl.h +++ b/freebsd/sys/sys/sysctl.h @@ -38,7 +38,9 @@ #ifndef _SYS_SYSCTL_H_ #define _SYS_SYSCTL_H_ +#ifdef _KERNEL #include <sys/queue.h> +#endif struct thread; /* @@ -1053,9 +1055,6 @@ SYSCTL_DECL(_compat); SYSCTL_DECL(_regression); SYSCTL_DECL(_security); SYSCTL_DECL(_security_bsd); -#ifdef EXT_RESOURCES -SYSCTL_DECL(_clock); -#endif extern char machine[]; extern char osrelease[]; diff --git a/freebsd/sys/sys/sysproto.h b/freebsd/sys/sys/sysproto.h index f70d820c..b328cb51 100644 --- a/freebsd/sys/sys/sysproto.h +++ b/freebsd/sys/sys/sysproto.h @@ -271,9 +271,6 @@ struct sbrk_args { struct sstk_args { char incr_l_[PADL_(int)]; int incr; char incr_r_[PADR_(int)]; }; -struct ovadvise_args { - char anom_l_[PADL_(int)]; int anom; char anom_r_[PADR_(int)]; -}; struct munmap_args { char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)]; char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)]; @@ -1875,7 +1872,6 @@ int sys_msync(struct thread *, struct msync_args *); int sys_vfork(struct thread *, struct vfork_args *); int sys_sbrk(struct thread *, struct sbrk_args *); int sys_sstk(struct thread *, struct sstk_args *); -int sys_ovadvise(struct thread *, struct ovadvise_args *); int sys_munmap(struct thread *, struct munmap_args *); int sys_mprotect(struct thread *, struct mprotect_args *); int sys_madvise(struct thread *, struct madvise_args *); @@ -2540,6 +2536,9 @@ struct freebsd11_mknod_args { char mode_l_[PADL_(int)]; int mode; char mode_r_[PADR_(int)]; char dev_l_[PADL_(int)]; int dev; char dev_r_[PADR_(int)]; }; +struct freebsd11_vadvise_args { + char anom_l_[PADL_(int)]; int anom; char anom_r_[PADR_(int)]; +}; struct freebsd11_stat_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char ub_l_[PADL_(struct freebsd11_stat *)]; struct freebsd11_stat * ub; char ub_r_[PADR_(struct freebsd11_stat *)]; @@ -2617,6 +2616,7 @@ struct freebsd11_mknodat_args { char dev_l_[PADL_(uint32_t)]; uint32_t dev; char dev_r_[PADR_(uint32_t)]; }; int freebsd11_mknod(struct thread *, struct freebsd11_mknod_args *); +int freebsd11_vadvise(struct thread *, struct freebsd11_vadvise_args *); int freebsd11_stat(struct thread *, struct freebsd11_stat_args *); int freebsd11_fstat(struct thread *, struct freebsd11_fstat_args *); int freebsd11_lstat(struct thread *, struct freebsd11_lstat_args *); @@ -2705,7 +2705,7 @@ int freebsd11_mknodat(struct thread *, struct freebsd11_mknodat_args *); #define SYS_AUE_sbrk AUE_SBRK #define SYS_AUE_sstk AUE_SSTK #define SYS_AUE_ommap AUE_MMAP -#define SYS_AUE_vadvise AUE_O_VADVISE +#define SYS_AUE_freebsd11_vadvise AUE_O_VADVISE #define SYS_AUE_munmap AUE_MUNMAP #define SYS_AUE_mprotect AUE_MPROTECT #define SYS_AUE_madvise AUE_MADVISE diff --git a/freebsd/sys/sys/systm.h b/freebsd/sys/sys/systm.h index 98efffd0..9c21f589 100644 --- a/freebsd/sys/sys/systm.h +++ b/freebsd/sys/sys/systm.h @@ -331,6 +331,12 @@ void hexdump(const void *ptr, int length, const char *hdr, int flags); #define ovbcopy(f, t, l) bcopy((f), (t), (l)) #ifndef __rtems__ void bcopy(const void * _Nonnull from, void * _Nonnull to, size_t len); +#define bcopy(from, to, len) ({ \ + if (__builtin_constant_p(len) && (len) <= 64) \ + __builtin_memmove((to), (from), (len)); \ + else \ + bcopy((from), (to), (len)); \ +}) void bzero(void * _Nonnull buf, size_t len); #define bzero(buf, len) ({ \ if (__builtin_constant_p(len) && (len) <= 64) \ @@ -345,6 +351,7 @@ void bzero(void * _Nonnull buf, size_t len); void explicit_bzero(void * _Nonnull, size_t); void *memcpy(void * _Nonnull to, const void * _Nonnull from, size_t len); +#define memcpy(to, from, len) __builtin_memcpy(to, from, len) void *memmove(void * _Nonnull dest, const void * _Nonnull src, size_t n); #ifndef __rtems__ @@ -462,6 +469,8 @@ void startprofclock(struct proc *); void stopprofclock(struct proc *); void cpu_startprofclock(void); void cpu_stopprofclock(void); +void suspendclock(void); +void resumeclock(void); sbintime_t cpu_idleclock(void); void cpu_activeclock(void); void cpu_new_callout(int cpu, sbintime_t bt, sbintime_t bt_opt); diff --git a/freebsd/sys/sys/unpcb.h b/freebsd/sys/sys/unpcb.h index 1ab3457d..d80b1384 100644 --- a/freebsd/sys/sys/unpcb.h +++ b/freebsd/sys/sys/unpcb.h @@ -69,27 +69,29 @@ typedef uint64_t unp_gen_t; LIST_HEAD(unp_head, unpcb); struct unpcb { - LIST_ENTRY(unpcb) unp_link; /* glue on list of all PCBs */ + /* Cache line 1 */ + struct mtx unp_mtx; /* mutex */ + struct unpcb *unp_conn; /* control block of connected socket */ + volatile u_int unp_refcount; + short unp_flags; /* flags */ + short unp_gcflag; /* Garbage collector flags. */ + struct sockaddr_un *unp_addr; /* bound address of socket */ struct socket *unp_socket; /* pointer back to socket */ - struct file *unp_file; /* back-pointer to file for gc. */ + /* Cache line 2 */ #ifndef __rtems__ struct vnode *unp_vnode; /* if associated with file */ #else /* __rtems__ */ void *unp_vnode; /* if associated with file */ #endif /* __rtems__ */ - ino_t unp_ino; /* fake inode number */ - struct unpcb *unp_conn; /* control block of connected socket */ - struct unp_head unp_refs; /* referencing socket linked list */ + struct xucred unp_peercred; /* peer credentials, if applicable */ LIST_ENTRY(unpcb) unp_reflink; /* link in unp_refs list */ - struct sockaddr_un *unp_addr; /* bound address of socket */ + LIST_ENTRY(unpcb) unp_link; /* glue on list of all PCBs */ + struct unp_head unp_refs; /* referencing socket linked list */ unp_gen_t unp_gencnt; /* generation count of this instance */ - short unp_flags; /* flags */ - short unp_gcflag; /* Garbage collector flags. */ - struct xucred unp_peercred; /* peer credentials, if applicable */ - u_int unp_refcount; + struct file *unp_file; /* back-pointer to file for gc. */ u_int unp_msgcount; /* references from message queue */ - struct mtx unp_mtx; /* mutex */ -}; + ino_t unp_ino; /* fake inode number */ +} __aligned(CACHE_LINE_SIZE); /* * Flags in unp_flags. diff --git a/freebsd/sys/sys/vmmeter.h b/freebsd/sys/sys/vmmeter.h index 408cd862..3c570b0a 100644 --- a/freebsd/sys/sys/vmmeter.h +++ b/freebsd/sys/sys/vmmeter.h @@ -73,11 +73,8 @@ struct vmtotal { /* * System wide statistics counters. * Locking: - * a - locked by atomic operations * c - constant after initialization - * f - locked by vm_page_queue_free_mtx * p - uses counter(9) - * q - changes are synchronized by the corresponding vm_pagequeue lock */ struct vmmeter { /* diff --git a/freebsd/sys/vm/uma.h b/freebsd/sys/vm/uma.h index 935c5aa7..d71f0ee3 100644 --- a/freebsd/sys/vm/uma.h +++ b/freebsd/sys/vm/uma.h @@ -265,8 +265,8 @@ uma_zone_t uma_zcache_create(char *name, int size, uma_ctor ctor, uma_dtor dtor, * information in the vm_page. */ #define UMA_ZONE_SECONDARY 0x0200 /* Zone is a Secondary Zone */ -/* 0x0400 Unused */ -#define UMA_ZONE_MAXBUCKET 0x0800 /* Use largest buckets */ +#define UMA_ZONE_NOBUCKET 0x0400 /* Do not use buckets. */ +#define UMA_ZONE_MAXBUCKET 0x0800 /* Use largest buckets. */ #define UMA_ZONE_CACHESPREAD 0x1000 /* * Spread memory start locations across * all possible cache lines. May @@ -286,6 +286,10 @@ uma_zone_t uma_zcache_create(char *name, int size, uma_ctor ctor, uma_dtor dtor, * NUMA aware Zone. Implements a best * effort first-touch policy. */ +#define UMA_ZONE_NOBUCKETCACHE 0x20000 /* + * Don't cache full buckets. Limit + * UMA to per-cpu state. + */ /* * These flags are shared between the keg and zone. In zones wishing to add diff --git a/freebsd/sys/vm/uma_core.c b/freebsd/sys/vm/uma_core.c index fdf7dc35..b8145c72 100644 --- a/freebsd/sys/vm/uma_core.c +++ b/freebsd/sys/vm/uma_core.c @@ -1364,7 +1364,15 @@ keg_small_init(uma_keg_t keg) else shsize = sizeof(struct uma_slab); - keg->uk_ipers = (slabsize - shsize) / rsize; + if (rsize <= slabsize - shsize) + keg->uk_ipers = (slabsize - shsize) / rsize; + else { + /* Handle special case when we have 1 item per slab, so + * alignment requirement can be relaxed. */ + KASSERT(keg->uk_size <= slabsize - shsize, + ("%s: size %u greater than slab", __func__, keg->uk_size)); + keg->uk_ipers = 1; + } KASSERT(keg->uk_ipers > 0 && keg->uk_ipers <= SLAB_SETSIZE, ("%s: keg->uk_ipers %u", __func__, keg->uk_ipers)); @@ -1547,7 +1555,7 @@ keg_ctor(void *mem, int size, void *udata, int flags) if (keg->uk_flags & UMA_ZONE_CACHESPREAD) { keg_cachespread_init(keg); } else { - if (keg->uk_size > (UMA_SLAB_SIZE - sizeof(struct uma_slab))) + if (keg->uk_size > UMA_SLAB_SPACE) keg_large_init(keg); else keg_small_init(keg); @@ -1751,10 +1759,15 @@ zone_ctor(void *mem, int size, void *udata, int flags) } out: - if ((arg->flags & UMA_ZONE_MAXBUCKET) == 0) - zone->uz_count = bucket_select(zone->uz_size); - else + KASSERT((arg->flags & (UMA_ZONE_MAXBUCKET | UMA_ZONE_NOBUCKET)) != + (UMA_ZONE_MAXBUCKET | UMA_ZONE_NOBUCKET), + ("Invalid zone flag combination")); + if ((arg->flags & UMA_ZONE_MAXBUCKET) != 0) zone->uz_count = BUCKET_MAX; + else if ((arg->flags & UMA_ZONE_NOBUCKET) != 0) + zone->uz_count = 0; + else + zone->uz_count = bucket_select(zone->uz_size); zone->uz_count_min = zone->uz_count; return (0); @@ -1901,9 +1914,11 @@ uma_startup_count(int vm_zones) #endif /* Memory for the rest of startup zones, UMA and VM, ... */ - if (zsize > UMA_SLAB_SIZE) + if (zsize > UMA_SLAB_SPACE) pages += (zones + vm_zones) * howmany(roundup2(zsize, UMA_BOOT_ALIGN), UMA_SLAB_SIZE); + else if (roundup2(zsize, UMA_BOOT_ALIGN) > UMA_SLAB_SPACE) + pages += zones; else pages += howmany(zones, UMA_SLAB_SPACE / roundup2(zsize, UMA_BOOT_ALIGN)); @@ -2444,14 +2459,6 @@ zalloc_start: cpu = curcpu; cache = &zone->uz_cpu[cpu]; - /* - * Since we have locked the zone we may as well send back our stats. - */ - atomic_add_long(&zone->uz_allocs, cache->uc_allocs); - atomic_add_long(&zone->uz_frees, cache->uc_frees); - cache->uc_allocs = 0; - cache->uc_frees = 0; - /* See if we lost the race to fill the cache. */ if (cache->uc_allocbucket != NULL) { ZONE_UNLOCK(zone); @@ -3103,7 +3110,13 @@ zfree_start: /* ub_cnt is pointing to the last free item */ KASSERT(bucket->ub_cnt != 0, ("uma_zfree: Attempting to insert an empty bucket onto the full list.\n")); - LIST_INSERT_HEAD(&zdom->uzd_buckets, bucket, ub_link); + if ((zone->uz_flags & UMA_ZONE_NOBUCKETCACHE) != 0) { + ZONE_UNLOCK(zone); + bucket_drain(zone, bucket); + bucket_free(zone, bucket, udata); + goto zfree_restart; + } else + LIST_INSERT_HEAD(&zdom->uzd_buckets, bucket, ub_link); } /* diff --git a/freebsd/sys/vm/uma_int.h b/freebsd/sys/vm/uma_int.h index 53d65dac..8d58fa33 100644 --- a/freebsd/sys/vm/uma_int.h +++ b/freebsd/sys/vm/uma_int.h @@ -177,7 +177,7 @@ struct uma_hash { * align field or structure to cache line */ #if defined(__amd64__) -#define UMA_ALIGN __aligned(CACHE_LINE_SIZE) +#define UMA_ALIGN __aligned(128) #else #define UMA_ALIGN #endif |