[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[dm-devel] [PATCH][RFC] dm+syfs



Currently, a dm device has an entry in /sys/block/dm-* that only displays the block layer attributes (queue, iosched and stats). With the attached patch (dm_sysfs.patch) the dm's attributes can now also be displayed in sysfs. For example, from /sys/block/dm-3 a table with three linear targets would look like this:

|-- dev
|-- mapped_device
|   |-- event_nr
|   |-- flags
|   `-- table
|       |-- target0
|       |   |-- num_sectors
|       |   |-- ram2
|       |   |   |-- ram2 -> ../../../../../../block/ram2
|       |   |   `-- start
|       |   |-- start_sector
|       |   `-- type
|       `-- target1
|           |-- num_sectors
|           |-- ram3
|           |   |-- ram3 -> ../../../../../../block/ram3
|           |   `-- start
|           |-- start_sector
|           `-- type
|-- queue
|   |-- iosched
|   `-- nr_requests
|-- range
|-- size
`-- stat

or a table with a striped target that has three devies would look like the following from /sys/block/dm-3:

|-- dev
|-- mapped_device
|   |-- event_nr
|   |-- flags
|   `-- table
|       `-- target0
|           |-- chunk_size
|           |-- num_sectors
|           |-- num_stripes
|           |-- ram4
|           |   |-- ram4 -> ../../../../../../block/ram4
|           |   `-- start
|           |-- ram5
|           |   |-- ram5 -> ../../../../../../block/ram5
|           |   `-- start
|           |-- ram6
|           |   |-- ram6 -> ../../../../../../block/ram6
|           |   `-- start
|           |-- start_sector
|           `-- type
|-- queue
|   |-- iosched
|   `-- nr_requests
|-- range
|-- size
`-- stat

dm_sysfs.patch was built against 2.6.0-test7.


Mike Christie mikenc us ibm com
diff -Naur linux-2.6.0-test7/drivers/md/dm.c linux-2.6.0-test7-work/drivers/md/dm.c
--- linux-2.6.0-test7/drivers/md/dm.c	2003-10-08 12:24:27.000000000 -0700
+++ linux-2.6.0-test7-work/drivers/md/dm.c	2003-10-14 17:50:09.000000000 -0700
@@ -32,45 +32,6 @@
 	struct deferred_io *next;
 };
 
-/*
- * Bits for the md->flags field.
- */
-#define DMF_BLOCK_IO 0
-#define DMF_SUSPENDED 1
-
-struct mapped_device {
-	struct rw_semaphore lock;
-	atomic_t holders;
-
-	unsigned long flags;
-
-	request_queue_t *queue;
-	struct gendisk *disk;
-
-	/*
-	 * A list of ios that arrived while we were suspended.
-	 */
-	atomic_t pending;
-	wait_queue_head_t wait;
-	struct deferred_io *deferred;
-
-	/*
-	 * The current mapping.
-	 */
-	struct dm_table *map;
-
-	/*
-	 * io objects are allocated from here.
-	 */
-	mempool_t *io_pool;
-
-	/*
-	 * Event handling.
-	 */
-	uint32_t event_nr;
-	wait_queue_head_t eventq;
-};
-
 #define MIN_IOS 256
 static kmem_cache_t *_io_cache;
 
@@ -636,6 +597,8 @@
 	sprintf(md->disk->disk_name, "dm-%d", minor);
 	add_disk(md->disk);
 
+	dm_sysfs_register_md(md);
+
 	atomic_set(&md->pending, 0);
 	init_waitqueue_head(&md->wait);
 	init_waitqueue_head(&md->eventq);
@@ -645,12 +608,7 @@
 
 static void free_dev(struct mapped_device *md)
 {
-	free_minor(md->disk->first_minor);
-	mempool_destroy(md->io_pool);
-	del_gendisk(md->disk);
-	put_disk(md->disk);
-	blk_put_queue(md->queue);
-	kfree(md);
+	dm_sysfs_unregister_md(md);
 }
 
 /*
@@ -672,6 +630,8 @@
 	sector_t size;
 	md->map = t;
 
+	dm_sysfs_register_table(md);
+
 	size = dm_table_get_size(t);
 	set_capacity(md->disk, size);
 	if (size == 0)
@@ -690,9 +650,9 @@
 		return;
 
 	dm_table_event_callback(md->map, NULL, NULL);
-	dm_table_put(md->map);
-	md->map = NULL;
 	set_capacity(md->disk, 0);
+	dm_sysfs_unregister_table(md->map);
+	md->map = NULL;
 }
 
 /*
diff -Naur linux-2.6.0-test7/drivers/md/dm.h linux-2.6.0-test7-work/drivers/md/dm.h
--- linux-2.6.0-test7/drivers/md/dm.h	2003-10-08 12:24:04.000000000 -0700
+++ linux-2.6.0-test7-work/drivers/md/dm.h	2003-10-14 15:55:16.000000000 -0700
@@ -42,12 +42,109 @@
 	atomic_t count;
 	int mode;
 	struct block_device *bdev;
+
+	/* target specific data */
+	void *private;
+
+	struct kobject kobj;
+	struct attribute_group *attr_group;
+};
+
+/*
+ * Bits for the md->flags field.
+ */
+#define DMF_BLOCK_IO 0
+#define DMF_SUSPENDED 1
+
+struct mapped_device {
+	struct rw_semaphore lock;
+	atomic_t holders;
+
+	unsigned long flags;
+
+	request_queue_t *queue;
+	struct gendisk *disk;
+
+	/*
+	 * A list of ios that arrived while we were suspended.
+	 */
+	atomic_t pending;
+	wait_queue_head_t wait;
+	struct deferred_io *deferred;
+
+	/*
+	 * The current mapping.
+	 */
+	struct dm_table *map;
+
+	/*
+	 * io objects are allocated from here.
+	 */
+	mempool_t *io_pool;
+
+	/*
+	 * Event handling.
+	 */
+	uint32_t event_nr;
+	wait_queue_head_t eventq;
+
+	/*
+	 * driver model
+	 */
+	struct kobject kobj;
+};
+
+#define MAX_DEPTH 16
+
+struct dm_table {
+	atomic_t holders;
+
+	/* btree table */
+	unsigned int depth;
+	unsigned int counts[MAX_DEPTH];	/* in nodes */
+	sector_t *index[MAX_DEPTH];
+
+	unsigned int num_targets;
+	unsigned int num_allocated;
+	sector_t *highs;
+	struct dm_target *targets;
+
+	/*
+	 * Indicates the rw permissions for the new logical
+	 * device.  This should be a combination of FMODE_READ
+	 * and FMODE_WRITE.
+	 */
+	int mode;
+
+	/*
+	 * These are optimistic limits taken from all the
+	 * targets, some targets will need smaller limits.
+	 */
+	struct io_restrictions limits;
+
+	/* events get handed up using this callback */
+	void (*event_fn)(void *);
+	void *event_context;
+
+	/*
+	 * driver model
+	 */
+	struct kobject kobj;
 };
 
 struct dm_table;
 struct mapped_device;
 
 /*-----------------------------------------------------------------
+ * Functions for registering a mapped_device and table with sysfs.
+ *---------------------------------------------------------------*/
+int dm_sysfs_register_md(struct mapped_device *md);
+void dm_sysfs_unregister_md(struct mapped_device *md);
+
+int dm_sysfs_register_table(struct mapped_device *md);
+void dm_sysfs_unregister_table(struct dm_table *tbl);
+
+/*-----------------------------------------------------------------
  * Functions for manipulating a struct mapped_device.
  * Drop the reference with dm_put when you finish with the object.
  *---------------------------------------------------------------*/
@@ -111,7 +208,7 @@
 struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
 void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q);
 unsigned int dm_table_get_num_targets(struct dm_table *t);
-struct list_head *dm_table_get_devices(struct dm_table *t);
+struct list_head *dm_target_get_devices(struct dm_target *t);
 int dm_table_get_mode(struct dm_table *t);
 void dm_table_suspend_targets(struct dm_table *t);
 void dm_table_resume_targets(struct dm_table *t);
diff -Naur linux-2.6.0-test7/drivers/md/dm-ioctl-v4.c linux-2.6.0-test7-work/drivers/md/dm-ioctl-v4.c
--- linux-2.6.0-test7/drivers/md/dm-ioctl-v4.c	2003-10-08 12:24:00.000000000 -0700
+++ linux-2.6.0-test7-work/drivers/md/dm-ioctl-v4.c	2003-10-14 15:55:16.000000000 -0700
@@ -933,17 +933,22 @@
 			  struct dm_ioctl *param, size_t param_size)
 {
 	unsigned int count = 0;
-	struct list_head *tmp;
 	size_t len, needed;
 	struct dm_target_deps *deps;
+	int i, num_tgts = dm_table_get_num_targets(table);
 
 	deps = get_result_buffer(param, param_size, &len);
 
 	/*
 	 * Count the devices.
 	 */
-	list_for_each(tmp, dm_table_get_devices(table))
-		count++;
+	for (i = 0; i < num_tgts; i++) {
+		struct dm_target *tgt = dm_table_get_target(table, i);
+		struct list_head *tmp;
+
+		list_for_each(tmp, dm_target_get_devices(tgt))
+			count++;
+	}
 
 	/*
 	 * Check we have enough space.
@@ -959,9 +964,15 @@
 	 */
 	deps->count = count;
 	count = 0;
-	list_for_each(tmp, dm_table_get_devices(table)) {
-		struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
-		deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev);
+	for (i = 0; i < num_tgts; i++) {
+		struct dm_target *tgt = dm_table_get_target(table, i);
+		struct list_head *tmp;
+
+		list_for_each(tmp, dm_target_get_devices(tgt)) {
+			struct dm_dev *dd = list_entry(tmp, struct dm_dev,
+						       list);
+			deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev);
+		}
 	}
 
 	param->data_size = param->data_start + needed;
diff -Naur linux-2.6.0-test7/drivers/md/dm-linear.c linux-2.6.0-test7-work/drivers/md/dm-linear.c
--- linux-2.6.0-test7/drivers/md/dm-linear.c	2003-10-08 12:24:07.000000000 -0700
+++ linux-2.6.0-test7-work/drivers/md/dm-linear.c	2003-10-14 15:55:16.000000000 -0700
@@ -20,6 +20,28 @@
 	sector_t start;
 };
 
+static ssize_t show_start(struct dm_dev *dmdev, char *buf)
+{
+	struct linear_c *lc = (struct linear_c*) dmdev->private;
+	return snprintf(buf, 32, ""SECTOR_FORMAT"\n", lc->start);
+}
+
+static struct dm_dev_sysfs_entry start_entry = {
+	.attr = {.name = "start",
+		 .mode = S_IRUGO,
+		 .owner = THIS_MODULE },
+	.show = show_start,
+};
+
+static struct attribute *linear_attrs[] = {
+	&start_entry.attr,
+	NULL
+};
+
+static struct attribute_group linear_attr_group = {
+	.attrs = linear_attrs,
+};
+
 /*
  * Construct a linear mapping: <dev_path> <offset>
  */
@@ -49,6 +71,7 @@
 		goto bad;
 	}
 
+	dm_sysfs_init_dev(lc->dev, lc, &linear_attr_group);
 	ti->private = lc;
 	return 0;
 
diff -Naur linux-2.6.0-test7/drivers/md/dm-stripe.c linux-2.6.0-test7-work/drivers/md/dm-stripe.c
--- linux-2.6.0-test7/drivers/md/dm-stripe.c	2003-10-08 12:24:05.000000000 -0700
+++ linux-2.6.0-test7-work/drivers/md/dm-stripe.c	2003-10-14 15:55:16.000000000 -0700
@@ -17,6 +17,28 @@
 	sector_t physical_start;
 };
 
+static ssize_t show_start(struct dm_dev *dmdev, char *buf)
+{
+	struct stripe *s = (struct stripe *) dmdev->private;
+	return snprintf(buf, 32, ""SECTOR_FORMAT"\n", s->physical_start);
+}
+
+static struct dm_dev_sysfs_entry start_entry = {
+	.attr = {.name = "start",
+		 .mode = S_IRUGO,
+		 .owner = THIS_MODULE },
+	.show = show_start,
+};
+
+static struct attribute *stripe_attrs[] = {
+	&start_entry.attr,
+	NULL
+};
+
+static struct attribute_group stripe_attr_group = {
+	.attrs = stripe_attrs,
+};
+
 struct stripe_c {
 	uint32_t stripes;
 
@@ -30,6 +52,42 @@
 	struct stripe stripe[0];
 };
 
+static ssize_t show_num_stripes(struct dm_target *tgt, char *buf)
+{
+	struct stripe_c *sc = (struct stripe_c *) tgt->private;
+	return snprintf(buf, 32, "%u\n", sc->stripes);
+}
+
+static ssize_t show_chunk_size(struct dm_target *tgt, char *buf)
+{
+	struct stripe_c *sc = (struct stripe_c *) tgt->private;
+	return snprintf(buf, 32, "%u\n", sc->stripe_width);
+}
+
+static struct dm_target_sysfs_entry num_stripes_entry = {
+	.attr = {.name = "num_stripes",
+		 .mode = S_IRUGO,
+		 .owner = THIS_MODULE },
+	.show = show_num_stripes,
+};
+
+static struct dm_target_sysfs_entry chunk_size_entry = {
+	.attr = {.name = "chunk_size",
+		 .mode = S_IRUGO,
+		 .owner = THIS_MODULE },
+	.show = show_chunk_size,
+};
+
+static struct attribute *stripe_c_attrs[] = {
+	&num_stripes_entry.attr,
+	&chunk_size_entry.attr,
+	NULL
+};
+
+static struct attribute_group stripe_c_attr_group = {
+	.attrs = stripe_c_attrs,
+};
+
 static inline struct stripe_c *alloc_context(unsigned int stripes)
 {
 	size_t len;
@@ -60,6 +118,10 @@
 		return -ENXIO;
 
 	sc->stripe[stripe].physical_start = start;
+	dm_sysfs_init_dev(sc->stripe[stripe].dev,
+			  &sc->stripe[stripe],
+			  &stripe_attr_group);
+	
 	return 0;
 }
 
@@ -151,6 +213,7 @@
 		}
 	}
 
+	dm_sysfs_init_target(ti, &stripe_c_attr_group);
 	ti->private = sc;
 	return 0;
 }
diff -Naur linux-2.6.0-test7/drivers/md/dm-sysfs.c linux-2.6.0-test7-work/drivers/md/dm-sysfs.c
--- linux-2.6.0-test7/drivers/md/dm-sysfs.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.0-test7-work/drivers/md/dm-sysfs.c	2003-10-14 15:55:16.000000000 -0700
@@ -0,0 +1,488 @@
+/*
+ * dm-sysfs.c - sysfs code for Device Mapper
+ * Written by Mike Christie (mikenc us ibm com)
+ * Copyright (C) 2003 IBM Corp.
+ */
+
+#include "dm.h"
+
+#include <linux/kobject.h>
+#include <linux/dm-ioctl-v4.h>
+
+/*********************************************************
+ *
+ * device mapper mapped_device sysfs functions
+ *
+ *********************************************************/
+
+inline struct mapped_device *dm_kobj_to_md(struct kobject *kobj)
+{
+	return container_of(kobj, struct mapped_device, kobj);
+}
+
+struct md_sysfs_entry {
+	struct attribute attr;
+	ssize_t (*show)(struct mapped_device *, char *);
+	ssize_t (*store)(struct mapped_device *, 
+			 const char *, size_t);
+};
+
+static ssize_t md_show_event(struct mapped_device *md, char *buf)
+{
+	return snprintf(buf, 20, "%u\n", md->event_nr);
+}
+
+static ssize_t md_show_flags(struct mapped_device *md, char *buf)
+{
+	unsigned int flags = 0;
+
+	if (dm_suspended(md))
+		flags |= DM_SUSPEND_FLAG;
+
+	if (md->disk->policy)
+		flags |= DM_READONLY_FLAG;
+
+	if (md->map)
+		flags |= DM_ACTIVE_PRESENT_FLAG;
+
+	return snprintf(buf, 20, "0x%x\n", flags);
+}
+
+static struct md_sysfs_entry md_event_entry = {
+	.attr = {.name = "event_nr",
+		 .mode = S_IRUGO,
+		 .owner = THIS_MODULE },
+	.show = md_show_event,
+};
+
+static struct md_sysfs_entry md_flags_entry = {
+	.attr = {.name = "flags",
+		 .mode = S_IRUGO,
+		 .owner = THIS_MODULE },
+	.show = md_show_flags,
+};
+
+static struct attribute *md_attrs[] = {
+	&md_event_entry.attr,
+	&md_flags_entry.attr,
+	NULL
+};
+
+static inline struct md_sysfs_entry *attr_to_md_entry(struct attribute *attr)
+{
+	return container_of((attr), struct md_sysfs_entry, attr);
+}
+
+static ssize_t md_attr_show(struct kobject *kobj, struct attribute *attr,
+			    char *buf)
+{
+	struct md_sysfs_entry *entry = attr_to_md_entry(attr);
+	struct mapped_device *md;
+
+	if (!entry->show)
+		return 0;
+
+	md = dm_kobj_to_md(kobj);
+	return entry->show(md, buf);
+}
+
+static ssize_t md_attr_store(struct kobject *kobj, struct attribute *attr,
+			     const char *page, size_t length)
+{
+	struct md_sysfs_entry *entry = attr_to_md_entry(attr);
+	struct mapped_device *md;
+
+	if (!entry->store)
+		return-EINVAL;
+
+	md = dm_kobj_to_md(kobj);
+	return entry->store(md, page, length);
+}
+
+static struct sysfs_ops md_sysfs_ops = {
+	.show	= md_attr_show,
+	.store	= md_attr_store,
+};
+
+static void md_kobj_release(struct kobject *kobj)
+{
+	struct mapped_device *md;
+	struct kobject *parent;
+
+	md = dm_kobj_to_md(kobj);
+	parent = &md->disk->kobj;
+
+	del_gendisk(md->disk);
+	put_disk(md->disk);
+	blk_put_queue(md->queue);
+	mempool_destroy(md->io_pool);
+	kfree(md);
+
+	kobject_put(parent);
+}
+
+struct kobj_type md_ktype = {
+	.release	= md_kobj_release,
+	.sysfs_ops	= &md_sysfs_ops,
+	.default_attrs	= md_attrs,
+};
+
+int dm_sysfs_register_md(struct mapped_device *md)
+{
+	if (!md) return -EINVAL;
+
+	md->kobj.parent = kobject_get(&md->disk->kobj);
+	if (!md->kobj.parent) return -EINVAL;
+
+	snprintf(md->kobj.name, KOBJ_NAME_LEN, "%s", "mapped_device");
+	md->kobj.ktype = &md_ktype;
+
+	return kobject_register(&md->kobj);
+}
+
+void dm_sysfs_unregister_md(struct mapped_device *md)
+{
+	if (md)	kobject_unregister(&md->kobj);
+}
+
+
+/*********************************************************
+ *
+ * device mapper dm_dev sysfs functions
+ *
+ *********************************************************/
+
+static inline struct dm_dev *kobj_to_device(struct kobject *kobj)
+{
+	return container_of(kobj, struct dm_dev, kobj);
+}
+
+static inline struct dm_dev_sysfs_entry *attr_to_device_entry(struct attribute *attr)
+{
+	return container_of((attr), struct dm_dev_sysfs_entry, attr);
+}
+
+static ssize_t device_attr_show(struct kobject *kobj, struct attribute *attr,
+				char *buf)
+{
+	struct dm_dev_sysfs_entry *entry = attr_to_device_entry(attr);
+	struct dm_dev *dmdev;
+	
+	if (!entry->show)
+		return 0;
+	
+	dmdev = kobj_to_device(kobj);
+	return entry->show(dmdev, buf);
+}
+
+static ssize_t device_attr_store(struct kobject *kobj, struct attribute *attr,
+				 const char *page, size_t length)
+{
+	struct dm_dev_sysfs_entry *entry = attr_to_device_entry(attr);
+	struct dm_dev *dmdev;
+
+	if (!entry->store)
+		return -EINVAL;
+
+	dmdev = kobj_to_device(kobj);
+	return entry->store(dmdev, page, length);
+}
+
+static struct sysfs_ops device_sysfs_ops = {
+	.show	= device_attr_show,
+	.store	= device_attr_store,
+};
+
+static void device_kobj_release(struct kobject *kobj)
+{
+	struct kobject *parent = kobj->parent;
+	struct dm_dev *dmdev;
+
+	dmdev = kobj_to_device(kobj);
+	kobject_put(parent);
+}
+
+static struct kobj_type dmdev_ktype = {
+	.release	= device_kobj_release,
+	.sysfs_ops	= &device_sysfs_ops,
+};
+
+static int device_sysfs_register(struct dm_target *tgt,
+				 struct dm_dev *dmdev)
+{
+	int err;
+	struct gendisk *disk = dmdev->bdev->bd_disk;
+
+	dmdev->kobj.parent = kobject_get(&tgt->kobj);
+	snprintf(dmdev->kobj.name, KOBJ_NAME_LEN, "%s",
+		 disk->disk_name);
+	dmdev->kobj.ktype = &dmdev_ktype;
+
+	err = kobject_register(&dmdev->kobj);
+	if (err)
+		return err;
+
+	if (dmdev->attr_group) {
+		err = sysfs_create_group(&dmdev->kobj,
+					 dmdev->attr_group);
+		if (err) {
+			kobject_unregister(&dmdev->kobj);
+			return err;
+		}
+	}
+	
+	sysfs_create_link(&dmdev->kobj, &disk->kobj,
+			  disk->disk_name);
+
+	return 0;
+}
+
+static void device_sysfs_unregister(struct dm_dev *dmdev)
+{
+	struct gendisk *disk = dmdev->bdev->bd_disk;
+
+	if (dmdev->attr_group)
+		sysfs_remove_group(&dmdev->kobj, dmdev->attr_group);
+
+	sysfs_remove_link(&dmdev->kobj, disk->disk_name);
+	kobject_unregister(&dmdev->kobj);
+}
+
+void dm_sysfs_init_dev(struct dm_dev *dmdev, void *priv,
+		       struct attribute_group *attr_group)
+{
+	if (dmdev) {
+		dmdev->private = priv;
+		dmdev->attr_group = attr_group;
+	}
+}
+
+/*********************************************************
+ *
+ * device mapper dm_target sysfs functions
+ *
+ *********************************************************/
+
+static inline struct dm_target *kobj_to_target(struct kobject *kobj)
+{
+	return container_of(kobj, struct dm_target, kobj);
+}
+
+static ssize_t target_show_begin(struct dm_target *tgt, char *buf)
+{
+	return snprintf(buf, 20, ""SECTOR_FORMAT"\n", tgt->begin);
+}
+
+static ssize_t target_show_len(struct dm_target *tgt, char *buf)
+{
+	return snprintf(buf, 20, ""SECTOR_FORMAT"\n", tgt->len);
+}
+
+static ssize_t target_show_type(struct dm_target *tgt, char *buf)
+{
+	return snprintf(buf, 32, "%s\n", tgt->type->name);
+}
+
+static struct dm_target_sysfs_entry target_begin_entry = {
+	.attr = {.name = "start_sector",
+		 .mode = S_IRUGO,
+		 .owner = THIS_MODULE },
+	.show = target_show_begin,
+};
+
+static struct dm_target_sysfs_entry target_len_entry = {
+	.attr = {.name = "num_sectors",
+		 .mode = S_IRUGO,
+		 .owner = THIS_MODULE },
+	.show = target_show_len,
+};
+
+static struct dm_target_sysfs_entry target_type_entry = {
+	.attr = {.name = "type",
+		 .mode = S_IRUGO,
+		 .owner = THIS_MODULE },
+	.show = target_show_type,
+};
+
+static struct attribute *default_target_attrs[] = {
+	&target_type_entry.attr,
+	&target_len_entry.attr,
+	&target_begin_entry.attr,
+	NULL
+};
+
+static inline struct dm_target_sysfs_entry *attr_to_tgt_entry(struct attribute *attr)
+{
+	return container_of((attr), struct dm_target_sysfs_entry, attr);
+}
+
+static ssize_t target_attr_show(struct kobject *kobj, struct attribute *attr,
+				char *buf)
+{
+	struct dm_target_sysfs_entry *entry = attr_to_tgt_entry(attr);
+	struct dm_target *tgt;
+
+	if (!entry->show)
+		return 0;
+
+	tgt = kobj_to_target(kobj);
+	return entry->show(tgt, buf);
+}
+
+
+static ssize_t target_attr_store(struct kobject *kobj, struct attribute *attr,
+				const char *page, size_t length)
+{
+	struct dm_target_sysfs_entry *entry = attr_to_tgt_entry(attr);
+	struct dm_target *tgt;
+
+	if (!entry->store)
+		return -EINVAL;
+
+	tgt = kobj_to_target(kobj);
+	return entry->store(tgt, page, length);
+}
+
+static struct sysfs_ops target_sysfs_ops = {
+	.show	= target_attr_show,
+	.store	= target_attr_store,
+};
+
+static void target_kobj_release(struct kobject *kobj)
+{
+	struct kobject *parent = kobj->parent;
+	struct dm_target *tgt;
+
+	tgt = kobj_to_target(kobj);
+	kobject_put(parent);
+}
+
+static struct kobj_type target_ktype = {
+	.release	= target_kobj_release,
+	.sysfs_ops	= &target_sysfs_ops,
+	.default_attrs	= default_target_attrs,
+};
+
+static int target_sysfs_register(struct dm_target *tgt, int i)
+{
+	struct list_head *curr;
+	int err;
+
+	tgt->kobj.parent = kobject_get(&tgt->table->kobj);
+	snprintf(tgt->kobj.name, KOBJ_NAME_LEN, "%s%d", "target", i);
+	tgt->kobj.ktype = &target_ktype;
+
+	err = kobject_register(&tgt->kobj);
+	if (err)
+		return err;
+
+	if (tgt->attr_group) {
+		err = sysfs_create_group(&tgt->kobj, tgt->attr_group);
+		if (err) {
+			kobject_unregister(&tgt->kobj);
+			return err;
+		}
+	}
+
+	list_for_each(curr, &tgt->devices) {
+		struct dm_dev *dmdev;
+
+		dmdev = list_entry(curr, struct dm_dev, list);
+		device_sysfs_register(tgt, dmdev);
+	}
+
+	return 0;
+}
+
+static void target_sysfs_unregister(struct dm_target *tgt)
+{	
+	struct list_head *curr;
+
+	if (tgt->attr_group)
+		sysfs_remove_group(&tgt->kobj, tgt->attr_group);
+
+	list_for_each(curr, &tgt->devices) {
+		struct dm_dev *dmdev;
+
+		dmdev = list_entry(curr, struct dm_dev, list);
+		device_sysfs_unregister(dmdev);
+	}
+
+	kobject_unregister(&tgt->kobj);
+}
+
+void dm_sysfs_init_target(struct dm_target *tgt,
+			  struct attribute_group *attr_group)
+{
+	if (tgt) tgt->attr_group = attr_group;
+}
+
+/*********************************************************
+ *
+ * device mapper dm_table sysfs functions
+ *
+ *********************************************************/
+
+
+static inline struct dm_table *kobj_to_table(struct kobject *kobj)
+{
+	return container_of(kobj, struct dm_table, kobj);
+}
+
+static void table_kobj_release(struct kobject *kobj)
+{
+	struct dm_table *tbl;
+	struct kobject *parent = kobj->parent;
+
+	tbl = kobj_to_table(kobj);
+	dm_table_put(tbl);
+
+	if (parent)
+		kobject_put(parent);
+}
+
+static struct kobj_type table_ktype = {
+	.release	= table_kobj_release,
+};
+
+int dm_sysfs_register_table(struct mapped_device *md)
+{
+	int err, i, num_tgts;
+	struct dm_table *tbl = md->map;
+
+	if (!tbl) return -EINVAL;
+
+	snprintf(tbl->kobj.name, KOBJ_NAME_LEN, "%s", "table");
+	tbl->kobj.ktype = &table_ktype;
+	tbl->kobj.parent = kobject_get(&md->kobj);
+
+	err =  kobject_register(&tbl->kobj);
+	if (err) return err;
+
+	num_tgts = dm_table_get_num_targets(tbl);
+	for (i = 0; i < num_tgts; i++) {
+		err = target_sysfs_register(dm_table_get_target(tbl, i), i);
+		if (err) {
+			kobject_unregister(&tbl->kobj);
+			break;
+		}
+	}
+
+	return err;
+}
+
+void dm_sysfs_unregister_table(struct dm_table *tbl)
+{	
+	int i, num_tgts;
+	
+	if (!tbl) return;
+
+	num_tgts = dm_table_get_num_targets(tbl);
+	for (i = 0; i < num_tgts; i++)
+		target_sysfs_unregister(dm_table_get_target(tbl, i));
+
+	kobject_unregister(&tbl->kobj);
+}
+
+EXPORT_SYMBOL(dm_sysfs_init_dev);
+EXPORT_SYMBOL(dm_sysfs_init_target);
diff -Naur linux-2.6.0-test7/drivers/md/dm-table.c linux-2.6.0-test7-work/drivers/md/dm-table.c
--- linux-2.6.0-test7/drivers/md/dm-table.c	2003-10-08 12:24:51.000000000 -0700
+++ linux-2.6.0-test7-work/drivers/md/dm-table.c	2003-10-14 17:43:18.000000000 -0700
@@ -14,45 +14,10 @@
 #include <linux/slab.h>
 #include <asm/atomic.h>
 
-#define MAX_DEPTH 16
 #define NODE_SIZE L1_CACHE_BYTES
 #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t))
 #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
 
-struct dm_table {
-	atomic_t holders;
-
-	/* btree table */
-	unsigned int depth;
-	unsigned int counts[MAX_DEPTH];	/* in nodes */
-	sector_t *index[MAX_DEPTH];
-
-	unsigned int num_targets;
-	unsigned int num_allocated;
-	sector_t *highs;
-	struct dm_target *targets;
-
-	/*
-	 * Indicates the rw permissions for the new logical
-	 * device.  This should be a combination of FMODE_READ
-	 * and FMODE_WRITE.
-	 */
-	int mode;
-
-	/* a list of devices used by this table */
-	struct list_head devices;
-
-	/*
-	 * These are optimistic limits taken from all the
-	 * targets, some targets will need smaller limits.
-	 */
-	struct io_restrictions limits;
-
-	/* events get handed up using this callback */
-	void (*event_fn)(void *);
-	void *event_context;
-};
-
 /*
  * Similar to ceiling(log_size(n))
  */
@@ -210,7 +175,6 @@
 		return -ENOMEM;
 
 	memset(t, 0, sizeof(*t));
-	INIT_LIST_HEAD(&t->devices);
 	atomic_set(&t->holders, 1);
 
 	/* allocate a single nodes worth of targets to begin with */
@@ -252,18 +216,16 @@
 			tgt->type->dtr(tgt);
 
 		dm_put_target_type(tgt->type);
-	}
 
-	vfree(t->highs);
+		if (tgt->devices.next != &tgt->devices) {
+			DMWARN("devices still present during destroy: "
+			       "dm_put_device calls missing");
 
-	/* free the device list */
-	if (t->devices.next != &t->devices) {
-		DMWARN("devices still present during destroy: "
-		       "dm_table_remove_device calls missing");
-
-		free_devices(&t->devices);
+			free_devices(&tgt->devices);
+		}
 	}
 
+	vfree(t->highs);
 	kfree(t);
 }
 
@@ -434,11 +396,12 @@
 			return r;
 	}
 
-	dd = find_device(&t->devices, dev);
+	dd = find_device(&ti->devices, dev);
 	if (!dd) {
 		dd = kmalloc(sizeof(*dd), GFP_KERNEL);
 		if (!dd)
 			return -ENOMEM;
+		memset(dd, 0, sizeof(*dd));
 
 		dd->mode = mode;
 		dd->bdev = NULL;
@@ -449,7 +412,7 @@
 		}
 
 		atomic_set(&dd->count, 0);
-		list_add(&dd->list, &t->devices);
+		list_add(&dd->list, &ti->devices);
 
 	} else if (dd->mode != (mode | dd->mode)) {
 		r = upgrade_mode(dd, mode);
@@ -626,6 +589,7 @@
 
 	tgt = t->targets + t->num_targets;
 	memset(tgt, 0, sizeof(*tgt));
+	INIT_LIST_HEAD(&tgt->devices);
 
 	tgt->type = dm_get_target_type(type);
 	if (!tgt->type) {
@@ -789,9 +753,9 @@
 	return t->num_targets;
 }
 
-struct list_head *dm_table_get_devices(struct dm_table *t)
+struct list_head *dm_target_get_devices(struct dm_target *tgt)
 {
-	return &t->devices;
+	return &tgt->devices;
 }
 
 int dm_table_get_mode(struct dm_table *t)
@@ -799,6 +763,11 @@
 	return t->mode;
 }
 
+struct kobject *dm_table_get_kobj(struct dm_table *t)
+{
+	return &t->kobj;
+}
+
 void dm_table_suspend_targets(struct dm_table *t)
 {
 	int i;
diff -Naur linux-2.6.0-test7/drivers/md/Makefile linux-2.6.0-test7-work/drivers/md/Makefile
--- linux-2.6.0-test7/drivers/md/Makefile	2003-10-08 12:24:07.000000000 -0700
+++ linux-2.6.0-test7-work/drivers/md/Makefile	2003-10-14 15:55:16.000000000 -0700
@@ -2,8 +2,8 @@
 # Makefile for the kernel software RAID and LVM drivers.
 #
 
-dm-mod-objs	:= dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
-		   dm-ioctl.o
+dm-mod-objs	:= dm-sysfs.o dm.o dm-table.o dm-target.o dm-linear.o \
+			dm-stripe.o dm-ioctl.o
 
 # Note: link order is important.  All raid personalities
 # and xor.o must come before md.o, as they each initialise 
diff -Naur linux-2.6.0-test7/include/linux/device-mapper.h linux-2.6.0-test7-work/include/linux/device-mapper.h
--- linux-2.6.0-test7/include/linux/device-mapper.h	2003-10-08 12:24:17.000000000 -0700
+++ linux-2.6.0-test7-work/include/linux/device-mapper.h	2003-10-14 17:24:55.000000000 -0700
@@ -82,6 +82,9 @@
 	sector_t begin;
 	sector_t len;
 
+	/* a list of devices used by this target */
+	struct list_head devices;
+
 	/* FIXME: turn this into a mask, and merge with io_restrictions */
 	sector_t split_io;
 
@@ -96,9 +99,35 @@
 
 	/* Used to provide an error string from the ctr */
 	char *error;
+
+	/* driver model */
+	struct kobject kobj;
+	struct attribute_group *attr_group;
 };
 
 int dm_register_target(struct target_type *t);
 int dm_unregister_target(struct target_type *t);
 
+/*
+ * Functions and structures for displaying target
+ * attributes in sysfs.
+ */
+struct dm_target_sysfs_entry {
+	struct attribute attr;
+	ssize_t (*show)(struct dm_target *, char *);
+	ssize_t (*store)(struct dm_target *, const char *, size_t);
+};
+
+void dm_sysfs_init_target(struct dm_target *tgt,
+			  struct attribute_group *attr_group);
+
+struct dm_dev_sysfs_entry {
+	struct attribute attr;
+	ssize_t (*show)(struct dm_dev *, char *);
+	ssize_t (*store)(struct dm_dev *, const char *, size_t);
+};
+
+void dm_sysfs_init_dev(struct dm_dev *dmdev, void *priv,
+		       struct attribute_group *attr_group);
+
 #endif				/* _LINUX_DEVICE_MAPPER_H */

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]