This is the merge of the upstream LTS release of 5.10.149 into the android12-5.10 branch. It contains the following commits:0118fb827b
Merge branch 'android12-5.10' into branch 'android12-5.10-lts'69a9a62c66
ANDROID: GKI: db845c: Update symbols list and ABI2498b03977
Merge 5.10.149 into android12-5.10-lts09be132bfe
Linux 5.10.14931ce5da48a
wifi: mac80211: fix MBSSID parsing use-after-free353b5c8d4b
wifi: mac80211: don't parse mbssid in assoc response66dacdbc2e
mac80211: mlme: find auth challenge directlya07708a843
Revert "fs: check FMODE_LSEEK to control internal pipe splicing"c1e111543d
Merge 5.10.148 into android12-5.10-lts3783e64fee
Linux 5.10.1480df206bdc6
misc: pci_endpoint_test: Fix pci_endpoint_test_{copy,write,read}() panic40a29e58f6
misc: pci_endpoint_test: Aggregate params checking for xfer9c13b1a044
Input: xpad - fix wireless 360 controller breaking after suspend19dba9c3b5
Input: xpad - add supported devices as contributed on githubb2b9386667
wifi: cfg80211: update hidden BSSes to avoid WARN_ON58c0306d0b
wifi: mac80211: fix crash in beacon protection for P2P-device3539e75abe
wifi: mac80211_hwsim: avoid mac80211 warning on bad rateb0e5c5deb7
wifi: cfg80211: avoid nontransmitted BSS list corruption6b94484503
wifi: cfg80211: fix BSS refcounting bugs6144c97f96
wifi: cfg80211: ensure length byte is present before accesse7aa7fd10e
wifi: cfg80211/mac80211: reject bad MBSSID elementsa6408e0b69
wifi: cfg80211: fix u8 overflow in cfg80211_update_notlisted_nontrans()b0c37581be
random: use expired timer rather than wq for mixing fast poolc1a4423fd3
random: avoid reading two cache lines on irq randomness638f84a718
USB: serial: qcserial: add new usb-id for Dell branded EM745536b33c6351
scsi: stex: Properly zero out the passthrough command structure438994b8cd
efi: Correct Macmini DMI match in uefi cert quirk2fd1caa0c6
ALSA: hda: Fix position reporting on Poulsbo011399a3f9
random: clamp credited irq bits to maximum mixedfc87c413f2
random: restore O_NONBLOCK supportc04b67c544
Revert "clk: ti: Stop using legacy clkctrl names for omap4 and 5"0a49bfa8f8
rpmsg: qcom: glink: replace strncpy() with strscpy_pad()3451df3a51
USB: serial: ftdi_sio: fix 300 bps rate for SIO1b257f97fe
usb: mon: make mmapped memory read only3ba555d8e1
mmc: core: Terminate infinite loop in SD-UHS voltage switch0684658366
mmc: core: Replace with already defined values for readability4f32f266b1
drm/amd/display: skip audio setup when audio stream is enableda6fe179ba0
drm/amd/display: update gamut remap if plane has changed73e1b27b58
net: atlantic: fix potential memory leak in aq_ndev_close()3287f0d727
arch: um: Mark the stack non-executable to fix a binutils warningaeb8315593
um: Cleanup compiler warning in arch/x86/um/tls_32.c6d4deaba06
um: Cleanup syscall_handler_t cast in syscalls_32.h6d7a47e849
ALSA: hda/hdmi: Fix the converter reuse for the silent streamc1337f8ea8
net/ieee802154: fix uninit value bug in dgram_sendmsg034b30c311
scsi: qedf: Fix a UAF bug in __qedf_probe()29461bbe2d
ARM: dts: fix Moxa SDIO 'compatible', remove 'sdhci' misnomerdae0b77cb8
dmaengine: xilinx_dma: Report error in case of dma_set_mask_and_coherent API failuree0ca2998df
dmaengine: xilinx_dma: cleanup for fetching xlnx,num-fstores property789e590cb8
dmaengine: xilinx_dma: Fix devm_platform_ioremap_resource error handling64e240934c
firmware: arm_scmi: Add SCMI PM driver remove routine6df7c6d141
compiler_attributes.h: move __compiletime_{error|warning}1e555c3ed1
fs: fix UAF/GPF bug in nilfs_mdt_destroyacf05d61d3
powerpc/64s/radix: don't need to broadcast IPI for radix pmd collapse flush377c60dd32
mm: gup: fix the fast GUP race against THP collapsefce793a056
ALSA: pcm: oss: Fix race at SNDCTL_DSP_SYNC132590d776
xsk: Inherit need_wakeup flag for shared socketsbeffc38dc6
perf tools: Fixup get_current_dir_name() compilationfb380f548c
docs: update mediator information in CoC docsc7f4af575b
Makefile.extrawarn: Move -Wcast-function-type-strict to W=1b23b0cd57e
ceph: don't truncate file in atomic_open8a18fdc5ae
nilfs2: replace WARN_ONs by nilfs_error for checkpoint acquisition failureaad4c99785
nilfs2: fix leak of nilfs_root in case of writer thread creation failure21ee3cffed
nilfs2: fix use-after-free bug of struct nilfs_root3f840480e3
nilfs2: fix NULL pointer dereference at nilfs_bmap_lookup_at_level()bc7618b493
Merge 5.10.147 into android12-5.10-lts014862eecf
Linux 5.10.14798f722cc24
ALSA: hda/hdmi: fix warning about PCM count when used with SOFb12d0489e4
x86/alternative: Fix race in try_get_desc()374d4c3075
KVM: x86: Hide IA32_PLATFORM_DCA_CAP[31:0] from the guesta8e6cde506
clk: iproc: Do not rely on node name for correct PLL setupcf41711aa4
clk: imx: imx6sx: remove the SET_RATE_PARENT flag for QSPI clocks83db457b41
selftests: Fix the if conditions of in test_extra_filter()84cab3531f
net: stmmac: power up/down serdes in stmmac_open/release743a6e53cf
nvme: Fix IOC_PR_CLEAR and IOC_PR_RELEASE ioctls for nvme devices469dc5fd9a
nvme: add new line after variable declatation2c248c4681
cxgb4: fix missing unlock on ETHOFLD desc collect fail pathfde656dbc3
net: sched: act_ct: fix possible refcount leak in tcf_ct_init()fa065e6081
usbnet: Fix memory leak in usbnet_disconnect()57959392f7
Input: melfas_mip4 - fix return value check in mip4_probe()330b775781
Revert "drm: bridge: analogix/dp: add panel prepare/unprepare in suspend/resume time"359e73edd3
ASoC: tas2770: Reinit regcache on reset8884a192f9
soc: sunxi: sram: Fix debugfs info for A64 SRAM C4e2ede7cb9
soc: sunxi: sram: Fix probe function ordering issues50fbc81f80
soc: sunxi_sram: Make use of the helper function devm_platform_ioremap_resource()0fdc3ab9b4
soc: sunxi: sram: Prevent the driver from being unbound3e0405c69b
soc: sunxi: sram: Actually claim SRAM regionsa658f0bc72
reset: imx7: Fix the iMX8MP PCIe PHY PERST support8934aea1a4
ARM: dts: am33xx: Fix MMCHS0 dma propertiescce5dc0333
scsi: hisi_sas: Revert "scsi: hisi_sas: Limit max hw sectors for v3 HW"625899cd06
swiotlb: max mapping size takes min align mask into account6f478fe8c3
media: rkvdec: Disable H.264 error detectionac828e2416
media: dvb_vb2: fix possible out of bound accessbe2cd261ca
mm: fix madivse_pageout mishandling on non-LRU page1002d5fef4
mm/migrate_device.c: flush TLB while holding PTLa54fc53691
mm: prevent page_frag_alloc() from corrupting the memory466a26af2d
mm/page_alloc: fix race condition between build_all_zonelists and page allocation9b751b4dc3
mmc: hsq: Fix data stomping during mmc recovery36b10cde0c
mmc: moxart: fix 4-bit bus width and remove 8-bit bus width02d55a837e
libata: add ATA_HORKAGE_NOLPM for Pioneer BDR-207M and BDR-205e72a435fa3
net: mt7531: only do PLL once after the reseta48daecd09
ntfs: fix BUG_ON in ntfs_lookup_inode_by_name()1d71422bd4
ARM: dts: integrator: Tag PCI host with device_typedab144c5dd
clk: ingenic-tcu: Properly enable registers before accessing timers6c5742372b
Input: snvs_pwrkey - fix SNVS_HPVIDR1 register address8cf377baf0
net: usb: qmi_wwan: Add new usb-id for Dell branded EM74550695e590de
thunderbolt: Explicitly reset plug events delay back to USB4 spec valueefdff53394
usb: typec: ucsi: Remove incorrect warninge5ee7b77ac
uas: ignore UAS for Thinkplus chips5f91ceea6c
usb-storage: Add Hiksemi USB3-FW to IGNORE_UAS1e4b856fc0
uas: add no-uas quirk for Hiksemi usb_disk6ac5b52e3f
btrfs: fix hang during unmount when stopping a space reclaim worker29d849c3de
ALSA: hda: Fix Nvidia dp infoframe24070d32c6
ALSA: hda/hdmi: let new platforms assign the pcm slot dynamicallyc1256c531d
ALSA: hda/tegra: Reset hardwareded9e8964d
ALSA: hda/tegra: Use clk_bulk helpersb2ad53fbc0
thunderbolt: Add support for Intel Maple Ridge single port controller53e6282dde
thunderbolt: Add support for Intel Maple Ridge0e8dfc1216
Merge branch 'android12-5.10' into branch 'android12-5.10-lts'391716695e
Revert "usb: dwc3: gadget: Avoid starting DWC3 gadget during UDC unbind"1d17080edb
Merge 5.10.146 into android12-5.10-lts62aea69444
Linux 5.10.146c18383218c
ext4: make directory inode spreading reflect flexbg sizea968542d7e
ext4: limit the number of retries after discarding preallocations blocks958b0ee23f
ext4: fix bug in extents parsing when eh_entries == 0 and eh_depth > 02511726515
devdax: Fix soft-reservation memory description0fa11239c4
i2c: mlxbf: Fix frequency calculation48ee0a864d
i2c: mlxbf: prevent stack overflow in mlxbf_i2c_smbus_start_transaction()4f6db1f921
i2c: mlxbf: incorrect base address passed during io write2f58c47c36
i2c: imx: If pm_runtime_get_sync() returned 1 device access is possible90f1c0025b
workqueue: don't skip lockdep work dependency in cancel_work_sync()4dfc96d8d7
drm/rockchip: Fix return type of cdn_dp_connector_mode_valid58101a9cfc
drm/amd/display: Mark dml30's UseMinimumDCFCLK() as noinline for stack usage3ae1dede22
drm/amd/display: Limit user regamma to a valid value867b2b2b68
drm/amdgpu: use dirty framebuffer helperc5812807e4
drm/gma500: Fix BUG: sleeping function called from invalid context errorsec2bf249bd
Drivers: hv: Never allocate anything besides framebuffer from framebuffer memory region2a2e503a62
cifs: always initialize struct msghdr smb_msg completely877231b0e6
cifs: use discard iterator to discard unneeded network data more efficiently09867977fc
drm/amdgpu: Fix check for RAS support8c6fd05cf8
vfio/type1: fix vaddr_get_pfns() return in vfio_pin_page_external()f31ea57c11
usb: xhci-mtk: fix issue of out-of-bounds array accessf5fcc9d6d7
s390/dasd: fix Oops in dasd_alias_get_start_dev due to missing pavgroupfb189aa1be
serial: tegra-tcu: Use uart_xmit_advance(), fixes icount.tx accountinge1993864a9
serial: tegra: Use uart_xmit_advance(), fixes icount.tx accounting7f11386733
serial: Create uart_xmit_advance()fda04a0bab
drm/amd/amdgpu: fixing read wrong pf2vf data in SRIOV4bc4b6419e
selftests: forwarding: add shebang for sch_red.sh8844c750ee
net: sched: fix possible refcount leak in tc_new_tfilter()75ca7f44da
net: sunhme: Fix packet reception for len < RX_COPY_THRESHOLDd76151a813
net/smc: Stop the CLC flow if no link to map buffers onfd938b4ce0
drm/mediatek: dsi: Move mtk_dsi_stop() call back to mtk_dsi_poweroff()c990621606
perf kcore_copy: Do not check /proc/modules is unchanged28d185095e
perf jit: Include program header in ELF files78926cf762
can: gs_usb: gs_can_open(): fix race dev->can.state conditionebd97dbe3c
netfilter: ebtables: fix memory leak when blob is malformedb043a525a3
netfilter: nf_tables: fix percpu memory leak at nf_tables_addchain()710e3f526b
netfilter: nf_tables: fix nft_counters_enabled underflow at nf_tables_addchain()1e7e55374d
net/sched: taprio: make qdisc_leaf() see the per-netdev-queue pfifo child qdiscs586def6ebe
net/sched: taprio: avoid disabling offload when it was never enabledaa400ccadf
net: socket: remove register_gifconf8bd98cfbfc
net: enetc: move enetc_set_psfp() out of the common enetc_set_features()f0a057f49b
wireguard: netlink: avoid variable-sized memcpy on sockaddrb7b3859598
wireguard: ratelimiter: disable timings test by defaultddd47f1cd6
net: ipa: properly limit modem routing table use8c1454d549
net: ipa: kill IPA_TABLE_ENTRY_SIZE53b1715e28
net: ipa: DMA addresses are nicely aligned48afea293a
net: ipa: avoid 64-bit modulus3ae25aca3f
net: ipa: fix table alignment requirementc2cf0613d1
net: ipa: fix assumptions about DMA address sized58815af89
of: mdio: Add of_node_put() when breaking out of for_each_xx9101e54c95
drm/hisilicon: Add depends on MMUbac7328fc0
drm/hisilicon/hibmc: Allow to be built if COMPILE_TEST is enabledb3b41d4d95
sfc: fix null pointer dereference in efx_hard_start_xmitb4afd3878f
sfc: fix TX channel offset when using legacy interrupts2dbf487d6b
i40e: Fix set max_tx_rate when it is lower than 1 Mbps65ee2bcc89
i40e: Fix VF set max MTU size15e9724f6b
iavf: Fix set max MTU size with port VLAN and jumbo framesccddb1db4b
iavf: Fix bad page state21b535fe5e
MIPS: Loongson32: Fix PHY-mode being left unspecifieda4121785a3
MIPS: lantiq: export clk_get_io() for lantiq_wdt.ko1ac50c1ad4
drm/panel: simple: Fix innolux_g121i1_l01 bus_format90fbcb26d6
net: team: Unsync device addresses on ndo_stope2b94a1122
net: bonding: Unsync device addresses on ndo_stopdc209962c0
net: bonding: Share lacpdu_mcast_addr definition2b9aba0c5d
scsi: mpt3sas: Fix return value check of dma_get_required_mask()e7fafef983
scsi: mpt3sas: Force PCIe scatterlist allocations to be within same 4 GB region351f2d2c35
net: phy: aquantia: wait for the suspend/resume operations to finishd298fc2eef
net: core: fix flow symmetric hashe90001e1dd
net: let flow have same hash in two directionsab4a733874
ipvlan: Fix out-of-bound bugs caused by unset skb->mac_header14446a1bc2
iavf: Fix cached head and tail value for iavf_get_tx_pending5d75fef3e6
netfilter: nfnetlink_osf: fix possible bogus match in nf_osf_find()9a5d7e0acb
netfilter: nf_conntrack_irc: Tighten matching on DCC message369ec4dab0
netfilter: nf_conntrack_sip: fix ct_sip_walk_headers66f9470ffe
arm64: dts: rockchip: Remove 'enable-active-low' from rk3399-pumaaa11dae059
dmaengine: ti: k3-udma-private: Fix refcount leak bug in of_xudma_dev_get()1cc871fe6d
arm64: dts: rockchip: Set RK3399-Gru PCLK_EDP to 24 MHz3ca272b231
drm/mediatek: dsi: Add atomic {destroy,duplicate}_state, reset callbacks39f97714f3
arm64: dts: rockchip: Pull up wlan wake# on Gru-Bobdce4662869
xfs: validate inode fork size against fork formata6bfdc157f
xfs: reorder iunlink remove operation in xfs_ifreee811a534ec
xfs: fix up non-directory creation in SGID directories4e74179a16
interconnect: qcom: icc-rpmh: Add BCMs to commit list in pre_aggregatea60babeb60
KVM: SEV: add cache flush to solve SEV cache incoherency issues379ac7905f
mm/slub: fix to return errno if kmalloc() failsfa57bb9b1a
can: flexcan: flexcan_mailbox_read() fix return value for drop = true12fda27a41
riscv: fix a nasty sigreturn bug...657803b918
gpiolib: cdev: Set lineevent_state::irq after IRQ register successfullybdea98b98f
gpio: mockup: fix NULL pointer dereference when removing debugfsbd5958ccfc
wifi: mt76: fix reading current per-tid starting sequence number for aggregation85f9a2d51e
efi: libstub: check Shim mode using MokSBStateRT3490ebe435
efi: x86: Wipe setup_data on pure EFI bootc5ee36018d
media: flexcop-usb: fix endpoint type check0d99b180ce
iommu/vt-d: Check correct capability for sagaw determination213cdb2901
ALSA: hda/realtek: Enable 4-speaker output Dell Precision 5530 laptop10c7e52d95
ALSA: hda/realtek: Add quirk for ASUS GA503R laptop4cd84a9518
ALSA: hda/realtek: Add pincfg for ASUS G533Z HP jack2f7cad4ecd
ALSA: hda/realtek: Add pincfg for ASUS G513 HP jack62ce31979f
ALSA: hda/realtek: Re-arrange quirk table entriesd4bad13828
ALSA: hda/realtek: Enable 4-speaker output Dell Precision 5570 laptop62b0824c2c
ALSA: hda/realtek: Add quirk for Huawei WRT-WX9c78bce842d
ALSA: hda: add Intel 5 Series / 3400 PCI DIDf109dd1607
ALSA: hda/tegra: set depop delay for tegraa1926f11d9
USB: serial: option: add Quectel RM520N4d1d91a634
USB: serial: option: add Quectel BG95 0x0203 composition3a26651a78
USB: core: Fix RST error in hub.c381f77b6a6
arm64/bti: Disable in kernel BTI when cross section thunks are broken050de28980
arm64: Restrict ARM64_BTI_KERNEL to clang 12.0.0 and newer561d86bd0e
Revert "usb: gadget: udc-xilinx: replace memcpy with memcpy_toio"578d644edc
vfio/type1: Unpin zero pagesabb560abdf
vfio/type1: Prepare for batched pinning with struct vfio_batch38cb9b8683
vfio/type1: Change success value of vaddr_get_pfn()c4adbfa9ce
Revert "usb: add quirks for Lenovo OneLink+ Dock"905e8be528
usb: cdns3: fix issue with rearming ISO OUT endpoint8fcb5f027b
usb: cdns3: fix incorrect handling TRB_SMM flag for ISOC transferf457bb2198
usb: gadget: udc-xilinx: replace memcpy with memcpy_toiob9e5c47e33
usb: add quirks for Lenovo OneLink+ Dock345bdea212
tty: serial: atmel: Preserve previous USART mode if RS485 disabled730f78c51b
serial: atmel: remove redundant assignment in rs485_configb3f2adf426
mmc: core: Fix inconsistent sd3_bus_mode at UHS-I SD voltage switch failure7780b3dda2
usb: xhci-mtk: relax TT periodic bandwidth allocation99f48a3a6e
usb: xhci-mtk: allow multiple Start-Split in a microframeb19f9f4122
usb: xhci-mtk: add some schedule error number402fa9214e
usb: xhci-mtk: add a function to (un)load bandwidth infoc2e7000b13
usb: xhci-mtk: use @sch_tt to check whether need do TT schedulea2566a8dc5
usb: xhci-mtk: add only one extra CS for FS/LS INTRb1e11bc66c
usb: xhci-mtk: get the microframe boundary for ESIT9c28189bb6
usb: dwc3: gadget: Avoid duplicate requests to enable Run/Stopff23c7277f
usb: dwc3: gadget: Don't modify GEVNTCOUNT in pullup()ab046365c9
usb: dwc3: gadget: Refactor pullup()db27874477
usb: dwc3: gadget: Prevent repeat pullup()6bd182beef
usb: dwc3: Issue core soft reset before enabling run/stopb83692feb0
usb: dwc3: gadget: Avoid starting DWC3 gadget during UDC unbind2a358ad19c
usb: typec: intel_pmc_mux: Add new ACPI ID for Meteor Lake IOM devicec267bb8334
usb: typec: intel_pmc_mux: Update IOM port status offset for AlderLake7b0db849ea
drm/amdgpu: make sure to init common IP before gmc9d18013dac
drm/amdgpu: Separate vf2pf work item init from virt data exchange87a4e51fb8
drm/amdgpu: indirect register access for nv12 sriov9f55f36f74
drm/amdgpu: move nbio sdma_doorbell_range() into sdma code for vegaef2aee5cec
Merge 5.10.145 into android12-5.10-lts4a77e6ef20
Linux 5.10.145ca5539d421
ALSA: hda/sigmatel: Fix unused variable warning for beep power change9f267393b0
cgroup: Add missing cpus_read_lock() to cgroup_attach_task_all()06e194e113
video: fbdev: pxa3xx-gcu: Fix integer overflow in pxa3xx_gcu_write3fefe614ed
mksysmap: Fix the mismatch of 'L0' symbols in System.map3e6d2eff56
MIPS: OCTEON: irq: Fix octeon_irq_force_ciu_mapping()72602bc620
afs: Return -EAGAIN, not -EREMOTEIO, when a file already locked517a0324db
net: usb: qmi_wwan: add Quectel RM520Na36fd2d8d6
ALSA: hda/tegra: Align BDL entry to 4KB boundarye41b97a277
ALSA: hda/sigmatel: Keep power up while beep is enabledb95a5ef4c0
wifi: mac80211_hwsim: check length for virtio packetsc505fee07b
rxrpc: Fix calc of resend age35da670ed1
rxrpc: Fix local destruction being repeated891d5c46f2
regulator: pfuze100: Fix the global-out-of-bounds access in pfuze100_regulator_probe()c2ef959e33
ASoC: nau8824: Fix semaphore unbalance at error paths107c6b6058
Revert "serial: 8250: Fix reporting real baudrate value in c_ospeed field"e00582a361
video: fbdev: i740fb: Error out if 'pixclock' equals zerof63ddf62d0
tools/include/uapi: Fix <asm/errno.h> for parisc and xtensa331eba80cb
cifs: don't send down the destination address to sendmsg for a SOCK_STREAMf3fbd08e7c
cifs: revalidate mapping when doing direct writesa9398cb81c
of/device: Fix up of_dma_configure_id() stub6a27acda3d
tracing: hold caller_addr to hardirq_{enable,disable}_ip65dd251c51
parisc: ccio-dma: Add missing iounmap in error path in ccio_probe()1f24b0a7ca
drm/meson: Fix OSD1 RGB to YCbCr coefficient4d3d2e384b
drm/meson: Correct OSD1 global alpha value24196210b1
gpio: mpc8xxx: Fix support for IRQ_TYPE_LEVEL_LOW flow_type in mpc85xx4d065f8356
NFSv4: Turn off open-by-filehandle and NFS re-export for NFSv4.02f16f5b582
pinctrl: sunxi: Fix name for A100 R_PIOee4369260e
of: fdt: fix off-by-one error in unflatten_dt_nodes()cae6172a94
net: dsa: mv88e6xxx: allow use of PHYs on CPU and DSA ports4a6c6041e8
platform/x86/intel: hid: add quirk to support Surface Go 38faabaf112
usb: cdns3: gadget: fix new urb never complete if ep cancel previous requestscd226d8c1b
powerpc/pseries/mobility: ignore ibm, platform-facilities updatesd5ee5a9e47
powerpc/pseries/mobility: refactor node lookup during DT update4dbe84b9b6
dmaengine: bestcomm: fix system boot lockups7bbdf49e26
parisc: Flush kernel data mapping in set_pte_at() when installing pte for user pageb00a56e647
parisc: Optimize per-pagetable spinlocks59819f0aaf
serial: 8250: Fix reporting real baudrate value in c_ospeed field9230af9188
KVM: PPC: Tick accounting should defer vtime accounting 'til after IRQ handling6bae475481
KVM: PPC: Book3S HV: Context tracking exit guest context before enabling irqs7474313da8
Merge 5.10.144 into android12-5.10-lts3dbfa90b61
Merge 5.10.143 into android12-5.10-lts51659937e3
Revert "USB: core: Prevent nested device-reset calls"2e00a2dc61
Revert "xhci: Add grace period after xHC start to prevent premature runtime suspend."e0f0b200a5
Merge 5.10.142 into android12-5.10-ltse69a383052
Revert "mm/rmap: Fix anon_vma->degree ambiguity leading to double-reuse"e4a7358455
Revert "io_uring: disable polling pollfree files"99c2dfe47a
Linux 5.10.144744f98f71d
Input: goodix - add compatible string for GT1158c7f4c203d1
soc: fsl: select FSL_GUTS driver for DPIO35371fd688
x86/ftrace: Use alternative RET encoding4586df06a0
x86/ibt,ftrace: Make function-graph play nice33015556a9
Revert "x86/ftrace: Use alternative RET encoding"891f03f688
mm: Fix TLB flush for not-first PFNMAP mappings in unmap_region()dd3aa77d5d
usb: storage: Add ASUS <0x0b05:0x1932> to IGNORE_UAS5ce017619c
platform/x86: acer-wmi: Acer Aspire One AOD270/Packard Bell Dot keymap fixesfc2c14c2cd
perf/arm_pmu_platform: fix tests for platform_get_irq() failure187908079d
drm/amd/amdgpu: skip ucode loading if ucode_size == 0c598e2704c
nvmet-tcp: fix unhandled tcp states in nvmet_tcp_state_change()1cae6f8e17
Input: iforce - add support for Boeder Force Feedback Wheelde2aa49523
ieee802154: cc2520: add rc code in cc2520_tx()3815e66c21
gpio: mockup: remove gpio debugfs when remove device1b8b5384e8
tg3: Disable tg3 device on system reboot to avoid triggering AER704d1f2ac6
hid: intel-ish-hid: ishtp: Fix ishtp client sending disordered messageef033e619e
HID: ishtp-hid-clientHID: ishtp-hid-client: Fix comment typocff2b3a50c
drm/msm/rd: Fix FIFO-full deadlockfac2c299ef
Input: goodix - add support for GT1158218b71e32f
tracefs: Only clobber mode/uid/gid on remount if asked0a81ddfc20
iommu/vt-d: Correctly calculate sagaw value of IOMMU5ce1b0a0c2
ARM: dts: imx6qdl-kontron-samx6i: fix spi-flash compatiblea381cac2ab
ARM: dts: imx: align SPI NOR node name with dtschemaf1101295c1
Linux 5.10.14371d3adbb28
arm64: errata: add detection for AMEVCNTR01 incrementing incorrectly202341395c
hwmon: (mr75203) enable polling for all VM channelsc9da73ae78
hwmon: (mr75203) fix multi-channel voltage reading19841592ae
hwmon: (mr75203) fix voltage equation for negative source input8e8dc8fc53
hwmon: (mr75203) update pvt->v_num and vm_num to the actual number of used sensors13521c94b9
hwmon: (mr75203) fix VM sensor allocation when "intel,vm-map" not defined5e17967c7e
iommu/amd: use full 64-bit value in build_completion_wait()1a27425523
swiotlb: avoid potential left shift overflow586f8c8330
MIPS: loongson32: ls1c: Fix hang during startupa9453be390
ASoC: mchp-spdiftx: Fix clang -Wbitfield-constant-conversion9dacdc1d47
ASoC: mchp-spdiftx: remove references to mchp_i2s_caps2ead78fbe6
sch_sfb: Also store skb len before calling child enqueued47475d4e5
tcp: fix early ETIMEDOUT after spurious non-SACK RTO6a2a344844
nvme-tcp: fix regression that causes sporadic requests to time out5914fa32ef
nvme-tcp: fix UAF when detecting digest errorsa00b1b10e0
RDMA/mlx5: Set local port to one when accessing counterse8de6cb575
IB/core: Fix a nested dead lock as part of ODP flow076f2479fc
ipv6: sr: fix out-of-bounds read when setting HMAC data.047e66867e
RDMA/siw: Pass a pointer to virt_to_page()0f1e7977e1
xen-netback: only remove 'hotplug-status' when the vif is actually destroyed342d77769a
i40e: Fix kernel crash during module removal9d11d06e50
ice: use bitmap_free instead of devm_kfree22922da737
tipc: fix shift wrapping bug in map_get()2ee85ac1b2
sch_sfb: Don't assume the skb is still around after enqueueing to child63677a0923
afs: Use the operation issue time instead of the reply time for callbacksfbbd5d05ea
rxrpc: Fix an insufficiently large sglist in rxkad_verify_packet_2()6ccbb74801
ALSA: usb-audio: Register card again for iface over delayed_register option1d29a63585
ALSA: usb-audio: Inform the delayed registration more properlye12ce30fe5
netfilter: nf_conntrack_irc: Fix forged IP logic910891a2a4
netfilter: nf_tables: clean up hook list when offload flags check fails908180f633
netfilter: br_netfilter: Drop dst references before setting.7d29f2bdd1
ARM: dts: at91: sama5d2_icp: don't keep vdd_other enabled all the time0796953300
ARM: dts: at91: sama5d27_wlsom1: don't keep ldo2 enabled all the time360dd120eb
ARM: dts: at91: sama5d2_icp: specify proper regulator output ranges6bbef2694a
ARM: dts: at91: sama5d27_wlsom1: specify proper regulator output rangese198c08570
RDMA/hns: Fix wrong fixed value of qp->rq.wqe_shiftb2e82e325a
RDMA/hns: Fix supported page size6dc0251638
soc: brcmstb: pm-arm: Fix refcount leak and __iomem leak bugse9ea271c2e
RDMA/cma: Fix arguments order in net device validation465eecd2b3
tee: fix compiler warning in tee_shm_register()75c961d011
regulator: core: Clean up on enable failurebb4bee3eca
ARM: dts: imx6qdl-kontron-samx6i: remove duplicated node015c2ec053
smb3: missing inode locks in punch hole98127f140b
cifs: remove useless parameter 'is_fsctl' from SMB2_ioctl()dee1e2b18c
cgroup: Fix threadgroup_rwsem <-> cpus_read_lock() deadlockbfbacc2ef7
cgroup: Elide write-locking threadgroup_rwsem when updating csses on an empty subtreea5620d3e0c
scsi: lpfc: Add missing destroy_workqueue() in error pathea10a652ad
scsi: mpt3sas: Fix use-after-free warningde572edecc
drm/i915: Implement WaEdpLinkRateDataReloadbe01f1c988
nvmet: fix a use-after-free68f22c80c1
debugfs: add debugfs_lookup_and_remove()ab60010225
kprobes: Prohibit probes in gate area6123bec848
ALSA: usb-audio: Fix an out-of-bounds bug in __snd_usb_parse_audio_interface()ab730d3c44
ALSA: aloop: Fix random zeros in capture data when using jiffies timer39a90720f3
ALSA: emu10k1: Fix out of bounds access in snd_emu10k1_pcm_channel_alloc()dfb27648ee
drm/amdgpu: mmVM_L2_CNTL3 register not initialized correctly2078e326b6
fbdev: chipsfb: Add missing pci_disable_device() in chipsfb_pci_init()9d040a629e
net/core/skbuff: Check the return value of skb_copy_bits()43b9af7275
arm64: cacheinfo: Fix incorrect assignment of signed error value to unsigned fw_level96d206d0a1
parisc: Add runtime check to prevent PA2.0 kernels on PA1.x machines44739b5aae
parisc: ccio-dma: Handle kmalloc failure in ccio_init_resources()826b46fd59
drm/radeon: add a force flush to delay work when radeon0410256867
drm/amdgpu: Check num_gfx_rings for gfx v9_0 rb setup.c19656cd95
drm/amdgpu: Move psp_xgmi_terminate call from amdgpu_xgmi_remove_device to psp_hw_fini67bf86ff81
drm/gem: Fix GEM handle release errorsa175aed83e
scsi: megaraid_sas: Fix double kfree()004e26ef05
scsi: qla2xxx: Disable ATIO interrupt coalesce for quad port ISP27XXa14f1799ce
Revert "mm: kmemleak: take a full lowmem check in kmemleak_*_phys()"13c8f561be
fs: only do a memory barrier for the first set_buffer_uptodate()2946d2ae5a
wifi: iwlegacy: 4965: corrected fix for potential off-by-one overflow in il4965_rs_fill_link_cmd()918d9c4a4b
efi: capsule-loader: Fix use-after-free in efi_capsule_write94f0f30b2d
efi: libstub: Disable struct randomizationeb75efdec8
tty: n_gsm: avoid call of sleeping functions from atomic contextfb6cadd2a3
tty: n_gsm: initialize more members at gsm_alloc_mux()186cb020bd
xen-blkfront: Cache feature_persistent value before advertisementd3d885507b
NFSD: Fix verifier returned in stable WRITEs281e81a5e2
Linux 5.10.1422058aab4e3
USB: serial: ch341: fix disabled rx timer on older devices2a4c619a87
USB: serial: ch341: fix lost character on LCR updates06a84bda0a
usb: dwc3: disable USB core PHY management451fa90150
usb: dwc3: qcom: fix use-after-free on runtime-PM wakeup8984ca41de
usb: dwc3: fix PHY disable sequencecb27189360
mmc: core: Fix UHS-I SD 1.8V workaround branch7f73a9dea0
btrfs: harden identification of a stale device3c63a22d02
drm/i915/glk: ECS Liva Q2 needs GLK HDMI port timing quirk1079d09572
ALSA: seq: Fix data-race at module auto-loadingf19a209f61
ALSA: seq: oss: Fix data-race for max_midi_devs access7565c15030
ALSA: hda/realtek: Add speaker AMP init for Samsung laptops with ALC298ab9f890377
net: mac802154: Fix a condition in the receive pathd71a1c9fce
net: Use u64_stats_fetch_begin_irq() for stats fetch.685f4e5671
ip: fix triggering of 'icmp redirect'4abc8c07a0
wifi: mac80211: Fix UAF in ieee80211_scan_rx()dd649b4921
wifi: mac80211: Don't finalize CSA in IBSS mode if state is disconnected742e222dd5
driver core: Don't probe devices after bus_type.match() probe deferral6202637fde
usb: gadget: mass_storage: Fix cdrom data transfers on MAC-OSabe3cfb7a7
USB: core: Prevent nested device-reset callsb0d4993c4b
s390: fix nospec table alignments0361d50e86
s390/hugetlb: fix prepare_hugepage_range() check for 2 GB hugepagesb9097c5e10
usb-storage: Add ignore-residue quirk for NXP PN7462AU5f0d11796a
USB: cdc-acm: Add Icom PMR F3400 support (0c26:0020)d608c131df
usb: dwc2: fix wrong order of phy_power_on and phy_init95791d51f7
usb: typec: altmodes/displayport: correct pin assignment for UFP receptacles89b01a88ef
USB: serial: option: add support for Cinterion MV32-WA/WB RmNet mode7f1f176715
USB: serial: option: add Quectel EM060K modemefcc3e1e6a
USB: serial: option: add support for OPPO R11 diag porte547c07c28
USB: serial: cp210x: add Decagon UCA device id5a603f4c12
xhci: Add grace period after xHC start to prevent premature runtime suspend.587f793c64
media: mceusb: Use new usb_control_msg_*() routines07fb6b10b6
thunderbolt: Use the actual buffer in tb_async_error()f210912d1a
xen-blkfront: Advertise feature-persistent as user requestedaa45c50703
xen-blkback: Advertise feature-persistent as user requested47a73e5e6b
mm: pagewalk: Fix race between unmap and page walker5d0d46e625
xen/grants: prevent integer overflow in gnttab_dma_alloc_pages()eb0c614c42
KVM: x86: Mask off unsupported and unknown bits of IA32_ARCH_CAPABILITIES7efcbac55a
gpio: pca953x: Add mutex_lock for regcache sync in PM517dba7987
hwmon: (gpio-fan) Fix array out of bounds accessa971343557
clk: bcm: rpi: Add missing newlinefcae47b2d2
clk: bcm: rpi: Prevent out-of-bounds access8c90a3e0d3
clk: bcm: rpi: Use correct order for the parameters of devm_kcalloc()00d8bc0c16
clk: bcm: rpi: Fix error handling of raspberrypi_fw_get_ratee32982115d
Input: rk805-pwrkey - fix module autoloadinge2945f936c
clk: core: Fix runtime PM sequence in clk_core_unprepare()4ff599df31
Revert "clk: core: Honor CLK_OPS_PARENT_ENABLE for clk gate ops"c0f0ed9ef9
clk: core: Honor CLK_OPS_PARENT_ENABLE for clk gate ops5f1aee7f05
drm/i915/reg: Fix spelling mistake "Unsupport" -> "Unsupported"9629f2dfdb
binder: fix UAF of ref->proc caused by race condition08fa8cb6df
USB: serial: ftdi_sio: add Omron CS1W-CIF31 device id5cf2a57c7a
misc: fastrpc: fix memory corruption on openc99bc901d5
misc: fastrpc: fix memory corruption on probe30fd0e23e3
iio: adc: mcp3911: use correct formula for AD conversion89aa443437
iio: ad7292: Prevent regulator double disableb271090eea
Input: iforce - wake up after clearing IFORCE_XMIT_RUNNING flagb202400c9c
tty: serial: lpuart: disable flow control while waiting for the transmit engine to complete989201bb8c
vt: Clear selection before changing the font7fd8d33adb
powerpc: align syscall table for ppc3219e3f69d19
staging: rtl8712: fix use after free bugs6ccd69141b
serial: fsl_lpuart: RS485 RTS polariy is inversee416fe7f16
net/smc: Remove redundant refcount increased73b89c3b3
Revert "sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb"f3d1554d0f
tcp: annotate data-race around challenge_timestamp870b6a1561
sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb1b6666964c
kcm: fix strp_init() order and cleanup406d554844
ethernet: rocker: fix sleep in atomic context bug in neigh_timer_handler44dfa64589
net/sched: fix netdevice reference leaks in attach_default_qdiscs()699d82e9a6
net: sched: tbf: don't call qdisc_put() while holding tree lockc0cb63ee2e
Revert "xhci: turn off port power in shutdown"6855efbaf5
wifi: cfg80211: debugfs: fix return type in ht40allow_map_read()ddcb56e841
ALSA: hda: intel-nhlt: Correct the handling of fmt_config flexible array9276eb98cd
ALSA: hda: intel-nhlt: remove use of __func__ in dev_dbg23a2993271
ieee802154/adf7242: defer destroy_workqueue callc5f975e3eb
bpf, cgroup: Fix kernel BUG in purge_effective_progse6aeb8be85
iio: adc: mcp3911: make use of the sign bitb69e05b1e8
platform/x86: pmc_atom: Fix SLP_TYPx bitfield maskf040abf62e
drm/msm/dsi: Fix number of regulators for SDM66043e523a407
drm/msm/dsi: Fix number of regulators for msm8996_dsi_cfg1487e8fc16
drm/msm/dp: delete DP_RECOVERED_CLOCK_OUT_EN to fix tps4631fbefd87
drm/msm/dsi: fix the inconsistent indenting5d60de7a5f
Merge 5.10.141 into android12-5.10-lts0b8e37cbaa
Linux 5.10.141bdc786d737
net: neigh: don't call kfree_skb() under spin_lock_irqsave()4931af31c4
net/af_packet: check len when min_header_len equals to 064f6da455b
xfs: revert "xfs: actually bump warning counts when we send warnings"d34798d846
xfs: fix soft lockup via spinning in filestream ag selection loopf168801da9
xfs: fix overfilling of reserve pool72a259bdd5
xfs: always succeed at setting the reserve pool sizecb41f22df3
xfs: remove infinite loop when reserving free block pool28d8d2737e
io_uring: disable polling pollfree files744b0d3080
kprobes: don't call disarm_kprobe() for disabled kprobes8c70cce892
lib/vdso: Mark do_hres_timens() and do_coarse_timens() __always_inline()6ba9e8fb47
netfilter: conntrack: NF_CONNTRACK_PROCFS should no longer default to yafa169f79d
drm/amdgpu: Increase tlb flush timeout for sriovf08a3712ba
drm/amd/display: Fix pixel clock programming60d522f317
drm/amd/pm: add missing ->fini_microcode interface for Sienna Cichlidf2b7b8b1c4
s390/hypfs: avoid error message under KVMc35adafe42
neigh: fix possible DoS due to net iface start/stop loop3c1dfeaeb3
drm/amd/display: clear optc underflow before turn off odm clock4e5e67b13a
drm/amd/display: For stereo keep "FLIP_ANY_FRAME"828b2a5399
drm/amd/display: Avoid MPC infinite loop9d36e2c264
mmc: mtk-sd: Clear interrupts when cqe off/disable98f401d363
mm/rmap: Fix anon_vma->degree ambiguity leading to double-reuse6204bf78b2
bpf: Don't redirect packets with invalid pkt_lendbd8c8fc60
ftrace: Fix NULL pointer dereference in is_ftrace_trampoline when ftrace is dead8fc778ee2f
fbdev: fb_pm2fb: Avoid potential divide by zero error61cc798591
net: fix refcount bug in sk_psock_get (2)7e2fa79226
HID: hidraw: fix memory leak in hidraw_release()bacb37bdc2
media: pvrusb2: fix memory leak in pvr_probe872875c9ec
udmabuf: Set the DMA mask for the udmabuf device (v2)dc81576194
HID: steam: Prevent NULL pointer dereference in steam_{recv,send}_report412b844143
Revert "PCI/portdrv: Don't disable AER reporting in get_port_device_capability()"38267d2663
Bluetooth: L2CAP: Fix build errors in some archsad697ade59
kbuild: Fix include path in scripts/Makefile.modpostb9feeb6100
s390/mm: do not trigger write fault when vma does not allow VM_WRITE0dea6b3e22
crypto: lib - remove unneeded selection of XOR_BLOCKSe5796ff9ac
x86/nospec: Fix i386 RSB stuffingadee8f3082
x86/nospec: Unwreck the RSB stuffing895428ee12
mm: Force TLB flush for PFNMAP mappings before unlink_file_vma()5939035887
Merge 5.10.140 into android12-5.10-lts18ed766f36
Linux 5.10.140e897980717
bpf: Don't use tnum_range on array range checking for poke descriptors46fcb0fc88
scsi: storvsc: Remove WQ_MEM_RECLAIM from storvsc_error_wq8d5c106fe2
scsi: ufs: core: Enable link lost interruptc0ba9aa95b
perf/x86/intel/uncore: Fix broken read_counter() for SNB IMC PMU5a768c9770
perf python: Fix build when PYTHON_CONFIG is user supplied3ddbd0907f
blk-mq: fix io hung due to missing commit_rqs7ca73d0a16
Documentation/ABI: Mention retbleed vulnerability info file for sysfs1896232619
arm64: Fix match_list for erratum 1286807 on Arm Cortex-A76a5a58fab55
md: call __md_stop_writes in md_stopf68f025c7e
Revert "md-raid: destroy the bitmap after destroying the thread"62af37c5cd
mm/hugetlb: fix hugetlb not supporting softdirty tracking6de50db104
xen/privcmd: fix error exit of privcmd_ioctl_dm_op()8d5f8a4f25
ACPI: processor: Remove freq Qos request for all CPUs297ae7e87a
s390: fix double free of GS and RI CBs on fork() failurec60ae87878
asm-generic: sections: refactor memory_intersects6858933131
loop: Check for overflow while configuring loop14cbbb9c99
x86/bugs: Add "unknown" reporting for MMIO Stale Datae3e0d11729
x86/unwind/orc: Unwind ftrace trampolines with correct ORC entry090f0ac167
perf/x86/lbr: Enable the branch type for the Arch LBR by defaultd2bd18d50c
btrfs: check if root is readonly while setting security xattrdcac6293f5
btrfs: add info when mount fails due to stale replace targetb2d352ed4d
btrfs: replace: drop assert for suspended replace2fc3c168d5
btrfs: fix silent failure when deleting root reference3a351b567e
ionic: fix up issues with handling EAGAIN on FW cmds79e2ca7aa9
rxrpc: Fix locking in rxrpc's sendmsgc3a6e863d5
ixgbe: stop resetting SYSTIME in ixgbe_ptp_start_cyclecounter23cf93bb32
net: Fix a data-race around sysctl_somaxconn.9fcc4f4066
net: Fix data-races around sysctl_devconf_inherit_init_net.371a3bcf31
net: Fix data-races around sysctl_fb_tunnels_only_for_init_net.c3bda708e9
net: Fix a data-race around netdev_budget_usecs.12a34d7f04
net: Fix a data-race around netdev_budget.410c88314c
net: Fix a data-race around sysctl_net_busy_read.2c7dae6c45
net: Fix a data-race around sysctl_net_busy_poll.8db070463e
net: Fix a data-race around sysctl_tstamp_allow_data.ed48223f87
net: Fix data-races around sysctl_optmem_max.27e8ade792
bpf: Folding omem_charge() into sk_storage_charge()4d4e39245d
ratelimit: Fix data-races in ___ratelimit().e73009ebc1
net: Fix data-races around netdev_tstamp_prequeue.3850060352
net: Fix data-races around netdev_max_backlog.b498a1b017
net: Fix data-races around weight_p and dev_weight_[rt]x_bias.fb442c72db
net: Fix data-races around sysctl_[rw]mem_(max|default).613fd02620
net: Fix data-races around sysctl_[rw]mem(_offset)?.e73a29554f
tcp: tweak len/truesize ratio for coalesce candidatesc08a104a8b
netfilter: nf_tables: disallow binding to already bound chain6301a73bd8
netfilter: nf_tables: disallow jump to implicit chain from set element9882768759
netfilter: nf_tables: upfront validation of data via nft_data_init()8790eecdea
netfilter: bitwise: improve error goto labels2267d38520
netfilter: nft_cmp: optimize comparison for 16-bytes1d7d74a824
netfilter: nf_tables: consolidate rule verdict trace callcd962806c4
netfilter: nftables: remove redundant assignment of variable err35519ce7ba
netfilter: nft_tunnel: restrict it to netdev family9a67c2c89c
netfilter: nft_osf: restrict osf to ipv4, ipv6 and inet familiesc907dfe4ea
netfilter: nf_tables: do not leave chain stats enabled on errorea358cfc8e
netfilter: nft_payload: do not truncate csum_offset and csum_type93a46d6c72
netfilter: nft_payload: report ERANGE for too long offset and lengthe0f8cf0192
bnxt_en: fix NQ resource accounting during vf creation on 57500 chips624c305212
netfilter: ebtables: reject blobs that don't provide all entry pointsf82a6b85e0
net: ipvtap - add __init/__exit annotations to module init/exit funcs7e7e88e8b5
bonding: 802.3ad: fix no transmission of LACPDUs14ef913a95
net: moxa: get rid of asymmetry in DMA mapping/unmappingfaa8bf8451
net: ipa: don't assume SMEM is page-aligned29accb2d96
net/mlx5e: Properly disable vlan strip on non-UL reps1bfdcde723
ice: xsk: prohibit usage of non-balanced queue idd29d7108e1
ice: xsk: Force rings to be sized to power of 250403ee6da
nfc: pn533: Fix use-after-free bugs caused by pn532_cmd_timeoutde3deadd11
rose: check NULL rose_loopback_neigh->loopbacke9fe1283a8
mm/smaps: don't access young/dirty bit if pte unpresentc7c77185fa
mm/huge_memory.c: use helper function migration_entry_to_page()8be096f018
SUNRPC: RPC level errors should set task->tk_rpc_status5e49ea0998
NFSv4.2 fix problems with __nfs42_ssc_open23c6f25a60
NFS: Don't allocate nfs_fattr on the stack in __nfs42_ssc_open()2761612bcd
xfrm: policy: fix metadata dst->dev xmit null pointer dereferencec5c4d4c980
af_key: Do not call xfrm_probe_algs in parallel4379a10c1d
xfrm: clone missing x->lastused in xfrm_do_migrate1305d7d4f3
xfrm: fix refcount leak in __xfrm_policy_check()c30c0f7205
kernel/sched: Remove dl_boosted flag comment70d560e2fb
xfs: only bother with sync_filesystem during readonly remount37837bc3ef
xfs: return errors in xfs_fs_sync_fs76a51e49da
vfs: make sync_filesystem return errors from ->sync_fs9255a42fe7
fs: remove __sync_filesystem1b9b4139d7
xfs: reject crazy array sizes being fed to XFS_IOC_GETBMAP*6a564bad3a
xfs: prevent a WARN_ONCE() in xfs_ioc_attr_list()a5757df612
pinctrl: amd: Don't save/restore interrupt status and wake status bits665433b5dd
kernel/sys_ni: add compat entry for fadvise64_64df1d445e7f
parisc: Fix exception handler for fldw and fstw instructionse10bb2f2e9
audit: fix potential double free on error path from fsnotify_add_inode_mark44cde61acc
Merge 5.10.139 into android12-5.10-lts7a3ca8147f
Revert "ALSA: control: Use deferred fasync helper"5597d5439f
Merge 5.10.138 into android12-5.10-lts1e247e4040
Revert "block: remove the request_queue to argument request based tracepoints"33d6fea819
Revert "blktrace: Trace remapped requests correctly"eb5eb075d8
Revert "USB: HCD: Fix URB giveback issue in tasklet function"fbe6a13851
Merge 5.10.137 into android12-5.10-lts665ee74607
Linux 5.10.13937c7f25fe2
kbuild: dummy-tools: avoid tmpdir leak in dummy gccfa3303d70b
Linux 5.10.138606fe84a41
tee: fix memory leak in tee_shm_register()3527e3cbb8
bpf: Fix KASAN use-after-free Read in compute_effective_progs4f7286422a
qrtr: Convert qrtr_ports from IDR to XArray1daa7629d2
PCI/ERR: Retain status from error notificationa220ff3433
can: j1939: j1939_session_destroy(): fix memory leak of skbs05b9b0a7a7
can: j1939: j1939_sk_queue_activate_next_locked(): replace WARN_ON_ONCE with netdev_warn_once()184e73f12c
tracing/probes: Have kprobes and uprobes use $COMM too3debec96ca
netfilter: nf_tables: fix audit memory leak in nf_tables_commitf3d0db3b43
netfilter: nftables: fix a warning message in nf_tables_commit_audit_collect()059f47b3a4
MIPS: tlbex: Explicitly compare _PAGE_NO_EXEC against 04b20c61365
video: fbdev: i740fb: Check the argument of i740_calc_vclk()dac28dff90
powerpc/64: Init jump labels before parse_early_param()52a408548a
smb3: check xattr value length earlier336936f72a
f2fs: fix to do sanity check on segment type in build_sit_entries()800ba89791
f2fs: fix to avoid use f2fs_bug_on() in f2fs_new_node_page()857ccedcf5
ALSA: control: Use deferred fasync helper658bc550a4
ALSA: timer: Use deferred fasync helperbe094c417a
ALSA: core: Add async signal helpers6ed3e280c7
powerpc/32: Don't always pass -mcpu=powerpc to the compiler63671b2bdf
watchdog: export lockup_detector_reconfigure399d245775
RISC-V: Add fast call path of crash_kexec()d881c98d0a
riscv: mmap with PROT_WRITE but no PROT_READ is invalid333bdb72be
modules: Ensure natural alignment for .altinstructions and __bug_table sections1e39037e44
mips: cavium-octeon: Fix missing of_node_put() in octeon2_usb_clocks_start5e034e03f4
vfio: Clear the caps->buf to NULL after free81939c4fbc
tty: serial: Fix refcount leak bug in ucc_uart.c58275db3c7
lib/list_debug.c: Detect uninitialized lists8028888329
ext4: avoid resizing to a partial cluster size285447b819
ext4: avoid remove directory when directory is corrupted5d8325fd15
drivers:md:fix a potential use-after-free bug534e96302a
nvmet-tcp: fix lockdep complaint on nvmet_tcp_wq flush during queue teardown6d7aabdba6
md: Notify sysfs sync_completed in md_reap_sync_thread()f43a72d4da
dmaengine: sprd: Cleanup in .remove() after pm_runtime_get_sync() failedb30aa4ff11
selftests/kprobe: Do not test for GRP/ without event failuresfa45327d8c
csky/kprobe: reclaim insn_slot on kprobe unregistration18f62a453b
RDMA/rxe: Limit the number of calls to each tasklet9a6178c225
um: add "noreboot" command line option for PANIC_TIMEOUT=-1 setupse4c9f16219
PCI/ACPI: Guard ARM64-specific mcfg_quirks4be138bcd6
cxl: Fix a memory leak in an error handling path84d94619c7
pinctrl: intel: Check against matching data instead of ACPI companion9ac14f973c
gadgetfs: ep_io - wait until IRQ finishesc29a4baaad
scsi: lpfc: Prevent buffer overflow crashes in debugfs with malformed user inputeb01065fd3
clk: qcom: clk-alpha-pll: fix clk_trion_pll_configure description56a4bccab9
zram: do not lookup algorithm in backends table09c90f89b2
uacce: Handle parent device removal or parent driver module rmmod6b90ab9524
clk: qcom: ipq8074: dont disable gcc_sleep_clk_srceddb352a80
vboxguest: Do not use devm for irq9a87f33f1d
usb: dwc2: gadget: remove D+ pull-up while no vbus with usb-role-switch9790a5a4f0
usb: renesas: Fix refcount leak bugcb5dd65e88
usb: host: ohci-ppc-of: Fix refcount leak bugd86c6447ee
clk: ti: Stop using legacy clkctrl names for omap4 and 5152c94c10b
drm/meson: Fix overflow implicit truncation warningsda6b37983a
irqchip/tegra: Fix overflow implicit truncation warnings24304c6f9c
usb: gadget: uvc: call uvc uvcg_warn on completed status instead of uvcg_info6d7ac60098
usb: cdns3 fix use-after-free at workaround 20a0da5ef5b
platform/chrome: cros_ec_proto: don't show MKBP version if unsupportede2ab7afe66
PCI: Add ACS quirk for Broadcom BCM5750x NICsa1e7908f78
drm/sun4i: dsi: Prevent underflow when computing packet sizesbd6165b802
netfilter: add helper function to set up the nfnetlink header and use it06fde3cd0b
netfilter: nftables: add helper function to set the base sequence numbere2a49009ba
audit: log nftables configuration change events once per table3aa710e967
drm/meson: Fix refcount bugs in meson_vpu_has_available_connectors()1bfdb1912c
ASoC: SOF: intel: move sof_intel_dsp_desc() forward823280a8fb
locking/atomic: Make test_and_*_bit() ordered on failure0bd35968bc
gcc-plugins: Undefine LATENT_ENTROPY_PLUGIN when plugin disabled for a file9112826f28
kbuild: fix the modules order between drivers and libs0f516dcd14
igb: Add lock to avoid data race02f3642d8e
stmmac: intel: Add a missing clk_disable_unprepare() call in intel_eth_pci_remove()efae1735ff
fec: Fix timer capture timing in `fec_ptp_enable_pps()`668f38fb9a
i40e: Fix to stop tx_timeout recovery if GLOBR failsbbd6723d75
regulator: pca9450: Remove restrictions for regulator-nameb5ba5c3669
i2c: imx: Make sure to unregister adapter on remove()19cb691faf
ice: Ignore EEXIST when setting promisc mode7983e1e44c
net: dsa: sja1105: fix buffer overflow in sja1105_setup_devlink_regions()83411c9f05
net: genl: fix error path memory leak in policy dumpingaf1748ee51
net: dsa: felix: fix ethtool 256-511 and 512-1023 TX packet counters9900af65f2
net: dsa: microchip: ksz9477: fix fdb_dump last invalid entry7d51385ae0
net: moxa: pass pdev instead of ndev to DMA functions92dc64e8f5
net: dsa: mv88e6060: prevent crash on an unused portaa16c8c4e8
spi: meson-spicc: add local pow2 clock ops to preserve rate between messagesa868f771ee
powerpc/pci: Fix get_phb_number() locking3561f4d12f
netfilter: nf_tables: check NFT_SET_CONCAT flag if field_count is specified01b0cae6b7
netfilter: nf_tables: validate NFTA_SET_ELEM_OBJREF based on NFT_SET_OBJECT flag8d2fe4b9ed
netfilter: nf_tables: really skip inactive sets when allocating name330f0a552b
ASoC: tas2770: Fix handling of mute/unmute353cc4cb97
ASoC: tas2770: Drop conflicting set_bias_level power settingdffe1c4780
ASoC: tas2770: Allow mono streamsfc57e3fde2
ASoC: tas2770: Set correct FSYNC polarity4fe80492d5
iavf: Fix adminq error handling63684e467b
nios2: add force_successful_syscall_return()600ff4b13b
nios2: restarts apply only to the first sigframe we build...f20bc59ccf
nios2: fix syscall restart checks8d0118a027
nios2: traced syscall does need to check the syscall number1d2c89dc48
nios2: don't leave NULLs in sys_call_table[]d29cdf865a
nios2: page fault et.al. are *not* restartable syscalls...76be981882
dpaa2-eth: trace the allocated address instead of page struct787511c768
perf probe: Fix an error handling path in 'parse_perf_probe_command()'2c746ec91d
geneve: fix TOS inheriting for ipv4a0ae122e9a
atm: idt77252: fix use-after-free bugs caused by tst_timer291cba960b
xen/xenbus: fix return type in xenbus_file_read()3c555a0599
nfp: ethtool: fix the display error of `ethtool -m DEVNAME`76f3b97e56
NTB: ntb_tool: uninitialized heap data in tool_fn_write()7ef9f0efbe
tools build: Switch to new openssl API for test-libcrypto7ef0645ebe
kbuild: dummy-tools: avoid tmpdir leak in dummy gccaee18421bd
ceph: don't leak snap_rwsem in handle_cap_granteea0d84a4f
tools/vm/slabinfo: use alphabetic order when two values are equal97cea2cb7c
ceph: use correct index when encoding client supported features7a327285a7
dt-bindings: clock: qcom,gcc-msm8996: add more GCC clock sources87c4b359e3
dt-bindings: arm: qcom: fix MSM8916 MTP compatibles55fdefcb52
vsock: Set socket state back to SS_UNCONNECTED in vsock_connect_timeout()38ddccbda5
vsock: Fix memory leak in vsock_connect()549822e0dc
plip: avoid rcu debug splat0c4542cb6a
ipv6: do not use RT_TOS for IPv6 flowlabel38b83883ce
geneve: do not use RT_TOS for IPv6 flowlabelb0c3eec4ac
ACPI: property: Return type of acpi_add_nondev_subnodes() should be boolcc0bfd933c
pinctrl: qcom: sm8250: Fix PDC mapd35d9bba29
pinctrl: sunxi: Add I/O bias setting for H6 R-PIOe8f5699a82
pinctrl: qcom: msm8916: Allow CAMSS GP clocks to be muxed78d0510389
pinctrl: nomadik: Fix refcount leak in nmk_pinctrl_dt_subnode_to_mapab2b55bb25
net: bgmac: Fix a BUG triggered by wrong bytes_compl0e28678a77
devlink: Fix use-after-free after a failed reloadfaafa2a87f
virtio_net: fix memory leak inside XPD_TX with mergeablefd70ebf299
SUNRPC: Reinitialise the backchannel request buffers before reuse59d2e8fa41
sunrpc: fix expiry of auth credsdf60c534d4
net: atlantic: fix aq_vec index out of range errorcc25abcec8
can: mcp251x: Fix race condition on receive interruptb9d9cf88c8
bpf: Check the validity of max_rdwr_access for sock local storage map iteratorf7d844df5e
bpf: Acquire map uref in .init_seq_private for sock{map,hash} iteratord7ad7e65aa
bpf: Acquire map uref in .init_seq_private for sock local storage map iteratorbda6fe3ea8
bpf: Acquire map uref in .init_seq_private for hash map iterator30d7198da8
bpf: Acquire map uref in .init_seq_private for array map iterator76ffd20424
NFSv4/pnfs: Fix a use-after-free bug in openf2bd1cc1fe
NFSv4.1: RECLAIM_COMPLETE must handle EACCEScfde64bd31
NFSv4: Fix races in the legacy idmapper upcall060c111373
NFSv4.1: Handle NFS4ERR_DELAY replies to OP_SEQUENCE correctlya351a73d90
NFSv4.1: Don't decrease the value of seq_nr_highest_senta408f135c4
Documentation: ACPI: EINJ: Fix obsolete example8aab429558
apparmor: Fix memleak in aa_simple_write_to_buffer()2ceeb3296e
apparmor: fix reference count leak in aa_pivotroot()2672f3eb7a
apparmor: fix overlapping attachment computation1ac89741a2
apparmor: fix setting unconfined mode on a loaded profile4188f91c82
apparmor: fix aa_label_asxprint return checke0ca0156a7
apparmor: Fix failed mount permission check error message08f8128bc9
apparmor: fix absroot causing audited secids to begin with =bca03f0bbc
apparmor: fix quiet_denied for file rules2b74344135
can: ems_usb: fix clang's -Wunaligned-access warning7f06c78211
ALSA: usb-audio: More comprehensive mixer map for ASUS ROG Zenith II5d3b02b80d
tracing: Have filter accept "common_cpu" to be consistent6359850f9d
btrfs: fix lost error handling when looking up extended ref on log replay79895cefa4
mmc: meson-gx: Fix an error handling path in meson_mmc_probe()13a497c3c5
mmc: pxamci: Fix an error handling path in pxamci_probe()4a211dd485
mmc: pxamci: Fix another error handling path in pxamci_probe()a785d84178
ata: libata-eh: Add missing command namefb1857c2e4
rds: add missing barrier to release_refill6876b4804b
x86/mm: Use proper mask when setting PUD mappingb68e40b52f
ALSA: hda/realtek: Add quirk for Clevo NS50PU, NS70PUe14e2fec35
ALSA: info: Fix llseek return value when using callbacka634d58881
Merge branch 'android12-5.10' into branch 'android12-5.10-lts'74ded189e5
Linux 5.10.137fb4e220e1b
btrfs: raid56: don't trust any cached sector in __raid56_parity_recover()1e1a039f44
btrfs: only write the sectors in the vertical stripe which has data stripes8f317cd888
sched/fair: Fix fault in reweight_entityaa318d35be
net_sched: cls_route: disallow handle of 05a2a00b604
net/9p: Initialize the iounit field during fid creation578c349570
tee: add overflow check in register_shm_helper()98b20e1612
kvm: x86/pmu: Fix the compare function used by the pmu event filter705dfc4575
mtd: rawnand: arasan: Prevent an unsupported configurationc898e917d8
Bluetooth: L2CAP: Fix l2cap_global_chan_by_psm regressione81046da1d
Revert "net: usb: ax88179_178a needs FLAG_SEND_ZLP"a60996dc02
drm/vc4: change vc4_dma_range_matches from a global to static3422e24af9
drm/bridge: tc358767: Fix (e)DP bridge endpoint parsing in dedicated function2223b35c57
Revert "mwifiex: fix sleep in atomic context bugs caused by dev_coredumpv"8338305317
tcp: fix over estimation in sk_forced_mem_schedule()c35c01a7cb
mac80211: fix a memory leak where sta_info is not freedac7de8c2ba
KVM: x86: Avoid theoretical NULL pointer dereference in kvm_irq_delivery_to_apic_fast()4c85e207c1
KVM: x86: Check lapic_in_kernel() before attempting to set a SynIC irqa4c94205ba
KVM: Add infrastructure and macro to mark VM as bugged7018f03d97
net_sched: cls_route: remove from list when handle is 049dba30638
dm raid: fix address sanitizer warning in raid_statusc2d47bef93
dm raid: fix address sanitizer warning in raid_resumed0b495aa26
ext4: correct the misjudgment in ext4_iget_extra_inode603fb7bd74
ext4: correct max_inline_xattr_value_size computinge8c747496f
ext4: fix extent status tree race in writeback error recovery pathac8cc06114
ext4: update s_overhead_clusters in the superblock during an on-line resizebb8592efcf
ext4: fix use-after-free in ext4_xattr_set_entry69d1a36eb4
ext4: make sure ext4_append() always allocates new blocke1682c7171
ext4: fix warning in ext4_iomap_begin as race between bmap and write2da44a2927
ext4: add EXT4_INODE_HAS_XATTR_SPACE macro in xattr.h1571c46130
ext4: check if directory block is within i_sizee99da0f921
tracing: Use a struct alignof to determine trace event field alignment35508b60b5
tpm: eventlog: Fix section mismatch for DEBUG_SECTION_MISMATCH0e48eaf75d
KEYS: asymmetric: enforce SM2 signature use pkey algo135d9e0710
xen-blkfront: Apply 'feature_persistent' parameter when connectd4fb08e5a4
xen-blkback: Apply 'feature_persistent' parameter when connect9e84088452
xen-blkback: fix persistent grants negotiationb788508a09
KVM: x86/pmu: Ignore pmu->global_ctrl check if vPMU doesn't support global_ctrl6b4addec2f
KVM: VMX: Mark all PERF_GLOBAL_(OVF)_CTRL bits reserved if there's no vPMU46ec3d8e90
KVM: x86/pmu: Introduce the ctrl_mask value for fixed counter2ba1feb143
KVM: x86/pmu: Use different raw event masks for AMD and Intel4bbfc055d3
KVM: x86/pmu: Use binary search to check filtered events441726394e
KVM: x86/pmu: preserve IA32_PERF_CAPABILITIES across CPUID refresha7d0b21c6b
KVM: nVMX: Inject #UD if VMXON is attempted with incompatible CR0/CR4c72a9b1d0d
KVM: x86: Move vendor CR4 validity check to dedicated kvm_x86_ops hook2f04a04d06
KVM: SVM: Drop VMXE check from svm_set_cr4()da7f731f2e
KVM: VMX: Drop explicit 'nested' check from vmx_set_cr4()8b8b376903
KVM: VMX: Drop guest CPUID check for VMXE in vmx_set_cr4()5f3c8352cc
ACPI: CPPC: Do not prevent CPPC from working in the future40d28ae576
btrfs: reset block group chunk force if we have to waite2f1507303
btrfs: reject log replay if there is unsupported RO compat flagb58294ce1a
um: Allow PM with suspend-to-idlec6cf21d8d5
timekeeping: contribute wall clock to rng on time change5e2cf70515
dm thin: fix use-after-free crash in dm_sm_register_threshold_callback539c20ad26
kexec, KEYS, s390: Make use of built-in and secondary keyring for signature verification782e73acdb
dm writecache: set a default MAX_WRITEBACK_JOBSe41b3b8831
serial: 8250: Fold EndRun device support into OxSemi Tornado code194dc559e6
serial: 8250_pci: Replace dev_*() by pci_*() macros297e2fd08a
serial: 8250_pci: Refactor the loop in pci_ite887x_init()3110e5a49b
serial: 8250: Correct the clock for OxSemi PCIe devices3e9baedb32
serial: 8250: Dissociate 4MHz Titan ports from Oxford ports85d6306a87
PCI/AER: Iterate over error counters instead of error stringsd83d886e69
PCI/ERR: Recover from RCEC AER errorsbb6990fd37
PCI/ERR: Add pci_walk_bridge() to pcie_do_recovery()7730ba6151
PCI/ERR: Avoid negated conditional for clarity078d79fad5
PCI/ERR: Use "bridge" for clarity in pcie_do_recovery()2e3458b995
PCI/ERR: Simplify by computing pci_pcie_type() oncef236fa3850
PCI/ERR: Simplify by using pci_upstream_bridge()de4534ac28
PCI/ERR: Rename reset_link() to reset_subordinates()78d431e8a5
PCI/ERR: Bind RCEC devices to the Root Port driverdce8d7427c
PCI/AER: Write AER Capability only when we control it5659efdadf
iommu/vt-d: avoid invalid memory access via node_online(NUMA_NO_NODE)e7ccee2f09
KVM: x86: Signal #GP, not -EPERM, on bad WRMSR(MCi_CTL/STATUS)f5385a590d
KVM: set_msr_mce: Permit guests to ignore single-bit ECC errors6a84dae3a7
intel_th: pci: Add Raptor Lake-S CPU support581f7eb8ae
intel_th: pci: Add Raptor Lake-S PCH support36f5ddde67
intel_th: pci: Add Meteor Lake-P support08272646cd
firmware: arm_scpi: Ensure scpi_info is not assigned if the probe failsbc945ca496
usbnet: smsc95xx: Avoid link settings race on interrupt receptione9733561e9
usbnet: smsc95xx: Don't clear read-only PHY interrupt04c9d23ac3
mtd: rawnand: arasan: Fix clock rate in NV-DDRdc0e4a10b4
mtd: rawnand: arasan: Support NV-DDR interface87d1266b4c
mtd: rawnand: arasan: Fix a macro parameterd4f7bcce90
mtd: rawnand: Add NV-DDR timings72fae7e7f7
mtd: rawnand: arasan: Check the proposed data interface is supportedc91e5215a4
mtd: rawnand: Add a helper to clarify the interface configurationae1e2bc7bf
drm/vc4: drv: Adopt the dma configuration from the HVS or V3D componentfe695a2b46
HID: hid-input: add Surface Go battery quirk434c4aad53
HID: Ignore battery for Elan touchscreen on HP Spectre X360 15-df0xxx2d05cf1069
drm/mediatek: Keep dsi as LP00 before dcs cmds transfer3117287578
drm/mediatek: Allow commands to be sent during video modea3a85c045a
drm/i915/dg1: Update DMC_DEBUG3 registerdd02510fb4
spmi: trace: fix stack-out-of-bound access in SPMI tracing functionsbc8c5b3b3e
__follow_mount_rcu(): verify that mount_lock remains unchangedbda7046d4d
Input: gscps2 - check return value of ioremap() in gscps2_probe()541840859a
posix-cpu-timers: Cleanup CPU timers before freeing them during execce19182b43
x86/olpc: fix 'logical not is only applied to the left hand side'43e059d016
ftrace/x86: Add back ftrace_expected assignmentfd96b61389
x86/bugs: Enable STIBP for IBPB mitigated RETBleed1118020b3b
scsi: qla2xxx: Fix losing FCP-2 targets during port perturbation tests912408ba0b
scsi: qla2xxx: Fix losing FCP-2 targets on long port disable with I/Os82cb0ebe5b
scsi: qla2xxx: Fix erroneous mailbox timeout after PCI error injection7941ca578c
scsi: qla2xxx: Turn off multi-queue for 8G adapters2ffe5285ea
scsi: qla2xxx: Fix discovery issues in FC-AL topologyb8aad5eba7
scsi: zfcp: Fix missing auto port scan and thus missing target ports5e0da18956
video: fbdev: s3fb: Check the size of screen before memset_io()09e733d6ac
video: fbdev: arkfb: Check the size of screen before memset_io()bd8269e576
video: fbdev: vt8623fb: Check the size of screen before memset_io()a9943942a5
x86/entry: Build thunk_$(BITS) only if CONFIG_PREEMPTION=ye6c228b950
sched: Fix the check of nr_running at queue wakelistbd1ebcbbf0
tools/thermal: Fix possible path truncations0288fa799e
video: fbdev: arkfb: Fix a divide-by-zero bug in ark_set_pixclock()94398c1fec
x86/numa: Use cpumask_available instead of hardcoded NULL check336626564b
sched, cpuset: Fix dl_cpu_busy() panic due to empty cs->cpus_allowed0039189a3b
sched/deadline: Merge dl_task_can_attach() and dl_cpu_busy()e695256d46
scripts/faddr2line: Fix vmlinux detection on arm64232f4aca40
genelf: Use HAVE_LIBCRYPTO_SUPPORT, not the never defined HAVE_LIBCRYPTOcadeb5186e
powerpc/pci: Fix PHB numbering when using opal-phbid2a49b025c3
kprobes: Forbid probing on trampoline and BPF code areas4296089f61
perf symbol: Fail to read phdr workaround00dc7cbbb5
powerpc/cell/axon_msi: Fix refcount leak in setup_msi_msg_address6d1e53f7f1
powerpc/xive: Fix refcount leak in xive_get_max_prio85aff6a9b7
powerpc/spufs: Fix refcount leak in spufs_init_isolated_loader50e7896c8e
f2fs: fix to remove F2FS_COMPR_FL and tag F2FS_NOCOMP_FL at the same timeec769406d0
f2fs: write checkpoint during FG_GCd031105739
f2fs: don't set GC_FAILURE_PIN for background GC47a8fe1b15
powerpc/pci: Prefer PCI domain assignment via DT 'linux,pci-domain' and alias7ac58a83d8
powerpc/32: Do not allow selection of e5500 or e6500 CPUs on PPC322d2b6adb22
ASoC: mchp-spdifrx: disable end of block interrupt on failuresca326aff6b
video: fbdev: sis: fix typos in SiS_GetModeID()da276dc288
video: fbdev: amba-clcd: Fix refcount leak bugs345208581c
watchdog: armada_37xx_wdt: check the return value of devm_ioremap() in armada_37xx_wdt_probe()d3e6460619
ASoC: audio-graph-card: Add of_node_put() in fail path92644d505b
fuse: Remove the control interface for virtio-fs60e494b4d5
ASoC: qcom: q6dsp: Fix an off-by-one in q6adm_alloc_copp()5682b4f84a
ASoC: fsl_easrc: use snd_pcm_format_t type for sample_format9c2ad32ed9
s390/zcore: fix race when reading from hardware system areaae921d176b
s390/dump: fix old lowcore virtual vs physical address confusionb002a71d45
perf tools: Fix dso_id inode generation comparison2ada6b4a80
iommu/arm-smmu: qcom_iommu: Add of_node_put() when breaking out of loopafdbadbf18
mfd: max77620: Fix refcount leak in max77620_initialise_fps52ae9c1599
mfd: t7l66xb: Drop platform disable callback5a0e3350c2
remoteproc: sysmon: Wait for SSCTL service to come up3487aa558a
lib/smp_processor_id: fix imbalanced instrumentation_end() call483ad8a16f
kfifo: fix kfifo_to_user() return type9715809b9e
rpmsg: qcom_smd: Fix refcount leak in qcom_smd_parse_edge0ce20194b4
iommu/exynos: Handle failed IOMMU device registration properly8fd063a608
tty: n_gsm: fix missing corner cases in gsmld_poll()01c8094bed
tty: n_gsm: fix DM command6737d4f5f5
tty: n_gsm: fix wrong T1 retry count handlingb16d653bc7
vfio/ccw: Do not change FSM state in subchannel eventdb574d3bb6
vfio/mdev: Make to_mdev_device() into a static inlinea2fbf4acd2
vfio: Split creation of a vfio_device into init and register opsf54fa910e6
vfio: Simplify the lifetime logic for vfio_device0abdb80e81
vfio: Remove extra put/gets around vfio_device->groupcb83b12320
remoteproc: qcom: wcnss: Fix handling of IRQs2f735069cd
ASoC: qcom: Fix missing of_node_put() in asoc_qcom_lpass_cpu_platform_probe()273d412177
tty: n_gsm: fix race condition in gsmld_write()2466486cae
tty: n_gsm: fix packet re-transmission without open control channel34c9fe392d
tty: n_gsm: fix non flow control frames during mux flow off006e9d5a98
tty: n_gsm: fix wrong queuing behavior in gsm_dlci_data_output()c45b5d24fe
tty: n_gsm: fix user open not possible at responder until initiator open9e38020f17
tty: n_gsm: Delete gsmtty open SABM frame when config requesterd94a552183
ASoC: samsung: change gpiod_speaker_power and rx1950_audio from global to static variables875b2bf469
powerpc/perf: Optimize clearing the pending PMI and remove WARN_ON for PMI check in power_pmu_disableba889da9a0
ASoC: samsung: h1940_uda1380: include proepr GPIO consumer header4046f3ef3b
profiling: fix shift too large makes kernel panic3bf64b9cc6
selftests/livepatch: better synchronize test_klp_callbacks_busy75358732af
remoteproc: k3-r5: Fix refcount leak in k3_r5_cluster_of_init2aa8737d49
rpmsg: mtk_rpmsg: Fix circular locking dependency1d5fc40382
ASoC: codecs: wcd9335: move gains from SX_TLV to S8_TLV4181b21418
ASoC: codecs: msm8916-wcd-digital: move gains from SX_TLV to S8_TLV4b171ac88c
serial: 8250_dw: Store LSR into lsr_saved_flags in dw8250_tx_wait_empty()d98dd16d3d
serial: 8250: Export ICR access helpers for internal use403d469719
ASoC: mediatek: mt8173-rt5650: Fix refcount leak in mt8173_rt5650_dev_probe132b2757c5
ASoC: codecs: da7210: add check for i2c_add_drivera0381a9f3e
ASoC: mt6797-mt6351: Fix refcount leak in mt6797_mt6351_dev_probeaa1214ece3
ASoC: mediatek: mt8173: Fix refcount leak in mt8173_rt5650_rt5676_dev_probeec0c272b18
ASoC: samsung: Fix error handling in aries_audio_probebae95c5aee
ASoC: cros_ec_codec: Fix refcount leak in cros_ec_codec_platform_probee2a4e46f52
opp: Fix error check in dev_pm_opp_attach_genpd()3b97370322
usb: cdns3: Don't use priv_dev uninitialized in cdns3_gadget_ep_enable()f7161d0da9
jbd2: fix assertion 'jh->b_frozen_data == NULL' failure when journal aborteda6d7f22473
ext4: recover csum seed of tmp_inode after migrating to extents914bf4aa2d
jbd2: fix outstanding credits assert in jbd2_journal_commit_transaction()706960d328
nvme: use command_id instead of req->tag in trace_nvme_complete_rq()7a4b46784a
null_blk: fix ida error handling in null_add_dev()3ef491b26c
RDMA/rxe: Fix error unwind in rxe_create_qp()53da1f0fa0
RDMA/mlx5: Add missing check for return value in get namespace flowc0ba87f3e7
selftests: kvm: set rax before vmcall4ffa6cecb5
mm/mmap.c: fix missing call to vm_unacct_memory in mmap_regionde95b52d9a
RDMA/srpt: Fix a use-after-freed14a44cf29
RDMA/srpt: Introduce a reference count in struct srpt_device204a8486d7
RDMA/srpt: Duplicate port name members5ba56d9bd0
platform/olpc: Fix uninitialized data in debugfs write7af83bb516
usb: cdns3: change place of 'priv_ep' assignment in cdns3_gadget_ep_dequeue(), cdns3_gadget_ep_enable()a916e80360
USB: serial: fix tty-port initialized commentsb1124a2f47
PCI: tegra194: Fix link up retry sequence88a694d9c8
PCI: tegra194: Fix Root Port interrupt handlinge2d132ca7f
HID: alps: Declare U1_UNICORN_LEGACY support74e57439e2
mmc: cavium-thunderx: Add of_node_put() when breaking out of loop3bed7b9811
mmc: cavium-octeon: Add of_node_put() when breaking out of loop66c8e816f2
HID: mcp2221: prevent a buffer overflow in mcp_smbus_write()26975d8ea9
gpio: gpiolib-of: Fix refcount bugs in of_mm_gpiochip_add_data()a85c7dd1ed
RDMA/hfi1: fix potential memory leak in setup_base_ctxt()9ade92ddaf
RDMA/siw: Fix duplicated reported IW_CM_EVENT_CONNECT_REPLY event0ecc91cf96
RDMA/hns: Fix incorrect clearing of interrupt status register79ce50ddda
RDMA/qedr: Fix potential memory leak in __qedr_alloc_mr()aaa1a81506
RDMA/qedr: Improve error logs for rdma_alloc_tid error return84f83a2619
RDMA/rtrs-srv: Fix modinfo output for stringify50a249ad1d
RDMA/rtrs: Avoid Wtautological-constant-out-of-range-compare2b3dcfbece
RDMA/rtrs: Define MIN_CHUNK_SIZE993cd16211
um: random: Don't initialise hwrng struct with zeroa6a7f80e62
interconnect: imx: fix max_node_id5bcc37dc24
eeprom: idt_89hpesx: uninitialized data in idt_dbgfs_csr_write()4ab5662cc3
usb: dwc3: qcom: fix missing optional irq warningsd376ca6716
usb: dwc3: core: Do not perform GCTL_CORE_SOFTRESET during bootup251572a26d
usb: dwc3: core: Deprecate GCTL.CORESOFTRESETe6db5780c2
usb: aspeed-vhub: Fix refcount leak bug in ast_vhub_init_desc()c818fa991c
usb: gadget: udc: amd5536 depends on HAS_DMAd6d344eeef
xtensa: iss: fix handling error cases in iss_net_configure()fb4c1555f9
xtensa: iss/network: provide release() callback2fe0b06c16
scsi: smartpqi: Fix DMA direction for RAID requests7542130af1
PCI: qcom: Set up rev 2.1.0 PARF_PHY before enabling clocksee70aa214a
PCI/portdrv: Don't disable AER reporting in get_port_device_capability()9d216035d1
KVM: s390: pv: leak the topmost page table when destroy fails59fd7c0b41
mmc: block: Add single read for 4k sector cards2985acdaf2
mmc: sdhci-of-at91: fix set_uhs_signaling rewriting of MC1R9260a154b3
memstick/ms_block: Fix a memory leakae2369ac42
memstick/ms_block: Fix some incorrect memory allocationb305475df7
mmc: sdhci-of-esdhc: Fix refcount leak in esdhc_signal_voltage_switch028c8632a2
staging: rtl8192u: Fix sleep in atomic context bug in dm_fsync_timer_callback6ae2881c1d
intel_th: msu: Fix vmalloced buffers81222cfda6
intel_th: msu-sink: Potential dereference of null pointera8f3b78b1f
intel_th: Fix a resource leak in an error handling pathab3b82435f
PCI: endpoint: Don't stop controller when unbinding endpoint functionb9b4992f89
dmaengine: sf-pdma: Add multithread support for a DMA channel37e1d474a3
dmaengine: sf-pdma: apply proper spinlock flags in sf_pdma_prep_dma_memcpy()38715a0ccb
KVM: arm64: Don't return from void functionfbd7b564f9
soundwire: bus_type: fix remove and shutdown supported457b0029
PCI: dwc: Always enable CDM check if "snps,enable-cdm-check" existse7599a5974
PCI: dwc: Deallocate EPC memory on dw_pcie_ep_init() errors80d9f6541e
PCI: dwc: Add unroll iATU space support to dw_pcie_disable_atu()2293b23d27
clk: qcom: camcc-sdm845: Fix topology around titan_top power domainb28ebe7d2f
clk: qcom: ipq8074: set BRANCH_HALT_DELAY flag for UBI clocksb83af7b4ec
clk: qcom: ipq8074: fix NSS port frequency tables58023f5291
clk: qcom: ipq8074: SW workaround for UBI32 PLL locke2330494f0
clk: qcom: ipq8074: fix NSS core PLL-sb840c2926d
usb: host: xhci: use snprintf() in xhci_decode_trb()42f1827096
clk: qcom: clk-krait: unlock spin after mux completiona93f33aeef
driver core: fix potential deadlock in __driver_attach2593f971f0
misc: rtsx: Fix an error handling path in rtsx_pci_probe()267c5f17a0
dmaengine: dw-edma: Fix eDMA Rd/Wr-channels and DMA-direction semantics956b79c206
mwifiex: fix sleep in atomic context bugs caused by dev_coredumpv803526555b
mwifiex: Ignore BTCOEX events from the 88W8897 firmwaredceedbb5ab
KVM: Don't set Accessed/Dirty bits for ZERO_PAGE02d203f488
clk: mediatek: reset: Fix written reset bit offset4f51a09f3d
iio: accel: bma400: Reordering of header filesab831a12c8
platform/chrome: cros_ec: Always expose last resume result366d0123c3
iio: accel: bma400: Fix the scale min and max macro valuesedfa0851d8
netfilter: xtables: Bring SPDX identifier back9feb3ecd07
usb: xhci: tegra: Fix error checkbb5e59f00f
usb: gadget: tegra-xudc: Fix error check in tegra_xudc_powerdomain_init()d35903e965
usb: ohci-nxp: Fix refcount leak in ohci_hcd_nxp_probe585d22a562
usb: host: Fix refcount leak in ehci_hcd_ppc_of_probe474f12deaa
fpga: altera-pr-ip: fix unsigned comparison with less than zero175428c86f
mtd: st_spi_fsm: Add a clk_disable_unprepare() in .probe()'s error path55d0f7da66
mtd: partitions: Fix refcount leak in parse_redboot_ofb4e150d295
mtd: sm_ftl: Fix deadlock caused by cancel_work_sync in sm_releaseebda3d6b00
HID: cp2112: prevent a buffer overflow in cp2112_xfer()cdf92a0aee
PCI: tegra194: Fix PM error handling in tegra_pcie_config_ep()b0e82f95fd
mtd: rawnand: meson: Fix a potential double free issue941ef6997f
mtd: maps: Fix refcount leak in ap_flash_init52ae2b14f7
mtd: maps: Fix refcount leak in of_flash_probe_versatile6471c83894
clk: renesas: r9a06g032: Fix UART clkgrp bitsel38c9cc68e3
wireguard: allowedips: don't corrupt stack when detecting overflow17541a4aab
wireguard: ratelimiter: use hrtimer in selftestaa8f559336
dccp: put dccp_qpolicy_full() and dccp_qpolicy_push() in the same lock5b69f34dac
net: ionic: fix error check for vlan flags in ionic_set_nic_features()9a070a4417
net: rose: fix netdev reference changes397e52dec1
netdevsim: Avoid allocation warnings triggered from user space692751f260
iavf: Fix max_rate limitingb0d67ef5b4
net: allow unbound socket for packets in VRF when tcp_l3mdev_accept set1d9c81833d
tcp: Fix data-races around sysctl_tcp_l3mdev_accept.0de9b3f81e
ipv6: add READ_ONCE(sk->sk_bound_dev_if) in INET6_MATCH()b7325b27d8
tcp: sk->sk_bound_dev_if once in inet_request_bound_dev_if()f7884d9500
inet: add READ_ONCE(sk->sk_bound_dev_if) in INET_MATCH()c206177ca8
crypto: hisilicon/sec - fix auth key size error9524edb1a7
crypto: inside-secure - Add missing MODULE_DEVICE_TABLE for ofcb62775079
crypto: hisilicon/hpre - don't use GFP_KERNEL to alloc mem during softirqe6cbd15950
net/mlx5e: Fix the value of MLX5E_MAX_RQ_NUM_MTTS1f7ffdea19
net/mlx5e: Remove WARN_ON when trying to offload an unsupported TLS cipher/version420cf3b781
media: cedrus: hevc: Add check for invalid timestamp97e5d3e46a
wifi: libertas: Fix possible refcount leak in if_usb_probe()38d71acc15
wifi: iwlwifi: mvm: fix double list_add at iwl_mvm_mac_wake_tx_queue6c5fee83bd
wifi: wil6210: debugfs: fix uninitialized variable use in `wil_write_file_wmi()`c040a02e4c
i2c: mux-gpmux: Add of_node_put() when breaking out of loop353d55ff1b
i2c: cadence: Support PEC for SMBus block read0c5dbac1ce
Bluetooth: hci_intel: Add check for platform_driver_registera7a7488cb1
can: pch_can: pch_can_error(): initialize errc before using it4c036be757
can: error: specify the values of data[5..7] of CAN error framesf0ef21b739
can: usb_8dev: do not report txerr and rxerr during bus-offca1a2c5388
can: kvaser_usb_leaf: do not report txerr and rxerr during bus-off9e6ceba6be
can: kvaser_usb_hydra: do not report txerr and rxerr during bus-offcddef4bbeb
can: sun4i_can: do not report txerr and rxerr during bus-off22e382d47d
can: hi311x: do not report txerr and rxerr during bus-off06e355b46c
can: sja1000: do not report txerr and rxerr during bus-off6ec509679b
can: rcar_can: do not report txerr and rxerr during bus-off5d85a89875
can: pch_can: do not report txerr and rxerr during bus-offd2b9e664bb
selftests/bpf: fix a test for snprintf() overflowa06c98c47e
wifi: p54: add missing parentheses in p54_flush()56924fc19d
wifi: p54: Fix an error handling path in p54spi_probe()05ceda14ef
wifi: wil6210: debugfs: fix info leak in wil_write_file_wmi()36ba389960
fs: check FMODE_LSEEK to control internal pipe splicing7430e58764
bpf: Fix subprog names in stack traces.990ca39e78
selftests: timers: clocksource-switch: fix passing errors from childee3cc4c761
selftests: timers: valid-adjtimex: build fix for newer toolchainsf29cf37698
libbpf: Fix the name of a reused map799cfed1b1
tcp: make retransmitted SKB fit into the send window5713b0be6d
drm/exynos/exynos7_drm_decon: free resources when clk_set_parent() failed.9aa4ad5cca
mediatek: mt76: mac80211: Fix missing of_node_put() in mt76_led_init()3ad958bc48
mt76: mt76x02u: fix possible memory leak in __mt76x02u_mcu_send_msgb1812f6500
media: platform: mtk-mdp: Fix mdp_ipi_comm structure alignment1008c6d98b
crypto: hisilicon - Kunpeng916 crypto driver don't sleep when in softirq16e18a8ac7
crypto: hisilicon/sec - don't sleep when in softirq1f697d7952
crypto: hisilicon/sec - fixes some coding stylebf386c955f
drm/msm/mdp5: Fix global state lock backoffe74f3097a9
net: hinic: avoid kernel hung in hinic_get_stats64()e286a882f2
net: hinic: fix bug that ethtool get wrong stats8369a39b52
hinic: Use the bitmap API when applicable26a10aef28
lib: bitmap: provide devm_bitmap_alloc() and devm_bitmap_zalloc()1238da5f32
lib: bitmap: order includes alphabetically7f29d75693
drm: bridge: sii8620: fix possible off-by-one8bb0be3186
drm/mediatek: dpi: Only enable dpi after the bridge is enabledc47d69ed56
drm/mediatek: dpi: Remove output format of YUVfc85cb33f6
drm/rockchip: Fix an error handling path rockchip_dp_probe()9f416e32ed
drm/rockchip: vop: Don't crash for invalid duplicate_state()e2d2dcab19
selftests/xsk: Destroy BPF resources only when ctx refcount drops to 064b1e3f904
crypto: arm64/gcm - Select AEAD for GHASH_ARM64_CE2e306d74ad
drm/vc4: hdmi: Correct HDMI timing registers for interlaced modes36f797a10f
drm/vc4: hdmi: Fix timings for interlaced modes717325e814
drm/vc4: hdmi: Limit the BCM2711 to the max without scramblingc015d12317
drm/vc4: hdmi: Don't access the connector state in reset if kmalloc failsba8ffdb450
drm/vc4: hdmi: Avoid full hdmi audio fifo writesb161b27067
drm/vc4: hdmi: Remove firmware logic for MAI threshold settingcefc8e7e0e
drm/vc4: dsi: Add correct stop condition to vc4_dsi_encoder_disable iterationacfca24ec0
drm/vc4: dsi: Fix dsi0 interrupt support97c2fa3a7b
drm/vc4: dsi: Register dsi0 as the correct vc4 encoder type6cc1edddcf
drm/vc4: dsi: Introduce a variant structure79374da862
drm/vc4: dsi: Use snprintf for the PHY clocks instead of an array1f98187a7c
drm/vc4: drv: Remove the DSI pointer in vc4_drved2f42bd80
drm/vc4: dsi: Correct pixel order for DSI0ddf6af3b0b
drm/vc4: dsi: Correct DSI divider calculationsf517da5234
drm/vc4: plane: Fix margin calculations for the right/bottom edges5aec7cb08b
drm/vc4: plane: Remove subpixel positioning check611f86965d
media: tw686x: Fix memory leak in tw686x_video_init7f7336ce35
media: v4l2-mem2mem: prevent pollerr when last_buffer_dequeued is setbb480bffc1
media: hdpvr: fix error value returns in hdpvr_readf57699a9b6
drm/mcde: Fix refcount leak in mcde_dsi_bind6a43236ebc
drm: bridge: adv7511: Add check for mipi_dsi_driver_register87af9b0b45
crypto: ccp - During shutdown, check SEV data pointer before using5f8a6e8f14
test_bpf: fix incorrect netdev features45e1dbe5f6
drm/radeon: fix incorrrect SPDX-License-Identifierse7d6cac696
wifi: iwlegacy: 4965: fix potential off-by-one overflow in il4965_rs_fill_link_cmd()eccd7c3e25
ath9k: fix use-after-free in ath9k_hif_usb_rx_cb918f42ca1d
media: tw686x: Register the irq at the end of probed45eaf4114
crypto: sun8i-ss - fix infinite loop in sun8i_ss_setup_ivs()81cb317568
i2c: Fix a potential use after freed0412d8f69
net: fix sk_wmem_schedule() and sk_rmem_schedule() errors0e70bb9cdb
crypto: sun8i-ss - fix error codes in allocate_flows()e8673fbc10
crypto: sun8i-ss - do not allocate memory when handling hash requests648b1bb29a
drm: adv7511: override i2c address of cec before accessing it259773fc87
virtio-gpu: fix a missing check to avoid NULL dereferencee28aa4f467
i2c: npcm: Correct slave role behavior385f6ef4de
i2c: npcm: Remove own slave addresses 2:105ce9cff371
drm/mediatek: Add pull-down MIPI operation in mtk_dsi_poweroff functionb54bc0013d
drm/mediatek: Separate poweron/poweroff from enable/disable and define new funcs0cb6589885
drm/mediatek: Modify dsi funcs to atomic operations8508d6d23a
drm/radeon: fix potential buffer overflow in ni_set_mc_special_registers()ac22537643
ath11k: Fix incorrect debug_mask mappings648d3c8714
drm/mipi-dbi: align max_chunk to 2 in spi_transfera2c45f8c3d
ath11k: fix netdev open race58fd794675
wifi: rtlwifi: fix error codes in rtl_debugfs_set_write_h2c()71426d31d0
drm/st7735r: Fix module autoloading for Okaya RH128128Tfd98ccda50
ath10k: do not enforce interrupt trigger typebcc05372a2
drm/bridge: tc358767: Make sure Refclk clock are enabledc038b9b733
drm/bridge: tc358767: Move (e)DP bridge endpoint parsing into dedicated functionf312bc33ca
pwm: lpc18xx-sct: Convert to devm_platform_ioremap_resource()6aaac1d924
pwm: sifive: Shut down hardware only after pwmchip_remove() completed9073dbec88
pwm: sifive: Ensure the clk is enabled exactly once per running PWM47902de24a
pwm: sifive: Simplify offset calculation for PWMCMP registers6d7f7ffbcd
pwm: sifive: Don't check the return code of pwmchip_remove()b7e2d64d67
dm: return early from dm_pr_call() if DM device is suspendedb3f5cc0cc0
thermal/tools/tmon: Include pthread and time headers in tmon.h7aa3a25599
selftests/seccomp: Fix compile warning when CC=clange06a31e61f
nohz/full, sched/rt: Fix missed tick-reenabling bug in dequeue_task_rt()298417471e
drivers/perf: arm_spe: Fix consistency of SYS_PMSCR_EL1.CXa1891d3df7
arm64: dts: qcom: qcs404: Fix incorrect USB2 PHYs assignmenta7753a260e
soc: qcom: Make QCOM_RPMPD depend on PM332e555dca
regulator: of: Fix refcount leak bug in of_get_regulation_constraints()1ed71e6bce
blktrace: Trace remapped requests correctly1cb3032406
block: remove the request_queue to argument request based tracepointsd125b13a66
hwmon: (drivetemp) Add module aliased6ae23811
blk-mq: don't create hctx debugfs dir until q->debugfs_dir is created0ca556256f
erofs: avoid consecutive detection for Highmem memory8dee22b457
arm64: tegra: Fix SDMMC1 CD on P2888a1e2386909
arm64: dts: mt7622: fix BPI-R64 WPS button7eafa9a1aa
bus: hisi_lpc: fix missing platform_device_put() in hisi_lpc_acpi_probe()7fcf4401d5
ARM: dts: qcom: pm8841: add required thermal-sensor-cells97713ed9b6
soc: qcom: aoss: Fix refcount leak in qmp_cooling_devices_register07aea6819d
soc: qcom: ocmem: Fix refcount leak in of_get_ocmem71042279b1
ACPI: APEI: Fix _EINJ vs EFI_MEMORY_SP5f29b045da
regulator: qcom_smd: Fix pm8916_pldo range22e6d8bcde
cpufreq: zynq: Fix refcount leak in zynq_get_revisiond294d60dc6
ARM: OMAP2+: Fix refcount leak in omap3xxx_prm_late_init14bac0c703
ARM: OMAP2+: Fix refcount leak in omapdss_init_offdcb1fdbdc
ARM: dts: qcom: mdm9615: add missing PMIC GPIO regc32d5491c8
block: fix infinite loop for invalid zone append2d9a1a96eb
soc: fsl: guts: machine variable might be unset4cea839177
locking/lockdep: Fix lockdep_init_map_*() confusion87e415aec4
arm64: cpufeature: Allow different PMU versions in ID_DFR0_EL130119131e3
hexagon: select ARCH_WANT_LD_ORPHAN_WARN9d744229cd
ARM: dts: ast2600-evb: fix board compatible75a24da2b9
ARM: dts: ast2500-evb: fix board compatible2c07688d3e
x86/pmem: Fix platform-device leak in error path6a28f363d3
arm64: dts: renesas: Fix thermal-sensors on single-zone sensors80c469e63b
soc: amlogic: Fix refcount leak in meson-secure-pwrc.c6cd8ba0c0b
soc: renesas: r8a779a0-sysc: Fix A2DP1 and A2CV[2357] PDR values6771609e19
Input: atmel_mxt_ts - fix up inverted RESET handler11903c5457
ARM: dts: imx7d-colibri-emmc: add cpu1 supplyb8b1f0d74f
ACPI: processor/idle: Annotate more functions to live in cpuidle section91e7f04f53
ARM: bcm: Fix refcount leak in bcm_kona_smc_initf6a6cc6d57
arm64: dts: renesas: beacon: Fix regulator node names2691b8780f
meson-mx-socinfo: Fix refcount leak in meson_mx_socinfo_initccf56ea52b
ARM: findbit: fix overflowing offset71fc6e0dca
spi: spi-rspi: Fix PIO fallback on RZ platforms4234c5f34e
powerpc/64s: Disable stack variable initialisation for prom_initadbfdaacde
selinux: Add boundary check in put_entry()003a456ae6
PM: hibernate: defer device probing when resuming from hibernation70bccff899
firmware: tegra: Fix error check return value of debugfs_create_file()c2e53a1b07
ARM: shmobile: rcar-gen2: Increase refcount for new referencef48cec5736
arm64: dts: allwinner: a64: orangepi-win: Fix LED node namefcdc1e13e0
arm64: dts: qcom: ipq8074: fix NAND node name931d0a574c
ACPI: LPSS: Fix missing check in register_device_clock()d257d9b0a4
ACPI: PM: save NVS memory for Lenovo G40-4585bc8689a7
ACPI: EC: Drop the EC_FLAGS_IGNORE_DSDT_GPE quirkdef469523d
ACPI: EC: Remove duplicate ThinkPad X1 Carbon 6th entry from DMI quirks88d556029a
ARM: OMAP2+: display: Fix refcount leak bug43157bc5f9
spi: synquacer: Add missing clk_disable_unprepare()607570808a
ARM: dts: BCM5301X: Add DT for Meraki MR269213e5a397
ARM: dts: imx6ul: fix qspi node compatible976db15fee
ARM: dts: imx6ul: fix lcdif node compatible6045ac40e3
ARM: dts: imx6ul: fix csi node compatiblec7ce841f48
ARM: dts: imx6ul: fix keypad compatible15af2deb19
ARM: dts: imx6ul: change operating-points to uint32-matrix278aa4c73d
ARM: dts: imx6ul: add missing properties for sram695a3c2a82
wait: Fix __wait_event_hrtimeout for RT/DL tasks2b8c55900d
irqchip/mips-gic: Check the return value of ioremap() in gic_of_init()8dfb4a99b1
genirq: GENERIC_IRQ_IPI depends on SMPf460141f29
irqchip/mips-gic: Only register IPI domain when SMP is enabled4aba3247af
genirq: Don't return error on missing optional irq_request_resources()d08bb199a4
ext2: Add more validity checks for inode counts353b4673d0
arm64: fix oops in concurrently setting insn_emulation sysctls913f173237
arm64: Do not forget syscall when starting a new thread.fb086aea39
x86: Handle idle=nomwait cmdline properly for x86_idle48c3900210
epoll: autoremove wakers even more aggressively80977126bc
netfilter: nf_tables: fix null deref due to zeroed list head0cc5c6b756
netfilter: nf_tables: do not allow RULE_ID to refer to another chain9e7dcb88ec
netfilter: nf_tables: do not allow CHAIN_ID to refer to another table1a4b18b1ff
netfilter: nf_tables: do not allow SET_ID to refer to another table19bf7199c3
lockdep: Allow tuning tracing capacity constants.f294829fb4
usb: dwc3: gadget: fix high speed multiplier settingfc2a039cdb
usb: dwc3: gadget: refactor dwc3_repare_one_trb9a3a61bd73
arm64: dts: uniphier: Fix USB interrupts for PXs3 SoC63228d8328
ARM: dts: uniphier: Fix USB interrupts for PXs2 SoC4d7da7e565
USB: HCD: Fix URB giveback issue in tasklet function37c7fe9b31
usb: typec: ucsi: Acknowledge the GET_ERROR_STATUS command completion847b9273dd
coresight: Clear the connection field properly807adf6ffa
MIPS: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK26d767990e
powerpc/powernv: Avoid crashing if rng is NULL3db593ab8e
powerpc/ptdump: Fix display of RW pages on FSL_BOOK3Eb326b8d6ae
powerpc/fsl-pci: Fix Class Code of PCIe Root Port39c51471ef
PCI: Add defines for normal and subtractive PCI bridges23c2f921f2
ia64, processor: fix -Wincompatible-pointer-types in ia64_get_irr()2f36ba13cb
media: [PATCH] pci: atomisp_cmd: fix three missing checks on list iterator5fd4ffa237
md-raid10: fix KASAN warninge0bdaed154
md-raid: destroy the bitmap after destroying the thread3bdda8656a
serial: mvebu-uart: uart2 error bits clearingcfe17ae313
fuse: limit nsece63ea5814b
scsi: qla2xxx: Zero undefined mailbox IN registers6f18b5ad2d
scsi: qla2xxx: Fix incorrect display of max frame size408bfa1489
scsi: sg: Allow waiting for commands to complete on removed devicefb1888205c
iio: light: isl29028: Fix the warning in isl29028_remove()fb7eea3946
mtd: rawnand: arasan: Update NAND bus clock instead of system clock15d0aeb017
drm/amdgpu: Check BO's requested pinning domains against its preferred_domains55f5584427
drm/nouveau/acpi: Don't print error when we get -EINPROGRESS from pm_runtime92050011e0
drm/nouveau: Don't pm_runtime_put_sync(), only pm_runtime_put_autosuspend()ca0742a8ed
drm/nouveau: fix another off-by-one in nvbios_addrde63dbc296
drm/vc4: hdmi: Disable audio if dmas property is present but empty1ff71d4f53
drm/gem: Properly annotate WW context on drm_gem_lock_reservations() error043f4642c1
parisc: io_pgetevents_time64() needs compat syscall in 32-bit compat modefc3918d70b
parisc: Check the return value of ioremap() in lba_driver_probe()b0dfba6d3b
parisc: Fix device names in /proc/iomem542d2e799d
ovl: drop WARN_ON() dentry is NULL in ovl_encode_fh()135199a2ed
usbnet: Fix linkwatch use-after-free on disconnectd65c3fcd6d
fbcon: Fix accelerated fbdev scrolling while logo is still shown16badd9987
fbcon: Fix boundary checks for fbcon=vc:n1-n2 parameters826955eebc
thermal: sysfs: Fix cooling_device_stats_setup() error code path60a8f0e62a
fs: Add missing umask strip in vfs_tmpfilecf65b5bfac
vfs: Check the truncate maximum size in inode_newsize_ok()5c6c65681f
tty: vt: initialize unicode screen bufferf9b244e541
ALSA: hda/realtek: Add a quirk for HP OMEN 15 (8786) mute LED7b9ee47c28
ALSA: hda/realtek: Add quirk for another Asus K42JZ modelc366ccad5b
ALSA: hda/cirrus - support for iMac 12,1 modelf2b72c51c2
ALSA: hda/conexant: Add quirk for LENOVO 20149 Notebook model2613baa3ab
mm/mremap: hold the rmap lock in write mode when moving page table entries.0a69f1f842
xfs: fix I_DONTCACHEe32bb24281
xfs: only set IOMAP_F_SHARED when providing a srcmap to a writef5f3e54f81
mm: Add kvrealloc()3ff605513f
riscv: set default pm_power_off to NULL230e369d49
KVM: x86: Tag kvm_mmu_x86_module_init() with __init0dd8ba6670
KVM: x86: Set error code to segment selector on LLDT/LTR non-canonical #GP68ba319b88
KVM: x86: Mark TSS busy during LTR emulation _after_ all fault checksb670a58549
KVM: nVMX: Let userspace set nVMX MSR to any _host_ supported valuee9c55562b3
KVM: s390: pv: don't present the ecall interrupt twice8bb6834902
KVM: SVM: Don't BUG if userspace injects an interrupt with GIF=0860e334395
KVM: nVMX: Snapshot pre-VM-Enter DEBUGCTL for !nested_run_pending caseab4805c263
KVM: nVMX: Snapshot pre-VM-Enter BNDCFGS for !nested_run_pending case40593c5898
HID: wacom: Don't register pad_input for touch switch0ba645def7
HID: wacom: Only report rotation for art pen57f2ee517d
add barriers to buffer_uptodate and set_buffer_uptodate6dece5ad6e
wifi: mac80211_hwsim: use 32-bit skb cookied400222f49
wifi: mac80211_hwsim: add back erroneously removed casteb8fc4277b
wifi: mac80211_hwsim: fix race condition in pending packet9a22b1f7da
ALSA: hda/realtek: Add quirk for HP Spectre x360 15-eb0xxxd909d9bdc8
ALSA: hda/realtek: Add quirk for Clevo NV45PZ348620464a
ALSA: bcd2000: Fix a UAF bug on the error path of probing101e0c052d
scsi: Revert "scsi: qla2xxx: Fix disk failure to rediscover"14eb40fd79
Revert "pNFS: nfs3_set_ds_client should set NFS_CS_NOPING"4ad6a94c68
x86: link vdso and boot with -z noexecstack --no-warn-rwx-segments8f4f2c9b98
Makefile: link with -z noexecstack --no-warn-rwx-segments Add the following symbol as needed by the -lts merge: Leaf changes summary: 1 artifact changed Changed leaf types summary: 0 leaf type changed Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 1 Added function Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable 1 Added function: [A] 'function ssize_t strscpy_pad(char*, const char*, size_t)' Change-Id: I7b4e08152fafe9bf2285afd207af47481eb9c774 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
4055 lines
101 KiB
C
4055 lines
101 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Block multiqueue core code
|
|
*
|
|
* Copyright (C) 2013-2014 Jens Axboe
|
|
* Copyright (C) 2013-2014 Christoph Hellwig
|
|
*/
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/backing-dev.h>
|
|
#include <linux/bio.h>
|
|
#include <linux/blkdev.h>
|
|
#include <linux/kmemleak.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/init.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/llist.h>
|
|
#include <linux/list_sort.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/cache.h>
|
|
#include <linux/sched/sysctl.h>
|
|
#include <linux/sched/topology.h>
|
|
#include <linux/sched/signal.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/crash_dump.h>
|
|
#include <linux/prefetch.h>
|
|
#include <linux/blk-crypto.h>
|
|
|
|
#include <trace/events/block.h>
|
|
|
|
#include <linux/blk-mq.h>
|
|
#include <linux/t10-pi.h>
|
|
#include "blk.h"
|
|
#include "blk-mq.h"
|
|
#include "blk-mq-debugfs.h"
|
|
#include "blk-mq-tag.h"
|
|
#include "blk-pm.h"
|
|
#include "blk-stat.h"
|
|
#include "blk-mq-sched.h"
|
|
#include "blk-rq-qos.h"
|
|
|
|
#include <trace/hooks/block.h>
|
|
|
|
static DEFINE_PER_CPU(struct list_head, blk_cpu_done);
|
|
|
|
static void blk_mq_poll_stats_start(struct request_queue *q);
|
|
static void blk_mq_poll_stats_fn(struct blk_stat_callback *cb);
|
|
|
|
static int blk_mq_poll_stats_bkt(const struct request *rq)
|
|
{
|
|
int ddir, sectors, bucket;
|
|
|
|
ddir = rq_data_dir(rq);
|
|
sectors = blk_rq_stats_sectors(rq);
|
|
|
|
bucket = ddir + 2 * ilog2(sectors);
|
|
|
|
if (bucket < 0)
|
|
return -1;
|
|
else if (bucket >= BLK_MQ_POLL_STATS_BKTS)
|
|
return ddir + BLK_MQ_POLL_STATS_BKTS - 2;
|
|
|
|
return bucket;
|
|
}
|
|
|
|
/*
|
|
* Check if any of the ctx, dispatch list or elevator
|
|
* have pending work in this hardware queue.
|
|
*/
|
|
static bool blk_mq_hctx_has_pending(struct blk_mq_hw_ctx *hctx)
|
|
{
|
|
return !list_empty_careful(&hctx->dispatch) ||
|
|
sbitmap_any_bit_set(&hctx->ctx_map) ||
|
|
blk_mq_sched_has_work(hctx);
|
|
}
|
|
|
|
/*
|
|
* Mark this ctx as having pending work in this hardware queue
|
|
*/
|
|
static void blk_mq_hctx_mark_pending(struct blk_mq_hw_ctx *hctx,
|
|
struct blk_mq_ctx *ctx)
|
|
{
|
|
const int bit = ctx->index_hw[hctx->type];
|
|
|
|
if (!sbitmap_test_bit(&hctx->ctx_map, bit))
|
|
sbitmap_set_bit(&hctx->ctx_map, bit);
|
|
}
|
|
|
|
static void blk_mq_hctx_clear_pending(struct blk_mq_hw_ctx *hctx,
|
|
struct blk_mq_ctx *ctx)
|
|
{
|
|
const int bit = ctx->index_hw[hctx->type];
|
|
|
|
sbitmap_clear_bit(&hctx->ctx_map, bit);
|
|
}
|
|
|
|
struct mq_inflight {
|
|
struct hd_struct *part;
|
|
unsigned int inflight[2];
|
|
};
|
|
|
|
static bool blk_mq_check_inflight(struct blk_mq_hw_ctx *hctx,
|
|
struct request *rq, void *priv,
|
|
bool reserved)
|
|
{
|
|
struct mq_inflight *mi = priv;
|
|
|
|
if ((!mi->part->partno || rq->part == mi->part) &&
|
|
blk_mq_rq_state(rq) == MQ_RQ_IN_FLIGHT)
|
|
mi->inflight[rq_data_dir(rq)]++;
|
|
|
|
return true;
|
|
}
|
|
|
|
unsigned int blk_mq_in_flight(struct request_queue *q, struct hd_struct *part)
|
|
{
|
|
struct mq_inflight mi = { .part = part };
|
|
|
|
blk_mq_queue_tag_busy_iter(q, blk_mq_check_inflight, &mi);
|
|
|
|
return mi.inflight[0] + mi.inflight[1];
|
|
}
|
|
|
|
void blk_mq_in_flight_rw(struct request_queue *q, struct hd_struct *part,
|
|
unsigned int inflight[2])
|
|
{
|
|
struct mq_inflight mi = { .part = part };
|
|
|
|
blk_mq_queue_tag_busy_iter(q, blk_mq_check_inflight, &mi);
|
|
inflight[0] = mi.inflight[0];
|
|
inflight[1] = mi.inflight[1];
|
|
}
|
|
|
|
void blk_freeze_queue_start(struct request_queue *q)
|
|
{
|
|
mutex_lock(&q->mq_freeze_lock);
|
|
if (++q->mq_freeze_depth == 1) {
|
|
percpu_ref_kill(&q->q_usage_counter);
|
|
mutex_unlock(&q->mq_freeze_lock);
|
|
if (queue_is_mq(q))
|
|
blk_mq_run_hw_queues(q, false);
|
|
} else {
|
|
mutex_unlock(&q->mq_freeze_lock);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_freeze_queue_start);
|
|
|
|
void blk_mq_freeze_queue_wait(struct request_queue *q)
|
|
{
|
|
wait_event(q->mq_freeze_wq, percpu_ref_is_zero(&q->q_usage_counter));
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_freeze_queue_wait);
|
|
|
|
int blk_mq_freeze_queue_wait_timeout(struct request_queue *q,
|
|
unsigned long timeout)
|
|
{
|
|
return wait_event_timeout(q->mq_freeze_wq,
|
|
percpu_ref_is_zero(&q->q_usage_counter),
|
|
timeout);
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_freeze_queue_wait_timeout);
|
|
|
|
/*
|
|
* Guarantee no request is in use, so we can change any data structure of
|
|
* the queue afterward.
|
|
*/
|
|
void blk_freeze_queue(struct request_queue *q)
|
|
{
|
|
/*
|
|
* In the !blk_mq case we are only calling this to kill the
|
|
* q_usage_counter, otherwise this increases the freeze depth
|
|
* and waits for it to return to zero. For this reason there is
|
|
* no blk_unfreeze_queue(), and blk_freeze_queue() is not
|
|
* exported to drivers as the only user for unfreeze is blk_mq.
|
|
*/
|
|
blk_freeze_queue_start(q);
|
|
blk_mq_freeze_queue_wait(q);
|
|
}
|
|
|
|
void blk_mq_freeze_queue(struct request_queue *q)
|
|
{
|
|
/*
|
|
* ...just an alias to keep freeze and unfreeze actions balanced
|
|
* in the blk_mq_* namespace
|
|
*/
|
|
blk_freeze_queue(q);
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_freeze_queue);
|
|
|
|
void blk_mq_unfreeze_queue(struct request_queue *q)
|
|
{
|
|
mutex_lock(&q->mq_freeze_lock);
|
|
q->mq_freeze_depth--;
|
|
WARN_ON_ONCE(q->mq_freeze_depth < 0);
|
|
if (!q->mq_freeze_depth) {
|
|
percpu_ref_resurrect(&q->q_usage_counter);
|
|
wake_up_all(&q->mq_freeze_wq);
|
|
}
|
|
mutex_unlock(&q->mq_freeze_lock);
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_unfreeze_queue);
|
|
|
|
/*
|
|
* FIXME: replace the scsi_internal_device_*block_nowait() calls in the
|
|
* mpt3sas driver such that this function can be removed.
|
|
*/
|
|
void blk_mq_quiesce_queue_nowait(struct request_queue *q)
|
|
{
|
|
blk_queue_flag_set(QUEUE_FLAG_QUIESCED, q);
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_quiesce_queue_nowait);
|
|
|
|
/**
|
|
* blk_mq_quiesce_queue() - wait until all ongoing dispatches have finished
|
|
* @q: request queue.
|
|
*
|
|
* Note: this function does not prevent that the struct request end_io()
|
|
* callback function is invoked. Once this function is returned, we make
|
|
* sure no dispatch can happen until the queue is unquiesced via
|
|
* blk_mq_unquiesce_queue().
|
|
*/
|
|
void blk_mq_quiesce_queue(struct request_queue *q)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
unsigned int i;
|
|
bool rcu = false;
|
|
|
|
blk_mq_quiesce_queue_nowait(q);
|
|
|
|
queue_for_each_hw_ctx(q, hctx, i) {
|
|
if (hctx->flags & BLK_MQ_F_BLOCKING)
|
|
synchronize_srcu(hctx->srcu);
|
|
else
|
|
rcu = true;
|
|
}
|
|
if (rcu)
|
|
synchronize_rcu();
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_quiesce_queue);
|
|
|
|
/*
|
|
* blk_mq_unquiesce_queue() - counterpart of blk_mq_quiesce_queue()
|
|
* @q: request queue.
|
|
*
|
|
* This function recovers queue into the state before quiescing
|
|
* which is done by blk_mq_quiesce_queue.
|
|
*/
|
|
void blk_mq_unquiesce_queue(struct request_queue *q)
|
|
{
|
|
blk_queue_flag_clear(QUEUE_FLAG_QUIESCED, q);
|
|
|
|
/* dispatch requests which are inserted during quiescing */
|
|
blk_mq_run_hw_queues(q, true);
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_unquiesce_queue);
|
|
|
|
void blk_mq_wake_waiters(struct request_queue *q)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
unsigned int i;
|
|
|
|
queue_for_each_hw_ctx(q, hctx, i)
|
|
if (blk_mq_hw_queue_mapped(hctx))
|
|
blk_mq_tag_wakeup_all(hctx->tags, true);
|
|
}
|
|
|
|
/*
|
|
* Only need start/end time stamping if we have iostat or
|
|
* blk stats enabled, or using an IO scheduler.
|
|
*/
|
|
static inline bool blk_mq_need_time_stamp(struct request *rq)
|
|
{
|
|
return (rq->rq_flags & (RQF_IO_STAT | RQF_STATS)) || rq->q->elevator;
|
|
}
|
|
|
|
static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data,
|
|
unsigned int tag, u64 alloc_time_ns)
|
|
{
|
|
struct blk_mq_tags *tags = blk_mq_tags_from_data(data);
|
|
struct request *rq = tags->static_rqs[tag];
|
|
|
|
if (data->q->elevator) {
|
|
rq->tag = BLK_MQ_NO_TAG;
|
|
rq->internal_tag = tag;
|
|
} else {
|
|
rq->tag = tag;
|
|
rq->internal_tag = BLK_MQ_NO_TAG;
|
|
}
|
|
|
|
/* csd/requeue_work/fifo_time is initialized before use */
|
|
rq->q = data->q;
|
|
rq->mq_ctx = data->ctx;
|
|
rq->mq_hctx = data->hctx;
|
|
rq->rq_flags = 0;
|
|
rq->cmd_flags = data->cmd_flags;
|
|
if (data->flags & BLK_MQ_REQ_PM)
|
|
rq->rq_flags |= RQF_PM;
|
|
if (blk_queue_io_stat(data->q))
|
|
rq->rq_flags |= RQF_IO_STAT;
|
|
INIT_LIST_HEAD(&rq->queuelist);
|
|
INIT_HLIST_NODE(&rq->hash);
|
|
RB_CLEAR_NODE(&rq->rb_node);
|
|
rq->rq_disk = NULL;
|
|
rq->part = NULL;
|
|
#ifdef CONFIG_BLK_RQ_ALLOC_TIME
|
|
rq->alloc_time_ns = alloc_time_ns;
|
|
#endif
|
|
if (blk_mq_need_time_stamp(rq))
|
|
rq->start_time_ns = ktime_get_ns();
|
|
else
|
|
rq->start_time_ns = 0;
|
|
rq->io_start_time_ns = 0;
|
|
rq->stats_sectors = 0;
|
|
rq->nr_phys_segments = 0;
|
|
#if defined(CONFIG_BLK_DEV_INTEGRITY)
|
|
rq->nr_integrity_segments = 0;
|
|
#endif
|
|
blk_crypto_rq_set_defaults(rq);
|
|
/* tag was already set */
|
|
WRITE_ONCE(rq->deadline, 0);
|
|
|
|
rq->timeout = 0;
|
|
|
|
rq->end_io = NULL;
|
|
rq->end_io_data = NULL;
|
|
|
|
data->ctx->rq_dispatched[op_is_sync(data->cmd_flags)]++;
|
|
refcount_set(&rq->ref, 1);
|
|
|
|
if (!op_is_flush(data->cmd_flags)) {
|
|
struct elevator_queue *e = data->q->elevator;
|
|
|
|
rq->elv.icq = NULL;
|
|
if (e && e->type->ops.prepare_request) {
|
|
if (e->type->icq_cache)
|
|
blk_mq_sched_assign_ioc(rq);
|
|
|
|
e->type->ops.prepare_request(rq);
|
|
rq->rq_flags |= RQF_ELVPRIV;
|
|
}
|
|
}
|
|
|
|
data->hctx->queued++;
|
|
trace_android_vh_blk_rq_ctx_init(rq, tags, data, alloc_time_ns);
|
|
return rq;
|
|
}
|
|
|
|
static struct request *__blk_mq_alloc_request(struct blk_mq_alloc_data *data)
|
|
{
|
|
struct request_queue *q = data->q;
|
|
struct elevator_queue *e = q->elevator;
|
|
u64 alloc_time_ns = 0;
|
|
unsigned int tag;
|
|
|
|
/* alloc_time includes depth and tag waits */
|
|
if (blk_queue_rq_alloc_time(q))
|
|
alloc_time_ns = ktime_get_ns();
|
|
|
|
if (data->cmd_flags & REQ_NOWAIT)
|
|
data->flags |= BLK_MQ_REQ_NOWAIT;
|
|
|
|
if (e) {
|
|
/*
|
|
* Flush requests are special and go directly to the
|
|
* dispatch list. Don't include reserved tags in the
|
|
* limiting, as it isn't useful.
|
|
*/
|
|
if (!op_is_flush(data->cmd_flags) &&
|
|
e->type->ops.limit_depth &&
|
|
!(data->flags & BLK_MQ_REQ_RESERVED))
|
|
e->type->ops.limit_depth(data->cmd_flags, data);
|
|
}
|
|
|
|
retry:
|
|
data->ctx = blk_mq_get_ctx(q);
|
|
data->hctx = blk_mq_map_queue(q, data->cmd_flags, data->ctx);
|
|
if (!e)
|
|
blk_mq_tag_busy(data->hctx);
|
|
|
|
/*
|
|
* Waiting allocations only fail because of an inactive hctx. In that
|
|
* case just retry the hctx assignment and tag allocation as CPU hotplug
|
|
* should have migrated us to an online CPU by now.
|
|
*/
|
|
tag = blk_mq_get_tag(data);
|
|
if (tag == BLK_MQ_NO_TAG) {
|
|
if (data->flags & BLK_MQ_REQ_NOWAIT)
|
|
return NULL;
|
|
|
|
/*
|
|
* Give up the CPU and sleep for a random short time to ensure
|
|
* that thread using a realtime scheduling class are migrated
|
|
* off the CPU, and thus off the hctx that is going away.
|
|
*/
|
|
msleep(3);
|
|
goto retry;
|
|
}
|
|
return blk_mq_rq_ctx_init(data, tag, alloc_time_ns);
|
|
}
|
|
|
|
struct request *blk_mq_alloc_request(struct request_queue *q, unsigned int op,
|
|
blk_mq_req_flags_t flags)
|
|
{
|
|
struct blk_mq_alloc_data data = {
|
|
.q = q,
|
|
.flags = flags,
|
|
.cmd_flags = op,
|
|
};
|
|
struct request *rq;
|
|
int ret;
|
|
|
|
ret = blk_queue_enter(q, flags);
|
|
if (ret)
|
|
return ERR_PTR(ret);
|
|
|
|
rq = __blk_mq_alloc_request(&data);
|
|
if (!rq)
|
|
goto out_queue_exit;
|
|
rq->__data_len = 0;
|
|
rq->__sector = (sector_t) -1;
|
|
rq->bio = rq->biotail = NULL;
|
|
return rq;
|
|
out_queue_exit:
|
|
blk_queue_exit(q);
|
|
return ERR_PTR(-EWOULDBLOCK);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_alloc_request);
|
|
|
|
struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
|
|
unsigned int op, blk_mq_req_flags_t flags, unsigned int hctx_idx)
|
|
{
|
|
struct blk_mq_alloc_data data = {
|
|
.q = q,
|
|
.flags = flags,
|
|
.cmd_flags = op,
|
|
};
|
|
u64 alloc_time_ns = 0;
|
|
unsigned int cpu;
|
|
unsigned int tag;
|
|
int ret;
|
|
|
|
/* alloc_time includes depth and tag waits */
|
|
if (blk_queue_rq_alloc_time(q))
|
|
alloc_time_ns = ktime_get_ns();
|
|
|
|
/*
|
|
* If the tag allocator sleeps we could get an allocation for a
|
|
* different hardware context. No need to complicate the low level
|
|
* allocator for this for the rare use case of a command tied to
|
|
* a specific queue.
|
|
*/
|
|
if (WARN_ON_ONCE(!(flags & (BLK_MQ_REQ_NOWAIT | BLK_MQ_REQ_RESERVED))))
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
if (hctx_idx >= q->nr_hw_queues)
|
|
return ERR_PTR(-EIO);
|
|
|
|
ret = blk_queue_enter(q, flags);
|
|
if (ret)
|
|
return ERR_PTR(ret);
|
|
|
|
/*
|
|
* Check if the hardware context is actually mapped to anything.
|
|
* If not tell the caller that it should skip this queue.
|
|
*/
|
|
ret = -EXDEV;
|
|
data.hctx = q->queue_hw_ctx[hctx_idx];
|
|
if (!blk_mq_hw_queue_mapped(data.hctx))
|
|
goto out_queue_exit;
|
|
cpu = cpumask_first_and(data.hctx->cpumask, cpu_online_mask);
|
|
if (cpu >= nr_cpu_ids)
|
|
goto out_queue_exit;
|
|
data.ctx = __blk_mq_get_ctx(q, cpu);
|
|
|
|
if (!q->elevator)
|
|
blk_mq_tag_busy(data.hctx);
|
|
|
|
ret = -EWOULDBLOCK;
|
|
tag = blk_mq_get_tag(&data);
|
|
if (tag == BLK_MQ_NO_TAG)
|
|
goto out_queue_exit;
|
|
return blk_mq_rq_ctx_init(&data, tag, alloc_time_ns);
|
|
|
|
out_queue_exit:
|
|
blk_queue_exit(q);
|
|
return ERR_PTR(ret);
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_alloc_request_hctx);
|
|
|
|
static void __blk_mq_free_request(struct request *rq)
|
|
{
|
|
struct request_queue *q = rq->q;
|
|
struct blk_mq_ctx *ctx = rq->mq_ctx;
|
|
struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
|
|
const int sched_tag = rq->internal_tag;
|
|
|
|
blk_crypto_free_request(rq);
|
|
blk_pm_mark_last_busy(rq);
|
|
rq->mq_hctx = NULL;
|
|
if (rq->tag != BLK_MQ_NO_TAG)
|
|
blk_mq_put_tag(hctx->tags, ctx, rq->tag);
|
|
if (sched_tag != BLK_MQ_NO_TAG)
|
|
blk_mq_put_tag(hctx->sched_tags, ctx, sched_tag);
|
|
blk_mq_sched_restart(hctx);
|
|
blk_queue_exit(q);
|
|
}
|
|
|
|
void blk_mq_free_request(struct request *rq)
|
|
{
|
|
struct request_queue *q = rq->q;
|
|
struct elevator_queue *e = q->elevator;
|
|
struct blk_mq_ctx *ctx = rq->mq_ctx;
|
|
struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
|
|
|
|
if (rq->rq_flags & RQF_ELVPRIV) {
|
|
if (e && e->type->ops.finish_request)
|
|
e->type->ops.finish_request(rq);
|
|
if (rq->elv.icq) {
|
|
put_io_context(rq->elv.icq->ioc);
|
|
rq->elv.icq = NULL;
|
|
}
|
|
}
|
|
|
|
ctx->rq_completed[rq_is_sync(rq)]++;
|
|
if (rq->rq_flags & RQF_MQ_INFLIGHT)
|
|
__blk_mq_dec_active_requests(hctx);
|
|
|
|
if (unlikely(laptop_mode && !blk_rq_is_passthrough(rq)))
|
|
laptop_io_completion(q->backing_dev_info);
|
|
|
|
rq_qos_done(q, rq);
|
|
|
|
WRITE_ONCE(rq->state, MQ_RQ_IDLE);
|
|
if (refcount_dec_and_test(&rq->ref))
|
|
__blk_mq_free_request(rq);
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_free_request);
|
|
|
|
inline void __blk_mq_end_request(struct request *rq, blk_status_t error)
|
|
{
|
|
u64 now = 0;
|
|
|
|
if (blk_mq_need_time_stamp(rq))
|
|
now = ktime_get_ns();
|
|
|
|
if (rq->rq_flags & RQF_STATS) {
|
|
blk_mq_poll_stats_start(rq->q);
|
|
blk_stat_add(rq, now);
|
|
}
|
|
|
|
blk_mq_sched_completed_request(rq, now);
|
|
|
|
blk_account_io_done(rq, now);
|
|
|
|
if (rq->end_io) {
|
|
rq_qos_done(rq->q, rq);
|
|
rq->end_io(rq, error);
|
|
} else {
|
|
blk_mq_free_request(rq);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(__blk_mq_end_request);
|
|
|
|
void blk_mq_end_request(struct request *rq, blk_status_t error)
|
|
{
|
|
if (blk_update_request(rq, error, blk_rq_bytes(rq)))
|
|
BUG();
|
|
__blk_mq_end_request(rq, error);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_end_request);
|
|
|
|
/*
|
|
* Softirq action handler - move entries to local list and loop over them
|
|
* while passing them to the queue registered handler.
|
|
*/
|
|
static __latent_entropy void blk_done_softirq(struct softirq_action *h)
|
|
{
|
|
struct list_head *cpu_list, local_list;
|
|
|
|
local_irq_disable();
|
|
cpu_list = this_cpu_ptr(&blk_cpu_done);
|
|
list_replace_init(cpu_list, &local_list);
|
|
local_irq_enable();
|
|
|
|
while (!list_empty(&local_list)) {
|
|
struct request *rq;
|
|
|
|
rq = list_entry(local_list.next, struct request, ipi_list);
|
|
list_del_init(&rq->ipi_list);
|
|
rq->q->mq_ops->complete(rq);
|
|
}
|
|
}
|
|
|
|
static void blk_mq_trigger_softirq(struct request *rq)
|
|
{
|
|
struct list_head *list;
|
|
unsigned long flags;
|
|
|
|
local_irq_save(flags);
|
|
list = this_cpu_ptr(&blk_cpu_done);
|
|
list_add_tail(&rq->ipi_list, list);
|
|
|
|
/*
|
|
* If the list only contains our just added request, signal a raise of
|
|
* the softirq. If there are already entries there, someone already
|
|
* raised the irq but it hasn't run yet.
|
|
*/
|
|
if (list->next == &rq->ipi_list)
|
|
raise_softirq_irqoff(BLOCK_SOFTIRQ);
|
|
local_irq_restore(flags);
|
|
}
|
|
|
|
static int blk_softirq_cpu_dead(unsigned int cpu)
|
|
{
|
|
/*
|
|
* If a CPU goes away, splice its entries to the current CPU
|
|
* and trigger a run of the softirq
|
|
*/
|
|
local_irq_disable();
|
|
list_splice_init(&per_cpu(blk_cpu_done, cpu),
|
|
this_cpu_ptr(&blk_cpu_done));
|
|
raise_softirq_irqoff(BLOCK_SOFTIRQ);
|
|
local_irq_enable();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void __blk_mq_complete_request_remote(void *data)
|
|
{
|
|
struct request *rq = data;
|
|
|
|
/*
|
|
* For most of single queue controllers, there is only one irq vector
|
|
* for handling I/O completion, and the only irq's affinity is set
|
|
* to all possible CPUs. On most of ARCHs, this affinity means the irq
|
|
* is handled on one specific CPU.
|
|
*
|
|
* So complete I/O requests in softirq context in case of single queue
|
|
* devices to avoid degrading I/O performance due to irqsoff latency.
|
|
*/
|
|
if (rq->q->nr_hw_queues == 1)
|
|
blk_mq_trigger_softirq(rq);
|
|
else
|
|
rq->q->mq_ops->complete(rq);
|
|
}
|
|
|
|
static inline bool blk_mq_complete_need_ipi(struct request *rq)
|
|
{
|
|
int cpu = raw_smp_processor_id();
|
|
|
|
if (!IS_ENABLED(CONFIG_SMP) ||
|
|
!test_bit(QUEUE_FLAG_SAME_COMP, &rq->q->queue_flags))
|
|
return false;
|
|
|
|
/* same CPU or cache domain? Complete locally */
|
|
if (cpu == rq->mq_ctx->cpu ||
|
|
(!test_bit(QUEUE_FLAG_SAME_FORCE, &rq->q->queue_flags) &&
|
|
cpus_share_cache(cpu, rq->mq_ctx->cpu)))
|
|
return false;
|
|
|
|
/* don't try to IPI to an offline CPU */
|
|
return cpu_online(rq->mq_ctx->cpu);
|
|
}
|
|
|
|
bool blk_mq_complete_request_remote(struct request *rq)
|
|
{
|
|
WRITE_ONCE(rq->state, MQ_RQ_COMPLETE);
|
|
|
|
/*
|
|
* For a polled request, always complete locallly, it's pointless
|
|
* to redirect the completion.
|
|
*/
|
|
if (rq->cmd_flags & REQ_HIPRI)
|
|
return false;
|
|
|
|
if (blk_mq_complete_need_ipi(rq)) {
|
|
rq->csd.func = __blk_mq_complete_request_remote;
|
|
rq->csd.info = rq;
|
|
rq->csd.flags = 0;
|
|
smp_call_function_single_async(rq->mq_ctx->cpu, &rq->csd);
|
|
} else {
|
|
if (rq->q->nr_hw_queues > 1)
|
|
return false;
|
|
blk_mq_trigger_softirq(rq);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_complete_request_remote);
|
|
|
|
/**
|
|
* blk_mq_complete_request - end I/O on a request
|
|
* @rq: the request being processed
|
|
*
|
|
* Description:
|
|
* Complete a request by scheduling the ->complete_rq operation.
|
|
**/
|
|
void blk_mq_complete_request(struct request *rq)
|
|
{
|
|
if (!blk_mq_complete_request_remote(rq))
|
|
rq->q->mq_ops->complete(rq);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_complete_request);
|
|
|
|
static void hctx_unlock(struct blk_mq_hw_ctx *hctx, int srcu_idx)
|
|
__releases(hctx->srcu)
|
|
{
|
|
if (!(hctx->flags & BLK_MQ_F_BLOCKING))
|
|
rcu_read_unlock();
|
|
else
|
|
srcu_read_unlock(hctx->srcu, srcu_idx);
|
|
}
|
|
|
|
static void hctx_lock(struct blk_mq_hw_ctx *hctx, int *srcu_idx)
|
|
__acquires(hctx->srcu)
|
|
{
|
|
if (!(hctx->flags & BLK_MQ_F_BLOCKING)) {
|
|
/* shut up gcc false positive */
|
|
*srcu_idx = 0;
|
|
rcu_read_lock();
|
|
} else
|
|
*srcu_idx = srcu_read_lock(hctx->srcu);
|
|
}
|
|
|
|
/**
|
|
* blk_mq_start_request - Start processing a request
|
|
* @rq: Pointer to request to be started
|
|
*
|
|
* Function used by device drivers to notify the block layer that a request
|
|
* is going to be processed now, so blk layer can do proper initializations
|
|
* such as starting the timeout timer.
|
|
*/
|
|
void blk_mq_start_request(struct request *rq)
|
|
{
|
|
struct request_queue *q = rq->q;
|
|
|
|
trace_block_rq_issue(q, rq);
|
|
|
|
if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags)) {
|
|
rq->io_start_time_ns = ktime_get_ns();
|
|
rq->stats_sectors = blk_rq_sectors(rq);
|
|
rq->rq_flags |= RQF_STATS;
|
|
rq_qos_issue(q, rq);
|
|
}
|
|
|
|
WARN_ON_ONCE(blk_mq_rq_state(rq) != MQ_RQ_IDLE);
|
|
|
|
blk_add_timer(rq);
|
|
WRITE_ONCE(rq->state, MQ_RQ_IN_FLIGHT);
|
|
|
|
#ifdef CONFIG_BLK_DEV_INTEGRITY
|
|
if (blk_integrity_rq(rq) && req_op(rq) == REQ_OP_WRITE)
|
|
q->integrity.profile->prepare_fn(rq);
|
|
#endif
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_start_request);
|
|
|
|
static void __blk_mq_requeue_request(struct request *rq)
|
|
{
|
|
struct request_queue *q = rq->q;
|
|
|
|
blk_mq_put_driver_tag(rq);
|
|
|
|
trace_block_rq_requeue(q, rq);
|
|
rq_qos_requeue(q, rq);
|
|
|
|
if (blk_mq_request_started(rq)) {
|
|
WRITE_ONCE(rq->state, MQ_RQ_IDLE);
|
|
rq->rq_flags &= ~RQF_TIMED_OUT;
|
|
}
|
|
}
|
|
|
|
void blk_mq_requeue_request(struct request *rq, bool kick_requeue_list)
|
|
{
|
|
__blk_mq_requeue_request(rq);
|
|
|
|
/* this request will be re-inserted to io scheduler queue */
|
|
blk_mq_sched_requeue_request(rq);
|
|
|
|
blk_mq_add_to_requeue_list(rq, true, kick_requeue_list);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_requeue_request);
|
|
|
|
static void blk_mq_requeue_work(struct work_struct *work)
|
|
{
|
|
struct request_queue *q =
|
|
container_of(work, struct request_queue, requeue_work.work);
|
|
LIST_HEAD(rq_list);
|
|
struct request *rq, *next;
|
|
|
|
spin_lock_irq(&q->requeue_lock);
|
|
list_splice_init(&q->requeue_list, &rq_list);
|
|
spin_unlock_irq(&q->requeue_lock);
|
|
|
|
list_for_each_entry_safe(rq, next, &rq_list, queuelist) {
|
|
if (!(rq->rq_flags & (RQF_SOFTBARRIER | RQF_DONTPREP)))
|
|
continue;
|
|
|
|
rq->rq_flags &= ~RQF_SOFTBARRIER;
|
|
list_del_init(&rq->queuelist);
|
|
/*
|
|
* If RQF_DONTPREP, rq has contained some driver specific
|
|
* data, so insert it to hctx dispatch list to avoid any
|
|
* merge.
|
|
*/
|
|
if (rq->rq_flags & RQF_DONTPREP)
|
|
blk_mq_request_bypass_insert(rq, false, false);
|
|
else
|
|
blk_mq_sched_insert_request(rq, true, false, false);
|
|
}
|
|
|
|
while (!list_empty(&rq_list)) {
|
|
rq = list_entry(rq_list.next, struct request, queuelist);
|
|
list_del_init(&rq->queuelist);
|
|
blk_mq_sched_insert_request(rq, false, false, false);
|
|
}
|
|
|
|
blk_mq_run_hw_queues(q, false);
|
|
}
|
|
|
|
void blk_mq_add_to_requeue_list(struct request *rq, bool at_head,
|
|
bool kick_requeue_list)
|
|
{
|
|
struct request_queue *q = rq->q;
|
|
unsigned long flags;
|
|
|
|
/*
|
|
* We abuse this flag that is otherwise used by the I/O scheduler to
|
|
* request head insertion from the workqueue.
|
|
*/
|
|
BUG_ON(rq->rq_flags & RQF_SOFTBARRIER);
|
|
|
|
spin_lock_irqsave(&q->requeue_lock, flags);
|
|
if (at_head) {
|
|
rq->rq_flags |= RQF_SOFTBARRIER;
|
|
list_add(&rq->queuelist, &q->requeue_list);
|
|
} else {
|
|
list_add_tail(&rq->queuelist, &q->requeue_list);
|
|
}
|
|
spin_unlock_irqrestore(&q->requeue_lock, flags);
|
|
|
|
if (kick_requeue_list)
|
|
blk_mq_kick_requeue_list(q);
|
|
}
|
|
|
|
void blk_mq_kick_requeue_list(struct request_queue *q)
|
|
{
|
|
kblockd_mod_delayed_work_on(WORK_CPU_UNBOUND, &q->requeue_work, 0);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_kick_requeue_list);
|
|
|
|
void blk_mq_delay_kick_requeue_list(struct request_queue *q,
|
|
unsigned long msecs)
|
|
{
|
|
kblockd_mod_delayed_work_on(WORK_CPU_UNBOUND, &q->requeue_work,
|
|
msecs_to_jiffies(msecs));
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_delay_kick_requeue_list);
|
|
|
|
struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag)
|
|
{
|
|
if (tag < tags->nr_tags) {
|
|
prefetch(tags->rqs[tag]);
|
|
return tags->rqs[tag];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_tag_to_rq);
|
|
|
|
static bool blk_mq_rq_inflight(struct blk_mq_hw_ctx *hctx, struct request *rq,
|
|
void *priv, bool reserved)
|
|
{
|
|
/*
|
|
* If we find a request that isn't idle and the queue matches,
|
|
* we know the queue is busy. Return false to stop the iteration.
|
|
*/
|
|
if (blk_mq_request_started(rq) && rq->q == hctx->queue) {
|
|
bool *busy = priv;
|
|
|
|
*busy = true;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool blk_mq_queue_inflight(struct request_queue *q)
|
|
{
|
|
bool busy = false;
|
|
|
|
blk_mq_queue_tag_busy_iter(q, blk_mq_rq_inflight, &busy);
|
|
return busy;
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_queue_inflight);
|
|
|
|
static void blk_mq_rq_timed_out(struct request *req, bool reserved)
|
|
{
|
|
req->rq_flags |= RQF_TIMED_OUT;
|
|
if (req->q->mq_ops->timeout) {
|
|
enum blk_eh_timer_return ret;
|
|
|
|
ret = req->q->mq_ops->timeout(req, reserved);
|
|
if (ret == BLK_EH_DONE)
|
|
return;
|
|
WARN_ON_ONCE(ret != BLK_EH_RESET_TIMER);
|
|
}
|
|
|
|
blk_add_timer(req);
|
|
}
|
|
|
|
static bool blk_mq_req_expired(struct request *rq, unsigned long *next)
|
|
{
|
|
unsigned long deadline;
|
|
|
|
if (blk_mq_rq_state(rq) != MQ_RQ_IN_FLIGHT)
|
|
return false;
|
|
if (rq->rq_flags & RQF_TIMED_OUT)
|
|
return false;
|
|
|
|
deadline = READ_ONCE(rq->deadline);
|
|
if (time_after_eq(jiffies, deadline))
|
|
return true;
|
|
|
|
if (*next == 0)
|
|
*next = deadline;
|
|
else if (time_after(*next, deadline))
|
|
*next = deadline;
|
|
return false;
|
|
}
|
|
|
|
void blk_mq_put_rq_ref(struct request *rq)
|
|
{
|
|
if (is_flush_rq(rq))
|
|
rq->end_io(rq, 0);
|
|
else if (refcount_dec_and_test(&rq->ref))
|
|
__blk_mq_free_request(rq);
|
|
}
|
|
|
|
static bool blk_mq_check_expired(struct blk_mq_hw_ctx *hctx,
|
|
struct request *rq, void *priv, bool reserved)
|
|
{
|
|
unsigned long *next = priv;
|
|
|
|
/*
|
|
* blk_mq_queue_tag_busy_iter() has locked the request, so it cannot
|
|
* be reallocated underneath the timeout handler's processing, then
|
|
* the expire check is reliable. If the request is not expired, then
|
|
* it was completed and reallocated as a new request after returning
|
|
* from blk_mq_check_expired().
|
|
*/
|
|
if (blk_mq_req_expired(rq, next))
|
|
blk_mq_rq_timed_out(rq, reserved);
|
|
return true;
|
|
}
|
|
|
|
static void blk_mq_timeout_work(struct work_struct *work)
|
|
{
|
|
struct request_queue *q =
|
|
container_of(work, struct request_queue, timeout_work);
|
|
unsigned long next = 0;
|
|
struct blk_mq_hw_ctx *hctx;
|
|
int i;
|
|
|
|
/* A deadlock might occur if a request is stuck requiring a
|
|
* timeout at the same time a queue freeze is waiting
|
|
* completion, since the timeout code would not be able to
|
|
* acquire the queue reference here.
|
|
*
|
|
* That's why we don't use blk_queue_enter here; instead, we use
|
|
* percpu_ref_tryget directly, because we need to be able to
|
|
* obtain a reference even in the short window between the queue
|
|
* starting to freeze, by dropping the first reference in
|
|
* blk_freeze_queue_start, and the moment the last request is
|
|
* consumed, marked by the instant q_usage_counter reaches
|
|
* zero.
|
|
*/
|
|
if (!percpu_ref_tryget(&q->q_usage_counter))
|
|
return;
|
|
|
|
blk_mq_queue_tag_busy_iter(q, blk_mq_check_expired, &next);
|
|
|
|
if (next != 0) {
|
|
mod_timer(&q->timeout, next);
|
|
} else {
|
|
/*
|
|
* Request timeouts are handled as a forward rolling timer. If
|
|
* we end up here it means that no requests are pending and
|
|
* also that no request has been pending for a while. Mark
|
|
* each hctx as idle.
|
|
*/
|
|
queue_for_each_hw_ctx(q, hctx, i) {
|
|
/* the hctx may be unmapped, so check it here */
|
|
if (blk_mq_hw_queue_mapped(hctx))
|
|
blk_mq_tag_idle(hctx);
|
|
}
|
|
}
|
|
blk_queue_exit(q);
|
|
}
|
|
|
|
struct flush_busy_ctx_data {
|
|
struct blk_mq_hw_ctx *hctx;
|
|
struct list_head *list;
|
|
};
|
|
|
|
static bool flush_busy_ctx(struct sbitmap *sb, unsigned int bitnr, void *data)
|
|
{
|
|
struct flush_busy_ctx_data *flush_data = data;
|
|
struct blk_mq_hw_ctx *hctx = flush_data->hctx;
|
|
struct blk_mq_ctx *ctx = hctx->ctxs[bitnr];
|
|
enum hctx_type type = hctx->type;
|
|
|
|
spin_lock(&ctx->lock);
|
|
list_splice_tail_init(&ctx->rq_lists[type], flush_data->list);
|
|
sbitmap_clear_bit(sb, bitnr);
|
|
spin_unlock(&ctx->lock);
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Process software queues that have been marked busy, splicing them
|
|
* to the for-dispatch
|
|
*/
|
|
void blk_mq_flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list)
|
|
{
|
|
struct flush_busy_ctx_data data = {
|
|
.hctx = hctx,
|
|
.list = list,
|
|
};
|
|
|
|
sbitmap_for_each_set(&hctx->ctx_map, flush_busy_ctx, &data);
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_flush_busy_ctxs);
|
|
|
|
struct dispatch_rq_data {
|
|
struct blk_mq_hw_ctx *hctx;
|
|
struct request *rq;
|
|
};
|
|
|
|
static bool dispatch_rq_from_ctx(struct sbitmap *sb, unsigned int bitnr,
|
|
void *data)
|
|
{
|
|
struct dispatch_rq_data *dispatch_data = data;
|
|
struct blk_mq_hw_ctx *hctx = dispatch_data->hctx;
|
|
struct blk_mq_ctx *ctx = hctx->ctxs[bitnr];
|
|
enum hctx_type type = hctx->type;
|
|
|
|
spin_lock(&ctx->lock);
|
|
if (!list_empty(&ctx->rq_lists[type])) {
|
|
dispatch_data->rq = list_entry_rq(ctx->rq_lists[type].next);
|
|
list_del_init(&dispatch_data->rq->queuelist);
|
|
if (list_empty(&ctx->rq_lists[type]))
|
|
sbitmap_clear_bit(sb, bitnr);
|
|
}
|
|
spin_unlock(&ctx->lock);
|
|
|
|
return !dispatch_data->rq;
|
|
}
|
|
|
|
struct request *blk_mq_dequeue_from_ctx(struct blk_mq_hw_ctx *hctx,
|
|
struct blk_mq_ctx *start)
|
|
{
|
|
unsigned off = start ? start->index_hw[hctx->type] : 0;
|
|
struct dispatch_rq_data data = {
|
|
.hctx = hctx,
|
|
.rq = NULL,
|
|
};
|
|
|
|
__sbitmap_for_each_set(&hctx->ctx_map, off,
|
|
dispatch_rq_from_ctx, &data);
|
|
|
|
return data.rq;
|
|
}
|
|
|
|
static inline unsigned int queued_to_index(unsigned int queued)
|
|
{
|
|
if (!queued)
|
|
return 0;
|
|
|
|
return min(BLK_MQ_MAX_DISPATCH_ORDER - 1, ilog2(queued) + 1);
|
|
}
|
|
|
|
static bool __blk_mq_get_driver_tag(struct request *rq)
|
|
{
|
|
struct sbitmap_queue *bt = rq->mq_hctx->tags->bitmap_tags;
|
|
unsigned int tag_offset = rq->mq_hctx->tags->nr_reserved_tags;
|
|
int tag;
|
|
|
|
blk_mq_tag_busy(rq->mq_hctx);
|
|
|
|
if (blk_mq_tag_is_reserved(rq->mq_hctx->sched_tags, rq->internal_tag)) {
|
|
bt = rq->mq_hctx->tags->breserved_tags;
|
|
tag_offset = 0;
|
|
} else {
|
|
if (!hctx_may_queue(rq->mq_hctx, bt))
|
|
return false;
|
|
}
|
|
|
|
tag = __sbitmap_queue_get(bt);
|
|
if (tag == BLK_MQ_NO_TAG)
|
|
return false;
|
|
|
|
rq->tag = tag + tag_offset;
|
|
return true;
|
|
}
|
|
|
|
static bool blk_mq_get_driver_tag(struct request *rq)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
|
|
|
|
if (rq->tag == BLK_MQ_NO_TAG && !__blk_mq_get_driver_tag(rq))
|
|
return false;
|
|
|
|
if ((hctx->flags & BLK_MQ_F_TAG_QUEUE_SHARED) &&
|
|
!(rq->rq_flags & RQF_MQ_INFLIGHT)) {
|
|
rq->rq_flags |= RQF_MQ_INFLIGHT;
|
|
__blk_mq_inc_active_requests(hctx);
|
|
}
|
|
hctx->tags->rqs[rq->tag] = rq;
|
|
return true;
|
|
}
|
|
|
|
static int blk_mq_dispatch_wake(wait_queue_entry_t *wait, unsigned mode,
|
|
int flags, void *key)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
|
|
hctx = container_of(wait, struct blk_mq_hw_ctx, dispatch_wait);
|
|
|
|
spin_lock(&hctx->dispatch_wait_lock);
|
|
if (!list_empty(&wait->entry)) {
|
|
struct sbitmap_queue *sbq;
|
|
|
|
list_del_init(&wait->entry);
|
|
sbq = hctx->tags->bitmap_tags;
|
|
atomic_dec(&sbq->ws_active);
|
|
}
|
|
spin_unlock(&hctx->dispatch_wait_lock);
|
|
|
|
blk_mq_run_hw_queue(hctx, true);
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Mark us waiting for a tag. For shared tags, this involves hooking us into
|
|
* the tag wakeups. For non-shared tags, we can simply mark us needing a
|
|
* restart. For both cases, take care to check the condition again after
|
|
* marking us as waiting.
|
|
*/
|
|
static bool blk_mq_mark_tag_wait(struct blk_mq_hw_ctx *hctx,
|
|
struct request *rq)
|
|
{
|
|
struct sbitmap_queue *sbq = hctx->tags->bitmap_tags;
|
|
struct wait_queue_head *wq;
|
|
wait_queue_entry_t *wait;
|
|
bool ret;
|
|
|
|
if (!(hctx->flags & BLK_MQ_F_TAG_QUEUE_SHARED)) {
|
|
blk_mq_sched_mark_restart_hctx(hctx);
|
|
|
|
/*
|
|
* It's possible that a tag was freed in the window between the
|
|
* allocation failure and adding the hardware queue to the wait
|
|
* queue.
|
|
*
|
|
* Don't clear RESTART here, someone else could have set it.
|
|
* At most this will cost an extra queue run.
|
|
*/
|
|
return blk_mq_get_driver_tag(rq);
|
|
}
|
|
|
|
wait = &hctx->dispatch_wait;
|
|
if (!list_empty_careful(&wait->entry))
|
|
return false;
|
|
|
|
wq = &bt_wait_ptr(sbq, hctx)->wait;
|
|
|
|
spin_lock_irq(&wq->lock);
|
|
spin_lock(&hctx->dispatch_wait_lock);
|
|
if (!list_empty(&wait->entry)) {
|
|
spin_unlock(&hctx->dispatch_wait_lock);
|
|
spin_unlock_irq(&wq->lock);
|
|
return false;
|
|
}
|
|
|
|
atomic_inc(&sbq->ws_active);
|
|
wait->flags &= ~WQ_FLAG_EXCLUSIVE;
|
|
__add_wait_queue(wq, wait);
|
|
|
|
/*
|
|
* It's possible that a tag was freed in the window between the
|
|
* allocation failure and adding the hardware queue to the wait
|
|
* queue.
|
|
*/
|
|
ret = blk_mq_get_driver_tag(rq);
|
|
if (!ret) {
|
|
spin_unlock(&hctx->dispatch_wait_lock);
|
|
spin_unlock_irq(&wq->lock);
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* We got a tag, remove ourselves from the wait queue to ensure
|
|
* someone else gets the wakeup.
|
|
*/
|
|
list_del_init(&wait->entry);
|
|
atomic_dec(&sbq->ws_active);
|
|
spin_unlock(&hctx->dispatch_wait_lock);
|
|
spin_unlock_irq(&wq->lock);
|
|
|
|
return true;
|
|
}
|
|
|
|
#define BLK_MQ_DISPATCH_BUSY_EWMA_WEIGHT 8
|
|
#define BLK_MQ_DISPATCH_BUSY_EWMA_FACTOR 4
|
|
/*
|
|
* Update dispatch busy with the Exponential Weighted Moving Average(EWMA):
|
|
* - EWMA is one simple way to compute running average value
|
|
* - weight(7/8 and 1/8) is applied so that it can decrease exponentially
|
|
* - take 4 as factor for avoiding to get too small(0) result, and this
|
|
* factor doesn't matter because EWMA decreases exponentially
|
|
*/
|
|
static void blk_mq_update_dispatch_busy(struct blk_mq_hw_ctx *hctx, bool busy)
|
|
{
|
|
unsigned int ewma;
|
|
|
|
ewma = hctx->dispatch_busy;
|
|
|
|
if (!ewma && !busy)
|
|
return;
|
|
|
|
ewma *= BLK_MQ_DISPATCH_BUSY_EWMA_WEIGHT - 1;
|
|
if (busy)
|
|
ewma += 1 << BLK_MQ_DISPATCH_BUSY_EWMA_FACTOR;
|
|
ewma /= BLK_MQ_DISPATCH_BUSY_EWMA_WEIGHT;
|
|
|
|
hctx->dispatch_busy = ewma;
|
|
}
|
|
|
|
#define BLK_MQ_RESOURCE_DELAY 3 /* ms units */
|
|
|
|
static void blk_mq_handle_dev_resource(struct request *rq,
|
|
struct list_head *list)
|
|
{
|
|
struct request *next =
|
|
list_first_entry_or_null(list, struct request, queuelist);
|
|
|
|
/*
|
|
* If an I/O scheduler has been configured and we got a driver tag for
|
|
* the next request already, free it.
|
|
*/
|
|
if (next)
|
|
blk_mq_put_driver_tag(next);
|
|
|
|
list_add(&rq->queuelist, list);
|
|
__blk_mq_requeue_request(rq);
|
|
}
|
|
|
|
static void blk_mq_handle_zone_resource(struct request *rq,
|
|
struct list_head *zone_list)
|
|
{
|
|
/*
|
|
* If we end up here it is because we cannot dispatch a request to a
|
|
* specific zone due to LLD level zone-write locking or other zone
|
|
* related resource not being available. In this case, set the request
|
|
* aside in zone_list for retrying it later.
|
|
*/
|
|
list_add(&rq->queuelist, zone_list);
|
|
__blk_mq_requeue_request(rq);
|
|
}
|
|
|
|
enum prep_dispatch {
|
|
PREP_DISPATCH_OK,
|
|
PREP_DISPATCH_NO_TAG,
|
|
PREP_DISPATCH_NO_BUDGET,
|
|
};
|
|
|
|
static enum prep_dispatch blk_mq_prep_dispatch_rq(struct request *rq,
|
|
bool need_budget)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
|
|
|
|
if (need_budget && !blk_mq_get_dispatch_budget(rq->q)) {
|
|
blk_mq_put_driver_tag(rq);
|
|
return PREP_DISPATCH_NO_BUDGET;
|
|
}
|
|
|
|
if (!blk_mq_get_driver_tag(rq)) {
|
|
/*
|
|
* The initial allocation attempt failed, so we need to
|
|
* rerun the hardware queue when a tag is freed. The
|
|
* waitqueue takes care of that. If the queue is run
|
|
* before we add this entry back on the dispatch list,
|
|
* we'll re-run it below.
|
|
*/
|
|
if (!blk_mq_mark_tag_wait(hctx, rq)) {
|
|
/*
|
|
* All budgets not got from this function will be put
|
|
* together during handling partial dispatch
|
|
*/
|
|
if (need_budget)
|
|
blk_mq_put_dispatch_budget(rq->q);
|
|
return PREP_DISPATCH_NO_TAG;
|
|
}
|
|
}
|
|
|
|
return PREP_DISPATCH_OK;
|
|
}
|
|
|
|
/* release all allocated budgets before calling to blk_mq_dispatch_rq_list */
|
|
static void blk_mq_release_budgets(struct request_queue *q,
|
|
unsigned int nr_budgets)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < nr_budgets; i++)
|
|
blk_mq_put_dispatch_budget(q);
|
|
}
|
|
|
|
/*
|
|
* Returns true if we did some work AND can potentially do more.
|
|
*/
|
|
bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *list,
|
|
unsigned int nr_budgets)
|
|
{
|
|
enum prep_dispatch prep;
|
|
struct request_queue *q = hctx->queue;
|
|
struct request *rq, *nxt;
|
|
int errors, queued;
|
|
blk_status_t ret = BLK_STS_OK;
|
|
LIST_HEAD(zone_list);
|
|
bool needs_resource = false;
|
|
|
|
if (list_empty(list))
|
|
return false;
|
|
|
|
/*
|
|
* Now process all the entries, sending them to the driver.
|
|
*/
|
|
errors = queued = 0;
|
|
do {
|
|
struct blk_mq_queue_data bd;
|
|
|
|
rq = list_first_entry(list, struct request, queuelist);
|
|
|
|
WARN_ON_ONCE(hctx != rq->mq_hctx);
|
|
prep = blk_mq_prep_dispatch_rq(rq, !nr_budgets);
|
|
if (prep != PREP_DISPATCH_OK)
|
|
break;
|
|
|
|
list_del_init(&rq->queuelist);
|
|
|
|
bd.rq = rq;
|
|
|
|
/*
|
|
* Flag last if we have no more requests, or if we have more
|
|
* but can't assign a driver tag to it.
|
|
*/
|
|
if (list_empty(list))
|
|
bd.last = true;
|
|
else {
|
|
nxt = list_first_entry(list, struct request, queuelist);
|
|
bd.last = !blk_mq_get_driver_tag(nxt);
|
|
}
|
|
|
|
/*
|
|
* once the request is queued to lld, no need to cover the
|
|
* budget any more
|
|
*/
|
|
if (nr_budgets)
|
|
nr_budgets--;
|
|
ret = q->mq_ops->queue_rq(hctx, &bd);
|
|
switch (ret) {
|
|
case BLK_STS_OK:
|
|
queued++;
|
|
break;
|
|
case BLK_STS_RESOURCE:
|
|
needs_resource = true;
|
|
fallthrough;
|
|
case BLK_STS_DEV_RESOURCE:
|
|
blk_mq_handle_dev_resource(rq, list);
|
|
goto out;
|
|
case BLK_STS_ZONE_RESOURCE:
|
|
/*
|
|
* Move the request to zone_list and keep going through
|
|
* the dispatch list to find more requests the drive can
|
|
* accept.
|
|
*/
|
|
blk_mq_handle_zone_resource(rq, &zone_list);
|
|
needs_resource = true;
|
|
break;
|
|
default:
|
|
errors++;
|
|
blk_mq_end_request(rq, BLK_STS_IOERR);
|
|
}
|
|
} while (!list_empty(list));
|
|
out:
|
|
if (!list_empty(&zone_list))
|
|
list_splice_tail_init(&zone_list, list);
|
|
|
|
hctx->dispatched[queued_to_index(queued)]++;
|
|
|
|
/* If we didn't flush the entire list, we could have told the driver
|
|
* there was more coming, but that turned out to be a lie.
|
|
*/
|
|
if ((!list_empty(list) || errors || needs_resource ||
|
|
ret == BLK_STS_DEV_RESOURCE) && q->mq_ops->commit_rqs && queued)
|
|
q->mq_ops->commit_rqs(hctx);
|
|
/*
|
|
* Any items that need requeuing? Stuff them into hctx->dispatch,
|
|
* that is where we will continue on next queue run.
|
|
*/
|
|
if (!list_empty(list)) {
|
|
bool needs_restart;
|
|
/* For non-shared tags, the RESTART check will suffice */
|
|
bool no_tag = prep == PREP_DISPATCH_NO_TAG &&
|
|
(hctx->flags & BLK_MQ_F_TAG_QUEUE_SHARED);
|
|
|
|
blk_mq_release_budgets(q, nr_budgets);
|
|
|
|
spin_lock(&hctx->lock);
|
|
list_splice_tail_init(list, &hctx->dispatch);
|
|
spin_unlock(&hctx->lock);
|
|
|
|
/*
|
|
* Order adding requests to hctx->dispatch and checking
|
|
* SCHED_RESTART flag. The pair of this smp_mb() is the one
|
|
* in blk_mq_sched_restart(). Avoid restart code path to
|
|
* miss the new added requests to hctx->dispatch, meantime
|
|
* SCHED_RESTART is observed here.
|
|
*/
|
|
smp_mb();
|
|
|
|
/*
|
|
* If SCHED_RESTART was set by the caller of this function and
|
|
* it is no longer set that means that it was cleared by another
|
|
* thread and hence that a queue rerun is needed.
|
|
*
|
|
* If 'no_tag' is set, that means that we failed getting
|
|
* a driver tag with an I/O scheduler attached. If our dispatch
|
|
* waitqueue is no longer active, ensure that we run the queue
|
|
* AFTER adding our entries back to the list.
|
|
*
|
|
* If no I/O scheduler has been configured it is possible that
|
|
* the hardware queue got stopped and restarted before requests
|
|
* were pushed back onto the dispatch list. Rerun the queue to
|
|
* avoid starvation. Notes:
|
|
* - blk_mq_run_hw_queue() checks whether or not a queue has
|
|
* been stopped before rerunning a queue.
|
|
* - Some but not all block drivers stop a queue before
|
|
* returning BLK_STS_RESOURCE. Two exceptions are scsi-mq
|
|
* and dm-rq.
|
|
*
|
|
* If driver returns BLK_STS_RESOURCE and SCHED_RESTART
|
|
* bit is set, run queue after a delay to avoid IO stalls
|
|
* that could otherwise occur if the queue is idle. We'll do
|
|
* similar if we couldn't get budget or couldn't lock a zone
|
|
* and SCHED_RESTART is set.
|
|
*/
|
|
needs_restart = blk_mq_sched_needs_restart(hctx);
|
|
if (prep == PREP_DISPATCH_NO_BUDGET)
|
|
needs_resource = true;
|
|
if (!needs_restart ||
|
|
(no_tag && list_empty_careful(&hctx->dispatch_wait.entry)))
|
|
blk_mq_run_hw_queue(hctx, true);
|
|
else if (needs_restart && needs_resource)
|
|
blk_mq_delay_run_hw_queue(hctx, BLK_MQ_RESOURCE_DELAY);
|
|
|
|
blk_mq_update_dispatch_busy(hctx, true);
|
|
return false;
|
|
} else
|
|
blk_mq_update_dispatch_busy(hctx, false);
|
|
|
|
return (queued + errors) != 0;
|
|
}
|
|
|
|
/**
|
|
* __blk_mq_run_hw_queue - Run a hardware queue.
|
|
* @hctx: Pointer to the hardware queue to run.
|
|
*
|
|
* Send pending requests to the hardware.
|
|
*/
|
|
static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
|
|
{
|
|
int srcu_idx;
|
|
|
|
/*
|
|
* We should be running this queue from one of the CPUs that
|
|
* are mapped to it.
|
|
*
|
|
* There are at least two related races now between setting
|
|
* hctx->next_cpu from blk_mq_hctx_next_cpu() and running
|
|
* __blk_mq_run_hw_queue():
|
|
*
|
|
* - hctx->next_cpu is found offline in blk_mq_hctx_next_cpu(),
|
|
* but later it becomes online, then this warning is harmless
|
|
* at all
|
|
*
|
|
* - hctx->next_cpu is found online in blk_mq_hctx_next_cpu(),
|
|
* but later it becomes offline, then the warning can't be
|
|
* triggered, and we depend on blk-mq timeout handler to
|
|
* handle dispatched requests to this hctx
|
|
*/
|
|
if (!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask) &&
|
|
cpu_online(hctx->next_cpu)) {
|
|
printk(KERN_WARNING "run queue from wrong CPU %d, hctx %s\n",
|
|
raw_smp_processor_id(),
|
|
cpumask_empty(hctx->cpumask) ? "inactive": "active");
|
|
dump_stack();
|
|
}
|
|
|
|
/*
|
|
* We can't run the queue inline with ints disabled. Ensure that
|
|
* we catch bad users of this early.
|
|
*/
|
|
WARN_ON_ONCE(in_interrupt());
|
|
|
|
might_sleep_if(hctx->flags & BLK_MQ_F_BLOCKING);
|
|
|
|
hctx_lock(hctx, &srcu_idx);
|
|
blk_mq_sched_dispatch_requests(hctx);
|
|
hctx_unlock(hctx, srcu_idx);
|
|
}
|
|
|
|
static inline int blk_mq_first_mapped_cpu(struct blk_mq_hw_ctx *hctx)
|
|
{
|
|
int cpu = cpumask_first_and(hctx->cpumask, cpu_online_mask);
|
|
|
|
if (cpu >= nr_cpu_ids)
|
|
cpu = cpumask_first(hctx->cpumask);
|
|
return cpu;
|
|
}
|
|
|
|
/*
|
|
* It'd be great if the workqueue API had a way to pass
|
|
* in a mask and had some smarts for more clever placement.
|
|
* For now we just round-robin here, switching for every
|
|
* BLK_MQ_CPU_WORK_BATCH queued items.
|
|
*/
|
|
static int blk_mq_hctx_next_cpu(struct blk_mq_hw_ctx *hctx)
|
|
{
|
|
bool tried = false;
|
|
int next_cpu = hctx->next_cpu;
|
|
|
|
if (hctx->queue->nr_hw_queues == 1)
|
|
return WORK_CPU_UNBOUND;
|
|
|
|
if (--hctx->next_cpu_batch <= 0) {
|
|
select_cpu:
|
|
next_cpu = cpumask_next_and(next_cpu, hctx->cpumask,
|
|
cpu_online_mask);
|
|
if (next_cpu >= nr_cpu_ids)
|
|
next_cpu = blk_mq_first_mapped_cpu(hctx);
|
|
hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH;
|
|
}
|
|
|
|
/*
|
|
* Do unbound schedule if we can't find a online CPU for this hctx,
|
|
* and it should only happen in the path of handling CPU DEAD.
|
|
*/
|
|
if (!cpu_online(next_cpu)) {
|
|
if (!tried) {
|
|
tried = true;
|
|
goto select_cpu;
|
|
}
|
|
|
|
/*
|
|
* Make sure to re-select CPU next time once after CPUs
|
|
* in hctx->cpumask become online again.
|
|
*/
|
|
hctx->next_cpu = next_cpu;
|
|
hctx->next_cpu_batch = 1;
|
|
return WORK_CPU_UNBOUND;
|
|
}
|
|
|
|
hctx->next_cpu = next_cpu;
|
|
return next_cpu;
|
|
}
|
|
|
|
/**
|
|
* __blk_mq_delay_run_hw_queue - Run (or schedule to run) a hardware queue.
|
|
* @hctx: Pointer to the hardware queue to run.
|
|
* @async: If we want to run the queue asynchronously.
|
|
* @msecs: Microseconds of delay to wait before running the queue.
|
|
*
|
|
* If !@async, try to run the queue now. Else, run the queue asynchronously and
|
|
* with a delay of @msecs.
|
|
*/
|
|
static void __blk_mq_delay_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async,
|
|
unsigned long msecs)
|
|
{
|
|
if (unlikely(blk_mq_hctx_stopped(hctx)))
|
|
return;
|
|
|
|
if (!async && !(hctx->flags & BLK_MQ_F_BLOCKING)) {
|
|
int cpu = get_cpu();
|
|
if (cpumask_test_cpu(cpu, hctx->cpumask)) {
|
|
__blk_mq_run_hw_queue(hctx);
|
|
put_cpu();
|
|
return;
|
|
}
|
|
|
|
put_cpu();
|
|
}
|
|
|
|
kblockd_mod_delayed_work_on(blk_mq_hctx_next_cpu(hctx), &hctx->run_work,
|
|
msecs_to_jiffies(msecs));
|
|
}
|
|
|
|
/**
|
|
* blk_mq_delay_run_hw_queue - Run a hardware queue asynchronously.
|
|
* @hctx: Pointer to the hardware queue to run.
|
|
* @msecs: Microseconds of delay to wait before running the queue.
|
|
*
|
|
* Run a hardware queue asynchronously with a delay of @msecs.
|
|
*/
|
|
void blk_mq_delay_run_hw_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs)
|
|
{
|
|
__blk_mq_delay_run_hw_queue(hctx, true, msecs);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_delay_run_hw_queue);
|
|
|
|
/**
|
|
* blk_mq_run_hw_queue - Start to run a hardware queue.
|
|
* @hctx: Pointer to the hardware queue to run.
|
|
* @async: If we want to run the queue asynchronously.
|
|
*
|
|
* Check if the request queue is not in a quiesced state and if there are
|
|
* pending requests to be sent. If this is true, run the queue to send requests
|
|
* to hardware.
|
|
*/
|
|
void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
|
|
{
|
|
int srcu_idx;
|
|
bool need_run;
|
|
|
|
/*
|
|
* When queue is quiesced, we may be switching io scheduler, or
|
|
* updating nr_hw_queues, or other things, and we can't run queue
|
|
* any more, even __blk_mq_hctx_has_pending() can't be called safely.
|
|
*
|
|
* And queue will be rerun in blk_mq_unquiesce_queue() if it is
|
|
* quiesced.
|
|
*/
|
|
hctx_lock(hctx, &srcu_idx);
|
|
need_run = !blk_queue_quiesced(hctx->queue) &&
|
|
blk_mq_hctx_has_pending(hctx);
|
|
hctx_unlock(hctx, srcu_idx);
|
|
|
|
if (need_run)
|
|
__blk_mq_delay_run_hw_queue(hctx, async, 0);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_run_hw_queue);
|
|
|
|
/*
|
|
* Is the request queue handled by an IO scheduler that does not respect
|
|
* hardware queues when dispatching?
|
|
*/
|
|
static bool blk_mq_has_sqsched(struct request_queue *q)
|
|
{
|
|
struct elevator_queue *e = q->elevator;
|
|
|
|
if (e && e->type->ops.dispatch_request &&
|
|
!(e->type->elevator_features & ELEVATOR_F_MQ_AWARE))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Return prefered queue to dispatch from (if any) for non-mq aware IO
|
|
* scheduler.
|
|
*/
|
|
static struct blk_mq_hw_ctx *blk_mq_get_sq_hctx(struct request_queue *q)
|
|
{
|
|
struct blk_mq_ctx *ctx = blk_mq_get_ctx(q);
|
|
/*
|
|
* If the IO scheduler does not respect hardware queues when
|
|
* dispatching, we just don't bother with multiple HW queues and
|
|
* dispatch from hctx for the current CPU since running multiple queues
|
|
* just causes lock contention inside the scheduler and pointless cache
|
|
* bouncing.
|
|
*/
|
|
struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, 0, ctx);
|
|
|
|
if (!blk_mq_hctx_stopped(hctx))
|
|
return hctx;
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* blk_mq_run_hw_queues - Run all hardware queues in a request queue.
|
|
* @q: Pointer to the request queue to run.
|
|
* @async: If we want to run the queue asynchronously.
|
|
*/
|
|
void blk_mq_run_hw_queues(struct request_queue *q, bool async)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx, *sq_hctx;
|
|
int i;
|
|
|
|
sq_hctx = NULL;
|
|
if (blk_mq_has_sqsched(q))
|
|
sq_hctx = blk_mq_get_sq_hctx(q);
|
|
queue_for_each_hw_ctx(q, hctx, i) {
|
|
if (blk_mq_hctx_stopped(hctx))
|
|
continue;
|
|
/*
|
|
* Dispatch from this hctx either if there's no hctx preferred
|
|
* by IO scheduler or if it has requests that bypass the
|
|
* scheduler.
|
|
*/
|
|
if (!sq_hctx || sq_hctx == hctx ||
|
|
!list_empty_careful(&hctx->dispatch))
|
|
blk_mq_run_hw_queue(hctx, async);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_run_hw_queues);
|
|
|
|
/**
|
|
* blk_mq_delay_run_hw_queues - Run all hardware queues asynchronously.
|
|
* @q: Pointer to the request queue to run.
|
|
* @msecs: Microseconds of delay to wait before running the queues.
|
|
*/
|
|
void blk_mq_delay_run_hw_queues(struct request_queue *q, unsigned long msecs)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx, *sq_hctx;
|
|
int i;
|
|
|
|
sq_hctx = NULL;
|
|
if (blk_mq_has_sqsched(q))
|
|
sq_hctx = blk_mq_get_sq_hctx(q);
|
|
queue_for_each_hw_ctx(q, hctx, i) {
|
|
if (blk_mq_hctx_stopped(hctx))
|
|
continue;
|
|
/*
|
|
* Dispatch from this hctx either if there's no hctx preferred
|
|
* by IO scheduler or if it has requests that bypass the
|
|
* scheduler.
|
|
*/
|
|
if (!sq_hctx || sq_hctx == hctx ||
|
|
!list_empty_careful(&hctx->dispatch))
|
|
blk_mq_delay_run_hw_queue(hctx, msecs);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_delay_run_hw_queues);
|
|
|
|
/**
|
|
* blk_mq_queue_stopped() - check whether one or more hctxs have been stopped
|
|
* @q: request queue.
|
|
*
|
|
* The caller is responsible for serializing this function against
|
|
* blk_mq_{start,stop}_hw_queue().
|
|
*/
|
|
bool blk_mq_queue_stopped(struct request_queue *q)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
int i;
|
|
|
|
queue_for_each_hw_ctx(q, hctx, i)
|
|
if (blk_mq_hctx_stopped(hctx))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_queue_stopped);
|
|
|
|
/*
|
|
* This function is often used for pausing .queue_rq() by driver when
|
|
* there isn't enough resource or some conditions aren't satisfied, and
|
|
* BLK_STS_RESOURCE is usually returned.
|
|
*
|
|
* We do not guarantee that dispatch can be drained or blocked
|
|
* after blk_mq_stop_hw_queue() returns. Please use
|
|
* blk_mq_quiesce_queue() for that requirement.
|
|
*/
|
|
void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx)
|
|
{
|
|
cancel_delayed_work(&hctx->run_work);
|
|
|
|
set_bit(BLK_MQ_S_STOPPED, &hctx->state);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_stop_hw_queue);
|
|
|
|
/*
|
|
* This function is often used for pausing .queue_rq() by driver when
|
|
* there isn't enough resource or some conditions aren't satisfied, and
|
|
* BLK_STS_RESOURCE is usually returned.
|
|
*
|
|
* We do not guarantee that dispatch can be drained or blocked
|
|
* after blk_mq_stop_hw_queues() returns. Please use
|
|
* blk_mq_quiesce_queue() for that requirement.
|
|
*/
|
|
void blk_mq_stop_hw_queues(struct request_queue *q)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
int i;
|
|
|
|
queue_for_each_hw_ctx(q, hctx, i)
|
|
blk_mq_stop_hw_queue(hctx);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_stop_hw_queues);
|
|
|
|
void blk_mq_start_hw_queue(struct blk_mq_hw_ctx *hctx)
|
|
{
|
|
clear_bit(BLK_MQ_S_STOPPED, &hctx->state);
|
|
|
|
blk_mq_run_hw_queue(hctx, false);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_start_hw_queue);
|
|
|
|
void blk_mq_start_hw_queues(struct request_queue *q)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
int i;
|
|
|
|
queue_for_each_hw_ctx(q, hctx, i)
|
|
blk_mq_start_hw_queue(hctx);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_start_hw_queues);
|
|
|
|
void blk_mq_start_stopped_hw_queue(struct blk_mq_hw_ctx *hctx, bool async)
|
|
{
|
|
if (!blk_mq_hctx_stopped(hctx))
|
|
return;
|
|
|
|
clear_bit(BLK_MQ_S_STOPPED, &hctx->state);
|
|
blk_mq_run_hw_queue(hctx, async);
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_start_stopped_hw_queue);
|
|
|
|
void blk_mq_start_stopped_hw_queues(struct request_queue *q, bool async)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
int i;
|
|
|
|
queue_for_each_hw_ctx(q, hctx, i)
|
|
blk_mq_start_stopped_hw_queue(hctx, async);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_start_stopped_hw_queues);
|
|
|
|
static void blk_mq_run_work_fn(struct work_struct *work)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
|
|
hctx = container_of(work, struct blk_mq_hw_ctx, run_work.work);
|
|
|
|
/*
|
|
* If we are stopped, don't run the queue.
|
|
*/
|
|
if (blk_mq_hctx_stopped(hctx))
|
|
return;
|
|
|
|
__blk_mq_run_hw_queue(hctx);
|
|
}
|
|
|
|
static inline void __blk_mq_insert_req_list(struct blk_mq_hw_ctx *hctx,
|
|
struct request *rq,
|
|
bool at_head)
|
|
{
|
|
struct blk_mq_ctx *ctx = rq->mq_ctx;
|
|
enum hctx_type type = hctx->type;
|
|
|
|
lockdep_assert_held(&ctx->lock);
|
|
|
|
trace_block_rq_insert(hctx->queue, rq);
|
|
|
|
if (at_head)
|
|
list_add(&rq->queuelist, &ctx->rq_lists[type]);
|
|
else
|
|
list_add_tail(&rq->queuelist, &ctx->rq_lists[type]);
|
|
}
|
|
|
|
void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
|
|
bool at_head)
|
|
{
|
|
struct blk_mq_ctx *ctx = rq->mq_ctx;
|
|
|
|
lockdep_assert_held(&ctx->lock);
|
|
|
|
__blk_mq_insert_req_list(hctx, rq, at_head);
|
|
blk_mq_hctx_mark_pending(hctx, ctx);
|
|
}
|
|
|
|
/**
|
|
* blk_mq_request_bypass_insert - Insert a request at dispatch list.
|
|
* @rq: Pointer to request to be inserted.
|
|
* @at_head: true if the request should be inserted at the head of the list.
|
|
* @run_queue: If we should run the hardware queue after inserting the request.
|
|
*
|
|
* Should only be used carefully, when the caller knows we want to
|
|
* bypass a potential IO scheduler on the target device.
|
|
*/
|
|
void blk_mq_request_bypass_insert(struct request *rq, bool at_head,
|
|
bool run_queue)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
|
|
|
|
spin_lock(&hctx->lock);
|
|
if (at_head)
|
|
list_add(&rq->queuelist, &hctx->dispatch);
|
|
else
|
|
list_add_tail(&rq->queuelist, &hctx->dispatch);
|
|
spin_unlock(&hctx->lock);
|
|
|
|
if (run_queue)
|
|
blk_mq_run_hw_queue(hctx, false);
|
|
}
|
|
|
|
void blk_mq_insert_requests(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
|
|
struct list_head *list)
|
|
|
|
{
|
|
struct request *rq;
|
|
enum hctx_type type = hctx->type;
|
|
|
|
/*
|
|
* preemption doesn't flush plug list, so it's possible ctx->cpu is
|
|
* offline now
|
|
*/
|
|
list_for_each_entry(rq, list, queuelist) {
|
|
BUG_ON(rq->mq_ctx != ctx);
|
|
trace_block_rq_insert(hctx->queue, rq);
|
|
}
|
|
|
|
spin_lock(&ctx->lock);
|
|
list_splice_tail_init(list, &ctx->rq_lists[type]);
|
|
blk_mq_hctx_mark_pending(hctx, ctx);
|
|
spin_unlock(&ctx->lock);
|
|
}
|
|
|
|
static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
|
|
{
|
|
struct request *rqa = container_of(a, struct request, queuelist);
|
|
struct request *rqb = container_of(b, struct request, queuelist);
|
|
|
|
if (rqa->mq_ctx != rqb->mq_ctx)
|
|
return rqa->mq_ctx > rqb->mq_ctx;
|
|
if (rqa->mq_hctx != rqb->mq_hctx)
|
|
return rqa->mq_hctx > rqb->mq_hctx;
|
|
|
|
return blk_rq_pos(rqa) > blk_rq_pos(rqb);
|
|
}
|
|
|
|
void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule)
|
|
{
|
|
LIST_HEAD(list);
|
|
|
|
if (list_empty(&plug->mq_list))
|
|
return;
|
|
list_splice_init(&plug->mq_list, &list);
|
|
|
|
if (plug->rq_count > 2 && plug->multiple_queues)
|
|
list_sort(NULL, &list, plug_rq_cmp);
|
|
|
|
plug->rq_count = 0;
|
|
|
|
do {
|
|
struct list_head rq_list;
|
|
struct request *rq, *head_rq = list_entry_rq(list.next);
|
|
struct list_head *pos = &head_rq->queuelist; /* skip first */
|
|
struct blk_mq_hw_ctx *this_hctx = head_rq->mq_hctx;
|
|
struct blk_mq_ctx *this_ctx = head_rq->mq_ctx;
|
|
unsigned int depth = 1;
|
|
|
|
list_for_each_continue(pos, &list) {
|
|
rq = list_entry_rq(pos);
|
|
BUG_ON(!rq->q);
|
|
if (rq->mq_hctx != this_hctx || rq->mq_ctx != this_ctx)
|
|
break;
|
|
depth++;
|
|
}
|
|
|
|
list_cut_before(&rq_list, &list, pos);
|
|
trace_block_unplug(head_rq->q, depth, !from_schedule);
|
|
blk_mq_sched_insert_requests(this_hctx, this_ctx, &rq_list,
|
|
from_schedule);
|
|
} while(!list_empty(&list));
|
|
}
|
|
|
|
static void blk_mq_bio_to_request(struct request *rq, struct bio *bio,
|
|
unsigned int nr_segs)
|
|
{
|
|
int err;
|
|
|
|
if (bio->bi_opf & REQ_RAHEAD)
|
|
rq->cmd_flags |= REQ_FAILFAST_MASK;
|
|
|
|
rq->__sector = bio->bi_iter.bi_sector;
|
|
rq->write_hint = bio->bi_write_hint;
|
|
blk_rq_bio_prep(rq, bio, nr_segs);
|
|
|
|
/* This can't fail, since GFP_NOIO includes __GFP_DIRECT_RECLAIM. */
|
|
err = blk_crypto_rq_bio_prep(rq, bio, GFP_NOIO);
|
|
WARN_ON_ONCE(err);
|
|
|
|
blk_account_io_start(rq);
|
|
}
|
|
|
|
static blk_status_t __blk_mq_issue_directly(struct blk_mq_hw_ctx *hctx,
|
|
struct request *rq,
|
|
blk_qc_t *cookie, bool last)
|
|
{
|
|
struct request_queue *q = rq->q;
|
|
struct blk_mq_queue_data bd = {
|
|
.rq = rq,
|
|
.last = last,
|
|
};
|
|
blk_qc_t new_cookie;
|
|
blk_status_t ret;
|
|
|
|
new_cookie = request_to_qc_t(hctx, rq);
|
|
|
|
/*
|
|
* For OK queue, we are done. For error, caller may kill it.
|
|
* Any other error (busy), just add it to our list as we
|
|
* previously would have done.
|
|
*/
|
|
ret = q->mq_ops->queue_rq(hctx, &bd);
|
|
switch (ret) {
|
|
case BLK_STS_OK:
|
|
blk_mq_update_dispatch_busy(hctx, false);
|
|
*cookie = new_cookie;
|
|
break;
|
|
case BLK_STS_RESOURCE:
|
|
case BLK_STS_DEV_RESOURCE:
|
|
blk_mq_update_dispatch_busy(hctx, true);
|
|
__blk_mq_requeue_request(rq);
|
|
break;
|
|
default:
|
|
blk_mq_update_dispatch_busy(hctx, false);
|
|
*cookie = BLK_QC_T_NONE;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static blk_status_t __blk_mq_try_issue_directly(struct blk_mq_hw_ctx *hctx,
|
|
struct request *rq,
|
|
blk_qc_t *cookie,
|
|
bool bypass_insert, bool last)
|
|
{
|
|
struct request_queue *q = rq->q;
|
|
bool run_queue = true;
|
|
|
|
/*
|
|
* RCU or SRCU read lock is needed before checking quiesced flag.
|
|
*
|
|
* When queue is stopped or quiesced, ignore 'bypass_insert' from
|
|
* blk_mq_request_issue_directly(), and return BLK_STS_OK to caller,
|
|
* and avoid driver to try to dispatch again.
|
|
*/
|
|
if (blk_mq_hctx_stopped(hctx) || blk_queue_quiesced(q)) {
|
|
run_queue = false;
|
|
bypass_insert = false;
|
|
goto insert;
|
|
}
|
|
|
|
if (q->elevator && !bypass_insert)
|
|
goto insert;
|
|
|
|
if (!blk_mq_get_dispatch_budget(q))
|
|
goto insert;
|
|
|
|
if (!blk_mq_get_driver_tag(rq)) {
|
|
blk_mq_put_dispatch_budget(q);
|
|
goto insert;
|
|
}
|
|
|
|
return __blk_mq_issue_directly(hctx, rq, cookie, last);
|
|
insert:
|
|
if (bypass_insert)
|
|
return BLK_STS_RESOURCE;
|
|
|
|
blk_mq_sched_insert_request(rq, false, run_queue, false);
|
|
|
|
return BLK_STS_OK;
|
|
}
|
|
|
|
/**
|
|
* blk_mq_try_issue_directly - Try to send a request directly to device driver.
|
|
* @hctx: Pointer of the associated hardware queue.
|
|
* @rq: Pointer to request to be sent.
|
|
* @cookie: Request queue cookie.
|
|
*
|
|
* If the device has enough resources to accept a new request now, send the
|
|
* request directly to device driver. Else, insert at hctx->dispatch queue, so
|
|
* we can try send it another time in the future. Requests inserted at this
|
|
* queue have higher priority.
|
|
*/
|
|
static void blk_mq_try_issue_directly(struct blk_mq_hw_ctx *hctx,
|
|
struct request *rq, blk_qc_t *cookie)
|
|
{
|
|
blk_status_t ret;
|
|
int srcu_idx;
|
|
|
|
might_sleep_if(hctx->flags & BLK_MQ_F_BLOCKING);
|
|
|
|
hctx_lock(hctx, &srcu_idx);
|
|
|
|
ret = __blk_mq_try_issue_directly(hctx, rq, cookie, false, true);
|
|
if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE)
|
|
blk_mq_request_bypass_insert(rq, false, true);
|
|
else if (ret != BLK_STS_OK)
|
|
blk_mq_end_request(rq, ret);
|
|
|
|
hctx_unlock(hctx, srcu_idx);
|
|
}
|
|
|
|
blk_status_t blk_mq_request_issue_directly(struct request *rq, bool last)
|
|
{
|
|
blk_status_t ret;
|
|
int srcu_idx;
|
|
blk_qc_t unused_cookie;
|
|
struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
|
|
|
|
hctx_lock(hctx, &srcu_idx);
|
|
ret = __blk_mq_try_issue_directly(hctx, rq, &unused_cookie, true, last);
|
|
hctx_unlock(hctx, srcu_idx);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
|
|
struct list_head *list)
|
|
{
|
|
int queued = 0;
|
|
int errors = 0;
|
|
|
|
while (!list_empty(list)) {
|
|
blk_status_t ret;
|
|
struct request *rq = list_first_entry(list, struct request,
|
|
queuelist);
|
|
|
|
list_del_init(&rq->queuelist);
|
|
ret = blk_mq_request_issue_directly(rq, list_empty(list));
|
|
if (ret != BLK_STS_OK) {
|
|
errors++;
|
|
if (ret == BLK_STS_RESOURCE ||
|
|
ret == BLK_STS_DEV_RESOURCE) {
|
|
blk_mq_request_bypass_insert(rq, false,
|
|
list_empty(list));
|
|
break;
|
|
}
|
|
blk_mq_end_request(rq, ret);
|
|
} else
|
|
queued++;
|
|
}
|
|
|
|
/*
|
|
* If we didn't flush the entire list, we could have told
|
|
* the driver there was more coming, but that turned out to
|
|
* be a lie.
|
|
*/
|
|
if ((!list_empty(list) || errors) &&
|
|
hctx->queue->mq_ops->commit_rqs && queued)
|
|
hctx->queue->mq_ops->commit_rqs(hctx);
|
|
}
|
|
|
|
static void blk_add_rq_to_plug(struct blk_plug *plug, struct request *rq)
|
|
{
|
|
list_add_tail(&rq->queuelist, &plug->mq_list);
|
|
plug->rq_count++;
|
|
if (!plug->multiple_queues && !list_is_singular(&plug->mq_list)) {
|
|
struct request *tmp;
|
|
|
|
tmp = list_first_entry(&plug->mq_list, struct request,
|
|
queuelist);
|
|
if (tmp->q != rq->q)
|
|
plug->multiple_queues = true;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Allow 2x BLK_MAX_REQUEST_COUNT requests on plug queue for multiple
|
|
* queues. This is important for md arrays to benefit from merging
|
|
* requests.
|
|
*/
|
|
static inline unsigned short blk_plug_max_rq_count(struct blk_plug *plug)
|
|
{
|
|
if (plug->multiple_queues)
|
|
return BLK_MAX_REQUEST_COUNT * 2;
|
|
return BLK_MAX_REQUEST_COUNT;
|
|
}
|
|
|
|
/**
|
|
* blk_mq_submit_bio - Create and send a request to block device.
|
|
* @bio: Bio pointer.
|
|
*
|
|
* Builds up a request structure from @q and @bio and send to the device. The
|
|
* request may not be queued directly to hardware if:
|
|
* * This request can be merged with another one
|
|
* * We want to place request at plug queue for possible future merging
|
|
* * There is an IO scheduler active at this queue
|
|
*
|
|
* It will not queue the request if there is an error with the bio, or at the
|
|
* request creation.
|
|
*
|
|
* Returns: Request queue cookie.
|
|
*/
|
|
blk_qc_t blk_mq_submit_bio(struct bio *bio)
|
|
{
|
|
struct request_queue *q = bio->bi_disk->queue;
|
|
const int is_sync = op_is_sync(bio->bi_opf);
|
|
const int is_flush_fua = op_is_flush(bio->bi_opf);
|
|
struct blk_mq_alloc_data data = {
|
|
.q = q,
|
|
};
|
|
struct request *rq;
|
|
struct blk_plug *plug;
|
|
struct request *same_queue_rq = NULL;
|
|
unsigned int nr_segs;
|
|
blk_qc_t cookie;
|
|
blk_status_t ret;
|
|
|
|
blk_queue_bounce(q, &bio);
|
|
__blk_queue_split(&bio, &nr_segs);
|
|
|
|
if (!bio_integrity_prep(bio))
|
|
goto queue_exit;
|
|
|
|
if (!is_flush_fua && !blk_queue_nomerges(q) &&
|
|
blk_attempt_plug_merge(q, bio, nr_segs, &same_queue_rq))
|
|
goto queue_exit;
|
|
|
|
if (blk_mq_sched_bio_merge(q, bio, nr_segs))
|
|
goto queue_exit;
|
|
|
|
rq_qos_throttle(q, bio);
|
|
|
|
data.cmd_flags = bio->bi_opf;
|
|
rq = __blk_mq_alloc_request(&data);
|
|
if (unlikely(!rq)) {
|
|
rq_qos_cleanup(q, bio);
|
|
if (bio->bi_opf & REQ_NOWAIT)
|
|
bio_wouldblock_error(bio);
|
|
goto queue_exit;
|
|
}
|
|
|
|
trace_block_getrq(q, bio, bio->bi_opf);
|
|
|
|
rq_qos_track(q, rq, bio);
|
|
|
|
cookie = request_to_qc_t(data.hctx, rq);
|
|
|
|
blk_mq_bio_to_request(rq, bio, nr_segs);
|
|
|
|
ret = blk_crypto_init_request(rq);
|
|
if (ret != BLK_STS_OK) {
|
|
bio->bi_status = ret;
|
|
bio_endio(bio);
|
|
blk_mq_free_request(rq);
|
|
return BLK_QC_T_NONE;
|
|
}
|
|
|
|
plug = blk_mq_plug(q, bio);
|
|
if (unlikely(is_flush_fua)) {
|
|
/* Bypass scheduler for flush requests */
|
|
blk_insert_flush(rq);
|
|
blk_mq_run_hw_queue(data.hctx, true);
|
|
} else if (plug && (q->nr_hw_queues == 1 ||
|
|
blk_mq_is_sbitmap_shared(rq->mq_hctx->flags) ||
|
|
q->mq_ops->commit_rqs || !blk_queue_nonrot(q))) {
|
|
/*
|
|
* Use plugging if we have a ->commit_rqs() hook as well, as
|
|
* we know the driver uses bd->last in a smart fashion.
|
|
*
|
|
* Use normal plugging if this disk is slow HDD, as sequential
|
|
* IO may benefit a lot from plug merging.
|
|
*/
|
|
unsigned int request_count = plug->rq_count;
|
|
struct request *last = NULL;
|
|
|
|
if (!request_count)
|
|
trace_block_plug(q);
|
|
else
|
|
last = list_entry_rq(plug->mq_list.prev);
|
|
|
|
if (request_count >= blk_plug_max_rq_count(plug) || (last &&
|
|
blk_rq_bytes(last) >= BLK_PLUG_FLUSH_SIZE)) {
|
|
blk_flush_plug_list(plug, false);
|
|
trace_block_plug(q);
|
|
}
|
|
|
|
blk_add_rq_to_plug(plug, rq);
|
|
} else if (q->elevator) {
|
|
/* Insert the request at the IO scheduler queue */
|
|
blk_mq_sched_insert_request(rq, false, true, true);
|
|
} else if (plug && !blk_queue_nomerges(q)) {
|
|
/*
|
|
* We do limited plugging. If the bio can be merged, do that.
|
|
* Otherwise the existing request in the plug list will be
|
|
* issued. So the plug list will have one request at most
|
|
* The plug list might get flushed before this. If that happens,
|
|
* the plug list is empty, and same_queue_rq is invalid.
|
|
*/
|
|
if (list_empty(&plug->mq_list))
|
|
same_queue_rq = NULL;
|
|
if (same_queue_rq) {
|
|
list_del_init(&same_queue_rq->queuelist);
|
|
plug->rq_count--;
|
|
}
|
|
blk_add_rq_to_plug(plug, rq);
|
|
trace_block_plug(q);
|
|
|
|
if (same_queue_rq) {
|
|
data.hctx = same_queue_rq->mq_hctx;
|
|
trace_block_unplug(q, 1, true);
|
|
blk_mq_try_issue_directly(data.hctx, same_queue_rq,
|
|
&cookie);
|
|
}
|
|
} else if ((q->nr_hw_queues > 1 && is_sync) ||
|
|
!data.hctx->dispatch_busy) {
|
|
/*
|
|
* There is no scheduler and we can try to send directly
|
|
* to the hardware.
|
|
*/
|
|
blk_mq_try_issue_directly(data.hctx, rq, &cookie);
|
|
} else {
|
|
/* Default case. */
|
|
blk_mq_sched_insert_request(rq, false, true, true);
|
|
}
|
|
|
|
return cookie;
|
|
queue_exit:
|
|
blk_queue_exit(q);
|
|
return BLK_QC_T_NONE;
|
|
}
|
|
|
|
static size_t order_to_size(unsigned int order)
|
|
{
|
|
return (size_t)PAGE_SIZE << order;
|
|
}
|
|
|
|
/* called before freeing request pool in @tags */
|
|
static void blk_mq_clear_rq_mapping(struct blk_mq_tag_set *set,
|
|
struct blk_mq_tags *tags, unsigned int hctx_idx)
|
|
{
|
|
struct blk_mq_tags *drv_tags = set->tags[hctx_idx];
|
|
struct page *page;
|
|
unsigned long flags;
|
|
|
|
list_for_each_entry(page, &tags->page_list, lru) {
|
|
unsigned long start = (unsigned long)page_address(page);
|
|
unsigned long end = start + order_to_size(page->private);
|
|
int i;
|
|
|
|
for (i = 0; i < set->queue_depth; i++) {
|
|
struct request *rq = drv_tags->rqs[i];
|
|
unsigned long rq_addr = (unsigned long)rq;
|
|
|
|
if (rq_addr >= start && rq_addr < end) {
|
|
WARN_ON_ONCE(refcount_read(&rq->ref) != 0);
|
|
cmpxchg(&drv_tags->rqs[i], rq, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Wait until all pending iteration is done.
|
|
*
|
|
* Request reference is cleared and it is guaranteed to be observed
|
|
* after the ->lock is released.
|
|
*/
|
|
spin_lock_irqsave(&drv_tags->lock, flags);
|
|
spin_unlock_irqrestore(&drv_tags->lock, flags);
|
|
}
|
|
|
|
void blk_mq_free_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
|
|
unsigned int hctx_idx)
|
|
{
|
|
struct page *page;
|
|
|
|
if (tags->rqs && set->ops->exit_request) {
|
|
int i;
|
|
|
|
for (i = 0; i < tags->nr_tags; i++) {
|
|
struct request *rq = tags->static_rqs[i];
|
|
|
|
if (!rq)
|
|
continue;
|
|
set->ops->exit_request(set, rq, hctx_idx);
|
|
tags->static_rqs[i] = NULL;
|
|
}
|
|
}
|
|
|
|
blk_mq_clear_rq_mapping(set, tags, hctx_idx);
|
|
|
|
while (!list_empty(&tags->page_list)) {
|
|
page = list_first_entry(&tags->page_list, struct page, lru);
|
|
list_del_init(&page->lru);
|
|
/*
|
|
* Remove kmemleak object previously allocated in
|
|
* blk_mq_alloc_rqs().
|
|
*/
|
|
kmemleak_free(page_address(page));
|
|
__free_pages(page, page->private);
|
|
}
|
|
}
|
|
|
|
void blk_mq_free_rq_map(struct blk_mq_tags *tags, unsigned int flags)
|
|
{
|
|
kfree(tags->rqs);
|
|
tags->rqs = NULL;
|
|
kfree(tags->static_rqs);
|
|
tags->static_rqs = NULL;
|
|
|
|
blk_mq_free_tags(tags, flags);
|
|
}
|
|
|
|
struct blk_mq_tags *blk_mq_alloc_rq_map(struct blk_mq_tag_set *set,
|
|
unsigned int hctx_idx,
|
|
unsigned int nr_tags,
|
|
unsigned int reserved_tags,
|
|
unsigned int flags)
|
|
{
|
|
struct blk_mq_tags *tags;
|
|
int node;
|
|
|
|
node = blk_mq_hw_queue_to_node(&set->map[HCTX_TYPE_DEFAULT], hctx_idx);
|
|
if (node == NUMA_NO_NODE)
|
|
node = set->numa_node;
|
|
|
|
tags = blk_mq_init_tags(nr_tags, reserved_tags, node, flags);
|
|
if (!tags)
|
|
return NULL;
|
|
|
|
tags->rqs = kcalloc_node(nr_tags, sizeof(struct request *),
|
|
GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY,
|
|
node);
|
|
if (!tags->rqs) {
|
|
blk_mq_free_tags(tags, flags);
|
|
return NULL;
|
|
}
|
|
|
|
tags->static_rqs = kcalloc_node(nr_tags, sizeof(struct request *),
|
|
GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY,
|
|
node);
|
|
if (!tags->static_rqs) {
|
|
kfree(tags->rqs);
|
|
blk_mq_free_tags(tags, flags);
|
|
return NULL;
|
|
}
|
|
|
|
return tags;
|
|
}
|
|
|
|
static int blk_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
|
|
unsigned int hctx_idx, int node)
|
|
{
|
|
int ret;
|
|
|
|
if (set->ops->init_request) {
|
|
ret = set->ops->init_request(set, rq, hctx_idx, node);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
WRITE_ONCE(rq->state, MQ_RQ_IDLE);
|
|
return 0;
|
|
}
|
|
|
|
int blk_mq_alloc_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
|
|
unsigned int hctx_idx, unsigned int depth)
|
|
{
|
|
unsigned int i, j, entries_per_page, max_order = 4;
|
|
size_t rq_size, left;
|
|
int node;
|
|
|
|
node = blk_mq_hw_queue_to_node(&set->map[HCTX_TYPE_DEFAULT], hctx_idx);
|
|
if (node == NUMA_NO_NODE)
|
|
node = set->numa_node;
|
|
|
|
INIT_LIST_HEAD(&tags->page_list);
|
|
|
|
/*
|
|
* rq_size is the size of the request plus driver payload, rounded
|
|
* to the cacheline size
|
|
*/
|
|
rq_size = round_up(sizeof(struct request) + set->cmd_size,
|
|
cache_line_size());
|
|
trace_android_vh_blk_alloc_rqs(&rq_size, set, tags);
|
|
left = rq_size * depth;
|
|
|
|
for (i = 0; i < depth; ) {
|
|
int this_order = max_order;
|
|
struct page *page;
|
|
int to_do;
|
|
void *p;
|
|
|
|
while (this_order && left < order_to_size(this_order - 1))
|
|
this_order--;
|
|
|
|
do {
|
|
page = alloc_pages_node(node,
|
|
GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO,
|
|
this_order);
|
|
if (page)
|
|
break;
|
|
if (!this_order--)
|
|
break;
|
|
if (order_to_size(this_order) < rq_size)
|
|
break;
|
|
} while (1);
|
|
|
|
if (!page)
|
|
goto fail;
|
|
|
|
page->private = this_order;
|
|
list_add_tail(&page->lru, &tags->page_list);
|
|
|
|
p = page_address(page);
|
|
/*
|
|
* Allow kmemleak to scan these pages as they contain pointers
|
|
* to additional allocations like via ops->init_request().
|
|
*/
|
|
kmemleak_alloc(p, order_to_size(this_order), 1, GFP_NOIO);
|
|
entries_per_page = order_to_size(this_order) / rq_size;
|
|
to_do = min(entries_per_page, depth - i);
|
|
left -= to_do * rq_size;
|
|
for (j = 0; j < to_do; j++) {
|
|
struct request *rq = p;
|
|
|
|
tags->static_rqs[i] = rq;
|
|
if (blk_mq_init_request(set, rq, hctx_idx, node)) {
|
|
tags->static_rqs[i] = NULL;
|
|
goto fail;
|
|
}
|
|
|
|
p += rq_size;
|
|
i++;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
fail:
|
|
blk_mq_free_rqs(set, tags, hctx_idx);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
struct rq_iter_data {
|
|
struct blk_mq_hw_ctx *hctx;
|
|
bool has_rq;
|
|
};
|
|
|
|
static bool blk_mq_has_request(struct request *rq, void *data, bool reserved)
|
|
{
|
|
struct rq_iter_data *iter_data = data;
|
|
|
|
if (rq->mq_hctx != iter_data->hctx)
|
|
return true;
|
|
iter_data->has_rq = true;
|
|
return false;
|
|
}
|
|
|
|
static bool blk_mq_hctx_has_requests(struct blk_mq_hw_ctx *hctx)
|
|
{
|
|
struct blk_mq_tags *tags = hctx->sched_tags ?
|
|
hctx->sched_tags : hctx->tags;
|
|
struct rq_iter_data data = {
|
|
.hctx = hctx,
|
|
};
|
|
|
|
blk_mq_all_tag_iter(tags, blk_mq_has_request, &data);
|
|
return data.has_rq;
|
|
}
|
|
|
|
static inline bool blk_mq_last_cpu_in_hctx(unsigned int cpu,
|
|
struct blk_mq_hw_ctx *hctx)
|
|
{
|
|
if (cpumask_next_and(-1, hctx->cpumask, cpu_online_mask) != cpu)
|
|
return false;
|
|
if (cpumask_next_and(cpu, hctx->cpumask, cpu_online_mask) < nr_cpu_ids)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static int blk_mq_hctx_notify_offline(unsigned int cpu, struct hlist_node *node)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx = hlist_entry_safe(node,
|
|
struct blk_mq_hw_ctx, cpuhp_online);
|
|
|
|
if (!cpumask_test_cpu(cpu, hctx->cpumask) ||
|
|
!blk_mq_last_cpu_in_hctx(cpu, hctx))
|
|
return 0;
|
|
|
|
/*
|
|
* Prevent new request from being allocated on the current hctx.
|
|
*
|
|
* The smp_mb__after_atomic() Pairs with the implied barrier in
|
|
* test_and_set_bit_lock in sbitmap_get(). Ensures the inactive flag is
|
|
* seen once we return from the tag allocator.
|
|
*/
|
|
set_bit(BLK_MQ_S_INACTIVE, &hctx->state);
|
|
smp_mb__after_atomic();
|
|
|
|
/*
|
|
* Try to grab a reference to the queue and wait for any outstanding
|
|
* requests. If we could not grab a reference the queue has been
|
|
* frozen and there are no requests.
|
|
*/
|
|
if (percpu_ref_tryget(&hctx->queue->q_usage_counter)) {
|
|
while (blk_mq_hctx_has_requests(hctx))
|
|
msleep(5);
|
|
percpu_ref_put(&hctx->queue->q_usage_counter);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int blk_mq_hctx_notify_online(unsigned int cpu, struct hlist_node *node)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx = hlist_entry_safe(node,
|
|
struct blk_mq_hw_ctx, cpuhp_online);
|
|
|
|
if (cpumask_test_cpu(cpu, hctx->cpumask))
|
|
clear_bit(BLK_MQ_S_INACTIVE, &hctx->state);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 'cpu' is going away. splice any existing rq_list entries from this
|
|
* software queue to the hw queue dispatch list, and ensure that it
|
|
* gets run.
|
|
*/
|
|
static int blk_mq_hctx_notify_dead(unsigned int cpu, struct hlist_node *node)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
struct blk_mq_ctx *ctx;
|
|
LIST_HEAD(tmp);
|
|
enum hctx_type type;
|
|
|
|
hctx = hlist_entry_safe(node, struct blk_mq_hw_ctx, cpuhp_dead);
|
|
if (!cpumask_test_cpu(cpu, hctx->cpumask))
|
|
return 0;
|
|
|
|
ctx = __blk_mq_get_ctx(hctx->queue, cpu);
|
|
type = hctx->type;
|
|
|
|
spin_lock(&ctx->lock);
|
|
if (!list_empty(&ctx->rq_lists[type])) {
|
|
list_splice_init(&ctx->rq_lists[type], &tmp);
|
|
blk_mq_hctx_clear_pending(hctx, ctx);
|
|
}
|
|
spin_unlock(&ctx->lock);
|
|
|
|
if (list_empty(&tmp))
|
|
return 0;
|
|
|
|
spin_lock(&hctx->lock);
|
|
list_splice_tail_init(&tmp, &hctx->dispatch);
|
|
spin_unlock(&hctx->lock);
|
|
|
|
blk_mq_run_hw_queue(hctx, true);
|
|
return 0;
|
|
}
|
|
|
|
static void blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx)
|
|
{
|
|
if (!(hctx->flags & BLK_MQ_F_STACKING))
|
|
cpuhp_state_remove_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE,
|
|
&hctx->cpuhp_online);
|
|
cpuhp_state_remove_instance_nocalls(CPUHP_BLK_MQ_DEAD,
|
|
&hctx->cpuhp_dead);
|
|
}
|
|
|
|
/*
|
|
* Before freeing hw queue, clearing the flush request reference in
|
|
* tags->rqs[] for avoiding potential UAF.
|
|
*/
|
|
static void blk_mq_clear_flush_rq_mapping(struct blk_mq_tags *tags,
|
|
unsigned int queue_depth, struct request *flush_rq)
|
|
{
|
|
int i;
|
|
unsigned long flags;
|
|
|
|
/* The hw queue may not be mapped yet */
|
|
if (!tags)
|
|
return;
|
|
|
|
WARN_ON_ONCE(refcount_read(&flush_rq->ref) != 0);
|
|
|
|
for (i = 0; i < queue_depth; i++)
|
|
cmpxchg(&tags->rqs[i], flush_rq, NULL);
|
|
|
|
/*
|
|
* Wait until all pending iteration is done.
|
|
*
|
|
* Request reference is cleared and it is guaranteed to be observed
|
|
* after the ->lock is released.
|
|
*/
|
|
spin_lock_irqsave(&tags->lock, flags);
|
|
spin_unlock_irqrestore(&tags->lock, flags);
|
|
}
|
|
|
|
/* hctx->ctxs will be freed in queue's release handler */
|
|
static void blk_mq_exit_hctx(struct request_queue *q,
|
|
struct blk_mq_tag_set *set,
|
|
struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx)
|
|
{
|
|
struct request *flush_rq = hctx->fq->flush_rq;
|
|
|
|
if (blk_mq_hw_queue_mapped(hctx))
|
|
blk_mq_tag_idle(hctx);
|
|
|
|
blk_mq_clear_flush_rq_mapping(set->tags[hctx_idx],
|
|
set->queue_depth, flush_rq);
|
|
if (set->ops->exit_request)
|
|
set->ops->exit_request(set, flush_rq, hctx_idx);
|
|
|
|
if (set->ops->exit_hctx)
|
|
set->ops->exit_hctx(hctx, hctx_idx);
|
|
|
|
blk_mq_remove_cpuhp(hctx);
|
|
|
|
spin_lock(&q->unused_hctx_lock);
|
|
list_add(&hctx->hctx_list, &q->unused_hctx_list);
|
|
spin_unlock(&q->unused_hctx_lock);
|
|
}
|
|
|
|
static void blk_mq_exit_hw_queues(struct request_queue *q,
|
|
struct blk_mq_tag_set *set, int nr_queue)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
unsigned int i;
|
|
|
|
queue_for_each_hw_ctx(q, hctx, i) {
|
|
if (i == nr_queue)
|
|
break;
|
|
blk_mq_debugfs_unregister_hctx(hctx);
|
|
blk_mq_exit_hctx(q, set, hctx, i);
|
|
}
|
|
}
|
|
|
|
static int blk_mq_hw_ctx_size(struct blk_mq_tag_set *tag_set)
|
|
{
|
|
int hw_ctx_size = sizeof(struct blk_mq_hw_ctx);
|
|
|
|
BUILD_BUG_ON(ALIGN(offsetof(struct blk_mq_hw_ctx, srcu),
|
|
__alignof__(struct blk_mq_hw_ctx)) !=
|
|
sizeof(struct blk_mq_hw_ctx));
|
|
|
|
if (tag_set->flags & BLK_MQ_F_BLOCKING)
|
|
hw_ctx_size += sizeof(struct srcu_struct);
|
|
|
|
return hw_ctx_size;
|
|
}
|
|
|
|
static int blk_mq_init_hctx(struct request_queue *q,
|
|
struct blk_mq_tag_set *set,
|
|
struct blk_mq_hw_ctx *hctx, unsigned hctx_idx)
|
|
{
|
|
hctx->queue_num = hctx_idx;
|
|
|
|
if (!(hctx->flags & BLK_MQ_F_STACKING))
|
|
cpuhp_state_add_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE,
|
|
&hctx->cpuhp_online);
|
|
cpuhp_state_add_instance_nocalls(CPUHP_BLK_MQ_DEAD, &hctx->cpuhp_dead);
|
|
|
|
hctx->tags = set->tags[hctx_idx];
|
|
|
|
if (set->ops->init_hctx &&
|
|
set->ops->init_hctx(hctx, set->driver_data, hctx_idx))
|
|
goto unregister_cpu_notifier;
|
|
|
|
if (blk_mq_init_request(set, hctx->fq->flush_rq, hctx_idx,
|
|
hctx->numa_node))
|
|
goto exit_hctx;
|
|
return 0;
|
|
|
|
exit_hctx:
|
|
if (set->ops->exit_hctx)
|
|
set->ops->exit_hctx(hctx, hctx_idx);
|
|
unregister_cpu_notifier:
|
|
blk_mq_remove_cpuhp(hctx);
|
|
return -1;
|
|
}
|
|
|
|
static struct blk_mq_hw_ctx *
|
|
blk_mq_alloc_hctx(struct request_queue *q, struct blk_mq_tag_set *set,
|
|
int node)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
gfp_t gfp = GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY;
|
|
|
|
hctx = kzalloc_node(blk_mq_hw_ctx_size(set), gfp, node);
|
|
if (!hctx)
|
|
goto fail_alloc_hctx;
|
|
|
|
if (!zalloc_cpumask_var_node(&hctx->cpumask, gfp, node))
|
|
goto free_hctx;
|
|
|
|
atomic_set(&hctx->nr_active, 0);
|
|
if (node == NUMA_NO_NODE)
|
|
node = set->numa_node;
|
|
hctx->numa_node = node;
|
|
|
|
INIT_DELAYED_WORK(&hctx->run_work, blk_mq_run_work_fn);
|
|
spin_lock_init(&hctx->lock);
|
|
INIT_LIST_HEAD(&hctx->dispatch);
|
|
hctx->queue = q;
|
|
hctx->flags = set->flags & ~BLK_MQ_F_TAG_QUEUE_SHARED;
|
|
|
|
INIT_LIST_HEAD(&hctx->hctx_list);
|
|
|
|
/*
|
|
* Allocate space for all possible cpus to avoid allocation at
|
|
* runtime
|
|
*/
|
|
hctx->ctxs = kmalloc_array_node(nr_cpu_ids, sizeof(void *),
|
|
gfp, node);
|
|
if (!hctx->ctxs)
|
|
goto free_cpumask;
|
|
|
|
if (sbitmap_init_node(&hctx->ctx_map, nr_cpu_ids, ilog2(8),
|
|
gfp, node))
|
|
goto free_ctxs;
|
|
hctx->nr_ctx = 0;
|
|
|
|
spin_lock_init(&hctx->dispatch_wait_lock);
|
|
init_waitqueue_func_entry(&hctx->dispatch_wait, blk_mq_dispatch_wake);
|
|
INIT_LIST_HEAD(&hctx->dispatch_wait.entry);
|
|
|
|
hctx->fq = blk_alloc_flush_queue(hctx->numa_node, set->cmd_size, gfp);
|
|
if (!hctx->fq)
|
|
goto free_bitmap;
|
|
|
|
if (hctx->flags & BLK_MQ_F_BLOCKING)
|
|
init_srcu_struct(hctx->srcu);
|
|
blk_mq_hctx_kobj_init(hctx);
|
|
|
|
return hctx;
|
|
|
|
free_bitmap:
|
|
sbitmap_free(&hctx->ctx_map);
|
|
free_ctxs:
|
|
kfree(hctx->ctxs);
|
|
free_cpumask:
|
|
free_cpumask_var(hctx->cpumask);
|
|
free_hctx:
|
|
kfree(hctx);
|
|
fail_alloc_hctx:
|
|
return NULL;
|
|
}
|
|
|
|
static void blk_mq_init_cpu_queues(struct request_queue *q,
|
|
unsigned int nr_hw_queues)
|
|
{
|
|
struct blk_mq_tag_set *set = q->tag_set;
|
|
unsigned int i, j;
|
|
|
|
for_each_possible_cpu(i) {
|
|
struct blk_mq_ctx *__ctx = per_cpu_ptr(q->queue_ctx, i);
|
|
struct blk_mq_hw_ctx *hctx;
|
|
int k;
|
|
|
|
__ctx->cpu = i;
|
|
spin_lock_init(&__ctx->lock);
|
|
for (k = HCTX_TYPE_DEFAULT; k < HCTX_MAX_TYPES; k++)
|
|
INIT_LIST_HEAD(&__ctx->rq_lists[k]);
|
|
|
|
__ctx->queue = q;
|
|
|
|
/*
|
|
* Set local node, IFF we have more than one hw queue. If
|
|
* not, we remain on the home node of the device
|
|
*/
|
|
for (j = 0; j < set->nr_maps; j++) {
|
|
hctx = blk_mq_map_queue_type(q, j, i);
|
|
if (nr_hw_queues > 1 && hctx->numa_node == NUMA_NO_NODE)
|
|
hctx->numa_node = cpu_to_node(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool __blk_mq_alloc_map_and_request(struct blk_mq_tag_set *set,
|
|
int hctx_idx)
|
|
{
|
|
unsigned int flags = set->flags;
|
|
int ret = 0;
|
|
|
|
set->tags[hctx_idx] = blk_mq_alloc_rq_map(set, hctx_idx,
|
|
set->queue_depth, set->reserved_tags, flags);
|
|
if (!set->tags[hctx_idx])
|
|
return false;
|
|
|
|
ret = blk_mq_alloc_rqs(set, set->tags[hctx_idx], hctx_idx,
|
|
set->queue_depth);
|
|
if (!ret)
|
|
return true;
|
|
|
|
blk_mq_free_rq_map(set->tags[hctx_idx], flags);
|
|
set->tags[hctx_idx] = NULL;
|
|
return false;
|
|
}
|
|
|
|
static void blk_mq_free_map_and_requests(struct blk_mq_tag_set *set,
|
|
unsigned int hctx_idx)
|
|
{
|
|
unsigned int flags = set->flags;
|
|
|
|
if (set->tags && set->tags[hctx_idx]) {
|
|
blk_mq_free_rqs(set, set->tags[hctx_idx], hctx_idx);
|
|
blk_mq_free_rq_map(set->tags[hctx_idx], flags);
|
|
set->tags[hctx_idx] = NULL;
|
|
}
|
|
}
|
|
|
|
static void blk_mq_map_swqueue(struct request_queue *q)
|
|
{
|
|
unsigned int i, j, hctx_idx;
|
|
struct blk_mq_hw_ctx *hctx;
|
|
struct blk_mq_ctx *ctx;
|
|
struct blk_mq_tag_set *set = q->tag_set;
|
|
|
|
queue_for_each_hw_ctx(q, hctx, i) {
|
|
cpumask_clear(hctx->cpumask);
|
|
hctx->nr_ctx = 0;
|
|
hctx->dispatch_from = NULL;
|
|
}
|
|
|
|
/*
|
|
* Map software to hardware queues.
|
|
*
|
|
* If the cpu isn't present, the cpu is mapped to first hctx.
|
|
*/
|
|
for_each_possible_cpu(i) {
|
|
|
|
ctx = per_cpu_ptr(q->queue_ctx, i);
|
|
for (j = 0; j < set->nr_maps; j++) {
|
|
if (!set->map[j].nr_queues) {
|
|
ctx->hctxs[j] = blk_mq_map_queue_type(q,
|
|
HCTX_TYPE_DEFAULT, i);
|
|
continue;
|
|
}
|
|
hctx_idx = set->map[j].mq_map[i];
|
|
/* unmapped hw queue can be remapped after CPU topo changed */
|
|
if (!set->tags[hctx_idx] &&
|
|
!__blk_mq_alloc_map_and_request(set, hctx_idx)) {
|
|
/*
|
|
* If tags initialization fail for some hctx,
|
|
* that hctx won't be brought online. In this
|
|
* case, remap the current ctx to hctx[0] which
|
|
* is guaranteed to always have tags allocated
|
|
*/
|
|
set->map[j].mq_map[i] = 0;
|
|
}
|
|
|
|
hctx = blk_mq_map_queue_type(q, j, i);
|
|
ctx->hctxs[j] = hctx;
|
|
/*
|
|
* If the CPU is already set in the mask, then we've
|
|
* mapped this one already. This can happen if
|
|
* devices share queues across queue maps.
|
|
*/
|
|
if (cpumask_test_cpu(i, hctx->cpumask))
|
|
continue;
|
|
|
|
cpumask_set_cpu(i, hctx->cpumask);
|
|
hctx->type = j;
|
|
ctx->index_hw[hctx->type] = hctx->nr_ctx;
|
|
hctx->ctxs[hctx->nr_ctx++] = ctx;
|
|
|
|
/*
|
|
* If the nr_ctx type overflows, we have exceeded the
|
|
* amount of sw queues we can support.
|
|
*/
|
|
BUG_ON(!hctx->nr_ctx);
|
|
}
|
|
|
|
for (; j < HCTX_MAX_TYPES; j++)
|
|
ctx->hctxs[j] = blk_mq_map_queue_type(q,
|
|
HCTX_TYPE_DEFAULT, i);
|
|
}
|
|
|
|
queue_for_each_hw_ctx(q, hctx, i) {
|
|
/*
|
|
* If no software queues are mapped to this hardware queue,
|
|
* disable it and free the request entries.
|
|
*/
|
|
if (!hctx->nr_ctx) {
|
|
/* Never unmap queue 0. We need it as a
|
|
* fallback in case of a new remap fails
|
|
* allocation
|
|
*/
|
|
if (i && set->tags[i])
|
|
blk_mq_free_map_and_requests(set, i);
|
|
|
|
hctx->tags = NULL;
|
|
continue;
|
|
}
|
|
|
|
hctx->tags = set->tags[i];
|
|
WARN_ON(!hctx->tags);
|
|
|
|
/*
|
|
* Set the map size to the number of mapped software queues.
|
|
* This is more accurate and more efficient than looping
|
|
* over all possibly mapped software queues.
|
|
*/
|
|
sbitmap_resize(&hctx->ctx_map, hctx->nr_ctx);
|
|
|
|
/*
|
|
* Initialize batch roundrobin counts
|
|
*/
|
|
hctx->next_cpu = blk_mq_first_mapped_cpu(hctx);
|
|
hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Caller needs to ensure that we're either frozen/quiesced, or that
|
|
* the queue isn't live yet.
|
|
*/
|
|
static void queue_set_hctx_shared(struct request_queue *q, bool shared)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
int i;
|
|
|
|
queue_for_each_hw_ctx(q, hctx, i) {
|
|
if (shared)
|
|
hctx->flags |= BLK_MQ_F_TAG_QUEUE_SHARED;
|
|
else
|
|
hctx->flags &= ~BLK_MQ_F_TAG_QUEUE_SHARED;
|
|
}
|
|
}
|
|
|
|
static void blk_mq_update_tag_set_shared(struct blk_mq_tag_set *set,
|
|
bool shared)
|
|
{
|
|
struct request_queue *q;
|
|
|
|
lockdep_assert_held(&set->tag_list_lock);
|
|
|
|
list_for_each_entry(q, &set->tag_list, tag_set_list) {
|
|
blk_mq_freeze_queue(q);
|
|
queue_set_hctx_shared(q, shared);
|
|
blk_mq_unfreeze_queue(q);
|
|
}
|
|
}
|
|
|
|
static void blk_mq_del_queue_tag_set(struct request_queue *q)
|
|
{
|
|
struct blk_mq_tag_set *set = q->tag_set;
|
|
|
|
mutex_lock(&set->tag_list_lock);
|
|
list_del(&q->tag_set_list);
|
|
if (list_is_singular(&set->tag_list)) {
|
|
/* just transitioned to unshared */
|
|
set->flags &= ~BLK_MQ_F_TAG_QUEUE_SHARED;
|
|
/* update existing queue */
|
|
blk_mq_update_tag_set_shared(set, false);
|
|
}
|
|
mutex_unlock(&set->tag_list_lock);
|
|
INIT_LIST_HEAD(&q->tag_set_list);
|
|
}
|
|
|
|
static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set,
|
|
struct request_queue *q)
|
|
{
|
|
mutex_lock(&set->tag_list_lock);
|
|
|
|
/*
|
|
* Check to see if we're transitioning to shared (from 1 to 2 queues).
|
|
*/
|
|
if (!list_empty(&set->tag_list) &&
|
|
!(set->flags & BLK_MQ_F_TAG_QUEUE_SHARED)) {
|
|
set->flags |= BLK_MQ_F_TAG_QUEUE_SHARED;
|
|
/* update existing queue */
|
|
blk_mq_update_tag_set_shared(set, true);
|
|
}
|
|
if (set->flags & BLK_MQ_F_TAG_QUEUE_SHARED)
|
|
queue_set_hctx_shared(q, true);
|
|
list_add_tail(&q->tag_set_list, &set->tag_list);
|
|
|
|
mutex_unlock(&set->tag_list_lock);
|
|
}
|
|
|
|
/* All allocations will be freed in release handler of q->mq_kobj */
|
|
static int blk_mq_alloc_ctxs(struct request_queue *q)
|
|
{
|
|
struct blk_mq_ctxs *ctxs;
|
|
int cpu;
|
|
|
|
ctxs = kzalloc(sizeof(*ctxs), GFP_KERNEL);
|
|
if (!ctxs)
|
|
return -ENOMEM;
|
|
|
|
ctxs->queue_ctx = alloc_percpu(struct blk_mq_ctx);
|
|
if (!ctxs->queue_ctx)
|
|
goto fail;
|
|
|
|
for_each_possible_cpu(cpu) {
|
|
struct blk_mq_ctx *ctx = per_cpu_ptr(ctxs->queue_ctx, cpu);
|
|
ctx->ctxs = ctxs;
|
|
}
|
|
|
|
q->mq_kobj = &ctxs->kobj;
|
|
q->queue_ctx = ctxs->queue_ctx;
|
|
|
|
return 0;
|
|
fail:
|
|
kfree(ctxs);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/*
|
|
* It is the actual release handler for mq, but we do it from
|
|
* request queue's release handler for avoiding use-after-free
|
|
* and headache because q->mq_kobj shouldn't have been introduced,
|
|
* but we can't group ctx/kctx kobj without it.
|
|
*/
|
|
void blk_mq_release(struct request_queue *q)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx, *next;
|
|
int i;
|
|
|
|
queue_for_each_hw_ctx(q, hctx, i)
|
|
WARN_ON_ONCE(hctx && list_empty(&hctx->hctx_list));
|
|
|
|
/* all hctx are in .unused_hctx_list now */
|
|
list_for_each_entry_safe(hctx, next, &q->unused_hctx_list, hctx_list) {
|
|
list_del_init(&hctx->hctx_list);
|
|
kobject_put(&hctx->kobj);
|
|
}
|
|
|
|
kfree(q->queue_hw_ctx);
|
|
|
|
/*
|
|
* release .mq_kobj and sw queue's kobject now because
|
|
* both share lifetime with request queue.
|
|
*/
|
|
blk_mq_sysfs_deinit(q);
|
|
}
|
|
|
|
struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set,
|
|
void *queuedata)
|
|
{
|
|
struct request_queue *uninit_q, *q;
|
|
|
|
uninit_q = blk_alloc_queue(set->numa_node);
|
|
if (!uninit_q)
|
|
return ERR_PTR(-ENOMEM);
|
|
uninit_q->queuedata = queuedata;
|
|
|
|
/*
|
|
* Initialize the queue without an elevator. device_add_disk() will do
|
|
* the initialization.
|
|
*/
|
|
q = blk_mq_init_allocated_queue(set, uninit_q, false);
|
|
if (IS_ERR(q))
|
|
blk_cleanup_queue(uninit_q);
|
|
|
|
return q;
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_init_queue_data);
|
|
|
|
struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
|
|
{
|
|
return blk_mq_init_queue_data(set, NULL);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_init_queue);
|
|
|
|
/*
|
|
* Helper for setting up a queue with mq ops, given queue depth, and
|
|
* the passed in mq ops flags.
|
|
*/
|
|
struct request_queue *blk_mq_init_sq_queue(struct blk_mq_tag_set *set,
|
|
const struct blk_mq_ops *ops,
|
|
unsigned int queue_depth,
|
|
unsigned int set_flags)
|
|
{
|
|
struct request_queue *q;
|
|
int ret;
|
|
|
|
memset(set, 0, sizeof(*set));
|
|
set->ops = ops;
|
|
set->nr_hw_queues = 1;
|
|
set->nr_maps = 1;
|
|
set->queue_depth = queue_depth;
|
|
set->numa_node = NUMA_NO_NODE;
|
|
set->flags = set_flags;
|
|
|
|
ret = blk_mq_alloc_tag_set(set);
|
|
if (ret)
|
|
return ERR_PTR(ret);
|
|
|
|
q = blk_mq_init_queue(set);
|
|
if (IS_ERR(q)) {
|
|
blk_mq_free_tag_set(set);
|
|
return q;
|
|
}
|
|
|
|
return q;
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_init_sq_queue);
|
|
|
|
static struct blk_mq_hw_ctx *blk_mq_alloc_and_init_hctx(
|
|
struct blk_mq_tag_set *set, struct request_queue *q,
|
|
int hctx_idx, int node)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx = NULL, *tmp;
|
|
|
|
/* reuse dead hctx first */
|
|
spin_lock(&q->unused_hctx_lock);
|
|
list_for_each_entry(tmp, &q->unused_hctx_list, hctx_list) {
|
|
if (tmp->numa_node == node) {
|
|
hctx = tmp;
|
|
break;
|
|
}
|
|
}
|
|
if (hctx)
|
|
list_del_init(&hctx->hctx_list);
|
|
spin_unlock(&q->unused_hctx_lock);
|
|
|
|
if (!hctx)
|
|
hctx = blk_mq_alloc_hctx(q, set, node);
|
|
if (!hctx)
|
|
goto fail;
|
|
|
|
if (blk_mq_init_hctx(q, set, hctx, hctx_idx))
|
|
goto free_hctx;
|
|
|
|
return hctx;
|
|
|
|
free_hctx:
|
|
kobject_put(&hctx->kobj);
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
|
|
struct request_queue *q)
|
|
{
|
|
int i, j, end;
|
|
struct blk_mq_hw_ctx **hctxs = q->queue_hw_ctx;
|
|
|
|
if (q->nr_hw_queues < set->nr_hw_queues) {
|
|
struct blk_mq_hw_ctx **new_hctxs;
|
|
|
|
new_hctxs = kcalloc_node(set->nr_hw_queues,
|
|
sizeof(*new_hctxs), GFP_KERNEL,
|
|
set->numa_node);
|
|
if (!new_hctxs)
|
|
return;
|
|
if (hctxs)
|
|
memcpy(new_hctxs, hctxs, q->nr_hw_queues *
|
|
sizeof(*hctxs));
|
|
q->queue_hw_ctx = new_hctxs;
|
|
kfree(hctxs);
|
|
hctxs = new_hctxs;
|
|
}
|
|
|
|
/* protect against switching io scheduler */
|
|
mutex_lock(&q->sysfs_lock);
|
|
for (i = 0; i < set->nr_hw_queues; i++) {
|
|
int node;
|
|
struct blk_mq_hw_ctx *hctx;
|
|
|
|
node = blk_mq_hw_queue_to_node(&set->map[HCTX_TYPE_DEFAULT], i);
|
|
/*
|
|
* If the hw queue has been mapped to another numa node,
|
|
* we need to realloc the hctx. If allocation fails, fallback
|
|
* to use the previous one.
|
|
*/
|
|
if (hctxs[i] && (hctxs[i]->numa_node == node))
|
|
continue;
|
|
|
|
hctx = blk_mq_alloc_and_init_hctx(set, q, i, node);
|
|
if (hctx) {
|
|
if (hctxs[i])
|
|
blk_mq_exit_hctx(q, set, hctxs[i], i);
|
|
hctxs[i] = hctx;
|
|
} else {
|
|
if (hctxs[i])
|
|
pr_warn("Allocate new hctx on node %d fails,\
|
|
fallback to previous one on node %d\n",
|
|
node, hctxs[i]->numa_node);
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* Increasing nr_hw_queues fails. Free the newly allocated
|
|
* hctxs and keep the previous q->nr_hw_queues.
|
|
*/
|
|
if (i != set->nr_hw_queues) {
|
|
j = q->nr_hw_queues;
|
|
end = i;
|
|
} else {
|
|
j = i;
|
|
end = q->nr_hw_queues;
|
|
q->nr_hw_queues = set->nr_hw_queues;
|
|
}
|
|
|
|
for (; j < end; j++) {
|
|
struct blk_mq_hw_ctx *hctx = hctxs[j];
|
|
|
|
if (hctx) {
|
|
if (hctx->tags)
|
|
blk_mq_free_map_and_requests(set, j);
|
|
blk_mq_exit_hctx(q, set, hctx, j);
|
|
hctxs[j] = NULL;
|
|
}
|
|
}
|
|
mutex_unlock(&q->sysfs_lock);
|
|
}
|
|
|
|
struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
|
|
struct request_queue *q,
|
|
bool elevator_init)
|
|
{
|
|
/* mark the queue as mq asap */
|
|
q->mq_ops = set->ops;
|
|
|
|
q->poll_cb = blk_stat_alloc_callback(blk_mq_poll_stats_fn,
|
|
blk_mq_poll_stats_bkt,
|
|
BLK_MQ_POLL_STATS_BKTS, q);
|
|
if (!q->poll_cb)
|
|
goto err_exit;
|
|
|
|
if (blk_mq_alloc_ctxs(q))
|
|
goto err_poll;
|
|
|
|
/* init q->mq_kobj and sw queues' kobjects */
|
|
blk_mq_sysfs_init(q);
|
|
|
|
INIT_LIST_HEAD(&q->unused_hctx_list);
|
|
spin_lock_init(&q->unused_hctx_lock);
|
|
|
|
blk_mq_realloc_hw_ctxs(set, q);
|
|
if (!q->nr_hw_queues)
|
|
goto err_hctxs;
|
|
|
|
INIT_WORK(&q->timeout_work, blk_mq_timeout_work);
|
|
blk_queue_rq_timeout(q, set->timeout ? set->timeout : 30 * HZ);
|
|
|
|
q->tag_set = set;
|
|
|
|
q->queue_flags |= QUEUE_FLAG_MQ_DEFAULT;
|
|
if (set->nr_maps > HCTX_TYPE_POLL &&
|
|
set->map[HCTX_TYPE_POLL].nr_queues)
|
|
blk_queue_flag_set(QUEUE_FLAG_POLL, q);
|
|
|
|
q->sg_reserved_size = INT_MAX;
|
|
|
|
INIT_DELAYED_WORK(&q->requeue_work, blk_mq_requeue_work);
|
|
INIT_LIST_HEAD(&q->requeue_list);
|
|
spin_lock_init(&q->requeue_lock);
|
|
|
|
q->nr_requests = set->queue_depth;
|
|
|
|
/*
|
|
* Default to classic polling
|
|
*/
|
|
q->poll_nsec = BLK_MQ_POLL_CLASSIC;
|
|
|
|
blk_mq_init_cpu_queues(q, set->nr_hw_queues);
|
|
blk_mq_add_queue_tag_set(set, q);
|
|
blk_mq_map_swqueue(q);
|
|
|
|
if (elevator_init)
|
|
elevator_init_mq(q);
|
|
|
|
return q;
|
|
|
|
err_hctxs:
|
|
kfree(q->queue_hw_ctx);
|
|
q->nr_hw_queues = 0;
|
|
blk_mq_sysfs_deinit(q);
|
|
err_poll:
|
|
blk_stat_free_callback(q->poll_cb);
|
|
q->poll_cb = NULL;
|
|
err_exit:
|
|
q->mq_ops = NULL;
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_init_allocated_queue);
|
|
|
|
/* tags can _not_ be used after returning from blk_mq_exit_queue */
|
|
void blk_mq_exit_queue(struct request_queue *q)
|
|
{
|
|
struct blk_mq_tag_set *set = q->tag_set;
|
|
|
|
/* Checks hctx->flags & BLK_MQ_F_TAG_QUEUE_SHARED. */
|
|
blk_mq_exit_hw_queues(q, set, set->nr_hw_queues);
|
|
/* May clear BLK_MQ_F_TAG_QUEUE_SHARED in hctx->flags. */
|
|
blk_mq_del_queue_tag_set(q);
|
|
}
|
|
|
|
static int __blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < set->nr_hw_queues; i++) {
|
|
if (!__blk_mq_alloc_map_and_request(set, i))
|
|
goto out_unwind;
|
|
cond_resched();
|
|
}
|
|
|
|
return 0;
|
|
|
|
out_unwind:
|
|
while (--i >= 0)
|
|
blk_mq_free_map_and_requests(set, i);
|
|
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/*
|
|
* Allocate the request maps associated with this tag_set. Note that this
|
|
* may reduce the depth asked for, if memory is tight. set->queue_depth
|
|
* will be updated to reflect the allocated depth.
|
|
*/
|
|
static int blk_mq_alloc_map_and_requests(struct blk_mq_tag_set *set)
|
|
{
|
|
unsigned int depth;
|
|
int err;
|
|
|
|
depth = set->queue_depth;
|
|
do {
|
|
err = __blk_mq_alloc_rq_maps(set);
|
|
if (!err)
|
|
break;
|
|
|
|
set->queue_depth >>= 1;
|
|
if (set->queue_depth < set->reserved_tags + BLK_MQ_TAG_MIN) {
|
|
err = -ENOMEM;
|
|
break;
|
|
}
|
|
} while (set->queue_depth);
|
|
|
|
if (!set->queue_depth || err) {
|
|
pr_err("blk-mq: failed to allocate request map\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (depth != set->queue_depth)
|
|
pr_info("blk-mq: reduced tag depth (%u -> %u)\n",
|
|
depth, set->queue_depth);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int blk_mq_update_queue_map(struct blk_mq_tag_set *set)
|
|
{
|
|
/*
|
|
* blk_mq_map_queues() and multiple .map_queues() implementations
|
|
* expect that set->map[HCTX_TYPE_DEFAULT].nr_queues is set to the
|
|
* number of hardware queues.
|
|
*/
|
|
if (set->nr_maps == 1)
|
|
set->map[HCTX_TYPE_DEFAULT].nr_queues = set->nr_hw_queues;
|
|
|
|
if (set->ops->map_queues && !is_kdump_kernel()) {
|
|
int i;
|
|
|
|
/*
|
|
* transport .map_queues is usually done in the following
|
|
* way:
|
|
*
|
|
* for (queue = 0; queue < set->nr_hw_queues; queue++) {
|
|
* mask = get_cpu_mask(queue)
|
|
* for_each_cpu(cpu, mask)
|
|
* set->map[x].mq_map[cpu] = queue;
|
|
* }
|
|
*
|
|
* When we need to remap, the table has to be cleared for
|
|
* killing stale mapping since one CPU may not be mapped
|
|
* to any hw queue.
|
|
*/
|
|
for (i = 0; i < set->nr_maps; i++)
|
|
blk_mq_clear_mq_map(&set->map[i]);
|
|
|
|
return set->ops->map_queues(set);
|
|
} else {
|
|
BUG_ON(set->nr_maps > 1);
|
|
return blk_mq_map_queues(&set->map[HCTX_TYPE_DEFAULT]);
|
|
}
|
|
}
|
|
|
|
static int blk_mq_realloc_tag_set_tags(struct blk_mq_tag_set *set,
|
|
int cur_nr_hw_queues, int new_nr_hw_queues)
|
|
{
|
|
struct blk_mq_tags **new_tags;
|
|
|
|
if (cur_nr_hw_queues >= new_nr_hw_queues)
|
|
return 0;
|
|
|
|
new_tags = kcalloc_node(new_nr_hw_queues, sizeof(struct blk_mq_tags *),
|
|
GFP_KERNEL, set->numa_node);
|
|
if (!new_tags)
|
|
return -ENOMEM;
|
|
|
|
if (set->tags)
|
|
memcpy(new_tags, set->tags, cur_nr_hw_queues *
|
|
sizeof(*set->tags));
|
|
kfree(set->tags);
|
|
set->tags = new_tags;
|
|
set->nr_hw_queues = new_nr_hw_queues;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Alloc a tag set to be associated with one or more request queues.
|
|
* May fail with EINVAL for various error conditions. May adjust the
|
|
* requested depth down, if it's too large. In that case, the set
|
|
* value will be stored in set->queue_depth.
|
|
*/
|
|
int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
|
|
{
|
|
int i, ret;
|
|
|
|
BUILD_BUG_ON(BLK_MQ_MAX_DEPTH > 1 << BLK_MQ_UNIQUE_TAG_BITS);
|
|
|
|
if (!set->nr_hw_queues)
|
|
return -EINVAL;
|
|
if (!set->queue_depth)
|
|
return -EINVAL;
|
|
if (set->queue_depth < set->reserved_tags + BLK_MQ_TAG_MIN)
|
|
return -EINVAL;
|
|
|
|
if (!set->ops->queue_rq)
|
|
return -EINVAL;
|
|
|
|
if (!set->ops->get_budget ^ !set->ops->put_budget)
|
|
return -EINVAL;
|
|
|
|
if (set->queue_depth > BLK_MQ_MAX_DEPTH) {
|
|
pr_info("blk-mq: reduced tag depth to %u\n",
|
|
BLK_MQ_MAX_DEPTH);
|
|
set->queue_depth = BLK_MQ_MAX_DEPTH;
|
|
}
|
|
|
|
if (!set->nr_maps)
|
|
set->nr_maps = 1;
|
|
else if (set->nr_maps > HCTX_MAX_TYPES)
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* If a crashdump is active, then we are potentially in a very
|
|
* memory constrained environment. Limit us to 1 queue and
|
|
* 64 tags to prevent using too much memory.
|
|
*/
|
|
if (is_kdump_kernel()) {
|
|
set->nr_hw_queues = 1;
|
|
set->nr_maps = 1;
|
|
set->queue_depth = min(64U, set->queue_depth);
|
|
}
|
|
/*
|
|
* There is no use for more h/w queues than cpus if we just have
|
|
* a single map
|
|
*/
|
|
if (set->nr_maps == 1 && set->nr_hw_queues > nr_cpu_ids)
|
|
set->nr_hw_queues = nr_cpu_ids;
|
|
|
|
if (blk_mq_realloc_tag_set_tags(set, 0, set->nr_hw_queues) < 0)
|
|
return -ENOMEM;
|
|
|
|
ret = -ENOMEM;
|
|
for (i = 0; i < set->nr_maps; i++) {
|
|
set->map[i].mq_map = kcalloc_node(nr_cpu_ids,
|
|
sizeof(set->map[i].mq_map[0]),
|
|
GFP_KERNEL, set->numa_node);
|
|
if (!set->map[i].mq_map)
|
|
goto out_free_mq_map;
|
|
set->map[i].nr_queues = is_kdump_kernel() ? 1 : set->nr_hw_queues;
|
|
}
|
|
|
|
ret = blk_mq_update_queue_map(set);
|
|
if (ret)
|
|
goto out_free_mq_map;
|
|
|
|
ret = blk_mq_alloc_map_and_requests(set);
|
|
if (ret)
|
|
goto out_free_mq_map;
|
|
|
|
if (blk_mq_is_sbitmap_shared(set->flags)) {
|
|
atomic_set(&set->active_queues_shared_sbitmap, 0);
|
|
|
|
if (blk_mq_init_shared_sbitmap(set, set->flags)) {
|
|
ret = -ENOMEM;
|
|
goto out_free_mq_rq_maps;
|
|
}
|
|
}
|
|
|
|
mutex_init(&set->tag_list_lock);
|
|
INIT_LIST_HEAD(&set->tag_list);
|
|
|
|
return 0;
|
|
|
|
out_free_mq_rq_maps:
|
|
for (i = 0; i < set->nr_hw_queues; i++)
|
|
blk_mq_free_map_and_requests(set, i);
|
|
out_free_mq_map:
|
|
for (i = 0; i < set->nr_maps; i++) {
|
|
kfree(set->map[i].mq_map);
|
|
set->map[i].mq_map = NULL;
|
|
}
|
|
kfree(set->tags);
|
|
set->tags = NULL;
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_alloc_tag_set);
|
|
|
|
void blk_mq_free_tag_set(struct blk_mq_tag_set *set)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < set->nr_hw_queues; i++)
|
|
blk_mq_free_map_and_requests(set, i);
|
|
|
|
if (blk_mq_is_sbitmap_shared(set->flags))
|
|
blk_mq_exit_shared_sbitmap(set);
|
|
|
|
for (j = 0; j < set->nr_maps; j++) {
|
|
kfree(set->map[j].mq_map);
|
|
set->map[j].mq_map = NULL;
|
|
}
|
|
|
|
kfree(set->tags);
|
|
set->tags = NULL;
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_free_tag_set);
|
|
|
|
int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr)
|
|
{
|
|
struct blk_mq_tag_set *set = q->tag_set;
|
|
struct blk_mq_hw_ctx *hctx;
|
|
int i, ret;
|
|
|
|
if (!set)
|
|
return -EINVAL;
|
|
|
|
if (q->nr_requests == nr)
|
|
return 0;
|
|
|
|
blk_mq_freeze_queue(q);
|
|
blk_mq_quiesce_queue(q);
|
|
|
|
ret = 0;
|
|
queue_for_each_hw_ctx(q, hctx, i) {
|
|
if (!hctx->tags)
|
|
continue;
|
|
/*
|
|
* If we're using an MQ scheduler, just update the scheduler
|
|
* queue depth. This is similar to what the old code would do.
|
|
*/
|
|
if (!hctx->sched_tags) {
|
|
ret = blk_mq_tag_update_depth(hctx, &hctx->tags, nr,
|
|
false);
|
|
if (!ret && blk_mq_is_sbitmap_shared(set->flags))
|
|
blk_mq_tag_resize_shared_sbitmap(set, nr);
|
|
} else {
|
|
ret = blk_mq_tag_update_depth(hctx, &hctx->sched_tags,
|
|
nr, true);
|
|
}
|
|
if (ret)
|
|
break;
|
|
if (q->elevator && q->elevator->type->ops.depth_updated)
|
|
q->elevator->type->ops.depth_updated(hctx);
|
|
}
|
|
|
|
if (!ret)
|
|
q->nr_requests = nr;
|
|
|
|
blk_mq_unquiesce_queue(q);
|
|
blk_mq_unfreeze_queue(q);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* request_queue and elevator_type pair.
|
|
* It is just used by __blk_mq_update_nr_hw_queues to cache
|
|
* the elevator_type associated with a request_queue.
|
|
*/
|
|
struct blk_mq_qe_pair {
|
|
struct list_head node;
|
|
struct request_queue *q;
|
|
struct elevator_type *type;
|
|
};
|
|
|
|
/*
|
|
* Cache the elevator_type in qe pair list and switch the
|
|
* io scheduler to 'none'
|
|
*/
|
|
static bool blk_mq_elv_switch_none(struct list_head *head,
|
|
struct request_queue *q)
|
|
{
|
|
struct blk_mq_qe_pair *qe;
|
|
|
|
if (!q->elevator)
|
|
return true;
|
|
|
|
qe = kmalloc(sizeof(*qe), GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY);
|
|
if (!qe)
|
|
return false;
|
|
|
|
INIT_LIST_HEAD(&qe->node);
|
|
qe->q = q;
|
|
qe->type = q->elevator->type;
|
|
list_add(&qe->node, head);
|
|
|
|
mutex_lock(&q->sysfs_lock);
|
|
/*
|
|
* After elevator_switch_mq, the previous elevator_queue will be
|
|
* released by elevator_release. The reference of the io scheduler
|
|
* module get by elevator_get will also be put. So we need to get
|
|
* a reference of the io scheduler module here to prevent it to be
|
|
* removed.
|
|
*/
|
|
__module_get(qe->type->elevator_owner);
|
|
elevator_switch_mq(q, NULL);
|
|
mutex_unlock(&q->sysfs_lock);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void blk_mq_elv_switch_back(struct list_head *head,
|
|
struct request_queue *q)
|
|
{
|
|
struct blk_mq_qe_pair *qe;
|
|
struct elevator_type *t = NULL;
|
|
|
|
list_for_each_entry(qe, head, node)
|
|
if (qe->q == q) {
|
|
t = qe->type;
|
|
break;
|
|
}
|
|
|
|
if (!t)
|
|
return;
|
|
|
|
list_del(&qe->node);
|
|
kfree(qe);
|
|
|
|
mutex_lock(&q->sysfs_lock);
|
|
elevator_switch_mq(q, t);
|
|
mutex_unlock(&q->sysfs_lock);
|
|
}
|
|
|
|
static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
|
|
int nr_hw_queues)
|
|
{
|
|
struct request_queue *q;
|
|
LIST_HEAD(head);
|
|
int prev_nr_hw_queues;
|
|
|
|
lockdep_assert_held(&set->tag_list_lock);
|
|
|
|
if (set->nr_maps == 1 && nr_hw_queues > nr_cpu_ids)
|
|
nr_hw_queues = nr_cpu_ids;
|
|
if (nr_hw_queues < 1)
|
|
return;
|
|
if (set->nr_maps == 1 && nr_hw_queues == set->nr_hw_queues)
|
|
return;
|
|
|
|
list_for_each_entry(q, &set->tag_list, tag_set_list)
|
|
blk_mq_freeze_queue(q);
|
|
/*
|
|
* Switch IO scheduler to 'none', cleaning up the data associated
|
|
* with the previous scheduler. We will switch back once we are done
|
|
* updating the new sw to hw queue mappings.
|
|
*/
|
|
list_for_each_entry(q, &set->tag_list, tag_set_list)
|
|
if (!blk_mq_elv_switch_none(&head, q))
|
|
goto switch_back;
|
|
|
|
list_for_each_entry(q, &set->tag_list, tag_set_list) {
|
|
blk_mq_debugfs_unregister_hctxs(q);
|
|
blk_mq_sysfs_unregister(q);
|
|
}
|
|
|
|
prev_nr_hw_queues = set->nr_hw_queues;
|
|
if (blk_mq_realloc_tag_set_tags(set, set->nr_hw_queues, nr_hw_queues) <
|
|
0)
|
|
goto reregister;
|
|
|
|
set->nr_hw_queues = nr_hw_queues;
|
|
fallback:
|
|
blk_mq_update_queue_map(set);
|
|
list_for_each_entry(q, &set->tag_list, tag_set_list) {
|
|
blk_mq_realloc_hw_ctxs(set, q);
|
|
if (q->nr_hw_queues != set->nr_hw_queues) {
|
|
pr_warn("Increasing nr_hw_queues to %d fails, fallback to %d\n",
|
|
nr_hw_queues, prev_nr_hw_queues);
|
|
set->nr_hw_queues = prev_nr_hw_queues;
|
|
blk_mq_map_queues(&set->map[HCTX_TYPE_DEFAULT]);
|
|
goto fallback;
|
|
}
|
|
blk_mq_map_swqueue(q);
|
|
}
|
|
|
|
reregister:
|
|
list_for_each_entry(q, &set->tag_list, tag_set_list) {
|
|
blk_mq_sysfs_register(q);
|
|
blk_mq_debugfs_register_hctxs(q);
|
|
}
|
|
|
|
switch_back:
|
|
list_for_each_entry(q, &set->tag_list, tag_set_list)
|
|
blk_mq_elv_switch_back(&head, q);
|
|
|
|
list_for_each_entry(q, &set->tag_list, tag_set_list)
|
|
blk_mq_unfreeze_queue(q);
|
|
}
|
|
|
|
void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues)
|
|
{
|
|
mutex_lock(&set->tag_list_lock);
|
|
__blk_mq_update_nr_hw_queues(set, nr_hw_queues);
|
|
mutex_unlock(&set->tag_list_lock);
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_mq_update_nr_hw_queues);
|
|
|
|
/* Enable polling stats and return whether they were already enabled. */
|
|
static bool blk_poll_stats_enable(struct request_queue *q)
|
|
{
|
|
if (test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags) ||
|
|
blk_queue_flag_test_and_set(QUEUE_FLAG_POLL_STATS, q))
|
|
return true;
|
|
blk_stat_add_callback(q, q->poll_cb);
|
|
return false;
|
|
}
|
|
|
|
static void blk_mq_poll_stats_start(struct request_queue *q)
|
|
{
|
|
/*
|
|
* We don't arm the callback if polling stats are not enabled or the
|
|
* callback is already active.
|
|
*/
|
|
if (!test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags) ||
|
|
blk_stat_is_active(q->poll_cb))
|
|
return;
|
|
|
|
blk_stat_activate_msecs(q->poll_cb, 100);
|
|
}
|
|
|
|
static void blk_mq_poll_stats_fn(struct blk_stat_callback *cb)
|
|
{
|
|
struct request_queue *q = cb->data;
|
|
int bucket;
|
|
|
|
for (bucket = 0; bucket < BLK_MQ_POLL_STATS_BKTS; bucket++) {
|
|
if (cb->stat[bucket].nr_samples)
|
|
q->poll_stat[bucket] = cb->stat[bucket];
|
|
}
|
|
}
|
|
|
|
static unsigned long blk_mq_poll_nsecs(struct request_queue *q,
|
|
struct request *rq)
|
|
{
|
|
unsigned long ret = 0;
|
|
int bucket;
|
|
|
|
/*
|
|
* If stats collection isn't on, don't sleep but turn it on for
|
|
* future users
|
|
*/
|
|
if (!blk_poll_stats_enable(q))
|
|
return 0;
|
|
|
|
/*
|
|
* As an optimistic guess, use half of the mean service time
|
|
* for this type of request. We can (and should) make this smarter.
|
|
* For instance, if the completion latencies are tight, we can
|
|
* get closer than just half the mean. This is especially
|
|
* important on devices where the completion latencies are longer
|
|
* than ~10 usec. We do use the stats for the relevant IO size
|
|
* if available which does lead to better estimates.
|
|
*/
|
|
bucket = blk_mq_poll_stats_bkt(rq);
|
|
if (bucket < 0)
|
|
return ret;
|
|
|
|
if (q->poll_stat[bucket].nr_samples)
|
|
ret = (q->poll_stat[bucket].mean + 1) / 2;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bool blk_mq_poll_hybrid_sleep(struct request_queue *q,
|
|
struct request *rq)
|
|
{
|
|
struct hrtimer_sleeper hs;
|
|
enum hrtimer_mode mode;
|
|
unsigned int nsecs;
|
|
ktime_t kt;
|
|
|
|
if (rq->rq_flags & RQF_MQ_POLL_SLEPT)
|
|
return false;
|
|
|
|
/*
|
|
* If we get here, hybrid polling is enabled. Hence poll_nsec can be:
|
|
*
|
|
* 0: use half of prev avg
|
|
* >0: use this specific value
|
|
*/
|
|
if (q->poll_nsec > 0)
|
|
nsecs = q->poll_nsec;
|
|
else
|
|
nsecs = blk_mq_poll_nsecs(q, rq);
|
|
|
|
if (!nsecs)
|
|
return false;
|
|
|
|
rq->rq_flags |= RQF_MQ_POLL_SLEPT;
|
|
|
|
/*
|
|
* This will be replaced with the stats tracking code, using
|
|
* 'avg_completion_time / 2' as the pre-sleep target.
|
|
*/
|
|
kt = nsecs;
|
|
|
|
mode = HRTIMER_MODE_REL;
|
|
hrtimer_init_sleeper_on_stack(&hs, CLOCK_MONOTONIC, mode);
|
|
hrtimer_set_expires(&hs.timer, kt);
|
|
|
|
do {
|
|
if (blk_mq_rq_state(rq) == MQ_RQ_COMPLETE)
|
|
break;
|
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
hrtimer_sleeper_start_expires(&hs, mode);
|
|
if (hs.task)
|
|
io_schedule();
|
|
hrtimer_cancel(&hs.timer);
|
|
mode = HRTIMER_MODE_ABS;
|
|
} while (hs.task && !signal_pending(current));
|
|
|
|
__set_current_state(TASK_RUNNING);
|
|
destroy_hrtimer_on_stack(&hs.timer);
|
|
return true;
|
|
}
|
|
|
|
static bool blk_mq_poll_hybrid(struct request_queue *q,
|
|
struct blk_mq_hw_ctx *hctx, blk_qc_t cookie)
|
|
{
|
|
struct request *rq;
|
|
|
|
if (q->poll_nsec == BLK_MQ_POLL_CLASSIC)
|
|
return false;
|
|
|
|
if (!blk_qc_t_is_internal(cookie))
|
|
rq = blk_mq_tag_to_rq(hctx->tags, blk_qc_t_to_tag(cookie));
|
|
else {
|
|
rq = blk_mq_tag_to_rq(hctx->sched_tags, blk_qc_t_to_tag(cookie));
|
|
/*
|
|
* With scheduling, if the request has completed, we'll
|
|
* get a NULL return here, as we clear the sched tag when
|
|
* that happens. The request still remains valid, like always,
|
|
* so we should be safe with just the NULL check.
|
|
*/
|
|
if (!rq)
|
|
return false;
|
|
}
|
|
|
|
return blk_mq_poll_hybrid_sleep(q, rq);
|
|
}
|
|
|
|
/**
|
|
* blk_poll - poll for IO completions
|
|
* @q: the queue
|
|
* @cookie: cookie passed back at IO submission time
|
|
* @spin: whether to spin for completions
|
|
*
|
|
* Description:
|
|
* Poll for completions on the passed in queue. Returns number of
|
|
* completed entries found. If @spin is true, then blk_poll will continue
|
|
* looping until at least one completion is found, unless the task is
|
|
* otherwise marked running (or we need to reschedule).
|
|
*/
|
|
int blk_poll(struct request_queue *q, blk_qc_t cookie, bool spin)
|
|
{
|
|
struct blk_mq_hw_ctx *hctx;
|
|
long state;
|
|
|
|
if (!blk_qc_t_valid(cookie) ||
|
|
!test_bit(QUEUE_FLAG_POLL, &q->queue_flags))
|
|
return 0;
|
|
|
|
if (current->plug)
|
|
blk_flush_plug_list(current->plug, false);
|
|
|
|
hctx = q->queue_hw_ctx[blk_qc_t_to_queue_num(cookie)];
|
|
|
|
/*
|
|
* If we sleep, have the caller restart the poll loop to reset
|
|
* the state. Like for the other success return cases, the
|
|
* caller is responsible for checking if the IO completed. If
|
|
* the IO isn't complete, we'll get called again and will go
|
|
* straight to the busy poll loop.
|
|
*/
|
|
if (blk_mq_poll_hybrid(q, hctx, cookie))
|
|
return 1;
|
|
|
|
hctx->poll_considered++;
|
|
|
|
state = current->state;
|
|
do {
|
|
int ret;
|
|
|
|
hctx->poll_invoked++;
|
|
|
|
ret = q->mq_ops->poll(hctx);
|
|
if (ret > 0) {
|
|
hctx->poll_success++;
|
|
__set_current_state(TASK_RUNNING);
|
|
return ret;
|
|
}
|
|
|
|
if (signal_pending_state(state, current))
|
|
__set_current_state(TASK_RUNNING);
|
|
|
|
if (current->state == TASK_RUNNING)
|
|
return 1;
|
|
if (ret < 0 || !spin)
|
|
break;
|
|
cpu_relax();
|
|
} while (!need_resched());
|
|
|
|
__set_current_state(TASK_RUNNING);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(blk_poll);
|
|
|
|
unsigned int blk_mq_rq_cpu(struct request *rq)
|
|
{
|
|
return rq->mq_ctx->cpu;
|
|
}
|
|
EXPORT_SYMBOL(blk_mq_rq_cpu);
|
|
|
|
static int __init blk_mq_init(void)
|
|
{
|
|
int i;
|
|
|
|
for_each_possible_cpu(i)
|
|
INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
|
|
open_softirq(BLOCK_SOFTIRQ, blk_done_softirq);
|
|
|
|
cpuhp_setup_state_nocalls(CPUHP_BLOCK_SOFTIRQ_DEAD,
|
|
"block/softirq:dead", NULL,
|
|
blk_softirq_cpu_dead);
|
|
cpuhp_setup_state_multi(CPUHP_BLK_MQ_DEAD, "block/mq:dead", NULL,
|
|
blk_mq_hctx_notify_dead);
|
|
cpuhp_setup_state_multi(CPUHP_AP_BLK_MQ_ONLINE, "block/mq:online",
|
|
blk_mq_hctx_notify_online,
|
|
blk_mq_hctx_notify_offline);
|
|
return 0;
|
|
}
|
|
subsys_initcall(blk_mq_init);
|