diff options
author | Dave Chinner <dchinner@redhat.com> | 2013-04-03 01:11:20 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2013-04-27 12:51:56 -0400 |
commit | f5f3d9b0161633e8943520e83df634ad540b3b7f (patch) | |
tree | bd1a014fd6472904e53d7680e5692b49431ca6ab /fs | |
parent | f948dd76dde021c050c7c35720dc066a8b9a5e35 (diff) |
xfs: add CRC checks to block format directory blocks
Now that directory buffers are made from a single struct xfs_buf, we
can add CRC calculation and checking callbacks. While there, add all
the fields to the on disk structures for future functionality such
as d_type support, uuids, block numbers, owner inode, etc.
To distinguish between the different on disk formats, change the
magic numbers for the new format directory blocks.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Ben Myers <bpm@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_dir2_block.c | 132 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_data.c | 160 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_format.h | 143 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_leaf.c | 6 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_node.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_priv.h | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_sf.c | 2 |
7 files changed, 344 insertions, 105 deletions
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index 12afe07a91d7..79a3f1b2bc7d 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. |
3 | * Copyright (c) 2013 Red Hat, Inc. | ||
3 | * All Rights Reserved. | 4 | * All Rights Reserved. |
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -28,11 +29,13 @@ | |||
28 | #include "xfs_dinode.h" | 29 | #include "xfs_dinode.h" |
29 | #include "xfs_inode.h" | 30 | #include "xfs_inode.h" |
30 | #include "xfs_inode_item.h" | 31 | #include "xfs_inode_item.h" |
32 | #include "xfs_buf_item.h" | ||
31 | #include "xfs_dir2.h" | 33 | #include "xfs_dir2.h" |
32 | #include "xfs_dir2_format.h" | 34 | #include "xfs_dir2_format.h" |
33 | #include "xfs_dir2_priv.h" | 35 | #include "xfs_dir2_priv.h" |
34 | #include "xfs_error.h" | 36 | #include "xfs_error.h" |
35 | #include "xfs_trace.h" | 37 | #include "xfs_trace.h" |
38 | #include "xfs_cksum.h" | ||
36 | 39 | ||
37 | /* | 40 | /* |
38 | * Local function prototypes. | 41 | * Local function prototypes. |
@@ -56,44 +59,74 @@ xfs_dir_startup(void) | |||
56 | xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); | 59 | xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); |
57 | } | 60 | } |
58 | 61 | ||
59 | static void | 62 | static bool |
60 | xfs_dir2_block_verify( | 63 | xfs_dir3_block_verify( |
61 | struct xfs_buf *bp) | 64 | struct xfs_buf *bp) |
62 | { | 65 | { |
63 | struct xfs_mount *mp = bp->b_target->bt_mount; | 66 | struct xfs_mount *mp = bp->b_target->bt_mount; |
64 | struct xfs_dir2_data_hdr *hdr = bp->b_addr; | 67 | struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; |
65 | int block_ok = 0; | 68 | |
66 | 69 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | |
67 | block_ok = hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); | 70 | if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) |
68 | block_ok = block_ok && __xfs_dir2_data_check(NULL, bp) == 0; | 71 | return false; |
69 | 72 | if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid)) | |
70 | if (!block_ok) { | 73 | return false; |
71 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr); | 74 | if (be64_to_cpu(hdr3->blkno) != bp->b_bn) |
72 | xfs_buf_ioerror(bp, EFSCORRUPTED); | 75 | return false; |
76 | } else { | ||
77 | if (hdr3->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) | ||
78 | return false; | ||
73 | } | 79 | } |
80 | if (__xfs_dir2_data_check(NULL, bp)) | ||
81 | return false; | ||
82 | return true; | ||
74 | } | 83 | } |
75 | 84 | ||
76 | static void | 85 | static void |
77 | xfs_dir2_block_read_verify( | 86 | xfs_dir3_block_read_verify( |
78 | struct xfs_buf *bp) | 87 | struct xfs_buf *bp) |
79 | { | 88 | { |
80 | xfs_dir2_block_verify(bp); | 89 | struct xfs_mount *mp = bp->b_target->bt_mount; |
90 | |||
91 | if ((xfs_sb_version_hascrc(&mp->m_sb) && | ||
92 | !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
93 | XFS_DIR3_DATA_CRC_OFF)) || | ||
94 | !xfs_dir3_block_verify(bp)) { | ||
95 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
96 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
97 | } | ||
81 | } | 98 | } |
82 | 99 | ||
83 | static void | 100 | static void |
84 | xfs_dir2_block_write_verify( | 101 | xfs_dir3_block_write_verify( |
85 | struct xfs_buf *bp) | 102 | struct xfs_buf *bp) |
86 | { | 103 | { |
87 | xfs_dir2_block_verify(bp); | 104 | struct xfs_mount *mp = bp->b_target->bt_mount; |
105 | struct xfs_buf_log_item *bip = bp->b_fspriv; | ||
106 | struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; | ||
107 | |||
108 | if (!xfs_dir3_block_verify(bp)) { | ||
109 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
110 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
111 | return; | ||
112 | } | ||
113 | |||
114 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
115 | return; | ||
116 | |||
117 | if (bip) | ||
118 | hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); | ||
119 | |||
120 | xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_DIR3_DATA_CRC_OFF); | ||
88 | } | 121 | } |
89 | 122 | ||
90 | const struct xfs_buf_ops xfs_dir2_block_buf_ops = { | 123 | const struct xfs_buf_ops xfs_dir3_block_buf_ops = { |
91 | .verify_read = xfs_dir2_block_read_verify, | 124 | .verify_read = xfs_dir3_block_read_verify, |
92 | .verify_write = xfs_dir2_block_write_verify, | 125 | .verify_write = xfs_dir3_block_write_verify, |
93 | }; | 126 | }; |
94 | 127 | ||
95 | static int | 128 | static int |
96 | xfs_dir2_block_read( | 129 | xfs_dir3_block_read( |
97 | struct xfs_trans *tp, | 130 | struct xfs_trans *tp, |
98 | struct xfs_inode *dp, | 131 | struct xfs_inode *dp, |
99 | struct xfs_buf **bpp) | 132 | struct xfs_buf **bpp) |
@@ -101,7 +134,29 @@ xfs_dir2_block_read( | |||
101 | struct xfs_mount *mp = dp->i_mount; | 134 | struct xfs_mount *mp = dp->i_mount; |
102 | 135 | ||
103 | return xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp, | 136 | return xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp, |
104 | XFS_DATA_FORK, &xfs_dir2_block_buf_ops); | 137 | XFS_DATA_FORK, &xfs_dir3_block_buf_ops); |
138 | } | ||
139 | |||
140 | static void | ||
141 | xfs_dir3_block_init( | ||
142 | struct xfs_mount *mp, | ||
143 | struct xfs_buf *bp, | ||
144 | struct xfs_inode *dp) | ||
145 | { | ||
146 | struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; | ||
147 | |||
148 | bp->b_ops = &xfs_dir3_block_buf_ops; | ||
149 | |||
150 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | ||
151 | memset(hdr3, 0, sizeof(*hdr3)); | ||
152 | hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC); | ||
153 | hdr3->blkno = cpu_to_be64(bp->b_bn); | ||
154 | hdr3->owner = cpu_to_be64(dp->i_ino); | ||
155 | uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid); | ||
156 | return; | ||
157 | |||
158 | } | ||
159 | hdr3->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); | ||
105 | } | 160 | } |
106 | 161 | ||
107 | static void | 162 | static void |
@@ -121,7 +176,7 @@ xfs_dir2_block_need_space( | |||
121 | struct xfs_dir2_data_unused *enddup = NULL; | 176 | struct xfs_dir2_data_unused *enddup = NULL; |
122 | 177 | ||
123 | *compact = 0; | 178 | *compact = 0; |
124 | bf = hdr->bestfree; | 179 | bf = xfs_dir3_data_bestfree_p(hdr); |
125 | 180 | ||
126 | /* | 181 | /* |
127 | * If there are stale entries we'll use one for the leaf. | 182 | * If there are stale entries we'll use one for the leaf. |
@@ -303,7 +358,7 @@ xfs_dir2_block_addname( | |||
303 | mp = dp->i_mount; | 358 | mp = dp->i_mount; |
304 | 359 | ||
305 | /* Read the (one and only) directory block into bp. */ | 360 | /* Read the (one and only) directory block into bp. */ |
306 | error = xfs_dir2_block_read(tp, dp, &bp); | 361 | error = xfs_dir3_block_read(tp, dp, &bp); |
307 | if (error) | 362 | if (error) |
308 | return error; | 363 | return error; |
309 | 364 | ||
@@ -531,7 +586,7 @@ xfs_dir2_block_getdents( | |||
531 | if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk) | 586 | if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk) |
532 | return 0; | 587 | return 0; |
533 | 588 | ||
534 | error = xfs_dir2_block_read(NULL, dp, &bp); | 589 | error = xfs_dir3_block_read(NULL, dp, &bp); |
535 | if (error) | 590 | if (error) |
536 | return error; | 591 | return error; |
537 | 592 | ||
@@ -546,7 +601,7 @@ xfs_dir2_block_getdents( | |||
546 | * Set up values for the loop. | 601 | * Set up values for the loop. |
547 | */ | 602 | */ |
548 | btp = xfs_dir2_block_tail_p(mp, hdr); | 603 | btp = xfs_dir2_block_tail_p(mp, hdr); |
549 | ptr = (char *)(hdr + 1); | 604 | ptr = (char *)xfs_dir3_data_entry_p(hdr); |
550 | endptr = (char *)xfs_dir2_block_leaf_p(btp); | 605 | endptr = (char *)xfs_dir2_block_leaf_p(btp); |
551 | 606 | ||
552 | /* | 607 | /* |
@@ -711,7 +766,7 @@ xfs_dir2_block_lookup_int( | |||
711 | tp = args->trans; | 766 | tp = args->trans; |
712 | mp = dp->i_mount; | 767 | mp = dp->i_mount; |
713 | 768 | ||
714 | error = xfs_dir2_block_read(tp, dp, &bp); | 769 | error = xfs_dir3_block_read(tp, dp, &bp); |
715 | if (error) | 770 | if (error) |
716 | return error; | 771 | return error; |
717 | 772 | ||
@@ -974,9 +1029,12 @@ xfs_dir2_leaf_to_block( | |||
974 | * These will show up in the leaf bests table. | 1029 | * These will show up in the leaf bests table. |
975 | */ | 1030 | */ |
976 | while (dp->i_d.di_size > mp->m_dirblksize) { | 1031 | while (dp->i_d.di_size > mp->m_dirblksize) { |
1032 | int hdrsz; | ||
1033 | |||
1034 | hdrsz = xfs_dir3_data_hdr_size(xfs_sb_version_hascrc(&mp->m_sb)); | ||
977 | bestsp = xfs_dir2_leaf_bests_p(ltp); | 1035 | bestsp = xfs_dir2_leaf_bests_p(ltp); |
978 | if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) == | 1036 | if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) == |
979 | mp->m_dirblksize - (uint)sizeof(*hdr)) { | 1037 | mp->m_dirblksize - hdrsz) { |
980 | if ((error = | 1038 | if ((error = |
981 | xfs_dir2_leaf_trim_data(args, lbp, | 1039 | xfs_dir2_leaf_trim_data(args, lbp, |
982 | (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1)))) | 1040 | (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1)))) |
@@ -1014,8 +1072,8 @@ xfs_dir2_leaf_to_block( | |||
1014 | /* | 1072 | /* |
1015 | * Start converting it to block form. | 1073 | * Start converting it to block form. |
1016 | */ | 1074 | */ |
1017 | dbp->b_ops = &xfs_dir2_block_buf_ops; | 1075 | xfs_dir3_block_init(mp, dbp, dp); |
1018 | hdr->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); | 1076 | |
1019 | needlog = 1; | 1077 | needlog = 1; |
1020 | needscan = 0; | 1078 | needscan = 0; |
1021 | /* | 1079 | /* |
@@ -1137,16 +1195,16 @@ xfs_dir2_sf_to_block( | |||
1137 | return error; | 1195 | return error; |
1138 | } | 1196 | } |
1139 | /* | 1197 | /* |
1140 | * Initialize the data block. | 1198 | * Initialize the data block, then convert it to block format. |
1141 | */ | 1199 | */ |
1142 | error = xfs_dir2_data_init(args, blkno, &bp); | 1200 | error = xfs_dir3_data_init(args, blkno, &bp); |
1143 | if (error) { | 1201 | if (error) { |
1144 | kmem_free(sfp); | 1202 | kmem_free(sfp); |
1145 | return error; | 1203 | return error; |
1146 | } | 1204 | } |
1147 | bp->b_ops = &xfs_dir2_block_buf_ops; | 1205 | xfs_dir3_block_init(mp, bp, dp); |
1148 | hdr = bp->b_addr; | 1206 | hdr = bp->b_addr; |
1149 | hdr->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); | 1207 | |
1150 | /* | 1208 | /* |
1151 | * Compute size of block "tail" area. | 1209 | * Compute size of block "tail" area. |
1152 | */ | 1210 | */ |
@@ -1156,7 +1214,7 @@ xfs_dir2_sf_to_block( | |||
1156 | * The whole thing is initialized to free by the init routine. | 1214 | * The whole thing is initialized to free by the init routine. |
1157 | * Say we're using the leaf and tail area. | 1215 | * Say we're using the leaf and tail area. |
1158 | */ | 1216 | */ |
1159 | dup = (xfs_dir2_data_unused_t *)(hdr + 1); | 1217 | dup = xfs_dir3_data_unused_p(hdr); |
1160 | needlog = needscan = 0; | 1218 | needlog = needscan = 0; |
1161 | xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog, | 1219 | xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog, |
1162 | &needscan); | 1220 | &needscan); |
@@ -1178,8 +1236,7 @@ xfs_dir2_sf_to_block( | |||
1178 | /* | 1236 | /* |
1179 | * Create entry for . | 1237 | * Create entry for . |
1180 | */ | 1238 | */ |
1181 | dep = (xfs_dir2_data_entry_t *) | 1239 | dep = xfs_dir3_data_dot_entry_p(hdr); |
1182 | ((char *)hdr + XFS_DIR2_DATA_DOT_OFFSET); | ||
1183 | dep->inumber = cpu_to_be64(dp->i_ino); | 1240 | dep->inumber = cpu_to_be64(dp->i_ino); |
1184 | dep->namelen = 1; | 1241 | dep->namelen = 1; |
1185 | dep->name[0] = '.'; | 1242 | dep->name[0] = '.'; |
@@ -1192,8 +1249,7 @@ xfs_dir2_sf_to_block( | |||
1192 | /* | 1249 | /* |
1193 | * Create entry for .. | 1250 | * Create entry for .. |
1194 | */ | 1251 | */ |
1195 | dep = (xfs_dir2_data_entry_t *) | 1252 | dep = xfs_dir3_data_dotdot_entry_p(hdr); |
1196 | ((char *)hdr + XFS_DIR2_DATA_DOTDOT_OFFSET); | ||
1197 | dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp)); | 1253 | dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp)); |
1198 | dep->namelen = 2; | 1254 | dep->namelen = 2; |
1199 | dep->name[0] = dep->name[1] = '.'; | 1255 | dep->name[0] = dep->name[1] = '.'; |
@@ -1203,7 +1259,7 @@ xfs_dir2_sf_to_block( | |||
1203 | blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot); | 1259 | blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot); |
1204 | blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, | 1260 | blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, |
1205 | (char *)dep - (char *)hdr)); | 1261 | (char *)dep - (char *)hdr)); |
1206 | offset = XFS_DIR2_DATA_FIRST_OFFSET; | 1262 | offset = xfs_dir3_data_first_offset(hdr); |
1207 | /* | 1263 | /* |
1208 | * Loop over existing entries, stuff them in. | 1264 | * Loop over existing entries, stuff them in. |
1209 | */ | 1265 | */ |
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c index ffcf1774152e..8484ec4848ea 100644 --- a/fs/xfs/xfs_dir2_data.c +++ b/fs/xfs/xfs_dir2_data.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. |
3 | * Copyright (c) 2013 Red Hat, Inc. | ||
3 | * All Rights Reserved. | 4 | * All Rights Reserved. |
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -65,10 +66,11 @@ __xfs_dir2_data_check( | |||
65 | 66 | ||
66 | mp = bp->b_target->bt_mount; | 67 | mp = bp->b_target->bt_mount; |
67 | hdr = bp->b_addr; | 68 | hdr = bp->b_addr; |
68 | bf = hdr->bestfree; | 69 | bf = xfs_dir3_data_bestfree_p(hdr); |
69 | p = (char *)(hdr + 1); | 70 | p = (char *)xfs_dir3_data_entry_p(hdr); |
70 | 71 | ||
71 | switch (hdr->magic) { | 72 | switch (hdr->magic) { |
73 | case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): | ||
72 | case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): | 74 | case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): |
73 | btp = xfs_dir2_block_tail_p(mp, hdr); | 75 | btp = xfs_dir2_block_tail_p(mp, hdr); |
74 | lep = xfs_dir2_block_leaf_p(btp); | 76 | lep = xfs_dir2_block_leaf_p(btp); |
@@ -148,7 +150,8 @@ __xfs_dir2_data_check( | |||
148 | (char *)dep - (char *)hdr); | 150 | (char *)dep - (char *)hdr); |
149 | count++; | 151 | count++; |
150 | lastfree = 0; | 152 | lastfree = 0; |
151 | if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) { | 153 | if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
154 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { | ||
152 | addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, | 155 | addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, |
153 | (xfs_dir2_data_aoff_t) | 156 | (xfs_dir2_data_aoff_t) |
154 | ((char *)dep - (char *)hdr)); | 157 | ((char *)dep - (char *)hdr)); |
@@ -168,7 +171,8 @@ __xfs_dir2_data_check( | |||
168 | * Need to have seen all the entries and all the bestfree slots. | 171 | * Need to have seen all the entries and all the bestfree slots. |
169 | */ | 172 | */ |
170 | XFS_WANT_CORRUPTED_RETURN(freeseen == 7); | 173 | XFS_WANT_CORRUPTED_RETURN(freeseen == 7); |
171 | if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) { | 174 | if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
175 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { | ||
172 | for (i = stale = 0; i < be32_to_cpu(btp->count); i++) { | 176 | for (i = stale = 0; i < be32_to_cpu(btp->count); i++) { |
173 | if (lep[i].address == | 177 | if (lep[i].address == |
174 | cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) | 178 | cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) |
@@ -216,7 +220,8 @@ xfs_dir2_data_reada_verify( | |||
216 | 220 | ||
217 | switch (hdr->magic) { | 221 | switch (hdr->magic) { |
218 | case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): | 222 | case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): |
219 | bp->b_ops = &xfs_dir2_block_buf_ops; | 223 | case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): |
224 | bp->b_ops = &xfs_dir3_block_buf_ops; | ||
220 | bp->b_ops->verify_read(bp); | 225 | bp->b_ops->verify_read(bp); |
221 | return; | 226 | return; |
222 | case cpu_to_be32(XFS_DIR2_DATA_MAGIC): | 227 | case cpu_to_be32(XFS_DIR2_DATA_MAGIC): |
@@ -288,12 +293,15 @@ xfs_dir2_data_freefind( | |||
288 | { | 293 | { |
289 | xfs_dir2_data_free_t *dfp; /* bestfree entry */ | 294 | xfs_dir2_data_free_t *dfp; /* bestfree entry */ |
290 | xfs_dir2_data_aoff_t off; /* offset value needed */ | 295 | xfs_dir2_data_aoff_t off; /* offset value needed */ |
296 | struct xfs_dir2_data_free *bf; | ||
291 | #if defined(DEBUG) && defined(__KERNEL__) | 297 | #if defined(DEBUG) && defined(__KERNEL__) |
292 | int matched; /* matched the value */ | 298 | int matched; /* matched the value */ |
293 | int seenzero; /* saw a 0 bestfree entry */ | 299 | int seenzero; /* saw a 0 bestfree entry */ |
294 | #endif | 300 | #endif |
295 | 301 | ||
296 | off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); | 302 | off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); |
303 | bf = xfs_dir3_data_bestfree_p(hdr); | ||
304 | |||
297 | #if defined(DEBUG) && defined(__KERNEL__) | 305 | #if defined(DEBUG) && defined(__KERNEL__) |
298 | /* | 306 | /* |
299 | * Validate some consistency in the bestfree table. | 307 | * Validate some consistency in the bestfree table. |
@@ -301,9 +309,10 @@ xfs_dir2_data_freefind( | |||
301 | * one we're looking for it has to be exact. | 309 | * one we're looking for it has to be exact. |
302 | */ | 310 | */ |
303 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || | 311 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || |
304 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); | 312 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
305 | for (dfp = &hdr->bestfree[0], seenzero = matched = 0; | 313 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); |
306 | dfp < &hdr->bestfree[XFS_DIR2_DATA_FD_COUNT]; | 314 | for (dfp = &bf[0], seenzero = matched = 0; |
315 | dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; | ||
307 | dfp++) { | 316 | dfp++) { |
308 | if (!dfp->offset) { | 317 | if (!dfp->offset) { |
309 | ASSERT(!dfp->length); | 318 | ASSERT(!dfp->length); |
@@ -319,7 +328,7 @@ xfs_dir2_data_freefind( | |||
319 | else | 328 | else |
320 | ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off); | 329 | ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off); |
321 | ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length)); | 330 | ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length)); |
322 | if (dfp > &hdr->bestfree[0]) | 331 | if (dfp > &bf[0]) |
323 | ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length)); | 332 | ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length)); |
324 | } | 333 | } |
325 | #endif | 334 | #endif |
@@ -328,14 +337,12 @@ xfs_dir2_data_freefind( | |||
328 | * it can't be there since they're sorted. | 337 | * it can't be there since they're sorted. |
329 | */ | 338 | */ |
330 | if (be16_to_cpu(dup->length) < | 339 | if (be16_to_cpu(dup->length) < |
331 | be16_to_cpu(hdr->bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length)) | 340 | be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length)) |
332 | return NULL; | 341 | return NULL; |
333 | /* | 342 | /* |
334 | * Look at the three bestfree entries for our guy. | 343 | * Look at the three bestfree entries for our guy. |
335 | */ | 344 | */ |
336 | for (dfp = &hdr->bestfree[0]; | 345 | for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { |
337 | dfp < &hdr->bestfree[XFS_DIR2_DATA_FD_COUNT]; | ||
338 | dfp++) { | ||
339 | if (!dfp->offset) | 346 | if (!dfp->offset) |
340 | return NULL; | 347 | return NULL; |
341 | if (be16_to_cpu(dfp->offset) == off) | 348 | if (be16_to_cpu(dfp->offset) == off) |
@@ -359,11 +366,12 @@ xfs_dir2_data_freeinsert( | |||
359 | xfs_dir2_data_free_t *dfp; /* bestfree table pointer */ | 366 | xfs_dir2_data_free_t *dfp; /* bestfree table pointer */ |
360 | xfs_dir2_data_free_t new; /* new bestfree entry */ | 367 | xfs_dir2_data_free_t new; /* new bestfree entry */ |
361 | 368 | ||
362 | #ifdef __KERNEL__ | ||
363 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || | 369 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || |
364 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); | 370 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
365 | #endif | 371 | hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || |
366 | dfp = hdr->bestfree; | 372 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); |
373 | |||
374 | dfp = xfs_dir3_data_bestfree_p(hdr); | ||
367 | new.length = dup->length; | 375 | new.length = dup->length; |
368 | new.offset = cpu_to_be16((char *)dup - (char *)hdr); | 376 | new.offset = cpu_to_be16((char *)dup - (char *)hdr); |
369 | 377 | ||
@@ -400,32 +408,36 @@ xfs_dir2_data_freeremove( | |||
400 | xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */ | 408 | xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */ |
401 | int *loghead) /* out: log data header */ | 409 | int *loghead) /* out: log data header */ |
402 | { | 410 | { |
403 | #ifdef __KERNEL__ | 411 | struct xfs_dir2_data_free *bf; |
412 | |||
404 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || | 413 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || |
405 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); | 414 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
406 | #endif | 415 | hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || |
416 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); | ||
417 | |||
407 | /* | 418 | /* |
408 | * It's the first entry, slide the next 2 up. | 419 | * It's the first entry, slide the next 2 up. |
409 | */ | 420 | */ |
410 | if (dfp == &hdr->bestfree[0]) { | 421 | bf = xfs_dir3_data_bestfree_p(hdr); |
411 | hdr->bestfree[0] = hdr->bestfree[1]; | 422 | if (dfp == &bf[0]) { |
412 | hdr->bestfree[1] = hdr->bestfree[2]; | 423 | bf[0] = bf[1]; |
424 | bf[1] = bf[2]; | ||
413 | } | 425 | } |
414 | /* | 426 | /* |
415 | * It's the second entry, slide the 3rd entry up. | 427 | * It's the second entry, slide the 3rd entry up. |
416 | */ | 428 | */ |
417 | else if (dfp == &hdr->bestfree[1]) | 429 | else if (dfp == &bf[1]) |
418 | hdr->bestfree[1] = hdr->bestfree[2]; | 430 | bf[1] = bf[2]; |
419 | /* | 431 | /* |
420 | * Must be the last entry. | 432 | * Must be the last entry. |
421 | */ | 433 | */ |
422 | else | 434 | else |
423 | ASSERT(dfp == &hdr->bestfree[2]); | 435 | ASSERT(dfp == &bf[2]); |
424 | /* | 436 | /* |
425 | * Clear the 3rd entry, must be zero now. | 437 | * Clear the 3rd entry, must be zero now. |
426 | */ | 438 | */ |
427 | hdr->bestfree[2].length = 0; | 439 | bf[2].length = 0; |
428 | hdr->bestfree[2].offset = 0; | 440 | bf[2].offset = 0; |
429 | *loghead = 1; | 441 | *loghead = 1; |
430 | } | 442 | } |
431 | 443 | ||
@@ -441,23 +453,26 @@ xfs_dir2_data_freescan( | |||
441 | xfs_dir2_block_tail_t *btp; /* block tail */ | 453 | xfs_dir2_block_tail_t *btp; /* block tail */ |
442 | xfs_dir2_data_entry_t *dep; /* active data entry */ | 454 | xfs_dir2_data_entry_t *dep; /* active data entry */ |
443 | xfs_dir2_data_unused_t *dup; /* unused data entry */ | 455 | xfs_dir2_data_unused_t *dup; /* unused data entry */ |
456 | struct xfs_dir2_data_free *bf; | ||
444 | char *endp; /* end of block's data */ | 457 | char *endp; /* end of block's data */ |
445 | char *p; /* current entry pointer */ | 458 | char *p; /* current entry pointer */ |
446 | 459 | ||
447 | #ifdef __KERNEL__ | ||
448 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || | 460 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || |
449 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); | 461 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
450 | #endif | 462 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); |
463 | |||
451 | /* | 464 | /* |
452 | * Start by clearing the table. | 465 | * Start by clearing the table. |
453 | */ | 466 | */ |
454 | memset(hdr->bestfree, 0, sizeof(hdr->bestfree)); | 467 | bf = xfs_dir3_data_bestfree_p(hdr); |
468 | memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT); | ||
455 | *loghead = 1; | 469 | *loghead = 1; |
456 | /* | 470 | /* |
457 | * Set up pointers. | 471 | * Set up pointers. |
458 | */ | 472 | */ |
459 | p = (char *)(hdr + 1); | 473 | p = (char *)xfs_dir3_data_entry_p(hdr); |
460 | if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) { | 474 | if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
475 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { | ||
461 | btp = xfs_dir2_block_tail_p(mp, hdr); | 476 | btp = xfs_dir2_block_tail_p(mp, hdr); |
462 | endp = (char *)xfs_dir2_block_leaf_p(btp); | 477 | endp = (char *)xfs_dir2_block_leaf_p(btp); |
463 | } else | 478 | } else |
@@ -493,7 +508,7 @@ xfs_dir2_data_freescan( | |||
493 | * Give back the buffer for the created block. | 508 | * Give back the buffer for the created block. |
494 | */ | 509 | */ |
495 | int /* error */ | 510 | int /* error */ |
496 | xfs_dir2_data_init( | 511 | xfs_dir3_data_init( |
497 | xfs_da_args_t *args, /* directory operation args */ | 512 | xfs_da_args_t *args, /* directory operation args */ |
498 | xfs_dir2_db_t blkno, /* logical dir block number */ | 513 | xfs_dir2_db_t blkno, /* logical dir block number */ |
499 | struct xfs_buf **bpp) /* output block buffer */ | 514 | struct xfs_buf **bpp) /* output block buffer */ |
@@ -502,6 +517,7 @@ xfs_dir2_data_init( | |||
502 | xfs_dir2_data_hdr_t *hdr; /* data block header */ | 517 | xfs_dir2_data_hdr_t *hdr; /* data block header */ |
503 | xfs_inode_t *dp; /* incore directory inode */ | 518 | xfs_inode_t *dp; /* incore directory inode */ |
504 | xfs_dir2_data_unused_t *dup; /* unused entry pointer */ | 519 | xfs_dir2_data_unused_t *dup; /* unused entry pointer */ |
520 | struct xfs_dir2_data_free *bf; | ||
505 | int error; /* error return value */ | 521 | int error; /* error return value */ |
506 | int i; /* bestfree index */ | 522 | int i; /* bestfree index */ |
507 | xfs_mount_t *mp; /* filesystem mount point */ | 523 | xfs_mount_t *mp; /* filesystem mount point */ |
@@ -524,21 +540,34 @@ xfs_dir2_data_init( | |||
524 | * Initialize the header. | 540 | * Initialize the header. |
525 | */ | 541 | */ |
526 | hdr = bp->b_addr; | 542 | hdr = bp->b_addr; |
527 | hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC); | 543 | |
528 | hdr->bestfree[0].offset = cpu_to_be16(sizeof(*hdr)); | 544 | if (xfs_sb_version_hascrc(&mp->m_sb)) { |
545 | struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; | ||
546 | |||
547 | memset(hdr3, 0, sizeof(*hdr3)); | ||
548 | hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC); | ||
549 | hdr3->blkno = cpu_to_be64(bp->b_bn); | ||
550 | hdr3->owner = cpu_to_be64(dp->i_ino); | ||
551 | uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid); | ||
552 | |||
553 | } else | ||
554 | hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC); | ||
555 | |||
556 | bf = xfs_dir3_data_bestfree_p(hdr); | ||
557 | bf[0].offset = cpu_to_be16(xfs_dir3_data_entry_offset(hdr)); | ||
529 | for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { | 558 | for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { |
530 | hdr->bestfree[i].length = 0; | 559 | bf[i].length = 0; |
531 | hdr->bestfree[i].offset = 0; | 560 | bf[i].offset = 0; |
532 | } | 561 | } |
533 | 562 | ||
534 | /* | 563 | /* |
535 | * Set up an unused entry for the block's body. | 564 | * Set up an unused entry for the block's body. |
536 | */ | 565 | */ |
537 | dup = (xfs_dir2_data_unused_t *)(hdr + 1); | 566 | dup = xfs_dir3_data_unused_p(hdr); |
538 | dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); | 567 | dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); |
539 | 568 | ||
540 | t = mp->m_dirblksize - (uint)sizeof(*hdr); | 569 | t = mp->m_dirblksize - (uint)xfs_dir3_data_entry_offset(hdr); |
541 | hdr->bestfree[0].length = cpu_to_be16(t); | 570 | bf[0].length = cpu_to_be16(t); |
542 | dup->length = cpu_to_be16(t); | 571 | dup->length = cpu_to_be16(t); |
543 | *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr); | 572 | *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr); |
544 | /* | 573 | /* |
@@ -562,7 +591,8 @@ xfs_dir2_data_log_entry( | |||
562 | xfs_dir2_data_hdr_t *hdr = bp->b_addr; | 591 | xfs_dir2_data_hdr_t *hdr = bp->b_addr; |
563 | 592 | ||
564 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || | 593 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || |
565 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); | 594 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
595 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); | ||
566 | 596 | ||
567 | xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr), | 597 | xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr), |
568 | (uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) - | 598 | (uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) - |
@@ -580,9 +610,10 @@ xfs_dir2_data_log_header( | |||
580 | xfs_dir2_data_hdr_t *hdr = bp->b_addr; | 610 | xfs_dir2_data_hdr_t *hdr = bp->b_addr; |
581 | 611 | ||
582 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || | 612 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || |
583 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); | 613 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
614 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); | ||
584 | 615 | ||
585 | xfs_trans_log_buf(tp, bp, 0, sizeof(*hdr) - 1); | 616 | xfs_trans_log_buf(tp, bp, 0, xfs_dir3_data_entry_offset(hdr) - 1); |
586 | } | 617 | } |
587 | 618 | ||
588 | /* | 619 | /* |
@@ -597,7 +628,8 @@ xfs_dir2_data_log_unused( | |||
597 | xfs_dir2_data_hdr_t *hdr = bp->b_addr; | 628 | xfs_dir2_data_hdr_t *hdr = bp->b_addr; |
598 | 629 | ||
599 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || | 630 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || |
600 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); | 631 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
632 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); | ||
601 | 633 | ||
602 | /* | 634 | /* |
603 | * Log the first part of the unused entry. | 635 | * Log the first part of the unused entry. |
@@ -635,6 +667,7 @@ xfs_dir2_data_make_free( | |||
635 | xfs_dir2_data_unused_t *newdup; /* new unused entry */ | 667 | xfs_dir2_data_unused_t *newdup; /* new unused entry */ |
636 | xfs_dir2_data_unused_t *postdup; /* unused entry after us */ | 668 | xfs_dir2_data_unused_t *postdup; /* unused entry after us */ |
637 | xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ | 669 | xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ |
670 | struct xfs_dir2_data_free *bf; | ||
638 | 671 | ||
639 | mp = tp->t_mountp; | 672 | mp = tp->t_mountp; |
640 | hdr = bp->b_addr; | 673 | hdr = bp->b_addr; |
@@ -647,7 +680,8 @@ xfs_dir2_data_make_free( | |||
647 | else { | 680 | else { |
648 | xfs_dir2_block_tail_t *btp; /* block tail */ | 681 | xfs_dir2_block_tail_t *btp; /* block tail */ |
649 | 682 | ||
650 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); | 683 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
684 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); | ||
651 | btp = xfs_dir2_block_tail_p(mp, hdr); | 685 | btp = xfs_dir2_block_tail_p(mp, hdr); |
652 | endptr = (char *)xfs_dir2_block_leaf_p(btp); | 686 | endptr = (char *)xfs_dir2_block_leaf_p(btp); |
653 | } | 687 | } |
@@ -655,7 +689,7 @@ xfs_dir2_data_make_free( | |||
655 | * If this isn't the start of the block, then back up to | 689 | * If this isn't the start of the block, then back up to |
656 | * the previous entry and see if it's free. | 690 | * the previous entry and see if it's free. |
657 | */ | 691 | */ |
658 | if (offset > sizeof(*hdr)) { | 692 | if (offset > xfs_dir3_data_entry_offset(hdr)) { |
659 | __be16 *tagp; /* tag just before us */ | 693 | __be16 *tagp; /* tag just before us */ |
660 | 694 | ||
661 | tagp = (__be16 *)((char *)hdr + offset) - 1; | 695 | tagp = (__be16 *)((char *)hdr + offset) - 1; |
@@ -681,6 +715,7 @@ xfs_dir2_data_make_free( | |||
681 | * Previous and following entries are both free, | 715 | * Previous and following entries are both free, |
682 | * merge everything into a single free entry. | 716 | * merge everything into a single free entry. |
683 | */ | 717 | */ |
718 | bf = xfs_dir3_data_bestfree_p(hdr); | ||
684 | if (prevdup && postdup) { | 719 | if (prevdup && postdup) { |
685 | xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ | 720 | xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ |
686 | 721 | ||
@@ -695,7 +730,7 @@ xfs_dir2_data_make_free( | |||
695 | * since the third bestfree is there, there might be more | 730 | * since the third bestfree is there, there might be more |
696 | * entries. | 731 | * entries. |
697 | */ | 732 | */ |
698 | needscan = (hdr->bestfree[2].length != 0); | 733 | needscan = (bf[2].length != 0); |
699 | /* | 734 | /* |
700 | * Fix up the new big freespace. | 735 | * Fix up the new big freespace. |
701 | */ | 736 | */ |
@@ -711,10 +746,10 @@ xfs_dir2_data_make_free( | |||
711 | * Remove entry 1 first then entry 0. | 746 | * Remove entry 1 first then entry 0. |
712 | */ | 747 | */ |
713 | ASSERT(dfp && dfp2); | 748 | ASSERT(dfp && dfp2); |
714 | if (dfp == &hdr->bestfree[1]) { | 749 | if (dfp == &bf[1]) { |
715 | dfp = &hdr->bestfree[0]; | 750 | dfp = &bf[0]; |
716 | ASSERT(dfp2 == dfp); | 751 | ASSERT(dfp2 == dfp); |
717 | dfp2 = &hdr->bestfree[1]; | 752 | dfp2 = &bf[1]; |
718 | } | 753 | } |
719 | xfs_dir2_data_freeremove(hdr, dfp2, needlogp); | 754 | xfs_dir2_data_freeremove(hdr, dfp2, needlogp); |
720 | xfs_dir2_data_freeremove(hdr, dfp, needlogp); | 755 | xfs_dir2_data_freeremove(hdr, dfp, needlogp); |
@@ -722,7 +757,7 @@ xfs_dir2_data_make_free( | |||
722 | * Now insert the new entry. | 757 | * Now insert the new entry. |
723 | */ | 758 | */ |
724 | dfp = xfs_dir2_data_freeinsert(hdr, prevdup, needlogp); | 759 | dfp = xfs_dir2_data_freeinsert(hdr, prevdup, needlogp); |
725 | ASSERT(dfp == &hdr->bestfree[0]); | 760 | ASSERT(dfp == &bf[0]); |
726 | ASSERT(dfp->length == prevdup->length); | 761 | ASSERT(dfp->length == prevdup->length); |
727 | ASSERT(!dfp[1].length); | 762 | ASSERT(!dfp[1].length); |
728 | ASSERT(!dfp[2].length); | 763 | ASSERT(!dfp[2].length); |
@@ -751,7 +786,7 @@ xfs_dir2_data_make_free( | |||
751 | */ | 786 | */ |
752 | else { | 787 | else { |
753 | needscan = be16_to_cpu(prevdup->length) > | 788 | needscan = be16_to_cpu(prevdup->length) > |
754 | be16_to_cpu(hdr->bestfree[2].length); | 789 | be16_to_cpu(bf[2].length); |
755 | } | 790 | } |
756 | } | 791 | } |
757 | /* | 792 | /* |
@@ -779,7 +814,7 @@ xfs_dir2_data_make_free( | |||
779 | */ | 814 | */ |
780 | else { | 815 | else { |
781 | needscan = be16_to_cpu(newdup->length) > | 816 | needscan = be16_to_cpu(newdup->length) > |
782 | be16_to_cpu(hdr->bestfree[2].length); | 817 | be16_to_cpu(bf[2].length); |
783 | } | 818 | } |
784 | } | 819 | } |
785 | /* | 820 | /* |
@@ -818,10 +853,12 @@ xfs_dir2_data_use_free( | |||
818 | xfs_dir2_data_unused_t *newdup; /* new unused entry */ | 853 | xfs_dir2_data_unused_t *newdup; /* new unused entry */ |
819 | xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ | 854 | xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ |
820 | int oldlen; /* old unused entry's length */ | 855 | int oldlen; /* old unused entry's length */ |
856 | struct xfs_dir2_data_free *bf; | ||
821 | 857 | ||
822 | hdr = bp->b_addr; | 858 | hdr = bp->b_addr; |
823 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || | 859 | ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || |
824 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)); | 860 | hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || |
861 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); | ||
825 | ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG); | 862 | ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG); |
826 | ASSERT(offset >= (char *)dup - (char *)hdr); | 863 | ASSERT(offset >= (char *)dup - (char *)hdr); |
827 | ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr); | 864 | ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr); |
@@ -831,7 +868,8 @@ xfs_dir2_data_use_free( | |||
831 | */ | 868 | */ |
832 | dfp = xfs_dir2_data_freefind(hdr, dup); | 869 | dfp = xfs_dir2_data_freefind(hdr, dup); |
833 | oldlen = be16_to_cpu(dup->length); | 870 | oldlen = be16_to_cpu(dup->length); |
834 | ASSERT(dfp || oldlen <= be16_to_cpu(hdr->bestfree[2].length)); | 871 | bf = xfs_dir3_data_bestfree_p(hdr); |
872 | ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length)); | ||
835 | /* | 873 | /* |
836 | * Check for alignment with front and back of the entry. | 874 | * Check for alignment with front and back of the entry. |
837 | */ | 875 | */ |
@@ -845,7 +883,7 @@ xfs_dir2_data_use_free( | |||
845 | */ | 883 | */ |
846 | if (matchfront && matchback) { | 884 | if (matchfront && matchback) { |
847 | if (dfp) { | 885 | if (dfp) { |
848 | needscan = (hdr->bestfree[2].offset != 0); | 886 | needscan = (bf[2].offset != 0); |
849 | if (!needscan) | 887 | if (!needscan) |
850 | xfs_dir2_data_freeremove(hdr, dfp, needlogp); | 888 | xfs_dir2_data_freeremove(hdr, dfp, needlogp); |
851 | } | 889 | } |
@@ -875,7 +913,7 @@ xfs_dir2_data_use_free( | |||
875 | * that means we don't know if there was a better | 913 | * that means we don't know if there was a better |
876 | * choice for the last slot, or not. Rescan. | 914 | * choice for the last slot, or not. Rescan. |
877 | */ | 915 | */ |
878 | needscan = dfp == &hdr->bestfree[2]; | 916 | needscan = dfp == &bf[2]; |
879 | } | 917 | } |
880 | } | 918 | } |
881 | /* | 919 | /* |
@@ -902,7 +940,7 @@ xfs_dir2_data_use_free( | |||
902 | * that means we don't know if there was a better | 940 | * that means we don't know if there was a better |
903 | * choice for the last slot, or not. Rescan. | 941 | * choice for the last slot, or not. Rescan. |
904 | */ | 942 | */ |
905 | needscan = dfp == &hdr->bestfree[2]; | 943 | needscan = dfp == &bf[2]; |
906 | } | 944 | } |
907 | } | 945 | } |
908 | /* | 946 | /* |
@@ -930,7 +968,7 @@ xfs_dir2_data_use_free( | |||
930 | * the 2 new will work. | 968 | * the 2 new will work. |
931 | */ | 969 | */ |
932 | if (dfp) { | 970 | if (dfp) { |
933 | needscan = (hdr->bestfree[2].length != 0); | 971 | needscan = (bf[2].length != 0); |
934 | if (!needscan) { | 972 | if (!needscan) { |
935 | xfs_dir2_data_freeremove(hdr, dfp, needlogp); | 973 | xfs_dir2_data_freeremove(hdr, dfp, needlogp); |
936 | xfs_dir2_data_freeinsert(hdr, newdup, needlogp); | 974 | xfs_dir2_data_freeinsert(hdr, newdup, needlogp); |
diff --git a/fs/xfs/xfs_dir2_format.h b/fs/xfs/xfs_dir2_format.h index 07270981f48f..845979a4ee96 100644 --- a/fs/xfs/xfs_dir2_format.h +++ b/fs/xfs/xfs_dir2_format.h | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. |
3 | * Copyright (c) 2013 Red Hat, Inc. | ||
3 | * All Rights Reserved. | 4 | * All Rights Reserved. |
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -36,6 +37,37 @@ | |||
36 | #define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F: free index blocks */ | 37 | #define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F: free index blocks */ |
37 | 38 | ||
38 | /* | 39 | /* |
40 | * Directory Version 3 With CRCs. | ||
41 | * | ||
42 | * The tree formats are the same as for version 2 directories. The difference | ||
43 | * is in the block header and dirent formats. In many cases the v3 structures | ||
44 | * use v2 definitions as they are no different and this makes code sharing much | ||
45 | * easier. | ||
46 | * | ||
47 | * Also, the xfs_dir3_*() functions handle both v2 and v3 formats - if the | ||
48 | * format is v2 then they switch to the existing v2 code, or the format is v3 | ||
49 | * they implement the v3 functionality. This means the existing dir2 is a mix of | ||
50 | * xfs_dir2/xfs_dir3 calls and functions. The xfs_dir3 functions are called | ||
51 | * where there is a difference in the formats, otherwise the code is unchanged. | ||
52 | * | ||
53 | * Where it is possible, the code decides what to do based on the magic numbers | ||
54 | * in the blocks rather than feature bits in the superblock. This means the code | ||
55 | * is as independent of the external XFS code as possible as doesn't require | ||
56 | * passing struct xfs_mount pointers into places where it isn't really | ||
57 | * necessary. | ||
58 | * | ||
59 | * Version 3 includes: | ||
60 | * | ||
61 | * - a larger block header for CRC and identification purposes and so the | ||
62 | * offsets of all the structures inside the blocks are different. | ||
63 | * | ||
64 | * - new magic numbers to be able to detect the v2/v3 types on the fly. | ||
65 | */ | ||
66 | |||
67 | #define XFS_DIR3_BLOCK_MAGIC 0x58444233 /* XDB3: single block dirs */ | ||
68 | #define XFS_DIR3_DATA_MAGIC 0x58444433 /* XDD3: multiblock dirs */ | ||
69 | |||
70 | /* | ||
39 | * Byte offset in data block and shortform entry. | 71 | * Byte offset in data block and shortform entry. |
40 | */ | 72 | */ |
41 | typedef __uint16_t xfs_dir2_data_off_t; | 73 | typedef __uint16_t xfs_dir2_data_off_t; |
@@ -226,6 +258,38 @@ typedef struct xfs_dir2_data_hdr { | |||
226 | } xfs_dir2_data_hdr_t; | 258 | } xfs_dir2_data_hdr_t; |
227 | 259 | ||
228 | /* | 260 | /* |
261 | * define a structure for all the verification fields we are adding to the | ||
262 | * directory block structures. This will be used in several structures. | ||
263 | * The magic number must be the first entry to align with all the dir2 | ||
264 | * structures so we determine how to decode them just by the magic number. | ||
265 | */ | ||
266 | struct xfs_dir3_blk_hdr { | ||
267 | __be32 magic; /* magic number */ | ||
268 | __be32 crc; /* CRC of block */ | ||
269 | __be64 blkno; /* first block of the buffer */ | ||
270 | __be64 lsn; /* sequence number of last write */ | ||
271 | uuid_t uuid; /* filesystem we belong to */ | ||
272 | __be64 owner; /* inode that owns the block */ | ||
273 | }; | ||
274 | |||
275 | struct xfs_dir3_data_hdr { | ||
276 | struct xfs_dir3_blk_hdr hdr; | ||
277 | xfs_dir2_data_free_t best_free[XFS_DIR2_DATA_FD_COUNT]; | ||
278 | }; | ||
279 | |||
280 | #define XFS_DIR3_DATA_CRC_OFF offsetof(struct xfs_dir3_data_hdr, hdr.crc) | ||
281 | |||
282 | static inline struct xfs_dir2_data_free * | ||
283 | xfs_dir3_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) | ||
284 | { | ||
285 | if (hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { | ||
286 | struct xfs_dir3_data_hdr *hdr3 = (struct xfs_dir3_data_hdr *)hdr; | ||
287 | return hdr3->best_free; | ||
288 | } | ||
289 | return hdr->bestfree; | ||
290 | } | ||
291 | |||
292 | /* | ||
229 | * Active entry in a data block. | 293 | * Active entry in a data block. |
230 | * | 294 | * |
231 | * Aligned to 8 bytes. After the variable length name field there is a | 295 | * Aligned to 8 bytes. After the variable length name field there is a |
@@ -280,6 +344,85 @@ xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup) | |||
280 | be16_to_cpu(dup->length) - sizeof(__be16)); | 344 | be16_to_cpu(dup->length) - sizeof(__be16)); |
281 | } | 345 | } |
282 | 346 | ||
347 | static inline struct xfs_dir2_data_unused * | ||
348 | xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr) | ||
349 | { | ||
350 | if (hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { | ||
351 | return (struct xfs_dir2_data_unused *) | ||
352 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); | ||
353 | } | ||
354 | return (struct xfs_dir2_data_unused *) | ||
355 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); | ||
356 | } | ||
357 | |||
358 | static inline size_t | ||
359 | xfs_dir3_data_hdr_size(bool dir3) | ||
360 | { | ||
361 | if (dir3) | ||
362 | return sizeof(struct xfs_dir3_data_hdr); | ||
363 | return sizeof(struct xfs_dir2_data_hdr); | ||
364 | } | ||
365 | |||
366 | static inline size_t | ||
367 | xfs_dir3_data_entry_offset(struct xfs_dir2_data_hdr *hdr) | ||
368 | { | ||
369 | bool dir3 = hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || | ||
370 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC); | ||
371 | return xfs_dir3_data_hdr_size(dir3); | ||
372 | } | ||
373 | |||
374 | static inline struct xfs_dir2_data_entry * | ||
375 | xfs_dir3_data_entry_p(struct xfs_dir2_data_hdr *hdr) | ||
376 | { | ||
377 | return (struct xfs_dir2_data_entry *) | ||
378 | ((char *)hdr + xfs_dir3_data_entry_offset(hdr)); | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * Offsets of . and .. in data space (always block 0) | ||
383 | */ | ||
384 | static inline xfs_dir2_data_aoff_t | ||
385 | xfs_dir3_data_dot_offset(struct xfs_dir2_data_hdr *hdr) | ||
386 | { | ||
387 | return xfs_dir3_data_entry_offset(hdr); | ||
388 | } | ||
389 | |||
390 | static inline xfs_dir2_data_aoff_t | ||
391 | xfs_dir3_data_dotdot_offset(struct xfs_dir2_data_hdr *hdr) | ||
392 | { | ||
393 | return xfs_dir3_data_dot_offset(hdr) + xfs_dir2_data_entsize(1); | ||
394 | } | ||
395 | |||
396 | static inline xfs_dir2_data_aoff_t | ||
397 | xfs_dir3_data_first_offset(struct xfs_dir2_data_hdr *hdr) | ||
398 | { | ||
399 | return xfs_dir3_data_dotdot_offset(hdr) + xfs_dir2_data_entsize(2); | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * location of . and .. in data space (always block 0) | ||
404 | */ | ||
405 | static inline struct xfs_dir2_data_entry * | ||
406 | xfs_dir3_data_dot_entry_p(struct xfs_dir2_data_hdr *hdr) | ||
407 | { | ||
408 | return (struct xfs_dir2_data_entry *) | ||
409 | ((char *)hdr + xfs_dir3_data_dot_offset(hdr)); | ||
410 | } | ||
411 | |||
412 | static inline struct xfs_dir2_data_entry * | ||
413 | xfs_dir3_data_dotdot_entry_p(struct xfs_dir2_data_hdr *hdr) | ||
414 | { | ||
415 | return (struct xfs_dir2_data_entry *) | ||
416 | ((char *)hdr + xfs_dir3_data_dotdot_offset(hdr)); | ||
417 | } | ||
418 | |||
419 | static inline struct xfs_dir2_data_entry * | ||
420 | xfs_dir3_data_first_entry_p(struct xfs_dir2_data_hdr *hdr) | ||
421 | { | ||
422 | return (struct xfs_dir2_data_entry *) | ||
423 | ((char *)hdr + xfs_dir3_data_first_offset(hdr)); | ||
424 | } | ||
425 | |||
283 | /* | 426 | /* |
284 | * Leaf block structures. | 427 | * Leaf block structures. |
285 | * | 428 | * |
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index 60cd2fa4e047..ef163f06fd16 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c | |||
@@ -149,6 +149,7 @@ xfs_dir2_block_to_leaf( | |||
149 | int needlog; /* need to log block header */ | 149 | int needlog; /* need to log block header */ |
150 | int needscan; /* need to rescan bestfree */ | 150 | int needscan; /* need to rescan bestfree */ |
151 | xfs_trans_t *tp; /* transaction pointer */ | 151 | xfs_trans_t *tp; /* transaction pointer */ |
152 | struct xfs_dir2_data_free *bf; | ||
152 | 153 | ||
153 | trace_xfs_dir2_block_to_leaf(args); | 154 | trace_xfs_dir2_block_to_leaf(args); |
154 | 155 | ||
@@ -177,6 +178,7 @@ xfs_dir2_block_to_leaf( | |||
177 | xfs_dir2_data_check(dp, dbp); | 178 | xfs_dir2_data_check(dp, dbp); |
178 | btp = xfs_dir2_block_tail_p(mp, hdr); | 179 | btp = xfs_dir2_block_tail_p(mp, hdr); |
179 | blp = xfs_dir2_block_leaf_p(btp); | 180 | blp = xfs_dir2_block_leaf_p(btp); |
181 | bf = xfs_dir3_data_bestfree_p(hdr); | ||
180 | /* | 182 | /* |
181 | * Set the counts in the leaf header. | 183 | * Set the counts in the leaf header. |
182 | */ | 184 | */ |
@@ -212,7 +214,7 @@ xfs_dir2_block_to_leaf( | |||
212 | ltp = xfs_dir2_leaf_tail_p(mp, leaf); | 214 | ltp = xfs_dir2_leaf_tail_p(mp, leaf); |
213 | ltp->bestcount = cpu_to_be32(1); | 215 | ltp->bestcount = cpu_to_be32(1); |
214 | bestsp = xfs_dir2_leaf_bests_p(ltp); | 216 | bestsp = xfs_dir2_leaf_bests_p(ltp); |
215 | bestsp[0] = hdr->bestfree[0].length; | 217 | bestsp[0] = bf[0].length; |
216 | /* | 218 | /* |
217 | * Log the data header and leaf bests table. | 219 | * Log the data header and leaf bests table. |
218 | */ | 220 | */ |
@@ -544,7 +546,7 @@ xfs_dir2_leaf_addname( | |||
544 | /* | 546 | /* |
545 | * Initialize the block. | 547 | * Initialize the block. |
546 | */ | 548 | */ |
547 | if ((error = xfs_dir2_data_init(args, use_block, &dbp))) { | 549 | if ((error = xfs_dir3_data_init(args, use_block, &dbp))) { |
548 | xfs_trans_brelse(tp, lbp); | 550 | xfs_trans_brelse(tp, lbp); |
549 | return error; | 551 | return error; |
550 | } | 552 | } |
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index 5980f9b7fa9b..985d70bc391d 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c | |||
@@ -1588,7 +1588,7 @@ xfs_dir2_node_addname_int( | |||
1588 | if (unlikely((error = xfs_dir2_grow_inode(args, | 1588 | if (unlikely((error = xfs_dir2_grow_inode(args, |
1589 | XFS_DIR2_DATA_SPACE, | 1589 | XFS_DIR2_DATA_SPACE, |
1590 | &dbno)) || | 1590 | &dbno)) || |
1591 | (error = xfs_dir2_data_init(args, dbno, &dbp)))) | 1591 | (error = xfs_dir3_data_init(args, dbno, &dbp)))) |
1592 | return error; | 1592 | return error; |
1593 | 1593 | ||
1594 | /* | 1594 | /* |
diff --git a/fs/xfs/xfs_dir2_priv.h b/fs/xfs/xfs_dir2_priv.h index 7da79f6515fd..e6f2e0a7bb65 100644 --- a/fs/xfs/xfs_dir2_priv.h +++ b/fs/xfs/xfs_dir2_priv.h | |||
@@ -30,7 +30,7 @@ extern int xfs_dir_cilookup_result(struct xfs_da_args *args, | |||
30 | const unsigned char *name, int len); | 30 | const unsigned char *name, int len); |
31 | 31 | ||
32 | /* xfs_dir2_block.c */ | 32 | /* xfs_dir2_block.c */ |
33 | extern const struct xfs_buf_ops xfs_dir2_block_buf_ops; | 33 | extern const struct xfs_buf_ops xfs_dir3_block_buf_ops; |
34 | 34 | ||
35 | extern int xfs_dir2_block_addname(struct xfs_da_args *args); | 35 | extern int xfs_dir2_block_addname(struct xfs_da_args *args); |
36 | extern int xfs_dir2_block_getdents(struct xfs_inode *dp, void *dirent, | 36 | extern int xfs_dir2_block_getdents(struct xfs_inode *dp, void *dirent, |
@@ -61,7 +61,7 @@ xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr, | |||
61 | struct xfs_dir2_data_unused *dup, int *loghead); | 61 | struct xfs_dir2_data_unused *dup, int *loghead); |
62 | extern void xfs_dir2_data_freescan(struct xfs_mount *mp, | 62 | extern void xfs_dir2_data_freescan(struct xfs_mount *mp, |
63 | struct xfs_dir2_data_hdr *hdr, int *loghead); | 63 | struct xfs_dir2_data_hdr *hdr, int *loghead); |
64 | extern int xfs_dir2_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno, | 64 | extern int xfs_dir3_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno, |
65 | struct xfs_buf **bpp); | 65 | struct xfs_buf **bpp); |
66 | extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_buf *bp, | 66 | extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_buf *bp, |
67 | struct xfs_dir2_data_entry *dep); | 67 | struct xfs_dir2_data_entry *dep); |
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c index 1b9fc3ec7e4b..b9756228e9c0 100644 --- a/fs/xfs/xfs_dir2_sf.c +++ b/fs/xfs/xfs_dir2_sf.c | |||
@@ -278,7 +278,7 @@ xfs_dir2_block_to_sf( | |||
278 | * Set up to loop over the block's entries. | 278 | * Set up to loop over the block's entries. |
279 | */ | 279 | */ |
280 | btp = xfs_dir2_block_tail_p(mp, hdr); | 280 | btp = xfs_dir2_block_tail_p(mp, hdr); |
281 | ptr = (char *)(hdr + 1); | 281 | ptr = (char *)xfs_dir3_data_entry_p(hdr); |
282 | endptr = (char *)xfs_dir2_block_leaf_p(btp); | 282 | endptr = (char *)xfs_dir2_block_leaf_p(btp); |
283 | sfep = xfs_dir2_sf_firstentry(sfp); | 283 | sfep = xfs_dir2_sf_firstentry(sfp); |
284 | /* | 284 | /* |