1
+ /*
2
+ * Add configfs and memory store: Kyungchan Koh <[email protected] > and
3
+
4
+ */
1
5
#include <linux/module.h>
2
6
3
7
#include <linux/moduleparam.h>
9
13
#include <linux/blk-mq.h>
10
14
#include <linux/hrtimer.h>
11
15
#include <linux/lightnvm.h>
16
+ #include <linux/configfs.h>
12
17
13
18
struct nullb_cmd {
14
19
struct list_head list ;
@@ -30,8 +35,21 @@ struct nullb_queue {
30
35
struct nullb_cmd * cmds ;
31
36
};
32
37
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
+
33
49
struct nullb_device {
34
50
struct nullb * nullb ;
51
+ struct config_item item ;
52
+ unsigned long flags ; /* device flags */
35
53
36
54
unsigned long size ; /* device size in MB */
37
55
unsigned long completion_nsec ; /* time in ns to complete a request */
@@ -173,6 +191,185 @@ static bool g_use_per_node_hctx;
173
191
module_param_named (use_per_node_hctx , g_use_per_node_hctx , bool , S_IRUGO );
174
192
MODULE_PARM_DESC (use_per_node_hctx , "Use per-node allocation for hardware context queues. Default: false" );
175
193
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
+
176
373
static struct nullb_device * null_alloc_dev (void )
177
374
{
178
375
struct nullb_device * dev ;
@@ -919,12 +1116,19 @@ static int __init null_init(void)
919
1116
return ret ;
920
1117
}
921
1118
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
+
922
1126
mutex_init (& lock );
923
1127
924
1128
null_major = register_blkdev (0 , "nullb" );
925
1129
if (null_major < 0 ) {
926
1130
ret = null_major ;
927
- goto err_tagset ;
1131
+ goto err_conf ;
928
1132
}
929
1133
930
1134
if (g_use_lightnvm ) {
@@ -961,6 +1165,8 @@ static int __init null_init(void)
961
1165
kmem_cache_destroy (ppa_cache );
962
1166
err_ppa :
963
1167
unregister_blkdev (null_major , "nullb" );
1168
+ err_conf :
1169
+ configfs_unregister_subsystem (& nullb_subsys );
964
1170
err_tagset :
965
1171
if (g_queue_mode == NULL_Q_MQ && shared_tags )
966
1172
blk_mq_free_tag_set (& tag_set );
@@ -971,6 +1177,8 @@ static void __exit null_exit(void)
971
1177
{
972
1178
struct nullb * nullb ;
973
1179
1180
+ configfs_unregister_subsystem (& nullb_subsys );
1181
+
974
1182
unregister_blkdev (null_major , "nullb" );
975
1183
976
1184
mutex_lock (& lock );
0 commit comments