Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm
Browse files Browse the repository at this point in the history
* git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm: (36 commits)
  dm: set queue ordered mode
  dm: move wait queue declaration
  dm: merge pushback and deferred bio lists
  dm: allow uninterruptible wait for pending io
  dm: merge __flush_deferred_io into caller
  dm: move bio_io_error into __split_and_process_bio
  dm: rename __split_bio
  dm: remove unnecessary struct dm_wq_req
  dm: remove unnecessary work queue context field
  dm: remove unnecessary work queue type field
  dm: bio list add bio_list_add_head
  dm snapshot: persistent fix dtr cleanup
  dm snapshot: move status to exception store
  dm snapshot: move ctr parsing to exception store
  dm snapshot: use DMEMIT macro for status
  dm snapshot: remove dm_snap header
  dm snapshot: remove dm_snap header use
  dm exception store: move cow pointer
  dm exception store: move chunk_fields
  dm exception store: move dm_target pointer
  ...
  • Loading branch information
Linus Torvalds committed Apr 3, 2009
2 parents 9b59f03 + 99360b4 commit d9b9be0
Show file tree
Hide file tree
Showing 19 changed files with 893 additions and 620 deletions.
10 changes: 10 additions & 0 deletions drivers/md/dm-bio-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ static inline void bio_list_add(struct bio_list *bl, struct bio *bio)
bl->tail = bio;
}

static inline void bio_list_add_head(struct bio_list *bl, struct bio *bio)
{
bio->bi_next = bl->head;

bl->head = bio;

if (!bl->tail)
bl->tail = bio;
}

static inline void bio_list_merge(struct bio_list *bl, struct bio_list *bl2)
{
if (!bl2->head)
Expand Down
26 changes: 26 additions & 0 deletions drivers/md/dm-bio-record.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,56 @@
* functions in this file help the target record and restore the
* original bio state.
*/

struct dm_bio_vec_details {
#if PAGE_SIZE < 65536
__u16 bv_len;
__u16 bv_offset;
#else
unsigned bv_len;
unsigned bv_offset;
#endif
};

struct dm_bio_details {
sector_t bi_sector;
struct block_device *bi_bdev;
unsigned int bi_size;
unsigned short bi_idx;
unsigned long bi_flags;
struct dm_bio_vec_details bi_io_vec[BIO_MAX_PAGES];
};

static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio)
{
unsigned i;

bd->bi_sector = bio->bi_sector;
bd->bi_bdev = bio->bi_bdev;
bd->bi_size = bio->bi_size;
bd->bi_idx = bio->bi_idx;
bd->bi_flags = bio->bi_flags;

for (i = 0; i < bio->bi_vcnt; i++) {
bd->bi_io_vec[i].bv_len = bio->bi_io_vec[i].bv_len;
bd->bi_io_vec[i].bv_offset = bio->bi_io_vec[i].bv_offset;
}
}

static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio)
{
unsigned i;

bio->bi_sector = bd->bi_sector;
bio->bi_bdev = bd->bi_bdev;
bio->bi_size = bd->bi_size;
bio->bi_idx = bd->bi_idx;
bio->bi_flags = bd->bi_flags;

for (i = 0; i < bio->bi_vcnt; i++) {
bio->bi_io_vec[i].bv_len = bd->bi_io_vec[i].bv_len;
bio->bi_io_vec[i].bv_offset = bd->bi_io_vec[i].bv_offset;
}
}

#endif
6 changes: 2 additions & 4 deletions drivers/md/dm-crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1156,8 +1156,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
crypto_free_ablkcipher(tfm);
bad_cipher:
/* Must zero key material before freeing */
memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8));
kfree(cc);
kzfree(cc);
return -EINVAL;
}

Expand All @@ -1183,8 +1182,7 @@ static void crypt_dtr(struct dm_target *ti)
dm_put_device(ti, cc->dev);

/* Must zero key material before freeing */
memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8));
kfree(cc);
kzfree(cc);
}

static int crypt_map(struct dm_target *ti, struct bio *bio,
Expand Down
252 changes: 252 additions & 0 deletions drivers/md/dm-exception-store.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,265 @@

#include "dm-exception-store.h"

#include <linux/ctype.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>

#define DM_MSG_PREFIX "snapshot exception stores"

static LIST_HEAD(_exception_store_types);
static DEFINE_SPINLOCK(_lock);

static struct dm_exception_store_type *__find_exception_store_type(const char *name)
{
struct dm_exception_store_type *type;

list_for_each_entry(type, &_exception_store_types, list)
if (!strcmp(name, type->name))
return type;

return NULL;
}

static struct dm_exception_store_type *_get_exception_store_type(const char *name)
{
struct dm_exception_store_type *type;

spin_lock(&_lock);

type = __find_exception_store_type(name);

if (type && !try_module_get(type->module))
type = NULL;

spin_unlock(&_lock);

return type;
}

/*
* get_type
* @type_name
*
* Attempt to retrieve the dm_exception_store_type by name. If not already
* available, attempt to load the appropriate module.
*
* Exstore modules are named "dm-exstore-" followed by the 'type_name'.
* Modules may contain multiple types.
* This function will first try the module "dm-exstore-<type_name>",
* then truncate 'type_name' on the last '-' and try again.
*
* For example, if type_name was "clustered-shared", it would search
* 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'.
*
* 'dm-exception-store-<type_name>' is too long of a name in my
* opinion, which is why I've chosen to have the files
* containing exception store implementations be 'dm-exstore-<type_name>'.
* If you want your module to be autoloaded, you will follow this
* naming convention.
*
* Returns: dm_exception_store_type* on success, NULL on failure
*/
static struct dm_exception_store_type *get_type(const char *type_name)
{
char *p, *type_name_dup;
struct dm_exception_store_type *type;

type = _get_exception_store_type(type_name);
if (type)
return type;

type_name_dup = kstrdup(type_name, GFP_KERNEL);
if (!type_name_dup) {
DMERR("No memory left to attempt load for \"%s\"", type_name);
return NULL;
}

while (request_module("dm-exstore-%s", type_name_dup) ||
!(type = _get_exception_store_type(type_name))) {
p = strrchr(type_name_dup, '-');
if (!p)
break;
p[0] = '\0';
}

if (!type)
DMWARN("Module for exstore type \"%s\" not found.", type_name);

kfree(type_name_dup);

return type;
}

static void put_type(struct dm_exception_store_type *type)
{
spin_lock(&_lock);
module_put(type->module);
spin_unlock(&_lock);
}

int dm_exception_store_type_register(struct dm_exception_store_type *type)
{
int r = 0;

spin_lock(&_lock);
if (!__find_exception_store_type(type->name))
list_add(&type->list, &_exception_store_types);
else
r = -EEXIST;
spin_unlock(&_lock);

return r;
}
EXPORT_SYMBOL(dm_exception_store_type_register);

int dm_exception_store_type_unregister(struct dm_exception_store_type *type)
{
spin_lock(&_lock);

if (!__find_exception_store_type(type->name)) {
spin_unlock(&_lock);
return -EINVAL;
}

list_del(&type->list);

spin_unlock(&_lock);

return 0;
}
EXPORT_SYMBOL(dm_exception_store_type_unregister);

/*
* Round a number up to the nearest 'size' boundary. size must
* be a power of 2.
*/
static ulong round_up(ulong n, ulong size)
{
size--;
return (n + size) & ~size;
}

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') {
*error = "Invalid chunk size";
return -EINVAL;
}

if (!chunk_size_ulong) {
store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
return 0;
}

/*
* Chunk size must be multiple of page size. Silently
* round up if it's not.
*/
chunk_size_ulong = round_up(chunk_size_ulong, PAGE_SIZE >> 9);

/* Check chunk_size is a power of 2 */
if (!is_power_of_2(chunk_size_ulong)) {
*error = "Chunk size is not a power of 2";
return -EINVAL;
}

/* Validate the chunk size against the device block size */
if (chunk_size_ulong % (bdev_hardsect_size(store->cow->bdev) >> 9)) {
*error = "Chunk size is not a multiple of device blocksize";
return -EINVAL;
}

store->chunk_size = chunk_size_ulong;
store->chunk_mask = chunk_size_ulong - 1;
store->chunk_shift = ffs(chunk_size_ulong) - 1;

return 0;
}

int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
unsigned *args_used,
struct dm_exception_store **store)
{
int r = 0;
struct dm_exception_store_type *type;
struct dm_exception_store *tmp_store;
char persistent;

if (argc < 3) {
ti->error = "Insufficient exception store arguments";
return -EINVAL;
}

tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL);
if (!tmp_store) {
ti->error = "Exception store allocation failed";
return -ENOMEM;
}

persistent = toupper(*argv[1]);
if (persistent != 'P' && persistent != 'N') {
ti->error = "Persistent flag is not P or N";
return -EINVAL;
}

type = get_type(argv[1]);
if (!type) {
ti->error = "Exception store type not recognised";
r = -EINVAL;
goto bad_type;
}

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

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);
if (r)
goto bad_cow;

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

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

bad_ctr:
dm_put_device(ti, tmp_store->cow);
bad_cow:
put_type(type);
bad_type:
kfree(tmp_store);
return r;
}
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);
}
EXPORT_SYMBOL(dm_exception_store_destroy);

int dm_exception_store_init(void)
{
int r;
Expand Down
Loading

0 comments on commit d9b9be0

Please sign in to comment.