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

[dm-devel] [PATCH][RESEND+fixes] dm + sysfs



Hello Joe,

This is a resend of my dm+sysfs patch, except I moved everything (mapped_device, dm_table and dm_table's dm_dev list) back to where they belong and added better code to test for and clean up from sysfs/kobject failures.

I also unified the ref counting for the structs represented in sysfs. If someone does "dmsetup remove mydev" but has a dm sysfs file open, the memory for mydev should not be released until the file is closed. For structs like mapped_device and dm_table I removed the atomic_t holders variable and am just using the kobject ref count.

The patch was built and tested against 2.6.0-test9. I have also only tested against the v4 ioctl.

Mike Christie
mikenc us ibm com
diff -Naur linux-2.6.0-test9/drivers/md/dm.c linux-2.6.0-test9-dm/drivers/md/dm.c
--- linux-2.6.0-test9/drivers/md/dm.c	2003-10-25 11:44:25.000000000 -0700
+++ linux-2.6.0-test9-dm/drivers/md/dm.c	2003-11-09 20:03:03.000000000 -0800
@@ -40,7 +40,6 @@
 
 struct mapped_device {
 	struct rw_semaphore lock;
-	atomic_t holders;
 
 	unsigned long flags;
 
@@ -69,6 +68,8 @@
 	 */
 	uint32_t event_nr;
 	wait_queue_head_t eventq;
+
+	struct kobject kobj;
 };
 
 #define MIN_IOS 256
@@ -599,7 +600,6 @@
 
 	memset(md, 0, sizeof(*md));
 	init_rwsem(&md->lock);
-	atomic_set(&md->holders, 1);
 
 	md->queue = blk_alloc_queue(GFP_KERNEL);
 	if (!md->queue) {
@@ -643,7 +643,7 @@
 	return md;
 }
 
-static void free_dev(struct mapped_device *md)
+void dm_free(struct mapped_device *md)
 {
 	free_minor(md->disk->first_minor);
 	mempool_destroy(md->io_pool);
@@ -676,7 +676,8 @@
 	set_capacity(md->disk, size);
 	if (size == 0)
 		return 0;
-
+	
+	dm_sysfs_rename_table(dm_table_get_kobj(t), "table");
 	dm_table_event_callback(md->map, event_callback, md);
 
 	dm_table_get(t);
@@ -689,8 +690,9 @@
 	if (!md->map)
 		return;
 
+	dm_sysfs_rename_table(dm_table_get_kobj(md->map), ".table");
 	dm_table_event_callback(md->map, NULL, NULL);
-	dm_table_put(md->map);
+	dm_table_del(md->map);
 	md->map = NULL;
 	set_capacity(md->disk, 0);
 }
@@ -702,11 +704,18 @@
 		      struct mapped_device **result)
 {
 	struct mapped_device *md;
+	int err;
 
 	md = alloc_dev(minor, persistent);
 	if (!md)
 		return -ENXIO;
 
+	err = dm_register_md(&md->disk->kobj, &md->kobj);
+	if (err) {
+		dm_free(md);
+		return err;
+	}
+
 	*result = md;
 	return 0;
 }
@@ -723,17 +732,20 @@
 
 void dm_get(struct mapped_device *md)
 {
-	atomic_inc(&md->holders);
+	kobject_get(&md->kobj);
 }
 
 void dm_put(struct mapped_device *md)
 {
-	if (atomic_dec_and_test(&md->holders)) {
-		if (!test_bit(DMF_SUSPENDED, &md->flags) && md->map)
-			dm_table_suspend_targets(md->map);
-		__unbind(md);
-		free_dev(md);
-	}
+	kobject_put(&md->kobj);
+}
+
+void dm_del(struct mapped_device *md)
+{
+	if (!test_bit(DMF_SUSPENDED, &md->flags) && md->map)
+		dm_table_suspend_targets(md->map);
+	__unbind(md);
+	dm_unregister_md(&md->kobj);
 }
 
 /*
@@ -909,6 +921,16 @@
 	return t;
 }
 
+struct mapped_device *dm_kobj_to_md(struct kobject *kobj)
+{
+	return container_of(kobj, struct mapped_device, kobj);
+}
+
+struct kobject *dm_md_get_kobj(struct mapped_device *md)
+{
+	return &md->kobj;
+}
+
 int dm_suspended(struct mapped_device *md)
 {
 	return test_bit(DMF_SUSPENDED, &md->flags);
diff -Naur linux-2.6.0-test9/drivers/md/dm.h linux-2.6.0-test9-dm/drivers/md/dm.h
--- linux-2.6.0-test9/drivers/md/dm.h	2003-10-25 11:43:34.000000000 -0700
+++ linux-2.6.0-test9-dm/drivers/md/dm.h	2003-11-09 15:07:54.000000000 -0800
@@ -48,17 +48,33 @@
 struct mapped_device;
 
 /*-----------------------------------------------------------------
+ * Functions for registering a mapped_device,
+ * table and target.
+ *---------------------------------------------------------------*/
+int dm_register_md(struct kobject *parent_kobj, struct kobject *kobj);
+void dm_unregister_md(struct kobject *kobj);
+int dm_register_table(struct kobject *parent_kobj, struct kobject *kobj);
+void dm_unregister_table(struct kobject *kobj);
+void dm_sysfs_rename_table(struct kobject *kobj, const char *name);
+int dm_register_target(struct kobject *parent_kobj,
+		       struct kobject *kobj, int i);
+void dm_unregister_target(struct kobject *kobj);
+
+/*-----------------------------------------------------------------
  * Functions for manipulating a struct mapped_device.
  * Drop the reference with dm_put when you finish with the object.
  *---------------------------------------------------------------*/
 int dm_create(struct mapped_device **md);
 int dm_create_with_minor(unsigned int minor, struct mapped_device **md);
+void dm_free(struct mapped_device *md);
+struct mapped_device *dm_kobj_to_md(struct kobject *kobj);
 
 /*
  * Reference counting for md.
  */
 void dm_get(struct mapped_device *md);
 void dm_put(struct mapped_device *md);
+void dm_del(struct mapped_device *md);
 
 /*
  * A device can still be used while suspended, but I/O is deferred.
@@ -90,15 +106,20 @@
  */
 struct gendisk *dm_disk(struct mapped_device *md);
 int dm_suspended(struct mapped_device *md);
+struct kobject *dm_md_get_kobj(struct mapped_device *md);
+struct mapped_device *dm_kobj_to_md(struct kobject *kobj);
 
 /*-----------------------------------------------------------------
  * Functions for manipulating a table.  Tables are also reference
  * counted.
  *---------------------------------------------------------------*/
-int dm_table_create(struct dm_table **result, int mode);
+int dm_table_create(struct mapped_device *md, struct dm_table **result,
+		    int mode);
 
 void dm_table_get(struct dm_table *t);
 void dm_table_put(struct dm_table *t);
+void dm_table_del(struct dm_table *t);
+void dm_table_free(struct dm_table *t);
 
 int dm_table_add_target(struct dm_table *t, const char *type,
 			sector_t start,	sector_t len, char *params);
@@ -115,6 +136,8 @@
 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);
+struct kobject *dm_table_get_kobj(struct dm_table *t);
+struct dm_table *dm_kobj_to_table(struct kobject *kobj);
 
 /*-----------------------------------------------------------------
  * A registry of target types.
diff -Naur linux-2.6.0-test9/drivers/md/dm-ioctl-v1.c linux-2.6.0-test9-dm/drivers/md/dm-ioctl-v1.c
--- linux-2.6.0-test9/drivers/md/dm-ioctl-v1.c	2003-10-25 11:44:52.000000000 -0700
+++ linux-2.6.0-test9-dm/drivers/md/dm-ioctl-v1.c	2003-11-09 15:30:59.000000000 -0800
@@ -236,7 +236,7 @@
 	list_del(&hc->uuid_list);
 	list_del(&hc->name_list);
 	unregister_with_devfs(hc);
-	dm_put(hc->md);
+	dm_del(hc->md);
 	free_cell(hc);
 }
 
@@ -572,7 +572,7 @@
 
 	r = populate_table(t, param);
 	if (r) {
-		dm_table_put(t);
+		dm_table_del(t);
 		return r;
 	}
 
@@ -582,7 +582,7 @@
 		r = dm_create(&md);
 
 	if (r) {
-		dm_table_put(t);
+		dm_table_del(t);
 		return r;
 	}
 
@@ -590,16 +590,16 @@
 	r = dm_suspend(md);
 	if (r) {
 		DMWARN("suspend failed");
-		dm_table_put(t);
-		dm_put(md);
+		dm_table_del(t);
+		dm_del(md);
 		return r;
 	}
 	/* swap in the table */
 	r = dm_swap_table(md, t);
 	if (r) {
 		DMWARN("table swap failed");
-		dm_table_put(t);
-		dm_put(md);
+		dm_table_del(t);
+		dm_del(md);
 		return r;
 	}
 
@@ -607,8 +607,8 @@
 	r = dm_resume(md);
 	if (r) {
 		DMWARN("resume failed");
-		dm_table_put(t);
-		dm_put(md);
+		dm_table_del(t);
+		dm_del(md);
 		return r;
 	}
 
@@ -900,20 +900,20 @@
 
 	r = populate_table(t, param);
 	if (r) {
-		dm_table_put(t);
+		dm_table_del(t);
 		return r;
 	}
 
 	md = find_device(param);
 	if (!md) {
-		dm_table_put(t);
+		dm_table_del(t);
 		return -ENXIO;
 	}
 
 	r = dm_swap_table(md, t);
 	if (r) {
 		dm_put(md);
-		dm_table_put(t);
+		dm_table_del(t);
 		return r;
 	}
 	dm_table_put(t);	/* md will have taken its own reference */
diff -Naur linux-2.6.0-test9/drivers/md/dm-ioctl-v4.c linux-2.6.0-test9-dm/drivers/md/dm-ioctl-v4.c
--- linux-2.6.0-test9/drivers/md/dm-ioctl-v4.c	2003-10-25 11:42:47.000000000 -0700
+++ linux-2.6.0-test9-dm/drivers/md/dm-ioctl-v4.c	2003-11-08 14:24:37.000000000 -0800
@@ -238,9 +238,9 @@
 	list_del(&hc->uuid_list);
 	list_del(&hc->name_list);
 	unregister_with_devfs(hc);
-	dm_put(hc->md);
+	dm_del(hc->md);
 	if (hc->new_map)
-		dm_table_put(hc->new_map);
+		dm_table_del(hc->new_map);
 	free_cell(hc);
 }
 
@@ -490,7 +490,7 @@
 
 	r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
 	if (r) {
-		dm_put(md);
+		dm_del(md);
 		return r;
 	}
 
@@ -646,8 +646,8 @@
 
 		r = dm_swap_table(md, new_map);
 		if (r) {
-			dm_put(md);
-			dm_table_put(new_map);
+			dm_del(md);
+			dm_table_del(new_map);
 			return r;
 		}
 
@@ -872,30 +872,32 @@
 	struct hash_cell *hc;
 	struct dm_table *t;
 
-	r = dm_table_create(&t, get_mode(param));
-	if (r)
-		return r;
-
-	r = populate_table(t, param, param_size);
-	if (r) {
-		dm_table_put(t);
-		return r;
-	}
-
 	down_write(&_hash_lock);
 	hc = __find_device_hash_cell(param);
 	if (!hc) {
 		DMWARN("device doesn't appear to be in the dev hash table.");
-		up_write(&_hash_lock);
-		return -ENXIO;
+		r = -ENXIO;
+		goto hash_unlock;
+	}
+
+	r = dm_table_create(hc->md, &t, get_mode(param));
+	if (r)
+		goto hash_unlock;
+
+	r = populate_table(t, param, param_size);
+	if (r) {
+		dm_table_del(t);
+		goto hash_unlock;
 	}
 
 	if (hc->new_map)
-		dm_table_put(hc->new_map);
+		dm_table_del(hc->new_map);
 	hc->new_map = t;
 	param->flags |= DM_INACTIVE_PRESENT_FLAG;
 
 	r = __dev_status(hc->md, param);
+
+ hash_unlock:
 	up_write(&_hash_lock);
 	return r;
 }
@@ -915,7 +917,7 @@
 	}
 
 	if (hc->new_map) {
-		dm_table_put(hc->new_map);
+		dm_table_del(hc->new_map);
 		hc->new_map = NULL;
 	}
 
diff -Naur linux-2.6.0-test9/drivers/md/dm-kobj.c linux-2.6.0-test9-dm/drivers/md/dm-kobj.c
--- linux-2.6.0-test9/drivers/md/dm-kobj.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.0-test9-dm/drivers/md/dm-kobj.c	2003-11-10 17:43:20.000000000 -0800
@@ -0,0 +1,334 @@
+/*
+ * dm-kobj.c - driver model and 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>
+
+
+static inline struct dm_attribute *to_dm_attr(struct attribute *attr)
+{
+	return container_of((attr), struct dm_attribute, attr);
+}
+
+static ssize_t dm_attr_show(struct kobject *kobj, struct attribute *attr,
+			    char *buf)
+{
+	struct dm_attribute *dm_attr = to_dm_attr(attr);
+
+	if (!dm_attr->show)
+		return 0;
+
+	return dm_attr->show(kobj, buf);
+}
+
+static ssize_t dm_attr_store(struct kobject *kobj, struct attribute *attr,
+			     const char *page, size_t length)
+{
+	struct dm_attribute *dm_attr = to_dm_attr(attr);
+
+	if (!dm_attr->store)
+		return -EINVAL;
+
+	return dm_attr->store(kobj, page, length);
+}
+
+static struct sysfs_ops dm_sysfs_ops = {
+	.show	= dm_attr_show,
+	.store	= dm_attr_store,
+};
+
+/*********************************************************
+ *
+ * device mapper dm_dev sysfs functions
+ *
+ *********************************************************/
+
+static void device_kobj_release(struct kobject *kobj)
+{
+	kobject_put(kobj->parent);
+}
+
+static struct kobj_type device_ktype = {
+	.release	= device_kobj_release,
+	.sysfs_ops	= &dm_sysfs_ops,
+};
+
+int dm_register_dev(struct kobject *parent, struct kobject *kobj,
+		    struct attribute_group *attrs, struct dm_dev *dev)
+{
+	int err = 0;
+	struct gendisk *disk;
+
+	if (!kobj || !parent || !dev)
+		return -EINVAL;
+
+	disk = dev->bdev->bd_disk;
+	kobj->parent = kobject_get(parent);
+	snprintf(kobj->name, KOBJ_NAME_LEN, "%s",
+		 disk->disk_name);
+	kobj->ktype = &device_ktype;
+
+	err = kobject_register(kobj);
+	if (err)
+		goto put_parent;
+
+	if (attrs) {
+		err = sysfs_create_group(kobj, attrs);
+		if (err)
+			goto unreg;
+	}
+
+	err = sysfs_create_link(kobj, &disk->kobj,
+				disk->disk_name);
+	if (err)
+		goto rm_group;
+
+	return 0;
+
+
+ rm_group:
+	if (attrs)
+		sysfs_remove_group(kobj, attrs);
+ unreg:
+	kobject_unregister(kobj);
+ put_parent:
+	kobj->parent = NULL;
+	kobject_put(parent);
+
+	return err;
+}
+
+void dm_unregister_dev(struct kobject *kobj, struct dm_dev *dev)
+{
+	struct gendisk *disk;
+
+	if (kobj && dev) {
+		disk = dev->bdev->bd_disk;
+		sysfs_remove_link(kobj, disk->disk_name);
+		kobject_unregister(kobj);
+	}
+}
+
+/*********************************************************
+ *
+ * device mapper dm_target sysfs functions
+ *
+ *********************************************************/
+
+struct dm_target *dm_kobj_to_target(struct kobject *kobj)
+{
+	return container_of(kobj, struct dm_target, kobj);
+}
+
+static ssize_t target_show_begin(struct kobject *kobj, char *buf)
+{
+	struct dm_target *tgt = dm_kobj_to_target(kobj);
+	return snprintf(buf, 20, ""SECTOR_FORMAT"\n", tgt->begin);
+}
+
+static ssize_t target_show_len(struct kobject *kobj, char *buf)
+{
+	struct dm_target *tgt = dm_kobj_to_target(kobj);
+	return snprintf(buf, 20, ""SECTOR_FORMAT"\n", tgt->len);
+}
+
+static ssize_t target_show_type(struct kobject *kobj, char *buf)
+{
+	struct dm_target *tgt = dm_kobj_to_target(kobj);
+	return snprintf(buf, 32, "%s\n", tgt->type->name);
+}
+
+static DM_ATTR(start_sector, S_IRUGO, target_show_begin, NULL);
+static DM_ATTR(num_sectors, S_IRUGO, target_show_len, NULL);
+static DM_ATTR(type, S_IRUGO, target_show_type, NULL);
+
+static struct attribute *default_target_attrs[] = {
+	&dm_attr_type.attr,
+	&dm_attr_num_sectors.attr,
+	&dm_attr_start_sector.attr,
+	NULL
+};
+
+int dm_sysfs_create_group(struct kobject *kobj,
+			  struct attribute_group *attr_group)
+{
+	return sysfs_create_group(kobj, attr_group);
+}
+
+static void target_kobj_release(struct kobject *kobj)
+{
+	kobject_put(kobj->parent);
+}
+
+static struct kobj_type target_ktype = {
+	.release	= target_kobj_release,
+	.sysfs_ops	= &dm_sysfs_ops,
+	.default_attrs	= default_target_attrs,
+};
+
+int dm_register_target(struct kobject *parent, struct kobject *kobj, int i)
+{
+	int err;
+
+	if (!kobj || !parent)
+		return -EINVAL;
+
+	kobj->parent = kobject_get(parent);
+	snprintf(kobj->name, KOBJ_NAME_LEN, "%s%d", "target", i);
+	kobj->ktype = &target_ktype;
+
+	err = kobject_register(kobj);
+	if (err)
+		kobject_put(parent);
+
+	return err;
+}
+
+void dm_unregister_target(struct kobject *kobj)
+{
+	if (kobj) kobject_unregister(kobj);
+}
+
+/*********************************************************
+ *
+ * device mapper dm_table sysfs functions
+ *
+ *********************************************************/
+
+static void table_kobj_release(struct kobject *kobj)
+{
+	struct kobject *parent = kobj->parent;
+
+	dm_table_free(dm_kobj_to_table(kobj));
+	kobject_put(parent);
+}
+
+static struct kobj_type table_ktype = {
+	.release	= table_kobj_release,
+};
+
+void dm_sysfs_rename_table(struct kobject *kobj, const char *name)
+{
+	sysfs_rename_dir(kobj, name);
+}
+
+int dm_register_table(struct kobject *parent, struct kobject *kobj)
+{
+	int err = 0;
+
+	if (!kobj || !parent)
+		return -EINVAL;
+
+	snprintf(kobj->name, KOBJ_NAME_LEN, "%s%p", ".table",
+		 dm_kobj_to_table(kobj));
+	kobj->ktype = &table_ktype;
+	kobj->parent = kobject_get(parent);
+
+	err =  kobject_register(kobj);
+	if (err) {
+		kobject_put(parent);
+		return err;
+	}
+
+	return err;
+}
+
+void dm_unregister_table(struct kobject *kobj)
+{	
+	if (kobj) kobject_unregister(kobj);
+}
+
+/*********************************************************
+ *
+ * device mapper mapped_device sysfs functions
+ *
+ *********************************************************/
+
+static ssize_t md_show_event(struct kobject *kobj, char *buf)
+{
+	struct mapped_device *md = dm_kobj_to_md(kobj);
+	return snprintf(buf, 20, "%u\n", dm_get_event_nr(md));
+}
+
+static ssize_t md_show_flags(struct kobject *kobj, char *buf)
+{
+	unsigned int flags = 0;
+	struct gendisk *disk;
+	struct dm_table *tbl;
+	struct mapped_device *md = dm_kobj_to_md(kobj);
+
+	if (dm_suspended(md))
+		flags |= DM_SUSPEND_FLAG;
+
+	disk = dm_disk(md);
+	if (disk->policy)
+		flags |= DM_READONLY_FLAG;
+
+	tbl = dm_get_table(md);
+	if (tbl) {
+		flags |= DM_ACTIVE_PRESENT_FLAG;
+		dm_table_put(tbl);
+	}
+
+	return snprintf(buf, 20, "0x%x\n", flags);
+}
+
+static DM_ATTR(event_nr, S_IRUGO, md_show_event, NULL);
+static DM_ATTR(flags, S_IRUGO, md_show_flags, NULL);
+
+static struct attribute *md_attrs[] = {
+	&dm_attr_event_nr.attr,
+	&dm_attr_flags.attr,
+	NULL
+};
+
+static void md_kobj_release(struct kobject *kobj)
+{
+	struct mapped_device *md;
+	struct gendisk *disk;
+
+	md = dm_kobj_to_md(kobj);
+	disk = dm_disk(md);
+	dm_free(md);
+	kobject_put(&disk->kobj);
+}
+
+struct kobj_type md_ktype = {
+	.release	= md_kobj_release,
+	.sysfs_ops	= &dm_sysfs_ops,
+	.default_attrs	= md_attrs,
+};
+
+int dm_register_md(struct kobject *parent, struct kobject *kobj)
+{
+	int err = 0;
+
+	if (!kobj || !parent)
+		return -EINVAL;
+
+	kobj->parent = kobject_get(parent);
+
+	snprintf(kobj->name, KOBJ_NAME_LEN, "%s", "mapped_device");
+	kobj->ktype = &md_ktype;
+
+	err = kobject_register(kobj);
+	if (err)
+		kobject_put(parent);
+
+	return err;
+}
+
+void dm_unregister_md(struct kobject *kobj)
+{
+	if (kobj) kobject_unregister(kobj);
+}
+
+EXPORT_SYMBOL(dm_register_dev);
+EXPORT_SYMBOL(dm_unregister_dev);
+EXPORT_SYMBOL(dm_kobj_to_target);
+EXPORT_SYMBOL(dm_sysfs_create_group);
diff -Naur linux-2.6.0-test9/drivers/md/dm-linear.c linux-2.6.0-test9-dm/drivers/md/dm-linear.c
--- linux-2.6.0-test9/drivers/md/dm-linear.c	2003-10-25 11:43:49.000000000 -0700
+++ linux-2.6.0-test9-dm/drivers/md/dm-linear.c	2003-11-08 15:44:33.000000000 -0800
@@ -18,6 +18,29 @@
 struct linear_c {
 	struct dm_dev *dev;
 	sector_t start;
+	struct kobject kobj;
+};
+
+static inline struct linear_c *to_linear(struct kobject *kobj)
+{
+	return container_of(kobj, struct linear_c, kobj);
+}
+
+static ssize_t show_start(struct kobject *kobj, char *buf)
+{
+	struct linear_c *lc = to_linear(kobj);
+	return snprintf(buf, 32, ""SECTOR_FORMAT"\n", lc->start);
+}
+
+static DM_ATTR(start, S_IRUGO, show_start, NULL);
+
+static struct attribute *linear_attrs[] = {
+	&dm_attr_start.attr,
+	NULL
+};
+
+static struct attribute_group linear_attr_group = {
+	.attrs = linear_attrs,
 };
 
 /*
@@ -37,6 +60,7 @@
 		ti->error = "dm-linear: Cannot allocate linear context";
 		return -ENOMEM;
 	}
+	memset(lc, 0, sizeof(struct linear_c));
 
 	if (sscanf(argv[1], SECTOR_FORMAT, &lc->start) != 1) {
 		ti->error = "dm-linear: Invalid device sector";
@@ -49,6 +73,12 @@
 		goto bad;
 	}
 
+	if (dm_register_dev(&ti->kobj, &lc->kobj,
+			    &linear_attr_group, lc->dev)) {
+		dm_put_device(lc->dev);
+		goto bad;
+	}
+
 	ti->private = lc;
 	return 0;
 
@@ -60,8 +90,13 @@
 static void linear_dtr(struct dm_target *ti)
 {
 	struct linear_c *lc = (struct linear_c *) ti->private;
+	dm_unregister_dev(&lc->kobj, lc->dev);
+}
 
-	dm_put_device(ti, lc->dev);
+static void linear_free(struct dm_target *ti)
+{
+	struct linear_c *lc = (struct linear_c *) ti->private;
+	dm_put_device(lc->dev);
 	kfree(lc);
 }
 
@@ -99,13 +134,14 @@
 	.module = THIS_MODULE,
 	.ctr    = linear_ctr,
 	.dtr    = linear_dtr,
+	.free   = linear_free,
 	.map    = linear_map,
 	.status = linear_status,
 };
 
 int __init dm_linear_init(void)
 {
-	int r = dm_register_target(&linear_target);
+	int r = dm_register_target_type(&linear_target);
 
 	if (r < 0)
 		DMERR("linear: register failed %d", r);
@@ -115,7 +151,7 @@
 
 void dm_linear_exit(void)
 {
-	int r = dm_unregister_target(&linear_target);
+	int r = dm_unregister_target_type(&linear_target);
 
 	if (r < 0)
 		DMERR("linear: unregister failed %d", r);
diff -Naur linux-2.6.0-test9/drivers/md/dm-stripe.c linux-2.6.0-test9-dm/drivers/md/dm-stripe.c
--- linux-2.6.0-test9/drivers/md/dm-stripe.c	2003-10-25 11:43:35.000000000 -0700
+++ linux-2.6.0-test9-dm/drivers/md/dm-stripe.c	2003-11-08 16:17:33.000000000 -0800
@@ -15,6 +15,29 @@
 struct stripe {
 	struct dm_dev *dev;
 	sector_t physical_start;
+	struct kobject kobj;
+};
+
+static inline struct stripe *to_stripe(struct kobject *kobj)
+{
+	return container_of(kobj, struct stripe, kobj);
+}
+
+static ssize_t show_start(struct kobject *kobj, char *buf)
+{
+	struct stripe *s = to_stripe(kobj);
+	return snprintf(buf, 32, ""SECTOR_FORMAT"\n", s->physical_start);
+}
+
+static DM_ATTR(start, S_IRUGO, show_start, NULL);
+
+static struct attribute *stripe_attrs[] = {
+	&dm_attr_start.attr,
+	NULL
+};
+
+static struct attribute_group stripe_attr_group = {
+	.attrs = stripe_attrs,
 };
 
 struct stripe_c {
@@ -30,6 +53,34 @@
 	struct stripe stripe[0];
 };
 
+
+static ssize_t show_num_stripes(struct kobject *kobj, char *buf)
+{
+	struct dm_target *tgt = dm_kobj_to_target(kobj);
+	struct stripe_c *sc = (struct stripe_c *) tgt->private;
+	return snprintf(buf, 32, "%u\n", sc->stripes);
+}
+
+static ssize_t show_chunk_size(struct kobject *kobj, char *buf)
+{
+	struct dm_target *tgt = dm_kobj_to_target(kobj);
+	struct stripe_c *sc = (struct stripe_c *) tgt->private;
+	return snprintf(buf, 32, "%u\n", sc->stripe_width);
+}
+
+static DM_ATTR(num_stripes, S_IRUGO, show_num_stripes, NULL);
+static DM_ATTR(chunk_size, S_IRUGO, show_chunk_size, NULL);
+
+static struct attribute *stripe_c_attrs[] = {
+	&dm_attr_num_stripes.attr,
+	&dm_attr_chunk_size.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;
@@ -50,6 +101,8 @@
 		      unsigned int stripe, char **argv)
 {
 	sector_t start;
+	
+	memset(&sc->stripe[stripe], 0, sizeof(struct stripe));
 
 	if (sscanf(argv[1], SECTOR_FORMAT, &start) != 1)
 		return -EINVAL;
@@ -144,13 +197,22 @@
 		if (r < 0) {
 			ti->error = "dm-stripe: Couldn't parse stripe "
 				"destination";
-			while (i--)
-				dm_put_device(ti, sc->stripe[i].dev);
+			while (i--) {
+				dm_unregister_dev(&sc->stripe[i].kobj,
+						  sc->stripe[i].dev);
+				dm_put_device(sc->stripe[i].dev);
+			}
 			kfree(sc);
 			return r;
 		}
+
+		dm_register_dev(&ti->kobj,
+				&sc->stripe[i].kobj,
+				&stripe_attr_group,
+				sc->stripe[i].dev);
 	}
 
+	dm_sysfs_create_group(&ti->kobj, &stripe_c_attr_group);
 	ti->private = sc;
 	return 0;
 }
@@ -161,7 +223,16 @@
 	struct stripe_c *sc = (struct stripe_c *) ti->private;
 
 	for (i = 0; i < sc->stripes; i++)
-		dm_put_device(ti, sc->stripe[i].dev);
+		dm_unregister_dev(&sc->stripe[i].kobj, sc->stripe[i].dev);
+}
+
+static void stripe_free(struct dm_target *ti)
+{
+	unsigned int i;
+	struct stripe_c *sc = (struct stripe_c *) ti->private;
+
+	for (i = 0; i < sc->stripes; i++)
+		dm_put_device(sc->stripe[i].dev);
 
 	kfree(sc);
 }
@@ -214,6 +285,7 @@
 	.module = THIS_MODULE,
 	.ctr    = stripe_ctr,
 	.dtr    = stripe_dtr,
+	.free   = stripe_free,
 	.map    = stripe_map,
 	.status = stripe_status,
 };
@@ -222,7 +294,7 @@
 {
 	int r;
 
-	r = dm_register_target(&stripe_target);
+	r = dm_register_target_type(&stripe_target);
 	if (r < 0)
 		DMWARN("striped target registration failed");
 
@@ -231,7 +303,7 @@
 
 void dm_stripe_exit(void)
 {
-	if (dm_unregister_target(&stripe_target))
+	if (dm_unregister_target_type(&stripe_target))
 		DMWARN("striped target unregistration failed");
 
 	return;
diff -Naur linux-2.6.0-test9/drivers/md/dm-table.c linux-2.6.0-test9-dm/drivers/md/dm-table.c
--- linux-2.6.0-test9/drivers/md/dm-table.c	2003-10-25 11:44:52.000000000 -0700
+++ linux-2.6.0-test9-dm/drivers/md/dm-table.c	2003-11-09 20:02:50.000000000 -0800
@@ -20,8 +20,6 @@
 #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 */
@@ -51,6 +49,8 @@
 	/* events get handed up using this callback */
 	void (*event_fn)(void *);
 	void *event_context;
+
+	struct kobject kobj;
 };
 
 /*
@@ -202,8 +202,10 @@
 	return 0;
 }
 
-int dm_table_create(struct dm_table **result, int mode)
+int dm_table_create(struct mapped_device *md,
+		    struct dm_table **result, int mode)
 {
+	int err = 0;
 	struct dm_table *t = kmalloc(sizeof(*t), GFP_NOIO);
 
 	if (!t)
@@ -211,18 +213,29 @@
 
 	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 */
 	if (alloc_targets(t, KEYS_PER_NODE)) {
-		kfree(t);
-		t = NULL;
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto free_tbl;
 	}
 
+	err = dm_register_table(dm_md_get_kobj(md), &t->kobj);
+	if (err)
+		goto free_tgts;
+
 	t->mode = mode;
 	*result = t;
 	return 0;
+
+
+ free_tgts:
+	vfree(t->highs);
+ free_tbl:
+	kfree(t);
+	t = NULL;
+
+	return err;
 }
 
 static void free_devices(struct list_head *devices)
@@ -236,7 +249,7 @@
 	}
 }
 
-void table_destroy(struct dm_table *t)
+void dm_table_free(struct dm_table *t)
 {
 	unsigned int i;
 
@@ -248,9 +261,8 @@
 	for (i = 0; i < t->num_targets; i++) {
 		struct dm_target *tgt = t->targets + i;
 
-		if (tgt->type->dtr)
-			tgt->type->dtr(tgt);
-
+		if (tgt->type->free)
+			tgt->type->free(tgt);
 		dm_put_target_type(tgt->type);
 	}
 
@@ -269,13 +281,28 @@
 
 void dm_table_get(struct dm_table *t)
 {
-	atomic_inc(&t->holders);
+	kobject_get(&t->kobj);
 }
 
 void dm_table_put(struct dm_table *t)
 {
-	if (atomic_dec_and_test(&t->holders))
-		table_destroy(t);
+	kobject_put(&t->kobj);
+}
+
+void dm_table_del(struct dm_table *t)
+{
+	int i;
+
+	for (i = 0; i < t->num_targets; i++) {
+		struct dm_target *tgt = t->targets + i;
+		
+		if (tgt->type->dtr)
+			tgt->type->dtr(tgt);
+		
+		dm_unregister_target(&tgt->kobj);
+	}
+
+	dm_unregister_table(&t->kobj);
 }
 
 /*
@@ -460,7 +487,7 @@
 
 	if (!check_device_area(dd, start, len)) {
 		DMWARN("device %s too small for target", path);
-		dm_put_device(ti, dd);
+		dm_put_device(dd);
 		return -EINVAL;
 	}
 
@@ -512,7 +539,7 @@
 /*
  * Decrement a devices use count and remove it if necessary.
  */
-void dm_put_device(struct dm_target *ti, struct dm_dev *dd)
+void dm_put_device(struct dm_dev *dd)
 {
 	if (atomic_dec_and_test(&dd->count)) {
 		close_dev(dd);
@@ -637,6 +664,11 @@
 	tgt->begin = start;
 	tgt->len = len;
 	tgt->error = "Unknown error";
+	r = dm_register_target(&t->kobj, &tgt->kobj, t->num_targets);
+	if (r) {
+		tgt->error = "couldn't register target in sysfs";
+		goto put;
+	}
 
 	/*
 	 * Does this target adjoin the previous one ?
@@ -644,19 +676,19 @@
 	if (!adjoin(t, tgt)) {
 		tgt->error = "Gap in table";
 		r = -EINVAL;
-		goto bad;
+		goto unreg;
 	}
 
 	r = split_args(&argc, &argv, params);
 	if (r) {
 		tgt->error = "couldn't split parameters (insufficient memory)";
-		goto bad;
+		goto unreg;
 	}
 
 	r = tgt->type->ctr(tgt, argc, argv);
 	kfree(argv);
 	if (r)
-		goto bad;
+		goto unreg;
 
 	t->highs[t->num_targets++] = tgt->begin + tgt->len - 1;
 
@@ -665,9 +697,11 @@
 	combine_restrictions_low(&t->limits, &tgt->limits);
 	return 0;
 
- bad:
-	printk(KERN_ERR DM_NAME ": %s\n", tgt->error);
+ unreg:
+	dm_unregister_target(&tgt->kobj);
+ put:
 	dm_put_target_type(tgt->type);
+	printk(KERN_ERR DM_NAME ": %s\n", tgt->error);
 	return r;
 }
 
@@ -799,6 +833,16 @@
 	return t->mode;
 }
 
+struct dm_table *dm_kobj_to_table(struct kobject *kobj)
+{
+	return container_of(kobj, struct dm_table, kobj);
+}
+
+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-test9/drivers/md/dm-target.c linux-2.6.0-test9-dm/drivers/md/dm-target.c
--- linux-2.6.0-test9/drivers/md/dm-target.c	2003-10-25 11:44:53.000000000 -0700
+++ linux-2.6.0-test9-dm/drivers/md/dm-target.c	2003-11-08 16:16:35.000000000 -0800
@@ -100,7 +100,7 @@
 	return ti;
 }
 
-int dm_register_target(struct target_type *t)
+int dm_register_target_type(struct target_type *t)
 {
 	int rv = 0;
 	struct tt_internal *ti = alloc_target(t);
@@ -121,7 +121,7 @@
 	return rv;
 }
 
-int dm_unregister_target(struct target_type *t)
+int dm_unregister_target_type(struct target_type *t)
 {
 	struct tt_internal *ti;
 
@@ -171,12 +171,12 @@
 
 int dm_target_init(void)
 {
-	return dm_register_target(&error_target);
+	return dm_register_target_type(&error_target);
 }
 
 void dm_target_exit(void)
 {
-	if (dm_unregister_target(&error_target))
+	if (dm_unregister_target_type(&error_target))
 		DMWARN("error target unregistration failed");
 }
 
diff -Naur linux-2.6.0-test9/drivers/md/Makefile linux-2.6.0-test9-dm/drivers/md/Makefile
--- linux-2.6.0-test9/drivers/md/Makefile	2003-10-25 11:43:49.000000000 -0700
+++ linux-2.6.0-test9-dm/drivers/md/Makefile	2003-11-09 20:30:42.000000000 -0800
@@ -3,7 +3,7 @@
 #
 
 dm-mod-objs	:= dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
-		   dm-ioctl.o
+		   dm-kobj.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-test9/include/linux/device-mapper.h linux-2.6.0-test9-dm/include/linux/device-mapper.h
--- linux-2.6.0-test9/include/linux/device-mapper.h	2003-10-25 11:44:05.000000000 -0700
+++ linux-2.6.0-test9-dm/include/linux/device-mapper.h	2003-11-09 20:03:44.000000000 -0800
@@ -22,11 +22,17 @@
 
 /*
  * The destructor doesn't need to free the dm_target, just
- * anything hidden ti->private.
+ * break down any structures registered in the constructor.
  */
 typedef void (*dm_dtr_fn) (struct dm_target *ti);
 
 /*
+ * This is called when it is safe to deallocate the
+ * the target's private structures.
+ */
+typedef void (*dm_free_fn) (struct dm_target *ti);
+
+/*
  * The map function must return:
  * < 0: error
  * = 0: The target will handle the io by resubmitting it later
@@ -49,7 +55,7 @@
  */
 int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
 		  sector_t len, int mode, struct dm_dev **result);
-void dm_put_device(struct dm_target *ti, struct dm_dev *d);
+void dm_put_device(struct dm_dev *d);
 
 /*
  * Information about a target type
@@ -59,6 +65,7 @@
 	struct module *module;
 	dm_ctr_fn ctr;
 	dm_dtr_fn dtr;
+	dm_free_fn free;
 	dm_map_fn map;
 	dm_suspend_fn suspend;
 	dm_resume_fn resume;
@@ -96,9 +103,40 @@
 
 	/* Used to provide an error string from the ctr */
 	char *error;
+
+	struct kobject kobj;
+	struct attribute_group *attr_group;
+};
+
+int dm_register_target_type(struct target_type *t);
+int dm_unregister_target_type(struct target_type *t);
+
+/*
+ * Functions and structures for displaying target
+ * and device attributes in sysfs. Look at dm-stripe
+ * and dm-linear for examples.
+ */
+
+struct dm_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct kobject *, char *);
+	ssize_t (*store)(struct kobject *, const char *, size_t);
+};
+
+#define DM_ATTR(_name,_mode,_show,_store)	\
+struct dm_attribute dm_attr_##_name = { 	\
+	.attr = {.name = __stringify(_name),	\
+		 .mode = _mode,			\
+		 .owner = THIS_MODULE },	\
+	.show   = _show,			\
+	.store  = _store,			\
 };
 
-int dm_register_target(struct target_type *t);
-int dm_unregister_target(struct target_type *t);
+struct dm_target *dm_kobj_to_target(struct kobject *kobj);
+int dm_sysfs_create_group(struct kobject *kobj,
+			  struct attribute_group *attr_group);
+int dm_register_dev(struct kobject *parent, struct kobject *kobj,
+		    struct attribute_group *attrs, struct dm_dev *dev);
+void dm_unregister_dev(struct kobject *kobj, struct dm_dev *dev);
 
 #endif				/* _LINUX_DEVICE_MAPPER_H */

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