On Tue, May 06, 2014 at 03:19:17PM +0200, Lukas Czerner wrote: > Currently there is no easy way to tell that the mounted file system > contains errors other than checking for log messages, or reading the > information directly from superblock. > > This patch adds new sysfs entry "contains_errors" for each ext4 file > system so user can simply check > > cat /sys/fs/ext4/sda/contains_errors Minor complaint: "contains" makes me think that cat'ing that file will return either 0 or 1, not a string of error text. Perhaps we could shorten it to /sys/fs/ext4/sda/errors ? Otherwise looks good to me. --D > > If the file system is not marked as containing errors then the file is > empty. Otherwise it would print the same information that could be found > in the log. For example: > > error count: 1 > EXT4-fs (sda): initial error at 1399305407: trigger_test_error:2630 > EXT4-fs (sda): last error at 1399305407: trigger_test_error:2630 > > Signed-off-by: Lukas Czerner <lczerner@xxxxxxxxxx> > --- > fs/ext4/super.c | 100 ++++++++++++++++++++++++++++++++++++++------------------ > 1 file changed, 68 insertions(+), 32 deletions(-) > > diff --git a/fs/ext4/super.c b/fs/ext4/super.c > index 6f9e6fa..61dc3d6 100644 > --- a/fs/ext4/super.c > +++ b/fs/ext4/super.c > @@ -2502,6 +2502,59 @@ static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a, > EXT4_SB(sb)->s_sectors_written_start) >> 1))); > } > > +static ssize_t get_fs_errors(struct ext4_sb_info *sbi, char *buf, ssize_t size) > +{ > + struct super_block *sb = sbi->s_buddy_cache->i_sb; > + struct ext4_super_block *es = sbi->s_es; > + int len = 0; > + > + if (es->s_error_count) > + len = snprintf(buf + len, size - len, > + "error count: %u\n", > + le32_to_cpu(es->s_error_count)); > + if (es->s_first_error_time) { > + len += snprintf(buf + len, size - len, > + "EXT4-fs (%s): initial error at %u: %.*s:%d", > + sb->s_id, le32_to_cpu(es->s_first_error_time), > + (int) sizeof(es->s_first_error_func), > + es->s_first_error_func, > + le32_to_cpu(es->s_first_error_line)); > + if (es->s_first_error_ino) > + len += snprintf(buf + len, size - len, > + ": inode %u", > + le32_to_cpu(es->s_first_error_ino)); > + if (es->s_first_error_block) > + len += snprintf(buf + len, size - len, > + ": block %llu", (unsigned long long) > + le64_to_cpu(es->s_first_error_block)); > + len += snprintf(buf + len, size - len, "\n"); > + } > + if (es->s_last_error_time) { > + len += snprintf(buf + len, size - len, > + "EXT4-fs (%s): last error at %u: %.*s:%d", > + sb->s_id, le32_to_cpu(es->s_last_error_time), > + (int) sizeof(es->s_last_error_func), > + es->s_last_error_func, > + le32_to_cpu(es->s_last_error_line)); > + if (es->s_last_error_ino) > + len += snprintf(buf + len, size - len, > + ": inode %u", > + le32_to_cpu(es->s_last_error_ino)); > + if (es->s_last_error_block) > + len += snprintf(buf + len, size - len, > + ": block %llu", (unsigned long long) > + le64_to_cpu(es->s_last_error_block)); > + len += snprintf(buf + len, size - len, "\n"); > + } > + return len; > +} > + > +static ssize_t contains_errors_show(struct ext4_attr *a, > + struct ext4_sb_info *sbi, char *buf) > +{ > + return get_fs_errors(sbi, buf, PAGE_SIZE); > +} > + > static ssize_t inode_readahead_blks_store(struct ext4_attr *a, > struct ext4_sb_info *sbi, > const char *buf, size_t count) > @@ -2617,6 +2670,7 @@ static struct ext4_attr ext4_attr_##_name = { \ > EXT4_RO_ATTR(delayed_allocation_blocks); > EXT4_RO_ATTR(session_write_kbytes); > EXT4_RO_ATTR(lifetime_write_kbytes); > +EXT4_RO_ATTR(contains_errors); > EXT4_RW_ATTR(reserved_clusters); > EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show, > inode_readahead_blks_store, s_inode_readahead_blks); > @@ -2659,6 +2713,7 @@ static struct attribute *ext4_attrs[] = { > ATTR_LIST(warning_ratelimit_burst), > ATTR_LIST(msg_ratelimit_interval_ms), > ATTR_LIST(msg_ratelimit_burst), > + ATTR_LIST(contains_errors), > NULL, > }; > > @@ -2792,42 +2847,23 @@ static void print_daily_error_info(unsigned long arg) > { > struct super_block *sb = (struct super_block *) arg; > struct ext4_sb_info *sbi; > - struct ext4_super_block *es; > + ssize_t size; > + char *buf = NULL; > > sbi = EXT4_SB(sb); > - es = sbi->s_es; > > - if (es->s_error_count) > - ext4_msg(sb, KERN_NOTICE, "error count: %u", > - le32_to_cpu(es->s_error_count)); > - if (es->s_first_error_time) { > - printk(KERN_NOTICE "EXT4-fs (%s): initial error at %u: %.*s:%d", > - sb->s_id, le32_to_cpu(es->s_first_error_time), > - (int) sizeof(es->s_first_error_func), > - es->s_first_error_func, > - le32_to_cpu(es->s_first_error_line)); > - if (es->s_first_error_ino) > - printk(": inode %u", > - le32_to_cpu(es->s_first_error_ino)); > - if (es->s_first_error_block) > - printk(": block %llu", (unsigned long long) > - le64_to_cpu(es->s_first_error_block)); > - printk("\n"); > - } > - if (es->s_last_error_time) { > - printk(KERN_NOTICE "EXT4-fs (%s): last error at %u: %.*s:%d", > - sb->s_id, le32_to_cpu(es->s_last_error_time), > - (int) sizeof(es->s_last_error_func), > - es->s_last_error_func, > - le32_to_cpu(es->s_last_error_line)); > - if (es->s_last_error_ino) > - printk(": inode %u", > - le32_to_cpu(es->s_last_error_ino)); > - if (es->s_last_error_block) > - printk(": block %llu", (unsigned long long) > - le64_to_cpu(es->s_last_error_block)); > - printk("\n"); > + buf = kmalloc(255, GFP_NOFS); > + if (!buf) { > + ext4_msg(sb, KERN_NOTICE, "File system contains errors, " > + "running e2fsck is recommended"); > + return; > } > + > + size = get_fs_errors(sbi, buf, 255); > + if (size) > + ext4_msg(sb, KERN_NOTICE, "%s", buf); > + kfree(buf); > + > mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ); /* Once a day */ > } > > -- > 1.8.3.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html