forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
3.7 KiB
152 lines
3.7 KiB
/* |
|
* Copyright (C) 2001-2002 Sistina Software (UK) Limited. |
|
* Copyright (C) 2006-2008 Red Hat GmbH |
|
* |
|
* This file is released under the GPL. |
|
*/ |
|
|
|
#include "dm-exception-store.h" |
|
|
|
#include <linux/mm.h> |
|
#include <linux/pagemap.h> |
|
#include <linux/vmalloc.h> |
|
#include <linux/export.h> |
|
#include <linux/slab.h> |
|
#include <linux/dm-io.h> |
|
|
|
#define DM_MSG_PREFIX "transient snapshot" |
|
|
|
/*----------------------------------------------------------------- |
|
* Implementation of the store for non-persistent snapshots. |
|
*---------------------------------------------------------------*/ |
|
struct transient_c { |
|
sector_t next_free; |
|
}; |
|
|
|
static void transient_dtr(struct dm_exception_store *store) |
|
{ |
|
kfree(store->context); |
|
} |
|
|
|
static int transient_read_metadata(struct dm_exception_store *store, |
|
int (*callback)(void *callback_context, |
|
chunk_t old, chunk_t new), |
|
void *callback_context) |
|
{ |
|
return 0; |
|
} |
|
|
|
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(dm_snap_cow(store->snap)->bdev); |
|
|
|
if (size < (tc->next_free + store->chunk_size)) |
|
return -1; |
|
|
|
e->new_chunk = sector_to_chunk(store, tc->next_free); |
|
tc->next_free += store->chunk_size; |
|
|
|
return 0; |
|
} |
|
|
|
static void transient_commit_exception(struct dm_exception_store *store, |
|
struct dm_exception *e, int valid, |
|
void (*callback) (void *, int success), |
|
void *callback_context) |
|
{ |
|
/* Just succeed */ |
|
callback(callback_context, valid); |
|
} |
|
|
|
static void transient_usage(struct dm_exception_store *store, |
|
sector_t *total_sectors, |
|
sector_t *sectors_allocated, |
|
sector_t *metadata_sectors) |
|
{ |
|
*sectors_allocated = ((struct transient_c *) store->context)->next_free; |
|
*total_sectors = get_dev_size(dm_snap_cow(store->snap)->bdev); |
|
*metadata_sectors = 0; |
|
} |
|
|
|
static int transient_ctr(struct dm_exception_store *store, char *options) |
|
{ |
|
struct transient_c *tc; |
|
|
|
tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL); |
|
if (!tc) |
|
return -ENOMEM; |
|
|
|
tc->next_free = 0; |
|
store->context = tc; |
|
|
|
return 0; |
|
} |
|
|
|
static unsigned transient_status(struct dm_exception_store *store, |
|
status_type_t status, char *result, |
|
unsigned maxlen) |
|
{ |
|
unsigned sz = 0; |
|
|
|
switch (status) { |
|
case STATUSTYPE_INFO: |
|
break; |
|
case STATUSTYPE_TABLE: |
|
DMEMIT(" N %llu", (unsigned long long)store->chunk_size); |
|
} |
|
|
|
return sz; |
|
} |
|
|
|
static struct dm_exception_store_type _transient_type = { |
|
.name = "transient", |
|
.module = THIS_MODULE, |
|
.ctr = transient_ctr, |
|
.dtr = transient_dtr, |
|
.read_metadata = transient_read_metadata, |
|
.prepare_exception = transient_prepare_exception, |
|
.commit_exception = transient_commit_exception, |
|
.usage = transient_usage, |
|
.status = transient_status, |
|
}; |
|
|
|
static struct dm_exception_store_type _transient_compat_type = { |
|
.name = "N", |
|
.module = THIS_MODULE, |
|
.ctr = transient_ctr, |
|
.dtr = transient_dtr, |
|
.read_metadata = transient_read_metadata, |
|
.prepare_exception = transient_prepare_exception, |
|
.commit_exception = transient_commit_exception, |
|
.usage = transient_usage, |
|
.status = transient_status, |
|
}; |
|
|
|
int dm_transient_snapshot_init(void) |
|
{ |
|
int r; |
|
|
|
r = dm_exception_store_type_register(&_transient_type); |
|
if (r) { |
|
DMWARN("Unable to register transient exception store type"); |
|
return r; |
|
} |
|
|
|
r = dm_exception_store_type_register(&_transient_compat_type); |
|
if (r) { |
|
DMWARN("Unable to register old-style transient " |
|
"exception store type"); |
|
dm_exception_store_type_unregister(&_transient_type); |
|
return r; |
|
} |
|
|
|
return r; |
|
} |
|
|
|
void dm_transient_snapshot_exit(void) |
|
{ |
|
dm_exception_store_type_unregister(&_transient_type); |
|
dm_exception_store_type_unregister(&_transient_compat_type); |
|
}
|
|
|