diff options
author | Heinz Mauelshagen <heinzm@redhat.com> | 2016-05-19 12:49:27 -0400 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2016-06-13 14:40:27 -0400 |
commit | f090279eaff814a550b35bb51aac6b8541bddf97 (patch) | |
tree | 63013e80c7294f09668d0d91fa0a714db23a7090 | |
parent | 702108d194e3649f69afcd2661282a0157c71e54 (diff) |
dm raid: check constructor arguments for invalid raid level/argument combinations
Reject invalid flag combinations to avoid potential data corruption or
failing raid set construction:
- add definitions for constructor flag combinations and invalid flags
per level
- add bool test functions for the various raid types
(also will be used by future reshaping enhancements)
- introduce rs_check_for_invalid_flags() and _invalid_flags()
to perform the validity checks
Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
-rw-r--r-- | drivers/md/dm-raid.c | 131 |
1 files changed, 130 insertions, 1 deletions
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index ab7aa7d83364..ebb64eb66def 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c | |||
@@ -64,6 +64,61 @@ struct raid_dev { | |||
64 | #define CTR_FLAG_RAID10_COPIES 0x400 /* 2 */ /* Only with raid10 */ | 64 | #define CTR_FLAG_RAID10_COPIES 0x400 /* 2 */ /* Only with raid10 */ |
65 | #define CTR_FLAG_RAID10_FORMAT 0x800 /* 2 */ /* Only with raid10 */ | 65 | #define CTR_FLAG_RAID10_FORMAT 0x800 /* 2 */ /* Only with raid10 */ |
66 | 66 | ||
67 | /* | ||
68 | * Definitions of various constructor flags to | ||
69 | * be used in checks of valid / invalid flags | ||
70 | * per raid level. | ||
71 | */ | ||
72 | /* Define all any sync flags */ | ||
73 | #define CTR_FLAGS_ANY_SYNC (CTR_FLAG_SYNC | CTR_FLAG_NOSYNC) | ||
74 | |||
75 | /* Define flags for options without argument (e.g. 'nosync') */ | ||
76 | #define CTR_FLAG_OPTIONS_NO_ARGS CTR_FLAGS_ANY_SYNC | ||
77 | |||
78 | /* Define flags for options with one argument (e.g. 'delta_disks +2') */ | ||
79 | #define CTR_FLAG_OPTIONS_ONE_ARG (CTR_FLAG_REBUILD | \ | ||
80 | CTR_FLAG_WRITE_MOSTLY | \ | ||
81 | CTR_FLAG_DAEMON_SLEEP | \ | ||
82 | CTR_FLAG_MIN_RECOVERY_RATE | \ | ||
83 | CTR_FLAG_MAX_RECOVERY_RATE | \ | ||
84 | CTR_FLAG_MAX_WRITE_BEHIND | \ | ||
85 | CTR_FLAG_STRIPE_CACHE | \ | ||
86 | CTR_FLAG_REGION_SIZE | \ | ||
87 | CTR_FLAG_RAID10_COPIES | \ | ||
88 | CTR_FLAG_RAID10_FORMAT) | ||
89 | |||
90 | /* All ctr optional arguments */ | ||
91 | #define ALL_CTR_FLAGS (CTR_FLAG_OPTIONS_NO_ARGS | \ | ||
92 | CTR_FLAG_OPTIONS_ONE_ARG) | ||
93 | |||
94 | /* Invalid options definitions per raid level... */ | ||
95 | |||
96 | /* "raid0" does not accept any options */ | ||
97 | #define RAID0_INVALID_FLAGS ALL_CTR_FLAGS | ||
98 | |||
99 | /* "raid1" does not accept stripe cache or any raid10 options */ | ||
100 | #define RAID1_INVALID_FLAGS (CTR_FLAG_STRIPE_CACHE | \ | ||
101 | CTR_FLAG_RAID10_COPIES | \ | ||
102 | CTR_FLAG_RAID10_FORMAT) | ||
103 | |||
104 | /* "raid10" does not accept any raid1 or stripe cache options */ | ||
105 | #define RAID10_INVALID_FLAGS (CTR_FLAG_WRITE_MOSTLY | \ | ||
106 | CTR_FLAG_MAX_WRITE_BEHIND | \ | ||
107 | CTR_FLAG_STRIPE_CACHE) | ||
108 | /* | ||
109 | * "raid4/5/6" do not accept any raid1 or raid10 specific options | ||
110 | * | ||
111 | * "raid6" does not accept "nosync", because it is not guaranteed | ||
112 | * that both parity and q-syndrome are being written properly with | ||
113 | * any writes | ||
114 | */ | ||
115 | #define RAID45_INVALID_FLAGS (CTR_FLAG_WRITE_MOSTLY | \ | ||
116 | CTR_FLAG_MAX_WRITE_BEHIND | \ | ||
117 | CTR_FLAG_RAID10_FORMAT | \ | ||
118 | CTR_FLAG_RAID10_COPIES) | ||
119 | #define RAID6_INVALID_FLAGS (CTR_FLAG_NOSYNC | RAID45_INVALID_FLAGS) | ||
120 | /* ...invalid options definitions per raid level */ | ||
121 | |||
67 | struct raid_set { | 122 | struct raid_set { |
68 | struct dm_target *ti; | 123 | struct dm_target *ti; |
69 | 124 | ||
@@ -167,6 +222,41 @@ static const char *_argname_by_flag(const uint32_t flag) | |||
167 | } | 222 | } |
168 | 223 | ||
169 | /* | 224 | /* |
225 | * bool helpers to test for various raid levels of a raid type | ||
226 | */ | ||
227 | |||
228 | /* Return true, if raid type in @rt is raid0 */ | ||
229 | static bool rt_is_raid0(struct raid_type *rt) | ||
230 | { | ||
231 | return !rt->level; | ||
232 | } | ||
233 | |||
234 | /* Return true, if raid type in @rt is raid1 */ | ||
235 | static bool rt_is_raid1(struct raid_type *rt) | ||
236 | { | ||
237 | return rt->level == 1; | ||
238 | } | ||
239 | |||
240 | /* Return true, if raid type in @rt is raid10 */ | ||
241 | static bool rt_is_raid10(struct raid_type *rt) | ||
242 | { | ||
243 | return rt->level == 10; | ||
244 | } | ||
245 | |||
246 | /* Return true, if raid type in @rt is raid4/5 */ | ||
247 | static bool rt_is_raid45(struct raid_type *rt) | ||
248 | { | ||
249 | return _in_range(rt->level, 4, 5); | ||
250 | } | ||
251 | |||
252 | /* Return true, if raid type in @rt is raid6 */ | ||
253 | static bool rt_is_raid6(struct raid_type *rt) | ||
254 | { | ||
255 | return rt->level == 6; | ||
256 | } | ||
257 | /* END: raid level bools */ | ||
258 | |||
259 | /* | ||
170 | * Convenience functions to set ti->error to @errmsg and | 260 | * Convenience functions to set ti->error to @errmsg and |
171 | * return @r in order to shorten code in a lot of places | 261 | * return @r in order to shorten code in a lot of places |
172 | */ | 262 | */ |
@@ -182,6 +272,44 @@ static int ti_error_einval(struct dm_target *ti, const char *errmsg) | |||
182 | } | 272 | } |
183 | /* END: convenience functions to set ti->error to @errmsg... */ | 273 | /* END: convenience functions to set ti->error to @errmsg... */ |
184 | 274 | ||
275 | /* Return invalid ctr flags for the raid level of @rs */ | ||
276 | static uint32_t _invalid_flags(struct raid_set *rs) | ||
277 | { | ||
278 | if (rt_is_raid0(rs->raid_type)) | ||
279 | return RAID0_INVALID_FLAGS; | ||
280 | else if (rt_is_raid1(rs->raid_type)) | ||
281 | return RAID1_INVALID_FLAGS; | ||
282 | else if (rt_is_raid10(rs->raid_type)) | ||
283 | return RAID10_INVALID_FLAGS; | ||
284 | else if (rt_is_raid45(rs->raid_type)) | ||
285 | return RAID45_INVALID_FLAGS; | ||
286 | else if (rt_is_raid6(rs->raid_type)) | ||
287 | return RAID6_INVALID_FLAGS; | ||
288 | |||
289 | return ~0; | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * Check for any invalid flags set on @rs defined by bitset @invalid_flags | ||
294 | * | ||
295 | * Has to be called after parsing of the ctr flags! | ||
296 | */ | ||
297 | static int rs_check_for_invalid_flags(struct raid_set *rs) | ||
298 | { | ||
299 | unsigned int ctr_flags = rs->ctr_flags, flag = 0; | ||
300 | const uint32_t invalid_flags = _invalid_flags(rs); | ||
301 | |||
302 | while ((ctr_flags &= ~flag)) { | ||
303 | flag = 1 << __ffs(ctr_flags); | ||
304 | |||
305 | if (_test_flag(flag, rs->ctr_flags) && | ||
306 | _test_flag(flag, invalid_flags)) | ||
307 | return ti_error_einval(rs->ti, "Invalid flag combined"); | ||
308 | } | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
185 | static char *raid10_md_layout_to_format(int layout) | 313 | static char *raid10_md_layout_to_format(int layout) |
186 | { | 314 | { |
187 | /* | 315 | /* |
@@ -806,7 +934,8 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as, | |||
806 | rs->md.persistent = 0; | 934 | rs->md.persistent = 0; |
807 | rs->md.external = 1; | 935 | rs->md.external = 1; |
808 | 936 | ||
809 | return 0; | 937 | /* Check, if any invalid ctr arguments have been passed in for the raid level */ |
938 | return rs_check_for_invalid_flags(rs); | ||
810 | } | 939 | } |
811 | 940 | ||
812 | static void do_table_event(struct work_struct *ws) | 941 | static void do_table_event(struct work_struct *ws) |