]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - e2fsck/journal.c
mke2fs: free tdb_dir string if it came from the profile
[thirdparty/e2fsprogs.git] / e2fsck / journal.c
CommitLineData
17390c04
TT
1/*
2 * journal.c --- code for handling the "ext3" journal
3b5386dc
TT
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.
17390c04
TT
13 */
14
3b5386dc 15#ifdef HAVE_SYS_MOUNT_H
b34cbddb 16#include <sys/param.h>
3b5386dc
TT
17#include <sys/mount.h>
18#define MNT_FL (MS_MGC_VAL | MS_RDONLY)
19#endif
20#ifdef HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
17390c04 23
53ef44c4 24#define E2FSCK_INCLUDE_INLINE_FUNCS
0e8a9560 25#include "jfs_user.h"
3b5386dc
TT
26#include "problem.h"
27#include "uuid/uuid.h"
17390c04 28
8cf93332 29#ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jfs-debug */
3b5386dc 30static int bh_count = 0;
3b5386dc
TT
31#endif
32
d1a2182a
TT
33/*
34 * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths.
35 * This creates a larger static binary, and a smaller binary using
36 * shared libraries. It's also probably slightly less CPU-efficient,
37 * which is why it's not on by default. But, it's a good way of
38 * testing the functions in inode_io.c and fileio.c.
39 */
40#undef USE_INODE_IO
41
b2f93192
TT
42/* Kernel compatibility functions for handling the journal. These allow us
43 * to use the recovery.c file virtually unchanged from the kernel, so we
44 * don't have to do much to keep kernel and user recovery in sync.
45 */
6dc64392 46int journal_bmap(journal_t *journal, blk64_t block, unsigned long *phys)
3b5386dc 47{
d1a2182a
TT
48#ifdef USE_INODE_IO
49 *phys = block;
50 return 0;
51#else
8cf93332
TT
52 struct inode *inode = journal->j_inode;
53 errcode_t retval;
6dc64392 54 blk64_t pblk;
3b5386dc 55
8cf93332
TT
56 if (!inode) {
57 *phys = block;
58 return 0;
59 }
3b5386dc 60
6dc64392
VAH
61 retval= ext2fs_bmap2(inode->i_ctx->fs, inode->i_ino,
62 &inode->i_ext2, NULL, 0, block, 0, &pblk);
8cf93332
TT
63 *phys = pblk;
64 return (retval);
d1a2182a 65#endif
3b5386dc
TT
66}
67
6dc64392 68struct buffer_head *getblk(kdev_t kdev, blk64_t blocknr, int blocksize)
3b5386dc
TT
69{
70 struct buffer_head *bh;
e35d548b
TT
71 int bufsize = sizeof(*bh) + kdev->k_ctx->fs->blocksize -
72 sizeof(bh->b_data);
3b5386dc 73
e35d548b 74 bh = e2fsck_allocate_memory(kdev->k_ctx, bufsize, "block buffer");
3b5386dc
TT
75 if (!bh)
76 return NULL;
77
185c4aea
TT
78#ifdef CONFIG_JBD_DEBUG
79 if (journal_enable_debug >= 3)
80 bh_count++;
81#endif
3b5386dc 82 jfs_debug(4, "getblk for block %lu (%d bytes)(total %d)\n",
185c4aea 83 (unsigned long) blocknr, blocksize, bh_count);
3b5386dc 84
8cf93332
TT
85 bh->b_ctx = kdev->k_ctx;
86 if (kdev->k_dev == K_DEV_FS)
87 bh->b_io = kdev->k_ctx->fs->io;
efc6f628 88 else
8cf93332 89 bh->b_io = kdev->k_ctx->journal_io;
3b5386dc
TT
90 bh->b_size = blocksize;
91 bh->b_blocknr = blocknr;
92
93 return bh;
94}
95
93effaa4
TT
96void sync_blockdev(kdev_t kdev)
97{
98 io_channel io;
99
100 if (kdev->k_dev == K_DEV_FS)
101 io = kdev->k_ctx->fs->io;
efc6f628 102 else
93effaa4
TT
103 io = kdev->k_ctx->journal_io;
104
105 io_channel_flush(io);
106}
107
0e8a9560 108void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
3b5386dc
TT
109{
110 int retval;
0e8a9560 111 struct buffer_head *bh;
3b5386dc 112
0e8a9560
TT
113 for (; nr > 0; --nr) {
114 bh = *bhp++;
115 if (rw == READ && !bh->b_uptodate) {
efc6f628 116 jfs_debug(3, "reading block %lu/%p\n",
53ef44c4 117 (unsigned long) bh->b_blocknr, (void *) bh);
24a117ab 118 retval = io_channel_read_blk64(bh->b_io,
0e8a9560
TT
119 bh->b_blocknr,
120 1, bh->b_data);
121 if (retval) {
122 com_err(bh->b_ctx->device_name, retval,
efc6f628 123 "while reading block %lu\n",
54434927 124 (unsigned long) bh->b_blocknr);
0e8a9560
TT
125 bh->b_err = retval;
126 continue;
127 }
128 bh->b_uptodate = 1;
129 } else if (rw == WRITE && bh->b_dirty) {
efc6f628 130 jfs_debug(3, "writing block %lu/%p\n",
53ef44c4 131 (unsigned long) bh->b_blocknr, (void *) bh);
24a117ab 132 retval = io_channel_write_blk64(bh->b_io,
0e8a9560
TT
133 bh->b_blocknr,
134 1, bh->b_data);
135 if (retval) {
136 com_err(bh->b_ctx->device_name, retval,
efc6f628 137 "while writing block %lu\n",
54434927 138 (unsigned long) bh->b_blocknr);
0e8a9560
TT
139 bh->b_err = retval;
140 continue;
141 }
142 bh->b_dirty = 0;
143 bh->b_uptodate = 1;
b969b1b8 144 } else {
0e8a9560 145 jfs_debug(3, "no-op %s for block %lu\n",
efc6f628 146 rw == READ ? "read" : "write",
53ef44c4 147 (unsigned long) bh->b_blocknr);
b969b1b8 148 }
0e8a9560 149 }
3b5386dc
TT
150}
151
8cf93332 152void mark_buffer_dirty(struct buffer_head *bh)
3b5386dc 153{
8cf93332 154 bh->b_dirty = 1;
3b5386dc
TT
155}
156
6a6d3d44
TT
157static void mark_buffer_clean(struct buffer_head * bh)
158{
159 bh->b_dirty = 0;
160}
161
3b5386dc
TT
162void brelse(struct buffer_head *bh)
163{
164 if (bh->b_dirty)
0e8a9560 165 ll_rw_block(WRITE, 1, &bh);
3b5386dc 166 jfs_debug(3, "freeing block %lu/%p (total %d)\n",
53ef44c4 167 (unsigned long) bh->b_blocknr, (void *) bh, --bh_count);
c4e3d3f3 168 ext2fs_free_mem(&bh);
3b5386dc
TT
169}
170
171int buffer_uptodate(struct buffer_head *bh)
172{
173 return bh->b_uptodate;
174}
175
15986f79
TT
176void mark_buffer_uptodate(struct buffer_head *bh, int val)
177{
178 bh->b_uptodate = val;
179}
180
3b5386dc
TT
181void wait_on_buffer(struct buffer_head *bh)
182{
183 if (!bh->b_uptodate)
0e8a9560 184 ll_rw_block(READ, 1, &bh);
3b5386dc
TT
185}
186
80bfaa3e 187
3b5386dc
TT
188static void e2fsck_clear_recover(e2fsck_t ctx, int error)
189{
5dd8f963 190 ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
3b5386dc
TT
191
192 /* if we had an error doing journal recovery, we need a full fsck */
193 if (error)
5dd8f963 194 ctx->fs->super->s_state &= ~EXT2_VALID_FS;
3b5386dc
TT
195 ext2fs_mark_super_dirty(ctx->fs);
196}
197
051afbe0
TT
198/*
199 * This is a helper function to check the validity of the journal.
200 */
201struct process_block_struct {
202 e2_blkcnt_t last_block;
203};
204
205static int process_journal_block(ext2_filsys fs,
6dc64392 206 blk64_t *block_nr,
051afbe0 207 e2_blkcnt_t blockcnt,
6dc64392 208 blk64_t ref_block EXT2FS_ATTR((unused)),
051afbe0
TT
209 int ref_offset EXT2FS_ATTR((unused)),
210 void *priv_data)
211{
212 struct process_block_struct *p;
6dc64392 213 blk64_t blk = *block_nr;
051afbe0
TT
214
215 p = (struct process_block_struct *) priv_data;
216
5750e5f9 217 if (!blk || blk < fs->super->s_first_data_block ||
4efbac6f 218 blk >= ext2fs_blocks_count(fs->super))
051afbe0
TT
219 return BLOCK_ABORT;
220
221 if (blockcnt >= 0)
222 p->last_block = blockcnt;
223 return 0;
224}
225
d1a2182a 226static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
3b5386dc 227{
051afbe0 228 struct process_block_struct pb;
d1a2182a
TT
229 struct ext2_super_block *sb = ctx->fs->super;
230 struct ext2_super_block jsuper;
231 struct problem_context pctx;
232 struct buffer_head *bh;
233 struct inode *j_inode = NULL;
234 struct kdev_s *dev_fs = NULL, *dev_journal;
3e699064 235 const char *journal_name = 0;
d1a2182a 236 journal_t *journal = NULL;
3e699064
TT
237 errcode_t retval = 0;
238 io_manager io_ptr = 0;
d1a2182a 239 unsigned long start = 0;
d1a2182a 240 int ext_journal = 0;
a435ec34 241 int tried_backup_jnl = 0;
2bfe0bdb 242
d1a2182a 243 clear_problem_context(&pctx);
2bfe0bdb 244
d1a2182a
TT
245 journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
246 if (!journal) {
3b5386dc
TT
247 return EXT2_ET_NO_MEMORY;
248 }
249
8cf93332
TT
250 dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
251 if (!dev_fs) {
252 retval = EXT2_ET_NO_MEMORY;
253 goto errout;
254 }
255 dev_journal = dev_fs+1;
2bfe0bdb 256
8cf93332
TT
257 dev_fs->k_ctx = dev_journal->k_ctx = ctx;
258 dev_fs->k_dev = K_DEV_FS;
259 dev_journal->k_dev = K_DEV_JOURNAL;
2bfe0bdb 260
d1a2182a
TT
261 journal->j_dev = dev_journal;
262 journal->j_fs_dev = dev_fs;
263 journal->j_inode = NULL;
264 journal->j_blocksize = ctx->fs->blocksize;
3b5386dc 265
d1a2182a 266 if (uuid_is_null(sb->s_journal_uuid)) {
2bfe0bdb
BB
267 if (!sb->s_journal_inum) {
268 retval = EXT2_ET_BAD_INODE_NUM;
269 goto errout;
270 }
d1a2182a
TT
271 j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
272 "journal inode");
273 if (!j_inode) {
274 retval = EXT2_ET_NO_MEMORY;
275 goto errout;
276 }
3b5386dc 277
d1a2182a
TT
278 j_inode->i_ctx = ctx;
279 j_inode->i_ino = sb->s_journal_inum;
2bfe0bdb 280
d1a2182a
TT
281 if ((retval = ext2fs_read_inode(ctx->fs,
282 sb->s_journal_inum,
a435ec34
TT
283 &j_inode->i_ext2))) {
284 try_backup_journal:
285 if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
286 tried_backup_jnl)
287 goto errout;
288 memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
efc6f628 289 memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
a435ec34 290 EXT2_N_BLOCKS*4);
931b58e1 291 j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15];
a435ec34
TT
292 j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
293 j_inode->i_ext2.i_links_count = 1;
294 j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
051afbe0
TT
295 e2fsck_use_inode_shortcuts(ctx, 1);
296 ctx->stashed_ino = j_inode->i_ino;
297 ctx->stashed_inode = &j_inode->i_ext2;
a435ec34
TT
298 tried_backup_jnl++;
299 }
d1a2182a
TT
300 if (!j_inode->i_ext2.i_links_count ||
301 !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
302 retval = EXT2_ET_NO_JOURNAL;
a435ec34 303 goto try_backup_journal;
d1a2182a 304 }
931b58e1 305 if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize <
d1a2182a
TT
306 JFS_MIN_JOURNAL_BLOCKS) {
307 retval = EXT2_ET_JOURNAL_TOO_SMALL;
a435ec34
TT
308 goto try_backup_journal;
309 }
051afbe0 310 pb.last_block = -1;
6dc64392 311 retval = ext2fs_block_iterate3(ctx->fs, j_inode->i_ino,
efc6f628 312 BLOCK_FLAG_HOLE, 0,
051afbe0 313 process_journal_block, &pb);
931b58e1
AD
314 if ((pb.last_block + 1) * ctx->fs->blocksize <
315 EXT2_I_SIZE(&j_inode->i_ext2)) {
051afbe0
TT
316 retval = EXT2_ET_JOURNAL_TOO_SMALL;
317 goto try_backup_journal;
d1a2182a 318 }
ded28ac2
KS
319 if (tried_backup_jnl && !(ctx->options & E2F_OPT_READONLY)) {
320 retval = ext2fs_write_inode(ctx->fs, sb->s_journal_inum,
321 &j_inode->i_ext2);
322 if (retval)
323 goto errout;
324 }
325
931b58e1
AD
326 journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) /
327 journal->j_blocksize;
3b5386dc 328
d1a2182a 329#ifdef USE_INODE_IO
a435ec34
TT
330 retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
331 &j_inode->i_ext2,
332 &journal_name);
d1a2182a
TT
333 if (retval)
334 goto errout;
3b5386dc 335
d1a2182a
TT
336 io_ptr = inode_io_manager;
337#else
338 journal->j_inode = j_inode;
339 ctx->journal_io = ctx->fs->io;
340 if ((retval = journal_bmap(journal, 0, &start)) != 0)
341 goto errout;
342#endif
343 } else {
344 ext_journal = 1;
f364093b
TT
345 if (!ctx->journal_name) {
346 char uuid[37];
347
348 uuid_unparse(sb->s_journal_uuid, uuid);
349 ctx->journal_name = blkid_get_devname(ctx->blkid,
350 "UUID", uuid);
351 if (!ctx->journal_name)
352 ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
d1a2182a 353 }
f364093b 354 journal_name = ctx->journal_name;
2bfe0bdb 355
d1a2182a
TT
356 if (!journal_name) {
357 fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
2bfe0bdb
BB
358 retval = EXT2_ET_LOAD_EXT_JOURNAL;
359 goto errout;
d1a2182a 360 }
2bfe0bdb 361
d1a2182a
TT
362 jfs_debug(1, "Using journal file %s\n", journal_name);
363 io_ptr = unix_io_manager;
3b5386dc
TT
364 }
365
d1a2182a
TT
366#if 0
367 test_io_backing_manager = io_ptr;
adee8d75 368 io_ptr = test_io_manager;
adee8d75 369#endif
d1a2182a
TT
370#ifndef USE_INODE_IO
371 if (ext_journal)
372#endif
8718359b
TT
373 retval = io_ptr->open(journal_name,
374 IO_FLAG_RW | IO_FLAG_EXCLUSIVE,
d1a2182a 375 &ctx->journal_io);
6d222f32 376 if (retval)
d1a2182a 377 goto errout;
adee8d75 378
d1a2182a
TT
379 io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);
380
381 if (ext_journal) {
382 if (ctx->fs->blocksize == 1024)
383 start = 1;
384 bh = getblk(dev_journal, start, ctx->fs->blocksize);
385 if (!bh) {
386 retval = EXT2_ET_NO_MEMORY;
387 goto errout;
388 }
389 ll_rw_block(READ, 1, &bh);
2aa362f5
TT
390 if ((retval = bh->b_err) != 0) {
391 brelse(bh);
d1a2182a 392 goto errout;
2aa362f5 393 }
d1a2182a
TT
394 memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024,
395 sizeof(jsuper));
396 brelse(bh);
2eae0930 397#ifdef WORDS_BIGENDIAN
efc6f628 398 if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
d1a2182a 399 ext2fs_swap_super(&jsuper);
adee8d75 400#endif
d1a2182a
TT
401 if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
402 !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
403 fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
404 retval = EXT2_ET_LOAD_EXT_JOURNAL;
405 goto errout;
406 }
407 /* Make sure the journal UUID is correct */
408 if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
409 sizeof(jsuper.s_uuid))) {
410 fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
411 retval = EXT2_ET_LOAD_EXT_JOURNAL;
412 goto errout;
413 }
2bfe0bdb 414
4efbac6f 415 journal->j_maxlen = ext2fs_blocks_count(&jsuper);
d1a2182a 416 start++;
3b5386dc
TT
417 }
418
d1a2182a 419 if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
adee8d75
TT
420 retval = EXT2_ET_NO_MEMORY;
421 goto errout;
422 }
2bfe0bdb 423
d1a2182a
TT
424 journal->j_sb_buffer = bh;
425 journal->j_superblock = (journal_superblock_t *)bh->b_data;
2bfe0bdb 426
d1a2182a
TT
427#ifdef USE_INODE_IO
428 if (j_inode)
c4e3d3f3 429 ext2fs_free_mem(&j_inode);
d1a2182a
TT
430#endif
431
432 *ret_journal = journal;
051afbe0 433 e2fsck_use_inode_shortcuts(ctx, 0);
adee8d75
TT
434 return 0;
435
436errout:
051afbe0 437 e2fsck_use_inode_shortcuts(ctx, 0);
d1a2182a 438 if (dev_fs)
c4e3d3f3 439 ext2fs_free_mem(&dev_fs);
d1a2182a 440 if (j_inode)
c4e3d3f3 441 ext2fs_free_mem(&j_inode);
d1a2182a 442 if (journal)
c4e3d3f3 443 ext2fs_free_mem(&journal);
adee8d75 444 return retval;
3b5386dc
TT
445}
446
6a6d3d44
TT
447static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
448 struct problem_context *pctx)
3b5386dc 449{
5dd8f963
TT
450 struct ext2_super_block *sb = ctx->fs->super;
451 int recover = ctx->fs->super->s_feature_incompat &
452 EXT3_FEATURE_INCOMPAT_RECOVER;
453 int has_journal = ctx->fs->super->s_feature_compat &
454 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
3b5386dc 455
5dd8f963 456 if (has_journal || sb->s_journal_inum) {
3b5386dc 457 /* The journal inode is bogus, remove and force full fsck */
7e92dfae 458 pctx->ino = sb->s_journal_inum;
3b5386dc 459 if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
5dd8f963 460 if (has_journal && sb->s_journal_inum)
3b5386dc
TT
461 printf("*** ext3 journal has been deleted - "
462 "filesystem is now ext2 only ***\n\n");
5dd8f963
TT
463 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
464 sb->s_journal_inum = 0;
5107d0d1 465 ctx->flags |= E2F_FLAG_JOURNAL_INODE;
0cfce7f7 466 ctx->fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
3b5386dc
TT
467 e2fsck_clear_recover(ctx, 1);
468 return 0;
469 }
470 return EXT2_ET_BAD_INODE_NUM;
471 } else if (recover) {
472 if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) {
473 e2fsck_clear_recover(ctx, 1);
474 return 0;
475 }
476 return EXT2_ET_UNSUPP_FEATURE;
477 }
478 return 0;
479}
480
62e3e7fe
TT
481#define V1_SB_SIZE 0x0024
482static void clear_v2_journal_fields(journal_t *journal)
483{
8cf93332 484 e2fsck_t ctx = journal->j_dev->k_ctx;
62e3e7fe
TT
485 struct problem_context pctx;
486
487 clear_problem_context(&pctx);
488
489 if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx))
490 return;
491
492 memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0,
493 ctx->fs->blocksize-V1_SB_SIZE);
8cf93332 494 mark_buffer_dirty(journal->j_sb_buffer);
62e3e7fe
TT
495}
496
497
6a6d3d44 498static errcode_t e2fsck_journal_load(journal_t *journal)
3b5386dc 499{
8cf93332 500 e2fsck_t ctx = journal->j_dev->k_ctx;
3b5386dc
TT
501 journal_superblock_t *jsb;
502 struct buffer_head *jbh = journal->j_sb_buffer;
503 struct problem_context pctx;
504
505 clear_problem_context(&pctx);
506
0e8a9560 507 ll_rw_block(READ, 1, &jbh);
3b5386dc
TT
508 if (jbh->b_err) {
509 com_err(ctx->device_name, jbh->b_err,
510 _("reading journal superblock\n"));
511 return jbh->b_err;
512 }
513
514 jsb = journal->j_superblock;
515 /* If we don't even have JFS_MAGIC, we probably have a wrong inode */
516 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
517 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
518
0e8a9560
TT
519 switch (ntohl(jsb->s_header.h_blocktype)) {
520 case JFS_SUPERBLOCK_V1:
521 journal->j_format_version = 1;
62e3e7fe
TT
522 if (jsb->s_feature_compat ||
523 jsb->s_feature_incompat ||
524 jsb->s_feature_ro_compat ||
525 jsb->s_nr_users)
526 clear_v2_journal_fields(journal);
0e8a9560 527 break;
efc6f628 528
0e8a9560
TT
529 case JFS_SUPERBLOCK_V2:
530 journal->j_format_version = 2;
b3b3d465 531 if (ntohl(jsb->s_nr_users) > 1 &&
a435ec34 532 uuid_is_null(ctx->fs->super->s_journal_uuid))
62e3e7fe 533 clear_v2_journal_fields(journal);
adee8d75
TT
534 if (ntohl(jsb->s_nr_users) > 1) {
535 fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
536 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
537 }
0e8a9560 538 break;
c7f23364
TT
539
540 /*
541 * These should never appear in a journal super block, so if
542 * they do, the journal is badly corrupted.
543 */
544 case JFS_DESCRIPTOR_BLOCK:
545 case JFS_COMMIT_BLOCK:
546 case JFS_REVOKE_BLOCK:
547 return EXT2_ET_CORRUPT_SUPERBLOCK;
efc6f628 548
0e8a9560
TT
549 /* If we don't understand the superblock major type, but there
550 * is a magic number, then it is likely to be a new format we
551 * just don't understand, so leave it alone. */
552 default:
c7f23364 553 return EXT2_ET_JOURNAL_UNSUPP_VERSION;
0e8a9560
TT
554 }
555
2f686ace
TT
556 if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
557 return EXT2_ET_UNSUPP_FEATURE;
efc6f628 558
2f686ace
TT
559 if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
560 return EXT2_ET_RO_UNSUPP_FEATURE;
3b5386dc 561
0e8a9560
TT
562 /* We have now checked whether we know enough about the journal
563 * format to be able to proceed safely, so any other checks that
564 * fail we should attempt to recover from. */
565 if (jsb->s_blocksize != htonl(journal->j_blocksize)) {
566 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
567 _("%s: no valid journal superblock found\n"),
568 ctx->device_name);
569 return EXT2_ET_CORRUPT_SUPERBLOCK;
3b5386dc
TT
570 }
571
572 if (ntohl(jsb->s_maxlen) < journal->j_maxlen)
573 journal->j_maxlen = ntohl(jsb->s_maxlen);
574 else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) {
0e8a9560
TT
575 com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
576 _("%s: journal too short\n"),
577 ctx->device_name);
3b5386dc
TT
578 return EXT2_ET_CORRUPT_SUPERBLOCK;
579 }
580
581 journal->j_tail_sequence = ntohl(jsb->s_sequence);
ecf1b776 582 journal->j_transaction_sequence = journal->j_tail_sequence;
3b5386dc
TT
583 journal->j_tail = ntohl(jsb->s_start);
584 journal->j_first = ntohl(jsb->s_first);
585 journal->j_last = ntohl(jsb->s_maxlen);
586
587 return 0;
588}
589
53ef44c4 590static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
6a6d3d44 591 journal_t *journal)
3b5386dc 592{
0e8a9560 593 char *p;
424cd2be
TT
594 union {
595 uuid_t uuid;
596 __u32 val[4];
597 } u;
598 __u32 new_seq = 0;
599 int i;
600
0e8a9560
TT
601 /* Leave a valid existing V1 superblock signature alone.
602 * Anything unrecognisable we overwrite with a new V2
603 * signature. */
efc6f628 604
0e8a9560
TT
605 if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
606 jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
607 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
608 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
609 }
610
611 /* Zero out everything else beyond the superblock header */
efc6f628 612
0e8a9560
TT
613 p = ((char *) jsb) + sizeof(journal_header_t);
614 memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
615
3b5386dc 616 jsb->s_blocksize = htonl(ctx->fs->blocksize);
0e8a9560
TT
617 jsb->s_maxlen = htonl(journal->j_maxlen);
618 jsb->s_first = htonl(1);
0e8a9560 619
424cd2be
TT
620 /* Initialize the journal sequence number so that there is "no"
621 * chance we will find old "valid" transactions in the journal.
622 * This avoids the need to zero the whole journal (slow to do,
623 * and risky when we are just recovering the filesystem).
624 */
625 uuid_generate(u.uuid);
626 for (i = 0; i < 4; i ++)
627 new_seq ^= u.val[i];
628 jsb->s_sequence = htonl(new_seq);
0e8a9560 629
8cf93332 630 mark_buffer_dirty(journal->j_sb_buffer);
0e8a9560 631 ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
3b5386dc
TT
632}
633
6a6d3d44
TT
634static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
635 journal_t *journal,
636 struct problem_context *pctx)
3b5386dc 637{
5dd8f963
TT
638 struct ext2_super_block *sb = ctx->fs->super;
639 int recover = ctx->fs->super->s_feature_incompat &
640 EXT3_FEATURE_INCOMPAT_RECOVER;
3b5386dc 641
5dd8f963 642 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
3b5386dc 643 if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
b2f93192
TT
644 e2fsck_journal_reset_super(ctx, journal->j_superblock,
645 journal);
3b5386dc
TT
646 journal->j_transaction_sequence = 1;
647 e2fsck_clear_recover(ctx, recover);
648 return 0;
649 }
650 return EXT2_ET_CORRUPT_SUPERBLOCK;
651 } else if (e2fsck_journal_fix_bad_inode(ctx, pctx))
652 return EXT2_ET_CORRUPT_SUPERBLOCK;
653
654 return 0;
655}
656
6a6d3d44
TT
657static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
658 int reset, int drop)
3b5386dc
TT
659{
660 journal_superblock_t *jsb;
661
6a6d3d44
TT
662 if (drop)
663 mark_buffer_clean(journal->j_sb_buffer);
664 else if (!(ctx->options & E2F_OPT_READONLY)) {
3b5386dc
TT
665 jsb = journal->j_superblock;
666 jsb->s_sequence = htonl(journal->j_transaction_sequence);
667 if (reset)
668 jsb->s_start = 0; /* this marks the journal as empty */
8cf93332 669 mark_buffer_dirty(journal->j_sb_buffer);
3b5386dc
TT
670 }
671 brelse(journal->j_sb_buffer);
672
6d222f32
TT
673 if (ctx->journal_io) {
674 if (ctx->fs && ctx->fs->io != ctx->journal_io)
675 io_channel_close(ctx->journal_io);
676 ctx->journal_io = 0;
677 }
efc6f628 678
d1a2182a 679#ifndef USE_INODE_IO
3b5386dc 680 if (journal->j_inode)
c4e3d3f3 681 ext2fs_free_mem(&journal->j_inode);
d1a2182a
TT
682#endif
683 if (journal->j_fs_dev)
c4e3d3f3
TT
684 ext2fs_free_mem(&journal->j_fs_dev);
685 ext2fs_free_mem(&journal);
3b5386dc
TT
686}
687
9b565759
TT
688/*
689 * This function makes sure that the superblock fields regarding the
690 * journal are consistent.
691 */
3b5386dc
TT
692int e2fsck_check_ext3_journal(e2fsck_t ctx)
693{
5dd8f963 694 struct ext2_super_block *sb = ctx->fs->super;
3b5386dc 695 journal_t *journal;
5dd8f963
TT
696 int recover = ctx->fs->super->s_feature_incompat &
697 EXT3_FEATURE_INCOMPAT_RECOVER;
3b5386dc 698 struct problem_context pctx;
d37066a9 699 problem_t problem;
d3f35b64 700 int reset = 0, force_fsck = 0;
3b5386dc
TT
701 int retval;
702
703 /* If we don't have any journal features, don't do anything more */
5dd8f963
TT
704 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
705 !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 &&
706 uuid_is_null(sb->s_journal_uuid))
9b565759 707 return 0;
3b5386dc
TT
708
709 clear_problem_context(&pctx);
5dd8f963 710 pctx.num = sb->s_journal_inum;
3b5386dc
TT
711
712 retval = e2fsck_get_journal(ctx, &journal);
713 if (retval) {
f2d5c937 714 if ((retval == EXT2_ET_BAD_INODE_NUM) ||
6e4fbbeb 715 (retval == EXT2_ET_BAD_BLOCK_NUM) ||
f2d5c937
TT
716 (retval == EXT2_ET_JOURNAL_TOO_SMALL) ||
717 (retval == EXT2_ET_NO_JOURNAL))
3b5386dc
TT
718 return e2fsck_journal_fix_bad_inode(ctx, &pctx);
719 return retval;
720 }
721
722 retval = e2fsck_journal_load(journal);
723 if (retval) {
c7f23364 724 if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
2f686ace
TT
725 ((retval == EXT2_ET_UNSUPP_FEATURE) &&
726 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT,
727 &pctx))) ||
728 ((retval == EXT2_ET_RO_UNSUPP_FEATURE) &&
729 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT,
730 &pctx))) ||
c7f23364
TT
731 ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) &&
732 (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx))))
6a6d3d44
TT
733 retval = e2fsck_journal_fix_corrupt_super(ctx, journal,
734 &pctx);
735 e2fsck_journal_release(ctx, journal, 0, 1);
3b5386dc
TT
736 return retval;
737 }
738
739 /*
740 * We want to make the flags consistent here. We will not leave with
741 * needs_recovery set but has_journal clear. We can't get in a loop
742 * with -y, -n, or -p, only if a user isn't making up their mind.
743 */
744no_has_journal:
5dd8f963
TT
745 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
746 recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
3b5386dc
TT
747 pctx.str = "inode";
748 if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) {
749 if (recover &&
750 !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx))
751 goto no_has_journal;
d3f35b64
TT
752 /*
753 * Need a full fsck if we are releasing a
8c2dc521 754 * journal stored on a reserved inode.
d3f35b64
TT
755 */
756 force_fsck = recover ||
757 (sb->s_journal_inum < EXT2_FIRST_INODE(sb));
758 /* Clear all of the journal fields */
5dd8f963 759 sb->s_journal_inum = 0;
d3f35b64
TT
760 sb->s_journal_dev = 0;
761 memset(sb->s_journal_uuid, 0,
762 sizeof(sb->s_journal_uuid));
763 e2fsck_clear_recover(ctx, force_fsck);
3b5386dc 764 } else if (!(ctx->options & E2F_OPT_READONLY)) {
5dd8f963 765 sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
0cfce7f7 766 ctx->fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
3b5386dc
TT
767 ext2fs_mark_super_dirty(ctx->fs);
768 }
769 }
770
5dd8f963
TT
771 if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
772 !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
3b5386dc 773 journal->j_superblock->s_start != 0) {
d37066a9
TT
774 /* Print status information */
775 fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx);
776 if (ctx->superblock)
777 problem = PR_0_JOURNAL_RUN_DEFAULT;
778 else
779 problem = PR_0_JOURNAL_RUN;
780 if (fix_problem(ctx, problem, &pctx)) {
781 ctx->options |= E2F_OPT_FORCE;
782 sb->s_feature_incompat |=
783 EXT3_FEATURE_INCOMPAT_RECOVER;
784 ext2fs_mark_super_dirty(ctx->fs);
785 } else if (fix_problem(ctx,
786 PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
3b5386dc 787 reset = 1;
d3f35b64
TT
788 sb->s_state &= ~EXT2_VALID_FS;
789 ext2fs_mark_super_dirty(ctx->fs);
790 }
791 /*
792 * If the user answers no to the above question, we
793 * ignore the fact that journal apparently has data;
794 * accidentally replaying over valid data would be far
795 * worse than skipping a questionable recovery.
efc6f628 796 *
d3f35b64
TT
797 * XXX should we abort with a fatal error here? What
798 * will the ext3 kernel code do if a filesystem with
799 * !NEEDS_RECOVERY but with a non-zero
800 * journal->j_superblock->s_start is mounted?
801 */
3b5386dc
TT
802 }
803
6a6d3d44 804 e2fsck_journal_release(ctx, journal, reset, 0);
3b5386dc
TT
805 return retval;
806}
807
6a6d3d44 808static errcode_t recover_ext3_journal(e2fsck_t ctx)
3b5386dc 809{
185c4aea 810 struct problem_context pctx;
3b5386dc
TT
811 journal_t *journal;
812 int retval;
813
185c4aea
TT
814 clear_problem_context(&pctx);
815
8cf93332 816 journal_init_revoke_caches();
3b5386dc
TT
817 retval = e2fsck_get_journal(ctx, &journal);
818 if (retval)
ecf1b776
TT
819 return retval;
820
3b5386dc
TT
821 retval = e2fsck_journal_load(journal);
822 if (retval)
6a6d3d44 823 goto errout;
3b5386dc 824
0e8a9560
TT
825 retval = journal_init_revoke(journal, 1024);
826 if (retval)
6a6d3d44 827 goto errout;
efc6f628 828
3b5386dc 829 retval = -journal_recover(journal);
c0a083fa
TT
830 if (retval)
831 goto errout;
efc6f628 832
185c4aea
TT
833 if (journal->j_failed_commit) {
834 pctx.ino = journal->j_failed_commit;
835 fix_problem(ctx, PR_0_JNL_TXN_CORRUPT, &pctx);
836 ctx->fs->super->s_state |= EXT2_ERROR_FS;
837 ext2fs_mark_super_dirty(ctx->fs);
838 }
839
840
c0a083fa
TT
841 if (journal->j_superblock->s_errno) {
842 ctx->fs->super->s_state |= EXT2_ERROR_FS;
843 ext2fs_mark_super_dirty(ctx->fs);
844 journal->j_superblock->s_errno = 0;
8cf93332 845 mark_buffer_dirty(journal->j_sb_buffer);
c0a083fa 846 }
efc6f628 847
6a6d3d44 848errout:
d1a2182a 849 journal_destroy_revoke(journal);
8cf93332 850 journal_destroy_revoke_caches();
6a6d3d44 851 e2fsck_journal_release(ctx, journal, 1, 0);
3b5386dc
TT
852 return retval;
853}
854
80bfaa3e
TT
855int e2fsck_run_ext3_journal(e2fsck_t ctx)
856{
857 io_manager io_ptr = ctx->fs->io->manager;
858 int blocksize = ctx->fs->blocksize;
ecf1b776 859 errcode_t retval, recover_retval;
27a407df
TT
860 io_stats stats = 0;
861 unsigned long long kbytes_written = 0;
8394902e
TT
862
863 printf(_("%s: recovering journal\n"), ctx->device_name);
ecf1b776 864 if (ctx->options & E2F_OPT_READONLY) {
8394902e 865 printf(_("%s: won't do journal recovery while read-only\n"),
ecf1b776
TT
866 ctx->device_name);
867 return EXT2_ET_FILE_RO;
868 }
869
0f2cfe25 870 if (ctx->fs->flags & EXT2_FLAG_DIRTY)
3c6b8977 871 ext2fs_flush(ctx->fs); /* Force out any modifications */
d0515212 872
ecf1b776 873 recover_retval = recover_ext3_journal(ctx);
efc6f628 874
80bfaa3e
TT
875 /*
876 * Reload the filesystem context to get up-to-date data from disk
877 * because journal recovery will change the filesystem under us.
878 */
27a407df
TT
879 if (ctx->fs->super->s_kbytes_written &&
880 ctx->fs->io->manager->get_stats)
881 ctx->fs->io->manager->get_stats(ctx->fs->io, &stats);
882 if (stats && stats->bytes_written)
883 kbytes_written = stats->bytes_written >> 10;
884 ext2fs_free(ctx->fs);
ecf1b776 885 retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW,
80bfaa3e
TT
886 ctx->superblock, blocksize, io_ptr,
887 &ctx->fs);
80bfaa3e
TT
888 if (retval) {
889 com_err(ctx->program_name, retval,
890 _("while trying to re-open %s"),
891 ctx->device_name);
99a2cc96 892 fatal_error(ctx, 0);
80bfaa3e
TT
893 }
894 ctx->fs->priv_data = ctx;
8dceb924 895 ctx->fs->now = ctx->now;
058ad1c7 896 ctx->fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
27a407df 897 ctx->fs->super->s_kbytes_written += kbytes_written;
17390c04 898
ecf1b776
TT
899 /* Set the superblock flags */
900 e2fsck_clear_recover(ctx, recover_retval);
901 return recover_retval;
17390c04 902}
773fd8a1
TT
903
904/*
905 * This function will move the journal inode from a visible file in
906 * the filesystem directory hierarchy to the reserved inode if necessary.
907 */
546a1ff1 908static const char * const journal_names[] = {
773fd8a1
TT
909 ".journal", "journal", ".journal.dat", "journal.dat", 0 };
910
911void e2fsck_move_ext3_journal(e2fsck_t ctx)
912{
913 struct ext2_super_block *sb = ctx->fs->super;
914 struct problem_context pctx;
915 struct ext2_inode inode;
916 ext2_filsys fs = ctx->fs;
917 ext2_ino_t ino;
918 errcode_t retval;
919 const char * const * cpp;
920 int group, mount_flags;
efc6f628 921
a435ec34
TT
922 clear_problem_context(&pctx);
923
773fd8a1
TT
924 /*
925 * If the filesystem is opened read-only, or there is no
a435ec34 926 * journal, then do nothing.
773fd8a1
TT
927 */
928 if ((ctx->options & E2F_OPT_READONLY) ||
929 (sb->s_journal_inum == 0) ||
773fd8a1
TT
930 !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
931 return;
932
a435ec34
TT
933 /*
934 * Read in the journal inode
935 */
936 if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0)
937 return;
938
939 /*
940 * If it's necessary to backup the journal inode, do so.
941 */
942 if ((sb->s_jnl_backup_type == 0) ||
943 ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) &&
944 memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) {
945 if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) {
946 memcpy(sb->s_jnl_blocks, inode.i_block,
947 EXT2_N_BLOCKS*4);
931b58e1 948 sb->s_jnl_blocks[15] = inode.i_size_high;
a435ec34
TT
949 sb->s_jnl_blocks[16] = inode.i_size;
950 sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
951 ext2fs_mark_super_dirty(fs);
27479eb2 952 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
a435ec34
TT
953 }
954 }
955
956 /*
957 * If the journal is already the hidden inode, then do nothing
958 */
959 if (sb->s_journal_inum == EXT2_JOURNAL_INO)
960 return;
efc6f628 961
a435ec34
TT
962 /*
963 * The journal inode had better have only one link and not be readable.
964 */
965 if (inode.i_links_count != 1)
966 return;
967
773fd8a1
TT
968 /*
969 * If the filesystem is mounted, or we can't tell whether
970 * or not it's mounted, do nothing.
971 */
972 retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
973 if (retval || (mount_flags & EXT2_MF_MOUNTED))
974 return;
975
976 /*
977 * If we can't find the name of the journal inode, then do
978 * nothing.
979 */
980 for (cpp = journal_names; *cpp; cpp++) {
981 retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp,
982 strlen(*cpp), 0, &ino);
983 if ((retval == 0) && (ino == sb->s_journal_inum))
984 break;
985 }
986 if (*cpp == 0)
987 return;
988
773fd8a1
TT
989 /* We need the inode bitmap to be loaded */
990 retval = ext2fs_read_bitmaps(fs);
991 if (retval)
992 return;
993
773fd8a1
TT
994 pctx.str = *cpp;
995 if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx))
996 return;
efc6f628 997
773fd8a1
TT
998 /*
999 * OK, we've done all the checks, let's actually move the
1000 * journal inode. Errors at this point mean we need to force
1001 * an ext2 filesystem check.
1002 */
1003 if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0)
1004 goto err_out;
1005 if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0)
1006 goto err_out;
1007 sb->s_journal_inum = EXT2_JOURNAL_INO;
1008 ext2fs_mark_super_dirty(fs);
27479eb2 1009 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
773fd8a1 1010 inode.i_links_count = 0;
1f3ad14a 1011 inode.i_dtime = ctx->now;
773fd8a1
TT
1012 if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
1013 goto err_out;
1014
1015 group = ext2fs_group_of_ino(fs, ino);
c5d2f50d 1016 ext2fs_unmark_inode_bitmap2(fs->inode_map, ino);
773fd8a1 1017 ext2fs_mark_ib_dirty(fs);
d7cca6b0 1018 ext2fs_bg_free_inodes_count_set(fs, group, ext2fs_bg_free_inodes_count(fs, group) + 1);
49a7360b 1019 ext2fs_group_desc_csum_set(fs, group);
773fd8a1
TT
1020 fs->super->s_free_inodes_count++;
1021 return;
1022
1023err_out:
1024 pctx.errcode = retval;
1025 fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx);
1026 fs->super->s_state &= ~EXT2_VALID_FS;
1027 ext2fs_mark_super_dirty(fs);
1028 return;
1029}
1030
b1c52b26
TT
1031/*
1032 * This function makes sure the superblock hint for the external
1033 * journal is correct.
1034 */
1035int e2fsck_fix_ext3_journal_hint(e2fsck_t ctx)
1036{
1037 struct ext2_super_block *sb = ctx->fs->super;
1038 struct problem_context pctx;
1039 char uuid[37], *journal_name;
1040 struct stat st;
b1c52b26
TT
1041
1042 if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) ||
1043 uuid_is_null(sb->s_journal_uuid))
1044 return 0;
1045
1046 uuid_unparse(sb->s_journal_uuid, uuid);
1047 journal_name = blkid_get_devname(ctx->blkid, "UUID", uuid);
1048 if (!journal_name)
1049 return 0;
1050
1051 if (stat(journal_name, &st) < 0)
1052 return 0;
1053
1054 if (st.st_rdev != sb->s_journal_dev) {
1055 clear_problem_context(&pctx);
1056 pctx.num = st.st_rdev;
1057 if (fix_problem(ctx, PR_0_EXTERNAL_JOURNAL_HINT, &pctx)) {
1058 sb->s_journal_dev = st.st_rdev;
1059 ext2fs_mark_super_dirty(ctx->fs);
1060 }
1061 }
1062
1063 free(journal_name);
1064 return 0;
1065}