Skip to content

Commit

Permalink
dm cache: make sure every metadata function checks fail_io
Browse files Browse the repository at this point in the history
Otherwise operations may be attempted that will only ever go on to crash
(since the metadata device is either missing or unreliable if 'fail_io'
is set).

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Cc: stable@vger.kernel.org
  • Loading branch information
jthornber authored and snitm committed Mar 10, 2016
1 parent 3f06804 commit d14fcf3
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 43 deletions.
98 changes: 59 additions & 39 deletions drivers/md/dm-cache-metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -867,19 +867,40 @@ static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd,
return 0;
}

#define WRITE_LOCK(cmd) \
if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
#define WRITE_LOCK(cmd) \
down_write(&cmd->root_lock); \
if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
up_write(&cmd->root_lock); \
return -EINVAL; \
down_write(&cmd->root_lock)
}

#define WRITE_LOCK_VOID(cmd) \
if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
down_write(&cmd->root_lock); \
if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
up_write(&cmd->root_lock); \
return; \
down_write(&cmd->root_lock)
}

#define WRITE_UNLOCK(cmd) \
up_write(&cmd->root_lock)

#define READ_LOCK(cmd) \
down_read(&cmd->root_lock); \
if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
up_read(&cmd->root_lock); \
return -EINVAL; \
}

#define READ_LOCK_VOID(cmd) \
down_read(&cmd->root_lock); \
if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) { \
up_read(&cmd->root_lock); \
return; \
}

#define READ_UNLOCK(cmd) \
up_read(&cmd->root_lock)

int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size)
{
int r;
Expand Down Expand Up @@ -1015,22 +1036,20 @@ int dm_cache_load_discards(struct dm_cache_metadata *cmd,
{
int r;

down_read(&cmd->root_lock);
READ_LOCK(cmd);
r = __load_discards(cmd, fn, context);
up_read(&cmd->root_lock);
READ_UNLOCK(cmd);

return r;
}

dm_cblock_t dm_cache_size(struct dm_cache_metadata *cmd)
int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result)
{
dm_cblock_t r;
READ_LOCK(cmd);
*result = cmd->cache_blocks;
READ_UNLOCK(cmd);

down_read(&cmd->root_lock);
r = cmd->cache_blocks;
up_read(&cmd->root_lock);

return r;
return 0;
}

static int __remove(struct dm_cache_metadata *cmd, dm_cblock_t cblock)
Expand Down Expand Up @@ -1188,9 +1207,9 @@ int dm_cache_load_mappings(struct dm_cache_metadata *cmd,
{
int r;

down_read(&cmd->root_lock);
READ_LOCK(cmd);
r = __load_mappings(cmd, policy, fn, context);
up_read(&cmd->root_lock);
READ_UNLOCK(cmd);

return r;
}
Expand All @@ -1215,18 +1234,18 @@ static int __dump_mappings(struct dm_cache_metadata *cmd)

void dm_cache_dump(struct dm_cache_metadata *cmd)
{
down_read(&cmd->root_lock);
READ_LOCK_VOID(cmd);
__dump_mappings(cmd);
up_read(&cmd->root_lock);
READ_UNLOCK(cmd);
}

int dm_cache_changed_this_transaction(struct dm_cache_metadata *cmd)
{
int r;

down_read(&cmd->root_lock);
READ_LOCK(cmd);
r = cmd->changed;
up_read(&cmd->root_lock);
READ_UNLOCK(cmd);

return r;
}
Expand Down Expand Up @@ -1276,9 +1295,9 @@ int dm_cache_set_dirty(struct dm_cache_metadata *cmd,
void dm_cache_metadata_get_stats(struct dm_cache_metadata *cmd,
struct dm_cache_statistics *stats)
{
down_read(&cmd->root_lock);
READ_LOCK_VOID(cmd);
*stats = cmd->stats;
up_read(&cmd->root_lock);
READ_UNLOCK(cmd);
}

void dm_cache_metadata_set_stats(struct dm_cache_metadata *cmd,
Expand Down Expand Up @@ -1312,9 +1331,9 @@ int dm_cache_get_free_metadata_block_count(struct dm_cache_metadata *cmd,
{
int r = -EINVAL;

down_read(&cmd->root_lock);
READ_LOCK(cmd);
r = dm_sm_get_nr_free(cmd->metadata_sm, result);
up_read(&cmd->root_lock);
READ_UNLOCK(cmd);

return r;
}
Expand All @@ -1324,9 +1343,9 @@ int dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd,
{
int r = -EINVAL;

down_read(&cmd->root_lock);
READ_LOCK(cmd);
r = dm_sm_get_nr_blocks(cmd->metadata_sm, result);
up_read(&cmd->root_lock);
READ_UNLOCK(cmd);

return r;
}
Expand Down Expand Up @@ -1417,7 +1436,13 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *

int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result)
{
return blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result);
int r;

READ_LOCK(cmd);
r = blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result);
READ_UNLOCK(cmd);

return r;
}

void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd)
Expand All @@ -1440,10 +1465,7 @@ int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd)
struct dm_block *sblock;
struct cache_disk_superblock *disk_super;

/*
* We ignore fail_io for this function.
*/
down_write(&cmd->root_lock);
WRITE_LOCK(cmd);
set_bit(NEEDS_CHECK, &cmd->flags);

r = superblock_lock(cmd, &sblock);
Expand All @@ -1458,19 +1480,17 @@ int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd)
dm_bm_unlock(sblock);

out:
up_write(&cmd->root_lock);
WRITE_UNLOCK(cmd);
return r;
}

bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd)
int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result)
{
bool needs_check;
READ_LOCK(cmd);
*result = !!test_bit(NEEDS_CHECK, &cmd->flags);
READ_UNLOCK(cmd);

down_read(&cmd->root_lock);
needs_check = !!test_bit(NEEDS_CHECK, &cmd->flags);
up_read(&cmd->root_lock);

return needs_check;
return 0;
}

int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
Expand Down
4 changes: 2 additions & 2 deletions drivers/md/dm-cache-metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd);
* origin blocks to map to.
*/
int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size);
dm_cblock_t dm_cache_size(struct dm_cache_metadata *cmd);
int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result);

int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd,
sector_t discard_block_size,
Expand Down Expand Up @@ -137,7 +137,7 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *
*/
int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result);

bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd);
int dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd, bool *result);
int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd);
void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd);
void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd);
Expand Down
12 changes: 10 additions & 2 deletions drivers/md/dm-cache-target.c
Original file line number Diff line number Diff line change
Expand Up @@ -984,9 +984,14 @@ static void notify_mode_switch(struct cache *cache, enum cache_metadata_mode mod

static void set_cache_mode(struct cache *cache, enum cache_metadata_mode new_mode)
{
bool needs_check = dm_cache_metadata_needs_check(cache->cmd);
bool needs_check;
enum cache_metadata_mode old_mode = get_cache_mode(cache);

if (dm_cache_metadata_needs_check(cache->cmd, &needs_check)) {
DMERR("unable to read needs_check flag, setting failure mode");
new_mode = CM_FAIL;
}

if (new_mode == CM_WRITE && needs_check) {
DMERR("%s: unable to switch cache to write mode until repaired.",
cache_device_name(cache));
Expand Down Expand Up @@ -3510,6 +3515,7 @@ static void cache_status(struct dm_target *ti, status_type_t type,
char buf[BDEVNAME_SIZE];
struct cache *cache = ti->private;
dm_cblock_t residency;
bool needs_check;

switch (type) {
case STATUSTYPE_INFO:
Expand Down Expand Up @@ -3583,7 +3589,9 @@ static void cache_status(struct dm_target *ti, status_type_t type,
else
DMEMIT("rw ");

if (dm_cache_metadata_needs_check(cache->cmd))
r = dm_cache_metadata_needs_check(cache->cmd, &needs_check);

if (r || needs_check)
DMEMIT("needs_check ");
else
DMEMIT("- ");
Expand Down

0 comments on commit d14fcf3

Please sign in to comment.