diff options
Diffstat (limited to 'sys')
66 files changed, 1104 insertions, 1288 deletions
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index 7aff1e8..48f41b3 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -35,6 +35,7 @@ options SOFTUPDATES # Enable FFS soft updates support options UFS_ACL # Support for access control lists options UFS_DIRHASH # Improve performance on big directories options UFS_GJOURNAL # Enable gjournal-based UFS journaling +options QUOTA # Enable disk quotas for UFS options MD_ROOT # MD is a potential root device options NFSCL # New Network Filesystem Client options NFSD # New Network Filesystem Server @@ -317,15 +318,6 @@ device usb # USB Bus (required) device ukbd # Keyboard device umass # Disks/Mass storage - Requires scbus and da -# FireWire support -device firewire # FireWire bus code -# sbp(4) works for some systems but causes boot failure on others -#device sbp # SCSI over FireWire (Requires scbus and da) -device fwe # Ethernet over FireWire (non-standard!) -device fwip # IP over FireWire (RFC 2734,3146) -device dcons # Dumb console driver -device dcons_crom # Configuration ROM for dcons - # Sound support device sound # Generic sound driver (required) device snd_cmi # CMedia CMI8338/CMI8738 diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c index e358f96..a1b5a8f 100644 --- a/sys/arm/arm/machdep.c +++ b/sys/arm/arm/machdep.c @@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$"); #include <sys/ptrace.h> #include <sys/signalvar.h> #include <sys/syscallsubr.h> +#include <sys/sysctl.h> #include <sys/sysent.h> #include <sys/sysproto.h> #include <sys/uio.h> @@ -162,8 +163,6 @@ const struct pmap_devmap *pmap_devmap_bootstrap_table; uint32_t board_id; struct arm_lbabi_tag *atag_list; -uint32_t revision; -uint64_t serial; char linux_command_line[LBABI_MAX_COMMAND_LINE + 1]; char atags[LBABI_MAX_COMMAND_LINE * 2]; uint32_t memstart[LBABI_MAX_BANKS]; @@ -171,6 +170,31 @@ uint32_t memsize[LBABI_MAX_BANKS]; uint32_t membanks; #endif +static uint32_t board_revision; +/* hex representation of uint64_t */ +static char board_serial[32]; + +SYSCTL_NODE(_hw, OID_AUTO, board, CTLFLAG_RD, 0, "Board attributes"); +SYSCTL_UINT(_hw_board, OID_AUTO, revision, CTLFLAG_RD, + &board_revision, 0, "Board revision"); +SYSCTL_STRING(_hw_board, OID_AUTO, serial, CTLFLAG_RD, + board_serial, 0, "Board serial"); + +void +board_set_serial(uint64_t serial) +{ + + snprintf(board_serial, sizeof(board_serial)-1, + "%016jx", serial); +} + +void +board_set_revision(uint32_t revision) +{ + + board_revision = revision; +} + void sendsig(catcher, ksi, mask) sig_t catcher; @@ -849,6 +873,8 @@ vm_offset_t linux_parse_boot_param(struct arm_boot_params *abp) { struct arm_lbabi_tag *walker; + uint32_t revision; + uint64_t serial; /* * Linux boot ABI: r0 = 0, r1 is the board type (!= 0) and r2 @@ -883,9 +909,11 @@ linux_parse_boot_param(struct arm_boot_params *abp) case ATAG_SERIAL: serial = walker->u.tag_sn.low | ((uint64_t)walker->u.tag_sn.high << 32); + board_set_serial(serial); break; case ATAG_REVISION: revision = walker->u.tag_rev.rev; + board_set_revision(revision); break; case ATAG_CMDLINE: /* XXX open question: Parse this for boothowto? */ diff --git a/sys/arm/arm/pl310.c b/sys/arm/arm/pl310.c index a5af23c..4e78375 100644 --- a/sys/arm/arm/pl310.c +++ b/sys/arm/arm/pl310.c @@ -135,11 +135,12 @@ pl310_cache_sync(void) return; #ifdef PL310_ERRATA_753970 - /* Write uncached PL310 register */ - pl310_write4(pl310_softc, 0x740, 0xffffffff); -#else - pl310_write4(pl310_softc, PL310_CACHE_SYNC, 0xffffffff); + if (pl310_softc->sc_rtl_revision == CACHE_ID_RELEASE_r3p0) + /* Write uncached PL310 register */ + pl310_write4(pl310_softc, 0x740, 0xffffffff); + else #endif + pl310_write4(pl310_softc, PL310_CACHE_SYNC, 0xffffffff); } @@ -152,13 +153,17 @@ pl310_wbinv_all(void) PL310_LOCK(pl310_softc); #ifdef PL310_ERRATA_727915 - platform_pl310_write_debug(pl310_softc, 3); + if (pl310_softc->sc_rtl_revision == CACHE_ID_RELEASE_r2p0 || + pl310_softc->sc_rtl_revision == CACHE_ID_RELEASE_r3p0) + platform_pl310_write_debug(pl310_softc, 3); #endif pl310_write4(pl310_softc, PL310_CLEAN_INV_WAY, g_l2cache_way_mask); pl310_wait_background_op(PL310_CLEAN_INV_WAY, g_l2cache_way_mask); pl310_cache_sync(); #ifdef PL310_ERRATA_727915 - platform_pl310_write_debug(pl310_softc, 0); + if (pl310_softc->sc_rtl_revision == CACHE_ID_RELEASE_r2p0 || + pl310_softc->sc_rtl_revision == CACHE_ID_RELEASE_r3p0) + platform_pl310_write_debug(pl310_softc, 0); #endif PL310_UNLOCK(pl310_softc); } @@ -186,18 +191,19 @@ pl310_wbinv_range(vm_paddr_t start, vm_size_t size) #endif while (size > 0) { #ifdef PL310_ERRATA_588369 - /* - * Errata 588369 says that clean + inv may keep the - * cache line if it was clean, the recommanded workaround - * is to clean then invalidate the cache line, with - * write-back and cache linefill disabled - */ - - pl310_write4(pl310_softc, PL310_CLEAN_LINE_PA, start); - pl310_write4(pl310_softc, PL310_INV_LINE_PA, start); -#else - pl310_write4(pl310_softc, PL310_CLEAN_INV_LINE_PA, start); + if (pl310_softc->sc_rtl_revision <= CACHE_ID_RELEASE_r1p0) { + /* + * Errata 588369 says that clean + inv may keep the + * cache line if it was clean, the recommanded + * workaround is to clean then invalidate the cache + * line, with write-back and cache linefill disabled. + */ + pl310_write4(pl310_softc, PL310_CLEAN_LINE_PA, start); + pl310_write4(pl310_softc, PL310_INV_LINE_PA, start); + } else #endif + pl310_write4(pl310_softc, PL310_CLEAN_INV_LINE_PA, + start); start += g_l2cache_line_size; size -= g_l2cache_line_size; } @@ -307,6 +313,8 @@ pl310_attach(device_t dev) pl310_filter, NULL, sc, &sc->sc_irq_h); cache_id = pl310_read4(sc, PL310_CACHE_ID); + sc->sc_rtl_revision = (cache_id >> CACHE_ID_RELEASE_SHIFT) & + CACHE_ID_RELEASE_MASK; device_printf(dev, "Part number: 0x%x, release: 0x%x\n", (cache_id >> CACHE_ID_PARTNUM_SHIFT) & CACHE_ID_PARTNUM_MASK, (cache_id >> CACHE_ID_RELEASE_SHIFT) & CACHE_ID_RELEASE_MASK); diff --git a/sys/arm/arm/pmap-v6.c b/sys/arm/arm/pmap-v6.c index 0df6281..d3e386d 100644 --- a/sys/arm/arm/pmap-v6.c +++ b/sys/arm/arm/pmap-v6.c @@ -193,6 +193,14 @@ int pmap_debug_level = 0; #define PMAP_INLINE __inline #endif /* PMAP_DEBUG */ +#ifdef ARM_L2_PIPT +#define pmap_l2cache_wbinv_range(va, pa, size) cpu_l2cache_wbinv_range((pa), (size)) +#define pmap_l2cache_inv_range(va, pa, size) cpu_l2cache_inv_range((pa), (size)) +#else +#define pmap_l2cache_wbinv_range(va, pa, size) cpu_l2cache_wbinv_range((va), (size)) +#define pmap_l2cache_inv_range(va, pa, size) cpu_l2cache_inv_range((va), (size)) +#endif + extern struct pv_addr systempage; /* @@ -786,11 +794,7 @@ pmap_l2ptp_ctor(void *mem, int size, void *arg, int flags) pte = *ptep; cpu_idcache_wbinv_range(va, PAGE_SIZE); -#ifdef ARM_L2_PIPT - cpu_l2cache_wbinv_range(pte & L2_S_FRAME, PAGE_SIZE); -#else - cpu_l2cache_wbinv_range(va, PAGE_SIZE); -#endif + pmap_l2cache_wbinv_range(va, pte & L2_S_FRAME, PAGE_SIZE); if ((pte & L2_S_CACHE_MASK) != pte_l2_s_cache_mode_pt) { /* * Page tables must have the cache-mode set to @@ -2121,6 +2125,7 @@ pmap_kremove(vm_offset_t va) cpu_tlb_flushD_SE(va); cpu_cpwait(); *pte = 0; + PTE_SYNC(pte); } } @@ -2387,11 +2392,7 @@ pmap_change_attr(vm_offset_t sva, vm_size_t len, int mode) pte = *ptep &~ L2_S_CACHE_MASK; cpu_idcache_wbinv_range(tmpva, PAGE_SIZE); -#ifdef ARM_L2_PIPT - cpu_l2cache_wbinv_range(pte & L2_S_FRAME, PAGE_SIZE); -#else - cpu_l2cache_wbinv_range(tmpva, PAGE_SIZE); -#endif + pmap_l2cache_wbinv_range(tmpva, pte & L2_S_FRAME, PAGE_SIZE); *ptep = pte; cpu_tlb_flushID_SE(tmpva); @@ -2754,6 +2755,9 @@ do_l2b_alloc: else if (PV_BEEN_REFD(oflags)) cpu_tlb_flushD_SE(va); } + + if ((pmap != pmap_kernel()) && (pmap == &curproc->p_vmspace->vm_pmap)) + cpu_icache_sync_range(va, PAGE_SIZE); } /* @@ -3197,6 +3201,16 @@ pmap_zero_page_gen(vm_page_t pg, int off, int size) else bzero_page(cdstp); + /* + * Although aliasing is not possible if we use + * cdstp temporary mappings with memory that + * will be mapped later as non-cached or with write-through + * caches we might end up overwriting it when calling wbinv_all + * So make sure caches are clean after copy operation + */ + cpu_idcache_wbinv_range(cdstp, size); + pmap_l2cache_wbinv_range(cdstp, phys, size); + mtx_unlock(&cmtx); } @@ -3276,12 +3290,23 @@ pmap_copy_page_generic(vm_paddr_t src, vm_paddr_t dst) *cdst_pte = L2_S_PROTO | dst | pte_l2_s_cache_mode; pmap_set_prot(cdst_pte, VM_PROT_READ | VM_PROT_WRITE, 0); PTE_SYNC(cdst_pte); + cpu_tlb_flushD_SE(csrcp); cpu_tlb_flushD_SE(cdstp); cpu_cpwait(); + /* + * Although aliasing is not possible if we use + * cdstp temporary mappings with memory that + * will be mapped later as non-cached or with write-through + * caches we might end up overwriting it when calling wbinv_all + * So make sure caches are clean after copy operation + */ bcopy_page(csrcp, cdstp); + cpu_idcache_wbinv_range(cdstp, PAGE_SIZE); + pmap_l2cache_wbinv_range(cdstp, dst, PAGE_SIZE); + mtx_unlock(&cmtx); } diff --git a/sys/arm/broadcom/bcm2835/bcm2835_fb.c b/sys/arm/broadcom/bcm2835/bcm2835_fb.c index e8b2534..35343c8 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_fb.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_fb.c @@ -891,7 +891,7 @@ bcmfb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) + (sc->depth/8) * (col + sc->xmargin); fg = a & 0xf ; - bg = (a >> 8) & 0xf; + bg = (a >> 4) & 0xf; for (i = 0; i < BCMFB_FONT_HEIGHT; i++) { for (j = 0, k = 7; j < 8; j++, k--) { diff --git a/sys/arm/broadcom/bcm2835/bcm2835_machdep.c b/sys/arm/broadcom/bcm2835/bcm2835_machdep.c index 6baa8dd..7308c0f 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_machdep.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_machdep.c @@ -78,6 +78,25 @@ initarm_gpio_init(void) void initarm_late_init(void) { + phandle_t system; + pcell_t cells[2]; + int len; + + /* + * It seems there is no way to let syscons framework know + * that framebuffer resolution has changed. So just try + * to fetch data from FDT and go with defaults if failed + */ + system = OF_finddevice("/system"); + if (system != 0) { + len = OF_getprop(system, "linux,serial", &cells, sizeof(cells)); + if (len > 0) + board_set_serial(fdt64_to_cpu(*((uint64_t *)cells))); + + len = OF_getprop(system, "linux,revision", &cells, sizeof(cells)); + if (len > 0) + board_set_revision(fdt32_to_cpu(*((uint32_t *)cells))); + } } #define FDT_DEVMAP_MAX (2) // FIXME diff --git a/sys/arm/conf/BEAGLEBONE b/sys/arm/conf/BEAGLEBONE index 2874dfd..1481d92 100644 --- a/sys/arm/conf/BEAGLEBONE +++ b/sys/arm/conf/BEAGLEBONE @@ -62,11 +62,11 @@ options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed # NFS support #options NFSCL -#options NFSSERVER #Network Filesystem Server -#options NFSCLIENT #Network Filesystem Client +#options NFSD +#options NFSLOCKD # Uncomment this for NFS root -#options NFS_ROOT #NFS usable as /, requires NFSCLIENT +#options NFS_ROOT #NFS usable as /, requires NFSCL #options BOOTP_NFSROOT #options BOOTP_COMPAT #options BOOTP diff --git a/sys/arm/include/atomic.h b/sys/arm/include/atomic.h index 1a96176..4862453 100644 --- a/sys/arm/include/atomic.h +++ b/sys/arm/include/atomic.h @@ -47,9 +47,25 @@ #include <machine/cpuconf.h> #endif -#define mb() -#define wmb() -#define rmb() +#if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__) +#define isb() __asm __volatile("isb" : : : "memory") +#define dsb() __asm __volatile("dsb" : : : "memory") +#define dmb() __asm __volatile("dmb" : : : "memory") +#elif defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__) || \ + defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6Z__) || \ + defined (__ARM_ARCH_6ZK__) +#define isb() __asm __volatile("mcr p15, 0, %0, c7, c5, 4" : : "r" (0) : "memory") +#define dsb() __asm __volatile("mcr p15, 0, %0, c7, c10, 4" : : "r" (0) : "memory") +#define dmb() __asm __volatile("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory") +#else +#define isb() +#define dsb() +#define dmb() +#endif + +#define mb() dmb() +#define wmb() dmb() +#define rmb() dmb() #ifndef I32_bit #define I32_bit (1 << 7) /* IRQ disable */ diff --git a/sys/arm/include/machdep.h b/sys/arm/include/machdep.h index 8ea5e2f..f50cde8 100644 --- a/sys/arm/include/machdep.h +++ b/sys/arm/include/machdep.h @@ -37,6 +37,10 @@ void initarm_gpio_init(void); void initarm_late_init(void); int platform_devmap_init(void); +/* Board-specific attributes */ +void board_set_serial(uint64_t); +void board_set_revision(uint32_t); + /* Needs to be initialised by platform_devmap_init */ extern const struct pmap_devmap *pmap_devmap_bootstrap_table; diff --git a/sys/arm/include/pl310.h b/sys/arm/include/pl310.h index 26f6c60..a3c42d8 100644 --- a/sys/arm/include/pl310.h +++ b/sys/arm/include/pl310.h @@ -131,6 +131,7 @@ struct pl310_softc { void* sc_irq_h; int sc_enabled; struct mtx sc_mtx; + u_int sc_rtl_revision; }; /** diff --git a/sys/arm/include/pmap.h b/sys/arm/include/pmap.h index da4571d..4f7566e 100644 --- a/sys/arm/include/pmap.h +++ b/sys/arm/include/pmap.h @@ -61,7 +61,7 @@ #else #define PTE_NOCACHE 1 #endif -#define PTE_CACHE 4 +#define PTE_CACHE 6 #define PTE_DEVICE 2 #define PTE_PAGETABLE 4 #else diff --git a/sys/arm/ti/cpsw/if_cpsw.c b/sys/arm/ti/cpsw/if_cpsw.c index 80cbe73..a47c131 100644 --- a/sys/arm/ti/cpsw/if_cpsw.c +++ b/sys/arm/ti/cpsw/if_cpsw.c @@ -98,7 +98,7 @@ static int cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data); static int cpsw_init_slot_lists(struct cpsw_softc *sc); static void cpsw_free_slot(struct cpsw_softc *sc, struct cpsw_slot *slot); static void cpsw_fill_rx_queue_locked(struct cpsw_softc *sc); -static void cpsw_watchdog(struct cpsw_softc *sc); +static void cpsw_tx_watchdog(struct cpsw_softc *sc); static void cpsw_intr_rx_thresh(void *arg); static void cpsw_intr_rx(void *arg); @@ -716,34 +716,24 @@ cpsw_start_locked(struct ifnet *ifp) if (STAILQ_EMPTY(&newslots)) return; - /* Attach new segments to the hardware TX queue. */ + /* Attach the list of new buffers to the hardware TX queue. */ prev_slot = STAILQ_LAST(&sc->tx_active, cpsw_slot, next); first_new_slot = STAILQ_FIRST(&newslots); STAILQ_CONCAT(&sc->tx_active, &newslots); if (prev_slot == NULL) { /* Start the TX queue fresh. */ cpsw_write_4(CPSW_CPDMA_TX_HDP(0), - cpsw_cpdma_txbd_paddr(first_new_slot->index)); + cpsw_cpdma_txbd_paddr(first_new_slot->index)); } else { - /* Add packets to current queue. */ - /* Race: The hardware might have sent the last packet - * on the queue and stopped the transmitter just - * before we got here. In that case, this is a no-op, - * but it also means there's a TX interrupt waiting - * to be processed as soon as we release the lock here. - * That TX interrupt can detect and recover from this - * situation; see cpsw_intr_tx_locked. - */ + /* Add buffers to end of current queue. */ cpsw_cpdma_write_txbd_next(prev_slot->index, cpsw_cpdma_txbd_paddr(first_new_slot->index)); + /* If underrun, restart queue. */ + if (cpsw_cpdma_read_txbd_flags(prev_slot->index) & CPDMA_BD_EOQ) + cpsw_write_4(CPSW_CPDMA_TX_HDP(0), + cpsw_cpdma_txbd_paddr(first_new_slot->index)); } - /* If tx_retires hasn't changed, then we may have - lost a TX interrupt, so let the timer tick. */ sc->tx_enqueues += enqueued; - if (sc->tx_retires_at_wd_reset != sc->tx_retires) { - sc->tx_retires_at_wd_reset = sc->tx_retires; - sc->wd_timer = 5; - } sc->tx_queued += enqueued; if (sc->tx_queued > sc->tx_max_queued) { sc->tx_max_queued = sc->tx_queued; @@ -771,7 +761,6 @@ cpsw_stop_locked(struct cpsw_softc *sc) /* Stop tick engine */ callout_stop(&sc->wd_callout); - sc->wd_timer = 0; /* Wait for hardware to clear pending ops. */ CPSW_GLOBAL_UNLOCK(sc); @@ -1098,14 +1087,10 @@ cpsw_fill_rx_queue_locked(struct cpsw_softc *sc) cpsw_write_4(CPSW_CPDMA_RX_HDP(0), cpsw_cpdma_rxbd_paddr(next_slot->index)); } else { - /* Extend an existing RX queue. */ + /* Add buffers to end of current queue. */ cpsw_cpdma_write_rxbd_next(prev_slot->index, cpsw_cpdma_rxbd_paddr(next_slot->index)); - /* XXX Order matters: Previous write must complete - before next read begins in order to avoid an - end-of-queue race. I think bus_write and bus_read have - sufficient barriers built-in to ensure this. XXX */ - /* If old RX queue was stopped, restart it. */ + /* If underrun, restart queue. */ if (cpsw_cpdma_read_rxbd_flags(prev_slot->index) & CPDMA_BD_EOQ) { cpsw_write_4(CPSW_CPDMA_RX_HDP(0), cpsw_cpdma_rxbd_paddr(next_slot->index)); @@ -1177,15 +1162,8 @@ cpsw_intr_tx_locked(void *arg) /* Tell hardware the last item we dequeued. */ cpsw_write_4(CPSW_CPDMA_TX_CP(0), cpsw_cpdma_txbd_paddr(last_slot->index)); - /* If transmitter stopped and there's more, restart it. */ - /* This resolves the race described in tx_start above. */ - if ((last_flags & CPDMA_BD_EOQ) && (slot != NULL)) { - cpsw_write_4(CPSW_CPDMA_TX_HDP(0), - cpsw_cpdma_txbd_paddr(slot->index)); - } sc->tx_retires += retires; sc->tx_queued -= retires; - sc->wd_timer = 0; } } @@ -1206,7 +1184,7 @@ cpsw_tick(void *msc) struct cpsw_softc *sc = msc; /* Check for TX timeout */ - cpsw_watchdog(sc); + cpsw_tx_watchdog(sc); mii_tick(sc->mii); @@ -1222,21 +1200,28 @@ cpsw_tick(void *msc) } static void -cpsw_watchdog(struct cpsw_softc *sc) +cpsw_tx_watchdog(struct cpsw_softc *sc) { - struct ifnet *ifp; + struct ifnet *ifp = sc->ifp; - ifp = sc->ifp; CPSW_GLOBAL_LOCK(sc); - if (sc->wd_timer == 0 || --sc->wd_timer) { - CPSW_GLOBAL_UNLOCK(sc); - return; + if (sc->tx_retires > sc->tx_retires_at_last_tick) { + sc->tx_wd_timer = 0; /* Stuff got sent. */ + } else if (sc->tx_queued == 0) { + sc->tx_wd_timer = 0; /* Nothing to send. */ + } else { + /* There was something to send but we didn't. */ + ++sc->tx_wd_timer; + if (sc->tx_wd_timer > 3) { + sc->tx_wd_timer = 0; + ifp->if_oerrors++; + if_printf(ifp, "watchdog timeout\n"); + cpsw_stop_locked(sc); + cpsw_init_locked(sc); + CPSW_DEBUGF(("watchdog reset completed\n")); + } } - - ifp->if_oerrors++; - if_printf(ifp, "watchdog timeout\n"); - cpsw_stop_locked(sc); - cpsw_init_locked(sc); + sc->tx_retires_at_last_tick = sc->tx_retires; CPSW_GLOBAL_UNLOCK(sc); } @@ -1381,7 +1366,7 @@ cpsw_init_locked(void *arg) /* Activate network interface */ sc->rx_running = 1; sc->tx_running = 1; - sc->wd_timer = 0; + sc->tx_wd_timer = 0; callout_reset(&sc->wd_callout, hz, cpsw_tick, sc); sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; diff --git a/sys/arm/ti/cpsw/if_cpswvar.h b/sys/arm/ti/cpsw/if_cpswvar.h index 3cae489..35024c6 100644 --- a/sys/arm/ti/cpsw/if_cpswvar.h +++ b/sys/arm/ti/cpsw/if_cpswvar.h @@ -63,7 +63,7 @@ struct cpsw_softc { int cpsw_media_status; struct callout wd_callout; - int wd_timer; + int tx_wd_timer; bus_dma_tag_t mbuf_dtag; @@ -82,7 +82,7 @@ struct cpsw_softc { /* Statistics */ uint32_t tx_enqueues; /* total TX bufs added to queue */ uint32_t tx_retires; /* total TX bufs removed from queue */ - uint32_t tx_retires_at_wd_reset; /* used for watchdog */ + uint32_t tx_retires_at_last_tick; /* used for watchdog */ /* Note: tx_queued != tx_enqueues - tx_retires At driver reset, packets can be discarded from TX queue without being retired. */ diff --git a/sys/arm/ti/ti_cpuid.c b/sys/arm/ti/ti_cpuid.c index 16de8aa..89046c4 100644 --- a/sys/arm/ti/ti_cpuid.c +++ b/sys/arm/ti/ti_cpuid.c @@ -129,27 +129,75 @@ omap4_get_revision(void) switch (hawkeye) { case 0xB852: - if (revision == 0) + switch (revision) { + case 0: chip_revision = OMAP4430_REV_ES1_0; - else - chip_revision = OMAP4430_REV_ES2_0; + break; + case 1: + chip_revision = OMAP4430_REV_ES2_1; + break; + default: + chip_revision = OMAP4430_REV_UNKNOWN; + break; + } break; + case 0xB95C: - if (revision == 3) + switch (revision) { + case 3: chip_revision = OMAP4430_REV_ES2_1; - else if (revision == 4) + break; + case 4: chip_revision = OMAP4430_REV_ES2_2; - else + break; + case 6: chip_revision = OMAP4430_REV_ES2_3; + break; + default: + chip_revision = OMAP4430_REV_UNKNOWN; + break; + } break; + + case 0xB94E: + switch (revision) { + case 0: + chip_revision = OMAP4460_REV_ES1_0; + break; + case 2: + chip_revision = OMAP4460_REV_ES1_1; + break; + default: + chip_revision = OMAP4460_REV_UNKNOWN; + break; + } + break; + + case 0xB975: + switch (revision) { + case 0: + chip_revision = OMAP4470_REV_ES1_0; + break; + default: + chip_revision = OMAP4470_REV_UNKNOWN; + break; + } + break; + default: /* Default to the latest revision if we can't determine type */ - chip_revision = OMAP4430_REV_ES2_3; + chip_revision = OMAP_UNKNOWN_DEV; break; } - printf("Texas Instruments OMAP%04x Processor, Revision ES%u.%u\n", - OMAP_REV_DEVICE(chip_revision), OMAP_REV_MAJOR(chip_revision), - OMAP_REV_MINOR(chip_revision)); + if (chip_revision != OMAP_UNKNOWN_DEV) { + printf("Texas Instruments OMAP%04x Processor, Revision ES%u.%u\n", + OMAP_REV_DEVICE(chip_revision), OMAP_REV_MAJOR(chip_revision), + OMAP_REV_MINOR(chip_revision)); + } + else { + printf("Texas Instruments unknown OMAP chip: %04x, rev %d\n", + hawkeye, revision); + } } /** diff --git a/sys/arm/ti/ti_cpuid.h b/sys/arm/ti/ti_cpuid.h index f68f54c..6efbf32 100644 --- a/sys/arm/ti/ti_cpuid.h +++ b/sys/arm/ti/ti_cpuid.h @@ -30,34 +30,46 @@ #ifndef _TI_CPUID_H_ #define _TI_CPUID_H_ -#define OMAP_MAKEREV(d, a, b, c) \ +#define OMAP_MAKEREV(d, a, b, c) \ (uint32_t)(((d) << 16) | (((a) & 0xf) << 8) | (((b) & 0xf) << 4) | ((c) & 0xf)) -#define OMAP_REV_DEVICE(x) (((x) >> 16) & 0xffff) -#define OMAP_REV_MAJOR(x) (((x) >> 8) & 0xf) -#define OMAP_REV_MINOR(x) (((x) >> 4) & 0xf) -#define OMAP_REV_MINOR_MINOR(x) (((x) >> 0) & 0xf) +#define OMAP_REV_DEVICE(x) (((x) >> 16) & 0xffff) +#define OMAP_REV_MAJOR(x) (((x) >> 8) & 0xf) +#define OMAP_REV_MINOR(x) (((x) >> 4) & 0xf) +#define OMAP_REV_MINOR_MINOR(x) (((x) >> 0) & 0xf) #define OMAP3350_DEV 0x3530 -#define OMAP3350_REV_ES1_0 OMAP_MAKEREV(OMAP3350_DEV, 1, 0, 0) -#define OMAP3530_REV_ES2_0 OMAP_MAKEREV(OMAP3350_DEV, 2, 0, 0) -#define OMAP3530_REV_ES2_1 OMAP_MAKEREV(OMAP3350_DEV, 2, 1, 0) -#define OMAP3530_REV_ES3_0 OMAP_MAKEREV(OMAP3350_DEV, 3, 0, 0) -#define OMAP3530_REV_ES3_1 OMAP_MAKEREV(OMAP3350_DEV, 3, 1, 0) -#define OMAP3530_REV_ES3_1_2 OMAP_MAKEREV(OMAP3350_DEV, 3, 1, 2) +#define OMAP3350_REV_ES1_0 OMAP_MAKEREV(OMAP3350_DEV, 1, 0, 0) +#define OMAP3530_REV_ES2_0 OMAP_MAKEREV(OMAP3350_DEV, 2, 0, 0) +#define OMAP3530_REV_ES2_1 OMAP_MAKEREV(OMAP3350_DEV, 2, 1, 0) +#define OMAP3530_REV_ES3_0 OMAP_MAKEREV(OMAP3350_DEV, 3, 0, 0) +#define OMAP3530_REV_ES3_1 OMAP_MAKEREV(OMAP3350_DEV, 3, 1, 0) +#define OMAP3530_REV_ES3_1_2 OMAP_MAKEREV(OMAP3350_DEV, 3, 1, 2) #define OMAP4430_DEV 0x4430 -#define OMAP4430_REV_ES1_0 OMAP_MAKEREV(OMAP4430_DEV, 1, 0, 0) -#define OMAP4430_REV_ES2_0 OMAP_MAKEREV(OMAP4430_DEV, 2, 0, 0) -#define OMAP4430_REV_ES2_1 OMAP_MAKEREV(OMAP4430_DEV, 2, 1, 0) -#define OMAP4430_REV_ES2_2 OMAP_MAKEREV(OMAP4430_DEV, 2, 2, 0) -#define OMAP4430_REV_ES2_3 OMAP_MAKEREV(OMAP4430_DEV, 2, 3, 0) +#define OMAP4430_REV_ES1_0 OMAP_MAKEREV(OMAP4430_DEV, 1, 0, 0) +#define OMAP4430_REV_ES2_0 OMAP_MAKEREV(OMAP4430_DEV, 2, 0, 0) +#define OMAP4430_REV_ES2_1 OMAP_MAKEREV(OMAP4430_DEV, 2, 1, 0) +#define OMAP4430_REV_ES2_2 OMAP_MAKEREV(OMAP4430_DEV, 2, 2, 0) +#define OMAP4430_REV_ES2_3 OMAP_MAKEREV(OMAP4430_DEV, 2, 3, 0) +#define OMAP4430_REV_UNKNOWN OMAP_MAKEREV(OMAP4430_DEV, 9, 9, 9) -#define AM335X_DEVREV(x) ((x) >> 28) +#define OMAP4460_DEV 0x4460 +#define OMAP4460_REV_ES1_0 OMAP_MAKEREV(OMAP4460_DEV, 1, 0, 0) +#define OMAP4460_REV_ES1_1 OMAP_MAKEREV(OMAP4460_DEV, 1, 1, 0) +#define OMAP4460_REV_UNKNOWN OMAP_MAKEREV(OMAP4460_DEV, 9, 9, 9) -#define CHIP_OMAP_3 0 -#define CHIP_OMAP_4 1 -#define CHIP_AM335X 2 +#define OMAP4470_DEV 0x4470 +#define OMAP4470_REV_ES1_0 OMAP_MAKEREV(OMAP4470_DEV, 1, 0, 0) +#define OMAP4470_REV_UNKNOWN OMAP_MAKEREV(OMAP4470_DEV, 9, 9, 9) + +#define OMAP_UNKNOWN_DEV OMAP_MAKEREV(0x9999, 9, 9, 9) + +#define AM335X_DEVREV(x) ((x) >> 28) + +#define CHIP_OMAP_3 0 +#define CHIP_OMAP_4 1 +#define CHIP_AM335X 2 static __inline int ti_chip(void) { diff --git a/sys/arm/versatile/versatile_clcd.c b/sys/arm/versatile/versatile_clcd.c index 53226ff..34d29fa 100644 --- a/sys/arm/versatile/versatile_clcd.c +++ b/sys/arm/versatile/versatile_clcd.c @@ -892,7 +892,7 @@ versatilefb_putc(video_adapter_t *adp, vm_offset_t off, uint8_t c, uint8_t a) + (sc->depth/8) * (col + sc->xmargin); fg = a & 0xf ; - bg = (a >> 8) & 0xf; + bg = (a >> 4) & 0xf; for (i = 0; i < VERSATILE_FONT_HEIGHT; i++) { for (j = 0, k = 7; j < 8; j++, k--) { diff --git a/sys/boot/common/interp_forth.c b/sys/boot/common/interp_forth.c index ef4265e..f89bc41 100644 --- a/sys/boot/common/interp_forth.c +++ b/sys/boot/common/interp_forth.c @@ -53,8 +53,8 @@ extern char bootprog_rev[]; /* * FreeBSD loader default dictionary cells */ -#ifndef BF_DICTSIZE -#define BF_DICTSIZE 10000 +#ifndef BF_DICTSIZE +#define BF_DICTSIZE 10000 #endif /* @@ -247,6 +247,7 @@ bf_init(void) char create_buf[41]; /* 31 characters-long builtins */ int fd; + bf_sys = ficlInitSystem(BF_DICTSIZE); bf_vm = ficlNewVM(bf_sys); diff --git a/sys/conf/options.mips b/sys/conf/options.mips index a86a749..2f27206 100644 --- a/sys/conf/options.mips +++ b/sys/conf/options.mips @@ -73,6 +73,7 @@ MAXMEM opt_global.h # OCTEON_MODEL opt_cvmx.h OCTEON_VENDOR_LANNER opt_cvmx.h +OCTEON_VENDOR_UBIQUITI opt_cvmx.h OCTEON_VENDOR_RADISYS opt_cvmx.h OCTEON_BOARD_CAPK_0100ND opt_cvmx.h diff --git a/sys/contrib/octeon-sdk/cvmx-app-init.h b/sys/contrib/octeon-sdk/cvmx-app-init.h index a986814..605f43e 100644 --- a/sys/contrib/octeon-sdk/cvmx-app-init.h +++ b/sys/contrib/octeon-sdk/cvmx-app-init.h @@ -299,6 +299,9 @@ enum cvmx_board_types_enum { CVMX_BOARD_TYPE_CUST_LANNER_MR320= 20002, CVMX_BOARD_TYPE_CUST_LANNER_MR321X=20007, #endif +#if defined(OCTEON_VENDOR_UBIQUITI) + CVMX_BOARD_TYPE_CUST_UBIQUITI_E100=20002, +#endif #if defined(OCTEON_VENDOR_RADISYS) CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE=20002, #endif @@ -426,6 +429,9 @@ static inline const char *cvmx_board_type_to_string(enum cvmx_board_types_enum t ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_LANNER_MR320) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_LANNER_MR321X) #endif +#if defined(OCTEON_VENDOR_UBIQUITI) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_UBIQUITI_E100) +#endif #if defined(OCTEON_VENDOR_RADISYS) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE) #endif diff --git a/sys/contrib/octeon-sdk/cvmx-helper-board.c b/sys/contrib/octeon-sdk/cvmx-helper-board.c index deb6018..8d2b0bd 100644 --- a/sys/contrib/octeon-sdk/cvmx-helper-board.c +++ b/sys/contrib/octeon-sdk/cvmx-helper-board.c @@ -592,6 +592,12 @@ int cvmx_helper_board_get_mii_address(int ipd_port) return -1; } #endif +#if defined(OCTEON_VENDOR_UBIQUITI) + case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100: + if (ipd_port > 2) + return -1; + return (7 - ipd_port); +#endif #if defined(OCTEON_VENDOR_RADISYS) case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE: /* No MII. */ @@ -1463,6 +1469,9 @@ cvmx_helper_board_usb_clock_types_t __cvmx_helper_board_usb_get_clock_type(void) case CVMX_BOARD_TYPE_CUST_LANNER_MR320: case CVMX_BOARD_TYPE_CUST_LANNER_MR321X: #endif +#if defined(OCTEON_VENDOR_UBIQUITI) + case CVMX_BOARD_TYPE_CUST_UBIQUITI_E100: +#endif #if defined(OCTEON_BOARD_CAPK_0100ND) case CVMX_BOARD_TYPE_CN3010_EVB_HS5: #endif diff --git a/sys/dev/ath/if_ath_rx.c b/sys/dev/ath/if_ath_rx.c index 543ba43..78f19e2 100644 --- a/sys/dev/ath/if_ath_rx.c +++ b/sys/dev/ath/if_ath_rx.c @@ -423,7 +423,21 @@ ath_rx_tap(struct ifnet *ifp, struct mbuf *m, sc->sc_rx_th.wr_flags = sc->sc_hwmap[rix].rxflags; #ifdef AH_SUPPORT_AR5416 sc->sc_rx_th.wr_chan_flags &= ~CHAN_HT; - if (sc->sc_rx_th.wr_rate & IEEE80211_RATE_MCS) { /* HT rate */ + if (rs->rs_status & HAL_RXERR_PHY) { + struct ieee80211com *ic = ifp->if_l2com; + + /* + * PHY error - make sure the channel flags + * reflect the actual channel configuration, + * not the received frame. + */ + if (IEEE80211_IS_CHAN_HT40U(ic->ic_curchan)) + sc->sc_rx_th.wr_chan_flags |= CHAN_HT40U; + else if (IEEE80211_IS_CHAN_HT40D(ic->ic_curchan)) + sc->sc_rx_th.wr_chan_flags |= CHAN_HT40D; + else if (IEEE80211_IS_CHAN_HT20(ic->ic_curchan)) + sc->sc_rx_th.wr_chan_flags |= CHAN_HT20; + } else if (sc->sc_rx_th.wr_rate & IEEE80211_RATE_MCS) { /* HT rate */ struct ieee80211com *ic = ifp->if_l2com; if ((rs->rs_flags & HAL_RX_2040) == 0) @@ -435,6 +449,7 @@ ath_rx_tap(struct ifnet *ifp, struct mbuf *m, if ((rs->rs_flags & HAL_RX_GI) == 0) sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI; } + #endif sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(sc, rs->rs_tstamp, tsf)); if (rs->rs_status & HAL_RXERR_CRC) diff --git a/sys/dev/ath/if_ath_spectral.c b/sys/dev/ath/if_ath_spectral.c index 12fb87a7..0dc0114 100644 --- a/sys/dev/ath/if_ath_spectral.c +++ b/sys/dev/ath/if_ath_spectral.c @@ -82,13 +82,20 @@ struct ath_spectral_state { */ /* - * Attach DFS to the given interface + * Attach spectral to the given interface */ int ath_spectral_attach(struct ath_softc *sc) { struct ath_spectral_state *ss; + /* + * If spectral isn't supported, don't error - just + * quietly complete. + */ + if (! ath_hal_spectral_supported(sc->sc_ah)) + return (0); + ss = malloc(sizeof(struct ath_spectral_state), M_TEMP, M_WAITOK | M_ZERO); @@ -106,11 +113,15 @@ ath_spectral_attach(struct ath_softc *sc) } /* - * Detach DFS from the given interface + * Detach spectral from the given interface */ int ath_spectral_detach(struct ath_softc *sc) { + + if (! ath_hal_spectral_supported(sc->sc_ah)) + return (0); + if (sc->sc_spectral != NULL) { free(sc->sc_spectral, M_TEMP); } @@ -148,6 +159,9 @@ ath_ioctl_spectral(struct ath_softc *sc, struct ath_diag *ad) HAL_SPECTRAL_PARAM *pe; struct ath_spectral_state *ss = sc->sc_spectral; + if (! ath_hal_spectral_supported(sc->sc_ah)) + return (EINVAL); + if (ad->ad_id & ATH_DIAG_IN) { /* * Copy in data. diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 12252ed..2e170a3 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -1303,6 +1303,8 @@ void ath_intr(void *); #define ath_hal_get_chan_ext_busy(_ah) \ ((*(_ah)->ah_get11nExtBusy)((_ah))) +#define ath_hal_spectral_supported(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_SPECTRAL_SCAN, 0, NULL) == HAL_OK) #define ath_hal_spectral_get_config(_ah, _p) \ ((*(_ah)->ah_spectralGetConfig)((_ah), (_p))) #define ath_hal_spectral_configure(_ah, _p) \ diff --git a/sys/dev/nvme/nvme_test.c b/sys/dev/nvme/nvme_test.c index 3d04ea5..4177227 100644 --- a/sys/dev/nvme/nvme_test.c +++ b/sys/dev/nvme/nvme_test.c @@ -287,10 +287,10 @@ nvme_ns_test(struct nvme_namespace *ns, u_long cmd, caddr_t arg) for (i = 0; i < io_test->num_threads; i++) #if __FreeBSD_version >= 800004 kthread_add(fn, io_test_internal, - curproc, NULL, 0, 0, "nvme_io_test[%d]", i); + NULL, NULL, 0, 0, "nvme_io_test[%d]", i); #else kthread_create(fn, io_test_internal, - curproc, 0, 0, "nvme_io_test[%d]", i); + NULL, 0, 0, "nvme_io_test[%d]", i); #endif tsleep(io_test_internal, 0, "nvme_test", io_test->time * 2 * hz); diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 7290de6..7632e73 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -244,7 +244,7 @@ static const struct pci_quirk pci_quirks[] = { * but support MSI just fine. QEMU uses the Intel 82440. */ { 0x12378086, PCI_QUIRK_ENABLE_MSI_VM, 0, 0 }, - { 0x12751275, PCI_QUIRK_ENABLE_MSI_VM, 0, 0 }, /* BHyVe */ + { 0x12751275, PCI_QUIRK_ENABLE_MSI_VM, 0, 0 }, /* bhyve */ /* * HPET MMIO base address may appear in Bar1 for AMD SB600 SMBus diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c index f32e89a..c62f781 100644 --- a/sys/dev/usb/controller/xhci.c +++ b/sys/dev/usb/controller/xhci.c @@ -1440,26 +1440,37 @@ void xhci_interrupt(struct xhci_softc *sc) { uint32_t status; - uint32_t temp; + uint32_t iman; USB_BUS_LOCK(&sc->sc_bus); status = XREAD4(sc, oper, XHCI_USBSTS); + if (status == 0) + goto done; /* acknowledge interrupts */ XWRITE4(sc, oper, XHCI_USBSTS, status); - temp = XREAD4(sc, runt, XHCI_IMAN(0)); + DPRINTFN(16, "real interrupt (status=0x%08x)\n", status); + + if (status & XHCI_STS_EINT) { - /* acknowledge pending event */ + /* acknowledge pending event */ + iman = XREAD4(sc, runt, XHCI_IMAN(0)); - XWRITE4(sc, runt, XHCI_IMAN(0), temp); + /* reset interrupt */ + XWRITE4(sc, runt, XHCI_IMAN(0), iman); + + DPRINTFN(16, "real interrupt (iman=0x%08x)\n", iman); + + /* check for event(s) */ + xhci_interrupt_poll(sc); + } - DPRINTFN(16, "real interrupt (sts=0x%08x, " - "iman=0x%08x)\n", status, temp); + if (status & (XHCI_STS_PCD | XHCI_STS_HCH | + XHCI_STS_HSE | XHCI_STS_HCE)) { - if (status != 0) { if (status & XHCI_STS_PCD) { xhci_root_intr(sc); } @@ -1479,9 +1490,7 @@ xhci_interrupt(struct xhci_softc *sc) __FUNCTION__); } } - - xhci_interrupt_poll(sc); - +done: USB_BUS_UNLOCK(&sc->sc_bus); } diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c index 3d2577f..3940636 100644 --- a/sys/dev/usb/wlan/if_run.c +++ b/sys/dev/usb/wlan/if_run.c @@ -2019,7 +2019,8 @@ run_key_set_cb(void *arg) wcid = 0; /* NB: update WCID0 for group keys */ base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix); } else { - wcid = RUN_AID2WCID(associd); + wcid = (vap->iv_opmode == IEEE80211_M_STA) ? + 1 : RUN_AID2WCID(associd); base = RT2860_PKEY(wcid); } @@ -2374,9 +2375,12 @@ run_newassoc(struct ieee80211_node *ni, int isnew) struct run_softc *sc = ic->ic_ifp->if_softc; uint8_t rate; uint8_t ridx; - uint8_t wcid = RUN_AID2WCID(ni->ni_associd); + uint8_t wcid; int i, j; + wcid = (vap->iv_opmode == IEEE80211_M_STA) ? + 1 : RUN_AID2WCID(ni->ni_associd); + if (wcid > RT2870_WCID_MAX) { device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid); return; @@ -3044,8 +3048,12 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) txd->flags = qflags; txwi = (struct rt2860_txwi *)(txd + 1); txwi->xflags = xflags; - txwi->wcid = IEEE80211_IS_MULTICAST(wh->i_addr1) ? - 0 : RUN_AID2WCID(ni->ni_associd); + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { + txwi->wcid = 0; + } else { + txwi->wcid = (vap->iv_opmode == IEEE80211_M_STA) ? + 1 : RUN_AID2WCID(ni->ni_associd); + } /* clear leftover garbage bits */ txwi->flags = 0; txwi->txop = 0; diff --git a/sys/dev/xen/control/control.c b/sys/dev/xen/control/control.c index 63ece1e..18f42bb 100644 --- a/sys/dev/xen/control/control.c +++ b/sys/dev/xen/control/control.c @@ -125,7 +125,6 @@ __FBSDID("$FreeBSD$"); #include <sys/smp.h> #endif - #include <geom/geom.h> #include <machine/_inttypes.h> @@ -145,8 +144,6 @@ __FBSDID("$FreeBSD$"); #include <xen/xenbus/xenbusvar.h> -#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*(x))) - /*--------------------------- Forward Declarations --------------------------*/ /** Function signature for shutdown event handlers. */ typedef void (xctrl_shutdown_handler_t)(void); @@ -165,7 +162,7 @@ struct xctrl_shutdown_reason { }; /** Lookup table for shutdown event name to handler. */ -static struct xctrl_shutdown_reason xctrl_shutdown_reasons[] = { +static const struct xctrl_shutdown_reason xctrl_shutdown_reasons[] = { { "poweroff", xctrl_poweroff }, { "reboot", xctrl_reboot }, { "suspend", xctrl_suspend }, @@ -198,7 +195,6 @@ extern void xencons_resume(void); static void xctrl_suspend() { - u_int cpuid; int i, j, k, fpp; unsigned long max_pfn, start_info_mfn; @@ -207,6 +203,8 @@ xctrl_suspend() #ifdef SMP struct thread *td; cpuset_t map; + u_int cpuid; + /* * Bind us to CPU 0 and stop any other VCPUs. */ @@ -231,7 +229,7 @@ xctrl_suspend() mtx_lock(&Giant); if (DEVICE_SUSPEND(root_bus) != 0) { mtx_unlock(&Giant); - printf("xen_suspend: device_suspend failed\n"); + printf("%s: device_suspend failed\n", __func__); #ifdef SMP if (!CPU_EMPTY(&map)) restart_cpus(map); @@ -343,9 +341,9 @@ xctrl_suspend() * drivers need this. */ mtx_lock(&Giant); - if (DEVICE_SUSPEND(root_bus)) { + if (DEVICE_SUSPEND(root_bus) != 0) { mtx_unlock(&Giant); - printf("xen_suspend: device_suspend failed\n"); + printf("%s: device_suspend failed\n", __func__); return; } mtx_unlock(&Giant); @@ -396,8 +394,8 @@ xctrl_halt() static void xctrl_on_watch_event(struct xs_watch *watch, const char **vec, unsigned int len) { - struct xctrl_shutdown_reason *reason; - struct xctrl_shutdown_reason *last_reason; + const struct xctrl_shutdown_reason *reason; + const struct xctrl_shutdown_reason *last_reason; char *result; int error; int result_len; @@ -408,7 +406,7 @@ xctrl_on_watch_event(struct xs_watch *watch, const char **vec, unsigned int len) return; reason = xctrl_shutdown_reasons; - last_reason = reason + NUM_ELEMENTS(xctrl_shutdown_reasons); + last_reason = reason + nitems(xctrl_shutdown_reasons); while (reason < last_reason) { if (!strcmp(result, reason->name)) { @@ -511,10 +509,10 @@ static device_method_t xctrl_methods[] = { DEVMETHOD(device_attach, xctrl_attach), DEVMETHOD(device_detach, xctrl_detach), - { 0, 0 } + DEVMETHOD_END }; DEFINE_CLASS_0(xctrl, xctrl_driver, xctrl_methods, sizeof(struct xctrl_softc)); devclass_t xctrl_devclass; -DRIVER_MODULE(xctrl, xenstore, xctrl_driver, xctrl_devclass, 0, 0); +DRIVER_MODULE(xctrl, xenstore, xctrl_driver, xctrl_devclass, NULL, NULL); diff --git a/sys/dev/xen/evtchn/evtchn_dev.c b/sys/dev/xen/evtchn/evtchn_dev.c deleted file mode 100644 index 6925a22..0000000 --- a/sys/dev/xen/evtchn/evtchn_dev.c +++ /dev/null @@ -1,394 +0,0 @@ -/****************************************************************************** - * evtchn.c - * - * Xenolinux driver for receiving and demuxing event-channel signals. - * - * Copyright (c) 2004, K A Fraser - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/uio.h> -#include <sys/bus.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/selinfo.h> -#include <sys/poll.h> -#include <sys/conf.h> -#include <sys/fcntl.h> -#include <sys/ioccom.h> - -#include <machine/cpufunc.h> -#include <machine/intr_machdep.h> -#include <machine/xen-os.h> -#include <xen/xen_intr.h> -#include <machine/bus.h> -#include <sys/rman.h> -#include <machine/resource.h> -#include <machine/synch_bitops.h> - -#include <xen/hypervisor.h> - - -typedef struct evtchn_sotfc { - - struct selinfo ev_rsel; -} evtchn_softc_t; - - -#ifdef linuxcrap -/* NB. This must be shared amongst drivers if more things go in /dev/xen */ -static devfs_handle_t xen_dev_dir; -#endif - -/* Only one process may open /dev/xen/evtchn at any time. */ -static unsigned long evtchn_dev_inuse; - -/* Notification ring, accessed via /dev/xen/evtchn. */ - -#define EVTCHN_RING_SIZE 2048 /* 2048 16-bit entries */ - -#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1)) -static uint16_t *ring; -static unsigned int ring_cons, ring_prod, ring_overflow; - -/* Which ports is user-space bound to? */ -static uint32_t bound_ports[32]; - -/* Unique address for processes to sleep on */ -static void *evtchn_waddr = ˚ - -static struct mtx lock, upcall_lock; - -static d_read_t evtchn_read; -static d_write_t evtchn_write; -static d_ioctl_t evtchn_ioctl; -static d_poll_t evtchn_poll; -static d_open_t evtchn_open; -static d_close_t evtchn_close; - - -void -evtchn_device_upcall(int port) -{ - mtx_lock(&upcall_lock); - - mask_evtchn(port); - clear_evtchn(port); - - if ( ring != NULL ) { - if ( (ring_prod - ring_cons) < EVTCHN_RING_SIZE ) { - ring[EVTCHN_RING_MASK(ring_prod)] = (uint16_t)port; - if ( ring_cons == ring_prod++ ) { - wakeup(evtchn_waddr); - } - } - else { - ring_overflow = 1; - } - } - - mtx_unlock(&upcall_lock); -} - -static void -__evtchn_reset_buffer_ring(void) -{ - /* Initialise the ring to empty. Clear errors. */ - ring_cons = ring_prod = ring_overflow = 0; -} - -static int -evtchn_read(struct cdev *dev, struct uio *uio, int ioflag) -{ - int rc; - unsigned int count, c, p, sst = 0, bytes1 = 0, bytes2 = 0; - count = uio->uio_resid; - - count &= ~1; /* even number of bytes */ - - if ( count == 0 ) - { - rc = 0; - goto out; - } - - if ( count > PAGE_SIZE ) - count = PAGE_SIZE; - - for ( ; ; ) { - if ( (c = ring_cons) != (p = ring_prod) ) - break; - - if ( ring_overflow ) { - rc = EFBIG; - goto out; - } - - if (sst != 0) { - rc = EINTR; - goto out; - } - - /* PCATCH == check for signals before and after sleeping - * PWAIT == priority of waiting on resource - */ - sst = tsleep(evtchn_waddr, PWAIT|PCATCH, "evchwt", 10); - } - - /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ - if ( ((c ^ p) & EVTCHN_RING_SIZE) != 0 ) { - bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * sizeof(uint16_t); - bytes2 = EVTCHN_RING_MASK(p) * sizeof(uint16_t); - } - else { - bytes1 = (p - c) * sizeof(uint16_t); - bytes2 = 0; - } - - /* Truncate chunks according to caller's maximum byte count. */ - if ( bytes1 > count ) { - bytes1 = count; - bytes2 = 0; - } - else if ( (bytes1 + bytes2) > count ) { - bytes2 = count - bytes1; - } - - if ( uiomove(&ring[EVTCHN_RING_MASK(c)], bytes1, uio) || - ((bytes2 != 0) && uiomove(&ring[0], bytes2, uio))) - /* keeping this around as its replacement is not equivalent - * copyout(&ring[0], &buf[bytes1], bytes2) - */ - { - rc = EFAULT; - goto out; - } - - ring_cons += (bytes1 + bytes2) / sizeof(uint16_t); - - rc = bytes1 + bytes2; - - out: - - return rc; -} - -static int -evtchn_write(struct cdev *dev, struct uio *uio, int ioflag) -{ - int rc, i, count; - - count = uio->uio_resid; - - uint16_t *kbuf = (uint16_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); - - - if ( kbuf == NULL ) - return ENOMEM; - - count &= ~1; /* even number of bytes */ - - if ( count == 0 ) { - rc = 0; - goto out; - } - - if ( count > PAGE_SIZE ) - count = PAGE_SIZE; - - if ( uiomove(kbuf, count, uio) != 0 ) { - rc = EFAULT; - goto out; - } - - mtx_lock_spin(&lock); - for ( i = 0; i < (count/2); i++ ) - if ( test_bit(kbuf[i], &bound_ports[0]) ) - unmask_evtchn(kbuf[i]); - mtx_unlock_spin(&lock); - - rc = count; - - out: - free(kbuf, M_DEVBUF); - return rc; -} - -static int -evtchn_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg, - int mode, struct thread *td __unused) -{ - int rc = 0; - - mtx_lock_spin(&lock); - - switch ( cmd ) - { - case EVTCHN_RESET: - __evtchn_reset_buffer_ring(); - break; - case EVTCHN_BIND: - if ( !synch_test_and_set_bit((int)arg, &bound_ports[0]) ) - unmask_evtchn((int)arg); - else - rc = EINVAL; - break; - case EVTCHN_UNBIND: - if ( synch_test_and_clear_bit((int)arg, &bound_ports[0]) ) - mask_evtchn((int)arg); - else - rc = EINVAL; - break; - default: - rc = ENOSYS; - break; - } - - mtx_unlock_spin(&lock); - - return rc; -} - -static int -evtchn_poll(struct cdev *dev, int poll_events, struct thread *td) -{ - - evtchn_softc_t *sc; - unsigned int mask = POLLOUT | POLLWRNORM; - - sc = dev->si_drv1; - - if ( ring_cons != ring_prod ) - mask |= POLLIN | POLLRDNORM; - else if ( ring_overflow ) - mask = POLLERR; - else - selrecord(td, &sc->ev_rsel); - - - return mask; -} - - -static int -evtchn_open(struct cdev *dev, int flag, int otyp, struct thread *td) -{ - uint16_t *_ring; - - if (flag & O_NONBLOCK) - return EBUSY; - - if ( synch_test_and_set_bit(0, &evtchn_dev_inuse) ) - return EBUSY; - - if ( (_ring = (uint16_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK)) == NULL ) - return ENOMEM; - - mtx_lock_spin(&lock); - ring = _ring; - __evtchn_reset_buffer_ring(); - mtx_unlock_spin(&lock); - - - return 0; -} - -static int -evtchn_close(struct cdev *dev, int flag, int otyp, struct thread *td __unused) -{ - int i; - - mtx_lock_spin(&lock); - if (ring != NULL) { - free(ring, M_DEVBUF); - ring = NULL; - } - for ( i = 0; i < NR_EVENT_CHANNELS; i++ ) - if ( synch_test_and_clear_bit(i, &bound_ports[0]) ) - mask_evtchn(i); - mtx_unlock_spin(&lock); - - evtchn_dev_inuse = 0; - - return 0; -} - -static struct cdevsw evtchn_devsw = { - d_version: D_VERSION, - d_open: evtchn_open, - d_close: evtchn_close, - d_read: evtchn_read, - d_write: evtchn_write, - d_ioctl: evtchn_ioctl, - d_poll: evtchn_poll, - d_name: "evtchn", - d_flags: 0, -}; - - -/* XXX - if this device is ever supposed to support use by more than one process - * this global static will have to go away - */ -static struct cdev *evtchn_dev; - - - -static int -evtchn_init(void *dummy __unused) -{ - /* XXX I believe we don't need these leaving them here for now until we - * have some semblance of it working - */ - mtx_init(&upcall_lock, "evtchup", NULL, MTX_DEF); - - /* (DEVFS) create '/dev/misc/evtchn'. */ - evtchn_dev = make_dev(&evtchn_devsw, 0, UID_ROOT, GID_WHEEL, 0600, "xen/evtchn"); - - mtx_init(&lock, "evch", NULL, MTX_SPIN | MTX_NOWITNESS); - - evtchn_dev->si_drv1 = malloc(sizeof(evtchn_softc_t), M_DEVBUF, M_WAITOK); - bzero(evtchn_dev->si_drv1, sizeof(evtchn_softc_t)); - - /* XXX I don't think we need any of this rubbish */ -#if 0 - if ( err != 0 ) - { - printk(KERN_ALERT "Could not register /dev/misc/evtchn\n"); - return err; - } - - /* (DEVFS) create directory '/dev/xen'. */ - xen_dev_dir = devfs_mk_dir(NULL, "xen", NULL); - - /* (DEVFS) &link_dest[pos] == '../misc/evtchn'. */ - pos = devfs_generate_path(evtchn_miscdev.devfs_handle, - &link_dest[3], - sizeof(link_dest) - 3); - if ( pos >= 0 ) - strncpy(&link_dest[pos], "../", 3); - /* (DEVFS) symlink '/dev/xen/evtchn' -> '../misc/evtchn'. */ - (void)devfs_mk_symlink(xen_dev_dir, - "evtchn", - DEVFS_FL_DEFAULT, - &link_dest[pos], - &symlink_handle, - NULL); - - /* (DEVFS) automatically destroy the symlink with its destination. */ - devfs_auto_unregister(evtchn_miscdev.devfs_handle, symlink_handle); -#endif - printk("Event-channel device installed.\n"); - - return 0; -} - - -SYSINIT(evtchn_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, evtchn_init, NULL); - - diff --git a/sys/dev/xen/netfront/netfront.c b/sys/dev/xen/netfront/netfront.c index 856c988..88641e3 100644 --- a/sys/dev/xen/netfront/netfront.c +++ b/sys/dev/xen/netfront/netfront.c @@ -24,7 +24,6 @@ * SUCH DAMAGE. */ - #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -208,8 +207,6 @@ struct xn_chain_data { struct mbuf *xn_rx_chain[NET_RX_RING_SIZE+1]; }; -#define NUM_ELEMENTS(x) (sizeof(x)/sizeof(*x)) - struct net_device_stats { u_long rx_packets; /* total packets received */ @@ -244,7 +241,6 @@ struct net_device_stats }; struct netfront_info { - struct ifnet *xn_ifp; #if __FreeBSD_version >= 700000 struct lro_ctrl xn_lro; @@ -329,12 +325,6 @@ struct netfront_rx_info { /* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */ - - -/* - * Access macros for acquiring freeing slots in tx_skbs[]. - */ - static inline void add_id_to_freelist(struct mbuf **list, uintptr_t id) { @@ -517,7 +507,6 @@ netfront_resume(device_t dev) return (0); } - /* Common code used when first setting up, and when resuming. */ static int talk_to_backend(device_t dev, struct netfront_info *info) @@ -605,7 +594,6 @@ talk_to_backend(device_t dev, struct netfront_info *info) return err; } - static int setup_device(device_t dev, struct netfront_info *info) { @@ -794,7 +782,7 @@ netif_release_tx_bufs(struct netfront_info *np) add_id_to_freelist(np->tx_mbufs, i); np->xn_cdata.xn_tx_chain_cnt--; if (np->xn_cdata.xn_tx_chain_cnt < 0) { - panic("netif_release_tx_bufs: tx_chain_cnt must be >= 0"); + panic("%s: tx_chain_cnt must be >= 0", __func__); } m_free(m); } @@ -946,7 +934,6 @@ refill: reservation.domid = DOMID_SELF; if (!xen_feature(XENFEAT_auto_translated_physmap)) { - /* After all PTEs have been zapped, flush the TLB. */ sc->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL; @@ -958,15 +945,11 @@ refill: /* Zap PTEs and give away pages in one big multicall. */ (void)HYPERVISOR_multicall(sc->rx_mcl, i+1); - /* Check return status of HYPERVISOR_dom_mem_op(). */ - if (unlikely(sc->rx_mcl[i].result != i)) - panic("Unable to reduce memory reservation\n"); - } else { - if (HYPERVISOR_memory_op( - XENMEM_decrease_reservation, &reservation) - != i) - panic("Unable to reduce memory " - "reservation\n"); + if (unlikely(sc->rx_mcl[i].result != i || + HYPERVISOR_memory_op(XENMEM_decrease_reservation, + &reservation) != i)) + panic("%s: unable to reduce memory " + "reservation\n", __func__); } } else { wmb(); @@ -1169,8 +1152,8 @@ xn_txeof(struct netfront_info *np) ifp->if_opackets++; if (unlikely(gnttab_query_foreign_access( np->grant_tx_ref[id]) != 0)) { - panic("grant id %u still in use by the backend", - id); + panic("%s: grant id %u still in use by the " + "backend", __func__, id); } gnttab_end_foreign_access_ref( np->grant_tx_ref[id]); @@ -1210,7 +1193,6 @@ xn_txeof(struct netfront_info *np) netif_wake_queue(dev); #endif } - } static void @@ -1240,7 +1222,6 @@ xn_intr(void *xsc) xn_start(ifp); } - static void xennet_move_rx_slot(struct netfront_info *np, struct mbuf *m, grant_ref_t ref) @@ -1319,17 +1300,15 @@ xennet_get_responses(struct netfront_info *np, m0 = m = m_prev = xennet_get_rx_mbuf(np, *cons); - if (rx->flags & NETRXF_extra_info) { err = xennet_get_extras(np, extras, rp, cons); } - if (m0 != NULL) { m0->m_pkthdr.len = 0; m0->m_next = NULL; } - + for (;;) { u_long mfn; @@ -1468,10 +1447,8 @@ xn_tick_locked(struct netfront_info *sc) callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); /* XXX placeholder for printing debug information */ - } - static void xn_tick(void *xsc) { @@ -1481,7 +1458,6 @@ xn_tick(void *xsc) XN_RX_LOCK(sc); xn_tick_locked(sc); XN_RX_UNLOCK(sc); - } /** @@ -1595,10 +1571,12 @@ xn_assemble_tx_request(struct netfront_info *sc, struct mbuf *m_head) tx = RING_GET_REQUEST(&sc->tx, sc->tx.req_prod_pvt); id = get_id_from_freelist(sc->tx_mbufs); if (id == 0) - panic("xn_start_locked: was allocated the freelist head!\n"); + panic("%s: was allocated the freelist head!\n", + __func__); sc->xn_cdata.xn_tx_chain_cnt++; if (sc->xn_cdata.xn_tx_chain_cnt > NET_TX_RING_SIZE) - panic("xn_start_locked: tx_chain_cnt must be <= NET_TX_RING_SIZE\n"); + panic("%s: tx_chain_cnt must be <= NET_TX_RING_SIZE\n", + __func__); sc->tx_mbufs[id] = m; tx->id = id; ref = gnttab_claim_grant_reference(&sc->gref_tx_head); @@ -1710,7 +1688,6 @@ xn_start_locked(struct ifnet *ifp) } } - static void xn_start(struct ifnet *ifp) { @@ -1744,10 +1721,8 @@ xn_ifinit_locked(struct netfront_info *sc) if_link_state_change(ifp, LINK_STATE_UP); callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); - } - static void xn_ifinit(void *xsc) { @@ -1756,10 +1731,8 @@ xn_ifinit(void *xsc) XN_LOCK(sc); xn_ifinit_locked(sc); XN_UNLOCK(sc); - } - static int xn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { @@ -2261,7 +2234,7 @@ static device_method_t netfront_methods[] = { /* Xenbus interface */ DEVMETHOD(xenbus_otherend_changed, netfront_backend_changed), - { 0, 0 } + DEVMETHOD_END }; static driver_t netfront_driver = { @@ -2271,4 +2244,5 @@ static driver_t netfront_driver = { }; devclass_t netfront_devclass; -DRIVER_MODULE(xe, xenbusb_front, netfront_driver, netfront_devclass, 0, 0); +DRIVER_MODULE(xe, xenbusb_front, netfront_driver, netfront_devclass, NULL, + NULL); diff --git a/sys/dev/xen/xenpci/machine_reboot.c b/sys/dev/xen/xenpci/machine_reboot.c deleted file mode 100644 index 4036554..0000000 --- a/sys/dev/xen/xenpci/machine_reboot.c +++ /dev/null @@ -1,80 +0,0 @@ -/*- - * Copyright (c) 2008 Citrix Systems, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 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/bus.h> -#include <sys/kernel.h> -#include <sys/interrupt.h> - -#include <machine/atomic.h> -#include <machine/xen/xen-os.h> -#include <xen/hypervisor.h> -#include <xen/xen_intr.h> - -#include <dev/xen/xenpci/xenpcivar.h> - -void -xen_suspend() -{ - int suspend_cancelled; - - if (DEVICE_SUSPEND(root_bus)) { - printf("xen_suspend: device_suspend failed\n"); - return; - } - - /* - * Make sure we don't change cpus or switch to some other - * thread. for the duration. - */ - critical_enter(); - - /* - * Prevent any races with evtchn_interrupt() handler. - */ - irq_suspend(); - disable_intr(); - - suspend_cancelled = HYPERVISOR_suspend(0); - if (!suspend_cancelled) - xenpci_resume(); - - /* - * Re-enable interrupts and put the scheduler back to normal. - */ - enable_intr(); - critical_exit(); - - /* - * FreeBSD really needs to add DEVICE_SUSPEND_CANCEL or - * similar. - */ - if (!suspend_cancelled) - DEVICE_RESUME(root_bus); -} diff --git a/sys/fs/ext2fs/ext2_dinode.h b/sys/fs/ext2fs/ext2_dinode.h index 9a87fc4..7d97bb8 100755 --- a/sys/fs/ext2fs/ext2_dinode.h +++ b/sys/fs/ext2fs/ext2_dinode.h @@ -29,8 +29,6 @@ #ifndef _FS_EXT2FS_EXT2_DINODE_H_ #define _FS_EXT2FS_EXT2_DINODE_H_ -#define e2di_size_high e2di_dacl - /* * Special inode numbers * The root inode is the root of the file system. Inode 0 can't be used for @@ -87,11 +85,11 @@ struct ext2fs_dinode { uint16_t e2di_mode; /* 0: IFMT, permissions; see below. */ uint16_t e2di_uid; /* 2: Owner UID */ - uint32_t e2di_size; /* 4: Size (in bytes) */ - uint32_t e2di_atime; /* 8: Access time */ - uint32_t e2di_ctime; /* 12: Change time */ - uint32_t e2di_mtime; /* 16: Modification time */ - uint32_t e2di_dtime; /* 20: Deletion time */ + uint32_t e2di_size; /* 4: Size (in bytes) */ + uint32_t e2di_atime; /* 8: Access time */ + uint32_t e2di_ctime; /* 12: Change time */ + uint32_t e2di_mtime; /* 16: Modification time */ + uint32_t e2di_dtime; /* 20: Deletion time */ uint16_t e2di_gid; /* 24: Owner GID */ uint16_t e2di_nlink; /* 26: File link count */ uint32_t e2di_nblock; /* 28: Blocks count */ @@ -99,22 +97,23 @@ struct ext2fs_dinode { uint32_t e2di_version; /* 36: Low 32 bits inode version */ uint32_t e2di_blocks[EXT2_N_BLOCKS]; /* 40: disk blocks */ uint32_t e2di_gen; /* 100: generation number */ - uint32_t e2di_facl; /* 104: file ACL (not implemented) */ - uint32_t e2di_dacl; /* 108: dir ACL (not implemented) */ - uint32_t e2di_faddr; /* 112: fragment address */ + uint32_t e2di_facl; /* 104: Low EA block */ + uint32_t e2di_size_high; /* 108: Upper bits of file size */ + uint32_t e2di_faddr; /* 112: Fragment address (obsolete) */ uint16_t e2di_nblock_high; /* 116: Blocks count bits 47:32 */ - uint16_t e2di_facl_high; /* 118: file ACL bits 47:32 */ + uint16_t e2di_facl_high; /* 118: File EA bits 47:32 */ uint16_t e2di_uid_high; /* 120: Owner UID top 16 bits */ uint16_t e2di_gid_high; /* 122: Owner GID top 16 bits */ - uint32_t e2di_linux_reserved3; /* 124 */ - uint16_t e2di_extra_isize; - uint16_t e2di_pad1; - uint32_t e2di_ctime_extra; /* Extra change time */ - uint32_t e2di_mtime_extra; /* Extra modification time */ - uint32_t e2di_atime_extra; /* Extra access time */ - uint32_t e2di_crtime; /* Creation (birth)time */ - uint32_t e2di_crtime_extra; /* Extra creation (birth)time */ - uint32_t e2di_version_hi; /* High 30 bits of inode version */ + uint16_t e2di_chksum_lo; /* 124: Lower inode checksum */ + uint16_t e2di_lx_reserved; /* 126: Unused */ + uint16_t e2di_extra_isize; /* 128: Size of this inode */ + uint16_t e2di_chksum_hi; /* 130: High inode checksum */ + uint32_t e2di_ctime_extra; /* 132: Extra change time */ + uint32_t e2di_mtime_extra; /* 136: Extra modification time */ + uint32_t e2di_atime_extra; /* 140: Extra access time */ + uint32_t e2di_crtime; /* 144: Creation (birth)time */ + uint32_t e2di_crtime_extra; /* 148: Extra creation (birth)time */ + uint32_t e2di_version_hi; /* 152: High bits of inode version */ }; #endif /* !_FS_EXT2FS_EXT2_DINODE_H_ */ diff --git a/sys/fs/fuse/fuse_io.c b/sys/fs/fuse/fuse_io.c index 5b71a6b..e576568 100644 --- a/sys/fs/fuse/fuse_io.c +++ b/sys/fs/fuse/fuse_io.c @@ -113,7 +113,7 @@ fuse_write_directbackend(struct vnode *vp, struct uio *uio, struct ucred *cred, struct fuse_filehandle *fufh); static int fuse_write_biobackend(struct vnode *vp, struct uio *uio, - struct ucred *cred, struct fuse_filehandle *fufh); + struct ucred *cred, struct fuse_filehandle *fufh, int ioflag); int fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag, @@ -162,7 +162,7 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag, } else { FS_DEBUG("buffered write of vnode %ju\n", (uintmax_t)VTOILLU(vp)); - err = fuse_write_biobackend(vp, uio, cred, fufh); + err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag); } break; default: @@ -371,7 +371,7 @@ fuse_write_directbackend(struct vnode *vp, struct uio *uio, static int fuse_write_biobackend(struct vnode *vp, struct uio *uio, - struct ucred *cred, struct fuse_filehandle *fufh) + struct ucred *cred, struct fuse_filehandle *fufh, int ioflag) { struct fuse_vnode_data *fvdat = VTOFUD(vp); struct buf *bp; @@ -390,6 +390,8 @@ fuse_write_biobackend(struct vnode *vp, struct uio *uio, return (EINVAL); if (uio->uio_resid == 0) return (0); + if (ioflag & IO_APPEND) + uio_setoffset(uio, fvdat->filesize); /* * Find all of this file's B_NEEDCOMMIT buffers. If our writes diff --git a/sys/fs/nandfs/nandfs_segment.c b/sys/fs/nandfs/nandfs_segment.c index 836bead..7433e77 100644 --- a/sys/fs/nandfs/nandfs_segment.c +++ b/sys/fs/nandfs/nandfs_segment.c @@ -478,39 +478,19 @@ nandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo) struct nandfs_node *nandfs_node; struct vnode *vp, *mvp; struct thread *td; - int error, lockreq, update; + int error, update; td = curthread; - lockreq = LK_EXCLUSIVE | LK_INTERLOCK | LK_RETRY; - MNT_ILOCK(mp); - - MNT_VNODE_FOREACH(vp, mp, mvp) { + MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { update = 0; - if (mp->mnt_syncer == vp) - continue; - if (VOP_ISLOCKED(vp)) - continue; - - VI_LOCK(vp); - MNT_IUNLOCK(mp); - if (vp->v_iflag & VI_DOOMED) { + if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) { VI_UNLOCK(vp); - MNT_ILOCK(mp); - continue; - } - - if ((error = vget(vp, lockreq, td)) != 0) { - MNT_ILOCK(mp); continue; } - - if (vp->v_iflag & VI_DOOMED) { - vput(vp); - MNT_ILOCK(mp); + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0) continue; - } nandfs_node = VTON(vp); if (nandfs_node->nn_flags & IN_MODIFIED) { @@ -532,12 +512,8 @@ nandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo) if (update) nandfs_node_update(nandfs_node); - - MNT_ILOCK(mp); } - MNT_IUNLOCK(mp); - return (0); } diff --git a/sys/fs/nullfs/null.h b/sys/fs/nullfs/null.h index 0878e55..4f37020 100644 --- a/sys/fs/nullfs/null.h +++ b/sys/fs/nullfs/null.h @@ -34,9 +34,15 @@ * $FreeBSD$ */ +#ifndef FS_NULL_H +#define FS_NULL_H + +#define NULLM_CACHE 0x0001 + struct null_mount { struct mount *nullm_vfs; struct vnode *nullm_rootvp; /* Reference to root null_node */ + uint64_t nullm_flags; }; #ifdef _KERNEL @@ -80,3 +86,5 @@ MALLOC_DECLARE(M_NULLFSNODE); #endif /* NULLFS_DEBUG */ #endif /* _KERNEL */ + +#endif diff --git a/sys/fs/nullfs/null_subr.c b/sys/fs/nullfs/null_subr.c index b2c7a75..0b72249 100644 --- a/sys/fs/nullfs/null_subr.c +++ b/sys/fs/nullfs/null_subr.c @@ -224,6 +224,9 @@ null_nodeget(mp, lowervp, vpp) * provide ready to use vnode. */ if (VOP_ISLOCKED(lowervp) != LK_EXCLUSIVE) { + KASSERT((MOUNTTONULLMOUNT(mp)->nullm_flags & NULLM_CACHE) != 0, + ("lowervp %p is not excl locked and cache is disabled", + lowervp)); vn_lock(lowervp, LK_UPGRADE | LK_RETRY); if ((lowervp->v_iflag & VI_DOOMED) != 0) { vput(lowervp); diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c index 7d84d51..5abfa49 100644 --- a/sys/fs/nullfs/null_vfsops.c +++ b/sys/fs/nullfs/null_vfsops.c @@ -67,6 +67,15 @@ static vfs_vget_t nullfs_vget; static vfs_extattrctl_t nullfs_extattrctl; static vfs_reclaim_lowervp_t nullfs_reclaim_lowervp; +/* Mount options that we support. */ +static const char *nullfs_opts[] = { + "cache", + "export", + "from", + "target", + NULL +}; + /* * Mount null layer */ @@ -86,9 +95,11 @@ nullfs_mount(struct mount *mp) if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_NULLFS)) return (EPERM); - if (mp->mnt_flag & MNT_ROOTFS) return (EOPNOTSUPP); + if (vfs_filteropt(mp->mnt_optnew, nullfs_opts)) + return (EINVAL); + /* * Update is a no-op */ @@ -149,7 +160,7 @@ nullfs_mount(struct mount *mp) } xmp = (struct null_mount *) malloc(sizeof(struct null_mount), - M_NULLFSMNT, M_WAITOK); + M_NULLFSMNT, M_WAITOK | M_ZERO); /* * Save reference to underlying FS @@ -187,16 +198,27 @@ nullfs_mount(struct mount *mp) mp->mnt_flag |= MNT_LOCAL; MNT_IUNLOCK(mp); } + + xmp->nullm_flags |= NULLM_CACHE; + if (vfs_getopt(mp->mnt_optnew, "nocache", NULL, NULL) == 0) + xmp->nullm_flags &= ~NULLM_CACHE; + MNT_ILOCK(mp); - mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & - (MNTK_SHARED_WRITES | MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED); + if ((xmp->nullm_flags & NULLM_CACHE) != 0) { + mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & + (MNTK_SHARED_WRITES | MNTK_LOOKUP_SHARED | + MNTK_EXTENDED_SHARED); + } mp->mnt_kern_flag |= MNTK_LOOKUP_EXCL_DOTDOT; MNT_IUNLOCK(mp); mp->mnt_data = xmp; vfs_getnewfsid(mp); - MNT_ILOCK(xmp->nullm_vfs); - TAILQ_INSERT_TAIL(&xmp->nullm_vfs->mnt_uppers, mp, mnt_upper_link); - MNT_IUNLOCK(xmp->nullm_vfs); + if ((xmp->nullm_flags & NULLM_CACHE) != 0) { + MNT_ILOCK(xmp->nullm_vfs); + TAILQ_INSERT_TAIL(&xmp->nullm_vfs->mnt_uppers, mp, + mnt_upper_link); + MNT_IUNLOCK(xmp->nullm_vfs); + } vfs_mountedfrom(mp, target); @@ -234,13 +256,15 @@ nullfs_unmount(mp, mntflags) */ mntdata = mp->mnt_data; ump = mntdata->nullm_vfs; - MNT_ILOCK(ump); - while ((ump->mnt_kern_flag & MNTK_VGONE_UPPER) != 0) { - ump->mnt_kern_flag |= MNTK_VGONE_WAITER; - msleep(&ump->mnt_uppers, &ump->mnt_mtx, 0, "vgnupw", 0); + if ((mntdata->nullm_flags & NULLM_CACHE) != 0) { + MNT_ILOCK(ump); + while ((ump->mnt_kern_flag & MNTK_VGONE_UPPER) != 0) { + ump->mnt_kern_flag |= MNTK_VGONE_WAITER; + msleep(&ump->mnt_uppers, &ump->mnt_mtx, 0, "vgnupw", 0); + } + TAILQ_REMOVE(&ump->mnt_uppers, mp, mnt_upper_link); + MNT_IUNLOCK(ump); } - TAILQ_REMOVE(&ump->mnt_uppers, mp, mnt_upper_link); - MNT_IUNLOCK(ump); mp->mnt_data = NULL; free(mntdata, M_NULLFSMNT); return (0); diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c index f530ed2..cc35d81 100644 --- a/sys/fs/nullfs/null_vnops.c +++ b/sys/fs/nullfs/null_vnops.c @@ -692,7 +692,22 @@ null_unlock(struct vop_unlock_args *ap) static int null_inactive(struct vop_inactive_args *ap __unused) { + struct vnode *vp; + struct mount *mp; + struct null_mount *xmp; + vp = ap->a_vp; + mp = vp->v_mount; + xmp = MOUNTTONULLMOUNT(mp); + if ((xmp->nullm_flags & NULLM_CACHE) == 0) { + /* + * If this is the last reference and caching of the + * nullfs vnodes is not enabled, then free up the + * vnode so as not to tie up the lower vnodes. + */ + vp->v_object = NULL; + vrecycle(vp); + } return (0); } diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h index 1c6d714..8073c64 100644 --- a/sys/fs/tmpfs/tmpfs.h +++ b/sys/fs/tmpfs/tmpfs.h @@ -49,6 +49,7 @@ /* --------------------------------------------------------------------- */ #include <sys/malloc.h> #include <sys/systm.h> +#include <sys/tree.h> #include <sys/vmmeter.h> #include <vm/swap_pager.h> @@ -60,104 +61,81 @@ MALLOC_DECLARE(M_TMPFSNAME); /* * Internal representation of a tmpfs directory entry. */ + +LIST_HEAD(tmpfs_dir_duphead, tmpfs_dirent); + struct tmpfs_dirent { - TAILQ_ENTRY(tmpfs_dirent) td_entries; + /* + * Depending on td_cookie flag entry can be of 3 types: + * - regular -- no hash collisions, stored in RB-Tree + * - duphead -- synthetic linked list head for dup entries + * - dup -- stored in linked list instead of RB-Tree + */ + union { + /* regular and duphead entry types */ + RB_ENTRY(tmpfs_dirent) td_entries; - /* Length of the name stored in this directory entry. This avoids - * the need to recalculate it every time the name is used. */ - uint16_t td_namelen; + /* dup entry type */ + struct { + LIST_ENTRY(tmpfs_dirent) entries; + LIST_ENTRY(tmpfs_dirent) index_entries; + } td_dup; + } uh; - /* The name of the entry, allocated from a string pool. This - * string is not required to be zero-terminated; therefore, the - * td_namelen field must always be used when accessing its value. */ - char * td_name; + uint32_t td_cookie; + uint32_t td_hash; + u_int td_namelen; /* Pointer to the node this entry refers to. In case this field * is NULL, the node is a whiteout. */ struct tmpfs_node * td_node; + + union { + /* + * The name of the entry, allocated from a string pool. This + * string is not required to be zero-terminated. + */ + char * td_name; /* regular, dup */ + struct tmpfs_dir_duphead td_duphead; /* duphead */ + } ud; }; -/* A directory in tmpfs holds a sorted list of directory entries, which in +/* A directory in tmpfs holds a list of directory entries, which in * turn point to other files (which can be directories themselves). * - * In tmpfs, this list is managed by a tail queue, whose head is defined by + * In tmpfs, this list is managed by a RB-Tree, whose head is defined by * the struct tmpfs_dir type. * - * It is imporant to notice that directories do not have entries for . and + * It is important to notice that directories do not have entries for . and * .. as other file systems do. These can be generated when requested * based on information available by other means, such as the pointer to * the node itself in the former case or the pointer to the parent directory * in the latter case. This is done to simplify tmpfs's code and, more * importantly, to remove redundancy. */ -TAILQ_HEAD(tmpfs_dir, tmpfs_dirent); +RB_HEAD(tmpfs_dir, tmpfs_dirent); /* Each entry in a directory has a cookie that identifies it. Cookies * supersede offsets within directories because, given how tmpfs stores - * directories in memory, there is no such thing as an offset. (Emulating - * a real offset could be very difficult.) - * + * directories in memory, there is no such thing as an offset. + * * The '.', '..' and the end of directory markers have fixed cookies which * cannot collide with the cookies generated by other entries. The cookies - * fot the other entries are generated based on the memory address on which - * stores their information is stored. - * - * Ideally, using the entry's memory pointer as the cookie would be enough - * to represent it and it wouldn't cause collisions in any system. - * Unfortunately, this results in "offsets" with very large values which - * later raise problems in the Linux compatibility layer (and maybe in other - * places) as described in PR kern/32034. Hence we need to workaround this - * with a rather ugly hack. - * - * Linux 32-bit binaries, unless built with _FILE_OFFSET_BITS=64, have off_t - * set to 'long', which is a 32-bit *signed* long integer. Regardless of - * the macro value, GLIBC (2.3 at least) always uses the getdents64 - * system call (when calling readdir) which internally returns off64_t - * offsets. In order to make 32-bit binaries work, *GLIBC* converts the - * 64-bit values returned by the kernel to 32-bit ones and aborts with - * EOVERFLOW if the conversion results in values that won't fit in 32-bit - * integers (which it assumes is because the directory is extremely large). - * This wouldn't cause problems if we were dealing with unsigned integers, - * but as we have signed integers, this check fails due to sign expansion. + * for the other entries are generated based on the file name hash value or + * unique number in case of name hash collision. * - * For example, consider that the kernel returns the 0xc1234567 cookie to - * userspace in a off64_t integer. Later on, GLIBC casts this value to - * off_t (remember, signed) with code similar to: - * system call returns the offset in kernel_value; - * off_t casted_value = kernel_value; - * if (sizeof(off_t) != sizeof(off64_t) && - * kernel_value != casted_value) - * error! - * In this case, casted_value still has 0xc1234567, but when it is compared - * for equality against kernel_value, it is promoted to a 64-bit integer and - * becomes 0xffffffffc1234567, which is different than 0x00000000c1234567. - * Then, GLIBC assumes this is because the directory is very large. - * - * Given that all the above happens in user-space, we have no control over - * it; therefore we must workaround the issue here. We do this by - * truncating the pointer value to a 32-bit integer and hope that there - * won't be collisions. In fact, this will not cause any problems in - * 32-bit platforms but some might arise in 64-bit machines (I'm not sure - * if they can happen at all in practice). - * - * XXX A nicer solution shall be attempted. */ -#ifdef _KERNEL -#define TMPFS_DIRCOOKIE_DOT 0 -#define TMPFS_DIRCOOKIE_DOTDOT 1 -#define TMPFS_DIRCOOKIE_EOF 2 -static __inline -off_t -tmpfs_dircookie(struct tmpfs_dirent *de) -{ - off_t cookie; - - cookie = ((off_t)(uintptr_t)de >> 1) & 0x7FFFFFFF; - MPASS(cookie != TMPFS_DIRCOOKIE_DOT); - MPASS(cookie != TMPFS_DIRCOOKIE_DOTDOT); - MPASS(cookie != TMPFS_DIRCOOKIE_EOF); + * To preserve compatibility cookies are limited to 31 bits. + */ - return cookie; -} -#endif +#define TMPFS_DIRCOOKIE_DOT 0 +#define TMPFS_DIRCOOKIE_DOTDOT 1 +#define TMPFS_DIRCOOKIE_EOF 2 +#define TMPFS_DIRCOOKIE_MASK ((off_t)0x3fffffffU) +#define TMPFS_DIRCOOKIE_MIN ((off_t)0x00000004U) +#define TMPFS_DIRCOOKIE_DUP ((off_t)0x40000000U) +#define TMPFS_DIRCOOKIE_DUPHEAD ((off_t)0x80000000U) +#define TMPFS_DIRCOOKIE_DUP_MIN TMPFS_DIRCOOKIE_DUP +#define TMPFS_DIRCOOKIE_DUP_MAX \ + (TMPFS_DIRCOOKIE_DUP | TMPFS_DIRCOOKIE_MASK) /* --------------------------------------------------------------------- */ @@ -243,29 +221,31 @@ struct tmpfs_node { dev_t tn_rdev; /* Valid when tn_type == VDIR. */ - struct tn_dir{ + struct tn_dir { /* Pointer to the parent directory. The root * directory has a pointer to itself in this field; * this property identifies the root node. */ struct tmpfs_node * tn_parent; - /* Head of a tail-queue that links the contents of - * the directory together. See above for a - * description of its contents. */ + /* Head of a tree that links the contents of + * the directory together. */ struct tmpfs_dir tn_dirhead; + /* Head of a list the contains fake directory entries + * heads, i.e. entries with TMPFS_DIRCOOKIE_DUPHEAD + * flag. */ + struct tmpfs_dir_duphead tn_dupindex; + /* Number and pointer of the first directory entry * returned by the readdir operation if it were * called again to continue reading data from the * same directory as before. This is used to speed * up reads of long directories, assuming that no * more than one read is in progress at a given time. - * Otherwise, these values are discarded and a linear - * scan is performed from the beginning up to the - * point where readdir starts returning values. */ + * Otherwise, these values are discarded. */ off_t tn_readdir_lastn; struct tmpfs_dirent * tn_readdir_lastp; - }tn_dir; + } tn_dir; /* Valid when tn_type == VLNK. */ /* The link's target, allocated from a string pool. */ @@ -419,9 +399,9 @@ int tmpfs_alloc_node(struct tmpfs_mount *, enum vtype, char *, dev_t, struct tmpfs_node **); void tmpfs_free_node(struct tmpfs_mount *, struct tmpfs_node *); int tmpfs_alloc_dirent(struct tmpfs_mount *, struct tmpfs_node *, - const char *, uint16_t, struct tmpfs_dirent **); -void tmpfs_free_dirent(struct tmpfs_mount *, struct tmpfs_dirent *, - boolean_t); + const char *, u_int, struct tmpfs_dirent **); +void tmpfs_free_dirent(struct tmpfs_mount *, struct tmpfs_dirent *); +void tmpfs_dirent_init(struct tmpfs_dirent *, const char *, u_int); int tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, int, struct vnode **); void tmpfs_free_vp(struct vnode *); @@ -429,13 +409,12 @@ int tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *, struct componentname *, char *); void tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *); void tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *); +void tmpfs_dir_destroy(struct tmpfs_mount *, struct tmpfs_node *); struct tmpfs_dirent * tmpfs_dir_lookup(struct tmpfs_node *node, struct tmpfs_node *f, struct componentname *cnp); -int tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *); -int tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *); -struct tmpfs_dirent * tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t); -int tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *); +int tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, int, + u_long *, int *); int tmpfs_dir_whiteout_add(struct vnode *, struct componentname *); void tmpfs_dir_whiteout_remove(struct vnode *, struct componentname *); int tmpfs_reg_resize(struct vnode *, off_t, boolean_t); @@ -467,8 +446,8 @@ int tmpfs_truncate(struct vnode *, off_t); * with a length of 'len'. */ #define TMPFS_DIRENT_MATCHES(de, name, len) \ - (de->td_namelen == (uint16_t)len && \ - bcmp((de)->td_name, (name), (de)->td_namelen) == 0) + (de->td_namelen == len && \ + bcmp((de)->ud.td_name, (name), (de)->td_namelen) == 0) /* --------------------------------------------------------------------- */ @@ -476,11 +455,10 @@ int tmpfs_truncate(struct vnode *, off_t); * Ensures that the node pointed by 'node' is a directory and that its * contents are consistent with respect to directories. */ -#define TMPFS_VALIDATE_DIR(node) \ - MPASS((node)->tn_type == VDIR); \ - MPASS((node)->tn_size % sizeof(struct tmpfs_dirent) == 0); \ - MPASS((node)->tn_dir.tn_readdir_lastp == NULL || \ - tmpfs_dircookie((node)->tn_dir.tn_readdir_lastp) == (node)->tn_dir.tn_readdir_lastn); +#define TMPFS_VALIDATE_DIR(node) do { \ + MPASS((node)->tn_type == VDIR); \ + MPASS((node)->tn_size % sizeof(struct tmpfs_dirent) == 0); \ +} while (0) /* --------------------------------------------------------------------- */ diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index 5f1616c..47ac2e6 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> +#include <sys/fnv_hash.h> #include <sys/namei.h> #include <sys/priv.h> #include <sys/proc.h> @@ -58,6 +59,11 @@ __FBSDID("$FreeBSD$"); #include <fs/tmpfs/tmpfs_fifoops.h> #include <fs/tmpfs/tmpfs_vnops.h> +struct tmpfs_dir_cursor { + struct tmpfs_dirent *tdc_current; + struct tmpfs_dirent *tdc_tree; +}; + SYSCTL_NODE(_vfs, OID_AUTO, tmpfs, CTLFLAG_RW, 0, "tmpfs file system"); static long tmpfs_pages_reserved = TMPFS_PAGES_MINRESERVED; @@ -87,6 +93,10 @@ SYSCTL_PROC(_vfs_tmpfs, OID_AUTO, memory_reserved, CTLTYPE_LONG|CTLFLAG_RW, &tmpfs_pages_reserved, 0, sysctl_mem_reserved, "L", "Amount of available memory and swap below which tmpfs growth stops"); +static __inline int tmpfs_dirtree_cmp(struct tmpfs_dirent *a, + struct tmpfs_dirent *b); +RB_PROTOTYPE_STATIC(tmpfs_dir, tmpfs_dirent, uh.td_entries, tmpfs_dirtree_cmp); + size_t tmpfs_mem_avail(void) { @@ -188,7 +198,8 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type, break; case VDIR: - TAILQ_INIT(&nnode->tn_dir.tn_dirhead); + RB_INIT(&nnode->tn_dir.tn_dirhead); + LIST_INIT(&nnode->tn_dir.tn_dupindex); MPASS(parent != nnode); MPASS(IMPLIES(parent == NULL, tmp->tm_root == NULL)); nnode->tn_dir.tn_parent = (parent == NULL) ? nnode : parent; @@ -309,6 +320,49 @@ tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node) /* --------------------------------------------------------------------- */ +static __inline uint32_t +tmpfs_dirent_hash(const char *name, u_int len) +{ + uint32_t hash; + + hash = fnv_32_buf(name, len, FNV1_32_INIT + len) & TMPFS_DIRCOOKIE_MASK; +#ifdef TMPFS_DEBUG_DIRCOOKIE_DUP + hash &= 0xf; +#endif + if (hash < TMPFS_DIRCOOKIE_MIN) + hash += TMPFS_DIRCOOKIE_MIN; + + return (hash); +} + +static __inline off_t +tmpfs_dirent_cookie(struct tmpfs_dirent *de) +{ + MPASS(de->td_cookie >= TMPFS_DIRCOOKIE_MIN); + + return (de->td_cookie); +} + +static __inline boolean_t +tmpfs_dirent_dup(struct tmpfs_dirent *de) +{ + return ((de->td_cookie & TMPFS_DIRCOOKIE_DUP) != 0); +} + +static __inline boolean_t +tmpfs_dirent_duphead(struct tmpfs_dirent *de) +{ + return ((de->td_cookie & TMPFS_DIRCOOKIE_DUPHEAD) != 0); +} + +void +tmpfs_dirent_init(struct tmpfs_dirent *de, const char *name, u_int namelen) +{ + de->td_hash = de->td_cookie = tmpfs_dirent_hash(name, namelen); + memcpy(de->ud.td_name, name, namelen); + de->td_namelen = namelen; +} + /* * Allocates a new directory entry for the node node with a name of name. * The new directory entry is returned in *de. @@ -320,17 +374,17 @@ tmpfs_free_node(struct tmpfs_mount *tmp, struct tmpfs_node *node) */ int tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node, - const char *name, uint16_t len, struct tmpfs_dirent **de) + const char *name, u_int len, struct tmpfs_dirent **de) { struct tmpfs_dirent *nde; - nde = (struct tmpfs_dirent *)uma_zalloc( - tmp->tm_dirent_pool, M_WAITOK); - nde->td_name = malloc(len, M_TMPFSNAME, M_WAITOK); - nde->td_namelen = len; - memcpy(nde->td_name, name, len); - + nde = uma_zalloc(tmp->tm_dirent_pool, M_WAITOK); nde->td_node = node; + if (name != NULL) { + nde->ud.td_name = malloc(len, M_TMPFSNAME, M_WAITOK); + tmpfs_dirent_init(nde, name, len); + } else + nde->td_namelen = 0; if (node != NULL) node->tn_links++; @@ -351,20 +405,17 @@ tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node, * directory entry, as it may already have been released from the outside. */ void -tmpfs_free_dirent(struct tmpfs_mount *tmp, struct tmpfs_dirent *de, - boolean_t node_exists) +tmpfs_free_dirent(struct tmpfs_mount *tmp, struct tmpfs_dirent *de) { - if (node_exists) { - struct tmpfs_node *node; + struct tmpfs_node *node; - node = de->td_node; - if (node != NULL) { - MPASS(node->tn_links > 0); - node->tn_links--; - } + node = de->td_node; + if (node != NULL) { + MPASS(node->tn_links > 0); + node->tn_links--; } - - free(de->td_name, M_TMPFSNAME); + if (!tmpfs_dirent_duphead(de) && de->ud.td_name != NULL) + free(de->ud.td_name, M_TMPFSNAME); uma_zfree(tmp->tm_dirent_pool, de); } @@ -586,7 +637,7 @@ tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap, /* Allocate a vnode for the new file. */ error = tmpfs_alloc_vp(dvp->v_mount, node, LK_EXCLUSIVE, vpp); if (error != 0) { - tmpfs_free_dirent(tmp, de, TRUE); + tmpfs_free_dirent(tmp, de); tmpfs_free_node(tmp, node); goto out; } @@ -605,6 +656,215 @@ out: /* --------------------------------------------------------------------- */ +static struct tmpfs_dirent * +tmpfs_dir_first(struct tmpfs_node *dnode, struct tmpfs_dir_cursor *dc) +{ + struct tmpfs_dirent *de; + + de = RB_MIN(tmpfs_dir, &dnode->tn_dir.tn_dirhead); + dc->tdc_tree = de; + if (de != NULL && tmpfs_dirent_duphead(de)) + de = LIST_FIRST(&de->ud.td_duphead); + dc->tdc_current = de; + + return (dc->tdc_current); +} + +static struct tmpfs_dirent * +tmpfs_dir_next(struct tmpfs_node *dnode, struct tmpfs_dir_cursor *dc) +{ + struct tmpfs_dirent *de; + + MPASS(dc->tdc_tree != NULL); + if (tmpfs_dirent_dup(dc->tdc_current)) { + dc->tdc_current = LIST_NEXT(dc->tdc_current, uh.td_dup.entries); + if (dc->tdc_current != NULL) + return (dc->tdc_current); + } + dc->tdc_tree = dc->tdc_current = RB_NEXT(tmpfs_dir, + &dnode->tn_dir.tn_dirhead, dc->tdc_tree); + if ((de = dc->tdc_current) != NULL && tmpfs_dirent_duphead(de)) { + dc->tdc_current = LIST_FIRST(&de->ud.td_duphead); + MPASS(dc->tdc_current != NULL); + } + + return (dc->tdc_current); +} + +/* Lookup directory entry in RB-Tree. Function may return duphead entry. */ +static struct tmpfs_dirent * +tmpfs_dir_xlookup_hash(struct tmpfs_node *dnode, uint32_t hash) +{ + struct tmpfs_dirent *de, dekey; + + dekey.td_hash = hash; + de = RB_FIND(tmpfs_dir, &dnode->tn_dir.tn_dirhead, &dekey); + return (de); +} + +/* Lookup directory entry by cookie, initialize directory cursor accordingly. */ +static struct tmpfs_dirent * +tmpfs_dir_lookup_cookie(struct tmpfs_node *node, off_t cookie, + struct tmpfs_dir_cursor *dc) +{ + struct tmpfs_dir *dirhead = &node->tn_dir.tn_dirhead; + struct tmpfs_dirent *de, dekey; + + MPASS(cookie >= TMPFS_DIRCOOKIE_MIN); + + if (cookie == node->tn_dir.tn_readdir_lastn && + (de = node->tn_dir.tn_readdir_lastp) != NULL) { + /* Protect against possible race, tn_readdir_last[pn] + * may be updated with only shared vnode lock held. */ + if (cookie == tmpfs_dirent_cookie(de)) + goto out; + } + + if ((cookie & TMPFS_DIRCOOKIE_DUP) != 0) { + LIST_FOREACH(de, &node->tn_dir.tn_dupindex, + uh.td_dup.index_entries) { + MPASS(tmpfs_dirent_dup(de)); + if (de->td_cookie == cookie) + goto out; + /* dupindex list is sorted. */ + if (de->td_cookie < cookie) { + de = NULL; + goto out; + } + } + MPASS(de == NULL); + goto out; + } + + MPASS((cookie & TMPFS_DIRCOOKIE_MASK) == cookie); + dekey.td_hash = cookie; + /* Recover if direntry for cookie was removed */ + de = RB_NFIND(tmpfs_dir, dirhead, &dekey); + dc->tdc_tree = de; + dc->tdc_current = de; + if (de != NULL && tmpfs_dirent_duphead(de)) { + dc->tdc_current = LIST_FIRST(&de->ud.td_duphead); + MPASS(dc->tdc_current != NULL); + } + return (dc->tdc_current); + +out: + dc->tdc_tree = de; + dc->tdc_current = de; + if (de != NULL && tmpfs_dirent_dup(de)) + dc->tdc_tree = tmpfs_dir_xlookup_hash(node, + de->td_hash); + return (dc->tdc_current); +} + +/* + * Looks for a directory entry in the directory represented by node. + * 'cnp' describes the name of the entry to look for. Note that the . + * and .. components are not allowed as they do not physically exist + * within directories. + * + * Returns a pointer to the entry when found, otherwise NULL. + */ +struct tmpfs_dirent * +tmpfs_dir_lookup(struct tmpfs_node *node, struct tmpfs_node *f, + struct componentname *cnp) +{ + struct tmpfs_dir_duphead *duphead; + struct tmpfs_dirent *de; + uint32_t hash; + + MPASS(IMPLIES(cnp->cn_namelen == 1, cnp->cn_nameptr[0] != '.')); + MPASS(IMPLIES(cnp->cn_namelen == 2, !(cnp->cn_nameptr[0] == '.' && + cnp->cn_nameptr[1] == '.'))); + TMPFS_VALIDATE_DIR(node); + + hash = tmpfs_dirent_hash(cnp->cn_nameptr, cnp->cn_namelen); + de = tmpfs_dir_xlookup_hash(node, hash); + if (de != NULL && tmpfs_dirent_duphead(de)) { + duphead = &de->ud.td_duphead; + LIST_FOREACH(de, duphead, uh.td_dup.entries) { + if (TMPFS_DIRENT_MATCHES(de, cnp->cn_nameptr, + cnp->cn_namelen)) + break; + } + } else if (de != NULL) { + if (!TMPFS_DIRENT_MATCHES(de, cnp->cn_nameptr, + cnp->cn_namelen)) + de = NULL; + } + if (de != NULL && f != NULL && de->td_node != f) + de = NULL; + + return (de); +} + +/* + * Attach duplicate-cookie directory entry nde to dnode and insert to dupindex + * list, allocate new cookie value. + */ +static void +tmpfs_dir_attach_dup(struct tmpfs_node *dnode, + struct tmpfs_dir_duphead *duphead, struct tmpfs_dirent *nde) +{ + struct tmpfs_dir_duphead *dupindex; + struct tmpfs_dirent *de, *pde; + + dupindex = &dnode->tn_dir.tn_dupindex; + de = LIST_FIRST(dupindex); + if (de == NULL || de->td_cookie < TMPFS_DIRCOOKIE_DUP_MAX) { + if (de == NULL) + nde->td_cookie = TMPFS_DIRCOOKIE_DUP_MIN; + else + nde->td_cookie = de->td_cookie + 1; + MPASS(tmpfs_dirent_dup(nde)); + LIST_INSERT_HEAD(dupindex, nde, uh.td_dup.index_entries); + LIST_INSERT_HEAD(duphead, nde, uh.td_dup.entries); + return; + } + + /* + * Cookie numbers are near exhaustion. Scan dupindex list for unused + * numbers. dupindex list is sorted in descending order. Keep it so + * after inserting nde. + */ + while (1) { + pde = de; + de = LIST_NEXT(de, uh.td_dup.index_entries); + if (de == NULL && pde->td_cookie != TMPFS_DIRCOOKIE_DUP_MIN) { + /* + * Last element of the index doesn't have minimal cookie + * value, use it. + */ + nde->td_cookie = TMPFS_DIRCOOKIE_DUP_MIN; + LIST_INSERT_AFTER(pde, nde, uh.td_dup.index_entries); + LIST_INSERT_HEAD(duphead, nde, uh.td_dup.entries); + return; + } else if (de == NULL) { + /* + * We are so lucky have 2^30 hash duplicates in single + * directory :) Return largest possible cookie value. + * It should be fine except possible issues with + * VOP_READDIR restart. + */ + nde->td_cookie = TMPFS_DIRCOOKIE_DUP_MAX; + LIST_INSERT_HEAD(dupindex, nde, + uh.td_dup.index_entries); + LIST_INSERT_HEAD(duphead, nde, uh.td_dup.entries); + return; + } + if (de->td_cookie + 1 == pde->td_cookie || + de->td_cookie >= TMPFS_DIRCOOKIE_DUP_MAX) + continue; /* No hole or invalid cookie. */ + nde->td_cookie = de->td_cookie + 1; + MPASS(tmpfs_dirent_dup(nde)); + MPASS(pde->td_cookie > nde->td_cookie); + MPASS(nde->td_cookie > de->td_cookie); + LIST_INSERT_BEFORE(de, nde, uh.td_dup.index_entries); + LIST_INSERT_HEAD(duphead, nde, uh.td_dup.entries); + return; + }; +} + /* * Attaches the directory entry de to the directory represented by vp. * Note that this does not change the link count of the node pointed by @@ -614,10 +874,38 @@ void tmpfs_dir_attach(struct vnode *vp, struct tmpfs_dirent *de) { struct tmpfs_node *dnode; + struct tmpfs_dirent *xde, *nde; ASSERT_VOP_ELOCKED(vp, __func__); + MPASS(de->td_namelen > 0); + MPASS(de->td_hash >= TMPFS_DIRCOOKIE_MIN); + MPASS(de->td_cookie == de->td_hash); + dnode = VP_TO_TMPFS_DIR(vp); - TAILQ_INSERT_TAIL(&dnode->tn_dir.tn_dirhead, de, td_entries); + dnode->tn_dir.tn_readdir_lastn = 0; + dnode->tn_dir.tn_readdir_lastp = NULL; + + MPASS(!tmpfs_dirent_dup(de)); + xde = RB_INSERT(tmpfs_dir, &dnode->tn_dir.tn_dirhead, de); + if (xde != NULL && tmpfs_dirent_duphead(xde)) + tmpfs_dir_attach_dup(dnode, &xde->ud.td_duphead, de); + else if (xde != NULL) { + /* + * Allocate new duphead. Swap xde with duphead to avoid + * adding/removing elements with the same hash. + */ + MPASS(!tmpfs_dirent_dup(xde)); + tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), NULL, NULL, 0, + &nde); + /* *nde = *xde; XXX gcc 4.2.1 may generate invalid code. */ + memcpy(nde, xde, sizeof(*xde)); + xde->td_cookie |= TMPFS_DIRCOOKIE_DUPHEAD; + LIST_INIT(&xde->ud.td_duphead); + xde->td_namelen = 0; + xde->td_node = NULL; + tmpfs_dir_attach_dup(dnode, &xde->ud.td_duphead, nde); + tmpfs_dir_attach_dup(dnode, &xde->ud.td_duphead, de); + } dnode->tn_size += sizeof(struct tmpfs_dirent); dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ TMPFS_NODE_MODIFIED; @@ -633,58 +921,61 @@ tmpfs_dir_attach(struct vnode *vp, struct tmpfs_dirent *de) void tmpfs_dir_detach(struct vnode *vp, struct tmpfs_dirent *de) { + struct tmpfs_mount *tmp; + struct tmpfs_dir *head; struct tmpfs_node *dnode; + struct tmpfs_dirent *xde; ASSERT_VOP_ELOCKED(vp, __func__); - dnode = VP_TO_TMPFS_DIR(vp); - if (dnode->tn_dir.tn_readdir_lastp == de) { - dnode->tn_dir.tn_readdir_lastn = 0; - dnode->tn_dir.tn_readdir_lastp = NULL; - } + dnode = VP_TO_TMPFS_DIR(vp); + head = &dnode->tn_dir.tn_dirhead; + dnode->tn_dir.tn_readdir_lastn = 0; + dnode->tn_dir.tn_readdir_lastp = NULL; + + if (tmpfs_dirent_dup(de)) { + /* Remove duphead if de was last entry. */ + if (LIST_NEXT(de, uh.td_dup.entries) == NULL) { + xde = tmpfs_dir_xlookup_hash(dnode, de->td_hash); + MPASS(tmpfs_dirent_duphead(xde)); + } else + xde = NULL; + LIST_REMOVE(de, uh.td_dup.entries); + LIST_REMOVE(de, uh.td_dup.index_entries); + if (xde != NULL) { + if (LIST_EMPTY(&xde->ud.td_duphead)) { + RB_REMOVE(tmpfs_dir, head, xde); + tmp = VFS_TO_TMPFS(vp->v_mount); + MPASS(xde->td_node == NULL); + tmpfs_free_dirent(tmp, xde); + } + } + } else + RB_REMOVE(tmpfs_dir, head, de); - TAILQ_REMOVE(&dnode->tn_dir.tn_dirhead, de, td_entries); dnode->tn_size -= sizeof(struct tmpfs_dirent); dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ TMPFS_NODE_MODIFIED; } -/* --------------------------------------------------------------------- */ - -/* - * Looks for a directory entry in the directory represented by node. - * 'cnp' describes the name of the entry to look for. Note that the . - * and .. components are not allowed as they do not physically exist - * within directories. - * - * Returns a pointer to the entry when found, otherwise NULL. - */ -struct tmpfs_dirent * -tmpfs_dir_lookup(struct tmpfs_node *node, struct tmpfs_node *f, - struct componentname *cnp) +void +tmpfs_dir_destroy(struct tmpfs_mount *tmp, struct tmpfs_node *dnode) { - boolean_t found; - struct tmpfs_dirent *de; - - MPASS(IMPLIES(cnp->cn_namelen == 1, cnp->cn_nameptr[0] != '.')); - MPASS(IMPLIES(cnp->cn_namelen == 2, !(cnp->cn_nameptr[0] == '.' && - cnp->cn_nameptr[1] == '.'))); - TMPFS_VALIDATE_DIR(node); - - found = 0; - TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) { - if (f != NULL && de->td_node != f) - continue; - MPASS(cnp->cn_namelen < 0xffff); - if (de->td_namelen == (uint16_t)cnp->cn_namelen && - bcmp(de->td_name, cnp->cn_nameptr, de->td_namelen) == 0) { - found = 1; - break; + struct tmpfs_dirent *de, *dde, *nde; + + RB_FOREACH_SAFE(de, tmpfs_dir, &dnode->tn_dir.tn_dirhead, nde) { + RB_REMOVE(tmpfs_dir, &dnode->tn_dir.tn_dirhead, de); + /* Node may already be destroyed. */ + de->td_node = NULL; + if (tmpfs_dirent_duphead(de)) { + while ((dde = LIST_FIRST(&de->ud.td_duphead)) != NULL) { + LIST_REMOVE(dde, uh.td_dup.entries); + dde->td_node = NULL; + tmpfs_free_dirent(tmp, dde); + } } + tmpfs_free_dirent(tmp, de); } - node->tn_status |= TMPFS_NODE_ACCESSED; - - return found ? de : NULL; } /* --------------------------------------------------------------------- */ @@ -696,7 +987,7 @@ tmpfs_dir_lookup(struct tmpfs_node *node, struct tmpfs_node *f, * hold the directory entry or an appropriate error code if another * error happens. */ -int +static int tmpfs_dir_getdotdent(struct tmpfs_node *node, struct uio *uio) { int error; @@ -713,12 +1004,9 @@ tmpfs_dir_getdotdent(struct tmpfs_node *node, struct uio *uio) dent.d_reclen = GENERIC_DIRSIZ(&dent); if (dent.d_reclen > uio->uio_resid) - error = -1; - else { + error = EJUSTRETURN; + else error = uiomove(&dent, dent.d_reclen, uio); - if (error == 0) - uio->uio_offset = TMPFS_DIRCOOKIE_DOTDOT; - } node->tn_status |= TMPFS_NODE_ACCESSED; @@ -734,7 +1022,7 @@ tmpfs_dir_getdotdent(struct tmpfs_node *node, struct uio *uio) * hold the directory entry or an appropriate error code if another * error happens. */ -int +static int tmpfs_dir_getdotdotdent(struct tmpfs_node *node, struct uio *uio) { int error; @@ -763,19 +1051,9 @@ tmpfs_dir_getdotdotdent(struct tmpfs_node *node, struct uio *uio) dent.d_reclen = GENERIC_DIRSIZ(&dent); if (dent.d_reclen > uio->uio_resid) - error = -1; - else { + error = EJUSTRETURN; + else error = uiomove(&dent, dent.d_reclen, uio); - if (error == 0) { - struct tmpfs_dirent *de; - - de = TAILQ_FIRST(&node->tn_dir.tn_dirhead); - if (de == NULL) - uio->uio_offset = TMPFS_DIRCOOKIE_EOF; - else - uio->uio_offset = tmpfs_dircookie(de); - } - } node->tn_status |= TMPFS_NODE_ACCESSED; @@ -785,30 +1063,6 @@ tmpfs_dir_getdotdotdent(struct tmpfs_node *node, struct uio *uio) /* --------------------------------------------------------------------- */ /* - * Lookup a directory entry by its associated cookie. - */ -struct tmpfs_dirent * -tmpfs_dir_lookupbycookie(struct tmpfs_node *node, off_t cookie) -{ - struct tmpfs_dirent *de; - - if (cookie == node->tn_dir.tn_readdir_lastn && - node->tn_dir.tn_readdir_lastp != NULL) { - return node->tn_dir.tn_readdir_lastp; - } - - TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) { - if (tmpfs_dircookie(de) == cookie) { - break; - } - } - - return de; -} - -/* --------------------------------------------------------------------- */ - -/* * Helper function for tmpfs_readdir. Returns as much directory entries * as can fit in the uio space. The read starts at uio->uio_offset. * The function returns 0 on success, -1 if there was not enough space @@ -816,27 +1070,47 @@ tmpfs_dir_lookupbycookie(struct tmpfs_node *node, off_t cookie) * error code if another error happens. */ int -tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, off_t *cntp) +tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, int cnt, + u_long *cookies, int *ncookies) { - int error; - off_t startcookie; + struct tmpfs_dir_cursor dc; struct tmpfs_dirent *de; + off_t off; + int error; TMPFS_VALIDATE_DIR(node); - /* Locate the first directory entry we have to return. We have cached - * the last readdir in the node, so use those values if appropriate. - * Otherwise do a linear scan to find the requested entry. */ - startcookie = uio->uio_offset; - MPASS(startcookie != TMPFS_DIRCOOKIE_DOT); - MPASS(startcookie != TMPFS_DIRCOOKIE_DOTDOT); - if (startcookie == TMPFS_DIRCOOKIE_EOF) { - return 0; - } else { - de = tmpfs_dir_lookupbycookie(node, startcookie); - } - if (de == NULL) { - return EINVAL; + off = 0; + switch (uio->uio_offset) { + case TMPFS_DIRCOOKIE_DOT: + error = tmpfs_dir_getdotdent(node, uio); + if (error != 0) + return (error); + uio->uio_offset = TMPFS_DIRCOOKIE_DOTDOT; + if (cnt != 0) + cookies[(*ncookies)++] = off = uio->uio_offset; + case TMPFS_DIRCOOKIE_DOTDOT: + error = tmpfs_dir_getdotdotdent(node, uio); + if (error != 0) + return (error); + de = tmpfs_dir_first(node, &dc); + if (de == NULL) + uio->uio_offset = TMPFS_DIRCOOKIE_EOF; + else + uio->uio_offset = tmpfs_dirent_cookie(de); + if (cnt != 0) + cookies[(*ncookies)++] = off = uio->uio_offset; + if (de == NULL) + return (0); + break; + case TMPFS_DIRCOOKIE_EOF: + return (0); + default: + de = tmpfs_dir_lookup_cookie(node, uio->uio_offset, &dc); + if (de == NULL) + return (EINVAL); + if (cnt != 0) + off = tmpfs_dirent_cookie(de); } /* Read as much entries as possible; i.e., until we reach the end of @@ -887,14 +1161,14 @@ tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, off_t *cntp) } d.d_namlen = de->td_namelen; MPASS(de->td_namelen < sizeof(d.d_name)); - (void)memcpy(d.d_name, de->td_name, de->td_namelen); + (void)memcpy(d.d_name, de->ud.td_name, de->td_namelen); d.d_name[de->td_namelen] = '\0'; d.d_reclen = GENERIC_DIRSIZ(&d); /* Stop reading if the directory entry we are treating is * bigger than the amount of data that can be returned. */ if (d.d_reclen > uio->uio_resid) { - error = -1; + error = EJUSTRETURN; break; } @@ -902,21 +1176,30 @@ tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, off_t *cntp) * advance pointers. */ error = uiomove(&d, d.d_reclen, uio); if (error == 0) { - (*cntp)++; - de = TAILQ_NEXT(de, td_entries); + de = tmpfs_dir_next(node, &dc); + if (cnt != 0) { + if (de == NULL) + off = TMPFS_DIRCOOKIE_EOF; + else + off = tmpfs_dirent_cookie(de); + MPASS(*ncookies < cnt); + cookies[(*ncookies)++] = off; + } } } while (error == 0 && uio->uio_resid > 0 && de != NULL); /* Update the offset and cache. */ - if (de == NULL) { - uio->uio_offset = TMPFS_DIRCOOKIE_EOF; - node->tn_dir.tn_readdir_lastn = 0; - node->tn_dir.tn_readdir_lastp = NULL; - } else { - node->tn_dir.tn_readdir_lastn = uio->uio_offset = tmpfs_dircookie(de); - node->tn_dir.tn_readdir_lastp = de; + if (cnt == 0) { + if (de == NULL) + off = TMPFS_DIRCOOKIE_EOF; + else + off = tmpfs_dirent_cookie(de); } + uio->uio_offset = off; + node->tn_dir.tn_readdir_lastn = off; + node->tn_dir.tn_readdir_lastp = de; + node->tn_status |= TMPFS_NODE_ACCESSED; return error; } @@ -943,7 +1226,7 @@ tmpfs_dir_whiteout_remove(struct vnode *dvp, struct componentname *cnp) de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp); MPASS(de != NULL && de->td_node == NULL); tmpfs_dir_detach(dvp, de); - tmpfs_free_dirent(VFS_TO_TMPFS(dvp->v_mount), de, TRUE); + tmpfs_free_dirent(VFS_TO_TMPFS(dvp->v_mount), de); } /* --------------------------------------------------------------------- */ @@ -1436,3 +1719,15 @@ out: return error; } + +static __inline int +tmpfs_dirtree_cmp(struct tmpfs_dirent *a, struct tmpfs_dirent *b) +{ + if (a->td_hash > b->td_hash) + return (1); + else if (a->td_hash < b->td_hash) + return (-1); + return (0); +} + +RB_GENERATE_STATIC(tmpfs_dir, tmpfs_dirent, uh.td_entries, tmpfs_dirtree_cmp); diff --git a/sys/fs/tmpfs/tmpfs_vfsops.c b/sys/fs/tmpfs/tmpfs_vfsops.c index b2aa786..8cf8693 100644 --- a/sys/fs/tmpfs/tmpfs_vfsops.c +++ b/sys/fs/tmpfs/tmpfs_vfsops.c @@ -294,19 +294,8 @@ tmpfs_unmount(struct mount *mp, int mntflags) while (node != NULL) { struct tmpfs_node *next; - if (node->tn_type == VDIR) { - struct tmpfs_dirent *de; - - de = TAILQ_FIRST(&node->tn_dir.tn_dirhead); - while (de != NULL) { - struct tmpfs_dirent *nde; - - nde = TAILQ_NEXT(de, td_entries); - tmpfs_free_dirent(tmp, de, FALSE); - de = nde; - node->tn_size -= sizeof(struct tmpfs_dirent); - } - } + if (node->tn_type == VDIR) + tmpfs_dir_destroy(tmp, node); next = LIST_NEXT(node, tn_entries); tmpfs_free_node(tmp, node); diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index 368e1ca..5e2ea65 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -847,7 +847,7 @@ tmpfs_remove(struct vop_remove_args *v) /* Free the directory entry we just deleted. Note that the node * referred by it will not be removed until the vnode is really * reclaimed. */ - tmpfs_free_dirent(tmp, de, TRUE); + tmpfs_free_dirent(tmp, de); node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED; error = 0; @@ -1263,26 +1263,25 @@ tmpfs_rename(struct vop_rename_args *v) fdnode->tn_links--; TMPFS_NODE_UNLOCK(fdnode); } - - /* Do the move: just remove the entry from the source directory - * and insert it into the target one. */ - tmpfs_dir_detach(fdvp, de); - if (fcnp->cn_flags & DOWHITEOUT) - tmpfs_dir_whiteout_add(fdvp, fcnp); - if (tcnp->cn_flags & ISWHITEOUT) - tmpfs_dir_whiteout_remove(tdvp, tcnp); - tmpfs_dir_attach(tdvp, de); } + /* Do the move: just remove the entry from the source directory + * and insert it into the target one. */ + tmpfs_dir_detach(fdvp, de); + + if (fcnp->cn_flags & DOWHITEOUT) + tmpfs_dir_whiteout_add(fdvp, fcnp); + if (tcnp->cn_flags & ISWHITEOUT) + tmpfs_dir_whiteout_remove(tdvp, tcnp); + /* If the name has changed, we need to make it effective by changing * it in the directory entry. */ if (newname != NULL) { MPASS(tcnp->cn_namelen <= MAXNAMLEN); - free(de->td_name, M_TMPFSNAME); - de->td_namelen = (uint16_t)tcnp->cn_namelen; - memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen); - de->td_name = newname; + free(de->ud.td_name, M_TMPFSNAME); + de->ud.td_name = newname; + tmpfs_dirent_init(de, tcnp->cn_nameptr, tcnp->cn_namelen); fnode->tn_status |= TMPFS_NODE_CHANGED; tdnode->tn_status |= TMPFS_NODE_MODIFIED; @@ -1291,15 +1290,20 @@ tmpfs_rename(struct vop_rename_args *v) /* If we are overwriting an entry, we have to remove the old one * from the target directory. */ if (tvp != NULL) { + struct tmpfs_dirent *tde; + /* Remove the old entry from the target directory. */ - de = tmpfs_dir_lookup(tdnode, tnode, tcnp); - tmpfs_dir_detach(tdvp, de); + tde = tmpfs_dir_lookup(tdnode, tnode, tcnp); + tmpfs_dir_detach(tdvp, tde); /* Free the directory entry we just deleted. Note that the * node referred by it will not be removed until the vnode is * really reclaimed. */ - tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, TRUE); + tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), tde); } + + tmpfs_dir_attach(tdvp, de); + cache_purge(fvp); if (tvp != NULL) cache_purge(tvp); @@ -1427,7 +1431,7 @@ tmpfs_rmdir(struct vop_rmdir_args *v) /* Free the directory entry we just deleted. Note that the node * referred by it will not be removed until the vnode is really * reclaimed. */ - tmpfs_free_dirent(tmp, de, TRUE); + tmpfs_free_dirent(tmp, de); /* Release the deleted vnode (will destroy the node, notify * interested parties and clean it from the cache). */ @@ -1473,8 +1477,8 @@ tmpfs_readdir(struct vop_readdir_args *v) int *ncookies = v->a_ncookies; int error; - off_t startoff; - off_t cnt = 0; + ssize_t startresid; + int cnt = 0; struct tmpfs_node *node; /* This operation only makes sense on directory nodes. */ @@ -1483,69 +1487,29 @@ tmpfs_readdir(struct vop_readdir_args *v) node = VP_TO_TMPFS_DIR(vp); - startoff = uio->uio_offset; + startresid = uio->uio_resid; - if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) { - error = tmpfs_dir_getdotdent(node, uio); - if (error != 0) - goto outok; - cnt++; - } - - if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) { - error = tmpfs_dir_getdotdotdent(node, uio); - if (error != 0) - goto outok; - cnt++; + if (cookies != NULL && ncookies != NULL) { + cnt = howmany(node->tn_size, sizeof(struct tmpfs_dirent)) + 2; + *cookies = malloc(cnt * sizeof(**cookies), M_TEMP, M_WAITOK); + *ncookies = 0; } - error = tmpfs_dir_getdents(node, uio, &cnt); + if (cnt == 0) + error = tmpfs_dir_getdents(node, uio, 0, NULL, NULL); + else + error = tmpfs_dir_getdents(node, uio, cnt, *cookies, ncookies); -outok: - MPASS(error >= -1); + if (error == EJUSTRETURN) + error = (uio->uio_resid != startresid) ? 0 : EINVAL; - if (error == -1) - error = (cnt != 0) ? 0 : EINVAL; + if (error != 0 && cnt != 0) + free(*cookies, M_TEMP); if (eofflag != NULL) *eofflag = (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF); - /* Update NFS-related variables. */ - if (error == 0 && cookies != NULL && ncookies != NULL) { - off_t i; - off_t off = startoff; - struct tmpfs_dirent *de = NULL; - - *ncookies = cnt; - *cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK); - - for (i = 0; i < cnt; i++) { - MPASS(off != TMPFS_DIRCOOKIE_EOF); - if (off == TMPFS_DIRCOOKIE_DOT) { - off = TMPFS_DIRCOOKIE_DOTDOT; - } else { - if (off == TMPFS_DIRCOOKIE_DOTDOT) { - de = TAILQ_FIRST(&node->tn_dir.tn_dirhead); - } else if (de != NULL) { - de = TAILQ_NEXT(de, td_entries); - } else { - de = tmpfs_dir_lookupbycookie(node, - off); - MPASS(de != NULL); - de = TAILQ_NEXT(de, td_entries); - } - if (de == NULL) - off = TMPFS_DIRCOOKIE_EOF; - else - off = tmpfs_dircookie(de); - } - - (*cookies)[i] = off; - } - MPASS(uio->uio_offset == off); - } - return error; } diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index 76d09dd..3a808ba 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -37,6 +37,7 @@ options SOFTUPDATES # Enable FFS soft updates support options UFS_ACL # Support for access control lists options UFS_DIRHASH # Improve performance on big directories options UFS_GJOURNAL # Enable gjournal-based UFS journaling +options QUOTA # Enable disk quotas for UFS options MD_ROOT # MD is a potential root device options NFSCL # New Network Filesystem Client options NFSD # New Network Filesystem Server @@ -331,15 +332,6 @@ device usb # USB Bus (required) device ukbd # Keyboard device umass # Disks/Mass storage - Requires scbus and da -# FireWire support -device firewire # FireWire bus code -# sbp(4) works for some systems but causes boot failure on others -#device sbp # SCSI over FireWire (Requires scbus and da) -device fwe # Ethernet over FireWire (non-standard!) -device fwip # IP over FireWire (RFC 2734,3146) -device dcons # Dumb console driver -device dcons_crom # Configuration ROM for dcons - # Sound support device sound # Generic sound driver (required) device snd_cmi # CMedia CMI8338/CMI8738 diff --git a/sys/i386/xen/xen_machdep.c b/sys/i386/xen/xen_machdep.c index f197976..3b3da6f 100644 --- a/sys/i386/xen/xen_machdep.c +++ b/sys/i386/xen/xen_machdep.c @@ -216,7 +216,9 @@ static mmu_update_t xpq_queue[MAX_VIRT_CPUS][XPQUEUE_SIZE]; #else static mmu_update_t xpq_queue[XPQUEUE_SIZE]; +#ifdef INVARIANTS static struct mmu_log xpq_queue_log[XPQUEUE_SIZE]; +#endif static int xpq_idx = 0; #define XPQ_QUEUE_LOG xpq_queue_log diff --git a/sys/ia64/conf/GENERIC b/sys/ia64/conf/GENERIC index e22450b..196e5be 100644 --- a/sys/ia64/conf/GENERIC +++ b/sys/ia64/conf/GENERIC @@ -60,6 +60,7 @@ options SYSVSHM # SYSV-style shared memory options UFS_ACL # Support for access control lists options UFS_DIRHASH # Hash-based directory lookup scheme options UFS_GJOURNAL # Enable gjournal-based UFS journaling +options QUOTA # Enable disk quotas for UFS options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B RT extensions # Debugging support. Always need this: @@ -77,7 +78,6 @@ options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones # Various "busses" -device firewire # FireWire bus code device miibus # MII bus support (Ethernet) device pci # PCI bus support device scbus # SCSI bus (required for ATA/SCSI) @@ -190,11 +190,6 @@ options IEEE80211_SUPPORT_MESH # builds everything including AR5416 (and later 11n NIC) support. options AH_SUPPORT_AR5416 -# FireWire support -device fwip # IP over FireWire (RFC 2734,3146) -# sbp(4) works for some systems but causes boot failure on others -#device sbp # SCSI over FireWire (need scbus & da) - # Various (pseudo) devices device ether # Ethernet support device faith # IPv6-to-IPv4 relaying (translation) diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 3dd6521..50b47fb 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -1074,7 +1074,9 @@ kern_wait6(struct thread *td, idtype_t idtype, id_t id, int *status, q = td->td_proc; if ((pid_t)id == WAIT_MYPGRP && (idtype == P_PID || idtype == P_PGID)) { + PROC_LOCK(q); id = (id_t)q->p_pgid; + PROC_UNLOCK(q); idtype = P_PGID; } diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 98f0156..7962ae1 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -498,6 +498,8 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk, case LK_DOWNGRADE: _lockmgr_assert(lk, KA_XLOCKED | KA_NOTRECURSED, file, line); + if (flags & LK_INTERLOCK) + class->lc_unlock(ilk); return (0); } } diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index e2e4081..73dfd70 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -133,10 +133,10 @@ sleepinit(void) * General sleep call. Suspends the current thread until a wakeup is * performed on the specified identifier. The thread will then be made * runnable with the specified priority. Sleeps at most timo/hz seconds - * (0 means no timeout). If pri includes PCATCH flag, signals are checked - * before and after sleeping, else signals are not checked. Returns 0 if + * (0 means no timeout). If pri includes the PCATCH flag, let signals + * interrupt the sleep, otherwise ignore them while sleeping. Returns 0 if * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a - * signal needs to be delivered, ERESTART is returned if the current system + * signal becomes pending, ERESTART is returned if the current system * call should be restarted if possible, and EINTR is returned if the system * call should be interrupted by the signal (return EINTR). * diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c index 510033f..fe10a87 100644 --- a/sys/kern/subr_param.c +++ b/sys/kern/subr_param.c @@ -160,7 +160,7 @@ static const char *const vm_bnames[] = { "Plex86", /* Plex86 */ "Bochs", /* Bochs */ "Xen", /* Xen */ - "BHYVE", /* BHyVe */ + "BHYVE", /* bhyve */ NULL }; diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 5926e15..3f10669 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -559,7 +559,7 @@ vfs_donmount(struct thread *td, uint64_t fsflags, struct uio *fsoptions) if (error || fstype[fstypelen - 1] != '\0') { error = EINVAL; if (errmsg != NULL) - strlcpy(errmsg, "Invalid fstype", errmsg_len); + strncpy(errmsg, "Invalid fstype", errmsg_len); goto bail; } fspathlen = 0; @@ -567,7 +567,7 @@ vfs_donmount(struct thread *td, uint64_t fsflags, struct uio *fsoptions) if (error || fspath[fspathlen - 1] != '\0') { error = EINVAL; if (errmsg != NULL) - strlcpy(errmsg, "Invalid fspath", errmsg_len); + strncpy(errmsg, "Invalid fspath", errmsg_len); goto bail; } @@ -1447,7 +1447,7 @@ vfs_filteropt(struct vfsoptlist *opts, const char **legal) if (ret != 0) { TAILQ_FOREACH(opt, opts, link) { if (strcmp(opt->name, "errmsg") == 0) { - strlcpy((char *)opt->value, errmsg, opt->len); + strncpy((char *)opt->value, errmsg, opt->len); break; } } @@ -1705,103 +1705,6 @@ vfs_copyopt(opts, name, dest, len) return (ENOENT); } -/* - * These are helper functions for filesystems to traverse all - * their vnodes. See MNT_VNODE_FOREACH() in sys/mount.h. - * - * This interface has been deprecated in favor of MNT_VNODE_FOREACH_ALL. - */ - -MALLOC_DECLARE(M_VNODE_MARKER); - -struct vnode * -__mnt_vnode_next(struct vnode **mvp, struct mount *mp) -{ - struct vnode *vp; - - mtx_assert(MNT_MTX(mp), MA_OWNED); - - KASSERT((*mvp)->v_mount == mp, ("marker vnode mount list mismatch")); - if (should_yield()) { - MNT_IUNLOCK(mp); - kern_yield(PRI_USER); - MNT_ILOCK(mp); - } - vp = TAILQ_NEXT(*mvp, v_nmntvnodes); - while (vp != NULL && vp->v_type == VMARKER) - vp = TAILQ_NEXT(vp, v_nmntvnodes); - - /* Check if we are done */ - if (vp == NULL) { - __mnt_vnode_markerfree(mvp, mp); - return (NULL); - } - TAILQ_REMOVE(&mp->mnt_nvnodelist, *mvp, v_nmntvnodes); - TAILQ_INSERT_AFTER(&mp->mnt_nvnodelist, vp, *mvp, v_nmntvnodes); - return (vp); -} - -struct vnode * -__mnt_vnode_first(struct vnode **mvp, struct mount *mp) -{ - struct vnode *vp; - - mtx_assert(MNT_MTX(mp), MA_OWNED); - - vp = TAILQ_FIRST(&mp->mnt_nvnodelist); - while (vp != NULL && vp->v_type == VMARKER) - vp = TAILQ_NEXT(vp, v_nmntvnodes); - - /* Check if we are done */ - if (vp == NULL) { - *mvp = NULL; - return (NULL); - } - MNT_REF(mp); - MNT_IUNLOCK(mp); - *mvp = (struct vnode *) malloc(sizeof(struct vnode), - M_VNODE_MARKER, - M_WAITOK | M_ZERO); - MNT_ILOCK(mp); - (*mvp)->v_type = VMARKER; - - vp = TAILQ_FIRST(&mp->mnt_nvnodelist); - while (vp != NULL && vp->v_type == VMARKER) - vp = TAILQ_NEXT(vp, v_nmntvnodes); - - /* Check if we are done */ - if (vp == NULL) { - MNT_IUNLOCK(mp); - free(*mvp, M_VNODE_MARKER); - MNT_ILOCK(mp); - *mvp = NULL; - MNT_REL(mp); - return (NULL); - } - (*mvp)->v_mount = mp; - TAILQ_INSERT_AFTER(&mp->mnt_nvnodelist, vp, *mvp, v_nmntvnodes); - return (vp); -} - - -void -__mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp) -{ - - if (*mvp == NULL) - return; - - mtx_assert(MNT_MTX(mp), MA_OWNED); - - KASSERT((*mvp)->v_mount == mp, ("marker vnode mount list mismatch")); - TAILQ_REMOVE(&mp->mnt_nvnodelist, *mvp, v_nmntvnodes); - MNT_IUNLOCK(mp); - free(*mvp, M_VNODE_MARKER); - MNT_ILOCK(mp); - *mvp = NULL; - MNT_REL(mp); -} - int __vfs_statfs(struct mount *mp, struct statfs *sbp) { diff --git a/sys/mips/atheros/ar71xx_pci.c b/sys/mips/atheros/ar71xx_pci.c index 126537c..9b88f60 100644 --- a/sys/mips/atheros/ar71xx_pci.c +++ b/sys/mips/atheros/ar71xx_pci.c @@ -81,6 +81,7 @@ struct ar71xx_pci_softc { device_t sc_dev; int sc_busno; + int sc_baseslot; struct rman sc_mem_rman; struct rman sc_irq_rman; @@ -395,6 +396,16 @@ ar71xx_pci_attach(device_t dev) AR71XX_PCI_IRQ_END) != 0) panic("ar71xx_pci_attach: failed to set up IRQ rman"); + /* + * Check if there is a base slot hint. Otherwise use default value. + */ + if (resource_int_value(device_get_name(dev), + device_get_unit(dev), "baseslot", &sc->sc_baseslot) != 0) { + device_printf(dev, + "%s: missing hint '%s', default to AR71XX_PCI_BASE_SLOT\n", + __func__, "baseslot"); + sc->sc_baseslot = AR71XX_PCI_BASE_SLOT; + } ATH_WRITE_REG(AR71XX_PCI_INTR_STATUS, 0); ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, 0); @@ -648,11 +659,13 @@ ar71xx_pci_maxslots(device_t dev) static int ar71xx_pci_route_interrupt(device_t pcib, device_t device, int pin) { - if (pci_get_slot(device) < AR71XX_PCI_BASE_SLOT) + struct ar71xx_pci_softc *sc = device_get_softc(pcib); + + if (pci_get_slot(device) < sc->sc_baseslot) panic("%s: PCI slot %d is less then AR71XX_PCI_BASE_SLOT", __func__, pci_get_slot(device)); - return (pci_get_slot(device) - AR71XX_PCI_BASE_SLOT); + return (pci_get_slot(device) - sc->sc_baseslot); } static device_method_t ar71xx_pci_methods[] = { diff --git a/sys/mips/conf/OCTEON1 b/sys/mips/conf/OCTEON1 index 1d637d8..3ddb164 100644 --- a/sys/mips/conf/OCTEON1 +++ b/sys/mips/conf/OCTEON1 @@ -39,6 +39,7 @@ makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols # Board-specific support that cannot be auto-detected at runtime. #options OCTEON_VENDOR_LANNER # Support for Lanner boards. #options OCTEON_VENDOR_RADISYS # Support for Radisys boards. +#options OCTEON_VENDOR_UBIQUITI # Support for Ubiquiti boards. #options OCTEON_BOARD_CAPK_0100ND # Support for CAPK-0100nd. # Compile for a specified Octeon model. If not specified, support for diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h index 5e71dd8..a84a0b8 100644 --- a/sys/net/if_pfsync.h +++ b/sys/net/if_pfsync.h @@ -1,6 +1,4 @@ -/* $OpenBSD: if_pfsync.h,v 1.35 2008/06/29 08:42:15 mcbride Exp $ */ - -/* +/*- * Copyright (c) 2001 Michael Shalayeff * All rights reserved. * @@ -26,7 +24,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -/* +/*- * Copyright (c) 2008 David Gwynne <dlg@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -42,6 +40,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/* + * $OpenBSD: if_pfsync.h,v 1.35 2008/06/29 08:42:15 mcbride Exp $ + * $FreeBSD$ + */ + + #ifndef _NET_IF_PFSYNC_H_ #define _NET_IF_PFSYNC_H_ @@ -63,20 +67,6 @@ #define PFSYNC_ACT_EOF 12 /* end of frame */ #define PFSYNC_ACT_MAX 13 -#define PFSYNC_ACTIONS "CLR ST", \ - "INS ST", \ - "INS ST ACK", \ - "UPD ST", \ - "UPD ST COMP", \ - "UPD ST REQ", \ - "DEL ST", \ - "DEL ST COMP", \ - "INS FR", \ - "DEL FR", \ - "BULK UPD STAT", \ - "TDB UPD", \ - "EOF" - #define PFSYNC_HMAC_LEN 20 /* diff --git a/sys/net/zlib.c b/sys/net/zlib.c index 8fc8cab..b348248 100644 --- a/sys/net/zlib.c +++ b/sys/net/zlib.c @@ -25,7 +25,14 @@ #define MY_ZCALLOC #if defined(__FreeBSD__) && defined(_KERNEL) -#define inflate inflate_ppp /* FreeBSD already has an inflate :-( */ +#define _tr_init _zlib104_tr_init +#define _tr_align _zlib104_tr_align +#define _tr_tally _zlib104_tr_tally +#define _tr_flush_block _zlib104_tr_flush_block +#define _tr_stored_block _zlib104_tr_stored_block +#define inflate_fast _zlib104_inflate_fast +#define inflate _zlib104_inflate +#define zlibVersion _zlib104_Version #endif diff --git a/sys/net/zlib.h b/sys/net/zlib.h index 44aa425..04941df 100644 --- a/sys/net/zlib.h +++ b/sys/net/zlib.h @@ -511,7 +511,7 @@ extern int EXPORT inflateInit OF((z_streamp strm)); */ #if defined(__FreeBSD__) && defined(_KERNEL) -#define inflate inflate_ppp /* FreeBSD already has an inflate :-( */ +#define inflate _zlib104_inflate /* FreeBSD already has an inflate :-( */ #endif extern int EXPORT inflate OF((z_streamp strm, int flush)); diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c index 675f3da..7087748 100644 --- a/sys/net80211/ieee80211_hostap.c +++ b/sys/net80211/ieee80211_hostap.c @@ -2324,5 +2324,19 @@ ieee80211_recv_pspoll(struct ieee80211_node *ni, struct mbuf *m0) ifp = vap->iv_ic->ic_ifp; else ifp = vap->iv_ifp; - (void) ifp->if_transmit(ifp, m); + + /* + * Free any node ref which this mbuf may have. + * + * Much like psq_mfree(), we assume that M_ENCAP nodes have + * node references. + */ + if (ifp->if_transmit(ifp, m) != 0) { + /* + * XXX m is invalid (freed) at this point, determine M_ENCAP + * an alternate way. + */ + if (ifp == vap->iv_ic->ic_ifp) + ieee80211_free_node(ni); + } } diff --git a/sys/net80211/ieee80211_hwmp.c b/sys/net80211/ieee80211_hwmp.c index fcc4af1..2f8ec85 100644 --- a/sys/net80211/ieee80211_hwmp.c +++ b/sys/net80211/ieee80211_hwmp.c @@ -1227,6 +1227,8 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, struct mbuf *m, *next; uint32_t metric = 0; const uint8_t *addr; + int is_encap; + struct ieee80211_node *ni_encap; if (ni == vap->iv_bss || ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) @@ -1403,11 +1405,21 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, (struct ieee80211_node *)(uintptr_t) ieee80211_mac_hash(ic, addr)); /* either dest or ext_dest */ for (; m != NULL; m = next) { + is_encap = !! (m->m_flags & M_ENCAP); + ni_encap = (struct ieee80211_node *) m->m_pkthdr.rcvif; next = m->m_nextpkt; m->m_nextpkt = NULL; IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "flush queued frame %p len %d", m, m->m_pkthdr.len); - ifp->if_transmit(ifp, m); + + /* + * If the mbuf has M_ENCAP set, ensure we free it. + * Note that after if_transmit() is called, m is invalid. + */ + if (ifp->if_transmit(ifp, m) != 0) { + if (is_encap) + ieee80211_free_node(ni_encap); + } } #undef IS_PROXY #undef PROXIED_BY_US diff --git a/sys/net80211/ieee80211_radiotap.h b/sys/net80211/ieee80211_radiotap.h index f11ba73..388d70e 100644 --- a/sys/net80211/ieee80211_radiotap.h +++ b/sys/net80211/ieee80211_radiotap.h @@ -194,9 +194,20 @@ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_ANTENNA = 11, IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, IEEE80211_RADIOTAP_DB_ANTNOISE = 13, - /* NB: gap for netbsd definitions */ + /* + * 14-17 are from Linux, they overlap the netbsd-specific + * fields. + */ + IEEE80211_RADIOTAP_RX_FLAGS = 14, + IEEE80211_RADIOTAP_TX_FLAGS = 15, + IEEE80211_RADIOTAP_RTS_RETRIES = 16, + IEEE80211_RADIOTAP_DATA_RETRIES = 17, + IEEE80211_RADIOTAP_XCHANNEL = 18, IEEE80211_RADIOTAP_MCS = 19, + IEEE80211_RADIOTAP_AMPDU_STATUS = 20, + + IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, IEEE80211_RADIOTAP_VENDOREXT = 30, IEEE80211_RADIOTAP_EXT = 31, }; diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 6cb37e5..2b805c6 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -819,19 +819,14 @@ in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin, return (error); /* - * Give the interface a chance to initialize if this is its first - * address, and to validate the address if necessary. - * - * Historically, drivers managed IFF_UP flag theirselves, so we - * need to check whether driver did that. + * Give the interface a chance to initialize + * if this is its first address, + * and to validate the address if necessary. */ - flags = ifp->if_flags; if (ifp->if_ioctl != NULL && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) != 0) /* LIST_REMOVE(ia, ia_hash) is done in in_control */ return (error); - if ((ifp->if_flags & IFF_UP) && (flags & IFF_UP) == 0) - if_up(ifp); /* * Be compatible with network classes, if netmask isn't supplied, diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 08dd259..e260e5d 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1874,18 +1874,9 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, ia->ia_addr = *sin6; if (ifacount <= 1 && ifp->if_ioctl) { - int flags; - - /* - * Historically, drivers managed IFF_UP flag theirselves, so we - * need to check whether driver did that. - */ - flags = ifp->if_flags; error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); if (error) return (error); - if ((ifp->if_flags & IFF_UP) && (flags & IFF_UP) == 0) - if_up(ifp); } ia->ia_ifa.ifa_metric = ifp->if_metric; diff --git a/sys/pc98/conf/GENERIC b/sys/pc98/conf/GENERIC index d2f6bc0..2b048a9 100644 --- a/sys/pc98/conf/GENERIC +++ b/sys/pc98/conf/GENERIC @@ -238,45 +238,11 @@ device bpf # Berkeley packet filter #device ohci # OHCI PCI->USB interface #device ehci # EHCI PCI->USB interface (USB 2.0) #device usb # USB Bus (required) -#device udbp # USB Double Bulk Pipe devices (needs netgraph) -#device uhid # "Human Interface Devices" #device ukbd # Keyboard -#device ulpt # Printer #device umass # Disks/Mass storage - Requires scbus and da -#device ums # Mouse -#device urio # Diamond Rio 500 MP3 player -# USB Serial devices -#device uark # Technologies ARK3116 based serial adapters -#device ubsa # Belkin F5U103 and compatible serial adapters -#device ubser # BWCT console serial adapters -#device uftdi # For FTDI usb serial adapters -#device uipaq # Some WinCE based devices -#device uplcom # Prolific PL-2303 serial adapters -#device uslcom # SI Labs CP2101/CP2102 serial adapters -#device uvisor # Visor and Palm devices -#device uvscom # USB serial support for DDI pocket's PHS -# USB Ethernet, requires miibus -#device aue # ADMtek USB Ethernet -#device axe # ASIX Electronics USB Ethernet -#device cdce # Generic USB over Ethernet -#device cue # CATC USB Ethernet -#device kue # Kawasaki LSI USB Ethernet -#device rue # RealTek RTL8150 USB Ethernet -#device udav # Davicom DM9601E USB -# USB Wireless -#device rum # Ralink Technology RT2501USB wireless NICs -#device uath # Atheros AR5523 wireless NICs -#device ural # Ralink Technology RT2500USB wireless NICs -#device zyd # ZyDAS zd1211/zd1211b wireless NICs - -# FireWire support -#device firewire # FireWire bus code -#device sbp # SCSI over FireWire (Requires scbus and da) -#device fwe # Ethernet over FireWire (non-standard!) # Sound support #device sound # Generic sound driver (required) #device snd_mss # Microsoft Sound System #device "snd_sb16" # Sound Blaster 16 #device snd_sbc # Sound Blaster -#device snd_uaudio # USB Audio diff --git a/sys/powerpc/conf/GENERIC b/sys/powerpc/conf/GENERIC index 7f31d43..f7c3511 100644 --- a/sys/powerpc/conf/GENERIC +++ b/sys/powerpc/conf/GENERIC @@ -41,6 +41,7 @@ options SOFTUPDATES #Enable FFS soft updates support options UFS_ACL #Support for access control lists options UFS_DIRHASH #Improve performance on big directories options UFS_GJOURNAL #Enable gjournal-based UFS journaling +options QUOTA #Enable disk quotas for UFS options MD_ROOT #MD is a potential root device options NFSCL #New Network Filesystem Client options NFSD #New Network Filesystem Server @@ -183,12 +184,6 @@ device kue # Kawasaki LSI USB Ethernet options IEEE80211_SUPPORT_MESH options AH_SUPPORT_AR5416 -# FireWire support -device firewire # FireWire bus code -# sbp(4) works for some systems but causes boot failure on others -device sbp # SCSI over FireWire (Requires scbus and da) -device fwe # Ethernet over FireWire (non-standard!) - # Misc device iicbus # I2C bus code device kiic # Keywest I2C diff --git a/sys/powerpc/conf/GENERIC64 b/sys/powerpc/conf/GENERIC64 index 0e1555d..a2a283f 100644 --- a/sys/powerpc/conf/GENERIC64 +++ b/sys/powerpc/conf/GENERIC64 @@ -40,6 +40,7 @@ options SOFTUPDATES #Enable FFS soft updates support options UFS_ACL #Support for access control lists options UFS_DIRHASH #Improve performance on big directories options UFS_GJOURNAL #Enable gjournal-based UFS journaling +options QUOTA #Enable disk quotas for UFS options MD_ROOT #MD is a potential root device options NFSCL #New Network Filesystem Client options NFSD #New Network Filesystem Server diff --git a/sys/sparc64/conf/GENERIC b/sys/sparc64/conf/GENERIC index bcd94cd..f9d3b93 100644 --- a/sys/sparc64/conf/GENERIC +++ b/sys/sparc64/conf/GENERIC @@ -36,6 +36,7 @@ options SOFTUPDATES # Enable FFS soft updates support options UFS_ACL # Support for access control lists options UFS_DIRHASH # Improve performance on big directories options UFS_GJOURNAL # Enable gjournal-based UFS journaling +options QUOTA # Enable disk quotas for UFS options MD_ROOT # MD is a potential root device options NFSCL # New Network Filesystem Client options NFSD # New Network Filesystem Server @@ -238,15 +239,6 @@ device usb # USB Bus (required) device ukbd # Keyboard device umass # Disks/Mass storage - Requires scbus and da -# FireWire support -device firewire # FireWire bus code -# sbp(4) works for some systems but causes boot failure on others -#device sbp # SCSI over FireWire (Requires scbus and da) -device fwe # Ethernet over FireWire (non-standard!) -device fwip # IP over FireWire (RFC 2734,3146) -device dcons # Dumb console driver -device dcons_crom # Configuration ROM for dcons - # Sound support device sound # Generic sound driver (required) device snd_audiocs # Crystal Semiconductor CS4231 diff --git a/sys/sparc64/sparc64/interrupt.S b/sys/sparc64/sparc64/interrupt.S index fc144f4..179eeb6 100644 --- a/sys/sparc64/sparc64/interrupt.S +++ b/sys/sparc64/sparc64/interrupt.S @@ -83,13 +83,13 @@ ENTRY(intr_vector) * The 2nd word points to code to execute and the 3rd is an argument * to pass. Jump to it. */ - brnz,a,pt %g3, 1f - srlx %g3, 60, %g6 + brnz,pt %g3, 1f /* * NB: Zeus CPUs set some undocumented bits in the first data word. */ - jmpl %g4, %g0 and %g3, IV_MAX - 1, %g3 + jmpl %g4, %g0 + nop /* NOTREACHED */ /* @@ -98,7 +98,8 @@ ENTRY(intr_vector) * 4 bits of the 1st data word specify a priority, and the 2nd and * 3rd a function and argument. */ -1: brnz,a,pn %g6, 2f +1: srlx %g3, 60, %g6 + brnz,a,pn %g6, 2f clr %g3 /* diff --git a/sys/sys/mount.h b/sys/sys/mount.h index ed2b002..992227c 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -225,29 +225,6 @@ void __mnt_vnode_markerfree_active(struct vnode **mvp, struct mount *); #define MNT_VNODE_FOREACH_ACTIVE_ABORT(mp, mvp) \ __mnt_vnode_markerfree_active(&(mvp), (mp)) -/* - * Definitions for MNT_VNODE_FOREACH. - * - * This interface has been deprecated in favor of MNT_VNODE_FOREACH_ALL. - */ -struct vnode *__mnt_vnode_next(struct vnode **mvp, struct mount *mp); -struct vnode *__mnt_vnode_first(struct vnode **mvp, struct mount *mp); -void __mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp); - -#define MNT_VNODE_FOREACH(vp, mp, mvp) \ - for (vp = __mnt_vnode_first(&(mvp), (mp)); \ - (vp) != NULL; vp = __mnt_vnode_next(&(mvp), (mp))) - -#define MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp) \ - __mnt_vnode_markerfree(&(mvp), (mp)) - -#define MNT_VNODE_FOREACH_ABORT(mp, mvp) \ - do { \ - MNT_ILOCK(mp); \ - MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); \ - MNT_IUNLOCK(mp); \ - } while (0) - #define MNT_ILOCK(mp) mtx_lock(&(mp)->mnt_mtx) #define MNT_ITRYLOCK(mp) mtx_trylock(&(mp)->mnt_mtx) #define MNT_IUNLOCK(mp) mtx_unlock(&(mp)->mnt_mtx) |