Changes in 4.19.268
wifi: mac80211_hwsim: fix debugfs attribute ps with rc table support
audit: fix undefined behavior in bit shift for AUDIT_BIT
wifi: mac80211: Fix ack frame idr leak when mesh has no route
spi: stm32: fix stm32_spi_prepare_mbr() that halves spi clk for every run
drm: panel-orientation-quirks: Add quirk for Acer Switch V 10 (SW5-017)
RISC-V: vdso: Do not add missing symbols to version section in linker script
MIPS: pic32: treat port as signed integer
af_key: Fix send_acquire race with pfkey_register
ARM: dts: am335x-pcm-953: Define fixed regulators in root node
ASoC: sgtl5000: Reset the CHIP_CLK_CTRL reg on remove
bus: sunxi-rsb: Support atomic transfers
ARM: dts: at91: sam9g20ek: enable udc vbus gpio pinctrl
nfc/nci: fix race with opening and closing
net: pch_gbe: fix potential memleak in pch_gbe_tx_queue()
9p/fd: fix issue of list_del corruption in p9_fd_cancel()
ARM: mxs: fix memory leak in mxs_machine_init()
net/mlx4: Check retval of mlx4_bitmap_init
net/qla3xxx: fix potential memleak in ql3xxx_send()
net: pch_gbe: fix pci device refcount leak while module exiting
Drivers: hv: vmbus: fix double free in the error path of vmbus_add_channel_work()
Drivers: hv: vmbus: fix possible memory leak in vmbus_device_register()
net/mlx5: Fix FW tracer timestamp calculation
tipc: set con sock in tipc_conn_alloc
tipc: add an extra conn_get in tipc_conn_alloc
tipc: check skb_linearize() return value in tipc_disc_rcv()
xfrm: Fix ignored return value in xfrm6_init()
NFC: nci: fix memory leak in nci_rx_data_packet()
bnx2x: fix pci device refcount leak in bnx2x_vf_is_pcie_pending()
dccp/tcp: Reset saddr on failure after inet6?_hash_connect().
s390/dasd: fix no record found for raw_track_access
nfc: st-nci: fix incorrect validating logic in EVT_TRANSACTION
nfc: st-nci: fix memory leaks in EVT_TRANSACTION
net: thunderx: Fix the ACPI memory leak
s390/crashdump: fix TOD programmable field size
arm64: dts: rockchip: lower rk3399-puma-haikou SD controller clock frequency
iio: light: apds9960: fix wrong register for gesture gain
iio: core: Fix entry not deleted when iio_register_sw_trigger_type() fails
nios2: add FORCE for vmlinuz.gz
iio: ms5611: Simplify IO callback parameters
iio: pressure: ms5611: fixed value compensation bug
ceph: do not update snapshot context when there is no new snapshot
ceph: avoid putting the realm twice when decoding snaps fails
nilfs2: fix nilfs_sufile_mark_dirty() not set segment usage as dirty
Input: synaptics - switch touchpad on HP Laptop 15-da3001TU to RMI mode
serial: 8250: 8250_omap: Avoid RS485 RTS glitch on ->set_termios()
xen/platform-pci: add missing free_irq() in error path
platform/x86: asus-wmi: add missing pci_dev_put() in asus_wmi_set_xusb2pr()
platform/x86: acer-wmi: Enable SW_TABLET_MODE on Switch V 10 (SW5-017)
platform/x86: hp-wmi: Ignore Smart Experience App event
tcp: configurable source port perturb table size
net: usb: qmi_wwan: add Telit 0x103a composition
dm integrity: flush the journal on suspend
btrfs: free btrfs_path before copying root refs to userspace
btrfs: free btrfs_path before copying fspath to userspace
btrfs: free btrfs_path before copying subvol info to userspace
drm/amd/dc/dce120: Fix audio register mapping, stop triggering KASAN
drm/amdgpu: always register an MMU notifier for userptr
btrfs: free btrfs_path before copying inodes to userspace
spi: spi-imx: Fix spi_bus_clk if requested clock is higher than input clock
proc: avoid integer type confusion in get_proc_long
proc: proc_skip_spaces() shouldn't think it is working on C strings
v4l2: don't fall back to follow_pfn() if pin_user_pages_fast() fails
Revert "x86/speculation: Change FILL_RETURN_BUFFER to work with objtool"
iio: health: afe4403: Fix oob read in afe4403_read_raw
iio: health: afe4404: Fix oob read in afe4404_[read|write]_raw
iio: light: rpr0521: add missing Kconfig dependencies
scripts/faddr2line: Fix regression in name resolution on ppc64le
hwmon: (i5500_temp) fix missing pci_disable_device()
hwmon: (ibmpex) Fix possible UAF when ibmpex_register_bmc() fails
of: property: decrement node refcount in of_fwnode_get_reference_args()
net/mlx5: Fix uninitialized variable bug in outlen_write()
can: sja1000_isa: sja1000_isa_probe(): add missing free_sja1000dev()
can: cc770: cc770_isa_probe(): add missing free_cc770dev()
qlcnic: fix sleep-in-atomic-context bugs caused by msleep
net: phy: fix null-ptr-deref while probe() failed
net: net_netdev: Fix error handling in ntb_netdev_init_module()
net/9p: Fix a potential socket leak in p9_socket_open
dsa: lan9303: Correct stat name
net: hsr: Fix potential use-after-free
net: tun: Fix use-after-free in tun_detach()
packet: do not set TP_STATUS_CSUM_VALID on CHECKSUM_COMPLETE
net: ethernet: renesas: ravb: Fix promiscuous mode after system resumed
hwmon: (coretemp) Check for null before removing sysfs attrs
hwmon: (coretemp) fix pci device refcount leak in nv1a_ram_new()
btrfs: qgroup: fix sleep from invalid context bug in btrfs_qgroup_inherit()
error-injection: Add prompt for function error injection
tools/vm/slabinfo-gnuplot: use "grep -E" instead of "egrep"
nilfs2: fix NULL pointer dereference in nilfs_palloc_commit_free_entry()
x86/bugs: Make sure MSR_SPEC_CTRL is updated properly upon resume from S3
pinctrl: intel: Save and restore pins in "direct IRQ" mode
arm64: Fix panic() when Spectre-v2 causes Spectre-BHB to re-allocate KVM vectors
arm64: errata: Fix KVM Spectre-v2 mitigation selection for Cortex-A57/A72
mm: Fix '.data.once' orphan section warning
ASoC: ops: Fix bounds check for _sx controls
pinctrl: single: Fix potential division by zero
iommu/vt-d: Fix PCI device refcount leak in dmar_dev_scope_init()
parisc: Increase size of gcc stack frame check
xtensa: increase size of gcc stack frame check
parisc: Increase FRAME_WARN to 2048 bytes on parisc
Kconfig.debug: provide a little extra FRAME_WARN leeway when KASAN is enabled
tcp/udp: Fix memory leak in ipv6_renew_options().
nvme: restrict management ioctls to admin
x86/tsx: Add a feature bit for TSX control MSR support
x86/pm: Add enumeration check before spec MSRs save/restore setup
Bluetooth: L2CAP: Fix accepting connection request for invalid SPSM
x86/ioremap: Fix page aligned size calculation in __ioremap_caller()
mmc: sdhci: use FIELD_GET for preset value bit masks
mmc: sdhci: Fix voltage switch delay
ipc/sem: Fix dangling sem_array access in semtimedop race
Linux 4.19.268
Change-Id: Ifb1a44994650c56c8be98fa5eaff557699c0999e
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
223 lines
6.1 KiB
C
223 lines
6.1 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <linux/kernel.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/err.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/pagemap.h>
|
|
#include <linux/sched.h>
|
|
|
|
/**
|
|
* get_vaddr_frames() - map virtual addresses to pfns
|
|
* @start: starting user address
|
|
* @nr_frames: number of pages / pfns from start to map
|
|
* @gup_flags: flags modifying lookup behaviour
|
|
* @vec: structure which receives pages / pfns of the addresses mapped.
|
|
* It should have space for at least nr_frames entries.
|
|
*
|
|
* This function maps virtual addresses from @start and fills @vec structure
|
|
* with page frame numbers or page pointers to corresponding pages (choice
|
|
* depends on the type of the vma underlying the virtual address). If @start
|
|
* belongs to a normal vma, the function grabs reference to each of the pages
|
|
* to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
|
|
* touch page structures and the caller must make sure pfns aren't reused for
|
|
* anything else while he is using them.
|
|
*
|
|
* The function returns number of pages mapped which may be less than
|
|
* @nr_frames. In particular we stop mapping if there are more vmas of
|
|
* different type underlying the specified range of virtual addresses.
|
|
* When the function isn't able to map a single page, it returns error.
|
|
*
|
|
* This function takes care of grabbing mmap_sem as necessary.
|
|
*/
|
|
int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
|
|
unsigned int gup_flags, struct frame_vector *vec)
|
|
{
|
|
struct mm_struct *mm = current->mm;
|
|
struct vm_area_struct *vma;
|
|
int ret = 0;
|
|
int locked;
|
|
|
|
if (nr_frames == 0)
|
|
return 0;
|
|
|
|
if (WARN_ON_ONCE(nr_frames > vec->nr_allocated))
|
|
nr_frames = vec->nr_allocated;
|
|
|
|
start = untagged_addr(start);
|
|
|
|
down_read(&mm->mmap_sem);
|
|
locked = 1;
|
|
vma = find_vma_intersection(mm, start, start + 1);
|
|
if (!vma) {
|
|
ret = -EFAULT;
|
|
goto out;
|
|
}
|
|
|
|
/*
|
|
* While get_vaddr_frames() could be used for transient (kernel
|
|
* controlled lifetime) pinning of memory pages all current
|
|
* users establish long term (userspace controlled lifetime)
|
|
* page pinning. Treat get_vaddr_frames() like
|
|
* get_user_pages_longterm() and disallow it for filesystem-dax
|
|
* mappings.
|
|
*/
|
|
if (vma_is_fsdax(vma)) {
|
|
ret = -EOPNOTSUPP;
|
|
goto out;
|
|
}
|
|
|
|
if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) {
|
|
vec->got_ref = true;
|
|
vec->is_pfns = false;
|
|
ret = get_user_pages_locked(start, nr_frames,
|
|
gup_flags, (struct page **)(vec->ptrs), &locked);
|
|
if (likely(ret > 0))
|
|
goto out;
|
|
}
|
|
|
|
/* This used to (racily) return non-refcounted pfns. Let people know */
|
|
WARN_ONCE(1, "get_vaddr_frames() cannot follow VM_IO mapping");
|
|
vec->nr_frames = 0;
|
|
|
|
out:
|
|
if (locked)
|
|
up_read(&mm->mmap_sem);
|
|
if (!ret)
|
|
ret = -EFAULT;
|
|
if (ret > 0)
|
|
vec->nr_frames = ret;
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(get_vaddr_frames);
|
|
|
|
/**
|
|
* put_vaddr_frames() - drop references to pages if get_vaddr_frames() acquired
|
|
* them
|
|
* @vec: frame vector to put
|
|
*
|
|
* Drop references to pages if get_vaddr_frames() acquired them. We also
|
|
* invalidate the frame vector so that it is prepared for the next call into
|
|
* get_vaddr_frames().
|
|
*/
|
|
void put_vaddr_frames(struct frame_vector *vec)
|
|
{
|
|
int i;
|
|
struct page **pages;
|
|
|
|
if (!vec->got_ref)
|
|
goto out;
|
|
pages = frame_vector_pages(vec);
|
|
/*
|
|
* frame_vector_pages() might needed to do a conversion when
|
|
* get_vaddr_frames() got pages but vec was later converted to pfns.
|
|
* But it shouldn't really fail to convert pfns back...
|
|
*/
|
|
if (WARN_ON(IS_ERR(pages)))
|
|
goto out;
|
|
for (i = 0; i < vec->nr_frames; i++)
|
|
put_page(pages[i]);
|
|
vec->got_ref = false;
|
|
out:
|
|
vec->nr_frames = 0;
|
|
}
|
|
EXPORT_SYMBOL(put_vaddr_frames);
|
|
|
|
/**
|
|
* frame_vector_to_pages - convert frame vector to contain page pointers
|
|
* @vec: frame vector to convert
|
|
*
|
|
* Convert @vec to contain array of page pointers. If the conversion is
|
|
* successful, return 0. Otherwise return an error. Note that we do not grab
|
|
* page references for the page structures.
|
|
*/
|
|
int frame_vector_to_pages(struct frame_vector *vec)
|
|
{
|
|
int i;
|
|
unsigned long *nums;
|
|
struct page **pages;
|
|
|
|
if (!vec->is_pfns)
|
|
return 0;
|
|
nums = frame_vector_pfns(vec);
|
|
for (i = 0; i < vec->nr_frames; i++)
|
|
if (!pfn_valid(nums[i]))
|
|
return -EINVAL;
|
|
pages = (struct page **)nums;
|
|
for (i = 0; i < vec->nr_frames; i++)
|
|
pages[i] = pfn_to_page(nums[i]);
|
|
vec->is_pfns = false;
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(frame_vector_to_pages);
|
|
|
|
/**
|
|
* frame_vector_to_pfns - convert frame vector to contain pfns
|
|
* @vec: frame vector to convert
|
|
*
|
|
* Convert @vec to contain array of pfns.
|
|
*/
|
|
void frame_vector_to_pfns(struct frame_vector *vec)
|
|
{
|
|
int i;
|
|
unsigned long *nums;
|
|
struct page **pages;
|
|
|
|
if (vec->is_pfns)
|
|
return;
|
|
pages = (struct page **)(vec->ptrs);
|
|
nums = (unsigned long *)pages;
|
|
for (i = 0; i < vec->nr_frames; i++)
|
|
nums[i] = page_to_pfn(pages[i]);
|
|
vec->is_pfns = true;
|
|
}
|
|
EXPORT_SYMBOL(frame_vector_to_pfns);
|
|
|
|
/**
|
|
* frame_vector_create() - allocate & initialize structure for pinned pfns
|
|
* @nr_frames: number of pfns slots we should reserve
|
|
*
|
|
* Allocate and initialize struct pinned_pfns to be able to hold @nr_pfns
|
|
* pfns.
|
|
*/
|
|
struct frame_vector *frame_vector_create(unsigned int nr_frames)
|
|
{
|
|
struct frame_vector *vec;
|
|
int size = sizeof(struct frame_vector) + sizeof(void *) * nr_frames;
|
|
|
|
if (WARN_ON_ONCE(nr_frames == 0))
|
|
return NULL;
|
|
/*
|
|
* This is absurdly high. It's here just to avoid strange effects when
|
|
* arithmetics overflows.
|
|
*/
|
|
if (WARN_ON_ONCE(nr_frames > INT_MAX / sizeof(void *) / 2))
|
|
return NULL;
|
|
/*
|
|
* Avoid higher order allocations, use vmalloc instead. It should
|
|
* be rare anyway.
|
|
*/
|
|
vec = kvmalloc(size, GFP_KERNEL);
|
|
if (!vec)
|
|
return NULL;
|
|
vec->nr_allocated = nr_frames;
|
|
vec->nr_frames = 0;
|
|
return vec;
|
|
}
|
|
EXPORT_SYMBOL(frame_vector_create);
|
|
|
|
/**
|
|
* frame_vector_destroy() - free memory allocated to carry frame vector
|
|
* @vec: Frame vector to free
|
|
*
|
|
* Free structure allocated by frame_vector_create() to carry frames.
|
|
*/
|
|
void frame_vector_destroy(struct frame_vector *vec)
|
|
{
|
|
/* Make sure put_vaddr_frames() got called properly... */
|
|
VM_BUG_ON(vec->nr_frames > 0);
|
|
kvfree(vec);
|
|
}
|
|
EXPORT_SYMBOL(frame_vector_destroy);
|