This is the start of the stable review cycle for the 4.19.84 release. There are 125 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 13 Nov 2019 18:08:44 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at: https://www.kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.19.84-rc1... or in the git tree and branch at: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-4.19.y and the diffstat can be found below.
thanks,
greg k-h
------------- Pseudo-Shortlog of commits:
Greg Kroah-Hartman gregkh@linuxfoundation.org Linux 4.19.84-rc1
Tejun Heo tj@kernel.org cgroup,writeback: don't switch wbs immediately on dead wbs if the memcg is dead
Konstantin Khlebnikov khlebnikov@yandex-team.ru mm/filemap.c: don't initiate writeback if mapping has no dirty pages
Jean-Baptiste Maneyrol JManeyrol@invensense.com iio: imu: inv_mpu6050: fix no data on MPU6050
Randolph Maaßen gaireg@gaireg.de iio: imu: mpu6050: Add support for the ICM 20602 IMU
Tejun Heo tj@kernel.org blkcg: make blkcg_print_stat() print stats only for online blkgs
Hans de Goede hdegoede@redhat.com pinctrl: cherryview: Fix irq_valid_mask calculation
Shuning Zhang sunny.s.zhang@oracle.com ocfs2: protect extent tree in ocfs2_prepare_inode_for_write()
Andy Shevchenko andriy.shevchenko@linux.intel.com pinctrl: intel: Avoid potential glitches if pin is in GPIO mode
Wenwen Wang wenwen@cs.uga.edu e1000: fix memory leaks
Manfred Rudigier manfred.rudigier@omicronenergy.com igb: Fix constant media auto sense switching when no cable is connected
Chuhong Yuan hslester96@gmail.com net: ethernet: arc: add the missed clk_disable_unprepare
Trond Myklebust trondmy@gmail.com NFSv4: Don't allow a cached open with a revoked delegation
Felipe Balbi felipe.balbi@linux.intel.com usb: dwc3: gadget: fix race when disabling ep with cancelled xfers
Haiyang Zhang haiyangz@microsoft.com hv_netvsc: Fix error handling in netvsc_attach()
Michael Strauss michael.strauss@amd.com drm/amd/display: Passive DP->HDMI dongle detection fix
Andrey Grodzovsky andrey.grodzovsky@amd.com drm/amdgpu: If amdgpu_ib_schedule fails return back the error.
Takashi Iwai tiwai@suse.de iommu/amd: Apply the same IVRS IOAPIC workaround to Acer Aspire A315-41
Vladimir Oltean olteanv@gmail.com net: mscc: ocelot: refuse to overwrite the port's native vlan
Vladimir Oltean olteanv@gmail.com net: mscc: ocelot: fix vlan_filtering when enslaving to bridge before link is up
Jiangfeng Xiao xiaojiangfeng@huawei.com net: hisilicon: Fix "Trying to free already-free IRQ"
Will Deacon will@kernel.org fjes: Handle workqueue allocation failure
Anton Eidelman anton@lightbitslabs.com nvme-multipath: fix possible io hang after ctrl reconnect
Nicholas Piggin npiggin@gmail.com scsi: qla2xxx: stop timer in shutdown path
Lijun Ou oulijun@huawei.com RDMA/hns: Prevent memory leaks of eq->buf_list
Potnuri Bharat Teja bharat@chelsio.com RDMA/iw_cxgb4: Avoid freeing skb twice in arp failure case
GwanYeong Kim gy741.kim@gmail.com usbip: tools: Fix read_usb_vudc_device() error path handling
Johan Hovold johan@kernel.org USB: ldusb: use unsigned size format specifiers
Alan Stern stern@rowland.harvard.edu USB: Skip endpoints with 0 maxpacket length
Kan Liang kan.liang@linux.intel.com perf/x86/uncore: Fix event group support
Kim Phillips kim.phillips@amd.com perf/x86/amd/ibs: Handle erratum #420 only on the affected CPU family (10h)
Kim Phillips kim.phillips@amd.com perf/x86/amd/ibs: Fix reading of the IBS OpData register and thus precise RIP validity
Yinbo Zhu yinbo.zhu@nxp.com usb: dwc3: remove the call trace of USBx_GFLADJ
Peter Chen peter.chen@nxp.com usb: gadget: configfs: fix concurrent issue between composite APIs
Navid Emamdoost navid.emamdoost@gmail.com usb: dwc3: pci: prevent memory leak in dwc3_pci_probe
Chandana Kishori Chiluveru cchiluve@codeaurora.org usb: gadget: composite: Fix possible double free memory bug
Cristian Birsan cristian.birsan@microchip.com usb: gadget: udc: atmel: Fix interrupt storm in FIFO mode.
Nikhil Badola nikhil.badola@freescale.com usb: fsl: Check memory resource before releasing it
Taehee Yoo ap420073@gmail.com macsec: fix refcnt leak in module exit routine
Taehee Yoo ap420073@gmail.com bonding: fix unexpected IFF_BONDING bit unset
Eric Dumazet edumazet@google.com ipvs: move old_secure_tcp into struct netns_ipvs
Davide Caratti dcaratti@redhat.com ipvs: don't ignore errors in case refcounting ip_vs module fails
Pablo Neira Ayuso pablo@netfilter.org netfilter: nf_flow_table: set timeout before insertion into hashes
Himanshu Madhani hmadhani@marvell.com scsi: qla2xxx: Initialized mailbox to prevent driver load failure
Daniel Wagner dwagner@suse.de scsi: lpfc: Honor module parameter lpfc_use_adisc
Hillf Danton hdanton@sina.com net: openvswitch: free vport unless register_netdevice() succeeds
Dan Carpenter dan.carpenter@oracle.com RDMA/uverbs: Prevent potential underflow
Hannes Reinecke hare@suse.com scsi: qla2xxx: fixup incorrect usage of host_byte
Navid Emamdoost navid.emamdoost@gmail.com net/mlx5: prevent memory leak in mlx5_fpga_conn_create_cq
Tariq Toukan tariqt@mellanox.com net/mlx5e: TX, Fix consumer index of error cqe dump
Kamal Heib kamalheib1@gmail.com RDMA/qedr: Fix reported firmware version
Potnuri Bharat Teja bharat@chelsio.com iw_cxgb4: fix ECN check on the passive accept
Rafi Wiener rafiw@mellanox.com RDMA/mlx5: Clear old rate limit when closing QP
Zhang Lixu lixu.zhang@intel.com HID: intel-ish-hid: fix wrong error handling in ishtp_cl_alloc_tx_ring()
Baolin Wang baolin.wang@linaro.org dmaengine: sprd: Fix the possible memory leak issue
Radhey Shyam Pandey radhey.shyam.pandey@xilinx.com dmaengine: xilinx_dma: Fix control reg update in vdma_channel_set_config
Nicolas Boichat drinkcat@chromium.org HID: google: add magnemite/masterball USB ids
Vidya Sagar vidyas@nvidia.com PCI: tegra: Enable Relaxed Ordering only for Tegra20 & Tegra30
Suwan Kim suwan.kim027@gmail.com usbip: Implement SG support to vhci-hcd and stub driver
Shuah Khan shuah@kernel.org usbip: Fix vhci_urb_enqueue() URB null transfer buffer error path
Qian Cai cai@lca.pw sched/fair: Fix -Wunused-but-set-variable warnings
Dave Chiluk chiluk+linux@indeed.com sched/fair: Fix low cpu usage with high throttling by removing expiration of cpu-local slices
Takashi Iwai tiwai@suse.de ALSA: usb-audio: Fix copy&paste error in the validator
Dan Carpenter dan.carpenter@oracle.com ALSA: usb-audio: remove some dead code
Takashi Iwai tiwai@suse.de ALSA: usb-audio: Fix possible NULL dereference at create_yamaha_midi_quirk()
Takashi Iwai tiwai@suse.de ALSA: usb-audio: Clean up check_input_term()
Takashi Iwai tiwai@suse.de ALSA: usb-audio: Remove superfluous bLength checks
Takashi Iwai tiwai@suse.de ALSA: usb-audio: Unify the release of usb_mixer_elem_info objects
Takashi Iwai tiwai@suse.de ALSA: usb-audio: Simplify parse_audio_unit()
Takashi Iwai tiwai@suse.de ALSA: usb-audio: More validations of descriptor units
Al Viro viro@zeniv.linux.org.uk configfs: fix a deadlock in configfs_symlink()
Al Viro viro@zeniv.linux.org.uk configfs: provide exclusion between IO and removals
Al Viro viro@zeniv.linux.org.uk configfs: new object reprsenting tree fragments
Al Viro viro@zeniv.linux.org.uk configfs_register_group() shouldn't be (and isn't) called in rmdirable parts
Al Viro viro@zeniv.linux.org.uk configfs: stash the data we need into configfs_buffer at open time
Johan Hovold johan@kernel.org can: peak_usb: fix slab info leak
Johan Hovold johan@kernel.org can: mcba_usb: fix use-after-free on disconnect
Wen Yang wenyang@linux.alibaba.com can: dev: add missing of_node_put() after calling of_get_child_by_name()
Navid Emamdoost navid.emamdoost@gmail.com can: gs_usb: gs_can_open(): prevent memory leak
Marc Kleine-Budde mkl@pengutronix.de can: rx-offload: can_rx_offload_queue_sorted(): fix error handling, avoid skb mem leak
Stephane Grosjean s.grosjean@peak-system.com can: peak_usb: fix a potential out-of-sync while decoding packets
Kurt Van Dijck dev.kurt@vandijck-laurijssen.be can: c_can: c_can_poll(): only read status register after status IRQ
Joakim Zhang qiangqing.zhang@nxp.com can: flexcan: disable completely the ECC mechanism
Johan Hovold johan@kernel.org can: usb_8dev: fix use-after-free on disconnect
Pavel Shilovsky pshilov@microsoft.com SMB3: Fix persistent handles reconnect
Jan Beulich jbeulich@suse.com x86/apic/32: Avoid bogus LDR warnings
Alexander Shishkin alexander.shishkin@linux.intel.com intel_th: pci: Add Jasper Lake PCH support
Alexander Shishkin alexander.shishkin@linux.intel.com intel_th: pci: Add Comet Lake PCH support
Dan Carpenter dan.carpenter@oracle.com netfilter: ipset: Fix an error code in ip_set_sockfn_get()
Lukas Wunner lukas@wunner.de netfilter: nf_tables: Align nft_expr private data to 64-bit
Ondrej Jirman megous@megous.com ARM: sunxi: Fix CPU powerdown on A83T
Andreas Klinger ak@it-klinger.de iio: srf04: fix wrong limitation in distance measuring
Alexandru Ardelean alexandru.ardelean@analog.com iio: imu: adis16480: make sure provided frequency is positive
Fabrice Gasnier fabrice.gasnier@st.com iio: adc: stm32-adc: fix stopping dma
Al Viro viro@zeniv.linux.org.uk ceph: add missing check in d_revalidate snapdir handling
Luis Henriques lhenriques@suse.com ceph: fix use-after-free in __ceph_remove_cap()
Catalin Marinas catalin.marinas@arm.com arm64: Do not mask out PTE_RDONLY in pte_same()
Bard Liao yung-chuan.liao@linux.intel.com soundwire: bus: set initial value to port_status
Michal Suchanek msuchanek@suse.de soundwire: depend on ACPI
Jason Gerecke killertofu@gmail.com HID: wacom: generic: Treat serial number and related fields as unsigned
Alex Deucher alexander.deucher@amd.com drm/radeon: fix si_enable_smc_cac() failed issue
Jiri Olsa jolsa@kernel.org perf tools: Fix time sorting
Shuah Khan skhan@linuxfoundation.org tools: gpio: Use !building_out_of_srctree to determine srctree
Kevin Hao haokexin@gmail.com dump_stack: avoid the livelock of the dump_lock
Michal Hocko mhocko@suse.com mm, vmstat: hide /proc/pagetypeinfo from normal users
Yang Shi yang.shi@linux.alibaba.com mm: thp: handle page cache THP correctly in PageTransCompoundMap
Mel Gorman mgorman@techsingularity.net mm, meminit: recalculate pcpu batch and high limits after init completes
Johannes Weiner hannes@cmpxchg.org mm: memcontrol: fix network errors from failing __GFP_ATOMIC charges
Takashi Iwai tiwai@suse.de ALSA: hda/ca0132 - Fix possible workqueue stall
Takashi Sakamoto o-takashi@sakamocchi.jp ALSA: bebob: fix to detect configured source of sampling clock for Focusrite Saffire Pro i/o series
Takashi Iwai tiwai@suse.de ALSA: timer: Fix incorrectly assigned timer instance
Salil Mehta salil.mehta@huawei.com net: hns: Fix the stray netpoll locks causing deadlock in NAPI path
Eric Dumazet edumazet@google.com ipv6: fixes rt6_probe() and fib6_nh->last_probe init
Claudiu Manoil claudiu.manoil@nxp.com net: mscc: ocelot: fix NULL pointer on LAG slave removal
Claudiu Manoil claudiu.manoil@nxp.com net: mscc: ocelot: don't handle netdev events for other netdevs
Manish Chopra manishc@marvell.com qede: fix NULL pointer deref in __qede_remove()
Pan Bian bianpan2016@163.com NFC: st21nfca: fix double free
Pan Bian bianpan2016@163.com nfc: netlink: fix double device reference drop
Pan Bian bianpan2016@163.com NFC: fdp: fix incorrect free object
Aleksander Morgado aleksander@aleksander.es net: usb: qmi_wwan: add support for DW5821e with eSIM support
Sean Tranchetti stranche@codeaurora.org net: qualcomm: rmnet: Fix potential UAF when unregistering
Eric Dumazet edumazet@google.com net: fix data-race in neigh_event_send()
Alexander Sverdlin alexander.sverdlin@nokia.com net: ethernet: octeon_mgmt: Account for second possible VLAN header
David Ahern dsahern@kernel.org ipv4: Fix table id reference in fib_sync_down_addr
Oliver Neukum oneukum@suse.com CDC-NCM: handle incomplete transfer of MTU
Jay Vosburgh jay.vosburgh@canonical.com bonding: fix state transition issue in link monitoring
-------------
Diffstat:
Documentation/scheduler/sched-bwc.txt | 45 ++ Makefile | 4 +- arch/arm/mach-sunxi/mc_smp.c | 6 +- arch/arm64/include/asm/pgtable.h | 17 - arch/x86/events/amd/ibs.c | 8 +- arch/x86/events/intel/uncore.c | 44 +- arch/x86/events/intel/uncore.h | 12 - arch/x86/kernel/apic/apic.c | 28 +- block/blk-cgroup.c | 13 +- drivers/dma/sprd-dma.c | 15 + drivers/dma/xilinx/xilinx_dma.c | 7 + drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 4 +- drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c | 24 +- drivers/gpu/drm/radeon/si_dpm.c | 1 + drivers/hid/hid-google-hammer.c | 4 + drivers/hid/hid-ids.h | 2 + drivers/hid/intel-ish-hid/ishtp/client-buffers.c | 2 +- drivers/hid/wacom.h | 15 + drivers/hid/wacom_wac.c | 10 +- drivers/hwtracing/intel_th/pci.c | 10 + drivers/iio/adc/stm32-adc.c | 4 +- drivers/iio/imu/adis16480.c | 5 +- drivers/iio/imu/inv_mpu6050/Kconfig | 8 +- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 40 ++ drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 6 + drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 10 + drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 15 +- drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c | 12 +- drivers/iio/proximity/srf04.c | 29 +- drivers/infiniband/core/uverbs.h | 2 +- drivers/infiniband/hw/cxgb4/cm.c | 30 +- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 6 +- drivers/infiniband/hw/mlx5/qp.c | 8 +- drivers/infiniband/hw/qedr/main.c | 2 +- drivers/iommu/amd_iommu_quirks.c | 13 + drivers/net/bonding/bond_main.c | 47 +- drivers/net/can/c_can/c_can.c | 25 +- drivers/net/can/c_can/c_can.h | 1 + drivers/net/can/dev.c | 1 + drivers/net/can/flexcan.c | 1 + drivers/net/can/rx-offload.c | 6 +- drivers/net/can/usb/gs_usb.c | 1 + drivers/net/can/usb/mcba_usb.c | 3 +- drivers/net/can/usb/peak_usb/pcan_usb.c | 17 +- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 2 +- drivers/net/can/usb/usb_8dev.c | 3 +- drivers/net/ethernet/arc/emac_rockchip.c | 3 + drivers/net/ethernet/cavium/octeon/octeon_mgmt.c | 2 +- drivers/net/ethernet/hisilicon/hip04_eth.c | 1 - drivers/net/ethernet/hisilicon/hns/hnae.c | 1 - drivers/net/ethernet/hisilicon/hns/hnae.h | 3 - drivers/net/ethernet/hisilicon/hns/hns_enet.c | 22 +- drivers/net/ethernet/intel/e1000/e1000_ethtool.c | 7 +- drivers/net/ethernet/intel/igb/igb_main.c | 3 +- drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 5 +- .../net/ethernet/mellanox/mlx5/core/fpga/conn.c | 4 +- drivers/net/ethernet/mscc/ocelot.c | 20 +- drivers/net/ethernet/qlogic/qede/qede_main.c | 12 +- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 4 +- drivers/net/fjes/fjes_main.c | 15 +- drivers/net/hyperv/netvsc_drv.c | 9 +- drivers/net/macsec.c | 4 - drivers/net/usb/cdc_ncm.c | 6 +- drivers/net/usb/qmi_wwan.c | 1 + drivers/nfc/fdp/i2c.c | 2 +- drivers/nfc/st21nfca/core.c | 1 + drivers/nvme/host/multipath.c | 2 +- drivers/pci/controller/pci-tegra.c | 7 +- drivers/pinctrl/intel/pinctrl-cherryview.c | 2 +- drivers/pinctrl/intel/pinctrl-intel.c | 21 +- drivers/scsi/lpfc/lpfc_nportdisc.c | 4 +- drivers/scsi/qla2xxx/qla_bsg.c | 6 +- drivers/scsi/qla2xxx/qla_mbx.c | 3 +- drivers/scsi/qla2xxx/qla_os.c | 4 + drivers/soundwire/Kconfig | 1 + drivers/soundwire/bus.c | 2 +- drivers/usb/core/config.c | 5 + drivers/usb/dwc3/core.c | 3 +- drivers/usb/dwc3/dwc3-pci.c | 2 +- drivers/usb/dwc3/gadget.c | 6 + drivers/usb/gadget/composite.c | 4 + drivers/usb/gadget/configfs.c | 110 +++- drivers/usb/gadget/udc/atmel_usba_udc.c | 6 +- drivers/usb/gadget/udc/fsl_udc_core.c | 2 +- drivers/usb/misc/ldusb.c | 7 +- drivers/usb/usbip/stub.h | 7 +- drivers/usb/usbip/stub_main.c | 57 +- drivers/usb/usbip/stub_rx.c | 204 +++++-- drivers/usb/usbip/stub_tx.c | 99 +++- drivers/usb/usbip/usbip_common.c | 59 +- drivers/usb/usbip/vhci_hcd.c | 16 +- drivers/usb/usbip/vhci_rx.c | 3 + drivers/usb/usbip/vhci_tx.c | 66 ++- fs/ceph/caps.c | 10 +- fs/ceph/inode.c | 1 + fs/cifs/smb2pdu.h | 1 + fs/configfs/configfs_internal.h | 15 +- fs/configfs/dir.c | 137 +++-- fs/configfs/file.c | 280 ++++----- fs/configfs/symlink.c | 33 +- fs/fs-writeback.c | 9 +- fs/nfs/delegation.c | 10 + fs/nfs/delegation.h | 1 + fs/nfs/nfs4proc.c | 7 +- fs/ocfs2/file.c | 134 +++-- include/linux/mm.h | 5 - include/linux/mm_types.h | 5 + include/linux/page-flags.h | 20 +- include/net/bonding.h | 3 +- include/net/ip_vs.h | 1 + include/net/neighbour.h | 4 +- include/net/netfilter/nf_tables.h | 3 +- include/rdma/ib_verbs.h | 2 +- kernel/sched/fair.c | 91 +-- kernel/sched/sched.h | 4 - lib/dump_stack.c | 7 +- mm/filemap.c | 3 +- mm/memcontrol.c | 9 + mm/page_alloc.c | 10 +- mm/vmstat.c | 2 +- net/ipv4/fib_semantics.c | 2 +- net/ipv6/route.c | 13 +- net/netfilter/ipset/ip_set_core.c | 8 +- net/netfilter/ipvs/ip_vs_app.c | 12 +- net/netfilter/ipvs/ip_vs_ctl.c | 29 +- net/netfilter/ipvs/ip_vs_pe.c | 3 +- net/netfilter/ipvs/ip_vs_sched.c | 3 +- net/netfilter/ipvs/ip_vs_sync.c | 13 +- net/netfilter/nf_flow_table_core.c | 3 +- net/nfc/netlink.c | 2 - net/openvswitch/vport-internal_dev.c | 11 +- sound/core/timer.c | 6 +- sound/firewire/bebob/bebob_focusrite.c | 3 + sound/pci/hda/patch_ca0132.c | 2 +- sound/usb/Makefile | 3 +- sound/usb/clock.c | 14 +- sound/usb/helper.h | 4 + sound/usb/mixer.c | 633 +++++++++------------ sound/usb/power.c | 2 + sound/usb/quirks.c | 3 + sound/usb/stream.c | 25 +- sound/usb/validate.c | 332 +++++++++++ tools/gpio/Makefile | 6 +- tools/perf/util/hist.c | 2 +- tools/usb/usbip/libsrc/usbip_device_driver.c | 6 +- 145 files changed, 2224 insertions(+), 1124 deletions(-)
From: Jay Vosburgh jay.vosburgh@canonical.com
[ Upstream commit 1899bb325149e481de31a4f32b59ea6f24e176ea ]
Since de77ecd4ef02 ("bonding: improve link-status update in mii-monitoring"), the bonding driver has utilized two separate variables to indicate the next link state a particular slave should transition to. Each is used to communicate to a different portion of the link state change commit logic; one to the bond_miimon_commit function itself, and another to the state transition logic.
Unfortunately, the two variables can become unsynchronized, resulting in incorrect link state transitions within bonding. This can cause slaves to become stuck in an incorrect link state until a subsequent carrier state transition.
The issue occurs when a special case in bond_slave_netdev_event sets slave->link directly to BOND_LINK_FAIL. On the next pass through bond_miimon_inspect after the slave goes carrier up, the BOND_LINK_FAIL case will set the proposed next state (link_new_state) to BOND_LINK_UP, but the new_link to BOND_LINK_DOWN. The setting of the final link state from new_link comes after that from link_new_state, and so the slave will end up incorrectly in _DOWN state.
Resolve this by combining the two variables into one.
Reported-by: Aleksei Zakharov zakharov.a.g@yandex.ru Reported-by: Sha Zhang zhangsha.zhang@huawei.com Cc: Mahesh Bandewar maheshb@google.com Fixes: de77ecd4ef02 ("bonding: improve link-status update in mii-monitoring") Signed-off-by: Jay Vosburgh jay.vosburgh@canonical.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/net/bonding/bond_main.c | 41 +++++++++++++++++++--------------------- include/net/bonding.h | 3 -- 2 files changed, 21 insertions(+), 23 deletions(-)
--- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2074,8 +2074,7 @@ static int bond_miimon_inspect(struct bo ignore_updelay = !rcu_dereference(bond->curr_active_slave);
bond_for_each_slave_rcu(bond, slave, iter) { - slave->new_link = BOND_LINK_NOCHANGE; - slave->link_new_state = slave->link; + bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
link_state = bond_check_dev_link(bond, slave->dev, 0);
@@ -2111,7 +2110,7 @@ static int bond_miimon_inspect(struct bo }
if (slave->delay <= 0) { - slave->new_link = BOND_LINK_DOWN; + bond_propose_link_state(slave, BOND_LINK_DOWN); commit++; continue; } @@ -2150,7 +2149,7 @@ static int bond_miimon_inspect(struct bo slave->delay = 0;
if (slave->delay <= 0) { - slave->new_link = BOND_LINK_UP; + bond_propose_link_state(slave, BOND_LINK_UP); commit++; ignore_updelay = false; continue; @@ -2188,7 +2187,7 @@ static void bond_miimon_commit(struct bo struct slave *slave, *primary;
bond_for_each_slave(bond, slave, iter) { - switch (slave->new_link) { + switch (slave->link_new_state) { case BOND_LINK_NOCHANGE: /* For 802.3ad mode, check current slave speed and * duplex again in case its port was disabled after @@ -2263,8 +2262,8 @@ static void bond_miimon_commit(struct bo
default: netdev_err(bond->dev, "invalid new link %d on slave %s\n", - slave->new_link, slave->dev->name); - slave->new_link = BOND_LINK_NOCHANGE; + slave->link_new_state, slave->dev->name); + bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
continue; } @@ -2664,13 +2663,13 @@ static void bond_loadbalance_arp_mon(str bond_for_each_slave_rcu(bond, slave, iter) { unsigned long trans_start = dev_trans_start(slave->dev);
- slave->new_link = BOND_LINK_NOCHANGE; + bond_propose_link_state(slave, BOND_LINK_NOCHANGE);
if (slave->link != BOND_LINK_UP) { if (bond_time_in_interval(bond, trans_start, 1) && bond_time_in_interval(bond, slave->last_rx, 1)) {
- slave->new_link = BOND_LINK_UP; + bond_propose_link_state(slave, BOND_LINK_UP); slave_state_changed = 1;
/* primary_slave has no meaning in round-robin @@ -2697,7 +2696,7 @@ static void bond_loadbalance_arp_mon(str if (!bond_time_in_interval(bond, trans_start, 2) || !bond_time_in_interval(bond, slave->last_rx, 2)) {
- slave->new_link = BOND_LINK_DOWN; + bond_propose_link_state(slave, BOND_LINK_DOWN); slave_state_changed = 1;
if (slave->link_failure_count < UINT_MAX) @@ -2729,8 +2728,8 @@ static void bond_loadbalance_arp_mon(str goto re_arm;
bond_for_each_slave(bond, slave, iter) { - if (slave->new_link != BOND_LINK_NOCHANGE) - slave->link = slave->new_link; + if (slave->link_new_state != BOND_LINK_NOCHANGE) + slave->link = slave->link_new_state; }
if (slave_state_changed) { @@ -2753,9 +2752,9 @@ re_arm: }
/* Called to inspect slaves for active-backup mode ARP monitor link state - * changes. Sets new_link in slaves to specify what action should take - * place for the slave. Returns 0 if no changes are found, >0 if changes - * to link states must be committed. + * changes. Sets proposed link state in slaves to specify what action + * should take place for the slave. Returns 0 if no changes are found, >0 + * if changes to link states must be committed. * * Called with rcu_read_lock held. */ @@ -2767,12 +2766,12 @@ static int bond_ab_arp_inspect(struct bo int commit = 0;
bond_for_each_slave_rcu(bond, slave, iter) { - slave->new_link = BOND_LINK_NOCHANGE; + bond_propose_link_state(slave, BOND_LINK_NOCHANGE); last_rx = slave_last_rx(bond, slave);
if (slave->link != BOND_LINK_UP) { if (bond_time_in_interval(bond, last_rx, 1)) { - slave->new_link = BOND_LINK_UP; + bond_propose_link_state(slave, BOND_LINK_UP); commit++; } continue; @@ -2800,7 +2799,7 @@ static int bond_ab_arp_inspect(struct bo if (!bond_is_active_slave(slave) && !rcu_access_pointer(bond->current_arp_slave) && !bond_time_in_interval(bond, last_rx, 3)) { - slave->new_link = BOND_LINK_DOWN; + bond_propose_link_state(slave, BOND_LINK_DOWN); commit++; }
@@ -2813,7 +2812,7 @@ static int bond_ab_arp_inspect(struct bo if (bond_is_active_slave(slave) && (!bond_time_in_interval(bond, trans_start, 2) || !bond_time_in_interval(bond, last_rx, 2))) { - slave->new_link = BOND_LINK_DOWN; + bond_propose_link_state(slave, BOND_LINK_DOWN); commit++; } } @@ -2833,7 +2832,7 @@ static void bond_ab_arp_commit(struct bo struct slave *slave;
bond_for_each_slave(bond, slave, iter) { - switch (slave->new_link) { + switch (slave->link_new_state) { case BOND_LINK_NOCHANGE: continue;
@@ -2886,7 +2885,7 @@ static void bond_ab_arp_commit(struct bo
default: netdev_err(bond->dev, "impossible: new_link %d on slave %s\n", - slave->new_link, slave->dev->name); + slave->link_new_state, slave->dev->name); continue; }
--- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -149,7 +149,6 @@ struct slave { unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS]; s8 link; /* one of BOND_LINK_XXXX */ s8 link_new_state; /* one of BOND_LINK_XXXX */ - s8 new_link; u8 backup:1, /* indicates backup slave. Value corresponds with BOND_STATE_ACTIVE and BOND_STATE_BACKUP */ inactive:1, /* indicates inactive slave */ @@ -539,7 +538,7 @@ static inline void bond_propose_link_sta
static inline void bond_commit_link_state(struct slave *slave, bool notify) { - if (slave->link == slave->link_new_state) + if (slave->link_new_state == BOND_LINK_NOCHANGE) return;
slave->link = slave->link_new_state;
On Tue, Nov 12, 2019 at 3:05 AM Greg Kroah-Hartman gregkh@linuxfoundation.org wrote:
From: Jay Vosburgh jay.vosburgh@canonical.com
[ Upstream commit 1899bb325149e481de31a4f32b59ea6f24e176ea ]
Since de77ecd4ef02 ("bonding: improve link-status update in mii-monitoring"), the bonding driver has utilized two separate variables to indicate the next link state a particular slave should transition to. Each is used to communicate to a different portion of the link state change commit logic; one to the bond_miimon_commit function itself, and another to the state transition logic.
Unfortunately, the two variables can become unsynchronized,
resulting in incorrect link state transitions within bonding. This can cause slaves to become stuck in an incorrect link state until a subsequent carrier state transition.
The issue occurs when a special case in bond_slave_netdev_event
sets slave->link directly to BOND_LINK_FAIL. On the next pass through bond_miimon_inspect after the slave goes carrier up, the BOND_LINK_FAIL case will set the proposed next state (link_new_state) to BOND_LINK_UP, but the new_link to BOND_LINK_DOWN. The setting of the final link state from new_link comes after that from link_new_state, and so the slave will end up incorrectly in _DOWN state.
Resolve this by combining the two variables into one.
Reported-by: Aleksei Zakharov zakharov.a.g@yandex.ru Reported-by: Sha Zhang zhangsha.zhang@huawei.com Cc: Mahesh Bandewar maheshb@google.com Fixes: de77ecd4ef02 ("bonding: improve link-status update in mii-monitoring") Signed-off-by: Jay Vosburgh jay.vosburgh@canonical.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
drivers/net/bonding/bond_main.c | 41 +++++++++++++++++++--------------------- include/net/bonding.h | 3 -- 2 files changed, 21 insertions(+), 23 deletions(-)
--- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2074,8 +2074,7 @@ static int bond_miimon_inspect(struct bo ignore_updelay = !rcu_dereference(bond->curr_active_slave);
bond_for_each_slave_rcu(bond, slave, iter) {
slave->new_link = BOND_LINK_NOCHANGE;
slave->link_new_state = slave->link;
bond_propose_link_state(slave, BOND_LINK_NOCHANGE); link_state = bond_check_dev_link(bond, slave->dev, 0);
@@ -2111,7 +2110,7 @@ static int bond_miimon_inspect(struct bo }
if (slave->delay <= 0) {
slave->new_link = BOND_LINK_DOWN;
bond_propose_link_state(slave, BOND_LINK_DOWN); commit++; continue; }
@@ -2150,7 +2149,7 @@ static int bond_miimon_inspect(struct bo slave->delay = 0;
if (slave->delay <= 0) {
slave->new_link = BOND_LINK_UP;
bond_propose_link_state(slave, BOND_LINK_UP); commit++; ignore_updelay = false; continue;
@@ -2188,7 +2187,7 @@ static void bond_miimon_commit(struct bo struct slave *slave, *primary;
bond_for_each_slave(bond, slave, iter) {
switch (slave->new_link) {
switch (slave->link_new_state) { case BOND_LINK_NOCHANGE: /* For 802.3ad mode, check current slave speed and * duplex again in case its port was disabled after
@@ -2263,8 +2262,8 @@ static void bond_miimon_commit(struct bo
default: netdev_err(bond->dev, "invalid new link %d on slave %s\n",
slave->new_link, slave->dev->name);
slave->new_link = BOND_LINK_NOCHANGE;
slave->link_new_state, slave->dev->name);
bond_propose_link_state(slave, BOND_LINK_NOCHANGE); continue; }
@@ -2664,13 +2663,13 @@ static void bond_loadbalance_arp_mon(str bond_for_each_slave_rcu(bond, slave, iter) { unsigned long trans_start = dev_trans_start(slave->dev);
slave->new_link = BOND_LINK_NOCHANGE;
bond_propose_link_state(slave, BOND_LINK_NOCHANGE); if (slave->link != BOND_LINK_UP) { if (bond_time_in_interval(bond, trans_start, 1) && bond_time_in_interval(bond, slave->last_rx, 1)) {
slave->new_link = BOND_LINK_UP;
bond_propose_link_state(slave, BOND_LINK_UP); slave_state_changed = 1; /* primary_slave has no meaning in round-robin
@@ -2697,7 +2696,7 @@ static void bond_loadbalance_arp_mon(str if (!bond_time_in_interval(bond, trans_start, 2) || !bond_time_in_interval(bond, slave->last_rx, 2)) {
slave->new_link = BOND_LINK_DOWN;
bond_propose_link_state(slave, BOND_LINK_DOWN); slave_state_changed = 1; if (slave->link_failure_count < UINT_MAX)
@@ -2729,8 +2728,8 @@ static void bond_loadbalance_arp_mon(str goto re_arm;
bond_for_each_slave(bond, slave, iter) {
if (slave->new_link != BOND_LINK_NOCHANGE)
slave->link = slave->new_link;
if (slave->link_new_state != BOND_LINK_NOCHANGE)
slave->link = slave->link_new_state; } if (slave_state_changed) {
@@ -2753,9 +2752,9 @@ re_arm: }
/* Called to inspect slaves for active-backup mode ARP monitor link state
- changes. Sets new_link in slaves to specify what action should take
- place for the slave. Returns 0 if no changes are found, >0 if changes
- to link states must be committed.
- changes. Sets proposed link state in slaves to specify what action
- should take place for the slave. Returns 0 if no changes are found, >0
*/
- if changes to link states must be committed.
- Called with rcu_read_lock held.
@@ -2767,12 +2766,12 @@ static int bond_ab_arp_inspect(struct bo int commit = 0;
bond_for_each_slave_rcu(bond, slave, iter) {
slave->new_link = BOND_LINK_NOCHANGE;
bond_propose_link_state(slave, BOND_LINK_NOCHANGE); last_rx = slave_last_rx(bond, slave); if (slave->link != BOND_LINK_UP) { if (bond_time_in_interval(bond, last_rx, 1)) {
slave->new_link = BOND_LINK_UP;
bond_propose_link_state(slave, BOND_LINK_UP); commit++; } continue;
@@ -2800,7 +2799,7 @@ static int bond_ab_arp_inspect(struct bo if (!bond_is_active_slave(slave) && !rcu_access_pointer(bond->current_arp_slave) && !bond_time_in_interval(bond, last_rx, 3)) {
slave->new_link = BOND_LINK_DOWN;
bond_propose_link_state(slave, BOND_LINK_DOWN); commit++; }
@@ -2813,7 +2812,7 @@ static int bond_ab_arp_inspect(struct bo if (bond_is_active_slave(slave) && (!bond_time_in_interval(bond, trans_start, 2) || !bond_time_in_interval(bond, last_rx, 2))) {
slave->new_link = BOND_LINK_DOWN;
bond_propose_link_state(slave, BOND_LINK_DOWN); commit++; } }
@@ -2833,7 +2832,7 @@ static void bond_ab_arp_commit(struct bo struct slave *slave;
bond_for_each_slave(bond, slave, iter) {
switch (slave->new_link) {
switch (slave->link_new_state) { case BOND_LINK_NOCHANGE: continue;
@@ -2886,7 +2885,7 @@ static void bond_ab_arp_commit(struct bo
default: netdev_err(bond->dev, "impossible: new_link %d on slave %s\n",
Hello,
I think the error message here should be: "impossible: link_new_state %d on slave %s\n" instead? As in the upstream commit it's: slave_err(bond->dev, slave->dev, "impossible: link_new_state %d on slave\n", slave->link_new_state);
Thanks
slave->new_link, slave->dev->name);
slave->link_new_state, slave->dev->name); continue; }
--- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -149,7 +149,6 @@ struct slave { unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS]; s8 link; /* one of BOND_LINK_XXXX */ s8 link_new_state; /* one of BOND_LINK_XXXX */
s8 new_link; u8 backup:1, /* indicates backup slave. Value corresponds with BOND_STATE_ACTIVE and BOND_STATE_BACKUP */ inactive:1, /* indicates inactive slave */
@@ -539,7 +538,7 @@ static inline void bond_propose_link_sta
static inline void bond_commit_link_state(struct slave *slave, bool notify) {
if (slave->link == slave->link_new_state)
if (slave->link_new_state == BOND_LINK_NOCHANGE) return; slave->link = slave->link_new_state;
From: Oliver Neukum oneukum@suse.com
[ Upstream commit 332f989a3b0041b810836c5c3747e59aad7e9d0b ]
A malicious device may give half an answer when asked for its MTU. The driver will proceed after this with a garbage MTU. Anything but a complete answer must be treated as an error.
V2: used sizeof as request by Alexander
Reported-and-tested-by: syzbot+0631d878823ce2411636@syzkaller.appspotmail.com Signed-off-by: Oliver Neukum oneukum@suse.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/net/usb/cdc_ncm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
--- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -578,8 +578,8 @@ static void cdc_ncm_set_dgram_size(struc /* read current mtu value from device */ err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE, USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, - 0, iface_no, &max_datagram_size, 2); - if (err < 0) { + 0, iface_no, &max_datagram_size, sizeof(max_datagram_size)); + if (err < sizeof(max_datagram_size)) { dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed\n"); goto out; } @@ -590,7 +590,7 @@ static void cdc_ncm_set_dgram_size(struc max_datagram_size = cpu_to_le16(ctx->max_datagram_size); err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, - 0, iface_no, &max_datagram_size, 2); + 0, iface_no, &max_datagram_size, sizeof(max_datagram_size)); if (err < 0) dev_dbg(&dev->intf->dev, "SET_MAX_DATAGRAM_SIZE failed\n");
From: David Ahern dsahern@kernel.org
[ Upstream commit e0a312629fefa943534fc46f7bfbe6de3fdaf463 ]
Hendrik reported routes in the main table using source address are not removed when the address is removed. The problem is that fib_sync_down_addr does not account for devices in the default VRF which are associated with the main table. Fix by updating the table id reference.
Fixes: 5a56a0b3a45d ("net: Don't delete routes in different VRFs") Reported-by: Hendrik Donner hd@os-cillation.de Signed-off-by: David Ahern dsahern@kernel.org Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- net/ipv4/fib_semantics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -1421,8 +1421,8 @@ int fib_sync_down_addr(struct net_device int ret = 0; unsigned int hash = fib_laddr_hashfn(local); struct hlist_head *head = &fib_info_laddrhash[hash]; + int tb_id = l3mdev_fib_table(dev) ? : RT_TABLE_MAIN; struct net *net = dev_net(dev); - int tb_id = l3mdev_fib_table(dev); struct fib_info *fi;
if (!fib_info_laddrhash || local == 0)
From: Alexander Sverdlin alexander.sverdlin@nokia.com
[ Upstream commit e4dd5608033efe7b6030cde359bfdbaeb73bc22d ]
Octeon's input ring-buffer entry has 14 bits-wide size field, so to account for second possible VLAN header max_mtu must be further reduced.
Fixes: 109cc16526c6d ("ethernet/cavium: use core min/max MTU checking") Signed-off-by: Alexander Sverdlin alexander.sverdlin@nokia.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/net/ethernet/cavium/octeon/octeon_mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c @@ -1495,7 +1495,7 @@ static int octeon_mgmt_probe(struct plat netdev->ethtool_ops = &octeon_mgmt_ethtool_ops;
netdev->min_mtu = 64 - OCTEON_MGMT_RX_HEADROOM; - netdev->max_mtu = 16383 - OCTEON_MGMT_RX_HEADROOM; + netdev->max_mtu = 16383 - OCTEON_MGMT_RX_HEADROOM - VLAN_HLEN;
mac = of_get_mac_address(pdev->dev.of_node);
From: Eric Dumazet edumazet@google.com
[ Upstream commit 1b53d64435d56902fc234ff2507142d971a09687 ]
KCSAN reported the following data-race [1]
The fix will also prevent the compiler from optimizing out the condition.
[1]
BUG: KCSAN: data-race in neigh_resolve_output / neigh_resolve_output
write to 0xffff8880a41dba78 of 8 bytes by interrupt on cpu 1: neigh_event_send include/net/neighbour.h:443 [inline] neigh_resolve_output+0x78/0x480 net/core/neighbour.c:1474 neigh_output include/net/neighbour.h:511 [inline] ip_finish_output2+0x4af/0xe40 net/ipv4/ip_output.c:228 __ip_finish_output net/ipv4/ip_output.c:308 [inline] __ip_finish_output+0x23a/0x490 net/ipv4/ip_output.c:290 ip_finish_output+0x41/0x160 net/ipv4/ip_output.c:318 NF_HOOK_COND include/linux/netfilter.h:294 [inline] ip_output+0xdf/0x210 net/ipv4/ip_output.c:432 dst_output include/net/dst.h:436 [inline] ip_local_out+0x74/0x90 net/ipv4/ip_output.c:125 __ip_queue_xmit+0x3a8/0xa40 net/ipv4/ip_output.c:532 ip_queue_xmit+0x45/0x60 include/net/ip.h:237 __tcp_transmit_skb+0xe81/0x1d60 net/ipv4/tcp_output.c:1169 tcp_transmit_skb net/ipv4/tcp_output.c:1185 [inline] __tcp_retransmit_skb+0x4bd/0x15f0 net/ipv4/tcp_output.c:2976 tcp_retransmit_skb+0x36/0x1a0 net/ipv4/tcp_output.c:2999 tcp_retransmit_timer+0x719/0x16d0 net/ipv4/tcp_timer.c:515 tcp_write_timer_handler+0x42d/0x510 net/ipv4/tcp_timer.c:598 tcp_write_timer+0xd1/0xf0 net/ipv4/tcp_timer.c:618
read to 0xffff8880a41dba78 of 8 bytes by interrupt on cpu 0: neigh_event_send include/net/neighbour.h:442 [inline] neigh_resolve_output+0x57/0x480 net/core/neighbour.c:1474 neigh_output include/net/neighbour.h:511 [inline] ip_finish_output2+0x4af/0xe40 net/ipv4/ip_output.c:228 __ip_finish_output net/ipv4/ip_output.c:308 [inline] __ip_finish_output+0x23a/0x490 net/ipv4/ip_output.c:290 ip_finish_output+0x41/0x160 net/ipv4/ip_output.c:318 NF_HOOK_COND include/linux/netfilter.h:294 [inline] ip_output+0xdf/0x210 net/ipv4/ip_output.c:432 dst_output include/net/dst.h:436 [inline] ip_local_out+0x74/0x90 net/ipv4/ip_output.c:125 __ip_queue_xmit+0x3a8/0xa40 net/ipv4/ip_output.c:532 ip_queue_xmit+0x45/0x60 include/net/ip.h:237 __tcp_transmit_skb+0xe81/0x1d60 net/ipv4/tcp_output.c:1169 tcp_transmit_skb net/ipv4/tcp_output.c:1185 [inline] __tcp_retransmit_skb+0x4bd/0x15f0 net/ipv4/tcp_output.c:2976 tcp_retransmit_skb+0x36/0x1a0 net/ipv4/tcp_output.c:2999 tcp_retransmit_timer+0x719/0x16d0 net/ipv4/tcp_timer.c:515 tcp_write_timer_handler+0x42d/0x510 net/ipv4/tcp_timer.c:598
Reported by Kernel Concurrency Sanitizer on: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.4.0-rc3+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Signed-off-by: Eric Dumazet edumazet@google.com Reported-by: syzbot syzkaller@googlegroups.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- include/net/neighbour.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -430,8 +430,8 @@ static inline int neigh_event_send(struc { unsigned long now = jiffies; - if (neigh->used != now) - neigh->used = now; + if (READ_ONCE(neigh->used) != now) + WRITE_ONCE(neigh->used, now); if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE))) return __neigh_event_send(neigh, skb); return 0;
From: Sean Tranchetti stranche@codeaurora.org
[ Upstream commit e7a86c687e64ab24f88330ad24ecc9442ce40c5a ]
During the exit/unregistration process of the RmNet driver, the function rmnet_unregister_real_device() is called to handle freeing the driver's internal state and removing the RX handler on the underlying physical device. However, the order of operations this function performs is wrong and can lead to a use after free of the rmnet_port structure.
Before calling netdev_rx_handler_unregister(), this port structure is freed with kfree(). If packets are received on any RmNet devices before synchronize_net() completes, they will attempt to use this already-freed port structure when processing the packet. As such, before cleaning up any other internal state, the RX handler must be unregistered in order to guarantee that no further packets will arrive on the device.
Fixes: ceed73a2cf4a ("drivers: net: ethernet: qualcomm: rmnet: Initial implementation") Signed-off-by: Sean Tranchetti stranche@codeaurora.org Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -66,10 +66,10 @@ static int rmnet_unregister_real_device( if (port->nr_rmnet_devs) return -EINVAL;
- kfree(port); - netdev_rx_handler_unregister(real_dev);
+ kfree(port); + /* release reference on real_dev */ dev_put(real_dev);
From: Aleksander Morgado aleksander@aleksander.es
[ Upstream commit e497df686e8fed8c1dd69179010656362858edb3 ]
Exactly same layout as the default DW5821e module, just a different vid/pid.
The QMI interface is exposed in USB configuration #1:
P: Vendor=413c ProdID=81e0 Rev=03.18 S: Manufacturer=Dell Inc. S: Product=DW5821e-eSIM Snapdragon X20 LTE S: SerialNumber=0123456789ABCDEF C: #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#=0x0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan I: If#=0x1 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=00 Prot=00 Driver=usbhid I: If#=0x2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#=0x3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#=0x4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option I: If#=0x5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option
Signed-off-by: Aleksander Morgado aleksander@aleksander.es Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1297,6 +1297,7 @@ static const struct usb_device_id produc {QMI_FIXED_INTF(0x413c, 0x81b6, 8)}, /* Dell Wireless 5811e */ {QMI_FIXED_INTF(0x413c, 0x81b6, 10)}, /* Dell Wireless 5811e */ {QMI_FIXED_INTF(0x413c, 0x81d7, 0)}, /* Dell Wireless 5821e */ + {QMI_FIXED_INTF(0x413c, 0x81e0, 0)}, /* Dell Wireless 5821e with eSIM support*/ {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */ {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */
From: Pan Bian bianpan2016@163.com
[ Upstream commit 517ce4e93368938b204451285e53014549804868 ]
The address of fw_vsc_cfg is on stack. Releasing it with devm_kfree() is incorrect, which may result in a system crash or other security impacts. The expected object to free is *fw_vsc_cfg.
Signed-off-by: Pan Bian bianpan2016@163.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/nfc/fdp/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/nfc/fdp/i2c.c +++ b/drivers/nfc/fdp/i2c.c @@ -267,7 +267,7 @@ static void fdp_nci_i2c_read_device_prop *fw_vsc_cfg, len);
if (r) { - devm_kfree(dev, fw_vsc_cfg); + devm_kfree(dev, *fw_vsc_cfg); goto vsc_read_err; } } else {
From: Pan Bian bianpan2016@163.com
[ Upstream commit 025ec40b81d785a98f76b8bdb509ac10773b4f12 ]
The function nfc_put_device(dev) is called twice to drop the reference to dev when there is no associated local llcp. Remove one of them to fix the bug.
Fixes: 52feb444a903 ("NFC: Extend netlink interface for LTO, RW, and MIUX parameters support") Fixes: d9b8d8e19b07 ("NFC: llcp: Service Name Lookup netlink interface") Signed-off-by: Pan Bian bianpan2016@163.com Reviewed-by: Johan Hovold johan@kernel.org Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- net/nfc/netlink.c | 2 -- 1 file changed, 2 deletions(-)
--- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -1110,7 +1110,6 @@ static int nfc_genl_llc_set_params(struc
local = nfc_llcp_find_local(dev); if (!local) { - nfc_put_device(dev); rc = -ENODEV; goto exit; } @@ -1170,7 +1169,6 @@ static int nfc_genl_llc_sdreq(struct sk_
local = nfc_llcp_find_local(dev); if (!local) { - nfc_put_device(dev); rc = -ENODEV; goto exit; }
From: Pan Bian bianpan2016@163.com
[ Upstream commit 99a8efbb6e30b72ac98cecf81103f847abffb1e5 ]
The variable nfcid_skb is not changed in the callee nfc_hci_get_param() if error occurs. Consequently, the freed variable nfcid_skb will be freed again, resulting in a double free bug. Set nfcid_skb to NULL after releasing it to fix the bug.
Signed-off-by: Pan Bian bianpan2016@163.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/nfc/st21nfca/core.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/nfc/st21nfca/core.c +++ b/drivers/nfc/st21nfca/core.c @@ -719,6 +719,7 @@ static int st21nfca_hci_complete_target_ NFC_PROTO_FELICA_MASK; } else { kfree_skb(nfcid_skb); + nfcid_skb = NULL; /* P2P in type A */ r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE, ST21NFCA_RF_READER_F_NFCID1,
From: Manish Chopra manishc@marvell.com
[ Upstream commit deabc87111c690097c03765ea017cd500f7376fc ]
While rebooting the system with SR-IOV vfs enabled leads to below crash due to recurrence of __qede_remove() on the VF devices (first from .shutdown() flow of the VF itself and another from PF's .shutdown() flow executing pci_disable_sriov())
This patch adds a safeguard in __qede_remove() flow to fix this, so that driver doesn't attempt to remove "already removed" devices.
[ 194.360134] BUG: unable to handle kernel NULL pointer dereference at 00000000000008dc [ 194.360227] IP: [<ffffffffc03553c4>] __qede_remove+0x24/0x130 [qede] [ 194.360304] PGD 0 [ 194.360325] Oops: 0000 [#1] SMP [ 194.360360] Modules linked in: tcp_lp fuse tun bridge stp llc devlink bonding ip_set nfnetlink ib_isert iscsi_target_mod ib_srpt target_core_mod ib_srp scsi_transport_srp scsi_tgt ib_ipoib ib_umad rpcrdma sunrpc rdma_ucm ib_uverbs ib_iser rdma_cm iw_cm ib_cm libiscsi scsi_transport_iscsi dell_smbios iTCO_wdt iTCO_vendor_support dell_wmi_descriptor dcdbas vfat fat pcc_cpufreq skx_edac intel_powerclamp coretemp intel_rapl iosf_mbi kvm_intel kvm irqbypass crc32_pclmul ghash_clmulni_intel aesni_intel lrw gf128mul glue_helper ablk_helper cryptd qedr ib_core pcspkr ses enclosure joydev ipmi_ssif sg i2c_i801 lpc_ich mei_me mei wmi ipmi_si ipmi_devintf ipmi_msghandler tpm_crb acpi_pad acpi_power_meter xfs libcrc32c sd_mod crc_t10dif crct10dif_generic crct10dif_pclmul crct10dif_common crc32c_intel mgag200 [ 194.361044] qede i2c_algo_bit drm_kms_helper qed syscopyarea sysfillrect nvme sysimgblt fb_sys_fops ttm nvme_core mpt3sas crc8 ptp drm pps_core ahci raid_class scsi_transport_sas libahci libata drm_panel_orientation_quirks nfit libnvdimm dm_mirror dm_region_hash dm_log dm_mod [last unloaded: ip_tables] [ 194.361297] CPU: 51 PID: 7996 Comm: reboot Kdump: loaded Not tainted 3.10.0-1062.el7.x86_64 #1 [ 194.361359] Hardware name: Dell Inc. PowerEdge MX840c/0740HW, BIOS 2.4.6 10/15/2019 [ 194.361412] task: ffff9cea9b360000 ti: ffff9ceabebdc000 task.ti: ffff9ceabebdc000 [ 194.361463] RIP: 0010:[<ffffffffc03553c4>] [<ffffffffc03553c4>] __qede_remove+0x24/0x130 [qede] [ 194.361534] RSP: 0018:ffff9ceabebdfac0 EFLAGS: 00010282 [ 194.361570] RAX: 0000000000000000 RBX: ffff9cd013846098 RCX: 0000000000000000 [ 194.361621] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff9cd013846098 [ 194.361668] RBP: ffff9ceabebdfae8 R08: 0000000000000000 R09: 0000000000000000 [ 194.361715] R10: 00000000bfe14201 R11: ffff9ceabfe141e0 R12: 0000000000000000 [ 194.361762] R13: ffff9cd013846098 R14: 0000000000000000 R15: ffff9ceab5e48000 [ 194.361810] FS: 00007f799c02d880(0000) GS:ffff9ceacb0c0000(0000) knlGS:0000000000000000 [ 194.361865] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 194.361903] CR2: 00000000000008dc CR3: 0000001bdac76000 CR4: 00000000007607e0 [ 194.361953] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 194.362002] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 194.362051] PKRU: 55555554 [ 194.362073] Call Trace: [ 194.362109] [<ffffffffc0355500>] qede_remove+0x10/0x20 [qede] [ 194.362180] [<ffffffffb97d0f3e>] pci_device_remove+0x3e/0xc0 [ 194.362240] [<ffffffffb98b3c52>] __device_release_driver+0x82/0xf0 [ 194.362285] [<ffffffffb98b3ce3>] device_release_driver+0x23/0x30 [ 194.362343] [<ffffffffb97c86d4>] pci_stop_bus_device+0x84/0xa0 [ 194.362388] [<ffffffffb97c87e2>] pci_stop_and_remove_bus_device+0x12/0x20 [ 194.362450] [<ffffffffb97f153f>] pci_iov_remove_virtfn+0xaf/0x160 [ 194.362496] [<ffffffffb97f1aec>] sriov_disable+0x3c/0xf0 [ 194.362534] [<ffffffffb97f1bc3>] pci_disable_sriov+0x23/0x30 [ 194.362599] [<ffffffffc02f83c3>] qed_sriov_disable+0x5e3/0x650 [qed] [ 194.362658] [<ffffffffb9622df6>] ? kfree+0x106/0x140 [ 194.362709] [<ffffffffc02cc0c0>] ? qed_free_stream_mem+0x70/0x90 [qed] [ 194.362754] [<ffffffffb9622df6>] ? kfree+0x106/0x140 [ 194.362803] [<ffffffffc02cd659>] qed_slowpath_stop+0x1a9/0x1d0 [qed] [ 194.362854] [<ffffffffc035544e>] __qede_remove+0xae/0x130 [qede] [ 194.362904] [<ffffffffc03554e0>] qede_shutdown+0x10/0x20 [qede] [ 194.362956] [<ffffffffb97cf90a>] pci_device_shutdown+0x3a/0x60 [ 194.363010] [<ffffffffb98b180b>] device_shutdown+0xfb/0x1f0 [ 194.363066] [<ffffffffb94b66c6>] kernel_restart_prepare+0x36/0x40 [ 194.363107] [<ffffffffb94b66e2>] kernel_restart+0x12/0x60 [ 194.363146] [<ffffffffb94b6959>] SYSC_reboot+0x229/0x260 [ 194.363196] [<ffffffffb95f200d>] ? handle_mm_fault+0x39d/0x9b0 [ 194.363253] [<ffffffffb942b621>] ? __switch_to+0x151/0x580 [ 194.363304] [<ffffffffb9b7ec28>] ? __schedule+0x448/0x9c0 [ 194.363343] [<ffffffffb94b69fe>] SyS_reboot+0xe/0x10 [ 194.363387] [<ffffffffb9b8bede>] system_call_fastpath+0x25/0x2a [ 194.363430] Code: f9 e9 37 ff ff ff 90 0f 1f 44 00 00 55 48 89 e5 41 57 41 56 41 55 4c 8d af 98 00 00 00 41 54 4c 89 ef 41 89 f4 53 e8 4c e4 55 f9 <80> b8 dc 08 00 00 01 48 89 c3 4c 8d b8 c0 08 00 00 4c 8b b0 c0 [ 194.363712] RIP [<ffffffffc03553c4>] __qede_remove+0x24/0x130 [qede] [ 194.363764] RSP <ffff9ceabebdfac0> [ 194.363791] CR2: 00000000000008dc
Signed-off-by: Manish Chopra manishc@marvell.com Signed-off-by: Ariel Elior aelior@marvell.com Signed-off-by: Sudarsana Kalluru skalluru@marvell.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/net/ethernet/qlogic/qede/qede_main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -1170,8 +1170,16 @@ enum qede_remove_mode { static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) { struct net_device *ndev = pci_get_drvdata(pdev); - struct qede_dev *edev = netdev_priv(ndev); - struct qed_dev *cdev = edev->cdev; + struct qede_dev *edev; + struct qed_dev *cdev; + + if (!ndev) { + dev_info(&pdev->dev, "Device has already been removed\n"); + return; + } + + edev = netdev_priv(ndev); + cdev = edev->cdev;
DP_INFO(edev, "Starting qede_remove\n");
From: Claudiu Manoil claudiu.manoil@nxp.com
[ Upstream commit 7afb3e575e5aa9f5a200a3eb3f45d8130f6d6601 ]
The check that the event is actually for this device should be moved from the "port" handler to the net device handler.
Otherwise the port handler will deny bonding configuration for other net devices in the same system (like enetc in the LS1028A) that don't have the lag_upper_info->tx_type restriction that ocelot has.
Fixes: dc96ee3730fc ("net: mscc: ocelot: add bonding support") Signed-off-by: Claudiu Manoil claudiu.manoil@nxp.com Signed-off-by: Vladimir Oltean olteanv@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/net/ethernet/mscc/ocelot.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
--- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1506,9 +1506,6 @@ static int ocelot_netdevice_port_event(s struct ocelot_port *ocelot_port = netdev_priv(dev); int err = 0;
- if (!ocelot_netdevice_dev_check(dev)) - return 0; - switch (event) { case NETDEV_CHANGEUPPER: if (netif_is_bridge_master(info->upper_dev)) { @@ -1545,6 +1542,9 @@ static int ocelot_netdevice_event(struct struct net_device *dev = netdev_notifier_info_to_dev(ptr); int ret = 0;
+ if (!ocelot_netdevice_dev_check(dev)) + return 0; + if (event == NETDEV_PRECHANGEUPPER && netif_is_lag_master(info->upper_dev)) { struct netdev_lag_upper_info *lag_upper_info = info->upper_info;
From: Claudiu Manoil claudiu.manoil@nxp.com
[ Upstream commit 3b3eed8eec47259939ee6c3d58aea1c311ddee3b ]
lag_upper_info may be NULL on slave removal.
Fixes: dc96ee3730fc ("net: mscc: ocelot: add bonding support") Signed-off-by: Claudiu Manoil claudiu.manoil@nxp.com Signed-off-by: Vladimir Oltean olteanv@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/net/ethernet/mscc/ocelot.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1550,7 +1550,8 @@ static int ocelot_netdevice_event(struct struct netdev_lag_upper_info *lag_upper_info = info->upper_info; struct netlink_ext_ack *extack;
- if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { + if (lag_upper_info && + lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { extack = netdev_notifier_info_to_extack(&info->info); NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type");
From: Eric Dumazet edumazet@google.com
[ Upstream commit 1bef4c223b8588cf50433bdc2c6953d82949b3b3 ]
While looking at a syzbot KCSAN report [1], I found multiple issues in this code :
1) fib6_nh->last_probe has an initial value of 0.
While probably okay on 64bit kernels, this causes an issue on 32bit kernels since the time_after(jiffies, 0 + interval) might be false ~24 days after boot (for HZ=1000)
2) The data-race found by KCSAN I could use READ_ONCE() and WRITE_ONCE(), but we also can take the opportunity of not piling-up too many rt6_probe_deferred() works by using instead cmpxchg() so that only one cpu wins the race.
[1] BUG: KCSAN: data-race in find_match / find_match
write to 0xffff8880bb7aabe8 of 8 bytes by interrupt on cpu 1: rt6_probe net/ipv6/route.c:663 [inline] find_match net/ipv6/route.c:757 [inline] find_match+0x5bd/0x790 net/ipv6/route.c:733 __find_rr_leaf+0xe3/0x780 net/ipv6/route.c:831 find_rr_leaf net/ipv6/route.c:852 [inline] rt6_select net/ipv6/route.c:896 [inline] fib6_table_lookup+0x383/0x650 net/ipv6/route.c:2164 ip6_pol_route+0xee/0x5c0 net/ipv6/route.c:2200 ip6_pol_route_output+0x48/0x60 net/ipv6/route.c:2452 fib6_rule_lookup+0x3d6/0x470 net/ipv6/fib6_rules.c:117 ip6_route_output_flags_noref+0x16b/0x230 net/ipv6/route.c:2484 ip6_route_output_flags+0x50/0x1a0 net/ipv6/route.c:2497 ip6_dst_lookup_tail+0x25d/0xc30 net/ipv6/ip6_output.c:1049 ip6_dst_lookup_flow+0x68/0x120 net/ipv6/ip6_output.c:1150 inet6_csk_route_socket+0x2f7/0x420 net/ipv6/inet6_connection_sock.c:106 inet6_csk_xmit+0x91/0x1f0 net/ipv6/inet6_connection_sock.c:121 __tcp_transmit_skb+0xe81/0x1d60 net/ipv4/tcp_output.c:1169 tcp_transmit_skb net/ipv4/tcp_output.c:1185 [inline] tcp_xmit_probe_skb+0x19b/0x1d0 net/ipv4/tcp_output.c:3735
read to 0xffff8880bb7aabe8 of 8 bytes by interrupt on cpu 0: rt6_probe net/ipv6/route.c:657 [inline] find_match net/ipv6/route.c:757 [inline] find_match+0x521/0x790 net/ipv6/route.c:733 __find_rr_leaf+0xe3/0x780 net/ipv6/route.c:831 find_rr_leaf net/ipv6/route.c:852 [inline] rt6_select net/ipv6/route.c:896 [inline] fib6_table_lookup+0x383/0x650 net/ipv6/route.c:2164 ip6_pol_route+0xee/0x5c0 net/ipv6/route.c:2200 ip6_pol_route_output+0x48/0x60 net/ipv6/route.c:2452 fib6_rule_lookup+0x3d6/0x470 net/ipv6/fib6_rules.c:117 ip6_route_output_flags_noref+0x16b/0x230 net/ipv6/route.c:2484 ip6_route_output_flags+0x50/0x1a0 net/ipv6/route.c:2497 ip6_dst_lookup_tail+0x25d/0xc30 net/ipv6/ip6_output.c:1049 ip6_dst_lookup_flow+0x68/0x120 net/ipv6/ip6_output.c:1150 inet6_csk_route_socket+0x2f7/0x420 net/ipv6/inet6_connection_sock.c:106 inet6_csk_xmit+0x91/0x1f0 net/ipv6/inet6_connection_sock.c:121 __tcp_transmit_skb+0xe81/0x1d60 net/ipv4/tcp_output.c:1169
Reported by Kernel Concurrency Sanitizer on: CPU: 0 PID: 18894 Comm: udevd Not tainted 5.4.0-rc3+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
Fixes: cc3a86c802f0 ("ipv6: Change rt6_probe to take a fib6_nh") Fixes: f547fac624be ("ipv6: rate-limit probes for neighbourless routes") Signed-off-by: Eric Dumazet edumazet@google.com Reported-by: syzbot syzkaller@googlegroups.com Reviewed-by: David Ahern dsahern@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- net/ipv6/route.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
--- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -521,6 +521,7 @@ static void rt6_probe(struct fib6_info * { struct __rt6_probe_work *work = NULL; const struct in6_addr *nh_gw; + unsigned long last_probe; struct neighbour *neigh; struct net_device *dev; struct inet6_dev *idev; @@ -539,6 +540,7 @@ static void rt6_probe(struct fib6_info * nh_gw = &rt->fib6_nh.nh_gw; dev = rt->fib6_nh.nh_dev; rcu_read_lock_bh(); + last_probe = READ_ONCE(rt->last_probe); idev = __in6_dev_get(dev); neigh = __ipv6_neigh_lookup_noref(dev, nh_gw); if (neigh) { @@ -554,13 +556,15 @@ static void rt6_probe(struct fib6_info * __neigh_set_probe_once(neigh); } write_unlock(&neigh->lock); - } else if (time_after(jiffies, rt->last_probe + + } else if (time_after(jiffies, last_probe + idev->cnf.rtr_probe_interval)) { work = kmalloc(sizeof(*work), GFP_ATOMIC); }
- if (work) { - rt->last_probe = jiffies; + if (!work || cmpxchg(&rt->last_probe, + last_probe, jiffies) != last_probe) { + kfree(work); + } else { INIT_WORK(&work->work, rt6_probe_deferred); work->target = *nh_gw; dev_hold(dev); @@ -3066,6 +3070,9 @@ static struct fib6_info *ip6_route_info_ if (!rt) goto out;
+#ifdef CONFIG_IPV6_ROUTER_PREF + rt->last_probe = jiffies; +#endif if (cfg->fc_flags & RTF_ADDRCONF) rt->dst_nocount = true;
From: Salil Mehta salil.mehta@huawei.com
[ Upstream commit bf5a6b4c474c589244dc25ee1af2c3c829228ef8 ]
This patch fixes the problem of the spin locks, originally meant for the netpoll path of hns driver, causing deadlock in the normal NAPI poll path. The issue happened due to the presence of the stray leftover spin lock code related to the netpoll, whose support was earlier removed from the HNS[1], got activated due to enabling of NET_POLL_CONTROLLER switch.
Earlier background: The netpoll handling code originally had this bug(as identified by Marc Zyngier[2]) of wrong spin lock API being used which did not disable the interrupts and hence could cause locking issues. i.e. if the lock were first acquired in context to thread like 'ip' util and this lock if ever got later acquired again in context to the interrupt context like TX/RX (Interrupts could always pre-empt the lock holding task and acquire the lock again) and hence could cause deadlock.
Proposed Solution: 1. If the netpoll was enabled in the HNS driver, which is not right now, we could have simply used spin_[un]lock_irqsave() 2. But as netpoll is disabled, therefore, it is best to get rid of the existing locks and stray code for now. This should solve the problem reported by Marc.
[1] https://git.kernel.org/torvalds/c/4bd2c03be7 [2] https://patchwork.ozlabs.org/patch/1189139/
Fixes: 4bd2c03be707 ("net: hns: remove ndo_poll_controller") Cc: lipeng lipeng321@huawei.com Cc: Yisen Zhuang yisen.zhuang@huawei.com Cc: Eric Dumazet edumazet@google.com Cc: David S. Miller davem@davemloft.net Reported-by: Marc Zyngier maz@kernel.org Acked-by: Marc Zyngier maz@kernel.org Tested-by: Marc Zyngier maz@kernel.org Signed-off-by: Salil Mehta salil.mehta@huawei.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/net/ethernet/hisilicon/hns/hnae.c | 1 - drivers/net/ethernet/hisilicon/hns/hnae.h | 3 --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 22 +--------------------- 3 files changed, 1 insertion(+), 25 deletions(-)
--- a/drivers/net/ethernet/hisilicon/hns/hnae.c +++ b/drivers/net/ethernet/hisilicon/hns/hnae.c @@ -203,7 +203,6 @@ hnae_init_ring(struct hnae_queue *q, str
ring->q = q; ring->flags = flags; - spin_lock_init(&ring->lock); ring->coal_param = q->handle->coal_param; assert(!ring->desc && !ring->desc_cb && !ring->desc_dma_addr);
--- a/drivers/net/ethernet/hisilicon/hns/hnae.h +++ b/drivers/net/ethernet/hisilicon/hns/hnae.h @@ -278,9 +278,6 @@ struct hnae_ring { /* statistic */ struct ring_stats stats;
- /* ring lock for poll one */ - spinlock_t lock; - dma_addr_t desc_dma_addr; u32 buf_size; /* size for hnae_desc->addr, preset by AE */ u16 desc_num; /* total number of desc */ --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -947,15 +947,6 @@ static int is_valid_clean_head(struct hn return u > c ? (h > c && h <= u) : (h > c || h <= u); }
-/* netif_tx_lock will turn down the performance, set only when necessary */ -#ifdef CONFIG_NET_POLL_CONTROLLER -#define NETIF_TX_LOCK(ring) spin_lock(&(ring)->lock) -#define NETIF_TX_UNLOCK(ring) spin_unlock(&(ring)->lock) -#else -#define NETIF_TX_LOCK(ring) -#define NETIF_TX_UNLOCK(ring) -#endif - /* reclaim all desc in one budget * return error or number of desc left */ @@ -969,21 +960,16 @@ static int hns_nic_tx_poll_one(struct hn int head; int bytes, pkts;
- NETIF_TX_LOCK(ring); - head = readl_relaxed(ring->io_base + RCB_REG_HEAD); rmb(); /* make sure head is ready before touch any data */
- if (is_ring_empty(ring) || head == ring->next_to_clean) { - NETIF_TX_UNLOCK(ring); + if (is_ring_empty(ring) || head == ring->next_to_clean) return 0; /* no data to poll */ - }
if (!is_valid_clean_head(ring, head)) { netdev_err(ndev, "wrong head (%d, %d-%d)\n", head, ring->next_to_use, ring->next_to_clean); ring->stats.io_err_cnt++; - NETIF_TX_UNLOCK(ring); return -EIO; }
@@ -998,8 +984,6 @@ static int hns_nic_tx_poll_one(struct hn ring->stats.tx_pkts += pkts; ring->stats.tx_bytes += bytes;
- NETIF_TX_UNLOCK(ring); - dev_queue = netdev_get_tx_queue(ndev, ring_data->queue_index); netdev_tx_completed_queue(dev_queue, pkts, bytes);
@@ -1059,16 +1043,12 @@ static void hns_nic_tx_clr_all_bufs(stru int head; int bytes, pkts;
- NETIF_TX_LOCK(ring); - head = ring->next_to_use; /* ntu :soft setted ring position*/ bytes = 0; pkts = 0; while (head != ring->next_to_clean) hns_nic_reclaim_one_desc(ring, &bytes, &pkts);
- NETIF_TX_UNLOCK(ring); - dev_queue = netdev_get_tx_queue(ndev, ring_data->queue_index); netdev_tx_reset_queue(dev_queue); }
From: Takashi Iwai tiwai@suse.de
commit e7af6307a8a54f0b873960b32b6a644f2d0fbd97 upstream.
The clean up commit 41672c0c24a6 ("ALSA: timer: Simplify error path in snd_timer_open()") unified the error handling code paths with the standard goto, but it introduced a subtle bug: the timer instance is stored in snd_timer_open() incorrectly even if it returns an error. This may eventually lead to UAF, as spotted by fuzzer.
The culprit is the snd_timer_open() code checks the SNDRV_TIMER_IFLG_EXCLUSIVE flag with the common variable timeri. This variable is supposed to be the newly created instance, but we (ab-)used it for a temporary check before the actual creation of a timer instance. After that point, there is another check for the max number of instances, and it bails out if over the threshold. Before the refactoring above, it worked fine because the code returned directly from that point. After the refactoring, however, it jumps to the unified error path that stores the timeri variable in return -- even if it returns an error. Unfortunately this stored value is kept in the caller side (snd_timer_user_tselect()) in tu->timeri. This causes inconsistency later, as if the timer was successfully assigned.
In this patch, we fix it by not re-using timeri variable but a temporary variable for testing the exclusive connection, so timeri remains NULL at that point.
Fixes: 41672c0c24a6 ("ALSA: timer: Simplify error path in snd_timer_open()") Reported-and-tested-by: Tristan Madani tristmd@gmail.com Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20191106165547.23518-1-tiwai@suse.de Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- sound/core/timer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
--- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -298,11 +298,11 @@ int snd_timer_open(struct snd_timer_inst goto unlock; } if (!list_empty(&timer->open_list_head)) { - timeri = list_entry(timer->open_list_head.next, + struct snd_timer_instance *t = + list_entry(timer->open_list_head.next, struct snd_timer_instance, open_list); - if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) { + if (t->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) { err = -EBUSY; - timeri = NULL; goto unlock; } }
From: Takashi Sakamoto o-takashi@sakamocchi.jp
commit 706ad6746a66546daf96d4e4a95e46faf6cf689a upstream.
For Focusrite Saffire Pro i/o, the lowest 8 bits of register represents configured source of sampling clock. The next lowest 8 bits represents whether the configured source is actually detected or not just after the register is changed for the source.
Current implementation evaluates whole the register to detect configured source. This results in failure due to the next lowest 8 bits when the source is connected in advance.
This commit fixes the bug.
Fixes: 25784ec2d034 ("ALSA: bebob: Add support for Focusrite Saffire/SaffirePro series") Cc: stable@vger.kernel.org # v3.16+ Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp Link: https://lore.kernel.org/r/20191102150920.20367-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- sound/firewire/bebob/bebob_focusrite.c | 3 +++ 1 file changed, 3 insertions(+)
--- a/sound/firewire/bebob/bebob_focusrite.c +++ b/sound/firewire/bebob/bebob_focusrite.c @@ -28,6 +28,8 @@ #define SAFFIRE_CLOCK_SOURCE_SPDIF 1
/* clock sources as returned from register of Saffire Pro 10 and 26 */ +#define SAFFIREPRO_CLOCK_SOURCE_SELECT_MASK 0x000000ff +#define SAFFIREPRO_CLOCK_SOURCE_DETECT_MASK 0x0000ff00 #define SAFFIREPRO_CLOCK_SOURCE_INTERNAL 0 #define SAFFIREPRO_CLOCK_SOURCE_SKIP 1 /* never used on hardware */ #define SAFFIREPRO_CLOCK_SOURCE_SPDIF 2 @@ -190,6 +192,7 @@ saffirepro_both_clk_src_get(struct snd_b map = saffirepro_clk_maps[1];
/* In a case that this driver cannot handle the value of register. */ + value &= SAFFIREPRO_CLOCK_SOURCE_SELECT_MASK; if (value >= SAFFIREPRO_CLOCK_SOURCE_COUNT || map[value] < 0) { err = -EIO; goto end;
From: Takashi Iwai tiwai@suse.de
commit 15c2b3cc09a31620914955cb2a89c277c18ee999 upstream.
The unsolicited event handler for the headphone jack on CA0132 codec driver tries to reschedule the another delayed work with cancel_delayed_work_sync(). It's no good idea, unfortunately, especially after we changed the work queue to the standard global one; this may lead to a stall because both works are using the same global queue.
Fix it by dropping the _sync but does call cancel_delayed_work() instead.
Fixes: 993884f6a26c ("ALSA: hda/ca0132 - Delay HP amp turnon.") BugLink: https://bugzilla.suse.com/show_bug.cgi?id=1155836 Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20191105134316.19294-1-tiwai@suse.de Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- sound/pci/hda/patch_ca0132.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -6769,7 +6769,7 @@ static void hp_callback(struct hda_codec /* Delay enabling the HP amp, to let the mic-detection * state machine run. */ - cancel_delayed_work_sync(&spec->unsol_hp_work); + cancel_delayed_work(&spec->unsol_hp_work); schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500)); tbl = snd_hda_jack_tbl_get(codec, cb->nid); if (tbl)
From: Johannes Weiner hannes@cmpxchg.org
commit 869712fd3de5a90b7ba23ae1272278cddc66b37b upstream.
While upgrading from 4.16 to 5.2, we noticed these allocation errors in the log of the new kernel:
SLUB: Unable to allocate memory on node -1, gfp=0xa20(GFP_ATOMIC) cache: tw_sock_TCPv6(960:helper-logs), object size: 232, buffer size: 240, default order: 1, min order: 0 node 0: slabs: 5, objs: 170, free: 0
slab_out_of_memory+1 ___slab_alloc+969 __slab_alloc+14 kmem_cache_alloc+346 inet_twsk_alloc+60 tcp_time_wait+46 tcp_fin+206 tcp_data_queue+2034 tcp_rcv_state_process+784 tcp_v6_do_rcv+405 __release_sock+118 tcp_close+385 inet_release+46 __sock_release+55 sock_close+17 __fput+170 task_work_run+127 exit_to_usermode_loop+191 do_syscall_64+212 entry_SYSCALL_64_after_hwframe+68
accompanied by an increase in machines going completely radio silent under memory pressure.
One thing that changed since 4.16 is e699e2c6a654 ("net, mm: account sock objects to kmemcg"), which made these slab caches subject to cgroup memory accounting and control.
The problem with that is that cgroups, unlike the page allocator, do not maintain dedicated atomic reserves. As a cgroup's usage hovers at its limit, atomic allocations - such as done during network rx - can fail consistently for extended periods of time. The kernel is not able to operate under these conditions.
We don't want to revert the culprit patch, because it indeed tracks a potentially substantial amount of memory used by a cgroup.
We also don't want to implement dedicated atomic reserves for cgroups. There is no point in keeping a fixed margin of unused bytes in the cgroup's memory budget to accomodate a consumer that is impossible to predict - we'd be wasting memory and get into configuration headaches, not unlike what we have going with min_free_kbytes. We do this for physical mem because we have to, but cgroups are an accounting game.
Instead, account these privileged allocations to the cgroup, but let them bypass the configured limit if they have to. This way, we get the benefits of accounting the consumed memory and have it exert pressure on the rest of the cgroup, but like with the page allocator, we shift the burden of reclaimining on behalf of atomic allocations onto the regular allocations that can block.
Link: http://lkml.kernel.org/r/20191022233708.365764-1-hannes@cmpxchg.org Fixes: e699e2c6a654 ("net, mm: account sock objects to kmemcg") Signed-off-by: Johannes Weiner hannes@cmpxchg.org Reviewed-by: Shakeel Butt shakeelb@google.com Cc: Suleiman Souhlal suleiman@google.com Cc: Michal Hocko mhocko@kernel.org Cc: stable@vger.kernel.org [4.18+] Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- mm/memcontrol.c | 9 +++++++++ 1 file changed, 9 insertions(+)
--- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2225,6 +2225,15 @@ retry: }
/* + * Memcg doesn't have a dedicated reserve for atomic + * allocations. But like the global atomic pool, we need to + * put the burden of reclaim on regular allocation requests + * and let these go through as privileged allocations. + */ + if (gfp_mask & __GFP_ATOMIC) + goto force; + + /* * Unlike in global OOM situations, memcg is not in a physical * memory shortage. Allow dying and OOM-killed tasks to * bypass the last charges so that they can exit quickly and
From: Mel Gorman mgorman@techsingularity.net
commit 3e8fc0075e24338b1117cdff6a79477427b8dbed upstream.
Deferred memory initialisation updates zone->managed_pages during the initialisation phase but before that finishes, the per-cpu page allocator (pcpu) calculates the number of pages allocated/freed in batches as well as the maximum number of pages allowed on a per-cpu list. As zone->managed_pages is not up to date yet, the pcpu initialisation calculates inappropriately low batch and high values.
This increases zone lock contention quite severely in some cases with the degree of severity depending on how many CPUs share a local zone and the size of the zone. A private report indicated that kernel build times were excessive with extremely high system CPU usage. A perf profile indicated that a large chunk of time was lost on zone->lock contention.
This patch recalculates the pcpu batch and high values after deferred initialisation completes for every populated zone in the system. It was tested on a 2-socket AMD EPYC 2 machine using a kernel compilation workload -- allmodconfig and all available CPUs.
mmtests configuration: config-workload-kernbench-max Configuration was modified to build on a fresh XFS partition.
kernbench 5.4.0-rc3 5.4.0-rc3 vanilla resetpcpu-v2 Amean user-256 13249.50 ( 0.00%) 16401.31 * -23.79%* Amean syst-256 14760.30 ( 0.00%) 4448.39 * 69.86%* Amean elsp-256 162.42 ( 0.00%) 119.13 * 26.65%* Stddev user-256 42.97 ( 0.00%) 19.15 ( 55.43%) Stddev syst-256 336.87 ( 0.00%) 6.71 ( 98.01%) Stddev elsp-256 2.46 ( 0.00%) 0.39 ( 84.03%)
5.4.0-rc3 5.4.0-rc3 vanilla resetpcpu-v2 Duration User 39766.24 49221.79 Duration System 44298.10 13361.67 Duration Elapsed 519.11 388.87
The patch reduces system CPU usage by 69.86% and total build time by 26.65%. The variance of system CPU usage is also much reduced.
Before, this was the breakdown of batch and high values over all zones was:
256 batch: 1 256 batch: 63 512 batch: 7 256 high: 0 256 high: 378 512 high: 42
512 pcpu pagesets had a batch limit of 7 and a high limit of 42. After the patch:
256 batch: 1 768 batch: 63 256 high: 0 768 high: 378
[mgorman@techsingularity.net: fix merge/linkage snafu] Link: http://lkml.kernel.org/r/20191023084705.GD3016@techsingularity.netLink: http://lkml.kernel.org/r/20191021094808.28824-2-mgorman@techsingularity.net Signed-off-by: Mel Gorman mgorman@techsingularity.net Acked-by: Michal Hocko mhocko@suse.com Acked-by: Vlastimil Babka vbabka@suse.cz Acked-by: David Hildenbrand david@redhat.com Cc: Matt Fleming matt@codeblueprint.co.uk Cc: Thomas Gleixner tglx@linutronix.de Cc: Borislav Petkov bp@alien8.de Cc: Qian Cai cai@lca.pw Cc: stable@vger.kernel.org [4.1+] Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- mm/page_alloc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
--- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1743,6 +1743,14 @@ void __init page_alloc_init_late(void) wait_for_completion(&pgdat_init_all_done_comp);
/* + * The number of managed pages has changed due to the initialisation + * so the pcpu batch and high limits needs to be updated or the limits + * will be artificially small. + */ + for_each_populated_zone(zone) + zone_pcp_update(zone); + + /* * We initialized the rest of the deferred pages. Permanently disable * on-demand struct page initialization. */ @@ -8011,7 +8019,6 @@ void free_contig_range(unsigned long pfn } #endif
-#ifdef CONFIG_MEMORY_HOTPLUG /* * The zone indicated has a new number of managed_pages; batch sizes and percpu * page high values need to be recalulated. @@ -8025,7 +8032,6 @@ void __meminit zone_pcp_update(struct zo per_cpu_ptr(zone->pageset, cpu)); mutex_unlock(&pcp_batch_high_lock); } -#endif
void zone_pcp_reset(struct zone *zone) {
From: Yang Shi yang.shi@linux.alibaba.com
commit 169226f7e0d275c1879551f37484ef6683579a5c upstream.
We have a usecase to use tmpfs as QEMU memory backend and we would like to take the advantage of THP as well. But, our test shows the EPT is not PMD mapped even though the underlying THP are PMD mapped on host. The number showed by /sys/kernel/debug/kvm/largepage is much less than the number of PMD mapped shmem pages as the below:
7f2778200000-7f2878200000 rw-s 00000000 00:14 262232 /dev/shm/qemu_back_mem.mem.Hz2hSf (deleted) Size: 4194304 kB [snip] AnonHugePages: 0 kB ShmemPmdMapped: 579584 kB [snip] Locked: 0 kB
cat /sys/kernel/debug/kvm/largepages 12
And some benchmarks do worse than with anonymous THPs.
By digging into the code we figured out that commit 127393fbe597 ("mm: thp: kvm: fix memory corruption in KVM with THP enabled") checks if there is a single PTE mapping on the page for anonymous THP when setting up EPT map. But the _mapcount < 0 check doesn't work for page cache THP since every subpage of page cache THP would get _mapcount inc'ed once it is PMD mapped, so PageTransCompoundMap() always returns false for page cache THP. This would prevent KVM from setting up PMD mapped EPT entry.
So we need handle page cache THP correctly. However, when page cache THP's PMD gets split, kernel just remove the map instead of setting up PTE map like what anonymous THP does. Before KVM calls get_user_pages() the subpages may get PTE mapped even though it is still a THP since the page cache THP may be mapped by other processes at the mean time.
Checking its _mapcount and whether the THP has PTE mapped or not. Although this may report some false negative cases (PTE mapped by other processes), it looks not trivial to make this accurate.
With this fix /sys/kernel/debug/kvm/largepage would show reasonable pages are PMD mapped by EPT as the below:
7fbeaee00000-7fbfaee00000 rw-s 00000000 00:14 275464 /dev/shm/qemu_back_mem.mem.SKUvat (deleted) Size: 4194304 kB [snip] AnonHugePages: 0 kB ShmemPmdMapped: 557056 kB [snip] Locked: 0 kB
cat /sys/kernel/debug/kvm/largepages 271
And the benchmarks are as same as anonymous THPs.
[yang.shi@linux.alibaba.com: v4] Link: http://lkml.kernel.org/r/1571865575-42913-1-git-send-email-yang.shi@linux.al... Link: http://lkml.kernel.org/r/1571769577-89735-1-git-send-email-yang.shi@linux.al... Fixes: dd78fedde4b9 ("rmap: support file thp") Signed-off-by: Yang Shi yang.shi@linux.alibaba.com Reported-by: Gang Deng gavin.dg@linux.alibaba.com Tested-by: Gang Deng gavin.dg@linux.alibaba.com Suggested-by: Hugh Dickins hughd@google.com Acked-by: Kirill A. Shutemov kirill.shutemov@linux.intel.com Cc: Andrea Arcangeli aarcange@redhat.com Cc: Matthew Wilcox willy@infradead.org Cc: stable@vger.kernel.org [4.8+] Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- include/linux/mm.h | 5 ----- include/linux/mm_types.h | 5 +++++ include/linux/page-flags.h | 20 ++++++++++++++++++-- 3 files changed, 23 insertions(+), 7 deletions(-)
--- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -602,11 +602,6 @@ static inline void *kvcalloc(size_t n, s
extern void kvfree(const void *addr);
-static inline atomic_t *compound_mapcount_ptr(struct page *page) -{ - return &page[1].compound_mapcount; -} - static inline int compound_mapcount(struct page *page) { VM_BUG_ON_PAGE(!PageCompound(page), page); --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -226,6 +226,11 @@ struct page_frag_cache {
typedef unsigned long vm_flags_t;
+static inline atomic_t *compound_mapcount_ptr(struct page *page) +{ + return &page[1].compound_mapcount; +} + /* * A region containing a mapping of a non-memory backed file under NOMMU * conditions. These are held in a global tree and are pinned by the VMAs that --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -577,12 +577,28 @@ static inline int PageTransCompound(stru * * Unlike PageTransCompound, this is safe to be called only while * split_huge_pmd() cannot run from under us, like if protected by the - * MMU notifier, otherwise it may result in page->_mapcount < 0 false + * MMU notifier, otherwise it may result in page->_mapcount check false * positives. + * + * We have to treat page cache THP differently since every subpage of it + * would get _mapcount inc'ed once it is PMD mapped. But, it may be PTE + * mapped in the current process so comparing subpage's _mapcount to + * compound_mapcount to filter out PTE mapped case. */ static inline int PageTransCompoundMap(struct page *page) { - return PageTransCompound(page) && atomic_read(&page->_mapcount) < 0; + struct page *head; + + if (!PageTransCompound(page)) + return 0; + + if (PageAnon(page)) + return atomic_read(&page->_mapcount) < 0; + + head = compound_head(page); + /* File THP is PMD mapped and not PTE mapped */ + return atomic_read(&page->_mapcount) == + atomic_read(compound_mapcount_ptr(head)); }
/*
From: Michal Hocko mhocko@suse.com
commit abaed0112c1db08be15a784a2c5c8a8b3063cdd3 upstream.
/proc/pagetypeinfo is a debugging tool to examine internal page allocator state wrt to fragmentation. It is not very useful for any other use so normal users really do not need to read this file.
Waiman Long has noticed that reading this file can have negative side effects because zone->lock is necessary for gathering data and that a) interferes with the page allocator and its users and b) can lead to hard lockups on large machines which have very long free_list.
Reduce both issues by simply not exporting the file to regular users.
Link: http://lkml.kernel.org/r/20191025072610.18526-2-mhocko@kernel.org Fixes: 467c996c1e19 ("Print out statistics in relation to fragmentation avoidance to /proc/pagetypeinfo") Signed-off-by: Michal Hocko mhocko@suse.com Reported-by: Waiman Long longman@redhat.com Acked-by: Mel Gorman mgorman@suse.de Acked-by: Vlastimil Babka vbabka@suse.cz Acked-by: Waiman Long longman@redhat.com Acked-by: Rafael Aquini aquini@redhat.com Acked-by: David Rientjes rientjes@google.com Reviewed-by: Andrew Morton akpm@linux-foundation.org Cc: David Hildenbrand david@redhat.com Cc: Johannes Weiner hannes@cmpxchg.org Cc: Roman Gushchin guro@fb.com Cc: Konstantin Khlebnikov khlebnikov@yandex-team.ru Cc: Jann Horn jannh@google.com Cc: Song Liu songliubraving@fb.com Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: stable@vger.kernel.org Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- mm/vmstat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1972,7 +1972,7 @@ void __init init_mm_internals(void) #endif #ifdef CONFIG_PROC_FS proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op); - proc_create_seq("pagetypeinfo", 0444, NULL, &pagetypeinfo_op); + proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op); proc_create_seq("vmstat", 0444, NULL, &vmstat_op); proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op); #endif
From: Kevin Hao haokexin@gmail.com
commit 5cbf2fff3bba8d3c6a4d47c1754de1cf57e2b01f upstream.
In the current code, we use the atomic_cmpxchg() to serialize the output of the dump_stack(), but this implementation suffers the thundering herd problem. We have observed such kind of livelock on a Marvell cn96xx board(24 cpus) when heavily using the dump_stack() in a kprobe handler. Actually we can let the competitors to wait for the releasing of the lock before jumping to atomic_cmpxchg(). This will definitely mitigate the thundering herd problem. Thanks Linus for the suggestion.
[akpm@linux-foundation.org: fix comment] Link: http://lkml.kernel.org/r/20191030031637.6025-1-haokexin@gmail.com Fixes: b58d977432c8 ("dump_stack: serialize the output from dump_stack()") Signed-off-by: Kevin Hao haokexin@gmail.com Suggested-by: Linus Torvalds torvalds@linux-foundation.org Cc: stable@vger.kernel.org Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- lib/dump_stack.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
--- a/lib/dump_stack.c +++ b/lib/dump_stack.c @@ -106,7 +106,12 @@ retry: was_locked = 1; } else { local_irq_restore(flags); - cpu_relax(); + /* + * Wait for the lock to release before jumping to + * atomic_cmpxchg() in order to mitigate the thundering herd + * problem. + */ + do { cpu_relax(); } while (atomic_read(&dump_lock) != -1); goto retry; }
From: Shuah Khan skhan@linuxfoundation.org
commit 4a6a6f5c4aeedb72db871d60bfcca89835f317aa upstream.
make TARGETS=gpio kselftest fails with:
Makefile:23: tools/build/Makefile.include: No such file or directory
When the gpio tool make is invoked from tools Makefile, srctree is cleared and the current logic check for srctree equals to empty string to determine srctree location from CURDIR.
When the build in invoked from selftests/gpio Makefile, the srctree is set to "." and the same logic used for srctree equals to empty is needed to determine srctree.
Check building_out_of_srctree undefined as the condition for both cases to fix "make TARGETS=gpio kselftest" build failure.
Cc: stable@vger.kernel.org Signed-off-by: Shuah Khan skhan@linuxfoundation.org Signed-off-by: Bartosz Golaszewski bgolaszewski@baylibre.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- tools/gpio/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
--- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile @@ -3,7 +3,11 @@ include ../scripts/Makefile.include
bindir ?= /usr/bin
-ifeq ($(srctree),) +# This will work when gpio is built in tools env. where srctree +# isn't set and when invoked from selftests build, where srctree +# is set to ".". building_out_of_srctree is undefined for in srctree +# builds +ifndef building_out_of_srctree srctree := $(patsubst %/,%,$(dir $(CURDIR))) srctree := $(patsubst %/,%,$(dir $(srctree))) endif
From: Jiri Olsa jolsa@kernel.org
commit 722ddfde366fd46205456a9c5ff9b3359dc9a75e upstream.
The final sort might get confused when the comparison is done over bigger numbers than int like for -s time.
Check the following report for longer workloads:
$ perf report -s time -F time,overhead --stdio
Fix hist_entry__sort() to properly return int64_t and not possible cut int.
Fixes: 043ca389a318 ("perf tools: Use hpp formats to sort final output") Signed-off-by: Jiri Olsa jolsa@kernel.org Reviewed-by: Andi Kleen ak@linux.intel.com Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Michael Petlan mpetlan@redhat.com Cc: Namhyung Kim namhyung@kernel.org Cc: Peter Zijlstra peterz@infradead.org Cc: stable@vger.kernel.org # v3.16+ Link: http://lore.kernel.org/lkml/20191104232711.16055-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo acme@redhat.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- tools/perf/util/hist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1508,7 +1508,7 @@ int hists__collapse_resort(struct hists return 0; }
-static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b) +static int64_t hist_entry__sort(struct hist_entry *a, struct hist_entry *b) { struct hists *hists = a->hists; struct perf_hpp_fmt *fmt;
From: Alex Deucher alexander.deucher@amd.com
commit 2c409ba81be25516afe05ae27a4a15da01740b01 upstream.
Need to set the dte flag on this asic.
Port the fix from amdgpu: 5cb818b861be114 ("drm/amd/amdgpu: fix si_enable_smc_cac() failed issue")
Reviewed-by: Yong Zhao yong.zhao@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/gpu/drm/radeon/si_dpm.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -1956,6 +1956,7 @@ static void si_initialize_powertune_defa case 0x682C: si_pi->cac_weights = cac_weights_cape_verde_pro; si_pi->dte_data = dte_data_sun_xt; + update_dte_from_pl2 = true; break; case 0x6825: case 0x6827:
From: Jason Gerecke killertofu@gmail.com
commit ff479731c3859609530416a18ddb3db5db019b66 upstream.
The HID descriptors for most Wacom devices oddly declare the serial number and other related fields as signed integers. When these numbers are ingested by the HID subsystem, they are automatically sign-extended into 32-bit integers. We treat the fields as unsigned elsewhere in the kernel and userspace, however, so this sign-extension causes problems. In particular, the sign-extended tool ID sent to userspace as ABS_MISC does not properly match unsigned IDs used by xf86-input-wacom and libwacom.
We introduce a function 'wacom_s32tou' that can undo the automatic sign extension performed by 'hid_snto32'. We call this function when processing the serial number and related fields to ensure that we are dealing with and reporting the unsigned form. We opt to use this method rather than adding a descriptor fixup in 'wacom_hid_usage_quirk' since it should be more robust in the face of future devices.
Ref: https://github.com/linuxwacom/input-wacom/issues/134 Fixes: f85c9dc678 ("HID: wacom: generic: Support tool ID and additional tool types") CC: stable@vger.kernel.org # v4.10+ Signed-off-by: Jason Gerecke jason.gerecke@wacom.com Reviewed-by: Aaron Armstrong Skomra aaron.skomra@wacom.com Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/hid/wacom.h | 15 +++++++++++++++ drivers/hid/wacom_wac.c | 10 ++++++---- 2 files changed, 21 insertions(+), 4 deletions(-)
--- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -205,6 +205,21 @@ static inline void wacom_schedule_work(s } }
+/* + * Convert a signed 32-bit integer to an unsigned n-bit integer. Undoes + * the normally-helpful work of 'hid_snto32' for fields that use signed + * ranges for questionable reasons. + */ +static inline __u32 wacom_s32tou(s32 value, __u8 n) +{ + switch (n) { + case 8: return ((__u8)value); + case 16: return ((__u16)value); + case 32: return ((__u32)value); + } + return value & (1 << (n - 1)) ? value & (~(~0U << n)) : value; +} + extern const struct hid_device_id wacom_ids[];
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len); --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2271,7 +2271,7 @@ static void wacom_wac_pen_event(struct h case HID_DG_TOOLSERIALNUMBER: if (value) { wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL); - wacom_wac->serial[0] |= (__u32)value; + wacom_wac->serial[0] |= wacom_s32tou(value, field->report_size); } return; case HID_DG_TWIST: @@ -2287,15 +2287,17 @@ static void wacom_wac_pen_event(struct h return; case WACOM_HID_WD_SERIALHI: if (value) { + __u32 raw_value = wacom_s32tou(value, field->report_size); + wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF); - wacom_wac->serial[0] |= ((__u64)value) << 32; + wacom_wac->serial[0] |= ((__u64)raw_value) << 32; /* * Non-USI EMR devices may contain additional tool type * information here. See WACOM_HID_WD_TOOLTYPE case for * more details. */ if (value >> 20 == 1) { - wacom_wac->id[0] |= value & 0xFFFFF; + wacom_wac->id[0] |= raw_value & 0xFFFFF; } } return; @@ -2307,7 +2309,7 @@ static void wacom_wac_pen_event(struct h * bitwise OR so the complete value can be built * up over time :( */ - wacom_wac->id[0] |= value; + wacom_wac->id[0] |= wacom_s32tou(value, field->report_size); return; case WACOM_HID_WD_OFFSETLEFT: if (features->offset_left && value != features->offset_left)
Hi!
From: Jason Gerecke killertofu@gmail.com
commit ff479731c3859609530416a18ddb3db5db019b66 upstream.
The HID descriptors for most Wacom devices oddly declare the serial number and other related fields as signed integers. When these numbers are ingested by the HID subsystem, they are automatically sign-extended into 32-bit integers. We treat the fields as unsigned elsewhere in the kernel and userspace, however, so this sign-extension causes problems. In particular, the sign-extended tool ID sent to userspace as ABS_MISC does not properly match unsigned IDs used by xf86-input-wacom and libwacom.
We introduce a function 'wacom_s32tou' that can undo the automatic sign extension performed by 'hid_snto32'. We call this function when processing the serial number and related fields to ensure that we are dealing with and reporting the unsigned form. We opt to use this method rather than adding a descriptor fixup in 'wacom_hid_usage_quirk' since it should be more robust in the face of future devices.
+++ b/drivers/hid/wacom.h @@ -205,6 +205,21 @@ static inline void wacom_schedule_work(s } } +/*
- Convert a signed 32-bit integer to an unsigned n-bit integer. Undoes
- the normally-helpful work of 'hid_snto32' for fields that use signed
- ranges for questionable reasons.
- */
+static inline __u32 wacom_s32tou(s32 value, __u8 n) +{
- switch (n) {
- case 8: return ((__u8)value);
- case 16: return ((__u16)value);
- case 32: return ((__u32)value);
- }
- return value & (1 << (n - 1)) ? value & (~(~0U << n)) : value;
+}
Can we do something like:
BUG_ON(n>32); if (n==32) return ((__u32)value); return value & ((1 << n) - 1);
instead?
Best regards, Pavel
On Wed, 13 Nov 2019, Pavel Machek wrote:
From: Jason Gerecke killertofu@gmail.com
commit ff479731c3859609530416a18ddb3db5db019b66 upstream.
The HID descriptors for most Wacom devices oddly declare the serial number and other related fields as signed integers. When these numbers are ingested by the HID subsystem, they are automatically sign-extended into 32-bit integers. We treat the fields as unsigned elsewhere in the kernel and userspace, however, so this sign-extension causes problems. In particular, the sign-extended tool ID sent to userspace as ABS_MISC does not properly match unsigned IDs used by xf86-input-wacom and libwacom.
We introduce a function 'wacom_s32tou' that can undo the automatic sign extension performed by 'hid_snto32'. We call this function when processing the serial number and related fields to ensure that we are dealing with and reporting the unsigned form. We opt to use this method rather than adding a descriptor fixup in 'wacom_hid_usage_quirk' since it should be more robust in the face of future devices.
+++ b/drivers/hid/wacom.h @@ -205,6 +205,21 @@ static inline void wacom_schedule_work(s } } +/*
- Convert a signed 32-bit integer to an unsigned n-bit integer. Undoes
- the normally-helpful work of 'hid_snto32' for fields that use signed
- ranges for questionable reasons.
- */
+static inline __u32 wacom_s32tou(s32 value, __u8 n) +{
- switch (n) {
- case 8: return ((__u8)value);
- case 16: return ((__u16)value);
- case 32: return ((__u32)value);
- }
- return value & (1 << (n - 1)) ? value & (~(~0U << n)) : value;
+}
Can we do something like:
BUG_ON(n>32);
Please no BUG_ON()s in bitop helpers.
Thanks,
From: Jiri Kosina jikos@kernel.org Sent: Wednesday, November 13, 2019 3:02 AM To: Pavel Machek pavel@denx.de Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org; linux-kernel@vger.kernel.org linux-kernel@vger.kernel.org; stable@vger.kernel.org stable@vger.kernel.org; Gerecke, Jason Jason.Gerecke@wacom.com; Skomra, Aaron Aaron.Skomra@wacom.com Subject: Re: [PATCH 4.19 027/125] HID: wacom: generic: Treat serial number and related fields as unsigned
[EXTERNAL]
On Wed, 13 Nov 2019, Pavel Machek wrote:
From: Jason Gerecke killertofu@gmail.com
commit ff479731c3859609530416a18ddb3db5db019b66 upstream.
The HID descriptors for most Wacom devices oddly declare the serial number and other related fields as signed integers. When these numbers are ingested by the HID subsystem, they are automatically sign-extended into 32-bit integers. We treat the fields as unsigned elsewhere in the kernel and userspace, however, so this sign-extension causes problems. In particular, the sign-extended tool ID sent to userspace as ABS_MISC does not properly match unsigned IDs used by xf86-input-wacom and libwacom.
We introduce a function 'wacom_s32tou' that can undo the automatic sign extension performed by 'hid_snto32'. We call this function when processing the serial number and related fields to ensure that we are dealing with and reporting the unsigned form. We opt to use this method rather than adding a descriptor fixup in 'wacom_hid_usage_quirk' since it should be more robust in the face of future devices.
+++ b/drivers/hid/wacom.h @@ -205,6 +205,21 @@ static inline void wacom_schedule_work(s } }
+/*
- Convert a signed 32-bit integer to an unsigned n-bit integer. Undoes
- the normally-helpful work of 'hid_snto32' for fields that use signed
- ranges for questionable reasons.
- */
+static inline __u32 wacom_s32tou(s32 value, __u8 n) +{
- switch (n) {
- case 8: return ((__u8)value);
- case 16: return ((__u16)value);
- case 32: return ((__u32)value);
- }
- return value & (1 << (n - 1)) ? value & (~(~0U << n)) : value;
+}
Can we do something like:
The implementation here was copied from 'hid_snto32' (except, of course, to make it convert signed to unsigned). That function provides justification for how it is written, but if changes make sense then we should probably do them to both this and 'hid_snto32'.
Jason
BUG_ON(n>32);
Please no BUG_ON()s in bitop helpers.
Thanks,
-- Jiri Kosina SUSE Labs
From: Michal Suchanek msuchanek@suse.de
commit 52eb063d153ac310058fbaa91577a72c0e7a7169 upstream.
The device cannot be probed on !ACPI and gives this warning:
drivers/soundwire/slave.c:16:12: warning: ‘sdw_slave_add’ defined but not used [-Wunused-function] static int sdw_slave_add(struct sdw_bus *bus, ^~~~~~~~~~~~~
Cc: stable@vger.kernel.org Fixes: 7c3cd189b86d ("soundwire: Add Master registration") Signed-off-by: Michal Suchanek msuchanek@suse.de Link: https://lore.kernel.org/r/bd685232ea511251eeb9554172f1524eabf9a46e.157009762... Signed-off-by: Vinod Koul vkoul@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/soundwire/Kconfig | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/soundwire/Kconfig +++ b/drivers/soundwire/Kconfig @@ -4,6 +4,7 @@
menuconfig SOUNDWIRE tristate "SoundWire support" + depends on ACPI help SoundWire is a 2-Pin interface with data and clock line ratified by the MIPI Alliance. SoundWire is used for transporting data
From: Bard Liao yung-chuan.liao@linux.intel.com
commit f1fac63af678b2fc1044ca71fedf1f2ae8bf7c3b upstream.
port_status[port_num] are assigned for each port_num in some if conditions. So some of the port_status may not be initialized.
Signed-off-by: Bard Liao yung-chuan.liao@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Link: https://lore.kernel.org/r/20190829181135.16049-1-yung-chuan.liao@linux.intel... Signed-off-by: Vinod Koul vkoul@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/soundwire/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -805,7 +805,7 @@ static int sdw_handle_port_interrupt(str static int sdw_handle_slave_alerts(struct sdw_slave *slave) { struct sdw_slave_intr_status slave_intr; - u8 clear = 0, bit, port_status[15]; + u8 clear = 0, bit, port_status[15] = {0}; int port_num, stat, ret, count = 0; unsigned long port; bool slave_notify = false;
From: Catalin Marinas catalin.marinas@arm.com
commit 6767df245f4736d0cf0c6fb7cf9cf94b27414245 upstream.
Following commit 73e86cb03cf2 ("arm64: Move PTE_RDONLY bit handling out of set_pte_at()"), the PTE_RDONLY bit is no longer managed by set_pte_at() but built into the PAGE_* attribute definitions. Consequently, pte_same() must include this bit when checking two PTEs for equality.
Remove the arm64-specific pte_same() function, practically reverting commit 747a70e60b72 ("arm64: Fix copy-on-write referencing in HugeTLB")
Fixes: 73e86cb03cf2 ("arm64: Move PTE_RDONLY bit handling out of set_pte_at()") Cc: stable@vger.kernel.org # 4.14.x- Cc: Will Deacon will@kernel.org Cc: Steve Capper steve.capper@arm.com Reported-by: John Stultz john.stultz@linaro.org Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Will Deacon will@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- arch/arm64/include/asm/pgtable.h | 17 ----------------- 1 file changed, 17 deletions(-)
--- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -274,23 +274,6 @@ static inline void set_pte_at(struct mm_ set_pte(ptep, pte); }
-#define __HAVE_ARCH_PTE_SAME -static inline int pte_same(pte_t pte_a, pte_t pte_b) -{ - pteval_t lhs, rhs; - - lhs = pte_val(pte_a); - rhs = pte_val(pte_b); - - if (pte_present(pte_a)) - lhs &= ~PTE_RDONLY; - - if (pte_present(pte_b)) - rhs &= ~PTE_RDONLY; - - return (lhs == rhs); -} - /* * Huge pte definitions. */
From: Luis Henriques lhenriques@suse.com
commit ea60ed6fcf29eebc78f2ce91491e6309ee005a01 upstream.
KASAN reports a use-after-free when running xfstest generic/531, with the following trace:
[ 293.903362] kasan_report+0xe/0x20 [ 293.903365] rb_erase+0x1f/0x790 [ 293.903370] __ceph_remove_cap+0x201/0x370 [ 293.903375] __ceph_remove_caps+0x4b/0x70 [ 293.903380] ceph_evict_inode+0x4e/0x360 [ 293.903386] evict+0x169/0x290 [ 293.903390] __dentry_kill+0x16f/0x250 [ 293.903394] dput+0x1c6/0x440 [ 293.903398] __fput+0x184/0x330 [ 293.903404] task_work_run+0xb9/0xe0 [ 293.903410] exit_to_usermode_loop+0xd3/0xe0 [ 293.903413] do_syscall_64+0x1a0/0x1c0 [ 293.903417] entry_SYSCALL_64_after_hwframe+0x44/0xa9
This happens because __ceph_remove_cap() may queue a cap release (__ceph_queue_cap_release) which can be scheduled before that cap is removed from the inode list with
rb_erase(&cap->ci_node, &ci->i_caps);
And, when this finally happens, the use-after-free will occur.
This can be fixed by removing the cap from the inode list before being removed from the session list, and thus eliminating the risk of an UAF.
Cc: stable@vger.kernel.org Signed-off-by: Luis Henriques lhenriques@suse.com Reviewed-by: Jeff Layton jlayton@kernel.org Signed-off-by: Ilya Dryomov idryomov@gmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- fs/ceph/caps.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
--- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1053,6 +1053,11 @@ void __ceph_remove_cap(struct ceph_cap *
dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode);
+ /* remove from inode's cap rbtree, and clear auth cap */ + rb_erase(&cap->ci_node, &ci->i_caps); + if (ci->i_auth_cap == cap) + ci->i_auth_cap = NULL; + /* remove from session list */ spin_lock(&session->s_cap_lock); if (session->s_cap_iterator == cap) { @@ -1088,11 +1093,6 @@ void __ceph_remove_cap(struct ceph_cap *
spin_unlock(&session->s_cap_lock);
- /* remove from inode list */ - rb_erase(&cap->ci_node, &ci->i_caps); - if (ci->i_auth_cap == cap) - ci->i_auth_cap = NULL; - if (removed) ceph_put_cap(mdsc, cap);
From: Al Viro viro@zeniv.linux.org.uk
commit 1f08529c84cfecaf1261ed9b7e17fab18541c58f upstream.
We should not play with dcache without parent locked...
Cc: stable@vger.kernel.org Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Jeff Layton jlayton@kernel.org Signed-off-by: Ilya Dryomov idryomov@gmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- fs/ceph/inode.c | 1 + 1 file changed, 1 insertion(+)
--- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1399,6 +1399,7 @@ retry_lookup: dout(" final dn %p\n", dn); } else if ((req->r_op == CEPH_MDS_OP_LOOKUPSNAP || req->r_op == CEPH_MDS_OP_MKSNAP) && + test_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags) && !test_bit(CEPH_MDS_R_ABORTED, &req->r_req_flags)) { struct dentry *dn = req->r_dentry; struct inode *dir = req->r_parent;
From: Fabrice Gasnier fabrice.gasnier@st.com
commit e6afcf6c598d6f3a0c9c408bfeddb3f5730608b0 upstream.
There maybe a race when using dmaengine_terminate_all(). The predisable routine may call iio_triggered_buffer_predisable() prior to a pending DMA callback. Adopt dmaengine_terminate_sync() to ensure there's no pending DMA request before calling iio_triggered_buffer_predisable().
Fixes: 2763ea0585c9 ("iio: adc: stm32: add optional dma support")
Signed-off-by: Fabrice Gasnier fabrice.gasnier@st.com Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron Jonathan.Cameron@huawei.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/iio/adc/stm32-adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1340,7 +1340,7 @@ static int stm32_adc_dma_start(struct ii cookie = dmaengine_submit(desc); ret = dma_submit_error(cookie); if (ret) { - dmaengine_terminate_all(adc->dma_chan); + dmaengine_terminate_sync(adc->dma_chan); return ret; }
@@ -1413,7 +1413,7 @@ static int stm32_adc_buffer_predisable(s dev_err(&indio_dev->dev, "predisable failed\n");
if (adc->dma_chan) - dmaengine_terminate_all(adc->dma_chan); + dmaengine_terminate_sync(adc->dma_chan);
if (stm32_adc_set_trig(indio_dev, NULL)) dev_err(&indio_dev->dev, "Can't clear trigger\n");
From: Alexandru Ardelean alexandru.ardelean@analog.com
commit 24e1eb5c0d78cfb9750b690bbe997d4d59170258 upstream.
It could happen that either `val` or `val2` [provided from userspace] is negative. In that case the computed frequency could get a weird value.
Fix this by checking that neither of the 2 variables is negative, and check that the computed result is not-zero.
Fixes: e4f959390178 ("iio: imu: adis16480 switch sampling frequency attr to core support") Signed-off-by: Alexandru Ardelean alexandru.ardelean@analog.com Cc: Stable@vger.kernel.org Signed-off-by: Jonathan Cameron Jonathan.Cameron@huawei.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/iio/imu/adis16480.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
--- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -270,8 +270,11 @@ static int adis16480_set_freq(struct iio struct adis16480 *st = iio_priv(indio_dev); unsigned int t;
+ if (val < 0 || val2 < 0) + return -EINVAL; + t = val * 1000 + val2 / 1000; - if (t <= 0) + if (t == 0) return -EINVAL;
t = 2460000 / t;
From: Andreas Klinger ak@it-klinger.de
commit 431f7667bd6889a274913162dfd19cce9d84848e upstream.
The measured time value in the driver is limited to the maximum distance which can be read by the sensor. This limitation was wrong and is fixed by this patch.
It also takes into account that we are supporting a variety of sensors today and that the recently added sensors have a higher maximum distance range.
Changes in v2: - Added a Tested-by
Suggested-by: Zbyněk Kocur zbynek.kocur@fel.cvut.cz Tested-by: Zbyněk Kocur zbynek.kocur@fel.cvut.cz Signed-off-by: Andreas Klinger ak@it-klinger.de Cc:Stable@vger.kernel.org Signed-off-by: Jonathan Cameron Jonathan.Cameron@huawei.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/iio/proximity/srf04.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-)
--- a/drivers/iio/proximity/srf04.c +++ b/drivers/iio/proximity/srf04.c @@ -105,7 +105,7 @@ static int srf04_read(struct srf04_data udelay(10); gpiod_set_value(data->gpiod_trig, 0);
- /* it cannot take more than 20 ms */ + /* it should not take more than 20 ms until echo is rising */ ret = wait_for_completion_killable_timeout(&data->rising, HZ/50); if (ret < 0) { mutex_unlock(&data->lock); @@ -115,7 +115,8 @@ static int srf04_read(struct srf04_data return -ETIMEDOUT; }
- ret = wait_for_completion_killable_timeout(&data->falling, HZ/50); + /* it cannot take more than 50 ms until echo is falling */ + ret = wait_for_completion_killable_timeout(&data->falling, HZ/20); if (ret < 0) { mutex_unlock(&data->lock); return ret; @@ -130,19 +131,19 @@ static int srf04_read(struct srf04_data
dt_ns = ktime_to_ns(ktime_dt); /* - * measuring more than 3 meters is beyond the capabilities of - * the sensor + * measuring more than 6,45 meters is beyond the capabilities of + * the supported sensors * ==> filter out invalid results for not measuring echos of * another us sensor * * formula: - * distance 3 m - * time = ---------- = --------- = 9404389 ns - * speed 319 m/s + * distance 6,45 * 2 m + * time = ---------- = ------------ = 40438871 ns + * speed 319 m/s * * using a minimum speed at -20 °C of 319 m/s */ - if (dt_ns > 9404389) + if (dt_ns > 40438871) return -EIO;
time_ns = dt_ns; @@ -154,20 +155,20 @@ static int srf04_read(struct srf04_data * with Temp in °C * and speed in m/s * - * use 343 m/s as ultrasonic speed at 20 °C here in absence of the + * use 343,5 m/s as ultrasonic speed at 20 °C here in absence of the * temperature * * therefore: - * time 343 - * distance = ------ * ----- - * 10^6 2 + * time 343,5 time * 106 + * distance = ------ * ------- = ------------ + * 10^6 2 617176 * with time in ns * and distance in mm (one way) * - * because we limit to 3 meters the multiplication with 343 just + * because we limit to 6,45 meters the multiplication with 106 just * fits into 32 bit */ - distance_mm = time_ns * 343 / 2000000; + distance_mm = time_ns * 106 / 617176;
return distance_mm; }
From: Ondrej Jirman megous@megous.com
commit e690053e97e7a9c968df9a97cef9089dfa8e6a44 upstream.
PRCM_PWROFF_GATING_REG has CPU0 at bit 4 on A83T. So without this patch, instead of gating the CPU0, the whole cluster was power gated, when shutting down first CPU in the cluster.
Fixes: 6961275e72a8c1 ("ARM: sun8i: smp: Add support for A83T") Signed-off-by: Ondrej Jirman megous@megous.com Acked-by: Chen-Yu Tsai wens@csie.org Cc: stable@vger.kernel.org Signed-off-by: Maxime Ripard mripard@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- arch/arm/mach-sunxi/mc_smp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
--- a/arch/arm/mach-sunxi/mc_smp.c +++ b/arch/arm/mach-sunxi/mc_smp.c @@ -478,14 +478,18 @@ static void sunxi_mc_smp_cpu_die(unsigne static int sunxi_cpu_powerdown(unsigned int cpu, unsigned int cluster) { u32 reg; + int gating_bit = cpu;
pr_debug("%s: cluster %u cpu %u\n", __func__, cluster, cpu); if (cpu >= SUNXI_CPUS_PER_CLUSTER || cluster >= SUNXI_NR_CLUSTERS) return -EINVAL;
+ if (is_a83t && cpu == 0) + gating_bit = 4; + /* gate processor power */ reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster)); - reg |= PRCM_PWROFF_GATING_REG_CORE(cpu); + reg |= PRCM_PWROFF_GATING_REG_CORE(gating_bit); writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster)); udelay(20);
From: Lukas Wunner lukas@wunner.de
commit 250367c59e6ba0d79d702a059712d66edacd4a1a upstream.
Invoking the following commands on a 32-bit architecture with strict alignment requirements (such as an ARMv7-based Raspberry Pi) results in an alignment exception:
# nft add table ip test-ip4 # nft add chain ip test-ip4 output { type filter hook output priority 0; } # nft add rule ip test-ip4 output quota 1025 bytes
Alignment trap: not handling instruction e1b26f9f at [<7f4473f8>] Unhandled fault: alignment exception (0x001) at 0xb832e824 Internal error: : 1 [#1] PREEMPT SMP ARM Hardware name: BCM2835 [<7f4473fc>] (nft_quota_do_init [nft_quota]) [<7f447448>] (nft_quota_init [nft_quota]) [<7f4260d0>] (nf_tables_newrule [nf_tables]) [<7f4168dc>] (nfnetlink_rcv_batch [nfnetlink]) [<7f416bd0>] (nfnetlink_rcv [nfnetlink]) [<8078b334>] (netlink_unicast) [<8078b664>] (netlink_sendmsg) [<8071b47c>] (sock_sendmsg) [<8071bd18>] (___sys_sendmsg) [<8071ce3c>] (__sys_sendmsg) [<8071ce94>] (sys_sendmsg)
The reason is that nft_quota_do_init() calls atomic64_set() on an atomic64_t which is only aligned to 32-bit, not 64-bit, because it succeeds struct nft_expr in memory which only contains a 32-bit pointer. Fix by aligning the nft_expr private data to 64-bit.
Fixes: 96518518cc41 ("netfilter: add nftables") Signed-off-by: Lukas Wunner lukas@wunner.de Cc: stable@vger.kernel.org # v3.13+ Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- include/net/netfilter/nf_tables.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
--- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -793,7 +793,8 @@ struct nft_expr_ops { */ struct nft_expr { const struct nft_expr_ops *ops; - unsigned char data[]; + unsigned char data[] + __attribute__((aligned(__alignof__(u64)))); };
static inline void *nft_expr_priv(const struct nft_expr *expr)
From: Dan Carpenter dan.carpenter@oracle.com
commit 30b7244d79651460ff114ba8f7987ed94c86b99a upstream.
The copy_to_user() function returns the number of bytes remaining to be copied. In this code, that positive return is checked at the end of the function and we return zero/success. What we should do instead is return -EFAULT.
Fixes: a7b4f989a629 ("netfilter: ipset: IP set core support") Signed-off-by: Dan Carpenter dan.carpenter@oracle.com Signed-off-by: Jozsef Kadlecsik kadlec@netfilter.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- net/netfilter/ipset/ip_set_core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
--- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1977,8 +1977,9 @@ ip_set_sockfn_get(struct sock *sk, int o }
req_version->version = IPSET_PROTOCOL; - ret = copy_to_user(user, req_version, - sizeof(struct ip_set_req_version)); + if (copy_to_user(user, req_version, + sizeof(struct ip_set_req_version))) + ret = -EFAULT; goto done; } case IP_SET_OP_GET_BYNAME: { @@ -2035,7 +2036,8 @@ ip_set_sockfn_get(struct sock *sk, int o } /* end of switch(op) */
copy: - ret = copy_to_user(user, data, copylen); + if (copy_to_user(user, data, copylen)) + ret = -EFAULT;
done: vfree(data);
From: Alexander Shishkin alexander.shishkin@linux.intel.com
commit 3adbb5718dd5264666ddbc2b9b43799d292e9cb6 upstream.
This adds support for Intel TH on Comet Lake PCH.
Signed-off-by: Alexander Shishkin alexander.shishkin@linux.intel.com Reviewed-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20191028070651.9770-7-alexander.shishkin@linux.int... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/hwtracing/intel_th/pci.c | 5 +++++ 1 file changed, 5 insertions(+)
--- a/drivers/hwtracing/intel_th/pci.c +++ b/drivers/hwtracing/intel_th/pci.c @@ -176,6 +176,11 @@ static const struct pci_device_id intel_ .driver_data = (kernel_ulong_t)&intel_th_2x, }, { + /* Comet Lake PCH */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x06a6), + .driver_data = (kernel_ulong_t)&intel_th_2x, + }, + { /* Ice Lake NNPI */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x45c5), .driver_data = (kernel_ulong_t)&intel_th_2x,
From: Alexander Shishkin alexander.shishkin@linux.intel.com
commit 9d55499d8da49e9261e95a490f3fda41d955f505 upstream.
This adds support for Intel TH on Jasper Lake PCH.
Signed-off-by: Alexander Shishkin alexander.shishkin@linux.intel.com Reviewed-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20191028070651.9770-8-alexander.shishkin@linux.int... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/hwtracing/intel_th/pci.c | 5 +++++ 1 file changed, 5 insertions(+)
--- a/drivers/hwtracing/intel_th/pci.c +++ b/drivers/hwtracing/intel_th/pci.c @@ -190,6 +190,11 @@ static const struct pci_device_id intel_ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa0a6), .driver_data = (kernel_ulong_t)&intel_th_2x, }, + { + /* Jasper Lake PCH */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4da6), + .driver_data = (kernel_ulong_t)&intel_th_2x, + }, { 0 }, };
From: Jan Beulich jbeulich@suse.com
commit fe6f85ca121e9c74e7490fe66b0c5aae38e332c3 upstream.
The removal of the LDR initialization in the bigsmp_32 APIC code unearthed a problem in setup_local_APIC().
The code checks unconditionally for a mismatch of the logical APIC id by comparing the early APIC id which was initialized in get_smp_config() with the actual LDR value in the APIC.
Due to the removal of the bogus LDR initialization the check now can trigger on bigsmp_32 APIC systems emitting a warning for every booting CPU. This is of course a false positive because the APIC is not using logical destination mode.
Restrict the check and the possibly resulting fixup to systems which are actually using the APIC in logical destination mode.
[ tglx: Massaged changelog and added Cc stable ]
Fixes: bae3a8d3308 ("x86/apic: Do not initialize LDR and DFR for bigsmp") Signed-off-by: Jan Beulich jbeulich@suse.com Signed-off-by: Thomas Gleixner tglx@linutronix.de Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/666d8f91-b5a8-1afd-7add-821e72a35f03@suse.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- arch/x86/kernel/apic/apic.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-)
--- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1528,9 +1528,6 @@ static void setup_local_APIC(void) { int cpu = smp_processor_id(); unsigned int value; -#ifdef CONFIG_X86_32 - int logical_apicid, ldr_apicid; -#endif
if (disable_apic) { @@ -1571,16 +1568,21 @@ static void setup_local_APIC(void) apic->init_apic_ldr();
#ifdef CONFIG_X86_32 - /* - * APIC LDR is initialized. If logical_apicid mapping was - * initialized during get_smp_config(), make sure it matches the - * actual value. - */ - logical_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu); - ldr_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR)); - WARN_ON(logical_apicid != BAD_APICID && logical_apicid != ldr_apicid); - /* always use the value from LDR */ - early_per_cpu(x86_cpu_to_logical_apicid, cpu) = ldr_apicid; + if (apic->dest_logical) { + int logical_apicid, ldr_apicid; + + /* + * APIC LDR is initialized. If logical_apicid mapping was + * initialized during get_smp_config(), make sure it matches + * the actual value. + */ + logical_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu); + ldr_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR)); + if (logical_apicid != BAD_APICID) + WARN_ON(logical_apicid != ldr_apicid); + /* Always use the value from LDR. */ + early_per_cpu(x86_cpu_to_logical_apicid, cpu) = ldr_apicid; + } #endif
/*
From: Pavel Shilovsky pshilov@microsoft.com
commit d243af7ab9feb49f11f2c0050d2077e2d9556f9b upstream.
When the client hits a network reconnect, it re-opens every open file with a create context to reconnect a persistent handle. All create context types should be 8-bytes aligned but the padding was missed for that one. As a result, some servers don't allow us to reconnect handles and return an error. The problem occurs when the problematic context is not at the end of the create request packet. Fix this by adding a proper padding at the end of the reconnect persistent handle context.
Cc: Stable stable@vger.kernel.org # 4.19.x Signed-off-by: Pavel Shilovsky pshilov@microsoft.com Signed-off-by: Steve French stfrench@microsoft.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- fs/cifs/smb2pdu.h | 1 + 1 file changed, 1 insertion(+)
--- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -777,6 +777,7 @@ struct create_durable_handle_reconnect_v struct create_context ccontext; __u8 Name[8]; struct durable_reconnect_context_v2 dcontext; + __u8 Pad[4]; } __packed;
/* See MS-SMB2 2.2.13.2.5 */
From: Johan Hovold johan@kernel.org
commit 3759739426186a924675651b388d1c3963c5710e upstream.
The driver was accessing its driver data after having freed it.
Fixes: 0024d8ad1639 ("can: usb_8dev: Add support for USB2CAN interface from 8 devices") Cc: stable stable@vger.kernel.org # 3.9 Cc: Bernd Krumboeck b.krumboeck@gmail.com Cc: Wolfgang Grandegger wg@grandegger.com Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/net/can/usb/usb_8dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
--- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -1007,9 +1007,8 @@ static void usb_8dev_disconnect(struct u netdev_info(priv->netdev, "device disconnected\n");
unregister_netdev(priv->netdev); - free_candev(priv->netdev); - unlink_all_urbs(priv); + free_candev(priv->netdev); }
}
From: Joakim Zhang qiangqing.zhang@nxp.com
commit 5e269324db5adb2f5f6ec9a93a9c7b0672932b47 upstream.
The ECC (memory error detection and correction) mechanism can be activated or not, controlled by the ECCDIS bit in CAN_MECR. When disabled, updates on indications and reporting registers are stopped. So if want to disable ECC completely, had better assert ECCDIS bit, not just mask the related interrupts.
Fixes: cdce844865be ("can: flexcan: add vf610 support for FlexCAN") Signed-off-by: Joakim Zhang qiangqing.zhang@nxp.com Cc: linux-stable stable@vger.kernel.org Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/net/can/flexcan.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -1048,6 +1048,7 @@ static int flexcan_chip_start(struct net reg_mecr = priv->read(®s->mecr); reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS; priv->write(reg_mecr, ®s->mecr); + reg_mecr |= FLEXCAN_MECR_ECCDIS; reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK | FLEXCAN_MECR_FANCEI_MSK); priv->write(reg_mecr, ®s->mecr);
From: Kurt Van Dijck dev.kurt@vandijck-laurijssen.be
commit 3cb3eaac52c0f145d895f4b6c22834d5f02b8569 upstream.
When the status register is read without the status IRQ pending, the chip may not raise the interrupt line for an upcoming status interrupt and the driver may miss a status interrupt.
It is critical that the BUSOFF status interrupt is forwarded to the higher layers, since no more interrupts will follow without intervention.
Thanks to Wolfgang and Joe for bringing up the first idea.
Signed-off-by: Kurt Van Dijck dev.kurt@vandijck-laurijssen.be Cc: Wolfgang Grandegger wg@grandegger.com Cc: Joe Burmeister joe.burmeister@devtank.co.uk Fixes: fa39b54ccf28 ("can: c_can: Get rid of pointless interrupts") Cc: linux-stable stable@vger.kernel.org Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/net/can/c_can/c_can.c | 25 ++++++++++++++++++++----- drivers/net/can/c_can/c_can.h | 1 + 2 files changed, 21 insertions(+), 5 deletions(-)
--- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -97,6 +97,9 @@ #define BTR_TSEG2_SHIFT 12 #define BTR_TSEG2_MASK (0x7 << BTR_TSEG2_SHIFT)
+/* interrupt register */ +#define INT_STS_PENDING 0x8000 + /* brp extension register */ #define BRP_EXT_BRPE_MASK 0x0f #define BRP_EXT_BRPE_SHIFT 0 @@ -1029,10 +1032,16 @@ static int c_can_poll(struct napi_struct u16 curr, last = priv->last_status; int work_done = 0;
- priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG); - /* Ack status on C_CAN. D_CAN is self clearing */ - if (priv->type != BOSCH_D_CAN) - priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED); + /* Only read the status register if a status interrupt was pending */ + if (atomic_xchg(&priv->sie_pending, 0)) { + priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG); + /* Ack status on C_CAN. D_CAN is self clearing */ + if (priv->type != BOSCH_D_CAN) + priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED); + } else { + /* no change detected ... */ + curr = last; + }
/* handle state changes */ if ((curr & STATUS_EWARN) && (!(last & STATUS_EWARN))) { @@ -1083,10 +1092,16 @@ static irqreturn_t c_can_isr(int irq, vo { struct net_device *dev = (struct net_device *)dev_id; struct c_can_priv *priv = netdev_priv(dev); + int reg_int;
- if (!priv->read_reg(priv, C_CAN_INT_REG)) + reg_int = priv->read_reg(priv, C_CAN_INT_REG); + if (!reg_int) return IRQ_NONE;
+ /* save for later use */ + if (reg_int & INT_STS_PENDING) + atomic_set(&priv->sie_pending, 1); + /* disable all interrupts and schedule the NAPI */ c_can_irq_control(priv, false); napi_schedule(&priv->napi); --- a/drivers/net/can/c_can/c_can.h +++ b/drivers/net/can/c_can/c_can.h @@ -198,6 +198,7 @@ struct c_can_priv { struct net_device *dev; struct device *device; atomic_t tx_active; + atomic_t sie_pending; unsigned long tx_dir; int last_status; u16 (*read_reg) (const struct c_can_priv *priv, enum reg index);
From: Stephane Grosjean s.grosjean@peak-system.com
commit de280f403f2996679e2607384980703710576fed upstream.
When decoding a buffer received from PCAN-USB, the first timestamp read in a packet is a 16-bit coded time base, and the next ones are an 8-bit offset to this base, regardless of the type of packet read.
This patch corrects a potential loss of synchronization by using a timestamp index read from the buffer, rather than an index of received data packets, to determine on the sizeof the timestamp to be read from the packet being decoded.
Signed-off-by: Stephane Grosjean s.grosjean@peak-system.com Fixes: 46be265d3388 ("can: usb: PEAK-System Technik PCAN-USB specific part") Cc: linux-stable stable@vger.kernel.org Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/net/can/usb/peak_usb/pcan_usb.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -108,7 +108,7 @@ struct pcan_usb_msg_context { u8 *end; u8 rec_cnt; u8 rec_idx; - u8 rec_data_idx; + u8 rec_ts_idx; struct net_device *netdev; struct pcan_usb *pdev; }; @@ -555,10 +555,15 @@ static int pcan_usb_decode_status(struct mc->ptr += PCAN_USB_CMD_ARGS;
if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) { - int err = pcan_usb_decode_ts(mc, !mc->rec_idx); + int err = pcan_usb_decode_ts(mc, !mc->rec_ts_idx);
if (err) return err; + + /* Next packet in the buffer will have a timestamp on a single + * byte + */ + mc->rec_ts_idx++; }
switch (f) { @@ -640,10 +645,13 @@ static int pcan_usb_decode_data(struct p
cf->can_dlc = get_can_dlc(rec_len);
- /* first data packet timestamp is a word */ - if (pcan_usb_decode_ts(mc, !mc->rec_data_idx)) + /* Only first packet timestamp is a word */ + if (pcan_usb_decode_ts(mc, !mc->rec_ts_idx)) goto decode_failed;
+ /* Next packet in the buffer will have a timestamp on a single byte */ + mc->rec_ts_idx++; + /* read data */ memset(cf->data, 0x0, sizeof(cf->data)); if (status_len & PCAN_USB_STATUSLEN_RTR) { @@ -696,7 +704,6 @@ static int pcan_usb_decode_msg(struct pe /* handle normal can frames here */ } else { err = pcan_usb_decode_data(&mc, sl); - mc.rec_data_idx++; } }
From: Marc Kleine-Budde mkl@pengutronix.de
commit ca913f1ac024559ebc17f0b599af262f0ad997c9 upstream.
If the rx-offload skb_queue is full can_rx_offload_queue_sorted() will not queue the skb and return with an error.
None of the callers of this function, issue a kfree_skb() to free the not queued skb. This results in a memory leak.
This patch fixes the problem by freeing the skb in case of a full queue. The return value is adjusted to -ENOBUFS to better reflect the actual problem.
The device stats handling is left to the callers, as this function might be used in both the rx and tx path.
Fixes: 55059f2b7f86 ("can: rx-offload: introduce can_rx_offload_get_echo_skb() and can_rx_offload_queue_sorted() functions") Cc: linux-stable stable@vger.kernel.org Cc: Martin Hundebøll martin@geanix.com Reported-by: Martin Hundebøll martin@geanix.com Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/net/can/rx-offload.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
--- a/drivers/net/can/rx-offload.c +++ b/drivers/net/can/rx-offload.c @@ -216,8 +216,10 @@ int can_rx_offload_queue_sorted(struct c unsigned long flags;
if (skb_queue_len(&offload->skb_queue) > - offload->skb_queue_len_max) - return -ENOMEM; + offload->skb_queue_len_max) { + kfree_skb(skb); + return -ENOBUFS; + }
cb = can_rx_offload_get_cb(skb); cb->timestamp = timestamp;
From: Navid Emamdoost navid.emamdoost@gmail.com
commit fb5be6a7b4863ecc44963bb80ca614584b6c7817 upstream.
In gs_can_open() if usb_submit_urb() fails the allocated urb should be released.
Fixes: d08e973a77d1 ("can: gs_usb: Added support for the GS_USB CAN devices") Cc: linux-stable stable@vger.kernel.org Signed-off-by: Navid Emamdoost navid.emamdoost@gmail.com Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/net/can/usb/gs_usb.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -631,6 +631,7 @@ static int gs_can_open(struct net_device rc);
usb_unanchor_urb(urb); + usb_free_urb(urb); break; }
From: Wen Yang wenyang@linux.alibaba.com
commit db9ee384f6f71f7c5296ce85b7c1a2a2527e7c72 upstream.
of_node_put() needs to be called when the device node which is got from of_get_child_by_name() finished using.
Fixes: 2290aefa2e90 ("can: dev: Add support for limiting configured bitrate") Cc: Franklin S Cooper Jr fcooper@ti.com Signed-off-by: Wen Yang wenyang@linux.alibaba.com Cc: linux-stable stable@vger.kernel.org Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/net/can/dev.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -853,6 +853,7 @@ void of_can_transceiver(struct net_devic return;
ret = of_property_read_u32(dn, "max-bitrate", &priv->bitrate_max); + of_node_put(dn); if ((ret && ret != -EINVAL) || (!ret && !priv->bitrate_max)) netdev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit.\n"); }
From: Johan Hovold johan@kernel.org
commit 4d6636498c41891d0482a914dd570343a838ad79 upstream.
The driver was accessing its driver data after having freed it.
Fixes: 51f3baad7de9 ("can: mcba_usb: Add support for Microchip CAN BUS Analyzer") Cc: stable stable@vger.kernel.org # 4.12 Cc: Remigiusz Kołłątaj remigiusz.kollataj@mobica.com Reported-by: syzbot+e29b17e5042bbc56fae9@syzkaller.appspotmail.com Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/net/can/usb/mcba_usb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
--- a/drivers/net/can/usb/mcba_usb.c +++ b/drivers/net/can/usb/mcba_usb.c @@ -887,9 +887,8 @@ static void mcba_usb_disconnect(struct u netdev_info(priv->netdev, "device disconnected\n");
unregister_candev(priv->netdev); - free_candev(priv->netdev); - mcba_urb_unlink(priv); + free_candev(priv->netdev); }
static struct usb_driver mcba_usb_driver = {
From: Johan Hovold johan@kernel.org
commit f7a1337f0d29b98733c8824e165fca3371d7d4fd upstream.
Fix a small slab info leak due to a failure to clear the command buffer at allocation.
The first 16 bytes of the command buffer are always sent to the device in pcan_usb_send_cmd() even though only the first two may have been initialised in case no argument payload is provided (e.g. when waiting for a response).
Fixes: bb4785551f64 ("can: usb: PEAK-System Technik USB adapters driver core") Cc: stable stable@vger.kernel.org # 3.4 Reported-by: syzbot+863724e7128e14b26732@syzkaller.appspotmail.com Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -758,7 +758,7 @@ static int peak_usb_create_dev(const str dev = netdev_priv(netdev);
/* allocate a buffer large enough to send commands */ - dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL); + dev->cmd_buf = kzalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL); if (!dev->cmd_buf) { err = -ENOMEM; goto lbl_free_candev;
From: Al Viro viro@zeniv.linux.org.uk
commit ff4dd081977da56566a848f071aed8fa92d604a1 upstream.
simplifies the ->read()/->write()/->release() instances nicely
Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- fs/configfs/file.c | 229 +++++++++++++++++++++-------------------------------- 1 file changed, 95 insertions(+), 134 deletions(-)
--- a/fs/configfs/file.c +++ b/fs/configfs/file.c @@ -53,24 +53,18 @@ struct configfs_buffer { bool write_in_progress; char *bin_buffer; int bin_buffer_size; + int cb_max_size; + struct config_item *item; + struct module *owner; + union { + struct configfs_attribute *attr; + struct configfs_bin_attribute *bin_attr; + }; };
-/** - * fill_read_buffer - allocate and fill buffer from item. - * @dentry: dentry pointer. - * @buffer: data buffer for file. - * - * Allocate @buffer->page, if it hasn't been already, then call the - * config_item's show() method to fill the buffer with this attribute's - * data. - * This is called only once, on the file's first read. - */ -static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buffer) +static int fill_read_buffer(struct configfs_buffer * buffer) { - struct configfs_attribute * attr = to_attr(dentry); - struct config_item * item = to_item(dentry->d_parent); - int ret = 0; ssize_t count;
if (!buffer->page) @@ -78,15 +72,15 @@ static int fill_read_buffer(struct dentr if (!buffer->page) return -ENOMEM;
- count = attr->show(item, buffer->page); + count = buffer->attr->show(buffer->item, buffer->page); + if (count < 0) + return count; + if (WARN_ON_ONCE(count > (ssize_t)SIMPLE_ATTR_SIZE)) + return -EIO;
- BUG_ON(count > (ssize_t)SIMPLE_ATTR_SIZE); - if (count >= 0) { - buffer->needs_read_fill = 0; - buffer->count = count; - } else - ret = count; - return ret; + buffer->needs_read_fill = 0; + buffer->count = count; + return 0; }
/** @@ -111,12 +105,13 @@ static int fill_read_buffer(struct dentr static ssize_t configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct configfs_buffer * buffer = file->private_data; + struct configfs_buffer *buffer = file->private_data; ssize_t retval = 0;
mutex_lock(&buffer->mutex); if (buffer->needs_read_fill) { - if ((retval = fill_read_buffer(file->f_path.dentry,buffer))) + retval = fill_read_buffer(buffer); + if (retval) goto out; } pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n", @@ -153,9 +148,6 @@ configfs_read_bin_file(struct file *file size_t count, loff_t *ppos) { struct configfs_buffer *buffer = file->private_data; - struct dentry *dentry = file->f_path.dentry; - struct config_item *item = to_item(dentry->d_parent); - struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry); ssize_t retval = 0; ssize_t len = min_t(size_t, count, PAGE_SIZE);
@@ -170,14 +162,14 @@ configfs_read_bin_file(struct file *file
if (buffer->needs_read_fill) { /* perform first read with buf == NULL to get extent */ - len = bin_attr->read(item, NULL, 0); + len = buffer->bin_attr->read(buffer->item, NULL, 0); if (len <= 0) { retval = len; goto out; }
/* do not exceed the maximum value */ - if (bin_attr->cb_max_size && len > bin_attr->cb_max_size) { + if (buffer->cb_max_size && len > buffer->cb_max_size) { retval = -EFBIG; goto out; } @@ -190,7 +182,8 @@ configfs_read_bin_file(struct file *file buffer->bin_buffer_size = len;
/* perform second read to fill buffer */ - len = bin_attr->read(item, buffer->bin_buffer, len); + len = buffer->bin_attr->read(buffer->item, + buffer->bin_buffer, len); if (len < 0) { retval = len; vfree(buffer->bin_buffer); @@ -240,25 +233,10 @@ fill_write_buffer(struct configfs_buffer return error ? -EFAULT : count; }
- -/** - * flush_write_buffer - push buffer to config_item. - * @dentry: dentry to the attribute - * @buffer: data buffer for file. - * @count: number of bytes - * - * Get the correct pointers for the config_item and the attribute we're - * dealing with, then call the store() method for the attribute, - * passing the buffer that we acquired in fill_write_buffer(). - */ - static int -flush_write_buffer(struct dentry * dentry, struct configfs_buffer * buffer, size_t count) +flush_write_buffer(struct configfs_buffer *buffer, size_t count) { - struct configfs_attribute * attr = to_attr(dentry); - struct config_item * item = to_item(dentry->d_parent); - - return attr->store(item, buffer->page, count); + return buffer->attr->store(buffer->item, buffer->page, count); }
@@ -282,13 +260,13 @@ flush_write_buffer(struct dentry * dentr static ssize_t configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct configfs_buffer * buffer = file->private_data; + struct configfs_buffer *buffer = file->private_data; ssize_t len;
mutex_lock(&buffer->mutex); len = fill_write_buffer(buffer, buf, count); if (len > 0) - len = flush_write_buffer(file->f_path.dentry, buffer, len); + len = flush_write_buffer(buffer, len); if (len > 0) *ppos += len; mutex_unlock(&buffer->mutex); @@ -313,8 +291,6 @@ configfs_write_bin_file(struct file *fil size_t count, loff_t *ppos) { struct configfs_buffer *buffer = file->private_data; - struct dentry *dentry = file->f_path.dentry; - struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry); void *tbuf = NULL; ssize_t len;
@@ -330,8 +306,8 @@ configfs_write_bin_file(struct file *fil /* buffer grows? */ if (*ppos + count > buffer->bin_buffer_size) {
- if (bin_attr->cb_max_size && - *ppos + count > bin_attr->cb_max_size) { + if (buffer->cb_max_size && + *ppos + count > buffer->cb_max_size) { len = -EFBIG; goto out; } @@ -363,31 +339,45 @@ out: return len; }
-static int check_perm(struct inode * inode, struct file * file, int type) +static int __configfs_open_file(struct inode *inode, struct file *file, int type) { - struct config_item *item = configfs_get_config_item(file->f_path.dentry->d_parent); - struct configfs_attribute * attr = to_attr(file->f_path.dentry); - struct configfs_bin_attribute *bin_attr = NULL; - struct configfs_buffer * buffer; - struct configfs_item_operations * ops = NULL; - int error = 0; + struct dentry *dentry = file->f_path.dentry; + struct configfs_attribute *attr; + struct configfs_buffer *buffer; + int error;
- if (!item || !attr) - goto Einval; + error = -ENOMEM; + buffer = kzalloc(sizeof(struct configfs_buffer), GFP_KERNEL); + if (!buffer) + goto out;
- if (type & CONFIGFS_ITEM_BIN_ATTR) - bin_attr = to_bin_attr(file->f_path.dentry); + error = -EINVAL; + buffer->item = configfs_get_config_item(dentry->d_parent); + if (!buffer->item) + goto out_free_buffer; + + attr = to_attr(dentry); + if (!attr) + goto out_put_item; + + if (type & CONFIGFS_ITEM_BIN_ATTR) { + buffer->bin_attr = to_bin_attr(dentry); + buffer->cb_max_size = buffer->bin_attr->cb_max_size; + } else { + buffer->attr = attr; + }
+ buffer->owner = attr->ca_owner; /* Grab the module reference for this attribute if we have one */ - if (!try_module_get(attr->ca_owner)) { - error = -ENODEV; - goto Done; - } + error = -ENODEV; + if (!try_module_get(buffer->owner)) + goto out_put_item;
- if (item->ci_type) - ops = item->ci_type->ct_item_ops; - else - goto Eaccess; + error = -EACCES; + if (!buffer->item->ci_type) + goto out_put_module; + + buffer->ops = buffer->item->ci_type->ct_item_ops;
/* File needs write support. * The inode's perms must say it's ok, @@ -395,13 +385,11 @@ static int check_perm(struct inode * ino */ if (file->f_mode & FMODE_WRITE) { if (!(inode->i_mode & S_IWUGO)) - goto Eaccess; - + goto out_put_module; if ((type & CONFIGFS_ITEM_ATTR) && !attr->store) - goto Eaccess; - - if ((type & CONFIGFS_ITEM_BIN_ATTR) && !bin_attr->write) - goto Eaccess; + goto out_put_module; + if ((type & CONFIGFS_ITEM_BIN_ATTR) && !buffer->bin_attr->write) + goto out_put_module; }
/* File needs read support. @@ -410,90 +398,65 @@ static int check_perm(struct inode * ino */ if (file->f_mode & FMODE_READ) { if (!(inode->i_mode & S_IRUGO)) - goto Eaccess; - + goto out_put_module; if ((type & CONFIGFS_ITEM_ATTR) && !attr->show) - goto Eaccess; - - if ((type & CONFIGFS_ITEM_BIN_ATTR) && !bin_attr->read) - goto Eaccess; + goto out_put_module; + if ((type & CONFIGFS_ITEM_BIN_ATTR) && !buffer->bin_attr->read) + goto out_put_module; }
- /* No error? Great, allocate a buffer for the file, and store it - * it in file->private_data for easy access. - */ - buffer = kzalloc(sizeof(struct configfs_buffer),GFP_KERNEL); - if (!buffer) { - error = -ENOMEM; - goto Enomem; - } mutex_init(&buffer->mutex); buffer->needs_read_fill = 1; buffer->read_in_progress = false; buffer->write_in_progress = false; - buffer->ops = ops; file->private_data = buffer; - goto Done; + return 0;
- Einval: - error = -EINVAL; - goto Done; - Eaccess: - error = -EACCES; - Enomem: - module_put(attr->ca_owner); - Done: - if (error && item) - config_item_put(item); +out_put_module: + module_put(buffer->owner); +out_put_item: + config_item_put(buffer->item); +out_free_buffer: + kfree(buffer); +out: return error; }
static int configfs_release(struct inode *inode, struct file *filp) { - struct config_item * item = to_item(filp->f_path.dentry->d_parent); - struct configfs_attribute * attr = to_attr(filp->f_path.dentry); - struct module * owner = attr->ca_owner; - struct configfs_buffer * buffer = filp->private_data; - - if (item) - config_item_put(item); - /* After this point, attr should not be accessed. */ - module_put(owner); - - if (buffer) { - if (buffer->page) - free_page((unsigned long)buffer->page); - mutex_destroy(&buffer->mutex); - kfree(buffer); - } + struct configfs_buffer *buffer = filp->private_data; + + if (buffer->item) + config_item_put(buffer->item); + module_put(buffer->owner); + if (buffer->page) + free_page((unsigned long)buffer->page); + mutex_destroy(&buffer->mutex); + kfree(buffer); return 0; }
static int configfs_open_file(struct inode *inode, struct file *filp) { - return check_perm(inode, filp, CONFIGFS_ITEM_ATTR); + return __configfs_open_file(inode, filp, CONFIGFS_ITEM_ATTR); }
static int configfs_open_bin_file(struct inode *inode, struct file *filp) { - return check_perm(inode, filp, CONFIGFS_ITEM_BIN_ATTR); + return __configfs_open_file(inode, filp, CONFIGFS_ITEM_BIN_ATTR); }
-static int configfs_release_bin_file(struct inode *inode, struct file *filp) +static int configfs_release_bin_file(struct inode *inode, struct file *file) { - struct configfs_buffer *buffer = filp->private_data; - struct dentry *dentry = filp->f_path.dentry; - struct config_item *item = to_item(dentry->d_parent); - struct configfs_bin_attribute *bin_attr = to_bin_attr(dentry); - ssize_t len = 0; - int ret; + struct configfs_buffer *buffer = file->private_data;
buffer->read_in_progress = false;
if (buffer->write_in_progress) { buffer->write_in_progress = false;
- len = bin_attr->write(item, buffer->bin_buffer, + /* result of ->release() is ignored */ + buffer->bin_attr->write(buffer->item, buffer->bin_buffer, buffer->bin_buffer_size);
/* vfree on NULL is safe */ @@ -503,10 +466,8 @@ static int configfs_release_bin_file(str buffer->needs_read_fill = 1; }
- ret = configfs_release(inode, filp); - if (len < 0) - return len; - return ret; + configfs_release(inode, file); + return 0; }
From: Al Viro viro@zeniv.linux.org.uk
commit f19e4ed1e1edbfa3c9ccb9fed17759b7d6db24c6 upstream.
revert cc57c07343bd "configfs: fix registered group removal" It was an attempt to handle something that fundamentally doesn't work - configfs_register_group() should never be done in a part of tree that can be rmdir'ed. And in mainline it never had been, so let's not borrow trouble; the fix was racy anyway, it would take a lot more to make that work and desired semantics is not clear.
Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- fs/configfs/dir.c | 11 ----------- 1 file changed, 11 deletions(-)
--- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -1782,16 +1782,6 @@ void configfs_unregister_group(struct co struct dentry *dentry = group->cg_item.ci_dentry; struct dentry *parent = group->cg_item.ci_parent->ci_dentry;
- mutex_lock(&subsys->su_mutex); - if (!group->cg_item.ci_parent->ci_group) { - /* - * The parent has already been unlinked and detached - * due to a rmdir. - */ - goto unlink_group; - } - mutex_unlock(&subsys->su_mutex); - inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); spin_lock(&configfs_dirent_lock); configfs_detach_prep(dentry, NULL); @@ -1806,7 +1796,6 @@ void configfs_unregister_group(struct co dput(dentry);
mutex_lock(&subsys->su_mutex); -unlink_group: unlink_group(group); mutex_unlock(&subsys->su_mutex); }
From: Al Viro viro@zeniv.linux.org.uk
commit 47320fbe11a6059ae502c9c16b668022fdb4cf76 upstream.
Refcounted, hangs of configfs_dirent, created by operations that add fragments to configfs tree (mkdir and configfs_register_{subsystem,group}). Will be used in the next commit to provide exclusion between fragment removal and ->show/->store calls.
Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- fs/configfs/configfs_internal.h | 15 ++++- fs/configfs/dir.c | 105 +++++++++++++++++++++++++++++++--------- fs/configfs/file.c | 4 - 3 files changed, 97 insertions(+), 27 deletions(-)
--- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h @@ -34,6 +34,15 @@ #include <linux/list.h> #include <linux/spinlock.h>
+struct configfs_fragment { + atomic_t frag_count; + struct rw_semaphore frag_sem; + bool frag_dead; +}; + +void put_fragment(struct configfs_fragment *); +struct configfs_fragment *get_fragment(struct configfs_fragment *); + struct configfs_dirent { atomic_t s_count; int s_dependent_count; @@ -48,6 +57,7 @@ struct configfs_dirent { #ifdef CONFIG_LOCKDEP int s_depth; #endif + struct configfs_fragment *s_frag; };
#define CONFIGFS_ROOT 0x0001 @@ -75,8 +85,8 @@ extern int configfs_create(struct dentry extern int configfs_create_file(struct config_item *, const struct configfs_attribute *); extern int configfs_create_bin_file(struct config_item *, const struct configfs_bin_attribute *); -extern int configfs_make_dirent(struct configfs_dirent *, - struct dentry *, void *, umode_t, int); +extern int configfs_make_dirent(struct configfs_dirent *, struct dentry *, + void *, umode_t, int, struct configfs_fragment *); extern int configfs_dirent_is_ready(struct configfs_dirent *);
extern void configfs_hash_and_remove(struct dentry * dir, const char * name); @@ -151,6 +161,7 @@ static inline void release_configfs_dire { if (!(sd->s_type & CONFIGFS_ROOT)) { kfree(sd->s_iattr); + put_fragment(sd->s_frag); kmem_cache_free(configfs_dir_cachep, sd); } } --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -164,11 +164,38 @@ configfs_adjust_dir_dirent_depth_after_p
#endif /* CONFIG_LOCKDEP */
+static struct configfs_fragment *new_fragment(void) +{ + struct configfs_fragment *p; + + p = kmalloc(sizeof(struct configfs_fragment), GFP_KERNEL); + if (p) { + atomic_set(&p->frag_count, 1); + init_rwsem(&p->frag_sem); + p->frag_dead = false; + } + return p; +} + +void put_fragment(struct configfs_fragment *frag) +{ + if (frag && atomic_dec_and_test(&frag->frag_count)) + kfree(frag); +} + +struct configfs_fragment *get_fragment(struct configfs_fragment *frag) +{ + if (likely(frag)) + atomic_inc(&frag->frag_count); + return frag; +} + /* * Allocates a new configfs_dirent and links it to the parent configfs_dirent */ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *parent_sd, - void *element, int type) + void *element, int type, + struct configfs_fragment *frag) { struct configfs_dirent * sd;
@@ -188,6 +215,7 @@ static struct configfs_dirent *configfs_ kmem_cache_free(configfs_dir_cachep, sd); return ERR_PTR(-ENOENT); } + sd->s_frag = get_fragment(frag); list_add(&sd->s_sibling, &parent_sd->s_children); spin_unlock(&configfs_dirent_lock);
@@ -222,11 +250,11 @@ static int configfs_dirent_exists(struct
int configfs_make_dirent(struct configfs_dirent * parent_sd, struct dentry * dentry, void * element, - umode_t mode, int type) + umode_t mode, int type, struct configfs_fragment *frag) { struct configfs_dirent * sd;
- sd = configfs_new_dirent(parent_sd, element, type); + sd = configfs_new_dirent(parent_sd, element, type, frag); if (IS_ERR(sd)) return PTR_ERR(sd);
@@ -273,7 +301,8 @@ static void init_symlink(struct inode * * until it is validated by configfs_dir_set_ready() */
-static int configfs_create_dir(struct config_item *item, struct dentry *dentry) +static int configfs_create_dir(struct config_item *item, struct dentry *dentry, + struct configfs_fragment *frag) { int error; umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; @@ -286,7 +315,8 @@ static int configfs_create_dir(struct co return error;
error = configfs_make_dirent(p->d_fsdata, dentry, item, mode, - CONFIGFS_DIR | CONFIGFS_USET_CREATING); + CONFIGFS_DIR | CONFIGFS_USET_CREATING, + frag); if (unlikely(error)) return error;
@@ -351,9 +381,10 @@ int configfs_create_link(struct configfs { int err = 0; umode_t mode = S_IFLNK | S_IRWXUGO; + struct configfs_dirent *p = parent->d_fsdata;
- err = configfs_make_dirent(parent->d_fsdata, dentry, sl, mode, - CONFIGFS_ITEM_LINK); + err = configfs_make_dirent(p, dentry, sl, mode, + CONFIGFS_ITEM_LINK, p->s_frag); if (!err) { err = configfs_create(dentry, mode, init_symlink); if (err) { @@ -612,7 +643,8 @@ static int populate_attrs(struct config_
static int configfs_attach_group(struct config_item *parent_item, struct config_item *item, - struct dentry *dentry); + struct dentry *dentry, + struct configfs_fragment *frag); static void configfs_detach_group(struct config_item *item);
static void detach_groups(struct config_group *group) @@ -660,7 +692,8 @@ static void detach_groups(struct config_ * try using vfs_mkdir. Just a thought. */ static int create_default_group(struct config_group *parent_group, - struct config_group *group) + struct config_group *group, + struct configfs_fragment *frag) { int ret; struct configfs_dirent *sd; @@ -676,7 +709,7 @@ static int create_default_group(struct c d_add(child, NULL);
ret = configfs_attach_group(&parent_group->cg_item, - &group->cg_item, child); + &group->cg_item, child, frag); if (!ret) { sd = child->d_fsdata; sd->s_type |= CONFIGFS_USET_DEFAULT; @@ -690,13 +723,14 @@ static int create_default_group(struct c return ret; }
-static int populate_groups(struct config_group *group) +static int populate_groups(struct config_group *group, + struct configfs_fragment *frag) { struct config_group *new_group; int ret = 0;
list_for_each_entry(new_group, &group->default_groups, group_entry) { - ret = create_default_group(group, new_group); + ret = create_default_group(group, new_group, frag); if (ret) { detach_groups(group); break; @@ -810,11 +844,12 @@ static void link_group(struct config_gro */ static int configfs_attach_item(struct config_item *parent_item, struct config_item *item, - struct dentry *dentry) + struct dentry *dentry, + struct configfs_fragment *frag) { int ret;
- ret = configfs_create_dir(item, dentry); + ret = configfs_create_dir(item, dentry, frag); if (!ret) { ret = populate_attrs(item); if (ret) { @@ -844,12 +879,13 @@ static void configfs_detach_item(struct
static int configfs_attach_group(struct config_item *parent_item, struct config_item *item, - struct dentry *dentry) + struct dentry *dentry, + struct configfs_fragment *frag) { int ret; struct configfs_dirent *sd;
- ret = configfs_attach_item(parent_item, item, dentry); + ret = configfs_attach_item(parent_item, item, dentry, frag); if (!ret) { sd = dentry->d_fsdata; sd->s_type |= CONFIGFS_USET_DIR; @@ -865,7 +901,7 @@ static int configfs_attach_group(struct */ inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD); configfs_adjust_dir_dirent_depth_before_populate(sd); - ret = populate_groups(to_config_group(item)); + ret = populate_groups(to_config_group(item), frag); if (ret) { configfs_detach_item(item); d_inode(dentry)->i_flags |= S_DEAD; @@ -1260,6 +1296,7 @@ static int configfs_mkdir(struct inode * struct configfs_dirent *sd; const struct config_item_type *type; struct module *subsys_owner = NULL, *new_item_owner = NULL; + struct configfs_fragment *frag; char *name;
sd = dentry->d_parent->d_fsdata; @@ -1278,6 +1315,12 @@ static int configfs_mkdir(struct inode * goto out; }
+ frag = new_fragment(); + if (!frag) { + ret = -ENOMEM; + goto out; + } + /* Get a working ref for the duration of this function */ parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; @@ -1380,9 +1423,9 @@ static int configfs_mkdir(struct inode * spin_unlock(&configfs_dirent_lock);
if (group) - ret = configfs_attach_group(parent_item, item, dentry); + ret = configfs_attach_group(parent_item, item, dentry, frag); else - ret = configfs_attach_item(parent_item, item, dentry); + ret = configfs_attach_item(parent_item, item, dentry, frag);
spin_lock(&configfs_dirent_lock); sd->s_type &= ~CONFIGFS_USET_IN_MKDIR; @@ -1419,6 +1462,7 @@ out_put: * reference. */ config_item_put(parent_item); + put_fragment(frag);
out: return ret; @@ -1587,7 +1631,7 @@ static int configfs_dir_open(struct inod */ err = -ENOENT; if (configfs_dirent_is_ready(parent_sd)) { - file->private_data = configfs_new_dirent(parent_sd, NULL, 0); + file->private_data = configfs_new_dirent(parent_sd, NULL, 0, NULL); if (IS_ERR(file->private_data)) err = PTR_ERR(file->private_data); else @@ -1743,8 +1787,13 @@ int configfs_register_group(struct confi { struct configfs_subsystem *subsys = parent_group->cg_subsys; struct dentry *parent; + struct configfs_fragment *frag; int ret;
+ frag = new_fragment(); + if (!frag) + return -ENOMEM; + mutex_lock(&subsys->su_mutex); link_group(parent_group, group); mutex_unlock(&subsys->su_mutex); @@ -1752,7 +1801,7 @@ int configfs_register_group(struct confi parent = parent_group->cg_item.ci_dentry;
inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); - ret = create_default_group(parent_group, group); + ret = create_default_group(parent_group, group, frag); if (ret) goto err_out;
@@ -1760,12 +1809,14 @@ int configfs_register_group(struct confi configfs_dir_set_ready(group->cg_item.ci_dentry->d_fsdata); spin_unlock(&configfs_dirent_lock); inode_unlock(d_inode(parent)); + put_fragment(frag); return 0; err_out: inode_unlock(d_inode(parent)); mutex_lock(&subsys->su_mutex); unlink_group(group); mutex_unlock(&subsys->su_mutex); + put_fragment(frag); return ret; } EXPORT_SYMBOL(configfs_register_group); @@ -1852,10 +1903,17 @@ int configfs_register_subsystem(struct c struct dentry *dentry; struct dentry *root; struct configfs_dirent *sd; + struct configfs_fragment *frag; + + frag = new_fragment(); + if (!frag) + return -ENOMEM;
root = configfs_pin_fs(); - if (IS_ERR(root)) + if (IS_ERR(root)) { + put_fragment(frag); return PTR_ERR(root); + }
if (!group->cg_item.ci_name) group->cg_item.ci_name = group->cg_item.ci_namebuf; @@ -1871,7 +1929,7 @@ int configfs_register_subsystem(struct c d_add(dentry, NULL);
err = configfs_attach_group(sd->s_element, &group->cg_item, - dentry); + dentry, frag); if (err) { BUG_ON(d_inode(dentry)); d_drop(dentry); @@ -1889,6 +1947,7 @@ int configfs_register_subsystem(struct c unlink_group(group); configfs_release_fs(); } + put_fragment(frag);
return err; } --- a/fs/configfs/file.c +++ b/fs/configfs/file.c @@ -502,7 +502,7 @@ int configfs_create_file(struct config_i
inode_lock_nested(d_inode(dir), I_MUTEX_NORMAL); error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode, - CONFIGFS_ITEM_ATTR); + CONFIGFS_ITEM_ATTR, parent_sd->s_frag); inode_unlock(d_inode(dir));
return error; @@ -524,7 +524,7 @@ int configfs_create_bin_file(struct conf
inode_lock_nested(dir->d_inode, I_MUTEX_NORMAL); error = configfs_make_dirent(parent_sd, NULL, (void *) bin_attr, mode, - CONFIGFS_ITEM_BIN_ATTR); + CONFIGFS_ITEM_BIN_ATTR, parent_sd->s_frag); inode_unlock(dir->d_inode);
return error;
From: Al Viro viro@zeniv.linux.org.uk
commit b0841eefd9693827afb9888235e26ddd098f9cef upstream.
Make sure that attribute methods are not called after the item has been removed from the tree. To do so, we * at the point of no return in removals, grab ->frag_sem exclusive and mark the fragment dead. * call the methods of attributes with ->frag_sem taken shared and only after having verified that the fragment is still alive.
The main benefit is for method instances - they are guaranteed that the objects they are accessing *and* all ancestors are still there. Another win is that we don't need to bother with extra refcount on config_item when opening a file - the item will be alive for as long as it stays in the tree, and we won't touch it/attributes/any associated data after it's been removed from the tree.
Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- fs/configfs/dir.c | 23 ++++++++++++++++ fs/configfs/file.c | 75 ++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 80 insertions(+), 18 deletions(-)
--- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -1474,6 +1474,7 @@ static int configfs_rmdir(struct inode * struct config_item *item; struct configfs_subsystem *subsys; struct configfs_dirent *sd; + struct configfs_fragment *frag; struct module *subsys_owner = NULL, *dead_item_owner = NULL; int ret;
@@ -1531,6 +1532,16 @@ static int configfs_rmdir(struct inode * } } while (ret == -EAGAIN);
+ frag = sd->s_frag; + if (down_write_killable(&frag->frag_sem)) { + spin_lock(&configfs_dirent_lock); + configfs_detach_rollback(dentry); + spin_unlock(&configfs_dirent_lock); + return -EINTR; + } + frag->frag_dead = true; + up_write(&frag->frag_sem); + /* Get a working ref for the duration of this function */ item = configfs_get_config_item(dentry);
@@ -1832,6 +1843,12 @@ void configfs_unregister_group(struct co struct configfs_subsystem *subsys = group->cg_subsys; struct dentry *dentry = group->cg_item.ci_dentry; struct dentry *parent = group->cg_item.ci_parent->ci_dentry; + struct configfs_dirent *sd = dentry->d_fsdata; + struct configfs_fragment *frag = sd->s_frag; + + down_write(&frag->frag_sem); + frag->frag_dead = true; + up_write(&frag->frag_sem);
inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); spin_lock(&configfs_dirent_lock); @@ -1957,12 +1974,18 @@ void configfs_unregister_subsystem(struc struct config_group *group = &subsys->su_group; struct dentry *dentry = group->cg_item.ci_dentry; struct dentry *root = dentry->d_sb->s_root; + struct configfs_dirent *sd = dentry->d_fsdata; + struct configfs_fragment *frag = sd->s_frag;
if (dentry->d_parent != root) { pr_err("Tried to unregister non-subsystem!\n"); return; }
+ down_write(&frag->frag_sem); + frag->frag_dead = true; + up_write(&frag->frag_sem); + inode_lock_nested(d_inode(root), I_MUTEX_PARENT); inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD); --- a/fs/configfs/file.c +++ b/fs/configfs/file.c @@ -62,22 +62,32 @@ struct configfs_buffer { }; };
+static inline struct configfs_fragment *to_frag(struct file *file) +{ + struct configfs_dirent *sd = file->f_path.dentry->d_fsdata; + + return sd->s_frag; +}
-static int fill_read_buffer(struct configfs_buffer * buffer) +static int fill_read_buffer(struct file *file, struct configfs_buffer *buffer) { - ssize_t count; + struct configfs_fragment *frag = to_frag(file); + ssize_t count = -ENOENT;
if (!buffer->page) buffer->page = (char *) get_zeroed_page(GFP_KERNEL); if (!buffer->page) return -ENOMEM;
- count = buffer->attr->show(buffer->item, buffer->page); + down_read(&frag->frag_sem); + if (!frag->frag_dead) + count = buffer->attr->show(buffer->item, buffer->page); + up_read(&frag->frag_sem); + if (count < 0) return count; if (WARN_ON_ONCE(count > (ssize_t)SIMPLE_ATTR_SIZE)) return -EIO; - buffer->needs_read_fill = 0; buffer->count = count; return 0; @@ -110,7 +120,7 @@ configfs_read_file(struct file *file, ch
mutex_lock(&buffer->mutex); if (buffer->needs_read_fill) { - retval = fill_read_buffer(buffer); + retval = fill_read_buffer(file, buffer); if (retval) goto out; } @@ -147,6 +157,7 @@ static ssize_t configfs_read_bin_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + struct configfs_fragment *frag = to_frag(file); struct configfs_buffer *buffer = file->private_data; ssize_t retval = 0; ssize_t len = min_t(size_t, count, PAGE_SIZE); @@ -162,7 +173,12 @@ configfs_read_bin_file(struct file *file
if (buffer->needs_read_fill) { /* perform first read with buf == NULL to get extent */ - len = buffer->bin_attr->read(buffer->item, NULL, 0); + down_read(&frag->frag_sem); + if (!frag->frag_dead) + len = buffer->bin_attr->read(buffer->item, NULL, 0); + else + len = -ENOENT; + up_read(&frag->frag_sem); if (len <= 0) { retval = len; goto out; @@ -182,8 +198,13 @@ configfs_read_bin_file(struct file *file buffer->bin_buffer_size = len;
/* perform second read to fill buffer */ - len = buffer->bin_attr->read(buffer->item, - buffer->bin_buffer, len); + down_read(&frag->frag_sem); + if (!frag->frag_dead) + len = buffer->bin_attr->read(buffer->item, + buffer->bin_buffer, len); + else + len = -ENOENT; + up_read(&frag->frag_sem); if (len < 0) { retval = len; vfree(buffer->bin_buffer); @@ -234,9 +255,16 @@ fill_write_buffer(struct configfs_buffer }
static int -flush_write_buffer(struct configfs_buffer *buffer, size_t count) +flush_write_buffer(struct file *file, struct configfs_buffer *buffer, size_t count) { - return buffer->attr->store(buffer->item, buffer->page, count); + struct configfs_fragment *frag = to_frag(file); + int res = -ENOENT; + + down_read(&frag->frag_sem); + if (!frag->frag_dead) + res = buffer->attr->store(buffer->item, buffer->page, count); + up_read(&frag->frag_sem); + return res; }
@@ -266,7 +294,7 @@ configfs_write_file(struct file *file, c mutex_lock(&buffer->mutex); len = fill_write_buffer(buffer, buf, count); if (len > 0) - len = flush_write_buffer(buffer, len); + len = flush_write_buffer(file, buffer, len); if (len > 0) *ppos += len; mutex_unlock(&buffer->mutex); @@ -342,6 +370,7 @@ out: static int __configfs_open_file(struct inode *inode, struct file *file, int type) { struct dentry *dentry = file->f_path.dentry; + struct configfs_fragment *frag = to_frag(file); struct configfs_attribute *attr; struct configfs_buffer *buffer; int error; @@ -351,8 +380,13 @@ static int __configfs_open_file(struct i if (!buffer) goto out;
+ error = -ENOENT; + down_read(&frag->frag_sem); + if (unlikely(frag->frag_dead)) + goto out_free_buffer; + error = -EINVAL; - buffer->item = configfs_get_config_item(dentry->d_parent); + buffer->item = to_item(dentry->d_parent); if (!buffer->item) goto out_free_buffer;
@@ -410,6 +444,7 @@ static int __configfs_open_file(struct i buffer->read_in_progress = false; buffer->write_in_progress = false; file->private_data = buffer; + up_read(&frag->frag_sem); return 0;
out_put_module: @@ -417,6 +452,7 @@ out_put_module: out_put_item: config_item_put(buffer->item); out_free_buffer: + up_read(&frag->frag_sem); kfree(buffer); out: return error; @@ -426,8 +462,6 @@ static int configfs_release(struct inode { struct configfs_buffer *buffer = filp->private_data;
- if (buffer->item) - config_item_put(buffer->item); module_put(buffer->owner); if (buffer->page) free_page((unsigned long)buffer->page); @@ -453,12 +487,17 @@ static int configfs_release_bin_file(str buffer->read_in_progress = false;
if (buffer->write_in_progress) { + struct configfs_fragment *frag = to_frag(file); buffer->write_in_progress = false;
- /* result of ->release() is ignored */ - buffer->bin_attr->write(buffer->item, buffer->bin_buffer, - buffer->bin_buffer_size); - + down_read(&frag->frag_sem); + if (!frag->frag_dead) { + /* result of ->release() is ignored */ + buffer->bin_attr->write(buffer->item, + buffer->bin_buffer, + buffer->bin_buffer_size); + } + up_read(&frag->frag_sem); /* vfree on NULL is safe */ vfree(buffer->bin_buffer); buffer->bin_buffer = NULL;
From: Al Viro viro@zeniv.linux.org.uk
commit 351e5d869e5ac10cb40c78b5f2d7dfc816ad4587 upstream.
Configfs abuses symlink(2). Unlike the normal filesystems, it wants the target resolved at symlink(2) time, like link(2) would've done. The problem is that ->symlink() is called with the parent directory locked exclusive, so resolving the target inside the ->symlink() is easily deadlocked.
Short of really ugly games in sys_symlink() itself, all we can do is to unlock the parent before resolving the target and relock it after. However, that invalidates the checks done by the caller of ->symlink(), so we have to * check that dentry is still where it used to be (it couldn't have been moved, but it could've been unhashed) * recheck that it's still negative (somebody else might've successfully created a symlink with the same name while we were looking the target up) * recheck the permissions on the parent directory.
Cc: stable@vger.kernel.org Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- fs/configfs/symlink.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-)
--- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c @@ -157,11 +157,42 @@ int configfs_symlink(struct inode *dir, !type->ct_item_ops->allow_link) goto out_put;
+ /* + * This is really sick. What they wanted was a hybrid of + * link(2) and symlink(2) - they wanted the target resolved + * at syscall time (as link(2) would've done), be a directory + * (which link(2) would've refused to do) *AND* be a deep + * fucking magic, making the target busy from rmdir POV. + * symlink(2) is nothing of that sort, and the locking it + * gets matches the normal symlink(2) semantics. Without + * attempts to resolve the target (which might very well + * not even exist yet) done prior to locking the parent + * directory. This perversion, OTOH, needs to resolve + * the target, which would lead to obvious deadlocks if + * attempted with any directories locked. + * + * Unfortunately, that garbage is userland ABI and we should've + * said "no" back in 2005. Too late now, so we get to + * play very ugly games with locking. + * + * Try *ANYTHING* of that sort in new code, and you will + * really regret it. Just ask yourself - what could a BOFH + * do to me and do I want to find it out first-hand? + * + * AV, a thoroughly annoyed bastard. + */ + inode_unlock(dir); ret = get_target(symname, &path, &target_item, dentry->d_sb); + inode_lock(dir); if (ret) goto out_put;
- ret = type->ct_item_ops->allow_link(parent_item, target_item); + if (dentry->d_inode || d_unhashed(dentry)) + ret = -EEXIST; + else + ret = inode_permission(dir, MAY_WRITE | MAY_EXEC); + if (!ret) + ret = type->ct_item_ops->allow_link(parent_item, target_item); if (!ret) { mutex_lock(&configfs_symlink_mutex); ret = create_link(parent_item, target_item, dentry);
From: Takashi Iwai tiwai@suse.de
commit 57f8770620e9b51c61089751f0b5ad3dbe376ff2 upstream.
Introduce a new helper to validate each audio descriptor unit before and check the unit before actually accessing it. This should harden against the OOB access cases with malformed descriptors that have been recently frequently reported by fuzzers.
The existing descriptor checks are still kept although they become superfluous after this patch. They'll be cleaned up eventually later.
Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- sound/usb/Makefile | 3 sound/usb/helper.h | 4 sound/usb/mixer.c | 10 + sound/usb/power.c | 2 sound/usb/quirks.c | 3 sound/usb/stream.c | 25 +-- sound/usb/validate.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 366 insertions(+), 13 deletions(-)
--- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -16,7 +16,8 @@ snd-usb-audio-objs := card.o \ power.o \ proc.o \ quirks.o \ - stream.o + stream.o \ + validate.o
snd-usbmidi-lib-objs := midi.o
--- a/sound/usb/helper.h +++ b/sound/usb/helper.h @@ -30,4 +30,8 @@ static inline int snd_usb_ctrl_intf(stru return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber; }
+/* in validate.c */ +bool snd_usb_validate_audio_desc(void *p, int protocol); +bool snd_usb_validate_midi_desc(void *p); + #endif /* __USBAUDIO_HELPER_H */ --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -800,6 +800,8 @@ static int __check_input_term(struct mix p1 = find_audio_control_unit(state, id); if (!p1) break; + if (!snd_usb_validate_audio_desc(p1, protocol)) + break; /* bad descriptor */
hdr = p1; term->id = id; @@ -2794,6 +2796,11 @@ static int parse_audio_unit(struct mixer return -EINVAL; }
+ if (!snd_usb_validate_audio_desc(p1, protocol)) { + usb_audio_dbg(state->chip, "invalid unit %d\n", unitid); + return 0; /* skip invalid unit */ + } + if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { switch (p1[2]) { case UAC_INPUT_TERMINAL: @@ -3164,6 +3171,9 @@ static int snd_usb_mixer_controls(struct while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, mixer->hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) { + if (!snd_usb_validate_audio_desc(p, mixer->protocol)) + continue; /* skip invalid descriptor */ + if (mixer->protocol == UAC_VERSION_1) { struct uac1_output_terminal_descriptor *desc = p;
--- a/sound/usb/power.c +++ b/sound/usb/power.c @@ -31,6 +31,8 @@ snd_usb_find_power_domain(struct usb_hos struct uac3_power_domain_descriptor *pd_desc = p; int i;
+ if (!snd_usb_validate_audio_desc(p, UAC_VERSION_3)) + continue; for (i = 0; i < pd_desc->bNrEntities; i++) { if (pd_desc->baEntityID[i] == id) { pd->pd_id = pd_desc->bPowerDomainID; --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -259,6 +259,9 @@ static int create_yamaha_midi_quirk(stru NULL, USB_MS_MIDI_OUT_JACK); if (!injd && !outjd) return -ENODEV; + if (!snd_usb_validate_midi_desc(injd) || + !snd_usb_validate_midi_desc(outjd)) + return -ENODEV; if (injd && (injd->bLength < 5 || (injd->bJackType != USB_MS_EMBEDDED && injd->bJackType != USB_MS_EXTERNAL))) --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -637,16 +637,14 @@ static int parse_uac_endpoint_attributes */ static void * snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, - int terminal_id, bool uac23) + int terminal_id, int protocol) { struct uac2_input_terminal_descriptor *term = NULL; - size_t minlen = uac23 ? sizeof(struct uac2_input_terminal_descriptor) : - sizeof(struct uac_input_terminal_descriptor);
while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, term, UAC_INPUT_TERMINAL))) { - if (term->bLength < minlen) + if (!snd_usb_validate_audio_desc(term, protocol)) continue; if (term->bTerminalID == terminal_id) return term; @@ -657,7 +655,7 @@ snd_usb_find_input_terminal_descriptor(s
static void * snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, - int terminal_id) + int terminal_id, int protocol) { /* OK to use with both UAC2 and UAC3 */ struct uac2_output_terminal_descriptor *term = NULL; @@ -665,8 +663,9 @@ snd_usb_find_output_terminal_descriptor( while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, ctrl_iface->extralen, term, UAC_OUTPUT_TERMINAL))) { - if (term->bLength >= sizeof(*term) && - term->bTerminalID == terminal_id) + if (!snd_usb_validate_audio_desc(term, protocol)) + continue; + if (term->bTerminalID == terminal_id) return term; }
@@ -741,7 +740,7 @@ snd_usb_get_audioformat_uac12(struct snd
iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, as->bTerminalLink, - false); + protocol); if (iterm) { num_channels = iterm->bNrChannels; chconfig = le16_to_cpu(iterm->wChannelConfig); @@ -777,7 +776,7 @@ snd_usb_get_audioformat_uac12(struct snd */ input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, as->bTerminalLink, - true); + protocol); if (input_term) { clock = input_term->bCSourceID; if (!chconfig && (num_channels == input_term->bNrChannels)) @@ -786,7 +785,8 @@ snd_usb_get_audioformat_uac12(struct snd }
output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); + as->bTerminalLink, + protocol); if (output_term) { clock = output_term->bCSourceID; goto found_clock; @@ -1012,14 +1012,15 @@ snd_usb_get_audioformat_uac3(struct snd_ */ input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, as->bTerminalLink, - true); + UAC_VERSION_3); if (input_term) { clock = input_term->bCSourceID; goto found_clock; }
output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); + as->bTerminalLink, + UAC_VERSION_3); if (output_term) { clock = output_term->bCSourceID; goto found_clock; --- /dev/null +++ b/sound/usb/validate.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Validation of USB-audio class descriptors +// + +#include <linux/init.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> +#include <linux/usb/audio-v2.h> +#include <linux/usb/audio-v3.h> +#include <linux/usb/midi.h> +#include "usbaudio.h" +#include "helper.h" + +struct usb_desc_validator { + unsigned char protocol; + unsigned char type; + bool (*func)(const void *p, const struct usb_desc_validator *v); + size_t size; +}; + +#define UAC_VERSION_ALL (unsigned char)(-1) + +/* UAC1 only */ +static bool validate_uac1_header(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac1_ac_header_descriptor *d = p; + + return d->bLength >= sizeof(*d) && + d->bLength >= sizeof(*d) + d->bInCollection; +} + +/* for mixer unit; covering all UACs */ +static bool validate_mixer_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_mixer_unit_descriptor *d = p; + size_t len; + + if (d->bLength < sizeof(*d) || !d->bNrInPins) + return false; + len = sizeof(*d) + d->bNrInPins; + /* We can't determine the bitmap size only from this unit descriptor, + * so just check with the remaining length. + * The actual bitmap is checked at mixer unit parser. + */ + switch (v->protocol) { + case UAC_VERSION_1: + default: + len += 2 + 1; /* wChannelConfig, iChannelNames */ + /* bmControls[n*m] */ + len += 1; /* iMixer */ + break; + case UAC_VERSION_2: + len += 4 + 1; /* bmChannelConfig, iChannelNames */ + /* bmMixerControls[n*m] */ + len += 1 + 1; /* bmControls, iMixer */ + break; + case UAC_VERSION_3: + len += 2; /* wClusterDescrID */ + /* bmMixerControls[n*m] */ + break; + } + return d->bLength >= len; +} + +/* both for processing and extension units; covering all UACs */ +static bool validate_processing_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_processing_unit_descriptor *d = p; + const unsigned char *hdr = p; + size_t len, m; + + if (d->bLength < sizeof(*d)) + return false; + len = d->bLength < sizeof(*d) + d->bNrInPins; + if (d->bLength < len) + return false; + switch (v->protocol) { + case UAC_VERSION_1: + default: + /* bNrChannels, wChannelConfig, iChannelNames, bControlSize */ + len += 1 + 2 + 1 + 1; + if (d->bLength < len) /* bControlSize */ + return false; + m = hdr[len]; + len += 1 + m + 1; /* bControlSize, bmControls, iProcessing */ + break; + case UAC_VERSION_2: + /* bNrChannels, bmChannelConfig, iChannelNames */ + len += 1 + 4 + 1; + if (v->type == UAC2_PROCESSING_UNIT_V2) + len += 2; /* bmControls -- 2 bytes for PU */ + else + len += 1; /* bmControls -- 1 byte for EU */ + len += 1; /* iProcessing */ + break; + case UAC_VERSION_3: + /* wProcessingDescrStr, bmControls */ + len += 2 + 4; + break; + } + if (d->bLength < len) + return false; + + switch (v->protocol) { + case UAC_VERSION_1: + default: + if (v->type == UAC1_EXTENSION_UNIT) + return true; /* OK */ + switch (d->wProcessType) { + case UAC_PROCESS_UP_DOWNMIX: + case UAC_PROCESS_DOLBY_PROLOGIC: + if (d->bLength < len + 1) /* bNrModes */ + return false; + m = hdr[len]; + len += 1 + m * 2; /* bNrModes, waModes(n) */ + break; + default: + break; + } + break; + case UAC_VERSION_2: + if (v->type == UAC2_EXTENSION_UNIT_V2) + return true; /* OK */ + switch (d->wProcessType) { + case UAC2_PROCESS_UP_DOWNMIX: + case UAC2_PROCESS_DOLBY_PROLOCIC: /* SiC! */ + if (d->bLength < len + 1) /* bNrModes */ + return false; + m = hdr[len]; + len += 1 + m * 4; /* bNrModes, daModes(n) */ + break; + default: + break; + } + break; + case UAC_VERSION_3: + if (v->type == UAC3_EXTENSION_UNIT) { + len += 2; /* wClusterDescrID */ + break; + } + switch (d->wProcessType) { + case UAC3_PROCESS_UP_DOWNMIX: + if (d->bLength < len + 1) /* bNrModes */ + return false; + m = hdr[len]; + len += 1 + m * 2; /* bNrModes, waClusterDescrID(n) */ + break; + case UAC3_PROCESS_MULTI_FUNCTION: + len += 2 + 4; /* wClusterDescrID, bmAlgorighms */ + break; + default: + break; + } + break; + } + if (d->bLength < len) + return false; + + return true; +} + +/* both for selector and clock selector units; covering all UACs */ +static bool validate_selector_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_selector_unit_descriptor *d = p; + size_t len; + + if (d->bLength < sizeof(*d)) + return false; + len = sizeof(*d) + d->bNrInPins; + switch (v->protocol) { + case UAC_VERSION_1: + default: + len += 1; /* iSelector */ + break; + case UAC_VERSION_2: + len += 1 + 1; /* bmControls, iSelector */ + break; + case UAC_VERSION_3: + len += 4 + 2; /* bmControls, wSelectorDescrStr */ + break; + } + return d->bLength >= len; +} + +static bool validate_uac1_feature_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac_feature_unit_descriptor *d = p; + + if (d->bLength < sizeof(*d) || !d->bControlSize) + return false; + /* at least bmaControls(0) for master channel + iFeature */ + return d->bLength >= sizeof(*d) + d->bControlSize + 1; +} + +static bool validate_uac2_feature_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac2_feature_unit_descriptor *d = p; + + if (d->bLength < sizeof(*d)) + return false; + /* at least bmaControls(0) for master channel + iFeature */ + return d->bLength >= sizeof(*d) + 4 + 1; +} + +static bool validate_uac3_feature_unit(const void *p, + const struct usb_desc_validator *v) +{ + const struct uac3_feature_unit_descriptor *d = p; + + if (d->bLength < sizeof(*d)) + return false; + /* at least bmaControls(0) for master channel + wFeatureDescrStr */ + return d->bLength >= sizeof(*d) + 4 + 2; +} + +static bool validate_midi_out_jack(const void *p, + const struct usb_desc_validator *v) +{ + const struct usb_midi_out_jack_descriptor *d = p; + + return d->bLength >= sizeof(*d) && + d->bLength >= sizeof(*d) + d->bNrInputPins * 2; +} + +#define FIXED(p, t, s) { .protocol = (p), .type = (t), .size = sizeof(s) } +#define FUNC(p, t, f) { .protocol = (p), .type = (t), .func = (f) } + +static struct usb_desc_validator audio_validators[] = { + /* UAC1 */ + FUNC(UAC_VERSION_1, UAC_HEADER, validate_uac1_header), + FIXED(UAC_VERSION_1, UAC_INPUT_TERMINAL, + struct uac_input_terminal_descriptor), + FIXED(UAC_VERSION_1, UAC_OUTPUT_TERMINAL, + struct uac1_output_terminal_descriptor), + FUNC(UAC_VERSION_1, UAC_MIXER_UNIT, validate_mixer_unit), + FUNC(UAC_VERSION_1, UAC_SELECTOR_UNIT, validate_selector_unit), + FUNC(UAC_VERSION_1, UAC_FEATURE_UNIT, validate_uac1_feature_unit), + FUNC(UAC_VERSION_1, UAC1_PROCESSING_UNIT, validate_processing_unit), + FUNC(UAC_VERSION_1, UAC1_EXTENSION_UNIT, validate_processing_unit), + + /* UAC2 */ + FIXED(UAC_VERSION_2, UAC_HEADER, struct uac2_ac_header_descriptor), + FIXED(UAC_VERSION_2, UAC_INPUT_TERMINAL, + struct uac2_input_terminal_descriptor), + FIXED(UAC_VERSION_2, UAC_OUTPUT_TERMINAL, + struct uac2_output_terminal_descriptor), + FUNC(UAC_VERSION_2, UAC_MIXER_UNIT, validate_mixer_unit), + FUNC(UAC_VERSION_2, UAC_SELECTOR_UNIT, validate_selector_unit), + FUNC(UAC_VERSION_2, UAC_FEATURE_UNIT, validate_uac2_feature_unit), + /* UAC_VERSION_2, UAC2_EFFECT_UNIT: not implemented yet */ + FUNC(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2, validate_processing_unit), + FUNC(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2, validate_processing_unit), + FIXED(UAC_VERSION_2, UAC2_CLOCK_SOURCE, + struct uac_clock_source_descriptor), + FUNC(UAC_VERSION_2, UAC2_CLOCK_SELECTOR, validate_selector_unit), + FIXED(UAC_VERSION_2, UAC2_CLOCK_MULTIPLIER, + struct uac_clock_multiplier_descriptor), + /* UAC_VERSION_2, UAC2_SAMPLE_RATE_CONVERTER: not implemented yet */ + + /* UAC3 */ + FIXED(UAC_VERSION_2, UAC_HEADER, struct uac3_ac_header_descriptor), + FIXED(UAC_VERSION_3, UAC_INPUT_TERMINAL, + struct uac3_input_terminal_descriptor), + FIXED(UAC_VERSION_3, UAC_OUTPUT_TERMINAL, + struct uac3_output_terminal_descriptor), + /* UAC_VERSION_3, UAC3_EXTENDED_TERMINAL: not implemented yet */ + FUNC(UAC_VERSION_3, UAC3_MIXER_UNIT, validate_mixer_unit), + FUNC(UAC_VERSION_3, UAC3_SELECTOR_UNIT, validate_selector_unit), + FUNC(UAC_VERSION_3, UAC_FEATURE_UNIT, validate_uac3_feature_unit), + /* UAC_VERSION_3, UAC3_EFFECT_UNIT: not implemented yet */ + FUNC(UAC_VERSION_3, UAC3_PROCESSING_UNIT, validate_processing_unit), + FUNC(UAC_VERSION_3, UAC3_EXTENSION_UNIT, validate_processing_unit), + FIXED(UAC_VERSION_3, UAC3_CLOCK_SOURCE, + struct uac3_clock_source_descriptor), + FUNC(UAC_VERSION_3, UAC3_CLOCK_SELECTOR, validate_selector_unit), + FIXED(UAC_VERSION_3, UAC3_CLOCK_MULTIPLIER, + struct uac3_clock_multiplier_descriptor), + /* UAC_VERSION_3, UAC3_SAMPLE_RATE_CONVERTER: not implemented yet */ + /* UAC_VERSION_3, UAC3_CONNECTORS: not implemented yet */ + { } /* terminator */ +}; + +static struct usb_desc_validator midi_validators[] = { + FIXED(UAC_VERSION_ALL, USB_MS_HEADER, + struct usb_ms_header_descriptor), + FIXED(UAC_VERSION_ALL, USB_MS_MIDI_IN_JACK, + struct usb_midi_in_jack_descriptor), + FUNC(UAC_VERSION_ALL, USB_MS_MIDI_OUT_JACK, + validate_midi_out_jack), + { } /* terminator */ +}; + + +/* Validate the given unit descriptor, return true if it's OK */ +static bool validate_desc(unsigned char *hdr, int protocol, + const struct usb_desc_validator *v) +{ + if (hdr[1] != USB_DT_CS_INTERFACE) + return true; /* don't care */ + + for (; v->type; v++) { + if (v->type == hdr[2] && + (v->protocol == UAC_VERSION_ALL || + v->protocol == protocol)) { + if (v->func) + return v->func(hdr, v); + /* check for the fixed size */ + return hdr[0] >= v->size; + } + } + + return true; /* not matching, skip validation */ +} + +bool snd_usb_validate_audio_desc(void *p, int protocol) +{ + return validate_desc(p, protocol, audio_validators); +} + +bool snd_usb_validate_midi_desc(void *p) +{ + return validate_desc(p, UAC_VERSION_1, midi_validators); +} +
From: Takashi Iwai tiwai@suse.de
commit 68e9fde245591d18200f8a9054cac22339437adb upstream.
Minor code refactoring by combining the UAC version and the type in the switch-case flow, so that we reduce the indentation and redundancy. One good bonus is that the duplicated definition of the same type value (e.g. UAC2_EFFECT_UNIT) can be handled more cleanly.
Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- sound/usb/mixer.c | 95 ++++++++++++++++++++++-------------------------------- 1 file changed, 39 insertions(+), 56 deletions(-)
--- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2801,62 +2801,45 @@ static int parse_audio_unit(struct mixer return 0; /* skip invalid unit */ }
- if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { - switch (p1[2]) { - case UAC_INPUT_TERMINAL: - return parse_audio_input_terminal(state, unitid, p1); - case UAC_MIXER_UNIT: - return parse_audio_mixer_unit(state, unitid, p1); - case UAC2_CLOCK_SOURCE: - return parse_clock_source_unit(state, unitid, p1); - case UAC_SELECTOR_UNIT: - case UAC2_CLOCK_SELECTOR: - return parse_audio_selector_unit(state, unitid, p1); - case UAC_FEATURE_UNIT: - return parse_audio_feature_unit(state, unitid, p1); - case UAC1_PROCESSING_UNIT: - /* UAC2_EFFECT_UNIT has the same value */ - if (protocol == UAC_VERSION_1) - return parse_audio_processing_unit(state, unitid, p1); - else - return 0; /* FIXME - effect units not implemented yet */ - case UAC1_EXTENSION_UNIT: - /* UAC2_PROCESSING_UNIT_V2 has the same value */ - if (protocol == UAC_VERSION_1) - return parse_audio_extension_unit(state, unitid, p1); - else /* UAC_VERSION_2 */ - return parse_audio_processing_unit(state, unitid, p1); - case UAC2_EXTENSION_UNIT_V2: - return parse_audio_extension_unit(state, unitid, p1); - default: - usb_audio_err(state->chip, - "unit %u: unexpected type 0x%02x\n", unitid, p1[2]); - return -EINVAL; - } - } else { /* UAC_VERSION_3 */ - switch (p1[2]) { - case UAC_INPUT_TERMINAL: - return parse_audio_input_terminal(state, unitid, p1); - case UAC3_MIXER_UNIT: - return parse_audio_mixer_unit(state, unitid, p1); - case UAC3_CLOCK_SOURCE: - return parse_clock_source_unit(state, unitid, p1); - case UAC3_SELECTOR_UNIT: - case UAC3_CLOCK_SELECTOR: - return parse_audio_selector_unit(state, unitid, p1); - case UAC3_FEATURE_UNIT: - return parse_audio_feature_unit(state, unitid, p1); - case UAC3_EFFECT_UNIT: - return 0; /* FIXME - effect units not implemented yet */ - case UAC3_PROCESSING_UNIT: - return parse_audio_processing_unit(state, unitid, p1); - case UAC3_EXTENSION_UNIT: - return parse_audio_extension_unit(state, unitid, p1); - default: - usb_audio_err(state->chip, - "unit %u: unexpected type 0x%02x\n", unitid, p1[2]); - return -EINVAL; - } +#define PTYPE(a, b) ((a) << 8 | (b)) + switch (PTYPE(protocol, p1[2])) { + case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL): + case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL): + case PTYPE(UAC_VERSION_3, UAC_INPUT_TERMINAL): + return parse_audio_input_terminal(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_2, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_MIXER_UNIT): + return parse_audio_mixer_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SOURCE): + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SOURCE): + return parse_clock_source_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SELECTOR): + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SELECTOR): + return parse_audio_selector_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_2, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_FEATURE_UNIT): + return parse_audio_feature_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC1_PROCESSING_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_PROCESSING_UNIT): + return parse_audio_processing_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT): + return parse_audio_extension_unit(state, unitid, p1); + case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT): + return 0; /* FIXME - effect units not implemented yet */ + default: + usb_audio_err(state->chip, + "unit %u: unexpected type 0x%02x\n", + unitid, p1[2]); + return -EINVAL; } }
From: Takashi Iwai tiwai@suse.de
commit 52c3e317a857091fd746e15179a637f32be4d337 upstream.
Instead of the direct kfree() calls, introduce a new local helper to release the usb_mixer_elem_info object. This will be extended to do more than a single kfree() in the later patches.
Also, use the standard goto instead of multiple calls in parse_audio_selector_unit() error paths.
Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- sound/usb/mixer.c | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-)
--- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1041,10 +1041,15 @@ static struct usb_feature_control_info a { UAC2_FU_PHASE_INVERTER, "Phase Inverter Control", USB_MIXER_BOOLEAN, -1 }, };
+static void usb_mixer_elem_info_free(struct usb_mixer_elem_info *cval) +{ + kfree(cval); +} + /* private_free callback */ void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl) { - kfree(kctl->private_data); + usb_mixer_elem_info_free(kctl->private_data); kctl->private_data = NULL; }
@@ -1567,7 +1572,7 @@ static void __build_feature_ctl(struct u
ctl_info = get_feature_control_info(control); if (!ctl_info) { - kfree(cval); + usb_mixer_elem_info_free(cval); return; } if (mixer->protocol == UAC_VERSION_1) @@ -1600,7 +1605,7 @@ static void __build_feature_ctl(struct u
if (!kctl) { usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); - kfree(cval); + usb_mixer_elem_info_free(cval); return; } kctl->private_free = snd_usb_mixer_elem_free; @@ -1770,7 +1775,7 @@ static void build_connector_control(stru kctl = snd_ctl_new1(&usb_connector_ctl_ro, cval); if (!kctl) { usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); - kfree(cval); + usb_mixer_elem_info_free(cval); return; } get_connector_control_name(mixer, term, is_input, kctl->id.name, @@ -1823,7 +1828,7 @@ static int parse_clock_source_unit(struc kctl = snd_ctl_new1(&usb_bool_master_control_ctl_ro, cval);
if (!kctl) { - kfree(cval); + usb_mixer_elem_info_free(cval); return -ENOMEM; }
@@ -2089,7 +2094,7 @@ static void build_mixer_unit_ctl(struct kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); if (!kctl) { usb_audio_err(state->chip, "cannot malloc kcontrol\n"); - kfree(cval); + usb_mixer_elem_info_free(cval); return; } kctl->private_free = snd_usb_mixer_elem_free; @@ -2487,7 +2492,7 @@ static int build_audio_procunit(struct m
kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); if (!kctl) { - kfree(cval); + usb_mixer_elem_info_free(cval); return -ENOMEM; } kctl->private_free = snd_usb_mixer_elem_free; @@ -2625,7 +2630,7 @@ static void usb_mixer_selector_elem_free if (kctl->private_data) { struct usb_mixer_elem_info *cval = kctl->private_data; num_ins = cval->max; - kfree(cval); + usb_mixer_elem_info_free(cval); kctl->private_data = NULL; } if (kctl->private_value) { @@ -2697,10 +2702,10 @@ static int parse_audio_selector_unit(str break; }
- namelist = kmalloc_array(desc->bNrInPins, sizeof(char *), GFP_KERNEL); + namelist = kcalloc(desc->bNrInPins, sizeof(char *), GFP_KERNEL); if (!namelist) { - kfree(cval); - return -ENOMEM; + err = -ENOMEM; + goto error_cval; } #define MAX_ITEM_NAME_LEN 64 for (i = 0; i < desc->bNrInPins; i++) { @@ -2708,11 +2713,8 @@ static int parse_audio_selector_unit(str len = 0; namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL); if (!namelist[i]) { - while (i--) - kfree(namelist[i]); - kfree(namelist); - kfree(cval); - return -ENOMEM; + err = -ENOMEM; + goto error_name; } len = check_mapped_selector_name(state, unitid, i, namelist[i], MAX_ITEM_NAME_LEN); @@ -2726,10 +2728,8 @@ static int parse_audio_selector_unit(str kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval); if (! kctl) { usb_audio_err(state->chip, "cannot malloc kcontrol\n"); - for (i = 0; i < desc->bNrInPins; i++) - kfree(namelist[i]); - kfree(namelist); - kfree(cval); + err = -ENOMEM; + goto error_name; return -ENOMEM; } kctl->private_value = (unsigned long)namelist; @@ -2776,6 +2776,14 @@ static int parse_audio_selector_unit(str usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n", cval->head.id, kctl->id.name, desc->bNrInPins); return snd_usb_mixer_add_control(&cval->head, kctl); + + error_name: + for (i = 0; i < desc->bNrInPins; i++) + kfree(namelist[i]); + kfree(namelist); + error_cval: + usb_mixer_elem_info_free(cval); + return err; }
/*
From: Takashi Iwai tiwai@suse.de
commit b8e4f1fdfa422398c2d6c47bfb7d1feb3046d70a upstream.
Now that we got the more comprehensive validation code for USB-audio descriptors, the check of overflow in each descriptor unit parser became superfluous. Drop some of the obvious cases.
Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- sound/usb/clock.c | 14 +++------ sound/usb/mixer.c | 84 ------------------------------------------------------ 2 files changed, 6 insertions(+), 92 deletions(-)
--- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -52,39 +52,37 @@ static void *find_uac_clock_desc(struct static bool validate_clock_source_v2(void *p, int id) { struct uac_clock_source_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; }
static bool validate_clock_source_v3(void *p, int id) { struct uac3_clock_source_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; }
static bool validate_clock_selector_v2(void *p, int id) { struct uac_clock_selector_descriptor *cs = p; - return cs->bLength >= sizeof(*cs) && cs->bClockID == id && - cs->bLength == 7 + cs->bNrInPins; + return cs->bClockID == id; }
static bool validate_clock_selector_v3(void *p, int id) { struct uac3_clock_selector_descriptor *cs = p; - return cs->bLength >= sizeof(*cs) && cs->bClockID == id && - cs->bLength == 11 + cs->bNrInPins; + return cs->bClockID == id; }
static bool validate_clock_multiplier_v2(void *p, int id) { struct uac_clock_multiplier_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; }
static bool validate_clock_multiplier_v3(void *p, int id) { struct uac3_clock_multiplier_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; + return cs->bClockID == id; }
#define DEFINE_FIND_HELPER(name, obj, validator, type) \ --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -755,13 +755,6 @@ static int uac_mixer_unit_get_channels(s { int mu_channels;
- if (desc->bLength < sizeof(*desc)) - return -EINVAL; - if (!desc->bNrInPins) - return -EINVAL; - if (desc->bLength < sizeof(*desc) + desc->bNrInPins) - return -EINVAL; - switch (state->mixer->protocol) { case UAC_VERSION_1: case UAC_VERSION_2: @@ -1796,13 +1789,6 @@ static int parse_clock_source_unit(struc if (state->mixer->protocol != UAC_VERSION_2) return -EINVAL;
- if (hdr->bLength != sizeof(*hdr)) { - usb_audio_dbg(state->chip, - "Bogus clock source descriptor length of %d, ignoring.\n", - hdr->bLength); - return 0; - } - /* * The only property of this unit we are interested in is the * clock source validity. If that isn't readable, just bail out. @@ -1861,62 +1847,20 @@ static int parse_audio_feature_unit(stru __u8 *bmaControls;
if (state->mixer->protocol == UAC_VERSION_1) { - if (hdr->bLength < 7) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } csize = hdr->bControlSize; - if (!csize) { - usb_audio_dbg(state->chip, - "unit %u: invalid bControlSize == 0\n", - unitid); - return -EINVAL; - } channels = (hdr->bLength - 7) / csize - 1; bmaControls = hdr->bmaControls; - if (hdr->bLength < 7 + csize) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } } else if (state->mixer->protocol == UAC_VERSION_2) { struct uac2_feature_unit_descriptor *ftr = _ftr; - if (hdr->bLength < 6) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } csize = 4; channels = (hdr->bLength - 6) / 4 - 1; bmaControls = ftr->bmaControls; - if (hdr->bLength < 6 + csize) { - usb_audio_err(state->chip, - "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } } else { /* UAC_VERSION_3 */ struct uac3_feature_unit_descriptor *ftr = _ftr;
- if (hdr->bLength < 7) { - usb_audio_err(state->chip, - "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } csize = 4; channels = (ftr->bLength - 7) / 4 - 1; bmaControls = ftr->bmaControls; - if (hdr->bLength < 7 + csize) { - usb_audio_err(state->chip, - "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } }
/* parse the source unit */ @@ -2120,15 +2064,11 @@ static int parse_audio_input_terminal(st
if (state->mixer->protocol == UAC_VERSION_2) { struct uac2_input_terminal_descriptor *d_v2 = raw_desc; - if (d_v2->bLength < sizeof(*d_v2)) - return -EINVAL; control = UAC2_TE_CONNECTOR; term_id = d_v2->bTerminalID; bmctls = le16_to_cpu(d_v2->bmControls); } else if (state->mixer->protocol == UAC_VERSION_3) { struct uac3_input_terminal_descriptor *d_v3 = raw_desc; - if (d_v3->bLength < sizeof(*d_v3)) - return -EINVAL; control = UAC3_TE_INSERTION; term_id = d_v3->bTerminalID; bmctls = le32_to_cpu(d_v3->bmControls); @@ -2390,18 +2330,7 @@ static int build_audio_procunit(struct m const char *name = extension_unit ? "Extension Unit" : "Processing Unit";
- if (desc->bLength < 13) { - usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid); - return -EINVAL; - } - num_ins = desc->bNrInPins; - if (desc->bLength < 13 + num_ins || - desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) { - usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid); - return -EINVAL; - } - for (i = 0; i < num_ins; i++) { err = parse_audio_unit(state, desc->baSourceID[i]); if (err < 0) @@ -2656,13 +2585,6 @@ static int parse_audio_selector_unit(str const struct usbmix_name_map *map; char **namelist;
- if (desc->bLength < 5 || !desc->bNrInPins || - desc->bLength < 5 + desc->bNrInPins) { - usb_audio_err(state->chip, - "invalid SELECTOR UNIT descriptor %d\n", unitid); - return -EINVAL; - } - for (i = 0; i < desc->bNrInPins; i++) { err = parse_audio_unit(state, desc->baSourceID[i]); if (err < 0) @@ -3168,8 +3090,6 @@ static int snd_usb_mixer_controls(struct if (mixer->protocol == UAC_VERSION_1) { struct uac1_output_terminal_descriptor *desc = p;
- if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ /* mark terminal ID as visited */ set_bit(desc->bTerminalID, state.unitbitmap); state.oterm.id = desc->bTerminalID; @@ -3181,8 +3101,6 @@ static int snd_usb_mixer_controls(struct } else if (mixer->protocol == UAC_VERSION_2) { struct uac2_output_terminal_descriptor *desc = p;
- if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ /* mark terminal ID as visited */ set_bit(desc->bTerminalID, state.unitbitmap); state.oterm.id = desc->bTerminalID; @@ -3208,8 +3126,6 @@ static int snd_usb_mixer_controls(struct } else { /* UAC_VERSION_3 */ struct uac3_output_terminal_descriptor *desc = p;
- if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ /* mark terminal ID as visited */ set_bit(desc->bTerminalID, state.unitbitmap); state.oterm.id = desc->bTerminalID;
From: Takashi Iwai tiwai@suse.de
commit e0ccdef92653f8867e2d1667facfd3c23699f540 upstream.
The primary changes in this patch are cleanups of __check_input_term() and move to a non-nested switch-case block by evaluating the pair of UAC version and the unit type, as we've done for parse_audio_unit(). Also each parser is split into the function for readability.
Now, a slight behavior change by this cleanup is the handling of processing and extension units. Formerly we've dealt with them differently between UAC1/2 and UAC3; the latter returns an error if no input sources are available, while the former continues to parse.
In this patch, unify the behavior in all cases: when input sources are available, it parses recursively, then override the type and the id, as well as channel information if not provided yet.
Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- sound/usb/mixer.c | 407 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 212 insertions(+), 195 deletions(-)
--- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -773,224 +773,242 @@ static int uac_mixer_unit_get_channels(s }
/* - * parse the source unit recursively until it reaches to a terminal - * or a branched unit. + * Parse Input Terminal Unit */ static int __check_input_term(struct mixer_build *state, int id, - struct usb_audio_term *term) + struct usb_audio_term *term); + +static int parse_term_uac1_iterm_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac_input_terminal_descriptor *d = p1; + + term->type = le16_to_cpu(d->wTerminalType); + term->channels = d->bNrChannels; + term->chconfig = le16_to_cpu(d->wChannelConfig); + term->name = d->iTerminal; + return 0; +} + +static int parse_term_uac2_iterm_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) { - int protocol = state->mixer->protocol; + struct uac2_input_terminal_descriptor *d = p1; int err; - void *p1; - unsigned char *hdr;
- memset(term, 0, sizeof(*term)); - for (;;) { - /* a loop in the terminal chain? */ - if (test_and_set_bit(id, state->termbitmap)) - return -EINVAL; + /* call recursively to verify the referenced clock entity */ + err = __check_input_term(state, d->bCSourceID, term); + if (err < 0) + return err;
- p1 = find_audio_control_unit(state, id); - if (!p1) - break; - if (!snd_usb_validate_audio_desc(p1, protocol)) - break; /* bad descriptor */ + /* save input term properties after recursion, + * to ensure they are not overriden by the recursion calls + */ + term->id = id; + term->type = le16_to_cpu(d->wTerminalType); + term->channels = d->bNrChannels; + term->chconfig = le32_to_cpu(d->bmChannelConfig); + term->name = d->iTerminal; + return 0; +}
- hdr = p1; - term->id = id; +static int parse_term_uac3_iterm_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac3_input_terminal_descriptor *d = p1; + int err;
- if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { - switch (hdr[2]) { - case UAC_INPUT_TERMINAL: - if (protocol == UAC_VERSION_1) { - struct uac_input_terminal_descriptor *d = p1; - - term->type = le16_to_cpu(d->wTerminalType); - term->channels = d->bNrChannels; - term->chconfig = le16_to_cpu(d->wChannelConfig); - term->name = d->iTerminal; - } else { /* UAC_VERSION_2 */ - struct uac2_input_terminal_descriptor *d = p1; - - /* call recursively to verify that the - * referenced clock entity is valid */ - err = __check_input_term(state, d->bCSourceID, term); - if (err < 0) - return err; - - /* save input term properties after recursion, - * to ensure they are not overriden by the - * recursion calls */ - term->id = id; - term->type = le16_to_cpu(d->wTerminalType); - term->channels = d->bNrChannels; - term->chconfig = le32_to_cpu(d->bmChannelConfig); - term->name = d->iTerminal; - } - return 0; - case UAC_FEATURE_UNIT: { - /* the header is the same for v1 and v2 */ - struct uac_feature_unit_descriptor *d = p1; + /* call recursively to verify the referenced clock entity */ + err = __check_input_term(state, d->bCSourceID, term); + if (err < 0) + return err;
- id = d->bSourceID; - break; /* continue to parse */ - } - case UAC_MIXER_UNIT: { - struct uac_mixer_unit_descriptor *d = p1; + /* save input term properties after recursion, + * to ensure they are not overriden by the recursion calls + */ + term->id = id; + term->type = le16_to_cpu(d->wTerminalType);
- term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ - term->channels = uac_mixer_unit_bNrChannels(d); - term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol); - term->name = uac_mixer_unit_iMixer(d); - return 0; - } - case UAC_SELECTOR_UNIT: - case UAC2_CLOCK_SELECTOR: { - struct uac_selector_unit_descriptor *d = p1; - /* call recursively to retrieve the channel info */ - err = __check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; - term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ - term->id = id; - term->name = uac_selector_unit_iSelector(d); - return 0; - } - case UAC1_PROCESSING_UNIT: - /* UAC2_EFFECT_UNIT */ - if (protocol == UAC_VERSION_1) - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - else /* UAC_VERSION_2 */ - term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */ - /* fall through */ - case UAC1_EXTENSION_UNIT: - /* UAC2_PROCESSING_UNIT_V2 */ - if (protocol == UAC_VERSION_1 && !term->type) - term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ - else if (protocol == UAC_VERSION_2 && !term->type) - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - /* fall through */ - case UAC2_EXTENSION_UNIT_V2: { - struct uac_processing_unit_descriptor *d = p1; - - if (protocol == UAC_VERSION_2 && - hdr[2] == UAC2_EFFECT_UNIT) { - /* UAC2/UAC1 unit IDs overlap here in an - * uncompatible way. Ignore this unit for now. - */ - return 0; - } + err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID)); + if (err < 0) + return err; + term->channels = err;
- if (d->bNrInPins) { - id = d->baSourceID[0]; - break; /* continue to parse */ - } - if (!term->type) - term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ + /* REVISIT: UAC3 IT doesn't have channels cfg */ + term->chconfig = 0;
- term->channels = uac_processing_unit_bNrChannels(d); - term->chconfig = uac_processing_unit_wChannelConfig(d, protocol); - term->name = uac_processing_unit_iProcessing(d, protocol); - return 0; - } - case UAC2_CLOCK_SOURCE: { - struct uac_clock_source_descriptor *d = p1; + term->name = le16_to_cpu(d->wTerminalDescrStr); + return 0; +}
- term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ - term->id = id; - term->name = d->iClockSource; - return 0; - } - default: - return -ENODEV; - } - } else { /* UAC_VERSION_3 */ - switch (hdr[2]) { - case UAC_INPUT_TERMINAL: { - struct uac3_input_terminal_descriptor *d = p1; - - /* call recursively to verify that the - * referenced clock entity is valid */ - err = __check_input_term(state, d->bCSourceID, term); - if (err < 0) - return err; - - /* save input term properties after recursion, - * to ensure they are not overriden by the - * recursion calls */ - term->id = id; - term->type = le16_to_cpu(d->wTerminalType); - - err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID)); - if (err < 0) - return err; - term->channels = err; +static int parse_term_mixer_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac_mixer_unit_descriptor *d = p1; + int protocol = state->mixer->protocol; + int err;
- /* REVISIT: UAC3 IT doesn't have channels cfg */ - term->chconfig = 0; + err = uac_mixer_unit_get_channels(state, d); + if (err <= 0) + return err;
- term->name = le16_to_cpu(d->wTerminalDescrStr); - return 0; - } - case UAC3_FEATURE_UNIT: { - struct uac3_feature_unit_descriptor *d = p1; + term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ + term->channels = err; + if (protocol != UAC_VERSION_3) { + term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol); + term->name = uac_mixer_unit_iMixer(d); + } + return 0; +}
- id = d->bSourceID; - break; /* continue to parse */ - } - case UAC3_CLOCK_SOURCE: { - struct uac3_clock_source_descriptor *d = p1; +static int parse_term_selector_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac_selector_unit_descriptor *d = p1; + int err;
- term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ - term->id = id; - term->name = le16_to_cpu(d->wClockSourceStr); - return 0; - } - case UAC3_MIXER_UNIT: { - struct uac_mixer_unit_descriptor *d = p1; + /* call recursively to retrieve the channel info */ + err = __check_input_term(state, d->baSourceID[0], term); + if (err < 0) + return err; + term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ + term->id = id; + if (state->mixer->protocol != UAC_VERSION_3) + term->name = uac_selector_unit_iSelector(d); + return 0; +}
- err = uac_mixer_unit_get_channels(state, d); - if (err <= 0) - return err; +static int parse_term_proc_unit(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id, int vtype) +{ + struct uac_processing_unit_descriptor *d = p1; + int protocol = state->mixer->protocol; + int err;
- term->channels = err; - term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ + if (d->bNrInPins) { + /* call recursively to retrieve the channel info */ + err = __check_input_term(state, d->baSourceID[0], term); + if (err < 0) + return err; + }
- return 0; - } - case UAC3_SELECTOR_UNIT: - case UAC3_CLOCK_SELECTOR: { - struct uac_selector_unit_descriptor *d = p1; - /* call recursively to retrieve the channel info */ - err = __check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; - term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ - term->id = id; - term->name = 0; /* TODO: UAC3 Class-specific strings */ + term->type = vtype << 16; /* virtual type */ + term->id = id;
- return 0; - } - case UAC3_PROCESSING_UNIT: { - struct uac_processing_unit_descriptor *d = p1; + if (protocol == UAC_VERSION_3) + return 0;
- if (!d->bNrInPins) - return -EINVAL; + if (!term->channels) { + term->channels = uac_processing_unit_bNrChannels(d); + term->chconfig = uac_processing_unit_wChannelConfig(d, protocol); + } + term->name = uac_processing_unit_iProcessing(d, protocol); + return 0; +} + +static int parse_term_uac2_clock_source(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac_clock_source_descriptor *d = p1; + + term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ + term->id = id; + term->name = d->iClockSource; + return 0; +}
- /* call recursively to retrieve the channel info */ - err = __check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; - - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - term->id = id; - term->name = 0; /* TODO: UAC3 Class-specific strings */ +static int parse_term_uac3_clock_source(struct mixer_build *state, + struct usb_audio_term *term, + void *p1, int id) +{ + struct uac3_clock_source_descriptor *d = p1; + + term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ + term->id = id; + term->name = le16_to_cpu(d->wClockSourceStr); + return 0; +}
- return 0; - } - default: - return -ENODEV; - } +#define PTYPE(a, b) ((a) << 8 | (b)) + +/* + * parse the source unit recursively until it reaches to a terminal + * or a branched unit. + */ +static int __check_input_term(struct mixer_build *state, int id, + struct usb_audio_term *term) +{ + int protocol = state->mixer->protocol; + void *p1; + unsigned char *hdr; + + for (;;) { + /* a loop in the terminal chain? */ + if (test_and_set_bit(id, state->termbitmap)) + return -EINVAL; + + p1 = find_audio_control_unit(state, id); + if (!p1) + break; + if (!snd_usb_validate_audio_desc(p1, protocol)) + break; /* bad descriptor */ + + hdr = p1; + term->id = id; + + switch (PTYPE(protocol, hdr[2])) { + case PTYPE(UAC_VERSION_1, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_2, UAC_FEATURE_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_FEATURE_UNIT): { + /* the header is the same for all versions */ + struct uac_feature_unit_descriptor *d = p1; + + id = d->bSourceID; + break; /* continue to parse */ + } + case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL): + return parse_term_uac1_iterm_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL): + return parse_term_uac2_iterm_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_3, UAC_INPUT_TERMINAL): + return parse_term_uac3_iterm_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_1, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_2, UAC_MIXER_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_MIXER_UNIT): + return parse_term_mixer_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_1, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SELECTOR): + case PTYPE(UAC_VERSION_3, UAC3_SELECTOR_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SELECTOR): + return parse_term_selector_unit(state, term, p1, id); + case PTYPE(UAC_VERSION_1, UAC1_PROCESSING_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_PROCESSING_UNIT): + return parse_term_proc_unit(state, term, p1, id, + UAC3_PROCESSING_UNIT); + case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT): + case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT): + return parse_term_proc_unit(state, term, p1, id, + UAC3_EFFECT_UNIT); + case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT): + case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2): + case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT): + return parse_term_proc_unit(state, term, p1, id, + UAC3_EXTENSION_UNIT); + case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SOURCE): + return parse_term_uac2_clock_source(state, term, p1, id); + case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SOURCE): + return parse_term_uac3_clock_source(state, term, p1, id); + default: + return -ENODEV; } } return -ENODEV; @@ -2731,7 +2749,6 @@ static int parse_audio_unit(struct mixer return 0; /* skip invalid unit */ }
-#define PTYPE(a, b) ((a) << 8 | (b)) switch (PTYPE(protocol, p1[2])) { case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL): case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL):
From: Takashi Iwai tiwai@suse.de
commit 60849562a5db4a1eee2160167e4dce4590d3eafe upstream.
The previous addition of descriptor validation may lead to a NULL dereference at create_yamaha_midi_quirk() when either injd or outjd is NULL. Add proper non-NULL checks.
Fixes: 57f8770620e9 ("ALSA: usb-audio: More validations of descriptor units") Reported-by: Dan Carpenter dan.carpenter@oracle.com Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- sound/usb/quirks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -259,8 +259,8 @@ static int create_yamaha_midi_quirk(stru NULL, USB_MS_MIDI_OUT_JACK); if (!injd && !outjd) return -ENODEV; - if (!snd_usb_validate_midi_desc(injd) || - !snd_usb_validate_midi_desc(outjd)) + if (!(injd && snd_usb_validate_midi_desc(injd)) || + !(outjd && snd_usb_validate_midi_desc(outjd))) return -ENODEV; if (injd && (injd->bLength < 5 || (injd->bJackType != USB_MS_EMBEDDED &&
Hi!
From: Takashi Iwai tiwai@suse.de
commit 60849562a5db4a1eee2160167e4dce4590d3eafe upstream.
The previous addition of descriptor validation may lead to a NULL dereference at create_yamaha_midi_quirk() when either injd or outjd is NULL. Add proper non-NULL checks.
This is wrong.
@@ -259,8 +259,8 @@ static int create_yamaha_midi_quirk(stru NULL, USB_MS_MIDI_OUT_JACK); if (!injd && !outjd) return -ENODEV;
Clearly code wants to allow at most one of them to be NULL.
- if (!snd_usb_validate_midi_desc(injd) ||
!snd_usb_validate_midi_desc(outjd))
- if (!(injd && snd_usb_validate_midi_desc(injd)) ||
return -ENODEV;!(outjd && snd_usb_validate_midi_desc(outjd)))
Yet it will return here if it is. Correct check would be
+ if (!(!injd || snd_usb_validate_midi_desc(injd)) || + !(!outjd || snd_usb_validate_midi_desc(outjd)))
AFAICT.
Best regards, Pavel
On Wed, 13 Nov 2019 11:19:54 +0100, Pavel Machek wrote:
Hi!
From: Takashi Iwai tiwai@suse.de
commit 60849562a5db4a1eee2160167e4dce4590d3eafe upstream.
The previous addition of descriptor validation may lead to a NULL dereference at create_yamaha_midi_quirk() when either injd or outjd is NULL. Add proper non-NULL checks.
This is wrong.
@@ -259,8 +259,8 @@ static int create_yamaha_midi_quirk(stru NULL, USB_MS_MIDI_OUT_JACK); if (!injd && !outjd) return -ENODEV;
Clearly code wants to allow at most one of them to be NULL.
- if (!snd_usb_validate_midi_desc(injd) ||
!snd_usb_validate_midi_desc(outjd))
- if (!(injd && snd_usb_validate_midi_desc(injd)) ||
return -ENODEV;!(outjd && snd_usb_validate_midi_desc(outjd)))
Yet it will return here if it is. Correct check would be
if (!(!injd || snd_usb_validate_midi_desc(injd)) ||
!(!outjd || snd_usb_validate_midi_desc(outjd)))
AFAICT.
Erm, right, but a better representation is:
if ((injd && !snd_usb_validate_midi_desc(injd)) || (outjd && !snd_usb_validate_midi_desc(injd)))
thanks,
Takashi
On Wed, 13 Nov 2019 11:35:16 +0100, Takashi Iwai wrote:
On Wed, 13 Nov 2019 11:19:54 +0100, Pavel Machek wrote:
Hi!
From: Takashi Iwai tiwai@suse.de
commit 60849562a5db4a1eee2160167e4dce4590d3eafe upstream.
The previous addition of descriptor validation may lead to a NULL dereference at create_yamaha_midi_quirk() when either injd or outjd is NULL. Add proper non-NULL checks.
This is wrong.
@@ -259,8 +259,8 @@ static int create_yamaha_midi_quirk(stru NULL, USB_MS_MIDI_OUT_JACK); if (!injd && !outjd) return -ENODEV;
Clearly code wants to allow at most one of them to be NULL.
- if (!snd_usb_validate_midi_desc(injd) ||
!snd_usb_validate_midi_desc(outjd))
- if (!(injd && snd_usb_validate_midi_desc(injd)) ||
return -ENODEV;!(outjd && snd_usb_validate_midi_desc(outjd)))
Yet it will return here if it is. Correct check would be
if (!(!injd || snd_usb_validate_midi_desc(injd)) ||
!(!outjd || snd_usb_validate_midi_desc(outjd)))
AFAICT.
Erm, right, but a better representation is:
if ((injd && !snd_usb_validate_midi_desc(injd)) || (outjd && !snd_usb_validate_midi_desc(injd)))
Of course, another typo:
if ((injd && !snd_usb_validate_midi_desc(injd)) || (outjd && !snd_usb_validate_midi_desc(outjd)))
Takashi
Hi!
Clearly code wants to allow at most one of them to be NULL.
- if (!snd_usb_validate_midi_desc(injd) ||
!snd_usb_validate_midi_desc(outjd))
- if (!(injd && snd_usb_validate_midi_desc(injd)) ||
return -ENODEV;!(outjd && snd_usb_validate_midi_desc(outjd)))
Yet it will return here if it is. Correct check would be
if (!(!injd || snd_usb_validate_midi_desc(injd)) ||
!(!outjd || snd_usb_validate_midi_desc(outjd)))
AFAICT.
Erm, right, but a better representation is:
if ((injd && !snd_usb_validate_midi_desc(injd)) || (outjd && !snd_usb_validate_midi_desc(injd)))
Of course, another typo:
if ((injd && !snd_usb_validate_midi_desc(injd)) || (outjd && !snd_usb_validate_midi_desc(outjd)))
Agreed, that is better. I was focusing on boolean algebra too much.
Best regards, Pavel
From: Dan Carpenter dan.carpenter@oracle.com
commit b39e077fcb283dd96dd251a3abeba585402c61fe upstream.
We recently cleaned up the error handling in commit 52c3e317a857 ("ALSA: usb-audio: Unify the release of usb_mixer_elem_info objects") but accidentally left this stray return.
Fixes: 52c3e317a857 ("ALSA: usb-audio: Unify the release of usb_mixer_elem_info objects") Signed-off-by: Dan Carpenter dan.carpenter@oracle.com Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- sound/usb/mixer.c | 1 - 1 file changed, 1 deletion(-)
--- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2670,7 +2670,6 @@ static int parse_audio_selector_unit(str usb_audio_err(state->chip, "cannot malloc kcontrol\n"); err = -ENOMEM; goto error_name; - return -ENOMEM; } kctl->private_value = (unsigned long)namelist; kctl->private_free = usb_mixer_selector_elem_free;
From: Takashi Iwai tiwai@suse.de
commit ba8bf0967a154796be15c4983603aad0b05c3138 upstream.
The recently introduced USB-audio descriptor validator had a stupid copy&paste error that may lead to an unexpected overlook of too short descriptors for processing and extension units. It's likely the cause of the report triggered by syzkaller fuzzer. Let's fix it.
Fixes: 57f8770620e9 ("ALSA: usb-audio: More validations of descriptor units") Reported-by: syzbot+0620f79a1978b1133fd7@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/s5hsgnkdbsl.wl-tiwai@suse.de Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- sound/usb/validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/sound/usb/validate.c +++ b/sound/usb/validate.c @@ -75,7 +75,7 @@ static bool validate_processing_unit(con
if (d->bLength < sizeof(*d)) return false; - len = d->bLength < sizeof(*d) + d->bNrInPins; + len = sizeof(*d) + d->bNrInPins; if (d->bLength < len) return false; switch (v->protocol) {
From: Dave Chiluk chiluk+linux@indeed.com
commit de53fd7aedb100f03e5d2231cfce0e4993282425 upstream.
It has been observed, that highly-threaded, non-cpu-bound applications running under cpu.cfs_quota_us constraints can hit a high percentage of periods throttled while simultaneously not consuming the allocated amount of quota. This use case is typical of user-interactive non-cpu bound applications, such as those running in kubernetes or mesos when run on multiple cpu cores.
This has been root caused to cpu-local run queue being allocated per cpu bandwidth slices, and then not fully using that slice within the period. At which point the slice and quota expires. This expiration of unused slice results in applications not being able to utilize the quota for which they are allocated.
The non-expiration of per-cpu slices was recently fixed by 'commit 512ac999d275 ("sched/fair: Fix bandwidth timer clock drift condition")'. Prior to that it appears that this had been broken since at least 'commit 51f2176d74ac ("sched/fair: Fix unlocked reads of some cfs_b->quota/period")' which was introduced in v3.16-rc1 in 2014. That added the following conditional which resulted in slices never being expired.
if (cfs_rq->runtime_expires != cfs_b->runtime_expires) { /* extend local deadline, drift is bounded above by 2 ticks */ cfs_rq->runtime_expires += TICK_NSEC;
Because this was broken for nearly 5 years, and has recently been fixed and is now being noticed by many users running kubernetes (https://github.com/kubernetes/kubernetes/issues/67577) it is my opinion that the mechanisms around expiring runtime should be removed altogether.
This allows quota already allocated to per-cpu run-queues to live longer than the period boundary. This allows threads on runqueues that do not use much CPU to continue to use their remaining slice over a longer period of time than cpu.cfs_period_us. However, this helps prevent the above condition of hitting throttling while also not fully utilizing your cpu quota.
This theoretically allows a machine to use slightly more than its allotted quota in some periods. This overflow would be bounded by the remaining quota left on each per-cpu runqueueu. This is typically no more than min_cfs_rq_runtime=1ms per cpu. For CPU bound tasks this will change nothing, as they should theoretically fully utilize all of their quota in each period. For user-interactive tasks as described above this provides a much better user/application experience as their cpu utilization will more closely match the amount they requested when they hit throttling. This means that cpu limits no longer strictly apply per period for non-cpu bound applications, but that they are still accurate over longer timeframes.
This greatly improves performance of high-thread-count, non-cpu bound applications with low cfs_quota_us allocation on high-core-count machines. In the case of an artificial testcase (10ms/100ms of quota on 80 CPU machine), this commit resulted in almost 30x performance improvement, while still maintaining correct cpu quota restrictions. That testcase is available at https://github.com/indeedeng/fibtest.
Fixes: 512ac999d275 ("sched/fair: Fix bandwidth timer clock drift condition") Signed-off-by: Dave Chiluk chiluk+linux@indeed.com Signed-off-by: Peter Zijlstra (Intel) peterz@infradead.org Reviewed-by: Phil Auld pauld@redhat.com Reviewed-by: Ben Segall bsegall@google.com Cc: Ingo Molnar mingo@redhat.com Cc: John Hammond jhammond@indeed.com Cc: Jonathan Corbet corbet@lwn.net Cc: Kyle Anderson kwa@yelp.com Cc: Gabriel Munos gmunoz@netflix.com Cc: Peter Oskolkov posk@posk.io Cc: Cong Wang xiyou.wangcong@gmail.com Cc: Brendan Gregg bgregg@netflix.com Link: https://lkml.kernel.org/r/1563900266-19734-2-git-send-email-chiluk+linux@ind... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- Documentation/scheduler/sched-bwc.txt | 45 +++++++++++++++++++++ kernel/sched/fair.c | 72 +++------------------------------- kernel/sched/sched.h | 4 - 3 files changed, 52 insertions(+), 69 deletions(-)
--- a/Documentation/scheduler/sched-bwc.txt +++ b/Documentation/scheduler/sched-bwc.txt @@ -90,6 +90,51 @@ There are two ways in which a group may In case b) above, even though the child may have runtime remaining it will not be allowed to until the parent's runtime is refreshed.
+CFS Bandwidth Quota Caveats +--------------------------- +Once a slice is assigned to a cpu it does not expire. However all but 1ms of +the slice may be returned to the global pool if all threads on that cpu become +unrunnable. This is configured at compile time by the min_cfs_rq_runtime +variable. This is a performance tweak that helps prevent added contention on +the global lock. + +The fact that cpu-local slices do not expire results in some interesting corner +cases that should be understood. + +For cgroup cpu constrained applications that are cpu limited this is a +relatively moot point because they will naturally consume the entirety of their +quota as well as the entirety of each cpu-local slice in each period. As a +result it is expected that nr_periods roughly equal nr_throttled, and that +cpuacct.usage will increase roughly equal to cfs_quota_us in each period. + +For highly-threaded, non-cpu bound applications this non-expiration nuance +allows applications to briefly burst past their quota limits by the amount of +unused slice on each cpu that the task group is running on (typically at most +1ms per cpu or as defined by min_cfs_rq_runtime). This slight burst only +applies if quota had been assigned to a cpu and then not fully used or returned +in previous periods. This burst amount will not be transferred between cores. +As a result, this mechanism still strictly limits the task group to quota +average usage, albeit over a longer time window than a single period. This +also limits the burst ability to no more than 1ms per cpu. This provides +better more predictable user experience for highly threaded applications with +small quota limits on high core count machines. It also eliminates the +propensity to throttle these applications while simultanously using less than +quota amounts of cpu. Another way to say this, is that by allowing the unused +portion of a slice to remain valid across periods we have decreased the +possibility of wastefully expiring quota on cpu-local silos that don't need a +full slice's amount of cpu time. + +The interaction between cpu-bound and non-cpu-bound-interactive applications +should also be considered, especially when single core usage hits 100%. If you +gave each of these applications half of a cpu-core and they both got scheduled +on the same CPU it is theoretically possible that the non-cpu bound application +will use up to 1ms additional quota in some periods, thereby preventing the +cpu-bound application from fully using its quota by that same amount. In these +instances it will be up to the CFS algorithm (see sched-design-CFS.rst) to +decide which application is chosen to run, as they will both be runnable and +have remaining quota. This runtime discrepancy will be made up in the following +periods when the interactive application idles. + Examples -------- 1. Limit a group to 1 CPU worth of runtime. --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4320,8 +4320,6 @@ void __refill_cfs_bandwidth_runtime(stru
now = sched_clock_cpu(smp_processor_id()); cfs_b->runtime = cfs_b->quota; - cfs_b->runtime_expires = now + ktime_to_ns(cfs_b->period); - cfs_b->expires_seq++; }
static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg) @@ -4343,8 +4341,7 @@ static int assign_cfs_rq_runtime(struct { struct task_group *tg = cfs_rq->tg; struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(tg); - u64 amount = 0, min_amount, expires; - int expires_seq; + u64 amount = 0, min_amount;
/* note: this is a positive sum as runtime_remaining <= 0 */ min_amount = sched_cfs_bandwidth_slice() - cfs_rq->runtime_remaining; @@ -4361,61 +4358,17 @@ static int assign_cfs_rq_runtime(struct cfs_b->idle = 0; } } - expires_seq = cfs_b->expires_seq; - expires = cfs_b->runtime_expires; raw_spin_unlock(&cfs_b->lock);
cfs_rq->runtime_remaining += amount; - /* - * we may have advanced our local expiration to account for allowed - * spread between our sched_clock and the one on which runtime was - * issued. - */ - if (cfs_rq->expires_seq != expires_seq) { - cfs_rq->expires_seq = expires_seq; - cfs_rq->runtime_expires = expires; - }
return cfs_rq->runtime_remaining > 0; }
-/* - * Note: This depends on the synchronization provided by sched_clock and the - * fact that rq->clock snapshots this value. - */ -static void expire_cfs_rq_runtime(struct cfs_rq *cfs_rq) -{ - struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg); - - /* if the deadline is ahead of our clock, nothing to do */ - if (likely((s64)(rq_clock(rq_of(cfs_rq)) - cfs_rq->runtime_expires) < 0)) - return; - - if (cfs_rq->runtime_remaining < 0) - return; - - /* - * If the local deadline has passed we have to consider the - * possibility that our sched_clock is 'fast' and the global deadline - * has not truly expired. - * - * Fortunately we can check determine whether this the case by checking - * whether the global deadline(cfs_b->expires_seq) has advanced. - */ - if (cfs_rq->expires_seq == cfs_b->expires_seq) { - /* extend local deadline, drift is bounded above by 2 ticks */ - cfs_rq->runtime_expires += TICK_NSEC; - } else { - /* global deadline is ahead, expiration has passed */ - cfs_rq->runtime_remaining = 0; - } -} - static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) { /* dock delta_exec before expiring quota (as it could span periods) */ cfs_rq->runtime_remaining -= delta_exec; - expire_cfs_rq_runtime(cfs_rq);
if (likely(cfs_rq->runtime_remaining > 0)) return; @@ -4600,8 +4553,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cf resched_curr(rq); }
-static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b, - u64 remaining, u64 expires) +static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b, u64 remaining) { struct cfs_rq *cfs_rq; u64 runtime; @@ -4626,7 +4578,6 @@ static u64 distribute_cfs_runtime(struct remaining -= runtime;
cfs_rq->runtime_remaining += runtime; - cfs_rq->runtime_expires = expires;
/* we check whether we're throttled above */ if (cfs_rq->runtime_remaining > 0) @@ -4651,7 +4602,7 @@ next: */ static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun) { - u64 runtime, runtime_expires; + u64 runtime; int throttled;
/* no need to continue the timer with no bandwidth constraint */ @@ -4679,8 +4630,6 @@ static int do_sched_cfs_period_timer(str /* account preceding periods in which throttling occurred */ cfs_b->nr_throttled += overrun;
- runtime_expires = cfs_b->runtime_expires; - /* * This check is repeated as we are holding onto the new bandwidth while * we unthrottle. This can potentially race with an unthrottled group @@ -4693,8 +4642,7 @@ static int do_sched_cfs_period_timer(str cfs_b->distribute_running = 1; raw_spin_unlock(&cfs_b->lock); /* we can't nest cfs_b->lock while distributing bandwidth */ - runtime = distribute_cfs_runtime(cfs_b, runtime, - runtime_expires); + runtime = distribute_cfs_runtime(cfs_b, runtime); raw_spin_lock(&cfs_b->lock);
cfs_b->distribute_running = 0; @@ -4771,8 +4719,7 @@ static void __return_cfs_rq_runtime(stru return;
raw_spin_lock(&cfs_b->lock); - if (cfs_b->quota != RUNTIME_INF && - cfs_rq->runtime_expires == cfs_b->runtime_expires) { + if (cfs_b->quota != RUNTIME_INF) { cfs_b->runtime += slack_runtime;
/* we are under rq->lock, defer unthrottling using a timer */ @@ -4804,7 +4751,6 @@ static __always_inline void return_cfs_r static void do_sched_cfs_slack_timer(struct cfs_bandwidth *cfs_b) { u64 runtime = 0, slice = sched_cfs_bandwidth_slice(); - u64 expires;
/* confirm we're still not at a refresh boundary */ raw_spin_lock(&cfs_b->lock); @@ -4821,7 +4767,6 @@ static void do_sched_cfs_slack_timer(str if (cfs_b->quota != RUNTIME_INF && cfs_b->runtime > slice) runtime = cfs_b->runtime;
- expires = cfs_b->runtime_expires; if (runtime) cfs_b->distribute_running = 1;
@@ -4830,11 +4775,10 @@ static void do_sched_cfs_slack_timer(str if (!runtime) return;
- runtime = distribute_cfs_runtime(cfs_b, runtime, expires); + runtime = distribute_cfs_runtime(cfs_b, runtime);
raw_spin_lock(&cfs_b->lock); - if (expires == cfs_b->runtime_expires) - cfs_b->runtime -= min(runtime, cfs_b->runtime); + cfs_b->runtime -= min(runtime, cfs_b->runtime); cfs_b->distribute_running = 0; raw_spin_unlock(&cfs_b->lock); } @@ -4989,8 +4933,6 @@ void start_cfs_bandwidth(struct cfs_band
cfs_b->period_active = 1; overrun = hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period); - cfs_b->runtime_expires += (overrun + 1) * ktime_to_ns(cfs_b->period); - cfs_b->expires_seq++; hrtimer_start_expires(&cfs_b->period_timer, HRTIMER_MODE_ABS_PINNED); }
--- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -334,8 +334,6 @@ struct cfs_bandwidth { u64 quota; u64 runtime; s64 hierarchical_quota; - u64 runtime_expires; - int expires_seq;
short idle; short period_active; @@ -555,8 +553,6 @@ struct cfs_rq {
#ifdef CONFIG_CFS_BANDWIDTH int runtime_enabled; - int expires_seq; - u64 runtime_expires; s64 runtime_remaining;
u64 throttled_clock;
From: Qian Cai cai@lca.pw
commit 763a9ec06c409dcde2a761aac4bb83ff3938e0b3 upstream.
Commit:
de53fd7aedb1 ("sched/fair: Fix low cpu usage with high throttling by removing expiration of cpu-local slices")
introduced a few compilation warnings:
kernel/sched/fair.c: In function '__refill_cfs_bandwidth_runtime': kernel/sched/fair.c:4365:6: warning: variable 'now' set but not used [-Wunused-but-set-variable] kernel/sched/fair.c: In function 'start_cfs_bandwidth': kernel/sched/fair.c:4992:6: warning: variable 'overrun' set but not used [-Wunused-but-set-variable]
Also, __refill_cfs_bandwidth_runtime() does no longer update the expiration time, so fix the comments accordingly.
Signed-off-by: Qian Cai cai@lca.pw Signed-off-by: Peter Zijlstra (Intel) peterz@infradead.org Reviewed-by: Ben Segall bsegall@google.com Reviewed-by: Dave Chiluk chiluk+linux@indeed.com Cc: Linus Torvalds torvalds@linux-foundation.org Cc: Peter Zijlstra peterz@infradead.org Cc: Thomas Gleixner tglx@linutronix.de Cc: pauld@redhat.com Fixes: de53fd7aedb1 ("sched/fair: Fix low cpu usage with high throttling by removing expiration of cpu-local slices") Link: https://lkml.kernel.org/r/1566326455-8038-1-git-send-email-cai@lca.pw Signed-off-by: Ingo Molnar mingo@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- kernel/sched/fair.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-)
--- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4305,21 +4305,16 @@ static inline u64 sched_cfs_bandwidth_sl }
/* - * Replenish runtime according to assigned quota and update expiration time. - * We use sched_clock_cpu directly instead of rq->clock to avoid adding - * additional synchronization around rq->lock. + * Replenish runtime according to assigned quota. We use sched_clock_cpu + * directly instead of rq->clock to avoid adding additional synchronization + * around rq->lock. * * requires cfs_b->lock */ void __refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b) { - u64 now; - - if (cfs_b->quota == RUNTIME_INF) - return; - - now = sched_clock_cpu(smp_processor_id()); - cfs_b->runtime = cfs_b->quota; + if (cfs_b->quota != RUNTIME_INF) + cfs_b->runtime = cfs_b->quota; }
static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg) @@ -4924,15 +4919,13 @@ static void init_cfs_rq_runtime(struct c
void start_cfs_bandwidth(struct cfs_bandwidth *cfs_b) { - u64 overrun; - lockdep_assert_held(&cfs_b->lock);
if (cfs_b->period_active) return;
cfs_b->period_active = 1; - overrun = hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period); + hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period); hrtimer_start_expires(&cfs_b->period_timer, HRTIMER_MODE_ABS_PINNED); }
From: Shuah Khan shuah@kernel.org
commit 2c904963b1dd2acd4bc785b6c72e10a6283c2081 upstream.
Fix vhci_urb_enqueue() to print debug msg and return error instead of failing with BUG_ON.
Signed-off-by: Shuah Khan shuah@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/usb/usbip/vhci_hcd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
--- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -702,8 +702,10 @@ static int vhci_urb_enqueue(struct usb_h } vdev = &vhci_hcd->vdev[portnum-1];
- /* patch to usb_sg_init() is in 2.5.60 */ - BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length); + if (!urb->transfer_buffer && urb->transfer_buffer_length) { + dev_dbg(dev, "Null URB transfer buffer\n"); + return -EINVAL; + }
spin_lock_irqsave(&vhci->lock, flags);
From: Suwan Kim suwan.kim027@gmail.com
commit ea44d190764b4422af4d1c29eaeb9e69e353b406 upstream.
There are bugs on vhci with usb 3.0 storage device. In USB, each SG list entry buffer should be divisible by the bulk max packet size. But with native SG support, this problem doesn't matter because the SG buffer is treated as contiguous buffer. But without native SG support, USB storage driver breaks SG list into several URBs and the error occurs because of a buffer size of URB that cannot be divided by the bulk max packet size. The error situation is as follows.
When USB Storage driver requests 31.5 KB data and has SG list which has 3584 bytes buffer followed by 7 4096 bytes buffer for some reason. USB Storage driver splits this SG list into several URBs because VHCI doesn't support SG and sends them separately. So the first URB buffer size is 3584 bytes. When receiving data from device, USB 3.0 device sends data packet of 1024 bytes size because the max packet size of BULK pipe is 1024 bytes. So device sends 4096 bytes. But the first URB buffer has only 3584 bytes buffer size. So host controller terminates the transfer even though there is more data to receive. So, vhci needs to support SG transfer to prevent this error.
In this patch, vhci supports SG regardless of whether the server's host controller supports SG or not, because stub driver splits SG list into several URBs if the server's host controller doesn't support SG.
To support SG, vhci sets URB_DMA_MAP_SG flag in urb->transfer_flags if URB has SG list and this flag will tell stub driver to use SG list. After receiving urb from stub driver, vhci clear URB_DMA_MAP_SG flag to avoid unnecessary DMA unmapping in HCD.
vhci sends each SG list entry to stub driver. Then, stub driver sees the total length of the buffer and allocates SG table and pages according to the total buffer length calling sgl_alloc(). After stub driver receives completed URB, it again sends each SG list entry to vhci.
If the server's host controller doesn't support SG, stub driver breaks a single SG request into several URBs and submits them to the server's host controller. When all the split URBs are completed, stub driver reassembles the URBs into a single return command and sends it to vhci.
Moreover, in the situation where vhci supports SG, but stub driver does not, or vice versa, usbip works normally. Because there is no protocol modification, there is no problem in communication between server and client even if the one has a kernel without SG support.
In the case of vhci supports SG and stub driver doesn't, because vhci sends only the total length of the buffer to stub driver as it did before the patch applied, stub driver only needs to allocate the required length of buffers using only kmalloc() regardless of whether vhci supports SG or not. But stub driver has to allocate buffer with kmalloc() as much as the total length of SG buffer which is quite huge when vhci sends SG request, so it has overhead in buffer allocation in this situation.
If stub driver needs to send data buffer to vhci because of IN pipe, stub driver also sends only total length of buffer as metadata and then sends real data as vhci does. Then vhci receive data from stub driver and store it to the corresponding buffer of SG list entry.
And for the case of stub driver supports SG and vhci doesn't, since the USB storage driver checks that vhci doesn't support SG and sends the request to stub driver by splitting the SG list into multiple URBs, stub driver allocates a buffer for each URB with kmalloc() as it did before this patch.
* Test environment
Test uses two difference machines and two different kernel version to make mismatch situation between the client and the server where vhci supports SG, but stub driver does not, or vice versa. All tests are conducted in both full SG support that both vhci and stub support SG and half SG support that is the mismatch situation. Test kernel version is 5.3-rc6 with commit "usb: add a HCD_DMA flag instead of guestimating DMA capabilities" to avoid unnecessary DMA mapping and unmapping.
- Test kernel version - 5.3-rc6 with SG support - 5.1.20-200.fc29.x86_64 without SG support
* SG support test
- Test devices - Super-speed storage device - SanDisk Ultra USB 3.0 - High-speed storage device - SMI corporation USB 2.0 flash drive
- Test description
Test read and write operation of mass storage device that uses the BULK transfer. In test, the client reads and writes files whose size is over 1G and it works normally.
* Regression test
- Test devices - Super-speed device - Logitech Brio webcam - High-speed device - Logitech C920 HD Pro webcam - Full-speed device - Logitech bluetooth mouse - Britz BR-Orion speaker - Low-speed device - Logitech wired mouse
- Test description
Moving and click test for mouse. To test the webcam, use gnome-cheese. To test the speaker, play music and video on the client. All works normally.
* VUDC compatibility test
VUDC also works well with this patch. Tests are done with two USB gadget created by CONFIGFS USB gadget. Both use the BULK pipe.
1. Serial gadget 2. Mass storage gadget
- Serial gadget test
Serial gadget on the host sends and receives data using cat command on the /dev/ttyGS<N>. The client uses minicom to communicate with the serial gadget.
- Mass storage gadget test
After connecting the gadget with vhci, use "dd" to test read and write operation on the client side.
Read - dd if=/dev/sd<N> iflag=direct of=/dev/null bs=1G count=1 Write - dd if=<my file path> iflag=direct of=/dev/sd<N> bs=1G count=1
Signed-off-by: Suwan Kim suwan.kim027@gmail.com Acked-by: Shuah khan skhan@linuxfoundation.org Link: https://lore.kernel.org/r/20190828032741.12234-1-suwan.kim027@gmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/usb/usbip/stub.h | 7 + drivers/usb/usbip/stub_main.c | 57 ++++++++--- drivers/usb/usbip/stub_rx.c | 202 +++++++++++++++++++++++++++------------ drivers/usb/usbip/stub_tx.c | 99 ++++++++++++++----- drivers/usb/usbip/usbip_common.c | 59 +++++++---- drivers/usb/usbip/vhci_hcd.c | 12 ++ drivers/usb/usbip/vhci_rx.c | 3 drivers/usb/usbip/vhci_tx.c | 66 ++++++++++-- 8 files changed, 379 insertions(+), 126 deletions(-)
--- a/drivers/usb/usbip/stub.h +++ b/drivers/usb/usbip/stub.h @@ -52,7 +52,11 @@ struct stub_priv { unsigned long seqnum; struct list_head list; struct stub_device *sdev; - struct urb *urb; + struct urb **urbs; + struct scatterlist *sgl; + int num_urbs; + int completed_urbs; + int urb_status;
int unlinking; }; @@ -86,6 +90,7 @@ extern struct usb_device_driver stub_dri struct bus_id_priv *get_busid_priv(const char *busid); void put_busid_priv(struct bus_id_priv *bid); int del_match_busid(char *busid); +void stub_free_priv_and_urb(struct stub_priv *priv); void stub_device_cleanup_urbs(struct stub_device *sdev);
/* stub_rx.c */ --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -6,6 +6,7 @@ #include <linux/string.h> #include <linux/module.h> #include <linux/device.h> +#include <linux/scatterlist.h>
#include "usbip_common.h" #include "stub.h" @@ -283,13 +284,49 @@ static struct stub_priv *stub_priv_pop_f struct stub_priv *priv, *tmp;
list_for_each_entry_safe(priv, tmp, listhead, list) { - list_del(&priv->list); + list_del_init(&priv->list); return priv; }
return NULL; }
+void stub_free_priv_and_urb(struct stub_priv *priv) +{ + struct urb *urb; + int i; + + for (i = 0; i < priv->num_urbs; i++) { + urb = priv->urbs[i]; + + if (!urb) + return; + + kfree(urb->setup_packet); + urb->setup_packet = NULL; + + + if (urb->transfer_buffer && !priv->sgl) { + kfree(urb->transfer_buffer); + urb->transfer_buffer = NULL; + } + + if (urb->num_sgs) { + sgl_free(urb->sg); + urb->sg = NULL; + urb->num_sgs = 0; + } + + usb_free_urb(urb); + } + if (!list_empty(&priv->list)) + list_del(&priv->list); + if (priv->sgl) + sgl_free(priv->sgl); + kfree(priv->urbs); + kmem_cache_free(stub_priv_cache, priv); +} + static struct stub_priv *stub_priv_pop(struct stub_device *sdev) { unsigned long flags; @@ -316,25 +353,15 @@ done: void stub_device_cleanup_urbs(struct stub_device *sdev) { struct stub_priv *priv; - struct urb *urb; + int i;
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 seqnum %lu\n", - priv->seqnum); - usb_kill_urb(urb); - - kmem_cache_free(stub_priv_cache, priv); + for (i = 0; i < priv->num_urbs; i++) + usb_kill_urb(priv->urbs[i]);
- kfree(urb->transfer_buffer); - urb->transfer_buffer = NULL; - - kfree(urb->setup_packet); - urb->setup_packet = NULL; - - usb_free_urb(urb); + stub_free_priv_and_urb(priv); } }
--- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c @@ -7,6 +7,7 @@ #include <linux/kthread.h> #include <linux/usb.h> #include <linux/usb/hcd.h> +#include <linux/scatterlist.h>
#include "usbip_common.h" #include "stub.h" @@ -201,7 +202,7 @@ static void tweak_special_requests(struc static int stub_recv_cmd_unlink(struct stub_device *sdev, struct usbip_header *pdu) { - int ret; + int ret, i; unsigned long flags; struct stub_priv *priv;
@@ -246,12 +247,14 @@ static int stub_recv_cmd_unlink(struct s * so a driver in a client host will know the failure * of the unlink request ? */ - ret = usb_unlink_urb(priv->urb); - if (ret != -EINPROGRESS) - dev_err(&priv->urb->dev->dev, - "failed to unlink a urb # %lu, ret %d\n", - priv->seqnum, ret); - + for (i = priv->completed_urbs; i < priv->num_urbs; i++) { + ret = usb_unlink_urb(priv->urbs[i]); + if (ret != -EINPROGRESS) + dev_err(&priv->urbs[i]->dev->dev, + "failed to unlink %d/%d urb of seqnum %lu, ret %d\n", + i + 1, priv->num_urbs, + priv->seqnum, ret); + } return 0; }
@@ -433,14 +436,36 @@ static void masking_bogus_flags(struct u urb->transfer_flags &= allowed; }
+static int stub_recv_xbuff(struct usbip_device *ud, struct stub_priv *priv) +{ + int ret; + int i; + + for (i = 0; i < priv->num_urbs; i++) { + ret = usbip_recv_xbuff(ud, priv->urbs[i]); + if (ret < 0) + break; + } + + return ret; +} + static void stub_recv_cmd_submit(struct stub_device *sdev, struct usbip_header *pdu) { - int ret; struct stub_priv *priv; struct usbip_device *ud = &sdev->ud; struct usb_device *udev = sdev->udev; + struct scatterlist *sgl = NULL, *sg; + void *buffer = NULL; + unsigned long long buf_len; + int nents; + int num_urbs = 1; int pipe = get_pipe(sdev, pdu); + int use_sg = pdu->u.cmd_submit.transfer_flags & URB_DMA_MAP_SG; + int support_sg = 1; + int np = 0; + int ret, i;
if (pipe == -1) return; @@ -449,76 +474,139 @@ static void stub_recv_cmd_submit(struct if (!priv) return;
- /* setup a urb */ - if (usb_pipeisoc(pipe)) - priv->urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets, - GFP_KERNEL); - else - priv->urb = usb_alloc_urb(0, GFP_KERNEL); + buf_len = (unsigned long long)pdu->u.cmd_submit.transfer_buffer_length;
- if (!priv->urb) { - usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); - return; + /* allocate urb transfer buffer, if needed */ + if (buf_len) { + if (use_sg) { + sgl = sgl_alloc(buf_len, GFP_KERNEL, &nents); + if (!sgl) + goto err_malloc; + } else { + buffer = kzalloc(buf_len, GFP_KERNEL); + if (!buffer) + goto err_malloc; + } }
- /* allocate urb transfer buffer, if needed */ - if (pdu->u.cmd_submit.transfer_buffer_length > 0) { - priv->urb->transfer_buffer = - kzalloc(pdu->u.cmd_submit.transfer_buffer_length, - GFP_KERNEL); - if (!priv->urb->transfer_buffer) { + /* Check if the server's HCD supports SG */ + if (use_sg && !udev->bus->sg_tablesize) { + /* + * If the server's HCD doesn't support SG, break a single SG + * request into several URBs and map each SG list entry to + * corresponding URB buffer. The previously allocated SG + * list is stored in priv->sgl (If the server's HCD support SG, + * SG list is stored only in urb->sg) and it is used as an + * indicator that the server split single SG request into + * several URBs. Later, priv->sgl is used by stub_complete() and + * stub_send_ret_submit() to reassemble the divied URBs. + */ + support_sg = 0; + num_urbs = nents; + priv->completed_urbs = 0; + pdu->u.cmd_submit.transfer_flags &= ~URB_DMA_MAP_SG; + } + + /* allocate urb array */ + priv->num_urbs = num_urbs; + priv->urbs = kmalloc_array(num_urbs, sizeof(*priv->urbs), GFP_KERNEL); + if (!priv->urbs) + goto err_urbs; + + /* setup a urb */ + if (support_sg) { + if (usb_pipeisoc(pipe)) + np = pdu->u.cmd_submit.number_of_packets; + + priv->urbs[0] = usb_alloc_urb(np, GFP_KERNEL); + if (!priv->urbs[0]) + goto err_urb; + + if (buf_len) { + if (use_sg) { + priv->urbs[0]->sg = sgl; + priv->urbs[0]->num_sgs = nents; + priv->urbs[0]->transfer_buffer = NULL; + } else { + priv->urbs[0]->transfer_buffer = buffer; + } + } + + /* copy urb setup packet */ + priv->urbs[0]->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, + 8, GFP_KERNEL); + if (!priv->urbs[0]->setup_packet) { usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); return; } - }
- /* copy urb setup packet */ - priv->urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8, - GFP_KERNEL); - if (!priv->urb->setup_packet) { - dev_err(&udev->dev, "allocate setup_packet\n"); - usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); - return; + usbip_pack_pdu(pdu, priv->urbs[0], USBIP_CMD_SUBMIT, 0); + } else { + for_each_sg(sgl, sg, nents, i) { + priv->urbs[i] = usb_alloc_urb(0, GFP_KERNEL); + /* The URBs which is previously allocated will be freed + * in stub_device_cleanup_urbs() if error occurs. + */ + if (!priv->urbs[i]) + goto err_urb; + + usbip_pack_pdu(pdu, priv->urbs[i], USBIP_CMD_SUBMIT, 0); + priv->urbs[i]->transfer_buffer = sg_virt(sg); + priv->urbs[i]->transfer_buffer_length = sg->length; + } + priv->sgl = sgl; }
- /* set other members from the base header of pdu */ - priv->urb->context = (void *) priv; - priv->urb->dev = udev; - priv->urb->pipe = pipe; - priv->urb->complete = stub_complete; + for (i = 0; i < num_urbs; i++) { + /* set other members from the base header of pdu */ + priv->urbs[i]->context = (void *) priv; + priv->urbs[i]->dev = udev; + priv->urbs[i]->pipe = pipe; + priv->urbs[i]->complete = stub_complete;
- usbip_pack_pdu(pdu, priv->urb, USBIP_CMD_SUBMIT, 0); + /* no need to submit an intercepted request, but harmless? */ + tweak_special_requests(priv->urbs[i]);
+ masking_bogus_flags(priv->urbs[i]); + }
- if (usbip_recv_xbuff(ud, priv->urb) < 0) + if (stub_recv_xbuff(ud, priv) < 0) return;
- if (usbip_recv_iso(ud, priv->urb) < 0) + if (usbip_recv_iso(ud, priv->urbs[0]) < 0) return;
- /* no need to submit an intercepted request, but harmless? */ - tweak_special_requests(priv->urb); - - masking_bogus_flags(priv->urb); /* urb is now ready to submit */ - ret = usb_submit_urb(priv->urb, GFP_KERNEL); - - if (ret == 0) - usbip_dbg_stub_rx("submit urb ok, seqnum %u\n", - pdu->base.seqnum); - else { - dev_err(&udev->dev, "submit_urb error, %d\n", ret); - usbip_dump_header(pdu); - usbip_dump_urb(priv->urb); + for (i = 0; i < priv->num_urbs; i++) { + ret = usb_submit_urb(priv->urbs[i], GFP_KERNEL);
- /* - * Pessimistic. - * This connection will be discarded. - */ - usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT); + if (ret == 0) + usbip_dbg_stub_rx("submit urb ok, seqnum %u\n", + pdu->base.seqnum); + else { + dev_err(&udev->dev, "submit_urb error, %d\n", ret); + usbip_dump_header(pdu); + usbip_dump_urb(priv->urbs[i]); + + /* + * Pessimistic. + * This connection will be discarded. + */ + usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT); + break; + } }
usbip_dbg_stub_rx("Leave\n"); + return; + +err_urb: + kfree(priv->urbs); +err_urbs: + kfree(buffer); + sgl_free(sgl); +err_malloc: + usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); }
/* recv a pdu */ --- a/drivers/usb/usbip/stub_tx.c +++ b/drivers/usb/usbip/stub_tx.c @@ -5,25 +5,11 @@
#include <linux/kthread.h> #include <linux/socket.h> +#include <linux/scatterlist.h>
#include "usbip_common.h" #include "stub.h"
-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); -} - /* be in spin_lock_irqsave(&sdev->priv_lock, flags) */ void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum, __u32 status) @@ -85,6 +71,22 @@ void stub_complete(struct urb *urb) break; }
+ /* + * If the server breaks single SG request into the several URBs, the + * URBs must be reassembled before sending completed URB to the vhci. + * Don't wake up the tx thread until all the URBs are completed. + */ + if (priv->sgl) { + priv->completed_urbs++; + + /* Only save the first error status */ + if (urb->status && !priv->urb_status) + priv->urb_status = urb->status; + + if (priv->completed_urbs < priv->num_urbs) + return; + } + /* link a urb to the queue of tx. */ spin_lock_irqsave(&sdev->priv_lock, flags); if (sdev->ud.tcp_socket == NULL) { @@ -156,18 +158,22 @@ static int stub_send_ret_submit(struct s size_t total_size = 0;
while ((priv = dequeue_from_priv_tx(sdev)) != NULL) { - int ret; - struct urb *urb = priv->urb; + struct urb *urb = priv->urbs[0]; struct usbip_header pdu_header; struct usbip_iso_packet_descriptor *iso_buffer = NULL; struct kvec *iov = NULL; + struct scatterlist *sg; + u32 actual_length = 0; int iovnum = 0; + int ret; + int i;
txsize = 0; memset(&pdu_header, 0, sizeof(pdu_header)); memset(&msg, 0, sizeof(msg));
- if (urb->actual_length > 0 && !urb->transfer_buffer) { + if (urb->actual_length > 0 && !urb->transfer_buffer && + !urb->num_sgs) { dev_err(&sdev->udev->dev, "urb: actual_length %d transfer_buffer null\n", urb->actual_length); @@ -176,6 +182,11 @@ static int stub_send_ret_submit(struct s
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) iovnum = 2 + urb->number_of_packets; + else if (usb_pipein(urb->pipe) && urb->actual_length > 0 && + urb->num_sgs) + iovnum = 1 + urb->num_sgs; + else if (usb_pipein(urb->pipe) && priv->sgl) + iovnum = 1 + priv->num_urbs; else iovnum = 2;
@@ -192,6 +203,15 @@ static int stub_send_ret_submit(struct s setup_ret_submit_pdu(&pdu_header, urb); usbip_dbg_stub_tx("setup txdata seqnum: %d\n", pdu_header.base.seqnum); + + if (priv->sgl) { + for (i = 0; i < priv->num_urbs; i++) + actual_length += priv->urbs[i]->actual_length; + + pdu_header.u.ret_submit.status = priv->urb_status; + pdu_header.u.ret_submit.actual_length = actual_length; + } + usbip_header_correct_endian(&pdu_header, 1);
iov[iovnum].iov_base = &pdu_header; @@ -200,12 +220,47 @@ static int stub_send_ret_submit(struct s txsize += sizeof(pdu_header);
/* 2. setup transfer buffer */ - if (usb_pipein(urb->pipe) && + if (usb_pipein(urb->pipe) && priv->sgl) { + /* If the server split a single SG request into several + * URBs because the server's HCD doesn't support SG, + * reassemble the split URB buffers into a single + * return command. + */ + for (i = 0; i < priv->num_urbs; i++) { + iov[iovnum].iov_base = + priv->urbs[i]->transfer_buffer; + iov[iovnum].iov_len = + priv->urbs[i]->actual_length; + iovnum++; + } + txsize += actual_length; + } else if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS && urb->actual_length > 0) { - iov[iovnum].iov_base = urb->transfer_buffer; - iov[iovnum].iov_len = urb->actual_length; - iovnum++; + if (urb->num_sgs) { + unsigned int copy = urb->actual_length; + int size; + + for_each_sg(urb->sg, sg, urb->num_sgs, i) { + if (copy == 0) + break; + + if (copy < sg->length) + size = copy; + else + size = sg->length; + + iov[iovnum].iov_base = sg_virt(sg); + iov[iovnum].iov_len = size; + + iovnum++; + copy -= size; + } + } else { + iov[iovnum].iov_base = urb->transfer_buffer; + iov[iovnum].iov_len = urb->actual_length; + iovnum++; + } txsize += urb->actual_length; } else if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { --- a/drivers/usb/usbip/usbip_common.c +++ b/drivers/usb/usbip/usbip_common.c @@ -680,8 +680,12 @@ EXPORT_SYMBOL_GPL(usbip_pad_iso); /* some members of urb must be substituted before. */ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) { - int ret; + struct scatterlist *sg; + int ret = 0; + int recv; int size; + int copy; + int i;
if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) { /* the direction of urb must be OUT. */ @@ -701,29 +705,48 @@ int usbip_recv_xbuff(struct usbip_device if (!(size > 0)) return 0;
- if (size > urb->transfer_buffer_length) { + if (size > urb->transfer_buffer_length) /* should not happen, probably malicious packet */ - if (ud->side == USBIP_STUB) { - usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); - return 0; - } else { - usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); - return -EPIPE; - } - } + goto error; + + if (urb->num_sgs) { + copy = size; + for_each_sg(urb->sg, sg, urb->num_sgs, i) { + int recv_size; + + if (copy < sg->length) + recv_size = copy; + else + recv_size = sg->length; + + recv = usbip_recv(ud->tcp_socket, sg_virt(sg), + recv_size);
- 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 || ud->side == USBIP_VUDC) { - usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); - } else { - usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); - return -EPIPE; + if (recv != recv_size) + goto error; + + copy -= recv; + ret += recv; } + + if (ret != size) + goto error; + } else { + ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size); + if (ret != size) + goto error; }
return ret; + +error: + dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret); + if (ud->side == USBIP_STUB || ud->side == USBIP_VUDC) + usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); + else + usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); + + return -EPIPE; } EXPORT_SYMBOL_GPL(usbip_recv_xbuff);
--- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -702,7 +702,8 @@ static int vhci_urb_enqueue(struct usb_h } vdev = &vhci_hcd->vdev[portnum-1];
- if (!urb->transfer_buffer && urb->transfer_buffer_length) { + if (!urb->transfer_buffer && !urb->num_sgs && + urb->transfer_buffer_length) { dev_dbg(dev, "Null URB transfer buffer\n"); return -EINVAL; } @@ -1148,6 +1149,15 @@ static int vhci_setup(struct usb_hcd *hc hcd->speed = HCD_USB3; hcd->self.root_hub->speed = USB_SPEED_SUPER; } + + /* + * Support SG. + * sg_tablesize is an arbitrary value to alleviate memory pressure + * on the host. + */ + hcd->self.sg_tablesize = 32; + hcd->self.no_sg_constraint = 1; + return 0; }
--- a/drivers/usb/usbip/vhci_rx.c +++ b/drivers/usb/usbip/vhci_rx.c @@ -90,6 +90,9 @@ static void vhci_recv_ret_submit(struct if (usbip_dbg_flag_vhci_rx) usbip_dump_urb(urb);
+ if (urb->num_sgs) + urb->transfer_flags &= ~URB_DMA_MAP_SG; + usbip_dbg_vhci_rx("now giveback urb %u\n", pdu->base.seqnum);
spin_lock_irqsave(&vhci->lock, flags); --- a/drivers/usb/usbip/vhci_tx.c +++ b/drivers/usb/usbip/vhci_tx.c @@ -5,6 +5,7 @@
#include <linux/kthread.h> #include <linux/slab.h> +#include <linux/scatterlist.h>
#include "usbip_common.h" #include "vhci.h" @@ -50,19 +51,23 @@ static struct vhci_priv *dequeue_from_pr
static int vhci_send_cmd_submit(struct vhci_device *vdev) { + struct usbip_iso_packet_descriptor *iso_buffer = NULL; struct vhci_priv *priv = NULL; + struct scatterlist *sg;
struct msghdr msg; - struct kvec iov[3]; + struct kvec *iov; size_t txsize;
size_t total_size = 0; + int iovnum; + int err = -ENOMEM; + int i;
while ((priv = dequeue_from_priv_tx(vdev)) != NULL) { int ret; struct urb *urb = priv->urb; struct usbip_header pdu_header; - struct usbip_iso_packet_descriptor *iso_buffer = NULL;
txsize = 0; memset(&pdu_header, 0, sizeof(pdu_header)); @@ -72,18 +77,45 @@ static int vhci_send_cmd_submit(struct v usbip_dbg_vhci_tx("setup txdata urb seqnum %lu\n", priv->seqnum);
+ if (urb->num_sgs && usb_pipeout(urb->pipe)) + iovnum = 2 + urb->num_sgs; + else + iovnum = 3; + + iov = kcalloc(iovnum, sizeof(*iov), GFP_KERNEL); + if (!iov) { + usbip_event_add(&vdev->ud, SDEV_EVENT_ERROR_MALLOC); + return -ENOMEM; + } + + if (urb->num_sgs) + urb->transfer_flags |= URB_DMA_MAP_SG; + /* 1. setup usbip_header */ setup_cmd_submit_pdu(&pdu_header, urb); usbip_header_correct_endian(&pdu_header, 1); + iovnum = 0;
- iov[0].iov_base = &pdu_header; - iov[0].iov_len = sizeof(pdu_header); + iov[iovnum].iov_base = &pdu_header; + iov[iovnum].iov_len = sizeof(pdu_header); txsize += sizeof(pdu_header); + iovnum++;
/* 2. setup transfer buffer */ if (!usb_pipein(urb->pipe) && urb->transfer_buffer_length > 0) { - iov[1].iov_base = urb->transfer_buffer; - iov[1].iov_len = urb->transfer_buffer_length; + if (urb->num_sgs && + !usb_endpoint_xfer_isoc(&urb->ep->desc)) { + for_each_sg(urb->sg, sg, urb->num_sgs, i) { + iov[iovnum].iov_base = sg_virt(sg); + iov[iovnum].iov_len = sg->length; + iovnum++; + } + } else { + iov[iovnum].iov_base = urb->transfer_buffer; + iov[iovnum].iov_len = + urb->transfer_buffer_length; + iovnum++; + } txsize += urb->transfer_buffer_length; }
@@ -95,23 +127,26 @@ static int vhci_send_cmd_submit(struct v if (!iso_buffer) { usbip_event_add(&vdev->ud, SDEV_EVENT_ERROR_MALLOC); - return -1; + goto err_iso_buffer; }
- iov[2].iov_base = iso_buffer; - iov[2].iov_len = len; + iov[iovnum].iov_base = iso_buffer; + iov[iovnum].iov_len = len; + iovnum++; txsize += len; }
- ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 3, txsize); + ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, iovnum, + txsize); if (ret != txsize) { pr_err("sendmsg failed!, ret=%d for %zd\n", ret, txsize); - kfree(iso_buffer); usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP); - return -1; + err = -EPIPE; + goto err_tx; }
+ kfree(iov); kfree(iso_buffer); usbip_dbg_vhci_tx("send txdata\n");
@@ -119,6 +154,13 @@ static int vhci_send_cmd_submit(struct v }
return total_size; + +err_tx: + kfree(iso_buffer); +err_iso_buffer: + kfree(iov); + + return err; }
static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)
From: Vidya Sagar vidyas@nvidia.com
commit 7be142caabc4780b13a522c485abc806de5c4114 upstream.
The PCI Tegra controller conversion to a device tree configurable driver in commit d1523b52bff3 ("PCI: tegra: Move PCIe driver to drivers/pci/host") implied that code for the driver can be compiled in for a kernel supporting multiple platforms.
Unfortunately, a blind move of the code did not check that some of the quirks that were applied in arch/arm (eg enabling Relaxed Ordering on all PCI devices - since the quirk hook erroneously matches PCI_ANY_ID for both Vendor-ID and Device-ID) are now applied in all kernels that compile the PCI Tegra controlled driver, DT and ACPI alike.
This is completely wrong, in that enablement of Relaxed Ordering is only required by default in Tegra20 platforms as described in the Tegra20 Technical Reference Manual (available at https://developer.nvidia.com/embedded/downloads#?search=tegra%202 in Section 34.1, where it is mentioned that Relaxed Ordering bit needs to be enabled in its root ports to avoid deadlock in hardware) and in the Tegra30 platforms for the same reasons (unfortunately not documented in the TRM).
There is no other strict requirement on PCI devices Relaxed Ordering enablement on any other Tegra platforms or PCI host bridge driver.
Fix this quite upsetting situation by limiting the vendor and device IDs to which the Relaxed Ordering quirk applies to the root ports in question, reported above.
Signed-off-by: Vidya Sagar vidyas@nvidia.com [lorenzo.pieralisi@arm.com: completely rewrote the commit log/fixes tag] Signed-off-by: Lorenzo Pieralisi lorenzo.pieralisi@arm.com Acked-by: Thierry Reding treding@nvidia.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/pci/controller/pci-tegra.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
--- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -545,12 +545,15 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NV DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_fixup_class); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_fixup_class);
-/* Tegra PCIE requires relaxed ordering */ +/* Tegra20 and Tegra30 PCIE requires relaxed ordering */ static void tegra_pcie_relax_enable(struct pci_dev *dev) { pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN); } -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_relax_enable); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_relax_enable); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1c, tegra_pcie_relax_enable); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, 0x0e1d, tegra_pcie_relax_enable);
static int tegra_pcie_request_resources(struct tegra_pcie *pcie) {
From: Nicolas Boichat drinkcat@chromium.org
[ Upstream commit 9e4dbc4646a84b2562ea7c64a542740687ff7daf ]
Add 2 additional hammer-like devices.
Signed-off-by: Nicolas Boichat drinkcat@chromium.org Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hid/hid-google-hammer.c | 4 ++++ drivers/hid/hid-ids.h | 2 ++ 2 files changed, 6 insertions(+)
diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c index 6bf4da7ad63a5..8cb63ea9977d6 100644 --- a/drivers/hid/hid-google-hammer.c +++ b/drivers/hid/hid-google-hammer.c @@ -120,6 +120,10 @@ static int hammer_input_configured(struct hid_device *hdev, static const struct hid_device_id hammer_devices[] = { { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) }, + { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, + USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MAGNEMITE) }, + { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, + USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MASTERBALL) }, { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_STAFF) }, { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 6b33117ca60e5..02c263a4c0836 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -466,6 +466,8 @@ #define USB_DEVICE_ID_GOOGLE_STAFF 0x502b #define USB_DEVICE_ID_GOOGLE_WAND 0x502d #define USB_DEVICE_ID_GOOGLE_WHISKERS 0x5030 +#define USB_DEVICE_ID_GOOGLE_MASTERBALL 0x503c +#define USB_DEVICE_ID_GOOGLE_MAGNEMITE 0x503d
#define USB_VENDOR_ID_GOTOP 0x08f2 #define USB_DEVICE_ID_SUPER_Q2 0x007f
From: Radhey Shyam Pandey radhey.shyam.pandey@xilinx.com
[ Upstream commit 6c6de1ddb1be3840f2ed5cc9d009a622720940c9 ]
In vdma_channel_set_config clear the delay, frame count and master mask before updating their new values. It avoids programming incorrect state when input parameters are different from default.
Signed-off-by: Radhey Shyam Pandey radhey.shyam.pandey@xilinx.com Acked-by: Appana Durga Kedareswara rao appana.durga.rao@xilinx.com Signed-off-by: Michal Simek michal.simek@xilinx.com Link: https://lore.kernel.org/r/1569495060-18117-3-git-send-email-radhey.shyam.pan... Signed-off-by: Vinod Koul vkoul@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/dma/xilinx/xilinx_dma.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index c124423125951..8aec137b4fcaa 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -72,6 +72,9 @@ #define XILINX_DMA_DMACR_CIRC_EN BIT(1) #define XILINX_DMA_DMACR_RUNSTOP BIT(0) #define XILINX_DMA_DMACR_FSYNCSRC_MASK GENMASK(6, 5) +#define XILINX_DMA_DMACR_DELAY_MASK GENMASK(31, 24) +#define XILINX_DMA_DMACR_FRAME_COUNT_MASK GENMASK(23, 16) +#define XILINX_DMA_DMACR_MASTER_MASK GENMASK(11, 8)
#define XILINX_DMA_REG_DMASR 0x0004 #define XILINX_DMA_DMASR_EOL_LATE_ERR BIT(15) @@ -2112,8 +2115,10 @@ int xilinx_vdma_channel_set_config(struct dma_chan *dchan, chan->config.gen_lock = cfg->gen_lock; chan->config.master = cfg->master;
+ dmacr &= ~XILINX_DMA_DMACR_GENLOCK_EN; if (cfg->gen_lock && chan->genlock) { dmacr |= XILINX_DMA_DMACR_GENLOCK_EN; + dmacr &= ~XILINX_DMA_DMACR_MASTER_MASK; dmacr |= cfg->master << XILINX_DMA_DMACR_MASTER_SHIFT; }
@@ -2129,11 +2134,13 @@ int xilinx_vdma_channel_set_config(struct dma_chan *dchan, chan->config.delay = cfg->delay;
if (cfg->coalesc <= XILINX_DMA_DMACR_FRAME_COUNT_MAX) { + dmacr &= ~XILINX_DMA_DMACR_FRAME_COUNT_MASK; dmacr |= cfg->coalesc << XILINX_DMA_DMACR_FRAME_COUNT_SHIFT; chan->config.coalesc = cfg->coalesc; }
if (cfg->delay <= XILINX_DMA_DMACR_DELAY_MAX) { + dmacr &= ~XILINX_DMA_DMACR_DELAY_MASK; dmacr |= cfg->delay << XILINX_DMA_DMACR_DELAY_SHIFT; chan->config.delay = cfg->delay; }
From: Baolin Wang baolin.wang@linaro.org
[ Upstream commit ec1ac309596a7bdf206743b092748205f6cd5720 ]
If we terminate the channel to free all descriptors associated with this channel, we will leak the memory of current descriptor if the current descriptor is not completed, since it had been deteled from the desc_issued list and have not been added into the desc_completed list.
Thus we should check if current descriptor is completed or not, when freeing the descriptors associated with one channel, if not, we should free it to avoid this issue.
Fixes: 9b3b8171f7f4 ("dmaengine: sprd: Add Spreadtrum DMA driver") Reported-by: Zhenfang Wang zhenfang.wang@unisoc.com Tested-by: Zhenfang Wang zhenfang.wang@unisoc.com Signed-off-by: Baolin Wang baolin.wang@linaro.org Link: https://lore.kernel.org/r/170dbbc6d5366b6fa974ce2d366652e23a334251.157060978... Signed-off-by: Vinod Koul vkoul@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/dma/sprd-dma.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 1ed1c7efa2885..9e8ce56a83d8a 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -181,6 +181,7 @@ struct sprd_dma_dev { struct sprd_dma_chn channels[0]; };
+static void sprd_dma_free_desc(struct virt_dma_desc *vd); static bool sprd_dma_filter_fn(struct dma_chan *chan, void *param); static struct of_dma_filter_info sprd_dma_info = { .filter_fn = sprd_dma_filter_fn, @@ -493,12 +494,19 @@ static int sprd_dma_alloc_chan_resources(struct dma_chan *chan) static void sprd_dma_free_chan_resources(struct dma_chan *chan) { struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); + struct virt_dma_desc *cur_vd = NULL; unsigned long flags;
spin_lock_irqsave(&schan->vc.lock, flags); + if (schan->cur_desc) + cur_vd = &schan->cur_desc->vd; + sprd_dma_stop(schan); spin_unlock_irqrestore(&schan->vc.lock, flags);
+ if (cur_vd) + sprd_dma_free_desc(cur_vd); + vchan_free_chan_resources(&schan->vc); pm_runtime_put(chan->device->dev); } @@ -814,15 +822,22 @@ static int sprd_dma_resume(struct dma_chan *chan) static int sprd_dma_terminate_all(struct dma_chan *chan) { struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); + struct virt_dma_desc *cur_vd = NULL; unsigned long flags; LIST_HEAD(head);
spin_lock_irqsave(&schan->vc.lock, flags); + if (schan->cur_desc) + cur_vd = &schan->cur_desc->vd; + sprd_dma_stop(schan);
vchan_get_all_descriptors(&schan->vc, &head); spin_unlock_irqrestore(&schan->vc.lock, flags);
+ if (cur_vd) + sprd_dma_free_desc(cur_vd); + vchan_dma_desc_free_list(&schan->vc, &head); return 0; }
From: Zhang Lixu lixu.zhang@intel.com
[ Upstream commit 16ff7bf6dbcc6f77d2eec1ac9120edf44213c2f1 ]
When allocating tx ring buffers failed, should free tx buffers, not rx buffers.
Signed-off-by: Zhang Lixu lixu.zhang@intel.com Acked-by: Srinivas Pandruvada srinivas.pandruvada@linux.intel.com Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/hid/intel-ish-hid/ishtp/client-buffers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/hid/intel-ish-hid/ishtp/client-buffers.c b/drivers/hid/intel-ish-hid/ishtp/client-buffers.c index b9b917d2d50db..c41dbb167c91b 100644 --- a/drivers/hid/intel-ish-hid/ishtp/client-buffers.c +++ b/drivers/hid/intel-ish-hid/ishtp/client-buffers.c @@ -90,7 +90,7 @@ int ishtp_cl_alloc_tx_ring(struct ishtp_cl *cl) return 0; out: dev_err(&cl->device->dev, "error in allocating Tx pool\n"); - ishtp_cl_free_rx_ring(cl); + ishtp_cl_free_tx_ring(cl); return -ENOMEM; }
From: Rafi Wiener rafiw@mellanox.com
[ Upstream commit c8973df2da677f375f8b12b6eefca2f44c8884d5 ]
Before QP is closed it changes to ERROR state, when this happens the QP was left with old rate limit that was already removed from the table.
Fixes: 7d29f349a4b9 ("IB/mlx5: Properly adjust rate limit on QP state transitions") Signed-off-by: Rafi Wiener rafiw@mellanox.com Signed-off-by: Oleg Kuporosov olegk@mellanox.com Signed-off-by: Leon Romanovsky leonro@mellanox.com Link: https://lore.kernel.org/r/20191002120243.16971-1-leon@kernel.org Signed-off-by: Doug Ledford dledford@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/infiniband/hw/mlx5/qp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 77b1f3fd086ad..900f85ce0fb08 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2828,10 +2828,12 @@ static int modify_raw_packet_qp_sq(struct mlx5_core_dev *dev, }
/* Only remove the old rate after new rate was set */ - if ((old_rl.rate && - !mlx5_rl_are_equal(&old_rl, &new_rl)) || - (new_state != MLX5_SQC_STATE_RDY)) + if ((old_rl.rate && !mlx5_rl_are_equal(&old_rl, &new_rl)) || + (new_state != MLX5_SQC_STATE_RDY)) { mlx5_rl_remove_rate(dev, &old_rl); + if (new_state != MLX5_SQC_STATE_RDY) + memset(&new_rl, 0, sizeof(new_rl)); + }
ibqp->rl = new_rl; sq->state = new_state;
From: Potnuri Bharat Teja bharat@chelsio.com
[ Upstream commit 612e0486ad0845c41ac10492e78144f99e326375 ]
pass_accept_req() is using the same skb for handling accept request and sending accept reply to HW. Here req and rpl structures are pointing to same skb->data which is over written by INIT_TP_WR() and leads to accessing corrupt req fields in accept_cr() while checking for ECN flags. Reordered code in accept_cr() to fetch correct req fields.
Fixes: 92e7ae7172 ("iw_cxgb4: Choose appropriate hw mtu index and ISS for iWARP connections") Signed-off-by: Potnuri Bharat Teja bharat@chelsio.com Link: https://lore.kernel.org/r/20191003104353.11590-1-bharat@chelsio.com Signed-off-by: Doug Ledford dledford@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/infiniband/hw/cxgb4/cm.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 3be6405d9855e..566bfcc6add0d 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -2380,20 +2380,6 @@ static int accept_cr(struct c4iw_ep *ep, struct sk_buff *skb, enum chip_type adapter_type = ep->com.dev->rdev.lldi.adapter_type;
pr_debug("ep %p tid %u\n", ep, ep->hwtid); - - skb_get(skb); - rpl = cplhdr(skb); - if (!is_t4(adapter_type)) { - skb_trim(skb, roundup(sizeof(*rpl5), 16)); - rpl5 = (void *)rpl; - INIT_TP_WR(rpl5, ep->hwtid); - } else { - skb_trim(skb, sizeof(*rpl)); - INIT_TP_WR(rpl, ep->hwtid); - } - OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL, - ep->hwtid)); - cxgb_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx, enable_tcp_timestamps && req->tcpopt.tstamp, (ep->com.remote_addr.ss_family == AF_INET) ? 0 : 1); @@ -2439,6 +2425,20 @@ static int accept_cr(struct c4iw_ep *ep, struct sk_buff *skb, if (tcph->ece && tcph->cwr) opt2 |= CCTRL_ECN_V(1); } + + skb_get(skb); + rpl = cplhdr(skb); + if (!is_t4(adapter_type)) { + skb_trim(skb, roundup(sizeof(*rpl5), 16)); + rpl5 = (void *)rpl; + INIT_TP_WR(rpl5, ep->hwtid); + } else { + skb_trim(skb, sizeof(*rpl)); + INIT_TP_WR(rpl, ep->hwtid); + } + OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL, + ep->hwtid)); + if (CHELSIO_CHIP_VERSION(adapter_type) > CHELSIO_T4) { u32 isn = (prandom_u32() & ~7UL) - 1; opt2 |= T5_OPT_2_VALID_F;
From: Kamal Heib kamalheib1@gmail.com
[ Upstream commit b806c94ee44e53233b8ce6c92d9078d9781786a5 ]
Remove spaces from the reported firmware version string. Actual value: $ cat /sys/class/infiniband/qedr0/fw_ver 8. 37. 7. 0
Expected value: $ cat /sys/class/infiniband/qedr0/fw_ver 8.37.7.0
Fixes: ec72fce401c6 ("qedr: Add support for RoCE HW init") Signed-off-by: Kamal Heib kamalheib1@gmail.com Acked-by: Michal Kalderon michal.kalderon@marvell.com Link: https://lore.kernel.org/r/20191007210730.7173-1-kamalheib1@gmail.com Signed-off-by: Doug Ledford dledford@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/infiniband/hw/qedr/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index a0af6d424aeda..d1680d3b58250 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -77,7 +77,7 @@ static void qedr_get_dev_fw_str(struct ib_device *ibdev, char *str) struct qedr_dev *qedr = get_qedr_dev(ibdev); u32 fw_ver = (u32)qedr->attr.fw_ver;
- snprintf(str, IB_FW_VERSION_NAME_MAX, "%d. %d. %d. %d", + snprintf(str, IB_FW_VERSION_NAME_MAX, "%d.%d.%d.%d", (fw_ver >> 24) & 0xFF, (fw_ver >> 16) & 0xFF, (fw_ver >> 8) & 0xFF, fw_ver & 0xFF); }
From: Tariq Toukan tariqt@mellanox.com
[ Upstream commit 61ea02d2c13106116c6e4916ac5d9dd41151c959 ]
The completion queue consumer index increments upon a call to mlx5_cqwq_pop(). When dumping an error CQE, the index is already incremented. Decrease one for the print command.
Fixes: 16cc14d81733 ("net/mlx5e: Dump xmit error completions") Signed-off-by: Tariq Toukan tariqt@mellanox.com Signed-off-by: Saeed Mahameed saeedm@mellanox.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 0b03d65474e93..73dce92c41c44 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -462,7 +462,10 @@ netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev) static void mlx5e_dump_error_cqe(struct mlx5e_txqsq *sq, struct mlx5_err_cqe *err_cqe) { - u32 ci = mlx5_cqwq_get_ci(&sq->cq.wq); + struct mlx5_cqwq *wq = &sq->cq.wq; + u32 ci; + + ci = mlx5_cqwq_ctr2ix(wq, wq->cc - 1);
netdev_err(sq->channel->netdev, "Error cqe on cqn 0x%x, ci 0x%x, sqn 0x%x, syndrome 0x%x, vendor syndrome 0x%x\n",
From: Navid Emamdoost navid.emamdoost@gmail.com
[ Upstream commit c8c2a057fdc7de1cd16f4baa51425b932a42eb39 ]
In mlx5_fpga_conn_create_cq if mlx5_vector2eqn fails the allocated memory should be released.
Fixes: 537a50574175 ("net/mlx5: FPGA, Add high-speed connection routines") Signed-off-by: Navid Emamdoost navid.emamdoost@gmail.com Signed-off-by: Saeed Mahameed saeedm@mellanox.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c index 8ca1d1949d930..d8d0b6bd5c5ae 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/conn.c @@ -462,8 +462,10 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size) }
err = mlx5_vector2eqn(mdev, smp_processor_id(), &eqn, &irqn); - if (err) + if (err) { + kvfree(in); goto err_cqwq; + }
cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); MLX5_SET(cqc, cqc, log_cq_size, ilog2(cq_size));
From: Hannes Reinecke hare@suse.com
[ Upstream commit 66cf50e65b183c863825f5c28a818e3f47a72e40 ]
DRIVER_ERROR is a a driver byte setting, not a host byte. The qla2xxx driver should rather return DID_ERROR here to be in line with the other drivers.
Link: https://lore.kernel.org/r/20191018140458.108278-1-hare@suse.de Signed-off-by: Hannes Reinecke hare@suse.com Acked-by: Himanshu Madhani hmadhani@marvell.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/scsi/qla2xxx/qla_bsg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 4a9fd8d944d60..85b03a7f473c1 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -258,7 +258,7 @@ qla2x00_process_els(struct bsg_job *bsg_job) srb_t *sp; const char *type; int req_sg_cnt, rsp_sg_cnt; - int rval = (DRIVER_ERROR << 16); + int rval = (DID_ERROR << 16); uint16_t nextlid = 0;
if (bsg_request->msgcode == FC_BSG_RPT_ELS) { @@ -433,7 +433,7 @@ qla2x00_process_ct(struct bsg_job *bsg_job) struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; - int rval = (DRIVER_ERROR << 16); + int rval = (DID_ERROR << 16); int req_sg_cnt, rsp_sg_cnt; uint16_t loop_id; struct fc_port *fcport; @@ -1948,7 +1948,7 @@ qlafx00_mgmt_cmd(struct bsg_job *bsg_job) struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; - int rval = (DRIVER_ERROR << 16); + int rval = (DID_ERROR << 16); struct qla_mt_iocb_rqst_fx00 *piocb_rqst; srb_t *sp; int req_sg_cnt = 0, rsp_sg_cnt = 0;
From: Dan Carpenter dan.carpenter@oracle.com
[ Upstream commit a9018adfde809d44e71189b984fa61cc89682b5e ]
The issue is in drivers/infiniband/core/uverbs_std_types_cq.c in the UVERBS_HANDLER(UVERBS_METHOD_CQ_CREATE) function. We check that:
if (attr.comp_vector >= attrs->ufile->device->num_comp_vectors) {
But we don't check if "attr.comp_vector" is negative. It could potentially lead to an array underflow. My concern would be where cq->vector is used in the create_cq() function from the cxgb4 driver.
And really "attr.comp_vector" is appears as a u32 to user space so that's the right type to use.
Fixes: 9ee79fce3642 ("IB/core: Add completion queue (cq) object actions") Link: https://lore.kernel.org/r/20191011133419.GA22905@mwanda Signed-off-by: Dan Carpenter dan.carpenter@oracle.com Reviewed-by: Jason Gunthorpe jgg@mellanox.com Signed-off-by: Jason Gunthorpe jgg@mellanox.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/infiniband/core/uverbs.h | 2 +- include/rdma/ib_verbs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 5df8e548cc146..4a14de2d8c716 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -98,7 +98,7 @@ ib_uverbs_init_udata_buf_or_null(struct ib_udata *udata,
struct ib_uverbs_device { atomic_t refcount; - int num_comp_vectors; + u32 num_comp_vectors; struct completion comp; struct device *dev; struct ib_device __rcu *ib_dev; diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index b7d63c3970d18..f3d475024d376 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -310,7 +310,7 @@ struct ib_tm_caps {
struct ib_cq_init_attr { unsigned int cqe; - int comp_vector; + u32 comp_vector; u32 flags; };
From: Hillf Danton hdanton@sina.com
[ Upstream commit 9464cc37f3671ee69cb1c00662b5e1f113a96b23 ]
syzbot found the following crash on:
HEAD commit: 1e78030e Merge tag 'mmc-v5.3-rc1' of git://git.kernel.org/.. git tree: upstream console output: https://syzkaller.appspot.com/x/log.txt?x=148d3d1a600000 kernel config: https://syzkaller.appspot.com/x/.config?x=30cef20daf3e9977 dashboard link: https://syzkaller.appspot.com/bug?extid=13210896153522fe1ee5 compiler: gcc (GCC) 9.0.0 20181231 (experimental) syz repro: https://syzkaller.appspot.com/x/repro.syz?x=136aa8c4600000 C reproducer: https://syzkaller.appspot.com/x/repro.c?x=109ba792600000
===================================================================== BUG: memory leak unreferenced object 0xffff8881207e4100 (size 128): comm "syz-executor032", pid 7014, jiffies 4294944027 (age 13.830s) hex dump (first 32 bytes): 00 70 16 18 81 88 ff ff 80 af 8c 22 81 88 ff ff .p.........".... 00 b6 23 17 81 88 ff ff 00 00 00 00 00 00 00 00 ..#............. backtrace: [<000000000eb78212>] kmemleak_alloc_recursive include/linux/kmemleak.h:43 [inline] [<000000000eb78212>] slab_post_alloc_hook mm/slab.h:522 [inline] [<000000000eb78212>] slab_alloc mm/slab.c:3319 [inline] [<000000000eb78212>] kmem_cache_alloc_trace+0x145/0x2c0 mm/slab.c:3548 [<00000000006ea6c6>] kmalloc include/linux/slab.h:552 [inline] [<00000000006ea6c6>] kzalloc include/linux/slab.h:748 [inline] [<00000000006ea6c6>] ovs_vport_alloc+0x37/0xf0 net/openvswitch/vport.c:130 [<00000000f9a04a7d>] internal_dev_create+0x24/0x1d0 net/openvswitch/vport-internal_dev.c:164 [<0000000056ee7c13>] ovs_vport_add+0x81/0x190 net/openvswitch/vport.c:199 [<000000005434efc7>] new_vport+0x19/0x80 net/openvswitch/datapath.c:194 [<00000000b7b253f1>] ovs_dp_cmd_new+0x22f/0x410 net/openvswitch/datapath.c:1614 [<00000000e0988518>] genl_family_rcv_msg+0x2ab/0x5b0 net/netlink/genetlink.c:629 [<00000000d0cc9347>] genl_rcv_msg+0x54/0x9c net/netlink/genetlink.c:654 [<000000006694b647>] netlink_rcv_skb+0x61/0x170 net/netlink/af_netlink.c:2477 [<0000000088381f37>] genl_rcv+0x29/0x40 net/netlink/genetlink.c:665 [<00000000dad42a47>] netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] [<00000000dad42a47>] netlink_unicast+0x1ec/0x2d0 net/netlink/af_netlink.c:1328 [<0000000067e6b079>] netlink_sendmsg+0x270/0x480 net/netlink/af_netlink.c:1917 [<00000000aab08a47>] sock_sendmsg_nosec net/socket.c:637 [inline] [<00000000aab08a47>] sock_sendmsg+0x54/0x70 net/socket.c:657 [<000000004cb7c11d>] ___sys_sendmsg+0x393/0x3c0 net/socket.c:2311 [<00000000c4901c63>] __sys_sendmsg+0x80/0xf0 net/socket.c:2356 [<00000000c10abb2d>] __do_sys_sendmsg net/socket.c:2365 [inline] [<00000000c10abb2d>] __se_sys_sendmsg net/socket.c:2363 [inline] [<00000000c10abb2d>] __x64_sys_sendmsg+0x23/0x30 net/socket.c:2363
BUG: memory leak unreferenced object 0xffff88811723b600 (size 64): comm "syz-executor032", pid 7014, jiffies 4294944027 (age 13.830s) hex dump (first 32 bytes): 01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 02 00 00 00 05 35 82 c1 .............5.. backtrace: [<00000000352f46d8>] kmemleak_alloc_recursive include/linux/kmemleak.h:43 [inline] [<00000000352f46d8>] slab_post_alloc_hook mm/slab.h:522 [inline] [<00000000352f46d8>] slab_alloc mm/slab.c:3319 [inline] [<00000000352f46d8>] __do_kmalloc mm/slab.c:3653 [inline] [<00000000352f46d8>] __kmalloc+0x169/0x300 mm/slab.c:3664 [<000000008e48f3d1>] kmalloc include/linux/slab.h:557 [inline] [<000000008e48f3d1>] ovs_vport_set_upcall_portids+0x54/0xd0 net/openvswitch/vport.c:343 [<00000000541e4f4a>] ovs_vport_alloc+0x7f/0xf0 net/openvswitch/vport.c:139 [<00000000f9a04a7d>] internal_dev_create+0x24/0x1d0 net/openvswitch/vport-internal_dev.c:164 [<0000000056ee7c13>] ovs_vport_add+0x81/0x190 net/openvswitch/vport.c:199 [<000000005434efc7>] new_vport+0x19/0x80 net/openvswitch/datapath.c:194 [<00000000b7b253f1>] ovs_dp_cmd_new+0x22f/0x410 net/openvswitch/datapath.c:1614 [<00000000e0988518>] genl_family_rcv_msg+0x2ab/0x5b0 net/netlink/genetlink.c:629 [<00000000d0cc9347>] genl_rcv_msg+0x54/0x9c net/netlink/genetlink.c:654 [<000000006694b647>] netlink_rcv_skb+0x61/0x170 net/netlink/af_netlink.c:2477 [<0000000088381f37>] genl_rcv+0x29/0x40 net/netlink/genetlink.c:665 [<00000000dad42a47>] netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] [<00000000dad42a47>] netlink_unicast+0x1ec/0x2d0 net/netlink/af_netlink.c:1328 [<0000000067e6b079>] netlink_sendmsg+0x270/0x480 net/netlink/af_netlink.c:1917 [<00000000aab08a47>] sock_sendmsg_nosec net/socket.c:637 [inline] [<00000000aab08a47>] sock_sendmsg+0x54/0x70 net/socket.c:657 [<000000004cb7c11d>] ___sys_sendmsg+0x393/0x3c0 net/socket.c:2311 [<00000000c4901c63>] __sys_sendmsg+0x80/0xf0 net/socket.c:2356
BUG: memory leak unreferenced object 0xffff8881228ca500 (size 128): comm "syz-executor032", pid 7015, jiffies 4294944622 (age 7.880s) hex dump (first 32 bytes): 00 f0 27 18 81 88 ff ff 80 ac 8c 22 81 88 ff ff ..'........".... 40 b7 23 17 81 88 ff ff 00 00 00 00 00 00 00 00 @.#............. backtrace: [<000000000eb78212>] kmemleak_alloc_recursive include/linux/kmemleak.h:43 [inline] [<000000000eb78212>] slab_post_alloc_hook mm/slab.h:522 [inline] [<000000000eb78212>] slab_alloc mm/slab.c:3319 [inline] [<000000000eb78212>] kmem_cache_alloc_trace+0x145/0x2c0 mm/slab.c:3548 [<00000000006ea6c6>] kmalloc include/linux/slab.h:552 [inline] [<00000000006ea6c6>] kzalloc include/linux/slab.h:748 [inline] [<00000000006ea6c6>] ovs_vport_alloc+0x37/0xf0 net/openvswitch/vport.c:130 [<00000000f9a04a7d>] internal_dev_create+0x24/0x1d0 net/openvswitch/vport-internal_dev.c:164 [<0000000056ee7c13>] ovs_vport_add+0x81/0x190 net/openvswitch/vport.c:199 [<000000005434efc7>] new_vport+0x19/0x80 net/openvswitch/datapath.c:194 [<00000000b7b253f1>] ovs_dp_cmd_new+0x22f/0x410 net/openvswitch/datapath.c:1614 [<00000000e0988518>] genl_family_rcv_msg+0x2ab/0x5b0 net/netlink/genetlink.c:629 [<00000000d0cc9347>] genl_rcv_msg+0x54/0x9c net/netlink/genetlink.c:654 [<000000006694b647>] netlink_rcv_skb+0x61/0x170 net/netlink/af_netlink.c:2477 [<0000000088381f37>] genl_rcv+0x29/0x40 net/netlink/genetlink.c:665 [<00000000dad42a47>] netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] [<00000000dad42a47>] netlink_unicast+0x1ec/0x2d0 net/netlink/af_netlink.c:1328 [<0000000067e6b079>] netlink_sendmsg+0x270/0x480 net/netlink/af_netlink.c:1917 [<00000000aab08a47>] sock_sendmsg_nosec net/socket.c:637 [inline] [<00000000aab08a47>] sock_sendmsg+0x54/0x70 net/socket.c:657 [<000000004cb7c11d>] ___sys_sendmsg+0x393/0x3c0 net/socket.c:2311 [<00000000c4901c63>] __sys_sendmsg+0x80/0xf0 net/socket.c:2356 [<00000000c10abb2d>] __do_sys_sendmsg net/socket.c:2365 [inline] [<00000000c10abb2d>] __se_sys_sendmsg net/socket.c:2363 [inline] [<00000000c10abb2d>] __x64_sys_sendmsg+0x23/0x30 net/socket.c:2363 =====================================================================
The function in net core, register_netdevice(), may fail with vport's destruction callback either invoked or not. After commit 309b66970ee2 ("net: openvswitch: do not free vport if register_netdevice() is failed."), the duty to destroy vport is offloaded from the driver OTOH, which ends up in the memory leak reported.
It is fixed by releasing vport unless device is registered successfully. To do that, the callback assignment is defered until device is registered.
Reported-by: syzbot+13210896153522fe1ee5@syzkaller.appspotmail.com Fixes: 309b66970ee2 ("net: openvswitch: do not free vport if register_netdevice() is failed.") Cc: Taehee Yoo ap420073@gmail.com Cc: Greg Rose gvrose8192@gmail.com Cc: Eric Dumazet eric.dumazet@gmail.com Cc: Marcelo Ricardo Leitner marcelo.leitner@gmail.com Cc: Ying Xue ying.xue@windriver.com Cc: Andrey Konovalov andreyknvl@google.com Signed-off-by: Hillf Danton hdanton@sina.com Acked-by: Pravin B Shelar pshelar@ovn.org [sbrivio: this was sent to dev@openvswitch.org and never made its way to netdev -- resending original patch] Signed-off-by: Stefano Brivio sbrivio@redhat.com Reviewed-by: Greg Rose gvrose8192@gmail.com Signed-off-by: Jakub Kicinski jakub.kicinski@netronome.com Signed-off-by: Sasha Levin sashal@kernel.org --- net/openvswitch/vport-internal_dev.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 5a304cfc84233..d2356a284646c 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -149,7 +149,7 @@ static void do_setup(struct net_device *netdev) netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_OPENVSWITCH | IFF_NO_QUEUE; netdev->needs_free_netdev = true; - netdev->priv_destructor = internal_dev_destructor; + netdev->priv_destructor = NULL; netdev->ethtool_ops = &internal_dev_ethtool_ops; netdev->rtnl_link_ops = &internal_dev_link_ops;
@@ -171,7 +171,6 @@ static struct vport *internal_dev_create(const struct vport_parms *parms) struct internal_dev *internal_dev; struct net_device *dev; int err; - bool free_vport = true;
vport = ovs_vport_alloc(0, &ovs_internal_vport_ops, parms); if (IS_ERR(vport)) { @@ -202,10 +201,9 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
rtnl_lock(); err = register_netdevice(vport->dev); - if (err) { - free_vport = false; + if (err) goto error_unlock; - } + vport->dev->priv_destructor = internal_dev_destructor;
dev_set_promiscuity(vport->dev, 1); rtnl_unlock(); @@ -219,8 +217,7 @@ error_unlock: error_free_netdev: free_netdev(dev); error_free_vport: - if (free_vport) - ovs_vport_free(vport); + ovs_vport_free(vport); error: return ERR_PTR(err); }
From: Daniel Wagner dwagner@suse.de
[ Upstream commit 0fd103ccfe6a06e40e2d9d8c91d96332cc9e1239 ]
The initial lpfc_desc_set_adisc implementation in commit dea3101e0a5c ("lpfc: add Emulex FC driver version 8.0.28") enabled ADISC if
cfg_use_adisc && RSCN_MODE && FCP_2_DEVICE
In commit 92d7f7b0cde3 ("[SCSI] lpfc: NPIV: add NPIV support on top of SLI-3") this changed to
(cfg_use_adisc && RSC_MODE) || FCP_2_DEVICE
and later in commit ffc954936b13 ("[SCSI] lpfc 8.3.13: FC Discovery Fixes and enhancements.") to
(cfg_use_adisc && RSC_MODE) || (FCP_2_DEVICE && FCP_TARGET)
A customer reports that after a devloss, an ADISC failure is logged. It turns out the ADISC flag is set even the user explicitly set lpfc_use_adisc = 0.
[Sat Dec 22 22:55:58 2018] lpfc 0000:82:00.0: 2:(0):0203 Devloss timeout on WWPN 50:01:43:80:12:8e:40:20 NPort x05df00 Data: x82000000 x8 xa [Sat Dec 22 23:08:20 2018] lpfc 0000:82:00.0: 2:(0):2755 ADISC failure DID:05DF00 Status:x9/x70000
[mkp: fixed Hannes' email]
Fixes: 92d7f7b0cde3 ("[SCSI] lpfc: NPIV: add NPIV support on top of SLI-3") Cc: Dick Kennedy dick.kennedy@broadcom.com Cc: James Smart james.smart@broadcom.com Link: https://lore.kernel.org/r/20191022072112.132268-1-dwagner@suse.de Reviewed-by: Hannes Reinecke hare@suse.de Reviewed-by: James Smart james.smart@broadcom.com Signed-off-by: Daniel Wagner dwagner@suse.de Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/scsi/lpfc/lpfc_nportdisc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index a6619fd8238c1..ae6301c796785 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -844,9 +844,9 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
if (!(vport->fc_flag & FC_PT2PT)) { /* Check config parameter use-adisc or FCP-2 */ - if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) || + if (vport->cfg_use_adisc && ((vport->fc_flag & FC_RSCN_MODE) || ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && - (ndlp->nlp_type & NLP_FCP_TARGET))) { + (ndlp->nlp_type & NLP_FCP_TARGET)))) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_ADISC; spin_unlock_irq(shost->host_lock);
From: Himanshu Madhani hmadhani@marvell.com
[ Upstream commit c2ff2a36eff60efb5e123c940115216d6bf65684 ]
This patch fixes issue with Gen7 adapter in a blade environment where one of the ports will not be detected by driver. Firmware expects mailbox 11 to be set or cleared by driver for newer ISP.
Following message is seen in the log file:
[ 18.810892] qla2xxx [0000:d8:00.0]-1820:1: **** Failed=102 mb[0]=4005 mb[1]=37 mb[2]=20 mb[3]=8 [ 18.819596] cmd=2 ****
[mkp: typos]
Link: https://lore.kernel.org/r/20191022193643.7076-2-hmadhani@marvell.com Signed-off-by: Himanshu Madhani hmadhani@marvell.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/scsi/qla2xxx/qla_mbx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 84f57f075455e..128fcff24f1be 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -684,6 +684,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) mcp->mb[2] = LSW(risc_addr); mcp->mb[3] = 0; mcp->mb[4] = 0; + mcp->mb[11] = 0; ha->flags.using_lr_setting = 0; if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha)) { @@ -727,7 +728,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) if (ha->flags.exchoffld_enabled) mcp->mb[4] |= ENABLE_EXCHANGE_OFFLD;
- mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1; + mcp->out_mb |= MBX_4 | MBX_3 | MBX_2 | MBX_1 | MBX_11; mcp->in_mb |= MBX_3 | MBX_2 | MBX_1; } else { mcp->mb[1] = LSW(risc_addr);
From: Pablo Neira Ayuso pablo@netfilter.org
[ Upstream commit daf61b026f4686250e6afa619e6d7b49edc61df7 ]
Other garbage collector might remove an entry not fully set up yet.
[570953.958293] RIP: 0010:memcmp+0x9/0x50 [...] [570953.958567] flow_offload_hash_cmp+0x1e/0x30 [nf_flow_table] [570953.958585] flow_offload_lookup+0x8c/0x110 [nf_flow_table] [570953.958606] nf_flow_offload_ip_hook+0x135/0xb30 [nf_flow_table] [570953.958624] nf_flow_offload_inet_hook+0x35/0x37 [nf_flow_table_inet] [570953.958646] nf_hook_slow+0x3c/0xb0 [570953.958664] __netif_receive_skb_core+0x90f/0xb10 [570953.958678] ? ip_rcv_finish+0x82/0xa0 [570953.958692] __netif_receive_skb_one_core+0x3b/0x80 [570953.958711] __netif_receive_skb+0x18/0x60 [570953.958727] netif_receive_skb_internal+0x45/0xf0 [570953.958741] napi_gro_receive+0xcd/0xf0 [570953.958764] ixgbe_clean_rx_irq+0x432/0xe00 [ixgbe] [570953.958782] ixgbe_poll+0x27b/0x700 [ixgbe] [570953.958796] net_rx_action+0x284/0x3c0 [570953.958817] __do_softirq+0xcc/0x27c [570953.959464] irq_exit+0xe8/0x100 [570953.960097] do_IRQ+0x59/0xe0 [570953.960734] common_interrupt+0xf/0xf
Fixes: 43c8f131184f ("netfilter: nf_flow_table: fix missing error check for rhashtable_insert_fast") Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org Signed-off-by: Sasha Levin sashal@kernel.org --- net/netfilter/nf_flow_table_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index 8ade405129444..70bd730ca0597 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -187,6 +187,8 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow) { int err;
+ flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT; + err = rhashtable_insert_fast(&flow_table->rhashtable, &flow->tuplehash[0].node, nf_flow_offload_rhash_params); @@ -203,7 +205,6 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow) return err; }
- flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT; return 0; } EXPORT_SYMBOL_GPL(flow_offload_add);
From: Davide Caratti dcaratti@redhat.com
[ Upstream commit 62931f59ce9cbabb934a431f48f2f1f441c605ac ]
if the IPVS module is removed while the sync daemon is starting, there is a small gap where try_module_get() might fail getting the refcount inside ip_vs_use_count_inc(). Then, the refcounts of IPVS module are unbalanced, and the subsequent call to stop_sync_thread() causes the following splat:
WARNING: CPU: 0 PID: 4013 at kernel/module.c:1146 module_put.part.44+0x15b/0x290 Modules linked in: ip_vs(-) nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 veth ip6table_filter ip6_tables iptable_filter binfmt_misc intel_rapl_msr intel_rapl_common crct10dif_pclmul crc32_pclmul ext4 mbcache jbd2 ghash_clmulni_intel snd_hda_codec_generic ledtrig_audio snd_hda_intel snd_intel_nhlt snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm aesni_intel crypto_simd cryptd glue_helper joydev pcspkr snd_timer virtio_balloon snd soundcore i2c_piix4 nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs libcrc32c ata_generic pata_acpi virtio_net net_failover virtio_blk failover virtio_console qxl drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ata_piix ttm crc32c_intel serio_raw drm virtio_pci libata virtio_ring virtio floppy dm_mirror dm_region_hash dm_log dm_mod [last unloaded: nf_defrag_ipv6] CPU: 0 PID: 4013 Comm: modprobe Tainted: G W 5.4.0-rc1.upstream+ #741 Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 RIP: 0010:module_put.part.44+0x15b/0x290 Code: 04 25 28 00 00 00 0f 85 18 01 00 00 48 83 c4 68 5b 5d 41 5c 41 5d 41 5e 41 5f c3 89 44 24 28 83 e8 01 89 c5 0f 89 57 ff ff ff <0f> 0b e9 78 ff ff ff 65 8b 1d 67 83 26 4a 89 db be 08 00 00 00 48 RSP: 0018:ffff888050607c78 EFLAGS: 00010297 RAX: 0000000000000003 RBX: ffffffffc1420590 RCX: ffffffffb5db0ef9 RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffc1420590 RBP: 00000000ffffffff R08: fffffbfff82840b3 R09: fffffbfff82840b3 R10: 0000000000000001 R11: fffffbfff82840b2 R12: 1ffff1100a0c0f90 R13: ffffffffc1420200 R14: ffff88804f533300 R15: ffff88804f533ca0 FS: 00007f8ea9720740(0000) GS:ffff888053800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f3245abe000 CR3: 000000004c28a006 CR4: 00000000001606f0 Call Trace: stop_sync_thread+0x3a3/0x7c0 [ip_vs] ip_vs_sync_net_cleanup+0x13/0x50 [ip_vs] ops_exit_list.isra.5+0x94/0x140 unregister_pernet_operations+0x29d/0x460 unregister_pernet_device+0x26/0x60 ip_vs_cleanup+0x11/0x38 [ip_vs] __x64_sys_delete_module+0x2d5/0x400 do_syscall_64+0xa5/0x4e0 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x7f8ea8bf0db7 Code: 73 01 c3 48 8b 0d b9 80 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 b8 b0 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 89 80 2c 00 f7 d8 64 89 01 48 RSP: 002b:00007ffcd38d2fe8 EFLAGS: 00000206 ORIG_RAX: 00000000000000b0 RAX: ffffffffffffffda RBX: 0000000002436240 RCX: 00007f8ea8bf0db7 RDX: 0000000000000000 RSI: 0000000000000800 RDI: 00000000024362a8 RBP: 0000000000000000 R08: 00007f8ea8eba060 R09: 00007f8ea8c658a0 R10: 00007ffcd38d2a60 R11: 0000000000000206 R12: 0000000000000000 R13: 0000000000000001 R14: 00000000024362a8 R15: 0000000000000000 irq event stamp: 4538 hardirqs last enabled at (4537): [<ffffffffb6193dde>] quarantine_put+0x9e/0x170 hardirqs last disabled at (4538): [<ffffffffb5a0556a>] trace_hardirqs_off_thunk+0x1a/0x20 softirqs last enabled at (4522): [<ffffffffb6f8ebe9>] sk_common_release+0x169/0x2d0 softirqs last disabled at (4520): [<ffffffffb6f8eb3e>] sk_common_release+0xbe/0x2d0
Check the return value of ip_vs_use_count_inc() and let its caller return proper error. Inside do_ip_vs_set_ctl() the module is already refcounted, we don't need refcount/derefcount there. Finally, in register_ip_vs_app() and start_sync_thread(), take the module refcount earlier and ensure it's released in the error path.
Change since v1: - better return values in case of failure of ip_vs_use_count_inc(), thanks to Julian Anastasov - no need to increase/decrease the module refcount in ip_vs_set_ctl(), thanks to Julian Anastasov
Signed-off-by: Davide Caratti dcaratti@redhat.com Signed-off-by: Julian Anastasov ja@ssi.bg Signed-off-by: Simon Horman horms@verge.net.au Signed-off-by: Sasha Levin sashal@kernel.org --- net/netfilter/ipvs/ip_vs_app.c | 12 ++++++++++-- net/netfilter/ipvs/ip_vs_ctl.c | 14 ++++---------- net/netfilter/ipvs/ip_vs_pe.c | 3 ++- net/netfilter/ipvs/ip_vs_sched.c | 3 ++- net/netfilter/ipvs/ip_vs_sync.c | 13 ++++++++++--- 5 files changed, 28 insertions(+), 17 deletions(-)
diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c index 7588aeaa605ff..80759aadd3e06 100644 --- a/net/netfilter/ipvs/ip_vs_app.c +++ b/net/netfilter/ipvs/ip_vs_app.c @@ -198,21 +198,29 @@ struct ip_vs_app *register_ip_vs_app(struct netns_ipvs *ipvs, struct ip_vs_app *
mutex_lock(&__ip_vs_app_mutex);
+ /* increase the module use count */ + if (!ip_vs_use_count_inc()) { + err = -ENOENT; + goto out_unlock; + } + list_for_each_entry(a, &ipvs->app_list, a_list) { if (!strcmp(app->name, a->name)) { err = -EEXIST; + /* decrease the module use count */ + ip_vs_use_count_dec(); goto out_unlock; } } a = kmemdup(app, sizeof(*app), GFP_KERNEL); if (!a) { err = -ENOMEM; + /* decrease the module use count */ + ip_vs_use_count_dec(); goto out_unlock; } INIT_LIST_HEAD(&a->incs_list); list_add(&a->a_list, &ipvs->app_list); - /* increase the module use count */ - ip_vs_use_count_inc();
out_unlock: mutex_unlock(&__ip_vs_app_mutex); diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 3df94a4991266..b2134c3894289 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1204,7 +1204,8 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u, struct ip_vs_service *svc = NULL;
/* increase the module use count */ - ip_vs_use_count_inc(); + if (!ip_vs_use_count_inc()) + return -ENOPROTOOPT;
/* Lookup the scheduler by 'u->sched_name' */ if (strcmp(u->sched_name, "none")) { @@ -2363,9 +2364,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) if (copy_from_user(arg, user, len) != 0) return -EFAULT;
- /* increase the module use count */ - ip_vs_use_count_inc(); - /* Handle daemons since they have another lock */ if (cmd == IP_VS_SO_SET_STARTDAEMON || cmd == IP_VS_SO_SET_STOPDAEMON) { @@ -2378,13 +2376,13 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) ret = -EINVAL; if (strscpy(cfg.mcast_ifn, dm->mcast_ifn, sizeof(cfg.mcast_ifn)) <= 0) - goto out_dec; + return ret; cfg.syncid = dm->syncid; ret = start_sync_thread(ipvs, &cfg, dm->state); } else { ret = stop_sync_thread(ipvs, dm->state); } - goto out_dec; + return ret; }
mutex_lock(&__ip_vs_mutex); @@ -2479,10 +2477,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
out_unlock: mutex_unlock(&__ip_vs_mutex); - out_dec: - /* decrease the module use count */ - ip_vs_use_count_dec(); - return ret; }
diff --git a/net/netfilter/ipvs/ip_vs_pe.c b/net/netfilter/ipvs/ip_vs_pe.c index 0df17caa8af6c..714e7e05c1021 100644 --- a/net/netfilter/ipvs/ip_vs_pe.c +++ b/net/netfilter/ipvs/ip_vs_pe.c @@ -67,7 +67,8 @@ int register_ip_vs_pe(struct ip_vs_pe *pe) struct ip_vs_pe *tmp;
/* increase the module use count */ - ip_vs_use_count_inc(); + if (!ip_vs_use_count_inc()) + return -ENOENT;
mutex_lock(&ip_vs_pe_mutex); /* Make sure that the pe with this name doesn't exist diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c index a2ff7d746ebf4..3bd0ff36dc41b 100644 --- a/net/netfilter/ipvs/ip_vs_sched.c +++ b/net/netfilter/ipvs/ip_vs_sched.c @@ -184,7 +184,8 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler) }
/* increase the module use count */ - ip_vs_use_count_inc(); + if (!ip_vs_use_count_inc()) + return -ENOENT;
mutex_lock(&ip_vs_sched_mutex);
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index ecb71062fcb3c..5acd99f83166b 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -1762,6 +1762,10 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %zd bytes\n", sizeof(struct ip_vs_sync_conn_v0));
+ /* increase the module use count */ + if (!ip_vs_use_count_inc()) + return -ENOPROTOOPT; + /* Do not hold one mutex and then to block on another */ for (;;) { rtnl_lock(); @@ -1892,9 +1896,6 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, mutex_unlock(&ipvs->sync_mutex); rtnl_unlock();
- /* increase the module use count */ - ip_vs_use_count_inc(); - return 0;
out: @@ -1924,11 +1925,17 @@ out: } kfree(ti); } + + /* decrease the module use count */ + ip_vs_use_count_dec(); return result;
out_early: mutex_unlock(&ipvs->sync_mutex); rtnl_unlock(); + + /* decrease the module use count */ + ip_vs_use_count_dec(); return result; }
From: Eric Dumazet edumazet@google.com
[ Upstream commit c24b75e0f9239e78105f81c5f03a751641eb07ef ]
syzbot reported the following issue :
BUG: KCSAN: data-race in update_defense_level / update_defense_level
read to 0xffffffff861a6260 of 4 bytes by task 3006 on cpu 1: update_defense_level+0x621/0xb30 net/netfilter/ipvs/ip_vs_ctl.c:177 defense_work_handler+0x3d/0xd0 net/netfilter/ipvs/ip_vs_ctl.c:225 process_one_work+0x3d4/0x890 kernel/workqueue.c:2269 worker_thread+0xa0/0x800 kernel/workqueue.c:2415 kthread+0x1d4/0x200 drivers/block/aoe/aoecmd.c:1253 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:352
write to 0xffffffff861a6260 of 4 bytes by task 7333 on cpu 0: update_defense_level+0xa62/0xb30 net/netfilter/ipvs/ip_vs_ctl.c:205 defense_work_handler+0x3d/0xd0 net/netfilter/ipvs/ip_vs_ctl.c:225 process_one_work+0x3d4/0x890 kernel/workqueue.c:2269 worker_thread+0xa0/0x800 kernel/workqueue.c:2415 kthread+0x1d4/0x200 drivers/block/aoe/aoecmd.c:1253 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:352
Reported by Kernel Concurrency Sanitizer on: CPU: 0 PID: 7333 Comm: kworker/0:5 Not tainted 5.4.0-rc3+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Workqueue: events defense_work_handler
Indeed, old_secure_tcp is currently a static variable, while it needs to be a per netns variable.
Fixes: a0840e2e165a ("IPVS: netns, ip_vs_ctl local vars moved to ipvs struct.") Signed-off-by: Eric Dumazet edumazet@google.com Reported-by: syzbot syzkaller@googlegroups.com Signed-off-by: Simon Horman horms@verge.net.au Signed-off-by: Sasha Levin sashal@kernel.org --- include/net/ip_vs.h | 1 + net/netfilter/ipvs/ip_vs_ctl.c | 15 +++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 0e3c0d83bd991..af0ede9ad4d0b 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -885,6 +885,7 @@ struct netns_ipvs { struct delayed_work defense_work; /* Work handler */ int drop_rate; int drop_counter; + int old_secure_tcp; atomic_t dropentry; /* locks in ctl.c */ spinlock_t dropentry_lock; /* drop entry handling */ diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index b2134c3894289..c339b5e386b78 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -98,7 +98,6 @@ static bool __ip_vs_addr_is_local_v6(struct net *net, static void update_defense_level(struct netns_ipvs *ipvs) { struct sysinfo i; - static int old_secure_tcp = 0; int availmem; int nomem; int to_change = -1; @@ -179,35 +178,35 @@ static void update_defense_level(struct netns_ipvs *ipvs) spin_lock(&ipvs->securetcp_lock); switch (ipvs->sysctl_secure_tcp) { case 0: - if (old_secure_tcp >= 2) + if (ipvs->old_secure_tcp >= 2) to_change = 0; break; case 1: if (nomem) { - if (old_secure_tcp < 2) + if (ipvs->old_secure_tcp < 2) to_change = 1; ipvs->sysctl_secure_tcp = 2; } else { - if (old_secure_tcp >= 2) + if (ipvs->old_secure_tcp >= 2) to_change = 0; } break; case 2: if (nomem) { - if (old_secure_tcp < 2) + if (ipvs->old_secure_tcp < 2) to_change = 1; } else { - if (old_secure_tcp >= 2) + if (ipvs->old_secure_tcp >= 2) to_change = 0; ipvs->sysctl_secure_tcp = 1; } break; case 3: - if (old_secure_tcp < 2) + if (ipvs->old_secure_tcp < 2) to_change = 1; break; } - old_secure_tcp = ipvs->sysctl_secure_tcp; + ipvs->old_secure_tcp = ipvs->sysctl_secure_tcp; if (to_change >= 0) ip_vs_protocol_timeout_change(ipvs, ipvs->sysctl_secure_tcp > 1);
From: Taehee Yoo ap420073@gmail.com
[ Upstream commit 65de65d9033750d2cf1b336c9d6e9da3a8b5cc6e ]
The IFF_BONDING means bonding master or bonding slave device. ->ndo_add_slave() sets IFF_BONDING flag and ->ndo_del_slave() unsets IFF_BONDING flag.
bond0<--bond1
Both bond0 and bond1 are bonding device and these should keep having IFF_BONDING flag until they are removed. But bond1 would lose IFF_BONDING at ->ndo_del_slave() because that routine do not check whether the slave device is the bonding type or not. This patch adds the interface type check routine before removing IFF_BONDING flag.
Test commands: ip link add bond0 type bond ip link add bond1 type bond ip link set bond1 master bond0 ip link set bond1 nomaster ip link del bond1 type bond ip link add bond1 type bond
Splat looks like: [ 226.665555] proc_dir_entry 'bonding/bond1' already registered [ 226.666440] WARNING: CPU: 0 PID: 737 at fs/proc/generic.c:361 proc_register+0x2a9/0x3e0 [ 226.667571] Modules linked in: bonding af_packet sch_fq_codel ip_tables x_tables unix [ 226.668662] CPU: 0 PID: 737 Comm: ip Not tainted 5.4.0-rc3+ #96 [ 226.669508] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 [ 226.670652] RIP: 0010:proc_register+0x2a9/0x3e0 [ 226.671612] Code: 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 39 01 00 00 48 8b 04 24 48 89 ea 48 c7 c7 a0 0b 14 9f 48 8b b0 e 0 00 00 00 e8 07 e7 88 ff <0f> 0b 48 c7 c7 40 2d a5 9f e8 59 d6 23 01 48 8b 4c 24 10 48 b8 00 [ 226.675007] RSP: 0018:ffff888050e17078 EFLAGS: 00010282 [ 226.675761] RAX: dffffc0000000008 RBX: ffff88805fdd0f10 RCX: ffffffff9dd344e2 [ 226.676757] RDX: 0000000000000001 RSI: 0000000000000008 RDI: ffff88806c9f6b8c [ 226.677751] RBP: ffff8880507160f3 R08: ffffed100d940019 R09: ffffed100d940019 [ 226.678761] R10: 0000000000000001 R11: ffffed100d940018 R12: ffff888050716008 [ 226.679757] R13: ffff8880507160f2 R14: dffffc0000000000 R15: ffffed100a0e2c1e [ 226.680758] FS: 00007fdc217cc0c0(0000) GS:ffff88806c800000(0000) knlGS:0000000000000000 [ 226.681886] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 226.682719] CR2: 00007f49313424d0 CR3: 0000000050e46001 CR4: 00000000000606f0 [ 226.683727] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 226.684725] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 226.685681] Call Trace: [ 226.687089] proc_create_seq_private+0xb3/0xf0 [ 226.687778] bond_create_proc_entry+0x1b3/0x3f0 [bonding] [ 226.691458] bond_netdev_event+0x433/0x970 [bonding] [ 226.692139] ? __module_text_address+0x13/0x140 [ 226.692779] notifier_call_chain+0x90/0x160 [ 226.693401] register_netdevice+0x9b3/0xd80 [ 226.694010] ? alloc_netdev_mqs+0x854/0xc10 [ 226.694629] ? netdev_change_features+0xa0/0xa0 [ 226.695278] ? rtnl_create_link+0x2ed/0xad0 [ 226.695849] bond_newlink+0x2a/0x60 [bonding] [ 226.696422] __rtnl_newlink+0xb9f/0x11b0 [ 226.696968] ? rtnl_link_unregister+0x220/0x220 [ ... ]
Fixes: 0b680e753724 ("[PATCH] bonding: Add priv_flag to avoid event mishandling") Signed-off-by: Taehee Yoo ap420073@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/bonding/bond_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 136a972ea903a..9b8143dca5123 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1798,7 +1798,8 @@ err_detach: slave_disable_netpoll(new_slave);
err_close: - slave_dev->priv_flags &= ~IFF_BONDING; + if (!netif_is_bond_master(slave_dev)) + slave_dev->priv_flags &= ~IFF_BONDING; dev_close(slave_dev);
err_restore_mac: @@ -2004,7 +2005,8 @@ static int __bond_release_one(struct net_device *bond_dev, else dev_set_mtu(slave_dev, slave->original_mtu);
- slave_dev->priv_flags &= ~IFF_BONDING; + if (!netif_is_bond_master(slave_dev)) + slave_dev->priv_flags &= ~IFF_BONDING;
bond_free_slave(slave);
From: Taehee Yoo ap420073@gmail.com
[ Upstream commit 2bce1ebed17da54c65042ec2b962e3234bad5b47 ]
When a macsec interface is created, it increases a refcnt to a lower device(real device). when macsec interface is deleted, the refcnt is decreased in macsec_free_netdev(), which is ->priv_destructor() of macsec interface.
The problem scenario is this. When nested macsec interfaces are exiting, the exit routine of the macsec module makes refcnt leaks.
Test commands: ip link add dummy0 type dummy ip link add macsec0 link dummy0 type macsec ip link add macsec1 link macsec0 type macsec modprobe -rv macsec
[ 208.629433] unregister_netdevice: waiting for macsec0 to become free. Usage count = 1
Steps of exit routine of macsec module are below. 1. Calls ->dellink() in __rtnl_link_unregister(). 2. Checks refcnt and wait refcnt to be 0 if refcnt is not 0 in netdev_run_todo(). 3. Calls ->priv_destruvtor() in netdev_run_todo().
Step2 checks refcnt, but step3 decreases refcnt. So, step2 waits forever.
This patch makes the macsec module do not hold a refcnt of the lower device because it already holds a refcnt of the lower device with netdev_upper_dev_link().
Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver") Signed-off-by: Taehee Yoo ap420073@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/macsec.c | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 0dc92d2faa64d..05115fb0c97a9 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -3008,12 +3008,10 @@ static const struct nla_policy macsec_rtnl_policy[IFLA_MACSEC_MAX + 1] = { static void macsec_free_netdev(struct net_device *dev) { struct macsec_dev *macsec = macsec_priv(dev); - struct net_device *real_dev = macsec->real_dev;
free_percpu(macsec->stats); free_percpu(macsec->secy.tx_sc.stats);
- dev_put(real_dev); }
static void macsec_setup(struct net_device *dev) @@ -3268,8 +3266,6 @@ static int macsec_newlink(struct net *net, struct net_device *dev, if (err < 0) return err;
- dev_hold(real_dev); - macsec->nest_level = dev_get_nest_level(real_dev) + 1; netdev_lockdep_set_classes(dev); lockdep_set_class_and_subclass(&dev->addr_list_lock,
From: Nikhil Badola nikhil.badola@freescale.com
[ Upstream commit bc1e3a2dd0c9954fd956ac43ca2876bbea018c01 ]
Check memory resource existence before releasing it to avoid NULL pointer dereference
Signed-off-by: Nikhil Badola nikhil.badola@freescale.com Reviewed-by: Ran Wang ran.wang_1@nxp.com Reviewed-by: Peter Chen peter.chen@nxp.com Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/usb/gadget/udc/fsl_udc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index be59309e848c3..d44b26d5b2a2c 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -2552,7 +2552,7 @@ static int fsl_udc_remove(struct platform_device *pdev) dma_pool_destroy(udc_controller->td_pool); free_irq(udc_controller->irq, udc_controller); iounmap(dr_regs); - if (pdata->operating_mode == FSL_USB2_DR_DEVICE) + if (res && (pdata->operating_mode == FSL_USB2_DR_DEVICE)) release_mem_region(res->start, resource_size(res));
/* free udc --wait for the release() finished */
From: Cristian Birsan cristian.birsan@microchip.com
[ Upstream commit ba3a1a915c49cc3023e4ddfc88f21e7514e82aa4 ]
Fix interrupt storm generated by endpoints when working in FIFO mode. The TX_COMPLETE interrupt is used only by control endpoints processing. Do not enable it for other types of endpoints.
Fixes: 914a3f3b3754 ("USB: add atmel_usba_udc driver") Signed-off-by: Cristian Birsan cristian.birsan@microchip.com Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/usb/gadget/udc/atmel_usba_udc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 8f267be1745d8..a4ab230335786 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -436,9 +436,11 @@ static void submit_request(struct usba_ep *ep, struct usba_request *req) next_fifo_transaction(ep, req); if (req->last_transaction) { usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); - usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + if (ep_is_control(ep)) + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); } else { - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + if (ep_is_control(ep)) + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); } }
From: Chandana Kishori Chiluveru cchiluve@codeaurora.org
[ Upstream commit 1c20c89b0421b52b2417bb0f62a611bc669eda1d ]
composite_dev_cleanup call from the failure of configfs_composite_bind frees up the cdev->os_desc_req and cdev->req. If the previous calls of bind and unbind is successful these will carry stale values.
Consider the below sequence of function calls: configfs_composite_bind() composite_dev_prepare() - Allocate cdev->req, cdev->req->buf composite_os_desc_req_prepare() - Allocate cdev->os_desc_req, cdev->os_desc_req->buf configfs_composite_unbind() composite_dev_cleanup() - free the cdev->os_desc_req->buf and cdev->req->buf Next composition switch configfs_composite_bind() - If it fails goto err_comp_cleanup will call the composite_dev_cleanup() function composite_dev_cleanup() - calls kfree up with the stale values of cdev->req->buf and cdev->os_desc_req from the previous configfs_composite_bind call. The free call on these stale values leads to double free.
Hence, Fix this issue by setting request and buffer pointer to NULL after kfree.
Signed-off-by: Chandana Kishori Chiluveru cchiluve@codeaurora.org Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/usb/gadget/composite.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index dfcabadeed01b..33115e19756c6 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2156,14 +2156,18 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev) usb_ep_dequeue(cdev->gadget->ep0, cdev->os_desc_req);
kfree(cdev->os_desc_req->buf); + cdev->os_desc_req->buf = NULL; usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req); + cdev->os_desc_req = NULL; } if (cdev->req) { if (cdev->setup_pending) usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
kfree(cdev->req->buf); + cdev->req->buf = NULL; usb_ep_free_request(cdev->gadget->ep0, cdev->req); + cdev->req = NULL; } cdev->next_string_id = 0; device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
From: Navid Emamdoost navid.emamdoost@gmail.com
[ Upstream commit 9bbfceea12a8f145097a27d7c7267af25893c060 ]
In dwc3_pci_probe a call to platform_device_alloc allocates a device which is correctly put in case of error except one case: when the call to platform_device_add_properties fails it directly returns instead of going to error handling. This commit replaces return with the goto.
Fixes: 1a7b12f69a94 ("usb: dwc3: pci: Supply device properties via driver data") Signed-off-by: Navid Emamdoost navid.emamdoost@gmail.com Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/usb/dwc3/dwc3-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 8cced3609e243..b4e42d597211a 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -256,7 +256,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
ret = platform_device_add_properties(dwc->dwc3, p); if (ret < 0) - return ret; + goto err;
ret = dwc3_pci_quirks(dwc); if (ret)
From: Peter Chen peter.chen@nxp.com
[ Upstream commit 1a1c851bbd706ea9f3a9756c2d3db28523506d3b ]
We meet several NULL pointer issues if configfs_composite_unbind and composite_setup (or composite_disconnect) are running together. These issues occur when do the function switch stress test, the configfs_compsoite_unbind is called from user mode by echo "" to /sys/../UDC entry, and meanwhile, the setup interrupt or disconnect interrupt occurs by hardware. The composite_setup will get the cdev from get_gadget_data, but configfs_composite_unbind will set gadget data as NULL, so the NULL pointer issue occurs. This concurrent is hard to reproduce by native kernel, but can be reproduced by android kernel.
In this commit, we introduce one spinlock belongs to structure gadget_info since we can't use the same spinlock in usb_composite_dev due to exclusive running together between composite_setup and configfs_composite_unbind. And one bit flag 'unbind' to indicate the code is at unbind routine, this bit is needed due to we release the lock at during configfs_composite_unbind sometimes, and composite_setup may be run at that time.
Several oops:
oops 1: android_work: sent uevent USB_STATE=CONNECTED configfs-gadget gadget: super-speed config #1: b android_work: sent uevent USB_STATE=CONFIGURED init: Received control message 'start' for 'adbd' from pid: 3515 (system_server) Unable to handle kernel NULL pointer dereference at virtual address 0000002a init: Received control message 'stop' for 'adbd' from pid: 3375 (/vendor/bin/hw/android.hardware.usb@1.1-servic) Mem abort info: Exception class = DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 Data abort info: ISV = 0, ISS = 0x00000004 CM = 0, WnR = 0 user pgtable: 4k pages, 48-bit VAs, pgd = ffff8008f1b7f000 [000000000000002a] *pgd=0000000000000000 Internal error: Oops: 96000004 [#1] PREEMPT SMP Modules linked in: CPU: 4 PID: 2457 Comm: irq/125-5b11000 Not tainted 4.14.98-07846-g0b40a9b-dirty #16 Hardware name: Freescale i.MX8QM MEK (DT) task: ffff8008f2a98000 task.stack: ffff00000b7b8000 PC is at composite_setup+0x44/0x1508 LR is at android_setup+0xb8/0x13c pc : [<ffff0000089ffb3c>] lr : [<ffff000008a032fc>] pstate: 800001c5 sp : ffff00000b7bbb80 x29: ffff00000b7bbb80 x28: ffff8008f2a3c010 x27: 0000000000000001 x26: 0000000000000000 [1232/1897] audit: audit_lost=25791 audit_rate_limit=5 audit_backlog_limit=64 x25: 00000000ffffffa1 x24: ffff8008f2a3c010 audit: rate limit exceeded x23: 0000000000000409 x22: ffff000009c8e000 x21: ffff8008f7a8b428 x20: ffff00000afae000 x19: ffff0000089ff000 x18: 0000000000000000 x17: 0000000000000000 x16: ffff0000082b7c9c x15: 0000000000000000 x14: f1866f5b952aca46 x13: e35502e30d44349c x12: 0000000000000008 x11: 0000000000000008 x10: 0000000000000a30 x9 : ffff00000b7bbd00 x8 : ffff8008f2a98a90 x7 : ffff8008f27a9c90 x6 : 0000000000000001 x5 : 0000000000000000 x4 : 0000000000000001 x3 : 0000000000000000 x2 : 0000000000000006 x1 : ffff0000089ff8d0 x0 : 732a010310b9ed00
X7: 0xffff8008f27a9c10: 9c10 00000002 00000000 00000001 00000000 13110000 ffff0000 00000002 00208040 9c30 00000000 00000000 00000000 00000000 00000000 00000005 00000029 00000000 9c50 00051778 00000001 f27a8e00 ffff8008 00000005 00000000 00000078 00000078 9c70 00000078 00000000 09031d48 ffff0000 00100000 00000000 00400000 00000000 9c90 00000001 00000000 00000000 00000000 00000000 00000000 ffefb1a0 ffff8008 9cb0 f27a9ca8 ffff8008 00000000 00000000 b9d88037 00000173 1618a3eb 00000001 9cd0 870a792a 0000002e 16188fe6 00000001 0000242b 00000000 00000000 00000000 using random self ethernet address 9cf0 019a4646 00000000 000547f3 00000000 ecfd6c33 00000002 00000000 using random host ethernet address 00000000
X8: 0xffff8008f2a98a10: 8a10 00000000 00000000 f7788d00 ffff8008 00000001 00000000 00000000 00000000 8a30 eb218000 ffff8008 f2a98000 ffff8008 f2a98000 ffff8008 09885000 ffff0000 8a50 f34df480 ffff8008 00000000 00000000 f2a98648 ffff8008 09c8e000 ffff0000 8a70 fff2c800 ffff8008 09031d48 ffff0000 0b7bbd00 ffff0000 0b7bbd00 ffff0000 8a90 080861bc ffff0000 00000000 00000000 00000000 00000000 00000000 00000000 8ab0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 8ad0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 8af0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
X21: 0xffff8008f7a8b3a8: b3a8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 b3c8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 b3e8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 b408 00000000 00000000 00000000 00000000 00000000 00000000 00000001 00000000 b428 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 b448 0053004d 00540046 00300031 00010030 eb07b520 ffff8008 20011201 00000003 b468 e418d109 0104404e 00010302 00000000 eb07b558 ffff8008 eb07b558 ffff8008 b488 f7a8b488 ffff8008 f7a8b488 ffff8008 f7a8b300 ffff8008 00000000 00000000
X24: 0xffff8008f2a3bf90: bf90 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 bfb0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 bfd0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 bff0 00000000 00000000 00000000 00000000 f76c8010 ffff8008 f76c8010 ffff8008 c010 00000000 00000000 f2a3c018 ffff8008 f2a3c018 ffff8008 08a067dc ffff0000 c030 f2a5a000 ffff8008 091c3650 ffff0000 f716fd18 ffff8008 f716fe30 ffff8008 c050 f2ce4a30 ffff8008 00000000 00000005 00000000 00000000 095d1568 ffff0000 c070 f76c8010 ffff8008 f2ce4b00 ffff8008 095cac68 ffff0000 f2a5a028 ffff8008
X28: 0xffff8008f2a3bf90: bf90 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 bfb0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 bfd0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 bff0 00000000 00000000 00000000 00000000 f76c8010 ffff8008 f76c8010 ffff8008 c010 00000000 00000000 f2a3c018 ffff8008 f2a3c018 ffff8008 08a067dc ffff0000 c030 f2a5a000 ffff8008 091c3650 ffff0000 f716fd18 ffff8008 f716fe30 ffff8008 c050 f2ce4a30 ffff8008 00000000 00000005 00000000 00000000 095d1568 ffff0000 c070 f76c8010 ffff8008 f2ce4b00 ffff8008 095cac68 ffff0000 f2a5a028 ffff8008
Process irq/125-5b11000 (pid: 2457, stack limit = 0xffff00000b7b8000) Call trace: Exception stack(0xffff00000b7bba40 to 0xffff00000b7bbb80) ba40: 732a010310b9ed00 ffff0000089ff8d0 0000000000000006 0000000000000000 ba60: 0000000000000001 0000000000000000 0000000000000001 ffff8008f27a9c90 ba80: ffff8008f2a98a90 ffff00000b7bbd00 0000000000000a30 0000000000000008 baa0: 0000000000000008 e35502e30d44349c f1866f5b952aca46 0000000000000000 bac0: ffff0000082b7c9c 0000000000000000 0000000000000000 ffff0000089ff000 bae0: ffff00000afae000 ffff8008f7a8b428 ffff000009c8e000 0000000000000409 bb00: ffff8008f2a3c010 00000000ffffffa1 0000000000000000 0000000000000001 bb20: ffff8008f2a3c010 ffff00000b7bbb80 ffff000008a032fc ffff00000b7bbb80 bb40: ffff0000089ffb3c 00000000800001c5 ffff00000b7bbb80 732a010310b9ed00 bb60: ffffffffffffffff ffff0000080f777c ffff00000b7bbb80 ffff0000089ffb3c [<ffff0000089ffb3c>] composite_setup+0x44/0x1508 [<ffff000008a032fc>] android_setup+0xb8/0x13c [<ffff0000089bd9a8>] cdns3_ep0_delegate_req+0x44/0x70 [<ffff0000089bdff4>] cdns3_check_ep0_interrupt_proceed+0x33c/0x654 [<ffff0000089bca44>] cdns3_device_thread_irq_handler+0x4b0/0x4bc [<ffff0000089b77b4>] cdns3_thread_irq+0x48/0x68 [<ffff000008145bf0>] irq_thread_fn+0x28/0x88 [<ffff000008145e38>] irq_thread+0x13c/0x228 [<ffff0000080fed70>] kthread+0x104/0x130 [<ffff000008085064>] ret_from_fork+0x10/0x18
oops2: composite_disconnect: Calling disconnect on a Gadget that is not connected android_work: did not send uevent (0 0 (null)) init: Received control message 'stop' for 'adbd' from pid: 3359 (/vendor/bin/hw/android.hardware.usb@1.1-service.imx) init: Sending signal 9 to service 'adbd' (pid 22343) process group... ------------[ cut here ]------------ audit: audit_lost=180038 audit_rate_limit=5 audit_backlog_limit=64 audit: rate limit exceeded WARNING: CPU: 0 PID: 3468 at kernel_imx/drivers/usb/gadget/composite.c:2009 composite_disconnect+0x80/0x88 Modules linked in: CPU: 0 PID: 3468 Comm: HWC-UEvent-Thre Not tainted 4.14.98-07846-g0b40a9b-dirty #16 Hardware name: Freescale i.MX8QM MEK (DT) task: ffff8008f2349c00 task.stack: ffff00000b0a8000 PC is at composite_disconnect+0x80/0x88 LR is at composite_disconnect+0x80/0x88 pc : [<ffff0000089ff9b0>] lr : [<ffff0000089ff9b0>] pstate: 600001c5 sp : ffff000008003dd0 x29: ffff000008003dd0 x28: ffff8008f2349c00 x27: ffff000009885018 x26: ffff000008004000 Timeout for IPC response! x25: ffff000009885018 x24: ffff000009c8e280 x23: ffff8008f2d98010 x22: 00000000000001c0 x21: ffff8008f2d98394 x20: ffff8008f2d98010 x19: 0000000000000000 x18: 0000e3956f4f075a fxos8700 4-001e: i2c block read acc failed x17: 0000e395735727e8 x16: ffff00000829f4d4 x15: ffffffffffffffff x14: 7463656e6e6f6320 x13: 746f6e2009090920 x12: 7369207461687420 x11: 7465676461472061 x10: 206e6f207463656e x9 : 6e6f637369642067 x8 : ffff000009c8e280 x7 : ffff0000086ca6cc x6 : ffff000009f15e78 x5 : 0000000000000000 x4 : 0000000000000000 x3 : ffffffffffffffff x2 : c3f28b86000c3900 x1 : c3f28b86000c3900 x0 : 000000000000004e
X20: 0xffff8008f2d97f90: 7f90 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 7fb0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 libprocessgroup: Failed to kill process cgroup uid 0 pid 22343 in 215ms, 1 processes remain 7fd0 Timeout for IPC response! 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 using random self ethernet address 7ff0 00000000 00000000 00000000 00000000 f76c8010 ffff8008 f76c8010 ffff8008 8010 00000100 00000000 f2d98018 ffff8008 f2d98018 ffff8008 08a067dc using random host ethernet address ffff0000 8030 f206d800 ffff8008 091c3650 ffff0000 f7957b18 ffff8008 f7957730 ffff8008 8050 f716a630 ffff8008 00000000 00000005 00000000 00000000 095d1568 ffff0000 8070 f76c8010 ffff8008 f716a800 ffff8008 095cac68 ffff0000 f206d828 ffff8008
X21: 0xffff8008f2d98314: 8314 ffff8008 00000000 00000000 00000000 00000000 00000000 00000000 00000000 8334 00000000 00000000 00000000 00000000 00000000 08a04cf4 ffff0000 00000000 8354 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 8374 00000000 00000000 00000000 00001001 00000000 00000000 00000000 00000000 8394 e4bbe4bb 0f230000 ffff0000 0afae000 ffff0000 ae001000 00000000 f206d400 Timeout for IPC response! 83b4 ffff8008 00000000 00000000 f7957b18 ffff8008 f7957718 ffff8008 f7957018 83d4 ffff8008 f7957118 ffff8008 f7957618 ffff8008 f7957818 ffff8008 f7957918 83f4 ffff8008 f7957d18 ffff8008 00000000 00000000 00000000 00000000 00000000
X23: 0xffff8008f2d97f90: 7f90 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 7fb0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 7fd0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 7ff0 00000000 00000000 00000000 00000000 f76c8010 ffff8008 f76c8010 ffff8008 8010 00000100 00000000 f2d98018 ffff8008 f2d98018 ffff8008 08a067dc ffff0000 8030 f206d800 ffff8008 091c3650 ffff0000 f7957b18 ffff8008 f7957730 ffff8008 8050 f716a630 ffff8008 00000000 00000005 00000000 00000000 095d1568 ffff0000 8070 f76c8010 ffff8008 f716a800 ffff8008 095cac68 ffff0000 f206d828 ffff8008
X28: 0xffff8008f2349b80: 9b80 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9ba0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9bc0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9be0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 9c00 00000022 00000000 ffffffff ffffffff 00010001 00000000 00000000 00000000 9c20 0b0a8000 ffff0000 00000002 00404040 00000000 00000000 00000000 00000000 9c40 00000001 00000000 00000001 00000000 001ebd44 00000001 f390b800 ffff8008 9c60 00000000 00000001 00000070 00000070 00000070 00000000 09031d48 ffff0000
Call trace: Exception stack(0xffff000008003c90 to 0xffff000008003dd0) 3c80: 000000000000004e c3f28b86000c3900 3ca0: c3f28b86000c3900 ffffffffffffffff 0000000000000000 0000000000000000 3cc0: ffff000009f15e78 ffff0000086ca6cc ffff000009c8e280 6e6f637369642067 3ce0: 206e6f207463656e 7465676461472061 7369207461687420 746f6e2009090920 3d00: 7463656e6e6f6320 ffffffffffffffff ffff00000829f4d4 0000e395735727e8 3d20: 0000e3956f4f075a 0000000000000000 ffff8008f2d98010 ffff8008f2d98394 3d40: 00000000000001c0 ffff8008f2d98010 ffff000009c8e280 ffff000009885018 3d60: ffff000008004000 ffff000009885018 ffff8008f2349c00 ffff000008003dd0 3d80: ffff0000089ff9b0 ffff000008003dd0 ffff0000089ff9b0 00000000600001c5 3da0: ffff8008f33f2cd8 0000000000000000 0000ffffffffffff 0000000000000000 init: Received control message 'start' for 'adbd' from pid: 3359 (/vendor/bin/hw/android.hardware.usb@1.1-service.imx) 3dc0: ffff000008003dd0 ffff0000089ff9b0 [<ffff0000089ff9b0>] composite_disconnect+0x80/0x88 [<ffff000008a044d4>] android_disconnect+0x3c/0x68 [<ffff0000089ba9f8>] cdns3_device_irq_handler+0xfc/0x2c8 [<ffff0000089b84c0>] cdns3_irq+0x44/0x94 [<ffff00000814494c>] __handle_irq_event_percpu+0x60/0x24c [<ffff000008144c0c>] handle_irq_event+0x58/0xc0 [<ffff00000814873c>] handle_fasteoi_irq+0x98/0x180 [<ffff000008143a10>] generic_handle_irq+0x24/0x38 [<ffff000008144170>] __handle_domain_irq+0x60/0xac [<ffff0000080819c4>] gic_handle_irq+0xd4/0x17c
Signed-off-by: Peter Chen peter.chen@nxp.com Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/usb/gadget/configfs.c | 110 ++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 0251299428946..33852c2b29d1a 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -61,6 +61,8 @@ struct gadget_info { bool use_os_desc; char b_vendor_code; char qw_sign[OS_STRING_QW_SIGN_LEN]; + spinlock_t spinlock; + bool unbind; };
static inline struct gadget_info *to_gadget_info(struct config_item *item) @@ -1244,6 +1246,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget, int ret;
/* the gi->lock is hold by the caller */ + gi->unbind = 0; cdev->gadget = gadget; set_gadget_data(gadget, cdev); ret = composite_dev_prepare(composite, cdev); @@ -1376,31 +1379,128 @@ static void configfs_composite_unbind(struct usb_gadget *gadget) { struct usb_composite_dev *cdev; struct gadget_info *gi; + unsigned long flags;
/* the gi->lock is hold by the caller */
cdev = get_gadget_data(gadget); gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + gi->unbind = 1; + spin_unlock_irqrestore(&gi->spinlock, flags);
kfree(otg_desc[0]); otg_desc[0] = NULL; purge_configs_funcs(gi); composite_dev_cleanup(cdev); usb_ep_autoconfig_reset(cdev->gadget); + spin_lock_irqsave(&gi->spinlock, flags); cdev->gadget = NULL; set_gadget_data(gadget, NULL); + spin_unlock_irqrestore(&gi->spinlock, flags); +} + +static int configfs_composite_setup(struct usb_gadget *gadget, + const struct usb_ctrlrequest *ctrl) +{ + struct usb_composite_dev *cdev; + struct gadget_info *gi; + unsigned long flags; + int ret; + + cdev = get_gadget_data(gadget); + if (!cdev) + return 0; + + gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + cdev = get_gadget_data(gadget); + if (!cdev || gi->unbind) { + spin_unlock_irqrestore(&gi->spinlock, flags); + return 0; + } + + ret = composite_setup(gadget, ctrl); + spin_unlock_irqrestore(&gi->spinlock, flags); + return ret; +} + +static void configfs_composite_disconnect(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev; + struct gadget_info *gi; + unsigned long flags; + + cdev = get_gadget_data(gadget); + if (!cdev) + return; + + gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + cdev = get_gadget_data(gadget); + if (!cdev || gi->unbind) { + spin_unlock_irqrestore(&gi->spinlock, flags); + return; + } + + composite_disconnect(gadget); + spin_unlock_irqrestore(&gi->spinlock, flags); +} + +static void configfs_composite_suspend(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev; + struct gadget_info *gi; + unsigned long flags; + + cdev = get_gadget_data(gadget); + if (!cdev) + return; + + gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + cdev = get_gadget_data(gadget); + if (!cdev || gi->unbind) { + spin_unlock_irqrestore(&gi->spinlock, flags); + return; + } + + composite_suspend(gadget); + spin_unlock_irqrestore(&gi->spinlock, flags); +} + +static void configfs_composite_resume(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev; + struct gadget_info *gi; + unsigned long flags; + + cdev = get_gadget_data(gadget); + if (!cdev) + return; + + gi = container_of(cdev, struct gadget_info, cdev); + spin_lock_irqsave(&gi->spinlock, flags); + cdev = get_gadget_data(gadget); + if (!cdev || gi->unbind) { + spin_unlock_irqrestore(&gi->spinlock, flags); + return; + } + + composite_resume(gadget); + spin_unlock_irqrestore(&gi->spinlock, flags); }
static const struct usb_gadget_driver configfs_driver_template = { .bind = configfs_composite_bind, .unbind = configfs_composite_unbind,
- .setup = composite_setup, - .reset = composite_disconnect, - .disconnect = composite_disconnect, + .setup = configfs_composite_setup, + .reset = configfs_composite_disconnect, + .disconnect = configfs_composite_disconnect,
- .suspend = composite_suspend, - .resume = composite_resume, + .suspend = configfs_composite_suspend, + .resume = configfs_composite_resume,
.max_speed = USB_SPEED_SUPER, .driver = {
On Mon 2019-11-11 19:28:52, Greg Kroah-Hartman wrote:
From: Peter Chen peter.chen@nxp.com
[ Upstream commit 1a1c851bbd706ea9f3a9756c2d3db28523506d3b ]
We meet several NULL pointer issues if configfs_composite_unbind and composite_setup (or composite_disconnect) are running together. These issues occur when do the function switch stress test, the configfs_compsoite_unbind is called from user mode by echo "" to /sys/../UDC entry, and meanwhile, the setup interrupt or disconnect interrupt occurs by hardware. The composite_setup
+++ b/drivers/usb/gadget/configfs.c @@ -61,6 +61,8 @@ struct gadget_info { bool use_os_desc; char b_vendor_code; char qw_sign[OS_STRING_QW_SIGN_LEN];
- spinlock_t spinlock;
- bool unbind;
}; static inline struct gadget_info *to_gadget_info(struct config_item *item) @@ -1244,6 +1246,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget, int ret; /* the gi->lock is hold by the caller */
- gi->unbind = 0; cdev->gadget = gadget;
Since variable is bool, I'd expect "= false" here?
- unsigned long flags;
/* the gi->lock is hold by the caller */
"is held".
cdev = get_gadget_data(gadget); gi = container_of(cdev, struct gadget_info, cdev);
- spin_lock_irqsave(&gi->spinlock, flags);
- gi->unbind = 1;
= true;
+static int configfs_composite_setup(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctrl)
+{
- struct usb_composite_dev *cdev;
- struct gadget_info *gi;
- unsigned long flags;
- int ret;
- cdev = get_gadget_data(gadget);
- if (!cdev)
return 0;
- gi = container_of(cdev, struct gadget_info, cdev);
- spin_lock_irqsave(&gi->spinlock, flags);
- cdev = get_gadget_data(gadget);
cdev already contains required value, why get it second time? (If it needs to be done under lock, comment might be useful...)
Best regards, Pavel
We meet several NULL pointer issues if configfs_composite_unbind and composite_setup (or composite_disconnect) are running together. These issues occur when do the function switch stress test, the configfs_compsoite_unbind is called from user mode by echo "" to /sys/../UDC entry, and meanwhile, the setup interrupt or disconnect interrupt occurs by hardware. The composite_setup
+++ b/drivers/usb/gadget/configfs.c @@ -61,6 +61,8 @@ struct gadget_info { bool use_os_desc; char b_vendor_code; char qw_sign[OS_STRING_QW_SIGN_LEN];
- spinlock_t spinlock;
- bool unbind;
};
static inline struct gadget_info *to_gadget_info(struct config_item *item) @@ -1244,6 +1246,7 @@ static int configfs_composite_bind(struct
usb_gadget *gadget,
int ret;
/* the gi->lock is hold by the caller */
- gi->unbind = 0; cdev->gadget = gadget;
Since variable is bool, I'd expect "= false" here?
unsigned long flags;
/* the gi->lock is hold by the caller */
"is held".
cdev = get_gadget_data(gadget); gi = container_of(cdev, struct gadget_info, cdev);
- spin_lock_irqsave(&gi->spinlock, flags);
- gi->unbind = 1;
= true;
+static int configfs_composite_setup(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctrl) {
- struct usb_composite_dev *cdev;
- struct gadget_info *gi;
- unsigned long flags;
- int ret;
- cdev = get_gadget_data(gadget);
- if (!cdev)
return 0;
- gi = container_of(cdev, struct gadget_info, cdev);
- spin_lock_irqsave(&gi->spinlock, flags);
- cdev = get_gadget_data(gadget);
cdev already contains required value, why get it second time? (If it needs to be done under lock, comment might be useful...)
Hi Pavel,
Thanks for comment.
The reason is the cdev may be set to NULL by configfs_composite_unbind through another process, eg, the user wants to disable current USB gadget function, this patch tries to fix such kinds of concurrent issue.
Peter
From: Yinbo Zhu yinbo.zhu@nxp.com
[ Upstream commit a7d9874c6f3fbc8d25cd9ceba35b6822612c4ebf ]
layerscape board sometimes reported some usb call trace, that is due to kernel sent LPM tokerns automatically when it has no pending transfers and think that the link is idle enough to enter L1, which procedure will ask usb register has a recovery,then kernel will compare USBx_GFLADJ and set GFLADJ_30MHZ, GFLADJ_30MHZ_REG until GFLADJ_30MHZ is equal 0x20, if the conditions were met then issue occur, but whatever the conditions whether were met that usb is all need keep GFLADJ_30MHZ of value is 0x20 (xhci spec ask use GFLADJ_30MHZ to adjust any offset from clock source that generates the clock that drives the SOF counter, 0x20 is default value of it)That is normal logic, so need remove the call trace.
Signed-off-by: Yinbo Zhu yinbo.zhu@nxp.com Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/usb/dwc3/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 05b9ccff7447a..aca7e7fa5e47d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -299,8 +299,7 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); dft = reg & DWC3_GFLADJ_30MHZ_MASK; - if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj, - "request value same as default, ignoring\n")) { + if (dft != dwc->fladj) { reg &= ~DWC3_GFLADJ_30MHZ_MASK; reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
From: Kim Phillips kim.phillips@amd.com
[ Upstream commit 317b96bb14303c7998dbcd5bc606bd8038fdd4b4 ]
The loop that reads all the IBS MSRs into *buf stopped one MSR short of reading the IbsOpData register, which contains the RipInvalid status bit.
Fix the offset_max assignment so the MSR gets read, so the RIP invalid evaluation is based on what the IBS h/w output, instead of what was left in memory.
Signed-off-by: Kim Phillips kim.phillips@amd.com Signed-off-by: Peter Zijlstra (Intel) peterz@infradead.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Arnaldo Carvalho de Melo acme@redhat.com Cc: Borislav Petkov bp@alien8.de Cc: H. Peter Anvin hpa@zytor.com Cc: Jiri Olsa jolsa@redhat.com Cc: Linus Torvalds torvalds@linux-foundation.org Cc: Mark Rutland mark.rutland@arm.com Cc: Namhyung Kim namhyung@kernel.org Cc: Stephane Eranian eranian@google.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Vince Weaver vincent.weaver@maine.edu Fixes: d47e8238cd76 ("perf/x86-ibs: Take instruction pointer from ibs sample") Link: https://lkml.kernel.org/r/20191023150955.30292-1-kim.phillips@amd.com Signed-off-by: Ingo Molnar mingo@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- arch/x86/events/amd/ibs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c index 80c6d84cad67b..fac0867907d4d 100644 --- a/arch/x86/events/amd/ibs.c +++ b/arch/x86/events/amd/ibs.c @@ -625,7 +625,7 @@ fail: if (event->attr.sample_type & PERF_SAMPLE_RAW) offset_max = perf_ibs->offset_max; else if (check_rip) - offset_max = 2; + offset_max = 3; else offset_max = 1; do {
From: Kim Phillips kim.phillips@amd.com
[ Upstream commit e431e79b60603079d269e0c2a5177943b95fa4b6 ]
This saves us writing the IBS control MSR twice when disabling the event.
I searched revision guides for all families since 10h, and did not find occurrence of erratum #420, nor anything remotely similar: so we isolate the secondary MSR write to family 10h only.
Also unconditionally update the count mask for IBS Op implementations that have read & writeable current count (CurCnt) fields in addition to the MaxCnt field. These bits were reserved on prior implementations, and therefore shouldn't have negative impact.
Signed-off-by: Kim Phillips kim.phillips@amd.com Signed-off-by: Peter Zijlstra (Intel) peterz@infradead.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Arnaldo Carvalho de Melo acme@kernel.org Cc: Arnaldo Carvalho de Melo acme@redhat.com Cc: Borislav Petkov bp@alien8.de Cc: H. Peter Anvin hpa@zytor.com Cc: Jiri Olsa jolsa@redhat.com Cc: Linus Torvalds torvalds@linux-foundation.org Cc: Mark Rutland mark.rutland@arm.com Cc: Namhyung Kim namhyung@kernel.org Cc: Stephane Eranian eranian@google.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Vince Weaver vincent.weaver@maine.edu Fixes: c9574fe0bdb9 ("perf/x86-ibs: Implement workaround for IBS erratum #420") Link: https://lkml.kernel.org/r/20191023150955.30292-2-kim.phillips@amd.com Signed-off-by: Ingo Molnar mingo@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- arch/x86/events/amd/ibs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c index fac0867907d4d..07bf5517d9d8b 100644 --- a/arch/x86/events/amd/ibs.c +++ b/arch/x86/events/amd/ibs.c @@ -389,7 +389,8 @@ static inline void perf_ibs_disable_event(struct perf_ibs *perf_ibs, struct hw_perf_event *hwc, u64 config) { config &= ~perf_ibs->cnt_mask; - wrmsrl(hwc->config_base, config); + if (boot_cpu_data.x86 == 0x10) + wrmsrl(hwc->config_base, config); config &= ~perf_ibs->enable_mask; wrmsrl(hwc->config_base, config); } @@ -564,7 +565,8 @@ static struct perf_ibs perf_ibs_op = { }, .msr = MSR_AMD64_IBSOPCTL, .config_mask = IBS_OP_CONFIG_MASK, - .cnt_mask = IBS_OP_MAX_CNT, + .cnt_mask = IBS_OP_MAX_CNT | IBS_OP_CUR_CNT | + IBS_OP_CUR_CNT_RAND, .enable_mask = IBS_OP_ENABLE, .valid_mask = IBS_OP_VAL, .max_period = IBS_OP_MAX_CNT << 4,
From: Kan Liang kan.liang@linux.intel.com
[ Upstream commit 75be6f703a141b048590d659a3954c4fedd30bba ]
The events in the same group don't start or stop simultaneously. Here is the ftrace when enabling event group for uncore_iio_0:
# perf stat -e "{uncore_iio_0/event=0x1/,uncore_iio_0/event=0xe/}"
<idle>-0 [000] d.h. 8959.064832: read_msr: a41, value b2b0b030 //Read counter reg of IIO unit0 counter0 <idle>-0 [000] d.h. 8959.064835: write_msr: a48, value 400001 //Write Ctrl reg of IIO unit0 counter0 to enable counter0. <------ Although counter0 is enabled, Unit Ctrl is still freezed. Nothing will count. We are still good here. <idle>-0 [000] d.h. 8959.064836: read_msr: a40, value 30100 //Read Unit Ctrl reg of IIO unit0 <idle>-0 [000] d.h. 8959.064838: write_msr: a40, value 30000 //Write Unit Ctrl reg of IIO unit0 to enable all counters in the unit by clear Freeze bit <------Unit0 is un-freezed. Counter0 has been enabled. Now it starts counting. But counter1 has not been enabled yet. The issue starts here. <idle>-0 [000] d.h. 8959.064846: read_msr: a42, value 0 //Read counter reg of IIO unit0 counter1 <idle>-0 [000] d.h. 8959.064847: write_msr: a49, value 40000e //Write Ctrl reg of IIO unit0 counter1 to enable counter1. <------ Now, counter1 just starts to count. Counter0 has been running for a while.
Current code un-freezes the Unit Ctrl right after the first counter is enabled. The subsequent group events always loses some counter values.
Implement pmu_enable and pmu_disable support for uncore, which can help to batch hardware accesses.
No one uses uncore_enable_box and uncore_disable_box. Remove them.
Signed-off-by: Kan Liang kan.liang@linux.intel.com Signed-off-by: Peter Zijlstra (Intel) peterz@infradead.org Cc: Alexander Shishkin alexander.shishkin@linux.intel.com Cc: Arnaldo Carvalho de Melo acme@redhat.com Cc: Jiri Olsa jolsa@redhat.com Cc: Linus Torvalds torvalds@linux-foundation.org Cc: Mark Rutland mark.rutland@arm.com Cc: Namhyung Kim namhyung@kernel.org Cc: Stephane Eranian eranian@google.com Cc: Thomas Gleixner tglx@linutronix.de Cc: Vince Weaver vincent.weaver@maine.edu Cc: linux-drivers-review@eclists.intel.com Cc: linux-perf@eclists.intel.com Fixes: 087bfbb03269 ("perf/x86: Add generic Intel uncore PMU support") Link: https://lkml.kernel.org/r/1572014593-31591-1-git-send-email-kan.liang@linux.... Signed-off-by: Ingo Molnar mingo@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- arch/x86/events/intel/uncore.c | 44 +++++++++++++++++++++++++++++----- arch/x86/events/intel/uncore.h | 12 ---------- 2 files changed, 38 insertions(+), 18 deletions(-)
diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index 2690135bf83f0..7098b9b05d566 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -485,10 +485,8 @@ void uncore_pmu_event_start(struct perf_event *event, int flags) local64_set(&event->hw.prev_count, uncore_read_counter(box, event)); uncore_enable_event(box, event);
- if (box->n_active == 1) { - uncore_enable_box(box); + if (box->n_active == 1) uncore_pmu_start_hrtimer(box); - } }
void uncore_pmu_event_stop(struct perf_event *event, int flags) @@ -512,10 +510,8 @@ void uncore_pmu_event_stop(struct perf_event *event, int flags) WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); hwc->state |= PERF_HES_STOPPED;
- if (box->n_active == 0) { - uncore_disable_box(box); + if (box->n_active == 0) uncore_pmu_cancel_hrtimer(box); - } }
if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { @@ -769,6 +765,40 @@ static int uncore_pmu_event_init(struct perf_event *event) return ret; }
+static void uncore_pmu_enable(struct pmu *pmu) +{ + struct intel_uncore_pmu *uncore_pmu; + struct intel_uncore_box *box; + + uncore_pmu = container_of(pmu, struct intel_uncore_pmu, pmu); + if (!uncore_pmu) + return; + + box = uncore_pmu_to_box(uncore_pmu, smp_processor_id()); + if (!box) + return; + + if (uncore_pmu->type->ops->enable_box) + uncore_pmu->type->ops->enable_box(box); +} + +static void uncore_pmu_disable(struct pmu *pmu) +{ + struct intel_uncore_pmu *uncore_pmu; + struct intel_uncore_box *box; + + uncore_pmu = container_of(pmu, struct intel_uncore_pmu, pmu); + if (!uncore_pmu) + return; + + box = uncore_pmu_to_box(uncore_pmu, smp_processor_id()); + if (!box) + return; + + if (uncore_pmu->type->ops->disable_box) + uncore_pmu->type->ops->disable_box(box); +} + static ssize_t uncore_get_attr_cpumask(struct device *dev, struct device_attribute *attr, char *buf) { @@ -794,6 +824,8 @@ static int uncore_pmu_register(struct intel_uncore_pmu *pmu) pmu->pmu = (struct pmu) { .attr_groups = pmu->type->attr_groups, .task_ctx_nr = perf_invalid_context, + .pmu_enable = uncore_pmu_enable, + .pmu_disable = uncore_pmu_disable, .event_init = uncore_pmu_event_init, .add = uncore_pmu_event_add, .del = uncore_pmu_event_del, diff --git a/arch/x86/events/intel/uncore.h b/arch/x86/events/intel/uncore.h index 42fa3974c421c..40e040ec31b50 100644 --- a/arch/x86/events/intel/uncore.h +++ b/arch/x86/events/intel/uncore.h @@ -412,18 +412,6 @@ static inline int uncore_freerunning_hw_config(struct intel_uncore_box *box, return -EINVAL; }
-static inline void uncore_disable_box(struct intel_uncore_box *box) -{ - if (box->pmu->type->ops->disable_box) - box->pmu->type->ops->disable_box(box); -} - -static inline void uncore_enable_box(struct intel_uncore_box *box) -{ - if (box->pmu->type->ops->enable_box) - box->pmu->type->ops->enable_box(box); -} - static inline void uncore_disable_event(struct intel_uncore_box *box, struct perf_event *event) {
Hi!
return ret; } +static void uncore_pmu_enable(struct pmu *pmu) +{
- struct intel_uncore_pmu *uncore_pmu;
- struct intel_uncore_box *box;
- uncore_pmu = container_of(pmu, struct intel_uncore_pmu, pmu);
- if (!uncore_pmu)
return;
AFAICT this test can never trigger.
+static void uncore_pmu_disable(struct pmu *pmu) +{
- struct intel_uncore_pmu *uncore_pmu;
- struct intel_uncore_box *box;
- uncore_pmu = container_of(pmu, struct intel_uncore_pmu, pmu);
- if (!uncore_pmu)
return;
And neither can this one.
Best regards, Pavel
On 11/13/2019 5:35 AM, Pavel Machek wrote:
Hi!
return ret; } +static void uncore_pmu_enable(struct pmu *pmu) +{
- struct intel_uncore_pmu *uncore_pmu;
- struct intel_uncore_box *box;
- uncore_pmu = container_of(pmu, struct intel_uncore_pmu, pmu);
- if (!uncore_pmu)
return;
AFAICT this test can never trigger.
+static void uncore_pmu_disable(struct pmu *pmu) +{
- struct intel_uncore_pmu *uncore_pmu;
- struct intel_uncore_box *box;
- uncore_pmu = container_of(pmu, struct intel_uncore_pmu, pmu);
- if (!uncore_pmu)
return;
And neither can this one.
I will submit a patch to fix it.
Thanks, Kan
From: Alan Stern stern@rowland.harvard.edu
[ Upstream commit d482c7bb0541d19dea8bff437a9f3c5563b5b2d2 ]
Endpoints with a maxpacket length of 0 are probably useless. They can't transfer any data, and it's not at all unlikely that an HCD will crash or hang when trying to handle an URB for such an endpoint.
Currently the USB core does not check for endpoints having a maxpacket value of 0. This patch adds a check, printing a warning and skipping over any endpoints it catches.
Now, the USB spec does not rule out endpoints having maxpacket = 0. But since they wouldn't have any practical use, there doesn't seem to be any good reason for us to accept them.
Signed-off-by: Alan Stern stern@rowland.harvard.edu
Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1910281050420.1485-100000@iolanthe... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/usb/core/config.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 921ad6998dec7..1eb72be75fb7b 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -348,6 +348,11 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
/* Validate the wMaxPacketSize field */ maxp = usb_endpoint_maxp(&endpoint->desc); + if (maxp == 0) { + dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has wMaxPacketSize 0, skipping\n", + cfgno, inum, asnum, d->bEndpointAddress); + goto skip_to_next_endpoint_or_interface_descriptor; + }
/* Find the highest legal maxpacket size for this endpoint */ i = 0; /* additional transactions per microframe */
From: Johan Hovold johan@kernel.org
[ Upstream commit 88f6bf3846ee90bf33aa1ce848cd3bfb3229f4a4 ]
A recent info-leak bug manifested itself along with warning about a negative buffer overflow:
ldusb 1-1:0.28: Read buffer overflow, -131383859965943 bytes dropped
when it was really a rather large positive one.
A sanity check that prevents this has now been put in place, but let's fix up the size format specifiers, which should all be unsigned.
Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20191022143203.5260-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/usb/misc/ldusb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 320b06e0724b1..67c1b8f5d54d6 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -487,7 +487,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, } bytes_to_read = min(count, *actual_buffer); if (bytes_to_read < *actual_buffer) - dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n", + dev_warn(&dev->intf->dev, "Read buffer overflow, %zu bytes dropped\n", *actual_buffer-bytes_to_read);
/* copy one interrupt_in_buffer from ring_buffer into userspace */ @@ -562,8 +562,9 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, /* write the data into interrupt_out_buffer from userspace */ bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size); if (bytes_to_write < count) - dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n", count-bytes_to_write); - dev_dbg(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", + dev_warn(&dev->intf->dev, "Write buffer overflow, %zu bytes dropped\n", + count - bytes_to_write); + dev_dbg(&dev->intf->dev, "%s: count = %zu, bytes_to_write = %zu\n", __func__, count, bytes_to_write);
if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
From: GwanYeong Kim gy741.kim@gmail.com
[ Upstream commit 28df0642abbf6d66908a2858922a7e4b21cdd8c2 ]
This isn't really accurate right. fread() doesn't always return 0 in error. It could return < number of elements and set errno.
Signed-off-by: GwanYeong Kim gy741.kim@gmail.com Acked-by: Shuah Khan skhan@linuxfoundation.org Link: https://lore.kernel.org/r/20191018032223.4644-1-gy741.kim@gmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- tools/usb/usbip/libsrc/usbip_device_driver.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/tools/usb/usbip/libsrc/usbip_device_driver.c b/tools/usb/usbip/libsrc/usbip_device_driver.c index ec3a0b794f159..67ae6c1557b8c 100644 --- a/tools/usb/usbip/libsrc/usbip_device_driver.c +++ b/tools/usb/usbip/libsrc/usbip_device_driver.c @@ -81,7 +81,7 @@ int read_usb_vudc_device(struct udev_device *sdev, struct usbip_usb_device *dev) FILE *fd = NULL; struct udev_device *plat; const char *speed; - int ret = 0; + size_t ret;
plat = udev_device_get_parent(sdev); path = udev_device_get_syspath(plat); @@ -91,8 +91,10 @@ int read_usb_vudc_device(struct udev_device *sdev, struct usbip_usb_device *dev) if (!fd) return -1; ret = fread((char *) &descr, sizeof(descr), 1, fd); - if (ret < 0) + if (ret != 1) { + err("Cannot read vudc device descr file: %s", strerror(errno)); goto err; + } fclose(fd);
copy_descr_attr(dev, &descr, bDeviceClass);
From: Potnuri Bharat Teja bharat@chelsio.com
[ Upstream commit d4934f45693651ea15357dd6c7c36be28b6da884 ]
_put_ep_safe() and _put_pass_ep_safe() free the skb before it is freed by process_work(). fix double free by freeing the skb only in process_work().
Fixes: 1dad0ebeea1c ("iw_cxgb4: Avoid touch after free error in ARP failure handlers") Link: https://lore.kernel.org/r/1572006880-5800-1-git-send-email-bharat@chelsio.co... Signed-off-by: Dakshaja Uppalapati dakshaja@chelsio.com Signed-off-by: Potnuri Bharat Teja bharat@chelsio.com Reviewed-by: Jason Gunthorpe jgg@mellanox.com Signed-off-by: Jason Gunthorpe jgg@mellanox.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/infiniband/hw/cxgb4/cm.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 566bfcc6add0d..a5ff1f0f2073e 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -493,7 +493,6 @@ static int _put_ep_safe(struct c4iw_dev *dev, struct sk_buff *skb)
ep = *((struct c4iw_ep **)(skb->cb + 2 * sizeof(void *))); release_ep_resources(ep); - kfree_skb(skb); return 0; }
@@ -504,7 +503,6 @@ static int _put_pass_ep_safe(struct c4iw_dev *dev, struct sk_buff *skb) ep = *((struct c4iw_ep **)(skb->cb + 2 * sizeof(void *))); c4iw_put_ep(&ep->parent_ep->com); release_ep_resources(ep); - kfree_skb(skb); return 0; }
From: Lijun Ou oulijun@huawei.com
[ Upstream commit b681a0529968d2261aa15d7a1e78801b2c06bb07 ]
eq->buf_list->buf and eq->buf_list should also be freed when eqe_hop_num is set to 0, or there will be memory leaks.
Fixes: a5073d6054f7 ("RDMA/hns: Add eq support of hip08") Link: https://lore.kernel.org/r/1572072995-11277-3-git-send-email-liweihang@hisili... Signed-off-by: Lijun Ou oulijun@huawei.com Signed-off-by: Weihang Li liweihang@hisilicon.com Signed-off-by: Jason Gunthorpe jgg@mellanox.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index a442b29e76119..cf878e1b71fc1 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -4572,9 +4572,9 @@ static void hns_roce_v2_free_eq(struct hns_roce_dev *hr_dev, return; }
- if (eq->buf_list) - dma_free_coherent(hr_dev->dev, buf_chk_sz, - eq->buf_list->buf, eq->buf_list->map); + dma_free_coherent(hr_dev->dev, buf_chk_sz, eq->buf_list->buf, + eq->buf_list->map); + kfree(eq->buf_list); }
static void hns_roce_config_eqc(struct hns_roce_dev *hr_dev,
From: Nicholas Piggin npiggin@gmail.com
[ Upstream commit d3566abb1a1e7772116e4d50fb6a58d19c9802e5 ]
In shutdown/reboot paths, the timer is not stopped:
qla2x00_shutdown pci_device_shutdown device_shutdown kernel_restart_prepare kernel_restart sys_reboot
This causes lockups (on powerpc) when firmware config space access calls are interrupted by smp_send_stop later in reboot.
Fixes: e30d1756480dc ("[SCSI] qla2xxx: Addition of shutdown callback handler.") Link: https://lore.kernel.org/r/20191024063804.14538-1-npiggin@gmail.com Signed-off-by: Nicholas Piggin npiggin@gmail.com Acked-by: Himanshu Madhani hmadhani@marvell.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/scsi/qla2xxx/qla_os.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 856a7ceb9a041..18ee614fe07f5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3496,6 +3496,10 @@ qla2x00_shutdown(struct pci_dev *pdev) qla2x00_try_to_stop_firmware(vha); }
+ /* Disable timer */ + if (vha->timer_active) + qla2x00_stop_timer(vha); + /* Turn adapter off line */ vha->flags.online = 0;
From: Anton Eidelman anton@lightbitslabs.com
[ Upstream commit af8fd0424713a2adb812d10d55e86718152cf656 ]
The following scenario results in an IO hang: 1) ctrl completes a request with NVME_SC_ANA_TRANSITION. NVME_NS_ANA_PENDING bit in ns->flags is set and ana_work is triggered. 2) ana_work: nvme_read_ana_log() tries to get the ANA log page from the ctrl. This fails because ctrl disconnects. Therefore nvme_update_ns_ana_state() is not called and NVME_NS_ANA_PENDING bit in ns->flags is not cleared. 3) ctrl reconnects: nvme_mpath_init(ctrl,...) calls nvme_read_ana_log(ctrl, groups_only=true). However, nvme_update_ana_state() does not update namespaces because nr_nsids = 0 (due to groups_only mode). 4) scan_work calls nvme_validate_ns() finds the ns and re-validates OK.
Result: The ctrl is now live but NVME_NS_ANA_PENDING bit in ns->flags is still set. Consequently ctrl will never be considered a viable path by __nvme_find_path(). IO will hang if ctrl is the only or the last path to the namespace.
More generally, while ctrl is reconnecting, its ANA state may change. And because nvme_mpath_init() requests ANA log in groups_only mode, these changes are not propagated to the existing ctrl namespaces. This may result in a mal-function or an IO hang.
Solution: nvme_mpath_init() will nvme_read_ana_log() with groups_only set to false. This will not harm the new ctrl case (no namespaces present), and will make sure the ANA state of namespaces gets updated after reconnect.
Note: Another option would be for nvme_mpath_init() to invoke nvme_parse_ana_log(..., nvme_set_ns_ana_state) for each existing namespace.
Reviewed-by: Sagi Grimberg sagi@grimberg.me Signed-off-by: Anton Eidelman anton@lightbitslabs.com Signed-off-by: Keith Busch kbusch@kernel.org Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/nvme/host/multipath.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 892ef52122329..838ee58d80cda 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -575,7 +575,7 @@ int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id) goto out; }
- error = nvme_read_ana_log(ctrl, true); + error = nvme_read_ana_log(ctrl, false); if (error) goto out_free_ana_log_buf; return 0;
From: Will Deacon will@kernel.org
[ Upstream commit 85ac30fa2e24f628e9f4f9344460f4015d33fd7d ]
In the highly unlikely event that we fail to allocate either of the "/txrx" or "/control" workqueues, we should bail cleanly rather than blindly march on with NULL queue pointer(s) installed in the 'fjes_adapter' instance.
Cc: "David S. Miller" davem@davemloft.net Reported-by: Nicolas Waisman nico@semmle.com Link: https://lore.kernel.org/lkml/CADJ_3a8WFrs5NouXNqS5WYe7rebFP+_A5CheeqAyD_p7DF... Signed-off-by: Will Deacon will@kernel.org Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/fjes/fjes_main.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index d3eae12390457..61a9843346ad7 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -1252,8 +1252,17 @@ static int fjes_probe(struct platform_device *plat_dev) adapter->open_guard = false;
adapter->txrx_wq = alloc_workqueue(DRV_NAME "/txrx", WQ_MEM_RECLAIM, 0); + if (unlikely(!adapter->txrx_wq)) { + err = -ENOMEM; + goto err_free_netdev; + } + adapter->control_wq = alloc_workqueue(DRV_NAME "/control", WQ_MEM_RECLAIM, 0); + if (unlikely(!adapter->control_wq)) { + err = -ENOMEM; + goto err_free_txrx_wq; + }
INIT_WORK(&adapter->tx_stall_task, fjes_tx_stall_task); INIT_WORK(&adapter->raise_intr_rxdata_task, @@ -1270,7 +1279,7 @@ static int fjes_probe(struct platform_device *plat_dev) hw->hw_res.irq = platform_get_irq(plat_dev, 0); err = fjes_hw_init(&adapter->hw); if (err) - goto err_free_netdev; + goto err_free_control_wq;
/* setup MAC address (02:00:00:00:00:[epid])*/ netdev->dev_addr[0] = 2; @@ -1292,6 +1301,10 @@ static int fjes_probe(struct platform_device *plat_dev)
err_hw_exit: fjes_hw_exit(&adapter->hw); +err_free_control_wq: + destroy_workqueue(adapter->control_wq); +err_free_txrx_wq: + destroy_workqueue(adapter->txrx_wq); err_free_netdev: free_netdev(netdev); err_out:
From: Jiangfeng Xiao xiaojiangfeng@huawei.com
[ Upstream commit 63a41746827cb16dc6ad0d4d761ab4e7dda7a0c3 ]
When rmmod hip04_eth.ko, we can get the following warning:
Task track: rmmod(1623)>bash(1591)>login(1581)>init(1) ------------[ cut here ]------------ WARNING: CPU: 0 PID: 1623 at kernel/irq/manage.c:1557 __free_irq+0xa4/0x2ac() Trying to free already-free IRQ 200 Modules linked in: ping(O) pramdisk(O) cpuinfo(O) rtos_snapshot(O) interrupt_ctrl(O) mtdblock mtd_blkdevrtfs nfs_acl nfs lockd grace sunrpc xt_tcpudp ipt_REJECT iptable_filter ip_tables x_tables nf_reject_ipv CPU: 0 PID: 1623 Comm: rmmod Tainted: G O 4.4.193 #1 Hardware name: Hisilicon A15 [<c020b408>] (rtos_unwind_backtrace) from [<c0206624>] (show_stack+0x10/0x14) [<c0206624>] (show_stack) from [<c03f2be4>] (dump_stack+0xa0/0xd8) [<c03f2be4>] (dump_stack) from [<c021a780>] (warn_slowpath_common+0x84/0xb0) [<c021a780>] (warn_slowpath_common) from [<c021a7e8>] (warn_slowpath_fmt+0x3c/0x68) [<c021a7e8>] (warn_slowpath_fmt) from [<c026876c>] (__free_irq+0xa4/0x2ac) [<c026876c>] (__free_irq) from [<c0268a14>] (free_irq+0x60/0x7c) [<c0268a14>] (free_irq) from [<c0469e80>] (release_nodes+0x1c4/0x1ec) [<c0469e80>] (release_nodes) from [<c0466924>] (__device_release_driver+0xa8/0x104) [<c0466924>] (__device_release_driver) from [<c0466a80>] (driver_detach+0xd0/0xf8) [<c0466a80>] (driver_detach) from [<c0465e18>] (bus_remove_driver+0x64/0x8c) [<c0465e18>] (bus_remove_driver) from [<c02935b0>] (SyS_delete_module+0x198/0x1e0) [<c02935b0>] (SyS_delete_module) from [<c0202ed0>] (__sys_trace_return+0x0/0x10) ---[ end trace bb25d6123d849b44 ]---
Currently "rmmod hip04_eth.ko" call free_irq more than once as devres_release_all and hip04_remove both call free_irq. This results in a 'Trying to free already-free IRQ' warning. To solve the problem free_irq has been moved out of hip04_remove.
Signed-off-by: Jiangfeng Xiao xiaojiangfeng@huawei.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/ethernet/hisilicon/hip04_eth.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index 2f8f03e0db81e..644ad78d00515 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -945,7 +945,6 @@ static int hip04_remove(struct platform_device *pdev)
hip04_free_ring(ndev, d); unregister_netdev(ndev); - free_irq(ndev->irq, ndev); of_node_put(priv->phy_node); cancel_work_sync(&priv->tx_timeout_task); free_netdev(ndev);
From: Vladimir Oltean olteanv@gmail.com
[ Upstream commit 1c44ce560b4de639f237b458be1729489ff44d0a ]
Background information: the driver operates the hardware in a mode where a single VLAN can be transmitted as untagged on a particular egress port. That is the "native VLAN on trunk port" use case. Its value is held in port->vid.
Consider the following command sequence (no network manager, all interfaces are down, debugging prints added by me):
$ ip link add dev br0 type bridge vlan_filtering 1 $ ip link set dev swp0 master br0
Kernel code path during last command:
br_add_slave -> ocelot_netdevice_port_event (NETDEV_CHANGEUPPER): [ 21.401901] ocelot_vlan_port_apply: port 0 vlan aware 0 pvid 0 vid 0
br_add_slave -> nbp_vlan_init -> switchdev_port_attr_set -> ocelot_port_attr_set (SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING): [ 21.413335] ocelot_vlan_port_apply: port 0 vlan aware 1 pvid 0 vid 0
br_add_slave -> nbp_vlan_init -> nbp_vlan_add -> br_switchdev_port_vlan_add -> switchdev_port_obj_add -> ocelot_port_obj_add -> ocelot_vlan_vid_add [ 21.667421] ocelot_vlan_port_apply: port 0 vlan aware 1 pvid 1 vid 1
So far so good. The bridge has replaced the driver's default pvid used in standalone mode (0) with its own default_pvid (1). The port's vid (native VLAN) has also changed from 0 to 1.
$ ip link set dev swp0 up
[ 31.722956] 8021q: adding VLAN 0 to HW filter on device swp0 do_setlink -> dev_change_flags -> vlan_vid_add -> ocelot_vlan_rx_add_vid -> ocelot_vlan_vid_add: [ 31.728700] ocelot_vlan_port_apply: port 0 vlan aware 1 pvid 1 vid 0
The 8021q module uses the .ndo_vlan_rx_add_vid API on .ndo_open to make ports be able to transmit and receive 802.1p-tagged traffic by default. This API is supposed to offload a VLAN sub-interface, which for a switch port means to add a VLAN that is not a pvid, and tagged on egress.
But the driver implementation of .ndo_vlan_rx_add_vid is wrong: it adds back vid 0 as "egress untagged". Now back to the initial paragraph: there is a single untagged VID that the driver keeps track of, and that has just changed from 1 (the pvid) to 0. So this breaks the bridge core's expectation, because it has changed vid 1 from untagged to tagged, when what the user sees is.
$ bridge vlan port vlan ids swp0 1 PVID Egress Untagged
br0 1 PVID Egress Untagged
But curiously, instead of manifesting itself as "untagged and pvid-tagged traffic gets sent as tagged on egress", the bug:
- is hidden when vlan_filtering=0 - manifests as dropped traffic when vlan_filtering=1, due to this setting:
if (port->vlan_aware && !port->vid) /* If port is vlan-aware and tagged, drop untagged and priority * tagged frames. */ val |= ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA | ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA | ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA;
which would have made sense if it weren't for this bug. The setting's intention was "this is a trunk port with no native VLAN, so don't accept untagged traffic". So the driver was never expecting to set VLAN 0 as the value of the native VLAN, 0 was just encoding for "invalid".
So the fix is to not send 802.1p traffic as untagged, because that would change the port's native vlan to 0, unbeknownst to the bridge, and trigger unexpected code paths in the driver.
Cc: Antoine Tenart antoine.tenart@bootlin.com Cc: Alexandre Belloni alexandre.belloni@bootlin.com Fixes: 7142529f1688 ("net: mscc: ocelot: add VLAN filtering") Signed-off-by: Vladimir Oltean olteanv@gmail.com Reviewed-by: Florian Fainelli f.fainelli@gmail.com Acked-by: Alexandre Belloni alexandre.belloni@bootlin.com Reviewed-by: Horatiu Vultur horatiu.vultur@microchip.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/ethernet/mscc/ocelot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index e05a59ae9a593..965f13944c76b 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -886,7 +886,7 @@ end: static int ocelot_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid) { - return ocelot_vlan_vid_add(dev, vid, false, true); + return ocelot_vlan_vid_add(dev, vid, false, false); }
static int ocelot_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
From: Vladimir Oltean olteanv@gmail.com
[ Upstream commit b9cd75e6689560140dadaed98eb4b41aad75d55d ]
The switch driver keeps a "vid" variable per port, which signifies _the_ VLAN ID that is stripped on that port's egress (aka the native VLAN on a trunk port).
That is the way the hardware is designed (mostly). The port->vid is programmed into REW:PORT:PORT_VLAN_CFG:PORT_VID and the rewriter is told to send all traffic as tagged except the one having port->vid.
There exists a possibility of finer-grained egress untagging decisions: using the VCAP IS1 engine, one rule can be added to match every VLAN-tagged frame whose VLAN should be untagged, and set POP_CNT=1 as action. However, the IS1 can hold at most 512 entries, and the VLANs are in the order of 6 * 4096.
So the code is fine for now. But this sequence of commands:
$ bridge vlan add dev swp0 vid 1 pvid untagged $ bridge vlan add dev swp0 vid 2 untagged
makes untagged and pvid-tagged traffic be sent out of swp0 as tagged with VID 1, despite user's request.
Prevent that from happening. The user should temporarily remove the existing untagged VLAN (1 in this case), add it back as tagged, and then add the new untagged VLAN (2 in this case).
Cc: Antoine Tenart antoine.tenart@bootlin.com Cc: Alexandre Belloni alexandre.belloni@bootlin.com Fixes: 7142529f1688 ("net: mscc: ocelot: add VLAN filtering") Signed-off-by: Vladimir Oltean olteanv@gmail.com Reviewed-by: Florian Fainelli f.fainelli@gmail.com Acked-by: Alexandre Belloni alexandre.belloni@bootlin.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/ethernet/mscc/ocelot.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 965f13944c76b..a29a6a618110e 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -253,8 +253,15 @@ static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, port->pvid = vid;
/* Untagged egress vlan clasification */ - if (untagged) + if (untagged && port->vid != vid) { + if (port->vid) { + dev_err(ocelot->dev, + "Port already has a native VLAN: %d\n", + port->vid); + return -EBUSY; + } port->vid = vid; + }
ocelot_vlan_port_apply(ocelot, port);
From: Takashi Iwai tiwai@suse.de
[ Upstream commit ad3e8da2d422c63c13819a53d3c5ea9312cc0b9d ]
Acer Aspire A315-41 requires the very same workaround as the existing quirk for Dell Latitude 5495. Add the new entry for that.
BugLink: https://bugzilla.suse.com/show_bug.cgi?id=1137799 Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Joerg Roedel jroedel@suse.de Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/iommu/amd_iommu_quirks.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/drivers/iommu/amd_iommu_quirks.c b/drivers/iommu/amd_iommu_quirks.c index c235f79b7a200..5120ce4fdce32 100644 --- a/drivers/iommu/amd_iommu_quirks.c +++ b/drivers/iommu/amd_iommu_quirks.c @@ -73,6 +73,19 @@ static const struct dmi_system_id ivrs_quirks[] __initconst = { }, .driver_data = (void *)&ivrs_ioapic_quirks[DELL_LATITUDE_5495], }, + { + /* + * Acer Aspire A315-41 requires the very same workaround as + * Dell Latitude 5495 + */ + .callback = ivrs_ioapic_quirk_cb, + .ident = "Acer Aspire A315-41", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire A315-41"), + }, + .driver_data = (void *)&ivrs_ioapic_quirks[DELL_LATITUDE_5495], + }, { .callback = ivrs_ioapic_quirk_cb, .ident = "Lenovo ideapad 330S-15ARR",
From: Andrey Grodzovsky andrey.grodzovsky@amd.com
[ Upstream commit 57c0f58e9f562089de5f0b60da103677d232374c ]
Use ERR_PTR to return back the error happened during amdgpu_ib_schedule.
Signed-off-by: Andrey Grodzovsky andrey.grodzovsky@amd.com Reviewed-by: Christian König christian.koenig@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index f823d4baf044d..cf582cc46d53e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -203,7 +203,7 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) struct amdgpu_ring *ring = to_amdgpu_ring(sched_job->sched); struct dma_fence *fence = NULL, *finished; struct amdgpu_job *job; - int r; + int r = 0;
job = to_amdgpu_job(sched_job); finished = &job->base.s_fence->finished; @@ -228,6 +228,8 @@ static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job) job->fence = dma_fence_get(fence);
amdgpu_job_free_resources(job); + + fence = r ? ERR_PTR(r) : fence; return fence; }
From: Michael Strauss michael.strauss@amd.com
[ Upstream commit bc2fde42e2418808dbfc04de1a6da91d7d31cf1a ]
[WHY] i2c_read is called to differentiate passive DP->HDMI and DP->DVI-D dongles The call is expected to fail in DVI-D case but pass in HDMI case Some HDMI dongles have a chance to fail as well, causing misdetection as DVI-D
[HOW] Retry i2c_read to ensure failed result is valid
Signed-off-by: Michael Strauss michael.strauss@amd.com Reviewed-by: Tony Cheng Tony.Cheng@amd.com Acked-by: Leo Li sunpeng.li@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com Signed-off-by: Sasha Levin sashal@kernel.org --- .../gpu/drm/amd/display/dc/core/dc_link_ddc.c | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index 8def0d9fa0ff0..46c9cb47a96e5 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -433,6 +433,7 @@ void dal_ddc_service_i2c_query_dp_dual_mode_adaptor( enum display_dongle_type *dongle = &sink_cap->dongle_type; uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE]; bool is_type2_dongle = false; + int retry_count = 2; struct dp_hdmi_dongle_signature_data *dongle_signature;
/* Assume we have no valid DP passive dongle connected */ @@ -445,13 +446,24 @@ void dal_ddc_service_i2c_query_dp_dual_mode_adaptor( DP_HDMI_DONGLE_ADDRESS, type2_dongle_buf, sizeof(type2_dongle_buf))) { - *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; - sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK; + /* Passive HDMI dongles can sometimes fail here without retrying*/ + while (retry_count > 0) { + if (i2c_read(ddc, + DP_HDMI_DONGLE_ADDRESS, + type2_dongle_buf, + sizeof(type2_dongle_buf))) + break; + retry_count--; + } + if (retry_count == 0) { + *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE; + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK;
- CONN_DATA_DETECT(ddc->link, type2_dongle_buf, sizeof(type2_dongle_buf), - "DP-DVI passive dongle %dMhz: ", - DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000); - return; + CONN_DATA_DETECT(ddc->link, type2_dongle_buf, sizeof(type2_dongle_buf), + "DP-DVI passive dongle %dMhz: ", + DP_ADAPTOR_DVI_MAX_TMDS_CLK / 1000); + return; + } }
/* Check if Type 2 dongle.*/
From: Haiyang Zhang haiyangz@microsoft.com
[ Upstream commit 719b85c336ed35565d0f3982269d6f684087bb00 ]
If rndis_filter_open() fails, we need to remove the rndis device created in earlier steps, before returning an error code. Otherwise, the retry of netvsc_attach() from its callers will fail and hang.
Fixes: 7b2ee50c0cd5 ("hv_netvsc: common detach logic") Signed-off-by: Haiyang Zhang haiyangz@microsoft.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/hyperv/netvsc_drv.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 6f6c0dbd91fc8..b7a71c203aa37 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -993,7 +993,7 @@ static int netvsc_attach(struct net_device *ndev, if (netif_running(ndev)) { ret = rndis_filter_open(nvdev); if (ret) - return ret; + goto err;
rdev = nvdev->extension; if (!rdev->link_state) @@ -1001,6 +1001,13 @@ static int netvsc_attach(struct net_device *ndev, }
return 0; + +err: + netif_device_detach(ndev); + + rndis_filter_device_remove(hdev, nvdev); + + return ret; }
static int netvsc_set_channels(struct net_device *net,
From: Felipe Balbi felipe.balbi@linux.intel.com
[ Upstream commit d8eca64eec7103ab1fbabc0a187dbf6acfb2af93 ]
When disabling an endpoint which has cancelled requests, we should make sure to giveback requests that are currently pending in the cancelled list, otherwise we may fall into a situation where command completion interrupt fires after endpoint has been disabled, therefore causing a splat.
Fixes: fec9095bdef4 "usb: dwc3: gadget: remove wait_end_transfer" Reported-by: Roger Quadros rogerq@ti.com Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com Link: https://lore.kernel.org/r/20191031090713.1452818-1-felipe.balbi@linux.intel.... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/usb/dwc3/gadget.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 54de732550648..8398c33d08e7c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -698,6 +698,12 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
dwc3_gadget_giveback(dep, req, -ESHUTDOWN); } + + while (!list_empty(&dep->cancelled_list)) { + req = next_request(&dep->cancelled_list); + + dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + } }
/**
From: Trond Myklebust trondmy@gmail.com
[ Upstream commit be3df3dd4c70ee020587a943a31b98a0fb4b6424 ]
If the delegation is marked as being revoked, we must not use it for cached opens.
Fixes: 869f9dfa4d6d ("NFSv4: Fix races between nfs_remove_bad_delegation() and delegation return") Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com Signed-off-by: Anna Schumaker Anna.Schumaker@Netapp.com Signed-off-by: Sasha Levin sashal@kernel.org --- fs/nfs/delegation.c | 10 ++++++++++ fs/nfs/delegation.h | 1 + fs/nfs/nfs4proc.c | 7 ++----- 3 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 825a8c52165a2..c5c3394148f72 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -54,6 +54,16 @@ nfs4_is_valid_delegation(const struct nfs_delegation *delegation, return false; }
+struct nfs_delegation *nfs4_get_valid_delegation(const struct inode *inode) +{ + struct nfs_delegation *delegation; + + delegation = rcu_dereference(NFS_I(inode)->delegation); + if (nfs4_is_valid_delegation(delegation, 0)) + return delegation; + return NULL; +} + static int nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark) { diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index c95477823fa6b..dd0f3eed3890d 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -66,6 +66,7 @@ int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, nfs4_stateid *dst, struct rpc_cred **cred); bool nfs4_refresh_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
+struct nfs_delegation *nfs4_get_valid_delegation(const struct inode *inode); void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); int nfs4_have_delegation(struct inode *inode, fmode_t flags); int nfs4_check_delegation(struct inode *inode, fmode_t flags); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 75faef7af22d3..792f8821b5d6b 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1393,8 +1393,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode, return 0; if ((delegation->type & fmode) != fmode) return 0; - if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) - return 0; switch (claim) { case NFS4_OPEN_CLAIM_NULL: case NFS4_OPEN_CLAIM_FH: @@ -1751,7 +1749,6 @@ static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmo static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) { struct nfs4_state *state = opendata->state; - struct nfs_inode *nfsi = NFS_I(state->inode); struct nfs_delegation *delegation; int open_mode = opendata->o_arg.open_flags; fmode_t fmode = opendata->o_arg.fmode; @@ -1768,7 +1765,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) } spin_unlock(&state->owner->so_lock); rcu_read_lock(); - delegation = rcu_dereference(nfsi->delegation); + delegation = nfs4_get_valid_delegation(state->inode); if (!can_open_delegated(delegation, fmode, claim)) { rcu_read_unlock(); break; @@ -2293,7 +2290,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) data->o_arg.open_flags, claim)) goto out_no_action; rcu_read_lock(); - delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); + delegation = nfs4_get_valid_delegation(data->state->inode); if (can_open_delegated(delegation, data->o_arg.fmode, claim)) goto unlock_no_action; rcu_read_unlock();
From: Chuhong Yuan hslester96@gmail.com
[ Upstream commit 4202e219edd6cc164c042e16fa327525410705ae ]
The remove misses to disable and unprepare priv->macclk like what is done when probe fails. Add the missed call in remove.
Signed-off-by: Chuhong Yuan hslester96@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/ethernet/arc/emac_rockchip.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c index 0f65768026072..a1df2ebab07f0 100644 --- a/drivers/net/ethernet/arc/emac_rockchip.c +++ b/drivers/net/ethernet/arc/emac_rockchip.c @@ -265,6 +265,9 @@ static int emac_rockchip_remove(struct platform_device *pdev) if (priv->regulator) regulator_disable(priv->regulator);
+ if (priv->soc_data->need_div_macclk) + clk_disable_unprepare(priv->macclk); + free_netdev(ndev); return err; }
From: Manfred Rudigier manfred.rudigier@omicronenergy.com
[ Upstream commit 8d5cfd7f76a2414e23c74bb8858af7540365d985 ]
At least on the i350 there is an annoying behavior that is maybe also present on 82580 devices, but was probably not noticed yet as MAS is not widely used.
If no cable is connected on both fiber/copper ports the media auto sense code will constantly swap between them as part of the watchdog task and produce many unnecessary kernel log messages.
The swap code responsible for this behavior (switching to fiber) should not be executed if the current media type is copper and there is no signal detected on the fiber port. In this case we can safely wait until the AUTOSENSE_EN bit is cleared.
Signed-off-by: Manfred Rudigier manfred.rudigier@omicronenergy.com Tested-by: Aaron Brown aaron.f.brown@intel.com Signed-off-by: Jeff Kirsher jeffrey.t.kirsher@intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/ethernet/intel/igb/igb_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index ab76a5f77cd0e..36db874f3c928 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2064,7 +2064,8 @@ static void igb_check_swap_media(struct igb_adapter *adapter) if ((hw->phy.media_type == e1000_media_type_copper) && (!(connsw & E1000_CONNSW_AUTOSENSE_EN))) { swap_now = true; - } else if (!(connsw & E1000_CONNSW_SERDESD)) { + } else if ((hw->phy.media_type != e1000_media_type_copper) && + !(connsw & E1000_CONNSW_SERDESD)) { /* copper signal takes time to appear */ if (adapter->copper_tries < 4) { adapter->copper_tries++;
From: Wenwen Wang wenwen@cs.uga.edu
[ Upstream commit 8472ba62154058b64ebb83d5f57259a352d28697 ]
In e1000_set_ringparam(), 'tx_old' and 'rx_old' are not deallocated if e1000_up() fails, leading to memory leaks. Refactor the code to fix this issue.
Signed-off-by: Wenwen Wang wenwen@cs.uga.edu Tested-by: Aaron Brown aaron.f.brown@intel.com Signed-off-by: Jeff Kirsher jeffrey.t.kirsher@intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/ethernet/intel/e1000/e1000_ethtool.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index 2569a168334cb..903b0a902cb95 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -607,6 +607,7 @@ static int e1000_set_ringparam(struct net_device *netdev, for (i = 0; i < adapter->num_rx_queues; i++) rxdr[i].count = rxdr->count;
+ err = 0; if (netif_running(adapter->netdev)) { /* Try to get new resources before deleting old */ err = e1000_setup_all_rx_resources(adapter); @@ -627,14 +628,13 @@ static int e1000_set_ringparam(struct net_device *netdev, adapter->rx_ring = rxdr; adapter->tx_ring = txdr; err = e1000_up(adapter); - if (err) - goto err_setup; } kfree(tx_old); kfree(rx_old);
clear_bit(__E1000_RESETTING, &adapter->flags); - return 0; + return err; + err_setup_tx: e1000_free_all_rx_resources(adapter); err_setup_rx: @@ -646,7 +646,6 @@ err_alloc_rx: err_alloc_tx: if (netif_running(adapter->netdev)) e1000_up(adapter); -err_setup: clear_bit(__E1000_RESETTING, &adapter->flags); return err; }
From: Andy Shevchenko andriy.shevchenko@linux.intel.com
[ Upstream commit 29c2c6aa32405dfee4a29911a51ba133edcedb0f ]
When consumer requests a pin, in order to be on the safest side, we switch it first to GPIO mode followed by immediate transition to the input state. Due to posted writes it's luckily to be a single I/O transaction.
However, if firmware or boot loader already configures the pin to the GPIO mode, user expects no glitches for the requested pin. We may check if the pin is pre-configured and leave it as is till the actual consumer toggles its state to avoid glitches.
Fixes: 7981c0015af2 ("pinctrl: intel: Add Intel Sunrisepoint pin controller and GPIO support") Depends-on: f5a26acf0162 ("pinctrl: intel: Initialize GPIO properly when used through irqchip") Cc: stable@vger.kernel.org Cc: fei.yang@intel.com Reported-by: Oliver Barta oliver.barta@aptiv.com Reported-by: Malin Jonsson malin.jonsson@ericsson.com Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Signed-off-by: Mika Westerberg mika.westerberg@linux.intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/pinctrl/intel/pinctrl-intel.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 1ea3438ea67e9..89ff2795a8b55 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -49,6 +49,7 @@ #define PADCFG0_GPIROUTNMI BIT(17) #define PADCFG0_PMODE_SHIFT 10 #define PADCFG0_PMODE_MASK (0xf << PADCFG0_PMODE_SHIFT) +#define PADCFG0_PMODE_GPIO 0 #define PADCFG0_GPIORXDIS BIT(9) #define PADCFG0_GPIOTXDIS BIT(8) #define PADCFG0_GPIORXSTATE BIT(1) @@ -301,7 +302,7 @@ static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, cfg1 = readl(intel_get_padcfg(pctrl, pin, PADCFG1));
mode = (cfg0 & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; - if (!mode) + if (mode == PADCFG0_PMODE_GPIO) seq_puts(s, "GPIO "); else seq_printf(s, "mode %d ", mode); @@ -422,6 +423,11 @@ static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input) writel(value, padcfg0); }
+static int intel_gpio_get_gpio_mode(void __iomem *padcfg0) +{ + return (readl(padcfg0) & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT; +} + static void intel_gpio_set_gpio_mode(void __iomem *padcfg0) { u32 value; @@ -450,7 +456,20 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, }
padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); + + /* + * If pin is already configured in GPIO mode, we assume that + * firmware provides correct settings. In such case we avoid + * potential glitches on the pin. Otherwise, for the pin in + * alternative mode, consumer has to supply respective flags. + */ + if (intel_gpio_get_gpio_mode(padcfg0) == PADCFG0_PMODE_GPIO) { + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + return 0; + } + intel_gpio_set_gpio_mode(padcfg0); + /* Disable TX buffer and enable RX (this will be input) */ __intel_gpio_set_direction(padcfg0, true);
From: Shuning Zhang sunny.s.zhang@oracle.com
[ Upstream commit e74540b285569d2b1e14fe7aee92297078f235ce ]
When the extent tree is modified, it should be protected by inode cluster lock and ip_alloc_sem.
The extent tree is accessed and modified in the ocfs2_prepare_inode_for_write, but isn't protected by ip_alloc_sem.
The following is a case. The function ocfs2_fiemap is accessing the extent tree, which is modified at the same time.
kernel BUG at fs/ocfs2/extent_map.c:475! invalid opcode: 0000 [#1] SMP Modules linked in: tun ocfs2 ocfs2_nodemanager configfs ocfs2_stackglue [...] CPU: 16 PID: 14047 Comm: o2info Not tainted 4.1.12-124.23.1.el6uek.x86_64 #2 Hardware name: Oracle Corporation ORACLE SERVER X7-2L/ASM, MB MECH, X7-2L, BIOS 42040600 10/19/2018 task: ffff88019487e200 ti: ffff88003daa4000 task.ti: ffff88003daa4000 RIP: ocfs2_get_clusters_nocache.isra.11+0x390/0x550 [ocfs2] Call Trace: ocfs2_fiemap+0x1e3/0x430 [ocfs2] do_vfs_ioctl+0x155/0x510 SyS_ioctl+0x81/0xa0 system_call_fastpath+0x18/0xd8 Code: 18 48 c7 c6 60 7f 65 a0 31 c0 bb e2 ff ff ff 48 8b 4a 40 48 8b 7a 28 48 c7 c2 78 2d 66 a0 e8 38 4f 05 00 e9 28 fe ff ff 0f 1f 00 <0f> 0b 66 0f 1f 44 00 00 bb 86 ff ff ff e9 13 fe ff ff 66 0f 1f RIP ocfs2_get_clusters_nocache.isra.11+0x390/0x550 [ocfs2] ---[ end trace c8aa0c8180e869dc ]--- Kernel panic - not syncing: Fatal exception Kernel Offset: disabled
This issue can be reproduced every week in a production environment.
This issue is related to the usage mode. If others use ocfs2 in this mode, the kernel will panic frequently.
[akpm@linux-foundation.org: coding style fixes] [Fix new warning due to unused function by removing said function - Linus ] Link: http://lkml.kernel.org/r/1568772175-2906-2-git-send-email-sunny.s.zhang@orac... Signed-off-by: Shuning Zhang sunny.s.zhang@oracle.com Reviewed-by: Junxiao Bi junxiao.bi@oracle.com Reviewed-by: Gang He ghe@suse.com Cc: Mark Fasheh mark@fasheh.com Cc: Joel Becker jlbec@evilplan.org Cc: Joseph Qi jiangqi903@gmail.com Cc: Changwei Ge gechangwei@live.cn Cc: Jun Piao piaojun@huawei.com Cc: stable@vger.kernel.org Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- fs/ocfs2/file.c | 134 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 90 insertions(+), 44 deletions(-)
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 9fa35cb6f6e0b..a847fe52c56ee 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2106,54 +2106,90 @@ static int ocfs2_is_io_unaligned(struct inode *inode, size_t count, loff_t pos) return 0; }
-static int ocfs2_prepare_inode_for_refcount(struct inode *inode, - struct file *file, - loff_t pos, size_t count, - int *meta_level) +static int ocfs2_inode_lock_for_extent_tree(struct inode *inode, + struct buffer_head **di_bh, + int meta_level, + int overwrite_io, + int write_sem, + int wait) { - int ret; - struct buffer_head *di_bh = NULL; - u32 cpos = pos >> OCFS2_SB(inode->i_sb)->s_clustersize_bits; - u32 clusters = - ocfs2_clusters_for_bytes(inode->i_sb, pos + count) - cpos; + int ret = 0;
- ret = ocfs2_inode_lock(inode, &di_bh, 1); - if (ret) { - mlog_errno(ret); + if (wait) + ret = ocfs2_inode_lock(inode, NULL, meta_level); + else + ret = ocfs2_try_inode_lock(inode, + overwrite_io ? NULL : di_bh, meta_level); + if (ret < 0) goto out; + + if (wait) { + if (write_sem) + down_write(&OCFS2_I(inode)->ip_alloc_sem); + else + down_read(&OCFS2_I(inode)->ip_alloc_sem); + } else { + if (write_sem) + ret = down_write_trylock(&OCFS2_I(inode)->ip_alloc_sem); + else + ret = down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem); + + if (!ret) { + ret = -EAGAIN; + goto out_unlock; + } }
- *meta_level = 1; + return ret;
- ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX); - if (ret) - mlog_errno(ret); +out_unlock: + brelse(*di_bh); + ocfs2_inode_unlock(inode, meta_level); out: - brelse(di_bh); return ret; }
+static void ocfs2_inode_unlock_for_extent_tree(struct inode *inode, + struct buffer_head **di_bh, + int meta_level, + int write_sem) +{ + if (write_sem) + up_write(&OCFS2_I(inode)->ip_alloc_sem); + else + up_read(&OCFS2_I(inode)->ip_alloc_sem); + + brelse(*di_bh); + *di_bh = NULL; + + if (meta_level >= 0) + ocfs2_inode_unlock(inode, meta_level); +} + static int ocfs2_prepare_inode_for_write(struct file *file, loff_t pos, size_t count, int wait) { int ret = 0, meta_level = 0, overwrite_io = 0; + int write_sem = 0; struct dentry *dentry = file->f_path.dentry; struct inode *inode = d_inode(dentry); struct buffer_head *di_bh = NULL; loff_t end; + u32 cpos; + u32 clusters;
/* * We start with a read level meta lock and only jump to an ex * if we need to make modifications here. */ for(;;) { - if (wait) - ret = ocfs2_inode_lock(inode, NULL, meta_level); - else - ret = ocfs2_try_inode_lock(inode, - overwrite_io ? NULL : &di_bh, meta_level); + ret = ocfs2_inode_lock_for_extent_tree(inode, + &di_bh, + meta_level, + overwrite_io, + write_sem, + wait); if (ret < 0) { - meta_level = -1; if (ret != -EAGAIN) mlog_errno(ret); goto out; @@ -2165,15 +2201,8 @@ static int ocfs2_prepare_inode_for_write(struct file *file, */ if (!wait && !overwrite_io) { overwrite_io = 1; - if (!down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem)) { - ret = -EAGAIN; - goto out_unlock; - }
ret = ocfs2_overwrite_io(inode, di_bh, pos, count); - brelse(di_bh); - di_bh = NULL; - up_read(&OCFS2_I(inode)->ip_alloc_sem); if (ret < 0) { if (ret != -EAGAIN) mlog_errno(ret); @@ -2192,7 +2221,10 @@ static int ocfs2_prepare_inode_for_write(struct file *file, * set inode->i_size at the end of a write. */ if (should_remove_suid(dentry)) { if (meta_level == 0) { - ocfs2_inode_unlock(inode, meta_level); + ocfs2_inode_unlock_for_extent_tree(inode, + &di_bh, + meta_level, + write_sem); meta_level = 1; continue; } @@ -2208,18 +2240,32 @@ static int ocfs2_prepare_inode_for_write(struct file *file,
ret = ocfs2_check_range_for_refcount(inode, pos, count); if (ret == 1) { - ocfs2_inode_unlock(inode, meta_level); - meta_level = -1; - - ret = ocfs2_prepare_inode_for_refcount(inode, - file, - pos, - count, - &meta_level); + ocfs2_inode_unlock_for_extent_tree(inode, + &di_bh, + meta_level, + write_sem); + ret = ocfs2_inode_lock_for_extent_tree(inode, + &di_bh, + meta_level, + overwrite_io, + 1, + wait); + write_sem = 1; + if (ret < 0) { + if (ret != -EAGAIN) + mlog_errno(ret); + goto out; + } + + cpos = pos >> OCFS2_SB(inode->i_sb)->s_clustersize_bits; + clusters = + ocfs2_clusters_for_bytes(inode->i_sb, pos + count) - cpos; + ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX); }
if (ret < 0) { - mlog_errno(ret); + if (ret != -EAGAIN) + mlog_errno(ret); goto out_unlock; }
@@ -2230,10 +2276,10 @@ out_unlock: trace_ocfs2_prepare_inode_for_write(OCFS2_I(inode)->ip_blkno, pos, count, wait);
- brelse(di_bh); - - if (meta_level >= 0) - ocfs2_inode_unlock(inode, meta_level); + ocfs2_inode_unlock_for_extent_tree(inode, + &di_bh, + meta_level, + write_sem);
out: return ret;
From: Hans de Goede hdegoede@redhat.com
[ Upstream commit 63bdef6cd6941917c823b9cc9aa0219d19fcb716 ]
Commit 03c4749dd6c7 ("gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation") has made the cherryview gpio numbers sparse, to get a 1:1 mapping between ACPI pin numbers and gpio numbers in Linux.
This has greatly simplified things, but the code setting the irq_valid_mask was not updated for this, so the valid mask is still in the old "compressed" numbering with the gaps in the pin numbers skipped, which is wrong as irq_valid_mask needs to be expressed in gpio numbers.
This results in the following error on devices using pin 24 (0x0018) on the north GPIO controller as an ACPI event source:
[ 0.422452] cherryview-pinctrl INT33FF:01: Failed to translate GPIO to IRQ
This has been reported (by email) to be happening on a Caterpillar CAT T20 tablet and I've reproduced this myself on a Medion Akoya e2215t 2-in-1.
This commit uses the pin number instead of the compressed index into community->pins to clear the correct bits in irq_valid_mask for GPIOs using GPEs for interrupts, fixing these errors and in case of the Medion Akoya e2215t also fixing the LID switch not working.
Cc: stable@vger.kernel.org Fixes: 03c4749dd6c7 ("gpio / ACPI: Drop unnecessary ACPI GPIO to Linux GPIO translation") Signed-off-by: Hans de Goede hdegoede@redhat.com Reviewed-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Signed-off-by: Mika Westerberg mika.westerberg@linux.intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/pinctrl/intel/pinctrl-cherryview.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index 227646eb817c8..9eab508395814 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1595,7 +1595,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq) intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
if (need_valid_mask && intsel >= community->nirqs) - clear_bit(i, chip->irq.valid_mask); + clear_bit(desc->number, chip->irq.valid_mask); }
/*
From: Tejun Heo tj@kernel.org
[ Upstream commit b0814361a25cba73a224548843ed92d8ea78715a ]
blkcg_print_stat() iterates blkgs under RCU and doesn't test whether the blkg is online. This can call into pd_stat_fn() on a pd which is still being initialized leading to an oops.
The heaviest operation - recursively summing up rwstat counters - is already done while holding the queue_lock. Expand queue_lock to cover the other operations and skip the blkg if it isn't online yet. The online state is protected by both blkcg and queue locks, so this guarantees that only online blkgs are processed.
Signed-off-by: Tejun Heo tj@kernel.org Reported-by: Roman Gushchin guro@fb.com Cc: Josef Bacik jbacik@fb.com Fixes: 903d23f0a354 ("blk-cgroup: allow controllers to output their own stats") Cc: stable@vger.kernel.org # v4.19+ Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org --- block/blk-cgroup.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 5275241346930..a06547fe6f6b4 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -955,9 +955,14 @@ static int blkcg_print_stat(struct seq_file *sf, void *v) int i; bool has_stats = false;
+ spin_lock_irq(blkg->q->queue_lock); + + if (!blkg->online) + goto skip; + dname = blkg_dev_name(blkg); if (!dname) - continue; + goto skip;
/* * Hooray string manipulation, count is the size written NOT @@ -967,8 +972,6 @@ static int blkcg_print_stat(struct seq_file *sf, void *v) */ off += scnprintf(buf+off, size-off, "%s ", dname);
- spin_lock_irq(blkg->q->queue_lock); - rwstat = blkg_rwstat_recursive_sum(blkg, NULL, offsetof(struct blkcg_gq, stat_bytes)); rbytes = atomic64_read(&rwstat.aux_cnt[BLKG_RWSTAT_READ]); @@ -981,8 +984,6 @@ static int blkcg_print_stat(struct seq_file *sf, void *v) wios = atomic64_read(&rwstat.aux_cnt[BLKG_RWSTAT_WRITE]); dios = atomic64_read(&rwstat.aux_cnt[BLKG_RWSTAT_DISCARD]);
- spin_unlock_irq(blkg->q->queue_lock); - if (rbytes || wbytes || rios || wios) { has_stats = true; off += scnprintf(buf+off, size-off, @@ -1023,6 +1024,8 @@ next: seq_commit(sf, -1); } } + skip: + spin_unlock_irq(blkg->q->queue_lock); }
rcu_read_unlock();
From: Randolph Maaßen gaireg@gaireg.de
[ Upstream commit 22904bdff97839960bd98b3452a583b1daee628b ]
The Invensense ICM-20602 is a 6-axis MotionTracking device that combines a 3-axis gyroscope and an 3-axis accelerometer. It is very similar to the ICM-20608 imu which is already supported by the mpu6050 driver. The main difference is that the ICM-20602 has the i2c bus disable bit in a separate register.
Signed-off-by: Randolph Maaßen gaireg@gaireg.de Signed-off-by: Jonathan Cameron Jonathan.Cameron@huawei.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/iio/imu/inv_mpu6050/Kconfig | 8 +++--- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 31 ++++++++++++++++++++++ drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 6 +++++ drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 8 ++++++ drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c | 12 ++++++--- 5 files changed, 58 insertions(+), 7 deletions(-)
diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig index 5483b2ea754dd..d2fe9dbddda74 100644 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -13,8 +13,8 @@ config INV_MPU6050_I2C select INV_MPU6050_IIO select REGMAP_I2C help - This driver supports the Invensense MPU6050/6500/9150 and ICM20608 - motion tracking devices over I2C. + This driver supports the Invensense MPU6050/6500/9150 and + ICM20608/20602 motion tracking devices over I2C. This driver can be built as a module. The module will be called inv-mpu6050-i2c.
@@ -24,7 +24,7 @@ config INV_MPU6050_SPI select INV_MPU6050_IIO select REGMAP_SPI help - This driver supports the Invensense MPU6050/6500/9150 and ICM20608 - motion tracking devices over SPI. + This driver supports the Invensense MPU6050/6500/9150 and + ICM20608/20602 motion tracking devices over SPI. This driver can be built as a module. The module will be called inv-mpu6050-spi. diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index d80ef468508a1..cb80c9e49fc7b 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -37,6 +37,29 @@ static const int gyro_scale_6050[] = {133090, 266181, 532362, 1064724}; */ static const int accel_scale[] = {598, 1196, 2392, 4785};
+static const struct inv_mpu6050_reg_map reg_set_icm20602 = { + .sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV, + .lpf = INV_MPU6050_REG_CONFIG, + .accel_lpf = INV_MPU6500_REG_ACCEL_CONFIG_2, + .user_ctrl = INV_MPU6050_REG_USER_CTRL, + .fifo_en = INV_MPU6050_REG_FIFO_EN, + .gyro_config = INV_MPU6050_REG_GYRO_CONFIG, + .accl_config = INV_MPU6050_REG_ACCEL_CONFIG, + .fifo_count_h = INV_MPU6050_REG_FIFO_COUNT_H, + .fifo_r_w = INV_MPU6050_REG_FIFO_R_W, + .raw_gyro = INV_MPU6050_REG_RAW_GYRO, + .raw_accl = INV_MPU6050_REG_RAW_ACCEL, + .temperature = INV_MPU6050_REG_TEMPERATURE, + .int_enable = INV_MPU6050_REG_INT_ENABLE, + .int_status = INV_MPU6050_REG_INT_STATUS, + .pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1, + .pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2, + .int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG, + .accl_offset = INV_MPU6500_REG_ACCEL_OFFSET, + .gyro_offset = INV_MPU6050_REG_GYRO_OFFSET, + .i2c_if = INV_ICM20602_REG_I2C_IF, +}; + static const struct inv_mpu6050_reg_map reg_set_6500 = { .sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV, .lpf = INV_MPU6050_REG_CONFIG, @@ -57,6 +80,7 @@ static const struct inv_mpu6050_reg_map reg_set_6500 = { .int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG, .accl_offset = INV_MPU6500_REG_ACCEL_OFFSET, .gyro_offset = INV_MPU6050_REG_GYRO_OFFSET, + .i2c_if = 0, };
static const struct inv_mpu6050_reg_map reg_set_6050 = { @@ -77,6 +101,7 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = { .int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG, .accl_offset = INV_MPU6050_REG_ACCEL_OFFSET, .gyro_offset = INV_MPU6050_REG_GYRO_OFFSET, + .i2c_if = 0, };
static const struct inv_mpu6050_chip_config chip_config_6050 = { @@ -139,6 +164,12 @@ static const struct inv_mpu6050_hw hw_info[] = { .reg = ®_set_6500, .config = &chip_config_6050, }, + { + .whoami = INV_ICM20602_WHOAMI_VALUE, + .name = "ICM20602", + .reg = ®_set_icm20602, + .config = &chip_config_6050, + }, };
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index dd758e3d403da..e46eb4ddea210 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -127,6 +127,7 @@ static int inv_mpu_probe(struct i2c_client *client, st = iio_priv(dev_get_drvdata(&client->dev)); switch (st->chip_type) { case INV_ICM20608: + case INV_ICM20602: /* no i2c auxiliary bus on the chip */ break; default: @@ -179,6 +180,7 @@ static const struct i2c_device_id inv_mpu_id[] = { {"mpu9250", INV_MPU9250}, {"mpu9255", INV_MPU9255}, {"icm20608", INV_ICM20608}, + {"icm20602", INV_ICM20602}, {} };
@@ -213,6 +215,10 @@ static const struct of_device_id inv_of_match[] = { .compatible = "invensense,icm20608", .data = (void *)INV_ICM20608 }, + { + .compatible = "invensense,icm20602", + .data = (void *)INV_ICM20602 + }, { } }; MODULE_DEVICE_TABLE(of, inv_of_match); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index e69a59659dbcf..bdbaf6e01ce3e 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -44,6 +44,7 @@ * @int_pin_cfg; Controls interrupt pin configuration. * @accl_offset: Controls the accelerometer calibration offset. * @gyro_offset: Controls the gyroscope calibration offset. + * @i2c_if: Controls the i2c interface */ struct inv_mpu6050_reg_map { u8 sample_rate_div; @@ -65,6 +66,7 @@ struct inv_mpu6050_reg_map { u8 int_pin_cfg; u8 accl_offset; u8 gyro_offset; + u8 i2c_if; };
/*device enum */ @@ -77,6 +79,7 @@ enum inv_devices { INV_MPU9250, INV_MPU9255, INV_ICM20608, + INV_ICM20602, INV_NUM_PARTS };
@@ -193,6 +196,10 @@ struct inv_mpu6050_state { #define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38 #define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07
+/* ICM20602 register */ +#define INV_ICM20602_REG_I2C_IF 0x70 +#define INV_ICM20602_BIT_I2C_IF_DIS 0x40 + #define INV_MPU6050_REG_FIFO_COUNT_H 0x72 #define INV_MPU6050_REG_FIFO_R_W 0x74
@@ -259,6 +266,7 @@ struct inv_mpu6050_state { #define INV_MPU9255_WHOAMI_VALUE 0x73 #define INV_MPU6515_WHOAMI_VALUE 0x74 #define INV_ICM20608_WHOAMI_VALUE 0xAF +#define INV_ICM20602_WHOAMI_VALUE 0x12
/* scan element definition */ enum inv_mpu6050_scan { diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 227f50afff22f..a112c3f45f748 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -31,9 +31,14 @@ static int inv_mpu_i2c_disable(struct iio_dev *indio_dev) if (ret) return ret;
- st->chip_config.user_ctrl |= INV_MPU6050_BIT_I2C_IF_DIS; - ret = regmap_write(st->map, st->reg->user_ctrl, - st->chip_config.user_ctrl); + if (st->reg->i2c_if) { + ret = regmap_write(st->map, st->reg->i2c_if, + INV_ICM20602_BIT_I2C_IF_DIS); + } else { + st->chip_config.user_ctrl |= INV_MPU6050_BIT_I2C_IF_DIS; + ret = regmap_write(st->map, st->reg->user_ctrl, + st->chip_config.user_ctrl); + } if (ret) { inv_mpu6050_set_power_itg(st, false); return ret; @@ -81,6 +86,7 @@ static const struct spi_device_id inv_mpu_id[] = { {"mpu9250", INV_MPU9250}, {"mpu9255", INV_MPU9255}, {"icm20608", INV_ICM20608}, + {"icm20602", INV_ICM20602}, {} };
From: Jean-Baptiste Maneyrol JManeyrol@invensense.com
[ Upstream commit 6e82ae6b8d11b948b74e71396efd8e074c415f44 ]
Some chips have a fifo overflow bit issue where the bit is always set. The result is that every data is dropped.
Change fifo overflow management by checking fifo count against a maximum value.
Add fifo size in chip hardware set of values.
Fixes: f5057e7b2dba ("iio: imu: inv_mpu6050: better fifo overflow handling") Cc: stable@vger.kernel.org Signed-off-by: Jean-Baptiste Maneyrol jmaneyrol@invensense.com Signed-off-by: Jonathan Cameron Jonathan.Cameron@huawei.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 9 +++++++++ drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 2 ++ drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 15 ++++++++++++--- 3 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index cb80c9e49fc7b..ea099523e0355 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -121,54 +121,63 @@ static const struct inv_mpu6050_hw hw_info[] = { .name = "MPU6050", .reg = ®_set_6050, .config = &chip_config_6050, + .fifo_size = 1024, }, { .whoami = INV_MPU6500_WHOAMI_VALUE, .name = "MPU6500", .reg = ®_set_6500, .config = &chip_config_6050, + .fifo_size = 512, }, { .whoami = INV_MPU6515_WHOAMI_VALUE, .name = "MPU6515", .reg = ®_set_6500, .config = &chip_config_6050, + .fifo_size = 512, }, { .whoami = INV_MPU6000_WHOAMI_VALUE, .name = "MPU6000", .reg = ®_set_6050, .config = &chip_config_6050, + .fifo_size = 1024, }, { .whoami = INV_MPU9150_WHOAMI_VALUE, .name = "MPU9150", .reg = ®_set_6050, .config = &chip_config_6050, + .fifo_size = 1024, }, { .whoami = INV_MPU9250_WHOAMI_VALUE, .name = "MPU9250", .reg = ®_set_6500, .config = &chip_config_6050, + .fifo_size = 512, }, { .whoami = INV_MPU9255_WHOAMI_VALUE, .name = "MPU9255", .reg = ®_set_6500, .config = &chip_config_6050, + .fifo_size = 512, }, { .whoami = INV_ICM20608_WHOAMI_VALUE, .name = "ICM20608", .reg = ®_set_6500, .config = &chip_config_6050, + .fifo_size = 512, }, { .whoami = INV_ICM20602_WHOAMI_VALUE, .name = "ICM20602", .reg = ®_set_icm20602, .config = &chip_config_6050, + .fifo_size = 1008, }, };
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index bdbaf6e01ce3e..e56c1d191ae46 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -108,12 +108,14 @@ struct inv_mpu6050_chip_config { * @name: name of the chip. * @reg: register map of the chip. * @config: configuration of the chip. + * @fifo_size: size of the FIFO in bytes. */ struct inv_mpu6050_hw { u8 whoami; u8 *name; const struct inv_mpu6050_reg_map *reg; const struct inv_mpu6050_chip_config *config; + size_t fifo_size; };
/* diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index 548e042f7b5bd..4f9c2765aa23f 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -188,9 +188,6 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) "failed to ack interrupt\n"); goto flush_fifo; } - /* handle fifo overflow by reseting fifo */ - if (int_status & INV_MPU6050_BIT_FIFO_OVERFLOW_INT) - goto flush_fifo; if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT)) { dev_warn(regmap_get_device(st->map), "spurious interrupt with status 0x%x\n", int_status); @@ -216,6 +213,18 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) if (result) goto end_session; fifo_count = get_unaligned_be16(&data[0]); + + /* + * Handle fifo overflow by resetting fifo. + * Reset if there is only 3 data set free remaining to mitigate + * possible delay between reading fifo count and fifo data. + */ + nb = 3 * bytes_per_datum; + if (fifo_count >= st->hw->fifo_size - nb) { + dev_warn(regmap_get_device(st->map), "fifo overflow reset\n"); + goto flush_fifo; + } + /* compute and process all complete datum */ nb = fifo_count / bytes_per_datum; inv_mpu6050_update_period(st, pf->timestamp, nb);
From: Konstantin Khlebnikov khlebnikov@yandex-team.ru
commit c3aab9a0bd91b696a852169479b7db1ece6cbf8c upstream.
Functions like filemap_write_and_wait_range() should do nothing if inode has no dirty pages or pages currently under writeback. But they anyway construct struct writeback_control and this does some atomic operations if CONFIG_CGROUP_WRITEBACK=y - on fast path it locks inode->i_lock and updates state of writeback ownership, on slow path might be more work. Current this path is safely avoided only when inode mapping has no pages.
For example generic_file_read_iter() calls filemap_write_and_wait_range() at each O_DIRECT read - pretty hot path.
This patch skips starting new writeback if mapping has no dirty tags set. If writeback is already in progress filemap_write_and_wait_range() will wait for it.
Link: http://lkml.kernel.org/r/156378816804.1087.8607636317907921438.stgit@buzz Signed-off-by: Konstantin Khlebnikov khlebnikov@yandex-team.ru Reviewed-by: Jan Kara jack@suse.cz Cc: Tejun Heo tj@kernel.org Cc: Jens Axboe axboe@kernel.dk Cc: Johannes Weiner hannes@cmpxchg.org Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- mm/filemap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
--- a/mm/filemap.c +++ b/mm/filemap.c @@ -438,7 +438,8 @@ int __filemap_fdatawrite_range(struct ad .range_end = end, };
- if (!mapping_cap_writeback_dirty(mapping)) + if (!mapping_cap_writeback_dirty(mapping) || + !mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) return 0;
wbc_attach_fdatawrite_inode(&wbc, mapping->host);
From: Tejun Heo tj@kernel.org
commit 65de03e251382306a4575b1779c57c87889eee49 upstream.
cgroup writeback tries to refresh the associated wb immediately if the current wb is dead. This is to avoid keeping issuing IOs on the stale wb after memcg - blkcg association has changed (ie. when blkcg got disabled / enabled higher up in the hierarchy).
Unfortunately, the logic gets triggered spuriously on inodes which are associated with dead cgroups. When the logic is triggered on dead cgroups, the attempt fails only after doing quite a bit of work allocating and initializing a new wb.
While c3aab9a0bd91 ("mm/filemap.c: don't initiate writeback if mapping has no dirty pages") alleviated the issue significantly as it now only triggers when the inode has dirty pages. However, the condition can still be triggered before the inode is switched to a different cgroup and the logic simply doesn't make sense.
Skip the immediate switching if the associated memcg is dying.
This is a simplified version of the following two patches:
* https://lore.kernel.org/linux-mm/20190513183053.GA73423@dennisz-mbp/ * http://lkml.kernel.org/r/156355839560.2063.5265687291430814589.stgit@buzz
Cc: Konstantin Khlebnikov khlebnikov@yandex-team.ru Fixes: e8a7abf5a5bd ("writeback: disassociate inodes from dying bdi_writebacks") Acked-by: Dennis Zhou dennis@kernel.org Signed-off-by: Tejun Heo tj@kernel.org Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- fs/fs-writeback.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
--- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -582,10 +582,13 @@ void wbc_attach_and_unlock_inode(struct spin_unlock(&inode->i_lock);
/* - * A dying wb indicates that the memcg-blkcg mapping has changed - * and a new wb is already serving the memcg. Switch immediately. + * A dying wb indicates that either the blkcg associated with the + * memcg changed or the associated memcg is dying. In the first + * case, a replacement wb should already be available and we should + * refresh the wb immediately. In the second case, trying to + * refresh will keep failing. */ - if (unlikely(wb_dying(wbc->wb))) + if (unlikely(wb_dying(wbc->wb) && !css_is_dying(wbc->wb->memcg_css))) inode_switch_wbs(inode, wbc->wb_id); }
stable-rc/linux-4.19.y boot: 120 boots: 0 failed, 112 passed with 8 offline (v4.19.83-126-g0f8b6b0b5b94)
Full Boot Summary: https://kernelci.org/boot/all/job/stable-rc/branch/linux-4.19.y/kernel/v4.19... Full Build Summary: https://kernelci.org/build/stable-rc/branch/linux-4.19.y/kernel/v4.19.83-126...
Tree: stable-rc Branch: linux-4.19.y Git Describe: v4.19.83-126-g0f8b6b0b5b94 Git Commit: 0f8b6b0b5b946b33f5b60e9de252afb809a17e6a Git URL: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git Tested: 68 unique boards, 22 SoC families, 14 builds out of 206
Offline Platforms:
arm:
sunxi_defconfig: gcc-8 sun5i-r8-chip: 1 offline lab sun7i-a20-bananapi: 1 offline lab
multi_v7_defconfig: gcc-8 qcom-apq8064-cm-qs600: 1 offline lab sun5i-r8-chip: 1 offline lab sun7i-a20-bananapi: 1 offline lab
davinci_all_defconfig: gcc-8 dm365evm,legacy: 1 offline lab
qcom_defconfig: gcc-8 qcom-apq8064-cm-qs600: 1 offline lab
arm64:
defconfig: gcc-8 meson-axg-s400: 1 offline lab
--- For more info write to info@kernelci.org
On Tue, 12 Nov 2019 at 00:12, Greg Kroah-Hartman gregkh@linuxfoundation.org wrote:
This is the start of the stable review cycle for the 4.19.84 release. There are 125 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 13 Nov 2019 18:08:44 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at: https://www.kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.19.84-rc1... or in the git tree and branch at: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-4.19.y and the diffstat can be found below.
thanks,
greg k-h
Results from Linaro’s test farm. No regressions on arm64, arm, x86_64, and i386.
Summary ------------------------------------------------------------------------
kernel: 4.19.84-rc1 git repo: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git git branch: linux-4.19.y git commit: 0f8b6b0b5b946b33f5b60e9de252afb809a17e6a git describe: v4.19.83-126-g0f8b6b0b5b94 Test details: https://qa-reports.linaro.org/lkft/linux-stable-rc-4.19-oe/build/v4.19.83-12...
No regressions (compared to build v4.19.83-124-gb8764c8bac2d)
No fixes (compared to build v4.19.83-124-gb8764c8bac2d)
Ran 23945 total tests in the following environments and test suites.
Environments -------------- - dragonboard-410c - hi6220-hikey - i386 - juno-r2 - qemu_arm - qemu_arm64 - qemu_i386 - qemu_x86_64 - x15 - x86
Test Suites ----------- * build * install-android-platform-tools-r2600 * kselftest * libgpiod * libhugetlbfs * ltp-cap_bounds-tests * ltp-commands-tests * ltp-containers-tests * ltp-cpuhotplug-tests * ltp-cve-tests * ltp-dio-tests * ltp-fcntl-locktests-tests * ltp-filecaps-tests * ltp-fs-tests * ltp-fs_bind-tests * ltp-fs_perms_simple-tests * ltp-fsx-tests * ltp-hugetlb-tests * ltp-io-tests * ltp-ipc-tests * ltp-math-tests * ltp-mm-tests * ltp-nptl-tests * ltp-pty-tests * ltp-sched-tests * ltp-securebits-tests * ltp-syscalls-tests * perf * spectre-meltdown-checker-test * network-basic-tests * v4l2-compliance * ltp-open-posix-tests * kvm-unit-tests * ssuite * kselftest-vsyscall-mode-native * kselftest-vsyscall-mode-none
On 11/11/2019 18:27, Greg Kroah-Hartman wrote:
This is the start of the stable review cycle for the 4.19.84 release. There are 125 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 13 Nov 2019 18:08:44 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at: https://www.kernel.org/pub/linux/kernel/v4.x/stable-review/patch-4.19.84-rc1... or in the git tree and branch at: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-4.19.y and the diffstat can be found below.
thanks,
greg k-h
All tests for Tegra are passing ...
Test results for stable-v4.19: 12 builds: 12 pass, 0 fail 22 boots: 22 pass, 0 fail 32 tests: 32 pass, 0 fail
Linux version: 4.19.84-rc1-g0f8b6b0b5b94 Boards tested: tegra124-jetson-tk1, tegra186-p2771-0000, tegra194-p2972-0000, tegra20-ventana, tegra210-p2371-2180, tegra30-cardhu-a04
Cheers Jon
On Mon, Nov 11, 2019 at 07:27:19PM +0100, Greg Kroah-Hartman wrote:
This is the start of the stable review cycle for the 4.19.84 release. There are 125 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Wed, 13 Nov 2019 18:08:44 +0000. Anything received after that time might be too late.
Build results: total: 156 pass: 156 fail: 0 Qemu test results: total: 390 pass: 390 fail: 0
Guenter
linux-stable-mirror@lists.linaro.org