diff options
author | Christoph Hellwig <hch@lst.de> | 2011-07-13 07:43:48 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2011-07-13 07:43:48 -0400 |
commit | 5792664070c62479b088e4909000582de3686396 (patch) | |
tree | 900e7d35b33da062fe8fad5694539fdad8c59266 /fs/xfs/xfs_dir2_format.h | |
parent | 2bcf6e970f5a88fa05dced5eeb0326e13d93c4a1 (diff) |
xfs: reshuffle dir2 headers
Replace the current mess of dir2 headers with just three that have a clear
purpose:
- xfs_dir2_format.h for all format definitions, including the inline helpers
to access our variable size structures
- xfs_dir2_priv.h for all prototypes that are internal to the dir2 code
and not needed by anything outside of the directory code. For this
purpose xfs_da_btree.c, and phase6.c in xfs_repair are considered part
of the directory code.
- xfs_dir2.h for the public interface to the directory code
In addition to the reshuffle I have also update the comments to not only
match the new file structure, but also to describe the directory format
better.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alex Elder <aelder@sgi.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Diffstat (limited to 'fs/xfs/xfs_dir2_format.h')
-rw-r--r-- | fs/xfs/xfs_dir2_format.h | 595 |
1 files changed, 595 insertions, 0 deletions
diff --git a/fs/xfs/xfs_dir2_format.h b/fs/xfs/xfs_dir2_format.h new file mode 100644 index 000000000000..c3c4839eebd6 --- /dev/null +++ b/fs/xfs/xfs_dir2_format.h | |||
@@ -0,0 +1,595 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it would be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write the Free Software Foundation, | ||
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | */ | ||
18 | #ifndef __XFS_DIR2_FORMAT_H__ | ||
19 | #define __XFS_DIR2_FORMAT_H__ | ||
20 | |||
21 | /* | ||
22 | * Directory version 2. | ||
23 | * | ||
24 | * There are 4 possible formats: | ||
25 | * - shortform - embedded into the inode | ||
26 | * - single block - data with embedded leaf at the end | ||
27 | * - multiple data blocks, single leaf+freeindex block | ||
28 | * - data blocks, node and leaf blocks (btree), freeindex blocks | ||
29 | * | ||
30 | * Note: many node blocks structures and constants are shared with the attr | ||
31 | * code and defined in xfs_da_btree.h. | ||
32 | */ | ||
33 | |||
34 | #define XFS_DIR2_BLOCK_MAGIC 0x58443242 /* XD2B: single block dirs */ | ||
35 | #define XFS_DIR2_DATA_MAGIC 0x58443244 /* XD2D: multiblock dirs */ | ||
36 | #define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F: free index blocks */ | ||
37 | |||
38 | /* | ||
39 | * Byte offset in data block and shortform entry. | ||
40 | */ | ||
41 | typedef __uint16_t xfs_dir2_data_off_t; | ||
42 | #define NULLDATAOFF 0xffffU | ||
43 | typedef uint xfs_dir2_data_aoff_t; /* argument form */ | ||
44 | |||
45 | /* | ||
46 | * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t. | ||
47 | * Only need 16 bits, this is the byte offset into the single block form. | ||
48 | */ | ||
49 | typedef struct { __uint8_t i[2]; } __arch_pack xfs_dir2_sf_off_t; | ||
50 | |||
51 | /* | ||
52 | * Offset in data space of a data entry. | ||
53 | */ | ||
54 | typedef __uint32_t xfs_dir2_dataptr_t; | ||
55 | #define XFS_DIR2_MAX_DATAPTR ((xfs_dir2_dataptr_t)0xffffffff) | ||
56 | #define XFS_DIR2_NULL_DATAPTR ((xfs_dir2_dataptr_t)0) | ||
57 | |||
58 | /* | ||
59 | * Byte offset in a directory. | ||
60 | */ | ||
61 | typedef xfs_off_t xfs_dir2_off_t; | ||
62 | |||
63 | /* | ||
64 | * Directory block number (logical dirblk in file) | ||
65 | */ | ||
66 | typedef __uint32_t xfs_dir2_db_t; | ||
67 | |||
68 | /* | ||
69 | * Inode number stored as 8 8-bit values. | ||
70 | */ | ||
71 | typedef struct { __uint8_t i[8]; } xfs_dir2_ino8_t; | ||
72 | |||
73 | /* | ||
74 | * Inode number stored as 4 8-bit values. | ||
75 | * Works a lot of the time, when all the inode numbers in a directory | ||
76 | * fit in 32 bits. | ||
77 | */ | ||
78 | typedef struct { __uint8_t i[4]; } xfs_dir2_ino4_t; | ||
79 | |||
80 | typedef union { | ||
81 | xfs_dir2_ino8_t i8; | ||
82 | xfs_dir2_ino4_t i4; | ||
83 | } xfs_dir2_inou_t; | ||
84 | #define XFS_DIR2_MAX_SHORT_INUM ((xfs_ino_t)0xffffffffULL) | ||
85 | |||
86 | /* | ||
87 | * Directory layout when stored internal to an inode. | ||
88 | * | ||
89 | * Small directories are packed as tightly as possible so as to fit into the | ||
90 | * literal area of the inode. These "shortform" directories consist of a | ||
91 | * single xfs_dir2_sf_hdr header followed by zero or more xfs_dir2_sf_entry | ||
92 | * structures. Due the different inode number storage size and the variable | ||
93 | * length name field in the xfs_dir2_sf_entry all these structure are | ||
94 | * variable length, and the accessors in this file should be used to iterate | ||
95 | * over them. | ||
96 | */ | ||
97 | typedef struct xfs_dir2_sf_hdr { | ||
98 | __uint8_t count; /* count of entries */ | ||
99 | __uint8_t i8count; /* count of 8-byte inode #s */ | ||
100 | xfs_dir2_inou_t parent; /* parent dir inode number */ | ||
101 | } __arch_pack xfs_dir2_sf_hdr_t; | ||
102 | |||
103 | typedef struct xfs_dir2_sf_entry { | ||
104 | __u8 namelen; /* actual name length */ | ||
105 | xfs_dir2_sf_off_t offset; /* saved offset */ | ||
106 | __u8 name[]; /* name, variable size */ | ||
107 | /* | ||
108 | * A xfs_dir2_ino8_t or xfs_dir2_ino4_t follows here, at a | ||
109 | * variable offset after the name. | ||
110 | */ | ||
111 | } __arch_pack xfs_dir2_sf_entry_t; | ||
112 | |||
113 | static inline int xfs_dir2_sf_hdr_size(int i8count) | ||
114 | { | ||
115 | return sizeof(struct xfs_dir2_sf_hdr) - | ||
116 | (i8count == 0) * | ||
117 | (sizeof(xfs_dir2_ino8_t) - sizeof(xfs_dir2_ino4_t)); | ||
118 | } | ||
119 | |||
120 | static inline xfs_dir2_data_aoff_t | ||
121 | xfs_dir2_sf_get_offset(xfs_dir2_sf_entry_t *sfep) | ||
122 | { | ||
123 | return get_unaligned_be16(&sfep->offset.i); | ||
124 | } | ||
125 | |||
126 | static inline void | ||
127 | xfs_dir2_sf_put_offset(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off) | ||
128 | { | ||
129 | put_unaligned_be16(off, &sfep->offset.i); | ||
130 | } | ||
131 | |||
132 | static inline int | ||
133 | xfs_dir2_sf_entsize(struct xfs_dir2_sf_hdr *hdr, int len) | ||
134 | { | ||
135 | return sizeof(struct xfs_dir2_sf_entry) + /* namelen + offset */ | ||
136 | len + /* name */ | ||
137 | (hdr->i8count ? /* ino */ | ||
138 | sizeof(xfs_dir2_ino8_t) : | ||
139 | sizeof(xfs_dir2_ino4_t)); | ||
140 | } | ||
141 | |||
142 | static inline struct xfs_dir2_sf_entry * | ||
143 | xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr) | ||
144 | { | ||
145 | return (struct xfs_dir2_sf_entry *) | ||
146 | ((char *)hdr + xfs_dir2_sf_hdr_size(hdr->i8count)); | ||
147 | } | ||
148 | |||
149 | static inline struct xfs_dir2_sf_entry * | ||
150 | xfs_dir2_sf_nextentry(struct xfs_dir2_sf_hdr *hdr, | ||
151 | struct xfs_dir2_sf_entry *sfep) | ||
152 | { | ||
153 | return (struct xfs_dir2_sf_entry *) | ||
154 | ((char *)sfep + xfs_dir2_sf_entsize(hdr, sfep->namelen)); | ||
155 | } | ||
156 | |||
157 | |||
158 | /* | ||
159 | * Data block structures. | ||
160 | * | ||
161 | * A pure data block looks like the following drawing on disk: | ||
162 | * | ||
163 | * +-------------------------------------------------+ | ||
164 | * | xfs_dir2_data_hdr_t | | ||
165 | * +-------------------------------------------------+ | ||
166 | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | | ||
167 | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | | ||
168 | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | | ||
169 | * | ... | | ||
170 | * +-------------------------------------------------+ | ||
171 | * | unused space | | ||
172 | * +-------------------------------------------------+ | ||
173 | * | ||
174 | * As all the entries are variable size structures the accessors below should | ||
175 | * be used to iterate over them. | ||
176 | * | ||
177 | * In addition to the pure data blocks for the data and node formats, | ||
178 | * most structures are also used for the combined data/freespace "block" | ||
179 | * format below. | ||
180 | */ | ||
181 | |||
182 | #define XFS_DIR2_DATA_ALIGN_LOG 3 /* i.e., 8 bytes */ | ||
183 | #define XFS_DIR2_DATA_ALIGN (1 << XFS_DIR2_DATA_ALIGN_LOG) | ||
184 | #define XFS_DIR2_DATA_FREE_TAG 0xffff | ||
185 | #define XFS_DIR2_DATA_FD_COUNT 3 | ||
186 | |||
187 | /* | ||
188 | * Directory address space divided into sections, | ||
189 | * spaces separated by 32GB. | ||
190 | */ | ||
191 | #define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG)) | ||
192 | #define XFS_DIR2_DATA_SPACE 0 | ||
193 | #define XFS_DIR2_DATA_OFFSET (XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE) | ||
194 | #define XFS_DIR2_DATA_FIRSTDB(mp) \ | ||
195 | xfs_dir2_byte_to_db(mp, XFS_DIR2_DATA_OFFSET) | ||
196 | |||
197 | /* | ||
198 | * Offsets of . and .. in data space (always block 0) | ||
199 | */ | ||
200 | #define XFS_DIR2_DATA_DOT_OFFSET \ | ||
201 | ((xfs_dir2_data_aoff_t)sizeof(struct xfs_dir2_data_hdr)) | ||
202 | #define XFS_DIR2_DATA_DOTDOT_OFFSET \ | ||
203 | (XFS_DIR2_DATA_DOT_OFFSET + xfs_dir2_data_entsize(1)) | ||
204 | #define XFS_DIR2_DATA_FIRST_OFFSET \ | ||
205 | (XFS_DIR2_DATA_DOTDOT_OFFSET + xfs_dir2_data_entsize(2)) | ||
206 | |||
207 | /* | ||
208 | * Describe a free area in the data block. | ||
209 | * | ||
210 | * The freespace will be formatted as a xfs_dir2_data_unused_t. | ||
211 | */ | ||
212 | typedef struct xfs_dir2_data_free { | ||
213 | __be16 offset; /* start of freespace */ | ||
214 | __be16 length; /* length of freespace */ | ||
215 | } xfs_dir2_data_free_t; | ||
216 | |||
217 | /* | ||
218 | * Header for the data blocks. | ||
219 | * | ||
220 | * The code knows that XFS_DIR2_DATA_FD_COUNT is 3. | ||
221 | */ | ||
222 | typedef struct xfs_dir2_data_hdr { | ||
223 | __be32 magic; /* XFS_DIR2_DATA_MAGIC or */ | ||
224 | /* XFS_DIR2_BLOCK_MAGIC */ | ||
225 | xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT]; | ||
226 | } xfs_dir2_data_hdr_t; | ||
227 | |||
228 | /* | ||
229 | * Active entry in a data block. | ||
230 | * | ||
231 | * Aligned to 8 bytes. After the variable length name field there is a | ||
232 | * 2 byte tag field, which can be accessed using xfs_dir2_data_entry_tag_p. | ||
233 | */ | ||
234 | typedef struct xfs_dir2_data_entry { | ||
235 | __be64 inumber; /* inode number */ | ||
236 | __u8 namelen; /* name length */ | ||
237 | __u8 name[]; /* name bytes, no null */ | ||
238 | /* __be16 tag; */ /* starting offset of us */ | ||
239 | } xfs_dir2_data_entry_t; | ||
240 | |||
241 | /* | ||
242 | * Unused entry in a data block. | ||
243 | * | ||
244 | * Aligned to 8 bytes. Tag appears as the last 2 bytes and must be accessed | ||
245 | * using xfs_dir2_data_unused_tag_p. | ||
246 | */ | ||
247 | typedef struct xfs_dir2_data_unused { | ||
248 | __be16 freetag; /* XFS_DIR2_DATA_FREE_TAG */ | ||
249 | __be16 length; /* total free length */ | ||
250 | /* variable offset */ | ||
251 | __be16 tag; /* starting offset of us */ | ||
252 | } xfs_dir2_data_unused_t; | ||
253 | |||
254 | /* | ||
255 | * Size of a data entry. | ||
256 | */ | ||
257 | static inline int xfs_dir2_data_entsize(int n) | ||
258 | { | ||
259 | return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n + | ||
260 | (uint)sizeof(xfs_dir2_data_off_t), XFS_DIR2_DATA_ALIGN); | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Pointer to an entry's tag word. | ||
265 | */ | ||
266 | static inline __be16 * | ||
267 | xfs_dir2_data_entry_tag_p(struct xfs_dir2_data_entry *dep) | ||
268 | { | ||
269 | return (__be16 *)((char *)dep + | ||
270 | xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16)); | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Pointer to a freespace's tag word. | ||
275 | */ | ||
276 | static inline __be16 * | ||
277 | xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup) | ||
278 | { | ||
279 | return (__be16 *)((char *)dup + | ||
280 | be16_to_cpu(dup->length) - sizeof(__be16)); | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * Leaf block structures. | ||
285 | * | ||
286 | * A pure leaf block looks like the following drawing on disk: | ||
287 | * | ||
288 | * +---------------------------+ | ||
289 | * | xfs_dir2_leaf_hdr_t | | ||
290 | * +---------------------------+ | ||
291 | * | xfs_dir2_leaf_entry_t | | ||
292 | * | xfs_dir2_leaf_entry_t | | ||
293 | * | xfs_dir2_leaf_entry_t | | ||
294 | * | xfs_dir2_leaf_entry_t | | ||
295 | * | ... | | ||
296 | * +---------------------------+ | ||
297 | * | xfs_dir2_data_off_t | | ||
298 | * | xfs_dir2_data_off_t | | ||
299 | * | xfs_dir2_data_off_t | | ||
300 | * | ... | | ||
301 | * +---------------------------+ | ||
302 | * | xfs_dir2_leaf_tail_t | | ||
303 | * +---------------------------+ | ||
304 | * | ||
305 | * The xfs_dir2_data_off_t members (bests) and tail are at the end of the block | ||
306 | * for single-leaf (magic = XFS_DIR2_LEAF1_MAGIC) blocks only, but not present | ||
307 | * for directories with separate leaf nodes and free space blocks | ||
308 | * (magic = XFS_DIR2_LEAFN_MAGIC). | ||
309 | * | ||
310 | * As all the entries are variable size structures the accessors below should | ||
311 | * be used to iterate over them. | ||
312 | */ | ||
313 | |||
314 | /* | ||
315 | * Offset of the leaf/node space. First block in this space | ||
316 | * is the btree root. | ||
317 | */ | ||
318 | #define XFS_DIR2_LEAF_SPACE 1 | ||
319 | #define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE) | ||
320 | #define XFS_DIR2_LEAF_FIRSTDB(mp) \ | ||
321 | xfs_dir2_byte_to_db(mp, XFS_DIR2_LEAF_OFFSET) | ||
322 | |||
323 | /* | ||
324 | * Leaf block header. | ||
325 | */ | ||
326 | typedef struct xfs_dir2_leaf_hdr { | ||
327 | xfs_da_blkinfo_t info; /* header for da routines */ | ||
328 | __be16 count; /* count of entries */ | ||
329 | __be16 stale; /* count of stale entries */ | ||
330 | } xfs_dir2_leaf_hdr_t; | ||
331 | |||
332 | /* | ||
333 | * Leaf block entry. | ||
334 | */ | ||
335 | typedef struct xfs_dir2_leaf_entry { | ||
336 | __be32 hashval; /* hash value of name */ | ||
337 | __be32 address; /* address of data entry */ | ||
338 | } xfs_dir2_leaf_entry_t; | ||
339 | |||
340 | /* | ||
341 | * Leaf block tail. | ||
342 | */ | ||
343 | typedef struct xfs_dir2_leaf_tail { | ||
344 | __be32 bestcount; | ||
345 | } xfs_dir2_leaf_tail_t; | ||
346 | |||
347 | /* | ||
348 | * Leaf block. | ||
349 | */ | ||
350 | typedef struct xfs_dir2_leaf { | ||
351 | xfs_dir2_leaf_hdr_t hdr; /* leaf header */ | ||
352 | xfs_dir2_leaf_entry_t ents[]; /* entries */ | ||
353 | } xfs_dir2_leaf_t; | ||
354 | |||
355 | /* | ||
356 | * DB blocks here are logical directory block numbers, not filesystem blocks. | ||
357 | */ | ||
358 | |||
359 | static inline int xfs_dir2_max_leaf_ents(struct xfs_mount *mp) | ||
360 | { | ||
361 | return (mp->m_dirblksize - (uint)sizeof(struct xfs_dir2_leaf_hdr)) / | ||
362 | (uint)sizeof(struct xfs_dir2_leaf_entry); | ||
363 | } | ||
364 | |||
365 | /* | ||
366 | * Get address of the bestcount field in the single-leaf block. | ||
367 | */ | ||
368 | static inline struct xfs_dir2_leaf_tail * | ||
369 | xfs_dir2_leaf_tail_p(struct xfs_mount *mp, struct xfs_dir2_leaf *lp) | ||
370 | { | ||
371 | return (struct xfs_dir2_leaf_tail *) | ||
372 | ((char *)lp + mp->m_dirblksize - | ||
373 | sizeof(struct xfs_dir2_leaf_tail)); | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * Get address of the bests array in the single-leaf block. | ||
378 | */ | ||
379 | static inline __be16 * | ||
380 | xfs_dir2_leaf_bests_p(struct xfs_dir2_leaf_tail *ltp) | ||
381 | { | ||
382 | return (__be16 *)ltp - be32_to_cpu(ltp->bestcount); | ||
383 | } | ||
384 | |||
385 | /* | ||
386 | * Convert dataptr to byte in file space | ||
387 | */ | ||
388 | static inline xfs_dir2_off_t | ||
389 | xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp) | ||
390 | { | ||
391 | return (xfs_dir2_off_t)dp << XFS_DIR2_DATA_ALIGN_LOG; | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * Convert byte in file space to dataptr. It had better be aligned. | ||
396 | */ | ||
397 | static inline xfs_dir2_dataptr_t | ||
398 | xfs_dir2_byte_to_dataptr(struct xfs_mount *mp, xfs_dir2_off_t by) | ||
399 | { | ||
400 | return (xfs_dir2_dataptr_t)(by >> XFS_DIR2_DATA_ALIGN_LOG); | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Convert byte in space to (DB) block | ||
405 | */ | ||
406 | static inline xfs_dir2_db_t | ||
407 | xfs_dir2_byte_to_db(struct xfs_mount *mp, xfs_dir2_off_t by) | ||
408 | { | ||
409 | return (xfs_dir2_db_t) | ||
410 | (by >> (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)); | ||
411 | } | ||
412 | |||
413 | /* | ||
414 | * Convert dataptr to a block number | ||
415 | */ | ||
416 | static inline xfs_dir2_db_t | ||
417 | xfs_dir2_dataptr_to_db(struct xfs_mount *mp, xfs_dir2_dataptr_t dp) | ||
418 | { | ||
419 | return xfs_dir2_byte_to_db(mp, xfs_dir2_dataptr_to_byte(mp, dp)); | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * Convert byte in space to offset in a block | ||
424 | */ | ||
425 | static inline xfs_dir2_data_aoff_t | ||
426 | xfs_dir2_byte_to_off(struct xfs_mount *mp, xfs_dir2_off_t by) | ||
427 | { | ||
428 | return (xfs_dir2_data_aoff_t)(by & | ||
429 | ((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) - 1)); | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * Convert dataptr to a byte offset in a block | ||
434 | */ | ||
435 | static inline xfs_dir2_data_aoff_t | ||
436 | xfs_dir2_dataptr_to_off(struct xfs_mount *mp, xfs_dir2_dataptr_t dp) | ||
437 | { | ||
438 | return xfs_dir2_byte_to_off(mp, xfs_dir2_dataptr_to_byte(mp, dp)); | ||
439 | } | ||
440 | |||
441 | /* | ||
442 | * Convert block and offset to byte in space | ||
443 | */ | ||
444 | static inline xfs_dir2_off_t | ||
445 | xfs_dir2_db_off_to_byte(struct xfs_mount *mp, xfs_dir2_db_t db, | ||
446 | xfs_dir2_data_aoff_t o) | ||
447 | { | ||
448 | return ((xfs_dir2_off_t)db << | ||
449 | (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) + o; | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * Convert block (DB) to block (dablk) | ||
454 | */ | ||
455 | static inline xfs_dablk_t | ||
456 | xfs_dir2_db_to_da(struct xfs_mount *mp, xfs_dir2_db_t db) | ||
457 | { | ||
458 | return (xfs_dablk_t)(db << mp->m_sb.sb_dirblklog); | ||
459 | } | ||
460 | |||
461 | /* | ||
462 | * Convert byte in space to (DA) block | ||
463 | */ | ||
464 | static inline xfs_dablk_t | ||
465 | xfs_dir2_byte_to_da(struct xfs_mount *mp, xfs_dir2_off_t by) | ||
466 | { | ||
467 | return xfs_dir2_db_to_da(mp, xfs_dir2_byte_to_db(mp, by)); | ||
468 | } | ||
469 | |||
470 | /* | ||
471 | * Convert block and offset to dataptr | ||
472 | */ | ||
473 | static inline xfs_dir2_dataptr_t | ||
474 | xfs_dir2_db_off_to_dataptr(struct xfs_mount *mp, xfs_dir2_db_t db, | ||
475 | xfs_dir2_data_aoff_t o) | ||
476 | { | ||
477 | return xfs_dir2_byte_to_dataptr(mp, xfs_dir2_db_off_to_byte(mp, db, o)); | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * Convert block (dablk) to block (DB) | ||
482 | */ | ||
483 | static inline xfs_dir2_db_t | ||
484 | xfs_dir2_da_to_db(struct xfs_mount *mp, xfs_dablk_t da) | ||
485 | { | ||
486 | return (xfs_dir2_db_t)(da >> mp->m_sb.sb_dirblklog); | ||
487 | } | ||
488 | |||
489 | /* | ||
490 | * Convert block (dablk) to byte offset in space | ||
491 | */ | ||
492 | static inline xfs_dir2_off_t | ||
493 | xfs_dir2_da_to_byte(struct xfs_mount *mp, xfs_dablk_t da) | ||
494 | { | ||
495 | return xfs_dir2_db_off_to_byte(mp, xfs_dir2_da_to_db(mp, da), 0); | ||
496 | } | ||
497 | |||
498 | /* | ||
499 | * Free space block defintions for the node format. | ||
500 | */ | ||
501 | |||
502 | /* | ||
503 | * Offset of the freespace index. | ||
504 | */ | ||
505 | #define XFS_DIR2_FREE_SPACE 2 | ||
506 | #define XFS_DIR2_FREE_OFFSET (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE) | ||
507 | #define XFS_DIR2_FREE_FIRSTDB(mp) \ | ||
508 | xfs_dir2_byte_to_db(mp, XFS_DIR2_FREE_OFFSET) | ||
509 | |||
510 | typedef struct xfs_dir2_free_hdr { | ||
511 | __be32 magic; /* XFS_DIR2_FREE_MAGIC */ | ||
512 | __be32 firstdb; /* db of first entry */ | ||
513 | __be32 nvalid; /* count of valid entries */ | ||
514 | __be32 nused; /* count of used entries */ | ||
515 | } xfs_dir2_free_hdr_t; | ||
516 | |||
517 | typedef struct xfs_dir2_free { | ||
518 | xfs_dir2_free_hdr_t hdr; /* block header */ | ||
519 | __be16 bests[1]; /* best free counts */ | ||
520 | /* unused entries are -1 */ | ||
521 | } xfs_dir2_free_t; | ||
522 | |||
523 | #define XFS_DIR2_MAX_FREE_BESTS(mp) \ | ||
524 | (((mp)->m_dirblksize - (uint)sizeof(struct xfs_dir2_free_hdr)) / \ | ||
525 | (uint)sizeof(xfs_dir2_data_off_t)) | ||
526 | |||
527 | /* | ||
528 | * Convert data space db to the corresponding free db. | ||
529 | */ | ||
530 | static inline xfs_dir2_db_t | ||
531 | xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db) | ||
532 | { | ||
533 | return XFS_DIR2_FREE_FIRSTDB(mp) + db / XFS_DIR2_MAX_FREE_BESTS(mp); | ||
534 | } | ||
535 | |||
536 | /* | ||
537 | * Convert data space db to the corresponding index in a free db. | ||
538 | */ | ||
539 | static inline int | ||
540 | xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db) | ||
541 | { | ||
542 | return db % XFS_DIR2_MAX_FREE_BESTS(mp); | ||
543 | } | ||
544 | |||
545 | /* | ||
546 | * Single block format. | ||
547 | * | ||
548 | * The single block format looks like the following drawing on disk: | ||
549 | * | ||
550 | * +-------------------------------------------------+ | ||
551 | * | xfs_dir2_data_hdr_t | | ||
552 | * +-------------------------------------------------+ | ||
553 | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | | ||
554 | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | | ||
555 | * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t : | ||
556 | * | ... | | ||
557 | * +-------------------------------------------------+ | ||
558 | * | unused space | | ||
559 | * +-------------------------------------------------+ | ||
560 | * | ... | | ||
561 | * | xfs_dir2_leaf_entry_t | | ||
562 | * | xfs_dir2_leaf_entry_t | | ||
563 | * +-------------------------------------------------+ | ||
564 | * | xfs_dir2_block_tail_t | | ||
565 | * +-------------------------------------------------+ | ||
566 | * | ||
567 | * As all the entries are variable size structures the accessors below should | ||
568 | * be used to iterate over them. | ||
569 | */ | ||
570 | |||
571 | typedef struct xfs_dir2_block_tail { | ||
572 | __be32 count; /* count of leaf entries */ | ||
573 | __be32 stale; /* count of stale lf entries */ | ||
574 | } xfs_dir2_block_tail_t; | ||
575 | |||
576 | /* | ||
577 | * Pointer to the leaf header embedded in a data block (1-block format) | ||
578 | */ | ||
579 | static inline struct xfs_dir2_block_tail * | ||
580 | xfs_dir2_block_tail_p(struct xfs_mount *mp, struct xfs_dir2_data_hdr *hdr) | ||
581 | { | ||
582 | return ((struct xfs_dir2_block_tail *) | ||
583 | ((char *)hdr + mp->m_dirblksize)) - 1; | ||
584 | } | ||
585 | |||
586 | /* | ||
587 | * Pointer to the leaf entries embedded in a data block (1-block format) | ||
588 | */ | ||
589 | static inline struct xfs_dir2_leaf_entry * | ||
590 | xfs_dir2_block_leaf_p(struct xfs_dir2_block_tail *btp) | ||
591 | { | ||
592 | return ((struct xfs_dir2_leaf_entry *)btp) - be32_to_cpu(btp->count); | ||
593 | } | ||
594 | |||
595 | #endif /* __XFS_DIR2_FORMAT_H__ */ | ||