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
此提交包含在:
Joe Thornber
2014-03-27 14:13:23 +00:00
提交者 Mike Snitzer
父節點 a9d45396f5
當前提交 5a32083d03
共有 3 個檔案被更改,包括 129 行新增83 行删除

查看文件

@@ -120,6 +120,12 @@ struct dm_cache_metadata {
unsigned policy_version[CACHE_POLICY_VERSION_SIZE];
size_t policy_hint_size;
struct dm_cache_statistics stats;
/*
* Reading the space map root can fail, so we read it into this
* buffer before the superblock is locked and updated.
*/
__u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE];
};
/*-------------------------------------------------------------------
@@ -260,11 +266,31 @@ static void __setup_mapping_info(struct dm_cache_metadata *cmd)
}
}
static int __save_sm_root(struct dm_cache_metadata *cmd)
{
int r;
size_t metadata_len;
r = dm_sm_root_size(cmd->metadata_sm, &metadata_len);
if (r < 0)
return r;
return dm_sm_copy_root(cmd->metadata_sm, &cmd->metadata_space_map_root,
metadata_len);
}
static void __copy_sm_root(struct dm_cache_metadata *cmd,
struct cache_disk_superblock *disk_super)
{
memcpy(&disk_super->metadata_space_map_root,
&cmd->metadata_space_map_root,
sizeof(cmd->metadata_space_map_root));
}
static int __write_initial_superblock(struct dm_cache_metadata *cmd)
{
int r;
struct dm_block *sblock;
size_t metadata_len;
struct cache_disk_superblock *disk_super;
sector_t bdev_size = i_size_read(cmd->bdev->bd_inode) >> SECTOR_SHIFT;
@@ -272,12 +298,16 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd)
if (bdev_size > DM_CACHE_METADATA_MAX_SECTORS)
bdev_size = DM_CACHE_METADATA_MAX_SECTORS;
r = dm_sm_root_size(cmd->metadata_sm, &metadata_len);
r = dm_tm_pre_commit(cmd->tm);
if (r < 0)
return r;
r = dm_tm_pre_commit(cmd->tm);
if (r < 0)
/*
* dm_sm_copy_root() can fail. So we need to do it before we start
* updating the superblock.
*/
r = __save_sm_root(cmd);
if (r)
return r;
r = superblock_lock_zero(cmd, &sblock);
@@ -293,10 +323,7 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd)
memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version));
disk_super->policy_hint_size = 0;
r = dm_sm_copy_root(cmd->metadata_sm, &disk_super->metadata_space_map_root,
metadata_len);
if (r < 0)
goto bad_locked;
__copy_sm_root(cmd, disk_super);
disk_super->mapping_root = cpu_to_le64(cmd->root);
disk_super->hint_root = cpu_to_le64(cmd->hint_root);
@@ -313,10 +340,6 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd)
disk_super->write_misses = cpu_to_le32(0);
return dm_tm_commit(cmd->tm, sblock);
bad_locked:
dm_bm_unlock(sblock);
return r;
}
static int __format_metadata(struct dm_cache_metadata *cmd)
@@ -560,7 +583,6 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
flags_mutator mutator)
{
int r;
size_t metadata_len;
struct cache_disk_superblock *disk_super;
struct dm_block *sblock;
@@ -578,8 +600,8 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
if (r < 0)
return r;
r = dm_sm_root_size(cmd->metadata_sm, &metadata_len);
if (r < 0)
r = __save_sm_root(cmd);
if (r)
return r;
r = superblock_lock(cmd, &sblock);
@@ -606,13 +628,7 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses);
disk_super->write_hits = cpu_to_le32(cmd->stats.write_hits);
disk_super->write_misses = cpu_to_le32(cmd->stats.write_misses);
r = dm_sm_copy_root(cmd->metadata_sm, &disk_super->metadata_space_map_root,
metadata_len);
if (r < 0) {
dm_bm_unlock(sblock);
return r;
}
__copy_sm_root(cmd, disk_super);
return dm_tm_commit(cmd->tm, sblock);
}