aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2010-10-04 15:35:05 -0400
committerJan Kara <jack@suse.cz>2010-10-27 19:30:02 -0400
commitdff6825e9fde93891e60751e01480337a991235e (patch)
tree3b243584ee48752096b110c04ecd803e285325ae
parent8117f98c058dbe463eaba2b51b84d19bd5d78804 (diff)
ext3/jbd: Avoid WARN() messages when failing to write the superblock
This fixes a WARN backtrace in mark_buffer_dirty() that occurs during unmount when the underlying block device is removed. This bug has been seen on System Z when removing all paths from a multipath-backed ext3 mount; on System P when injecting enough PCI EEH errors to make the SCSI controller go offline; and similar warnings have been seen (and patched) with ext2/ext4. The super block update from a previous operation has marked the buffer as in error, and the flag has to be cleared before doing the update. Similar changes have been made to ext4 by commit 914258bf2cb22bf4336a1b1d90c551b4b11ca5aa. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--fs/ext3/super.c24
-rw-r--r--fs/jbd/journal.c30
2 files changed, 51 insertions, 3 deletions
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 5dbf4dba03c4..3ef272488ac9 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -2361,6 +2361,21 @@ static int ext3_commit_super(struct super_block *sb,
2361 2361
2362 if (!sbh) 2362 if (!sbh)
2363 return error; 2363 return error;
2364
2365 if (buffer_write_io_error(sbh)) {
2366 /*
2367 * Oh, dear. A previous attempt to write the
2368 * superblock failed. This could happen because the
2369 * USB device was yanked out. Or it could happen to
2370 * be a transient write error and maybe the block will
2371 * be remapped. Nothing we can do but to retry the
2372 * write and hope for the best.
2373 */
2374 ext3_msg(sb, KERN_ERR, "previous I/O error to "
2375 "superblock detected");
2376 clear_buffer_write_io_error(sbh);
2377 set_buffer_uptodate(sbh);
2378 }
2364 /* 2379 /*
2365 * If the file system is mounted read-only, don't update the 2380 * If the file system is mounted read-only, don't update the
2366 * superblock write time. This avoids updating the superblock 2381 * superblock write time. This avoids updating the superblock
@@ -2377,8 +2392,15 @@ static int ext3_commit_super(struct super_block *sb,
2377 es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb)); 2392 es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb));
2378 BUFFER_TRACE(sbh, "marking dirty"); 2393 BUFFER_TRACE(sbh, "marking dirty");
2379 mark_buffer_dirty(sbh); 2394 mark_buffer_dirty(sbh);
2380 if (sync) 2395 if (sync) {
2381 error = sync_dirty_buffer(sbh); 2396 error = sync_dirty_buffer(sbh);
2397 if (buffer_write_io_error(sbh)) {
2398 ext3_msg(sb, KERN_ERR, "I/O error while writing "
2399 "superblock");
2400 clear_buffer_write_io_error(sbh);
2401 set_buffer_uptodate(sbh);
2402 }
2403 }
2382 return error; 2404 return error;
2383} 2405}
2384 2406
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index d7a86935553a..e56117651826 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -85,6 +85,7 @@ EXPORT_SYMBOL(journal_force_commit);
85 85
86static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *); 86static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
87static void __journal_abort_soft (journal_t *journal, int errno); 87static void __journal_abort_soft (journal_t *journal, int errno);
88static const char *journal_dev_name(journal_t *journal, char *buffer);
88 89
89/* 90/*
90 * Helper function used to manage commit timeouts 91 * Helper function used to manage commit timeouts
@@ -1011,6 +1012,23 @@ void journal_update_superblock(journal_t *journal, int wait)
1011 goto out; 1012 goto out;
1012 } 1013 }
1013 1014
1015 if (buffer_write_io_error(bh)) {
1016 char b[BDEVNAME_SIZE];
1017 /*
1018 * Oh, dear. A previous attempt to write the journal
1019 * superblock failed. This could happen because the
1020 * USB device was yanked out. Or it could happen to
1021 * be a transient write error and maybe the block will
1022 * be remapped. Nothing we can do but to retry the
1023 * write and hope for the best.
1024 */
1025 printk(KERN_ERR "JBD: previous I/O error detected "
1026 "for journal superblock update for %s.\n",
1027 journal_dev_name(journal, b));
1028 clear_buffer_write_io_error(bh);
1029 set_buffer_uptodate(bh);
1030 }
1031
1014 spin_lock(&journal->j_state_lock); 1032 spin_lock(&journal->j_state_lock);
1015 jbd_debug(1,"JBD: updating superblock (start %u, seq %d, errno %d)\n", 1033 jbd_debug(1,"JBD: updating superblock (start %u, seq %d, errno %d)\n",
1016 journal->j_tail, journal->j_tail_sequence, journal->j_errno); 1034 journal->j_tail, journal->j_tail_sequence, journal->j_errno);
@@ -1022,9 +1040,17 @@ void journal_update_superblock(journal_t *journal, int wait)
1022 1040
1023 BUFFER_TRACE(bh, "marking dirty"); 1041 BUFFER_TRACE(bh, "marking dirty");
1024 mark_buffer_dirty(bh); 1042 mark_buffer_dirty(bh);
1025 if (wait) 1043 if (wait) {
1026 sync_dirty_buffer(bh); 1044 sync_dirty_buffer(bh);
1027 else 1045 if (buffer_write_io_error(bh)) {
1046 char b[BDEVNAME_SIZE];
1047 printk(KERN_ERR "JBD: I/O error detected "
1048 "when updating journal superblock for %s.\n",
1049 journal_dev_name(journal, b));
1050 clear_buffer_write_io_error(bh);
1051 set_buffer_uptodate(bh);
1052 }
1053 } else
1028 write_dirty_buffer(bh, WRITE); 1054 write_dirty_buffer(bh, WRITE);
1029 1055
1030out: 1056out: