| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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/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; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:31 +01:00
										 |  |  | static void transient_dtr(struct dm_exception_store *store) | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	kfree(store->context); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:19 +00:00
										 |  |  | static int transient_read_metadata(struct dm_exception_store *store, | 
					
						
							|  |  |  | 				   int (*callback)(void *callback_context, | 
					
						
							|  |  |  | 						   chunk_t old, chunk_t new), | 
					
						
							|  |  |  | 				   void *callback_context) | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:19 +00:00
										 |  |  | static int transient_prepare_exception(struct dm_exception_store *store, | 
					
						
							| 
									
										
										
										
											2009-12-10 23:52:10 +00:00
										 |  |  | 				       struct dm_exception *e) | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:30 +01:00
										 |  |  | 	struct transient_c *tc = store->context; | 
					
						
							| 
									
										
										
										
											2009-12-10 23:52:12 +00:00
										 |  |  | 	sector_t size = get_dev_size(dm_snap_cow(store->snap)->bdev); | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:32 +01:00
										 |  |  | 	if (size < (tc->next_free + store->chunk_size)) | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:33 +01:00
										 |  |  | 	e->new_chunk = sector_to_chunk(store, tc->next_free); | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:32 +01:00
										 |  |  | 	tc->next_free += store->chunk_size; | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:19 +00:00
										 |  |  | static void transient_commit_exception(struct dm_exception_store *store, | 
					
						
							| 
									
										
										
										
											2009-12-10 23:52:10 +00:00
										 |  |  | 				       struct dm_exception *e, | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:19 +00:00
										 |  |  | 				       void (*callback) (void *, int success), | 
					
						
							|  |  |  | 				       void *callback_context) | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	/* Just succeed */ | 
					
						
							|  |  |  | 	callback(callback_context, 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-10 23:52:11 +00:00
										 |  |  | static void transient_usage(struct dm_exception_store *store, | 
					
						
							|  |  |  | 			    sector_t *total_sectors, | 
					
						
							|  |  |  | 			    sector_t *sectors_allocated, | 
					
						
							|  |  |  | 			    sector_t *metadata_sectors) | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-12-10 23:52:11 +00:00
										 |  |  | 	*sectors_allocated = ((struct transient_c *) store->context)->next_free; | 
					
						
							| 
									
										
										
										
											2009-12-10 23:52:12 +00:00
										 |  |  | 	*total_sectors = get_dev_size(dm_snap_cow(store->snap)->bdev); | 
					
						
							| 
									
										
										
										
											2009-12-10 23:52:11 +00:00
										 |  |  | 	*metadata_sectors = 0; | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:31 +01:00
										 |  |  | static int transient_ctr(struct dm_exception_store *store, | 
					
						
							|  |  |  | 			 unsigned argc, char **argv) | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:35 +01:00
										 |  |  | static unsigned transient_status(struct dm_exception_store *store, | 
					
						
							|  |  |  | 				 status_type_t status, char *result, | 
					
						
							|  |  |  | 				 unsigned maxlen) | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:31 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:35 +01:00
										 |  |  | 	unsigned sz = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (status) { | 
					
						
							|  |  |  | 	case STATUSTYPE_INFO: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case STATUSTYPE_TABLE: | 
					
						
							| 
									
										
										
										
											2009-12-10 23:52:12 +00:00
										 |  |  | 		DMEMIT(" N %llu", (unsigned long long)store->chunk_size); | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:35 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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, | 
					
						
							| 
									
										
										
										
											2009-12-10 23:52:11 +00:00
										 |  |  | 	.usage = transient_usage, | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:31 +01:00
										 |  |  | 	.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, | 
					
						
							| 
									
										
										
										
											2009-12-10 23:52:11 +00:00
										 |  |  | 	.usage = transient_usage, | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:31 +01:00
										 |  |  | 	.status = transient_status, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | int dm_transient_snapshot_init(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:31 +01:00
										 |  |  | 	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; | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void dm_transient_snapshot_exit(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-04-02 19:55:31 +01:00
										 |  |  | 	dm_exception_store_type_unregister(&_transient_type); | 
					
						
							|  |  |  | 	dm_exception_store_type_unregister(&_transient_compat_type); | 
					
						
							| 
									
										
										
										
											2009-01-06 03:05:17 +00:00
										 |  |  | } |