]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/jbd/journal.c
jbd: Check return value of __getblk()
[net-next-2.6.git] / fs / jbd / journal.c
index d7a86935553a919ccb6ce2d6be6b1418565972e4..ac1840415a650b063319d55e02384e1b278954dc 100644 (file)
@@ -85,6 +85,7 @@ EXPORT_SYMBOL(journal_force_commit);
 
 static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
 static void __journal_abort_soft (journal_t *journal, int errno);
+static const char *journal_dev_name(journal_t *journal, char *buffer);
 
 /*
  * Helper function used to manage commit timeouts
@@ -951,6 +952,8 @@ int journal_create(journal_t *journal)
                if (err)
                        return err;
                bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
+               if (unlikely(!bh))
+                       return -ENOMEM;
                lock_buffer(bh);
                memset (bh->b_data, 0, journal->j_blocksize);
                BUFFER_TRACE(bh, "marking dirty");
@@ -1011,6 +1014,23 @@ void journal_update_superblock(journal_t *journal, int wait)
                goto out;
        }
 
+       if (buffer_write_io_error(bh)) {
+               char b[BDEVNAME_SIZE];
+               /*
+                * Oh, dear.  A previous attempt to write the journal
+                * superblock failed.  This could happen because the
+                * USB device was yanked out.  Or it could happen to
+                * be a transient write error and maybe the block will
+                * be remapped.  Nothing we can do but to retry the
+                * write and hope for the best.
+                */
+               printk(KERN_ERR "JBD: previous I/O error detected "
+                      "for journal superblock update for %s.\n",
+                      journal_dev_name(journal, b));
+               clear_buffer_write_io_error(bh);
+               set_buffer_uptodate(bh);
+       }
+
        spin_lock(&journal->j_state_lock);
        jbd_debug(1,"JBD: updating superblock (start %u, seq %d, errno %d)\n",
                  journal->j_tail, journal->j_tail_sequence, journal->j_errno);
@@ -1022,9 +1042,17 @@ void journal_update_superblock(journal_t *journal, int wait)
 
        BUFFER_TRACE(bh, "marking dirty");
        mark_buffer_dirty(bh);
-       if (wait)
+       if (wait) {
                sync_dirty_buffer(bh);
-       else
+               if (buffer_write_io_error(bh)) {
+                       char b[BDEVNAME_SIZE];
+                       printk(KERN_ERR "JBD: I/O error detected "
+                              "when updating journal superblock for %s.\n",
+                              journal_dev_name(journal, b));
+                       clear_buffer_write_io_error(bh);
+                       set_buffer_uptodate(bh);
+               }
+       } else
                write_dirty_buffer(bh, WRITE);
 
 out: