Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 493df71c authored by Jonathan Brassow's avatar Jonathan Brassow Committed by Alasdair G Kergon
Browse files

dm exception store: introduce registry



Move exception stores into a registry.

Signed-off-by: default avatarJonathan Brassow <jbrassow@redhat.com>
Signed-off-by: default avatarAlasdair G Kergon <agk@redhat.com>
parent 7513c2a7
Loading
Loading
Loading
Loading
+162 −0
Original line number Diff line number Diff line
@@ -14,6 +14,168 @@

#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);

int dm_exception_store_create(const char *type_name,
			      struct dm_exception_store **store)
{
	int r = 0;
	struct dm_exception_store_type *type;
	struct dm_exception_store *tmp_store;

	tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL);
	if (!tmp_store)
		return -ENOMEM;

	type = get_type(type_name);
	if (!type) {
		kfree(tmp_store);
		return -EINVAL;
	}

	tmp_store->type = type;

	r = type->ctr(tmp_store, 0, NULL);
	if (r) {
		put_type(type);
		kfree(tmp_store);
		return r;
	}

	*store = tmp_store;
	return 0;
}
EXPORT_SYMBOL(dm_exception_store_create);

void dm_exception_store_destroy(struct dm_exception_store *store)
{
	store->type->dtr(store);
	put_type(store->type);
	kfree(store);
}
EXPORT_SYMBOL(dm_exception_store_destroy);

int dm_exception_store_init(void)
{
	int r;
+14 −5
Original line number Diff line number Diff line
@@ -39,6 +39,9 @@ struct dm_snap_exception {
 */
struct dm_exception_store;
struct dm_exception_store_type {
	const char *name;
	struct module *module;

	int (*ctr) (struct dm_exception_store *store,
		    unsigned argc, char **argv);

@@ -85,10 +88,13 @@ struct dm_exception_store_type {
	void (*fraction_full) (struct dm_exception_store *store,
			       sector_t *numerator,
			       sector_t *denominator);

	/* For internal device-mapper use only. */
	struct list_head list;
};

struct dm_exception_store {
	struct dm_exception_store_type type;
	struct dm_exception_store_type *type;

	struct dm_snapshot *snap;

@@ -138,6 +144,13 @@ static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e)

#  endif

int dm_exception_store_type_register(struct dm_exception_store_type *type);
int dm_exception_store_type_unregister(struct dm_exception_store_type *type);

int dm_exception_store_create(const char *type_name,
			      struct dm_exception_store **store);
void dm_exception_store_destroy(struct dm_exception_store *store);

int dm_exception_store_init(void);
void dm_exception_store_exit(void);

@@ -150,8 +163,4 @@ void dm_persistent_snapshot_exit(void);
int dm_transient_snapshot_init(void);
void dm_transient_snapshot_exit(void);

int dm_create_persistent(struct dm_exception_store *store);

int dm_create_transient(struct dm_exception_store *store);

#endif /* _LINUX_DM_EXCEPTION_STORE */
+57 −10
Original line number Diff line number Diff line
@@ -478,7 +478,7 @@ static void persistent_fraction_full(struct dm_exception_store *store,
	*denominator = get_dev_size(store->snap->cow->bdev);
}

static void persistent_destroy(struct dm_exception_store *store)
static void persistent_dtr(struct dm_exception_store *store)
{
	struct pstore *ps = get_info(store);

@@ -656,7 +656,8 @@ static void persistent_drop_snapshot(struct dm_exception_store *store)
		DMWARN("write header failed");
}

int dm_create_persistent(struct dm_exception_store *store)
static int persistent_ctr(struct dm_exception_store *store,
			  unsigned argc, char **argv)
{
	struct pstore *ps;

@@ -683,23 +684,69 @@ int dm_create_persistent(struct dm_exception_store *store)
		return -ENOMEM;
	}

	store->type.dtr = persistent_destroy;
	store->type.read_metadata = persistent_read_metadata;
	store->type.prepare_exception = persistent_prepare_exception;
	store->type.commit_exception = persistent_commit_exception;
	store->type.drop_snapshot = persistent_drop_snapshot;
	store->type.fraction_full = persistent_fraction_full;

	store->context = ps;

	return 0;
}

static int persistent_status(struct dm_exception_store *store,
			     status_type_t status, char *result,
			     unsigned int maxlen)
{
	int sz = 0;

	return sz;
}

static struct dm_exception_store_type _persistent_type = {
	.name = "persistent",
	.module = THIS_MODULE,
	.ctr = persistent_ctr,
	.dtr = persistent_dtr,
	.read_metadata = persistent_read_metadata,
	.prepare_exception = persistent_prepare_exception,
	.commit_exception = persistent_commit_exception,
	.drop_snapshot = persistent_drop_snapshot,
	.fraction_full = persistent_fraction_full,
	.status = persistent_status,
};

static struct dm_exception_store_type _persistent_compat_type = {
	.name = "P",
	.module = THIS_MODULE,
	.ctr = persistent_ctr,
	.dtr = persistent_dtr,
	.read_metadata = persistent_read_metadata,
	.prepare_exception = persistent_prepare_exception,
	.commit_exception = persistent_commit_exception,
	.drop_snapshot = persistent_drop_snapshot,
	.fraction_full = persistent_fraction_full,
	.status = persistent_status,
};

int dm_persistent_snapshot_init(void)
{
	return 0;
	int r;

	r = dm_exception_store_type_register(&_persistent_type);
	if (r) {
		DMERR("Unable to register persistent exception store type");
		return r;
	}

	r = dm_exception_store_type_register(&_persistent_compat_type);
	if (r) {
		DMERR("Unable to register old-style persistent exception "
		      "store type");
		dm_exception_store_type_unregister(&_persistent_type);
		return r;
	}

	return r;
}

void dm_persistent_snapshot_exit(void)
{
	dm_exception_store_type_unregister(&_persistent_type);
	dm_exception_store_type_unregister(&_persistent_compat_type);
}
+55 −10
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ struct transient_c {
	sector_t next_free;
};

static void transient_destroy(struct dm_exception_store *store)
static void transient_dtr(struct dm_exception_store *store)
{
	kfree(store->context);
}
@@ -67,17 +67,11 @@ static void transient_fraction_full(struct dm_exception_store *store,
	*denominator = get_dev_size(store->snap->cow->bdev);
}

int dm_create_transient(struct dm_exception_store *store)
static int transient_ctr(struct dm_exception_store *store,
			 unsigned argc, char **argv)
{
	struct transient_c *tc;

	store->type.dtr = transient_destroy;
	store->type.read_metadata = transient_read_metadata;
	store->type.prepare_exception = transient_prepare_exception;
	store->type.commit_exception = transient_commit_exception;
	store->type.drop_snapshot = NULL;
	store->type.fraction_full = transient_fraction_full;

	tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL);
	if (!tc)
		return -ENOMEM;
@@ -88,11 +82,62 @@ int dm_create_transient(struct dm_exception_store *store)
	return 0;
}

static int transient_status(struct dm_exception_store *store,
			    status_type_t status, char *result,
			    unsigned maxlen)
{
	int sz = 0;

	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,
	.fraction_full = transient_fraction_full,
	.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,
	.fraction_full = transient_fraction_full,
	.status = transient_status,
};

int dm_transient_snapshot_init(void)
{
	return 0;
	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);
}
+18 −23
Original line number Diff line number Diff line
@@ -610,8 +610,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
	if (r)
		goto bad3;

	s->type = persistent;

	s->valid = 1;
	s->active = 0;
	atomic_set(&s->pending_exceptions_count, 0);
@@ -626,19 +624,15 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
		goto bad3;
	}

	s->store.snap = s;

	if (persistent == 'P')
		r = dm_create_persistent(&s->store);
	else
		r = dm_create_transient(&s->store);

	r = dm_exception_store_create(argv[2], &s->store);
	if (r) {
		ti->error = "Couldn't create exception store";
		r = -EINVAL;
		goto bad4;
	}

	s->store->snap = s;

	r = dm_kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client);
	if (r) {
		ti->error = "Could not create kcopyd client";
@@ -665,7 +659,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
	spin_lock_init(&s->tracked_chunk_lock);

	/* Metadata must only be loaded into one table at once */
	r = s->store.type.read_metadata(&s->store, dm_add_exception, (void *)s);
	r = s->store->type->read_metadata(s->store, dm_add_exception,
					  (void *)s);
	if (r < 0) {
		ti->error = "Failed to read snapshot metadata";
		goto bad_load_and_register;
@@ -700,7 +695,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
	dm_kcopyd_client_destroy(s->kcopyd_client);

 bad5:
	s->store.type.dtr(&s->store);
	s->store->type->dtr(s->store);

 bad4:
	exit_exception_table(&s->pending, pending_cache);
@@ -725,7 +720,7 @@ static void __free_exceptions(struct dm_snapshot *s)
	exit_exception_table(&s->pending, pending_cache);
	exit_exception_table(&s->complete, exception_cache);

	s->store.type.dtr(&s->store);
	s->store->type->dtr(s->store);
}

static void snapshot_dtr(struct dm_target *ti)
@@ -820,8 +815,8 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)
	else if (err == -ENOMEM)
		DMERR("Invalidating snapshot: Unable to allocate exception.");

	if (s->store.type.drop_snapshot)
		s->store.type.drop_snapshot(&s->store);
	if (s->store->type->drop_snapshot)
		s->store->type->drop_snapshot(s->store);

	s->valid = 0;

@@ -943,7 +938,7 @@ static void copy_callback(int read_err, unsigned long write_err, void *context)

	else
		/* Update the metadata if we are persistent */
		s->store.type.commit_exception(&s->store, &pe->e,
		s->store->type->commit_exception(s->store, &pe->e,
						 commit_callback, pe);
}

@@ -1010,7 +1005,7 @@ __find_pending_exception(struct dm_snapshot *s,
	atomic_set(&pe->ref_count, 0);
	pe->started = 0;

	if (s->store.type.prepare_exception(&s->store, &pe->e)) {
	if (s->store->type->prepare_exception(s->store, &pe->e)) {
		free_pending_exception(pe);
		return NULL;
	}
@@ -1149,9 +1144,9 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
		if (!snap->valid)
			snprintf(result, maxlen, "Invalid");
		else {
			if (snap->store.type.fraction_full) {
			if (snap->store->type->fraction_full) {
				sector_t numerator, denominator;
				snap->store.type.fraction_full(&snap->store,
				snap->store->type->fraction_full(snap->store,
								 &numerator,
								 &denominator);
				snprintf(result, maxlen, "%llu/%llu",
@@ -1169,9 +1164,9 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
		 * to make private copies if the output is to
		 * make sense.
		 */
		snprintf(result, maxlen, "%s %s %c %llu",
		snprintf(result, maxlen, "%s %s %s %llu",
			 snap->origin->name, snap->cow->name,
			 snap->type,
			 snap->store->type->name,
			 (unsigned long long)snap->chunk_size);
		break;
	}
Loading