[dm-devel] [PATCH] dm-snapshot.c: Allocate an origin structure in origin_ctr()
Kevin Corry
kevcorry at us.ibm.com
Wed Jul 30 14:48:02 UTC 2003
On Tuesday 29 July 2003 15:22, Kevin Corry wrote:
> Joe,
>
> We talked on Saturday about adding code in the origin_ctr() path to
> allocate an origin structure if one was not already present. This would
> allow an origin device to be active without any active snapshots, and thus
> prevent hitting the BUG in do_origin. You said you had a patch that did
> this, but in case you've misplaced it, I put one together this afternoon.
> If you do have your patch available, could you please post it here, and I
> will test with your version instead of this one.
>
> Thanks!
Damn.
Well, I found a bug in the patch I sent in yesterday. :( If you create an origin
device, then create a snapshot device, then delete the snapshot device, the
struct origin gets deleted by the snapshot_dtr, which leads right back to the
BUG we're trying to avoid in do_origin().
This new version adds a referrence count to the struct origin and deallocates
it only when the count goes to zero.
(diff did something weird with this one, so the patch looks a bit strange in
places...but it still works.)
--
Kevin Corry
kevcorry at us.ibm.com
http://evms.sourceforge.net/
--- a/drivers/md/dm-snapshot.c 4 Jul 2003 19:38:50 -0000
+++ b/drivers/md/dm-snapshot.c 30 Jul 2003 19:29:25 -0000
@@ -92,6 +92,9 @@
/* List of snapshots for this origin */
struct list_head snapshots;
+
+ /* Count of snapshots and origins referrencing this structure. */
+ unsigned int count;
};
/*
@@ -155,6 +158,36 @@
}
/*
+ * Allocate and initialize an origin structure.
+ */
+static struct origin * __alloc_origin(kdev_t dev)
+{
+ struct origin *o = kmalloc(sizeof(*o), GFP_KERNEL);
+ if (o) {
+ o->dev = dev;
+ o->count = 0;
+ INIT_LIST_HEAD(&o->hash_list);
+ INIT_LIST_HEAD(&o->snapshots);
+ __insert_origin(o);
+ }
+ return o;
+}
+
+static void __get_origin(struct origin *o)
+{
+ o->count++;
+}
+
+static void __put_origin(struct origin *o)
+{
+ o->count--;
+ if (o->count == 0) {
+ list_del(&o->hash_list);
+ kfree(o);
+ }
+}
+
+/*
* Make a note of the snapshot and its origin so we can look it
* up when the origin has a write on it.
*/
@@ -168,20 +201,37 @@
if (!o) {
/* New origin */
- o = kmalloc(sizeof(*o), GFP_KERNEL);
+ o = __alloc_origin(dev);
if (!o) {
up_write(&_origins_lock);
return -ENOMEM;
}
+ }
- /* Initialise the struct */
- INIT_LIST_HEAD(&o->snapshots);
- o->dev = dev;
+ __get_origin(o);
+ list_add_tail(&snap->list, &o->snapshots);
- __insert_origin(o);
+ up_write(&_origins_lock);
+ return 0;
+}
+
+static int register_origin(kdev_t dev)
+{
+ struct origin *o;
+
+ down_write(&_origins_lock);
+ o = __lookup_origin(dev);
+
+ if (!o) {
+ /* New origin */
+ o = __alloc_origin(dev);
+ if (!o) {
+ up_write(&_origins_lock);
+ return -ENOMEM;
+ }
}
- list_add_tail(&snap->list, &o->snapshots);
+ __get_origin(o);
up_write(&_origins_lock);
return 0;
@@ -195,11 +245,18 @@
o = __lookup_origin(s->origin->dev);
list_del(&s->list);
- if (list_empty(&o->snapshots)) {
- list_del(&o->hash_list);
- kfree(o);
- }
+ __put_origin(o);
+
+ up_write(&_origins_lock);
+}
+
+static void unregister_origin(kdev_t dev)
+{
+ struct origin *o;
+ down_write(&_origins_lock);
+ o = __lookup_origin(dev);
+ __put_origin(o);
up_write(&_origins_lock);
}
@@ -1050,6 +1104,13 @@
return r;
}
+ r = register_origin(dev->dev);
+ if (r) {
+ ti->error = "Cannot register origin";
+ dm_put_device(ti, dev);
+ return r;
+ }
+
ti->private = dev;
return 0;
}
@@ -1057,6 +1118,7 @@
static void origin_dtr(struct dm_target *ti)
{
struct dm_dev *dev = (struct dm_dev *) ti->private;
+ unregister_origin(dev->dev);
dm_put_device(ti, dev);
}
More information about the dm-devel
mailing list