From dff6825e9fde93891e60751e01480337a991235e Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 4 Oct 2010 12:35:05 -0700 Subject: 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 Signed-off-by: Jan Kara --- fs/ext3/super.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'fs/ext3/super.c') 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, if (!sbh) return error; + + if (buffer_write_io_error(sbh)) { + /* + * Oh, dear. A previous attempt to write the + * 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. + */ + ext3_msg(sb, KERN_ERR, "previous I/O error to " + "superblock detected"); + clear_buffer_write_io_error(sbh); + set_buffer_uptodate(sbh); + } /* * If the file system is mounted read-only, don't update the * superblock write time. This avoids updating the superblock @@ -2377,8 +2392,15 @@ static int ext3_commit_super(struct super_block *sb, es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb)); BUFFER_TRACE(sbh, "marking dirty"); mark_buffer_dirty(sbh); - if (sync) + if (sync) { error = sync_dirty_buffer(sbh); + if (buffer_write_io_error(sbh)) { + ext3_msg(sb, KERN_ERR, "I/O error while writing " + "superblock"); + clear_buffer_write_io_error(sbh); + set_buffer_uptodate(sbh); + } + } return error; } -- cgit v1.2.3 From df0d6b8ff152b1a1aaae17c27a445ad025a358bd Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 10 Oct 2010 21:36:59 +0900 Subject: ext3: Cleanup ext3_setup_super() Fix mount-count check to emit warning only if s_max_mnt_count is greater than 0 according to man tune2fs(8). Also removes unnecessary casts. Signed-off-by: Namhyung Kim Signed-off-by: Jan Kara --- fs/ext3/super.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/ext3/super.c') diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 3ef272488ac9..daf34b1c4fb5 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1306,9 +1306,9 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, ext3_msg(sb, KERN_WARNING, "warning: mounting fs with errors, " "running e2fsck is recommended"); - else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && + else if ((__s16) le16_to_cpu(es->s_max_mnt_count) > 0 && le16_to_cpu(es->s_mnt_count) >= - (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) + le16_to_cpu(es->s_max_mnt_count)) ext3_msg(sb, KERN_WARNING, "warning: maximal mount count reached, " "running e2fsck is recommended"); @@ -1325,7 +1325,7 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, valid forever! :) */ es->s_state &= cpu_to_le16(~EXT3_VALID_FS); #endif - if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) + if (!le16_to_cpu(es->s_max_mnt_count)) es->s_max_mnt_count = cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT); le16_add_cpu(&es->s_mnt_count, 1); es->s_mtime = cpu_to_le32(get_seconds()); -- cgit v1.2.3 From 57e94d8647e9aa60ad317ccd0cd54eefd603f1fe Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 11 Oct 2010 02:10:45 +0900 Subject: ext3: Remove unnecessary casts on bh->b_data bh->b_data is already a pointer to char so casts to 'char *' should be meaningless. Remove them. Signed-off-by: Namhyung Kim Signed-off-by: Jan Kara --- fs/ext3/super.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/ext3/super.c') diff --git a/fs/ext3/super.c b/fs/ext3/super.c index daf34b1c4fb5..af7aead1000a 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1654,7 +1654,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) * Note: s_es must be initialized as soon as possible because * some ext3 macro-instructions depend on its value */ - es = (struct ext3_super_block *) (((char *)bh->b_data) + offset); + es = (struct ext3_super_block *) (bh->b_data + offset); sbi->s_es = es; sb->s_magic = le16_to_cpu(es->s_magic); if (sb->s_magic != EXT3_SUPER_MAGIC) @@ -1765,7 +1765,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) "error: can't read superblock on 2nd try"); goto failed_mount; } - es = (struct ext3_super_block *)(((char *)bh->b_data) + offset); + es = (struct ext3_super_block *)(bh->b_data + offset); sbi->s_es = es; if (es->s_magic != cpu_to_le16(EXT3_SUPER_MAGIC)) { ext3_msg(sb, KERN_ERR, @@ -2168,7 +2168,7 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb, goto out_bdev; } - es = (struct ext3_super_block *) (((char *)bh->b_data) + offset); + es = (struct ext3_super_block *) (bh->b_data + offset); if ((le16_to_cpu(es->s_magic) != EXT3_SUPER_MAGIC) || !(le32_to_cpu(es->s_feature_incompat) & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { -- cgit v1.2.3 From 4569cd1b0d91e4d7fa67f950201befc2acfecb34 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 11 Oct 2010 19:08:06 +0900 Subject: ext3: Return proper error code on ext3_fill_super() Signed-off-by: Namhyung Kim Signed-off-by: Jan Kara --- fs/ext3/super.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs/ext3/super.c') diff --git a/fs/ext3/super.c b/fs/ext3/super.c index af7aead1000a..1811c6fd5ba4 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1871,6 +1871,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) if (sbi->s_group_desc == NULL) { ext3_msg(sb, KERN_ERR, "error: not enough memory"); + ret = -ENOMEM; goto failed_mount; } @@ -1958,6 +1959,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) } if (err) { ext3_msg(sb, KERN_ERR, "error: insufficient memory"); + ret = err; goto failed_mount3; } -- cgit v1.2.3 From 81a4e320e6ee29bde3fe880ab87b2122bc1de88b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 11 Oct 2010 19:38:39 +0900 Subject: ext3: Use DIV_ROUND_UP() on group desc block counting Signed-off-by: Namhyung Kim Signed-off-by: Jan Kara --- fs/ext3/super.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'fs/ext3/super.c') diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 1811c6fd5ba4..1c6875118b1e 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -1864,8 +1864,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - le32_to_cpu(es->s_first_data_block) - 1) / EXT3_BLOCKS_PER_GROUP(sb)) + 1; - db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) / - EXT3_DESC_PER_BLOCK(sb); + db_count = DIV_ROUND_UP(sbi->s_groups_count, EXT3_DESC_PER_BLOCK(sb)); sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *), GFP_KERNEL); if (sbi->s_group_desc == NULL) { -- cgit v1.2.3