diff options
Diffstat (limited to 'fs/xfs/xfs_btree.c')
-rw-r--r-- | fs/xfs/xfs_btree.c | 121 |
1 files changed, 121 insertions, 0 deletions
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 | |||