diff options
Diffstat (limited to 'drivers/md/persistent-data/dm-space-map-metadata.c')
| -rw-r--r-- | drivers/md/persistent-data/dm-space-map-metadata.c | 115 |
1 files changed, 94 insertions, 21 deletions
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c index 536782e3bcb7..786b689bdfc7 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.c +++ b/drivers/md/persistent-data/dm-space-map-metadata.c | |||
| @@ -91,6 +91,69 @@ struct block_op { | |||
| 91 | dm_block_t block; | 91 | dm_block_t block; |
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | struct bop_ring_buffer { | ||
| 95 | unsigned begin; | ||
| 96 | unsigned end; | ||
| 97 | struct block_op bops[MAX_RECURSIVE_ALLOCATIONS + 1]; | ||
| 98 | }; | ||
| 99 | |||
| 100 | static void brb_init(struct bop_ring_buffer *brb) | ||
| 101 | { | ||
| 102 | brb->begin = 0; | ||
| 103 | brb->end = 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | static bool brb_empty(struct bop_ring_buffer *brb) | ||
| 107 | { | ||
| 108 | return brb->begin == brb->end; | ||
| 109 | } | ||
| 110 | |||
| 111 | static unsigned brb_next(struct bop_ring_buffer *brb, unsigned old) | ||
| 112 | { | ||
| 113 | unsigned r = old + 1; | ||
| 114 | return (r >= (sizeof(brb->bops) / sizeof(*brb->bops))) ? 0 : r; | ||
| 115 | } | ||
| 116 | |||
| 117 | static int brb_push(struct bop_ring_buffer *brb, | ||
| 118 | enum block_op_type type, dm_block_t b) | ||
| 119 | { | ||
| 120 | struct block_op *bop; | ||
| 121 | unsigned next = brb_next(brb, brb->end); | ||
| 122 | |||
| 123 | /* | ||
| 124 | * We don't allow the last bop to be filled, this way we can | ||
| 125 | * differentiate between full and empty. | ||
| 126 | */ | ||
| 127 | if (next == brb->begin) | ||
| 128 | return -ENOMEM; | ||
| 129 | |||
| 130 | bop = brb->bops + brb->end; | ||
| 131 | bop->type = type; | ||
| 132 | bop->block = b; | ||
| 133 | |||
| 134 | brb->end = next; | ||
| 135 | |||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result) | ||
| 140 | { | ||
| 141 | struct block_op *bop; | ||
| 142 | |||
| 143 | if (brb_empty(brb)) | ||
| 144 | return -ENODATA; | ||
| 145 | |||
| 146 | bop = brb->bops + brb->begin; | ||
| 147 | result->type = bop->type; | ||
| 148 | result->block = bop->block; | ||
| 149 | |||
| 150 | brb->begin = brb_next(brb, brb->begin); | ||
| 151 | |||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 155 | /*----------------------------------------------------------------*/ | ||
| 156 | |||
| 94 | struct sm_metadata { | 157 | struct sm_metadata { |
| 95 | struct dm_space_map sm; | 158 | struct dm_space_map sm; |
| 96 | 159 | ||
| @@ -101,25 +164,20 @@ struct sm_metadata { | |||
| 101 | 164 | ||
| 102 | unsigned recursion_count; | 165 | unsigned recursion_count; |
| 103 | unsigned allocated_this_transaction; | 166 | unsigned allocated_this_transaction; |
| 104 | unsigned nr_uncommitted; | 167 | struct bop_ring_buffer uncommitted; |
| 105 | struct block_op uncommitted[MAX_RECURSIVE_ALLOCATIONS]; | ||
| 106 | 168 | ||
| 107 | struct threshold threshold; | 169 | struct threshold threshold; |
| 108 | }; | 170 | }; |
| 109 | 171 | ||
| 110 | static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b) | 172 | static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b) |
| 111 | { | 173 | { |
| 112 | struct block_op *op; | 174 | int r = brb_push(&smm->uncommitted, type, b); |
| 113 | 175 | ||
| 114 | if (smm->nr_uncommitted == MAX_RECURSIVE_ALLOCATIONS) { | 176 | if (r) { |
| 115 | DMERR("too many recursive allocations"); | 177 | DMERR("too many recursive allocations"); |
| 116 | return -ENOMEM; | 178 | return -ENOMEM; |
| 117 | } | 179 | } |
| 118 | 180 | ||
| 119 | op = smm->uncommitted + smm->nr_uncommitted++; | ||
| 120 | op->type = type; | ||
| 121 | op->block = b; | ||
| 122 | |||
| 123 | return 0; | 181 | return 0; |
| 124 | } | 182 | } |
| 125 | 183 | ||
| @@ -158,11 +216,17 @@ static int out(struct sm_metadata *smm) | |||
| 158 | return -ENOMEM; | 216 | return -ENOMEM; |
| 159 | } | 217 | } |
| 160 | 218 | ||
| 161 | if (smm->recursion_count == 1 && smm->nr_uncommitted) { | 219 | if (smm->recursion_count == 1) { |
| 162 | while (smm->nr_uncommitted && !r) { | 220 | while (!brb_empty(&smm->uncommitted)) { |
| 163 | smm->nr_uncommitted--; | 221 | struct block_op bop; |
| 164 | r = commit_bop(smm, smm->uncommitted + | 222 | |
| 165 | smm->nr_uncommitted); | 223 | r = brb_pop(&smm->uncommitted, &bop); |
| 224 | if (r) { | ||
| 225 | DMERR("bug in bop ring buffer"); | ||
| 226 | break; | ||
| 227 | } | ||
| 228 | |||
| 229 | r = commit_bop(smm, &bop); | ||
| 166 | if (r) | 230 | if (r) |
| 167 | break; | 231 | break; |
| 168 | } | 232 | } |
| @@ -217,7 +281,8 @@ static int sm_metadata_get_nr_free(struct dm_space_map *sm, dm_block_t *count) | |||
| 217 | static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b, | 281 | static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b, |
| 218 | uint32_t *result) | 282 | uint32_t *result) |
| 219 | { | 283 | { |
| 220 | int r, i; | 284 | int r; |
| 285 | unsigned i; | ||
| 221 | struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); | 286 | struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); |
| 222 | unsigned adjustment = 0; | 287 | unsigned adjustment = 0; |
| 223 | 288 | ||
| @@ -225,8 +290,10 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b, | |||
| 225 | * We may have some uncommitted adjustments to add. This list | 290 | * We may have some uncommitted adjustments to add. This list |
| 226 | * should always be really short. | 291 | * should always be really short. |
| 227 | */ | 292 | */ |
| 228 | for (i = 0; i < smm->nr_uncommitted; i++) { | 293 | for (i = smm->uncommitted.begin; |
| 229 | struct block_op *op = smm->uncommitted + i; | 294 | i != smm->uncommitted.end; |
| 295 | i = brb_next(&smm->uncommitted, i)) { | ||
| 296 | struct block_op *op = smm->uncommitted.bops + i; | ||
| 230 | 297 | ||
| 231 | if (op->block != b) | 298 | if (op->block != b) |
| 232 | continue; | 299 | continue; |
| @@ -254,7 +321,8 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b, | |||
| 254 | static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm, | 321 | static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm, |
| 255 | dm_block_t b, int *result) | 322 | dm_block_t b, int *result) |
| 256 | { | 323 | { |
| 257 | int r, i, adjustment = 0; | 324 | int r, adjustment = 0; |
| 325 | unsigned i; | ||
| 258 | struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); | 326 | struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); |
| 259 | uint32_t rc; | 327 | uint32_t rc; |
| 260 | 328 | ||
| @@ -262,8 +330,11 @@ static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm, | |||
| 262 | * We may have some uncommitted adjustments to add. This list | 330 | * We may have some uncommitted adjustments to add. This list |
| 263 | * should always be really short. | 331 | * should always be really short. |
| 264 | */ | 332 | */ |
| 265 | for (i = 0; i < smm->nr_uncommitted; i++) { | 333 | for (i = smm->uncommitted.begin; |
| 266 | struct block_op *op = smm->uncommitted + i; | 334 | i != smm->uncommitted.end; |
| 335 | i = brb_next(&smm->uncommitted, i)) { | ||
| 336 | |||
| 337 | struct block_op *op = smm->uncommitted.bops + i; | ||
| 267 | 338 | ||
| 268 | if (op->block != b) | 339 | if (op->block != b) |
| 269 | continue; | 340 | continue; |
| @@ -671,7 +742,7 @@ int dm_sm_metadata_create(struct dm_space_map *sm, | |||
| 671 | smm->begin = superblock + 1; | 742 | smm->begin = superblock + 1; |
| 672 | smm->recursion_count = 0; | 743 | smm->recursion_count = 0; |
| 673 | smm->allocated_this_transaction = 0; | 744 | smm->allocated_this_transaction = 0; |
| 674 | smm->nr_uncommitted = 0; | 745 | brb_init(&smm->uncommitted); |
| 675 | threshold_init(&smm->threshold); | 746 | threshold_init(&smm->threshold); |
| 676 | 747 | ||
| 677 | memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm)); | 748 | memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm)); |
| @@ -680,6 +751,8 @@ int dm_sm_metadata_create(struct dm_space_map *sm, | |||
| 680 | if (r) | 751 | if (r) |
| 681 | return r; | 752 | return r; |
| 682 | 753 | ||
| 754 | if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS) | ||
| 755 | nr_blocks = DM_SM_METADATA_MAX_BLOCKS; | ||
| 683 | r = sm_ll_extend(&smm->ll, nr_blocks); | 756 | r = sm_ll_extend(&smm->ll, nr_blocks); |
| 684 | if (r) | 757 | if (r) |
| 685 | return r; | 758 | return r; |
| @@ -713,7 +786,7 @@ int dm_sm_metadata_open(struct dm_space_map *sm, | |||
| 713 | smm->begin = 0; | 786 | smm->begin = 0; |
| 714 | smm->recursion_count = 0; | 787 | smm->recursion_count = 0; |
| 715 | smm->allocated_this_transaction = 0; | 788 | smm->allocated_this_transaction = 0; |
| 716 | smm->nr_uncommitted = 0; | 789 | brb_init(&smm->uncommitted); |
| 717 | threshold_init(&smm->threshold); | 790 | threshold_init(&smm->threshold); |
| 718 | 791 | ||
| 719 | memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll)); | 792 | memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll)); |
