* Re: hv_hypercall_pg page permissios
From: Wei Liu @ 2020-04-07 20:42 UTC (permalink / raw)
To: Dexuan Cui
Cc: vkuznets, Christoph Hellwig, x86@kernel.org,
linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org,
KY Srinivasan, Stephen Hemminger, Andy Lutomirski, Peter Zijlstra,
Wei Liu
In-Reply-To: <HK0P153MB0273278D61381693E022B3ADBFC30@HK0P153MB0273.APCP153.PROD.OUTLOOK.COM>
On Tue, Apr 07, 2020 at 06:10:42PM +0000, Dexuan Cui wrote:
> > From: linux-hyperv-owner@vger.kernel.org
> > <linux-hyperv-owner@vger.kernel.org> On Behalf Of Vitaly Kuznetsov
> > Sent: Tuesday, April 7, 2020 12:28 AM
> > Christoph Hellwig <hch@lst.de> writes:
> >
> > > Hi all,
> > >
> > > The x86 Hyper-V hypercall page (hv_hypercall_pg) is the only allocation
> > > in the kernel using __vmalloc with exectutable persmissions, and the
> > > only user of PAGE_KERNEL_RX. Is there any good reason it needs to
> > > be readable? Otherwise we could use vmalloc_exec and kill off
> > > PAGE_KERNEL_RX. Note that before 372b1e91343e6 ("drivers: hv: Turn
> > off
> > > write permission on the hypercall page") it was even mapped writable..
> >
> > [There is nothing secret in the hypercall page, by reading it you can
> > figure out if you're running on Intel or AMD (VMCALL/VMMCALL) but it's
> > likely not the only possible way :-)]
> >
> > I see no reason for hv_hypercall_pg to remain readable. I just
> > smoke-tested
> >
> > diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
> > index 7581cab74acb..17845db67fe2 100644
> > --- a/arch/x86/hyperv/hv_init.c
> > +++ b/arch/x86/hyperv/hv_init.c
> > @@ -382,7 +382,7 @@ void __init hyperv_init(void)
> > guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0);
> > wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id);
> >
> > - hv_hypercall_pg = __vmalloc(PAGE_SIZE, GFP_KERNEL,
> > PAGE_KERNEL_RX);
> > + hv_hypercall_pg = vmalloc_exec(PAGE_SIZE);
>
> If we try to write into the page, Hyper-V will kill the guest immediately
> by a virtual double-fault (or triple fault?), IIRC.
>
The guest would get injected a #GP fault in that case FWIW. Perhaps
that leads to further double-fault or triple-fault.
Wei.
^ permalink raw reply
* Re: hv_hypercall_pg page permissios
From: Andy Lutomirski @ 2020-04-07 21:01 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Vitaly Kuznetsov, x86, linux-hyperv, linux-kernel,
K. Y. Srinivasan, Stephen Hemminger, Andy Lutomirski,
Peter Zijlstra
In-Reply-To: <20200407073830.GA29279@lst.de>
> On Apr 7, 2020, at 12:38 AM, Christoph Hellwig <hch@lst.de> wrote:
>
> On Tue, Apr 07, 2020 at 09:28:01AM +0200, Vitaly Kuznetsov wrote:
>> Christoph Hellwig <hch@lst.de> writes:
>>
>>> Hi all,
>>>
>>> The x86 Hyper-V hypercall page (hv_hypercall_pg) is the only allocation
>>> in the kernel using __vmalloc with exectutable persmissions, and the
>>> only user of PAGE_KERNEL_RX. Is there any good reason it needs to
>>> be readable? Otherwise we could use vmalloc_exec and kill off
>>> PAGE_KERNEL_RX. Note that before 372b1e91343e6 ("drivers: hv: Turn off
>>> write permission on the hypercall page") it was even mapped writable..
>>
>> [There is nothing secret in the hypercall page, by reading it you can
>> figure out if you're running on Intel or AMD (VMCALL/VMMCALL) but it's
>> likely not the only possible way :-)]
>>
>> I see no reason for hv_hypercall_pg to remain readable. I just
>> smoke-tested
>
> Thanks, I have the same in my WIP tree, but just wanted to confirm this
> makes sense.
Just to make sure we’re all on the same page: x86 doesn’t normally have an execute-only mode. Executable memory in the kernel is readable unless you are using fancy hypervisor-based XO support.
^ permalink raw reply
* [PATCH] Drivers: hv: vmbus: Disallow the freeze PM operation
From: Dexuan Cui @ 2020-04-07 22:01 UTC (permalink / raw)
To: kys, haiyangz, sthemmin, wei.liu, linux-hyperv, linux-kernel,
mikelley, vkuznets
Cc: Dexuan Cui
Before the hibernation patchset (e.g. f53335e3289f), a Linux VM on Hyper-V
can run "echo freeze > /sys/power/state" (or "systemctl suspend")
to freeze the system. The user can press the keyboard or move the mouse
to wake up the VM. Note: the two aforementioned commands are equivalent
here, because Hyper-V doesn't support the guest ACPI S3 state.
With the hibernation patchset, a Linux VM on Hyper-V can hibernate to disk
and resume back; however, the 'freeze' operation is broken for Hyper-V
Generation-2 VM (which doesn't have a legacy keyboard/mouse): when the
vmbus devices are suspended, the VM can not receive any interrupt from
the synthetic keyboard/mouse devices, so there is no way to wake up the
VM. This is not an issue for Generaton-1 VM, because it looks the legacy
keyboard/mouse devices can still be used to wake up the VM in my test.
IMO 'freeze' in a Linux VM on Hyper-V is not really useful in practice,
so let's disallow the operation for both Gen-1 and Gen-2 VMs, even if
it's not an issue for Gen-1 VMs.
Fixes: f53335e3289f ("Drivers: hv: vmbus: Suspend/resume the vmbus itself for hibernation")
Signed-off-by: Dexuan Cui <decui@microsoft.com>
---
drivers/hv/vmbus_drv.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 029378c..82a4327 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -28,6 +28,7 @@
#include <linux/notifier.h>
#include <linux/ptrace.h>
#include <linux/screen_info.h>
+#include <linux/suspend.h>
#include <linux/kdebug.h>
#include <linux/efi.h>
#include <linux/random.h>
@@ -2357,6 +2358,23 @@ static void hv_synic_resume(void)
.resume = hv_synic_resume,
};
+/*
+ * Note: "freeze/suspend" here means "systemctl suspend".
+ * "systemctl hibernate" is still supported.
+ */
+static int hv_pm_notify(struct notifier_block *nb,
+ unsigned long val, void *ign)
+{
+ if (val == PM_SUSPEND_PREPARE) {
+ pr_info("freeze/suspend is not supported\n");
+ return NOTIFY_BAD;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block hv_pm_nb;
+
static int __init hv_acpi_init(void)
{
int ret, t;
@@ -2389,6 +2407,8 @@ static int __init hv_acpi_init(void)
hv_setup_crash_handler(hv_crash_handler);
register_syscore_ops(&hv_synic_syscore_ops);
+ hv_pm_nb.notifier_call = hv_pm_notify;
+ register_pm_notifier(&hv_pm_nb);
return 0;
@@ -2402,6 +2422,7 @@ static void __exit vmbus_exit(void)
{
int cpu;
+ unregister_pm_notifier(&hv_pm_nb);
unregister_syscore_ops(&hv_synic_syscore_ops);
hv_remove_kexec_handler();
--
1.8.3.1
^ permalink raw reply related
* RE: [PATCH 11/11] scsi: storvsc: Re-init stor_chns when a channel interrupt is re-assigned
From: Long Li @ 2020-04-08 2:25 UTC (permalink / raw)
To: Andrea Parri
Cc: linux-kernel@vger.kernel.org, KY Srinivasan, Haiyang Zhang,
Stephen Hemminger, Wei Liu, linux-hyperv@vger.kernel.org,
Michael Kelley, Dexuan Cui, Boqun Feng, vkuznets,
James E.J. Bottomley, Martin K. Petersen,
linux-scsi@vger.kernel.org
In-Reply-To: <20200407003459.GA7776@andrea>
>Subject: Re: [PATCH 11/11] scsi: storvsc: Re-init stor_chns when a channel
>interrupt is re-assigned
>
>> >@@ -621,6 +621,63 @@ static inline struct storvsc_device
>> >*get_in_stor_device(
>> >
>> > }
>> >
>> >+void storvsc_change_target_cpu(struct vmbus_channel *channel, u32
>> >+old,
>> >+u32 new) {
>> >+ struct storvsc_device *stor_device;
>> >+ struct vmbus_channel *cur_chn;
>> >+ bool old_is_alloced = false;
>> >+ struct hv_device *device;
>> >+ unsigned long flags;
>> >+ int cpu;
>> >+
>> >+ device = channel->primary_channel ?
>> >+ channel->primary_channel->device_obj
>> >+ : channel->device_obj;
>> >+ stor_device = get_out_stor_device(device);
>> >+ if (!stor_device)
>> >+ return;
>> >+
>> >+ /* See storvsc_do_io() -> get_og_chn(). */
>> >+ spin_lock_irqsave(&device->channel->lock, flags);
>> >+
>> >+ /*
>> >+ * Determines if the storvsc device has other channels assigned to
>> >+ * the "old" CPU to update the alloced_cpus mask and the stor_chns
>> >+ * array.
>> >+ */
>> >+ if (device->channel != channel && device->channel->target_cpu ==
>> >old) {
>> >+ cur_chn = device->channel;
>> >+ old_is_alloced = true;
>> >+ goto old_is_alloced;
>> >+ }
>> >+ list_for_each_entry(cur_chn, &device->channel->sc_list, sc_list) {
>> >+ if (cur_chn == channel)
>> >+ continue;
>> >+ if (cur_chn->target_cpu == old) {
>> >+ old_is_alloced = true;
>> >+ goto old_is_alloced;
>> >+ }
>> >+ }
>> >+
>> >+old_is_alloced:
>> >+ if (old_is_alloced)
>> >+ WRITE_ONCE(stor_device->stor_chns[old], cur_chn);
>> >+ else
>> >+ cpumask_clear_cpu(old, &stor_device->alloced_cpus);
>>
>> If the old cpu is not allocated, is it still necessary to do a cpumask_clear_cpu?
>
>AFAICT, this really depends on how much we "believe" in the current heuristic
>(as implemented by get_og_chn()): ;-)
>
>The cpumask_clear_cpu() (and the below, dependent "flush" as well) are
>intended to re-initialize alloced_cpus and stor_chns in order for get_og_chn()
>to re-process/update them.
>
>Also, notice that (both in the current code and after this series) alloced_cpus
>can't be offlined and get_og_chn() does rely on this property (cf., e.g., the
>loop/check over alloced_cpus/node_mask).
>
>I suspect that giving up on this invariant/property would require a certain
>amount of re-design in the heuristic/code in question...
>
>
>> >@@ -1360,7 +1432,14 @@ static int storvsc_do_io(struct hv_device
>*device,
>> > }
>> > }
>> > } else {
>> >+ spin_lock_irqsave(&device->channel->lock, flags);
>> >+ outgoing_channel = stor_device->stor_chns[q_num];
>> >+ if (outgoing_channel != NULL) {
>> >+ spin_unlock_irqrestore(&device->channel->lock,
>> >flags);
>>
>> Checking outgoing_channel again seems unnecessary. Why not just call
>get_og_chn()?
>
>target_cpu_store() might have changed stor_chns (and alloced_cpus) in the
>meantime (but before we've acquired the device's lock): the double check is
>to make sure we have a "consistent"/an up-to-date view of stor_chns and
>alloced_cpus.
>
>
>>
>> >+ goto found_channel;
>> >+ }
>> > outgoing_channel = get_og_chn(stor_device, q_num);
>> >+ spin_unlock_irqrestore(&device->channel->lock, flags);
>> > }
>>
>> With device->channel->lock, now we have one more lock on the I/O issuing
>path. It doesn't seem optimal as you are trying to protect the code in
>storvsc_change_target_cpu(), this doesn't need to block concurrent I/O
>issuers. Maybe moving to RCU is a better approach?
>
>I don't see this as a problem (*and I've validated such conclusion in
>experiments, where the "patched kernel" was sometimes performing slighlty
>better than the "unpatched kernel" and sometimes slightly
>worse...):
>
>On the one hand, the stor_chns array "stabilizes" quite early after system
>initialization in "normal" (i.e., common) situations (i.e., no channel
>reassignments, no device hotplugs...); IOW, get_og_chn() really represents
>the "rare and slow" path here (but not that slow!
>after all...). Furthermore, notice that even in those "rare cases"
>the number of "contending" channels is limited to at most 1 per 4 CPUs IIRC
>(alloced_cpus is "sparsely populated"...).
Yes I realized it is on the slow path. There is no need to optimize locks.
Reviewed-by; Long Li <longli@microsoft.com>
>
>The latencies of the RCU grace period (in the order of milliseconds) would be a
>major concern for the adoption of RCU here (at least, if we continue to
>consider get_og_chn() as an "updater"). I'm afraid that this could be "too
>slow" even for our slow path... ;-/
>
>What am I missing? ;-)
>
>Thanks,
> Andrea
^ permalink raw reply
* [PATCH 02/28] staging: android: ion: use vmap instead of vm_map_ram
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
vm_map_ram can keep mappings around after the vm_unmap_ram. Using that
with non-PAGE_KERNEL mappings can lead to all kinds of aliasing issues.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/staging/android/ion/ion_heap.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c
index 473b465724f1..a2d5c6df4b96 100644
--- a/drivers/staging/android/ion/ion_heap.c
+++ b/drivers/staging/android/ion/ion_heap.c
@@ -99,12 +99,12 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot)
{
- void *addr = vm_map_ram(pages, num, -1, pgprot);
+ void *addr = vmap(pages, num, VM_MAP);
if (!addr)
return -ENOMEM;
memset(addr, 0, PAGE_SIZE * num);
- vm_unmap_ram(addr, num);
+ vunmap(addr);
return 0;
}
--
2.25.1
^ permalink raw reply related
* [PATCH 03/28] staging: media: ipu3: use vmap insted of reimplementing it
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
Just use vmap instead of messing with vmalloc internals.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/staging/media/ipu3/ipu3-css-pool.h | 4 +--
drivers/staging/media/ipu3/ipu3-dmamap.c | 30 ++++++----------------
2 files changed, 9 insertions(+), 25 deletions(-)
diff --git a/drivers/staging/media/ipu3/ipu3-css-pool.h b/drivers/staging/media/ipu3/ipu3-css-pool.h
index f4a60b41401b..a8ccd4f70320 100644
--- a/drivers/staging/media/ipu3/ipu3-css-pool.h
+++ b/drivers/staging/media/ipu3/ipu3-css-pool.h
@@ -15,14 +15,12 @@ struct imgu_device;
* @size: size of the buffer in bytes.
* @vaddr: kernel virtual address.
* @daddr: iova dma address to access IPU3.
- * @vma: private, a pointer to &struct vm_struct,
- * used for imgu_dmamap_free.
*/
struct imgu_css_map {
size_t size;
void *vaddr;
dma_addr_t daddr;
- struct vm_struct *vma;
+ struct page **pages;
};
/**
diff --git a/drivers/staging/media/ipu3/ipu3-dmamap.c b/drivers/staging/media/ipu3/ipu3-dmamap.c
index 7431322379f6..8a19b0024152 100644
--- a/drivers/staging/media/ipu3/ipu3-dmamap.c
+++ b/drivers/staging/media/ipu3/ipu3-dmamap.c
@@ -96,6 +96,7 @@ void *imgu_dmamap_alloc(struct imgu_device *imgu, struct imgu_css_map *map,
unsigned long shift = iova_shift(&imgu->iova_domain);
struct device *dev = &imgu->pci_dev->dev;
size_t size = PAGE_ALIGN(len);
+ int count = size >> PAGE_SHIFT;
struct page **pages;
dma_addr_t iovaddr;
struct iova *iova;
@@ -114,7 +115,7 @@ void *imgu_dmamap_alloc(struct imgu_device *imgu, struct imgu_css_map *map,
/* Call IOMMU driver to setup pgt */
iovaddr = iova_dma_addr(&imgu->iova_domain, iova);
- for (i = 0; i < size / PAGE_SIZE; ++i) {
+ for (i = 0; i < count; ++i) {
rval = imgu_mmu_map(imgu->mmu, iovaddr,
page_to_phys(pages[i]), PAGE_SIZE);
if (rval)
@@ -123,33 +124,23 @@ void *imgu_dmamap_alloc(struct imgu_device *imgu, struct imgu_css_map *map,
iovaddr += PAGE_SIZE;
}
- /* Now grab a virtual region */
- map->vma = __get_vm_area(size, VM_USERMAP, VMALLOC_START, VMALLOC_END);
- if (!map->vma)
+ map->vaddr = vmap(pages, count, VM_USERMAP, PAGE_KERNEL);
+ if (!map->vaddr)
goto out_unmap;
- map->vma->pages = pages;
- /* And map it in KVA */
- if (map_vm_area(map->vma, PAGE_KERNEL, pages))
- goto out_vunmap;
-
+ map->pages = pages;
map->size = size;
map->daddr = iova_dma_addr(&imgu->iova_domain, iova);
- map->vaddr = map->vma->addr;
dev_dbg(dev, "%s: allocated %zu @ IOVA %pad @ VA %p\n", __func__,
- size, &map->daddr, map->vma->addr);
-
- return map->vma->addr;
+ size, &map->daddr, map->vaddr);
-out_vunmap:
- vunmap(map->vma->addr);
+ return map->vaddr;
out_unmap:
imgu_dmamap_free_buffer(pages, size);
imgu_mmu_unmap(imgu->mmu, iova_dma_addr(&imgu->iova_domain, iova),
i * PAGE_SIZE);
- map->vma = NULL;
out_free_iova:
__free_iova(&imgu->iova_domain, iova);
@@ -177,8 +168,6 @@ void imgu_dmamap_unmap(struct imgu_device *imgu, struct imgu_css_map *map)
*/
void imgu_dmamap_free(struct imgu_device *imgu, struct imgu_css_map *map)
{
- struct vm_struct *area = map->vma;
-
dev_dbg(&imgu->pci_dev->dev, "%s: freeing %zu @ IOVA %pad @ VA %p\n",
__func__, map->size, &map->daddr, map->vaddr);
@@ -187,11 +176,8 @@ void imgu_dmamap_free(struct imgu_device *imgu, struct imgu_css_map *map)
imgu_dmamap_unmap(imgu, map);
- if (WARN_ON(!area) || WARN_ON(!area->pages))
- return;
-
- imgu_dmamap_free_buffer(area->pages, map->size);
vunmap(map->vaddr);
+ imgu_dmamap_free_buffer(map->pages, map->size);
map->vaddr = NULL;
}
--
2.25.1
^ permalink raw reply related
* [PATCH 04/28] dma-mapping: use vmap insted of reimplementing it
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
Replace the open coded instance of vmap with the actual function. In
the non-contiguous (IOMMU) case this requires an extra find_vm_area,
but given that this isn't a fast path function that is a small price
to pay.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
kernel/dma/remap.c | 48 ++++++++++++----------------------------------
1 file changed, 12 insertions(+), 36 deletions(-)
diff --git a/kernel/dma/remap.c b/kernel/dma/remap.c
index d14cbc83986a..7a8ba60951e8 100644
--- a/kernel/dma/remap.c
+++ b/kernel/dma/remap.c
@@ -20,23 +20,6 @@ struct page **dma_common_find_pages(void *cpu_addr)
return area->pages;
}
-static struct vm_struct *__dma_common_pages_remap(struct page **pages,
- size_t size, pgprot_t prot, const void *caller)
-{
- struct vm_struct *area;
-
- area = get_vm_area_caller(size, VM_DMA_COHERENT, caller);
- if (!area)
- return NULL;
-
- if (map_vm_area(area, prot, pages)) {
- vunmap(area->addr);
- return NULL;
- }
-
- return area;
-}
-
/*
* Remaps an array of PAGE_SIZE pages into another vm_area.
* Cannot be used in non-sleeping contexts
@@ -44,15 +27,12 @@ static struct vm_struct *__dma_common_pages_remap(struct page **pages,
void *dma_common_pages_remap(struct page **pages, size_t size,
pgprot_t prot, const void *caller)
{
- struct vm_struct *area;
+ void *vaddr;
- area = __dma_common_pages_remap(pages, size, prot, caller);
- if (!area)
- return NULL;
-
- area->pages = pages;
-
- return area->addr;
+ vaddr = vmap(pages, count, VM_DMA_COHERENT, prot);
+ if (vaddr)
+ find_vm_area(vaddr)->pages = pages;
+ return vaddr;
}
/*
@@ -62,24 +42,20 @@ void *dma_common_pages_remap(struct page **pages, size_t size,
void *dma_common_contiguous_remap(struct page *page, size_t size,
pgprot_t prot, const void *caller)
{
- int i;
+ int count = size >> PAGE_SHIFT;
struct page **pages;
- struct vm_struct *area;
+ void *vaddr;
+ int i;
- pages = kmalloc(sizeof(struct page *) << get_order(size), GFP_KERNEL);
+ pages = kmalloc_array(count, sizeof(struct page *), GFP_KERNEL);
if (!pages)
return NULL;
-
- for (i = 0; i < (size >> PAGE_SHIFT); i++)
+ for (i = 0; i < count; i++)
pages[i] = nth_page(page, i);
-
- area = __dma_common_pages_remap(pages, size, prot, caller);
-
+ vaddr = vmap(pages, count, VM_DMA_COHERENT, prot);
kfree(pages);
- if (!area)
- return NULL;
- return area->addr;
+ return vaddr;
}
/*
--
2.25.1
^ permalink raw reply related
* [PATCH 01/28] x86/hyperv: use vmalloc_exec for the hypercall page
From: Christoph Hellwig @ 2020-04-08 11:58 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
Use the designated helper for allocating executable kernel memory, and
remove the now unused PAGE_KERNEL_RX define.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
arch/x86/hyperv/hv_init.c | 2 +-
arch/x86/include/asm/pgtable_types.h | 2 --
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c
index b0da5320bcff..5a4b363ba67b 100644
--- a/arch/x86/hyperv/hv_init.c
+++ b/arch/x86/hyperv/hv_init.c
@@ -355,7 +355,7 @@ void __init hyperv_init(void)
guest_id = generate_guest_id(0, LINUX_VERSION_CODE, 0);
wrmsrl(HV_X64_MSR_GUEST_OS_ID, guest_id);
- hv_hypercall_pg = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX);
+ hv_hypercall_pg = vmalloc_exec(PAGE_SIZE);
if (hv_hypercall_pg == NULL) {
wrmsrl(HV_X64_MSR_GUEST_OS_ID, 0);
goto remove_cpuhp_state;
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index b6606fe6cfdf..947867f112ea 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -194,7 +194,6 @@ enum page_cache_mode {
#define _PAGE_TABLE_NOENC (__PP|__RW|_USR|___A| 0|___D| 0| 0)
#define _PAGE_TABLE (__PP|__RW|_USR|___A| 0|___D| 0| 0| _ENC)
#define __PAGE_KERNEL_RO (__PP| 0| 0|___A|__NX|___D| 0|___G)
-#define __PAGE_KERNEL_RX (__PP| 0| 0|___A| 0|___D| 0|___G)
#define __PAGE_KERNEL_NOCACHE (__PP|__RW| 0|___A|__NX|___D| 0|___G| __NC)
#define __PAGE_KERNEL_VVAR (__PP| 0|_USR|___A|__NX|___D| 0|___G)
#define __PAGE_KERNEL_LARGE (__PP|__RW| 0|___A|__NX|___D|_PSE|___G)
@@ -220,7 +219,6 @@ enum page_cache_mode {
#define PAGE_KERNEL_RO __pgprot_mask(__PAGE_KERNEL_RO | _ENC)
#define PAGE_KERNEL_EXEC __pgprot_mask(__PAGE_KERNEL_EXEC | _ENC)
#define PAGE_KERNEL_EXEC_NOENC __pgprot_mask(__PAGE_KERNEL_EXEC | 0)
-#define PAGE_KERNEL_RX __pgprot_mask(__PAGE_KERNEL_RX | _ENC)
#define PAGE_KERNEL_NOCACHE __pgprot_mask(__PAGE_KERNEL_NOCACHE | _ENC)
#define PAGE_KERNEL_LARGE __pgprot_mask(__PAGE_KERNEL_LARGE | _ENC)
#define PAGE_KERNEL_LARGE_EXEC __pgprot_mask(__PAGE_KERNEL_LARGE_EXEC | _ENC)
--
2.25.1
^ permalink raw reply related
* decruft the vmalloc API
From: Christoph Hellwig @ 2020-04-08 11:58 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
Hi all,
Peter noticed that with some dumb luck you can toast the kernel address
space with exported vmalloc symbols.
I used this as an opportunity to decruft the vmalloc.c API and make it
much more systematic. This also removes any chance to create vmalloc
mappings outside the designated areas or using executable permissions
from modules. Besides that it removes more than 300 lines of code.
A git tree is also available here:
git://git.infradead.org/users/hch/misc.git sanitize-vmalloc-api
Gitweb:
http://git.infradead.org/users/hch/misc.git/shortlog/refs/heads/sanitize-vmalloc-api
^ permalink raw reply
* [PATCH 06/28] powerpc: remove __ioremap_at and __iounmap_at
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
These helpers are only used for remapping the ISA I/O base. Replace
the mapping side with a remap_isa_range helper in isa-bridge.c that
hard codes all the known arguments, and just remove __iounmap_at in
favour of open coding it in the only caller.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
arch/powerpc/include/asm/io.h | 8 -----
arch/powerpc/kernel/isa-bridge.c | 28 +++++++++++++-----
arch/powerpc/mm/ioremap_64.c | 50 --------------------------------
3 files changed, 21 insertions(+), 65 deletions(-)
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 71f1c5d69839..4fdbb9e45dd7 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -699,10 +699,6 @@ static inline void iosync(void)
*
* * iounmap undoes such a mapping and can be hooked
*
- * * __ioremap_at (and the pending __iounmap_at) are low level functions to
- * create hand-made mappings for use only by the PCI code and cannot
- * currently be hooked. Must be page aligned.
- *
* * __ioremap_caller is the same as above but takes an explicit caller
* reference rather than using __builtin_return_address(0)
*
@@ -729,10 +725,6 @@ void __iomem *do_ioremap(phys_addr_t pa, phys_addr_t offset, unsigned long size,
extern void __iomem *__ioremap_caller(phys_addr_t, unsigned long size,
pgprot_t prot, void *caller);
-extern void __iomem * __ioremap_at(phys_addr_t pa, void *ea,
- unsigned long size, pgprot_t prot);
-extern void __iounmap_at(void *ea, unsigned long size);
-
/*
* When CONFIG_PPC_INDIRECT_PIO is set, we use the generic iomap implementation
* which needs some additional definitions here. They basically allow PIO
diff --git a/arch/powerpc/kernel/isa-bridge.c b/arch/powerpc/kernel/isa-bridge.c
index 773671b512df..2257d24e6a26 100644
--- a/arch/powerpc/kernel/isa-bridge.c
+++ b/arch/powerpc/kernel/isa-bridge.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/notifier.h>
+#include <linux/vmalloc.h>
#include <asm/processor.h>
#include <asm/io.h>
@@ -38,6 +39,22 @@ EXPORT_SYMBOL_GPL(isa_bridge_pcidev);
#define ISA_SPACE_MASK 0x1
#define ISA_SPACE_IO 0x1
+static void remap_isa_base(phys_addr_t pa, unsigned long size)
+{
+ WARN_ON_ONCE(ISA_IO_BASE & ~PAGE_MASK);
+ WARN_ON_ONCE(pa & ~PAGE_MASK);
+ WARN_ON_ONCE(size & ~PAGE_MASK);
+
+ if (slab_is_available()) {
+ if (ioremap_page_range(ISA_IO_BASE, ISA_IO_BASE + size, pa,
+ pgprot_noncached(PAGE_KERNEL)))
+ unmap_kernel_range(ISA_IO_BASE, size);
+ } else {
+ early_ioremap_range(ISA_IO_BASE, pa, size,
+ pgprot_noncached(PAGE_KERNEL));
+ }
+}
+
static void pci_process_ISA_OF_ranges(struct device_node *isa_node,
unsigned long phb_io_base_phys)
{
@@ -105,15 +122,13 @@ static void pci_process_ISA_OF_ranges(struct device_node *isa_node,
if (size > 0x10000)
size = 0x10000;
- __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
- size, pgprot_noncached(PAGE_KERNEL));
+ remap_isa_base(phb_io_base_phys, size);
return;
inval_range:
printk(KERN_ERR "no ISA IO ranges or unexpected isa range, "
"mapping 64k\n");
- __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
- 0x10000, pgprot_noncached(PAGE_KERNEL));
+ remap_isa_base(phb_io_base_phys, 0x10000);
}
@@ -248,8 +263,7 @@ void __init isa_bridge_init_non_pci(struct device_node *np)
* and map it
*/
isa_io_base = ISA_IO_BASE;
- __ioremap_at(pbase, (void *)ISA_IO_BASE,
- size, pgprot_noncached(PAGE_KERNEL));
+ remap_isa_base(pbase, size);
pr_debug("ISA: Non-PCI bridge is %pOF\n", np);
}
@@ -297,7 +311,7 @@ static void isa_bridge_remove(void)
isa_bridge_pcidev = NULL;
/* Unmap the ISA area */
- __iounmap_at((void *)ISA_IO_BASE, 0x10000);
+ unmap_kernel_range(ISA_IO_BASE, 0x10000);
}
/**
diff --git a/arch/powerpc/mm/ioremap_64.c b/arch/powerpc/mm/ioremap_64.c
index 50a99d9684f7..ba5cbb0d66bd 100644
--- a/arch/powerpc/mm/ioremap_64.c
+++ b/arch/powerpc/mm/ioremap_64.c
@@ -4,56 +4,6 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
-/**
- * Low level function to establish the page tables for an IO mapping
- */
-void __iomem *__ioremap_at(phys_addr_t pa, void *ea, unsigned long size, pgprot_t prot)
-{
- int ret;
- unsigned long va = (unsigned long)ea;
-
- /* We don't support the 4K PFN hack with ioremap */
- if (pgprot_val(prot) & H_PAGE_4K_PFN)
- return NULL;
-
- if ((ea + size) >= (void *)IOREMAP_END) {
- pr_warn("Outside the supported range\n");
- return NULL;
- }
-
- WARN_ON(pa & ~PAGE_MASK);
- WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
- WARN_ON(size & ~PAGE_MASK);
-
- if (slab_is_available()) {
- ret = ioremap_page_range(va, va + size, pa, prot);
- if (ret)
- unmap_kernel_range(va, size);
- } else {
- ret = early_ioremap_range(va, pa, size, prot);
- }
-
- if (ret)
- return NULL;
-
- return (void __iomem *)ea;
-}
-EXPORT_SYMBOL(__ioremap_at);
-
-/**
- * Low level function to tear down the page tables for an IO mapping. This is
- * used for mappings that are manipulated manually, like partial unmapping of
- * PCI IOs or ISA space.
- */
-void __iounmap_at(void *ea, unsigned long size)
-{
- WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
- WARN_ON(size & ~PAGE_MASK);
-
- unmap_kernel_range((unsigned long)ea, size);
-}
-EXPORT_SYMBOL(__iounmap_at);
-
void __iomem *__ioremap_caller(phys_addr_t addr, unsigned long size,
pgprot_t prot, void *caller)
{
--
2.25.1
^ permalink raw reply related
* [PATCH 05/28] powerpc: add an ioremap_phb helper
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
Factor code shared between pci_64 and electra_cf into a ioremap_pbh
helper that follows the normal ioremap semantics, and returns a
useful __iomem pointer. Note that it opencodes __ioremap_at as
we know from the callers the slab is available. Switch pci_64
to also store the result as __iomem pointer, and unmap the result
using iounmap instead of force casting and using vmalloc APIs.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
arch/powerpc/include/asm/io.h | 2 +
arch/powerpc/include/asm/pci-bridge.h | 2 +-
arch/powerpc/kernel/pci_64.c | 53 ++++++++++++++++++---------
drivers/pcmcia/electra_cf.c | 45 ++++++++---------------
4 files changed, 54 insertions(+), 48 deletions(-)
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 635969b5b58e..71f1c5d69839 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -719,6 +719,8 @@ void __iomem *ioremap_coherent(phys_addr_t address, unsigned long size);
extern void iounmap(volatile void __iomem *addr);
+void __iomem *ioremap_pbh(phys_addr_t paddr, unsigned long size);
+
int early_ioremap_range(unsigned long ea, phys_addr_t pa,
unsigned long size, pgprot_t prot);
void __iomem *do_ioremap(phys_addr_t pa, phys_addr_t offset, unsigned long size,
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
index 69f4cb3b7c56..b92e81b256e5 100644
--- a/arch/powerpc/include/asm/pci-bridge.h
+++ b/arch/powerpc/include/asm/pci-bridge.h
@@ -66,7 +66,7 @@ struct pci_controller {
void __iomem *io_base_virt;
#ifdef CONFIG_PPC64
- void *io_base_alloc;
+ void __iomem *io_base_alloc;
#endif
resource_size_t io_base_phys;
resource_size_t pci_io_size;
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index f83d1f69b1dd..8e86bd9c1eca 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -109,23 +109,46 @@ int pcibios_unmap_io_space(struct pci_bus *bus)
/* Get the host bridge */
hose = pci_bus_to_host(bus);
- /* Check if we have IOs allocated */
- if (hose->io_base_alloc == NULL)
- return 0;
-
pr_debug("IO unmapping for PHB %pOF\n", hose->dn);
pr_debug(" alloc=0x%p\n", hose->io_base_alloc);
- /* This is a PHB, we fully unmap the IO area */
- vunmap(hose->io_base_alloc);
-
+ iounmap(hose->io_base_alloc);
return 0;
}
EXPORT_SYMBOL_GPL(pcibios_unmap_io_space);
-static int pcibios_map_phb_io_space(struct pci_controller *hose)
+void __iomem *ioremap_pbh(phys_addr_t paddr, unsigned long size)
{
struct vm_struct *area;
+ unsigned long addr;
+
+ WARN_ON_ONCE(paddr & ~PAGE_MASK);
+ WARN_ON_ONCE(size & ~PAGE_MASK);
+
+ /*
+ * Let's allocate some IO space for that guy. We don't pass VM_IOREMAP
+ * because we don't care about alignment tricks that the core does in
+ * that case. Maybe we should due to stupid card with incomplete
+ * address decoding but I'd rather not deal with those outside of the
+ * reserved 64K legacy region.
+ */
+ area = __get_vm_area(size, 0, PHB_IO_BASE, PHB_IO_END);
+ if (!area)
+ return NULL;
+
+ addr = (unsigned long)area->addr;
+ if (ioremap_page_range(addr, addr + size, paddr,
+ pgprot_noncached(PAGE_KERNEL))) {
+ unmap_kernel_range(addr, size);
+ return NULL;
+ }
+
+ return (void __iomem *)addr;
+}
+EXPORT_SYMBOL_GPL(ioremap_pbh);
+
+static int pcibios_map_phb_io_space(struct pci_controller *hose)
+{
unsigned long phys_page;
unsigned long size_page;
unsigned long io_virt_offset;
@@ -146,12 +169,11 @@ static int pcibios_map_phb_io_space(struct pci_controller *hose)
* with incomplete address decoding but I'd rather not deal with
* those outside of the reserved 64K legacy region.
*/
- area = __get_vm_area(size_page, 0, PHB_IO_BASE, PHB_IO_END);
- if (area == NULL)
+ hose->io_base_alloc = ioremap_pbh(phys_page, size_page);
+ if (!hose->io_base_alloc)
return -ENOMEM;
- hose->io_base_alloc = area->addr;
- hose->io_base_virt = (void __iomem *)(area->addr +
- hose->io_base_phys - phys_page);
+ hose->io_base_virt = hose->io_base_alloc +
+ hose->io_base_phys - phys_page;
pr_debug("IO mapping for PHB %pOF\n", hose->dn);
pr_debug(" phys=0x%016llx, virt=0x%p (alloc=0x%p)\n",
@@ -159,11 +181,6 @@ static int pcibios_map_phb_io_space(struct pci_controller *hose)
pr_debug(" size=0x%016llx (alloc=0x%016lx)\n",
hose->pci_io_size, size_page);
- /* Establish the mapping */
- if (__ioremap_at(phys_page, area->addr, size_page,
- pgprot_noncached(PAGE_KERNEL)) == NULL)
- return -ENOMEM;
-
/* Fixup hose IO resource */
io_virt_offset = pcibios_io_space_offset(hose);
hose->io_resource.start += io_virt_offset;
diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c
index f2741c04289d..77b229f8d218 100644
--- a/drivers/pcmcia/electra_cf.c
+++ b/drivers/pcmcia/electra_cf.c
@@ -178,10 +178,9 @@ static int electra_cf_probe(struct platform_device *ofdev)
struct device_node *np = ofdev->dev.of_node;
struct electra_cf_socket *cf;
struct resource mem, io;
- int status;
+ int status = -ENOMEM;
const unsigned int *prop;
int err;
- struct vm_struct *area;
err = of_address_to_resource(np, 0, &mem);
if (err)
@@ -202,30 +201,19 @@ static int electra_cf_probe(struct platform_device *ofdev)
cf->mem_phys = mem.start;
cf->mem_size = PAGE_ALIGN(resource_size(&mem));
cf->mem_base = ioremap(cf->mem_phys, cf->mem_size);
+ if (!cf->mem_base)
+ goto out_free_cf;
cf->io_size = PAGE_ALIGN(resource_size(&io));
-
- area = __get_vm_area(cf->io_size, 0, PHB_IO_BASE, PHB_IO_END);
- if (area == NULL) {
- status = -ENOMEM;
- goto fail1;
- }
-
- cf->io_virt = (void __iomem *)(area->addr);
+ cf->io_virt = ioremap_pbh(io.start, cf->io_size);
+ if (!cf->io_virt)
+ goto out_unmap_mem;
cf->gpio_base = ioremap(0xfc103000, 0x1000);
+ if (!cf->gpio_base)
+ goto out_unmap_virt;
dev_set_drvdata(device, cf);
- if (!cf->mem_base || !cf->io_virt || !cf->gpio_base ||
- (__ioremap_at(io.start, cf->io_virt, cf->io_size,
- pgprot_noncached(PAGE_KERNEL)) == NULL)) {
- dev_err(device, "can't ioremap ranges\n");
- status = -ENOMEM;
- goto fail1;
- }
-
-
cf->io_base = (unsigned long)cf->io_virt - VMALLOC_END;
-
cf->iomem.start = (unsigned long)cf->mem_base;
cf->iomem.end = (unsigned long)cf->mem_base + (mem.end - mem.start);
cf->iomem.flags = IORESOURCE_MEM;
@@ -305,14 +293,13 @@ static int electra_cf_probe(struct platform_device *ofdev)
if (cf->irq)
free_irq(cf->irq, cf);
- if (cf->io_virt)
- __iounmap_at(cf->io_virt, cf->io_size);
- if (cf->mem_base)
- iounmap(cf->mem_base);
- if (cf->gpio_base)
- iounmap(cf->gpio_base);
- if (area)
- device_init_wakeup(&ofdev->dev, 0);
+ iounmap(cf->gpio_base);
+out_unmap_virt:
+ device_init_wakeup(&ofdev->dev, 0);
+ iounmap(cf->io_virt);
+out_unmap_mem:
+ iounmap(cf->mem_base);
+out_free_cf:
kfree(cf);
return status;
@@ -330,7 +317,7 @@ static int electra_cf_remove(struct platform_device *ofdev)
free_irq(cf->irq, cf);
del_timer_sync(&cf->timer);
- __iounmap_at(cf->io_virt, cf->io_size);
+ iounmap(cf->io_virt);
iounmap(cf->mem_base);
iounmap(cf->gpio_base);
release_mem_region(cf->mem_phys, cf->mem_size);
--
2.25.1
^ permalink raw reply related
* [PATCH 08/28] mm: unexport unmap_kernel_range_noflush
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
There are no modular users of this function.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
mm/vmalloc.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index d1534d610b48..3375f9508ef6 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2029,7 +2029,6 @@ void unmap_kernel_range_noflush(unsigned long addr, unsigned long size)
{
vunmap_page_range(addr, addr + size);
}
-EXPORT_SYMBOL_GPL(unmap_kernel_range_noflush);
/**
* unmap_kernel_range - unmap kernel VM area and flush cache and TLB
--
2.25.1
^ permalink raw reply related
* [PATCH 07/28] mm: remove __get_vm_area
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
Switch the two remaining callers to use __get_vm_area_caller instead.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
arch/powerpc/kernel/pci_64.c | 3 ++-
arch/sh/kernel/cpu/sh4/sq.c | 3 ++-
include/linux/vmalloc.h | 2 --
mm/vmalloc.c | 8 --------
4 files changed, 4 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 8e86bd9c1eca..155e2ef60053 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -132,7 +132,8 @@ void __iomem *ioremap_pbh(phys_addr_t paddr, unsigned long size)
* address decoding but I'd rather not deal with those outside of the
* reserved 64K legacy region.
*/
- area = __get_vm_area(size, 0, PHB_IO_BASE, PHB_IO_END);
+ area = __get_vm_area_caller(size, 0, PHB_IO_BASE, PHB_IO_END,
+ __builtin_return_address(0));
if (!area)
return NULL;
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index 934ff84844fa..d432164b23b7 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -103,7 +103,8 @@ static int __sq_remap(struct sq_mapping *map, pgprot_t prot)
#if defined(CONFIG_MMU)
struct vm_struct *vma;
- vma = __get_vm_area(map->size, VM_ALLOC, map->sq_addr, SQ_ADDRMAX);
+ vma = __get_vm_area_caller(map->size, VM_ALLOC, map->sq_addr,
+ SQ_ADDRMAX, __builtin_return_address(0));
if (!vma)
return -ENOMEM;
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 0507a162ccd0..3070b4dbc2d9 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -161,8 +161,6 @@ static inline size_t get_vm_area_size(const struct vm_struct *area)
extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
extern struct vm_struct *get_vm_area_caller(unsigned long size,
unsigned long flags, const void *caller);
-extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
- unsigned long start, unsigned long end);
extern struct vm_struct *__get_vm_area_caller(unsigned long size,
unsigned long flags,
unsigned long start, unsigned long end,
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 399f219544f7..d1534d610b48 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2127,14 +2127,6 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,
return area;
}
-struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
- unsigned long start, unsigned long end)
-{
- return __get_vm_area_node(size, 1, flags, start, end, NUMA_NO_NODE,
- GFP_KERNEL, __builtin_return_address(0));
-}
-EXPORT_SYMBOL_GPL(__get_vm_area);
-
struct vm_struct *__get_vm_area_caller(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end,
const void *caller)
--
2.25.1
^ permalink raw reply related
* [PATCH 12/28] mm: remove vmap_page_range_noflush and vunmap_page_range
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
These have non-static aliases claled map_kernel_range_noflush and
unmap_kernel_range_noflush that just differ slightly in the calling
conventions that pass addr + size instead of an end.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
mm/vmalloc.c | 98 +++++++++++++++++++++-------------------------------
1 file changed, 40 insertions(+), 58 deletions(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index aada9e9144bd..55df5dc6a9fc 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -127,10 +127,24 @@ static void vunmap_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end)
} while (p4d++, addr = next, addr != end);
}
-static void vunmap_page_range(unsigned long addr, unsigned long end)
+/**
+ * unmap_kernel_range_noflush - unmap kernel VM area
+ * @addr: start of the VM area to unmap
+ * @size: size of the VM area to unmap
+ *
+ * Unmap PFN_UP(@size) pages at @addr. The VM area @addr and @size specify
+ * should have been allocated using get_vm_area() and its friends.
+ *
+ * NOTE:
+ * This function does NOT do any cache flushing. The caller is responsible
+ * for calling flush_cache_vunmap() on to-be-mapped areas before calling this
+ * function and flush_tlb_kernel_range() after.
+ */
+void unmap_kernel_range_noflush(unsigned long addr, unsigned long size)
{
- pgd_t *pgd;
+ unsigned long end = addr + size;
unsigned long next;
+ pgd_t *pgd;
BUG_ON(addr >= end);
pgd = pgd_offset_k(addr);
@@ -219,18 +233,30 @@ static int vmap_p4d_range(pgd_t *pgd, unsigned long addr,
return 0;
}
-/*
- * Set up page tables in kva (addr, end). The ptes shall have prot "prot", and
- * will have pfns corresponding to the "pages" array.
+/**
+ * map_kernel_range_noflush - map kernel VM area with the specified pages
+ * @addr: start of the VM area to map
+ * @size: size of the VM area to map
+ * @prot: page protection flags to use
+ * @pages: pages to map
*
- * Ie. pte at addr+N*PAGE_SIZE shall point to pfn corresponding to pages[N]
+ * Map PFN_UP(@size) pages at @addr. The VM area @addr and @size specify should
+ * have been allocated using get_vm_area() and its friends.
+ *
+ * NOTE:
+ * This function does NOT do any cache flushing. The caller is responsible for
+ * calling flush_cache_vmap() on to-be-mapped areas before calling this
+ * function.
+ *
+ * RETURNS:
+ * The number of pages mapped on success, -errno on failure.
*/
-static int vmap_page_range_noflush(unsigned long start, unsigned long end,
- pgprot_t prot, struct page **pages)
+int map_kernel_range_noflush(unsigned long addr, unsigned long size,
+ pgprot_t prot, struct page **pages)
{
- pgd_t *pgd;
+ unsigned long end = addr + size;
unsigned long next;
- unsigned long addr = start;
+ pgd_t *pgd;
int err = 0;
int nr = 0;
@@ -251,7 +277,7 @@ static int vmap_page_range(unsigned long start, unsigned long end,
{
int ret;
- ret = vmap_page_range_noflush(start, end, prot, pages);
+ ret = map_kernel_range_noflush(start, end - start, prot, pages);
flush_cache_vmap(start, end);
return ret;
}
@@ -1226,7 +1252,7 @@ EXPORT_SYMBOL_GPL(unregister_vmap_purge_notifier);
*/
static void unmap_vmap_area(struct vmap_area *va)
{
- vunmap_page_range(va->va_start, va->va_end);
+ unmap_kernel_range_noflush(va->va_start, va->va_end - va->va_start);
}
/*
@@ -1686,7 +1712,7 @@ static void vb_free(unsigned long addr, unsigned long size)
rcu_read_unlock();
BUG_ON(!vb);
- vunmap_page_range(addr, addr + size);
+ unmap_kernel_range_noflush(addr, size);
if (debug_pagealloc_enabled_static())
flush_tlb_kernel_range(addr, addr + size);
@@ -1984,50 +2010,6 @@ void __init vmalloc_init(void)
vmap_initialized = true;
}
-/**
- * map_kernel_range_noflush - map kernel VM area with the specified pages
- * @addr: start of the VM area to map
- * @size: size of the VM area to map
- * @prot: page protection flags to use
- * @pages: pages to map
- *
- * Map PFN_UP(@size) pages at @addr. The VM area @addr and @size
- * specify should have been allocated using get_vm_area() and its
- * friends.
- *
- * NOTE:
- * This function does NOT do any cache flushing. The caller is
- * responsible for calling flush_cache_vmap() on to-be-mapped areas
- * before calling this function.
- *
- * RETURNS:
- * The number of pages mapped on success, -errno on failure.
- */
-int map_kernel_range_noflush(unsigned long addr, unsigned long size,
- pgprot_t prot, struct page **pages)
-{
- return vmap_page_range_noflush(addr, addr + size, prot, pages);
-}
-
-/**
- * unmap_kernel_range_noflush - unmap kernel VM area
- * @addr: start of the VM area to unmap
- * @size: size of the VM area to unmap
- *
- * Unmap PFN_UP(@size) pages at @addr. The VM area @addr and @size
- * specify should have been allocated using get_vm_area() and its
- * friends.
- *
- * NOTE:
- * This function does NOT do any cache flushing. The caller is
- * responsible for calling flush_cache_vunmap() on to-be-mapped areas
- * before calling this function and flush_tlb_kernel_range() after.
- */
-void unmap_kernel_range_noflush(unsigned long addr, unsigned long size)
-{
- vunmap_page_range(addr, addr + size);
-}
-
/**
* unmap_kernel_range - unmap kernel VM area and flush cache and TLB
* @addr: start of the VM area to unmap
@@ -2041,7 +2023,7 @@ void unmap_kernel_range(unsigned long addr, unsigned long size)
unsigned long end = addr + size;
flush_cache_vunmap(addr, end);
- vunmap_page_range(addr, end);
+ unmap_kernel_range_noflush(addr, size);
flush_tlb_kernel_range(addr, end);
}
--
2.25.1
^ permalink raw reply related
* [PATCH 11/28] mm: pass addr as unsigned long to vb_free
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
Ever use of addr in vb_free casts to unsigned long first, and the caller
has an unsigned long version of the address available anyway. Just pass
that and avoid all the casts.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
mm/vmalloc.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 9183fc0d365a..aada9e9144bd 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1664,7 +1664,7 @@ static void *vb_alloc(unsigned long size, gfp_t gfp_mask)
return vaddr;
}
-static void vb_free(const void *addr, unsigned long size)
+static void vb_free(unsigned long addr, unsigned long size)
{
unsigned long offset;
unsigned long vb_idx;
@@ -1674,24 +1674,22 @@ static void vb_free(const void *addr, unsigned long size)
BUG_ON(offset_in_page(size));
BUG_ON(size > PAGE_SIZE*VMAP_MAX_ALLOC);
- flush_cache_vunmap((unsigned long)addr, (unsigned long)addr + size);
+ flush_cache_vunmap(addr, addr + size);
order = get_order(size);
- offset = (unsigned long)addr & (VMAP_BLOCK_SIZE - 1);
- offset >>= PAGE_SHIFT;
+ offset = (addr & (VMAP_BLOCK_SIZE - 1)) >> PAGE_SHIFT;
- vb_idx = addr_to_vb_idx((unsigned long)addr);
+ vb_idx = addr_to_vb_idx(addr);
rcu_read_lock();
vb = radix_tree_lookup(&vmap_block_tree, vb_idx);
rcu_read_unlock();
BUG_ON(!vb);
- vunmap_page_range((unsigned long)addr, (unsigned long)addr + size);
+ vunmap_page_range(addr, addr + size);
if (debug_pagealloc_enabled_static())
- flush_tlb_kernel_range((unsigned long)addr,
- (unsigned long)addr + size);
+ flush_tlb_kernel_range(addr, addr + size);
spin_lock(&vb->lock);
@@ -1791,7 +1789,7 @@ void vm_unmap_ram(const void *mem, unsigned int count)
if (likely(count <= VMAP_MAX_ALLOC)) {
debug_check_no_locks_freed(mem, size);
- vb_free(mem, size);
+ vb_free(addr, size);
return;
}
--
2.25.1
^ permalink raw reply related
* [PATCH 14/28] mm: don't return the number of pages from map_kernel_range{,_noflush}
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
None of the callers needs the number of pages, and a 0 / -errno return
value is a lot more intuitive.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
mm/vmalloc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index a3d810def567..ca8dc5d42580 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -249,7 +249,7 @@ static int vmap_p4d_range(pgd_t *pgd, unsigned long addr,
* function.
*
* RETURNS:
- * The number of pages mapped on success, -errno on failure.
+ * 0 on success, -errno on failure.
*/
int map_kernel_range_noflush(unsigned long addr, unsigned long size,
pgprot_t prot, struct page **pages)
@@ -269,7 +269,7 @@ int map_kernel_range_noflush(unsigned long addr, unsigned long size,
return err;
} while (pgd++, addr = next, addr != end);
- return nr;
+ return 0;
}
static int map_kernel_range(unsigned long start, unsigned long size,
--
2.25.1
^ permalink raw reply related
* [PATCH 16/28] mm: remove unmap_vmap_area
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
This function just has a single caller, open code it there.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
mm/vmalloc.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index b0c7cdc8701a..258220b203f1 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1247,14 +1247,6 @@ int unregister_vmap_purge_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(unregister_vmap_purge_notifier);
-/*
- * Clear the pagetable entries of a given vmap_area
- */
-static void unmap_vmap_area(struct vmap_area *va)
-{
- unmap_kernel_range_noflush(va->va_start, va->va_end - va->va_start);
-}
-
/*
* lazy_max_pages is the maximum amount of virtual address space we gather up
* before attempting to purge with a TLB flush.
@@ -1416,7 +1408,7 @@ static void free_vmap_area_noflush(struct vmap_area *va)
static void free_unmap_vmap_area(struct vmap_area *va)
{
flush_cache_vunmap(va->va_start, va->va_end);
- unmap_vmap_area(va);
+ unmap_kernel_range_noflush(va->va_start, va->va_end - va->va_start);
if (debug_pagealloc_enabled_static())
flush_tlb_kernel_range(va->va_start, va->va_end);
--
2.25.1
^ permalink raw reply related
* [PATCH 18/28] mm: enforce that vmap can't map pages executable
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
To help enforcing the W^X protection don't allow remapping existing
pages as executable.
Based on patch from Peter Zijlstra <peterz@infradead.org>.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
arch/x86/include/asm/pgtable_types.h | 6 ++++++
include/asm-generic/pgtable.h | 4 ++++
mm/vmalloc.c | 2 +-
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 947867f112ea..2e7c442cc618 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -282,6 +282,12 @@ typedef struct pgprot { pgprotval_t pgprot; } pgprot_t;
typedef struct { pgdval_t pgd; } pgd_t;
+static inline pgprot_t pgprot_nx(pgprot_t prot)
+{
+ return __pgprot(pgprot_val(prot) | _PAGE_NX);
+}
+#define pgprot_nx pgprot_nx
+
#ifdef CONFIG_X86_PAE
/*
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 329b8c8ca703..8c5f9c29698b 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -491,6 +491,10 @@ static inline int arch_unmap_one(struct mm_struct *mm,
#define flush_tlb_fix_spurious_fault(vma, address) flush_tlb_page(vma, address)
#endif
+#ifndef pgprot_nx
+#define pgprot_nx(prot) (prot)
+#endif
+
#ifndef pgprot_noncached
#define pgprot_noncached(prot) (prot)
#endif
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 7356b3f07bd8..334c75251ddb 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2390,7 +2390,7 @@ void *vmap(struct page **pages, unsigned int count,
if (!area)
return NULL;
- if (map_kernel_range((unsigned long)area->addr, size, prot,
+ if (map_kernel_range((unsigned long)area->addr, size, pgprot_nx(prot),
pages) < 0) {
vunmap(area->addr);
return NULL;
--
2.25.1
^ permalink raw reply related
* [PATCH 19/28] gpu/drm: remove the powerpc hack in drm_legacy_sg_alloc
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
If this code was broken for non-coherent caches a crude powerpc hack
isn't going to help anyone else. Remove the hack as it is the last
user of __vmalloc passing a page protection flag other than PAGE_KERNEL.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
drivers/gpu/drm/drm_scatter.c | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/drm_scatter.c b/drivers/gpu/drm/drm_scatter.c
index ca520028b2cb..f4e6184d1877 100644
--- a/drivers/gpu/drm/drm_scatter.c
+++ b/drivers/gpu/drm/drm_scatter.c
@@ -43,15 +43,6 @@
#define DEBUG_SCATTER 0
-static inline void *drm_vmalloc_dma(unsigned long size)
-{
-#if defined(__powerpc__) && defined(CONFIG_NOT_COHERENT_CACHE)
- return __vmalloc(size, GFP_KERNEL, pgprot_noncached_wc(PAGE_KERNEL));
-#else
- return vmalloc_32(size);
-#endif
-}
-
static void drm_sg_cleanup(struct drm_sg_mem * entry)
{
struct page *page;
@@ -126,7 +117,7 @@ int drm_legacy_sg_alloc(struct drm_device *dev, void *data,
return -ENOMEM;
}
- entry->virtual = drm_vmalloc_dma(pages << PAGE_SHIFT);
+ entry->virtual = vmalloc_32(pages << PAGE_SHIFT);
if (!entry->virtual) {
kfree(entry->busaddr);
kfree(entry->pagelist);
--
2.25.1
^ permalink raw reply related
* [PATCH 22/28] mm: remove both instances of __vmalloc_node_flags
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
The real version just had a few callers that can open code it and
remove one layer of indirection. The nommu stub was public but only
had a single caller, so remove it and avoid a CONFIG_MMU ifdef in
vmalloc.h.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
include/linux/vmalloc.h | 9 ---------
mm/nommu.c | 3 ++-
mm/vmalloc.c | 20 ++++++--------------
3 files changed, 8 insertions(+), 24 deletions(-)
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index c1b9d6eca05f..4a46d296e70d 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -115,17 +115,8 @@ extern void *__vmalloc_node_range(unsigned long size, unsigned long align,
unsigned long start, unsigned long end, gfp_t gfp_mask,
pgprot_t prot, unsigned long vm_flags, int node,
const void *caller);
-#ifndef CONFIG_MMU
-extern void *__vmalloc_node_flags(unsigned long size, int node, gfp_t flags);
-static inline void *__vmalloc_node_flags_caller(unsigned long size, int node,
- gfp_t flags, void *caller)
-{
- return __vmalloc_node_flags(size, node, flags);
-}
-#else
extern void *__vmalloc_node_flags_caller(unsigned long size,
int node, gfp_t flags, void *caller);
-#endif
extern void vfree(const void *addr);
extern void vfree_atomic(const void *addr);
diff --git a/mm/nommu.c b/mm/nommu.c
index 2df549adb22b..9553efa59787 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -150,7 +150,8 @@ void *__vmalloc(unsigned long size, gfp_t gfp_mask)
}
EXPORT_SYMBOL(__vmalloc);
-void *__vmalloc_node_flags(unsigned long size, int node, gfp_t flags)
+void *__vmalloc_node_flags_caller(unsigned long size, int node, gfp_t flags,
+ void *caller)
{
return __vmalloc(size, flags);
}
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index de7952959e82..3d59d848ad48 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2566,14 +2566,6 @@ void *__vmalloc(unsigned long size, gfp_t gfp_mask)
}
EXPORT_SYMBOL(__vmalloc);
-static inline void *__vmalloc_node_flags(unsigned long size,
- int node, gfp_t flags)
-{
- return __vmalloc_node(size, 1, flags, node,
- __builtin_return_address(0));
-}
-
-
void *__vmalloc_node_flags_caller(unsigned long size, int node, gfp_t flags,
void *caller)
{
@@ -2594,8 +2586,8 @@ void *__vmalloc_node_flags_caller(unsigned long size, int node, gfp_t flags,
*/
void *vmalloc(unsigned long size)
{
- return __vmalloc_node_flags(size, NUMA_NO_NODE,
- GFP_KERNEL);
+ return __vmalloc_node(size, 1, GFP_KERNEL, NUMA_NO_NODE,
+ __builtin_return_address(0));
}
EXPORT_SYMBOL(vmalloc);
@@ -2614,8 +2606,8 @@ EXPORT_SYMBOL(vmalloc);
*/
void *vzalloc(unsigned long size)
{
- return __vmalloc_node_flags(size, NUMA_NO_NODE,
- GFP_KERNEL | __GFP_ZERO);
+ return __vmalloc_node(size, 1, GFP_KERNEL | __GFP_ZERO, NUMA_NO_NODE,
+ __builtin_return_address(0));
}
EXPORT_SYMBOL(vzalloc);
@@ -2670,8 +2662,8 @@ EXPORT_SYMBOL(vmalloc_node);
*/
void *vzalloc_node(unsigned long size, int node)
{
- return __vmalloc_node_flags(size, node,
- GFP_KERNEL | __GFP_ZERO);
+ return __vmalloc_node(size, 1, GFP_KERNEL | __GFP_ZERO, node,
+ __builtin_return_address(0));
}
EXPORT_SYMBOL(vzalloc_node);
--
2.25.1
^ permalink raw reply related
* [PATCH 27/28] s390: use __vmalloc_node in alloc_vm_stack
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
alloc_vm_stack can use a slightly higher level vmalloc function.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
arch/powerpc/kernel/irq.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index a25ed47087ee..4518fb1d6bf4 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -735,9 +735,8 @@ void do_IRQ(struct pt_regs *regs)
static void *__init alloc_vm_stack(void)
{
- return __vmalloc_node_range(THREAD_SIZE, THREAD_ALIGN, VMALLOC_START,
- VMALLOC_END, THREADINFO_GFP, PAGE_KERNEL,
- 0, NUMA_NO_NODE, (void*)_RET_IP_);
+ return __vmalloc_node(THREAD_SIZE, THREAD_ALIGN, THREADINFO_GFP,
+ NUMA_NO_NODE, (void *)_RET_IP_);
}
static void __init vmap_irqstack_init(void)
--
2.25.1
^ permalink raw reply related
* [PATCH 28/28] s390: use __vmalloc_node in stack_alloc
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
stack_alloc can use a slightly higher level vmalloc function.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
arch/s390/kernel/setup.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 36445dd40fdb..0f0b140b5558 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -305,12 +305,9 @@ void *restart_stack __section(.data);
unsigned long stack_alloc(void)
{
#ifdef CONFIG_VMAP_STACK
- return (unsigned long)
- __vmalloc_node_range(THREAD_SIZE, THREAD_SIZE,
- VMALLOC_START, VMALLOC_END,
- THREADINFO_GFP,
- PAGE_KERNEL, 0, NUMA_NO_NODE,
- __builtin_return_address(0));
+ return (unsigned long)__vmalloc_node(THREAD_SIZE, THREAD_SIZE,
+ THREADINFO_GFP, NUMA_NO_NODE,
+ __builtin_return_address(0));
#else
return __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
#endif
--
2.25.1
^ permalink raw reply related
* [PATCH 26/28] arm64: use __vmalloc_node in arch_alloc_vmap_stack
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
arch_alloc_vmap_stack can use a slightly higher level vmalloc function.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
arch/arm64/include/asm/vmap_stack.h | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/vmap_stack.h b/arch/arm64/include/asm/vmap_stack.h
index 0a12115d9638..0cc6636e3f15 100644
--- a/arch/arm64/include/asm/vmap_stack.h
+++ b/arch/arm64/include/asm/vmap_stack.h
@@ -19,10 +19,8 @@ static inline unsigned long *arch_alloc_vmap_stack(size_t stack_size, int node)
{
BUILD_BUG_ON(!IS_ENABLED(CONFIG_VMAP_STACK));
- return __vmalloc_node_range(stack_size, THREAD_ALIGN,
- VMALLOC_START, VMALLOC_END,
- THREADINFO_GFP, PAGE_KERNEL, 0, node,
- __builtin_return_address(0));
+ return __vmalloc_node(stack_size, THREAD_ALIGN, THREADINFO_GFP, node,
+ __builtin_return_address(0));
}
#endif /* __ASM_VMAP_STACK_H */
--
2.25.1
^ permalink raw reply related
* [PATCH 25/28] mm: remove vmalloc_user_node_flags
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
Open code it in __bpf_map_area_alloc, which is the only caller. Also
clean up __bpf_map_area_alloc to have a single vmalloc call with
slightly different flags instead of the current two different calls.
For this to compile for the nommu case add a __vmalloc_node_range stub
to nommu.c.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
include/linux/vmalloc.h | 1 -
kernel/bpf/syscall.c | 23 +++++++++++++----------
mm/nommu.c | 14 ++++++++------
mm/vmalloc.c | 20 --------------------
4 files changed, 21 insertions(+), 37 deletions(-)
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 108f49b47756..f90f2946aac2 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -106,7 +106,6 @@ extern void *vzalloc(unsigned long size);
extern void *vmalloc_user(unsigned long size);
extern void *vmalloc_node(unsigned long size, int node);
extern void *vzalloc_node(unsigned long size, int node);
-extern void *vmalloc_user_node_flags(unsigned long size, int node, gfp_t flags);
extern void *vmalloc_exec(unsigned long size);
extern void *vmalloc_32(unsigned long size);
extern void *vmalloc_32_user(unsigned long size);
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 48d98ea8fad6..249d9bd43321 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -281,26 +281,29 @@ static void *__bpf_map_area_alloc(u64 size, int numa_node, bool mmapable)
* __GFP_RETRY_MAYFAIL to avoid such situations.
*/
- const gfp_t flags = __GFP_NOWARN | __GFP_ZERO;
+ const gfp_t gfp = __GFP_NOWARN | __GFP_ZERO;
+ unsigned int flags = 0;
+ unsigned long align = 1;
void *area;
if (size >= SIZE_MAX)
return NULL;
/* kmalloc()'ed memory can't be mmap()'ed */
- if (!mmapable && size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
- area = kmalloc_node(size, GFP_USER | __GFP_NORETRY | flags,
+ if (mmapable) {
+ BUG_ON(!PAGE_ALIGNED(size));
+ align = SHMLBA;
+ flags = VM_USERMAP;
+ } else if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
+ area = kmalloc_node(size, gfp | GFP_USER | __GFP_NORETRY,
numa_node);
if (area != NULL)
return area;
}
- if (mmapable) {
- BUG_ON(!PAGE_ALIGNED(size));
- return vmalloc_user_node_flags(size, numa_node, GFP_KERNEL |
- __GFP_RETRY_MAYFAIL | flags);
- }
- return __vmalloc_node(size, 1, GFP_KERNEL | __GFP_RETRY_MAYFAIL | flags,
- numa_node, __builtin_return_address(0));
+
+ return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
+ gfp | GFP_KERNEL | __GFP_RETRY_MAYFAIL, PAGE_KERNEL,
+ flags, numa_node, __builtin_return_address(0));
}
void *bpf_map_area_alloc(u64 size, int numa_node)
diff --git a/mm/nommu.c b/mm/nommu.c
index 81a86cd85893..b42cd6003d7d 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -150,6 +150,14 @@ void *__vmalloc(unsigned long size, gfp_t gfp_mask)
}
EXPORT_SYMBOL(__vmalloc);
+void *__vmalloc_node_range(unsigned long size, unsigned long align,
+ unsigned long start, unsigned long end, gfp_t gfp_mask,
+ pgprot_t prot, unsigned long vm_flags, int node,
+ const void *caller)
+{
+ return __vmalloc(size, flags);
+}
+
void *__vmalloc_node(unsigned long size, unsigned long align, gfp_t gfp_mask,
int node, const void *caller)
{
@@ -180,12 +188,6 @@ void *vmalloc_user(unsigned long size)
}
EXPORT_SYMBOL(vmalloc_user);
-void *vmalloc_user_node_flags(unsigned long size, int node, gfp_t flags)
-{
- return __vmalloc_user_flags(size, flags | __GFP_ZERO);
-}
-EXPORT_SYMBOL(vmalloc_user_node_flags);
-
struct page *vmalloc_to_page(const void *addr)
{
return virt_to_page(addr);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 333fbe77255a..f6f2acdaf70c 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2658,26 +2658,6 @@ void *vzalloc_node(unsigned long size, int node)
}
EXPORT_SYMBOL(vzalloc_node);
-/**
- * vmalloc_user_node_flags - allocate memory for userspace on a specific node
- * @size: allocation size
- * @node: numa node
- * @flags: flags for the page level allocator
- *
- * The resulting memory area is zeroed so it can be mapped to userspace
- * without leaking data.
- *
- * Return: pointer to the allocated memory or %NULL on error
- */
-void *vmalloc_user_node_flags(unsigned long size, int node, gfp_t flags)
-{
- return __vmalloc_node_range(size, SHMLBA, VMALLOC_START, VMALLOC_END,
- flags | __GFP_ZERO, PAGE_KERNEL,
- VM_USERMAP, node,
- __builtin_return_address(0));
-}
-EXPORT_SYMBOL(vmalloc_user_node_flags);
-
/**
* vmalloc_exec - allocate virtually contiguous, executable memory
* @size: allocation size
--
2.25.1
^ permalink raw reply related
* [PATCH 24/28] mm: switch the test_vmalloc module to use __vmalloc_node
From: Christoph Hellwig @ 2020-04-08 11:59 UTC (permalink / raw)
To: Andrew Morton, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger,
Wei Liu, x86, David Airlie, Daniel Vetter, Laura Abbott,
Sumit Semwal, Sakari Ailus, Minchan Kim, Nitin Gupta
Cc: Robin Murphy, Christophe Leroy, Peter Zijlstra, linuxppc-dev,
linux-hyperv, dri-devel, linaro-mm-sig, linux-arch, linux-mm,
iommu, linux-arm-kernel, linux-s390, bpf, linux-kernel
In-Reply-To: <20200408115926.1467567-1-hch@lst.de>
No need to export the very low-level __vmalloc_node_range when the
test module can use a slightly higher level variant.
Signed-off-by: Christoph Hellwig <hch@lst.de>
---
lib/test_vmalloc.c | 26 +++++++-------------------
mm/vmalloc.c | 17 ++++++++---------
2 files changed, 15 insertions(+), 28 deletions(-)
diff --git a/lib/test_vmalloc.c b/lib/test_vmalloc.c
index 8bbefcaddfe8..cd6aef05dfb4 100644
--- a/lib/test_vmalloc.c
+++ b/lib/test_vmalloc.c
@@ -91,12 +91,8 @@ static int random_size_align_alloc_test(void)
*/
size = ((rnd % 10) + 1) * PAGE_SIZE;
- ptr = __vmalloc_node_range(size, align,
- VMALLOC_START, VMALLOC_END,
- GFP_KERNEL | __GFP_ZERO,
- PAGE_KERNEL,
- 0, 0, __builtin_return_address(0));
-
+ ptr = __vmalloc_node(size, align, GFP_KERNEL | __GFP_ZERO,
+ __builtin_return_address(0));
if (!ptr)
return -1;
@@ -118,12 +114,8 @@ static int align_shift_alloc_test(void)
for (i = 0; i < BITS_PER_LONG; i++) {
align = ((unsigned long) 1) << i;
- ptr = __vmalloc_node_range(PAGE_SIZE, align,
- VMALLOC_START, VMALLOC_END,
- GFP_KERNEL | __GFP_ZERO,
- PAGE_KERNEL,
- 0, 0, __builtin_return_address(0));
-
+ ptr = __vmalloc_node(PAGE_SIZE, align, GFP_KERNEL | __GFP_ZERO,
+ __builtin_return_address(0));
if (!ptr)
return -1;
@@ -139,13 +131,9 @@ static int fix_align_alloc_test(void)
int i;
for (i = 0; i < test_loop_count; i++) {
- ptr = __vmalloc_node_range(5 * PAGE_SIZE,
- THREAD_ALIGN << 1,
- VMALLOC_START, VMALLOC_END,
- GFP_KERNEL | __GFP_ZERO,
- PAGE_KERNEL,
- 0, 0, __builtin_return_address(0));
-
+ ptr = __vmalloc_node(5 * PAGE_SIZE, THREAD_ALIGN << 1,
+ GFP_KERNEL | __GFP_ZERO,
+ __builtin_return_address(0));
if (!ptr)
return -1;
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index ae8249ef5821..333fbe77255a 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -2522,15 +2522,6 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,
return NULL;
}
-/*
- * This is only for performance analysis of vmalloc and stress purpose.
- * It is required by vmalloc test module, therefore do not use it other
- * than that.
- */
-#ifdef CONFIG_TEST_VMALLOC_MODULE
-EXPORT_SYMBOL_GPL(__vmalloc_node_range);
-#endif
-
/**
* __vmalloc_node - allocate virtually contiguous memory
* @size: allocation size
@@ -2556,6 +2547,14 @@ void *__vmalloc_node(unsigned long size, unsigned long align,
return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
gfp_mask, PAGE_KERNEL, 0, node, caller);
}
+/*
+ * This is only for performance analysis of vmalloc and stress purpose.
+ * It is required by vmalloc test module, therefore do not use it other
+ * than that.
+ */
+#ifdef CONFIG_TEST_VMALLOC_MODULE
+EXPORT_SYMBOL_GPL(__vmalloc_node);
+#endif
void *__vmalloc(unsigned long size, gfp_t gfp_mask)
{
--
2.25.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox