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@xxxxxxxxxx
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@xxxxxxxxxx)
+ * 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 */