UBIFS: improve power cut emulation testing

This patch cleans-up and improves the power cut testing:

1. Kill custom 'simple_random()' function and use 'random32()' instead.
2. Make timeout larger
3. When cutting the buffer - fill the end with random data sometimes, not
   only with 0xFFs.
4. Some times cut in the middle of the buffer, not always at the end.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
This commit is contained in:
Artem Bityutskiy 2011-06-03 16:20:03 +03:00 коммит произвёл Artem Bityutskiy
Родитель d27462a518
Коммит a7fa94a9fe
1 изменённых файлов: 50 добавлений и 41 удалений

Просмотреть файл

@ -27,11 +27,12 @@
* various local functions of those subsystems. * various local functions of those subsystems.
*/ */
#include "ubifs.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/math64.h> #include <linux/math64.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/random.h>
#include "ubifs.h"
#ifdef CONFIG_UBIFS_FS_DEBUG #ifdef CONFIG_UBIFS_FS_DEBUG
@ -2535,17 +2536,10 @@ error_dump:
return 0; return 0;
} }
/* Failure mode for recovery testing */ static inline int chance(unsigned int n, unsigned int out_of)
#define chance(n, d) (simple_rand() <= (n) * 32768LL / (d))
static unsigned int next;
static int simple_rand(void)
{ {
if (next == 0) return !!((random32() % out_of) + 1 <= n);
next = current->pid;
next = next * 1103515245 + 12345;
return (next >> 16) & 32767;
} }
static int power_cut_emulated(struct ubifs_info *c, int lnum, int write) static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
@ -2557,33 +2551,37 @@ static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
if (!d->pc_cnt) { if (!d->pc_cnt) {
/* First call - decide delay to the power cut */ /* First call - decide delay to the power cut */
if (chance(1, 2)) { if (chance(1, 2)) {
unsigned int delay = 1 << (simple_rand() >> 11); unsigned long delay;
if (chance(1, 2)) { if (chance(1, 2)) {
d->pc_delay = 1; d->pc_delay = 1;
d->pc_timeout = jiffies + /* Fail withing 1 minute */
msecs_to_jiffies(delay); delay = random32() % 60000;
ubifs_warn("failing after %ums", delay); d->pc_timeout = jiffies;
d->pc_timeout += msecs_to_jiffies(delay);
ubifs_warn("failing after %lums", delay);
} else { } else {
d->pc_delay = 2; d->pc_delay = 2;
delay = random32() % 10000;
/* Fail within 10000 operations */
d->pc_cnt_max = delay; d->pc_cnt_max = delay;
ubifs_warn("failing after %u calls", delay); ubifs_warn("failing after %lu calls", delay);
} }
} }
d->pc_cnt += 1; d->pc_cnt += 1;
} }
/* Determine if failure delay has expired */ /* Determine if failure delay has expired */
if (d->pc_delay == 1) { if (d->pc_delay == 1 && time_before(jiffies, d->pc_timeout))
if (time_before(jiffies, d->pc_timeout))
return 0; return 0;
} else if (d->pc_delay == 2) if (d->pc_delay == 2 && d->pc_cnt++ < d->pc_cnt_max)
if (d->pc_cnt++ < d->pc_cnt_max)
return 0; return 0;
if (lnum == UBIFS_SB_LNUM) { if (lnum == UBIFS_SB_LNUM) {
if (write) { if (write && chance(1, 2))
if (chance(1, 2)) return 0;
return 0; if (chance(19, 20))
} else if (chance(19, 20))
return 0; return 0;
ubifs_warn("failing in super block LEB %d", lnum); ubifs_warn("failing in super block LEB %d", lnum);
} else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) { } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) {
@ -2591,24 +2589,21 @@ static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
return 0; return 0;
ubifs_warn("failing in master LEB %d", lnum); ubifs_warn("failing in master LEB %d", lnum);
} else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) { } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) {
if (write) { if (write && chance(99, 100))
if (chance(99, 100)) return 0;
return 0; if (chance(399, 400))
} else if (chance(399, 400))
return 0; return 0;
ubifs_warn("failing in log LEB %d", lnum); ubifs_warn("failing in log LEB %d", lnum);
} else if (lnum >= c->lpt_first && lnum <= c->lpt_last) { } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) {
if (write) { if (write && chance(7, 8))
if (chance(7, 8)) return 0;
return 0; if (chance(19, 20))
} else if (chance(19, 20))
return 0; return 0;
ubifs_warn("failing in LPT LEB %d", lnum); ubifs_warn("failing in LPT LEB %d", lnum);
} else if (lnum >= c->orph_first && lnum <= c->orph_last) { } else if (lnum >= c->orph_first && lnum <= c->orph_last) {
if (write) { if (write && chance(1, 2))
if (chance(1, 2)) return 0;
return 0; if (chance(9, 10))
} else if (chance(9, 10))
return 0; return 0;
ubifs_warn("failing in orphan LEB %d", lnum); ubifs_warn("failing in orphan LEB %d", lnum);
} else if (lnum == c->ihead_lnum) { } else if (lnum == c->ihead_lnum) {
@ -2636,18 +2631,32 @@ static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
} }
d->pc_happened = 1; d->pc_happened = 1;
ubifs_warn("========== Power cut emulated ==========");
dump_stack(); dump_stack();
return 1; 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; unsigned char *p = (void *)buf;
flen = (len * (long long)simple_rand()) >> 15; from = random32() % (len + 1);
for (i = flen; i < len; i++) if (chance(1, 2))
p[i] = 0xff; 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 ubifs_info *c, int lnum, const void *buf, int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,