summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-07-23 13:42:58 +0100
committerMark Brown <broonie@kernel.org>2026-07-23 13:43:02 +0100
commitcdae9963d80ffb6351ae94b866d6c05ff456952c (patch)
tree655f312daba7c56c037ce5013ad0816a112b6ce4 /drivers
parentb60d1fe05289a42ca691c26825503cc3d31305e2 (diff)
parent71a7a58818a33631c9518f944cef5ca55aba6537 (diff)
downloadlinux-next-cdae9963d80ffb6351ae94b866d6c05ff456952c.tar.gz
linux-next-cdae9963d80ffb6351ae94b866d6c05ff456952c.zip
Merge branch 'mm-unstable' of https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Diffstat (limited to 'drivers')
-rw-r--r--drivers/accel/amdxdna/aie2_ctx.c23
-rw-r--r--drivers/base/arch_numa.c4
-rw-r--r--drivers/base/memory.c9
-rw-r--r--drivers/char/mem.c8
-rw-r--r--drivers/dax/bus.h2
-rw-r--r--drivers/dax/kmem.c500
-rw-r--r--drivers/gpu/drm/drm_gem.c2
-rw-r--r--drivers/gpu/drm/drm_gem_dma_helper.c2
-rw-r--r--drivers/gpu/drm/drm_gem_shmem_helper.c2
-rw-r--r--drivers/gpu/drm/drm_gpusvm.c60
-rw-r--r--drivers/gpu/drm/drm_pagemap.c2
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem.c5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c6
-rw-r--r--drivers/gpu/drm/gma500/gem.c2
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_mman.c12
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_shmem.c2
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_svm.c20
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem.c11
-rw-r--r--drivers/gpu/drm/panthor/panthor_gem.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_gem.c2
-rw-r--r--drivers/gpu/drm/tegra/gem.c5
-rw-r--r--drivers/gpu/drm/ttm/ttm_backup.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c7
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_vram.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c2
-rw-r--r--drivers/gpu/drm/xe/xe_device.c2
-rw-r--r--drivers/gpu/drm/xe/xe_mmio_gem.c2
-rw-r--r--drivers/gpu/drm/xen/xen_drm_front_gem.c2
-rw-r--r--drivers/hv/mshv_regions.c54
-rw-r--r--drivers/infiniband/core/umem_odp.c18
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c5
-rw-r--r--drivers/net/ethernet/fungible/funeth/funeth_rx.c2
-rw-r--r--drivers/vfio/pci/nvgrace-gpu/main.c3
-rw-r--r--drivers/vfio/pci/vfio_pci_core.c3
-rw-r--r--drivers/video/fbdev/core/fb_io_fops.c2
38 files changed, 502 insertions, 294 deletions
diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c
index 4b3a62aa8798..0a0ff9a10946 100644
--- a/drivers/accel/amdxdna/aie2_ctx.c
+++ b/drivers/accel/amdxdna/aie2_ctx.c
@@ -1047,7 +1047,7 @@ static int aie2_populate_range(struct amdxdna_gem_obj *abo)
bool found;
int ret;
- timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
+ timeout = msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
again:
found = false;
down_write(&xdna->notifier_lock);
@@ -1072,24 +1072,9 @@ again:
return -EFAULT;
}
- mapp->range.notifier_seq = mmu_interval_read_begin(&mapp->notifier);
- mmap_read_lock(mm);
- ret = hmm_range_fault(&mapp->range);
- mmap_read_unlock(mm);
- if (ret) {
- if (time_after(jiffies, timeout)) {
- ret = -ETIME;
- goto put_mm;
- }
-
- if (ret == -EBUSY) {
- amdxdna_umap_put(mapp);
- mmput(mm);
- goto again;
- }
-
+ ret = hmm_range_fault_unlocked_timeout(&mapp->range, timeout);
+ if (ret)
goto put_mm;
- }
down_write(&xdna->notifier_lock);
if (mmu_interval_read_retry(&mapp->notifier, mapp->range.notifier_seq)) {
@@ -1107,7 +1092,7 @@ again:
put_mm:
amdxdna_umap_put(mapp);
mmput(mm);
- return ret;
+ return ret == -EBUSY ? -ETIME : ret;
}
int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, u64 *seq)
diff --git a/drivers/base/arch_numa.c b/drivers/base/arch_numa.c
index c99f2ab105e5..442ea239bba7 100644
--- a/drivers/base/arch_numa.c
+++ b/drivers/base/arch_numa.c
@@ -231,10 +231,6 @@ static int __init numa_init(int (*init_func)(void))
{
int ret;
- nodes_clear(numa_nodes_parsed);
- nodes_clear(node_possible_map);
- nodes_clear(node_online_map);
-
ret = numa_memblks_init(init_func, /* memblock_force_top_down */ false);
if (ret < 0)
goto out_free_distance;
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index bcfe2d9f4adb..5eead3346f1e 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -46,6 +46,15 @@ int mhp_online_type_from_str(const char *str)
}
return -EINVAL;
}
+EXPORT_SYMBOL_GPL(mhp_online_type_from_str);
+
+const char *mhp_online_type_to_str(int online_type)
+{
+ if (online_type < 0 || online_type >= (int)ARRAY_SIZE(online_type_to_str))
+ return NULL;
+ return online_type_to_str[online_type];
+}
+EXPORT_SYMBOL_GPL(mhp_online_type_to_str);
#define to_memory_block(dev) container_of(dev, struct memory_block, dev)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 63253d1de5d7..dcfd896b733d 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -506,11 +506,7 @@ static int mmap_zero_prepare(struct vm_area_desc *desc)
if (vma_desc_test(desc, VMA_SHARED_BIT))
return shmem_zero_setup_desc(desc);
- /*
- * This is a highly unique situation where we mark a MAP_PRIVATE mapping
- * of /dev/zero anonymous, despite it not being.
- */
- vma_desc_set_anonymous(desc);
+ /* MAP_PRIVATE semantics are taken care for us by core mm. */
return 0;
}
@@ -698,7 +694,7 @@ static const struct memdev {
#ifdef CONFIG_DEVPORT
[4] = { "port", &port_fops, 0, 0 },
#endif
- [5] = { "zero", &zero_fops, FMODE_NOWAIT, 0666 },
+ [DEVZERO_MINOR] = { "zero", &zero_fops, FMODE_NOWAIT, 0666 },
[7] = { "full", &full_fops, 0, 0666 },
[8] = { "random", &random_fops, FMODE_NOWAIT, 0666 },
[9] = { "urandom", &urandom_fops, FMODE_NOWAIT, 0666 },
diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h
index 5909171a4428..bfc31923f3ff 100644
--- a/drivers/dax/bus.h
+++ b/drivers/dax/bus.h
@@ -16,6 +16,8 @@ struct dax_region;
#define IORESOURCE_DAX_STATIC BIT(0)
#define IORESOURCE_DAX_KMEM BIT(1)
+#define DAX_KMEM_UNPLUGGED (-1) /* Do not create memory blocks */
+
struct dax_region *alloc_dax_region(struct device *parent, int region_id,
struct range *range, int target_node, unsigned int align,
unsigned long flags);
diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c
index a18e2b968e4d..a48d699cf344 100644
--- a/drivers/dax/kmem.c
+++ b/drivers/dax/kmem.c
@@ -33,9 +33,7 @@ static int dax_kmem_range(struct dev_dax *dev_dax, int i, struct range *r)
struct dev_dax_range *dax_range = &dev_dax->ranges[i];
struct range *range = &dax_range->range;
- /* memory-block align the hotplug range */
- r->start = ALIGN(range->start, memory_block_size_bytes());
- r->end = ALIGN_DOWN(range->end + 1, memory_block_size_bytes()) - 1;
+ *r = memory_block_aligned_range(range);
if (r->start >= r->end) {
r->start = range->start;
r->end = range->end;
@@ -47,6 +45,8 @@ static int dax_kmem_range(struct dev_dax *dev_dax, int i, struct range *r)
struct dax_kmem_data {
const char *res_name;
int mgid;
+ int state;
+ struct mutex lock; /* protects hotplug state transitions */
struct resource *res[];
};
@@ -65,16 +65,331 @@ static void kmem_put_memory_types(void)
mt_put_memory_types(&kmem_memory_types);
}
+/* True for the online states a kmem dax device can hold. */
+static bool dax_kmem_state_is_online(int state)
+{
+ return state == MMOP_ONLINE ||
+ state == MMOP_ONLINE_KERNEL ||
+ state == MMOP_ONLINE_MOVABLE;
+}
+
+/**
+ * dax_kmem_do_hotplug - hotplug memory for dax kmem device
+ * @dev_dax: the dev_dax instance
+ * @data: the dax_kmem_data structure with resource tracking
+ * @online_type: the online policy to use for the memory blocks
+ *
+ * Hotplugs all ranges in the dev_dax region as system memory with the
+ * provided online policy (offline, online, online_movable, online_kernel).
+ *
+ * Returns the number of successfully mapped ranges, or negative error.
+ */
+static int dax_kmem_do_hotplug(struct dev_dax *dev_dax,
+ struct dax_kmem_data *data,
+ int online_type)
+{
+ struct device *dev = &dev_dax->dev;
+ int i, rc, added = 0;
+ mhp_t mhp_flags;
+
+ if (dax_kmem_state_is_online(data->state))
+ return -EINVAL;
+
+ if (online_type < MMOP_OFFLINE || online_type > MMOP_ONLINE_MOVABLE)
+ return -EINVAL;
+
+ for (i = 0; i < dev_dax->nr_range; i++) {
+ struct range range;
+
+ rc = dax_kmem_range(dev_dax, i, &range);
+ if (rc)
+ continue;
+
+ /*
+ * init_resources() is best-effort: if a reservation conflict
+ * occurs it keeps the range but leaves res[i]=NULL. For hotplug
+ * on probe systems, this means kmem will partially online.
+ *
+ * We have to keep this behavior not to break those systems.
+ * For those systems - atomicity only applies to valid ranges.
+ */
+ if (!data->res[i])
+ continue;
+
+ mhp_flags = MHP_NID_IS_MGID;
+ if (dev_dax->memmap_on_memory)
+ mhp_flags |= MHP_MEMMAP_ON_MEMORY;
+
+ /*
+ * Ensure that future kexec'd kernels will not treat
+ * this as RAM automatically.
+ */
+ rc = __add_memory_driver_managed(data->mgid, range.start,
+ range_len(&range), kmem_name, mhp_flags,
+ online_type);
+
+ if (rc) {
+ dev_warn(dev, "mapping%d: %#llx-%#llx memory add failed\n",
+ i, range.start, range.end);
+ /*
+ * Release the reservation for the range that failed to
+ * add so a later hotremove does not try to remove memory
+ * that was never added.
+ */
+ if (data->res[i]) {
+ remove_resource(data->res[i]);
+ kfree(data->res[i]);
+ data->res[i] = NULL;
+ }
+ if (added)
+ continue;
+ return rc;
+ }
+ added++;
+ }
+
+ return added;
+}
+
+/**
+ * dax_kmem_init_resources - create memory regions for dax kmem
+ * @dev_dax: the dev_dax instance
+ * @data: the dax_kmem_data structure with resource tracking
+ *
+ * Initializes all the resources for the DAX
+ *
+ * Returns the number of successfully mapped ranges, or negative error.
+ */
+static int dax_kmem_init_resources(struct dev_dax *dev_dax,
+ struct dax_kmem_data *data)
+{
+ struct device *dev = &dev_dax->dev;
+ int i, rc, mapped = 0;
+
+ for (i = 0; i < dev_dax->nr_range; i++) {
+ struct resource *res;
+ struct range range;
+
+ rc = dax_kmem_range(dev_dax, i, &range);
+ if (rc)
+ continue;
+
+ /* Skip ranges already added */
+ if (data->res[i])
+ continue;
+
+ /* Region is permanently reserved if hotremove fails. */
+ res = request_mem_region(range.start, range_len(&range),
+ data->res_name);
+ if (!res) {
+ dev_warn(dev, "mapping%d: %#llx-%#llx could not reserve region\n",
+ i, range.start, range.end);
+ /*
+ * Once some memory has been onlined we can't
+ * assume that it can be un-onlined safely.
+ */
+ if (mapped)
+ continue;
+ return -EBUSY;
+ }
+ data->res[i] = res;
+ /*
+ * Set flags appropriate for System RAM. Leave ..._BUSY clear
+ * so that add_memory() can add a child resource. Do not
+ * inherit flags from the parent since it may set new flags
+ * unknown to us that will break add_memory() later.
+ */
+ res->flags = IORESOURCE_SYSTEM_RAM;
+ mapped++;
+ }
+ return mapped;
+}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+/**
+ * dax_kmem_do_hotremove - hot-remove memory for dax kmem device
+ * @dev_dax: the dev_dax instance
+ * @data: the dax_kmem_data structure with resource tracking
+ *
+ * Offlines and removes every currently-added range in the dev_dax region
+ * atomically: either all ranges are offlined and removed, or none are and
+ * the device is returned to its prior state.
+ *
+ * Returns 0 on success, or a negative errno on failure.
+ */
+static int dax_kmem_do_hotremove(struct dev_dax *dev_dax,
+ struct dax_kmem_data *data)
+{
+ struct device *dev = &dev_dax->dev;
+ struct range *ranges;
+ int i, nr_ranges = 0, rc;
+
+ ranges = kmalloc_objs(*ranges, dev_dax->nr_range);
+ if (!ranges)
+ return -ENOMEM;
+
+ /* Collect the ranges that were actually added during probe. */
+ for (i = 0; i < dev_dax->nr_range; i++) {
+ struct range range;
+
+ if (!data->res[i])
+ continue;
+ if (dax_kmem_range(dev_dax, i, &range))
+ continue;
+ ranges[nr_ranges++] = range;
+ }
+
+ /* Nothing added means nothing to remove. */
+ if (!nr_ranges) {
+ kfree(ranges);
+ return 0;
+ }
+
+ rc = offline_and_remove_memory_ranges(ranges, nr_ranges);
+ kfree(ranges);
+ if (rc) {
+ /* Recoverable: the ranges rolled back, nothing is leaked yet. */
+ dev_err(dev, "hotremove failed, device left online: %d\n", rc);
+ return rc;
+ }
+
+ /* All ranges removed; release the reserved resources. */
+ for (i = 0; i < dev_dax->nr_range; i++) {
+ if (!data->res[i])
+ continue;
+ remove_resource(data->res[i]);
+ kfree(data->res[i]);
+ data->res[i] = NULL;
+ }
+
+ return 0;
+}
+#else
+static int dax_kmem_do_hotremove(struct dev_dax *dev_dax,
+ struct dax_kmem_data *data)
+{
+ return -EBUSY;
+}
+#endif /* CONFIG_MEMORY_HOTREMOVE */
+
+/**
+ * dax_kmem_cleanup_resources - remove the dax memory resources
+ * @dev_dax: the dev_dax instance
+ * @data: the dax_kmem_data structure with resource tracking
+ *
+ * Removes all resources in the dev_dax region.
+ */
+static void dax_kmem_cleanup_resources(struct dev_dax *dev_dax,
+ struct dax_kmem_data *data)
+{
+ int i;
+
+ /*
+ * If the device unbind occurs before memory is hotremoved, we can never
+ * remove the memory (requires reboot). Attempting an offline operation
+ * here may cause deadlock and a failure to finish the unbind.
+ *
+ * Note: This leaks the resources.
+ */
+ if (WARN(((data->state != DAX_KMEM_UNPLUGGED) &&
+ (data->state != MMOP_OFFLINE)),
+ "Hotplug memory regions stuck online until reboot"))
+ return;
+
+ for (i = 0; i < dev_dax->nr_range; i++) {
+ if (!data->res[i])
+ continue;
+ remove_resource(data->res[i]);
+ kfree(data->res[i]);
+ data->res[i] = NULL;
+ }
+}
+
+static int dax_kmem_parse_state(const char *buf)
+{
+ int online_type;
+
+ /* "unplugged" is kmem-specific - the rest map to MMOP_ */
+ if (sysfs_streq(buf, "unplugged"))
+ return DAX_KMEM_UNPLUGGED;
+
+ online_type = mhp_online_type_from_str(buf);
+ /* Disallow "offline": it's not useful and creates race conditions */
+ if (online_type == MMOP_OFFLINE)
+ return -EINVAL;
+ return online_type;
+}
+
+static ssize_t state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dax_kmem_data *data = dev_get_drvdata(dev);
+ const char *state_str;
+
+ if (data->state == DAX_KMEM_UNPLUGGED)
+ state_str = "unplugged";
+ else
+ state_str = mhp_online_type_to_str(data->state);
+
+ return sysfs_emit(buf, "%s\n", state_str ?: "unknown");
+}
+
+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct dev_dax *dev_dax = to_dev_dax(dev);
+ struct dax_kmem_data *data = dev_get_drvdata(dev);
+ int online_type;
+ int rc;
+
+ online_type = dax_kmem_parse_state(buf);
+ if (online_type < DAX_KMEM_UNPLUGGED)
+ return online_type;
+
+ guard(mutex)(&data->lock);
+
+ /* Already in requested state */
+ if (data->state == online_type)
+ return len;
+
+ if (online_type == DAX_KMEM_UNPLUGGED) {
+ rc = dax_kmem_do_hotremove(dev_dax, data);
+ if (rc)
+ return rc;
+ data->state = DAX_KMEM_UNPLUGGED;
+ return len;
+ }
+
+ /* Onlining is only allowed from the unplugged state. */
+ if (data->state != DAX_KMEM_UNPLUGGED)
+ return -EBUSY;
+
+ /* Re-acquire resources if previously unplugged, otherwise no-op */
+ rc = dax_kmem_init_resources(dev_dax, data);
+ if (rc < 0)
+ return rc;
+
+ rc = dax_kmem_do_hotplug(dev_dax, data, online_type);
+ if (rc < 0) {
+ /* Total failure, drop the reservations we took. */
+ dax_kmem_cleanup_resources(dev_dax, data);
+ return rc;
+ }
+
+ data->state = online_type;
+ return len;
+}
+
static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
{
struct device *dev = &dev_dax->dev;
unsigned long total_len = 0, orig_len = 0;
struct dax_kmem_data *data;
struct memory_dev_type *mtype;
- int i, rc, mapped = 0;
- mhp_t mhp_flags;
+ int i, rc;
int numa_node;
int adist = MEMTIER_DEFAULT_DAX_ADISTANCE;
+ int online_type = mhp_get_default_online_type();
/*
* Ensure good NUMA information for the persistent memory.
@@ -133,68 +448,26 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax)
if (rc < 0)
goto err_reg_mgid;
data->mgid = rc;
+ data->state = DAX_KMEM_UNPLUGGED;
+ mutex_init(&data->lock);
- for (i = 0; i < dev_dax->nr_range; i++) {
- struct resource *res;
- struct range range;
-
- rc = dax_kmem_range(dev_dax, i, &range);
- if (rc)
- continue;
-
- /* Region is permanently reserved if hotremove fails. */
- res = request_mem_region(range.start, range_len(&range), data->res_name);
- if (!res) {
- dev_warn(dev, "mapping%d: %#llx-%#llx could not reserve region\n",
- i, range.start, range.end);
- /*
- * Once some memory has been onlined we can't
- * assume that it can be un-onlined safely.
- */
- if (mapped)
- continue;
- rc = -EBUSY;
- goto err_request_mem;
- }
- data->res[i] = res;
-
- /*
- * Set flags appropriate for System RAM. Leave ..._BUSY clear
- * so that add_memory() can add a child resource. Do not
- * inherit flags from the parent since it may set new flags
- * unknown to us that will break add_memory() below.
- */
- res->flags = IORESOURCE_SYSTEM_RAM;
-
- mhp_flags = MHP_NID_IS_MGID;
- if (dev_dax->memmap_on_memory)
- mhp_flags |= MHP_MEMMAP_ON_MEMORY;
-
- /*
- * Ensure that future kexec'd kernels will not treat
- * this as RAM automatically.
- */
- rc = add_memory_driver_managed(data->mgid, range.start,
- range_len(&range), kmem_name, mhp_flags);
+ dev_set_drvdata(dev, data);
- if (rc) {
- dev_warn(dev, "mapping%d: %#llx-%#llx memory add failed\n",
- i, range.start, range.end);
- remove_resource(res);
- kfree(res);
- data->res[i] = NULL;
- if (mapped)
- continue;
- goto err_request_mem;
- }
- mapped++;
- }
+ rc = dax_kmem_init_resources(dev_dax, data);
+ if (rc < 0)
+ goto err_resources;
- dev_set_drvdata(dev, data);
+ rc = dax_kmem_do_hotplug(dev_dax, data, online_type);
+ if (rc < 0)
+ goto err_hotplug;
+ data->state = online_type;
return 0;
-err_request_mem:
+err_hotplug:
+ dax_kmem_cleanup_resources(dev_dax, data);
+err_resources:
+ dev_set_drvdata(dev, NULL);
memory_group_unregister(data->mgid);
err_reg_mgid:
kfree(data->res_name);
@@ -206,61 +479,71 @@ err_dax_kmem_data:
}
#ifdef CONFIG_MEMORY_HOTREMOVE
-static void dev_dax_kmem_remove(struct dev_dax *dev_dax)
+/*
+ * Remove the device's added ranges with remove_memory().
+ * Unlike the sysfs unplug path it never offlines and fails if the blocks are
+ * online (-EBUSY), so it is safe from unbind. Failures leak until reboot.
+ *
+ * Returns 0 only if every added range was removed.
+ */
+static int dax_kmem_remove_ranges(struct dev_dax *dev_dax,
+ struct dax_kmem_data *data)
{
- int i, success = 0;
- int node = dev_dax->target_node;
struct device *dev = &dev_dax->dev;
- struct dax_kmem_data *data = dev_get_drvdata(dev);
+ int i, rc = 0;
- /*
- * We have one shot for removing memory, if some memory blocks were not
- * offline prior to calling this function remove_memory() will fail, and
- * there is no way to hotremove this memory until reboot because device
- * unbind will succeed even if we return failure.
- */
for (i = 0; i < dev_dax->nr_range; i++) {
struct range range;
- int rc;
- rc = dax_kmem_range(dev_dax, i, &range);
- if (rc)
+ if (!data->res[i] || dax_kmem_range(dev_dax, i, &range))
continue;
-
- /* range was never added during probe */
- if (!data->res[i]) {
- success++;
+ if (remove_memory(range.start, range_len(&range))) {
+ dev_warn(dev, "mapping%d: %#llx-%#llx stuck online until reboot\n",
+ i, range.start, range.end);
+ rc = -EBUSY;
continue;
}
+ remove_resource(data->res[i]);
+ kfree(data->res[i]);
+ data->res[i] = NULL;
+ }
+ return rc;
+}
- rc = remove_memory(range.start, range_len(&range));
- if (rc == 0) {
- remove_resource(data->res[i]);
- kfree(data->res[i]);
- data->res[i] = NULL;
- success++;
- continue;
- }
+static void dev_dax_kmem_remove(struct dev_dax *dev_dax)
+{
+ int node = dev_dax->target_node;
+ struct device *dev = &dev_dax->dev;
+ struct dax_kmem_data *data = dev_get_drvdata(dev);
+
+ /*
+ * Remove every range that is still added. dax_kmem_remove_ranges()
+ * uses remove_memory(), which never offlines: an online block fails
+ * with -EBUSY rather than deadlocking an uninterruptible unbind.
+ *
+ * data->state only tracks daxX.Y/state writes, so it can be stale if
+ * blocks were toggled via memoryX/state. Do not trust it here and
+ * attempt simply remove_memory() - which reports the true state of
+ * each range anyway. Anything left online is leaked until reboot.
+ */
+ if (dax_kmem_remove_ranges(dev_dax, data)) {
+ dev_err(dev, "Hotplug regions stuck online until reboot\n");
any_hotremove_failed = true;
- dev_err(dev,
- "mapping%d: %#llx-%#llx cannot be hotremoved until the next reboot\n",
- i, range.start, range.end);
+ return;
}
- if (success >= dev_dax->nr_range) {
- memory_group_unregister(data->mgid);
- kfree(data->res_name);
- kfree(data);
- dev_set_drvdata(dev, NULL);
- /*
- * Clear the memtype association on successful unplug.
- * If not, we have memory blocks left which can be
- * offlined/onlined later. We need to keep memory_dev_type
- * for that. This implies this reference will be around
- * till next reboot.
- */
- clear_node_memory_type(node, NULL);
- }
+ memory_group_unregister(data->mgid);
+ kfree(data->res_name);
+ kfree(data);
+ dev_set_drvdata(dev, NULL);
+ /*
+ * Clear the memtype association on successful unplug.
+ * If not, we have memory blocks left which can be
+ * offlined/onlined later. We need to keep memory_dev_type
+ * for that. This implies this reference will be around
+ * till next reboot.
+ */
+ clear_node_memory_type(node, NULL);
}
#else
static void dev_dax_kmem_remove(struct dev_dax *dev_dax)
@@ -276,10 +559,21 @@ static void dev_dax_kmem_remove(struct dev_dax *dev_dax)
}
#endif /* CONFIG_MEMORY_HOTREMOVE */
+static DEVICE_ATTR_RW(state);
+
+static struct attribute *dev_dax_kmem_attrs[] = {
+ &dev_attr_state.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(dev_dax_kmem);
+
static struct dax_device_driver device_dax_kmem_driver = {
.probe = dev_dax_kmem_probe,
.remove = dev_dax_kmem_remove,
.type = DAXDRV_KMEM_TYPE,
+ .drv = {
+ .dev_groups = dev_dax_kmem_groups,
+ },
};
static int __init dax_kmem_init(void)
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index e3ed684ddcf2..32a05d889b9a 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -1252,7 +1252,7 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
}
vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
- vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+ vma->vm_page_prot = pgprot_writecombine(vma_get_page_prot(vma));
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
}
diff --git a/drivers/gpu/drm/drm_gem_dma_helper.c b/drivers/gpu/drm/drm_gem_dma_helper.c
index 1c00a71ab3c9..7d9612075d31 100644
--- a/drivers/gpu/drm/drm_gem_dma_helper.c
+++ b/drivers/gpu/drm/drm_gem_dma_helper.c
@@ -540,7 +540,7 @@ int drm_gem_dma_mmap(struct drm_gem_dma_object *dma_obj, struct vm_area_struct *
vm_flags_mod(vma, VM_DONTDUMP | VM_DONTEXPAND, VM_PFNMAP);
if (dma_obj->map_noncoherent) {
- vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ vma->vm_page_prot = vma_get_page_prot(vma);
ret = dma_mmap_pages(drm_dev_dma_dev(dma_obj->base.dev),
vma, vma->vm_end - vma->vm_start,
diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index c989459eb215..06d019d51d3e 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -764,7 +764,7 @@ int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct
return ret;
vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
- vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ vma->vm_page_prot = vma_get_page_prot(vma);
if (shmem->map_wc)
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
index 18ddef94da47..cdb1521eb1cf 100644
--- a/drivers/gpu/drm/drm_gpusvm.c
+++ b/drivers/gpu/drm/drm_gpusvm.c
@@ -773,8 +773,7 @@ enum drm_gpusvm_scan_result drm_gpusvm_scan_mm(struct drm_gpusvm_range *range,
.end = end,
.dev_private_owner = dev_private_owner,
};
- unsigned long timeout =
- jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
+ unsigned long timeout = msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
enum drm_gpusvm_scan_result state = DRM_GPUSVM_SCAN_UNPOPULATED, new_state;
unsigned long *pfns;
unsigned long npages = npages_in_range(start, end);
@@ -788,22 +787,7 @@ enum drm_gpusvm_scan_result drm_gpusvm_scan_mm(struct drm_gpusvm_range *range,
hmm_range.hmm_pfns = pfns;
retry:
- hmm_range.notifier_seq = mmu_interval_read_begin(notifier);
- mmap_read_lock(range->gpusvm->mm);
-
- while (true) {
- err = hmm_range_fault(&hmm_range);
- if (err == -EBUSY) {
- if (time_after(jiffies, timeout))
- break;
-
- hmm_range.notifier_seq =
- mmu_interval_read_begin(notifier);
- continue;
- }
- break;
- }
- mmap_read_unlock(range->gpusvm->mm);
+ err = hmm_range_fault_unlocked_timeout(&hmm_range, timeout);
if (err)
goto err_free;
@@ -1423,6 +1407,7 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
void *zdd;
unsigned long timeout =
jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
+ unsigned long remaining;
unsigned long i, j;
unsigned long npages = npages_in_range(pages_start, pages_end);
unsigned long num_dma_mapped;
@@ -1437,9 +1422,11 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
struct dma_iova_state *state = &svm_pages->state;
retry:
- if (time_after(jiffies, timeout))
+ if (time_after_eq(jiffies, timeout))
return -EBUSY;
+ remaining = timeout - jiffies;
+
hmm_range.notifier_seq = mmu_interval_read_begin(notifier);
if (drm_gpusvm_pages_valid_unlocked(gpusvm, svm_pages))
goto set_seqno;
@@ -1454,21 +1441,7 @@ retry:
}
hmm_range.hmm_pfns = pfns;
- while (true) {
- mmap_read_lock(mm);
- err = hmm_range_fault(&hmm_range);
- mmap_read_unlock(mm);
-
- if (err == -EBUSY) {
- if (time_after(jiffies, timeout))
- break;
-
- hmm_range.notifier_seq =
- mmu_interval_read_begin(notifier);
- continue;
- }
- break;
- }
+ err = hmm_range_fault_unlocked_timeout(&hmm_range, remaining);
mmput(mm);
if (err)
goto err_free;
@@ -1741,8 +1714,7 @@ int drm_gpusvm_range_evict(struct drm_gpusvm *gpusvm,
.end = drm_gpusvm_range_end(range),
.dev_private_owner = NULL,
};
- unsigned long timeout =
- jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
+ unsigned long timeout = msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
unsigned long *pfns;
unsigned long npages = npages_in_range(drm_gpusvm_range_start(range),
drm_gpusvm_range_end(range));
@@ -1759,24 +1731,12 @@ int drm_gpusvm_range_evict(struct drm_gpusvm *gpusvm,
}
hmm_range.hmm_pfns = pfns;
- while (!time_after(jiffies, timeout)) {
- hmm_range.notifier_seq = mmu_interval_read_begin(notifier);
- if (time_after(jiffies, timeout)) {
- err = -ETIME;
- break;
- }
-
- mmap_read_lock(mm);
- err = hmm_range_fault(&hmm_range);
- mmap_read_unlock(mm);
- if (err != -EBUSY)
- break;
- }
+ err = hmm_range_fault_unlocked_timeout(&hmm_range, timeout);
kvfree(pfns);
mmput(mm);
- return err;
+ return err == -EBUSY ? -ETIME : err;
}
EXPORT_SYMBOL_GPL(drm_gpusvm_range_evict);
diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c
index 4a794544b7dc..f00c27edbfb9 100644
--- a/drivers/gpu/drm/drm_pagemap.c
+++ b/drivers/gpu/drm/drm_pagemap.c
@@ -12,7 +12,7 @@
#include <drm/drm_pagemap_util.h>
#include <drm/drm_print.h>
-#if IS_ENABLED(CONFIG_ARCH_ENABLE_THP_MIGRATION)
+#if IS_ENABLED(CONFIG_ARCH_HAS_PMD_SOFTLEAVES)
#define DRM_PAGEMAP_PMD_ORDER HPAGE_PMD_ORDER
#else
#define DRM_PAGEMAP_PMD_ORDER (-1)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
index b0436a1e103f..f9c8b7b2bfc7 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
@@ -6,6 +6,7 @@
#include <drm/drm_prime.h>
#include <drm/drm_print.h>
#include <linux/dma-mapping.h>
+#include <linux/pagemap.h>
#include <linux/shmem_fs.h>
#include <linux/spinlock.h>
#include <linux/vmalloc.h>
@@ -132,7 +133,7 @@ static int etnaviv_gem_mmap_obj(struct etnaviv_gem_object *etnaviv_obj,
vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
- vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ vm_page_prot = vma_get_page_prot(vma);
if (etnaviv_obj->flags & ETNA_BO_WC) {
vma->vm_page_prot = pgprot_writecombine(vm_page_prot);
@@ -188,7 +189,7 @@ static vm_fault_t etnaviv_gem_fault(struct vm_fault *vmf)
}
/* We don't use vmf->pgoff since that has the fake offset: */
- pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
+ pgoff = linear_page_delta(vma, vmf->address);
pfn = page_to_pfn(pages[pgoff]);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 9a6270f3dca6..0208c9259572 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -377,13 +377,13 @@ static int exynos_drm_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct
/* non-cachable as default. */
if (exynos_gem->flags & EXYNOS_BO_CACHABLE)
- vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ vma->vm_page_prot = vma_get_page_prot(vma);
else if (exynos_gem->flags & EXYNOS_BO_WC)
vma->vm_page_prot =
- pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+ pgprot_writecombine(vma_get_page_prot(vma));
else
vma->vm_page_prot =
- pgprot_noncached(vm_get_page_prot(vma->vm_flags));
+ pgprot_noncached(vma_get_page_prot(vma));
ret = exynos_drm_gem_mmap_buffer(exynos_gem, vma);
if (ret)
diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c
index 88f1e86c8903..2708e8c68f4c 100644
--- a/drivers/gpu/drm/gma500/gem.c
+++ b/drivers/gpu/drm/gma500/gem.c
@@ -288,7 +288,7 @@ static vm_fault_t psb_gem_fault(struct vm_fault *vmf)
/* Page relative to the VMA start - we must calculate this ourselves
because vmf->pgoff is the fake GEM offset */
- page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
+ page_offset = linear_page_delta(vma, vmf->address);
/* CPU view of the page, don't go via the GART for CPU writes */
if (pobj->stolen)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/i915_gem_mman.c
index 0644f85c6c8e..9ca90c1bb5b4 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_mman.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_mman.c
@@ -112,7 +112,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
vma = find_vma(mm, addr);
if (vma && __vma_matches(vma, obj->base.filp, addr, args->size))
vma->vm_page_prot =
- pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+ pgprot_writecombine(vma_get_page_prot(vma));
else
addr = -ENOMEM;
mmap_write_unlock(mm);
@@ -1024,7 +1024,7 @@ i915_gem_object_mmap(struct drm_i915_gem_object *obj,
fput(anon);
if (obj->ops->mmap_ops) {
- vma->vm_page_prot = pgprot_decrypted(vm_get_page_prot(vma->vm_flags));
+ vma->vm_page_prot = pgprot_decrypted(vma_get_page_prot(vma));
vma->vm_ops = obj->ops->mmap_ops;
vma->vm_private_data = obj->base.vma_node.driver_private;
return 0;
@@ -1035,7 +1035,7 @@ i915_gem_object_mmap(struct drm_i915_gem_object *obj,
switch (mmo->mmap_type) {
case I915_MMAP_TYPE_WC:
vma->vm_page_prot =
- pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+ pgprot_writecombine(vma_get_page_prot(vma));
vma->vm_ops = &vm_ops_cpu;
break;
@@ -1043,19 +1043,19 @@ i915_gem_object_mmap(struct drm_i915_gem_object *obj,
GEM_WARN_ON(1);
fallthrough;
case I915_MMAP_TYPE_WB:
- vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ vma->vm_page_prot = vma_get_page_prot(vma);
vma->vm_ops = &vm_ops_cpu;
break;
case I915_MMAP_TYPE_UC:
vma->vm_page_prot =
- pgprot_noncached(vm_get_page_prot(vma->vm_flags));
+ pgprot_noncached(vma_get_page_prot(vma));
vma->vm_ops = &vm_ops_cpu;
break;
case I915_MMAP_TYPE_GTT:
vma->vm_page_prot =
- pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+ pgprot_writecombine(vma_get_page_prot(vma));
vma->vm_ops = &vm_ops_gtt;
break;
}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index 06543ae60706..ef9440166295 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -325,7 +325,7 @@ void __shmem_writeback(size_t size, struct address_space *mapping)
if (folio_mapped(folio))
folio_redirty_for_writepage(&wbc, folio);
else
- error = shmem_writeout(folio, NULL, NULL);
+ error = shmem_write_folio(folio);
}
}
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index efd3d3c9a449..6a78e242de7c 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -9,6 +9,7 @@
#include <linux/spinlock.h>
#include <linux/shmem_fs.h>
#include <linux/dma-buf.h>
+#include <linux/pagemap.h>
#include <drm/drm_dumb_buffers.h>
#include <drm/drm_prime.h>
@@ -360,7 +361,7 @@ static vm_fault_t msm_gem_fault(struct vm_fault *vmf)
}
/* We don't use vmf->pgoff since that has the fake offset: */
- pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
+ pgoff = linear_page_delta(vma, vmf->address);
pfn = page_to_pfn(pages[pgoff]);
@@ -1124,7 +1125,7 @@ static int msm_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
struct msm_gem_object *msm_obj = to_msm_bo(obj);
vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
- vma->vm_page_prot = msm_gem_pgprot(msm_obj, vm_get_page_prot(vma->vm_flags));
+ vma->vm_page_prot = msm_gem_pgprot(msm_obj, vma_get_page_prot(vma));
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 20dba02d6175..9a6ee2e880c0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -55,7 +55,7 @@ static vm_fault_t nouveau_ttm_fault(struct vm_fault *vmf)
goto error_unlock;
nouveau_bo_del_io_reserve_lru(bo);
- prot = vm_get_page_prot(vma->vm_flags);
+ prot = vma_get_page_prot(vma);
ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT);
nouveau_bo_add_io_reserve_lru(bo);
if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c
index dcc92131488e..58735446d783 100644
--- a/drivers/gpu/drm/nouveau/nouveau_svm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_svm.c
@@ -678,20 +678,22 @@ static int nouveau_range_fault(struct nouveau_svmm *svmm,
range.end = notifier->notifier.interval_tree.last + 1;
while (true) {
- if (time_after(jiffies, timeout)) {
+ long remaining = timeout - jiffies;
+
+ /*
+ * The HMM timeout only bounds retries while HMM is walking and
+ * faulting the range. This fault is handled by a kernel worker,
+ * so fatal signals from the faulting process cannot stop an
+ * endless stream of invalidations here.
+ */
+ if (time_after_eq(jiffies, timeout)) {
ret = -EBUSY;
goto out;
}
- range.notifier_seq = mmu_interval_read_begin(range.notifier);
- mmap_read_lock(mm);
- ret = hmm_range_fault(&range);
- mmap_read_unlock(mm);
- if (ret) {
- if (ret == -EBUSY)
- continue;
+ ret = hmm_range_fault_unlocked_timeout(&range, remaining);
+ if (ret)
goto out;
- }
mutex_lock(&svmm->mutex);
if (mmu_interval_read_retry(range.notifier,
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index ca3fb186bf19..4881777642d2 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -84,7 +84,7 @@ fallback:
static int omap_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
- vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+ vma->vm_page_prot = pgprot_writecombine(vma_get_page_prot(vma));
return fb_deferred_io_mmap(info, vma);
}
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c
index 8e013e4f2c6b..fb0e6f556b31 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -5,6 +5,7 @@
*/
#include <linux/dma-mapping.h>
+#include <linux/pagemap.h>
#include <linux/seq_file.h>
#include <linux/shmem_fs.h>
#include <linux/spinlock.h>
@@ -359,7 +360,7 @@ static vm_fault_t omap_gem_fault_1d(struct drm_gem_object *obj,
pgoff_t pgoff;
/* We don't use vmf->pgoff since that has the fake offset: */
- pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
+ pgoff = linear_page_delta(vma, vmf->address);
if (omap_obj->pages) {
omap_gem_cpu_sync_page(obj, pgoff);
@@ -407,7 +408,7 @@ static vm_fault_t omap_gem_fault_2d(struct drm_gem_object *obj,
const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE);
/* We don't use vmf->pgoff since that has the fake offset: */
- pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
+ pgoff = linear_page_delta(vma, vmf->address);
/*
* Actual address we start mapping at is rounded down to previous slot
@@ -537,9 +538,9 @@ static int omap_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struc
vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP | VM_IO | VM_MIXEDMAP);
if (omap_obj->flags & OMAP_BO_WC) {
- vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+ vma->vm_page_prot = pgprot_writecombine(vma_get_page_prot(vma));
} else if (omap_obj->flags & OMAP_BO_UNCACHED) {
- vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags));
+ vma->vm_page_prot = pgprot_noncached(vma_get_page_prot(vma));
} else {
/*
* We do have some private objects, at least for scanout buffers
@@ -557,7 +558,7 @@ static int omap_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struc
vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
vma_set_file(vma, obj->filp);
- vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ vma->vm_page_prot = vma_get_page_prot(vma);
}
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c
index a1e2eb1ca7bb..770556353968 100644
--- a/drivers/gpu/drm/panthor/panthor_gem.c
+++ b/drivers/gpu/drm/panthor/panthor_gem.c
@@ -776,7 +776,7 @@ static int panthor_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *v
}
vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
- vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ vma->vm_page_prot = vma_get_page_prot(vma);
if (should_map_wc(bo))
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index b188539dca0b..9a1dc9f12072 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -255,7 +255,7 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
*/
vm_flags_mod(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP, VM_PFNMAP);
- vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+ vma->vm_page_prot = pgprot_writecombine(vma_get_page_prot(vma));
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
if (rk_obj->pages)
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 436394e04812..f76af733ea79 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -13,6 +13,7 @@
#include <linux/dma-buf.h>
#include <linux/iommu.h>
#include <linux/module.h>
+#include <linux/pagemap.h>
#include <linux/vmalloc.h>
#include <drm/drm_drv.h>
@@ -564,7 +565,7 @@ static vm_fault_t tegra_bo_fault(struct vm_fault *vmf)
if (!bo->pages)
return VM_FAULT_SIGBUS;
- offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
+ offset = linear_page_delta(vma, vmf->address);
page = bo->pages[offset];
return vmf_insert_page(vma, vmf->address, page);
@@ -601,7 +602,7 @@ int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma)
vma->vm_pgoff = vm_pgoff;
} else {
- pgprot_t prot = vm_get_page_prot(vma->vm_flags);
+ pgprot_t prot = vma_get_page_prot(vma);
vm_flags_mod(vma, VM_MIXEDMAP, VM_PFNMAP);
diff --git a/drivers/gpu/drm/ttm/ttm_backup.c b/drivers/gpu/drm/ttm/ttm_backup.c
index 3c067aadc52d..658eeab73255 100644
--- a/drivers/gpu/drm/ttm/ttm_backup.c
+++ b/drivers/gpu/drm/ttm/ttm_backup.c
@@ -160,7 +160,7 @@ ttm_backup_backup_folio(struct file *backup, struct folio *folio,
if (writeback && !folio_mapped(to_folio) &&
folio_clear_dirty_for_io(to_folio)) {
folio_set_reclaim(to_folio);
- ret = shmem_writeout(to_folio, NULL, NULL);
+ ret = shmem_write_folio(to_folio);
if (!folio_test_writeback(to_folio))
folio_clear_reclaim(to_folio);
if (ret == AOP_WRITEPAGE_ACTIVATE)
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index a80510489c45..88babf435ac2 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -32,6 +32,7 @@
#define pr_fmt(fmt) "[TTM] " fmt
#include <linux/export.h>
+#include <linux/pagemap.h>
#include <drm/ttm/ttm_bo.h>
#include <drm/ttm/ttm_placement.h>
@@ -208,9 +209,9 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
if (unlikely(err != 0))
return VM_FAULT_SIGBUS;
- page_offset = ((address - vma->vm_start) >> PAGE_SHIFT) +
- vma->vm_pgoff - drm_vma_node_start(&bo->base.vma_node);
- page_last = vma_pages(vma) + vma->vm_pgoff -
+ page_offset = linear_page_index(vma, address) -
+ drm_vma_node_start(&bo->base.vma_node);
+ page_last = vma_end_pgoff(vma) -
drm_vma_node_start(&bo->base.vma_node);
if (unlikely(page_offset >= PFN_UP(bo->base.size)))
diff --git a/drivers/gpu/drm/virtio/virtgpu_vram.c b/drivers/gpu/drm/virtio/virtgpu_vram.c
index 4ae3cbc35dd3..544a6abddbc8 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vram.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vram.c
@@ -55,7 +55,7 @@ static int virtio_gpu_vram_mmap(struct drm_gem_object *obj,
vma->vm_pgoff -= drm_vma_node_start(&obj->vma_node);
vm_flags_set(vma, VM_MIXEDMAP | VM_DONTEXPAND);
- vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ vma->vm_page_prot = vma_get_page_prot(vma);
vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
vma->vm_ops = &virtio_gpu_vram_vm_ops;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
index 45561bc1c9ef..a9fd4015a0ca 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_page_dirty.c
@@ -481,7 +481,7 @@ vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf)
if (vbo->dirty && vbo->dirty->method == VMW_BO_DIRTY_MKWRITE)
prot = vm_get_page_prot(vma->vm_flags & ~VM_SHARED);
else
- prot = vm_get_page_prot(vma->vm_flags);
+ prot = vma_get_page_prot(vma);
ret = ttm_bo_vm_fault_reserved(vmf, prot, num_prefault);
if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index dcb48caa485d..9d119c95a569 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -281,7 +281,7 @@ static vm_fault_t barrier_fault(struct vm_fault *vmf)
pgprot_t prot;
int idx;
- prot = vm_get_page_prot(vma->vm_flags);
+ prot = vma_get_page_prot(vma);
if (drm_dev_enter(dev, &idx)) {
unsigned long pfn;
diff --git a/drivers/gpu/drm/xe/xe_mmio_gem.c b/drivers/gpu/drm/xe/xe_mmio_gem.c
index 8c803ef233cc..3741ae60f532 100644
--- a/drivers/gpu/drm/xe/xe_mmio_gem.c
+++ b/drivers/gpu/drm/xe/xe_mmio_gem.c
@@ -149,7 +149,7 @@ static int xe_mmio_gem_mmap(struct drm_gem_object *base, struct vm_area_struct *
/* Set vm_pgoff (used as a fake buffer offset by DRM) to 0 */
vma->vm_pgoff = 0;
- vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags));
+ vma->vm_page_prot = pgprot_noncached(vma_get_page_prot(vma));
vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
VM_DONTCOPY | VM_NORESERVE);
diff --git a/drivers/gpu/drm/xen/xen_drm_front_gem.c b/drivers/gpu/drm/xen/xen_drm_front_gem.c
index eec4c1da3f9e..dd158443f55f 100644
--- a/drivers/gpu/drm/xen/xen_drm_front_gem.c
+++ b/drivers/gpu/drm/xen/xen_drm_front_gem.c
@@ -80,7 +80,7 @@ static int xen_drm_front_gem_object_mmap(struct drm_gem_object *gem_obj,
* which is mapped as Normal Inner Write-Back Outer Write-Back
* Inner-Shareable.
*/
- vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ vma->vm_page_prot = vma_get_page_prot(vma);
/*
* vm_operations_struct.fault handler will be called if CPU access
diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c
index 6d65e5b42152..dddaade31b5d 100644
--- a/drivers/hv/mshv_regions.c
+++ b/drivers/hv/mshv_regions.c
@@ -382,46 +382,6 @@ int mshv_region_get(struct mshv_mem_region *region)
}
/**
- * mshv_region_hmm_fault_and_lock - Handle HMM faults and lock the memory region
- * @region: Pointer to the memory region structure
- * @range: Pointer to the HMM range structure
- *
- * This function performs the following steps:
- * 1. Reads the notifier sequence for the HMM range.
- * 2. Acquires a read lock on the memory map.
- * 3. Handles HMM faults for the specified range.
- * 4. Releases the read lock on the memory map.
- * 5. If successful, locks the memory region mutex.
- * 6. Verifies if the notifier sequence has changed during the operation.
- * If it has, releases the mutex and returns -EBUSY to match with
- * hmm_range_fault() return code for repeating.
- *
- * Return: 0 on success, a negative error code otherwise.
- */
-static int mshv_region_hmm_fault_and_lock(struct mshv_mem_region *region,
- struct hmm_range *range)
-{
- int ret;
-
- range->notifier_seq = mmu_interval_read_begin(range->notifier);
- mmap_read_lock(region->mreg_mni.mm);
- ret = hmm_range_fault(range);
- mmap_read_unlock(region->mreg_mni.mm);
- if (ret)
- return ret;
-
- mutex_lock(&region->mreg_mutex);
-
- if (mmu_interval_read_retry(range->notifier, range->notifier_seq)) {
- mutex_unlock(&region->mreg_mutex);
- cond_resched();
- return -EBUSY;
- }
-
- return 0;
-}
-
-/**
* mshv_region_range_fault - Handle memory range faults for a given region.
* @region: Pointer to the memory region structure.
* @page_offset: Offset of the page within the region.
@@ -452,13 +412,19 @@ static int mshv_region_range_fault(struct mshv_mem_region *region,
range.start = region->start_uaddr + page_offset * HV_HYP_PAGE_SIZE;
range.end = range.start + page_count * HV_HYP_PAGE_SIZE;
- do {
- ret = mshv_region_hmm_fault_and_lock(region, &range);
- } while (ret == -EBUSY);
-
+again:
+ ret = hmm_range_fault_unlocked_timeout(&range, 0);
if (ret)
goto out;
+ mutex_lock(&region->mreg_mutex);
+
+ if (mmu_interval_read_retry(range.notifier, range.notifier_seq)) {
+ mutex_unlock(&region->mreg_mutex);
+ cond_resched();
+ goto again;
+ }
+
for (i = 0; i < page_count; i++)
region->mreg_pages[page_offset + i] = hmm_pfn_to_page(pfns[i]);
diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
index 404fa1cc3254..9cc21cd762d9 100644
--- a/drivers/infiniband/core/umem_odp.c
+++ b/drivers/infiniband/core/umem_odp.c
@@ -329,7 +329,7 @@ int ib_umem_odp_map_dma_and_lock(struct ib_umem_odp *umem_odp, u64 user_virt,
struct mm_struct *owning_mm = umem_odp->umem.owning_mm;
int pfn_index, dma_index, ret = 0, start_idx;
unsigned int page_shift, hmm_order, pfn_start_idx;
- unsigned long num_pfns, current_seq;
+ unsigned long num_pfns;
struct hmm_range range = {};
unsigned long timeout;
@@ -363,26 +363,18 @@ int ib_umem_odp_map_dma_and_lock(struct ib_umem_odp *umem_odp, u64 user_virt,
}
range.hmm_pfns = &(umem_odp->map.pfn_list[pfn_start_idx]);
- timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
+ timeout = msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
retry:
- current_seq = range.notifier_seq =
- mmu_interval_read_begin(&umem_odp->notifier);
-
- mmap_read_lock(owning_mm);
- ret = hmm_range_fault(&range);
- mmap_read_unlock(owning_mm);
- if (unlikely(ret)) {
- if (ret == -EBUSY && !time_after(jiffies, timeout))
- goto retry;
+ ret = hmm_range_fault_unlocked_timeout(&range, timeout);
+ if (unlikely(ret))
goto out_put_mm;
- }
start_idx = (range.start - ib_umem_start(umem_odp)) >> page_shift;
dma_index = start_idx;
mutex_lock(&umem_odp->umem_mutex);
- if (mmu_interval_read_retry(&umem_odp->notifier, current_seq)) {
+ if (mmu_interval_read_retry(&umem_odp->notifier, range.notifier_seq)) {
mutex_unlock(&umem_odp->umem_mutex);
goto retry;
}
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index 772c78726893..79c2f00ed4d7 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -170,9 +170,8 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
mq->mmr_blade = uv_cpu_to_blade_id(cpu);
nid = cpu_to_node(cpu);
- page = __alloc_pages_node(nid,
- GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
- pg_order);
+ page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
+ pg_order);
if (page == NULL) {
dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
"bytes of memory on nid=%d for GRU mq\n", mq_size, nid);
diff --git a/drivers/net/ethernet/fungible/funeth/funeth_rx.c b/drivers/net/ethernet/fungible/funeth/funeth_rx.c
index 7e2584895de3..d7000017ac2b 100644
--- a/drivers/net/ethernet/fungible/funeth/funeth_rx.c
+++ b/drivers/net/ethernet/fungible/funeth/funeth_rx.c
@@ -103,7 +103,7 @@ static int funeth_alloc_page(struct funeth_rxq *q, struct funeth_rxbuf *rb,
if (cache_get(q, rb))
return 0;
- p = __alloc_pages_node(node, gfp | __GFP_NOWARN, 0);
+ p = alloc_pages_node(node, gfp | __GFP_NOWARN, 0);
if (unlikely(!p))
return -ENOMEM;
diff --git a/drivers/vfio/pci/nvgrace-gpu/main.c b/drivers/vfio/pci/nvgrace-gpu/main.c
index d07dcacb76bd..963fd8ded20d 100644
--- a/drivers/vfio/pci/nvgrace-gpu/main.c
+++ b/drivers/vfio/pci/nvgrace-gpu/main.c
@@ -11,6 +11,7 @@
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/pci-p2pdma.h>
+#include <linux/pagemap.h>
#include <linux/pm_runtime.h>
#include <linux/memory-failure.h>
@@ -385,7 +386,7 @@ static unsigned long addr_to_pgoff(struct vm_area_struct *vma,
u64 pgoff = vma->vm_pgoff &
((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
- return ((addr - vma->vm_start) >> PAGE_SHIFT) + pgoff;
+ return linear_page_delta(vma, addr) + pgoff;
}
static vm_fault_t nvgrace_gpu_vfio_pci_huge_fault(struct vm_fault *vmf,
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 3f11a9624b9c..a113c55845e1 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
+#include <linux/pagemap.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
@@ -1780,7 +1781,7 @@ static vm_fault_t vfio_pci_mmap_huge_fault(struct vm_fault *vmf,
struct vm_area_struct *vma = vmf->vma;
struct vfio_pci_core_device *vdev = vma->vm_private_data;
unsigned long addr = vmf->address & ~((PAGE_SIZE << order) - 1);
- unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
+ unsigned long pgoff = linear_page_delta(vma, addr);
unsigned long pfn = vma_to_pfn(vma) + pgoff;
vm_fault_t ret = VM_FAULT_FALLBACK;
diff --git a/drivers/video/fbdev/core/fb_io_fops.c b/drivers/video/fbdev/core/fb_io_fops.c
index 6ab60fcd0050..6d0a8c8e141a 100644
--- a/drivers/video/fbdev/core/fb_io_fops.c
+++ b/drivers/video/fbdev/core/fb_io_fops.c
@@ -161,7 +161,7 @@ int fb_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
len = info->fix.mmio_len;
}
- vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ vma->vm_page_prot = vma_get_page_prot(vma);
vma->vm_page_prot = pgprot_framebuffer(vma->vm_page_prot, vma->vm_start,
vma->vm_end, start);