Skip to content

Commit d200781

Browse files
committed
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>
1 parent 89ec9f2 commit d200781

File tree

3 files changed

+156
-10
lines changed

3 files changed

+156
-10
lines changed

drivers/dax/bus.c

Lines changed: 140 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,21 @@
22
/* Copyright(c) 2017-2018 Intel Corporation. All rights reserved. */
33
#include <linux/memremap.h>
44
#include <linux/device.h>
5+
#include <linux/mutex.h>
6+
#include <linux/list.h>
57
#include <linux/slab.h>
68
#include <linux/dax.h>
79
#include "dax-private.h"
810
#include "bus.h"
911

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+
};
19+
1020
static int dax_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
1121
{
1222
/*
@@ -16,22 +26,115 @@ static int dax_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
1626
return add_uevent_var(env, "MODALIAS=" DAX_DEVICE_MODALIAS_FMT, 0);
1727
}
1828

29+
static struct dax_device_driver *to_dax_drv(struct device_driver *drv)
30+
{
31+
return container_of(drv, struct dax_device_driver, drv);
32+
}
33+
34+
static struct dax_id *__dax_match_id(struct dax_device_driver *dax_drv,
35+
const char *dev_name)
36+
{
37+
struct dax_id *dax_id;
38+
39+
lockdep_assert_held(&dax_bus_lock);
40+
41+
list_for_each_entry(dax_id, &dax_drv->ids, list)
42+
if (sysfs_streq(dax_id->dev_name, dev_name))
43+
return dax_id;
44+
return NULL;
45+
}
46+
47+
static int dax_match_id(struct dax_device_driver *dax_drv, struct device *dev)
48+
{
49+
int match;
50+
51+
mutex_lock(&dax_bus_lock);
52+
match = !!__dax_match_id(dax_drv, dev_name(dev));
53+
mutex_unlock(&dax_bus_lock);
54+
55+
return match;
56+
}
57+
58+
static ssize_t do_id_store(struct device_driver *drv, const char *buf,
59+
size_t count, bool add)
60+
{
61+
struct dax_device_driver *dax_drv = to_dax_drv(drv);
62+
unsigned int region_id, id;
63+
char devname[DAX_NAME_LEN];
64+
struct dax_id *dax_id;
65+
ssize_t rc = count;
66+
int fields;
67+
68+
fields = sscanf(buf, "dax%d.%d", &region_id, &id);
69+
if (fields != 2)
70+
return -EINVAL;
71+
sprintf(devname, "dax%d.%d", region_id, id);
72+
if (!sysfs_streq(buf, devname))
73+
return -EINVAL;
74+
75+
mutex_lock(&dax_bus_lock);
76+
dax_id = __dax_match_id(dax_drv, buf);
77+
if (!dax_id) {
78+
if (add) {
79+
dax_id = kzalloc(sizeof(*dax_id), GFP_KERNEL);
80+
if (dax_id) {
81+
strncpy(dax_id->dev_name, buf, DAX_NAME_LEN);
82+
list_add(&dax_id->list, &dax_drv->ids);
83+
} else
84+
rc = -ENOMEM;
85+
} else
86+
/* nothing to remove */;
87+
} else if (!add) {
88+
list_del(&dax_id->list);
89+
kfree(dax_id);
90+
} else
91+
/* dax_id already added */;
92+
mutex_unlock(&dax_bus_lock);
93+
return rc;
94+
}
95+
96+
static ssize_t new_id_store(struct device_driver *drv, const char *buf,
97+
size_t count)
98+
{
99+
return do_id_store(drv, buf, count, true);
100+
}
101+
static DRIVER_ATTR_WO(new_id);
102+
103+
static ssize_t remove_id_store(struct device_driver *drv, const char *buf,
104+
size_t count)
105+
{
106+
return do_id_store(drv, buf, count, false);
107+
}
108+
static DRIVER_ATTR_WO(remove_id);
109+
110+
static struct attribute *dax_drv_attrs[] = {
111+
&driver_attr_new_id.attr,
112+
&driver_attr_remove_id.attr,
113+
NULL,
114+
};
115+
ATTRIBUTE_GROUPS(dax_drv);
116+
19117
static int dax_bus_match(struct device *dev, struct device_driver *drv);
20118

21119
static struct bus_type dax_bus_type = {
22120
.name = "dax",
23121
.uevent = dax_bus_uevent,
24122
.match = dax_bus_match,
123+
.drv_groups = dax_drv_groups,
25124
};
26125

27126
static int dax_bus_match(struct device *dev, struct device_driver *drv)
28127
{
128+
struct dax_device_driver *dax_drv = to_dax_drv(drv);
129+
29130
/*
30-
* The drivers that can register on the 'dax' bus are private to
31-
* drivers/dax/ so any device and driver on the bus always
32-
* match.
131+
* All but the 'device-dax' driver, which has 'match_always'
132+
* set, requires an exact id match.
33133
*/
34-
return 1;
134+
if (dax_drv->match_always)
135+
return 1;
136+
137+
return dax_match_id(dax_drv, dev);
35138
}
36139

37140
/*
@@ -273,17 +376,49 @@ struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id,
273376
}
274377
EXPORT_SYMBOL_GPL(devm_create_dev_dax);
275378

276-
int __dax_driver_register(struct device_driver *drv,
379+
static int match_always_count;
380+
381+
int __dax_driver_register(struct dax_device_driver *dax_drv,
277382
struct module *module, const char *mod_name)
278383
{
384+
struct device_driver *drv = &dax_drv->drv;
385+
int rc = 0;
386+
387+
INIT_LIST_HEAD(&dax_drv->ids);
279388
drv->owner = module;
280389
drv->name = mod_name;
281390
drv->mod_name = mod_name;
282391
drv->bus = &dax_bus_type;
392+
393+
/* there can only be one default driver */
394+
mutex_lock(&dax_bus_lock);
395+
match_always_count += dax_drv->match_always;
396+
if (match_always_count > 1) {
397+
match_always_count--;
398+
WARN_ON(1);
399+
rc = -EINVAL;
400+
}
401+
mutex_unlock(&dax_bus_lock);
402+
if (rc)
403+
return rc;
283404
return driver_register(drv);
284405
}
285406
EXPORT_SYMBOL_GPL(__dax_driver_register);
286407

408+
void dax_driver_unregister(struct dax_device_driver *dax_drv)
409+
{
410+
struct dax_id *dax_id, *_id;
411+
412+
mutex_lock(&dax_bus_lock);
413+
match_always_count -= dax_drv->match_always;
414+
list_for_each_entry_safe(dax_id, _id, &dax_drv->ids, list) {
415+
list_del(&dax_id->list);
416+
kfree(dax_id);
417+
}
418+
mutex_unlock(&dax_bus_lock);
419+
}
420+
EXPORT_SYMBOL_GPL(dax_driver_unregister);
421+
287422
int __init dax_bus_init(void)
288423
{
289424
return bus_register(&dax_bus_type);

drivers/dax/bus.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,18 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id,
1212
struct resource *res, unsigned int align, unsigned long flags);
1313
struct dev_dax *devm_create_dev_dax(struct dax_region *dax_region, int id,
1414
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,
1623
struct module *module, const char *mod_name);
1724
#define dax_driver_register(driver) \
1825
__dax_driver_register(driver, THIS_MODULE, KBUILD_MODNAME)
26+
void dax_driver_unregister(struct dax_device_driver *dax_drv);
1927
void kill_dev_dax(struct dev_dax *dev_dax);
2028

2129
/*

drivers/dax/device.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -504,9 +504,12 @@ static int dev_dax_remove(struct device *dev)
504504
return 0;
505505
}
506506

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,
510513
};
511514

512515
static int __init dax_init(void)
@@ -516,7 +519,7 @@ static int __init dax_init(void)
516519

517520
static void __exit dax_exit(void)
518521
{
519-
driver_unregister(&device_dax_driver);
522+
dax_driver_unregister(&device_dax_driver);
520523
}
521524

522525
MODULE_AUTHOR("Intel Corporation");

0 commit comments

Comments
 (0)