UBI: power cut emulation for testing
[deliverable/linux.git] / drivers / mtd / ubi / debug.c
index 7335c9ff9d997110e479c72aeb4b7bd43a772ab4..b077e43b5ba913b2ba208ed54673c3fe291afc66 100644 (file)
@@ -263,7 +263,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
        struct dentry *dent = file->f_path.dentry;
        struct ubi_device *ubi;
        struct ubi_debug_info *d;
-       char buf[3];
+       char buf[8];
        int val;
 
        ubi = ubi_get_device(ubi_num);
@@ -275,12 +275,30 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
                val = d->chk_gen;
        else if (dent == d->dfs_chk_io)
                val = d->chk_io;
+       else if (dent == d->dfs_chk_fastmap)
+               val = d->chk_fastmap;
        else if (dent == d->dfs_disable_bgt)
                val = d->disable_bgt;
        else if (dent == d->dfs_emulate_bitflips)
                val = d->emulate_bitflips;
        else if (dent == d->dfs_emulate_io_failures)
                val = d->emulate_io_failures;
+       else if (dent == d->dfs_emulate_power_cut) {
+               snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut);
+               count = simple_read_from_buffer(user_buf, count, ppos,
+                                               buf, strlen(buf));
+               goto out;
+       } else if (dent == d->dfs_power_cut_min) {
+               snprintf(buf, sizeof(buf), "%u\n", d->power_cut_min);
+               count = simple_read_from_buffer(user_buf, count, ppos,
+                                               buf, strlen(buf));
+               goto out;
+       } else if (dent == d->dfs_power_cut_max) {
+               snprintf(buf, sizeof(buf), "%u\n", d->power_cut_max);
+               count = simple_read_from_buffer(user_buf, count, ppos,
+                                               buf, strlen(buf));
+               goto out;
+       }
        else {
                count = -EINVAL;
                goto out;
@@ -309,7 +327,7 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
        struct ubi_device *ubi;
        struct ubi_debug_info *d;
        size_t buf_size;
-       char buf[8];
+       char buf[8] = {0};
        int val;
 
        ubi = ubi_get_device(ubi_num);
@@ -323,6 +341,21 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
                goto out;
        }
 
+       if (dent == d->dfs_power_cut_min) {
+               if (kstrtouint(buf, 0, &d->power_cut_min) != 0)
+                       count = -EINVAL;
+               goto out;
+       } else if (dent == d->dfs_power_cut_max) {
+               if (kstrtouint(buf, 0, &d->power_cut_max) != 0)
+                       count = -EINVAL;
+               goto out;
+       } else if (dent == d->dfs_emulate_power_cut) {
+               if (kstrtoint(buf, 0, &val) != 0)
+                       count = -EINVAL;
+               d->emulate_power_cut = val;
+               goto out;
+       }
+
        if (buf[0] == '1')
                val = 1;
        else if (buf[0] == '0')
@@ -336,6 +369,8 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
                d->chk_gen = val;
        else if (dent == d->dfs_chk_io)
                d->chk_io = val;
+       else if (dent == d->dfs_chk_fastmap)
+               d->chk_fastmap = val;
        else if (dent == d->dfs_disable_bgt)
                d->disable_bgt = val;
        else if (dent == d->dfs_emulate_bitflips)
@@ -406,6 +441,13 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
                goto out_remove;
        d->dfs_chk_io = dent;
 
+       fname = "chk_fastmap";
+       dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
+                                  &dfs_fops);
+       if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_chk_fastmap = dent;
+
        fname = "tst_disable_bgt";
        dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
                                   &dfs_fops);
@@ -427,6 +469,27 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
                goto out_remove;
        d->dfs_emulate_io_failures = dent;
 
+       fname = "tst_emulate_power_cut";
+       dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
+                                  &dfs_fops);
+       if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_emulate_power_cut = dent;
+
+       fname = "tst_emulate_power_cut_min";
+       dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
+                                  &dfs_fops);
+       if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_power_cut_min = dent;
+
+       fname = "tst_emulate_power_cut_max";
+       dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
+                                  &dfs_fops);
+       if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_power_cut_max = dent;
+
        return 0;
 
 out_remove:
@@ -447,3 +510,36 @@ void ubi_debugfs_exit_dev(struct ubi_device *ubi)
        if (IS_ENABLED(CONFIG_DEBUG_FS))
                debugfs_remove_recursive(ubi->dbg.dfs_dir);
 }
+
+/**
+ * ubi_dbg_power_cut - emulate a power cut if it is time to do so
+ * @ubi: UBI device description object
+ * @caller: Flags set to indicate from where the function is being called
+ *
+ * Returns non-zero if a power cut was emulated, zero if not.
+ */
+int ubi_dbg_power_cut(struct ubi_device *ubi, int caller)
+{
+       unsigned int range;
+
+       if ((ubi->dbg.emulate_power_cut & caller) == 0)
+               return 0;
+
+       if (ubi->dbg.power_cut_counter == 0) {
+               ubi->dbg.power_cut_counter = ubi->dbg.power_cut_min;
+
+               if (ubi->dbg.power_cut_max > ubi->dbg.power_cut_min) {
+                       range = ubi->dbg.power_cut_max - ubi->dbg.power_cut_min;
+                       ubi->dbg.power_cut_counter += prandom_u32() % range;
+               }
+               return 0;
+       }
+
+       ubi->dbg.power_cut_counter--;
+       if (ubi->dbg.power_cut_counter)
+               return 0;
+
+       ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX");
+       ubi_ro_mode(ubi);
+       return 1;
+}
This page took 0.025686 seconds and 5 git commands to generate.