[Stgt-devel] [PATCH] add sysfs to core stgt structs

Mike Christie michaelc at cs.wisc.edu
Tue Aug 23 04:51:02 CEST 2005


This patch adds sysfs integration to the core stgt structs.
For transport attrs like iscsi session or connection things
or FC rports the LLD can call into the transport class to
do this. If the transport attr is related to the device
or target, then we can just copy more code from scsi-ml
(the transport template pointer on the struct or template
I mean). I could not think of any at the moment so I did
not add this.


I also changed the netlink numbers so I could test with current kernels.



diff -Naurp trunk/iscsi/include/iet_u.h trunk.work/iscsi/include/iet_u.h
--- trunk/iscsi/include/iet_u.h	2005-08-22 18:21:41.000000000 -0500
+++ trunk.work/iscsi/include/iet_u.h	2005-08-22 19:29:06.000000000 -0500
@@ -112,7 +112,7 @@ struct iet_event {
 #define	MIN_NR_QUEUED_CMNDS	1
 #define	MAX_NR_QUEUED_CMNDS	256
 
-#define NETLINK_IET	11
+#define NETLINK_IET	21
 
 #define ADD_TARGET _IOW('i', 0, struct target_info)
 #define DEL_TARGET _IOW('i', 1, struct target_info)
diff -Naurp trunk/iscsi/kernel/iscsi.h trunk.work/iscsi/kernel/iscsi.h
--- trunk/iscsi/kernel/iscsi.h	2005-08-22 18:21:41.000000000 -0500
+++ trunk.work/iscsi/kernel/iscsi.h	2005-08-22 19:33:48.000000000 -0500
@@ -56,6 +56,7 @@ struct network_thread_info {
 };
 
 struct iscsi_cmnd;
+struct stgt_target;
 
 enum iscsi_device_state {
 	IDEV_RUNNING,
diff -Naurp trunk/iscsi/kernel/target.c trunk.work/iscsi/kernel/target.c
--- trunk/iscsi/kernel/target.c	2005-08-22 18:21:41.000000000 -0500
+++ trunk.work/iscsi/kernel/target.c	2005-08-22 19:37:03.000000000 -0500
@@ -10,6 +10,7 @@
 #include <digest.h>
 #include <iscsi_dbg.h>
 #include <stgt.h>
+#include <stgt_target.h>
 
 #define	MAX_NR_TARGETS	(1UL << 30)
 
@@ -111,6 +112,11 @@ static void target_thread_stop(struct is
 	nthread_stop(target);
 }
 
+static struct stgt_target_template iet_stgt_target_template = {
+	.name = "iet",
+	.queued_cmnds = DEFAULT_NR_QUEUED_CMNDS,
+};
+
 static int iscsi_target_create(struct target_info *info, u32 tid)
 {
 	int err = -EINVAL, len;
@@ -154,7 +160,7 @@ static int iscsi_target_create(struct ta
 		goto out;
 	}
 
-	target->stt = stgt_target_create();
+	target->stt = stgt_target_create(&iet_stgt_target_template);
 	assert(target->stt);
 
 	return 0;
diff -Naurp trunk/kernel/Makefile trunk.work/kernel/Makefile
--- trunk/kernel/Makefile	2005-08-22 18:21:40.000000000 -0500
+++ trunk.work/kernel/Makefile	2005-08-22 20:47:51.000000000 -0500
@@ -2,10 +2,11 @@
 # Makefile for the Linux kernel device drivers.
 #
 
-EXTRA_CFLAGS += -I$(obj) -I$(obj)/../include -DNETLINK_STGT=12
+EXTRA_CFLAGS += -I$(obj) -I$(obj)/../include -DNETLINK_STGT=20
 
 ifneq ($(KERNELRELEASE),)
-obj-m		+= stgt.o
+obj-m		+= stgt_core.o
+stgt_core-objs	:= stgt_sysfs.o stgt.o
 else
 
 ifeq ($(KERNELSRC),)
diff -Naurp trunk/kernel/stgt.c trunk.work/kernel/stgt.c
--- trunk/kernel/stgt.c	2005-08-22 18:21:40.000000000 -0500
+++ trunk.work/kernel/stgt.c	2005-08-22 21:42:03.000000000 -0500
@@ -17,6 +17,8 @@
 #include <scsi/scsi.h>
 
 #include <stgt.h>
+#include <stgt_target.h>
+#include <stgt_device.h>
 #include <stgt_if.h>
 
 #define DEBUG_STGT
@@ -127,7 +129,7 @@ static void stgt_queue_work(struct stgt_
 	schedule_work(&target->work);
 }
 
-struct stgt_target *stgt_target_create(void)
+struct stgt_target *stgt_target_create(struct stgt_target_template *stt)
 {
 	struct stgt_target *target;
 
@@ -150,6 +152,13 @@ struct stgt_target *stgt_target_create(v
 	INIT_LIST_HEAD(&target->work_list);
 
 	INIT_WORK(&target->work, stgt_worker, target);
+	target->stt = stt;
+	target->queued_cmnds = stt->queued_cmnds;
+
+	if (stgt_sysfs_register_target(target)) {
+		kfree(target);
+		return NULL;
+	}
 
 	spin_lock(&all_targets_lock);
 	list_add(&target->tlist, &all_targets);
@@ -165,7 +174,7 @@ int stgt_target_destroy(struct stgt_targ
 	list_del(&target->tlist);
 	spin_unlock(&all_targets_lock);
 
-	kfree(target);
+	stgt_sysfs_unregister_target(target);
 
 	return 0;
 }
@@ -309,8 +318,8 @@ int stgt_session_destroy(struct stgt_ses
 EXPORT_SYMBOL(stgt_session_destroy);
 
 struct stgt_device *
-stgt_device_create(struct stgt_target *target, char *path, uint32_t lun,
-		   unsigned long dflags)
+stgt_device_create(struct stgt_device_template *sdt, struct stgt_target *target,
+		   char *path, uint32_t lun, unsigned long dflags)
 {
 	struct stgt_device *device;
 	unsigned long flags;
@@ -324,12 +333,14 @@ stgt_device_create(struct stgt_target *t
 
 	memset(device, 0, sizeof(*device));
 
+	device->sdt = sdt;
 	device->lun = lun;
-	device->path = kmalloc(strlen(path) + 1, GFP_KERNEL);
-	if (!device->path)
+	device->target = target;
+	if (!strcpy(device->path, path))
+		goto out;
+
+	if (stgt_sysfs_register_device(device))
 		goto out;
-	strcpy(device->path, path);
-	device->path[strlen(path)] = '\0';
 
 	spin_lock_irqsave(&target->lock, flags);
 	list_add(&device->dlist, &target->device_list);
@@ -356,8 +367,7 @@ int stgt_device_destroy(struct stgt_devi
 	list_del(&device->dlist);
 	spin_unlock_irqrestore(&target->lock, flags);
 
-	kfree(device->path);
-	kfree(device);
+	stgt_sysfs_unregister_device(device);
 
 	return 0;
 }
@@ -693,6 +703,8 @@ static void __exit stgt_exit(void)
 
 	if (nls)
 		sock_release(nls->sk_socket);
+
+	stgt_sysfs_exit();
 }
 
 static int __init stgt_init(void)
@@ -703,6 +715,10 @@ static int __init stgt_init(void)
 	spin_lock_init(&atomic_sessions_lock);
 	spin_lock_init(&cmnd_hash_lock);
 
+	err = stgt_sysfs_init();
+	if (err)
+		return err;
+
 	cmnd_slab = kmem_cache_create("stgt_cmnd", sizeof(struct stgt_cmnd), 0,
 				      SLAB_HWCACHE_ALIGN | SLAB_NO_REAP,
 				      NULL, NULL);
diff -Naurp trunk/kernel/stgt_device.h trunk.work/kernel/stgt_device.h
--- trunk/kernel/stgt_device.h	1969-12-31 18:00:00.000000000 -0600
+++ trunk.work/kernel/stgt_device.h	2005-08-22 21:37:38.000000000 -0500
@@ -0,0 +1,42 @@
+/*
+ * STGT device
+ */
+#ifndef __SCSI_STGT_DEVICE_H
+#define __SCSI_STGT_DEVICE_H
+
+#include <linux/device.h>
+#include <linux/list.h>
+
+struct stgt_device_template {
+	const char *name;
+
+	/*
+	 * Pointer to the sysfs class properties for this host, NULL terminated.
+	 */
+	struct class_device_attribute **device_attrs;
+};
+
+struct stgt_device {
+	struct stgt_device_template *sdt;
+	struct class_device cdev;
+
+        char *path;
+        uint32_t lun;
+        uint32_t blk_shift;
+        uint64_t blk_count;
+
+        struct stgt_target *target;
+        struct list_head dlist;
+};
+
+#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 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);
+
+#endif
diff -Naurp trunk/kernel/stgt.h trunk.work/kernel/stgt.h
--- trunk/kernel/stgt.h	2005-08-22 18:21:40.000000000 -0500
+++ trunk.work/kernel/stgt.h	2005-08-22 21:14:09.000000000 -0500
@@ -8,19 +8,6 @@
 
 #include <scsi/scsi_cmnd.h>
 
-struct stgt_target {
-	/* Protects session_list, work_list, device_list */
-	spinlock_t lock;
-
-	struct list_head tlist;
-
-	struct list_head device_list;
-	struct list_head session_list;
-
-	struct work_struct work;
-	struct list_head work_list;
-};
-
 struct stgt_session {
 	struct stgt_target *target;
 	struct list_head slist;
@@ -52,19 +39,6 @@ struct stgt_cmnd {
 	void *private;
 };
 
-struct stgt_device {
-	char *path;
-	uint32_t lun;
-	uint32_t blk_shift;
-	uint64_t blk_count;
-
-	struct stgt_target *target;
-	struct list_head dlist;
-};
-
-extern struct stgt_target *stgt_target_create(void);
-extern int stgt_target_destroy(struct stgt_target *target);
-
 extern struct stgt_session *
 stgt_session_create(struct stgt_target *target,
 		    int max_cmnds,
@@ -77,10 +51,6 @@ extern void stgt_cmnd_alloc_buffer(struc
 				  void (*done)(struct stgt_cmnd *));
 extern int stgt_cmnd_queue(struct stgt_cmnd *cmnd,
 			   void (*done)(struct stgt_cmnd *));
-
-extern struct stgt_device*
-stgt_device_create(struct stgt_target *target, char *path, uint32_t lun,
-		   unsigned long dflags);
-extern int stgt_device_destroy(struct stgt_device *device);
-
+extern int stgt_sysfs_init(void);
+extern void stgt_sysfs_exit(void);
 #endif
diff -Naurp trunk/kernel/stgt_sysfs.c trunk.work/kernel/stgt_sysfs.c
--- trunk/kernel/stgt_sysfs.c	1969-12-31 18:00:00.000000000 -0600
+++ trunk.work/kernel/stgt_sysfs.c	2005-08-22 21:44:05.000000000 -0500
@@ -0,0 +1,235 @@
+/*
+ * STGT core sysfs files
+ */
+#include <stgt_target.h>
+#include <stgt_device.h>
+
+/*
+ * Target files
+ */
+#define stgt_target_show_fn(field, format_string)			\
+static ssize_t								\
+show_##field (struct class_device *cdev, char *buf)			\
+{									\
+	struct stgt_target *target = cdev_to_stgt_target(cdev);		\
+	return snprintf (buf, 20, format_string, target->field);	\
+}
+
+#define stgt_target_rd_attr(field, format_string)		\
+	stgt_target_show_fn(field, format_string)		\
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+stgt_target_rd_attr(queued_cmnds, "%u\n");
+
+static struct class_device_attribute *stgt_target_attrs[] = {
+	&class_device_attr_queued_cmnds,
+	NULL
+};
+
+static void stgt_target_class_release(struct class_device *cdev)
+{
+	struct stgt_target *target = cdev_to_stgt_target(cdev);
+	kfree(target);
+}
+
+static struct class stgt_target_class = {
+	.name = "stgt_target",
+	.release = stgt_target_class_release,
+};
+
+/*
+ * Tmp: used for unique class_id names. For software we could
+ * push the naming to userspace
+ */
+static int stgt_target_num = 0;
+
+static struct class_device_attribute *class_attr_overridden(
+				struct class_device_attribute **attrs,
+				struct class_device_attribute *attr)
+{
+	int i;
+
+	if (!attrs)
+		return NULL;
+
+	for (i = 0; attrs[i]; i++)
+		if (!strcmp(attrs[i]->attr.name, attr->attr.name))
+			return attrs[i];
+	return NULL;
+}
+
+static int class_attr_add(struct class_device *classdev,
+			  struct class_device_attribute *attr)
+{
+	struct class_device_attribute *base_attr;
+
+	/*
+	 * Spare the caller from having to copy things it's not interested in.
+	*/
+	base_attr = class_attr_overridden(stgt_target_attrs, attr);
+	if (base_attr) {
+		/* extend permissions */
+		attr->attr.mode |= base_attr->attr.mode;
+
+		/* override null show/store with default */
+		if (!attr->show)
+			attr->show = base_attr->show;
+		if (!attr->store)
+			attr->store = base_attr->store;
+	}
+
+	return class_device_create_file(classdev, attr);
+}
+
+int stgt_sysfs_register_target(struct stgt_target *target)
+{
+	struct class_device *cdev = &target->cdev;
+	int err, i;
+	
+	cdev->class = &stgt_target_class;
+	snprintf(cdev->class_id, BUS_ID_SIZE, "target%d", stgt_target_num);
+
+	err = class_device_register(cdev);
+	if (err)
+		return err;
+
+	if (target->stt->target_attrs) {
+		for (i = 0; target->stt->target_attrs[i]; i++) {
+			err = class_attr_add(&target->cdev,
+					     target->stt->target_attrs[i]);
+                        if (err)
+                                goto cleanup;
+		}
+	}
+
+	for (i = 0; stgt_target_attrs[i]; i++) {
+		if (!class_attr_overridden(target->stt->target_attrs,
+					   stgt_target_attrs[i])) {
+			err = class_device_create_file(&target->cdev,
+						       stgt_target_attrs[i]);
+			if (err)
+				goto cleanup;
+		}
+	}
+
+	return 0;
+
+cleanup:
+	class_device_unregister(cdev);
+	return err;
+}
+
+void stgt_sysfs_unregister_target(struct stgt_target *target)
+{
+	class_device_unregister(&target->cdev);
+}
+
+/*
+ * Device files
+ */
+#define stgt_device_show_fn(field, format_string)			\
+static ssize_t								\
+show_##field (struct class_device *cdev, char *buf)			\
+{									\
+	struct stgt_device *device = cdev_to_stgt_device(cdev);		\
+	return sprintf (buf, format_string, device->field);	\
+}
+
+#define stgt_device_rd_attr(field, format_string)		\
+	stgt_device_show_fn(field, format_string)		\
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+stgt_device_rd_attr(path, "%s\n");
+
+static struct class_device_attribute *stgt_device_attrs[] = {
+	&class_device_attr_path,
+	NULL
+};
+
+
+static void stgt_device_class_release(struct class_device *cdev)
+{
+	struct stgt_device *device = cdev_to_stgt_device(cdev);
+	struct stgt_target *target = device->target;
+
+	class_device_put(&target->cdev);
+	kfree(device->path);
+	kfree(device);
+}
+
+static struct class stgt_device_class = {
+	.name = "stgt_device",
+	.release = stgt_device_class_release,
+};
+
+int stgt_sysfs_register_device(struct stgt_device *device)
+{
+	struct stgt_target *target = device->target;
+	struct class_device *cdev = &device->cdev;
+	int err, i;
+
+	cdev->class = &stgt_device_class;
+	snprintf(cdev->class_id, BUS_ID_SIZE, "device%d", device->lun);
+	err = class_device_register(cdev);
+	if (err)
+		return err;
+
+	/*
+	 * get handle to target so our parent is never released before
+	 * us
+	 */
+	if (!class_device_get(&target->cdev))
+		return -EINVAL;
+
+	if (device->sdt->device_attrs) {
+		for (i = 0; device->sdt->device_attrs[i]; i++) {
+			err = class_attr_add(&device->cdev,
+					     device->sdt->device_attrs[i]);
+                        if (err)
+                                goto cleanup;
+		}
+	}
+
+	for (i = 0; stgt_device_attrs[i]; i++) {
+		if (!class_attr_overridden(device->sdt->device_attrs,
+					   stgt_device_attrs[i])) {
+			err = class_device_create_file(&device->cdev,
+						       stgt_device_attrs[i]);
+			if (err)
+				goto cleanup;
+		}
+	}
+
+	return 0;
+
+cleanup:
+	class_device_put(&target->cdev);
+	class_device_unregister(cdev);
+	return err;
+
+}
+
+void stgt_sysfs_unregister_device(struct stgt_device *device)
+{
+	class_device_unregister(&device->cdev);
+}
+
+int stgt_sysfs_init(void)
+{
+	int err;
+
+	err = class_register(&stgt_target_class);
+	if (err)
+		return err;
+
+	err = class_register(&stgt_device_class);
+	if (err)
+		class_unregister(&stgt_target_class);
+	return err;
+}
+
+void stgt_sysfs_exit(void)
+{
+	class_unregister(&stgt_target_class);
+	class_unregister(&stgt_device_class);
+}
diff -Naurp trunk/kernel/stgt_target.h trunk.work/kernel/stgt_target.h
--- trunk/kernel/stgt_target.h	1969-12-31 18:00:00.000000000 -0600
+++ trunk.work/kernel/stgt_target.h	2005-08-22 21:22:49.000000000 -0500
@@ -0,0 +1,46 @@
+/*
+ * STGT target definitions
+ */
+#ifndef __SCSI_STGT_TARGET_H
+#define __SCSI_STGT_TARGET_H
+
+#include <linux/device.h>
+#include <linux/list.h>
+
+struct stgt_target_template {
+	const char *name;
+
+	int queued_cmnds;
+	/*
+	 * Pointer to the sysfs class properties for this host, NULL terminated.
+	 */
+	struct class_device_attribute **target_attrs;
+};
+
+struct stgt_target {
+	struct stgt_target_template *stt;
+	struct class_device cdev;
+
+	int queued_cmnds;
+
+	/* Protects session_list, work_list, device_list */
+	spinlock_t lock;
+
+	struct list_head tlist;
+
+	struct list_head device_list;
+	struct list_head session_list;
+
+	struct work_struct work;
+	struct list_head work_list;
+};
+
+#define cdev_to_stgt_target(cdev) \
+	container_of(cdev, struct stgt_target, cdev)
+
+extern struct stgt_target *stgt_target_create(struct stgt_target_template *stt);
+extern int stgt_target_destroy(struct stgt_target *target);
+extern int stgt_sysfs_register_target(struct stgt_target *target);
+extern void stgt_sysfs_unregister_target(struct stgt_target *target);
+
+#endif
diff -Naurp trunk/usr/Makefile trunk.work/usr/Makefile
--- trunk/usr/Makefile	2005-08-22 18:21:40.000000000 -0500
+++ trunk.work/usr/Makefile	2005-08-22 19:28:30.000000000 -0500
@@ -1,4 +1,4 @@
-CFLAGS += -O2 -fno-inline -Wall -Wstrict-prototypes -I../include -DNETLINK_STGT=12
+CFLAGS += -O2 -fno-inline -Wall -Wstrict-prototypes -I../include -DNETLINK_STGT=20
 PROGRAMS = stgtd
 
 all: $(PROGRAMS)





More information about the stgt mailing list