From 14e8805a0835776167cf435aaf91a56b74746d2f Mon Sep 17 00:00:00 2001 From: Victor Leschuck Date: Fri, 23 Aug 2013 10:26:32 -0400 Subject: [PATCH] journal: fix division by 0 with one transaction in log We have met a situation when reiserfsck segfaulted on one of our partitions. I have performed a small research and the cause appeared to be wrong detection of transaction count. Our FS had only one journal transaction, however trans_count which was passed to progbar_update() as maximum transaction value was detected as (last_transaction - first_transaction) which in our case was 0. Thus progbar_update() resulted in segmentation fault: (gdb) bt "Replaying journal", curr=1, max=0, dpynum=1) at progbar.c:80 Here is part of debugreiserfs -j output Journal header (block #8210 of ./partition.bug): j_last_flush_trans_id 0 j_first_unflushed_offset 0 j_mount_id 10 Device [0x0] Magic [0x4f0a099e] Size 8193 blocks (including 1 for journal header) (first block 18) Max transaction length 1024 blocks Max batch size 900 blocks Max commit age 30 Mountid 10, transid 10, desc 18, length 2, commit 21 I successfully reproduced it on versions 3.6.21 (which we were using) and 3.6.23 (which I believe is the latest). Attaching patch. Let me know your opinion. If I am wrong, please comment, if I am correct, feel free to include patch into sources. Thanks. Signed-off-by: Victor Leschuk Signed-off-by: Jeff Mahoney --- lib/progbar.c | 3 +++ reiserfscore/journal.c | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/progbar.c b/lib/progbar.c index fde2e70..9ecc803 100644 --- a/lib/progbar.c +++ b/lib/progbar.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "progbar.h" @@ -37,6 +38,8 @@ int progbar_update(struct progbar * ctx, const char *label, int curr, int max, struct timeval tv; int dpywidth; int fixed_percent; + assert (curr >= 0); + assert (max > 0); float percent = ((float) curr) / ((float) max) * 100; if (ctx->flags & E2F_FLAG_PROG_SUPPRESS) diff --git a/reiserfscore/journal.c b/reiserfscore/journal.c index a3ebcde..00e1939 100644 --- a/reiserfscore/journal.c +++ b/reiserfscore/journal.c @@ -818,13 +818,12 @@ int replay_journal (reiserfs_filsys_t * fs) control.trans_id = get_jh_last_flushed (j_head); control.desc_blocknr = get_jh_replay_start_offset (j_head); - if (!get_boundary_transactions (fs, &cur, &newest)) { + trans_count = get_boundary_transactions (fs, &cur, &newest); + if (!trans_count) { reiserfs_warning (stderr, "No transactions found\n"); return 0; } - trans_count = newest.trans_id - cur.trans_id; - /* Smth strange with journal header or journal. We cannot say for sure what was the last replaied transaction, but relying on JH data is preferable. */