diff options
Diffstat (limited to 'fs/jbd/journal.c')
-rw-r--r-- | fs/jbd/journal.c | 44 |
1 files changed, 35 insertions, 9 deletions
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 2c4b1f109da..da1b5e4ffce 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/poison.h> | 36 | #include <linux/poison.h> |
37 | #include <linux/proc_fs.h> | 37 | #include <linux/proc_fs.h> |
38 | #include <linux/debugfs.h> | 38 | #include <linux/debugfs.h> |
39 | #include <linux/ratelimit.h> | ||
39 | 40 | ||
40 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
41 | #include <asm/page.h> | 42 | #include <asm/page.h> |
@@ -84,6 +85,7 @@ EXPORT_SYMBOL(journal_force_commit); | |||
84 | 85 | ||
85 | static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *); | 86 | static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *); |
86 | static void __journal_abort_soft (journal_t *journal, int errno); | 87 | static void __journal_abort_soft (journal_t *journal, int errno); |
88 | static const char *journal_dev_name(journal_t *journal, char *buffer); | ||
87 | 89 | ||
88 | /* | 90 | /* |
89 | * Helper function used to manage commit timeouts | 91 | * Helper function used to manage commit timeouts |
@@ -439,7 +441,7 @@ int __log_start_commit(journal_t *journal, tid_t target) | |||
439 | */ | 441 | */ |
440 | if (!tid_geq(journal->j_commit_request, target)) { | 442 | if (!tid_geq(journal->j_commit_request, target)) { |
441 | /* | 443 | /* |
442 | * We want a new commit: OK, mark the request and wakup the | 444 | * We want a new commit: OK, mark the request and wakeup the |
443 | * commit thread. We do _not_ do the commit ourselves. | 445 | * commit thread. We do _not_ do the commit ourselves. |
444 | */ | 446 | */ |
445 | 447 | ||
@@ -950,6 +952,8 @@ int journal_create(journal_t *journal) | |||
950 | if (err) | 952 | if (err) |
951 | return err; | 953 | return err; |
952 | bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); | 954 | bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); |
955 | if (unlikely(!bh)) | ||
956 | return -ENOMEM; | ||
953 | lock_buffer(bh); | 957 | lock_buffer(bh); |
954 | memset (bh->b_data, 0, journal->j_blocksize); | 958 | memset (bh->b_data, 0, journal->j_blocksize); |
955 | BUFFER_TRACE(bh, "marking dirty"); | 959 | BUFFER_TRACE(bh, "marking dirty"); |
@@ -1010,6 +1014,23 @@ void journal_update_superblock(journal_t *journal, int wait) | |||
1010 | goto out; | 1014 | goto out; |
1011 | } | 1015 | } |
1012 | 1016 | ||
1017 | if (buffer_write_io_error(bh)) { | ||
1018 | char b[BDEVNAME_SIZE]; | ||
1019 | /* | ||
1020 | * Oh, dear. A previous attempt to write the journal | ||
1021 | * superblock failed. This could happen because the | ||
1022 | * USB device was yanked out. Or it could happen to | ||
1023 | * be a transient write error and maybe the block will | ||
1024 | * be remapped. Nothing we can do but to retry the | ||
1025 | * write and hope for the best. | ||
1026 | */ | ||
1027 | printk(KERN_ERR "JBD: previous I/O error detected " | ||
1028 | "for journal superblock update for %s.\n", | ||
1029 | journal_dev_name(journal, b)); | ||
1030 | clear_buffer_write_io_error(bh); | ||
1031 | set_buffer_uptodate(bh); | ||
1032 | } | ||
1033 | |||
1013 | spin_lock(&journal->j_state_lock); | 1034 | spin_lock(&journal->j_state_lock); |
1014 | jbd_debug(1,"JBD: updating superblock (start %u, seq %d, errno %d)\n", | 1035 | jbd_debug(1,"JBD: updating superblock (start %u, seq %d, errno %d)\n", |
1015 | journal->j_tail, journal->j_tail_sequence, journal->j_errno); | 1036 | journal->j_tail, journal->j_tail_sequence, journal->j_errno); |
@@ -1021,9 +1042,17 @@ void journal_update_superblock(journal_t *journal, int wait) | |||
1021 | 1042 | ||
1022 | BUFFER_TRACE(bh, "marking dirty"); | 1043 | BUFFER_TRACE(bh, "marking dirty"); |
1023 | mark_buffer_dirty(bh); | 1044 | mark_buffer_dirty(bh); |
1024 | if (wait) | 1045 | if (wait) { |
1025 | sync_dirty_buffer(bh); | 1046 | sync_dirty_buffer(bh); |
1026 | else | 1047 | if (buffer_write_io_error(bh)) { |
1048 | char b[BDEVNAME_SIZE]; | ||
1049 | printk(KERN_ERR "JBD: I/O error detected " | ||
1050 | "when updating journal superblock for %s.\n", | ||
1051 | journal_dev_name(journal, b)); | ||
1052 | clear_buffer_write_io_error(bh); | ||
1053 | set_buffer_uptodate(bh); | ||
1054 | } | ||
1055 | } else | ||
1027 | write_dirty_buffer(bh, WRITE); | 1056 | write_dirty_buffer(bh, WRITE); |
1028 | 1057 | ||
1029 | out: | 1058 | out: |
@@ -1719,7 +1748,6 @@ static void journal_destroy_journal_head_cache(void) | |||
1719 | static struct journal_head *journal_alloc_journal_head(void) | 1748 | static struct journal_head *journal_alloc_journal_head(void) |
1720 | { | 1749 | { |
1721 | struct journal_head *ret; | 1750 | struct journal_head *ret; |
1722 | static unsigned long last_warning; | ||
1723 | 1751 | ||
1724 | #ifdef CONFIG_JBD_DEBUG | 1752 | #ifdef CONFIG_JBD_DEBUG |
1725 | atomic_inc(&nr_journal_heads); | 1753 | atomic_inc(&nr_journal_heads); |
@@ -1727,11 +1755,9 @@ static struct journal_head *journal_alloc_journal_head(void) | |||
1727 | ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); | 1755 | ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); |
1728 | if (ret == NULL) { | 1756 | if (ret == NULL) { |
1729 | jbd_debug(1, "out of memory for journal_head\n"); | 1757 | jbd_debug(1, "out of memory for journal_head\n"); |
1730 | if (time_after(jiffies, last_warning + 5*HZ)) { | 1758 | printk_ratelimited(KERN_NOTICE "ENOMEM in %s, retrying.\n", |
1731 | printk(KERN_NOTICE "ENOMEM in %s, retrying.\n", | 1759 | __func__); |
1732 | __func__); | 1760 | |
1733 | last_warning = jiffies; | ||
1734 | } | ||
1735 | while (ret == NULL) { | 1761 | while (ret == NULL) { |
1736 | yield(); | 1762 | yield(); |
1737 | ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); | 1763 | ret = kmem_cache_alloc(journal_head_cache, GFP_NOFS); |