[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