Skip to content

Commit

Permalink
dm snapshot: move cow ref from exception store to snap core
Browse files Browse the repository at this point in the history
Store the reference to the snapshot cow device in the core snapshot
code instead of each exception store.  It can be accessed through the
new function dm_snap_cow().  Exception stores should each now maintain a
reference to their parent snapshot struct.

This is cleaner and makes part of the forthcoming snapshot merge code simpler.

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Reviewed-by: Jonathan Brassow <jbrassow@redhat.com>
Cc: Mikulas Patocka <mpatocka@redhat.com>
  • Loading branch information
Mike Snitzer authored and Alasdair G Kergon committed Dec 10, 2009
1 parent 985903b commit fc56f6f
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 57 deletions.
30 changes: 11 additions & 19 deletions drivers/md/dm-exception-store.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
}

/* Validate the chunk size against the device block size */
if (chunk_size % (bdev_logical_block_size(store->cow->bdev) >> 9)) {
if (chunk_size %
(bdev_logical_block_size(dm_snap_cow(store->snap)->bdev) >> 9)) {
*error = "Chunk size is not a multiple of device blocksize";
return -EINVAL;
}
Expand All @@ -190,6 +191,7 @@ int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
}

int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
struct dm_snapshot *snap,
unsigned *args_used,
struct dm_exception_store **store)
{
Expand All @@ -198,7 +200,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
struct dm_exception_store *tmp_store;
char persistent;

if (argc < 3) {
if (argc < 2) {
ti->error = "Insufficient exception store arguments";
return -EINVAL;
}
Expand All @@ -209,7 +211,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
return -ENOMEM;
}

persistent = toupper(*argv[1]);
persistent = toupper(*argv[0]);
if (persistent == 'P')
type = get_type("P");
else if (persistent == 'N')
Expand All @@ -227,32 +229,23 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
}

tmp_store->type = type;
tmp_store->ti = ti;
tmp_store->snap = snap;

r = dm_get_device(ti, argv[0], 0, 0,
FMODE_READ | FMODE_WRITE, &tmp_store->cow);
if (r) {
ti->error = "Cannot get COW device";
goto bad_cow;
}

r = set_chunk_size(tmp_store, argv[2], &ti->error);
r = set_chunk_size(tmp_store, argv[1], &ti->error);
if (r)
goto bad_ctr;
goto bad;

r = type->ctr(tmp_store, 0, NULL);
if (r) {
ti->error = "Exception store type constructor failed";
goto bad_ctr;
goto bad;
}

*args_used = 3;
*args_used = 2;
*store = tmp_store;
return 0;

bad_ctr:
dm_put_device(ti, tmp_store->cow);
bad_cow:
bad:
put_type(type);
bad_type:
kfree(tmp_store);
Expand All @@ -263,7 +256,6 @@ EXPORT_SYMBOL(dm_exception_store_create);
void dm_exception_store_destroy(struct dm_exception_store *store)
{
store->type->dtr(store);
dm_put_device(store->ti, store->cow);
put_type(store->type);
kfree(store);
}
Expand Down
12 changes: 9 additions & 3 deletions drivers/md/dm-exception-store.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ struct dm_exception_store_type {
struct list_head list;
};

struct dm_snapshot;

struct dm_exception_store {
struct dm_exception_store_type *type;
struct dm_target *ti;

struct dm_dev *cow;
struct dm_snapshot *snap;

/* Size of data blocks saved - must be a power of 2 */
unsigned chunk_size;
Expand All @@ -108,6 +108,11 @@ struct dm_exception_store {
void *context;
};

/*
* Obtain the cow device used by a given snapshot.
*/
struct dm_dev *dm_snap_cow(struct dm_snapshot *snap);

/*
* Funtions to manipulate consecutive chunks
*/
Expand Down Expand Up @@ -173,6 +178,7 @@ int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
char **error);

int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
struct dm_snapshot *snap,
unsigned *args_used,
struct dm_exception_store **store);
void dm_exception_store_destroy(struct dm_exception_store *store);
Expand Down
12 changes: 6 additions & 6 deletions drivers/md/dm-snap-persistent.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw,
int metadata)
{
struct dm_io_region where = {
.bdev = ps->store->cow->bdev,
.bdev = dm_snap_cow(ps->store->snap)->bdev,
.sector = ps->store->chunk_size * chunk,
.count = ps->store->chunk_size,
};
Expand Down Expand Up @@ -294,7 +294,8 @@ static int read_header(struct pstore *ps, int *new_snapshot)
*/
if (!ps->store->chunk_size) {
ps->store->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS,
bdev_logical_block_size(ps->store->cow->bdev) >> 9);
bdev_logical_block_size(dm_snap_cow(ps->store->snap)->
bdev) >> 9);
ps->store->chunk_mask = ps->store->chunk_size - 1;
ps->store->chunk_shift = ffs(ps->store->chunk_size) - 1;
chunk_size_supplied = 0;
Expand Down Expand Up @@ -497,7 +498,7 @@ static void persistent_usage(struct dm_exception_store *store,
struct pstore *ps = get_info(store);

*sectors_allocated = ps->next_free * store->chunk_size;
*total_sectors = get_dev_size(store->cow->bdev);
*total_sectors = get_dev_size(dm_snap_cow(store->snap)->bdev);

/*
* First chunk is the fixed header.
Expand Down Expand Up @@ -596,7 +597,7 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
struct pstore *ps = get_info(store);
uint32_t stride;
chunk_t next_free;
sector_t size = get_dev_size(store->cow->bdev);
sector_t size = get_dev_size(dm_snap_cow(store->snap)->bdev);

/* Is there enough room ? */
if (size < ((ps->next_free + 1) * store->chunk_size))
Expand Down Expand Up @@ -733,8 +734,7 @@ static unsigned persistent_status(struct dm_exception_store *store,
case STATUSTYPE_INFO:
break;
case STATUSTYPE_TABLE:
DMEMIT(" %s P %llu", store->cow->name,
(unsigned long long)store->chunk_size);
DMEMIT(" P %llu", (unsigned long long)store->chunk_size);
}

return sz;
Expand Down
7 changes: 3 additions & 4 deletions drivers/md/dm-snap-transient.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ static int transient_prepare_exception(struct dm_exception_store *store,
struct dm_exception *e)
{
struct transient_c *tc = store->context;
sector_t size = get_dev_size(store->cow->bdev);
sector_t size = get_dev_size(dm_snap_cow(store->snap)->bdev);

if (size < (tc->next_free + store->chunk_size))
return -1;
Expand All @@ -65,7 +65,7 @@ static void transient_usage(struct dm_exception_store *store,
sector_t *metadata_sectors)
{
*sectors_allocated = ((struct transient_c *) store->context)->next_free;
*total_sectors = get_dev_size(store->cow->bdev);
*total_sectors = get_dev_size(dm_snap_cow(store->snap)->bdev);
*metadata_sectors = 0;
}

Expand Down Expand Up @@ -94,8 +94,7 @@ static unsigned transient_status(struct dm_exception_store *store,
case STATUSTYPE_INFO:
break;
case STATUSTYPE_TABLE:
DMEMIT(" %s N %llu", store->cow->name,
(unsigned long long)store->chunk_size);
DMEMIT(" N %llu", (unsigned long long)store->chunk_size);
}

return sz;
Expand Down
74 changes: 49 additions & 25 deletions drivers/md/dm-snap.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ struct dm_snapshot {
struct rw_semaphore lock;

struct dm_dev *origin;
struct dm_dev *cow;

struct dm_target *ti;

/* List of snapshots per Origin */
struct list_head list;
Expand Down Expand Up @@ -97,6 +100,12 @@ struct dm_snapshot {
struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE];
};

struct dm_dev *dm_snap_cow(struct dm_snapshot *s)
{
return s->cow;
}
EXPORT_SYMBOL(dm_snap_cow);

static struct workqueue_struct *ksnapd;
static void flush_queued_bios(struct work_struct *work);

Expand Down Expand Up @@ -558,7 +567,7 @@ static int init_hash_tables(struct dm_snapshot *s)
* Calculate based on the size of the original volume or
* the COW volume...
*/
cow_dev_size = get_dev_size(s->store->cow->bdev);
cow_dev_size = get_dev_size(s->cow->bdev);
origin_dev_size = get_dev_size(s->origin->bdev);
max_buckets = calc_max_buckets();

Expand Down Expand Up @@ -596,45 +605,55 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
struct dm_snapshot *s;
int i;
int r = -EINVAL;
char *origin_path;
struct dm_exception_store *store;
char *origin_path, *cow_path;
unsigned args_used;

if (argc != 4) {
ti->error = "requires exactly 4 arguments";
r = -EINVAL;
goto bad_args;
goto bad;
}

origin_path = argv[0];
argv++;
argc--;

r = dm_exception_store_create(ti, argc, argv, &args_used, &store);
s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s) {
ti->error = "Cannot allocate snapshot context private "
"structure";
r = -ENOMEM;
goto bad;
}

cow_path = argv[0];
argv++;
argc--;

r = dm_get_device(ti, cow_path, 0, 0,
FMODE_READ | FMODE_WRITE, &s->cow);
if (r) {
ti->error = "Cannot get COW device";
goto bad_cow;
}

r = dm_exception_store_create(ti, argc, argv, s, &args_used, &s->store);
if (r) {
ti->error = "Couldn't create exception store";
r = -EINVAL;
goto bad_args;
goto bad_store;
}

argv += args_used;
argc -= args_used;

s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s) {
ti->error = "Cannot allocate snapshot context private "
"structure";
r = -ENOMEM;
goto bad_snap;
}

r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin);
if (r) {
ti->error = "Cannot get origin device";
goto bad_origin;
}

s->store = store;
s->ti = ti;
s->valid = 1;
s->active = 0;
atomic_set(&s->pending_exceptions_count, 0);
Expand Down Expand Up @@ -723,12 +742,15 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
dm_put_device(ti, s->origin);

bad_origin:
kfree(s);
dm_exception_store_destroy(s->store);

bad_snap:
dm_exception_store_destroy(store);
bad_store:
dm_put_device(ti, s->cow);

bad_args:
bad_cow:
kfree(s);

bad:
return r;
}

Expand Down Expand Up @@ -777,6 +799,8 @@ static void snapshot_dtr(struct dm_target *ti)

dm_exception_store_destroy(s->store);

dm_put_device(ti, s->cow);

kfree(s);
}

Expand Down Expand Up @@ -839,7 +863,7 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)

s->valid = 0;

dm_table_event(s->store->ti->table);
dm_table_event(s->ti->table);
}

static void get_pending_exception(struct dm_snap_pending_exception *pe)
Expand Down Expand Up @@ -977,7 +1001,7 @@ static void start_copy(struct dm_snap_pending_exception *pe)
src.sector = chunk_to_sector(s->store, pe->e.old_chunk);
src.count = min((sector_t)s->store->chunk_size, dev_size - src.sector);

dest.bdev = s->store->cow->bdev;
dest.bdev = s->cow->bdev;
dest.sector = chunk_to_sector(s->store, pe->e.new_chunk);
dest.count = src.count;

Expand Down Expand Up @@ -1038,7 +1062,7 @@ __find_pending_exception(struct dm_snapshot *s,
static void remap_exception(struct dm_snapshot *s, struct dm_exception *e,
struct bio *bio, chunk_t chunk)
{
bio->bi_bdev = s->store->cow->bdev;
bio->bi_bdev = s->cow->bdev;
bio->bi_sector = chunk_to_sector(s->store,
dm_chunk_number(e->new_chunk) +
(chunk - e->old_chunk)) +
Expand All @@ -1056,7 +1080,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
struct dm_snap_pending_exception *pe = NULL;

if (unlikely(bio_empty_barrier(bio))) {
bio->bi_bdev = s->store->cow->bdev;
bio->bi_bdev = s->cow->bdev;
return DM_MAPIO_REMAPPED;
}

Expand Down Expand Up @@ -1200,7 +1224,7 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
* to make private copies if the output is to
* make sense.
*/
DMEMIT("%s", snap->origin->name);
DMEMIT("%s %s", snap->origin->name, snap->cow->name);
snap->store->type->status(snap->store, type, result + sz,
maxlen - sz);
break;
Expand Down Expand Up @@ -1240,7 +1264,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
goto next_snapshot;

/* Nothing to do if writing beyond end of snapshot */
if (bio->bi_sector >= dm_table_get_size(snap->store->ti->table))
if (bio->bi_sector >= dm_table_get_size(snap->ti->table))
goto next_snapshot;

/*
Expand Down

0 comments on commit fc56f6f

Please sign in to comment.