===================================================================
@@ -92,6 +92,17 @@ struct dm_snapshot {
struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE];
};
+struct dm_snapshare {
+ struct dm_snapshot *snap;
+
+ struct list_head shared_list;
+
+ atomic_t pending_exceptions_count;
+
+ /* The on disk metadata handler */
+ struct dm_exception_store *store;
+};
+
static struct workqueue_struct *ksnapd;
static void flush_queued_bios(struct work_struct *work);
@@ -530,6 +541,7 @@ static int snapshot_ctr(struct dm_target
{
sector_t hash_size, cow_dev_size, origin_dev_size, max_buckets;
struct dm_dev *origin;
+ struct dm_snapshare *ss;
struct dm_snapshot *s;
int i;
int r = -EINVAL;
@@ -546,11 +558,20 @@ static int snapshot_ctr(struct dm_target
argv++;
argc--;
+ ss = kzalloc(sizeof(*ss), GFP_KERNEL);
+ if (!ss) {
+ ti->error = "Failed to allocate snapshot memory";
+ return -ENOMEM;
+ }
+ INIT_LIST_HEAD(&ss->shared_list);
+ atomic_set(&ss->pending_exceptions_count, 0);
+
r = create_exception_store(ti, argc, argv, &args_used, &store);
if (r) {
ti->error = "Failed to create snapshot exception store";
- return r;
+ goto bad_exception_store;
}
+ ss->store = store;
argv += args_used;
argc -= args_used;
@@ -586,9 +607,9 @@ static int snapshot_ctr(struct dm_target
ti->error = "Failed to create snapshot structure";
goto bad_alloc_snapshot;
}
-
+ ss->snap = s;
s->origin = origin;
- s->store = store;
+ s->store = ss->store;
/* Add snapshot to the list of snapshots for this origin */
/* Exceptions aren't triggered till snapshot_resume() is called */
@@ -598,8 +619,8 @@ static int snapshot_ctr(struct dm_target
goto bad_load_and_register;
}
- ti->private = s;
- ti->split_io = s->store->chunk_size;
+ ti->private = ss;
+ ti->split_io = store->chunk_size;
return 0;
@@ -612,6 +633,9 @@ bad_alloc_snapshot:
bad_origin:
dm_exception_store_destroy(store);
+bad_exception_store:
+ kfree(ss);
+
return r;
}
@@ -620,7 +644,8 @@ static void snapshot_dtr(struct dm_targe
#ifdef CONFIG_DM_DEBUG
int i;
#endif
- struct dm_snapshot *s = ti->private;
+ struct dm_snapshare *ss = ti->private;
+ struct dm_snapshot *s = ss->snap;
flush_workqueue(ksnapd);
@@ -643,9 +668,11 @@ static void snapshot_dtr(struct dm_targe
dm_put_device(ti, s->origin);
- dm_exception_store_destroy(s->store);
-
dealloc_snapshot(s);
+
+ dm_exception_store_destroy(ss->store);
+
+ kfree(ss);
}
/*
@@ -843,7 +870,8 @@ static void start_copy(struct dm_snap_pe
* this.
*/
static struct dm_snap_pending_exception *
-__find_pending_exception(struct dm_snapshot *s, struct bio *bio, int group)
+__find_pending_exception(struct dm_snapshot *s, struct bio *bio,
+ struct dm_snapshare *ss)
{
struct dm_exception *e, *tmp_e;
struct dm_snap_pending_exception *pe;
@@ -887,7 +915,7 @@ __find_pending_exception(struct dm_snaps
atomic_set(&pe->ref_count, 0);
pe->started = 0;
- if (s->store->type->prepare_exception(s->store, &pe->e, group)) {
+ if (s->store->type->prepare_exception(s->store, &pe->e, ss ? 0 : 1)) {
dm_free_exception(s->pending, &pe->e);
return NULL;
}
@@ -909,12 +937,13 @@ static void remap_exception(struct dm_sn
static int snapshot_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
{
- struct dm_snapshot *s = ti->private;
+ struct dm_snapshare *ss = ti->private;
+ struct dm_snapshot *s = ss->snap;
int rtn, r = DM_MAPIO_REMAPPED;
chunk_t chunk, new_chunk;
struct dm_snap_pending_exception *pe = NULL;
- chunk = sector_to_chunk(s->store, bio->bi_sector);
+ chunk = sector_to_chunk(ss->store, bio->bi_sector);
/* Full snapshots are not usable */
/* To get here the table must be live so s->active is always set. */
@@ -931,7 +960,7 @@ static int snapshot_map(struct dm_target
}
/* If the block is already remapped - use that, else remap it */
- rtn = s->store->type->lookup_exception(s->store, chunk, &new_chunk, 0);
+ rtn = ss->store->type->lookup_exception(ss->store, chunk, &new_chunk, 0);
if (!rtn) {
remap_exception(s, bio, new_chunk);
goto out_unlock;
@@ -950,7 +979,7 @@ static int snapshot_map(struct dm_target
* writeable.
*/
if (bio_rw(bio) == WRITE) {
- pe = __find_pending_exception(s, bio, 0);
+ pe = __find_pending_exception(s, bio, ss);
if (!pe) {
__invalidate_snapshot(s, -ENOMEM);
r = -EIO;
@@ -983,7 +1012,8 @@ out:
static int snapshot_end_io(struct dm_target *ti, struct bio *bio,
int error, union map_info *map_context)
{
- struct dm_snapshot *s = ti->private;
+ struct dm_snapshare *ss = ti->private;
+ struct dm_snapshot *s = ss->snap;
struct dm_snap_tracked_chunk *c = map_context->ptr;
if (c)
@@ -995,7 +1025,8 @@ static int snapshot_end_io(struct dm_tar
static void snapshot_resume(struct dm_target *ti)
{
int r;
- struct dm_snapshot *s = ti->private;
+ struct dm_snapshare *ss = ti->private;
+ struct dm_snapshot *s = ss->snap;
/*
* Target resumes cannot fail, which leaves us in a tight spot.
@@ -1004,47 +1035,48 @@ static void snapshot_resume(struct dm_ta
* If invalid, mark the snapshot as such. However, if other,
* what can we do? Mark 'not active'?
*/
- r = s->store->type->resume(s->store);
- if (r == -EINVAL)
- r = s->valid = 0;
-
+ r = ss->store->type->resume(ss->store);
down_write(&s->lock);
- s->active = (r) ? 0 : 1;
+ if (r == -EINVAL)
+ s->valid = 0;
+ else
+ s->active = (r) ? 0 : 1;
up_write(&s->lock);
}
static void snapshot_presuspend(struct dm_target *ti)
{
- struct dm_snapshot *s = ti->private;
+ struct dm_snapshare *ss = ti->private;
- if(s->store->type->presuspend)
- s->store->type->presuspend(s->store);
+ if(ss->store->type->presuspend)
+ ss->store->type->presuspend(ss->store);
}
static void snapshot_postsuspend(struct dm_target *ti)
{
- struct dm_snapshot *s = ti->private;
+ struct dm_snapshare *ss = ti->private;
- if (s->store->type->postsuspend)
- s->store->type->postsuspend(s->store);
+ if (ss->store->type->postsuspend)
+ ss->store->type->postsuspend(ss->store);
}
static int snapshot_status(struct dm_target *ti, status_type_t type,
char *result, unsigned int maxlen)
{
unsigned int sz = 0;
- struct dm_snapshot *snap = ti->private;
+ struct dm_snapshare *ss = ti->private;
+ struct dm_snapshot *s = ss->snap;
switch (type) {
case STATUSTYPE_INFO:
- if (!snap->valid)
+ if (!s->valid)
DMEMIT("Invalid");
else {
- if (snap->store->type->fraction_full) {
+ if (ss->store->type->fraction_full) {
sector_t numerator, denominator;
- snap->store->type->fraction_full(snap->store,
- &numerator,
- &denominator);
+ ss->store->type->fraction_full(ss->store,
+ &numerator,
+ &denominator);
DMEMIT("%llu/%llu",
(unsigned long long)numerator,
(unsigned long long)denominator);
@@ -1060,9 +1092,9 @@ static int snapshot_status(struct dm_tar
* to make private copies if the output is to
* make sense.
*/
- DMEMIT("%s ", snap->origin->name);
- snap->store->type->status(snap->store, type,
- result+sz, maxlen-sz);
+ DMEMIT("%s ", s->origin->name);
+ ss->store->type->status(ss->store, type,
+ result+sz, maxlen-sz);
break;
}
@@ -1072,10 +1104,10 @@ static int snapshot_status(struct dm_tar
static int snapshot_message(struct dm_target *ti, unsigned argc, char **argv)
{
int r = 0;
- struct dm_snapshot *s = ti->private;
+ struct dm_snapshare *ss = ti->private;
- if (s->store->type->message)
- r = s->store->type->message(s->store, argc, argv);
+ if (ss->store->type->message)
+ r = ss->store->type->message(ss->store, argc, argv);
return r;
}
@@ -1130,7 +1162,7 @@ static int __origin_write(struct list_he
*/
BUG_ON(rtn != -ENOENT);
- pe = __find_pending_exception(snap, bio, 1);
+ pe = __find_pending_exception(snap, bio, NULL);
if (!pe) {
__invalidate_snapshot(snap, -ENOMEM);
goto next_snapshot;