Merge branch 'stable-3.2' into pandora-3.2
authorGrazvydas Ignotas <notasas@gmail.com>
Sun, 24 Jun 2018 15:26:36 +0000 (18:26 +0300)
committerGrazvydas Ignotas <notasas@gmail.com>
Sun, 24 Jun 2018 15:33:21 +0000 (18:33 +0300)
754 files changed:
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/cgroups/cpusets.txt
Documentation/device-mapper/thin-provisioning.txt
Documentation/filesystems/ext4.txt
Documentation/gcov.txt
Documentation/kernel-parameters.txt
Documentation/speculation.txt [new file with mode: 0644]
Documentation/x86/pti.txt [new file with mode: 0644]
Makefile
arch/alpha/include/asm/types.h
arch/alpha/kernel/pci_impl.h
arch/alpha/kernel/process.c
arch/arm/kernel/traps.c
arch/arm/mach-pxa/Kconfig
arch/cris/arch-v10/lib/Makefile
arch/m32r/include/asm/io.h
arch/m32r/kernel/ptrace.c
arch/mips/ar7/clock.c
arch/mips/ar7/platform.c
arch/mips/bcm63xx/clk.c
arch/mips/boot/compressed/Makefile
arch/mips/kernel/branch.c
arch/mips/kernel/mips_ksyms.c
arch/mips/kernel/syscall.c
arch/mips/mm/Makefile
arch/mips/mm/page-funcs.S [new file with mode: 0644]
arch/mips/mm/page.c
arch/mips/txx9/generic/setup.c
arch/mips/txx9/generic/setup_tx4939.c
arch/mips/txx9/rbtx4939/setup.c
arch/mn10300/mm/misalignment.c
arch/openrisc/kernel/traps.c
arch/parisc/kernel/syscall_table.S
arch/powerpc/boot/4xx.c
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/topology.h
arch/powerpc/lib/sstep.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/s390/include/asm/syscall.h
arch/s390/include/asm/system.h
arch/s390/kernel/compat_linux.c
arch/s390/kernel/dis.c
arch/s390/mm/gup.c
arch/sh/boards/mach-se/770x/setup.c
arch/sh/include/cpu-sh4/cpu/sh7722.h
arch/sh/include/cpu-sh4/cpu/sh7757.h
arch/sh/include/mach-se/mach/se.h
arch/sh/kernel/traps_32.c
arch/tile/kernel/setup.c
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/boot/compressed/misc.h
arch/x86/crypto/crc32c-intel.c
arch/x86/crypto/salsa20_glue.c
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/alternative-asm.h
arch/x86/include/asm/alternative.h
arch/x86/include/asm/asm.h
arch/x86/include/asm/bitops.h
arch/x86/include/asm/cmdline.h [new file with mode: 0644]
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/desc.h
arch/x86/include/asm/elf.h
arch/x86/include/asm/hardirq.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/intel-family.h [new file with mode: 0644]
arch/x86/include/asm/kaiser.h [new file with mode: 0644]
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/kvm_para.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/mmu.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/msr.h
arch/x86/include/asm/nospec-branch.h [new file with mode: 0644]
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_64.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/processor-flags.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/system.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/tlbflush.h
arch/x86/include/asm/traps.h
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/uaccess_32.h
arch/x86/include/asm/uaccess_64.h
arch/x86/include/asm/vsyscall.h
arch/x86/include/asm/xen/hypercall.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/alternative.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/bugs_64.c [deleted file]
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/espfix_64.c
arch/x86/kernel/head_64.S
arch/x86/kernel/hpet.c
arch/x86/kernel/init_task.c
arch/x86/kernel/irq_32.c
arch/x86/kernel/irqinit.c
arch/x86/kernel/kprobes.c
arch/x86/kernel/kvm.c
arch/x86/kernel/ldt.c
arch/x86/kernel/paravirt_patch_64.c
arch/x86/kernel/process_64.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/traps.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kernel/vsyscall_64.c
arch/x86/kvm/lapic.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/lib/Makefile
arch/x86/lib/checksum_32.S
arch/x86/lib/clear_page_64.S
arch/x86/lib/cmdline.c [new file with mode: 0644]
arch/x86/lib/copy_page_64.S
arch/x86/lib/copy_user_64.S
arch/x86/lib/getuser.S
arch/x86/lib/memcpy_64.S
arch/x86/lib/memmove_64.S
arch/x86/lib/memset_64.S
arch/x86/lib/msr.c
arch/x86/lib/retpoline-export.c [new file with mode: 0644]
arch/x86/lib/retpoline.S [new file with mode: 0644]
arch/x86/lib/usercopy_32.c
arch/x86/lib/x86-opcode-map.txt
arch/x86/mm/Makefile
arch/x86/mm/init.c
arch/x86/mm/init_64.c
arch/x86/mm/kaiser.c [new file with mode: 0644]
arch/x86/mm/pgtable.c
arch/x86/mm/tlb.c
arch/x86/oprofile/op_model_ppro.c
arch/x86/pci/fixup.c
arch/x86/xen/enlighten.c
arch/x86/xen/smp.c
arch/xtensa/kernel/pci-dma.c
arch/xtensa/kernel/xtensa_ksyms.c
arch/xtensa/mm/cache.c
block/blk-core.c
crypto/af_alg.c
crypto/ahash.c
crypto/algapi.c
crypto/algif_hash.c
crypto/crc32c.c
crypto/cryptd.c
crypto/hmac.c
crypto/salsa20_generic.c
crypto/shash.c
drivers/acpi/acpica/nsrepair.c
drivers/acpi/apei/erst.c
drivers/acpi/sbshc.c
drivers/ata/ahci.c
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/ata/pata_amd.c
drivers/ata/pata_cs5536.c
drivers/base/Kconfig
drivers/base/bus.c
drivers/base/cpu.c
drivers/base/isa.c
drivers/base/power/domain.c
drivers/block/DAC960.c
drivers/block/drbd/drbd_main.c
drivers/block/pktcdvd.c
drivers/cdrom/cdrom.c
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm_tis.c
drivers/crypto/n2_core.c
drivers/crypto/talitos.c
drivers/edac/i7300_edac.c
drivers/edac/mce_amd.h
drivers/firmware/dmi_scan.c
drivers/gpio/gpio-tegra.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_page_alloc.c
drivers/hid/hid-roccat-kovaplus.c
drivers/hid/usbhid/hid-core.c
drivers/hv/hv.c
drivers/hwmon/pmbus/pmbus_core.c
drivers/hwmon/w83781d.c
drivers/i2c/i2c-core.c
drivers/idle/intel_idle.c
drivers/infiniband/core/cache.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/device.c
drivers/infiniband/core/ucma.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/qib/qib_rc.c
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/ff-core.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/matrix_keypad.c
drivers/input/misc/adxl34x.c
drivers/input/misc/uinput.c
drivers/input/mouse/elantech.c
drivers/input/mouse/trackpoint.c
drivers/input/mouse/trackpoint.h
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042.c
drivers/input/tablet/gtco.c
drivers/iommu/amd_iommu.c
drivers/iommu/intel-iommu.c
drivers/isdn/gigaset/capi.c
drivers/isdn/hardware/eicon/capi20.h
drivers/isdn/hardware/mISDN/hfcpci.c
drivers/md/dm-bufio.c
drivers/md/dm-mpath.c
drivers/md/dm-snap.c
drivers/md/dm-table.c
drivers/md/dm-thin-metadata.c
drivers/md/dm.c
drivers/md/persistent-data/dm-btree.c
drivers/md/raid1.c
drivers/md/raid5.c
drivers/media/common/tuners/max2165.c
drivers/media/common/tuners/tda18212.c
drivers/media/common/tuners/tda18218.c
drivers/media/common/tuners/xc4000.c
drivers/media/dvb/bt8xx/bt878.c
drivers/media/dvb/dvb-usb/cxusb.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/mxl111sf.c
drivers/media/dvb/frontends/tda8261_cfg.h
drivers/media/rc/imon.c
drivers/media/rc/ir-lirc-codec.c
drivers/media/rc/mceusb.c
drivers/media/rc/redrat3.c
drivers/media/video/Makefile
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/omap/omap_vout.c
drivers/media/video/saa7164/saa7164-buffer.c
drivers/media/video/saa7164/saa7164-bus.c
drivers/media/video/saa7164/saa7164-core.c
drivers/media/video/saa7164/saa7164-fw.c
drivers/media/video/saa7164/saa7164-types.h
drivers/media/video/saa7164/saa7164.h
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/v4l2-compat-ioctl32.c
drivers/media/video/v4l2-ioctl.c
drivers/misc/eeprom/at24.c
drivers/misc/enclosure.c
drivers/misc/vmw_balloon.c
drivers/mmc/card/block.c
drivers/mmc/host/s3cmci.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/devices/sst25l.c
drivers/mtd/nand/nand_base.c
drivers/mtd/ubi/vmt.c
drivers/net/bonding/bond_main.c
drivers/net/can/ti_hecc.c
drivers/net/can/usb/ems_usb.c
drivers/net/can/usb/esd_usb2.c
drivers/net/ethernet/amd/nmclan_cs.c
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
drivers/net/ethernet/freescale/fs_enet/fs_enet.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/lib.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/mellanox/mlx4/en_main.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/fw.h
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
drivers/net/ethernet/realtek/atp.c
drivers/net/ethernet/realtek/atp.h
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/sfc/mcdi_mac.c
drivers/net/macvtap.c
drivers/net/phy/marvell.c
drivers/net/ppp/pppoe.c
drivers/net/slip/slip.c
drivers/net/tun.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/smsc95xx.c
drivers/net/wireless/ath/ath6kl/hif.h
drivers/net/wireless/ath/ath6kl/sdio.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/rayctl.h
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rtlwifi/rtl8192de/dm.c
drivers/net/wireless/rtlwifi/rtl8192se/phy.c
drivers/net/wireless/wl1251/main.c
drivers/net/wireless/wl12xx/wl12xx.h
drivers/of/fdt.c
drivers/parisc/dino.c
drivers/parisc/lba_pci.c
drivers/pci/hotplug/shpchp_hpc.c
drivers/pci/pci-driver.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/quirks.c
drivers/platform/x86/samsung-laptop.c
drivers/rtc/interface.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-nuc900.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_dbf.c
drivers/s390/scsi/zfcp_dbf.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_fc.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_scsi.c
drivers/scsi/aacraid/aachba.c
drivers/scsi/advansys.c
drivers/scsi/aic94xx/aic94xx_sds.c
drivers/scsi/arm/fas216.c
drivers/scsi/bfa/bfad_debugfs.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/ibmvscsi/ibmvfc.h
drivers/scsi/libiscsi.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/mac_esp.c
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/sd.c
drivers/scsi/sun_esp.c
drivers/staging/bcm/Kconfig
drivers/staging/comedi/drivers/vmk80xx.c
drivers/staging/cxt1e1/functions.c
drivers/staging/cxt1e1/pmcc4.h
drivers/staging/iio/accel/lis3l02dq_core.c
drivers/staging/iio/adc/ad7298_ring.c
drivers/staging/iio/gyro/adis16080_core.c
drivers/staging/iio/light/tsl2563.c
drivers/staging/iio/meter/ade7759.c
drivers/staging/iio/resolver/ad2s1210.c
drivers/staging/media/as102/as102_fw.c
drivers/staging/media/lirc/lirc_zilog.c
drivers/staging/slicoss/slicoss.c
drivers/staging/usbip/stub_dev.c
drivers/staging/usbip/stub_main.c
drivers/staging/usbip/stub_rx.c
drivers/staging/usbip/stub_tx.c
drivers/staging/usbip/usbip_common.c
drivers/staging/usbip/usbip_common.h
drivers/staging/usbip/userspace/libsrc/usbip_common.c
drivers/staging/usbip/userspace/libsrc/vhci_driver.c
drivers/staging/usbip/userspace/src/utils.c
drivers/staging/usbip/vhci_hcd.c
drivers/staging/usbip/vhci_rx.c
drivers/staging/usbip/vhci_sysfs.c
drivers/staging/usbip/vhci_tx.c
drivers/staging/vt6655/device_main.c
drivers/staging/wlan-ng/p80211netdev.c
drivers/staging/wlan-ng/prism2fw.c
drivers/tty/n_tty.c
drivers/tty/serial/8250_pci.c
drivers/tty/serial/sh-sci.c
drivers/tty/vt/vt.c
drivers/usb/class/cdc-acm.c
drivers/usb/core/config.c
drivers/usb/core/devio.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/inode.c
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ohci-q.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/usbtest.c
drivers/usb/mon/mon_bin.c
drivers/usb/mon/mon_text.c
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/renesas_usbhs/mod_host.c
drivers/usb/renesas_usbhs/pipe.h
drivers/usb/serial/console.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/storage/isd200.c
drivers/usb/storage/unusual_devs.h
drivers/uwb/hwa-rc.c
drivers/uwb/uwbd.c
drivers/video/aty/atyfb_base.c
drivers/video/console/dummycon.c
drivers/video/sbuslib.c
drivers/video/udlfb.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/autofs4/waitq.c
fs/bio.c
fs/btrfs/acl.c
fs/btrfs/extent-tree.c
fs/btrfs/ioctl.c
fs/btrfs/tree-log.c
fs/cifs/dir.c
fs/cifs/file.c
fs/coda/upcall.c
fs/compat_ioctl.c
fs/dcache.c
fs/dlm/user.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/keystore.c
fs/ecryptfs/messaging.c
fs/eventpoll.c
fs/ext2/acl.c
fs/ext3/acl.c
fs/ext4/acl.c
fs/ext4/balloc.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/super.c
fs/fcntl.c
fs/fscache/object-list.c
fs/fuse/cuse.c
fs/fuse/file.c
fs/hugetlbfs/inode.c
fs/isofs/isofs.h
fs/isofs/rock.h
fs/isofs/util.c
fs/jffs2/fs.c
fs/namei.c
fs/ncpfs/ncplib_kernel.c
fs/nfs/client.c
fs/nfs/nfs4proc.c
fs/nfs/super.c
fs/nfsd/auth.c
fs/nilfs2/btree.c
fs/nilfs2/recovery.c
fs/nilfs2/segment.c
fs/nilfs2/super.c
fs/ocfs2/acl.c
fs/ocfs2/alloc.c
fs/ocfs2/cluster/nodemanager.c
fs/ocfs2/file.c
fs/read_write.c
fs/reiserfs/xattr_acl.c
fs/ubifs/journal.c
fs/ubifs/tnc.c
fs/ubifs/ubifs.h
fs/ubifs/xattr.c
fs/udf/file.c
fs/udf/inode.c
fs/xattr.c
fs/xfs/xfs_dinode.h
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_log.c
include/asm-generic/dma-mapping-broken.h
include/asm-generic/siginfo.h
include/asm-generic/topology.h
include/asm-generic/vmlinux.lds.h
include/crypto/hash.h
include/crypto/internal/hash.h
include/linux/bitops.h
include/linux/blkdev.h
include/linux/cpu.h
include/linux/cpumask.h
include/linux/cpuset.h
include/linux/cred.h
include/linux/crypto.h
include/linux/device-mapper.h
include/linux/dma-mapping.h
include/linux/fdtable.h
include/linux/fs.h
include/linux/fscache.h
include/linux/init.h
include/linux/input.h
include/linux/kaiser.h [new file with mode: 0644]
include/linux/kconfig.h
include/linux/key.h
include/linux/mlx4/device.h
include/linux/mmu_context.h
include/linux/mmzone.h
include/linux/module.h
include/linux/mtd/map.h
include/linux/nospec.h [new file with mode: 0644]
include/linux/pci_ids.h
include/linux/percpu-defs.h
include/linux/perf_event.h
include/linux/sched.h
include/linux/signal.h
include/linux/spi/spidev.h
include/linux/stddef.h
include/linux/usb/audio.h
include/linux/usb/ch9.h
include/linux/usb/hcd.h
include/linux/usb/quirks.h
include/net/bluetooth/l2cap.h
include/net/ip6_fib.h
include/net/ip6_route.h
include/net/red.h
include/net/regulatory.h
include/net/sctp/sctp.h
include/net/sctp/structs.h
include/net/tcp.h
include/net/xfrm.h
include/rdma/ib_verbs.h
include/scsi/libsas.h
include/scsi/scsi_device.h
include/scsi/scsi_devinfo.h
include/sound/seq_kernel.h
include/sound/seq_virmidi.h
include/sound/timer.h
include/trace/events/kvm.h
init/main.c
kernel/audit_watch.c
kernel/cpu.c
kernel/cpuset.c
kernel/debug/kdb/kdb_io.c
kernel/events/core.c
kernel/events/hw_breakpoint.c
kernel/extable.c
kernel/fork.c
kernel/futex.c
kernel/gcov/Kconfig
kernel/gcov/Makefile
kernel/gcov/base.c
kernel/gcov/fs.c
kernel/gcov/gcc_3_4.c
kernel/gcov/gcc_4_7.c [new file with mode: 0644]
kernel/gcov/gcov.h
kernel/groups.c
kernel/hrtimer.c
kernel/irq/irqdesc.c
kernel/kprobes.c
kernel/module.c
kernel/params.c
kernel/posix-timers.c
kernel/ptrace.c
kernel/relay.c
kernel/sched.c
kernel/sysctl.c
kernel/trace/blktrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_selftest.c
kernel/uid16.c
lib/cpumask.c
mm/huge_memory.c
mm/hugetlb.c
mm/madvise.c
mm/mempolicy.c
mm/mmap.c
mm/mmu_context.c
mm/mprotect.c
mm/page_alloc.c
mm/slab.c
mm/vmscan.c
mm/vmstat.c
net/8021q/vlan.c
net/9p/client.c
net/9p/trans_virtio.c
net/batman-adv/bat_iv_ogm.c
net/batman-adv/soft-interface.c
net/bluetooth/bnep/core.c
net/bluetooth/cmtp/core.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_sock.c
net/bridge/br_netlink.c
net/bridge/br_sysfs_if.c
net/bridge/netfilter/ebt_among.c
net/bridge/netfilter/ebtables.c
net/can/af_can.c
net/core/dev.c
net/core/rtnetlink.c
net/core/skbuff.c
net/dccp/ccids/ccid2.c
net/dccp/probe.c
net/dccp/proto.c
net/decnet/af_decnet.c
net/ipv4/esp4.c
net/ipv4/fib_frontend.c
net/ipv4/igmp.c
net/ipv4/ip_sockglue.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/netfilter/nf_nat_proto_common.c
net/ipv4/raw.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/xfrm4_input.c
net/ipv6/addrconf.c
net/ipv6/esp6.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ipv6_sockglue.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/ipv6/xfrm6_input.c
net/ipv6/xfrm6_policy.c
net/iucv/af_iucv.c
net/key/af_key.c
net/l2tp/l2tp_core.c
net/l2tp/l2tp_core.h
net/l2tp/l2tp_eth.c
net/l2tp/l2tp_ip.c
net/l2tp/l2tp_netlink.c
net/l2tp/l2tp_ppp.c
net/mac80211/key.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_conntrack_core.c
net/netfilter/xt_IDLETIMER.c
net/netfilter/xt_LED.c
net/netfilter/xt_RATEEST.c
net/netfilter/xt_TCPMSS.c
net/netfilter/xt_TCPOPTSTRIP.c
net/netfilter/xt_socket.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/packet/af_packet.c
net/rds/rdma.c
net/sched/cls_api.c
net/sched/sch_api.c
net/sched/sch_cbq.c
net/sched/sch_choke.c
net/sched/sch_drr.c
net/sched/sch_gred.c
net/sched/sch_hfsc.c
net/sched/sch_htb.c
net/sched/sch_mq.c
net/sched/sch_mqprio.c
net/sched/sch_multiq.c
net/sched/sch_netem.c
net/sched/sch_qfq.c
net/sched/sch_red.c
net/sched/sch_tbf.c
net/sctp/ipv6.c
net/sctp/protocol.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/socket.c
net/sctp/transport.c
net/sctp/ulpevent.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/svcauth_unix.c
net/wireless/core.c
net/wireless/nl80211.c
net/wireless/wext-compat.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_user.c
scripts/mod/modpost.c
security/Kconfig
security/keys/encrypted-keys/encrypted.c
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/keys/trusted.c
security/selinux/hooks.c
security/selinux/ss/services.c
security/smack/smack_lsm.c
sound/core/control.c
sound/core/hrtimer.c
sound/core/oss/pcm_oss.c
sound/core/oss/pcm_plugin.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/core/seq/oss/seq_oss_midi.c
sound/core/seq/oss/seq_oss_readq.c
sound/core/seq/oss/seq_oss_readq.h
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_clientmgr.h
sound/core/seq/seq_fifo.c
sound/core/seq/seq_lock.c
sound/core/seq/seq_lock.h
sound/core/seq/seq_memory.c
sound/core/seq/seq_memory.h
sound/core/seq/seq_ports.c
sound/core/seq/seq_prioq.c
sound/core/seq/seq_prioq.h
sound/core/seq/seq_queue.c
sound/core/seq/seq_timer.c
sound/core/seq/seq_virmidi.c
sound/core/timer.c
sound/core/timer_compat.c
sound/drivers/aloop.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_conexant.c
sound/soc/au1x/ac97c.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/wm8983.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm_hubs.c
sound/soc/nuc900/nuc900-ac97.c
sound/usb/caiaq/device.c
sound/usb/card.c
sound/usb/clock.c
sound/usb/mixer.c
sound/usb/mixer.h
sound/usb/mixer_quirks.c
sound/usb/quirks-table.h
sound/usb/usx2y/usb_stream.c

index e7be75b..8e7ecfe 100644 (file)
@@ -201,3 +201,19 @@ Description:       Disable L3 cache indices
                All AMD processors with L3 caches provide this functionality.
                For details, see BKDGs at
                http://developer.amd.com/documentation/guides/Pages/default.aspx
+
+What:          /sys/devices/system/cpu/vulnerabilities
+               /sys/devices/system/cpu/vulnerabilities/meltdown
+               /sys/devices/system/cpu/vulnerabilities/spectre_v1
+               /sys/devices/system/cpu/vulnerabilities/spectre_v2
+Date:          January 2018
+Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
+Description:   Information about CPU vulnerabilities
+
+               The files are named after the code names of CPU
+               vulnerabilities. The output of those files reflects the
+               state of the CPUs in the system. Possible output values:
+
+               "Not affected"    CPU is not affected by the vulnerability
+               "Vulnerable"      CPU is affected and no mitigation in effect
+               "Mitigation: $M"  CPU is affected and mitigation $M is in effect
index 5c51ed4..eedecbb 100644 (file)
@@ -345,14 +345,14 @@ the named feature on.
 The implementation is simple.
 
 Setting the flag 'cpuset.memory_spread_page' turns on a per-process flag
-PF_SPREAD_PAGE for each task that is in that cpuset or subsequently
+PFA_SPREAD_PAGE for each task that is in that cpuset or subsequently
 joins that cpuset.  The page allocation calls for the page cache
-is modified to perform an inline check for this PF_SPREAD_PAGE task
+is modified to perform an inline check for this PFA_SPREAD_PAGE task
 flag, and if set, a call to a new routine cpuset_mem_spread_node()
 returns the node to prefer for the allocation.
 
 Similarly, setting 'cpuset.memory_spread_slab' turns on the flag
-PF_SPREAD_SLAB, and appropriately marked slab caches will allocate
+PFA_SPREAD_SLAB, and appropriately marked slab caches will allocate
 pages from the node returned by cpuset_mem_spread_node().
 
 The cpuset_mem_spread_node() routine is also simple.  It uses the
index 801d9d1..55faf87 100644 (file)
@@ -109,9 +109,11 @@ $low_water_mark is expressed in blocks of size $data_block_size.  If
 free space on the data device drops below this level then a dm event
 will be triggered which a userspace daemon should catch allowing it to
 extend the pool device.  Only one such event will be sent.
-Resuming a device with a new table itself triggers an event so the
-userspace daemon can use this to detect a situation where a new table
-already exceeds the threshold.
+
+No special event is triggered if a just resumed device's free space is below
+the low water mark. However, resuming a device always triggers an
+event; a userspace daemon should verify that free space exceeds the low
+water mark when handling this event.
 
 Thin provisioning
 -----------------
index 4917cf2..447384b 100644 (file)
@@ -238,7 +238,7 @@ data_err=ignore(*)  Just print an error message if an error occurs
 data_err=abort         Abort the journal if an error occurs in a file
                        data buffer in ordered mode.
 
-grpid                  Give objects the same group ID as their creator.
+grpid                  New objects have the group ID of their parent.
 bsdgroups
 
 nogrpid                (*)     New objects have the group ID of their creator.
index e7ca647..7b72778 100644 (file)
@@ -50,6 +50,10 @@ Configure the kernel with:
         CONFIG_DEBUG_FS=y
         CONFIG_GCOV_KERNEL=y
 
+select the gcc's gcov format, default is autodetect based on gcc version:
+
+        CONFIG_GCOV_FORMAT_AUTODETECT=y
+
 and to get coverage data for the entire kernel:
 
         CONFIG_GCOV_PROFILE_ALL=y
index d3940af..e3fa31c 100644 (file)
@@ -1781,6 +1781,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        register save and restore. The kernel will only save
                        legacy floating-point registers on task switch.
 
+       nospectre_v2    [X86] Disable all mitigations for the Spectre variant 2
+                       (indirect branch prediction) vulnerability. System may
+                       allow data leaks with this option, which is equivalent
+                       to spectre_v2=off.
+
        noxsave         [BUGS=X86] Disables x86 extended register state save
                        and restore using xsave. The kernel will fallback to
                        enabling legacy floating-point and sse state.
@@ -1827,6 +1832,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        nointroute      [IA-64]
 
+       noinvpcid       [X86] Disable the INVPCID cpu feature.
+
        nojitter        [IA-64] Disables jitter checking for ITC timers.
 
        no-kvmclock     [X86,KVM] Disable paravirtualized KVM clock driver
@@ -1855,11 +1862,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        nopat           [X86] Disable PAT (page attribute table extension of
                        pagetables) support.
 
+       nopcid          [X86-64] Disable the PCID cpu feature.
+
        norandmaps      Don't use address space randomization.  Equivalent to
                        echo 0 > /proc/sys/kernel/randomize_va_space
 
-       noreplace-paravirt      [X86,IA-64,PV_OPS] Don't patch paravirt_ops
-
        noreplace-smp   [X86-32,SMP] Don't replace SMP instructions
                        with UP alternatives
 
@@ -2267,6 +2274,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        pt.             [PARIDE]
                        See Documentation/blockdev/paride.txt.
 
+       pti=            [X86_64] Control Page Table Isolation of user and
+                       kernel address spaces.  Disabling this feature
+                       removes hardening, but improves performance of
+                       system calls and interrupts.
+
+                       on   - unconditionally enable
+                       off  - unconditionally disable
+                       auto - kernel detects whether your CPU model is
+                              vulnerable to issues that PTI mitigates
+
+                       Not specifying this option is equivalent to pti=auto.
+
+       nopti           [X86_64]
+                       Equivalent to pti=off
+
        pty.legacy_count=
                        [KNL] Number of legacy pty's. Overwrites compiled-in
                        default number.
@@ -2456,9 +2478,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        smart2=         [HW]
                        Format: <io1>[,<io2>[,...,<io8>]]
 
-       smp-alt-once    [X86-32,SMP] On a hotplug CPU system, only
-                       attempt to substitute SMP alternatives once at boot.
-
        smsc-ircc2.nopnp        [HW] Don't use PNP to discover SMC devices
        smsc-ircc2.ircc_cfg=    [HW] Device configuration I/O port
        smsc-ircc2.ircc_sir=    [HW] SIR base I/O port
@@ -2480,6 +2499,29 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        specialix=      [HW,SERIAL] Specialix multi-serial port adapter
                        See Documentation/serial/specialix.txt.
 
+       spectre_v2=     [X86] Control mitigation of Spectre variant 2
+                       (indirect branch speculation) vulnerability.
+
+                       on   - unconditionally enable
+                       off  - unconditionally disable
+                       auto - kernel detects whether your CPU model is
+                              vulnerable
+
+                       Selecting 'on' will, and 'auto' may, choose a
+                       mitigation method at run time according to the
+                       CPU, the available microcode, the setting of the
+                       CONFIG_RETPOLINE configuration option, and the
+                       compiler with which the kernel was built.
+
+                       Specific mitigations can also be selected manually:
+
+                       retpoline         - replace indirect branches
+                       retpoline,generic - google's original retpoline
+                       retpoline,amd     - AMD-specific minimal thunk
+
+                       Not specifying this option is equivalent to
+                       spectre_v2=auto.
+
        spia_io_base=   [HW,MTD]
        spia_fio_base=
        spia_pedr=
diff --git a/Documentation/speculation.txt b/Documentation/speculation.txt
new file mode 100644 (file)
index 0000000..e9e6cba
--- /dev/null
@@ -0,0 +1,90 @@
+This document explains potential effects of speculation, and how undesirable
+effects can be mitigated portably using common APIs.
+
+===========
+Speculation
+===========
+
+To improve performance and minimize average latencies, many contemporary CPUs
+employ speculative execution techniques such as branch prediction, performing
+work which may be discarded at a later stage.
+
+Typically speculative execution cannot be observed from architectural state,
+such as the contents of registers. However, in some cases it is possible to
+observe its impact on microarchitectural state, such as the presence or
+absence of data in caches. Such state may form side-channels which can be
+observed to extract secret information.
+
+For example, in the presence of branch prediction, it is possible for bounds
+checks to be ignored by code which is speculatively executed. Consider the
+following code:
+
+       int load_array(int *array, unsigned int index)
+       {
+               if (index >= MAX_ARRAY_ELEMS)
+                       return 0;
+               else
+                       return array[index];
+       }
+
+Which, on arm64, may be compiled to an assembly sequence such as:
+
+       CMP     <index>, #MAX_ARRAY_ELEMS
+       B.LT    less
+       MOV     <returnval>, #0
+       RET
+  less:
+       LDR     <returnval>, [<array>, <index>]
+       RET
+
+It is possible that a CPU mis-predicts the conditional branch, and
+speculatively loads array[index], even if index >= MAX_ARRAY_ELEMS. This
+value will subsequently be discarded, but the speculated load may affect
+microarchitectural state which can be subsequently measured.
+
+More complex sequences involving multiple dependent memory accesses may
+result in sensitive information being leaked. Consider the following
+code, building on the prior example:
+
+       int load_dependent_arrays(int *arr1, int *arr2, int index)
+       {
+               int val1, val2,
+
+               val1 = load_array(arr1, index);
+               val2 = load_array(arr2, val1);
+
+               return val2;
+       }
+
+Under speculation, the first call to load_array() may return the value
+of an out-of-bounds address, while the second call will influence
+microarchitectural state dependent on this value. This may provide an
+arbitrary read primitive.
+
+====================================
+Mitigating speculation side-channels
+====================================
+
+The kernel provides a generic API to ensure that bounds checks are
+respected even under speculation. Architectures which are affected by
+speculation-based side-channels are expected to implement these
+primitives.
+
+The array_index_nospec() helper in <linux/nospec.h> can be used to
+prevent information from being leaked via side-channels.
+
+A call to array_index_nospec(index, size) returns a sanitized index
+value that is bounded to [0, size) even under cpu speculation
+conditions.
+
+This can be used to protect the earlier load_array() example:
+
+       int load_array(int *array, unsigned int index)
+       {
+               if (index >= MAX_ARRAY_ELEMS)
+                       return 0;
+               else {
+                       index = array_index_nospec(index, MAX_ARRAY_ELEMS);
+                       return array[index];
+               }
+       }
diff --git a/Documentation/x86/pti.txt b/Documentation/x86/pti.txt
new file mode 100644 (file)
index 0000000..5cd5843
--- /dev/null
@@ -0,0 +1,186 @@
+Overview
+========
+
+Page Table Isolation (pti, previously known as KAISER[1]) is a
+countermeasure against attacks on the shared user/kernel address
+space such as the "Meltdown" approach[2].
+
+To mitigate this class of attacks, we create an independent set of
+page tables for use only when running userspace applications.  When
+the kernel is entered via syscalls, interrupts or exceptions, the
+page tables are switched to the full "kernel" copy.  When the system
+switches back to user mode, the user copy is used again.
+
+The userspace page tables contain only a minimal amount of kernel
+data: only what is needed to enter/exit the kernel such as the
+entry/exit functions themselves and the interrupt descriptor table
+(IDT).  There are a few strictly unnecessary things that get mapped
+such as the first C function when entering an interrupt (see
+comments in pti.c).
+
+This approach helps to ensure that side-channel attacks leveraging
+the paging structures do not function when PTI is enabled.  It can be
+enabled by setting CONFIG_PAGE_TABLE_ISOLATION=y at compile time.
+Once enabled at compile-time, it can be disabled at boot with the
+'nopti' or 'pti=' kernel parameters (see kernel-parameters.txt).
+
+Page Table Management
+=====================
+
+When PTI is enabled, the kernel manages two sets of page tables.
+The first set is very similar to the single set which is present in
+kernels without PTI.  This includes a complete mapping of userspace
+that the kernel can use for things like copy_to_user().
+
+Although _complete_, the user portion of the kernel page tables is
+crippled by setting the NX bit in the top level.  This ensures
+that any missed kernel->user CR3 switch will immediately crash
+userspace upon executing its first instruction.
+
+The userspace page tables map only the kernel data needed to enter
+and exit the kernel.  This data is entirely contained in the 'struct
+cpu_entry_area' structure which is placed in the fixmap which gives
+each CPU's copy of the area a compile-time-fixed virtual address.
+
+For new userspace mappings, the kernel makes the entries in its
+page tables like normal.  The only difference is when the kernel
+makes entries in the top (PGD) level.  In addition to setting the
+entry in the main kernel PGD, a copy of the entry is made in the
+userspace page tables' PGD.
+
+This sharing at the PGD level also inherently shares all the lower
+layers of the page tables.  This leaves a single, shared set of
+userspace page tables to manage.  One PTE to lock, one set of
+accessed bits, dirty bits, etc...
+
+Overhead
+========
+
+Protection against side-channel attacks is important.  But,
+this protection comes at a cost:
+
+1. Increased Memory Use
+  a. Each process now needs an order-1 PGD instead of order-0.
+     (Consumes an additional 4k per process).
+  b. The 'cpu_entry_area' structure must be 2MB in size and 2MB
+     aligned so that it can be mapped by setting a single PMD
+     entry.  This consumes nearly 2MB of RAM once the kernel
+     is decompressed, but no space in the kernel image itself.
+
+2. Runtime Cost
+  a. CR3 manipulation to switch between the page table copies
+     must be done at interrupt, syscall, and exception entry
+     and exit (it can be skipped when the kernel is interrupted,
+     though.)  Moves to CR3 are on the order of a hundred
+     cycles, and are required at every entry and exit.
+  b. A "trampoline" must be used for SYSCALL entry.  This
+     trampoline depends on a smaller set of resources than the
+     non-PTI SYSCALL entry code, so requires mapping fewer
+     things into the userspace page tables.  The downside is
+     that stacks must be switched at entry time.
+  c. Global pages are disabled for all kernel structures not
+     mapped into both kernel and userspace page tables.  This
+     feature of the MMU allows different processes to share TLB
+     entries mapping the kernel.  Losing the feature means more
+     TLB misses after a context switch.  The actual loss of
+     performance is very small, however, never exceeding 1%.
+  d. Process Context IDentifiers (PCID) is a CPU feature that
+     allows us to skip flushing the entire TLB when switching page
+     tables by setting a special bit in CR3 when the page tables
+     are changed.  This makes switching the page tables (at context
+     switch, or kernel entry/exit) cheaper.  But, on systems with
+     PCID support, the context switch code must flush both the user
+     and kernel entries out of the TLB.  The user PCID TLB flush is
+     deferred until the exit to userspace, minimizing the cost.
+     See intel.com/sdm for the gory PCID/INVPCID details.
+  e. The userspace page tables must be populated for each new
+     process.  Even without PTI, the shared kernel mappings
+     are created by copying top-level (PGD) entries into each
+     new process.  But, with PTI, there are now *two* kernel
+     mappings: one in the kernel page tables that maps everything
+     and one for the entry/exit structures.  At fork(), we need to
+     copy both.
+  f. In addition to the fork()-time copying, there must also
+     be an update to the userspace PGD any time a set_pgd() is done
+     on a PGD used to map userspace.  This ensures that the kernel
+     and userspace copies always map the same userspace
+     memory.
+  g. On systems without PCID support, each CR3 write flushes
+     the entire TLB.  That means that each syscall, interrupt
+     or exception flushes the TLB.
+  h. INVPCID is a TLB-flushing instruction which allows flushing
+     of TLB entries for non-current PCIDs.  Some systems support
+     PCIDs, but do not support INVPCID.  On these systems, addresses
+     can only be flushed from the TLB for the current PCID.  When
+     flushing a kernel address, we need to flush all PCIDs, so a
+     single kernel address flush will require a TLB-flushing CR3
+     write upon the next use of every PCID.
+
+Possible Future Work
+====================
+1. We can be more careful about not actually writing to CR3
+   unless its value is actually changed.
+2. Allow PTI to be enabled/disabled at runtime in addition to the
+   boot-time switching.
+
+Testing
+========
+
+To test stability of PTI, the following test procedure is recommended,
+ideally doing all of these in parallel:
+
+1. Set CONFIG_DEBUG_ENTRY=y
+2. Run several copies of all of the tools/testing/selftests/x86/ tests
+   (excluding MPX and protection_keys) in a loop on multiple CPUs for
+   several minutes.  These tests frequently uncover corner cases in the
+   kernel entry code.  In general, old kernels might cause these tests
+   themselves to crash, but they should never crash the kernel.
+3. Run the 'perf' tool in a mode (top or record) that generates many
+   frequent performance monitoring non-maskable interrupts (see "NMI"
+   in /proc/interrupts).  This exercises the NMI entry/exit code which
+   is known to trigger bugs in code paths that did not expect to be
+   interrupted, including nested NMIs.  Using "-c" boosts the rate of
+   NMIs, and using two -c with separate counters encourages nested NMIs
+   and less deterministic behavior.
+
+       while true; do perf record -c 10000 -e instructions,cycles -a sleep 10; done
+
+4. Launch a KVM virtual machine.
+5. Run 32-bit binaries on systems supporting the SYSCALL instruction.
+   This has been a lightly-tested code path and needs extra scrutiny.
+
+Debugging
+=========
+
+Bugs in PTI cause a few different signatures of crashes
+that are worth noting here.
+
+ * Failures of the selftests/x86 code.  Usually a bug in one of the
+   more obscure corners of entry_64.S
+ * Crashes in early boot, especially around CPU bringup.  Bugs
+   in the trampoline code or mappings cause these.
+ * Crashes at the first interrupt.  Caused by bugs in entry_64.S,
+   like screwing up a page table switch.  Also caused by
+   incorrectly mapping the IRQ handler entry code.
+ * Crashes at the first NMI.  The NMI code is separate from main
+   interrupt handlers and can have bugs that do not affect
+   normal interrupts.  Also caused by incorrectly mapping NMI
+   code.  NMIs that interrupt the entry code must be very
+   careful and can be the cause of crashes that show up when
+   running perf.
+ * Kernel crashes at the first exit to userspace.  entry_64.S
+   bugs, or failing to map some of the exit code.
+ * Crashes at first interrupt that interrupts userspace. The paths
+   in entry_64.S that return to userspace are sometimes separate
+   from the ones that return to the kernel.
+ * Double faults: overflowing the kernel stack because of page
+   faults upon page faults.  Caused by touching non-pti-mapped
+   data in the entry code, or forgetting to switch to kernel
+   CR3 before calling into C functions which are not pti-mapped.
+ * Userspace segfaults early in boot, sometimes manifesting
+   as mount(8) failing to mount the rootfs.  These have
+   tended to be TLB invalidation issues.  Usually invalidating
+   the wrong PCID, or otherwise missing an invalidation.
+
+1. https://gruss.cc/files/kaiser.pdf
+2. https://meltdownattack.com/meltdown.pdf
index ec64e6f..46779a6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 VERSION = 3
 PATCHLEVEL = 2
-SUBLEVEL = 93
+SUBLEVEL = 102
 EXTRAVERSION =
-NAME = Saber-toothed Squirrel
+NAME = Sleepy Otter
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -559,7 +559,7 @@ endif # $(dot-config)
 all: vmlinux
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-KBUILD_CFLAGS  += -Os
+KBUILD_CFLAGS  += -Os $(call cc-disable-warning,maybe-uninitialized,)
 else
 KBUILD_CFLAGS  += -O2
 endif
@@ -631,6 +631,9 @@ KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign)
 # disable invalid "can't wrap" optimizations for signed / pointers
 KBUILD_CFLAGS  += $(call cc-option,-fno-strict-overflow)
 
+# Make sure -fstack-check isn't enabled (like gentoo apparently did)
+KBUILD_CFLAGS  += $(call cc-option,-fno-stack-check,)
+
 # conserve stack if available
 KBUILD_CFLAGS   += $(call cc-option,-fconserve-stack)
 
index 8815443..5993b2a 100644 (file)
@@ -9,10 +9,18 @@
  * need to be careful to avoid a name clashes.
  */
 
-#ifdef __KERNEL__
-#include <asm-generic/int-ll64.h>
-#else
+/*
+ * This is here because we used to use l64 for alpha
+ * and we don't want to impact user mode with our change to ll64
+ * in the kernel.
+ *
+ * However, some user programs are fine with this.  They can
+ * flag __SANE_USERSPACE_TYPES__ to get int-ll64.h here.
+ */
+#if !defined(__SANE_USERSPACE_TYPES__) && !defined(__KERNEL__)
 #include <asm-generic/int-l64.h>
+#else
+#include <asm-generic/int-ll64.h>
 #endif
 
 #ifndef __ASSEMBLY__
index 85457b2..cc74213 100644 (file)
@@ -143,7 +143,8 @@ struct pci_iommu_arena
 };
 
 #if defined(CONFIG_ALPHA_SRM) && \
-    (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA))
+    (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \
+     defined(CONFIG_ALPHA_AVANTI))
 # define NEED_SRM_SAVE_RESTORE
 #else
 # undef NEED_SRM_SAVE_RESTORE
index 89bbe5b..42c2481 100644 (file)
@@ -279,7 +279,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
        struct thread_info *childti = task_thread_info(p);
        struct pt_regs * childregs;
        struct switch_stack * childstack, *stack;
-       unsigned long stack_offset, settls;
+       unsigned long stack_offset;
 
        stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
        if (!(regs->ps & 8))
@@ -288,11 +288,9 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
          (stack_offset + PAGE_SIZE + task_stack_page(p));
                
        *childregs = *regs;
-       settls = regs->r20;
        childregs->r0 = 0;
        childregs->r19 = 0;
        childregs->r20 = 1;     /* OSF/1 has some strange fork() semantics.  */
-       regs->r20 = 0;
        stack = ((struct switch_stack *) regs) - 1;
        childstack = ((struct switch_stack *) childregs) - 1;
        *childstack = *stack;
@@ -302,16 +300,16 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
        childti->pcb.flags = 1; /* set FEN, clear everything else */
 
        /* Set a new TLS for the child thread?  Peek back into the
-          syscall arguments that we saved on syscall entry.  Oops,
-          except we'd have clobbered it with the parent/child set
-          of r20.  Read the saved copy.  */
+          syscall arguments that we saved on syscall entry. */
        /* Note: if CLONE_SETTLS is not set, then we must inherit the
           value from the parent, which will have been set by the block
           copy in dup_task_struct.  This is non-intuitive, but is
           required for proper operation in the case of a threaded
           application calling fork.  */
        if (clone_flags & CLONE_SETTLS)
-               childti->pcb.unique = settls;
+               childti->pcb.unique = regs->r20;
+       else
+               regs->r20 = 0;  /* OSF/1 has some strange fork() semantics.  */
 
        return 0;
 }
index 071772c..667587b 100644 (file)
@@ -130,30 +130,26 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
        set_fs(fs);
 }
 
-static void dump_instr(const char *lvl, struct pt_regs *regs)
+static void __dump_instr(const char *lvl, struct pt_regs *regs)
 {
        unsigned long addr = instruction_pointer(regs);
        const int thumb = thumb_mode(regs);
        const int width = thumb ? 4 : 8;
-       mm_segment_t fs;
        char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
        int i;
 
        /*
-        * We need to switch to kernel mode so that we can use __get_user
-        * to safely read from kernel space.  Note that we now dump the
-        * code first, just in case the backtrace kills us.
+        * Note that we now dump the code first, just in case the backtrace
+        * kills us.
         */
-       fs = get_fs();
-       set_fs(KERNEL_DS);
 
        for (i = -4; i < 1 + !!thumb; i++) {
                unsigned int val, bad;
 
                if (thumb)
-                       bad = __get_user(val, &((u16 *)addr)[i]);
+                       bad = get_user(val, &((u16 *)addr)[i]);
                else
-                       bad = __get_user(val, &((u32 *)addr)[i]);
+                       bad = get_user(val, &((u32 *)addr)[i]);
 
                if (!bad)
                        p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
@@ -164,8 +160,20 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
                }
        }
        printk("%sCode: %s\n", lvl, str);
+}
 
-       set_fs(fs);
+static void dump_instr(const char *lvl, struct pt_regs *regs)
+{
+       mm_segment_t fs;
+
+       if (!user_mode(regs)) {
+               fs = get_fs();
+               set_fs(KERNEL_DS);
+               __dump_instr(lvl, regs);
+               set_fs(fs);
+       } else {
+               __dump_instr(lvl, regs);
+       }
 }
 
 #ifdef CONFIG_ARM_UNWIND
index 109ccd2..7e32ac6 100644 (file)
@@ -564,6 +564,7 @@ config ARCH_PXA_ESERIES
        bool "PXA based Toshiba e-series PDAs"
        select PXA25x
        select FB_W100
+       select FB
 
 config MACH_E330
        bool "Toshiba e330"
index 36e9a9c..725153e 100644 (file)
@@ -2,8 +2,5 @@
 # Makefile for Etrax-specific library files..
 #
 
-
-EXTRA_AFLAGS := -traditional
-
 lib-y  = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o
 
index 4010f1f..cea944c 100644 (file)
@@ -67,6 +67,7 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
 
 extern void iounmap(volatile void __iomem *addr);
 #define ioremap_nocache(off,size) ioremap(off,size)
+#define ioremap_wc ioremap_nocache
 
 /*
  * IO bus memory addresses are also 1:1 with the physical address
@@ -162,13 +163,21 @@ static inline void _writel(unsigned long l, unsigned long addr)
 #define __raw_writew writew
 #define __raw_writel writel
 
-#define ioread8 read
+#define ioread8 readb
 #define ioread16 readw
 #define ioread32 readl
 #define iowrite8 writeb
 #define iowrite16 writew
 #define iowrite32 writel
 
+#define ioread8_rep(p, dst, count) insb((unsigned long)(p), (dst), (count))
+#define ioread16_rep(p, dst, count) insw((unsigned long)(p), (dst), (count))
+#define ioread32_rep(p, dst, count) insl((unsigned long)(p), (dst), (count))
+
+#define iowrite8_rep(p, src, count) outsb((unsigned long)(p), (src), (count))
+#define iowrite16_rep(p, src, count) outsw((unsigned long)(p), (src), (count))
+#define iowrite32_rep(p, src, count) outsl((unsigned long)(p), (src), (count))
+
 #define mmiowb()
 
 #define flush_write_buffers() do { } while (0)  /* M32R_FIXME */
index 2074375..20c5b5c 100644 (file)
@@ -592,17 +592,16 @@ void user_enable_single_step(struct task_struct *child)
 
        if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0)
            != sizeof(insn))
-               return -EIO;
+               return;
 
        compute_next_pc(insn, pc, &next_pc, child);
        if (next_pc & 0x80000000)
-               return -EIO;
+               return;
 
        if (embed_debug_trap(child, next_pc))
-               return -EIO;
+               return;
 
        invalidate_cache();
-       return 0;
 }
 
 void user_disable_single_step(struct task_struct *child)
index 2460f9d..320e5b8 100644 (file)
@@ -430,6 +430,9 @@ EXPORT_SYMBOL(clk_disable);
 
 unsigned long clk_get_rate(struct clk *clk)
 {
+       if (!clk)
+               return 0;
+
        return clk->rate;
 }
 EXPORT_SYMBOL(clk_get_rate);
index 33ffecf..8e64ab5 100644 (file)
@@ -541,6 +541,7 @@ static int __init ar7_register_uarts(void)
        uart_port.type          = PORT_AR7;
        uart_port.uartclk       = clk_get_rate(bus_clk) / 2;
        uart_port.iotype        = UPIO_MEM32;
+       uart_port.flags         = UPF_FIXED_TYPE;
        uart_port.regshift      = 2;
 
        uart_port.line          = 0;
index 2c68ee9..2bbf5f7 100644 (file)
@@ -193,6 +193,9 @@ EXPORT_SYMBOL(clk_disable);
 
 unsigned long clk_get_rate(struct clk *clk)
 {
+       if (!clk)
+               return 0;
+
        return clk->rate;
 }
 
index 5042d51..35034cf 100644 (file)
@@ -105,4 +105,8 @@ OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec
 vmlinuz.srec: vmlinuz
        $(call cmd,objcopy)
 
-clean-files := $(objtree)/vmlinuz $(objtree)/vmlinuz.{32,ecoff,bin,srec}
+clean-files += $(objtree)/vmlinuz
+clean-files += $(objtree)/vmlinuz.32
+clean-files += $(objtree)/vmlinuz.ecoff
+clean-files += $(objtree)/vmlinuz.bin
+clean-files += $(objtree)/vmlinuz.srec
index 32103cc..88f19e3 100644 (file)
@@ -247,7 +247,8 @@ unaligned:
        return -EFAULT;
 
 sigill:
-       printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm);
-       force_sig(SIGBUS, current);
+       pr_info("%s: DSP branch but not DSP ASE - sending SIGILL.\n",
+               current->comm);
+       force_sig(SIGILL, current);
        return -EFAULT;
 }
index 57ba13e..3fc1691 100644 (file)
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996, 97, 98, 99, 2000, 01, 03, 04, 05 by Ralf Baechle
+ * Copyright (C) 1996, 97, 98, 99, 2000, 01, 03, 04, 05, 12 by Ralf Baechle
  * Copyright (C) 1999, 2000, 01 Silicon Graphics, Inc.
  */
 #include <linux/interrupt.h>
@@ -34,6 +34,12 @@ EXPORT_SYMBOL(memmove);
 
 EXPORT_SYMBOL(kernel_thread);
 
+/*
+ * Functions that operate on entire pages.  Mostly used by memory management.
+ */
+EXPORT_SYMBOL(clear_page);
+EXPORT_SYMBOL(copy_page);
+
 /*
  * Userspace access stuff.
  */
index d027657..4e40a90 100644 (file)
@@ -203,7 +203,7 @@ static inline int mips_atomic_set(struct pt_regs *regs,
                "1:     ll      %[old], (%[addr])                       \n"
                "       move    %[tmp], %[new]                          \n"
                "2:     sc      %[tmp], (%[addr])                       \n"
-               "       bnez    %[tmp], 4f                              \n"
+               "       beqz    %[tmp], 4f                              \n"
                "3:                                                     \n"
                "       .subsection 2                                   \n"
                "4:     b       1b                                      \n"
index 4d8c162..0d3871c 100644 (file)
@@ -3,8 +3,8 @@
 #
 
 obj-y                          += cache.o dma-default.o extable.o fault.o \
-                                  init.o mmap.o tlbex.o tlbex-fault.o uasm.o \
-                                  page.o
+                                  init.o mmap.o page.o page-funcs.o \
+                                  tlbex.o tlbex-fault.o uasm.o
 
 obj-$(CONFIG_32BIT)            += ioremap.o pgtable-32.o
 obj-$(CONFIG_64BIT)            += pgtable-64.o
diff --git a/arch/mips/mm/page-funcs.S b/arch/mips/mm/page-funcs.S
new file mode 100644 (file)
index 0000000..48a6b38
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Micro-assembler generated clear_page/copy_page functions.
+ *
+ * Copyright (C) 2012  MIPS Technologies, Inc.
+ * Copyright (C) 2012  Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
+#define cpu_clear_page_function_name   clear_page_cpu
+#define cpu_copy_page_function_name    copy_page_cpu
+#else
+#define cpu_clear_page_function_name   clear_page
+#define cpu_copy_page_function_name    copy_page
+#endif
+
+/*
+ * Maximum sizes:
+ *
+ * R4000 128 bytes S-cache:            0x058 bytes
+ * R4600 v1.7:                         0x05c bytes
+ * R4600 v2.0:                         0x060 bytes
+ * With prefetching, 16 word strides   0x120 bytes
+ */
+EXPORT(__clear_page_start)
+LEAF(cpu_clear_page_function_name)
+1:     j       1b              /* Dummy, will be replaced. */
+       .space 288
+END(cpu_clear_page_function_name)
+EXPORT(__clear_page_end)
+
+/*
+ * Maximum sizes:
+ *
+ * R4000 128 bytes S-cache:            0x11c bytes
+ * R4600 v1.7:                         0x080 bytes
+ * R4600 v2.0:                         0x07c bytes
+ * With prefetching, 16 word strides   0x540 bytes
+ */
+EXPORT(__copy_page_start)
+LEAF(cpu_copy_page_function_name)
+1:     j       1b              /* Dummy, will be replaced. */
+       .space 1344
+END(cpu_copy_page_function_name)
+EXPORT(__copy_page_end)
index 36272f7..a22bd40 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 2007  Maciej W. Rozycki
  * Copyright (C) 2008  Thiemo Seufer
+ * Copyright (C) 2012  MIPS Technologies, Inc.
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -72,45 +73,6 @@ static struct uasm_reloc __cpuinitdata relocs[5];
 #define cpu_is_r4600_v1_x()    ((read_c0_prid() & 0xfffffff0) == 0x00002010)
 #define cpu_is_r4600_v2_x()    ((read_c0_prid() & 0xfffffff0) == 0x00002020)
 
-/*
- * Maximum sizes:
- *
- * R4000 128 bytes S-cache:            0x058 bytes
- * R4600 v1.7:                         0x05c bytes
- * R4600 v2.0:                         0x060 bytes
- * With prefetching, 16 word strides   0x120 bytes
- */
-
-static u32 clear_page_array[0x120 / 4];
-
-#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
-void clear_page_cpu(void *page) __attribute__((alias("clear_page_array")));
-#else
-void clear_page(void *page) __attribute__((alias("clear_page_array")));
-#endif
-
-EXPORT_SYMBOL(clear_page);
-
-/*
- * Maximum sizes:
- *
- * R4000 128 bytes S-cache:            0x11c bytes
- * R4600 v1.7:                         0x080 bytes
- * R4600 v2.0:                         0x07c bytes
- * With prefetching, 16 word strides   0x540 bytes
- */
-static u32 copy_page_array[0x540 / 4];
-
-#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
-void
-copy_page_cpu(void *to, void *from) __attribute__((alias("copy_page_array")));
-#else
-void copy_page(void *to, void *from) __attribute__((alias("copy_page_array")));
-#endif
-
-EXPORT_SYMBOL(copy_page);
-
-
 static int pref_bias_clear_store __cpuinitdata;
 static int pref_bias_copy_load __cpuinitdata;
 static int pref_bias_copy_store __cpuinitdata;
@@ -283,10 +245,15 @@ static inline void __cpuinit build_clear_pref(u32 **buf, int off)
                }
 }
 
+extern u32 __clear_page_start;
+extern u32 __clear_page_end;
+extern u32 __copy_page_start;
+extern u32 __copy_page_end;
+
 void __cpuinit build_clear_page(void)
 {
        int off;
-       u32 *buf = (u32 *)&clear_page_array;
+       u32 *buf = &__clear_page_start;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
        int i;
@@ -357,17 +324,17 @@ void __cpuinit build_clear_page(void)
        uasm_i_jr(&buf, RA);
        uasm_i_nop(&buf);
 
-       BUG_ON(buf > clear_page_array + ARRAY_SIZE(clear_page_array));
+       BUG_ON(buf > &__clear_page_end);
 
        uasm_resolve_relocs(relocs, labels);
 
        pr_debug("Synthesized clear page handler (%u instructions).\n",
-                (u32)(buf - clear_page_array));
+                (u32)(buf - &__clear_page_start));
 
        pr_debug("\t.set push\n");
        pr_debug("\t.set noreorder\n");
-       for (i = 0; i < (buf - clear_page_array); i++)
-               pr_debug("\t.word 0x%08x\n", clear_page_array[i]);
+       for (i = 0; i < (buf - &__clear_page_start); i++)
+               pr_debug("\t.word 0x%08x\n", (&__clear_page_start)[i]);
        pr_debug("\t.set pop\n");
 }
 
@@ -428,7 +395,7 @@ static inline void build_copy_store_pref(u32 **buf, int off)
 void __cpuinit build_copy_page(void)
 {
        int off;
-       u32 *buf = (u32 *)&copy_page_array;
+       u32 *buf = &__copy_page_start;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
        int i;
@@ -596,21 +563,23 @@ void __cpuinit build_copy_page(void)
        uasm_i_jr(&buf, RA);
        uasm_i_nop(&buf);
 
-       BUG_ON(buf > copy_page_array + ARRAY_SIZE(copy_page_array));
+       BUG_ON(buf > &__copy_page_end);
 
        uasm_resolve_relocs(relocs, labels);
 
        pr_debug("Synthesized copy page handler (%u instructions).\n",
-                (u32)(buf - copy_page_array));
+                (u32)(buf - &__copy_page_start));
 
        pr_debug("\t.set push\n");
        pr_debug("\t.set noreorder\n");
-       for (i = 0; i < (buf - copy_page_array); i++)
-               pr_debug("\t.word 0x%08x\n", copy_page_array[i]);
+       for (i = 0; i < (buf - &__copy_page_start); i++)
+               pr_debug("\t.word 0x%08x\n", (&__copy_page_start)[i]);
        pr_debug("\t.set pop\n");
 }
 
 #ifdef CONFIG_SIBYTE_DMA_PAGEOPS
+extern void clear_page_cpu(void *page);
+extern void copy_page_cpu(void *to, void *from);
 
 /*
  * Pad descriptors to cacheline, since each is exclusively owned by a
index ec38e00..f9f07ba 100644 (file)
@@ -632,7 +632,7 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr,
                                    unsigned long size,
                                    const struct physmap_flash_data *pdata)
 {
-#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+#if IS_ENABLED(CONFIG_MTD_PHYSMAP)
        struct resource res = {
                .start = addr,
                .end = addr + size - 1,
@@ -670,8 +670,7 @@ void __init txx9_physmap_flash_init(int no, unsigned long addr,
 void __init txx9_ndfmc_init(unsigned long baseaddr,
                            const struct txx9ndfmc_platform_data *pdata)
 {
-#if defined(CONFIG_MTD_NAND_TXX9NDFMC) || \
-       defined(CONFIG_MTD_NAND_TXX9NDFMC_MODULE)
+#if IS_ENABLED(CONFIG_MTD_NAND_TXX9NDFMC)
        struct resource res = {
                .start = baseaddr,
                .end = baseaddr + 0x1000 - 1,
@@ -687,7 +686,7 @@ void __init txx9_ndfmc_init(unsigned long baseaddr,
 #endif
 }
 
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#if IS_ENABLED(CONFIG_LEDS_GPIO)
 static DEFINE_SPINLOCK(txx9_iocled_lock);
 
 #define TXX9_IOCLED_MAXLEDS 8
@@ -810,7 +809,7 @@ void __init txx9_iocled_init(unsigned long baseaddr,
 void __init txx9_dmac_init(int id, unsigned long baseaddr, int irq,
                           const struct txx9dmac_platform_data *pdata)
 {
-#if defined(CONFIG_TXX9_DMAC) || defined(CONFIG_TXX9_DMAC_MODULE)
+#if IS_ENABLED(CONFIG_TXX9_DMAC)
        struct resource res[] = {
                {
                        .start = baseaddr,
@@ -866,8 +865,7 @@ void __init txx9_aclc_init(unsigned long baseaddr, int irq,
                           unsigned int dma_chan_out,
                           unsigned int dma_chan_in)
 {
-#if defined(CONFIG_SND_SOC_TXX9ACLC) || \
-       defined(CONFIG_SND_SOC_TXX9ACLC_MODULE)
+#if IS_ENABLED(CONFIG_SND_SOC_TXX9ACLC)
        unsigned int dma_base = dmac_id * TXX9_DMA_MAX_NR_CHANNELS;
        struct resource res[] = {
                {
index ba3cec3..3cbeacc 100644 (file)
@@ -317,7 +317,7 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)
        }
 }
 
-#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
+#if IS_ENABLED(CONFIG_TC35815)
 static u32 tx4939_get_eth_speed(struct net_device *dev)
 {
        struct ethtool_cmd cmd;
index 2ad8973..120343f 100644 (file)
@@ -40,8 +40,7 @@ static void __init rbtx4939_time_init(void)
        tx4939_time_init(0);
 }
 
-#if defined(__BIG_ENDIAN) && \
-       (defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE))
+#if defined(__BIG_ENDIAN) && IS_ENABLED(CONFIG_SMC91X)
 #define HAVE_RBTX4939_IOSWAB
 #define IS_CE1_ADDR(addr) \
        ((((unsigned long)(addr) - IO_BASE) & 0xfff00000) == TXX9_CE(1))
@@ -187,7 +186,7 @@ static void __init rbtx4939_update_ioc_pen(void)
 
 #define RBTX4939_MAX_7SEGLEDS  8
 
-#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+#if IS_BUILTIN(CONFIG_LEDS_CLASS)
 static u8 led_val[RBTX4939_MAX_7SEGLEDS];
 struct rbtx4939_led_data {
        struct led_classdev cdev;
@@ -263,7 +262,7 @@ static inline void rbtx4939_led_setup(void)
 
 static void __rbtx4939_7segled_putc(unsigned int pos, unsigned char val)
 {
-#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+#if IS_BUILTIN(CONFIG_LEDS_CLASS)
        unsigned long flags;
        local_irq_save(flags);
        /* bit7: reserved for LED class */
@@ -287,7 +286,7 @@ static void rbtx4939_7segled_putc(unsigned int pos, unsigned char val)
        __rbtx4939_7segled_putc(pos, val);
 }
 
-#if defined(CONFIG_MTD_RBTX4939) || defined(CONFIG_MTD_RBTX4939_MODULE)
+#if IS_ENABLED(CONFIG_MTD_RBTX4939)
 /* special mapping for boot rom */
 static unsigned long rbtx4939_flash_fixup_ofs(unsigned long ofs)
 {
@@ -463,7 +462,7 @@ static void __init rbtx4939_device_init(void)
                .flags = SMC91X_USE_16BIT,
        };
        struct platform_device *pdev;
-#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
+#if IS_ENABLED(CONFIG_TC35815)
        int i, j;
        unsigned char ethaddr[2][6];
        u8 bdipsw = readb(rbtx4939_bdipsw_addr) & 0x0f;
index f9bb8cb..c91d8ad 100644 (file)
@@ -438,7 +438,7 @@ transfer_failed:
 
        info.si_signo   = SIGSEGV;
        info.si_errno   = 0;
-       info.si_code    = 0;
+       info.si_code    = SEGV_MAPERR;
        info.si_addr    = (void *) regs->pc;
        force_sig_info(SIGSEGV, &info, current);
        return;
index a4ec44a..9ced6e9 100644 (file)
@@ -313,12 +313,12 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address)
        siginfo_t info;
 
        if (user_mode(regs)) {
-               /* Send a SIGSEGV */
-               info.si_signo = SIGSEGV;
+               /* Send a SIGBUS */
+               info.si_signo = SIGBUS;
                info.si_errno = 0;
-               /* info.si_code has been set above */
-               info.si_addr = (void *)address;
-               force_sig_info(SIGSEGV, &info, current);
+               info.si_code = BUS_ADRALN;
+               info.si_addr = (void __user *)address;
+               force_sig_info(SIGBUS, &info, current);
        } else {
                printk("KERNEL: Unaligned Access 0x%.8lx\n", address);
                show_registers(regs);
index 4014d90..4fdbb58 100644 (file)
        ENTRY_SAME(ni_syscall)  /* 263: reserved for vserver */
        ENTRY_SAME(add_key)
        ENTRY_SAME(request_key)         /* 265 */
-       ENTRY_SAME(keyctl)
+       ENTRY_COMP(keyctl)
        ENTRY_SAME(ioprio_set)
        ENTRY_SAME(ioprio_get)
        ENTRY_SAME(inotify_init)
index 9d3bd4c..f7da651 100644 (file)
@@ -564,7 +564,7 @@ void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
                fbdv = 16;
        cbdv = ((pllmr & 0x00060000) >> 17) + 1; /* CPU:PLB */
        opdv = ((pllmr & 0x00018000) >> 15) + 1; /* PLB:OPB */
-       ppdv = ((pllmr & 0x00001800) >> 13) + 1; /* PLB:PCI */
+       ppdv = ((pllmr & 0x00006000) >> 13) + 1; /* PLB:PCI */
        epdv = ((pllmr & 0x00001800) >> 11) + 2; /* PLB:EBC */
        udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
 
index c8d7f24..208d4e5 100644 (file)
@@ -58,7 +58,7 @@
 #define PPC_INST_WAIT                  0x7c00007c
 #define PPC_INST_TLBIVAX               0x7c000624
 #define PPC_INST_TLBSRX_DOT            0x7c0006a5
-#define PPC_INST_XXLOR                 0xf0000510
+#define PPC_INST_XXLOR                 0xf0000490
 
 #define PPC_INST_NAP                   0x4c000364
 #define PPC_INST_SLEEP                 0x4c0003a4
index 578e5a0..b3b9d08 100644 (file)
                                "       .llong 0\n"                     \
                                "       .llong 0\n"                     \
                                ".previous"                             \
-                       : "=r" (rval) : "i" (CPU_FTR_CELL_TB_BUG)); rval;})
+                       : "=r" (rval) \
+                       : "i" (CPU_FTR_CELL_TB_BUG) : "cr0"); \
+                       rval;})
 #else
 #define mftb()         ({unsigned long rval;   \
                        asm volatile("mftb %0" : "=r" (rval)); rval;})
index 1e104af..60097b3 100644 (file)
@@ -89,6 +89,11 @@ extern void __init dump_numa_cpu_topology(void);
 extern int sysfs_add_device_to_node(struct sys_device *dev, int nid);
 extern void sysfs_remove_device_from_node(struct sys_device *dev, int nid);
 
+static inline void update_numa_cpu_lookup_table(unsigned int cpu, int node)
+{
+       numa_cpu_lookup_table[cpu] = node;
+}
+
 #else
 
 static inline void dump_numa_cpu_topology(void) {}
@@ -102,6 +107,9 @@ static inline void sysfs_remove_device_from_node(struct sys_device *dev,
                                                int nid)
 {
 }
+
+static inline void update_numa_cpu_lookup_table(unsigned int cpu, int node) {}
+
 #endif /* CONFIG_NUMA */
 
 #if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR)
index 9a52349..6ca7fe0 100644 (file)
@@ -863,6 +863,19 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                        goto instr_done;
 #endif
                case 19:        /* mfcr */
+                       if ((instr >> 20) & 1) {
+                               imm = 0xf0000000UL;
+                               for (sh = 0; sh < 8; ++sh) {
+                                       if (instr & (0x80000 >> sh)) {
+                                               regs->gpr[rd] = regs->ccr & imm;
+                                               break;
+                                       }
+                                       imm >>= 4;
+                               }
+
+                               goto instr_done;
+                       }
+
                        regs->gpr[rd] = regs->ccr;
                        regs->gpr[rd] &= 0xffffffffUL;
                        goto instr_done;
index e9a8b8c..02139e2 100644 (file)
@@ -383,7 +383,7 @@ static int __init htab_dt_scan_hugepage_blocks(unsigned long node,
        printk(KERN_INFO "Huge page(16GB) memory: "
                        "addr = 0x%lX size = 0x%lX pages = %d\n",
                        phys_addr, block_size, expected_pages);
-       if (phys_addr + (16 * GB) <= memblock_end_of_DRAM()) {
+       if (phys_addr + block_size * expected_pages <= memblock_end_of_DRAM()) {
                memblock_reserve(phys_addr, block_size * expected_pages);
                add_gpage(phys_addr, block_size, expected_pages);
        }
index c986d08..c01165d 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/pSeries_reconfig.h>
 #include <asm/xics.h>
 #include "plpar_wrappers.h"
+#include <asm/topology.h>
 #include "offline_states.h"
 
 /* This version can't take the spinlock, because it never returns */
@@ -319,6 +320,7 @@ static void pseries_remove_processor(struct device_node *np)
                        BUG_ON(cpu_online(cpu));
                        set_cpu_present(cpu, false);
                        set_hard_smp_processor_id(cpu, -1);
+                       update_numa_cpu_lookup_table(cpu, -1);
                        break;
                }
                if (cpu >= nr_cpu_ids)
index b239ff5..2be14b2 100644 (file)
@@ -62,6 +62,12 @@ static inline void syscall_get_arguments(struct task_struct *task,
 {
        unsigned long mask = -1UL;
 
+       /*
+        * No arguments for this syscall, there's nothing to do.
+        */
+       if (!n)
+               return;
+
        BUG_ON(i + n > 6);
 #ifdef CONFIG_COMPAT
        if (test_tsk_thread_flag(task, TIF_31BIT))
index ef573c1..b68fef3 100644 (file)
@@ -89,17 +89,13 @@ static inline void restore_access_regs(unsigned int *acrs)
        asm volatile("lam 0,15,%0" : : "Q" (*acrs));
 }
 
-#define switch_to(prev,next,last) do {                                 \
-       if (prev->mm) {                                                 \
-               save_fp_regs(&prev->thread.fp_regs);                    \
-               save_access_regs(&prev->thread.acrs[0]);                \
-       }                                                               \
-       if (next->mm) {                                                 \
-               restore_fp_regs(&next->thread.fp_regs);                 \
-               restore_access_regs(&next->thread.acrs[0]);             \
-               update_per_regs(next);                                  \
-       }                                                               \
-       prev = __switch_to(prev,next);                                  \
+#define switch_to(prev, next, last) do {                               \
+       save_fp_regs(&prev->thread.fp_regs);                            \
+       save_access_regs(&prev->thread.acrs[0]);                        \
+       restore_fp_regs(&next->thread.fp_regs);                         \
+       restore_access_regs(&next->thread.acrs[0]);                     \
+       update_per_regs(next);                                          \
+       prev = __switch_to(prev, next);                                 \
 } while (0)
 
 extern void account_vtime(struct task_struct *, struct task_struct *);
index 38c6645..93ce6de 100644 (file)
@@ -114,7 +114,7 @@ asmlinkage long sys32_setregid16(u16 rgid, u16 egid)
 
 asmlinkage long sys32_setgid16(u16 gid)
 {
-       return sys_setgid((gid_t)gid);
+       return sys_setgid(low2highgid(gid));
 }
 
 asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
@@ -124,7 +124,7 @@ asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
 
 asmlinkage long sys32_setuid16(u16 uid)
 {
-       return sys_setuid((uid_t)uid);
+       return sys_setuid(low2highuid(uid));
 }
 
 asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
@@ -163,12 +163,12 @@ asmlinkage long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user
 
 asmlinkage long sys32_setfsuid16(u16 uid)
 {
-       return sys_setfsuid((uid_t)uid);
+       return sys_setfsuid(low2highuid(uid));
 }
 
 asmlinkage long sys32_setfsgid16(u16 gid)
 {
-       return sys_setfsgid((gid_t)gid);
+       return sys_setfsgid(low2highgid(gid));
 }
 
 static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
@@ -242,6 +242,7 @@ asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
                return retval;
        }
 
+       groups_sort(group_info);
        retval = set_current_groups(group_info);
        put_group_info(group_info);
 
index 847ea15..eaf12bb 100644 (file)
@@ -1542,7 +1542,7 @@ void show_code(struct pt_regs *regs)
 {
        char *mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
        unsigned char code[64];
-       char buffer[64], *ptr;
+       char buffer[128], *ptr;
        mm_segment_t old_fs;
        unsigned long addr;
        int start, end, opsize, hops, i;
@@ -1600,7 +1600,7 @@ void show_code(struct pt_regs *regs)
                start += opsize;
                printk(buffer);
                ptr = buffer;
-               ptr += sprintf(ptr, "\n          ");
+               ptr += sprintf(ptr, "\n\t  ");
                hops++;
        }
        printk("\n");
index 4ccf9f5..65dcae7 100644 (file)
@@ -51,13 +51,12 @@ static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
 static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
                unsigned long end, int write, struct page **pages, int *nr)
 {
-       unsigned long mask, result;
        struct page *head, *page, *tail;
+       unsigned long mask;
        int refs;
 
-       result = write ? 0 : _SEGMENT_ENTRY_RO;
-       mask = result | _SEGMENT_ENTRY_INV;
-       if ((pmd_val(pmd) & mask) != result)
+       mask = (write ? _SEGMENT_ENTRY_RO : 0) | _SEGMENT_ENTRY_INV;
+       if ((pmd_val(pmd) & mask) != 0)
                return 0;
        VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT));
 
index 31330c6..24d7577 100644 (file)
@@ -8,6 +8,7 @@
  */
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/sh_eth.h>
 #include <mach-se/mach/se.h>
 #include <mach-se/mach/mrshpc.h>
 #include <asm/machvec.h>
@@ -114,13 +115,23 @@ static struct platform_device heartbeat_device = {
 #if defined(CONFIG_CPU_SUBTYPE_SH7710) ||\
        defined(CONFIG_CPU_SUBTYPE_SH7712)
 /* SH771X Ethernet driver */
+static struct sh_eth_plat_data sh_eth_plat = {
+       .phy = PHY_ID,
+       .phy_interface = PHY_INTERFACE_MODE_MII,
+};
+
 static struct resource sh_eth0_resources[] = {
        [0] = {
                .start = SH_ETH0_BASE,
-               .end = SH_ETH0_BASE + 0x1B8,
+               .end = SH_ETH0_BASE + 0x1B8 - 1,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
+               .start = SH_TSU_BASE,
+               .end = SH_TSU_BASE + 0x200 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [2] = {
                .start = SH_ETH0_IRQ,
                .end = SH_ETH0_IRQ,
                .flags = IORESOURCE_IRQ,
@@ -131,7 +142,7 @@ static struct platform_device sh_eth0_device = {
        .name = "sh-eth",
        .id     = 0,
        .dev = {
-               .platform_data = PHY_ID,
+               .platform_data = &sh_eth_plat,
        },
        .num_resources = ARRAY_SIZE(sh_eth0_resources),
        .resource = sh_eth0_resources,
@@ -140,10 +151,15 @@ static struct platform_device sh_eth0_device = {
 static struct resource sh_eth1_resources[] = {
        [0] = {
                .start = SH_ETH1_BASE,
-               .end = SH_ETH1_BASE + 0x1B8,
+               .end = SH_ETH1_BASE + 0x1B8 - 1,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
+               .start = SH_TSU_BASE,
+               .end = SH_TSU_BASE + 0x200 - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [2] = {
                .start = SH_ETH1_IRQ,
                .end = SH_ETH1_IRQ,
                .flags = IORESOURCE_IRQ,
@@ -154,7 +170,7 @@ static struct platform_device sh_eth1_device = {
        .name = "sh-eth",
        .id     = 1,
        .dev = {
-               .platform_data = PHY_ID,
+               .platform_data = &sh_eth_plat,
        },
        .num_resources = ARRAY_SIZE(sh_eth1_resources),
        .resource = sh_eth1_resources,
index bd06227..e84a5cf 100644 (file)
@@ -67,7 +67,7 @@ enum {
        GPIO_PTN3, GPIO_PTN2, GPIO_PTN1, GPIO_PTN0,
 
        /* PTQ */
-       GPIO_PTQ7, GPIO_PTQ6, GPIO_PTQ5, GPIO_PTQ4,
+       GPIO_PTQ6, GPIO_PTQ5, GPIO_PTQ4,
        GPIO_PTQ3, GPIO_PTQ2, GPIO_PTQ1, GPIO_PTQ0,
 
        /* PTR */
index 41f9f8b..004759b 100644 (file)
@@ -40,7 +40,7 @@ enum {
 
        /* PTJ */
        GPIO_PTJ0, GPIO_PTJ1, GPIO_PTJ2, GPIO_PTJ3,
-       GPIO_PTJ4, GPIO_PTJ5, GPIO_PTJ6, GPIO_PTJ7_RESV,
+       GPIO_PTJ4, GPIO_PTJ5, GPIO_PTJ6,
 
        /* PTK */
        GPIO_PTK0, GPIO_PTK1, GPIO_PTK2, GPIO_PTK3,
@@ -48,7 +48,7 @@ enum {
 
        /* PTL */
        GPIO_PTL0, GPIO_PTL1, GPIO_PTL2, GPIO_PTL3,
-       GPIO_PTL4, GPIO_PTL5, GPIO_PTL6, GPIO_PTL7_RESV,
+       GPIO_PTL4, GPIO_PTL5, GPIO_PTL6,
 
        /* PTM */
        GPIO_PTM0, GPIO_PTM1, GPIO_PTM2, GPIO_PTM3,
@@ -56,7 +56,7 @@ enum {
 
        /* PTN */
        GPIO_PTN0, GPIO_PTN1, GPIO_PTN2, GPIO_PTN3,
-       GPIO_PTN4, GPIO_PTN5, GPIO_PTN6, GPIO_PTN7_RESV,
+       GPIO_PTN4, GPIO_PTN5, GPIO_PTN6,
 
        /* PTO */
        GPIO_PTO0, GPIO_PTO1, GPIO_PTO2, GPIO_PTO3,
@@ -68,7 +68,7 @@ enum {
 
        /* PTQ */
        GPIO_PTQ0, GPIO_PTQ1, GPIO_PTQ2, GPIO_PTQ3,
-       GPIO_PTQ4, GPIO_PTQ5, GPIO_PTQ6, GPIO_PTQ7_RESV,
+       GPIO_PTQ4, GPIO_PTQ5, GPIO_PTQ6,
 
        /* PTR */
        GPIO_PTR0, GPIO_PTR1, GPIO_PTR2, GPIO_PTR3,
index 14be91c..0ed7db4 100644 (file)
@@ -98,6 +98,7 @@
 /* Base address */
 #define SH_ETH0_BASE 0xA7000000
 #define SH_ETH1_BASE 0xA7000400
+#define SH_TSU_BASE  0xA7000800
 /* PHY ID */
 #if defined(CONFIG_CPU_SUBTYPE_SH7710)
 # define PHY_ID 0x00
index 7bbef95..13a257d 100644 (file)
@@ -706,7 +706,8 @@ asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
                break;
        }
 
-       force_sig_info(SIGFPE, &info, current);
+       info.si_signo = SIGFPE;
+       force_sig_info(info.si_signo, &info, current);
 }
 #endif
 
index bf3e71a..b737c93 100644 (file)
@@ -119,7 +119,8 @@ early_param("maxmem", setup_maxmem);
 static int __init setup_maxnodemem(char *str)
 {
        char *endp;
-       long maxnodemem_mb, node;
+       long maxnodemem_mb;
+       unsigned long node;
 
        node = str ? simple_strtoul(str, &endp, 0) : INT_MAX;
        if (node >= MAX_NUMNODES || *endp != ':' ||
index c2274c1..58d02a7 100644 (file)
@@ -76,6 +76,7 @@ config X86
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
        select CLKEVT_I8253
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
+       select GENERIC_CPU_VULNERABILITIES
        select ARCH_SUPPORTS_ATOMIC_RMW
 
 config INSTRUCTION_DECODER
@@ -312,6 +313,19 @@ config X86_BIGSMP
        ---help---
          This option is needed for the systems that have more than 8 CPUs
 
+config RETPOLINE
+       bool "Avoid speculative indirect branches in kernel"
+       default y
+       help
+         Compile kernel with the retpoline compiler options to guard against
+         kernel-to-user data leaks by avoiding speculative indirect
+         branches. Requires a compiler with -mindirect-branch=thunk-extern
+         support for full protection. The kernel may run slower.
+
+         Without compiler support, at least indirect branches in assembler
+         code are eliminated. Since this includes the syscall entry path,
+         it is not entirely pointless.
+
 if X86_32
 config X86_EXTENDED_PLATFORM
        bool "Support for extended (non-PC) x86 platforms"
index 03dbc7f..e2e3422 100644 (file)
@@ -117,6 +117,14 @@ KBUILD_CFLAGS += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,)
 KBUILD_CFLAGS += $(mflags-y)
 KBUILD_AFLAGS += $(mflags-y)
 
+# Avoid indirect branches in kernel to deal with Spectre
+ifdef CONFIG_RETPOLINE
+    RETPOLINE_CFLAGS += $(call cc-option,-mindirect-branch=thunk-extern -mindirect-branch-register)
+    ifneq ($(RETPOLINE_CFLAGS),)
+        KBUILD_CFLAGS += $(RETPOLINE_CFLAGS) -DRETPOLINE
+    endif
+endif
+
 archscripts:
        $(Q)$(MAKE) $(build)=arch/x86/tools relocs
 
index 3f19c81..ac9ae22 100644 (file)
@@ -7,6 +7,7 @@
  * we just keep it from happening
  */
 #undef CONFIG_PARAVIRT
+#undef CONFIG_PAGE_TABLE_ISOLATION
 #ifdef CONFIG_X86_32
 #define _ASM_X86_DESC_H 1
 #endif
index 7dad700..da4e96b 100644 (file)
@@ -166,6 +166,7 @@ static struct shash_alg alg = {
                .cra_name               =       "crc32c",
                .cra_driver_name        =       "crc32c-intel",
                .cra_priority           =       200,
+               .cra_flags              =       CRYPTO_ALG_OPTIONAL_KEY,
                .cra_blocksize          =       CHKSUM_BLOCK_SIZE,
                .cra_ctxsize            =       sizeof(u32),
                .cra_module             =       THIS_MODULE,
index ae1ee37..6d8c7a4 100644 (file)
@@ -64,13 +64,6 @@ static int encrypt(struct blkcipher_desc *desc,
 
        salsa20_ivsetup(ctx, walk.iv);
 
-       if (likely(walk.nbytes == nbytes))
-       {
-               salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
-                                     walk.dst.virt.addr, nbytes);
-               return blkcipher_walk_done(desc, &walk, 0);
-       }
-
        while (walk.nbytes >= 64) {
                salsa20_encrypt_bytes(ctx, walk.src.virt.addr,
                                      walk.dst.virt.addr,
index 2b55277..750c6f7 100644 (file)
 #include <asm/ia32_unistd.h>   
 #include <asm/thread_info.h>   
 #include <asm/segment.h>
+#include <asm/pgtable_types.h>
+#include <asm/alternative-asm.h>
+#include <asm/cpufeature.h>
+#include <asm/kaiser.h>
 #include <asm/irqflags.h>
 #include <linux/linkage.h>
+#include <asm/nospec-branch.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
 #include <linux/elf-em.h>
@@ -120,6 +125,7 @@ ENTRY(ia32_sysenter_target)
        CFI_DEF_CFA     rsp,0
        CFI_REGISTER    rsp,rbp
        SWAPGS_UNSAFE_STACK
+       SWITCH_KERNEL_CR3_NO_STACK
        movq    PER_CPU_VAR(kernel_stack), %rsp
        addq    $(KERNEL_STACK_OFFSET),%rsp
        /*
@@ -155,12 +161,19 @@ ENTRY(ia32_sysenter_target)
        testl  $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
        CFI_REMEMBER_STATE
        jnz  sysenter_tracesys
-       cmpq    $(IA32_NR_syscalls-1),%rax
-       ja      ia32_badsys
+       cmpq    $(IA32_NR_syscalls),%rax
+       jae     ia32_badsys
 sysenter_do_call:
+       sbb     %r8,%r8                         /* array_index_mask_nospec() */
+       and     %r8,%rax
        IA32_ARG_FIXUP
 sysenter_dispatch:
+#ifdef CONFIG_RETPOLINE
+       movq    ia32_sys_call_table(,%rax,8),%rax
+       call    __x86_indirect_thunk_rax
+#else
        call    *ia32_sys_call_table(,%rax,8)
+#endif
        movq    %rax,RAX-ARGOFFSET(%rsp)
        GET_THREAD_INFO(%r10)
        DISABLE_INTERRUPTS(CLBR_NONE)
@@ -183,6 +196,7 @@ sysexit_from_sys_call:
        popq_cfi %rcx                           /* User %esp */
        CFI_REGISTER rsp,rcx
        TRACE_IRQS_ON
+       SWITCH_USER_CR3
        ENABLE_INTERRUPTS_SYSEXIT32
 
 #ifdef CONFIG_AUDITSYSCALL
@@ -195,8 +209,10 @@ sysexit_from_sys_call:
        movl $AUDIT_ARCH_I386,%edi      /* 1st arg: audit arch */
        call audit_syscall_entry
        movl RAX-ARGOFFSET(%rsp),%eax   /* reload syscall number */
-       cmpq $(IA32_NR_syscalls-1),%rax
-       ja ia32_badsys
+       cmpq $(IA32_NR_syscalls),%rax
+       jae  ia32_badsys
+       sbb  %r8,%r8                    /* array_index_mask_nospec() */
+       and  %r8,%rax
        movl %ebx,%edi                  /* reload 1st syscall arg */
        movl RCX-ARGOFFSET(%rsp),%esi   /* reload 2nd syscall arg */
        movl RDX-ARGOFFSET(%rsp),%edx   /* reload 3rd syscall arg */
@@ -248,8 +264,8 @@ sysenter_tracesys:
        call    syscall_trace_enter
        LOAD_ARGS32 ARGOFFSET  /* reload args from stack in case ptrace changed it */
        RESTORE_REST
-       cmpq    $(IA32_NR_syscalls-1),%rax
-       ja      int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */
+       cmpq    $(IA32_NR_syscalls),%rax
+       jae     int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */
        jmp     sysenter_do_call
        CFI_ENDPROC
 ENDPROC(ia32_sysenter_target)
@@ -281,6 +297,7 @@ ENTRY(ia32_cstar_target)
        CFI_REGISTER    rip,rcx
        /*CFI_REGISTER  rflags,r11*/
        SWAPGS_UNSAFE_STACK
+       SWITCH_KERNEL_CR3_NO_STACK
        movl    %esp,%r8d
        CFI_REGISTER    rsp,r8
        movq    PER_CPU_VAR(kernel_stack),%rsp
@@ -314,12 +331,19 @@ ENTRY(ia32_cstar_target)
        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
        CFI_REMEMBER_STATE
        jnz   cstar_tracesys
-       cmpq $IA32_NR_syscalls-1,%rax
-       ja  ia32_badsys
+       cmpq $IA32_NR_syscalls,%rax
+       jae  ia32_badsys
 cstar_do_call:
+       sbb  %r8,%r8                            /* array_index_mask_nospec() */
+       and  %r8,%rax
        IA32_ARG_FIXUP 1
 cstar_dispatch:
+#ifdef CONFIG_RETPOLINE
+       movq ia32_sys_call_table(,%rax,8),%rax
+       call __x86_indirect_thunk_rax
+#else
        call *ia32_sys_call_table(,%rax,8)
+#endif
        movq %rax,RAX-ARGOFFSET(%rsp)
        GET_THREAD_INFO(%r10)
        DISABLE_INTERRUPTS(CLBR_NONE)
@@ -337,6 +361,7 @@ sysretl_from_sys_call:
        xorq    %r9,%r9
        xorq    %r8,%r8
        TRACE_IRQS_ON
+       SWITCH_USER_CR3
        movl RSP-ARGOFFSET(%rsp),%esp
        CFI_RESTORE rsp
        USERGS_SYSRET32
@@ -367,8 +392,8 @@ cstar_tracesys:
        LOAD_ARGS32 ARGOFFSET, 1  /* reload args from stack in case ptrace changed it */
        RESTORE_REST
        xchgl %ebp,%r9d
-       cmpq $(IA32_NR_syscalls-1),%rax
-       ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */
+       cmpq $(IA32_NR_syscalls),%rax
+       jae int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */
        jmp cstar_do_call
 END(ia32_cstar_target)
                                
@@ -409,6 +434,7 @@ ENTRY(ia32_syscall)
        CFI_REL_OFFSET  rip,RIP-RIP
        PARAVIRT_ADJUST_EXCEPTION_FRAME
        SWAPGS
+       SWITCH_KERNEL_CR3_NO_STACK
        /*
         * No need to follow this irqs on/off section: the syscall
         * disabled irqs and here we enable it straight after entry:
@@ -424,11 +450,18 @@ ENTRY(ia32_syscall)
        orl   $TS_COMPAT,TI_status(%r10)
        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
        jnz ia32_tracesys
-       cmpq $(IA32_NR_syscalls-1),%rax
-       ja ia32_badsys
+       cmpq $(IA32_NR_syscalls),%rax
+       ja ia32_badsys
 ia32_do_call:
+       sbb  %r8,%r8                            /* array_index_mask_nospec() */
+       and  %r8,%rax
        IA32_ARG_FIXUP
+#ifdef CONFIG_RETPOLINE
+       movq ia32_sys_call_table(,%rax,8),%rax
+       call __x86_indirect_thunk_rax
+#else
        call *ia32_sys_call_table(,%rax,8) # xxx: rip relative
+#endif
 ia32_sysret:
        movq %rax,RAX-ARGOFFSET(%rsp)
 ia32_ret_from_sys_call:
@@ -443,8 +476,8 @@ ia32_tracesys:
        call syscall_trace_enter
        LOAD_ARGS32 ARGOFFSET  /* reload args from stack in case ptrace changed it */
        RESTORE_REST
-       cmpq $(IA32_NR_syscalls-1),%rax
-       ja  int_ret_from_sys_call       /* ia32_tracesys has set RAX(%rsp) */
+       cmpq $(IA32_NR_syscalls),%rax
+       jae int_ret_from_sys_call       /* ia32_tracesys has set RAX(%rsp) */
        jmp ia32_do_call
 END(ia32_syscall)
 
@@ -494,7 +527,7 @@ ENTRY(ia32_ptregs_common)
        CFI_REL_OFFSET  rsp,RSP-ARGOFFSET
 /*     CFI_REL_OFFSET  ss,SS-ARGOFFSET*/
        SAVE_REST
-       call *%rax
+       CALL_NOSPEC %rax
        RESTORE_REST
        jmp  ia32_sysret        /* misbalances the return cache */
        CFI_ENDPROC
index 091508b..fd4b8eb 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef _ASM_X86_ALTERNATIVE_ASM_H
+#define _ASM_X86_ALTERNATIVE_ASM_H
+
 #ifdef __ASSEMBLY__
 
 #include <asm/asm.h>
        .endm
 #endif
 
-.macro altinstruction_entry orig alt feature orig_len alt_len
+.macro altinstruction_entry orig alt feature orig_len alt_len pad_len
        .long \orig - .
        .long \alt - .
        .word \feature
        .byte \orig_len
        .byte \alt_len
+       .byte \pad_len
+.endm
+
+.macro ALTERNATIVE oldinstr, newinstr, feature
+140:
+       \oldinstr
+141:
+       .skip -(((144f-143f)-(141b-140b)) > 0) * ((144f-143f)-(141b-140b)),0x90
+142:
+
+       .pushsection .altinstructions,"a"
+       altinstruction_entry 140b,143f,\feature,142b-140b,144f-143f,142b-141b
+       .popsection
+
+       .pushsection .altinstr_replacement,"ax"
+143:
+       \newinstr
+144:
+       .popsection
+.endm
+
+#define old_len                        141b-140b
+#define new_len1               144f-143f
+#define new_len2               145f-144f
+
+/*
+ * max without conditionals. Idea adapted from:
+ * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
+ */
+#define alt_max_short(a, b)    ((a) ^ (((a) ^ (b)) & -(-((a) < (b)))))
+
+.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
+140:
+       \oldinstr
+141:
+       .skip -((alt_max_short(new_len1, new_len2) - (old_len)) > 0) * \
+               (alt_max_short(new_len1, new_len2) - (old_len)),0x90
+142:
+
+       .pushsection .altinstructions,"a"
+       altinstruction_entry 140b,143f,\feature1,142b-140b,144f-143f,142b-141b
+       altinstruction_entry 140b,144f,\feature2,142b-140b,145f-144f,142b-141b
+       .popsection
+
+       .pushsection .altinstr_replacement,"ax"
+143:
+       \newinstr1
+144:
+       \newinstr2
+145:
+       .popsection
 .endm
 
 #endif  /*  __ASSEMBLY__  */
+
+#endif /* _ASM_X86_ALTERNATIVE_ASM_H */
index 37ad100..375459d 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _ASM_X86_ALTERNATIVE_H
 #define _ASM_X86_ALTERNATIVE_H
 
+#ifndef __ASSEMBLY__
+
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/stringify.h>
@@ -47,8 +49,9 @@ struct alt_instr {
        s32 repl_offset;        /* offset to replacement instruction */
        u16 cpuid;              /* cpuid bit set for replacement */
        u8  instrlen;           /* length of original instruction */
-       u8  replacementlen;     /* length of new instruction, <= instrlen */
-};
+       u8  replacementlen;     /* length of new instruction */
+       u8  padlen;             /* length of build-time padding */
+} __packed;
 
 extern void alternative_instructions(void);
 extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
@@ -60,7 +63,7 @@ extern void alternatives_smp_module_add(struct module *mod, char *name,
                                        void *locks, void *locks_end,
                                        void *text, void *text_end);
 extern void alternatives_smp_module_del(struct module *mod);
-extern void alternatives_smp_switch(int smp);
+extern void alternatives_enable_smp(void);
 extern int alternatives_text_reserved(void *start, void *end);
 extern bool skip_smp_alternatives;
 #else
@@ -68,30 +71,80 @@ static inline void alternatives_smp_module_add(struct module *mod, char *name,
                                               void *locks, void *locks_end,
                                               void *text, void *text_end) {}
 static inline void alternatives_smp_module_del(struct module *mod) {}
-static inline void alternatives_smp_switch(int smp) {}
+static inline void alternatives_enable_smp(void) {}
 static inline int alternatives_text_reserved(void *start, void *end)
 {
        return 0;
 }
 #endif /* CONFIG_SMP */
 
+#define b_replacement(num)     "664"#num
+#define e_replacement(num)     "665"#num
+
+#define alt_end_marker         "663"
+#define alt_slen               "662b-661b"
+#define alt_pad_len            alt_end_marker"b-662b"
+#define alt_total_slen         alt_end_marker"b-661b"
+#define alt_rlen(num)          e_replacement(num)"f-"b_replacement(num)"f"
+
+#define __OLDINSTR(oldinstr, num)                                      \
+       "661:\n\t" oldinstr "\n662:\n"                                  \
+       ".skip -(((" alt_rlen(num) ")-(" alt_slen ")) > 0) * "          \
+               "((" alt_rlen(num) ")-(" alt_slen ")),0x90\n"
+
+#define OLDINSTR(oldinstr, num)                                                \
+       __OLDINSTR(oldinstr, num)                                       \
+       alt_end_marker ":\n"
+
+/*
+ * max without conditionals. Idea adapted from:
+ * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
+ *
+ * The additional "-" is needed because gas works with s32s.
+ */
+#define alt_max_short(a, b)    "((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") - (" b ")))))"
+
+/*
+ * Pad the second replacement alternative with additional NOPs if it is
+ * additionally longer than the first replacement alternative.
+ */
+#define OLDINSTR_2(oldinstr, num1, num2) \
+       "661:\n\t" oldinstr "\n662:\n"                                                          \
+       ".skip -((" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")) > 0) * "  \
+               "(" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")), 0x90\n"  \
+       alt_end_marker ":\n"
+
+#define ALTINSTR_ENTRY(feature, num)                                         \
+       " .long 661b - .\n"                             /* label           */ \
+       " .long " b_replacement(num)"f - .\n"           /* new instruction */ \
+       " .word " __stringify(feature) "\n"             /* feature bit     */ \
+       " .byte " alt_total_slen "\n"                   /* source len      */ \
+       " .byte " alt_rlen(num) "\n"                    /* replacement len */ \
+       " .byte " alt_pad_len "\n"                      /* pad len */
+
+#define ALTINSTR_REPLACEMENT(newinstr, feature, num)   /* replacement */     \
+       b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n\t"
+
 /* alternative assembly primitive: */
 #define ALTERNATIVE(oldinstr, newinstr, feature)                       \
-                                                                       \
-      "661:\n\t" oldinstr "\n662:\n"                                   \
-      ".section .altinstructions,\"a\"\n"                              \
-      "         .long 661b - .\n"                      /* label           */   \
-      "         .long 663f - .\n"                      /* new instruction */   \
-      "         .word " __stringify(feature) "\n"      /* feature bit     */   \
-      "         .byte 662b-661b\n"                     /* sourcelen       */   \
-      "         .byte 664f-663f\n"                     /* replacementlen  */   \
-      ".previous\n"                                                    \
-      ".section .discard,\"aw\",@progbits\n"                           \
-      "         .byte 0xff + (664f-663f) - (662b-661b)\n" /* rlen <= slen */   \
-      ".previous\n"                                                    \
-      ".section .altinstr_replacement, \"ax\"\n"                       \
-      "663:\n\t" newinstr "\n664:\n"           /* replacement     */   \
-      ".previous"
+       OLDINSTR(oldinstr, 1)                                           \
+       ".pushsection .altinstructions,\"a\"\n"                         \
+       ALTINSTR_ENTRY(feature, 1)                                      \
+       ".popsection\n"                                                 \
+       ".pushsection .altinstr_replacement, \"ax\"\n"                  \
+       ALTINSTR_REPLACEMENT(newinstr, feature, 1)                      \
+       ".popsection\n"
+
+#define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
+       OLDINSTR_2(oldinstr, 1, 2)                                      \
+       ".pushsection .altinstructions,\"a\"\n"                         \
+       ALTINSTR_ENTRY(feature1, 1)                                     \
+       ALTINSTR_ENTRY(feature2, 2)                                     \
+       ".popsection\n"                                                 \
+       ".pushsection .altinstr_replacement, \"ax\"\n"                  \
+       ALTINSTR_REPLACEMENT(newinstr1, feature1, 1)                    \
+       ALTINSTR_REPLACEMENT(newinstr2, feature2, 2)                    \
+       ".popsection\n"
 
 /*
  * This must be included *after* the definition of ALTERNATIVE due to
@@ -114,6 +167,9 @@ static inline int alternatives_text_reserved(void *start, void *end)
 #define alternative(oldinstr, newinstr, feature)                       \
        asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory")
 
+#define alternative_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \
+       asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) ::: "memory")
+
 /*
  * Alternative inline assembly with input.
  *
@@ -186,4 +242,6 @@ extern void *text_poke(void *addr, const void *opcode, size_t len);
 extern void *text_poke_smp(void *addr, const void *opcode, size_t len);
 extern void text_poke_smp_batch(struct text_poke_param *params, int n);
 
+#endif /* __ASSEMBLY__ */
+
 #endif /* _ASM_X86_ALTERNATIVE_H */
index 9412d65..14b488f 100644 (file)
@@ -3,23 +3,27 @@
 
 #ifdef __ASSEMBLY__
 # define __ASM_FORM(x) x
+# define __ASM_FORM_RAW(x)     x
 # define __ASM_FORM_COMMA(x) x,
 # define __ASM_EX_SEC  .section __ex_table, "a"
 #else
 # define __ASM_FORM(x) " " #x " "
+# define __ASM_FORM_RAW(x)     #x
 # define __ASM_FORM_COMMA(x) " " #x ","
 # define __ASM_EX_SEC  " .section __ex_table,\"a\"\n"
 #endif
 
 #ifdef CONFIG_X86_32
 # define __ASM_SEL(a,b) __ASM_FORM(a)
+# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a)
 #else
 # define __ASM_SEL(a,b) __ASM_FORM(b)
+# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
 #endif
 
 #define __ASM_SIZE(inst, ...)  __ASM_SEL(inst##l##__VA_ARGS__, \
                                          inst##q##__VA_ARGS__)
-#define __ASM_REG(reg)         __ASM_SEL(e##reg, r##reg)
+#define __ASM_REG(reg)         __ASM_SEL_RAW(e##reg, r##reg)
 
 #define _ASM_PTR       __ASM_SEL(.long, .quad)
 #define _ASM_ALIGN     __ASM_SEL(.balign 4, .balign 8)
        " .previous\n"
 #endif
 
+#ifndef __ASSEMBLY__
+/*
+ * This output constraint should be used for any inline asm which has a "call"
+ * instruction.  Otherwise the asm may be inserted before the frame pointer
+ * gets set up by the containing function.  If you forget to do this, objtool
+ * may print a "call without frame pointer save/setup" warning.
+ */
+register unsigned long current_stack_pointer asm(_ASM_SP);
+#define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer)
+#endif
+
 #endif /* _ASM_X86_ASM_H */
index 1775d6e..7aa2d34 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/compiler.h>
 #include <asm/alternative.h>
 
+#define BIT_64(n)                      (U64_C(1) << (n))
+
 /*
  * These have to be done with inline assembly: that way the bit-setting
  * is guaranteed to be atomic. All bit operations return 0 if the bit
diff --git a/arch/x86/include/asm/cmdline.h b/arch/x86/include/asm/cmdline.h
new file mode 100644 (file)
index 0000000..84ae170
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _ASM_X86_CMDLINE_H
+#define _ASM_X86_CMDLINE_H
+
+int cmdline_find_option_bool(const char *cmdline_ptr, const char *option);
+int cmdline_find_option(const char *cmdline_ptr, const char *option,
+                       char *buffer, int bufsize);
+
+#endif /* _ASM_X86_CMDLINE_H */
index b8a5fe5..fbad310 100644 (file)
@@ -7,6 +7,7 @@
 #include <asm/required-features.h>
 
 #define NCAPINTS       10      /* N 32-bit words worth of info */
+#define NBUGINTS       1       /* N 32-bit bug flags */
 
 /*
  * Note: If the comment begins with a quoted string, that string is used
 #define X86_FEATURE_PLN                (7*32+ 5) /* Intel Power Limit Notification */
 #define X86_FEATURE_PTS                (7*32+ 6) /* Intel Package Thermal Status */
 #define X86_FEATURE_DTHERM     (7*32+ 7) /* Digital Thermal Sensor */
+#define X86_FEATURE_INVPCID_SINGLE (7*32+ 8) /* Effectively INVPCID && CR4.PCIDE=1 */
+#define X86_FEATURE_RSB_CTXSW  (7*32+9) /* "" Fill RSB on context switches */
+
+#define X86_FEATURE_RETPOLINE  (7*32+29) /* "" Generic Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_AMD (7*32+30) /* "" AMD Retpoline mitigation for Spectre variant 2 */
+/* Because the ALTERNATIVE scheme is for members of the X86_FEATURE club... */
+#define X86_FEATURE_KAISER     ( 7*32+31) /* "" CONFIG_PAGE_TABLE_ISOLATION w/o nokaiser */
 
 /* Virtualization flags: Linux defined, word 8 */
 #define X86_FEATURE_TPR_SHADOW  (8*32+ 0) /* Intel TPR Shadow */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
 #define X86_FEATURE_FSGSBASE   (9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/
+#define X86_FEATURE_HLE                (9*32+ 4) /* Hardware Lock Elision */
 #define X86_FEATURE_SMEP       (9*32+ 7) /* Supervisor Mode Execution Protection */
 #define X86_FEATURE_ERMS       (9*32+ 9) /* Enhanced REP MOVSB/STOSB */
+#define X86_FEATURE_INVPCID    (9*32+10) /* Invalidate Processor Context ID */
+#define X86_FEATURE_RTM                (9*32+11) /* Restricted Transactional Memory */
+
+/*
+ * BUG word(s)
+ */
+#define X86_BUG(x)             (NCAPINTS*32 + (x))
+
+#define X86_BUG_CPU_MELTDOWN   X86_BUG(0) /* CPU is affected by meltdown attack and needs kernel page table isolation */
+#define X86_BUG_SPECTRE_V1     X86_BUG(1) /* CPU is affected by Spectre variant 1 attack with conditional branches */
+#define X86_BUG_SPECTRE_V2     X86_BUG(2) /* CPU is affected by Spectre variant 2 attack with indirect branches */
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 
@@ -245,6 +265,8 @@ extern const char * const x86_power_flags[32];
        set_bit(bit, (unsigned long *)cpu_caps_set);    \
 } while (0)
 
+#define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit)
+
 #define cpu_has_fpu            boot_cpu_has(X86_FEATURE_FPU)
 #define cpu_has_vme            boot_cpu_has(X86_FEATURE_VME)
 #define cpu_has_de             boot_cpu_has(X86_FEATURE_DE)
@@ -334,7 +356,7 @@ extern const char * const x86_power_flags[32];
  */
 static __always_inline __pure bool __static_cpu_has(u16 bit)
 {
-#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
+#ifdef CC_HAVE_ASM_GOTO
                asm_volatile_goto("1: jmp %l[t_no]\n"
                         "2:\n"
                         ".section .altinstructions,\"a\"\n"
@@ -343,6 +365,7 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
                         " .word %P0\n"         /* feature bit */
                         " .byte 2b - 1b\n"     /* source len */
                         " .byte 0\n"           /* replacement len */
+                        " .byte 0\n"           /* pad len */
                         ".previous\n"
                         /* skipping size check since replacement size = 0 */
                         : : "i" (bit) : : t_no);
@@ -360,6 +383,7 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
                             " .word %P1\n"             /* feature bit */
                             " .byte 2b - 1b\n"         /* source len */
                             " .byte 4f - 3f\n"         /* replacement len */
+                            " .byte 0\n"               /* pad len */
                             ".previous\n"
                             ".section .discard,\"aw\",@progbits\n"
                             " .byte 0xff + (4f-3f) - (2b-1b)\n" /* size check */
@@ -388,6 +412,13 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
 #define static_cpu_has(bit) boot_cpu_has(bit)
 #endif
 
+#define cpu_has_bug(c, bit)    cpu_has(c, (bit))
+#define set_cpu_bug(c, bit)    set_cpu_cap(c, (bit))
+#define clear_cpu_bug(c, bit)  clear_cpu_cap(c, (bit));
+
+#define static_cpu_has_bug(bit)        static_cpu_has((bit))
+#define boot_cpu_has_bug(bit)  cpu_has_bug(&boot_cpu_data, (bit))
+
 #endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
 
 #endif /* _ASM_X86_CPUFEATURE_H */
index 382ce8a..7f1ead9 100644 (file)
@@ -40,7 +40,7 @@ struct gdt_page {
        struct desc_struct gdt[GDT_ENTRIES];
 } __attribute__((aligned(PAGE_SIZE)));
 
-DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page);
+DECLARE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(struct gdt_page, gdt_page);
 
 static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu)
 {
index 81a1569..e67dd21 100644 (file)
@@ -192,6 +192,7 @@ void set_personality_ia32(void);
 
 #define ELF_CORE_COPY_REGS(pr_reg, regs)                       \
 do {                                                           \
+       unsigned long base;                                     \
        unsigned v;                                             \
        (pr_reg)[0] = (regs)->r15;                              \
        (pr_reg)[1] = (regs)->r14;                              \
@@ -214,8 +215,8 @@ do {                                                                \
        (pr_reg)[18] = (regs)->flags;                           \
        (pr_reg)[19] = (regs)->sp;                              \
        (pr_reg)[20] = (regs)->ss;                              \
-       (pr_reg)[21] = current->thread.fs;                      \
-       (pr_reg)[22] = current->thread.gs;                      \
+       rdmsrl(MSR_FS_BASE, base); (pr_reg)[21] = base;         \
+       rdmsrl(MSR_KERNEL_GS_BASE, base); (pr_reg)[22] = base;  \
        asm("movl %%ds,%0" : "=r" (v)); (pr_reg)[23] = v;       \
        asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v;       \
        asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v;       \
index 55e4de6..33c8d1d 100644 (file)
@@ -18,8 +18,8 @@ typedef struct {
 #ifdef CONFIG_SMP
        unsigned int irq_resched_count;
        unsigned int irq_call_count;
-       unsigned int irq_tlb_count;
 #endif
+       unsigned int irq_tlb_count;
 #ifdef CONFIG_X86_THERMAL_VECTOR
        unsigned int irq_thermal_count;
 #endif
index eb92a6e..3354a39 100644 (file)
@@ -164,7 +164,7 @@ extern asmlinkage void smp_invalidate_interrupt(struct pt_regs *);
 extern void (*__initconst interrupt[NR_VECTORS-FIRST_EXTERNAL_VECTOR])(void);
 
 typedef int vector_irq_t[NR_VECTORS];
-DECLARE_PER_CPU(vector_irq_t, vector_irq);
+DECLARE_PER_CPU_USER_MAPPED(vector_irq_t, vector_irq);
 extern void setup_vector_irq(int cpu);
 
 #ifdef CONFIG_X86_IO_APIC
diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h
new file mode 100644 (file)
index 0000000..6999f7d
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef _ASM_X86_INTEL_FAMILY_H
+#define _ASM_X86_INTEL_FAMILY_H
+
+/*
+ * "Big Core" Processors (Branded as Core, Xeon, etc...)
+ *
+ * The "_X" parts are generally the EP and EX Xeons, or the
+ * "Extreme" ones, like Broadwell-E.
+ *
+ * Things ending in "2" are usually because we have no better
+ * name for them.  There's no processor called "WESTMERE2".
+ */
+
+#define INTEL_FAM6_CORE_YONAH          0x0E
+#define INTEL_FAM6_CORE2_MEROM         0x0F
+#define INTEL_FAM6_CORE2_MEROM_L       0x16
+#define INTEL_FAM6_CORE2_PENRYN                0x17
+#define INTEL_FAM6_CORE2_DUNNINGTON    0x1D
+
+#define INTEL_FAM6_NEHALEM             0x1E
+#define INTEL_FAM6_NEHALEM_EP          0x1A
+#define INTEL_FAM6_NEHALEM_EX          0x2E
+#define INTEL_FAM6_WESTMERE            0x25
+#define INTEL_FAM6_WESTMERE2           0x1F
+#define INTEL_FAM6_WESTMERE_EP         0x2C
+#define INTEL_FAM6_WESTMERE_EX         0x2F
+
+#define INTEL_FAM6_SANDYBRIDGE         0x2A
+#define INTEL_FAM6_SANDYBRIDGE_X       0x2D
+#define INTEL_FAM6_IVYBRIDGE           0x3A
+#define INTEL_FAM6_IVYBRIDGE_X         0x3E
+
+#define INTEL_FAM6_HASWELL_CORE                0x3C
+#define INTEL_FAM6_HASWELL_X           0x3F
+#define INTEL_FAM6_HASWELL_ULT         0x45
+#define INTEL_FAM6_HASWELL_GT3E                0x46
+
+#define INTEL_FAM6_BROADWELL_CORE      0x3D
+#define INTEL_FAM6_BROADWELL_XEON_D    0x56
+#define INTEL_FAM6_BROADWELL_GT3E      0x47
+#define INTEL_FAM6_BROADWELL_X         0x4F
+
+#define INTEL_FAM6_SKYLAKE_MOBILE      0x4E
+#define INTEL_FAM6_SKYLAKE_DESKTOP     0x5E
+#define INTEL_FAM6_SKYLAKE_X           0x55
+#define INTEL_FAM6_KABYLAKE_MOBILE     0x8E
+#define INTEL_FAM6_KABYLAKE_DESKTOP    0x9E
+
+/* "Small Core" Processors (Atom) */
+
+#define INTEL_FAM6_ATOM_PINEVIEW       0x1C
+#define INTEL_FAM6_ATOM_LINCROFT       0x26
+#define INTEL_FAM6_ATOM_PENWELL                0x27
+#define INTEL_FAM6_ATOM_CLOVERVIEW     0x35
+#define INTEL_FAM6_ATOM_CEDARVIEW      0x36
+#define INTEL_FAM6_ATOM_SILVERMONT1    0x37 /* BayTrail/BYT / Valleyview */
+#define INTEL_FAM6_ATOM_SILVERMONT2    0x4D /* Avaton/Rangely */
+#define INTEL_FAM6_ATOM_AIRMONT                0x4C /* CherryTrail / Braswell */
+#define INTEL_FAM6_ATOM_MERRIFIELD1    0x4A /* Tangier */
+#define INTEL_FAM6_ATOM_MERRIFIELD2    0x5A /* Annidale */
+#define INTEL_FAM6_ATOM_GOLDMONT       0x5C
+#define INTEL_FAM6_ATOM_DENVERTON      0x5F /* Goldmont Microserver */
+
+/* Xeon Phi */
+
+#define INTEL_FAM6_XEON_PHI_KNL                0x57 /* Knights Landing */
+
+#endif /* _ASM_X86_INTEL_FAMILY_H */
diff --git a/arch/x86/include/asm/kaiser.h b/arch/x86/include/asm/kaiser.h
new file mode 100644 (file)
index 0000000..de6fd81
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef _ASM_X86_KAISER_H
+#define _ASM_X86_KAISER_H
+
+#include <asm/processor-flags.h> /* For PCID constants */
+
+/*
+ * This file includes the definitions for the KAISER feature.
+ * KAISER is a counter measure against x86_64 side channel attacks on
+ * the kernel virtual memory.  It has a shadow pgd for every process: the
+ * shadow pgd has a minimalistic kernel-set mapped, but includes the whole
+ * user memory. Within a kernel context switch, or when an interrupt is handled,
+ * the pgd is switched to the normal one. When the system switches to user mode,
+ * the shadow pgd is enabled. By this, the virtual memory caches are freed,
+ * and the user may not attack the whole kernel memory.
+ *
+ * A minimalistic kernel mapping holds the parts needed to be mapped in user
+ * mode, such as the entry/exit functions of the user space, or the stacks.
+ */
+
+#define KAISER_SHADOW_PGD_OFFSET 0x1000
+
+#ifdef __ASSEMBLY__
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+
+.macro _SWITCH_TO_KERNEL_CR3 reg
+movq %cr3, \reg
+andq $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), \reg
+/* If PCID enabled, set X86_CR3_PCID_NOFLUSH_BIT */
+ALTERNATIVE "", "bts $63, \reg", X86_FEATURE_PCID
+movq \reg, %cr3
+.endm
+
+.macro _SWITCH_TO_USER_CR3 reg regb
+/*
+ * regb must be the low byte portion of reg: because we have arranged
+ * for the low byte of the user PCID to serve as the high byte of NOFLUSH
+ * (0x80 for each when PCID is enabled, or 0x00 when PCID and NOFLUSH are
+ * not enabled): so that the one register can update both memory and cr3.
+ */
+movq %cr3, \reg
+orq  PER_CPU_VAR(x86_cr3_pcid_user), \reg
+js   9f
+/* If PCID enabled, FLUSH this time, reset to NOFLUSH for next time */
+movb \regb, PER_CPU_VAR(x86_cr3_pcid_user+7)
+9:
+movq \reg, %cr3
+.endm
+
+.macro SWITCH_KERNEL_CR3
+ALTERNATIVE "jmp 8f", "pushq %rax", X86_FEATURE_KAISER
+_SWITCH_TO_KERNEL_CR3 %rax
+popq %rax
+8:
+.endm
+
+.macro SWITCH_USER_CR3
+ALTERNATIVE "jmp 8f", "pushq %rax", X86_FEATURE_KAISER
+_SWITCH_TO_USER_CR3 %rax %al
+popq %rax
+8:
+.endm
+
+.macro SWITCH_KERNEL_CR3_NO_STACK
+ALTERNATIVE "jmp 8f", \
+       __stringify(movq %rax, PER_CPU_VAR(unsafe_stack_register_backup)), \
+       X86_FEATURE_KAISER
+_SWITCH_TO_KERNEL_CR3 %rax
+movq PER_CPU_VAR(unsafe_stack_register_backup), %rax
+8:
+.endm
+
+#else /* CONFIG_PAGE_TABLE_ISOLATION */
+
+.macro SWITCH_KERNEL_CR3
+.endm
+.macro SWITCH_USER_CR3
+.endm
+.macro SWITCH_KERNEL_CR3_NO_STACK
+.endm
+
+#endif /* CONFIG_PAGE_TABLE_ISOLATION */
+
+#else /* __ASSEMBLY__ */
+
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+/*
+ * Upon kernel/user mode switch, it may happen that the address
+ * space has to be switched before the registers have been
+ * stored.  To change the address space, another register is
+ * needed.  A register therefore has to be stored/restored.
+*/
+DECLARE_PER_CPU_USER_MAPPED(unsigned long, unsafe_stack_register_backup);
+
+DECLARE_PER_CPU(unsigned long, x86_cr3_pcid_user);
+
+extern char __per_cpu_user_mapped_start[], __per_cpu_user_mapped_end[];
+
+extern int kaiser_enabled;
+extern void __init kaiser_check_boottime_disable(void);
+#else
+#define kaiser_enabled 0
+static inline void __init kaiser_check_boottime_disable(void) {}
+#endif /* CONFIG_PAGE_TABLE_ISOLATION */
+
+/*
+ * Kaiser function prototypes are needed even when CONFIG_PAGE_TABLE_ISOLATION is not set,
+ * so as to build with tests on kaiser_enabled instead of #ifdefs.
+ */
+
+/**
+ *  kaiser_add_mapping - map a virtual memory part to the shadow (user) mapping
+ *  @addr: the start address of the range
+ *  @size: the size of the range
+ *  @flags: The mapping flags of the pages
+ *
+ *  The mapping is done on a global scope, so no bigger
+ *  synchronization has to be done.  the pages have to be
+ *  manually unmapped again when they are not needed any longer.
+ */
+extern int kaiser_add_mapping(unsigned long addr, unsigned long size, unsigned long flags);
+
+/**
+ *  kaiser_remove_mapping - unmap a virtual memory part of the shadow mapping
+ *  @addr: the start address of the range
+ *  @size: the size of the range
+ */
+extern void kaiser_remove_mapping(unsigned long start, unsigned long size);
+
+/**
+ *  kaiser_init - Initialize the shadow mapping
+ *
+ *  Most parts of the shadow mapping can be mapped upon boot
+ *  time.  Only per-process things like the thread stacks
+ *  or a new LDT have to be mapped at runtime.  These boot-
+ *  time mappings are permanent and never unmapped.
+ */
+extern void kaiser_init(void);
+
+#endif /* __ASSEMBLY */
+
+#endif /* _ASM_X86_KAISER_H */
index 51f85fc..f0afe86 100644 (file)
@@ -694,13 +694,15 @@ enum emulation_result {
 #define EMULTYPE_NO_DECODE         (1 << 0)
 #define EMULTYPE_TRAP_UD           (1 << 1)
 #define EMULTYPE_SKIP              (1 << 2)
+#define EMULTYPE_NO_REEXECUTE      (1 << 4)
 int x86_emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2,
                            int emulation_type, void *insn, int insn_len);
 
 static inline int emulate_instruction(struct kvm_vcpu *vcpu,
                        int emulation_type)
 {
-       return x86_emulate_instruction(vcpu, 0, emulation_type, NULL, 0);
+       return x86_emulate_instruction(vcpu, 0,
+                       emulation_type | EMULTYPE_NO_REEXECUTE, NULL, 0);
 }
 
 void kvm_enable_efer_bits(u64);
index 9f0a680..22d3fb1 100644 (file)
@@ -195,13 +195,13 @@ static inline unsigned int kvm_arch_para_features(void)
 
 #ifdef CONFIG_KVM_GUEST
 void __init kvm_guest_init(void);
-void kvm_async_pf_task_wait(u32 token);
+void kvm_async_pf_task_wait(u32 token, int interrupt_kernel);
 void kvm_async_pf_task_wake(u32 token);
 u32 kvm_read_and_reset_pf_reason(void);
 extern void kvm_disable_steal_time(void);
 #else
 #define kvm_guest_init() do { } while (0)
-#define kvm_async_pf_task_wait(T) do {} while(0)
+#define kvm_async_pf_task_wait(T, I) do {} while(0)
 #define kvm_async_pf_task_wake(T) do {} while(0)
 static inline u32 kvm_read_and_reset_pf_reason(void)
 {
index 0e8ae57..589e485 100644 (file)
@@ -76,6 +76,10 @@ struct mce {
        __u32 socketid; /* CPU socket ID */
        __u32 apicid;   /* CPU initial apic ID */
        __u64 mcgcap;   /* MCGCAP MSR: machine check capabilities of CPU */
+       __u64 synd;     /* MCA_SYND MSR: only valid on SMCA systems */
+       __u64 ipid;     /* MCA_IPID MSR: only valid on SMCA systems */
+       __u64 ppin;     /* Protected Processor Inventory Number */
+       __u32 microcode;/* Microcode revision */
 };
 
 /*
index 926f672..b19dbcf 100644 (file)
@@ -20,12 +20,6 @@ typedef struct {
        void *vdso;
 } mm_context_t;
 
-#ifdef CONFIG_SMP
 void leave_mm(int cpu);
-#else
-static inline void leave_mm(int cpu)
-{
-}
-#endif
 
 #endif /* _ASM_X86_MMU_H */
index babbcd1..6ab9577 100644 (file)
@@ -69,82 +69,16 @@ void destroy_context(struct mm_struct *mm);
 
 static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
-#ifdef CONFIG_SMP
        if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
                percpu_write(cpu_tlbstate.state, TLBSTATE_LAZY);
-#endif
 }
 
-static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
-                            struct task_struct *tsk)
-{
-       unsigned cpu = smp_processor_id();
+extern void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+                     struct task_struct *tsk);
 
-       if (likely(prev != next)) {
-#ifdef CONFIG_SMP
-               percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
-               percpu_write(cpu_tlbstate.active_mm, next);
-#endif
-               cpumask_set_cpu(cpu, mm_cpumask(next));
-
-               /*
-                * Re-load page tables.
-                *
-                * This logic has an ordering constraint:
-                *
-                *  CPU 0: Write to a PTE for 'next'
-                *  CPU 0: load bit 1 in mm_cpumask.  if nonzero, send IPI.
-                *  CPU 1: set bit 1 in next's mm_cpumask
-                *  CPU 1: load from the PTE that CPU 0 writes (implicit)
-                *
-                * We need to prevent an outcome in which CPU 1 observes
-                * the new PTE value and CPU 0 observes bit 1 clear in
-                * mm_cpumask.  (If that occurs, then the IPI will never
-                * be sent, and CPU 0's TLB will contain a stale entry.)
-                *
-                * The bad outcome can occur if either CPU's load is
-                * reordered before that CPU's store, so both CPUs must
-                * execute full barriers to prevent this from happening.
-                *
-                * Thus, switch_mm needs a full barrier between the
-                * store to mm_cpumask and any operation that could load
-                * from next->pgd.  TLB fills are special and can happen
-                * due to instruction fetches or for no reason at all,
-                * and neither LOCK nor MFENCE orders them.
-                * Fortunately, load_cr3() is serializing and gives the
-                * ordering guarantee we need.
-                *
-                */
-               load_cr3(next->pgd);
-
-               /* stop flush ipis for the previous mm */
-               cpumask_clear_cpu(cpu, mm_cpumask(prev));
-
-               /*
-                * load the LDT, if the LDT is different:
-                */
-               if (unlikely(prev->context.ldt != next->context.ldt))
-                       load_mm_ldt(next);
-       }
-#ifdef CONFIG_SMP
-       else {
-               percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
-               BUG_ON(percpu_read(cpu_tlbstate.active_mm) != next);
-
-               if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next))) {
-                       /* We were in lazy tlb mode and leave_mm disabled
-                        * tlb flush IPI delivery. We must reload CR3
-                        * to make sure to use no freed page tables.
-                        *
-                        * As above, load_cr3() is serializing and orders TLB
-                        * fills with respect to the mm_cpumask write.
-                        */
-                       load_cr3(next->pgd);
-                       load_mm_ldt(next);
-               }
-       }
-#endif
-}
+extern void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
+                              struct task_struct *tsk);
+#define switch_mm_irqs_off switch_mm_irqs_off
 
 #define activate_mm(prev, next)                        \
 do {                                           \
index 3d48aa4..719b622 100644 (file)
 #define FAM10H_MMIO_CONF_BASE_MASK     0xfffffffULL
 #define FAM10H_MMIO_CONF_BASE_SHIFT    20
 #define MSR_FAM10H_NODE_ID             0xc001100c
+#define MSR_F10H_DECFG                 0xc0011029
+#define MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT    1
+#define MSR_F10H_DECFG_LFENCE_SERIALIZE                BIT_ULL(MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT)
 
 /* K8 MSRs */
 #define MSR_K8_TOP_MEM1                        0xc001001a
index 95203d4..d7facae 100644 (file)
@@ -265,6 +265,8 @@ do {                                                            \
 
 struct msr *msrs_alloc(void);
 void msrs_free(struct msr *msrs);
+int msr_set_bit(u32 msr, u8 bit);
+int msr_clear_bit(u32 msr, u8 bit);
 
 #ifdef CONFIG_SMP
 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
new file mode 100644 (file)
index 0000000..4e0e2e6
--- /dev/null
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_X86_NOSPEC_BRANCH_H_
+#define _ASM_X86_NOSPEC_BRANCH_H_
+
+#include <asm/alternative.h>
+#include <asm/alternative-asm.h>
+#include <asm/cpufeature.h>
+
+/*
+ * Fill the CPU return stack buffer.
+ *
+ * Each entry in the RSB, if used for a speculative 'ret', contains an
+ * infinite 'pause; lfence; jmp' loop to capture speculative execution.
+ *
+ * This is required in various cases for retpoline and IBRS-based
+ * mitigations for the Spectre variant 2 vulnerability. Sometimes to
+ * eliminate potentially bogus entries from the RSB, and sometimes
+ * purely to ensure that it doesn't get empty, which on some CPUs would
+ * allow predictions from other (unwanted!) sources to be used.
+ *
+ * We define a CPP macro such that it can be used from both .S files and
+ * inline assembly. It's possible to do a .macro and then include that
+ * from C via asm(".include <asm/nospec-branch.h>") but let's not go there.
+ */
+
+#define RSB_CLEAR_LOOPS                32      /* To forcibly overwrite all entries */
+#define RSB_FILL_LOOPS         16      /* To avoid underflow */
+
+/*
+ * Google experimented with loop-unrolling and this turned out to be
+ * the optimal version â€” two calls, each with their own speculation
+ * trap should their return address end up getting used, in a loop.
+ */
+#define __FILL_RETURN_BUFFER(reg, nr, sp)      \
+       mov     $(nr/2), reg;                   \
+771:                                           \
+       call    772f;                           \
+773:   /* speculation trap */                  \
+       pause;                                  \
+       lfence;                                 \
+       jmp     773b;                           \
+772:                                           \
+       call    774f;                           \
+775:   /* speculation trap */                  \
+       pause;                                  \
+       lfence;                                 \
+       jmp     775b;                           \
+774:                                           \
+       dec     reg;                            \
+       jnz     771b;                           \
+       add     $(BITS_PER_LONG/8) * nr, sp;
+
+#ifdef __ASSEMBLY__
+
+/*
+ * These are the bare retpoline primitives for indirect jmp and call.
+ * Do not use these directly; they only exist to make the ALTERNATIVE
+ * invocation below less ugly.
+ */
+.macro RETPOLINE_JMP reg:req
+       call    .Ldo_rop_\@
+.Lspec_trap_\@:
+       pause
+       lfence
+       jmp     .Lspec_trap_\@
+.Ldo_rop_\@:
+       mov     \reg, (%_ASM_SP)
+       ret
+.endm
+
+/*
+ * This is a wrapper around RETPOLINE_JMP so the called function in reg
+ * returns to the instruction after the macro.
+ */
+.macro RETPOLINE_CALL reg:req
+       jmp     .Ldo_call_\@
+.Ldo_retpoline_jmp_\@:
+       RETPOLINE_JMP \reg
+.Ldo_call_\@:
+       call    .Ldo_retpoline_jmp_\@
+.endm
+
+/*
+ * JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple
+ * indirect jmp/call which may be susceptible to the Spectre variant 2
+ * attack.
+ */
+.macro JMP_NOSPEC reg:req
+#ifdef CONFIG_RETPOLINE
+       ALTERNATIVE_2 __stringify(jmp *\reg),                           \
+               __stringify(RETPOLINE_JMP \reg), X86_FEATURE_RETPOLINE, \
+               __stringify(lfence; jmp *\reg), X86_FEATURE_RETPOLINE_AMD
+#else
+       jmp     *\reg
+#endif
+.endm
+
+.macro CALL_NOSPEC reg:req
+#ifdef CONFIG_RETPOLINE
+       ALTERNATIVE_2 __stringify(call *\reg),                          \
+               __stringify(RETPOLINE_CALL \reg), X86_FEATURE_RETPOLINE,\
+               __stringify(lfence; call *\reg), X86_FEATURE_RETPOLINE_AMD
+#else
+       call    *\reg
+#endif
+.endm
+
+ /*
+  * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP
+  * monstrosity above, manually.
+  */
+.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
+#ifdef CONFIG_RETPOLINE
+       ALTERNATIVE "jmp .Lskip_rsb_\@",                                \
+               __stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP))    \
+               \ftr
+.Lskip_rsb_\@:
+#endif
+.endm
+
+#else /* __ASSEMBLY__ */
+
+#if defined(CONFIG_X86_64) && defined(RETPOLINE)
+
+/*
+ * Since the inline asm uses the %V modifier which is only in newer GCC,
+ * the 64-bit one is dependent on RETPOLINE not CONFIG_RETPOLINE.
+ */
+# define CALL_NOSPEC                                           \
+       ALTERNATIVE(                                            \
+       "call *%[thunk_target]\n",                              \
+       "call __x86_indirect_thunk_%V[thunk_target]\n",         \
+       X86_FEATURE_RETPOLINE)
+# define THUNK_TARGET(addr) [thunk_target] "r" (addr)
+
+#elif defined(CONFIG_X86_32) && defined(CONFIG_RETPOLINE)
+/*
+ * For i386 we use the original ret-equivalent retpoline, because
+ * otherwise we'll run out of registers. We don't care about CET
+ * here, anyway.
+ */
+# define CALL_NOSPEC ALTERNATIVE("call *%[thunk_target]\n",    \
+       "       jmp    904f;\n"                                 \
+       "       .align 16\n"                                    \
+       "901:   call   903f;\n"                                 \
+       "902:   pause;\n"                                       \
+       "       lfence;\n"                                      \
+       "       jmp    902b;\n"                                 \
+       "       .align 16\n"                                    \
+       "903:   addl   $4, %%esp;\n"                            \
+       "       pushl  %[thunk_target];\n"                      \
+       "       ret;\n"                                         \
+       "       .align 16\n"                                    \
+       "904:   call   901b;\n",                                \
+       X86_FEATURE_RETPOLINE)
+
+# define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
+#else /* No retpoline for C / inline asm */
+# define CALL_NOSPEC "call *%[thunk_target]\n"
+# define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
+#endif
+
+/* The Spectre V2 mitigation variants */
+enum spectre_v2_mitigation {
+       SPECTRE_V2_NONE,
+       SPECTRE_V2_RETPOLINE_MINIMAL,
+       SPECTRE_V2_RETPOLINE_MINIMAL_AMD,
+       SPECTRE_V2_RETPOLINE_GENERIC,
+       SPECTRE_V2_RETPOLINE_AMD,
+       SPECTRE_V2_IBRS,
+};
+
+extern char __indirect_thunk_start[];
+extern char __indirect_thunk_end[];
+extern char __indirect_thunk_size[];
+
+/*
+ * On VMEXIT we must ensure that no RSB predictions learned in the guest
+ * can be followed in the host, by overwriting the RSB completely. Both
+ * retpoline and IBRS mitigations for Spectre v2 need this; only on future
+ * CPUs with IBRS_ALL *might* it be avoided.
+ */
+static inline void vmexit_fill_RSB(void)
+{
+#ifdef CONFIG_RETPOLINE
+       unsigned long loops;
+
+       asm volatile (ALTERNATIVE("jmp 910f",
+                                 __stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1)),
+                                 X86_FEATURE_RETPOLINE)
+                     "910:"
+                     : "=r" (loops), ASM_CALL_CONSTRAINT
+                     : : "memory" );
+#endif
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
index 6be9909..daaf934 100644 (file)
 #ifndef __ASSEMBLY__
 
 #include <asm/x86_init.h>
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+extern int kaiser_enabled;
+#else
+#define kaiser_enabled 0
+#endif
 
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
@@ -249,14 +254,14 @@ static inline pmd_t pmd_set_flags(pmd_t pmd, pmdval_t set)
 {
        pmdval_t v = native_pmd_val(pmd);
 
-       return __pmd(v | set);
+       return native_make_pmd(v | set);
 }
 
 static inline pmd_t pmd_clear_flags(pmd_t pmd, pmdval_t clear)
 {
        pmdval_t v = native_pmd_val(pmd);
 
-       return __pmd(v & ~clear);
+       return native_make_pmd(v & ~clear);
 }
 
 static inline pmd_t pmd_mkold(pmd_t pmd)
@@ -570,7 +575,17 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long address)
 
 static inline int pgd_bad(pgd_t pgd)
 {
-       return (pgd_flags(pgd) & ~_PAGE_USER) != _KERNPG_TABLE;
+       pgdval_t ignore_flags = _PAGE_USER;
+       /*
+        * We set NX on KAISER pgds that map userspace memory so
+        * that userspace can not meaningfully use the kernel
+        * page table by accident; it will fault on the first
+        * instruction it tries to run.  See native_set_pgd().
+        */
+       if (kaiser_enabled)
+               ignore_flags |= _PAGE_NX;
+
+       return (pgd_flags(pgd) & ~ignore_flags) != _KERNPG_TABLE;
 }
 
 static inline int pgd_none(pgd_t pgd)
@@ -770,7 +785,15 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
  */
 static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
 {
-       memcpy(dst, src, count * sizeof(pgd_t));
+       memcpy(dst, src, count * sizeof(pgd_t));
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+       if (kaiser_enabled) {
+               /* Clone the shadow pgd part as well */
+               memcpy(native_get_shadow_pgd(dst),
+                       native_get_shadow_pgd(src),
+                       count * sizeof(pgd_t));
+       }
+#endif
 }
 
 
index 975f709..f810cca 100644 (file)
@@ -105,9 +105,31 @@ static inline void native_pud_clear(pud_t *pud)
        native_set_pud(pud, native_make_pud(0));
 }
 
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+extern pgd_t kaiser_set_shadow_pgd(pgd_t *pgdp, pgd_t pgd);
+
+static inline pgd_t *native_get_shadow_pgd(pgd_t *pgdp)
+{
+#ifdef CONFIG_DEBUG_VM
+       /* linux/mmdebug.h may not have been included at this point */
+       BUG_ON(!kaiser_enabled);
+#endif
+       return (pgd_t *)((unsigned long)pgdp | (unsigned long)PAGE_SIZE);
+}
+#else
+static inline pgd_t kaiser_set_shadow_pgd(pgd_t *pgdp, pgd_t pgd)
+{
+       return pgd;
+}
+static inline pgd_t *native_get_shadow_pgd(pgd_t *pgdp)
+{
+       return NULL;
+}
+#endif /* CONFIG_PAGE_TABLE_ISOLATION */
+
 static inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd)
 {
-       *pgdp = pgd;
+       *pgdp = kaiser_set_shadow_pgd(pgdp, pgd);
 }
 
 static inline void native_pgd_clear(pgd_t *pgd)
index 013286a..3c46723 100644 (file)
@@ -62,7 +62,7 @@
 #endif
 
 #define _PAGE_FILE     (_AT(pteval_t, 1) << _PAGE_BIT_FILE)
-#define _PAGE_PROTNONE (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE)
+#define _PAGE_PROTNONE  (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE)
 
 #define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER |        \
                         _PAGE_ACCESSED | _PAGE_DIRTY)
                         _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE)
 
+/* The ASID is the lower 12 bits of CR3 */
+#define X86_CR3_PCID_ASID_MASK  (_AC((1<<12)-1,UL))
+
+/* Mask for all the PCID-related bits in CR3: */
+#define X86_CR3_PCID_MASK       (X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_MASK)
+#define X86_CR3_PCID_ASID_KERN  (_AC(0x0,UL))
+
+#if defined(CONFIG_PAGE_TABLE_ISOLATION) && defined(CONFIG_X86_64)
+/* Let X86_CR3_PCID_ASID_USER be usable for the X86_CR3_PCID_NOFLUSH bit */
+#define X86_CR3_PCID_ASID_USER (_AC(0x80,UL))
+
+#define X86_CR3_PCID_KERN_FLUSH                (X86_CR3_PCID_ASID_KERN)
+#define X86_CR3_PCID_USER_FLUSH                (X86_CR3_PCID_ASID_USER)
+#define X86_CR3_PCID_KERN_NOFLUSH      (X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_KERN)
+#define X86_CR3_PCID_USER_NOFLUSH      (X86_CR3_PCID_NOFLUSH | X86_CR3_PCID_ASID_USER)
+#else
+#define X86_CR3_PCID_ASID_USER  (_AC(0x0,UL))
+/*
+ * PCIDs are unsupported on 32-bit and none of these bits can be
+ * set in CR3:
+ */
+#define X86_CR3_PCID_KERN_FLUSH                (0)
+#define X86_CR3_PCID_USER_FLUSH                (0)
+#define X86_CR3_PCID_KERN_NOFLUSH      (0)
+#define X86_CR3_PCID_USER_NOFLUSH      (0)
+#endif
+
 #define _PAGE_CACHE_MASK       (_PAGE_PCD | _PAGE_PWT)
 #define _PAGE_CACHE_WB         (0)
 #define _PAGE_CACHE_WC         (_PAGE_PWT)
@@ -244,6 +271,11 @@ static inline pmdval_t native_pmd_val(pmd_t pmd)
 #else
 #include <asm-generic/pgtable-nopmd.h>
 
+static inline pmd_t native_make_pmd(pmdval_t val)
+{
+       return (pmd_t) { .pud.pgd = native_make_pgd(val) };
+}
+
 static inline pmdval_t native_pmd_val(pmd_t pmd)
 {
        return native_pgd_val(pmd.pud.pgd);
index 2dddb31..360e80d 100644 (file)
@@ -43,6 +43,8 @@
  */
 #define X86_CR3_PWT    0x00000008 /* Page Write Through */
 #define X86_CR3_PCD    0x00000010 /* Page Cache Disable */
+#define X86_CR3_PCID_NOFLUSH_BIT 63 /* Preserve old PCID */
+#define X86_CR3_PCID_NOFLUSH (_AC(1,ULL) << X86_CR3_PCID_NOFLUSH_BIT)
 
 /*
  * Intel CPU features in CR4
@@ -60,6 +62,7 @@
 #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */
 #define X86_CR4_VMXE   0x00002000 /* enable VMX virtualization */
 #define X86_CR4_RDWRGSFS 0x00010000 /* enable RDWRGSFS support */
+#define X86_CR4_PCIDE  0x00020000 /* enable PCID support */
 #define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */
 #define X86_CR4_SMEP   0x00100000 /* enable SMEP support */
 
index f7c89e2..243ce08 100644 (file)
@@ -86,7 +86,7 @@ struct cpuinfo_x86 {
        __u32                   extended_cpuid_level;
        /* Maximum supported CPUID level, -1=no CPUID: */
        int                     cpuid_level;
-       __u32                   x86_capability[NCAPINTS];
+       __u32                   x86_capability[NCAPINTS + NBUGINTS];
        char                    x86_vendor_id[16];
        char                    x86_model_id[64];
        /* in KB - valid for CPUS which support this call: */
@@ -130,8 +130,8 @@ extern struct cpuinfo_x86   boot_cpu_data;
 extern struct cpuinfo_x86      new_cpu_data;
 
 extern struct tss_struct       doublefault_tss;
-extern __u32                   cpu_caps_cleared[NCAPINTS];
-extern __u32                   cpu_caps_set[NCAPINTS];
+extern __u32                   cpu_caps_cleared[NCAPINTS + NBUGINTS];
+extern __u32                   cpu_caps_set[NCAPINTS + NBUGINTS];
 
 #ifdef CONFIG_SMP
 DECLARE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
@@ -266,7 +266,7 @@ struct tss_struct {
 
 } ____cacheline_aligned;
 
-DECLARE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss);
+DECLARE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(struct tss_struct, init_tss);
 
 /*
  * Save the original ist values for checking stack pointers during debugging
index d75adff..59567d1 100644 (file)
@@ -6,6 +6,7 @@
 #include <asm/cpufeature.h>
 #include <asm/cmpxchg.h>
 #include <asm/nops.h>
+#include <asm/nospec-branch.h>
 
 #include <linux/kernel.h>
 #include <linux/irqflags.h>
@@ -41,6 +42,23 @@ extern void show_regs_common(void);
 #define __switch_canary_iparam
 #endif /* CC_STACKPROTECTOR */
 
+#ifdef CONFIG_RETPOLINE
+       /*
+        * When switching from a shallower to a deeper call stack
+        * the RSB may either underflow or use entries populated
+        * with userspace addresses. On CPUs where those concerns
+        * exist, overwrite the RSB with entries which capture
+        * speculative execution to prevent attack.
+        */
+#define __retpoline_fill_return_buffer                                 \
+       ALTERNATIVE("jmp 910f",                                         \
+               __stringify(__FILL_RETURN_BUFFER(%%ebx, RSB_CLEAR_LOOPS, %%esp)),\
+               X86_FEATURE_RSB_CTXSW)                                  \
+       "910:\n\t"
+#else
+#define __retpoline_fill_return_buffer
+#endif
+
 /*
  * Saving eflags is important. It switches not only IOPL between tasks,
  * it also protects other tasks from NT leaking through sysenter etc.
@@ -63,6 +81,7 @@ do {                                                                  \
                     "movl $1f,%[prev_ip]\n\t"  /* save    EIP   */     \
                     "pushl %[next_ip]\n\t"     /* restore EIP   */     \
                     __switch_canary                                    \
+                    __retpoline_fill_return_buffer                     \
                     "jmp __switch_to\n"        /* regparm call  */     \
                     "1:\t"                                             \
                     "popl %%ebp\n\t"           /* restore EBP   */     \
@@ -117,6 +136,23 @@ do {                                                                       \
 #define __switch_canary_iparam
 #endif /* CC_STACKPROTECTOR */
 
+#ifdef CONFIG_RETPOLINE
+       /*
+        * When switching from a shallower to a deeper call stack
+        * the RSB may either underflow or use entries populated
+        * with userspace addresses. On CPUs where those concerns
+        * exist, overwrite the RSB with entries which capture
+        * speculative execution to prevent attack.
+        */
+#define __retpoline_fill_return_buffer                                 \
+       ALTERNATIVE("jmp 910f",                                         \
+               __stringify(__FILL_RETURN_BUFFER(%%r12, RSB_CLEAR_LOOPS, %%rsp)),\
+               X86_FEATURE_RSB_CTXSW)                                  \
+       "910:\n\t"
+#else
+#define __retpoline_fill_return_buffer
+#endif
+
 /* Save restore flags to clear handle leaking NT */
 #define switch_to(prev, next, last) \
        asm volatile(SAVE_CONTEXT                                         \
@@ -125,6 +161,7 @@ do {                                                                        \
             "call __switch_to\n\t"                                       \
             "movq "__percpu_arg([current_task])",%%rsi\n\t"              \
             __switch_canary                                              \
+            __retpoline_fill_return_buffer                               \
             "movq %P[thread_info](%%rsi),%%r8\n\t"                       \
             "movq %%rax,%%rdi\n\t"                                       \
             "testl  %[_tif_fork],%P[ti_flags](%%r8)\n\t"                 \
@@ -417,6 +454,34 @@ void stop_this_cpu(void *dummy);
 #define wmb()  asm volatile("sfence" ::: "memory")
 #endif
 
+/**
+ * array_index_mask_nospec() - generate a mask that is ~0UL when the
+ *     bounds check succeeds and 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * Returns:
+ *     0 - (index < size)
+ */
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+               unsigned long size)
+{
+       unsigned long mask;
+
+       asm ("cmp %1,%2; sbb %0,%0;"
+                       :"=r" (mask)
+                       :"r"(size),"r" (index)
+                       :"cc");
+       return mask;
+}
+
+/* Override the default implementation from linux/nospec.h. */
+#define array_index_mask_nospec array_index_mask_nospec
+
+/* Prevent speculative execution past this barrier. */
+#define barrier_nospec() alternative_2("", "mfence", X86_FEATURE_MFENCE_RDTSC, \
+                                          "lfence", X86_FEATURE_LFENCE_RDTSC)
+
 /**
  * read_barrier_depends - Flush all pending reads that subsequents reads
  * depend on.
@@ -502,8 +567,7 @@ void stop_this_cpu(void *dummy);
  */
 static __always_inline void rdtsc_barrier(void)
 {
-       alternative(ASM_NOP3, "mfence", X86_FEATURE_MFENCE_RDTSC);
-       alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC);
+       barrier_nospec();
 }
 
 /*
index d7ef849..829c234 100644 (file)
@@ -181,9 +181,6 @@ struct thread_info {
 #ifndef __ASSEMBLY__
 
 
-/* how to get the current stack pointer from C */
-register unsigned long current_stack_pointer asm("esp") __used;
-
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
 {
index a7973dd..e680388 100644 (file)
@@ -6,6 +6,55 @@
 
 #include <asm/processor.h>
 #include <asm/system.h>
+#include <asm/smp.h>
+
+static inline void __invpcid(unsigned long pcid, unsigned long addr,
+                            unsigned long type)
+{
+       struct { u64 d[2]; } desc = { { pcid, addr } };
+
+       /*
+        * The memory clobber is because the whole point is to invalidate
+        * stale TLB entries and, especially if we're flushing global
+        * mappings, we don't want the compiler to reorder any subsequent
+        * memory accesses before the TLB flush.
+        *
+        * The hex opcode is invpcid (%ecx), %eax in 32-bit mode and
+        * invpcid (%rcx), %rax in long mode.
+        */
+       asm volatile (".byte 0x66, 0x0f, 0x38, 0x82, 0x01"
+                     : : "m" (desc), "a" (type), "c" (&desc) : "memory");
+}
+
+#define INVPCID_TYPE_INDIV_ADDR                0
+#define INVPCID_TYPE_SINGLE_CTXT       1
+#define INVPCID_TYPE_ALL_INCL_GLOBAL   2
+#define INVPCID_TYPE_ALL_NON_GLOBAL    3
+
+/* Flush all mappings for a given pcid and addr, not including globals. */
+static inline void invpcid_flush_one(unsigned long pcid,
+                                    unsigned long addr)
+{
+       __invpcid(pcid, addr, INVPCID_TYPE_INDIV_ADDR);
+}
+
+/* Flush all mappings for a given PCID, not including globals. */
+static inline void invpcid_flush_single_context(unsigned long pcid)
+{
+       __invpcid(pcid, 0, INVPCID_TYPE_SINGLE_CTXT);
+}
+
+/* Flush all mappings, including globals, for all PCIDs. */
+static inline void invpcid_flush_all(void)
+{
+       __invpcid(0, 0, INVPCID_TYPE_ALL_INCL_GLOBAL);
+}
+
+/* Flush all mappings for all PCIDs except globals. */
+static inline void invpcid_flush_all_nonglobals(void)
+{
+       __invpcid(0, 0, INVPCID_TYPE_ALL_NON_GLOBAL);
+}
 
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #define __flush_tlb_single(addr) __native_flush_tlb_single(addr)
 #endif
 
+/*
+ * Declare a couple of kaiser interfaces here for convenience,
+ * to avoid the need for asm/kaiser.h in unexpected places.
+ */
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+extern int kaiser_enabled;
+extern void kaiser_setup_pcid(void);
+extern void kaiser_flush_tlb_on_return_to_user(void);
+#else
+#define kaiser_enabled 0
+static inline void kaiser_setup_pcid(void)
+{
+}
+static inline void kaiser_flush_tlb_on_return_to_user(void)
+{
+}
+#endif
+
 static inline void __native_flush_tlb(void)
 {
        /*
@@ -23,6 +90,8 @@ static inline void __native_flush_tlb(void)
         * back:
         */
        preempt_disable();
+       if (kaiser_enabled)
+               kaiser_flush_tlb_on_return_to_user();
        native_write_cr3(native_read_cr3());
        preempt_enable();
 }
@@ -32,6 +101,17 @@ static inline void __native_flush_tlb_global(void)
        unsigned long flags;
        unsigned long cr4;
 
+       if (this_cpu_has(X86_FEATURE_INVPCID)) {
+               /*
+                * Using INVPCID is considerably faster than a pair of writes
+                * to CR4 sandwiched inside an IRQ flag save/restore.
+                *
+                * Note, this works with CR4.PCIDE=0 or 1.
+                */
+               invpcid_flush_all();
+               return;
+       }
+
        /*
         * Read-modify-write to CR4 - protect it from preemption and
         * from interrupts. (Use the raw variant because this code can
@@ -40,25 +120,61 @@ static inline void __native_flush_tlb_global(void)
        raw_local_irq_save(flags);
 
        cr4 = native_read_cr4();
-       /* clear PGE */
-       native_write_cr4(cr4 & ~X86_CR4_PGE);
-       /* write old PGE again and flush TLBs */
-       native_write_cr4(cr4);
+       if (cr4 & X86_CR4_PGE) {
+               /* clear PGE and flush TLB of all entries */
+               native_write_cr4(cr4 & ~X86_CR4_PGE);
+               /* restore PGE as it was before */
+               native_write_cr4(cr4);
+       } else {
+               /* do it with cr3, letting kaiser flush user PCID */
+               __native_flush_tlb();
+       }
 
        raw_local_irq_restore(flags);
 }
 
 static inline void __native_flush_tlb_single(unsigned long addr)
 {
-       asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
+       /*
+        * SIMICS #GP's if you run INVPCID with type 2/3
+        * and X86_CR4_PCIDE clear.  Shame!
+        *
+        * The ASIDs used below are hard-coded.  But, we must not
+        * call invpcid(type=1/2) before CR4.PCIDE=1.  Just call
+        * invlpg in the case we are called early.
+        */
+
+       if (!this_cpu_has(X86_FEATURE_INVPCID_SINGLE)) {
+               if (kaiser_enabled)
+                       kaiser_flush_tlb_on_return_to_user();
+               asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
+               return;
+       }
+       /* Flush the address out of both PCIDs. */
+       /*
+        * An optimization here might be to determine addresses
+        * that are only kernel-mapped and only flush the kernel
+        * ASID.  But, userspace flushes are probably much more
+        * important performance-wise.
+        *
+        * Make sure to do only a single invpcid when KAISER is
+        * disabled and we have only a single ASID.
+        */
+       if (kaiser_enabled)
+               invpcid_flush_one(X86_CR3_PCID_ASID_USER, addr);
+       invpcid_flush_one(X86_CR3_PCID_ASID_KERN, addr);
 }
 
 static inline void __flush_tlb_all(void)
 {
-       if (cpu_has_pge)
-               __flush_tlb_global();
-       else
-               __flush_tlb();
+       __flush_tlb_global();
+       /*
+        * Note: if we somehow had PCID but not PGE, then this wouldn't work --
+        * we'd end up flushing kernel translations for the current ASID but
+        * we might fail to flush kernel translations for other cached ASIDs.
+        *
+        * To avoid this issue, we force PCID off if PGE is off.
+        */
 }
 
 static inline void __flush_tlb_one(unsigned long addr)
@@ -88,52 +204,8 @@ static inline void __flush_tlb_one(unsigned long addr)
  *
  * ..but the i386 has somewhat limited tlb flushing capabilities,
  * and page-granular flushes are available only on i486 and up.
- *
- * x86-64 can only flush individual pages or full VMs. For a range flush
- * we always do the full VM. Might be worth trying if for a small
- * range a few INVLPGs in a row are a win.
  */
 
-#ifndef CONFIG_SMP
-
-#define flush_tlb() __flush_tlb()
-#define flush_tlb_all() __flush_tlb_all()
-#define local_flush_tlb() __flush_tlb()
-
-static inline void flush_tlb_mm(struct mm_struct *mm)
-{
-       if (mm == current->active_mm)
-               __flush_tlb();
-}
-
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-                                 unsigned long addr)
-{
-       if (vma->vm_mm == current->active_mm)
-               __flush_tlb_one(addr);
-}
-
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-                                  unsigned long start, unsigned long end)
-{
-       if (vma->vm_mm == current->active_mm)
-               __flush_tlb();
-}
-
-static inline void native_flush_tlb_others(const struct cpumask *cpumask,
-                                          struct mm_struct *mm,
-                                          unsigned long va)
-{
-}
-
-static inline void reset_lazy_tlbstate(void)
-{
-}
-
-#else  /* SMP */
-
-#include <asm/smp.h>
-
 #define local_flush_tlb() __flush_tlb()
 
 extern void flush_tlb_all(void);
@@ -167,8 +239,6 @@ static inline void reset_lazy_tlbstate(void)
        percpu_write(cpu_tlbstate.active_mm, &init_mm);
 }
 
-#endif /* SMP */
-
 #ifndef CONFIG_PARAVIRT
 #define flush_tlb_others(mask, mm, va) native_flush_tlb_others(mask, mm, va)
 #endif
index 88eae2a..e8666d8 100644 (file)
@@ -69,6 +69,7 @@ dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long);
 #ifdef CONFIG_X86_32
 dotraplinkage void do_iret_error(struct pt_regs *, long);
 #endif
+void do_mce(struct pt_regs *, long);
 
 static inline int get_si_code(unsigned long condition)
 {
index 7bdc8f4..7dd47ba 100644 (file)
@@ -32,9 +32,9 @@
 
 #define segment_eq(a, b)       ((a).seg == (b).seg)
 
-#define __addr_ok(addr)                                        \
-       ((unsigned long __force)(addr) <                \
-        (current_thread_info()->addr_limit.seg))
+#define user_addr_max() (current_thread_info()->addr_limit.seg)
+#define __addr_ok(addr)        \
+       ((unsigned long __force)(addr) < user_addr_max())
 
 /*
  * Test whether a block of memory is a valid user space address.
  * This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry...
  */
 
-#define __range_not_ok(addr, size)                                     \
+#define __range_not_ok(addr, size, limit)                              \
 ({                                                                     \
        unsigned long flag, roksum;                                     \
        __chk_user_ptr(addr);                                           \
        asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0"             \
            : "=&r" (flag), "=r" (roksum)                               \
            : "1" (addr), "g" ((long)(size)),                           \
-             "rm" (current_thread_info()->addr_limit.seg));            \
+             "rm" (limit));                                            \
        flag;                                                           \
 })
 
@@ -76,7 +76,8 @@
  * checks that the pointer is in the user space range - after calling
  * this function, memory access functions may still return -EFAULT.
  */
-#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))
+#define access_ok(type, addr, size) \
+       (likely(__range_not_ok(addr, size, user_addr_max()) == 0))
 
 /*
  * The exception table consists of pairs of addresses: the first is the
@@ -422,6 +423,7 @@ do {                                                                        \
 ({                                                                     \
        int __gu_err;                                                   \
        unsigned long __gu_val;                                         \
+       barrier_nospec();                                       \
        __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT);    \
        (x) = (__force __typeof__(*(ptr)))__gu_val;                     \
        __gu_err;                                                       \
@@ -461,6 +463,11 @@ struct __large_struct { unsigned long buf[100]; };
        current_thread_info()->uaccess_err = 0;                         \
        barrier();
 
+#define uaccess_try_nospec do {                                                \
+       int prev_err = current_thread_info()->uaccess_err;              \
+       current_thread_info()->uaccess_err = 0;                         \
+       barrier_nospec();
+
 #define uaccess_catch(err)                                             \
        (err) |= current_thread_info()->uaccess_err;                    \
        current_thread_info()->uaccess_err = prev_err;                  \
@@ -523,7 +530,7 @@ struct __large_struct { unsigned long buf[100]; };
  *     get_user_ex(...);
  * } get_user_catch(err)
  */
-#define get_user_try           uaccess_try
+#define get_user_try           uaccess_try_nospec
 #define get_user_catch(err)    uaccess_catch(err)
 
 #define get_user_ex(x, ptr)    do {                                    \
index 566e803..b6f5617 100644 (file)
@@ -48,14 +48,17 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
 
                switch (n) {
                case 1:
+                       barrier_nospec();
                        __put_user_size(*(u8 *)from, (u8 __user *)to,
                                        1, ret, 1);
                        return ret;
                case 2:
+                       barrier_nospec();
                        __put_user_size(*(u16 *)from, (u16 __user *)to,
                                        2, ret, 2);
                        return ret;
                case 4:
+                       barrier_nospec();
                        __put_user_size(*(u32 *)from, (u32 __user *)to,
                                        4, ret, 4);
                        return ret;
@@ -98,12 +101,15 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
 
                switch (n) {
                case 1:
+                       barrier_nospec();
                        __get_user_size(*(u8 *)to, from, 1, ret, 1);
                        return ret;
                case 2:
+                       barrier_nospec();
                        __get_user_size(*(u16 *)to, from, 2, ret, 2);
                        return ret;
                case 4:
+                       barrier_nospec();
                        __get_user_size(*(u32 *)to, from, 4, ret, 4);
                        return ret;
                }
@@ -142,12 +148,15 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)
 
                switch (n) {
                case 1:
+                       barrier_nospec();
                        __get_user_size(*(u8 *)to, from, 1, ret, 1);
                        return ret;
                case 2:
+                       barrier_nospec();
                        __get_user_size(*(u16 *)to, from, 2, ret, 2);
                        return ret;
                case 4:
+                       barrier_nospec();
                        __get_user_size(*(u32 *)to, from, 4, ret, 4);
                        return ret;
                }
@@ -164,12 +173,15 @@ static __always_inline unsigned long __copy_from_user_nocache(void *to,
 
                switch (n) {
                case 1:
+                       barrier_nospec();
                        __get_user_size(*(u8 *)to, from, 1, ret, 1);
                        return ret;
                case 2:
+                       barrier_nospec();
                        __get_user_size(*(u16 *)to, from, 2, ret, 2);
                        return ret;
                case 4:
+                       barrier_nospec();
                        __get_user_size(*(u32 *)to, from, 4, ret, 4);
                        return ret;
                }
index 31fed19..dda633c 100644 (file)
@@ -75,19 +75,28 @@ int __copy_from_user_nocheck(void *dst, const void __user *src, unsigned size)
        if (!__builtin_constant_p(size))
                return copy_user_generic(dst, (__force void *)src, size);
        switch (size) {
-       case 1:__get_user_asm(*(u8 *)dst, (u8 __user *)src,
+       case 1:
+               barrier_nospec();
+               __get_user_asm(*(u8 *)dst, (u8 __user *)src,
                              ret, "b", "b", "=q", 1);
                return ret;
-       case 2:__get_user_asm(*(u16 *)dst, (u16 __user *)src,
+       case 2:
+               barrier_nospec();
+               __get_user_asm(*(u16 *)dst, (u16 __user *)src,
                              ret, "w", "w", "=r", 2);
                return ret;
-       case 4:__get_user_asm(*(u32 *)dst, (u32 __user *)src,
+       case 4:
+               barrier_nospec();
+               __get_user_asm(*(u32 *)dst, (u32 __user *)src,
                              ret, "l", "k", "=r", 4);
                return ret;
-       case 8:__get_user_asm(*(u64 *)dst, (u64 __user *)src,
+       case 8:
+               barrier_nospec();
+               __get_user_asm(*(u64 *)dst, (u64 __user *)src,
                              ret, "q", "", "=r", 8);
                return ret;
        case 10:
+               barrier_nospec();
                __get_user_asm(*(u64 *)dst, (u64 __user *)src,
                               ret, "q", "", "=r", 10);
                if (unlikely(ret))
@@ -97,6 +106,7 @@ int __copy_from_user_nocheck(void *dst, const void __user *src, unsigned size)
                               ret, "w", "w", "=r", 2);
                return ret;
        case 16:
+               barrier_nospec();
                __get_user_asm(*(u64 *)dst, (u64 __user *)src,
                               ret, "q", "", "=r", 16);
                if (unlikely(ret))
@@ -179,6 +189,7 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
        switch (size) {
        case 1: {
                u8 tmp;
+               barrier_nospec();
                __get_user_asm(tmp, (u8 __user *)src,
                               ret, "b", "b", "=q", 1);
                if (likely(!ret))
@@ -188,6 +199,7 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
        }
        case 2: {
                u16 tmp;
+               barrier_nospec();
                __get_user_asm(tmp, (u16 __user *)src,
                               ret, "w", "w", "=r", 2);
                if (likely(!ret))
@@ -198,6 +210,7 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
 
        case 4: {
                u32 tmp;
+               barrier_nospec();
                __get_user_asm(tmp, (u32 __user *)src,
                               ret, "l", "k", "=r", 4);
                if (likely(!ret))
@@ -207,6 +220,7 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
        }
        case 8: {
                u64 tmp;
+               barrier_nospec();
                __get_user_asm(tmp, (u64 __user *)src,
                               ret, "q", "", "=r", 8);
                if (likely(!ret))
index eaea1d3..143e98b 100644 (file)
@@ -22,6 +22,7 @@ enum vsyscall_num {
 /* kernel space (writeable) */
 extern int vgetcpu_mode;
 extern struct timezone sys_tz;
+extern unsigned long vsyscall_pgprot;
 
 #include <asm/vvar.h>
 
index 5728852..aa80db9 100644 (file)
@@ -43,6 +43,7 @@
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/nospec-branch.h>
 
 #include <xen/interface/xen.h>
 #include <xen/interface/sched.h>
@@ -212,9 +213,9 @@ privcmd_call(unsigned call,
        __HYPERCALL_DECLS;
        __HYPERCALL_5ARG(a1, a2, a3, a4, a5);
 
-       asm volatile("call *%[call]"
+       asm volatile(CALL_NOSPEC
                     : __HYPERCALL_5PARAM
-                    : [call] "a" (&hypercall_page[call])
+                    : [thunk_target] "a" (&hypercall_page[call])
                     : __HYPERCALL_CLOBBER5);
 
        return (long)__res;
index 479d03c..6532d91 100644 (file)
@@ -951,6 +951,14 @@ void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
        int pin;
        struct mpc_intsrc mp_irq;
 
+       /*
+        * Check bus_irq boundary.
+        */
+       if (bus_irq >= NR_IRQS_LEGACY) {
+               pr_warn("Invalid bus_irq %u for legacy override\n", bus_irq);
+               return;
+       }
+
        /*
         * Convert 'gsi' to 'ioapic.pin'.
         */
index bda833c..ad10e46 100644 (file)
 
 #define MAX_PATCH_LEN (255-1)
 
-#ifdef CONFIG_HOTPLUG_CPU
-static int smp_alt_once;
-
-static int __init bootonly(char *str)
-{
-       smp_alt_once = 1;
-       return 1;
-}
-__setup("smp-alt-boot", bootonly);
-#else
-#define smp_alt_once 1
-#endif
-
 static int __initdata_or_module debug_alternative;
 
 static int __init debug_alt(char *str)
@@ -52,19 +39,26 @@ static int __init setup_noreplace_smp(char *str)
 }
 __setup("noreplace-smp", setup_noreplace_smp);
 
-#ifdef CONFIG_PARAVIRT
-static int __initdata_or_module noreplace_paravirt = 0;
-
-static int __init setup_noreplace_paravirt(char *str)
-{
-       noreplace_paravirt = 1;
-       return 1;
-}
-__setup("noreplace-paravirt", setup_noreplace_paravirt);
-#endif
-
-#define DPRINTK(fmt, args...) if (debug_alternative) \
-       printk(KERN_DEBUG fmt, args)
+#define DPRINTK(fmt, args...)                                          \
+do {                                                                   \
+       if (debug_alternative)                                          \
+               printk(KERN_DEBUG "%s: " fmt "\n", __func__, ##args);   \
+} while (0)
+
+#define DUMP_BYTES(buf, len, fmt, args...)                             \
+do {                                                                   \
+       if (unlikely(debug_alternative)) {                              \
+               int j;                                                  \
+                                                                       \
+               if (!(len))                                             \
+                       break;                                          \
+                                                                       \
+               printk(KERN_DEBUG fmt, ##args);                         \
+               for (j = 0; j < (len) - 1; j++)                         \
+                       printk(KERN_CONT "%02hhx ", buf[j]);            \
+               printk(KERN_CONT "%02hhx\n", buf[j]);                   \
+       }                                                               \
+} while (0)
 
 /*
  * Each GENERIC_NOPX is of X bytes, and defined as an array of bytes
@@ -251,12 +245,97 @@ extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
 extern s32 __smp_locks[], __smp_locks_end[];
 void *text_poke_early(void *addr, const void *opcode, size_t len);
 
-/* Replace instructions with better alternatives for this CPU type.
-   This runs before SMP is initialized to avoid SMP problems with
-   self modifying code. This implies that asymmetric systems where
-   APs have less capabilities than the boot processor are not handled.
-   Tough. Make sure you disable such features by hand. */
+/*
+ * Are we looking at a near JMP with a 1 or 4-byte displacement.
+ */
+static inline bool is_jmp(const u8 opcode)
+{
+       return opcode == 0xeb || opcode == 0xe9;
+}
+
+static void __init_or_module
+recompute_jump(struct alt_instr *a, u8 *orig_insn, u8 *repl_insn, u8 *insnbuf)
+{
+       u8 *next_rip, *tgt_rip;
+       s32 n_dspl, o_dspl;
+       int repl_len;
+
+       if (a->replacementlen != 5)
+               return;
+
+       o_dspl = *(s32 *)(insnbuf + 1);
+
+       /* next_rip of the replacement JMP */
+       next_rip = repl_insn + a->replacementlen;
+       /* target rip of the replacement JMP */
+       tgt_rip  = next_rip + o_dspl;
+       n_dspl = tgt_rip - orig_insn;
+
+       DPRINTK("target RIP: %p, new_displ: 0x%x", tgt_rip, n_dspl);
+
+       if (tgt_rip - orig_insn >= 0) {
+               if (n_dspl - 2 <= 127)
+                       goto two_byte_jmp;
+               else
+                       goto five_byte_jmp;
+       /* negative offset */
+       } else {
+               if (((n_dspl - 2) & 0xff) == (n_dspl - 2))
+                       goto two_byte_jmp;
+               else
+                       goto five_byte_jmp;
+       }
+
+two_byte_jmp:
+       n_dspl -= 2;
+
+       insnbuf[0] = 0xeb;
+       insnbuf[1] = (s8)n_dspl;
+       add_nops(insnbuf + 2, 3);
+
+       repl_len = 2;
+       goto done;
+
+five_byte_jmp:
+       n_dspl -= 5;
+
+       insnbuf[0] = 0xe9;
+       *(s32 *)&insnbuf[1] = n_dspl;
+
+       repl_len = 5;
+
+done:
+
+       DPRINTK("final displ: 0x%08x, JMP 0x%lx",
+               n_dspl, (unsigned long)orig_insn + n_dspl + repl_len);
+}
+
+static void __init_or_module optimize_nops(struct alt_instr *a, u8 *instr)
+{
+       unsigned long flags;
+       int i;
+
+       for (i = 0; i < a->padlen; i++) {
+               if (instr[i] != 0x90)
+                       return;
+       }
+
+       local_irq_save(flags);
+       add_nops(instr + (a->instrlen - a->padlen), a->padlen);
+       sync_core();
+       local_irq_restore(flags);
+
+       DUMP_BYTES(instr, a->instrlen, "%p: [%d:%d) optimized NOPs: ",
+                  instr, a->instrlen - a->padlen, a->padlen);
+}
 
+/*
+ * Replace instructions with better alternatives for this CPU type. This runs
+ * before SMP is initialized to avoid SMP problems with self modifying code.
+ * This implies that asymmetric systems where APs have less capabilities than
+ * the boot processor are not handled. Tough. Make sure you disable such
+ * features by hand.
+ */
 void __init_or_module apply_alternatives(struct alt_instr *start,
                                         struct alt_instr *end)
 {
@@ -264,10 +343,10 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
        u8 *instr, *replacement;
        u8 insnbuf[MAX_PATCH_LEN];
 
-       DPRINTK("%s: alt table %p -> %p\n", __func__, start, end);
+       DPRINTK("alt table %p -> %p", start, end);
        /*
         * The scan order should be from start to end. A later scanned
-        * alternative code can overwrite a previous scanned alternative code.
+        * alternative code can overwrite previously scanned alternative code.
         * Some kernel functions (e.g. memcpy, memset, etc) use this order to
         * patch code.
         *
@@ -275,35 +354,59 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
         * order.
         */
        for (a = start; a < end; a++) {
+               int insnbuf_sz = 0;
+
                instr = (u8 *)&a->instr_offset + a->instr_offset;
                replacement = (u8 *)&a->repl_offset + a->repl_offset;
-               BUG_ON(a->replacementlen > a->instrlen);
                BUG_ON(a->instrlen > sizeof(insnbuf));
-               BUG_ON(a->cpuid >= NCAPINTS*32);
-               if (!boot_cpu_has(a->cpuid))
+               BUG_ON(a->cpuid >= (NCAPINTS + NBUGINTS) * 32);
+               if (!boot_cpu_has(a->cpuid)) {
+                       if (a->padlen > 1)
+                               optimize_nops(a, instr);
+
                        continue;
+               }
+
+               DPRINTK("feat: %d*32+%d, old: (%p, len: %d), repl: (%p, len: %d), pad: %d",
+                       a->cpuid >> 5,
+                       a->cpuid & 0x1f,
+                       instr, a->instrlen,
+                       replacement, a->replacementlen, a->padlen);
+
+               DUMP_BYTES(instr, a->instrlen, "%p: old_insn: ", instr);
+               DUMP_BYTES(replacement, a->replacementlen, "%p: rpl_insn: ", replacement);
 
                memcpy(insnbuf, replacement, a->replacementlen);
+               insnbuf_sz = a->replacementlen;
 
                /* 0xe8 is a relative jump; fix the offset. */
-               if (*insnbuf == 0xe8 && a->replacementlen == 5)
-                   *(s32 *)(insnbuf + 1) += replacement - instr;
+               if (*insnbuf == 0xe8 && a->replacementlen == 5) {
+                       *(s32 *)(insnbuf + 1) += replacement - instr;
+                       DPRINTK("Fix CALL offset: 0x%x, CALL 0x%lx",
+                               *(s32 *)(insnbuf + 1),
+                               (unsigned long)instr + *(s32 *)(insnbuf + 1) + 5);
+               }
+
+               if (a->replacementlen && is_jmp(replacement[0]))
+                       recompute_jump(a, instr, replacement, insnbuf);
 
-               add_nops(insnbuf + a->replacementlen,
-                        a->instrlen - a->replacementlen);
+               if (a->instrlen > a->replacementlen) {
+                       add_nops(insnbuf + a->replacementlen,
+                                a->instrlen - a->replacementlen);
+                       insnbuf_sz += a->instrlen - a->replacementlen;
+               }
+               DUMP_BYTES(insnbuf, insnbuf_sz, "%p: final_insn: ", instr);
 
-               text_poke_early(instr, insnbuf, a->instrlen);
+               text_poke_early(instr, insnbuf, insnbuf_sz);
        }
 }
 
 #ifdef CONFIG_SMP
-
 static void alternatives_smp_lock(const s32 *start, const s32 *end,
                                  u8 *text, u8 *text_end)
 {
        const s32 *poff;
 
-       mutex_lock(&text_mutex);
        for (poff = start; poff < end; poff++) {
                u8 *ptr = (u8 *)poff + *poff;
 
@@ -313,7 +416,6 @@ static void alternatives_smp_lock(const s32 *start, const s32 *end,
                if (*ptr == 0x3e)
                        text_poke(ptr, ((unsigned char []){0xf0}), 1);
        };
-       mutex_unlock(&text_mutex);
 }
 
 static void alternatives_smp_unlock(const s32 *start, const s32 *end,
@@ -321,10 +423,6 @@ static void alternatives_smp_unlock(const s32 *start, const s32 *end,
 {
        const s32 *poff;
 
-       if (noreplace_smp)
-               return;
-
-       mutex_lock(&text_mutex);
        for (poff = start; poff < end; poff++) {
                u8 *ptr = (u8 *)poff + *poff;
 
@@ -334,7 +432,6 @@ static void alternatives_smp_unlock(const s32 *start, const s32 *end,
                if (*ptr == 0xf0)
                        text_poke(ptr, ((unsigned char []){0x3E}), 1);
        };
-       mutex_unlock(&text_mutex);
 }
 
 struct smp_alt_module {
@@ -353,8 +450,7 @@ struct smp_alt_module {
        struct list_head next;
 };
 static LIST_HEAD(smp_alt_modules);
-static DEFINE_MUTEX(smp_alt);
-static int smp_mode = 1;       /* protected by smp_alt */
+static bool uniproc_patched = false;   /* protected by text_mutex */
 
 void __init_or_module alternatives_smp_module_add(struct module *mod,
                                                  char *name,
@@ -363,19 +459,18 @@ void __init_or_module alternatives_smp_module_add(struct module *mod,
 {
        struct smp_alt_module *smp;
 
-       if (noreplace_smp)
-               return;
+       mutex_lock(&text_mutex);
+       if (!uniproc_patched)
+               goto unlock;
 
-       if (smp_alt_once) {
-               if (boot_cpu_has(X86_FEATURE_UP))
-                       alternatives_smp_unlock(locks, locks_end,
-                                               text, text_end);
-               return;
-       }
+       if (num_possible_cpus() == 1)
+               /* Don't bother remembering, we'll never have to undo it. */
+               goto smp_unlock;
 
        smp = kzalloc(sizeof(*smp), GFP_KERNEL);
        if (NULL == smp)
-               return; /* we'll run the (safe but slow) SMP code then ... */
+               /* we'll run the (safe but slow) SMP code then ... */
+               goto unlock;
 
        smp->mod        = mod;
        smp->name       = name;
@@ -383,40 +478,33 @@ void __init_or_module alternatives_smp_module_add(struct module *mod,
        smp->locks_end  = locks_end;
        smp->text       = text;
        smp->text_end   = text_end;
-       DPRINTK("%s: locks %p -> %p, text %p -> %p, name %s\n",
-               __func__, smp->locks, smp->locks_end,
+       DPRINTK("locks %p -> %p, text %p -> %p, name %s\n",
+               smp->locks, smp->locks_end,
                smp->text, smp->text_end, smp->name);
 
-       mutex_lock(&smp_alt);
        list_add_tail(&smp->next, &smp_alt_modules);
-       if (boot_cpu_has(X86_FEATURE_UP))
-               alternatives_smp_unlock(smp->locks, smp->locks_end,
-                                       smp->text, smp->text_end);
-       mutex_unlock(&smp_alt);
+smp_unlock:
+       alternatives_smp_unlock(locks, locks_end, text, text_end);
+unlock:
+       mutex_unlock(&text_mutex);
 }
 
 void __init_or_module alternatives_smp_module_del(struct module *mod)
 {
        struct smp_alt_module *item;
 
-       if (smp_alt_once || noreplace_smp)
-               return;
-
-       mutex_lock(&smp_alt);
+       mutex_lock(&text_mutex);
        list_for_each_entry(item, &smp_alt_modules, next) {
                if (mod != item->mod)
                        continue;
                list_del(&item->next);
-               mutex_unlock(&smp_alt);
-               DPRINTK("%s: %s\n", __func__, item->name);
                kfree(item);
-               return;
+               break;
        }
-       mutex_unlock(&smp_alt);
+       mutex_unlock(&text_mutex);
 }
 
-bool skip_smp_alternatives;
-void alternatives_smp_switch(int smp)
+void alternatives_enable_smp(void)
 {
        struct smp_alt_module *mod;
 
@@ -431,38 +519,28 @@ void alternatives_smp_switch(int smp)
        printk("lockdep: fixing up alternatives.\n");
 #endif
 
-       if (noreplace_smp || smp_alt_once || skip_smp_alternatives)
-               return;
-       BUG_ON(!smp && (num_online_cpus() > 1));
+       /* Why bother if there are no other CPUs? */
+       BUG_ON(num_possible_cpus() == 1);
 
-       mutex_lock(&smp_alt);
+       mutex_lock(&text_mutex);
 
-       /*
-        * Avoid unnecessary switches because it forces JIT based VMs to
-        * throw away all cached translations, which can be quite costly.
-        */
-       if (smp == smp_mode) {
-               /* nothing */
-       } else if (smp) {
+       if (uniproc_patched) {
                printk(KERN_INFO "SMP alternatives: switching to SMP code\n");
+               BUG_ON(num_online_cpus() != 1);
                clear_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
                clear_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
                list_for_each_entry(mod, &smp_alt_modules, next)
                        alternatives_smp_lock(mod->locks, mod->locks_end,
                                              mod->text, mod->text_end);
-       } else {
-               printk(KERN_INFO "SMP alternatives: switching to UP code\n");
-               set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
-               set_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
-               list_for_each_entry(mod, &smp_alt_modules, next)
-                       alternatives_smp_unlock(mod->locks, mod->locks_end,
-                                               mod->text, mod->text_end);
+               uniproc_patched = false;
        }
-       smp_mode = smp;
-       mutex_unlock(&smp_alt);
+       mutex_unlock(&text_mutex);
 }
 
-/* Return 1 if the address range is reserved for smp-alternatives */
+/*
+ * Return 1 if the address range is reserved for SMP-alternatives.
+ * Must hold text_mutex.
+ */
 int alternatives_text_reserved(void *start, void *end)
 {
        struct smp_alt_module *mod;
@@ -470,6 +548,8 @@ int alternatives_text_reserved(void *start, void *end)
        u8 *text_start = start;
        u8 *text_end = end;
 
+       lockdep_assert_held(&text_mutex);
+
        list_for_each_entry(mod, &smp_alt_modules, next) {
                if (mod->text > text_end || mod->text_end < text_start)
                        continue;
@@ -483,7 +563,7 @@ int alternatives_text_reserved(void *start, void *end)
 
        return 0;
 }
-#endif
+#endif /* CONFIG_SMP */
 
 #ifdef CONFIG_PARAVIRT
 void __init_or_module apply_paravirt(struct paravirt_patch_site *start,
@@ -492,9 +572,6 @@ void __init_or_module apply_paravirt(struct paravirt_patch_site *start,
        struct paravirt_patch_site *p;
        char insnbuf[MAX_PATCH_LEN];
 
-       if (noreplace_paravirt)
-               return;
-
        for (p = start; p < end; p++) {
                unsigned int used;
 
@@ -535,40 +612,22 @@ void __init alternative_instructions(void)
 
        apply_alternatives(__alt_instructions, __alt_instructions_end);
 
-       /* switch to patch-once-at-boottime-only mode and free the
-        * tables in case we know the number of CPUs will never ever
-        * change */
-#ifdef CONFIG_HOTPLUG_CPU
-       if (num_possible_cpus() < 2)
-               smp_alt_once = 1;
-#endif
-
 #ifdef CONFIG_SMP
-       if (smp_alt_once) {
-               if (1 == num_possible_cpus()) {
-                       printk(KERN_INFO "SMP alternatives: switching to UP code\n");
-                       set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
-                       set_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
-
-                       alternatives_smp_unlock(__smp_locks, __smp_locks_end,
-                                               _text, _etext);
-               }
-       } else {
+       /* Patch to UP if other cpus not imminent. */
+       if (!noreplace_smp && (num_present_cpus() == 1 || setup_max_cpus <= 1)) {
+               uniproc_patched = true;
                alternatives_smp_module_add(NULL, "core kernel",
                                            __smp_locks, __smp_locks_end,
                                            _text, _etext);
-
-               /* Only switch to UP mode if we don't immediately boot others */
-               if (num_present_cpus() == 1 || setup_max_cpus <= 1)
-                       alternatives_smp_switch(0);
        }
-#endif
-       apply_paravirt(__parainstructions, __parainstructions_end);
 
-       if (smp_alt_once)
+       if (!uniproc_patched || num_possible_cpus() == 1)
                free_init_pages("SMP alternatives",
                                (unsigned long)__smp_locks,
                                (unsigned long)__smp_locks_end);
+#endif
+
+       apply_paravirt(__parainstructions, __parainstructions_end);
 
        restart_nmi();
 }
index 25f24dc..06afb95 100644 (file)
@@ -16,9 +16,7 @@ obj-y                 := intel_cacheinfo.o scattered.o topology.o
 obj-y                  += proc.o capflags.o powerflags.o common.o
 obj-y                  += vmware.o hypervisor.o sched.o mshyperv.o
 obj-y                  += rdrand.o
-
-obj-$(CONFIG_X86_32)   += bugs.o
-obj-$(CONFIG_X86_64)   += bugs_64.o
+obj-y                  += bugs.o
 
 obj-$(CONFIG_CPU_SUP_INTEL)            += intel.o
 obj-$(CONFIG_CPU_SUP_AMD)              += amd.o
index 60d4c33..f2f2e6b 100644 (file)
@@ -641,8 +641,32 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
                set_cpu_cap(c, X86_FEATURE_K8);
 
        if (cpu_has_xmm2) {
-               /* MFENCE stops RDTSC speculation */
-               set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
+               unsigned long long val;
+               int ret;
+
+               /*
+                * A serializing LFENCE has less overhead than MFENCE, so
+                * use it for execution serialization.  On families which
+                * don't have that MSR, LFENCE is already serializing.
+                * msr_set_bit() uses the safe accessors, too, even if the MSR
+                * is not present.
+                */
+               msr_set_bit(MSR_F10H_DECFG,
+                           MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT);
+
+               /*
+                * Verify that the MSR write was successful (could be running
+                * under a hypervisor) and only then assume that LFENCE is
+                * serializing.
+                */
+               ret = rdmsrl_safe(MSR_F10H_DECFG, &val);
+               if (!ret && (val & MSR_F10H_DECFG_LFENCE_SERIALIZE)) {
+                       /* A serializing LFENCE stops RDTSC speculation */
+                       set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
+               } else {
+                       /* MFENCE stops RDTSC speculation */
+                       set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
+               }
        }
 
 #ifdef CONFIG_X86_64
index 46674fb..af3b134 100644 (file)
@@ -9,6 +9,11 @@
  */
 #include <linux/init.h>
 #include <linux/utsname.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+
+#include <asm/nospec-branch.h>
+#include <asm/cmdline.h>
 #include <asm/bugs.h>
 #include <asm/processor.h>
 #include <asm/processor-flags.h>
 #include <asm/msr.h>
 #include <asm/paravirt.h>
 #include <asm/alternative.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+#include <asm/intel-family.h>
+
+static void __init spectre_v2_select_mitigation(void);
+
+#ifdef CONFIG_X86_32
 
 static int __init no_halt(char *s)
 {
@@ -156,14 +168,29 @@ static void __init check_config(void)
 #endif
 }
 
+#endif /* CONFIG_X86_32 */
 
 void __init check_bugs(void)
 {
-       identify_boot_cpu();
-#ifndef CONFIG_SMP
-       printk(KERN_INFO "CPU: ");
-       print_cpu_info(&boot_cpu_data);
+#ifdef CONFIG_X86_32
+       /*
+        * Regardless of whether PCID is enumerated, the SDM says
+        * that it can't be enabled in 32-bit mode.
+        */
+       setup_clear_cpu_cap(X86_FEATURE_PCID);
 #endif
+
+       identify_boot_cpu();
+
+       if (!IS_ENABLED(CONFIG_SMP)) {
+               pr_info("CPU: ");
+               print_cpu_info(&boot_cpu_data);
+       }
+
+       /* Select the proper spectre mitigation before patching alternatives */
+       spectre_v2_select_mitigation();
+
+#ifdef CONFIG_X86_32
        check_config();
        check_fpu();
        check_hlt();
@@ -171,4 +198,276 @@ void __init check_bugs(void)
        init_utsname()->machine[1] =
                '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
        alternative_instructions();
+#else /* CONFIG_X86_64 */
+       alternative_instructions();
+
+       /*
+        * Make sure the first 2MB area is not mapped by huge pages
+        * There are typically fixed size MTRRs in there and overlapping
+        * MTRRs into large pages causes slow downs.
+        *
+        * Right now we don't do that with gbpages because there seems
+        * very little benefit for that case.
+        */
+       if (!direct_gbpages)
+               set_memory_4k((unsigned long)__va(0), 1);
+#endif
+}
+
+/* The kernel command line selection */
+enum spectre_v2_mitigation_cmd {
+       SPECTRE_V2_CMD_NONE,
+       SPECTRE_V2_CMD_AUTO,
+       SPECTRE_V2_CMD_FORCE,
+       SPECTRE_V2_CMD_RETPOLINE,
+       SPECTRE_V2_CMD_RETPOLINE_GENERIC,
+       SPECTRE_V2_CMD_RETPOLINE_AMD,
+};
+
+static const char *spectre_v2_strings[] = {
+       [SPECTRE_V2_NONE]                       = "Vulnerable",
+       [SPECTRE_V2_RETPOLINE_MINIMAL]          = "Vulnerable: Minimal generic ASM retpoline",
+       [SPECTRE_V2_RETPOLINE_MINIMAL_AMD]      = "Vulnerable: Minimal AMD ASM retpoline",
+       [SPECTRE_V2_RETPOLINE_GENERIC]          = "Mitigation: Full generic retpoline",
+       [SPECTRE_V2_RETPOLINE_AMD]              = "Mitigation: Full AMD retpoline",
+};
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "Spectre V2 : " fmt
+
+static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE;
+
+#ifdef RETPOLINE
+static bool spectre_v2_bad_module;
+
+bool retpoline_module_ok(bool has_retpoline)
+{
+       if (spectre_v2_enabled == SPECTRE_V2_NONE || has_retpoline)
+               return true;
+
+       pr_err("System may be vulnerable to spectre v2\n");
+       spectre_v2_bad_module = true;
+       return false;
+}
+
+static inline const char *spectre_v2_module_string(void)
+{
+       return spectre_v2_bad_module ? " - vulnerable module loaded" : "";
+}
+#else
+static inline const char *spectre_v2_module_string(void) { return ""; }
+#endif
+
+static void __init spec2_print_if_insecure(const char *reason)
+{
+       if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
+               pr_info("%s selected on command line.\n", reason);
+}
+
+static void __init spec2_print_if_secure(const char *reason)
+{
+       if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
+               pr_info("%s selected on command line.\n", reason);
+}
+
+static inline bool retp_compiler(void)
+{
+       return __is_defined(RETPOLINE);
+}
+
+static inline bool match_option(const char *arg, int arglen, const char *opt)
+{
+       int len = strlen(opt);
+
+       return len == arglen && !strncmp(arg, opt, len);
+}
+
+static const struct {
+       const char *option;
+       enum spectre_v2_mitigation_cmd cmd;
+       bool secure;
+} mitigation_options[] = {
+       { "off",               SPECTRE_V2_CMD_NONE,              false },
+       { "on",                SPECTRE_V2_CMD_FORCE,             true },
+       { "retpoline",         SPECTRE_V2_CMD_RETPOLINE,         false },
+       { "retpoline,amd",     SPECTRE_V2_CMD_RETPOLINE_AMD,     false },
+       { "retpoline,generic", SPECTRE_V2_CMD_RETPOLINE_GENERIC, false },
+       { "auto",              SPECTRE_V2_CMD_AUTO,              false },
+};
+
+static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
+{
+       char arg[20];
+       int ret, i;
+       enum spectre_v2_mitigation_cmd cmd = SPECTRE_V2_CMD_AUTO;
+
+       if (cmdline_find_option_bool(boot_command_line, "nospectre_v2"))
+               return SPECTRE_V2_CMD_NONE;
+       else {
+               ret = cmdline_find_option(boot_command_line, "spectre_v2", arg,
+                                         sizeof(arg));
+               if (ret < 0)
+                       return SPECTRE_V2_CMD_AUTO;
+
+               for (i = 0; i < ARRAY_SIZE(mitigation_options); i++) {
+                       if (!match_option(arg, ret, mitigation_options[i].option))
+                               continue;
+                       cmd = mitigation_options[i].cmd;
+                       break;
+               }
+
+               if (i >= ARRAY_SIZE(mitigation_options)) {
+                       pr_err("unknown option (%s). Switching to AUTO select\n", arg);
+                       return SPECTRE_V2_CMD_AUTO;
+               }
+       }
+
+       if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
+            cmd == SPECTRE_V2_CMD_RETPOLINE_AMD ||
+            cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) &&
+           !IS_ENABLED(CONFIG_RETPOLINE)) {
+               pr_err("%s selected but not compiled in. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_RETPOLINE_AMD &&
+           boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
+               pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (mitigation_options[i].secure)
+               spec2_print_if_secure(mitigation_options[i].option);
+       else
+               spec2_print_if_insecure(mitigation_options[i].option);
+
+       return cmd;
 }
+
+/* Check for Skylake-like CPUs (for RSB handling) */
+static bool __init is_skylake_era(void)
+{
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+           boot_cpu_data.x86 == 6) {
+               switch (boot_cpu_data.x86_model) {
+               case INTEL_FAM6_SKYLAKE_MOBILE:
+               case INTEL_FAM6_SKYLAKE_DESKTOP:
+               case INTEL_FAM6_SKYLAKE_X:
+               case INTEL_FAM6_KABYLAKE_MOBILE:
+               case INTEL_FAM6_KABYLAKE_DESKTOP:
+                       return true;
+               }
+       }
+       return false;
+}
+
+static void __init spectre_v2_select_mitigation(void)
+{
+       enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
+       enum spectre_v2_mitigation mode = SPECTRE_V2_NONE;
+
+       /*
+        * If the CPU is not affected and the command line mode is NONE or AUTO
+        * then nothing to do.
+        */
+       if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2) &&
+           (cmd == SPECTRE_V2_CMD_NONE || cmd == SPECTRE_V2_CMD_AUTO))
+               return;
+
+       switch (cmd) {
+       case SPECTRE_V2_CMD_NONE:
+               return;
+
+       case SPECTRE_V2_CMD_FORCE:
+       case SPECTRE_V2_CMD_AUTO:
+               if (IS_ENABLED(CONFIG_RETPOLINE))
+                       goto retpoline_auto;
+               break;
+       case SPECTRE_V2_CMD_RETPOLINE_AMD:
+               if (IS_ENABLED(CONFIG_RETPOLINE))
+                       goto retpoline_amd;
+               break;
+       case SPECTRE_V2_CMD_RETPOLINE_GENERIC:
+               if (IS_ENABLED(CONFIG_RETPOLINE))
+                       goto retpoline_generic;
+               break;
+       case SPECTRE_V2_CMD_RETPOLINE:
+               if (IS_ENABLED(CONFIG_RETPOLINE))
+                       goto retpoline_auto;
+               break;
+       }
+       pr_err("kernel not compiled with retpoline; no mitigation available!");
+       return;
+
+retpoline_auto:
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
+       retpoline_amd:
+               if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
+                       pr_err("LFENCE not serializing. Switching to generic retpoline\n");
+                       goto retpoline_generic;
+               }
+               mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_AMD :
+                                        SPECTRE_V2_RETPOLINE_MINIMAL_AMD;
+               setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD);
+               setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
+       } else {
+       retpoline_generic:
+               mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_GENERIC :
+                                        SPECTRE_V2_RETPOLINE_MINIMAL;
+               setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
+       }
+
+       spectre_v2_enabled = mode;
+       pr_info("%s\n", spectre_v2_strings[mode]);
+
+       /*
+        * If neither SMEP or KPTI are available, there is a risk of
+        * hitting userspace addresses in the RSB after a context switch
+        * from a shallow call stack to a deeper one. To prevent this fill
+        * the entire RSB, even when using IBRS.
+        *
+        * Skylake era CPUs have a separate issue with *underflow* of the
+        * RSB, when they will predict 'ret' targets from the generic BTB.
+        * The proper mitigation for this is IBRS. If IBRS is not supported
+        * or deactivated in favour of retpolines the RSB fill on context
+        * switch is required.
+        */
+       if ((!boot_cpu_has(X86_FEATURE_KAISER) &&
+            !boot_cpu_has(X86_FEATURE_SMEP)) || is_skylake_era()) {
+               setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
+               pr_info("Filling RSB on context switch\n");
+       }
+}
+
+#undef pr_fmt
+
+#ifdef CONFIG_SYSFS
+ssize_t cpu_show_meltdown(struct sysdev_class *dev,
+                         struct sysdev_class_attribute *attr, char *buf)
+{
+       if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN))
+               return sprintf(buf, "Not affected\n");
+       if (boot_cpu_has(X86_FEATURE_KAISER))
+               return sprintf(buf, "Mitigation: PTI\n");
+       return sprintf(buf, "Vulnerable\n");
+}
+
+ssize_t cpu_show_spectre_v1(struct sysdev_class *dev,
+                           struct sysdev_class_attribute *attr, char *buf)
+{
+       if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1))
+               return sprintf(buf, "Not affected\n");
+       return sprintf(buf, "Mitigation: __user pointer sanitization\n");
+}
+
+ssize_t cpu_show_spectre_v2(struct sysdev_class *dev,
+                           struct sysdev_class_attribute *attr, char *buf)
+{
+       if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
+               return sprintf(buf, "Not affected\n");
+
+       return sprintf(buf, "%s%s\n", spectre_v2_strings[spectre_v2_enabled],
+                      spectre_v2_module_string());
+}
+#endif
diff --git a/arch/x86/kernel/cpu/bugs_64.c b/arch/x86/kernel/cpu/bugs_64.c
deleted file mode 100644 (file)
index 04f0fe5..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  Copyright (C) 1994  Linus Torvalds
- *  Copyright (C) 2000  SuSE
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/alternative.h>
-#include <asm/bugs.h>
-#include <asm/processor.h>
-#include <asm/mtrr.h>
-#include <asm/cacheflush.h>
-
-void __init check_bugs(void)
-{
-       identify_boot_cpu();
-#if !defined(CONFIG_SMP)
-       printk(KERN_INFO "CPU: ");
-       print_cpu_info(&boot_cpu_data);
-#endif
-       alternative_instructions();
-
-       /*
-        * Make sure the first 2MB area is not mapped by huge pages
-        * There are typically fixed size MTRRs in there and overlapping
-        * MTRRs into large pages causes slow downs.
-        *
-        * Right now we don't do that with gbpages because there seems
-        * very little benefit for that case.
-        */
-       if (!direct_gbpages)
-               set_memory_4k((unsigned long)__va(0), 1);
-}
index 83df01d..458c595 100644 (file)
@@ -84,7 +84,7 @@ static const struct cpu_dev __cpuinitconst default_cpu = {
 
 static const struct cpu_dev *this_cpu __cpuinitdata = &default_cpu;
 
-DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = {
+DEFINE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(struct gdt_page, gdt_page) = { .gdt = {
 #ifdef CONFIG_X86_64
        /*
         * We need valid kernel segments for data and code in long mode too
@@ -155,6 +155,40 @@ static int __init x86_xsaveopt_setup(char *s)
 }
 __setup("noxsaveopt", x86_xsaveopt_setup);
 
+#ifdef CONFIG_X86_64
+static int __init x86_pcid_setup(char *s)
+{
+       /* require an exact match without trailing characters */
+       if (strlen(s))
+               return 0;
+
+       /* do not emit a message if the feature is not present */
+       if (!boot_cpu_has(X86_FEATURE_PCID))
+               return 1;
+
+       setup_clear_cpu_cap(X86_FEATURE_PCID);
+       pr_info("nopcid: PCID feature disabled\n");
+       return 1;
+}
+__setup("nopcid", x86_pcid_setup);
+#endif
+
+static int __init x86_noinvpcid_setup(char *s)
+{
+       /* noinvpcid doesn't accept parameters */
+       if (s)
+               return -EINVAL;
+
+       /* do not emit a message if the feature is not present */
+       if (!boot_cpu_has(X86_FEATURE_INVPCID))
+               return 0;
+
+       setup_clear_cpu_cap(X86_FEATURE_INVPCID);
+       pr_info("noinvpcid: INVPCID feature disabled\n");
+       return 0;
+}
+early_param("noinvpcid", x86_noinvpcid_setup);
+
 #ifdef CONFIG_X86_32
 static int cachesize_override __cpuinitdata = -1;
 static int disable_x86_serial_nr __cpuinitdata = 1;
@@ -276,6 +310,44 @@ static __cpuinit void setup_smep(struct cpuinfo_x86 *c)
        }
 }
 
+static void setup_pcid(struct cpuinfo_x86 *c)
+{
+       if (cpu_has(c, X86_FEATURE_PCID)) {
+               if (IS_ENABLED(CONFIG_X86_64) &&
+                    (cpu_has(c, X86_FEATURE_PGE) || kaiser_enabled)) {
+                       /*
+                        * Regardless of whether PCID is enumerated, the
+                        * SDM says that it can't be enabled in 32-bit mode.
+                        */
+                       set_in_cr4(X86_CR4_PCIDE);
+                       /*
+                        * INVPCID has two "groups" of types:
+                        * 1/2: Invalidate an individual address
+                        * 3/4: Invalidate all contexts
+                        *
+                        * 1/2 take a PCID, but 3/4 do not.  So, 3/4
+                        * ignore the PCID argument in the descriptor.
+                        * But, we have to be careful not to call 1/2
+                        * with an actual non-zero PCID in them before
+                        * we do the above set_in_cr4().
+                        */
+                       if (cpu_has(c, X86_FEATURE_INVPCID))
+                               set_cpu_cap(c, X86_FEATURE_INVPCID_SINGLE);
+               } else {
+                       /*
+                        * flush_tlb_all(), as currently implemented, won't
+                        * work if PCID is on but PGE is not.  Since that
+                        * combination doesn't exist on real hardware, there's
+                        * no reason to try to fully support it, but it's
+                        * polite to avoid corrupting data if we're on
+                        * an improperly configured VM.
+                        */
+                       clear_cpu_cap(c, X86_FEATURE_PCID);
+               }
+       }
+       kaiser_setup_pcid();
+}
+
 /*
  * Some CPU features depend on higher CPUID levels, which may not always
  * be available due to CPUID level capping or broken virtualization
@@ -352,8 +424,8 @@ static const char *__cpuinit table_lookup_model(struct cpuinfo_x86 *c)
        return NULL;            /* Not found */
 }
 
-__u32 cpu_caps_cleared[NCAPINTS] __cpuinitdata;
-__u32 cpu_caps_set[NCAPINTS] __cpuinitdata;
+__u32 cpu_caps_cleared[NCAPINTS + NBUGINTS] __cpuinitdata;
+__u32 cpu_caps_set[NCAPINTS + NBUGINTS] __cpuinitdata;
 
 void load_percpu_segment(int cpu)
 {
@@ -560,6 +632,16 @@ void __cpuinit cpu_detect(struct cpuinfo_x86 *c)
        }
 }
 
+static void apply_forced_caps(struct cpuinfo_x86 *c)
+{
+       int i;
+
+       for (i = 0; i < NCAPINTS + NBUGINTS; i++) {
+               c->x86_capability[i] &= ~cpu_caps_cleared[i];
+               c->x86_capability[i] |= cpu_caps_set[i];
+       }
+}
+
 void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
 {
        u32 tfms, xlvl;
@@ -685,6 +767,12 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 
        if (this_cpu->c_bsp_init)
                this_cpu->c_bsp_init(c);
+
+       if (c->x86_vendor != X86_VENDOR_AMD)
+               setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN);
+
+       setup_force_cpu_bug(X86_BUG_SPECTRE_V1);
+       setup_force_cpu_bug(X86_BUG_SPECTRE_V2);
 }
 
 void __init early_cpu_init(void)
@@ -808,10 +896,7 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
                this_cpu->c_identify(c);
 
        /* Clear/Set all flags overriden by options, after probe */
-       for (i = 0; i < NCAPINTS; i++) {
-               c->x86_capability[i] &= ~cpu_caps_cleared[i];
-               c->x86_capability[i] |= cpu_caps_set[i];
-       }
+       apply_forced_caps(c);
 
 #ifdef CONFIG_X86_64
        c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
@@ -833,6 +918,9 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
        /* Disable the PN if appropriate */
        squash_the_stupid_serial_number(c);
 
+       /* Set up PCID */
+       setup_pcid(c);
+
        /*
         * The vendor-specific functions might have changed features.
         * Now we do "generic changes."
@@ -864,10 +952,7 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
         * Clear/Set all flags overriden by options, need do it
         * before following smp all cpus cap AND.
         */
-       for (i = 0; i < NCAPINTS; i++) {
-               c->x86_capability[i] &= ~cpu_caps_cleared[i];
-               c->x86_capability[i] |= cpu_caps_set[i];
-       }
+       apply_forced_caps(c);
 
        /*
         * On SMP, boot_cpu_data holds the common feature set between
@@ -879,6 +964,10 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
                /* AND the already accumulated flags with these */
                for (i = 0; i < NCAPINTS; i++)
                        boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
+
+               /* OR, i.e. replicate the bug flags */
+               for (i = NCAPINTS; i < NCAPINTS + NBUGINTS; i++)
+                       c->x86_capability[i] |= boot_cpu_data.x86_capability[i];
        }
 
        /* Init Machine Check Exception if available. */
@@ -1055,7 +1144,7 @@ static const unsigned int exception_stack_sizes[N_EXCEPTION_STACKS] = {
          [DEBUG_STACK - 1]                     = DEBUG_STKSZ
 };
 
-static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks
+DEFINE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(char, exception_stacks
        [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]);
 
 /* May not be marked __init: used by software suspend */
@@ -1155,6 +1244,15 @@ void __cpuinit cpu_init(void)
        int cpu;
        int i;
 
+       if (!kaiser_enabled) {
+               /*
+                * secondary_startup_64() deferred setting PGE in cr4:
+                * init_memory_mapping() sets it on the boot cpu,
+                * but it needs to be set on each secondary cpu.
+                */
+               set_in_cr4(X86_CR4_PGE);
+       }
+
        cpu = stack_smp_processor_id();
        t = &per_cpu(init_tss, cpu);
        oist = &per_cpu(orig_ist, cpu);
index 3b67877..1f439d4 100644 (file)
@@ -52,6 +52,9 @@ static DEFINE_MUTEX(mce_chrdev_read_mutex);
                              rcu_read_lock_sched_held() || \
                              lockdep_is_held(&mce_chrdev_read_mutex))
 
+/* sysfs synchronization */
+static DEFINE_MUTEX(mce_sysfs_mutex);
+
 #define CREATE_TRACE_POINTS
 #include <trace/events/mce.h>
 
@@ -122,6 +125,8 @@ void mce_setup(struct mce *m)
        m->socketid = cpu_data(m->extcpu).phys_proc_id;
        m->apicid = cpu_data(m->extcpu).initial_apicid;
        rdmsrl(MSR_IA32_MCG_CAP, m->mcgcap);
+
+       m->microcode = boot_cpu_data.microcode;
 }
 
 DEFINE_PER_CPU(struct mce, injectm);
@@ -218,7 +223,7 @@ static void print_mce(struct mce *m)
         */
        pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n",
                m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
-               cpu_data(m->extcpu).microcode);
+               m->microcode);
 
        /*
         * Print out human-readable details about the MCE error,
@@ -1407,6 +1412,11 @@ static void unexpected_machine_check(struct pt_regs *regs, long error_code)
 void (*machine_check_vector)(struct pt_regs *, long error_code) =
                                                unexpected_machine_check;
 
+void do_mce(struct pt_regs *regs, long error_code)
+{
+       machine_check_vector(regs, error_code);
+}
+
 /*
  * Called for each booted CPU to set up machine checks.
  * Must be called with preempt off:
@@ -1878,6 +1888,7 @@ static ssize_t set_ignore_ce(struct sys_device *s,
        if (strict_strtoull(buf, 0, &new) < 0)
                return -EINVAL;
 
+       mutex_lock(&mce_sysfs_mutex);
        if (mce_ignore_ce ^ !!new) {
                if (new) {
                        /* disable ce features */
@@ -1890,6 +1901,8 @@ static ssize_t set_ignore_ce(struct sys_device *s,
                        on_each_cpu(mce_enable_ce, (void *)1, 1);
                }
        }
+       mutex_unlock(&mce_sysfs_mutex);
+
        return size;
 }
 
@@ -1902,6 +1915,7 @@ static ssize_t set_cmci_disabled(struct sys_device *s,
        if (strict_strtoull(buf, 0, &new) < 0)
                return -EINVAL;
 
+       mutex_lock(&mce_sysfs_mutex);
        if (mce_cmci_disabled ^ !!new) {
                if (new) {
                        /* disable cmci */
@@ -1913,6 +1927,8 @@ static ssize_t set_cmci_disabled(struct sys_device *s,
                        on_each_cpu(mce_enable_ce, NULL, 1);
                }
        }
+       mutex_unlock(&mce_sysfs_mutex);
+
        return size;
 }
 
@@ -1920,8 +1936,19 @@ static ssize_t store_int_with_restart(struct sys_device *s,
                                      struct sysdev_attribute *attr,
                                      const char *buf, size_t size)
 {
-       ssize_t ret = sysdev_store_int(s, attr, buf, size);
+       unsigned long old_check_interval = check_interval;
+       ssize_t ret = sysdev_store_ulong(s, attr, buf, size);
+
+       if (check_interval == old_check_interval)
+               return ret;
+
+       if (check_interval < 1)
+               check_interval = 1;
+
+       mutex_lock(&mce_sysfs_mutex);
        mce_restart();
+       mutex_unlock(&mce_sysfs_mutex);
+
        return ret;
 }
 
index 1c041e0..57cb4fa 100644 (file)
@@ -1461,6 +1461,12 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
        dump_trace(NULL, regs, NULL, 0, &backtrace_ops, entry);
 }
 
+static inline int
+valid_user_frame(const void __user *fp, unsigned long size)
+{
+       return (__range_not_ok(fp, size, TASK_SIZE) == 0);
+}
+
 #ifdef CONFIG_COMPAT
 static inline int
 perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
@@ -1485,6 +1491,9 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
                if (fp < compat_ptr(regs->sp))
                        break;
 
+               if (!valid_user_frame(fp, sizeof(frame)))
+                       break;
+
                perf_callchain_store(entry, frame.return_address);
                fp = compat_ptr(frame.next_frame);
        }
@@ -1531,6 +1540,9 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
                if ((unsigned long)fp < regs->sp)
                        break;
 
+               if (!valid_user_frame(fp, sizeof(frame)))
+                       break;
+
                perf_callchain_store(entry, frame.return_address);
                fp = frame.next_frame;
        }
index 2d4e76b..721d236 100644 (file)
@@ -2,10 +2,14 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 
+#include <asm/kaiser.h>
 #include <asm/perf_event.h>
 
 #include "perf_event.h"
 
+static
+DEFINE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(struct debug_store, cpu_debug_store);
+
 /* The size of a BTS record in bytes: */
 #define BTS_RECORD_SIZE                24
 
@@ -60,6 +64,39 @@ void fini_debug_store_on_cpu(int cpu)
        wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0);
 }
 
+static void *dsalloc(size_t size, gfp_t flags, int node)
+{
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+       unsigned int order = get_order(size);
+       struct page *page;
+       unsigned long addr;
+
+       page = alloc_pages_node(node, flags | __GFP_ZERO, order);
+       if (!page)
+               return NULL;
+       addr = (unsigned long)page_address(page);
+       if (kaiser_add_mapping(addr, size, __PAGE_KERNEL) < 0) {
+               __free_pages(page, order);
+               addr = 0;
+       }
+       return (void *)addr;
+#else
+       return kmalloc_node(size, flags | __GFP_ZERO, node);
+#endif
+}
+
+static void dsfree(const void *buffer, size_t size)
+{
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+       if (!buffer)
+               return;
+       kaiser_remove_mapping((unsigned long)buffer, size);
+       free_pages((unsigned long)buffer, get_order(size));
+#else
+       kfree(buffer);
+#endif
+}
+
 static int alloc_pebs_buffer(int cpu)
 {
        struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
@@ -70,7 +107,7 @@ static int alloc_pebs_buffer(int cpu)
        if (!x86_pmu.pebs)
                return 0;
 
-       buffer = kmalloc_node(PEBS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
+       buffer = dsalloc(PEBS_BUFFER_SIZE, GFP_KERNEL, node);
        if (unlikely(!buffer))
                return -ENOMEM;
 
@@ -94,7 +131,7 @@ static void release_pebs_buffer(int cpu)
        if (!ds || !x86_pmu.pebs)
                return;
 
-       kfree((void *)(unsigned long)ds->pebs_buffer_base);
+       dsfree((void *)(unsigned long)ds->pebs_buffer_base, PEBS_BUFFER_SIZE);
        ds->pebs_buffer_base = 0;
 }
 
@@ -108,7 +145,7 @@ static int alloc_bts_buffer(int cpu)
        if (!x86_pmu.bts)
                return 0;
 
-       buffer = kmalloc_node(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
+       buffer = dsalloc(BTS_BUFFER_SIZE, GFP_KERNEL, node);
        if (unlikely(!buffer))
                return -ENOMEM;
 
@@ -132,19 +169,15 @@ static void release_bts_buffer(int cpu)
        if (!ds || !x86_pmu.bts)
                return;
 
-       kfree((void *)(unsigned long)ds->bts_buffer_base);
+       dsfree((void *)(unsigned long)ds->bts_buffer_base, BTS_BUFFER_SIZE);
        ds->bts_buffer_base = 0;
 }
 
 static int alloc_ds_buffer(int cpu)
 {
-       int node = cpu_to_node(cpu);
-       struct debug_store *ds;
-
-       ds = kmalloc_node(sizeof(*ds), GFP_KERNEL | __GFP_ZERO, node);
-       if (unlikely(!ds))
-               return -ENOMEM;
+       struct debug_store *ds = per_cpu_ptr(&cpu_debug_store, cpu);
 
+       memset(ds, 0, sizeof(*ds));
        per_cpu(cpu_hw_events, cpu).ds = ds;
 
        return 0;
@@ -158,7 +191,6 @@ static void release_ds_buffer(int cpu)
                return;
 
        per_cpu(cpu_hw_events, cpu).ds = NULL;
-       kfree(ds);
 }
 
 void release_ds_buffers(void)
index 0fa4f89..ede58ee 100644 (file)
@@ -55,6 +55,7 @@
 #include <asm/irq_vectors.h>
 #include <asm/cpufeature.h>
 #include <asm/alternative-asm.h>
+#include <asm/nospec-branch.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
 #include <linux/elf-em.h>
@@ -428,7 +429,14 @@ sysenter_past_esp:
 sysenter_do_call:
        cmpl $(nr_syscalls), %eax
        jae sysenter_badsys
+       sbb %edx, %edx                          /* array_index_mask_nospec() */
+       and %edx, %eax
+#ifdef CONFIG_RETPOLINE
+       movl sys_call_table(,%eax,4),%eax
+       call __x86_indirect_thunk_eax
+#else
        call *sys_call_table(,%eax,4)
+#endif
 sysenter_after_call:
        movl %eax,PT_EAX(%esp)
        LOCKDEP_SYS_EXIT
@@ -511,7 +519,14 @@ ENTRY(system_call)
        cmpl $(nr_syscalls), %eax
        jae syscall_badsys
 syscall_call:
+       sbb %edx, %edx                          /* array_index_mask_nospec() */
+       and %edx, %eax
+#ifdef CONFIG_RETPOLINE
+       movl sys_call_table(,%eax,4),%eax
+       call __x86_indirect_thunk_eax
+#else
        call *sys_call_table(,%eax,4)
+#endif
 syscall_after_call:
        movl %eax,PT_EAX(%esp)          # store the return value
 syscall_exit:
@@ -887,7 +902,7 @@ ENTRY(simd_coprocessor_error)
 661:   pushl_cfi $do_general_protection
 662:
 .section .altinstructions,"a"
-       altinstruction_entry 661b, 663f, X86_FEATURE_XMM, 662b-661b, 664f-663f
+       altinstruction_entry 661b, 663f, X86_FEATURE_XMM, 662b-661b, 664f-663f, 0
 .previous
 .section .altinstr_replacement,"ax"
 663:   pushl $do_simd_coprocessor_error
@@ -1017,7 +1032,7 @@ ENTRY(kernel_thread_helper)
        pushl $0                # fake return address for unwinder
        CFI_STARTPROC
        movl %edi,%eax
-       call *%esi
+       CALL_NOSPEC %esi
        call do_exit
        ud2                     # padding for call trace
        CFI_ENDPROC
@@ -1182,7 +1197,8 @@ trace:
        movl 0x4(%ebp), %edx
        subl $MCOUNT_INSN_SIZE, %eax
 
-       call *ftrace_trace_function
+       movl ftrace_trace_function, %ecx
+       CALL_NOSPEC %ecx
 
        popl %edx
        popl %ecx
@@ -1220,7 +1236,7 @@ return_to_handler:
        movl %eax, %ecx
        popl %edx
        popl %eax
-       jmp *%ecx
+       JMP_NOSPEC %ecx
 #endif
 
 .section .rodata,"a"
@@ -1274,7 +1290,7 @@ error_code:
        movl %ecx, %es
        TRACE_IRQS_OFF
        movl %esp,%eax                  # pt_regs pointer
-       call *%edi
+       CALL_NOSPEC %edi
        jmp ret_from_exception
        CFI_ENDPROC
 END(page_fault)
index f6daf3c..b15af62 100644 (file)
 #include <asm/ftrace.h>
 #include <asm/percpu.h>
 #include <asm/pgtable_types.h>
+#include <asm/alternative-asm.h>
+#include <asm/cpufeature.h>
+#include <asm/kaiser.h>
+#include <asm/nospec-branch.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
 #include <linux/elf-em.h>
@@ -122,8 +126,8 @@ trace:
        movq 8(%rbp), %rsi
        subq $MCOUNT_INSN_SIZE, %rdi
 
-       call   *ftrace_trace_function
-
+       movq ftrace_trace_function, %r8
+       CALL_NOSPEC %r8
        MCOUNT_RESTORE_FRAME
 
        jmp ftrace_stub
@@ -164,7 +168,7 @@ GLOBAL(return_to_handler)
        movq 8(%rsp), %rdx
        movq (%rsp), %rax
        addq $24, %rsp
-       jmp *%rdi
+       JMP_NOSPEC %rdi
 #endif
 
 
@@ -323,6 +327,7 @@ ENDPROC(native_usergs_sysret64)
        testl $3, CS(%rdi)
        je 1f
        SWAPGS
+       SWITCH_KERNEL_CR3
        /*
         * irq_count is used to check if a CPU is already on an interrupt stack
         * or not. While this is essentially redundant with preempt_count it is
@@ -362,6 +367,12 @@ END(save_rest)
 
 /* save complete stack frame */
        .pushsection .kprobes.text, "ax"
+/*
+ * Return: ebx=0: needs swapgs but not SWITCH_USER_CR3 in paranoid_exit
+ *         ebx=1: needs neither swapgs nor SWITCH_USER_CR3 in paranoid_exit
+ *         ebx=2: needs both swapgs and SWITCH_USER_CR3 in paranoid_exit
+ *         ebx=3: needs SWITCH_USER_CR3 but not swapgs in paranoid_exit
+ */
 ENTRY(save_paranoid)
        XCPT_FRAME 1 RDI+8
        cld
@@ -387,7 +398,26 @@ ENTRY(save_paranoid)
        js 1f   /* negative -> in kernel */
        SWAPGS
        xorl %ebx,%ebx
-1:     ret
+1:
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+       /*
+        * We might have come in between a swapgs and a SWITCH_KERNEL_CR3
+        * on entry, or between a SWITCH_USER_CR3 and a swapgs on exit.
+        * Do a conditional SWITCH_KERNEL_CR3: this could safely be done
+        * unconditionally, but we need to find out whether the reverse
+        * should be done on return (conveyed to paranoid_exit in %ebx).
+        */
+       ALTERNATIVE "jmp 2f", "movq %cr3, %rax", X86_FEATURE_KAISER
+       testl   $KAISER_SHADOW_PGD_OFFSET, %eax
+       jz      2f
+       orl     $2, %ebx
+       andq    $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), %rax
+       /* If PCID enabled, set X86_CR3_PCID_NOFLUSH_BIT */
+       ALTERNATIVE "", "bts $63, %rax", X86_FEATURE_PCID
+       movq    %rax, %cr3
+2:
+#endif
+       ret
        CFI_ENDPROC
 END(save_paranoid)
        .popsection
@@ -464,6 +494,7 @@ ENTRY(system_call)
        CFI_REGISTER    rip,rcx
        /*CFI_REGISTER  rflags,r11*/
        SWAPGS_UNSAFE_STACK
+       SWITCH_KERNEL_CR3_NO_STACK
        /*
         * A hypervisor implementation might want to use a label
         * after the swapgs, so that it can do the swapgs
@@ -486,10 +517,17 @@ ENTRY(system_call_after_swapgs)
        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%rcx)
        jnz tracesys
 system_call_fastpath:
-       cmpq $__NR_syscall_max,%rax
-       ja badsys
+       cmpq    $NR_syscalls, %rax
+       jae     badsys
+       sbb     %rcx, %rcx                      /* array_index_mask_nospec() */
+       and     %rcx, %rax
        movq %r10,%rcx
+#ifdef CONFIG_RETPOLINE
+       movq    sys_call_table(, %rax, 8), %rax
+       call    __x86_indirect_thunk_rax
+#else
        call *sys_call_table(,%rax,8)  # XXX:    rip relative
+#endif
        movq %rax,RAX-ARGOFFSET(%rsp)
 /*
  * Syscall return path ending with SYSRET (fast path)
@@ -515,6 +553,14 @@ sysret_check:
        CFI_REGISTER    rip,rcx
        RESTORE_ARGS 1,-ARG_SKIP,0
        /*CFI_REGISTER  rflags,r11*/
+       /*
+        * This opens a window where we have a user CR3, but are
+        * running in the kernel.  This makes using the CS
+        * register useless for telling whether or not we need to
+        * switch CR3 in NMIs.  Normal interrupts are OK because
+        * they are off here.
+        */
+       SWITCH_USER_CR3
        movq    PER_CPU_VAR(old_rsp), %rsp
        USERGS_SYSRET64
 
@@ -602,10 +648,17 @@ tracesys:
         */
        LOAD_ARGS ARGOFFSET, 1
        RESTORE_REST
-       cmpq $__NR_syscall_max,%rax
-       ja   int_ret_from_sys_call      /* RAX(%rsp) set to -ENOSYS above */
+       cmpq    $NR_syscalls, %rax
+       jae     int_ret_from_sys_call           /* RAX(%rsp) set to -ENOSYS above */
+       sbb     %rcx, %rcx                      /* array_index_mask_nospec() */
+       and     %rcx, %rax
        movq %r10,%rcx  /* fixup for C */
+#ifdef CONFIG_RETPOLINE
+       movq    sys_call_table(, %rax, 8), %rax
+       call    __x86_indirect_thunk_rax
+#else
        call *sys_call_table(,%rax,8)
+#endif
        movq %rax,RAX-ARGOFFSET(%rsp)
        /* Use IRET because user could have changed frame */
 
@@ -851,6 +904,14 @@ retint_swapgs:             /* return to user-space */
         */
        DISABLE_INTERRUPTS(CLBR_ANY)
        TRACE_IRQS_IRETQ
+       /*
+        * This opens a window where we have a user CR3, but are
+        * running in the kernel.  This makes using the CS
+        * register useless for telling whether or not we need to
+        * switch CR3 in NMIs.  Normal interrupts are OK because
+        * they are off here.
+        */
+       SWITCH_USER_CR3
        SWAPGS
        jmp restore_args
 
@@ -891,6 +952,7 @@ native_irq_return_ldt:
        pushq_cfi %rax
        pushq_cfi %rdi
        SWAPGS
+       SWITCH_KERNEL_CR3
        movq PER_CPU_VAR(espfix_waddr),%rdi
        movq %rax,(0*8)(%rdi)   /* RAX */
        movq (2*8)(%rsp),%rax   /* RIP */
@@ -906,6 +968,7 @@ native_irq_return_ldt:
        andl $0xffff0000,%eax
        popq_cfi %rdi
        orq PER_CPU_VAR(espfix_stack),%rax
+       SWITCH_USER_CR3
        SWAPGS
        movq %rax,%rsp
        popq_cfi %rax
@@ -1171,7 +1234,7 @@ ENTRY(kernel_thread_helper)
         * Here we are in the child and the registers are set as they were
         * at kernel_thread() invocation in the parent.
         */
-       call *%rsi
+       CALL_NOSPEC %rsi
        # exit
        mov %eax, %edi
        call do_exit
@@ -1338,7 +1401,7 @@ apicinterrupt XEN_HVM_EVTCHN_CALLBACK \
        .pushsection .kprobes.text, "ax"
 
 paranoidzeroentry_ist debug do_debug DEBUG_STACK
-paranoidzeroentry_ist int3 do_int3 DEBUG_STACK
+zeroentry int3 do_int3
 errorentry stack_segment do_stack_segment
 #ifdef CONFIG_XEN
 zeroentry xen_debug do_debug
@@ -1351,7 +1414,7 @@ errorentry page_fault do_page_fault
 errorentry async_page_fault do_async_page_fault
 #endif
 #ifdef CONFIG_X86_MCE
-paranoidzeroentry machine_check *machine_check_vector(%rip)
+paranoidzeroentry machine_check do_mce
 #endif
 
        /*
@@ -1366,30 +1429,41 @@ paranoidzeroentry machine_check *machine_check_vector(%rip)
         * is fundamentally NMI-unsafe. (we cannot change the soft and
         * hard flags at once, atomically)
         */
-
-       /* ebx: no swapgs flag */
+/*
+ * On entry: ebx=0: needs swapgs but not SWITCH_USER_CR3
+ *           ebx=1: needs neither swapgs nor SWITCH_USER_CR3
+ *           ebx=2: needs both swapgs and SWITCH_USER_CR3
+ *           ebx=3: needs SWITCH_USER_CR3 but not swapgs
+ */
 ENTRY(paranoid_exit)
        DEFAULT_FRAME
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
-       testl %ebx,%ebx                         /* swapgs needed? */
-       jnz paranoid_restore
-       testl $3,CS(%rsp)
-       jnz   paranoid_userspace
-paranoid_swapgs:
+       movq    %rbx, %r12              /* paranoid_userspace uses %ebx */
+       testl   $3, CS(%rsp)
+       jnz     paranoid_userspace
+paranoid_kernel:
+       movq    %r12, %rbx              /* restore after paranoid_userspace */
        TRACE_IRQS_IRETQ 0
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+       /* No ALTERNATIVE for X86_FEATURE_KAISER: save_paranoid sets %ebx */
+       testl   $2, %ebx                /* SWITCH_USER_CR3 needed? */
+       jz      paranoid_exit_no_switch
+       SWITCH_USER_CR3
+paranoid_exit_no_switch:
+#endif
+       testl   $1, %ebx                /* swapgs needed? */
+       jnz     paranoid_exit_no_swapgs
        SWAPGS_UNSAFE_STACK
+paranoid_exit_no_swapgs:
        RESTORE_ALL 8
-       jmp irq_return
-paranoid_restore:
-       TRACE_IRQS_IRETQ 0
-       RESTORE_ALL 8
-       jmp irq_return
+       jmp     irq_return
+
 paranoid_userspace:
        GET_THREAD_INFO(%rcx)
        movl TI_flags(%rcx),%ebx
        andl $_TIF_WORK_MASK,%ebx
-       jz paranoid_swapgs
+       jz paranoid_kernel
        movq %rsp,%rdi                  /* &pt_regs */
        call sync_regs
        movq %rax,%rsp                  /* switch stack for scheduling */
@@ -1438,6 +1512,13 @@ ENTRY(error_entry)
        movq_cfi r13, R13+8
        movq_cfi r14, R14+8
        movq_cfi r15, R15+8
+       /*
+        * error_entry() always returns with a kernel gsbase and
+        * CR3.  We must also have a kernel CR3/gsbase before
+        * calling TRACE_IRQS_*.  Just unconditionally switch to
+        * the kernel CR3 here.
+        */
+       SWITCH_KERNEL_CR3
        xorl %ebx,%ebx
        testl $3,CS+8(%rsp)
        je error_kernelspace
@@ -1527,22 +1608,32 @@ ENTRY(nmi)
        call do_nmi
 #ifdef CONFIG_TRACE_IRQFLAGS
        /* paranoidexit; without TRACE_IRQS_OFF */
-       /* ebx: no swapgs flag */
+       /* ebx: no-swapgs and kaiser-switch-cr3 flag */
        DISABLE_INTERRUPTS(CLBR_NONE)
-       testl %ebx,%ebx                         /* swapgs needed? */
-       jnz nmi_restore
-       testl $3,CS(%rsp)
-       jnz nmi_userspace
-nmi_swapgs:
+       movq    %rbx, %r12              /* nmi_userspace uses %ebx */
+       testl   $3, CS(%rsp)
+       jnz     nmi_userspace
+nmi_kernel:
+       movq    %r12, %rbx              /* restore after nmi_userspace */
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+       /* No ALTERNATIVE for X86_FEATURE_KAISER: save_paranoid sets %ebx */
+       testl   $2, %ebx                /* SWITCH_USER_CR3 needed? */
+       jz      nmi_exit_no_switch
+       SWITCH_USER_CR3
+nmi_exit_no_switch:
+#endif
+       testl   $1, %ebx                /* swapgs needed? */
+       jnz     nmi_exit_no_swapgs
        SWAPGS_UNSAFE_STACK
-nmi_restore:
+nmi_exit_no_swapgs:
        RESTORE_ALL 8
-       jmp irq_return
+       jmp     irq_return
+
 nmi_userspace:
        GET_THREAD_INFO(%rcx)
        movl TI_flags(%rcx),%ebx
        andl $_TIF_WORK_MASK,%ebx
-       jz nmi_swapgs
+       jz nmi_kernel
        movq %rsp,%rdi                  /* &pt_regs */
        call sync_regs
        movq %rax,%rsp                  /* switch stack for scheduling */
index 94d857f..a1944fa 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/pgalloc.h>
 #include <asm/setup.h>
 #include <asm/espfix.h>
+#include <asm/kaiser.h>
 
 /*
  * Note: we only need 6*8 = 48 bytes for the espfix stack, but round
@@ -129,6 +130,15 @@ void __init init_espfix_bsp(void)
        /* Install the espfix pud into the kernel page directory */
        pgd_p = &init_level4_pgt[pgd_index(ESPFIX_BASE_ADDR)];
        pgd_populate(&init_mm, pgd_p, (pud_t *)espfix_pud_page);
+       /*
+        * Just copy the top-level PGD that is mapping the espfix
+        * area to ensure it is mapped into the shadow user page
+        * tables.
+        */
+       if (kaiser_enabled) {
+               set_pgd(native_get_shadow_pgd(pgd_p),
+                       __pgd(_KERNPG_TABLE | __pa((pud_t *)espfix_pud_page)));
+       }
 
        /* Randomize the locations */
        init_espfix_random();
index 0f8ebf7..1de317b 100644 (file)
@@ -166,8 +166,8 @@ ENTRY(secondary_startup_64)
        /* Sanitize CPU configuration */
        call verify_cpu
 
-       /* Enable PAE mode and PGE */
-       movl    $(X86_CR4_PAE | X86_CR4_PGE), %eax
+       /* Enable PAE and PSE, but defer PGE until kaiser_enabled is decided */
+       movl    $(X86_CR4_PAE | X86_CR4_PSE), %eax
        movq    %rax, %cr4
 
        /* Setup early boot stage 4 level pagetables. */
@@ -338,6 +338,27 @@ early_idt_ripmsg:
        .balign PAGE_SIZE; \
 ENTRY(name)
 
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+/*
+ * Each PGD needs to be 8k long and 8k aligned.  We do not
+ * ever go out to userspace with these, so we do not
+ * strictly *need* the second page, but this allows us to
+ * have a single set_pgd() implementation that does not
+ * need to worry about whether it has 4k or 8k to work
+ * with.
+ *
+ * This ensures PGDs are 8k long:
+ */
+#define KAISER_USER_PGD_FILL   512
+/* This ensures they are 8k-aligned: */
+#define NEXT_PGD_PAGE(name) \
+       .balign 2 * PAGE_SIZE; \
+GLOBAL(name)
+#else
+#define NEXT_PGD_PAGE(name) NEXT_PAGE(name)
+#define KAISER_USER_PGD_FILL   0
+#endif
+
 /* Automate the creation of 1 to 1 mapping pmd entries */
 #define PMDS(START, PERM, COUNT)                       \
        i = 0 ;                                         \
@@ -353,13 +374,14 @@ ENTRY(name)
         * 0xffffffff80000000 to physical address 0x000000. (always using
         * 2Mbyte large pages provided by PAE mode)
         */
-NEXT_PAGE(init_level4_pgt)
+NEXT_PGD_PAGE(init_level4_pgt)
        .quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
        .org    init_level4_pgt + L4_PAGE_OFFSET*8, 0
        .quad   level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
        .org    init_level4_pgt + L4_START_KERNEL*8, 0
        /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
        .quad   level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
+       .fill   KAISER_USER_PGD_FILL,8,0
 
 NEXT_PAGE(level3_ident_pgt)
        .quad   level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
@@ -385,6 +407,7 @@ NEXT_PAGE(level2_ident_pgt)
         * Don't set NX because code runs from these pages.
         */
        PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)
+       .fill   KAISER_USER_PGD_FILL,8,0
 
 NEXT_PAGE(level2_kernel_pgt)
        /*
index 4970ef0..02fd03b 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/cpu.h>
 #include <linux/pm.h>
 #include <linux/io.h>
+#include <linux/kaiser.h>
 
 #include <asm/fixmap.h>
 #include <asm/hpet.h>
@@ -74,6 +75,8 @@ static inline void hpet_set_mapping(void)
        hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
 #ifdef CONFIG_X86_64
        __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VVAR_NOCACHE);
+       kaiser_add_mapping(__fix_to_virt(VSYSCALL_HPET), PAGE_SIZE,
+                          __PAGE_KERNEL_VVAR_NOCACHE);
 #endif
 }
 
index 43e9ccf..f00e6e7 100644 (file)
@@ -38,5 +38,5 @@ EXPORT_SYMBOL(init_task);
  * section. Since TSS's are completely CPU-local, we want them
  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
  */
-DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS;
+DEFINE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(struct tss_struct, init_tss) = INIT_TSS;
 
index 7209070..91fc132 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 
 #include <asm/apic.h>
+#include <asm/nospec-branch.h>
 
 DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
 EXPORT_PER_CPU_SYMBOL(irq_stat);
@@ -64,11 +65,11 @@ static DEFINE_PER_CPU(union irq_ctx *, softirq_ctx);
 static void call_on_stack(void *func, void *stack)
 {
        asm volatile("xchgl     %%ebx,%%esp     \n"
-                    "call      *%%edi          \n"
+                    CALL_NOSPEC
                     "movl      %%ebx,%%esp     \n"
                     : "=b" (stack)
                     : "0" (stack),
-                      "D"(func)
+                      [thunk_target] "D"(func)
                     : "memory", "cc", "edx", "ecx", "eax");
 }
 
@@ -107,11 +108,11 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
                call_on_stack(print_stack_overflow, isp);
 
        asm volatile("xchgl     %%ebx,%%esp     \n"
-                    "call      *%%edi          \n"
+                    CALL_NOSPEC
                     "movl      %%ebx,%%esp     \n"
                     : "=a" (arg1), "=d" (arg2), "=b" (isp)
                     :  "0" (irq),   "1" (desc),  "2" (isp),
-                       "D" (desc->handle_irq)
+                       [thunk_target] "D" (desc->handle_irq)
                     : "memory", "cc", "ecx");
        return 1;
 }
index e328f69..990f743 100644 (file)
@@ -85,7 +85,7 @@ static struct irqaction irq2 = {
        .flags = IRQF_NO_THREAD,
 };
 
-DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
+DEFINE_PER_CPU_USER_MAPPED(vector_irq_t, vector_irq) = {
        [0 ... NR_VECTORS - 1] = -1,
 };
 
index 29aed8d..dc5e1bc 100644 (file)
@@ -58,6 +58,7 @@
 #include <asm/alternative.h>
 #include <asm/insn.h>
 #include <asm/debugreg.h>
+#include <asm/nospec-branch.h>
 
 void jprobe_return_end(void);
 
@@ -1256,7 +1257,7 @@ static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src)
 }
 
 /* Check whether insn is indirect jump */
-static int __kprobes insn_is_indirect_jump(struct insn *insn)
+static int __kprobes __insn_is_indirect_jump(struct insn *insn)
 {
        return ((insn->opcode.bytes[0] == 0xff &&
                (X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */
@@ -1290,6 +1291,26 @@ static int insn_jump_into_range(struct insn *insn, unsigned long start, int len)
        return (start <= target && target <= start + len);
 }
 
+static int __kprobes insn_is_indirect_jump(struct insn *insn)
+{
+       int ret = __insn_is_indirect_jump(insn);
+
+#ifdef CONFIG_RETPOLINE
+       /*
+        * Jump to x86_indirect_thunk_* is treated as an indirect jump.
+        * Note that even with CONFIG_RETPOLINE=y, the kernel compiled with
+        * older gcc may use indirect jump. So we add this check instead of
+        * replace indirect-jump check.
+        */
+       if (!ret)
+               ret = insn_jump_into_range(insn,
+                               (unsigned long)__indirect_thunk_start,
+                               (unsigned long)__indirect_thunk_end -
+                               (unsigned long)__indirect_thunk_start);
+#endif
+       return ret;
+}
+
 /* Decode whole function to ensure any instructions don't jump into target */
 static int __kprobes can_optimize(unsigned long paddr)
 {
index 4b6701e..9d1121d 100644 (file)
@@ -91,7 +91,6 @@ struct kvm_task_sleep_node {
        u32 token;
        int cpu;
        bool halted;
-       struct mm_struct *mm;
 };
 
 static struct kvm_task_sleep_head {
@@ -114,7 +113,11 @@ static struct kvm_task_sleep_node *_find_apf_task(struct kvm_task_sleep_head *b,
        return NULL;
 }
 
-void kvm_async_pf_task_wait(u32 token)
+/*
+ * @interrupt_kernel: Is this called from a routine which interrupts the kernel
+ *                   (other than user space)?
+ */
+void kvm_async_pf_task_wait(u32 token, int interrupt_kernel)
 {
        u32 key = hash_32(token, KVM_TASK_SLEEP_HASHBITS);
        struct kvm_task_sleep_head *b = &async_pf_sleepers[key];
@@ -138,9 +141,10 @@ void kvm_async_pf_task_wait(u32 token)
 
        n.token = token;
        n.cpu = smp_processor_id();
-       n.mm = current->active_mm;
-       n.halted = idle || preempt_count() > 1;
-       atomic_inc(&n.mm->mm_count);
+       n.halted = idle ||
+                  (IS_ENABLED(CONFIG_PREEMPT_COUNT)
+                   ? preempt_count() > 1 || rcu_preempt_depth()
+                   : interrupt_kernel);
        init_waitqueue_head(&n.wq);
        hlist_add_head(&n.link, &b->list);
        spin_unlock(&b->lock);
@@ -173,9 +177,6 @@ EXPORT_SYMBOL_GPL(kvm_async_pf_task_wait);
 static void apf_task_wake_one(struct kvm_task_sleep_node *n)
 {
        hlist_del_init(&n->link);
-       if (!n->mm)
-               return;
-       mmdrop(n->mm);
        if (n->halted)
                smp_send_reschedule(n->cpu);
        else if (waitqueue_active(&n->wq))
@@ -219,7 +220,7 @@ again:
                 * async PF was not yet handled.
                 * Add dummy entry for the token.
                 */
-               n = kmalloc(sizeof(*n), GFP_ATOMIC);
+               n = kzalloc(sizeof(*n), GFP_ATOMIC);
                if (!n) {
                        /*
                         * Allocation failed! Busy wait while other cpu
@@ -231,7 +232,6 @@ again:
                }
                n->token = token;
                n->cpu = smp_processor_id();
-               n->mm = NULL;
                init_waitqueue_head(&n->wq);
                hlist_add_head(&n->link, &b->list);
        } else
@@ -263,7 +263,7 @@ do_async_page_fault(struct pt_regs *regs, unsigned long error_code)
                break;
        case KVM_PV_REASON_PAGE_NOT_PRESENT:
                /* page is swapped out by the host. */
-               kvm_async_pf_task_wait((u32)read_cr2());
+               kvm_async_pf_task_wait((u32)read_cr2(), !user_mode_vm(regs));
                break;
        case KVM_PV_REASON_PAGE_READY:
                kvm_async_pf_task_wake((u32)read_cr2());
index 1dd3230..8d4e15f 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/uaccess.h>
+#include <linux/kaiser.h>
 
 #include <asm/system.h>
 #include <asm/ldt.h>
@@ -34,11 +35,21 @@ static void flush_ldt(void *current_mm)
        set_ldt(pc->ldt->entries, pc->ldt->size);
 }
 
+static void __free_ldt_struct(struct ldt_struct *ldt)
+{
+       if (ldt->size * LDT_ENTRY_SIZE > PAGE_SIZE)
+               vfree(ldt->entries);
+       else
+               free_page((unsigned long)ldt->entries);
+       kfree(ldt);
+}
+
 /* The caller must call finalize_ldt_struct on the result. LDT starts zeroed. */
 static struct ldt_struct *alloc_ldt_struct(int size)
 {
        struct ldt_struct *new_ldt;
        int alloc_size;
+       int ret;
 
        if (size > LDT_ENTRIES)
                return NULL;
@@ -59,14 +70,20 @@ static struct ldt_struct *alloc_ldt_struct(int size)
        if (alloc_size > PAGE_SIZE)
                new_ldt->entries = vzalloc(alloc_size);
        else
-               new_ldt->entries = kzalloc(PAGE_SIZE, GFP_KERNEL);
+               new_ldt->entries = (void *)get_zeroed_page(GFP_KERNEL);
 
        if (!new_ldt->entries) {
                kfree(new_ldt);
                return NULL;
        }
 
+       ret = kaiser_add_mapping((unsigned long)new_ldt->entries, alloc_size,
+                                __PAGE_KERNEL);
        new_ldt->size = size;
+       if (ret) {
+               __free_ldt_struct(new_ldt);
+               return NULL;
+       }
        return new_ldt;
 }
 
@@ -97,12 +114,10 @@ static void free_ldt_struct(struct ldt_struct *ldt)
        if (likely(!ldt))
                return;
 
+       kaiser_remove_mapping((unsigned long)ldt->entries,
+                             ldt->size * LDT_ENTRY_SIZE);
        paravirt_free_ldt(ldt->entries, ldt->size);
-       if (ldt->size * LDT_ENTRY_SIZE > PAGE_SIZE)
-               vfree(ldt->entries);
-       else
-               kfree(ldt->entries);
-       kfree(ldt);
+       __free_ldt_struct(ldt);
 }
 
 /*
index a1da673..a91d9b9 100644 (file)
@@ -9,7 +9,6 @@ DEF_NATIVE(pv_irq_ops, save_fl, "pushfq; popq %rax");
 DEF_NATIVE(pv_mmu_ops, read_cr2, "movq %cr2, %rax");
 DEF_NATIVE(pv_mmu_ops, read_cr3, "movq %cr3, %rax");
 DEF_NATIVE(pv_mmu_ops, write_cr3, "movq %rdi, %cr3");
-DEF_NATIVE(pv_mmu_ops, flush_tlb_single, "invlpg (%rdi)");
 DEF_NATIVE(pv_cpu_ops, clts, "clts");
 DEF_NATIVE(pv_cpu_ops, wbinvd, "wbinvd");
 
@@ -57,7 +56,6 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
                PATCH_SITE(pv_mmu_ops, read_cr3);
                PATCH_SITE(pv_mmu_ops, write_cr3);
                PATCH_SITE(pv_cpu_ops, clts);
-               PATCH_SITE(pv_mmu_ops, flush_tlb_single);
                PATCH_SITE(pv_cpu_ops, wbinvd);
 
        patch_site:
index 557eb37..d2ce2a3 100644 (file)
@@ -57,7 +57,7 @@
 
 asmlinkage extern void ret_from_fork(void);
 
-DEFINE_PER_CPU(unsigned long, old_rsp);
+DEFINE_PER_CPU_USER_MAPPED(unsigned long, old_rsp);
 static DEFINE_PER_CPU(unsigned char, is_idle);
 
 static ATOMIC_NOTIFIER_HEAD(idle_notifier);
index a34bddd..04da0bf 100644 (file)
@@ -357,6 +357,12 @@ void machine_real_restart(unsigned int type)
        lowmem_gdt[1] =
                GDT_ENTRY(0x009b, restart_pa, 0xffff);
 
+#ifdef CONFIG_X86_64
+       /* Exiting long mode will fail if CR4.PCIDE is set. */
+       if (static_cpu_has(X86_FEATURE_PCID))
+               clear_in_cr4(X86_CR4_PCIDE);
+#endif
+
        /* Jump to the identity-mapped low memory code */
        restart_lowmem(type);
 }
index b506f41..cb3a585 100644 (file)
 #include <asm/mce.h>
 #include <asm/alternative.h>
 #include <asm/prom.h>
+#include <asm/kaiser.h>
 
 /*
  * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
@@ -921,6 +922,12 @@ void __init setup_arch(char **cmdline_p)
         */
        init_hypervisor_platform();
 
+       /*
+        * This needs to happen right after XENPV is set on xen and
+        * kaiser_enabled is checked below in cleanup_highmap().
+        */
+       kaiser_check_boottime_disable();
+
        x86_init.resources.probe_roms();
 
        /* after parse_early_param, so could debug it */
index bb28f2c..a5591d4 100644 (file)
@@ -689,7 +689,8 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
 
        INIT_WORK_ONSTACK(&c_idle.work, do_fork_idle);
 
-       alternatives_smp_switch(1);
+       /* Just in case we booted with a single CPU. */
+       alternatives_enable_smp();
 
        c_idle.idle = get_idle_for_cpu(cpu);
 
@@ -1109,20 +1110,6 @@ out:
        preempt_enable();
 }
 
-void arch_disable_nonboot_cpus_begin(void)
-{
-       /*
-        * Avoid the smp alternatives switch during the disable_nonboot_cpus().
-        * In the suspend path, we will be back in the SMP mode shortly anyways.
-        */
-       skip_smp_alternatives = true;
-}
-
-void arch_disable_nonboot_cpus_end(void)
-{
-       skip_smp_alternatives = false;
-}
-
 void arch_enable_nonboot_cpus_begin(void)
 {
        set_mtrr_aps_delayed_init();
@@ -1321,9 +1308,6 @@ void native_cpu_die(unsigned int cpu)
                if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
                        if (system_state == SYSTEM_RUNNING)
                                pr_info("CPU %u is now offline\n", cpu);
-
-                       if (1 == num_online_cpus())
-                               alternatives_smp_switch(0);
                        return;
                }
                msleep(100);
index edbd30a..f755bff 100644 (file)
@@ -314,7 +314,6 @@ gp_in_kernel:
        die("general protection fault", regs, error_code);
 }
 
-/* May run on IST stack. */
 dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
 {
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
@@ -718,9 +717,17 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
 /* Set of traps needed for early debugging. */
 void __init early_trap_init(void)
 {
-       set_intr_gate_ist(X86_TRAP_DB, &debug, DEBUG_STACK);
+       /*
+        * Don't set ist to DEBUG_STACK as it doesn't work until TSS is
+        * ready in cpu_init() <-- trap_init(). Before trap_init(), CPU
+        * runs at ring 0 so it is impossible to hit an invalid stack.
+        * Using the original stack works well enough at this early
+        * stage. DEBUG_STACK will be equipped after cpu_init() in
+        * trap_init().
+        */
+       set_intr_gate_ist(X86_TRAP_DB, &debug, 0);
        /* int3 can be called from all */
-       set_system_intr_gate_ist(X86_TRAP_BP, &int3, DEBUG_STACK);
+       set_system_intr_gate_ist(X86_TRAP_BP, &int3, 0);
        set_intr_gate(X86_TRAP_PF, &page_fault);
        load_idt(&idt_descr);
 }
@@ -781,5 +788,12 @@ void __init trap_init(void)
         */
        cpu_init();
 
+       /*
+        * X86_TRAP_DB was installed in early_trap_init(). However,
+        * DEBUG_STACK works only after cpu_init() loads TSS. See comments
+        * in early_trap_init().
+        */
+       set_intr_gate_ist(X86_TRAP_DB, &debug, DEBUG_STACK);
+
        x86_init.irqs.trap_init();
 }
index 0f703f1..84aae84 100644 (file)
@@ -108,6 +108,13 @@ SECTIONS
                IRQENTRY_TEXT
                *(.fixup)
                *(.gnu.warning)
+#ifdef CONFIG_RETPOLINE
+               __indirect_thunk_start = .;
+               *(.text.__x86.indirect_thunk)
+               __indirect_thunk_end = .;
+               __indirect_thunk_size = __indirect_thunk_end - __indirect_thunk_start;
+#endif
+
                /* End of text section */
                _etext = .;
        } :text = 0x9090
index e4d4a22..3178f30 100644 (file)
@@ -58,6 +58,7 @@ DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data) =
 };
 
 static enum { EMULATE, NATIVE, NONE } vsyscall_mode = NATIVE;
+unsigned long vsyscall_pgprot = __PAGE_KERNEL_VSYSCALL;
 
 static int __init vsyscall_setup(char *str)
 {
@@ -274,10 +275,10 @@ void __init map_vsyscall(void)
        extern char __vvar_page;
        unsigned long physaddr_vvar_page = __pa_symbol(&__vvar_page);
 
+       if (vsyscall_mode != NATIVE)
+               vsyscall_pgprot = __PAGE_KERNEL_VVAR;
        __set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_vsyscall,
-                    vsyscall_mode == NATIVE
-                    ? PAGE_KERNEL_VSYSCALL
-                    : PAGE_KERNEL_VVAR);
+                    __pgprot(vsyscall_pgprot));
        BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_FIRST_PAGE) !=
                     (unsigned long)VSYSCALL_START);
 
index 055cc49..264b153 100644 (file)
@@ -1022,7 +1022,7 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
        vcpu->arch.apic_base = value;
        if (apic_x2apic_mode(apic)) {
                u32 id = kvm_apic_id(apic);
-               u32 ldr = ((id & ~0xf) << 16) | (1 << (id & 0xf));
+               u32 ldr = ((id >> 4) << 16) | (1 << (id & 0xf));
                apic_set_reg(apic, APIC_LDR, ldr);
        }
        apic->base_address = apic->vcpu->arch.apic_base &
index ff3535a..3dacb59 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/tlbflush.h>
 #include <asm/desc.h>
 #include <asm/kvm_para.h>
+#include <asm/nospec-branch.h>
 
 #include <asm/virtext.h>
 #include "trace.h"
@@ -1620,7 +1621,7 @@ static int pf_interception(struct vcpu_svm *svm)
        case KVM_PV_REASON_PAGE_NOT_PRESENT:
                svm->apf_reason = 0;
                local_irq_disable();
-               kvm_async_pf_task_wait(fault_address);
+               kvm_async_pf_task_wait(fault_address, 0);
                local_irq_enable();
                break;
        case KVM_PV_REASON_PAGE_READY:
@@ -3040,6 +3041,13 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
        struct vcpu_svm *svm = to_svm(vcpu);
 
        switch (ecx) {
+       case MSR_IA32_CR_PAT:
+               if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data))
+                       return 1;
+               vcpu->arch.pat = data;
+               svm->vmcb->save.g_pat = data;
+               mark_dirty(svm->vmcb, VMCB_NPT);
+               break;
        case MSR_IA32_TSC:
                kvm_write_tsc(vcpu, data);
                break;
@@ -3672,12 +3680,6 @@ static void svm_cancel_injection(struct kvm_vcpu *vcpu)
        svm_complete_interrupts(svm);
 }
 
-#ifdef CONFIG_X86_64
-#define R "r"
-#else
-#define R "e"
-#endif
-
 static void svm_vcpu_run(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -3704,13 +3706,13 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
        local_irq_enable();
 
        asm volatile (
-               "push %%"R"bp; \n\t"
-               "mov %c[rbx](%[svm]), %%"R"bx \n\t"
-               "mov %c[rcx](%[svm]), %%"R"cx \n\t"
-               "mov %c[rdx](%[svm]), %%"R"dx \n\t"
-               "mov %c[rsi](%[svm]), %%"R"si \n\t"
-               "mov %c[rdi](%[svm]), %%"R"di \n\t"
-               "mov %c[rbp](%[svm]), %%"R"bp \n\t"
+               "push %%" _ASM_BP "; \n\t"
+               "mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t"
+               "mov %c[rcx](%[svm]), %%" _ASM_CX " \n\t"
+               "mov %c[rdx](%[svm]), %%" _ASM_DX " \n\t"
+               "mov %c[rsi](%[svm]), %%" _ASM_SI " \n\t"
+               "mov %c[rdi](%[svm]), %%" _ASM_DI " \n\t"
+               "mov %c[rbp](%[svm]), %%" _ASM_BP " \n\t"
 #ifdef CONFIG_X86_64
                "mov %c[r8](%[svm]),  %%r8  \n\t"
                "mov %c[r9](%[svm]),  %%r9  \n\t"
@@ -3723,20 +3725,20 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
 #endif
 
                /* Enter guest mode */
-               "push %%"R"ax \n\t"
-               "mov %c[vmcb](%[svm]), %%"R"ax \n\t"
+               "push %%" _ASM_AX " \n\t"
+               "mov %c[vmcb](%[svm]), %%" _ASM_AX " \n\t"
                __ex(SVM_VMLOAD) "\n\t"
                __ex(SVM_VMRUN) "\n\t"
                __ex(SVM_VMSAVE) "\n\t"
-               "pop %%"R"ax \n\t"
+               "pop %%" _ASM_AX " \n\t"
 
                /* Save guest registers, load host registers */
-               "mov %%"R"bx, %c[rbx](%[svm]) \n\t"
-               "mov %%"R"cx, %c[rcx](%[svm]) \n\t"
-               "mov %%"R"dx, %c[rdx](%[svm]) \n\t"
-               "mov %%"R"si, %c[rsi](%[svm]) \n\t"
-               "mov %%"R"di, %c[rdi](%[svm]) \n\t"
-               "mov %%"R"bp, %c[rbp](%[svm]) \n\t"
+               "mov %%" _ASM_BX ", %c[rbx](%[svm]) \n\t"
+               "mov %%" _ASM_CX ", %c[rcx](%[svm]) \n\t"
+               "mov %%" _ASM_DX ", %c[rdx](%[svm]) \n\t"
+               "mov %%" _ASM_SI ", %c[rsi](%[svm]) \n\t"
+               "mov %%" _ASM_DI ", %c[rdi](%[svm]) \n\t"
+               "mov %%" _ASM_BP ", %c[rbp](%[svm]) \n\t"
 #ifdef CONFIG_X86_64
                "mov %%r8,  %c[r8](%[svm]) \n\t"
                "mov %%r9,  %c[r9](%[svm]) \n\t"
@@ -3747,7 +3749,26 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
                "mov %%r14, %c[r14](%[svm]) \n\t"
                "mov %%r15, %c[r15](%[svm]) \n\t"
 #endif
-               "pop %%"R"bp"
+               /*
+               * Clear host registers marked as clobbered to prevent
+               * speculative use.
+               */
+               "xor %%" _ASM_BX ", %%" _ASM_BX " \n\t"
+               "xor %%" _ASM_CX ", %%" _ASM_CX " \n\t"
+               "xor %%" _ASM_DX ", %%" _ASM_DX " \n\t"
+               "xor %%" _ASM_SI ", %%" _ASM_SI " \n\t"
+               "xor %%" _ASM_DI ", %%" _ASM_DI " \n\t"
+#ifdef CONFIG_X86_64
+               "xor %%r8, %%r8 \n\t"
+               "xor %%r9, %%r9 \n\t"
+               "xor %%r10, %%r10 \n\t"
+               "xor %%r11, %%r11 \n\t"
+               "xor %%r12, %%r12 \n\t"
+               "xor %%r13, %%r13 \n\t"
+               "xor %%r14, %%r14 \n\t"
+               "xor %%r15, %%r15 \n\t"
+#endif
+               "pop %%" _ASM_BP
                :
                : [svm]"a"(svm),
                  [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)),
@@ -3768,12 +3789,17 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
                  [r15]"i"(offsetof(struct vcpu_svm, vcpu.arch.regs[VCPU_REGS_R15]))
 #endif
                : "cc", "memory"
-               , R"bx", R"cx", R"dx", R"si", R"di"
 #ifdef CONFIG_X86_64
+               , "rbx", "rcx", "rdx", "rsi", "rdi"
                , "r8", "r9", "r10", "r11" , "r12", "r13", "r14", "r15"
+#else
+               , "ebx", "ecx", "edx", "esi", "edi"
 #endif
                );
 
+       /* Eliminate branch target predictions from guest mode */
+       vmexit_fill_RSB();
+
 #ifdef CONFIG_X86_64
        wrmsrl(MSR_GS_BASE, svm->host.gs_base);
 #else
@@ -3830,8 +3856,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
        mark_all_clean(svm->vmcb);
 }
 
-#undef R
-
 static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -4079,6 +4103,7 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
                 */
                if (info->rep_prefix != REPE_PREFIX)
                        goto out;
+               break;
        case SVM_EXIT_IOIO: {
                u64 exit_info;
                u32 bytes;
index 0fb33a0..24227a8 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/ftrace_event.h>
 #include <linux/slab.h>
 #include <linux/tboot.h>
+#include <linux/nospec.h>
 #include "kvm_cache_regs.h"
 #include "x86.h"
 
@@ -40,6 +41,7 @@
 #include <asm/i387.h>
 #include <asm/xcr.h>
 #include <asm/perf_event.h>
+#include <asm/nospec-branch.h>
 
 #include "trace.h"
 
@@ -569,13 +571,21 @@ static unsigned short vmcs_field_to_offset_table[] = {
        FIELD(HOST_RSP, host_rsp),
        FIELD(HOST_RIP, host_rip),
 };
-static const int max_vmcs_field = ARRAY_SIZE(vmcs_field_to_offset_table);
 
 static inline short vmcs_field_to_offset(unsigned long field)
 {
-       if (field >= max_vmcs_field || vmcs_field_to_offset_table[field] == 0)
+       const size_t size = ARRAY_SIZE(vmcs_field_to_offset_table);
+       unsigned short offset;
+
+       BUILD_BUG_ON(size > SHRT_MAX);
+       if (field >= size)
+               return -1;
+
+       field = array_index_nospec(field, size);
+       offset = vmcs_field_to_offset_table[field];
+       if (offset == 0)
                return -1;
-       return vmcs_field_to_offset_table[field];
+       return offset;
 }
 
 static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
@@ -2204,6 +2214,8 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
                break;
        case MSR_IA32_CR_PAT:
                if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) {
+                       if (!kvm_mtrr_valid(vcpu, MSR_IA32_CR_PAT, data))
+                               return 1;
                        vmcs_write64(GUEST_IA32_PAT, data);
                        vcpu->arch.pat = data;
                        break;
@@ -6118,14 +6130,6 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
                                        msrs[i].host);
 }
 
-#ifdef CONFIG_X86_64
-#define R "r"
-#define Q "q"
-#else
-#define R "e"
-#define Q "l"
-#endif
-
 static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -6179,30 +6183,30 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
        vmx->__launched = vmx->loaded_vmcs->launched;
        asm(
                /* Store host registers */
-               "push %%"R"dx; push %%"R"bp;"
-               "push %%"R"cx \n\t" /* placeholder for guest rcx */
-               "push %%"R"cx \n\t"
-               "cmp %%"R"sp, %c[host_rsp](%0) \n\t"
+               "push %%" _ASM_DX "; push %%" _ASM_BP ";"
+               "push %%" _ASM_CX " \n\t" /* placeholder for guest rcx */
+               "push %%" _ASM_CX " \n\t"
+               "cmp %%" _ASM_SP ", %c[host_rsp](%0) \n\t"
                "je 1f \n\t"
-               "mov %%"R"sp, %c[host_rsp](%0) \n\t"
+               "mov %%" _ASM_SP ", %c[host_rsp](%0) \n\t"
                __ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t"
                "1: \n\t"
                /* Reload cr2 if changed */
-               "mov %c[cr2](%0), %%"R"ax \n\t"
-               "mov %%cr2, %%"R"dx \n\t"
-               "cmp %%"R"ax, %%"R"dx \n\t"
+               "mov %c[cr2](%0), %%" _ASM_AX " \n\t"
+               "mov %%cr2, %%" _ASM_DX " \n\t"
+               "cmp %%" _ASM_AX ", %%" _ASM_DX " \n\t"
                "je 2f \n\t"
-               "mov %%"R"ax, %%cr2 \n\t"
+               "mov %%" _ASM_AX", %%cr2 \n\t"
                "2: \n\t"
                /* Check if vmlaunch of vmresume is needed */
                "cmpl $0, %c[launched](%0) \n\t"
                /* Load guest registers.  Don't clobber flags. */
-               "mov %c[rax](%0), %%"R"ax \n\t"
-               "mov %c[rbx](%0), %%"R"bx \n\t"
-               "mov %c[rdx](%0), %%"R"dx \n\t"
-               "mov %c[rsi](%0), %%"R"si \n\t"
-               "mov %c[rdi](%0), %%"R"di \n\t"
-               "mov %c[rbp](%0), %%"R"bp \n\t"
+               "mov %c[rax](%0), %%" _ASM_AX " \n\t"
+               "mov %c[rbx](%0), %%" _ASM_BX " \n\t"
+               "mov %c[rdx](%0), %%" _ASM_DX " \n\t"
+               "mov %c[rsi](%0), %%" _ASM_SI " \n\t"
+               "mov %c[rdi](%0), %%" _ASM_DI " \n\t"
+               "mov %c[rbp](%0), %%" _ASM_BP " \n\t"
 #ifdef CONFIG_X86_64
                "mov %c[r8](%0),  %%r8  \n\t"
                "mov %c[r9](%0),  %%r9  \n\t"
@@ -6213,7 +6217,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
                "mov %c[r14](%0), %%r14 \n\t"
                "mov %c[r15](%0), %%r15 \n\t"
 #endif
-               "mov %c[rcx](%0), %%"R"cx \n\t" /* kills %0 (ecx) */
+               "mov %c[rcx](%0), %%" _ASM_CX " \n\t" /* kills %0 (ecx) */
 
                /* Enter guest mode */
                "jne .Llaunched \n\t"
@@ -6222,15 +6226,16 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
                ".Llaunched: " __ex(ASM_VMX_VMRESUME) "\n\t"
                ".Lkvm_vmx_return: "
                /* Save guest registers, load host registers, keep flags */
-               "mov %0, %c[wordsize](%%"R"sp) \n\t"
+               "mov %0, %c[wordsize](%%" _ASM_SP ") \n\t"
                "pop %0 \n\t"
-               "mov %%"R"ax, %c[rax](%0) \n\t"
-               "mov %%"R"bx, %c[rbx](%0) \n\t"
-               "pop"Q" %c[rcx](%0) \n\t"
-               "mov %%"R"dx, %c[rdx](%0) \n\t"
-               "mov %%"R"si, %c[rsi](%0) \n\t"
-               "mov %%"R"di, %c[rdi](%0) \n\t"
-               "mov %%"R"bp, %c[rbp](%0) \n\t"
+               "setbe %c[fail](%0)\n\t"
+               "mov %%" _ASM_AX ", %c[rax](%0) \n\t"
+               "mov %%" _ASM_BX ", %c[rbx](%0) \n\t"
+               __ASM_SIZE(pop) " %c[rcx](%0) \n\t"
+               "mov %%" _ASM_DX ", %c[rdx](%0) \n\t"
+               "mov %%" _ASM_SI ", %c[rsi](%0) \n\t"
+               "mov %%" _ASM_DI ", %c[rdi](%0) \n\t"
+               "mov %%" _ASM_BP ", %c[rbp](%0) \n\t"
 #ifdef CONFIG_X86_64
                "mov %%r8,  %c[r8](%0) \n\t"
                "mov %%r9,  %c[r9](%0) \n\t"
@@ -6240,12 +6245,23 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
                "mov %%r13, %c[r13](%0) \n\t"
                "mov %%r14, %c[r14](%0) \n\t"
                "mov %%r15, %c[r15](%0) \n\t"
+               "xor %%r8d,  %%r8d \n\t"
+               "xor %%r9d,  %%r9d \n\t"
+               "xor %%r10d, %%r10d \n\t"
+               "xor %%r11d, %%r11d \n\t"
+               "xor %%r12d, %%r12d \n\t"
+               "xor %%r13d, %%r13d \n\t"
+               "xor %%r14d, %%r14d \n\t"
+               "xor %%r15d, %%r15d \n\t"
 #endif
-               "mov %%cr2, %%"R"ax   \n\t"
-               "mov %%"R"ax, %c[cr2](%0) \n\t"
-
-               "pop  %%"R"bp; pop  %%"R"dx \n\t"
-               "setbe %c[fail](%0) \n\t"
+               "mov %%cr2, %%" _ASM_AX "   \n\t"
+               "mov %%" _ASM_AX ", %c[cr2](%0) \n\t"
+
+               "xor %%eax, %%eax \n\t"
+               "xor %%ebx, %%ebx \n\t"
+               "xor %%esi, %%esi \n\t"
+               "xor %%edi, %%edi \n\t"
+               "pop  %%" _ASM_BP "; pop  %%" _ASM_DX " \n\t"
              : : "c"(vmx), "d"((unsigned long)HOST_RSP),
                [launched]"i"(offsetof(struct vcpu_vmx, __launched)),
                [fail]"i"(offsetof(struct vcpu_vmx, fail)),
@@ -6270,12 +6286,17 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
                [cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2)),
                [wordsize]"i"(sizeof(ulong))
              : "cc", "memory"
-               , R"ax", R"bx", R"di", R"si"
 #ifdef CONFIG_X86_64
+               , "rax", "rbx", "rdi", "rsi"
                , "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+#else
+               , "eax", "ebx", "edi", "esi"
 #endif
              );
 
+       /* Eliminate branch target predictions from guest mode */
+       vmexit_fill_RSB();
+
        vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP)
                                  | (1 << VCPU_EXREG_RFLAGS)
                                  | (1 << VCPU_EXREG_CPL)
@@ -6308,9 +6329,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
        vmx_complete_interrupts(vmx);
 }
 
-#undef R
-#undef Q
-
 static void vmx_load_vmcs01(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -6671,6 +6689,14 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
        exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING;
        exec_control &= ~CPU_BASED_TPR_SHADOW;
        exec_control |= vmcs12->cpu_based_vm_exec_control;
+
+       if (!(exec_control & CPU_BASED_TPR_SHADOW)) {
+#ifdef CONFIG_X86_64
+               exec_control |= CPU_BASED_CR8_LOAD_EXITING |
+                               CPU_BASED_CR8_STORE_EXITING;
+#endif
+       }
+
        /*
         * Merging of IO and MSR bitmaps not currently supported.
         * Rather, exit every time.
@@ -7047,7 +7073,7 @@ void load_vmcs12_host_state(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
         * (KVM doesn't change it)- no reason to call set_cr4_guest_host_mask();
         */
        vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK);
-       kvm_set_cr4(vcpu, vmcs12->host_cr4);
+       vmx_set_cr4(vcpu, vmcs12->host_cr4);
 
        /* shadow page tables on either EPT or shadow page tables */
        kvm_set_cr3(vcpu, vmcs12->host_cr3);
@@ -7068,6 +7094,8 @@ void load_vmcs12_host_state(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
        vmcs_writel(GUEST_SYSENTER_EIP, vmcs12->host_ia32_sysenter_eip);
        vmcs_writel(GUEST_IDTR_BASE, vmcs12->host_idtr_base);
        vmcs_writel(GUEST_GDTR_BASE, vmcs12->host_gdtr_base);
+       vmcs_write32(GUEST_IDTR_LIMIT, 0xFFFF);
+       vmcs_write32(GUEST_GDTR_LIMIT, 0xFFFF);
        vmcs_writel(GUEST_TR_BASE, vmcs12->host_tr_base);
        vmcs_writel(GUEST_GS_BASE, vmcs12->host_gs_base);
        vmcs_writel(GUEST_FS_BASE, vmcs12->host_fs_base);
@@ -7277,12 +7305,7 @@ static int __init vmx_init(void)
                goto out2;
        }
 
-       /*
-        * Allow direct access to the PC debug port (it is often used for I/O
-        * delays, but the vmexits simply slow things down).
-        */
        memset(vmx_io_bitmap_a, 0xff, PAGE_SIZE);
-       clear_bit(0x80, vmx_io_bitmap_a);
 
        memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE);
 
index c8c3c39..42cc537 100644 (file)
@@ -1274,7 +1274,7 @@ static bool valid_mtrr_type(unsigned t)
        return t < 8 && (1 << t) & 0x73; /* 0, 1, 4, 5, 6 */
 }
 
-static bool mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data)
+bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 {
        int i;
 
@@ -1300,12 +1300,13 @@ static bool mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data)
        /* variable MTRRs */
        return valid_mtrr_type(data & 0xff);
 }
+EXPORT_SYMBOL_GPL(kvm_mtrr_valid);
 
 static int set_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 {
        u64 *p = (u64 *)&vcpu->arch.mtrr_state.fixed_ranges;
 
-       if (!mtrr_valid(vcpu, msr, data))
+       if (!kvm_mtrr_valid(vcpu, msr, data))
                return 1;
 
        if (msr == MSR_MTRRdefType) {
@@ -3920,7 +3921,7 @@ static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
                      !kvm_iodevice_read(&vcpu->arch.apic->dev, addr, n, v))
                    && kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, addr, n, v))
                        break;
-               trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, *(u64 *)v);
+               trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, v);
                handled += n;
                addr += n;
                len -= n;
@@ -4152,7 +4153,7 @@ static int read_prepare(struct kvm_vcpu *vcpu, void *val, int bytes)
        if (vcpu->mmio_read_completed) {
                memcpy(val, vcpu->mmio_data, bytes);
                trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes,
-                              vcpu->mmio_phys_addr, *(u64 *)val);
+                              vcpu->mmio_phys_addr, val);
                vcpu->mmio_read_completed = 0;
                return 1;
        }
@@ -4174,14 +4175,14 @@ static int write_emulate(struct kvm_vcpu *vcpu, gpa_t gpa,
 
 static int write_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes, void *val)
 {
-       trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, *(u64 *)val);
+       trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, val);
        return vcpu_mmio_write(vcpu, gpa, bytes, val);
 }
 
 static int read_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa,
                          void *val, int bytes)
 {
-       trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0);
+       trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, NULL);
        return X86EMUL_IO_NEEDED;
 }
 
@@ -4887,10 +4888,14 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu)
        return r;
 }
 
-static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva)
+static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva,
+                                 int emulation_type)
 {
        gpa_t gpa;
 
+       if (emulation_type & EMULTYPE_NO_REEXECUTE)
+               return false;
+
        if (tdp_enabled)
                return false;
 
@@ -4941,7 +4946,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
                if (r != EMULATION_OK)  {
                        if (emulation_type & EMULTYPE_TRAP_UD)
                                return EMULATE_FAIL;
-                       if (reexecute_instruction(vcpu, cr2))
+                       if (reexecute_instruction(vcpu, cr2, emulation_type))
                                return EMULATE_DONE;
                        if (emulation_type & EMULTYPE_SKIP)
                                return EMULATE_FAIL;
@@ -4968,7 +4973,7 @@ restart:
                return EMULATE_DONE;
 
        if (r == EMULATION_FAILED) {
-               if (reexecute_instruction(vcpu, cr2))
+               if (reexecute_instruction(vcpu, cr2, emulation_type))
                        return EMULATE_DONE;
 
                return handle_emulation_failure(vcpu);
@@ -6072,7 +6077,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 #endif
 
        kvm_rip_write(vcpu, regs->rip);
-       kvm_set_rflags(vcpu, regs->rflags);
+       kvm_set_rflags(vcpu, regs->rflags | 0x2 /*X86_EFLAGS_FIXED*/);
 
        vcpu->arch.exception.pending = false;
 
@@ -6167,6 +6172,29 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
 }
 EXPORT_SYMBOL_GPL(kvm_task_switch);
 
+int kvm_valid_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+{
+       if ((sregs->efer & EFER_LME) && (sregs->cr0 & X86_CR0_PG)) {
+               /*
+                * When EFER.LME and CR0.PG are set, the processor is in
+                * 64-bit mode (though maybe in a 32-bit code segment).
+                * CR4.PAE and EFER.LMA must be set.
+                */
+               if (!(sregs->cr4 & X86_CR4_PAE)
+                   || !(sregs->efer & EFER_LMA))
+                       return -EINVAL;
+       } else {
+               /*
+                * Not in 64-bit mode: EFER.LMA is clear and the code
+                * segment cannot be 64-bit.
+                */
+               if (sregs->efer & EFER_LMA || sregs->cs.l)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
                                  struct kvm_sregs *sregs)
 {
@@ -6177,6 +6205,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
        if (!guest_cpuid_has_xsave(vcpu) && (sregs->cr4 & X86_CR4_OSXSAVE))
                return -EINVAL;
 
+       if (kvm_valid_sregs(vcpu, sregs))
+               return -EINVAL;
+
        dt.size = sregs->idt.limit;
        dt.address = sregs->idt.base;
        kvm_x86_ops->set_idt(vcpu, &dt);
@@ -6885,6 +6916,13 @@ static int apf_put_user(struct kvm_vcpu *vcpu, u32 val)
                                      sizeof(val));
 }
 
+static int apf_get_user(struct kvm_vcpu *vcpu, u32 *val)
+{
+
+       return kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.apf.data, val,
+                                     sizeof(u32));
+}
+
 void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
                                     struct kvm_async_pf *work)
 {
@@ -6911,6 +6949,7 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
                                 struct kvm_async_pf *work)
 {
        struct x86_exception fault;
+       u32 val;
 
        trace_kvm_async_pf_ready(work->arch.token, work->gva);
        if (is_error_page(work->page))
@@ -6918,14 +6957,24 @@ void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
        else
                kvm_del_async_pf_gfn(vcpu, work->arch.gfn);
 
-       if ((vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED) &&
-           !apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) {
-               fault.vector = PF_VECTOR;
-               fault.error_code_valid = true;
-               fault.error_code = 0;
-               fault.nested_page_fault = false;
-               fault.address = work->arch.token;
-               kvm_inject_page_fault(vcpu, &fault);
+       if (vcpu->arch.apf.msr_val & KVM_ASYNC_PF_ENABLED &&
+           !apf_get_user(vcpu, &val)) {
+               if (val == KVM_PV_REASON_PAGE_NOT_PRESENT &&
+                   vcpu->arch.exception.pending &&
+                   vcpu->arch.exception.nr == PF_VECTOR &&
+                   !apf_put_user(vcpu, 0)) {
+                       vcpu->arch.exception.pending = false;
+                       vcpu->arch.exception.nr = 0;
+                       vcpu->arch.exception.has_error_code = false;
+                       vcpu->arch.exception.error_code = 0;
+               } else if (!apf_put_user(vcpu, KVM_PV_REASON_PAGE_READY)) {
+                       fault.vector = PF_VECTOR;
+                       fault.error_code_valid = true;
+                       fault.error_code = 0;
+                       fault.nested_page_fault = false;
+                       fault.address = work->arch.token;
+                       kvm_inject_page_fault(vcpu, &fault);
+               }
        }
        vcpu->arch.apf.halted = false;
 }
index 6c3c94f..10eb765 100644 (file)
@@ -135,6 +135,8 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
        gva_t addr, void *val, unsigned int bytes,
        struct x86_exception *exception);
 
+bool kvm_mtrr_valid(struct kvm_vcpu *vcpu, u32 msr, u64 data);
+
 extern unsigned int min_timer_period_us;
 
 #endif
index b00f678..bd1dcf5 100644 (file)
@@ -16,13 +16,15 @@ clean-files := inat-tables.c
 
 obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o
 
-lib-y := delay.o
+lib-y := delay.o cmdline.o
 lib-y += thunk_$(BITS).o
 lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
 lib-y += memcpy_$(BITS).o
 lib-$(CONFIG_SMP) += rwlock.o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
+lib-$(CONFIG_RETPOLINE) += retpoline.o
+obj-$(CONFIG_RETPOLINE) += retpoline-export.o
 
 obj-y += msr.o msr-reg.o msr-reg-export.o
 
index 78d16a5..6122c6f 100644 (file)
@@ -28,7 +28,8 @@
 #include <linux/linkage.h>
 #include <asm/dwarf2.h>
 #include <asm/errno.h>
-                               
+#include <asm/nospec-branch.h>
+
 /*
  * computes a partial checksum, e.g. for TCP/UDP fragments
  */
@@ -164,7 +165,7 @@ ENTRY(csum_partial)
        negl %ebx
        lea 45f(%ebx,%ebx,2), %ebx
        testl %esi, %esi
-       jmp *%ebx
+       JMP_NOSPEC %ebx
 
        # Handle 2-byte-aligned regions
 20:    addw (%esi), %ax
@@ -466,7 +467,7 @@ ENTRY(csum_partial_copy_generic)
        andl $-32,%edx
        lea 3f(%ebx,%ebx), %ebx
        testl %esi, %esi 
-       jmp *%ebx
+       JMP_NOSPEC %ebx
 1:     addl $64,%esi
        addl $64,%edi 
        SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl)
index f2145cf..38e57fa 100644 (file)
@@ -67,7 +67,7 @@ ENDPROC(clear_page)
        .previous
        .section .altinstructions,"a"
        altinstruction_entry clear_page,1b,X86_FEATURE_REP_GOOD,\
-                            .Lclear_page_end-clear_page, 2b-1b
+                            .Lclear_page_end-clear_page, 2b-1b, 0
        altinstruction_entry clear_page,2b,X86_FEATURE_ERMS,   \
-                            .Lclear_page_end-clear_page,3b-2b
+                            .Lclear_page_end-clear_page,3b-2b, 0
        .previous
diff --git a/arch/x86/lib/cmdline.c b/arch/x86/lib/cmdline.c
new file mode 100644 (file)
index 0000000..3261abb
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * Misc librarized functions for cmdline poking.
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <asm/setup.h>
+
+static inline int myisspace(u8 c)
+{
+       return c <= ' ';        /* Close enough approximation */
+}
+
+/**
+ * Find a boolean option (like quiet,noapic,nosmp....)
+ *
+ * @cmdline: the cmdline string
+ * @option: option string to look for
+ *
+ * Returns the position of that @option (starts counting with 1)
+ * or 0 on not found.  @option will only be found if it is found
+ * as an entire word in @cmdline.  For instance, if @option="car"
+ * then a cmdline which contains "cart" will not match.
+ */
+static int
+__cmdline_find_option_bool(const char *cmdline, int max_cmdline_size,
+                          const char *option)
+{
+       char c;
+       int pos = 0, wstart = 0;
+       const char *opptr = NULL;
+       enum {
+               st_wordstart = 0,       /* Start of word/after whitespace */
+               st_wordcmp,     /* Comparing this word */
+               st_wordskip,    /* Miscompare, skip */
+       } state = st_wordstart;
+
+       if (!cmdline)
+               return -1;      /* No command line */
+
+       /*
+        * This 'pos' check ensures we do not overrun
+        * a non-NULL-terminated 'cmdline'
+        */
+       while (pos < max_cmdline_size) {
+               c = *(char *)cmdline++;
+               pos++;
+
+               switch (state) {
+               case st_wordstart:
+                       if (!c)
+                               return 0;
+                       else if (myisspace(c))
+                               break;
+
+                       state = st_wordcmp;
+                       opptr = option;
+                       wstart = pos;
+                       /* fall through */
+
+               case st_wordcmp:
+                       if (!*opptr) {
+                               /*
+                                * We matched all the way to the end of the
+                                * option we were looking for.  If the
+                                * command-line has a space _or_ ends, then
+                                * we matched!
+                                */
+                               if (!c || myisspace(c))
+                                       return wstart;
+                               /*
+                                * We hit the end of the option, but _not_
+                                * the end of a word on the cmdline.  Not
+                                * a match.
+                                */
+                       } else if (!c) {
+                               /*
+                                * Hit the NULL terminator on the end of
+                                * cmdline.
+                                */
+                               return 0;
+                       } else if (c == *opptr++) {
+                               /*
+                                * We are currently matching, so continue
+                                * to the next character on the cmdline.
+                                */
+                               break;
+                       }
+                       state = st_wordskip;
+                       /* fall through */
+
+               case st_wordskip:
+                       if (!c)
+                               return 0;
+                       else if (myisspace(c))
+                               state = st_wordstart;
+                       break;
+               }
+       }
+
+       return 0;       /* Buffer overrun */
+}
+
+/*
+ * Find a non-boolean option (i.e. option=argument). In accordance with
+ * standard Linux practice, if this option is repeated, this returns the
+ * last instance on the command line.
+ *
+ * @cmdline: the cmdline string
+ * @max_cmdline_size: the maximum size of cmdline
+ * @option: option string to look for
+ * @buffer: memory buffer to return the option argument
+ * @bufsize: size of the supplied memory buffer
+ *
+ * Returns the length of the argument (regardless of if it was
+ * truncated to fit in the buffer), or -1 on not found.
+ */
+static int
+__cmdline_find_option(const char *cmdline, int max_cmdline_size,
+                     const char *option, char *buffer, int bufsize)
+{
+       char c;
+       int pos = 0, len = -1;
+       const char *opptr = NULL;
+       char *bufptr = buffer;
+       enum {
+               st_wordstart = 0,       /* Start of word/after whitespace */
+               st_wordcmp,     /* Comparing this word */
+               st_wordskip,    /* Miscompare, skip */
+               st_bufcpy,      /* Copying this to buffer */
+       } state = st_wordstart;
+
+       if (!cmdline)
+               return -1;      /* No command line */
+
+       /*
+        * This 'pos' check ensures we do not overrun
+        * a non-NULL-terminated 'cmdline'
+        */
+       while (pos++ < max_cmdline_size) {
+               c = *(char *)cmdline++;
+               if (!c)
+                       break;
+
+               switch (state) {
+               case st_wordstart:
+                       if (myisspace(c))
+                               break;
+
+                       state = st_wordcmp;
+                       opptr = option;
+                       /* fall through */
+
+               case st_wordcmp:
+                       if ((c == '=') && !*opptr) {
+                               /*
+                                * We matched all the way to the end of the
+                                * option we were looking for, prepare to
+                                * copy the argument.
+                                */
+                               len = 0;
+                               bufptr = buffer;
+                               state = st_bufcpy;
+                               break;
+                       } else if (c == *opptr++) {
+                               /*
+                                * We are currently matching, so continue
+                                * to the next character on the cmdline.
+                                */
+                               break;
+                       }
+                       state = st_wordskip;
+                       /* fall through */
+
+               case st_wordskip:
+                       if (myisspace(c))
+                               state = st_wordstart;
+                       break;
+
+               case st_bufcpy:
+                       if (myisspace(c)) {
+                               state = st_wordstart;
+                       } else {
+                               /*
+                                * Increment len, but don't overrun the
+                                * supplied buffer and leave room for the
+                                * NULL terminator.
+                                */
+                               if (++len < bufsize)
+                                       *bufptr++ = c;
+                       }
+                       break;
+               }
+       }
+
+       if (bufsize)
+               *bufptr = '\0';
+
+       return len;
+}
+
+int cmdline_find_option_bool(const char *cmdline, const char *option)
+{
+       return __cmdline_find_option_bool(cmdline, COMMAND_LINE_SIZE, option);
+}
+
+int cmdline_find_option(const char *cmdline, const char *option, char *buffer,
+                       int bufsize)
+{
+       return __cmdline_find_option(cmdline, COMMAND_LINE_SIZE, option,
+                                    buffer, bufsize);
+}
index 01c805b..8f1917e 100644 (file)
@@ -112,5 +112,5 @@ ENDPROC(copy_page)
        .previous
        .section .altinstructions,"a"
        altinstruction_entry copy_page, 1b, X86_FEATURE_REP_GOOD,       \
-               .Lcopy_page_end-copy_page, 2b-1b
+               .Lcopy_page_end-copy_page, 2b-1b, 0
        .previous
index 0248402..18b0059 100644 (file)
  */
        .macro ALTERNATIVE_JUMP feature1,feature2,orig,alt1,alt2
 0:
-       .byte 0xe9      /* 32bit jump */
-       .long \orig-1f  /* by default jump to orig */
+       jmp \orig
 1:
        .section .altinstr_replacement,"ax"
-2:     .byte 0xe9                      /* near jump with 32bit immediate */
-       .long \alt1-1b /* offset */   /* or alternatively to alt1 */
-3:     .byte 0xe9                      /* near jump with 32bit immediate */
-       .long \alt2-1b /* offset */   /* or alternatively to alt2 */
+2:
+       jmp \alt1
+3:
+       jmp \alt2
        .previous
 
        .section .altinstructions,"a"
-       altinstruction_entry 0b,2b,\feature1,5,5
-       altinstruction_entry 0b,3b,\feature2,5,5
+       altinstruction_entry 0b,2b,\feature1,5,5,0
+       altinstruction_entry 0b,3b,\feature2,5,5,0
        .previous
        .endm
 
index 51f1504..559f676 100644 (file)
@@ -40,6 +40,8 @@ ENTRY(__get_user_1)
        GET_THREAD_INFO(%_ASM_DX)
        cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
        jae bad_get_user
+       sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
+       and %_ASM_DX, %_ASM_AX
 1:     movzb (%_ASM_AX),%edx
        xor %eax,%eax
        ret
@@ -53,6 +55,8 @@ ENTRY(__get_user_2)
        GET_THREAD_INFO(%_ASM_DX)
        cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
        jae bad_get_user
+       sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
+       and %_ASM_DX, %_ASM_AX
 2:     movzwl -1(%_ASM_AX),%edx
        xor %eax,%eax
        ret
@@ -66,6 +70,8 @@ ENTRY(__get_user_4)
        GET_THREAD_INFO(%_ASM_DX)
        cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
        jae bad_get_user
+       sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
+       and %_ASM_DX, %_ASM_AX
 3:     mov -3(%_ASM_AX),%edx
        xor %eax,%eax
        ret
@@ -80,6 +86,8 @@ ENTRY(__get_user_8)
        GET_THREAD_INFO(%_ASM_DX)
        cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
        jae     bad_get_user
+       sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
+       and %_ASM_DX, %_ASM_AX
 4:     movq -7(%_ASM_AX),%_ASM_DX
        xor %eax,%eax
        ret
index efbf2a0..6c32ff9 100644 (file)
@@ -203,8 +203,8 @@ ENDPROC(__memcpy)
         * only outcome...
         */
        .section .altinstructions, "a"
-       altinstruction_entry memcpy,.Lmemcpy_c,X86_FEATURE_REP_GOOD,\
-                            .Lmemcpy_e-.Lmemcpy_c,.Lmemcpy_e-.Lmemcpy_c
-       altinstruction_entry memcpy,.Lmemcpy_c_e,X86_FEATURE_ERMS, \
-                            .Lmemcpy_e_e-.Lmemcpy_c_e,.Lmemcpy_e_e-.Lmemcpy_c_e
+       altinstruction_entry __memcpy,.Lmemcpy_c,X86_FEATURE_REP_GOOD,\
+                            .Lmemcpy_e-.Lmemcpy_c,.Lmemcpy_e-.Lmemcpy_c,0
+       altinstruction_entry __memcpy,.Lmemcpy_c_e,X86_FEATURE_ERMS, \
+                            .Lmemcpy_e_e-.Lmemcpy_c_e,.Lmemcpy_e_e-.Lmemcpy_c_e,0
        .previous
index ee16461..f8f64ce 100644 (file)
@@ -218,6 +218,6 @@ ENTRY(memmove)
        altinstruction_entry .Lmemmove_begin_forward,           \
                .Lmemmove_begin_forward_efs,X86_FEATURE_ERMS,   \
                .Lmemmove_end_forward-.Lmemmove_begin_forward,  \
-               .Lmemmove_end_forward_efs-.Lmemmove_begin_forward_efs
+               .Lmemmove_end_forward_efs-.Lmemmove_begin_forward_efs,0
        .previous
 ENDPROC(memmove)
index 79bd454..ea830ff 100644 (file)
@@ -150,8 +150,8 @@ ENDPROC(__memset)
          * feature to implement the right patch order.
         */
        .section .altinstructions,"a"
-       altinstruction_entry memset,.Lmemset_c,X86_FEATURE_REP_GOOD,\
-                            .Lfinal-memset,.Lmemset_e-.Lmemset_c
-       altinstruction_entry memset,.Lmemset_c_e,X86_FEATURE_ERMS, \
-                            .Lfinal-memset,.Lmemset_e_e-.Lmemset_c_e
+       altinstruction_entry __memset,.Lmemset_c,X86_FEATURE_REP_GOOD,\
+                            .Lfinal-__memset,.Lmemset_e-.Lmemset_c,0
+       altinstruction_entry __memset,.Lmemset_c_e,X86_FEATURE_ERMS, \
+                            .Lfinal-__memset,.Lmemset_e_e-.Lmemset_c_e,0
        .previous
index 8f8eebd..ec07174 100644 (file)
@@ -8,7 +8,7 @@ struct msr *msrs_alloc(void)
 
        msrs = alloc_percpu(struct msr);
        if (!msrs) {
-               pr_warning("%s: error allocating msrs\n", __func__);
+               pr_warn("%s: error allocating msrs\n", __func__);
                return NULL;
        }
 
@@ -21,3 +21,90 @@ void msrs_free(struct msr *msrs)
        free_percpu(msrs);
 }
 EXPORT_SYMBOL(msrs_free);
+
+/**
+ * Read an MSR with error handling
+ *
+ * @msr: MSR to read
+ * @m: value to read into
+ *
+ * It returns read data only on success, otherwise it doesn't change the output
+ * argument @m.
+ *
+ */
+int msr_read(u32 msr, struct msr *m)
+{
+       int err;
+       u64 val;
+
+       err = rdmsrl_safe(msr, &val);
+       if (!err)
+               m->q = val;
+
+       return err;
+}
+
+/**
+ * Write an MSR with error handling
+ *
+ * @msr: MSR to write
+ * @m: value to write
+ */
+int msr_write(u32 msr, struct msr *m)
+{
+       return checking_wrmsrl(msr, m->q);
+}
+
+static inline int __flip_bit(u32 msr, u8 bit, bool set)
+{
+       struct msr m, m1;
+       int err = -EINVAL;
+
+       if (bit > 63)
+               return err;
+
+       err = msr_read(msr, &m);
+       if (err)
+               return err;
+
+       m1 = m;
+       if (set)
+               m1.q |=  BIT_64(bit);
+       else
+               m1.q &= ~BIT_64(bit);
+
+       if (m1.q == m.q)
+               return 0;
+
+       err = msr_write(msr, &m);
+       if (err)
+               return err;
+
+       return 1;
+}
+
+/**
+ * Set @bit in a MSR @msr.
+ *
+ * Retval:
+ * < 0: An error was encountered.
+ * = 0: Bit was already set.
+ * > 0: Hardware accepted the MSR write.
+ */
+int msr_set_bit(u32 msr, u8 bit)
+{
+       return __flip_bit(msr, bit, true);
+}
+
+/**
+ * Clear @bit in a MSR @msr.
+ *
+ * Retval:
+ * < 0: An error was encountered.
+ * = 0: Bit was already cleared.
+ * > 0: Hardware accepted the MSR write.
+ */
+int msr_clear_bit(u32 msr, u8 bit)
+{
+       return __flip_bit(msr, bit, false);
+}
diff --git a/arch/x86/lib/retpoline-export.c b/arch/x86/lib/retpoline-export.c
new file mode 100644 (file)
index 0000000..a17f17f
--- /dev/null
@@ -0,0 +1,25 @@
+#include <linux/export.h>
+#include <linux/linkage.h>
+
+#ifdef CONFIG_RETPOLINE
+#ifdef CONFIG_X86_32
+#define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_e ## reg(void); EXPORT_SYMBOL(__x86_indirect_thunk_e ## reg);
+#else
+#define INDIRECT_THUNK(reg) extern asmlinkage void __x86_indirect_thunk_r ## reg(void); EXPORT_SYMBOL(__x86_indirect_thunk_r ## reg);
+INDIRECT_THUNK(8)
+INDIRECT_THUNK(9)
+INDIRECT_THUNK(10)
+INDIRECT_THUNK(11)
+INDIRECT_THUNK(12)
+INDIRECT_THUNK(13)
+INDIRECT_THUNK(14)
+INDIRECT_THUNK(15)
+#endif
+INDIRECT_THUNK(ax)
+INDIRECT_THUNK(bx)
+INDIRECT_THUNK(cx)
+INDIRECT_THUNK(dx)
+INDIRECT_THUNK(si)
+INDIRECT_THUNK(di)
+INDIRECT_THUNK(bp)
+#endif /* CONFIG_RETPOLINE */
diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S
new file mode 100644 (file)
index 0000000..5242a3b
--- /dev/null
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/stringify.h>
+#include <linux/linkage.h>
+#include <asm/dwarf2.h>
+#include <asm/cpufeature.h>
+#include <asm/alternative-asm.h>
+#include <asm/nospec-branch.h>
+
+.macro THUNK reg
+       .section .text.__x86.indirect_thunk
+
+ENTRY(__x86_indirect_thunk_\reg)
+       CFI_STARTPROC
+       JMP_NOSPEC %\reg
+       CFI_ENDPROC
+ENDPROC(__x86_indirect_thunk_\reg)
+.endm
+
+/*
+ * Despite being an assembler file we can't just use .irp here
+ * because __KSYM_DEPS__ only uses the C preprocessor and would
+ * only see one instance of "__x86_indirect_thunk_\reg" rather
+ * than one per register with the correct names. So we do it
+ * the simple and nasty way...
+ */
+#define GENERATE_THUNK(reg) THUNK reg
+
+GENERATE_THUNK(_ASM_AX)
+GENERATE_THUNK(_ASM_BX)
+GENERATE_THUNK(_ASM_CX)
+GENERATE_THUNK(_ASM_DX)
+GENERATE_THUNK(_ASM_SI)
+GENERATE_THUNK(_ASM_DI)
+GENERATE_THUNK(_ASM_BP)
+#ifdef CONFIG_64BIT
+GENERATE_THUNK(r8)
+GENERATE_THUNK(r9)
+GENERATE_THUNK(r10)
+GENERATE_THUNK(r11)
+GENERATE_THUNK(r12)
+GENERATE_THUNK(r13)
+GENERATE_THUNK(r14)
+GENERATE_THUNK(r15)
+#endif
index e218d5d..0462f65 100644 (file)
@@ -774,6 +774,7 @@ survive:
                return n;
        }
 #endif
+       barrier_nospec();
        if (movsl_is_ok(to, from, n))
                __copy_user(to, from, n);
        else
@@ -785,6 +786,7 @@ EXPORT_SYMBOL(__copy_to_user_ll);
 unsigned long __copy_from_user_ll(void *to, const void __user *from,
                                        unsigned long n)
 {
+       barrier_nospec();
        if (movsl_is_ok(to, from, n))
                __copy_user_zeroing(to, from, n);
        else
@@ -796,6 +798,7 @@ EXPORT_SYMBOL(__copy_from_user_ll);
 unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from,
                                         unsigned long n)
 {
+       barrier_nospec();
        if (movsl_is_ok(to, from, n))
                __copy_user(to, from, n);
        else
@@ -808,6 +811,7 @@ EXPORT_SYMBOL(__copy_from_user_ll_nozero);
 unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
                                        unsigned long n)
 {
+       barrier_nospec();
 #ifdef CONFIG_X86_INTEL_USERCOPY
        if (n > 64 && cpu_has_xmm2)
                n = __copy_user_zeroing_intel_nocache(to, from, n);
@@ -823,6 +827,7 @@ EXPORT_SYMBOL(__copy_from_user_ll_nocache);
 unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
                                        unsigned long n)
 {
+       barrier_nospec();
 #ifdef CONFIG_X86_INTEL_USERCOPY
        if (n > 64 && cpu_has_xmm2)
                n = __copy_user_intel_nocache(to, from, n);
index a793da5..d9cc829 100644 (file)
@@ -759,7 +759,7 @@ EndTable
 
 GrpTable: Grp3_1
 0: TEST Eb,Ib
-1:
+1: TEST Eb,Ib
 2: NOT Eb
 3: NEG Eb
 4: MUL AL,Eb
index 3d11327..08505d2 100644 (file)
@@ -1,5 +1,5 @@
 obj-y  :=  init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \
-           pat.o pgtable.o physaddr.o gup.o setup_nx.o
+           pat.o pgtable.o physaddr.o gup.o setup_nx.o tlb.o
 
 # Make sure __phys_addr has no stackprotector
 nostackp := $(call cc-option, -fno-stack-protector)
@@ -7,7 +7,6 @@ CFLAGS_physaddr.o               := $(nostackp)
 CFLAGS_setup_nx.o              := $(nostackp)
 
 obj-$(CONFIG_X86_PAT)          += pat_rbtree.o
-obj-$(CONFIG_SMP)              += tlb.o
 
 obj-$(CONFIG_X86_32)           += pgtable_32.o iomap_32.o
 
@@ -30,3 +29,4 @@ obj-$(CONFIG_NUMA_EMU)                += numa_emulation.o
 obj-$(CONFIG_HAVE_MEMBLOCK)            += memblock.o
 
 obj-$(CONFIG_MEMTEST)          += memtest.o
+obj-$(CONFIG_PAGE_TABLE_ISOLATION)             += kaiser.o
index dba71b2..f897b97 100644 (file)
@@ -161,7 +161,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
                set_in_cr4(X86_CR4_PSE);
 
        /* Enable PGE if available */
-       if (cpu_has_pge) {
+       if (cpu_has_pge && !kaiser_enabled) {
                set_in_cr4(X86_CR4_PGE);
                __supported_pte_mask |= _PAGE_GLOBAL;
        }
index 44b93da..1f1b8ed 100644 (file)
@@ -312,6 +312,16 @@ void __init cleanup_highmap(void)
                        continue;
                if (vaddr < (unsigned long) _text || vaddr > end)
                        set_pmd(pmd, __pmd(0));
+               else if (kaiser_enabled) {
+                       /*
+                        * level2_kernel_pgt is initialized with _PAGE_GLOBAL:
+                        * clear that now.  This is not important, so long as
+                        * CR4.PGE remains clear, but it removes an anomaly.
+                        * Physical mapping setup below avoids _PAGE_GLOBAL
+                        * by use of massage_pgprot() inside pfn_pte() etc.
+                        */
+                       set_pmd(pmd, pmd_clear_flags(*pmd, _PAGE_GLOBAL));
+               }
        }
 }
 
diff --git a/arch/x86/mm/kaiser.c b/arch/x86/mm/kaiser.c
new file mode 100644 (file)
index 0000000..b6c645e
--- /dev/null
@@ -0,0 +1,455 @@
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/ftrace.h>
+#include <xen/xen.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "Kernel/User page tables isolation: " fmt
+
+extern struct mm_struct init_mm;
+
+#include <asm/kaiser.h>
+#include <asm/tlbflush.h>      /* to verify its kaiser declarations */
+#include <asm/vsyscall.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/desc.h>
+#include <asm/cmdline.h>
+
+int kaiser_enabled __read_mostly = 1;
+EXPORT_SYMBOL(kaiser_enabled); /* for inlined TLB flush functions */
+
+DEFINE_PER_CPU_USER_MAPPED(unsigned long, unsafe_stack_register_backup);
+
+/*
+ * These can have bit 63 set, so we can not just use a plain "or"
+ * instruction to get their value or'd into CR3.  It would take
+ * another register.  So, we use a memory reference to these instead.
+ *
+ * This is also handy because systems that do not support PCIDs
+ * just end up or'ing a 0 into their CR3, which does no harm.
+ */
+DEFINE_PER_CPU(unsigned long, x86_cr3_pcid_user);
+
+/*
+ * At runtime, the only things we map are some things for CPU
+ * hotplug, and stacks for new processes.  No two CPUs will ever
+ * be populating the same addresses, so we only need to ensure
+ * that we protect between two CPUs trying to allocate and
+ * populate the same page table page.
+ *
+ * Only take this lock when doing a set_p[4um]d(), but it is not
+ * needed for doing a set_pte().  We assume that only the *owner*
+ * of a given allocation will be doing this for _their_
+ * allocation.
+ *
+ * This ensures that once a system has been running for a while
+ * and there have been stacks all over and these page tables
+ * are fully populated, there will be no further acquisitions of
+ * this lock.
+ */
+static DEFINE_SPINLOCK(shadow_table_allocation_lock);
+
+/*
+ * Returns -1 on error.
+ */
+static inline unsigned long get_pa_from_mapping(unsigned long vaddr)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       pgd = pgd_offset_k(vaddr);
+       /*
+        * We made all the kernel PGDs present in kaiser_init().
+        * We expect them to stay that way.
+        */
+       BUG_ON(pgd_none(*pgd));
+       /*
+        * PGDs are either 512GB or 128TB on all x86_64
+        * configurations.  We don't handle these.
+        */
+       BUG_ON(pgd_large(*pgd));
+
+       pud = pud_offset(pgd, vaddr);
+       if (pud_none(*pud)) {
+               WARN_ON_ONCE(1);
+               return -1;
+       }
+
+       if (pud_large(*pud))
+               return (pud_pfn(*pud) << PAGE_SHIFT) | (vaddr & ~PUD_PAGE_MASK);
+
+       pmd = pmd_offset(pud, vaddr);
+       if (pmd_none(*pmd)) {
+               WARN_ON_ONCE(1);
+               return -1;
+       }
+
+       if (pmd_large(*pmd))
+               return (pmd_pfn(*pmd) << PAGE_SHIFT) | (vaddr & ~PMD_PAGE_MASK);
+
+       pte = pte_offset_kernel(pmd, vaddr);
+       if (pte_none(*pte)) {
+               WARN_ON_ONCE(1);
+               return -1;
+       }
+
+       return (pte_pfn(*pte) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);
+}
+
+/*
+ * This is a relatively normal page table walk, except that it
+ * also tries to allocate page tables pages along the way.
+ *
+ * Returns a pointer to a PTE on success, or NULL on failure.
+ */
+static pte_t *kaiser_pagetable_walk(unsigned long address)
+{
+       pmd_t *pmd;
+       pud_t *pud;
+       pgd_t *pgd = native_get_shadow_pgd(pgd_offset_k(address));
+       gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO);
+
+       if (pgd_none(*pgd)) {
+               WARN_ONCE(1, "All shadow pgds should have been populated");
+               return NULL;
+       }
+       BUILD_BUG_ON(pgd_large(*pgd) != 0);
+
+       pud = pud_offset(pgd, address);
+       /* The shadow page tables do not use large mappings: */
+       if (pud_large(*pud)) {
+               WARN_ON(1);
+               return NULL;
+       }
+       if (pud_none(*pud)) {
+               unsigned long new_pmd_page = __get_free_page(gfp);
+               if (!new_pmd_page)
+                       return NULL;
+               spin_lock(&shadow_table_allocation_lock);
+               if (pud_none(*pud)) {
+                       set_pud(pud, __pud(_PAGE_TABLE | __pa(new_pmd_page)));
+                       __inc_zone_page_state(virt_to_page((void *)
+                                               new_pmd_page), NR_KAISERTABLE);
+               } else
+                       free_page(new_pmd_page);
+               spin_unlock(&shadow_table_allocation_lock);
+       }
+
+       pmd = pmd_offset(pud, address);
+       /* The shadow page tables do not use large mappings: */
+       if (pmd_large(*pmd)) {
+               WARN_ON(1);
+               return NULL;
+       }
+       if (pmd_none(*pmd)) {
+               unsigned long new_pte_page = __get_free_page(gfp);
+               if (!new_pte_page)
+                       return NULL;
+               spin_lock(&shadow_table_allocation_lock);
+               if (pmd_none(*pmd)) {
+                       set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(new_pte_page)));
+                       __inc_zone_page_state(virt_to_page((void *)
+                                               new_pte_page), NR_KAISERTABLE);
+               } else
+                       free_page(new_pte_page);
+               spin_unlock(&shadow_table_allocation_lock);
+       }
+
+       return pte_offset_kernel(pmd, address);
+}
+
+static int kaiser_add_user_map(const void *__start_addr, unsigned long size,
+                              unsigned long flags)
+{
+       int ret = 0;
+       pte_t *pte;
+       unsigned long start_addr = (unsigned long )__start_addr;
+       unsigned long address = start_addr & PAGE_MASK;
+       unsigned long end_addr = PAGE_ALIGN(start_addr + size);
+       unsigned long target_address;
+
+       /*
+        * It is convenient for callers to pass in __PAGE_KERNEL etc,
+        * and there is no actual harm from setting _PAGE_GLOBAL, so
+        * long as CR4.PGE is not set.  But it is nonetheless troubling
+        * to see Kaiser itself setting _PAGE_GLOBAL (now that "nokaiser"
+        * requires that not to be #defined to 0): so mask it off here.
+        */
+       flags &= ~_PAGE_GLOBAL;
+       if (!(__supported_pte_mask & _PAGE_NX))
+               flags &= ~_PAGE_NX;
+
+       if (flags & _PAGE_USER)
+               BUG_ON(address < FIXADDR_START || end_addr >= FIXADDR_TOP);
+
+       for (; address < end_addr; address += PAGE_SIZE) {
+               target_address = get_pa_from_mapping(address);
+               if (target_address == -1) {
+                       ret = -EIO;
+                       break;
+               }
+               pte = kaiser_pagetable_walk(address);
+               if (!pte) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               if (pte_none(*pte)) {
+                       set_pte(pte, __pte(flags | target_address));
+               } else {
+                       pte_t tmp;
+                       set_pte(&tmp, __pte(flags | target_address));
+                       WARN_ON_ONCE(!pte_same(*pte, tmp));
+               }
+       }
+       return ret;
+}
+
+static int kaiser_add_user_map_ptrs(const void *start, const void *end, unsigned long flags)
+{
+       unsigned long size = end - start;
+
+       return kaiser_add_user_map(start, size, flags);
+}
+
+/*
+ * Ensure that the top level of the (shadow) page tables are
+ * entirely populated.  This ensures that all processes that get
+ * forked have the same entries.  This way, we do not have to
+ * ever go set up new entries in older processes.
+ *
+ * Note: we never free these, so there are no updates to them
+ * after this.
+ */
+static void __init kaiser_init_all_pgds(void)
+{
+       pgd_t *pgd;
+       int i = 0;
+
+       pgd = native_get_shadow_pgd(pgd_offset_k((unsigned long )0));
+       for (i = PTRS_PER_PGD / 2; i < PTRS_PER_PGD; i++) {
+               pgd_t new_pgd;
+               pud_t *pud = pud_alloc_one(&init_mm,
+                                          PAGE_OFFSET + i * PGDIR_SIZE);
+               if (!pud) {
+                       WARN_ON(1);
+                       break;
+               }
+               inc_zone_page_state(virt_to_page(pud), NR_KAISERTABLE);
+               new_pgd = __pgd(_PAGE_TABLE |__pa(pud));
+               /*
+                * Make sure not to stomp on some other pgd entry.
+                */
+               if (!pgd_none(pgd[i])) {
+                       WARN_ON(1);
+                       continue;
+               }
+               set_pgd(pgd + i, new_pgd);
+       }
+}
+
+#define kaiser_add_user_map_early(start, size, flags) do {     \
+       int __ret = kaiser_add_user_map(start, size, flags);    \
+       WARN_ON(__ret);                                         \
+} while (0)
+
+#define kaiser_add_user_map_ptrs_early(start, end, flags) do {         \
+       int __ret = kaiser_add_user_map_ptrs(start, end, flags);        \
+       WARN_ON(__ret);                                                 \
+} while (0)
+
+void __init kaiser_check_boottime_disable(void)
+{
+       bool enable = true;
+       char arg[5];
+       int ret;
+
+       if (xen_pv_domain())
+               goto silent_disable;
+
+       ret = cmdline_find_option(boot_command_line, "pti", arg, sizeof(arg));
+       if (ret > 0) {
+               if (!strncmp(arg, "on", 2))
+                       goto enable;
+
+               if (!strncmp(arg, "off", 3))
+                       goto disable;
+
+               if (!strncmp(arg, "auto", 4))
+                       goto skip;
+       }
+
+       if (cmdline_find_option_bool(boot_command_line, "nopti"))
+               goto disable;
+
+skip:
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+               goto disable;
+
+enable:
+       if (enable)
+               setup_force_cpu_cap(X86_FEATURE_KAISER);
+
+       return;
+
+disable:
+       pr_info("disabled\n");
+
+silent_disable:
+       kaiser_enabled = 0;
+       setup_clear_cpu_cap(X86_FEATURE_KAISER);
+}
+
+/*
+ * If anything in here fails, we will likely die on one of the
+ * first kernel->user transitions and init will die.  But, we
+ * will have most of the kernel up by then and should be able to
+ * get a clean warning out of it.  If we BUG_ON() here, we run
+ * the risk of being before we have good console output.
+ */
+void __init kaiser_init(void)
+{
+       int cpu;
+
+       if (!kaiser_enabled)
+               return;
+
+       kaiser_init_all_pgds();
+
+       for_each_possible_cpu(cpu) {
+               void *percpu_vaddr = __per_cpu_user_mapped_start +
+                                    per_cpu_offset(cpu);
+               unsigned long percpu_sz = __per_cpu_user_mapped_end -
+                                         __per_cpu_user_mapped_start;
+               kaiser_add_user_map_early(percpu_vaddr, percpu_sz,
+                                         __PAGE_KERNEL);
+       }
+
+       /*
+        * Map the entry/exit text section, which is needed at
+        * switches from user to and from kernel.
+        */
+       kaiser_add_user_map_ptrs_early(__entry_text_start, __entry_text_end,
+                                      __PAGE_KERNEL_RX);
+       kaiser_add_user_map_ptrs_early(__kprobes_text_start, __kprobes_text_end,
+                                      __PAGE_KERNEL_RX);
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       kaiser_add_user_map_ptrs_early(__irqentry_text_start,
+                                      __irqentry_text_end,
+                                      __PAGE_KERNEL_RX);
+#endif
+       kaiser_add_user_map_early((void *)idt_descr.address,
+                                 sizeof(gate_desc) * NR_VECTORS,
+                                 __PAGE_KERNEL_RO);
+       kaiser_add_user_map_early((void *)VVAR_ADDRESS, PAGE_SIZE,
+                                 __PAGE_KERNEL_VVAR);
+       kaiser_add_user_map_early((void *)VSYSCALL_START, PAGE_SIZE,
+                                 vsyscall_pgprot);
+
+       pr_info("enabled\n");
+}
+
+/* Add a mapping to the shadow mapping, and synchronize the mappings */
+int kaiser_add_mapping(unsigned long addr, unsigned long size, unsigned long flags)
+{
+       if (!kaiser_enabled)
+               return 0;
+       return kaiser_add_user_map((const void *)addr, size, flags);
+}
+
+void kaiser_remove_mapping(unsigned long start, unsigned long size)
+{
+       unsigned long end = start + size;
+       unsigned long addr;
+       pte_t *pte;
+
+       if (!kaiser_enabled)
+               return;
+       for (addr = start; addr < end; addr += PAGE_SIZE) {
+               pte = kaiser_pagetable_walk(addr);
+               if (pte)
+                       set_pte(pte, __pte(0));
+       }
+}
+
+/*
+ * Page table pages are page-aligned.  The lower half of the top
+ * level is used for userspace and the top half for the kernel.
+ * This returns true for user pages that need to get copied into
+ * both the user and kernel copies of the page tables, and false
+ * for kernel pages that should only be in the kernel copy.
+ */
+static inline bool is_userspace_pgd(pgd_t *pgdp)
+{
+       return ((unsigned long)pgdp % PAGE_SIZE) < (PAGE_SIZE / 2);
+}
+
+pgd_t kaiser_set_shadow_pgd(pgd_t *pgdp, pgd_t pgd)
+{
+       if (!kaiser_enabled)
+               return pgd;
+       /*
+        * Do we need to also populate the shadow pgd?  Check _PAGE_USER to
+        * skip cases like kexec and EFI which make temporary low mappings.
+        */
+       if (pgd.pgd & _PAGE_USER) {
+               if (is_userspace_pgd(pgdp)) {
+                       native_get_shadow_pgd(pgdp)->pgd = pgd.pgd;
+                       /*
+                        * Even if the entry is *mapping* userspace, ensure
+                        * that userspace can not use it.  This way, if we
+                        * get out to userspace running on the kernel CR3,
+                        * userspace will crash instead of running.
+                        */
+                       if (__supported_pte_mask & _PAGE_NX)
+                               pgd.pgd |= _PAGE_NX;
+               }
+       } else if (!pgd.pgd) {
+               /*
+                * pgd_clear() cannot check _PAGE_USER, and is even used to
+                * clear corrupted pgd entries: so just rely on cases like
+                * kexec and EFI never to be using pgd_clear().
+                */
+               if (!WARN_ON_ONCE((unsigned long)pgdp & PAGE_SIZE) &&
+                   is_userspace_pgd(pgdp))
+                       native_get_shadow_pgd(pgdp)->pgd = pgd.pgd;
+       }
+       return pgd;
+}
+
+void kaiser_setup_pcid(void)
+{
+       unsigned long user_cr3 = KAISER_SHADOW_PGD_OFFSET;
+
+       if (this_cpu_has(X86_FEATURE_PCID))
+               user_cr3 |= X86_CR3_PCID_USER_NOFLUSH;
+       /*
+        * These variables are used by the entry/exit
+        * code to change PCID and pgd and TLB flushing.
+        */
+       this_cpu_write(x86_cr3_pcid_user, user_cr3);
+}
+
+/*
+ * Make a note that this cpu will need to flush USER tlb on return to user.
+ * If cpu does not have PCID, then the NOFLUSH bit will never have been set.
+ */
+void kaiser_flush_tlb_on_return_to_user(void)
+{
+       if (this_cpu_has(X86_FEATURE_PCID))
+               this_cpu_write(x86_cr3_pcid_user,
+                       X86_CR3_PCID_USER_FLUSH | KAISER_SHADOW_PGD_OFFSET);
+}
+EXPORT_SYMBOL(kaiser_flush_tlb_on_return_to_user);
index 8573b83..0b246ef 100644 (file)
@@ -5,7 +5,7 @@
 #include <asm/tlb.h>
 #include <asm/fixmap.h>
 
-#define PGALLOC_GFP GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO
+#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
 
 #ifdef CONFIG_HIGHPTE
 #define PGALLOC_USER_GFP __GFP_HIGHMEM
@@ -253,12 +253,31 @@ static void pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmds[])
        }
 }
 
+/*
+ * Instead of one pgd, Kaiser acquires two pgds.  Being order-1, it is
+ * both 8k in size and 8k-aligned.  That lets us just flip bit 12
+ * in a pointer to swap between the two 4k halves.
+ */
+#define PGD_ALLOCATION_ORDER   kaiser_enabled
+
+static inline pgd_t *_pgd_alloc(void)
+{
+       /* No __GFP_REPEAT: to avoid page allocation stalls in order-1 case */
+       return (pgd_t *)__get_free_pages(PGALLOC_GFP & ~__GFP_REPEAT,
+                                        PGD_ALLOCATION_ORDER);
+}
+
+static inline void _pgd_free(pgd_t *pgd)
+{
+       free_pages((unsigned long)pgd, PGD_ALLOCATION_ORDER);
+}
+
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
        pgd_t *pgd;
        pmd_t *pmds[PREALLOCATED_PMDS];
 
-       pgd = (pgd_t *)__get_free_page(PGALLOC_GFP);
+       pgd = _pgd_alloc();
 
        if (pgd == NULL)
                goto out;
@@ -288,7 +307,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
 out_free_pmds:
        free_pmds(pmds);
 out_free_pgd:
-       free_page((unsigned long)pgd);
+       _pgd_free(pgd);
 out:
        return NULL;
 }
@@ -298,7 +317,7 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
        pgd_mop_up_pmds(mm, pgd);
        pgd_dtor(pgd);
        paravirt_pgd_free(mm, pgd);
-       free_page((unsigned long)pgd);
+       _pgd_free(pgd);
 }
 
 int ptep_set_access_flags(struct vm_area_struct *vma,
index 55034a1..5e1536b 100644 (file)
 #include <asm/cache.h>
 #include <asm/apic.h>
 #include <asm/uv/uv.h>
+#include <asm/kaiser.h>
 
 DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate)
                        = { &init_mm, 0, };
 
+static void load_new_mm_cr3(pgd_t *pgdir)
+{
+       unsigned long new_mm_cr3 = __pa(pgdir);
+
+       if (kaiser_enabled) {
+               /*
+                * We reuse the same PCID for different tasks, so we must
+                * flush all the entries for the PCID out when we change tasks.
+                * Flush KERN below, flush USER when returning to userspace in
+                * kaiser's SWITCH_USER_CR3 (_SWITCH_TO_USER_CR3) macro.
+                *
+                * invpcid_flush_single_context(X86_CR3_PCID_ASID_USER) could
+                * do it here, but can only be used if X86_FEATURE_INVPCID is
+                * available - and many machines support pcid without invpcid.
+                *
+                * If X86_CR3_PCID_KERN_FLUSH actually added something, then it
+                * would be needed in the write_cr3() below - if PCIDs enabled.
+                */
+               BUILD_BUG_ON(X86_CR3_PCID_KERN_FLUSH);
+               kaiser_flush_tlb_on_return_to_user();
+       }
+
+       /*
+        * Caution: many callers of this function expect
+        * that load_new_mm_cr3() is serializing and orders TLB
+        * fills with respect to the mm_cpumask writes.
+        */
+       write_cr3(new_mm_cr3);
+}
+
 /*
- *     Smarter SMP flushing macros.
+ *     TLB flushing, formerly SMP-only
  *             c/o Linus Torvalds.
  *
  *     These mean you can really definitely utterly forget about
@@ -65,10 +96,85 @@ void leave_mm(int cpu)
                BUG();
        cpumask_clear_cpu(cpu,
                          mm_cpumask(percpu_read(cpu_tlbstate.active_mm)));
-       load_cr3(swapper_pg_dir);
+       load_new_mm_cr3(swapper_pg_dir);
 }
 EXPORT_SYMBOL_GPL(leave_mm);
 
+void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+              struct task_struct *tsk)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       switch_mm_irqs_off(prev, next, tsk);
+       local_irq_restore(flags);
+}
+
+void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
+                       struct task_struct *tsk)
+{
+       unsigned cpu = smp_processor_id();
+
+       if (likely(prev != next)) {
+               percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
+               percpu_write(cpu_tlbstate.active_mm, next);
+               cpumask_set_cpu(cpu, mm_cpumask(next));
+
+               /*
+                * Re-load page tables.
+                *
+                * This logic has an ordering constraint:
+                *
+                *  CPU 0: Write to a PTE for 'next'
+                *  CPU 0: load bit 1 in mm_cpumask.  if nonzero, send IPI.
+                *  CPU 1: set bit 1 in next's mm_cpumask
+                *  CPU 1: load from the PTE that CPU 0 writes (implicit)
+                *
+                * We need to prevent an outcome in which CPU 1 observes
+                * the new PTE value and CPU 0 observes bit 1 clear in
+                * mm_cpumask.  (If that occurs, then the IPI will never
+                * be sent, and CPU 0's TLB will contain a stale entry.)
+                *
+                * The bad outcome can occur if either CPU's load is
+                * reordered before that CPU's store, so both CPUs must
+                * execute full barriers to prevent this from happening.
+                *
+                * Thus, switch_mm needs a full barrier between the
+                * store to mm_cpumask and any operation that could load
+                * from next->pgd.  TLB fills are special and can happen
+                * due to instruction fetches or for no reason at all,
+                * and neither LOCK nor MFENCE orders them.
+                * Fortunately, load_new_mm_cr3() is serializing
+                * and gives the  ordering guarantee we need.
+                */
+               load_new_mm_cr3(next->pgd);
+
+               /* stop flush ipis for the previous mm */
+               cpumask_clear_cpu(cpu, mm_cpumask(prev));
+
+               /*
+                * load the LDT, if the LDT is different:
+                */
+               if (unlikely(prev->context.ldt != next->context.ldt))
+                       load_mm_ldt(next);
+       } else {
+               percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
+               BUG_ON(percpu_read(cpu_tlbstate.active_mm) != next);
+
+               if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next))) {
+                       /* We were in lazy tlb mode and leave_mm disabled
+                        * tlb flush IPI delivery. We must reload CR3
+                        * to make sure to use no freed page tables.
+                        *
+                        * As above, load_new_mm_cr3() is serializing and orders
+                        * TLB fills with respect to the mm_cpumask write.
+                        */
+                       load_new_mm_cr3(next->pgd);
+                       load_mm_ldt(next);
+               }
+       }
+}
+
 /*
  *
  * The flush IPI assumes that a thread switch happens in this order:
@@ -172,6 +278,7 @@ out:
 static void flush_tlb_others_ipi(const struct cpumask *cpumask,
                                 struct mm_struct *mm, unsigned long va)
 {
+#ifdef CONFIG_SMP
        unsigned int sender;
        union smp_flush_state *f;
 
@@ -200,6 +307,7 @@ static void flush_tlb_others_ipi(const struct cpumask *cpumask,
        f->flush_va = 0;
        if (nr_cpu_ids > NUM_INVALIDATE_TLB_VECTORS)
                raw_spin_unlock(&f->tlbstate_lock);
+#endif
 }
 
 void native_flush_tlb_others(const struct cpumask *cpumask,
index d90528e..12c051d 100644 (file)
@@ -212,8 +212,8 @@ static void arch_perfmon_setup_counters(void)
        eax.full = cpuid_eax(0xa);
 
        /* Workaround for BIOS bugs in 6/15. Taken from perfmon2 */
-       if (eax.split.version_id == 0 && __this_cpu_read(cpu_info.x86) == 6 &&
-               __this_cpu_read(cpu_info.x86_model) == 15) {
+       if (eax.split.version_id == 0 && boot_cpu_data.x86 == 6 &&
+           boot_cpu_data.x86_model == 15) {
                eax.split.version_id = 2;
                eax.split.num_counters = 2;
                eax.split.bit_width = 40;
index 38eaf74..2c7daef 100644 (file)
@@ -540,15 +540,53 @@ static void __devinit twinhead_reserve_killing_zone(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x27B9, twinhead_reserve_killing_zone);
 
 /*
- * Broadwell EP Home Agent BARs erroneously return non-zero values when read.
+ * Device [8086:2fc0]
+ * Erratum HSE43
+ * CONFIG_TDP_NOMINAL CSR Implemented at Incorrect Offset
+ * http://www.intel.com/content/www/us/en/processors/xeon/xeon-e5-v3-spec-update.html
  *
- * See http://www.intel.com/content/www/us/en/processors/xeon/xeon-e5-v4-spec-update.html
- * entry BDF2.
+ * Devices [8086:6f60,6fa0,6fc0]
+ * Erratum BDF2
+ * PCI BARs in the Home Agent Will Return Non-Zero Values During Enumeration
+ * http://www.intel.com/content/www/us/en/processors/xeon/xeon-e5-v4-spec-update.html
  */
-static void pci_bdwep_bar(struct pci_dev *dev)
+static void pci_invalid_bar(struct pci_dev *dev)
 {
        dev->non_compliant_bars = 1;
 }
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_bdwep_bar);
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_bdwep_bar);
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_bdwep_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2fc0, pci_invalid_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_invalid_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_invalid_bar);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_invalid_bar);
+
+/*
+ * Apple MacBook Pro: Avoid [mem 0x7fa00000-0x7fbfffff]
+ *
+ * Using the [mem 0x7fa00000-0x7fbfffff] region, e.g., by assigning it to
+ * the 00:1c.0 Root Port, causes a conflict with [io 0x1804], which is used
+ * for soft poweroff and suspend-to-RAM.
+ *
+ * As far as we know, this is related to the address space, not to the Root
+ * Port itself.  Attaching the quirk to the Root Port is a convenience, but
+ * it could probably also be a standalone DMI quirk.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=103211
+ */
+static void quirk_apple_mbp_poweroff(struct pci_dev *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+
+       if ((!dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,4") &&
+            !dmi_match(DMI_PRODUCT_NAME, "MacBookPro11,5")) ||
+           pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x1c, 0))
+               return;
+
+       res = request_mem_region(0x7fa00000, 0x200000,
+                                "MacBook Pro poweroff workaround");
+       if (res)
+               dev_info(dev, "claimed %s %pR\n", res->name, res);
+       else
+               dev_info(dev, "can't work around MacBook Pro poweroff issue\n");
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x8c10, quirk_apple_mbp_poweroff);
index b255312..4cfb125 100644 (file)
@@ -270,6 +270,12 @@ static void __init xen_init_cpuid_mask(void)
                  (1 << X86_FEATURE_MTRR) |  /* disable MTRR */
                  (1 << X86_FEATURE_ACC));   /* thermal monitoring */
 
+       /*
+        * Xen PV would need some work to support PCID: CR3 handling as well
+        * as xen_flush_tlb_others() would need updating.
+        */
+       cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_PCID % 32));  /* disable PCID */
+
        if (!xen_initial_domain())
                cpuid_leaf1_edx_mask &=
                        ~((1 << X86_FEATURE_APIC) |  /* disable local APIC */
index 6e4d5dc..a8991d4 100644 (file)
@@ -368,7 +368,8 @@ static int __cpuinit xen_cpu_up(unsigned int cpu)
                return rc;
 
        if (num_online_cpus() == 1)
-               alternatives_smp_switch(1);
+               /* Just in case we booted with a single CPU. */
+               alternatives_enable_smp();
 
        rc = xen_smp_intr_init(cpu);
        if (rc)
@@ -414,9 +415,6 @@ static void xen_cpu_die(unsigned int cpu)
        unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
        xen_uninit_lock_cpu(cpu);
        xen_teardown_timer(cpu);
-
-       if (num_online_cpus() == 1)
-               alternatives_smp_switch(0);
 }
 
 static void __cpuinit xen_play_dead(void) /* used only with HOTPLUG_CPU */
index 2783fda..2d9cc6d 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/gfp.h>
+#include <linux/module.h>
 #include <asm/io.h>
 #include <asm/cacheflush.h>
 
@@ -62,6 +63,7 @@ dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *handle,gfp_t flag)
 
        return (void*)uncached;
 }
+EXPORT_SYMBOL(dma_alloc_coherent);
 
 void dma_free_coherent(struct device *hwdev, size_t size,
                         void *vaddr, dma_addr_t dma_handle)
@@ -73,6 +75,7 @@ void dma_free_coherent(struct device *hwdev, size_t size,
 
        free_pages(addr, get_order(size));
 }
+EXPORT_SYMBOL(dma_free_coherent);
 
 
 void consistent_sync(void *vaddr, size_t size, int direction)
@@ -92,3 +95,4 @@ void consistent_sync(void *vaddr, size_t size, int direction)
                break;
        }
 }
+EXPORT_SYMBOL(consistent_sync);
index c9a7c5b..20425ef 100644 (file)
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(__strncpy_user);
+EXPORT_SYMBOL(clear_page);
+EXPORT_SYMBOL(copy_page);
 
 EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(empty_zero_page);
 
 /*
  * gcc internal math functions
@@ -69,12 +73,11 @@ EXPORT_SYMBOL(__umodsi3);
 EXPORT_SYMBOL(__udivdi3);
 EXPORT_SYMBOL(__umoddi3);
 
-#ifdef CONFIG_NET
 /*
  * Networking support
  */
+EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_generic);
-#endif /* CONFIG_NET */
 
 /*
  * Architecture-specific symbols
index 85df465..1b62461 100644 (file)
@@ -59,7 +59,7 @@
  *
  */
 
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
 
 /*
  * Any time the kernel writes to a user page cache page, or it is about to
@@ -112,7 +112,7 @@ void flush_dcache_page(struct page *page)
 
        /* There shouldn't be an entry in the cache for this page anymore. */
 }
-
+EXPORT_SYMBOL(flush_dcache_page);
 
 /*
  * For now, flush the whole cache. FIXME??
@@ -124,6 +124,7 @@ void flush_cache_range(struct vm_area_struct* vma,
        __flush_invalidate_dcache_all();
        __invalidate_icache_all();
 }
+EXPORT_SYMBOL(local_flush_cache_range);
 
 /* 
  * Remove any entry in the cache for this page. 
@@ -143,8 +144,9 @@ void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
        __flush_invalidate_dcache_page_alias(virt, phys);
        __invalidate_icache_page_alias(virt, phys);
 }
+EXPORT_SYMBOL(local_flush_cache_page);
 
-#endif
+#endif /* DCACHE_WAY_SIZE > PAGE_SIZE */
 
 void
 update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
@@ -162,7 +164,7 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
        invalidate_itlb_mapping(addr);
        invalidate_dtlb_mapping(addr);
 
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
 
        if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) {
 
@@ -193,7 +195,7 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
  * flush_dcache_page() on the page.
  */
 
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
 
 void copy_to_user_page(struct vm_area_struct *vma, struct page *page, 
                unsigned long vaddr, void *dst, const void *src,
index ec494ff..416b263 100644 (file)
@@ -235,7 +235,7 @@ EXPORT_SYMBOL(blk_delay_queue);
  **/
 void blk_start_queue(struct request_queue *q)
 {
-       WARN_ON(!irqs_disabled());
+       WARN_ON(!in_interrupt() && !irqs_disabled());
 
        queue_flag_clear(QUEUE_FLAG_STOPPED, q);
        __blk_run_queue(q);
@@ -499,6 +499,9 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 
        kobject_init(&q->kobj, &blk_queue_ktype);
 
+#ifdef CONFIG_BLK_DEV_IO_TRACE
+       mutex_init(&q->blk_trace_mutex);
+#endif
        mutex_init(&q->sysfs_lock);
        spin_lock_init(&q->__queue_lock);
 
index 68ec1ac..db3e5ec 100644 (file)
@@ -149,6 +149,7 @@ EXPORT_SYMBOL_GPL(af_alg_release_parent);
 
 static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
+       const u32 allowed = 0;
        struct sock *sk = sock->sk;
        struct alg_sock *ask = alg_sk(sk);
        struct sockaddr_alg *sa = (void *)uaddr;
@@ -156,6 +157,10 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        void *private;
        int err;
 
+       /* If caller uses non-allowed flag, return error. */
+       if ((sa->salg_feat & ~allowed) || (sa->salg_mask & ~allowed))
+               return -EINVAL;
+
        if (sock->state == SS_CONNECTED)
                return -EINVAL;
 
index a6f94c4..555c5e5 100644 (file)
@@ -172,11 +172,18 @@ int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
                        unsigned int keylen)
 {
        unsigned long alignmask = crypto_ahash_alignmask(tfm);
+       int err;
 
        if ((unsigned long)key & alignmask)
-               return ahash_setkey_unaligned(tfm, key, keylen);
+               err = ahash_setkey_unaligned(tfm, key, keylen);
+       else
+               err = tfm->setkey(tfm, key, keylen);
+
+       if (err)
+               return err;
 
-       return tfm->setkey(tfm, key, keylen);
+       crypto_ahash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(crypto_ahash_setkey);
 
@@ -349,7 +356,12 @@ EXPORT_SYMBOL_GPL(crypto_ahash_finup);
 
 int crypto_ahash_digest(struct ahash_request *req)
 {
-       return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->digest);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+
+       if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+               return -ENOKEY;
+
+       return crypto_ahash_op(req, tfm->digest);
 }
 EXPORT_SYMBOL_GPL(crypto_ahash_digest);
 
@@ -435,7 +447,6 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
        struct ahash_alg *alg = crypto_ahash_alg(hash);
 
        hash->setkey = ahash_nosetkey;
-       hash->has_setkey = false;
        hash->export = ahash_no_export;
        hash->import = ahash_no_import;
 
@@ -450,7 +461,8 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
 
        if (alg->setkey) {
                hash->setkey = alg->setkey;
-               hash->has_setkey = true;
+               if (!(alg->halg.base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY))
+                       crypto_ahash_set_flags(hash, CRYPTO_TFM_NEED_KEY);
        }
        if (alg->export)
                hash->export = alg->export;
@@ -599,5 +611,16 @@ struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask)
 }
 EXPORT_SYMBOL_GPL(ahash_attr_alg);
 
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg)
+{
+       struct crypto_alg *alg = &halg->base;
+
+       if (alg->cra_type != &crypto_ahash_type)
+               return crypto_shash_alg_has_setkey(__crypto_shash_alg(alg));
+
+       return __crypto_ahash_alg(alg)->setkey != NULL;
+}
+EXPORT_SYMBOL_GPL(crypto_hash_alg_has_setkey);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
index 2f19548..49e1268 100644 (file)
@@ -163,6 +163,18 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
 
                        spawn->alg = NULL;
                        spawns = &inst->alg.cra_users;
+
+                       /*
+                        * We may encounter an unregistered instance here, since
+                        * an instance's spawns are set up prior to the instance
+                        * being registered.  An unregistered instance will have
+                        * NULL ->cra_users.next, since ->cra_users isn't
+                        * properly initialized until registration.  But an
+                        * unregistered instance cannot have any users, so treat
+                        * it the same as ->cra_users being empty.
+                        */
+                       if (spawns->next == NULL)
+                               break;
                }
        } while ((spawns = crypto_more_spawns(alg, &stack, &top,
                                              &secondary_spawns)));
index d11d431..3aa8890 100644 (file)
@@ -34,11 +34,6 @@ struct hash_ctx {
        struct ahash_request req;
 };
 
-struct algif_hash_tfm {
-       struct crypto_ahash *hash;
-       bool has_key;
-};
-
 static int hash_sendmsg(struct kiocb *unused, struct socket *sock,
                        struct msghdr *msg, size_t ignored)
 {
@@ -258,7 +253,7 @@ static int hash_check_key(struct socket *sock)
        int err = 0;
        struct sock *psk;
        struct alg_sock *pask;
-       struct algif_hash_tfm *tfm;
+       struct crypto_ahash *tfm;
        struct sock *sk = sock->sk;
        struct alg_sock *ask = alg_sk(sk);
 
@@ -272,7 +267,7 @@ static int hash_check_key(struct socket *sock)
 
        err = -ENOKEY;
        lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
-       if (!tfm->has_key)
+       if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
                goto unlock;
 
        if (!pask->refcnt++)
@@ -363,41 +358,17 @@ static struct proto_ops algif_hash_ops_nokey = {
 
 static void *hash_bind(const char *name, u32 type, u32 mask)
 {
-       struct algif_hash_tfm *tfm;
-       struct crypto_ahash *hash;
-
-       tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
-       if (!tfm)
-               return ERR_PTR(-ENOMEM);
-
-       hash = crypto_alloc_ahash(name, type, mask);
-       if (IS_ERR(hash)) {
-               kfree(tfm);
-               return ERR_CAST(hash);
-       }
-
-       tfm->hash = hash;
-
-       return tfm;
+       return crypto_alloc_ahash(name, type, mask);
 }
 
 static void hash_release(void *private)
 {
-       struct algif_hash_tfm *tfm = private;
-
-       crypto_free_ahash(tfm->hash);
-       kfree(tfm);
+       crypto_free_ahash(private);
 }
 
 static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
 {
-       struct algif_hash_tfm *tfm = private;
-       int err;
-
-       err = crypto_ahash_setkey(tfm->hash, key, keylen);
-       tfm->has_key = !err;
-
-       return err;
+       return crypto_ahash_setkey(private, key, keylen);
 }
 
 static void hash_sock_destruct(struct sock *sk)
@@ -413,12 +384,11 @@ static void hash_sock_destruct(struct sock *sk)
 
 static int hash_accept_parent_nokey(void *private, struct sock *sk)
 {
-       struct hash_ctx *ctx;
+       struct crypto_ahash *tfm = private;
        struct alg_sock *ask = alg_sk(sk);
-       struct algif_hash_tfm *tfm = private;
-       struct crypto_ahash *hash = tfm->hash;
-       unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(hash);
-       unsigned ds = crypto_ahash_digestsize(hash);
+       struct hash_ctx *ctx;
+       unsigned int len = sizeof(*ctx) + crypto_ahash_reqsize(tfm);
+       unsigned ds = crypto_ahash_digestsize(tfm);
 
        ctx = sock_kmalloc(sk, len, GFP_KERNEL);
        if (!ctx)
@@ -438,7 +408,7 @@ static int hash_accept_parent_nokey(void *private, struct sock *sk)
 
        ask->private = ctx;
 
-       ahash_request_set_tfm(&ctx->req, hash);
+       ahash_request_set_tfm(&ctx->req, tfm);
        ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
                                   af_alg_complete, &ctx->completion);
 
@@ -449,9 +419,9 @@ static int hash_accept_parent_nokey(void *private, struct sock *sk)
 
 static int hash_accept_parent(void *private, struct sock *sk)
 {
-       struct algif_hash_tfm *tfm = private;
+       struct crypto_ahash *tfm = private;
 
-       if (!tfm->has_key && crypto_ahash_has_setkey(tfm->hash))
+       if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
                return -ENOKEY;
 
        return hash_accept_parent_nokey(private, sk);
index b2c030b..55f5ed1 100644 (file)
@@ -234,6 +234,7 @@ static struct shash_alg alg = {
                .cra_name               =       "crc32c",
                .cra_driver_name        =       "crc32c-generic",
                .cra_priority           =       100,
+               .cra_flags              =       CRYPTO_ALG_OPTIONAL_KEY,
                .cra_blocksize          =       CHKSUM_BLOCK_SIZE,
                .cra_alignmask          =       3,
                .cra_ctxsize            =       sizeof(struct chksum_ctx),
index d85fab9..3443c11 100644 (file)
@@ -603,7 +603,8 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
        if (err)
                goto out_free_inst;
 
-       inst->alg.halg.base.cra_flags = CRYPTO_ALG_ASYNC;
+       inst->alg.halg.base.cra_flags = CRYPTO_ALG_ASYNC |
+               (alg->cra_flags & CRYPTO_ALG_OPTIONAL_KEY);
 
        inst->alg.halg.digestsize = salg->digestsize;
        inst->alg.halg.base.cra_ctxsize = sizeof(struct cryptd_hash_ctx);
@@ -617,7 +618,8 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
        inst->alg.finup  = cryptd_hash_finup_enqueue;
        inst->alg.export = cryptd_hash_export;
        inst->alg.import = cryptd_hash_import;
-       inst->alg.setkey = cryptd_hash_setkey;
+       if (crypto_shash_alg_has_setkey(salg))
+               inst->alg.setkey = cryptd_hash_setkey;
        inst->alg.digest = cryptd_hash_digest_enqueue;
 
        err = ahash_register_instance(tmpl, inst);
index ade790b..758688b 100644 (file)
@@ -197,11 +197,15 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb)
        salg = shash_attr_alg(tb[1], 0, 0);
        if (IS_ERR(salg))
                return PTR_ERR(salg);
+       alg = &salg->base;
 
+       /* The underlying hash algorithm must be unkeyed */
        err = -EINVAL;
+       if (crypto_shash_alg_has_setkey(salg))
+               goto out_put_alg;
+
        ds = salg->digestsize;
        ss = salg->statesize;
-       alg = &salg->base;
        if (ds > alg->cra_blocksize ||
            ss < alg->cra_blocksize)
                goto out_put_alg;
index f5e5a33..5d2d548 100644 (file)
@@ -188,13 +188,6 @@ static int encrypt(struct blkcipher_desc *desc,
 
        salsa20_ivsetup(ctx, walk.iv);
 
-       if (likely(walk.nbytes == nbytes))
-       {
-               salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
-                                     walk.src.virt.addr, nbytes);
-               return blkcipher_walk_done(desc, &walk, 0);
-       }
-
        while (walk.nbytes >= 64) {
                salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
                                      walk.src.virt.addr,
index 060e42b..5441f4e 100644 (file)
 
 static const struct crypto_type crypto_shash_type;
 
-static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
-                          unsigned int keylen)
+int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+                   unsigned int keylen)
 {
        return -ENOSYS;
 }
+EXPORT_SYMBOL_GPL(shash_no_setkey);
 
 static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
                                  unsigned int keylen)
@@ -56,11 +57,18 @@ int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key,
 {
        struct shash_alg *shash = crypto_shash_alg(tfm);
        unsigned long alignmask = crypto_shash_alignmask(tfm);
+       int err;
 
        if ((unsigned long)key & alignmask)
-               return shash_setkey_unaligned(tfm, key, keylen);
+               err = shash_setkey_unaligned(tfm, key, keylen);
+       else
+               err = shash->setkey(tfm, key, keylen);
 
-       return shash->setkey(tfm, key, keylen);
+       if (err)
+               return err;
+
+       crypto_shash_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(crypto_shash_setkey);
 
@@ -178,6 +186,9 @@ int crypto_shash_digest(struct shash_desc *desc, const u8 *data,
        struct shash_alg *shash = crypto_shash_alg(tfm);
        unsigned long alignmask = crypto_shash_alignmask(tfm);
 
+       if (crypto_shash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+               return -ENOKEY;
+
        if (((unsigned long)data | (unsigned long)out) & alignmask)
                return shash_digest_unaligned(desc, data, len, out);
 
@@ -273,12 +284,14 @@ static int shash_async_finup(struct ahash_request *req)
 
 int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc)
 {
-       struct scatterlist *sg = req->src;
-       unsigned int offset = sg->offset;
        unsigned int nbytes = req->nbytes;
+       struct scatterlist *sg;
+       unsigned int offset;
        int err;
 
-       if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) {
+       if (nbytes &&
+           (sg = req->src, offset = sg->offset,
+            nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset))) {
                void *data;
 
                data = crypto_kmap(sg_page(sg), 0);
@@ -355,7 +368,8 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
        crt->digest = shash_async_digest;
        crt->setkey = shash_async_setkey;
 
-       crt->has_setkey = alg->setkey != shash_no_setkey;
+       crypto_ahash_set_flags(crt, crypto_shash_get_flags(shash) &
+                                   CRYPTO_TFM_NEED_KEY);
 
        if (alg->export)
                crt->export = shash_async_export;
@@ -515,8 +529,14 @@ static unsigned int crypto_shash_ctxsize(struct crypto_alg *alg, u32 type,
 static int crypto_shash_init_tfm(struct crypto_tfm *tfm)
 {
        struct crypto_shash *hash = __crypto_shash_cast(tfm);
+       struct shash_alg *alg = crypto_shash_alg(hash);
+
+       hash->descsize = alg->descsize;
+
+       if (crypto_shash_alg_has_setkey(alg) &&
+           !(alg->base.cra_flags & CRYPTO_ALG_OPTIONAL_KEY))
+               crypto_shash_set_flags(hash, CRYPTO_TFM_NEED_KEY);
 
-       hash->descsize = crypto_shash_alg(hash)->descsize;
        return 0;
 }
 
index ac7b854..9d1a5da 100644 (file)
@@ -121,7 +121,7 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
                      union acpi_operand_object **return_object_ptr)
 {
        union acpi_operand_object *return_object = *return_object_ptr;
-       union acpi_operand_object *new_object;
+       union acpi_operand_object *new_object = NULL;
        acpi_status status;
 
        ACPI_FUNCTION_NAME(ns_repair_object);
index 631b947..93ef09c 100644 (file)
@@ -1019,7 +1019,7 @@ skip:
        /* The record may be cleared by others, try read next record */
        if (len == -ENOENT)
                goto skip;
-       else if (len < sizeof(*rcd)) {
+       else if (len < 0 || len < sizeof(*rcd)) {
                rc = -EIO;
                goto out;
        }
index f8d2a47..c9cfe4c 100644 (file)
@@ -288,8 +288,8 @@ static int acpi_smbus_hc_add(struct acpi_device *device)
        device->driver_data = hc;
 
        acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
-       printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n",
-               hc->ec, hc->offset, hc->query_bit);
+       dev_info(&device->dev, "SBS HC: offset = 0x%0x, query_bit = 0x%0x\n",
+                hc->offset, hc->query_bit);
 
        return 0;
 }
index 93ace9b..476a414 100644 (file)
@@ -542,7 +542,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
          .driver_data = board_ahci_yes_fbs },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
          .driver_data = board_ahci_yes_fbs },
-       { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642),
+       { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642), /* highpoint rocketraid 642L */
+         .driver_data = board_ahci_yes_fbs },
+       { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0645), /* highpoint rocketraid 644L */
          .driver_data = board_ahci_yes_fbs },
 
        /* Promise */
index 4e9beff..ddfdb9c 100644 (file)
@@ -4155,6 +4155,16 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "PIONEER DVD-RW  DVR-212D",   NULL,   ATA_HORKAGE_NOSETXFER },
        { "PIONEER DVD-RW  DVR-216D",   NULL,   ATA_HORKAGE_NOSETXFER },
 
+       /* Crucial BX100 SSD 500GB has broken LPM support */
+       { "CT500BX100SSD1",             NULL,   ATA_HORKAGE_NOLPM },
+
+       /* The 512GB version of the MX100 has LPM issues */
+       { "Crucial_CT512MX100*",        NULL,   ATA_HORKAGE_NOLPM, },
+
+       /* 480GB+ M500 SSDs have LPM issues */
+       { "Crucial_CT480M500*",         NULL,   ATA_HORKAGE_NOLPM, },
+       { "Crucial_CT960M500*",         NULL,   ATA_HORKAGE_NOLPM, },
+
        /* devices that don't properly handle TRIM commands */
        { "SuperSSpeed S238*",          NULL,   ATA_HORKAGE_NOTRIM, },
 
@@ -5060,8 +5070,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
         * We guarantee to LLDs that they will have at least one
         * non-zero sg if the command is a data command.
         */
-       if (WARN_ON_ONCE(ata_is_data(prot) &&
-                        (!qc->sg || !qc->n_elem || !qc->nbytes)))
+       if (ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes))
                goto sys_err;
 
        if (ata_is_dma(prot) || (ata_is_pio(prot) &&
index 01a019e..a7cd210 100644 (file)
@@ -2755,10 +2755,12 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
 static struct ata_device *ata_find_dev(struct ata_port *ap, int devno)
 {
        if (!sata_pmp_attached(ap)) {
-               if (likely(devno < ata_link_max_devices(&ap->link)))
+               if (likely(devno >= 0 &&
+                          devno < ata_link_max_devices(&ap->link)))
                        return &ap->link.device[devno];
        } else {
-               if (likely(devno < ap->nr_pmp_links))
+               if (likely(devno >= 0 &&
+                          devno < ap->nr_pmp_links))
                        return &ap->pmp_link[devno].device[0];
        }
 
@@ -3192,7 +3194,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
                if (likely((scsi_op != ATA_16) || !atapi_passthru16)) {
                        /* relay SCSI command to ATAPI device */
                        int len = COMMAND_SIZE(scsi_op);
-                       if (unlikely(len > scmd->cmd_len || len > dev->cdb_len))
+                       if (unlikely(len > scmd->cmd_len ||
+                                    len > dev->cdb_len ||
+                                    scmd->cmd_len > ATAPI_CDB_LEN))
                                goto bad_cdb_len;
 
                        xlat_func = atapi_xlat;
index dc6b5da..6e55a34 100644 (file)
@@ -617,6 +617,7 @@ static const struct pci_device_id amd[] = {
        { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE), 8 },
        { PCI_VDEVICE(NVIDIA,   PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE), 8 },
        { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_CS5536_IDE),          9 },
+       { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_CS5536_DEV_IDE),      9 },
 
        { },
 };
index 628c8fa..dbe0fa8 100644 (file)
@@ -275,6 +275,7 @@ static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 
 static const struct pci_device_id cs5536[] = {
        { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_CS5536_IDE), },
+       { PCI_VDEVICE(AMD,      PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), },
        { },
 };
 
index 305e831..d9b011e 100644 (file)
@@ -175,6 +175,9 @@ config SYS_HYPERVISOR
 config SOC_BUS
        bool
 
+config GENERIC_CPU_VULNERABILITIES
+       bool
+
 source "drivers/base/regmap/Kconfig"
 
 config CMA
index b802cfc..db41a4b 100644 (file)
@@ -684,7 +684,7 @@ int bus_add_driver(struct device_driver *drv)
 
 out_unregister:
        kobject_put(&priv->kobj);
-       kfree(drv->p);
+       /* drv->p is freed in driver_release()  */
        drv->p = NULL;
 out_put_bus:
        bus_put(bus);
index 251acea..8d82884 100644 (file)
@@ -247,6 +247,53 @@ struct sys_device *get_cpu_sysdev(unsigned cpu)
 }
 EXPORT_SYMBOL_GPL(get_cpu_sysdev);
 
+#ifdef CONFIG_GENERIC_CPU_VULNERABILITIES
+
+ssize_t __weak cpu_show_meltdown(struct sysdev_class *class,
+                                struct sysdev_class_attribute *attr, char *buf)
+{
+       return sprintf(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_spectre_v1(struct sysdev_class *class,
+                                  struct sysdev_class_attribute *attr, char *buf)
+{
+       return sprintf(buf, "Not affected\n");
+}
+
+ssize_t __weak cpu_show_spectre_v2(struct sysdev_class *class,
+                                  struct sysdev_class_attribute *attr, char *buf)
+{
+       return sprintf(buf, "Not affected\n");
+}
+
+static SYSDEV_CLASS_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
+static SYSDEV_CLASS_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
+static SYSDEV_CLASS_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL);
+
+static struct attribute *cpu_root_vulnerabilities_attrs[] = {
+       &attr_meltdown.attr,
+       &attr_spectre_v1.attr,
+       &attr_spectre_v2.attr,
+       NULL
+};
+
+static const struct attribute_group cpu_root_vulnerabilities_group = {
+       .name  = "vulnerabilities",
+       .attrs = cpu_root_vulnerabilities_attrs,
+};
+
+static void __init cpu_register_vulnerabilities(void)
+{
+       if (sysfs_create_group(&cpu_sysdev_class.kset.kobj,
+                              &cpu_root_vulnerabilities_group))
+               pr_err("Unable to register CPU vulnerabilities\n");
+}
+
+#else
+static inline void cpu_register_vulnerabilities(void) { }
+#endif
+
 int __init cpu_dev_init(void)
 {
        int err;
@@ -256,6 +303,8 @@ int __init cpu_dev_init(void)
        if (!err)
                err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class);
 #endif
+       if (!err)
+               cpu_register_vulnerabilities();
 
        return err;
 }
index cd6ccdc..372d10a 100644 (file)
@@ -39,7 +39,7 @@ static int isa_bus_probe(struct device *dev)
 {
        struct isa_driver *isa_driver = dev->platform_data;
 
-       if (isa_driver->probe)
+       if (isa_driver && isa_driver->probe)
                return isa_driver->probe(dev, to_isa_dev(dev)->id);
 
        return 0;
@@ -49,7 +49,7 @@ static int isa_bus_remove(struct device *dev)
 {
        struct isa_driver *isa_driver = dev->platform_data;
 
-       if (isa_driver->remove)
+       if (isa_driver && isa_driver->remove)
                return isa_driver->remove(dev, to_isa_dev(dev)->id);
 
        return 0;
@@ -59,7 +59,7 @@ static void isa_bus_shutdown(struct device *dev)
 {
        struct isa_driver *isa_driver = dev->platform_data;
 
-       if (isa_driver->shutdown)
+       if (isa_driver && isa_driver->shutdown)
                isa_driver->shutdown(dev, to_isa_dev(dev)->id);
 }
 
@@ -67,7 +67,7 @@ static int isa_bus_suspend(struct device *dev, pm_message_t state)
 {
        struct isa_driver *isa_driver = dev->platform_data;
 
-       if (isa_driver->suspend)
+       if (isa_driver && isa_driver->suspend)
                return isa_driver->suspend(dev, to_isa_dev(dev)->id, state);
 
        return 0;
@@ -77,7 +77,7 @@ static int isa_bus_resume(struct device *dev)
 {
        struct isa_driver *isa_driver = dev->platform_data;
 
-       if (isa_driver->resume)
+       if (isa_driver && isa_driver->resume)
                return isa_driver->resume(dev, to_isa_dev(dev)->id);
 
        return 0;
index 6790cf7..6731e91 100644 (file)
@@ -1240,7 +1240,7 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
                              struct generic_pm_domain *subdomain)
 {
-       struct gpd_link *link;
+       struct gpd_link *l, *link;
        int ret = -EINVAL;
 
        if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
@@ -1249,7 +1249,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
  start:
        genpd_acquire_lock(genpd);
 
-       list_for_each_entry(link, &genpd->master_links, master_node) {
+       list_for_each_entry_safe(link, l, &genpd->master_links, master_node) {
                if (link->slave != subdomain)
                        continue;
 
index e086fbb..8db9089 100644 (file)
@@ -1177,7 +1177,8 @@ static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T
   int TimeoutCounter;
   int i;
 
-  
+  memset(&CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T));
+
   if (pci_set_dma_mask(Controller->PCIDevice, DMA_BIT_MASK(32)))
        return DAC960_Failure(Controller, "DMA mask out of range");
   Controller->BounceBufferLimit = DMA_BIT_MASK(32);
@@ -4627,7 +4628,8 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
   DAC960_Controller_T *Controller = Command->Controller;
   DAC960_CommandType_T CommandType = Command->CommandType;
   DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
-  DAC960_V2_IOCTL_Opcode_T CommandOpcode = CommandMailbox->Common.IOCTL_Opcode;
+  DAC960_V2_IOCTL_Opcode_T IOCTLOpcode = CommandMailbox->Common.IOCTL_Opcode;
+  DAC960_V2_CommandOpcode_T CommandOpcode = CommandMailbox->SCSI_10.CommandOpcode;
   DAC960_V2_CommandStatus_T CommandStatus = Command->V2.CommandStatus;
 
   if (CommandType == DAC960_ReadCommand ||
@@ -4699,7 +4701,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
     {
       if (Controller->ShutdownMonitoringTimer)
              return;
-      if (CommandOpcode == DAC960_V2_GetControllerInfo)
+      if (IOCTLOpcode == DAC960_V2_GetControllerInfo)
        {
          DAC960_V2_ControllerInfo_T *NewControllerInfo =
            Controller->V2.NewControllerInformation;
@@ -4719,14 +4721,14 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
          memcpy(ControllerInfo, NewControllerInfo,
                 sizeof(DAC960_V2_ControllerInfo_T));
        }
-      else if (CommandOpcode == DAC960_V2_GetEvent)
+      else if (IOCTLOpcode == DAC960_V2_GetEvent)
        {
          if (CommandStatus == DAC960_V2_NormalCompletion) {
            DAC960_V2_ReportEvent(Controller, Controller->V2.Event);
          }
          Controller->V2.NextEventSequenceNumber++;
        }
-      else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid &&
+      else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid &&
               CommandStatus == DAC960_V2_NormalCompletion)
        {
          DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo =
@@ -4915,7 +4917,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
          NewPhysicalDeviceInfo->LogicalUnit++;
          Controller->V2.PhysicalDeviceIndex++;
        }
-      else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid)
+      else if (IOCTLOpcode == DAC960_V2_GetPhysicalDeviceInfoValid)
        {
          unsigned int DeviceIndex;
          for (DeviceIndex = Controller->V2.PhysicalDeviceIndex;
@@ -4938,7 +4940,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
            }
          Controller->V2.NeedPhysicalDeviceInformation = false;
        }
-      else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid &&
+      else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid &&
               CommandStatus == DAC960_V2_NormalCompletion)
        {
          DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo =
@@ -5065,7 +5067,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
                         [LogicalDeviceNumber] = true;
          NewLogicalDeviceInfo->LogicalDeviceNumber++;
        }
-      else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid)
+      else if (IOCTLOpcode == DAC960_V2_GetLogicalDeviceInfoValid)
        {
          int LogicalDriveNumber;
          for (LogicalDriveNumber = 0;
index 0358e55..a6ad652 100644 (file)
@@ -4183,12 +4183,11 @@ const char *drbd_buildtag(void)
        static char buildtag[38] = "\0uilt-in";
 
        if (buildtag[0] == 0) {
-#ifdef CONFIG_MODULES
-               if (THIS_MODULE != NULL)
-                       sprintf(buildtag, "srcversion: %-24s", THIS_MODULE->srcversion);
-               else
+#ifdef MODULE
+               sprintf(buildtag, "srcversion: %-24s", THIS_MODULE->srcversion);
+#else
+               buildtag[0] = 'b';
 #endif
-                       buildtag[0] = 'b';
        }
 
        return buildtag;
index a63b0a2..87ba51e 100644 (file)
@@ -2885,7 +2885,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
        pd->pkt_dev = MKDEV(pktdev_major, idx);
        ret = pkt_new_dev(pd, dev);
        if (ret)
-               goto out_new_dev;
+               goto out_mem2;
 
        /* inherit events of the host device */
        disk->events = pd->bdev->bd_disk->events;
@@ -2903,8 +2903,6 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
        mutex_unlock(&ctl_mutex);
        return 0;
 
-out_new_dev:
-       blk_cleanup_queue(disk->queue);
 out_mem2:
        put_disk(disk);
 out_mem:
index a03e849..3792f5c 100644 (file)
@@ -2342,7 +2342,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
        if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
                return media_changed(cdi, 1);
 
-       if ((unsigned int)arg >= cdi->capacity)
+       if (arg >= cdi->capacity)
                return -EINVAL;
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
index f7395c4..706c583 100644 (file)
@@ -879,9 +879,10 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
        ssize_t err;
        int i, rc;
        char *str = buf;
-
        struct tpm_chip *chip = dev_get_drvdata(dev);
 
+       memset(&tpm_cmd, 0, sizeof(tpm_cmd));
+
        tpm_cmd.header.in = tpm_readpubek_header;
        err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
                        "attempting to read the PUBEK");
@@ -1113,6 +1114,12 @@ ssize_t tpm_write(struct file *file, const char __user *buf,
                return -EFAULT;
        }
 
+       if (in_size < 6 ||
+           in_size < be32_to_cpu(*((__be32 *) (chip->data_buffer + 2)))) {
+               mutex_unlock(&chip->buffer_mutex);
+               return -EINVAL;
+       }
+
        /* atomic tpm command send and result receive */
        out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
        if (out_size < 0) {
index 0c4885d..34c60cd 100644 (file)
@@ -253,7 +253,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
 static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
        int size = 0;
-       int expected, status;
+       int status;
+       u32 expected;
 
        if (count < TPM_HEADER_SIZE) {
                size = -EIO;
@@ -268,7 +269,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
        }
 
        expected = be32_to_cpu(*(__be32 *) (buf + 2));
-       if (expected > count) {
+       if (expected > count || expected < TPM_HEADER_SIZE) {
                size = -EIO;
                goto out;
        }
index 8944dab..17e5921 100644 (file)
@@ -1642,6 +1642,7 @@ static int queue_cache_init(void)
                                          CWQ_ENTRY_SIZE, 0, NULL);
        if (!queue_cache[HV_NCS_QTYPE_CWQ - 1]) {
                kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]);
+               queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL;
                return -ENOMEM;
        }
        return 0;
@@ -1651,6 +1652,8 @@ static void queue_cache_destroy(void)
 {
        kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]);
        kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_CWQ - 1]);
+       queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL;
+       queue_cache[HV_NCS_QTYPE_CWQ - 1] = NULL;
 }
 
 static int spu_queue_register(struct spu_queue *p, unsigned long q_type)
index 90c76fc..68acc0d 100644 (file)
@@ -1632,9 +1632,9 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
                req_ctx->swinit = 0;
        } else {
                desc->ptr[1] = zero_entry;
-               /* Indicate next op is not the first. */
-               req_ctx->first = 0;
        }
+       /* Indicate next op is not the first. */
+       req_ctx->first = 0;
 
        /* HMAC key */
        if (ctx->keylen)
index 1e08426..9afb598 100644 (file)
@@ -803,6 +803,7 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
        }
 
        /* Get the set of MTR[0-7] regs by each branch */
+       nr_pages = 0;
        for (slot = 0; slot < MAX_SLOTS; slot++) {
                int where = mtr_regs[slot];
                for (branch = 0; branch < MAX_BRANCHES; branch++) {
index 0106747..a40dcfd 100644 (file)
@@ -5,8 +5,6 @@
 
 #include <asm/mce.h>
 
-#define BIT_64(n)                      (U64_C(1) << (n))
-
 #define EC(x)                          ((x) & 0xffff)
 #define XEC(x, mask)                   (((x) >> 16) & mask)
 
index 20f7daa..bde7ebb 100644 (file)
@@ -14,7 +14,7 @@
  * of and an antecedent to, SMBIOS, which stands for System
  * Management BIOS.  See further: http://www.dmtf.org/standards
  */
-static char dmi_empty_string[] = "        ";
+static const char dmi_empty_string[] = "";
 
 static u16 __initdata dmi_ver;
 /*
@@ -25,28 +25,24 @@ static int dmi_initialized;
 static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s)
 {
        const u8 *bp = ((u8 *) dm) + dm->length;
+       const u8 *nsp;
 
        if (s) {
-               s--;
-               while (s > 0 && *bp) {
+               while (--s > 0 && *bp)
                        bp += strlen(bp) + 1;
-                       s--;
-               }
-
-               if (*bp != 0) {
-                       size_t len = strlen(bp)+1;
-                       size_t cmp_len = len > 8 ? 8 : len;
 
-                       if (!memcmp(bp, dmi_empty_string, cmp_len))
-                               return dmi_empty_string;
+               /* Strings containing only spaces are considered empty */
+               nsp = bp;
+               while (*nsp == ' ')
+                       nsp++;
+               if (*nsp != '\0')
                        return bp;
-               }
        }
 
-       return "";
+       return dmi_empty_string;
 }
 
-static char * __init dmi_string(const struct dmi_header *dm, u8 s)
+static const char * __init dmi_string(const struct dmi_header *dm, u8 s)
 {
        const char *bp = dmi_string_nosave(dm, s);
        char *str;
@@ -130,7 +126,7 @@ static int __init dmi_checksum(const u8 *buf, u8 len)
        return sum == 0;
 }
 
-static char *dmi_ident[DMI_STRING_MAX];
+static const char *dmi_ident[DMI_STRING_MAX];
 static LIST_HEAD(dmi_devices);
 int dmi_available;
 
@@ -140,7 +136,7 @@ int dmi_available;
 static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int string)
 {
        const char *d = (const char*) dm;
-       char *p;
+       const char *p;
 
        if (dmi_ident[slot])
                return;
@@ -246,7 +242,7 @@ static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
        struct dmi_device *dev;
 
        for (i = 1; i <= count; i++) {
-               char *devname = dmi_string(dm, i);
+               const char *devname = dmi_string(dm, i);
 
                if (devname == dmi_empty_string)
                        continue;
index 61044c8..9c84ad5 100644 (file)
@@ -230,7 +230,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
        struct tegra_gpio_bank *bank;
        int port;
        int pin;
-       int unmasked = 0;
+       bool unmasked = false;
        struct irq_chip *chip = irq_desc_get_chip(desc);
 
        chained_irq_enter(chip, desc);
@@ -250,8 +250,8 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
                         * before executing the hander so that we don't
                         * miss edges
                         */
-                       if (lvl & (0x100 << pin)) {
-                               unmasked = 1;
+                       if (!unmasked && lvl & (0x100 << pin)) {
+                               unmasked = true;
                                chained_irq_exit(chip, desc);
                        }
 
index ca67338..8ea257e 100644 (file)
@@ -2059,10 +2059,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
         * and the registers being closely associated.
         *
         * According to chipset errata, on the 965GM, MSI interrupts may
-        * be lost or delayed, but we use them anyways to avoid
-        * stuck interrupts on some machines.
+        * be lost or delayed, and was defeatured. MSI interrupts seem to
+        * get lost on g4x as well, and interrupt delivery seems to stay
+        * properly dead afterwards. So we'll just disable them for all
+        * pre-gen5 chipsets.
         */
-       if (!IS_I945G(dev) && !IS_I945GM(dev))
+       if (INTEL_INFO(dev)->gen >= 5)
                pci_enable_msi(dev->pdev);
 
        spin_lock_init(&dev_priv->gt_lock);
index e216c21..ba62ada 100644 (file)
@@ -971,13 +971,6 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL and additional rights");
 
-/* We give fast paths for the really cool registers */
-#define NEEDS_FORCE_WAKE(dev_priv, reg) \
-       ((HAS_FORCE_WAKE((dev_priv)->dev)) && \
-        ((reg) < 0x40000) &&            \
-        ((reg) != FORCEWAKE) &&         \
-        ((reg) != ECOBUS))
-
 #define __i915_read(x, y) \
 u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
        u##x val = 0; \
index 61274bf..783153a 100644 (file)
@@ -1369,10 +1369,9 @@ void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
 
 /* We give fast paths for the really cool registers */
 #define NEEDS_FORCE_WAKE(dev_priv, reg) \
-       (((dev_priv)->info->gen >= 6) && \
+       ((HAS_FORCE_WAKE((dev_priv)->dev)) && \
         ((reg) < 0x40000) &&            \
-        ((reg) != FORCEWAKE) &&         \
-        ((reg) != ECOBUS))
+        ((reg) != FORCEWAKE))
 
 #define __i915_read(x, y) \
        u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
index c7b5428..4a7d597 100644 (file)
@@ -8699,9 +8699,15 @@ static void intel_init_display(struct drm_device *dev)
                if (IS_IVYBRIDGE(dev)) {
                        u32     ecobus;
 
+                       /* A small trick here - if the bios hasn't configured MT forcewake,
+                        * and if the device is in RC6, then force_wake_mt_get will not wake
+                        * the device and the ECOBUS read will return zero. Which will be
+                        * (correctly) interpreted by the test below as MT forcewake being
+                        * disabled.
+                        */
                        mutex_lock(&dev->struct_mutex);
                        __gen6_gt_force_wake_mt_get(dev_priv);
-                       ecobus = I915_READ(ECOBUS);
+                       ecobus = I915_READ_NOTRACE(ECOBUS);
                        __gen6_gt_force_wake_mt_put(dev_priv);
                        mutex_unlock(&dev->struct_mutex);
 
index 40633f3..7f40e0a 100644 (file)
@@ -76,25 +76,18 @@ void radeon_connector_hotplug(struct drm_connector *connector)
                /* don't do anything if sink is not display port, i.e.,
                 * passive dp->(dvi|hdmi) adaptor
                 */
-               if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
-                       int saved_dpms = connector->dpms;
-                       /* Only turn off the display if it's physically disconnected */
-                       if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
-                               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
-                       } else if (radeon_dp_needs_link_train(radeon_connector)) {
-                               /* Don't try to start link training before we
-                                * have the dpcd */
-                               if (!radeon_dp_getdpcd(radeon_connector))
-                                       return;
-
-                               /* set it to OFF so that drm_helper_connector_dpms()
-                                * won't return immediately since the current state
-                                * is ON at this point.
-                                */
-                               connector->dpms = DRM_MODE_DPMS_OFF;
-                               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
-                       }
-                       connector->dpms = saved_dpms;
+               if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT &&
+                   radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
+                   radeon_dp_needs_link_train(radeon_connector)) {
+                       /* Don't start link training before we have the DPCD */
+                       if (!radeon_dp_getdpcd(radeon_connector))
+                               return;
+
+                       /* Turn the connector off and back on immediately, which
+                        * will trigger link training
+                        */
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
                }
        }
 }
index f122e61..2cc26a1 100644 (file)
@@ -784,6 +784,10 @@ int radeon_device_init(struct radeon_device *rdev,
        if ((rdev->flags & RADEON_IS_PCI) &&
            (rdev->family <= CHIP_RS740))
                rdev->need_dma32 = true;
+#ifdef CONFIG_PPC64
+       if (rdev->family == CHIP_CEDAR)
+               rdev->need_dma32 = true;
+#endif
 
        dma_bits = rdev->need_dma32 ? 32 : 40;
        r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits));
index f5e5037..35d98cf 100644 (file)
@@ -184,7 +184,7 @@ void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
                list_add_tail(&bo->lru, &man->lru);
                kref_get(&bo->list_kref);
 
-               if (bo->ttm != NULL) {
+               if (bo->ttm && !(bo->ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) {
                        list_add_tail(&bo->swap, &bo->glob->swap_lru);
                        kref_get(&bo->list_kref);
                }
index 508c64c..08f2fe7 100644 (file)
@@ -609,7 +609,7 @@ static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool,
                        printk(KERN_ERR TTM_PFX
                               "Failed to fill pool (%p).", pool);
                        /* If we have any pages left put them to the pool. */
-                       list_for_each_entry(p, &pool->list, lru) {
+                       list_for_each_entry(p, &new_pages, lru) {
                                ++cpages;
                        }
                        list_splice(&new_pages, &pool->list);
index 112d934..3d37c89 100644 (file)
@@ -37,6 +37,8 @@ static uint kovaplus_convert_event_cpi(uint value)
 static void kovaplus_profile_activated(struct kovaplus_device *kovaplus,
                uint new_profile_index)
 {
+       if (new_profile_index >= ARRAY_SIZE(kovaplus->profile_settings))
+               return;
        kovaplus->actual_profile = new_profile_index;
        kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level;
        kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x;
index 831e20d..e873c0b 100644 (file)
@@ -912,6 +912,8 @@ static int usbhid_parse(struct hid_device *hid)
        unsigned int rsize = 0;
        char *rdesc;
        int ret, n;
+       int num_descriptors;
+       size_t offset = offsetof(struct hid_descriptor, desc);
 
        quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
                        le16_to_cpu(dev->descriptor.idProduct));
@@ -934,10 +936,18 @@ static int usbhid_parse(struct hid_device *hid)
                return -ENODEV;
        }
 
+       if (hdesc->bLength < sizeof(struct hid_descriptor)) {
+               dbg_hid("hid descriptor is too short\n");
+               return -EINVAL;
+       }
+
        hid->version = le16_to_cpu(hdesc->bcdHID);
        hid->country = hdesc->bCountryCode;
 
-       for (n = 0; n < hdesc->bNumDescriptors; n++)
+       num_descriptors = min_t(int, hdesc->bNumDescriptors,
+              (hdesc->bLength - offset) / sizeof(struct hid_class_descriptor));
+
+       for (n = 0; n < num_descriptors; n++)
                if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
                        rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
 
index f5cccd0..c31014b 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/vmalloc.h>
 #include <linux/hyperv.h>
 #include <asm/hyperv.h>
+#include <asm/nospec-branch.h>
 #include "hyperv_vmbus.h"
 
 /* The one and only */
@@ -113,10 +114,13 @@ static u64 do_hypercall(u64 control, void *input, void *output)
        u64 output_address = (output) ? virt_to_phys(output) : 0;
        void *hypercall_page = hv_context.hypercall_page;
 
-       __asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8");
-       __asm__ __volatile__("call *%3" : "=a" (hv_status) :
-                            "c" (control), "d" (input_address),
-                            "m" (hypercall_page));
+       __asm__ __volatile__("mov %4, %%r8\n"
+                            CALL_NOSPEC
+                            : "=a" (hv_status), ASM_CALL_CONSTRAINT,
+                              "+c" (control), "+d" (input_address)
+                            :  "r" (output_address),
+                               THUNK_TARGET(hypercall_page)
+                            : "cc", "memory", "r8", "r9", "r10", "r11");
 
        return hv_status;
 
@@ -134,11 +138,14 @@ static u64 do_hypercall(u64 control, void *input, void *output)
        u32 output_address_lo = output_address & 0xFFFFFFFF;
        void *hypercall_page = hv_context.hypercall_page;
 
-       __asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi),
-                             "=a"(hv_status_lo) : "d" (control_hi),
-                             "a" (control_lo), "b" (input_address_hi),
-                             "c" (input_address_lo), "D"(output_address_hi),
-                             "S"(output_address_lo), "m" (hypercall_page));
+       __asm__ __volatile__(CALL_NOSPEC
+                            : "=d" (hv_status_hi), "=a" (hv_status_lo),
+                              "+c" (input_address_lo), ASM_CALL_CONSTRAINT
+                            : "d" (control_hi), "a" (control_lo),
+                              "b" (input_address_hi),
+                              "D"(output_address_hi), "S"(output_address_lo),
+                              THUNK_TARGET(hypercall_page)
+                            : "cc", "memory");
 
        return hv_status_lo | ((u64)hv_status_hi << 32);
 #endif /* !x86_64 */
index d89b339..d62b086 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -475,8 +476,8 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
 static long pmbus_reg2data_direct(struct pmbus_data *data,
                                  struct pmbus_sensor *sensor)
 {
-       long val = (s16) sensor->data;
-       long m, b, R;
+       s64 b, val = (s16)sensor->data;
+       s32 m, R;
 
        m = data->info->m[sensor->class];
        b = data->info->b[sensor->class];
@@ -504,11 +505,12 @@ static long pmbus_reg2data_direct(struct pmbus_data *data,
                R--;
        }
        while (R < 0) {
-               val = DIV_ROUND_CLOSEST(val, 10);
+               val = div_s64(val + 5LL, 10L);  /* round closest */
                R++;
        }
 
-       return (val - b) / m;
+       val = div_s64(val - b, m);
+       return clamp_val(val, LONG_MIN, LONG_MAX);
 }
 
 /*
@@ -620,7 +622,8 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
 static u16 pmbus_data2reg_direct(struct pmbus_data *data,
                                 enum pmbus_sensor_classes class, long val)
 {
-       long m, b, R;
+       s64 b, val64 = val;
+       s32 m, R;
 
        m = data->info->m[class];
        b = data->info->b[class];
@@ -637,18 +640,18 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
                R -= 3;         /* Adjust R and b for data in milli-units */
                b *= 1000;
        }
-       val = val * m + b;
+       val64 = val64 * m + b;
 
        while (R > 0) {
-               val *= 10;
+               val64 *= 10;
                R--;
        }
        while (R < 0) {
-               val = DIV_ROUND_CLOSEST(val, 10);
+               val64 = div_s64(val64 + 5LL, 10L);  /* round closest */
                R++;
        }
 
-       return val;
+       return (u16)clamp_val(val64, -32768, 32767);
 }
 
 static u16 pmbus_data2reg_vid(struct pmbus_data *data,
index 65b685e..56a69c1 100644 (file)
@@ -826,6 +826,7 @@ w83781d_detect_subclients(struct i2c_client *new_client)
        struct i2c_adapter *adapter = new_client->adapter;
        struct w83781d_data *data = i2c_get_clientdata(new_client);
        enum chips kind = data->type;
+       int num_sc = 1;
 
        id = i2c_adapter_id(adapter);
 
@@ -850,6 +851,7 @@ w83781d_detect_subclients(struct i2c_client *new_client)
        }
 
        if (kind != w83783s) {
+               num_sc = 2;
                if (force_subclients[0] == id &&
                    force_subclients[1] == address) {
                        sc_addr[1] = force_subclients[3];
@@ -865,7 +867,7 @@ w83781d_detect_subclients(struct i2c_client *new_client)
                }
        }
 
-       for (i = 0; i <= 1; i++) {
+       for (i = 0; i < num_sc; i++) {
                data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
                if (!data->lm75[i]) {
                        dev_err(&new_client->dev, "Subclient %d "
@@ -876,8 +878,6 @@ w83781d_detect_subclients(struct i2c_client *new_client)
                                goto ERROR_SC_3;
                        goto ERROR_SC_2;
                }
-               if (kind == w83783s)
-                       break;
        }
 
        return 0;
index c3793a7..8d96a47 100644 (file)
@@ -2009,16 +2009,17 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
                                   the underlying bus driver */
                break;
        case I2C_SMBUS_I2C_BLOCK_DATA:
+               if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
+                       dev_err(&adapter->dev, "Invalid block %s size %d\n",
+                               read_write == I2C_SMBUS_READ ? "read" : "write",
+                               data->block[0]);
+                       return -EINVAL;
+               }
+
                if (read_write == I2C_SMBUS_READ) {
                        msg[1].len = data->block[0];
                } else {
                        msg[0].len = data->block[0] + 1;
-                       if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
-                               dev_err(&adapter->dev,
-                                       "Invalid block write size %d\n",
-                                       data->block[0]);
-                               return -EINVAL;
-                       }
                        for (i = 1; i <= data->block[0]; i++)
                                msgbuf0[i] = data->block[i];
                }
index 44fde43..2a81c88 100644 (file)
@@ -229,7 +229,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
                .enter = &intel_idle },
 };
 
-static int get_driver_data(int cstate)
+static long get_driver_data(int cstate)
 {
        int driver_data;
        switch (cstate) {
index 9353992..29478d2 100644 (file)
@@ -58,17 +58,6 @@ struct ib_update_work {
        u8                 port_num;
 };
 
-static inline int start_port(struct ib_device *device)
-{
-       return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
-}
-
-static inline int end_port(struct ib_device *device)
-{
-       return (device->node_type == RDMA_NODE_IB_SWITCH) ?
-               0 : device->phys_port_cnt;
-}
-
 int ib_get_cached_gid(struct ib_device *device,
                      u8                port_num,
                      int               index,
@@ -78,12 +67,12 @@ int ib_get_cached_gid(struct ib_device *device,
        unsigned long flags;
        int ret = 0;
 
-       if (port_num < start_port(device) || port_num > end_port(device))
+       if (!rdma_is_port_valid(device, port_num))
                return -EINVAL;
 
        read_lock_irqsave(&device->cache.lock, flags);
 
-       cache = device->cache.gid_cache[port_num - start_port(device)];
+       cache = device->cache.gid_cache[port_num - rdma_start_port(device)];
 
        if (index < 0 || index >= cache->table_len)
                ret = -EINVAL;
@@ -112,11 +101,11 @@ int ib_find_cached_gid(struct ib_device *device,
 
        read_lock_irqsave(&device->cache.lock, flags);
 
-       for (p = 0; p <= end_port(device) - start_port(device); ++p) {
+       for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) {
                cache = device->cache.gid_cache[p];
                for (i = 0; i < cache->table_len; ++i) {
                        if (!memcmp(gid, &cache->table[i], sizeof *gid)) {
-                               *port_num = p + start_port(device);
+                               *port_num = p + rdma_start_port(device);
                                if (index)
                                        *index = i;
                                ret = 0;
@@ -140,12 +129,12 @@ int ib_get_cached_pkey(struct ib_device *device,
        unsigned long flags;
        int ret = 0;
 
-       if (port_num < start_port(device) || port_num > end_port(device))
+       if (!rdma_is_port_valid(device, port_num))
                return -EINVAL;
 
        read_lock_irqsave(&device->cache.lock, flags);
 
-       cache = device->cache.pkey_cache[port_num - start_port(device)];
+       cache = device->cache.pkey_cache[port_num - rdma_start_port(device)];
 
        if (index < 0 || index >= cache->table_len)
                ret = -EINVAL;
@@ -168,12 +157,12 @@ int ib_find_cached_pkey(struct ib_device *device,
        int i;
        int ret = -ENOENT;
 
-       if (port_num < start_port(device) || port_num > end_port(device))
+       if (!rdma_is_port_valid(device, port_num))
                return -EINVAL;
 
        read_lock_irqsave(&device->cache.lock, flags);
 
-       cache = device->cache.pkey_cache[port_num - start_port(device)];
+       cache = device->cache.pkey_cache[port_num - rdma_start_port(device)];
 
        *index = -1;
 
@@ -197,11 +186,11 @@ int ib_get_cached_lmc(struct ib_device *device,
        unsigned long flags;
        int ret = 0;
 
-       if (port_num < start_port(device) || port_num > end_port(device))
+       if (!rdma_is_port_valid(device, port_num))
                return -EINVAL;
 
        read_lock_irqsave(&device->cache.lock, flags);
-       *lmc = device->cache.lmc_cache[port_num - start_port(device)];
+       *lmc = device->cache.lmc_cache[port_num - rdma_start_port(device)];
        read_unlock_irqrestore(&device->cache.lock, flags);
 
        return ret;
@@ -262,13 +251,13 @@ static void ib_cache_update(struct ib_device *device,
 
        write_lock_irq(&device->cache.lock);
 
-       old_pkey_cache = device->cache.pkey_cache[port - start_port(device)];
-       old_gid_cache  = device->cache.gid_cache [port - start_port(device)];
+       old_pkey_cache = device->cache.pkey_cache[port - rdma_start_port(device)];
+       old_gid_cache  = device->cache.gid_cache [port - rdma_start_port(device)];
 
-       device->cache.pkey_cache[port - start_port(device)] = pkey_cache;
-       device->cache.gid_cache [port - start_port(device)] = gid_cache;
+       device->cache.pkey_cache[port - rdma_start_port(device)] = pkey_cache;
+       device->cache.gid_cache [port - rdma_start_port(device)] = gid_cache;
 
-       device->cache.lmc_cache[port - start_port(device)] = tprops->lmc;
+       device->cache.lmc_cache[port - rdma_start_port(device)] = tprops->lmc;
 
        write_unlock_irq(&device->cache.lock);
 
@@ -322,14 +311,14 @@ static void ib_cache_setup_one(struct ib_device *device)
 
        device->cache.pkey_cache =
                kmalloc(sizeof *device->cache.pkey_cache *
-                       (end_port(device) - start_port(device) + 1), GFP_KERNEL);
+                       (rdma_end_port(device) - rdma_start_port(device) + 1), GFP_KERNEL);
        device->cache.gid_cache =
                kmalloc(sizeof *device->cache.gid_cache *
-                       (end_port(device) - start_port(device) + 1), GFP_KERNEL);
+                       (rdma_end_port(device) - rdma_start_port(device) + 1), GFP_KERNEL);
 
        device->cache.lmc_cache = kmalloc(sizeof *device->cache.lmc_cache *
-                                         (end_port(device) -
-                                          start_port(device) + 1),
+                                         (rdma_end_port(device) -
+                                          rdma_start_port(device) + 1),
                                          GFP_KERNEL);
 
        if (!device->cache.pkey_cache || !device->cache.gid_cache ||
@@ -339,10 +328,10 @@ static void ib_cache_setup_one(struct ib_device *device)
                goto err;
        }
 
-       for (p = 0; p <= end_port(device) - start_port(device); ++p) {
+       for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) {
                device->cache.pkey_cache[p] = NULL;
                device->cache.gid_cache [p] = NULL;
-               ib_cache_update(device, p + start_port(device));
+               ib_cache_update(device, p + rdma_start_port(device));
        }
 
        INIT_IB_EVENT_HANDLER(&device->cache.event_handler,
@@ -353,7 +342,7 @@ static void ib_cache_setup_one(struct ib_device *device)
        return;
 
 err_cache:
-       for (p = 0; p <= end_port(device) - start_port(device); ++p) {
+       for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) {
                kfree(device->cache.pkey_cache[p]);
                kfree(device->cache.gid_cache[p]);
        }
@@ -371,7 +360,7 @@ static void ib_cache_cleanup_one(struct ib_device *device)
        ib_unregister_event_handler(&device->cache.event_handler);
        flush_workqueue(ib_wq);
 
-       for (p = 0; p <= end_port(device) - start_port(device); ++p) {
+       for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) {
                kfree(device->cache.pkey_cache[p]);
                kfree(device->cache.gid_cache[p]);
        }
index 09cc0fc..f51c6e4 100644 (file)
@@ -661,6 +661,8 @@ int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
                } else
                        ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
                                                 qp_attr_mask);
+               qp_attr->port_num = id_priv->id.port_num;
+               *qp_attr_mask |= IB_QP_PORT;
                break;
        default:
                ret = -ENOSYS;
@@ -3129,6 +3131,9 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
        struct cma_multicast *mc;
        int ret;
 
+       if (!id->device)
+               return -EINVAL;
+
        id_priv = container_of(id, struct rdma_id_private, id);
        if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) &&
            !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED))
index e711de4..df844af 100644 (file)
@@ -151,18 +151,6 @@ static int alloc_name(char *name)
        return 0;
 }
 
-static int start_port(struct ib_device *device)
-{
-       return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
-}
-
-
-static int end_port(struct ib_device *device)
-{
-       return (device->node_type == RDMA_NODE_IB_SWITCH) ?
-               0 : device->phys_port_cnt;
-}
-
 /**
  * ib_alloc_device - allocate an IB device struct
  * @size:size of structure to allocate
@@ -232,7 +220,7 @@ static int read_port_table_lengths(struct ib_device *device)
        if (!tprops)
                goto out;
 
-       num_ports = end_port(device) - start_port(device) + 1;
+       num_ports = rdma_end_port(device) - rdma_start_port(device) + 1;
 
        device->pkey_tbl_len = kmalloc(sizeof *device->pkey_tbl_len * num_ports,
                                       GFP_KERNEL);
@@ -242,7 +230,7 @@ static int read_port_table_lengths(struct ib_device *device)
                goto err;
 
        for (port_index = 0; port_index < num_ports; ++port_index) {
-               ret = ib_query_port(device, port_index + start_port(device),
+               ret = ib_query_port(device, port_index + rdma_start_port(device),
                                        tprops);
                if (ret)
                        goto err;
@@ -575,7 +563,7 @@ int ib_query_port(struct ib_device *device,
                  u8 port_num,
                  struct ib_port_attr *port_attr)
 {
-       if (port_num < start_port(device) || port_num > end_port(device))
+       if (!rdma_is_port_valid(device, port_num))
                return -EINVAL;
 
        return device->query_port(device, port_num, port_attr);
@@ -653,7 +641,7 @@ int ib_modify_port(struct ib_device *device,
        if (!device->modify_port)
                return -ENOSYS;
 
-       if (port_num < start_port(device) || port_num > end_port(device))
+       if (!rdma_is_port_valid(device, port_num))
                return -EINVAL;
 
        return device->modify_port(device, port_num, port_modify_mask,
@@ -676,8 +664,8 @@ int ib_find_gid(struct ib_device *device, union ib_gid *gid,
        union ib_gid tmp_gid;
        int ret, port, i;
 
-       for (port = start_port(device); port <= end_port(device); ++port) {
-               for (i = 0; i < device->gid_tbl_len[port - start_port(device)]; ++i) {
+       for (port = rdma_start_port(device); port <= rdma_end_port(device); ++port) {
+               for (i = 0; i < device->gid_tbl_len[port - rdma_start_port(device)]; ++i) {
                        ret = ib_query_gid(device, port, i, &tmp_gid);
                        if (ret)
                                return ret;
@@ -708,7 +696,7 @@ int ib_find_pkey(struct ib_device *device,
        int ret, i;
        u16 tmp_pkey;
 
-       for (i = 0; i < device->pkey_tbl_len[port_num - start_port(device)]; ++i) {
+       for (i = 0; i < device->pkey_tbl_len[port_num - rdma_start_port(device)]; ++i) {
                ret = ib_query_pkey(device, port_num, i, &tmp_pkey);
                if (ret)
                        return ret;
index 91e82b7..49d94c1 100644 (file)
@@ -126,7 +126,7 @@ static inline struct ucma_context *_ucma_find_context(int id,
        ctx = idr_find(&ctx_idr, id);
        if (!ctx)
                ctx = ERR_PTR(-ENOENT);
-       else if (ctx->file != file)
+       else if (ctx->file != file || !ctx->cm_id)
                ctx = ERR_PTR(-EINVAL);
        return ctx;
 }
@@ -393,6 +393,7 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
        struct rdma_ucm_create_id cmd;
        struct rdma_ucm_create_id_resp resp;
        struct ucma_context *ctx;
+       struct rdma_cm_id *cm_id;
        enum ib_qp_type qp_type;
        int ret;
 
@@ -413,9 +414,9 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
                return -ENOMEM;
 
        ctx->uid = cmd.uid;
-       ctx->cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps, qp_type);
-       if (IS_ERR(ctx->cm_id)) {
-               ret = PTR_ERR(ctx->cm_id);
+       cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps, qp_type);
+       if (IS_ERR(cm_id)) {
+               ret = PTR_ERR(cm_id);
                goto err1;
        }
 
@@ -425,14 +426,19 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
                ret = -EFAULT;
                goto err2;
        }
+
+       ctx->cm_id = cm_id;
        return 0;
 
 err2:
-       rdma_destroy_id(ctx->cm_id);
+       rdma_destroy_id(cm_id);
 err1:
        mutex_lock(&mut);
        idr_remove(&ctx_idr, ctx->id);
        mutex_unlock(&mut);
+       mutex_lock(&file->mut);
+       list_del(&ctx->list);
+       mutex_unlock(&file->mut);
        kfree(ctx);
        return ret;
 }
@@ -873,10 +879,18 @@ static ssize_t ucma_init_qp_attr(struct ucma_file *file,
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
+       if (cmd.qp_state > IB_QPS_ERR)
+               return -EINVAL;
+
        ctx = ucma_get_ctx(file, cmd.id);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
+       if (!ctx->cm_id->device) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        resp.qp_attr_mask = 0;
        memset(&qp_attr, 0, sizeof qp_attr);
        qp_attr.qp_state = cmd.qp_state;
@@ -1000,6 +1014,9 @@ static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf,
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
+       if (unlikely(cmd.optlen > KMALLOC_MAX_SIZE))
+               return -EINVAL;
+
        optval = kmalloc(cmd.optlen, GFP_KERNEL);
        if (!optval) {
                ret = -ENOMEM;
@@ -1026,7 +1043,7 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
 {
        struct rdma_ucm_notify cmd;
        struct ucma_context *ctx;
-       int ret;
+       int ret = -EINVAL;
 
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
@@ -1035,7 +1052,9 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event);
+       if (ctx->cm_id->device)
+               ret = rdma_notify(ctx->cm_id, (enum ib_event_type)cmd.event);
+
        ucma_put_ctx(ctx);
        return ret;
 }
index 7f2254e..29c01fc 100644 (file)
@@ -1192,7 +1192,7 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
                            int out_len)
 {
        struct ib_uverbs_resize_cq      cmd;
-       struct ib_uverbs_resize_cq_resp resp;
+       struct ib_uverbs_resize_cq_resp resp = {};
        struct ib_udata                 udata;
        struct ib_cq                    *cq;
        int                             ret = -EINVAL;
@@ -1790,6 +1790,12 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
                goto out;
        }
 
+       if ((cmd.attr_mask & IB_QP_PORT) &&
+           !rdma_is_port_valid(qp->device, cmd.port_num)) {
+               ret = -EINVAL;
+               goto release_qp;
+       }
+
        attr->qp_state            = cmd.qp_state;
        attr->cur_qp_state        = cmd.cur_qp_state;
        attr->path_mtu            = cmd.path_mtu;
@@ -1843,6 +1849,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
                ret = ib_modify_qp(qp, attr, modify_qp_mask(qp->qp_type, cmd.attr_mask));
        }
 
+release_qp:
        put_qp_read(qp);
 
        if (ret)
@@ -2262,6 +2269,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
                            const char __user *buf, int in_len,
                            int out_len)
 {
+       struct ib_device                *ib_dev = file->device->ib_dev;
        struct ib_uverbs_create_ah       cmd;
        struct ib_uverbs_create_ah_resp  resp;
        struct ib_uobject               *uobj;
@@ -2276,6 +2284,9 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
+       if (!rdma_is_port_valid(ib_dev, cmd.attr.port_num))
+               return -EINVAL;
+
        uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
        if (!uobj)
                return -ENOMEM;
index 1661650..a17f0fa 100644 (file)
@@ -290,6 +290,7 @@ static void ib_uverbs_release_file(struct kref *ref)
        if (atomic_dec_and_test(&file->device->refcount))
                ib_uverbs_comp_dev(file->device);
 
+       kobject_put(&file->device->kobj);
        kfree(file);
 }
 
@@ -671,7 +672,6 @@ err:
 static int ib_uverbs_close(struct inode *inode, struct file *filp)
 {
        struct ib_uverbs_file *file = filp->private_data;
-       struct ib_uverbs_device *dev = file->device;
 
        ib_uverbs_cleanup_ucontext(file, file->ucontext);
 
@@ -679,7 +679,6 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp)
                kref_put(&file->async_file->ref, ib_uverbs_release_event_file);
 
        kref_put(&file->ref, ib_uverbs_release_file);
-       kobject_put(&dev->kobj);
 
        return 0;
 }
index 45a6744..6759129 100644 (file)
@@ -1181,13 +1181,50 @@ EXPORT_SYMBOL(ib_dealloc_fmr);
 
 /* Multicast groups */
 
+static bool is_valid_mcast_lid(struct ib_qp *qp, u16 lid)
+{
+       struct ib_qp_init_attr init_attr = {};
+       struct ib_qp_attr attr = {};
+       int num_eth_ports = 0;
+       int port;
+
+       /* If QP state >= init, it is assigned to a port and we can check this
+        * port only.
+        */
+       if (!ib_query_qp(qp, &attr, IB_QP_STATE | IB_QP_PORT, &init_attr)) {
+               if (attr.qp_state >= IB_QPS_INIT) {
+                       if (qp->device->get_link_layer(qp->device, attr.port_num) !=
+                           IB_LINK_LAYER_INFINIBAND)
+                               return true;
+                       goto lid_check;
+               }
+       }
+
+       /* Can't get a quick answer, iterate over all ports */
+       for (port = 0; port < qp->device->phys_port_cnt; port++)
+               if (qp->device->get_link_layer(qp->device, port) !=
+                   IB_LINK_LAYER_INFINIBAND)
+                       num_eth_ports++;
+
+       /* If we have at lease one Ethernet port, RoCE annex declares that
+        * multicast LID should be ignored. We can't tell at this step if the
+        * QP belongs to an IB or Ethernet port.
+        */
+       if (num_eth_ports)
+               return true;
+
+       /* If all the ports are IB, we can check according to IB spec. */
+lid_check:
+       return !(lid < 0xC000 ||
+                lid == be16_to_cpu(IB_LID_PERMISSIVE));
+}
+
 int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
 {
        if (!qp->device->attach_mcast)
                return -ENOSYS;
        if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD ||
-           lid < 0xC000 ||
-           lid == be16_to_cpu(IB_LID_PERMISSIVE))
+           !is_valid_mcast_lid(qp, lid))
                return -EINVAL;
 
        return qp->device->attach_mcast(qp, gid, lid);
@@ -1199,8 +1236,7 @@ int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid)
        if (!qp->device->detach_mcast)
                return -ENOSYS;
        if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD ||
-           lid < 0xC000 ||
-           lid == be16_to_cpu(IB_LID_PERMISSIVE))
+           !is_valid_mcast_lid(qp, lid))
                return -EINVAL;
 
        return qp->device->detach_mcast(qp, gid, lid);
index 37c224f..35fa4e7 100644 (file)
@@ -795,7 +795,7 @@ static struct ib_mr *iwch_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth)
        struct iwch_mr *mhp;
        u32 mmid;
        u32 stag = 0;
-       int ret = 0;
+       int ret = -ENOMEM;
 
        php = to_iwch_pd(pd);
        rhp = php->rhp;
@@ -818,7 +818,8 @@ static struct ib_mr *iwch_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth)
        mhp->attr.state = 1;
        mmid = (stag) >> 8;
        mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
-       if (insert_handle(rhp, &rhp->mmidr, mhp, mmid))
+       ret = insert_handle(rhp, &rhp->mmidr, mhp, mmid);
+       if (ret)
                goto err3;
 
        PDBG("%s mmid 0x%x mhp %p stag 0x%x\n", __func__, mmid, mhp, stag);
index 3bd6b69..29527f6 100644 (file)
@@ -484,10 +484,10 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
                        ret = -EAGAIN;
                        goto skip_cqe;
                }
-               if (unlikely((CQE_WRID_MSN(hw_cqe) != (wq->rq.msn)))) {
+               if (unlikely(!CQE_STATUS(hw_cqe) &&
+                            CQE_WRID_MSN(hw_cqe) != wq->rq.msn)) {
                        t4_set_wq_in_error(wq);
-                       hw_cqe->header |= htonl(V_CQE_STATUS(T4_ERR_MSN));
-                       goto proc_cqe;
+                       hw_cqe->header |= cpu_to_be32(V_CQE_STATUS(T4_ERR_MSN));
                }
                goto proc_cqe;
        }
@@ -826,6 +826,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
                goto err2;
 
        if (ucontext) {
+               ret = -ENOMEM;
                mm = kmalloc(sizeof *mm, GFP_KERNEL);
                if (!mm)
                        goto err3;
index 1165949..8850b8d 100644 (file)
@@ -1047,7 +1047,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                        context->mtu_msgmax = (IB_MTU_4096 << 5) |
                                              ilog2(dev->dev->caps.max_gso_sz);
                else
-                       context->mtu_msgmax = (IB_MTU_4096 << 5) | 12;
+                       context->mtu_msgmax = (IB_MTU_4096 << 5) | 13;
        } else if (attr_mask & IB_QP_PATH_MTU) {
                if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) {
                        printk(KERN_ERR "path MTU (%u) is invalid\n",
@@ -1363,7 +1363,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
        int is_eth;
        int is_vlan = 0;
        int is_grh;
-       u16 vlan;
+       u16 vlan = 0xffff;
 
        send_size = 0;
        for (i = 0; i < wr->num_sge; ++i)
index 894afac..b338dd0 100644 (file)
@@ -365,7 +365,7 @@ int qib_make_rc_req(struct qib_qp *qp)
                case IB_WR_RDMA_WRITE:
                        if (newreq && !(qp->s_flags & QIB_S_UNLIMITED_CREDIT))
                                qp->s_lsn++;
-                       /* FALLTHROUGH */
+                       goto no_flow_control;
                case IB_WR_RDMA_WRITE_WITH_IMM:
                        /* If no credit, return. */
                        if (!(qp->s_flags & QIB_S_UNLIMITED_CREDIT) &&
@@ -373,6 +373,7 @@ int qib_make_rc_req(struct qib_qp *qp)
                                qp->s_flags |= QIB_S_WAIT_SSN_CREDIT;
                                goto bail;
                        }
+no_flow_control:
                        ohdr->u.rc.reth.vaddr =
                                cpu_to_be64(wqe->wr.wr.rdma.remote_addr);
                        ohdr->u.rc.reth.rkey =
index 74aa131..80c9a29 100644 (file)
@@ -506,7 +506,6 @@ static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id,
        case IB_CM_REQ_RECEIVED:
                return ipoib_cm_req_handler(cm_id, event);
        case IB_CM_DREQ_RECEIVED:
-               p = cm_id->context;
                ib_send_cm_drep(cm_id, NULL, 0);
                /* Fall through */
        case IB_CM_REJ_RECEIVED:
index ae3b1d2..c3d96e8 100644 (file)
@@ -1366,6 +1366,7 @@ static int __init ipoib_init_module(void)
        ipoib_sendq_size = max3(ipoib_sendq_size, 2 * MAX_SEND_CQE, IPOIB_MIN_QUEUE_SIZE);
 #ifdef CONFIG_INFINIBAND_IPOIB_CM
        ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP);
+       ipoib_max_conn_qp = max(ipoib_max_conn_qp, 0);
 #endif
 
        /*
index 8770d44..ded023c 100644 (file)
@@ -310,10 +310,19 @@ static void srp_path_rec_completion(int status,
 
 static int srp_lookup_path(struct srp_target_port *target)
 {
+       int ret = -ENODEV;
+
        target->path.numb_path = 1;
 
        init_completion(&target->done);
 
+       /*
+        * Avoid that the SCSI host can be removed by srp_remove_target()
+        * before srp_path_rec_completion() is called.
+        */
+       if (!scsi_host_get(target->scsi_host))
+               goto out;
+
        target->path_query_id = ib_sa_path_rec_get(&srp_sa_client,
                                                   target->srp_host->srp_dev->dev,
                                                   target->srp_host->port,
@@ -327,16 +336,22 @@ static int srp_lookup_path(struct srp_target_port *target)
                                                   GFP_KERNEL,
                                                   srp_path_rec_completion,
                                                   target, &target->path_query);
-       if (target->path_query_id < 0)
-               return target->path_query_id;
+       ret = target->path_query_id;
+       if (ret < 0)
+               goto put;
 
        wait_for_completion(&target->done);
 
-       if (target->status < 0)
+       ret = target->status;
+       if (ret < 0)
                shost_printk(KERN_WARNING, target->scsi_host,
                             PFX "Path record query failed\n");
 
-       return target->status;
+put:
+       scsi_host_put(target->scsi_host);
+
+out:
+       return ret;
 }
 
 static int srp_send_req(struct srp_target_port *target)
index 480eb9d..6c8df17 100644 (file)
@@ -239,9 +239,15 @@ int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file)
 EXPORT_SYMBOL_GPL(input_ff_erase);
 
 /*
- * flush_effects - erase all effects owned by a file handle
+ * input_ff_flush - erase all effects owned by a file handle
+ * @dev: input device to erase effect from
+ * @file: purported owner of the effects
+ *
+ * This function erases all force-feedback effects associated with
+ * the given owner from specified device. Note that @file may be %NULL,
+ * in which case all effects will be erased.
  */
-static int flush_effects(struct input_dev *dev, struct file *file)
+int input_ff_flush(struct input_dev *dev, struct file *file)
 {
        struct ff_device *ff = dev->ff;
        int i;
@@ -257,6 +263,7 @@ static int flush_effects(struct input_dev *dev, struct file *file)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(input_ff_flush);
 
 /**
  * input_ff_event() - generic handler for force-feedback events
@@ -340,7 +347,7 @@ int input_ff_create(struct input_dev *dev, unsigned int max_effects)
        mutex_init(&ff->mutex);
 
        dev->ff = ff;
-       dev->flush = flush_effects;
+       dev->flush = input_ff_flush;
        dev->event = input_ff_event;
        __set_bit(EV_FF, dev->evbit);
 
index 37471e0..a092c45 100644 (file)
@@ -96,7 +96,8 @@
 #define XTYPE_XBOX        0
 #define XTYPE_XBOX360     1
 #define XTYPE_XBOX360W    2
-#define XTYPE_UNKNOWN     3
+#define XTYPE_XBOXONE     3
+#define XTYPE_UNKNOWN     4
 
 static int dpad_to_buttons;
 module_param(dpad_to_buttons, bool, S_IRUGO);
@@ -118,11 +119,13 @@ static const struct xpad_device {
        u8 xtype;
 } xpad_device[] = {
        { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX },
-       { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
        { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
        { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
+       { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
+       { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
+       { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
+       { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
-       { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
        { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
        { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
        { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
@@ -136,9 +139,12 @@ static const struct xpad_device {
        { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX },
        { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", XTYPE_XBOX360 },
        { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+       { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 },
        { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
+       { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
        { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX },
        { 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
        { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
@@ -148,24 +154,28 @@ static const struct xpad_device {
        { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX },
        { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX },
        { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX },
-       { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
        { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX },
+       { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+       { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
        { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
        { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
-       { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
-       { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
+       { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
        { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
-       { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
+       { 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
        { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
-       { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
-       { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
-       { 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
+       { 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 },
+       { 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 },
+       { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
        { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
        { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
 };
@@ -221,10 +231,12 @@ static const signed short xpad_abs_triggers[] = {
        -1
 };
 
-/* Xbox 360 has a vendor-specific class, so we cannot match it with only
+/*
+ * Xbox 360 has a vendor-specific class, so we cannot match it with only
  * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
  * match against vendor id as well. Wired Xbox 360 devices have protocol 1,
- * wireless controllers have protocol 129. */
+ * wireless controllers have protocol 129.
+ */
 #define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \
        .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
        .idVendor = (vend), \
@@ -235,9 +247,20 @@ static const signed short xpad_abs_triggers[] = {
        { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \
        { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) }
 
+/* The Xbox One controller uses subclass 71 and protocol 208. */
+#define XPAD_XBOXONE_VENDOR_PROTOCOL(vend, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
+       .idVendor = (vend), \
+       .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
+       .bInterfaceSubClass = 71, \
+       .bInterfaceProtocol = (pr)
+#define XPAD_XBOXONE_VENDOR(vend) \
+       { XPAD_XBOXONE_VENDOR_PROTOCOL(vend, 208) }
+
 static struct usb_device_id xpad_table [] = {
        { USB_INTERFACE_INFO('X', 'B', 0) },    /* X-Box USB-IF not approved class */
        XPAD_XBOX360_VENDOR(0x045e),            /* Microsoft X-Box 360 controllers */
+       XPAD_XBOXONE_VENDOR(0x045e),            /* Microsoft X-Box One controllers */
        XPAD_XBOX360_VENDOR(0x046d),            /* Logitech X-Box 360 style controllers */
        XPAD_XBOX360_VENDOR(0x0738),            /* Mad Catz X-Box 360 controllers */
        { USB_DEVICE(0x0738, 0x4540) },         /* Mad Catz Beat Pad */
@@ -248,6 +271,7 @@ static struct usb_device_id xpad_table [] = {
        XPAD_XBOX360_VENDOR(0x1bad),            /* Harminix Rock Band Guitar and Drums */
        XPAD_XBOX360_VENDOR(0x0f0d),            /* Hori Controllers */
        XPAD_XBOX360_VENDOR(0x1689),            /* Razer Onza */
+       XPAD_XBOX360_VENDOR(0x24c6),            /* PowerA Controllers */
        { }
 };
 
@@ -266,12 +290,10 @@ struct usb_xpad {
        struct urb *bulk_out;
        unsigned char *bdata;
 
-#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
        struct urb *irq_out;            /* urb for interrupt out report */
        unsigned char *odata;           /* output data */
        dma_addr_t odata_dma;
        struct mutex odata_mutex;
-#endif
 
 #if defined(CONFIG_JOYSTICK_XPAD_LEDS)
        struct xpad_led *led;
@@ -462,6 +484,105 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
        xpad360_process_packet(xpad, cmd, &data[4]);
 }
 
+/*
+ *     xpadone_process_buttons
+ *
+ *     Process a button update packet from an Xbox one controller.
+ */
+static void xpadone_process_buttons(struct usb_xpad *xpad,
+                               struct input_dev *dev,
+                               unsigned char *data)
+{
+       /* menu/view buttons */
+       input_report_key(dev, BTN_START,  data[4] & 0x04);
+       input_report_key(dev, BTN_SELECT, data[4] & 0x08);
+
+       /* buttons A,B,X,Y */
+       input_report_key(dev, BTN_A,    data[4] & 0x10);
+       input_report_key(dev, BTN_B,    data[4] & 0x20);
+       input_report_key(dev, BTN_X,    data[4] & 0x40);
+       input_report_key(dev, BTN_Y,    data[4] & 0x80);
+
+       /* digital pad */
+       if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
+               /* dpad as buttons (left, right, up, down) */
+               input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & 0x04);
+               input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & 0x08);
+               input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & 0x01);
+               input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & 0x02);
+       } else {
+               input_report_abs(dev, ABS_HAT0X,
+                                !!(data[5] & 0x08) - !!(data[5] & 0x04));
+               input_report_abs(dev, ABS_HAT0Y,
+                                !!(data[5] & 0x02) - !!(data[5] & 0x01));
+       }
+
+       /* TL/TR */
+       input_report_key(dev, BTN_TL,   data[5] & 0x10);
+       input_report_key(dev, BTN_TR,   data[5] & 0x20);
+
+       /* stick press left/right */
+       input_report_key(dev, BTN_THUMBL, data[5] & 0x40);
+       input_report_key(dev, BTN_THUMBR, data[5] & 0x80);
+
+       if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+               /* left stick */
+               input_report_abs(dev, ABS_X,
+                                (__s16) le16_to_cpup((__le16 *)(data + 10)));
+               input_report_abs(dev, ABS_Y,
+                                ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+
+               /* right stick */
+               input_report_abs(dev, ABS_RX,
+                                (__s16) le16_to_cpup((__le16 *)(data + 14)));
+               input_report_abs(dev, ABS_RY,
+                                ~(__s16) le16_to_cpup((__le16 *)(data + 16)));
+       }
+
+       /* triggers left/right */
+       if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+               input_report_key(dev, BTN_TL2,
+                                (__u16) le16_to_cpup((__le16 *)(data + 6)));
+               input_report_key(dev, BTN_TR2,
+                                (__u16) le16_to_cpup((__le16 *)(data + 8)));
+       } else {
+               input_report_abs(dev, ABS_Z,
+                                (__u16) le16_to_cpup((__le16 *)(data + 6)));
+               input_report_abs(dev, ABS_RZ,
+                                (__u16) le16_to_cpup((__le16 *)(data + 8)));
+       }
+
+       input_sync(dev);
+}
+
+/*
+ *     xpadone_process_packet
+ *
+ *     Completes a request by converting the data into events for the
+ *     input subsystem. This version is for the Xbox One controller.
+ *
+ *     The report format was gleaned from
+ *     https://github.com/kylelemons/xbox/blob/master/xbox.go
+ */
+
+static void xpadone_process_packet(struct usb_xpad *xpad,
+                               u16 cmd, unsigned char *data)
+{
+       struct input_dev *dev = xpad->dev;
+
+       switch (data[0]) {
+       case 0x20:
+               xpadone_process_buttons(xpad, dev, data);
+               break;
+
+       case 0x07:
+               /* the xbox button has its own special report */
+               input_report_key(dev, BTN_MODE, data[4] & 0x01);
+               input_sync(dev);
+               break;
+       }
+}
+
 static void xpad_irq_in(struct urb *urb)
 {
        struct usb_xpad *xpad = urb->context;
@@ -493,6 +614,9 @@ static void xpad_irq_in(struct urb *urb)
        case XTYPE_XBOX360W:
                xpad360w_process_packet(xpad, 0, xpad->idata);
                break;
+       case XTYPE_XBOXONE:
+               xpadone_process_packet(xpad, 0, xpad->idata);
+               break;
        default:
                xpad_process_packet(xpad, 0, xpad->idata);
        }
@@ -521,7 +645,6 @@ static void xpad_bulk_out(struct urb *urb)
        }
 }
 
-#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
 static void xpad_irq_out(struct urb *urb)
 {
        int retval, status;
@@ -552,9 +675,9 @@ exit:
                    __func__, retval);
 }
 
-static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad,
+                       struct usb_endpoint_descriptor *ep_irq_out)
 {
-       struct usb_endpoint_descriptor *ep_irq_out;
        int error;
 
        if (xpad->xtype == XTYPE_UNKNOWN)
@@ -575,7 +698,6 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
                goto fail2;
        }
 
-       ep_irq_out = &intf->cur_altsetting->endpoint[1].desc;
        usb_fill_int_urb(xpad->irq_out, xpad->udev,
                         usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress),
                         xpad->odata, XPAD_PKT_LEN,
@@ -603,11 +725,6 @@ static void xpad_deinit_output(struct usb_xpad *xpad)
                                xpad->odata, xpad->odata_dma);
        }
 }
-#else
-static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
-static void xpad_deinit_output(struct usb_xpad *xpad) {}
-static void xpad_stop_output(struct usb_xpad *xpad) {}
-#endif
 
 #ifdef CONFIG_JOYSTICK_XPAD_FF
 static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
@@ -673,7 +790,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
 
 static int xpad_init_ff(struct usb_xpad *xpad)
 {
-       if (xpad->xtype == XTYPE_UNKNOWN)
+       if (xpad->xtype == XTYPE_UNKNOWN || xpad->xtype == XTYPE_XBOXONE)
                return 0;
 
        input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
@@ -782,6 +899,14 @@ static int xpad_open(struct input_dev *dev)
        if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
                return -EIO;
 
+       if (xpad->xtype == XTYPE_XBOXONE) {
+               /* Xbox one controller needs to be initialized. */
+               xpad->odata[0] = 0x05;
+               xpad->odata[1] = 0x20;
+               xpad->irq_out->transfer_buffer_length = 2;
+               return usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+       }
+
        return 0;
 }
 
@@ -797,6 +922,7 @@ static void xpad_close(struct input_dev *dev)
 
 static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
 {
+       struct usb_xpad *xpad = input_get_drvdata(input_dev);
        set_bit(abs, input_dev->absbit);
 
        switch (abs) {
@@ -808,7 +934,10 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
                break;
        case ABS_Z:
        case ABS_RZ:    /* the triggers (if mapped to axes) */
-               input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
+               if (xpad->xtype == XTYPE_XBOXONE)
+                       input_set_abs_params(input_dev, abs, 0, 1023, 0, 0);
+               else
+                       input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
                break;
        case ABS_HAT0X:
        case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */
@@ -822,7 +951,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        struct usb_device *udev = interface_to_usbdev(intf);
        struct usb_xpad *xpad;
        struct input_dev *input_dev;
-       struct usb_endpoint_descriptor *ep_irq_in;
+       struct usb_endpoint_descriptor *ep_irq_in, *ep_irq_out;
        int i, error;
 
        if (intf->cur_altsetting->desc.bNumEndpoints != 2)
@@ -834,6 +963,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                        break;
        }
 
+       if (xpad_device[i].xtype == XTYPE_XBOXONE &&
+           intf->cur_altsetting->desc.bInterfaceNumber != 0) {
+               /*
+                * The Xbox One controller lists three interfaces all with the
+                * same interface class, subclass and protocol. Differentiate by
+                * interface number.
+                */
+               return -ENODEV;
+       }
+
        xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!xpad || !input_dev) {
@@ -903,7 +1042,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                __set_bit(xpad_common_btn[i], input_dev->keybit);
 
        /* set up model-specific ones */
-       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
+       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W ||
+           xpad->xtype == XTYPE_XBOXONE) {
                for (i = 0; xpad360_btn[i] >= 0; i++)
                        __set_bit(xpad360_btn[i], input_dev->keybit);
        } else {
@@ -916,7 +1056,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                        __set_bit(xpad_btn_pad[i], input_dev->keybit);
        } else {
                for (i = 0; xpad_abs_pad[i] >= 0; i++)
-                   xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
+                       xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
        }
 
        if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -927,7 +1067,26 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                        xpad_set_up_abs(input_dev, xpad_abs_triggers[i]);
        }
 
-       error = xpad_init_output(intf, xpad);
+       ep_irq_in = ep_irq_out = NULL;
+
+       for (i = 0; i < 2; i++) {
+               struct usb_endpoint_descriptor *ep =
+                               &intf->cur_altsetting->endpoint[i].desc;
+
+               if (usb_endpoint_xfer_int(ep)) {
+                       if (usb_endpoint_dir_in(ep))
+                               ep_irq_in = ep;
+                       else
+                               ep_irq_out = ep;
+               }
+       }
+
+       if (!ep_irq_in || !ep_irq_out) {
+               error = -ENODEV;
+               goto fail3;
+       }
+
+       error = xpad_init_output(intf, xpad, ep_irq_out);
        if (error)
                goto fail3;
 
@@ -939,7 +1098,6 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        if (error)
                goto fail5;
 
-       ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
        usb_fill_int_urb(xpad->irq_in, udev,
                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
                         xpad->idata, XPAD_PKT_LEN, xpad_irq_in,
index e2ae657..4389ed3 100644 (file)
@@ -214,8 +214,10 @@ static void matrix_keypad_stop(struct input_dev *dev)
 {
        struct matrix_keypad *keypad = input_get_drvdata(dev);
 
+       spin_lock_irq(&keypad->lock);
        keypad->stopped = true;
-       mb();
+       spin_unlock_irq(&keypad->lock);
+
        flush_work(&keypad->work.work);
        /*
         * matrix_keypad_scan() will leave IRQs enabled;
index 0924480..89b2f5b 100644 (file)
@@ -797,7 +797,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
 
        if (pdata->watermark) {
                ac->int_mask |= WATERMARK;
-               if (!FIFO_MODE(pdata->fifo_mode))
+               if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
                        ac->pdata.fifo_mode |= FIFO_STREAM;
        } else {
                ac->int_mask |= DATA_READY;
index f236a29..2a57de5 100644 (file)
@@ -218,6 +218,18 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
        return retval;
 }
 
+static int uinput_dev_flush(struct input_dev *dev, struct file *file)
+{
+       /*
+        * If we are called with file == NULL that means we are tearing
+        * down the device, and therefore we can not handle FF erase
+        * requests: either we are handling UI_DEV_DESTROY (and holding
+        * the udev->mutex), or the file descriptor is closed and there is
+        * nobody on the other side anymore.
+        */
+       return file ? input_ff_flush(dev, file) : 0;
+}
+
 static void uinput_destroy_device(struct uinput_device *udev)
 {
        const char *name, *phys;
@@ -261,6 +273,12 @@ static int uinput_create_device(struct uinput_device *udev)
                dev->ff->playback = uinput_dev_playback;
                dev->ff->set_gain = uinput_dev_set_gain;
                dev->ff->set_autocenter = uinput_dev_set_autocenter;
+               /*
+                * The standard input_ff_flush() implementation does
+                * not quite work for uinput as we can't reasonably
+                * handle FF requests during device teardown.
+                */
+               dev->flush = uinput_dev_flush;
        }
 
        error = input_register_device(udev->dev);
index 537692d..62e9e5e 100644 (file)
@@ -1284,7 +1284,7 @@ static int elantech_set_properties(struct elantech_data *etd)
                case 5:
                        etd->hw_version = 3;
                        break;
-               case 6 ... 14:
+               case 6 ... 15:
                        etd->hw_version = 4;
                        break;
                default:
index 54b2fa8..46c6145 100644 (file)
@@ -186,7 +186,8 @@ static int trackpoint_start_protocol(struct psmouse *psmouse, unsigned char *fir
        if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
                return -1;
 
-       if (param[0] != TP_MAGIC_IDENT)
+       /* add new TP ID. */
+       if (!(param[0] & TP_MAGIC_IDENT))
                return -1;
 
        if (firmware_id)
@@ -297,8 +298,11 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
                return 0;
 
        if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
-               printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n");
-               button_info = 0;
+               printk(KERN_WARNING "trackpoint.c: failed to get extended button data, assuming 3 buttons\n");
+               button_info = 0x33;
+       } else if (!button_info) {
+               printk(KERN_WARNING "trackpoint.c: got 0 in extended button data, assuming 3 buttons\n");
+               button_info = 0x33;
        }
 
        psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
index e558a70..bdee131 100644 (file)
@@ -21,8 +21,9 @@
 #define TP_COMMAND             0xE2    /* Commands start with this */
 
 #define TP_READ_ID             0xE1    /* Sent for device identification */
-#define TP_MAGIC_IDENT         0x01    /* Sent after a TP_READ_ID followed */
+#define TP_MAGIC_IDENT         0x03    /* Sent after a TP_READ_ID followed */
                                        /* by the firmware ID */
+                                       /* Firmware ID includes 0x1, 0x2, 0x3 */
 
 
 /*
index 961e56b..a045869 100644 (file)
@@ -789,6 +789,13 @@ static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "P34"),
                },
        },
+       {
+               /* Gigabyte P57 - Elantech touchpad */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "P57"),
+               },
+       },
        {
                /* Schenker XMG C504 - Elantech touchpad */
                .matches = {
index 1284b92..1233bb4 100644 (file)
@@ -390,8 +390,10 @@ static int i8042_start(struct serio *serio)
 {
        struct i8042_port *port = serio->port_data;
 
+       spin_lock_irq(&i8042_lock);
        port->exists = true;
-       mb();
+       spin_unlock_irq(&i8042_lock);
+
        return 0;
 }
 
@@ -404,16 +406,20 @@ static void i8042_stop(struct serio *serio)
 {
        struct i8042_port *port = serio->port_data;
 
+       spin_lock_irq(&i8042_lock);
        port->exists = false;
+       port->serio = NULL;
+       spin_unlock_irq(&i8042_lock);
 
        /*
+        * We need to make sure that interrupt handler finishes using
+        * our serio port before we return from this function.
         * We synchronize with both AUX and KBD IRQs because there is
         * a (very unlikely) chance that AUX IRQ is raised for KBD port
         * and vice versa.
         */
        synchronize_irq(I8042_AUX_IRQ);
        synchronize_irq(I8042_KBD_IRQ);
-       port->serio = NULL;
 }
 
 /*
@@ -530,7 +536,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
 
        spin_unlock_irqrestore(&i8042_lock, flags);
 
-       if (likely(port->exists && !filtered))
+       if (likely(serio && !filtered))
                serio_interrupt(serio, data, dfl);
 
  out:
index 929215a..ce26a82 100644 (file)
@@ -232,13 +232,17 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
 
        /* Walk  this report and pull out the info we need */
        while (i < length) {
-               prefix = report[i];
-
-               /* Skip over prefix */
-               i++;
+               prefix = report[i++];
 
                /* Determine data size and save the data in the proper variable */
-               size = PREF_SIZE(prefix);
+               size = (1U << PREF_SIZE(prefix)) >> 1;
+               if (i + size > length) {
+                       dev_err(&device->usbdev->dev,
+                               "Not enough data (need %d, have %d)\n",
+                               i + size, length);
+                       break;
+               }
+
                switch (size) {
                case 1:
                        data = report[i];
@@ -246,8 +250,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
                case 2:
                        data16 = get_unaligned_le16(&report[i]);
                        break;
-               case 3:
-                       size = 4;
+               case 4:
                        data32 = get_unaligned_le32(&report[i]);
                        break;
                }
index a803690..94e8fc4 100644 (file)
@@ -2772,6 +2772,7 @@ static int amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
        mutex_unlock(&domain->api_lock);
 
        domain_flush_tlb_pde(domain);
+       domain_flush_complete(domain);
 
        return get_order(unmap_size);
 }
index 41b7464..ff037bb 100644 (file)
@@ -1783,10 +1783,12 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                uint64_t tmp;
 
                if (!sg_res) {
+                       unsigned int pgoff = sg->offset & ~PAGE_MASK;
+
                        sg_res = aligned_nrpages(sg->offset, sg->length);
-                       sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
+                       sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + pgoff;
                        sg->dma_length = sg->length;
-                       pteval = page_to_phys(sg_page(sg)) | prot;
+                       pteval = (sg_phys(sg) - pgoff) | prot;
                        phys_pfn = pteval >> VTD_PAGE_SHIFT;
                }
 
@@ -3085,7 +3087,7 @@ static int intel_nontranslate_map_sg(struct device *hddev,
 
        for_each_sg(sglist, sg, nelems, i) {
                BUG_ON(!sg_page(sg));
-               sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
+               sg->dma_address = sg_phys(sg);
                sg->dma_length = sg->length;
        }
        return nelems;
index 08c2329..ba45c77 100644 (file)
@@ -306,6 +306,7 @@ static inline void dump_rawmsg(enum debuglevel level, const char *tag,
  * format CAPI IE as string
  */
 
+#ifdef CONFIG_GIGASET_DEBUG
 static const char *format_ie(const char *ie)
 {
        static char result[3*MAX_FMT_IE_LEN];
@@ -331,6 +332,7 @@ static const char *format_ie(const char *ie)
        *--pout = 0;
        return result;
 }
+#endif
 
 /*
  * emit DATA_B3_CONF message
index 7ebcccd..27ecd61 100644 (file)
@@ -117,7 +117,7 @@ typedef struct api_profile_s {
 /*------------------------------------------------------------------*/
         /* ALERT-REQUEST                                            */
 typedef struct {
-  byte structs[1];      /* Additional Info */
+  byte structs[0];      /* Additional Info */
 } _ALT_REQP;
         /* ALERT-CONFIRM                                            */
 typedef struct {
@@ -126,7 +126,7 @@ typedef struct {
         /* CONNECT-REQUEST                                          */
 typedef struct {
   word CIP_Value;
-  byte structs[1];      /* Called party number,
+  byte structs[0];      /* Called party number,
                            Called party subaddress,
                            Calling party number,
                            Calling party subaddress,
@@ -143,7 +143,7 @@ typedef struct {
         /* CONNECT-INDICATION                                       */
 typedef struct {
   word CIP_Value;
-  byte structs[1];      /* Called party number,
+  byte structs[0];      /* Called party number,
                            Called party subaddress,
                            Calling party number,
                            Calling party subaddress,
@@ -155,24 +155,24 @@ typedef struct {
         /* CONNECT-RESPONSE                                         */
 typedef struct {
   word Accept;
-  byte structs[1];      /* B_protocol,
+  byte structs[0];      /* B_protocol,
                            Connected party number,
                            Connected party subaddress,
                            LLC */
 } _CON_RESP;
         /* CONNECT-ACTIVE-INDICATION                                */
 typedef struct {
-  byte structs[1];      /* Connected party number,
+  byte structs[0];      /* Connected party number,
                            Connected party subaddress,
                            LLC */
 } _CON_A_INDP;
         /* CONNECT-ACTIVE-RESPONSE                                  */
 typedef struct {
-  byte structs[1];      /* empty */
+  byte structs[0];      /* empty */
 } _CON_A_RESP;
         /* DISCONNECT-REQUEST                                       */
 typedef struct {
-  byte structs[1];      /* Additional Info */
+  byte structs[0];      /* Additional Info */
 } _DIS_REQP;
         /* DISCONNECT-CONFIRM                                       */
 typedef struct {
@@ -184,13 +184,13 @@ typedef struct {
 } _DIS_INDP;
         /* DISCONNECT-RESPONSE                                      */
 typedef struct {
-  byte structs[1];      /* empty */
+  byte structs[0];      /* empty */
 } _DIS_RESP;
         /* LISTEN-REQUEST                                           */
 typedef struct {
   dword Info_Mask;
   dword CIP_Mask;
-  byte structs[1];      /* Calling party number,
+  byte structs[0];      /* Calling party number,
                            Calling party subaddress */
 } _LIS_REQP;
         /* LISTEN-CONFIRM                                           */
@@ -199,7 +199,7 @@ typedef struct {
 } _LIS_CONP;
         /* INFO-REQUEST                                             */
 typedef struct {
-  byte structs[1];      /* Called party number,
+  byte structs[0];      /* Called party number,
                            Additional Info */
 } _INF_REQP;
         /* INFO-CONFIRM                                             */
@@ -209,15 +209,15 @@ typedef struct {
         /* INFO-INDICATION                                          */
 typedef struct {
   word Number;
-  byte structs[1];      /* Info element */
+  byte structs[0];      /* Info element */
 } _INF_INDP;
         /* INFO-RESPONSE                                            */
 typedef struct {
-  byte structs[1];      /* empty */
+  byte structs[0];      /* empty */
 } _INF_RESP;
         /* SELECT-B-REQUEST                                         */
 typedef struct {
-  byte structs[1];      /* B-protocol */
+  byte structs[0];      /* B-protocol */
 } _SEL_B_REQP;
         /* SELECT-B-CONFIRM                                         */
 typedef struct {
@@ -226,7 +226,7 @@ typedef struct {
         /* FACILITY-REQUEST */
 typedef struct {
   word Selector;
-  byte structs[1];      /* Facility parameters */
+  byte structs[0];      /* Facility parameters */
 } _FAC_REQP;
         /* FACILITY-CONFIRM STRUCT FOR SUPPLEMENT. SERVICES */
 typedef struct {
@@ -240,21 +240,21 @@ typedef struct {
 typedef struct {
   word Info;
   word Selector;
-  byte structs[1];      /* Facility parameters */
+  byte structs[0];      /* Facility parameters */
 } _FAC_CONP;
         /* FACILITY-INDICATION */
 typedef struct {
   word Selector;
-  byte structs[1];      /* Facility parameters */
+  byte structs[0];      /* Facility parameters */
 } _FAC_INDP;
         /* FACILITY-RESPONSE */
 typedef struct {
   word Selector;
-  byte structs[1];      /* Facility parameters */
+  byte structs[0];      /* Facility parameters */
 } _FAC_RESP;
         /* CONNECT-B3-REQUEST                                       */
 typedef struct {
-  byte structs[1];      /* NCPI */
+  byte structs[0];      /* NCPI */
 } _CON_B3_REQP;
         /* CONNECT-B3-CONFIRM                                       */
 typedef struct {
@@ -262,24 +262,24 @@ typedef struct {
 } _CON_B3_CONP;
         /* CONNECT-B3-INDICATION                                    */
 typedef struct {
-  byte structs[1];      /* NCPI */
+  byte structs[0];      /* NCPI */
 } _CON_B3_INDP;
         /* CONNECT-B3-RESPONSE                                      */
 typedef struct {
   word Accept;
-  byte structs[1];      /* NCPI */
+  byte structs[0];      /* NCPI */
 } _CON_B3_RESP;
         /* CONNECT-B3-ACTIVE-INDICATION                             */
 typedef struct {
-  byte structs[1];      /* NCPI */
+  byte structs[0];      /* NCPI */
 } _CON_B3_A_INDP;
         /* CONNECT-B3-ACTIVE-RESPONSE                               */
 typedef struct {
-  byte structs[1];      /* empty */
+  byte structs[0];      /* empty */
 } _CON_B3_A_RESP;
         /* DISCONNECT-B3-REQUEST                                    */
 typedef struct {
-  byte structs[1];      /* NCPI */
+  byte structs[0];      /* NCPI */
 } _DIS_B3_REQP;
         /* DISCONNECT-B3-CONFIRM                                    */
 typedef struct {
@@ -288,11 +288,11 @@ typedef struct {
         /* DISCONNECT-B3-INDICATION                                 */
 typedef struct {
   word Info;
-  byte structs[1];      /* NCPI */
+  byte structs[0];      /* NCPI */
 } _DIS_B3_INDP;
         /* DISCONNECT-B3-RESPONSE                                   */
 typedef struct {
-  byte structs[1];      /* empty */
+  byte structs[0];      /* empty */
 } _DIS_B3_RESP;
         /* DATA-B3-REQUEST                                          */
 typedef struct {
@@ -335,7 +335,7 @@ typedef struct {
 } _DAT_B3_RESP;
         /* RESET-B3-REQUEST                                         */
 typedef struct {
-  byte structs[1];      /* NCPI */
+  byte structs[0];      /* NCPI */
 } _RES_B3_REQP;
         /* RESET-B3-CONFIRM                                         */
 typedef struct {
@@ -343,20 +343,20 @@ typedef struct {
 } _RES_B3_CONP;
         /* RESET-B3-INDICATION                                      */
 typedef struct {
-  byte structs[1];      /* NCPI */
+  byte structs[0];      /* NCPI */
 } _RES_B3_INDP;
         /* RESET-B3-RESPONSE                                        */
 typedef struct {
-  byte structs[1];      /* empty */
+  byte structs[0];      /* empty */
 } _RES_B3_RESP;
         /* CONNECT-B3-T90-ACTIVE-INDICATION                         */
 typedef struct {
-  byte structs[1];      /* NCPI */
+  byte structs[0];      /* NCPI */
 } _CON_B3_T90_A_INDP;
         /* CONNECT-B3-T90-ACTIVE-RESPONSE                           */
 typedef struct {
   word Reject;
-  byte structs[1];      /* NCPI */
+  byte structs[0];      /* NCPI */
 } _CON_B3_T90_A_RESP;
 /*------------------------------------------------------------------*/
 /* message structure                                                */
index 3261de1..d5db9ac 100644 (file)
@@ -2316,8 +2316,8 @@ _hfcpci_softirq(struct device *dev, void *arg)
 static void
 hfcpci_softirq(void *arg)
 {
-       (void) driver_for_each_device(&hfc_driver.driver, NULL, arg,
-                                       _hfcpci_softirq);
+       WARN_ON_ONCE(driver_for_each_device(&hfc_driver.driver, NULL, arg,
+                                     _hfcpci_softirq) != 0);
 
        /* if next event would be in the past ... */
        if ((s32)(hfc_jiffies + tics - jiffies) <= 0)
index 3bf7267..ec24a1c 100644 (file)
@@ -839,7 +839,8 @@ static void __get_memory_limit(struct dm_bufio_client *c,
                buffers = DM_BUFIO_MIN_BUFFERS;
 
        *limit_buffers = buffers;
-       *threshold_buffers = buffers * DM_BUFIO_WRITEBACK_PERCENT / 100;
+       *threshold_buffers = mult_frac(buffers,
+                                      DM_BUFIO_WRITEBACK_PERCENT, 100);
 }
 
 /*
@@ -1620,19 +1621,15 @@ static int __init dm_bufio_init(void)
        memset(&dm_bufio_caches, 0, sizeof dm_bufio_caches);
        memset(&dm_bufio_cache_names, 0, sizeof dm_bufio_cache_names);
 
-       mem = (__u64)((totalram_pages - totalhigh_pages) *
-                     DM_BUFIO_MEMORY_PERCENT / 100) << PAGE_SHIFT;
+       mem = (__u64)mult_frac(totalram_pages - totalhigh_pages,
+                              DM_BUFIO_MEMORY_PERCENT, 100) << PAGE_SHIFT;
 
        if (mem > ULONG_MAX)
                mem = ULONG_MAX;
 
 #ifdef CONFIG_MMU
-       /*
-        * Get the size of vmalloc space the same way as VMALLOC_TOTAL
-        * in fs/proc/internal.h
-        */
-       if (mem > (VMALLOC_END - VMALLOC_START) * DM_BUFIO_VMALLOC_PERCENT / 100)
-               mem = (VMALLOC_END - VMALLOC_START) * DM_BUFIO_VMALLOC_PERCENT / 100;
+       if (mem > mult_frac(VMALLOC_END - VMALLOC_START, DM_BUFIO_VMALLOC_PERCENT, 100))
+               mem = mult_frac(VMALLOC_END - VMALLOC_START, DM_BUFIO_VMALLOC_PERCENT, 100);
 #endif
 
        dm_bufio_default_cache_size = mem;
index 84ad530..dd0c882 100644 (file)
@@ -1658,19 +1658,11 @@ static int __init dm_multipath_init(void)
        if (!_mpio_cache)
                return -ENOMEM;
 
-       r = dm_register_target(&multipath_target);
-       if (r < 0) {
-               DMERR("register failed %d", r);
-               kmem_cache_destroy(_mpio_cache);
-               return -EINVAL;
-       }
-
        kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0);
        if (!kmultipathd) {
                DMERR("failed to create workqueue kmpathd");
-               dm_unregister_target(&multipath_target);
-               kmem_cache_destroy(_mpio_cache);
-               return -ENOMEM;
+               r = -ENOMEM;
+               goto bad_alloc_kmultipathd;
        }
 
        /*
@@ -1683,16 +1675,30 @@ static int __init dm_multipath_init(void)
                                                  WQ_MEM_RECLAIM);
        if (!kmpath_handlerd) {
                DMERR("failed to create workqueue kmpath_handlerd");
-               destroy_workqueue(kmultipathd);
-               dm_unregister_target(&multipath_target);
-               kmem_cache_destroy(_mpio_cache);
-               return -ENOMEM;
+               r = -ENOMEM;
+               goto bad_alloc_kmpath_handlerd;
+       }
+
+       r = dm_register_target(&multipath_target);
+       if (r < 0) {
+               DMERR("register failed %d", r);
+               r = -EINVAL;
+               goto bad_register_target;
        }
 
        DMINFO("version %u.%u.%u loaded",
               multipath_target.version[0], multipath_target.version[1],
               multipath_target.version[2]);
 
+       return 0;
+
+bad_register_target:
+       destroy_workqueue(kmpath_handlerd);
+bad_alloc_kmpath_handlerd:
+       destroy_workqueue(kmultipathd);
+bad_alloc_kmultipathd:
+       kmem_cache_destroy(_mpio_cache);
+
        return r;
 }
 
index 6674ebf..5d6b533 100644 (file)
@@ -2293,24 +2293,6 @@ static int __init dm_snapshot_init(void)
                return r;
        }
 
-       r = dm_register_target(&snapshot_target);
-       if (r < 0) {
-               DMERR("snapshot target register failed %d", r);
-               goto bad_register_snapshot_target;
-       }
-
-       r = dm_register_target(&origin_target);
-       if (r < 0) {
-               DMERR("Origin target register failed %d", r);
-               goto bad_register_origin_target;
-       }
-
-       r = dm_register_target(&merge_target);
-       if (r < 0) {
-               DMERR("Merge target register failed %d", r);
-               goto bad_register_merge_target;
-       }
-
        r = init_origin_hash();
        if (r) {
                DMERR("init_origin_hash failed.");
@@ -2338,8 +2320,32 @@ static int __init dm_snapshot_init(void)
                goto bad_tracked_chunk_cache;
        }
 
+       r = dm_register_target(&snapshot_target);
+       if (r < 0) {
+               DMERR("snapshot target register failed %d", r);
+               goto bad_register_snapshot_target;
+       }
+
+       r = dm_register_target(&origin_target);
+       if (r < 0) {
+               DMERR("Origin target register failed %d", r);
+               goto bad_register_origin_target;
+       }
+
+       r = dm_register_target(&merge_target);
+       if (r < 0) {
+               DMERR("Merge target register failed %d", r);
+               goto bad_register_merge_target;
+       }
+
        return 0;
 
+bad_register_merge_target:
+       dm_unregister_target(&origin_target);
+bad_register_origin_target:
+       dm_unregister_target(&snapshot_target);
+bad_register_snapshot_target:
+       kmem_cache_destroy(tracked_chunk_cache);
 bad_tracked_chunk_cache:
        kmem_cache_destroy(pending_cache);
 bad_pending_cache:
@@ -2347,12 +2353,6 @@ bad_pending_cache:
 bad_exception_cache:
        exit_origin_hash();
 bad_origin_hash:
-       dm_unregister_target(&merge_target);
-bad_register_merge_target:
-       dm_unregister_target(&origin_target);
-bad_register_origin_target:
-       dm_unregister_target(&snapshot_target);
-bad_register_snapshot_target:
        dm_exception_store_exit();
 
        return r;
index 0d0bc04..5ec0239 100644 (file)
@@ -1584,12 +1584,12 @@ struct mapped_device *dm_table_get_md(struct dm_table *t)
 }
 EXPORT_SYMBOL(dm_table_get_md);
 
-static int device_discard_capable(struct dm_target *ti, struct dm_dev *dev,
-                                 sector_t start, sector_t len, void *data)
+static int device_not_discard_capable(struct dm_target *ti, struct dm_dev *dev,
+                                     sector_t start, sector_t len, void *data)
 {
        struct request_queue *q = bdev_get_queue(dev->bdev);
 
-       return q && blk_queue_discard(q);
+       return q && !blk_queue_discard(q);
 }
 
 bool dm_table_supports_discards(struct dm_table *t)
@@ -1597,26 +1597,22 @@ bool dm_table_supports_discards(struct dm_table *t)
        struct dm_target *ti;
        unsigned i = 0;
 
-       /*
-        * Unless any target used by the table set discards_supported,
-        * require at least one underlying device to support discards.
-        * t->devices includes internal dm devices such as mirror logs
-        * so we need to use iterate_devices here, which targets
-        * supporting discard selectively must provide.
-        */
        while (i < dm_table_get_num_targets(t)) {
                ti = dm_table_get_target(t, i++);
 
                if (!ti->num_discard_requests)
-                       continue;
+                       return false;
 
-               if (ti->discards_supported)
-                       return 1;
-
-               if (ti->type->iterate_devices &&
-                   ti->type->iterate_devices(ti, device_discard_capable, NULL))
-                       return 1;
+               /*
+                * Either the target provides discard support (as implied by setting
+                * 'discards_supported') or it relies on _all_ data devices having
+                * discard support.
+                */
+               if (!ti->discards_supported &&
+                   (!ti->type->iterate_devices ||
+                    ti->type->iterate_devices(ti, device_not_discard_capable, NULL)))
+                       return false;
        }
 
-       return 0;
+       return true;
 }
index 237571a..b2ad14e 100644 (file)
 #define THIN_METADATA_CACHE_SIZE 64
 #define SECTOR_TO_BLOCK_SHIFT 3
 
+/*
+ * For btree insert:
+ *  3 for btree insert +
+ *  2 for btree lookup used within space map
+ * For btree remove:
+ *  2 for shadow spine +
+ *  4 for rebalance 3 child node
+ */
+#define THIN_MAX_CONCURRENT_LOCKS 6
+
 /* This should be plenty */
 #define SPACE_MAP_ROOT_SIZE 128
 
@@ -669,13 +679,9 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,
                return ERR_PTR(-ENOMEM);
        }
 
-       /*
-        * Max hex locks:
-        *  3 for btree insert +
-        *  2 for btree lookup used within space map
-        */
        bm = dm_block_manager_create(bdev, THIN_METADATA_BLOCK_SIZE,
-                                    THIN_METADATA_CACHE_SIZE, 5);
+                                    THIN_METADATA_CACHE_SIZE,
+                                    THIN_MAX_CONCURRENT_LOCKS);
        if (!bm) {
                DMERR("could not create block manager");
                kfree(pmd);
index c00bcdc..d7e6399 100644 (file)
 
 #define DM_MSG_PREFIX "core"
 
-#ifdef CONFIG_PRINTK
-/*
- * ratelimit state to be used in DMXXX_LIMIT().
- */
-DEFINE_RATELIMIT_STATE(dm_ratelimit_state,
-                      DEFAULT_RATELIMIT_INTERVAL,
-                      DEFAULT_RATELIMIT_BURST);
-EXPORT_SYMBOL(dm_ratelimit_state);
-#endif
-
 /*
  * Cookies are numeric values sent with CHANGE and REMOVE
  * uevents while resuming, removing or renaming the device.
@@ -2695,11 +2685,15 @@ struct mapped_device *dm_get_from_kobject(struct kobject *kobj)
 
        md = container_of(kobj, struct mapped_device, kobj_holder.kobj);
 
-       if (test_bit(DMF_FREEING, &md->flags) ||
-           dm_deleting_md(md))
-               return NULL;
-
+       spin_lock(&_minor_lock);
+       if (test_bit(DMF_FREEING, &md->flags) || dm_deleting_md(md)) {
+               md = NULL;
+               goto out;
+       }
        dm_get(md);
+out:
+       spin_unlock(&_minor_lock);
+
        return md;
 }
 
index a8f4f7e..008231f 100644 (file)
@@ -568,23 +568,8 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
        pn->keys[1] = rn->keys[0];
        memcpy_disk(value_ptr(pn, 1, sizeof(__le64)), &val, sizeof(__le64));
 
-       /*
-        * rejig the spine.  This is ugly, since it knows too
-        * much about the spine
-        */
-       if (s->nodes[0] != new_parent) {
-               unlock_block(s->info, s->nodes[0]);
-               s->nodes[0] = new_parent;
-       }
-       if (key < le64_to_cpu(rn->keys[0])) {
-               unlock_block(s->info, right);
-               s->nodes[1] = left;
-       } else {
-               unlock_block(s->info, left);
-               s->nodes[1] = right;
-       }
-       s->count = 2;
-
+       unlock_block(s->info, left);
+       unlock_block(s->info, right);
        return 0;
 }
 
index 7b75a19..308e8c8 100644 (file)
@@ -875,13 +875,16 @@ static void make_request(struct mddev *mddev, struct bio * bio)
                 */
                DEFINE_WAIT(w);
                for (;;) {
-                       flush_signals(current);
+                       sigset_t full, old;
                        prepare_to_wait(&conf->wait_barrier,
                                        &w, TASK_INTERRUPTIBLE);
                        if (bio->bi_sector + bio->bi_size/512 <= mddev->suspend_lo ||
                            bio->bi_sector >= mddev->suspend_hi)
                                break;
+                       sigfillset(&full);
+                       sigprocmask(SIG_BLOCK, &full, &old);
                        schedule();
+                       sigprocmask(SIG_SETMASK, &old, NULL);
                }
                finish_wait(&conf->wait_barrier, &w);
        }
index 6056ee7..2682eb9 100644 (file)
@@ -3823,12 +3823,16 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                                 * userspace, we want an interruptible
                                 * wait.
                                 */
-                               flush_signals(current);
                                prepare_to_wait(&conf->wait_for_overlap,
                                                &w, TASK_INTERRUPTIBLE);
                                if (logical_sector >= mddev->suspend_lo &&
-                                   logical_sector < mddev->suspend_hi)
+                                   logical_sector < mddev->suspend_hi) {
+                                       sigset_t full, old;
+                                       sigfillset(&full);
+                                       sigprocmask(SIG_BLOCK, &full, &old);
                                        schedule();
+                                       sigprocmask(SIG_SETMASK, &old, NULL);
+                               }
                                goto retry;
                        }
 
index 9883617..d5773bd 100644 (file)
@@ -168,7 +168,7 @@ int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction)
        int i;
 
        if (0 == divisor)
-               return -1;
+               return -EINVAL;
 
        q = dividend / divisor;
        remainder = dividend - q * divisor;
@@ -194,10 +194,13 @@ static int max2165_set_rf(struct max2165_priv *priv, u32 freq)
        u8 tf_ntch;
        u32 t;
        u32 quotient, fraction;
+       int ret;
 
        /* Set PLL divider according to RF frequency */
-       fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
-               &quotient, &fraction);
+       ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
+                        &quotient, &fraction);
+       if (ret != 0)
+               return ret;
 
        /* 20-bit fraction */
        fraction >>= 12;
index e29cc2b..27c1861 100644 (file)
@@ -241,7 +241,7 @@ struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
 {
        struct tda18212_priv *priv = NULL;
        int ret;
-       u8 val;
+       u8 uninitialized_var(val);
 
        priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
        if (priv == NULL)
index 4fc2973..361a31f 100644 (file)
@@ -274,7 +274,7 @@ struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
        struct i2c_adapter *i2c, struct tda18218_config *cfg)
 {
        struct tda18218_priv *priv = NULL;
-       u8 val;
+       u8 uninitialized_var(val);
        int ret;
        /* chip default registers values */
        static u8 def_regs[] = {
index 634f4d9..3b9fdba 100644 (file)
@@ -923,7 +923,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
        int                        rc = 0, is_retry = 0;
        u16                        hwmodel;
        v4l2_std_id                std0;
-       u8                         hw_major, hw_minor, fw_major, fw_minor;
+       u8                         hw_major = 0, hw_minor = 0, fw_major = 0, fw_minor = 0;
 
        dprintk(1, "%s called\n", __func__);
 
index b34fa95..db53824 100644 (file)
@@ -434,8 +434,7 @@ static int __devinit bt878_probe(struct pci_dev *dev,
               bt878_num);
        if (bt878_num >= BT878_MAX) {
                printk(KERN_ERR "bt878: Too many devices inserted\n");
-               result = -ENOMEM;
-               goto fail0;
+               return -ENOMEM;
        }
        if (pci_enable_device(dev))
                return -EIO;
index 9f2a02c..0955935 100644 (file)
@@ -772,6 +772,8 @@ static int dvico_bluebird_xc2028_callback(void *ptr, int component,
        case XC2028_RESET_CLK:
                deb_info("%s: XC2028_RESET_CLK %d\n", __func__, arg);
                break;
+       case XC2028_I2C_FLUSH:
+               break;
        default:
                deb_info("%s: unknown command %d, arg %d\n", __func__,
                         command, arg);
index f313182..d25ea88 100644 (file)
@@ -405,6 +405,7 @@ static int stk7700ph_xc3028_callback(void *ptr, int component,
                dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
                break;
        case XC2028_RESET_CLK:
+       case XC2028_I2C_FLUSH:
                break;
        default:
                err("%s: unknown command %d, arg %d\n", __func__,
index a76bbb2..e314c32 100644 (file)
@@ -169,8 +169,20 @@ EXPORT_SYMBOL(dibusb_i2c_algo);
 
 int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
 {
-       u8 wbuf[1] = { offs };
-       return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1);
+       u8 *buf;
+       int rc;
+
+       buf = kmalloc(2, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf[0] = offs;
+
+       rc = dibusb_i2c_msg(d, 0x50, &buf[0], 1, &buf[1], 1);
+       *val = buf[1];
+       kfree(buf);
+
+       return rc;
 }
 EXPORT_SYMBOL(dibusb_read_eeprom_byte);
 
index bc6ea9f..738f7b0 100644 (file)
@@ -340,7 +340,6 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        struct mxl111sf_state *state = d->priv;
        struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv;
        int ret = 0;
-       u8 tmp;
 
        deb_info("%s(%d)\n", __func__, onoff);
 
index 1af1ee4..4671074 100644 (file)
@@ -78,7 +78,7 @@ static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
                        return err;
                }
                *bandwidth = t_state.bandwidth;
+               printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
        }
-       printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
        return 0;
 }
index 3f175eb..3fb5949 100644 (file)
@@ -2318,6 +2318,11 @@ static int __devinit imon_probe(struct usb_interface *interface,
        mutex_lock(&driver_lock);
 
        first_if = usb_ifnum_to_if(usbdev, 0);
+       if (!first_if) {
+               ret = -ENODEV;
+               goto fail;
+       }
+
        first_if_ctx = usb_get_intfdata(first_if);
 
        if (ifnum == 0) {
index 695fef9..4ee9f4e 100644 (file)
@@ -255,11 +255,14 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
                if (!dev->max_timeout)
                        return -ENOSYS;
 
+               /* Check for multiply overflow */
+               if (val > (u32)(-1) / 1000)
+                       return -EINVAL;
+
                tmp = val * 1000;
 
-               if (tmp < dev->min_timeout ||
-                   tmp > dev->max_timeout)
-                               return -EINVAL;
+               if (tmp < dev->min_timeout || tmp > dev->max_timeout)
+                       return -EINVAL;
 
                dev->timeout = tmp;
                break;
index 2fb6473..6e7468e 100644 (file)
@@ -739,6 +739,7 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
        } else if (urb_type == MCEUSB_RX) {
                /* standard request */
                async_urb = ir->urb_in;
+               async_buf = NULL;
                ir->send_flags = RECV_FLAG_IN_PROGRESS;
 
        } else {
@@ -754,6 +755,10 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
        res = usb_submit_urb(async_urb, GFP_ATOMIC);
        if (res) {
                mce_dbg(dev, "receive request FAILED! (res=%d)\n", res);
+               if (urb_type == MCEUSB_TX) {
+                       kfree(async_buf);
+                       usb_free_urb(async_urb);
+               }
                return;
        }
        mce_dbg(dev, "receive request complete (res=%d)\n", res);
index 61287fc..9bff23c 100644 (file)
@@ -286,12 +286,6 @@ static void redrat3_issue_async(struct redrat3_dev *rr3)
 
        rr3_ftr(rr3->dev, "Entering %s\n", __func__);
 
-       if (!rr3->det_enabled) {
-               dev_warn(rr3->dev, "not issuing async read, "
-                        "detector not enabled\n");
-               return;
-       }
-
        memset(rr3->bulk_in_buf, 0, rr3->ep_in->wMaxPacketSize);
        res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC);
        if (res)
@@ -827,6 +821,7 @@ out:
 static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
 {
        struct redrat3_dev *rr3;
+       int ret;
 
        if (!urb)
                return;
@@ -840,15 +835,13 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
 
        rr3_ftr(rr3->dev, "Entering %s\n", __func__);
 
-       if (!rr3->det_enabled) {
-               rr3_dbg(rr3->dev, "received a read callback but detector "
-                       "disabled - ignoring\n");
-               return;
-       }
-
        switch (urb->status) {
        case 0:
-               redrat3_get_ir_data(rr3, urb->actual_length);
+               ret = redrat3_get_ir_data(rr3, urb->actual_length);
+               if (!ret) {
+                       /* no error, prepare to read more */
+                       redrat3_issue_async(rr3);
+               }
                break;
 
        case -ECONNRESET:
@@ -865,11 +858,6 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
                rr3->pkttype = 0;
                break;
        }
-
-       if (!rr3->transmitting)
-               redrat3_issue_async(rr3);
-       else
-               rr3_dbg(rr3->dev, "IR transmit in progress\n");
 }
 
 static void redrat3_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
@@ -896,21 +884,24 @@ static u16 mod_freq_to_val(unsigned int mod_freq)
        return (u16)(65536 - (mult / mod_freq));
 }
 
-static int redrat3_set_tx_carrier(struct rc_dev *dev, u32 carrier)
+static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier)
 {
-       struct redrat3_dev *rr3 = dev->priv;
+       struct redrat3_dev *rr3 = rcdev->priv;
+       struct device *dev = rr3->dev;
 
+       rr3_dbg(dev, "Setting modulation frequency to %u", carrier);
        rr3->carrier = carrier;
 
        return carrier;
 }
 
-static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
+static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
+                               unsigned count)
 {
        struct redrat3_dev *rr3 = rcdev->priv;
        struct device *dev = rr3->dev;
        struct redrat3_signal_header header;
-       int i, j, count, ret, ret_len, offset;
+       int i, j, ret, ret_len, offset;
        int lencheck, cur_sample_len, pipe;
        char *buffer = NULL, *sigdata = NULL;
        int *sample_lens = NULL;
@@ -928,20 +919,13 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
                return -EAGAIN;
        }
 
-       count = n / sizeof(int);
        if (count > (RR3_DRIVER_MAXLENS * 2))
                return -EINVAL;
 
+       /* rr3 will disable rc detector on transmit */
+       rr3->det_enabled = false;
        rr3->transmitting = true;
 
-       redrat3_disable_detector(rr3);
-
-       if (rr3->det_enabled) {
-               dev_err(dev, "%s: cannot tx while rx is enabled\n", __func__);
-               ret = -EIO;
-               goto out;
-       }
-
        sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL);
        if (!sample_lens) {
                ret = -ENOMEM;
@@ -1055,7 +1039,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
        if (ret < 0)
                dev_err(dev, "Error: control msg send failed, rc %d\n", ret);
        else
-               ret = n;
+               ret = count;
 
 out:
        kfree(sample_lens);
@@ -1063,8 +1047,8 @@ out:
        kfree(sigdata);
 
        rr3->transmitting = false;
-
-       redrat3_enable_detector(rr3);
+       /* rr3 re-enables rc detector because it was enabled before */
+       rr3->det_enabled = true;
 
        return ret;
 }
index 117f9c4..aa1e164 100644 (file)
@@ -13,12 +13,13 @@ omap2cam-objs       :=      omap24xxcam.o omap24xxcam-dma.o
 videodev-objs  :=      v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
                        v4l2-event.o v4l2-ctrls.o v4l2-subdev.o
 
+ifeq ($(CONFIG_COMPAT),y)
+  videodev-objs += v4l2-compat-ioctl32.o
+endif
+
 # V4L2 core modules
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
-ifeq ($(CONFIG_COMPAT),y)
-  obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o
-endif
 
 obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
 
index 077eb1d..4c6777f 100644 (file)
@@ -1152,7 +1152,7 @@ static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
        struct camera_data *cam = video_drvdata(file);
 
        if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-          buf->index > cam->num_frames)
+          buf->index >= cam->num_frames)
                return -EINVAL;
 
        buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
@@ -1201,7 +1201,7 @@ static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 
        if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
           buf->memory != V4L2_MEMORY_MMAP ||
-          buf->index > cam->num_frames)
+          buf->index >= cam->num_frames)
                return -EINVAL;
 
        DBG("QBUF #%d\n", buf->index);
index 21f23b6..7b52600 100644 (file)
@@ -1070,8 +1070,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        dev->vbi_or_sliced_cc_mode = 0;
 
        /* get maximum no.of IAD interfaces */
-       assoc_desc = udev->actconfig->intf_assoc[0];
-       dev->max_iad_interface_count = assoc_desc->bInterfaceCount;
+       dev->max_iad_interface_count = udev->config->desc.bNumInterfaces;
 
        /* init CIR module TBD */
 
@@ -1127,7 +1126,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
        nr = dev->devno;
 
        assoc_desc = udev->actconfig->intf_assoc[0];
-       if (assoc_desc->bFirstInterface != ifnum) {
+       if (!assoc_desc || assoc_desc->bFirstInterface != ifnum) {
                cx231xx_err(DRIVER_NAME ": Not found "
                            "matching IAD interface\n");
                retval = -ENODEV;
index cff0768..e902bf5 100644 (file)
@@ -507,7 +507,7 @@ static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
                val, (int)kcontrol->private_value);
 
        value->value.integer.value[0] = 0x1f - (val & 0x1f);
-       value->value.integer.value[1] = 0x1f - ((val << 8) & 0x1f);
+       value->value.integer.value[1] = 0x1f - ((val >> 8) & 0x1f);
 
        return 0;
 }
index 36324d8..94366d6 100644 (file)
@@ -1002,11 +1002,12 @@ static int omap_vout_open(struct file *file)
        struct omap_vout_device *vout = NULL;
 
        vout = video_drvdata(file);
-       v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
 
        if (vout == NULL)
                return -ENODEV;
 
+       v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
+
        /* for now, we only support single open */
        if (vout->opened)
                return -EBUSY;
index 66696fa..9bd1f73 100644 (file)
@@ -130,9 +130,9 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port,
                goto fail2;
 
        /* init the buffers to a known pattern, easier during debugging */
-       memset_io(buf->cpu, 0xff, buf->pci_size);
+       memset(buf->cpu, 0xff, buf->pci_size);
        buf->crc = crc32(0, buf->cpu, buf->actual_size);
-       memset_io(buf->pt_cpu, 0xff, buf->pt_size);
+       memset(buf->pt_cpu, 0xff, buf->pt_size);
 
        dprintk(DBGLVL_BUF, "%s()   allocated buffer @ 0x%p (%d pageptrs)\n",
                __func__, buf, params->numpagetables);
index 466e1b0..6ef5064 100644 (file)
@@ -33,12 +33,12 @@ int saa7164_bus_setup(struct saa7164_dev *dev)
        b->Type                 = TYPE_BUS_PCIe;
        b->m_wMaxReqSize        = SAA_DEVICE_MAXREQUESTSIZE;
 
-       b->m_pdwSetRing         = (u8 *)(dev->bmmio +
+       b->m_pdwSetRing         = (u8 __iomem *)(dev->bmmio +
                ((u32)dev->busdesc.CommandRing));
 
        b->m_dwSizeSetRing      = SAA_DEVICE_BUFFERBLOCKSIZE;
 
-       b->m_pdwGetRing         = (u8 *)(dev->bmmio +
+       b->m_pdwGetRing         = (u8 __iomem *)(dev->bmmio +
                ((u32)dev->busdesc.ResponseRing));
 
        b->m_dwSizeGetRing      = SAA_DEVICE_BUFFERBLOCKSIZE;
@@ -138,6 +138,7 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
        u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp;
        u32 new_swp, space_rem;
        int ret = SAA_ERR_BAD_PARAMETER;
+       u16 size;
 
        if (!msg) {
                printk(KERN_ERR "%s() !msg\n", __func__);
@@ -148,10 +149,6 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
 
        saa7164_bus_verify(dev);
 
-       msg->size = cpu_to_le16(msg->size);
-       msg->command = cpu_to_le16(msg->command);
-       msg->controlselector = cpu_to_le16(msg->controlselector);
-
        if (msg->size > dev->bus.m_wMaxReqSize) {
                printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
                        __func__);
@@ -169,8 +166,8 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
        bytes_to_write = sizeof(*msg) + msg->size;
        free_write_space = 0;
        timeout = SAA_BUS_TIMEOUT;
-       curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos));
-       curr_swp = le32_to_cpu(saa7164_readl(bus->m_dwSetWritePos));
+       curr_srp = saa7164_readl(bus->m_dwSetReadPos);
+       curr_swp = saa7164_readl(bus->m_dwSetWritePos);
 
        /* Deal with ring wrapping issues */
        if (curr_srp > curr_swp)
@@ -203,7 +200,7 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
                mdelay(1);
 
                /* Check the space usage again */
-               curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos));
+               curr_srp = saa7164_readl(bus->m_dwSetReadPos);
 
                /* Deal with ring wrapping issues */
                if (curr_srp > curr_swp)
@@ -223,6 +220,16 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
        dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__,
                bus->m_dwSizeSetRing);
 
+       /*
+        * Make a copy of msg->size before it is converted to le16 since it is
+        * used in the code below.
+        */
+       size = msg->size;
+       /* Convert to le16/le32 */
+       msg->size = (__force u16)cpu_to_le16(msg->size);
+       msg->command = (__force u32)cpu_to_le32(msg->command);
+       msg->controlselector = (__force u16)cpu_to_le16(msg->controlselector);
+
        /* Mental Note: line 462 tmmhComResBusPCIe.cpp */
 
        /* Check if we're going to wrap again */
@@ -243,28 +250,28 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
                        dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
 
                        /* Split the msg into pieces as the ring wraps */
-                       memcpy(bus->m_pdwSetRing + curr_swp, msg, space_rem);
-                       memcpy(bus->m_pdwSetRing, (u8 *)msg + space_rem,
+                       memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, space_rem);
+                       memcpy_toio(bus->m_pdwSetRing, (u8 *)msg + space_rem,
                                sizeof(*msg) - space_rem);
 
-                       memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
-                               buf, msg->size);
+                       memcpy_toio(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
+                               buf, size);
 
                } else if (space_rem == sizeof(*msg)) {
                        dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
 
                        /* Additional data at the beginning of the ring */
-                       memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
-                       memcpy(bus->m_pdwSetRing, buf, msg->size);
+                       memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
+                       memcpy_toio(bus->m_pdwSetRing, buf, size);
 
                } else {
                        /* Additional data wraps around the ring */
-                       memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
-                       if (msg->size > 0) {
-                               memcpy(bus->m_pdwSetRing + curr_swp +
+                       memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
+                       if (size > 0) {
+                               memcpy_toio(bus->m_pdwSetRing + curr_swp +
                                        sizeof(*msg), buf, space_rem -
                                        sizeof(*msg));
-                               memcpy(bus->m_pdwSetRing, (u8 *)buf +
+                               memcpy_toio(bus->m_pdwSetRing, (u8 *)buf +
                                        space_rem - sizeof(*msg),
                                        bytes_to_write - space_rem);
                        }
@@ -276,15 +283,20 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
                dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
 
                /* The ring buffer doesn't wrap, two simple copies */
-               memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
-               memcpy(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf,
-                       msg->size);
+               memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
+               memcpy_toio(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf,
+                       size);
        }
 
        dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
 
        /* Update the bus write position */
-       saa7164_writel(bus->m_dwSetWritePos, cpu_to_le32(new_swp));
+       saa7164_writel(bus->m_dwSetWritePos, new_swp);
+
+       /* Convert back to cpu after writing the msg to the ringbuffer. */
+       msg->size = le16_to_cpu((__force __le16)msg->size);
+       msg->command = le32_to_cpu((__force __le32)msg->command);
+       msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
        ret = SAA_OK;
 
 out:
@@ -336,8 +348,8 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
        /* Peek the bus to see if a msg exists, if it's not what we're expecting
         * then return cleanly else read the message from the bus.
         */
-       curr_gwp = le32_to_cpu(saa7164_readl(bus->m_dwGetWritePos));
-       curr_grp = le32_to_cpu(saa7164_readl(bus->m_dwGetReadPos));
+       curr_gwp = saa7164_readl(bus->m_dwGetWritePos);
+       curr_grp = saa7164_readl(bus->m_dwGetReadPos);
 
        if (curr_gwp == curr_grp) {
                ret = SAA_ERR_EMPTY;
@@ -369,19 +381,23 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
                new_grp -= bus->m_dwSizeGetRing;
                space_rem = bus->m_dwSizeGetRing - curr_grp;
 
-               memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem);
-               memcpy((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing,
+               memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem);
+               memcpy_fromio((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing,
                        bytes_to_read - space_rem);
 
        } else {
                /* No wrapping */
-               memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
+               memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
        }
+       /* Convert from little endian to CPU */
+       msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size);
+       msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command);
+       msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector);
+       memcpy(msg, &msg_tmp, sizeof(*msg));
 
        /* No need to update the read positions, because this was a peek */
        /* If the caller specifically want to peek, return */
        if (peekonly) {
-               memcpy(msg, &msg_tmp, sizeof(*msg));
                goto peekout;
        }
 
@@ -426,25 +442,19 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
                space_rem = bus->m_dwSizeGetRing - curr_grp;
 
                if (space_rem < sizeof(*msg)) {
-                       /* msg wraps around the ring */
-                       memcpy(msg, bus->m_pdwGetRing + curr_grp, space_rem);
-                       memcpy((u8 *)msg + space_rem, bus->m_pdwGetRing,
-                               sizeof(*msg) - space_rem);
                        if (buf)
-                               memcpy(buf, bus->m_pdwGetRing + sizeof(*msg) -
+                               memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) -
                                        space_rem, buf_size);
 
                } else if (space_rem == sizeof(*msg)) {
-                       memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
                        if (buf)
-                               memcpy(buf, bus->m_pdwGetRing, buf_size);
+                               memcpy_fromio(buf, bus->m_pdwGetRing, buf_size);
                } else {
                        /* Additional data wraps around the ring */
-                       memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
                        if (buf) {
-                               memcpy(buf, bus->m_pdwGetRing + curr_grp +
+                               memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp +
                                        sizeof(*msg), space_rem - sizeof(*msg));
-                               memcpy(buf + space_rem - sizeof(*msg),
+                               memcpy_fromio(buf + space_rem - sizeof(*msg),
                                        bus->m_pdwGetRing, bytes_to_read -
                                        space_rem);
                        }
@@ -453,19 +463,15 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
 
        } else {
                /* No wrapping */
-               memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
                if (buf)
-                       memcpy(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
+                       memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
                                buf_size);
        }
 
        /* Update the read positions, adjusting the ring */
-       saa7164_writel(bus->m_dwGetReadPos, cpu_to_le32(new_grp));
+       saa7164_writel(bus->m_dwGetReadPos, new_grp);
 
 peekout:
-       msg->size = le16_to_cpu(msg->size);
-       msg->command = le16_to_cpu(msg->command);
-       msg->controlselector = le16_to_cpu(msg->controlselector);
        ret = SAA_OK;
 out:
        mutex_unlock(&bus->lock);
index 8f3c47e..14e158e 100644 (file)
@@ -140,7 +140,7 @@ static void saa7164_ts_verifier(struct saa7164_buffer *buf)
        u32 i;
        u8 cc, a;
        u16 pid;
-       u8 __iomem *bufcpu = (u8 *)buf->cpu;
+       u8 *bufcpu = (u8 *)buf->cpu;
 
        port->sync_errors = 0;
        port->v_cc_errors = 0;
@@ -281,7 +281,7 @@ static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
        struct saa7164_user_buffer *ubuf = NULL;
        struct list_head *c, *n;
        int i = 0;
-       u8 __iomem *p;
+       u8 *p;
 
        mutex_lock(&port->dmaqueue_lock);
        list_for_each_safe(c, n, &port->dmaqueue.list) {
@@ -338,8 +338,7 @@ static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
 
                                if (buf->actual_size <= ubuf->actual_size) {
 
-                                       memcpy_fromio(ubuf->data, buf->cpu,
-                                               ubuf->actual_size);
+                                       memcpy(ubuf->data, buf->cpu, ubuf->actual_size);
 
                                        if (crc_checking) {
                                                /* Throw a new checksum on the read buffer */
@@ -366,7 +365,7 @@ static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
                         * with known bad data. We check for this data at a later point
                         * in time. */
                        saa7164_buffer_zero_offsets(port, bufnr);
-                       memset_io(buf->cpu, 0xff, buf->pci_size);
+                       memset(buf->cpu, 0xff, buf->pci_size);
                        if (crc_checking) {
                                /* Throw yet aanother new checksum on the dma buffer */
                                buf->crc = crc32(0, buf->cpu, buf->actual_size);
@@ -1134,7 +1133,7 @@ static int saa7164_proc_show(struct seq_file *m, void *v)
                        if (c == 0)
                                seq_printf(m, " %04x:", i);
 
-                       seq_printf(m, " %02x", *(b->m_pdwSetRing + i));
+                       seq_printf(m, " %02x", readb(b->m_pdwSetRing + i));
 
                        if (++c == 16) {
                                seq_printf(m, "\n");
@@ -1149,7 +1148,7 @@ static int saa7164_proc_show(struct seq_file *m, void *v)
                        if (c == 0)
                                seq_printf(m, " %04x:", i);
 
-                       seq_printf(m, " %02x", *(b->m_pdwGetRing + i));
+                       seq_printf(m, " %02x", readb(b->m_pdwGetRing + i));
 
                        if (++c == 16) {
                                seq_printf(m, "\n");
index a266bf0..124223a 100644 (file)
@@ -72,7 +72,7 @@ int saa7164_dl_wait_clr(struct saa7164_dev *dev, u32 reg)
 /* TODO: move dlflags into dev-> and change to write/readl/b */
 /* TODO: Excessive levels of debug */
 int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize,
-       u32 dlflags, u8 *dst, u32 dstsize)
+                                u32 dlflags, u8 __iomem *dst, u32 dstsize)
 {
        u32 reg, timeout, offset;
        u8 *srcbuf = NULL;
@@ -136,7 +136,7 @@ int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize,
                srcsize -= dstsize, offset += dstsize) {
 
                dprintk(DBGLVL_FW, "%s() memcpy %d\n", __func__, dstsize);
-               memcpy(dst, srcbuf + offset, dstsize);
+               memcpy_toio(dst, srcbuf + offset, dstsize);
 
                /* Flag the data as ready */
                saa7164_writel(drflag, 1);
@@ -154,7 +154,7 @@ int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize,
 
        dprintk(DBGLVL_FW, "%s() memcpy(l) %d\n", __func__, dstsize);
        /* Write last block to the device */
-       memcpy(dst, srcbuf+offset, srcsize);
+       memcpy_toio(dst, srcbuf+offset, srcsize);
 
        /* Flag the data as ready */
        saa7164_writel(drflag, 1);
index 1d2140a..f48ba97 100644 (file)
@@ -78,9 +78,9 @@ enum tmBusType {
 struct tmComResBusInfo {
        enum tmBusType Type;
        u16     m_wMaxReqSize;
-       u8      *m_pdwSetRing;
+       u8 __iomem *m_pdwSetRing;
        u32     m_dwSizeSetRing;
-       u8      *m_pdwGetRing;
+       u8 __iomem *m_pdwGetRing;
        u32     m_dwSizeGetRing;
        u32     m_dwSetWritePos;
        u32     m_dwSetReadPos;
index 742b341..360e6e6 100644 (file)
@@ -315,13 +315,13 @@ struct saa7164_buffer {
 
        /* A block of page align PCI memory */
        u32 pci_size;   /* PCI allocation size in bytes */
-       u64 __iomem *cpu;       /* Virtual address */
+       u64 *cpu;       /* Virtual address */
        dma_addr_t dma; /* Physical address */
        u32 crc;        /* Checksum for the entire buffer data */
 
        /* A page table that splits the block into a number of entries */
        u32 pt_size;            /* PCI allocation size in bytes */
-       u64 __iomem *pt_cpu;            /* Virtual address */
+       u64 *pt_cpu;            /* Virtual address */
        dma_addr_t pt_dma;      /* Physical address */
 
        /* Encoder fops */
index 254d326..47c3a55 100644 (file)
@@ -1698,6 +1698,13 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
                goto done;
        }
 
+       /* Validate the user-provided bit-size and offset */
+       if (mapping->size > 32 ||
+           mapping->offset + mapping->size > ctrl->info.size * 8) {
+               ret = -EINVAL;
+               goto done;
+       }
+
        list_for_each_entry(map, &ctrl->info.mappings, list) {
                if (mapping->id == map->id) {
                        uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', "
index 2671959..b431b1f 100644 (file)
 #include <linux/videodev2.h>
 #include <linux/module.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
 
 #ifdef CONFIG_COMPAT
 
+/* Use the same argument order as copy_in_user */
+#define assign_in_user(to, from)                                       \
+({                                                                     \
+       typeof(*from) __assign_tmp;                                     \
+                                                                       \
+       get_user(__assign_tmp, from) || put_user(__assign_tmp, to);     \
+})
+
 static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        long ret = -ENOIOCTLCMD;
@@ -33,117 +44,88 @@ static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 struct v4l2_clip32 {
        struct v4l2_rect        c;
-       compat_caddr_t          next;
+       compat_caddr_t          next;
 };
 
 struct v4l2_window32 {
        struct v4l2_rect        w;
-       enum v4l2_field         field;
+       __u32                   field;  /* enum v4l2_field */
        __u32                   chromakey;
        compat_caddr_t          clips; /* actually struct v4l2_clip32 * */
        __u32                   clipcount;
        compat_caddr_t          bitmap;
+       __u8                    global_alpha;
 };
 
-static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
+static int get_v4l2_window32(struct v4l2_window __user *kp,
+                            struct v4l2_window32 __user *up,
+                            void __user *aux_buf, u32 aux_space)
 {
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
-               copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
-               get_user(kp->field, &up->field) ||
-               get_user(kp->chromakey, &up->chromakey) ||
-               get_user(kp->clipcount, &up->clipcount))
-                       return -EFAULT;
-       if (kp->clipcount > 2048)
-               return -EINVAL;
-       if (kp->clipcount) {
-               struct v4l2_clip32 __user *uclips;
-               struct v4l2_clip __user *kclips;
-               int n = kp->clipcount;
-               compat_caddr_t p;
-
-               if (get_user(p, &up->clips))
-                       return -EFAULT;
-               uclips = compat_ptr(p);
-               kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
-               kp->clips = kclips;
-               while (--n >= 0) {
-                       if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
-                               return -EFAULT;
-                       if (put_user(n ? kclips + 1 : NULL, &kclips->next))
-                               return -EFAULT;
-                       uclips += 1;
-                       kclips += 1;
-               }
-       } else
-               kp->clips = NULL;
-       return 0;
-}
-
-static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
-{
-       if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
-               put_user(kp->field, &up->field) ||
-               put_user(kp->chromakey, &up->chromakey) ||
-               put_user(kp->clipcount, &up->clipcount))
-                       return -EFAULT;
-       return 0;
-}
-
-static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
-{
-       if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
-               return -EFAULT;
-       return 0;
-}
-
-static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
-                               struct v4l2_pix_format_mplane __user *up)
-{
-       if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
+       struct v4l2_clip32 __user *uclips;
+       struct v4l2_clip __user *kclips;
+       compat_caddr_t p;
+       u32 clipcount;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
+           assign_in_user(&kp->field, &up->field) ||
+           assign_in_user(&kp->chromakey, &up->chromakey) ||
+           assign_in_user(&kp->global_alpha, &up->global_alpha) ||
+           get_user(clipcount, &up->clipcount) ||
+           put_user(clipcount, &kp->clipcount))
                return -EFAULT;
-       return 0;
-}
+       if (clipcount > 2048)
+               return -EINVAL;
+       if (!clipcount)
+               return put_user(NULL, &kp->clips);
 
-static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
+       if (get_user(p, &up->clips))
                return -EFAULT;
-       return 0;
-}
-
-static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
-                               struct v4l2_pix_format_mplane __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
+       uclips = compat_ptr(p);
+       if (aux_space < clipcount * sizeof(*kclips))
                return -EFAULT;
-       return 0;
-}
-
-static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
-{
-       if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
+       kclips = aux_buf;
+       if (put_user(kclips, &kp->clips))
                return -EFAULT;
-       return 0;
-}
 
-static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
-               return -EFAULT;
+       while (clipcount--) {
+               if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
+                       return -EFAULT;
+               if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
+                       return -EFAULT;
+               uclips++;
+               kclips++;
+       }
        return 0;
 }
 
-static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+static int put_v4l2_window32(struct v4l2_window __user *kp,
+                            struct v4l2_window32 __user *up)
 {
-       if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
+       struct v4l2_clip __user *kclips = kp->clips;
+       struct v4l2_clip32 __user *uclips;
+       compat_caddr_t p;
+       u32 clipcount;
+
+       if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
+           assign_in_user(&up->field, &kp->field) ||
+           assign_in_user(&up->chromakey, &kp->chromakey) ||
+           assign_in_user(&up->global_alpha, &kp->global_alpha) ||
+           get_user(clipcount, &kp->clipcount) ||
+           put_user(clipcount, &up->clipcount))
                return -EFAULT;
-       return 0;
-}
+       if (!clipcount)
+               return 0;
 
-static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
+       if (get_user(p, &up->clips))
                return -EFAULT;
+       uclips = compat_ptr(p);
+       while (clipcount--) {
+               if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
+                       return -EFAULT;
+               uclips++;
+               kclips++;
+       }
        return 0;
 }
 
@@ -176,128 +158,185 @@ struct v4l2_create_buffers32 {
        __u32                   reserved[8];
 };
 
-static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
 {
-       if (get_user(kp->type, &up->type))
+       u32 type;
+
+       if (get_user(type, &up->type))
+               return -EFAULT;
+
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
+               u32 clipcount;
+
+               if (get_user(clipcount, &up->fmt.win.clipcount))
+                       return -EFAULT;
+               if (clipcount > 2048)
+                       return -EINVAL;
+               *size = clipcount * sizeof(struct v4l2_clip);
+               return 0;
+       }
+       default:
+               *size = 0;
+               return 0;
+       }
+}
+
+static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
+{
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+               return -EFAULT;
+       return __bufsize_v4l2_format(up, size);
+}
+
+static int __get_v4l2_format32(struct v4l2_format __user *kp,
+                              struct v4l2_format32 __user *up,
+                              void __user *aux_buf, u32 aux_space)
+{
+       u32 type;
+
+       if (get_user(type, &up->type) || put_user(type, &kp->type))
                return -EFAULT;
 
-       switch (kp->type) {
+       switch (type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-               return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+               return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
+                                   sizeof(kp->fmt.pix)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-               return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
-                                                 &up->fmt.pix_mp);
+               return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
+                                   sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
-               return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
+               return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
+                                        aux_buf, aux_space);
        case V4L2_BUF_TYPE_VBI_CAPTURE:
        case V4L2_BUF_TYPE_VBI_OUTPUT:
-               return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+               return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
+                                   sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
        case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-               return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
-       case V4L2_BUF_TYPE_PRIVATE:
-               if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data)))
-                       return -EFAULT;
-               return 0;
+               return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
+                                   sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
        default:
-               printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
-                                                               kp->type);
                return -EINVAL;
        }
 }
 
-static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int get_v4l2_format32(struct v4l2_format __user *kp,
+                            struct v4l2_format32 __user *up,
+                            void __user *aux_buf, u32 aux_space)
+{
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)))
+               return -EFAULT;
+       return __get_v4l2_format32(kp, up, aux_buf, aux_space);
+}
+
+static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
+                              u32 *size)
 {
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)))
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)))
                return -EFAULT;
-       return __get_v4l2_format32(kp, up);
+       return __bufsize_v4l2_format(&up->format, size);
 }
 
-static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
+                            struct v4l2_create_buffers32 __user *up,
+                            void __user *aux_buf, u32 aux_space)
 {
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
-           copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format)))
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           copy_in_user(kp, up,
+                        offsetof(struct v4l2_create_buffers32, format)))
                return -EFAULT;
-       return __get_v4l2_format32(&kp->format, &up->format);
+       return __get_v4l2_format32(&kp->format, &up->format,
+                                  aux_buf, aux_space);
 }
 
-static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int __put_v4l2_format32(struct v4l2_format __user *kp,
+                              struct v4l2_format32 __user *up)
 {
-       switch (kp->type) {
+       u32 type;
+
+       if (get_user(type, &kp->type))
+               return -EFAULT;
+
+       switch (type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-               return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
+               return copy_in_user(&up->fmt.pix, &kp->fmt.pix,
+                                   sizeof(kp->fmt.pix)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-               return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
-                                                 &up->fmt.pix_mp);
+               return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
+                                   sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
        case V4L2_BUF_TYPE_VBI_CAPTURE:
        case V4L2_BUF_TYPE_VBI_OUTPUT:
-               return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+               return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi,
+                                   sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
        case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
-               return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
-       case V4L2_BUF_TYPE_PRIVATE:
-               if (copy_to_user(up, kp, sizeof(up->fmt.raw_data)))
-                       return -EFAULT;
-               return 0;
+               return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
+                                   sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
        default:
-               printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
-                                                               kp->type);
                return -EINVAL;
        }
 }
 
-static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
+static int put_v4l2_format32(struct v4l2_format __user *kp,
+                            struct v4l2_format32 __user *up)
 {
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
-               put_user(kp->type, &up->type))
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
                return -EFAULT;
        return __put_v4l2_format32(kp, up);
 }
 
-static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
+static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
+                            struct v4l2_create_buffers32 __user *up)
 {
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
-           copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt)))
-                       return -EFAULT;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           copy_in_user(up, kp,
+                        offsetof(struct v4l2_create_buffers32, format)) ||
+           copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
+               return -EFAULT;
        return __put_v4l2_format32(&kp->format, &up->format);
 }
 
 struct v4l2_standard32 {
        __u32                index;
-       __u32                id[2]; /* __u64 would get the alignment wrong */
+       compat_u64           id;
        __u8                 name[24];
        struct v4l2_fract    frameperiod; /* Frames, not fields */
        __u32                framelines;
        __u32                reserved[4];
 };
 
-static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+static int get_v4l2_standard32(struct v4l2_standard __user *kp,
+                              struct v4l2_standard32 __user *up)
 {
        /* other fields are not set by the user, nor used by the driver */
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
-               get_user(kp->index, &up->index))
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           assign_in_user(&kp->index, &up->index))
                return -EFAULT;
        return 0;
 }
 
-static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
+static int put_v4l2_standard32(struct v4l2_standard __user *kp,
+                              struct v4l2_standard32 __user *up)
 {
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
-               put_user(kp->index, &up->index) ||
-               copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
-               copy_to_user(up->name, kp->name, 24) ||
-               copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
-               put_user(kp->framelines, &up->framelines) ||
-               copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
-                       return -EFAULT;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           assign_in_user(&up->index, &kp->index) ||
+           assign_in_user(&up->id, &kp->id) ||
+           copy_in_user(up->name, kp->name, sizeof(up->name)) ||
+           copy_in_user(&up->frameperiod, &kp->frameperiod,
+                        sizeof(up->frameperiod)) ||
+           assign_in_user(&up->framelines, &kp->framelines) ||
+           copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+               return -EFAULT;
        return 0;
 }
 
@@ -334,191 +373,242 @@ struct v4l2_buffer32 {
        __u32                   reserved;
 };
 
-static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
-                               enum v4l2_memory memory)
+static int get_v4l2_plane32(struct v4l2_plane __user *up,
+                           struct v4l2_plane32 __user *up32,
+                           enum v4l2_memory memory)
 {
-       void __user *up_pln;
-       compat_long_t p;
+       compat_ulong_t p;
 
        if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
-               copy_in_user(&up->data_offset, &up32->data_offset,
-                               sizeof(__u32)))
+           copy_in_user(&up->data_offset, &up32->data_offset,
+                        sizeof(up->data_offset)))
                return -EFAULT;
 
-       if (memory == V4L2_MEMORY_USERPTR) {
-               if (get_user(p, &up32->m.userptr))
-                       return -EFAULT;
-               up_pln = compat_ptr(p);
-               if (put_user((unsigned long)up_pln, &up->m.userptr))
-                       return -EFAULT;
-       } else {
+       switch (memory) {
+       case V4L2_MEMORY_MMAP:
+       case V4L2_MEMORY_OVERLAY:
                if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
-                                       sizeof(__u32)))
+                                sizeof(up32->m.mem_offset)))
+                       return -EFAULT;
+               break;
+       case V4L2_MEMORY_USERPTR:
+               if (get_user(p, &up32->m.userptr) ||
+                   put_user((unsigned long)compat_ptr(p), &up->m.userptr))
                        return -EFAULT;
+               break;
        }
 
        return 0;
 }
 
-static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
-                               enum v4l2_memory memory)
+static int put_v4l2_plane32(struct v4l2_plane __user *up,
+                           struct v4l2_plane32 __user *up32,
+                           enum v4l2_memory memory)
 {
+       unsigned long p;
+
        if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
-               copy_in_user(&up32->data_offset, &up->data_offset,
-                               sizeof(__u32)))
+           copy_in_user(&up32->data_offset, &up->data_offset,
+                        sizeof(up->data_offset)))
                return -EFAULT;
 
-       /* For MMAP, driver might've set up the offset, so copy it back.
-        * USERPTR stays the same (was userspace-provided), so no copying. */
-       if (memory == V4L2_MEMORY_MMAP)
+       switch (memory) {
+       case V4L2_MEMORY_MMAP:
+       case V4L2_MEMORY_OVERLAY:
                if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
-                                       sizeof(__u32)))
+                                sizeof(up->m.mem_offset)))
+                       return -EFAULT;
+               break;
+       case V4L2_MEMORY_USERPTR:
+               if (get_user(p, &up->m.userptr) ||
+                   put_user((compat_ulong_t)ptr_to_compat((__force void *)p),
+                            &up32->m.userptr))
                        return -EFAULT;
+               break;
+       }
 
        return 0;
 }
 
-static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
 {
+       u32 type;
+       u32 length;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(type, &up->type) ||
+           get_user(length, &up->length))
+               return -EFAULT;
+
+       if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+               if (length > VIDEO_MAX_PLANES)
+                       return -EINVAL;
+
+               /*
+                * We don't really care if userspace decides to kill itself
+                * by passing a very big length value
+                */
+               *size = length * sizeof(struct v4l2_plane);
+       } else {
+               *size = 0;
+       }
+       return 0;
+}
+
+static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
+                            struct v4l2_buffer32 __user *up,
+                            void __user *aux_buf, u32 aux_space)
+{
+       u32 type;
+       u32 length;
+       enum v4l2_memory memory;
        struct v4l2_plane32 __user *uplane32;
        struct v4l2_plane __user *uplane;
        compat_caddr_t p;
-       int num_planes;
        int ret;
 
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
-               get_user(kp->index, &up->index) ||
-               get_user(kp->type, &up->type) ||
-               get_user(kp->flags, &up->flags) ||
-               get_user(kp->memory, &up->memory) ||
-               get_user(kp->input, &up->input))
-                       return -EFAULT;
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           assign_in_user(&kp->index, &up->index) ||
+           get_user(type, &up->type) ||
+           put_user(type, &kp->type) ||
+           assign_in_user(&kp->flags, &up->flags) ||
+           get_user(memory, &up->memory) ||
+           put_user(memory, &kp->memory) ||
+           get_user(length, &up->length) ||
+           put_user(length, &kp->length))
+               return -EFAULT;
 
-       if (V4L2_TYPE_IS_OUTPUT(kp->type))
-               if (get_user(kp->bytesused, &up->bytesused) ||
-                       get_user(kp->field, &up->field) ||
-                       get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
-                       get_user(kp->timestamp.tv_usec,
-                                       &up->timestamp.tv_usec))
+       if (V4L2_TYPE_IS_OUTPUT(type))
+               if (assign_in_user(&kp->bytesused, &up->bytesused) ||
+                   assign_in_user(&kp->field, &up->field) ||
+                   assign_in_user(&kp->timestamp.tv_sec,
+                                  &up->timestamp.tv_sec) ||
+                   assign_in_user(&kp->timestamp.tv_usec,
+                                  &up->timestamp.tv_usec))
                        return -EFAULT;
 
-       if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
-               if (get_user(kp->length, &up->length))
-                       return -EFAULT;
+       if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+               u32 num_planes = length;
 
-               num_planes = kp->length;
                if (num_planes == 0) {
-                       kp->m.planes = NULL;
-                       /* num_planes == 0 is legal, e.g. when userspace doesn't
-                        * need planes array on DQBUF*/
-                       return 0;
+                       /*
+                        * num_planes == 0 is legal, e.g. when userspace doesn't
+                        * need planes array on DQBUF
+                        */
+                       return put_user(NULL, &kp->m.planes);
                }
+               if (num_planes > VIDEO_MAX_PLANES)
+                       return -EINVAL;
 
                if (get_user(p, &up->m.planes))
                        return -EFAULT;
 
                uplane32 = compat_ptr(p);
                if (!access_ok(VERIFY_READ, uplane32,
-                               num_planes * sizeof(struct v4l2_plane32)))
+                              num_planes * sizeof(*uplane32)))
+                       return -EFAULT;
+
+               /*
+                * We don't really care if userspace decides to kill itself
+                * by passing a very big num_planes value
+                */
+               if (aux_space < num_planes * sizeof(*uplane))
                        return -EFAULT;
 
-               /* We don't really care if userspace decides to kill itself
-                * by passing a very big num_planes value */
-               uplane = compat_alloc_user_space(num_planes *
-                                               sizeof(struct v4l2_plane));
-               kp->m.planes = uplane;
+               uplane = aux_buf;
+               if (put_user((__force struct v4l2_plane *)uplane,
+                            &kp->m.planes))
+                       return -EFAULT;
 
-               while (--num_planes >= 0) {
-                       ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
+               while (num_planes--) {
+                       ret = get_v4l2_plane32(uplane, uplane32, memory);
                        if (ret)
                                return ret;
-                       ++uplane;
-                       ++uplane32;
+                       uplane++;
+                       uplane32++;
                }
        } else {
-               switch (kp->memory) {
+               switch (memory) {
                case V4L2_MEMORY_MMAP:
-                       if (get_user(kp->length, &up->length) ||
-                               get_user(kp->m.offset, &up->m.offset))
+               case V4L2_MEMORY_OVERLAY:
+                       if (assign_in_user(&kp->m.offset, &up->m.offset))
                                return -EFAULT;
                        break;
-               case V4L2_MEMORY_USERPTR:
-                       {
-                       compat_long_t tmp;
+               case V4L2_MEMORY_USERPTR: {
+                       compat_ulong_t userptr;
 
-                       if (get_user(kp->length, &up->length) ||
-                           get_user(tmp, &up->m.userptr))
-                               return -EFAULT;
-
-                       kp->m.userptr = (unsigned long)compat_ptr(tmp);
-                       }
-                       break;
-               case V4L2_MEMORY_OVERLAY:
-                       if (get_user(kp->m.offset, &up->m.offset))
+                       if (get_user(userptr, &up->m.userptr) ||
+                           put_user((unsigned long)compat_ptr(userptr),
+                                    &kp->m.userptr))
                                return -EFAULT;
                        break;
                }
+               }
        }
 
        return 0;
 }
 
-static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
+static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
+                            struct v4l2_buffer32 __user *up)
 {
+       u32 type;
+       u32 length;
+       enum v4l2_memory memory;
        struct v4l2_plane32 __user *uplane32;
        struct v4l2_plane __user *uplane;
        compat_caddr_t p;
-       int num_planes;
        int ret;
 
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
-               put_user(kp->index, &up->index) ||
-               put_user(kp->type, &up->type) ||
-               put_user(kp->flags, &up->flags) ||
-               put_user(kp->memory, &up->memory) ||
-               put_user(kp->input, &up->input))
-                       return -EFAULT;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           assign_in_user(&up->index, &kp->index) ||
+           get_user(type, &kp->type) ||
+           put_user(type, &up->type) ||
+           assign_in_user(&up->flags, &kp->flags) ||
+           get_user(memory, &kp->memory) ||
+           put_user(memory, &up->memory))
+               return -EFAULT;
 
-       if (put_user(kp->bytesused, &up->bytesused) ||
-               put_user(kp->field, &up->field) ||
-               put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
-               put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
-               copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
-               put_user(kp->sequence, &up->sequence) ||
-               put_user(kp->reserved, &up->reserved))
-                       return -EFAULT;
+       if (assign_in_user(&up->bytesused, &kp->bytesused) ||
+           assign_in_user(&up->field, &kp->field) ||
+           assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
+           assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
+           copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
+           assign_in_user(&up->sequence, &kp->sequence) ||
+           assign_in_user(&up->input, &kp->input) ||
+           assign_in_user(&up->reserved, &kp->reserved) ||
+           get_user(length, &kp->length) ||
+           put_user(length, &up->length))
+               return -EFAULT;
+
+       if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+               u32 num_planes = length;
 
-       if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
-               num_planes = kp->length;
                if (num_planes == 0)
                        return 0;
 
-               uplane = kp->m.planes;
+               if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
+                       return -EFAULT;
                if (get_user(p, &up->m.planes))
                        return -EFAULT;
                uplane32 = compat_ptr(p);
 
-               while (--num_planes >= 0) {
-                       ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
+               while (num_planes--) {
+                       ret = put_v4l2_plane32(uplane, uplane32, memory);
                        if (ret)
                                return ret;
                        ++uplane;
                        ++uplane32;
                }
        } else {
-               switch (kp->memory) {
+               switch (memory) {
                case V4L2_MEMORY_MMAP:
-                       if (put_user(kp->length, &up->length) ||
-                               put_user(kp->m.offset, &up->m.offset))
+               case V4L2_MEMORY_OVERLAY:
+                       if (assign_in_user(&up->m.offset, &kp->m.offset))
                                return -EFAULT;
                        break;
                case V4L2_MEMORY_USERPTR:
-                       if (put_user(kp->length, &up->length) ||
-                               put_user(kp->m.userptr, &up->m.userptr))
-                               return -EFAULT;
-                       break;
-               case V4L2_MEMORY_OVERLAY:
-                       if (put_user(kp->m.offset, &up->m.offset))
+                       if (assign_in_user(&up->m.userptr, &kp->m.userptr))
                                return -EFAULT;
                        break;
                }
@@ -530,34 +620,46 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
 struct v4l2_framebuffer32 {
        __u32                   capability;
        __u32                   flags;
-       compat_caddr_t          base;
-       struct v4l2_pix_format  fmt;
+       compat_caddr_t          base;
+       struct {
+               __u32           width;
+               __u32           height;
+               __u32           pixelformat;
+               __u32           field;
+               __u32           bytesperline;
+               __u32           sizeimage;
+               __u32           colorspace;
+               __u32           priv;
+       } fmt;
 };
 
-static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
+                                 struct v4l2_framebuffer32 __user *up)
 {
-       u32 tmp;
-
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
-               get_user(tmp, &up->base) ||
-               get_user(kp->capability, &up->capability) ||
-               get_user(kp->flags, &up->flags))
-                       return -EFAULT;
-       kp->base = compat_ptr(tmp);
-       get_v4l2_pix_format(&kp->fmt, &up->fmt);
+       compat_caddr_t tmp;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(tmp, &up->base) ||
+           put_user((__force void *)compat_ptr(tmp), &kp->base) ||
+           assign_in_user(&kp->capability, &up->capability) ||
+           assign_in_user(&kp->flags, &up->flags) ||
+           copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
+               return -EFAULT;
        return 0;
 }
 
-static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
+static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
+                                 struct v4l2_framebuffer32 __user *up)
 {
-       u32 tmp = (u32)((unsigned long)kp->base);
-
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
-               put_user(tmp, &up->base) ||
-               put_user(kp->capability, &up->capability) ||
-               put_user(kp->flags, &up->flags))
-                       return -EFAULT;
-       put_v4l2_pix_format(&kp->fmt, &up->fmt);
+       void *base;
+
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           get_user(base, &kp->base) ||
+           put_user(ptr_to_compat(base), &up->base) ||
+           assign_in_user(&up->capability, &kp->capability) ||
+           assign_in_user(&up->flags, &kp->flags) ||
+           copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
+               return -EFAULT;
        return 0;
 }
 
@@ -567,33 +669,38 @@ struct v4l2_input32 {
        __u32        type;              /*  Type of input */
        __u32        audioset;          /*  Associated audios (bitfield) */
        __u32        tuner;             /*  Associated tuner */
-       v4l2_std_id  std;
+       compat_u64   std;
        __u32        status;
-       __u32        reserved[4];
-} __attribute__ ((packed));
+       __u32        capabilities;
+       __u32        reserved[3];
+};
 
-/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
-   Otherwise it is identical to the 32-bit version. */
-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+/*
+ * The 64-bit v4l2_input struct has extra padding at the end of the struct.
+ * Otherwise it is identical to the 32-bit version.
+ */
+static inline int get_v4l2_input32(struct v4l2_input __user *kp,
+                                  struct v4l2_input32 __user *up)
 {
-       if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
+       if (copy_in_user(kp, up, sizeof(*up)))
                return -EFAULT;
        return 0;
 }
 
-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
+static inline int put_v4l2_input32(struct v4l2_input __user *kp,
+                                  struct v4l2_input32 __user *up)
 {
-       if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
+       if (copy_in_user(up, kp, sizeof(*up)))
                return -EFAULT;
        return 0;
 }
 
 struct v4l2_ext_controls32 {
-       __u32 ctrl_class;
-       __u32 count;
-       __u32 error_idx;
-       __u32 reserved[2];
-       compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
+       __u32 ctrl_class;
+       __u32 count;
+       __u32 error_idx;
+       __u32 reserved[2];
+       compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
 };
 
 struct v4l2_ext_control32 {
@@ -607,53 +714,88 @@ struct v4l2_ext_control32 {
        };
 } __attribute__ ((packed));
 
-/* The following function really belong in v4l2-common, but that causes
-   a circular dependency between modules. We need to think about this, but
-   for now this will do. */
-
-/* Return non-zero if this control is a pointer type. Currently only
-   type STRING is a pointer type. */
-static inline int ctrl_is_pointer(u32 id)
+/* Return true if this control is a pointer type. */
+static inline bool ctrl_is_pointer(struct file *file, u32 id)
 {
-       switch (id) {
-       case V4L2_CID_RDS_TX_PS_NAME:
-       case V4L2_CID_RDS_TX_RADIO_TEXT:
-               return 1;
-       default:
-               return 0;
+       struct video_device *vdev = video_devdata(file);
+       struct v4l2_fh *fh = NULL;
+       struct v4l2_ctrl_handler *hdl = NULL;
+
+       if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
+               fh = file->private_data;
+
+       if (fh && fh->ctrl_handler)
+               hdl = fh->ctrl_handler;
+       else if (vdev->ctrl_handler)
+               hdl = vdev->ctrl_handler;
+
+       if (hdl) {
+               struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
+
+               return ctrl && ctrl->type == V4L2_CTRL_TYPE_STRING;
        }
+       return false;
+}
+
+static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
+                                    u32 *size)
+{
+       u32 count;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           get_user(count, &up->count))
+               return -EFAULT;
+       if (count > V4L2_CID_MAX_CTRLS)
+               return -EINVAL;
+       *size = count * sizeof(struct v4l2_ext_control);
+       return 0;
 }
 
-static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
+static int get_v4l2_ext_controls32(struct file *file,
+                                  struct v4l2_ext_controls __user *kp,
+                                  struct v4l2_ext_controls32 __user *up,
+                                  void __user *aux_buf, u32 aux_space)
 {
        struct v4l2_ext_control32 __user *ucontrols;
        struct v4l2_ext_control __user *kcontrols;
-       int n;
+       u32 count;
+       u32 n;
        compat_caddr_t p;
 
-       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
-               get_user(kp->ctrl_class, &up->ctrl_class) ||
-               get_user(kp->count, &up->count) ||
-               get_user(kp->error_idx, &up->error_idx) ||
-               copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
-                       return -EFAULT;
-       n = kp->count;
-       if (n == 0) {
-               kp->controls = NULL;
-               return 0;
-       }
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
+           assign_in_user(&kp->ctrl_class, &up->ctrl_class) ||
+           get_user(count, &up->count) ||
+           put_user(count, &kp->count) ||
+           assign_in_user(&kp->error_idx, &up->error_idx) ||
+           copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
+               return -EFAULT;
+
+       if (count == 0)
+               return put_user(NULL, &kp->controls);
+       if (count > V4L2_CID_MAX_CTRLS)
+               return -EINVAL;
        if (get_user(p, &up->controls))
                return -EFAULT;
        ucontrols = compat_ptr(p);
-       if (!access_ok(VERIFY_READ, ucontrols,
-                       n * sizeof(struct v4l2_ext_control32)))
+       if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
                return -EFAULT;
-       kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
-       kp->controls = kcontrols;
-       while (--n >= 0) {
+       if (aux_space < count * sizeof(*kcontrols))
+               return -EFAULT;
+       kcontrols = aux_buf;
+       if (put_user((__force struct v4l2_ext_control *)kcontrols,
+                    &kp->controls))
+               return -EFAULT;
+
+       for (n = 0; n < count; n++) {
+               u32 id;
+
                if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
                        return -EFAULT;
-               if (ctrl_is_pointer(kcontrols->id)) {
+
+               if (get_user(id, &kcontrols->id))
+                       return -EFAULT;
+
+               if (ctrl_is_pointer(file, id)) {
                        void __user *s;
 
                        if (get_user(p, &ucontrols->string))
@@ -668,39 +810,55 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
        return 0;
 }
 
-static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
+static int put_v4l2_ext_controls32(struct file *file,
+                                  struct v4l2_ext_controls __user *kp,
+                                  struct v4l2_ext_controls32 __user *up)
 {
        struct v4l2_ext_control32 __user *ucontrols;
-       struct v4l2_ext_control __user *kcontrols = kp->controls;
-       int n = kp->count;
+       struct v4l2_ext_control __user *kcontrols;
+       u32 count;
+       u32 n;
        compat_caddr_t p;
 
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
-               put_user(kp->ctrl_class, &up->ctrl_class) ||
-               put_user(kp->count, &up->count) ||
-               put_user(kp->error_idx, &up->error_idx) ||
-               copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
-                       return -EFAULT;
-       if (!kp->count)
-               return 0;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           assign_in_user(&up->ctrl_class, &kp->ctrl_class) ||
+           get_user(count, &kp->count) ||
+           put_user(count, &up->count) ||
+           assign_in_user(&up->error_idx, &kp->error_idx) ||
+           copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
+           get_user(kcontrols, &kp->controls))
+               return -EFAULT;
 
+       if (!count)
+               return 0;
        if (get_user(p, &up->controls))
                return -EFAULT;
        ucontrols = compat_ptr(p);
-       if (!access_ok(VERIFY_WRITE, ucontrols,
-                       n * sizeof(struct v4l2_ext_control32)))
+       if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols)))
                return -EFAULT;
 
-       while (--n >= 0) {
-               unsigned size = sizeof(*ucontrols);
+       for (n = 0; n < count; n++) {
+               unsigned int size = sizeof(*ucontrols);
+               u32 id;
 
-               /* Do not modify the pointer when copying a pointer control.
-                  The contents of the pointer was changed, not the pointer
-                  itself. */
-               if (ctrl_is_pointer(kcontrols->id))
+               if (get_user(id, &kcontrols->id) ||
+                   put_user(id, &ucontrols->id) ||
+                   assign_in_user(&ucontrols->size, &kcontrols->size) ||
+                   copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
+                                sizeof(ucontrols->reserved2)))
+                       return -EFAULT;
+
+               /*
+                * Do not modify the pointer when copying a pointer control.
+                * The contents of the pointer was changed, not the pointer
+                * itself.
+                */
+               if (ctrl_is_pointer(file, id))
                        size -= sizeof(ucontrols->value64);
+
                if (copy_in_user(ucontrols, kcontrols, size))
                        return -EFAULT;
+
                ucontrols++;
                kcontrols++;
        }
@@ -710,6 +868,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
 struct v4l2_event32 {
        __u32                           type;
        union {
+               compat_s64              value64;
                __u8                    data[64];
        } u;
        __u32                           pending;
@@ -719,17 +878,19 @@ struct v4l2_event32 {
        __u32                           reserved[8];
 };
 
-static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
+static int put_v4l2_event32(struct v4l2_event __user *kp,
+                           struct v4l2_event32 __user *up)
 {
-       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
-               put_user(kp->type, &up->type) ||
-               copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
-               put_user(kp->pending, &up->pending) ||
-               put_user(kp->sequence, &up->sequence) ||
-               put_compat_timespec(&kp->timestamp, &up->timestamp) ||
-               put_user(kp->id, &up->id) ||
-               copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
-                       return -EFAULT;
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
+           assign_in_user(&up->type, &kp->type) ||
+           copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
+           assign_in_user(&up->pending, &kp->pending) ||
+           assign_in_user(&up->sequence, &kp->sequence) ||
+           assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
+           assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
+           assign_in_user(&up->id, &kp->id) ||
+           copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+               return -EFAULT;
        return 0;
 }
 
@@ -742,7 +903,7 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u
 #define VIDIOC_DQBUF32         _IOWR('V', 17, struct v4l2_buffer32)
 #define VIDIOC_ENUMSTD32       _IOWR('V', 25, struct v4l2_standard32)
 #define VIDIOC_ENUMINPUT32     _IOWR('V', 26, struct v4l2_input32)
-#define VIDIOC_TRY_FMT32       _IOWR('V', 64, struct v4l2_format32)
+#define VIDIOC_TRY_FMT32       _IOWR('V', 64, struct v4l2_format32)
 #define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
 #define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
 #define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
@@ -758,21 +919,23 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u
 #define VIDIOC_G_OUTPUT32      _IOR ('V', 46, s32)
 #define VIDIOC_S_OUTPUT32      _IOWR('V', 47, s32)
 
+static int alloc_userspace(unsigned int size, u32 aux_space,
+                          void __user **up_native)
+{
+       *up_native = compat_alloc_user_space(size + aux_space);
+       if (!*up_native)
+               return -ENOMEM;
+       if (clear_user(*up_native, size))
+               return -EFAULT;
+       return 0;
+}
+
 static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       union {
-               struct v4l2_format v2f;
-               struct v4l2_buffer v2b;
-               struct v4l2_framebuffer v2fb;
-               struct v4l2_input v2i;
-               struct v4l2_standard v2s;
-               struct v4l2_ext_controls v2ecs;
-               struct v4l2_event v2ev;
-               struct v4l2_create_buffers v2crt;
-               unsigned long vx;
-               int vi;
-       } karg;
        void __user *up = compat_ptr(arg);
+       void __user *up_native = NULL;
+       void __user *aux_buf;
+       u32 aux_space;
        int compatible_arg = 1;
        long err = 0;
 
@@ -809,24 +972,44 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
        case VIDIOC_STREAMOFF:
        case VIDIOC_S_INPUT:
        case VIDIOC_S_OUTPUT:
-               err = get_user(karg.vi, (s32 __user *)up);
+               err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
+               if (!err && assign_in_user((unsigned int __user *)up_native,
+                                          (compat_uint_t __user *)up))
+                       err = -EFAULT;
                compatible_arg = 0;
                break;
 
        case VIDIOC_G_INPUT:
        case VIDIOC_G_OUTPUT:
+               err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
                compatible_arg = 0;
                break;
 
        case VIDIOC_G_FMT:
        case VIDIOC_S_FMT:
        case VIDIOC_TRY_FMT:
-               err = get_v4l2_format32(&karg.v2f, up);
+               err = bufsize_v4l2_format(up, &aux_space);
+               if (!err)
+                       err = alloc_userspace(sizeof(struct v4l2_format),
+                                             aux_space, &up_native);
+               if (!err) {
+                       aux_buf = up_native + sizeof(struct v4l2_format);
+                       err = get_v4l2_format32(up_native, up,
+                                               aux_buf, aux_space);
+               }
                compatible_arg = 0;
                break;
 
        case VIDIOC_CREATE_BUFS:
-               err = get_v4l2_create32(&karg.v2crt, up);
+               err = bufsize_v4l2_create(up, &aux_space);
+               if (!err)
+                       err = alloc_userspace(sizeof(struct v4l2_create_buffers),
+                                             aux_space, &up_native);
+               if (!err) {
+                       aux_buf = up_native + sizeof(struct v4l2_create_buffers);
+                       err = get_v4l2_create32(up_native, up,
+                                               aux_buf, aux_space);
+               }
                compatible_arg = 0;
                break;
 
@@ -834,36 +1017,63 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
        case VIDIOC_QUERYBUF:
        case VIDIOC_QBUF:
        case VIDIOC_DQBUF:
-               err = get_v4l2_buffer32(&karg.v2b, up);
+               err = bufsize_v4l2_buffer(up, &aux_space);
+               if (!err)
+                       err = alloc_userspace(sizeof(struct v4l2_buffer),
+                                             aux_space, &up_native);
+               if (!err) {
+                       aux_buf = up_native + sizeof(struct v4l2_buffer);
+                       err = get_v4l2_buffer32(up_native, up,
+                                               aux_buf, aux_space);
+               }
                compatible_arg = 0;
                break;
 
        case VIDIOC_S_FBUF:
-               err = get_v4l2_framebuffer32(&karg.v2fb, up);
+               err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
+                                     &up_native);
+               if (!err)
+                       err = get_v4l2_framebuffer32(up_native, up);
                compatible_arg = 0;
                break;
 
        case VIDIOC_G_FBUF:
+               err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
+                                     &up_native);
                compatible_arg = 0;
                break;
 
        case VIDIOC_ENUMSTD:
-               err = get_v4l2_standard32(&karg.v2s, up);
+               err = alloc_userspace(sizeof(struct v4l2_standard), 0,
+                                     &up_native);
+               if (!err)
+                       err = get_v4l2_standard32(up_native, up);
                compatible_arg = 0;
                break;
 
        case VIDIOC_ENUMINPUT:
-               err = get_v4l2_input32(&karg.v2i, up);
+               err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
+               if (!err)
+                       err = get_v4l2_input32(up_native, up);
                compatible_arg = 0;
                break;
 
        case VIDIOC_G_EXT_CTRLS:
        case VIDIOC_S_EXT_CTRLS:
        case VIDIOC_TRY_EXT_CTRLS:
-               err = get_v4l2_ext_controls32(&karg.v2ecs, up);
+               err = bufsize_v4l2_ext_controls(up, &aux_space);
+               if (!err)
+                       err = alloc_userspace(sizeof(struct v4l2_ext_controls),
+                                             aux_space, &up_native);
+               if (!err) {
+                       aux_buf = up_native + sizeof(struct v4l2_ext_controls);
+                       err = get_v4l2_ext_controls32(file, up_native, up,
+                                                     aux_buf, aux_space);
+               }
                compatible_arg = 0;
                break;
        case VIDIOC_DQEVENT:
+               err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
                compatible_arg = 0;
                break;
        }
@@ -872,22 +1082,22 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
 
        if (compatible_arg)
                err = native_ioctl(file, cmd, (unsigned long)up);
-       else {
-               mm_segment_t old_fs = get_fs();
+       else
+               err = native_ioctl(file, cmd, (unsigned long)up_native);
 
-               set_fs(KERNEL_DS);
-               err = native_ioctl(file, cmd, (unsigned long)&karg);
-               set_fs(old_fs);
-       }
+       if (err == -ENOTTY)
+               return err;
 
-       /* Special case: even after an error we need to put the
-          results back for these ioctls since the error_idx will
-          contain information on which control failed. */
+       /*
+        * Special case: even after an error we need to put the
+        * results back for these ioctls since the error_idx will
+        * contain information on which control failed.
+        */
        switch (cmd) {
        case VIDIOC_G_EXT_CTRLS:
        case VIDIOC_S_EXT_CTRLS:
        case VIDIOC_TRY_EXT_CTRLS:
-               if (put_v4l2_ext_controls32(&karg.v2ecs, up))
+               if (put_v4l2_ext_controls32(file, up_native, up))
                        err = -EFAULT;
                break;
        }
@@ -899,39 +1109,42 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
        case VIDIOC_S_OUTPUT:
        case VIDIOC_G_INPUT:
        case VIDIOC_G_OUTPUT:
-               err = put_user(((s32)karg.vi), (s32 __user *)up);
+               if (assign_in_user((compat_uint_t __user *)up,
+                                  ((unsigned int __user *)up_native)))
+                       err = -EFAULT;
                break;
 
        case VIDIOC_G_FBUF:
-               err = put_v4l2_framebuffer32(&karg.v2fb, up);
+               err = put_v4l2_framebuffer32(up_native, up);
                break;
 
        case VIDIOC_DQEVENT:
-               err = put_v4l2_event32(&karg.v2ev, up);
+               err = put_v4l2_event32(up_native, up);
                break;
 
        case VIDIOC_G_FMT:
        case VIDIOC_S_FMT:
        case VIDIOC_TRY_FMT:
-               err = put_v4l2_format32(&karg.v2f, up);
+               err = put_v4l2_format32(up_native, up);
                break;
 
        case VIDIOC_CREATE_BUFS:
-               err = put_v4l2_create32(&karg.v2crt, up);
+               err = put_v4l2_create32(up_native, up);
                break;
 
+       case VIDIOC_PREPARE_BUF:
        case VIDIOC_QUERYBUF:
        case VIDIOC_QBUF:
        case VIDIOC_DQBUF:
-               err = put_v4l2_buffer32(&karg.v2b, up);
+               err = put_v4l2_buffer32(up_native, up);
                break;
 
        case VIDIOC_ENUMSTD:
-               err = put_v4l2_standard32(&karg.v2s, up);
+               err = put_v4l2_standard32(up_native, up);
                break;
 
        case VIDIOC_ENUMINPUT:
-               err = put_v4l2_input32(&karg.v2i, up);
+               err = put_v4l2_input32(up_native, up);
                break;
        }
        return err;
@@ -1026,8 +1239,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
 
        default:
                printk(KERN_WARNING "compat_ioctl32: "
-                       "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
-                       _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
+                      "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
+                      _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
                break;
        }
        return ret;
index 639abee..bae5dd7 100644 (file)
@@ -2308,8 +2308,10 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
 
        /* Handles IOCTL */
        err = func(file, cmd, parg);
-       if (err == -ENOIOCTLCMD)
-               err = -EINVAL;
+       if (err == -ENOTTY || err == -ENOIOCTLCMD) {
+               err = -ENOTTY;
+               goto out;
+       }
 
        if (has_array_args) {
                *kernel_ptr = user_ptr;
index ab1ad41..18b2dec 100644 (file)
@@ -274,6 +274,9 @@ static ssize_t at24_read(struct at24_data *at24,
        if (unlikely(!count))
                return count;
 
+       if (off + count > at24->chip.byte_len)
+               return -EINVAL;
+
        /*
         * Read data from chip, protecting against concurrent updates
         * from this host, but not from other I2C masters.
@@ -396,6 +399,9 @@ static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
        if (unlikely(!count))
                return count;
 
+       if (off + count > at24->chip.byte_len)
+               return -EINVAL;
+
        /*
         * Write data to chip, protecting against concurrent updates
         * from this host, but not from other I2C masters.
index cbee842..2419b0f 100644 (file)
@@ -320,6 +320,7 @@ int enclosure_add_device(struct enclosure_device *edev, int component,
                         struct device *dev)
 {
        struct enclosure_component *cdev;
+       int err;
 
        if (!edev || component >= edev->components)
                return -EINVAL;
@@ -329,12 +330,17 @@ int enclosure_add_device(struct enclosure_device *edev, int component,
        if (cdev->dev == dev)
                return -EEXIST;
 
-       if (cdev->dev)
+       if (cdev->dev) {
                enclosure_remove_links(cdev);
-
-       put_device(cdev->dev);
+               put_device(cdev->dev);
+       }
        cdev->dev = get_device(dev);
-       return enclosure_add_links(cdev);
+       err = enclosure_add_links(cdev);
+       if (err) {
+               put_device(cdev->dev);
+               cdev->dev = NULL;
+       }
+       return err;
 }
 EXPORT_SYMBOL_GPL(enclosure_add_device);
 
index cd41d40..cb56e27 100644 (file)
@@ -314,7 +314,7 @@ static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target)
  * fear that guest will need it. Host may reject some pages, we need to
  * check the return value and maybe submit a different page.
  */
-static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn,
+static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn,
                                     unsigned int *hv_status)
 {
        unsigned long status, dummy;
@@ -322,17 +322,17 @@ static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn,
 
        pfn32 = (u32)pfn;
        if (pfn32 != pfn)
-               return false;
+               return -1;
 
        STATS_INC(b->stats.lock);
 
        *hv_status = status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy);
        if (vmballoon_check_status(b, status))
-               return true;
+               return 0;
 
        pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status);
        STATS_INC(b->stats.lock_fail);
-       return false;
+       return 1;
 }
 
 /*
@@ -411,7 +411,7 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep)
        struct page *page;
        gfp_t flags;
        unsigned int hv_status;
-       bool locked = false;
+       int locked;
        flags = can_sleep ? VMW_PAGE_ALLOC_CANSLEEP : VMW_PAGE_ALLOC_NOSLEEP;
 
        do {
@@ -431,7 +431,7 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep)
 
                /* inform monitor */
                locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status);
-               if (!locked) {
+               if (locked > 0) {
                        STATS_INC(b->stats.refused_alloc);
 
                        if (hv_status == VMW_BALLOON_ERROR_RESET ||
@@ -449,7 +449,7 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep)
                        if (++b->n_refused_pages >= VMW_BALLOON_MAX_REFUSED)
                                return -EIO;
                }
-       } while (!locked);
+       } while (locked != 0);
 
        /* track allocated page */
        list_add(&page->lru, &b->pages);
index 69f26f3..602d2a8 100644 (file)
@@ -59,6 +59,9 @@ MODULE_ALIAS("mmc:block");
 #define INAND_CMD38_ARG_SECTRIM1 0x81
 #define INAND_CMD38_ARG_SECTRIM2 0x88
 
+#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
+#define MMC_EXTRACT_VALUE_FROM_ARG(x) ((x & 0x0000FF00) >> 8)
+
 static DEFINE_MUTEX(block_mutex);
 
 /*
@@ -393,6 +396,24 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
                goto cmd_rel_host;
        }
 
+       /*
+        * Make sure the cache of the PARTITION_CONFIG register and
+        * PARTITION_ACCESS bits is updated in case the ioctl ext_csd write
+        * changed it successfully.
+        */
+       if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_PART_CONFIG) &&
+           (cmd.opcode == MMC_SWITCH)) {
+               struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
+               u8 value = MMC_EXTRACT_VALUE_FROM_ARG(cmd.arg);
+
+               /*
+                * Update cache so the next mmc_blk_part_switch call operates
+                * on up-to-date data.
+                */
+               card->ext_csd.part_config = value;
+               main_md->part_curr = value & EXT_CSD_PART_CONFIG_ACC_MASK;
+       }
+
        /*
         * According to the SD specs, some commands require a delay after
         * issuing the command.
index 720f993..1530fb4 100644 (file)
@@ -1460,7 +1460,9 @@ static const struct file_operations s3cmci_fops_state = {
 struct s3cmci_reg {
        unsigned short  addr;
        unsigned char   *name;
-} debug_regs[] = {
+};
+
+static const struct s3cmci_reg debug_regs[] = {
        DBG_REG(CON),
        DBG_REG(PRE),
        DBG_REG(CMDARG),
@@ -1482,7 +1484,7 @@ struct s3cmci_reg {
 static int s3cmci_regs_show(struct seq_file *seq, void *v)
 {
        struct s3cmci_host *host = seq->private;
-       struct s3cmci_reg *rptr = debug_regs;
+       const struct s3cmci_reg *rptr = debug_regs;
 
        for (; rptr->name; rptr++)
                seq_printf(seq, "SDI%s\t=0x%08x\n", rptr->name,
index c443f52..88ce823 100644 (file)
@@ -1888,6 +1888,8 @@ static inline u32 jedec_read_mfr(struct map_info *map, uint32_t base,
        do {
                uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi);
                mask = (1 << (cfi->device_type * 8)) - 1;
+               if (ofs >= map->size)
+                       return 0;
                result = map_read(map, base + ofs);
                bank++;
        } while ((result.x[0] & mask) == CFI_MFR_CONTINUATION);
index 9c35250..077d88a 100644 (file)
@@ -378,7 +378,7 @@ static int __devinit sst25l_probe(struct spi_device *spi)
        struct flash_info *flash_info;
        struct sst25l_flash *flash;
        struct flash_platform_data *data;
-       int ret, i;
+       int ret;
 
        flash_info = sst25l_match_device(spi);
        if (!flash_info)
index 89b8583..e1596e5 100644 (file)
@@ -2290,6 +2290,7 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
                            size_t *retlen, const uint8_t *buf)
 {
        struct nand_chip *chip = mtd->priv;
+       int chipnr = (int)(to >> chip->chip_shift);
        struct mtd_oob_ops ops;
        int ret;
 
@@ -2299,12 +2300,14 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
        if (!len)
                return 0;
 
-       /* Wait for the device to get ready */
-       panic_nand_wait(mtd, chip, 400);
-
        /* Grab the device */
        panic_nand_get_device(chip, mtd, FL_WRITING);
 
+       chip->select_chip(mtd, chipnr);
+
+       /* Wait for the device to get ready */
+       panic_nand_wait(mtd, chip, 400);
+
        ops.len = len;
        ops.datbuf = (uint8_t *)buf;
        ops.oobbuf = NULL;
index 0669cff..9df07ad 100644 (file)
@@ -308,6 +308,12 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
                        vol->last_eb_bytes = vol->usable_leb_size;
        }
 
+       /* Make volume "available" before it becomes accessible via sysfs */
+       spin_lock(&ubi->volumes_lock);
+       ubi->volumes[vol_id] = vol;
+       ubi->vol_count += 1;
+       spin_unlock(&ubi->volumes_lock);
+
        /* Register character device for the volume */
        cdev_init(&vol->cdev, &ubi_vol_cdev_operations);
        vol->cdev.owner = THIS_MODULE;
@@ -350,11 +356,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
        if (err)
                goto out_sysfs;
 
-       spin_lock(&ubi->volumes_lock);
-       ubi->volumes[vol_id] = vol;
-       ubi->vol_count += 1;
-       spin_unlock(&ubi->volumes_lock);
-
        ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED);
        self_check_volumes(ubi);
        return err;
@@ -374,6 +375,10 @@ out_sysfs:
 out_cdev:
        cdev_del(&vol->cdev);
 out_mapping:
+       spin_lock(&ubi->volumes_lock);
+       ubi->volumes[vol_id] = NULL;
+       ubi->vol_count -= 1;
+       spin_unlock(&ubi->volumes_lock);
        if (do_free)
                kfree(vol->eba_tbl);
 out_acc:
index 9145834..18ebffa 100644 (file)
@@ -1704,8 +1704,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                /* set allmulti level to new slave */
                if (bond_dev->flags & IFF_ALLMULTI) {
                        res = dev_set_allmulti(slave_dev, 1);
-                       if (res)
+                       if (res) {
+                               if (bond_dev->flags & IFF_PROMISC)
+                                       dev_set_promiscuity(slave_dev, -1);
                                goto err_close;
+                       }
                }
 
                netif_addr_lock_bh(bond_dev);
index a5eeeb1..af3abc6 100644 (file)
@@ -651,6 +651,9 @@ static int ti_hecc_rx_poll(struct napi_struct *napi, int quota)
                mbx_mask = hecc_read(priv, HECC_CANMIM);
                mbx_mask |= HECC_TX_MBOX_MASK;
                hecc_write(priv, HECC_CANMIM, mbx_mask);
+       } else {
+               /* repoll is done only if whole budget is used */
+               num_pkts = quota;
        }
 
        return num_pkts;
index 3b8c4da..96f500c 100644 (file)
@@ -292,6 +292,8 @@ static void ems_usb_read_interrupt_callback(struct urb *urb)
 
        case -ECONNRESET: /* unlink */
        case -ENOENT:
+       case -EPIPE:
+       case -EPROTO:
        case -ESHUTDOWN:
                return;
 
index 9ecf098..68b51c0 100644 (file)
@@ -332,7 +332,7 @@ static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
                }
 
                cf->can_id = id & ESD_IDMASK;
-               cf->can_dlc = get_can_dlc(msg->msg.rx.dlc);
+               cf->can_dlc = get_can_dlc(msg->msg.rx.dlc & ~ESD_RTR);
 
                if (id & ESD_EXTID)
                        cf->can_id |= CAN_EFF_FLAG;
@@ -393,6 +393,8 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
                break;
 
        case -ENOENT:
+       case -EPIPE:
+       case -EPROTO:
        case -ESHUTDOWN:
                return;
 
index 3accd5d..3279a1a 100644 (file)
@@ -625,7 +625,7 @@ static int nmclan_config(struct pcmcia_device *link)
   ret = pcmcia_request_io(link);
   if (ret)
          goto failed;
-  ret = pcmcia_request_exclusive_irq(link, mace_interrupt);
+  ret = pcmcia_request_irq(link, mace_interrupt);
   if (ret)
          goto failed;
   ret = pcmcia_enable_device(link);
@@ -955,6 +955,8 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
   do {
     /* WARNING: MACE_IR is a READ/CLEAR port! */
     status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR);
+    if (!(status & ~MACE_IMR_DEFAULT) && IntrCnt == MACE_MAX_IR_ITERATIONS)
+      return IRQ_NONE;
 
     pr_debug("mace_interrupt: irq 0x%X status 0x%X.\n", irq, status);
 
index 5bf5471..fa59553 100644 (file)
@@ -706,9 +706,11 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        return NETDEV_TX_OK;
 }
 
-static void fs_timeout(struct net_device *dev)
+static void fs_timeout_work(struct work_struct *work)
 {
-       struct fs_enet_private *fep = netdev_priv(dev);
+       struct fs_enet_private *fep = container_of(work, struct fs_enet_private,
+                                                  timeout_work);
+       struct net_device *dev = fep->ndev;
        unsigned long flags;
        int wake = 0;
 
@@ -720,7 +722,6 @@ static void fs_timeout(struct net_device *dev)
                phy_stop(fep->phydev);
                (*fep->ops->stop)(dev);
                (*fep->ops->restart)(dev);
-               phy_start(fep->phydev);
        }
 
        phy_start(fep->phydev);
@@ -731,6 +732,13 @@ static void fs_timeout(struct net_device *dev)
                netif_wake_queue(dev);
 }
 
+static void fs_timeout(struct net_device *dev)
+{
+       struct fs_enet_private *fep = netdev_priv(dev);
+
+       schedule_work(&fep->timeout_work);
+}
+
 /*-----------------------------------------------------------------------------
  *  generic link-change handler - should be sufficient for most cases
  *-----------------------------------------------------------------------------*/
@@ -857,6 +865,7 @@ static int fs_enet_close(struct net_device *dev)
        netif_carrier_off(dev);
        if (fep->fpi->use_napi)
                napi_disable(&fep->napi);
+       cancel_work_sync(&fep->timeout_work);
        phy_stop(fep->phydev);
 
        spin_lock_irqsave(&fep->lock, flags);
@@ -1080,6 +1089,7 @@ static int __devinit fs_enet_probe(struct platform_device *ofdev)
 
        ndev->netdev_ops = &fs_enet_netdev_ops;
        ndev->watchdog_timeo = 2 * HZ;
+       INIT_WORK(&fep->timeout_work, fs_timeout_work);
        if (fpi->use_napi)
                netif_napi_add(ndev, &fep->napi, fs_enet_rx_napi,
                               fpi->napi_weight);
index 1ece4b1..65b5c5f 100644 (file)
@@ -124,6 +124,7 @@ struct fs_enet_private {
        spinlock_t lock;        /* during all ops except TX pckt processing */
        spinlock_t tx_lock;     /* during fs_start_xmit and fs_tx         */
        struct fs_platform_info *fpi;
+       struct work_struct timeout_work;
        const struct fs_ops *ops;
        int rx_ring, tx_ring;
        dma_addr_t ring_mem_addr;
index e2a80a2..55895af 100644 (file)
@@ -657,6 +657,9 @@ out:
  *  Checks to see of the link status of the hardware has changed.  If a
  *  change in link status has been detected, then we read the PHY registers
  *  to get the current speed/duplex if link exists.
+ *
+ *  Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link
+ *  up).
  **/
 static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
 {
@@ -672,7 +675,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
         * Change or Rx Sequence Error interrupt.
         */
        if (!mac->get_link_status) {
-               ret_val = 0;
+               ret_val = 1;
                goto out;
        }
 
@@ -743,7 +746,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
         * we have already determined whether we have link or not.
         */
        if (!mac->autoneg) {
-               ret_val = -E1000_ERR_CONFIG;
+               ret_val = 1;
                goto out;
        }
 
@@ -761,9 +764,12 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
         * different link partner.
         */
        ret_val = e1000e_config_fc_after_link_up(hw);
-       if (ret_val)
+       if (ret_val) {
                e_dbg("Error configuring flow control\n");
+               return ret_val;
+       }
 
+       ret_val = 1;
 out:
        return ret_val;
 }
index 0893ab1..bfc80c3 100644 (file)
@@ -435,6 +435,9 @@ void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw)
  *  Checks to see of the link status of the hardware has changed.  If a
  *  change in link status has been detected, then we read the PHY registers
  *  to get the current speed/duplex if link exists.
+ *
+ *  Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link
+ *  up).
  **/
 s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
 {
@@ -449,7 +452,7 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
         * Change or Rx Sequence Error interrupt.
         */
        if (!mac->get_link_status)
-               return 0;
+               return 1;
 
        /*
         * First we want to see if the MII Status Register reports
@@ -475,10 +478,8 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
         * If we are forcing speed/duplex, then we simply return since
         * we have already determined whether we have link or not.
         */
-       if (!mac->autoneg) {
-               ret_val = -E1000_ERR_CONFIG;
-               return ret_val;
-       }
+       if (!mac->autoneg)
+               return 1;
 
        /*
         * Auto-Neg is enabled.  Auto Speed Detection takes care
@@ -494,10 +495,12 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
         * different link partner.
         */
        ret_val = e1000e_config_fc_after_link_up(hw);
-       if (ret_val)
+       if (ret_val) {
                e_dbg("Error configuring flow control\n");
+               return ret_val;
+       }
 
-       return ret_val;
+       return 1;
 }
 
 /**
index a783530..73cc0f6 100644 (file)
@@ -4222,7 +4222,7 @@ static bool e1000e_has_link(struct e1000_adapter *adapter)
        case e1000_media_type_copper:
                if (hw->mac.get_link_status) {
                        ret_val = hw->mac.ops.check_for_link(hw);
-                       link_active = !hw->mac.get_link_status;
+                       link_active = ret_val > 0;
                } else {
                        link_active = 1;
                }
index 74e2a2a..11c51bc 100644 (file)
@@ -101,27 +101,28 @@ static void mlx4_en_get_wol(struct net_device *netdev,
                            struct ethtool_wolinfo *wol)
 {
        struct mlx4_en_priv *priv = netdev_priv(netdev);
+       struct mlx4_caps *caps = &priv->mdev->dev->caps;
        int err = 0;
        u64 config = 0;
 
-       if (!(priv->mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_WOL)) {
+       if (!(caps->flags & MLX4_DEV_CAP_FLAG_WOL)) {
                wol->supported = 0;
                wol->wolopts = 0;
                return;
        }
 
+       if (caps->wol_port[priv->port])
+               wol->supported = WAKE_MAGIC;
+       else
+               wol->supported = 0;
+
        err = mlx4_wol_read(priv->mdev->dev, &config, priv->port);
        if (err) {
                en_err(priv, "Failed to get WoL information\n");
                return;
        }
 
-       if (config & MLX4_EN_WOL_MAGIC)
-               wol->supported = WAKE_MAGIC;
-       else
-               wol->supported = 0;
-
-       if (config & MLX4_EN_WOL_ENABLED)
+       if ((config & MLX4_EN_WOL_ENABLED) && (config & MLX4_EN_WOL_MAGIC))
                wol->wolopts = WAKE_MAGIC;
        else
                wol->wolopts = 0;
@@ -361,18 +362,29 @@ static int mlx4_en_set_pauseparam(struct net_device *dev,
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
+       u8 tx_pause, tx_ppp, rx_pause, rx_ppp;
        int err;
 
-       priv->prof->tx_pause = pause->tx_pause != 0;
-       priv->prof->rx_pause = pause->rx_pause != 0;
+       if (pause->autoneg)
+               return -EINVAL;
+
+       tx_pause = !!(pause->tx_pause);
+       rx_pause = !!(pause->rx_pause);
+       rx_ppp = priv->prof->rx_ppp && !(tx_pause || rx_pause);
+       tx_ppp = priv->prof->tx_ppp && !(tx_pause || rx_pause);
+
        err = mlx4_SET_PORT_general(mdev->dev, priv->port,
                                    priv->rx_skb_size + ETH_FCS_LEN,
-                                   priv->prof->tx_pause,
-                                   priv->prof->tx_ppp,
-                                   priv->prof->rx_pause,
-                                   priv->prof->rx_ppp);
-       if (err)
-               en_err(priv, "Failed setting pause params\n");
+                                   tx_pause, tx_ppp, rx_pause, rx_ppp);
+       if (err) {
+               en_err(priv, "Failed setting pause params, err = %d\n", err);
+               return err;
+       }
+
+       priv->prof->tx_pause = tx_pause;
+       priv->prof->rx_pause = rx_pause;
+       priv->prof->tx_ppp = tx_ppp;
+       priv->prof->rx_ppp = rx_ppp;
 
        return err;
 }
index a06096f..725ac17 100644 (file)
@@ -112,9 +112,9 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
                params->udp_rss = 0;
        }
        for (i = 1; i <= MLX4_MAX_PORTS; i++) {
-               params->prof[i].rx_pause = 1;
+               params->prof[i].rx_pause = !(pfcrx || pfctx);
                params->prof[i].rx_ppp = pfcrx;
-               params->prof[i].tx_pause = 1;
+               params->prof[i].tx_pause = !(pfcrx || pfctx);
                params->prof[i].tx_ppp = pfctx;
                params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE;
                params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE;
index 435ca6e..46aae5b 100644 (file)
@@ -189,6 +189,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 #define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET      0x3c
 #define QUERY_DEV_CAP_MAX_PKEY_OFFSET          0x3f
 #define QUERY_DEV_CAP_EXT_FLAGS_OFFSET         0x40
+#define QUERY_DEV_CAP_WOL_OFFSET               0x43
 #define QUERY_DEV_CAP_FLAGS_OFFSET             0x44
 #define QUERY_DEV_CAP_RSVD_UAR_OFFSET          0x48
 #define QUERY_DEV_CAP_UAR_SZ_OFFSET            0x49
@@ -285,6 +286,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        MLX4_GET(ext_flags, outbox, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
        MLX4_GET(flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
        dev_cap->flags = flags | (u64)ext_flags << 32;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_WOL_OFFSET);
+       dev_cap->wol_port[1] = !!(field & 0x20);
+       dev_cap->wol_port[2] = !!(field & 0x40);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET);
        dev_cap->reserved_uars = field >> 4;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_UAR_SZ_OFFSET);
@@ -508,7 +512,7 @@ int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt)
                for (i = 0; i < mlx4_icm_size(&iter) >> lg; ++i) {
                        if (virt != -1) {
                                pages[nent * 2] = cpu_to_be64(virt);
-                               virt += 1 << lg;
+                               virt += 1ULL << lg;
                        }
 
                        pages[nent * 2 + 1] =
index bf5ec22..bd6e404 100644 (file)
@@ -114,6 +114,7 @@ struct mlx4_dev_cap {
        u8  log_max_macs[MLX4_MAX_PORTS + 1];
        u8  log_max_vlans[MLX4_MAX_PORTS + 1];
        u32 max_counters;
+       bool wol_port[MLX4_MAX_PORTS + 1];
 };
 
 struct mlx4_adapter {
index b02adbc..ca46ea3 100644 (file)
@@ -234,6 +234,8 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        dev->caps.reserved_lkey      = dev_cap->reserved_lkey;
        dev->caps.stat_rate_support  = dev_cap->stat_rate_support;
        dev->caps.max_gso_sz         = dev_cap->max_gso_sz;
+       dev->caps.wol_port[1]          = dev_cap->wol_port[1];
+       dev->caps.wol_port[2]          = dev_cap->wol_port[2];
 
        dev->caps.log_num_macs  = log_num_mac;
        dev->caps.log_num_vlans = MLX4_LOG_NUM_VLANS;
index fca804f..a11195f 100644 (file)
@@ -724,7 +724,7 @@ static void ql_build_coredump_seg_header(
        seg_hdr->cookie = MPI_COREDUMP_COOKIE;
        seg_hdr->segNum = seg_number;
        seg_hdr->segSize = seg_size;
-       memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
+       strncpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
 }
 
 /*
index e3f57fd..8c7dd4d 100644 (file)
@@ -176,8 +176,7 @@ struct net_local {
     unsigned int tx_unit_busy:1;
     unsigned char re_tx,       /* Number of packet retransmissions. */
                addr_mode,              /* Current Rx filter e.g. promiscuous, etc. */
-               pac_cnt_in_tx_buf,
-               chip_type;
+               pac_cnt_in_tx_buf;
 };
 
 /* This code, written by wwc@super.org, resets the adapter every
@@ -340,7 +339,6 @@ static int __init atp_probe1(long ioaddr)
        write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX);
 
        lp = netdev_priv(dev);
-       lp->chip_type = RTL8002;
        lp->addr_mode = CMR2h_Normal;
        spin_lock_init(&lp->lock);
 
@@ -853,7 +851,7 @@ net_close(struct net_device *dev)
  *     Set or clear the multicast filter for this adapter.
  */
 
-static void set_rx_mode_8002(struct net_device *dev)
+static void set_rx_mode(struct net_device *dev)
 {
        struct net_local *lp = netdev_priv(dev);
        long ioaddr = dev->base_addr;
@@ -865,58 +863,6 @@ static void set_rx_mode_8002(struct net_device *dev)
        write_reg_high(ioaddr, CMR2, lp->addr_mode);
 }
 
-static void set_rx_mode_8012(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-       long ioaddr = dev->base_addr;
-       unsigned char new_mode, mc_filter[8]; /* Multicast hash filter */
-       int i;
-
-       if (dev->flags & IFF_PROMISC) {                 /* Set promiscuous. */
-               new_mode = CMR2h_PROMISC;
-       } else if ((netdev_mc_count(dev) > 1000) ||
-                  (dev->flags & IFF_ALLMULTI)) {
-               /* Too many to filter perfectly -- accept all multicasts. */
-               memset(mc_filter, 0xff, sizeof(mc_filter));
-               new_mode = CMR2h_Normal;
-       } else {
-               struct netdev_hw_addr *ha;
-
-               memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(ha, dev) {
-                       int filterbit = ether_crc_le(ETH_ALEN, ha->addr) & 0x3f;
-                       mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
-               }
-               new_mode = CMR2h_Normal;
-       }
-       lp->addr_mode = new_mode;
-    write_reg(ioaddr, CMR2, CMR2_IRQOUT | 0x04); /* Switch to page 1. */
-    for (i = 0; i < 8; i++)
-               write_reg_byte(ioaddr, i, mc_filter[i]);
-       if (net_debug > 2 || 1) {
-               lp->addr_mode = 1;
-               printk(KERN_DEBUG "%s: Mode %d, setting multicast filter to",
-                          dev->name, lp->addr_mode);
-               for (i = 0; i < 8; i++)
-                       printk(" %2.2x", mc_filter[i]);
-               printk(".\n");
-       }
-
-       write_reg_high(ioaddr, CMR2, lp->addr_mode);
-    write_reg(ioaddr, CMR2, CMR2_IRQOUT); /* Switch back to page 0 */
-}
-
-static void set_rx_mode(struct net_device *dev)
-{
-       struct net_local *lp = netdev_priv(dev);
-
-       if (lp->chip_type == RTL8002)
-               return set_rx_mode_8002(dev);
-       else
-               return set_rx_mode_8012(dev);
-}
-
-
 static int __init atp_init_module(void) {
        if (debug)                                      /* Emit version even if no cards detected. */
                printk(KERN_INFO "%s", version);
index 0edc642..040b137 100644 (file)
@@ -16,8 +16,6 @@ struct rx_header {
 #define PAR_STATUS     1
 #define PAR_CONTROL 2
 
-enum chip_type { RTL8002, RTL8012 };
-
 #define Ctrl_LNibRead  0x08    /* LP_PSELECP */
 #define Ctrl_HNibRead  0
 #define Ctrl_LNibWrite 0x08    /* LP_PSELECP */
index 0c26787..356b7d4 100644 (file)
@@ -5371,7 +5371,6 @@ static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
                        rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
                                             tp->TxDescArray + entry);
                        if (skb) {
-                               tp->dev->stats.tx_dropped++;
                                dev_kfree_skb_any(skb);
                                tx_skb->skb = NULL;
                        }
index da269d7..738589f 100644 (file)
@@ -54,7 +54,7 @@ int efx_mcdi_set_mac(struct efx_nic *efx)
                            NULL, 0, NULL);
 }
 
-static int efx_mcdi_get_mac_faults(struct efx_nic *efx, u32 *faults)
+static bool efx_mcdi_mac_check_fault(struct efx_nic *efx)
 {
        u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
        size_t outlength;
@@ -64,16 +64,13 @@ static int efx_mcdi_get_mac_faults(struct efx_nic *efx, u32 *faults)
 
        rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
                          outbuf, sizeof(outbuf), &outlength);
-       if (rc)
-               goto fail;
-
-       *faults = MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT);
-       return 0;
+       if (rc) {
+               netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
+                         __func__, rc);
+               return true;
+       }
 
-fail:
-       netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
-                 __func__, rc);
-       return rc;
+       return MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT) != 0;
 }
 
 int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
@@ -132,14 +129,6 @@ static int efx_mcdi_mac_reconfigure(struct efx_nic *efx)
 }
 
 
-static bool efx_mcdi_mac_check_fault(struct efx_nic *efx)
-{
-       u32 faults;
-       int rc = efx_mcdi_get_mac_faults(efx, &faults);
-       return (rc != 0) || (faults != 0);
-}
-
-
 const struct efx_mac_operations efx_mcdi_mac_operations = {
        .reconfigure    = efx_mcdi_mac_reconfigure,
        .update_stats   = efx_port_dummy_op_void,
index 1c3db94..de286ef 100644 (file)
@@ -951,10 +951,12 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
                return 0;
 
        case TUNSETSNDBUF:
-               if (get_user(u, up))
+               if (get_user(s, sp))
                        return -EFAULT;
+               if (s <= 0)
+                       return -EINVAL;
 
-               q->sk.sk_sndbuf = u;
+               q->sk.sk_sndbuf = s;
                return 0;
 
        case TUNGETVNETHDRSZ:
index 4915d10..6394850 100644 (file)
@@ -808,7 +808,7 @@ static struct phy_driver marvell_drivers[] = {
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
                .config_init = &m88e1145_config_init,
-               .config_aneg = &marvell_config_aneg,
+               .config_aneg = &m88e1101_config_aneg,
                .read_status = &genphy_read_status,
                .ack_interrupt = &marvell_ack_interrupt,
                .config_intr = &marvell_config_intr,
index 239e6e7..abbc430 100644 (file)
@@ -838,6 +838,7 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
        struct pppoe_hdr *ph;
        struct net_device *dev;
        char *start;
+       int hlen;
 
        lock_sock(sk);
        if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) {
@@ -856,16 +857,16 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
        if (total_len > (dev->mtu + dev->hard_header_len))
                goto end;
 
-
-       skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
-                          0, GFP_KERNEL);
+       hlen = LL_RESERVED_SPACE(dev);
+       skb = sock_wmalloc(sk, hlen + sizeof(*ph) + total_len +
+                          dev->needed_tailroom, 0, GFP_KERNEL);
        if (!skb) {
                error = -ENOMEM;
                goto end;
        }
 
        /* Reserve space for headers. */
-       skb_reserve(skb, dev->hard_header_len);
+       skb_reserve(skb, hlen);
        skb_reset_network_header(skb);
 
        skb->dev = dev;
@@ -926,7 +927,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
        /* Copy the data if there is no space for the header or if it's
         * read-only.
         */
-       if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len))
+       if (skb_cow_head(skb, LL_RESERVED_SPACE(dev) + sizeof(*ph)))
                goto abort;
 
        __skb_push(skb, sizeof(*ph));
index 1a6e2ea..d9ebe38 100644 (file)
@@ -719,7 +719,7 @@ static void sl_sync(void)
 
 
 /* Find a free SLIP channel, and link in this `tty' line. */
-static struct slip *sl_alloc(dev_t line)
+static struct slip *sl_alloc(void)
 {
        int i;
        char name[IFNAMSIZ];
@@ -800,7 +800,7 @@ static int slip_open(struct tty_struct *tty)
 
        /* OK.  Find a free SLIP channel to use. */
        err = -ENFILE;
-       sl = sl_alloc(tty_devnum(tty));
+       sl = sl_alloc();
        if (sl == NULL)
                goto err_exit;
 
index 9c2e91c..e4788b1 100644 (file)
@@ -1397,6 +1397,10 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
                        ret = -EFAULT;
                        break;
                }
+               if (sndbuf <= 0) {
+                       ret = -EINVAL;
+                       break;
+               }
 
                tun->socket.sk->sk_sndbuf = sndbuf;
                break;
index 43aa06b..a1ca474 100644 (file)
@@ -234,8 +234,9 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                                        info->ether->bLength);
                                goto bad_desc;
                        }
-                       dev->hard_mtu = le16_to_cpu(
-                                               info->ether->wMaxSegmentSize);
+                       if (info->ether->wMaxSegmentSize)
+                               dev->hard_mtu = le16_to_cpu(
+                                       info->ether->wMaxSegmentSize);
                        /* because of Zaurus, we may be ignoring the host
                         * side link address we were given.
                         */
index 6617325..f1235ed 100644 (file)
@@ -419,7 +419,7 @@ static void smsc95xx_set_multicast(struct net_device *netdev)
 static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
                                            u16 lcladv, u16 rmtadv)
 {
-       u32 flow, afc_cfg = 0;
+       u32 flow = 0, afc_cfg;
 
        int ret = smsc95xx_read_reg(dev, AFC_CFG, &afc_cfg);
        if (ret < 0) {
@@ -432,20 +432,19 @@ static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex,
 
                if (cap & FLOW_CTRL_RX)
                        flow = 0xFFFF0002;
-               else
-                       flow = 0;
 
-               if (cap & FLOW_CTRL_TX)
+               if (cap & FLOW_CTRL_TX) {
                        afc_cfg |= 0xF;
-               else
+                       flow |= 0xFFFF0000;
+               } else {
                        afc_cfg &= ~0xF;
+               }
 
                netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s\n",
                                   cap & FLOW_CTRL_RX ? "enabled" : "disabled",
                                   cap & FLOW_CTRL_TX ? "enabled" : "disabled");
        } else {
                netif_dbg(dev, link, dev->net, "half duplex\n");
-               flow = 0;
                afc_cfg |= 0xF;
        }
 
index 797e2d1..73e84e5 100644 (file)
@@ -183,7 +183,7 @@ struct hif_scatter_req {
        /* bounce buffer for upper layers to copy to/from */
        u8 *virt_dma_buf;
 
-       struct hif_scatter_item scat_list[1];
+       struct hif_scatter_item scat_list[0];
 };
 
 struct ath6kl_hif_ops {
index 066d4f8..edec7c7 100644 (file)
@@ -319,7 +319,7 @@ static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio,
        int i, scat_req_sz, scat_list_sz, sg_sz, buf_sz;
        u8 *virt_buf;
 
-       scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item);
+       scat_list_sz = n_scat_entry * sizeof(struct hif_scatter_item);
        scat_req_sz = sizeof(*s_req) + scat_list_sz;
 
        if (!virt_scat)
@@ -670,7 +670,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
 {
        struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
        struct htc_target *target = ar->htc_target;
-       int ret;
+       int ret = 0;
        bool virt_scat = false;
 
        /* check if host supports scatter and it meets our requirements */
index b6cd36c..f051e0c 100644 (file)
@@ -1640,6 +1640,10 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
+               if (tid >= ATH9K_HTC_MAX_TID) {
+                       ret = -EINVAL;
+                       break;
+               }
                ista = (struct ath9k_htc_sta *) sta->drv_priv;
                spin_lock_bh(&priv->tx.tx_lock);
                ista->tid_state[tid] = AGGR_OPERATIONAL;
index e4e326a..adf99be 100644 (file)
@@ -2465,7 +2465,7 @@ static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv)
        return err;
 }
 
-static void brcmf_delay(u32 ms)
+static __always_inline void brcmf_delay(u32 ms)
 {
        if (ms < 1000 / HZ) {
                cond_resched();
index 025fa0e..68d0505 100644 (file)
@@ -1193,9 +1193,6 @@ void ai_detach(struct si_pub *sih)
 {
        struct si_info *sii;
 
-       struct si_pub *si_local = NULL;
-       memcpy(&si_local, &sih, sizeof(struct si_pub **));
-
        sii = (struct si_info *)sih;
 
        if (sii == NULL)
index 4d7e334..68e9583 100644 (file)
@@ -1176,6 +1176,7 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
        struct mwifiex_adapter *adapter;
        struct net_device *dev;
        void *mdev_priv;
+       int ret;
 
        if (!priv)
                return ERR_PTR(-EFAULT);
@@ -1216,8 +1217,8 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
                              ether_setup, 1);
        if (!dev) {
                wiphy_err(wiphy, "no memory available for netdevice\n");
-               priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
-               return ERR_PTR(-ENOMEM);
+               ret = -ENOMEM;
+               goto err_alloc_netdev;
        }
 
        dev_net_set(dev, wiphy_net(wiphy));
@@ -1239,23 +1240,29 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
 
        SET_NETDEV_DEV(dev, adapter->dev);
 
+       sema_init(&priv->async_sem, 1);
+       priv->scan_pending_on_block = false;
+
        /* Register network device */
        if (register_netdevice(dev)) {
                wiphy_err(wiphy, "cannot register virtual network device\n");
-               free_netdev(dev);
-               priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
-               return ERR_PTR(-EFAULT);
+               ret = -EFAULT;
+               goto err_reg_netdev;
        }
 
-       sema_init(&priv->async_sem, 1);
-       priv->scan_pending_on_block = false;
-
        dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
 
 #ifdef CONFIG_DEBUG_FS
        mwifiex_dev_debugfs_init(priv);
 #endif
        return dev;
+
+err_reg_netdev:
+       free_netdev(dev);
+       priv->netdev = NULL;
+err_alloc_netdev:
+       priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
 
index 0021e49..04fec1f 100644 (file)
@@ -2426,7 +2426,7 @@ static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs,
                            unsigned int pkt_addr, int rx_len)
 {
        UCHAR buff[256];
-       struct rx_msg *msg = (struct rx_msg *)buff;
+       struct ray_rx_msg *msg = (struct ray_rx_msg *) buff;
 
        del_timer(&local->timer);
 
@@ -2513,7 +2513,7 @@ static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs,
                              unsigned int pkt_addr, int rx_len)
 {
 /*  UCHAR buff[256];
-    struct rx_msg *msg = (struct rx_msg *)buff;
+    struct ray_rx_msg *msg = (struct ray_rx_msg *) buff;
 */
        pr_debug("Deauthentication frame received\n");
        local->authentication_state = UNAUTHENTICATED;
index d7646f2..3c3b98b 100644 (file)
@@ -566,9 +566,9 @@ struct phy_header {
     UCHAR hdr_3;
     UCHAR hdr_4;
 };
-struct rx_msg {
+struct ray_rx_msg {
     struct mac_header mac;
-    UCHAR  var[1];
+    UCHAR  var[0];
 };
 
 struct tx_msg {
index ba28807..f62b7ec 100644 (file)
@@ -64,7 +64,7 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
                 * -ENODEV: Device has disappeared, no point continuing.
                 * All other errors: Try again.
                 */
-               else if (status == -ENODEV) {
+               else if (status == -ENODEV || status == -ENOENT) {
                        clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
                        break;
                }
@@ -311,7 +311,7 @@ static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data)
 
        status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
        if (status) {
-               if (status == -ENODEV)
+               if (status == -ENODEV || status == -ENOENT)
                        clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
                set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
                rt2x00lib_dmadone(entry);
@@ -400,7 +400,7 @@ static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void* data)
 
        status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
        if (status) {
-               if (status == -ENODEV)
+               if (status == -ENODEV || status == -ENOENT)
                        clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
                set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
                rt2x00lib_dmadone(entry);
index 3cd0736..05f2c53 100644 (file)
@@ -843,9 +843,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
        long ele_a = 0, ele_d, temp_cck, val_x, value32;
        long val_y, ele_c = 0;
        u8 ofdm_index[2];
-       u8 cck_index = 0;
-       u8 ofdm_index_old[2];
-       u8 cck_index_old = 0;
+       s8 cck_index = 0;
+       u8 ofdm_index_old[2] = {0, 0};
+       s8 cck_index_old = 0;
        u8 index;
        int i;
        bool is2t = IS_92D_SINGLEPHY(rtlhal->version);
index f10ac1a..c336026 100644 (file)
@@ -1254,6 +1254,9 @@ static void _rtl92s_phy_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
                /* Read HT 40 OFDM TX power */
                ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_2s[0][index];
                ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_2s[1][index];
+       } else {
+               ofdmpowerLevel[0] = 0;
+               ofdmpowerLevel[1] = 0;
        }
 }
 
index b012867..dd89a2b 100644 (file)
@@ -1702,6 +1702,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
 
        wl->state = WL1251_STATE_OFF;
        mutex_init(&wl->mutex);
+       spin_lock_init(&wl->wl_lock);
 
        wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE;
        wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE;
index 1ec90fc..6531622 100644 (file)
@@ -166,7 +166,7 @@ extern u32 wl12xx_debug_level;
 
 #define ACX_TX_DESCRIPTORS         16
 
-#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)
+#define WL1271_AGGR_BUFFER_SIZE (4 * 0x00001000)
 
 enum wl1271_state {
        WL1271_STATE_OFF,
index 29f121e..a84c03c 100644 (file)
@@ -389,7 +389,7 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
        mem = (unsigned long)
                dt_alloc(size + 4, __alignof__(struct device_node));
        if (!mem)
-               return NULL;
+               return;
 
        memset((void *)mem, 0, size);
 
index bcd5d54..d12d272 100644 (file)
@@ -988,7 +988,7 @@ static int __init dino_probe(struct parisc_device *dev)
 
        dino_dev->hba.dev = dev;
        dino_dev->hba.base_addr = ioremap_nocache(hpa, 4096);
-       dino_dev->hba.lmmio_space_offset = 0;   /* CPU addrs == bus addrs */
+       dino_dev->hba.lmmio_space_offset = PCI_F_EXTEND;
        spin_lock_init(&dino_dev->dinosaur_pen);
        dino_dev->hba.iommu = ccio_get_iommu(dev);
 
index 3aeb327..37d8fdc 100644 (file)
@@ -1603,3 +1603,36 @@ void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask)
        iounmap(base_addr);
 }
 
+
+/*
+ * The design of the Diva management card in rp34x0 machines (rp3410, rp3440)
+ * seems rushed, so that many built-in components simply don't work.
+ * The following quirks disable the serial AUX port and the built-in ATI RV100
+ * Radeon 7000 graphics card which both don't have any external connectors and
+ * thus are useless, and even worse, e.g. the AUX port occupies ttyS0 and as
+ * such makes those machines the only PARISC machines on which we can't use
+ * ttyS0 as boot console.
+ */
+static void quirk_diva_ati_card(struct pci_dev *dev)
+{
+       if (dev->subsystem_vendor != PCI_VENDOR_ID_HP ||
+           dev->subsystem_device != 0x1292)
+               return;
+
+       dev_info(&dev->dev, "Hiding Diva built-in ATI card");
+       dev->device = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QY,
+       quirk_diva_ati_card);
+
+static void quirk_diva_aux_disable(struct pci_dev *dev)
+{
+       if (dev->subsystem_vendor != PCI_VENDOR_ID_HP ||
+           dev->subsystem_device != 0x1291)
+               return;
+
+       dev_info(&dev->dev, "Hiding Diva built-in AUX serial device");
+       dev->device = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX,
+       quirk_diva_aux_disable);
index 75ba231..60f780e 100644 (file)
@@ -1064,6 +1064,8 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
                                  "Can't get msi for the hotplug controller\n");
                        ctrl_info(ctrl,
                                  "Use INTx for the hotplug controller\n");
+               } else {
+                       pci_set_master(pdev);
                }
 
                rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED,
index 68af94c..5dde000 100644 (file)
@@ -872,7 +872,13 @@ static int pci_pm_thaw_noirq(struct device *dev)
        if (pci_has_legacy_pm_support(pci_dev))
                return pci_legacy_resume_early(dev);
 
-       pci_update_current_state(pci_dev, PCI_D0);
+       /*
+        * pci_restore_state() requires the device to be in D0 (because of MSI
+        * restoration among other things), so force it into D0 in case the
+        * driver's "freeze" callbacks put it into a low-power state directly.
+        */
+       pci_set_power_state(pci_dev, PCI_D0);
+       pci_restore_state(pci_dev);
 
        if (drv && drv->pm && drv->pm->thaw_noirq)
                error = drv->pm->thaw_noirq(dev);
index 21addfa..8bca1d7 100644 (file)
@@ -367,7 +367,14 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
                 * If the error is reported by an end point, we think this
                 * error is related to the upstream link of the end point.
                 */
-               pci_walk_bus(dev->bus, cb, &result_data);
+               if (state == pci_channel_io_normal)
+                       /*
+                        * the error is non fatal so the bus is ok, just invoke
+                        * the callback for the function that logged the error.
+                        */
+                       cb(dev, &result_data);
+               else
+                       pci_walk_bus(dev->bus, cb, &result_data);
        }
 
        return result_data.result;
index ea6123f..9290d23 100644 (file)
@@ -358,7 +358,7 @@ static void quirk_extend_bar_to_page(struct pci_dev *dev)
 {
        int i;
 
-       for (i = 0; i < PCI_STD_RESOURCE_END; i++) {
+       for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
                struct resource *r = &dev->resource[i];
 
                if (r->flags & IORESOURCE_MEM && resource_size(r) < PAGE_SIZE) {
index 64e1f2d..7ec43a5 100644 (file)
@@ -601,7 +601,7 @@ static int __init samsung_init(void)
        struct sabi_retval sretval;
        unsigned int ifaceP;
        int i;
-       int loca;
+       int loca = 0xffff;
        int retval;
 
        if (efi_enabled(EFI_BOOT))
index 9592b93..a08e879 100644 (file)
@@ -763,9 +763,23 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
  */
 static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
 {
+       struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
+       struct rtc_time tm;
+       ktime_t now;
+
        timer->enabled = 1;
+       __rtc_read_time(rtc, &tm);
+       now = rtc_tm_to_ktime(tm);
+
+       /* Skip over expired timers */
+       while (next) {
+               if (next->expires.tv64 >= now.tv64)
+                       break;
+               next = timerqueue_iterate_next(next);
+       }
+
        timerqueue_add(&rtc->timerqueue, &timer->node);
-       if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) {
+       if (!next || timer->node.expires.tv64 < next->expires.tv64) {
                struct rtc_wkalrm alarm;
                int err;
                alarm.time = rtc_ktime_to_tm(timer->node.expires);
index 64aedd8..a3511e7 100644 (file)
@@ -213,163 +213,14 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
        return m41t80_set_datetime(to_i2c_client(dev), tm);
 }
 
-static int m41t80_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       int rc;
-
-       rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
-       if (rc < 0)
-               goto err;
-
-       if (enabled)
-               rc |= M41T80_ALMON_AFE;
-       else
-               rc &= ~M41T80_ALMON_AFE;
-
-       if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, rc) < 0)
-               goto err;
-
-       return 0;
-err:
-       return -EIO;
-}
-
-static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       u8 wbuf[1 + M41T80_ALARM_REG_SIZE];
-       u8 *buf = &wbuf[1];
-       u8 *reg = buf - M41T80_REG_ALARM_MON;
-       u8 dt_addr[1] = { M41T80_REG_ALARM_MON };
-       struct i2c_msg msgs_in[] = {
-               {
-                       .addr   = client->addr,
-                       .flags  = 0,
-                       .len    = 1,
-                       .buf    = dt_addr,
-               },
-               {
-                       .addr   = client->addr,
-                       .flags  = I2C_M_RD,
-                       .len    = M41T80_ALARM_REG_SIZE,
-                       .buf    = buf,
-               },
-       };
-       struct i2c_msg msgs[] = {
-               {
-                       .addr   = client->addr,
-                       .flags  = 0,
-                       .len    = 1 + M41T80_ALARM_REG_SIZE,
-                       .buf    = wbuf,
-                },
-       };
-
-       if (i2c_transfer(client->adapter, msgs_in, 2) < 0) {
-               dev_err(&client->dev, "read error\n");
-               return -EIO;
-       }
-       reg[M41T80_REG_ALARM_MON] &= ~(0x1f | M41T80_ALMON_AFE);
-       reg[M41T80_REG_ALARM_DAY] = 0;
-       reg[M41T80_REG_ALARM_HOUR] &= ~(0x3f | 0x80);
-       reg[M41T80_REG_ALARM_MIN] = 0;
-       reg[M41T80_REG_ALARM_SEC] = 0;
-
-       wbuf[0] = M41T80_REG_ALARM_MON; /* offset into rtc's regs */
-       reg[M41T80_REG_ALARM_SEC] |= t->time.tm_sec >= 0 ?
-               bin2bcd(t->time.tm_sec) : 0x80;
-       reg[M41T80_REG_ALARM_MIN] |= t->time.tm_min >= 0 ?
-               bin2bcd(t->time.tm_min) : 0x80;
-       reg[M41T80_REG_ALARM_HOUR] |= t->time.tm_hour >= 0 ?
-               bin2bcd(t->time.tm_hour) : 0x80;
-       reg[M41T80_REG_ALARM_DAY] |= t->time.tm_mday >= 0 ?
-               bin2bcd(t->time.tm_mday) : 0x80;
-       if (t->time.tm_mon >= 0)
-               reg[M41T80_REG_ALARM_MON] |= bin2bcd(t->time.tm_mon + 1);
-       else
-               reg[M41T80_REG_ALARM_DAY] |= 0x40;
-
-       if (i2c_transfer(client->adapter, msgs, 1) != 1) {
-               dev_err(&client->dev, "write error\n");
-               return -EIO;
-       }
-
-       if (t->enabled) {
-               reg[M41T80_REG_ALARM_MON] |= M41T80_ALMON_AFE;
-               if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
-                                             reg[M41T80_REG_ALARM_MON]) < 0) {
-                       dev_err(&client->dev, "write error\n");
-                       return -EIO;
-               }
-       }
-       return 0;
-}
-
-static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       u8 buf[M41T80_ALARM_REG_SIZE + 1]; /* all alarm regs and flags */
-       u8 dt_addr[1] = { M41T80_REG_ALARM_MON };
-       u8 *reg = buf - M41T80_REG_ALARM_MON;
-       struct i2c_msg msgs[] = {
-               {
-                       .addr   = client->addr,
-                       .flags  = 0,
-                       .len    = 1,
-                       .buf    = dt_addr,
-               },
-               {
-                       .addr   = client->addr,
-                       .flags  = I2C_M_RD,
-                       .len    = M41T80_ALARM_REG_SIZE + 1,
-                       .buf    = buf,
-               },
-       };
-
-       if (i2c_transfer(client->adapter, msgs, 2) < 0) {
-               dev_err(&client->dev, "read error\n");
-               return -EIO;
-       }
-       t->time.tm_sec = -1;
-       t->time.tm_min = -1;
-       t->time.tm_hour = -1;
-       t->time.tm_mday = -1;
-       t->time.tm_mon = -1;
-       if (!(reg[M41T80_REG_ALARM_SEC] & 0x80))
-               t->time.tm_sec = bcd2bin(reg[M41T80_REG_ALARM_SEC] & 0x7f);
-       if (!(reg[M41T80_REG_ALARM_MIN] & 0x80))
-               t->time.tm_min = bcd2bin(reg[M41T80_REG_ALARM_MIN] & 0x7f);
-       if (!(reg[M41T80_REG_ALARM_HOUR] & 0x80))
-               t->time.tm_hour = bcd2bin(reg[M41T80_REG_ALARM_HOUR] & 0x3f);
-       if (!(reg[M41T80_REG_ALARM_DAY] & 0x80))
-               t->time.tm_mday = bcd2bin(reg[M41T80_REG_ALARM_DAY] & 0x3f);
-       if (!(reg[M41T80_REG_ALARM_DAY] & 0x40))
-               t->time.tm_mon = bcd2bin(reg[M41T80_REG_ALARM_MON] & 0x1f) - 1;
-       t->time.tm_year = -1;
-       t->time.tm_wday = -1;
-       t->time.tm_yday = -1;
-       t->time.tm_isdst = -1;
-       t->enabled = !!(reg[M41T80_REG_ALARM_MON] & M41T80_ALMON_AFE);
-       t->pending = !!(reg[M41T80_REG_FLAGS] & M41T80_FLAGS_AF);
-       return 0;
-}
-
+/*
+ * XXX - m41t80 alarm functionality is reported broken.
+ * until it is fixed, don't register alarm functions.
+ */
 static struct rtc_class_ops m41t80_rtc_ops = {
        .read_time = m41t80_rtc_read_time,
        .set_time = m41t80_rtc_set_time,
-       /*
-        * XXX - m41t80 alarm functionality is reported broken.
-        * until it is fixed, don't register alarm functions.
-        *
-       .read_alarm = m41t80_rtc_read_alarm,
-       .set_alarm = m41t80_rtc_set_alarm,
-       */
        .proc = m41t80_rtc_proc,
-       /*
-        * See above comment on broken alarm
-        *
-       .alarm_irq_enable = m41t80_rtc_alarm_irq_enable,
-       */
 };
 
 #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
index 781068d..5e6c08e 100644 (file)
@@ -93,7 +93,7 @@ static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc)
        __raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER);
 
        while (!(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB)
-                                                               && timeout--)
+                                                               && --timeout)
                mdelay(1);
 
        if (!timeout)
index 4abc79d..be1d5b5 100644 (file)
@@ -578,6 +578,11 @@ struct qeth_cmd_buffer {
        void (*callback) (struct qeth_channel *, struct qeth_cmd_buffer *);
 };
 
+static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob)
+{
+       return (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE);
+}
+
 /**
  * definition of a qeth channel, used for read and write
  */
index 55f6488..0c2f7a5 100644 (file)
@@ -1932,7 +1932,7 @@ int qeth_send_control_data(struct qeth_card *card, int len,
        unsigned long flags;
        struct qeth_reply *reply = NULL;
        unsigned long timeout, event_timeout;
-       struct qeth_ipa_cmd *cmd;
+       struct qeth_ipa_cmd *cmd = NULL;
 
        QETH_CARD_TEXT(card, 2, "sendctl");
 
@@ -1959,10 +1959,13 @@ int qeth_send_control_data(struct qeth_card *card, int len,
        while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ;
        qeth_prepare_control_data(card, len, iob);
 
-       if (IS_IPA(iob->data))
+       if (IS_IPA(iob->data)) {
+               cmd = __ipa_cmd(iob);
                event_timeout = QETH_IPA_TIMEOUT;
-       else
+       } else {
                event_timeout = QETH_TIMEOUT;
+       }
+
        timeout = jiffies + event_timeout;
 
        QETH_CARD_TEXT(card, 6, "noirqpnd");
@@ -1987,9 +1990,8 @@ int qeth_send_control_data(struct qeth_card *card, int len,
 
        /* we have only one long running ipassist, since we can ensure
           process context of this command we can sleep */
-       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
-       if ((cmd->hdr.command == IPA_CMD_SETIP) &&
-           (cmd->hdr.prot_version == QETH_PROT_IPV4)) {
+       if (cmd && cmd->hdr.command == IPA_CMD_SETIP &&
+           cmd->hdr.prot_version == QETH_PROT_IPV4) {
                if (!wait_event_timeout(reply->wait_q,
                    atomic_read(&reply->received), event_timeout))
                        goto time_err;
@@ -4576,8 +4578,6 @@ static void qeth_core_free_card(struct qeth_card *card)
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
        qeth_clean_channel(&card->read);
        qeth_clean_channel(&card->write);
-       if (card->dev)
-               free_netdev(card->dev);
        kfree(card->ip_tbd_list);
        qeth_free_qdio_buffers(card);
        unregister_service_level(&card->qeth_service_level);
index fc75659..f4a6203 100644 (file)
@@ -897,8 +897,8 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
                qeth_l2_set_offline(cgdev);
 
        if (card->dev) {
-               netif_napi_del(&card->napi);
                unregister_netdev(card->dev);
+               free_netdev(card->dev);
                card->dev = NULL;
        }
        return;
index fa38a36..a557487 100644 (file)
@@ -3395,8 +3395,8 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
                qeth_l3_set_offline(cgdev);
 
        if (card->dev) {
-               netif_napi_del(&card->napi);
                unregister_netdev(card->dev);
+               free_netdev(card->dev);
                card->dev = NULL;
        }
 
index 3743ac9..7acfa95 100644 (file)
@@ -366,6 +366,8 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
        INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports);
        INIT_WORK(&adapter->ns_up_work, zfcp_fc_sym_name_update);
 
+       adapter->erp_action.adapter = adapter;
+
        if (zfcp_qdio_setup(adapter))
                goto failed;
 
@@ -535,6 +537,9 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn,
        port->dev.parent = &adapter->ccw_device->dev;
        port->dev.release = zfcp_port_release;
 
+       port->erp_action.adapter = adapter;
+       port->erp_action.port = port;
+
        if (dev_set_name(&port->dev, "0x%016llx", (unsigned long long)wwpn)) {
                kfree(port);
                goto err_out;
index bf13e73..23655e4 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Debug traces for zfcp.
  *
- * Copyright IBM Corp. 2002, 2016
+ * Copyright IBM Corp. 2002, 2017
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -440,6 +440,7 @@ static u16 zfcp_dbf_san_res_cap_len_if_gpn_ft(char *tag,
        struct fc_ct_hdr *reqh = sg_virt(ct_els->req);
        struct fc_ns_gid_ft *reqn = (struct fc_ns_gid_ft *)(reqh + 1);
        struct scatterlist *resp_entry = ct_els->resp;
+       struct fc_ct_hdr *resph;
        struct fc_gpn_ft_resp *acc;
        int max_entries, x, last = 0;
 
@@ -466,6 +467,13 @@ static u16 zfcp_dbf_san_res_cap_len_if_gpn_ft(char *tag,
                return len; /* not GPN_FT response so do not cap */
 
        acc = sg_virt(resp_entry);
+
+       /* cap all but accept CT responses to at least the CT header */
+       resph = (struct fc_ct_hdr *)acc;
+       if ((ct_els->status) ||
+           (resph->ct_cmd != cpu_to_be16(FC_FS_ACC)))
+               return max(FC_CT_HDR_LEN, ZFCP_DBF_SAN_MAX_PAYLOAD);
+
        max_entries = (reqh->ct_mr_size * 4 / sizeof(struct fc_gpn_ft_resp))
                + 1 /* zfcp_fc_scan_ports: bytes correct, entries off-by-one
                     * to account for header as 1st pseudo "entry" */;
@@ -556,19 +564,32 @@ void zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *sc,
 
        if (fsf) {
                rec->fsf_req_id = fsf->req_id;
+               rec->pl_len = FCP_RESP_WITH_EXT;
                fcp_rsp = (struct fcp_resp_with_ext *)
                                &(fsf->qtcb->bottom.io.fcp_rsp);
+               /* mandatory parts of FCP_RSP IU in this SCSI record */
                memcpy(&rec->fcp_rsp, fcp_rsp, FCP_RESP_WITH_EXT);
                if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) {
                        fcp_rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
                        rec->fcp_rsp_info = fcp_rsp_info->rsp_code;
+                       rec->pl_len += be32_to_cpu(fcp_rsp->ext.fr_rsp_len);
                }
                if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) {
-                       rec->pl_len = min((u16)SCSI_SENSE_BUFFERSIZE,
-                                         (u16)ZFCP_DBF_PAY_MAX_REC);
-                       zfcp_dbf_pl_write(dbf, sc->sense_buffer, rec->pl_len,
-                                         "fcp_sns", fsf->req_id);
+                       rec->pl_len += be32_to_cpu(fcp_rsp->ext.fr_sns_len);
                }
+               /* complete FCP_RSP IU in associated PAYload record
+                * but only if there are optional parts
+                */
+               if (fcp_rsp->resp.fr_flags != 0)
+                       zfcp_dbf_pl_write(
+                               dbf, fcp_rsp,
+                               /* at least one full PAY record
+                                * but not beyond hardware response field
+                                */
+                               min_t(u16, max_t(u16, rec->pl_len,
+                                                ZFCP_DBF_PAY_MAX_REC),
+                                     FSF_FCP_RSP_SIZE),
+                               "fcp_riu", fsf->req_id);
        }
 
        debug_event(dbf->scsi, level, rec, sizeof(*rec));
index a8165f1..4b8e952 100644 (file)
@@ -2,7 +2,7 @@
  * zfcp device driver
  * debug feature declarations
  *
- * Copyright IBM Corp. 2008, 2016
+ * Copyright IBM Corp. 2008, 2017
  */
 
 #ifndef ZFCP_DBF_H
@@ -323,7 +323,11 @@ void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req)
 {
        struct fsf_qtcb *qtcb = req->qtcb;
 
-       if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
+       if (unlikely(req->status & (ZFCP_STATUS_FSFREQ_DISMISSED |
+                                   ZFCP_STATUS_FSFREQ_ERROR))) {
+               zfcp_dbf_hba_fsf_resp("fs_rerr", 3, req);
+
+       } else if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
            (qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) {
                zfcp_dbf_hba_fsf_resp("fs_perr", 1, req);
 
@@ -401,7 +405,8 @@ void zfcp_dbf_scsi_abort(char *tag, struct scsi_cmnd *scmd,
  * @flag: indicates type of reset (Target Reset, Logical Unit Reset)
  */
 static inline
-void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag)
+void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag,
+                           struct zfcp_fsf_req *fsf_req)
 {
        char tmp_tag[ZFCP_DBF_TAG_LEN];
 
@@ -411,7 +416,7 @@ void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag)
                memcpy(tmp_tag, "lr_", 3);
 
        memcpy(&tmp_tag[3], tag, 4);
-       _zfcp_dbf_scsi(tmp_tag, 1, scmnd, NULL);
+       _zfcp_dbf_scsi(tmp_tag, 1, scmnd, fsf_req);
 }
 
 /**
index 126fa41..a0b7fc5 100644 (file)
@@ -193,9 +193,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
                atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
                                &zfcp_sdev->status);
                erp_action = &zfcp_sdev->erp_action;
-               memset(erp_action, 0, sizeof(struct zfcp_erp_action));
-               erp_action->port = port;
-               erp_action->sdev = sdev;
+               WARN_ON_ONCE(erp_action->port != port);
+               WARN_ON_ONCE(erp_action->sdev != sdev);
                if (!(atomic_read(&zfcp_sdev->status) &
                      ZFCP_STATUS_COMMON_RUNNING))
                        act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
@@ -208,8 +207,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
                zfcp_erp_action_dismiss_port(port);
                atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status);
                erp_action = &port->erp_action;
-               memset(erp_action, 0, sizeof(struct zfcp_erp_action));
-               erp_action->port = port;
+               WARN_ON_ONCE(erp_action->port != port);
+               WARN_ON_ONCE(erp_action->sdev != NULL);
                if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING))
                        act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
                break;
@@ -219,7 +218,8 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
                zfcp_erp_action_dismiss_adapter(adapter);
                atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status);
                erp_action = &adapter->erp_action;
-               memset(erp_action, 0, sizeof(struct zfcp_erp_action));
+               WARN_ON_ONCE(erp_action->port != NULL);
+               WARN_ON_ONCE(erp_action->sdev != NULL);
                if (!(atomic_read(&adapter->status) &
                      ZFCP_STATUS_COMMON_RUNNING))
                        act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY;
@@ -229,7 +229,11 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
                return NULL;
        }
 
-       erp_action->adapter = adapter;
+       WARN_ON_ONCE(erp_action->adapter != adapter);
+       memset(&erp_action->list, 0, sizeof(erp_action->list));
+       memset(&erp_action->timer, 0, sizeof(erp_action->timer));
+       erp_action->step = ZFCP_ERP_STEP_UNINITIALIZED;
+       erp_action->fsf_req_id = 0;
        erp_action->action = need;
        erp_action->status = act_status;
 
index 4561f3b..c2e40e1 100644 (file)
@@ -4,7 +4,7 @@
  * Fibre Channel related definitions and inline functions for the zfcp
  * device driver
  *
- * Copyright IBM Corporation 2009
+ * Copyright IBM Corp. 2009, 2017
  */
 
 #ifndef ZFCP_FC_H
@@ -291,6 +291,10 @@ void zfcp_fc_eval_fcp_rsp(struct fcp_resp_with_ext *fcp_rsp,
                     !(rsp_flags & FCP_SNS_LEN_VAL) &&
                     fcp_rsp->resp.fr_status == SAM_STAT_GOOD)
                        set_host_byte(scsi, DID_ERROR);
+       } else if (unlikely(rsp_flags & FCP_RESID_OVER)) {
+               /* FCP_DL was not sufficient for SCSI data length */
+               if (fcp_rsp->resp.fr_status == SAM_STAT_GOOD)
+                       set_host_byte(scsi, DID_ERROR);
        }
 }
 
index 98bb859..7799641 100644 (file)
@@ -902,8 +902,8 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
 
        switch (header->fsf_status) {
         case FSF_GOOD:
-               zfcp_dbf_san_res("fsscth2", req);
                ct->status = 0;
+               zfcp_dbf_san_res("fsscth2", req);
                break;
         case FSF_SERVICE_CLASS_NOT_SUPPORTED:
                zfcp_fsf_class_not_supp(req);
@@ -1086,8 +1086,8 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
 
        switch (header->fsf_status) {
        case FSF_GOOD:
-               zfcp_dbf_san_res("fsselh1", req);
                send_els->status = 0;
+               zfcp_dbf_san_res("fsselh1", req);
                break;
        case FSF_SERVICE_CLASS_NOT_SUPPORTED:
                zfcp_fsf_class_not_supp(req);
@@ -2256,7 +2256,8 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)
        fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
        zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd, 0);
 
-       if (scsi_prot_sg_count(scsi_cmnd)) {
+       if ((scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) &&
+           scsi_prot_sg_count(scsi_cmnd)) {
                zfcp_qdio_set_data_div(qdio, &req->qdio_req,
                                       scsi_prot_sg_count(scsi_cmnd));
                retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
index 66c37e7..0c03ae1 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Interface to Linux SCSI midlayer.
  *
- * Copyright IBM Corp. 2002, 2016
+ * Copyright IBM Corp. 2002, 2017
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -136,10 +136,15 @@ static int zfcp_scsi_slave_alloc(struct scsi_device *sdev)
        struct zfcp_unit *unit;
        int npiv = adapter->connection_features & FSF_FEATURE_NPIV_MODE;
 
+       zfcp_sdev->erp_action.adapter = adapter;
+       zfcp_sdev->erp_action.sdev = sdev;
+
        port = zfcp_get_port_by_wwpn(adapter, rport->port_name);
        if (!port)
                return -ENXIO;
 
+       zfcp_sdev->erp_action.port = port;
+
        unit = zfcp_unit_find(port, zfcp_scsi_dev_lun(sdev));
        if (unit)
                put_device(&unit->dev);
@@ -294,25 +299,29 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
 
                zfcp_erp_wait(adapter);
                ret = fc_block_scsi_eh(scpnt);
-               if (ret)
+               if (ret) {
+                       zfcp_dbf_scsi_devreset("fiof", scpnt, tm_flags, NULL);
                        return ret;
+               }
 
                if (!(atomic_read(&adapter->status) &
                      ZFCP_STATUS_COMMON_RUNNING)) {
-                       zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags);
+                       zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags, NULL);
                        return SUCCESS;
                }
        }
-       if (!fsf_req)
+       if (!fsf_req) {
+               zfcp_dbf_scsi_devreset("reqf", scpnt, tm_flags, NULL);
                return FAILED;
+       }
 
        wait_for_completion(&fsf_req->completion);
 
        if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
-               zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags);
+               zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags, fsf_req);
                retval = FAILED;
        } else {
-               zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags);
+               zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags, fsf_req);
                zfcp_scsi_forget_cmnds(zfcp_sdev, tm_flags);
        }
 
index 409f580..29ffc65 100644 (file)
@@ -468,6 +468,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
 
        aac_fib_init(cmd_fibcontext);
        dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext);
+       scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
 
        dinfo->command = cpu_to_le32(VM_ContainerConfig);
        dinfo->type = cpu_to_le32(CT_READ_NAME);
@@ -485,10 +486,8 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
        /*
         *      Check that the command queued to the controller
         */
-       if (status == -EINPROGRESS) {
-               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+       if (status == -EINPROGRESS)
                return 0;
-       }
 
        printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
        aac_fib_complete(cmd_fibcontext);
@@ -577,6 +576,7 @@ static void _aac_probe_container1(void * context, struct fib * fibptr)
        dinfo->command = cpu_to_le32(VM_NameServe64);
        dinfo->count = cpu_to_le32(scmd_id(scsicmd));
        dinfo->type = cpu_to_le32(FT_FILESYS);
+       scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
 
        status = aac_fib_send(ContainerCommand,
                          fibptr,
@@ -588,9 +588,7 @@ static void _aac_probe_container1(void * context, struct fib * fibptr)
        /*
         *      Check that the command queued to the controller
         */
-       if (status == -EINPROGRESS)
-               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
-       else if (status < 0) {
+       if (status < 0 && status != -EINPROGRESS) {
                /* Inherit results from VM_NameServe, if any */
                dresp->status = cpu_to_le32(ST_OK);
                _aac_probe_container2(context, fibptr);
@@ -613,6 +611,7 @@ static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(stru
                dinfo->count = cpu_to_le32(scmd_id(scsicmd));
                dinfo->type = cpu_to_le32(FT_FILESYS);
                scsicmd->SCp.ptr = (char *)callback;
+               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
 
                status = aac_fib_send(ContainerCommand,
                          fibptr,
@@ -624,10 +623,9 @@ static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(stru
                /*
                 *      Check that the command queued to the controller
                 */
-               if (status == -EINPROGRESS) {
-                       scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+               if (status == -EINPROGRESS)
                        return 0;
-               }
+
                if (status < 0) {
                        scsicmd->SCp.ptr = NULL;
                        aac_fib_complete(fibptr);
@@ -760,8 +758,16 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex)
        memset(str, ' ', sizeof(*str));
 
        if (dev->supplement_adapter_info.AdapterTypeText[0]) {
-               char * cp = dev->supplement_adapter_info.AdapterTypeText;
                int c;
+               char *cp;
+               char *cname = kmemdup(dev->supplement_adapter_info.AdapterTypeText,
+                               sizeof(dev->supplement_adapter_info.AdapterTypeText),
+                                                               GFP_ATOMIC);
+
+               if (!cname)
+                       return;
+
+               cp = cname;
                if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C'))
                        inqstrcpy("SMC", str->vid);
                else {
@@ -770,8 +776,7 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex)
                                ++cp;
                        c = *cp;
                        *cp = '\0';
-                       inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
-                                  str->vid);
+                       inqstrcpy(cname, str->vid);
                        *cp = c;
                        while (*cp && *cp != ' ')
                                ++cp;
@@ -779,14 +784,11 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex)
                while (*cp == ' ')
                        ++cp;
                /* last six chars reserved for vol type */
-               c = 0;
-               if (strlen(cp) > sizeof(str->pid)) {
-                       c = cp[sizeof(str->pid)];
+               if (strlen(cp) > sizeof(str->pid))
                        cp[sizeof(str->pid)] = '\0';
-               }
                inqstrcpy (cp, str->pid);
-               if (c)
-                       cp[sizeof(str->pid)] = c;
+
+               kfree(cname);
        } else {
                struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype);
 
@@ -861,6 +863,7 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
        dinfo->command = cpu_to_le32(VM_ContainerConfig);
        dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID);
        dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
+       scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
 
        status = aac_fib_send(ContainerCommand,
                  cmd_fibcontext,
@@ -873,10 +876,8 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
        /*
         *      Check that the command queued to the controller
         */
-       if (status == -EINPROGRESS) {
-               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+       if (status == -EINPROGRESS)
                return 0;
-       }
 
        printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
        aac_fib_complete(cmd_fibcontext);
@@ -1689,16 +1690,14 @@ static int aac_read(struct scsi_cmnd * scsicmd)
                printk(KERN_WARNING "aac_read: fib allocation failed\n");
                return -1;
        }
-
+       scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
        status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count);
 
        /*
         *      Check that the command queued to the controller
         */
-       if (status == -EINPROGRESS) {
-               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+       if (status == -EINPROGRESS)
                return 0;
-       }
 
        printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
        /*
@@ -1792,16 +1791,14 @@ static int aac_write(struct scsi_cmnd * scsicmd)
                printk(KERN_WARNING "aac_write: fib allocation failed\n");
                return -1;
        }
-
+       scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
        status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua);
 
        /*
         *      Check that the command queued to the controller
         */
-       if (status == -EINPROGRESS) {
-               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+       if (status == -EINPROGRESS)
                return 0;
-       }
 
        printk(KERN_WARNING "aac_write: aac_fib_send failed with status: %d\n", status);
        /*
@@ -1951,6 +1948,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
        synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd));
        synchronizecmd->count =
             cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
+       scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
 
        /*
         *      Now send the Fib to the adapter
@@ -1966,10 +1964,8 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
        /*
         *      Check that the command queued to the controller
         */
-       if (status == -EINPROGRESS) {
-               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+       if (status == -EINPROGRESS)
                return 0;
-       }
 
        printk(KERN_WARNING
                "aac_synchronize: aac_fib_send failed with status: %d.\n", status);
@@ -2031,6 +2027,7 @@ static int aac_start_stop(struct scsi_cmnd *scsicmd)
        pmcmd->cid = cpu_to_le32(sdev_id(sdev));
        pmcmd->parm = (scsicmd->cmnd[1] & 1) ?
                cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0;
+       scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
 
        /*
         *      Now send the Fib to the adapter
@@ -2046,10 +2043,8 @@ static int aac_start_stop(struct scsi_cmnd *scsicmd)
        /*
         *      Check that the command queued to the controller
         */
-       if (status == -EINPROGRESS) {
-               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+       if (status == -EINPROGRESS)
                return 0;
-       }
 
        aac_fib_complete(cmd_fibcontext);
        aac_fib_free(cmd_fibcontext);
@@ -2798,15 +2793,14 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
        if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
                return -1;
        }
+       scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
        status = aac_adapter_scsi(cmd_fibcontext, scsicmd);
 
        /*
         *      Check that the command queued to the controller
         */
-       if (status == -EINPROGRESS) {
-               scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+       if (status == -EINPROGRESS)
                return 0;
-       }
 
        printk(KERN_WARNING "aac_srb: aac_fib_send failed with status: %d\n", status);
        aac_fib_complete(cmd_fibcontext);
index bfd618a..52f7f3a 100644 (file)
@@ -50,7 +50,7 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 
-/* FIXME:
+/* Fixed in linux-4.2, not backported to 3.2:
  *
  *  1. Although all of the necessary command mapping places have the
  *     appropriate dma_map.. APIs, the driver still processes its internal
@@ -69,7 +69,6 @@
  *  7. advansys_info is not safe against multiple simultaneous callers
  *  8. Add module_param to override ISA/VLB ioport array
  */
-#warning this driver is still not properly converted to the DMA API
 
 /* Enable driver /proc statistics. */
 #define ADVANSYS_STATS
index edb43fd..c831e30 100644 (file)
@@ -983,7 +983,7 @@ static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
 {
        int err, i;
        u32 offs, size;
-       struct asd_ll_el *el;
+       struct asd_ll_el *el = NULL;
        struct asd_ctrla_phy_settings *ps;
        struct asd_ctrla_phy_settings dflt_ps;
 
@@ -1004,6 +1004,7 @@ static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
 
                size = sizeof(struct asd_ctrla_phy_settings);
                ps = &dflt_ps;
+               goto out_process;
        }
 
        if (size == 0)
@@ -1028,7 +1029,7 @@ static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
                ASD_DPRINTK("couldn't find ctrla phy settings struct\n");
                goto out2;
        }
-
+out_process:
        err = asd_process_ctrla_phy_settings(asd_ha, ps);
        if (err) {
                ASD_DPRINTK("couldn't process ctrla phy settings\n");
index e85c40b..922e30b 100644 (file)
@@ -2009,7 +2009,7 @@ static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt,
                 * have valid data in the sense buffer that could
                 * confuse the higher levels.
                 */
-               memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+               memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 //printk("scsi%d.%c: sense buffer: ", info->host->host_no, '0' + SCpnt->device->id);
 //{ int i; for (i = 0; i < 32; i++) printk("%02x ", SCpnt->sense_buffer[i]); printk("\n"); }
        /*
index caca9b7..c1f0e80 100644 (file)
@@ -276,7 +276,8 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
        struct bfad_s *bfad = port->bfad;
        struct bfa_s *bfa = &bfad->bfa;
        struct bfa_ioc_s *ioc = &bfa->ioc;
-       int addr, len, rc, i;
+       int addr, rc, i;
+       u32 len;
        u32 *regbuf;
        void __iomem *rb, *reg_addr;
        unsigned long flags;
@@ -296,7 +297,7 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
        }
 
        rc = sscanf(kern_buf, "%x:%x", &addr, &len);
-       if (rc < 2) {
+       if (rc < 2 || len > (UINT_MAX >> 2)) {
                printk(KERN_INFO
                        "bfad[%d]: %s failed to read user buf\n",
                        bfad->inst_no, __func__);
index d1e6971..d52c3c4 100644 (file)
@@ -1894,7 +1894,8 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost,
 
        bnx2i_ep_active_list_add(hba, bnx2i_ep);
 
-       if (bnx2i_map_ep_dbell_regs(bnx2i_ep))
+       rc = bnx2i_map_ep_dbell_regs(bnx2i_ep);
+       if (rc)
                goto del_active_ep;
 
        mutex_unlock(&hba->net_dev_lock);
index 834c37f..b187a6f 100644 (file)
@@ -365,7 +365,7 @@ enum ibmvfc_fcp_rsp_info_codes {
 };
 
 struct ibmvfc_fcp_rsp_info {
-       u16 reserved;
+       u8 reserved[3];
        u8 rsp_code;
        u8 reserved2[4];
 }__attribute__((packed, aligned (2)));
index 8771c03..22f9aa0 100644 (file)
@@ -1660,7 +1660,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
 
        if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
                reason = FAILURE_SESSION_IN_RECOVERY;
-               sc->result = DID_REQUEUE;
+               sc->result = DID_REQUEUE << 16;
                goto fault;
        }
 
index 33e0c18..62687fd 100644 (file)
@@ -121,10 +121,6 @@ static void sas_ata_task_done(struct sas_task *task)
                        if (unlikely(link->eh_info.err_mask))
                                qc->flags |= ATA_QCFLAG_FAILED;
                }
-
-               dev->sata_dev.sstatus = resp->sstatus;
-               dev->sata_dev.serror = resp->serror;
-               dev->sata_dev.scontrol = resp->scontrol;
        } else {
                ac = sas_to_ata_err(stat);
                if (ac) {
index dbe3568..1435695 100644 (file)
@@ -557,7 +557,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy)
        res = smp_execute_task(dev, req, RPEL_REQ_SIZE,
                                    resp, RPEL_RESP_SIZE);
 
-       if (!res)
+       if (res)
                goto out;
 
        phy->invalid_dword_count = scsi_to_u32(&resp[12]);
@@ -566,6 +566,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy)
        phy->phy_reset_problem_count = scsi_to_u32(&resp[24]);
 
  out:
+       kfree(req);
        kfree(resp);
        return res;
 
index b6e233d..e6f0a48 100644 (file)
 #include <linux/scatterlist.h>
 #include <linux/libata.h>
 
-/* ---------- SCSI Host glue ---------- */
-
-static void sas_scsi_task_done(struct sas_task *task)
+/* record final status and free the task */
+static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task)
 {
        struct task_status_struct *ts = &task->task_status;
-       struct scsi_cmnd *sc = task->uldd_task;
        int hs = 0, stat = 0;
 
-       if (unlikely(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-               /* Aborted tasks will be completed by the error handler */
-               SAS_DPRINTK("task done but aborted\n");
-               return;
-       }
-
-       if (unlikely(!sc)) {
-               SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
-               list_del_init(&task->list);
-               sas_free_task(task);
-               return;
-       }
-
        if (ts->resp == SAS_TASK_UNDELIVERED) {
                /* transport error */
                hs = DID_NO_CONNECT;
@@ -124,10 +109,32 @@ static void sas_scsi_task_done(struct sas_task *task)
                        break;
                }
        }
-       ASSIGN_SAS_TASK(sc, NULL);
+
        sc->result = (hs << 16) | stat;
+       ASSIGN_SAS_TASK(sc, NULL);
        list_del_init(&task->list);
        sas_free_task(task);
+}
+
+static void sas_scsi_task_done(struct sas_task *task)
+{
+       struct scsi_cmnd *sc = task->uldd_task;
+
+       if (unlikely(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+               /* Aborted tasks will be completed by the error handler */
+               SAS_DPRINTK("task done but aborted\n");
+               return;
+       }
+
+       if (unlikely(!sc)) {
+               SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
+               list_del_init(&task->list);
+               sas_free_task(task);
+               return;
+       }
+
+       ASSIGN_SAS_TASK(sc, NULL);
+       sas_end_task(sc, task);
        sc->scsi_done(sc);
 }
 
@@ -238,18 +245,16 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
        struct sas_task *task = TO_SAS_TASK(cmd);
        struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host);
 
-       /* remove the aborted task flag to allow the task to be
-        * completed now. At this point, we only get called following
-        * an actual abort of the task, so we should be guaranteed not
-        * to be racing with any completions from the LLD (hence we
-        * don't need the task state lock to clear the flag) */
-       task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
-       /* Now call task_done.  However, task will be free'd after
-        * this */
-       task->task_done(task);
+       /* At this point, we only get called following an actual abort
+        * of the task, so we should be guaranteed not to be racing with
+        * any completions from the LLD.  Task is freed after this.
+        */
+       sas_end_task(cmd, task);
+
        /* now finish the command and move it on to the error
         * handler done list, this also takes it off the
-        * error handler pending list */
+        * error handler pending list.
+        */
        scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q);
 }
 
index 1421ca3..0fa2c20 100644 (file)
@@ -4490,6 +4490,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "2999 Unsupported SLI4 Parameters "
                                "Extents and RPI headers enabled.\n");
+                       rc = -EIO;
                        goto out_free_bsmbx;
                }
        }
index 590ce1e..f46bc4f 100644 (file)
@@ -347,25 +347,23 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
 {
        struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp);
        u8 *fifo = esp->regs + ESP_FDATA * 16;
+       u8 phase = esp->sreg & ESP_STAT_PMASK;
 
        cmd &= ~ESP_CMD_DMA;
        mep->error = 0;
 
        if (write) {
+               u8 *dst = (u8 *)addr;
+               u8 mask = ~(phase == ESP_MIP ? ESP_INTR_FDONE : ESP_INTR_BSERV);
+
                scsi_esp_cmd(esp, cmd);
 
                while (1) {
-                       unsigned int n;
-
-                       n = mac_esp_wait_for_fifo(esp);
-                       if (!n)
+                       if (!mac_esp_wait_for_fifo(esp))
                                break;
 
-                       if (n > esp_count)
-                               n = esp_count;
-                       esp_count -= n;
-
-                       MAC_ESP_PIO_LOOP("%2@,%0@+", n);
+                       *dst++ = esp_read8(ESP_FDATA);
+                       --esp_count;
 
                        if (!esp_count)
                                break;
@@ -373,14 +371,17 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
                        if (mac_esp_wait_for_intr(esp))
                                break;
 
-                       if (((esp->sreg & ESP_STAT_PMASK) != ESP_DIP) &&
-                           ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP))
+                       if ((esp->sreg & ESP_STAT_PMASK) != phase)
                                break;
 
                        esp->ireg = esp_read8(ESP_INTRPT);
-                       if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) !=
-                           ESP_INTR_BSERV)
+                       if (esp->ireg & mask) {
+                               mep->error = 1;
                                break;
+                       }
+
+                       if (phase == ESP_MIP)
+                               scsi_esp_cmd(esp, ESP_CMD_MOK);
 
                        scsi_esp_cmd(esp, ESP_CMD_TI);
                }
@@ -400,14 +401,14 @@ static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count,
                        if (mac_esp_wait_for_intr(esp))
                                break;
 
-                       if (((esp->sreg & ESP_STAT_PMASK) != ESP_DOP) &&
-                           ((esp->sreg & ESP_STAT_PMASK) != ESP_MOP))
+                       if ((esp->sreg & ESP_STAT_PMASK) != phase)
                                break;
 
                        esp->ireg = esp_read8(ESP_INTRPT);
-                       if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) !=
-                           ESP_INTR_BSERV)
+                       if (esp->ireg & ~ESP_INTR_BSERV) {
+                               mep->error = 1;
                                break;
+                       }
 
                        n = MAC_ESP_FIFO_SIZE -
                            (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES);
index 01780a9..044c702 100644 (file)
@@ -5734,9 +5734,10 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
        u8 task_abort_retries;
 
        mutex_lock(&ioc->tm_cmds.mutex);
-       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: phy number(%d), "
-           "width(%d)\n", ioc->name, __func__, event_data->PhyNum,
-            event_data->PortWidth));
+       pr_info(MPT2SAS_FMT
+               "%s: enter: phy number(%d), width(%d)\n",
+               ioc->name, __func__, event_data->PhyNum,
+               event_data->PortWidth);
 
        _scsih_block_io_all_device(ioc);
 
index 6465dae..a735dad 100644 (file)
@@ -107,7 +107,7 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
                        set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
                break;
        }
-       return -EINVAL;
+       return count;
 }
 
 static struct bin_attribute sysfs_fw_dump_attr = {
@@ -215,12 +215,17 @@ qla2x00_sysfs_read_optrom(struct file *filp, struct kobject *kobj,
        struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
        struct qla_hw_data *ha = vha->hw;
+       ssize_t rval = 0;
 
        if (ha->optrom_state != QLA_SREADING)
                return 0;
 
-       return memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
-                                       ha->optrom_region_size);
+       mutex_lock(&ha->optrom_mutex);
+       rval = memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
+           ha->optrom_region_size);
+       mutex_unlock(&ha->optrom_mutex);
+
+       return rval;
 }
 
 static ssize_t
@@ -239,7 +244,9 @@ qla2x00_sysfs_write_optrom(struct file *filp, struct kobject *kobj,
        if (off + count > ha->optrom_region_size)
                count = ha->optrom_region_size - off;
 
+       mutex_lock(&ha->optrom_mutex);
        memcpy(&ha->optrom_buffer[off], buf, count);
+       mutex_unlock(&ha->optrom_mutex);
 
        return count;
 }
@@ -262,10 +269,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
        struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
            struct device, kobj)));
        struct qla_hw_data *ha = vha->hw;
-
        uint32_t start = 0;
        uint32_t size = ha->optrom_size;
        int val, valid;
+       ssize_t rval = count;
 
        if (off)
                return -EINVAL;
@@ -277,13 +284,17 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                return -EINVAL;
        if (start > ha->optrom_size)
                return -EINVAL;
+       if (size > ha->optrom_size - start)
+               size = ha->optrom_size - start;
 
+       mutex_lock(&ha->optrom_mutex);
        switch (val) {
        case 0:
                if (ha->optrom_state != QLA_SREADING &&
-                   ha->optrom_state != QLA_SWRITING)
-                       return -EINVAL;
-
+                   ha->optrom_state != QLA_SWRITING) {
+                       rval =  -EINVAL;
+                       goto out;
+               }
                ha->optrom_state = QLA_SWAITING;
 
                ql_dbg(ql_dbg_user, vha, 0x7061,
@@ -294,12 +305,13 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                ha->optrom_buffer = NULL;
                break;
        case 1:
-               if (ha->optrom_state != QLA_SWAITING)
-                       return -EINVAL;
+               if (ha->optrom_state != QLA_SWAITING) {
+                       rval = -EINVAL;
+                       goto out;
+               }
 
                ha->optrom_region_start = start;
-               ha->optrom_region_size = start + size > ha->optrom_size ?
-                   ha->optrom_size - start : size;
+               ha->optrom_region_size = start + size;
 
                ha->optrom_state = QLA_SREADING;
                ha->optrom_buffer = vmalloc(ha->optrom_region_size);
@@ -309,13 +321,15 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                            "(%x).\n", ha->optrom_region_size);
 
                        ha->optrom_state = QLA_SWAITING;
-                       return -ENOMEM;
+                       rval = -ENOMEM;
+                       goto out;
                }
 
                if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
                        ql_log(ql_log_warn, vha, 0x7063,
                            "HBA not online, failing NVRAM update.\n");
-                       return -EAGAIN;
+                       rval = -EAGAIN;
+                       goto out;
                }
 
                ql_dbg(ql_dbg_user, vha, 0x7064,
@@ -327,8 +341,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                    ha->optrom_region_start, ha->optrom_region_size);
                break;
        case 2:
-               if (ha->optrom_state != QLA_SWAITING)
-                       return -EINVAL;
+               if (ha->optrom_state != QLA_SWAITING) {
+                       rval = -EINVAL;
+                       goto out;
+               }
 
                /*
                 * We need to be more restrictive on which FLASH regions are
@@ -361,12 +377,12 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                if (!valid) {
                        ql_log(ql_log_warn, vha, 0x7065,
                            "Invalid start region 0x%x/0x%x.\n", start, size);
-                       return -EINVAL;
+                       rval = -EINVAL;
+                       goto out;
                }
 
                ha->optrom_region_start = start;
-               ha->optrom_region_size = start + size > ha->optrom_size ?
-                   ha->optrom_size - start : size;
+               ha->optrom_region_size = start + size;
 
                ha->optrom_state = QLA_SWRITING;
                ha->optrom_buffer = vmalloc(ha->optrom_region_size);
@@ -376,7 +392,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                            "(%x)\n", ha->optrom_region_size);
 
                        ha->optrom_state = QLA_SWAITING;
-                       return -ENOMEM;
+                       rval = -ENOMEM;
+                       goto out;
                }
 
                ql_dbg(ql_dbg_user, vha, 0x7067,
@@ -386,13 +403,16 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                memset(ha->optrom_buffer, 0, ha->optrom_region_size);
                break;
        case 3:
-               if (ha->optrom_state != QLA_SWRITING)
-                       return -ENOMEM;
+               if (ha->optrom_state != QLA_SWRITING) {
+                       rval = -EINVAL;
+                       goto out;
+               }
 
                if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
                        ql_log(ql_log_warn, vha, 0x7068,
                            "HBA not online, failing flash update.\n");
-                       return -EAGAIN;
+                       rval = -EAGAIN;
+                       goto out;
                }
 
                ql_dbg(ql_dbg_user, vha, 0x7069,
@@ -403,9 +423,12 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
                    ha->optrom_region_start, ha->optrom_region_size);
                break;
        default:
-               return -EINVAL;
+               rval = -EINVAL;
        }
-       return count;
+
+out:
+       mutex_unlock(&ha->optrom_mutex);
+       return rval;
 }
 
 static struct bin_attribute sysfs_optrom_ctl_attr = {
index 8b641a8..30edc4b 100644 (file)
@@ -1400,9 +1400,12 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
        struct qla_hw_data *ha = vha->hw;
        int rval = 0;
 
+       mutex_lock(&ha->optrom_mutex);
        rval = qla2x00_optrom_setup(bsg_job, vha, 0);
-       if (rval)
+       if (rval) {
+               mutex_unlock(&ha->optrom_mutex);
                return rval;
+       }
 
        ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
            ha->optrom_region_start, ha->optrom_region_size);
@@ -1416,6 +1419,7 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
        vfree(ha->optrom_buffer);
        ha->optrom_buffer = NULL;
        ha->optrom_state = QLA_SWAITING;
+       mutex_unlock(&ha->optrom_mutex);
        bsg_job->job_done(bsg_job);
        return rval;
 }
@@ -1428,9 +1432,12 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
        struct qla_hw_data *ha = vha->hw;
        int rval = 0;
 
+       mutex_lock(&ha->optrom_mutex);
        rval = qla2x00_optrom_setup(bsg_job, vha, 1);
-       if (rval)
+       if (rval) {
+               mutex_unlock(&ha->optrom_mutex);
                return rval;
+       }
 
        sg_copy_to_buffer(bsg_job->request_payload.sg_list,
            bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
@@ -1443,6 +1450,7 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
        vfree(ha->optrom_buffer);
        ha->optrom_buffer = NULL;
        ha->optrom_state = QLA_SWAITING;
+       mutex_unlock(&ha->optrom_mutex);
        bsg_job->job_done(bsg_job);
        return rval;
 }
index c491a94..2032c3f 100644 (file)
@@ -2723,6 +2723,7 @@ struct qla_hw_data {
 #define QLA_SWRITING   2
        uint32_t        optrom_region_start;
        uint32_t        optrom_region_size;
+       struct mutex    optrom_mutex;
 
 /* PCI expansion ROM image information. */
 #define ROM_CODE_TYPE_BIOS     0
index 6cda887..7a5217f 100644 (file)
@@ -2023,6 +2023,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        ha->mem_only = mem_only;
        spin_lock_init(&ha->hardware_lock);
        spin_lock_init(&ha->vport_slock);
+       mutex_init(&ha->optrom_mutex);
 
        /* Set ISP-type information. */
        qla2x00_set_isp_flags(ha);
index f6a464a..823f0e9 100644 (file)
@@ -1688,11 +1688,13 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
                q->limits.cluster = 0;
 
        /*
-        * set a reasonable default alignment on word boundaries: the
-        * host and device may alter it using
-        * blk_queue_update_dma_alignment() later.
+        * Set a reasonable default alignment:  The larger of 32-byte (dword),
+        * which is a common minimum for HBAs, and the minimum DMA alignment,
+        * which is set by the platform.
+        *
+        * Devices that require a bigger alignment can increase it later.
         */
-       blk_queue_dma_alignment(q, 0x03);
+       blk_queue_dma_alignment(q, max(4, dma_get_cache_alignment()) - 1);
 
        return q;
 }
index 5d207f1..8d640eb 100644 (file)
@@ -957,6 +957,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
        if (*bflags & BLIST_RETRY_HWERROR)
                sdev->retry_hwerror = 1;
 
+       if (*bflags & BLIST_UNMAP_LIMIT_WS)
+               sdev->unmap_limit_for_ws = 1;
+
        transport_configure_device(&sdev->sdev_gendev);
 
        if (sdev->host->hostt->slave_configure) {
index c874458..771b916 100644 (file)
@@ -2079,7 +2079,7 @@ iscsi_if_rx(struct sk_buff *skb)
                uint32_t group;
 
                nlh = nlmsg_hdr(skb);
-               if (nlh->nlmsg_len < sizeof(*nlh) ||
+               if (nlh->nlmsg_len < sizeof(*nlh) + sizeof(*ev) ||
                    skb->len < nlh->nlmsg_len) {
                        break;
                }
index 6cbe2eb..ff16bc3 100644 (file)
@@ -523,11 +523,21 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
                break;
 
        case SD_LBP_WS16:
-               max_blocks = min_not_zero(sdkp->max_ws_blocks, 0xffffffff);
+               if (sdkp->device->unmap_limit_for_ws)
+                       max_blocks = sdkp->max_unmap_blocks;
+               else
+                       max_blocks = sdkp->max_ws_blocks;
+
+               max_blocks = min_not_zero(max_blocks, 0xffffffff);
                break;
 
        case SD_LBP_WS10:
-               max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff);
+               if (sdkp->device->unmap_limit_for_ws)
+                       max_blocks = sdkp->max_unmap_blocks;
+               else
+                       max_blocks = sdkp->max_ws_blocks;
+
+               max_blocks = min_not_zero(max_blocks, (u32)0xffff);
                break;
 
        case SD_LBP_ZERO:
index 676fe9a..06b30f0 100644 (file)
@@ -568,6 +568,7 @@ static int __devinit esp_sbus_probe(struct platform_device *op)
        struct device_node *dp = op->dev.of_node;
        struct platform_device *dma_of = NULL;
        int hme = 0;
+       int ret;
 
        if (dp->parent &&
            (!strcmp(dp->parent->name, "espdma") ||
@@ -582,7 +583,11 @@ static int __devinit esp_sbus_probe(struct platform_device *op)
        if (!dma_of)
                return -ENODEV;
 
-       return esp_sbus_probe_one(op, dma_of, hme);
+       ret = esp_sbus_probe_one(op, dma_of, hme);
+       if (ret)
+               put_device(&dma_of->dev);
+
+       return ret;
 }
 
 static int __devexit esp_sbus_remove(struct platform_device *op)
@@ -615,6 +620,8 @@ static int __devexit esp_sbus_remove(struct platform_device *op)
 
        dev_set_drvdata(&op->dev, NULL);
 
+       put_device(&dma_of->dev);
+
        return 0;
 }
 
index 96adb10..22f5aa4 100644 (file)
@@ -1,6 +1,7 @@
 config BCM_WIMAX
        tristate "Beceem BCS200/BCS220-3 and BCSM250 wimax support"
        depends on USB && NET && EXPERIMENTAL
+       depends on !64BIT
        default N
        help
          This is an experimental driver for the Beceem WIMAX chipset used
index 3d13ca6..c7ff0cc 100644 (file)
@@ -605,6 +605,7 @@ static int vmk80xx_ai_rinsn(struct comedi_device *cdev,
                        reg[0] = VMK8055_AI2_REG;
                break;
        case VMK8061_MODEL:
+       default:
                reg[0] = VMK8061_AI_REG1;
                reg[1] = VMK8061_AI_REG2;
                dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI;
@@ -979,6 +980,7 @@ static int vmk80xx_cnt_rinsn(struct comedi_device *cdev,
                        reg[0] = VMK8055_CNT2_REG;
                break;
        case VMK8061_MODEL:
+       default:
                reg[0] = VMK8061_CNT_REG;
                reg[1] = VMK8061_CNT_REG;
                dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT;
index d9a9aa3..a98729e 100644 (file)
@@ -269,15 +269,6 @@ void sd_recv_consume(void *token, size_t len, void *user)
 #include "comet.h"
 
 extern ci_t *CI;                /* dummy pointer to board ZERO's data */
-void
-VMETRO_TRACE (void *x)
-{
-    u_int32_t   y = (u_int32_t) x;
-
-    pci_write_32 ((u_int32_t *) &CI->cpldbase->leds, y);
-}
-
-
 void
 VMETRO_TRIGGER (ci_t * ci, int x)
 {
index e046b87..d92ea7d 100644 (file)
@@ -138,7 +138,6 @@ void        sbeid_set_bdtype (ci_t * ci);
 void        sbeid_set_hdwbid (ci_t * ci);
 u_int32_t   sbeCrc (u_int8_t *, u_int32_t, u_int32_t, u_int32_t *);
 
-void        VMETRO_TRACE (void *);       /* put data into 8 LEDs */
 void        VMETRO_TRIGGER (ci_t *, int);       /* Note: int = 0(default)
                                                  * thru 15 */
 
index 559545a..84145a4 100644 (file)
@@ -534,7 +534,7 @@ static struct iio_chan_spec lis3l02dq_channels[] = {
 };
 
 
-static ssize_t lis3l02dq_read_event_config(struct iio_dev *indio_dev,
+static int lis3l02dq_read_event_config(struct iio_dev *indio_dev,
                                           u64 event_code)
 {
 
index 47630d5..76dad99 100644 (file)
@@ -120,7 +120,7 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
        struct iio_dev *indio_dev = pf->indio_dev;
        struct ad7298_state *st = iio_priv(indio_dev);
        struct iio_buffer *ring = indio_dev->buffer;
-       s64 time_ns;
+       s64 time_ns = 0;
        __u16 buf[16];
        int b_sent, i;
 
index 5d7a906..b9dc422 100644 (file)
@@ -82,7 +82,7 @@ static int adis16080_read_raw(struct iio_dev *indio_dev,
                             long mask)
 {
        int ret = -EINVAL;
-       u16 ut;
+       u16 ut = 0;
        /* Take the iio_dev status lock */
 
        mutex_lock(&indio_dev->mlock);
index 7e984bc..ee83ccb 100644 (file)
@@ -606,7 +606,7 @@ static irqreturn_t tsl2563_event_handler(int irq, void *private)
        struct tsl2563_chip *chip = iio_priv(dev_info);
 
        iio_push_event(dev_info,
-                      IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+                      IIO_UNMOD_EVENT_CODE(IIO_INTENSITY,
                                            0,
                                            IIO_EV_TYPE_THRESH,
                                            IIO_EV_DIR_EITHER),
index b691f10..60376d3 100644 (file)
@@ -128,7 +128,7 @@ static int ade7759_spi_read_reg_40(struct device *dev,
                                reg_address);
                goto error_ret;
        }
-       *val = ((u64)st->rx[1] << 32) | (st->rx[2] << 24) |
+       *val = ((u64)st->rx[1] << 32) | ((u64)st->rx[2] << 24) |
                (st->rx[3] << 16) | (st->rx[4] << 8) | st->rx[5];
 
 error_ret:
index 6401a62..0ed8c0b 100644 (file)
@@ -480,7 +480,7 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev,
                             long m)
 {
        struct ad2s1210_state *st = iio_priv(indio_dev);
-       bool negative;
+       u16 negative;
        int ret = 0;
        u16 pos;
        s16 vel;
index c019df9..9ff1595 100644 (file)
@@ -106,20 +106,25 @@ static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap,
                                 unsigned char *cmd,
                                 const struct firmware *firmware) {
 
-       struct as10x_fw_pkt_t fw_pkt;
+       struct as10x_fw_pkt_t *fw_pkt;
        int total_read_bytes = 0, errno = 0;
        unsigned char addr_has_changed = 0;
 
        ENTER();
 
+       fw_pkt = kmalloc(sizeof(*fw_pkt), GFP_KERNEL);
+       if (!fw_pkt)
+               return -ENOMEM;
+
+
        for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
                int read_bytes = 0, data_len = 0;
 
                /* parse intel hex line */
                read_bytes = parse_hex_line(
                                (u8 *) (firmware->data + total_read_bytes),
-                               fw_pkt.raw.address,
-                               fw_pkt.raw.data,
+                               fw_pkt->raw.address,
+                               fw_pkt->raw.data,
                                &data_len,
                                &addr_has_changed);
 
@@ -129,28 +134,28 @@ static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap,
                /* detect the end of file */
                total_read_bytes += read_bytes;
                if (total_read_bytes == firmware->size) {
-                       fw_pkt.u.request[0] = 0x00;
-                       fw_pkt.u.request[1] = 0x03;
+                       fw_pkt->u.request[0] = 0x00;
+                       fw_pkt->u.request[1] = 0x03;
 
                        /* send EOF command */
                        errno = bus_adap->ops->upload_fw_pkt(bus_adap,
                                                             (uint8_t *)
-                                                            &fw_pkt, 2, 0);
+                                                            fw_pkt, 2, 0);
                        if (errno < 0)
                                goto error;
                } else {
                        if (!addr_has_changed) {
                                /* prepare command to send */
-                               fw_pkt.u.request[0] = 0x00;
-                               fw_pkt.u.request[1] = 0x01;
+                               fw_pkt->u.request[0] = 0x00;
+                               fw_pkt->u.request[1] = 0x01;
 
-                               data_len += sizeof(fw_pkt.u.request);
-                               data_len += sizeof(fw_pkt.raw.address);
+                               data_len += sizeof(fw_pkt->u.request);
+                               data_len += sizeof(fw_pkt->raw.address);
 
                                /* send cmd to device */
                                errno = bus_adap->ops->upload_fw_pkt(bus_adap,
                                                                     (uint8_t *)
-                                                                    &fw_pkt,
+                                                                    fw_pkt,
                                                                     data_len,
                                                                     0);
                                if (errno < 0)
@@ -159,6 +164,7 @@ static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap,
                }
        }
 error:
+       kfree(fw_pkt);
        LEAVE();
        return (errno == 0) ? total_read_bytes : errno;
 }
index 0302d82..564a33d 100644 (file)
@@ -297,7 +297,7 @@ static void release_ir_tx(struct kref *ref)
        struct IR_tx *tx = container_of(ref, struct IR_tx, ref);
        struct IR *ir = tx->ir;
 
-       ir->l.features &= ~LIRC_CAN_SEND_PULSE;
+       ir->l.features &= ~LIRC_CAN_SEND_LIRCCODE;
        /* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */
        ir->tx = NULL;
        kfree(tx);
@@ -1261,14 +1261,14 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
                if (!(features&LIRC_CAN_SEND_MASK))
                        return -ENOSYS;
 
-               result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
+               result = put_user(LIRC_MODE_LIRCCODE, (unsigned long *) arg);
                break;
        case LIRC_SET_SEND_MODE:
                if (!(features&LIRC_CAN_SEND_MASK))
                        return -ENOSYS;
 
                result = get_user(mode, (unsigned long *) arg);
-               if (!result && mode != LIRC_MODE_PULSE)
+               if (!result && mode != LIRC_MODE_LIRCCODE)
                        return -EINVAL;
                break;
        default:
@@ -1506,7 +1506,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
                kref_init(&tx->ref);
                ir->tx = tx;
 
-               ir->l.features |= LIRC_CAN_SEND_PULSE;
+               ir->l.features |= LIRC_CAN_SEND_LIRCCODE;
                mutex_init(&tx->client_lock);
                tx->c = client;
                tx->need_boot = 1;
index 77a0751..f54057b 100644 (file)
@@ -1490,7 +1490,7 @@ static struct slic_rspbuf *slic_rspqueue_getnext(struct adapter *adapter)
                slic_reg64_write(adapter, &adapter->slic_regs->slic_rbar64,
                        (rspq->paddr[rspq->pageindex] | SLIC_RSPQ_BUFSINPAGE),
                        &adapter->slic_regs->slic_addr_upper, 0, DONT_FLUSH);
-               rspq->pageindex = (++rspq->pageindex) % rspq->num_pages;
+               rspq->pageindex = (rspq->pageindex + 1) % rspq->num_pages;
                rspq->offset = 0;
                rspq->rspbuf = (struct slic_rspbuf *)
                                                rspq->vaddr[rspq->pageindex];
index 55c0b51..d98821a 100644 (file)
@@ -186,8 +186,7 @@ static void stub_shutdown_connection(struct usbip_device *ud)
         * step 1?
         */
        if (ud->tcp_socket) {
-               dev_dbg(&sdev->udev->dev, "shutdown tcp_socket %p\n",
-                       ud->tcp_socket);
+               dev_dbg(&sdev->udev->dev, "shutdown sockfd %d\n", ud->sockfd);
                kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
        }
 
index 2d63178..4d7c8a5 100644 (file)
@@ -227,17 +227,22 @@ void stub_device_cleanup_urbs(struct stub_device *sdev)
        struct stub_priv *priv;
        struct urb *urb;
 
-       dev_dbg(&sdev->udev->dev, "free sdev %p\n", sdev);
+       dev_dbg(&sdev->udev->dev, "Stub device cleaning up urbs\n");
 
        while ((priv = stub_priv_pop(sdev))) {
                urb = priv->urb;
-               dev_dbg(&sdev->udev->dev, "free urb %p\n", urb);
+               dev_dbg(&sdev->udev->dev, "free urb seqnum %lu\n",
+                       priv->seqnum);
                usb_kill_urb(urb);
 
                kmem_cache_free(stub_priv_cache, priv);
 
                kfree(urb->transfer_buffer);
+               urb->transfer_buffer = NULL;
+
                kfree(urb->setup_packet);
+               urb->setup_packet = NULL;
+
                usb_free_urb(urb);
        }
 }
index 6b4e3e1..67757b6 100644 (file)
@@ -239,9 +239,6 @@ static int stub_recv_cmd_unlink(struct stub_device *sdev,
                if (priv->seqnum == pdu->u.cmd_unlink.seqnum) {
                        int ret;
 
-                       dev_info(&priv->urb->dev->dev, "unlink urb %p\n",
-                                priv->urb);
-
                        /*
                         * This matched urb is not completed yet (i.e., be in
                         * flight in usb hcd hardware/driver). Now we are
@@ -280,8 +277,8 @@ static int stub_recv_cmd_unlink(struct stub_device *sdev,
                        ret = usb_unlink_urb(priv->urb);
                        if (ret != -EINPROGRESS)
                                dev_err(&priv->urb->dev->dev,
-                                       "failed to unlink a urb %p, ret %d\n",
-                                       priv->urb, ret);
+                                       "failed to unlink a urb # %lu, ret %d\n",
+                                       priv->seqnum, ret);
                        return 0;
                }
        }
@@ -350,32 +347,34 @@ static struct stub_priv *stub_priv_alloc(struct stub_device *sdev,
        return priv;
 }
 
-static int get_pipe(struct stub_device *sdev, int epnum, int dir)
+static int get_pipe(struct stub_device *sdev, struct usbip_header *pdu)
 {
        struct usb_device *udev = sdev->udev;
        struct usb_host_endpoint *ep;
        struct usb_endpoint_descriptor *epd = NULL;
+       int epnum = pdu->base.ep;
+       int dir = pdu->base.direction;
+
+       if (epnum < 0 || epnum > 15)
+               goto err_ret;
 
        if (dir == USBIP_DIR_IN)
                ep = udev->ep_in[epnum & 0x7f];
        else
                ep = udev->ep_out[epnum & 0x7f];
-       if (!ep) {
-               dev_err(&sdev->interface->dev, "no such endpoint?, %d\n",
-                       epnum);
-               BUG();
-       }
+       if (!ep)
+               goto err_ret;
 
        epd = &ep->desc;
-#if 0
-       /* epnum 0 is always control */
-       if (epnum == 0) {
-               if (dir == USBIP_DIR_OUT)
-                       return usb_sndctrlpipe(udev, 0);
-               else
-                       return usb_rcvctrlpipe(udev, 0);
+
+       /* validate transfer_buffer_length */
+       if (pdu->u.cmd_submit.transfer_buffer_length > INT_MAX) {
+               dev_err(&sdev->interface->dev,
+                       "CMD_SUBMIT: -EMSGSIZE transfer_buffer_length %d\n",
+                       pdu->u.cmd_submit.transfer_buffer_length);
+               return -1;
        }
-#endif
+
        if (usb_endpoint_xfer_control(epd)) {
                if (dir == USBIP_DIR_OUT)
                        return usb_sndctrlpipe(udev, epnum);
@@ -398,15 +397,31 @@ static int get_pipe(struct stub_device *sdev, int epnum, int dir)
        }
 
        if (usb_endpoint_xfer_isoc(epd)) {
+               /* validate packet size and number of packets */
+               unsigned int maxp, packets, bytes;
+
+               maxp = usb_endpoint_maxp(epd);
+               maxp *= usb_endpoint_maxp_mult(epd);
+               bytes = pdu->u.cmd_submit.transfer_buffer_length;
+               packets = DIV_ROUND_UP(bytes, maxp);
+
+               if (pdu->u.cmd_submit.number_of_packets < 0 ||
+                   pdu->u.cmd_submit.number_of_packets > packets) {
+                       dev_err(&sdev->interface->dev,
+                               "CMD_SUBMIT: isoc invalid num packets %d\n",
+                               pdu->u.cmd_submit.number_of_packets);
+                       return -1;
+               }
                if (dir == USBIP_DIR_OUT)
                        return usb_sndisocpipe(udev, epnum);
                else
                        return usb_rcvisocpipe(udev, epnum);
        }
 
+err_ret:
        /* NOT REACHED */
-       dev_err(&sdev->interface->dev, "get pipe, epnum %d\n", epnum);
-       return 0;
+       dev_err(&sdev->interface->dev, "CMD_SUBMIT: invalid epnum %d\n", epnum);
+       return -1;
 }
 
 static void masking_bogus_flags(struct urb *urb)
@@ -470,7 +485,10 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
        struct stub_priv *priv;
        struct usbip_device *ud = &sdev->ud;
        struct usb_device *udev = sdev->udev;
-       int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction);
+       int pipe = get_pipe(sdev, pdu);
+
+       if (pipe == -1)
+               return;
 
        priv = stub_priv_alloc(sdev, pdu);
        if (!priv)
@@ -490,7 +508,8 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
        }
 
        /* set priv->urb->transfer_buffer */
-       if (pdu->u.cmd_submit.transfer_buffer_length > 0) {
+       if (pdu->u.cmd_submit.transfer_buffer_length > 0 &&
+           pdu->u.cmd_submit.transfer_buffer_length <= INT_MAX) {
                priv->urb->transfer_buffer =
                        kzalloc(pdu->u.cmd_submit.transfer_buffer_length,
                                GFP_KERNEL);
@@ -564,7 +583,7 @@ static void stub_rx_pdu(struct usbip_device *ud)
        memset(&pdu, 0, sizeof(pdu));
 
        /* 1. receive a pdu header */
-       ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0);
+       ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
        if (ret != sizeof(pdu)) {
                dev_err(dev, "recv a header, %d\n", ret);
                usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
index 023fda3..7f21170 100644 (file)
@@ -28,7 +28,11 @@ static void stub_free_priv_and_urb(struct stub_priv *priv)
        struct urb *urb = priv->urb;
 
        kfree(urb->setup_packet);
+       urb->setup_packet = NULL;
+
        kfree(urb->transfer_buffer);
+       urb->transfer_buffer = NULL;
+
        list_del(&priv->list);
        kmem_cache_free(stub_priv_cache, priv);
        usb_free_urb(urb);
@@ -174,6 +178,13 @@ static int stub_send_ret_submit(struct stub_device *sdev)
                memset(&pdu_header, 0, sizeof(pdu_header));
                memset(&msg, 0, sizeof(msg));
 
+               if (urb->actual_length > 0 && !urb->transfer_buffer) {
+                       dev_err(&sdev->interface->dev,
+                               "urb: actual_length %d transfer_buffer null\n",
+                               urb->actual_length);
+                       return -1;
+               }
+
                if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
                        iovnum = 2 + urb->number_of_packets;
                else
@@ -190,8 +201,8 @@ static int stub_send_ret_submit(struct stub_device *sdev)
 
                /* 1. setup usbip_header */
                setup_ret_submit_pdu(&pdu_header, urb);
-               usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n",
-                                 pdu_header.base.seqnum, urb);
+               usbip_dbg_stub_tx("setup txdata seqnum: %d\n",
+                                 pdu_header.base.seqnum);
                /*usbip_dump_header(pdu_header);*/
                usbip_header_correct_endian(&pdu_header, 1);
 
index 4fbef0c..499f774 100644 (file)
@@ -115,7 +115,7 @@ static void usbip_dump_usb_device(struct usb_device *udev)
                break;
        }
 
-       pr_debug("tt %p, ttport %d\n", udev->tt, udev->ttport);
+       pr_debug("tt hub ttport %d\n", udev->ttport);
 
        dev_dbg(dev, "                    ");
        for (i = 0; i < 16; i++)
@@ -148,11 +148,8 @@ static void usbip_dump_usb_device(struct usb_device *udev)
        }
        pr_debug("\n");
 
-       dev_dbg(dev, "parent %p, bus %p\n", udev->parent, udev->bus);
-
-       dev_dbg(dev, "descriptor %p, config %p, actconfig %p, "
-               "rawdescriptors %p\n", &udev->descriptor, udev->config,
-               udev->actconfig, udev->rawdescriptors);
+       dev_dbg(dev, "parent %s, bus %s\n", dev_name(&udev->parent->dev),
+               udev->bus->bus_name);
 
        dev_dbg(dev, "have_langid %d, string_langid %d\n",
                udev->have_langid, udev->string_langid);
@@ -261,9 +258,6 @@ void usbip_dump_urb(struct urb *urb)
 
        dev = &urb->dev->dev;
 
-       dev_dbg(dev, "   urb                   :%p\n", urb);
-       dev_dbg(dev, "   dev                   :%p\n", urb->dev);
-
        usbip_dump_usb_device(urb->dev);
 
        dev_dbg(dev, "   pipe                  :%08x ", urb->pipe);
@@ -272,11 +266,9 @@ void usbip_dump_urb(struct urb *urb)
 
        dev_dbg(dev, "   status                :%d\n", urb->status);
        dev_dbg(dev, "   transfer_flags        :%08X\n", urb->transfer_flags);
-       dev_dbg(dev, "   transfer_buffer       :%p\n", urb->transfer_buffer);
        dev_dbg(dev, "   transfer_buffer_length:%d\n",
                                                urb->transfer_buffer_length);
        dev_dbg(dev, "   actual_length         :%d\n", urb->actual_length);
-       dev_dbg(dev, "   setup_packet          :%p\n", urb->setup_packet);
 
        if (urb->setup_packet && usb_pipetype(urb->pipe) == PIPE_CONTROL)
                usbip_dump_usb_ctrlrequest(
@@ -286,8 +278,6 @@ void usbip_dump_urb(struct urb *urb)
        dev_dbg(dev, "   number_of_packets     :%d\n", urb->number_of_packets);
        dev_dbg(dev, "   interval              :%d\n", urb->interval);
        dev_dbg(dev, "   error_count           :%d\n", urb->error_count);
-       dev_dbg(dev, "   context               :%p\n", urb->context);
-       dev_dbg(dev, "   complete              :%p\n", urb->complete);
 }
 EXPORT_SYMBOL_GPL(usbip_dump_urb);
 
@@ -334,9 +324,8 @@ void usbip_dump_header(struct usbip_header *pdu)
 }
 EXPORT_SYMBOL_GPL(usbip_dump_header);
 
-/* Send/receive messages over TCP/IP. I refer drivers/block/nbd.c */
-int usbip_xmit(int send, struct socket *sock, char *buf, int size,
-              int msg_flags)
+/* Receive data over TCP/IP. */
+int usbip_recv(struct socket *sock, void *buf, int size)
 {
        int result;
        struct msghdr msg;
@@ -347,26 +336,10 @@ int usbip_xmit(int send, struct socket *sock, char *buf, int size,
        char *bp = buf;
        int osize = size;
 
-       usbip_dbg_xmit("enter\n");
-
-       if (!sock || !buf || !size) {
-               pr_err("invalid arg, sock %p buff %p size %d\n", sock, buf,
-                      size);
+       if (!sock || !buf || !size)
                return -EINVAL;
-       }
 
-       if (usbip_dbg_flag_xmit) {
-               if (send) {
-                       if (!in_interrupt())
-                               pr_debug("%-10s:", current->comm);
-                       else
-                               pr_debug("interrupt  :");
-
-                       pr_debug("sending... , sock %p, buf %p, size %d, "
-                                "msg_flags %d\n", sock, buf, size, msg_flags);
-                       usbip_dump_buffer(buf, size);
-               }
-       }
+       usbip_dbg_xmit("enter\n");
 
        do {
                sock->sk->sk_allocation = GFP_NOIO;
@@ -377,42 +350,27 @@ int usbip_xmit(int send, struct socket *sock, char *buf, int size,
                msg.msg_control = NULL;
                msg.msg_controllen = 0;
                msg.msg_namelen    = 0;
-               msg.msg_flags      = msg_flags | MSG_NOSIGNAL;
-
-               if (send)
-                       result = kernel_sendmsg(sock, &msg, &iov, 1, size);
-               else
-                       result = kernel_recvmsg(sock, &msg, &iov, 1, size,
-                                               MSG_WAITALL);
+               msg.msg_flags      = MSG_NOSIGNAL;
 
-               if (result <= 0) {
-                       pr_debug("%s sock %p buf %p size %u ret %d total %d\n",
-                                send ? "send" : "receive", sock, buf, size,
-                                result, total);
+               result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL);
+               if (result <= 0)
                        goto err;
-               }
 
                size -= result;
                buf += result;
                total += result;
-
        } while (size > 0);
 
        if (usbip_dbg_flag_xmit) {
-               if (!send) {
-                       if (!in_interrupt())
-                               pr_debug("%-10s:", current->comm);
-                       else
-                               pr_debug("interrupt  :");
-
-                       pr_debug("receiving....\n");
-                       usbip_dump_buffer(bp, osize);
-                       pr_debug("received, osize %d ret %d size %d total %d\n",
-                                osize, result, size, total);
-               }
+               if (!in_interrupt())
+                       pr_debug("%-10s:", current->comm);
+               else
+                       pr_debug("interrupt  :");
 
-               if (send)
-                       pr_debug("send, total %d\n", total);
+               pr_debug("receiving....\n");
+               usbip_dump_buffer(bp, osize);
+               pr_debug("received, osize %d ret %d size %d total %d\n",
+                       osize, result, size, total);
        }
 
        return total;
@@ -420,7 +378,7 @@ int usbip_xmit(int send, struct socket *sock, char *buf, int size,
 err:
        return result;
 }
-EXPORT_SYMBOL_GPL(usbip_xmit);
+EXPORT_SYMBOL_GPL(usbip_recv);
 
 struct socket *sockfd_to_socket(unsigned int sockfd)
 {
@@ -712,7 +670,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb)
        if (!buff)
                return -ENOMEM;
 
-       ret = usbip_xmit(0, ud->tcp_socket, buff, size, 0);
+       ret = usbip_recv(ud->tcp_socket, buff, size);
        if (ret != size) {
                dev_err(&urb->dev->dev, "recv iso_frame_descriptor, %d\n",
                        ret);
@@ -831,8 +789,7 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
                }
        }
 
-       ret = usbip_xmit(0, ud->tcp_socket, (char *)urb->transfer_buffer,
-                        size, 0);
+       ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size);
        if (ret != size) {
                dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
                if (ud->side == USBIP_STUB) {
index e547dba..1057c1d 100644 (file)
@@ -276,6 +276,7 @@ struct usbip_device {
        /* lock for status */
        spinlock_t lock;
 
+       int sockfd;
        struct socket *tcp_socket;
 
        struct task_struct *tcp_rx;
@@ -305,8 +306,7 @@ void setreuse(struct socket *);
 void usbip_dump_urb(struct urb *purb);
 void usbip_dump_header(struct usbip_header *pdu);
 
-int usbip_xmit(int send, struct socket *sock, char *buf, int size,
-              int msg_flags);
+int usbip_recv(struct socket *sock, void *buf, int size);
 struct socket *sockfd_to_socket(unsigned int sockfd);
 
 void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd,
index 154b4b1..8751ebd 100644 (file)
@@ -164,7 +164,7 @@ int read_attr_speed(struct sysfs_device *dev)
                goto err;
        }
 
-       ret = sscanf(attr->value, "%s\n", speed);
+       ret = sscanf(attr->value, "%99s\n", speed);
        if (ret < 1) {
                dbg("sscanf failed");
                goto err;
index 2697877..1c91bec 100644 (file)
@@ -63,12 +63,12 @@ static int parse_status(char *value)
 
        while (*c != '\0') {
                int port, status, speed, devid;
-               unsigned long socket;
+               int sockfd;
                char lbusid[SYSFS_BUS_ID_SIZE];
 
-               ret = sscanf(c, "%d %d %d %x %lx %s\n",
+               ret = sscanf(c, "%d %d %d %x %u %31s\n",
                                &port, &status, &speed,
-                               &devid, &socket, lbusid);
+                               &devid, &sockfd, lbusid);
 
                if (ret < 5) {
                        dbg("sscanf failed: %d", ret);
@@ -77,7 +77,7 @@ static int parse_status(char *value)
 
                dbg("port %d status %d speed %d devid %x",
                                port, status, speed, devid);
-               dbg("socket %lx lbusid %s", socket, lbusid);
+               dbg("sockfd %u lbusid %s", sockfd, lbusid);
 
 
                /* if a device is connected, look at it */
index 2d4966e..a52189f 100644 (file)
@@ -34,6 +34,7 @@ int modify_match_busid(char *busid, int add)
        char match_busid_attr_path[SYSFS_PATH_MAX];
        struct sysfs_attribute *match_busid_attr;
        int rc, ret = 0;
+       int cmd_size;
 
        if (strnlen(busid, SYSFS_BUS_ID_SIZE) > SYSFS_BUS_ID_SIZE - 1) {
                dbg("busid is too long");
@@ -58,13 +59,15 @@ int modify_match_busid(char *busid, int add)
        }
 
        if (add)
-               snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "add %s", busid);
+               cmd_size = snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "add %s",
+                                   busid);
        else
-               snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "del %s", busid);
+               cmd_size = snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "del %s",
+                                   busid);
 
        dbg("write \"%s\" to %s", buff, match_busid_attr->path);
 
-       rc = sysfs_write_attribute(match_busid_attr, buff, sizeof(buff));
+       rc = sysfs_write_attribute(match_busid_attr, buff, cmd_size);
        if (rc < 0) {
                dbg("failed to write match_busid: %s", strerror(errno));
                ret = -1;
index 68f9af8..40172b9 100644 (file)
@@ -391,29 +391,6 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                dum->port_status[rhport] |=
                                        USB_PORT_STAT_ENABLE;
                        }
-#if 0
-                       if (dum->driver) {
-                               dum->port_status[rhport] |=
-                                       USB_PORT_STAT_ENABLE;
-                               /* give it the best speed we agree on */
-                               dum->gadget.speed = dum->driver->speed;
-                               dum->gadget.ep0->maxpacket = 64;
-                               switch (dum->gadget.speed) {
-                               case USB_SPEED_HIGH:
-                                       dum->port_status[rhport] |=
-                                               USB_PORT_STAT_HIGH_SPEED;
-                                       break;
-                               case USB_SPEED_LOW:
-                                       dum->gadget.ep0->maxpacket = 8;
-                                       dum->port_status[rhport] |=
-                                               USB_PORT_STAT_LOW_SPEED;
-                                       break;
-                               default:
-                                       dum->gadget.speed = USB_SPEED_FULL;
-                                       break;
-                               }
-                       }
-#endif
                }
                ((u16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]);
                ((u16 *) buf)[1] = cpu_to_le16(dum->port_status[rhport] >> 16);
@@ -430,15 +407,6 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                case USB_PORT_FEAT_SUSPEND:
                        usbip_dbg_vhci_rh(" SetPortFeature: "
                                          "USB_PORT_FEAT_SUSPEND\n");
-#if 0
-                       dum->port_status[rhport] |=
-                               (1 << USB_PORT_FEAT_SUSPEND);
-                       if (dum->driver->suspend) {
-                               spin_unlock(&dum->lock);
-                               dum->driver->suspend(&dum->gadget);
-                               spin_lock(&dum->lock);
-                       }
-#endif
                        break;
                case USB_PORT_FEAT_RESET:
                        usbip_dbg_vhci_rh(" SetPortFeature: "
@@ -449,13 +417,6 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                        ~(USB_PORT_STAT_ENABLE |
                                          USB_PORT_STAT_LOW_SPEED |
                                          USB_PORT_STAT_HIGH_SPEED);
-#if 0
-                               if (dum->driver) {
-                                       dev_dbg(hardware, "disconnect\n");
-                                       stop_activity(dum, dum->driver);
-                               }
-#endif
-
                                /* FIXME test that code path! */
                        }
                        /* 50msec reset signaling */
@@ -555,9 +516,6 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
        unsigned long flags;
        struct vhci_device *vdev;
 
-       usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n",
-                         hcd, urb, mem_flags);
-
        /* patch to usb_sg_init() is in 2.5.60 */
        BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
 
@@ -716,8 +674,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
        struct vhci_priv *priv;
        struct vhci_device *vdev;
 
-       pr_info("dequeue a urb %p\n", urb);
-
        spin_lock_irqsave(&the_controller->lock, flags);
 
        priv = urb->hcpriv;
@@ -746,7 +702,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 
                spin_lock_irqsave(&vdev->priv_lock, flags2);
 
-               pr_info("device %p seems to be disconnected\n", vdev);
                list_del(&priv->list);
                kfree(priv);
                urb->hcpriv = NULL;
@@ -758,8 +713,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                 * vhci_rx will receive RET_UNLINK and give back the URB.
                 * Otherwise, we give back it here.
                 */
-               pr_info("gives back urb %p\n", urb);
-
                usb_hcd_unlink_urb_from_ep(hcd, urb);
 
                spin_unlock_irqrestore(&the_controller->lock, flags);
@@ -790,8 +743,6 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 
                unlink->unlink_seqnum = priv->seqnum;
 
-               pr_info("device %p seems to be still connected\n", vdev);
-
                /* send cmd_unlink and try to cancel the pending URB in the
                 * peer */
                list_add_tail(&unlink->list, &vdev->unlink_tx);
@@ -860,7 +811,7 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
 
        /* need this? see stub_dev.c */
        if (ud->tcp_socket) {
-               pr_debug("shutdown tcp_socket %p\n", ud->tcp_socket);
+               pr_debug("shutdown tcp_socket %d\n", ud->sockfd);
                kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
        }
 
index 1a7afaa..3b008e6 100644 (file)
@@ -35,21 +35,19 @@ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum)
                        urb = priv->urb;
                        status = urb->status;
 
-                       usbip_dbg_vhci_rx("find urb %p vurb %p seqnum %u\n",
-                                         urb, priv, seqnum);
+                       usbip_dbg_vhci_rx("find urb seqnum %u\n", seqnum);
 
                        /* TODO: fix logic here to improve indent situtation */
                        if (status != -EINPROGRESS) {
                                if (status == -ENOENT ||
                                    status == -ECONNRESET)
-                                       dev_info(&urb->dev->dev,
-                                                "urb %p was unlinked "
-                                                "%ssynchronuously.\n", urb,
-                                                status == -ENOENT ? "" : "a");
+                                       dev_dbg(&urb->dev->dev,
+                                               "urb seq# %u was unlinked %ssynchronuously\n",
+                                               seqnum, status == -ENOENT ? "" : "a");
                                else
-                                       dev_info(&urb->dev->dev,
-                                                "urb %p may be in a error, "
-                                                "status %d\n", urb, status);
+                                       dev_dbg(&urb->dev->dev,
+                                               "urb seq# %u may be in a error, status %d\n",
+                                               seqnum, status);
                        }
 
                        list_del(&priv->list);
@@ -75,8 +73,8 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
        spin_unlock(&vdev->priv_lock);
 
        if (!urb) {
-               pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
-               pr_info("max seqnum %d\n",
+               pr_err("cannot find a urb of seqnum %u max seqnum %d\n",
+                       pdu->base.seqnum,
                        atomic_read(&the_controller->seqnum));
                usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
                return;
@@ -99,7 +97,7 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
        if (usbip_dbg_flag_vhci_rx)
                usbip_dump_urb(urb);
 
-       usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
+       usbip_dbg_vhci_rx("now giveback urb %u\n", pdu->base.seqnum);
 
        spin_lock_irqsave(&the_controller->lock, flags);
        usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
@@ -165,7 +163,7 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
                pr_info("the urb (seqnum %d) was already given backed\n",
                        pdu->base.seqnum);
        } else {
-               usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
+               usbip_dbg_vhci_rx("now giveback urb %d\n", pdu->base.seqnum);
 
                /* If unlink is succeed, status is -ECONNRESET */
                urb->status = pdu->u.ret_unlink.status;
@@ -205,7 +203,7 @@ static void vhci_rx_pdu(struct usbip_device *ud)
        memset(&pdu, 0, sizeof(pdu));
 
        /* 1. receive a pdu header */
-       ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0);
+       ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
        if (ret < 0) {
                if (ret == -ECONNRESET)
                        pr_info("connection reset by peer\n");
index 0cd039b..ae305d0 100644 (file)
@@ -38,13 +38,18 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr,
 
        /*
         * output example:
-        * prt sta spd dev socket           local_busid
-        * 000 004 000 000         c5a7bb80 1-2.3
-        * 001 004 000 000         d8cee980 2-3.4
+        * prt sta spd dev sockfd    local_busid
+        * 000 004 000 000 3         1-2.3
+        * 001 004 000 000 4         2-3.4
+        *
+        * Output includes socket fd instead of socket pointer address to avoid
+        * leaking kernel memory address in:
+        *      /sys/devices/platform/vhci_hcd.0/status and in debug output.
+        * The socket pointer address is not used at the moment and it was made
+        * visible as a convenient way to find IP address from socket pointer
+        * address by looking up /proc/net/{tcp,tcp6}. As this opens a security
+        * hole, the change is made to use sockfd instead.
         *
-        * IP address can be retrieved from a socket pointer address by looking
-        * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
-        * port number and its peer IP address.
         */
        out += sprintf(out, "prt sta spd bus dev socket           "
                       "local_busid\n");
@@ -58,7 +63,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr,
                if (vdev->ud.status == VDEV_ST_USED) {
                        out += sprintf(out, "%03u %08x ",
                                       vdev->speed, vdev->devid);
-                       out += sprintf(out, "%16p ", vdev->ud.tcp_socket);
+                       out += sprintf(out, "%u", vdev->ud.sockfd);
                        out += sprintf(out, "%s", dev_name(&vdev->udev->dev));
 
                } else {
@@ -215,6 +220,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
 
        vdev->devid         = devid;
        vdev->speed         = speed;
+       vdev->ud.sockfd     = sockfd;
        vdev->ud.tcp_socket = socket;
        vdev->ud.status     = VDEV_ST_NOTASSIGNED;
 
index 9b437e7..d034261 100644 (file)
@@ -83,7 +83,8 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev)
                memset(&msg, 0, sizeof(msg));
                memset(&iov, 0, sizeof(iov));
 
-               usbip_dbg_vhci_tx("setup txdata urb %p\n", urb);
+               usbip_dbg_vhci_tx("setup txdata urb seqnum %lu\n",
+                                 priv->seqnum);
 
                /* 1. setup usbip_header */
                setup_cmd_submit_pdu(&pdu_header, urb);
index 077c506..5765bb9 100644 (file)
@@ -3387,9 +3387,12 @@ static int  device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
 
        case SIOCGIWAPLIST:
            {
-            char buffer[IW_MAX_AP * (sizeof(struct sockaddr) + sizeof(struct iw_quality))];
+               char *buffer = kzalloc(IW_MAX_AP * (sizeof(struct sockaddr) +
+                                      sizeof(struct iw_quality)), GFP_KERNEL);
 
-                   if (wrq->u.data.pointer) {
+               if (!buffer) {
+                       rc = -ENOMEM;
+               } else if (wrq->u.data.pointer) {
                        rc = iwctl_giwaplist(dev, NULL, &(wrq->u.data), buffer);
                        if (rc == 0) {
                     if (copy_to_user(wrq->u.data.pointer,
@@ -3399,6 +3402,7 @@ static int  device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
                                    rc = -EFAULT;
                        }
             }
+               kfree(buffer);
         }
                break;
 
index 14bfeb2..a8ca81e 100644 (file)
@@ -354,6 +354,8 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb,
        union p80211_hdr p80211_hdr;
        struct p80211_metawep p80211_wep;
 
+       p80211_wep.data = NULL;
+
        if (skb == NULL)
                return NETDEV_TX_OK;
 
index 3c40096..80e959d 100644 (file)
@@ -765,30 +765,35 @@ int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
 int read_cardpda(struct pda *pda, wlandevice_t *wlandev)
 {
        int result = 0;
-       struct p80211msg_p2req_readpda msg;
+       struct p80211msg_p2req_readpda *msg;
+
+       msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
 
        /* set up the msg */
-       msg.msgcode = DIDmsg_p2req_readpda;
-       msg.msglen = sizeof(msg);
-       strcpy(msg.devname, wlandev->name);
-       msg.pda.did = DIDmsg_p2req_readpda_pda;
-       msg.pda.len = HFA384x_PDA_LEN_MAX;
-       msg.pda.status = P80211ENUM_msgitem_status_no_value;
-       msg.resultcode.did = DIDmsg_p2req_readpda_resultcode;
-       msg.resultcode.len = sizeof(u32);
-       msg.resultcode.status = P80211ENUM_msgitem_status_no_value;
-
-       if (prism2mgmt_readpda(wlandev, &msg) != 0) {
+       msg->msgcode = DIDmsg_p2req_readpda;
+       msg->msglen = sizeof(msg);
+       strcpy(msg->devname, wlandev->name);
+       msg->pda.did = DIDmsg_p2req_readpda_pda;
+       msg->pda.len = HFA384x_PDA_LEN_MAX;
+       msg->pda.status = P80211ENUM_msgitem_status_no_value;
+       msg->resultcode.did = DIDmsg_p2req_readpda_resultcode;
+       msg->resultcode.len = sizeof(u32);
+       msg->resultcode.status = P80211ENUM_msgitem_status_no_value;
+
+       if (prism2mgmt_readpda(wlandev, msg) != 0) {
                /* prism2mgmt_readpda prints an errno if appropriate */
                result = -1;
-       } else if (msg.resultcode.data == P80211ENUM_resultcode_success) {
-               memcpy(pda->buf, msg.pda.data, HFA384x_PDA_LEN_MAX);
+       } else if (msg->resultcode.data == P80211ENUM_resultcode_success) {
+               memcpy(pda->buf, msg->pda.data, HFA384x_PDA_LEN_MAX);
                result = mkpdrlist(pda);
        } else {
                /* resultcode must've been something other than success */
                result = -1;
        }
 
+       kfree(msg);
        return result;
 }
 
@@ -980,9 +985,8 @@ int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
               unsigned int nfchunks)
 {
        int result = 0;
-       struct p80211msg_p2req_ramdl_state rstatemsg;
-       struct p80211msg_p2req_ramdl_write rwritemsg;
-       struct p80211msg *msgp;
+       struct p80211msg_p2req_ramdl_state *rstmsg;
+       struct p80211msg_p2req_ramdl_write *rwrmsg;
        u32 resultcode;
        int i;
        int j;
@@ -991,57 +995,68 @@ int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
        u32 currlen;
        u32 currdaddr;
 
+       rstmsg = kmalloc(sizeof(*rstmsg), GFP_KERNEL);
+       rwrmsg = kmalloc(sizeof(*rwrmsg), GFP_KERNEL);
+       if (!rstmsg || !rwrmsg) {
+               kfree(rstmsg);
+               kfree(rwrmsg);
+               printk(KERN_ERR
+                      "writeimage: no memory for firmware download, "
+                      "aborting download\n");
+               return -ENOMEM;
+       }
+
        /* Initialize the messages */
-       memset(&rstatemsg, 0, sizeof(rstatemsg));
-       strcpy(rstatemsg.devname, wlandev->name);
-       rstatemsg.msgcode = DIDmsg_p2req_ramdl_state;
-       rstatemsg.msglen = sizeof(rstatemsg);
-       rstatemsg.enable.did = DIDmsg_p2req_ramdl_state_enable;
-       rstatemsg.exeaddr.did = DIDmsg_p2req_ramdl_state_exeaddr;
-       rstatemsg.resultcode.did = DIDmsg_p2req_ramdl_state_resultcode;
-       rstatemsg.enable.status = P80211ENUM_msgitem_status_data_ok;
-       rstatemsg.exeaddr.status = P80211ENUM_msgitem_status_data_ok;
-       rstatemsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
-       rstatemsg.enable.len = sizeof(u32);
-       rstatemsg.exeaddr.len = sizeof(u32);
-       rstatemsg.resultcode.len = sizeof(u32);
-
-       memset(&rwritemsg, 0, sizeof(rwritemsg));
-       strcpy(rwritemsg.devname, wlandev->name);
-       rwritemsg.msgcode = DIDmsg_p2req_ramdl_write;
-       rwritemsg.msglen = sizeof(rwritemsg);
-       rwritemsg.addr.did = DIDmsg_p2req_ramdl_write_addr;
-       rwritemsg.len.did = DIDmsg_p2req_ramdl_write_len;
-       rwritemsg.data.did = DIDmsg_p2req_ramdl_write_data;
-       rwritemsg.resultcode.did = DIDmsg_p2req_ramdl_write_resultcode;
-       rwritemsg.addr.status = P80211ENUM_msgitem_status_data_ok;
-       rwritemsg.len.status = P80211ENUM_msgitem_status_data_ok;
-       rwritemsg.data.status = P80211ENUM_msgitem_status_data_ok;
-       rwritemsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
-       rwritemsg.addr.len = sizeof(u32);
-       rwritemsg.len.len = sizeof(u32);
-       rwritemsg.data.len = WRITESIZE_MAX;
-       rwritemsg.resultcode.len = sizeof(u32);
+       memset(rstmsg, 0, sizeof(*rstmsg));
+       strcpy(rstmsg->devname, wlandev->name);
+       rstmsg->msgcode = DIDmsg_p2req_ramdl_state;
+       rstmsg->msglen = sizeof(*rstmsg);
+       rstmsg->enable.did = DIDmsg_p2req_ramdl_state_enable;
+       rstmsg->exeaddr.did = DIDmsg_p2req_ramdl_state_exeaddr;
+       rstmsg->resultcode.did = DIDmsg_p2req_ramdl_state_resultcode;
+       rstmsg->enable.status = P80211ENUM_msgitem_status_data_ok;
+       rstmsg->exeaddr.status = P80211ENUM_msgitem_status_data_ok;
+       rstmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
+       rstmsg->enable.len = sizeof(u32);
+       rstmsg->exeaddr.len = sizeof(u32);
+       rstmsg->resultcode.len = sizeof(u32);
+
+       memset(rwrmsg, 0, sizeof(*rwrmsg));
+       strcpy(rwrmsg->devname, wlandev->name);
+       rwrmsg->msgcode = DIDmsg_p2req_ramdl_write;
+       rwrmsg->msglen = sizeof(*rwrmsg);
+       rwrmsg->addr.did = DIDmsg_p2req_ramdl_write_addr;
+       rwrmsg->len.did = DIDmsg_p2req_ramdl_write_len;
+       rwrmsg->data.did = DIDmsg_p2req_ramdl_write_data;
+       rwrmsg->resultcode.did = DIDmsg_p2req_ramdl_write_resultcode;
+       rwrmsg->addr.status = P80211ENUM_msgitem_status_data_ok;
+       rwrmsg->len.status = P80211ENUM_msgitem_status_data_ok;
+       rwrmsg->data.status = P80211ENUM_msgitem_status_data_ok;
+       rwrmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
+       rwrmsg->addr.len = sizeof(u32);
+       rwrmsg->len.len = sizeof(u32);
+       rwrmsg->data.len = WRITESIZE_MAX;
+       rwrmsg->resultcode.len = sizeof(u32);
 
        /* Send xxx_state(enable) */
        pr_debug("Sending dl_state(enable) message.\n");
-       rstatemsg.enable.data = P80211ENUM_truth_true;
-       rstatemsg.exeaddr.data = startaddr;
+       rstmsg->enable.data = P80211ENUM_truth_true;
+       rstmsg->exeaddr.data = startaddr;
 
-       msgp = (struct p80211msg *) &rstatemsg;
-       result = prism2mgmt_ramdl_state(wlandev, msgp);
+       result = prism2mgmt_ramdl_state(wlandev, rstmsg);
        if (result) {
                printk(KERN_ERR
                       "writeimage state enable failed w/ result=%d, "
                       "aborting download\n", result);
-               return result;
+               goto free_result;
        }
-       resultcode = rstatemsg.resultcode.data;
+       resultcode = rstmsg->resultcode.data;
        if (resultcode != P80211ENUM_resultcode_success) {
                printk(KERN_ERR
                       "writeimage()->xxxdl_state msg indicates failure, "
                       "w/ resultcode=%d, aborting download.\n", resultcode);
-               return 1;
+               result = 1;
+               goto free_result;
        }
 
        /* Now, loop through the data chunks and send WRITESIZE_MAX data */
@@ -1059,9 +1074,9 @@ int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
                        curroff = j * WRITESIZE_MAX;
                        currdaddr = fchunk[i].addr + curroff;
                        /* Setup the message */
-                       rwritemsg.addr.data = currdaddr;
-                       rwritemsg.len.data = currlen;
-                       memcpy(rwritemsg.data.data,
+                       rwrmsg->addr.data = currdaddr;
+                       rwrmsg->len.data = currlen;
+                       memcpy(rwrmsg->data.data,
                               fchunk[i].data + curroff, currlen);
 
                        /* Send flashdl_write(pda) */
@@ -1069,23 +1084,23 @@ int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
                            ("Sending xxxdl_write message addr=%06x len=%d.\n",
                             currdaddr, currlen);
 
-                       msgp = (struct p80211msg *) &rwritemsg;
-                       result = prism2mgmt_ramdl_write(wlandev, msgp);
+                       result = prism2mgmt_ramdl_write(wlandev, rwrmsg);
 
                        /* Check the results */
                        if (result) {
                                printk(KERN_ERR
                                       "writeimage chunk write failed w/ result=%d, "
                                       "aborting download\n", result);
-                               return result;
+                               goto free_result;
                        }
-                       resultcode = rstatemsg.resultcode.data;
+                       resultcode = rstmsg->resultcode.data;
                        if (resultcode != P80211ENUM_resultcode_success) {
                                printk(KERN_ERR
                                       "writeimage()->xxxdl_write msg indicates failure, "
                                       "w/ resultcode=%d, aborting download.\n",
                                       resultcode);
-                               return 1;
+                               result = 1;
+                               goto free_result;
                        }
 
                }
@@ -1093,24 +1108,28 @@ int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk,
 
        /* Send xxx_state(disable) */
        pr_debug("Sending dl_state(disable) message.\n");
-       rstatemsg.enable.data = P80211ENUM_truth_false;
-       rstatemsg.exeaddr.data = 0;
+       rstmsg->enable.data = P80211ENUM_truth_false;
+       rstmsg->exeaddr.data = 0;
 
-       msgp = (struct p80211msg *) &rstatemsg;
-       result = prism2mgmt_ramdl_state(wlandev, msgp);
+       result = prism2mgmt_ramdl_state(wlandev, rstmsg);
        if (result) {
                printk(KERN_ERR
                       "writeimage state disable failed w/ result=%d, "
                       "aborting download\n", result);
-               return result;
+               goto free_result;
        }
-       resultcode = rstatemsg.resultcode.data;
+       resultcode = rstmsg->resultcode.data;
        if (resultcode != P80211ENUM_resultcode_success) {
                printk(KERN_ERR
                       "writeimage()->xxxdl_state msg indicates failure, "
                       "w/ resultcode=%d, aborting download.\n", resultcode);
-               return 1;
+               result = 1;
+               goto free_result;
        }
+
+free_result:
+       kfree(rstmsg);
+       kfree(rwrmsg);
        return result;
 }
 
index 4671f8d..8e31696 100644 (file)
@@ -1459,7 +1459,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
        BUG_ON(!tty);
 
        if (old)
-               canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+               canon_change = (old->c_lflag ^ tty->termios->c_lflag) & (ICANON | EXTPROC);
        if (canon_change) {
                memset(&tty->read_flags, 0, sizeof tty->read_flags);
                tty->canon_head = tty->read_tail;
@@ -1809,6 +1809,12 @@ do_it_again:
                        }
                        if (tty_hung_up_p(file))
                                break;
+                       /*
+                        * Abort readers for ttys which never actually
+                        * get hung up.  See __tty_hangup().
+                        */
+                       if (test_bit(TTY_HUPPING, &tty->flags))
+                               break;
                        if (!timeout)
                                break;
                        if (file->f_flags & O_NONBLOCK) {
@@ -2096,7 +2102,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
        case TIOCINQ:
                /* FIXME: Locking */
                retval = tty->read_cnt;
-               if (L_ICANON(tty))
+               if (L_ICANON(tty) && !L_EXTPROC(tty))
                        retval = inq_canon(tty);
                return put_user(retval, (unsigned int __user *) arg);
        default:
index 7619e98..f613bf3 100644 (file)
@@ -4175,6 +4175,9 @@ static struct pci_device_id serial_pci_tbl[] = {
        { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 },
        { PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 },
 
+       /* Amazon PCI serial device */
+       { PCI_DEVICE(0x1d0f, 0x8250), .driver_data = pbn_b0_1_115200 },
+
        /*
         * These entries match devices with class COMMUNICATION_SERIAL,
         * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
index 60f71ec..4b73525 100644 (file)
@@ -668,6 +668,8 @@ static void sci_receive_chars(struct uart_port *port)
                /* Tell the rest of the system the news. New characters! */
                tty_flip_buffer_push(tty);
        } else {
+               /* TTY buffers full; read from RX reg to prevent lockup */
+               sci_in(port, SCxRDR);
                sci_in(port, SCxSR); /* dummy read */
                sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
        }
index 1c469ad..0dd5692 100644 (file)
@@ -1676,7 +1676,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
        default_attr(vc);
        update_attr(vc);
 
-       vc->vc_tab_stop[0]      = 0x01010100;
+       vc->vc_tab_stop[0]      =
        vc->vc_tab_stop[1]      =
        vc->vc_tab_stop[2]      =
        vc->vc_tab_stop[3]      =
@@ -1715,7 +1715,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                vc->vc_pos -= (vc->vc_x << 1);
                while (vc->vc_x < vc->vc_cols - 1) {
                        vc->vc_x++;
-                       if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
+                       if (vc->vc_tab_stop[7 & (vc->vc_x >> 5)] & (1 << (vc->vc_x & 31)))
                                break;
                }
                vc->vc_pos += (vc->vc_x << 1);
@@ -1775,7 +1775,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                        lf(vc);
                        return;
                case 'H':
-                       vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
+                       vc->vc_tab_stop[7 & (vc->vc_x >> 5)] |= (1 << (vc->vc_x & 31));
                        return;
                case 'Z':
                        respond_ID(tty);
@@ -1968,7 +1968,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                        return;
                case 'g':
                        if (!vc->vc_par[0])
-                               vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
+                               vc->vc_tab_stop[7 & (vc->vc_x >> 5)] &= ~(1 << (vc->vc_x & 31));
                        else if (vc->vc_par[0] == 3) {
                                vc->vc_tab_stop[0] =
                                        vc->vc_tab_stop[1] =
@@ -2650,18 +2650,18 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
         * related to the kernel should not use this.
         */
                        data = shift_state;
-                       ret = __put_user(data, p);
+                       ret = put_user(data, p);
                        break;
                case TIOCL_GETMOUSEREPORTING:
                        data = mouse_reporting();
-                       ret = __put_user(data, p);
+                       ret = put_user(data, p);
                        break;
                case TIOCL_SETVESABLANK:
                        ret = set_vesa_blanking(p);
                        break;
                case TIOCL_GETKMSGREDIRECT:
                        data = vt_get_kmsg_redirect();
-                       ret = __put_user(data, p);
+                       ret = put_user(data, p);
                        break;
                case TIOCL_SETKMSGREDIRECT:
                        if (!capable(CAP_SYS_ADMIN)) {
index 210b533..6322c3e 100644 (file)
@@ -353,7 +353,7 @@ static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags)
 
        res = usb_submit_urb(acm->read_urbs[index], mem_flags);
        if (res) {
-               if (res != -EPERM) {
+               if (res != -EPERM && res != -ENODEV) {
                        dev_err(&acm->data->dev,
                                        "%s - usb_submit_urb failed: %d\n",
                                        __func__, res);
@@ -1530,6 +1530,9 @@ static const struct usb_device_id acm_ids[] = {
        { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
        .driver_info = SINGLE_RX_URB, /* firmware bug */
        },
+       { USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */
+       .driver_info = SINGLE_RX_URB,
+       },
        { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
        .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
        },
@@ -1592,6 +1595,12 @@ static const struct usb_device_id acm_ids[] = {
        { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */
        .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
        },
+       { USB_DEVICE(0xfff0, 0x0100), /* DATECS FP-2000 */
+       .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
+       },
+       { USB_DEVICE(0x09d8, 0x0320), /* Elatec GmbH TWN3 */
+       .driver_info = NO_UNION_NORMAL, /* has misplaced union descriptor */
+       },
 
        { USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */
        .driver_info = CLEAR_HALT_CONDITIONS,
index 989256e..4c09812 100644 (file)
@@ -521,6 +521,9 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
        unsigned iad_num = 0;
 
        memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
+       nintf = nintf_orig = config->desc.bNumInterfaces;
+       config->desc.bNumInterfaces = 0;        // Adjusted later
+
        if (config->desc.bDescriptorType != USB_DT_CONFIG ||
            config->desc.bLength < USB_DT_CONFIG_SIZE ||
            config->desc.bLength > size) {
@@ -534,7 +537,6 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
        buffer += config->desc.bLength;
        size -= config->desc.bLength;
 
-       nintf = nintf_orig = config->desc.bNumInterfaces;
        if (nintf > USB_MAXINTERFACES) {
                dev_warn(ddev, "config %d has too many interfaces: %d, "
                    "using maximum allowed: %d\n",
@@ -609,15 +611,23 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
 
                } else if (header->bDescriptorType ==
                                USB_DT_INTERFACE_ASSOCIATION) {
+                       struct usb_interface_assoc_descriptor *d;
+
+                       d = (struct usb_interface_assoc_descriptor *)header;
+                       if (d->bLength < USB_DT_INTERFACE_ASSOCIATION_SIZE) {
+                               dev_warn(ddev,
+                                        "config %d has an invalid interface association descriptor of length %d, skipping\n",
+                                        cfgno, d->bLength);
+                               continue;
+                       }
+
                        if (iad_num == USB_MAXIADS) {
                                dev_warn(ddev, "found more Interface "
                                               "Association Descriptors "
                                               "than allocated for in "
                                               "configuration %d\n", cfgno);
                        } else {
-                               config->intf_assoc[iad_num] =
-                                       (struct usb_interface_assoc_descriptor
-                                       *)header;
+                               config->intf_assoc[iad_num] = d;
                                iad_num++;
                        }
 
@@ -822,7 +832,7 @@ int usb_get_configuration(struct usb_device *dev)
                }
 
                if (dev->quirks & USB_QUIRK_DELAY_INIT)
-                       msleep(100);
+                       msleep(200);
 
                result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
                    bigbuffer, length);
@@ -868,6 +878,13 @@ void usb_release_bos_descriptor(struct usb_device *dev)
        }
 }
 
+static const __u8 bos_desc_len[256] = {
+       [USB_CAP_TYPE_WIRELESS_USB] = USB_DT_USB_WIRELESS_CAP_SIZE,
+       [USB_CAP_TYPE_EXT]          = USB_DT_USB_EXT_CAP_SIZE,
+       [USB_SS_CAP_TYPE]           = USB_DT_USB_SS_CAP_SIZE,
+       [CONTAINER_ID_TYPE]         = USB_DT_USB_SS_CONTN_ID_SIZE,
+};
+
 /* Get BOS descriptor set */
 int usb_get_bos_descriptor(struct usb_device *dev)
 {
@@ -876,6 +893,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
        struct usb_dev_cap_header *cap;
        unsigned char *buffer;
        int length, total_len, num, i;
+       __u8 cap_type;
        int ret;
 
        bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL);
@@ -923,10 +941,18 @@ int usb_get_bos_descriptor(struct usb_device *dev)
        for (i = 0; i < num; i++) {
                buffer += length;
                cap = (struct usb_dev_cap_header *)buffer;
-               length = cap->bLength;
 
-               if (total_len < length)
+               if (total_len < sizeof(*cap) || total_len < cap->bLength) {
+                       dev->bos->desc->bNumDeviceCaps = i;
                        break;
+               }
+               cap_type = cap->bDevCapabilityType;
+               length = cap->bLength;
+               if (bos_desc_len[cap_type] && length < bos_desc_len[cap_type]) {
+                       dev->bos->desc->bNumDeviceCaps = i;
+                       break;
+               }
+
                total_len -= length;
 
                if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
@@ -934,7 +960,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)
                        continue;
                }
 
-               switch (cap->bDevCapabilityType) {
+               switch (cap_type) {
                case USB_CAP_TYPE_WIRELESS_USB:
                        /* Wireless USB cap descriptor is handled by wusb */
                        break;
index 6f34a26..a33e3cb 100644 (file)
@@ -423,6 +423,8 @@ static void async_completed(struct urb *urb)
        if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
                        as->status != -ENOENT)
                cancel_bulk_urbs(ps, as->bulk_addr);
+
+       wake_up(&ps->wait);
        spin_unlock(&ps->lock);
 
        if (signr) {
@@ -430,8 +432,6 @@ static void async_completed(struct urb *urb)
                put_pid(pid);
                put_cred(cred);
        }
-
-       wake_up(&ps->wait);
 }
 
 static void destroy_async(struct dev_state *ps, struct list_head *list)
@@ -1093,14 +1093,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        unsigned int u, totlen, isofrmlen;
        int ret, ifnum = -1;
        int is_in;
-
-       if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
-                               USBDEVFS_URB_SHORT_NOT_OK |
+       unsigned long mask =    USBDEVFS_URB_SHORT_NOT_OK |
                                USBDEVFS_URB_BULK_CONTINUATION |
                                USBDEVFS_URB_NO_FSBR |
                                USBDEVFS_URB_ZERO_PACKET |
-                               USBDEVFS_URB_NO_INTERRUPT))
-               return -EINVAL;
+                               USBDEVFS_URB_NO_INTERRUPT;
+       /* USBDEVFS_URB_ISO_ASAP is a special case */
+       if (uurb->type == USBDEVFS_URB_TYPE_ISO)
+               mask |= USBDEVFS_URB_ISO_ASAP;
+
+       if (uurb->flags & ~mask)
+                       return -EINVAL;
+
        if (uurb->buffer_length > 0 && !uurb->buffer)
                return -EINVAL;
        if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
@@ -1402,6 +1406,18 @@ static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
        return 0;
 }
 
+static void compute_isochronous_actual_length(struct urb *urb)
+{
+       unsigned int i;
+
+       if (urb->number_of_packets > 0) {
+               urb->actual_length = 0;
+               for (i = 0; i < urb->number_of_packets; i++)
+                       urb->actual_length +=
+                                       urb->iso_frame_desc[i].actual_length;
+       }
+}
+
 static int processcompl(struct async *as, void __user * __user *arg)
 {
        struct urb *urb = as->urb;
@@ -1409,6 +1425,7 @@ static int processcompl(struct async *as, void __user * __user *arg)
        void __user *addr = as->userurb;
        unsigned int i;
 
+       compute_isochronous_actual_length(urb);
        if (as->userbuffer && urb->actual_length) {
                if (urb->number_of_packets > 0)         /* Isochronous */
                        i = urb->transfer_buffer_length;
@@ -1581,6 +1598,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
        void __user *addr = as->userurb;
        unsigned int i;
 
+       compute_isochronous_actual_length(urb);
        if (as->userbuffer && urb->actual_length) {
                if (urb->number_of_packets > 0)         /* Isochronous */
                        i = urb->transfer_buffer_length;
index 3cedf91..aab9b1a 100644 (file)
@@ -2194,6 +2194,8 @@ void usb_hc_died (struct usb_hcd *hcd)
        }
        if (usb_hcd_is_primary_hcd(hcd) && hcd->shared_hcd) {
                hcd = hcd->shared_hcd;
+               clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);
+               set_bit(HCD_FLAG_DEAD, &hcd->flags);
                if (hcd->rh_registered) {
                        clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
 
index 7c59466..18dcd1c 100644 (file)
@@ -3552,7 +3552,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 
                usb_detect_quirks(udev);
                if (udev->quirks & USB_QUIRK_DELAY_INIT)
-                       msleep(1000);
+                       msleep(2000);
 
                /* consecutive bus-powered hubs aren't reliable; they can
                 * violate the voltage drop budget.  if the new child has
index ab11ca3..16fca16 100644 (file)
@@ -150,6 +150,10 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
 
        ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
 
+       /* Linger a bit, prior to the next control message. */
+       if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
+               msleep(200);
+
        kfree(dr);
 
        return ret;
index 2177ed4..215fdef 100644 (file)
@@ -53,9 +53,11 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Microsoft LifeCam-VX700 v2.0 */
        { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
 
-       /* Logitech HD Pro Webcams C920 and C930e */
+       /* Logitech HD Pro Webcams C920, C920-C, C925e and C930e */
        { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT },
+       { USB_DEVICE(0x046d, 0x0841), .driver_info = USB_QUIRK_DELAY_INIT },
        { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT },
+       { USB_DEVICE(0x046d, 0x085b), .driver_info = USB_QUIRK_DELAY_INIT },
 
        /* Logitech ConferenceCam CC3000e */
        { USB_DEVICE(0x046d, 0x0847), .driver_info = USB_QUIRK_DELAY_INIT },
@@ -127,6 +129,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* appletouch */
        { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* ELSA MicroLink 56K */
+       { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_RESET_RESUME },
+
        /* Avision AV600U */
        { USB_DEVICE(0x0638, 0x0a13), .driver_info =
          USB_QUIRK_STRING_FETCH_255 },
@@ -183,6 +188,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x1908, 0x1315), .driver_info =
                        USB_QUIRK_HONOR_BNUMINTERFACES },
 
+       /* Hauppauge HVR-950q */
+       { USB_DEVICE(0x2040, 0x7200), .driver_info =
+                       USB_QUIRK_CONFIG_INTF_STRINGS },
+
        /* INTEL VALUE SSD */
        { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
 
@@ -197,6 +206,20 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x1a0a, 0x0200), .driver_info =
                        USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
 
+       /* Corsair K70 RGB */
+       { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT },
+
+       /* Corsair Strafe RGB */
+       { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT |
+         USB_QUIRK_DELAY_CTRL_MSG },
+
+       /* Corsair K70 LUX */
+       { USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT },
+
+       /* MIDI keyboard WORLDE MINI */
+       { USB_DEVICE(0x1c75, 0x0204), .driver_info =
+                       USB_QUIRK_CONFIG_INTF_STRINGS },
+
        { }  /* terminating entry must be last */
 };
 
index 33fe3d3..47b8358 100644 (file)
@@ -1821,6 +1821,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
                break;
        }
 
+       dwc->eps[1]->endpoint.maxpacket = dwc->gadget.ep0->maxpacket;
+
        /* Disable unneded PHY */
        dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
 
index 03a9222..2506e3a 100644 (file)
@@ -167,6 +167,7 @@ struct dummy_hcd {
 
        struct usb_device               *udev;
        struct list_head                urbp_list;
+       struct urbp                     *next_frame_urbp;
 
        unsigned                        active:1;
        unsigned                        old_active:1;
@@ -181,11 +182,13 @@ struct dummy {
         */
        struct dummy_ep                 ep [DUMMY_ENDPOINTS];
        int                             address;
+       int                             callback_usage;
        struct usb_gadget               gadget;
        struct usb_gadget_driver        *driver;
        struct dummy_request            fifo_req;
        u8                              fifo_buf [FIFO_SIZE];
        u16                             devstatus;
+       unsigned                        ints_enabled:1;
        unsigned                        udc_suspended:1;
        unsigned                        pullup:1;
 
@@ -347,6 +350,7 @@ static void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
 static void set_link_state(struct dummy_hcd *dum_hcd)
 {
        struct dummy *dum = dum_hcd->dum;
+       unsigned int power_bit;
 
        dum_hcd->active = 0;
        if (dum->pullup)
@@ -357,36 +361,40 @@ static void set_link_state(struct dummy_hcd *dum_hcd)
                        return;
 
        set_link_state_by_speed(dum_hcd);
+       power_bit = (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 ?
+                       USB_SS_PORT_STAT_POWER : USB_PORT_STAT_POWER);
 
        if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
             dum_hcd->active)
                dum_hcd->resuming = 0;
 
        /* if !connected or reset */
-       if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+       if ((dum_hcd->port_status & power_bit) == 0 ||
                        (dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
                /*
                 * We're connected and not reset (reset occurred now),
                 * and driver attached - disconnect!
                 */
-               if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+               if ((dum_hcd->old_status & power_bit) != 0 &&
                    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
-                   dum->driver) {
+                   dum->ints_enabled) {
                        stop_activity(dum);
+                       ++dum->callback_usage;
                        spin_unlock(&dum->lock);
                        dum->driver->disconnect(&dum->gadget);
                        spin_lock(&dum->lock);
+                       --dum->callback_usage;
                }
-       } else if (dum_hcd->active != dum_hcd->old_active) {
-               if (dum_hcd->old_active && dum->driver->suspend) {
-                       spin_unlock(&dum->lock);
+       } else if (dum_hcd->active != dum_hcd->old_active &&
+                       dum->ints_enabled) {
+               ++dum->callback_usage;
+               spin_unlock(&dum->lock);
+               if (dum_hcd->old_active && dum->driver->suspend)
                        dum->driver->suspend(&dum->gadget);
-                       spin_lock(&dum->lock);
-               } else if (!dum_hcd->old_active &&  dum->driver->resume) {
-                       spin_unlock(&dum->lock);
+               else if (!dum_hcd->old_active &&  dum->driver->resume)
                        dum->driver->resume(&dum->gadget);
-                       spin_lock(&dum->lock);
-               }
+               spin_lock(&dum->lock);
+               --dum->callback_usage;
        }
 
        dum_hcd->old_status = dum_hcd->port_status;
@@ -907,9 +915,12 @@ static int dummy_udc_start(struct usb_gadget *g,
         * can't enumerate without help from the driver we're binding.
         */
 
+       spin_lock_irq(&dum->lock);
        dum->devstatus = 0;
 
        dum->driver = driver;
+       dum->ints_enabled = 1;
+       spin_unlock_irq(&dum->lock);
        dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
                        driver->driver.name);
        return 0;
@@ -924,7 +935,19 @@ static int dummy_udc_stop(struct usb_gadget *g,
        dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
                        driver->driver.name);
 
+       spin_lock_irq(&dum->lock);
+       dum->ints_enabled = 0;
+       stop_activity(dum);
+
+       /* emulate synchronize_irq(): wait for callbacks to finish */
+       while (dum->callback_usage > 0) {
+               spin_unlock_irq(&dum->lock);
+               usleep_range(1000, 2000);
+               spin_lock_irq(&dum->lock);
+       }
+
        dum->driver = NULL;
+       spin_unlock_irq(&dum->lock);
 
        return 0;
 }
@@ -1108,6 +1131,8 @@ static int dummy_urb_enqueue (
 
        list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
        urb->hcpriv = urbp;
+       if (!dum_hcd->next_frame_urbp)
+               dum_hcd->next_frame_urbp = urbp;
        if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
                urb->error_count = 1;           /* mark as a new urb */
 
@@ -1303,6 +1328,8 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
        if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
                        dum->ss_hcd : dum->hs_hcd)))
                return NULL;
+       if (!dum->ints_enabled)
+               return NULL;
        if ((address & ~USB_DIR_IN) == 0)
                return &dum->ep [0];
        for (i = 1; i < DUMMY_ENDPOINTS; i++) {
@@ -1544,6 +1571,7 @@ static void dummy_timer(unsigned long _dum_hcd)
                spin_unlock_irqrestore (&dum->lock, flags);
                return;
        }
+       dum_hcd->next_frame_urbp = NULL;
 
        for (i = 0; i < DUMMY_ENDPOINTS; i++) {
                if (!ep_name [i])
@@ -1560,6 +1588,10 @@ restart:
                int                     type;
                int                     status = -EINPROGRESS;
 
+               /* stop when we reach URBs queued after the timer interrupt */
+               if (urbp == dum_hcd->next_frame_urbp)
+                       break;
+
                urb = urbp->urb;
                if (urb->unlinked)
                        goto return_urb;
@@ -1639,10 +1671,12 @@ restart:
                         * until setup() returns; no reentrancy issues etc.
                         */
                        if (value > 0) {
+                               ++dum->callback_usage;
                                spin_unlock (&dum->lock);
                                value = dum->driver->setup (&dum->gadget,
                                                &setup);
                                spin_lock (&dum->lock);
+                               --dum->callback_usage;
 
                                if (value >= 0) {
                                        /* no delays (max 64KB data stage) */
index 0ed297b..f1991d1 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
-
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/moduleparam.h>
 
@@ -112,6 +112,7 @@ enum ep0_state {
 struct dev_data {
        spinlock_t                      lock;
        atomic_t                        count;
+       int                             udc_usage;
        enum ep0_state                  state;          /* P: lock */
        struct usb_gadgetfs_event       event [N_EVENT];
        unsigned                        ev_next;
@@ -608,9 +609,9 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
                priv->actual = req->actual;
                kick_iocb(iocb);
        }
-       spin_unlock(&epdata->dev->lock);
 
        usb_ep_free_request(ep, req);
+       spin_unlock(&epdata->dev->lock);
        put_ep(epdata);
 }
 
@@ -1010,8 +1011,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
                        struct usb_ep           *ep = dev->gadget->ep0;
                        struct usb_request      *req = dev->req;
 
-                       if ((retval = setup_req (ep, req, 0)) == 0)
-                               retval = usb_ep_queue (ep, req, GFP_ATOMIC);
+                       if ((retval = setup_req (ep, req, 0)) == 0) {
+                               ++dev->udc_usage;
+                               spin_unlock_irq (&dev->lock);
+                               retval = usb_ep_queue (ep, req, GFP_KERNEL);
+                               spin_lock_irq (&dev->lock);
+                               --dev->udc_usage;
+                       }
                        dev->state = STATE_DEV_CONNECTED;
 
                        /* assume that was SET_CONFIGURATION */
@@ -1052,11 +1058,14 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
                                retval = -EIO;
                        else {
                                len = min (len, (size_t)dev->req->actual);
-// FIXME don't call this with the spinlock held ...
+                               ++dev->udc_usage;
+                               spin_unlock_irq(&dev->lock);
                                if (copy_to_user (buf, dev->req->buf, len))
                                        retval = -EFAULT;
                                else
                                        retval = len;
+                               spin_lock_irq(&dev->lock);
+                               --dev->udc_usage;
                                clean_req (dev->gadget->ep0, dev->req);
                                /* NOTE userspace can't yet choose to stall */
                        }
@@ -1202,6 +1211,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                        retval = setup_req (dev->gadget->ep0, dev->req, len);
                        if (retval == 0) {
                                dev->state = STATE_DEV_CONNECTED;
+                               ++dev->udc_usage;
                                spin_unlock_irq (&dev->lock);
                                if (copy_from_user (dev->req->buf, buf, len))
                                        retval = -EFAULT;
@@ -1212,12 +1222,13 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                                                dev->gadget->ep0, dev->req,
                                                GFP_KERNEL);
                                }
+                               spin_lock_irq(&dev->lock);
+                               --dev->udc_usage;
                                if (retval < 0) {
-                                       spin_lock_irq (&dev->lock);
                                        clean_req (dev->gadget->ep0, dev->req);
-                                       spin_unlock_irq (&dev->lock);
                                } else
                                        retval = len;
+                               spin_unlock_irq(&dev->lock);
 
                                return retval;
                        }
@@ -1309,9 +1320,21 @@ static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
        struct usb_gadget       *gadget = dev->gadget;
        long ret = -ENOTTY;
 
-       if (gadget->ops->ioctl)
+       spin_lock_irq(&dev->lock);
+       if (dev->state == STATE_DEV_OPENED ||
+                       dev->state == STATE_DEV_UNBOUND) {
+               /* Not bound to a UDC */
+       } else if (gadget->ops->ioctl) {
+               ++dev->udc_usage;
+               spin_unlock_irq(&dev->lock);
+
                ret = gadget->ops->ioctl (gadget, code, value);
 
+               spin_lock_irq(&dev->lock);
+               --dev->udc_usage;
+       }
+       spin_unlock_irq(&dev->lock);
+
        return ret;
 }
 
@@ -1545,8 +1568,13 @@ delegate:
                                                        w_length);
                                if (value < 0)
                                        break;
+
+                               ++dev->udc_usage;
+                               spin_unlock (&dev->lock);
                                value = usb_ep_queue (gadget->ep0, dev->req,
-                                                       GFP_ATOMIC);
+                                                       GFP_KERNEL);
+                               spin_lock (&dev->lock);
+                               --dev->udc_usage;
                                if (value < 0) {
                                        clean_req (gadget->ep0, dev->req);
                                        break;
@@ -1569,11 +1597,18 @@ delegate:
        if (value >= 0 && dev->state != STATE_DEV_SETUP) {
                req->length = value;
                req->zero = value < w_length;
-               value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+
+               ++dev->udc_usage;
+               spin_unlock (&dev->lock);
+               value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL);
+               spin_lock(&dev->lock);
+               --dev->udc_usage;
+               spin_unlock(&dev->lock);
                if (value < 0) {
                        DBG (dev, "ep_queue --> %d\n", value);
                        req->status = 0;
                }
+               return value;
        }
 
        /* device stalls when value < 0 */
@@ -1598,21 +1633,24 @@ restart:
                /* break link to FS */
                ep = list_entry (entry, struct ep_data, epfiles);
                list_del_init (&ep->epfiles);
+               spin_unlock_irq (&dev->lock);
+
                dentry = ep->dentry;
                ep->dentry = NULL;
                parent = dentry->d_parent->d_inode;
 
                /* break link to controller */
+               mutex_lock(&ep->lock);
                if (ep->state == STATE_EP_ENABLED)
                        (void) usb_ep_disable (ep->ep);
                ep->state = STATE_EP_UNBOUND;
                usb_ep_free_request (ep->ep, ep->req);
                ep->ep = NULL;
+               mutex_unlock(&ep->lock);
+
                wake_up (&ep->wait);
                put_ep (ep);
 
-               spin_unlock_irq (&dev->lock);
-
                /* break link to dcache */
                mutex_lock (&parent->i_mutex);
                d_delete (dentry);
@@ -1686,6 +1724,11 @@ gadgetfs_unbind (struct usb_gadget *gadget)
 
        spin_lock_irq (&dev->lock);
        dev->state = STATE_DEV_UNBOUND;
+       while (dev->udc_usage > 0) {
+               spin_unlock_irq(&dev->lock);
+               usleep_range(1000, 2000);
+               spin_lock_irq(&dev->lock);
+       }
        spin_unlock_irq (&dev->lock);
 
        destroy_ep_files (dev);
@@ -1762,9 +1805,10 @@ static void
 gadgetfs_suspend (struct usb_gadget *gadget)
 {
        struct dev_data         *dev = get_gadget_data (gadget);
+       unsigned long           flags;
 
        INFO (dev, "suspended from state %d\n", dev->state);
-       spin_lock (&dev->lock);
+       spin_lock_irqsave(&dev->lock, flags);
        switch (dev->state) {
        case STATE_DEV_SETUP:           // VERY odd... host died??
        case STATE_DEV_CONNECTED:
@@ -1775,7 +1819,7 @@ gadgetfs_suspend (struct usb_gadget *gadget)
        default:
                break;
        }
-       spin_unlock (&dev->lock);
+       spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 static struct usb_gadget_driver gadgetfs_driver = {
index d6d74d2..f0a54c5 100644 (file)
@@ -785,7 +785,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
                        default:                /* unknown */
                                break;
                        }
-                       temp = (cap >> 8) & 0xff;
+                       offset = (cap >> 8) & 0xff;
                }
        }
 #endif
index 6c43152..e81e0de 100644 (file)
@@ -908,10 +908,6 @@ rescan_all:
                int                     completed, modified;
                __hc32                  *prev;
 
-               /* Is this ED already invisible to the hardware? */
-               if (ed->state == ED_IDLE)
-                       goto ed_idle;
-
                /* only take off EDs that the HC isn't using, accounting for
                 * frame counter wraps and EDs with partially retired TDs
                 */
@@ -942,19 +938,19 @@ skip_ed:
                }
 
                /* ED's now officially unlinked, hc doesn't see */
-               ed->state = ED_IDLE;
                if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
                        ohci->eds_scheduled--;
                ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
                ed->hwNextED = 0;
                wmb();
                ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE);
-ed_idle:
 
                /* reentrancy:  if we drop the schedule lock, someone might
                 * have modified this list.  normally it's just prepending
                 * entries (which we'd ignore), but paranoia won't hurt.
                 */
+               *last = ed->ed_next;
+               ed->ed_next = NULL;
                modified = 0;
 
                /* unlink urbs as requested, but rescan the list after
@@ -1013,19 +1009,21 @@ rescan_this:
                        goto rescan_this;
 
                /*
-                * If no TDs are queued, take ED off the ed_rm_list.
+                * If no TDs are queued, ED is now idle.
                 * Otherwise, if the HC is running, reschedule.
-                * If not, leave it on the list for further dequeues.
+                * If the HC isn't running, add ED back to the
+                * start of the list for later processing.
                 */
                if (list_empty(&ed->td_list)) {
-                       *last = ed->ed_next;
-                       ed->ed_next = NULL;
+                       ed->state = ED_IDLE;
                } else if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state)) {
-                       *last = ed->ed_next;
-                       ed->ed_next = NULL;
                        ed_schedule(ohci, ed);
                } else {
-                       last = &ed->ed_next;
+                       ed->ed_next = ohci->ed_rm_list;
+                       ohci->ed_rm_list = ed;
+                       /* Don't loop on the same ED */
+                       if (last == &ohci->ed_rm_list)
+                               last = &ed->ed_next;
                }
 
                if (modified)
index d5cb148..0d608f1 100644 (file)
@@ -866,7 +866,7 @@ EXPORT_SYMBOL_GPL(usb_disable_xhci_ports);
  *
  * Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS.
  * It signals to the BIOS that the OS wants control of the host controller,
- * and then waits 5 seconds for the BIOS to hand over control.
+ * and then waits 1 second for the BIOS to hand over control.
  * If we timeout, assume the BIOS is broken and take control anyway.
  */
 static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
@@ -912,9 +912,9 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
        if (val & XHCI_HC_BIOS_OWNED) {
                writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset);
 
-               /* Wait for 5 seconds with 10 microsecond polling interval */
+               /* Wait for 1 second with 10 microsecond polling interval */
                timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
-                               0, 5000, 10);
+                               0, 1000000, 10);
 
                /* Assume a buggy BIOS and take HC ownership anyway */
                if (timeout) {
@@ -942,7 +942,7 @@ hc_init:
         * operational or runtime registers.  Wait 5 seconds and no more.
         */
        timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0,
-                       5000, 10);
+                       5000000, 10);
        /* Assume a buggy HC and start HC initialization anyway */
        if (timeout) {
                val = readl(op_reg_base + XHCI_STS_OFFSET);
index d89b72c..223326b 100644 (file)
@@ -1023,6 +1023,9 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
                                t2 |= PORT_WKOC_E | PORT_WKCONN_E;
                                t2 &= ~PORT_WKDISC_E;
                        }
+                       if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) &&
+                           (hcd->speed < HCD_USB3))
+                               t2 &= ~PORT_WAKE_BITS;
                } else
                        t2 &= ~PORT_WAKE_BITS;
 
index 841eb68..187cabc 100644 (file)
@@ -873,10 +873,9 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
                return 0;
        }
 
-       xhci->devs[slot_id] = kzalloc(sizeof(*xhci->devs[slot_id]), flags);
-       if (!xhci->devs[slot_id])
+       dev = kzalloc(sizeof(*dev), flags);
+       if (!dev)
                return 0;
-       dev = xhci->devs[slot_id];
 
        /* Allocate the (output) device context that will be used in the HC. */
        dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags);
@@ -925,9 +924,19 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
                 &xhci->dcbaa->dev_context_ptrs[slot_id],
                 le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id]));
 
+       xhci->devs[slot_id] = dev;
+
        return 1;
 fail:
-       xhci_free_virt_device(xhci, slot_id);
+
+       if (dev->eps[0].ring)
+               xhci_ring_free(xhci, dev->eps[0].ring);
+       if (dev->in_ctx)
+               xhci_free_container_ctx(xhci, dev->in_ctx);
+       if (dev->out_ctx)
+               xhci_free_container_ctx(xhci, dev->out_ctx);
+       kfree(dev);
+
        return 0;
 }
 
index 423700b..636b5d9 100644 (file)
 #define PCI_DEVICE_ID_INTEL_APL_XHCI                   0x5aa8
 #define PCI_DEVICE_ID_INTEL_DNV_XHCI                   0x19d0
 
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_4                        0x43b9
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_3                        0x43ba
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_2                        0x43bb
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_1                        0x43bc
+
 static const char hcd_name[] = "xhci_hcd";
 
 /* called after powerup, by probe or system-pm "wakeup" */
@@ -107,9 +112,19 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
        if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
                xhci->quirks |= XHCI_AMD_PLL_FIX;
 
+       if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x43bb)
+               xhci->quirks |= XHCI_SUSPEND_DELAY;
+
        if (pdev->vendor == PCI_VENDOR_ID_AMD)
                xhci->quirks |= XHCI_TRUST_TX_LENGTH;
 
+       if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
+               ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
+               (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) ||
+               (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) ||
+               (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1)))
+               xhci->quirks |= XHCI_U2_DISABLE_WAKE;
+
        if (pdev->vendor == PCI_VENDOR_ID_INTEL)
                xhci->quirks |= XHCI_INTEL_HOST;
        if (pdev->vendor == PCI_VENDOR_ID_INTEL)
index 74ed210..ba0122c 100644 (file)
@@ -2396,12 +2396,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                 */
                if (list_empty(&ep_ring->td_list)) {
                        /*
-                        * A stopped endpoint may generate an extra completion
-                        * event if the device was suspended.  Don't print
-                        * warnings.
+                        * Don't print wanings if it's due to a stopped endpoint
+                        * generating an extra completion event if the device
+                        * was suspended. Or, a event for the last TRB of a
+                        * short TD we already got a short event for.
+                        * The short TD is already removed from the TD list.
                         */
+
                        if (!(trb_comp_code == COMP_STOP ||
-                                               trb_comp_code == COMP_STOP_INVAL)) {
+                             trb_comp_code == COMP_STOP_INVAL ||
+                             ep_ring->last_td_was_short)) {
                                xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n",
                                                TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
                                                ep_index);
index 547a039..550f4e7 100644 (file)
@@ -936,6 +936,9 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
        clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
        del_timer_sync(&hcd->rh_timer);
 
+       if (xhci->quirks & XHCI_SUSPEND_DELAY)
+               usleep_range(1000, 1500);
+
        spin_lock_irq(&xhci->lock);
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
index 4453f2a..f3677ff 100644 (file)
@@ -1375,7 +1375,7 @@ struct xhci_bus_state {
 
 static inline unsigned int hcd_index(struct usb_hcd *hcd)
 {
-       if (hcd->speed == HCD_USB3)
+       if (hcd->speed >= HCD_USB3)
                return 0;
        else
                return 1;
@@ -1502,6 +1502,8 @@ struct xhci_hcd {
 #define XHCI_SPURIOUS_WAKEUP   (1 << 18)
 #define XHCI_PME_STUCK_QUIRK   (1 << 20)
 #define XHCI_MISSING_CAS       (1 << 24)
+#define XHCI_U2_DISABLE_WAKE   (1 << 27)
+#define XHCI_SUSPEND_DELAY     (1 << 30)
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */
index 2a38a17..9e387ec 100644 (file)
@@ -152,12 +152,13 @@ found:
                        return tmp;
        }
 
-       if (in) {
+       if (in)
                dev->in_pipe = usb_rcvbulkpipe(udev,
                        in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+       if (out)
                dev->out_pipe = usb_sndbulkpipe(udev,
                        out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-       }
+
        if (iso_in) {
                dev->iso_in = &iso_in->desc;
                dev->in_iso_pipe = usb_rcvisocpipe(udev,
index 91cd850..76f47f1 100644 (file)
@@ -1000,7 +1000,9 @@ static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg
                break;
 
        case MON_IOCQ_RING_SIZE:
+               mutex_lock(&rp->fetch_lock);
                ret = rp->b_size;
+               mutex_unlock(&rp->fetch_lock);
                break;
 
        case MON_IOCT_RING_SIZE:
@@ -1227,12 +1229,16 @@ static int mon_bin_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        unsigned long offset, chunk_idx;
        struct page *pageptr;
 
+       mutex_lock(&rp->fetch_lock);
        offset = vmf->pgoff << PAGE_SHIFT;
-       if (offset >= rp->b_size)
+       if (offset >= rp->b_size) {
+               mutex_unlock(&rp->fetch_lock);
                return VM_FAULT_SIGBUS;
+       }
        chunk_idx = offset / CHUNK_SIZE;
        pageptr = rp->b_vec[chunk_idx].pg;
        get_page(pageptr);
+       mutex_unlock(&rp->fetch_lock);
        vmf->page = pageptr;
        return 0;
 }
index ad40825..108dcc5 100644 (file)
@@ -82,6 +82,8 @@ struct mon_reader_text {
 
        wait_queue_head_t wait;
        int printf_size;
+       size_t printf_offset;
+       size_t printf_togo;
        char *printf_buf;
        struct mutex printf_lock;
 
@@ -373,73 +375,103 @@ err_alloc:
        return rc;
 }
 
-/*
- * For simplicity, we read one record in one system call and throw out
- * what does not fit. This means that the following does not work:
- *   dd if=/dbg/usbmon/0t bs=10
- * Also, we do not allow seeks and do not bother advancing the offset.
- */
+static ssize_t mon_text_copy_to_user(struct mon_reader_text *rp,
+    char __user * const buf, const size_t nbytes)
+{
+       const size_t togo = min(nbytes, rp->printf_togo);
+
+       if (copy_to_user(buf, &rp->printf_buf[rp->printf_offset], togo))
+               return -EFAULT;
+       rp->printf_togo -= togo;
+       rp->printf_offset += togo;
+       return togo;
+}
+
+/* ppos is not advanced since the llseek operation is not permitted. */
 static ssize_t mon_text_read_t(struct file *file, char __user *buf,
-                               size_t nbytes, loff_t *ppos)
+    size_t nbytes, loff_t *ppos)
 {
        struct mon_reader_text *rp = file->private_data;
        struct mon_event_text *ep;
        struct mon_text_ptr ptr;
+       ssize_t ret;
 
-       if (IS_ERR(ep = mon_text_read_wait(rp, file)))
-               return PTR_ERR(ep);
        mutex_lock(&rp->printf_lock);
-       ptr.cnt = 0;
-       ptr.pbuf = rp->printf_buf;
-       ptr.limit = rp->printf_size;
-
-       mon_text_read_head_t(rp, &ptr, ep);
-       mon_text_read_statset(rp, &ptr, ep);
-       ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
-           " %d", ep->length);
-       mon_text_read_data(rp, &ptr, ep);
-
-       if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
-               ptr.cnt = -EFAULT;
+
+       if (rp->printf_togo == 0) {
+
+               ep = mon_text_read_wait(rp, file);
+               if (IS_ERR(ep)) {
+                       mutex_unlock(&rp->printf_lock);
+                       return PTR_ERR(ep);
+               }
+               ptr.cnt = 0;
+               ptr.pbuf = rp->printf_buf;
+               ptr.limit = rp->printf_size;
+
+               mon_text_read_head_t(rp, &ptr, ep);
+               mon_text_read_statset(rp, &ptr, ep);
+               ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
+                   " %d", ep->length);
+               mon_text_read_data(rp, &ptr, ep);
+
+               rp->printf_togo = ptr.cnt;
+               rp->printf_offset = 0;
+
+               kmem_cache_free(rp->e_slab, ep);
+       }
+
+       ret = mon_text_copy_to_user(rp, buf, nbytes);
        mutex_unlock(&rp->printf_lock);
-       kmem_cache_free(rp->e_slab, ep);
-       return ptr.cnt;
+       return ret;
 }
 
+/* ppos is not advanced since the llseek operation is not permitted. */
 static ssize_t mon_text_read_u(struct file *file, char __user *buf,
-                               size_t nbytes, loff_t *ppos)
+    size_t nbytes, loff_t *ppos)
 {
        struct mon_reader_text *rp = file->private_data;
        struct mon_event_text *ep;
        struct mon_text_ptr ptr;
+       ssize_t ret;
 
-       if (IS_ERR(ep = mon_text_read_wait(rp, file)))
-               return PTR_ERR(ep);
        mutex_lock(&rp->printf_lock);
-       ptr.cnt = 0;
-       ptr.pbuf = rp->printf_buf;
-       ptr.limit = rp->printf_size;
 
-       mon_text_read_head_u(rp, &ptr, ep);
-       if (ep->type == 'E') {
-               mon_text_read_statset(rp, &ptr, ep);
-       } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
-               mon_text_read_isostat(rp, &ptr, ep);
-               mon_text_read_isodesc(rp, &ptr, ep);
-       } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
-               mon_text_read_intstat(rp, &ptr, ep);
-       } else {
-               mon_text_read_statset(rp, &ptr, ep);
+       if (rp->printf_togo == 0) {
+
+               ep = mon_text_read_wait(rp, file);
+               if (IS_ERR(ep)) {
+                       mutex_unlock(&rp->printf_lock);
+                       return PTR_ERR(ep);
+               }
+               ptr.cnt = 0;
+               ptr.pbuf = rp->printf_buf;
+               ptr.limit = rp->printf_size;
+
+               mon_text_read_head_u(rp, &ptr, ep);
+               if (ep->type == 'E') {
+                       mon_text_read_statset(rp, &ptr, ep);
+               } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
+                       mon_text_read_isostat(rp, &ptr, ep);
+                       mon_text_read_isodesc(rp, &ptr, ep);
+               } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
+                       mon_text_read_intstat(rp, &ptr, ep);
+               } else {
+                       mon_text_read_statset(rp, &ptr, ep);
+               }
+               ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
+                   " %d", ep->length);
+               mon_text_read_data(rp, &ptr, ep);
+
+               rp->printf_togo = ptr.cnt;
+               rp->printf_offset = 0;
+
+               kmem_cache_free(rp->e_slab, ep);
        }
-       ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
-           " %d", ep->length);
-       mon_text_read_data(rp, &ptr, ep);
 
-       if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
-               ptr.cnt = -EFAULT;
+       ret = mon_text_copy_to_user(rp, buf, nbytes);
        mutex_unlock(&rp->printf_lock);
-       kmem_cache_free(rp->e_slab, ep);
-       return ptr.cnt;
+       return ret;
 }
 
 static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp,
index 08c679c..71f4dae 100644 (file)
@@ -599,12 +599,14 @@ static int usbhsc_resume(struct device *dev)
        struct usbhs_priv *priv = dev_get_drvdata(dev);
        struct platform_device *pdev = usbhs_priv_to_pdev(priv);
 
-       usbhs_platform_call(priv, phy_reset, pdev);
-
-       if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
+       if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) {
                usbhsc_power_ctrl(priv, 1);
+               usbhs_mod_autonomy_mode(priv);
+       }
 
-       usbhsc_hotplug(priv);
+       usbhs_platform_call(priv, phy_reset, pdev);
+
+       usbhsc_drvcllbck_notify_hotplug(pdev);
 
        return 0;
 }
index 2eb39b3..c47ba72 100644 (file)
@@ -261,11 +261,26 @@ static void usbhsf_fifo_clear(struct usbhs_pipe *pipe,
                              struct usbhs_fifo *fifo)
 {
        struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+       int ret = 0;
 
-       if (!usbhs_pipe_is_dcp(pipe))
-               usbhsf_fifo_barrier(priv, fifo);
+       if (!usbhs_pipe_is_dcp(pipe)) {
+               /*
+                * This driver checks the pipe condition first to avoid -EBUSY
+                * from usbhsf_fifo_barrier() with about 10 msec delay in
+                * the interrupt handler if the pipe is RX direction and empty.
+                */
+               if (usbhs_pipe_is_dir_in(pipe))
+                       ret = usbhs_pipe_is_accessible(pipe);
+               if (!ret)
+                       ret = usbhsf_fifo_barrier(priv, fifo);
+       }
 
-       usbhs_write(priv, fifo->ctr, BCLR);
+       /*
+        * if non-DCP pipe, this driver should set BCLR when
+        * usbhsf_fifo_barrier() returns 0.
+        */
+       if (!ret)
+               usbhs_write(priv, fifo->ctr, BCLR);
 }
 
 static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv,
@@ -802,8 +817,8 @@ static void usbhsf_dma_prepare_tasklet(unsigned long data)
        dev_dbg(dev, "  %s %d (%d/ %d)\n",
                fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero);
 
-       usbhsf_dma_start(pipe, fifo);
        dma_async_issue_pending(chan);
+       usbhsf_dma_start(pipe, fifo);
 
 xfer_work_end:
        usbhs_unlock(priv, flags);
index eb46562..674413e 100644 (file)
@@ -76,9 +76,9 @@ struct usbhsg_recip_handle {
                struct usbhsg_gpriv, mod)
 
 #define __usbhsg_for_each_uep(start, pos, g, i)        \
-       for (i = start, pos = (g)->uep + i;     \
-            i < (g)->uep_size;                 \
-            i++, pos = (g)->uep + i)
+       for ((i) = start;                                       \
+            ((i) < (g)->uep_size) && ((pos) = (g)->uep + (i)); \
+            (i)++)
 
 #define usbhsg_for_each_uep(pos, gpriv, i)     \
        __usbhsg_for_each_uep(1, pos, gpriv, i)
index 7955de5..b3a610c 100644 (file)
@@ -131,9 +131,9 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host";
        __usbhsh_for_each_hpipe(0, pos, hpriv, i)
 
 #define __usbhsh_for_each_udev(start, pos, h, i)       \
-       for (i = start, pos = (h)->udev + i;            \
-            i < USBHSH_DEVICE_MAX;                     \
-            i++, pos = (h)->udev + i)
+       for ((i) = start;                                               \
+            ((i) < USBHSH_DEVICE_MAX) && ((pos) = (h)->udev + (i));    \
+            (i)++)
 
 #define usbhsh_for_each_udev(pos, hpriv, i)    \
        __usbhsh_for_each_udev(1, pos, hpriv, i)
index 6334fc6..a00b67a 100644 (file)
@@ -54,9 +54,9 @@ struct usbhs_pipe_info {
  * pipe list
  */
 #define __usbhs_for_each_pipe(start, pos, info, i)     \
-       for (i = start, pos = (info)->pipe;             \
-            i < (info)->size;                          \
-            i++, pos = (info)->pipe + i)
+       for ((i) = start;                                               \
+            ((i) < (info)->size) && ((pos) = (info)->pipe + (i));      \
+            (i)++)
 
 #define usbhs_for_each_pipe(pos, priv, i)                      \
        __usbhs_for_each_pipe(1, pos, &((priv)->pipe_info), i)
index 87302dd..bcb4620 100644 (file)
@@ -195,6 +195,7 @@ static int usb_console_setup(struct console *co, char *options)
        tty_kref_put(tty);
  reset_open_count:
        port->port.count = 0;
+       info->port = NULL;
        usb_autopm_put_interface(serial->interface);
  error_get_interface:
        usb_serial_put(serial);
index 8dfb599..4736965 100644 (file)
@@ -126,6 +126,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x8470) }, /* Juniper Networks BX Series System Console */
        { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */
        { USB_DEVICE(0x10C4, 0x84B6) }, /* Starizona Hyperion */
+       { USB_DEVICE(0x10C4, 0x85A7) }, /* LifeScan OneTouch Verio IQ */
        { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */
        { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */
        { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
@@ -140,6 +141,8 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x8977) }, /* CEL MeshWorks DevKit Device */
        { USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */
        { USB_DEVICE(0x10C4, 0x8A2A) }, /* HubZ dual ZigBee and Z-Wave dongle */
+       { USB_DEVICE(0x10C4, 0x8A5E) }, /* CEL EM3588 ZigBee USB Stick Long Range */
+       { USB_DEVICE(0x10C4, 0x8B34) }, /* Qivicon ZigBee USB Radio Stick */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
@@ -174,6 +177,8 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
        { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
        { USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */
+       { USB_DEVICE(0x18EF, 0xE030) }, /* ELV ALC 8xxx Battery Charger */
+       { USB_DEVICE(0x18EF, 0xE032) }, /* ELV TFD500 Data Logger */
        { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */
        { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */
        { USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */
index a42adab..b79aac7 100644 (file)
@@ -1035,6 +1035,9 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(WICED_VID, WICED_USB20706V2_PID) },
        { USB_DEVICE(TI_VID, TI_CC3200_LAUNCHPAD_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_BT_USB_PID) },
+       { USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_WL_USB_PID) },
+       { USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
index 6181b79..0b3de2c 100644 (file)
 #define ADI_GNICE_PID          0xF000
 #define ADI_GNICEPLUS_PID      0xF001
 
+/*
+ * Cypress WICED USB UART
+ */
+#define CYPRESS_VID                    0x04B4
+#define CYPRESS_WICED_BT_USB_PID       0x009B
+#define CYPRESS_WICED_WL_USB_PID       0xF900
+
 /*
  * Microchip Technology, Inc.
  *
 #define ICPDAS_I7561U_PID              0x0104
 #define ICPDAS_I7563U_PID              0x0105
 
+/*
+ * Airbus Defence and Space
+ */
+#define AIRBUS_DS_VID                  0x1e8e  /* Vendor ID */
+#define AIRBUS_DS_P8GR                 0x6001  /* Tetra P8GR */
+
 /*
  * RT Systems programming cables for various ham radios
  */
index 0c1c8ca..23fd890 100644 (file)
@@ -142,6 +142,7 @@ struct garmin_data {
        __u8   privpkt[4*6];
        spinlock_t lock;
        struct list_head pktlist;
+       struct usb_anchor write_urbs;
 };
 
 
@@ -923,13 +924,19 @@ static int garmin_init_session(struct usb_serial_port *port)
                                        sizeof(GARMIN_START_SESSION_REQ), 0);
 
                        if (status < 0)
-                               break;
+                               goto err_kill_urbs;
                }
 
                if (status > 0)
                        status = 0;
        }
 
+       return status;
+
+err_kill_urbs:
+       usb_kill_anchored_urbs(&garmin_data_p->write_urbs);
+       usb_kill_urb(port->interrupt_in_urb);
+
        return status;
 }
 
@@ -950,7 +957,6 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port)
        spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
        /* shutdown any bulk reads that might be going on */
-       usb_kill_urb(port->write_urb);
        usb_kill_urb(port->read_urb);
 
        if (garmin_data_p->state == STATE_RESET)
@@ -977,7 +983,7 @@ static void garmin_close(struct usb_serial_port *port)
 
        /* shutdown our urbs */
        usb_kill_urb(port->read_urb);
-       usb_kill_urb(port->write_urb);
+       usb_kill_anchored_urbs(&garmin_data_p->write_urbs);
 
        /* keep reset state so we know that we must start a new session */
        if (garmin_data_p->state != STATE_RESET)
@@ -1069,12 +1075,14 @@ static int garmin_write_bulk(struct usb_serial_port *port,
        }
 
        /* send it down the pipe */
+       usb_anchor_urb(urb, &garmin_data_p->write_urbs);
        status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status) {
                dev_err(&port->dev,
                   "%s - usb_submit_urb(write bulk) failed with status = %d\n",
                                __func__, status);
                count = status;
+               usb_unanchor_urb(urb);
                kfree(buffer);
        }
 
@@ -1464,9 +1472,16 @@ static int garmin_attach(struct usb_serial *serial)
        garmin_data_p->state = 0;
        garmin_data_p->flags = 0;
        garmin_data_p->count = 0;
+       init_usb_anchor(&garmin_data_p->write_urbs);
        usb_set_serial_port_data(port, garmin_data_p);
 
        status = garmin_init_session(port);
+       if (status)
+               goto err_free;
+
+       return 0;
+err_free:
+       kfree(garmin_data_p);
 
        return status;
 }
@@ -1479,6 +1494,7 @@ static void garmin_disconnect(struct usb_serial *serial)
 
        dbg("%s", __func__);
 
+       usb_kill_anchored_urbs(&garmin_data_p->write_urbs);
        usb_kill_urb(port->interrupt_in_urb);
        del_timer_sync(&garmin_data_p->timer);
 }
index d4109f2..eb70184 100644 (file)
@@ -2387,7 +2387,6 @@ static int write_cmd_usb(struct edgeport_port *edge_port,
                dev_err(&edge_port->port->dev,
                    "%s - usb_submit_urb(write command) failed, status = %d\n",
                                                        __func__, status);
-               usb_kill_urb(urb);
                usb_free_urb(urb);
                atomic_dec(&CmdUrbs);
                return status;
index ed8694b..8901b8d 100644 (file)
@@ -449,7 +449,7 @@ static int mct_u232_startup(struct usb_serial *serial)
 
        /* check first to simplify error handling */
        if (!serial->port[1] || !serial->port[1]->interrupt_in_urb) {
-               dev_err(&port->dev, "expected endpoint missing\n");
+               dev_err(&serial->dev->dev, "expected endpoint missing\n");
                return -ENODEV;
        }
 
index cfb35ec..3073881 100644 (file)
@@ -237,11 +237,14 @@ static void option_instat_callback(struct urb *urb);
 /* These Quectel products use Qualcomm's vendor ID */
 #define QUECTEL_PRODUCT_UC20                   0x9003
 #define QUECTEL_PRODUCT_UC15                   0x9090
+/* These Yuga products use Qualcomm's vendor ID */
+#define YUGA_PRODUCT_CLM920_NC5                        0x9625
 
 #define QUECTEL_VENDOR_ID                      0x2c7c
 /* These Quectel products use Quectel's vendor ID */
 #define QUECTEL_PRODUCT_EC21                   0x0121
 #define QUECTEL_PRODUCT_EC25                   0x0125
+#define QUECTEL_PRODUCT_BG96                   0x0296
 
 #define CMOTECH_VENDOR_ID                      0x16d8
 #define CMOTECH_PRODUCT_6001                   0x6001
@@ -508,6 +511,7 @@ static void option_instat_callback(struct urb *urb);
 
 /* TP-LINK Incorporated products */
 #define TPLINK_VENDOR_ID                       0x2357
+#define TPLINK_PRODUCT_LTE                     0x000D
 #define TPLINK_PRODUCT_MA180                   0x0201
 
 /* Changhong products */
@@ -655,6 +659,10 @@ static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = {
        .reserved = BIT(1) | BIT(2) | BIT(3),
 };
 
+static const struct option_blacklist_info yuga_clm920_nc5_blacklist = {
+       .reserved = BIT(1) | BIT(4),
+};
+
 static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -1159,11 +1167,16 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC15)},
        { USB_DEVICE(QUALCOMM_VENDOR_ID, QUECTEL_PRODUCT_UC20),
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+       /* Yuga products use Qualcomm vendor ID */
+       { USB_DEVICE(QUALCOMM_VENDOR_ID, YUGA_PRODUCT_CLM920_NC5),
+         .driver_info = (kernel_ulong_t)&yuga_clm920_nc5_blacklist },
        /* Quectel products using Quectel vendor ID */
        { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC21),
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC25),
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+       { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
+         .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
@@ -1959,6 +1972,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
        { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600A) },
        { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T_600E) },
+       { USB_DEVICE_AND_INTERFACE_INFO(TPLINK_VENDOR_ID, TPLINK_PRODUCT_LTE, 0xff, 0x00, 0x00) },      /* TP-Link LTE Module */
        { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE(TPLINK_VENDOR_ID, 0x9000),                                 /* TP-Link MA260 */
index 5910dac..1d5379e 100644 (file)
@@ -45,6 +45,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
+       { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_CHILITAG) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
index 09d9be8..f379e00 100644 (file)
@@ -17,6 +17,7 @@
 #define PL2303_PRODUCT_ID_DCU11                0x1234
 #define PL2303_PRODUCT_ID_PHAROS       0xaaa0
 #define PL2303_PRODUCT_ID_RSAQ3                0xaaa2
+#define PL2303_PRODUCT_ID_CHILITAG     0xaaa8
 #define PL2303_PRODUCT_ID_ALDIGA       0x0611
 #define PL2303_PRODUCT_ID_MMX          0x0612
 #define PL2303_PRODUCT_ID_GPRS         0x0609
index ffc4193..36f18b5 100644 (file)
@@ -1522,8 +1522,11 @@ static void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
 
        /* Make sure driver was initialized */
 
-       if (us->extra == NULL)
+       if (us->extra == NULL) {
                US_DEBUGP("ERROR Driver not initialized\n");
+               srb->result = DID_ERROR << 16;
+               return;
+       }
 
        scsi_set_resid(srb, 0);
        /* scsi_bufflen might change in protocol translation to ata */
index a0c4cc4..5f08ce6 100644 (file)
@@ -1346,6 +1346,13 @@ UNUSUAL_DEV( 0x0bc2, 0x3010, 0x0000, 0x0000,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_SANE_SENSE ),
 
+/* Reported by Kris Lindgren <kris.lindgren@gmail.com> */
+UNUSUAL_DEV( 0x0bc2, 0x3332, 0x0000, 0x9999,
+               "Seagate",
+               "External",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_WP_DETECT ),
+
 UNUSUAL_DEV(  0x0d49, 0x7310, 0x0000, 0x9999,
                "Maxtor",
                "USB to SATA",
@@ -1954,6 +1961,13 @@ UNUSUAL_DEV(  0x152d, 0x0567, 0x0114, 0x0114,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_BROKEN_FUA ),
 
+/* Reported by David Kozub <zub@linux.fjfi.cvut.cz> */
+UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999,
+               "JMicron",
+               "JMS567",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_BROKEN_FUA),
+
 /* Reported by Alexandre Oliva <oliva@lsd.ic.unicamp.br>
  * JMicron responds to USN and several other SCSI ioctls with a
  * residue that causes subsequent I/O requests to fail.  */
index ad971df..eb0a952 100644 (file)
@@ -813,6 +813,8 @@ static int hwarc_probe(struct usb_interface *iface,
 
        if (iface->cur_altsetting->desc.bNumEndpoints < 1)
                return -ENODEV;
+       if (!usb_endpoint_xfer_int(&iface->cur_altsetting->endpoint[0].desc))
+               return -ENODEV;
 
        result = -ENOMEM;
        uwb_rc = uwb_rc_alloc();
index bdcb13c..5c98283 100644 (file)
@@ -303,18 +303,22 @@ static int uwbd(void *param)
 /** Start the UWB daemon */
 void uwbd_start(struct uwb_rc *rc)
 {
-       rc->uwbd.task = kthread_run(uwbd, rc, "uwbd");
-       if (rc->uwbd.task == NULL)
+       struct task_struct *task = kthread_run(uwbd, rc, "uwbd");
+       if (IS_ERR(task)) {
+               rc->uwbd.task = NULL;
                printk(KERN_ERR "UWB: Cannot start management daemon; "
                       "UWB won't work\n");
-       else
+       } else {
+               rc->uwbd.task = task;
                rc->uwbd.pid = rc->uwbd.task->pid;
+       }
 }
 
 /* Stop the UWB daemon and free any unprocessed events */
 void uwbd_stop(struct uwb_rc *rc)
 {
-       kthread_stop(rc->uwbd.task);
+       if (rc->uwbd.task)
+               kthread_stop(rc->uwbd.task);
        uwbd_flush(rc);
 }
 
index 44bdce4..3f75f5f 100644 (file)
@@ -1852,7 +1852,7 @@ static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 #if defined(DEBUG) && defined(CONFIG_FB_ATY_CT)
        case ATYIO_CLKR:
                if (M64_HAS(INTEGRATED)) {
-                       struct atyclk clk;
+                       struct atyclk clk = { 0 };
                        union aty_pll *pll = &par->pll;
                        u32 dsp_config = pll->ct.dsp_config;
                        u32 dsp_on_off = pll->ct.dsp_on_off;
index b63860f..821b598 100644 (file)
@@ -71,7 +71,6 @@ const struct consw dummy_con = {
     .con_switch =      DUMMY,
     .con_blank =       DUMMY,
     .con_font_set =    DUMMY,
-    .con_font_get =    DUMMY,
     .con_font_default =        DUMMY,
     .con_font_copy =   DUMMY,
     .con_set_palette = DUMMY,
index 37d764a..51c0df1 100644 (file)
@@ -122,7 +122,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
                unsigned char __user *ured;
                unsigned char __user *ugreen;
                unsigned char __user *ublue;
-               int index, count, i;
+               unsigned int index, count, i;
 
                if (get_user(index, &c->index) ||
                    __get_user(count, &c->count) ||
@@ -161,7 +161,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
                unsigned char __user *ugreen;
                unsigned char __user *ublue;
                struct fb_cmap *cmap = &info->cmap;
-               int index, count, i;
+               unsigned int index, count, i;
                u8 red, green, blue;
 
                if (get_user(index, &c->index) ||
index cb5988f..f1dbaeb 100644 (file)
@@ -765,11 +765,11 @@ static int dlfb_get_edid(struct dlfb_data *dev, char *edid, int len)
 
        for (i = 0; i < len; i++) {
                ret = usb_control_msg(dev->udev,
-                                   usb_rcvctrlpipe(dev->udev, 0), (0x02),
-                                   (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
-                                   HZ);
-               if (ret < 1) {
-                       pr_err("Read EDID byte %d failed err %x\n", i, ret);
+                                     usb_rcvctrlpipe(dev->udev, 0), 0x02,
+                                     (0x80 | (0x02 << 5)), i << 8, 0xA1,
+                                     rbuf, 2, USB_CTRL_GET_TIMEOUT);
+               if (ret < 2) {
+                       pr_err("Read EDID byte %d failed: %d\n", i, ret);
                        i--;
                        break;
                }
index 34defa1..2e99ded 100644 (file)
@@ -469,6 +469,9 @@ static int v9fs_test_inode(struct inode *inode, void *data)
 
        if (v9inode->qid.type != st->qid.type)
                return 0;
+
+       if (v9inode->qid.path != st->qid.path)
+               return 0;
        return 1;
 }
 
index 781e56e..da24b85 100644 (file)
@@ -105,6 +105,9 @@ static int v9fs_test_inode_dotl(struct inode *inode, void *data)
 
        if (v9inode->qid.type != st->qid.type)
                return 0;
+
+       if (v9inode->qid.path != st->qid.path)
+               return 0;
        return 1;
 }
 
index 18d73ef..933738f 100644 (file)
@@ -88,7 +88,8 @@ static int autofs4_write(struct file *file, const void *addr, int bytes)
                spin_unlock_irqrestore(&current->sighand->siglock, flags);
        }
 
-       return (bytes > 0);
+       /* if 'wr' returned 0 (impossible) we assume -EIO (safe) */
+       return bytes == 0 ? 0 : wr < 0 ? wr : -EIO;
 }
        
 static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
@@ -102,6 +103,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
        } pkt;
        struct file *pipe = NULL;
        size_t pktsz;
+       int ret;
 
        DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d",
                (unsigned long) wq->wait_queue_token, wq->name.len, wq->name.name, type);
@@ -174,12 +176,23 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
                return;
        }
 
-       pipe = get_file(sbi->pipe);
+       pipe = sbi->pipe;
+       get_file(pipe);
 
        mutex_unlock(&sbi->wq_mutex);
 
-       if (autofs4_write(pipe, &pkt, pktsz))
+       switch (ret = autofs4_write(pipe, &pkt, pktsz)) {
+       case 0:
+               break;
+       case -ENOMEM:
+       case -ERESTARTSYS:
+               /* Just fail this one */
+               autofs4_wait_release(sbi, wq->wait_queue_token, ret);
+               break;
+       default:
                autofs4_catatonic_mode(sbi);
+               break;
+       }
        fput(pipe);
 }
 
@@ -259,6 +272,9 @@ static int validate_request(struct autofs_wait_queue **wait,
        struct autofs_wait_queue *wq;
        struct autofs_info *ino;
 
+       if (sbi->catatonic)
+               return -ENOENT;
+
        /* Wait in progress, continue; */
        wq = autofs4_find_wait(sbi, qstr);
        if (wq) {
@@ -291,6 +307,9 @@ static int validate_request(struct autofs_wait_queue **wait,
                        if (mutex_lock_interruptible(&sbi->wq_mutex))
                                return -EINTR;
 
+                       if (sbi->catatonic)
+                               return -ENOENT;
+
                        wq = autofs4_find_wait(sbi, qstr);
                        if (wq) {
                                *wait = wq;
@@ -391,7 +410,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
 
        ret = validate_request(&wq, sbi, &qstr, dentry, notify);
        if (ret <= 0) {
-               if (ret == 0)
+               if (ret != -EINTR)
                        mutex_unlock(&sbi->wq_mutex);
                kfree(qstr.name);
                return ret;
index 55b5188..081747c 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -976,6 +976,7 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
        struct bio *bio;
        int cur_page = 0;
        int ret, offset;
+       struct bio_vec *bvec;
 
        for (i = 0; i < iov_count; i++) {
                unsigned long uaddr = (unsigned long)iov[i].iov_base;
@@ -1019,7 +1020,12 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
 
                ret = get_user_pages_fast(uaddr, local_nr_pages,
                                write_to_vm, &pages[cur_page]);
-               if (ret < local_nr_pages) {
+               if (unlikely(ret < local_nr_pages)) {
+                       for (j = cur_page; j < page_limit; j++) {
+                               if (!pages[j])
+                                       break;
+                               put_page(pages[j]);
+                       }
                        ret = -EFAULT;
                        goto out_unmap;
                }
@@ -1027,6 +1033,7 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
                offset = uaddr & ~PAGE_MASK;
                for (j = cur_page; j < page_limit; j++) {
                        unsigned int bytes = PAGE_SIZE - offset;
+                       unsigned short prev_bi_vcnt = bio->bi_vcnt;
 
                        if (len <= 0)
                                break;
@@ -1041,6 +1048,13 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
                                            bytes)
                                break;
 
+                       /*
+                        * check if vector was merged with previous
+                        * drop page reference if needed
+                        */
+                       if (bio->bi_vcnt == prev_bi_vcnt)
+                               put_page(pages[j]);
+
                        len -= bytes;
                        offset = 0;
                }
@@ -1066,10 +1080,8 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
        return bio;
 
  out_unmap:
-       for (i = 0; i < nr_pages; i++) {
-               if(!pages[i])
-                       break;
-               page_cache_release(pages[i]);
+       bio_for_each_segment_all(bvec, bio, j) {
+               put_page(bvec->bv_page);
        }
  out:
        kfree(pages);
index 9f55b54..286edc1 100644 (file)
@@ -117,12 +117,6 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans,
        switch (type) {
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
-               if (acl) {
-                       ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
-                       if (ret)
-                               return ret;
-               }
-               ret = 0;
                break;
        case ACL_TYPE_DEFAULT:
                if (!S_ISDIR(inode->i_mode))
@@ -161,11 +155,13 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
 {
        int ret;
        struct posix_acl *acl = NULL;
+       struct inode *inode = dentry->d_inode;
+       umode_t old_mode = inode->i_mode;
 
-       if (!inode_owner_or_capable(dentry->d_inode))
+       if (!inode_owner_or_capable(inode))
                return -EPERM;
 
-       if (!IS_POSIXACL(dentry->d_inode))
+       if (!IS_POSIXACL(inode))
                return -EOPNOTSUPP;
 
        if (value) {
@@ -180,7 +176,14 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
                }
        }
 
-       ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type);
+       if (type == ACL_TYPE_ACCESS && acl) {
+               ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+               if (ret)
+                       goto out;
+       }
+       ret = btrfs_set_acl(NULL, inode, acl, type);
+       if (ret)
+               inode->i_mode = old_mode;
 out:
        posix_acl_release(acl);
 
index da528f8..57c4ad3 100644 (file)
@@ -2759,13 +2759,6 @@ again:
                goto again;
        }
 
-       /* We've already setup this transaction, go ahead and exit */
-       if (block_group->cache_generation == trans->transid &&
-           i_size_read(inode)) {
-               dcs = BTRFS_DC_SETUP;
-               goto out_put;
-       }
-
        /*
         * We want to set the generation to 0, that way if anything goes wrong
         * from here on out we know not to trust this cache when we load up next
@@ -2775,6 +2768,13 @@ again:
        ret = btrfs_update_inode(trans, root, inode);
        WARN_ON(ret);
 
+       /* We've already setup this transaction, go ahead and exit */
+       if (block_group->cache_generation == trans->transid &&
+           i_size_read(inode)) {
+               dcs = BTRFS_DC_SETUP;
+               goto out_put;
+       }
+
        if (i_size_read(inode) > 0) {
                ret = btrfs_truncate_free_space_cache(root, trans, path,
                                                      inode);
index 231fbe1..205d588 100644 (file)
@@ -1751,7 +1751,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
        if (!path)
                return -ENOMEM;
 
-       ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX];
+       ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX - 1];
 
        key.objectid = tree_id;
        key.type = BTRFS_ROOT_ITEM_KEY;
index 6479b85..998a9cb 100644 (file)
@@ -2216,12 +2216,13 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
 
        while (1) {
                ret = find_first_extent_bit(&log->dirty_log_pages,
-                               0, &start, &end, EXTENT_DIRTY | EXTENT_NEW);
+                               0, &start, &end,
+                               EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT);
                if (ret)
                        break;
 
                clear_extent_bits(&log->dirty_log_pages, start, end,
-                                 EXTENT_DIRTY | EXTENT_NEW, GFP_NOFS);
+                                 EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT, GFP_NOFS);
        }
 
        free_extent_buffer(log->node);
index 6937e7c..22758b1 100644 (file)
@@ -520,6 +520,14 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 
        oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0;
 
+       /* Don't allow path components longer than the server max. */
+       if (unlikely(pTcon->fsAttrInfo.MaxPathNameComponentLength &&
+                    direntry->d_name.len >
+                    le32_to_cpu(pTcon->fsAttrInfo.MaxPathNameComponentLength))) {
+               rc = -ENAMETOOLONG;
+               goto lookup_out;
+       }
+
        /*
         * Don't allow the separator character in a path component.
         * The VFS will not allow "/", but "\" is allowed by posix.
index f9d2863..a491aef 100644 (file)
@@ -2530,20 +2530,18 @@ static struct vm_operations_struct cifs_file_vm_ops = {
 
 int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       int rc, xid;
+       int xid, rc = 0;
        struct inode *inode = file->f_path.dentry->d_inode;
 
        xid = GetXid();
 
-       if (!CIFS_I(inode)->clientCanCacheRead) {
+       if (!CIFS_I(inode)->clientCanCacheRead)
                rc = cifs_invalidate_mapping(inode);
-               if (rc)
-                       return rc;
-       }
-
-       rc = generic_file_mmap(file, vma);
-       if (rc == 0)
+       if (!rc)
+               rc = generic_file_mmap(file, vma);
+       if (!rc)
                vma->vm_ops = &cifs_file_vm_ops;
+
        FreeXid(xid);
        return rc;
 }
@@ -2553,15 +2551,15 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
        int rc, xid;
 
        xid = GetXid();
+
        rc = cifs_revalidate_file(file);
-       if (rc) {
+       if (rc)
                cFYI(1, "Validation prior to mmap failed, error=%d", rc);
-               FreeXid(xid);
-               return rc;
-       }
-       rc = generic_file_mmap(file, vma);
-       if (rc == 0)
+       if (!rc)
+               rc = generic_file_mmap(file, vma);
+       if (!rc)
                vma->vm_ops = &cifs_file_vm_ops;
+
        FreeXid(xid);
        return rc;
 }
index 9727e0c..446d6b6 100644 (file)
@@ -447,8 +447,7 @@ int venus_fsync(struct super_block *sb, struct CodaFid *fid)
        UPARG(CODA_FSYNC);
 
        inp->coda_fsync.VFid = *fid;
-       error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs),
-                           &outsize, inp);
+       error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
 
        CODA_FREE(inp, insize);
        return error;
index f854cf9..d72deac 100644 (file)
@@ -608,7 +608,6 @@ struct serial_struct32 {
 static int serial_struct_ioctl(unsigned fd, unsigned cmd,
                        struct serial_struct32 __user *ss32)
 {
-        typedef struct serial_struct SS;
         typedef struct serial_struct32 SS32;
         int err;
         struct serial_struct ss;
index 01c68ae..93df954 100644 (file)
@@ -836,6 +836,7 @@ void shrink_dcache_sb(struct super_block *sb)
                list_splice_init(&sb->s_dentry_lru, &tmp);
                spin_unlock(&dcache_lru_lock);
                shrink_dentry_list(&tmp);
+               cond_resched();
                spin_lock(&dcache_lru_lock);
        }
        spin_unlock(&dcache_lru_lock);
index d8ea607..cbc3c7b 100644 (file)
@@ -346,6 +346,10 @@ static int dlm_device_register(struct dlm_ls *ls, char *name)
        error = misc_register(&ls->ls_device);
        if (error) {
                kfree(ls->ls_device.name);
+               /* this has to be set to NULL
+                * to avoid a double-free in dlm_device_deregister
+                */
+               ls->ls_device.name = NULL;
        }
 fail:
        return error;
index e654e39..06933e3 100644 (file)
@@ -83,11 +83,16 @@ struct ecryptfs_page_crypt_context {
 static inline struct ecryptfs_auth_tok *
 ecryptfs_get_encrypted_key_payload_data(struct key *key)
 {
-       if (key->type == &key_type_encrypted)
-               return (struct ecryptfs_auth_tok *)
-                       (&((struct encrypted_key_payload *)key->payload.data)->payload_data);
-       else
+       struct encrypted_key_payload *payload;
+
+       if (key->type != &key_type_encrypted)
                return NULL;
+
+       payload = key->payload.data;
+       if (!payload)
+               return ERR_PTR(-EKEYREVOKED);
+
+       return (struct ecryptfs_auth_tok *)payload->payload_data;
 }
 
 static inline struct key *ecryptfs_get_encrypted_key(char *sig)
@@ -113,13 +118,17 @@ static inline struct ecryptfs_auth_tok *
 ecryptfs_get_key_payload_data(struct key *key)
 {
        struct ecryptfs_auth_tok *auth_tok;
+       struct user_key_payload *ukp;
 
        auth_tok = ecryptfs_get_encrypted_key_payload_data(key);
-       if (!auth_tok)
-               return (struct ecryptfs_auth_tok *)
-                       (((struct user_key_payload *)key->payload.data)->data);
-       else
+       if (auth_tok)
                return auth_tok;
+
+       ukp = key->payload.data;
+       if (!ukp)
+               return ERR_PTR(-EKEYREVOKED);
+
+       return (struct ecryptfs_auth_tok *)ukp->data;
 }
 
 #define ECRYPTFS_MAX_KEYSET_SIZE 1024
index 725f9c0..d69fcb0 100644 (file)
@@ -459,7 +459,8 @@ out:
  * @auth_tok_key: key containing the authentication token
  * @auth_tok: authentication token
  *
- * Returns zero on valid auth tok; -EINVAL otherwise
+ * Returns zero on valid auth tok; -EINVAL if the payload is invalid; or
+ * -EKEYREVOKED if the key was revoked before we acquired its semaphore.
  */
 static int
 ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key,
@@ -468,6 +469,12 @@ ecryptfs_verify_auth_tok_from_key(struct key *auth_tok_key,
        int rc = 0;
 
        (*auth_tok) = ecryptfs_get_key_payload_data(auth_tok_key);
+       if (IS_ERR(*auth_tok)) {
+               rc = PTR_ERR(*auth_tok);
+               *auth_tok = NULL;
+               goto out;
+       }
+
        if (ecryptfs_verify_version((*auth_tok)->version)) {
                printk(KERN_ERR "Data structure version mismatch. Userspace "
                       "tools must match eCryptfs kernel module with major "
@@ -1153,7 +1160,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
        struct ecryptfs_message *msg = NULL;
        char *auth_tok_sig;
        char *payload = NULL;
-       size_t payload_len;
+       size_t payload_len = 0;
        int rc;
 
        rc = ecryptfs_get_auth_tok_sig(&auth_tok_sig, auth_tok);
index ab22480..966a31f 100644 (file)
@@ -550,17 +550,17 @@ void ecryptfs_release_messaging(void)
                mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
        }
        if (ecryptfs_daemon_hash) {
-               struct hlist_node *elem;
                struct ecryptfs_daemon *daemon;
+               struct hlist_node *elem, *n;
                int i;
 
                mutex_lock(&ecryptfs_daemon_hash_mux);
                for (i = 0; i < (1 << ecryptfs_hash_bits); i++) {
                        int rc;
 
-                       hlist_for_each_entry(daemon, elem,
-                                            &ecryptfs_daemon_hash[i],
-                                            euid_chain) {
+                       hlist_for_each_entry_safe(daemon, elem, n,
+                                                 &ecryptfs_daemon_hash[i],
+                                                 euid_chain) {
                                rc = ecryptfs_exorcise_daemon(daemon);
                                if (rc)
                                        printk(KERN_ERR "%s: Error whilst "
index 451b9b8..7903ddb 100644 (file)
@@ -477,8 +477,14 @@ static void ep_remove_wait_queue(struct eppoll_entry *pwq)
        wait_queue_head_t *whead;
 
        rcu_read_lock();
-       /* If it is cleared by POLLFREE, it should be rcu-safe */
-       whead = rcu_dereference(pwq->whead);
+       /*
+        * If it is cleared by POLLFREE, it should be rcu-safe.
+        * If we read NULL we need a barrier paired with
+        * smp_store_release() in ep_poll_callback(), otherwise
+        * we rely on whead->lock.
+        */
+       whead = ACCESS_ONCE(pwq->whead);
+       smp_mb();
        if (whead)
                remove_wait_queue(whead, &pwq->wait);
        rcu_read_unlock();
@@ -859,17 +865,6 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
        struct epitem *epi = ep_item_from_wait(wait);
        struct eventpoll *ep = epi->ep;
 
-       if ((unsigned long)key & POLLFREE) {
-               ep_pwq_from_wait(wait)->whead = NULL;
-               /*
-                * whead = NULL above can race with ep_remove_wait_queue()
-                * which can do another remove_wait_queue() after us, so we
-                * can't use __remove_wait_queue(). whead->lock is held by
-                * the caller.
-                */
-               list_del_init(&wait->task_list);
-       }
-
        spin_lock_irqsave(&ep->lock, flags);
 
        /*
@@ -924,6 +919,23 @@ out_unlock:
        if (pwake)
                ep_poll_safewake(&ep->poll_wait);
 
+       if ((unsigned long)key & POLLFREE) {
+               /*
+                * If we race with ep_remove_wait_queue() it can miss
+                * ->whead = NULL and do another remove_wait_queue() after
+                * us, so we can't use __remove_wait_queue().
+                */
+               list_del_init(&wait->task_list);
+               /*
+                * ->whead != NULL protects us from the race with ep_free()
+                * or ep_remove(), ep_remove_wait_queue() takes whead->lock
+                * held by the caller. Once we nullify it, nothing protects
+                * ep/epi or even wait.
+                */
+               smp_mb();
+               ACCESS_ONCE(ep_pwq_from_wait(wait)->whead) = NULL;
+       }
+
        return 1;
 }
 
index e38a9b6..5106714 100644 (file)
@@ -174,11 +174,8 @@ ext2_get_acl(struct inode *inode, int type)
        return acl;
 }
 
-/*
- * inode->i_mutex: down
- */
 static int
-ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+__ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
        int name_index;
        void *value = NULL;
@@ -193,13 +190,6 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        switch(type) {
                case ACL_TYPE_ACCESS:
                        name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
-                       if (acl) {
-                               error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
-                               if (error)
-                                       return error;
-                               inode->i_ctime = CURRENT_TIME_SEC;
-                               mark_inode_dirty(inode);
-                       }
                        break;
 
                case ACL_TYPE_DEFAULT:
@@ -225,6 +215,31 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
        return error;
 }
 
+/*
+ * inode->i_mutex: down
+ */
+static int
+ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+       int error;
+       int update_mode = 0;
+       umode_t mode = inode->i_mode;
+
+       if (type == ACL_TYPE_ACCESS && acl) {
+               error = posix_acl_update_mode(inode, &mode, &acl);
+               if (error)
+                       return error;
+               update_mode = 1;
+       }
+       error = __ext2_set_acl(inode, acl, type);
+       if (!error && update_mode) {
+               inode->i_mode = mode;
+               inode->i_ctime = CURRENT_TIME_SEC;
+               mark_inode_dirty(inode);
+       }
+       return error;
+}
+
 /*
  * Initialize the ACLs of a new inode. Called from ext2_new_inode.
  *
@@ -248,7 +263,7 @@ ext2_init_acl(struct inode *inode, struct inode *dir)
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
                if (S_ISDIR(inode->i_mode)) {
-                       error = ext2_set_acl(inode, ACL_TYPE_DEFAULT, acl);
+                       error = __ext2_set_acl(inode, acl, ACL_TYPE_DEFAULT);
                        if (error)
                                goto cleanup;
                }
@@ -257,7 +272,7 @@ ext2_init_acl(struct inode *inode, struct inode *dir)
                        return error;
                if (error > 0) {
                        /* This is an extended ACL */
-                       error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl);
+                       error = __ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
                }
        }
 cleanup:
@@ -295,7 +310,7 @@ ext2_acl_chmod(struct inode *inode)
        error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
        if (error)
                return error;
-       error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl);
+       error = ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
        posix_acl_release(acl);
        return error;
 }
@@ -378,7 +393,7 @@ ext2_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
        } else
                acl = NULL;
 
-       error = ext2_set_acl(dentry->d_inode, type, acl);
+       error = ext2_set_acl(dentry->d_inode, acl, type);
 
 release_and_out:
        posix_acl_release(acl);
index 880d3d6..c84a8f6 100644 (file)
@@ -178,14 +178,9 @@ ext3_get_acl(struct inode *inode, int type)
        return acl;
 }
 
-/*
- * Set the access or default ACL of an inode.
- *
- * inode->i_mutex: down unless called from ext3_new_inode
- */
 static int
-ext3_set_acl(handle_t *handle, struct inode *inode, int type,
-            struct posix_acl *acl)
+__ext3_set_acl(handle_t *handle, struct inode *inode, int type,
+              struct posix_acl *acl)
 {
        int name_index;
        void *value = NULL;
@@ -198,13 +193,6 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
        switch(type) {
                case ACL_TYPE_ACCESS:
                        name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
-                       if (acl) {
-                               error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
-                               if (error)
-                                       return error;
-                               inode->i_ctime = CURRENT_TIME_SEC;
-                               ext3_mark_inode_dirty(handle, inode);
-                       }
                        break;
 
                case ACL_TYPE_DEFAULT:
@@ -233,6 +221,34 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
        return error;
 }
 
+/*
+ * Set the access or default ACL of an inode.
+ *
+ * inode->i_mutex: down
+ */
+static int
+ext3_set_acl(handle_t *handle, struct inode *inode, int type,
+            struct posix_acl *acl)
+{
+       int error;
+       int update_mode = 0;
+       umode_t mode = inode->i_mode;
+
+       if (type == ACL_TYPE_ACCESS && acl) {
+               error = posix_acl_update_mode(inode, &mode, &acl);
+               if (error)
+                       return error;
+               update_mode = 1;
+       }
+       error = __ext3_set_acl(handle, inode, type, acl);
+       if (!error && update_mode) {
+               inode->i_mode = mode;
+               inode->i_ctime = CURRENT_TIME_SEC;
+               ext3_mark_inode_dirty(handle, inode);
+       }
+       return error;
+}
+
 /*
  * Initialize the ACLs of a new inode. Called from ext3_new_inode.
  *
@@ -256,8 +272,8 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
                if (S_ISDIR(inode->i_mode)) {
-                       error = ext3_set_acl(handle, inode,
-                                            ACL_TYPE_DEFAULT, acl);
+                       error = __ext3_set_acl(handle, inode,
+                                              ACL_TYPE_DEFAULT, acl);
                        if (error)
                                goto cleanup;
                }
@@ -267,7 +283,7 @@ ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
 
                if (error > 0) {
                        /* This is an extended ACL */
-                       error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
+                       error = __ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
                }
        }
 cleanup:
index 5d419a4..c36fa74 100644 (file)
@@ -183,8 +183,8 @@ ext4_get_acl(struct inode *inode, int type)
  * inode->i_mutex: down unless called from ext4_new_inode
  */
 static int
-ext4_set_acl(handle_t *handle, struct inode *inode, int type,
-            struct posix_acl *acl)
+__ext4_set_acl(handle_t *handle, struct inode *inode, int type,
+              struct posix_acl *acl)
 {
        int name_index;
        void *value = NULL;
@@ -197,13 +197,6 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
        switch (type) {
        case ACL_TYPE_ACCESS:
                name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
-               if (acl) {
-                       error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
-                       if (error)
-                               return error;
-                       inode->i_ctime = ext4_current_time(inode);
-                       ext4_mark_inode_dirty(handle, inode);
-               }
                break;
 
        case ACL_TYPE_DEFAULT:
@@ -225,8 +218,34 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
                                      value, size, 0);
 
        kfree(value);
-       if (!error)
+       if (!error) {
                set_cached_acl(inode, type, acl);
+       }
+
+       return error;
+}
+
+static int
+ext4_set_acl(handle_t *handle, struct inode *inode, int type,
+            struct posix_acl *acl)
+{
+       umode_t mode = inode->i_mode;
+       int update_mode = 0;
+       int error;
+
+       if ((type == ACL_TYPE_ACCESS) && acl) {
+               error = posix_acl_update_mode(inode, &mode, &acl);
+               if (error)
+                       return error;
+               update_mode = 1;
+       }
+
+       error = __ext4_set_acl(handle, inode, type, acl);
+       if (!error && update_mode) {
+               inode->i_mode = mode;
+               inode->i_ctime = ext4_current_time(inode);
+               ext4_mark_inode_dirty(handle, inode);
+       }
 
        return error;
 }
@@ -254,8 +273,8 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
        }
        if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
                if (S_ISDIR(inode->i_mode)) {
-                       error = ext4_set_acl(handle, inode,
-                                            ACL_TYPE_DEFAULT, acl);
+                       error = __ext4_set_acl(handle, inode,
+                                              ACL_TYPE_DEFAULT, acl);
                        if (error)
                                goto cleanup;
                }
@@ -265,7 +284,7 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
 
                if (error > 0) {
                        /* This is an extended ACL */
-                       error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
+                       error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
                }
        }
 cleanup:
index 2845a1f..91d325c 100644 (file)
@@ -278,8 +278,10 @@ static int ext4_valid_block_bitmap(struct super_block *sb,
                                        unsigned int block_group,
                                        struct buffer_head *bh)
 {
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
        ext4_grpblk_t offset;
        ext4_grpblk_t next_zero_bit;
+       ext4_grpblk_t max_bit = EXT4_CLUSTERS_PER_GROUP(sb);
        ext4_fsblk_t bitmap_blk;
        ext4_fsblk_t group_first_block;
 
@@ -297,24 +299,30 @@ static int ext4_valid_block_bitmap(struct super_block *sb,
        /* check whether block bitmap block number is set */
        bitmap_blk = ext4_block_bitmap(sb, desc);
        offset = bitmap_blk - group_first_block;
-       if (!ext4_test_bit(offset, bh->b_data))
+       if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit ||
+           !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
                /* bad block bitmap */
                goto err_out;
 
        /* check whether the inode bitmap block number is set */
        bitmap_blk = ext4_inode_bitmap(sb, desc);
        offset = bitmap_blk - group_first_block;
-       if (!ext4_test_bit(offset, bh->b_data))
+       if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit ||
+           !ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data))
                /* bad block bitmap */
                goto err_out;
 
        /* check whether the inode table block number is set */
        bitmap_blk = ext4_inode_table(sb, desc);
        offset = bitmap_blk - group_first_block;
+       if (offset < 0 || EXT4_B2C(sbi, offset) >= max_bit ||
+           EXT4_B2C(sbi, offset + sbi->s_itb_per_group) >= max_bit)
+               goto err_out;
        next_zero_bit = ext4_find_next_zero_bit(bh->b_data,
-                               offset + EXT4_SB(sb)->s_itb_per_group,
-                               offset);
-       if (next_zero_bit >= offset + EXT4_SB(sb)->s_itb_per_group)
+                       EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group),
+                       EXT4_B2C(sbi, offset));
+       if (next_zero_bit >=
+           EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group))
                /* good bitmap for inode tables */
                return 1;
 
@@ -337,6 +345,7 @@ struct buffer_head *
 ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
 {
        struct ext4_group_desc *desc;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct buffer_head *bh = NULL;
        ext4_fsblk_t bitmap_blk;
 
@@ -344,6 +353,12 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
        if (!desc)
                return NULL;
        bitmap_blk = ext4_block_bitmap(sb, desc);
+       if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
+           (bitmap_blk >= ext4_blocks_count(sbi->s_es))) {
+               ext4_error(sb, "Invalid block bitmap block %llu in "
+                          "block_group %u", bitmap_blk, block_group);
+               return NULL;
+       }
        bh = sb_getblk(sb, bitmap_blk);
        if (unlikely(!bh)) {
                ext4_error(sb, "Cannot read block bitmap - "
index 476caae..9603b79 100644 (file)
@@ -102,6 +102,7 @@ static struct buffer_head *
 ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
 {
        struct ext4_group_desc *desc;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct buffer_head *bh = NULL;
        ext4_fsblk_t bitmap_blk;
 
@@ -110,6 +111,12 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
                return NULL;
 
        bitmap_blk = ext4_inode_bitmap(sb, desc);
+       if ((bitmap_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
+           (bitmap_blk >= ext4_blocks_count(sbi->s_es))) {
+               ext4_error(sb, "Invalid inode bitmap blk %llu in "
+                          "block_group %u", bitmap_blk, block_group);
+               return NULL;
+       }
        bh = sb_getblk(sb, bitmap_blk);
        if (unlikely(!bh)) {
                ext4_error(sb, "Cannot read inode bitmap - "
index fde77a7..af268ba 100644 (file)
@@ -3902,6 +3902,13 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        if (ret < 0)
                goto bad_inode;
        raw_inode = ext4_raw_inode(&iloc);
+
+       if ((ino == EXT4_ROOT_INO) && (raw_inode->i_links_count == 0)) {
+               EXT4_ERROR_INODE(inode, "root inode unallocated");
+               ret = -EIO;
+               goto bad_inode;
+       }
+
        inode->i_mode = le16_to_cpu(raw_inode->i_mode);
        inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
        inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
index ede3a33..6047b7f 100644 (file)
@@ -892,6 +892,10 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
                               "falling back\n"));
        }
        nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb);
+       if (!nblocks) {
+               ret = NULL;
+               goto cleanup_and_exit;
+       }
        start = EXT4_I(dir)->i_dir_start_lookup;
        if (start >= nblocks)
                start = 0;
index 72a75f8..1afb99d 100644 (file)
@@ -700,6 +700,7 @@ __acquires(bitlock)
        }
 
        ext4_unlock_group(sb, grp);
+       ext4_commit_super(sb, 1);
        ext4_handle_error(sb);
        /*
         * We only get here in the ERRORS_RO case; relocking the group
@@ -3692,6 +3693,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                        (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb)));
        db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
                   EXT4_DESC_PER_BLOCK(sb);
+       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG)) {
+               if (le32_to_cpu(es->s_first_meta_bg) > db_count) {
+                       ext4_msg(sb, KERN_WARNING,
+                                "first meta block group too large: %u "
+                                "(group descriptor block count %u)",
+                                le32_to_cpu(es->s_first_meta_bg), db_count);
+                       goto failed_mount;
+               }
+       }
        sbi->s_group_desc = ext4_kvmalloc(db_count *
                                          sizeof(struct buffer_head *),
                                          GFP_KERNEL);
index e69774e..d90a20b 100644 (file)
@@ -570,10 +570,21 @@ static void send_sigio_to_task(struct task_struct *p,
                        si.si_signo = signum;
                        si.si_errno = 0;
                        si.si_code  = reason;
+                       /*
+                        * Posix definies POLL_IN and friends to be signal
+                        * specific si_codes for SIG_POLL.  Linux extended
+                        * these si_codes to other signals in a way that is
+                        * ambiguous if other signals also have signal
+                        * specific si_codes.  In that case use SI_SIGIO instead
+                        * to remove the ambiguity.
+                        */
+                       if (sig_specific_sicodes(signum))
+                               si.si_code = SI_SIGIO;
+
                        /* Make sure we are called with one of the POLL_*
                           reasons, otherwise we could leak kernel stack into
                           userspace.  */
-                       BUG_ON((reason & __SI_MASK) != __SI_POLL);
+                       BUG_ON((reason < POLL_IN) || ((reason - POLL_IN) >= NSIGPOLL));
                        if (reason - POLL_IN >= NSIGPOLL)
                                si.si_band  = ~0L;
                        else
index ebe29c5..53d7fd3 100644 (file)
@@ -338,6 +338,13 @@ static void fscache_objlist_config(struct fscache_objlist_data *data)
        rcu_read_lock();
 
        confkey = key->payload.data;
+       if (!confkey) {
+               /* key was revoked */
+               rcu_read_unlock();
+               key_put(key);
+               goto no_config;
+       }
+
        buf = confkey->data;
 
        for (len = confkey->datalen - 1; len >= 0; len--) {
index 3426521..406352c 100644 (file)
@@ -267,7 +267,7 @@ static int cuse_parse_one(char **pp, char *end, char **keyp, char **valp)
 static int cuse_parse_devinfo(char *p, size_t len, struct cuse_devinfo *devinfo)
 {
        char *end = p + len;
-       char *key, *val;
+       char *uninitialized_var(key), *uninitialized_var(val);
        int rc;
 
        while (true) {
index 1f78f91..7be4719 100644 (file)
@@ -52,7 +52,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
 {
        struct fuse_file *ff;
 
-       ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
+       ff = kzalloc(sizeof(struct fuse_file), GFP_KERNEL);
        if (unlikely(!ff))
                return NULL;
 
index 99c51d6..906bcbd 100644 (file)
@@ -76,6 +76,16 @@ static void huge_pagevec_release(struct pagevec *pvec)
        pagevec_reinit(pvec);
 }
 
+/*
+ * Mask used when checking the page offset value passed in via system
+ * calls.  This value will be converted to a loff_t which is signed.
+ * Therefore, we want to check the upper PAGE_SHIFT + 1 bits of the
+ * value.  The extra bit (- 1 in the shift value) is to take the sign
+ * bit into account.
+ */
+#define PGOFF_LOFFT_MAX \
+       (((1UL << (PAGE_SHIFT + 1)) - 1) <<  (BITS_PER_LONG - (PAGE_SHIFT + 1)))
+
 static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct inode *inode = file->f_path.dentry->d_inode;
@@ -94,17 +104,27 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
        vma->vm_flags |= VM_HUGETLB | VM_RESERVED;
        vma->vm_ops = &hugetlb_vm_ops;
 
+       /*
+        * page based offset in vm_pgoff could be sufficiently large to
+        * overflow a (l)off_t when converted to byte offset.
+        */
+       if (vma->vm_pgoff & PGOFF_LOFFT_MAX)
+               return -EINVAL;
+
+       /* must be huge page aligned */
        if (vma->vm_pgoff & (~huge_page_mask(h) >> PAGE_SHIFT))
                return -EINVAL;
 
        vma_len = (loff_t)(vma->vm_end - vma->vm_start);
+       len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
+       /* check for overflow */
+       if (len < vma_len)
+               return -EINVAL;
 
        mutex_lock(&inode->i_mutex);
        file_accessed(file);
 
        ret = -ENOMEM;
-       len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
-
        if (hugetlb_reserve_pages(inode,
                                vma->vm_pgoff >> huge_page_order(h),
                                len >> huge_page_shift(h), vma,
@@ -114,7 +134,7 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
        ret = 0;
        hugetlb_prefault_arch_hook(vma->vm_mm);
        if (vma->vm_flags & VM_WRITE && inode->i_size < len)
-               inode->i_size = len;
+               i_size_write(inode, len);
 out:
        mutex_unlock(&inode->i_mutex);
 
index f9c9793..2c696a6 100644 (file)
@@ -103,7 +103,7 @@ static inline unsigned int isonum_733(char *p)
        /* Ignore bigendian datum due to broken mastering programs */
        return get_unaligned_le32(p);
 }
-extern int iso_date(char *, int);
+extern int iso_date(u8 *, int);
 
 struct inode;          /* To make gcc happy */
 
index ed09e2b..f835976 100644 (file)
@@ -65,7 +65,7 @@ struct RR_PL_s {
 };
 
 struct stamp {
-       char time[7];
+       __u8 time[7];           /* actually 6 unsigned, 1 signed */
 } __attribute__ ((packed));
 
 struct RR_TF_s {
index 01e1ee7..5cdf535 100644 (file)
@@ -14,7 +14,7 @@
  * to GMT.  Thus  we should always be correct.
  */
 
-int iso_date(char * p, int flag)
+int iso_date(u8 *p, int flag)
 {
        int year, month, day, hour, minute, second, tz;
        int crtime, days, i;
index 73652b2..05f4ae6 100644 (file)
@@ -352,7 +352,6 @@ error_io:
        ret = -EIO;
 error:
        mutex_unlock(&f->sem);
-       jffs2_do_clear_inode(c, f);
        iget_failed(inode);
        return ERR_PTR(ret);
 }
index 9af0125..4bcbe5e 100644 (file)
@@ -408,9 +408,10 @@ EXPORT_SYMBOL(path_put);
 static bool path_connected(const struct path *path)
 {
        struct vfsmount *mnt = path->mnt;
+       struct super_block *sb = mnt->mnt_sb;
 
-       /* Only bind mounts can have disconnected paths */
-       if (mnt->mnt_root == mnt->mnt_sb->s_root)
+       /* Bind mounts and multi-root filesystems can have disconnected paths */
+       if (!(sb->s_iflags & SB_I_MULTIROOT) && (mnt->mnt_root == sb->s_root))
                return true;
 
        return is_subdir(path->dentry, mnt->mnt_root);
index 981a956..76c6a8e 100644 (file)
@@ -982,6 +982,10 @@ ncp_read_kernel(struct ncp_server *server, const char *file_id,
                goto out;
        }
        *bytes_read = ncp_reply_be16(server, 0);
+       if (*bytes_read > to_read) {
+               result = -EINVAL;
+               goto out;
+       }
        source = ncp_reply_data(server, 2 + (offset & 1));
 
        memcpy(target, source, *bytes_read);
index d03a400..4ba011d 100644 (file)
@@ -1018,6 +1018,7 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve
        target->acdirmax = source->acdirmax;
        target->caps = source->caps;
        target->options = source->options;
+       target->port = source->port;
 }
 
 static void nfs_server_insert_lists(struct nfs_server *server)
index 8f509a0..0e7f45f 100644 (file)
@@ -151,15 +151,12 @@ const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
 };
 
 const u32 nfs4_fs_locations_bitmap[2] = {
-       FATTR4_WORD0_TYPE
-       | FATTR4_WORD0_CHANGE
+       FATTR4_WORD0_CHANGE
        | FATTR4_WORD0_SIZE
        | FATTR4_WORD0_FSID
        | FATTR4_WORD0_FILEID
        | FATTR4_WORD0_FS_LOCATIONS,
-       FATTR4_WORD1_MODE
-       | FATTR4_WORD1_NUMLINKS
-       | FATTR4_WORD1_OWNER
+       FATTR4_WORD1_OWNER
        | FATTR4_WORD1_OWNER_GROUP
        | FATTR4_WORD1_RAWDEV
        | FATTR4_WORD1_SPACE_USED
@@ -4805,9 +4802,7 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
                struct nfs4_fs_locations *fs_locations, struct page *page)
 {
        struct nfs_server *server = NFS_SERVER(dir);
-       u32 bitmask[2] = {
-               [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
-       };
+       u32 bitmask[2];
        struct nfs4_fs_locations_arg args = {
                .dir_fh = NFS_FH(dir),
                .name = name,
@@ -4826,12 +4821,15 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
 
        dprintk("%s: start\n", __func__);
 
+       bitmask[0] = nfs4_fattr_bitmap[0] | FATTR4_WORD0_FS_LOCATIONS;
+       bitmask[1] = nfs4_fattr_bitmap[1];
+
        /* Ask for the fileid of the absent filesystem if mounted_on_fileid
         * is not supported */
        if (NFS_SERVER(dir)->attr_bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
-               bitmask[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
+               bitmask[0] &= ~FATTR4_WORD0_FILEID;
        else
-               bitmask[0] |= FATTR4_WORD0_FILEID;
+               bitmask[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
 
        nfs_fattr_init(&fs_locations->fattr);
        fs_locations->server = server;
index 1943898..ba41561 100644 (file)
@@ -2288,6 +2288,8 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
                /* initial superblock/root creation */
                nfs_fill_super(s, data);
                nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL);
+               if (!(server->flags & NFS_MOUNT_UNSHARED))
+                       s->s_iflags |= SB_I_MULTIROOT;
        }
 
        mntroot = nfs_get_root(s, mntfh, dev_name);
index 79717a4..3d3f14c 100644 (file)
@@ -61,6 +61,9 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
                        else
                                GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
                }
+
+               /* Each thread allocates its own gi, no race */
+               groups_sort(gi);
        } else {
                gi = get_group_info(rqgi);
        }
index 090d8ce..250db08 100644 (file)
@@ -1797,7 +1797,7 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *btree,
                                   __u64 key, __u64 ptr,
                                   const __u64 *keys, const __u64 *ptrs, int n)
 {
-       struct buffer_head *bh;
+       struct buffer_head *bh = NULL;
        union nilfs_bmap_ptr_req dreq, nreq, *di, *ni;
        struct nilfs_bmap_stats stats;
        int ret;
index a604ac0..7fe6773 100644 (file)
@@ -581,7 +581,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
                                 struct nilfs_recovery_info *ri)
 {
        struct buffer_head *bh_sum = NULL;
-       struct nilfs_segment_summary *sum;
+       struct nilfs_segment_summary *sum = NULL;
        sector_t pseg_start;
        sector_t seg_start, seg_end;  /* Starting/ending DBN of full segment */
        unsigned long nsalvaged_blocks = 0;
@@ -813,7 +813,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs,
                            struct nilfs_recovery_info *ri)
 {
        struct buffer_head *bh_sum = NULL;
-       struct nilfs_segment_summary *sum;
+       struct nilfs_segment_summary *sum = NULL;
        sector_t pseg_start, pseg_end, sr_pseg_start = 0;
        sector_t seg_start, seg_end; /* range of full segment (block number) */
        sector_t b, end;
index 6bba106..3f7c5df 100644 (file)
@@ -1880,8 +1880,6 @@ static int nilfs_segctor_collect_dirty_files(struct nilfs_sc_info *sci,
                                              "failed to get inode block.\n");
                                return err;
                        }
-                       mark_buffer_dirty(ibh);
-                       nilfs_mdt_mark_dirty(ifile);
                        spin_lock(&nilfs->ns_inode_lock);
                        if (likely(!ii->i_bh))
                                ii->i_bh = ibh;
@@ -1890,6 +1888,10 @@ static int nilfs_segctor_collect_dirty_files(struct nilfs_sc_info *sci,
                        goto retry;
                }
 
+               // Always redirty the buffer to avoid race condition
+               mark_buffer_dirty(ii->i_bh);
+               nilfs_mdt_mark_dirty(ifile);
+
                clear_bit(NILFS_I_QUEUED, &ii->i_state);
                set_bit(NILFS_I_BUSY, &ii->i_state);
                list_move_tail(&ii->i_dirty, &sci->sc_dirty_files);
index 97bfbdd..8715fbc 100644 (file)
@@ -360,7 +360,7 @@ static int nilfs_move_2nd_super(struct super_block *sb, loff_t sb2off)
        struct nilfs_super_block *nsbp;
        sector_t blocknr, newblocknr;
        unsigned long offset;
-       int sb2i = -1;  /* array index of the secondary superblock */
+       int sb2i;  /* array index of the secondary superblock */
        int ret = 0;
 
        /* nilfs->ns_sem must be locked by the caller. */
@@ -371,6 +371,9 @@ static int nilfs_move_2nd_super(struct super_block *sb, loff_t sb2off)
        } else if (nilfs->ns_sbh[0]->b_blocknr > nilfs->ns_first_data_block) {
                sb2i = 0;
                blocknr = nilfs->ns_sbh[0]->b_blocknr;
+       } else {
+               sb2i = -1;
+               blocknr = 0;
        }
        if (sb2i >= 0 && (u64)blocknr << nilfs->ns_blocksize_bits == sb2off)
                goto out;  /* super block location is unchanged */
index 7e6e1f8..06a5027 100644 (file)
@@ -246,19 +246,6 @@ static int ocfs2_set_acl(handle_t *handle,
        switch (type) {
        case ACL_TYPE_ACCESS:
                name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
-               if (acl) {
-                       umode_t mode;
-                       ret = posix_acl_update_mode(inode, &mode, &acl);
-                       if (ret)
-                               return ret;
-                       else {
-                               ret = ocfs2_acl_set_mode(inode, di_bh,
-                                                        handle, mode);
-                               if (ret)
-                                       return ret;
-
-                       }
-               }
                break;
        case ACL_TYPE_DEFAULT:
                name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
@@ -483,6 +470,17 @@ static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name,
        } else
                acl = NULL;
 
+       if (type == ACL_TYPE_ACCESS && acl) {
+               umode_t mode;
+
+               ret = posix_acl_update_mode(inode, &mode, &acl);
+               if (ret)
+                       goto cleanup;
+
+               ret = ocfs2_acl_set_mode(inode, NULL, NULL, mode);
+               if (ret)
+                       goto cleanup;
+       }
        ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL);
 
 cleanup:
index 31b9463..88614cd 100644 (file)
@@ -7127,7 +7127,7 @@ int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
        if (end > i_size_read(inode))
                end = i_size_read(inode);
 
-       BUG_ON(start >= end);
+       BUG_ON(start > end);
 
        if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) ||
            !(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) ||
@@ -7188,13 +7188,24 @@ out:
 
 static int ocfs2_trim_extent(struct super_block *sb,
                             struct ocfs2_group_desc *gd,
-                            u32 start, u32 count)
+                            u64 group, u32 start, u32 count)
 {
        u64 discard, bcount;
+       struct ocfs2_super *osb = OCFS2_SB(sb);
 
        bcount = ocfs2_clusters_to_blocks(sb, count);
-       discard = le64_to_cpu(gd->bg_blkno) +
-                       ocfs2_clusters_to_blocks(sb, start);
+       discard = ocfs2_clusters_to_blocks(sb, start);
+
+       /*
+        * For the first cluster group, the gd->bg_blkno is not at the start
+        * of the group, but at an offset from the start. If we add it while
+        * calculating discard for first group, we will wrongly start fstrim a
+        * few blocks after the desried start block and the range can cross
+        * over into the next cluster group. So, add it only if this is not
+        * the first cluster group.
+        */
+       if (group != osb->first_cluster_group_blkno)
+               discard += le64_to_cpu(gd->bg_blkno);
 
        trace_ocfs2_trim_extent(sb, (unsigned long long)discard, bcount);
 
@@ -7202,7 +7213,7 @@ static int ocfs2_trim_extent(struct super_block *sb,
 }
 
 static int ocfs2_trim_group(struct super_block *sb,
-                           struct ocfs2_group_desc *gd,
+                           struct ocfs2_group_desc *gd, u64 group,
                            u32 start, u32 max, u32 minbits)
 {
        int ret = 0, count = 0, next;
@@ -7221,7 +7232,7 @@ static int ocfs2_trim_group(struct super_block *sb,
                next = ocfs2_find_next_bit(bitmap, max, start);
 
                if ((next - start) >= minbits) {
-                       ret = ocfs2_trim_extent(sb, gd,
+                       ret = ocfs2_trim_extent(sb, gd, group,
                                                start, next - start);
                        if (ret < 0) {
                                mlog_errno(ret);
@@ -7323,7 +7334,8 @@ int ocfs2_trim_fs(struct super_block *sb, struct fstrim_range *range)
                }
 
                gd = (struct ocfs2_group_desc *)gd_bh->b_data;
-               cnt = ocfs2_trim_group(sb, gd, first_bit, last_bit, minlen);
+               cnt = ocfs2_trim_group(sb, gd, group,
+                                      first_bit, last_bit, minlen);
                brelse(gd_bh);
                gd_bh = NULL;
                if (cnt < 0) {
index bb24064..c76302a 100644 (file)
@@ -41,6 +41,9 @@ char *o2nm_fence_method_desc[O2NM_FENCE_METHODS] = {
                "panic",        /* O2NM_FENCE_PANIC */
 };
 
+static inline void o2nm_lock_subsystem(void);
+static inline void o2nm_unlock_subsystem(void);
+
 struct o2nm_node *o2nm_get_node_by_num(u8 node_num)
 {
        struct o2nm_node *node = NULL;
@@ -182,7 +185,10 @@ static struct o2nm_cluster *to_o2nm_cluster_from_node(struct o2nm_node *node)
 {
        /* through the first node_set .parent
         * mycluster/nodes/mynode == o2nm_cluster->o2nm_node_group->o2nm_node */
-       return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent);
+       if (node->nd_item.ci_parent)
+               return to_o2nm_cluster(node->nd_item.ci_parent->ci_parent);
+       else
+               return NULL;
 }
 
 enum {
@@ -195,7 +201,7 @@ enum {
 static ssize_t o2nm_node_num_write(struct o2nm_node *node, const char *page,
                                   size_t count)
 {
-       struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
+       struct o2nm_cluster *cluster;
        unsigned long tmp;
        char *p = (char *)page;
 
@@ -214,6 +220,13 @@ static ssize_t o2nm_node_num_write(struct o2nm_node *node, const char *page,
            !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
                return -EINVAL; /* XXX */
 
+       o2nm_lock_subsystem();
+       cluster = to_o2nm_cluster_from_node(node);
+       if (!cluster) {
+               o2nm_unlock_subsystem();
+               return -EINVAL;
+       }
+
        write_lock(&cluster->cl_nodes_lock);
        if (cluster->cl_nodes[tmp])
                p = NULL;
@@ -223,6 +236,8 @@ static ssize_t o2nm_node_num_write(struct o2nm_node *node, const char *page,
                set_bit(tmp, cluster->cl_nodes_bitmap);
        }
        write_unlock(&cluster->cl_nodes_lock);
+       o2nm_unlock_subsystem();
+
        if (p == NULL)
                return -EEXIST;
 
@@ -262,7 +277,7 @@ static ssize_t o2nm_node_ipv4_address_write(struct o2nm_node *node,
                                            const char *page,
                                            size_t count)
 {
-       struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
+       struct o2nm_cluster *cluster;
        int ret, i;
        struct rb_node **p, *parent;
        unsigned int octets[4];
@@ -279,6 +294,13 @@ static ssize_t o2nm_node_ipv4_address_write(struct o2nm_node *node,
                be32_add_cpu(&ipv4_addr, octets[i] << (i * 8));
        }
 
+       o2nm_lock_subsystem();
+       cluster = to_o2nm_cluster_from_node(node);
+       if (!cluster) {
+               o2nm_unlock_subsystem();
+               return -EINVAL;
+       }
+
        ret = 0;
        write_lock(&cluster->cl_nodes_lock);
        if (o2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent))
@@ -288,6 +310,8 @@ static ssize_t o2nm_node_ipv4_address_write(struct o2nm_node *node,
                rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree);
        }
        write_unlock(&cluster->cl_nodes_lock);
+       o2nm_unlock_subsystem();
+
        if (ret)
                return ret;
 
@@ -304,7 +328,7 @@ static ssize_t o2nm_node_local_read(struct o2nm_node *node, char *page)
 static ssize_t o2nm_node_local_write(struct o2nm_node *node, const char *page,
                                     size_t count)
 {
-       struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
+       struct o2nm_cluster *cluster;
        unsigned long tmp;
        char *p = (char *)page;
        ssize_t ret;
@@ -322,17 +346,26 @@ static ssize_t o2nm_node_local_write(struct o2nm_node *node, const char *page,
            !test_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
                return -EINVAL; /* XXX */
 
+       o2nm_lock_subsystem();
+       cluster = to_o2nm_cluster_from_node(node);
+       if (!cluster) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        /* the only failure case is trying to set a new local node
         * when a different one is already set */
        if (tmp && tmp == cluster->cl_has_local &&
-           cluster->cl_local_node != node->nd_num)
-               return -EBUSY;
+           cluster->cl_local_node != node->nd_num) {
+               ret = -EBUSY;
+               goto out;
+       }
 
        /* bring up the rx thread if we're setting the new local node. */
        if (tmp && !cluster->cl_has_local) {
                ret = o2net_start_listening(node);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
        if (!tmp && cluster->cl_has_local &&
@@ -347,7 +380,11 @@ static ssize_t o2nm_node_local_write(struct o2nm_node *node, const char *page,
                cluster->cl_local_node = node->nd_num;
        }
 
-       return count;
+       ret = count;
+
+out:
+       o2nm_unlock_subsystem();
+       return ret;
 }
 
 struct o2nm_node_attribute {
@@ -890,6 +927,16 @@ static struct o2nm_cluster_group o2nm_cluster_group = {
        },
 };
 
+static inline void o2nm_lock_subsystem(void)
+{
+       mutex_lock(&o2nm_cluster_group.cs_subsys.su_mutex);
+}
+
+static inline void o2nm_unlock_subsystem(void)
+{
+       mutex_unlock(&o2nm_cluster_group.cs_subsys.su_mutex);
+}
+
 int o2nm_depend_item(struct config_item *item)
 {
        return configfs_depend_item(&o2nm_cluster_group.cs_subsys, item);
index a678e22..a22b5c9 100644 (file)
@@ -474,11 +474,6 @@ static int ocfs2_truncate_file(struct inode *inode,
                goto bail;
        }
 
-       /* lets handle the simple truncate cases before doing any more
-        * cluster locking. */
-       if (new_i_size == le64_to_cpu(fe->i_size))
-               goto bail;
-
        down_write(&OCFS2_I(inode)->ip_alloc_sem);
 
        ocfs2_resv_discard(&osb->osb_la_resmap,
@@ -1149,14 +1144,14 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
                goto bail_unlock_rw;
        }
 
-       if (size_change && attr->ia_size != i_size_read(inode)) {
+       if (size_change) {
                status = inode_newsize_ok(inode, attr->ia_size);
                if (status)
                        goto bail_unlock;
 
                inode_dio_wait(inode);
 
-               if (i_size_read(inode) > attr->ia_size) {
+               if (i_size_read(inode) >= attr->ia_size) {
                        if (ocfs2_should_order_data(inode)) {
                                status = ocfs2_begin_ordered_truncate(inode,
                                                                      attr->ia_size);
index 5ad4248..3649bfd 100644 (file)
@@ -99,7 +99,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int origin,
                 * In the generic case the entire file is data, so as long as
                 * offset isn't at the end of the file then the offset is data.
                 */
-               if (offset >= i_size_read(inode))
+               if ((unsigned long long)offset >= i_size_read(inode))
                        return -ENXIO;
                break;
        case SEEK_HOLE:
@@ -107,7 +107,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int origin,
                 * There is a virtual hole at the end of the file, so as long as
                 * offset isn't i_size or larger, return i_size.
                 */
-               if (offset >= i_size_read(inode))
+               if ((unsigned long long)offset >= i_size_read(inode))
                        return -ENXIO;
                offset = i_size_read(inode);
                break;
index 1d4f4c7..81b8c07 100644 (file)
@@ -250,15 +250,9 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
        return acl;
 }
 
-/*
- * Inode operation set_posix_acl().
- *
- * inode->i_mutex: down
- * BKL held [before 2.5.x]
- */
 static int
-reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
-                int type, struct posix_acl *acl)
+__reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
+                  int type, struct posix_acl *acl)
 {
        char *name;
        void *value = NULL;
@@ -271,11 +265,6 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
        switch (type) {
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
-               if (acl) {
-                       error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
-                       if (error)
-                               return error;
-               }
                break;
        case ACL_TYPE_DEFAULT:
                name = POSIX_ACL_XATTR_DEFAULT;
@@ -316,6 +305,31 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
        return error;
 }
 
+/*
+ * Inode operation set_posix_acl().
+ *
+ * inode->i_mutex: down
+ */
+static int
+reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
+                int type, struct posix_acl *acl)
+{
+       int error;
+       int update_mode = 0;
+       umode_t mode = inode->i_mode;
+
+       if (type == ACL_TYPE_ACCESS && acl) {
+               error = posix_acl_update_mode(inode, &mode, &acl);
+               if (error)
+                       return error;
+               update_mode = 1;
+       }
+       error = __reiserfs_set_acl(th, inode, type, acl);
+       if (!error && update_mode)
+               inode->i_mode = mode;
+       return error;
+}
+
 /* dir->i_mutex: locked,
  * inode is new and not released into the wild yet */
 int
@@ -350,8 +364,8 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
        if (acl) {
                /* Copy the default ACL to the default ACL of a new directory */
                if (S_ISDIR(inode->i_mode)) {
-                       err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
-                                              acl);
+                       err = __reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
+                                                acl);
                        if (err)
                                goto cleanup;
                }
@@ -364,7 +378,7 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
 
                /* If we need an ACL.. */
                if (err > 0)
-                       err = reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, acl);
+                       err = __reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, acl);
              cleanup:
                posix_acl_release(acl);
        } else {
index 12c0f15..c5505fa 100644 (file)
@@ -573,7 +573,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
        aligned_dlen = ALIGN(dlen, 8);
        aligned_ilen = ALIGN(ilen, 8);
        len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ;
-       dent = kmalloc(len, GFP_NOFS);
+       dent = kzalloc(len, GFP_NOFS);
        if (!dent)
                return -ENOMEM;
 
@@ -958,7 +958,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
        len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8);
        if (old_dir != new_dir)
                len += plen;
-       dent = kmalloc(len, GFP_NOFS);
+       dent = kzalloc(len, GFP_NOFS);
        if (!dent)
                return -ENOMEM;
 
@@ -1305,7 +1305,7 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
        hlen = host_ui->data_len + UBIFS_INO_NODE_SZ;
        len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8);
 
-       xent = kmalloc(len, GFP_NOFS);
+       xent = kzalloc(len, GFP_NOFS);
        if (!xent)
                return -ENOMEM;
 
@@ -1412,7 +1412,7 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
        aligned_len1 = ALIGN(len1, 8);
        aligned_len = aligned_len1 + ALIGN(len2, 8);
 
-       ino = kmalloc(aligned_len, GFP_NOFS);
+       ino = kzalloc(aligned_len, GFP_NOFS);
        if (!ino)
                return -ENOMEM;
 
index a4f7f00..33b7010 100644 (file)
@@ -2728,6 +2728,10 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
                dbg_tnc("xent '%s', ino %lu", xent->name,
                        (unsigned long)xattr_inum);
 
+#ifdef CONFIG_UBIFS_FS_XATTR
+               ubifs_evict_xattr_inode(c, xattr_inum);
+#endif
+
                nm.name = xent->name;
                nm.len = le16_to_cpu(xent->nlen);
                err = ubifs_tnc_remove_nm(c, &key1, &nm);
index 3ef953e..74fdcb8 100644 (file)
@@ -1740,6 +1740,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
                       size_t size);
 ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 int ubifs_removexattr(struct dentry *dentry, const char *name);
+void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum);
 
 /* super.c */
 struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
index 166ff21..682ab08 100644 (file)
@@ -481,6 +481,28 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
        return written;
 }
 
+/**
+ * ubifs_evict_xattr_inode - Evict an xattr inode.
+ * @c: UBIFS file-system description object
+ * @xattr_inum: xattr inode number
+ *
+ * When an inode that hosts xattrs is being removed we have to make sure
+ * that cached inodes of the xattrs also get removed from the inode cache
+ * otherwise we'd waste memory. This function looks up an inode from the
+ * inode cache and clears the link counter such that iput() will evict
+ * the inode.
+ */
+void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum)
+{
+       struct inode *inode;
+
+       inode = ilookup(c->vfs_sb, xattr_inum);
+       if (inode) {
+               clear_nlink(inode);
+               iput(inode);
+       }
+}
+
 static int remove_xattr(struct ubifs_info *c, struct inode *host,
                        struct inode *inode, const struct qstr *nm)
 {
index 26f9b52..905bbe1 100644 (file)
@@ -44,10 +44,15 @@ static void __udf_adinicb_readpage(struct page *page)
        struct inode *inode = page->mapping->host;
        char *kaddr;
        struct udf_inode_info *iinfo = UDF_I(inode);
+       loff_t isize = i_size_read(inode);
 
+       /*
+        * We have to be careful here as truncate can change i_size under us.
+        * So just sample it once and use the same value everywhere.
+        */
        kaddr = kmap(page);
-       memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, inode->i_size);
-       memset(kaddr + inode->i_size, 0, PAGE_CACHE_SIZE - inode->i_size);
+       memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, isize);
+       memset(kaddr + isize, 0, PAGE_CACHE_SIZE - isize);
        flush_dcache_page(page);
        SetPageUptodate(page);
        kunmap(page);
index 5d67e20..68de1c7 100644 (file)
@@ -1145,8 +1145,8 @@ int udf_setsize(struct inode *inode, loff_t newsize)
                        up_write(&iinfo->i_data_sem);
                        return err;
                }
-               truncate_setsize(inode, newsize);
                up_write(&iinfo->i_data_sem);
+               truncate_setsize(inode, newsize);
        } else {
                if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
                        down_write(&iinfo->i_data_sem);
@@ -1162,8 +1162,8 @@ int udf_setsize(struct inode *inode, loff_t newsize)
                                          udf_get_block);
                if (err)
                        return err;
-               down_write(&iinfo->i_data_sem);
                truncate_setsize(inode, newsize);
+               down_write(&iinfo->i_data_sem);
                udf_truncate_extents(inode);
                up_write(&iinfo->i_data_sem);
        }
index 67583de..f91e3c1 100644 (file)
@@ -161,7 +161,7 @@ xattr_getsecurity(struct inode *inode, const char *name, void *value,
        }
        memcpy(value, buffer, len);
 out:
-       security_release_secctx(buffer, len);
+       kfree(buffer);
 out_noalloc:
        return len;
 }
index a372163..9a51bcf 100644 (file)
@@ -201,7 +201,14 @@ static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev)
 #define XFS_DIFLAG_FILESTREAM    (1 << XFS_DIFLAG_FILESTREAM_BIT)
 
 #ifdef CONFIG_XFS_RT
-#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME)
+
+/*
+ * make sure we ignore the inode flag if the filesystem doesn't have a
+ * configured realtime device.
+ */
+#define XFS_IS_REALTIME_INODE(ip)                      \
+       (((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) &&  \
+        (ip)->i_mount->m_rtdev_targp)
 #else
 #define XFS_IS_REALTIME_INODE(ip) (0)
 #endif
index 169380e..24675e3 100644 (file)
@@ -894,13 +894,13 @@ nextag:
 
                        /* free inodes to the left? */
                        if (useleft && trec.ir_freecount) {
-                               rec = trec;
                                xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
                                cur = tcur;
 
                                pag->pagl_leftrec = trec.ir_startino;
                                pag->pagl_rightrec = rec.ir_startino;
                                pag->pagl_pagino = pagino;
+                               rec = trec;
                                goto alloc_inode;
                        }
 
index 10ca5e5..4ec90ce 100644 (file)
@@ -3025,8 +3025,6 @@ maybe_sleep:
                 */
                if (iclog->ic_state & XLOG_STATE_IOERROR)
                        return XFS_ERROR(EIO);
-               if (log_flushed)
-                       *log_flushed = 1;
        } else {
 
 no_sleep:
@@ -3135,8 +3133,6 @@ try_again:
 
                                xlog_wait(&iclog->ic_prev->ic_write_wait,
                                                        &log->l_icloglock);
-                               if (log_flushed)
-                                       *log_flushed = 1;
                                already_slept = 1;
                                goto try_again;
                        }
@@ -3170,9 +3166,6 @@ try_again:
                         */
                        if (iclog->ic_state & XLOG_STATE_IOERROR)
                                return XFS_ERROR(EIO);
-
-                       if (log_flushed)
-                               *log_flushed = 1;
                } else {                /* just return */
                        spin_unlock(&log->l_icloglock);
                }
index ccf7b4f..12ec4b1 100644 (file)
@@ -69,9 +69,6 @@ dma_supported(struct device *dev, u64 mask);
 extern int
 dma_set_mask(struct device *dev, u64 mask);
 
-extern int
-dma_get_cache_alignment(void);
-
 extern void
 dma_cache_sync(struct device *dev, void *vaddr, size_t size,
               enum dma_data_direction direction);
index 0dd4e87..16c53c8 100644 (file)
@@ -148,7 +148,7 @@ typedef struct siginfo {
 #define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */
 #define SI_MESGQ __SI_CODE(__SI_MESGQ,-3) /* sent by real time mesq state change */
 #define SI_ASYNCIO     -4              /* sent by AIO completion */
-#define SI_SIGIO       -5              /* sent by queued SIGIO */
+#define SI_SIGIO __SI_CODE(__SI_POLL,-5) /* sent by queued SIGIO */
 #define SI_TKILL       -6              /* sent by tkill system call */
 #define SI_DETHREAD    -7              /* sent by execve() killing subsidiary threads */
 
@@ -221,7 +221,7 @@ typedef struct siginfo {
 #define NSIGCHLD       6
 
 /*
- * SIGPOLL si_codes
+ * SIGPOLL (or any other signal without signal specific si_codes) si_codes
  */
 #define POLL_IN                (__SI_POLL|1)   /* data input available */
 #define POLL_OUT       (__SI_POLL|2)   /* output buffers available */
index fc824e2..5d2add1 100644 (file)
 #define parent_node(node)      ((void)(node),0)
 #endif
 #ifndef cpumask_of_node
-#define cpumask_of_node(node)  ((void)node, cpu_online_mask)
+  #ifdef CONFIG_NEED_MULTIPLE_NODES
+    #define cpumask_of_node(node)      ((node) == 0 ? cpu_online_mask : cpu_none_mask)
+  #else
+    #define cpumask_of_node(node)      ((void)node, cpu_online_mask)
+  #endif
 #endif
 #ifndef pcibus_to_node
 #define pcibus_to_node(bus)    ((void)(bus), -1)
index b5e2e4c..01c8155 100644 (file)
  */
 #define PERCPU_INPUT(cacheline)                                                \
        VMLINUX_SYMBOL(__per_cpu_start) = .;                            \
+       VMLINUX_SYMBOL(__per_cpu_user_mapped_start) = .;                \
        *(.data..percpu..first)                                         \
+       . = ALIGN(cacheline);                                           \
+       *(.data..percpu..user_mapped)                                   \
+       *(.data..percpu..user_mapped..shared_aligned)                   \
+       . = ALIGN(PAGE_SIZE);                                           \
+       *(.data..percpu..user_mapped..page_aligned)                     \
+       VMLINUX_SYMBOL(__per_cpu_user_mapped_end) = .;                  \
        . = ALIGN(PAGE_SIZE);                                           \
        *(.data..percpu..page_aligned)                                  \
        . = ALIGN(cacheline);                                           \
index c8c7987..9fa0f77 100644 (file)
@@ -94,7 +94,6 @@ struct crypto_ahash {
                      unsigned int keylen);
 
        unsigned int reqsize;
-       bool has_setkey;
        struct crypto_tfm base;
 };
 
@@ -182,11 +181,6 @@ static inline void *ahash_request_ctx(struct ahash_request *req)
 
 int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
                        unsigned int keylen);
-static inline bool crypto_ahash_has_setkey(struct crypto_ahash *tfm)
-{
-       return tfm->has_setkey;
-}
-
 int crypto_ahash_finup(struct ahash_request *req);
 int crypto_ahash_final(struct ahash_request *req);
 int crypto_ahash_digest(struct ahash_request *req);
@@ -198,12 +192,22 @@ static inline int crypto_ahash_export(struct ahash_request *req, void *out)
 
 static inline int crypto_ahash_import(struct ahash_request *req, const void *in)
 {
-       return crypto_ahash_reqtfm(req)->import(req, in);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+
+       if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+               return -ENOKEY;
+
+       return tfm->import(req, in);
 }
 
 static inline int crypto_ahash_init(struct ahash_request *req)
 {
-       return crypto_ahash_reqtfm(req)->init(req);
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+
+       if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+               return -ENOKEY;
+
+       return tfm->init(req);
 }
 
 static inline int crypto_ahash_update(struct ahash_request *req)
@@ -342,12 +346,22 @@ static inline int crypto_shash_export(struct shash_desc *desc, void *out)
 
 static inline int crypto_shash_import(struct shash_desc *desc, const void *in)
 {
-       return crypto_shash_alg(desc->tfm)->import(desc, in);
+       struct crypto_shash *tfm = desc->tfm;
+
+       if (crypto_shash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+               return -ENOKEY;
+
+       return crypto_shash_alg(tfm)->import(desc, in);
 }
 
 static inline int crypto_shash_init(struct shash_desc *desc)
 {
-       return crypto_shash_alg(desc->tfm)->init(desc);
+       struct crypto_shash *tfm = desc->tfm;
+
+       if (crypto_shash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
+               return -ENOKEY;
+
+       return crypto_shash_alg(tfm)->init(desc);
 }
 
 int crypto_shash_update(struct shash_desc *desc, const u8 *data,
index 7bdb812..df48747 100644 (file)
@@ -70,6 +70,16 @@ int ahash_register_instance(struct crypto_template *tmpl,
                            struct ahash_instance *inst);
 void ahash_free_instance(struct crypto_instance *inst);
 
+int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+                   unsigned int keylen);
+
+static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg)
+{
+       return alg->setkey != shash_no_setkey;
+}
+
+bool crypto_hash_alg_has_setkey(struct hash_alg_common *halg);
+
 int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
                            struct hash_alg_common *alg,
                            struct crypto_instance *inst);
index 87a375f..29c2dfa 100644 (file)
@@ -4,8 +4,11 @@
 
 #ifdef __KERNEL__
 #define BIT(nr)                        (1UL << (nr))
+#define BIT_ULL(nr)            (1ULL << (nr))
 #define BIT_MASK(nr)           (1UL << ((nr) % BITS_PER_LONG))
 #define BIT_WORD(nr)           ((nr) / BITS_PER_LONG)
+#define BIT_ULL_MASK(nr)       (1ULL << ((nr) % BITS_PER_LONG_LONG))
+#define BIT_ULL_WORD(nr)       ((nr) / BITS_PER_LONG_LONG)
 #define BITS_PER_BYTE          8
 #define BITS_TO_LONGS(nr)      DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
 #endif
index 664a07c..d682e7b 100644 (file)
@@ -361,6 +361,7 @@ struct request_queue {
        int                     node;
 #ifdef CONFIG_BLK_DEV_IO_TRACE
        struct blk_trace        *blk_trace;
+       struct mutex            blk_trace_mutex;
 #endif
        /*
         * for flush operations
index 21b1e97..4583d61 100644 (file)
@@ -36,6 +36,13 @@ extern void cpu_remove_sysdev_attr_group(struct attribute_group *attrs);
 
 extern int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls);
 
+ssize_t cpu_show_meltdown(struct sysdev_class *class,
+                         struct sysdev_class_attribute *attr, char *buf);
+ssize_t cpu_show_spectre_v1(struct sysdev_class *class,
+                           struct sysdev_class_attribute *attr, char *buf);
+ssize_t cpu_show_spectre_v2(struct sysdev_class *class,
+                           struct sysdev_class_attribute *attr, char *buf);
+
 #ifdef CONFIG_HOTPLUG_CPU
 extern void unregister_cpu(struct cpu *cpu);
 extern ssize_t arch_cpu_probe(const char *, size_t);
index 4f7a632..1b6ce8c 100644 (file)
@@ -216,6 +216,23 @@ int cpumask_any_but(const struct cpumask *mask, unsigned int cpu);
                (cpu) = cpumask_next_zero((cpu), (mask)),       \
                (cpu) < nr_cpu_ids;)
 
+extern int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap);
+
+/**
+ * for_each_cpu_wrap - iterate over every cpu in a mask, starting at a specified location
+ * @cpu: the (optionally unsigned) integer iterator
+ * @mask: the cpumask poiter
+ * @start: the start location
+ *
+ * The implementation does not assume any bit in @mask is set (including @start).
+ *
+ * After the loop, cpu is >= nr_cpu_ids.
+ */
+#define for_each_cpu_wrap(cpu, mask, start)                                    \
+       for ((cpu) = cpumask_next_wrap((start)-1, (mask), (start), false);      \
+            (cpu) < nr_cpumask_bits;                                           \
+            (cpu) = cpumask_next_wrap((cpu), (mask), (start), true))
+
 /**
  * for_each_cpu_and - iterate over every cpu in both masks
  * @cpu: the (optionally unsigned) integer iterator
index 7a7e5fd..1dc9427 100644 (file)
@@ -74,12 +74,12 @@ extern int cpuset_slab_spread_node(void);
 
 static inline int cpuset_do_page_mem_spread(void)
 {
-       return current->flags & PF_SPREAD_PAGE;
+       return task_spread_page(current);
 }
 
 static inline int cpuset_do_slab_mem_spread(void)
 {
-       return current->flags & PF_SPREAD_SLAB;
+       return task_spread_slab(current);
 }
 
 extern int current_cpuset_is_being_rebound(void);
index 4030896..c9900b3 100644 (file)
@@ -67,6 +67,7 @@ extern void groups_free(struct group_info *);
 extern int set_current_groups(struct group_info *);
 extern int set_groups(struct cred *, struct group_info *);
 extern int groups_search(const struct group_info *, gid_t);
+extern void groups_sort(struct group_info *);
 
 /* access the groups "array" with this macro */
 #define GROUP_AT(gi, i) \
index 6f501de..5c511ba 100644 (file)
  */
 #define CRYPTO_ALG_INSTANCE            0x00000800
 
+/*
+ * Set if the algorithm has a ->setkey() method but can be used without
+ * calling it first, i.e. there is a default key.
+ */
+#define CRYPTO_ALG_OPTIONAL_KEY                0x00004000
+
 /*
  * Transform masks and values (for crt_flags).
  */
+#define CRYPTO_TFM_NEED_KEY            0x00000001
+
 #define CRYPTO_TFM_REQ_MASK            0x000fff00
 #define CRYPTO_TFM_RES_MASK            0xfff00000
 
index 213a870..45bf2dd 100644 (file)
@@ -398,56 +398,32 @@ void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
  *---------------------------------------------------------------*/
 #define DM_NAME "device-mapper"
 
-#ifdef CONFIG_PRINTK
-extern struct ratelimit_state dm_ratelimit_state;
-
-#define dm_ratelimit() __ratelimit(&dm_ratelimit_state)
-#else
-#define dm_ratelimit() 0
-#endif
-
-#define DMCRIT(f, arg...) \
-       printk(KERN_CRIT DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-
-#define DMERR(f, arg...) \
-       printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-#define DMERR_LIMIT(f, arg...) \
-       do { \
-               if (dm_ratelimit())     \
-                       printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " \
-                              f "\n", ## arg); \
-       } while (0)
-
-#define DMWARN(f, arg...) \
-       printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-#define DMWARN_LIMIT(f, arg...) \
-       do { \
-               if (dm_ratelimit())     \
-                       printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " \
-                              f "\n", ## arg); \
-       } while (0)
-
-#define DMINFO(f, arg...) \
-       printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-#define DMINFO_LIMIT(f, arg...) \
-       do { \
-               if (dm_ratelimit())     \
-                       printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f \
-                              "\n", ## arg); \
-       } while (0)
+#define DM_RATELIMIT(pr_func, fmt, ...)                                        \
+do {                                                                   \
+       static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,   \
+                                     DEFAULT_RATELIMIT_BURST);         \
+                                                                       \
+       if (__ratelimit(&rs))                                           \
+               pr_func(DM_FMT(fmt), ##__VA_ARGS__);                    \
+} while (0)
+
+#define DM_FMT(fmt) DM_NAME ": " DM_MSG_PREFIX ": " fmt "\n"
+
+#define DMCRIT(fmt, ...) pr_crit(DM_FMT(fmt), ##__VA_ARGS__)
+
+#define DMERR(fmt, ...) pr_err(DM_FMT(fmt), ##__VA_ARGS__)
+#define DMERR_LIMIT(fmt, ...) DM_RATELIMIT(pr_err, fmt, ##__VA_ARGS__)
+#define DMWARN(fmt, ...) pr_warn(DM_FMT(fmt), ##__VA_ARGS__)
+#define DMWARN_LIMIT(fmt, ...) DM_RATELIMIT(pr_warn, fmt, ##__VA_ARGS__)
+#define DMINFO(fmt, ...) pr_info(DM_FMT(fmt), ##__VA_ARGS__)
+#define DMINFO_LIMIT(fmt, ...) DM_RATELIMIT(pr_info, fmt, ##__VA_ARGS__)
 
 #ifdef CONFIG_DM_DEBUG
-#  define DMDEBUG(f, arg...) \
-       printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX " DEBUG: " f "\n", ## arg)
-#  define DMDEBUG_LIMIT(f, arg...) \
-       do { \
-               if (dm_ratelimit())     \
-                       printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX ": " f \
-                              "\n", ## arg); \
-       } while (0)
+#define DMDEBUG(fmt, ...) printk(KERN_DEBUG DM_FMT(fmt), ##__VA_ARGS__)
+#define DMDEBUG_LIMIT(fmt, ...) DM_RATELIMIT(pr_debug, fmt, ##__VA_ARGS__)
 #else
-#  define DMDEBUG(f, arg...) do {} while (0)
-#  define DMDEBUG_LIMIT(f, arg...) do {} while (0)
+#define DMDEBUG(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
+#define DMDEBUG_LIMIT(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
 #endif
 
 #define DMEMIT(x...) sz += ((sz >= maxlen) ? \
index dfc099e..f29d342 100644 (file)
@@ -135,7 +135,6 @@ static inline void *dma_zalloc_coherent(struct device *dev, size_t size,
        return ret;
 }
 
-#ifdef CONFIG_HAS_DMA
 static inline int dma_get_cache_alignment(void)
 {
 #ifdef ARCH_DMA_MINALIGN
@@ -143,7 +142,6 @@ static inline int dma_get_cache_alignment(void)
 #endif
        return 1;
 }
-#endif
 
 /* flags for the coherent memory api */
 #define        DMA_MEMORY_MAP                  0x01
index 7675da2..8dad10c 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/compiler.h>
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/nospec.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/fs.h>
@@ -115,8 +116,10 @@ static inline struct file * fcheck_files(struct files_struct *files, unsigned in
        struct file * file = NULL;
        struct fdtable *fdt = files_fdtable(files);
 
-       if (fd < fdt->max_fds)
+       if (fd < fdt->max_fds) {
+               fd = array_index_nospec(fd, fdt->max_fds);
                file = rcu_dereference_check_fdtable(files, fdt->fd[fd]);
+       }
        return file;
 }
 
index 56d62fd..12e19eb 100644 (file)
@@ -1445,6 +1445,9 @@ extern int send_sigurg(struct fown_struct *fown);
 #define UMOUNT_NOFOLLOW        0x00000008      /* Don't follow symlink on umount */
 #define UMOUNT_UNUSED  0x80000000      /* Flag guaranteed to be unused */
 
+/* sb->s_iflags */
+#define SB_I_MULTIROOT 0x00000008      /* Multiple roots to the dentry tree */
+
 extern struct list_head super_blocks;
 extern spinlock_t sb_lock;
 
@@ -1461,6 +1464,7 @@ struct super_block {
        const struct quotactl_ops       *s_qcop;
        const struct export_operations *s_export_op;
        unsigned long           s_flags;
+       unsigned long           s_iflags;       /* internal SB_I_* flags */
        unsigned long           s_magic;
        struct dentry           *s_root;
        struct rw_semaphore     s_umount;
index 9ec20de..851a910 100644 (file)
@@ -642,7 +642,7 @@ bool fscache_maybe_release_page(struct fscache_cookie *cookie,
 {
        if (fscache_cookie_valid(cookie) && PageFsCache(page))
                return __fscache_maybe_release_page(cookie, page, gfp);
-       return false;
+       return true;
 }
 
 /**
index 9146f39..13dfc98 100644 (file)
@@ -3,6 +3,13 @@
 
 #include <linux/compiler.h>
 
+/* Built-in __init functions needn't be compiled with retpoline */
+#if defined(RETPOLINE) && !defined(MODULE)
+#define __noretpoline __attribute__((indirect_branch("keep")))
+#else
+#define __noretpoline
+#endif
+
 /* These macros are used to mark some functions or 
  * initialized data (doesn't apply to uninitialized data)
  * as `initialization' functions. The kernel can take this
@@ -40,7 +47,7 @@
 
 /* These are for everybody (although not all archs will actually
    discard it in modules) */
-#define __init         __section(.init.text) __cold notrace
+#define __init         __section(.init.text) __cold notrace __noretpoline
 #define __initdata     __section(.init.data)
 #define __initconst    __section(.init.rodata)
 #define __exitdata     __section(.exit.data)
index 3862e32..7631809 100644 (file)
@@ -1618,6 +1618,7 @@ int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code,
 
 int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file);
 int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file);
+int input_ff_flush(struct input_dev *dev, struct file *file);
 
 int input_ff_create_memless(struct input_dev *dev, void *data,
                int (*play_effect)(struct input_dev *, void *, struct ff_effect *));
diff --git a/include/linux/kaiser.h b/include/linux/kaiser.h
new file mode 100644 (file)
index 0000000..b56c190
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef _LINUX_KAISER_H
+#define _LINUX_KAISER_H
+
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#include <asm/kaiser.h>
+
+static inline int kaiser_map_thread_stack(void *stack)
+{
+       /*
+        * Map that page of kernel stack on which we enter from user context.
+        */
+       return kaiser_add_mapping((unsigned long)stack +
+                       THREAD_SIZE - PAGE_SIZE, PAGE_SIZE, __PAGE_KERNEL);
+}
+
+static inline void kaiser_unmap_thread_stack(void *stack)
+{
+       /*
+        * Note: may be called even when kaiser_map_thread_stack() failed.
+        */
+       kaiser_remove_mapping((unsigned long)stack +
+                       THREAD_SIZE - PAGE_SIZE, PAGE_SIZE);
+}
+#else
+
+/*
+ * These stubs are used whenever CONFIG_PAGE_TABLE_ISOLATION is off, which
+ * includes architectures that support KAISER, but have it disabled.
+ */
+
+static inline void kaiser_init(void)
+{
+}
+static inline int kaiser_add_mapping(unsigned long addr,
+                                    unsigned long size, u64 flags)
+{
+       return 0;
+}
+static inline void kaiser_remove_mapping(unsigned long start,
+                                        unsigned long size)
+{
+}
+static inline int kaiser_map_thread_stack(void *stack)
+{
+       return 0;
+}
+static inline void kaiser_unmap_thread_stack(void *stack)
+{
+}
+
+#endif /* !CONFIG_PAGE_TABLE_ISOLATION */
+#endif /* _LINUX_KAISER_H */
index 067eda0..4143edb 100644 (file)
@@ -4,29 +4,44 @@
 #include <generated/autoconf.h>
 
 /*
- * Helper macros to use CONFIG_ options in C expressions. Note that
+ * Helper macros to use CONFIG_ options in C/CPP expressions. Note that
  * these only work with boolean and tristate options.
  */
 
+/*
+ * Getting something that works in C and CPP for an arg that may or may
+ * not be defined is tricky.  Here, if we have "#define CONFIG_BOOGER 1"
+ * we match on the placeholder define, insert the "0," for arg1 and generate
+ * the triplet (0, 1, 0).  Then the last step cherry picks the 2nd arg (a one).
+ * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when
+ * the last step cherry picks the 2nd arg, we get a zero.
+ */
+#define __ARG_PLACEHOLDER_1 0,
+#define config_enabled(cfg)            ___is_defined(cfg)
+#define __is_defined(x)                        ___is_defined(x)
+#define ___is_defined(val)             ____is_defined(__ARG_PLACEHOLDER_##val)
+#define ____is_defined(arg1_or_junk)   __take_second_arg(arg1_or_junk 1, 0)
+#define __take_second_arg(__ignored, val, ...) val
+
 /*
  * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
  * 0 otherwise.
  *
  */
 #define IS_ENABLED(option) \
-       (__enabled_ ## option || __enabled_ ## option ## _MODULE)
+       (config_enabled(option) || config_enabled(option##_MODULE))
 
 /*
  * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
  * otherwise. For boolean options, this is equivalent to
  * IS_ENABLED(CONFIG_FOO).
  */
-#define IS_BUILTIN(option) __enabled_ ## option
+#define IS_BUILTIN(option) config_enabled(option)
 
 /*
  * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0
  * otherwise.
  */
-#define IS_MODULE(option) __enabled_ ## option ## _MODULE
+#define IS_MODULE(option) config_enabled(option##_MODULE)
 
 #endif /* __LINUX_KCONFIG_H */
index 183a6af..2c631b4 100644 (file)
@@ -155,6 +155,7 @@ struct key {
 #define KEY_FLAG_IN_QUOTA      3       /* set if key consumes quota */
 #define KEY_FLAG_USER_CONSTRUCT        4       /* set if key is being constructed in userspace */
 #define KEY_FLAG_NEGATIVE      5       /* set if key is negative */
+#define KEY_FLAG_UID_KEYRING   11      /* set if key is a user or user session keyring */
 
        /* the description string
         * - this is used to match a key against search criteria
@@ -196,6 +197,7 @@ extern struct key *key_alloc(struct key_type *type,
 #define KEY_ALLOC_IN_QUOTA     0x0000  /* add to quota, reject if would overrun */
 #define KEY_ALLOC_QUOTA_OVERRUN        0x0001  /* add to quota, permit even if overrun */
 #define KEY_ALLOC_NOT_IN_QUOTA 0x0002  /* not in quota */
+#define KEY_ALLOC_UID_KEYRING  0x0010  /* allocating a user or user session keyring */
 
 extern void key_revoke(struct key *key);
 extern void key_put(struct key *key);
index 84b0b18..081f038 100644 (file)
@@ -287,6 +287,7 @@ struct mlx4_caps {
        enum mlx4_port_type     possible_type[MLX4_MAX_PORTS + 1];
        u32                     max_counters;
        u8                      ext_port_cap[MLX4_MAX_PORTS + 1];
+       bool                    wol_port[MLX4_MAX_PORTS + 1];
 };
 
 struct mlx4_buf_list {
index 70fffeb..a444178 100644 (file)
@@ -1,9 +1,16 @@
 #ifndef _LINUX_MMU_CONTEXT_H
 #define _LINUX_MMU_CONTEXT_H
 
+#include <asm/mmu_context.h>
+
 struct mm_struct;
 
 void use_mm(struct mm_struct *mm);
 void unuse_mm(struct mm_struct *mm);
 
+/* Architectures that care about IRQ state in switch_mm can override this. */
+#ifndef switch_mm_irqs_off
+# define switch_mm_irqs_off switch_mm
+#endif
+
 #endif
index 132da3b..3984485 100644 (file)
@@ -121,8 +121,9 @@ enum zone_stat_item {
        NR_SLAB_RECLAIMABLE,
        NR_SLAB_UNRECLAIMABLE,
        NR_PAGETABLE,           /* used for pagetables */
-       NR_KERNEL_STACK,
        /* Second 128 byte cacheline */
+       NR_KERNEL_STACK,
+       NR_KAISERTABLE,
        NR_UNSTABLE_NFS,        /* NFS unstable pages */
        NR_BOUNCE,
        NR_VMSCAN_WRITE,
index 3cb7839..509e8ad 100644 (file)
@@ -661,4 +661,13 @@ static inline void module_bug_finalize(const Elf_Ehdr *hdr,
 static inline void module_bug_cleanup(struct module *mod) {}
 #endif /* CONFIG_GENERIC_BUG */
 
+#ifdef RETPOLINE
+extern bool retpoline_module_ok(bool has_retpoline);
+#else
+static inline bool retpoline_module_ok(bool has_retpoline)
+{
+       return true;
+}
+#endif
+
 #endif /* _LINUX_MODULE_H */
index 3887901..ec69d76 100644 (file)
@@ -327,7 +327,7 @@ static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word
 
 static inline map_word map_word_load(struct map_info *map, const void *ptr)
 {
-       map_word r;
+       map_word r = {{0} };
 
        if (map_bankwidth_is_1(map))
                r.x[0] = *(unsigned char *)ptr;
diff --git a/include/linux/nospec.h b/include/linux/nospec.h
new file mode 100644 (file)
index 0000000..6f06589
--- /dev/null
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018 Linus Torvalds. All rights reserved.
+// Copyright(c) 2018 Alexei Starovoitov. All rights reserved.
+// Copyright(c) 2018 Intel Corporation. All rights reserved.
+
+#ifndef _LINUX_NOSPEC_H
+#define _LINUX_NOSPEC_H
+#include <asm/system.h>
+
+/**
+ * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
+ * @index: array element index
+ * @size: number of elements in array
+ *
+ * When @index is out of bounds (@index >= @size), the sign bit will be
+ * set.  Extend the sign bit to all bits and invert, giving a result of
+ * zero for an out of bounds index, or ~0 if within bounds [0, @size).
+ */
+#ifndef array_index_mask_nospec
+static inline unsigned long array_index_mask_nospec(unsigned long index,
+                                                   unsigned long size)
+{
+       /*
+        * Always calculate and emit the mask even if the compiler
+        * thinks the mask is not needed. The compiler does not take
+        * into account the value of @index under speculation.
+        */
+       OPTIMIZER_HIDE_VAR(index);
+       return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1);
+}
+#endif
+
+/*
+ * array_index_nospec - sanitize an array index after a bounds check
+ *
+ * For a code sequence like:
+ *
+ *     if (index < size) {
+ *         index = array_index_nospec(index, size);
+ *         val = array[index];
+ *     }
+ *
+ * ...if the CPU speculates past the bounds check then
+ * array_index_nospec() will clamp the index within the range of [0,
+ * size).
+ */
+#define array_index_nospec(index, size)                                        \
+({                                                                     \
+       typeof(index) _i = (index);                                     \
+       typeof(size) _s = (size);                                       \
+       unsigned long _mask = array_index_mask_nospec(_i, _s);          \
+                                                                       \
+       BUILD_BUG_ON(sizeof(_i) > sizeof(long));                        \
+       BUILD_BUG_ON(sizeof(_s) > sizeof(long));                        \
+                                                                       \
+       (typeof(_i)) (_i & _mask);                                      \
+})
+#endif /* _LINUX_NOSPEC_H */
index d93f417..50bf221 100644 (file)
 #define PCI_DEVICE_ID_AMD_CS5536_EHC    0x2095
 #define PCI_DEVICE_ID_AMD_CS5536_UDC    0x2096
 #define PCI_DEVICE_ID_AMD_CS5536_UOC    0x2097
+#define PCI_DEVICE_ID_AMD_CS5536_DEV_IDE    0x2092
 #define PCI_DEVICE_ID_AMD_CS5536_IDE    0x209A
 #define PCI_DEVICE_ID_AMD_LX_VIDEO  0x2081
 #define PCI_DEVICE_ID_AMD_LX_AES    0x2082
index 27ef6b1..ea0c914 100644 (file)
        (void)__vpp_verify;                                             \
 } while (0)
 
+#ifdef CONFIG_PAGE_TABLE_ISOLATION
+#define USER_MAPPED_SECTION "..user_mapped"
+#else
+#define USER_MAPPED_SECTION ""
+#endif
+
 /*
  * s390 and alpha modules require percpu variables to be defined as
  * weak to force the compiler to generate GOT based external
 #define DEFINE_PER_CPU(type, name)                                     \
        DEFINE_PER_CPU_SECTION(type, name, "")
 
+#define DECLARE_PER_CPU_USER_MAPPED(type, name)                                \
+       DECLARE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION)
+
+#define DEFINE_PER_CPU_USER_MAPPED(type, name)                         \
+       DEFINE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION)
+
 /*
  * Declaration/definition used for per-CPU variables that must come first in
  * the set of variables.
        DEFINE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) \
        ____cacheline_aligned_in_smp
 
+#define DECLARE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(type, name)         \
+       DECLARE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION PER_CPU_SHARED_ALIGNED_SECTION) \
+       ____cacheline_aligned_in_smp
+
+#define DEFINE_PER_CPU_SHARED_ALIGNED_USER_MAPPED(type, name)          \
+       DEFINE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION PER_CPU_SHARED_ALIGNED_SECTION) \
+       ____cacheline_aligned_in_smp
+
 #define DECLARE_PER_CPU_ALIGNED(type, name)                            \
        DECLARE_PER_CPU_SECTION(type, name, PER_CPU_ALIGNED_SECTION)    \
        ____cacheline_aligned
 #define DEFINE_PER_CPU_PAGE_ALIGNED(type, name)                                \
        DEFINE_PER_CPU_SECTION(type, name, "..page_aligned")            \
        __aligned(PAGE_SIZE)
+/*
+ * Declaration/definition used for per-CPU variables that must be page aligned and need to be mapped in user mode.
+ */
+#define DECLARE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(type, name)           \
+       DECLARE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION"..page_aligned") \
+       __aligned(PAGE_SIZE)
+
+#define DEFINE_PER_CPU_PAGE_ALIGNED_USER_MAPPED(type, name)            \
+       DEFINE_PER_CPU_SECTION(type, name, USER_MAPPED_SECTION"..page_aligned") \
+       __aligned(PAGE_SIZE)
 
 /*
  * Declaration/definition used for per-CPU variables that must be read mostly.
  */
-#define DECLARE_PER_CPU_READ_MOSTLY(type, name)                        \
+#define DECLARE_PER_CPU_READ_MOSTLY(type, name)                                \
        DECLARE_PER_CPU_SECTION(type, name, "..readmostly")
 
 #define DEFINE_PER_CPU_READ_MOSTLY(type, name)                         \
index 8d5b91e..bee2357 100644 (file)
@@ -859,11 +859,6 @@ struct perf_event {
 #endif /* CONFIG_PERF_EVENTS */
 };
 
-enum perf_event_context_type {
-       task_context,
-       cpu_context,
-};
-
 /**
  * struct perf_event_context - event context structure
  *
@@ -871,7 +866,6 @@ enum perf_event_context_type {
  */
 struct perf_event_context {
        struct pmu                      *pmu;
-       enum perf_event_context_type    type;
        /*
         * Protect the states of the events in the list,
         * nr_active, and the list:
@@ -1146,6 +1140,7 @@ extern int perf_swevent_get_recursion_context(void);
 extern void perf_swevent_put_recursion_context(int rctx);
 extern void perf_event_enable(struct perf_event *event);
 extern void perf_event_disable(struct perf_event *event);
+extern int __perf_event_disable(void *info);
 extern void perf_event_task_tick(void);
 #else
 static inline void
@@ -1184,6 +1179,7 @@ static inline int  perf_swevent_get_recursion_context(void)               { return -1; }
 static inline void perf_swevent_put_recursion_context(int rctx)                { }
 static inline void perf_event_enable(struct perf_event *event)         { }
 static inline void perf_event_disable(struct perf_event *event)                { }
+static inline int __perf_event_disable(void *info)                     { return -1; }
 static inline void perf_event_task_tick(void)                          { }
 #endif
 
index fb76ee7..2d4ab76 100644 (file)
@@ -1313,6 +1313,8 @@ struct task_struct {
        unsigned sched_reset_on_fork:1;
        unsigned sched_contributes_to_load:1;
 
+       unsigned long atomic_flags; /* Flags needing atomic access. */
+
        pid_t pid;
        pid_t tgid;
 
@@ -1810,8 +1812,6 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 #define PF_KTHREAD     0x00200000      /* I am a kernel thread */
 #define PF_RANDOMIZE   0x00400000      /* randomize virtual address space */
 #define PF_SWAPWRITE   0x00800000      /* Allowed to write to swap */
-#define PF_SPREAD_PAGE 0x01000000      /* Spread page cache over cpuset */
-#define PF_SPREAD_SLAB 0x02000000      /* Spread some slab caches over cpuset */
 #define PF_THREAD_BOUND        0x04000000      /* Thread bound to specific cpu */
 #define PF_MCE_EARLY    0x08000000      /* Early kill for mce process policy */
 #define PF_MEMPOLICY   0x10000000      /* Non-default NUMA mempolicy */
@@ -1844,6 +1844,20 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 #define tsk_used_math(p) ((p)->flags & PF_USED_MATH)
 #define used_math() tsk_used_math(current)
 
+/* Per-process atomic flags. */
+#define PFA_SPREAD_PAGE  1      /* Spread page cache over cpuset */
+#define PFA_SPREAD_SLAB  2      /* Spread some slab caches over cpuset */
+
+#define TASK_PFA_TEST(name, func)                                      \
+       static inline bool task_##func(struct task_struct *p)           \
+       { return test_bit(PFA_##name, &p->atomic_flags); }
+#define TASK_PFA_SET(name, func)                                       \
+       static inline void task_set_##func(struct task_struct *p)       \
+       { set_bit(PFA_##name, &p->atomic_flags); }
+#define TASK_PFA_CLEAR(name, func)                                     \
+       static inline void task_clear_##func(struct task_struct *p)     \
+       { clear_bit(PFA_##name, &p->atomic_flags); }
+
 /*
  * task->jobctl flags
  */
@@ -1936,6 +1950,14 @@ static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
 }
 #endif
 
+TASK_PFA_TEST(SPREAD_PAGE, spread_page)
+TASK_PFA_SET(SPREAD_PAGE, spread_page)
+TASK_PFA_CLEAR(SPREAD_PAGE, spread_page)
+
+TASK_PFA_TEST(SPREAD_SLAB, spread_slab)
+TASK_PFA_SET(SPREAD_SLAB, spread_slab)
+TASK_PFA_CLEAR(SPREAD_SLAB, spread_slab)
+
 /*
  * Do not use outside of architecture code which knows its limitations.
  *
index a822300..0760794 100644 (file)
@@ -345,7 +345,9 @@ int unhandled_signal(struct task_struct *tsk, int sig);
 #else
 #define rt_sigmask(sig)        sigmask(sig)
 #endif
-#define siginmask(sig, mask) (rt_sigmask(sig) & (mask))
+
+#define siginmask(sig, mask) \
+       ((sig) < SIGRTMIN && (rt_sigmask(sig) & (mask)))
 
 #define SIG_KERNEL_ONLY_MASK (\
        rt_sigmask(SIGKILL)   |  rt_sigmask(SIGSTOP))
@@ -366,14 +368,18 @@ int unhandled_signal(struct task_struct *tsk, int sig);
         rt_sigmask(SIGCONT)   |  rt_sigmask(SIGCHLD)   | \
        rt_sigmask(SIGWINCH)  |  rt_sigmask(SIGURG)    )
 
-#define sig_kernel_only(sig) \
-       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_ONLY_MASK))
-#define sig_kernel_coredump(sig) \
-       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_COREDUMP_MASK))
-#define sig_kernel_ignore(sig) \
-       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_IGNORE_MASK))
-#define sig_kernel_stop(sig) \
-       (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_STOP_MASK))
+#define SIG_SPECIFIC_SICODES_MASK (\
+       rt_sigmask(SIGILL)    |  rt_sigmask(SIGFPE)    | \
+       rt_sigmask(SIGSEGV)   |  rt_sigmask(SIGBUS)    | \
+       rt_sigmask(SIGTRAP)   |  rt_sigmask(SIGCHLD)   | \
+       rt_sigmask(SIGPOLL)   |  rt_sigmask(SIGSYS)    | \
+       SIGEMT_MASK                                    )
+
+#define sig_kernel_only(sig)           siginmask(sig, SIG_KERNEL_ONLY_MASK)
+#define sig_kernel_coredump(sig)       siginmask(sig, SIG_KERNEL_COREDUMP_MASK)
+#define sig_kernel_ignore(sig)         siginmask(sig, SIG_KERNEL_IGNORE_MASK)
+#define sig_kernel_stop(sig)           siginmask(sig, SIG_KERNEL_STOP_MASK)
+#define sig_specific_sicodes(sig)      siginmask(sig, SIG_SPECIFIC_SICODES_MASK)
 
 #define sig_user_defined(t, signr) \
        (((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) &&  \
index 52d9ed0..834d2f6 100644 (file)
@@ -23,6 +23,7 @@
 #define SPIDEV_H
 
 #include <linux/types.h>
+#include <linux/ioctl.h>
 
 /* User space versions of kernel symbols for SPI clocking modes,
  * matching <linux/spi/spi.h>
index 6a40c76..ff9bbb6 100644 (file)
@@ -23,6 +23,16 @@ enum {
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 #endif
+
+/**
+ * offsetofend(TYPE, MEMBER)
+ *
+ * @TYPE: The type of the structure
+ * @MEMBER: The member within the structure to get the end offset of
+ */
+#define offsetofend(TYPE, MEMBER) \
+       (offsetof(TYPE, MEMBER) + sizeof(((TYPE *)0)->MEMBER))
+
 #endif /* __KERNEL__ */
 
 #endif
index 6f8b026..4ca049b 100644 (file)
@@ -369,7 +369,7 @@ static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_d
 {
        return (protocol == UAC_VERSION_1) ?
                desc->baSourceID[desc->bNrInPins + 4] :
-               desc->baSourceID[desc->bNrInPins + 6];
+               2; /* in UAC2, this value is constant */
 }
 
 static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc,
@@ -377,7 +377,7 @@ static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_de
 {
        return (protocol == UAC_VERSION_1) ?
                &desc->baSourceID[desc->bNrInPins + 5] :
-               &desc->baSourceID[desc->bNrInPins + 7];
+               &desc->baSourceID[desc->bNrInPins + 6];
 }
 
 static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc,
index 3b6f628..e89e286 100644 (file)
@@ -390,6 +390,11 @@ struct usb_endpoint_descriptor {
 #define USB_ENDPOINT_XFER_INT          3
 #define USB_ENDPOINT_MAX_ADJUSTABLE    0x80
 
+#define USB_EP_MAXP_MULT_SHIFT 11
+#define USB_EP_MAXP_MULT_MASK  (3 << USB_EP_MAXP_MULT_SHIFT)
+#define USB_EP_MAXP_MULT(m) \
+       (((m) & USB_EP_MAXP_MULT_MASK) >> USB_EP_MAXP_MULT_SHIFT)
+
 #define USB_ENDPOINT_SYNCTYPE          0x0c
 #define USB_ENDPOINT_SYNC_NONE         (0 << 2)
 #define USB_ENDPOINT_SYNC_ASYNC                (1 << 2)
@@ -592,6 +597,20 @@ static inline int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd)
        return __le16_to_cpu(epd->wMaxPacketSize);
 }
 
+/**
+ * usb_endpoint_maxp_mult - get endpoint's transactional opportunities
+ * @epd: endpoint to be checked
+ *
+ * Return @epd's wMaxPacketSize[12:11] + 1
+ */
+static inline int
+usb_endpoint_maxp_mult(const struct usb_endpoint_descriptor *epd)
+{
+       int maxp = __le16_to_cpu(epd->wMaxPacketSize);
+
+       return USB_EP_MAXP_MULT(maxp) + 1;
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
@@ -686,6 +705,7 @@ struct usb_interface_assoc_descriptor {
        __u8  iFunction;
 } __attribute__ ((packed));
 
+#define USB_DT_INTERFACE_ASSOCIATION_SIZE      8
 
 /*-------------------------------------------------------------------------*/
 
@@ -780,6 +800,8 @@ struct usb_wireless_cap_descriptor {        /* Ultra Wide Band */
        __u8  bReserved;
 } __attribute__((packed));
 
+#define USB_DT_USB_WIRELESS_CAP_SIZE   11
+
 /* USB 2.0 Extension descriptor */
 #define        USB_CAP_TYPE_EXT                2
 
index 4fc3e5d..088ecb0 100644 (file)
@@ -489,9 +489,9 @@ extern void usb_ep0_reinit(struct usb_device *);
        ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
 
 #define EndpointRequest \
-       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+       ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
 #define EndpointOutRequest \
-       ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+       ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
 
 /* class requests from the USB 2.0 hub spec, table 11-15 */
 /* GetBusState and SetHubDescriptor are optional, omitted */
index 15c99b7..abada78 100644 (file)
@@ -50,4 +50,7 @@
  */
 #define USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL  BIT(11)
 
+/* Device needs a pause after every control message. */
+#define USB_QUIRK_DELAY_CTRL_MSG               BIT(13)
+
 #endif /* __LINUX_USB_QUIRKS_H */
index 6cc18f3..5f66b9f 100644 (file)
@@ -496,6 +496,7 @@ extern int disable_ertm;
 
 int l2cap_init_sockets(void);
 void l2cap_cleanup_sockets(void);
+bool l2cap_is_socket(struct socket *sock);
 
 void __l2cap_connect_rsp_defer(struct l2cap_chan *chan);
 int __l2cap_wait_ack(struct sock *sk);
index 3907358..852f2ce 100644 (file)
@@ -63,6 +63,7 @@ struct fib6_node {
        __u16                   fn_flags;
        __u32                   fn_sernum;
        struct rt6_info         *rr_ptr;
+       struct rcu_head         rcu;
 };
 
 #ifndef CONFIG_IPV6_SUBTREES
@@ -95,7 +96,7 @@ struct rt6_info {
         * the same cache line.
         */
        struct fib6_table               *rt6i_table;
-       struct fib6_node                *rt6i_node;
+       struct fib6_node __rcu          *rt6i_node;
 
        struct in6_addr                 rt6i_gateway;
 
@@ -126,6 +127,38 @@ static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
        return ((struct rt6_info *)dst)->rt6i_idev;
 }
 
+/* Function to safely get fn->sernum for passed in rt
+ * and store result in passed in cookie.
+ * Return true if we can get cookie safely
+ * Return false if not
+ */
+static inline bool rt6_get_cookie_safe(const struct rt6_info *rt,
+                                      u32 *cookie)
+{
+       struct fib6_node *fn;
+       bool status = false;
+
+       rcu_read_lock();
+       fn = rcu_dereference(rt->rt6i_node);
+
+       if (fn) {
+               *cookie = fn->fn_sernum;
+               status = true;
+       }
+
+       rcu_read_unlock();
+       return status;
+}
+
+static inline u32 rt6_get_cookie(const struct rt6_info *rt)
+{
+       u32 cookie = 0;
+
+       rt6_get_cookie_safe(rt, &cookie);
+
+       return cookie;
+}
+
 struct fib6_walker_t {
        struct list_head lh;
        struct fib6_node *root, *node;
index 4913dac..67bfec1 100644 (file)
@@ -167,7 +167,7 @@ static inline void __ip6_dst_store(struct sock *sk, struct dst_entry *dst,
 #ifdef CONFIG_IPV6_SUBTREES
        np->saddr_cache = saddr;
 #endif
-       np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
+       np->dst_cookie = rt6_get_cookie(rt);
 }
 
 static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
index b72a3b8..d2eb24d 100644 (file)
@@ -124,6 +124,17 @@ static inline u32 red_rmask(u8 Plog)
        return Plog < 32 ? ((1 << Plog) - 1) : ~0UL;
 }
 
+static inline bool red_check_params(u32 qth_min, u32 qth_max, u8 Wlog)
+{
+       if (fls(qth_min) + Wlog > 32)
+               return false;
+       if (fls(qth_max) + Wlog > 32)
+               return false;
+       if (qth_max < qth_min)
+               return false;
+       return true;
+}
+
 static inline void red_set_parms(struct red_parms *p,
                                 u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog,
                                 u8 Scell_log, u8 *stab)
index c3c22e0..068fc65 100644 (file)
@@ -66,7 +66,7 @@ enum environment_cap {
 struct regulatory_request {
        int wiphy_idx;
        enum nl80211_reg_initiator initiator;
-       char alpha2[2];
+       char alpha2[3];
        bool intersect;
        bool processed;
        enum environment_cap country_ie_env;
index e0f1c91..b2fd7af 100644 (file)
@@ -538,6 +538,8 @@ _sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member)
 
 #define _sctp_walk_params(pos, chunk, end, member)\
 for (pos.v = chunk->member;\
+     (pos.v + offsetof(struct sctp_paramhdr, length) + sizeof(pos.p->length) <=\
+      (void *)chunk + end) &&\
      pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\
      ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\
      pos.v += WORD_ROUND(ntohs(pos.p->length)))
@@ -548,6 +550,8 @@ _sctp_walk_errors((err), (chunk_hdr), ntohs((chunk_hdr)->length))
 #define _sctp_walk_errors(err, chunk_hdr, end)\
 for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
            sizeof(sctp_chunkhdr_t));\
+     ((void *)err + offsetof(sctp_errhdr_t, length) + sizeof(err->length) <=\
+      (void *)chunk_hdr + end) &&\
      (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\
      ntohs(err->length) >= sizeof(sctp_errhdr_t); \
      err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length))))
@@ -700,9 +704,14 @@ static inline void sctp_v6_map_v4(union sctp_addr *addr)
 /* Map v4 address to v4-mapped v6 address */
 static inline void sctp_v4_map_v6(union sctp_addr *addr)
 {
-       addr->v6.sin6_family = AF_INET6;
-       addr->v6.sin6_port = addr->v4.sin_port;
+       __be16 port;
+
+       port = addr->v4.sin_port;
        addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
+       addr->v6.sin6_port = port;
+       addr->v6.sin6_family = AF_INET6;
+       addr->v6.sin6_flowinfo = 0;
+       addr->v6.sin6_scope_id = 0;
        addr->v6.sin6_addr.s6_addr32[0] = 0;
        addr->v6.sin6_addr.s6_addr32[1] = 0;
        addr->v6.sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
index 9069f8d..c6f6d60 100644 (file)
@@ -603,10 +603,6 @@ struct sctp_af {
                                         int saddr);
        void            (*from_sk)      (union sctp_addr *,
                                         struct sock *sk);
-       void            (*to_sk_saddr)  (union sctp_addr *,
-                                        struct sock *sk);
-       void            (*to_sk_daddr)  (union sctp_addr *,
-                                        struct sock *sk);
        void            (*from_addr_param) (union sctp_addr *,
                                            union sctp_addr_param *,
                                            __be16 port, int iif);
@@ -647,7 +643,9 @@ struct sctp_pf {
        int  (*supported_addrs)(const struct sctp_sock *, __be16 *);
        struct sock *(*create_accept_sk) (struct sock *sk,
                                          struct sctp_association *asoc);
-       void (*addr_v4map) (struct sctp_sock *, union sctp_addr *);
+       int (*addr_to_user)(struct sctp_sock *sk, union sctp_addr *addr);
+       void (*to_sk_saddr)(union sctp_addr *, struct sock *sk);
+       void (*to_sk_daddr)(union sctp_addr *, struct sock *sk);
        struct sctp_af *af;
 };
 
index 95c4211..3ff241e 100644 (file)
@@ -1394,12 +1394,12 @@ static inline void tcp_highest_sack_reset(struct sock *sk)
        tcp_sk(sk)->highest_sack = tcp_write_queue_head(sk);
 }
 
-/* Called when old skb is about to be deleted (to be combined with new skb) */
-static inline void tcp_highest_sack_combine(struct sock *sk,
+/* Called when old skb is about to be deleted and replaced by new skb */
+static inline void tcp_highest_sack_replace(struct sock *sk,
                                            struct sk_buff *old,
                                            struct sk_buff *new)
 {
-       if (tcp_sk(sk)->sacked_out && (old == tcp_sk(sk)->highest_sack))
+       if (old == tcp_highest_sack(sk))
                tcp_sk(sk)->highest_sack = new;
 }
 
index 9e5f337..19386d1 100644 (file)
@@ -1439,6 +1439,7 @@ extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi,
                      int encap_type);
 extern int xfrm_input_resume(struct sk_buff *skb, int nexthdr);
+int xfrm_trans_queue(struct sk_buff *skb, int (*finish)(struct sk_buff *));
 extern int xfrm_output_resume(struct sk_buff *skb, int err);
 extern int xfrm_output(struct sk_buff *skb);
 extern int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb);
index bf5daaf..a6bb7eb 100644 (file)
@@ -1308,6 +1308,40 @@ int ib_query_port(struct ib_device *device,
 enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device,
                                               u8 port_num);
 
+/**
+ * rdma_start_port - Return the first valid port number for the device
+ * specified
+ *
+ * @device: Device to be checked
+ *
+ * Return start port number
+ */
+static inline u8 rdma_start_port(const struct ib_device *device)
+{
+       return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
+}
+
+/**
+ * rdma_end_port - Return the last valid port number for the device
+ * specified
+ *
+ * @device: Device to be checked
+ *
+ * Return last port number
+ */
+static inline u8 rdma_end_port(const struct ib_device *device)
+{
+       return (device->node_type == RDMA_NODE_IB_SWITCH) ?
+               0 : device->phys_port_cnt;
+}
+
+static inline int rdma_is_port_valid(const struct ib_device *device,
+                                    unsigned int port)
+{
+       return (port >= rdma_start_port(device) &&
+               port <= rdma_end_port(device));
+}
+
 int ib_query_gid(struct ib_device *device,
                 u8 port_num, int index, union ib_gid *gid);
 
index 1e100c6..40e5fb9 100644 (file)
@@ -163,7 +163,6 @@ enum ata_command_set {
 
 struct sata_device {
         enum   ata_command_set command_set;
-        struct smp_resp        rps_resp; /* report_phy_sata_resp */
         __le16 *identify_device;
         __le16 *identify_packet_device;
 
@@ -172,10 +171,8 @@ struct sata_device {
 
        struct ata_port *ap;
        struct ata_host ata_host;
+       struct smp_resp rps_resp ____cacheline_aligned; /* report_phy_sata_resp */
        u8     fis[ATA_RESP_FIS_SIZE];
-       u32 sstatus;
-       u32 serror;
-       u32 scontrol;
 };
 
 /* ---------- Domain device ---------- */
@@ -449,7 +446,10 @@ enum service_response {
 };
 
 enum exec_status {
-       /* The SAM_STAT_.. codes fit in the lower 6 bits */
+       /* The SAM_STAT_.. codes fit in the lower 6 bits, alias some of
+        * them here to silence 'case value not in enumerated type' warnings
+        */
+       __SAM_STAT_CHECK_CONDITION = SAM_STAT_CHECK_CONDITION,
 
        SAS_DEV_NO_RESPONSE = 0x80,
        SAS_DATA_UNDERRUN,
@@ -489,10 +489,6 @@ enum exec_status {
 struct ata_task_resp {
        u16  frame_len;
        u8   ending_fis[ATA_RESP_FIS_SIZE];       /* dev to host or data-in */
-       u32  sstatus;
-       u32  serror;
-       u32  scontrol;
-       u32  sactive;
 };
 
 #define SAS_STATUS_BUF_SIZE 96
index 377ba61..4f768ae 100644 (file)
@@ -152,6 +152,7 @@ struct scsi_device {
        unsigned no_read_capacity_16:1; /* Avoid READ_CAPACITY_16 cmds */
        unsigned is_visible:1;  /* is the device visible in sysfs */
        unsigned broken_fua:1;          /* Don't set FUA bit */
+       unsigned unmap_limit_for_ws:1;  /* Use the UNMAP limit for WRITE SAME */
 
        DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
        struct list_head event_list;    /* asserted events */
index b4ddd3b..f25ba76 100644 (file)
@@ -30,4 +30,5 @@
 #define BLIST_RETRY_HWERROR    0x400000 /* retry HARDWARE_ERROR */
 #define BLIST_MAX_512          0x800000 /* maximum 512 sector cdb length */
 #define BLIST_ATTACH_PQ3       0x1000000 /* Scan: Attach to PQ3 devices */
+#define BLIST_UNMAP_LIMIT_WS   0x80000000 /* Use UNMAP limit for WRITE SAME */
 #endif
index f352a98..1495fd5 100644 (file)
@@ -55,7 +55,8 @@ typedef union snd_seq_timestamp snd_seq_timestamp_t;
 #define SNDRV_SEQ_DEFAULT_CLIENT_EVENTS        200
 
 /* max delivery path length */
-#define SNDRV_SEQ_MAX_HOPS             10
+/* NOTE: this shouldn't be greater than MAX_LOCKDEP_SUBCLASSES */
+#define SNDRV_SEQ_MAX_HOPS             8
 
 /* max size of event size */
 #define SNDRV_SEQ_MAX_EVENT_LEN                0x3fffffff
index d888433..ecfd526 100644 (file)
@@ -60,6 +60,7 @@ struct snd_virmidi_dev {
        int port;                       /* created/attached port */
        unsigned int flags;             /* SNDRV_VIRMIDI_* */
        rwlock_t filelist_lock;
+       struct rw_semaphore filelist_sem;
        struct list_head filelist;
 };
 
index 7990469..b0489b8 100644 (file)
@@ -90,6 +90,8 @@ struct snd_timer {
        struct list_head ack_list_head;
        struct list_head sack_list_head; /* slow ack list head */
        struct tasklet_struct task_queue;
+       int max_instances;      /* upper limit of timer instances */
+       int num_instances;      /* current number of timer instances */
 };
 
 struct snd_timer_instance {
index 46e3cd8..215a904 100644 (file)
@@ -152,7 +152,7 @@ TRACE_EVENT(kvm_ack_irq,
        { KVM_TRACE_MMIO_WRITE, "write" }
 
 TRACE_EVENT(kvm_mmio,
-       TP_PROTO(int type, int len, u64 gpa, u64 val),
+       TP_PROTO(int type, int len, u64 gpa, void *val),
        TP_ARGS(type, len, gpa, val),
 
        TP_STRUCT__entry(
@@ -166,7 +166,10 @@ TRACE_EVENT(kvm_mmio,
                __entry->type           = type;
                __entry->len            = len;
                __entry->gpa            = gpa;
-               __entry->val            = val;
+               __entry->val            = 0;
+               if (val)
+                       memcpy(&__entry->val, val,
+                              min_t(u32, sizeof(__entry->val), len));
        ),
 
        TP_printk("mmio %s len %u gpa 0x%llx val 0x%llx",
index e937d9b..558a9fd 100644 (file)
@@ -69,6 +69,7 @@
 #include <linux/slab.h>
 #include <linux/perf_event.h>
 #include <linux/random.h>
+#include <linux/kaiser.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -463,6 +464,7 @@ static void __init mm_init(void)
        percpu_init_late();
        pgtable_cache_init();
        vmalloc_init();
+       kaiser_init();
 }
 
 asmlinkage void __init start_kernel(void)
index e683869..4b4b9d5 100644 (file)
@@ -471,13 +471,15 @@ void audit_remove_watch_rule(struct audit_krule *krule)
        list_del(&krule->rlist);
 
        if (list_empty(&watch->rules)) {
+               /*
+                * audit_remove_watch() drops our reference to 'parent' which
+                * can get freed. Grab our own reference to be safe.
+                */
+               audit_get_parent(parent);
                audit_remove_watch(watch);
-
-               if (list_empty(&parent->watches)) {
-                       audit_get_parent(parent);
+               if (list_empty(&parent->watches))
                        fsnotify_destroy_mark(&parent->mark);
-                       audit_put_parent(parent);
-               }
+               audit_put_parent(parent);
        }
 }
 
index f735a58..00251dd 100644 (file)
@@ -406,14 +406,6 @@ out:
 #ifdef CONFIG_PM_SLEEP_SMP
 static cpumask_var_t frozen_cpus;
 
-void __weak arch_disable_nonboot_cpus_begin(void)
-{
-}
-
-void __weak arch_disable_nonboot_cpus_end(void)
-{
-}
-
 int disable_nonboot_cpus(void)
 {
        int cpu, first_cpu, error = 0;
@@ -425,7 +417,6 @@ int disable_nonboot_cpus(void)
         * with the userspace trying to use the CPU hotplug at the same time
         */
        cpumask_clear(frozen_cpus);
-       arch_disable_nonboot_cpus_begin();
 
        printk("Disabling non-boot CPUs ...\n");
        for_each_online_cpu(cpu) {
@@ -441,8 +432,6 @@ int disable_nonboot_cpus(void)
                }
        }
 
-       arch_disable_nonboot_cpus_end();
-
        if (!error) {
                BUG_ON(num_online_cpus() > 1);
                /* Make sure the CPUs won't be enabled by someone else */
index 4346f9a..5cc0eec 100644 (file)
@@ -326,13 +326,14 @@ static void cpuset_update_task_spread_flag(struct cpuset *cs,
                                        struct task_struct *tsk)
 {
        if (is_spread_page(cs))
-               tsk->flags |= PF_SPREAD_PAGE;
+               task_set_spread_page(tsk);
        else
-               tsk->flags &= ~PF_SPREAD_PAGE;
+               task_clear_spread_page(tsk);
+
        if (is_spread_slab(cs))
-               tsk->flags |= PF_SPREAD_SLAB;
+               task_set_spread_slab(tsk);
        else
-               tsk->flags &= ~PF_SPREAD_SLAB;
+               task_clear_spread_slab(tsk);
 }
 
 /*
index 4802eb5..c3c5b70 100644 (file)
@@ -349,7 +349,7 @@ poll_again:
                        }
                        kdb_printf("\n");
                        for (i = 0; i < count; i++) {
-                               if (kallsyms_symbol_next(p_tmp, i) < 0)
+                               if (WARN_ON(!kallsyms_symbol_next(p_tmp, i)))
                                        break;
                                kdb_printf("%s ", p_tmp);
                                *(p_tmp + len) = '\0';
index bc94278..beeac8e 100644 (file)
@@ -1344,7 +1344,7 @@ retry:
 /*
  * Cross CPU call to disable a performance event
  */
-static int __perf_event_disable(void *info)
+int __perf_event_disable(void *info)
 {
        struct perf_event *event = info;
        struct perf_event_context *ctx = event->ctx;
@@ -3277,50 +3277,77 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running)
 }
 EXPORT_SYMBOL_GPL(perf_event_read_value);
 
-static int perf_event_read_group(struct perf_event *event,
-                                  u64 read_format, char __user *buf)
+static void __perf_read_group_add(struct perf_event *leader,
+                                       u64 read_format, u64 *values)
 {
-       struct perf_event *leader = event->group_leader, *sub;
        struct perf_event_context *ctx = leader->ctx;
-       int n = 0, size = 0, ret;
+       struct perf_event *sub;
+       unsigned long flags;
+       int n = 1; /* skip @nr */
        u64 count, enabled, running;
-       u64 values[5];
-
-       lockdep_assert_held(&ctx->mutex);
 
        count = perf_event_read_value(leader, &enabled, &running);
 
-       values[n++] = 1 + leader->nr_siblings;
+       /*
+        * Since we co-schedule groups, {enabled,running} times of siblings
+        * will be identical to those of the leader, so we only publish one
+        * set.
+        */
        if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
                values[n++] = enabled;
        if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
                values[n++] = running;
-       values[n++] = count;
+
+       /*
+        * Write {count,id} tuples for every sibling.
+        */
+       values[n++] += count;
        if (read_format & PERF_FORMAT_ID)
                values[n++] = primary_event_id(leader);
 
-       size = n * sizeof(u64);
-
-       if (copy_to_user(buf, values, size))
-               return -EFAULT;
-
-       ret = size;
+       raw_spin_lock_irqsave(&ctx->lock, flags);
 
        list_for_each_entry(sub, &leader->sibling_list, group_entry) {
-               n = 0;
-
                values[n++] = perf_event_read_value(sub, &enabled, &running);
                if (read_format & PERF_FORMAT_ID)
                        values[n++] = primary_event_id(sub);
+       }
 
-               size = n * sizeof(u64);
+       raw_spin_unlock_irqrestore(&ctx->lock, flags);
+}
 
-               if (copy_to_user(buf + ret, values, size)) {
-                       return -EFAULT;
-               }
+static int perf_event_read_group(struct perf_event *event,
+                                  u64 read_format, char __user *buf)
+{
+       struct perf_event *leader = event->group_leader, *child;
+       struct perf_event_context *ctx = leader->ctx;
+       int ret = event->read_size;
+       u64 *values;
 
-               ret += size;
-       }
+       lockdep_assert_held(&ctx->mutex);
+
+       values = kzalloc(event->read_size, GFP_KERNEL);
+       if (!values)
+               return -ENOMEM;
+
+       values[0] = 1 + leader->nr_siblings;
+
+       /*
+        * By locking the child_mutex of the leader we effectively
+        * lock the child list of all siblings.. XXX explain how.
+        */
+       mutex_lock(&leader->child_mutex);
+
+       __perf_read_group_add(leader, read_format, values);
+       list_for_each_entry(child, &leader->child_list, child_list)
+               __perf_read_group_add(child, read_format, values);
+
+       mutex_unlock(&leader->child_mutex);
+
+       if (copy_to_user(buf, values, event->read_size))
+               ret = -EFAULT;
+
+       kfree(values);
 
        return ret;
 }
@@ -4240,9 +4267,6 @@ static void perf_output_read_one(struct perf_output_handle *handle,
        __output_copy(handle, values, n * sizeof(u64));
 }
 
-/*
- * XXX PERF_FORMAT_GROUP vs inherited events seems difficult.
- */
 static void perf_output_read_group(struct perf_output_handle *handle,
                            struct perf_event *event,
                            u64 enabled, u64 running)
@@ -4286,6 +4310,13 @@ static void perf_output_read_group(struct perf_output_handle *handle,
 #define PERF_FORMAT_TOTAL_TIMES (PERF_FORMAT_TOTAL_TIME_ENABLED|\
                                 PERF_FORMAT_TOTAL_TIME_RUNNING)
 
+/*
+ * XXX PERF_SAMPLE_READ vs inherited events seems difficult.
+ *
+ * The problem is that its both hard and excessively expensive to iterate the
+ * child list, not to mention that its impossible to IPI the children running
+ * on another CPU, from interrupt/NMI context.
+ */
 static void perf_output_read(struct perf_output_handle *handle,
                             struct perf_event *event)
 {
@@ -6085,7 +6116,6 @@ skip_type:
                __perf_event_init_context(&cpuctx->ctx);
                lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex);
                lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock);
-               cpuctx->ctx.type = cpu_context;
                cpuctx->ctx.pmu = pmu;
                cpuctx->jiffies_interval = 1;
                INIT_LIST_HEAD(&cpuctx->rotation_list);
@@ -6284,9 +6314,10 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
        local64_set(&hwc->period_left, hwc->sample_period);
 
        /*
-        * we currently do not support PERF_FORMAT_GROUP on inherited events
+        * We currently do not support PERF_SAMPLE_READ on inherited events.
+        * See perf_output_read().
         */
-       if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP))
+       if (attr->inherit && (attr->sample_type & PERF_SAMPLE_READ))
                goto done;
 
        pmu = perf_init_event(event);
@@ -6661,16 +6692,27 @@ SYSCALL_DEFINE5(perf_event_open,
                if (group_leader->group_leader != group_leader)
                        goto err_context;
                /*
-                * Do not allow to attach to a group in a different
-                * task or CPU context:
+                * Make sure we're both events for the same CPU;
+                * grouping events for different CPUs is broken; since
+                * you can never concurrently schedule them anyhow.
                 */
-               if (move_group) {
-                       if (group_leader->ctx->type != ctx->type)
-                               goto err_context;
-               } else {
-                       if (group_leader->ctx != ctx)
-                               goto err_context;
-               }
+               if (group_leader->cpu != event->cpu)
+                       goto err_context;
+
+               /*
+                * Make sure we're both on the same task, or both
+                * per-CPU events.
+                */
+               if (group_leader->ctx->task != ctx->task)
+                       goto err_context;
+
+               /*
+                * Do not allow to attach to a group in a different task
+                * or CPU context. If we're moving SW events, we'll fix
+                * this up later, so allow that.
+                */
+               if (!move_group && group_leader->ctx != ctx)
+                       goto err_context;
 
                /*
                 * Only a group leader can be exclusive or pinned
index 98ac24e..eeb84bb 100644 (file)
@@ -443,42 +443,35 @@ EXPORT_SYMBOL_GPL(register_user_hw_breakpoint);
  * modify_user_hw_breakpoint - modify a user-space hardware breakpoint
  * @bp: the breakpoint structure to modify
  * @attr: new breakpoint attributes
- * @triggered: callback to trigger when we hit the breakpoint
- * @tsk: pointer to 'task_struct' of the process to which the address belongs
  */
 int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr)
 {
-       u64 old_addr = bp->attr.bp_addr;
-       u64 old_len = bp->attr.bp_len;
-       int old_type = bp->attr.bp_type;
-       int err = 0;
-
-       perf_event_disable(bp);
+       /*
+        * modify_user_hw_breakpoint can be invoked with IRQs disabled and hence it
+        * will not be possible to raise IPIs that invoke __perf_event_disable.
+        * So call the function directly after making sure we are targeting the
+        * current task.
+        */
+       if (irqs_disabled() && bp->ctx && bp->ctx->task == current)
+               __perf_event_disable(bp);
+       else
+               perf_event_disable(bp);
 
        bp->attr.bp_addr = attr->bp_addr;
        bp->attr.bp_type = attr->bp_type;
        bp->attr.bp_len = attr->bp_len;
+       bp->attr.disabled = 1;
 
-       if (attr->disabled)
-               goto end;
+       if (!attr->disabled) {
+               int err = validate_hw_breakpoint(bp);
 
-       err = validate_hw_breakpoint(bp);
-       if (!err)
-               perf_event_enable(bp);
-
-       if (err) {
-               bp->attr.bp_addr = old_addr;
-               bp->attr.bp_type = old_type;
-               bp->attr.bp_len = old_len;
-               if (!bp->attr.disabled)
-                       perf_event_enable(bp);
+               if (err)
+                       return err;
 
-               return err;
+               perf_event_enable(bp);
+               bp->attr.disabled = 0;
        }
 
-end:
-       bp->attr.disabled = attr->disabled;
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);
index 5339705..ce211bb 100644 (file)
@@ -28,6 +28,8 @@
  * mutex protecting text section modification (dynamic code patching).
  * some users need to sleep (allocating memory...) while they hold this lock.
  *
+ * Note: Also protects SMP-alternatives modification on x86.
+ *
  * NOT exported to modules - patching kernel text is a really delicate matter.
  */
 DEFINE_MUTEX(text_mutex);
index 59ca16f..a2f4df8 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/tsacct_kern.h>
 #include <linux/cn_proc.h>
 #include <linux/freezer.h>
+#include <linux/kaiser.h>
 #include <linux/delayacct.h>
 #include <linux/taskstats_kern.h>
 #include <linux/random.h>
@@ -133,6 +134,7 @@ static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
 
 static inline void free_thread_info(struct thread_info *ti)
 {
+       kaiser_unmap_thread_stack(ti);
        free_pages((unsigned long)ti, THREAD_SIZE_ORDER);
 }
 #endif
@@ -275,6 +277,10 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
 
        tsk->stack = ti;
 
+       err = kaiser_map_thread_stack(tsk->stack);
+       if (err)
+               goto out;
+
        setup_thread_stack(tsk, orig);
        clear_user_return_notifier(tsk);
        clear_tsk_need_resched(tsk);
index 3854e75..5e48378 100644 (file)
@@ -1376,6 +1376,9 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
        struct plist_head *head1;
        struct futex_q *this, *next;
 
+       if (nr_wake < 0 || nr_requeue < 0)
+               return -EINVAL;
+
        if (requeue_pi) {
                /*
                 * Requeue PI only works on two distinct uaddrs. This
index a920281..74ae965 100644 (file)
@@ -46,4 +46,34 @@ config GCOV_PROFILE_ALL
        larger and run slower. Also be sure to exclude files from profiling
        which are not linked to the kernel image to prevent linker errors.
 
+choice
+       prompt "Specify GCOV format"
+       depends on GCOV_KERNEL
+       default GCOV_FORMAT_AUTODETECT
+       ---help---
+       The gcov format is usually determined by the GCC version, but there are
+       exceptions where format changes are integrated in lower-version GCCs.
+       In such a case use this option to adjust the format used in the kernel
+       accordingly.
+
+       If unsure, choose "Autodetect".
+
+config GCOV_FORMAT_AUTODETECT
+       bool "Autodetect"
+       ---help---
+       Select this option to use the format that corresponds to your GCC
+       version.
+
+config GCOV_FORMAT_3_4
+       bool "GCC 3.4 format"
+       ---help---
+       Select this option to use the format defined by GCC 3.4.
+
+config GCOV_FORMAT_4_7
+       bool "GCC 4.7 format"
+       ---help---
+       Select this option to use the format defined by GCC 4.7.
+
+endchoice
+
 endmenu
index e97ca59..52aa7e8 100644 (file)
@@ -1,3 +1,33 @@
 ccflags-y := -DSRCTREE='"$(srctree)"' -DOBJTREE='"$(objtree)"'
 
-obj-$(CONFIG_GCOV_KERNEL) := base.o fs.o gcc_3_4.o
+# if-lt
+# Usage VAR := $(call if-lt, $(a), $(b))
+# Returns 1 if (a < b)
+if-lt = $(shell [ $(1) -lt $(2) ] && echo 1)
+
+ifeq ($(CONFIG_GCOV_FORMAT_3_4),y)
+  cc-ver := 0304
+else ifeq ($(CONFIG_GCOV_FORMAT_4_7),y)
+  cc-ver := 0407
+else
+# Use cc-version if available, otherwise set 0
+#
+# scripts/Kbuild.include, which contains cc-version function, is not included
+# during make clean "make -f scripts/Makefile.clean obj=kernel/gcov"
+# Meaning cc-ver is empty causing if-lt test to fail with
+# "/bin/sh: line 0: [: -lt: unary operator expected" error mesage.
+# This has no affect on the clean phase, but the error message could be
+# confusing/annoying. So this dummy workaround sets cc-ver to zero if cc-version
+# is not available. We can probably move if-lt to Kbuild.include, so it's also
+# not defined during clean or to include Kbuild.include in
+# scripts/Makefile.clean. But the following workaround seems least invasive.
+  cc-ver := $(if $(call cc-version),$(call cc-version),0)
+endif
+
+obj-$(CONFIG_GCOV_KERNEL) := base.o fs.o
+
+ifeq ($(call if-lt, $(cc-ver), 0407),1)
+  obj-$(CONFIG_GCOV_KERNEL) += gcc_3_4.o
+else
+  obj-$(CONFIG_GCOV_KERNEL) += gcc_4_7.o
+endif
index 9b22d03..b358a80 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/mutex.h>
 #include "gcov.h"
 
-static struct gcov_info *gcov_info_head;
 static int gcov_events_enabled;
 static DEFINE_MUTEX(gcov_lock);
 
@@ -34,7 +33,7 @@ void __gcov_init(struct gcov_info *info)
 
        mutex_lock(&gcov_lock);
        if (gcov_version == 0) {
-               gcov_version = info->version;
+               gcov_version = gcov_info_version(info);
                /*
                 * Printing gcc's version magic may prove useful for debugging
                 * incompatibility reports.
@@ -45,8 +44,7 @@ void __gcov_init(struct gcov_info *info)
         * Add new profiling data structure to list and inform event
         * listener.
         */
-       info->next = gcov_info_head;
-       gcov_info_head = info;
+       gcov_info_link(info);
        if (gcov_events_enabled)
                gcov_event(GCOV_ADD, info);
        mutex_unlock(&gcov_lock);
@@ -81,6 +79,18 @@ void __gcov_merge_delta(gcov_type *counters, unsigned int n_counters)
 }
 EXPORT_SYMBOL(__gcov_merge_delta);
 
+void __gcov_merge_ior(gcov_type *counters, unsigned int n_counters)
+{
+       /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_merge_ior);
+
+void __gcov_merge_time_profile(gcov_type *counters, unsigned int n_counters)
+{
+       /* Unused. */
+}
+EXPORT_SYMBOL(__gcov_merge_time_profile);
+
 /**
  * gcov_enable_events - enable event reporting through gcov_event()
  *
@@ -91,13 +101,15 @@ EXPORT_SYMBOL(__gcov_merge_delta);
  */
 void gcov_enable_events(void)
 {
-       struct gcov_info *info;
+       struct gcov_info *info = NULL;
 
        mutex_lock(&gcov_lock);
        gcov_events_enabled = 1;
+
        /* Perform event callback for previously registered entries. */
-       for (info = gcov_info_head; info; info = info->next)
+       while ((info = gcov_info_next(info)))
                gcov_event(GCOV_ADD, info);
+
        mutex_unlock(&gcov_lock);
 }
 
@@ -112,25 +124,23 @@ static int gcov_module_notifier(struct notifier_block *nb, unsigned long event,
                                void *data)
 {
        struct module *mod = data;
-       struct gcov_info *info;
-       struct gcov_info *prev;
+       struct gcov_info *info = NULL;
+       struct gcov_info *prev = NULL;
 
        if (event != MODULE_STATE_GOING)
                return NOTIFY_OK;
        mutex_lock(&gcov_lock);
-       prev = NULL;
+
        /* Remove entries located in module from linked list. */
-       for (info = gcov_info_head; info; info = info->next) {
+       while ((info = gcov_info_next(info))) {
                if (within(info, mod->module_core, mod->core_size)) {
-                       if (prev)
-                               prev->next = info->next;
-                       else
-                               gcov_info_head = info->next;
+                       gcov_info_unlink(prev, info);
                        if (gcov_events_enabled)
                                gcov_event(GCOV_REMOVE, info);
                } else
                        prev = info;
        }
+
        mutex_unlock(&gcov_lock);
 
        return NOTIFY_OK;
index 9bd0934..27e12ce 100644 (file)
@@ -242,7 +242,7 @@ static struct gcov_node *get_node_by_name(const char *name)
 
        list_for_each_entry(node, &all_head, all) {
                info = get_node_info(node);
-               if (info && (strcmp(info->filename, name) == 0))
+               if (info && (strcmp(gcov_info_filename(info), name) == 0))
                        return node;
        }
 
@@ -279,7 +279,7 @@ static ssize_t gcov_seq_write(struct file *file, const char __user *addr,
        seq = file->private_data;
        info = gcov_iter_get_info(seq->private);
        mutex_lock(&node_lock);
-       node = get_node_by_name(info->filename);
+       node = get_node_by_name(gcov_info_filename(info));
        if (node) {
                /* Reset counts or remove node for unloaded modules. */
                if (node->num_loaded == 0)
@@ -376,8 +376,9 @@ static void add_links(struct gcov_node *node, struct dentry *parent)
        if (!node->links)
                return;
        for (i = 0; i < num; i++) {
-               target = get_link_target(get_node_info(node)->filename,
-                                        &gcov_link[i]);
+               target = get_link_target(
+                               gcov_info_filename(get_node_info(node)),
+                               &gcov_link[i]);
                if (!target)
                        goto out_err;
                basename = strrchr(target, '/');
@@ -576,7 +577,7 @@ static void add_node(struct gcov_info *info)
        struct gcov_node *parent;
        struct gcov_node *node;
 
-       filename = kstrdup(info->filename, GFP_KERNEL);
+       filename = kstrdup(gcov_info_filename(info), GFP_KERNEL);
        if (!filename)
                return;
        parent = &root_node;
@@ -631,7 +632,7 @@ static void add_info(struct gcov_node *node, struct gcov_info *info)
        loaded_info = kcalloc(num + 1, sizeof(struct gcov_info *), GFP_KERNEL);
        if (!loaded_info) {
                pr_warning("could not add '%s' (out of memory)\n",
-                          info->filename);
+                          gcov_info_filename(info));
                return;
        }
        memcpy(loaded_info, node->loaded_info,
@@ -645,7 +646,8 @@ static void add_info(struct gcov_node *node, struct gcov_info *info)
                 */
                if (!gcov_info_is_compatible(node->unloaded_info, info)) {
                        pr_warning("discarding saved data for %s "
-                                  "(incompatible version)\n", info->filename);
+                                  "(incompatible version)\n",
+                                  gcov_info_filename(info));
                        gcov_info_free(node->unloaded_info);
                        node->unloaded_info = NULL;
                }
@@ -656,7 +658,7 @@ static void add_info(struct gcov_node *node, struct gcov_info *info)
                 */
                if (!gcov_info_is_compatible(node->loaded_info[0], info)) {
                        pr_warning("could not add '%s' (incompatible "
-                                  "version)\n", info->filename);
+                                  "version)\n", gcov_info_filename(info));
                        kfree(loaded_info);
                        return;
                }
@@ -692,7 +694,8 @@ static void save_info(struct gcov_node *node, struct gcov_info *info)
                node->unloaded_info = gcov_info_dup(info);
                if (!node->unloaded_info) {
                        pr_warning("could not save data for '%s' "
-                                  "(out of memory)\n", info->filename);
+                                  "(out of memory)\n",
+                                  gcov_info_filename(info));
                }
        }
 }
@@ -708,7 +711,7 @@ static void remove_info(struct gcov_node *node, struct gcov_info *info)
        i = get_info_index(node, info);
        if (i < 0) {
                pr_warning("could not remove '%s' (not found)\n",
-                          info->filename);
+                          gcov_info_filename(info));
                return;
        }
        if (gcov_persist)
@@ -735,7 +738,7 @@ void gcov_event(enum gcov_action action, struct gcov_info *info)
        struct gcov_node *node;
 
        mutex_lock(&node_lock);
-       node = get_node_by_name(info->filename);
+       node = get_node_by_name(gcov_info_filename(info));
        switch (action) {
        case GCOV_ADD:
                if (node)
@@ -748,7 +751,7 @@ void gcov_event(enum gcov_action action, struct gcov_info *info)
                        remove_info(node, info);
                else {
                        pr_warning("could not remove '%s' (not found)\n",
-                                  info->filename);
+                                  gcov_info_filename(info));
                }
                break;
        }
index ae5bb42..27bc88a 100644 (file)
 #include <linux/vmalloc.h>
 #include "gcov.h"
 
+#define GCOV_COUNTERS          5
+
+static struct gcov_info *gcov_info_head;
+
+/**
+ * struct gcov_fn_info - profiling meta data per function
+ * @ident: object file-unique function identifier
+ * @checksum: function checksum
+ * @n_ctrs: number of values per counter type belonging to this function
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time.
+ */
+struct gcov_fn_info {
+       unsigned int ident;
+       unsigned int checksum;
+       unsigned int n_ctrs[0];
+};
+
+/**
+ * struct gcov_ctr_info - profiling data per counter type
+ * @num: number of counter values for this type
+ * @values: array of counter values for this type
+ * @merge: merge function for counter values of this type (unused)
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time with the exception of the values array.
+ */
+struct gcov_ctr_info {
+       unsigned int    num;
+       gcov_type       *values;
+       void            (*merge)(gcov_type *, unsigned int);
+};
+
+/**
+ * struct gcov_info - profiling data per object file
+ * @version: gcov version magic indicating the gcc version used for compilation
+ * @next: list head for a singly-linked list
+ * @stamp: time stamp
+ * @filename: name of the associated gcov data file
+ * @n_functions: number of instrumented functions
+ * @functions: function data
+ * @ctr_mask: mask specifying which counter types are active
+ * @counts: counter data per counter type
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time with the exception of the next pointer.
+ */
+struct gcov_info {
+       unsigned int                    version;
+       struct gcov_info                *next;
+       unsigned int                    stamp;
+       const char                      *filename;
+       unsigned int                    n_functions;
+       const struct gcov_fn_info       *functions;
+       unsigned int                    ctr_mask;
+       struct gcov_ctr_info            counts[0];
+};
+
+/**
+ * gcov_info_filename - return info filename
+ * @info: profiling data set
+ */
+const char *gcov_info_filename(struct gcov_info *info)
+{
+       return info->filename;
+}
+
+/**
+ * gcov_info_version - return info version
+ * @info: profiling data set
+ */
+unsigned int gcov_info_version(struct gcov_info *info)
+{
+       return info->version;
+}
+
+/**
+ * gcov_info_next - return next profiling data set
+ * @info: profiling data set
+ *
+ * Returns next gcov_info following @info or first gcov_info in the chain if
+ * @info is %NULL.
+ */
+struct gcov_info *gcov_info_next(struct gcov_info *info)
+{
+       if (!info)
+               return gcov_info_head;
+
+       return info->next;
+}
+
+/**
+ * gcov_info_link - link/add profiling data set to the list
+ * @info: profiling data set
+ */
+void gcov_info_link(struct gcov_info *info)
+{
+       info->next = gcov_info_head;
+       gcov_info_head = info;
+}
+
+/**
+ * gcov_info_unlink - unlink/remove profiling data set from the list
+ * @prev: previous profiling data set
+ * @info: profiling data set
+ */
+void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
+{
+       if (prev)
+               prev->next = info->next;
+       else
+               gcov_info_head = info->next;
+}
+
 /* Symbolic links to be created for each profiling data file. */
 const struct gcov_link gcov_link[] = {
        { OBJ_TREE, "gcno" },   /* Link to .gcno file in $(objtree). */
diff --git a/kernel/gcov/gcc_4_7.c b/kernel/gcov/gcc_4_7.c
new file mode 100644 (file)
index 0000000..826ba9f
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ *  This code provides functions to handle gcc's profiling data format
+ *  introduced with gcc 4.7.
+ *
+ *  This file is based heavily on gcc_3_4.c file.
+ *
+ *  For a better understanding, refer to gcc source:
+ *  gcc/gcov-io.h
+ *  libgcc/libgcov.c
+ *
+ *  Uses gcc-internal data definitions.
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
+#include "gcov.h"
+
+#if __GNUC__ == 4 && __GNUC_MINOR__ >= 9
+#define GCOV_COUNTERS                  9
+#else
+#define GCOV_COUNTERS                  8
+#endif
+
+#define GCOV_TAG_FUNCTION_LENGTH       3
+
+static struct gcov_info *gcov_info_head;
+
+/**
+ * struct gcov_ctr_info - information about counters for a single function
+ * @num: number of counter values for this type
+ * @values: array of counter values for this type
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time with the exception of the values array.
+ */
+struct gcov_ctr_info {
+       unsigned int num;
+       gcov_type *values;
+};
+
+/**
+ * struct gcov_fn_info - profiling meta data per function
+ * @key: comdat key
+ * @ident: unique ident of function
+ * @lineno_checksum: function lineo_checksum
+ * @cfg_checksum: function cfg checksum
+ * @ctrs: instrumented counters
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time.
+ *
+ * Information about a single function.  This uses the trailing array
+ * idiom. The number of counters is determined from the merge pointer
+ * array in gcov_info.  The key is used to detect which of a set of
+ * comdat functions was selected -- it points to the gcov_info object
+ * of the object file containing the selected comdat function.
+ */
+struct gcov_fn_info {
+       const struct gcov_info *key;
+       unsigned int ident;
+       unsigned int lineno_checksum;
+       unsigned int cfg_checksum;
+       struct gcov_ctr_info ctrs[0];
+};
+
+/**
+ * struct gcov_info - profiling data per object file
+ * @version: gcov version magic indicating the gcc version used for compilation
+ * @next: list head for a singly-linked list
+ * @stamp: uniquifying time stamp
+ * @filename: name of the associated gcov data file
+ * @merge: merge functions (null for unused counter type)
+ * @n_functions: number of instrumented functions
+ * @functions: pointer to pointers to function information
+ *
+ * This data is generated by gcc during compilation and doesn't change
+ * at run-time with the exception of the next pointer.
+ */
+struct gcov_info {
+       unsigned int version;
+       struct gcov_info *next;
+       unsigned int stamp;
+       const char *filename;
+       void (*merge[GCOV_COUNTERS])(gcov_type *, unsigned int);
+       unsigned int n_functions;
+       struct gcov_fn_info **functions;
+};
+
+/**
+ * gcov_info_filename - return info filename
+ * @info: profiling data set
+ */
+const char *gcov_info_filename(struct gcov_info *info)
+{
+       return info->filename;
+}
+
+/**
+ * gcov_info_version - return info version
+ * @info: profiling data set
+ */
+unsigned int gcov_info_version(struct gcov_info *info)
+{
+       return info->version;
+}
+
+/**
+ * gcov_info_next - return next profiling data set
+ * @info: profiling data set
+ *
+ * Returns next gcov_info following @info or first gcov_info in the chain if
+ * @info is %NULL.
+ */
+struct gcov_info *gcov_info_next(struct gcov_info *info)
+{
+       if (!info)
+               return gcov_info_head;
+
+       return info->next;
+}
+
+/**
+ * gcov_info_link - link/add profiling data set to the list
+ * @info: profiling data set
+ */
+void gcov_info_link(struct gcov_info *info)
+{
+       info->next = gcov_info_head;
+       gcov_info_head = info;
+}
+
+/**
+ * gcov_info_unlink - unlink/remove profiling data set from the list
+ * @prev: previous profiling data set
+ * @info: profiling data set
+ */
+void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info)
+{
+       if (prev)
+               prev->next = info->next;
+       else
+               gcov_info_head = info->next;
+}
+
+/* Symbolic links to be created for each profiling data file. */
+const struct gcov_link gcov_link[] = {
+       { OBJ_TREE, "gcno" },   /* Link to .gcno file in $(objtree). */
+       { 0, NULL},
+};
+
+/*
+ * Determine whether a counter is active. Doesn't change at run-time.
+ */
+static int counter_active(struct gcov_info *info, unsigned int type)
+{
+       return info->merge[type] ? 1 : 0;
+}
+
+/* Determine number of active counters. Based on gcc magic. */
+static unsigned int num_counter_active(struct gcov_info *info)
+{
+       unsigned int i;
+       unsigned int result = 0;
+
+       for (i = 0; i < GCOV_COUNTERS; i++) {
+               if (counter_active(info, i))
+                       result++;
+       }
+       return result;
+}
+
+/**
+ * gcov_info_reset - reset profiling data to zero
+ * @info: profiling data set
+ */
+void gcov_info_reset(struct gcov_info *info)
+{
+       struct gcov_ctr_info *ci_ptr;
+       unsigned int fi_idx;
+       unsigned int ct_idx;
+
+       for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
+               ci_ptr = info->functions[fi_idx]->ctrs;
+
+               for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
+                       if (!counter_active(info, ct_idx))
+                               continue;
+
+                       memset(ci_ptr->values, 0,
+                                       sizeof(gcov_type) * ci_ptr->num);
+                       ci_ptr++;
+               }
+       }
+}
+
+/**
+ * gcov_info_is_compatible - check if profiling data can be added
+ * @info1: first profiling data set
+ * @info2: second profiling data set
+ *
+ * Returns non-zero if profiling data can be added, zero otherwise.
+ */
+int gcov_info_is_compatible(struct gcov_info *info1, struct gcov_info *info2)
+{
+       return (info1->stamp == info2->stamp);
+}
+
+/**
+ * gcov_info_add - add up profiling data
+ * @dest: profiling data set to which data is added
+ * @source: profiling data set which is added
+ *
+ * Adds profiling counts of @source to @dest.
+ */
+void gcov_info_add(struct gcov_info *dst, struct gcov_info *src)
+{
+       struct gcov_ctr_info *dci_ptr;
+       struct gcov_ctr_info *sci_ptr;
+       unsigned int fi_idx;
+       unsigned int ct_idx;
+       unsigned int val_idx;
+
+       for (fi_idx = 0; fi_idx < src->n_functions; fi_idx++) {
+               dci_ptr = dst->functions[fi_idx]->ctrs;
+               sci_ptr = src->functions[fi_idx]->ctrs;
+
+               for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
+                       if (!counter_active(src, ct_idx))
+                               continue;
+
+                       for (val_idx = 0; val_idx < sci_ptr->num; val_idx++)
+                               dci_ptr->values[val_idx] +=
+                                       sci_ptr->values[val_idx];
+
+                       dci_ptr++;
+                       sci_ptr++;
+               }
+       }
+}
+
+/**
+ * gcov_info_dup - duplicate profiling data set
+ * @info: profiling data set to duplicate
+ *
+ * Return newly allocated duplicate on success, %NULL on error.
+ */
+struct gcov_info *gcov_info_dup(struct gcov_info *info)
+{
+       struct gcov_info *dup;
+       struct gcov_ctr_info *dci_ptr; /* dst counter info */
+       struct gcov_ctr_info *sci_ptr; /* src counter info */
+       unsigned int active;
+       unsigned int fi_idx; /* function info idx */
+       unsigned int ct_idx; /* counter type idx */
+       size_t fi_size; /* function info size */
+       size_t cv_size; /* counter values size */
+
+       dup = kmemdup(info, sizeof(*dup), GFP_KERNEL);
+       if (!dup)
+               return NULL;
+
+       dup->next = NULL;
+       dup->filename = NULL;
+       dup->functions = NULL;
+
+       dup->filename = kstrdup(info->filename, GFP_KERNEL);
+       if (!dup->filename)
+               goto err_free;
+
+       dup->functions = kcalloc(info->n_functions,
+                                sizeof(struct gcov_fn_info *), GFP_KERNEL);
+       if (!dup->functions)
+               goto err_free;
+
+       active = num_counter_active(info);
+       fi_size = sizeof(struct gcov_fn_info);
+       fi_size += sizeof(struct gcov_ctr_info) * active;
+
+       for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
+               dup->functions[fi_idx] = kzalloc(fi_size, GFP_KERNEL);
+               if (!dup->functions[fi_idx])
+                       goto err_free;
+
+               *(dup->functions[fi_idx]) = *(info->functions[fi_idx]);
+
+               sci_ptr = info->functions[fi_idx]->ctrs;
+               dci_ptr = dup->functions[fi_idx]->ctrs;
+
+               for (ct_idx = 0; ct_idx < active; ct_idx++) {
+
+                       cv_size = sizeof(gcov_type) * sci_ptr->num;
+
+                       dci_ptr->values = vmalloc(cv_size);
+
+                       if (!dci_ptr->values)
+                               goto err_free;
+
+                       dci_ptr->num = sci_ptr->num;
+                       memcpy(dci_ptr->values, sci_ptr->values, cv_size);
+
+                       sci_ptr++;
+                       dci_ptr++;
+               }
+       }
+
+       return dup;
+err_free:
+       gcov_info_free(dup);
+       return NULL;
+}
+
+/**
+ * gcov_info_free - release memory for profiling data set duplicate
+ * @info: profiling data set duplicate to free
+ */
+void gcov_info_free(struct gcov_info *info)
+{
+       unsigned int active;
+       unsigned int fi_idx;
+       unsigned int ct_idx;
+       struct gcov_ctr_info *ci_ptr;
+
+       if (!info->functions)
+               goto free_info;
+
+       active = num_counter_active(info);
+
+       for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
+               if (!info->functions[fi_idx])
+                       continue;
+
+               ci_ptr = info->functions[fi_idx]->ctrs;
+
+               for (ct_idx = 0; ct_idx < active; ct_idx++, ci_ptr++)
+                       vfree(ci_ptr->values);
+
+               kfree(info->functions[fi_idx]);
+       }
+
+free_info:
+       kfree(info->functions);
+       kfree(info->filename);
+       kfree(info);
+}
+
+#define ITER_STRIDE    PAGE_SIZE
+
+/**
+ * struct gcov_iterator - specifies current file position in logical records
+ * @info: associated profiling data
+ * @buffer: buffer containing file data
+ * @size: size of buffer
+ * @pos: current position in file
+ */
+struct gcov_iterator {
+       struct gcov_info *info;
+       void *buffer;
+       size_t size;
+       loff_t pos;
+};
+
+/**
+ * store_gcov_u32 - store 32 bit number in gcov format to buffer
+ * @buffer: target buffer or NULL
+ * @off: offset into the buffer
+ * @v: value to be stored
+ *
+ * Number format defined by gcc: numbers are recorded in the 32 bit
+ * unsigned binary form of the endianness of the machine generating the
+ * file. Returns the number of bytes stored. If @buffer is %NULL, doesn't
+ * store anything.
+ */
+static size_t store_gcov_u32(void *buffer, size_t off, u32 v)
+{
+       u32 *data;
+
+       if (buffer) {
+               data = buffer + off;
+               *data = v;
+       }
+
+       return sizeof(*data);
+}
+
+/**
+ * store_gcov_u64 - store 64 bit number in gcov format to buffer
+ * @buffer: target buffer or NULL
+ * @off: offset into the buffer
+ * @v: value to be stored
+ *
+ * Number format defined by gcc: numbers are recorded in the 32 bit
+ * unsigned binary form of the endianness of the machine generating the
+ * file. 64 bit numbers are stored as two 32 bit numbers, the low part
+ * first. Returns the number of bytes stored. If @buffer is %NULL, doesn't store
+ * anything.
+ */
+static size_t store_gcov_u64(void *buffer, size_t off, u64 v)
+{
+       u32 *data;
+
+       if (buffer) {
+               data = buffer + off;
+
+               data[0] = (v & 0xffffffffUL);
+               data[1] = (v >> 32);
+       }
+
+       return sizeof(*data) * 2;
+}
+
+/**
+ * convert_to_gcda - convert profiling data set to gcda file format
+ * @buffer: the buffer to store file data or %NULL if no data should be stored
+ * @info: profiling data set to be converted
+ *
+ * Returns the number of bytes that were/would have been stored into the buffer.
+ */
+static size_t convert_to_gcda(char *buffer, struct gcov_info *info)
+{
+       struct gcov_fn_info *fi_ptr;
+       struct gcov_ctr_info *ci_ptr;
+       unsigned int fi_idx;
+       unsigned int ct_idx;
+       unsigned int cv_idx;
+       size_t pos = 0;
+
+       /* File header. */
+       pos += store_gcov_u32(buffer, pos, GCOV_DATA_MAGIC);
+       pos += store_gcov_u32(buffer, pos, info->version);
+       pos += store_gcov_u32(buffer, pos, info->stamp);
+
+       for (fi_idx = 0; fi_idx < info->n_functions; fi_idx++) {
+               fi_ptr = info->functions[fi_idx];
+
+               /* Function record. */
+               pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION);
+               pos += store_gcov_u32(buffer, pos, GCOV_TAG_FUNCTION_LENGTH);
+               pos += store_gcov_u32(buffer, pos, fi_ptr->ident);
+               pos += store_gcov_u32(buffer, pos, fi_ptr->lineno_checksum);
+               pos += store_gcov_u32(buffer, pos, fi_ptr->cfg_checksum);
+
+               ci_ptr = fi_ptr->ctrs;
+
+               for (ct_idx = 0; ct_idx < GCOV_COUNTERS; ct_idx++) {
+                       if (!counter_active(info, ct_idx))
+                               continue;
+
+                       /* Counter record. */
+                       pos += store_gcov_u32(buffer, pos,
+                                             GCOV_TAG_FOR_COUNTER(ct_idx));
+                       pos += store_gcov_u32(buffer, pos, ci_ptr->num * 2);
+
+                       for (cv_idx = 0; cv_idx < ci_ptr->num; cv_idx++) {
+                               pos += store_gcov_u64(buffer, pos,
+                                                     ci_ptr->values[cv_idx]);
+                       }
+
+                       ci_ptr++;
+               }
+       }
+
+       return pos;
+}
+
+/**
+ * gcov_iter_new - allocate and initialize profiling data iterator
+ * @info: profiling data set to be iterated
+ *
+ * Return file iterator on success, %NULL otherwise.
+ */
+struct gcov_iterator *gcov_iter_new(struct gcov_info *info)
+{
+       struct gcov_iterator *iter;
+
+       iter = kzalloc(sizeof(struct gcov_iterator), GFP_KERNEL);
+       if (!iter)
+               goto err_free;
+
+       iter->info = info;
+       /* Dry-run to get the actual buffer size. */
+       iter->size = convert_to_gcda(NULL, info);
+       iter->buffer = vmalloc(iter->size);
+       if (!iter->buffer)
+               goto err_free;
+
+       convert_to_gcda(iter->buffer, info);
+
+       return iter;
+
+err_free:
+       kfree(iter);
+       return NULL;
+}
+
+
+/**
+ * gcov_iter_get_info - return profiling data set for given file iterator
+ * @iter: file iterator
+ */
+void gcov_iter_free(struct gcov_iterator *iter)
+{
+       vfree(iter->buffer);
+       kfree(iter);
+}
+
+/**
+ * gcov_iter_get_info - return profiling data set for given file iterator
+ * @iter: file iterator
+ */
+struct gcov_info *gcov_iter_get_info(struct gcov_iterator *iter)
+{
+       return iter->info;
+}
+
+/**
+ * gcov_iter_start - reset file iterator to starting position
+ * @iter: file iterator
+ */
+void gcov_iter_start(struct gcov_iterator *iter)
+{
+       iter->pos = 0;
+}
+
+/**
+ * gcov_iter_next - advance file iterator to next logical record
+ * @iter: file iterator
+ *
+ * Return zero if new position is valid, non-zero if iterator has reached end.
+ */
+int gcov_iter_next(struct gcov_iterator *iter)
+{
+       if (iter->pos < iter->size)
+               iter->pos += ITER_STRIDE;
+
+       if (iter->pos >= iter->size)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * gcov_iter_write - write data for current pos to seq_file
+ * @iter: file iterator
+ * @seq: seq_file handle
+ *
+ * Return zero on success, non-zero otherwise.
+ */
+int gcov_iter_write(struct gcov_iterator *iter, struct seq_file *seq)
+{
+       size_t len;
+
+       if (iter->pos >= iter->size)
+               return -EINVAL;
+
+       len = ITER_STRIDE;
+       if (iter->pos + len > iter->size)
+               len = iter->size - iter->pos;
+
+       seq_write(seq, iter->buffer + iter->pos, len);
+
+       return 0;
+}
index 060073e..92c8e22 100644 (file)
@@ -21,7 +21,6 @@
  * gcc and need to be kept as close to the original definition as possible to
  * remain compatible.
  */
-#define GCOV_COUNTERS          5
 #define GCOV_DATA_MAGIC                ((unsigned int) 0x67636461)
 #define GCOV_TAG_FUNCTION      ((unsigned int) 0x01000000)
 #define GCOV_TAG_COUNTER_BASE  ((unsigned int) 0x01a10000)
@@ -34,60 +33,18 @@ typedef long gcov_type;
 typedef long long gcov_type;
 #endif
 
-/**
- * struct gcov_fn_info - profiling meta data per function
- * @ident: object file-unique function identifier
- * @checksum: function checksum
- * @n_ctrs: number of values per counter type belonging to this function
- *
- * This data is generated by gcc during compilation and doesn't change
- * at run-time.
- */
-struct gcov_fn_info {
-       unsigned int ident;
-       unsigned int checksum;
-       unsigned int n_ctrs[0];
-};
-
-/**
- * struct gcov_ctr_info - profiling data per counter type
- * @num: number of counter values for this type
- * @values: array of counter values for this type
- * @merge: merge function for counter values of this type (unused)
- *
- * This data is generated by gcc during compilation and doesn't change
- * at run-time with the exception of the values array.
- */
-struct gcov_ctr_info {
-       unsigned int    num;
-       gcov_type       *values;
-       void            (*merge)(gcov_type *, unsigned int);
-};
+/* Opaque gcov_info. The gcov structures can change as for example in gcc 4.7 so
+ * we cannot use full definition here and they need to be placed in gcc specific
+ * implementation of gcov. This also means no direct access to the members in
+ * generic code and usage of the interface below.*/
+struct gcov_info;
 
-/**
- * struct gcov_info - profiling data per object file
- * @version: gcov version magic indicating the gcc version used for compilation
- * @next: list head for a singly-linked list
- * @stamp: time stamp
- * @filename: name of the associated gcov data file
- * @n_functions: number of instrumented functions
- * @functions: function data
- * @ctr_mask: mask specifying which counter types are active
- * @counts: counter data per counter type
- *
- * This data is generated by gcc during compilation and doesn't change
- * at run-time with the exception of the next pointer.
- */
-struct gcov_info {
-       unsigned int                    version;
-       struct gcov_info                *next;
-       unsigned int                    stamp;
-       const char                      *filename;
-       unsigned int                    n_functions;
-       const struct gcov_fn_info       *functions;
-       unsigned int                    ctr_mask;
-       struct gcov_ctr_info            counts[0];
-};
+/* Interface to access gcov_info data  */
+const char *gcov_info_filename(struct gcov_info *info);
+unsigned int gcov_info_version(struct gcov_info *info);
+struct gcov_info *gcov_info_next(struct gcov_info *info);
+void gcov_info_link(struct gcov_info *info);
+void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info);
 
 /* Base interface. */
 enum gcov_action {
index 99b53d1..b65d45c 100644 (file)
@@ -103,7 +103,7 @@ static int groups_from_user(struct group_info *group_info,
 }
 
 /* a simple Shell sort */
-static void groups_sort(struct group_info *group_info)
+void groups_sort(struct group_info *group_info)
 {
        int base, max, stride;
        int gidsetsize = group_info->ngroups;
@@ -130,6 +130,7 @@ static void groups_sort(struct group_info *group_info)
                stride /= 3;
        }
 }
+EXPORT_SYMBOL(groups_sort);
 
 /* a simple bsearch */
 int groups_search(const struct group_info *group_info, gid_t grp)
@@ -164,7 +165,6 @@ int groups_search(const struct group_info *group_info, gid_t grp)
 int set_groups(struct cred *new, struct group_info *group_info)
 {
        put_group_info(new->group_info);
-       groups_sort(group_info);
        get_group_info(group_info);
        new->group_info = group_info;
        return 0;
@@ -247,6 +247,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
                return retval;
        }
 
+       groups_sort(group_info);
        retval = set_current_groups(group_info);
        put_group_info(group_info);
 
index 6918c03..00ebf9a 100644 (file)
@@ -657,6 +657,7 @@ static int hrtimer_reprogram(struct hrtimer *timer,
 static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)
 {
        base->expires_next.tv64 = KTIME_MAX;
+       base->hang_detected = 0;
        base->hres_active = 0;
 }
 
@@ -1199,7 +1200,12 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
 
        cpu_base = &__raw_get_cpu_var(hrtimer_bases);
 
-       if (clock_id == CLOCK_REALTIME && mode != HRTIMER_MODE_ABS)
+       /*
+        * POSIX magic: Relative CLOCK_REALTIME timers are not affected by
+        * clock modifications, so they needs to become CLOCK_MONOTONIC to
+        * ensure POSIX compliance.
+        */
+       if (clock_id == CLOCK_REALTIME && mode & HRTIMER_MODE_REL)
                clock_id = CLOCK_MONOTONIC;
 
        base = hrtimer_clockid_to_base(clock_id);
@@ -1702,6 +1708,7 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
                timerqueue_init_head(&cpu_base->clock_base[i].active);
        }
 
+       cpu_base->active_bases = 0;
        hrtimer_init_hres(cpu_base);
 }
 
index f497ff7..a8cad80 100644 (file)
@@ -182,9 +182,7 @@ static void free_desc(unsigned int irq)
         * sparse tree we can free it. Access in proc will fail to
         * lookup the descriptor.
         */
-       mutex_lock(&sparse_irq_lock);
        delete_irq_desc(irq);
-       mutex_unlock(&sparse_irq_lock);
 
        free_masks(desc);
        free_percpu(desc->kstat_irqs);
@@ -201,19 +199,14 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node,
                desc = alloc_desc(start + i, node, owner);
                if (!desc)
                        goto err;
-               mutex_lock(&sparse_irq_lock);
                irq_insert_desc(start + i, desc);
-               mutex_unlock(&sparse_irq_lock);
        }
+       bitmap_set(allocated_irqs, start, cnt);
        return start;
 
 err:
        for (i--; i >= 0; i--)
                free_desc(start + i);
-
-       mutex_lock(&sparse_irq_lock);
-       bitmap_clear(allocated_irqs, start, cnt);
-       mutex_unlock(&sparse_irq_lock);
        return -ENOMEM;
 }
 
@@ -305,6 +298,7 @@ static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
 
                desc->owner = owner;
        }
+       bitmap_set(allocated_irqs, start, cnt);
        return start;
 }
 
@@ -345,10 +339,10 @@ void irq_free_descs(unsigned int from, unsigned int cnt)
        if (from >= nr_irqs || (from + cnt) > nr_irqs)
                return;
 
+       mutex_lock(&sparse_irq_lock);
        for (i = 0; i < cnt; i++)
                free_desc(from + i);
 
-       mutex_lock(&sparse_irq_lock);
        bitmap_clear(allocated_irqs, from, cnt);
        mutex_unlock(&sparse_irq_lock);
 }
@@ -385,19 +379,15 @@ __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
                                           from, cnt, 0);
        ret = -EEXIST;
        if (irq >=0 && start != irq)
-               goto err;
+               goto unlock;
 
        if (start + cnt > nr_irqs) {
                ret = irq_expand_nr_irqs(start + cnt);
                if (ret)
-                       goto err;
+                       goto unlock;
        }
-
-       bitmap_set(allocated_irqs, start, cnt);
-       mutex_unlock(&sparse_irq_lock);
-       return alloc_descs(start, cnt, node, owner);
-
-err:
+       ret = alloc_descs(start, cnt, node, owner);
+unlock:
        mutex_unlock(&sparse_irq_lock);
        return ret;
 }
index a4f561a..ec17486 100644 (file)
@@ -53,6 +53,9 @@
 #include <asm/cacheflush.h>
 #include <asm/errno.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_RETPOLINE
+#include <asm/nospec-branch.h>
+#endif
 
 #define KPROBE_HASH_BITS 6
 #define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
@@ -99,6 +102,11 @@ static struct kprobe_blackpoint kprobe_blacklist[] = {
        {"irq_entries_start",},
        {"common_interrupt",},
        {"mcount",},    /* mcount can be called from everywhere */
+#ifdef CONFIG_RETPOLINE
+       {"__indirect_thunk_start",
+        /* Linker scripts can't set symbol sizes */
+        .range = (size_t)__indirect_thunk_size},
+#endif
        {NULL}    /* Terminator */
 };
 
@@ -1986,7 +1994,7 @@ static int __init init_kprobes(void)
                                &size, &offset, &modname, namebuf);
                if (!symbol_name)
                        kb->range = 0;
-               else
+               else if (size)
                        kb->range = size;
        }
 
index 8d2f37d..7bc1aed 100644 (file)
@@ -2335,6 +2335,15 @@ static inline void kmemleak_load_module(const struct module *mod,
 }
 #endif
 
+static void check_modinfo_retpoline(struct module *mod, struct load_info *info)
+{
+       if (retpoline_module_ok(get_modinfo(info, "retpoline")))
+               return;
+
+       pr_warn("%s: loading module not compiled with retpoline compiler.\n",
+               mod->name);
+}
+
 /* Sets info->hdr and info->len. */
 static int copy_and_check(struct load_info *info,
                          const void __user *umod, unsigned long len,
@@ -2495,6 +2504,8 @@ static int check_modinfo(struct module *mod, struct load_info *info)
        if (!get_modinfo(info, "intree"))
                add_taint_module(mod, TAINT_OOT_MODULE);
 
+       check_modinfo_retpoline(mod, info);
+
        if (get_modinfo(info, "staging")) {
                add_taint_module(mod, TAINT_CRAP);
                printk(KERN_WARNING "%s: module is from the staging directory,"
index 65aae11..48a806f 100644 (file)
@@ -578,7 +578,7 @@ EXPORT_SYMBOL(__kernel_param_unlock);
 /*
  * add_sysfs_param - add a parameter to sysfs
  * @mk: struct module_kobject
- * @kparam: the actual parameter definition to add to sysfs
+ * @kp: the actual parameter definition to add to sysfs
  * @name: name of parameter
  *
  * Create a kobject if for a (per-module) parameter if mp NULL, and
index 6766183..3130973 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/export.h>
+#include <linux/nospec.h>
 
 /*
  * Management arrays for POSIX timers.  Timers are kept in slab memory
@@ -440,17 +441,22 @@ static struct pid *good_sigevent(sigevent_t * event)
 {
        struct task_struct *rtn = current->group_leader;
 
-       if ((event->sigev_notify & SIGEV_THREAD_ID ) &&
-               (!(rtn = find_task_by_vpid(event->sigev_notify_thread_id)) ||
-                !same_thread_group(rtn, current) ||
-                (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL))
+       switch (event->sigev_notify) {
+       case SIGEV_SIGNAL | SIGEV_THREAD_ID:
+               rtn = find_task_by_vpid(event->sigev_notify_thread_id);
+               if (!rtn || !same_thread_group(rtn, current))
+                       return NULL;
+               /* FALLTHRU */
+       case SIGEV_SIGNAL:
+       case SIGEV_THREAD:
+               if (event->sigev_signo <= 0 || event->sigev_signo > SIGRTMAX)
+                       return NULL;
+               /* FALLTHRU */
+       case SIGEV_NONE:
+               return task_pid(rtn);
+       default:
                return NULL;
-
-       if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) &&
-           ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX)))
-               return NULL;
-
-       return task_pid(rtn);
+       }
 }
 
 void posix_timers_register_clock(const clockid_t clock_id,
@@ -515,13 +521,21 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
 
 static struct k_clock *clockid_to_kclock(const clockid_t id)
 {
-       if (id < 0)
+       clockid_t idx = id;
+       struct k_clock *kc;
+
+       if (id < 0) {
                return (id & CLOCKFD_MASK) == CLOCKFD ?
                        &clock_posix_dynamic : &clock_posix_cpu;
+       }
+
+       if (id >= ARRAY_SIZE(posix_clocks))
+               return NULL;
 
-       if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres)
+       kc = &posix_clocks[array_index_nospec(idx, ARRAY_SIZE(posix_clocks))];
+       if (!kc->clock_getres)
                return NULL;
-       return &posix_clocks[id];
+       return kc;
 }
 
 static int common_timer_create(struct k_itimer *new_timer)
@@ -683,16 +697,17 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
 {
        ktime_t now, remaining, iv;
        struct hrtimer *timer = &timr->it.real.timer;
+       bool sig_none;
 
        memset(cur_setting, 0, sizeof(struct itimerspec));
 
+       sig_none = timr->it_sigev_notify == SIGEV_NONE;
        iv = timr->it.real.interval;
 
        /* interval timer ? */
        if (iv.tv64)
                cur_setting->it_interval = ktime_to_timespec(iv);
-       else if (!hrtimer_active(timer) &&
-                (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
+       else if (!hrtimer_active(timer) && !sig_none)
                return;
 
        now = timer->base->get_time();
@@ -702,8 +717,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
         * timer move the expiry time forward by intervals, so
         * expiry is > now.
         */
-       if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING ||
-           (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE))
+       if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING || sig_none))
                timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv);
 
        remaining = __hrtimer_expires_remaining_adjusted(timer, now);
@@ -713,7 +727,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
                 * A single shot SIGEV_NONE timer must return 0, when
                 * it is expired !
                 */
-               if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE)
+               if (!sig_none)
                        cur_setting->it_value.tv_nsec = 1;
        } else
                cur_setting->it_value = ktime_to_timespec(remaining);
@@ -811,7 +825,7 @@ common_timer_set(struct k_itimer *timr, int flags,
        timr->it.real.interval = timespec_to_ktime(new_setting->it_interval);
 
        /* SIGEV_NONE timers are not queued ! See common_timer_get */
-       if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) {
+       if (timr->it_sigev_notify == SIGEV_NONE) {
                /* Setup correct expiry time for relative timers */
                if (mode == HRTIMER_MODE_REL) {
                        hrtimer_add_expires(timer, timer->base->get_time());
index b50cded..f05d14c 100644 (file)
@@ -77,12 +77,11 @@ void __ptrace_unlink(struct task_struct *child)
 {
        BUG_ON(!child->ptrace);
 
-       child->ptrace = 0;
        child->parent = child->real_parent;
        list_del_init(&child->ptrace_entry);
 
        spin_lock(&child->sighand->siglock);
-
+       child->ptrace = 0;
        /*
         * Clear all pending traps and TRAPPING.  TRAPPING should be
         * cleared regardless of JOBCTL_STOP_PENDING.  Do it explicitly.
index e8cd202..bf8df08 100644 (file)
@@ -166,7 +166,7 @@ static struct rchan_buf *relay_create_buf(struct rchan *chan)
 {
        struct rchan_buf *buf;
 
-       if (chan->n_subbufs > UINT_MAX / sizeof(size_t *))
+       if (chan->n_subbufs > KMALLOC_MAX_SIZE / sizeof(size_t *))
                return NULL;
 
        buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL);
index 3b0e0dc..af9a268 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/init.h>
 #include <linux/uaccess.h>
 #include <linux/highmem.h>
-#include <asm/mmu_context.h>
+#include <linux/mmu_context.h>
 #include <linux/interrupt.h>
 #include <linux/capability.h>
 #include <linux/completion.h>
@@ -3331,7 +3331,7 @@ context_switch(struct rq *rq, struct task_struct *prev,
                atomic_inc(&oldmm->mm_count);
                enter_lazy_tlb(oldmm, next);
        } else
-               switch_mm(oldmm, mm, next);
+               switch_mm_irqs_off(oldmm, mm, next);
 
        if (!prev->mm) {
                prev->active_mm = NULL;
@@ -7480,7 +7480,7 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu)
 
        cpumask_clear(covered);
 
-       for_each_cpu(i, span) {
+       for_each_cpu_wrap(i, span, cpu) {
                struct cpumask *sg_span;
 
                if (cpumask_test_cpu(i, covered))
index cb0d862..59c254d 100644 (file)
@@ -329,7 +329,8 @@ static struct ctl_table kern_table[] = {
                .data           = &sysctl_sched_time_avg,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one,
        },
        {
                .procname       = "sched_shares_window",
index 2ad29a2..fa85588 100644 (file)
@@ -296,7 +296,7 @@ static void blk_trace_cleanup(struct blk_trace *bt)
                blk_unregister_tracepoints();
 }
 
-int blk_trace_remove(struct request_queue *q)
+static int __blk_trace_remove(struct request_queue *q)
 {
        struct blk_trace *bt;
 
@@ -309,6 +309,17 @@ int blk_trace_remove(struct request_queue *q)
 
        return 0;
 }
+
+int blk_trace_remove(struct request_queue *q)
+{
+       int ret;
+
+       mutex_lock(&q->blk_trace_mutex);
+       ret = __blk_trace_remove(q);
+       mutex_unlock(&q->blk_trace_mutex);
+
+       return ret;
+}
 EXPORT_SYMBOL_GPL(blk_trace_remove);
 
 static int blk_dropped_open(struct inode *inode, struct file *filp)
@@ -538,9 +549,8 @@ err:
        return ret;
 }
 
-int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
-                   struct block_device *bdev,
-                   char __user *arg)
+static int __blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
+                            struct block_device *bdev, char __user *arg)
 {
        struct blk_user_trace_setup buts;
        int ret;
@@ -559,6 +569,19 @@ int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
        }
        return 0;
 }
+
+int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
+                   struct block_device *bdev,
+                   char __user *arg)
+{
+       int ret;
+
+       mutex_lock(&q->blk_trace_mutex);
+       ret = __blk_trace_setup(q, name, dev, bdev, arg);
+       mutex_unlock(&q->blk_trace_mutex);
+
+       return ret;
+}
 EXPORT_SYMBOL_GPL(blk_trace_setup);
 
 #if defined(CONFIG_COMPAT) && defined(CONFIG_X86_64)
@@ -596,7 +619,7 @@ static int compat_blk_trace_setup(struct request_queue *q, char *name,
 }
 #endif
 
-int blk_trace_startstop(struct request_queue *q, int start)
+static int __blk_trace_startstop(struct request_queue *q, int start)
 {
        int ret;
        struct blk_trace *bt = q->blk_trace;
@@ -629,8 +652,25 @@ int blk_trace_startstop(struct request_queue *q, int start)
 
        return ret;
 }
+
+int blk_trace_startstop(struct request_queue *q, int start)
+{
+       int ret;
+
+       mutex_lock(&q->blk_trace_mutex);
+       ret = __blk_trace_startstop(q, start);
+       mutex_unlock(&q->blk_trace_mutex);
+
+       return ret;
+}
 EXPORT_SYMBOL_GPL(blk_trace_startstop);
 
+/*
+ * When reading or writing the blktrace sysfs files, the references to the
+ * opened sysfs or device files should prevent the underlying block device
+ * from being removed. So no further delete protection is really needed.
+ */
+
 /**
  * blk_trace_ioctl: - handle the ioctls associated with tracing
  * @bdev:      the block device
@@ -648,12 +688,12 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
        if (!q)
                return -ENXIO;
 
-       mutex_lock(&bdev->bd_mutex);
+       mutex_lock(&q->blk_trace_mutex);
 
        switch (cmd) {
        case BLKTRACESETUP:
                bdevname(bdev, b);
-               ret = blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
+               ret = __blk_trace_setup(q, b, bdev->bd_dev, bdev, arg);
                break;
 #if defined(CONFIG_COMPAT) && defined(CONFIG_X86_64)
        case BLKTRACESETUP32:
@@ -664,17 +704,17 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
        case BLKTRACESTART:
                start = 1;
        case BLKTRACESTOP:
-               ret = blk_trace_startstop(q, start);
+               ret = __blk_trace_startstop(q, start);
                break;
        case BLKTRACETEARDOWN:
-               ret = blk_trace_remove(q);
+               ret = __blk_trace_remove(q);
                break;
        default:
                ret = -ENOTTY;
                break;
        }
 
-       mutex_unlock(&bdev->bd_mutex);
+       mutex_unlock(&q->blk_trace_mutex);
        return ret;
 }
 
@@ -685,10 +725,14 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
  **/
 void blk_trace_shutdown(struct request_queue *q)
 {
+       mutex_lock(&q->blk_trace_mutex);
+
        if (q->blk_trace) {
-               blk_trace_startstop(q, 0);
-               blk_trace_remove(q);
+               __blk_trace_startstop(q, 0);
+               __blk_trace_remove(q);
        }
+
+       mutex_unlock(&q->blk_trace_mutex);
 }
 
 /*
@@ -1660,7 +1704,7 @@ static ssize_t sysfs_blk_trace_attr_show(struct device *dev,
        if (q == NULL)
                goto out_bdput;
 
-       mutex_lock(&bdev->bd_mutex);
+       mutex_lock(&q->blk_trace_mutex);
 
        if (attr == &dev_attr_enable) {
                ret = sprintf(buf, "%u\n", !!q->blk_trace);
@@ -1679,7 +1723,7 @@ static ssize_t sysfs_blk_trace_attr_show(struct device *dev,
                ret = sprintf(buf, "%llu\n", q->blk_trace->end_lba);
 
 out_unlock_bdev:
-       mutex_unlock(&bdev->bd_mutex);
+       mutex_unlock(&q->blk_trace_mutex);
 out_bdput:
        bdput(bdev);
 out:
@@ -1721,7 +1765,7 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
        if (q == NULL)
                goto out_bdput;
 
-       mutex_lock(&bdev->bd_mutex);
+       mutex_lock(&q->blk_trace_mutex);
 
        if (attr == &dev_attr_enable) {
                if (value)
@@ -1747,7 +1791,7 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
        }
 
 out_unlock_bdev:
-       mutex_unlock(&bdev->bd_mutex);
+       mutex_unlock(&q->blk_trace_mutex);
 out_bdput:
        bdput(bdev);
 out:
index d6899c4..c9954f3 100644 (file)
@@ -360,6 +360,8 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_data);
 /* Missed count stored at end */
 #define RB_MISSED_STORED       (1 << 30)
 
+#define RB_MISSED_FLAGS                (RB_MISSED_EVENTS|RB_MISSED_STORED)
+
 struct buffer_data_page {
        u64              time_stamp;    /* page time stamp */
        local_t          commit;        /* write committed index */
@@ -411,7 +413,9 @@ static void rb_init_page(struct buffer_data_page *bpage)
  */
 size_t ring_buffer_page_len(void *page)
 {
-       return local_read(&((struct buffer_data_page *)page)->commit)
+       struct buffer_data_page *bpage = page;
+
+       return (local_read(&bpage->commit) & ~RB_MISSED_FLAGS)
                + BUF_PAGE_HDR_SIZE;
 }
 
index 2ec1a38..367b365 100644 (file)
@@ -920,7 +920,7 @@ static struct notifier_block trace_probe_module_nb = {
 };
 
 /* Split symbol and offset. */
-static int split_symbol_offset(char *symbol, unsigned long *offset)
+static int split_symbol_offset(char *symbol, long *offset)
 {
        char *tmp;
        int ret;
@@ -928,10 +928,9 @@ static int split_symbol_offset(char *symbol, unsigned long *offset)
        if (!offset)
                return -EINVAL;
 
-       tmp = strchr(symbol, '+');
+       tmp = strpbrk(symbol, "+-");
        if (tmp) {
-               /* skip sign because strict_strtol doesn't accept '+' */
-               ret = strict_strtoul(tmp + 1, 0, offset);
+               ret = kstrtol(tmp, 0, offset);
                if (ret)
                        return ret;
                *tmp = '\0';
@@ -1165,7 +1164,7 @@ static int create_trace_probe(int argc, char **argv)
        int is_return = 0, is_delete = 0;
        char *symbol = NULL, *event = NULL, *group = NULL;
        char *arg;
-       unsigned long offset = 0;
+       long offset = 0;
        void *addr = NULL;
        char buf[MAX_EVENT_NAME_LEN];
 
@@ -1238,7 +1237,7 @@ static int create_trace_probe(int argc, char **argv)
                symbol = argv[1];
                /* TODO: support .init module functions */
                ret = split_symbol_offset(symbol, &offset);
-               if (ret) {
+               if (ret || offset < 0 || offset > UINT_MAX) {
                        pr_info("Failed to parse either an address or a symbol.\n");
                        return ret;
                }
index 09fd98a..4f2845c 100644 (file)
@@ -257,7 +257,7 @@ static int trace_selftest_ops(int cnt)
        if (trace_selftest_test_probe3_cnt != 3)
                goto out_free;
        if (trace_selftest_test_global_cnt == 0)
-               goto out;
+               goto out_free;
        if (trace_selftest_test_dyn_cnt == 0)
                goto out_free;
 
index 51c6e89..204340b 100644 (file)
@@ -203,6 +203,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist)
                return retval;
        }
 
+       groups_sort(group_info);
        retval = set_current_groups(group_info);
        put_group_info(group_info);
 
index af3e581..7018459 100644 (file)
@@ -75,6 +75,38 @@ int cpumask_any_but(const struct cpumask *mask, unsigned int cpu)
        return i;
 }
 
+/**
+ * cpumask_next_wrap - helper to implement for_each_cpu_wrap
+ * @n: the cpu prior to the place to search
+ * @mask: the cpumask pointer
+ * @start: the start point of the iteration
+ * @wrap: assume @n crossing @start terminates the iteration
+ *
+ * Returns >= nr_cpu_ids on completion
+ *
+ * Note: the @wrap argument is required for the start condition when
+ * we cannot assume @start is set in @mask.
+ */
+int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap)
+{
+       int next;
+
+again:
+       next = cpumask_next(n, mask);
+
+       if (wrap && n < start && next >= start) {
+               return nr_cpumask_bits;
+
+       } else if (next >= nr_cpumask_bits) {
+               wrap = true;
+               n = -1;
+               goto again;
+       }
+
+       return next;
+}
+EXPORT_SYMBOL(cpumask_next_wrap);
+
 /* These are not inline because of header tangles. */
 #ifdef CONFIG_CPUMASK_OFFSTACK
 /**
index 8023cc2..1b04121 100644 (file)
@@ -1042,7 +1042,6 @@ struct page *follow_trans_huge_pmd(struct mm_struct *mm,
        if (flags & FOLL_GET)
                get_page_foll(page);
 
-out:
        return page;
 }
 
index 031f036..426ee33 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/bootmem.h>
 #include <linux/sysfs.h>
 #include <linux/slab.h>
+#include <linux/mmdebug.h>
 #include <linux/rmap.h>
 #include <linux/swap.h>
 #include <linux/swapops.h>
@@ -3098,6 +3099,14 @@ int hugetlb_reserve_pages(struct inode *inode,
        struct hstate *h = hstate_inode(inode);
        struct hugepage_subpool *spool = subpool_inode(inode);
 
+       /* This should never happen */
+       if (from > to) {
+#ifdef CONFIG_DEBUG_VM
+               WARN(1, "%s called with a negative range\n", __func__);
+#endif
+               return -EINVAL;
+       }
+
        /*
         * Only apply hugepage reservation if asked. At fault time, an
         * attempt will be made for VM_NORESERVE to allocate a page
index 11c0225..42f4fd5 100644 (file)
@@ -128,6 +128,7 @@ static long madvise_willneed(struct vm_area_struct * vma,
 {
        struct file *file = vma->vm_file;
 
+       *prev = vma;
        if (!file)
                return -EBADF;
 
@@ -136,7 +137,6 @@ static long madvise_willneed(struct vm_area_struct * vma,
                return 0;
        }
 
-       *prev = vma;
        start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
        if (end > vma->vm_end)
                end = vma->vm_end;
index c8e4ebe..b056dc2 100644 (file)
@@ -885,11 +885,6 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,
                *policy |= (pol->flags & MPOL_MODE_FLAGS);
        }
 
-       if (vma) {
-               up_read(&current->mm->mmap_sem);
-               vma = NULL;
-       }
-
        err = 0;
        if (nmask) {
                if (mpol_store_user_nodemask(pol)) {
@@ -2024,6 +2019,9 @@ int __mpol_equal(struct mempolicy *a, struct mempolicy *b)
        case MPOL_INTERLEAVE:
                return nodes_equal(a->v.nodes, b->v.nodes);
        case MPOL_PREFERRED:
+               /* a's ->flags is the same as b's */
+               if (a->flags & MPOL_F_LOCAL)
+                       return true;
                return a->v.preferred_node == b->v.preferred_node;
        default:
                BUG();
index a34afb8..69a307b 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1731,7 +1731,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
 
        /* Guard against exceeding limits of the address space. */
        address &= PAGE_MASK;
-       if (address >= TASK_SIZE)
+       if (address >= (TASK_SIZE & PAGE_MASK))
                return -ENOMEM;
        address += PAGE_SIZE;
 
@@ -1743,7 +1743,8 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
                gap_addr = TASK_SIZE;
 
        next = vma->vm_next;
-       if (next && next->vm_start < gap_addr) {
+       if (next && next->vm_start < gap_addr &&
+                       (next->vm_flags & (VM_WRITE|VM_READ|VM_EXEC))) {
                if (!(next->vm_flags & VM_GROWSUP))
                        return -ENOMEM;
                /* Check that both stack segments have the same anon_vma? */
@@ -1802,7 +1803,8 @@ int expand_downwards(struct vm_area_struct *vma,
        if (gap_addr > address)
                return -ENOMEM;
        prev = vma->vm_prev;
-       if (prev && prev->vm_end > gap_addr) {
+       if (prev && prev->vm_end > gap_addr &&
+                       (prev->vm_flags & (VM_WRITE|VM_READ|VM_EXEC))) {
                if (!(prev->vm_flags & VM_GROWSDOWN))
                        return -ENOMEM;
                /* Check that both stack segments have the same anon_vma? */
index cf332bc..7454167 100644 (file)
@@ -4,9 +4,9 @@
  */
 
 #include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/mmu_context.h>
 #include <linux/export.h>
-#include <linux/sched.h>
 
 #include <asm/mmu_context.h>
 
index 5a688a2..ac64860 100644 (file)
@@ -92,13 +92,15 @@ static inline void change_pmd_range(struct vm_area_struct *vma, pud_t *pud,
                        if (next - addr != HPAGE_PMD_SIZE)
                                split_huge_page_pmd(vma->vm_mm, pmd);
                        else if (change_huge_pmd(vma, pmd, addr, newprot))
-                               continue;
+                               goto next;
                        /* fall through */
                }
                if (pmd_none_or_clear_bad(pmd))
-                       continue;
+                       goto next;
                change_pte_range(vma->vm_mm, pmd, addr, next, newprot,
                                 dirty_accountable);
+next:
+               cond_resched();
        } while (pmd++, addr = next, addr != end);
 }
 
index 092c992..5961c93 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/prefetch.h>
 #include <linux/migrate.h>
 #include <linux/page-debug-flags.h>
+#include <linux/nmi.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -1241,9 +1242,14 @@ void drain_all_pages(void)
 
 #ifdef CONFIG_HIBERNATION
 
+/*
+ * Touch the watchdog for every WD_PAGE_COUNT pages.
+ */
+#define WD_PAGE_COUNT  (128*1024)
+
 void mark_free_pages(struct zone *zone)
 {
-       unsigned long pfn, max_zone_pfn;
+       unsigned long pfn, max_zone_pfn, page_count = WD_PAGE_COUNT;
        unsigned long flags;
        int order, t;
        struct list_head *curr;
@@ -1258,6 +1264,11 @@ void mark_free_pages(struct zone *zone)
                if (pfn_valid(pfn)) {
                        struct page *page = pfn_to_page(pfn);
 
+                       if (!--page_count) {
+                               touch_nmi_watchdog();
+                               page_count = WD_PAGE_COUNT;
+                       }
+
                        if (!swsusp_page_is_forbidden(page))
                                swsusp_unset_page_free(page);
                }
@@ -1267,8 +1278,13 @@ void mark_free_pages(struct zone *zone)
                        unsigned long i;
 
                        pfn = page_to_pfn(list_entry(curr, struct page, lru));
-                       for (i = 0; i < (1UL << order); i++)
+                       for (i = 0; i < (1UL << order); i++) {
+                               if (!--page_count) {
+                                       touch_nmi_watchdog();
+                                       page_count = WD_PAGE_COUNT;
+                               }
                                swsusp_set_page_free(pfn_to_page(pfn + i));
+                       }
                }
        }
        spin_unlock_irqrestore(&zone->lock, flags);
index aea5e42..bb39255 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3255,7 +3255,7 @@ static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
 
 #ifdef CONFIG_NUMA
 /*
- * Try allocating on another node if PF_SPREAD_SLAB|PF_MEMPOLICY.
+ * Try allocating on another node if PFA_SPREAD_SLAB|PF_MEMPOLICY.
  *
  * If we are in_interrupt, then process context, including cpusets and
  * mempolicy, may not apply and should not be used for allocation policy.
@@ -3496,7 +3496,7 @@ __do_cache_alloc(struct kmem_cache *cache, gfp_t flags)
 {
        void *objp;
 
-       if (unlikely(current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY))) {
+       if (unlikely((current->flags & PF_MEMPOLICY) || cpuset_do_slab_mem_spread())) {
                objp = alternate_node_alloc(cache, flags);
                if (objp)
                        goto out;
index a3b1578..f7c0e86 100644 (file)
@@ -1067,6 +1067,7 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file)
 
                if (PageDirty(page)) {
                        struct address_space *mapping;
+                       bool migrate_dirty;
 
                        /* ISOLATE_CLEAN means only clean pages */
                        if (mode & ISOLATE_CLEAN)
@@ -1075,10 +1076,19 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode, int file)
                        /*
                         * Only pages without mappings or that have a
                         * ->migratepage callback are possible to migrate
-                        * without blocking
+                        * without blocking. However, we can be racing with
+                        * truncation so it's necessary to lock the page
+                        * to stabilise the mapping as truncation holds
+                        * the page lock until after the page is removed
+                        * from the page cache.
                         */
+                       if (!trylock_page(page))
+                               return ret;
+
                        mapping = page_mapping(page);
-                       if (mapping && !mapping->a_ops->migratepage)
+                       migrate_dirty = mapping && mapping->a_ops->migratepage;
+                       unlock_page(page);
+                       if (!migrate_dirty)
                                return ret;
                }
        }
index 901e631..0982da3 100644 (file)
@@ -702,6 +702,7 @@ const char * const vmstat_text[] = {
        "nr_slab_unreclaimable",
        "nr_page_table_pages",
        "nr_kernel_stack",
+       "nr_overhead",
        "nr_unstable",
        "nr_bounce",
        "nr_vmscan_write",
@@ -893,7 +894,7 @@ static void pagetypeinfo_showblockcount_print(struct seq_file *m,
        seq_putc(m, '\n');
 }
 
-/* Print out the free pages at each order for each migratetype */
+/* Print out the number of pageblocks for each migratetype */
 static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg)
 {
        int mtype;
index 963f285..ff24039 100644 (file)
@@ -132,11 +132,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
                call_rcu(&grp->rcu, vlan_rcu_free);
        }
 
-       /* Take it out of our own structures, but be sure to interlock with
-        * HW accelerating devices or SW vlan input packet processing if
-        * VLAN is not 0 (leave it there for 802.1p).
-        */
-       if (vlan_id && (real_dev->features & NETIF_F_HW_VLAN_FILTER))
+       if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
                ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id);
 
        /* Get rid of the vlan's reference to real_dev */
index 87173bb..3e61ba1 100644 (file)
@@ -740,8 +740,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
                goto reterr;
        }
        /* Wait for the response */
-       err = wait_event_interruptible(*req->wq,
-                                      req->status >= REQ_STATUS_RCVD);
+       err = wait_event_killable(*req->wq, req->status >= REQ_STATUS_RCVD);
 
        if (req->status == REQ_STATUS_ERROR) {
                P9_DPRINTK(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
index 55f0c09..a107265 100644 (file)
@@ -163,7 +163,8 @@ static void req_done(struct virtqueue *vq)
                P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
                req = p9_tag_lookup(chan->client, rc->tag);
                req->status = REQ_STATUS_RCVD;
-               p9_client_cb(chan->client, req);
+               if (len)
+                       p9_client_cb(chan->client, req);
        }
 }
 
@@ -276,8 +277,8 @@ req_retry:
                if (err == -ENOSPC) {
                        chan->ring_bufs_avail = 0;
                        spin_unlock_irqrestore(&chan->lock, flags);
-                       err = wait_event_interruptible(*chan->vc_wq,
-                                                       chan->ring_bufs_avail);
+                       err = wait_event_killable(*chan->vc_wq,
+                                                 chan->ring_bufs_avail);
                        if (err  == -ERESTARTSYS)
                                return err;
 
@@ -309,7 +310,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
                 * Other zc request to finish here
                 */
                if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
-                       err = wait_event_interruptible(vp_wq,
+                       err = wait_event_killable(vp_wq,
                              (atomic_read(&vp_pinned) < chan->p9_max_pages));
                        if (err == -ERESTARTSYS)
                                return err;
@@ -419,8 +420,8 @@ req_retry_pinned:
                if (err == -ENOSPC) {
                        chan->ring_bufs_avail = 0;
                        spin_unlock_irqrestore(&chan->lock, flags);
-                       err = wait_event_interruptible(*chan->vc_wq,
-                                                      chan->ring_bufs_avail);
+                       err = wait_event_killable(*chan->vc_wq,
+                                                 chan->ring_bufs_avail);
                        if (err  == -ERESTARTSYS)
                                goto err_out;
 
@@ -438,8 +439,7 @@ req_retry_pinned:
        virtqueue_kick(chan->vq);
        spin_unlock_irqrestore(&chan->lock, flags);
        P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
-       err = wait_event_interruptible(*req->wq,
-                                      req->status >= REQ_STATUS_RCVD);
+       err = wait_event_killable(*req->wq, req->status >= REQ_STATUS_RCVD);
        /*
         * Non kernel buffers are pinned, unpin them
         */
index 3512e25..b74e673 100644 (file)
@@ -760,10 +760,10 @@ static int bat_ogm_calc_tq(struct orig_node *orig_node,
        orig_node->last_valid = jiffies;
 
        /* find packet count of corresponding one hop neighbor */
-       spin_lock_bh(&orig_node->ogm_cnt_lock);
+       spin_lock_bh(&orig_neigh_node->ogm_cnt_lock);
        orig_eq_count = orig_neigh_node->bcast_own_sum[if_incoming->if_num];
        neigh_rq_count = neigh_node->real_packet_count;
-       spin_unlock_bh(&orig_node->ogm_cnt_lock);
+       spin_unlock_bh(&orig_neigh_node->ogm_cnt_lock);
 
        /* pay attention to not get a value bigger than 100 % */
        total_count = (orig_eq_count > neigh_rq_count ?
index a8f4627..dbe1a8c 100644 (file)
@@ -733,12 +733,7 @@ void interface_rx(struct net_device *soft_iface,
 
        /* skb->dev & skb->pkt_type are set here */
        skb->protocol = eth_type_trans(skb, soft_iface);
-
-       /* should not be necessary anymore as we use skb_pull_rcsum()
-        * TODO: please verify this and remove this TODO
-        * -- Dec 21st 2009, Simon Wunderlich */
-
-/*     skb->ip_summed = CHECKSUM_UNNECESSARY;*/
+       skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
 
        bat_priv->stats.rx_packets++;
        bat_priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr);
index 1eea820..1bafa4c 100644 (file)
@@ -560,6 +560,9 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
 
        BT_DBG("");
 
+       if (!l2cap_is_socket(sock))
+               return -EBADFD;
+
        baswap((void *) dst, &bt_sk(sock->sk)->dst);
        baswap((void *) src, &bt_sk(sock->sk)->src);
 
index 5a6e634..f129e13 100644 (file)
@@ -336,6 +336,9 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
 
        BT_DBG("");
 
+       if (!l2cap_is_socket(sock))
+               return -EBADFD;
+
        session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL);
        if (!session)
                return -ENOMEM;
index 0274157..b91d354 100644 (file)
@@ -972,6 +972,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
 
        BT_DBG("");
 
+       if (!l2cap_is_socket(ctrl_sock) || !l2cap_is_socket(intr_sock))
+               return -EINVAL;
        if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
                        bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
                return -ENOTUNIQ;
index 6c89d61..d47a197 100644 (file)
@@ -38,6 +38,12 @@ static const struct proto_ops l2cap_sock_ops;
 static void l2cap_sock_init(struct sock *sk, struct sock *parent);
 static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
 
+bool l2cap_is_socket(struct socket *sock)
+{
+       return sock && sock->ops == &l2cap_sock_ops;
+}
+EXPORT_SYMBOL(l2cap_is_socket);
+
 static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 {
        struct sock *sk = sock->sk;
index 99a48a3..8b29608 100644 (file)
@@ -215,6 +215,11 @@ static int br_dev_newlink(struct net *src_net, struct net_device *dev,
                          struct nlattr *tb[], struct nlattr *data[])
 {
        struct net_bridge *br = netdev_priv(dev);
+       int err;
+
+       err = register_netdevice(dev);
+       if (err)
+               return err;
 
        if (tb[IFLA_ADDRESS]) {
                spin_lock_bh(&br->lock);
@@ -222,7 +227,7 @@ static int br_dev_newlink(struct net *src_net, struct net_device *dev,
                spin_unlock_bh(&br->lock);
        }
 
-       return register_netdevice(dev);
+       return 0;
 }
 
 struct rtnl_link_ops br_link_ops __read_mostly = {
index 6229b62..d1f6604 100644 (file)
@@ -196,6 +196,9 @@ static ssize_t brport_show(struct kobject * kobj,
        struct brport_attribute * brport_attr = to_brport_attr(attr);
        struct net_bridge_port * p = to_brport(kobj);
 
+       if (!brport_attr->show)
+               return -EINVAL;
+
        return brport_attr->show(p, buf);
 }
 
index 8b84c58..06db707 100644 (file)
@@ -172,18 +172,69 @@ ebt_among_mt(const struct sk_buff *skb, struct xt_action_param *par)
        return true;
 }
 
+static bool poolsize_invalid(const struct ebt_mac_wormhash *w)
+{
+       return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple));
+}
+
+static bool wormhash_offset_invalid(int off, unsigned int len)
+{
+       if (off == 0) /* not present */
+               return false;
+
+       if (off < (int)sizeof(struct ebt_among_info) ||
+           off % __alignof__(struct ebt_mac_wormhash))
+               return true;
+
+       off += sizeof(struct ebt_mac_wormhash);
+
+       return off > len;
+}
+
+static bool wormhash_sizes_valid(const struct ebt_mac_wormhash *wh, int a, int b)
+{
+       if (a == 0)
+               a = sizeof(struct ebt_among_info);
+
+       return ebt_mac_wormhash_size(wh) + a == b;
+}
+
 static int ebt_among_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_among_info *info = par->matchinfo;
        const struct ebt_entry_match *em =
                container_of(par->matchinfo, const struct ebt_entry_match, data);
-       int expected_length = sizeof(struct ebt_among_info);
+       unsigned int expected_length = sizeof(struct ebt_among_info);
        const struct ebt_mac_wormhash *wh_dst, *wh_src;
        int err;
 
+       if (expected_length > em->match_size)
+               return -EINVAL;
+
+       if (wormhash_offset_invalid(info->wh_dst_ofs, em->match_size) ||
+           wormhash_offset_invalid(info->wh_src_ofs, em->match_size))
+               return -EINVAL;
+
        wh_dst = ebt_among_wh_dst(info);
-       wh_src = ebt_among_wh_src(info);
+       if (poolsize_invalid(wh_dst))
+               return -EINVAL;
+
        expected_length += ebt_mac_wormhash_size(wh_dst);
+       if (expected_length > em->match_size)
+               return -EINVAL;
+
+       wh_src = ebt_among_wh_src(info);
+       if (poolsize_invalid(wh_src))
+               return -EINVAL;
+
+       if (info->wh_src_ofs < info->wh_dst_ofs) {
+               if (!wormhash_sizes_valid(wh_src, info->wh_src_ofs, info->wh_dst_ofs))
+                       return -EINVAL;
+       } else {
+               if (!wormhash_sizes_valid(wh_dst, info->wh_dst_ofs, info->wh_src_ofs))
+                       return -EINVAL;
+       }
+
        expected_length += ebt_mac_wormhash_size(wh_src);
 
        if (em->match_size != EBT_ALIGN(expected_length)) {
index 45f93f8..9cde6d3 100644 (file)
@@ -2004,7 +2004,9 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32,
                if (match_kern)
                        match_kern->match_size = ret;
 
-               WARN_ON(type == EBT_COMPAT_TARGET && size_left);
+               if (WARN_ON(type == EBT_COMPAT_TARGET && size_left))
+                       return -EINVAL;
+
                match32 = (struct compat_ebt_entry_mwt *) buf;
        }
 
@@ -2061,6 +2063,19 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base,
         *
         * offsets are relative to beginning of struct ebt_entry (i.e., 0).
         */
+       for (i = 0; i < 4 ; ++i) {
+               if (offsets[i] > *total)
+                       return -EINVAL;
+
+               if (i < 3 && offsets[i] == *total)
+                       return -EINVAL;
+
+               if (i == 0)
+                       continue;
+               if (offsets[i-1] > offsets[i])
+                       return -EINVAL;
+       }
+
        for (i = 0, j = 1 ; j < 4 ; j++, i++) {
                struct compat_ebt_entry_mwt *match32;
                unsigned int size;
index 3ddc749..57c4364 100644 (file)
@@ -653,13 +653,13 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
        if (!net_eq(dev_net(dev), &init_net))
                goto drop;
 
-       if (WARN_ONCE(dev->type != ARPHRD_CAN ||
-                     skb->len != sizeof(struct can_frame) ||
-                     cf->can_dlc > 8,
-                     "PF_CAN: dropped non conform skbuf: "
-                     "dev type %d, len %d, can_dlc %d\n",
-                     dev->type, skb->len, cf->can_dlc))
+       if (unlikely(dev->type != ARPHRD_CAN ||
+                    skb->len != sizeof(struct can_frame) ||
+                    cf->can_dlc > 8)) {
+               pr_warn_once("PF_CAN: dropped non conform CAN skbuf: dev type %d, len %d, can_dlc %d\n",
+                            dev->type, skb->len, cf->can_dlc);
                goto drop;
+       }
 
        /* update statistics */
        can_stats.rx_frames++;
index bb7a0cc..56a6ad8 100644 (file)
@@ -1750,8 +1750,11 @@ static void netif_setup_tc(struct net_device *dev, unsigned int txq)
  */
 int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
 {
+       bool disabling;
        int rc;
 
+       disabling = txq < dev->real_num_tx_queues;
+
        if (txq < 1 || txq > dev->num_tx_queues)
                return -EINVAL;
 
@@ -1767,11 +1770,16 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
                if (dev->num_tc)
                        netif_setup_tc(dev, txq);
 
-               if (txq < dev->real_num_tx_queues)
+               dev->real_num_tx_queues = txq;
+
+               if (disabling) {
+                       synchronize_net();
                        qdisc_reset_all_tx_gt(dev, txq);
+               }
+       } else {
+               dev->real_num_tx_queues = txq;
        }
 
-       dev->real_num_tx_queues = txq;
        return 0;
 }
 EXPORT_SYMBOL(netif_set_real_num_tx_queues);
index f2007b3..9b9236d 100644 (file)
@@ -1137,7 +1137,10 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_LINKINFO]         = { .type = NLA_NESTED },
        [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
        [IFLA_NET_NS_FD]        = { .type = NLA_U32 },
-       [IFLA_IFALIAS]          = { .type = NLA_STRING, .len = IFALIASZ-1 },
+       /* IFLA_IFALIAS is a string, but policy is set to NLA_BINARY to
+        * allow 0-length string (needed to remove an alias).
+        */
+       [IFLA_IFALIAS]          = { .type = NLA_BINARY, .len = IFALIASZ - 1 },
        [IFLA_VFINFO_LIST]      = {. type = NLA_NESTED },
        [IFLA_VF_PORTS]         = { .type = NLA_NESTED },
        [IFLA_PORT_SELF]        = { .type = NLA_NESTED },
index 847b314..c5337c2 100644 (file)
@@ -3093,8 +3093,6 @@ static void sock_rmem_free(struct sk_buff *skb)
  */
 int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
 {
-       int len = skb->len;
-
        if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
            (unsigned)sk->sk_rcvbuf)
                return -ENOMEM;
@@ -3109,7 +3107,7 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
 
        skb_queue_tail(&sk->sk_error_queue, skb);
        if (!sock_flag(sk, SOCK_DEAD))
-               sk->sk_data_ready(sk, len);
+               sk->sk_error_report(sk);
        return 0;
 }
 EXPORT_SYMBOL(sock_queue_err_skb);
index 67164bb..eaa9d3e 100644 (file)
@@ -140,6 +140,9 @@ static void ccid2_hc_tx_rto_expire(unsigned long data)
 
        ccid2_pr_debug("RTO_EXPIRE\n");
 
+       if (sk->sk_state == DCCP_CLOSED)
+               goto out;
+
        /* back-off timer */
        hc->tx_rto <<= 1;
        if (hc->tx_rto > DCCP_RTO_MAX)
index 33d0e62..0a8d6eb 100644 (file)
@@ -152,6 +152,17 @@ static const struct file_operations dccpprobe_fops = {
        .llseek  = noop_llseek,
 };
 
+static __init int setup_jprobe(void)
+{
+       int ret = register_jprobe(&dccp_send_probe);
+
+       if (ret) {
+               request_module("dccp");
+               ret = register_jprobe(&dccp_send_probe);
+       }
+       return ret;
+}
+
 static __init int dccpprobe_init(void)
 {
        int ret = -ENOMEM;
@@ -163,8 +174,7 @@ static __init int dccpprobe_init(void)
        if (!proc_net_fops_create(&init_net, procname, S_IRUSR, &dccpprobe_fops))
                goto err0;
 
-       try_then_request_module((ret = register_jprobe(&dccp_send_probe)) == 0,
-                               "dccp");
+       ret = setup_jprobe();
        if (ret)
                goto err1;
 
index bd3ecdd..975dcdf 100644 (file)
@@ -252,6 +252,7 @@ int dccp_disconnect(struct sock *sk, int flags)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct inet_sock *inet = inet_sk(sk);
+       struct dccp_sock *dp = dccp_sk(sk);
        int err = 0;
        const int old_state = sk->sk_state;
 
@@ -271,6 +272,10 @@ int dccp_disconnect(struct sock *sk, int flags)
                sk->sk_err = ECONNRESET;
 
        dccp_clear_xmit_timers(sk);
+       ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+       ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+       dp->dccps_hc_rx_ccid = NULL;
+       dp->dccps_hc_tx_ccid = NULL;
 
        __skb_queue_purge(&sk->sk_receive_queue);
        __skb_queue_purge(&sk->sk_write_queue);
@@ -780,6 +785,11 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        if (skb == NULL)
                goto out_release;
 
+       if (sk->sk_state == DCCP_CLOSED) {
+               rc = -ENOTCONN;
+               goto out_discard;
+       }
+
        skb_reserve(skb, sk->sk_prot->max_header);
        rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
        if (rc != 0)
index c0486c8..0b42774 100644 (file)
@@ -1338,6 +1338,12 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use
        lock_sock(sk);
        err = __dn_setsockopt(sock, level, optname, optval, optlen, 0);
        release_sock(sk);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible ENOPROTOOPTs except default case */
+       if (err == -ENOPROTOOPT && optname != DSO_LINKINFO &&
+           optname != DSO_STREAM && optname != DSO_SEQPACKET)
+               err = nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
+#endif
 
        return err;
 }
@@ -1445,15 +1451,6 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
                dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);
                break;
 
-       default:
-#ifdef CONFIG_NETFILTER
-               return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
-#endif
-       case DSO_LINKINFO:
-       case DSO_STREAM:
-       case DSO_SEQPACKET:
-               return -ENOPROTOOPT;
-
        case DSO_MAXWINDOW:
                if (optlen != sizeof(unsigned long))
                        return -EINVAL;
@@ -1501,6 +1498,12 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
                        return -EINVAL;
                scp->info_loc = u.info;
                break;
+
+       case DSO_LINKINFO:
+       case DSO_STREAM:
+       case DSO_SEQPACKET:
+       default:
+               return -ENOPROTOOPT;
        }
 
        return 0;
@@ -1514,6 +1517,20 @@ static int dn_getsockopt(struct socket *sock, int level, int optname, char __use
        lock_sock(sk);
        err = __dn_getsockopt(sock, level, optname, optval, optlen, 0);
        release_sock(sk);
+#ifdef CONFIG_NETFILTER
+       if (err == -ENOPROTOOPT && optname != DSO_STREAM &&
+           optname != DSO_SEQPACKET && optname != DSO_CONACCEPT &&
+           optname != DSO_CONREJECT) {
+               int len;
+
+               if (get_user(len, optlen))
+                       return -EFAULT;
+
+               err = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
+               if (err >= 0)
+                       err = put_user(len, optlen);
+       }
+#endif
 
        return err;
 }
@@ -1579,26 +1596,6 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
                r_data = &link;
                break;
 
-       default:
-#ifdef CONFIG_NETFILTER
-       {
-               int ret, len;
-
-               if (get_user(len, optlen))
-                       return -EFAULT;
-
-               ret = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
-               if (ret >= 0)
-                       ret = put_user(len, optlen);
-               return ret;
-       }
-#endif
-       case DSO_STREAM:
-       case DSO_SEQPACKET:
-       case DSO_CONACCEPT:
-       case DSO_CONREJECT:
-               return -ENOPROTOOPT;
-
        case DSO_MAXWINDOW:
                if (r_len > sizeof(unsigned long))
                        r_len = sizeof(unsigned long);
@@ -1630,6 +1627,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
                        r_len = sizeof(unsigned char);
                r_data = &scp->info_rem;
                break;
+
+       case DSO_STREAM:
+       case DSO_SEQPACKET:
+       case DSO_CONACCEPT:
+       case DSO_CONREJECT:
+       default:
+               return -ENOPROTOOPT;
        }
 
        if (r_data) {
index 238fc3b..20a140c 100644 (file)
@@ -658,6 +658,7 @@ static int esp_init_state(struct xfrm_state *x)
 
                switch (encap->encap_type) {
                default:
+                       err = -EINVAL;
                        goto error;
                case UDP_ENCAP_ESPINUDP:
                        x->props.header_len += sizeof(struct udphdr);
index 76784c7..003a814 100644 (file)
@@ -1128,13 +1128,14 @@ static struct pernet_operations fib_net_ops = {
 
 void __init ip_fib_init(void)
 {
-       rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL);
-       rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL);
-       rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL);
+       fib_trie_init();
 
        register_pernet_subsys(&fib_net_ops);
+
        register_netdevice_notifier(&fib_netdev_notifier);
        register_inetaddr_notifier(&fib_inetaddr_notifier);
 
-       fib_trie_init();
+       rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL);
+       rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL);
+       rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL);
 }
index 0a35f08..59155c1 100644 (file)
@@ -89,6 +89,7 @@
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/times.h>
+#include <linux/byteorder/generic.h>
 
 #include <net/net_namespace.h>
 #include <net/arp.h>
@@ -299,6 +300,23 @@ igmp_scount(struct ip_mc_list *pmc, int type, int gdeleted, int sdeleted)
        return scount;
 }
 
+/* source address selection per RFC 3376 section 4.2.13 */
+static __be32 igmpv3_get_srcaddr(struct net_device *dev,
+                                const struct flowi4 *fl4)
+{
+       struct in_device *in_dev = __in_dev_get_rcu(dev);
+
+       if (!in_dev)
+               return htonl(INADDR_ANY);
+
+       for_ifa(in_dev) {
+               if (fl4->saddr == ifa->ifa_local)
+                       return fl4->saddr;
+       } endfor_ifa(in_dev);
+
+       return htonl(INADDR_ANY);
+}
+
 static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
 {
        struct sk_buff *skb;
@@ -345,7 +363,11 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
        pip->frag_off = htons(IP_DF);
        pip->ttl      = 1;
        pip->daddr    = fl4.daddr;
-       pip->saddr    = fl4.saddr;
+
+       rcu_read_lock();
+       pip->saddr    = igmpv3_get_srcaddr(dev, &fl4);
+       rcu_read_unlock();
+
        pip->protocol = IPPROTO_IGMP;
        pip->tot_len  = 0;      /* filled in later */
        ip_select_ident(skb, NULL);
index a6e1eeb..ff4dd68 100644 (file)
@@ -1030,11 +1030,8 @@ int ip_setsockopt(struct sock *sk, int level,
        if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
                        optname != IP_IPSEC_POLICY &&
                        optname != IP_XFRM_POLICY &&
-                       !ip_mroute_opt(optname)) {
-               lock_sock(sk);
+                       !ip_mroute_opt(optname))
                err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);
-               release_sock(sk);
-       }
 #endif
        return err;
 }
@@ -1059,12 +1056,9 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname,
        if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&
                        optname != IP_IPSEC_POLICY &&
                        optname != IP_XFRM_POLICY &&
-                       !ip_mroute_opt(optname)) {
-               lock_sock(sk);
-               err = compat_nf_setsockopt(sk, PF_INET, optname,
-                                          optval, optlen);
-               release_sock(sk);
-       }
+                       !ip_mroute_opt(optname))
+               err = compat_nf_setsockopt(sk, PF_INET, optname, optval,
+                                          optlen);
 #endif
        return err;
 }
@@ -1314,10 +1308,7 @@ int ip_getsockopt(struct sock *sk, int level,
                if (get_user(len, optlen))
                        return -EFAULT;
 
-               lock_sock(sk);
-               err = nf_getsockopt(sk, PF_INET, optname, optval,
-                               &len);
-               release_sock(sk);
+               err = nf_getsockopt(sk, PF_INET, optname, optval, &len);
                if (err >= 0)
                        err = put_user(len, optlen);
                return err;
@@ -1349,9 +1340,7 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname,
                if (get_user(len, optlen))
                        return -EFAULT;
 
-               lock_sock(sk);
                err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len);
-               release_sock(sk);
                if (err >= 0)
                        err = put_user(len, optlen);
                return err;
index a639967..cb21acc 100644 (file)
@@ -135,8 +135,12 @@ clusterip_config_find_get(__be32 clusterip, int entry)
        if (c) {
                if (unlikely(!atomic_inc_not_zero(&c->refcount)))
                        c = NULL;
-               else if (entry)
-                       atomic_inc(&c->entries);
+               else if (entry) {
+                       if (unlikely(!atomic_inc_not_zero(&c->entries))) {
+                               clusterip_config_put(c);
+                               c = NULL;
+                       }
+               }
        }
        rcu_read_unlock_bh();
 
@@ -354,7 +358,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
        struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
        const struct ipt_entry *e = par->entryinfo;
        struct clusterip_config *config;
-       int ret;
+       int ret, i;
 
        if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP &&
            cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT &&
@@ -368,8 +372,18 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
                pr_info("Please specify destination IP\n");
                return -EINVAL;
        }
-
-       /* FIXME: further sanity checks */
+       if (cipinfo->num_local_nodes > ARRAY_SIZE(cipinfo->local_nodes)) {
+               pr_info("bad num_local_nodes %u\n", cipinfo->num_local_nodes);
+               return -EINVAL;
+       }
+       for (i = 0; i < cipinfo->num_local_nodes; i++) {
+               if (cipinfo->local_nodes[i] - 1 >=
+                   sizeof(config->local_nodes) * 8) {
+                       pr_info("bad local_nodes[%d] %u\n",
+                               i, cipinfo->local_nodes[i]);
+                       return -EINVAL;
+               }
+       }
 
        config = clusterip_config_find_get(e->ip.dst.s_addr, 1);
        if (!config) {
index d7d63f4..6791f3a 100644 (file)
@@ -258,15 +258,19 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
        struct nf_conntrack_tuple tuple;
 
        memset(&tuple, 0, sizeof(tuple));
+
+       lock_sock(sk);
        tuple.src.u3.ip = inet->inet_rcv_saddr;
        tuple.src.u.tcp.port = inet->inet_sport;
        tuple.dst.u3.ip = inet->inet_daddr;
        tuple.dst.u.tcp.port = inet->inet_dport;
        tuple.src.l3num = PF_INET;
        tuple.dst.protonum = sk->sk_protocol;
+       release_sock(sk);
 
        /* We only do TCP and SCTP at the moment: is there a better way? */
-       if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) {
+       if (tuple.dst.protonum != IPPROTO_TCP &&
+           tuple.dst.protonum != IPPROTO_SCTP) {
                pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n");
                return -ENOPROTOOPT;
        }
index a3d9976..ccb69ce 100644 (file)
@@ -42,7 +42,7 @@ void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
                               const struct nf_conn *ct,
                               u_int16_t *rover)
 {
-       unsigned int range_size, min, i;
+       unsigned int range_size, min, max, i;
        __be16 *portptr;
        u_int16_t off;
 
@@ -72,7 +72,10 @@ void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
                }
        } else {
                min = ntohs(range->min.all);
-               range_size = ntohs(range->max.all) - min + 1;
+               max = ntohs(range->max.all);
+               if (unlikely(max < min))
+                       swap(max, min);
+               range_size = max - min + 1;
        }
 
        if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
index e643096..8a9233e 100644 (file)
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/compat.h>
+#include <linux/uio.h>
+
+struct raw_frag_vec {
+       struct iovec *iov;
+       union {
+               struct icmphdr icmph;
+               char c[1];
+       } hdr;
+       int hlen;
+};
 
 static struct raw_hashinfo raw_v4_hashinfo = {
        .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
@@ -409,53 +419,57 @@ error:
        return err;
 }
 
-static int raw_probe_proto_opt(struct flowi4 *fl4, struct msghdr *msg)
+static int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4)
 {
-       struct iovec *iov;
-       u8 __user *type = NULL;
-       u8 __user *code = NULL;
-       int probed = 0;
-       unsigned int i;
+       int err;
 
-       if (!msg->msg_iov)
+       if (fl4->flowi4_proto != IPPROTO_ICMP)
                return 0;
 
-       for (i = 0; i < msg->msg_iovlen; i++) {
-               iov = &msg->msg_iov[i];
-               if (!iov)
-                       continue;
-
-               switch (fl4->flowi4_proto) {
-               case IPPROTO_ICMP:
-                       /* check if one-byte field is readable or not. */
-                       if (iov->iov_base && iov->iov_len < 1)
-                               break;
-
-                       if (!type) {
-                               type = iov->iov_base;
-                               /* check if code field is readable or not. */
-                               if (iov->iov_len > 1)
-                                       code = type + 1;
-                       } else if (!code)
-                               code = iov->iov_base;
-
-                       if (type && code) {
-                               if (get_user(fl4->fl4_icmp_type, type) ||
-                                   get_user(fl4->fl4_icmp_code, code))
-                                       return -EFAULT;
-                               probed = 1;
-                       }
-                       break;
-               default:
-                       probed = 1;
-                       break;
-               }
-               if (probed)
-                       break;
-       }
+       /* We only need the first two bytes. */
+       rfv->hlen = 2;
+
+       err = memcpy_fromiovec(rfv->hdr.c, rfv->iov, rfv->hlen);
+       if (err)
+               return err;
+
+       fl4->fl4_icmp_type = rfv->hdr.icmph.type;
+       fl4->fl4_icmp_code = rfv->hdr.icmph.code;
+
        return 0;
 }
 
+static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
+                      struct sk_buff *skb)
+{
+       struct raw_frag_vec *rfv = from;
+
+       if (offset < rfv->hlen) {
+               int copy = min(rfv->hlen - offset, len);
+
+               if (skb->ip_summed == CHECKSUM_PARTIAL)
+                       memcpy(to, rfv->hdr.c + offset, copy);
+               else
+                       skb->csum = csum_block_add(
+                               skb->csum,
+                               csum_partial_copy_nocheck(rfv->hdr.c + offset,
+                                                         to, copy, 0),
+                               odd);
+
+               odd = 0;
+               offset += copy;
+               to += copy;
+               len -= copy;
+
+               if (!len)
+                       return 0;
+       }
+
+       offset -= rfv->hlen;
+
+       return ip_generic_getfrag(rfv->iov, to, offset, len, odd, skb);
+}
+
 static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                       size_t len)
 {
@@ -469,11 +483,19 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        u8  tos;
        int err;
        struct ip_options_data opt_copy;
+       struct raw_frag_vec rfv;
+       int hdrincl;
 
        err = -EMSGSIZE;
        if (len > 0xFFFF)
                goto out;
 
+       /* hdrincl should be READ_ONCE(inet->hdrincl)
+        * but READ_ONCE() doesn't work with bit fields.
+        * Doing this indirectly yields the same result.
+        */
+       hdrincl = inet->hdrincl;
+       hdrincl = ACCESS_ONCE(hdrincl);
        /*
         *      Check the flags.
         */
@@ -549,7 +571,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                /* Linux does not mangle headers on raw sockets,
                 * so that IP options + IP_HDRINCL is non-sense.
                 */
-               if (inet->hdrincl)
+               if (hdrincl)
                        goto done;
                if (ipc.opt->opt.srr) {
                        if (!daddr)
@@ -570,12 +592,15 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
        flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
                           RT_SCOPE_UNIVERSE,
-                          inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
+                          hdrincl ? IPPROTO_RAW : sk->sk_protocol,
                           inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP,
                           daddr, saddr, 0, 0);
 
-       if (!inet->hdrincl) {
-               err = raw_probe_proto_opt(&fl4, msg);
+       if (!hdrincl) {
+               rfv.iov = msg->msg_iov;
+               rfv.hlen = 0;
+
+               err = raw_probe_proto_opt(&rfv, &fl4);
                if (err)
                        goto done;
        }
@@ -596,7 +621,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                goto do_confirm;
 back_from_confirm:
 
-       if (inet->hdrincl)
+       if (hdrincl)
                err = raw_send_hdrinc(sk, &fl4, msg->msg_iov, len,
                                      &rt, msg->msg_flags);
 
@@ -604,8 +629,8 @@ back_from_confirm:
                if (!ipc.addr)
                        ipc.addr = fl4.daddr;
                lock_sock(sk);
-               err = ip_append_data(sk, &fl4, ip_generic_getfrag,
-                                    msg->msg_iov, len, 0,
+               err = ip_append_data(sk, &fl4, raw_getfrag,
+                                    &rfv, len, 0,
                                     &ipc, &rt, msg->msg_flags);
                if (err)
                        ip_flush_pending_frames(sk);
index 4ba77ee..52646b1 100644 (file)
@@ -764,7 +764,7 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
                        tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd,
                        req->ts_recent,
                        0,
-                       tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr),
+                       tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr),
                        inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0,
                        ip_hdr(skb)->tos);
 }
index 1c96e9b..da11cd7 100644 (file)
@@ -1676,6 +1676,7 @@ static int tcp_mtu_probe(struct sock *sk)
        nskb->ip_summed = skb->ip_summed;
 
        tcp_insert_write_queue_before(nskb, skb, sk);
+       tcp_highest_sack_replace(sk, skb, nskb);
 
        len = 0;
        tcp_for_write_queue_from_safe(skb, next, sk) {
@@ -1987,7 +1988,7 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
 
        BUG_ON(tcp_skb_pcount(skb) != 1 || tcp_skb_pcount(next_skb) != 1);
 
-       tcp_highest_sack_combine(sk, next_skb, skb);
+       tcp_highest_sack_replace(sk, next_skb, skb);
 
        tcp_unlink_write_queue(next_skb, sk);
 
index 06814b6..1620fa2 100644 (file)
@@ -22,6 +22,11 @@ int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb)
        return xfrm4_extract_header(skb);
 }
 
+static int xfrm4_rcv_encap_finish2(struct sk_buff *skb)
+{
+       return dst_input(skb);
+}
+
 static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
 {
        if (skb_dst(skb) == NULL) {
@@ -31,7 +36,11 @@ static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
                                         iph->tos, skb->dev))
                        goto drop;
        }
-       return dst_input(skb);
+
+       if (xfrm_trans_queue(skb, xfrm4_rcv_encap_finish2))
+               goto drop;
+
+       return 0;
 drop:
        kfree_skb(skb);
        return NET_RX_DROP;
index cb1de47..9d74f44 100644 (file)
@@ -1382,18 +1382,11 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add
 
 static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
 {
-       if (ifp->flags&IFA_F_PERMANENT) {
-               spin_lock_bh(&ifp->lock);
-               addrconf_del_timer(ifp);
-               ifp->flags |= IFA_F_TENTATIVE;
-               if (dad_failed)
-                       ifp->flags |= IFA_F_DADFAILED;
-               spin_unlock_bh(&ifp->lock);
-               if (dad_failed)
-                       ipv6_ifa_notify(0, ifp);
-               in6_ifa_put(ifp);
+       if (dad_failed)
+               ifp->flags |= IFA_F_DADFAILED;
+
 #ifdef CONFIG_IPV6_PRIVACY
-       } else if (ifp->flags&IFA_F_TEMPORARY) {
+       if (ifp->flags&IFA_F_TEMPORARY) {
                struct inet6_ifaddr *ifpub;
                spin_lock_bh(&ifp->lock);
                ifpub = ifp->ifpub;
@@ -1406,7 +1399,16 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
                        spin_unlock_bh(&ifp->lock);
                }
                ipv6_del_addr(ifp);
+       } else
 #endif
+       if (ifp->flags&IFA_F_PERMANENT || !dad_failed) {
+               spin_lock_bh(&ifp->lock);
+               addrconf_del_timer(ifp);
+               ifp->flags |= IFA_F_TENTATIVE;
+               spin_unlock_bh(&ifp->lock);
+               if (dad_failed)
+                       ipv6_ifa_notify(0, ifp);
+               in6_ifa_put(ifp);
        } else
                ipv6_del_addr(ifp);
 }
@@ -4282,7 +4284,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
                 * our DAD process, so we don't need
                 * to do it again
                 */
-               if (!(ifp->rt->rt6i_node))
+               if (!rcu_access_pointer(ifp->rt->rt6i_node))
                        ip6_ins_rt(ifp->rt);
                if (ifp->idev->cnf.forwarding)
                        addrconf_join_anycast(ifp);
index 65dd543..b154ae4 100644 (file)
@@ -606,13 +606,12 @@ static int esp6_init_state(struct xfrm_state *x)
                        x->props.header_len += IPV4_BEET_PHMAXLEN +
                                               (sizeof(struct ipv6hdr) - sizeof(struct iphdr));
                break;
+       default:
        case XFRM_MODE_TRANSPORT:
                break;
        case XFRM_MODE_TUNNEL:
                x->props.header_len += sizeof(struct ipv6hdr);
                break;
-       default:
-               goto error;
        }
 
        align = ALIGN(crypto_aead_blocksize(aead), 4);
index 785e62d..33de352 100644 (file)
@@ -153,11 +153,23 @@ static __inline__ struct fib6_node * node_alloc(void)
        return fn;
 }
 
-static __inline__ void node_free(struct fib6_node * fn)
+static void node_free_immediate(struct fib6_node *fn)
 {
        kmem_cache_free(fib6_node_kmem, fn);
 }
 
+static void node_free_rcu(struct rcu_head *head)
+{
+       struct fib6_node *fn = container_of(head, struct fib6_node, rcu);
+
+       kmem_cache_free(fib6_node_kmem, fn);
+}
+
+static void node_free(struct fib6_node *fn)
+{
+       call_rcu(&fn->rcu, node_free_rcu);
+}
+
 static __inline__ void rt6_release(struct rt6_info *rt)
 {
        if (atomic_dec_and_test(&rt->rt6i_ref))
@@ -529,9 +541,9 @@ insert_above:
 
                if (in == NULL || ln == NULL) {
                        if (in)
-                               node_free(in);
+                               node_free_immediate(in);
                        if (ln)
-                               node_free(ln);
+                               node_free_immediate(ln);
                        return NULL;
                }
 
@@ -658,7 +670,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
 
        rt->dst.rt6_next = iter;
        *ins = rt;
-       rt->rt6i_node = fn;
+       rcu_assign_pointer(rt->rt6i_node, fn);
        atomic_inc(&rt->rt6i_ref);
        inet6_rt_notify(RTM_NEWROUTE, rt, info);
        info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
@@ -743,7 +755,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
                                   root, and then (in st_failure) stale node
                                   in main tree.
                                 */
-                               node_free(sfn);
+                               node_free_immediate(sfn);
                                goto st_failure;
                        }
 
@@ -1169,8 +1181,9 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
 
 int fib6_del(struct rt6_info *rt, struct nl_info *info)
 {
+       struct fib6_node *fn = rcu_dereference_protected(rt->rt6i_node,
+                                   lockdep_is_held(&rt->rt6i_table->tb6_lock));
        struct net *net = info->nl_net;
-       struct fib6_node *fn = rt->rt6i_node;
        struct rt6_info **rtp;
 
 #if RT6_DEBUG >= 2
@@ -1348,7 +1361,10 @@ static int fib6_clean_node(struct fib6_walker_t *w)
                        res = fib6_del(rt, &info);
                        if (res) {
 #if RT6_DEBUG >= 2
-                               printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res);
+                               pr_debug("%s: del failed: rt=%p@%p err=%d\n",
+                                        __func__, rt,
+                                        rcu_access_pointer(rt->rt6i_node),
+                                        res);
 #endif
                                continue;
                        }
@@ -1561,13 +1577,22 @@ out_timer:
 
 static void fib6_net_exit(struct net *net)
 {
+       unsigned int i;
+
        rt6_ifdown(net, NULL);
        del_timer_sync(&net->ipv6.ip6_fib_timer);
 
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
-       kfree(net->ipv6.fib6_local_tbl);
-#endif
-       kfree(net->ipv6.fib6_main_tbl);
+       for (i = 0; i < FIB6_TABLE_HASHSZ; i++) {
+               struct hlist_head *head = &net->ipv6.fib_table_hash[i];
+               struct hlist_node *node, *tmp;
+               struct fib6_table *tb;
+
+               hlist_for_each_entry_safe(tb, node, tmp, head, tb6_hlist) {
+                       hlist_del(&tb->tb6_hlist);
+                       kfree(tb);
+               }
+       }
+
        kfree(net->ipv6.fib_table_hash);
        kfree(net->ipv6.rt6_stats);
 }
index a2a0852..c7568ce 100644 (file)
@@ -568,7 +568,6 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
 
        while (offset <= packet_len) {
                struct ipv6_opt_hdr *exthdr;
-               unsigned int len;
 
                switch (**nexthdr) {
 
@@ -594,10 +593,9 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
 
                exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
                                                 offset);
-               len = ipv6_optlen(exthdr);
-               if (len + offset >= IPV6_MAXPLEN)
+               offset += ipv6_optlen(exthdr);
+               if (offset > IPV6_MAXPLEN)
                        return -EINVAL;
-               offset += len;
                *nexthdr = &exthdr->nexthdr;
        }
 
index 2b4b4e3..55f5a1a 100644 (file)
@@ -143,7 +143,7 @@ static inline void ip6_tnl_dst_reset(struct ip6_tnl *t)
 static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
 {
        struct rt6_info *rt = (struct rt6_info *) dst;
-       t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
+       t->dst_cookie = rt6_get_cookie(rt);
        dst_release(t->dst_cache);
        t->dst_cache = dst;
 }
index 9af3f5c..4af98c8 100644 (file)
@@ -841,12 +841,8 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
        if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
-                       optname != IPV6_XFRM_POLICY) {
-               lock_sock(sk);
-               err = nf_setsockopt(sk, PF_INET6, optname, optval,
-                               optlen);
-               release_sock(sk);
-       }
+                       optname != IPV6_XFRM_POLICY)
+               err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen);
 #endif
        return err;
 }
@@ -877,12 +873,9 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
        if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
-           optname != IPV6_XFRM_POLICY) {
-               lock_sock(sk);
-               err = compat_nf_setsockopt(sk, PF_INET6, optname,
-                                          optval, optlen);
-               release_sock(sk);
-       }
+           optname != IPV6_XFRM_POLICY)
+               err = compat_nf_setsockopt(sk, PF_INET6, optname, optval,
+                                          optlen);
 #endif
        return err;
 }
@@ -1244,10 +1237,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
                if (get_user(len, optlen))
                        return -EFAULT;
 
-               lock_sock(sk);
-               err = nf_getsockopt(sk, PF_INET6, optname, optval,
-                               &len);
-               release_sock(sk);
+               err = nf_getsockopt(sk, PF_INET6, optname, optval, &len);
                if (err >= 0)
                        err = put_user(len, optlen);
        }
@@ -1287,10 +1277,7 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
                if (get_user(len, optlen))
                        return -EFAULT;
 
-               lock_sock(sk);
-               err = compat_nf_getsockopt(sk, PF_INET6,
-                                          optname, optval, &len);
-               release_sock(sk);
+               err = compat_nf_getsockopt(sk, PF_INET6, optname, optval, &len);
                if (err >= 0)
                        err = put_user(len, optlen);
        }
index cda5cfe..6fc91f9 100644 (file)
@@ -964,10 +964,11 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
 static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
 {
        struct rt6_info *rt;
+       u32 rt_cookie = 0;
 
        rt = (struct rt6_info *) dst;
 
-       if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) {
+       if (rt6_get_cookie_safe(rt, &rt_cookie) && rt_cookie == cookie) {
                if (rt->rt6i_peer_genid != rt6_peer_genid()) {
                        if (!rt->rt6i_peer)
                                rt6_bind_peer(rt, 0);
@@ -1007,8 +1008,15 @@ static void ip6_link_failure(struct sk_buff *skb)
                if (rt->rt6i_flags&RTF_CACHE) {
                        dst_set_expires(&rt->dst, 0);
                        rt->rt6i_flags |= RTF_EXPIRES;
-               } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT))
-                       rt->rt6i_node->fn_sernum = -1;
+               } else {
+                       struct fib6_node *fn;
+
+                       rcu_read_lock();
+                       fn = rcu_dereference(rt->rt6i_node);
+                       if (fn && (rt->rt6i_flags & RTF_DEFAULT))
+                               fn->fn_sernum = -1;
+                       rcu_read_unlock();
+               }
        }
 }
 
index f0a1b0b..abc2cd5 100644 (file)
@@ -1116,7 +1116,7 @@ static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
                                  struct request_sock *req)
 {
        tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent,
-                       tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0);
+                       tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr), 0);
 }
 
 
index f8c3cf8..11b6df9 100644 (file)
@@ -29,6 +29,13 @@ int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
 }
 EXPORT_SYMBOL(xfrm6_rcv_spi);
 
+static int xfrm6_transport_finish2(struct sk_buff *skb)
+{
+       if (xfrm_trans_queue(skb, ip6_rcv_finish))
+               __kfree_skb(skb);
+       return -1;
+}
+
 int xfrm6_transport_finish(struct sk_buff *skb, int async)
 {
        skb_network_header(skb)[IP6CB(skb)->nhoff] =
@@ -43,7 +50,7 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
        __skb_push(skb, skb->data - skb_network_header(skb));
 
        NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
-               ip6_rcv_finish);
+               xfrm6_transport_finish2);
        return -1;
 }
 
index db78e7d..353ce00 100644 (file)
@@ -78,8 +78,7 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst,
 {
        if (dst->ops->family == AF_INET6) {
                struct rt6_info *rt = (struct rt6_info*)dst;
-               if (rt->rt6i_node)
-                       path->path_cookie = rt->rt6i_node->fn_sernum;
+               path->path_cookie = rt6_get_cookie(rt);
        }
 
        path->u.rt6.rt6i_nfheader_len = nfheader_len;
@@ -111,8 +110,7 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
                                                   RTF_LOCAL);
        xdst->u.rt6.rt6i_metric = rt->rt6i_metric;
        xdst->u.rt6.rt6i_node = rt->rt6i_node;
-       if (rt->rt6i_node)
-               xdst->route_cookie = rt->rt6i_node->fn_sernum;
+       xdst->route_cookie = rt6_get_cookie(rt);
        xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
        xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
        xdst->u.rt6.rt6i_src = rt->rt6i_src;
index fc36acc..f95145c 100644 (file)
@@ -705,10 +705,8 @@ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr,
        char uid[9];
 
        /* Verify the input sockaddr */
-       if (!addr || addr->sa_family != AF_IUCV)
-               return -EINVAL;
-
-       if (addr_len < sizeof(struct sockaddr_iucv))
+       if (addr_len < sizeof(struct sockaddr_iucv) ||
+           addr->sa_family != AF_IUCV)
                return -EINVAL;
 
        lock_sock(sk);
@@ -879,7 +877,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
        struct iucv_sock *iucv = iucv_sk(sk);
        int err;
 
-       if (addr->sa_family != AF_IUCV || alen < sizeof(struct sockaddr_iucv))
+       if (alen < sizeof(struct sockaddr_iucv) || addr->sa_family != AF_IUCV)
                return -EINVAL;
 
        if (sk->sk_state != IUCV_OPEN && sk->sk_state != IUCV_BOUND)
index 35fc5ba..e588b17 100644 (file)
@@ -225,7 +225,7 @@ static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
 #define BROADCAST_ONE          1
 #define BROADCAST_REGISTERED   2
 #define BROADCAST_PROMISC_ONLY 4
-static int pfkey_broadcast(struct sk_buff *skb,
+static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
                           int broadcast_flags, struct sock *one_sk,
                           struct net *net)
 {
@@ -276,7 +276,7 @@ static int pfkey_broadcast(struct sk_buff *skb,
        rcu_read_unlock();
 
        if (one_sk != NULL)
-               err = pfkey_broadcast_one(skb, &skb2, GFP_KERNEL, one_sk);
+               err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk);
 
        kfree_skb(skb2);
        kfree_skb(skb);
@@ -309,7 +309,7 @@ static int pfkey_do_dump(struct pfkey_sock *pfk)
                hdr = (struct sadb_msg *) pfk->dump.skb->data;
                hdr->sadb_msg_seq = 0;
                hdr->sadb_msg_errno = rc;
-               pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE,
+               pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
                                &pfk->sk, sock_net(&pfk->sk));
                pfk->dump.skb = NULL;
        }
@@ -353,7 +353,7 @@ static int pfkey_error(const struct sadb_msg *orig, int err, struct sock *sk)
        hdr->sadb_msg_len = (sizeof(struct sadb_msg) /
                             sizeof(uint64_t));
 
-       pfkey_broadcast(skb, BROADCAST_ONE, sk, sock_net(sk));
+       pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk, sock_net(sk));
 
        return 0;
 }
@@ -398,6 +398,11 @@ static int verify_address_len(const void *p)
 #endif
        int len;
 
+       if (sp->sadb_address_len <
+           DIV_ROUND_UP(sizeof(*sp) + offsetofend(typeof(*addr), sa_family),
+                        sizeof(uint64_t)))
+               return -EINVAL;
+
        switch (addr->sa_family) {
        case AF_INET:
                len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin), sizeof(uint64_t));
@@ -508,6 +513,9 @@ static int parse_exthdrs(struct sk_buff *skb, const struct sadb_msg *hdr, void *
                uint16_t ext_type;
                int ext_len;
 
+               if (len < sizeof(*ehdr))
+                       return -EINVAL;
+
                ext_len  = ehdr->sadb_ext_len;
                ext_len *= sizeof(uint64_t);
                ext_type = ehdr->sadb_ext_type;
@@ -1388,7 +1396,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_
 
        xfrm_state_put(x);
 
-       pfkey_broadcast(resp_skb, BROADCAST_ONE, sk, net);
+       pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk, net);
 
        return 0;
 }
@@ -1476,7 +1484,7 @@ static int key_notify_sa(struct xfrm_state *x, const struct km_event *c)
        hdr->sadb_msg_seq = c->seq;
        hdr->sadb_msg_pid = c->pid;
 
-       pfkey_broadcast(skb, BROADCAST_ALL, NULL, xs_net(x));
+       pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xs_net(x));
 
        return 0;
 }
@@ -1593,7 +1601,7 @@ static int pfkey_get(struct sock *sk, struct sk_buff *skb, const struct sadb_msg
        out_hdr->sadb_msg_reserved = 0;
        out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
        out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
-       pfkey_broadcast(out_skb, BROADCAST_ONE, sk, sock_net(sk));
+       pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk));
 
        return 0;
 }
@@ -1694,8 +1702,8 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, const struct sad
                return -ENOBUFS;
        }
 
-       pfkey_broadcast(supp_skb, BROADCAST_REGISTERED, sk, sock_net(sk));
-
+       pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk,
+                       sock_net(sk));
        return 0;
 }
 
@@ -1713,7 +1721,8 @@ static int unicast_flush_resp(struct sock *sk, const struct sadb_msg *ihdr)
        hdr->sadb_msg_errno = (uint8_t) 0;
        hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
 
-       return pfkey_broadcast(skb, BROADCAST_ONE, sk, sock_net(sk));
+       return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ONE, sk,
+                              sock_net(sk));
 }
 
 static int key_notify_sa_flush(const struct km_event *c)
@@ -1734,7 +1743,7 @@ static int key_notify_sa_flush(const struct km_event *c)
        hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
        hdr->sadb_msg_reserved = 0;
 
-       pfkey_broadcast(skb, BROADCAST_ALL, NULL, c->net);
+       pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
 
        return 0;
 }
@@ -1795,7 +1804,7 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr)
        out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
 
        if (pfk->dump.skb)
-               pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE,
+               pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
                                &pfk->sk, sock_net(&pfk->sk));
        pfk->dump.skb = out_skb;
 
@@ -1862,7 +1871,7 @@ static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, const struct sadb
                new_hdr->sadb_msg_errno = 0;
        }
 
-       pfkey_broadcast(skb, BROADCAST_ALL, NULL, sock_net(sk));
+       pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ALL, NULL, sock_net(sk));
        return 0;
 }
 
@@ -2193,7 +2202,7 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, const struct km_ev
        out_hdr->sadb_msg_errno = 0;
        out_hdr->sadb_msg_seq = c->seq;
        out_hdr->sadb_msg_pid = c->pid;
-       pfkey_broadcast(out_skb, BROADCAST_ALL, NULL, xp_net(xp));
+       pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xp_net(xp));
        return 0;
 
 }
@@ -2419,7 +2428,7 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struc
        out_hdr->sadb_msg_errno = 0;
        out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
        out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
-       pfkey_broadcast(out_skb, BROADCAST_ONE, sk, xp_net(xp));
+       pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, xp_net(xp));
        err = 0;
 
 out:
@@ -2672,7 +2681,7 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
        out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
 
        if (pfk->dump.skb)
-               pfkey_broadcast(pfk->dump.skb, BROADCAST_ONE,
+               pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
                                &pfk->sk, sock_net(&pfk->sk));
        pfk->dump.skb = out_skb;
 
@@ -2727,7 +2736,7 @@ static int key_notify_policy_flush(const struct km_event *c)
        hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
        hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
        hdr->sadb_msg_reserved = 0;
-       pfkey_broadcast(skb_out, BROADCAST_ALL, NULL, c->net);
+       pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
        return 0;
 
 }
@@ -2793,7 +2802,7 @@ static int pfkey_process(struct sock *sk, struct sk_buff *skb, const struct sadb
        void *ext_hdrs[SADB_EXT_MAX];
        int err;
 
-       pfkey_broadcast(skb_clone(skb, GFP_KERNEL),
+       pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
                        BROADCAST_PROMISC_ONLY, NULL, sock_net(sk));
 
        memset(ext_hdrs, 0, sizeof(ext_hdrs));
@@ -2999,7 +3008,8 @@ static int key_notify_sa_expire(struct xfrm_state *x, const struct km_event *c)
        out_hdr->sadb_msg_seq = 0;
        out_hdr->sadb_msg_pid = 0;
 
-       pfkey_broadcast(out_skb, BROADCAST_REGISTERED, NULL, xs_net(x));
+       pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL,
+                       xs_net(x));
        return 0;
 }
 
@@ -3171,7 +3181,8 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
                       xfrm_ctx->ctx_len);
        }
 
-       return pfkey_broadcast(skb, BROADCAST_REGISTERED, NULL, xs_net(x));
+       return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL,
+                              xs_net(x));
 }
 
 static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
@@ -3369,7 +3380,8 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
        n_port->sadb_x_nat_t_port_port = sport;
        n_port->sadb_x_nat_t_port_reserved = 0;
 
-       return pfkey_broadcast(skb, BROADCAST_REGISTERED, NULL, xs_net(x));
+       return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL,
+                              xs_net(x));
 }
 
 #ifdef CONFIG_NET_KEY_MIGRATE
@@ -3561,7 +3573,7 @@ static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
        }
 
        /* broadcast migrate message to sockets */
-       pfkey_broadcast(skb, BROADCAST_ALL, NULL, &init_net);
+       pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, &init_net);
 
        return 0;
 
index 3954b18..a7f078e 100644 (file)
@@ -112,10 +112,9 @@ struct l2tp_net {
 };
 
 static void l2tp_session_set_header_len(struct l2tp_session *session, int version);
-static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
 static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
 
-static inline struct l2tp_net *l2tp_pernet(struct net *net)
+static inline struct l2tp_net *l2tp_pernet(const struct net *net)
 {
        BUG_ON(!net);
 
@@ -123,33 +122,6 @@ static inline struct l2tp_net *l2tp_pernet(struct net *net)
 }
 
 
-/* Tunnel reference counts. Incremented per session that is added to
- * the tunnel.
- */
-static inline void l2tp_tunnel_inc_refcount_1(struct l2tp_tunnel *tunnel)
-{
-       atomic_inc(&tunnel->ref_count);
-}
-
-static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel)
-{
-       if (atomic_dec_and_test(&tunnel->ref_count))
-               l2tp_tunnel_free(tunnel);
-}
-#ifdef L2TP_REFCNT_DEBUG
-#define l2tp_tunnel_inc_refcount(_t) do { \
-               printk(KERN_DEBUG "l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
-               l2tp_tunnel_inc_refcount_1(_t);                         \
-       } while (0)
-#define l2tp_tunnel_dec_refcount(_t) do { \
-               printk(KERN_DEBUG "l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
-               l2tp_tunnel_dec_refcount_1(_t);                         \
-       } while (0)
-#else
-#define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t)
-#define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t)
-#endif
-
 /* Session hash global list for L2TPv3.
  * The session_id SHOULD be random according to RFC3931, but several
  * L2TP implementations use incrementing session_ids.  So we do a real
@@ -225,10 +197,31 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn
 }
 EXPORT_SYMBOL_GPL(l2tp_session_find);
 
+/* Lookup a tunnel. A new reference is held on the returned tunnel. */
+struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id)
+{
+       const struct l2tp_net *pn = l2tp_pernet(net);
+       struct l2tp_tunnel *tunnel;
+
+       rcu_read_lock_bh();
+       list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
+               if (tunnel->tunnel_id == tunnel_id) {
+                       l2tp_tunnel_inc_refcount(tunnel);
+                       rcu_read_unlock_bh();
+
+                       return tunnel;
+               }
+       }
+       rcu_read_unlock_bh();
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(l2tp_tunnel_get);
+
 /* Like l2tp_session_find() but takes a reference on the returned session.
  * Optionally calls session->ref() too if do_ref is true.
  */
-struct l2tp_session *l2tp_session_get(struct net *net,
+struct l2tp_session *l2tp_session_get(const struct net *net,
                                      struct l2tp_tunnel *tunnel,
                                      u32 session_id, bool do_ref)
 {
@@ -305,7 +298,8 @@ EXPORT_SYMBOL_GPL(l2tp_session_get_nth);
 /* Lookup a session by interface name.
  * This is very inefficient but is only used by management interfaces.
  */
-struct l2tp_session *l2tp_session_get_by_ifname(struct net *net, char *ifname,
+struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
+                                               const char *ifname,
                                                bool do_ref)
 {
        struct l2tp_net *pn = l2tp_pernet(net);
@@ -333,21 +327,29 @@ struct l2tp_session *l2tp_session_get_by_ifname(struct net *net, char *ifname,
 }
 EXPORT_SYMBOL_GPL(l2tp_session_get_by_ifname);
 
-static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel,
-                                     struct l2tp_session *session)
+int l2tp_session_register(struct l2tp_session *session,
+                         struct l2tp_tunnel *tunnel)
 {
        struct l2tp_session *session_walk;
        struct hlist_head *g_head;
        struct hlist_head *head;
        struct l2tp_net *pn;
        struct hlist_node *walk;
+       int err;
 
        head = l2tp_session_id_hash(tunnel, session->session_id);
 
        write_lock_bh(&tunnel->hlist_lock);
+       if (!tunnel->acpt_newsess) {
+               err = -ENODEV;
+               goto err_tlock;
+       }
+
        hlist_for_each_entry(session_walk, walk, head, hlist)
-               if (session_walk->session_id == session->session_id)
-                       goto exist;
+               if (session_walk->session_id == session->session_id) {
+                       err = -EEXIST;
+                       goto err_tlock;
+               }
 
        if (tunnel->version == L2TP_HDR_VER_3) {
                pn = l2tp_pernet(tunnel->l2tp_net);
@@ -355,26 +357,40 @@ static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel,
                                                session->session_id);
 
                spin_lock_bh(&pn->l2tp_session_hlist_lock);
+
                hlist_for_each_entry(session_walk, walk, g_head, global_hlist)
-                       if (session_walk->session_id == session->session_id)
-                               goto exist_glob;
+                       if (session_walk->session_id == session->session_id) {
+                               err = -EEXIST;
+                               goto err_tlock_pnlock;
+                       }
 
+               l2tp_tunnel_inc_refcount(tunnel);
+               sock_hold(tunnel->sock);
                hlist_add_head_rcu(&session->global_hlist, g_head);
+
                spin_unlock_bh(&pn->l2tp_session_hlist_lock);
+       } else {
+               l2tp_tunnel_inc_refcount(tunnel);
+               sock_hold(tunnel->sock);
        }
 
        hlist_add_head(&session->hlist, head);
        write_unlock_bh(&tunnel->hlist_lock);
 
+       /* Ignore management session in session count value */
+       if (session->session_id != 0)
+               atomic_inc(&l2tp_session_count);
+
        return 0;
 
-exist_glob:
+err_tlock_pnlock:
        spin_unlock_bh(&pn->l2tp_session_hlist_lock);
-exist:
+err_tlock:
        write_unlock_bh(&tunnel->hlist_lock);
 
-       return -EEXIST;
+       return err;
 }
+EXPORT_SYMBOL_GPL(l2tp_session_register);
 
 /* Lookup a tunnel by id
  */
@@ -819,6 +835,23 @@ discard:
 }
 EXPORT_SYMBOL(l2tp_recv_common);
 
+/* Drop skbs from the session's reorder_q
+ */
+int l2tp_session_queue_purge(struct l2tp_session *session)
+{
+       struct sk_buff *skb = NULL;
+       BUG_ON(!session);
+       BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+       while ((skb = skb_dequeue(&session->reorder_q))) {
+               session->stats.rx_errors++;
+               kfree_skb(skb);
+               if (session->deref)
+                       (*session->deref)(session);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(l2tp_session_queue_purge);
+
 /* Internal UDP receive frame. Do the real work of receiving an L2TP data frame
  * here. The skb is not on a list when we get here.
  * Returns 0 if the packet was a data packet and was successfully passed on.
@@ -1288,6 +1321,7 @@ static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
               "%s: closing all sessions...\n", tunnel->name);
 
        write_lock_bh(&tunnel->hlist_lock);
+       tunnel->acpt_newsess = false;
        for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
 again:
                hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
@@ -1318,6 +1352,8 @@ again:
                                synchronize_rcu();
                        }
 
+                       l2tp_session_queue_purge(session);
+
                        if (session->session_close != NULL)
                                (*session->session_close)(session);
 
@@ -1340,7 +1376,7 @@ again:
 /* Really kill the tunnel.
  * Come here only when all sessions have been cleared from the tunnel.
  */
-static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
+void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
 {
        struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
 
@@ -1358,6 +1394,7 @@ static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
 
        atomic_dec(&l2tp_tunnel_count);
 }
+EXPORT_SYMBOL_GPL(l2tp_tunnel_free);
 
 /* Create a socket for the tunnel, if one isn't set up by
  * userspace. This is used for static tunnels where there is no
@@ -1468,9 +1505,14 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
                encap = cfg->encap;
 
        /* Quick sanity checks */
+       err = -EPROTONOSUPPORT;
+       if (sk->sk_type != SOCK_DGRAM) {
+               pr_debug("tunl %hu: fd %d wrong socket type\n",
+                        tunnel_id, fd);
+               goto err;
+       }
        switch (encap) {
        case L2TP_ENCAPTYPE_UDP:
-               err = -EPROTONOSUPPORT;
                if (sk->sk_protocol != IPPROTO_UDP) {
                        printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
                               tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP);
@@ -1478,7 +1520,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
                }
                break;
        case L2TP_ENCAPTYPE_IP:
-               err = -EPROTONOSUPPORT;
                if (sk->sk_protocol != IPPROTO_L2TP) {
                        printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
                               tunnel_id, fd, sk->sk_protocol, IPPROTO_L2TP);
@@ -1509,6 +1550,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
        tunnel->magic = L2TP_TUNNEL_MAGIC;
        sprintf(&tunnel->name[0], "tunl %u", tunnel_id);
        rwlock_init(&tunnel->hlist_lock);
+       tunnel->acpt_newsess = true;
 
        /* The net we belong to */
        tunnel->l2tp_net = net;
@@ -1638,6 +1680,8 @@ EXPORT_SYMBOL_GPL(l2tp_session_free);
  */
 int l2tp_session_delete(struct l2tp_session *session)
 {
+       l2tp_session_queue_purge(session);
+
        if (session->session_close != NULL)
                (*session->session_close)(session);
 
@@ -1668,7 +1712,6 @@ static void l2tp_session_set_header_len(struct l2tp_session *session, int versio
 struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
 {
        struct l2tp_session *session;
-       int err;
 
        session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL);
        if (session != NULL) {
@@ -1715,25 +1758,7 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
 
                l2tp_session_set_header_len(session, tunnel->version);
 
-               err = l2tp_session_add_to_tunnel(tunnel, session);
-               if (err) {
-                       kfree(session);
-
-                       return ERR_PTR(err);
-               }
-
-               /* Bump the reference count. The session context is deleted
-                * only when this drops to zero.
-                */
                l2tp_session_inc_refcount(session);
-               l2tp_tunnel_inc_refcount(tunnel);
-
-               /* Ensure tunnel socket isn't deleted */
-               sock_hold(tunnel->sock);
-
-               /* Ignore management session in session count value */
-               if (session->session_id != 0)
-                       atomic_inc(&l2tp_session_count);
 
                return session;
        }
index 1caf21e..3169379 100644 (file)
@@ -159,6 +159,10 @@ struct l2tp_tunnel {
        int                     magic;          /* Should be L2TP_TUNNEL_MAGIC */
        struct rcu_head rcu;
        rwlock_t                hlist_lock;     /* protect session_hlist */
+       bool                    acpt_newsess;   /* Indicates whether this
+                                                * tunnel accepts new sessions.
+                                                * Protected by hlist_lock.
+                                                */
        struct hlist_head       session_hlist[L2TP_HASH_SIZE];
                                                /* hashed list of sessions,
                                                 * hashed by id */
@@ -188,7 +192,9 @@ struct l2tp_tunnel {
 };
 
 struct l2tp_nl_cmd_ops {
-       int (*session_create)(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg);
+       int (*session_create)(struct net *net, struct l2tp_tunnel *tunnel,
+                             u32 session_id, u32 peer_session_id,
+                             struct l2tp_session_cfg *cfg);
        int (*session_delete)(struct l2tp_session *session);
 };
 
@@ -222,13 +228,17 @@ out:
        return tunnel;
 }
 
-struct l2tp_session *l2tp_session_get(struct net *net,
+struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id);
+void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
+
+struct l2tp_session *l2tp_session_get(const struct net *net,
                                      struct l2tp_tunnel *tunnel,
                                      u32 session_id, bool do_ref);
 extern struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id);
 struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth,
                                          bool do_ref);
-struct l2tp_session *l2tp_session_get_by_ifname(struct net *net, char *ifname,
+struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
+                                               const char *ifname,
                                                bool do_ref);
 extern struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id);
 extern struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth);
@@ -236,9 +246,12 @@ extern struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth);
 extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp);
 extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel);
 extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg);
+int l2tp_session_register(struct l2tp_session *session,
+                         struct l2tp_tunnel *tunnel);
 extern int l2tp_session_delete(struct l2tp_session *session);
 extern void l2tp_session_free(struct l2tp_session *session);
 extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb));
+extern int l2tp_session_queue_purge(struct l2tp_session *session);
 extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
 
 extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len);
@@ -247,6 +260,17 @@ extern int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_c
 extern void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
 int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 
+static inline void l2tp_tunnel_inc_refcount(struct l2tp_tunnel *tunnel)
+{
+       atomic_inc(&tunnel->ref_count);
+}
+
+static inline void l2tp_tunnel_dec_refcount(struct l2tp_tunnel *tunnel)
+{
+       if (atomic_dec_and_test(&tunnel->ref_count))
+               l2tp_tunnel_free(tunnel);
+}
+
 /* Session reference counts. Incremented when code obtains a reference
  * to a session.
  */
index 76820d6..35c8973 100644 (file)
@@ -39,25 +39,13 @@ struct l2tp_eth {
        struct net_device       *dev;
        struct sock             *tunnel_sock;
        struct l2tp_session     *session;
-       struct list_head        list;
 };
 
 /* via l2tp_session_priv() */
 struct l2tp_eth_sess {
-       struct net_device       *dev;
-};
-
-/* per-net private data for this module */
-static unsigned int l2tp_eth_net_id;
-struct l2tp_eth_net {
-       struct list_head l2tp_eth_dev_list;
-       spinlock_t l2tp_eth_lock;
+       struct net_device __rcu *dev;
 };
 
-static inline struct l2tp_eth_net *l2tp_eth_pernet(struct net *net)
-{
-       return net_generic(net, l2tp_eth_net_id);
-}
 
 static int l2tp_eth_dev_init(struct net_device *dev)
 {
@@ -73,12 +61,13 @@ static int l2tp_eth_dev_init(struct net_device *dev)
 static void l2tp_eth_dev_uninit(struct net_device *dev)
 {
        struct l2tp_eth *priv = netdev_priv(dev);
-       struct l2tp_eth_net *pn = l2tp_eth_pernet(dev_net(dev));
+       struct l2tp_eth_sess *spriv;
 
-       spin_lock(&pn->l2tp_eth_lock);
-       list_del_init(&priv->list);
-       spin_unlock(&pn->l2tp_eth_lock);
-       dev_put(dev);
+       spriv = l2tp_session_priv(priv->session);
+       RCU_INIT_POINTER(spriv->dev, NULL);
+       /* No need for synchronize_net() here. We're called by
+        * unregister_netdev*(), which does the synchronisation for us.
+        */
 }
 
 static int l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -111,7 +100,7 @@ static void l2tp_eth_dev_setup(struct net_device *dev)
 static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len)
 {
        struct l2tp_eth_sess *spriv = l2tp_session_priv(session);
-       struct net_device *dev = spriv->dev;
+       struct net_device *dev;
 
        if (session->debug & L2TP_MSG_DATA) {
                unsigned int length;
@@ -143,14 +132,22 @@ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb,
        skb_dst_drop(skb);
        nf_reset(skb);
 
+       rcu_read_lock();
+       dev = rcu_dereference(spriv->dev);
+       if (!dev)
+               goto error_rcu;
+
        if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) {
                dev->stats.rx_packets++;
                dev->stats.rx_bytes += data_len;
        } else
                dev->stats.rx_errors++;
+       rcu_read_unlock();
 
        return;
 
+error_rcu:
+       rcu_read_unlock();
 error:
        dev->stats.rx_errors++;
        kfree_skb(skb);
@@ -163,11 +160,15 @@ static void l2tp_eth_delete(struct l2tp_session *session)
 
        if (session) {
                spriv = l2tp_session_priv(session);
-               dev = spriv->dev;
+
+               rtnl_lock();
+               dev = rtnl_dereference(spriv->dev);
                if (dev) {
-                       unregister_netdev(dev);
-                       spriv->dev = NULL;
+                       unregister_netdevice(dev);
+                       rtnl_unlock();
                        module_put(THIS_MODULE);
+               } else {
+                       rtnl_unlock();
                }
        }
 }
@@ -177,35 +178,40 @@ static void l2tp_eth_show(struct seq_file *m, void *arg)
 {
        struct l2tp_session *session = arg;
        struct l2tp_eth_sess *spriv = l2tp_session_priv(session);
-       struct net_device *dev = spriv->dev;
+       struct net_device *dev;
+
+       rcu_read_lock();
+       dev = rcu_dereference(spriv->dev);
+       if (!dev) {
+               rcu_read_unlock();
+               return;
+       }
+       dev_hold(dev);
+       rcu_read_unlock();
 
        seq_printf(m, "   interface %s\n", dev->name);
+
+       dev_put(dev);
 }
 #endif
 
-static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
+static int l2tp_eth_create(struct net *net, struct l2tp_tunnel *tunnel,
+                          u32 session_id, u32 peer_session_id,
+                          struct l2tp_session_cfg *cfg)
 {
        struct net_device *dev;
        char name[IFNAMSIZ];
-       struct l2tp_tunnel *tunnel;
        struct l2tp_session *session;
        struct l2tp_eth *priv;
        struct l2tp_eth_sess *spriv;
        int rc;
-       struct l2tp_eth_net *pn;
-
-       tunnel = l2tp_tunnel_find(net, tunnel_id);
-       if (!tunnel) {
-               rc = -ENODEV;
-               goto out;
-       }
 
        if (cfg->ifname) {
                dev = dev_get_by_name(net, cfg->ifname);
                if (dev) {
                        dev_put(dev);
                        rc = -EEXIST;
-                       goto out;
+                       goto err;
                }
                strlcpy(name, cfg->ifname, IFNAMSIZ);
        } else
@@ -215,13 +221,13 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p
                                      peer_session_id, cfg);
        if (IS_ERR(session)) {
                rc = PTR_ERR(session);
-               goto out;
+               goto err;
        }
 
        dev = alloc_netdev(sizeof(*priv), name, l2tp_eth_dev_setup);
        if (!dev) {
                rc = -ENOMEM;
-               goto out_del_session;
+               goto err_sess;
        }
 
        dev_net_set(dev, net);
@@ -233,7 +239,6 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p
        priv = netdev_priv(dev);
        priv->dev = dev;
        priv->session = session;
-       INIT_LIST_HEAD(&priv->list);
 
        priv->tunnel_sock = tunnel->sock;
        session->recv_skb = l2tp_eth_dev_recv;
@@ -243,48 +248,50 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p
 #endif
 
        spriv = l2tp_session_priv(session);
-       spriv->dev = dev;
 
-       rc = register_netdev(dev);
-       if (rc < 0)
-               goto out_del_dev;
+       l2tp_session_inc_refcount(session);
 
-       __module_get(THIS_MODULE);
-       /* Must be done after register_netdev() */
-       strlcpy(session->ifname, dev->name, IFNAMSIZ);
+       rtnl_lock();
 
-       dev_hold(dev);
-       pn = l2tp_eth_pernet(dev_net(dev));
-       spin_lock(&pn->l2tp_eth_lock);
-       list_add(&priv->list, &pn->l2tp_eth_dev_list);
-       spin_unlock(&pn->l2tp_eth_lock);
+       /* Register both device and session while holding the rtnl lock. This
+        * ensures that l2tp_eth_delete() will see that there's a device to
+        * unregister, even if it happened to run before we assign spriv->dev.
+        */
+       rc = l2tp_session_register(session, tunnel);
+       if (rc < 0) {
+               rtnl_unlock();
+               goto err_sess_dev;
+       }
 
-       return 0;
+       rc = register_netdevice(dev);
+       if (rc < 0) {
+               rtnl_unlock();
+               l2tp_session_delete(session);
+               l2tp_session_dec_refcount(session);
+               free_netdev(dev);
 
-out_del_dev:
-       free_netdev(dev);
-       spriv->dev = NULL;
-out_del_session:
-       l2tp_session_delete(session);
-out:
-       return rc;
-}
+               return rc;
+       }
 
-static __net_init int l2tp_eth_init_net(struct net *net)
-{
-       struct l2tp_eth_net *pn = net_generic(net, l2tp_eth_net_id);
+       strlcpy(session->ifname, dev->name, IFNAMSIZ);
+       rcu_assign_pointer(spriv->dev, dev);
+
+       rtnl_unlock();
 
-       INIT_LIST_HEAD(&pn->l2tp_eth_dev_list);
-       spin_lock_init(&pn->l2tp_eth_lock);
+       l2tp_session_dec_refcount(session);
+
+       __module_get(THIS_MODULE);
 
        return 0;
-}
 
-static struct pernet_operations l2tp_eth_net_ops = {
-       .init = l2tp_eth_init_net,
-       .id   = &l2tp_eth_net_id,
-       .size = sizeof(struct l2tp_eth_net),
-};
+err_sess_dev:
+       l2tp_session_dec_refcount(session);
+       free_netdev(dev);
+err_sess:
+       kfree(session);
+err:
+       return rc;
+}
 
 
 static const struct l2tp_nl_cmd_ops l2tp_eth_nl_cmd_ops = {
@@ -299,25 +306,18 @@ static int __init l2tp_eth_init(void)
 
        err = l2tp_nl_register_ops(L2TP_PWTYPE_ETH, &l2tp_eth_nl_cmd_ops);
        if (err)
-               goto out;
-
-       err = register_pernet_device(&l2tp_eth_net_ops);
-       if (err)
-               goto out_unreg;
+               goto err;
 
        printk(KERN_INFO "L2TP ethernet pseudowire support (L2TPv3)\n");
 
        return 0;
 
-out_unreg:
-       l2tp_nl_unregister_ops(L2TP_PWTYPE_ETH);
-out:
+err:
        return err;
 }
 
 static void __exit l2tp_eth_exit(void)
 {
-       unregister_pernet_device(&l2tp_eth_net_ops);
        l2tp_nl_unregister_ops(L2TP_PWTYPE_ETH);
 }
 
index a753c9b..2e22254 100644 (file)
@@ -127,6 +127,7 @@ static int l2tp_ip_recv(struct sk_buff *skb)
        unsigned char *ptr, *optr;
        struct l2tp_session *session;
        struct l2tp_tunnel *tunnel = NULL;
+       struct iphdr *iph;
        int length;
        int offset;
 
@@ -189,21 +190,16 @@ pass_up:
                goto discard;
 
        tunnel_id = ntohl(*(__be32 *) &skb->data[4]);
-       tunnel = l2tp_tunnel_find(&init_net, tunnel_id);
-       if (tunnel != NULL)
-               sk = tunnel->sock;
-       else {
-               struct iphdr *iph = (struct iphdr *) skb_network_header(skb);
-
-               read_lock_bh(&l2tp_ip_lock);
-               sk = __l2tp_ip_bind_lookup(&init_net, iph->daddr, 0, tunnel_id);
-               read_unlock_bh(&l2tp_ip_lock);
-       }
+       iph = (struct iphdr *)skb_network_header(skb);
 
-       if (sk == NULL)
+       read_lock_bh(&l2tp_ip_lock);
+       sk = __l2tp_ip_bind_lookup(&init_net, iph->daddr, 0, tunnel_id);
+       if (!sk) {
+               read_unlock_bh(&l2tp_ip_lock);
                goto discard;
-
+       }
        sock_hold(sk);
+       read_unlock_bh(&l2tp_ip_lock);
 
        if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_put;
@@ -432,7 +428,7 @@ static int l2tp_ip_backlog_recv(struct sock *sk, struct sk_buff *skb)
 drop:
        IP_INC_STATS(&init_net, IPSTATS_MIB_INDISCARDS);
        kfree_skb(skb);
-       return -1;
+       return 0;
 }
 
 /* Userspace will call sendmsg() on the tunnel socket to send L2TP
index 6fd6322..9f80edf 100644 (file)
@@ -57,10 +57,12 @@ static struct l2tp_session *l2tp_nl_session_get(struct genl_info *info,
                   (info->attrs[L2TP_ATTR_CONN_ID])) {
                tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
                session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]);
-               tunnel = l2tp_tunnel_find(net, tunnel_id);
-               if (tunnel)
+               tunnel = l2tp_tunnel_get(net, tunnel_id);
+               if (tunnel) {
                        session = l2tp_session_get(net, tunnel, session_id,
                                                   do_ref);
+                       l2tp_tunnel_dec_refcount(tunnel);
+               }
        }
 
        return session;
@@ -182,14 +184,16 @@ static int l2tp_nl_cmd_tunnel_delete(struct sk_buff *skb, struct genl_info *info
        }
        tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
 
-       tunnel = l2tp_tunnel_find(net, tunnel_id);
-       if (tunnel == NULL) {
+       tunnel = l2tp_tunnel_get(net, tunnel_id);
+       if (!tunnel) {
                ret = -ENODEV;
                goto out;
        }
 
        (void) l2tp_tunnel_delete(tunnel);
 
+       l2tp_tunnel_dec_refcount(tunnel);
+
 out:
        return ret;
 }
@@ -207,8 +211,8 @@ static int l2tp_nl_cmd_tunnel_modify(struct sk_buff *skb, struct genl_info *info
        }
        tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
 
-       tunnel = l2tp_tunnel_find(net, tunnel_id);
-       if (tunnel == NULL) {
+       tunnel = l2tp_tunnel_get(net, tunnel_id);
+       if (!tunnel) {
                ret = -ENODEV;
                goto out;
        }
@@ -216,6 +220,8 @@ static int l2tp_nl_cmd_tunnel_modify(struct sk_buff *skb, struct genl_info *info
        if (info->attrs[L2TP_ATTR_DEBUG])
                tunnel->debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
 
+       l2tp_tunnel_dec_refcount(tunnel);
+
 out:
        return ret;
 }
@@ -289,34 +295,37 @@ static int l2tp_nl_cmd_tunnel_get(struct sk_buff *skb, struct genl_info *info)
 
        if (!info->attrs[L2TP_ATTR_CONN_ID]) {
                ret = -EINVAL;
-               goto out;
+               goto err;
        }
 
        tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
 
-       tunnel = l2tp_tunnel_find(net, tunnel_id);
-       if (tunnel == NULL) {
-               ret = -ENODEV;
-               goto out;
-       }
-
        msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
        if (!msg) {
                ret = -ENOMEM;
-               goto out;
+               goto err;
+       }
+
+       tunnel = l2tp_tunnel_get(net, tunnel_id);
+       if (!tunnel) {
+               ret = -ENODEV;
+               goto err_nlmsg;
        }
 
        ret = l2tp_nl_tunnel_send(msg, info->snd_pid, info->snd_seq,
                                  NLM_F_ACK, tunnel);
        if (ret < 0)
-               goto err_out;
+               goto err_nlmsg_tunnel;
+
+       l2tp_tunnel_dec_refcount(tunnel);
 
        return genlmsg_unicast(net, msg, info->snd_pid);
 
-err_out:
+err_nlmsg_tunnel:
+       l2tp_tunnel_dec_refcount(tunnel);
+err_nlmsg:
        nlmsg_free(msg);
-
-out:
+err:
        return ret;
 }
 
@@ -352,7 +361,6 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
        u32 peer_session_id;
        int ret = 0;
        struct l2tp_tunnel *tunnel;
-       struct l2tp_session *session;
        struct l2tp_session_cfg cfg = { 0, };
        struct net *net = genl_info_net(info);
 
@@ -360,8 +368,9 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
                ret = -EINVAL;
                goto out;
        }
+
        tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
-       tunnel = l2tp_tunnel_find(net, tunnel_id);
+       tunnel = l2tp_tunnel_get(net, tunnel_id);
        if (!tunnel) {
                ret = -ENODEV;
                goto out;
@@ -369,29 +378,24 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
 
        if (!info->attrs[L2TP_ATTR_SESSION_ID]) {
                ret = -EINVAL;
-               goto out;
+               goto out_tunnel;
        }
        session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]);
-       session = l2tp_session_find(net, tunnel, session_id);
-       if (session) {
-               ret = -EEXIST;
-               goto out;
-       }
 
        if (!info->attrs[L2TP_ATTR_PEER_SESSION_ID]) {
                ret = -EINVAL;
-               goto out;
+               goto out_tunnel;
        }
        peer_session_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_SESSION_ID]);
 
        if (!info->attrs[L2TP_ATTR_PW_TYPE]) {
                ret = -EINVAL;
-               goto out;
+               goto out_tunnel;
        }
        cfg.pw_type = nla_get_u16(info->attrs[L2TP_ATTR_PW_TYPE]);
        if (cfg.pw_type >= __L2TP_PWTYPE_MAX) {
                ret = -EINVAL;
-               goto out;
+               goto out_tunnel;
        }
 
        if (tunnel->version > 2) {
@@ -413,7 +417,7 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
                        u16 len = nla_len(info->attrs[L2TP_ATTR_COOKIE]);
                        if (len > 8) {
                                ret = -EINVAL;
-                               goto out;
+                               goto out_tunnel;
                        }
                        cfg.cookie_len = len;
                        memcpy(&cfg.cookie[0], nla_data(info->attrs[L2TP_ATTR_COOKIE]), len);
@@ -422,7 +426,7 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
                        u16 len = nla_len(info->attrs[L2TP_ATTR_PEER_COOKIE]);
                        if (len > 8) {
                                ret = -EINVAL;
-                               goto out;
+                               goto out_tunnel;
                        }
                        cfg.peer_cookie_len = len;
                        memcpy(&cfg.peer_cookie[0], nla_data(info->attrs[L2TP_ATTR_PEER_COOKIE]), len);
@@ -458,7 +462,7 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
        if ((l2tp_nl_cmd_ops[cfg.pw_type] == NULL) ||
            (l2tp_nl_cmd_ops[cfg.pw_type]->session_create == NULL)) {
                ret = -EPROTONOSUPPORT;
-               goto out;
+               goto out_tunnel;
        }
 
        /* Check that pseudowire-specific params are present */
@@ -468,7 +472,7 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
        case L2TP_PWTYPE_ETH_VLAN:
                if (!info->attrs[L2TP_ATTR_VLAN_ID]) {
                        ret = -EINVAL;
-                       goto out;
+                       goto out_tunnel;
                }
                break;
        case L2TP_PWTYPE_ETH:
@@ -482,11 +486,13 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf
                break;
        }
 
-       ret = -EPROTONOSUPPORT;
-       if (l2tp_nl_cmd_ops[cfg.pw_type]->session_create)
-               ret = (*l2tp_nl_cmd_ops[cfg.pw_type]->session_create)(net, tunnel_id,
-                       session_id, peer_session_id, &cfg);
+       ret = l2tp_nl_cmd_ops[cfg.pw_type]->session_create(net, tunnel,
+                                                          session_id,
+                                                          peer_session_id,
+                                                          &cfg);
 
+out_tunnel:
+       l2tp_tunnel_dec_refcount(tunnel);
 out:
        return ret;
 }
@@ -583,6 +589,8 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 pid, u32 seq, int flags
 
        if (session->ifname && session->ifname[0])
                NLA_PUT_STRING(skb, L2TP_ATTR_IFNAME, session->ifname);
+       if (session->offset)
+               NLA_PUT_U16(skb, L2TP_ATTR_OFFSET, session->offset);
        if (session->cookie_len)
                NLA_PUT(skb, L2TP_ATTR_COOKIE, session->cookie_len, &session->cookie[0]);
        if (session->peer_cookie_len)
index 45c23bd..62d7e71 100644 (file)
@@ -95,6 +95,7 @@
 #include <net/ip.h>
 #include <net/udp.h>
 #include <net/xfrm.h>
+#include <net/inet_common.h>
 
 #include <asm/byteorder.h>
 #include <linux/atomic.h>
 struct pppol2tp_session {
        int                     owner;          /* pid that opened the socket */
 
-       struct sock             *sock;          /* Pointer to the session
+       struct mutex            sk_lock;        /* Protects .sk */
+       struct sock __rcu       *sk;            /* Pointer to the session
                                                 * PPPoX socket */
+       struct sock             *__sk;          /* Copy of .sk, for cleanup */
+       struct rcu_head         rcu;            /* For asynchronous release */
        struct sock             *tunnel_sock;   /* Pointer to the tunnel UDP
                                                 * socket */
        int                     flags;          /* accessed by PPPIOCGFLAGS.
@@ -141,6 +145,24 @@ static const struct ppp_channel_ops pppol2tp_chan_ops = {
 
 static const struct proto_ops pppol2tp_ops;
 
+/* Retrieves the pppol2tp socket associated to a session.
+ * A reference is held on the returned socket, so this function must be paired
+ * with sock_put().
+ */
+static struct sock *pppol2tp_session_get_sock(struct l2tp_session *session)
+{
+       struct pppol2tp_session *ps = l2tp_session_priv(session);
+       struct sock *sk;
+
+       rcu_read_lock();
+       sk = rcu_dereference(ps->sk);
+       if (sk)
+               sock_hold(sk);
+       rcu_read_unlock();
+
+       return sk;
+}
+
 /* Helpers to obtain tunnel/session contexts from sockets.
  */
 static inline struct l2tp_session *pppol2tp_sock_to_session(struct sock *sk)
@@ -228,7 +250,8 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
        /* If the socket is bound, send it in to PPP's input queue. Otherwise
         * queue it on the session socket.
         */
-       sk = ps->sock;
+       rcu_read_lock();
+       sk = rcu_dereference(ps->sk);
        if (sk == NULL)
                goto no_sock;
 
@@ -264,31 +287,17 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
                session->stats.rx_errors++;
                kfree_skb(skb);
        }
+       rcu_read_unlock();
 
        return;
 
 no_sock:
+       rcu_read_unlock();
        PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
               "%s: no socket\n", session->name);
        kfree_skb(skb);
 }
 
-static void pppol2tp_session_sock_hold(struct l2tp_session *session)
-{
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
-
-       if (ps->sock)
-               sock_hold(ps->sock);
-}
-
-static void pppol2tp_session_sock_put(struct l2tp_session *session)
-{
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
-
-       if (ps->sock)
-               sock_put(ps->sock);
-}
-
 /************************************************************************
  * Transmit handling
  ***********************************************************************/
@@ -454,41 +463,28 @@ abort:
  * Session (and tunnel control) socket create/destroy.
  *****************************************************************************/
 
+static void pppol2tp_put_sk(struct rcu_head *head)
+{
+       struct pppol2tp_session *ps;
+
+       ps = container_of(head, typeof(*ps), rcu);
+       sock_put(ps->__sk);
+}
+
 /* Called by l2tp_core when a session socket is being closed.
  */
 static void pppol2tp_session_close(struct l2tp_session *session)
 {
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
-       struct sock *sk = ps->sock;
-       struct sk_buff *skb;
-
-       BUG_ON(session->magic != L2TP_SESSION_MAGIC);
-
-       if (session->session_id == 0)
-               goto out;
-
-       if (sk != NULL) {
-               lock_sock(sk);
-
-               if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
-                       pppox_unbind_sock(sk);
-                       sk->sk_state = PPPOX_DEAD;
-                       sk->sk_state_change(sk);
-               }
-
-               /* Purge any queued data */
-               skb_queue_purge(&sk->sk_receive_queue);
-               skb_queue_purge(&sk->sk_write_queue);
-               while ((skb = skb_dequeue(&session->reorder_q))) {
-                       kfree_skb(skb);
-                       sock_put(sk);
-               }
-
-               release_sock(sk);
-       }
+       struct pppol2tp_session *ps;
 
-out:
-       return;
+       ps = l2tp_session_priv(session);
+       mutex_lock(&ps->sk_lock);
+       ps->__sk = rcu_dereference_protected(ps->sk,
+                                            lockdep_is_held(&ps->sk_lock));
+       RCU_INIT_POINTER(ps->sk, NULL);
+       if (ps->__sk)
+               call_rcu(&ps->rcu, pppol2tp_put_sk);
+       mutex_unlock(&ps->sk_lock);
 }
 
 /* Really kill the session socket. (Called from sock_put() if
@@ -535,19 +531,19 @@ static int pppol2tp_release(struct socket *sock)
        sock_orphan(sk);
        sock->sk = NULL;
 
+       /* If the socket is associated with a session,
+        * l2tp_session_delete will call pppol2tp_session_close which
+        * will drop the session's ref on the socket.
+        */
        session = pppol2tp_sock_to_session(sk);
+       if (session) {
+               l2tp_session_delete(session);
+               /* drop the ref obtained by pppol2tp_sock_to_session */
+               sock_put(sk);
+       }
 
-       /* Purge any queued data */
        skb_queue_purge(&sk->sk_receive_queue);
        skb_queue_purge(&sk->sk_write_queue);
-       if (session != NULL) {
-               struct sk_buff *skb;
-               while ((skb = skb_dequeue(&session->reorder_q))) {
-                       kfree_skb(skb);
-                       sock_put(sk);
-               }
-               sock_put(sk);
-       }
 
        release_sock(sk);
 
@@ -614,16 +610,47 @@ out:
 static void pppol2tp_show(struct seq_file *m, void *arg)
 {
        struct l2tp_session *session = arg;
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
+       struct sock *sk;
+
+       sk = pppol2tp_session_get_sock(session);
+       if (sk) {
+               struct pppox_sock *po = pppox_sk(sk);
 
-       if (ps) {
-               struct pppox_sock *po = pppox_sk(ps->sock);
-               if (po)
-                       seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
+               seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
+               sock_put(sk);
        }
 }
 #endif
 
+static void pppol2tp_session_init(struct l2tp_session *session)
+{
+       struct pppol2tp_session *ps;
+       struct dst_entry *dst;
+
+       session->recv_skb = pppol2tp_recv;
+       session->session_close = pppol2tp_session_close;
+#if IS_ENABLED(CONFIG_L2TP_DEBUGFS)
+       session->show = pppol2tp_show;
+#endif
+
+       ps = l2tp_session_priv(session);
+       mutex_init(&ps->sk_lock);
+       ps->tunnel_sock = session->tunnel->sock;
+       ps->owner = current->pid;
+
+       /* If PMTU discovery was enabled, use the MTU that was discovered */
+       dst = sk_dst_get(session->tunnel->sock);
+       if (dst) {
+               u32 pmtu = dst_mtu(dst);
+
+               if (pmtu) {
+                       session->mtu = pmtu - PPPOL2TP_HEADER_OVERHEAD;
+                       session->mru = pmtu - PPPOL2TP_HEADER_OVERHEAD;
+               }
+               dst_release(dst);
+       }
+}
+
 /* connect() handler. Attach a PPPoX socket to a tunnel UDP socket
  */
 static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
@@ -636,12 +663,12 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        struct l2tp_session *session = NULL;
        struct l2tp_tunnel *tunnel;
        struct pppol2tp_session *ps;
-       struct dst_entry *dst;
        struct l2tp_session_cfg cfg = { 0, };
        int error = 0;
        u32 tunnel_id, peer_tunnel_id;
        u32 session_id, peer_session_id;
        bool drop_refcnt = false;
+       bool drop_tunnel = false;
        int ver = 2;
        int fd;
 
@@ -685,7 +712,9 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        if (tunnel_id == 0)
                goto end;
 
-       tunnel = l2tp_tunnel_find(sock_net(sk), tunnel_id);
+       tunnel = l2tp_tunnel_get(sock_net(sk), tunnel_id);
+       if (tunnel)
+               drop_tunnel = true;
 
        /* Special case: create tunnel context if session_id and
         * peer_session_id is 0. Otherwise look up tunnel using supplied
@@ -730,13 +759,17 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
                /* Using a pre-existing session is fine as long as it hasn't
                 * been connected yet.
                 */
-               if (ps->sock) {
+               mutex_lock(&ps->sk_lock);
+               if (rcu_dereference_protected(ps->sk,
+                                             lockdep_is_held(&ps->sk_lock))) {
+                       mutex_unlock(&ps->sk_lock);
                        error = -EEXIST;
                        goto end;
                }
 
                /* consistency checks */
                if (ps->tunnel_sock != tunnel->sock) {
+                       mutex_unlock(&ps->sk_lock);
                        error = -EEXIST;
                        goto end;
                }
@@ -752,35 +785,19 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
                        error = PTR_ERR(session);
                        goto end;
                }
-       }
-
-       /* Associate session with its PPPoL2TP socket */
-       ps = l2tp_session_priv(session);
-       ps->owner            = current->pid;
-       ps->sock             = sk;
-       ps->tunnel_sock = tunnel->sock;
 
-       session->recv_skb       = pppol2tp_recv;
-       session->session_close  = pppol2tp_session_close;
-#if defined(CONFIG_L2TP_DEBUGFS) || defined(CONFIG_L2TP_DEBUGFS_MODULE)
-       session->show           = pppol2tp_show;
-#endif
-
-       /* We need to know each time a skb is dropped from the reorder
-        * queue.
-        */
-       session->ref = pppol2tp_session_sock_hold;
-       session->deref = pppol2tp_session_sock_put;
-
-       /* If PMTU discovery was enabled, use the MTU that was discovered */
-       dst = sk_dst_get(tunnel->sock);
-       if (dst != NULL) {
-               u32 pmtu = dst_mtu(dst);
+               pppol2tp_session_init(session);
+               ps = l2tp_session_priv(session);
+               l2tp_session_inc_refcount(session);
 
-               if (pmtu != 0)
-                       session->mtu = session->mru = pmtu -
-                               PPPOL2TP_HEADER_OVERHEAD;
-               dst_release(dst);
+               mutex_lock(&ps->sk_lock);
+               error = l2tp_session_register(session, tunnel);
+               if (error < 0) {
+                       mutex_unlock(&ps->sk_lock);
+                       kfree(session);
+                       goto end;
+               }
+               drop_refcnt = true;
        }
 
        /* Special case: if source & dest session_id == 0x0000, this
@@ -805,12 +822,24 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        po->chan.mtu     = session->mtu;
 
        error = ppp_register_net_channel(sock_net(sk), &po->chan);
-       if (error)
+       if (error) {
+               mutex_unlock(&ps->sk_lock);
                goto end;
+       }
 
 out_no_ppp:
        /* This is how we get the session context from the socket. */
+       sock_hold(sk);
        sk->sk_user_data = session;
+       rcu_assign_pointer(ps->sk, sk);
+       mutex_unlock(&ps->sk_lock);
+
+       /* Keep the reference we've grabbed on the session: sk doesn't expect
+        * the session to disappear. pppol2tp_session_destruct() is responsible
+        * for dropping it.
+        */
+       drop_refcnt = false;
+
        sk->sk_state = PPPOX_CONNECTED;
        PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
               "%s: created\n", session->name);
@@ -818,6 +847,8 @@ out_no_ppp:
 end:
        if (drop_refcnt)
                l2tp_session_dec_refcount(session);
+       if (drop_tunnel)
+               l2tp_tunnel_dec_refcount(tunnel);
        release_sock(sk);
 
        return error;
@@ -825,25 +856,19 @@ end:
 
 #ifdef CONFIG_L2TP_V3
 
-/* Called when creating sessions via the netlink interface.
- */
-static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
+/* Called when creating sessions via the netlink interface. */
+static int pppol2tp_session_create(struct net *net, struct l2tp_tunnel *tunnel,
+                                  u32 session_id, u32 peer_session_id,
+                                  struct l2tp_session_cfg *cfg)
 {
        int error;
-       struct l2tp_tunnel *tunnel;
        struct l2tp_session *session;
-       struct pppol2tp_session *ps;
-
-       tunnel = l2tp_tunnel_find(net, tunnel_id);
-
-       /* Error if we can't find the tunnel */
-       error = -ENOENT;
-       if (tunnel == NULL)
-               goto out;
 
        /* Error if tunnel socket is not prepped */
-       if (tunnel->sock == NULL)
-               goto out;
+       if (!tunnel->sock) {
+               error = -ENOENT;
+               goto err;
+       }
 
        /* Default MTU values. */
        if (cfg->mtu == 0)
@@ -857,33 +882,23 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i
                                      peer_session_id, cfg);
        if (IS_ERR(session)) {
                error = PTR_ERR(session);
-               goto out;
+               goto err;
        }
 
-       ps = l2tp_session_priv(session);
-       ps->tunnel_sock = tunnel->sock;
+       pppol2tp_session_init(session);
 
-       PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-              "%s: created\n", session->name);
+       error = l2tp_session_register(session, tunnel);
+       if (error < 0)
+               goto err_sess;
 
-       error = 0;
+       return 0;
 
-out:
+err_sess:
+       kfree(session);
+err:
        return error;
 }
 
-/* Called when deleting sessions via the netlink interface.
- */
-static int pppol2tp_session_delete(struct l2tp_session *session)
-{
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
-
-       if (ps->sock == NULL)
-               l2tp_session_dec_refcount(session);
-
-       return 0;
-}
-
 #endif /* CONFIG_L2TP_V3 */
 
 /* getname() support.
@@ -1001,8 +1016,9 @@ static int pppol2tp_session_ioctl(struct l2tp_session *session,
               "%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx)\n",
               session->name, cmd, arg);
 
-       sk = ps->sock;
-       sock_hold(sk);
+       sk = pppol2tp_session_get_sock(session);
+       if (!sk)
+               return -EBADR;
 
        switch (cmd) {
        case SIOCGIFMTU:
@@ -1279,7 +1295,6 @@ static int pppol2tp_session_setsockopt(struct sock *sk,
                                       int optname, int val)
 {
        int err = 0;
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
 
        switch (optname) {
        case PPPOL2TP_SO_RECVSEQ:
@@ -1299,8 +1314,8 @@ static int pppol2tp_session_setsockopt(struct sock *sk,
                }
                session->send_seq = val ? -1 : 0;
                {
-                       struct sock *ssk      = ps->sock;
-                       struct pppox_sock *po = pppox_sk(ssk);
+                       struct pppox_sock *po = pppox_sk(sk);
+
                        po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :
                                PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
                }
@@ -1635,8 +1650,9 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
 {
        struct l2tp_session *session = v;
        struct l2tp_tunnel *tunnel = session->tunnel;
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
-       struct pppox_sock *po = pppox_sk(ps->sock);
+       unsigned char state;
+       char user_data_ok;
+       struct sock *sk;
        u32 ip = 0;
        u16 port = 0;
 
@@ -1646,6 +1662,15 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
                port = ntohs(inet->inet_sport);
        }
 
+       sk = pppol2tp_session_get_sock(session);
+       if (sk) {
+               state = sk->sk_state;
+               user_data_ok = (session == sk->sk_user_data) ? 'Y' : 'N';
+       } else {
+               state = 0;
+               user_data_ok = 'N';
+       }
+
        seq_printf(m, "  SESSION '%s' %08X/%d %04X/%04X -> "
                   "%04X/%04X %d %c\n",
                   session->name, ip, port,
@@ -1653,9 +1678,7 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
                   session->session_id,
                   tunnel->peer_tunnel_id,
                   session->peer_session_id,
-                  ps->sock->sk_state,
-                  (session == ps->sock->sk_user_data) ?
-                  'Y' : 'N');
+                  state, user_data_ok);
        seq_printf(m, "   %d/%d/%c/%c/%s %08x %u\n",
                   session->mtu, session->mru,
                   session->recv_seq ? 'R' : '-',
@@ -1672,8 +1695,12 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
                   (unsigned long long)session->stats.rx_bytes,
                   (unsigned long long)session->stats.rx_errors);
 
-       if (po)
+       if (sk) {
+               struct pppox_sock *po = pppox_sk(sk);
+
                seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
+               sock_put(sk);
+       }
 }
 
 static int pppol2tp_seq_show(struct seq_file *m, void *v)
@@ -1798,7 +1825,7 @@ static const struct pppox_proto pppol2tp_proto = {
 
 static const struct l2tp_nl_cmd_ops pppol2tp_nl_cmd_ops = {
        .session_create = pppol2tp_session_create,
-       .session_delete = pppol2tp_session_delete,
+       .session_delete = l2tp_session_delete,
 };
 
 #endif /* CONFIG_L2TP_V3 */
index fb02ea5..bef5111 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright 2005-2006, Devicescape Software, Inc.
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2017      Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -443,6 +444,39 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
        kfree(key);
 }
 
+static bool ieee80211_key_identical(struct ieee80211_sub_if_data *sdata,
+                                   struct ieee80211_key *old,
+                                   struct ieee80211_key *new)
+{
+       u8 tkip_old[WLAN_KEY_LEN_TKIP], tkip_new[WLAN_KEY_LEN_TKIP];
+       u8 *tk_old, *tk_new;
+
+       if (!old || new->conf.keylen != old->conf.keylen)
+               return false;
+
+       tk_old = old->conf.key;
+       tk_new = new->conf.key;
+
+       /*
+        * In station mode, don't compare the TX MIC key, as it's never used
+        * and offloaded rekeying may not care to send it to the host. This
+        * is the case in iwlwifi, for example.
+        */
+       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+           new->conf.cipher == WLAN_CIPHER_SUITE_TKIP &&
+           new->conf.keylen == WLAN_KEY_LEN_TKIP &&
+           !(new->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+               memcpy(tkip_old, tk_old, WLAN_KEY_LEN_TKIP);
+               memcpy(tkip_new, tk_new, WLAN_KEY_LEN_TKIP);
+               memset(tkip_old + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8);
+               memset(tkip_new + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 0, 8);
+               tk_old = tkip_old;
+               tk_new = tkip_new;
+       }
+
+       return !memcmp(tk_old, tk_new, new->conf.keylen);
+}
+
 int ieee80211_key_link(struct ieee80211_key *key,
                       struct ieee80211_sub_if_data *sdata,
                       struct sta_info *sta)
@@ -456,9 +490,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
 
        pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
        idx = key->conf.keyidx;
-       key->local = sdata->local;
-       key->sdata = sdata;
-       key->sta = sta;
 
        if (sta) {
                /*
@@ -477,7 +508,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
                         */
 
                        /* same here, the AP could be using QoS */
-                       ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid);
+                       ap = sta_info_get(sdata, sdata->u.mgd.bssid);
                        if (ap) {
                                if (test_sta_flag(ap, WLAN_STA_WME))
                                        key->conf.flags |=
@@ -495,6 +526,20 @@ int ieee80211_key_link(struct ieee80211_key *key,
        else
                old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
 
+       /*
+        * Silently accept key re-installation without really installing the
+        * new version of the key to avoid nonce reuse or replay issues.
+        */
+       if (ieee80211_key_identical(sdata, old_key, key)) {
+               __ieee80211_key_free(key);
+               ret = 0;
+               goto out;
+       }
+
+       key->local = sdata->local;
+       key->sdata = sdata;
+       key->sta = sta;
+
        increment_tailroom_need_count(sdata);
 
        __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
@@ -504,6 +549,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
 
        ret = ieee80211_key_enable_hw_accel(key);
 
+ out:
        mutex_unlock(&sdata->local->key_mtx);
 
        return ret;
index cc8f8b4..a6cbb7a 100644 (file)
@@ -272,7 +272,7 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
                                return NULL;
                        }
                        rt = (struct rt6_info *) dst;
-                       cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
+                       cookie = rt6_get_cookie(rt);
                        __ip_vs_dst_set(dest, 0, dst_clone(&rt->dst), cookie);
                        IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n",
                                  &dest->addr.in6, &dest->dst_saddr.in6,
index 69ce23f..77a0cc1 100644 (file)
@@ -307,6 +307,21 @@ static void death_by_timeout(unsigned long ul_conntrack)
        nf_ct_put(ct);
 }
 
+static inline bool
+nf_ct_key_equal(struct nf_conntrack_tuple_hash *h,
+                       const struct nf_conntrack_tuple *tuple,
+                       u16 zone)
+{
+       struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
+
+       /* A conntrack can be recreated with the equal tuple,
+        * so we need to check that the conntrack is confirmed
+        */
+       return nf_ct_tuple_equal(tuple, &h->tuple) &&
+               nf_ct_zone(ct) == zone &&
+               nf_ct_is_confirmed(ct);
+}
+
 /*
  * Warning :
  * - Caller must take a reference on returned object
@@ -328,8 +343,7 @@ ____nf_conntrack_find(struct net *net, u16 zone,
        local_bh_disable();
 begin:
        hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[bucket], hnnode) {
-               if (nf_ct_tuple_equal(tuple, &h->tuple) &&
-                   nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) {
+               if (nf_ct_key_equal(h, tuple, zone)) {
                        NF_CT_STAT_INC(net, found);
                        local_bh_enable();
                        return h;
@@ -376,8 +390,7 @@ begin:
                             !atomic_inc_not_zero(&ct->ct_general.use)))
                        h = NULL;
                else {
-                       if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple) ||
-                                    nf_ct_zone(ct) != zone)) {
+                       if (unlikely(!nf_ct_key_equal(h, tuple, zone))) {
                                nf_ct_put(ct);
                                goto begin;
                        }
index f407ebc..95b6ded 100644 (file)
@@ -146,11 +146,11 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
                    (unsigned long) info->timer);
        info->timer->refcnt = 1;
 
+       INIT_WORK(&info->timer->work, idletimer_tg_work);
+
        mod_timer(&info->timer->timer,
                  msecs_to_jiffies(info->timeout * 1000) + jiffies);
 
-       INIT_WORK(&info->timer->work, idletimer_tg_work);
-
        return 0;
 
 out_free_attr:
@@ -191,7 +191,10 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
                pr_debug("timeout value is zero\n");
                return -EINVAL;
        }
-
+       if (info->timeout >= INT_MAX / 1000) {
+               pr_debug("timeout value is too big\n");
+               return -EINVAL;
+       }
        if (info->label[0] == '\0' ||
            strnlen(info->label,
                    MAX_IDLETIMER_LABEL_SIZE) == MAX_IDLETIMER_LABEL_SIZE) {
index 993de2b..d944bc1 100644 (file)
@@ -139,10 +139,11 @@ static int led_tg_check(const struct xt_tgchk_param *par)
                goto exit_alloc;
        }
 
-       /* See if we need to set up a timer */
-       if (ledinfo->delay > 0)
-               setup_timer(&ledinternal->timer, led_timeout_callback,
-                           (unsigned long)ledinternal);
+       /* Since the letinternal timer can be shared between multiple targets,
+        * always set it up, even if the current target does not need it
+        */
+       setup_timer(&ledinternal->timer, led_timeout_callback,
+                   (unsigned long)ledinternal);
 
        list_add_tail(&ledinternal->list, &xt_led_triggers);
 
@@ -179,8 +180,7 @@ static void led_tg_destroy(const struct xt_tgdtor_param *par)
 
        list_del(&ledinternal->list);
 
-       if (ledinfo->delay > 0)
-               del_timer_sync(&ledinternal->timer);
+       del_timer_sync(&ledinternal->timer);
 
        led_trigger_unregister(&ledinternal->netfilter_led_trigger);
 
index f264032..309a520 100644 (file)
@@ -40,24 +40,32 @@ static void xt_rateest_hash_insert(struct xt_rateest *est)
        hlist_add_head(&est->list, &rateest_hash[h]);
 }
 
-struct xt_rateest *xt_rateest_lookup(const char *name)
+static struct xt_rateest *__xt_rateest_lookup(const char *name)
 {
        struct xt_rateest *est;
        struct hlist_node *n;
        unsigned int h;
 
        h = xt_rateest_hash(name);
-       mutex_lock(&xt_rateest_mutex);
        hlist_for_each_entry(est, n, &rateest_hash[h], list) {
                if (strcmp(est->name, name) == 0) {
                        est->refcnt++;
-                       mutex_unlock(&xt_rateest_mutex);
                        return est;
                }
        }
-       mutex_unlock(&xt_rateest_mutex);
+
        return NULL;
 }
+
+struct xt_rateest *xt_rateest_lookup(const char *name)
+{
+       struct xt_rateest *est;
+
+       mutex_lock(&xt_rateest_mutex);
+       est = __xt_rateest_lookup(name);
+       mutex_unlock(&xt_rateest_mutex);
+       return est;
+}
 EXPORT_SYMBOL_GPL(xt_rateest_lookup);
 
 void xt_rateest_put(struct xt_rateest *est)
@@ -105,8 +113,10 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
                rnd_inited = true;
        }
 
-       est = xt_rateest_lookup(info->name);
+       mutex_lock(&xt_rateest_mutex);
+       est = __xt_rateest_lookup(info->name);
        if (est) {
+               mutex_unlock(&xt_rateest_mutex);
                /*
                 * If estimator parameters are specified, they must match the
                 * existing estimator.
@@ -144,11 +154,13 @@ static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
 
        info->est = est;
        xt_rateest_hash_insert(est);
+       mutex_unlock(&xt_rateest_mutex);
        return 0;
 
 err2:
        kfree(est);
 err1:
+       mutex_unlock(&xt_rateest_mutex);
        return ret;
 }
 
index 9e63b43..0774164 100644 (file)
@@ -44,25 +44,34 @@ optlen(const u_int8_t *opt, unsigned int offset)
 
 static int
 tcpmss_mangle_packet(struct sk_buff *skb,
-                    const struct xt_tcpmss_info *info,
+                    const struct xt_action_param *par,
                     unsigned int in_mtu,
                     unsigned int tcphoff,
                     unsigned int minlen)
 {
+       const struct xt_tcpmss_info *info = par->targinfo;
        struct tcphdr *tcph;
-       unsigned int tcplen, i;
+       int len, tcp_hdrlen;
+       unsigned int i;
        __be16 oldval;
        u16 newmss;
        u8 *opt;
 
+       /* This is a fragment, no TCP header is available */
+       if (par->fragoff != 0)
+               return 0;
+
        if (!skb_make_writable(skb, skb->len))
                return -1;
 
-       tcplen = skb->len - tcphoff;
+       len = skb->len - tcphoff;
+       if (len < (int)sizeof(struct tcphdr))
+               return -1;
+
        tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
+       tcp_hdrlen = tcph->doff * 4;
 
-       /* Header cannot be larger than the packet */
-       if (tcplen < tcph->doff*4)
+       if (len < tcp_hdrlen || tcp_hdrlen < sizeof(struct tcphdr))
                return -1;
 
        if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
@@ -83,9 +92,8 @@ tcpmss_mangle_packet(struct sk_buff *skb,
                newmss = info->mss;
 
        opt = (u_int8_t *)tcph;
-       for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
-               if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
-                   opt[i+1] == TCPOLEN_MSS) {
+       for (i = sizeof(struct tcphdr); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen(opt, i)) {
+               if (opt[i] == TCPOPT_MSS && opt[i+1] == TCPOLEN_MSS) {
                        u_int16_t oldmss;
 
                        oldmss = (opt[i+2] << 8) | opt[i+3];
@@ -108,9 +116,14 @@ tcpmss_mangle_packet(struct sk_buff *skb,
        }
 
        /* There is data after the header so the option can't be added
-          without moving it, and doing so may make the SYN packet
-          itself too large. Accept the packet unmodified instead. */
-       if (tcplen > tcph->doff*4)
+        * without moving it, and doing so may make the SYN packet
+        * itself too large. Accept the packet unmodified instead.
+        */
+       if (len > tcp_hdrlen)
+               return 0;
+
+       /* tcph->doff has 4 bits, do not wrap it to 0 */
+       if (tcp_hdrlen >= 15 * 4)
                return 0;
 
        /*
@@ -127,10 +140,10 @@ tcpmss_mangle_packet(struct sk_buff *skb,
        skb_put(skb, TCPOLEN_MSS);
 
        opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
-       memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
+       memmove(opt + TCPOLEN_MSS, opt, len - sizeof(struct tcphdr));
 
        inet_proto_csum_replace2(&tcph->check, skb,
-                                htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
+                                htons(len), htons(len + TCPOLEN_MSS), 1);
        opt[0] = TCPOPT_MSS;
        opt[1] = TCPOLEN_MSS;
        opt[2] = (newmss & 0xff00) >> 8;
@@ -183,7 +196,7 @@ tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
        __be16 newlen;
        int ret;
 
-       ret = tcpmss_mangle_packet(skb, par->targinfo,
+       ret = tcpmss_mangle_packet(skb, par,
                                   tcpmss_reverse_mtu(skb, PF_INET),
                                   iph->ihl * 4,
                                   sizeof(*iph) + sizeof(struct tcphdr));
@@ -211,7 +224,7 @@ tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
        tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr);
        if (tcphoff < 0)
                return NF_DROP;
-       ret = tcpmss_mangle_packet(skb, par->targinfo,
+       ret = tcpmss_mangle_packet(skb, par,
                                   tcpmss_reverse_mtu(skb, PF_INET6),
                                   tcphoff,
                                   sizeof(*ipv6h) + sizeof(struct tcphdr));
index 9dc9ecf..817ffa7 100644 (file)
@@ -30,18 +30,31 @@ static inline unsigned int optlen(const u_int8_t *opt, unsigned int offset)
 
 static unsigned int
 tcpoptstrip_mangle_packet(struct sk_buff *skb,
-                         const struct xt_tcpoptstrip_target_info *info,
+                         const struct xt_action_param *par,
                          unsigned int tcphoff, unsigned int minlen)
 {
+       const struct xt_tcpoptstrip_target_info *info = par->targinfo;
        unsigned int optl, i, j;
        struct tcphdr *tcph;
        u_int16_t n, o;
        u_int8_t *opt;
+       int len;
+
+       /* This is a fragment, no TCP header is available */
+       if (par->fragoff != 0)
+               return XT_CONTINUE;
 
        if (!skb_make_writable(skb, skb->len))
                return NF_DROP;
 
+       len = skb->len - tcphoff;
+       if (len < (int)sizeof(struct tcphdr))
+               return NF_DROP;
+
        tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
+       if (tcph->doff * 4 > len)
+               return NF_DROP;
+
        opt  = (u_int8_t *)tcph;
 
        /*
@@ -76,7 +89,7 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
 static unsigned int
 tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_action_param *par)
 {
-       return tcpoptstrip_mangle_packet(skb, par->targinfo, ip_hdrlen(skb),
+       return tcpoptstrip_mangle_packet(skb, par, ip_hdrlen(skb),
               sizeof(struct iphdr) + sizeof(struct tcphdr));
 }
 
@@ -93,7 +106,7 @@ tcpoptstrip_tg6(struct sk_buff *skb, const struct xt_action_param *par)
        if (tcphoff < 0)
                return NF_DROP;
 
-       return tcpoptstrip_mangle_packet(skb, par->targinfo, tcphoff,
+       return tcpoptstrip_mangle_packet(skb, par, tcphoff,
               sizeof(*ipv6h) + sizeof(struct tcphdr));
 }
 #endif
index c4706be..1baf173 100644 (file)
@@ -108,9 +108,9 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
        const struct iphdr *iph = ip_hdr(skb);
        struct udphdr _hdr, *hp = NULL;
        struct sock *sk;
-       __be32 daddr, saddr;
-       __be16 dport, sport;
-       u8 protocol;
+       __be32 uninitialized_var(daddr), uninitialized_var(saddr);
+       __be16 uninitialized_var(dport), uninitialized_var(sport);
+       u8 uninitialized_var(protocol);
 #ifdef XT_SOCKET_HAVE_CONNTRACK
        struct nf_conn const *ct;
        enum ip_conntrack_info ctinfo;
@@ -263,9 +263,9 @@ socket_mt6_v1(const struct sk_buff *skb, struct xt_action_param *par)
        struct ipv6hdr ipv6_var, *iph = ipv6_hdr(skb);
        struct udphdr _hdr, *hp = NULL;
        struct sock *sk;
-       const struct in6_addr *daddr, *saddr;
-       __be16 dport, sport;
-       int thoff, tproto;
+       const struct in6_addr *daddr = NULL, *saddr = NULL;
+       __be16 uninitialized_var(dport), uninitialized_var(sport);
+       int thoff, uninitialized_var(tproto);
        const struct xt_socket_mtinfo1 *info = (struct xt_socket_mtinfo1 *) par->matchinfo;
 
        tproto = ipv6_find_hdr(skb, &thoff, -1, NULL);
index 2369e96..d1017ad 100644 (file)
@@ -706,6 +706,9 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
        if (addr->sa_family != AF_NETLINK)
                return -EINVAL;
 
+       if (alen < sizeof(struct sockaddr_nl))
+               return -EINVAL;
+
        /* Only superuser is allowed to send multicasts */
        if (nladdr->nl_groups && !netlink_capable(sock, NL_NONROOT_SEND))
                return -EPERM;
index 874f8ff..c41301a 100644 (file)
@@ -917,6 +917,7 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group,
 {
        struct sk_buff *tmp;
        struct net *net, *prev = NULL;
+       bool delivered = false;
        int err;
 
        for_each_net_rcu(net) {
@@ -928,14 +929,21 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group,
                        }
                        err = nlmsg_multicast(prev->genl_sock, tmp,
                                              pid, group, flags);
-                       if (err)
+                       if (!err)
+                               delivered = true;
+                       else if (err != -ESRCH)
                                goto error;
                }
 
                prev = net;
        }
 
-       return nlmsg_multicast(prev->genl_sock, skb, pid, group, flags);
+       err = nlmsg_multicast(prev->genl_sock, skb, pid, group, flags);
+       if (!err)
+               delivered = true;
+       else if (err != -ESRCH)
+               return err;
+       return delivered ? 0 : -ESRCH;
  error:
        kfree_skb(skb);
        return err;
index 57b5add..34cc788 100644 (file)
@@ -1294,10 +1294,6 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
 
        mutex_lock(&fanout_mutex);
 
-       err = -EINVAL;
-       if (!po->running)
-               goto out;
-
        err = -EALREADY;
        if (po->fanout)
                goto out;
@@ -1334,7 +1330,10 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
                list_add(&match->list, &fanout_list);
        }
        err = -EINVAL;
-       if (match->type == type &&
+
+       spin_lock(&po->bind_lock);
+       if (po->running &&
+           match->type == type &&
            match->prot_hook.type == po->prot_hook.type &&
            match->prot_hook.dev == po->prot_hook.dev) {
                err = -ENOSPC;
@@ -1346,6 +1345,13 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
                        err = 0;
                }
        }
+       spin_unlock(&po->bind_lock);
+
+       if (err && !atomic_read(&match->sk_ref)) {
+               list_del(&match->list);
+               kfree(match);
+       }
+
 out:
        mutex_unlock(&fanout_mutex);
        return err;
@@ -2225,6 +2231,7 @@ static int packet_snd(struct socket *sock,
        int offset = 0;
        int vnet_hdr_len;
        struct packet_sock *po = pkt_sk(sk);
+       bool has_vnet_hdr = false;
        unsigned short gso_type = 0;
 
        /*
@@ -2257,6 +2264,7 @@ static int packet_snd(struct socket *sock,
                reserve = dev->hard_header_len;
        if (po->has_vnet_hdr) {
                vnet_hdr_len = sizeof(vnet_hdr);
+               has_vnet_hdr = true;
 
                err = -EINVAL;
                if (len < vnet_hdr_len)
@@ -2348,7 +2356,7 @@ static int packet_snd(struct socket *sock,
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
 
-       if (po->has_vnet_hdr) {
+       if (has_vnet_hdr) {
                if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
                        if (!skb_partial_csum_set(skb, vnet_hdr.csum_start,
                                                  vnet_hdr.csum_offset)) {
@@ -2468,33 +2476,77 @@ static int packet_release(struct socket *sock)
  *     Attach a packet hook.
  */
 
-static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protocol)
+static int packet_do_bind(struct sock *sk, const char *name, int ifindex,
+                         __be16 protocol)
 {
        struct packet_sock *po = pkt_sk(sk);
+       struct net_device *dev_curr;
+       struct net_device *dev = NULL;
+       int ret = 0;
+       bool unlisted = false;
+
+       lock_sock(sk);
+
+       spin_lock(&po->bind_lock);
+       rcu_read_lock();
 
        if (po->fanout) {
-               if (dev)
-                       dev_put(dev);
+               ret = -EINVAL;
+               goto out_unlock;
+       }
 
-               return -EINVAL;
+       if (name) {
+               dev = dev_get_by_name_rcu(sock_net(sk), name);
+               if (!dev) {
+                       ret = -ENODEV;
+                       goto out_unlock;
+               }
+       } else if (ifindex) {
+               dev = dev_get_by_index_rcu(sock_net(sk), ifindex);
+               if (!dev) {
+                       ret = -ENODEV;
+                       goto out_unlock;
+               }
        }
 
-       lock_sock(sk);
+       if (dev)
+               dev_hold(dev);
 
-       spin_lock(&po->bind_lock);
-       unregister_prot_hook(sk, true);
+       dev_curr = po->prot_hook.dev;
+
+       if (po->running) {
+               rcu_read_unlock();
+               /* prevents packet_notifier() from calling
+                * register_prot_hook()
+                */
+               po->num = 0;
+               __unregister_prot_hook(sk, true);
+               rcu_read_lock();
+               dev_curr = po->prot_hook.dev;
+               if (dev)
+                       unlisted = !dev_get_by_index_rcu(sock_net(sk),
+                                                        dev->ifindex);
+       }
+       BUG_ON(po->running);
        po->num = protocol;
        po->prot_hook.type = protocol;
-       if (po->prot_hook.dev)
-               dev_put(po->prot_hook.dev);
-       po->prot_hook.dev = dev;
 
-       po->ifindex = dev ? dev->ifindex : 0;
+       if (unlikely(unlisted)) {
+               dev_put(dev);
+               po->prot_hook.dev = NULL;
+               po->ifindex = -1;
+       } else {
+               po->prot_hook.dev = dev;
+               po->ifindex = dev ? dev->ifindex : 0;
+       }
+
+       if (dev_curr)
+               dev_put(dev_curr);
 
        if (protocol == 0)
                goto out_unlock;
 
-       if (!dev || (dev->flags & IFF_UP)) {
+       if (!unlisted && (!dev || (dev->flags & IFF_UP))) {
                register_prot_hook(sk);
        } else {
                sk->sk_err = ENETDOWN;
@@ -2503,9 +2555,10 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protoc
        }
 
 out_unlock:
+       rcu_read_unlock();
        spin_unlock(&po->bind_lock);
        release_sock(sk);
-       return 0;
+       return ret;
 }
 
 /*
@@ -2517,8 +2570,6 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
 {
        struct sock *sk = sock->sk;
        char name[15];
-       struct net_device *dev;
-       int err = -ENODEV;
 
        /*
         *      Check legality
@@ -2528,19 +2579,13 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
                return -EINVAL;
        strlcpy(name, uaddr->sa_data, sizeof(name));
 
-       dev = dev_get_by_name(sock_net(sk), name);
-       if (dev)
-               err = packet_do_bind(sk, dev, pkt_sk(sk)->num);
-       return err;
+       return packet_do_bind(sk, name, 0, pkt_sk(sk)->num);
 }
 
 static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
        struct sockaddr_ll *sll = (struct sockaddr_ll *)uaddr;
        struct sock *sk = sock->sk;
-       struct net_device *dev = NULL;
-       int err;
-
 
        /*
         *      Check legality
@@ -2551,16 +2596,8 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len
        if (sll->sll_family != AF_PACKET)
                return -EINVAL;
 
-       if (sll->sll_ifindex) {
-               err = -ENODEV;
-               dev = dev_get_by_index(sock_net(sk), sll->sll_ifindex);
-               if (dev == NULL)
-                       goto out;
-       }
-       err = packet_do_bind(sk, dev, sll->sll_protocol ? : pkt_sk(sk)->num);
-
-out:
-       return err;
+       return packet_do_bind(sk, NULL, sll->sll_ifindex,
+                             sll->sll_protocol ? : pkt_sk(sk)->num);
 }
 
 static struct proto packet_proto = {
index 4e37c1c..11335aa 100644 (file)
@@ -184,7 +184,7 @@ static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
        long i;
        int ret;
 
-       if (rs->rs_bound_addr == 0) {
+       if (rs->rs_bound_addr == 0 || !rs->rs_transport) {
                ret = -ENOTCONN; /* XXX not a great errno */
                goto out;
        }
@@ -516,6 +516,9 @@ int rds_rdma_extra_size(struct rds_rdma_args *args)
 
        local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr;
 
+       if (args->nr_local == 0)
+               return -EINVAL;
+
        /* figure out the number of pages in the vector */
        for (i = 0; i < args->nr_local; i++) {
                if (copy_from_user(&vec, &local_vec[i],
@@ -852,6 +855,7 @@ int rds_cmsg_atomic(struct rds_sock *rs, struct rds_message *rm,
 err:
        if (page)
                put_page(page);
+       rm->atomic.op_active = 0;
        kfree(rm->atomic.op_notifier);
 
        return ret;
index fecb510..d24106c 100644 (file)
@@ -310,7 +310,8 @@ replay:
                case RTM_DELTFILTER:
                        err = tp->ops->delete(tp, fh);
                        if (err == 0)
-                               tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
+                               tfilter_notify(net, skb, n, tp,
+                                              t->tcm_handle, RTM_DELTFILTER);
                        goto errout;
                case RTM_GETTFILTER:
                        err = tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
index dca6c1a..2751bd8 100644 (file)
@@ -866,6 +866,8 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
 
                return sch;
        }
+       /* ops->init() failed, we call ->destroy() like qdisc_create_dflt() */
+       ops->destroy(sch);
 err_out3:
        dev_put(dev);
        kfree((char *) sch - sch->padded);
index 7f59944..407ffa7 100644 (file)
@@ -1367,6 +1367,13 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt)
        struct tc_ratespec *r;
        int err;
 
+       qdisc_watchdog_init(&q->watchdog, sch);
+       hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+       q->delay_timer.function = cbq_undelay;
+
+       if (!opt)
+               return -EINVAL;
+
        err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy);
        if (err < 0)
                return err;
@@ -1405,9 +1412,6 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt)
        q->link.avpkt = q->link.allot/2;
        q->link.minidle = -0x7FFFFFFF;
 
-       qdisc_watchdog_init(&q->watchdog, sch);
-       hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
-       q->delay_timer.function = cbq_undelay;
        q->toplevel = TC_CBQ_MAXLEVEL;
        q->now = psched_get_time();
        q->now_rt = q->now;
index 081ffb9..f3b1ed0 100644 (file)
@@ -479,6 +479,9 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
 
        ctl = nla_data(tb[TCA_CHOKE_PARMS]);
 
+       if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+               return -EINVAL;
+
        if (ctl->limit > CHOKE_MAX_QUEUE)
                return -EINVAL;
 
index 6b7fe4a..7ce8acc 100644 (file)
@@ -351,7 +351,7 @@ static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct drr_sched *q = qdisc_priv(sch);
        struct drr_class *cl;
-       int err;
+       int err = 0;
 
        cl = drr_classify(skb, sch, &err);
        if (cl == NULL) {
index e1afe0c..c65c831 100644 (file)
@@ -384,6 +384,9 @@ static inline int gred_change_vq(struct Qdisc *sch, int dp,
        struct gred_sched *table = qdisc_priv(sch);
        struct gred_sched_data *q;
 
+       if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+               return -EINVAL;
+
        if (table->tab[dp] == NULL) {
                table->tab[dp] = kzalloc(sizeof(*q), GFP_ATOMIC);
                if (table->tab[dp] == NULL)
index 6488e64..a239d0a 100644 (file)
@@ -1435,6 +1435,8 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
        struct tc_hfsc_qopt *qopt;
        int err;
 
+       qdisc_watchdog_init(&q->watchdog, sch);
+
        if (opt == NULL || nla_len(opt) < sizeof(*qopt))
                return -EINVAL;
        qopt = nla_data(opt);
@@ -1460,8 +1462,6 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
        qdisc_class_hash_insert(&q->clhash, &q->root.cl_common);
        qdisc_class_hash_grow(sch, &q->clhash);
 
-       qdisc_watchdog_init(&q->watchdog, sch);
-
        return 0;
 }
 
index 92f0c1f..3f93a5c 100644 (file)
@@ -997,6 +997,9 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt)
        int err;
        int i;
 
+       qdisc_watchdog_init(&q->watchdog, sch);
+       INIT_WORK(&q->work, htb_work_func);
+
        if (!opt)
                return -EINVAL;
 
@@ -1021,8 +1024,6 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt)
        for (i = 0; i < TC_HTB_NUMPRIO; i++)
                INIT_LIST_HEAD(q->drops + i);
 
-       qdisc_watchdog_init(&q->watchdog, sch);
-       INIT_WORK(&q->work, htb_work_func);
        skb_queue_head_init(&q->direct_queue);
 
        q->direct_qlen = qdisc_dev(sch)->tx_queue_len;
index 0a4b2f9..7cf451f 100644 (file)
@@ -52,7 +52,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt)
        /* pre-allocate qdiscs, attachment can't fail */
        priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]),
                               GFP_KERNEL);
-       if (priv->qdiscs == NULL)
+       if (!priv->qdiscs)
                return -ENOMEM;
 
        for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
@@ -60,17 +60,13 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt)
                qdisc = qdisc_create_dflt(dev_queue, &pfifo_fast_ops,
                                          TC_H_MAKE(TC_H_MAJ(sch->handle),
                                                    TC_H_MIN(ntx + 1)));
-               if (qdisc == NULL)
-                       goto err;
+               if (!qdisc)
+                       return -ENOMEM;
                priv->qdiscs[ntx] = qdisc;
        }
 
        sch->flags |= TCQ_F_MQROOT;
        return 0;
-
-err:
-       mq_destroy(sch);
-       return -ENOMEM;
 }
 
 static void mq_attach(struct Qdisc *sch)
index 28de430..b4a388b 100644 (file)
@@ -117,20 +117,17 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
        /* pre-allocate qdisc, attachment can't fail */
        priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]),
                               GFP_KERNEL);
-       if (priv->qdiscs == NULL) {
-               err = -ENOMEM;
-               goto err;
-       }
+       if (!priv->qdiscs)
+               return -ENOMEM;
 
        for (i = 0; i < dev->num_tx_queues; i++) {
                dev_queue = netdev_get_tx_queue(dev, i);
                qdisc = qdisc_create_dflt(dev_queue, &pfifo_fast_ops,
                                          TC_H_MAKE(TC_H_MAJ(sch->handle),
                                                    TC_H_MIN(i + 1)));
-               if (qdisc == NULL) {
-                       err = -ENOMEM;
-                       goto err;
-               }
+               if (!qdisc)
+                       return -ENOMEM;
+
                priv->qdiscs[i] = qdisc;
        }
 
@@ -142,7 +139,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
                priv->hw_owned = 1;
                err = dev->netdev_ops->ndo_setup_tc(dev, qopt->num_tc);
                if (err)
-                       goto err;
+                       return err;
        } else {
                netdev_set_num_tc(dev, qopt->num_tc);
                for (i = 0; i < qopt->num_tc; i++)
@@ -156,10 +153,6 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
 
        sch->flags |= TCQ_F_MQROOT;
        return 0;
-
-err:
-       mqprio_destroy(sch);
-       return err;
 }
 
 static void mqprio_attach(struct Qdisc *sch)
index edc1950..a8f8dc1 100644 (file)
@@ -250,7 +250,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt)
 static int multiq_init(struct Qdisc *sch, struct nlattr *opt)
 {
        struct multiq_sched_data *q = qdisc_priv(sch);
-       int i, err;
+       int i;
 
        q->queues = NULL;
 
@@ -265,12 +265,7 @@ static int multiq_init(struct Qdisc *sch, struct nlattr *opt)
        for (i = 0; i < q->max_bands; i++)
                q->queues[i] = &noop_qdisc;
 
-       err = multiq_tune(sch, opt);
-
-       if (err)
-               kfree(q->queues);
-
-       return err;
+       return multiq_tune(sch, opt);
 }
 
 static int multiq_dump(struct Qdisc *sch, struct sk_buff *skb)
index a489d8b..5856ce5 100644 (file)
@@ -758,11 +758,11 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt)
        struct netem_sched_data *q = qdisc_priv(sch);
        int ret;
 
+       qdisc_watchdog_init(&q->watchdog, sch);
+
        if (!opt)
                return -EINVAL;
 
-       qdisc_watchdog_init(&q->watchdog, sch);
-
        q->loss_model = CLG_RANDOM;
        q->qdisc = qdisc_create_dflt(sch->dev_queue, &tfifo_qdisc_ops,
                                     TC_H_MAKE(sch->handle, 1));
index ca0fb48..4ade918 100644 (file)
@@ -846,7 +846,7 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        struct qfq_sched *q = qdisc_priv(sch);
        struct qfq_group *grp;
        struct qfq_class *cl;
-       int err;
+       int err = 0;
        u64 roundedS;
        int s;
 
index d617161..bbf2dfd 100644 (file)
@@ -189,6 +189,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt)
                return -EINVAL;
 
        ctl = nla_data(tb[TCA_RED_PARMS]);
+       if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog))
+               return -EINVAL;
 
        if (ctl->limit > 0) {
                child = fifo_create_dflt(sch, &bfifo_qdisc_ops, ctl->limit);
index 1dcfb52..e24dfbe 100644 (file)
@@ -316,12 +316,13 @@ static int tbf_init(struct Qdisc *sch, struct nlattr *opt)
 {
        struct tbf_sched_data *q = qdisc_priv(sch);
 
+       qdisc_watchdog_init(&q->watchdog, sch);
+       q->qdisc = &noop_qdisc;
+
        if (opt == NULL)
                return -EINVAL;
 
        q->t_c = psched_get_time();
-       qdisc_watchdog_init(&q->watchdog, sch);
-       q->qdisc = &noop_qdisc;
 
        return tbf_change(sch, opt);
 }
index 762b61d..b41393e 100644 (file)
@@ -430,7 +430,7 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
 /* Initialize sk->sk_rcv_saddr from sctp_addr. */
 static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
 {
-       if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
+       if (addr->sa.sa_family == AF_INET) {
                inet6_sk(sk)->rcv_saddr.s6_addr32[0] = 0;
                inet6_sk(sk)->rcv_saddr.s6_addr32[1] = 0;
                inet6_sk(sk)->rcv_saddr.s6_addr32[2] = htonl(0x0000ffff);
@@ -444,7 +444,7 @@ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
 /* Initialize sk->sk_daddr from sctp_addr. */
 static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
 {
-       if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
+       if (addr->sa.sa_family == AF_INET) {
                inet6_sk(sk)->daddr.s6_addr32[0] = 0;
                inet6_sk(sk)->daddr.s6_addr32[1] = 0;
                inet6_sk(sk)->daddr.s6_addr32[2] = htonl(0x0000ffff);
@@ -487,7 +487,9 @@ static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
 {
        addr->sa.sa_family = AF_INET6;
        addr->v6.sin6_port = port;
+       addr->v6.sin6_flowinfo = 0;
        ipv6_addr_copy(&addr->v6.sin6_addr, saddr);
+       addr->v6.sin6_scope_id = 0;
 }
 
 /* Compare addresses exactly.
@@ -554,8 +556,6 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
        if (IPV6_ADDR_ANY == type)
                return 1;
        if (type == IPV6_ADDR_MAPPED) {
-               if (sp && !sp->v4mapped)
-                       return 0;
                if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
                        return 0;
                sctp_v6_map_v4(addr);
@@ -585,8 +585,6 @@ static int sctp_v6_addr_valid(union sctp_addr *addr,
                /* Note: This routine is used in input, so v4-mapped-v6
                 * are disallowed here when there is no sctp_sock.
                 */
-               if (!sp || !sp->v4mapped)
-                       return 0;
                if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
                        return 0;
                sctp_v6_map_v4(addr);
@@ -682,11 +680,23 @@ out:
        return newsk;
 }
 
-/* Map v4 address to mapped v6 address */
-static void sctp_v6_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr)
+/* Format a sockaddr for return to user space. This makes sure the return is
+ * AF_INET or AF_INET6 depending on the SCTP_I_WANT_MAPPED_V4_ADDR option.
+ */
+static int sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr)
 {
-       if (sp->v4mapped && AF_INET == addr->sa.sa_family)
-               sctp_v4_map_v6(addr);
+       if (sp->v4mapped) {
+               if (addr->sa.sa_family == AF_INET)
+                       sctp_v4_map_v6(addr);
+       } else {
+               if (addr->sa.sa_family == AF_INET6 &&
+                   ipv6_addr_v4mapped(&addr->v6.sin6_addr))
+                       sctp_v6_map_v4(addr);
+       }
+
+       if (addr->sa.sa_family == AF_INET)
+               return sizeof(struct sockaddr_in);
+       return sizeof(struct sockaddr_in6);
 }
 
 /* Where did this skb come from?  */
@@ -713,82 +723,70 @@ static void sctp_v6_ecn_capable(struct sock *sk)
        inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
 }
 
-/* Initialize a PF_INET6 socket msg_name. */
-static void sctp_inet6_msgname(char *msgname, int *addr_len)
-{
-       struct sockaddr_in6 *sin6;
-
-       sin6 = (struct sockaddr_in6 *)msgname;
-       sin6->sin6_family = AF_INET6;
-       sin6->sin6_flowinfo = 0;
-       sin6->sin6_scope_id = 0; /*FIXME */
-       *addr_len = sizeof(struct sockaddr_in6);
-}
-
 /* Initialize a PF_INET msgname from a ulpevent. */
 static void sctp_inet6_event_msgname(struct sctp_ulpevent *event,
                                     char *msgname, int *addrlen)
 {
-       struct sockaddr_in6 *sin6, *sin6from;
-
-       if (msgname) {
-               union sctp_addr *addr;
-               struct sctp_association *asoc;
-
-               asoc = event->asoc;
-               sctp_inet6_msgname(msgname, addrlen);
-               sin6 = (struct sockaddr_in6 *)msgname;
-               sin6->sin6_port = htons(asoc->peer.port);
-               addr = &asoc->peer.primary_addr;
+       union sctp_addr *addr;
+       struct sctp_association *asoc;
+       union sctp_addr *paddr;
 
-               /* Note: If we go to a common v6 format, this code
-                * will change.
-                */
+       if (!msgname)
+               return;
 
-               /* Map ipv4 address into v4-mapped-on-v6 address.  */
-               if (sctp_sk(asoc->base.sk)->v4mapped &&
-                   AF_INET == addr->sa.sa_family) {
-                       sctp_v4_map_v6((union sctp_addr *)sin6);
-                       sin6->sin6_addr.s6_addr32[3] =
-                               addr->v4.sin_addr.s_addr;
-                       return;
-               }
+       addr = (union sctp_addr *)msgname;
+       asoc = event->asoc;
+       paddr = &asoc->peer.primary_addr;
 
-               sin6from = &asoc->peer.primary_addr.v6;
-               ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr);
-               if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
-                       sin6->sin6_scope_id = sin6from->sin6_scope_id;
+       if (paddr->sa.sa_family == AF_INET) {
+               addr->v4.sin_family = AF_INET;
+               addr->v4.sin_port = htons(asoc->peer.port);
+               addr->v4.sin_addr = paddr->v4.sin_addr;
+       } else {
+               addr->v6.sin6_family = AF_INET6;
+               addr->v6.sin6_flowinfo = 0;
+               if (ipv6_addr_type(&paddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
+                       addr->v6.sin6_scope_id = paddr->v6.sin6_scope_id;
+               else
+                       addr->v6.sin6_scope_id = 0;
+               addr->v6.sin6_port = htons(asoc->peer.port);
+               addr->v6.sin6_addr = paddr->v6.sin6_addr;
        }
+
+       *addrlen = sctp_v6_addr_to_user(sctp_sk(asoc->base.sk), addr);
 }
 
 /* Initialize a msg_name from an inbound skb. */
 static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
                                   int *addr_len)
 {
+       union sctp_addr *addr;
        struct sctphdr *sh;
-       struct sockaddr_in6 *sin6;
-
-       if (msgname) {
-               sctp_inet6_msgname(msgname, addr_len);
-               sin6 = (struct sockaddr_in6 *)msgname;
-               sh = sctp_hdr(skb);
-               sin6->sin6_port = sh->source;
-
-               /* Map ipv4 address into v4-mapped-on-v6 address. */
-               if (sctp_sk(skb->sk)->v4mapped &&
-                   ip_hdr(skb)->version == 4) {
-                       sctp_v4_map_v6((union sctp_addr *)sin6);
-                       sin6->sin6_addr.s6_addr32[3] = ip_hdr(skb)->saddr;
-                       return;
-               }
 
-               /* Otherwise, just copy the v6 address. */
-               ipv6_addr_copy(&sin6->sin6_addr, &ipv6_hdr(skb)->saddr);
-               if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
+       if (!msgname)
+               return;
+
+       addr = (union sctp_addr *)msgname;
+       sh = sctp_hdr(skb);
+
+       if (ip_hdr(skb)->version == 4) {
+               addr->v4.sin_family = AF_INET;
+               addr->v4.sin_port = sh->source;
+               addr->v4.sin_addr.s_addr =  ip_hdr(skb)->saddr;
+       } else {
+               addr->v6.sin6_family = AF_INET6;
+               addr->v6.sin6_flowinfo = 0;
+               addr->v6.sin6_port = sh->source;
+               addr->v6.sin6_addr = ipv6_hdr(skb)->saddr;
+               if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) {
                        struct sctp_ulpevent *ev = sctp_skb2event(skb);
-                       sin6->sin6_scope_id = ev->iif;
+                       addr->v6.sin6_scope_id = ev->iif;
+               } else {
+                       addr->v6.sin6_scope_id = 0;
                }
        }
+
+       *addr_len = sctp_v6_addr_to_user(sctp_sk(skb->sk), addr);
 }
 
 /* Do we support this AF? */
@@ -864,9 +862,6 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr)
                                return 0;
                        }
                        rcu_read_unlock();
-               } else if (type == IPV6_ADDR_MAPPED) {
-                       if (!opt->v4mapped)
-                               return 0;
                }
 
                af = opt->pf->af;
@@ -921,6 +916,23 @@ static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
        return 1;
 }
 
+/* Handle SCTP_I_WANT_MAPPED_V4_ADDR for getpeername() and getsockname() */
+static int sctp_getname(struct socket *sock, struct sockaddr *uaddr,
+                       int *uaddr_len, int peer)
+{
+       int rc;
+
+       rc = inet6_getname(sock, uaddr, uaddr_len, peer);
+
+       if (rc != 0)
+               return rc;
+
+       *uaddr_len = sctp_v6_addr_to_user(sctp_sk(sock->sk),
+                                         (union sctp_addr *)uaddr);
+
+       return rc;
+}
+
 static const struct proto_ops inet6_seqpacket_ops = {
        .family            = PF_INET6,
        .owner             = THIS_MODULE,
@@ -929,7 +941,7 @@ static const struct proto_ops inet6_seqpacket_ops = {
        .connect           = inet_dgram_connect,
        .socketpair        = sock_no_socketpair,
        .accept            = inet_accept,
-       .getname           = inet6_getname,
+       .getname           = sctp_getname,
        .poll              = sctp_poll,
        .ioctl             = inet6_ioctl,
        .listen            = sctp_inet_listen,
@@ -983,8 +995,6 @@ static struct sctp_af sctp_af_inet6 = {
        .copy_addrlist     = sctp_v6_copy_addrlist,
        .from_skb          = sctp_v6_from_skb,
        .from_sk           = sctp_v6_from_sk,
-       .to_sk_saddr       = sctp_v6_to_sk_saddr,
-       .to_sk_daddr       = sctp_v6_to_sk_daddr,
        .from_addr_param   = sctp_v6_from_addr_param,
        .to_addr_param     = sctp_v6_to_addr_param,
        .cmp_addr          = sctp_v6_cmp_addr,
@@ -1014,7 +1024,9 @@ static struct sctp_pf sctp_pf_inet6 = {
        .send_verify   = sctp_inet6_send_verify,
        .supported_addrs = sctp_inet6_supported_addrs,
        .create_accept_sk = sctp_v6_create_accept_sk,
-       .addr_v4map    = sctp_v6_addr_v4map,
+       .addr_to_user  = sctp_v6_addr_to_user,
+       .to_sk_saddr   = sctp_v6_to_sk_saddr,
+       .to_sk_daddr   = sctp_v6_to_sk_daddr,
        .af            = &sctp_af_inet6,
 };
 
index 149deae..c16eac2 100644 (file)
@@ -615,10 +615,10 @@ out:
        return newsk;
 }
 
-/* Map address, empty for v4 family */
-static void sctp_v4_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr)
+static int sctp_v4_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr)
 {
-       /* Empty */
+       /* No address mapping for V4 sockets */
+       return sizeof(struct sockaddr_in);
 }
 
 /* Dump the v4 addr to the seq file. */
@@ -1010,7 +1010,9 @@ static struct sctp_pf sctp_pf_inet = {
        .send_verify   = sctp_inet_send_verify,
        .supported_addrs = sctp_inet_supported_addrs,
        .create_accept_sk = sctp_v4_create_accept_sk,
-       .addr_v4map     = sctp_v4_addr_v4map,
+       .addr_to_user  = sctp_v4_addr_to_user,
+       .to_sk_saddr   = sctp_v4_to_sk_saddr,
+       .to_sk_daddr   = sctp_v4_to_sk_daddr,
        .af            = &sctp_af_inet
 };
 
@@ -1081,8 +1083,6 @@ static struct sctp_af sctp_af_inet = {
        .copy_addrlist     = sctp_v4_copy_addrlist,
        .from_skb          = sctp_v4_from_skb,
        .from_sk           = sctp_v4_from_sk,
-       .to_sk_saddr       = sctp_v4_to_sk_saddr,
-       .to_sk_daddr       = sctp_v4_to_sk_daddr,
        .from_addr_param   = sctp_v4_from_addr_param,
        .to_addr_param     = sctp_v4_to_addr_param,
        .cmp_addr          = sctp_v4_cmp_addr,
index 743a644..89d03af 100644 (file)
@@ -1324,10 +1324,14 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
        sctp_chunkhdr_t *chunk_hdr;
        struct sk_buff *skb;
        struct sock *sk;
+       int chunklen;
+
+       chunklen = WORD_ROUND(sizeof(*chunk_hdr) + paylen);
+       if (chunklen > SCTP_MAX_CHUNK_LEN)
+               goto nodata;
 
        /* No need to allocate LL here, as this is only a chunk. */
-       skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen),
-                       GFP_ATOMIC);
+       skb = alloc_skb(chunklen, GFP_ATOMIC);
        if (!skb)
                goto nodata;
 
index 6dca588..dd01a50 100644 (file)
@@ -1598,8 +1598,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                case SCTP_CMD_PROCESS_CTSN:
                        /* Dummy up a SACK for processing. */
                        sackh.cum_tsn_ack = cmd->obj.be32;
-                       sackh.a_rwnd = asoc->peer.rwnd +
-                                       asoc->outqueue.outstanding_bytes;
+                       sackh.a_rwnd = htonl(asoc->peer.rwnd +
+                                            asoc->outqueue.outstanding_bytes);
                        sackh.num_gap_ack_blocks = 0;
                        sackh.num_dup_tsns = 0;
                        sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK,
index 93ea5ac..a572b43 100644 (file)
@@ -71,6 +71,7 @@
 #include <linux/crypto.h>
 #include <linux/slab.h>
 #include <linux/compat.h>
+#include <linux/nsproxy.h>
 
 #include <net/ip.h>
 #include <net/icmp.h>
@@ -92,7 +93,7 @@
 /* Forward declarations for internal helper functions. */
 static int sctp_writeable(struct sock *sk);
 static void sctp_wfree(struct sk_buff *skb);
-static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,
+static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
                                size_t msg_len);
 static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p);
 static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
@@ -264,7 +265,7 @@ static struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
        if (id_asoc && (id_asoc != addr_asoc))
                return NULL;
 
-       sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
+       sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk),
                                                (union sctp_addr *)addr);
 
        return transport;
@@ -313,16 +314,14 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt,
        if (len < sizeof (struct sockaddr))
                return NULL;
 
+       if (!opt->pf->af_supported(addr->sa.sa_family, opt))
+               return NULL;
+
        /* V4 mapped address are really of AF_INET family */
        if (addr->sa.sa_family == AF_INET6 &&
-           ipv6_addr_v4mapped(&addr->v6.sin6_addr)) {
-               if (!opt->pf->af_supported(AF_INET, opt))
-                       return NULL;
-       } else {
-               /* Does this PF support this AF? */
-               if (!opt->pf->af_supported(addr->sa.sa_family, opt))
-                       return NULL;
-       }
+           ipv6_addr_v4mapped(&addr->v6.sin6_addr) &&
+           !opt->pf->af_supported(AF_INET, opt))
+               return NULL;
 
        /* If we get this far, af is valid. */
        af = sctp_get_af_specific(addr->sa.sa_family);
@@ -409,7 +408,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
        /* Copy back into socket for getsockname() use. */
        if (!ret) {
                inet_sk(sk)->inet_sport = htons(inet_sk(sk)->inet_num);
-               af->to_sk_saddr(addr, sk);
+               sp->pf->to_sk_saddr(addr, sk);
        }
 
        return ret;
@@ -1060,7 +1059,6 @@ static int __sctp_connect(struct sock* sk,
        struct sctp_association *asoc2;
        struct sctp_transport *transport;
        union sctp_addr to;
-       struct sctp_af *af;
        sctp_scope_t scope;
        long timeo;
        int err = 0;
@@ -1088,6 +1086,8 @@ static int __sctp_connect(struct sock* sk,
        /* Walk through the addrs buffer and count the number of addresses. */
        addr_buf = kaddrs;
        while (walk_size < addrs_size) {
+               struct sctp_af *af;
+
                if (walk_size + sizeof(sa_family_t) > addrs_size) {
                        err = -EINVAL;
                        goto out_free;
@@ -1211,8 +1211,7 @@ static int __sctp_connect(struct sock* sk,
 
        /* Initialize sk's dport and daddr for getpeername() */
        inet_sk(sk)->inet_dport = htons(asoc->peer.port);
-       af = sctp_get_af_specific(sa_addr->sa.sa_family);
-       af->to_sk_daddr(sa_addr, sk);
+       sp->pf->to_sk_daddr(sa_addr, sk);
        sk->sk_err = 0;
 
        /* in-kernel sockets don't generally have a file allocated to them
@@ -1910,6 +1909,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
 
        timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
        if (!sctp_wspace(asoc)) {
+               /* sk can be changed by peel off when waiting for buf. */
                err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len);
                if (err)
                        goto out_free;
@@ -4079,7 +4079,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
        memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr,
                        transport->af_specific->sockaddr_len);
        /* Map ipv4 address into v4-mapped-on-v6 address.  */
-       sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
+       sctp_get_pf_specific(sk->sk_family)->addr_to_user(sctp_sk(sk),
                (union sctp_addr *)&status.sstat_primary.spinfo_address);
        status.sstat_primary.spinfo_state = transport->state;
        status.sstat_primary.spinfo_cwnd = transport->cwnd;
@@ -4238,15 +4238,13 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
                                struct socket **sockp)
 {
        struct sock *sk = asoc->base.sk;
+       struct sctp_sock *sp = sctp_sk(sk);
        struct socket *sock;
-       struct sctp_af *af;
        int err = 0;
 
-       /* If there is a thread waiting on more sndbuf space for
-        * sending on this asoc, it cannot be peeled.
-        */
-       if (waitqueue_active(&asoc->wait))
-               return -EBUSY;
+       /* Do not peel off from one netns to another one. */
+       if (!net_eq(current->nsproxy->net_ns, sock_net(sk)))
+               return -EINVAL;
 
        /* An association cannot be branched off from an already peeled-off
         * socket, nor is this supported for tcp style sockets.
@@ -4264,8 +4262,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
        /* Make peeled-off sockets more like 1-1 accepted sockets.
         * Set the daddr and initialize id to something more random
         */
-       af = sctp_get_af_specific(asoc->peer.primary_addr.sa.sa_family);
-       af->to_sk_daddr(&asoc->peer.primary_addr, sk);
+       sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk);
 
        /* Populate the fields of the newsk from the oldsk and migrate the
         * asoc to the newsk.
@@ -4640,8 +4637,8 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
        list_for_each_entry(from, &asoc->peer.transport_addr_list,
                                transports) {
                memcpy(&temp, &from->ipaddr, sizeof(temp));
-               sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
-               addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
+               addrlen = sctp_get_pf_specific(sk->sk_family)
+                             ->addr_to_user(sp, &temp);
                if (space_left < addrlen)
                        return -ENOMEM;
                if (copy_to_user(to, &temp, addrlen))
@@ -4684,9 +4681,9 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
                if (!temp.v4.sin_port)
                        temp.v4.sin_port = htons(port);
 
-               sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
-                                                               &temp);
-               addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
+               addrlen = sctp_get_pf_specific(sk->sk_family)
+                             ->addr_to_user(sctp_sk(sk), &temp);
+
                if (space_left < addrlen) {
                        cnt =  -ENOMEM;
                        break;
@@ -4774,8 +4771,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
         */
        list_for_each_entry(addr, &bp->address_list, list) {
                memcpy(&temp, &addr->a, sizeof(temp));
-               sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
-               addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
+               addrlen = sctp_get_pf_specific(sk->sk_family)
+                             ->addr_to_user(sp, &temp);
                if (space_left < addrlen) {
                        err =  -ENOMEM; /*fixme: right error?*/
                        goto out;
@@ -4834,7 +4831,7 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
        memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr,
                asoc->peer.primary_path->af_specific->sockaddr_len);
 
-       sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp,
+       sctp_get_pf_specific(sk->sk_family)->addr_to_user(sp,
                        (union sctp_addr *)&prim.ssp_addr);
 
        if (put_user(len, optlen))
@@ -6469,9 +6466,9 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
                                size_t msg_len)
 {
        struct sock *sk = asoc->base.sk;
-       int err = 0;
        long current_timeo = *timeo_p;
        DEFINE_WAIT(wait);
+       int err = 0;
 
        SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%zu\n",
                          asoc, (long)(*timeo_p), msg_len);
@@ -6499,6 +6496,8 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
                sctp_release_sock(sk);
                current_timeo = schedule_timeout(current_timeo);
                sctp_lock_sock(sk);
+               if (sk != asoc->base.sk)
+                       goto do_error;
 
                *timeo_p = current_timeo;
        }
index 8da4481..9e3d368 100644 (file)
@@ -274,8 +274,8 @@ void sctp_transport_route(struct sctp_transport *transport,
                 */
                if (asoc && (!asoc->peer.primary_path ||
                                (transport == asoc->peer.active_path)))
-                       opt->pf->af->to_sk_saddr(&transport->saddr,
-                                                asoc->base.sk);
+                       opt->pf->to_sk_saddr(&transport->saddr,
+                                            asoc->base.sk);
        } else
                transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
 }
index 57da447..d6baddc 100644 (file)
@@ -348,7 +348,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
        memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage));
 
        /* Map ipv4 address into v4-mapped-on-v6 address.  */
-       sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_v4map(
+       sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_to_user(
                                        sctp_sk(asoc->base.sk),
                                        (union sctp_addr *)&spc->spc_aaddr);
 
index f7a9906..f5c6068 100644 (file)
@@ -477,6 +477,7 @@ static int rsc_parse(struct cache_detail *cd,
                                goto out;
                        GROUP_AT(rsci.cred.cr_group_info, i) = gid;
                }
+               groups_sort(rsci.cred.cr_group_info);
 
                /* mech name */
                len = qword_get(&mesg, buf, mlen);
index ce13632..26d5f0d 100644 (file)
@@ -539,6 +539,7 @@ static int unix_gid_parse(struct cache_detail *cd,
                GROUP_AT(ug.gi, i) = gid;
        }
 
+       groups_sort(ug.gi);
        ugp = unix_gid_lookup(uid);
        if (ugp) {
                struct cache_head *ch;
@@ -806,6 +807,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
                return SVC_CLOSE;
        for (i = 0; i < slen; i++)
                GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
+       groups_sort(cred->cr_group_info);
        if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
                *authp = rpc_autherr_badverf;
                return SVC_DENIED;
index 4043f71..57fd882 100644 (file)
@@ -329,6 +329,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 
        struct cfg80211_registered_device *rdev;
        int alloc_size;
+       int rv;
 
        WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key));
        WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc));
@@ -362,7 +363,11 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
        mutex_unlock(&cfg80211_mutex);
 
        /* give it a proper name */
-       dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+       rv = dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+       if (rv < 0) {
+               kfree(rdev);
+               return NULL;
+       }
 
        mutex_init(&rdev->mtx);
        mutex_init(&rdev->devlist_mtx);
index 446d224..41a0ebb 100644 (file)
@@ -158,8 +158,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
        [NL80211_ATTR_PID] = { .type = NLA_U32 },
        [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
-       [NL80211_ATTR_PMKID] = { .type = NLA_BINARY,
-                                .len = WLAN_PMKID_LEN },
+       [NL80211_ATTR_PMKID] = { .len = WLAN_PMKID_LEN },
        [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
        [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
        [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
@@ -3500,6 +3499,10 @@ static int validate_scan_freqs(struct nlattr *freqs)
        struct nlattr *attr1, *attr2;
        int n_channels = 0, tmp1, tmp2;
 
+       nla_for_each_nested(attr1, freqs, tmp1)
+               if (nla_len(attr1) != sizeof(u32))
+                       return 0;
+
        nla_for_each_nested(attr1, freqs, tmp1) {
                n_channels++;
                /*
@@ -5820,6 +5823,9 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
        if (err)
                return err;
 
+       if (!tb[NL80211_REKEY_DATA_REPLAY_CTR] || !tb[NL80211_REKEY_DATA_KEK] ||
+           !tb[NL80211_REKEY_DATA_KCK])
+               return -EINVAL;
        if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN)
                return -ERANGE;
        if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN)
index 6897436..de366fb 100644 (file)
@@ -1265,8 +1265,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-       /* we are under RTNL - globally locked - so can use a static struct */
-       static struct station_info sinfo;
+       struct station_info sinfo = {};
        u8 addr[ETH_ALEN];
        int err;
 
index 2529dab..363e3c7 100644 (file)
@@ -7,15 +7,31 @@
  *
  */
 
+#include <linux/bottom_half.h>
+#include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
+#include <linux/percpu.h>
 #include <net/dst.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 
+struct xfrm_trans_tasklet {
+       struct tasklet_struct tasklet;
+       struct sk_buff_head queue;
+};
+
+struct xfrm_trans_cb {
+       int (*finish)(struct sk_buff *skb);
+};
+
+#define XFRM_TRANS_SKB_CB(__skb) ((struct xfrm_trans_cb *)&((__skb)->cb[0]))
+
 static struct kmem_cache *secpath_cachep __read_mostly;
 
+static DEFINE_PER_CPU(struct xfrm_trans_tasklet, xfrm_trans_tasklet);
+
 void __secpath_destroy(struct sec_path *sp)
 {
        int i;
@@ -285,10 +301,50 @@ int xfrm_input_resume(struct sk_buff *skb, int nexthdr)
 }
 EXPORT_SYMBOL(xfrm_input_resume);
 
+static void xfrm_trans_reinject(unsigned long data)
+{
+       struct xfrm_trans_tasklet *trans = (void *)data;
+       struct sk_buff_head queue;
+       struct sk_buff *skb;
+
+       __skb_queue_head_init(&queue);
+       skb_queue_splice_init(&trans->queue, &queue);
+
+       while ((skb = __skb_dequeue(&queue)))
+               XFRM_TRANS_SKB_CB(skb)->finish(skb);
+}
+
+int xfrm_trans_queue(struct sk_buff *skb, int (*finish)(struct sk_buff *))
+{
+       struct xfrm_trans_tasklet *trans;
+
+       trans = this_cpu_ptr(&xfrm_trans_tasklet);
+
+       if (skb_queue_len(&trans->queue) >= netdev_max_backlog)
+               return -ENOBUFS;
+
+       XFRM_TRANS_SKB_CB(skb)->finish = finish;
+       __skb_queue_tail(&trans->queue, skb);
+       tasklet_schedule(&trans->tasklet);
+       return 0;
+}
+EXPORT_SYMBOL(xfrm_trans_queue);
+
 void __init xfrm_input_init(void)
 {
+       int i;
+
        secpath_cachep = kmem_cache_create("secpath_cache",
                                           sizeof(struct sec_path),
                                           0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
                                           NULL);
+
+       for_each_possible_cpu(i) {
+               struct xfrm_trans_tasklet *trans;
+
+               trans = &per_cpu(xfrm_trans_tasklet, i);
+               __skb_queue_head_init(&trans->queue);
+               tasklet_init(&trans->tasklet, xfrm_trans_reinject,
+                            (unsigned long)trans);
+       }
 }
index bd26a97..7bb00d4 100644 (file)
@@ -125,22 +125,17 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
        struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
        struct xfrm_replay_state_esn *rs;
 
-       if (p->flags & XFRM_STATE_ESN) {
-               if (!rt)
-                       return -EINVAL;
-
-               rs = nla_data(rt);
+       if (!rt)
+               return (p->flags & XFRM_STATE_ESN) ? -EINVAL : 0;
 
-               if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
-                       return -EINVAL;
+       rs = nla_data(rt);
 
-               if (nla_len(rt) < xfrm_replay_state_esn_len(rs) &&
-                   nla_len(rt) != sizeof(*rs))
-                       return -EINVAL;
-       }
+       if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
+               return -EINVAL;
 
-       if (!rt)
-               return 0;
+       if (nla_len(rt) < (int)xfrm_replay_state_esn_len(rs) &&
+           nla_len(rt) != sizeof(*rs))
+               return -EINVAL;
 
        if (p->id.proto != IPPROTO_ESP)
                return -EINVAL;
@@ -1530,7 +1525,8 @@ static int xfrm_dump_policy_done(struct netlink_callback *cb)
 {
        struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
 
-       xfrm_policy_walk_done(walk);
+       if (cb->args[0])
+               xfrm_policy_walk_done(walk);
        return 0;
 }
 
@@ -1719,6 +1715,7 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct
                return -EMSGSIZE;
 
        id = nlmsg_data(nlh);
+       memset(&id->sa_id, 0, sizeof(id->sa_id));
        memcpy(&id->sa_id.daddr, &x->id.daddr,sizeof(x->id.daddr));
        id->sa_id.spi = x->id.spi;
        id->sa_id.family = x->props.family;
@@ -2507,6 +2504,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, const struct km_event *c)
                struct nlattr *attr;
 
                id = nlmsg_data(nlh);
+               memset(id, 0, sizeof(*id));
                memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr));
                id->spi = x->id.spi;
                id->family = x->props.family;
index dc5748f..cd23f82 100644 (file)
@@ -28,9 +28,9 @@
 
 
 /* Are we using CONFIG_MODVERSIONS? */
-int modversions = 0;
+static int modversions = 0;
 /* Warn about undefined symbols? (do so if we have vmlinux) */
-int have_vmlinux = 0;
+static int have_vmlinux = 0;
 /* Is CONFIG_MODULE_SRCVERSION_ALL set? */
 static int all_versions = 0;
 /* If we are modposting external module set to 1 */
@@ -225,7 +225,7 @@ static struct symbol *find_symbol(const char *name)
        return NULL;
 }
 
-static struct {
+static const struct {
        const char *str;
        enum export export;
 } export_list[] = {
@@ -816,7 +816,7 @@ static int match(const char *sym, const char * const pat[])
 }
 
 /* sections that we do not want to do full section mismatch check on */
-static const char *section_white_list[] =
+static const char *const section_white_list[] =
 {
        ".comment*",
        ".debug*",
@@ -876,6 +876,8 @@ static void check_section(const char *modname, struct elf_info *elf,
 
 #define DATA_SECTIONS ".data$", ".data.rel$"
 #define TEXT_SECTIONS ".text$"
+#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
+               ".fixup", ".entry.text"
 
 #define INIT_SECTIONS      ".init.*"
 #define DEV_INIT_SECTIONS  ".devinit.*"
@@ -887,18 +889,25 @@ static void check_section(const char *modname, struct elf_info *elf,
 #define CPU_EXIT_SECTIONS  ".cpuexit.*"
 #define MEM_EXIT_SECTIONS  ".memexit.*"
 
+#define ALL_TEXT_SECTIONS  ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
+               TEXT_SECTIONS, OTHER_TEXT_SECTIONS
+
 /* init data sections */
-static const char *init_data_sections[] = { ALL_INIT_DATA_SECTIONS, NULL };
+static const char *const init_data_sections[] =
+       { ALL_INIT_DATA_SECTIONS, NULL };
 
 /* all init sections */
-static const char *init_sections[] = { ALL_INIT_SECTIONS, NULL };
+static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL };
 
 /* All init and exit sections (code + data) */
-static const char *init_exit_sections[] =
+static const char *const init_exit_sections[] =
        {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL };
 
+/* all text sections */
+static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL };
+
 /* data section */
-static const char *data_sections[] = { DATA_SECTIONS, NULL };
+static const char *const data_sections[] = { DATA_SECTIONS, NULL };
 
 
 /* symbols in .data that may refer to init/exit sections */
@@ -912,9 +921,10 @@ static const char *data_sections[] = { DATA_SECTIONS, NULL };
        "*_probe_one",                                                  \
        "*_console"
 
-static const char *head_sections[] = { ".head.text*", NULL };
-static const char *linker_symbols[] =
+static const char *const head_sections[] = { ".head.text*", NULL };
+static const char *const linker_symbols[] =
        { "__init_begin", "_sinittext", "_einittext", NULL };
+static const char *const optim_symbols[] = { "*.constprop.*", NULL };
 
 enum mismatch {
        TEXT_TO_ANY_INIT,
@@ -935,7 +945,7 @@ struct sectioncheck {
        const char *symbol_white_list[20];
 };
 
-const struct sectioncheck sectioncheck[] = {
+static const struct sectioncheck sectioncheck[] = {
 /* Do not reference init/exit code/data from
  * normal code and data
  */
@@ -1096,6 +1106,17 @@ static const struct sectioncheck *section_mismatch(
  *   This pattern is identified by
  *   refsymname = __init_begin, _sinittext, _einittext
  *
+ * Pattern 5:
+ *   GCC may optimize static inlines when fed constant arg(s) resulting
+ *   in functions like cpumask_empty() -- generating an associated symbol
+ *   cpumask_empty.constprop.3 that appears in the audit.  If the const that
+ *   is passed in comes from __init, like say nmi_ipi_mask, we get a
+ *   meaningless section warning.  May need to add isra symbols too...
+ *   This pattern is identified by
+ *   tosec   = init section
+ *   fromsec = text section
+ *   refsymname = *.constprop.*
+ *
  **/
 static int secref_whitelist(const struct sectioncheck *mismatch,
                            const char *fromsec, const char *fromsym,
@@ -1128,6 +1149,12 @@ static int secref_whitelist(const struct sectioncheck *mismatch,
        if (match(tosym, linker_symbols))
                return 0;
 
+       /* Check for pattern 5 */
+       if (match(fromsec, text_sections) &&
+           match(tosec, init_sections) &&
+           match(fromsym, optim_symbols))
+               return 0;
+
        return 1;
 }
 
@@ -1862,6 +1889,14 @@ static void add_intree_flag(struct buffer *b, int is_intree)
                buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
 }
 
+/* Cannot check for assembler */
+static void add_retpoline(struct buffer *b)
+{
+       buf_printf(b, "\n#ifdef RETPOLINE\n");
+       buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
+       buf_printf(b, "#endif\n");
+}
+
 static void add_staging_flag(struct buffer *b, const char *name)
 {
        static const char *staging_dir = "drivers/staging";
@@ -2183,6 +2218,7 @@ int main(int argc, char **argv)
 
                add_header(&buf, mod);
                add_intree_flag(&buf, !external_module);
+               add_retpoline(&buf);
                add_staging_flag(&buf, mod->name);
                err |= add_versions(&buf, mod);
                add_depends(&buf, mod, modules);
index 51bd5a0..b9bc07d 100644 (file)
@@ -96,6 +96,16 @@ config SECURITY
 
          If you are unsure how to answer this question, answer N.
 
+config PAGE_TABLE_ISOLATION
+       bool "Remove the kernel mapping in user mode"
+       default y
+       depends on X86_64 && SMP
+       help
+         This enforces a strict kernel and user space isolation, in order
+         to close hardware side channels on kernel address information.
+
+         If you are unsure how to answer this question, answer Y.
+
 config SECURITYFS
        bool "Enable the securityfs filesystem"
        help
index 720eb81..b13db96 100644 (file)
@@ -315,6 +315,13 @@ static struct key *request_user_key(const char *master_desc, u8 **master_key,
 
        down_read(&ukey->sem);
        upayload = rcu_dereference(ukey->payload.data);
+       if (!upayload) {
+               /* key was revoked before we acquired its semaphore */
+               up_read(&ukey->sem);
+               key_put(ukey);
+               ukey = ERR_PTR(-EKEYREVOKED);
+               goto error;
+       }
        *master_key = upayload->data;
        *master_keylen = upayload->datalen;
 error:
index c7a7cae..1f4b104 100644 (file)
@@ -124,7 +124,7 @@ extern key_ref_t search_process_keyrings(struct key_type *type,
                                         key_match_func_t match,
                                         const struct cred *cred);
 
-extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check);
+extern struct key *find_keyring_by_name(const char *name, bool uid_keyring);
 
 extern int install_user_keyrings(void);
 extern int install_thread_keyring_to_cred(struct cred *);
index d3b2f6e..1f5c2c5 100644 (file)
@@ -305,6 +305,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
 
        if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
                key->flags |= 1 << KEY_FLAG_IN_QUOTA;
+       if (flags & KEY_ALLOC_UID_KEYRING)
+               key->flags |= 1 << KEY_FLAG_UID_KEYRING;
 
        memset(&key->type_data, 0, sizeof(key->type_data));
 
@@ -847,6 +849,16 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
        __key_link_end(keyring, ktype, prealloc);
        key_type_put(ktype);
 
+       key = key_ref_to_ptr(key_ref);
+       if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) {
+               ret = wait_for_key_construction(key, true);
+               if (ret < 0) {
+                       key_ref_put(key_ref);
+                       key_ref = ERR_PTR(ret);
+                       goto error;
+               }
+       }
+
        key_ref = __key_update(key_ref, payload, plen);
        goto error;
 }
index 4152533..659d1cb 100644 (file)
@@ -684,7 +684,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
        if (ret == 0)
                goto can_read_key;
        if (ret != -EACCES)
-               goto error;
+               goto error2;
 
        /* we can't; see if it's searchable from this process's keyrings
         * - we automatically take account of the fact that it may be
@@ -1345,11 +1345,9 @@ long keyctl_assume_authority(key_serial_t id)
        }
 
        ret = keyctl_change_reqkey_auth(authkey);
-       if (ret < 0)
-               goto error;
+       if (ret == 0)
+               ret = authkey->serial;
        key_put(authkey);
-
-       ret = authkey->serial;
 error:
        return ret;
 }
index 8f31d5f..4d01452 100644 (file)
@@ -550,15 +550,15 @@ found:
 /*
  * Find a keyring with the specified name.
  *
- * All named keyrings in the current user namespace are searched, provided they
- * grant Search permission directly to the caller (unless this check is
- * skipped).  Keyrings whose usage points have reached zero or who have been
- * revoked are skipped.
+ * Only keyrings that have nonzero refcount, are not revoked, and are owned by a
+ * user in the current user namespace are considered.  If @uid_keyring is %true,
+ * the keyring additionally must have been allocated as a user or user session
+ * keyring; otherwise, it must grant Search permission directly to the caller.
  *
  * Returns a pointer to the keyring with the keyring's refcount having being
  * incremented on success.  -ENOKEY is returned if a key could not be found.
  */
-struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
+struct key *find_keyring_by_name(const char *name, bool uid_keyring)
 {
        struct key *keyring;
        int bucket;
@@ -586,10 +586,15 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
                        if (strcmp(keyring->description, name) != 0)
                                continue;
 
-                       if (!skip_perm_check &&
-                           key_permission(make_key_ref(keyring, 0),
-                                          KEY_SEARCH) < 0)
-                               continue;
+                       if (uid_keyring) {
+                               if (!test_bit(KEY_FLAG_UID_KEYRING,
+                                             &keyring->flags))
+                                       continue;
+                       } else {
+                               if (key_permission(make_key_ref(keyring, 0),
+                                                  KEY_SEARCH) < 0)
+                                       continue;
+                       }
 
                        /* we've got a match but we might end up racing with
                         * key_cleanup() if the keyring is currently 'dead'
index fe5719f..7777cb8 100644 (file)
@@ -72,7 +72,9 @@ int install_user_keyrings(void)
                uid_keyring = find_keyring_by_name(buf, true);
                if (IS_ERR(uid_keyring)) {
                        uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
-                                                   cred, KEY_ALLOC_IN_QUOTA,
+                                                   cred,
+                                                   KEY_ALLOC_UID_KEYRING |
+                                                       KEY_ALLOC_IN_QUOTA,
                                                    NULL);
                        if (IS_ERR(uid_keyring)) {
                                ret = PTR_ERR(uid_keyring);
@@ -88,7 +90,10 @@ int install_user_keyrings(void)
                if (IS_ERR(session_keyring)) {
                        session_keyring =
                                keyring_alloc(buf, user->uid, (gid_t) -1,
-                                             cred, KEY_ALLOC_IN_QUOTA, NULL);
+                                             cred,
+                                             KEY_ALLOC_UID_KEYRING |
+                                                 KEY_ALLOC_IN_QUOTA,
+                                             NULL);
                        if (IS_ERR(session_keyring)) {
                                ret = PTR_ERR(session_keyring);
                                goto error_release;
index 8246532..a5e32b6 100644 (file)
@@ -267,11 +267,12 @@ static int construct_key(struct key *key, const void *callout_info,
  * The keyring selected is returned with an extra reference upon it which the
  * caller must release.
  */
-static void construct_get_dest_keyring(struct key **_dest_keyring)
+static int construct_get_dest_keyring(struct key **_dest_keyring)
 {
        struct request_key_auth *rka;
        const struct cred *cred = current_cred();
        struct key *dest_keyring = *_dest_keyring, *authkey;
+       int ret;
 
        kenter("%p", dest_keyring);
 
@@ -280,6 +281,8 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
                /* the caller supplied one */
                key_get(dest_keyring);
        } else {
+               bool do_perm_check = true;
+
                /* use a default keyring; falling through the cases until we
                 * find one that we actually have */
                switch (cred->jit_keyring) {
@@ -294,8 +297,10 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
                                        dest_keyring =
                                                key_get(rka->dest_keyring);
                                up_read(&authkey->sem);
-                               if (dest_keyring)
+                               if (dest_keyring) {
+                                       do_perm_check = false;
                                        break;
+                               }
                        }
 
                case KEY_REQKEY_DEFL_THREAD_KEYRING:
@@ -330,11 +335,29 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
                default:
                        BUG();
                }
+
+               /*
+                * Require Write permission on the keyring.  This is essential
+                * because the default keyring may be the session keyring, and
+                * joining a keyring only requires Search permission.
+                *
+                * However, this check is skipped for the "requestor keyring" so
+                * that /sbin/request-key can itself use request_key() to add
+                * keys to the original requestor's destination keyring.
+                */
+               if (dest_keyring && do_perm_check) {
+                       ret = key_permission(make_key_ref(dest_keyring, 1),
+                                            KEY_WRITE);
+                       if (ret) {
+                               key_put(dest_keyring);
+                               return ret;
+                       }
+               }
        }
 
        *_dest_keyring = dest_keyring;
        kleave(" [dk %d]", key_serial(dest_keyring));
-       return;
+       return 0;
 }
 
 /*
@@ -449,11 +472,15 @@ static struct key *construct_key_and_link(struct key_type *type,
 
        kenter("");
 
-       user = key_user_lookup(current_fsuid(), current_user_ns());
-       if (!user)
-               return ERR_PTR(-ENOMEM);
+       ret = construct_get_dest_keyring(&dest_keyring);
+       if (ret)
+               goto error;
 
-       construct_get_dest_keyring(&dest_keyring);
+       user = key_user_lookup(current_fsuid(), current_user_ns());
+       if (!user) {
+               ret = -ENOMEM;
+               goto error_put_dest_keyring;
+       }
 
        ret = construct_alloc_key(type, description, dest_keyring, flags, user,
                                  &key);
@@ -469,7 +496,7 @@ static struct key *construct_key_and_link(struct key_type *type,
        } else if (ret == -EINPROGRESS) {
                ret = 0;
        } else {
-               goto couldnt_alloc_key;
+               goto error_put_dest_keyring;
        }
 
        key_put(dest_keyring);
@@ -479,8 +506,9 @@ static struct key *construct_key_and_link(struct key_type *type,
 construction_failed:
        key_negate_and_link(key, key_negative_timeout, NULL, NULL);
        key_put(key);
-couldnt_alloc_key:
+error_put_dest_keyring:
        key_put(dest_keyring);
+error:
        kleave(" = %d", ret);
        return ERR_PTR(ret);
 }
index 60d4e3f..40a06a3 100644 (file)
@@ -106,6 +106,18 @@ static void request_key_auth_revoke(struct key *key)
        }
 }
 
+static void free_request_key_auth(struct request_key_auth *rka)
+{
+       if (!rka)
+               return;
+       key_put(rka->target_key);
+       key_put(rka->dest_keyring);
+       if (rka->cred)
+               put_cred(rka->cred);
+       kfree(rka->callout_info);
+       kfree(rka);
+}
+
 /*
  * Destroy an instantiation authorisation token key.
  */
@@ -115,15 +127,7 @@ static void request_key_auth_destroy(struct key *key)
 
        kenter("{%d}", key->serial);
 
-       if (rka->cred) {
-               put_cred(rka->cred);
-               rka->cred = NULL;
-       }
-
-       key_put(rka->target_key);
-       key_put(rka->dest_keyring);
-       kfree(rka->callout_info);
-       kfree(rka);
+       free_request_key_auth(rka);
 }
 
 /*
@@ -137,22 +141,17 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
        const struct cred *cred = current->cred;
        struct key *authkey = NULL;
        char desc[20];
-       int ret;
+       int ret = -ENOMEM;
 
        kenter("%d,", target->serial);
 
        /* allocate a auth record */
-       rka = kmalloc(sizeof(*rka), GFP_KERNEL);
-       if (!rka) {
-               kleave(" = -ENOMEM");
-               return ERR_PTR(-ENOMEM);
-       }
+       rka = kzalloc(sizeof(*rka), GFP_KERNEL);
+       if (!rka)
+               goto error;
        rka->callout_info = kmalloc(callout_len, GFP_KERNEL);
-       if (!rka->callout_info) {
-               kleave(" = -ENOMEM");
-               kfree(rka);
-               return ERR_PTR(-ENOMEM);
-       }
+       if (!rka->callout_info)
+               goto error_free_rka;
 
        /* see if the calling process is already servicing the key request of
         * another process */
@@ -162,8 +161,12 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
 
                /* if the auth key has been revoked, then the key we're
                 * servicing is already instantiated */
-               if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags))
-                       goto auth_key_revoked;
+               if (test_bit(KEY_FLAG_REVOKED,
+                            &cred->request_key_auth->flags)) {
+                       up_read(&cred->request_key_auth->sem);
+                       ret = -EKEYREVOKED;
+                       goto error_free_rka;
+               }
 
                irka = cred->request_key_auth->payload.data;
                rka->cred = get_cred(irka->cred);
@@ -191,32 +194,22 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
                            KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
        if (IS_ERR(authkey)) {
                ret = PTR_ERR(authkey);
-               goto error_alloc;
+               goto error_free_rka;
        }
 
        /* construct the auth key */
        ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL);
        if (ret < 0)
-               goto error_inst;
+               goto error_put_authkey;
 
        kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage));
        return authkey;
 
-auth_key_revoked:
-       up_read(&cred->request_key_auth->sem);
-       kfree(rka->callout_info);
-       kfree(rka);
-       kleave("= -EKEYREVOKED");
-       return ERR_PTR(-EKEYREVOKED);
-
-error_inst:
-       key_revoke(authkey);
+error_put_authkey:
        key_put(authkey);
-error_alloc:
-       key_put(rka->target_key);
-       key_put(rka->dest_keyring);
-       kfree(rka->callout_info);
-       kfree(rka);
+error_free_rka:
+       free_request_key_auth(rka);
+error:
        kleave("= %d", ret);
        return ERR_PTR(ret);
 }
index 0ed5fdf..c73462b 100644 (file)
@@ -69,7 +69,7 @@ static int TSS_sha1(const unsigned char *data, unsigned int datalen,
        }
 
        ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
-       kfree(sdesc);
+       kzfree(sdesc);
        return ret;
 }
 
@@ -113,7 +113,7 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
        if (!ret)
                ret = crypto_shash_final(&sdesc->shash, digest);
 out:
-       kfree(sdesc);
+       kzfree(sdesc);
        return ret;
 }
 
@@ -164,7 +164,7 @@ static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
                                  paramdigest, TPM_NONCE_SIZE, h1,
                                  TPM_NONCE_SIZE, h2, 1, &c, 0, 0);
 out:
-       kfree(sdesc);
+       kzfree(sdesc);
        return ret;
 }
 
@@ -245,7 +245,7 @@ static int TSS_checkhmac1(unsigned char *buffer,
        if (memcmp(testhmac, authdata, SHA1_DIGEST_SIZE))
                ret = -EINVAL;
 out:
-       kfree(sdesc);
+       kzfree(sdesc);
        return ret;
 }
 
@@ -346,7 +346,7 @@ static int TSS_checkhmac2(unsigned char *buffer,
        if (memcmp(testhmac2, authdata2, SHA1_DIGEST_SIZE))
                ret = -EINVAL;
 out:
-       kfree(sdesc);
+       kzfree(sdesc);
        return ret;
 }
 
@@ -396,7 +396,7 @@ static int my_get_random(unsigned char *buf, int len)
                return -ENOMEM;
        ret = tpm_get_random(tb, buf, len);
 
-       kfree(tb);
+       kzfree(tb);
        return ret;
 }
 
@@ -595,7 +595,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
                *bloblen = storedsize;
        }
 out:
-       kfree(td);
+       kzfree(td);
        return ret;
 }
 
@@ -709,7 +709,7 @@ static int key_seal(struct trusted_key_payload *p,
        if (ret < 0)
                pr_info("trusted_key: srkseal failed (%d)\n", ret);
 
-       kfree(tb);
+       kzfree(tb);
        return ret;
 }
 
@@ -734,7 +734,7 @@ static int key_unseal(struct trusted_key_payload *p,
                /* pull migratable flag out of sealed key */
                p->migratable = p->key[--p->key_len];
 
-       kfree(tb);
+       kzfree(tb);
        return ret;
 }
 
@@ -990,12 +990,12 @@ static int trusted_instantiate(struct key *key, const void *data,
        if (!ret && options->pcrlock)
                ret = pcrlock(options->pcrlock);
 out:
-       kfree(datablob);
-       kfree(options);
+       kzfree(datablob);
+       kzfree(options);
        if (!ret)
                rcu_assign_pointer(key->payload.data, payload);
        else
-               kfree(payload);
+               kzfree(payload);
        return ret;
 }
 
@@ -1004,8 +1004,7 @@ static void trusted_rcu_free(struct rcu_head *rcu)
        struct trusted_key_payload *p;
 
        p = container_of(rcu, struct trusted_key_payload, rcu);
-       memset(p->key, 0, p->key_len);
-       kfree(p);
+       kzfree(p);
 }
 
 /*
@@ -1043,7 +1042,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
        ret = datablob_parse(datablob, new_p, new_o);
        if (ret != Opt_update) {
                ret = -EINVAL;
-               kfree(new_p);
+               kzfree(new_p);
                goto out;
        }
        /* copy old key values, and reseal with new pcrs */
@@ -1056,22 +1055,22 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
        ret = key_seal(new_p, new_o);
        if (ret < 0) {
                pr_info("trusted_key: key_seal failed (%d)\n", ret);
-               kfree(new_p);
+               kzfree(new_p);
                goto out;
        }
        if (new_o->pcrlock) {
                ret = pcrlock(new_o->pcrlock);
                if (ret < 0) {
                        pr_info("trusted_key: pcrlock failed (%d)\n", ret);
-                       kfree(new_p);
+                       kzfree(new_p);
                        goto out;
                }
        }
        rcu_assign_pointer(key->payload.data, new_p);
        call_rcu(&p->rcu, trusted_rcu_free);
 out:
-       kfree(datablob);
-       kfree(new_o);
+       kzfree(datablob);
+       kzfree(new_o);
        return ret;
 }
 
@@ -1090,34 +1089,30 @@ static long trusted_read(const struct key *key, char __user *buffer,
        p = rcu_dereference_key(key);
        if (!p)
                return -EINVAL;
-       if (!buffer || buflen <= 0)
-               return 2 * p->blob_len;
-       ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL);
-       if (!ascii_buf)
-               return -ENOMEM;
 
-       bufp = ascii_buf;
-       for (i = 0; i < p->blob_len; i++)
-               bufp = hex_byte_pack(bufp, p->blob[i]);
-       if ((copy_to_user(buffer, ascii_buf, 2 * p->blob_len)) != 0) {
-               kfree(ascii_buf);
-               return -EFAULT;
+       if (buffer && buflen >= 2 * p->blob_len) {
+               ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL);
+               if (!ascii_buf)
+                       return -ENOMEM;
+
+               bufp = ascii_buf;
+               for (i = 0; i < p->blob_len; i++)
+                       bufp = hex_byte_pack(bufp, p->blob[i]);
+               if (copy_to_user(buffer, ascii_buf, 2 * p->blob_len) != 0) {
+                       kzfree(ascii_buf);
+                       return -EFAULT;
+               }
+               kzfree(ascii_buf);
        }
-       kfree(ascii_buf);
        return 2 * p->blob_len;
 }
 
 /*
- * trusted_destroy - before freeing the key, clear the decrypted data
+ * trusted_destroy - clear and free the key's payload
  */
 static void trusted_destroy(struct key *key)
 {
-       struct trusted_key_payload *p = key->payload.data;
-
-       if (!p)
-               return;
-       memset(p->key, 0, p->key_len);
-       kfree(key->payload.data);
+       kzfree(key->payload.data);
 }
 
 struct key_type key_type_trusted = {
index 4c6a347..ad1cb35 100644 (file)
@@ -1845,7 +1845,7 @@ static int selinux_ptrace_access_check(struct task_struct *child,
        if (rc)
                return rc;
 
-       if (mode == PTRACE_MODE_READ) {
+       if (mode & PTRACE_MODE_READ) {
                u32 sid = current_sid();
                u32 csid = task_sid(child);
                return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
index 72b20b1..bc069d5 100644 (file)
@@ -1806,7 +1806,7 @@ static int security_preserve_bools(struct policydb *p);
  */
 int security_load_policy(void *data, size_t len)
 {
-       struct policydb oldpolicydb, newpolicydb;
+       struct policydb *oldpolicydb, *newpolicydb;
        struct sidtab oldsidtab, newsidtab;
        struct selinux_mapping *oldmap, *map = NULL;
        struct convert_context_args args;
@@ -1815,12 +1815,19 @@ int security_load_policy(void *data, size_t len)
        int rc = 0;
        struct policy_file file = { data, len }, *fp = &file;
 
+       oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL);
+       if (!oldpolicydb) {
+               rc = -ENOMEM;
+               goto out;
+       }
+       newpolicydb = oldpolicydb + 1;
+
        if (!ss_initialized) {
                avtab_cache_init();
                rc = policydb_read(&policydb, fp);
                if (rc) {
                        avtab_cache_destroy();
-                       return rc;
+                       goto out;
                }
 
                policydb.len = len;
@@ -1830,14 +1837,14 @@ int security_load_policy(void *data, size_t len)
                if (rc) {
                        policydb_destroy(&policydb);
                        avtab_cache_destroy();
-                       return rc;
+                       goto out;
                }
 
                rc = policydb_load_isids(&policydb, &sidtab);
                if (rc) {
                        policydb_destroy(&policydb);
                        avtab_cache_destroy();
-                       return rc;
+                       goto out;
                }
 
                security_load_policycaps();
@@ -1849,36 +1856,36 @@ int security_load_policy(void *data, size_t len)
                selinux_status_update_policyload(seqno);
                selinux_netlbl_cache_invalidate();
                selinux_xfrm_notify_policyload();
-               return 0;
+               goto out;
        }
 
 #if 0
        sidtab_hash_eval(&sidtab, "sids");
 #endif
 
-       rc = policydb_read(&newpolicydb, fp);
+       rc = policydb_read(newpolicydb, fp);
        if (rc)
-               return rc;
+               goto out;
 
-       newpolicydb.len = len;
+       newpolicydb->len = len;
        /* If switching between different policy types, log MLS status */
-       if (policydb.mls_enabled && !newpolicydb.mls_enabled)
+       if (policydb.mls_enabled && !newpolicydb->mls_enabled)
                printk(KERN_INFO "SELinux: Disabling MLS support...\n");
-       else if (!policydb.mls_enabled && newpolicydb.mls_enabled)
+       else if (!policydb.mls_enabled && newpolicydb->mls_enabled)
                printk(KERN_INFO "SELinux: Enabling MLS support...\n");
 
-       rc = policydb_load_isids(&newpolicydb, &newsidtab);
+       rc = policydb_load_isids(newpolicydb, &newsidtab);
        if (rc) {
                printk(KERN_ERR "SELinux:  unable to load the initial SIDs\n");
-               policydb_destroy(&newpolicydb);
-               return rc;
+               policydb_destroy(newpolicydb);
+               goto out;
        }
 
-       rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size);
+       rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size);
        if (rc)
                goto err;
 
-       rc = security_preserve_bools(&newpolicydb);
+       rc = security_preserve_bools(newpolicydb);
        if (rc) {
                printk(KERN_ERR "SELinux:  unable to preserve booleans\n");
                goto err;
@@ -1896,7 +1903,7 @@ int security_load_policy(void *data, size_t len)
         * in the new SID table.
         */
        args.oldp = &policydb;
-       args.newp = &newpolicydb;
+       args.newp = newpolicydb;
        rc = sidtab_map(&newsidtab, convert_context, &args);
        if (rc) {
                printk(KERN_ERR "SELinux:  unable to convert the internal"
@@ -1906,12 +1913,12 @@ int security_load_policy(void *data, size_t len)
        }
 
        /* Save the old policydb and SID table to free later. */
-       memcpy(&oldpolicydb, &policydb, sizeof policydb);
+       memcpy(oldpolicydb, &policydb, sizeof(policydb));
        sidtab_set(&oldsidtab, &sidtab);
 
        /* Install the new policydb and SID table. */
        write_lock_irq(&policy_rwlock);
-       memcpy(&policydb, &newpolicydb, sizeof policydb);
+       memcpy(&policydb, newpolicydb, sizeof(policydb));
        sidtab_set(&sidtab, &newsidtab);
        security_load_policycaps();
        oldmap = current_mapping;
@@ -1921,7 +1928,7 @@ int security_load_policy(void *data, size_t len)
        write_unlock_irq(&policy_rwlock);
 
        /* Free the old policydb and SID table. */
-       policydb_destroy(&oldpolicydb);
+       policydb_destroy(oldpolicydb);
        sidtab_destroy(&oldsidtab);
        kfree(oldmap);
 
@@ -1931,14 +1938,17 @@ int security_load_policy(void *data, size_t len)
        selinux_netlbl_cache_invalidate();
        selinux_xfrm_notify_policyload();
 
-       return 0;
+       rc = 0;
+       goto out;
 
 err:
        kfree(map);
        sidtab_destroy(&newsidtab);
-       policydb_destroy(&newpolicydb);
-       return rc;
+       policydb_destroy(newpolicydb);
 
+out:
+       kfree(oldpolicydb);
+       return rc;
 }
 
 size_t security_policydb_len(void)
index 774c159..5e23bb8 100644 (file)
@@ -583,7 +583,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
        }
 
        if (len)
-               *len = strlen(isp) + 1;
+               *len = strlen(isp);
 
        return 0;
 }
@@ -940,7 +940,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
  * @inode: the object
  * @name: attribute name
  * @buffer: where to put the result
- * @alloc: unused
+ * @alloc: duplicate memory
  *
  * Returns the size of the attribute or an error code
  */
@@ -953,43 +953,38 @@ static int smack_inode_getsecurity(const struct inode *inode,
        struct super_block *sbp;
        struct inode *ip = (struct inode *)inode;
        char *isp;
-       int ilen;
-       int rc = 0;
 
-       if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
+       if (strcmp(name, XATTR_SMACK_SUFFIX) == 0)
                isp = smk_of_inode(inode);
-               ilen = strlen(isp) + 1;
-               *buffer = isp;
-               return ilen;
-       }
+       else {
+               /*
+                * The rest of the Smack xattrs are only on sockets.
+                */
+               sbp = ip->i_sb;
+               if (sbp->s_magic != SOCKFS_MAGIC)
+                       return -EOPNOTSUPP;
 
-       /*
-        * The rest of the Smack xattrs are only on sockets.
-        */
-       sbp = ip->i_sb;
-       if (sbp->s_magic != SOCKFS_MAGIC)
-               return -EOPNOTSUPP;
+               sock = SOCKET_I(ip);
+               if (sock == NULL || sock->sk == NULL)
+                       return -EOPNOTSUPP;
 
-       sock = SOCKET_I(ip);
-       if (sock == NULL || sock->sk == NULL)
-               return -EOPNOTSUPP;
-
-       ssp = sock->sk->sk_security;
+               ssp = sock->sk->sk_security;
 
-       if (strcmp(name, XATTR_SMACK_IPIN) == 0)
-               isp = ssp->smk_in;
-       else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
-               isp = ssp->smk_out;
-       else
-               return -EOPNOTSUPP;
+               if (strcmp(name, XATTR_SMACK_IPIN) == 0)
+                       isp = ssp->smk_in;
+               else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
+                       isp = ssp->smk_out;
+               else
+                       return -EOPNOTSUPP;
+       }
 
-       ilen = strlen(isp) + 1;
-       if (rc == 0) {
-               *buffer = isp;
-               rc = ilen;
+       if (alloc) {
+               *buffer = kstrdup(isp, GFP_KERNEL);
+               if (*buffer == NULL)
+                       return -ENOMEM;
        }
 
-       return rc;
+       return strlen(isp);
 }
 
 
index 132856b..fd2de93 100644 (file)
@@ -1084,7 +1084,7 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
                mutex_lock(&ue->card->user_ctl_lock);
                change = ue->tlv_data_size != size;
                if (!change)
-                       change = memcmp(ue->tlv_data, new_data, size);
+                       change = memcmp(ue->tlv_data, new_data, size) != 0;
                kfree(ue->tlv_data);
                ue->tlv_data = new_data;
                ue->tlv_data_size = size;
index 14d483d..834fa60 100644 (file)
@@ -145,6 +145,7 @@ static int __init snd_hrtimer_init(void)
        timer->hw = hrtimer_hw;
        timer->hw.resolution = resolution;
        timer->hw.ticks = NANO_SEC / resolution;
+       timer->max_instances = 100; /* lower the limit */
 
        err = snd_timer_global_register(timer);
        if (err < 0) {
index fa49a27..5343f34 100644 (file)
@@ -465,7 +465,6 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
                v = snd_pcm_hw_param_last(pcm, params, var, dir);
        else
                v = snd_pcm_hw_param_first(pcm, params, var, dir);
-       snd_BUG_ON(v < 0);
        return v;
 }
 
@@ -1368,7 +1367,7 @@ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const cha
 static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const char __user *buf, size_t bytes)
 {
        size_t xfer = 0;
-       ssize_t tmp;
+       ssize_t tmp = 0;
        struct snd_pcm_runtime *runtime = substream->runtime;
 
        if (atomic_read(&substream->mmap_count))
@@ -1376,8 +1375,11 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
 
        if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
                return tmp;
-       mutex_lock(&runtime->oss.params_lock);
        while (bytes > 0) {
+               if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+                       tmp = -ERESTARTSYS;
+                       break;
+               }
                if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
                        tmp = bytes;
                        if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
@@ -1421,14 +1423,18 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha
                        xfer += tmp;
                        if ((substream->f_flags & O_NONBLOCK) != 0 &&
                            tmp != runtime->oss.period_bytes)
-                               break;
+                               tmp = -EAGAIN;
                }
-       }
-       mutex_unlock(&runtime->oss.params_lock);
-       return xfer;
-
  err:
-       mutex_unlock(&runtime->oss.params_lock);
+               mutex_unlock(&runtime->oss.params_lock);
+               if (tmp < 0)
+                       break;
+               if (signal_pending(current)) {
+                       tmp = -ERESTARTSYS;
+                       break;
+               }
+               tmp = 0;
+       }
        return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
 }
 
@@ -1468,7 +1474,7 @@ static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf,
 static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __user *buf, size_t bytes)
 {
        size_t xfer = 0;
-       ssize_t tmp;
+       ssize_t tmp = 0;
        struct snd_pcm_runtime *runtime = substream->runtime;
 
        if (atomic_read(&substream->mmap_count))
@@ -1476,8 +1482,11 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
 
        if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
                return tmp;
-       mutex_lock(&runtime->oss.params_lock);
        while (bytes > 0) {
+               if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+                       tmp = -ERESTARTSYS;
+                       break;
+               }
                if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
                        if (runtime->oss.buffer_used == 0) {
                                tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
@@ -1508,12 +1517,16 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use
                        bytes -= tmp;
                        xfer += tmp;
                }
-       }
-       mutex_unlock(&runtime->oss.params_lock);
-       return xfer;
-
  err:
-       mutex_unlock(&runtime->oss.params_lock);
+               mutex_unlock(&runtime->oss.params_lock);
+               if (tmp < 0)
+                       break;
+               if (signal_pending(current)) {
+                       tmp = -ERESTARTSYS;
+                       break;
+               }
+               tmp = 0;
+       }
        return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
 }
 
index 71cc3dd..c6cecf7 100644 (file)
@@ -589,18 +589,26 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st
        snd_pcm_sframes_t frames = size;
 
        plugin = snd_pcm_plug_first(plug);
-       while (plugin && frames > 0) {
+       while (plugin) {
+               if (frames <= 0)
+                       return frames;
                if ((next = plugin->next) != NULL) {
                        snd_pcm_sframes_t frames1 = frames;
-                       if (plugin->dst_frames)
+                       if (plugin->dst_frames) {
                                frames1 = plugin->dst_frames(plugin, frames);
+                               if (frames1 <= 0)
+                                       return frames1;
+                       }
                        if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) {
                                return err;
                        }
                        if (err != frames1) {
                                frames = err;
-                               if (plugin->src_frames)
+                               if (plugin->src_frames) {
                                        frames = plugin->src_frames(plugin, frames1);
+                                       if (frames <= 0)
+                                               return frames;
+                               }
                        }
                } else
                        dst_channels = NULL;
index 13eaeb3..00905d1 100644 (file)
@@ -145,7 +145,9 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
                                err = -ENXIO;
                                goto _error;
                        }
+                       mutex_lock(&pcm->open_mutex);
                        err = snd_pcm_info_user(substream, info);
+                       mutex_unlock(&pcm->open_mutex);
                _error:
                        mutex_unlock(&register_mutex);
                        return err;
index b36544a..44e180a 100644 (file)
@@ -590,7 +590,6 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
 {
        u_int64_t n = (u_int64_t) a * b;
        if (c == 0) {
-               snd_BUG_ON(!n);
                *r = 0;
                return UINT_MAX;
        }
@@ -1546,7 +1545,7 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
                return changed;
        if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
-               if (snd_BUG_ON(err < 0))
+               if (err < 0)
                        return err;
        }
        return snd_pcm_hw_param_value(params, var, dir);
@@ -1592,7 +1591,7 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
                return changed;
        if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
-               if (snd_BUG_ON(err < 0))
+               if (err < 0)
                        return err;
        }
        return snd_pcm_hw_param_value(params, var, dir);
index 5b3c19a..7fd28bf 100644 (file)
@@ -3196,7 +3196,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
                                         area,
                                         substream->runtime->dma_area,
                                         substream->runtime->dma_addr,
-                                        area->vm_end - area->vm_start);
+                                        substream->runtime->dma_bytes);
 #elif defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
        if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV &&
            !plat_device_is_coherent(substream->dma_buffer.dev.dev))
index 25f6365..74a7fab 100644 (file)
@@ -575,15 +575,14 @@ static int snd_rawmidi_info_user(struct snd_rawmidi_substream *substream,
        return 0;
 }
 
-int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info)
+static int __snd_rawmidi_info_select(struct snd_card *card,
+                                    struct snd_rawmidi_info *info)
 {
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_str *pstr;
        struct snd_rawmidi_substream *substream;
 
-       mutex_lock(&register_mutex);
        rmidi = snd_rawmidi_search(card, info->device);
-       mutex_unlock(&register_mutex);
        if (!rmidi)
                return -ENXIO;
        if (info->stream < 0 || info->stream > 1)
@@ -600,6 +599,16 @@ int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info
        return -ENXIO;
 }
 
+int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info)
+{
+       int ret;
+
+       mutex_lock(&register_mutex);
+       ret = __snd_rawmidi_info_select(card, info);
+       mutex_unlock(&register_mutex);
+       return ret;
+}
+
 static int snd_rawmidi_info_select_user(struct snd_card *card,
                                        struct snd_rawmidi_info __user *_info)
 {
index 677dc84..707f6ff 100644 (file)
@@ -618,9 +618,7 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq
        if (!dp->timer->running)
                len = snd_seq_oss_timer_start(dp->timer);
        if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
-               if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
-                       snd_seq_oss_readq_puts(dp->readq, mdev->seq_device,
-                                              ev->data.ext.ptr, ev->data.ext.len);
+               snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev);
        } else {
                len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev);
                if (len > 0)
index 73661c4..7bbc610 100644 (file)
@@ -119,6 +119,35 @@ snd_seq_oss_readq_puts(struct seq_oss_readq *q, int dev, unsigned char *data, in
        return 0;
 }
 
+/*
+ * put MIDI sysex bytes; the event buffer may be chained, thus it has
+ * to be expanded via snd_seq_dump_var_event().
+ */
+struct readq_sysex_ctx {
+       struct seq_oss_readq *readq;
+       int dev;
+};
+
+static int readq_dump_sysex(void *ptr, void *buf, int count)
+{
+       struct readq_sysex_ctx *ctx = ptr;
+
+       return snd_seq_oss_readq_puts(ctx->readq, ctx->dev, buf, count);
+}
+
+int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,
+                           struct snd_seq_event *ev)
+{
+       struct readq_sysex_ctx ctx = {
+               .readq = q,
+               .dev = dev
+       };
+
+       if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
+               return 0;
+       return snd_seq_dump_var_event(ev, readq_dump_sysex, &ctx);
+}
+
 /*
  * copy an event to input queue:
  * return zero if enqueued
index f1463f1..8d033ca 100644 (file)
@@ -44,6 +44,8 @@ void snd_seq_oss_readq_delete(struct seq_oss_readq *q);
 void snd_seq_oss_readq_clear(struct seq_oss_readq *readq);
 unsigned int snd_seq_oss_readq_poll(struct seq_oss_readq *readq, struct file *file, poll_table *wait);
 int snd_seq_oss_readq_puts(struct seq_oss_readq *readq, int dev, unsigned char *data, int len);
+int snd_seq_oss_readq_sysex(struct seq_oss_readq *q, int dev,
+                           struct snd_seq_event *ev);
 int snd_seq_oss_readq_put_event(struct seq_oss_readq *readq, union evrec *ev);
 int snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *readq, unsigned long curt, int seq_mode);
 int snd_seq_oss_readq_pick(struct seq_oss_readq *q, union evrec *rec);
index d449dde..08d5003 100644 (file)
@@ -236,6 +236,7 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
        rwlock_init(&client->ports_lock);
        mutex_init(&client->ports_mutex);
        INIT_LIST_HEAD(&client->ports_list_head);
+       mutex_init(&client->ioctl_mutex);
 
        /* find free slot in the client table */
        spin_lock_irqsave(&clients_lock, flags);
@@ -269,12 +270,12 @@ static int seq_free_client1(struct snd_seq_client *client)
 
        if (!client)
                return 0;
-       snd_seq_delete_all_ports(client);
-       snd_seq_queue_client_leave(client->number);
        spin_lock_irqsave(&clients_lock, flags);
        clienttablock[client->number] = 1;
        clienttab[client->number] = NULL;
        spin_unlock_irqrestore(&clients_lock, flags);
+       snd_seq_delete_all_ports(client);
+       snd_seq_queue_client_leave(client->number);
        snd_use_lock_sync(&client->use_lock);
        snd_seq_queue_client_termination(client->number);
        if (client->pool)
@@ -676,7 +677,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
        if (atomic)
                read_lock(&grp->list_lock);
        else
-               down_read(&grp->list_mutex);
+               down_read_nested(&grp->list_mutex, hop);
        list_for_each_entry(subs, &grp->list_head, src_list) {
                /* both ports ready? */
                if (atomic_read(&subs->ref_count) != 2)
@@ -906,7 +907,8 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)
 static int snd_seq_client_enqueue_event(struct snd_seq_client *client,
                                        struct snd_seq_event *event,
                                        struct file *file, int blocking,
-                                       int atomic, int hop)
+                                       int atomic, int hop,
+                                       struct mutex *mutexp)
 {
        struct snd_seq_event_cell *cell;
        int err;
@@ -944,7 +946,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client,
                return -ENXIO; /* queue is not allocated */
 
        /* allocate an event cell */
-       err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, file);
+       err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic,
+                               file, mutexp);
        if (err < 0)
                return err;
 
@@ -999,7 +1002,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
 {
        struct snd_seq_client *client = file->private_data;
        int written = 0, len;
-       int err = -EINVAL;
+       int err;
        struct snd_seq_event event;
 
        if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
@@ -1013,12 +1016,15 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
                return -ENXIO;
 
        /* allocate the pool now if the pool is not allocated yet */ 
+       mutex_lock(&client->ioctl_mutex);
        if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) {
-               if (snd_seq_pool_init(client->pool) < 0)
-                       return -ENOMEM;
+               err = snd_seq_pool_init(client->pool);
+               if (err < 0)
+                       goto out;
        }
 
        /* only process whole events */
+       err = -EINVAL;
        while (count >= sizeof(struct snd_seq_event)) {
                /* Read in the event header from the user */
                len = sizeof(event);
@@ -1065,7 +1071,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
                /* ok, enqueue it */
                err = snd_seq_client_enqueue_event(client, &event, file,
                                                   !(file->f_flags & O_NONBLOCK),
-                                                  0, 0);
+                                                  0, 0, &client->ioctl_mutex);
                if (err < 0)
                        break;
 
@@ -1076,6 +1082,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
                written += len;
        }
 
+ out:
+       mutex_unlock(&client->ioctl_mutex);
        return written ? written : err;
 }
 
@@ -1248,6 +1256,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client,
        struct snd_seq_client_port *port;
        struct snd_seq_port_info info;
        struct snd_seq_port_callback *callback;
+       int port_idx;
 
        if (copy_from_user(&info, arg, sizeof(info)))
                return -EFAULT;
@@ -1261,7 +1270,9 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client,
                return -ENOMEM;
 
        if (client->type == USER_CLIENT && info.kernel) {
-               snd_seq_delete_port(client, port->addr.port);
+               port_idx = port->addr.port;
+               snd_seq_port_unlock(port);
+               snd_seq_delete_port(client, port_idx);
                return -EINVAL;
        }
        if (client->type == KERNEL_CLIENT) {
@@ -1283,6 +1294,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client,
 
        snd_seq_set_port_info(port, &info);
        snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
+       snd_seq_port_unlock(port);
 
        if (copy_to_user(arg, &info, sizeof(info)))
                return -EFAULT;
@@ -1908,6 +1920,9 @@ static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client,
            (! snd_seq_write_pool_allocated(client) ||
             info.output_pool != client->pool->size)) {
                if (snd_seq_write_pool_allocated(client)) {
+                       /* is the pool in use? */
+                       if (atomic_read(&client->pool->counter))
+                               return -EBUSY;
                        /* remove all existing cells */
                        snd_seq_pool_mark_closing(client->pool);
                        snd_seq_queue_client_leave_cells(client->number);
@@ -2209,11 +2224,15 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
 static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct snd_seq_client *client = file->private_data;
+       long ret;
 
        if (snd_BUG_ON(!client))
                return -ENXIO;
                
-       return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
+       mutex_lock(&client->ioctl_mutex);
+       ret = snd_seq_do_ioctl(client, cmd, (void __user *) arg);
+       mutex_unlock(&client->ioctl_mutex);
+       return ret;
 }
 
 #ifdef CONFIG_COMPAT
@@ -2327,7 +2346,8 @@ static int kernel_client_enqueue(int client, struct snd_seq_event *ev,
        if (! cptr->accept_output)
                result = -EPERM;
        else /* send it */
-               result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, atomic, hop);
+               result = snd_seq_client_enqueue_event(cptr, ev, file, blocking,
+                                                     atomic, hop, NULL);
 
        snd_seq_client_unlock(cptr);
        return result;
index 20f0a72..91f8f16 100644 (file)
@@ -59,6 +59,7 @@ struct snd_seq_client {
        struct list_head ports_list_head;
        rwlock_t ports_lock;
        struct mutex ports_mutex;
+       struct mutex ioctl_mutex;
        int convert32;          /* convert 32->64bit */
 
        /* output pool */
index 490b697..9d429bc 100644 (file)
@@ -125,9 +125,9 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
                return -EINVAL;
 
        snd_use_lock_use(&f->use_lock);
-       err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */
+       err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */
        if (err < 0) {
-               if (err == -ENOMEM)
+               if ((err == -ENOMEM) || (err == -EAGAIN))
                        atomic_inc(&f->overflow);
                snd_use_lock_free(&f->use_lock);
                return err;
index 8a6b7ba..d8405d3 100644 (file)
@@ -23,8 +23,6 @@
 #include <sound/core.h>
 #include "seq_lock.h"
 
-#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
-
 /* wait until all locks are released */
 void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
 {
@@ -42,5 +40,3 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
 }
 
 EXPORT_SYMBOL(snd_use_lock_sync_helper);
-
-#endif
index 54044bc..ac38031 100644 (file)
@@ -3,8 +3,6 @@
 
 #include <linux/sched.h>
 
-#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
-
 typedef atomic_t snd_use_lock_t;
 
 /* initialize lock */
@@ -20,14 +18,4 @@ typedef atomic_t snd_use_lock_t;
 void snd_use_lock_sync_helper(snd_use_lock_t *lock, const char *file, int line);
 #define snd_use_lock_sync(lockp) snd_use_lock_sync_helper(lockp, __BASE_FILE__, __LINE__)
 
-#else /* SMP || CONFIG_SND_DEBUG */
-
-typedef spinlock_t snd_use_lock_t;     /* dummy */
-#define snd_use_lock_init(lockp) /**/
-#define snd_use_lock_use(lockp) /**/
-#define snd_use_lock_free(lockp) /**/
-#define snd_use_lock_sync(lockp) /**/
-
-#endif /* SMP || CONFIG_SND_DEBUG */
-
 #endif /* __SND_SEQ_LOCK_H */
index 6fc211d..ce5d003 100644 (file)
@@ -221,7 +221,8 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)
  */
 static int snd_seq_cell_alloc(struct snd_seq_pool *pool,
                              struct snd_seq_event_cell **cellp,
-                             int nonblock, struct file *file)
+                             int nonblock, struct file *file,
+                             struct mutex *mutexp)
 {
        struct snd_seq_event_cell *cell;
        unsigned long flags;
@@ -245,7 +246,11 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool,
                set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&pool->output_sleep, &wait);
                spin_unlock_irq(&pool->lock);
+               if (mutexp)
+                       mutex_unlock(mutexp);
                schedule();
+               if (mutexp)
+                       mutex_lock(mutexp);
                spin_lock_irq(&pool->lock);
                remove_wait_queue(&pool->output_sleep, &wait);
                /* interrupted? */
@@ -288,7 +293,7 @@ __error:
  */
 int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
                      struct snd_seq_event_cell **cellp, int nonblock,
-                     struct file *file)
+                     struct file *file, struct mutex *mutexp)
 {
        int ncells, err;
        unsigned int extlen;
@@ -305,7 +310,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
        if (ncells >= pool->total_elements)
                return -ENOMEM;
 
-       err = snd_seq_cell_alloc(pool, &cell, nonblock, file);
+       err = snd_seq_cell_alloc(pool, &cell, nonblock, file, mutexp);
        if (err < 0)
                return err;
 
@@ -331,7 +336,8 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
                        int size = sizeof(struct snd_seq_event);
                        if (len < size)
                                size = len;
-                       err = snd_seq_cell_alloc(pool, &tmp, nonblock, file);
+                       err = snd_seq_cell_alloc(pool, &tmp, nonblock, file,
+                                                mutexp);
                        if (err < 0)
                                goto __error;
                        if (cell->event.data.ext.ptr == NULL)
index 32f959c..3abe306 100644 (file)
@@ -66,7 +66,8 @@ struct snd_seq_pool {
 void snd_seq_cell_free(struct snd_seq_event_cell *cell);
 
 int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
-                     struct snd_seq_event_cell **cellp, int nonblock, struct file *file);
+                     struct snd_seq_event_cell **cellp, int nonblock,
+                     struct file *file, struct mutex *mutexp);
 
 /* return number of unused (free) cells */
 static inline int snd_seq_unused_cells(struct snd_seq_pool *pool)
index ee0522a..a28d1ac 100644 (file)
@@ -122,7 +122,9 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
 }
 
 
-/* create a port, port number is returned (-1 on failure) */
+/* create a port, port number is returned (-1 on failure);
+ * the caller needs to unref the port via snd_seq_port_unlock() appropriately
+ */
 struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
                                                int port)
 {
@@ -153,6 +155,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
        snd_use_lock_init(&new_port->use_lock);
        port_subs_info_init(&new_port->c_src);
        port_subs_info_init(&new_port->c_dest);
+       snd_use_lock_use(&new_port->use_lock);
 
        num = port >= 0 ? port : 0;
        mutex_lock(&client->ports_mutex);
@@ -167,9 +170,9 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
        list_add_tail(&new_port->list, &p->list);
        client->num_ports++;
        new_port->addr.port = num;      /* store the port number in the port */
+       sprintf(new_port->name, "port-%d", num);
        write_unlock_irqrestore(&client->ports_lock, flags);
        mutex_unlock(&client->ports_mutex);
-       sprintf(new_port->name, "port-%d", num);
 
        return new_port;
 }
index 29896ab..15c5d67 100644 (file)
@@ -89,7 +89,7 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo)
        if (f->cells > 0) {
                /* drain prioQ */
                while (f->cells > 0)
-                       snd_seq_cell_free(snd_seq_prioq_cell_out(f));
+                       snd_seq_cell_free(snd_seq_prioq_cell_out(f, NULL));
        }
        
        kfree(f);
@@ -216,8 +216,18 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
        return 0;
 }
 
+/* return 1 if the current time >= event timestamp */
+static int event_is_ready(struct snd_seq_event *ev, void *current_time)
+{
+       if ((ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK)
+               return snd_seq_compare_tick_time(current_time, &ev->time.tick);
+       else
+               return snd_seq_compare_real_time(current_time, &ev->time.time);
+}
+
 /* dequeue cell from prioq */
-struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
+struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
+                                                 void *current_time)
 {
        struct snd_seq_event_cell *cell;
        unsigned long flags;
@@ -229,6 +239,8 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
        spin_lock_irqsave(&f->lock, flags);
 
        cell = f->head;
+       if (cell && current_time && !event_is_ready(&cell->event, current_time))
+               cell = NULL;
        if (cell) {
                f->head = cell->next;
 
@@ -255,17 +267,6 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
 }
 
 
-/* peek at cell at the head of the prioq */
-struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq * f)
-{
-       if (f == NULL) {
-               snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
-               return NULL;
-       }
-       return f->head;
-}
-
-
 static inline int prioq_match(struct snd_seq_event_cell *cell,
                              int client, int timestamp)
 {
index d38bb78..2c315ca 100644 (file)
@@ -44,14 +44,12 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo);
 int snd_seq_prioq_cell_in(struct snd_seq_prioq *f, struct snd_seq_event_cell *cell);
 
 /* dequeue cell from prioq */ 
-struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f);
+struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
+                                                 void *current_time);
 
 /* return number of events available in prioq */
 int snd_seq_prioq_avail(struct snd_seq_prioq *f);
 
-/* peek at cell at the head of the prioq */
-struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq *f);
-
 /* client left queue */
 void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp);        
 
index 17fe04d..cfe942c 100644 (file)
@@ -275,30 +275,20 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
 
       __again:
        /* Process tick queue... */
-       while ((cell = snd_seq_prioq_cell_peek(q->tickq)) != NULL) {
-               if (snd_seq_compare_tick_time(&q->timer->tick.cur_tick,
-                                             &cell->event.time.tick)) {
-                       cell = snd_seq_prioq_cell_out(q->tickq);
-                       if (cell)
-                               snd_seq_dispatch_event(cell, atomic, hop);
-               } else {
-                       /* event remains in the queue */
+       for (;;) {
+               cell = snd_seq_prioq_cell_out(q->tickq,
+                                             &q->timer->tick.cur_tick);
+               if (!cell)
                        break;
-               }
+               snd_seq_dispatch_event(cell, atomic, hop);
        }
 
-
        /* Process time queue... */
-       while ((cell = snd_seq_prioq_cell_peek(q->timeq)) != NULL) {
-               if (snd_seq_compare_real_time(&q->timer->cur_time,
-                                             &cell->event.time.time)) {
-                       cell = snd_seq_prioq_cell_out(q->timeq);
-                       if (cell)
-                               snd_seq_dispatch_event(cell, atomic, hop);
-               } else {
-                       /* event remains in the queue */
+       for (;;) {
+               cell = snd_seq_prioq_cell_out(q->timeq, &q->timer->cur_time);
+               if (!cell)
                        break;
-               }
+               snd_seq_dispatch_event(cell, atomic, hop);
        }
 
        /* free lock */
index 6ec30a9..755cf45 100644 (file)
@@ -357,7 +357,7 @@ static int initialize_timer(struct snd_seq_timer *tmr)
        unsigned long freq;
 
        t = tmr->timeri->timer;
-       if (snd_BUG_ON(!t))
+       if (!t)
                return -EINVAL;
 
        freq = tmr->preferred_resolution;
index 6b38e7c..c90464d 100644 (file)
@@ -77,13 +77,17 @@ static void snd_virmidi_init_event(struct snd_virmidi *vmidi,
  * decode input event and put to read buffer of each opened file
  */
 static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
-                                        struct snd_seq_event *ev)
+                                        struct snd_seq_event *ev,
+                                        bool atomic)
 {
        struct snd_virmidi *vmidi;
        unsigned char msg[4];
        int len;
 
-       read_lock(&rdev->filelist_lock);
+       if (atomic)
+               read_lock(&rdev->filelist_lock);
+       else
+               down_read(&rdev->filelist_sem);
        list_for_each_entry(vmidi, &rdev->filelist, list) {
                if (!vmidi->trigger)
                        continue;
@@ -97,7 +101,10 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
                                snd_rawmidi_receive(vmidi->substream, msg, len);
                }
        }
-       read_unlock(&rdev->filelist_lock);
+       if (atomic)
+               read_unlock(&rdev->filelist_lock);
+       else
+               up_read(&rdev->filelist_sem);
 
        return 0;
 }
@@ -115,7 +122,7 @@ int snd_virmidi_receive(struct snd_rawmidi *rmidi, struct snd_seq_event *ev)
        struct snd_virmidi_dev *rdev;
 
        rdev = rmidi->private_data;
-       return snd_virmidi_dev_receive_event(rdev, ev);
+       return snd_virmidi_dev_receive_event(rdev, ev, true);
 }
 #endif  /*  0  */
 
@@ -130,7 +137,7 @@ static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct,
        rdev = private_data;
        if (!(rdev->flags & SNDRV_VIRMIDI_USE))
                return 0; /* ignored */
-       return snd_virmidi_dev_receive_event(rdev, ev);
+       return snd_virmidi_dev_receive_event(rdev, ev, atomic);
 }
 
 /*
@@ -209,7 +216,6 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
        struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
        struct snd_rawmidi_runtime *runtime = substream->runtime;
        struct snd_virmidi *vmidi;
-       unsigned long flags;
 
        vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL);
        if (vmidi == NULL)
@@ -223,9 +229,11 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
        vmidi->client = rdev->client;
        vmidi->port = rdev->port;       
        runtime->private_data = vmidi;
-       write_lock_irqsave(&rdev->filelist_lock, flags);
+       down_write(&rdev->filelist_sem);
+       write_lock_irq(&rdev->filelist_lock);
        list_add_tail(&vmidi->list, &rdev->filelist);
-       write_unlock_irqrestore(&rdev->filelist_lock, flags);
+       write_unlock_irq(&rdev->filelist_lock);
+       up_write(&rdev->filelist_sem);
        vmidi->rdev = rdev;
        return 0;
 }
@@ -264,9 +272,11 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
        struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
        struct snd_virmidi *vmidi = substream->runtime->private_data;
 
+       down_write(&rdev->filelist_sem);
        write_lock_irq(&rdev->filelist_lock);
        list_del(&vmidi->list);
        write_unlock_irq(&rdev->filelist_lock);
+       up_write(&rdev->filelist_sem);
        snd_midi_event_free(vmidi->parser);
        substream->runtime->private_data = NULL;
        kfree(vmidi);
@@ -520,6 +530,7 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi
        rdev->rmidi = rmidi;
        rdev->device = device;
        rdev->client = -1;
+       init_rwsem(&rdev->filelist_sem);
        rwlock_init(&rdev->filelist_lock);
        INIT_LIST_HEAD(&rdev->filelist);
        rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH;
index 7754a37..69c801a 100644 (file)
@@ -179,7 +179,7 @@ static void snd_timer_request(struct snd_timer_id *tid)
  *
  * call this with register_mutex down.
  */
-static void snd_timer_check_slave(struct snd_timer_instance *slave)
+static int snd_timer_check_slave(struct snd_timer_instance *slave)
 {
        struct snd_timer *timer;
        struct snd_timer_instance *master;
@@ -189,16 +189,21 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
                list_for_each_entry(master, &timer->open_list_head, open_list) {
                        if (slave->slave_class == master->slave_class &&
                            slave->slave_id == master->slave_id) {
+                               if (master->timer->num_instances >=
+                                   master->timer->max_instances)
+                                       return -EBUSY;
                                list_move_tail(&slave->open_list,
                                               &master->slave_list_head);
+                               master->timer->num_instances++;
                                spin_lock_irq(&slave_active_lock);
                                slave->master = master;
                                slave->timer = master->timer;
                                spin_unlock_irq(&slave_active_lock);
-                               return;
+                               return 0;
                        }
                }
        }
+       return 0;
 }
 
 /*
@@ -207,7 +212,7 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave)
  *
  * call this with register_mutex down.
  */
-static void snd_timer_check_master(struct snd_timer_instance *master)
+static int snd_timer_check_master(struct snd_timer_instance *master)
 {
        struct snd_timer_instance *slave, *tmp;
 
@@ -215,7 +220,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master)
        list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
                if (slave->slave_class == master->slave_class &&
                    slave->slave_id == master->slave_id) {
+                       if (master->timer->num_instances >=
+                           master->timer->max_instances)
+                               return -EBUSY;
                        list_move_tail(&slave->open_list, &master->slave_list_head);
+                       master->timer->num_instances++;
                        spin_lock_irq(&slave_active_lock);
                        spin_lock(&master->timer->lock);
                        slave->master = master;
@@ -227,8 +236,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master)
                        spin_unlock_irq(&slave_active_lock);
                }
        }
+       return 0;
 }
 
+static int snd_timer_close_locked(struct snd_timer_instance *timeri);
+
 /*
  * open a timer instance
  * when opening a master, the slave id must be here given.
@@ -239,6 +251,7 @@ int snd_timer_open(struct snd_timer_instance **ti,
 {
        struct snd_timer *timer;
        struct snd_timer_instance *timeri = NULL;
+       int err;
 
        if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
                /* open a slave instance */
@@ -257,10 +270,14 @@ int snd_timer_open(struct snd_timer_instance **ti,
                timeri->slave_id = tid->device;
                timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
                list_add_tail(&timeri->open_list, &snd_timer_slave_list);
-               snd_timer_check_slave(timeri);
+               err = snd_timer_check_slave(timeri);
+               if (err < 0) {
+                       snd_timer_close_locked(timeri);
+                       timeri = NULL;
+               }
                mutex_unlock(&register_mutex);
                *ti = timeri;
-               return 0;
+               return err;
        }
 
        /* open a master instance */
@@ -286,6 +303,10 @@ int snd_timer_open(struct snd_timer_instance **ti,
                        return -EBUSY;
                }
        }
+       if (timer->num_instances >= timer->max_instances) {
+               mutex_unlock(&register_mutex);
+               return -EBUSY;
+       }
        timeri = snd_timer_instance_new(owner, timer);
        if (!timeri) {
                mutex_unlock(&register_mutex);
@@ -307,44 +328,36 @@ int snd_timer_open(struct snd_timer_instance **ti,
        }
 
        list_add_tail(&timeri->open_list, &timer->open_list_head);
-       snd_timer_check_master(timeri);
+       timer->num_instances++;
+       err = snd_timer_check_master(timeri);
+       if (err < 0) {
+               snd_timer_close_locked(timeri);
+               timeri = NULL;
+       }
        mutex_unlock(&register_mutex);
        *ti = timeri;
-       return 0;
+       return err;
 }
 
 static int _snd_timer_stop(struct snd_timer_instance *timeri, int event);
 
 /*
  * close a timer instance
+ * call this with register_mutex down.
  */
-int snd_timer_close(struct snd_timer_instance *timeri)
+static int snd_timer_close_locked(struct snd_timer_instance *timeri)
 {
        struct snd_timer *timer = NULL;
        struct snd_timer_instance *slave, *tmp;
 
-       if (snd_BUG_ON(!timeri))
-               return -ENXIO;
+       list_del(&timeri->open_list);
 
        /* force to stop the timer */
        snd_timer_stop(timeri);
 
-       if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
-               /* wait, until the active callback is finished */
-               spin_lock_irq(&slave_active_lock);
-               while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
-                       spin_unlock_irq(&slave_active_lock);
-                       udelay(10);
-                       spin_lock_irq(&slave_active_lock);
-               }
-               spin_unlock_irq(&slave_active_lock);
-               mutex_lock(&register_mutex);
-               list_del(&timeri->open_list);
-               mutex_unlock(&register_mutex);
-       } else {
-               timer = timeri->timer;
-               if (snd_BUG_ON(!timer))
-                       goto out;
+       timer = timeri->timer;
+       if (timer) {
+               timer->num_instances--;
                /* wait, until the active callback is finished */
                spin_lock_irq(&timer->lock);
                while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
@@ -353,17 +366,14 @@ int snd_timer_close(struct snd_timer_instance *timeri)
                        spin_lock_irq(&timer->lock);
                }
                spin_unlock_irq(&timer->lock);
-               mutex_lock(&register_mutex);
-               list_del(&timeri->open_list);
-               if (list_empty(&timer->open_list_head) &&
-                   timer->hw.close)
-                       timer->hw.close(timer);
+
                /* remove slave links */
                spin_lock_irq(&slave_active_lock);
                spin_lock(&timer->lock);
                list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
                                         open_list) {
                        list_move_tail(&slave->open_list, &snd_timer_slave_list);
+                       timer->num_instances--;
                        slave->master = NULL;
                        slave->timer = NULL;
                        list_del_init(&slave->ack_list);
@@ -371,18 +381,42 @@ int snd_timer_close(struct snd_timer_instance *timeri)
                }
                spin_unlock(&timer->lock);
                spin_unlock_irq(&slave_active_lock);
-               mutex_unlock(&register_mutex);
+
+               /* slave doesn't need to release timer resources below */
+               if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
+                       timer = NULL;
        }
- out:
+
        if (timeri->private_free)
                timeri->private_free(timeri);
        kfree(timeri->owner);
        kfree(timeri);
-       if (timer)
+
+       if (timer) {
+               if (list_empty(&timer->open_list_head) && timer->hw.close)
+                       timer->hw.close(timer);
                module_put(timer->module);
+       }
+
        return 0;
 }
 
+/*
+ * close a timer instance
+ */
+int snd_timer_close(struct snd_timer_instance *timeri)
+{
+       int err;
+
+       if (snd_BUG_ON(!timeri))
+               return -ENXIO;
+
+       mutex_lock(&register_mutex);
+       err = snd_timer_close_locked(timeri);
+       mutex_unlock(&register_mutex);
+       return err;
+}
+
 unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
 {
        struct snd_timer * timer;
@@ -847,6 +881,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
        spin_lock_init(&timer->lock);
        tasklet_init(&timer->task_queue, snd_timer_tasklet,
                     (unsigned long)timer);
+       timer->max_instances = 1000; /* default limit per timer */
        if (card != NULL) {
                timer->module = card->module;
                err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops);
index 8e7eddf..80343b9 100644 (file)
@@ -40,11 +40,11 @@ static int snd_timer_user_info_compat(struct file *file,
        struct snd_timer *t;
 
        tu = file->private_data;
-       if (snd_BUG_ON(!tu->timeri))
-               return -ENXIO;
+       if (!tu->timeri)
+               return -EBADFD;
        t = tu->timeri->timer;
-       if (snd_BUG_ON(!t))
-               return -ENXIO;
+       if (!t)
+               return -EBADFD;
        memset(&info, 0, sizeof(info));
        info.card = t->card ? t->card->number : -1;
        if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
@@ -73,8 +73,8 @@ static int snd_timer_user_status_compat(struct file *file,
        struct snd_timer_status32 status;
        
        tu = file->private_data;
-       if (snd_BUG_ON(!tu->timeri))
-               return -ENXIO;
+       if (!tu->timeri)
+               return -EBADFD;
        memset(&status, 0, sizeof(status));
        status.tstamp.tv_sec = tu->tstamp.tv_sec;
        status.tstamp.tv_nsec = tu->tstamp.tv_nsec;
@@ -97,7 +97,8 @@ enum {
        SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32),
 };
 
-static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
+                                         unsigned long arg)
 {
        void __user *argp = compat_ptr(arg);
 
@@ -118,7 +119,7 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns
        case SNDRV_TIMER_IOCTL_PAUSE:
        case SNDRV_TIMER_IOCTL_PAUSE_OLD:
        case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
-               return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
+               return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
        case SNDRV_TIMER_IOCTL_INFO32:
                return snd_timer_user_info_compat(file, argp);
        case SNDRV_TIMER_IOCTL_STATUS32:
@@ -126,3 +127,15 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns
        }
        return -ENOIOCTLCMD;
 }
+
+static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
+                                       unsigned long arg)
+{
+       struct snd_timer_user *tu = file->private_data;
+       long ret;
+
+       mutex_lock(&tu->ioctl_lock);
+       ret = __snd_timer_user_ioctl_compat(file, cmd, arg);
+       mutex_unlock(&tu->ioctl_lock);
+       return ret;
+}
index 42b876d..4e01b02 100644 (file)
@@ -39,6 +39,7 @@
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/info.h>
 #include <sound/initval.h>
 
@@ -194,6 +195,11 @@ static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
        spin_unlock(&dpcm->timer_lock);
 }
 
+static inline void loopback_timer_stop_sync(struct loopback_pcm *dpcm)
+{
+       del_timer_sync(&dpcm->timer);
+}
+
 #define CABLE_VALID_PLAYBACK   (1 << SNDRV_PCM_STREAM_PLAYBACK)
 #define CABLE_VALID_CAPTURE    (1 << SNDRV_PCM_STREAM_CAPTURE)
 #define CABLE_VALID_BOTH       (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE)
@@ -307,19 +313,6 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
        return 0;
 }
 
-static void params_change_substream(struct loopback_pcm *dpcm,
-                                   struct snd_pcm_runtime *runtime)
-{
-       struct snd_pcm_runtime *dst_runtime;
-
-       if (dpcm == NULL || dpcm->substream == NULL)
-               return;
-       dst_runtime = dpcm->substream->runtime;
-       if (dst_runtime == NULL)
-               return;
-       dst_runtime->hw = dpcm->cable->hw;
-}
-
 static void params_change(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
@@ -331,10 +324,6 @@ static void params_change(struct snd_pcm_substream *substream)
        cable->hw.rate_max = runtime->rate;
        cable->hw.channels_min = runtime->channels;
        cable->hw.channels_max = runtime->channels;
-       params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
-                               runtime);
-       params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE],
-                               runtime);
 }
 
 static int loopback_prepare(struct snd_pcm_substream *substream)
@@ -344,6 +333,8 @@ static int loopback_prepare(struct snd_pcm_substream *substream)
        struct loopback_cable *cable = dpcm->cable;
        int bps, salign;
 
+       loopback_timer_stop_sync(dpcm);
+
        salign = (snd_pcm_format_width(runtime->format) *
                                                runtime->channels) / 8;
        bps = salign * runtime->rate;
@@ -610,26 +601,29 @@ static unsigned int get_cable_index(struct snd_pcm_substream *substream)
 static int rule_format(struct snd_pcm_hw_params *params,
                       struct snd_pcm_hw_rule *rule)
 {
+       struct loopback_pcm *dpcm = rule->private;
+       struct loopback_cable *cable = dpcm->cable;
+       struct snd_mask m;
 
-       struct snd_pcm_hardware *hw = rule->private;
-       struct snd_mask *maskp = hw_param_mask(params, rule->var);
-
-       maskp->bits[0] &= (u_int32_t)hw->formats;
-       maskp->bits[1] &= (u_int32_t)(hw->formats >> 32);
-       memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
-       if (! maskp->bits[0] && ! maskp->bits[1])
-               return -EINVAL;
-       return 0;
+       snd_mask_none(&m);
+       mutex_lock(&dpcm->loopback->cable_lock);
+       m.bits[0] = (u_int32_t)cable->hw.formats;
+       m.bits[1] = (u_int32_t)(cable->hw.formats >> 32);
+       mutex_unlock(&dpcm->loopback->cable_lock);
+       return snd_mask_refine(hw_param_mask(params, rule->var), &m);
 }
 
 static int rule_rate(struct snd_pcm_hw_params *params,
                     struct snd_pcm_hw_rule *rule)
 {
-       struct snd_pcm_hardware *hw = rule->private;
+       struct loopback_pcm *dpcm = rule->private;
+       struct loopback_cable *cable = dpcm->cable;
        struct snd_interval t;
 
-        t.min = hw->rate_min;
-        t.max = hw->rate_max;
+       mutex_lock(&dpcm->loopback->cable_lock);
+       t.min = cable->hw.rate_min;
+       t.max = cable->hw.rate_max;
+       mutex_unlock(&dpcm->loopback->cable_lock);
         t.openmin = t.openmax = 0;
         t.integer = 0;
        return snd_interval_refine(hw_param_interval(params, rule->var), &t);
@@ -638,22 +632,46 @@ static int rule_rate(struct snd_pcm_hw_params *params,
 static int rule_channels(struct snd_pcm_hw_params *params,
                         struct snd_pcm_hw_rule *rule)
 {
-       struct snd_pcm_hardware *hw = rule->private;
+       struct loopback_pcm *dpcm = rule->private;
+       struct loopback_cable *cable = dpcm->cable;
        struct snd_interval t;
 
-        t.min = hw->channels_min;
-        t.max = hw->channels_max;
+       mutex_lock(&dpcm->loopback->cable_lock);
+       t.min = cable->hw.channels_min;
+       t.max = cable->hw.channels_max;
+       mutex_unlock(&dpcm->loopback->cable_lock);
         t.openmin = t.openmax = 0;
         t.integer = 0;
        return snd_interval_refine(hw_param_interval(params, rule->var), &t);
 }
 
+static void free_cable(struct snd_pcm_substream *substream)
+{
+       struct loopback *loopback = substream->private_data;
+       int dev = get_cable_index(substream);
+       struct loopback_cable *cable;
+
+       cable = loopback->cables[substream->number][dev];
+       if (!cable)
+               return;
+       if (cable->streams[!substream->stream]) {
+               /* other stream is still alive */
+               spin_lock_irq(&cable->lock);
+               cable->streams[substream->stream] = NULL;
+               spin_unlock_irq(&cable->lock);
+       } else {
+               /* free the cable */
+               loopback->cables[substream->number][dev] = NULL;
+               kfree(cable);
+       }
+}
+
 static int loopback_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct loopback *loopback = substream->private_data;
        struct loopback_pcm *dpcm;
-       struct loopback_cable *cable;
+       struct loopback_cable *cable = NULL;
        int err = 0;
        int dev = get_cable_index(substream);
 
@@ -673,7 +691,6 @@ static int loopback_open(struct snd_pcm_substream *substream)
        if (!cable) {
                cable = kzalloc(sizeof(*cable), GFP_KERNEL);
                if (!cable) {
-                       kfree(dpcm);
                        err = -ENOMEM;
                        goto unlock;
                }
@@ -682,7 +699,6 @@ static int loopback_open(struct snd_pcm_substream *substream)
                loopback->cables[substream->number][dev] = cable;
        }
        dpcm->cable = cable;
-       cable->streams[substream->stream] = dpcm;
 
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
 
@@ -691,19 +707,19 @@ static int loopback_open(struct snd_pcm_substream *substream)
        /* are cached -> they do not reflect the actual state */
        err = snd_pcm_hw_rule_add(runtime, 0,
                                  SNDRV_PCM_HW_PARAM_FORMAT,
-                                 rule_format, &runtime->hw,
+                                 rule_format, dpcm,
                                  SNDRV_PCM_HW_PARAM_FORMAT, -1);
        if (err < 0)
                goto unlock;
        err = snd_pcm_hw_rule_add(runtime, 0,
                                  SNDRV_PCM_HW_PARAM_RATE,
-                                 rule_rate, &runtime->hw,
+                                 rule_rate, dpcm,
                                  SNDRV_PCM_HW_PARAM_RATE, -1);
        if (err < 0)
                goto unlock;
        err = snd_pcm_hw_rule_add(runtime, 0,
                                  SNDRV_PCM_HW_PARAM_CHANNELS,
-                                 rule_channels, &runtime->hw,
+                                 rule_channels, dpcm,
                                  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
        if (err < 0)
                goto unlock;
@@ -714,7 +730,16 @@ static int loopback_open(struct snd_pcm_substream *substream)
                runtime->hw = loopback_pcm_hardware;
        else
                runtime->hw = cable->hw;
+
+       spin_lock_irq(&cable->lock);
+       cable->streams[substream->stream] = dpcm;
+       spin_unlock_irq(&cable->lock);
+
  unlock:
+       if (err < 0) {
+               free_cable(substream);
+               kfree(dpcm);
+       }
        mutex_unlock(&loopback->cable_lock);
        return err;
 }
@@ -723,20 +748,10 @@ static int loopback_close(struct snd_pcm_substream *substream)
 {
        struct loopback *loopback = substream->private_data;
        struct loopback_pcm *dpcm = substream->runtime->private_data;
-       struct loopback_cable *cable;
-       int dev = get_cable_index(substream);
 
-       loopback_timer_stop(dpcm);
+       loopback_timer_stop_sync(dpcm);
        mutex_lock(&loopback->cable_lock);
-       cable = loopback->cables[substream->number][dev];
-       if (cable->streams[!substream->stream]) {
-               /* other stream is still alive */
-               cable->streams[substream->stream] = NULL;
-       } else {
-               /* free the cable */
-               loopback->cables[substream->number][dev] = NULL;
-               kfree(cable);
-       }
+       free_cable(substream);
        mutex_unlock(&loopback->cable_lock);
        return 0;
 }
index 1da4738..fbfdbe4 100644 (file)
@@ -3045,6 +3045,9 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        /* AMD Hudson */
        { PCI_DEVICE(0x1022, 0x780d),
          .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
+       /* AMD Raven */
+       { PCI_DEVICE(0x1022, 0x15e3),
+         .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
        /* ATI HDMI */
        { PCI_DEVICE(0x1002, 0x793b),
          .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
index de51abc..81ac4c1 100644 (file)
@@ -4498,6 +4498,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
        {}
 };
index 726bd65..d79aa7c 100644 (file)
@@ -91,8 +91,8 @@ static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97,
        do {
                mutex_lock(&ctx->lock);
 
-               tmo = 5;
-               while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
+               tmo = 6;
+               while ((RD(ctx, AC97_STATUS) & STAT_CP) && --tmo)
                        udelay(21);     /* wait an ac97 frame time */
                if (!tmo) {
                        pr_debug("ac97rd timeout #1\n");
@@ -105,7 +105,7 @@ static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97,
                 * poll, Forrest, poll...
                 */
                tmo = 0x10000;
-               while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
+               while ((RD(ctx, AC97_STATUS) & STAT_CP) && --tmo)
                        asm volatile ("nop");
                data = RD(ctx, AC97_CMDRESP);
 
index 45c6302..396f356 100644 (file)
@@ -133,6 +133,8 @@ struct adau1373 {
 #define ADAU1373_DAI_FORMAT_DSP                0x3
 
 #define ADAU1373_BCLKDIV_SOURCE                BIT(5)
+#define ADAU1373_BCLKDIV_SR_MASK       (0x07 << 2)
+#define ADAU1373_BCLKDIV_BCLK_MASK     0x03
 #define ADAU1373_BCLKDIV_32            0x03
 #define ADAU1373_BCLKDIV_64            0x02
 #define ADAU1373_BCLKDIV_128           0x01
@@ -937,7 +939,8 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream,
        adau1373_dai->enable_src = (div != 0);
 
        snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id),
-               ~ADAU1373_BCLKDIV_SOURCE, (div << 2) | ADAU1373_BCLKDIV_64);
+               ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK,
+               (div << 2) | ADAU1373_BCLKDIV_64);
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
index 93ee284..f23944d 100644 (file)
@@ -855,30 +855,33 @@ static int wm8983_set_pll(struct snd_soc_dai *dai, int pll_id,
        struct pll_div pll_div;
 
        codec = dai->codec;
-       if (freq_in && freq_out) {
+       if (!freq_in || !freq_out) {
+               /* disable the PLL */
+               snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+                                   WM8983_PLLEN_MASK, 0);
+               return 0;
+       } else {
                ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
                if (ret)
                        return ret;
-       }
-
-       /* disable the PLL before re-programming it */
-       snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
-                           WM8983_PLLEN_MASK, 0);
 
-       if (!freq_in || !freq_out)
-               return 0;
+               /* disable the PLL before re-programming it */
+               snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+                                   WM8983_PLLEN_MASK, 0);
+
+               /* set PLLN and PRESCALE */
+               snd_soc_write(codec, WM8983_PLL_N,
+                       (pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT)
+                       | pll_div.n);
+               /* set PLLK */
+               snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff);
+               snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
+               snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18));
+               /* enable the PLL */
+               snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
+                                       WM8983_PLLEN_MASK, WM8983_PLLEN);
+       }
 
-       /* set PLLN and PRESCALE */
-       snd_soc_write(codec, WM8983_PLL_N,
-                     (pll_div.div2 << WM8983_PLL_PRESCALE_SHIFT)
-                     | pll_div.n);
-       /* set PLLK */
-       snd_soc_write(codec, WM8983_PLL_K_3, pll_div.k & 0x1ff);
-       snd_soc_write(codec, WM8983_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
-       snd_soc_write(codec, WM8983_PLL_K_1, (pll_div.k >> 18));
-       /* enable the PLL */
-       snd_soc_update_bits(codec, WM8983_POWER_MANAGEMENT_1,
-                           WM8983_PLLEN_MASK, WM8983_PLLEN);
        return 0;
 }
 
index bae510a..9d79cc7 100644 (file)
@@ -785,33 +785,30 @@ static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
        struct pll_div pll_div;
 
        codec = dai->codec;
-       if (freq_in && freq_out) {
+       if (!freq_in || !freq_out) {
+               /* disable the PLL */
+               snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                   WM8985_PLLEN_MASK, 0);
+       } else {
                ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
                if (ret)
                        return ret;
-       }
 
-       /* disable the PLL before reprogramming it */
-       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
-                           WM8985_PLLEN_MASK, 0);
-       
-       if (!freq_in || !freq_out)
-               return 0;
-
-       /* set PLLN and PRESCALE */
-       snd_soc_write(codec, WM8985_PLL_N,
-                     (pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
-                     | pll_div.n);
-       /* set PLLK */
-       snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff);
-       snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
-       snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18));
-       /* set the source of the clock to be the PLL */
-       snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
-                           WM8985_CLKSEL_MASK, WM8985_CLKSEL);
-       /* enable the PLL */
-       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
-                           WM8985_PLLEN_MASK, WM8985_PLLEN);
+               /* set PLLN and PRESCALE */
+               snd_soc_write(codec, WM8985_PLL_N,
+                             (pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
+                             | pll_div.n);
+               /* set PLLK */
+               snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff);
+               snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
+               snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18));
+               /* set the source of the clock to be the PLL */
+               snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                                   WM8985_CLKSEL_MASK, WM8985_CLKSEL);
+               /* enable the PLL */
+               snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                   WM8985_PLLEN_MASK, WM8985_PLLEN);
+       }
        return 0;
 }
 
index e44c0e3..3b26d44 100644 (file)
@@ -173,7 +173,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                break;
        default:
                WARN(1, "Unknown DCS readback method\n");
-               break;
+               return;
        }
 
        dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
index a4e3237..9c70fea 100644 (file)
@@ -66,7 +66,7 @@ static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97,
 
        /* polling the AC_R_FINISH */
        while (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_R_FINISH)
-                                                               && timeout--)
+                                                               && --timeout)
                mdelay(1);
 
        if (!timeout) {
@@ -120,7 +120,7 @@ static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 
        /* polling the AC_W_FINISH */
        while ((AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_W_FINISH)
-                                                               && timeout--)
+                                                               && --timeout)
                mdelay(1);
 
        if (!timeout)
index 88e3f81..ce755a9 100644 (file)
@@ -440,10 +440,12 @@ static int __devinit init_card(struct snd_usb_caiaqdev *dev)
 
        err = snd_usb_caiaq_send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0);
        if (err)
-               return err;
+               goto err_kill_urb;
 
-       if (!wait_event_timeout(dev->ep1_wait_queue, dev->spec_received, HZ))
-               return -ENODEV;
+       if (!wait_event_timeout(dev->ep1_wait_queue, dev->spec_received, HZ)) {
+               err = -ENODEV;
+               goto err_kill_urb;
+       }
 
        usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
                   dev->vendor_name, CAIAQ_USB_STR_LEN);
@@ -479,6 +481,10 @@ static int __devinit init_card(struct snd_usb_caiaqdev *dev)
 
        setup_card(dev);
        return 0;
+
+ err_kill_urb:
+       usb_kill_urb(&dev->ep1_in_urb);
+       return err;
 }
 
 static int __devinit snd_probe(struct usb_interface *intf,
index 413b32d..aefb62e 100644 (file)
@@ -222,6 +222,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
        struct usb_interface_descriptor *altsd;
        void *control_header;
        int i, protocol;
+       int rest_bytes;
 
        /* find audiocontrol interface */
        host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
@@ -236,6 +237,15 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
                return -EINVAL;
        }
 
+       rest_bytes = (void *)(host_iface->extra + host_iface->extralen) -
+               control_header;
+
+       /* just to be sure -- this shouldn't hit at all */
+       if (rest_bytes <= 0) {
+               dev_err(&dev->dev, "invalid control header\n");
+               return -EINVAL;
+       }
+
        switch (protocol) {
        default:
                snd_printdd(KERN_WARNING "unknown interface protocol %#02x, assuming v1\n",
@@ -245,11 +255,21 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
        case UAC_VERSION_1: {
                struct uac1_ac_header_descriptor *h1 = control_header;
 
+               if (rest_bytes < sizeof(*h1)) {
+                       dev_err(&dev->dev, "too short v1 buffer descriptor\n");
+                       return -EINVAL;
+               }
+
                if (!h1->bInCollection) {
                        snd_printk(KERN_INFO "skipping empty audio interface (v1)\n");
                        return -EINVAL;
                }
 
+               if (rest_bytes < h1->bLength) {
+                       dev_err(&dev->dev, "invalid buffer length (v1)\n");
+                       return -EINVAL;
+               }
+
                if (h1->bLength < sizeof(*h1) + h1->bInCollection) {
                        snd_printk(KERN_ERR "invalid UAC_HEADER (v1)\n");
                        return -EINVAL;
index 4c01f87..1fc26e4 100644 (file)
@@ -42,7 +42,7 @@ static struct uac_clock_source_descriptor *
        while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
                                             ctrl_iface->extralen,
                                             cs, UAC2_CLOCK_SOURCE))) {
-               if (cs->bClockID == clock_id)
+               if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id)
                        return cs;
        }
 
@@ -58,8 +58,11 @@ static struct uac_clock_selector_descriptor *
        while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
                                             ctrl_iface->extralen,
                                             cs, UAC2_CLOCK_SELECTOR))) {
-               if (cs->bClockID == clock_id)
+               if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id) {
+                       if (cs->bLength < 5 + cs->bNrInPins)
+                               return NULL;
                        return cs;
+               }
        }
 
        return NULL;
@@ -74,7 +77,7 @@ static struct uac_clock_multiplier_descriptor *
        while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
                                             ctrl_iface->extralen,
                                             cs, UAC2_CLOCK_MULTIPLIER))) {
-               if (cs->bClockID == clock_id)
+               if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id)
                        return cs;
        }
 
index 9c36a1f..0ba78dc 100644 (file)
@@ -197,6 +197,10 @@ static void *find_audio_control_unit(struct mixer_build *state, unsigned char un
 static int snd_usb_copy_string_desc(struct mixer_build *state, int index, char *buf, int maxlen)
 {
        int len = usb_string(state->chip->dev, index, buf, maxlen - 1);
+
+       if (len < 0)
+               return 0;
+
        buf[len] = 0;
        return len;
 }
@@ -515,6 +519,8 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 
        if (size < sizeof(scale))
                return -ENOMEM;
+       if (cval->min_mute)
+               scale[0] = SNDRV_CTL_TLVT_DB_MINMAX_MUTE;
        scale[2] = cval->dBmin;
        scale[3] = cval->dBmax;
        if (copy_to_user(_tlv, scale, sizeof(scale)))
@@ -1253,6 +1259,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
        __u8 *bmaControls;
 
        if (state->mixer->protocol == UAC_VERSION_1) {
+               if (hdr->bLength < 7) {
+                       snd_printk(KERN_ERR
+                                  "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+                                  unitid);
+                       return -EINVAL;
+               }
                csize = hdr->bControlSize;
                if (!csize) {
                        snd_printdd(KERN_ERR "usbaudio: unit %u: "
@@ -1269,6 +1281,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
                }
        } else {
                struct uac2_feature_unit_descriptor *ftr = _ftr;
+               if (hdr->bLength < 6) {
+                       snd_printk(KERN_ERR
+                                  "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
+                                  unitid);
+                       return -EINVAL;
+               }
                csize = 4;
                channels = (hdr->bLength - 6) / 4 - 1;
                bmaControls = ftr->bmaControls;
@@ -1831,7 +1849,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
        const struct usbmix_name_map *map;
        char **namelist;
 
-       if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) {
+       if (desc->bLength < 5 || !desc->bNrInPins ||
+           desc->bLength < 5 + desc->bNrInPins) {
                snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid);
                return -EINVAL;
        }
@@ -1904,18 +1923,25 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
        kctl->private_value = (unsigned long)namelist;
        kctl->private_free = usb_mixer_selector_elem_free;
 
-       nameid = uac_selector_unit_iSelector(desc);
+       /* check the static mapping table at first */
        len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
-       if (len)
-               ;
-       else if (nameid)
-               snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
-       else {
-               len = get_term_name(state, &state->oterm,
+       if (!len) {
+               /* no mapping ? */
+               /* if iSelector is given, use it */
+               nameid = uac_selector_unit_iSelector(desc);
+               if (nameid)
+                       len = snd_usb_copy_string_desc(state, nameid,
+                                                      kctl->id.name,
+                                                      sizeof(kctl->id.name));
+               /* ... or pick up the terminal name at next */
+               if (!len)
+                       len = get_term_name(state, &state->oterm,
                                    kctl->id.name, sizeof(kctl->id.name), 0);
-               if (! len)
+               /* ... or use the fixed string "USB" as the last resort */
+               if (!len)
                        strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
 
+               /* and add the proper suffix */
                if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR)
                        append_ctl_name(kctl, " Clock Source");
                else if ((state->oterm.type & 0xff00) == 0x0100)
@@ -1983,6 +2009,9 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
 
 static void snd_usb_mixer_free(struct usb_mixer_interface *mixer)
 {
+       /* kill pending URBs */
+       snd_usb_mixer_disconnect(&mixer->list);
+
        kfree(mixer->id_elems);
        if (mixer->urb) {
                kfree(mixer->urb->transfer_buffer);
@@ -2329,6 +2358,11 @@ void snd_usb_mixer_disconnect(struct list_head *p)
        struct usb_mixer_interface *mixer;
 
        mixer = list_entry(p, struct usb_mixer_interface, list);
-       usb_kill_urb(mixer->urb);
-       usb_kill_urb(mixer->rc_urb);
+       if (mixer->disconnected)
+               return;
+       if (mixer->urb)
+               usb_kill_urb(mixer->urb);
+       if (mixer->rc_urb)
+               usb_kill_urb(mixer->rc_urb);
+       mixer->disconnected = true;
 }
index 81b2d8a..7b6b683 100644 (file)
@@ -23,6 +23,8 @@ struct usb_mixer_interface {
 
        u8 audigy2nx_leds[3];
        u8 xonar_u1_status;
+
+       bool disconnected;
 };
 
 #define MAX_CHANNELS   16      /* max logical channels */
@@ -52,6 +54,7 @@ struct usb_mixer_elem_info {
        int cached;
        int cache_val[MAX_CHANNELS];
        u8 initialized;
+       u8 min_mute;
 };
 
 int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
index d422d16..ee1a148 100644 (file)
@@ -726,6 +726,12 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
                if (unitid == 7 && cval->control == UAC_FU_VOLUME)
                        snd_dragonfly_quirk_db_scale(mixer, cval, kctl);
                break;
+       /* lowest playback value is muted on C-Media devices */
+       case USB_ID(0x0d8c, 0x000c):
+       case USB_ID(0x0d8c, 0x0014):
+               if (strstr(kctl->id.name, "Playback"))
+                       cval->min_mute = 1;
+               break;
        }
 }
 
index 172799a..e3f0c7d 100644 (file)
@@ -2766,4 +2766,51 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
        }
 },
 
+{
+       /*
+        * Bower's & Wilkins PX headphones only support the 48 kHz sample rate
+        * even though it advertises more. The capture interface doesn't work
+        * even on windows.
+        */
+       USB_DEVICE(0x19b5, 0x0021),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_MIXER,
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_IGNORE_INTERFACE,
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 2,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_FILL_MAX |
+                                               UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x03,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) {
+                                               48000
+                                       }
+                               }
+                       },
+               }
+       }
+},
+
 #undef USB_DEVICE_VENDOR_SPEC
index 1e7a47a..ab7e14f 100644 (file)
@@ -192,7 +192,8 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
        }
 
        pg = get_order(read_size);
-       sk->s = (void *) __get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO, pg);
+       sk->s = (void *) __get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO|
+                                         __GFP_NOWARN, pg);
        if (!sk->s) {
                snd_printk(KERN_WARNING "couldn't __get_free_pages()\n");
                goto out;
@@ -212,7 +213,8 @@ struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
        pg = get_order(write_size);
 
        sk->write_page =
-               (void *)__get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO, pg);
+               (void *)__get_free_pages(GFP_KERNEL|__GFP_COMP|__GFP_ZERO|
+                                        __GFP_NOWARN, pg);
        if (!sk->write_page) {
                snd_printk(KERN_WARNING "couldn't __get_free_pages()\n");
                usb_stream_free(sk);