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! -- Kevin Corry kevcorry@xxxxxxxxxx http://evms.sourceforge.net/ Allocate an origin structure in the origin_ctr path. This prevents us from hitting the BUG in do_origin() if we have an active origin device with no active snapshot devices. This patch also creates some common routines to use in both the snapshot and origin constructors and destructors. --- a/drivers/md/dm-snapshot.c 4 Jul 2003 19:38:50 -0000 +++ b/drivers/md/dm-snapshot.c 29 Jul 2003 19:47:37 -0000 @@ -155,6 +155,29 @@ } /* + * Allocate an 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; + INIT_LIST_HEAD(&o->hash_list); + INIT_LIST_HEAD(&o->snapshots); + __insert_origin(o); + } + return o; +} + +static void __put_origin(struct origin *o) +{ + if (list_empty(&o->snapshots)) { + 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,17 +191,11 @@ 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; - - __insert_origin(o); } list_add_tail(&snap->list, &o->snapshots); @@ -187,6 +204,26 @@ 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; + } + } + + up_write(&_origins_lock); + return 0; +} + static void unregister_snapshot(struct dm_snapshot *s) { struct origin *o; @@ -195,14 +232,21 @@ 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); +} + /* * Implementation of the exception hash tables. */ @@ -1050,6 +1094,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 +1108,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); }