brintos

brintos / linux-shallow public Read only

0
0
Text · 7.8 KiB · e97d47f Raw
307 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2016-2019 Intel Corporation. All rights reserved. */3#include <linux/memremap.h>4#include <linux/pagemap.h>5#include <linux/memory.h>6#include <linux/module.h>7#include <linux/device.h>8#include <linux/pfn_t.h>9#include <linux/slab.h>10#include <linux/dax.h>11#include <linux/fs.h>12#include <linux/mm.h>13#include <linux/mman.h>14#include <linux/memory-tiers.h>15#include <linux/memory_hotplug.h>16#include "dax-private.h"17#include "bus.h"18 19/*20 * Default abstract distance assigned to the NUMA node onlined21 * by DAX/kmem if the low level platform driver didn't initialize22 * one for this NUMA node.23 */24#define MEMTIER_DEFAULT_DAX_ADISTANCE	(MEMTIER_ADISTANCE_DRAM * 5)25 26/* Memory resource name used for add_memory_driver_managed(). */27static const char *kmem_name;28/* Set if any memory will remain added when the driver will be unloaded. */29static bool any_hotremove_failed;30 31static int dax_kmem_range(struct dev_dax *dev_dax, int i, struct range *r)32{33	struct dev_dax_range *dax_range = &dev_dax->ranges[i];34	struct range *range = &dax_range->range;35 36	/* memory-block align the hotplug range */37	r->start = ALIGN(range->start, memory_block_size_bytes());38	r->end = ALIGN_DOWN(range->end + 1, memory_block_size_bytes()) - 1;39	if (r->start >= r->end) {40		r->start = range->start;41		r->end = range->end;42		return -ENOSPC;43	}44	return 0;45}46 47struct dax_kmem_data {48	const char *res_name;49	int mgid;50	struct resource *res[];51};52 53static DEFINE_MUTEX(kmem_memory_type_lock);54static LIST_HEAD(kmem_memory_types);55 56static struct memory_dev_type *kmem_find_alloc_memory_type(int adist)57{58	guard(mutex)(&kmem_memory_type_lock);59	return mt_find_alloc_memory_type(adist, &kmem_memory_types);60}61 62static void kmem_put_memory_types(void)63{64	guard(mutex)(&kmem_memory_type_lock);65	mt_put_memory_types(&kmem_memory_types);66}67 68static int dev_dax_kmem_probe(struct dev_dax *dev_dax)69{70	struct device *dev = &dev_dax->dev;71	unsigned long total_len = 0;72	struct dax_kmem_data *data;73	struct memory_dev_type *mtype;74	int i, rc, mapped = 0;75	mhp_t mhp_flags;76	int numa_node;77	int adist = MEMTIER_DEFAULT_DAX_ADISTANCE;78 79	/*80	 * Ensure good NUMA information for the persistent memory.81	 * Without this check, there is a risk that slow memory82	 * could be mixed in a node with faster memory, causing83	 * unavoidable performance issues.84	 */85	numa_node = dev_dax->target_node;86	if (numa_node < 0) {87		dev_warn(dev, "rejecting DAX region with invalid node: %d\n",88				numa_node);89		return -EINVAL;90	}91 92	mt_calc_adistance(numa_node, &adist);93	mtype = kmem_find_alloc_memory_type(adist);94	if (IS_ERR(mtype))95		return PTR_ERR(mtype);96 97	for (i = 0; i < dev_dax->nr_range; i++) {98		struct range range;99 100		rc = dax_kmem_range(dev_dax, i, &range);101		if (rc) {102			dev_info(dev, "mapping%d: %#llx-%#llx too small after alignment\n",103					i, range.start, range.end);104			continue;105		}106		total_len += range_len(&range);107	}108 109	if (!total_len) {110		dev_warn(dev, "rejecting DAX region without any memory after alignment\n");111		return -EINVAL;112	}113 114	init_node_memory_type(numa_node, mtype);115 116	rc = -ENOMEM;117	data = kzalloc(struct_size(data, res, dev_dax->nr_range), GFP_KERNEL);118	if (!data)119		goto err_dax_kmem_data;120 121	data->res_name = kstrdup(dev_name(dev), GFP_KERNEL);122	if (!data->res_name)123		goto err_res_name;124 125	rc = memory_group_register_static(numa_node, PFN_UP(total_len));126	if (rc < 0)127		goto err_reg_mgid;128	data->mgid = rc;129 130	for (i = 0; i < dev_dax->nr_range; i++) {131		struct resource *res;132		struct range range;133 134		rc = dax_kmem_range(dev_dax, i, &range);135		if (rc)136			continue;137 138		/* Region is permanently reserved if hotremove fails. */139		res = request_mem_region(range.start, range_len(&range), data->res_name);140		if (!res) {141			dev_warn(dev, "mapping%d: %#llx-%#llx could not reserve region\n",142					i, range.start, range.end);143			/*144			 * Once some memory has been onlined we can't145			 * assume that it can be un-onlined safely.146			 */147			if (mapped)148				continue;149			rc = -EBUSY;150			goto err_request_mem;151		}152		data->res[i] = res;153 154		/*155		 * Set flags appropriate for System RAM.  Leave ..._BUSY clear156		 * so that add_memory() can add a child resource.  Do not157		 * inherit flags from the parent since it may set new flags158		 * unknown to us that will break add_memory() below.159		 */160		res->flags = IORESOURCE_SYSTEM_RAM;161 162		mhp_flags = MHP_NID_IS_MGID;163		if (dev_dax->memmap_on_memory)164			mhp_flags |= MHP_MEMMAP_ON_MEMORY;165 166		/*167		 * Ensure that future kexec'd kernels will not treat168		 * this as RAM automatically.169		 */170		rc = add_memory_driver_managed(data->mgid, range.start,171				range_len(&range), kmem_name, mhp_flags);172 173		if (rc) {174			dev_warn(dev, "mapping%d: %#llx-%#llx memory add failed\n",175					i, range.start, range.end);176			remove_resource(res);177			kfree(res);178			data->res[i] = NULL;179			if (mapped)180				continue;181			goto err_request_mem;182		}183		mapped++;184	}185 186	dev_set_drvdata(dev, data);187 188	return 0;189 190err_request_mem:191	memory_group_unregister(data->mgid);192err_reg_mgid:193	kfree(data->res_name);194err_res_name:195	kfree(data);196err_dax_kmem_data:197	clear_node_memory_type(numa_node, mtype);198	return rc;199}200 201#ifdef CONFIG_MEMORY_HOTREMOVE202static void dev_dax_kmem_remove(struct dev_dax *dev_dax)203{204	int i, success = 0;205	int node = dev_dax->target_node;206	struct device *dev = &dev_dax->dev;207	struct dax_kmem_data *data = dev_get_drvdata(dev);208 209	/*210	 * We have one shot for removing memory, if some memory blocks were not211	 * offline prior to calling this function remove_memory() will fail, and212	 * there is no way to hotremove this memory until reboot because device213	 * unbind will succeed even if we return failure.214	 */215	for (i = 0; i < dev_dax->nr_range; i++) {216		struct range range;217		int rc;218 219		rc = dax_kmem_range(dev_dax, i, &range);220		if (rc)221			continue;222 223		rc = remove_memory(range.start, range_len(&range));224		if (rc == 0) {225			remove_resource(data->res[i]);226			kfree(data->res[i]);227			data->res[i] = NULL;228			success++;229			continue;230		}231		any_hotremove_failed = true;232		dev_err(dev,233			"mapping%d: %#llx-%#llx cannot be hotremoved until the next reboot\n",234				i, range.start, range.end);235	}236 237	if (success >= dev_dax->nr_range) {238		memory_group_unregister(data->mgid);239		kfree(data->res_name);240		kfree(data);241		dev_set_drvdata(dev, NULL);242		/*243		 * Clear the memtype association on successful unplug.244		 * If not, we have memory blocks left which can be245		 * offlined/onlined later. We need to keep memory_dev_type246		 * for that. This implies this reference will be around247		 * till next reboot.248		 */249		clear_node_memory_type(node, NULL);250	}251}252#else253static void dev_dax_kmem_remove(struct dev_dax *dev_dax)254{255	/*256	 * Without hotremove purposely leak the request_mem_region() for the257	 * device-dax range and return '0' to ->remove() attempts. The removal258	 * of the device from the driver always succeeds, but the region is259	 * permanently pinned as reserved by the unreleased260	 * request_mem_region().261	 */262	any_hotremove_failed = true;263}264#endif /* CONFIG_MEMORY_HOTREMOVE */265 266static struct dax_device_driver device_dax_kmem_driver = {267	.probe = dev_dax_kmem_probe,268	.remove = dev_dax_kmem_remove,269	.type = DAXDRV_KMEM_TYPE,270};271 272static int __init dax_kmem_init(void)273{274	int rc;275 276	/* Resource name is permanently allocated if any hotremove fails. */277	kmem_name = kstrdup_const("System RAM (kmem)", GFP_KERNEL);278	if (!kmem_name)279		return -ENOMEM;280 281	rc = dax_driver_register(&device_dax_kmem_driver);282	if (rc)283		goto error_dax_driver;284 285	return rc;286 287error_dax_driver:288	kmem_put_memory_types();289	kfree_const(kmem_name);290	return rc;291}292 293static void __exit dax_kmem_exit(void)294{295	dax_driver_unregister(&device_dax_kmem_driver);296	if (!any_hotremove_failed)297		kfree_const(kmem_name);298	kmem_put_memory_types();299}300 301MODULE_AUTHOR("Intel Corporation");302MODULE_DESCRIPTION("KMEM DAX: map dax-devices as System-RAM");303MODULE_LICENSE("GPL v2");304module_init(dax_kmem_init);305module_exit(dax_kmem_exit);306MODULE_ALIAS_DAX_DEVICE(0);307