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 <vleschuk@gmail.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
This commit is contained in:
Victor Leschuck authored and Jeff Mahoney committed 2013-08-23 10:26:41 -04:00
1 parent d83a36e872
commit 14e8805a08
2 files changed
+5 -3

No files matched your search

+3
View File
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <sys/time.h>
#include <string.h>
#include <assert.h>
#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)
+2 -3
View File
@@ -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. */