aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/block_validity.c8
-rw-r--r--fs/ext4/ext4.h17
-rw-r--r--fs/ext4/ext4_jbd2.c5
-rw-r--r--fs/ext4/inode.c2
-rw-r--r--fs/ext4/super.c80
5 files changed, 90 insertions, 22 deletions
diff --git a/fs/ext4/block_validity.c b/fs/ext4/block_validity.c
index 5b6973fbf1bd..3db5084db9bd 100644
--- a/fs/ext4/block_validity.c
+++ b/fs/ext4/block_validity.c
@@ -229,16 +229,20 @@ int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk,
229 229
230 if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || 230 if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) ||
231 (start_blk + count < start_blk) || 231 (start_blk + count < start_blk) ||
232 (start_blk + count > ext4_blocks_count(sbi->s_es))) 232 (start_blk + count > ext4_blocks_count(sbi->s_es))) {
233 sbi->s_es->s_last_error_block = cpu_to_le64(start_blk);
233 return 0; 234 return 0;
235 }
234 while (n) { 236 while (n) {
235 entry = rb_entry(n, struct ext4_system_zone, node); 237 entry = rb_entry(n, struct ext4_system_zone, node);
236 if (start_blk + count - 1 < entry->start_blk) 238 if (start_blk + count - 1 < entry->start_blk)
237 n = n->rb_left; 239 n = n->rb_left;
238 else if (start_blk >= (entry->start_blk + entry->count)) 240 else if (start_blk >= (entry->start_blk + entry->count))
239 n = n->rb_right; 241 n = n->rb_right;
240 else 242 else {
243 sbi->s_es->s_last_error_block = cpu_to_le64(start_blk);
241 return 0; 244 return 0;
245 }
242 } 246 }
243 return 1; 247 return 1;
244} 248}
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 088938148f5c..6b96125e7255 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1011,9 +1011,24 @@ struct ext4_super_block {
1011 snapshot's future use */ 1011 snapshot's future use */
1012 __le32 s_snapshot_list; /* inode number of the head of the 1012 __le32 s_snapshot_list; /* inode number of the head of the
1013 on-disk snapshot list */ 1013 on-disk snapshot list */
1014 __u32 s_reserved[155]; /* Padding to the end of the block */ 1014#define EXT4_S_ERR_START offsetof(struct ext4_super_block, s_error_count)
1015 __le32 s_error_count; /* number of fs errors */
1016 __le32 s_first_error_time; /* first time an error happened */
1017 __le32 s_first_error_ino; /* inode involved in first error */
1018 __le64 s_first_error_block; /* block involved of first error */
1019 __u8 s_first_error_func[32]; /* function where the error happened */
1020 __le32 s_first_error_line; /* line number where error happened */
1021 __le32 s_last_error_time; /* most recent time of an error */
1022 __le32 s_last_error_ino; /* inode involved in last error */
1023 __le32 s_last_error_line; /* line number where error happened */
1024 __le64 s_last_error_block; /* block involved of last error */
1025 __u8 s_last_error_func[32]; /* function where the error happened */
1026#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_reserved)
1027 __le32 s_reserved[128]; /* Padding to the end of the block */
1015}; 1028};
1016 1029
1030#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
1031
1017#ifdef __KERNEL__ 1032#ifdef __KERNEL__
1018 1033
1019/* 1034/*
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index 23425cd68daa..6e272ef6ba96 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -134,6 +134,11 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
134 if (inode && inode_needs_sync(inode)) { 134 if (inode && inode_needs_sync(inode)) {
135 sync_dirty_buffer(bh); 135 sync_dirty_buffer(bh);
136 if (buffer_req(bh) && !buffer_uptodate(bh)) { 136 if (buffer_req(bh) && !buffer_uptodate(bh)) {
137 struct ext4_super_block *es;
138
139 es = EXT4_SB(inode->i_sb)->s_es;
140 es->s_last_error_block =
141 cpu_to_le64(bh->b_blocknr);
137 ext4_error_inode(inode, where, line, 142 ext4_error_inode(inode, where, line,
138 bh->b_blocknr, 143 bh->b_blocknr,
139 "IO error syncing itable block"); 144 "IO error syncing itable block");
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 69ea663ef03e..755ba8682233 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -341,6 +341,7 @@ static int __ext4_check_blockref(const char *function, unsigned int line,
341 struct inode *inode, 341 struct inode *inode,
342 __le32 *p, unsigned int max) 342 __le32 *p, unsigned int max)
343{ 343{
344 struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
344 __le32 *bref = p; 345 __le32 *bref = p;
345 unsigned int blk; 346 unsigned int blk;
346 347
@@ -349,6 +350,7 @@ static int __ext4_check_blockref(const char *function, unsigned int line,
349 if (blk && 350 if (blk &&
350 unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb), 351 unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
351 blk, 1))) { 352 blk, 1))) {
353 es->s_last_error_block = cpu_to_le64(blk);
352 ext4_error_inode(inode, function, line, blk, 354 ext4_error_inode(inode, function, line, blk,
353 "invalid block"); 355 "invalid block");
354 return -EIO; 356 return -EIO;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index bcf74b31d014..a94d3f56898f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -307,6 +307,35 @@ void ext4_journal_abort_handle(const char *caller, unsigned int line,
307 jbd2_journal_abort_handle(handle); 307 jbd2_journal_abort_handle(handle);
308} 308}
309 309
310static void __save_error_info(struct super_block *sb, const char *func,
311 unsigned int line)
312{
313 struct ext4_super_block *es = EXT4_SB(sb)->s_es;
314
315 EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
316 es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
317 es->s_last_error_time = cpu_to_le32(get_seconds());
318 strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func));
319 es->s_last_error_line = cpu_to_le32(line);
320 if (!es->s_first_error_time) {
321 es->s_first_error_time = es->s_last_error_time;
322 strncpy(es->s_first_error_func, func,
323 sizeof(es->s_first_error_func));
324 es->s_first_error_line = cpu_to_le32(line);
325 es->s_first_error_ino = es->s_last_error_ino;
326 es->s_first_error_block = es->s_last_error_block;
327 }
328 es->s_error_count = cpu_to_le32(le32_to_cpu(es->s_error_count) + 1);
329}
330
331static void save_error_info(struct super_block *sb, const char *func,
332 unsigned int line)
333{
334 __save_error_info(sb, func, line);
335 ext4_commit_super(sb, 1);
336}
337
338
310/* Deal with the reporting of failure conditions on a filesystem such as 339/* Deal with the reporting of failure conditions on a filesystem such as
311 * inconsistencies detected or read IO failures. 340 * inconsistencies detected or read IO failures.
312 * 341 *
@@ -324,11 +353,6 @@ void ext4_journal_abort_handle(const char *caller, unsigned int line,
324 353
325static void ext4_handle_error(struct super_block *sb) 354static void ext4_handle_error(struct super_block *sb)
326{ 355{
327 struct ext4_super_block *es = EXT4_SB(sb)->s_es;
328
329 EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
330 es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
331
332 if (sb->s_flags & MS_RDONLY) 356 if (sb->s_flags & MS_RDONLY)
333 return; 357 return;
334 358
@@ -343,7 +367,6 @@ static void ext4_handle_error(struct super_block *sb)
343 ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); 367 ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
344 sb->s_flags |= MS_RDONLY; 368 sb->s_flags |= MS_RDONLY;
345 } 369 }
346 ext4_commit_super(sb, 1);
347 if (test_opt(sb, ERRORS_PANIC)) 370 if (test_opt(sb, ERRORS_PANIC))
348 panic("EXT4-fs (device %s): panic forced after error\n", 371 panic("EXT4-fs (device %s): panic forced after error\n",
349 sb->s_id); 372 sb->s_id);
@@ -369,7 +392,11 @@ void ext4_error_inode(struct inode *inode, const char *function,
369 const char *fmt, ...) 392 const char *fmt, ...)
370{ 393{
371 va_list args; 394 va_list args;
395 struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
372 396
397 es->s_last_error_ino = cpu_to_le32(inode->i_ino);
398 es->s_last_error_block = cpu_to_le64(block);
399 save_error_info(inode->i_sb, function, line);
373 va_start(args, fmt); 400 va_start(args, fmt);
374 printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: inode #%lu: ", 401 printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: inode #%lu: ",
375 inode->i_sb->s_id, function, line, inode->i_ino); 402 inode->i_sb->s_id, function, line, inode->i_ino);
@@ -387,9 +414,13 @@ void ext4_error_file(struct file *file, const char *function,
387 unsigned int line, const char *fmt, ...) 414 unsigned int line, const char *fmt, ...)
388{ 415{
389 va_list args; 416 va_list args;
417 struct ext4_super_block *es;
390 struct inode *inode = file->f_dentry->d_inode; 418 struct inode *inode = file->f_dentry->d_inode;
391 char pathname[80], *path; 419 char pathname[80], *path;
392 420
421 es = EXT4_SB(inode->i_sb)->s_es;
422 es->s_last_error_ino = cpu_to_le32(inode->i_ino);
423 save_error_info(inode->i_sb, function, line);
393 va_start(args, fmt); 424 va_start(args, fmt);
394 path = d_path(&(file->f_path), pathname, sizeof(pathname)); 425 path = d_path(&(file->f_path), pathname, sizeof(pathname));
395 if (!path) 426 if (!path)
@@ -459,6 +490,7 @@ void __ext4_std_error(struct super_block *sb, const char *function,
459 errstr = ext4_decode_error(sb, errno, nbuf); 490 errstr = ext4_decode_error(sb, errno, nbuf);
460 printk(KERN_CRIT "EXT4-fs error (device %s) in %s:%d: %s\n", 491 printk(KERN_CRIT "EXT4-fs error (device %s) in %s:%d: %s\n",
461 sb->s_id, function, line, errstr); 492 sb->s_id, function, line, errstr);
493 save_error_info(sb, function, line);
462 494
463 ext4_handle_error(sb); 495 ext4_handle_error(sb);
464} 496}
@@ -478,6 +510,7 @@ void __ext4_abort(struct super_block *sb, const char *function,
478{ 510{
479 va_list args; 511 va_list args;
480 512
513 save_error_info(sb, function, line);
481 va_start(args, fmt); 514 va_start(args, fmt);
482 printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: ", sb->s_id, 515 printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: ", sb->s_id,
483 function, line); 516 function, line);
@@ -485,18 +518,16 @@ void __ext4_abort(struct super_block *sb, const char *function,
485 printk("\n"); 518 printk("\n");
486 va_end(args); 519 va_end(args);
487 520
521 if ((sb->s_flags & MS_RDONLY) == 0) {
522 ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
523 sb->s_flags |= MS_RDONLY;
524 EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
525 if (EXT4_SB(sb)->s_journal)
526 jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
527 save_error_info(sb, function, line);
528 }
488 if (test_opt(sb, ERRORS_PANIC)) 529 if (test_opt(sb, ERRORS_PANIC))
489 panic("EXT4-fs panic from previous error\n"); 530 panic("EXT4-fs panic from previous error\n");
490
491 if (sb->s_flags & MS_RDONLY)
492 return;
493
494 ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
495 EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
496 sb->s_flags |= MS_RDONLY;
497 EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
498 if (EXT4_SB(sb)->s_journal)
499 jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
500} 531}
501 532
502void ext4_msg (struct super_block * sb, const char *prefix, 533void ext4_msg (struct super_block * sb, const char *prefix,
@@ -534,6 +565,9 @@ __acquires(bitlock)
534 va_list args; 565 va_list args;
535 struct ext4_super_block *es = EXT4_SB(sb)->s_es; 566 struct ext4_super_block *es = EXT4_SB(sb)->s_es;
536 567
568 es->s_last_error_ino = cpu_to_le32(ino);
569 es->s_last_error_block = cpu_to_le64(block);
570 __save_error_info(sb, function, line);
537 va_start(args, fmt); 571 va_start(args, fmt);
538 printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u", 572 printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u",
539 sb->s_id, function, line, grp); 573 sb->s_id, function, line, grp);
@@ -546,11 +580,10 @@ __acquires(bitlock)
546 va_end(args); 580 va_end(args);
547 581
548 if (test_opt(sb, ERRORS_CONT)) { 582 if (test_opt(sb, ERRORS_CONT)) {
549 EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
550 es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
551 ext4_commit_super(sb, 0); 583 ext4_commit_super(sb, 0);
552 return; 584 return;
553 } 585 }
586
554 ext4_unlock_group(sb, grp); 587 ext4_unlock_group(sb, grp);
555 ext4_handle_error(sb); 588 ext4_handle_error(sb);
556 /* 589 /*
@@ -3332,8 +3365,17 @@ static int ext4_load_journal(struct super_block *sb,
3332 3365
3333 if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) 3366 if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))
3334 err = jbd2_journal_wipe(journal, !really_read_only); 3367 err = jbd2_journal_wipe(journal, !really_read_only);
3335 if (!err) 3368 if (!err) {
3369 char *save = kmalloc(EXT4_S_ERR_LEN, GFP_KERNEL);
3370 if (save)
3371 memcpy(save, ((char *) es) +
3372 EXT4_S_ERR_START, EXT4_S_ERR_LEN);
3336 err = jbd2_journal_load(journal); 3373 err = jbd2_journal_load(journal);
3374 if (save)
3375 memcpy(((char *) es) + EXT4_S_ERR_START,
3376 save, EXT4_S_ERR_LEN);
3377 kfree(save);
3378 }
3337 3379
3338 if (err) { 3380 if (err) {
3339 ext4_msg(sb, KERN_ERR, "error loading journal"); 3381 ext4_msg(sb, KERN_ERR, "error loading journal");