patch-2.4.17 linux/fs/jbd/journal.c
Next file: linux/fs/jbd/recovery.c
Previous file: linux/fs/jbd/commit.c
Back to the patch index
Back to the overall index
- Lines: 294
- Date:
Fri Dec 21 16:40:32 2001
- Orig file:
linux-2.4.16/fs/jbd/journal.c
- Orig date:
Fri Nov 9 22:25:04 2001
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/fs/jbd/journal.c linux/fs/jbd/journal.c
@@ -70,7 +70,6 @@
EXPORT_SYMBOL(journal_destroy);
EXPORT_SYMBOL(journal_recover);
EXPORT_SYMBOL(journal_update_superblock);
-EXPORT_SYMBOL(__journal_abort);
EXPORT_SYMBOL(journal_abort);
EXPORT_SYMBOL(journal_errno);
EXPORT_SYMBOL(journal_ack_err);
@@ -606,7 +605,7 @@
* Log buffer allocation routines:
*/
-unsigned long journal_next_log_block(journal_t *journal)
+int journal_next_log_block(journal_t *journal, unsigned long *retp)
{
unsigned long blocknr;
@@ -617,7 +616,7 @@
journal->j_free--;
if (journal->j_head == journal->j_last)
journal->j_head = journal->j_first;
- return journal_bmap(journal, blocknr);
+ return journal_bmap(journal, blocknr, retp);
}
/*
@@ -627,17 +626,28 @@
* this is a no-op. If needed, we can use j_blk_offset - everything is
* ready.
*/
-unsigned long journal_bmap(journal_t *journal, unsigned long blocknr)
+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);
- J_ASSERT(ret != 0);
+ 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 {
- ret = blocknr; /* +journal->j_blk_offset */
+ *retp = blocknr; /* +journal->j_blk_offset */
}
- return ret;
+ return err;
}
/*
@@ -649,7 +659,13 @@
struct journal_head * journal_get_descriptor_buffer(journal_t *journal)
{
struct buffer_head *bh;
- unsigned long blocknr = journal_next_log_block(journal);
+ 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);
bh->b_state |= (1 << BH_Dirty);
@@ -747,7 +763,8 @@
{
struct buffer_head *bh;
journal_t *journal = journal_init_common();
- int blocknr;
+ int err;
+ unsigned long blocknr;
if (!journal)
return NULL;
@@ -757,13 +774,22 @@
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, inode->i_size,
+ 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;
- blocknr = journal_bmap(journal, 0);
+ 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;
@@ -772,6 +798,18 @@
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
@@ -817,14 +855,15 @@
int journal_create (journal_t *journal)
{
- int blocknr;
+ unsigned long blocknr;
struct buffer_head *bh;
journal_superblock_t *sb;
- int i;
+ 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;
}
@@ -841,7 +880,9 @@
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++) {
- blocknr = journal_bmap(journal, 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);
@@ -851,6 +892,7 @@
mark_buffer_uptodate(bh, 1);
__brelse(bh);
}
+
sync_dev(journal->j_dev);
jbd_debug(1, "JBD: journal cleared.\n");
@@ -915,7 +957,8 @@
{
struct buffer_head *bh;
journal_superblock_t *sb;
-
+ int err = -EIO;
+
bh = journal->j_sb_buffer;
J_ASSERT(bh != NULL);
@@ -925,16 +968,18 @@
if (!buffer_uptodate(bh)) {
printk (KERN_ERR
"JBD: IO error reading journal superblock\n");
- return -EIO;
+ 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");
- return -EINVAL;
+ goto out;
}
switch(ntohl(sb->s_header.h_blocktype)) {
@@ -946,17 +991,21 @@
break;
default:
printk(KERN_WARNING "JBD: unrecognised superblock format ID\n");
- return -EINVAL;
+ 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");
- return -EINVAL;
+ goto out;
}
return 0;
+
+out:
+ journal_fail_superblock(journal);
+ return err;
}
/*
@@ -1061,7 +1110,10 @@
/* We can now mark the journal as empty. */
journal->j_tail = 0;
journal->j_tail_sequence = ++journal->j_transaction_sequence;
- journal_update_superblock(journal, 1);
+ if (journal->j_sb_buffer) {
+ journal_update_superblock(journal, 1);
+ brelse(journal->j_sb_buffer);
+ }
if (journal->j_inode)
iput(journal->j_inode);
@@ -1069,7 +1121,6 @@
journal_destroy_revoke(journal);
unlock_journal(journal);
- brelse(journal->j_sb_buffer);
kfree(journal);
MOD_DEC_USE_COUNT;
}
@@ -1356,11 +1407,16 @@
* progress).
*/
-/* Quick version for internal journal use (doesn't lock the journal) */
-void __journal_abort (journal_t *journal)
+/* 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;
+ if (journal->j_flags & JFS_ABORT)
+ return;
+
printk (KERN_ERR "Aborting journal on device %s.\n",
journal_dev_name(journal));
@@ -1370,23 +1426,27 @@
log_start_commit(journal, transaction);
}
-/* Full version for external use */
-void journal_abort (journal_t *journal, int errno)
+/* Soft abort: record the abort error status in the journal superblock,
+ * but don't do any other IO. */
+void __journal_abort_soft (journal_t *journal, int errno)
{
- lock_journal(journal);
-
if (journal->j_flags & JFS_ABORT)
- goto out;
+ return;
if (!journal->j_errno)
journal->j_errno = errno;
- __journal_abort(journal);
+ __journal_abort_hard(journal);
if (errno)
journal_update_superblock(journal, 1);
+}
- out:
+/* Full version for external use */
+void journal_abort (journal_t *journal, int errno)
+{
+ lock_journal(journal);
+ __journal_abort_soft(journal, errno);
unlock_journal(journal);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)