| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2010-2011 Red Hat, Inc. | 
 | 3 |  * | 
 | 4 |  * This file is released under the GPL. | 
 | 5 |  */ | 
 | 6 |  | 
 | 7 | #ifndef DM_THIN_METADATA_H | 
 | 8 | #define DM_THIN_METADATA_H | 
 | 9 |  | 
 | 10 | #include "persistent-data/dm-block-manager.h" | 
| Joe Thornber | ac8c3f3 | 2013-05-10 14:37:21 +0100 | [diff] [blame] | 11 | #include "persistent-data/dm-space-map.h" | 
| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 12 |  | 
 | 13 | #define THIN_METADATA_BLOCK_SIZE 4096 | 
 | 14 |  | 
| Mike Snitzer | c4a69ec | 2012-03-28 18:41:28 +0100 | [diff] [blame] | 15 | /* | 
 | 16 |  * The metadata device is currently limited in size. | 
 | 17 |  * | 
 | 18 |  * We have one block of index, which can hold 255 index entries.  Each | 
 | 19 |  * index entry contains allocation info about 16k metadata blocks. | 
 | 20 |  */ | 
 | 21 | #define THIN_METADATA_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT))) | 
 | 22 |  | 
 | 23 | /* | 
 | 24 |  * A metadata device larger than 16GB triggers a warning. | 
 | 25 |  */ | 
 | 26 | #define THIN_METADATA_MAX_SECTORS_WARNING (16 * (1024 * 1024 * 1024 >> SECTOR_SHIFT)) | 
 | 27 |  | 
| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 28 | /*----------------------------------------------------------------*/ | 
 | 29 |  | 
 | 30 | struct dm_pool_metadata; | 
 | 31 | struct dm_thin_device; | 
 | 32 |  | 
 | 33 | /* | 
 | 34 |  * Device identifier | 
 | 35 |  */ | 
 | 36 | typedef uint64_t dm_thin_id; | 
 | 37 |  | 
 | 38 | /* | 
 | 39 |  * Reopens or creates a new, empty metadata volume. | 
 | 40 |  */ | 
 | 41 | struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev, | 
| Joe Thornber | 66b1edc | 2012-07-27 15:08:14 +0100 | [diff] [blame] | 42 | 					       sector_t data_block_size, | 
 | 43 | 					       bool format_device); | 
| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 44 |  | 
 | 45 | int dm_pool_metadata_close(struct dm_pool_metadata *pmd); | 
 | 46 |  | 
 | 47 | /* | 
 | 48 |  * Compat feature flags.  Any incompat flags beyond the ones | 
 | 49 |  * specified below will prevent use of the thin metadata. | 
 | 50 |  */ | 
 | 51 | #define THIN_FEATURE_COMPAT_SUPP	  0UL | 
 | 52 | #define THIN_FEATURE_COMPAT_RO_SUPP	  0UL | 
 | 53 | #define THIN_FEATURE_INCOMPAT_SUPP	  0UL | 
 | 54 |  | 
 | 55 | /* | 
 | 56 |  * Device creation/deletion. | 
 | 57 |  */ | 
 | 58 | int dm_pool_create_thin(struct dm_pool_metadata *pmd, dm_thin_id dev); | 
 | 59 |  | 
 | 60 | /* | 
 | 61 |  * An internal snapshot. | 
 | 62 |  * | 
 | 63 |  * You can only snapshot a quiesced origin i.e. one that is either | 
 | 64 |  * suspended or not instanced at all. | 
 | 65 |  */ | 
 | 66 | int dm_pool_create_snap(struct dm_pool_metadata *pmd, dm_thin_id dev, | 
 | 67 | 			dm_thin_id origin); | 
 | 68 |  | 
 | 69 | /* | 
 | 70 |  * Deletes a virtual device from the metadata.  It _is_ safe to call this | 
 | 71 |  * when that device is open.  Operations on that device will just start | 
 | 72 |  * failing.  You still need to call close() on the device. | 
 | 73 |  */ | 
 | 74 | int dm_pool_delete_thin_device(struct dm_pool_metadata *pmd, | 
 | 75 | 			       dm_thin_id dev); | 
 | 76 |  | 
 | 77 | /* | 
 | 78 |  * Commits _all_ metadata changes: device creation, deletion, mapping | 
 | 79 |  * updates. | 
 | 80 |  */ | 
 | 81 | int dm_pool_commit_metadata(struct dm_pool_metadata *pmd); | 
 | 82 |  | 
 | 83 | /* | 
| Joe Thornber | da105ed | 2012-07-27 15:08:15 +0100 | [diff] [blame] | 84 |  * Discards all uncommitted changes.  Rereads the superblock, rolling back | 
 | 85 |  * to the last good transaction.  Thin devices remain open. | 
 | 86 |  * dm_thin_aborted_changes() tells you if they had uncommitted changes. | 
 | 87 |  * | 
 | 88 |  * If this call fails it's only useful to call dm_pool_metadata_close(). | 
 | 89 |  * All other methods will fail with -EINVAL. | 
 | 90 |  */ | 
 | 91 | int dm_pool_abort_metadata(struct dm_pool_metadata *pmd); | 
 | 92 |  | 
 | 93 | /* | 
| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 94 |  * Set/get userspace transaction id. | 
 | 95 |  */ | 
 | 96 | int dm_pool_set_metadata_transaction_id(struct dm_pool_metadata *pmd, | 
 | 97 | 					uint64_t current_id, | 
 | 98 | 					uint64_t new_id); | 
 | 99 |  | 
 | 100 | int dm_pool_get_metadata_transaction_id(struct dm_pool_metadata *pmd, | 
 | 101 | 					uint64_t *result); | 
 | 102 |  | 
 | 103 | /* | 
 | 104 |  * Hold/get root for userspace transaction. | 
| Joe Thornber | cc8394d | 2012-06-03 00:30:01 +0100 | [diff] [blame] | 105 |  * | 
 | 106 |  * The metadata snapshot is a copy of the current superblock (minus the | 
 | 107 |  * space maps).  Userland can access the data structures for READ | 
 | 108 |  * operations only.  A small performance hit is incurred by providing this | 
 | 109 |  * copy of the metadata to userland due to extra copy-on-write operations | 
 | 110 |  * on the metadata nodes.  Release this as soon as you finish with it. | 
| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 111 |  */ | 
| Joe Thornber | cc8394d | 2012-06-03 00:30:01 +0100 | [diff] [blame] | 112 | int dm_pool_reserve_metadata_snap(struct dm_pool_metadata *pmd); | 
 | 113 | int dm_pool_release_metadata_snap(struct dm_pool_metadata *pmd); | 
| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 114 |  | 
| Joe Thornber | cc8394d | 2012-06-03 00:30:01 +0100 | [diff] [blame] | 115 | int dm_pool_get_metadata_snap(struct dm_pool_metadata *pmd, | 
 | 116 | 			      dm_block_t *result); | 
| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 117 |  | 
 | 118 | /* | 
 | 119 |  * Actions on a single virtual device. | 
 | 120 |  */ | 
 | 121 |  | 
 | 122 | /* | 
 | 123 |  * Opening the same device more than once will fail with -EBUSY. | 
 | 124 |  */ | 
 | 125 | int dm_pool_open_thin_device(struct dm_pool_metadata *pmd, dm_thin_id dev, | 
 | 126 | 			     struct dm_thin_device **td); | 
 | 127 |  | 
 | 128 | int dm_pool_close_thin_device(struct dm_thin_device *td); | 
 | 129 |  | 
 | 130 | dm_thin_id dm_thin_dev_id(struct dm_thin_device *td); | 
 | 131 |  | 
 | 132 | struct dm_thin_lookup_result { | 
 | 133 | 	dm_block_t block; | 
| Mike Snitzer | 17b7d63 | 2012-07-27 15:07:57 +0100 | [diff] [blame] | 134 | 	unsigned shared:1; | 
| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 135 | }; | 
 | 136 |  | 
 | 137 | /* | 
 | 138 |  * Returns: | 
 | 139 |  *   -EWOULDBLOCK iff @can_block is set and would block. | 
 | 140 |  *   -ENODATA iff that mapping is not present. | 
 | 141 |  *   0 success | 
 | 142 |  */ | 
 | 143 | int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block, | 
 | 144 | 		       int can_block, struct dm_thin_lookup_result *result); | 
 | 145 |  | 
 | 146 | /* | 
 | 147 |  * Obtain an unused block. | 
 | 148 |  */ | 
 | 149 | int dm_pool_alloc_data_block(struct dm_pool_metadata *pmd, dm_block_t *result); | 
 | 150 |  | 
 | 151 | /* | 
 | 152 |  * Insert or remove block. | 
 | 153 |  */ | 
 | 154 | int dm_thin_insert_block(struct dm_thin_device *td, dm_block_t block, | 
 | 155 | 			 dm_block_t data_block); | 
 | 156 |  | 
 | 157 | int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block); | 
 | 158 |  | 
 | 159 | /* | 
 | 160 |  * Queries. | 
 | 161 |  */ | 
| Joe Thornber | 40db5a5 | 2012-07-27 15:08:14 +0100 | [diff] [blame] | 162 | bool dm_thin_changed_this_transaction(struct dm_thin_device *td); | 
 | 163 |  | 
| Joe Thornber | da105ed | 2012-07-27 15:08:15 +0100 | [diff] [blame] | 164 | bool dm_thin_aborted_changes(struct dm_thin_device *td); | 
 | 165 |  | 
| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 166 | int dm_thin_get_highest_mapped_block(struct dm_thin_device *td, | 
 | 167 | 				     dm_block_t *highest_mapped); | 
 | 168 |  | 
 | 169 | int dm_thin_get_mapped_count(struct dm_thin_device *td, dm_block_t *result); | 
 | 170 |  | 
 | 171 | int dm_pool_get_free_block_count(struct dm_pool_metadata *pmd, | 
 | 172 | 				 dm_block_t *result); | 
 | 173 |  | 
 | 174 | int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd, | 
 | 175 | 					  dm_block_t *result); | 
 | 176 |  | 
 | 177 | int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd, | 
 | 178 | 				  dm_block_t *result); | 
 | 179 |  | 
 | 180 | int dm_pool_get_data_block_size(struct dm_pool_metadata *pmd, sector_t *result); | 
 | 181 |  | 
 | 182 | int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result); | 
 | 183 |  | 
 | 184 | /* | 
 | 185 |  * Returns -ENOSPC if the new size is too small and already allocated | 
 | 186 |  * blocks would be lost. | 
 | 187 |  */ | 
 | 188 | int dm_pool_resize_data_dev(struct dm_pool_metadata *pmd, dm_block_t new_size); | 
| Joe Thornber | 24347e9 | 2013-05-10 14:37:19 +0100 | [diff] [blame] | 189 | int dm_pool_resize_metadata_dev(struct dm_pool_metadata *pmd, dm_block_t new_size); | 
| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 190 |  | 
| Joe Thornber | 12ba58a | 2012-07-27 15:08:15 +0100 | [diff] [blame] | 191 | /* | 
 | 192 |  * Flicks the underlying block manager into read only mode, so you know | 
 | 193 |  * that nothing is changing. | 
 | 194 |  */ | 
 | 195 | void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd); | 
 | 196 |  | 
| Joe Thornber | ac8c3f3 | 2013-05-10 14:37:21 +0100 | [diff] [blame] | 197 | int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd, | 
 | 198 | 					dm_block_t threshold, | 
 | 199 | 					dm_sm_threshold_fn fn, | 
 | 200 | 					void *context); | 
 | 201 |  | 
| Joe Thornber | 991d9fa0 | 2011-10-31 20:21:18 +0000 | [diff] [blame] | 202 | /*----------------------------------------------------------------*/ | 
 | 203 |  | 
 | 204 | #endif |