Skip to content

Commit 3bf2bd2

Browse files
shligitaxboe
authored andcommitted
nullb: add configfs interface
Add configfs interface for nullb. configfs interface is more flexible and easy to configure in a per-disk basis. Configuration is something like this: mount -t configfs none /mnt Checking which features the driver supports: cat /mnt/nullb/features The 'features' attribute is for future extension. We probably will add new features into the driver, userspace can check this attribute to find the supported features. Create/remove a device: mkdir/rmdir /mnt/nullb/a Then configure the device by setting attributes under /mnt/nullb/a, most of nullb supported module parameters are converted to attributes: size; /* device size in MB */ completion_nsec; /* time in ns to complete a request */ submit_queues; /* number of submission queues */ home_node; /* home node for the device */ queue_mode; /* block interface */ blocksize; /* block size */ irqmode; /* IRQ completion handler */ hw_queue_depth; /* queue depth */ use_lightnvm; /* register as a LightNVM device */ blocking; /* blocking blk-mq device */ use_per_node_hctx; /* use per-node allocation for hardware context */ Note, creating a device doesn't create a disk immediately. Creating a disk is done in two phases: create a device and then power on the device. Next patch will introduce device power on. Based on original patch from Kyungchan Koh Signed-off-by: Kyungchan Koh <kkc6196@fb.com> Signed-off-by: Shaohua Li <shli@fb.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 2984c86 commit 3bf2bd2

File tree

2 files changed

+210
-1
lines changed

2 files changed

+210
-1
lines changed

drivers/block/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ if BLK_DEV
1717

1818
config BLK_DEV_NULL_BLK
1919
tristate "Null test block driver"
20+
depends on CONFIGFS_FS
2021

2122
config BLK_DEV_FD
2223
tristate "Normal floppy disk support"

drivers/block/null_blk.c

Lines changed: 209 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/*
2+
* Add configfs and memory store: Kyungchan Koh <kkc6196@fb.com> and
3+
* Shaohua Li <shli@fb.com>
4+
*/
15
#include <linux/module.h>
26

37
#include <linux/moduleparam.h>
@@ -9,6 +13,7 @@
913
#include <linux/blk-mq.h>
1014
#include <linux/hrtimer.h>
1115
#include <linux/lightnvm.h>
16+
#include <linux/configfs.h>
1217

1318
struct nullb_cmd {
1419
struct list_head list;
@@ -30,8 +35,21 @@ struct nullb_queue {
3035
struct nullb_cmd *cmds;
3136
};
3237

38+
/*
39+
* Status flags for nullb_device.
40+
*
41+
* CONFIGURED: Device has been configured and turned on. Cannot reconfigure.
42+
* UP: Device is currently on and visible in userspace.
43+
*/
44+
enum nullb_device_flags {
45+
NULLB_DEV_FL_CONFIGURED = 0,
46+
NULLB_DEV_FL_UP = 1,
47+
};
48+
3349
struct nullb_device {
3450
struct nullb *nullb;
51+
struct config_item item;
52+
unsigned long flags; /* device flags */
3553

3654
unsigned long size; /* device size in MB */
3755
unsigned long completion_nsec; /* time in ns to complete a request */
@@ -173,6 +191,185 @@ static bool g_use_per_node_hctx;
173191
module_param_named(use_per_node_hctx, g_use_per_node_hctx, bool, S_IRUGO);
174192
MODULE_PARM_DESC(use_per_node_hctx, "Use per-node allocation for hardware context queues. Default: false");
175193

194+
static struct nullb_device *null_alloc_dev(void);
195+
static void null_free_dev(struct nullb_device *dev);
196+
197+
static inline struct nullb_device *to_nullb_device(struct config_item *item)
198+
{
199+
return item ? container_of(item, struct nullb_device, item) : NULL;
200+
}
201+
202+
static inline ssize_t nullb_device_uint_attr_show(unsigned int val, char *page)
203+
{
204+
return snprintf(page, PAGE_SIZE, "%u\n", val);
205+
}
206+
207+
static inline ssize_t nullb_device_ulong_attr_show(unsigned long val,
208+
char *page)
209+
{
210+
return snprintf(page, PAGE_SIZE, "%lu\n", val);
211+
}
212+
213+
static inline ssize_t nullb_device_bool_attr_show(bool val, char *page)
214+
{
215+
return snprintf(page, PAGE_SIZE, "%u\n", val);
216+
}
217+
218+
static ssize_t nullb_device_uint_attr_store(unsigned int *val,
219+
const char *page, size_t count)
220+
{
221+
unsigned int tmp;
222+
int result;
223+
224+
result = kstrtouint(page, 0, &tmp);
225+
if (result)
226+
return result;
227+
228+
*val = tmp;
229+
return count;
230+
}
231+
232+
static ssize_t nullb_device_ulong_attr_store(unsigned long *val,
233+
const char *page, size_t count)
234+
{
235+
int result;
236+
unsigned long tmp;
237+
238+
result = kstrtoul(page, 0, &tmp);
239+
if (result)
240+
return result;
241+
242+
*val = tmp;
243+
return count;
244+
}
245+
246+
static ssize_t nullb_device_bool_attr_store(bool *val, const char *page,
247+
size_t count)
248+
{
249+
bool tmp;
250+
int result;
251+
252+
result = kstrtobool(page, &tmp);
253+
if (result)
254+
return result;
255+
256+
*val = tmp;
257+
return count;
258+
}
259+
260+
/* The following macro should only be used with TYPE = {uint, ulong, bool}. */
261+
#define NULLB_DEVICE_ATTR(NAME, TYPE) \
262+
static ssize_t \
263+
nullb_device_##NAME##_show(struct config_item *item, char *page) \
264+
{ \
265+
return nullb_device_##TYPE##_attr_show( \
266+
to_nullb_device(item)->NAME, page); \
267+
} \
268+
static ssize_t \
269+
nullb_device_##NAME##_store(struct config_item *item, const char *page, \
270+
size_t count) \
271+
{ \
272+
if (test_bit(NULLB_DEV_FL_CONFIGURED, &to_nullb_device(item)->flags)) \
273+
return -EBUSY; \
274+
return nullb_device_##TYPE##_attr_store( \
275+
&to_nullb_device(item)->NAME, page, count); \
276+
} \
277+
CONFIGFS_ATTR(nullb_device_, NAME);
278+
279+
NULLB_DEVICE_ATTR(size, ulong);
280+
NULLB_DEVICE_ATTR(completion_nsec, ulong);
281+
NULLB_DEVICE_ATTR(submit_queues, uint);
282+
NULLB_DEVICE_ATTR(home_node, uint);
283+
NULLB_DEVICE_ATTR(queue_mode, uint);
284+
NULLB_DEVICE_ATTR(blocksize, uint);
285+
NULLB_DEVICE_ATTR(irqmode, uint);
286+
NULLB_DEVICE_ATTR(hw_queue_depth, uint);
287+
NULLB_DEVICE_ATTR(use_lightnvm, bool);
288+
NULLB_DEVICE_ATTR(blocking, bool);
289+
NULLB_DEVICE_ATTR(use_per_node_hctx, bool);
290+
291+
static struct configfs_attribute *nullb_device_attrs[] = {
292+
&nullb_device_attr_size,
293+
&nullb_device_attr_completion_nsec,
294+
&nullb_device_attr_submit_queues,
295+
&nullb_device_attr_home_node,
296+
&nullb_device_attr_queue_mode,
297+
&nullb_device_attr_blocksize,
298+
&nullb_device_attr_irqmode,
299+
&nullb_device_attr_hw_queue_depth,
300+
&nullb_device_attr_use_lightnvm,
301+
&nullb_device_attr_blocking,
302+
&nullb_device_attr_use_per_node_hctx,
303+
NULL,
304+
};
305+
306+
static void nullb_device_release(struct config_item *item)
307+
{
308+
null_free_dev(to_nullb_device(item));
309+
}
310+
311+
static struct configfs_item_operations nullb_device_ops = {
312+
.release = nullb_device_release,
313+
};
314+
315+
static struct config_item_type nullb_device_type = {
316+
.ct_item_ops = &nullb_device_ops,
317+
.ct_attrs = nullb_device_attrs,
318+
.ct_owner = THIS_MODULE,
319+
};
320+
321+
static struct
322+
config_item *nullb_group_make_item(struct config_group *group, const char *name)
323+
{
324+
struct nullb_device *dev;
325+
326+
dev = null_alloc_dev();
327+
if (!dev)
328+
return ERR_PTR(-ENOMEM);
329+
330+
config_item_init_type_name(&dev->item, name, &nullb_device_type);
331+
332+
return &dev->item;
333+
}
334+
335+
static void
336+
nullb_group_drop_item(struct config_group *group, struct config_item *item)
337+
{
338+
config_item_put(item);
339+
}
340+
341+
static ssize_t memb_group_features_show(struct config_item *item, char *page)
342+
{
343+
return snprintf(page, PAGE_SIZE, "\n");
344+
}
345+
346+
CONFIGFS_ATTR_RO(memb_group_, features);
347+
348+
static struct configfs_attribute *nullb_group_attrs[] = {
349+
&memb_group_attr_features,
350+
NULL,
351+
};
352+
353+
static struct configfs_group_operations nullb_group_ops = {
354+
.make_item = nullb_group_make_item,
355+
.drop_item = nullb_group_drop_item,
356+
};
357+
358+
static struct config_item_type nullb_group_type = {
359+
.ct_group_ops = &nullb_group_ops,
360+
.ct_attrs = nullb_group_attrs,
361+
.ct_owner = THIS_MODULE,
362+
};
363+
364+
static struct configfs_subsystem nullb_subsys = {
365+
.su_group = {
366+
.cg_item = {
367+
.ci_namebuf = "nullb",
368+
.ci_type = &nullb_group_type,
369+
},
370+
},
371+
};
372+
176373
static struct nullb_device *null_alloc_dev(void)
177374
{
178375
struct nullb_device *dev;
@@ -919,12 +1116,19 @@ static int __init null_init(void)
9191116
return ret;
9201117
}
9211118

1119+
config_group_init(&nullb_subsys.su_group);
1120+
mutex_init(&nullb_subsys.su_mutex);
1121+
1122+
ret = configfs_register_subsystem(&nullb_subsys);
1123+
if (ret)
1124+
goto err_tagset;
1125+
9221126
mutex_init(&lock);
9231127

9241128
null_major = register_blkdev(0, "nullb");
9251129
if (null_major < 0) {
9261130
ret = null_major;
927-
goto err_tagset;
1131+
goto err_conf;
9281132
}
9291133

9301134
if (g_use_lightnvm) {
@@ -961,6 +1165,8 @@ static int __init null_init(void)
9611165
kmem_cache_destroy(ppa_cache);
9621166
err_ppa:
9631167
unregister_blkdev(null_major, "nullb");
1168+
err_conf:
1169+
configfs_unregister_subsystem(&nullb_subsys);
9641170
err_tagset:
9651171
if (g_queue_mode == NULL_Q_MQ && shared_tags)
9661172
blk_mq_free_tag_set(&tag_set);
@@ -971,6 +1177,8 @@ static void __exit null_exit(void)
9711177
{
9721178
struct nullb *nullb;
9731179

1180+
configfs_unregister_subsystem(&nullb_subsys);
1181+
9741182
unregister_blkdev(null_major, "nullb");
9751183

9761184
mutex_lock(&lock);

0 commit comments

Comments
 (0)