Restore __ALIGN_MASK()
[safe/jmp/linux-2.6] / drivers / md / dm-exception-store.c
index 59c949b..2b7907b 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "dm-exception-store.h"
 
+#include <linux/ctype.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/vmalloc.h>
@@ -137,41 +138,118 @@ int dm_exception_store_type_unregister(struct dm_exception_store_type *type)
 }
 EXPORT_SYMBOL(dm_exception_store_type_unregister);
 
-int dm_exception_store_create(const char *type_name, struct dm_target *ti,
-                             chunk_t chunk_size, chunk_t chunk_mask,
-                             chunk_t chunk_shift,
+static int set_chunk_size(struct dm_exception_store *store,
+                         const char *chunk_size_arg, char **error)
+{
+       unsigned long chunk_size_ulong;
+       char *value;
+
+       chunk_size_ulong = simple_strtoul(chunk_size_arg, &value, 10);
+       if (*chunk_size_arg == '\0' || *value != '\0' ||
+           chunk_size_ulong > UINT_MAX) {
+               *error = "Invalid chunk size";
+               return -EINVAL;
+       }
+
+       if (!chunk_size_ulong) {
+               store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
+               return 0;
+       }
+
+       return dm_exception_store_set_chunk_size(store,
+                                                (unsigned) chunk_size_ulong,
+                                                error);
+}
+
+int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
+                                     unsigned chunk_size,
+                                     char **error)
+{
+       /* Check chunk_size is a power of 2 */
+       if (!is_power_of_2(chunk_size)) {
+               *error = "Chunk size is not a power of 2";
+               return -EINVAL;
+       }
+
+       /* Validate the chunk size against the device block size */
+       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;
+       }
+
+       if (chunk_size > INT_MAX >> SECTOR_SHIFT) {
+               *error = "Chunk size is too high";
+               return -EINVAL;
+       }
+
+       store->chunk_size = chunk_size;
+       store->chunk_mask = chunk_size - 1;
+       store->chunk_shift = ffs(chunk_size) - 1;
+
+       return 0;
+}
+
+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)
 {
        int r = 0;
-       struct dm_exception_store_type *type;
+       struct dm_exception_store_type *type = NULL;
        struct dm_exception_store *tmp_store;
+       char persistent;
+
+       if (argc < 2) {
+               ti->error = "Insufficient exception store arguments";
+               return -EINVAL;
+       }
 
        tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL);
-       if (!tmp_store)
+       if (!tmp_store) {
+               ti->error = "Exception store allocation failed";
                return -ENOMEM;
+       }
+
+       persistent = toupper(*argv[0]);
+       if (persistent == 'P')
+               type = get_type("P");
+       else if (persistent == 'N')
+               type = get_type("N");
+       else {
+               ti->error = "Persistent flag is not P or N";
+               r = -EINVAL;
+               goto bad_type;
+       }
 
-       type = get_type(type_name);
        if (!type) {
-               kfree(tmp_store);
-               return -EINVAL;
+               ti->error = "Exception store type not recognised";
+               r = -EINVAL;
+               goto bad_type;
        }
 
        tmp_store->type = type;
-       tmp_store->ti = ti;
+       tmp_store->snap = snap;
 
-       tmp_store->chunk_size = chunk_size;
-       tmp_store->chunk_mask = chunk_mask;
-       tmp_store->chunk_shift = chunk_shift;
+       r = set_chunk_size(tmp_store, argv[1], &ti->error);
+       if (r)
+               goto bad;
 
        r = type->ctr(tmp_store, 0, NULL);
        if (r) {
-               put_type(type);
-               kfree(tmp_store);
-               return r;
+               ti->error = "Exception store type constructor failed";
+               goto bad;
        }
 
+       *args_used = 2;
        *store = tmp_store;
        return 0;
+
+bad:
+       put_type(type);
+bad_type:
+       kfree(tmp_store);
+       return r;
 }
 EXPORT_SYMBOL(dm_exception_store_create);