dm snapshot: test chunk size against both origin and snapshot
authorMikulas Patocka <mpatocka@redhat.com>
Thu, 12 Aug 2010 03:13:51 +0000 (04:13 +0100)
committerAlasdair G Kergon <agk@redhat.com>
Thu, 12 Aug 2010 03:13:51 +0000 (04:13 +0100)
Validate chunk size against both origin and snapshot sector size

Don't allow chunk size smaller than either origin or snapshot logical
sector size. Reading or writing data not aligned to sector size is not
allowed and causes immediate errors.

This requires us to open the origin before initialising the
exception store and to export dm_snap_origin.

Cc: stable@kernel.org
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Reviewed-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
drivers/md/dm-exception-store.c
drivers/md/dm-exception-store.h
drivers/md/dm-snap.c

index 2b7907b6dd094611c8cc9f31fbead6d7b553e1d7..0bdb201c2c2af04ceea2905db5f56c10fe1091df 100644 (file)
@@ -173,7 +173,9 @@ 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(dm_snap_cow(store->snap)->bdev) >> 9)) {
+           (bdev_logical_block_size(dm_snap_cow(store->snap)->bdev) >> 9) ||
+           chunk_size %
+           (bdev_logical_block_size(dm_snap_origin(store->snap)->bdev) >> 9)) {
                *error = "Chunk size is not a multiple of device blocksize";
                return -EINVAL;
        }
index e8dfa06af3ba531b6cca02842effd91cc083eb1c..0b2536247cf55a3215223b8b0c72ff29a629b87a 100644 (file)
@@ -126,8 +126,9 @@ struct dm_exception_store {
 };
 
 /*
- * Obtain the cow device used by a given snapshot.
+ * Obtain the origin or cow device used by a given snapshot.
  */
+struct dm_dev *dm_snap_origin(struct dm_snapshot *snap);
 struct dm_dev *dm_snap_cow(struct dm_snapshot *snap);
 
 /*
index a6ab98920cc3689bb5b8645277a5a658d02b5ee0..a1f2ab553b92763c9b520a161d8851e27ae04ed2 100644 (file)
@@ -148,6 +148,12 @@ struct dm_snapshot {
 #define RUNNING_MERGE          0
 #define SHUTDOWN_MERGE         1
 
+struct dm_dev *dm_snap_origin(struct dm_snapshot *s)
+{
+       return s->origin;
+}
+EXPORT_SYMBOL(dm_snap_origin);
+
 struct dm_dev *dm_snap_cow(struct dm_snapshot *s)
 {
        return s->cow;
@@ -1065,10 +1071,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                origin_mode = FMODE_WRITE;
        }
 
-       origin_path = argv[0];
-       argv++;
-       argc--;
-
        s = kmalloc(sizeof(*s), GFP_KERNEL);
        if (!s) {
                ti->error = "Cannot allocate snapshot context private "
@@ -1077,6 +1079,16 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad;
        }
 
+       origin_path = argv[0];
+       argv++;
+       argc--;
+
+       r = dm_get_device(ti, origin_path, origin_mode, &s->origin);
+       if (r) {
+               ti->error = "Cannot get origin device";
+               goto bad_origin;
+       }
+
        cow_path = argv[0];
        argv++;
        argc--;
@@ -1097,12 +1109,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        argv += args_used;
        argc -= args_used;
 
-       r = dm_get_device(ti, origin_path, origin_mode, &s->origin);
-       if (r) {
-               ti->error = "Cannot get origin device";
-               goto bad_origin;
-       }
-
        s->ti = ti;
        s->valid = 1;
        s->active = 0;
@@ -1212,15 +1218,15 @@ bad_kcopyd:
        dm_exception_table_exit(&s->complete, exception_cache);
 
 bad_hash_tables:
-       dm_put_device(ti, s->origin);
-
-bad_origin:
        dm_exception_store_destroy(s->store);
 
 bad_store:
        dm_put_device(ti, s->cow);
 
 bad_cow:
+       dm_put_device(ti, s->origin);
+
+bad_origin:
        kfree(s);
 
 bad:
@@ -1314,12 +1320,12 @@ static void snapshot_dtr(struct dm_target *ti)
 
        mempool_destroy(s->pending_pool);
 
-       dm_put_device(ti, s->origin);
-
        dm_exception_store_destroy(s->store);
 
        dm_put_device(ti, s->cow);
 
+       dm_put_device(ti, s->origin);
+
        kfree(s);
 }