aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorJie Liu <jeff.liu@oracle.com>2014-07-23 22:18:47 -0400
committerDave Chinner <david@fromorbit.com>2014-07-23 22:18:47 -0400
commitc7cb51dcb0a38624d42eeabb38502fa54a4d774b (patch)
tree5a4fa186782c9e3023056e2e34a6bdf0779fedde /fs/xfs
parent549fa00679dd14beaaa685486549c637e8e02182 (diff)
xfs: fix error handling at xfs_inumbers
From: Jie Liu <jeff.liu@oracle.com> To fetch the file system number tables, we currently just ignore the errors and proceed to loop over the next AG or bump agino to the next chunk in case of btree operations failed, that is not properly because those errors might hint us potential file system problems. This patch rework xfs_inumbers() to handle the btree operation errors as well as the loop conditions. Signed-off-by: Jie Liu <jeff.liu@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_itable.c97
1 files changed, 40 insertions, 57 deletions
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index df7605183aa2..ed042fff9337 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -536,7 +536,7 @@ xfs_inumbers(
536 xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, *lastino); 536 xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, *lastino);
537 xfs_agino_t agino = XFS_INO_TO_AGINO(mp, *lastino); 537 xfs_agino_t agino = XFS_INO_TO_AGINO(mp, *lastino);
538 struct xfs_btree_cur *cur = NULL; 538 struct xfs_btree_cur *cur = NULL;
539 xfs_buf_t *agbp = NULL; 539 struct xfs_buf *agbp = NULL;
540 struct xfs_inogrp *buffer; 540 struct xfs_inogrp *buffer;
541 int bcount; 541 int bcount;
542 int left = *count; 542 int left = *count;
@@ -550,61 +550,40 @@ xfs_inumbers(
550 550
551 bcount = MIN(left, (int)(PAGE_SIZE / sizeof(*buffer))); 551 bcount = MIN(left, (int)(PAGE_SIZE / sizeof(*buffer)));
552 buffer = kmem_alloc(bcount * sizeof(*buffer), KM_SLEEP); 552 buffer = kmem_alloc(bcount * sizeof(*buffer), KM_SLEEP);
553 while (left > 0 && agno < mp->m_sb.sb_agcount) { 553 do {
554 struct xfs_inobt_rec_incore r; 554 struct xfs_inobt_rec_incore r;
555 int stat; 555 int stat;
556 556
557 if (agbp == NULL) { 557 if (!agbp) {
558 error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); 558 error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
559 if (error) { 559 if (error)
560 /* 560 break;
561 * If we can't read the AGI of this ag, 561
562 * then just skip to the next one.
563 */
564 ASSERT(cur == NULL);
565 agbp = NULL;
566 agno++;
567 agino = 0;
568 continue;
569 }
570 cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno, 562 cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
571 XFS_BTNUM_INO); 563 XFS_BTNUM_INO);
572 error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE, 564 error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE,
573 &stat); 565 &stat);
574 if (error) { 566 if (error)
575 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); 567 break;
576 cur = NULL; 568 if (!stat)
577 xfs_buf_relse(agbp); 569 goto next_ag;
578 agbp = NULL;
579 /*
580 * Move up the last inode in the current
581 * chunk. The lookup_ge will always get
582 * us the first inode in the next chunk.
583 */
584 agino += XFS_INODES_PER_CHUNK - 1;
585 continue;
586 }
587 } 570 }
571
588 error = xfs_inobt_get_rec(cur, &r, &stat); 572 error = xfs_inobt_get_rec(cur, &r, &stat);
589 if (error || stat == 0) { 573 if (error)
590 xfs_buf_relse(agbp); 574 break;
591 agbp = NULL; 575 if (!stat)
592 xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); 576 goto next_ag;
593 cur = NULL; 577
594 agno++;
595 agino = 0;
596 continue;
597 }
598 agino = r.ir_startino + XFS_INODES_PER_CHUNK - 1; 578 agino = r.ir_startino + XFS_INODES_PER_CHUNK - 1;
599 buffer[bufidx].xi_startino = 579 buffer[bufidx].xi_startino =
600 XFS_AGINO_TO_INO(mp, agno, r.ir_startino); 580 XFS_AGINO_TO_INO(mp, agno, r.ir_startino);
601 buffer[bufidx].xi_alloccount = 581 buffer[bufidx].xi_alloccount =
602 XFS_INODES_PER_CHUNK - r.ir_freecount; 582 XFS_INODES_PER_CHUNK - r.ir_freecount;
603 buffer[bufidx].xi_allocmask = ~r.ir_free; 583 buffer[bufidx].xi_allocmask = ~r.ir_free;
604 bufidx++; 584 if (++bufidx == bcount) {
605 left--; 585 long written;
606 if (bufidx == bcount) { 586
607 long written;
608 error = formatter(ubuffer, buffer, bufidx, &written); 587 error = formatter(ubuffer, buffer, bufidx, &written);
609 if (error) 588 if (error)
610 break; 589 break;
@@ -612,36 +591,40 @@ xfs_inumbers(
612 *count += bufidx; 591 *count += bufidx;
613 bufidx = 0; 592 bufidx = 0;
614 } 593 }
615 if (left) { 594 if (!--left)
616 error = xfs_btree_increment(cur, 0, &stat); 595 break;
617 if (error) { 596
618 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); 597 error = xfs_btree_increment(cur, 0, &stat);
619 cur = NULL; 598 if (error)
620 xfs_buf_relse(agbp); 599 break;
621 agbp = NULL; 600 if (stat)
622 /* 601 continue;
623 * The agino value has already been bumped. 602
624 * Just try to skip up to it. 603next_ag:
625 */ 604 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
626 agino += XFS_INODES_PER_CHUNK; 605 cur = NULL;
627 continue; 606 xfs_buf_relse(agbp);
628 } 607 agbp = NULL;
629 } 608 agino = 0;
630 } 609 } while (++agno < mp->m_sb.sb_agcount);
610
631 if (!error) { 611 if (!error) {
632 if (bufidx) { 612 if (bufidx) {
633 long written; 613 long written;
614
634 error = formatter(ubuffer, buffer, bufidx, &written); 615 error = formatter(ubuffer, buffer, bufidx, &written);
635 if (!error) 616 if (!error)
636 *count += bufidx; 617 *count += bufidx;
637 } 618 }
638 *lastino = XFS_AGINO_TO_INO(mp, agno, agino); 619 *lastino = XFS_AGINO_TO_INO(mp, agno, agino);
639 } 620 }
621
640 kmem_free(buffer); 622 kmem_free(buffer);
641 if (cur) 623 if (cur)
642 xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR : 624 xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR :
643 XFS_BTREE_NOERROR)); 625 XFS_BTREE_NOERROR));
644 if (agbp) 626 if (agbp)
645 xfs_buf_relse(agbp); 627 xfs_buf_relse(agbp);
628
646 return error; 629 return error;
647} 630}