ReactOS 0.4.16-dev-336-gb667d82
recovery.c File Reference
#include "jfs_user.h"
Include dependency graph for recovery.c:

Go to the source code of this file.

Classes

struct  recovery_info
 

Macros

#define wrap(journal, var)
 

Enumerations

enum  passtype { PASS_SCAN , PASS_REVOKE , PASS_REPLAY }
 

Functions

static int do_one_pass (journal_t *journal, struct recovery_info *info, enum passtype pass)
 
static int scan_revoke_records (journal_t *, struct buffer_head *, tid_t, struct recovery_info *)
 
static int jread (struct buffer_head **bhp, journal_t *journal, unsigned int offset)
 
static int count_tags (struct buffer_head *bh, int size)
 
int journal_recover (journal_t *journal)
 
int journal_skip_recovery (journal_t *journal)
 

Macro Definition Documentation

◆ wrap

#define wrap (   journal,
  var 
)
Value:
do { \
if (var >= (journal)->j_last) \
var -= ((journal)->j_last - (journal)->j_first); \
} while (0)
const char * var
Definition: shader.c:5666

Definition at line 207 of file recovery.c.

Enumeration Type Documentation

◆ passtype

Enumerator
PASS_SCAN 
PASS_REVOKE 
PASS_REPLAY 

Definition at line 41 of file recovery.c.

@ PASS_REPLAY
Definition: recovery.c:41
@ PASS_REVOKE
Definition: recovery.c:41
@ PASS_SCAN
Definition: recovery.c:41

Function Documentation

◆ count_tags()

static int count_tags ( struct buffer_head bh,
int  size 
)
static

Definition at line 182 of file recovery.c.

183{
184 char * tagp;
186 int nr = 0;
187
188 tagp = &bh->b_data[sizeof(journal_header_t)];
189
190 while (((int)(tagp - bh->b_data) + (int)sizeof(journal_block_tag_t)) <= size) {
191 tag = (journal_block_tag_t *) tagp;
192
193 nr++;
194 tagp += sizeof(journal_block_tag_t);
195 if (!(tag->t_flags & cpu_to_be32(JFS_FLAG_SAME_UUID)))
196 tagp += 16;
197
198 if (tag->t_flags & cpu_to_be32(JFS_FLAG_LAST_TAG))
199 break;
200 }
201
202 return nr;
203}
GLsizeiptr size
Definition: glext.h:5919
#define JFS_FLAG_LAST_TAG
Definition: jbd.h:210
struct journal_block_tag_s journal_block_tag_t
#define JFS_FLAG_SAME_UUID
Definition: jbd.h:208
struct journal_header_s journal_header_t
#define cpu_to_be32
Definition: module.h:156
ULONG nr
Definition: thread.c:7
char * b_data
Definition: module.h:735
Definition: ecma_167.h:138

Referenced by do_one_pass().

◆ do_one_pass()

static int do_one_pass ( journal_t *  journal,
struct recovery_info info,
enum passtype  pass 
)
static

Definition at line 311 of file recovery.c.

313{
314 unsigned int first_commit_ID, next_commit_ID;
315 unsigned long next_log_block;
316 int err, success = 0;
318 journal_header_t * tmp;
319 struct buffer_head * bh;
320 unsigned int sequence;
321 int blocktype;
322
323 /* Precompute the maximum metadata descriptors in a descriptor block */
324 int MAX_BLOCKS_PER_DESC;
325 MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
326 / sizeof(journal_block_tag_t));
327
328 /*
329 * First thing is to establish what we expect to find in the log
330 * (in terms of transaction IDs), and where (in terms of log
331 * block offsets): query the superblock.
332 */
333
334 sb = journal->j_superblock;
335 next_commit_ID = be32_to_cpu(sb->s_sequence);
336 next_log_block = be32_to_cpu(sb->s_start);
337
338 first_commit_ID = next_commit_ID;
339 if (pass == PASS_SCAN)
340 info->start_transaction = first_commit_ID;
341
342 jbd_debug(1, "Starting recovery pass %d\n", pass);
343
344 /*
345 * Now we walk through the log, transaction by transaction,
346 * making sure that each transaction has a commit block in the
347 * expected place. Each complete transaction gets replayed back
348 * into the main filesystem.
349 */
350
351 while (1) {
352 int flags;
353 char * tagp;
355 struct buffer_head * obh;
356 struct buffer_head * nbh;
357
358 cond_resched();
359
360 /* If we already know where to stop the log traversal,
361 * check right now that we haven't gone past the end of
362 * the log. */
363
364 if (pass != PASS_SCAN)
365 if (tid_geq(next_commit_ID, info->end_transaction))
366 break;
367
368 jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
369 next_commit_ID, next_log_block, journal->j_last);
370
371 /* Skip over each chunk of the transaction looking
372 * either the next descriptor block or the final commit
373 * record. */
374
375 jbd_debug(3, "JBD: checking block %ld\n", next_log_block);
376 err = jread(&bh, journal, next_log_block);
377 if (err)
378 goto failed;
379
380 next_log_block++;
381 wrap(journal, next_log_block);
382
383 /* What kind of buffer is it?
384 *
385 * If it is a descriptor block, check that it has the
386 * expected sequence number. Otherwise, we're all done
387 * here. */
388
389 tmp = (journal_header_t *)bh->b_data;
390
392 brelse(bh);
393 break;
394 }
395
396 blocktype = be32_to_cpu(tmp->h_blocktype);
398 jbd_debug(3, "Found magic %d, sequence %d\n",
399 blocktype, sequence);
400
401 if (sequence != next_commit_ID) {
402 brelse(bh);
403 break;
404 }
405
406 /* OK, we have a valid descriptor block which matches
407 * all of the sequence number checks. What are we going
408 * to do with it? That depends on the pass... */
409
410 switch (blocktype) {
412 /* If it is a valid descriptor block, replay it
413 * in pass REPLAY; otherwise, just skip over the
414 * blocks it describes. */
415 if (pass != PASS_REPLAY) {
416 next_log_block +=
417 count_tags(bh, journal->j_blocksize);
418 wrap(journal, next_log_block);
419 brelse(bh);
420 continue;
421 }
422
423 /* A descriptor block: we can now write all of
424 * the data blocks. Yay, useful work is finally
425 * getting done here! */
426
427 tagp = &bh->b_data[sizeof(journal_header_t)];
428 while (((int)(tagp - bh->b_data) + (int)sizeof(journal_block_tag_t))
429 <= journal->j_blocksize) {
430 unsigned long io_block;
431
432 tag = (journal_block_tag_t *) tagp;
433 flags = be32_to_cpu(tag->t_flags);
434
435 io_block = next_log_block++;
436 wrap(journal, next_log_block);
437 err = jread(&obh, journal, io_block);
438 if (err) {
439 /* Recover what we can, but
440 * report failure at the end. */
441 success = err;
443 "JBD: IO error %d recovering "
444 "block %ld in log\n",
445 err, io_block);
446 } else {
447 unsigned long blocknr;
448
449 J_ASSERT(obh != NULL);
450 blocknr = be32_to_cpu(tag->t_blocknr);
451
452 /* If the block has been
453 * revoked, then we're all done
454 * here. */
456 (journal, blocknr,
457 next_commit_ID)) {
458 brelse(obh);
459 ++info->nr_revoke_hits;
460 goto skip_write;
461 }
462
463 /* Find a buffer for the new
464 * data being restored */
465 nbh = __getblk(journal->j_fs_dev,
466 blocknr,
467 journal->j_blocksize);
468 if (nbh == NULL) {
470 "JBD: Out of memory "
471 "during recovery.\n");
472 err = -ENOMEM;
473 brelse(bh);
474 brelse(obh);
475 goto failed;
476 }
477
478 lock_buffer(nbh);
479 memcpy(nbh->b_data, obh->b_data,
480 journal->j_blocksize);
481 if (flags & JFS_FLAG_ESCAPE) {
482 *((__be32 *)bh->b_data) =
484 }
485
486 BUFFER_TRACE(nbh, "marking dirty");
487 set_buffer_uptodate(nbh);
489 BUFFER_TRACE(nbh, "marking uptodate");
490 ++info->nr_replays;
491 /* ll_rw_block(WRITE, 1, &nbh); */
492 unlock_buffer(nbh);
493 brelse(obh);
494 brelse(nbh);
495 }
496
497skip_write:
498 tagp += sizeof(journal_block_tag_t);
499 if (!(flags & JFS_FLAG_SAME_UUID))
500 tagp += 16;
501
503 break;
504 }
505
506 brelse(bh);
507 continue;
508
509 case JFS_COMMIT_BLOCK:
510 /* Found an expected commit block: not much to
511 * do other than move on to the next sequence
512 * number. */
513 brelse(bh);
514 next_commit_ID++;
515 continue;
516
517 case JFS_REVOKE_BLOCK:
518 /* If we aren't in the REVOKE pass, then we can
519 * just skip over this block. */
520 if (pass != PASS_REVOKE) {
521 brelse(bh);
522 continue;
523 }
524
525 err = scan_revoke_records(journal, bh,
526 next_commit_ID, info);
527 brelse(bh);
528 if (err)
529 goto failed;
530 continue;
531
532 default:
533 jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
534 blocktype);
535 brelse(bh);
536 goto done;
537 }
538 }
539
540done:
541 /*
542 * We broke out of the log scan loop: either we came to the
543 * known end of the log or we found an unexpected block in the
544 * log. If the latter happened, then we know that the "current"
545 * transaction marks the end of the valid log.
546 */
547
548 if (pass == PASS_SCAN)
549 info->end_transaction = next_commit_ID;
550 else {
551 /* It's really bad news if different passes end up at
552 * different places (but possible due to IO errors). */
553 if (info->end_transaction != next_commit_ID) {
554 printk (KERN_ERR "JBD: recovery pass %d ended at "
555 "transaction %u, expected %u\n",
556 pass, next_commit_ID, info->end_transaction);
557 if (!success)
558 success = -EIO;
559 }
560 }
561
562 return success;
563
564failed:
565 return err;
566}
static struct recvd_message * sequence
Definition: SystemMenu.c:63
#define ENOMEM
Definition: acclib.h:84
#define EIO
Definition: acclib.h:81
#define NULL
Definition: types.h:112
superblock * sb
Definition: btrfs.c:4261
__u32 __bitwise __be32
Definition: types.h:67
static int scan_revoke_records(journal_t *, struct buffer_head *, tid_t, struct recovery_info *)
Definition: recovery.c:571
static int count_tags(struct buffer_head *bh, int size)
Definition: recovery.c:182
#define wrap(journal, var)
Definition: recovery.c:207
static int jread(struct buffer_head **bhp, journal_t *journal, unsigned int offset)
Definition: recovery.c:132
GLbitfield flags
Definition: glext.h:7161
#define JFS_REVOKE_BLOCK
Definition: jbd.h:173
#define JFS_DESCRIPTOR_BLOCK
Definition: jbd.h:169
#define JFS_COMMIT_BLOCK
Definition: jbd.h:170
#define JFS_MAGIC_NUMBER
Definition: jbd.h:159
static int tid_geq(tid_t x, tid_t y)
Definition: jbd.h:1091
#define JFS_FLAG_ESCAPE
Definition: jbd.h:207
if(dx< 0)
Definition: linetemp.h:194
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static cond_resched()
Definition: module.h:437
static void lock_buffer(struct buffer_head *bh)
Definition: module.h:1028
void unlock_buffer(struct buffer_head *bh)
Definition: linux.c:853
struct buffer_head * __getblk(struct block_device *bdev, sector_t block, unsigned long size)
Definition: linux.c:799
#define printk
Definition: module.h:231
#define be32_to_cpu
Definition: module.h:157
static void brelse(struct buffer_head *bh)
Definition: module.h:955
void mark_buffer_dirty(struct buffer_head *bh)
Definition: linux.c:914
#define KERN_ERR
Definition: module.h:225
#define err(...)
int journal_test_revoke(journal_t *journal, unsigned long blocknr, tid_t sequence)
Definition: revoke.c:670
__be32 h_blocktype
Definition: jbd.h:181
__be32 h_magic
Definition: jbd.h:180
__be32 h_sequence
Definition: jbd.h:182
pass
Definition: typegen.h:25
#define success(from, fromstr, to, tostr)

Referenced by journal_recover(), and journal_skip_recovery().

◆ journal_recover()

int journal_recover ( journal_t *  journal)

journal_recover - recovers a on-disk journal @journal: the journal to recover

The primary function for recovering the log contents when mounting a journaled device.

Recovery is done in three passes. In the first pass, we look for the end of the log. In the second, we assemble the list of revoke blocks. In the third and final pass, we replay any un-revoked blocks in the log.

Definition at line 225 of file recovery.c.

226{
227 int err;
229
230 struct recovery_info info;
231
232 memset(&info, 0, sizeof(info));
233 sb = journal->j_superblock;
234
235 /*
236 * The journal superblock's s_start field (the current log head)
237 * is always zero if, and only if, the journal was cleanly
238 * unmounted.
239 */
240
241 if (!sb->s_start) {
242 jbd_debug(1, "No recovery required, last transaction %d\n",
243 be32_to_cpu(sb->s_sequence));
244 journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1;
245 return 0;
246 }
247
248 err = do_one_pass(journal, &info, PASS_SCAN);
249 if (!err)
250 err = do_one_pass(journal, &info, PASS_REVOKE);
251 if (!err)
252 err = do_one_pass(journal, &info, PASS_REPLAY);
253
254 jbd_debug(1, "JBD: recovery, exit status %d, "
255 "recovered transactions %u to %u\n",
256 err, info.start_transaction, info.end_transaction);
257 jbd_debug(1, "JBD: Replayed %d and revoked %d/%d blocks\n",
258 info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
259
260 /* Restart the log at the next transaction ID, thus invalidating
261 * any existing commit records in the log. */
262 journal->j_transaction_sequence = ++info.end_transaction;
263
264 journal_clear_revoke(journal);
265 sync_blockdev(journal->j_fs_dev);
266 return err;
267}
static int do_one_pass(journal_t *journal, struct recovery_info *info, enum passtype pass)
Definition: recovery.c:311
int sync_blockdev(struct block_device *bdev)
Definition: linux.c:919
void journal_clear_revoke(journal_t *journal)
Definition: revoke.c:689
#define memset(x, y, z)
Definition: compat.h:39

Referenced by journal_load().

◆ journal_skip_recovery()

int journal_skip_recovery ( journal_t *  journal)

journal_skip_recovery - Start journal and wipe exiting records @journal: journal to startup

Locate any valid recovery information from the journal and set up the journal structures in memory to ignore it (presumably because the caller has evidence that it is out of date). This function does'nt appear to be exorted..

We perform one pass over the journal to allow us to tell the user how much recovery information is being erased, and to let us initialise the journal transaction sequence numbers to the next unused ID.

Definition at line 282 of file recovery.c.

283{
284 int err;
286
287 struct recovery_info info;
288
289 memset (&info, 0, sizeof(info));
290 sb = journal->j_superblock;
291
292 err = do_one_pass(journal, &info, PASS_SCAN);
293
294 if (err) {
295 printk(KERN_ERR "JBD: error %d scanning journal\n", err);
296 ++journal->j_transaction_sequence;
297 } else {
298#ifdef CONFIG_JBD_DEBUG
299 int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);
300 jbd_debug(1,
301 "JBD: ignoring %d transaction%s from the journal.\n",
302 dropped, (dropped == 1) ? "" : "s");
303#endif
304 journal->j_transaction_sequence = ++info.end_transaction;
305 }
306
307 journal->j_tail = 0;
308 return err;
309}
r dropped
Definition: btrfs.c:3014

Referenced by journal_wipe().

◆ jread()

static int jread ( struct buffer_head **  bhp,
journal_t *  journal,
unsigned int  offset 
)
static

Definition at line 132 of file recovery.c.

134{
135 int err;
136 unsigned long blocknr;
137 struct buffer_head *bh;
138
139 *bhp = NULL;
140
141 if (offset >= journal->j_maxlen) {
142 printk(KERN_ERR "JBD: corrupted journal superblock\n");
143 return -EIO;
144 }
145
146 err = journal_bmap(journal, offset, &blocknr);
147
148 if (err) {
149 printk (KERN_ERR "JBD: bad block at offset %u\n",
150 offset);
151 return err;
152 }
153
154 bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
155 if (!bh)
156 return -ENOMEM;
157
158 if (!buffer_uptodate(bh)) {
159 /* If this is a brand new buffer, start readahead.
160 Otherwise, we assume we are already reading it. */
161 if (!buffer_req(bh))
162 do_readahead(journal, offset);
163 wait_on_buffer(bh);
164 }
165
166 if (!buffer_uptodate(bh)) {
167 printk (KERN_ERR "JBD: Failed to read block at offset %u\n",
168 offset);
169 brelse(bh);
170 return -EIO;
171 }
172
173 *bhp = bh;
174 return 0;
175}
GLintptr offset
Definition: glext.h:5920
static void wait_on_buffer(struct buffer_head *bh)
Definition: module.h:1021
int journal_bmap(journal_t *journal, unsigned long blocknr, unsigned long *retp)
Definition: replay.c:484
static int do_readahead(mpg123_handle *fr, unsigned long newhead)
Definition: parse.c:1071

Referenced by do_one_pass().

◆ scan_revoke_records()

static int scan_revoke_records ( journal_t *  journal,
struct buffer_head bh,
tid_t  sequence,
struct recovery_info info 
)
static

Definition at line 571 of file recovery.c.

573{
575 int offset, max;
576
579 max = be32_to_cpu(header->r_count);
580
581 while (offset < max) {
582 unsigned long blocknr;
583 int err;
584
585 blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset)));
586 offset += 4;
587 err = journal_set_revoke(journal, blocknr, sequence);
588 if (err)
589 return err;
590 ++info->nr_revokes;
591 }
592 return 0;
593}
int journal_set_revoke(journal_t *journal, unsigned long blocknr, tid_t sequence)
Definition: revoke.c:646
#define max(a, b)
Definition: svc.c:63

Referenced by do_one_pass().