Re: Reiserfs: how to mount without journal replay?

Chris Mason
2001-09-04T20:54:03Z

On Thursday, August 30, 2001 11:50:05 PM +0200 Pavel Machek <pavel@suse.cz> wrote:

> ext2 is willing to mount ro even with known inconsistencies. SuSE 7.1
> does not come with 'live filesystem' and install cd does not have
> reiserfsck on it. Too bad. You have to install somewhere to be able to
> run reiserfsck on suse7.1.

If your reiserfs isn't consistent, your chances of finding reiserfsck in
the broken btree are slim to none. A readonly mount in this case is
unlikely to find a valid, fully intact reiserfsck executable.

The best reason I've heard for a -o noreplay option is for shared
readonly mounts. The patch below adds that, with a few conditions:

mount -o noreplay /dev/xxx /mnt

If no log replay is required, rw mount succeeds (ro is -o noreplay,ro is used).

Otherwise, no replay is done, mount is changed to readonly. Later
attempts at mount -o rw,remount /mnt will fail with -EIO.

This is lightly tested, and not intended for inclusion anywhere. If
there's enough interest, I'll verify and send in.

(against 2.4.10pre4)

-chris

#
--- linux/include/linux/reiserfs_fs_sb.h Tue Sep 4 14:37:27 2001
+++ linux/include/linux/reiserfs_fs_sb.h Tue Sep 4 14:39:44 2001
@@ -387,6 +387,7 @@
#define REISERFS_NO_UNHASHED_RELOCATION 12
#define REISERFS_HASHED_RELOCATION 13
#define REISERFS_TEST4 14
+#define REISERFS_NO_REPLAY 15

#define REISERFS_TEST1 11
#define REISERFS_TEST2 12
@@ -401,6 +402,7 @@
#define reiserfs_no_unhashed_relocation(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NO_UNHASHED_RELOCATION))
#define reiserfs_hashed_relocation(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_HASHED_RELOCATION))
#define reiserfs_test4(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_TEST4))
+#define reiserfs_noreplay(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NO_REPLAY))

#define dont_have_tails(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << NOTAIL))
#define replay_only(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REPLAYONLY))
--- linux/include/linux/reiserfs_fs.h Tue Sep 4 14:37:27 2001
+++ linux/include/linux/reiserfs_fs.h Tue Sep 4 15:47:43 2001
@@ -1723,6 +1723,7 @@
*/
#define JOURNAL_BUFFER(j,n) ((j)->j_ap_blocks[((j)->j_start + (n)) % JOURNAL_BLOCK_COUNT])

+int reiserfs_replay_error(struct super_block *s) ;
void reiserfs_wait_on_write_block(struct super_block *s) ;
void reiserfs_block_writes(struct reiserfs_transaction_handle *th) ;
void reiserfs_allow_writes(struct super_block *s) ;
--- linux/fs/reiserfs/journal.c Sun Sep 2 03:52:37 2001
+++ linux/fs/reiserfs/journal.c Tue Sep 4 15:57:59 2001
@@ -96,6 +96,7 @@

/* state bits for the journal */
#define WRITERS_BLOCKED 1 /* set when new writers not allowed */
+#define REPLAY_ERROR 2 /* set when -o noreplay forces unclean mount */

static int do_journal_end(struct reiserfs_transaction_handle *,struct super_block *,unsigned long nblocks,int flags) ;
static int flush_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) ;
@@ -106,6 +107,10 @@
memset(SB_JOURNAL(p_s_sb)->j_hash_table, 0, JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *)) ;
}

+int reiserfs_replay_error(struct super_block *s) {
+ return test_bit(REPLAY_ERROR, &SB_JOURNAL(s)->j_state) ;
+}
+
/*
** clears BH_Dirty and sticks the buffer on the clean list. Called because I can't allow refile_buffer to
** make schedule happen after I've freed a block. Look at remove_from_transaction and journal_mark_freed for
@@ -1651,12 +1656,20 @@
brelse(d_bh) ;
}

- if (continue_replay && is_read_only(p_s_sb->s_dev)) {
- printk("clm-2076: device is readonly, unable to replay log\n") ;
- return -1 ;
- }
- if (continue_replay && (p_s_sb->s_flags & MS_RDONLY)) {
- printk("Warning, log replay starting on readonly filesystem\n") ;
+ if (continue_replay) {
+ if (is_read_only(p_s_sb->s_dev)) {
+ printk("clm-2076: device is readonly, unable to replay log\n") ;
+ return -1 ;
+ }
+ if (reiserfs_noreplay(p_s_sb)) {
+ printk("-o noreplay used to force unclean mount. FS set to readonly\n");
+ p_s_sb->s_flags |= MS_RDONLY ;
+ set_bit(REPLAY_ERROR, &SB_JOURNAL(p_s_sb)->j_state) ;
+ return 0 ;
+ }
+ if (p_s_sb->s_flags & MS_RDONLY) {
+ printk("Warning, log replay starting on readonly filesystem\n") ;
+ }
}

/* ok, there are transactions that need to be replayed. start with the first log block, find
@@ -2022,6 +2035,12 @@
th->t_super = p_s_sb ; /* others will check this for the don't log flag */
return 0 ;
}
+
+ if (test_bit(REPLAY_ERROR, &SB_JOURNAL(p_s_sb)->j_state)) {
+ printk("clm-2100: calling journal_begin after replay errors\n") ;
+ BUG() ;
+ }
+

relock:
lock_journal(p_s_sb) ;
--- linux/fs/reiserfs/super.c Tue Sep 4 14:37:28 2001
+++ linux/fs/reiserfs/super.c Tue Sep 4 15:58:02 2001
@@ -176,6 +176,8 @@
set_bit (REISERFS_HASHED_RELOCATION, mount_options);
} else if (!strcmp (this_char, "test4")) {
set_bit (REISERFS_TEST4, mount_options);
+ } else if (!strcmp (this_char, "noreplay")) {
+ set_bit (REISERFS_NO_REPLAY, mount_options);
} else if (!strcmp (this_char, "nolog")) {
reiserfs_warning("reiserfs: nolog mount option not supported yet\n");
} else if (!strcmp (this_char, "replayonly")) {
@@ -268,6 +270,14 @@
journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
s->s_dirt = 0;
} else {
+ /* if we are currently readonly, and were mounted with noreplay,
+ ** we need to check if replay failed and the journal params are not
+ ** correctly set. If so, we cannot allow a rw mount, horrible, horrible
+ ** things would happen
+ */
+ if (reiserfs_replay_error(s)) {
+ return -EIO ;
+ }
s->u.reiserfs_sb.s_mount_state = sb_state(rs) ;
s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
journal_begin(&th, s, 10) ;