Skip to content

Commit 028ae9f

Browse files
jthornbersnitm
authored andcommitted
dm cache: add fail io mode and needs_check flag
If a cache metadata operation fails (e.g. transaction commit) the cache's metadata device will abort the current transaction, set a new needs_check flag, and the cache will transition to "read-only" mode. If aborting the transaction or setting the needs_check flag fails the cache will transition to "fail-io" mode. Once needs_check is set the cache device will not be allowed to activate. Activation requires write access to metadata. Future work is needed to add proper support for running the cache in read-only mode. Once in fail-io mode the cache will report a status of "Fail". Also, add commit() wrapper that will disallow commits if in read_only or fail mode. Signed-off-by: Joe Thornber <ejt@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
1 parent 88bf518 commit 028ae9f

File tree

7 files changed

+320
-58
lines changed

7 files changed

+320
-58
lines changed

Documentation/device-mapper/cache.txt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ Status
221221
<#read hits> <#read misses> <#write hits> <#write misses>
222222
<#demotions> <#promotions> <#dirty> <#features> <features>*
223223
<#core args> <core args>* <policy name> <#policy args> <policy args>*
224+
<cache metadata mode>
224225

225226
metadata block size : Fixed block size for each metadata block in
226227
sectors
@@ -251,8 +252,12 @@ core args : Key/value pairs for tuning the core
251252
e.g. migration_threshold
252253
policy name : Name of the policy
253254
#policy args : Number of policy arguments to follow (must be even)
254-
policy args : Key/value pairs
255-
e.g. sequential_threshold
255+
policy args : Key/value pairs e.g. sequential_threshold
256+
cache metadata mode : ro if read-only, rw if read-write
257+
In serious cases where even a read-only mode is deemed unsafe
258+
no further I/O will be permitted and the status will just
259+
contain the string 'Fail'. The userspace recovery tools
260+
should then be used.
256261

257262
Messages
258263
--------

drivers/md/dm-cache-metadata.c

Lines changed: 114 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
enum superblock_flag_bits {
4040
/* for spotting crashes that would invalidate the dirty bitset */
4141
CLEAN_SHUTDOWN,
42+
/* metadata must be checked using the tools */
43+
NEEDS_CHECK,
4244
};
4345

4446
/*
@@ -107,6 +109,7 @@ struct dm_cache_metadata {
107109
struct dm_disk_bitset discard_info;
108110

109111
struct rw_semaphore root_lock;
112+
unsigned long flags;
110113
dm_block_t root;
111114
dm_block_t hint_root;
112115
dm_block_t discard_root;
@@ -129,6 +132,14 @@ struct dm_cache_metadata {
129132
* buffer before the superblock is locked and updated.
130133
*/
131134
__u8 metadata_space_map_root[SPACE_MAP_ROOT_SIZE];
135+
136+
/*
137+
* Set if a transaction has to be aborted but the attempt to roll
138+
* back to the previous (good) transaction failed. The only
139+
* metadata operation permissible in this state is the closing of
140+
* the device.
141+
*/
142+
bool fail_io:1;
132143
};
133144

134145
/*-------------------------------------------------------------------
@@ -527,6 +538,7 @@ static unsigned long clear_clean_shutdown(unsigned long flags)
527538
static void read_superblock_fields(struct dm_cache_metadata *cmd,
528539
struct cache_disk_superblock *disk_super)
529540
{
541+
cmd->flags = le32_to_cpu(disk_super->flags);
530542
cmd->root = le64_to_cpu(disk_super->mapping_root);
531543
cmd->hint_root = le64_to_cpu(disk_super->hint_root);
532544
cmd->discard_root = le64_to_cpu(disk_super->discard_root);
@@ -625,6 +637,7 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
625637
if (mutator)
626638
update_flags(disk_super, mutator);
627639

640+
disk_super->flags = cpu_to_le32(cmd->flags);
628641
disk_super->mapping_root = cpu_to_le64(cmd->root);
629642
disk_super->hint_root = cpu_to_le64(cmd->hint_root);
630643
disk_super->discard_root = cpu_to_le64(cmd->discard_root);
@@ -693,6 +706,7 @@ static struct dm_cache_metadata *metadata_open(struct block_device *bdev,
693706
cmd->cache_blocks = 0;
694707
cmd->policy_hint_size = policy_hint_size;
695708
cmd->changed = true;
709+
cmd->fail_io = false;
696710

697711
r = __create_persistent_data_objects(cmd, may_format_device);
698712
if (r) {
@@ -796,7 +810,8 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd)
796810
list_del(&cmd->list);
797811
mutex_unlock(&table_lock);
798812

799-
__destroy_persistent_data_objects(cmd);
813+
if (!cmd->fail_io)
814+
__destroy_persistent_data_objects(cmd);
800815
kfree(cmd);
801816
}
802817
}
@@ -848,13 +863,26 @@ static int blocks_are_unmapped_or_clean(struct dm_cache_metadata *cmd,
848863
return 0;
849864
}
850865

866+
#define WRITE_LOCK(cmd) \
867+
if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
868+
return -EINVAL; \
869+
down_write(&cmd->root_lock)
870+
871+
#define WRITE_LOCK_VOID(cmd) \
872+
if (cmd->fail_io || dm_bm_is_read_only(cmd->bm)) \
873+
return; \
874+
down_write(&cmd->root_lock)
875+
876+
#define WRITE_UNLOCK(cmd) \
877+
up_write(&cmd->root_lock)
878+
851879
int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size)
852880
{
853881
int r;
854882
bool clean;
855883
__le64 null_mapping = pack_value(0, 0);
856884

857-
down_write(&cmd->root_lock);
885+
WRITE_LOCK(cmd);
858886
__dm_bless_for_disk(&null_mapping);
859887

860888
if (from_cblock(new_cache_size) < from_cblock(cmd->cache_blocks)) {
@@ -880,7 +908,7 @@ int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size)
880908
cmd->changed = true;
881909

882910
out:
883-
up_write(&cmd->root_lock);
911+
WRITE_UNLOCK(cmd);
884912

885913
return r;
886914
}
@@ -891,7 +919,7 @@ int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd,
891919
{
892920
int r;
893921

894-
down_write(&cmd->root_lock);
922+
WRITE_LOCK(cmd);
895923
r = dm_bitset_resize(&cmd->discard_info,
896924
cmd->discard_root,
897925
from_dblock(cmd->discard_nr_blocks),
@@ -903,7 +931,7 @@ int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd,
903931
}
904932

905933
cmd->changed = true;
906-
up_write(&cmd->root_lock);
934+
WRITE_UNLOCK(cmd);
907935

908936
return r;
909937
}
@@ -946,9 +974,9 @@ int dm_cache_set_discard(struct dm_cache_metadata *cmd,
946974
{
947975
int r;
948976

949-
down_write(&cmd->root_lock);
977+
WRITE_LOCK(cmd);
950978
r = __discard(cmd, dblock, discard);
951-
up_write(&cmd->root_lock);
979+
WRITE_UNLOCK(cmd);
952980

953981
return r;
954982
}
@@ -1020,9 +1048,9 @@ int dm_cache_remove_mapping(struct dm_cache_metadata *cmd, dm_cblock_t cblock)
10201048
{
10211049
int r;
10221050

1023-
down_write(&cmd->root_lock);
1051+
WRITE_LOCK(cmd);
10241052
r = __remove(cmd, cblock);
1025-
up_write(&cmd->root_lock);
1053+
WRITE_UNLOCK(cmd);
10261054

10271055
return r;
10281056
}
@@ -1048,9 +1076,9 @@ int dm_cache_insert_mapping(struct dm_cache_metadata *cmd,
10481076
{
10491077
int r;
10501078

1051-
down_write(&cmd->root_lock);
1079+
WRITE_LOCK(cmd);
10521080
r = __insert(cmd, cblock, oblock);
1053-
up_write(&cmd->root_lock);
1081+
WRITE_UNLOCK(cmd);
10541082

10551083
return r;
10561084
}
@@ -1234,9 +1262,9 @@ int dm_cache_set_dirty(struct dm_cache_metadata *cmd,
12341262
{
12351263
int r;
12361264

1237-
down_write(&cmd->root_lock);
1265+
WRITE_LOCK(cmd);
12381266
r = __dirty(cmd, cblock, dirty);
1239-
up_write(&cmd->root_lock);
1267+
WRITE_UNLOCK(cmd);
12401268

12411269
return r;
12421270
}
@@ -1252,9 +1280,9 @@ void dm_cache_metadata_get_stats(struct dm_cache_metadata *cmd,
12521280
void dm_cache_metadata_set_stats(struct dm_cache_metadata *cmd,
12531281
struct dm_cache_statistics *stats)
12541282
{
1255-
down_write(&cmd->root_lock);
1283+
WRITE_LOCK_VOID(cmd);
12561284
cmd->stats = *stats;
1257-
up_write(&cmd->root_lock);
1285+
WRITE_UNLOCK(cmd);
12581286
}
12591287

12601288
int dm_cache_commit(struct dm_cache_metadata *cmd, bool clean_shutdown)
@@ -1263,15 +1291,15 @@ int dm_cache_commit(struct dm_cache_metadata *cmd, bool clean_shutdown)
12631291
flags_mutator mutator = (clean_shutdown ? set_clean_shutdown :
12641292
clear_clean_shutdown);
12651293

1266-
down_write(&cmd->root_lock);
1294+
WRITE_LOCK(cmd);
12671295
r = __commit_transaction(cmd, mutator);
12681296
if (r)
12691297
goto out;
12701298

12711299
r = __begin_transaction(cmd);
12721300

12731301
out:
1274-
up_write(&cmd->root_lock);
1302+
WRITE_UNLOCK(cmd);
12751303
return r;
12761304
}
12771305

@@ -1376,9 +1404,9 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *
13761404
{
13771405
int r;
13781406

1379-
down_write(&cmd->root_lock);
1407+
WRITE_LOCK(cmd);
13801408
r = write_hints(cmd, policy);
1381-
up_write(&cmd->root_lock);
1409+
WRITE_UNLOCK(cmd);
13821410

13831411
return r;
13841412
}
@@ -1387,3 +1415,70 @@ int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result)
13871415
{
13881416
return blocks_are_unmapped_or_clean(cmd, 0, cmd->cache_blocks, result);
13891417
}
1418+
1419+
void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd)
1420+
{
1421+
WRITE_LOCK_VOID(cmd);
1422+
dm_bm_set_read_only(cmd->bm);
1423+
WRITE_UNLOCK(cmd);
1424+
}
1425+
1426+
void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd)
1427+
{
1428+
WRITE_LOCK_VOID(cmd);
1429+
dm_bm_set_read_write(cmd->bm);
1430+
WRITE_UNLOCK(cmd);
1431+
}
1432+
1433+
int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd)
1434+
{
1435+
int r;
1436+
struct dm_block *sblock;
1437+
struct cache_disk_superblock *disk_super;
1438+
1439+
/*
1440+
* We ignore fail_io for this function.
1441+
*/
1442+
down_write(&cmd->root_lock);
1443+
set_bit(NEEDS_CHECK, &cmd->flags);
1444+
1445+
r = superblock_lock(cmd, &sblock);
1446+
if (r) {
1447+
DMERR("couldn't read superblock");
1448+
goto out;
1449+
}
1450+
1451+
disk_super = dm_block_data(sblock);
1452+
disk_super->flags = cpu_to_le32(cmd->flags);
1453+
1454+
dm_bm_unlock(sblock);
1455+
1456+
out:
1457+
up_write(&cmd->root_lock);
1458+
return r;
1459+
}
1460+
1461+
bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd)
1462+
{
1463+
bool needs_check;
1464+
1465+
down_read(&cmd->root_lock);
1466+
needs_check = !!test_bit(NEEDS_CHECK, &cmd->flags);
1467+
up_read(&cmd->root_lock);
1468+
1469+
return needs_check;
1470+
}
1471+
1472+
int dm_cache_metadata_abort(struct dm_cache_metadata *cmd)
1473+
{
1474+
int r;
1475+
1476+
WRITE_LOCK(cmd);
1477+
__destroy_persistent_data_objects(cmd);
1478+
r = __create_persistent_data_objects(cmd, false);
1479+
if (r)
1480+
cmd->fail_io = true;
1481+
WRITE_UNLOCK(cmd);
1482+
1483+
return r;
1484+
}

drivers/md/dm-cache-metadata.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ struct dm_cache_statistics {
102102

103103
void dm_cache_metadata_get_stats(struct dm_cache_metadata *cmd,
104104
struct dm_cache_statistics *stats);
105+
106+
/*
107+
* 'void' because it's no big deal if it fails.
108+
*/
105109
void dm_cache_metadata_set_stats(struct dm_cache_metadata *cmd,
106110
struct dm_cache_statistics *stats);
107111

@@ -133,6 +137,12 @@ int dm_cache_write_hints(struct dm_cache_metadata *cmd, struct dm_cache_policy *
133137
*/
134138
int dm_cache_metadata_all_clean(struct dm_cache_metadata *cmd, bool *result);
135139

140+
bool dm_cache_metadata_needs_check(struct dm_cache_metadata *cmd);
141+
int dm_cache_metadata_set_needs_check(struct dm_cache_metadata *cmd);
142+
void dm_cache_metadata_set_read_only(struct dm_cache_metadata *cmd);
143+
void dm_cache_metadata_set_read_write(struct dm_cache_metadata *cmd);
144+
int dm_cache_metadata_abort(struct dm_cache_metadata *cmd);
145+
136146
/*----------------------------------------------------------------*/
137147

138148
#endif /* DM_CACHE_METADATA_H */

drivers/md/dm-cache-policy-internal.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,15 @@ static inline void policy_tick(struct dm_cache_policy *p)
8989
return p->tick(p);
9090
}
9191

92-
static inline int policy_emit_config_values(struct dm_cache_policy *p, char *result, unsigned maxlen)
92+
static inline int policy_emit_config_values(struct dm_cache_policy *p, char *result,
93+
unsigned maxlen, ssize_t *sz_ptr)
9394
{
94-
ssize_t sz = 0;
95+
ssize_t sz = *sz_ptr;
9596
if (p->emit_config_values)
96-
return p->emit_config_values(p, result, maxlen);
97+
return p->emit_config_values(p, result, maxlen, sz_ptr);
9798

98-
DMEMIT("0");
99+
DMEMIT("0 ");
100+
*sz_ptr = sz;
99101
return 0;
100102
}
101103

drivers/md/dm-cache-policy-mq.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,22 +1323,24 @@ static int mq_set_config_value(struct dm_cache_policy *p,
13231323
return 0;
13241324
}
13251325

1326-
static int mq_emit_config_values(struct dm_cache_policy *p, char *result, unsigned maxlen)
1326+
static int mq_emit_config_values(struct dm_cache_policy *p, char *result,
1327+
unsigned maxlen, ssize_t *sz_ptr)
13271328
{
1328-
ssize_t sz = 0;
1329+
ssize_t sz = *sz_ptr;
13291330
struct mq_policy *mq = to_mq_policy(p);
13301331

13311332
DMEMIT("10 random_threshold %u "
13321333
"sequential_threshold %u "
13331334
"discard_promote_adjustment %u "
13341335
"read_promote_adjustment %u "
1335-
"write_promote_adjustment %u",
1336+
"write_promote_adjustment %u ",
13361337
mq->tracker.thresholds[PATTERN_RANDOM],
13371338
mq->tracker.thresholds[PATTERN_SEQUENTIAL],
13381339
mq->discard_promote_adjustment,
13391340
mq->read_promote_adjustment,
13401341
mq->write_promote_adjustment);
13411342

1343+
*sz_ptr = sz;
13421344
return 0;
13431345
}
13441346

drivers/md/dm-cache-policy.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,8 @@ struct dm_cache_policy {
208208
/*
209209
* Configuration.
210210
*/
211-
int (*emit_config_values)(struct dm_cache_policy *p,
212-
char *result, unsigned maxlen);
211+
int (*emit_config_values)(struct dm_cache_policy *p, char *result,
212+
unsigned maxlen, ssize_t *sz_ptr);
213213
int (*set_config_value)(struct dm_cache_policy *p,
214214
const char *key, const char *value);
215215

0 commit comments

Comments
 (0)