aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-cache-metadata.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-cache-metadata.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-cache-metadata.c')
-rw-r--r--drivers/md/dm-cache-metadata.c60
1 files changed, 38 insertions, 22 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}