]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/ubifs/debug.c
Merge branch 'next/deletion' of git+ssh://master.kernel.org/pub/scm/linux/kernel...
[mv-sheeva.git] / fs / ubifs / debug.c
index 059c586b5ef840b6e00f9a6fd22a7f36810a7cb9..eef109a1a92772d67cfe7a5693e113c8c801dbec 100644 (file)
  * various local functions of those subsystems.
  */
 
-#define UBIFS_DBG_PRESERVE_UBI
-
-#include "ubifs.h"
 #include <linux/module.h>
 #include <linux/debugfs.h>
 #include <linux/math64.h>
 #include <linux/uaccess.h>
+#include <linux/random.h>
+#include "ubifs.h"
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
@@ -2537,121 +2536,52 @@ error_dump:
        return 0;
 }
 
-/* Failure mode for recovery testing */
-
-#define chance(n, d) (simple_rand() <= (n) * 32768LL / (d))
-
-struct failure_mode_info {
-       struct list_head list;
-       struct ubifs_info *c;
-};
-
-static LIST_HEAD(fmi_list);
-static DEFINE_SPINLOCK(fmi_lock);
-
-static unsigned int next;
-
-static int simple_rand(void)
-{
-       if (next == 0)
-               next = current->pid;
-       next = next * 1103515245 + 12345;
-       return (next >> 16) & 32767;
-}
-
-static void failure_mode_init(struct ubifs_info *c)
-{
-       struct failure_mode_info *fmi;
-
-       fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS);
-       if (!fmi) {
-               ubifs_err("Failed to register failure mode - no memory");
-               return;
-       }
-       fmi->c = c;
-       spin_lock(&fmi_lock);
-       list_add_tail(&fmi->list, &fmi_list);
-       spin_unlock(&fmi_lock);
-}
-
-static void failure_mode_exit(struct ubifs_info *c)
+static inline int chance(unsigned int n, unsigned int out_of)
 {
-       struct failure_mode_info *fmi, *tmp;
+       return !!((random32() % out_of) + 1 <= n);
 
-       spin_lock(&fmi_lock);
-       list_for_each_entry_safe(fmi, tmp, &fmi_list, list)
-               if (fmi->c == c) {
-                       list_del(&fmi->list);
-                       kfree(fmi);
-               }
-       spin_unlock(&fmi_lock);
-}
-
-static struct ubifs_info *dbg_find_info(struct ubi_volume_desc *desc)
-{
-       struct failure_mode_info *fmi;
-
-       spin_lock(&fmi_lock);
-       list_for_each_entry(fmi, &fmi_list, list)
-               if (fmi->c->ubi == desc) {
-                       struct ubifs_info *c = fmi->c;
-
-                       spin_unlock(&fmi_lock);
-                       return c;
-               }
-       spin_unlock(&fmi_lock);
-       return NULL;
 }
 
-static int in_failure_mode(struct ubi_volume_desc *desc)
+static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
 {
-       struct ubifs_info *c = dbg_find_info(desc);
+       struct ubifs_debug_info *d = c->dbg;
 
-       if (c && dbg_is_tst_rcvry(c))
-               return c->dbg->failure_mode;
-       return 0;
-}
+       ubifs_assert(dbg_is_tst_rcvry(c));
 
-static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
-{
-       struct ubifs_info *c = dbg_find_info(desc);
-       struct ubifs_debug_info *d;
-
-       if (!c || !dbg_is_tst_rcvry(c))
-               return 0;
-       d = c->dbg;
-       if (d->failure_mode)
-               return 1;
-       if (!d->fail_cnt) {
-               /* First call - decide delay to failure */
+       if (!d->pc_cnt) {
+               /* First call - decide delay to the power cut */
                if (chance(1, 2)) {
-                       unsigned int delay = 1 << (simple_rand() >> 11);
+                       unsigned long delay;
 
                        if (chance(1, 2)) {
-                               d->fail_delay = 1;
-                               d->fail_timeout = jiffies +
-                                                 msecs_to_jiffies(delay);
-                               ubifs_warn("failing after %ums", delay);
+                               d->pc_delay = 1;
+                               /* Fail withing 1 minute */
+                               delay = random32() % 60000;
+                               d->pc_timeout = jiffies;
+                               d->pc_timeout += msecs_to_jiffies(delay);
+                               ubifs_warn("failing after %lums", delay);
                        } else {
-                               d->fail_delay = 2;
-                               d->fail_cnt_max = delay;
-                               ubifs_warn("failing after %u calls", delay);
+                               d->pc_delay = 2;
+                               delay = random32() % 10000;
+                               /* Fail within 10000 operations */
+                               d->pc_cnt_max = delay;
+                               ubifs_warn("failing after %lu calls", delay);
                        }
                }
-               d->fail_cnt += 1;
+
+               d->pc_cnt += 1;
        }
+
        /* Determine if failure delay has expired */
-       if (d->fail_delay == 1) {
-               if (time_before(jiffies, d->fail_timeout))
+       if (d->pc_delay == 1 && time_before(jiffies, d->pc_timeout))
                        return 0;
-       } else if (d->fail_delay == 2)
-               if (d->fail_cnt++ < d->fail_cnt_max)
+       if (d->pc_delay == 2 && d->pc_cnt++ < d->pc_cnt_max)
                        return 0;
+
        if (lnum == UBIFS_SB_LNUM) {
-               if (write) {
-                       if (chance(1, 2))
-                               return 0;
-               } else if (chance(19, 20))
+               if (write && chance(1, 2))
+                       return 0;
+               if (chance(19, 20))
                        return 0;
                ubifs_warn("failing in super block LEB %d", lnum);
        } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) {
@@ -2659,24 +2589,21 @@ static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
                        return 0;
                ubifs_warn("failing in master LEB %d", lnum);
        } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) {
-               if (write) {
-                       if (chance(99, 100))
-                               return 0;
-               } else if (chance(399, 400))
+               if (write && chance(99, 100))
+                       return 0;
+               if (chance(399, 400))
                        return 0;
                ubifs_warn("failing in log LEB %d", lnum);
        } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) {
-               if (write) {
-                       if (chance(7, 8))
-                               return 0;
-               } else if (chance(19, 20))
+               if (write && chance(7, 8))
+                       return 0;
+               if (chance(19, 20))
                        return 0;
                ubifs_warn("failing in LPT LEB %d", lnum);
        } else if (lnum >= c->orph_first && lnum <= c->orph_last) {
-               if (write) {
-                       if (chance(1, 2))
-                               return 0;
-               } else if (chance(9, 10))
+               if (write && chance(1, 2))
+                       return 0;
+               if (chance(9, 10))
                        return 0;
                ubifs_warn("failing in orphan LEB %d", lnum);
        } else if (lnum == c->ihead_lnum) {
@@ -2703,32 +2630,47 @@ static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
                ubifs_warn("failing in bud LEB %d commit not running", lnum);
        }
 
-       d->failure_mode = 1;
+       d->pc_happened = 1;
+       ubifs_warn("========== Power cut emulated ==========");
        dump_stack();
        return 1;
 }
 
-static void cut_data(const void *buf, int len)
+static void cut_data(const void *buf, unsigned int len)
 {
-       int flen, i;
+       unsigned int from, to, i, ffs = chance(1, 2);
        unsigned char *p = (void *)buf;
 
-       flen = (len * (long long)simple_rand()) >> 15;
-       for (i = flen; i < len; i++)
-               p[i] = 0xff;
+       from = random32() % (len + 1);
+       if (chance(1, 2))
+               to = random32() % (len - from + 1);
+       else
+               to = len;
+
+       if (from < to)
+               ubifs_warn("filled bytes %u-%u with %s", from, to - 1,
+                          ffs ? "0xFFs" : "random data");
+
+       if (ffs)
+               for (i = from; i < to; i++)
+                       p[i] = 0xFF;
+       else
+               for (i = from; i < to; i++)
+                       p[i] = random32() % 0x100;
 }
 
-int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
+int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
                  int offs, int len, int dtype)
 {
        int err, failing;
 
-       if (in_failure_mode(desc))
+       if (c->dbg->pc_happened)
                return -EROFS;
-       failing = do_fail(desc, lnum, 1);
+
+       failing = power_cut_emulated(c, lnum, 1);
        if (failing)
                cut_data(buf, len);
-       err = ubi_leb_write(desc, lnum, buf, offs, len, dtype);
+       err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
        if (err)
                return err;
        if (failing)
@@ -2736,45 +2678,51 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
        return 0;
 }
 
-int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
+int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
                   int len, int dtype)
 {
        int err;
 
-       if (do_fail(desc, lnum, 1))
+       if (c->dbg->pc_happened)
                return -EROFS;
-       err = ubi_leb_change(desc, lnum, buf, len, dtype);
+       if (power_cut_emulated(c, lnum, 1))
+               return -EROFS;
+       err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
        if (err)
                return err;
-       if (do_fail(desc, lnum, 1))
+       if (power_cut_emulated(c, lnum, 1))
                return -EROFS;
        return 0;
 }
 
-int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum)
+int dbg_leb_unmap(struct ubifs_info *c, int lnum)
 {
        int err;
 
-       if (do_fail(desc, lnum, 0))
+       if (c->dbg->pc_happened)
+               return -EROFS;
+       if (power_cut_emulated(c, lnum, 0))
                return -EROFS;
-       err = ubi_leb_unmap(desc, lnum);
+       err = ubi_leb_unmap(c->ubi, lnum);
        if (err)
                return err;
-       if (do_fail(desc, lnum, 0))
+       if (power_cut_emulated(c, lnum, 0))
                return -EROFS;
        return 0;
 }
 
-int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
+int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype)
 {
        int err;
 
-       if (do_fail(desc, lnum, 0))
+       if (c->dbg->pc_happened)
+               return -EROFS;
+       if (power_cut_emulated(c, lnum, 0))
                return -EROFS;
-       err = ubi_leb_map(desc, lnum, dtype);
+       err = ubi_leb_map(c->ubi, lnum, dtype);
        if (err)
                return err;
-       if (do_fail(desc, lnum, 0))
+       if (power_cut_emulated(c, lnum, 0))
                return -EROFS;
        return 0;
 }
@@ -3212,7 +3160,6 @@ int ubifs_debugging_init(struct ubifs_info *c)
        if (!c->dbg)
                return -ENOMEM;
 
-       failure_mode_init(c);
        return 0;
 }
 
@@ -3222,7 +3169,6 @@ int ubifs_debugging_init(struct ubifs_info *c)
  */
 void ubifs_debugging_exit(struct ubifs_info *c)
 {
-       failure_mode_exit(c);
        kfree(c->dbg);
 }