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

📄 journal.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (wait)		wait_on_buffer(bh);	/* If we have just flushed the log (by marking s_start==0), then	 * any future commit will have to be careful to update the	 * superblock again to re-record the true start of the log. */	if (sb->s_start)		journal->j_flags &= ~JFS_FLUSHED;	else		journal->j_flags |= JFS_FLUSHED;}/* * Read the superblock for a given journal, performing initial * validation of the format. */static int journal_get_superblock(journal_t *journal){	struct buffer_head *bh;	journal_superblock_t *sb;	int err = -EIO;		bh = journal->j_sb_buffer;	J_ASSERT(bh != NULL);	if (!buffer_uptodate(bh)) {		ll_rw_block(READ, 1, &bh);		wait_on_buffer(bh);		if (!buffer_uptodate(bh)) {			printk (KERN_ERR				"JBD: IO error reading journal superblock\n");			goto out;		}	}	sb = journal->j_superblock;	err = -EINVAL;		if (sb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||	    sb->s_blocksize != htonl(journal->j_blocksize)) {		printk(KERN_WARNING "JBD: no valid journal superblock found\n");		goto out;	}	switch(ntohl(sb->s_header.h_blocktype)) {	case JFS_SUPERBLOCK_V1:		journal->j_format_version = 1;		break;	case JFS_SUPERBLOCK_V2:		journal->j_format_version = 2;		break;	default:		printk(KERN_WARNING "JBD: unrecognised superblock format ID\n");		goto out;	}	if (ntohl(sb->s_maxlen) < journal->j_maxlen)		journal->j_maxlen = ntohl(sb->s_maxlen);	else if (ntohl(sb->s_maxlen) > journal->j_maxlen) {		printk (KERN_WARNING "JBD: journal file too short\n");		goto out;	}	return 0;out:	journal_fail_superblock(journal);	return err;}/* * Load the on-disk journal superblock and read the key fields into the * journal_t. */static int load_superblock(journal_t *journal){	int err;	journal_superblock_t *sb;	err = journal_get_superblock(journal);	if (err)		return err;	sb = journal->j_superblock;	journal->j_tail_sequence = ntohl(sb->s_sequence);	journal->j_tail = ntohl(sb->s_start);	journal->j_first = ntohl(sb->s_first);	journal->j_last = ntohl(sb->s_maxlen);	journal->j_errno = ntohl(sb->s_errno);	return 0;}/* * Given a journal_t structure which tells us which disk blocks contain * a journal, read the journal from disk to initialise the in-memory * structures. */int journal_load(journal_t *journal){	int err;	err = load_superblock(journal);	if (err)		return err;	/* If this is a V2 superblock, then we have to check the	 * features flags on it. */	if (journal->j_format_version >= 2) {		journal_superblock_t *sb = journal->j_superblock;		if ((sb->s_feature_ro_compat &		     ~cpu_to_be32(JFS_KNOWN_ROCOMPAT_FEATURES)) ||		    (sb->s_feature_incompat &		     ~cpu_to_be32(JFS_KNOWN_INCOMPAT_FEATURES))) {			printk (KERN_WARNING				"JBD: Unrecognised features on journal\n");			return -EINVAL;		}	}	/* Let the recovery code check whether it needs to recover any	 * data from the journal. */	if (journal_recover(journal))		goto recovery_error;	/* OK, we've finished with the dynamic journal bits:	 * reinitialise the dynamic contents of the superblock in memory	 * and reset them on disk. */	if (journal_reset(journal))		goto recovery_error;	journal->j_flags &= ~JFS_ABORT;	journal->j_flags |= JFS_LOADED;	return 0;recovery_error:	printk (KERN_WARNING "JBD: recovery failed\n");	return -EIO;}/* * Release a journal_t structure once it is no longer in use by the * journaled object. */void journal_destroy (journal_t *journal){	/* Wait for the commit thread to wake up and die. */	journal_kill_thread(journal);	/* Force a final log commit */	if (journal->j_running_transaction)		journal_commit_transaction(journal);	/* Force any old transactions to disk */	lock_journal(journal);	while (journal->j_checkpoint_transactions != NULL)		log_do_checkpoint(journal, 1);	J_ASSERT(journal->j_running_transaction == NULL);	J_ASSERT(journal->j_committing_transaction == NULL);	J_ASSERT(journal->j_checkpoint_transactions == NULL);	/* We can now mark the journal as empty. */	journal->j_tail = 0;	journal->j_tail_sequence = ++journal->j_transaction_sequence;	if (journal->j_sb_buffer) {		journal_update_superblock(journal, 1);		brelse(journal->j_sb_buffer);	}	if (journal->j_inode)		iput(journal->j_inode);	if (journal->j_revoke)		journal_destroy_revoke(journal);	unlock_journal(journal);	kfree(journal);	MOD_DEC_USE_COUNT;}/* Published API: Check whether the journal uses all of a given set of * features.  Return true (non-zero) if it does. */int journal_check_used_features (journal_t *journal, unsigned long compat,				 unsigned long ro, unsigned long incompat){	journal_superblock_t *sb;	if (!compat && !ro && !incompat)		return 1;	if (journal->j_format_version == 1)		return 0;	sb = journal->j_superblock;	if (((be32_to_cpu(sb->s_feature_compat) & compat) == compat) &&	    ((be32_to_cpu(sb->s_feature_ro_compat) & ro) == ro) &&	    ((be32_to_cpu(sb->s_feature_incompat) & incompat) == incompat))		return 1;	return 0;}/* Published API: Check whether the journaling code supports the use of * all of a given set of features on this journal.  Return true * (non-zero) if it can. */int journal_check_available_features (journal_t *journal, unsigned long compat,				      unsigned long ro, unsigned long incompat){	journal_superblock_t *sb;	if (!compat && !ro && !incompat)		return 1;	sb = journal->j_superblock;	/* We can support any known requested features iff the	 * superblock is in version 2.  Otherwise we fail to support any	 * extended sb features. */	if (journal->j_format_version != 2)		return 0;	if ((compat   & JFS_KNOWN_COMPAT_FEATURES) == compat &&	    (ro       & JFS_KNOWN_ROCOMPAT_FEATURES) == ro &&	    (incompat & JFS_KNOWN_INCOMPAT_FEATURES) == incompat)		return 1;	return 0;}/* Published API: Mark a given journal feature as present on the * superblock.  Returns true if the requested features could be set. */int journal_set_features (journal_t *journal, unsigned long compat,			  unsigned long ro, unsigned long incompat){	journal_superblock_t *sb;	if (journal_check_used_features(journal, compat, ro, incompat))		return 1;	if (!journal_check_available_features(journal, compat, ro, incompat))		return 0;	jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n",		  compat, ro, incompat);	sb = journal->j_superblock;	sb->s_feature_compat    |= cpu_to_be32(compat);	sb->s_feature_ro_compat |= cpu_to_be32(ro);	sb->s_feature_incompat  |= cpu_to_be32(incompat);	return 1;}/* * Published API: * Given an initialised but unloaded journal struct, poke about in the * on-disk structure to update it to the most recent supported version. */int journal_update_format (journal_t *journal){	journal_superblock_t *sb;	int err;	err = journal_get_superblock(journal);	if (err)		return err;	sb = journal->j_superblock;	switch (ntohl(sb->s_header.h_blocktype)) {	case JFS_SUPERBLOCK_V2:		return 0;	case JFS_SUPERBLOCK_V1:		return journal_convert_superblock_v1(journal, sb);	default:		break;	}	return -EINVAL;}static int journal_convert_superblock_v1(journal_t *journal,					 journal_superblock_t *sb){	int offset, blocksize;	struct buffer_head *bh;	printk(KERN_WARNING		"JBD: Converting superblock from version 1 to 2.\n");	/* Pre-initialise new fields to zero */	offset = ((char *) &(sb->s_feature_compat)) - ((char *) sb);	blocksize = ntohl(sb->s_blocksize);	memset(&sb->s_feature_compat, 0, blocksize-offset);	sb->s_nr_users = cpu_to_be32(1);	sb->s_header.h_blocktype = cpu_to_be32(JFS_SUPERBLOCK_V2);	journal->j_format_version = 2;	bh = journal->j_sb_buffer;	BUFFER_TRACE(bh, "marking dirty");	mark_buffer_dirty(bh);	ll_rw_block(WRITE, 1, &bh);	wait_on_buffer(bh);	return 0;}/* * Flush all data for a given journal to disk and empty the journal. * Filesystems can use this when remounting readonly to ensure that * recovery does not need to happen on remount. */int journal_flush (journal_t *journal){	int err = 0;	transaction_t *transaction = NULL;	unsigned long old_tail;	lock_kernel();		/* Force everything buffered to the log... */	if (journal->j_running_transaction) {		transaction = journal->j_running_transaction;		log_start_commit(journal, transaction);	} else if (journal->j_committing_transaction)		transaction = journal->j_committing_transaction;	/* Wait for the log commit to complete... */	if (transaction)		log_wait_commit(journal, transaction->t_tid);	/* ...and flush everything in the log out to disk. */	lock_journal(journal);	while (!err && journal->j_checkpoint_transactions != NULL)		err = log_do_checkpoint(journal, journal->j_maxlen);	cleanup_journal_tail(journal);	/* Finally, mark the journal as really needing no recovery.	 * This sets s_start==0 in the underlying superblock, which is	 * the magic code for a fully-recovered superblock.  Any future	 * commits of data to the journal will restore the current	 * s_start value. */	old_tail = journal->j_tail;	journal->j_tail = 0;	journal_update_superblock(journal, 1);	journal->j_tail = old_tail;	unlock_journal(journal);	J_ASSERT(!journal->j_running_transaction);	J_ASSERT(!journal->j_committing_transaction);	J_ASSERT(!journal->j_checkpoint_transactions);	J_ASSERT(journal->j_head == journal->j_tail);	J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence);	unlock_kernel();		return err;}/* * Wipe out all of the contents of a journal, safely.  This will produce * a warning if the journal contains any valid recovery information. * Must be called between journal_init_*() and journal_load(). * * If (write) is non-zero, then we wipe out the journal on disk; otherwise * we merely suppress recovery. */int journal_wipe (journal_t *journal, int write){	journal_superblock_t *sb;	int err = 0;	J_ASSERT (!(journal->j_flags & JFS_LOADED));	err = load_superblock(journal);	if (err)		return err;	sb = journal->j_superblock;	if (!journal->j_tail)		goto no_recovery;	printk (KERN_WARNING "JBD: %s recovery information on journal\n",		write ? "Clearing" : "Ignoring");	err = journal_skip_recovery(journal);	if (write)		journal_update_superblock(journal, 1); no_recovery:	return err;}/* * journal_dev_name: format a character string to describe on what * device this journal is present. */const char * journal_dev_name(journal_t *journal){	kdev_t dev;	if (journal->j_inode)		dev = journal->j_inode->i_dev;	else		dev = journal->j_dev;	return bdevname(dev);}/* * journal_abort: perform a complete, immediate shutdown of the ENTIRE * journal (not of a single transaction).  This operation cannot be * undone without closing and reopening the journal. * * The journal_abort function is intended to support higher level error * recovery mechanisms such as the ext2/ext3 remount-readonly error * mode. * * Journal abort has very specific semantics.  Any existing dirty, * unjournaled buffers in the main filesystem will still be written to * disk by bdflush, but the journaling mechanism will be suspended * immediately and no further transaction commits will be honoured. * * Any dirty, journaled buffers will be written back to disk without * hitting the journal.  Atomicity cannot be guaranteed on an aborted * filesystem, but we _do_ attempt to leave as much data as possible * behind for fsck to use for cleanup. * * Any attempt to get a new transaction handle on a journal which is in * ABORT state will just result in an -EROFS error return.  A * journal_stop on an existing handle will return -EIO if we have * entered abort state during the update. * * Recursive transactions are not disturbed by journal abort until the * final journal_stop, which will receive the -EIO error. * * Finally, the journal_abort call allows the caller to supply an errno * which will be recored (if possible) in the journal superblock.  This * allows a client to record failure conditions in the middle of a * transaction without having to complete the transaction to record the * failure to disk.  ext3_error, for example, now uses this * functionality. * * Errors which originate from within the journaling layer will NOT * supply an errno; a null errno implies that absolutely no further

⌨️ 快捷键说明

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