Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

device-dax: Add support for a dax override driver

Introduce the 'new_id' concept for enabling a custom device-driver attach
policy for dax-bus drivers. The intended use is to have a mechanism for
hot-plugging device-dax ranges into the page allocator on-demand. With
this in place the default policy of using device-dax for performance
differentiated memory can be overridden by user-space policy that can
arrange for the memory range to be managed as 'System RAM' with
user-defined NUMA and other performance attributes.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+156 -10
+140 -5
drivers/dax/bus.c
··· 2 2 /* Copyright(c) 2017-2018 Intel Corporation. All rights reserved. */ 3 3 #include <linux/memremap.h> 4 4 #include <linux/device.h> 5 + #include <linux/mutex.h> 6 + #include <linux/list.h> 5 7 #include <linux/slab.h> 6 8 #include <linux/dax.h> 7 9 #include "dax-private.h" 8 10 #include "bus.h" 11 + 12 + static DEFINE_MUTEX(dax_bus_lock); 13 + 14 + #define DAX_NAME_LEN 30 15 + struct dax_id { 16 + struct list_head list; 17 + char dev_name[DAX_NAME_LEN]; 18 + }; 9 19 10 20 static int dax_bus_uevent(struct device *dev, struct kobj_uevent_env *env) 11 21 { ··· 26 16 return add_uevent_var(env, "MODALIAS=" DAX_DEVICE_MODALIAS_FMT, 0); 27 17 } 28 18 19 + static struct dax_device_driver *to_dax_drv(struct device_driver *drv) 20 + { 21 + return container_of(drv, struct dax_device_driver, drv); 22 + } 23 + 24 + static struct dax_id *__dax_match_id(struct dax_device_driver *dax_drv, 25 + const char *dev_name) 26 + { 27 + struct dax_id *dax_id; 28 + 29 + lockdep_assert_held(&dax_bus_lock); 30 + 31 + list_for_each_entry(dax_id, &dax_drv->ids, list) 32 + if (sysfs_streq(dax_id->dev_name, dev_name)) 33 + return dax_id; 34 + return NULL; 35 + } 36 + 37 + static int dax_match_id(struct dax_device_driver *dax_drv, struct device *dev) 38 + { 39 + int match; 40 + 41 + mutex_lock(&dax_bus_lock); 42 + match = !!__dax_match_id(dax_drv, dev_name(dev)); 43 + mutex_unlock(&dax_bus_lock); 44 + 45 + return match; 46 + } 47 + 48 + static ssize_t do_id_store(struct device_driver *drv, const char *buf, 49 + size_t count, bool add) 50 + { 51 + struct dax_device_driver *dax_drv = to_dax_drv(drv); 52 + unsigned int region_id, id; 53 + char devname[DAX_NAME_LEN]; 54 + struct dax_id *dax_id; 55 + ssize_t rc = count; 56 + int fields; 57 + 58 + fields = sscanf(buf, "dax%d.%d", &region_id, &id); 59 + if (fields != 2) 60 + return -EINVAL; 61 + sprintf(devname, "dax%d.%d", region_id, id); 62 + if (!sysfs_streq(buf, devname)) 63 + return -EINVAL; 64 + 65 + mutex_lock(&dax_bus_lock); 66 + dax_id = __dax_match_id(dax_drv, buf); 67 + if (!dax_id) { 68 + if (add) { 69 + dax_id = kzalloc(sizeof(*dax_id), GFP_KERNEL); 70 + if (dax_id) { 71 + strncpy(dax_id->dev_name, buf, DAX_NAME_LEN); 72 + list_add(&dax_id->list, &dax_drv->ids); 73 + } else 74 + rc = -ENOMEM; 75 + } else 76 + /* nothing to remove */; 77 + } else if (!add) { 78 + list_del(&dax_id->list); 79 + kfree(dax_id); 80 + } else 81 + /* dax_id already added */; 82 + mutex_unlock(&dax_bus_lock); 83 + return rc; 84 + } 85 + 86 + static ssize_t new_id_store(struct device_driver *drv, const char *buf, 87 + size_t count) 88 + { 89 + return do_id_store(drv, buf, count, true); 90 + } 91 + static DRIVER_ATTR_WO(new_id); 92 + 93 + static ssize_t remove_id_store(struct device_driver *drv, const char *buf, 94 + size_t count) 95 + { 96 + return do_id_store(drv, buf, count, false); 97 + } 98 + static DRIVER_ATTR_WO(remove_id); 99 + 100 + static struct attribute *dax_drv_attrs[] = { 101 + &driver_attr_new_id.attr, 102 + &driver_attr_remove_id.attr, 103 + NULL, 104 + }; 105 + ATTRIBUTE_GROUPS(dax_drv); 106 + 29 107 static int dax_bus_match(struct device *dev, struct device_driver *drv); 30 108 31 109 static struct bus_type dax_bus_type = { 32 110 .name = "dax", 33 111 .uevent = dax_bus_uevent, 34 112 .match = dax_bus_match, 113 + .drv_groups = dax_drv_groups, 35 114 }; 36 115 37 116 static int dax_bus_match(struct device *dev, struct device_driver *drv) 38 117 { 118 + struct dax_device_driver *dax_drv = to_dax_drv(drv); 119 + 39 120 /* 40 - * The drivers that can register on the 'dax' bus are private to 41 - * drivers/dax/ so any device and driver on the bus always 42 - * match. 121 + * All but the 'device-dax' driver, which has 'match_always' 122 + * set, requires an exact id match. 43 123 */ 44 - return 1; 124 + if (dax_drv->match_always) 125 + return 1; 126 + 127 + return dax_match_id(dax_drv, dev); 45 128 } 46 129 47 130 /* ··· 376 273 } 377 274 EXPORT_SYMBOL_GPL(devm_create_dev_dax); 378 275 379 - int __dax_driver_register(struct device_driver *drv, 276 + static int match_always_count; 277 + 278 + int __dax_driver_register(struct dax_device_driver *dax_drv, 380 279 struct module *module, const char *mod_name) 381 280 { 281 + struct device_driver *drv = &dax_drv->drv; 282 + int rc = 0; 283 + 284 + INIT_LIST_HEAD(&dax_drv->ids); 382 285 drv->owner = module; 383 286 drv->name = mod_name; 384 287 drv->mod_name = mod_name; 385 288 drv->bus = &dax_bus_type; 289 + 290 + /* there can only be one default driver */ 291 + mutex_lock(&dax_bus_lock); 292 + match_always_count += dax_drv->match_always; 293 + if (match_always_count > 1) { 294 + match_always_count--; 295 + WARN_ON(1); 296 + rc = -EINVAL; 297 + } 298 + mutex_unlock(&dax_bus_lock); 299 + if (rc) 300 + return rc; 386 301 return driver_register(drv); 387 302 } 388 303 EXPORT_SYMBOL_GPL(__dax_driver_register); 304 + 305 + void dax_driver_unregister(struct dax_device_driver *dax_drv) 306 + { 307 + struct dax_id *dax_id, *_id; 308 + 309 + mutex_lock(&dax_bus_lock); 310 + match_always_count -= dax_drv->match_always; 311 + list_for_each_entry_safe(dax_id, _id, &dax_drv->ids, list) { 312 + list_del(&dax_id->list); 313 + kfree(dax_id); 314 + } 315 + mutex_unlock(&dax_bus_lock); 316 + } 317 + EXPORT_SYMBOL_GPL(dax_driver_unregister); 389 318 390 319 int __init dax_bus_init(void) 391 320 {
+9 -1
drivers/dax/bus.h
··· 12 12 struct resource *res, unsigned int align, unsigned long flags); 13 13 struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id, 14 14 struct dev_pagemap *pgmap); 15 - int __dax_driver_register(struct device_driver *drv, 15 + 16 + struct dax_device_driver { 17 + struct device_driver drv; 18 + struct list_head ids; 19 + int match_always; 20 + }; 21 + 22 + int __dax_driver_register(struct dax_device_driver *dax_drv, 16 23 struct module *module, const char *mod_name); 17 24 #define dax_driver_register(driver) \ 18 25 __dax_driver_register(driver, THIS_MODULE, KBUILD_MODNAME) 26 + void dax_driver_unregister(struct dax_device_driver *dax_drv); 19 27 void kill_dev_dax(struct dev_dax *dev_dax); 20 28 21 29 /*
+7 -4
drivers/dax/device.c
··· 504 504 return 0; 505 505 } 506 506 507 - static struct device_driver device_dax_driver = { 508 - .probe = dev_dax_probe, 509 - .remove = dev_dax_remove, 507 + static struct dax_device_driver device_dax_driver = { 508 + .drv = { 509 + .probe = dev_dax_probe, 510 + .remove = dev_dax_remove, 511 + }, 512 + .match_always = 1, 510 513 }; 511 514 512 515 static int __init dax_init(void) ··· 519 516 520 517 static void __exit dax_exit(void) 521 518 { 522 - driver_unregister(&device_dax_driver); 519 + dax_driver_unregister(&device_dax_driver); 523 520 } 524 521 525 522 MODULE_AUTHOR("Intel Corporation");