📄 journal.c
字号:
/* * 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 + -