diff options
author | Christoph Hellwig <hch@infradead.org> | 2008-10-30 01:56:09 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@sgi.com> | 2008-10-30 01:56:09 -0400 |
commit | fe033cc848489851f0c7de48f0b1bab5d744ad8a (patch) | |
tree | f69709f4e9c125c528a699c32f439b53ea0969f3 /fs/xfs/xfs_ialloc_btree.c | |
parent | 8df4da4a0a642d3a016028c0d922bcb4d5a4a6d7 (diff) |
[XFS] implement generic xfs_btree_lookup
From: Dave Chinner <dgc@sgi.com>
[hch: split out from bigger patch and minor adaptions]
SGI-PV: 985583
SGI-Modid: xfs-linux-melb:xfs-kern:32192a
Signed-off-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: Bill O'Donnell <billodo@sgi.com>
Signed-off-by: David Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs/xfs_ialloc_btree.c')
-rw-r--r-- | fs/xfs/xfs_ialloc_btree.c | 294 |
1 files changed, 35 insertions, 259 deletions
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c index 9099a32f9972..161c3b2e245f 100644 --- a/fs/xfs/xfs_ialloc_btree.c +++ b/fs/xfs/xfs_ialloc_btree.c | |||
@@ -829,212 +829,6 @@ xfs_inobt_log_recs( | |||
829 | } | 829 | } |
830 | 830 | ||
831 | /* | 831 | /* |
832 | * Lookup the record. The cursor is made to point to it, based on dir. | ||
833 | * Return 0 if can't find any such record, 1 for success. | ||
834 | */ | ||
835 | STATIC int /* error */ | ||
836 | xfs_inobt_lookup( | ||
837 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
838 | xfs_lookup_t dir, /* <=, ==, or >= */ | ||
839 | int *stat) /* success/failure */ | ||
840 | { | ||
841 | xfs_agblock_t agbno; /* a.g. relative btree block number */ | ||
842 | xfs_agnumber_t agno; /* allocation group number */ | ||
843 | xfs_inobt_block_t *block=NULL; /* current btree block */ | ||
844 | __int64_t diff; /* difference for the current key */ | ||
845 | int error; /* error return value */ | ||
846 | int keyno=0; /* current key number */ | ||
847 | int level; /* level in the btree */ | ||
848 | xfs_mount_t *mp; /* file system mount point */ | ||
849 | |||
850 | /* | ||
851 | * Get the allocation group header, and the root block number. | ||
852 | */ | ||
853 | mp = cur->bc_mp; | ||
854 | { | ||
855 | xfs_agi_t *agi; /* a.g. inode header */ | ||
856 | |||
857 | agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); | ||
858 | agno = be32_to_cpu(agi->agi_seqno); | ||
859 | agbno = be32_to_cpu(agi->agi_root); | ||
860 | } | ||
861 | /* | ||
862 | * Iterate over each level in the btree, starting at the root. | ||
863 | * For each level above the leaves, find the key we need, based | ||
864 | * on the lookup record, then follow the corresponding block | ||
865 | * pointer down to the next level. | ||
866 | */ | ||
867 | for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { | ||
868 | xfs_buf_t *bp; /* buffer pointer for btree block */ | ||
869 | xfs_daddr_t d; /* disk address of btree block */ | ||
870 | |||
871 | /* | ||
872 | * Get the disk address we're looking for. | ||
873 | */ | ||
874 | d = XFS_AGB_TO_DADDR(mp, agno, agbno); | ||
875 | /* | ||
876 | * If the old buffer at this level is for a different block, | ||
877 | * throw it away, otherwise just use it. | ||
878 | */ | ||
879 | bp = cur->bc_bufs[level]; | ||
880 | if (bp && XFS_BUF_ADDR(bp) != d) | ||
881 | bp = NULL; | ||
882 | if (!bp) { | ||
883 | /* | ||
884 | * Need to get a new buffer. Read it, then | ||
885 | * set it in the cursor, releasing the old one. | ||
886 | */ | ||
887 | if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, | ||
888 | agno, agbno, 0, &bp, XFS_INO_BTREE_REF))) | ||
889 | return error; | ||
890 | xfs_btree_setbuf(cur, level, bp); | ||
891 | /* | ||
892 | * Point to the btree block, now that we have the buffer | ||
893 | */ | ||
894 | block = XFS_BUF_TO_INOBT_BLOCK(bp); | ||
895 | if ((error = xfs_btree_check_sblock(cur, block, level, | ||
896 | bp))) | ||
897 | return error; | ||
898 | } else | ||
899 | block = XFS_BUF_TO_INOBT_BLOCK(bp); | ||
900 | /* | ||
901 | * If we already had a key match at a higher level, we know | ||
902 | * we need to use the first entry in this block. | ||
903 | */ | ||
904 | if (diff == 0) | ||
905 | keyno = 1; | ||
906 | /* | ||
907 | * Otherwise we need to search this block. Do a binary search. | ||
908 | */ | ||
909 | else { | ||
910 | int high; /* high entry number */ | ||
911 | xfs_inobt_key_t *kkbase=NULL;/* base of keys in block */ | ||
912 | xfs_inobt_rec_t *krbase=NULL;/* base of records in block */ | ||
913 | int low; /* low entry number */ | ||
914 | |||
915 | /* | ||
916 | * Get a pointer to keys or records. | ||
917 | */ | ||
918 | if (level > 0) | ||
919 | kkbase = XFS_INOBT_KEY_ADDR(block, 1, cur); | ||
920 | else | ||
921 | krbase = XFS_INOBT_REC_ADDR(block, 1, cur); | ||
922 | /* | ||
923 | * Set low and high entry numbers, 1-based. | ||
924 | */ | ||
925 | low = 1; | ||
926 | if (!(high = be16_to_cpu(block->bb_numrecs))) { | ||
927 | /* | ||
928 | * If the block is empty, the tree must | ||
929 | * be an empty leaf. | ||
930 | */ | ||
931 | ASSERT(level == 0 && cur->bc_nlevels == 1); | ||
932 | cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; | ||
933 | *stat = 0; | ||
934 | return 0; | ||
935 | } | ||
936 | /* | ||
937 | * Binary search the block. | ||
938 | */ | ||
939 | while (low <= high) { | ||
940 | xfs_agino_t startino; /* key value */ | ||
941 | |||
942 | /* | ||
943 | * keyno is average of low and high. | ||
944 | */ | ||
945 | keyno = (low + high) >> 1; | ||
946 | /* | ||
947 | * Get startino. | ||
948 | */ | ||
949 | if (level > 0) { | ||
950 | xfs_inobt_key_t *kkp; | ||
951 | |||
952 | kkp = kkbase + keyno - 1; | ||
953 | startino = be32_to_cpu(kkp->ir_startino); | ||
954 | } else { | ||
955 | xfs_inobt_rec_t *krp; | ||
956 | |||
957 | krp = krbase + keyno - 1; | ||
958 | startino = be32_to_cpu(krp->ir_startino); | ||
959 | } | ||
960 | /* | ||
961 | * Compute difference to get next direction. | ||
962 | */ | ||
963 | diff = (__int64_t) | ||
964 | startino - cur->bc_rec.i.ir_startino; | ||
965 | /* | ||
966 | * Less than, move right. | ||
967 | */ | ||
968 | if (diff < 0) | ||
969 | low = keyno + 1; | ||
970 | /* | ||
971 | * Greater than, move left. | ||
972 | */ | ||
973 | else if (diff > 0) | ||
974 | high = keyno - 1; | ||
975 | /* | ||
976 | * Equal, we're done. | ||
977 | */ | ||
978 | else | ||
979 | break; | ||
980 | } | ||
981 | } | ||
982 | /* | ||
983 | * If there are more levels, set up for the next level | ||
984 | * by getting the block number and filling in the cursor. | ||
985 | */ | ||
986 | if (level > 0) { | ||
987 | /* | ||
988 | * If we moved left, need the previous key number, | ||
989 | * unless there isn't one. | ||
990 | */ | ||
991 | if (diff > 0 && --keyno < 1) | ||
992 | keyno = 1; | ||
993 | agbno = be32_to_cpu(*XFS_INOBT_PTR_ADDR(block, keyno, cur)); | ||
994 | #ifdef DEBUG | ||
995 | if ((error = xfs_btree_check_sptr(cur, agbno, level))) | ||
996 | return error; | ||
997 | #endif | ||
998 | cur->bc_ptrs[level] = keyno; | ||
999 | } | ||
1000 | } | ||
1001 | /* | ||
1002 | * Done with the search. | ||
1003 | * See if we need to adjust the results. | ||
1004 | */ | ||
1005 | if (dir != XFS_LOOKUP_LE && diff < 0) { | ||
1006 | keyno++; | ||
1007 | /* | ||
1008 | * If ge search and we went off the end of the block, but it's | ||
1009 | * not the last block, we're in the wrong block. | ||
1010 | */ | ||
1011 | if (dir == XFS_LOOKUP_GE && | ||
1012 | keyno > be16_to_cpu(block->bb_numrecs) && | ||
1013 | be32_to_cpu(block->bb_rightsib) != NULLAGBLOCK) { | ||
1014 | int i; | ||
1015 | |||
1016 | cur->bc_ptrs[0] = keyno; | ||
1017 | if ((error = xfs_btree_increment(cur, 0, &i))) | ||
1018 | return error; | ||
1019 | ASSERT(i == 1); | ||
1020 | *stat = 1; | ||
1021 | return 0; | ||
1022 | } | ||
1023 | } | ||
1024 | else if (dir == XFS_LOOKUP_LE && diff > 0) | ||
1025 | keyno--; | ||
1026 | cur->bc_ptrs[0] = keyno; | ||
1027 | /* | ||
1028 | * Return if we succeeded or not. | ||
1029 | */ | ||
1030 | if (keyno == 0 || keyno > be16_to_cpu(block->bb_numrecs)) | ||
1031 | *stat = 0; | ||
1032 | else | ||
1033 | *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0)); | ||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | /* | ||
1038 | * Move 1 record left from cur/level if possible. | 832 | * Move 1 record left from cur/level if possible. |
1039 | * Update cur to reflect the new path. | 833 | * Update cur to reflect the new path. |
1040 | */ | 834 | */ |
@@ -1798,59 +1592,6 @@ xfs_inobt_insert( | |||
1798 | } | 1592 | } |
1799 | 1593 | ||
1800 | /* | 1594 | /* |
1801 | * Lookup the record equal to ino in the btree given by cur. | ||
1802 | */ | ||
1803 | int /* error */ | ||
1804 | xfs_inobt_lookup_eq( | ||
1805 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
1806 | xfs_agino_t ino, /* starting inode of chunk */ | ||
1807 | __int32_t fcnt, /* free inode count */ | ||
1808 | xfs_inofree_t free, /* free inode mask */ | ||
1809 | int *stat) /* success/failure */ | ||
1810 | { | ||
1811 | cur->bc_rec.i.ir_startino = ino; | ||
1812 | cur->bc_rec.i.ir_freecount = fcnt; | ||
1813 | cur->bc_rec.i.ir_free = free; | ||
1814 | return xfs_inobt_lookup(cur, XFS_LOOKUP_EQ, stat); | ||
1815 | } | ||
1816 | |||
1817 | /* | ||
1818 | * Lookup the first record greater than or equal to ino | ||
1819 | * in the btree given by cur. | ||
1820 | */ | ||
1821 | int /* error */ | ||
1822 | xfs_inobt_lookup_ge( | ||
1823 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
1824 | xfs_agino_t ino, /* starting inode of chunk */ | ||
1825 | __int32_t fcnt, /* free inode count */ | ||
1826 | xfs_inofree_t free, /* free inode mask */ | ||
1827 | int *stat) /* success/failure */ | ||
1828 | { | ||
1829 | cur->bc_rec.i.ir_startino = ino; | ||
1830 | cur->bc_rec.i.ir_freecount = fcnt; | ||
1831 | cur->bc_rec.i.ir_free = free; | ||
1832 | return xfs_inobt_lookup(cur, XFS_LOOKUP_GE, stat); | ||
1833 | } | ||
1834 | |||
1835 | /* | ||
1836 | * Lookup the first record less than or equal to ino | ||
1837 | * in the btree given by cur. | ||
1838 | */ | ||
1839 | int /* error */ | ||
1840 | xfs_inobt_lookup_le( | ||
1841 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
1842 | xfs_agino_t ino, /* starting inode of chunk */ | ||
1843 | __int32_t fcnt, /* free inode count */ | ||
1844 | xfs_inofree_t free, /* free inode mask */ | ||
1845 | int *stat) /* success/failure */ | ||
1846 | { | ||
1847 | cur->bc_rec.i.ir_startino = ino; | ||
1848 | cur->bc_rec.i.ir_freecount = fcnt; | ||
1849 | cur->bc_rec.i.ir_free = free; | ||
1850 | return xfs_inobt_lookup(cur, XFS_LOOKUP_LE, stat); | ||
1851 | } | ||
1852 | |||
1853 | /* | ||
1854 | * Update the record referred to by cur, to the value given | 1595 | * Update the record referred to by cur, to the value given |
1855 | * by [ino, fcnt, free]. | 1596 | * by [ino, fcnt, free]. |
1856 | * This either works (return 0) or gets an EFSCORRUPTED error. | 1597 | * This either works (return 0) or gets an EFSCORRUPTED error. |
@@ -1918,6 +1659,38 @@ xfs_inobt_get_maxrecs( | |||
1918 | return cur->bc_mp->m_inobt_mxr[level != 0]; | 1659 | return cur->bc_mp->m_inobt_mxr[level != 0]; |
1919 | } | 1660 | } |
1920 | 1661 | ||
1662 | STATIC void | ||
1663 | xfs_inobt_init_key_from_rec( | ||
1664 | union xfs_btree_key *key, | ||
1665 | union xfs_btree_rec *rec) | ||
1666 | { | ||
1667 | key->inobt.ir_startino = rec->inobt.ir_startino; | ||
1668 | } | ||
1669 | |||
1670 | /* | ||
1671 | * intial value of ptr for lookup | ||
1672 | */ | ||
1673 | STATIC void | ||
1674 | xfs_inobt_init_ptr_from_cur( | ||
1675 | struct xfs_btree_cur *cur, | ||
1676 | union xfs_btree_ptr *ptr) | ||
1677 | { | ||
1678 | struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); | ||
1679 | |||
1680 | ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno)); | ||
1681 | |||
1682 | ptr->s = agi->agi_root; | ||
1683 | } | ||
1684 | |||
1685 | STATIC __int64_t | ||
1686 | xfs_inobt_key_diff( | ||
1687 | struct xfs_btree_cur *cur, | ||
1688 | union xfs_btree_key *key) | ||
1689 | { | ||
1690 | return (__int64_t)be32_to_cpu(key->inobt.ir_startino) - | ||
1691 | cur->bc_rec.i.ir_startino; | ||
1692 | } | ||
1693 | |||
1921 | #ifdef XFS_BTREE_TRACE | 1694 | #ifdef XFS_BTREE_TRACE |
1922 | ktrace_t *xfs_inobt_trace_buf; | 1695 | ktrace_t *xfs_inobt_trace_buf; |
1923 | 1696 | ||
@@ -1990,6 +1763,9 @@ static const struct xfs_btree_ops xfs_inobt_ops = { | |||
1990 | 1763 | ||
1991 | .dup_cursor = xfs_inobt_dup_cursor, | 1764 | .dup_cursor = xfs_inobt_dup_cursor, |
1992 | .get_maxrecs = xfs_inobt_get_maxrecs, | 1765 | .get_maxrecs = xfs_inobt_get_maxrecs, |
1766 | .init_key_from_rec = xfs_inobt_init_key_from_rec, | ||
1767 | .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, | ||
1768 | .key_diff = xfs_inobt_key_diff, | ||
1993 | 1769 | ||
1994 | #ifdef XFS_BTREE_TRACE | 1770 | #ifdef XFS_BTREE_TRACE |
1995 | .trace_enter = xfs_inobt_trace_enter, | 1771 | .trace_enter = xfs_inobt_trace_enter, |