--- drivers/md/multisnap/Kconfig | 9 drivers/md/multisnap/Makefile | 4 drivers/md/multisnap/dm-multisnap-joe-unit-tests.c | 132 ++++++++++++ drivers/md/multisnap/dm-multisnap-joe.c | 222 +++++++++++++++++++++ drivers/md/multisnap/dm-multisnap-joe.h | 21 + 5 files changed, 388 insertions(+) Index: linux-2.6.36-rc7-fast/drivers/md/multisnap/Kconfig =================================================================== --- linux-2.6.36-rc7-fast.orig/drivers/md/multisnap/Kconfig 2010-10-15 02:31:37.000000000 +0200 +++ linux-2.6.36-rc7-fast/drivers/md/multisnap/Kconfig 2010-10-15 02:31:37.000000000 +0200 @@ -34,3 +34,12 @@ config DM_MULTISNAPSHOT_DANIEL So far it doesn't support maintaining consistency across crashes; journaling is under development. +config DM_MULTISNAP_JOE + tristate "Joe's snapshot store" + depends on DM_MULTISNAPSHOT + ---help--- + Joe Thornber's snapshot store. This data store accepts no + origin, all the data are stored on the snapshot store. + It allows unlimited snapshots and unlimited + snapshots-of-snapshots. + Index: linux-2.6.36-rc7-fast/drivers/md/multisnap/Makefile =================================================================== --- linux-2.6.36-rc7-fast.orig/drivers/md/multisnap/Makefile 2010-10-15 02:31:37.000000000 +0200 +++ linux-2.6.36-rc7-fast/drivers/md/multisnap/Makefile 2010-10-15 02:31:37.000000000 +0200 @@ -13,3 +13,7 @@ obj-$(CONFIG_DM_MULTISNAPSHOT_MIKULAS) + dm-store-daniel-y += dm-multisnap-daniel.o obj-$(CONFIG_DM_MULTISNAPSHOT_DANIEL) += dm-store-daniel.o + +dm-store-joe-y += dm-multisnap-joe.o dm-multisnap-joe-unit-tests.o + +obj-$(CONFIG_DM_MULTISNAPSHOT_DANIEL) += dm-store-joe.o Index: linux-2.6.36-rc7-fast/drivers/md/multisnap/dm-multisnap-joe.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.36-rc7-fast/drivers/md/multisnap/dm-multisnap-joe.c 2010-10-15 02:31:37.000000000 +0200 @@ -0,0 +1,222 @@ +#include "dm-multisnap-joe.h" + +/* + * Initialize one instance of the store. + */ +static int dm_multisnap_joe_init(struct dm_multisnap *dm, + struct dm_exception_store **sp, + unsigned argc, char **argv, char **error) +{ + int r; + struct dm_exception_store *s; + + s = kzalloc(sizeof(struct dm_exception_store), GFP_KERNEL); + if (!s) { + *error = "Could not allocate private area"; + r = -ENOMEM; + goto bad_private; + } + *sp = s; + + s->dm = dm; + s->chunk_size = dm_multisnap_chunk_size(dm); + s->chunk_shift = ffs(s->chunk_size) - 1; + + while (argc) { + char *string; + r = dm_multisnap_get_string(&argv, &argc, &string, error); + if (r) + goto bad_arguments; + /* + * Add test for future arguments here. + * Also, regenerate the arguments in the "status_table" + * callback. + */ + { + *error = "Unknown parameter"; + r = -EINVAL; + goto bad_arguments; + } + } + + s->bufio = dm_bufio_client_create(dm_multisnap_snapshot_bdev(s->dm), + s->chunk_size); + if (IS_ERR(s->bufio)) { + *error = "Can't create bufio client"; + r = PTR_ERR(s->bufio); + goto bad_bufio; + } + +#ifdef UNIT_TEST_BUFIO + r = dm_multisnap_joe_unit_test_bufio(s); + if (r) + goto bad_unit_test; +#endif + + return 0; + +#if defined(UNIT_TEST_BUFIO) +bad_unit_test: +#endif + +bad_bufio: +bad_arguments: + kfree(s); +bad_private: + return r; +} + +/* + * Free one instance of the store. + */ +static void dm_multisnap_joe_exit(struct dm_exception_store *s) +{ + dm_bufio_client_destroy(s->bufio); + kfree(s); +} + +/* + * Allocate ID for new snapshot (possibly snapshot of another snapshot). + */ +static int dm_multisnap_joe_allocate_snapid(struct dm_exception_store *s, snapid_t *snapid, int snap_of_snap, snapid_t master) +{ + return -EOPNOTSUPP; +} + +/* + * Create snapshot with a given ID. + */ +static int dm_multisnap_joe_create_snapshot(struct dm_exception_store *s, snapid_t snapid) +{ + return -EOPNOTSUPP; +} + +/* + * If "snapid" is valid snapshot ID, return snapid. + * Otherwise, return the next valid snapshot ID. + * If there is no next valid snapshot ID, return DM_SNAPID_T_ORIGIN. + */ +static snapid_t dm_multisnap_joe_get_next_snapid(struct dm_exception_store *s, snapid_t snapid) +{ + return DM_SNAPID_T_ORIGIN; +} + +/* + * Look up a translation for a given chunk. + * "write" is the hint that tells that the lookup is for writing. + * + * returns: + * -1 --- error + * 0 --- not found + * 1 --- read-only mapping (shared with other snapshots) exists + * 2 --- read-write mapping exists + */ +static int dm_multisnap_joe_find_snapshot_chunk(struct dm_exception_store *s, snapid_t snapid, chunk_t chunk, int write, chunk_t *result) +{ + return -1; +} + +/* + * Add next mapping after "find_snapshot_chunk" returned 0. + * + * Store the new location in "new_chunk", store the chunk ID in "cd" + * (that will be used by "check_conflict" to find conflicting I/Os) + * + * Doesn't return error code, instead, sets the error flag. + */ +static void dm_multisnap_joe_add_next_remap(struct dm_exception_store *s, union chunk_descriptor *cd, chunk_t *new_chunk) +{ +} + +/* + * Copy read-only chunk to make it read-write. + * + * Store the new location in "new_chunk", store the chunk ID in "cd". + */ +static void dm_multisnap_joe_make_chunk_writeable(struct dm_exception_store *s, union chunk_descriptor *cd, chunk_t *new_chunk) +{ +} + +/* + * Test if "snapid" belongs to the set of snapids described by "cd". + */ +static int dm_multisnap_joe_check_conflict(struct dm_exception_store *s, union chunk_descriptor *cd, snapid_t snapid) +{ + return snapid == cd->range.from; +} + +/* + * This function is optional. It flushes all buffers prior to commit, so that + * most metadata writes are not done under the lock. + * + * This function is not run under the lock, so it may race with anything. + */ +void dm_multisnap_joe_prepare_for_commit(struct dm_exception_store *s) +{ + int r; + + r = dm_bufio_write_dirty_buffers(s->bufio); + if (unlikely(r < 0)) { + /* !!! FIXME: log the error */ + } +} + +/* + * Permanently commit the changes. + * + * The changes must not be committed before this function is called. + * They must be committed when this function exits. + * + * Error is stored in the error flag, there is no return code. + */ +void dm_multisnap_joe_commit(struct dm_exception_store *s) +{ +} + +struct dm_multisnap_exception_store dm_multisnap_joe_store = { + .name = "joe", + .module = THIS_MODULE, + .init_exception_store = dm_multisnap_joe_init, + .exit_exception_store = dm_multisnap_joe_exit, + .allocate_snapid = dm_multisnap_joe_allocate_snapid, + .create_snapshot = dm_multisnap_joe_create_snapshot, + .get_next_snapid = dm_multisnap_joe_get_next_snapid, + .find_snapshot_chunk = dm_multisnap_joe_find_snapshot_chunk, + .add_next_remap = dm_multisnap_joe_add_next_remap, + .make_chunk_writeable = dm_multisnap_joe_make_chunk_writeable, + .check_conflict = dm_multisnap_joe_check_conflict, + .prepare_for_commit = dm_multisnap_joe_prepare_for_commit, + .commit = dm_multisnap_joe_commit, +}; + +/* + * Init the whole module + */ +static int __init dm_multisnapshot_joe_module_init(void) +{ + int r; + + r = dm_multisnap_register_exception_store(&dm_multisnap_joe_store); + if (r) + goto cant_register; + + return 0; + +cant_register: + return r; +} + +/* + * Exit the whole module + */ +static void __exit dm_multisnapshot_joe_module_exit(void) +{ + dm_multisnap_unregister_exception_store(&dm_multisnap_joe_store); +} + +module_init(dm_multisnapshot_joe_module_init); +module_exit(dm_multisnapshot_joe_module_exit); + +MODULE_DESCRIPTION(DM_NAME " multisnapshot Joe's exceptions store"); +MODULE_AUTHOR("Joe Thornber"); +MODULE_LICENSE("GPL"); Index: linux-2.6.36-rc7-fast/drivers/md/multisnap/dm-multisnap-joe.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.36-rc7-fast/drivers/md/multisnap/dm-multisnap-joe.h 2010-10-15 02:31:37.000000000 +0200 @@ -0,0 +1,21 @@ +#ifndef DM_MULTISNAP_JOE_H +#define DM_MULTISNAP_JOE_H + +#include "dm-multisnap.h" + +#include "../dm-bufio.h" + +#include + +struct dm_exception_store { + struct dm_multisnap *dm; + struct dm_bufio_client *bufio; + unsigned chunk_size; + unsigned char chunk_shift; +}; + +#define UNIT_TEST_BUFIO + +int dm_multisnap_joe_unit_test_bufio(struct dm_exception_store *s); + +#endif Index: linux-2.6.36-rc7-fast/drivers/md/multisnap/dm-multisnap-joe-unit-tests.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.36-rc7-fast/drivers/md/multisnap/dm-multisnap-joe-unit-tests.c 2010-10-15 02:31:37.000000000 +0200 @@ -0,0 +1,132 @@ +#include "dm-multisnap-joe.h" + +typedef unsigned seed_t; + +static void set_random(seed_t *seed, int x) +{ + if (!x) + x = 1234567; + *seed = x; +} + +static unsigned get_random(seed_t *seed) +{ + return *seed = 36969 * (*seed & 65535) + (*seed >> 16); +} + +#ifdef UNIT_TEST_BUFIO + +#define BUFIO_MAX_CHUNKS 1000 + +static int bufio_pattern(struct dm_exception_store *s, int generate, int pass, chunk_t chunk) +{ + int r; + unsigned i; + seed_t pattern; + struct dm_buffer *bp; + unsigned char *block; + + if (generate && chunk & 1) + block = dm_bufio_new(s->bufio, chunk, &bp); + else + block = dm_bufio_read(s->bufio, chunk, &bp); + if (IS_ERR(block)) { + printk("dm_bufio_read failed (%Lx,%d) !\n", + (unsigned long long)chunk, pass); + return PTR_ERR(block); + } + set_random(&pattern, chunk + (pass << 24)); + r = 0; + for (i = 0; i < s->chunk_size; i++) { + if (generate) { + block[i] = get_random(&pattern); + } else { + if (block[i] != (unsigned char)get_random(&pattern)) { + printk("dm_bufio pattern failure at %Lx/%x !\n", + (unsigned long long)chunk, i); + r = -EILSEQ; + break; + } + } + } + if (generate) + dm_bufio_mark_buffer_dirty(bp); + dm_bufio_release(bp); + return r; +} + +int dm_multisnap_joe_unit_test_bufio(struct dm_exception_store *s) +{ + int r = 0; + chunk_t *array; + chunk_t n_chunks = i_size_read(dm_multisnap_snapshot_bdev(s->dm)->bd_inode) >> s->chunk_shift; + int pass; + printk("unit test: bufio\n"); + if (!n_chunks) { + printk("empty device\n"); + return 0; + } + + array = kmalloc(sizeof(chunk_t) * BUFIO_MAX_CHUNKS, GFP_KERNEL); + if (!array) { + printk("alloc failed !\n"); + return -ENOMEM; + } + + for (pass = 0; pass < 2; pass++) { + seed_t seed; + unsigned n, limit = min((chunk_t)BUFIO_MAX_CHUNKS, n_chunks); + set_random(&seed, 1); + for (n = 0; n < limit; n++) { + unsigned i; + chunk_t chunk = get_random(&seed) % n_chunks; +test_chunk_again: + for (i = 0; i < n; i++) { + cond_resched(); + if (array[i] == chunk) { + chunk = (chunk + 1) % n_chunks; + goto test_chunk_again; + } + } + array[n] = chunk; + /*printk("testing: %u - %Lx\n", n, (unsigned long long)chunk);*/ + r = bufio_pattern(s, 1, pass, chunk); + if (r) + goto failed; + i = get_random(&seed) % (n + 1); + r = bufio_pattern(s, 0, pass, array[i]); + if (r) + goto failed; + if (pass == 1) { + if (n == limit / 4) { + dm_bufio_drop_buffers(s->bufio); + } + if (n == limit / 2) { + r = dm_bufio_write_dirty_buffers(s->bufio); + if (r) { + printk("dm_bufio_write_dirty_buffers failed !\n"); + goto failed; + } + } + if (n == limit * 3 / 4) { + dm_bufio_write_dirty_buffers_async(s->bufio); + } + } + } + for (n = 0; n < limit; n++) { + r = bufio_pattern(s, 0, pass, array[n]); + if (r) + goto failed; + } + } + +failed: + kfree(array); + + if (r) + printk("TEST FAILED\n"); + + return r; +} + +#endif