aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_btree.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2008-10-30 01:56:43 -0400
committerLachlan McIlroy <lachlan@sgi.com>2008-10-30 01:56:43 -0400
commit9eaead51bed957af0070a277d945744a76df0c8b (patch)
tree7b0679186c06f366c7aed30873e3395bd414953e /fs/xfs/xfs_btree.c
parent278d0ca14e889c3932a05d1a68675252a12b3466 (diff)
[XFS] implement generic xfs_btree_rshift
Make the btree right 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:32196a 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.c319
1 files changed, 318 insertions, 1 deletions
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
index 205272f282d9..e1a213781849 100644
--- a/fs/xfs/xfs_btree.c
+++ b/fs/xfs/xfs_btree.c
@@ -1118,6 +1118,77 @@ xfs_btree_copy_recs(
1118} 1118}
1119 1119
1120/* 1120/*
1121 * Copy block pointers from one btree block to another.
1122 */
1123STATIC void
1124xfs_btree_copy_ptrs(
1125 struct xfs_btree_cur *cur,
1126 union xfs_btree_ptr *dst_ptr,
1127 union xfs_btree_ptr *src_ptr,
1128 int numptrs)
1129{
1130 ASSERT(numptrs >= 0);
1131 memcpy(dst_ptr, src_ptr, numptrs * xfs_btree_ptr_len(cur));
1132}
1133
1134/*
1135 * Shift keys one index left/right inside a single btree block.
1136 */
1137STATIC void
1138xfs_btree_shift_keys(
1139 struct xfs_btree_cur *cur,
1140 union xfs_btree_key *key,
1141 int dir,
1142 int numkeys)
1143{
1144 char *dst_key;
1145
1146 ASSERT(numkeys >= 0);
1147 ASSERT(dir == 1 || dir == -1);
1148
1149 dst_key = (char *)key + (dir * cur->bc_ops->key_len);
1150 memmove(dst_key, key, numkeys * cur->bc_ops->key_len);
1151}
1152
1153/*
1154 * Shift records one index left/right inside a single btree block.
1155 */
1156STATIC void
1157xfs_btree_shift_recs(
1158 struct xfs_btree_cur *cur,
1159 union xfs_btree_rec *rec,
1160 int dir,
1161 int numrecs)
1162{
1163 char *dst_rec;
1164
1165 ASSERT(numrecs >= 0);
1166 ASSERT(dir == 1 || dir == -1);
1167
1168 dst_rec = (char *)rec + (dir * cur->bc_ops->rec_len);
1169 memmove(dst_rec, rec, numrecs * cur->bc_ops->rec_len);
1170}
1171
1172/*
1173 * Shift block pointers one index left/right inside a single btree block.
1174 */
1175STATIC void
1176xfs_btree_shift_ptrs(
1177 struct xfs_btree_cur *cur,
1178 union xfs_btree_ptr *ptr,
1179 int dir,
1180 int numptrs)
1181{
1182 char *dst_ptr;
1183
1184 ASSERT(numptrs >= 0);
1185 ASSERT(dir == 1 || dir == -1);
1186
1187 dst_ptr = (char *)ptr + (dir * xfs_btree_ptr_len(cur));
1188 memmove(dst_ptr, ptr, numptrs * xfs_btree_ptr_len(cur));
1189}
1190
1191/*
1121 * Log key values from the btree block. 1192 * Log key values from the btree block.
1122 */ 1193 */
1123STATIC void 1194STATIC void
@@ -1163,6 +1234,79 @@ xfs_btree_log_recs(
1163} 1234}
1164 1235
1165/* 1236/*
1237 * Log block pointer fields from a btree block (nonleaf).
1238 */
1239STATIC void
1240xfs_btree_log_ptrs(
1241 struct xfs_btree_cur *cur, /* btree cursor */
1242 struct xfs_buf *bp, /* buffer containing btree block */
1243 int first, /* index of first pointer to log */
1244 int last) /* index of last pointer to log */
1245{
1246 XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
1247 XFS_BTREE_TRACE_ARGBII(cur, bp, first, last);
1248
1249 if (bp) {
1250 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
1251 int level = xfs_btree_get_level(block);
1252
1253 xfs_trans_log_buf(cur->bc_tp, bp,
1254 xfs_btree_ptr_offset(cur, first, level),
1255 xfs_btree_ptr_offset(cur, last + 1, level) - 1);
1256 } else {
1257 xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
1258 xfs_ilog_fbroot(cur->bc_private.b.whichfork));
1259 }
1260
1261 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
1262}
1263
1264/*
1265 * Log fields from a btree block header.
1266 */
1267STATIC void
1268xfs_btree_log_block(
1269 struct xfs_btree_cur *cur, /* btree cursor */
1270 struct xfs_buf *bp, /* buffer containing btree block */
1271 int fields) /* mask of fields: XFS_BB_... */
1272{
1273 int first; /* first byte offset logged */
1274 int last; /* last byte offset logged */
1275 static const short soffsets[] = { /* table of offsets (short) */
1276 offsetof(struct xfs_btree_sblock, bb_magic),
1277 offsetof(struct xfs_btree_sblock, bb_level),
1278 offsetof(struct xfs_btree_sblock, bb_numrecs),
1279 offsetof(struct xfs_btree_sblock, bb_leftsib),
1280 offsetof(struct xfs_btree_sblock, bb_rightsib),
1281 sizeof(struct xfs_btree_sblock)
1282 };
1283 static const short loffsets[] = { /* table of offsets (long) */
1284 offsetof(struct xfs_btree_lblock, bb_magic),
1285 offsetof(struct xfs_btree_lblock, bb_level),
1286 offsetof(struct xfs_btree_lblock, bb_numrecs),
1287 offsetof(struct xfs_btree_lblock, bb_leftsib),
1288 offsetof(struct xfs_btree_lblock, bb_rightsib),
1289 sizeof(struct xfs_btree_lblock)
1290 };
1291
1292 XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
1293 XFS_BTREE_TRACE_ARGBI(cur, bp, fields);
1294
1295 if (bp) {
1296 xfs_btree_offsets(fields,
1297 (cur->bc_flags & XFS_BTREE_LONG_PTRS) ?
1298 loffsets : soffsets,
1299 XFS_BB_NUM_BITS, &first, &last);
1300 xfs_trans_log_buf(cur->bc_tp, bp, first, last);
1301 } else {
1302 xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
1303 xfs_ilog_fbroot(cur->bc_private.b.whichfork));
1304 }
1305
1306 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
1307}
1308
1309/*
1166 * Increment cursor by one record at the level. 1310 * Increment cursor by one record at the level.
1167 * For nonzero levels the leaf-ward information is untouched. 1311 * For nonzero levels the leaf-ward information is untouched.
1168 */ 1312 */
@@ -1368,7 +1512,6 @@ error0:
1368 return error; 1512 return error;
1369} 1513}
1370 1514
1371
1372STATIC int 1515STATIC int
1373xfs_btree_lookup_get_block( 1516xfs_btree_lookup_get_block(
1374 struct xfs_btree_cur *cur, /* btree cursor */ 1517 struct xfs_btree_cur *cur, /* btree cursor */
@@ -1697,3 +1840,177 @@ error0:
1697 return error; 1840 return error;
1698} 1841}
1699 1842
1843/*
1844 * Move 1 record right from cur/level if possible.
1845 * Update cur to reflect the new path.
1846 */
1847int /* error */
1848xfs_btree_rshift(
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 struct xfs_buf *rbp; /* right buffer pointer */
1857 struct xfs_btree_block *right; /* right btree block */
1858 struct xfs_btree_cur *tcur; /* temporary btree cursor */
1859 union xfs_btree_ptr rptr; /* right block pointer */
1860 union xfs_btree_key *rkp; /* right btree key */
1861 int rrecs; /* right record count */
1862 int lrecs; /* left record count */
1863 int error; /* error return value */
1864 int i; /* loop counter */
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 "left". */
1874 left = xfs_btree_get_block(cur, level, &lbp);
1875
1876#ifdef DEBUG
1877 error = xfs_btree_check_block(cur, left, level, lbp);
1878 if (error)
1879 goto error0;
1880#endif
1881
1882 /* If we've got no right sibling then we can't shift an entry right. */
1883 xfs_btree_get_sibling(cur, left, &rptr, XFS_BB_RIGHTSIB);
1884 if (xfs_btree_ptr_is_null(cur, &rptr))
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 lrecs = xfs_btree_get_numrecs(left);
1892 if (cur->bc_ptrs[level] >= lrecs)
1893 goto out0;
1894
1895 /* Set up the right neighbor as "right". */
1896 error = xfs_btree_read_buf_block(cur, &rptr, level, 0, &right, &rbp);
1897 if (error)
1898 goto error0;
1899
1900 /* If it's full, it can't take another entry. */
1901 rrecs = xfs_btree_get_numrecs(right);
1902 if (rrecs == cur->bc_ops->get_maxrecs(cur, level))
1903 goto out0;
1904
1905 XFS_BTREE_STATS_INC(cur, rshift);
1906 XFS_BTREE_STATS_ADD(cur, moves, rrecs);
1907
1908 /*
1909 * Make a hole at the start of the right neighbor block, then
1910 * copy the last left block entry to the hole.
1911 */
1912 if (level > 0) {
1913 /* It's a nonleaf. make a hole in the keys and ptrs */
1914 union xfs_btree_key *lkp;
1915 union xfs_btree_ptr *lpp;
1916 union xfs_btree_ptr *rpp;
1917
1918 lkp = xfs_btree_key_addr(cur, lrecs, left);
1919 lpp = xfs_btree_ptr_addr(cur, lrecs, left);
1920 rkp = xfs_btree_key_addr(cur, 1, right);
1921 rpp = xfs_btree_ptr_addr(cur, 1, right);
1922
1923#ifdef DEBUG
1924 for (i = rrecs - 1; i >= 0; i--) {
1925 error = xfs_btree_check_ptr(cur, rpp, i, level);
1926 if (error)
1927 goto error0;
1928 }
1929#endif
1930
1931 xfs_btree_shift_keys(cur, rkp, 1, rrecs);
1932 xfs_btree_shift_ptrs(cur, rpp, 1, rrecs);
1933
1934#ifdef DEBUG
1935 error = xfs_btree_check_ptr(cur, lpp, 0, level);
1936 if (error)
1937 goto error0;
1938#endif
1939
1940 /* Now put the new data in, and log it. */
1941 xfs_btree_copy_keys(cur, rkp, lkp, 1);
1942 xfs_btree_copy_ptrs(cur, rpp, lpp, 1);
1943
1944 xfs_btree_log_keys(cur, rbp, 1, rrecs + 1);
1945 xfs_btree_log_ptrs(cur, rbp, 1, rrecs + 1);
1946
1947 xfs_btree_check_key(cur->bc_btnum, rkp,
1948 xfs_btree_key_addr(cur, 2, right));
1949 } else {
1950 /* It's a leaf. make a hole in the records */
1951 union xfs_btree_rec *lrp;
1952 union xfs_btree_rec *rrp;
1953
1954 lrp = xfs_btree_rec_addr(cur, lrecs, left);
1955 rrp = xfs_btree_rec_addr(cur, 1, right);
1956
1957 xfs_btree_shift_recs(cur, rrp, 1, rrecs);
1958
1959 /* Now put the new data in, and log it. */
1960 xfs_btree_copy_recs(cur, rrp, lrp, 1);
1961 xfs_btree_log_recs(cur, rbp, 1, rrecs + 1);
1962
1963 cur->bc_ops->init_key_from_rec(&key, rrp);
1964 rkp = &key;
1965
1966 xfs_btree_check_rec(cur->bc_btnum, rrp,
1967 xfs_btree_rec_addr(cur, 2, right));
1968 }
1969
1970 /*
1971 * Decrement and log left's numrecs, bump and log right's numrecs.
1972 */
1973 xfs_btree_set_numrecs(left, --lrecs);
1974 xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS);
1975
1976 xfs_btree_set_numrecs(right, ++rrecs);
1977 xfs_btree_log_block(cur, rbp, XFS_BB_NUMRECS);
1978
1979 /*
1980 * Using a temporary cursor, update the parent key values of the
1981 * block on the right.
1982 */
1983 error = xfs_btree_dup_cursor(cur, &tcur);
1984 if (error)
1985 goto error0;
1986 i = xfs_btree_lastrec(tcur, level);
1987 XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
1988
1989 error = xfs_btree_increment(tcur, level, &i);
1990 if (error)
1991 goto error1;
1992
1993 error = xfs_btree_updkey(tcur, rkp, level + 1);
1994 if (error)
1995 goto error1;
1996
1997 xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
1998
1999 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
2000 *stat = 1;
2001 return 0;
2002
2003out0:
2004 XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
2005 *stat = 0;
2006 return 0;
2007
2008error0:
2009 XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
2010 return error;
2011
2012error1:
2013 XFS_BTREE_TRACE_CURSOR(tcur, XBT_ERROR);
2014 xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
2015 return error;
2016}