aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBarry Naujok <bnaujok@sgi.com>2008-06-22 23:25:38 -0400
committerNiv Sardi <xaiki@debian.org>2008-07-28 02:59:01 -0400
commit90bb7ab077a63facbe3aa0b9e3763a0cb956a4c1 (patch)
treefae24e57f69a35c6de32910e2b5d75b7df0f3c04
parente5700704b2b0853c059e424284cceeff3032ea28 (diff)
[XFS] Fix returning case-preserved name with CI node form directories
xfs_dir2_node_lookup() calls xfs_da_node_lookup_int() which iterates through leaf blocks containing the matching hash value for the name being looked up. Inside xfs_da_node_lookup_int(), it calls the xfs_dir2_leafn_lookup_for_entry() for each leaf block. xfs_dir2_leafn_lookup_for_entry() iterates through each matching hash/offset pair doing a name comparison to find the matching dirent. For CI mode, the state->extrablk retains the details of the block that has the CI match so xfs_dir2_node_lookup() can return the case-preserved name. The original implementation didn't retain the xfs_da_buf_t properly, so the lookup was returning a bogus name to be stored in the dentry. In the case of unlink, the bad name was passed and in debug mode, ASSERTed when it can't find the entry. SGI-PV: 983284 SGI-Modid: xfs-linux-melb:xfs-kern:31337a Signed-off-by: Barry Naujok <bnaujok@sgi.com> Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
-rw-r--r--fs/xfs/xfs_dir2_node.c69
1 files changed, 43 insertions, 26 deletions
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index 1b5430223461..fa6c3a5ddbc6 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -549,7 +549,6 @@ xfs_dir2_leafn_lookup_for_entry(
549 xfs_dir2_data_entry_t *dep; /* data block entry */ 549 xfs_dir2_data_entry_t *dep; /* data block entry */
550 xfs_inode_t *dp; /* incore directory inode */ 550 xfs_inode_t *dp; /* incore directory inode */
551 int error; /* error return value */ 551 int error; /* error return value */
552 int di = -1; /* data entry index */
553 int index; /* leaf entry index */ 552 int index; /* leaf entry index */
554 xfs_dir2_leaf_t *leaf; /* leaf structure */ 553 xfs_dir2_leaf_t *leaf; /* leaf structure */
555 xfs_dir2_leaf_entry_t *lep; /* leaf entry */ 554 xfs_dir2_leaf_entry_t *lep; /* leaf entry */
@@ -577,7 +576,6 @@ xfs_dir2_leafn_lookup_for_entry(
577 if (state->extravalid) { 576 if (state->extravalid) {
578 curbp = state->extrablk.bp; 577 curbp = state->extrablk.bp;
579 curdb = state->extrablk.blkno; 578 curdb = state->extrablk.blkno;
580 di = state->extrablk.index;
581 } 579 }
582 /* 580 /*
583 * Loop over leaf entries with the right hash value. 581 * Loop over leaf entries with the right hash value.
@@ -602,17 +600,27 @@ xfs_dir2_leafn_lookup_for_entry(
602 */ 600 */
603 if (newdb != curdb) { 601 if (newdb != curdb) {
604 /* 602 /*
605 * If we had a block before, drop it. 603 * If we had a block before that we aren't saving
604 * for a CI name, drop it
606 */ 605 */
607 if (curbp) 606 if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT ||
607 curdb != state->extrablk.blkno))
608 xfs_da_brelse(tp, curbp); 608 xfs_da_brelse(tp, curbp);
609 /* 609 /*
610 * Read the data block. 610 * If needing the block that is saved with a CI match,
611 * use it otherwise read in the new data block.
611 */ 612 */
612 error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, 613 if (args->cmpresult != XFS_CMP_DIFFERENT &&
613 newdb), -1, &curbp, XFS_DATA_FORK); 614 newdb == state->extrablk.blkno) {
614 if (error) 615 ASSERT(state->extravalid);
615 return error; 616 curbp = state->extrablk.bp;
617 } else {
618 error = xfs_da_read_buf(tp, dp,
619 xfs_dir2_db_to_da(mp, newdb),
620 -1, &curbp, XFS_DATA_FORK);
621 if (error)
622 return error;
623 }
616 xfs_dir2_data_check(dp, curbp); 624 xfs_dir2_data_check(dp, curbp);
617 curdb = newdb; 625 curdb = newdb;
618 } 626 }
@@ -624,38 +632,47 @@ xfs_dir2_leafn_lookup_for_entry(
624 /* 632 /*
625 * Compare the entry and if it's an exact match, return 633 * Compare the entry and if it's an exact match, return
626 * EEXIST immediately. If it's the first case-insensitive 634 * EEXIST immediately. If it's the first case-insensitive
627 * match, store the inode number and continue looking. 635 * match, store the block & inode number and continue looking.
628 */ 636 */
629 cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); 637 cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen);
630 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { 638 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
639 /* If there is a CI match block, drop it */
640 if (args->cmpresult != XFS_CMP_DIFFERENT &&
641 curdb != state->extrablk.blkno)
642 xfs_da_brelse(tp, state->extrablk.bp);
631 args->cmpresult = cmp; 643 args->cmpresult = cmp;
632 args->inumber = be64_to_cpu(dep->inumber); 644 args->inumber = be64_to_cpu(dep->inumber);
633 di = (int)((char *)dep - (char *)curbp->data); 645 *indexp = index;
634 error = EEXIST; 646 state->extravalid = 1;
647 state->extrablk.bp = curbp;
648 state->extrablk.blkno = curdb;
649 state->extrablk.index = (int)((char *)dep -
650 (char *)curbp->data);
651 state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
635 if (cmp == XFS_CMP_EXACT) 652 if (cmp == XFS_CMP_EXACT)
636 goto out; 653 return XFS_ERROR(EEXIST);
637 } 654 }
638 } 655 }
639 /* Didn't find an exact match. */
640 error = ENOENT;
641 ASSERT(index == be16_to_cpu(leaf->hdr.count) || 656 ASSERT(index == be16_to_cpu(leaf->hdr.count) ||
642 (args->op_flags & XFS_DA_OP_OKNOENT)); 657 (args->op_flags & XFS_DA_OP_OKNOENT));
643out:
644 if (curbp) { 658 if (curbp) {
645 /* Giving back a data block. */ 659 if (args->cmpresult == XFS_CMP_DIFFERENT) {
646 state->extravalid = 1; 660 /* Giving back last used data block. */
647 state->extrablk.bp = curbp; 661 state->extravalid = 1;
648 state->extrablk.index = di; 662 state->extrablk.bp = curbp;
649 state->extrablk.blkno = curdb; 663 state->extrablk.index = -1;
650 state->extrablk.magic = XFS_DIR2_DATA_MAGIC; 664 state->extrablk.blkno = curdb;
665 state->extrablk.magic = XFS_DIR2_DATA_MAGIC;
666 } else {
667 /* If the curbp is not the CI match block, drop it */
668 if (state->extrablk.bp != curbp)
669 xfs_da_brelse(tp, curbp);
670 }
651 } else { 671 } else {
652 state->extravalid = 0; 672 state->extravalid = 0;
653 } 673 }
654 /*
655 * Return the index, that will be the deletion point for remove/replace.
656 */
657 *indexp = index; 674 *indexp = index;
658 return XFS_ERROR(error); 675 return XFS_ERROR(ENOENT);
659} 676}
660 677
661/* 678/*