diff options
author | Christoph Hellwig <hch@infradead.org> | 2008-10-30 01:56:32 -0400 |
---|---|---|
committer | Lachlan McIlroy <lachlan@sgi.com> | 2008-10-30 01:56:32 -0400 |
commit | 278d0ca14e889c3932a05d1a68675252a12b3466 (patch) | |
tree | a228d171d4aded60b27639e30eca1bf58ed7daa6 /fs | |
parent | 38bb74237d2d94c1aced2ec626d7d0f317e360da (diff) |
[XFS] implement generic xfs_btree_update
From: Dave Chinner <dgc@sgi.com>
The most complicated part here is the lastrec tracking for the alloc
btree. Most logic is in the update_lastrec method which has to do some
hopefully good enough dirty magic to maintain it.
[hch: split out from bigger patch and a rework of the lastrec
logic]
SGI-PV: 985583
SGI-Modid: xfs-linux-melb:xfs-kern:32194a
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')
-rw-r--r-- | fs/xfs/xfs_alloc.c | 17 | ||||
-rw-r--r-- | fs/xfs/xfs_alloc_btree.c | 106 | ||||
-rw-r--r-- | fs/xfs/xfs_alloc_btree.h | 7 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap.c | 18 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_btree.c | 45 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_btree.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_btree.c | 121 | ||||
-rw-r--r-- | fs/xfs/xfs_btree.h | 14 | ||||
-rw-r--r-- | fs/xfs/xfs_ialloc.c | 20 | ||||
-rw-r--r-- | fs/xfs/xfs_ialloc_btree.c | 52 | ||||
-rw-r--r-- | fs/xfs/xfs_ialloc_btree.h | 8 |
11 files changed, 228 insertions, 182 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 6bda0ae26c2a..875e1bae1941 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
@@ -136,6 +136,23 @@ xfs_alloc_lookup_le( | |||
136 | return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); | 136 | return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); |
137 | } | 137 | } |
138 | 138 | ||
139 | /* | ||
140 | * Update the record referred to by cur to the value given | ||
141 | * by [bno, len]. | ||
142 | * This either works (return 0) or gets an EFSCORRUPTED error. | ||
143 | */ | ||
144 | STATIC int /* error */ | ||
145 | xfs_alloc_update( | ||
146 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
147 | xfs_agblock_t bno, /* starting block of extent */ | ||
148 | xfs_extlen_t len) /* length of extent */ | ||
149 | { | ||
150 | union xfs_btree_rec rec; | ||
151 | |||
152 | rec.alloc.ar_startblock = cpu_to_be32(bno); | ||
153 | rec.alloc.ar_blockcount = cpu_to_be32(len); | ||
154 | return xfs_btree_update(cur, &rec); | ||
155 | } | ||
139 | 156 | ||
140 | /* | 157 | /* |
141 | * Compute aligned version of the found extent. | 158 | * Compute aligned version of the found extent. |
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index 28c6a698f562..c5c32999b810 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c | |||
@@ -1661,83 +1661,50 @@ xfs_alloc_insert( | |||
1661 | return 0; | 1661 | return 0; |
1662 | } | 1662 | } |
1663 | 1663 | ||
1664 | STATIC struct xfs_btree_cur * | ||
1665 | xfs_allocbt_dup_cursor( | ||
1666 | struct xfs_btree_cur *cur) | ||
1667 | { | ||
1668 | return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp, | ||
1669 | cur->bc_private.a.agbp, cur->bc_private.a.agno, | ||
1670 | cur->bc_btnum); | ||
1671 | } | ||
1672 | |||
1664 | /* | 1673 | /* |
1665 | * Update the record referred to by cur, to the value given by [bno, len]. | 1674 | * Update the longest extent in the AGF |
1666 | * This either works (return 0) or gets an EFSCORRUPTED error. | ||
1667 | */ | 1675 | */ |
1668 | int /* error */ | 1676 | STATIC void |
1669 | xfs_alloc_update( | 1677 | xfs_allocbt_update_lastrec( |
1670 | xfs_btree_cur_t *cur, /* btree cursor */ | 1678 | struct xfs_btree_cur *cur, |
1671 | xfs_agblock_t bno, /* starting block of extent */ | 1679 | struct xfs_btree_block *block, |
1672 | xfs_extlen_t len) /* length of extent */ | 1680 | union xfs_btree_rec *rec, |
1681 | int ptr, | ||
1682 | int reason) | ||
1673 | { | 1683 | { |
1674 | xfs_alloc_block_t *block; /* btree block to update */ | 1684 | struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); |
1675 | int error; /* error return value */ | 1685 | xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); |
1676 | int ptr; /* current record number (updating) */ | 1686 | __be32 len; |
1677 | 1687 | ||
1678 | ASSERT(len > 0); | 1688 | ASSERT(cur->bc_btnum == XFS_BTNUM_CNT); |
1679 | /* | ||
1680 | * Pick up the a.g. freelist struct and the current block. | ||
1681 | */ | ||
1682 | block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[0]); | ||
1683 | #ifdef DEBUG | ||
1684 | if ((error = xfs_btree_check_sblock(cur, block, 0, cur->bc_bufs[0]))) | ||
1685 | return error; | ||
1686 | #endif | ||
1687 | /* | ||
1688 | * Get the address of the rec to be updated. | ||
1689 | */ | ||
1690 | ptr = cur->bc_ptrs[0]; | ||
1691 | { | ||
1692 | xfs_alloc_rec_t *rp; /* pointer to updated record */ | ||
1693 | 1689 | ||
1694 | rp = XFS_ALLOC_REC_ADDR(block, ptr, cur); | 1690 | switch (reason) { |
1691 | case LASTREC_UPDATE: | ||
1695 | /* | 1692 | /* |
1696 | * Fill in the new contents and log them. | 1693 | * If this is the last leaf block and it's the last record, |
1694 | * then update the size of the longest extent in the AG. | ||
1697 | */ | 1695 | */ |
1698 | rp->ar_startblock = cpu_to_be32(bno); | 1696 | if (ptr != xfs_btree_get_numrecs(block)) |
1699 | rp->ar_blockcount = cpu_to_be32(len); | 1697 | return; |
1700 | xfs_alloc_log_recs(cur, cur->bc_bufs[0], ptr, ptr); | 1698 | len = rec->alloc.ar_blockcount; |
1701 | } | 1699 | break; |
1702 | /* | 1700 | default: |
1703 | * If it's the by-size btree and it's the last leaf block and | 1701 | ASSERT(0); |
1704 | * it's the last record... then update the size of the longest | 1702 | return; |
1705 | * extent in the a.g., which we cache in the a.g. freelist header. | ||
1706 | */ | ||
1707 | if (cur->bc_btnum == XFS_BTNUM_CNT && | ||
1708 | be32_to_cpu(block->bb_rightsib) == NULLAGBLOCK && | ||
1709 | ptr == be16_to_cpu(block->bb_numrecs)) { | ||
1710 | xfs_agf_t *agf; /* a.g. freespace header */ | ||
1711 | xfs_agnumber_t seqno; | ||
1712 | |||
1713 | agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); | ||
1714 | seqno = be32_to_cpu(agf->agf_seqno); | ||
1715 | cur->bc_mp->m_perag[seqno].pagf_longest = len; | ||
1716 | agf->agf_longest = cpu_to_be32(len); | ||
1717 | xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, | ||
1718 | XFS_AGF_LONGEST); | ||
1719 | } | ||
1720 | /* | ||
1721 | * Updating first record in leaf. Pass new key value up to our parent. | ||
1722 | */ | ||
1723 | if (ptr == 1) { | ||
1724 | xfs_alloc_key_t key; /* key containing [bno, len] */ | ||
1725 | |||
1726 | key.ar_startblock = cpu_to_be32(bno); | ||
1727 | key.ar_blockcount = cpu_to_be32(len); | ||
1728 | if ((error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, 1))) | ||
1729 | return error; | ||
1730 | } | 1703 | } |
1731 | return 0; | ||
1732 | } | ||
1733 | 1704 | ||
1734 | STATIC struct xfs_btree_cur * | 1705 | agf->agf_longest = len; |
1735 | xfs_allocbt_dup_cursor( | 1706 | cur->bc_mp->m_perag[seqno].pagf_longest = be32_to_cpu(len); |
1736 | struct xfs_btree_cur *cur) | 1707 | xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, XFS_AGF_LONGEST); |
1737 | { | ||
1738 | return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp, | ||
1739 | cur->bc_private.a.agbp, cur->bc_private.a.agno, | ||
1740 | cur->bc_btnum); | ||
1741 | } | 1708 | } |
1742 | 1709 | ||
1743 | STATIC int | 1710 | STATIC int |
@@ -1864,6 +1831,7 @@ static const struct xfs_btree_ops xfs_allocbt_ops = { | |||
1864 | .key_len = sizeof(xfs_alloc_key_t), | 1831 | .key_len = sizeof(xfs_alloc_key_t), |
1865 | 1832 | ||
1866 | .dup_cursor = xfs_allocbt_dup_cursor, | 1833 | .dup_cursor = xfs_allocbt_dup_cursor, |
1834 | .update_lastrec = xfs_allocbt_update_lastrec, | ||
1867 | .get_maxrecs = xfs_allocbt_get_maxrecs, | 1835 | .get_maxrecs = xfs_allocbt_get_maxrecs, |
1868 | .init_key_from_rec = xfs_allocbt_init_key_from_rec, | 1836 | .init_key_from_rec = xfs_allocbt_init_key_from_rec, |
1869 | .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, | 1837 | .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, |
@@ -1902,6 +1870,8 @@ xfs_allocbt_init_cursor( | |||
1902 | cur->bc_blocklog = mp->m_sb.sb_blocklog; | 1870 | cur->bc_blocklog = mp->m_sb.sb_blocklog; |
1903 | 1871 | ||
1904 | cur->bc_ops = &xfs_allocbt_ops; | 1872 | cur->bc_ops = &xfs_allocbt_ops; |
1873 | if (btnum == XFS_BTNUM_CNT) | ||
1874 | cur->bc_flags = XFS_BTREE_LASTREC_UPDATE; | ||
1905 | 1875 | ||
1906 | cur->bc_private.a.agbp = agbp; | 1876 | cur->bc_private.a.agbp = agbp; |
1907 | cur->bc_private.a.agno = agno; | 1877 | cur->bc_private.a.agno = agno; |
diff --git a/fs/xfs/xfs_alloc_btree.h b/fs/xfs/xfs_alloc_btree.h index aa110ff4feb1..81e2f3607819 100644 --- a/fs/xfs/xfs_alloc_btree.h +++ b/fs/xfs/xfs_alloc_btree.h | |||
@@ -113,13 +113,6 @@ extern int xfs_alloc_get_rec(struct xfs_btree_cur *cur, xfs_agblock_t *bno, | |||
113 | */ | 113 | */ |
114 | extern int xfs_alloc_insert(struct xfs_btree_cur *cur, int *stat); | 114 | extern int xfs_alloc_insert(struct xfs_btree_cur *cur, int *stat); |
115 | 115 | ||
116 | /* | ||
117 | * Update the record referred to by cur, to the value given by [bno, len]. | ||
118 | * This either works (return 0) or gets an EFSCORRUPTED error. | ||
119 | */ | ||
120 | extern int xfs_alloc_update(struct xfs_btree_cur *cur, xfs_agblock_t bno, | ||
121 | xfs_extlen_t len); | ||
122 | |||
123 | 116 | ||
124 | extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *, | 117 | extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *, |
125 | struct xfs_trans *, struct xfs_buf *, | 118 | struct xfs_trans *, struct xfs_buf *, |
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 1296b4102e97..7d6c4ace8052 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -430,6 +430,24 @@ xfs_bmbt_lookup_ge( | |||
430 | return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); | 430 | return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); |
431 | } | 431 | } |
432 | 432 | ||
433 | /* | ||
434 | * Update the record referred to by cur to the value given | ||
435 | * by [off, bno, len, state]. | ||
436 | * This either works (return 0) or gets an EFSCORRUPTED error. | ||
437 | */ | ||
438 | STATIC int | ||
439 | xfs_bmbt_update( | ||
440 | struct xfs_btree_cur *cur, | ||
441 | xfs_fileoff_t off, | ||
442 | xfs_fsblock_t bno, | ||
443 | xfs_filblks_t len, | ||
444 | xfs_exntst_t state) | ||
445 | { | ||
446 | union xfs_btree_rec rec; | ||
447 | |||
448 | xfs_bmbt_disk_set_allf(&rec.bmbt, off, bno, len, state); | ||
449 | return xfs_btree_update(cur, &rec); | ||
450 | } | ||
433 | 451 | ||
434 | /* | 452 | /* |
435 | * Called from xfs_bmap_add_attrfork to handle btree format files. | 453 | * Called from xfs_bmap_add_attrfork to handle btree format files. |
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 0a56257b7fd5..99200a9898f7 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
@@ -1964,51 +1964,6 @@ xfs_bmbt_to_bmdr( | |||
1964 | } | 1964 | } |
1965 | 1965 | ||
1966 | /* | 1966 | /* |
1967 | * Update the record to the passed values. | ||
1968 | */ | ||
1969 | int | ||
1970 | xfs_bmbt_update( | ||
1971 | xfs_btree_cur_t *cur, | ||
1972 | xfs_fileoff_t off, | ||
1973 | xfs_fsblock_t bno, | ||
1974 | xfs_filblks_t len, | ||
1975 | xfs_exntst_t state) | ||
1976 | { | ||
1977 | xfs_bmbt_block_t *block; | ||
1978 | xfs_buf_t *bp; | ||
1979 | int error; | ||
1980 | xfs_bmbt_key_t key; | ||
1981 | int ptr; | ||
1982 | xfs_bmbt_rec_t *rp; | ||
1983 | |||
1984 | XFS_BMBT_TRACE_CURSOR(cur, ENTRY); | ||
1985 | XFS_BMBT_TRACE_ARGFFFI(cur, (xfs_dfiloff_t)off, (xfs_dfsbno_t)bno, | ||
1986 | (xfs_dfilblks_t)len, (int)state); | ||
1987 | block = xfs_bmbt_get_block(cur, 0, &bp); | ||
1988 | #ifdef DEBUG | ||
1989 | if ((error = xfs_btree_check_lblock(cur, block, 0, bp))) { | ||
1990 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
1991 | return error; | ||
1992 | } | ||
1993 | #endif | ||
1994 | ptr = cur->bc_ptrs[0]; | ||
1995 | rp = XFS_BMAP_REC_IADDR(block, ptr, cur); | ||
1996 | xfs_bmbt_disk_set_allf(rp, off, bno, len, state); | ||
1997 | xfs_bmbt_log_recs(cur, bp, ptr, ptr); | ||
1998 | if (ptr > 1) { | ||
1999 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | ||
2000 | return 0; | ||
2001 | } | ||
2002 | key.br_startoff = cpu_to_be64(off); | ||
2003 | if ((error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, 1))) { | ||
2004 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
2005 | return error; | ||
2006 | } | ||
2007 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | ||
2008 | return 0; | ||
2009 | } | ||
2010 | |||
2011 | /* | ||
2012 | * Check extent records, which have just been read, for | 1967 | * Check extent records, which have just been read, for |
2013 | * any bit in the extent flag field. ASSERT on debug | 1968 | * any bit in the extent flag field. ASSERT on debug |
2014 | * kernels, as this condition should not occur. | 1969 | * kernels, as this condition should not occur. |
diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index d04198cdc4b3..6bfd62ec54fb 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h | |||
@@ -274,8 +274,6 @@ extern void xfs_bmbt_disk_set_allf(xfs_bmbt_rec_t *r, xfs_fileoff_t o, | |||
274 | xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v); | 274 | xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v); |
275 | 275 | ||
276 | extern void xfs_bmbt_to_bmdr(xfs_bmbt_block_t *, int, xfs_bmdr_block_t *, int); | 276 | extern void xfs_bmbt_to_bmdr(xfs_bmbt_block_t *, int, xfs_bmdr_block_t *, int); |
277 | extern int xfs_bmbt_update(struct xfs_btree_cur *, xfs_fileoff_t, | ||
278 | xfs_fsblock_t, xfs_filblks_t, xfs_exntst_t); | ||
279 | 277 | ||
280 | extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *, | 278 | extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *, |
281 | struct xfs_trans *, struct xfs_inode *, int); | 279 | struct xfs_trans *, struct xfs_inode *, int); |
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 1459a2b9a729..205272f282d9 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
@@ -988,6 +988,30 @@ xfs_btree_get_sibling( | |||
988 | } | 988 | } |
989 | } | 989 | } |
990 | 990 | ||
991 | /* | ||
992 | * Return true if ptr is the last record in the btree and | ||
993 | * we need to track updateѕ to this record. The decision | ||
994 | * will be further refined in the update_lastrec method. | ||
995 | */ | ||
996 | STATIC int | ||
997 | xfs_btree_is_lastrec( | ||
998 | struct xfs_btree_cur *cur, | ||
999 | struct xfs_btree_block *block, | ||
1000 | int level) | ||
1001 | { | ||
1002 | union xfs_btree_ptr ptr; | ||
1003 | |||
1004 | if (level > 0) | ||
1005 | return 0; | ||
1006 | if (!(cur->bc_flags & XFS_BTREE_LASTREC_UPDATE)) | ||
1007 | return 0; | ||
1008 | |||
1009 | xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); | ||
1010 | if (!xfs_btree_ptr_is_null(cur, &ptr)) | ||
1011 | return 0; | ||
1012 | return 1; | ||
1013 | } | ||
1014 | |||
991 | STATIC xfs_daddr_t | 1015 | STATIC xfs_daddr_t |
992 | xfs_btree_ptr_to_daddr( | 1016 | xfs_btree_ptr_to_daddr( |
993 | struct xfs_btree_cur *cur, | 1017 | struct xfs_btree_cur *cur, |
@@ -1080,6 +1104,20 @@ xfs_btree_copy_keys( | |||
1080 | } | 1104 | } |
1081 | 1105 | ||
1082 | /* | 1106 | /* |
1107 | * Copy records from one btree block to another. | ||
1108 | */ | ||
1109 | STATIC void | ||
1110 | xfs_btree_copy_recs( | ||
1111 | struct xfs_btree_cur *cur, | ||
1112 | union xfs_btree_rec *dst_rec, | ||
1113 | union xfs_btree_rec *src_rec, | ||
1114 | int numrecs) | ||
1115 | { | ||
1116 | ASSERT(numrecs >= 0); | ||
1117 | memcpy(dst_rec, src_rec, numrecs * cur->bc_ops->rec_len); | ||
1118 | } | ||
1119 | |||
1120 | /* | ||
1083 | * Log key values from the btree block. | 1121 | * Log key values from the btree block. |
1084 | */ | 1122 | */ |
1085 | STATIC void | 1123 | STATIC void |
@@ -1105,6 +1143,26 @@ xfs_btree_log_keys( | |||
1105 | } | 1143 | } |
1106 | 1144 | ||
1107 | /* | 1145 | /* |
1146 | * Log record values from the btree block. | ||
1147 | */ | ||
1148 | STATIC void | ||
1149 | xfs_btree_log_recs( | ||
1150 | struct xfs_btree_cur *cur, | ||
1151 | struct xfs_buf *bp, | ||
1152 | int first, | ||
1153 | int last) | ||
1154 | { | ||
1155 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); | ||
1156 | XFS_BTREE_TRACE_ARGBII(cur, bp, first, last); | ||
1157 | |||
1158 | xfs_trans_log_buf(cur->bc_tp, bp, | ||
1159 | xfs_btree_rec_offset(cur, first), | ||
1160 | xfs_btree_rec_offset(cur, last + 1) - 1); | ||
1161 | |||
1162 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
1163 | } | ||
1164 | |||
1165 | /* | ||
1108 | * Increment cursor by one record at the level. | 1166 | * Increment cursor by one record at the level. |
1109 | * For nonzero levels the leaf-ward information is untouched. | 1167 | * For nonzero levels the leaf-ward information is untouched. |
1110 | */ | 1168 | */ |
@@ -1576,3 +1634,66 @@ xfs_btree_updkey( | |||
1576 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | 1634 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); |
1577 | return 0; | 1635 | return 0; |
1578 | } | 1636 | } |
1637 | |||
1638 | /* | ||
1639 | * Update the record referred to by cur to the value in the | ||
1640 | * given record. This either works (return 0) or gets an | ||
1641 | * EFSCORRUPTED error. | ||
1642 | */ | ||
1643 | int | ||
1644 | xfs_btree_update( | ||
1645 | struct xfs_btree_cur *cur, | ||
1646 | union xfs_btree_rec *rec) | ||
1647 | { | ||
1648 | struct xfs_btree_block *block; | ||
1649 | struct xfs_buf *bp; | ||
1650 | int error; | ||
1651 | int ptr; | ||
1652 | union xfs_btree_rec *rp; | ||
1653 | |||
1654 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); | ||
1655 | XFS_BTREE_TRACE_ARGR(cur, rec); | ||
1656 | |||
1657 | /* Pick up the current block. */ | ||
1658 | block = xfs_btree_get_block(cur, 0, &bp); | ||
1659 | |||
1660 | #ifdef DEBUG | ||
1661 | error = xfs_btree_check_block(cur, block, 0, bp); | ||
1662 | if (error) | ||
1663 | goto error0; | ||
1664 | #endif | ||
1665 | /* Get the address of the rec to be updated. */ | ||
1666 | ptr = cur->bc_ptrs[0]; | ||
1667 | rp = xfs_btree_rec_addr(cur, ptr, block); | ||
1668 | |||
1669 | /* Fill in the new contents and log them. */ | ||
1670 | xfs_btree_copy_recs(cur, rp, rec, 1); | ||
1671 | xfs_btree_log_recs(cur, bp, ptr, ptr); | ||
1672 | |||
1673 | /* | ||
1674 | * If we are tracking the last record in the tree and | ||
1675 | * we are at the far right edge of the tree, update it. | ||
1676 | */ | ||
1677 | if (xfs_btree_is_lastrec(cur, block, 0)) { | ||
1678 | cur->bc_ops->update_lastrec(cur, block, rec, | ||
1679 | ptr, LASTREC_UPDATE); | ||
1680 | } | ||
1681 | |||
1682 | /* Updating first rec in leaf. Pass new key value up to our parent. */ | ||
1683 | if (ptr == 1) { | ||
1684 | union xfs_btree_key key; | ||
1685 | |||
1686 | cur->bc_ops->init_key_from_rec(&key, rec); | ||
1687 | error = xfs_btree_updkey(cur, &key, 1); | ||
1688 | if (error) | ||
1689 | goto error0; | ||
1690 | } | ||
1691 | |||
1692 | XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); | ||
1693 | return 0; | ||
1694 | |||
1695 | error0: | ||
1696 | XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); | ||
1697 | return error; | ||
1698 | } | ||
1699 | |||
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index ac3f527b0ac4..c3bfa5556c19 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h | |||
@@ -187,6 +187,12 @@ struct xfs_btree_ops { | |||
187 | /* cursor operations */ | 187 | /* cursor operations */ |
188 | struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *); | 188 | struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *); |
189 | 189 | ||
190 | /* update last record information */ | ||
191 | void (*update_lastrec)(struct xfs_btree_cur *cur, | ||
192 | struct xfs_btree_block *block, | ||
193 | union xfs_btree_rec *rec, | ||
194 | int ptr, int reason); | ||
195 | |||
190 | /* records in block/level */ | 196 | /* records in block/level */ |
191 | int (*get_maxrecs)(struct xfs_btree_cur *cur, int level); | 197 | int (*get_maxrecs)(struct xfs_btree_cur *cur, int level); |
192 | 198 | ||
@@ -221,6 +227,12 @@ struct xfs_btree_ops { | |||
221 | }; | 227 | }; |
222 | 228 | ||
223 | /* | 229 | /* |
230 | * Reasons for the update_lastrec method to be called. | ||
231 | */ | ||
232 | #define LASTREC_UPDATE 0 | ||
233 | |||
234 | |||
235 | /* | ||
224 | * Btree cursor structure. | 236 | * Btree cursor structure. |
225 | * This collects all information needed by the btree code in one place. | 237 | * This collects all information needed by the btree code in one place. |
226 | */ | 238 | */ |
@@ -264,6 +276,7 @@ typedef struct xfs_btree_cur | |||
264 | /* cursor flags */ | 276 | /* cursor flags */ |
265 | #define XFS_BTREE_LONG_PTRS (1<<0) /* pointers are 64bits long */ | 277 | #define XFS_BTREE_LONG_PTRS (1<<0) /* pointers are 64bits long */ |
266 | #define XFS_BTREE_ROOT_IN_INODE (1<<1) /* root may be variable size */ | 278 | #define XFS_BTREE_ROOT_IN_INODE (1<<1) /* root may be variable size */ |
279 | #define XFS_BTREE_LASTREC_UPDATE (1<<2) /* track last rec externally */ | ||
267 | 280 | ||
268 | 281 | ||
269 | #define XFS_BTREE_NOERROR 0 | 282 | #define XFS_BTREE_NOERROR 0 |
@@ -519,6 +532,7 @@ int xfs_btree_increment(struct xfs_btree_cur *, int, int *); | |||
519 | int xfs_btree_decrement(struct xfs_btree_cur *, int, int *); | 532 | int xfs_btree_decrement(struct xfs_btree_cur *, int, int *); |
520 | int xfs_btree_lookup(struct xfs_btree_cur *, xfs_lookup_t, int *); | 533 | int xfs_btree_lookup(struct xfs_btree_cur *, xfs_lookup_t, int *); |
521 | int xfs_btree_updkey(struct xfs_btree_cur *, union xfs_btree_key *, int); | 534 | int xfs_btree_updkey(struct xfs_btree_cur *, union xfs_btree_key *, int); |
535 | int xfs_btree_update(struct xfs_btree_cur *, union xfs_btree_rec *); | ||
522 | 536 | ||
523 | /* | 537 | /* |
524 | * Helpers. | 538 | * Helpers. |
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index bbf537f64c41..138651afd44f 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
@@ -172,6 +172,26 @@ xfs_inobt_lookup_le( | |||
172 | } | 172 | } |
173 | 173 | ||
174 | /* | 174 | /* |
175 | * Update the record referred to by cur to the value given | ||
176 | * by [ino, fcnt, free]. | ||
177 | * This either works (return 0) or gets an EFSCORRUPTED error. | ||
178 | */ | ||
179 | STATIC int /* error */ | ||
180 | xfs_inobt_update( | ||
181 | struct xfs_btree_cur *cur, /* btree cursor */ | ||
182 | xfs_agino_t ino, /* starting inode of chunk */ | ||
183 | __int32_t fcnt, /* free inode count */ | ||
184 | xfs_inofree_t free) /* free inode mask */ | ||
185 | { | ||
186 | union xfs_btree_rec rec; | ||
187 | |||
188 | rec.inobt.ir_startino = cpu_to_be32(ino); | ||
189 | rec.inobt.ir_freecount = cpu_to_be32(fcnt); | ||
190 | rec.inobt.ir_free = cpu_to_be64(free); | ||
191 | return xfs_btree_update(cur, &rec); | ||
192 | } | ||
193 | |||
194 | /* | ||
175 | * Allocate new inodes in the allocation group specified by agbp. | 195 | * Allocate new inodes in the allocation group specified by agbp. |
176 | * Return 0 for success, else error code. | 196 | * Return 0 for success, else error code. |
177 | */ | 197 | */ |
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c index cd8bb519cb5f..d080a6833a8d 100644 --- a/fs/xfs/xfs_ialloc_btree.c +++ b/fs/xfs/xfs_ialloc_btree.c | |||
@@ -1551,58 +1551,6 @@ xfs_inobt_insert( | |||
1551 | return 0; | 1551 | return 0; |
1552 | } | 1552 | } |
1553 | 1553 | ||
1554 | /* | ||
1555 | * Update the record referred to by cur, to the value given | ||
1556 | * by [ino, fcnt, free]. | ||
1557 | * This either works (return 0) or gets an EFSCORRUPTED error. | ||
1558 | */ | ||
1559 | int /* error */ | ||
1560 | xfs_inobt_update( | ||
1561 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
1562 | xfs_agino_t ino, /* starting inode of chunk */ | ||
1563 | __int32_t fcnt, /* free inode count */ | ||
1564 | xfs_inofree_t free) /* free inode mask */ | ||
1565 | { | ||
1566 | xfs_inobt_block_t *block; /* btree block to update */ | ||
1567 | xfs_buf_t *bp; /* buffer containing btree block */ | ||
1568 | int error; /* error return value */ | ||
1569 | int ptr; /* current record number (updating) */ | ||
1570 | xfs_inobt_rec_t *rp; /* pointer to updated record */ | ||
1571 | |||
1572 | /* | ||
1573 | * Pick up the current block. | ||
1574 | */ | ||
1575 | bp = cur->bc_bufs[0]; | ||
1576 | block = XFS_BUF_TO_INOBT_BLOCK(bp); | ||
1577 | #ifdef DEBUG | ||
1578 | if ((error = xfs_btree_check_sblock(cur, block, 0, bp))) | ||
1579 | return error; | ||
1580 | #endif | ||
1581 | /* | ||
1582 | * Get the address of the rec to be updated. | ||
1583 | */ | ||
1584 | ptr = cur->bc_ptrs[0]; | ||
1585 | rp = XFS_INOBT_REC_ADDR(block, ptr, cur); | ||
1586 | /* | ||
1587 | * Fill in the new contents and log them. | ||
1588 | */ | ||
1589 | rp->ir_startino = cpu_to_be32(ino); | ||
1590 | rp->ir_freecount = cpu_to_be32(fcnt); | ||
1591 | rp->ir_free = cpu_to_be64(free); | ||
1592 | xfs_inobt_log_recs(cur, bp, ptr, ptr); | ||
1593 | /* | ||
1594 | * Updating first record in leaf. Pass new key value up to our parent. | ||
1595 | */ | ||
1596 | if (ptr == 1) { | ||
1597 | xfs_inobt_key_t key; /* key containing [ino] */ | ||
1598 | |||
1599 | key.ir_startino = cpu_to_be32(ino); | ||
1600 | if ((error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, 1))) | ||
1601 | return error; | ||
1602 | } | ||
1603 | return 0; | ||
1604 | } | ||
1605 | |||
1606 | STATIC struct xfs_btree_cur * | 1554 | STATIC struct xfs_btree_cur * |
1607 | xfs_inobt_dup_cursor( | 1555 | xfs_inobt_dup_cursor( |
1608 | struct xfs_btree_cur *cur) | 1556 | struct xfs_btree_cur *cur) |
diff --git a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h index 674b459521f5..7f77549e82a6 100644 --- a/fs/xfs/xfs_ialloc_btree.h +++ b/fs/xfs/xfs_ialloc_btree.h | |||
@@ -135,14 +135,6 @@ extern int xfs_inobt_get_rec(struct xfs_btree_cur *cur, xfs_agino_t *ino, | |||
135 | */ | 135 | */ |
136 | extern int xfs_inobt_insert(struct xfs_btree_cur *cur, int *stat); | 136 | extern int xfs_inobt_insert(struct xfs_btree_cur *cur, int *stat); |
137 | 137 | ||
138 | /* | ||
139 | * Update the record referred to by cur, to the value given | ||
140 | * by [ino, fcnt, free]. | ||
141 | * This either works (return 0) or gets an EFSCORRUPTED error. | ||
142 | */ | ||
143 | extern int xfs_inobt_update(struct xfs_btree_cur *cur, xfs_agino_t ino, | ||
144 | __int32_t fcnt, xfs_inofree_t free); | ||
145 | |||
146 | 138 | ||
147 | extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *, | 139 | extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *, |
148 | struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t); | 140 | struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t); |