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 +#include + + +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 */