diff options
Diffstat (limited to 'drivers/md')
| -rw-r--r-- | drivers/md/dm-exception-store.c | 162 | ||||
| -rw-r--r-- | drivers/md/dm-exception-store.h | 19 | ||||
| -rw-r--r-- | drivers/md/dm-snap-persistent.c | 67 | ||||
| -rw-r--r-- | drivers/md/dm-snap-transient.c | 65 | ||||
| -rw-r--r-- | drivers/md/dm-snap.c | 41 | ||||
| -rw-r--r-- | drivers/md/dm-snap.h | 2 | 
6 files changed, 307 insertions, 49 deletions
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c index dccbfb0e010..8912a3637ca 100644 --- a/drivers/md/dm-exception-store.c +++ b/drivers/md/dm-exception-store.c @@ -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; diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h index aed1f1172f9..31377150080 100644 --- a/drivers/md/dm-exception-store.h +++ b/drivers/md/dm-exception-store.h @@ -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 */ diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 0bbbe3b7431..e85b7a186a1 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -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);  } diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c index b558176ff02..51bc4a78ce9 100644 --- a/drivers/md/dm-snap-transient.c +++ b/drivers/md/dm-snap-transient.c @@ -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);  } diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index dabd58e9aaf..be698f3a4ae 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -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,8 +938,8 @@ 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, -					       commit_callback, pe); +		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,11 +1144,11 @@ 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, -							  &numerator, -							  &denominator); +				snap->store->type->fraction_full(snap->store, +								 &numerator, +								 &denominator);  				snprintf(result, maxlen, "%llu/%llu",  					(unsigned long long)numerator,  					(unsigned long long)denominator); @@ -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;  	} diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h index d9e62b43cf8..627be0f52c3 100644 --- a/drivers/md/dm-snap.h +++ b/drivers/md/dm-snap.h @@ -61,7 +61,7 @@ struct dm_snapshot {  	spinlock_t pe_lock;  	/* The on disk metadata handler */ -	struct dm_exception_store store; +	struct dm_exception_store *store;  	struct dm_kcopyd_client *kcopyd_client;  |