diff options
Diffstat (limited to 'fs/ocfs2/inode.c')
-rw-r--r-- | fs/ocfs2/inode.c | 228 |
1 files changed, 219 insertions, 9 deletions
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 36294446d960..12f4a9e9800f 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include "xattr.h" | 53 | #include "xattr.h" |
54 | #include "refcounttree.h" | 54 | #include "refcounttree.h" |
55 | #include "ocfs2_trace.h" | 55 | #include "ocfs2_trace.h" |
56 | #include "filecheck.h" | ||
56 | 57 | ||
57 | #include "buffer_head_io.h" | 58 | #include "buffer_head_io.h" |
58 | 59 | ||
@@ -74,6 +75,14 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb, | |||
74 | struct inode *inode, | 75 | struct inode *inode, |
75 | struct buffer_head *fe_bh); | 76 | struct buffer_head *fe_bh); |
76 | 77 | ||
78 | static int ocfs2_filecheck_read_inode_block_full(struct inode *inode, | ||
79 | struct buffer_head **bh, | ||
80 | int flags, int type); | ||
81 | static int ocfs2_filecheck_validate_inode_block(struct super_block *sb, | ||
82 | struct buffer_head *bh); | ||
83 | static int ocfs2_filecheck_repair_inode_block(struct super_block *sb, | ||
84 | struct buffer_head *bh); | ||
85 | |||
77 | void ocfs2_set_inode_flags(struct inode *inode) | 86 | void ocfs2_set_inode_flags(struct inode *inode) |
78 | { | 87 | { |
79 | unsigned int flags = OCFS2_I(inode)->ip_attr; | 88 | unsigned int flags = OCFS2_I(inode)->ip_attr; |
@@ -127,6 +136,7 @@ struct inode *ocfs2_ilookup(struct super_block *sb, u64 blkno) | |||
127 | struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags, | 136 | struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags, |
128 | int sysfile_type) | 137 | int sysfile_type) |
129 | { | 138 | { |
139 | int rc = 0; | ||
130 | struct inode *inode = NULL; | 140 | struct inode *inode = NULL; |
131 | struct super_block *sb = osb->sb; | 141 | struct super_block *sb = osb->sb; |
132 | struct ocfs2_find_inode_args args; | 142 | struct ocfs2_find_inode_args args; |
@@ -161,12 +171,17 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags, | |||
161 | } | 171 | } |
162 | trace_ocfs2_iget5_locked(inode->i_state); | 172 | trace_ocfs2_iget5_locked(inode->i_state); |
163 | if (inode->i_state & I_NEW) { | 173 | if (inode->i_state & I_NEW) { |
164 | ocfs2_read_locked_inode(inode, &args); | 174 | rc = ocfs2_read_locked_inode(inode, &args); |
165 | unlock_new_inode(inode); | 175 | unlock_new_inode(inode); |
166 | } | 176 | } |
167 | if (is_bad_inode(inode)) { | 177 | if (is_bad_inode(inode)) { |
168 | iput(inode); | 178 | iput(inode); |
169 | inode = ERR_PTR(-ESTALE); | 179 | if ((flags & OCFS2_FI_FLAG_FILECHECK_CHK) || |
180 | (flags & OCFS2_FI_FLAG_FILECHECK_FIX)) | ||
181 | /* Return OCFS2_FILECHECK_ERR_XXX related errno */ | ||
182 | inode = ERR_PTR(rc); | ||
183 | else | ||
184 | inode = ERR_PTR(-ESTALE); | ||
170 | goto bail; | 185 | goto bail; |
171 | } | 186 | } |
172 | 187 | ||
@@ -410,7 +425,7 @@ static int ocfs2_read_locked_inode(struct inode *inode, | |||
410 | struct ocfs2_super *osb; | 425 | struct ocfs2_super *osb; |
411 | struct ocfs2_dinode *fe; | 426 | struct ocfs2_dinode *fe; |
412 | struct buffer_head *bh = NULL; | 427 | struct buffer_head *bh = NULL; |
413 | int status, can_lock; | 428 | int status, can_lock, lock_level = 0; |
414 | u32 generation = 0; | 429 | u32 generation = 0; |
415 | 430 | ||
416 | status = -EINVAL; | 431 | status = -EINVAL; |
@@ -478,7 +493,7 @@ static int ocfs2_read_locked_inode(struct inode *inode, | |||
478 | mlog_errno(status); | 493 | mlog_errno(status); |
479 | return status; | 494 | return status; |
480 | } | 495 | } |
481 | status = ocfs2_inode_lock(inode, NULL, 0); | 496 | status = ocfs2_inode_lock(inode, NULL, lock_level); |
482 | if (status) { | 497 | if (status) { |
483 | make_bad_inode(inode); | 498 | make_bad_inode(inode); |
484 | mlog_errno(status); | 499 | mlog_errno(status); |
@@ -495,16 +510,32 @@ static int ocfs2_read_locked_inode(struct inode *inode, | |||
495 | } | 510 | } |
496 | 511 | ||
497 | if (can_lock) { | 512 | if (can_lock) { |
498 | status = ocfs2_read_inode_block_full(inode, &bh, | 513 | if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_CHK) |
499 | OCFS2_BH_IGNORE_CACHE); | 514 | status = ocfs2_filecheck_read_inode_block_full(inode, |
515 | &bh, OCFS2_BH_IGNORE_CACHE, 0); | ||
516 | else if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_FIX) | ||
517 | status = ocfs2_filecheck_read_inode_block_full(inode, | ||
518 | &bh, OCFS2_BH_IGNORE_CACHE, 1); | ||
519 | else | ||
520 | status = ocfs2_read_inode_block_full(inode, | ||
521 | &bh, OCFS2_BH_IGNORE_CACHE); | ||
500 | } else { | 522 | } else { |
501 | status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh); | 523 | status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh); |
502 | /* | 524 | /* |
503 | * If buffer is in jbd, then its checksum may not have been | 525 | * If buffer is in jbd, then its checksum may not have been |
504 | * computed as yet. | 526 | * computed as yet. |
505 | */ | 527 | */ |
506 | if (!status && !buffer_jbd(bh)) | 528 | if (!status && !buffer_jbd(bh)) { |
507 | status = ocfs2_validate_inode_block(osb->sb, bh); | 529 | if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_CHK) |
530 | status = ocfs2_filecheck_validate_inode_block( | ||
531 | osb->sb, bh); | ||
532 | else if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_FIX) | ||
533 | status = ocfs2_filecheck_repair_inode_block( | ||
534 | osb->sb, bh); | ||
535 | else | ||
536 | status = ocfs2_validate_inode_block( | ||
537 | osb->sb, bh); | ||
538 | } | ||
508 | } | 539 | } |
509 | if (status < 0) { | 540 | if (status < 0) { |
510 | mlog_errno(status); | 541 | mlog_errno(status); |
@@ -532,11 +563,24 @@ static int ocfs2_read_locked_inode(struct inode *inode, | |||
532 | 563 | ||
533 | BUG_ON(args->fi_blkno != le64_to_cpu(fe->i_blkno)); | 564 | BUG_ON(args->fi_blkno != le64_to_cpu(fe->i_blkno)); |
534 | 565 | ||
566 | if (buffer_dirty(bh) && !buffer_jbd(bh)) { | ||
567 | if (can_lock) { | ||
568 | ocfs2_inode_unlock(inode, lock_level); | ||
569 | lock_level = 1; | ||
570 | ocfs2_inode_lock(inode, NULL, lock_level); | ||
571 | } | ||
572 | status = ocfs2_write_block(osb, bh, INODE_CACHE(inode)); | ||
573 | if (status < 0) { | ||
574 | mlog_errno(status); | ||
575 | goto bail; | ||
576 | } | ||
577 | } | ||
578 | |||
535 | status = 0; | 579 | status = 0; |
536 | 580 | ||
537 | bail: | 581 | bail: |
538 | if (can_lock) | 582 | if (can_lock) |
539 | ocfs2_inode_unlock(inode, 0); | 583 | ocfs2_inode_unlock(inode, lock_level); |
540 | 584 | ||
541 | if (status < 0) | 585 | if (status < 0) |
542 | make_bad_inode(inode); | 586 | make_bad_inode(inode); |
@@ -1126,6 +1170,9 @@ static void ocfs2_clear_inode(struct inode *inode) | |||
1126 | mlog_bug_on_msg(!list_empty(&oi->ip_io_markers), | 1170 | mlog_bug_on_msg(!list_empty(&oi->ip_io_markers), |
1127 | "Clear inode of %llu, inode has io markers\n", | 1171 | "Clear inode of %llu, inode has io markers\n", |
1128 | (unsigned long long)oi->ip_blkno); | 1172 | (unsigned long long)oi->ip_blkno); |
1173 | mlog_bug_on_msg(!list_empty(&oi->ip_unwritten_list), | ||
1174 | "Clear inode of %llu, inode has unwritten extents\n", | ||
1175 | (unsigned long long)oi->ip_blkno); | ||
1129 | 1176 | ||
1130 | ocfs2_extent_map_trunc(inode, 0); | 1177 | ocfs2_extent_map_trunc(inode, 0); |
1131 | 1178 | ||
@@ -1397,6 +1444,169 @@ bail: | |||
1397 | return rc; | 1444 | return rc; |
1398 | } | 1445 | } |
1399 | 1446 | ||
1447 | static int ocfs2_filecheck_validate_inode_block(struct super_block *sb, | ||
1448 | struct buffer_head *bh) | ||
1449 | { | ||
1450 | int rc = 0; | ||
1451 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data; | ||
1452 | |||
1453 | trace_ocfs2_filecheck_validate_inode_block( | ||
1454 | (unsigned long long)bh->b_blocknr); | ||
1455 | |||
1456 | BUG_ON(!buffer_uptodate(bh)); | ||
1457 | |||
1458 | /* | ||
1459 | * Call ocfs2_validate_meta_ecc() first since it has ecc repair | ||
1460 | * function, but we should not return error immediately when ecc | ||
1461 | * validation fails, because the reason is quite likely the invalid | ||
1462 | * inode number inputed. | ||
1463 | */ | ||
1464 | rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check); | ||
1465 | if (rc) { | ||
1466 | mlog(ML_ERROR, | ||
1467 | "Filecheck: checksum failed for dinode %llu\n", | ||
1468 | (unsigned long long)bh->b_blocknr); | ||
1469 | rc = -OCFS2_FILECHECK_ERR_BLOCKECC; | ||
1470 | } | ||
1471 | |||
1472 | if (!OCFS2_IS_VALID_DINODE(di)) { | ||
1473 | mlog(ML_ERROR, | ||
1474 | "Filecheck: invalid dinode #%llu: signature = %.*s\n", | ||
1475 | (unsigned long long)bh->b_blocknr, 7, di->i_signature); | ||
1476 | rc = -OCFS2_FILECHECK_ERR_INVALIDINO; | ||
1477 | goto bail; | ||
1478 | } else if (rc) | ||
1479 | goto bail; | ||
1480 | |||
1481 | if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) { | ||
1482 | mlog(ML_ERROR, | ||
1483 | "Filecheck: invalid dinode #%llu: i_blkno is %llu\n", | ||
1484 | (unsigned long long)bh->b_blocknr, | ||
1485 | (unsigned long long)le64_to_cpu(di->i_blkno)); | ||
1486 | rc = -OCFS2_FILECHECK_ERR_BLOCKNO; | ||
1487 | goto bail; | ||
1488 | } | ||
1489 | |||
1490 | if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) { | ||
1491 | mlog(ML_ERROR, | ||
1492 | "Filecheck: invalid dinode #%llu: OCFS2_VALID_FL " | ||
1493 | "not set\n", | ||
1494 | (unsigned long long)bh->b_blocknr); | ||
1495 | rc = -OCFS2_FILECHECK_ERR_VALIDFLAG; | ||
1496 | goto bail; | ||
1497 | } | ||
1498 | |||
1499 | if (le32_to_cpu(di->i_fs_generation) != | ||
1500 | OCFS2_SB(sb)->fs_generation) { | ||
1501 | mlog(ML_ERROR, | ||
1502 | "Filecheck: invalid dinode #%llu: fs_generation is %u\n", | ||
1503 | (unsigned long long)bh->b_blocknr, | ||
1504 | le32_to_cpu(di->i_fs_generation)); | ||
1505 | rc = -OCFS2_FILECHECK_ERR_GENERATION; | ||
1506 | goto bail; | ||
1507 | } | ||
1508 | |||
1509 | bail: | ||
1510 | return rc; | ||
1511 | } | ||
1512 | |||
1513 | static int ocfs2_filecheck_repair_inode_block(struct super_block *sb, | ||
1514 | struct buffer_head *bh) | ||
1515 | { | ||
1516 | int changed = 0; | ||
1517 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data; | ||
1518 | |||
1519 | if (!ocfs2_filecheck_validate_inode_block(sb, bh)) | ||
1520 | return 0; | ||
1521 | |||
1522 | trace_ocfs2_filecheck_repair_inode_block( | ||
1523 | (unsigned long long)bh->b_blocknr); | ||
1524 | |||
1525 | if (ocfs2_is_hard_readonly(OCFS2_SB(sb)) || | ||
1526 | ocfs2_is_soft_readonly(OCFS2_SB(sb))) { | ||
1527 | mlog(ML_ERROR, | ||
1528 | "Filecheck: cannot repair dinode #%llu " | ||
1529 | "on readonly filesystem\n", | ||
1530 | (unsigned long long)bh->b_blocknr); | ||
1531 | return -OCFS2_FILECHECK_ERR_READONLY; | ||
1532 | } | ||
1533 | |||
1534 | if (buffer_jbd(bh)) { | ||
1535 | mlog(ML_ERROR, | ||
1536 | "Filecheck: cannot repair dinode #%llu, " | ||
1537 | "its buffer is in jbd\n", | ||
1538 | (unsigned long long)bh->b_blocknr); | ||
1539 | return -OCFS2_FILECHECK_ERR_INJBD; | ||
1540 | } | ||
1541 | |||
1542 | if (!OCFS2_IS_VALID_DINODE(di)) { | ||
1543 | /* Cannot fix invalid inode block */ | ||
1544 | return -OCFS2_FILECHECK_ERR_INVALIDINO; | ||
1545 | } | ||
1546 | |||
1547 | if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) { | ||
1548 | /* Cannot just add VALID_FL flag back as a fix, | ||
1549 | * need more things to check here. | ||
1550 | */ | ||
1551 | return -OCFS2_FILECHECK_ERR_VALIDFLAG; | ||
1552 | } | ||
1553 | |||
1554 | if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) { | ||
1555 | di->i_blkno = cpu_to_le64(bh->b_blocknr); | ||
1556 | changed = 1; | ||
1557 | mlog(ML_ERROR, | ||
1558 | "Filecheck: reset dinode #%llu: i_blkno to %llu\n", | ||
1559 | (unsigned long long)bh->b_blocknr, | ||
1560 | (unsigned long long)le64_to_cpu(di->i_blkno)); | ||
1561 | } | ||
1562 | |||
1563 | if (le32_to_cpu(di->i_fs_generation) != | ||
1564 | OCFS2_SB(sb)->fs_generation) { | ||
1565 | di->i_fs_generation = cpu_to_le32(OCFS2_SB(sb)->fs_generation); | ||
1566 | changed = 1; | ||
1567 | mlog(ML_ERROR, | ||
1568 | "Filecheck: reset dinode #%llu: fs_generation to %u\n", | ||
1569 | (unsigned long long)bh->b_blocknr, | ||
1570 | le32_to_cpu(di->i_fs_generation)); | ||
1571 | } | ||
1572 | |||
1573 | if (changed || ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check)) { | ||
1574 | ocfs2_compute_meta_ecc(sb, bh->b_data, &di->i_check); | ||
1575 | mark_buffer_dirty(bh); | ||
1576 | mlog(ML_ERROR, | ||
1577 | "Filecheck: reset dinode #%llu: compute meta ecc\n", | ||
1578 | (unsigned long long)bh->b_blocknr); | ||
1579 | } | ||
1580 | |||
1581 | return 0; | ||
1582 | } | ||
1583 | |||
1584 | static int | ||
1585 | ocfs2_filecheck_read_inode_block_full(struct inode *inode, | ||
1586 | struct buffer_head **bh, | ||
1587 | int flags, int type) | ||
1588 | { | ||
1589 | int rc; | ||
1590 | struct buffer_head *tmp = *bh; | ||
1591 | |||
1592 | if (!type) /* Check inode block */ | ||
1593 | rc = ocfs2_read_blocks(INODE_CACHE(inode), | ||
1594 | OCFS2_I(inode)->ip_blkno, | ||
1595 | 1, &tmp, flags, | ||
1596 | ocfs2_filecheck_validate_inode_block); | ||
1597 | else /* Repair inode block */ | ||
1598 | rc = ocfs2_read_blocks(INODE_CACHE(inode), | ||
1599 | OCFS2_I(inode)->ip_blkno, | ||
1600 | 1, &tmp, flags, | ||
1601 | ocfs2_filecheck_repair_inode_block); | ||
1602 | |||
1603 | /* If ocfs2_read_blocks() got us a new bh, pass it up. */ | ||
1604 | if (!rc && !*bh) | ||
1605 | *bh = tmp; | ||
1606 | |||
1607 | return rc; | ||
1608 | } | ||
1609 | |||
1400 | int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh, | 1610 | int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh, |
1401 | int flags) | 1611 | int flags) |
1402 | { | 1612 | { |