aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavid.oberhollenzer@sigma-star.at <david.oberhollenzer@sigma-star.at>2015-03-26 18:59:50 -0400
committerRichard Weinberger <richard@nod.at>2015-04-13 15:05:17 -0400
commit502690674281a047abd45f81e64c498bc23a8bb3 (patch)
tree5aa08ca80d7de94bf0b3050a7f458ad0ed25d004
parent1a7e985dd1bf5939af0f56bbd6d13d2caf48dd63 (diff)
UBI: power cut emulation for testing
Emulate random power cuts by switching device to ro after a number of writes to allow simple power cut testing with nand-sim. Maximum and minimum number of successful writes before power cut and what kind of writes (EC header, VID header or none) to interrupt configurable via debugfs. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at> Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r--drivers/mtd/ubi/debug.c89
-rw-r--r--drivers/mtd/ubi/debug.h2
-rw-r--r--drivers/mtd/ubi/io.c6
-rw-r--r--drivers/mtd/ubi/ubi.h25
4 files changed, 120 insertions, 2 deletions
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 224fed085102..b077e43b5ba9 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -263,7 +263,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
263 struct dentry *dent = file->f_path.dentry; 263 struct dentry *dent = file->f_path.dentry;
264 struct ubi_device *ubi; 264 struct ubi_device *ubi;
265 struct ubi_debug_info *d; 265 struct ubi_debug_info *d;
266 char buf[3]; 266 char buf[8];
267 int val; 267 int val;
268 268
269 ubi = ubi_get_device(ubi_num); 269 ubi = ubi_get_device(ubi_num);
@@ -283,6 +283,22 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
283 val = d->emulate_bitflips; 283 val = d->emulate_bitflips;
284 else if (dent == d->dfs_emulate_io_failures) 284 else if (dent == d->dfs_emulate_io_failures)
285 val = d->emulate_io_failures; 285 val = d->emulate_io_failures;
286 else if (dent == d->dfs_emulate_power_cut) {
287 snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut);
288 count = simple_read_from_buffer(user_buf, count, ppos,
289 buf, strlen(buf));
290 goto out;
291 } else if (dent == d->dfs_power_cut_min) {
292 snprintf(buf, sizeof(buf), "%u\n", d->power_cut_min);
293 count = simple_read_from_buffer(user_buf, count, ppos,
294 buf, strlen(buf));
295 goto out;
296 } else if (dent == d->dfs_power_cut_max) {
297 snprintf(buf, sizeof(buf), "%u\n", d->power_cut_max);
298 count = simple_read_from_buffer(user_buf, count, ppos,
299 buf, strlen(buf));
300 goto out;
301 }
286 else { 302 else {
287 count = -EINVAL; 303 count = -EINVAL;
288 goto out; 304 goto out;
@@ -311,7 +327,7 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
311 struct ubi_device *ubi; 327 struct ubi_device *ubi;
312 struct ubi_debug_info *d; 328 struct ubi_debug_info *d;
313 size_t buf_size; 329 size_t buf_size;
314 char buf[8]; 330 char buf[8] = {0};
315 int val; 331 int val;
316 332
317 ubi = ubi_get_device(ubi_num); 333 ubi = ubi_get_device(ubi_num);
@@ -325,6 +341,21 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
325 goto out; 341 goto out;
326 } 342 }
327 343
344 if (dent == d->dfs_power_cut_min) {
345 if (kstrtouint(buf, 0, &d->power_cut_min) != 0)
346 count = -EINVAL;
347 goto out;
348 } else if (dent == d->dfs_power_cut_max) {
349 if (kstrtouint(buf, 0, &d->power_cut_max) != 0)
350 count = -EINVAL;
351 goto out;
352 } else if (dent == d->dfs_emulate_power_cut) {
353 if (kstrtoint(buf, 0, &val) != 0)
354 count = -EINVAL;
355 d->emulate_power_cut = val;
356 goto out;
357 }
358
328 if (buf[0] == '1') 359 if (buf[0] == '1')
329 val = 1; 360 val = 1;
330 else if (buf[0] == '0') 361 else if (buf[0] == '0')
@@ -438,6 +469,27 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
438 goto out_remove; 469 goto out_remove;
439 d->dfs_emulate_io_failures = dent; 470 d->dfs_emulate_io_failures = dent;
440 471
472 fname = "tst_emulate_power_cut";
473 dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
474 &dfs_fops);
475 if (IS_ERR_OR_NULL(dent))
476 goto out_remove;
477 d->dfs_emulate_power_cut = dent;
478
479 fname = "tst_emulate_power_cut_min";
480 dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
481 &dfs_fops);
482 if (IS_ERR_OR_NULL(dent))
483 goto out_remove;
484 d->dfs_power_cut_min = dent;
485
486 fname = "tst_emulate_power_cut_max";
487 dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
488 &dfs_fops);
489 if (IS_ERR_OR_NULL(dent))
490 goto out_remove;
491 d->dfs_power_cut_max = dent;
492
441 return 0; 493 return 0;
442 494
443out_remove: 495out_remove:
@@ -458,3 +510,36 @@ void ubi_debugfs_exit_dev(struct ubi_device *ubi)
458 if (IS_ENABLED(CONFIG_DEBUG_FS)) 510 if (IS_ENABLED(CONFIG_DEBUG_FS))
459 debugfs_remove_recursive(ubi->dbg.dfs_dir); 511 debugfs_remove_recursive(ubi->dbg.dfs_dir);
460} 512}
513
514/**
515 * ubi_dbg_power_cut - emulate a power cut if it is time to do so
516 * @ubi: UBI device description object
517 * @caller: Flags set to indicate from where the function is being called
518 *
519 * Returns non-zero if a power cut was emulated, zero if not.
520 */
521int ubi_dbg_power_cut(struct ubi_device *ubi, int caller)
522{
523 unsigned int range;
524
525 if ((ubi->dbg.emulate_power_cut & caller) == 0)
526 return 0;
527
528 if (ubi->dbg.power_cut_counter == 0) {
529 ubi->dbg.power_cut_counter = ubi->dbg.power_cut_min;
530
531 if (ubi->dbg.power_cut_max > ubi->dbg.power_cut_min) {
532 range = ubi->dbg.power_cut_max - ubi->dbg.power_cut_min;
533 ubi->dbg.power_cut_counter += prandom_u32() % range;
534 }
535 return 0;
536 }
537
538 ubi->dbg.power_cut_counter--;
539 if (ubi->dbg.power_cut_counter)
540 return 0;
541
542 ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX");
543 ubi_ro_mode(ubi);
544 return 1;
545}
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index c6ea4431acf3..eb8985e5c178 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -137,4 +137,6 @@ static inline void ubi_enable_dbg_chk_fastmap(struct ubi_device *ubi)
137{ 137{
138 ubi->dbg.chk_fastmap = 1; 138 ubi->dbg.chk_fastmap = 1;
139} 139}
140
141int ubi_dbg_power_cut(struct ubi_device *ubi, int caller);
140#endif /* !__UBI_DEBUG_H__ */ 142#endif /* !__UBI_DEBUG_H__ */
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index ed0bcb35472f..5bbd1f094f4e 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -859,6 +859,9 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
859 if (err) 859 if (err)
860 return err; 860 return err;
861 861
862 if (ubi_dbg_power_cut(ubi, POWER_CUT_EC_WRITE))
863 return -EROFS;
864
862 err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize); 865 err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize);
863 return err; 866 return err;
864} 867}
@@ -1106,6 +1109,9 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
1106 if (err) 1109 if (err)
1107 return err; 1110 return err;
1108 1111
1112 if (ubi_dbg_power_cut(ubi, POWER_CUT_VID_WRITE))
1113 return -EROFS;
1114
1109 p = (char *)vid_hdr - ubi->vid_hdr_shift; 1115 p = (char *)vid_hdr - ubi->vid_hdr_shift;
1110 err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset, 1116 err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset,
1111 ubi->vid_hdr_alsize); 1117 ubi->vid_hdr_alsize);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 3d58c749f9f1..c998212fc680 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -151,6 +151,17 @@ enum {
151 UBI_BAD_FASTMAP, 151 UBI_BAD_FASTMAP,
152}; 152};
153 153
154/*
155 * Flags for emulate_power_cut in ubi_debug_info
156 *
157 * POWER_CUT_EC_WRITE: Emulate a power cut when writing an EC header
158 * POWER_CUT_VID_WRITE: Emulate a power cut when writing a VID header
159 */
160enum {
161 POWER_CUT_EC_WRITE = 0x01,
162 POWER_CUT_VID_WRITE = 0x02,
163};
164
154/** 165/**
155 * struct ubi_wl_entry - wear-leveling entry. 166 * struct ubi_wl_entry - wear-leveling entry.
156 * @u.rb: link in the corresponding (free/used) RB-tree 167 * @u.rb: link in the corresponding (free/used) RB-tree
@@ -360,6 +371,10 @@ struct ubi_wl_entry;
360 * @disable_bgt: disable the background task for testing purposes 371 * @disable_bgt: disable the background task for testing purposes
361 * @emulate_bitflips: emulate bit-flips for testing purposes 372 * @emulate_bitflips: emulate bit-flips for testing purposes
362 * @emulate_io_failures: emulate write/erase failures for testing purposes 373 * @emulate_io_failures: emulate write/erase failures for testing purposes
374 * @emulate_power_cut: emulate power cut for testing purposes
375 * @power_cut_counter: count down for writes left until emulated power cut
376 * @power_cut_min: minimum number of writes before emulating a power cut
377 * @power_cut_max: maximum number of writes until emulating a power cut
363 * @dfs_dir_name: name of debugfs directory containing files of this UBI device 378 * @dfs_dir_name: name of debugfs directory containing files of this UBI device
364 * @dfs_dir: direntry object of the UBI device debugfs directory 379 * @dfs_dir: direntry object of the UBI device debugfs directory
365 * @dfs_chk_gen: debugfs knob to enable UBI general extra checks 380 * @dfs_chk_gen: debugfs knob to enable UBI general extra checks
@@ -368,6 +383,9 @@ struct ubi_wl_entry;
368 * @dfs_disable_bgt: debugfs knob to disable the background task 383 * @dfs_disable_bgt: debugfs knob to disable the background task
369 * @dfs_emulate_bitflips: debugfs knob to emulate bit-flips 384 * @dfs_emulate_bitflips: debugfs knob to emulate bit-flips
370 * @dfs_emulate_io_failures: debugfs knob to emulate write/erase failures 385 * @dfs_emulate_io_failures: debugfs knob to emulate write/erase failures
386 * @dfs_emulate_power_cut: debugfs knob to emulate power cuts
387 * @dfs_power_cut_min: debugfs knob for minimum writes before power cut
388 * @dfs_power_cut_max: debugfs knob for maximum writes until power cut
371 */ 389 */
372struct ubi_debug_info { 390struct ubi_debug_info {
373 unsigned int chk_gen:1; 391 unsigned int chk_gen:1;
@@ -376,6 +394,10 @@ struct ubi_debug_info {
376 unsigned int disable_bgt:1; 394 unsigned int disable_bgt:1;
377 unsigned int emulate_bitflips:1; 395 unsigned int emulate_bitflips:1;
378 unsigned int emulate_io_failures:1; 396 unsigned int emulate_io_failures:1;
397 unsigned int emulate_power_cut:2;
398 unsigned int power_cut_counter;
399 unsigned int power_cut_min;
400 unsigned int power_cut_max;
379 char dfs_dir_name[UBI_DFS_DIR_LEN + 1]; 401 char dfs_dir_name[UBI_DFS_DIR_LEN + 1];
380 struct dentry *dfs_dir; 402 struct dentry *dfs_dir;
381 struct dentry *dfs_chk_gen; 403 struct dentry *dfs_chk_gen;
@@ -384,6 +406,9 @@ struct ubi_debug_info {
384 struct dentry *dfs_disable_bgt; 406 struct dentry *dfs_disable_bgt;
385 struct dentry *dfs_emulate_bitflips; 407 struct dentry *dfs_emulate_bitflips;
386 struct dentry *dfs_emulate_io_failures; 408 struct dentry *dfs_emulate_io_failures;
409 struct dentry *dfs_emulate_power_cut;
410 struct dentry *dfs_power_cut_min;
411 struct dentry *dfs_power_cut_max;
387}; 412};
388 413
389/** 414/**