Files
kernel_arpi/fs/splice.c
Greg Kroah-Hartman 335a32d033 Merge 5.15.75 into android14-5.15
Changes in 5.15.75
	Revert "fs: check FMODE_LSEEK to control internal pipe splicing"
	ALSA: oss: Fix potential deadlock at unregistration
	ALSA: rawmidi: Drop register_mutex in snd_rawmidi_free()
	ALSA: usb-audio: Fix potential memory leaks
	ALSA: usb-audio: Fix NULL dererence at error path
	ALSA: hda/realtek: remove ALC289_FIXUP_DUAL_SPK for Dell 5530
	ALSA: hda/realtek: Correct pin configs for ASUS G533Z
	ALSA: hda/realtek: Add quirk for ASUS GV601R laptop
	ALSA: hda/realtek: Add Intel Reference SSID to support headset keys
	mtd: rawnand: atmel: Unmap streaming DMA mappings
	io_uring/net: don't update msg_name if not provided
	hv_netvsc: Fix race between VF offering and VF association message from host
	cifs: destage dirty pages before re-reading them for cache=none
	cifs: Fix the error length of VALIDATE_NEGOTIATE_INFO message
	iio: dac: ad5593r: Fix i2c read protocol requirements
	iio: ltc2497: Fix reading conversion results
	iio: adc: ad7923: fix channel readings for some variants
	iio: pressure: dps310: Refactor startup procedure
	iio: pressure: dps310: Reset chip after timeout
	xhci: dbc: Fix memory leak in xhci_alloc_dbc()
	usb: add quirks for Lenovo OneLink+ Dock
	can: kvaser_usb: Fix use of uninitialized completion
	can: kvaser_usb_leaf: Fix overread with an invalid command
	can: kvaser_usb_leaf: Fix TX queue out of sync after restart
	can: kvaser_usb_leaf: Fix CAN state after restart
	mmc: sdhci-sprd: Fix minimum clock limit
	i2c: designware: Fix handling of real but unexpected device interrupts
	fs: dlm: fix race between test_bit() and queue_work()
	fs: dlm: handle -EBUSY first in lock arg validation
	HID: multitouch: Add memory barriers
	quota: Check next/prev free block number after reading from quota file
	platform/chrome: cros_ec_proto: Update version on GET_NEXT_EVENT failure
	ASoC: wcd9335: fix order of Slimbus unprepare/disable
	ASoC: wcd934x: fix order of Slimbus unprepare/disable
	hwmon: (gsc-hwmon) Call of_node_get() before of_find_xxx API
	net: thunderbolt: Enable DMA paths only after rings are enabled
	regulator: qcom_rpm: Fix circular deferral regression
	arm64: topology: move store_cpu_topology() to shared code
	riscv: topology: fix default topology reporting
	RISC-V: Make port I/O string accessors actually work
	parisc: fbdev/stifb: Align graphics memory size to 4MB
	riscv: Allow PROT_WRITE-only mmap()
	riscv: Make VM_WRITE imply VM_READ
	riscv: always honor the CONFIG_CMDLINE_FORCE when parsing dtb
	riscv: Pass -mno-relax only on lld < 15.0.0
	UM: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK
	nvmem: core: Fix memleak in nvmem_register()
	nvme-multipath: fix possible hang in live ns resize with ANA access
	nvme-pci: set min_align_mask before calculating max_hw_sectors
	Revert "drm/amdgpu: use dirty framebuffer helper"
	dmaengine: mxs: use platform_driver_register
	drm/virtio: Check whether transferred 2D BO is shmem
	drm/virtio: Unlock reservations on virtio_gpu_object_shmem_init() error
	drm/virtio: Use appropriate atomic state in virtio_gpu_plane_cleanup_fb()
	drm/udl: Restore display mode on resume
	arm64: errata: Add Cortex-A55 to the repeat tlbi list
	mm/damon: validate if the pmd entry is present before accessing
	mm/mmap: undo ->mmap() when arch_validate_flags() fails
	xen/gntdev: Prevent leaking grants
	xen/gntdev: Accommodate VMA splitting
	PCI: Sanitise firmware BAR assignments behind a PCI-PCI bridge
	serial: 8250: Let drivers request full 16550A feature probing
	serial: 8250: Request full 16550A feature probing for OxSemi PCIe devices
	NFSD: Protect against send buffer overflow in NFSv3 READDIR
	NFSD: Protect against send buffer overflow in NFSv2 READ
	NFSD: Protect against send buffer overflow in NFSv3 READ
	powercap: intel_rapl: Use standard Energy Unit for SPR Dram RAPL domain
	powerpc/boot: Explicitly disable usage of SPE instructions
	slimbus: qcom-ngd: use correct error in message of pdr_add_lookup() failure
	slimbus: qcom-ngd: cleanup in probe error path
	scsi: qedf: Populate sysfs attributes for vport
	gpio: rockchip: request GPIO mux to pinctrl when setting direction
	pinctrl: rockchip: add pinmux_ops.gpio_set_direction callback
	fbdev: smscufx: Fix use-after-free in ufx_ops_open()
	ksmbd: fix endless loop when encryption for response fails
	ksmbd: Fix wrong return value and message length check in smb2_ioctl()
	ksmbd: Fix user namespace mapping
	fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE
	btrfs: fix race between quota enable and quota rescan ioctl
	btrfs: set generation before calling btrfs_clean_tree_block in btrfs_init_new_buffer
	f2fs: complete checkpoints during remount
	f2fs: flush pending checkpoints when freezing super
	f2fs: increase the limit for reserve_root
	f2fs: fix to do sanity check on destination blkaddr during recovery
	f2fs: fix to do sanity check on summary info
	hardening: Avoid harmless Clang option under CONFIG_INIT_STACK_ALL_ZERO
	hardening: Remove Clang's enable flag for -ftrivial-auto-var-init=zero
	jbd2: wake up journal waiters in FIFO order, not LIFO
	jbd2: fix potential buffer head reference count leak
	jbd2: fix potential use-after-free in jbd2_fc_wait_bufs
	jbd2: add miss release buffer head in fc_do_one_pass()
	ext4: avoid crash when inline data creation follows DIO write
	ext4: fix null-ptr-deref in ext4_write_info
	ext4: make ext4_lazyinit_thread freezable
	ext4: fix check for block being out of directory size
	ext4: don't increase iversion counter for ea_inodes
	ext4: ext4_read_bh_lock() should submit IO if the buffer isn't uptodate
	ext4: place buffer head allocation before handle start
	ext4: fix dir corruption when ext4_dx_add_entry() fails
	ext4: fix miss release buffer head in ext4_fc_write_inode
	ext4: fix potential memory leak in ext4_fc_record_modified_inode()
	ext4: fix potential memory leak in ext4_fc_record_regions()
	ext4: update 'state->fc_regions_size' after successful memory allocation
	livepatch: fix race between fork and KLP transition
	ftrace: Properly unset FTRACE_HASH_FL_MOD
	ring-buffer: Allow splice to read previous partially read pages
	ring-buffer: Have the shortest_full queue be the shortest not longest
	ring-buffer: Check pending waiters when doing wake ups as well
	ring-buffer: Add ring_buffer_wake_waiters()
	ring-buffer: Fix race between reset page and reading page
	tracing: Disable interrupt or preemption before acquiring arch_spinlock_t
	tracing: Wake up ring buffer waiters on closing of the file
	tracing: Wake up waiters when tracing is disabled
	tracing: Add ioctl() to force ring buffer waiters to wake up
	tracing: Move duplicate code of trace_kprobe/eprobe.c into header
	tracing: Add "(fault)" name injection to kernel probes
	tracing: Fix reading strings from synthetic events
	thunderbolt: Explicitly enable lane adapter hotplug events at startup
	efi: libstub: drop pointless get_memory_map() call
	media: cedrus: Set the platform driver data earlier
	media: cedrus: Fix endless loop in cedrus_h265_skip_bits()
	blk-wbt: call rq_qos_add() after wb_normal is initialized
	KVM: x86/emulator: Fix handing of POP SS to correctly set interruptibility
	KVM: nVMX: Unconditionally purge queued/injected events on nested "exit"
	KVM: nVMX: Don't propagate vmcs12's PERF_GLOBAL_CTRL settings to vmcs02
	KVM: VMX: Drop bits 31:16 when shoving exception error code into VMCS
	staging: greybus: audio_helper: remove unused and wrong debugfs usage
	drm/nouveau/kms/nv140-: Disable interlacing
	drm/nouveau: fix a use-after-free in nouveau_gem_prime_import_sg_table()
	drm/i915: Fix watermark calculations for gen12+ RC CCS modifier
	drm/i915: Fix watermark calculations for gen12+ MC CCS modifier
	drm/i915: Fix watermark calculations for gen12+ CCS+CC modifier
	drm/amd/display: Fix vblank refcount in vrr transition
	smb3: must initialize two ACL struct fields to zero
	selinux: use "grep -E" instead of "egrep"
	ima: fix blocking of security.ima xattrs of unsupported algorithms
	userfaultfd: open userfaultfds with O_RDONLY
	ntfs3: rework xattr handlers and switch to POSIX ACL VFS helpers
	thermal: cpufreq_cooling: Check the policy first in cpufreq_cooling_register()
	sh: machvec: Use char[] for section boundaries
	MIPS: SGI-IP27: Free some unused memory
	MIPS: SGI-IP27: Fix platform-device leak in bridge_platform_create()
	ARM: 9244/1: dump: Fix wrong pg_level in walk_pmd()
	ARM: 9247/1: mm: set readonly for MT_MEMORY_RO with ARM_LPAE
	objtool: Preserve special st_shndx indexes in elf_update_symbol
	nfsd: Fix a memory leak in an error handling path
	SUNRPC: Fix svcxdr_init_decode's end-of-buffer calculation
	SUNRPC: Fix svcxdr_init_encode's buflen calculation
	NFSD: Protect against send buffer overflow in NFSv2 READDIR
	NFSD: Fix handling of oversized NFSv4 COMPOUND requests
	wifi: rtlwifi: 8192de: correct checking of IQK reload
	wifi: ath10k: add peer map clean up for peer delete in ath10k_sta_state()
	leds: lm3601x: Don't use mutex after it was destroyed
	bpf: Fix reference state management for synchronous callbacks
	wifi: mac80211: allow bw change during channel switch in mesh
	bpftool: Fix a wrong type cast in btf_dumper_int
	spi: mt7621: Fix an error message in mt7621_spi_probe()
	x86/resctrl: Fix to restore to original value when re-enabling hardware prefetch register
	xsk: Fix backpressure mechanism on Tx
	bpf: Disable preemption when increasing per-cpu map_locked
	bpf: Propagate error from htab_lock_bucket() to userspace
	bpf: Use this_cpu_{inc|dec|inc_return} for bpf_task_storage_busy
	Bluetooth: btusb: mediatek: fix WMT failure during runtime suspend
	wifi: rtl8xxxu: tighten bounds checking in rtl8xxxu_read_efuse()
	wifi: rtw88: add missing destroy_workqueue() on error path in rtw_core_init()
	selftests/xsk: Avoid use-after-free on ctx
	spi: qup: add missing clk_disable_unprepare on error in spi_qup_resume()
	spi: qup: add missing clk_disable_unprepare on error in spi_qup_pm_resume_runtime()
	wifi: rtl8xxxu: Fix skb misuse in TX queue selection
	spi: meson-spicc: do not rely on busy flag in pow2 clk ops
	bpf: btf: fix truncated last_member_type_id in btf_struct_resolve
	wifi: rtl8xxxu: gen2: Fix mistake in path B IQ calibration
	wifi: rtl8xxxu: Remove copy-paste leftover in gen2_update_rate_mask
	wifi: mt76: sdio: fix transmitting packet hangs
	wifi: mt76: mt7615: add mt7615_mutex_acquire/release in mt7615_sta_set_decap_offload
	wifi: mt76: mt7915: do not check state before configuring implicit beamform
	Bluetooth: RFCOMM: Fix possible deadlock on socket shutdown/release
	net: fs_enet: Fix wrong check in do_pd_setup
	bpf: Ensure correct locking around vulnerable function find_vpid()
	Bluetooth: hci_{ldisc,serdev}: check percpu_init_rwsem() failure
	netfilter: conntrack: fix the gc rescheduling delay
	netfilter: conntrack: revisit the gc initial rescheduling bias
	wifi: ath11k: fix number of VHT beamformee spatial streams
	x86/microcode/AMD: Track patch allocation size explicitly
	x86/cpu: Include the header of init_ia32_feat_ctl()'s prototype
	spi: dw: Fix PM disable depth imbalance in dw_spi_bt1_probe
	spi/omap100k:Fix PM disable depth imbalance in omap1_spi100k_probe
	skmsg: Schedule psock work if the cached skb exists on the psock
	i2c: mlxbf: support lock mechanism
	Bluetooth: hci_core: Fix not handling link timeouts propertly
	xfrm: Reinject transport-mode packets through workqueue
	netfilter: nft_fib: Fix for rpath check with VRF devices
	spi: s3c64xx: Fix large transfers with DMA
	wifi: rtl8xxxu: Fix AIFS written to REG_EDCA_*_PARAM
	vhost/vsock: Use kvmalloc/kvfree for larger packets.
	eth: alx: take rtnl_lock on resume
	mISDN: fix use-after-free bugs in l1oip timer handlers
	sctp: handle the error returned from sctp_auth_asoc_init_active_key
	tcp: fix tcp_cwnd_validate() to not forget is_cwnd_limited
	spi: Ensure that sg_table won't be used after being freed
	hwmon: (pmbus/mp2888) Fix sensors readouts for MPS Multi-phase mp2888 controller
	net: rds: don't hold sock lock when cancelling work from rds_tcp_reset_callbacks()
	bnx2x: fix potential memory leak in bnx2x_tpa_stop()
	net: wwan: iosm: Call mutex_init before locking it
	net/ieee802154: reject zero-sized raw_sendmsg()
	once: add DO_ONCE_SLOW() for sleepable contexts
	net: mvpp2: fix mvpp2 debugfs leak
	drm: bridge: adv7511: fix CEC power down control register offset
	drm: bridge: adv7511: unregister cec i2c device after cec adapter
	drm/bridge: Avoid uninitialized variable warning
	drm/mipi-dsi: Detach devices when removing the host
	drm/virtio: Correct drm_gem_shmem_get_sg_table() error handling
	drm/bridge: parade-ps8640: Fix regulator supply order
	drm/dp_mst: fix drm_dp_dpcd_read return value checks
	drm:pl111: Add of_node_put() when breaking out of for_each_available_child_of_node()
	ASoC: mt6359: fix tests for platform_get_irq() failure
	platform/chrome: fix double-free in chromeos_laptop_prepare()
	platform/chrome: fix memory corruption in ioctl
	ASoC: tas2764: Allow mono streams
	ASoC: tas2764: Drop conflicting set_bias_level power setting
	ASoC: tas2764: Fix mute/unmute
	platform/x86: msi-laptop: Fix old-ec check for backlight registering
	platform/x86: msi-laptop: Fix resource cleanup
	platform/chrome: cros_ec_typec: Correct alt mode index
	drm/amdgpu: add missing pci_disable_device() in amdgpu_pmops_runtime_resume()
	drm/bridge: megachips: Fix a null pointer dereference bug
	ASoC: rsnd: Add check for rsnd_mod_power_on
	ALSA: hda: beep: Simplify keep-power-at-enable behavior
	drm/bochs: fix blanking
	drm/omap: dss: Fix refcount leak bugs
	drm/amdgpu: Fix memory leak in hpd_rx_irq_create_workqueue()
	mmc: au1xmmc: Fix an error handling path in au1xmmc_probe()
	ASoC: eureka-tlv320: Hold reference returned from of_find_xxx API
	drm/msm/dpu: index dpu_kms->hw_vbif using vbif_idx
	drm/msm/dp: correct 1.62G link rate at dp_catalog_ctrl_config_msa()
	drm/vmwgfx: Fix memory leak in vmw_mksstat_add_ioctl()
	ASoC: codecs: tx-macro: fix kcontrol put
	ASoC: da7219: Fix an error handling path in da7219_register_dai_clks()
	ALSA: dmaengine: increment buffer pointer atomically
	mmc: wmt-sdmmc: Fix an error handling path in wmt_mci_probe()
	ASoC: wm8997: Fix PM disable depth imbalance in wm8997_probe
	ASoC: wm5110: Fix PM disable depth imbalance in wm5110_probe
	ASoC: wm5102: Fix PM disable depth imbalance in wm5102_probe
	ASoC: mt6660: Fix PM disable depth imbalance in mt6660_i2c_probe
	ALSA: hda/hdmi: Don't skip notification handling during PM operation
	memory: pl353-smc: Fix refcount leak bug in pl353_smc_probe()
	memory: of: Fix refcount leak bug in of_get_ddr_timings()
	memory: of: Fix refcount leak bug in of_lpddr3_get_ddr_timings()
	locks: fix TOCTOU race when granting write lease
	soc: qcom: smsm: Fix refcount leak bugs in qcom_smsm_probe()
	soc: qcom: smem_state: Add refcounting for the 'state->of_node'
	ARM: dts: imx6qdl-kontron-samx6i: hook up DDC i2c bus
	ARM: dts: turris-omnia: Fix mpp26 pin name and comment
	ARM: dts: kirkwood: lsxl: fix serial line
	ARM: dts: kirkwood: lsxl: remove first ethernet port
	ia64: export memory_add_physaddr_to_nid to fix cxl build error
	soc/tegra: fuse: Drop Kconfig dependency on TEGRA20_APB_DMA
	arm64: dts: ti: k3-j7200: fix main pinmux range
	ARM: dts: exynos: correct s5k6a3 reset polarity on Midas family
	ARM: Drop CMDLINE_* dependency on ATAGS
	ext4: don't run ext4lazyinit for read-only filesystems
	arm64: ftrace: fix module PLTs with mcount
	ARM: dts: exynos: fix polarity of VBUS GPIO of Origen
	iio: adc: at91-sama5d2_adc: fix AT91_SAMA5D2_MR_TRACKTIM_MAX
	iio: adc: at91-sama5d2_adc: check return status for pressure and touch
	iio: adc: at91-sama5d2_adc: lock around oversampling and sample freq
	iio: adc: at91-sama5d2_adc: disable/prepare buffer on suspend/resume
	iio: inkern: only release the device node when done with it
	iio: inkern: fix return value in devm_of_iio_channel_get_by_name()
	iio: ABI: Fix wrong format of differential capacitance channel ABI.
	iio: magnetometer: yas530: Change data type of hard_offsets to signed
	RDMA/mlx5: Don't compare mkey tags in DEVX indirect mkey
	usb: common: debug: Check non-standard control requests
	clk: meson: Hold reference returned by of_get_parent()
	clk: oxnas: Hold reference returned by of_get_parent()
	clk: qoriq: Hold reference returned by of_get_parent()
	clk: berlin: Add of_node_put() for of_get_parent()
	clk: sprd: Hold reference returned by of_get_parent()
	clk: tegra: Fix refcount leak in tegra210_clock_init
	clk: tegra: Fix refcount leak in tegra114_clock_init
	clk: tegra20: Fix refcount leak in tegra20_clock_init
	HSI: omap_ssi: Fix refcount leak in ssi_probe
	HSI: omap_ssi_port: Fix dma_map_sg error check
	media: exynos4-is: fimc-is: Add of_node_put() when breaking out of loop
	tty: xilinx_uartps: Fix the ignore_status
	media: meson: vdec: add missing clk_disable_unprepare on error in vdec_hevc_start()
	media: uvcvideo: Fix memory leak in uvc_gpio_parse
	media: uvcvideo: Use entity get_cur in uvc_ctrl_set
	media: xilinx: vipp: Fix refcount leak in xvip_graph_dma_init
	RDMA/rxe: Fix "kernel NULL pointer dereference" error
	RDMA/rxe: Fix the error caused by qp->sk
	misc: ocxl: fix possible refcount leak in afu_ioctl()
	fpga: prevent integer overflow in dfl_feature_ioctl_set_irq()
	dmaengine: hisilicon: Disable channels when unregister hisi_dma
	dmaengine: hisilicon: Fix CQ head update
	dmaengine: hisilicon: Add multi-thread support for a DMA channel
	dyndbg: fix static_branch manipulation
	dyndbg: fix module.dyndbg handling
	dyndbg: let query-modname override actual module name
	dyndbg: drop EXPORTed dynamic_debug_exec_queries
	clk: qcom: sm6115: Select QCOM_GDSC
	mtd: devices: docg3: check the return value of devm_ioremap() in the probe
	phy: amlogic: phy-meson-axg-mipi-pcie-analog: Hold reference returned by of_get_parent()
	phy: phy-mtk-tphy: fix the phy type setting issue
	mtd: rawnand: intel: Read the chip-select line from the correct OF node
	mtd: rawnand: intel: Remove undocumented compatible string
	mtd: rawnand: fsl_elbc: Fix none ECC mode
	RDMA/irdma: Align AE id codes to correct flush code and event
	RDMA/srp: Fix srp_abort()
	RDMA/siw: Always consume all skbuf data in sk_data_ready() upcall.
	RDMA/siw: Fix QP destroy to wait for all references dropped.
	ata: fix ata_id_sense_reporting_enabled() and ata_id_has_sense_reporting()
	ata: fix ata_id_has_devslp()
	ata: fix ata_id_has_ncq_autosense()
	ata: fix ata_id_has_dipm()
	mtd: rawnand: meson: fix bit map use in meson_nfc_ecc_correct()
	md: Replace snprintf with scnprintf
	md/raid5: Ensure stripe_fill happens on non-read IO with journal
	md/raid5: Remove unnecessary bio_put() in raid5_read_one_chunk()
	RDMA/cm: Use SLID in the work completion as the DLID in responder side
	IB: Set IOVA/LENGTH on IB_MR in core/uverbs layers
	xhci: Don't show warning for reinit on known broken suspend
	usb: gadget: function: fix dangling pnp_string in f_printer.c
	drivers: serial: jsm: fix some leaks in probe
	serial: 8250: Toggle IER bits on only after irq has been set up
	tty: serial: fsl_lpuart: disable dma rx/tx use flags in lpuart_dma_shutdown
	phy: qualcomm: call clk_disable_unprepare in the error handling
	staging: vt6655: fix some erroneous memory clean-up loops
	slimbus: qcom-ngd-ctrl: allow compile testing without QCOM_RPROC_COMMON
	firmware: google: Test spinlock on panic path to avoid lockups
	serial: 8250: Fix restoring termios speed after suspend
	scsi: libsas: Fix use-after-free bug in smp_execute_task_sg()
	scsi: iscsi: Rename iscsi_conn_queue_work()
	scsi: iscsi: Add recv workqueue helpers
	scsi: iscsi: Run recv path from workqueue
	scsi: iscsi: iscsi_tcp: Fix null-ptr-deref while calling getpeername()
	clk: qcom: apss-ipq6018: mark apcs_alias0_core_clk as critical
	clk: qcom: gcc-sm6115: Override default Alpha PLL regs
	RDMA/rxe: Fix resize_finish() in rxe_queue.c
	fsi: core: Check error number after calling ida_simple_get
	mfd: intel_soc_pmic: Fix an error handling path in intel_soc_pmic_i2c_probe()
	mfd: fsl-imx25: Fix an error handling path in mx25_tsadc_setup_irq()
	mfd: lp8788: Fix an error handling path in lp8788_probe()
	mfd: lp8788: Fix an error handling path in lp8788_irq_init() and lp8788_irq_init()
	mfd: fsl-imx25: Fix check for platform_get_irq() errors
	mfd: sm501: Add check for platform_driver_register()
	clk: mediatek: mt8183: mfgcfg: Propagate rate changes to parent
	dmaengine: ioat: stop mod_timer from resurrecting deleted timer in __cleanup()
	usb: mtu3: fix failed runtime suspend in host only mode
	spmi: pmic-arb: correct duplicate APID to PPID mapping logic
	clk: vc5: Fix 5P49V6901 outputs disabling when enabling FOD
	clk: baikal-t1: Fix invalid xGMAC PTP clock divider
	clk: baikal-t1: Add shared xGMAC ref/ptp clocks internal parent
	clk: baikal-t1: Add SATA internal ref clock buffer
	clk: bcm2835: fix bcm2835_clock_rate_from_divisor declaration
	clk: imx: scu: fix memleak on platform_device_add() fails
	clk: ti: dra7-atl: Fix reference leak in of_dra7_atl_clk_probe
	clk: ast2600: BCLK comes from EPLL
	mailbox: mpfs: fix handling of the reg property
	mailbox: mpfs: account for mbox offsets while sending
	mailbox: bcm-ferxrm-mailbox: Fix error check for dma_map_sg
	powerpc/configs: Properly enable PAPR_SCM in pseries_defconfig
	powerpc/math_emu/efp: Include module.h
	powerpc/sysdev/fsl_msi: Add missing of_node_put()
	powerpc/pci_dn: Add missing of_node_put()
	powerpc/powernv: add missing of_node_put() in opal_export_attrs()
	powerpc: Fix fallocate and fadvise64_64 compat parameter combination
	x86/hyperv: Fix 'struct hv_enlightened_vmcs' definition
	powerpc/64s: Fix GENERIC_CPU build flags for PPC970 / G5
	powerpc: Fix SPE Power ISA properties for e500v1 platforms
	powerpc/kprobes: Fix null pointer reference in arch_prepare_kprobe()
	powerpc/pseries/vas: Pass hw_cpu_id to node associativity HCALL
	crypto: sahara - don't sleep when in softirq
	crypto: hisilicon/zip - fix mismatch in get/set sgl_sge_nr
	hwrng: arm-smccc-trng - fix NO_ENTROPY handling
	cgroup: Honor caller's cgroup NS when resolving path
	hwrng: imx-rngc - Moving IRQ handler registering after imx_rngc_irq_mask_clear()
	crypto: qat - fix default value of WDT timer
	crypto: hisilicon/qm - fix missing put dfx access
	cgroup/cpuset: Enable update_tasks_cpumask() on top_cpuset
	iommu/omap: Fix buffer overflow in debugfs
	crypto: akcipher - default implementation for setting a private key
	crypto: ccp - Release dma channels before dmaengine unrgister
	crypto: inside-secure - Change swab to swab32
	crypto: qat - fix DMA transfer direction
	cifs: return correct error in ->calc_signature()
	iommu/iova: Fix module config properly
	tracing: kprobe: Fix kprobe event gen test module on exit
	tracing: kprobe: Make gen test module work in arm and riscv
	tracing/osnoise: Fix possible recursive locking in stop_per_cpu_kthreads
	kbuild: remove the target in signal traps when interrupted
	kbuild: rpm-pkg: fix breakage when V=1 is used
	crypto: marvell/octeontx - prevent integer overflows
	crypto: cavium - prevent integer overflow loading firmware
	thermal/drivers/qcom/tsens-v0_1: Fix MSM8939 fourth sensor hw_id
	ACPI: APEI: do not add task_work to kernel thread to avoid memory leak
	f2fs: fix race condition on setting FI_NO_EXTENT flag
	f2fs: fix to account FS_CP_DATA_IO correctly
	selftest: tpm2: Add Client.__del__() to close /dev/tpm* handle
	fs: dlm: fix race in lowcomms
	rcu: Avoid triggering strict-GP irq-work when RCU is idle
	rcu: Back off upon fill_page_cache_func() allocation failure
	rcu-tasks: Convert RCU_LOCKDEP_WARN() to WARN_ONCE()
	ACPI: video: Add Toshiba Satellite/Portege Z830 quirk
	ACPI: tables: FPDT: Don't call acpi_os_map_memory() on invalid phys address
	cpufreq: intel_pstate: Add Tigerlake support in no-HWP mode
	MIPS: BCM47XX: Cast memcmp() of function to (void *)
	powercap: intel_rapl: fix UBSAN shift-out-of-bounds issue
	thermal: intel_powerclamp: Use get_cpu() instead of smp_processor_id() to avoid crash
	ARM: decompressor: Include .data.rel.ro.local
	ACPI: x86: Add a quirk for Dell Inspiron 14 2-in-1 for StorageD3Enable
	x86/entry: Work around Clang __bdos() bug
	NFSD: Return nfserr_serverfault if splice_ok but buf->pages have data
	NFSD: fix use-after-free on source server when doing inter-server copy
	wifi: brcmfmac: fix invalid address access when enabling SCAN log level
	bpftool: Clear errno after libcap's checks
	ice: set tx_tstamps when creating new Tx rings via ethtool
	net: ethernet: ti: davinci_mdio: Add workaround for errata i2329
	openvswitch: Fix double reporting of drops in dropwatch
	openvswitch: Fix overreporting of drops in dropwatch
	tcp: annotate data-race around tcp_md5sig_pool_populated
	x86/mce: Retrieve poison range from hardware
	wifi: ath9k: avoid uninit memory read in ath9k_htc_rx_msg()
	thunderbolt: Add back Intel Falcon Ridge end-to-end flow control workaround
	xfrm: Update ipcomp_scratches with NULL when freed
	iavf: Fix race between iavf_close and iavf_reset_task
	wifi: brcmfmac: fix use-after-free bug in brcmf_netdev_start_xmit()
	Bluetooth: btintel: Mark Intel controller to support LE_STATES quirk
	regulator: core: Prevent integer underflow
	wifi: mt76: mt7921: reset msta->airtime_ac while clearing up hw value
	Bluetooth: L2CAP: initialize delayed works at l2cap_chan_create()
	Bluetooth: hci_sysfs: Fix attempting to call device_add multiple times
	can: bcm: check the result of can_send() in bcm_can_tx()
	wifi: rt2x00: don't run Rt5592 IQ calibration on MT7620
	wifi: rt2x00: set correct TX_SW_CFG1 MAC register for MT7620
	wifi: rt2x00: set VGC gain for both chains of MT7620
	wifi: rt2x00: set SoC wmac clock register
	wifi: rt2x00: correctly set BBP register 86 for MT7620
	hwmon: (sht4x) do not overflow clamping operation on 32-bit platforms
	net: If sock is dead don't access sock's sk_wq in sk_stream_wait_memory
	Bluetooth: L2CAP: Fix user-after-free
	r8152: Rate limit overflow messages
	drm/nouveau/nouveau_bo: fix potential memory leak in nouveau_bo_alloc()
	drm: Use size_t type for len variable in drm_copy_field()
	drm: Prevent drm_copy_field() to attempt copying a NULL pointer
	drm/komeda: Fix handling of atomic commits in the atomic_commit_tail hook
	gpu: lontium-lt9611: Fix NULL pointer dereference in lt9611_connector_init()
	drm/amd/display: fix overflow on MIN_I64 definition
	udmabuf: Set ubuf->sg = NULL if the creation of sg table fails
	drm: bridge: dw_hdmi: only trigger hotplug event on link change
	ALSA: usb-audio: Register card at the last interface
	drm/vc4: vec: Fix timings for VEC modes
	drm: panel-orientation-quirks: Add quirk for Anbernic Win600
	platform/chrome: cros_ec: Notify the PM of wake events during resume
	platform/x86: msi-laptop: Change DMI match / alias strings to fix module autoloading
	ASoC: SOF: pci: Change DMI match info to support all Chrome platforms
	drm/amdgpu: fix initial connector audio value
	drm/meson: reorder driver deinit sequence to fix use-after-free bug
	drm/meson: explicitly remove aggregate driver at module unload time
	mmc: sdhci-msm: add compatible string check for sdm670
	drm/dp: Don't rewrite link config when setting phy test pattern
	drm/amd/display: Remove interface for periodic interrupt 1
	ARM: dts: imx7d-sdb: config the max pressure for tsc2046
	ARM: dts: imx6q: add missing properties for sram
	ARM: dts: imx6dl: add missing properties for sram
	ARM: dts: imx6qp: add missing properties for sram
	ARM: dts: imx6sl: add missing properties for sram
	ARM: dts: imx6sll: add missing properties for sram
	ARM: dts: imx6sx: add missing properties for sram
	kselftest/arm64: Fix validatation termination record after EXTRA_CONTEXT
	arm64: dts: imx8mq-librem5: Add bq25895 as max17055's power supply
	btrfs: dump extra info if one free space cache has more bitmaps than it should
	btrfs: scrub: try to fix super block errors
	btrfs: don't print information about space cache or tree every remount
	ARM: 9242/1: kasan: Only map modules if CONFIG_KASAN_VMALLOC=n
	clk: zynqmp: Fix stack-out-of-bounds in strncpy`
	media: cx88: Fix a null-ptr-deref bug in buffer_prepare()
	media: platform: fix some double free in meson-ge2d and mtk-jpeg and s5p-mfc
	clk: zynqmp: pll: rectify rate rounding in zynqmp_pll_round_rate
	usb: host: xhci-plat: suspend and resume clocks
	usb: host: xhci-plat: suspend/resume clks for brcm
	dmaengine: ti: k3-udma: Reset UDMA_CHAN_RT byte counters to prevent overflow
	scsi: 3w-9xxx: Avoid disabling device if failing to enable it
	nbd: Fix hung when signal interrupts nbd_start_device_ioctl()
	iommu/arm-smmu-v3: Make default domain type of HiSilicon PTT device to identity
	power: supply: adp5061: fix out-of-bounds read in adp5061_get_chg_type()
	staging: vt6655: fix potential memory leak
	blk-throttle: prevent overflow while calculating wait time
	ata: libahci_platform: Sanity check the DT child nodes number
	bcache: fix set_at_max_writeback_rate() for multiple attached devices
	soundwire: cadence: Don't overwrite msg->buf during write commands
	soundwire: intel: fix error handling on dai registration issues
	HID: roccat: Fix use-after-free in roccat_read()
	eventfd: guard wake_up in eventfd fs calls as well
	md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d
	usb: host: xhci: Fix potential memory leak in xhci_alloc_stream_info()
	usb: musb: Fix musb_gadget.c rxstate overflow bug
	arm64: dts: imx8mp: Add snps,gfladj-refclk-lpm-sel quirk to USB nodes
	usb: dwc3: core: Enable GUCTL1 bit 10 for fixing termination error after resume bug
	Revert "usb: storage: Add quirk for Samsung Fit flash"
	staging: rtl8723bs: fix potential memory leak in rtw_init_drv_sw()
	staging: rtl8723bs: fix a potential memory leak in rtw_init_cmd_priv()
	scsi: tracing: Fix compile error in trace_array calls when TRACING is disabled
	ext2: Use kvmalloc() for group descriptor array
	nvme: copy firmware_rev on each init
	nvmet-tcp: add bounds check on Transfer Tag
	usb: idmouse: fix an uninit-value in idmouse_open
	clk: bcm2835: Make peripheral PLLC critical
	clk: bcm2835: Round UART input clock up
	perf intel-pt: Fix segfault in intel_pt_print_info() with uClibc
	io_uring/af_unix: defer registered files gc to io_uring release
	io_uring: correct pinned_vm accounting
	io_uring/rw: fix short rw error handling
	io_uring/rw: fix error'ed retry return values
	io_uring/rw: fix unexpected link breakage
	mm: hugetlb: fix UAF in hugetlb_handle_userfault
	net: ieee802154: return -EINVAL for unknown addr type
	ALSA: usb-audio: Fix last interface check for registration
	blk-wbt: fix that 'rwb->wc' is always set to 1 in wbt_init()
	net: ethernet: ti: davinci_mdio: fix build for mdio bitbang uses
	Revert "net/ieee802154: reject zero-sized raw_sendmsg()"
	net/ieee802154: don't warn zero-sized raw_sendmsg()
	drm/amd/display: Fix build breakage with CONFIG_DEBUG_FS=n
	Kconfig.debug: simplify the dependency of DEBUG_INFO_DWARF4/5
	Kconfig.debug: add toolchain checks for DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT
	lib/Kconfig.debug: Add check for non-constant .{s,u}leb128 support to DWARF5
	ext4: continue to expand file system when the target size doesn't reach
	thermal: intel_powerclamp: Use first online CPU as control_cpu
	gcov: support GCC 12.1 and newer compilers
	io-wq: Fix memory leak in worker creation
	Linux 5.15.75

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: Id3dfe8285e830d01df7adb33729e78a75c1cac1a
2022-11-02 08:51:19 +01:00

1722 lines
39 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* "splice": joining two ropes together by interweaving their strands.
*
* This is the "extended pipe" functionality, where a pipe is used as
* an arbitrary in-memory buffer. Think of a pipe as a small kernel
* buffer that you can use to transfer data from one end to the other.
*
* The traditional unix read/write is extended with a "splice()" operation
* that transfers data buffers to or from a pipe buffer.
*
* Named by Larry McVoy, original implementation from Linus, extended by
* Jens to support splicing to files, network, direct splicing, etc and
* fixing lots of bugs.
*
* Copyright (C) 2005-2006 Jens Axboe <axboe@kernel.dk>
* Copyright (C) 2005-2006 Linus Torvalds <torvalds@osdl.org>
* Copyright (C) 2006 Ingo Molnar <mingo@elte.hu>
*
*/
#include <linux/bvec.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/pagemap.h>
#include <linux/splice.h>
#include <linux/memcontrol.h>
#include <linux/mm_inline.h>
#include <linux/swap.h>
#include <linux/writeback.h>
#include <linux/export.h>
#include <linux/syscalls.h>
#include <linux/uio.h>
#include <linux/security.h>
#include <linux/gfp.h>
#include <linux/socket.h>
#include <linux/sched/signal.h>
#include "internal.h"
/*
* Attempt to steal a page from a pipe buffer. This should perhaps go into
* a vm helper function, it's already simplified quite a bit by the
* addition of remove_mapping(). If success is returned, the caller may
* attempt to reuse this page for another destination.
*/
static bool page_cache_pipe_buf_try_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
struct page *page = buf->page;
struct address_space *mapping;
lock_page(page);
mapping = page_mapping(page);
if (mapping) {
WARN_ON(!PageUptodate(page));
/*
* At least for ext2 with nobh option, we need to wait on
* writeback completing on this page, since we'll remove it
* from the pagecache. Otherwise truncate wont wait on the
* page, allowing the disk blocks to be reused by someone else
* before we actually wrote our data to them. fs corruption
* ensues.
*/
wait_on_page_writeback(page);
if (page_has_private(page) &&
!try_to_release_page(page, GFP_KERNEL))
goto out_unlock;
/*
* If we succeeded in removing the mapping, set LRU flag
* and return good.
*/
if (remove_mapping(mapping, page)) {
buf->flags |= PIPE_BUF_FLAG_LRU;
return true;
}
}
/*
* Raced with truncate or failed to remove page from current
* address space, unlock and return failure.
*/
out_unlock:
unlock_page(page);
return false;
}
static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
put_page(buf->page);
buf->flags &= ~PIPE_BUF_FLAG_LRU;
}
/*
* Check whether the contents of buf is OK to access. Since the content
* is a page cache page, IO may be in flight.
*/
static int page_cache_pipe_buf_confirm(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
struct page *page = buf->page;
int err;
if (!PageUptodate(page)) {
lock_page(page);
/*
* Page got truncated/unhashed. This will cause a 0-byte
* splice, if this is the first page.
*/
if (!page->mapping) {
err = -ENODATA;
goto error;
}
/*
* Uh oh, read-error from disk.
*/
if (!PageUptodate(page)) {
err = -EIO;
goto error;
}
/*
* Page is ok afterall, we are done.
*/
unlock_page(page);
}
return 0;
error:
unlock_page(page);
return err;
}
const struct pipe_buf_operations page_cache_pipe_buf_ops = {
.confirm = page_cache_pipe_buf_confirm,
.release = page_cache_pipe_buf_release,
.try_steal = page_cache_pipe_buf_try_steal,
.get = generic_pipe_buf_get,
};
static bool user_page_pipe_buf_try_steal(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
if (!(buf->flags & PIPE_BUF_FLAG_GIFT))
return false;
buf->flags |= PIPE_BUF_FLAG_LRU;
return generic_pipe_buf_try_steal(pipe, buf);
}
static const struct pipe_buf_operations user_page_pipe_buf_ops = {
.release = page_cache_pipe_buf_release,
.try_steal = user_page_pipe_buf_try_steal,
.get = generic_pipe_buf_get,
};
static void wakeup_pipe_readers(struct pipe_inode_info *pipe)
{
smp_mb();
if (waitqueue_active(&pipe->rd_wait))
wake_up_interruptible(&pipe->rd_wait);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
}
/**
* splice_to_pipe - fill passed data into a pipe
* @pipe: pipe to fill
* @spd: data to fill
*
* Description:
* @spd contains a map of pages and len/offset tuples, along with
* the struct pipe_buf_operations associated with these pages. This
* function will link that data to the pipe.
*
*/
ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
struct splice_pipe_desc *spd)
{
unsigned int spd_pages = spd->nr_pages;
unsigned int tail = pipe->tail;
unsigned int head = pipe->head;
unsigned int mask = pipe->ring_size - 1;
int ret = 0, page_nr = 0;
if (!spd_pages)
return 0;
if (unlikely(!pipe->readers)) {
send_sig(SIGPIPE, current, 0);
ret = -EPIPE;
goto out;
}
while (!pipe_full(head, tail, pipe->max_usage)) {
struct pipe_buffer *buf = &pipe->bufs[head & mask];
buf->page = spd->pages[page_nr];
buf->offset = spd->partial[page_nr].offset;
buf->len = spd->partial[page_nr].len;
buf->private = spd->partial[page_nr].private;
buf->ops = spd->ops;
buf->flags = 0;
head++;
pipe->head = head;
page_nr++;
ret += buf->len;
if (!--spd->nr_pages)
break;
}
if (!ret)
ret = -EAGAIN;
out:
while (page_nr < spd_pages)
spd->spd_release(spd, page_nr++);
return ret;
}
EXPORT_SYMBOL_GPL(splice_to_pipe);
ssize_t add_to_pipe(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
{
unsigned int head = pipe->head;
unsigned int tail = pipe->tail;
unsigned int mask = pipe->ring_size - 1;
int ret;
if (unlikely(!pipe->readers)) {
send_sig(SIGPIPE, current, 0);
ret = -EPIPE;
} else if (pipe_full(head, tail, pipe->max_usage)) {
ret = -EAGAIN;
} else {
pipe->bufs[head & mask] = *buf;
pipe->head = head + 1;
return buf->len;
}
pipe_buf_release(pipe, buf);
return ret;
}
EXPORT_SYMBOL(add_to_pipe);
/*
* Check if we need to grow the arrays holding pages and partial page
* descriptions.
*/
int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
{
unsigned int max_usage = READ_ONCE(pipe->max_usage);
spd->nr_pages_max = max_usage;
if (max_usage <= PIPE_DEF_BUFFERS)
return 0;
spd->pages = kmalloc_array(max_usage, sizeof(struct page *), GFP_KERNEL);
spd->partial = kmalloc_array(max_usage, sizeof(struct partial_page),
GFP_KERNEL);
if (spd->pages && spd->partial)
return 0;
kfree(spd->pages);
kfree(spd->partial);
return -ENOMEM;
}
void splice_shrink_spd(struct splice_pipe_desc *spd)
{
if (spd->nr_pages_max <= PIPE_DEF_BUFFERS)
return;
kfree(spd->pages);
kfree(spd->partial);
}
/**
* generic_file_splice_read - splice data from file to a pipe
* @in: file to splice from
* @ppos: position in @in
* @pipe: pipe to splice to
* @len: number of bytes to splice
* @flags: splice modifier flags
*
* Description:
* Will read pages from given file and fill them into a pipe. Can be
* used as long as it has more or less sane ->read_iter().
*
*/
ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
struct iov_iter to;
struct kiocb kiocb;
unsigned int i_head;
int ret;
iov_iter_pipe(&to, READ, pipe, len);
i_head = to.head;
init_sync_kiocb(&kiocb, in);
kiocb.ki_pos = *ppos;
ret = call_read_iter(in, &kiocb, &to);
if (ret > 0) {
*ppos = kiocb.ki_pos;
file_accessed(in);
} else if (ret < 0) {
to.head = i_head;
to.iov_offset = 0;
iov_iter_advance(&to, 0); /* to free what was emitted */
/*
* callers of ->splice_read() expect -EAGAIN on
* "can't put anything in there", rather than -EFAULT.
*/
if (ret == -EFAULT)
ret = -EAGAIN;
}
return ret;
}
EXPORT_SYMBOL_NS(generic_file_splice_read, ANDROID_GKI_VFS_EXPORT_ONLY);
const struct pipe_buf_operations default_pipe_buf_ops = {
.release = generic_pipe_buf_release,
.try_steal = generic_pipe_buf_try_steal,
.get = generic_pipe_buf_get,
};
/* Pipe buffer operations for a socket and similar. */
const struct pipe_buf_operations nosteal_pipe_buf_ops = {
.release = generic_pipe_buf_release,
.get = generic_pipe_buf_get,
};
EXPORT_SYMBOL(nosteal_pipe_buf_ops);
/*
* Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos'
* using sendpage(). Return the number of bytes sent.
*/
static int pipe_to_sendpage(struct pipe_inode_info *pipe,
struct pipe_buffer *buf, struct splice_desc *sd)
{
struct file *file = sd->u.file;
loff_t pos = sd->pos;
int more;
if (!likely(file->f_op->sendpage))
return -EINVAL;
more = (sd->flags & SPLICE_F_MORE) ? MSG_MORE : 0;
if (sd->len < sd->total_len &&
pipe_occupancy(pipe->head, pipe->tail) > 1)
more |= MSG_SENDPAGE_NOTLAST;
return file->f_op->sendpage(file, buf->page, buf->offset,
sd->len, &pos, more);
}
static void wakeup_pipe_writers(struct pipe_inode_info *pipe)
{
smp_mb();
if (waitqueue_active(&pipe->wr_wait))
wake_up_interruptible(&pipe->wr_wait);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
}
/**
* splice_from_pipe_feed - feed available data from a pipe to a file
* @pipe: pipe to splice from
* @sd: information to @actor
* @actor: handler that splices the data
*
* Description:
* This function loops over the pipe and calls @actor to do the
* actual moving of a single struct pipe_buffer to the desired
* destination. It returns when there's no more buffers left in
* the pipe or if the requested number of bytes (@sd->total_len)
* have been copied. It returns a positive number (one) if the
* pipe needs to be filled with more data, zero if the required
* number of bytes have been copied and -errno on error.
*
* This, together with splice_from_pipe_{begin,end,next}, may be
* used to implement the functionality of __splice_from_pipe() when
* locking is required around copying the pipe buffers to the
* destination.
*/
static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd,
splice_actor *actor)
{
unsigned int head = pipe->head;
unsigned int tail = pipe->tail;
unsigned int mask = pipe->ring_size - 1;
int ret;
while (!pipe_empty(head, tail)) {
struct pipe_buffer *buf = &pipe->bufs[tail & mask];
sd->len = buf->len;
if (sd->len > sd->total_len)
sd->len = sd->total_len;
ret = pipe_buf_confirm(pipe, buf);
if (unlikely(ret)) {
if (ret == -ENODATA)
ret = 0;
return ret;
}
ret = actor(pipe, buf, sd);
if (ret <= 0)
return ret;
buf->offset += ret;
buf->len -= ret;
sd->num_spliced += ret;
sd->len -= ret;
sd->pos += ret;
sd->total_len -= ret;
if (!buf->len) {
pipe_buf_release(pipe, buf);
tail++;
pipe->tail = tail;
if (pipe->files)
sd->need_wakeup = true;
}
if (!sd->total_len)
return 0;
}
return 1;
}
/* We know we have a pipe buffer, but maybe it's empty? */
static inline bool eat_empty_buffer(struct pipe_inode_info *pipe)
{
unsigned int tail = pipe->tail;
unsigned int mask = pipe->ring_size - 1;
struct pipe_buffer *buf = &pipe->bufs[tail & mask];
if (unlikely(!buf->len)) {
pipe_buf_release(pipe, buf);
pipe->tail = tail+1;
return true;
}
return false;
}
/**
* splice_from_pipe_next - wait for some data to splice from
* @pipe: pipe to splice from
* @sd: information about the splice operation
*
* Description:
* This function will wait for some data and return a positive
* value (one) if pipe buffers are available. It will return zero
* or -errno if no more data needs to be spliced.
*/
static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd)
{
/*
* Check for signal early to make process killable when there are
* always buffers available
*/
if (signal_pending(current))
return -ERESTARTSYS;
repeat:
while (pipe_empty(pipe->head, pipe->tail)) {
if (!pipe->writers)
return 0;
if (sd->num_spliced)
return 0;
if (sd->flags & SPLICE_F_NONBLOCK)
return -EAGAIN;
if (signal_pending(current))
return -ERESTARTSYS;
if (sd->need_wakeup) {
wakeup_pipe_writers(pipe);
sd->need_wakeup = false;
}
pipe_wait_readable(pipe);
}
if (eat_empty_buffer(pipe))
goto repeat;
return 1;
}
/**
* splice_from_pipe_begin - start splicing from pipe
* @sd: information about the splice operation
*
* Description:
* This function should be called before a loop containing
* splice_from_pipe_next() and splice_from_pipe_feed() to
* initialize the necessary fields of @sd.
*/
static void splice_from_pipe_begin(struct splice_desc *sd)
{
sd->num_spliced = 0;
sd->need_wakeup = false;
}
/**
* splice_from_pipe_end - finish splicing from pipe
* @pipe: pipe to splice from
* @sd: information about the splice operation
*
* Description:
* This function will wake up pipe writers if necessary. It should
* be called after a loop containing splice_from_pipe_next() and
* splice_from_pipe_feed().
*/
static void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd)
{
if (sd->need_wakeup)
wakeup_pipe_writers(pipe);
}
/**
* __splice_from_pipe - splice data from a pipe to given actor
* @pipe: pipe to splice from
* @sd: information to @actor
* @actor: handler that splices the data
*
* Description:
* This function does little more than loop over the pipe and call
* @actor to do the actual moving of a single struct pipe_buffer to
* the desired destination. See pipe_to_file, pipe_to_sendpage, or
* pipe_to_user.
*
*/
ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
splice_actor *actor)
{
int ret;
splice_from_pipe_begin(sd);
do {
cond_resched();
ret = splice_from_pipe_next(pipe, sd);
if (ret > 0)
ret = splice_from_pipe_feed(pipe, sd, actor);
} while (ret > 0);
splice_from_pipe_end(pipe, sd);
return sd->num_spliced ? sd->num_spliced : ret;
}
EXPORT_SYMBOL(__splice_from_pipe);
/**
* splice_from_pipe - splice data from a pipe to a file
* @pipe: pipe to splice from
* @out: file to splice to
* @ppos: position in @out
* @len: how many bytes to splice
* @flags: splice modifier flags
* @actor: handler that splices the data
*
* Description:
* See __splice_from_pipe. This function locks the pipe inode,
* otherwise it's identical to __splice_from_pipe().
*
*/
ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
loff_t *ppos, size_t len, unsigned int flags,
splice_actor *actor)
{
ssize_t ret;
struct splice_desc sd = {
.total_len = len,
.flags = flags,
.pos = *ppos,
.u.file = out,
};
pipe_lock(pipe);
ret = __splice_from_pipe(pipe, &sd, actor);
pipe_unlock(pipe);
return ret;
}
/**
* iter_file_splice_write - splice data from a pipe to a file
* @pipe: pipe info
* @out: file to write to
* @ppos: position in @out
* @len: number of bytes to splice
* @flags: splice modifier flags
*
* Description:
* Will either move or copy pages (determined by @flags options) from
* the given pipe inode to the given file.
* This one is ->write_iter-based.
*
*/
ssize_t
iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
loff_t *ppos, size_t len, unsigned int flags)
{
struct splice_desc sd = {
.total_len = len,
.flags = flags,
.pos = *ppos,
.u.file = out,
};
int nbufs = pipe->max_usage;
struct bio_vec *array = kcalloc(nbufs, sizeof(struct bio_vec),
GFP_KERNEL);
ssize_t ret;
if (unlikely(!array))
return -ENOMEM;
pipe_lock(pipe);
splice_from_pipe_begin(&sd);
while (sd.total_len) {
struct iov_iter from;
unsigned int head, tail, mask;
size_t left;
int n;
ret = splice_from_pipe_next(pipe, &sd);
if (ret <= 0)
break;
if (unlikely(nbufs < pipe->max_usage)) {
kfree(array);
nbufs = pipe->max_usage;
array = kcalloc(nbufs, sizeof(struct bio_vec),
GFP_KERNEL);
if (!array) {
ret = -ENOMEM;
break;
}
}
head = pipe->head;
tail = pipe->tail;
mask = pipe->ring_size - 1;
/* build the vector */
left = sd.total_len;
for (n = 0; !pipe_empty(head, tail) && left && n < nbufs; tail++) {
struct pipe_buffer *buf = &pipe->bufs[tail & mask];
size_t this_len = buf->len;
/* zero-length bvecs are not supported, skip them */
if (!this_len)
continue;
this_len = min(this_len, left);
ret = pipe_buf_confirm(pipe, buf);
if (unlikely(ret)) {
if (ret == -ENODATA)
ret = 0;
goto done;
}
array[n].bv_page = buf->page;
array[n].bv_len = this_len;
array[n].bv_offset = buf->offset;
left -= this_len;
n++;
}
iov_iter_bvec(&from, WRITE, array, n, sd.total_len - left);
ret = vfs_iter_write(out, &from, &sd.pos, 0);
if (ret <= 0)
break;
sd.num_spliced += ret;
sd.total_len -= ret;
*ppos = sd.pos;
/* dismiss the fully eaten buffers, adjust the partial one */
tail = pipe->tail;
while (ret) {
struct pipe_buffer *buf = &pipe->bufs[tail & mask];
if (ret >= buf->len) {
ret -= buf->len;
buf->len = 0;
pipe_buf_release(pipe, buf);
tail++;
pipe->tail = tail;
if (pipe->files)
sd.need_wakeup = true;
} else {
buf->offset += ret;
buf->len -= ret;
ret = 0;
}
}
}
done:
kfree(array);
splice_from_pipe_end(pipe, &sd);
pipe_unlock(pipe);
if (sd.num_spliced)
ret = sd.num_spliced;
return ret;
}
EXPORT_SYMBOL_NS(iter_file_splice_write, ANDROID_GKI_VFS_EXPORT_ONLY);
/**
* generic_splice_sendpage - splice data from a pipe to a socket
* @pipe: pipe to splice from
* @out: socket to write to
* @ppos: position in @out
* @len: number of bytes to splice
* @flags: splice modifier flags
*
* Description:
* Will send @len bytes from the pipe to a network socket. No data copying
* is involved.
*
*/
ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out,
loff_t *ppos, size_t len, unsigned int flags)
{
return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_sendpage);
}
EXPORT_SYMBOL(generic_splice_sendpage);
static int warn_unsupported(struct file *file, const char *op)
{
pr_debug_ratelimited(
"splice %s not supported for file %pD4 (pid: %d comm: %.20s)\n",
op, file, current->pid, current->comm);
return -EINVAL;
}
/*
* Attempt to initiate a splice from pipe to file.
*/
static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
loff_t *ppos, size_t len, unsigned int flags)
{
if (unlikely(!out->f_op->splice_write))
return warn_unsupported(out, "write");
return out->f_op->splice_write(pipe, out, ppos, len, flags);
}
/*
* Attempt to initiate a splice from a file to a pipe.
*/
static long do_splice_to(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
unsigned int p_space;
int ret;
if (unlikely(!(in->f_mode & FMODE_READ)))
return -EBADF;
/* Don't try to read more the pipe has space for. */
p_space = pipe->max_usage - pipe_occupancy(pipe->head, pipe->tail);
len = min_t(size_t, len, p_space << PAGE_SHIFT);
ret = rw_verify_area(READ, in, ppos, len);
if (unlikely(ret < 0))
return ret;
if (unlikely(len > MAX_RW_COUNT))
len = MAX_RW_COUNT;
if (unlikely(!in->f_op->splice_read))
return warn_unsupported(in, "read");
return in->f_op->splice_read(in, ppos, pipe, len, flags);
}
/**
* splice_direct_to_actor - splices data directly between two non-pipes
* @in: file to splice from
* @sd: actor information on where to splice to
* @actor: handles the data splicing
*
* Description:
* This is a special case helper to splice directly between two
* points, without requiring an explicit pipe. Internally an allocated
* pipe is cached in the process, and reused during the lifetime of
* that process.
*
*/
ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
splice_direct_actor *actor)
{
struct pipe_inode_info *pipe;
long ret, bytes;
umode_t i_mode;
size_t len;
int i, flags, more;
/*
* We require the input being a regular file, as we don't want to
* randomly drop data for eg socket -> socket splicing. Use the
* piped splicing for that!
*/
i_mode = file_inode(in)->i_mode;
if (unlikely(!S_ISREG(i_mode) && !S_ISBLK(i_mode)))
return -EINVAL;
/*
* neither in nor out is a pipe, setup an internal pipe attached to
* 'out' and transfer the wanted data from 'in' to 'out' through that
*/
pipe = current->splice_pipe;
if (unlikely(!pipe)) {
pipe = alloc_pipe_info();
if (!pipe)
return -ENOMEM;
/*
* We don't have an immediate reader, but we'll read the stuff
* out of the pipe right after the splice_to_pipe(). So set
* PIPE_READERS appropriately.
*/
pipe->readers = 1;
current->splice_pipe = pipe;
}
/*
* Do the splice.
*/
ret = 0;
bytes = 0;
len = sd->total_len;
flags = sd->flags;
/*
* Don't block on output, we have to drain the direct pipe.
*/
sd->flags &= ~SPLICE_F_NONBLOCK;
more = sd->flags & SPLICE_F_MORE;
WARN_ON_ONCE(!pipe_empty(pipe->head, pipe->tail));
while (len) {
size_t read_len;
loff_t pos = sd->pos, prev_pos = pos;
ret = do_splice_to(in, &pos, pipe, len, flags);
if (unlikely(ret <= 0))
goto out_release;
read_len = ret;
sd->total_len = read_len;
/*
* If more data is pending, set SPLICE_F_MORE
* If this is the last data and SPLICE_F_MORE was not set
* initially, clears it.
*/
if (read_len < len)
sd->flags |= SPLICE_F_MORE;
else if (!more)
sd->flags &= ~SPLICE_F_MORE;
/*
* NOTE: nonblocking mode only applies to the input. We
* must not do the output in nonblocking mode as then we
* could get stuck data in the internal pipe:
*/
ret = actor(pipe, sd);
if (unlikely(ret <= 0)) {
sd->pos = prev_pos;
goto out_release;
}
bytes += ret;
len -= ret;
sd->pos = pos;
if (ret < read_len) {
sd->pos = prev_pos + ret;
goto out_release;
}
}
done:
pipe->tail = pipe->head = 0;
file_accessed(in);
return bytes;
out_release:
/*
* If we did an incomplete transfer we must release
* the pipe buffers in question:
*/
for (i = 0; i < pipe->ring_size; i++) {
struct pipe_buffer *buf = &pipe->bufs[i];
if (buf->ops)
pipe_buf_release(pipe, buf);
}
if (!bytes)
bytes = ret;
goto done;
}
EXPORT_SYMBOL(splice_direct_to_actor);
static int direct_splice_actor(struct pipe_inode_info *pipe,
struct splice_desc *sd)
{
struct file *file = sd->u.file;
return do_splice_from(pipe, file, sd->opos, sd->total_len,
sd->flags);
}
/**
* do_splice_direct - splices data directly between two files
* @in: file to splice from
* @ppos: input file offset
* @out: file to splice to
* @opos: output file offset
* @len: number of bytes to splice
* @flags: splice modifier flags
*
* Description:
* For use by do_sendfile(). splice can easily emulate sendfile, but
* doing it in the application would incur an extra system call
* (splice in + splice out, as compared to just sendfile()). So this helper
* can splice directly through a process-private pipe.
*
*/
long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
loff_t *opos, size_t len, unsigned int flags)
{
struct splice_desc sd = {
.len = len,
.total_len = len,
.flags = flags,
.pos = *ppos,
.u.file = out,
.opos = opos,
};
long ret;
if (unlikely(!(out->f_mode & FMODE_WRITE)))
return -EBADF;
if (unlikely(out->f_flags & O_APPEND))
return -EINVAL;
ret = rw_verify_area(WRITE, out, opos, len);
if (unlikely(ret < 0))
return ret;
ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
if (ret > 0)
*ppos = sd.pos;
return ret;
}
EXPORT_SYMBOL(do_splice_direct);
static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
{
for (;;) {
if (unlikely(!pipe->readers)) {
send_sig(SIGPIPE, current, 0);
return -EPIPE;
}
if (!pipe_full(pipe->head, pipe->tail, pipe->max_usage))
return 0;
if (flags & SPLICE_F_NONBLOCK)
return -EAGAIN;
if (signal_pending(current))
return -ERESTARTSYS;
pipe_wait_writable(pipe);
}
}
static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
struct pipe_inode_info *opipe,
size_t len, unsigned int flags);
long splice_file_to_pipe(struct file *in,
struct pipe_inode_info *opipe,
loff_t *offset,
size_t len, unsigned int flags)
{
long ret;
pipe_lock(opipe);
ret = wait_for_space(opipe, flags);
if (!ret)
ret = do_splice_to(in, offset, opipe, len, flags);
pipe_unlock(opipe);
if (ret > 0)
wakeup_pipe_readers(opipe);
return ret;
}
/*
* Determine where to splice to/from.
*/
long do_splice(struct file *in, loff_t *off_in, struct file *out,
loff_t *off_out, size_t len, unsigned int flags)
{
struct pipe_inode_info *ipipe;
struct pipe_inode_info *opipe;
loff_t offset;
long ret;
if (unlikely(!(in->f_mode & FMODE_READ) ||
!(out->f_mode & FMODE_WRITE)))
return -EBADF;
ipipe = get_pipe_info(in, true);
opipe = get_pipe_info(out, true);
if (ipipe && opipe) {
if (off_in || off_out)
return -ESPIPE;
/* Splicing to self would be fun, but... */
if (ipipe == opipe)
return -EINVAL;
if ((in->f_flags | out->f_flags) & O_NONBLOCK)
flags |= SPLICE_F_NONBLOCK;
return splice_pipe_to_pipe(ipipe, opipe, len, flags);
}
if (ipipe) {
if (off_in)
return -ESPIPE;
if (off_out) {
if (!(out->f_mode & FMODE_PWRITE))
return -EINVAL;
offset = *off_out;
} else {
offset = out->f_pos;
}
if (unlikely(out->f_flags & O_APPEND))
return -EINVAL;
ret = rw_verify_area(WRITE, out, &offset, len);
if (unlikely(ret < 0))
return ret;
if (in->f_flags & O_NONBLOCK)
flags |= SPLICE_F_NONBLOCK;
file_start_write(out);
ret = do_splice_from(ipipe, out, &offset, len, flags);
file_end_write(out);
if (!off_out)
out->f_pos = offset;
else
*off_out = offset;
return ret;
}
if (opipe) {
if (off_out)
return -ESPIPE;
if (off_in) {
if (!(in->f_mode & FMODE_PREAD))
return -EINVAL;
offset = *off_in;
} else {
offset = in->f_pos;
}
if (out->f_flags & O_NONBLOCK)
flags |= SPLICE_F_NONBLOCK;
ret = splice_file_to_pipe(in, opipe, &offset, len, flags);
if (!off_in)
in->f_pos = offset;
else
*off_in = offset;
return ret;
}
return -EINVAL;
}
static long __do_splice(struct file *in, loff_t __user *off_in,
struct file *out, loff_t __user *off_out,
size_t len, unsigned int flags)
{
struct pipe_inode_info *ipipe;
struct pipe_inode_info *opipe;
loff_t offset, *__off_in = NULL, *__off_out = NULL;
long ret;
ipipe = get_pipe_info(in, true);
opipe = get_pipe_info(out, true);
if (ipipe && off_in)
return -ESPIPE;
if (opipe && off_out)
return -ESPIPE;
if (off_out) {
if (copy_from_user(&offset, off_out, sizeof(loff_t)))
return -EFAULT;
__off_out = &offset;
}
if (off_in) {
if (copy_from_user(&offset, off_in, sizeof(loff_t)))
return -EFAULT;
__off_in = &offset;
}
ret = do_splice(in, __off_in, out, __off_out, len, flags);
if (ret < 0)
return ret;
if (__off_out && copy_to_user(off_out, __off_out, sizeof(loff_t)))
return -EFAULT;
if (__off_in && copy_to_user(off_in, __off_in, sizeof(loff_t)))
return -EFAULT;
return ret;
}
static int iter_to_pipe(struct iov_iter *from,
struct pipe_inode_info *pipe,
unsigned flags)
{
struct pipe_buffer buf = {
.ops = &user_page_pipe_buf_ops,
.flags = flags
};
size_t total = 0;
int ret = 0;
bool failed = false;
while (iov_iter_count(from) && !failed) {
struct page *pages[16];
ssize_t copied;
size_t start;
int n;
copied = iov_iter_get_pages(from, pages, ~0UL, 16, &start);
if (copied <= 0) {
ret = copied;
break;
}
for (n = 0; copied; n++, start = 0) {
int size = min_t(int, copied, PAGE_SIZE - start);
if (!failed) {
buf.page = pages[n];
buf.offset = start;
buf.len = size;
ret = add_to_pipe(pipe, &buf);
if (unlikely(ret < 0)) {
failed = true;
} else {
iov_iter_advance(from, ret);
total += ret;
}
} else {
put_page(pages[n]);
}
copied -= size;
}
}
return total ? total : ret;
}
static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
struct splice_desc *sd)
{
int n = copy_page_to_iter(buf->page, buf->offset, sd->len, sd->u.data);
return n == sd->len ? n : -EFAULT;
}
/*
* For lack of a better implementation, implement vmsplice() to userspace
* as a simple copy of the pipes pages to the user iov.
*/
static long vmsplice_to_user(struct file *file, struct iov_iter *iter,
unsigned int flags)
{
struct pipe_inode_info *pipe = get_pipe_info(file, true);
struct splice_desc sd = {
.total_len = iov_iter_count(iter),
.flags = flags,
.u.data = iter
};
long ret = 0;
if (!pipe)
return -EBADF;
if (sd.total_len) {
pipe_lock(pipe);
ret = __splice_from_pipe(pipe, &sd, pipe_to_user);
pipe_unlock(pipe);
}
return ret;
}
/*
* vmsplice splices a user address range into a pipe. It can be thought of
* as splice-from-memory, where the regular splice is splice-from-file (or
* to file). In both cases the output is a pipe, naturally.
*/
static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter,
unsigned int flags)
{
struct pipe_inode_info *pipe;
long ret = 0;
unsigned buf_flag = 0;
if (flags & SPLICE_F_GIFT)
buf_flag = PIPE_BUF_FLAG_GIFT;
pipe = get_pipe_info(file, true);
if (!pipe)
return -EBADF;
pipe_lock(pipe);
ret = wait_for_space(pipe, flags);
if (!ret)
ret = iter_to_pipe(iter, pipe, buf_flag);
pipe_unlock(pipe);
if (ret > 0)
wakeup_pipe_readers(pipe);
return ret;
}
static int vmsplice_type(struct fd f, int *type)
{
if (!f.file)
return -EBADF;
if (f.file->f_mode & FMODE_WRITE) {
*type = WRITE;
} else if (f.file->f_mode & FMODE_READ) {
*type = READ;
} else {
fdput(f);
return -EBADF;
}
return 0;
}
/*
* Note that vmsplice only really supports true splicing _from_ user memory
* to a pipe, not the other way around. Splicing from user memory is a simple
* operation that can be supported without any funky alignment restrictions
* or nasty vm tricks. We simply map in the user memory and fill them into
* a pipe. The reverse isn't quite as easy, though. There are two possible
* solutions for that:
*
* - memcpy() the data internally, at which point we might as well just
* do a regular read() on the buffer anyway.
* - Lots of nasty vm tricks, that are neither fast nor flexible (it
* has restriction limitations on both ends of the pipe).
*
* Currently we punt and implement it as a normal copy, see pipe_to_user().
*
*/
SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, uiov,
unsigned long, nr_segs, unsigned int, flags)
{
struct iovec iovstack[UIO_FASTIOV];
struct iovec *iov = iovstack;
struct iov_iter iter;
ssize_t error;
struct fd f;
int type;
if (unlikely(flags & ~SPLICE_F_ALL))
return -EINVAL;
f = fdget(fd);
error = vmsplice_type(f, &type);
if (error)
return error;
error = import_iovec(type, uiov, nr_segs,
ARRAY_SIZE(iovstack), &iov, &iter);
if (error < 0)
goto out_fdput;
if (!iov_iter_count(&iter))
error = 0;
else if (iov_iter_rw(&iter) == WRITE)
error = vmsplice_to_pipe(f.file, &iter, flags);
else
error = vmsplice_to_user(f.file, &iter, flags);
kfree(iov);
out_fdput:
fdput(f);
return error;
}
SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in,
int, fd_out, loff_t __user *, off_out,
size_t, len, unsigned int, flags)
{
struct fd in, out;
long error;
if (unlikely(!len))
return 0;
if (unlikely(flags & ~SPLICE_F_ALL))
return -EINVAL;
error = -EBADF;
in = fdget(fd_in);
if (in.file) {
out = fdget(fd_out);
if (out.file) {
error = __do_splice(in.file, off_in, out.file, off_out,
len, flags);
fdput(out);
}
fdput(in);
}
return error;
}
/*
* Make sure there's data to read. Wait for input if we can, otherwise
* return an appropriate error.
*/
static int ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
{
int ret;
/*
* Check the pipe occupancy without the inode lock first. This function
* is speculative anyways, so missing one is ok.
*/
if (!pipe_empty(pipe->head, pipe->tail))
return 0;
ret = 0;
pipe_lock(pipe);
while (pipe_empty(pipe->head, pipe->tail)) {
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
if (!pipe->writers)
break;
if (flags & SPLICE_F_NONBLOCK) {
ret = -EAGAIN;
break;
}
pipe_wait_readable(pipe);
}
pipe_unlock(pipe);
return ret;
}
/*
* Make sure there's writeable room. Wait for room if we can, otherwise
* return an appropriate error.
*/
static int opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
{
int ret;
/*
* Check pipe occupancy without the inode lock first. This function
* is speculative anyways, so missing one is ok.
*/
if (!pipe_full(pipe->head, pipe->tail, pipe->max_usage))
return 0;
ret = 0;
pipe_lock(pipe);
while (pipe_full(pipe->head, pipe->tail, pipe->max_usage)) {
if (!pipe->readers) {
send_sig(SIGPIPE, current, 0);
ret = -EPIPE;
break;
}
if (flags & SPLICE_F_NONBLOCK) {
ret = -EAGAIN;
break;
}
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
pipe_wait_writable(pipe);
}
pipe_unlock(pipe);
return ret;
}
/*
* Splice contents of ipipe to opipe.
*/
static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
struct pipe_inode_info *opipe,
size_t len, unsigned int flags)
{
struct pipe_buffer *ibuf, *obuf;
unsigned int i_head, o_head;
unsigned int i_tail, o_tail;
unsigned int i_mask, o_mask;
int ret = 0;
bool input_wakeup = false;
retry:
ret = ipipe_prep(ipipe, flags);
if (ret)
return ret;
ret = opipe_prep(opipe, flags);
if (ret)
return ret;
/*
* Potential ABBA deadlock, work around it by ordering lock
* grabbing by pipe info address. Otherwise two different processes
* could deadlock (one doing tee from A -> B, the other from B -> A).
*/
pipe_double_lock(ipipe, opipe);
i_tail = ipipe->tail;
i_mask = ipipe->ring_size - 1;
o_head = opipe->head;
o_mask = opipe->ring_size - 1;
do {
size_t o_len;
if (!opipe->readers) {
send_sig(SIGPIPE, current, 0);
if (!ret)
ret = -EPIPE;
break;
}
i_head = ipipe->head;
o_tail = opipe->tail;
if (pipe_empty(i_head, i_tail) && !ipipe->writers)
break;
/*
* Cannot make any progress, because either the input
* pipe is empty or the output pipe is full.
*/
if (pipe_empty(i_head, i_tail) ||
pipe_full(o_head, o_tail, opipe->max_usage)) {
/* Already processed some buffers, break */
if (ret)
break;
if (flags & SPLICE_F_NONBLOCK) {
ret = -EAGAIN;
break;
}
/*
* We raced with another reader/writer and haven't
* managed to process any buffers. A zero return
* value means EOF, so retry instead.
*/
pipe_unlock(ipipe);
pipe_unlock(opipe);
goto retry;
}
ibuf = &ipipe->bufs[i_tail & i_mask];
obuf = &opipe->bufs[o_head & o_mask];
if (len >= ibuf->len) {
/*
* Simply move the whole buffer from ipipe to opipe
*/
*obuf = *ibuf;
ibuf->ops = NULL;
i_tail++;
ipipe->tail = i_tail;
input_wakeup = true;
o_len = obuf->len;
o_head++;
opipe->head = o_head;
} else {
/*
* Get a reference to this pipe buffer,
* so we can copy the contents over.
*/
if (!pipe_buf_get(ipipe, ibuf)) {
if (ret == 0)
ret = -EFAULT;
break;
}
*obuf = *ibuf;
/*
* Don't inherit the gift and merge flags, we need to
* prevent multiple steals of this page.
*/
obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
obuf->flags &= ~PIPE_BUF_FLAG_CAN_MERGE;
obuf->len = len;
ibuf->offset += len;
ibuf->len -= len;
o_len = len;
o_head++;
opipe->head = o_head;
}
ret += o_len;
len -= o_len;
} while (len);
pipe_unlock(ipipe);
pipe_unlock(opipe);
/*
* If we put data in the output pipe, wakeup any potential readers.
*/
if (ret > 0)
wakeup_pipe_readers(opipe);
if (input_wakeup)
wakeup_pipe_writers(ipipe);
return ret;
}
/*
* Link contents of ipipe to opipe.
*/
static int link_pipe(struct pipe_inode_info *ipipe,
struct pipe_inode_info *opipe,
size_t len, unsigned int flags)
{
struct pipe_buffer *ibuf, *obuf;
unsigned int i_head, o_head;
unsigned int i_tail, o_tail;
unsigned int i_mask, o_mask;
int ret = 0;
/*
* Potential ABBA deadlock, work around it by ordering lock
* grabbing by pipe info address. Otherwise two different processes
* could deadlock (one doing tee from A -> B, the other from B -> A).
*/
pipe_double_lock(ipipe, opipe);
i_tail = ipipe->tail;
i_mask = ipipe->ring_size - 1;
o_head = opipe->head;
o_mask = opipe->ring_size - 1;
do {
if (!opipe->readers) {
send_sig(SIGPIPE, current, 0);
if (!ret)
ret = -EPIPE;
break;
}
i_head = ipipe->head;
o_tail = opipe->tail;
/*
* If we have iterated all input buffers or run out of
* output room, break.
*/
if (pipe_empty(i_head, i_tail) ||
pipe_full(o_head, o_tail, opipe->max_usage))
break;
ibuf = &ipipe->bufs[i_tail & i_mask];
obuf = &opipe->bufs[o_head & o_mask];
/*
* Get a reference to this pipe buffer,
* so we can copy the contents over.
*/
if (!pipe_buf_get(ipipe, ibuf)) {
if (ret == 0)
ret = -EFAULT;
break;
}
*obuf = *ibuf;
/*
* Don't inherit the gift and merge flag, we need to prevent
* multiple steals of this page.
*/
obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
obuf->flags &= ~PIPE_BUF_FLAG_CAN_MERGE;
if (obuf->len > len)
obuf->len = len;
ret += obuf->len;
len -= obuf->len;
o_head++;
opipe->head = o_head;
i_tail++;
} while (len);
pipe_unlock(ipipe);
pipe_unlock(opipe);
/*
* If we put data in the output pipe, wakeup any potential readers.
*/
if (ret > 0)
wakeup_pipe_readers(opipe);
return ret;
}
/*
* This is a tee(1) implementation that works on pipes. It doesn't copy
* any data, it simply references the 'in' pages on the 'out' pipe.
* The 'flags' used are the SPLICE_F_* variants, currently the only
* applicable one is SPLICE_F_NONBLOCK.
*/
long do_tee(struct file *in, struct file *out, size_t len, unsigned int flags)
{
struct pipe_inode_info *ipipe = get_pipe_info(in, true);
struct pipe_inode_info *opipe = get_pipe_info(out, true);
int ret = -EINVAL;
if (unlikely(!(in->f_mode & FMODE_READ) ||
!(out->f_mode & FMODE_WRITE)))
return -EBADF;
/*
* Duplicate the contents of ipipe to opipe without actually
* copying the data.
*/
if (ipipe && opipe && ipipe != opipe) {
if ((in->f_flags | out->f_flags) & O_NONBLOCK)
flags |= SPLICE_F_NONBLOCK;
/*
* Keep going, unless we encounter an error. The ipipe/opipe
* ordering doesn't really matter.
*/
ret = ipipe_prep(ipipe, flags);
if (!ret) {
ret = opipe_prep(opipe, flags);
if (!ret)
ret = link_pipe(ipipe, opipe, len, flags);
}
}
return ret;
}
SYSCALL_DEFINE4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags)
{
struct fd in, out;
int error;
if (unlikely(flags & ~SPLICE_F_ALL))
return -EINVAL;
if (unlikely(!len))
return 0;
error = -EBADF;
in = fdget(fdin);
if (in.file) {
out = fdget(fdout);
if (out.file) {
error = do_tee(in.file, out.file, len, flags);
fdput(out);
}
fdput(in);
}
return error;
}