Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Joe Thornber and committed by
Mike Snitzer
5a32083d a9d45396

+129 -83
+38 -22
drivers/md/dm-cache-metadata.c
··· 120 120 unsigned policy_version[CACHE_POLICY_VERSION_SIZE]; 121 121 size_t policy_hint_size; 122 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 /*------------------------------------------------------------------- ··· 266 260 } 267 261 } 268 262 263 + static int __save_sm_root(struct dm_cache_metadata *cmd) 264 + { 265 + int r; 266 + size_t metadata_len; 267 + 268 + r = dm_sm_root_size(cmd->metadata_sm, &metadata_len); 269 + if (r < 0) 270 + return r; 271 + 272 + return dm_sm_copy_root(cmd->metadata_sm, &cmd->metadata_space_map_root, 273 + metadata_len); 274 + } 275 + 276 + static void __copy_sm_root(struct dm_cache_metadata *cmd, 277 + struct cache_disk_superblock *disk_super) 278 + { 279 + memcpy(&disk_super->metadata_space_map_root, 280 + &cmd->metadata_space_map_root, 281 + sizeof(cmd->metadata_space_map_root)); 282 + } 283 + 269 284 static int __write_initial_superblock(struct dm_cache_metadata *cmd) 270 285 { 271 286 int r; 272 287 struct dm_block *sblock; 273 - size_t metadata_len; 274 288 struct cache_disk_superblock *disk_super; 275 289 sector_t bdev_size = i_size_read(cmd->bdev->bd_inode) >> SECTOR_SHIFT; 276 290 ··· 298 272 if (bdev_size > DM_CACHE_METADATA_MAX_SECTORS) 299 273 bdev_size = DM_CACHE_METADATA_MAX_SECTORS; 300 274 301 - r = dm_sm_root_size(cmd->metadata_sm, &metadata_len); 275 + r = dm_tm_pre_commit(cmd->tm); 302 276 if (r < 0) 303 277 return r; 304 278 305 - r = dm_tm_pre_commit(cmd->tm); 306 - if (r < 0) 279 + /* 280 + * dm_sm_copy_root() can fail. So we need to do it before we start 281 + * updating the superblock. 282 + */ 283 + r = __save_sm_root(cmd); 284 + if (r) 307 285 return r; 308 286 309 287 r = superblock_lock_zero(cmd, &sblock); ··· 323 293 memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version)); 324 294 disk_super->policy_hint_size = 0; 325 295 326 - r = dm_sm_copy_root(cmd->metadata_sm, &disk_super->metadata_space_map_root, 327 - metadata_len); 328 - if (r < 0) 329 - goto bad_locked; 296 + __copy_sm_root(cmd, disk_super); 330 297 331 298 disk_super->mapping_root = cpu_to_le64(cmd->root); 332 299 disk_super->hint_root = cpu_to_le64(cmd->hint_root); ··· 340 313 disk_super->write_misses = cpu_to_le32(0); 341 314 342 315 return dm_tm_commit(cmd->tm, sblock); 343 - 344 - bad_locked: 345 - dm_bm_unlock(sblock); 346 - return r; 347 316 } 348 317 349 318 static int __format_metadata(struct dm_cache_metadata *cmd) ··· 583 560 flags_mutator mutator) 584 561 { 585 562 int r; 586 - size_t metadata_len; 587 563 struct cache_disk_superblock *disk_super; 588 564 struct dm_block *sblock; 589 565 ··· 600 578 if (r < 0) 601 579 return r; 602 580 603 - r = dm_sm_root_size(cmd->metadata_sm, &metadata_len); 604 - if (r < 0) 581 + r = __save_sm_root(cmd); 582 + if (r) 605 583 return r; 606 584 607 585 r = superblock_lock(cmd, &sblock); ··· 628 606 disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses); 629 607 disk_super->write_hits = cpu_to_le32(cmd->stats.write_hits); 630 608 disk_super->write_misses = cpu_to_le32(cmd->stats.write_misses); 631 - 632 - r = dm_sm_copy_root(cmd->metadata_sm, &disk_super->metadata_space_map_root, 633 - metadata_len); 634 - if (r < 0) { 635 - dm_bm_unlock(sblock); 636 - return r; 637 - } 609 + __copy_sm_root(cmd, disk_super); 638 610 639 611 return dm_tm_commit(cmd->tm, sblock); 640 612 }
+42 -26
drivers/md/dm-era-target.c
··· 289 289 * A flag that is set whenever a writeset has been archived. 290 290 */ 291 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 294 300 static int superblock_read_lock(struct era_metadata *md, ··· 459 453 return r; 460 454 } 461 455 456 + static int save_sm_root(struct era_metadata *md) 457 + { 458 + int r; 459 + size_t metadata_len; 460 + 461 + r = dm_sm_root_size(md->sm, &metadata_len); 462 + if (r < 0) 463 + return r; 464 + 465 + return dm_sm_copy_root(md->sm, &md->metadata_space_map_root, 466 + metadata_len); 467 + } 468 + 469 + static void copy_sm_root(struct era_metadata *md, struct superblock_disk *disk) 470 + { 471 + memcpy(&disk->metadata_space_map_root, 472 + &md->metadata_space_map_root, 473 + sizeof(md->metadata_space_map_root)); 474 + } 475 + 462 476 /* 463 477 * Writes a superblock, including the static fields that don't get updated 464 478 * with every commit (possible optimisation here). 'md' should be fully 465 479 * constructed when this is called. 466 480 */ 467 - static int prepare_superblock(struct era_metadata *md, struct superblock_disk *disk) 481 + static void prepare_superblock(struct era_metadata *md, struct superblock_disk *disk) 468 482 { 469 - int r; 470 - size_t metadata_len; 471 - 472 483 disk->magic = cpu_to_le64(SUPERBLOCK_MAGIC); 473 484 disk->flags = cpu_to_le32(0ul); 474 485 ··· 493 470 memset(disk->uuid, 0, sizeof(disk->uuid)); 494 471 disk->version = cpu_to_le32(MAX_ERA_VERSION); 495 472 496 - r = dm_sm_root_size(md->sm, &metadata_len); 497 - if (r < 0) 498 - return r; 499 - 500 - r = dm_sm_copy_root(md->sm, &disk->metadata_space_map_root, 501 - metadata_len); 502 - if (r < 0) 503 - return r; 473 + copy_sm_root(md, disk); 504 474 505 475 disk->data_block_size = cpu_to_le32(md->block_size); 506 476 disk->metadata_block_size = cpu_to_le32(DM_ERA_METADATA_BLOCK_SIZE >> SECTOR_SHIFT); ··· 504 488 disk->writeset_tree_root = cpu_to_le64(md->writeset_tree_root); 505 489 disk->era_array_root = cpu_to_le64(md->era_array_root); 506 490 disk->metadata_snap = cpu_to_le64(md->metadata_snap); 507 - 508 - return 0; 509 491 } 510 492 511 493 static int write_superblock(struct era_metadata *md) ··· 512 498 struct dm_block *sblock; 513 499 struct superblock_disk *disk; 514 500 501 + r = save_sm_root(md); 502 + if (r) { 503 + DMERR("%s: save_sm_root failed", __func__); 504 + return r; 505 + } 506 + 515 507 r = superblock_lock_zero(md, &sblock); 516 508 if (r) 517 509 return r; 518 510 519 511 disk = dm_block_data(sblock); 520 - r = prepare_superblock(md, disk); 521 - if (r) { 522 - DMERR("%s: prepare_superblock failed", __func__); 523 - dm_bm_unlock(sblock); /* FIXME: does this commit? */ 524 - return r; 525 - } 512 + prepare_superblock(md, disk); 526 513 527 514 return dm_tm_commit(md->tm, sblock); 528 515 } ··· 957 942 } 958 943 } 959 944 945 + r = save_sm_root(md); 946 + if (r) { 947 + DMERR("%s: save_sm_root failed", __func__); 948 + return r; 949 + } 950 + 960 951 r = dm_tm_pre_commit(md->tm); 961 952 if (r) { 962 953 DMERR("%s: pre commit failed", __func__); ··· 975 954 return r; 976 955 } 977 956 978 - r = prepare_superblock(md, dm_block_data(sblock)); 979 - if (r) { 980 - DMERR("%s: prepare_superblock failed", __func__); 981 - dm_bm_unlock(sblock); /* FIXME: does this commit? */ 982 - return r; 983 - } 957 + prepare_superblock(md, dm_block_data(sblock)); 984 958 985 959 return dm_tm_commit(md->tm, sblock); 986 960 }
+49 -35
drivers/md/dm-thin-metadata.c
··· 192 192 * operation possible in this state is the closing of the device. 193 193 */ 194 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 197 204 struct dm_thin_device { ··· 438 431 pmd->details_info.value_type.equal = NULL; 439 432 } 440 433 434 + static int save_sm_roots(struct dm_pool_metadata *pmd) 435 + { 436 + int r; 437 + size_t len; 438 + 439 + r = dm_sm_root_size(pmd->metadata_sm, &len); 440 + if (r < 0) 441 + return r; 442 + 443 + r = dm_sm_copy_root(pmd->metadata_sm, &pmd->metadata_space_map_root, len); 444 + if (r < 0) 445 + return r; 446 + 447 + r = dm_sm_root_size(pmd->data_sm, &len); 448 + if (r < 0) 449 + return r; 450 + 451 + return dm_sm_copy_root(pmd->data_sm, &pmd->data_space_map_root, len); 452 + } 453 + 454 + static void copy_sm_roots(struct dm_pool_metadata *pmd, 455 + struct thin_disk_superblock *disk) 456 + { 457 + memcpy(&disk->metadata_space_map_root, 458 + &pmd->metadata_space_map_root, 459 + sizeof(pmd->metadata_space_map_root)); 460 + 461 + memcpy(&disk->data_space_map_root, 462 + &pmd->data_space_map_root, 463 + sizeof(pmd->data_space_map_root)); 464 + } 465 + 441 466 static int __write_initial_superblock(struct dm_pool_metadata *pmd) 442 467 { 443 468 int r; 444 469 struct dm_block *sblock; 445 - size_t metadata_len, data_len; 446 470 struct thin_disk_superblock *disk_super; 447 471 sector_t bdev_size = i_size_read(pmd->bdev->bd_inode) >> SECTOR_SHIFT; 448 472 449 473 if (bdev_size > THIN_METADATA_MAX_SECTORS) 450 474 bdev_size = THIN_METADATA_MAX_SECTORS; 451 475 452 - r = dm_sm_root_size(pmd->metadata_sm, &metadata_len); 453 - if (r < 0) 454 - return r; 455 - 456 - r = dm_sm_root_size(pmd->data_sm, &data_len); 457 - if (r < 0) 458 - return r; 459 - 460 476 r = dm_sm_commit(pmd->data_sm); 477 + if (r < 0) 478 + return r; 479 + 480 + r = save_sm_roots(pmd); 461 481 if (r < 0) 462 482 return r; 463 483 ··· 505 471 disk_super->trans_id = 0; 506 472 disk_super->held_root = 0; 507 473 508 - r = dm_sm_copy_root(pmd->metadata_sm, &disk_super->metadata_space_map_root, 509 - metadata_len); 510 - if (r < 0) 511 - goto bad_locked; 512 - 513 - r = dm_sm_copy_root(pmd->data_sm, &disk_super->data_space_map_root, 514 - data_len); 515 - if (r < 0) 516 - goto bad_locked; 474 + copy_sm_roots(pmd, disk_super); 517 475 518 476 disk_super->data_mapping_root = cpu_to_le64(pmd->root); 519 477 disk_super->device_details_root = cpu_to_le64(pmd->details_root); ··· 514 488 disk_super->data_block_size = cpu_to_le32(pmd->data_block_size); 515 489 516 490 return dm_tm_commit(pmd->tm, sblock); 517 - 518 - bad_locked: 519 - dm_bm_unlock(sblock); 520 - return r; 521 491 } 522 492 523 493 static int __format_metadata(struct dm_pool_metadata *pmd) ··· 791 769 if (r < 0) 792 770 return r; 793 771 772 + r = save_sm_roots(pmd); 773 + if (r < 0) 774 + return r; 775 + 794 776 r = superblock_lock(pmd, &sblock); 795 777 if (r) 796 778 return r; ··· 806 780 disk_super->trans_id = cpu_to_le64(pmd->trans_id); 807 781 disk_super->flags = cpu_to_le32(pmd->flags); 808 782 809 - r = dm_sm_copy_root(pmd->metadata_sm, &disk_super->metadata_space_map_root, 810 - metadata_len); 811 - if (r < 0) 812 - goto out_locked; 813 - 814 - r = dm_sm_copy_root(pmd->data_sm, &disk_super->data_space_map_root, 815 - data_len); 816 - if (r < 0) 817 - goto out_locked; 783 + copy_sm_roots(pmd, disk_super); 818 784 819 785 return dm_tm_commit(pmd->tm, sblock); 820 - 821 - out_locked: 822 - dm_bm_unlock(sblock); 823 - return r; 824 786 } 825 787 826 788 struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev,