📄 journal.c
字号:
new_bh->b_state = 0; init_buffer(new_bh, NULL, NULL); atomic_set(&new_bh->b_count, 1); new_jh = journal_add_journal_head(new_bh); set_bh_page(new_bh, new_page, new_offset); new_jh->b_transaction = NULL; new_bh->b_size = jh2bh(jh_in)->b_size; new_bh->b_dev = transaction->t_journal->j_dev; new_bh->b_blocknr = blocknr; new_bh->b_state |= (1 << BH_Mapped) | (1 << BH_Dirty); *jh_out = new_jh; /* * Did we need to do an escaping? Now we've done all the * copying, we can finally do so. */ if (do_escape) * ((unsigned int *) mapped_data) = 0; kunmap(new_page); /* * The to-be-written buffer needs to get moved to the io queue, * and the original buffer whose contents we are shadowing or * copying is moved to the transaction's shadow queue. */ JBUFFER_TRACE(jh_in, "file as BJ_Shadow"); journal_file_buffer(jh_in, transaction, BJ_Shadow); JBUFFER_TRACE(new_jh, "file as BJ_IO"); journal_file_buffer(new_jh, transaction, BJ_IO); return do_escape | (done_copy_out << 1);}/* * Allocation code for the journal file. Manage the space left in the * journal, so that we can begin checkpointing when appropriate. *//* * log_space_left: Return the number of free blocks left in the journal. * * Called with the journal already locked. */int log_space_left (journal_t *journal){ int left = journal->j_free; /* Be pessimistic here about the number of those free blocks * which might be required for log descriptor control blocks. */#define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */ left -= MIN_LOG_RESERVED_BLOCKS; if (left <= 0) return 0; left -= (left >> 3); return left;}/* * This function must be non-allocating for PF_MEMALLOC tasks */tid_t log_start_commit (journal_t *journal, transaction_t *transaction){ tid_t target = journal->j_commit_request; lock_kernel(); /* Protect journal->j_running_transaction */ /* * A NULL transaction asks us to commit the currently running * transaction, if there is one. */ if (transaction) target = transaction->t_tid; else { transaction = journal->j_running_transaction; if (!transaction) goto out; target = transaction->t_tid; } /* * Are we already doing a recent enough commit? */ if (tid_geq(journal->j_commit_request, target)) goto out; /* * We want a new commit: OK, mark the request and wakup the * commit thread. We do _not_ do the commit ourselves. */ journal->j_commit_request = target; jbd_debug(1, "JBD: requesting commit %d/%d\n", journal->j_commit_request, journal->j_commit_sequence); wake_up(&journal->j_wait_commit);out: unlock_kernel(); return target;}/* * Wait for a specified commit to complete. * The caller may not hold the journal lock. */void log_wait_commit (journal_t *journal, tid_t tid){ lock_kernel();#ifdef CONFIG_JBD_DEBUG lock_journal(journal); if (!tid_geq(journal->j_commit_request, tid)) { printk(KERN_EMERG __FUNCTION__ ": error: j_commit_request=%d, tid=%d\n", journal->j_commit_request, tid); } unlock_journal(journal);#endif 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); sleep_on(&journal->j_wait_done_commit); } unlock_kernel();}/* * Log buffer allocation routines: */int journal_next_log_block(journal_t *journal, unsigned long *retp){ unsigned long blocknr; 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; return 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 journal_bmap(journal_t *journal, unsigned long blocknr, unsigned long *retp){ int err = 0; unsigned long ret; if (journal->j_inode) { ret = bmap(journal->j_inode, blocknr); if (ret) *retp = ret; else { printk (KERN_ALERT __FUNCTION__ ": journal block not found " "at offset %lu on %s\n", blocknr, bdevname(journal->j_dev)); 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. * * We return a jh whose bh is locked and ready to be populated. */struct journal_head * journal_get_descriptor_buffer(journal_t *journal){ struct buffer_head *bh; unsigned long blocknr; int err; err = journal_next_log_block(journal, &blocknr); if (err) return NULL; bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); lock_buffer(bh); BUFFER_TRACE(bh, "return this buffer"); return 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; MOD_INC_USE_COUNT; journal = jbd_kmalloc(sizeof(*journal), GFP_KERNEL); if (!journal) goto fail; memset(journal, 0, sizeof(*journal)); 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); init_MUTEX(&journal->j_barrier); init_MUTEX(&journal->j_checkpoint_sem); init_MUTEX(&journal->j_sem); journal->j_commit_interval = (HZ * 5); /* The journal is marked for error until we succeed with recovery! */ journal->j_flags = JFS_ABORT; /* Set up a default-sized revoke table for the new mount. */ err = journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH); if (err) { kfree(journal); goto fail; } return journal;fail: MOD_DEC_USE_COUNT; return NULL;}/* journal_init_dev and 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_init_dev creates a journal which maps a fixed contiguous * range of blocks on an arbitrary block device. * * 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 * journal_init_dev(kdev_t dev, kdev_t fs_dev, int start, int len, int blocksize){ journal_t *journal = journal_init_common(); struct buffer_head *bh; if (!journal) return NULL; journal->j_dev = dev; journal->j_fs_dev = fs_dev; journal->j_blk_offset = start; journal->j_maxlen = len; journal->j_blocksize = blocksize; 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; return journal;}journal_t * journal_init_inode (struct inode *inode){ struct buffer_head *bh; journal_t *journal = journal_init_common(); int err; unsigned long blocknr; if (!journal) return NULL; journal->j_dev = inode->i_dev; journal->j_fs_dev = inode->i_dev; journal->j_inode = inode; jbd_debug(1, "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n", journal, bdevname(inode->i_dev), 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; err = journal_bmap(journal, 0, &blocknr); /* If that failed, give up */ if (err) { printk(KERN_ERR __FUNCTION__ ": Cannnot locate journal " "superblock\n"); 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 int first, last; first = ntohl(sb->s_first); last = ntohl(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. */ journal_update_superblock(journal, 1); lock_journal(journal); journal_start_thread(journal); unlock_journal(journal); return 0;}/* * 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 journal_create (journal_t *journal){ unsigned long blocknr; struct buffer_head *bh; journal_superblock_t *sb; int i, err; if (journal->j_maxlen < JFS_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 __FUNCTION__ ": creation of journal on external device!\n"); BUG(); } /* Zero out the entire journal on disk. We cannot afford to have any blocks on disk beginning with JFS_MAGIC_NUMBER. */ jbd_debug(1, "JBD: Zeroing out journal blocks...\n"); for (i = 0; i < journal->j_maxlen; i++) { err = journal_bmap(journal, i, &blocknr); if (err) return err; bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); wait_on_buffer(bh); memset (bh->b_data, 0, journal->j_blocksize); BUFFER_TRACE(bh, "marking dirty"); mark_buffer_dirty(bh); BUFFER_TRACE(bh, "marking uptodate"); mark_buffer_uptodate(bh, 1); __brelse(bh); } sync_dev(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 = htonl(JFS_MAGIC_NUMBER); sb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); sb->s_blocksize = htonl(journal->j_blocksize); sb->s_maxlen = htonl(journal->j_maxlen); sb->s_first = htonl(1); journal->j_transaction_sequence = 1; journal->j_flags &= ~JFS_ABORT; journal->j_format_version = 2; return journal_reset(journal);}/* * Update a journal's dynamic superblock fields and write it to disk, * optionally waiting for the IO to complete.*/void journal_update_superblock(journal_t *journal, int wait){ journal_superblock_t *sb = journal->j_superblock; struct buffer_head *bh = journal->j_sb_buffer; 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 = htonl(journal->j_tail_sequence); sb->s_start = htonl(journal->j_tail); sb->s_errno = htonl(journal->j_errno); BUFFER_TRACE(bh, "marking dirty"); mark_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -