⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 recovery.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/fs/jbd2/recovery.c * * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 * * Copyright 1999-2000 Red Hat Software --- All Rights Reserved * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your * option, any later version, incorporated herein by reference. * * Journal recovery routines for the generic filesystem journaling code; * part of the ext2fs journaling system. */#ifndef __KERNEL__#include "jfs_user.h"#else#include <linux/time.h>#include <linux/fs.h>#include <linux/jbd2.h>#include <linux/errno.h>#include <linux/slab.h>#endif/* * Maintain information about the progress of the recovery job, so that * the different passes can carry information between them. */struct recovery_info{	tid_t		start_transaction;	tid_t		end_transaction;	int		nr_replays;	int		nr_revokes;	int		nr_revoke_hits;};enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};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 *);#ifdef __KERNEL__/* Release readahead buffers after use */static void journal_brelse_array(struct buffer_head *b[], int n){	while (--n >= 0)		brelse (b[n]);}/* * When reading from the journal, we are going through the block device * layer directly and so there is no readahead being done for us.  We * need to implement any readahead ourselves if we want it to happen at * all.  Recovery is basically one long sequential read, so make sure we * do the IO in reasonably large chunks. * * This is not so critical that we need to be enormously clever about * the readahead size, though.  128K is a purely arbitrary, good-enough * fixed value. */#define MAXBUF 8static int do_readahead(journal_t *journal, unsigned int start){	int err;	unsigned int max, nbufs, next;	unsigned long long blocknr;	struct buffer_head *bh;	struct buffer_head * bufs[MAXBUF];	/* Do up to 128K of readahead */	max = start + (128 * 1024 / journal->j_blocksize);	if (max > journal->j_maxlen)		max = journal->j_maxlen;	/* Do the readahead itself.  We'll submit MAXBUF buffer_heads at	 * a time to the block device IO layer. */	nbufs = 0;	for (next = start; next < max; next++) {		err = jbd2_journal_bmap(journal, next, &blocknr);		if (err) {			printk (KERN_ERR "JBD: bad block at offset %u\n",				next);			goto failed;		}		bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);		if (!bh) {			err = -ENOMEM;			goto failed;		}		if (!buffer_uptodate(bh) && !buffer_locked(bh)) {			bufs[nbufs++] = bh;			if (nbufs == MAXBUF) {				ll_rw_block(READ, nbufs, bufs);				journal_brelse_array(bufs, nbufs);				nbufs = 0;			}		} else			brelse(bh);	}	if (nbufs)		ll_rw_block(READ, nbufs, bufs);	err = 0;failed:	if (nbufs)		journal_brelse_array(bufs, nbufs);	return err;}#endif /* __KERNEL__ *//* * Read a block from the journal */static int jread(struct buffer_head **bhp, journal_t *journal,		 unsigned int offset){	int err;	unsigned long long blocknr;	struct buffer_head *bh;	*bhp = NULL;	if (offset >= journal->j_maxlen) {		printk(KERN_ERR "JBD: corrupted journal superblock\n");		return -EIO;	}	err = jbd2_journal_bmap(journal, offset, &blocknr);	if (err) {		printk (KERN_ERR "JBD: bad block at offset %u\n",			offset);		return err;	}	bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);	if (!bh)		return -ENOMEM;	if (!buffer_uptodate(bh)) {		/* If this is a brand new buffer, start readahead.                   Otherwise, we assume we are already reading it.  */		if (!buffer_req(bh))			do_readahead(journal, offset);		wait_on_buffer(bh);	}	if (!buffer_uptodate(bh)) {		printk (KERN_ERR "JBD: Failed to read block at offset %u\n",			offset);		brelse(bh);		return -EIO;	}	*bhp = bh;	return 0;}/* * Count the number of in-use tags in a journal descriptor block. */static int count_tags(journal_t *journal, struct buffer_head *bh){	char *			tagp;	journal_block_tag_t *	tag;	int			nr = 0, size = journal->j_blocksize;	int			tag_bytes = journal_tag_bytes(journal);	tagp = &bh->b_data[sizeof(journal_header_t)];	while ((tagp - bh->b_data + tag_bytes) <= size) {		tag = (journal_block_tag_t *) tagp;		nr++;		tagp += tag_bytes;		if (!(tag->t_flags & cpu_to_be32(JBD2_FLAG_SAME_UUID)))			tagp += 16;		if (tag->t_flags & cpu_to_be32(JBD2_FLAG_LAST_TAG))			break;	}	return nr;}/* Make sure we wrap around the log correctly! */#define wrap(journal, var)						\do {									\	if (var >= (journal)->j_last)					\		var -= ((journal)->j_last - (journal)->j_first);	\} while (0)/** * jbd2_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. */int jbd2_journal_recover(journal_t *journal){	int			err;	journal_superblock_t *	sb;	struct recovery_info	info;	memset(&info, 0, sizeof(info));	sb = journal->j_superblock;	/*	 * The journal superblock's s_start field (the current log head)	 * is always zero if, and only if, the journal was cleanly	 * unmounted.	 */	if (!sb->s_start) {		jbd_debug(1, "No recovery required, last transaction %d\n",			  be32_to_cpu(sb->s_sequence));		journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1;		return 0;	}	err = do_one_pass(journal, &info, PASS_SCAN);	if (!err)		err = do_one_pass(journal, &info, PASS_REVOKE);	if (!err)		err = do_one_pass(journal, &info, PASS_REPLAY);	jbd_debug(1, "JBD: recovery, exit status %d, "		  "recovered transactions %u to %u\n",		  err, info.start_transaction, info.end_transaction);	jbd_debug(1, "JBD: Replayed %d and revoked %d/%d blocks\n",		  info.nr_replays, info.nr_revoke_hits, info.nr_revokes);	/* Restart the log at the next transaction ID, thus invalidating	 * any existing commit records in the log. */	journal->j_transaction_sequence = ++info.end_transaction;	jbd2_journal_clear_revoke(journal);	sync_blockdev(journal->j_fs_dev);	return err;}/** * jbd2_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. */int jbd2_journal_skip_recovery(journal_t *journal){	int			err;	journal_superblock_t *	sb;	struct recovery_info	info;	memset (&info, 0, sizeof(info));	sb = journal->j_superblock;	err = do_one_pass(journal, &info, PASS_SCAN);	if (err) {		printk(KERN_ERR "JBD: error %d scanning journal\n", err);		++journal->j_transaction_sequence;	} else {#ifdef CONFIG_JBD2_DEBUG		int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);#endif		jbd_debug(1,			  "JBD: ignoring %d transaction%s from the journal.\n",			  dropped, (dropped == 1) ? "" : "s");		journal->j_transaction_sequence = ++info.end_transaction;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -