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

📄 recovery.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	journal->j_tail = 0;	return err;}static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag_t *tag){	unsigned long long block = be32_to_cpu(tag->t_blocknr);	if (tag_bytes > JBD2_TAG_SIZE32)		block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32;	return block;}static int do_one_pass(journal_t *journal,			struct recovery_info *info, enum passtype pass){	unsigned int		first_commit_ID, next_commit_ID;	unsigned long		next_log_block;	int			err, success = 0;	journal_superblock_t *	sb;	journal_header_t *	tmp;	struct buffer_head *	bh;	unsigned int		sequence;	int			blocktype;	int			tag_bytes = journal_tag_bytes(journal);	/* Precompute the maximum metadata descriptors in a descriptor block */	int			MAX_BLOCKS_PER_DESC;	MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))			       / tag_bytes);	/*	 * First thing is to establish what we expect to find in the log	 * (in terms of transaction IDs), and where (in terms of log	 * block offsets): query the superblock.	 */	sb = journal->j_superblock;	next_commit_ID = be32_to_cpu(sb->s_sequence);	next_log_block = be32_to_cpu(sb->s_start);	first_commit_ID = next_commit_ID;	if (pass == PASS_SCAN)		info->start_transaction = first_commit_ID;	jbd_debug(1, "Starting recovery pass %d\n", pass);	/*	 * Now we walk through the log, transaction by transaction,	 * making sure that each transaction has a commit block in the	 * expected place.  Each complete transaction gets replayed back	 * into the main filesystem.	 */	while (1) {		int			flags;		char *			tagp;		journal_block_tag_t *	tag;		struct buffer_head *	obh;		struct buffer_head *	nbh;		cond_resched();		/* We're under lock_kernel() */		/* If we already know where to stop the log traversal,		 * check right now that we haven't gone past the end of		 * the log. */		if (pass != PASS_SCAN)			if (tid_geq(next_commit_ID, info->end_transaction))				break;		jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",			  next_commit_ID, next_log_block, journal->j_last);		/* Skip over each chunk of the transaction looking		 * either the next descriptor block or the final commit		 * record. */		jbd_debug(3, "JBD: checking block %ld\n", next_log_block);		err = jread(&bh, journal, next_log_block);		if (err)			goto failed;		next_log_block++;		wrap(journal, next_log_block);		/* What kind of buffer is it?		 *		 * If it is a descriptor block, check that it has the		 * expected sequence number.  Otherwise, we're all done		 * here. */		tmp = (journal_header_t *)bh->b_data;		if (tmp->h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER)) {			brelse(bh);			break;		}		blocktype = be32_to_cpu(tmp->h_blocktype);		sequence = be32_to_cpu(tmp->h_sequence);		jbd_debug(3, "Found magic %d, sequence %d\n",			  blocktype, sequence);		if (sequence != next_commit_ID) {			brelse(bh);			break;		}		/* OK, we have a valid descriptor block which matches		 * all of the sequence number checks.  What are we going		 * to do with it?  That depends on the pass... */		switch(blocktype) {		case JBD2_DESCRIPTOR_BLOCK:			/* If it is a valid descriptor block, replay it			 * in pass REPLAY; otherwise, just skip over the			 * blocks it describes. */			if (pass != PASS_REPLAY) {				next_log_block += count_tags(journal, bh);				wrap(journal, next_log_block);				brelse(bh);				continue;			}			/* A descriptor block: we can now write all of			 * the data blocks.  Yay, useful work is finally			 * getting done here! */			tagp = &bh->b_data[sizeof(journal_header_t)];			while ((tagp - bh->b_data + tag_bytes)			       <= journal->j_blocksize) {				unsigned long io_block;				tag = (journal_block_tag_t *) tagp;				flags = be32_to_cpu(tag->t_flags);				io_block = next_log_block++;				wrap(journal, next_log_block);				err = jread(&obh, journal, io_block);				if (err) {					/* Recover what we can, but					 * report failure at the end. */					success = err;					printk (KERN_ERR						"JBD: IO error %d recovering "						"block %ld in log\n",						err, io_block);				} else {					unsigned long long blocknr;					J_ASSERT(obh != NULL);					blocknr = read_tag_block(tag_bytes,								 tag);					/* If the block has been					 * revoked, then we're all done					 * here. */					if (jbd2_journal_test_revoke					    (journal, blocknr,					     next_commit_ID)) {						brelse(obh);						++info->nr_revoke_hits;						goto skip_write;					}					/* Find a buffer for the new					 * data being restored */					nbh = __getblk(journal->j_fs_dev,							blocknr,							journal->j_blocksize);					if (nbh == NULL) {						printk(KERN_ERR						       "JBD: Out of memory "						       "during recovery.\n");						err = -ENOMEM;						brelse(bh);						brelse(obh);						goto failed;					}					lock_buffer(nbh);					memcpy(nbh->b_data, obh->b_data,							journal->j_blocksize);					if (flags & JBD2_FLAG_ESCAPE) {						*((__be32 *)bh->b_data) =						cpu_to_be32(JBD2_MAGIC_NUMBER);					}					BUFFER_TRACE(nbh, "marking dirty");					set_buffer_uptodate(nbh);					mark_buffer_dirty(nbh);					BUFFER_TRACE(nbh, "marking uptodate");					++info->nr_replays;					/* ll_rw_block(WRITE, 1, &nbh); */					unlock_buffer(nbh);					brelse(obh);					brelse(nbh);				}			skip_write:				tagp += tag_bytes;				if (!(flags & JBD2_FLAG_SAME_UUID))					tagp += 16;				if (flags & JBD2_FLAG_LAST_TAG)					break;			}			brelse(bh);			continue;		case JBD2_COMMIT_BLOCK:			/* Found an expected commit block: not much to			 * do other than move on to the next sequence			 * number. */			brelse(bh);			next_commit_ID++;			continue;		case JBD2_REVOKE_BLOCK:			/* If we aren't in the REVOKE pass, then we can			 * just skip over this block. */			if (pass != PASS_REVOKE) {				brelse(bh);				continue;			}			err = scan_revoke_records(journal, bh,						  next_commit_ID, info);			brelse(bh);			if (err)				goto failed;			continue;		default:			jbd_debug(3, "Unrecognised magic %d, end of scan.\n",				  blocktype);			brelse(bh);			goto done;		}	} done:	/*	 * We broke out of the log scan loop: either we came to the	 * known end of the log or we found an unexpected block in the	 * log.  If the latter happened, then we know that the "current"	 * transaction marks the end of the valid log.	 */	if (pass == PASS_SCAN)		info->end_transaction = next_commit_ID;	else {		/* It's really bad news if different passes end up at		 * different places (but possible due to IO errors). */		if (info->end_transaction != next_commit_ID) {			printk (KERN_ERR "JBD: recovery pass %d ended at "				"transaction %u, expected %u\n",				pass, next_commit_ID, info->end_transaction);			if (!success)				success = -EIO;		}	}	return success; failed:	return err;}/* Scan a revoke record, marking all blocks mentioned as revoked. */static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,			       tid_t sequence, struct recovery_info *info){	jbd2_journal_revoke_header_t *header;	int offset, max;	int record_len = 4;	header = (jbd2_journal_revoke_header_t *) bh->b_data;	offset = sizeof(jbd2_journal_revoke_header_t);	max = be32_to_cpu(header->r_count);	if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))		record_len = 8;	while (offset + record_len <= max) {		unsigned long long blocknr;		int err;		if (record_len == 4)			blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset)));		else			blocknr = be64_to_cpu(* ((__be64 *) (bh->b_data+offset)));		offset += record_len;		err = jbd2_journal_set_revoke(journal, blocknr, sequence);		if (err)			return err;		++info->nr_revokes;	}	return 0;}

⌨️ 快捷键说明

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