[Stgt-devel] [PATCH] add stgt_device_template example
Mike Christie
michaelc at cs.wisc.edu
Tue Aug 23 07:59:16 CEST 2005
This adds the beginings of a stgt_device_template for
passthrough commands. It will end up using the block
layer BLOCK_PC facility to pass the command to the
underlying device similar to how we do it for SG_IO
and dm-multipath hw_handlers like dm-emc.c.
It is not completely hooked in yet. The command
handling needs to be done and so does the actual
device creation.
This was built over my last patch.
diff -Naurp trunk/kernel/Makefile trunk.work/kernel/Makefile
--- trunk/kernel/Makefile 2005-08-23 00:48:01.000000000 -0500
+++ trunk.work/kernel/Makefile 2005-08-23 00:31:38.000000000 -0500
@@ -7,6 +7,8 @@ EXTRA_CFLAGS += -I$(obj) -I$(obj)/../inc
ifneq ($(KERNELRELEASE),)
obj-m += stgt_core.o
stgt_core-objs := stgt_sysfs.o stgt.o
+
+obj-m += stgt_sd.o
else
ifeq ($(KERNELSRC),)
diff -Naurp trunk/kernel/stgt.c trunk.work/kernel/stgt.c
--- trunk/kernel/stgt.c 2005-08-23 00:48:01.000000000 -0500
+++ trunk.work/kernel/stgt.c 2005-08-23 00:41:43.000000000 -0500
@@ -48,6 +48,9 @@ MODULE_LICENSE("GPL");
static spinlock_t all_targets_lock;
static LIST_HEAD(all_targets);
+static spinlock_t device_tmpl_lock;
+static LIST_HEAD(device_tmpl_list);
+
static void session_init_handler(void *data);
static spinlock_t atomic_sessions_lock;
static LIST_HEAD(atomic_sessions);
@@ -317,9 +320,77 @@ int stgt_session_destroy(struct stgt_ses
}
EXPORT_SYMBOL(stgt_session_destroy);
-struct stgt_device *
-stgt_device_create(struct stgt_device_template *sdt, struct stgt_target *target,
- char *path, uint32_t lun, unsigned long dflags)
+struct device_type_internal {
+ struct stgt_device_template *sdt;
+ struct list_head list;
+};
+
+static struct stgt_device_template *device_template_get(const char *name)
+{
+ unsigned long flags;
+ struct device_type_internal *ti;
+
+ spin_lock_irqsave(&device_tmpl_lock, flags);
+
+ list_for_each_entry(ti, &device_tmpl_list, list)
+ if (!strcmp(name, ti->sdt->name)) {
+ if (!try_module_get(ti->sdt->module))
+ ti = NULL;
+ spin_unlock_irqrestore(&device_tmpl_lock, flags);
+ return ti ? ti->sdt : NULL;
+ }
+
+ spin_unlock_irqrestore(&device_tmpl_lock, flags);
+
+ return NULL;
+}
+
+static void device_template_put(struct stgt_device_template *sdt)
+{
+ module_put(sdt->module);
+}
+
+int stgt_device_template_register(struct stgt_device_template *sdt)
+{
+ unsigned long flags;
+ struct device_type_internal *ti;
+
+ ti = kmalloc(sizeof(*ti), GFP_KERNEL);
+ if (!ti)
+ return -ENOMEM;
+ memset(ti, 0, sizeof(*ti));
+ INIT_LIST_HEAD(&ti->list);
+ ti->sdt = sdt;
+
+ spin_lock_irqsave(&device_tmpl_lock, flags);
+ list_add_tail(&ti->list, &device_tmpl_list);
+ spin_unlock_irqrestore(&device_tmpl_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(stgt_device_template_register);
+
+void stgt_device_template_unregister(struct stgt_device_template *sdt)
+{
+ unsigned long flags;
+ struct device_type_internal *ti;
+
+ spin_lock_irqsave(&device_tmpl_lock, flags);
+
+ list_for_each_entry(ti, &device_tmpl_list, list)
+ if (ti->sdt == sdt) {
+ list_del(&ti->list);
+ kfree(ti);
+ break;
+ }
+
+ spin_unlock_irqrestore(&device_tmpl_lock, flags);
+}
+EXPORT_SYMBOL_GPL(stgt_device_template_unregister);
+
+struct stgt_device *stgt_device_create(struct stgt_target *target,
+ char *device_type, char *path,
+ uint32_t lun, unsigned long dflags)
{
struct stgt_device *device;
unsigned long flags;
@@ -333,23 +404,43 @@ stgt_device_create(struct stgt_device_te
memset(device, 0, sizeof(*device));
- device->sdt = sdt;
device->lun = lun;
device->target = target;
if (!strcpy(device->path, path))
- goto out;
+ goto free_device;
+
+ device->sdt = device_template_get(device_type);
+ if (device->sdt)
+ goto free_path;
+
+ device->sdt_data = kmalloc(sizeof(device->sdt->priv_data_size),
+ GFP_KERNEL);
+ if (!device->sdt_data)
+ goto put_template;
+
+ if (device->sdt->create)
+ if (device->sdt->create(device))
+ goto free_priv_sdt_data;
if (stgt_sysfs_register_device(device))
- goto out;
+ goto sdt_destroy;
spin_lock_irqsave(&target->lock, flags);
list_add(&device->dlist, &target->device_list);
spin_unlock_irqrestore(&target->lock, flags);
return device;
-out:
- if (device)
- kfree(device->path);
+
+sdt_destroy:
+ if (device->sdt->destroy)
+ device->sdt->destroy(device);
+free_priv_sdt_data:
+ kfree(device->sdt_data);
+put_template:
+ device_template_put(device->sdt);
+free_path:
+ kfree(device->path);
+free_device:
kfree(device);
return NULL;
}
@@ -367,6 +458,10 @@ int stgt_device_destroy(struct stgt_devi
list_del(&device->dlist);
spin_unlock_irqrestore(&target->lock, flags);
+ if (device->sdt->destroy)
+ device->sdt->destroy(device);
+
+ device_template_put(device->sdt);
stgt_sysfs_unregister_device(device);
return 0;
@@ -553,12 +648,19 @@ static void uspace_cmnd_done(struct stgt
cmnd_done(cmnd);
}
-static void virtual_disk_handler(void *data)
+static void queuecommand(void *data)
{
struct stgt_cmnd *cmnd = (struct stgt_cmnd *) data;
dprintk("%x\n", cmnd->scb[0]);
+ /*
+ * seperate vsd (virtual disk from sd (real sd))
+ * call scsi_device_temaplte->prepcommand to see if they want it
+ * and allow them to setup.
+ *
+ * Then call queuecommand
+ */
switch (cmnd->scb[0]) {
case READ_6:
case READ_10:
@@ -595,7 +697,7 @@ int stgt_cmnd_queue(struct stgt_cmnd *cm
return -EINVAL;
}
- work = stgt_init_work(session, virtual_disk_handler, cmnd);
+ work = stgt_init_work(session, queuecommand, cmnd);
if (!work)
return -ENOMEM;
stgt_queue_work(session->target, work);
@@ -714,6 +816,7 @@ static int __init stgt_init(void)
spin_lock_init(&all_targets_lock);
spin_lock_init(&atomic_sessions_lock);
spin_lock_init(&cmnd_hash_lock);
+ spin_lock_init(&device_tmpl_lock);
err = stgt_sysfs_init();
if (err)
diff -Naurp trunk/kernel/stgt_device.h trunk.work/kernel/stgt_device.h
--- trunk/kernel/stgt_device.h 2005-08-23 00:48:01.000000000 -0500
+++ trunk.work/kernel/stgt_device.h 2005-08-23 00:50:33.000000000 -0500
@@ -7,8 +7,18 @@
#include <linux/device.h>
#include <linux/list.h>
+struct stgt_device;
+struct stgt_cmnd;
+
struct stgt_device_template {
const char *name;
+ struct module *module;
+ unsigned priv_data_size;
+
+ int (* create)(struct stgt_device *);
+ void (* destroy)(struct stgt_device *);
+ int (* queuecommand)(struct stgt_device *device, struct stgt_cmnd *cmd);
+ int (* prepcommand)(struct stgt_device *device, struct stgt_cmnd *cmn);
/*
* Pointer to the sysfs class properties for this host, NULL terminated.
@@ -18,6 +28,8 @@ struct stgt_device_template {
struct stgt_device {
struct stgt_device_template *sdt;
+ void *sdt_data;
+
struct class_device cdev;
char *path;
@@ -32,11 +44,14 @@ struct stgt_device {
#define cdev_to_stgt_device(cdev) \
container_of(cdev, struct stgt_device, cdev)
-extern struct stgt_device* stgt_device_create(struct stgt_device_template *sdt,
- struct stgt_target *target, char *path, uint32_t lun,
- unsigned long dflags);
+extern struct stgt_device* stgt_device_create(struct stgt_target *target,
+ char *device_type, char *path,
+ uint32_t lun,
+ unsigned long dflags);
extern int stgt_device_destroy(struct stgt_device *device);
extern int stgt_sysfs_register_device(struct stgt_device *device);
extern void stgt_sysfs_unregister_device(struct stgt_device *device);
+extern int stgt_device_template_register(struct stgt_device_template *sdt);
+extern void stgt_device_template_unregister(struct stgt_device_template *sdt);
#endif
diff -Naurp trunk/kernel/stgt_sd.c trunk.work/kernel/stgt_sd.c
--- trunk/kernel/stgt_sd.c 1969-12-31 18:00:00.000000000 -0600
+++ trunk.work/kernel/stgt_sd.c 2005-08-23 00:50:19.000000000 -0500
@@ -0,0 +1,141 @@
+/*
+ * STGT passthrough device
+ */
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/namei.h>
+
+#include <stgt_device.h>
+
+struct stgt_sd_dev {
+ struct block_device *bdev;
+};
+
+/*
+ * Convert a device path to a dev_t.
+ * from dm-table.c
+ */
+static int lookup_device(const char *path, dev_t *dev)
+{
+ int r;
+ struct nameidata nd;
+ struct inode *inode;
+
+ r = path_lookup(path, LOOKUP_FOLLOW, &nd);
+ if (r)
+ return r;
+
+ inode = nd.dentry->d_inode;
+ if (!inode) {
+ r = -ENOENT;
+ goto out;
+ }
+
+ if (!S_ISBLK(inode->i_mode)) {
+ r = -ENOTBLK;
+ goto out;
+ }
+
+ *dev = inode->i_rdev;
+out:
+ path_release(&nd);
+ return r;
+}
+
+static int open_dev(struct stgt_sd_dev *sddev, dev_t devt)
+{
+ struct block_device *bdev;
+
+ bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
+ if (IS_ERR(bdev))
+ return PTR_ERR(bdev);
+ sddev->bdev = bdev;
+ return 0;
+}
+
+/*
+ * Close a device that we've been using.
+ */
+static void close_dev(struct stgt_sd_dev *sddev)
+{
+ blkdev_put(sddev->bdev);
+}
+
+static int stgt_sd_create(struct stgt_device *device)
+{
+ struct stgt_sd_dev *sddev = device->sdt_data;
+ dev_t devt;
+ int err;
+
+ err = lookup_device(device->path, &devt);
+ if (err)
+ return err;
+
+ sddev = kmalloc(sizeof(*sddev), GFP_KERNEL);
+ if (!sddev)
+ return -ENOMEM;
+
+ err = open_dev(sddev, devt);
+ if (err)
+ goto free_sddev;
+
+ return 0;
+
+free_sddev:
+ kfree(sddev);
+ return err;
+}
+
+static void stgt_sd_destroy(struct stgt_device *device)
+{
+ close_dev(device->sdt_data);
+}
+
+static int stgt_sd_queue(struct stgt_device *device, struct stgt_cmnd *cmnd)
+{
+ /*
+ struct stgt_sd_dev *sddev = device->sdt_data;
+ struct request_queue *q = bdev_get_queue(sddev->bdev);
+ struct request *rq;
+
+ * format struct request as BLOCK_PC command and do
+ * elv_add_request or if James's no_wait helper is in
+ * then use it
+ *
+ * Will need some stgt wrappers/helpers though
+ */
+ return 0;
+}
+
+static int stgt_sd_prep(struct stgt_device *device, struct stgt_cmnd *cmnd)
+{
+ /*
+ * can we take owner ship? If so return 0 else return a enum
+ * (TODO define this)
+ */
+ return 0;
+}
+
+static struct stgt_device_template stgt_sd = {
+ .name = "stgt_sd",
+ .module = THIS_MODULE,
+ .create = stgt_sd_create,
+ .destroy = stgt_sd_destroy,
+ .queuecommand = stgt_sd_queue,
+ .prepcommand = stgt_sd_prep,
+};
+
+static int __init stgt_sd_init(void)
+{
+ stgt_sd.priv_data_size = sizeof(struct stgt_sd_dev);
+ return stgt_device_template_register(&stgt_sd);
+}
+
+static void __exit stgt_sd_exit(void)
+{
+ stgt_device_template_unregister(&stgt_sd);
+}
+
+module_init(stgt_sd_init);
+module_exit(stgt_sd_exit);
+MODULE_LICENSE("GPL");
diff -Naurp trunk/kernel/stgt_sysfs.c trunk.work/kernel/stgt_sysfs.c
--- trunk/kernel/stgt_sysfs.c 2005-08-23 00:48:01.000000000 -0500
+++ trunk.work/kernel/stgt_sysfs.c 2005-08-23 00:25:41.000000000 -0500
@@ -153,6 +153,7 @@ static void stgt_device_class_release(st
struct stgt_target *target = device->target;
class_device_put(&target->cdev);
+ kfree(device->sdt_data);
kfree(device->path);
kfree(device);
}
More information about the stgt
mailing list