diff options
author | Christoph Hellwig <hch@infradead.org> | 2008-10-30 01:56:53 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@sgi.com> | 2008-10-30 01:56:53 -0400 |
commit | 687b890a184fef263ebb773926e1f4aa69240d01 (patch) | |
tree | b8f80c134ff994927225367d148ee63f4d76506b /fs/xfs/xfs_btree.c | |
parent | 9eaead51bed957af0070a277d945744a76df0c8b (diff) |
[XFS] implement generic xfs_btree_lshift
Make the btree left shift code generic. Based on a patch from David
Chinner with lots of changes to follow the original btree implementations
more closely. While this loses some of the generic helper routines for
inserting/moving/removing records it also solves some of the one off bugs
in the original code and makes it easier to verify.
SGI-PV: 985583
SGI-Modid: xfs-linux-melb:xfs-kern:32197a
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_btree.c')
-rw-r--r-- | fs/xfs/xfs_btree.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index e1a213781849..2b0d1422c4c6 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
@@ -1841,6 +1841,191 @@ error0: | |||
1841 | } | 1841 | } |
1842 | 1842 | ||
1843 | /* | 1843 | /* |
1844 | * Move 1 record left from cur/level if possible. | ||
1845 | * Update cur to reflect the new path. | ||
1846 | */ | ||
1847 | int /* error */ | ||
1848 | xfs_btree_lshift( | ||
1849 | struct xfs_btree_cur *cur, | ||
1850 | int level, | ||
1851 | int *stat) /* success/failure */ | ||
1852 | { | ||
1853 | union xfs_btree_key key; /* btree key */ | ||
1854 | struct xfs_buf *lbp; /* left buffer pointer */ | ||
1855 | struct xfs_btree_block *left; /* left btree block */ | ||
1856 | int lrecs; /* left record count */ | ||
1857 | struct xfs_buf *rbp; /* right buffer pointer */ | ||
1858 | struct xfs_btree_block *right; /* right btree block */ | ||
1859 | int rrecs; /* right record count */ | ||
1860 | union xfs_btree_ptr lptr; /* left btree pointer */ | ||
1861 | union xfs_btree_key *rkp = NULL; /* right btree key */ | ||
1862 | union xfs_btree_ptr *rpp = NULL; /* right address pointer */ | ||
1863 | union xfs_btree_rec *rrp = NULL; /* right record pointer */ | ||
1864 | int error; /* error return value */ | ||
1865 | |||
1866 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); | ||
1867 | XFS_BTREE_TRACE_ARGI(cur, level); | ||
1868 | |||
1869 | if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && | ||
1870 | level == cur->bc_nlevels - 1) | ||
1871 | goto out0; | ||
1872 | |||
1873 | /* Set up variables for this block as "right". */ | ||
1874 | right = xfs_btree_get_block(cur, level, &rbp); | ||
1875 | |||
1876 | #ifdef DEBUG | ||
1877 | error = xfs_btree_check_block(cur, right, level, rbp); | ||
1878 | if (error) | ||
1879 | goto error0; | ||
1880 | #endif | ||
1881 | |||
1882 | /* If we've got no left sibling then we can't shift an entry left. */ | ||
1883 | xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); | ||
1884 | if (xfs_btree_ptr_is_null(cur, &lptr)) | ||
1885 | goto out0; | ||
1886 | |||
1887 | /* | ||
1888 | * If the cursor entry is the one that would be moved, don't | ||
1889 | * do it... it's too complicated. | ||
1890 | */ | ||
1891 | if (cur->bc_ptrs[level] <= 1) | ||
1892 | goto out0; | ||
1893 | |||
1894 | /* Set up the left neighbor as "left". */ | ||
1895 | error = xfs_btree_read_buf_block(cur, &lptr, level, 0, &left, &lbp); | ||
1896 | if (error) | ||
1897 | goto error0; | ||
1898 | |||
1899 | /* If it's full, it can't take another entry. */ | ||
1900 | lrecs = xfs_btree_get_numrecs(left); | ||
1901 | if (lrecs == cur->bc_ops->get_maxrecs(cur, level)) | ||
1902 | goto out0; | ||
1903 | |||
1904 | rrecs = xfs_btree_get_numrecs(right); | ||
1905 | |||
1906 | /* | ||
1907 | * We add one entry to the left side and remove one for the right side. | ||
1908 | * Accout for it here, the changes will be updated on disk and logged | ||
1909 | * later. | ||
1910 | */ | ||
1911 | lrecs++; | ||
1912 | rrecs--; | ||
1913 | |||
1914 | XFS_BTREE_STATS_INC(cur, lshift); | ||
1915 | XFS_BTREE_STATS_ADD(cur, moves, 1); | ||
1916 | |||
1917 | /* | ||
1918 | * If non-leaf, copy a key and a ptr to the left block. | ||
1919 | * Log the changes to the left block. | ||
1920 | */ | ||
1921 | if (level > 0) { | ||
1922 | /* It's a non-leaf. Move keys and pointers. */ | ||
1923 | union xfs_btree_key *lkp; /* left btree key */ | ||
1924 | union xfs_btree_ptr *lpp; /* left address pointer */ | ||
1925 | |||
1926 | lkp = xfs_btree_key_addr(cur, lrecs, left); | ||
1927 | rkp = xfs_btree_key_addr(cur, 1, right); | ||
1928 | |||
1929 | lpp = xfs_btree_ptr_addr(cur, lrecs, left); | ||
1930 | rpp = xfs_btree_ptr_addr(cur, 1, right); | ||
1931 | #ifdef DEBUG | ||
1932 | error = xfs_btree_check_ptr(cur, rpp, 0, level); | ||
1933 | if (error) | ||
1934 | goto error0; | ||
1935 | #endif | ||
1936 | xfs_btree_copy_keys(cur, lkp, rkp, 1); | ||
1937 | xfs_btree_copy_ptrs(cur, lpp, rpp, 1); | ||
1938 | |||
1939 | xfs_btree_log_keys(cur, lbp, lrecs, lrecs); | ||
1940 | xfs_btree_log_ptrs(cur, lbp, lrecs, lrecs); | ||
1941 | |||
1942 | xfs_btree_check_key(cur->bc_btnum, | ||
1943 | xfs_btree_key_addr(cur, lrecs - 1, left), | ||
1944 | lkp); | ||
1945 | } else { | ||
1946 | /* It's a leaf. Move records. */ | ||
1947 | union xfs_btree_rec *lrp; /* left record pointer */ | ||
1948 | |||
1949 | lrp = xfs_btree_rec_addr(cur, lrecs, left); | ||
1950 | rrp = xfs_btree_rec_addr(cur, 1, right); | ||
1951 | |||
1952 | xfs_btree_copy_recs(cur, lrp, rrp, 1); | ||
1953 | xfs_btree_log_recs(cur, lbp, lrecs, lrecs); | ||
1954 | |||
1955 | xfs_btree_check_rec(cur->bc_btnum, | ||
1956 | xfs_btree_rec_addr(cur, lrecs - 1, left), | ||
1957 | lrp); | ||
1958 | } | ||
1959 | |||
1960 | xfs_btree_set_numrecs(left, lrecs); | ||
1961 | xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS); | ||
1962 | |||
1963 | xfs_btree_set_numrecs(right, rrecs); | ||
1964 | xfs_btree_log_block(cur, rbp, XFS_BB_NUMRECS); | ||
1965 | |||
1966 | /* | ||
1967 | * Slide the contents of right down one entry. | ||
1968 | */ | ||
1969 | XFS_BTREE_STATS_ADD(cur, moves, rrecs - 1); | ||
1970 | if (level > 0) { | ||
1971 | /* It's a nonleaf. operate on keys and ptrs */ | ||
1972 | #ifdef DEBUG | ||
1973 | int i; /* loop index */ | ||
1974 | |||
1975 | for (i = 0; i < rrecs; i++) { | ||
1976 | error = xfs_btree_check_ptr(cur, rpp, i + 1, level); | ||
1977 | if (error) | ||
1978 | goto error0; | ||
1979 | } | ||
1980 | #endif | ||
1981 | xfs_btree_shift_keys(cur, | ||
1982 | xfs_btree_key_addr(cur, 2, right), | ||
1983 | -1, rrecs); | ||
1984 | xfs_btree_shift_ptrs(cur, | ||
1985 | xfs_btree_ptr_addr(cur, 2, right), | ||
1986 | -1, rrecs); | ||
1987 | |||
1988 | xfs_btree_log_keys(cur, rbp, 1, rrecs); | ||
1989 | xfs_btree_log_ptrs(cur, rbp, 1, rrecs); | ||
1990 | } else { | ||
1991 | /* It's a leaf. operate on records */ | ||
1992 | xfs_btree_shift_recs(cur, | ||
1993 | xfs_btree_rec_addr(cur, 2, right), | ||
1994 | -1, rrecs); | ||
1995 | xfs_btree_log_recs(cur, rbp, 1, rrecs); | ||
1996 | |||
1997 | /* | ||
1998 | * If it's the first record in the block, we'll need a key | ||
1999 | * structure to pass up to the next level (updkey). | ||
2000 | */ | ||
2001 | cur->bc_ops->init_key_from_rec(&key, | ||
2002 | xfs_btree_rec_addr(cur, 1, right)); | ||
2003 | rkp = &key; | ||
2004 | } | ||
2005 | |||
2006 | /* Update the parent key values of right. */ | ||
2007 | error = xfs_btree_updkey(cur, rkp, level + 1); | ||
2008 | if (error) | ||
2009 | goto error0; | ||
2010 | |||
2011 | /* Slide the cursor value left one. */ | ||
2012 | cur->bc_ptrs[level]--; | ||
2013 | |||
2014 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
2015 | *stat = 1; | ||
2016 | return 0; | ||
2017 | |||
2018 | out0: | ||
2019 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
2020 | *stat = 0; | ||
2021 | return 0; | ||
2022 | |||
2023 | error0: | ||
2024 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | ||
2025 | return error; | ||
2026 | } | ||
2027 | |||
2028 | /* | ||
1844 | * Move 1 record right from cur/level if possible. | 2029 | * Move 1 record right from cur/level if possible. |
1845 | * Update cur to reflect the new path. | 2030 | * Update cur to reflect the new path. |
1846 | */ | 2031 | */ |