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

📄 journal.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Start a commit of the current running transaction (if any).  Returns true * if a transaction was started, and fills its tid in at *ptid */int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid){	int ret = 0;	spin_lock(&journal->j_state_lock);	if (journal->j_running_transaction) {		tid_t tid = journal->j_running_transaction->t_tid;		ret = __jbd2_log_start_commit(journal, tid);		if (ret && ptid)			*ptid = tid;	} else if (journal->j_committing_transaction && ptid) {		/*		 * If ext3_write_super() recently started a commit, then we		 * have to wait for completion of that transaction		 */		*ptid = journal->j_committing_transaction->t_tid;		ret = 1;	}	spin_unlock(&journal->j_state_lock);	return ret;}/* * Wait for a specified commit to complete. * The caller may not hold the journal lock. */int jbd2_log_wait_commit(journal_t *journal, tid_t tid){	int err = 0;#ifdef CONFIG_JBD2_DEBUG	spin_lock(&journal->j_state_lock);	if (!tid_geq(journal->j_commit_request, tid)) {		printk(KERN_EMERG		       "%s: error: j_commit_request=%d, tid=%d\n",		       __FUNCTION__, journal->j_commit_request, tid);	}	spin_unlock(&journal->j_state_lock);#endif	spin_lock(&journal->j_state_lock);	while (tid_gt(tid, journal->j_commit_sequence)) {		jbd_debug(1, "JBD: want %d, j_commit_sequence=%d\n",				  tid, journal->j_commit_sequence);		wake_up(&journal->j_wait_commit);		spin_unlock(&journal->j_state_lock);		wait_event(journal->j_wait_done_commit,				!tid_gt(tid, journal->j_commit_sequence));		spin_lock(&journal->j_state_lock);	}	spin_unlock(&journal->j_state_lock);	if (unlikely(is_journal_aborted(journal))) {		printk(KERN_EMERG "journal commit I/O error\n");		err = -EIO;	}	return err;}/* * Log buffer allocation routines: */int jbd2_journal_next_log_block(journal_t *journal, unsigned long long *retp){	unsigned long blocknr;	spin_lock(&journal->j_state_lock);	J_ASSERT(journal->j_free > 1);	blocknr = journal->j_head;	journal->j_head++;	journal->j_free--;	if (journal->j_head == journal->j_last)		journal->j_head = journal->j_first;	spin_unlock(&journal->j_state_lock);	return jbd2_journal_bmap(journal, blocknr, retp);}/* * Conversion of logical to physical block numbers for the journal * * On external journals the journal blocks are identity-mapped, so * this is a no-op.  If needed, we can use j_blk_offset - everything is * ready. */int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr,		 unsigned long long *retp){	int err = 0;	unsigned long long ret;	if (journal->j_inode) {		ret = bmap(journal->j_inode, blocknr);		if (ret)			*retp = ret;		else {			char b[BDEVNAME_SIZE];			printk(KERN_ALERT "%s: journal block not found "					"at offset %lu on %s\n",				__FUNCTION__,				blocknr,				bdevname(journal->j_dev, b));			err = -EIO;			__journal_abort_soft(journal, err);		}	} else {		*retp = blocknr; /* +journal->j_blk_offset */	}	return err;}/* * We play buffer_head aliasing tricks to write data/metadata blocks to * the journal without copying their contents, but for journal * descriptor blocks we do need to generate bona fide buffers. * * After the caller of jbd2_journal_get_descriptor_buffer() has finished modifying * the buffer's contents they really should run flush_dcache_page(bh->b_page). * But we don't bother doing that, so there will be coherency problems with * mmaps of blockdevs which hold live JBD-controlled filesystems. */struct journal_head *jbd2_journal_get_descriptor_buffer(journal_t *journal){	struct buffer_head *bh;	unsigned long long blocknr;	int err;	err = jbd2_journal_next_log_block(journal, &blocknr);	if (err)		return NULL;	bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);	lock_buffer(bh);	memset(bh->b_data, 0, journal->j_blocksize);	set_buffer_uptodate(bh);	unlock_buffer(bh);	BUFFER_TRACE(bh, "return this buffer");	return jbd2_journal_add_journal_head(bh);}/* * Management for journal control blocks: functions to create and * destroy journal_t structures, and to initialise and read existing * journal blocks from disk.  *//* First: create and setup a journal_t object in memory.  We initialise * very few fields yet: that has to wait until we have created the * journal structures from from scratch, or loaded them from disk. */static journal_t * journal_init_common (void){	journal_t *journal;	int err;	journal = kzalloc(sizeof(*journal), GFP_KERNEL|__GFP_NOFAIL);	if (!journal)		goto fail;	init_waitqueue_head(&journal->j_wait_transaction_locked);	init_waitqueue_head(&journal->j_wait_logspace);	init_waitqueue_head(&journal->j_wait_done_commit);	init_waitqueue_head(&journal->j_wait_checkpoint);	init_waitqueue_head(&journal->j_wait_commit);	init_waitqueue_head(&journal->j_wait_updates);	mutex_init(&journal->j_barrier);	mutex_init(&journal->j_checkpoint_mutex);	spin_lock_init(&journal->j_revoke_lock);	spin_lock_init(&journal->j_list_lock);	spin_lock_init(&journal->j_state_lock);	journal->j_commit_interval = (HZ * JBD2_DEFAULT_MAX_COMMIT_AGE);	/* The journal is marked for error until we succeed with recovery! */	journal->j_flags = JBD2_ABORT;	/* Set up a default-sized revoke table for the new mount. */	err = jbd2_journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH);	if (err) {		kfree(journal);		goto fail;	}	return journal;fail:	return NULL;}/* jbd2_journal_init_dev and jbd2_journal_init_inode: * * Create a journal structure assigned some fixed set of disk blocks to * the journal.  We don't actually touch those disk blocks yet, but we * need to set up all of the mapping information to tell the journaling * system where the journal blocks are. * *//** *  journal_t * jbd2_journal_init_dev() - creates an initialises a journal structure *  @bdev: Block device on which to create the journal *  @fs_dev: Device which hold journalled filesystem for this journal. *  @start: Block nr Start of journal. *  @len:  Length of the journal in blocks. *  @blocksize: blocksize of journalling device *  @returns: a newly created journal_t * * *  jbd2_journal_init_dev creates a journal which maps a fixed contiguous *  range of blocks on an arbitrary block device. * */journal_t * jbd2_journal_init_dev(struct block_device *bdev,			struct block_device *fs_dev,			unsigned long long start, int len, int blocksize){	journal_t *journal = journal_init_common();	struct buffer_head *bh;	int n;	if (!journal)		return NULL;	/* journal descriptor can store up to n blocks -bzzz */	journal->j_blocksize = blocksize;	n = journal->j_blocksize / sizeof(journal_block_tag_t);	journal->j_wbufsize = n;	journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);	if (!journal->j_wbuf) {		printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",			__FUNCTION__);		kfree(journal);		journal = NULL;		goto out;	}	journal->j_dev = bdev;	journal->j_fs_dev = fs_dev;	journal->j_blk_offset = start;	journal->j_maxlen = len;	bh = __getblk(journal->j_dev, start, journal->j_blocksize);	J_ASSERT(bh != NULL);	journal->j_sb_buffer = bh;	journal->j_superblock = (journal_superblock_t *)bh->b_data;out:	return journal;}/** *  journal_t * jbd2_journal_init_inode () - creates a journal which maps to a inode. *  @inode: An inode to create the journal in * * jbd2_journal_init_inode creates a journal which maps an on-disk inode as * the journal.  The inode must exist already, must support bmap() and * must have all data blocks preallocated. */journal_t * jbd2_journal_init_inode (struct inode *inode){	struct buffer_head *bh;	journal_t *journal = journal_init_common();	int err;	int n;	unsigned long long blocknr;	if (!journal)		return NULL;	journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev;	journal->j_inode = inode;	jbd_debug(1,		  "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",		  journal, inode->i_sb->s_id, inode->i_ino,		  (long long) inode->i_size,		  inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize);	journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;	journal->j_blocksize = inode->i_sb->s_blocksize;	/* journal descriptor can store up to n blocks -bzzz */	n = journal->j_blocksize / sizeof(journal_block_tag_t);	journal->j_wbufsize = n;	journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);	if (!journal->j_wbuf) {		printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",			__FUNCTION__);		kfree(journal);		return NULL;	}	err = jbd2_journal_bmap(journal, 0, &blocknr);	/* If that failed, give up */	if (err) {		printk(KERN_ERR "%s: Cannnot locate journal superblock\n",		       __FUNCTION__);		kfree(journal);		return NULL;	}	bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);	J_ASSERT(bh != NULL);	journal->j_sb_buffer = bh;	journal->j_superblock = (journal_superblock_t *)bh->b_data;	return journal;}/* * If the journal init or create aborts, we need to mark the journal * superblock as being NULL to prevent the journal destroy from writing * back a bogus superblock. */static void journal_fail_superblock (journal_t *journal){	struct buffer_head *bh = journal->j_sb_buffer;	brelse(bh);	journal->j_sb_buffer = NULL;}/* * Given a journal_t structure, initialise the various fields for * startup of a new journaling session.  We use this both when creating * a journal, and after recovering an old journal to reset it for * subsequent use. */static int journal_reset(journal_t *journal){	journal_superblock_t *sb = journal->j_superblock;	unsigned long long first, last;	first = be32_to_cpu(sb->s_first);	last = be32_to_cpu(sb->s_maxlen);	journal->j_first = first;	journal->j_last = last;	journal->j_head = first;	journal->j_tail = first;	journal->j_free = last - first;	journal->j_tail_sequence = journal->j_transaction_sequence;	journal->j_commit_sequence = journal->j_transaction_sequence - 1;	journal->j_commit_request = journal->j_commit_sequence;	journal->j_max_transaction_buffers = journal->j_maxlen / 4;	/* Add the dynamic fields and write it to disk. */	jbd2_journal_update_superblock(journal, 1);	return jbd2_journal_start_thread(journal);}/** * int jbd2_journal_create() - Initialise the new journal file * @journal: Journal to create. This structure must have been initialised * * Given a journal_t structure which tells us which disk blocks we can * use, create a new journal superblock and initialise all of the * journal fields from scratch. **/int jbd2_journal_create(journal_t *journal){	unsigned long long blocknr;	struct buffer_head *bh;	journal_superblock_t *sb;	int i, err;	if (journal->j_maxlen < JBD2_MIN_JOURNAL_BLOCKS) {		printk (KERN_ERR "Journal length (%d blocks) too short.\n",			journal->j_maxlen);		journal_fail_superblock(journal);		return -EINVAL;	}	if (journal->j_inode == NULL) {		/*		 * We don't know what block to start at!		 */		printk(KERN_EMERG		       "%s: creation of journal on external device!\n",		       __FUNCTION__);		BUG();	}	/* Zero out the entire journal on disk.  We cannot afford to	   have any blocks on disk beginning with JBD2_MAGIC_NUMBER. */	jbd_debug(1, "JBD: Zeroing out journal blocks...\n");	for (i = 0; i < journal->j_maxlen; i++) {		err = jbd2_journal_bmap(journal, i, &blocknr);		if (err)			return err;		bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);		lock_buffer(bh);		memset (bh->b_data, 0, journal->j_blocksize);		BUFFER_TRACE(bh, "marking dirty");		mark_buffer_dirty(bh);		BUFFER_TRACE(bh, "marking uptodate");		set_buffer_uptodate(bh);		unlock_buffer(bh);		__brelse(bh);	}	sync_blockdev(journal->j_dev);	jbd_debug(1, "JBD: journal cleared.\n");	/* OK, fill in the initial static fields in the new superblock */	sb = journal->j_superblock;	sb->s_header.h_magic	 = cpu_to_be32(JBD2_MAGIC_NUMBER);	sb->s_header.h_blocktype = cpu_to_be32(JBD2_SUPERBLOCK_V2);	sb->s_blocksize	= cpu_to_be32(journal->j_blocksize);	sb->s_maxlen	= cpu_to_be32(journal->j_maxlen);	sb->s_first	= cpu_to_be32(1);	journal->j_transaction_sequence = 1;	journal->j_flags &= ~JBD2_ABORT;	journal->j_format_version = 2;	return journal_reset(journal);}/** * void jbd2_journal_update_superblock() - Update journal sb on disk. * @journal: The journal to update. * @wait: Set to '0' if you don't want to wait for IO completion. * * Update a journal's dynamic superblock fields and write it to disk, * optionally waiting for the IO to complete. */void jbd2_journal_update_superblock(journal_t *journal, int wait){	journal_superblock_t *sb = journal->j_superblock;	struct buffer_head *bh = journal->j_sb_buffer;	/*	 * As a special case, if the on-disk copy is already marked as needing	 * no recovery (s_start == 0) and there are no outstanding transactions	 * in the filesystem, then we can safely defer the superblock update	 * until the next commit by setting JBD2_FLUSHED.  This avoids	 * attempting a write to a potential-readonly device.	 */	if (sb->s_start == 0 && journal->j_tail_sequence ==				journal->j_transaction_sequence) {		jbd_debug(1,"JBD: Skipping superblock update on recovered sb "			"(start %ld, seq %d, errno %d)\n",			journal->j_tail, journal->j_tail_sequence,			journal->j_errno);		goto out;	}	spin_lock(&journal->j_state_lock);	jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n",		  journal->j_tail, journal->j_tail_sequence, journal->j_errno);	sb->s_sequence = cpu_to_be32(journal->j_tail_sequence);	sb->s_start    = cpu_to_be32(journal->j_tail);	sb->s_errno    = cpu_to_be32(journal->j_errno);	spin_unlock(&journal->j_state_lock);	BUFFER_TRACE(bh, "marking dirty");	mark_buffer_dirty(bh);	if (wait)		sync_dirty_buffer(bh);	else		ll_rw_block(SWRITE, 1, &bh);out:	/* 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. */	spin_lock(&journal->j_state_lock);	if (sb->s_start)		journal->j_flags &= ~JBD2_FLUSHED;	else		journal->j_flags |= JBD2_FLUSHED;	spin_unlock(&journal->j_state_lock);}/* * 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;

⌨️ 快捷键说明

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