diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 30384eacad4f741eca429520563099316e85c9ea..67ee1ac76c7d112ee321a82278ba8e7c1c18152f 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -3405,7 +3405,6 @@ CONFIG_TCG_TIS_ST33ZP24_I2C=m CONFIG_TCG_TIS_ST33ZP24_SPI=m # CONFIG_XILLYBUS is not set CONFIG_PIN_MEMORY_DEV=m -CONFIG_HISI_SVM=m # CONFIG_RANDOM_TRUST_CPU is not set # CONFIG_RANDOM_TRUST_BOOTLOADER is not set # end of Character devices diff --git a/drivers/android/binder.c b/drivers/android/binder.c index b9985eee8c1bc536fbf6868167ef5ba809bb0844..cfb1393a0891a44d3481bcb280e6c367755f1ba0 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -6081,6 +6081,7 @@ const struct file_operations binder_fops = { .open = binder_open, .flush = binder_flush, .release = binder_release, + .may_pollfree = true, }; static int __init init_binder_device(const char *name) diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 95ca4f934d283db8489befafc90da6b762634e90..a77ed66425f27cee5a0875baa02d8125e7fc8f5f 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -212,7 +212,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, mm = alloc->vma_vm_mm; if (mm) { - mmap_read_lock(mm); + mmap_write_lock(mm); vma = alloc->vma; } @@ -270,7 +270,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, trace_binder_alloc_page_end(alloc, index); } if (mm) { - mmap_read_unlock(mm); + mmap_write_unlock(mm); mmput(mm); } return 0; @@ -303,7 +303,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, } err_no_vma: if (mm) { - mmap_read_unlock(mm); + mmap_write_unlock(mm); mmput(mm); } return vma ? -ENOMEM : -ESRCH; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 701811fcc0fd935737675a74c053b2b3a92c3c3e..6fa56a4739953ac63067e7d62613751a28ef6047 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -478,16 +478,6 @@ config PIN_MEMORY_DEV help pin memory driver -config HISI_SVM - tristate "Hisilicon svm driver" - depends on ARM64 && ARM_SMMU_V3 && MMU_NOTIFIER - default m - help - This driver provides character-level access to Hisilicon - SVM chipset. Typically, you can bind a task to the - svm and share the virtual memory with hisilicon svm device. - When in doubt, say "N". - config RANDOM_TRUST_CPU bool "Initialize RNG using CPU RNG instructions" default y diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 362d4a9cd4cf8b5bb0fdcec5249a24aac85d3970..71d76fd62692fe64859ca464984b0bdd8a9454f9 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -48,4 +48,3 @@ obj-$(CONFIG_XILLYBUS) += xillybus/ obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o obj-$(CONFIG_ADI) += adi.o obj-$(CONFIG_PIN_MEMORY_DEV) += pin_memory.o -obj-$(CONFIG_HISI_SVM) += svm.o diff --git a/drivers/char/svm.c b/drivers/char/svm.c deleted file mode 100644 index 6945e93354b4cda906b9850df56634c8728b7cf3..0000000000000000000000000000000000000000 --- a/drivers/char/svm.c +++ /dev/null @@ -1,1772 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2017-2018 Hisilicon Limited. - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <asm/esr.h> -#include <linux/mmu_context.h> - -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/iommu.h> -#include <linux/miscdevice.h> -#include <linux/mman.h> -#include <linux/mmu_notifier.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_device.h> -#include <linux/platform_device.h> -#include <linux/ptrace.h> -#include <linux/security.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/sched.h> -#include <linux/hugetlb.h> -#include <linux/sched/mm.h> -#include <linux/msi.h> -#include <linux/acpi.h> - -#define SVM_DEVICE_NAME "svm" -#define ASID_SHIFT 48 - -#define SVM_IOCTL_REMAP_PROC 0xfff4 -#define SVM_IOCTL_UNPIN_MEMORY 0xfff5 -#define SVM_IOCTL_PIN_MEMORY 0xfff7 -#define SVM_IOCTL_GET_PHYS 0xfff9 -#define SVM_IOCTL_LOAD_FLAG 0xfffa -#define SVM_IOCTL_SET_RC 0xfffc -#define SVM_IOCTL_PROCESS_BIND 0xffff - -#define CORE_SID 0 - -#define SVM_IOCTL_RELEASE_PHYS32 0xfff3 -#define SVM_REMAP_MEM_LEN_MAX (16 * 1024 * 1024) -#define MMAP_PHY32_MAX (16 * 1024 * 1024) - -static int probe_index; -static LIST_HEAD(child_list); -static DECLARE_RWSEM(svm_sem); -static struct rb_root svm_process_root = RB_ROOT; -static struct mutex svm_process_mutex; - -struct core_device { - struct device dev; - struct iommu_group *group; - struct iommu_domain *domain; - u8 smmu_bypass; - struct list_head entry; -}; - -struct svm_device { - unsigned long long id; - struct miscdevice miscdev; - struct device *dev; - phys_addr_t l2buff; - unsigned long l2size; -}; - -struct svm_bind_process { - pid_t vpid; - u64 ttbr; - u64 tcr; - int pasid; - u32 flags; -#define SVM_BIND_PID (1 << 0) -}; - -/* - *svm_process is released in svm_notifier_release() when mm refcnt - *goes down zero. We should access svm_process only in the context - *where mm_struct is valid, which means we should always get mm - *refcnt first. - */ -struct svm_process { - struct pid *pid; - struct mm_struct *mm; - unsigned long asid; - struct rb_node rb_node; - struct mmu_notifier notifier; - /* For postponed release */ - struct rcu_head rcu; - int pasid; - struct mutex mutex; - struct rb_root sdma_list; - struct svm_device *sdev; - struct iommu_sva *sva; -}; - -struct svm_sdma { - struct rb_node node; - unsigned long addr; - int nr_pages; - struct page **pages; - atomic64_t ref; -}; - -struct svm_proc_mem { - u32 dev_id; - u32 len; - u64 pid; - u64 vaddr; - u64 buf; -}; - -static char *svm_cmd_to_string(unsigned int cmd) -{ - switch (cmd) { - case SVM_IOCTL_PROCESS_BIND: - return "bind"; - case SVM_IOCTL_GET_PHYS: - return "get phys"; - case SVM_IOCTL_SET_RC: - return "set rc"; - case SVM_IOCTL_PIN_MEMORY: - return "pin memory"; - case SVM_IOCTL_UNPIN_MEMORY: - return "unpin memory"; - case SVM_IOCTL_REMAP_PROC: - return "remap proc"; - case SVM_IOCTL_LOAD_FLAG: - return "load flag"; - case SVM_IOCTL_RELEASE_PHYS32: - return "release phys"; - default: - return "unsupported"; - } - - return NULL; -} - -/* - * image word of slot - * SVM_IMAGE_WORD_INIT: initial value, indicating that the slot is not used. - * SVM_IMAGE_WORD_VALID: valid data is filled in the slot - * SVM_IMAGE_WORD_DONE: the DMA operation is complete when the TS uses this address, - * so, this slot can be freed. - */ -#define SVM_IMAGE_WORD_INIT 0x0 -#define SVM_IMAGE_WORD_VALID 0xaa55aa55 -#define SVM_IMAGE_WORD_DONE 0x55ff55ff - -/* - * The length of this structure must be 64 bytes, which is the agreement with the TS. - * And the data type and sequence cannot be changed, because the TS core reads data - * based on the data type and sequence. - * image_word: slot status. For details, see SVM_IMAGE_WORD_xxx - * pid: pid of process which ioctl svm device to get physical addr, it is used for - * verification by TS. - * data_type: used to determine the data type by TS. Currently, data type must be - * SVM_VA2PA_TYPE_DMA. - * char data[48]: for the data type SVM_VA2PA_TYPE_DMA, the DMA address is stored. - */ -struct svm_va2pa_slot { - int image_word; - int resv; - int pid; - int data_type; - union { - char user_defined_data[48]; - struct { - unsigned long phys; - unsigned long len; - char reserved[32]; - }; - }; -}; - -struct svm_va2pa_trunk { - struct svm_va2pa_slot *slots; - int slot_total; - int slot_used; - unsigned long *bitmap; - struct mutex mutex; -}; - -struct svm_va2pa_trunk va2pa_trunk; - -#define SVM_VA2PA_TRUNK_SIZE_MAX 0x3200000 -#define SVM_VA2PA_MEMORY_ALIGN 64 -#define SVM_VA2PA_SLOT_SIZE sizeof(struct svm_va2pa_slot) -#define SVM_VA2PA_TYPE_DMA 0x1 -#define SVM_MEM_REG "va2pa trunk" -#define SVM_VA2PA_CLEAN_BATCH_NUM 0x80 - -struct device_node *svm_find_mem_reg_node(struct device *dev, const char *compat) -{ - int index = 0; - struct device_node *tmp = NULL; - struct device_node *np = dev->of_node; - - for (; ; index++) { - tmp = of_parse_phandle(np, "memory-region", index); - if (!tmp) - break; - - if (of_device_is_compatible(tmp, compat)) - return tmp; - - of_node_put(tmp); - } - - return NULL; -} - -static int svm_parse_trunk_memory(struct device *dev, phys_addr_t *base, unsigned long *size) -{ - int err; - struct resource r; - struct device_node *trunk = NULL; - - trunk = svm_find_mem_reg_node(dev, SVM_MEM_REG); - if (!trunk) { - dev_err(dev, "Didn't find reserved memory\n"); - return -EINVAL; - } - - err = of_address_to_resource(trunk, 0, &r); - of_node_put(trunk); - if (err) { - dev_err(dev, "Couldn't address to resource for reserved memory\n"); - return -ENOMEM; - } - - *base = r.start; - *size = resource_size(&r); - - return 0; -} - -static int svm_setup_trunk(struct device *dev, phys_addr_t base, unsigned long size) -{ - int slot_total; - unsigned long *bitmap = NULL; - struct svm_va2pa_slot *slot = NULL; - - if (!IS_ALIGNED(base, SVM_VA2PA_MEMORY_ALIGN)) { - dev_err(dev, "Didn't aligned to %u\n", SVM_VA2PA_MEMORY_ALIGN); - return -EINVAL; - } - - if ((size == 0) || (size > SVM_VA2PA_TRUNK_SIZE_MAX)) { - dev_err(dev, "Size of reserved memory is not right\n"); - return -EINVAL; - } - - slot_total = size / SVM_VA2PA_SLOT_SIZE; - if (slot_total < BITS_PER_LONG) - return -EINVAL; - - bitmap = kvcalloc(slot_total / BITS_PER_LONG, sizeof(unsigned long), GFP_KERNEL); - if (!bitmap) { - dev_err(dev, "alloc memory failed\n"); - return -ENOMEM; - } - - slot = ioremap(base, size); - if (!slot) { - kvfree(bitmap); - dev_err(dev, "Ioremap trunk failed\n"); - return -ENXIO; - } - - va2pa_trunk.slots = slot; - va2pa_trunk.slot_used = 0; - va2pa_trunk.slot_total = slot_total; - va2pa_trunk.bitmap = bitmap; - mutex_init(&va2pa_trunk.mutex); - - return 0; -} - -static void svm_remove_trunk(struct device *dev) -{ - iounmap(va2pa_trunk.slots); - kvfree(va2pa_trunk.bitmap); - - va2pa_trunk.slots = NULL; - va2pa_trunk.bitmap = NULL; -} - -static void svm_set_slot_valid(unsigned long index, unsigned long phys, unsigned long len) -{ - struct svm_va2pa_slot *slot = &va2pa_trunk.slots[index]; - - slot->phys = phys; - slot->len = len; - slot->image_word = SVM_IMAGE_WORD_VALID; - slot->pid = current->tgid; - slot->data_type = SVM_VA2PA_TYPE_DMA; - __bitmap_set(va2pa_trunk.bitmap, index, 1); - va2pa_trunk.slot_used++; -} - -static void svm_set_slot_init(unsigned long index) -{ - struct svm_va2pa_slot *slot = &va2pa_trunk.slots[index]; - - slot->image_word = SVM_IMAGE_WORD_INIT; - __bitmap_clear(va2pa_trunk.bitmap, index, 1); - va2pa_trunk.slot_used--; -} - -static void svm_clean_done_slots(void) -{ - int used = va2pa_trunk.slot_used; - int count = 0; - long temp = -1; - phys_addr_t addr; - unsigned long *bitmap = va2pa_trunk.bitmap; - - for (; count < used && count < SVM_VA2PA_CLEAN_BATCH_NUM;) { - temp = find_next_bit(bitmap, va2pa_trunk.slot_total, temp + 1); - if (temp == va2pa_trunk.slot_total) - break; - - count++; - if (va2pa_trunk.slots[temp].image_word != SVM_IMAGE_WORD_DONE) - continue; - - addr = (phys_addr_t)va2pa_trunk.slots[temp].phys; - put_page(pfn_to_page(PHYS_PFN(addr))); - svm_set_slot_init(temp); - } -} - -static int svm_find_slot_init(unsigned long *index) -{ - int temp; - unsigned long *bitmap = va2pa_trunk.bitmap; - - temp = find_first_zero_bit(bitmap, va2pa_trunk.slot_total); - if (temp == va2pa_trunk.slot_total) - return -ENOSPC; - - *index = temp; - return 0; -} - -static int svm_va2pa_trunk_init(struct device *dev) -{ - int err; - phys_addr_t base; - unsigned long size; - - err = svm_parse_trunk_memory(dev, &base, &size); - if (err) - return err; - - err = svm_setup_trunk(dev, base, size); - if (err) - return err; - - return 0; -} - -static struct svm_process *find_svm_process(unsigned long asid) -{ - struct rb_node *node = svm_process_root.rb_node; - - while (node) { - struct svm_process *process = NULL; - - process = rb_entry(node, struct svm_process, rb_node); - if (asid < process->asid) - node = node->rb_left; - else if (asid > process->asid) - node = node->rb_right; - else - return process; - } - - return NULL; -} - -static void insert_svm_process(struct svm_process *process) -{ - struct rb_node **p = &svm_process_root.rb_node; - struct rb_node *parent = NULL; - - while (*p) { - struct svm_process *tmp_process = NULL; - - parent = *p; - tmp_process = rb_entry(parent, struct svm_process, rb_node); - if (process->asid < tmp_process->asid) - p = &(*p)->rb_left; - else if (process->asid > tmp_process->asid) - p = &(*p)->rb_right; - else { - WARN_ON_ONCE("asid already in the tree"); - return; - } - } - - rb_link_node(&process->rb_node, parent, p); - rb_insert_color(&process->rb_node, &svm_process_root); -} - -static void delete_svm_process(struct svm_process *process) -{ - rb_erase(&process->rb_node, &svm_process_root); - RB_CLEAR_NODE(&process->rb_node); -} - -static struct svm_device *file_to_sdev(struct file *file) -{ - return container_of(file->private_data, - struct svm_device, miscdev); -} - -static inline struct core_device *to_core_device(struct device *d) -{ - return container_of(d, struct core_device, dev); -} - -static struct svm_sdma *svm_find_sdma(struct svm_process *process, - unsigned long addr, int nr_pages) -{ - struct rb_node *node = process->sdma_list.rb_node; - - while (node) { - struct svm_sdma *sdma = NULL; - - sdma = rb_entry(node, struct svm_sdma, node); - if (addr < sdma->addr) - node = node->rb_left; - else if (addr > sdma->addr) - node = node->rb_right; - else if (nr_pages < sdma->nr_pages) - node = node->rb_left; - else if (nr_pages > sdma->nr_pages) - node = node->rb_right; - else - return sdma; - } - - return NULL; -} - -static int svm_insert_sdma(struct svm_process *process, struct svm_sdma *sdma) -{ - struct rb_node **p = &process->sdma_list.rb_node; - struct rb_node *parent = NULL; - - while (*p) { - struct svm_sdma *tmp_sdma = NULL; - - parent = *p; - tmp_sdma = rb_entry(parent, struct svm_sdma, node); - if (sdma->addr < tmp_sdma->addr) - p = &(*p)->rb_left; - else if (sdma->addr > tmp_sdma->addr) - p = &(*p)->rb_right; - else if (sdma->nr_pages < tmp_sdma->nr_pages) - p = &(*p)->rb_left; - else if (sdma->nr_pages > tmp_sdma->nr_pages) - p = &(*p)->rb_right; - else { - /* - * add reference count and return -EBUSY - * to free former alloced one. - */ - atomic64_inc(&tmp_sdma->ref); - return -EBUSY; - } - } - - rb_link_node(&sdma->node, parent, p); - rb_insert_color(&sdma->node, &process->sdma_list); - - return 0; -} - -static void svm_remove_sdma(struct svm_process *process, - struct svm_sdma *sdma, bool try_rm) -{ - int null_count = 0; - - if (try_rm && (!atomic64_dec_and_test(&sdma->ref))) - return; - - rb_erase(&sdma->node, &process->sdma_list); - RB_CLEAR_NODE(&sdma->node); - - while (sdma->nr_pages--) { - if (sdma->pages[sdma->nr_pages] == NULL) { - pr_err("null pointer, nr_pages:%d.\n", sdma->nr_pages); - null_count++; - continue; - } - - put_page(sdma->pages[sdma->nr_pages]); - } - - if (null_count) - dump_stack(); - - kvfree(sdma->pages); - kfree(sdma); -} - -static int svm_pin_pages(unsigned long addr, int nr_pages, - struct page **pages) -{ - int err; - - err = get_user_pages_fast(addr, nr_pages, 1, pages); - if (err > 0 && err < nr_pages) { - while (err--) - put_page(pages[err]); - err = -EFAULT; - } else if (err == 0) { - err = -EFAULT; - } - - return err; -} - -static int svm_add_sdma(struct svm_process *process, - unsigned long addr, unsigned long size) -{ - int err; - struct svm_sdma *sdma = NULL; - - sdma = kzalloc(sizeof(struct svm_sdma), GFP_KERNEL); - if (sdma == NULL) - return -ENOMEM; - - atomic64_set(&sdma->ref, 1); - sdma->addr = addr & PAGE_MASK; - sdma->nr_pages = (PAGE_ALIGN(size + addr) >> PAGE_SHIFT) - - (sdma->addr >> PAGE_SHIFT); - sdma->pages = kvcalloc(sdma->nr_pages, sizeof(char *), GFP_KERNEL); - if (sdma->pages == NULL) { - err = -ENOMEM; - goto err_free_sdma; - } - - /* - * If always pin the same addr with the same nr_pages, pin pages - * maybe should move after insert sdma with mutex lock. - */ - err = svm_pin_pages(sdma->addr, sdma->nr_pages, sdma->pages); - if (err < 0) { - pr_err("%s: failed to pin pages addr 0x%pK, size 0x%lx\n", - __func__, (void *)addr, size); - goto err_free_pages; - } - - err = svm_insert_sdma(process, sdma); - if (err < 0) { - err = 0; - pr_debug("%s: sdma already exist!\n", __func__); - goto err_unpin_pages; - } - - return err; - -err_unpin_pages: - while (sdma->nr_pages--) - put_page(sdma->pages[sdma->nr_pages]); -err_free_pages: - kvfree(sdma->pages); -err_free_sdma: - kfree(sdma); - - return err; -} - -static int svm_pin_memory(unsigned long __user *arg) -{ - int err; - struct svm_process *process = NULL; - unsigned long addr, size, asid; - - if (!acpi_disabled) - return -EPERM; - - if (arg == NULL) - return -EINVAL; - - if (get_user(addr, arg)) - return -EFAULT; - - if (get_user(size, arg + 1)) - return -EFAULT; - - if ((addr + size <= addr) || (size >= (u64)UINT_MAX) || (addr == 0)) - return -EINVAL; - - asid = arm64_mm_context_get(current->mm); - if (!asid) - return -ENOSPC; - - mutex_lock(&svm_process_mutex); - process = find_svm_process(asid); - if (process == NULL) { - mutex_unlock(&svm_process_mutex); - err = -ESRCH; - goto out; - } - mutex_unlock(&svm_process_mutex); - - mutex_lock(&process->mutex); - err = svm_add_sdma(process, addr, size); - mutex_unlock(&process->mutex); - -out: - arm64_mm_context_put(current->mm); - - return err; -} - -static int svm_unpin_memory(unsigned long __user *arg) -{ - int err = 0, nr_pages; - struct svm_sdma *sdma = NULL; - unsigned long addr, size, asid; - struct svm_process *process = NULL; - - if (!acpi_disabled) - return -EPERM; - - if (arg == NULL) - return -EINVAL; - - if (get_user(addr, arg)) - return -EFAULT; - - if (get_user(size, arg + 1)) - return -EFAULT; - - if (ULONG_MAX - addr < size) - return -EINVAL; - - asid = arm64_mm_context_get(current->mm); - if (!asid) - return -ENOSPC; - - nr_pages = (PAGE_ALIGN(size + addr) >> PAGE_SHIFT) - - ((addr & PAGE_MASK) >> PAGE_SHIFT); - addr &= PAGE_MASK; - - mutex_lock(&svm_process_mutex); - process = find_svm_process(asid); - if (process == NULL) { - mutex_unlock(&svm_process_mutex); - err = -ESRCH; - goto out; - } - mutex_unlock(&svm_process_mutex); - - mutex_lock(&process->mutex); - sdma = svm_find_sdma(process, addr, nr_pages); - if (sdma == NULL) { - mutex_unlock(&process->mutex); - err = -ESRCH; - goto out; - } - - svm_remove_sdma(process, sdma, true); - mutex_unlock(&process->mutex); - -out: - arm64_mm_context_put(current->mm); - - return err; -} - -static void svm_unpin_all(struct svm_process *process) -{ - struct rb_node *node = NULL; - - while ((node = rb_first(&process->sdma_list))) - svm_remove_sdma(process, - rb_entry(node, struct svm_sdma, node), - false); -} - -static int svm_acpi_bind_core(struct core_device *cdev, void *data) -{ - struct task_struct *task = NULL; - struct svm_process *process = data; - - if (cdev->smmu_bypass) - return 0; - - task = get_pid_task(process->pid, PIDTYPE_PID); - if (!task) { - pr_err("failed to get task_struct\n"); - return -ESRCH; - } - - process->sva = iommu_sva_bind_device(&cdev->dev, task->mm, NULL); - if (!process->sva) { - pr_err("failed to bind device\n"); - return PTR_ERR(process->sva); - } - - process->pasid = task->mm->pasid; - put_task_struct(task); - - return 0; -} - -static int svm_dt_bind_core(struct device *dev, void *data) -{ - struct task_struct *task = NULL; - struct svm_process *process = data; - struct core_device *cdev = to_core_device(dev); - - if (cdev->smmu_bypass) - return 0; - - task = get_pid_task(process->pid, PIDTYPE_PID); - if (!task) { - pr_err("failed to get task_struct\n"); - return -ESRCH; - } - - process->sva = iommu_sva_bind_device(dev, task->mm, NULL); - if (!process->sva) { - pr_err("failed to bind device\n"); - return PTR_ERR(process->sva); - } - - process->pasid = task->mm->pasid; - put_task_struct(task); - - return 0; -} - -static void svm_dt_bind_cores(struct svm_process *process) -{ - device_for_each_child(process->sdev->dev, process, svm_dt_bind_core); -} - -static void svm_acpi_bind_cores(struct svm_process *process) -{ - struct core_device *pos = NULL; - - list_for_each_entry(pos, &child_list, entry) { - svm_acpi_bind_core(pos, process); - } -} - -static void svm_process_free(struct mmu_notifier *mn) -{ - struct svm_process *process = NULL; - - process = container_of(mn, struct svm_process, notifier); - svm_unpin_all(process); - arm64_mm_context_put(process->mm); - kfree(process); -} - -static void svm_process_release(struct svm_process *process) -{ - delete_svm_process(process); - put_pid(process->pid); - - mmu_notifier_put(&process->notifier); -} - -static void svm_notifier_release(struct mmu_notifier *mn, - struct mm_struct *mm) -{ - struct svm_process *process = NULL; - - process = container_of(mn, struct svm_process, notifier); - - /* - * No need to call svm_unbind_cores(), as iommu-sva will do the - * unbind in its mm_notifier callback. - */ - - mutex_lock(&svm_process_mutex); - svm_process_release(process); - mutex_unlock(&svm_process_mutex); -} - -static struct mmu_notifier_ops svm_process_mmu_notifier = { - .release = svm_notifier_release, - .free_notifier = svm_process_free, -}; - -static struct svm_process * -svm_process_alloc(struct svm_device *sdev, struct pid *pid, - struct mm_struct *mm, unsigned long asid) -{ - struct svm_process *process = kzalloc(sizeof(*process), GFP_ATOMIC); - - if (!process) - return ERR_PTR(-ENOMEM); - - process->sdev = sdev; - process->pid = pid; - process->mm = mm; - process->asid = asid; - process->sdma_list = RB_ROOT; //lint !e64 - mutex_init(&process->mutex); - process->notifier.ops = &svm_process_mmu_notifier; - - return process; -} - -static struct task_struct *svm_get_task(struct svm_bind_process params) -{ - struct task_struct *task = NULL; - - if (params.flags & ~SVM_BIND_PID) - return ERR_PTR(-EINVAL); - - if (params.flags & SVM_BIND_PID) { - struct mm_struct *mm = NULL; - - task = find_get_task_by_vpid(params.vpid); - if (task == NULL) - return ERR_PTR(-ESRCH); - - /* check the permission */ - mm = mm_access(task, PTRACE_MODE_ATTACH_REALCREDS); - if (IS_ERR_OR_NULL(mm)) { - pr_err("cannot access mm\n"); - put_task_struct(task); - return ERR_PTR(-ESRCH); - } - - mmput(mm); - } else { - get_task_struct(current); - task = current; - } - - return task; -} - -static int svm_process_bind(struct task_struct *task, - struct svm_device *sdev, u64 *ttbr, u64 *tcr, int *pasid) -{ - int err; - unsigned long asid; - struct pid *pid = NULL; - struct svm_process *process = NULL; - struct mm_struct *mm = NULL; - - if ((ttbr == NULL) || (tcr == NULL) || (pasid == NULL)) - return -EINVAL; - - pid = get_task_pid(task, PIDTYPE_PID); - if (pid == NULL) - return -EINVAL; - - mm = get_task_mm(task); - if (!mm) { - err = -EINVAL; - goto err_put_pid; - } - - asid = arm64_mm_context_get(mm); - if (!asid) { - err = -ENOSPC; - goto err_put_mm; - } - - /* If a svm_process already exists, use it */ - mutex_lock(&svm_process_mutex); - process = find_svm_process(asid); - if (process == NULL) { - process = svm_process_alloc(sdev, pid, mm, asid); - if (IS_ERR(process)) { - err = PTR_ERR(process); - mutex_unlock(&svm_process_mutex); - goto err_put_mm_context; - } - err = mmu_notifier_register(&process->notifier, mm); - if (err) { - mutex_unlock(&svm_process_mutex); - goto err_free_svm_process; - } - - insert_svm_process(process); - - if (acpi_disabled) - svm_dt_bind_cores(process); - else - svm_acpi_bind_cores(process); - - mutex_unlock(&svm_process_mutex); - } else { - mutex_unlock(&svm_process_mutex); - arm64_mm_context_put(mm); - put_pid(pid); - } - - - *ttbr = virt_to_phys(mm->pgd) | asid << ASID_SHIFT; - *tcr = read_sysreg(tcr_el1); - *pasid = process->pasid; - - mmput(mm); - return 0; - -err_free_svm_process: - kfree(process); -err_put_mm_context: - arm64_mm_context_put(mm); -err_put_mm: - mmput(mm); -err_put_pid: - put_pid(pid); - - return err; -} - -static pte_t *svm_get_pte(struct vm_area_struct *vma, - pud_t *pud, - unsigned long addr, - unsigned long *page_size, - unsigned long *offset) -{ - pte_t *pte = NULL; - unsigned long size = 0; - - if (is_vm_hugetlb_page(vma)) { - if (pud_present(*pud)) { - if (pud_val(*pud) && !(pud_val(*pud) & PUD_TABLE_BIT)) { - pte = (pte_t *)pud; - *offset = addr & (PUD_SIZE - 1); - size = PUD_SIZE; - } else { - pte = (pte_t *)pmd_offset(pud, addr); - *offset = addr & (PMD_SIZE - 1); - size = PMD_SIZE; - } - } else { - pr_err("%s:hugetlb but pud not present\n", __func__); - } - } else { - pmd_t *pmd = pmd_offset(pud, addr); - - if (pmd_none(*pmd)) - return NULL; - - if (pmd_trans_huge(*pmd)) { - pte = (pte_t *)pmd; - *offset = addr & (PMD_SIZE - 1); - size = PMD_SIZE; - } else { - pte = pte_offset_map(pmd, addr); - *offset = addr & (PAGE_SIZE - 1); - size = PAGE_SIZE; - } - } - - if (page_size) - *page_size = size; - - return pte; -} - -/* Must be called with mmap_lock held */ -static pte_t *svm_walk_pt(unsigned long addr, unsigned long *page_size, - unsigned long *offset) -{ - pgd_t *pgd = NULL; - p4d_t *p4d = NULL; - pud_t *pud = NULL; - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma = NULL; - - vma = find_vma(mm, addr); - if (!vma) - return NULL; - - pgd = pgd_offset(mm, addr); - if (pgd_none(*pgd)) - return NULL; - - p4d = p4d_offset(pgd, addr); - if (p4d_none(*p4d)) - return NULL; - - pud = pud_offset(p4d, addr); - if (pud_none(*pud)) - return NULL; - - return svm_get_pte(vma, pud, addr, page_size, offset); -} - -static int svm_get_phys(unsigned long __user *arg) -{ - int err; - pte_t *ptep = NULL; - pte_t pte; - unsigned long index = 0; - struct page *page; - unsigned long addr, phys, offset; - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma = NULL; - unsigned long len; - - if (!acpi_disabled) - return -EPERM; - - if (get_user(addr, arg)) - return -EFAULT; - - down_read(&mm->mmap_lock); - ptep = svm_walk_pt(addr, NULL, &offset); - if (!ptep) { - up_read(&mm->mmap_lock); - return -EINVAL; - } - - pte = READ_ONCE(*ptep); - if (!pte_present(pte) || !(pfn_in_present_section(pte_pfn(pte)))) { - up_read(&mm->mmap_lock); - return -EINVAL; - } - - page = pte_page(pte); - get_page(page); - - phys = PFN_PHYS(pte_pfn(pte)) + offset; - - /* fix ts problem, which need the len to check out memory */ - len = 0; - vma = find_vma(mm, addr); - if (vma) - len = vma->vm_end - addr; - - up_read(&mm->mmap_lock); - - mutex_lock(&va2pa_trunk.mutex); - svm_clean_done_slots(); - if (va2pa_trunk.slot_used == va2pa_trunk.slot_total) { - err = -ENOSPC; - goto err_mutex_unlock; - } - - err = svm_find_slot_init(&index); - if (err) - goto err_mutex_unlock; - - svm_set_slot_valid(index, phys, len); - - err = put_user(index * SVM_VA2PA_SLOT_SIZE, (unsigned long __user *)arg); - if (err) - goto err_slot_init; - - mutex_unlock(&va2pa_trunk.mutex); - return 0; - -err_slot_init: - svm_set_slot_init(index); -err_mutex_unlock: - mutex_unlock(&va2pa_trunk.mutex); - put_page(page); - return err; -} - -static struct bus_type svm_bus_type = { - .name = "svm_bus", -}; - -static int svm_open(struct inode *inode, struct file *file) -{ - return 0; -} - -static int svm_proc_load_flag(int __user *arg) -{ - static atomic_t l2buf_load_flag = ATOMIC_INIT(0); - int flag; - - if (!acpi_disabled) - return -EPERM; - - if (arg == NULL) - return -EINVAL; - - if (0 == (atomic_cmpxchg(&l2buf_load_flag, 0, 1))) - flag = 0; - else - flag = 1; - - return put_user(flag, arg); -} - -static int svm_mmap(struct file *file, struct vm_area_struct *vma) -{ - int err; - struct svm_device *sdev = file_to_sdev(file); - - if (!acpi_disabled) - return -EPERM; - - if (vma->vm_flags & VM_PA32BIT) { - unsigned long vm_size = vma->vm_end - vma->vm_start; - struct page *page = NULL; - - if ((vma->vm_end < vma->vm_start) || (vm_size > MMAP_PHY32_MAX)) - return -EINVAL; - - /* vma->vm_pgoff transfer the nid */ - if (vma->vm_pgoff == 0) - page = alloc_pages(GFP_KERNEL | GFP_DMA32, - get_order(vm_size)); - else - page = alloc_pages_node((int)vma->vm_pgoff, - GFP_KERNEL | __GFP_THISNODE, - get_order(vm_size)); - if (!page) { - dev_err(sdev->dev, "fail to alloc page on node 0x%lx\n", - vma->vm_pgoff); - return -ENOMEM; - } - - err = remap_pfn_range(vma, - vma->vm_start, - page_to_pfn(page), - vm_size, vma->vm_page_prot); - if (err) - dev_err(sdev->dev, - "fail to remap 0x%pK err=%d\n", - (void *)vma->vm_start, err); - } else { - if ((vma->vm_end < vma->vm_start) || - ((vma->vm_end - vma->vm_start) > sdev->l2size)) - return -EINVAL; - - vma->vm_page_prot = __pgprot((~PTE_SHARED) & - vma->vm_page_prot.pgprot); - - err = remap_pfn_range(vma, - vma->vm_start, - sdev->l2buff >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - __pgprot(vma->vm_page_prot.pgprot | PTE_DIRTY)); - if (err) - dev_err(sdev->dev, - "fail to remap 0x%pK err=%d\n", - (void *)vma->vm_start, err); - } - - return err; -} - -static int svm_release_phys32(unsigned long __user *arg) -{ - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma = NULL; - struct page *page = NULL; - pte_t *pte = NULL; - unsigned long phys, addr, offset; - unsigned int len = 0; - - if (arg == NULL) - return -EINVAL; - - if (get_user(addr, arg)) - return -EFAULT; - - down_read(&mm->mmap_lock); - pte = svm_walk_pt(addr, NULL, &offset); - if (pte && pte_present(*pte)) { - phys = PFN_PHYS(pte_pfn(*pte)) + offset; - } else { - up_read(&mm->mmap_lock); - return -EINVAL; - } - - vma = find_vma(mm, addr); - if (!vma) { - up_read(&mm->mmap_lock); - return -EFAULT; - } - - page = phys_to_page(phys); - len = vma->vm_end - vma->vm_start; - - __free_pages(page, get_order(len)); - - up_read(&mm->mmap_lock); - - return 0; -} - -static long svm_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int err = -EINVAL; - struct svm_bind_process params; - struct svm_device *sdev = file_to_sdev(file); - struct task_struct *task; - - if (!arg) - return -EINVAL; - - if (cmd == SVM_IOCTL_PROCESS_BIND) { - err = copy_from_user(¶ms, (void __user *)arg, - sizeof(params)); - if (err) { - dev_err(sdev->dev, "fail to copy params %d\n", err); - return -EFAULT; - } - } - - switch (cmd) { - case SVM_IOCTL_PROCESS_BIND: - task = svm_get_task(params); - if (IS_ERR(task)) { - dev_err(sdev->dev, "failed to get task\n"); - return PTR_ERR(task); - } - - err = svm_process_bind(task, sdev, ¶ms.ttbr, - ¶ms.tcr, ¶ms.pasid); - if (err) { - put_task_struct(task); - dev_err(sdev->dev, "failed to bind task %d\n", err); - return err; - } - - put_task_struct(task); - err = copy_to_user((void __user *)arg, ¶ms, - sizeof(params)); - if (err) { - dev_err(sdev->dev, "failed to copy to user!\n"); - return -EFAULT; - } - break; - case SVM_IOCTL_GET_PHYS: - err = svm_get_phys((unsigned long __user *)arg); - break; - case SVM_IOCTL_PIN_MEMORY: - err = svm_pin_memory((unsigned long __user *)arg); - break; - case SVM_IOCTL_UNPIN_MEMORY: - err = svm_unpin_memory((unsigned long __user *)arg); - break; - case SVM_IOCTL_LOAD_FLAG: - err = svm_proc_load_flag((int __user *)arg); - break; - case SVM_IOCTL_RELEASE_PHYS32: - err = svm_release_phys32((unsigned long __user *)arg); - break; - default: - err = -EINVAL; - } - - if (err) - dev_err(sdev->dev, "%s: %s failed err = %d\n", __func__, - svm_cmd_to_string(cmd), err); - - return err; -} - -static const struct file_operations svm_fops = { - .owner = THIS_MODULE, - .open = svm_open, - .mmap = svm_mmap, - .unlocked_ioctl = svm_ioctl, -}; - -static void cdev_device_release(struct device *dev) -{ - struct core_device *cdev = to_core_device(dev); - - if (!acpi_disabled) - list_del(&cdev->entry); - - kfree(cdev); -} - -static int svm_remove_core(struct device *dev, void *data) -{ - struct core_device *cdev = to_core_device(dev); - - if (!cdev->smmu_bypass) { - iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA); - iommu_detach_group(cdev->domain, cdev->group); - iommu_group_put(cdev->group); - iommu_domain_free(cdev->domain); - } - - device_unregister(&cdev->dev); - - return 0; -} - -#ifdef CONFIG_ACPI -static int svm_acpi_add_core(struct svm_device *sdev, - struct acpi_device *children, int id) -{ - int err; - struct core_device *cdev = NULL; - char *name = NULL; - enum dev_dma_attr attr; - const union acpi_object *obj; - - name = devm_kasprintf(sdev->dev, GFP_KERNEL, "svm_child_dev%d", id); - if (name == NULL) - return -ENOMEM; - - cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); - if (cdev == NULL) - return -ENOMEM; - cdev->dev.fwnode = &children->fwnode; - cdev->dev.parent = sdev->dev; - cdev->dev.bus = &svm_bus_type; - cdev->dev.release = cdev_device_release; - cdev->smmu_bypass = 0; - list_add(&cdev->entry, &child_list); - dev_set_name(&cdev->dev, "%s", name); - - err = device_register(&cdev->dev); - if (err) { - dev_info(&cdev->dev, "core_device register failed\n"); - list_del(&cdev->entry); - kfree(cdev); - return err; - } - - attr = device_get_dma_attr(&children->dev); - if (attr != DEV_DMA_NOT_SUPPORTED) { - err = acpi_dma_configure(&cdev->dev, attr); - if (err) { - dev_dbg(&cdev->dev, "acpi_dma_configure failed\n"); - return err; - } - } - - err = acpi_dev_get_property(children, "hisi,smmu-bypass", - DEV_PROP_U8, &obj); - if (err) - dev_info(&children->dev, "read smmu bypass failed\n"); - - cdev->smmu_bypass = *(u8 *)obj->integer.value; - - cdev->group = iommu_group_get(&cdev->dev); - if (IS_ERR_OR_NULL(cdev->group)) { - dev_err(&cdev->dev, "smmu is not right configured\n"); - return -ENXIO; - } - - cdev->domain = iommu_domain_alloc(sdev->dev->bus); - if (cdev->domain == NULL) { - dev_info(&cdev->dev, "failed to alloc domain\n"); - return -ENOMEM; - } - - err = iommu_attach_group(cdev->domain, cdev->group); - if (err) { - dev_err(&cdev->dev, "failed group to domain\n"); - return err; - } - - err = iommu_dev_enable_feature(&cdev->dev, IOMMU_DEV_FEAT_IOPF); - if (err) { - dev_err(&cdev->dev, "failed to enable iopf feature, %d\n", err); - return err; - } - - err = iommu_dev_enable_feature(&cdev->dev, IOMMU_DEV_FEAT_SVA); - if (err) { - dev_err(&cdev->dev, "failed to enable sva feature\n"); - return err; - } - - return 0; -} - -static int svm_acpi_init_core(struct svm_device *sdev) -{ - int err = 0; - struct device *dev = sdev->dev; - struct acpi_device *adev = ACPI_COMPANION(sdev->dev); - struct acpi_device *cdev = NULL; - int id = 0; - - down_write(&svm_sem); - if (!svm_bus_type.iommu_ops) { - err = bus_register(&svm_bus_type); - if (err) { - up_write(&svm_sem); - dev_err(dev, "failed to register svm_bus_type\n"); - return err; - } - - err = bus_set_iommu(&svm_bus_type, dev->bus->iommu_ops); - if (err) { - up_write(&svm_sem); - dev_err(dev, "failed to set iommu for svm_bus_type\n"); - goto err_unregister_bus; - } - } else if (svm_bus_type.iommu_ops != dev->bus->iommu_ops) { - err = -EBUSY; - up_write(&svm_sem); - dev_err(dev, "iommu_ops configured, but changed!\n"); - return err; - } - up_write(&svm_sem); - - list_for_each_entry(cdev, &adev->children, node) { - err = svm_acpi_add_core(sdev, cdev, id++); - if (err) - device_for_each_child(dev, NULL, svm_remove_core); - } - - return err; - -err_unregister_bus: - bus_unregister(&svm_bus_type); - - return err; -} -#else -static int svm_acpi_init_core(struct svm_device *sdev) { return 0; } -#endif - -static int svm_of_add_core(struct svm_device *sdev, struct device_node *np) -{ - int err; - struct resource res; - struct core_device *cdev = NULL; - char *name = NULL; - - name = devm_kasprintf(sdev->dev, GFP_KERNEL, "svm%llu_%s", - sdev->id, np->name); - if (name == NULL) - return -ENOMEM; - - cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); - if (cdev == NULL) - return -ENOMEM; - - cdev->dev.of_node = np; - cdev->dev.parent = sdev->dev; - cdev->dev.bus = &svm_bus_type; - cdev->dev.release = cdev_device_release; - cdev->smmu_bypass = of_property_read_bool(np, "hisi,smmu_bypass"); - dev_set_name(&cdev->dev, "%s", name); - - err = device_register(&cdev->dev); - if (err) { - dev_info(&cdev->dev, "core_device register failed\n"); - kfree(cdev); - return err; - } - - err = of_dma_configure(&cdev->dev, np, true); - if (err) { - dev_dbg(&cdev->dev, "of_dma_configure failed\n"); - return err; - } - - err = of_address_to_resource(np, 0, &res); - if (err) { - dev_info(&cdev->dev, "no reg, FW should install the sid\n"); - } else { - /* If the reg specified, install sid for the core */ - void __iomem *core_base = NULL; - int sid = cdev->dev.iommu->fwspec->ids[0]; - - core_base = ioremap(res.start, resource_size(&res)); - if (core_base == NULL) { - dev_err(&cdev->dev, "ioremap failed\n"); - return -ENOMEM; - } - - writel_relaxed(sid, core_base + CORE_SID); - iounmap(core_base); - } - - cdev->group = iommu_group_get(&cdev->dev); - if (IS_ERR_OR_NULL(cdev->group)) { - dev_err(&cdev->dev, "smmu is not right configured\n"); - return -ENXIO; - } - - cdev->domain = iommu_domain_alloc(sdev->dev->bus); - if (cdev->domain == NULL) { - dev_info(&cdev->dev, "failed to alloc domain\n"); - return -ENOMEM; - } - - err = iommu_attach_group(cdev->domain, cdev->group); - if (err) { - dev_err(&cdev->dev, "failed group to domain\n"); - return err; - } - - err = iommu_dev_enable_feature(&cdev->dev, IOMMU_DEV_FEAT_IOPF); - if (err) { - dev_err(&cdev->dev, "failed to enable iopf feature, %d\n", err); - return err; - } - - err = iommu_dev_enable_feature(&cdev->dev, IOMMU_DEV_FEAT_SVA); - if (err) { - dev_err(&cdev->dev, "failed to enable sva feature, %d\n", err); - return err; - } - - return 0; -} - -static int svm_dt_init_core(struct svm_device *sdev, struct device_node *np) -{ - int err = 0; - struct device_node *child = NULL; - struct device *dev = sdev->dev; - - down_write(&svm_sem); - if (svm_bus_type.iommu_ops == NULL) { - err = bus_register(&svm_bus_type); - if (err) { - up_write(&svm_sem); - dev_err(dev, "failed to register svm_bus_type\n"); - return err; - } - - err = bus_set_iommu(&svm_bus_type, dev->bus->iommu_ops); - if (err) { - up_write(&svm_sem); - dev_err(dev, "failed to set iommu for svm_bus_type\n"); - goto err_unregister_bus; - } - } else if (svm_bus_type.iommu_ops != dev->bus->iommu_ops) { - err = -EBUSY; - up_write(&svm_sem); - dev_err(dev, "iommu_ops configured, but changed!\n"); - return err; - } - up_write(&svm_sem); - - for_each_available_child_of_node(np, child) { - err = svm_of_add_core(sdev, child); - if (err) - device_for_each_child(dev, NULL, svm_remove_core); - } - - return err; - -err_unregister_bus: - bus_unregister(&svm_bus_type); - - return err; -} - -int svm_get_pasid(pid_t vpid, int dev_id __maybe_unused) -{ - int pasid; - unsigned long asid; - struct task_struct *task = NULL; - struct mm_struct *mm = NULL; - struct svm_process *process = NULL; - struct svm_bind_process params; - - params.flags = SVM_BIND_PID; - params.vpid = vpid; - params.pasid = -1; - params.ttbr = 0; - params.tcr = 0; - task = svm_get_task(params); - if (IS_ERR(task)) - return PTR_ERR(task); - - mm = get_task_mm(task); - if (mm == NULL) { - pasid = -EINVAL; - goto put_task; - } - - asid = arm64_mm_context_get(mm); - if (!asid) { - pasid = -ENOSPC; - goto put_mm; - } - - mutex_lock(&svm_process_mutex); - process = find_svm_process(asid); - mutex_unlock(&svm_process_mutex); - if (process) - pasid = process->pasid; - else - pasid = -ESRCH; - - arm64_mm_context_put(mm); -put_mm: - mmput(mm); -put_task: - put_task_struct(task); - - return pasid; -} -EXPORT_SYMBOL_GPL(svm_get_pasid); - -static int svm_dt_setup_l2buff(struct svm_device *sdev, struct device_node *np) -{ - struct device_node *l2buff = of_parse_phandle(np, "memory-region", 0); - - if (l2buff) { - struct resource r; - int err = of_address_to_resource(l2buff, 0, &r); - - if (err) { - of_node_put(l2buff); - return err; - } - - sdev->l2buff = r.start; - sdev->l2size = resource_size(&r); - } - - of_node_put(l2buff); - return 0; -} - -static int svm_device_probe(struct platform_device *pdev) -{ - int err = -1; - struct device *dev = &pdev->dev; - struct svm_device *sdev = NULL; - struct device_node *np = dev->of_node; - int alias_id; - - if (acpi_disabled && np == NULL) - return -ENODEV; - - if (!dev->bus) { - dev_dbg(dev, "this dev bus is NULL\n"); - return -EPROBE_DEFER; - } - - if (!dev->bus->iommu_ops) { - dev_dbg(dev, "defer probe svm device\n"); - return -EPROBE_DEFER; - } - - sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL); - if (sdev == NULL) - return -ENOMEM; - - if (!acpi_disabled) { - err = device_property_read_u64(dev, "svmid", &sdev->id); - if (err) { - dev_err(dev, "failed to get this svm device id\n"); - return err; - } - } else { - alias_id = of_alias_get_id(np, "svm"); - if (alias_id < 0) - sdev->id = probe_index; - else - sdev->id = alias_id; - } - - sdev->dev = dev; - sdev->miscdev.minor = MISC_DYNAMIC_MINOR; - sdev->miscdev.fops = &svm_fops; - sdev->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, - SVM_DEVICE_NAME"%llu", sdev->id); - if (sdev->miscdev.name == NULL) - return -ENOMEM; - - dev_set_drvdata(dev, sdev); - err = misc_register(&sdev->miscdev); - if (err) { - dev_err(dev, "Unable to register misc device\n"); - return err; - } - - if (!acpi_disabled) { - err = svm_acpi_init_core(sdev); - if (err) { - dev_err(dev, "failed to init acpi cores\n"); - goto err_unregister_misc; - } - } else { - /* - * Get the l2buff phys address and size, if it do not exist - * just warn and continue, and runtime can not use L2BUFF. - */ - err = svm_dt_setup_l2buff(sdev, np); - if (err) - dev_warn(dev, "Cannot get l2buff\n"); - - if (svm_va2pa_trunk_init(dev)) { - dev_err(dev, "failed to init va2pa trunk\n"); - goto err_unregister_misc; - } - - err = svm_dt_init_core(sdev, np); - if (err) { - dev_err(dev, "failed to init dt cores\n"); - goto err_remove_trunk; - } - - probe_index++; - } - - mutex_init(&svm_process_mutex); - - return err; - -err_remove_trunk: - svm_remove_trunk(dev); - -err_unregister_misc: - misc_deregister(&sdev->miscdev); - - return err; -} - -static int svm_device_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct svm_device *sdev = dev_get_drvdata(dev); - - device_for_each_child(sdev->dev, NULL, svm_remove_core); - misc_deregister(&sdev->miscdev); - - return 0; -} - -static const struct acpi_device_id svm_acpi_match[] = { - { "HSVM1980", 0}, - { } -}; -MODULE_DEVICE_TABLE(acpi, svm_acpi_match); - -static const struct of_device_id svm_of_match[] = { - { .compatible = "hisilicon,svm" }, - { } -}; -MODULE_DEVICE_TABLE(of, svm_of_match); - -/*svm acpi probe and remove*/ -static struct platform_driver svm_driver = { - .probe = svm_device_probe, - .remove = svm_device_remove, - .driver = { - .name = SVM_DEVICE_NAME, - .acpi_match_table = ACPI_PTR(svm_acpi_match), - .of_match_table = svm_of_match, - }, -}; - -module_platform_driver(svm_driver); - -MODULE_DESCRIPTION("Hisilicon SVM driver"); -MODULE_AUTHOR("Fang Lijun <fanglijun3@huawei.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/fs/io_uring.c b/fs/io_uring.c index 3ccd34f4d134afbae03ed90e9e637ff6e3ad70c1..21adb7ff7b2e1f19baa9319197f6441f80bc3fc7 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -935,7 +935,7 @@ static const struct io_op_def io_op_defs[] = { .needs_file = 1, .hash_reg_file = 1, .unbound_nonreg_file = 1, - .work_flags = IO_WQ_WORK_BLKCG, + .work_flags = IO_WQ_WORK_BLKCG | IO_WQ_WORK_FILES, }, [IORING_OP_PROVIDE_BUFFERS] = {}, [IORING_OP_REMOVE_BUFFERS] = {}, @@ -5233,6 +5233,11 @@ static __poll_t __io_arm_poll_handler(struct io_kiocb *req, struct io_ring_ctx *ctx = req->ctx; bool cancel = false; + if (req->file->f_op->may_pollfree) { + spin_lock_irq(&ctx->completion_lock); + return -EOPNOTSUPP; + } + INIT_HLIST_NODE(&req->hash_node); io_init_poll_iocb(poll, mask, wake_func); poll->file = req->file; diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index fbc52a65af9975b35d11baa52e5c706769411314..d9b71c2f20f1fa952b0dbc8b89ba08ab523d5e40 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -1455,13 +1455,6 @@ iomap_do_writepage(struct page *page, struct writeback_control *wbc, void *data) PF_MEMALLOC)) goto redirty; - /* - * Given that we do not allow direct reclaim to call us, we should - * never be called in a recursive filesystem reclaim context. - */ - if (WARN_ON_ONCE(current->flags & PF_MEMALLOC_NOFS)) - goto redirty; - /* * Is this page beyond the end of the file? * diff --git a/fs/ksmbd/auth.c b/fs/ksmbd/auth.c index fc87c9913c8d96bd0aa9a6e00578886292f6f50f..0ac85a1a63c0572fc9057370ecab3de2d2621b93 100644 --- a/fs/ksmbd/auth.c +++ b/fs/ksmbd/auth.c @@ -321,7 +321,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob, dn_off = le32_to_cpu(authblob->DomainName.BufferOffset); dn_len = le16_to_cpu(authblob->DomainName.Length); - if (blob_len < (u64)dn_off + dn_len || blob_len < (u64)nt_off + nt_len) + if (blob_len < (u64)dn_off + dn_len || blob_len < (u64)nt_off + nt_len || + nt_len < CIFS_ENCPWD_SIZE) return -EINVAL; /* TODO : use domain name that imported from configuration file */ diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index e8c00dda42adbbff372908fdcb3d7d6814567cdf..4e74bc8f01edeceb2463e6767a9862475319cef9 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -1949,7 +1949,7 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size) return -ENOENT; if (!attr_b->non_res) { - u32 data_size = le32_to_cpu(attr->res.data_size); + u32 data_size = le32_to_cpu(attr_b->res.data_size); u32 from, to; if (vbo > data_size) diff --git a/fs/signalfd.c b/fs/signalfd.c index b94fb5f81797a6ab74914da7e95597d3ee343e46..41dc597b78cc6392294d4b1afe5683e150da93e1 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -248,6 +248,7 @@ static const struct file_operations signalfd_fops = { .poll = signalfd_poll, .read = signalfd_read, .llseek = noop_llseek, + .may_pollfree = true, }; static int do_signalfd4(int ufd, sigset_t *mask, int flags) diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 98c82f4935e1e7835c5be71a5f7d76d32824b335..24c7d30e41dfee71b5885ae4b76608d45378a370 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -2811,7 +2811,7 @@ xfs_btree_split_worker( struct xfs_btree_split_args *args = container_of(work, struct xfs_btree_split_args, work); unsigned long pflags; - unsigned long new_pflags = PF_MEMALLOC_NOFS; + unsigned long new_pflags = 0; /* * we are in a transaction context here, but may also be doing work @@ -2823,12 +2823,20 @@ xfs_btree_split_worker( new_pflags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD; current_set_flags_nested(&pflags, new_pflags); + xfs_trans_set_context(args->cur->bc_tp); args->result = __xfs_btree_split(args->cur, args->level, args->ptrp, args->key, args->curp, args->stat); - complete(args->done); + xfs_trans_clear_context(args->cur->bc_tp); current_restore_flags_nested(&pflags, new_pflags); + + /* + * Do not access args after complete() has run here. We don't own args + * and the owner may run and free args before we return here. + */ + complete(args->done); + } /* diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 7aa67d95c578dfe438ec3f5a374582f8e2cd7b5a..e341d6531e687ce94c863bb82214546c6bdeaea0 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -98,7 +98,7 @@ xfs_setfilesize_ioend( * thus we need to mark ourselves as being in a transaction manually. * Similarly for freeze protection. */ - current_set_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); + xfs_trans_set_context(tp); __sb_writers_acquired(VFS_I(ip)->i_sb, SB_FREEZE_FS); /* we abort the update if there was an IO error */ @@ -538,6 +538,12 @@ xfs_vm_writepage( { struct xfs_writepage_ctx wpc = { }; + if (WARN_ON_ONCE(current->journal_info)) { + redirty_page_for_writepage(wbc, page); + unlock_page(page); + return 0; + } + return iomap_writepage(page, wbc, &wpc.ctx, &xfs_writeback_ops); } @@ -548,6 +554,13 @@ xfs_vm_writepages( { struct xfs_writepage_ctx wpc = { }; + /* + * Writing back data in a transaction context can result in recursive + * transactions. This is bad, so issue a warning and get out of here. + */ + if (WARN_ON_ONCE(current->journal_info)) + return 0; + xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED); return iomap_writepages(mapping, wbc, &wpc.ctx, &xfs_writeback_ops); } diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 2741dbd22704568900974cb0d116fc2ded585983..81cb2b3b20f2df0a9795815fd2267024369ee524 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -374,46 +374,36 @@ xfs_reserve_blocks( * If the request is larger than the current reservation, reserve the * blocks before we update the reserve counters. Sample m_fdblocks and * perform a partial reservation if the request exceeds free space. + * + * The code below estimates how many blocks it can request from + * fdblocks to stash in the reserve pool. This is a classic TOCTOU + * race since fdblocks updates are not always coordinated via + * m_sb_lock. Set the reserve size even if there's not enough free + * space to fill it because mod_fdblocks will refill an undersized + * reserve when it can. */ - error = -ENOSPC; - do { - free = percpu_counter_sum(&mp->m_fdblocks) - - mp->m_alloc_set_aside; - if (free <= 0) - break; - - delta = request - mp->m_resblks; - lcounter = free - delta; - if (lcounter < 0) - /* We can't satisfy the request, just get what we can */ - fdblks_delta = free; - else - fdblks_delta = delta; - + free = percpu_counter_sum(&mp->m_fdblocks) - + xfs_fdblocks_unavailable(mp); + delta = request - mp->m_resblks; + mp->m_resblks = request; + if (delta > 0 && free > 0) { /* * We'll either succeed in getting space from the free block - * count or we'll get an ENOSPC. If we get a ENOSPC, it means - * things changed while we were calculating fdblks_delta and so - * we should try again to see if there is anything left to - * reserve. + * count or we'll get an ENOSPC. Don't set the reserved flag + * here - we don't want to reserve the extra reserve blocks + * from the reserve. * - * Don't set the reserved flag here - we don't want to reserve - * the extra reserve blocks from the reserve..... + * The desired reserve size can change after we drop the lock. + * Use mod_fdblocks to put the space into the reserve or into + * fdblocks as appropriate. */ + fdblks_delta = min(free, delta); spin_unlock(&mp->m_sb_lock); error = xfs_mod_fdblocks(mp, -fdblks_delta, 0); + if (!error) + xfs_mod_fdblocks(mp, fdblks_delta, 0); spin_lock(&mp->m_sb_lock); - } while (error == -ENOSPC); - - /* - * Update the reserve counters if blocks have been successfully - * allocated. - */ - if (!error && fdblks_delta) { - mp->m_resblks += fdblks_delta; - mp->m_resblks_avail += fdblks_delta; } - out: if (outval) { outval->resblks = mp->m_resblks; diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 46dba3289d10cb60bab8cdd31f0499c996f4ab78..91a66b7b88151f1e825f98e9569248257a1208f4 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -467,6 +467,14 @@ extern void xfs_unmountfs(xfs_mount_t *); */ #define XFS_FDBLOCKS_BATCH 1024 +/* Accessor added for 5.10.y backport */ +static inline uint64_t +xfs_fdblocks_unavailable( + struct xfs_mount *mp) +{ + return mp->m_alloc_set_aside; +} + extern int xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta, bool reserved); extern int xfs_mod_frextents(struct xfs_mount *mp, int64_t delta); diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index e8a9967e71942a1e1a371b26ee6cb0a5b85e205e..8836bb02d82d16fa53ce0b5befddff44659783a2 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -72,6 +72,7 @@ xfs_trans_free( xfs_extent_busy_clear(tp->t_mountp, &tp->t_busy, false); trace_xfs_trans_free(tp, _RET_IP_); + xfs_trans_clear_context(tp); if (!(tp->t_flags & XFS_TRANS_NO_WRITECOUNT)) sb_end_intwrite(tp->t_mountp->m_super); xfs_trans_free_dqinfo(tp); @@ -123,7 +124,8 @@ xfs_trans_dup( ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; tp->t_rtx_res = tp->t_rtx_res_used; - ntp->t_pflags = tp->t_pflags; + + xfs_trans_switch_context(tp, ntp); /* move deferred ops over to the new tp */ xfs_defer_move(ntp, tp); @@ -157,9 +159,6 @@ xfs_trans_reserve( int error = 0; bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; - /* Mark this thread as being in a transaction */ - current_set_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); - /* * Attempt to reserve the needed disk blocks by decrementing * the number needed from the number available. This will @@ -167,10 +166,8 @@ xfs_trans_reserve( */ if (blocks > 0) { error = xfs_mod_fdblocks(mp, -((int64_t)blocks), rsvd); - if (error != 0) { - current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); + if (error != 0) return -ENOSPC; - } tp->t_blk_res += blocks; } @@ -244,9 +241,6 @@ xfs_trans_reserve( xfs_mod_fdblocks(mp, (int64_t)blocks, rsvd); tp->t_blk_res = 0; } - - current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); - return error; } @@ -272,6 +266,7 @@ xfs_trans_alloc( tp = kmem_cache_zalloc(xfs_trans_zone, GFP_KERNEL | __GFP_NOFAIL); if (!(flags & XFS_TRANS_NO_WRITECOUNT)) sb_start_intwrite(mp->m_super); + xfs_trans_set_context(tp); /* * Zero-reservation ("empty") transactions can't modify anything, so @@ -893,7 +888,6 @@ __xfs_trans_commit( xlog_cil_commit(mp->m_log, tp, &commit_seq, regrant); - current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); xfs_trans_free(tp); /* @@ -925,7 +919,6 @@ __xfs_trans_commit( xfs_log_ticket_ungrant(mp->m_log, tp->t_ticket); tp->t_ticket = NULL; } - current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); xfs_trans_free_items(tp, !!error); xfs_trans_free(tp); @@ -985,9 +978,6 @@ xfs_trans_cancel( tp->t_ticket = NULL; } - /* mark this thread as no longer being in a transaction */ - current_restore_flags_nested(&tp->t_pflags, PF_MEMALLOC_NOFS); - xfs_trans_free_items(tp, dirty); xfs_trans_free(tp); } diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index f95566fe981b785f49f7bca4dfd4f1e14edf7449..50da47f23a0772af77cd36ec1c4f44fd7ba53d91 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -266,4 +266,34 @@ int xfs_trans_alloc_ichange(struct xfs_inode *ip, struct xfs_dquot *udqp, struct xfs_dquot *gdqp, struct xfs_dquot *pdqp, bool force, struct xfs_trans **tpp); +static inline void +xfs_trans_set_context( + struct xfs_trans *tp) +{ + ASSERT(current->journal_info == NULL); + tp->t_pflags = memalloc_nofs_save(); + current->journal_info = tp; +} + +static inline void +xfs_trans_clear_context( + struct xfs_trans *tp) +{ + if (current->journal_info == tp) { + memalloc_nofs_restore(tp->t_pflags); + current->journal_info = NULL; + } +} + +static inline void +xfs_trans_switch_context( + struct xfs_trans *old_tp, + struct xfs_trans *new_tp) +{ + ASSERT(current->journal_info == old_tp); + new_tp->t_pflags = old_tp->t_pflags; + old_tp->t_pflags = 0; + current->journal_info = new_tp; +} + #endif /* __XFS_TRANS_H__ */ diff --git a/include/linux/fault-inject.h b/include/linux/fault-inject.h index d506ee960ffdc70f1ee45bb9f90c46d5229efbf8..ff27c006732f0d5e3ea6b52a0b5e19615ac9fcf0 100644 --- a/include/linux/fault-inject.h +++ b/include/linux/fault-inject.h @@ -20,7 +20,6 @@ struct fault_attr { atomic_t space; unsigned long verbose; bool task_filter; - bool no_warn; unsigned long stacktrace_depth; unsigned long require_start; unsigned long require_end; @@ -32,6 +31,10 @@ struct fault_attr { struct dentry *dname; }; +enum fault_flags { + FAULT_NOWARN = 1 << 0, +}; + #define FAULT_ATTR_INITIALIZER { \ .interval = 1, \ .times = ATOMIC_INIT(1), \ @@ -40,11 +43,11 @@ struct fault_attr { .ratelimit_state = RATELIMIT_STATE_INIT_DISABLED, \ .verbose = 2, \ .dname = NULL, \ - .no_warn = false, \ } #define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER int setup_fault_attr(struct fault_attr *attr, char *str); +bool should_fail_ex(struct fault_attr *attr, ssize_t size, int flags); bool should_fail(struct fault_attr *attr, ssize_t size); #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS diff --git a/include/linux/fs.h b/include/linux/fs.h index 45ea1243118cd1ed6b5f4f15eac7fdb3212228c5..98236a86cca0c3871c62038068214cfb8647bb4b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1899,7 +1899,7 @@ struct file_operations { loff_t len, unsigned int remap_flags); int (*fadvise)(struct file *, loff_t, loff_t, int); - KABI_RESERVE(1) + KABI_USE(1, bool may_pollfree) KABI_RESERVE(2) KABI_RESERVE(3) KABI_RESERVE(4) diff --git a/kernel/trace/trace_osnoise.c b/kernel/trace/trace_osnoise.c index cfb80feb291ecd946b3469a605d2af2399272c4f..d23304b7f12cd221a065a7dea0c077c20a6620f3 100644 --- a/kernel/trace/trace_osnoise.c +++ b/kernel/trace/trace_osnoise.c @@ -2103,6 +2103,13 @@ static int osnoise_hook_events(void) return -EINVAL; } +static void osnoise_unhook_events(void) +{ + unhook_thread_events(); + unhook_softirq_events(); + unhook_irq_events(); +} + /* * osnoise_workload_start - start the workload and hook to events */ @@ -2135,7 +2142,14 @@ static int osnoise_workload_start(void) retval = start_per_cpu_kthreads(); if (retval) { - unhook_irq_events(); + trace_osnoise_callback_enabled = false; + /* + * Make sure that ftrace_nmi_enter/exit() see + * trace_osnoise_callback_enabled as false before continuing. + */ + barrier(); + + osnoise_unhook_events(); return retval; } @@ -2157,6 +2171,17 @@ static void osnoise_workload_stop(void) if (osnoise_has_registered_instances()) return; + /* + * If callbacks were already disabled in a previous stop + * call, there is no need to disable then again. + * + * For instance, this happens when tracing is stopped via: + * echo 0 > tracing_on + * echo nop > current_tracer. + */ + if (!trace_osnoise_callback_enabled) + return; + trace_osnoise_callback_enabled = false; /* * Make sure that ftrace_nmi_enter/exit() see @@ -2166,9 +2191,7 @@ static void osnoise_workload_stop(void) stop_per_cpu_kthreads(); - unhook_irq_events(); - unhook_softirq_events(); - unhook_thread_events(); + osnoise_unhook_events(); } static void osnoise_tracer_start(struct trace_array *tr) diff --git a/lib/fault-inject.c b/lib/fault-inject.c index 423784d9c058eaf7d8833eade65bd389bd6a993e..70768d8a2200ba040a049d4d2f4a88f4b76977df 100644 --- a/lib/fault-inject.c +++ b/lib/fault-inject.c @@ -41,9 +41,6 @@ EXPORT_SYMBOL_GPL(setup_fault_attr); static void fail_dump(struct fault_attr *attr) { - if (attr->no_warn) - return; - if (attr->verbose > 0 && __ratelimit(&attr->ratelimit_state)) { printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure.\n" "name %pd, interval %lu, probability %lu, " @@ -103,7 +100,7 @@ static inline bool fail_stacktrace(struct fault_attr *attr) * http://www.nongnu.org/failmalloc/ */ -bool should_fail(struct fault_attr *attr, ssize_t size) +bool should_fail_ex(struct fault_attr *attr, ssize_t size, int flags) { if (in_task()) { unsigned int fail_nth = READ_ONCE(current->fail_nth); @@ -146,13 +143,19 @@ bool should_fail(struct fault_attr *attr, ssize_t size) return false; fail: - fail_dump(attr); + if (!(flags & FAULT_NOWARN)) + fail_dump(attr); if (atomic_read(&attr->times) != -1) atomic_dec_not_zero(&attr->times); return true; } + +bool should_fail(struct fault_attr *attr, ssize_t size) +{ + return should_fail_ex(attr, size, 0); +} EXPORT_SYMBOL_GPL(should_fail); #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS diff --git a/mm/failslab.c b/mm/failslab.c index 58df9789f1d22627f569e92d527c50068f276062..ffc420c0e767f097380e587cb833eb495a484d49 100644 --- a/mm/failslab.c +++ b/mm/failslab.c @@ -16,6 +16,8 @@ static struct { bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags) { + int flags = 0; + /* No fault-injection for bootstrap cache */ if (unlikely(s == kmem_cache)) return false; @@ -30,10 +32,16 @@ bool __should_failslab(struct kmem_cache *s, gfp_t gfpflags) if (failslab.cache_filter && !(s->flags & SLAB_FAILSLAB)) return false; + /* + * In some cases, it expects to specify __GFP_NOWARN + * to avoid printing any information(not just a warning), + * thus avoiding deadlocks. See commit 6b9dbedbe349 for + * details. + */ if (gfpflags & __GFP_NOWARN) - failslab.attr.no_warn = true; + flags |= FAULT_NOWARN; - return should_fail(&failslab.attr, s->object_size); + return should_fail_ex(&failslab.attr, s->object_size, flags); } static int __init setup_failslab(char *str) diff --git a/mm/mmap.c b/mm/mmap.c index 568bc1b68faed0ba924c63a650d458908b51ca54..b7a5a135f20db3d28b31218346d6b1451c0d9819 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1479,9 +1479,11 @@ unsigned long __do_mmap_mm(struct mm_struct *mm, struct file *file, pkey = 0; } +#ifdef CONFIG_ASCEND_FEATURES /* Physical address is within 4G */ if (flags & MAP_PA32BIT) vm_flags |= VM_PA32BIT; +#endif /* Do simple checking here so the lower-level routines won't have * to. we assume access permissions have been handled by the open diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 274b68a147eaf9f7a6fb261aa656df619943badd..e1d6903702703f07ddbbb8c519438bb8ee869c64 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3545,6 +3545,8 @@ __setup("fail_page_alloc=", setup_fail_page_alloc); static bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order) { + int flags = 0; + if (order < fail_page_alloc.min_order) return false; if (gfp_mask & __GFP_NOFAIL) @@ -3555,10 +3557,11 @@ static bool __should_fail_alloc_page(gfp_t gfp_mask, unsigned int order) (gfp_mask & __GFP_DIRECT_RECLAIM)) return false; + /* See comment in __should_failslab() */ if (gfp_mask & __GFP_NOWARN) - fail_page_alloc.attr.no_warn = true; + flags |= FAULT_NOWARN; - return should_fail(&fail_page_alloc.attr, 1 << order); + return should_fail_ex(&fail_page_alloc.attr, 1 << order, flags); } #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS