Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 1 | /* |
| 2 | * journal.c --- code for handling the "ext3" journal |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 3 | * |
| 4 | * Copyright (C) 2000 Andreas Dilger |
| 5 | * Copyright (C) 2000 Theodore Ts'o |
| 6 | * |
| 7 | * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie |
| 8 | * Copyright (C) 1999 Red Hat Software |
| 9 | * |
| 10 | * This file may be redistributed under the terms of the |
| 11 | * GNU General Public License version 2 or at your discretion |
| 12 | * any later version. |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 13 | */ |
| 14 | |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 15 | #ifdef HAVE_SYS_MOUNT_H |
| 16 | #include <sys/mount.h> |
| 17 | #define MNT_FL (MS_MGC_VAL | MS_RDONLY) |
| 18 | #endif |
| 19 | #ifdef HAVE_SYS_STAT_H |
| 20 | #include <sys/stat.h> |
| 21 | #endif |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 22 | |
Theodore Ts'o | 53ef44c | 2001-01-06 05:55:58 +0000 | [diff] [blame] | 23 | #define E2FSCK_INCLUDE_INLINE_FUNCS |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 24 | #include "jfs_user.h" |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 25 | #include "problem.h" |
| 26 | #include "uuid/uuid.h" |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 27 | |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 28 | #ifdef JFS_DEBUG |
| 29 | static int bh_count = 0; |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 30 | int journal_enable_debug = 0; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 31 | #endif |
| 32 | |
Theodore Ts'o | b2f9319 | 2000-12-30 20:33:42 +0000 | [diff] [blame] | 33 | /* Kernel compatibility functions for handling the journal. These allow us |
| 34 | * to use the recovery.c file virtually unchanged from the kernel, so we |
| 35 | * don't have to do much to keep kernel and user recovery in sync. |
| 36 | */ |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 37 | int bmap(struct inode *inode, int block) |
| 38 | { |
| 39 | int retval; |
| 40 | blk_t phys; |
| 41 | |
| 42 | retval = ext2fs_bmap(inode->i_ctx->fs, inode->i_ino, &inode->i_ext2, |
| 43 | NULL, 0, block, &phys); |
| 44 | |
| 45 | if (retval) |
| 46 | com_err(inode->i_ctx->device_name, retval, |
| 47 | _("bmap journal inode %ld, block %d\n"), |
| 48 | inode->i_ino, block); |
| 49 | |
| 50 | return phys; |
| 51 | } |
| 52 | |
| 53 | struct buffer_head *getblk(e2fsck_t ctx, blk_t blocknr, int blocksize) |
| 54 | { |
| 55 | struct buffer_head *bh; |
| 56 | |
| 57 | bh = e2fsck_allocate_memory(ctx, sizeof(*bh), "block buffer"); |
| 58 | if (!bh) |
| 59 | return NULL; |
| 60 | |
| 61 | jfs_debug(4, "getblk for block %lu (%d bytes)(total %d)\n", |
Theodore Ts'o | 53ef44c | 2001-01-06 05:55:58 +0000 | [diff] [blame] | 62 | (unsigned long) blocknr, blocksize, ++bh_count); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 63 | |
| 64 | bh->b_ctx = ctx; |
| 65 | bh->b_size = blocksize; |
| 66 | bh->b_blocknr = blocknr; |
| 67 | |
| 68 | return bh; |
| 69 | } |
| 70 | |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 71 | void ll_rw_block(int rw, int nr, struct buffer_head *bhp[]) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 72 | { |
| 73 | int retval; |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 74 | struct buffer_head *bh; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 75 | |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 76 | for (; nr > 0; --nr) { |
| 77 | bh = *bhp++; |
| 78 | if (rw == READ && !bh->b_uptodate) { |
| 79 | jfs_debug(3, "reading block %lu/%p\n", |
Theodore Ts'o | 53ef44c | 2001-01-06 05:55:58 +0000 | [diff] [blame] | 80 | (unsigned long) bh->b_blocknr, (void *) bh); |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 81 | retval = io_channel_read_blk(bh->b_ctx->fs->io, |
| 82 | bh->b_blocknr, |
| 83 | 1, bh->b_data); |
| 84 | if (retval) { |
| 85 | com_err(bh->b_ctx->device_name, retval, |
| 86 | "while reading block %ld\n", |
| 87 | bh->b_blocknr); |
| 88 | bh->b_err = retval; |
| 89 | continue; |
| 90 | } |
| 91 | bh->b_uptodate = 1; |
| 92 | } else if (rw == WRITE && bh->b_dirty) { |
| 93 | jfs_debug(3, "writing block %lu/%p\n", |
Theodore Ts'o | 53ef44c | 2001-01-06 05:55:58 +0000 | [diff] [blame] | 94 | (unsigned long) bh->b_blocknr, (void *) bh); |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 95 | retval = io_channel_write_blk(bh->b_ctx->fs->io, |
| 96 | bh->b_blocknr, |
| 97 | 1, bh->b_data); |
| 98 | if (retval) { |
| 99 | com_err(bh->b_ctx->device_name, retval, |
| 100 | "while writing block %ld\n", |
| 101 | bh->b_blocknr); |
| 102 | bh->b_err = retval; |
| 103 | continue; |
| 104 | } |
| 105 | bh->b_dirty = 0; |
| 106 | bh->b_uptodate = 1; |
| 107 | } else |
| 108 | jfs_debug(3, "no-op %s for block %lu\n", |
| 109 | rw == READ ? "read" : "write", |
Theodore Ts'o | 53ef44c | 2001-01-06 05:55:58 +0000 | [diff] [blame] | 110 | (unsigned long) bh->b_blocknr); |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 111 | } |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 112 | } |
| 113 | |
| 114 | void mark_buffer_dirty(struct buffer_head *bh, int dummy) |
| 115 | { |
| 116 | bh->b_dirty = dummy | 1; /* use dummy to avoid unused variable */ |
| 117 | } |
| 118 | |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 119 | static void mark_buffer_clean(struct buffer_head * bh) |
| 120 | { |
| 121 | bh->b_dirty = 0; |
| 122 | } |
| 123 | |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 124 | void brelse(struct buffer_head *bh) |
| 125 | { |
| 126 | if (bh->b_dirty) |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 127 | ll_rw_block(WRITE, 1, &bh); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 128 | jfs_debug(3, "freeing block %lu/%p (total %d)\n", |
Theodore Ts'o | 53ef44c | 2001-01-06 05:55:58 +0000 | [diff] [blame] | 129 | (unsigned long) bh->b_blocknr, (void *) bh, --bh_count); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 130 | ext2fs_free_mem((void **) &bh); |
| 131 | } |
| 132 | |
| 133 | int buffer_uptodate(struct buffer_head *bh) |
| 134 | { |
| 135 | return bh->b_uptodate; |
| 136 | } |
| 137 | |
| 138 | void wait_on_buffer(struct buffer_head *bh) |
| 139 | { |
| 140 | if (!bh->b_uptodate) |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 141 | ll_rw_block(READ, 1, &bh); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 142 | } |
| 143 | |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 144 | |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 145 | static void e2fsck_clear_recover(e2fsck_t ctx, int error) |
| 146 | { |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 147 | ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 148 | |
| 149 | /* if we had an error doing journal recovery, we need a full fsck */ |
| 150 | if (error) |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 151 | ctx->fs->super->s_state &= ~EXT2_VALID_FS; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 152 | ext2fs_mark_super_dirty(ctx->fs); |
| 153 | } |
| 154 | |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 155 | static errcode_t e2fsck_journal_init_inode(e2fsck_t ctx, |
| 156 | struct ext2_super_block *s, |
| 157 | ext2_ino_t journal_inum, |
| 158 | journal_t **journal) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 159 | { |
| 160 | struct inode *inode; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 161 | struct buffer_head *bh; |
| 162 | blk_t start; |
| 163 | int retval; |
| 164 | |
Theodore Ts'o | 86c627e | 2001-01-11 15:12:14 +0000 | [diff] [blame] | 165 | jfs_debug(1, "Using journal inode %u\n", journal_inum); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 166 | *journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal"); |
| 167 | if (!*journal) { |
| 168 | return EXT2_ET_NO_MEMORY; |
| 169 | } |
| 170 | |
| 171 | inode = e2fsck_allocate_memory(ctx, sizeof(*inode), "journal inode"); |
| 172 | if (!inode) { |
| 173 | retval = EXT2_ET_NO_MEMORY; |
| 174 | goto exit_journal; |
| 175 | } |
| 176 | |
| 177 | inode->i_ctx = ctx; |
| 178 | inode->i_ino = journal_inum; |
| 179 | retval = ext2fs_read_inode(ctx->fs, journal_inum, &inode->i_ext2); |
| 180 | if (retval) |
| 181 | goto exit_inode; |
| 182 | |
| 183 | (*journal)->j_dev = ctx; |
| 184 | (*journal)->j_inode = inode; |
| 185 | (*journal)->j_blocksize = ctx->fs->blocksize; |
| 186 | (*journal)->j_maxlen = inode->i_ext2.i_size / (*journal)->j_blocksize; |
| 187 | |
| 188 | if (!inode->i_ext2.i_links_count || |
| 189 | !LINUX_S_ISREG(inode->i_ext2.i_mode) || |
| 190 | (*journal)->j_maxlen < JFS_MIN_JOURNAL_BLOCKS || |
| 191 | (start = bmap(inode, 0)) == 0) { |
| 192 | retval = EXT2_ET_BAD_INODE_NUM; |
| 193 | goto exit_inode; |
| 194 | } |
| 195 | |
| 196 | bh = getblk(ctx, start, (*journal)->j_blocksize); |
| 197 | if (!bh) { |
| 198 | retval = EXT2_ET_NO_MEMORY; |
| 199 | goto exit_inode; |
| 200 | } |
| 201 | (*journal)->j_sb_buffer = bh; |
| 202 | (*journal)->j_superblock = (journal_superblock_t *)bh->b_data; |
| 203 | |
| 204 | return 0; |
| 205 | |
| 206 | exit_inode: |
| 207 | ext2fs_free_mem((void **)&inode); |
| 208 | exit_journal: |
| 209 | ext2fs_free_mem((void **)journal); |
| 210 | |
| 211 | return retval; |
| 212 | } |
| 213 | |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 214 | static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **journal) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 215 | { |
| 216 | char uuid_str[40]; |
| 217 | struct problem_context pctx; |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 218 | struct ext2_super_block *sb = ctx->fs->super; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 219 | |
| 220 | clear_problem_context(&pctx); |
| 221 | |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 222 | if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) { |
Theodore Ts'o | 4e009f6 | 2001-02-08 02:26:04 +0000 | [diff] [blame] | 223 | /* FIXME: check if dev is valid block dev, has a journal */ |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 224 | if (sb->s_journal_dev) { |
| 225 | pctx.num = sb->s_journal_dev; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 226 | /* this problem aborts on -y, -p, unsupported on -n */ |
| 227 | if (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_DEV, &pctx)) |
| 228 | return EXT2_ET_UNSUPP_FEATURE; |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 229 | sb->s_journal_dev = 0; |
| 230 | sb->s_state &= ~EXT2_VALID_FS; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 231 | ext2fs_mark_super_dirty(ctx->fs); |
| 232 | } |
Theodore Ts'o | a9ca201 | 2001-01-12 21:53:25 +0000 | [diff] [blame] | 233 | /* FIXME: check if UUID is valid block dev, has a journal */ |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 234 | if (!uuid_is_null(sb->s_journal_uuid)) { |
| 235 | uuid_unparse(sb->s_journal_uuid, uuid_str); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 236 | pctx.str = uuid_str; |
| 237 | /* this problem aborts on -y, -p, unsupported on -n */ |
| 238 | if (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_UUID, &pctx)) |
| 239 | return EXT2_ET_UNSUPP_FEATURE; |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 240 | uuid_clear(sb->s_journal_uuid); |
| 241 | sb->s_state &= ~EXT2_VALID_FS; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 242 | ext2fs_mark_super_dirty(ctx->fs); |
| 243 | } |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 244 | if (!sb->s_journal_inum) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 245 | return EXT2_ET_BAD_INODE_NUM; |
| 246 | } |
| 247 | |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 248 | if (sb->s_journal_dev) { |
| 249 | pctx.num = sb->s_journal_dev; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 250 | if (!fix_problem(ctx, PR_0_JOURNAL_BAD_DEV, &pctx)) |
| 251 | return EXT2_ET_UNSUPP_FEATURE; |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 252 | sb->s_journal_dev = 0; |
| 253 | sb->s_state &= ~EXT2_VALID_FS; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 254 | ext2fs_mark_super_dirty(ctx->fs); |
| 255 | } |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 256 | if (!uuid_is_null(sb->s_journal_uuid)) { |
| 257 | uuid_unparse(sb->s_journal_uuid, uuid_str); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 258 | pctx.str = uuid_str; |
| 259 | if (!fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx)) |
| 260 | return EXT2_ET_UNSUPP_FEATURE; |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 261 | uuid_clear(sb->s_journal_uuid); |
| 262 | sb->s_state &= ~EXT2_VALID_FS; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 263 | ext2fs_mark_super_dirty(ctx->fs); |
| 264 | } |
| 265 | |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 266 | return e2fsck_journal_init_inode(ctx, sb, sb->s_journal_inum, journal); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 267 | } |
| 268 | |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 269 | static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx, |
| 270 | struct problem_context *pctx) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 271 | { |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 272 | struct ext2_super_block *sb = ctx->fs->super; |
| 273 | int recover = ctx->fs->super->s_feature_incompat & |
| 274 | EXT3_FEATURE_INCOMPAT_RECOVER; |
| 275 | int has_journal = ctx->fs->super->s_feature_compat & |
| 276 | EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 277 | |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 278 | if (has_journal || sb->s_journal_inum) { |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 279 | /* The journal inode is bogus, remove and force full fsck */ |
Theodore Ts'o | 7e92dfa | 2001-01-12 15:30:25 +0000 | [diff] [blame] | 280 | pctx->ino = sb->s_journal_inum; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 281 | if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) { |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 282 | if (has_journal && sb->s_journal_inum) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 283 | printf("*** ext3 journal has been deleted - " |
| 284 | "filesystem is now ext2 only ***\n\n"); |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 285 | sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
| 286 | sb->s_journal_inum = 0; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 287 | e2fsck_clear_recover(ctx, 1); |
| 288 | return 0; |
| 289 | } |
| 290 | return EXT2_ET_BAD_INODE_NUM; |
| 291 | } else if (recover) { |
| 292 | if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) { |
| 293 | e2fsck_clear_recover(ctx, 1); |
| 294 | return 0; |
| 295 | } |
| 296 | return EXT2_ET_UNSUPP_FEATURE; |
| 297 | } |
| 298 | return 0; |
| 299 | } |
| 300 | |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 301 | static errcode_t e2fsck_journal_load(journal_t *journal) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 302 | { |
| 303 | e2fsck_t ctx = journal->j_dev; |
| 304 | journal_superblock_t *jsb; |
| 305 | struct buffer_head *jbh = journal->j_sb_buffer; |
| 306 | struct problem_context pctx; |
| 307 | |
| 308 | clear_problem_context(&pctx); |
| 309 | |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 310 | ll_rw_block(READ, 1, &jbh); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 311 | if (jbh->b_err) { |
| 312 | com_err(ctx->device_name, jbh->b_err, |
| 313 | _("reading journal superblock\n")); |
| 314 | return jbh->b_err; |
| 315 | } |
| 316 | |
| 317 | jsb = journal->j_superblock; |
| 318 | /* If we don't even have JFS_MAGIC, we probably have a wrong inode */ |
| 319 | if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER)) |
| 320 | return e2fsck_journal_fix_bad_inode(ctx, &pctx); |
| 321 | |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 322 | switch (ntohl(jsb->s_header.h_blocktype)) { |
| 323 | case JFS_SUPERBLOCK_V1: |
| 324 | journal->j_format_version = 1; |
| 325 | break; |
| 326 | |
| 327 | case JFS_SUPERBLOCK_V2: |
| 328 | journal->j_format_version = 2; |
| 329 | break; |
| 330 | |
| 331 | /* If we don't understand the superblock major type, but there |
| 332 | * is a magic number, then it is likely to be a new format we |
| 333 | * just don't understand, so leave it alone. */ |
| 334 | default: |
| 335 | com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE, |
| 336 | _("%s: journal has unrecognised format\n"), |
| 337 | ctx->device_name); |
| 338 | return EXT2_ET_UNSUPP_FEATURE; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 339 | } |
| 340 | |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 341 | if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES)) { |
| 342 | com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE, |
| 343 | _("%s: journal has incompatible features\n"), |
| 344 | ctx->device_name); |
| 345 | return EXT2_ET_UNSUPP_FEATURE; |
| 346 | } |
| 347 | |
| 348 | if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES)) { |
| 349 | com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE, |
| 350 | _("%s: journal has readonly-incompatible features\n"), |
| 351 | ctx->device_name); |
| 352 | return EXT2_ET_RO_UNSUPP_FEATURE; |
| 353 | } |
| 354 | |
| 355 | /* We have now checked whether we know enough about the journal |
| 356 | * format to be able to proceed safely, so any other checks that |
| 357 | * fail we should attempt to recover from. */ |
| 358 | if (jsb->s_blocksize != htonl(journal->j_blocksize)) { |
| 359 | com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK, |
| 360 | _("%s: no valid journal superblock found\n"), |
| 361 | ctx->device_name); |
| 362 | return EXT2_ET_CORRUPT_SUPERBLOCK; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 363 | } |
| 364 | |
| 365 | if (ntohl(jsb->s_maxlen) < journal->j_maxlen) |
| 366 | journal->j_maxlen = ntohl(jsb->s_maxlen); |
| 367 | else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) { |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 368 | com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK, |
| 369 | _("%s: journal too short\n"), |
| 370 | ctx->device_name); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 371 | return EXT2_ET_CORRUPT_SUPERBLOCK; |
| 372 | } |
| 373 | |
| 374 | journal->j_tail_sequence = ntohl(jsb->s_sequence); |
Theodore Ts'o | ecf1b77 | 2000-08-20 22:06:31 +0000 | [diff] [blame] | 375 | journal->j_transaction_sequence = journal->j_tail_sequence; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 376 | journal->j_tail = ntohl(jsb->s_start); |
| 377 | journal->j_first = ntohl(jsb->s_first); |
| 378 | journal->j_last = ntohl(jsb->s_maxlen); |
| 379 | |
| 380 | return 0; |
| 381 | } |
| 382 | |
Theodore Ts'o | 53ef44c | 2001-01-06 05:55:58 +0000 | [diff] [blame] | 383 | static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb, |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 384 | journal_t *journal) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 385 | { |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 386 | char *p; |
| 387 | |
| 388 | /* Leave a valid existing V1 superblock signature alone. |
| 389 | * Anything unrecognisable we overwrite with a new V2 |
| 390 | * signature. */ |
| 391 | |
| 392 | if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) || |
| 393 | jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) { |
| 394 | jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); |
| 395 | jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); |
| 396 | } |
| 397 | |
| 398 | /* Zero out everything else beyond the superblock header */ |
| 399 | |
| 400 | p = ((char *) jsb) + sizeof(journal_header_t); |
| 401 | memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t)); |
| 402 | |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 403 | jsb->s_blocksize = htonl(ctx->fs->blocksize); |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 404 | jsb->s_maxlen = htonl(journal->j_maxlen); |
| 405 | jsb->s_first = htonl(1); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 406 | jsb->s_sequence = htonl(1); |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 407 | |
| 408 | /* In theory we should also re-zero the entire journal here. |
| 409 | * Initialising s_sequence to a random value would be a |
| 410 | * reasonable compromise. */ |
| 411 | |
| 412 | ll_rw_block(WRITE, 1, &journal->j_sb_buffer); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 413 | } |
| 414 | |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 415 | static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx, |
| 416 | journal_t *journal, |
| 417 | struct problem_context *pctx) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 418 | { |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 419 | struct ext2_super_block *sb = ctx->fs->super; |
| 420 | int recover = ctx->fs->super->s_feature_incompat & |
| 421 | EXT3_FEATURE_INCOMPAT_RECOVER; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 422 | |
| 423 | pctx->num = journal->j_inode->i_ino; |
| 424 | |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 425 | if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) { |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 426 | if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) { |
Theodore Ts'o | b2f9319 | 2000-12-30 20:33:42 +0000 | [diff] [blame] | 427 | e2fsck_journal_reset_super(ctx, journal->j_superblock, |
| 428 | journal); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 429 | journal->j_transaction_sequence = 1; |
| 430 | e2fsck_clear_recover(ctx, recover); |
| 431 | return 0; |
| 432 | } |
| 433 | return EXT2_ET_CORRUPT_SUPERBLOCK; |
| 434 | } else if (e2fsck_journal_fix_bad_inode(ctx, pctx)) |
| 435 | return EXT2_ET_CORRUPT_SUPERBLOCK; |
| 436 | |
| 437 | return 0; |
| 438 | } |
| 439 | |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 440 | static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal, |
| 441 | int reset, int drop) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 442 | { |
| 443 | journal_superblock_t *jsb; |
| 444 | |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 445 | if (drop) |
| 446 | mark_buffer_clean(journal->j_sb_buffer); |
| 447 | else if (!(ctx->options & E2F_OPT_READONLY)) { |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 448 | jsb = journal->j_superblock; |
| 449 | jsb->s_sequence = htonl(journal->j_transaction_sequence); |
| 450 | if (reset) |
| 451 | jsb->s_start = 0; /* this marks the journal as empty */ |
| 452 | mark_buffer_dirty(journal->j_sb_buffer, 1); |
| 453 | } |
| 454 | brelse(journal->j_sb_buffer); |
| 455 | |
| 456 | if (journal->j_inode) |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 457 | ext2fs_free_mem((void **)&journal->j_inode); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 458 | ext2fs_free_mem((void **)&journal); |
| 459 | } |
| 460 | |
Theodore Ts'o | 9b56575 | 2000-12-13 18:50:22 +0000 | [diff] [blame] | 461 | /* |
| 462 | * This function makes sure that the superblock fields regarding the |
| 463 | * journal are consistent. |
| 464 | */ |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 465 | int e2fsck_check_ext3_journal(e2fsck_t ctx) |
| 466 | { |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 467 | struct ext2_super_block *sb = ctx->fs->super; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 468 | journal_t *journal; |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 469 | int recover = ctx->fs->super->s_feature_incompat & |
| 470 | EXT3_FEATURE_INCOMPAT_RECOVER; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 471 | struct problem_context pctx; |
Theodore Ts'o | d3f35b6 | 2001-01-03 13:00:43 +0000 | [diff] [blame] | 472 | int reset = 0, force_fsck = 0; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 473 | int retval; |
| 474 | |
| 475 | /* If we don't have any journal features, don't do anything more */ |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 476 | if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && |
| 477 | !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 && |
| 478 | uuid_is_null(sb->s_journal_uuid)) |
Theodore Ts'o | 9b56575 | 2000-12-13 18:50:22 +0000 | [diff] [blame] | 479 | return 0; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 480 | |
Theodore Ts'o | d3f35b6 | 2001-01-03 13:00:43 +0000 | [diff] [blame] | 481 | #ifdef JFS_DEBUG /* Enabled by configure --enable-jfs-debug */ |
Theodore Ts'o | f43650c | 2000-12-09 06:47:56 +0000 | [diff] [blame] | 482 | journal_enable_debug = 2; |
| 483 | #endif |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 484 | clear_problem_context(&pctx); |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 485 | pctx.num = sb->s_journal_inum; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 486 | |
| 487 | retval = e2fsck_get_journal(ctx, &journal); |
| 488 | if (retval) { |
| 489 | if (retval == EXT2_ET_BAD_INODE_NUM) |
| 490 | return e2fsck_journal_fix_bad_inode(ctx, &pctx); |
| 491 | return retval; |
| 492 | } |
| 493 | |
| 494 | retval = e2fsck_journal_load(journal); |
| 495 | if (retval) { |
| 496 | if (retval == EXT2_ET_CORRUPT_SUPERBLOCK) |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 497 | retval = e2fsck_journal_fix_corrupt_super(ctx, journal, |
| 498 | &pctx); |
| 499 | e2fsck_journal_release(ctx, journal, 0, 1); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 500 | return retval; |
| 501 | } |
| 502 | |
| 503 | /* |
| 504 | * We want to make the flags consistent here. We will not leave with |
| 505 | * needs_recovery set but has_journal clear. We can't get in a loop |
| 506 | * with -y, -n, or -p, only if a user isn't making up their mind. |
| 507 | */ |
| 508 | no_has_journal: |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 509 | if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { |
| 510 | recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 511 | pctx.str = "inode"; |
| 512 | if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) { |
| 513 | if (recover && |
| 514 | !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx)) |
| 515 | goto no_has_journal; |
Theodore Ts'o | d3f35b6 | 2001-01-03 13:00:43 +0000 | [diff] [blame] | 516 | /* |
| 517 | * Need a full fsck if we are releasing a |
Theodore Ts'o | 8c2dc52 | 2001-01-03 13:14:23 +0000 | [diff] [blame] | 518 | * journal stored on a reserved inode. |
Theodore Ts'o | d3f35b6 | 2001-01-03 13:00:43 +0000 | [diff] [blame] | 519 | */ |
| 520 | force_fsck = recover || |
| 521 | (sb->s_journal_inum < EXT2_FIRST_INODE(sb)); |
| 522 | /* Clear all of the journal fields */ |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 523 | sb->s_journal_inum = 0; |
Theodore Ts'o | d3f35b6 | 2001-01-03 13:00:43 +0000 | [diff] [blame] | 524 | sb->s_journal_dev = 0; |
| 525 | memset(sb->s_journal_uuid, 0, |
| 526 | sizeof(sb->s_journal_uuid)); |
| 527 | e2fsck_clear_recover(ctx, force_fsck); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 528 | } else if (!(ctx->options & E2F_OPT_READONLY)) { |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 529 | sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 530 | ext2fs_mark_super_dirty(ctx->fs); |
| 531 | } |
| 532 | } |
| 533 | |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 534 | if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL && |
| 535 | !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) && |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 536 | journal->j_superblock->s_start != 0) { |
Theodore Ts'o | d3f35b6 | 2001-01-03 13:00:43 +0000 | [diff] [blame] | 537 | if (fix_problem(ctx, PR_0_JOURNAL_RESET_JOURNAL, &pctx)) { |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 538 | reset = 1; |
Theodore Ts'o | d3f35b6 | 2001-01-03 13:00:43 +0000 | [diff] [blame] | 539 | sb->s_state &= ~EXT2_VALID_FS; |
| 540 | ext2fs_mark_super_dirty(ctx->fs); |
| 541 | } |
| 542 | /* |
| 543 | * If the user answers no to the above question, we |
| 544 | * ignore the fact that journal apparently has data; |
| 545 | * accidentally replaying over valid data would be far |
| 546 | * worse than skipping a questionable recovery. |
| 547 | * |
| 548 | * XXX should we abort with a fatal error here? What |
| 549 | * will the ext3 kernel code do if a filesystem with |
| 550 | * !NEEDS_RECOVERY but with a non-zero |
| 551 | * journal->j_superblock->s_start is mounted? |
| 552 | */ |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 553 | } |
| 554 | |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 555 | e2fsck_journal_release(ctx, journal, reset, 0); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 556 | return retval; |
| 557 | } |
| 558 | |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 559 | static errcode_t recover_ext3_journal(e2fsck_t ctx) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 560 | { |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 561 | journal_t *journal; |
| 562 | int retval; |
| 563 | |
| 564 | retval = e2fsck_get_journal(ctx, &journal); |
| 565 | if (retval) |
Theodore Ts'o | ecf1b77 | 2000-08-20 22:06:31 +0000 | [diff] [blame] | 566 | return retval; |
| 567 | |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 568 | retval = e2fsck_journal_load(journal); |
| 569 | if (retval) |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 570 | goto errout; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 571 | |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 572 | retval = journal_init_revoke(journal, 1024); |
| 573 | if (retval) |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 574 | goto errout; |
Theodore Ts'o | 0e8a956 | 2000-12-09 06:41:25 +0000 | [diff] [blame] | 575 | |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 576 | retval = -journal_recover(journal); |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 577 | errout: |
| 578 | e2fsck_journal_release(ctx, journal, 1, 0); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 579 | return retval; |
| 580 | } |
| 581 | |
| 582 | |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 583 | #if 0 |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 584 | #define TEMPLATE "/tmp/ext3.XXXXXX" |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 585 | |
| 586 | /* |
| 587 | * This function attempts to mount and unmount an ext3 filesystem, |
| 588 | * which is a cheap way to force the kernel to run the journal and |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 589 | * handle the recovery for us. |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 590 | */ |
Theodore Ts'o | 6a6d3d4 | 2001-01-12 21:11:24 +0000 | [diff] [blame] | 591 | static errcode_t recover_ext3_journal_via_mount(e2fsck_t ctx) |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 592 | { |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 593 | ext2_filsys fs = ctx->fs; |
| 594 | char *dirlist[] = {"/mnt","/lost+found","/tmp","/root","/boot",0}; |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 595 | errcode_t retval, retval2; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 596 | int count = 0; |
| 597 | char template[] = TEMPLATE; |
| 598 | struct stat buf; |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 599 | char *tmpdir; |
| 600 | |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 601 | if (ctx->options & E2F_OPT_READONLY) { |
| 602 | printf("%s: won't do journal recovery while read-only\n", |
| 603 | ctx->device_name); |
| 604 | return EXT2_ET_FILE_RO; |
| 605 | } |
| 606 | |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 607 | printf(_("%s: trying for ext3 kernel journal recovery\n"), |
| 608 | ctx->device_name); |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 609 | /* |
| 610 | * First try to make a temporary directory. This may fail if |
| 611 | * the root partition is still mounted read-only. |
| 612 | */ |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 613 | newtemp: |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 614 | tmpdir = mktemp(template); |
| 615 | if (tmpdir) { |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 616 | jfs_debug(2, "trying %s as ext3 temp mount point\n", tmpdir); |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 617 | if (mkdir(template, 0700)) { |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 618 | if (errno == EROFS) { |
| 619 | tmpdir = NULL; |
| 620 | template[0] = '\0'; |
| 621 | } else if (errno == EEXIST && count++ < 10) { |
| 622 | strcpy(template, TEMPLATE); |
| 623 | goto newtemp; |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 624 | } |
| 625 | return errno; |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 626 | } |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 627 | } |
| 628 | |
| 629 | /* |
| 630 | * OK, creating a temporary directory didn't work. |
| 631 | * Let's try a list of possible temporary mountpoints. |
| 632 | */ |
| 633 | if (!tmpdir) { |
| 634 | dev_t rootdev; |
| 635 | char **cpp, *dir; |
| 636 | |
| 637 | if (stat("/", &buf)) |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 638 | return errno; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 639 | |
| 640 | rootdev = buf.st_dev; |
| 641 | |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 642 | /* |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 643 | * Check that dir is on the same device as root (no other |
| 644 | * filesystem is mounted there), and it's a directory. |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 645 | */ |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 646 | for (cpp = dirlist; (dir = *cpp); cpp++) |
| 647 | if (stat(dir, &buf) == 0 && buf.st_dev == rootdev && |
| 648 | S_ISDIR(buf.st_mode)) { |
| 649 | tmpdir = dir; |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 650 | break; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 651 | } |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 652 | } |
| 653 | |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 654 | if (tmpdir) { |
| 655 | io_manager io_ptr = fs->io->manager; |
| 656 | int blocksize = fs->blocksize; |
Theodore Ts'o | 17390c0 | 2000-07-07 04:13:21 +0000 | [diff] [blame] | 657 | |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 658 | jfs_debug(2, "using %s for ext3 mount\n", tmpdir); |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 659 | /* FIXME - need to handle loop devices here */ |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 660 | if (mount(ctx->device_name, tmpdir, "ext3", MNT_FL, NULL)) { |
| 661 | retval = errno; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 662 | com_err(ctx->program_name, errno, |
| 663 | "when mounting %s", ctx->device_name); |
| 664 | if (template[0]) |
| 665 | rmdir(tmpdir); |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 666 | return retval; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 667 | } |
| 668 | /* |
| 669 | * Now that it mounted cleanly, the filesystem will have been |
| 670 | * recovered, so we can now unmount it. |
| 671 | */ |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 672 | if (umount(tmpdir)) |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 673 | return errno; |
| 674 | |
| 675 | /* |
| 676 | * Remove the temporary directory, if it was created. |
| 677 | */ |
| 678 | if (template[0]) |
| 679 | rmdir(tmpdir); |
| 680 | return 0; |
| 681 | } |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 682 | } |
| 683 | #endif |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 684 | |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 685 | int e2fsck_run_ext3_journal(e2fsck_t ctx) |
| 686 | { |
| 687 | io_manager io_ptr = ctx->fs->io->manager; |
| 688 | int blocksize = ctx->fs->blocksize; |
Theodore Ts'o | ecf1b77 | 2000-08-20 22:06:31 +0000 | [diff] [blame] | 689 | errcode_t retval, recover_retval; |
Theodore Ts'o | 8394902 | 2000-10-25 01:38:50 +0000 | [diff] [blame] | 690 | |
| 691 | printf(_("%s: recovering journal\n"), ctx->device_name); |
Theodore Ts'o | ecf1b77 | 2000-08-20 22:06:31 +0000 | [diff] [blame] | 692 | if (ctx->options & E2F_OPT_READONLY) { |
Theodore Ts'o | 8394902 | 2000-10-25 01:38:50 +0000 | [diff] [blame] | 693 | printf(_("%s: won't do journal recovery while read-only\n"), |
Theodore Ts'o | ecf1b77 | 2000-08-20 22:06:31 +0000 | [diff] [blame] | 694 | ctx->device_name); |
| 695 | return EXT2_ET_FILE_RO; |
| 696 | } |
| 697 | |
Theodore Ts'o | e9e2a20 | 2001-02-20 16:31:38 +0000 | [diff] [blame^] | 698 | ext2fs_flush(ctx->fs); /* Force out any modifications */ |
Theodore Ts'o | d051521 | 2001-02-13 04:32:53 +0000 | [diff] [blame] | 699 | |
Theodore Ts'o | ecf1b77 | 2000-08-20 22:06:31 +0000 | [diff] [blame] | 700 | recover_retval = recover_ext3_journal(ctx); |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 701 | |
| 702 | /* |
| 703 | * Reload the filesystem context to get up-to-date data from disk |
| 704 | * because journal recovery will change the filesystem under us. |
| 705 | */ |
| 706 | ext2fs_close(ctx->fs); |
Theodore Ts'o | ecf1b77 | 2000-08-20 22:06:31 +0000 | [diff] [blame] | 707 | retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW, |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 708 | ctx->superblock, blocksize, io_ptr, |
| 709 | &ctx->fs); |
| 710 | |
| 711 | if (retval) { |
| 712 | com_err(ctx->program_name, retval, |
| 713 | _("while trying to re-open %s"), |
| 714 | ctx->device_name); |
Theodore Ts'o | 99a2cc9 | 2000-08-22 21:41:52 +0000 | [diff] [blame] | 715 | fatal_error(ctx, 0); |
Theodore Ts'o | 80bfaa3 | 2000-08-18 15:08:37 +0000 | [diff] [blame] | 716 | } |
| 717 | ctx->fs->priv_data = ctx; |
| 718 | |
Theodore Ts'o | ecf1b77 | 2000-08-20 22:06:31 +0000 | [diff] [blame] | 719 | /* Set the superblock flags */ |
| 720 | e2fsck_clear_recover(ctx, recover_retval); |
| 721 | return recover_retval; |
Theodore Ts'o | 3b5386d | 2000-08-14 14:25:19 +0000 | [diff] [blame] | 722 | } |