aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-era-target.c
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/md/dm-era-target.c
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/md/dm-era-target.c')
-rw-r--r--drivers/md/dm-era-target.c68
1 files changed, 42 insertions, 26 deletions
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}