cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dm-exception-store.c (6570B)


      1/*
      2 * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
      3 * Copyright (C) 2006-2008 Red Hat GmbH
      4 *
      5 * This file is released under the GPL.
      6 */
      7
      8#include "dm-exception-store.h"
      9
     10#include <linux/ctype.h>
     11#include <linux/mm.h>
     12#include <linux/pagemap.h>
     13#include <linux/vmalloc.h>
     14#include <linux/module.h>
     15#include <linux/slab.h>
     16
     17#define DM_MSG_PREFIX "snapshot exception stores"
     18
     19static LIST_HEAD(_exception_store_types);
     20static DEFINE_SPINLOCK(_lock);
     21
     22static struct dm_exception_store_type *__find_exception_store_type(const char *name)
     23{
     24	struct dm_exception_store_type *type;
     25
     26	list_for_each_entry(type, &_exception_store_types, list)
     27		if (!strcmp(name, type->name))
     28			return type;
     29
     30	return NULL;
     31}
     32
     33static struct dm_exception_store_type *_get_exception_store_type(const char *name)
     34{
     35	struct dm_exception_store_type *type;
     36
     37	spin_lock(&_lock);
     38
     39	type = __find_exception_store_type(name);
     40
     41	if (type && !try_module_get(type->module))
     42		type = NULL;
     43
     44	spin_unlock(&_lock);
     45
     46	return type;
     47}
     48
     49/*
     50 * get_type
     51 * @type_name
     52 *
     53 * Attempt to retrieve the dm_exception_store_type by name.  If not already
     54 * available, attempt to load the appropriate module.
     55 *
     56 * Exstore modules are named "dm-exstore-" followed by the 'type_name'.
     57 * Modules may contain multiple types.
     58 * This function will first try the module "dm-exstore-<type_name>",
     59 * then truncate 'type_name' on the last '-' and try again.
     60 *
     61 * For example, if type_name was "clustered-shared", it would search
     62 * 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'.
     63 *
     64 * 'dm-exception-store-<type_name>' is too long of a name in my
     65 * opinion, which is why I've chosen to have the files
     66 * containing exception store implementations be 'dm-exstore-<type_name>'.
     67 * If you want your module to be autoloaded, you will follow this
     68 * naming convention.
     69 *
     70 * Returns: dm_exception_store_type* on success, NULL on failure
     71 */
     72static struct dm_exception_store_type *get_type(const char *type_name)
     73{
     74	char *p, *type_name_dup;
     75	struct dm_exception_store_type *type;
     76
     77	type = _get_exception_store_type(type_name);
     78	if (type)
     79		return type;
     80
     81	type_name_dup = kstrdup(type_name, GFP_KERNEL);
     82	if (!type_name_dup) {
     83		DMERR("No memory left to attempt load for \"%s\"", type_name);
     84		return NULL;
     85	}
     86
     87	while (request_module("dm-exstore-%s", type_name_dup) ||
     88	       !(type = _get_exception_store_type(type_name))) {
     89		p = strrchr(type_name_dup, '-');
     90		if (!p)
     91			break;
     92		p[0] = '\0';
     93	}
     94
     95	if (!type)
     96		DMWARN("Module for exstore type \"%s\" not found.", type_name);
     97
     98	kfree(type_name_dup);
     99
    100	return type;
    101}
    102
    103static void put_type(struct dm_exception_store_type *type)
    104{
    105	spin_lock(&_lock);
    106	module_put(type->module);
    107	spin_unlock(&_lock);
    108}
    109
    110int dm_exception_store_type_register(struct dm_exception_store_type *type)
    111{
    112	int r = 0;
    113
    114	spin_lock(&_lock);
    115	if (!__find_exception_store_type(type->name))
    116		list_add(&type->list, &_exception_store_types);
    117	else
    118		r = -EEXIST;
    119	spin_unlock(&_lock);
    120
    121	return r;
    122}
    123EXPORT_SYMBOL(dm_exception_store_type_register);
    124
    125int dm_exception_store_type_unregister(struct dm_exception_store_type *type)
    126{
    127	spin_lock(&_lock);
    128
    129	if (!__find_exception_store_type(type->name)) {
    130		spin_unlock(&_lock);
    131		return -EINVAL;
    132	}
    133
    134	list_del(&type->list);
    135
    136	spin_unlock(&_lock);
    137
    138	return 0;
    139}
    140EXPORT_SYMBOL(dm_exception_store_type_unregister);
    141
    142static int set_chunk_size(struct dm_exception_store *store,
    143			  const char *chunk_size_arg, char **error)
    144{
    145	unsigned chunk_size;
    146
    147	if (kstrtouint(chunk_size_arg, 10, &chunk_size)) {
    148		*error = "Invalid chunk size";
    149		return -EINVAL;
    150	}
    151
    152	if (!chunk_size) {
    153		store->chunk_size = store->chunk_mask = store->chunk_shift = 0;
    154		return 0;
    155	}
    156
    157	return dm_exception_store_set_chunk_size(store, chunk_size, error);
    158}
    159
    160int dm_exception_store_set_chunk_size(struct dm_exception_store *store,
    161				      unsigned chunk_size,
    162				      char **error)
    163{
    164	/* Check chunk_size is a power of 2 */
    165	if (!is_power_of_2(chunk_size)) {
    166		*error = "Chunk size is not a power of 2";
    167		return -EINVAL;
    168	}
    169
    170	/* Validate the chunk size against the device block size */
    171	if (chunk_size %
    172	    (bdev_logical_block_size(dm_snap_cow(store->snap)->bdev) >> 9) ||
    173	    chunk_size %
    174	    (bdev_logical_block_size(dm_snap_origin(store->snap)->bdev) >> 9)) {
    175		*error = "Chunk size is not a multiple of device blocksize";
    176		return -EINVAL;
    177	}
    178
    179	if (chunk_size > INT_MAX >> SECTOR_SHIFT) {
    180		*error = "Chunk size is too high";
    181		return -EINVAL;
    182	}
    183
    184	store->chunk_size = chunk_size;
    185	store->chunk_mask = chunk_size - 1;
    186	store->chunk_shift = __ffs(chunk_size);
    187
    188	return 0;
    189}
    190
    191int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
    192			      struct dm_snapshot *snap,
    193			      unsigned *args_used,
    194			      struct dm_exception_store **store)
    195{
    196	int r = 0;
    197	struct dm_exception_store_type *type = NULL;
    198	struct dm_exception_store *tmp_store;
    199	char persistent;
    200
    201	if (argc < 2) {
    202		ti->error = "Insufficient exception store arguments";
    203		return -EINVAL;
    204	}
    205
    206	tmp_store = kzalloc(sizeof(*tmp_store), GFP_KERNEL);
    207	if (!tmp_store) {
    208		ti->error = "Exception store allocation failed";
    209		return -ENOMEM;
    210	}
    211
    212	persistent = toupper(*argv[0]);
    213	if (persistent == 'P')
    214		type = get_type("P");
    215	else if (persistent == 'N')
    216		type = get_type("N");
    217	else {
    218		ti->error = "Exception store type is not P or N";
    219		r = -EINVAL;
    220		goto bad_type;
    221	}
    222
    223	if (!type) {
    224		ti->error = "Exception store type not recognised";
    225		r = -EINVAL;
    226		goto bad_type;
    227	}
    228
    229	tmp_store->type = type;
    230	tmp_store->snap = snap;
    231
    232	r = set_chunk_size(tmp_store, argv[1], &ti->error);
    233	if (r)
    234		goto bad;
    235
    236	r = type->ctr(tmp_store, (strlen(argv[0]) > 1 ? &argv[0][1] : NULL));
    237	if (r) {
    238		ti->error = "Exception store type constructor failed";
    239		goto bad;
    240	}
    241
    242	*args_used = 2;
    243	*store = tmp_store;
    244	return 0;
    245
    246bad:
    247	put_type(type);
    248bad_type:
    249	kfree(tmp_store);
    250	return r;
    251}
    252EXPORT_SYMBOL(dm_exception_store_create);
    253
    254void dm_exception_store_destroy(struct dm_exception_store *store)
    255{
    256	store->type->dtr(store);
    257	put_type(store->type);
    258	kfree(store);
    259}
    260EXPORT_SYMBOL(dm_exception_store_destroy);
    261
    262int dm_exception_store_init(void)
    263{
    264	int r;
    265
    266	r = dm_transient_snapshot_init();
    267	if (r) {
    268		DMERR("Unable to register transient exception store type.");
    269		goto transient_fail;
    270	}
    271
    272	r = dm_persistent_snapshot_init();
    273	if (r) {
    274		DMERR("Unable to register persistent exception store type");
    275		goto persistent_fail;
    276	}
    277
    278	return 0;
    279
    280persistent_fail:
    281	dm_transient_snapshot_exit();
    282transient_fail:
    283	return r;
    284}
    285
    286void dm_exception_store_exit(void)
    287{
    288	dm_persistent_snapshot_exit();
    289	dm_transient_snapshot_exit();
    290}