summaryrefslogtreecommitdiff
path: root/fs/ubifs
diff options
context:
space:
mode:
authorAdrian Hunter <ext-adrian.hunter@nokia.com>2008-05-27 09:42:04 +0300
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2008-06-06 18:50:34 +0300
commit3cba725ac8b791171d4e958e118dadd0a5172308 (patch)
treea4638ad14f6addba5162ef16d44c64f6f31689db /fs/ubifs
parent33aef343b2093af29c1781eaa003c5337351aa7c (diff)
UBIFS: tweak asserts and gc_lnum fix
Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
Diffstat (limited to 'fs/ubifs')
-rw-r--r--fs/ubifs/debug.c37
-rw-r--r--fs/ubifs/gc.c3
-rw-r--r--fs/ubifs/recovery.c13
-rw-r--r--fs/ubifs/super.c7
-rw-r--r--fs/ubifs/ubifs.h8
5 files changed, 57 insertions, 11 deletions
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 69f1f7f16135..2698b10f4aa2 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -1337,9 +1337,34 @@ static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
return 0;
if (c->failure_mode)
return 1;
+ if (!c->fail_cnt) {
+ /* First call - decide delay to failure */
+ if (chance(1, 2)) {
+ unsigned int delay = 1 << (simple_rand() >> 11);
+
+ if (chance(1, 2)) {
+ c->fail_delay = 1;
+ c->fail_timeout = jiffies +
+ msecs_to_jiffies(delay);
+ dbg_rcvry("failing after %ums", delay);
+ } else {
+ c->fail_delay = 2;
+ c->fail_cnt_max = delay;
+ dbg_rcvry("failing after %u calls", delay);
+ }
+ }
+ c->fail_cnt += 1;
+ }
+ /* Determine if failure delay has expired */
+ if (c->fail_delay == 1) {
+ if (time_before(jiffies, c->fail_timeout))
+ return 0;
+ } else if (c->fail_delay == 2)
+ if (c->fail_cnt++ < c->fail_cnt_max)
+ return 0;
if (lnum == UBIFS_SB_LNUM) {
if (write) {
- if (chance(10, 20))
+ if (chance(1, 2))
return 0;
} else if (chance(19, 20))
return 0;
@@ -1357,16 +1382,16 @@ static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
dbg_rcvry("failing in log LEB %d", lnum);
} else if (lnum >= c->lpt_first && lnum <= c->lpt_last) {
if (write) {
- if (chance(99, 100))
+ if (chance(7, 8))
return 0;
- } else if (chance(399, 400))
+ } else if (chance(19, 20))
return 0;
dbg_rcvry("failing in LPT LEB %d", lnum);
} else if (lnum >= c->orph_first && lnum <= c->orph_last) {
if (write) {
- if (chance(9, 10))
+ if (chance(1, 2))
return 0;
- } else if (chance(39, 40))
+ } else if (chance(9, 10))
return 0;
dbg_rcvry("failing in orphan LEB %d", lnum);
} else if (lnum == c->ihead_lnum) {
@@ -1374,7 +1399,7 @@ static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
return 0;
dbg_rcvry("failing in index head LEB %d", lnum);
} else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) {
- if (chance(99, 100))
+ if (chance(9, 10))
return 0;
dbg_rcvry("failing in GC head LEB %d", lnum);
} else if (write && !RB_EMPTY_ROOT(&c->buds) &&
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index 1e8a940908ea..6d238aa10da3 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -273,7 +273,8 @@ int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp)
struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
int err = 0, lnum = lp->lnum;
- ubifs_assert(c->gc_lnum != -1 || wbuf->offs + wbuf->used == 0);
+ ubifs_assert(c->gc_lnum != -1 || wbuf->offs + wbuf->used == 0 ||
+ c->need_recovery);
ubifs_assert(c->gc_lnum != lnum);
ubifs_assert(wbuf->lnum != lnum);
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 6ee0e07bf3e3..0fdd560b8ca9 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -1125,9 +1125,17 @@ int ubifs_recover_gc_lnum(struct ubifs_info *c)
return err;
goto find_free;
}
- /* It fits, so GC it */
+ /* It fits, so GC it - use locking to keep 'ubifs_assert()' happy */
dbg_rcvry("GC'ing LEB %d", lnum);
+ mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
err = ubifs_garbage_collect_leb(c, &lp);
+ if (err >= 0) {
+ int err2 = ubifs_wbuf_sync_nolock(wbuf);
+
+ if (err2)
+ err = err2;
+ }
+ mutex_unlock(&wbuf->io_mutex);
if (err < 0) {
dbg_err("GC failed, error %d", err);
if (err == -EAGAIN)
@@ -1138,6 +1146,9 @@ int ubifs_recover_gc_lnum(struct ubifs_info *c)
dbg_err("GC returned %d", err);
return -EINVAL;
}
+ err = ubifs_leb_unmap(c, c->gc_lnum);
+ if (err)
+ return err;
dbg_rcvry("allocated LEB %d for GC", lnum);
return 0;
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index c84656fa611d..56be98f05d7b 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1345,6 +1345,10 @@ static int ubifs_remount_rw(struct ubifs_info *c)
}
wake_up_process(c->bgt);
+ err = ubifs_mount_orphans(c, c->need_recovery);
+ if (err)
+ goto out;
+
if (c->need_recovery)
err = ubifs_recover_gc_lnum(c);
else
@@ -1352,9 +1356,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
if (err)
goto out;
- err = ubifs_mount_orphans(c, c->need_recovery);
- if (err)
- goto out;
/* Check for enough log space */
lnum = c->lhead_lnum + 1;
if (lnum >= UBIFS_LOG_LNUM + c->log_lebs)
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 9bb05b9ffdc1..1d80991bbc2d 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1033,6 +1033,10 @@ struct ubifs_mount_opts {
* @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
* @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
* @failure_mode: failure mode for recovery testing
+ * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
+ * @fail_timeout: time in jiffies when delay of failure mode expires
+ * @fail_cnt: current number of calls to failure mode I/O functions
+ * @fail_cnt_max: number of calls by which to delay failure mode
*/
struct ubifs_info {
struct super_block *vfs_sb;
@@ -1257,6 +1261,10 @@ struct ubifs_info {
int old_zroot_level;
unsigned long long old_zroot_sqnum;
int failure_mode;
+ int fail_delay;
+ unsigned long fail_timeout;
+ unsigned int fail_cnt;
+ unsigned int fail_cnt_max;
#endif
};