aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJoe Thornber <ejt@redhat.com>2014-03-27 10:13:23 -0400
committerMike Snitzer <snitzer@redhat.com>2014-03-27 16:56:23 -0400
commit5a32083d03fb543f63489b2946c4948398579ba0 (patch)
tree4b14059d093b846876fa1203f31c0e31f23bcfe1 /drivers
parenta9d45396f5956d0b615c7ae3b936afd888351a47 (diff)
dm: take care to copy the space map roots before locking the superblock
In theory copying the space map root can fail, but in practice it never does because we're careful to check what size buffer is needed. But make certain we're able to copy the space map roots before locking the superblock. Signed-off-by: Joe Thornber <ejt@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com> Cc: stable@vger.kernel.org # drop dm-era and dm-cache changes as needed
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/dm-cache-metadata.c60
-rw-r--r--drivers/md/dm-era-target.c68
-rw-r--r--drivers/md/dm-thin-metadata.c80
3 files changed, 127 insertions, 81 deletions
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index 4b73abe9323f..66f102ab102c 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -120,6 +120,12 @@ struct dm_cache_metadata {
120 unsigned policy_version[CACHE_POLICY_VERSION_SIZE]; 120 unsigned policy_version[CACHE_POLICY_VERSION_SIZE];
121 size_t policy_hint_size; 121 size_t policy_hint_size;
122 struct dm_cache_statistics stats; 122 struct dm_cache_statistics stats;
123
124 /*
125 * Reading the space map root can fail, so we read it into this
126 * buffer before the superblock is locked and updated.
127 */
128 __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE];
123}; 129};
124 130
125/*------------------------------------------------------------------- 131/*-------------------------------------------------------------------
@@ -260,11 +266,31 @@ static void __setup_mapping_info(struct dm_cache_metadata *cmd)
260 } 266 }
261} 267}
262 268
269static int __save_sm_root(struct dm_cache_metadata *cmd)
270{
271 int r;
272 size_t metadata_len;
273
274 r = dm_sm_root_size(cmd->metadata_sm, &metadata_len);
275 if (r < 0)
276 return r;
277
278 return dm_sm_copy_root(cmd->metadata_sm, &cmd->metadata_space_map_root,
279 metadata_len);
280}
281
282static void __copy_sm_root(struct dm_cache_metadata *cmd,
283 struct cache_disk_superblock *disk_super)
284{
285 memcpy(&disk_super->metadata_space_map_root,
286 &cmd->metadata_space_map_root,
287 sizeof(cmd->metadata_space_map_root));
288}
289
263static int __write_initial_superblock(struct dm_cache_metadata *cmd) 290static int __write_initial_superblock(struct dm_cache_metadata *cmd)
264{ 291{
265 int r; 292 int r;
266 struct dm_block *sblock; 293 struct dm_block *sblock;
267 size_t metadata_len;
268 struct cache_disk_superblock *disk_super; 294 struct cache_disk_superblock *disk_super;
269 sector_t bdev_size = i_size_read(cmd->bdev->bd_inode) >> SECTOR_SHIFT; 295 sector_t bdev_size = i_size_read(cmd->bdev->bd_inode) >> SECTOR_SHIFT;
270 296
@@ -272,12 +298,16 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd)
272 if (bdev_size > DM_CACHE_METADATA_MAX_SECTORS) 298 if (bdev_size > DM_CACHE_METADATA_MAX_SECTORS)
273 bdev_size = DM_CACHE_METADATA_MAX_SECTORS; 299 bdev_size = DM_CACHE_METADATA_MAX_SECTORS;
274 300
275 r = dm_sm_root_size(cmd->metadata_sm, &metadata_len); 301 r = dm_tm_pre_commit(cmd->tm);
276 if (r < 0) 302 if (r < 0)
277 return r; 303 return r;
278 304
279 r = dm_tm_pre_commit(cmd->tm); 305 /*
280 if (r < 0) 306 * dm_sm_copy_root() can fail. So we need to do it before we start
307 * updating the superblock.
308 */
309 r = __save_sm_root(cmd);
310 if (r)
281 return r; 311 return r;
282 312
283 r = superblock_lock_zero(cmd, &sblock); 313 r = superblock_lock_zero(cmd, &sblock);
@@ -293,10 +323,7 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd)
293 memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version)); 323 memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version));
294 disk_super->policy_hint_size = 0; 324 disk_super->policy_hint_size = 0;
295 325
296 r = dm_sm_copy_root(cmd->metadata_sm, &disk_super->metadata_space_map_root, 326 __copy_sm_root(cmd, disk_super);
297 metadata_len);
298 if (r < 0)
299 goto bad_locked;
300 327
301 disk_super->mapping_root = cpu_to_le64(cmd->root); 328 disk_super->mapping_root = cpu_to_le64(cmd->root);
302 disk_super->hint_root = cpu_to_le64(cmd->hint_root); 329 disk_super->hint_root = cpu_to_le64(cmd->hint_root);
@@ -313,10 +340,6 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd)
313 disk_super->write_misses = cpu_to_le32(0); 340 disk_super->write_misses = cpu_to_le32(0);
314 341
315 return dm_tm_commit(cmd->tm, sblock); 342 return dm_tm_commit(cmd->tm, sblock);
316
317bad_locked:
318 dm_bm_unlock(sblock);
319 return r;
320} 343}
321 344
322static int __format_metadata(struct dm_cache_metadata *cmd) 345static int __format_metadata(struct dm_cache_metadata *cmd)
@@ -560,7 +583,6 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
560 flags_mutator mutator) 583 flags_mutator mutator)
561{ 584{
562 int r; 585 int r;
563 size_t metadata_len;
564 struct cache_disk_superblock *disk_super; 586 struct cache_disk_superblock *disk_super;
565 struct dm_block *sblock; 587 struct dm_block *sblock;
566 588
@@ -578,8 +600,8 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
578 if (r < 0) 600 if (r < 0)
579 return r; 601 return r;
580 602
581 r = dm_sm_root_size(cmd->metadata_sm, &metadata_len); 603 r = __save_sm_root(cmd);
582 if (r < 0) 604 if (r)
583 return r; 605 return r;
584 606
585 r = superblock_lock(cmd, &sblock); 607 r = superblock_lock(cmd, &sblock);
@@ -606,13 +628,7 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
606 disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses); 628 disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses);
607 disk_super->write_hits = cpu_to_le32(cmd->stats.write_hits); 629 disk_super->write_hits = cpu_to_le32(cmd->stats.write_hits);
608 disk_super->write_misses = cpu_to_le32(cmd->stats.write_misses); 630 disk_super->write_misses = cpu_to_le32(cmd->stats.write_misses);
609 631 __copy_sm_root(cmd, disk_super);
610 r = dm_sm_copy_root(cmd->metadata_sm, &disk_super->metadata_space_map_root,
611 metadata_len);
612 if (r < 0) {
613 dm_bm_unlock(sblock);
614 return r;
615 }
616 632
617 return dm_tm_commit(cmd->tm, sblock); 633 return dm_tm_commit(cmd->tm, sblock);
618} 634}
diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c
index 03d9560bfd95..414dad4cb49b 100644
--- a/drivers/md/dm-era-target.c
+++ b/drivers/md/dm-era-target.c
@@ -289,6 +289,12 @@ struct era_metadata {
289 * A flag that is set whenever a writeset has been archived. 289 * A flag that is set whenever a writeset has been archived.
290 */ 290 */
291 bool archived_writesets; 291 bool archived_writesets;
292
293 /*
294 * Reading the space map root can fail, so we read it into this
295 * buffer before the superblock is locked and updated.
296 */
297 __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE];
292}; 298};
293 299
294static int superblock_read_lock(struct era_metadata *md, 300static int superblock_read_lock(struct era_metadata *md,
@@ -453,16 +459,33 @@ bad:
453 return r; 459 return r;
454} 460}
455 461
462static int save_sm_root(struct era_metadata *md)
463{
464 int r;
465 size_t metadata_len;
466
467 r = dm_sm_root_size(md->sm, &metadata_len);
468 if (r < 0)
469 return r;
470
471 return dm_sm_copy_root(md->sm, &md->metadata_space_map_root,
472 metadata_len);
473}
474
475static void copy_sm_root(struct era_metadata *md, struct superblock_disk *disk)
476{
477 memcpy(&disk->metadata_space_map_root,
478 &md->metadata_space_map_root,
479 sizeof(md->metadata_space_map_root));
480}
481
456/* 482/*
457 * Writes a superblock, including the static fields that don't get updated 483 * Writes a superblock, including the static fields that don't get updated
458 * with every commit (possible optimisation here). 'md' should be fully 484 * with every commit (possible optimisation here). 'md' should be fully
459 * constructed when this is called. 485 * constructed when this is called.
460 */ 486 */
461static int prepare_superblock(struct era_metadata *md, struct superblock_disk *disk) 487static void prepare_superblock(struct era_metadata *md, struct superblock_disk *disk)
462{ 488{
463 int r;
464 size_t metadata_len;
465
466 disk->magic = cpu_to_le64(SUPERBLOCK_MAGIC); 489 disk->magic = cpu_to_le64(SUPERBLOCK_MAGIC);
467 disk->flags = cpu_to_le32(0ul); 490 disk->flags = cpu_to_le32(0ul);
468 491
@@ -470,14 +493,7 @@ static int prepare_superblock(struct era_metadata *md, struct superblock_disk *d
470 memset(disk->uuid, 0, sizeof(disk->uuid)); 493 memset(disk->uuid, 0, sizeof(disk->uuid));
471 disk->version = cpu_to_le32(MAX_ERA_VERSION); 494 disk->version = cpu_to_le32(MAX_ERA_VERSION);
472 495
473 r = dm_sm_root_size(md->sm, &metadata_len); 496 copy_sm_root(md, disk);
474 if (r < 0)
475 return r;
476
477 r = dm_sm_copy_root(md->sm, &disk->metadata_space_map_root,
478 metadata_len);
479 if (r < 0)
480 return r;
481 497
482 disk->data_block_size = cpu_to_le32(md->block_size); 498 disk->data_block_size = cpu_to_le32(md->block_size);
483 disk->metadata_block_size = cpu_to_le32(DM_ERA_METADATA_BLOCK_SIZE >> SECTOR_SHIFT); 499 disk->metadata_block_size = cpu_to_le32(DM_ERA_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
@@ -488,8 +504,6 @@ static int prepare_superblock(struct era_metadata *md, struct superblock_disk *d
488 disk->writeset_tree_root = cpu_to_le64(md->writeset_tree_root); 504 disk->writeset_tree_root = cpu_to_le64(md->writeset_tree_root);
489 disk->era_array_root = cpu_to_le64(md->era_array_root); 505 disk->era_array_root = cpu_to_le64(md->era_array_root);
490 disk->metadata_snap = cpu_to_le64(md->metadata_snap); 506 disk->metadata_snap = cpu_to_le64(md->metadata_snap);
491
492 return 0;
493} 507}
494 508
495static int write_superblock(struct era_metadata *md) 509static int write_superblock(struct era_metadata *md)
@@ -498,17 +512,18 @@ static int write_superblock(struct era_metadata *md)
498 struct dm_block *sblock; 512 struct dm_block *sblock;
499 struct superblock_disk *disk; 513 struct superblock_disk *disk;
500 514
515 r = save_sm_root(md);
516 if (r) {
517 DMERR("%s: save_sm_root failed", __func__);
518 return r;
519 }
520
501 r = superblock_lock_zero(md, &sblock); 521 r = superblock_lock_zero(md, &sblock);
502 if (r) 522 if (r)
503 return r; 523 return r;
504 524
505 disk = dm_block_data(sblock); 525 disk = dm_block_data(sblock);
506 r = prepare_superblock(md, disk); 526 prepare_superblock(md, disk);
507 if (r) {
508 DMERR("%s: prepare_superblock failed", __func__);
509 dm_bm_unlock(sblock); /* FIXME: does this commit? */
510 return r;
511 }
512 527
513 return dm_tm_commit(md->tm, sblock); 528 return dm_tm_commit(md->tm, sblock);
514} 529}
@@ -942,6 +957,12 @@ static int metadata_commit(struct era_metadata *md)
942 } 957 }
943 } 958 }
944 959
960 r = save_sm_root(md);
961 if (r) {
962 DMERR("%s: save_sm_root failed", __func__);
963 return r;
964 }
965
945 r = dm_tm_pre_commit(md->tm); 966 r = dm_tm_pre_commit(md->tm);
946 if (r) { 967 if (r) {
947 DMERR("%s: pre commit failed", __func__); 968 DMERR("%s: pre commit failed", __func__);
@@ -954,12 +975,7 @@ static int metadata_commit(struct era_metadata *md)
954 return r; 975 return r;
955 } 976 }
956 977
957 r = prepare_superblock(md, dm_block_data(sblock)); 978 prepare_superblock(md, dm_block_data(sblock));
958 if (r) {
959 DMERR("%s: prepare_superblock failed", __func__);
960 dm_bm_unlock(sblock); /* FIXME: does this commit? */
961 return r;
962 }
963 979
964 return dm_tm_commit(md->tm, sblock); 980 return dm_tm_commit(md->tm, sblock);
965} 981}
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index fb9efc829182..b086a945edcb 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -192,6 +192,13 @@ struct dm_pool_metadata {
192 * operation possible in this state is the closing of the device. 192 * operation possible in this state is the closing of the device.
193 */ 193 */
194 bool fail_io:1; 194 bool fail_io:1;
195
196 /*
197 * Reading the space map roots can fail, so we read it into these
198 * buffers before the superblock is locked and updated.
199 */
200 __u8 data_space_map_root[SPACE_MAP_ROOT_SIZE];
201 __u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE];
195}; 202};
196 203
197struct dm_thin_device { 204struct dm_thin_device {
@@ -431,26 +438,53 @@ static void __setup_btree_details(struct dm_pool_metadata *pmd)
431 pmd->details_info.value_type.equal = NULL; 438 pmd->details_info.value_type.equal = NULL;
432} 439}
433 440
441static int save_sm_roots(struct dm_pool_metadata *pmd)
442{
443 int r;
444 size_t len;
445
446 r = dm_sm_root_size(pmd->metadata_sm, &len);
447 if (r < 0)
448 return r;
449
450 r = dm_sm_copy_root(pmd->metadata_sm, &pmd->metadata_space_map_root, len);
451 if (r < 0)
452 return r;
453
454 r = dm_sm_root_size(pmd->data_sm, &len);
455 if (r < 0)
456 return r;
457
458 return dm_sm_copy_root(pmd->data_sm, &pmd->data_space_map_root, len);
459}
460
461static void copy_sm_roots(struct dm_pool_metadata *pmd,
462 struct thin_disk_superblock *disk)
463{
464 memcpy(&disk->metadata_space_map_root,
465 &pmd->metadata_space_map_root,
466 sizeof(pmd->metadata_space_map_root));
467
468 memcpy(&disk->data_space_map_root,
469 &pmd->data_space_map_root,
470 sizeof(pmd->data_space_map_root));
471}
472
434static int __write_initial_superblock(struct dm_pool_metadata *pmd) 473static int __write_initial_superblock(struct dm_pool_metadata *pmd)
435{ 474{
436 int r; 475 int r;
437 struct dm_block *sblock; 476 struct dm_block *sblock;
438 size_t metadata_len, data_len;
439 struct thin_disk_superblock *disk_super; 477 struct thin_disk_superblock *disk_super;
440 sector_t bdev_size = i_size_read(pmd->bdev->bd_inode) >> SECTOR_SHIFT; 478 sector_t bdev_size = i_size_read(pmd->bdev->bd_inode) >> SECTOR_SHIFT;
441 479
442 if (bdev_size > THIN_METADATA_MAX_SECTORS) 480 if (bdev_size > THIN_METADATA_MAX_SECTORS)
443 bdev_size = THIN_METADATA_MAX_SECTORS; 481 bdev_size = THIN_METADATA_MAX_SECTORS;
444 482
445 r = dm_sm_root_size(pmd->metadata_sm, &metadata_len); 483 r = dm_sm_commit(pmd->data_sm);
446 if (r < 0)
447 return r;
448
449 r = dm_sm_root_size(pmd->data_sm, &data_len);
450 if (r < 0) 484 if (r < 0)
451 return r; 485 return r;
452 486
453 r = dm_sm_commit(pmd->data_sm); 487 r = save_sm_roots(pmd);
454 if (r < 0) 488 if (r < 0)
455 return r; 489 return r;
456 490
@@ -471,15 +505,7 @@ static int __write_initial_superblock(struct dm_pool_metadata *pmd)
471 disk_super->trans_id = 0; 505 disk_super->trans_id = 0;
472 disk_super->held_root = 0; 506 disk_super->held_root = 0;
473 507
474 r = dm_sm_copy_root(pmd->metadata_sm, &disk_super->metadata_space_map_root, 508 copy_sm_roots(pmd, disk_super);
475 metadata_len);
476 if (r < 0)
477 goto bad_locked;
478
479 r = dm_sm_copy_root(pmd->data_sm, &disk_super->data_space_map_root,
480 data_len);
481 if (r < 0)
482 goto bad_locked;
483 509
484 disk_super->data_mapping_root = cpu_to_le64(pmd->root); 510 disk_super->data_mapping_root = cpu_to_le64(pmd->root);
485 disk_super->device_details_root = cpu_to_le64(pmd->details_root); 511 disk_super->device_details_root = cpu_to_le64(pmd->details_root);
@@ -488,10 +514,6 @@ static int __write_initial_superblock(struct dm_pool_metadata *pmd)
488 disk_super->data_block_size = cpu_to_le32(pmd->data_block_size); 514 disk_super->data_block_size = cpu_to_le32(pmd->data_block_size);
489 515
490 return dm_tm_commit(pmd->tm, sblock); 516 return dm_tm_commit(pmd->tm, sblock);
491
492bad_locked:
493 dm_bm_unlock(sblock);
494 return r;
495} 517}
496 518
497static int __format_metadata(struct dm_pool_metadata *pmd) 519static int __format_metadata(struct dm_pool_metadata *pmd)
@@ -769,6 +791,10 @@ static int __commit_transaction(struct dm_pool_metadata *pmd)
769 if (r < 0) 791 if (r < 0)
770 return r; 792 return r;
771 793
794 r = save_sm_roots(pmd);
795 if (r < 0)
796 return r;
797
772 r = superblock_lock(pmd, &sblock); 798 r = superblock_lock(pmd, &sblock);
773 if (r) 799 if (r)
774 return r; 800 return r;
@@ -780,21 +806,9 @@ static int __commit_transaction(struct dm_pool_metadata *pmd)
780 disk_super->trans_id = cpu_to_le64(pmd->trans_id); 806 disk_super->trans_id = cpu_to_le64(pmd->trans_id);
781 disk_super->flags = cpu_to_le32(pmd->flags); 807 disk_super->flags = cpu_to_le32(pmd->flags);
782 808
783 r = dm_sm_copy_root(pmd->metadata_sm, &disk_super->metadata_space_map_root, 809 copy_sm_roots(pmd, disk_super);
784 metadata_len);
785 if (r < 0)
786 goto out_locked;
787
788 r = dm_sm_copy_root(pmd->data_sm, &disk_super->data_space_map_root,
789 data_len);
790 if (r < 0)
791 goto out_locked;
792 810
793 return dm_tm_commit(pmd->tm, sblock); 811 return dm_tm_commit(pmd->tm, sblock);
794
795out_locked:
796 dm_bm_unlock(sblock);
797 return r;
798} 812}
799 813
800struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev, 814struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,