@@ -20,6 +20,87 @@
#include "gennvm.h"
+static struct attribute gen_type_attr = {
+ .name = "type",
+ .mode = S_IRUGO
+};
+
+static struct attribute *gen_target_attrs[] = {
+ &gen_type_attr,
+ NULL,
+};
+
+static ssize_t gen_target_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *page)
+{
+ struct nvm_target *t = container_of(kobj, struct nvm_target, kobj);
+
+ if (strcmp(attr->name, "type") == 0)
+ return scnprintf(page, PAGE_SIZE, "%s\n", t->type->name);
+
+ if (t->type->sysfs_show)
+ return t->type->sysfs_show(t, attr, page);
+
+ return scnprintf(page, PAGE_SIZE,
+ "Unhandled attr(%s) in `nvm_target_attr_show`\n",
+ attr->name);
+}
+
+static const struct sysfs_ops target_sysfs_ops = {
+ .show = gen_target_attr_show,
+};
+
+static void gen_target_release(struct kobject *kobj)
+{
+ struct nvm_target *t = container_of(kobj, struct nvm_target, kobj);
+ struct nvm_tgt_type *tt = t->type;
+ struct gendisk *tdisk = t->disk;
+ struct request_queue *q = tdisk->queue;
+
+ pr_debug("gen: `gen_target_release`\n");
+
+ del_gendisk(tdisk);
+ blk_cleanup_queue(q);
+ put_disk(tdisk);
+
+ if (tt->exit)
+ tt->exit(tdisk->private_data);
+
+ kfree(t);
+}
+
+static struct kobj_type nvm_target_type = {
+ .sysfs_ops = &target_sysfs_ops,
+ .default_attrs = gen_target_attrs,
+ .release = gen_target_release
+};
+
+void gen_unregister_target(struct nvm_target *t)
+{
+ kobject_uevent(&t->kobj, KOBJ_REMOVE);
+ kobject_del(&t->kobj);
+ kobject_put(&t->kobj);
+}
+
+int gen_register_target(struct nvm_target *t)
+{
+ struct gendisk *disk = t->disk;
+ struct device *dev = disk_to_dev(disk);
+ int ret;
+
+ ret = kobject_init_and_add(&t->kobj, &nvm_target_type,
+ kobject_get(&dev->kobj), "%s", "lightnvm");
+ if (ret < 0) {
+ pr_err("gen: `_register_target` failed.\n");
+ kobject_put(&t->kobj);
+ return ret;
+ }
+
+ kobject_uevent(&t->kobj, KOBJ_ADD);
+ return 0;
+}
+
static struct nvm_target *gen_find_target(struct gen_dev *gn, const char *name)
{
struct nvm_target *tgt;
@@ -60,7 +141,7 @@ static int gen_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
}
mutex_unlock(&gn->lock);
- t = kmalloc(sizeof(struct nvm_target), GFP_KERNEL);
+ t = kzalloc(sizeof(struct nvm_target), GFP_KERNEL);
if (!t)
return -ENOMEM;
@@ -89,13 +170,19 @@ static int gen_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
blk_queue_max_hw_sectors(tqueue, 8 * dev->ops->max_phys_sect);
- set_capacity(tdisk, tt->capacity(targetdata));
- add_disk(tdisk);
-
t->type = tt;
t->disk = tdisk;
t->dev = dev;
+ set_capacity(tdisk, tt->capacity(targetdata));
+ add_disk(tdisk);
+
+ if (gen_register_target(t))
+ goto err_init;
+
+ if (tt->sysfs_init)
+ tt->sysfs_init(t);
+
mutex_lock(&gn->lock);
list_add_tail(&t->list, &gn->targets);
mutex_unlock(&gn->lock);
@@ -112,20 +199,10 @@ err_t:
static void __gen_remove_target(struct nvm_target *t)
{
- struct nvm_tgt_type *tt = t->type;
- struct gendisk *tdisk = t->disk;
- struct request_queue *q = tdisk->queue;
-
- del_gendisk(tdisk);
- blk_cleanup_queue(q);
-
- if (tt->exit)
- tt->exit(tdisk->private_data);
-
- put_disk(tdisk);
-
list_del(&t->list);
- kfree(t);
+ if (t->type->sysfs_exit)
+ t->type->sysfs_exit(t);
+ gen_unregister_target(t);
}
/**
@@ -627,7 +704,6 @@ static void gen_lun_info_print(struct nvm_dev *dev)
struct gen_lun *lun;
unsigned int i;
-
gen_for_each_lun(gn, lun, i) {
spin_lock(&lun->vlun.lock);
@@ -211,6 +211,8 @@ struct nvm_target {
struct nvm_dev *dev;
struct nvm_tgt_type *type;
struct gendisk *disk;
+
+ struct kobject kobj;
};
struct nvm_tgt_instance {
@@ -434,6 +436,10 @@ typedef blk_qc_t (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *);
typedef sector_t (nvm_tgt_capacity_fn)(void *);
typedef void *(nvm_tgt_init_fn)(struct nvm_dev *, struct gendisk *, int, int);
typedef void (nvm_tgt_exit_fn)(void *);
+typedef void (nvm_tgt_sysfs_init_fn)(struct nvm_target *);
+typedef void (nvm_tgt_sysfs_exit_fn)(struct nvm_target *);
+typedef ssize_t(nvm_tgt_sysfs_show_fn)(struct nvm_target *,
+ struct attribute *, char *);
struct nvm_tgt_type {
const char *name;
@@ -448,6 +454,10 @@ struct nvm_tgt_type {
nvm_tgt_init_fn *init;
nvm_tgt_exit_fn *exit;
+ nvm_tgt_sysfs_init_fn *sysfs_init;
+ nvm_tgt_sysfs_exit_fn *sysfs_exit;
+ nvm_tgt_sysfs_show_fn *sysfs_show;
+
/* For internal use */
struct list_head list;
};