📄 journal.c
字号:
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 != cpu_to_be32(JFS_MAGIC_NUMBER) || sb->s_blocksize != cpu_to_be32(journal->j_blocksize)) { printk(KERN_WARNING "JBD: no valid journal superblock found\n"); goto out; } switch(be32_to_cpu(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 (be32_to_cpu(sb->s_maxlen) < journal->j_maxlen) journal->j_maxlen = be32_to_cpu(sb->s_maxlen); else if (be32_to_cpu(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 = be32_to_cpu(sb->s_sequence); journal->j_tail = be32_to_cpu(sb->s_start); journal->j_first = be32_to_cpu(sb->s_first); journal->j_last = be32_to_cpu(sb->s_maxlen); journal->j_errno = be32_to_cpu(sb->s_errno); return 0;}/** * int journal_load() - Read journal from disk. * @journal: Journal to act on. * * 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; journal_superblock_t *sb; err = load_superblock(journal); if (err) return err; sb = journal->j_superblock; /* If this is a V2 superblock, then we have to check the * features flags on it. */ if (journal->j_format_version >= 2) { 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;}/** * void journal_destroy() - Release a journal_t structure. * @journal: Journal to act on. * * 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 */ /* Totally anal locking here... */ spin_lock(&journal->j_list_lock); while (journal->j_checkpoint_transactions != NULL) { spin_unlock(&journal->j_list_lock); log_do_checkpoint(journal); spin_lock(&journal->j_list_lock); } J_ASSERT(journal->j_running_transaction == NULL); J_ASSERT(journal->j_committing_transaction == NULL); J_ASSERT(journal->j_checkpoint_transactions == NULL); spin_unlock(&journal->j_list_lock); /* 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); kfree(journal->j_wbuf); kfree(journal);}/** *int journal_check_used_features () - Check if features specified are used. * @journal: Journal to check. * @compat: bitmask of compatible features * @ro: bitmask of features that force read-only mount * @incompat: bitmask of incompatible features * * 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;}/** * int journal_check_available_features() - Check feature set in journalling layer * @journal: Journal to check. * @compat: bitmask of compatible features * @ro: bitmask of features that force read-only mount * @incompat: bitmask of incompatible features * * 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;}/** * int journal_set_features () - Mark a given journal feature in the superblock * @journal: Journal to act on. * @compat: bitmask of compatible features * @ro: bitmask of features that force read-only mount * @incompat: bitmask of incompatible features * * 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;}/** * int journal_update_format () - Update on-disk journal structure. * @journal: Journal to act on. * * 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 (be32_to_cpu(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 = be32_to_cpu(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); sync_dirty_buffer(bh); return 0;}/** * int journal_flush () - Flush journal * @journal: Journal to act on. * * 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; spin_lock(&journal->j_state_lock); /* Force everything buffered to the log... */ if (journal->j_running_transaction) { transaction = journal->j_running_transaction; __log_start_commit(journal, transaction->t_tid); } else if (journal->j_committing_transaction) transaction = journal->j_committing_transaction; /* Wait for the log commit to complete... */ if (transaction) { tid_t tid = transaction->t_tid; spin_unlock(&journal->j_state_lock); log_wait_commit(journal, tid); } else { spin_unlock(&journal->j_state_lock); } /* ...and flush everything in the log out to disk. */ spin_lock(&journal->j_list_lock); while (!err && journal->j_checkpoint_transactions != NULL) { spin_unlock(&journal->j_list_lock); err = log_do_checkpoint(journal); spin_lock(&journal->j_list_lock); } spin_unlock(&journal->j_list_lock); 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. */ spin_lock(&journal->j_state_lock); old_tail = journal->j_tail; journal->j_tail = 0; spin_unlock(&journal->j_state_lock); journal_update_superblock(journal, 1); spin_lock(&journal->j_state_lock); journal->j_tail = old_tail; 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); spin_unlock(&journal->j_state_lock); return err;}/** * int journal_wipe() - Wipe journal contents * @journal: Journal to act on. * @write: flag (see below) * * 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. */static const char *journal_dev_name(journal_t *journal, char *buffer){ struct block_device *bdev; if (journal->j_inode) bdev = journal->j_inode->i_sb->s_bdev; else bdev = journal->j_dev; return bdevname(bdev, buffer);}/* * Journal abort has very specific semantics, which we describe * for journal abort. * * Two internal function, which provide abort to te jbd layer * itself are here. *//* * Quick version for internal journal use (doesn't lock the journal). * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, * and don't attempt to make any other journal updates. */void __journal_abort_hard(journal_t *journal){ transaction_t *transaction; char b[BDEVNAME_SIZE]; if (journal->j_flags & JFS_ABORT) return; printk(KERN_ERR "Aborting journal on device %s.\n", journal_dev_name(journal, b)); spin_lock(&journal->j_state_lock); journal->j_flags |= JFS_ABORT; transaction = journal->j_running_transaction; if (transaction) __log_start_commit(journal, transaction->t_tid); spin_unlock(&journal->j_state_lock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -