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