Commit | Line | Data |
---|---|---|
0b61f8a4 | 1 | // SPDX-License-Identifier: GPL-2.0 |
32c5483a DC |
2 | /* |
3 | * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. | |
4 | * Copyright (c) 2013 Red Hat, Inc. | |
5 | * All Rights Reserved. | |
32c5483a DC |
6 | */ |
7 | #include "xfs.h" | |
8 | #include "xfs_fs.h" | |
632b89e8 | 9 | #include "xfs_shared.h" |
32c5483a DC |
10 | #include "xfs_format.h" |
11 | #include "xfs_log_format.h" | |
12 | #include "xfs_trans_resv.h" | |
32c5483a DC |
13 | #include "xfs_mount.h" |
14 | #include "xfs_da_format.h" | |
892e3f34 | 15 | #include "xfs_da_btree.h" |
32c5483a DC |
16 | #include "xfs_inode.h" |
17 | #include "xfs_dir2.h" | |
892e3f34 | 18 | #include "xfs_dir2_priv.h" |
32c5483a | 19 | |
9d23fc85 DC |
20 | /* |
21 | * Shortform directory ops | |
22 | */ | |
32c5483a DC |
23 | static int |
24 | xfs_dir2_sf_entsize( | |
25 | struct xfs_dir2_sf_hdr *hdr, | |
26 | int len) | |
27 | { | |
28 | int count = sizeof(struct xfs_dir2_sf_entry); /* namelen + offset */ | |
29 | ||
30 | count += len; /* name */ | |
266b6969 | 31 | count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE; /* ino # */ |
32c5483a DC |
32 | return count; |
33 | } | |
34 | ||
35 | static int | |
36 | xfs_dir3_sf_entsize( | |
37 | struct xfs_dir2_sf_hdr *hdr, | |
38 | int len) | |
39 | { | |
c8ce540d | 40 | return xfs_dir2_sf_entsize(hdr, len) + sizeof(uint8_t); |
32c5483a DC |
41 | } |
42 | ||
43 | static struct xfs_dir2_sf_entry * | |
44 | xfs_dir2_sf_nextentry( | |
45 | struct xfs_dir2_sf_hdr *hdr, | |
46 | struct xfs_dir2_sf_entry *sfep) | |
47 | { | |
48 | return (struct xfs_dir2_sf_entry *) | |
49 | ((char *)sfep + xfs_dir2_sf_entsize(hdr, sfep->namelen)); | |
50 | } | |
51 | ||
52 | static struct xfs_dir2_sf_entry * | |
53 | xfs_dir3_sf_nextentry( | |
54 | struct xfs_dir2_sf_hdr *hdr, | |
55 | struct xfs_dir2_sf_entry *sfep) | |
56 | { | |
57 | return (struct xfs_dir2_sf_entry *) | |
58 | ((char *)sfep + xfs_dir3_sf_entsize(hdr, sfep->namelen)); | |
59 | } | |
60 | ||
61 | ||
4740175e DC |
62 | /* |
63 | * For filetype enabled shortform directories, the file type field is stored at | |
64 | * the end of the name. Because it's only a single byte, endian conversion is | |
65 | * not necessary. For non-filetype enable directories, the type is always | |
66 | * unknown and we never store the value. | |
67 | */ | |
c8ce540d | 68 | static uint8_t |
4740175e DC |
69 | xfs_dir2_sfe_get_ftype( |
70 | struct xfs_dir2_sf_entry *sfep) | |
71 | { | |
72 | return XFS_DIR3_FT_UNKNOWN; | |
73 | } | |
74 | ||
75 | static void | |
76 | xfs_dir2_sfe_put_ftype( | |
77 | struct xfs_dir2_sf_entry *sfep, | |
c8ce540d | 78 | uint8_t ftype) |
4740175e DC |
79 | { |
80 | ASSERT(ftype < XFS_DIR3_FT_MAX); | |
81 | } | |
82 | ||
c8ce540d | 83 | static uint8_t |
4740175e DC |
84 | xfs_dir3_sfe_get_ftype( |
85 | struct xfs_dir2_sf_entry *sfep) | |
86 | { | |
c8ce540d | 87 | uint8_t ftype; |
4740175e DC |
88 | |
89 | ftype = sfep->name[sfep->namelen]; | |
90 | if (ftype >= XFS_DIR3_FT_MAX) | |
91 | return XFS_DIR3_FT_UNKNOWN; | |
92 | return ftype; | |
93 | } | |
94 | ||
95 | static void | |
96 | xfs_dir3_sfe_put_ftype( | |
97 | struct xfs_dir2_sf_entry *sfep, | |
c8ce540d | 98 | uint8_t ftype) |
4740175e DC |
99 | { |
100 | ASSERT(ftype < XFS_DIR3_FT_MAX); | |
101 | ||
102 | sfep->name[sfep->namelen] = ftype; | |
103 | } | |
104 | ||
105 | /* | |
106 | * Inode numbers in short-form directories can come in two versions, | |
107 | * either 4 bytes or 8 bytes wide. These helpers deal with the | |
108 | * two forms transparently by looking at the headers i8count field. | |
109 | * | |
110 | * For 64-bit inode number the most significant byte must be zero. | |
111 | */ | |
112 | static xfs_ino_t | |
113 | xfs_dir2_sf_get_ino( | |
114 | struct xfs_dir2_sf_hdr *hdr, | |
c8ce540d | 115 | uint8_t *from) |
4740175e DC |
116 | { |
117 | if (hdr->i8count) | |
266b6969 | 118 | return get_unaligned_be64(from) & 0x00ffffffffffffffULL; |
4740175e | 119 | else |
266b6969 | 120 | return get_unaligned_be32(from); |
4740175e DC |
121 | } |
122 | ||
123 | static void | |
124 | xfs_dir2_sf_put_ino( | |
125 | struct xfs_dir2_sf_hdr *hdr, | |
c8ce540d | 126 | uint8_t *to, |
4740175e DC |
127 | xfs_ino_t ino) |
128 | { | |
129 | ASSERT((ino & 0xff00000000000000ULL) == 0); | |
130 | ||
131 | if (hdr->i8count) | |
266b6969 | 132 | put_unaligned_be64(ino, to); |
4740175e | 133 | else |
266b6969 | 134 | put_unaligned_be32(ino, to); |
4740175e DC |
135 | } |
136 | ||
137 | static xfs_ino_t | |
138 | xfs_dir2_sf_get_parent_ino( | |
139 | struct xfs_dir2_sf_hdr *hdr) | |
140 | { | |
266b6969 | 141 | return xfs_dir2_sf_get_ino(hdr, hdr->parent); |
4740175e DC |
142 | } |
143 | ||
144 | static void | |
145 | xfs_dir2_sf_put_parent_ino( | |
146 | struct xfs_dir2_sf_hdr *hdr, | |
147 | xfs_ino_t ino) | |
148 | { | |
266b6969 | 149 | xfs_dir2_sf_put_ino(hdr, hdr->parent, ino); |
4740175e DC |
150 | } |
151 | ||
152 | /* | |
153 | * In short-form directory entries the inode numbers are stored at variable | |
154 | * offset behind the entry name. If the entry stores a filetype value, then it | |
155 | * sits between the name and the inode number. Hence the inode numbers may only | |
156 | * be accessed through the helpers below. | |
157 | */ | |
158 | static xfs_ino_t | |
159 | xfs_dir2_sfe_get_ino( | |
160 | struct xfs_dir2_sf_hdr *hdr, | |
161 | struct xfs_dir2_sf_entry *sfep) | |
162 | { | |
266b6969 | 163 | return xfs_dir2_sf_get_ino(hdr, &sfep->name[sfep->namelen]); |
4740175e DC |
164 | } |
165 | ||
166 | static void | |
167 | xfs_dir2_sfe_put_ino( | |
168 | struct xfs_dir2_sf_hdr *hdr, | |
169 | struct xfs_dir2_sf_entry *sfep, | |
170 | xfs_ino_t ino) | |
171 | { | |
266b6969 | 172 | xfs_dir2_sf_put_ino(hdr, &sfep->name[sfep->namelen], ino); |
4740175e DC |
173 | } |
174 | ||
175 | static xfs_ino_t | |
176 | xfs_dir3_sfe_get_ino( | |
177 | struct xfs_dir2_sf_hdr *hdr, | |
178 | struct xfs_dir2_sf_entry *sfep) | |
179 | { | |
266b6969 | 180 | return xfs_dir2_sf_get_ino(hdr, &sfep->name[sfep->namelen + 1]); |
4740175e DC |
181 | } |
182 | ||
183 | static void | |
184 | xfs_dir3_sfe_put_ino( | |
185 | struct xfs_dir2_sf_hdr *hdr, | |
186 | struct xfs_dir2_sf_entry *sfep, | |
187 | xfs_ino_t ino) | |
188 | { | |
266b6969 | 189 | xfs_dir2_sf_put_ino(hdr, &sfep->name[sfep->namelen + 1], ino); |
4740175e DC |
190 | } |
191 | ||
9d23fc85 DC |
192 | |
193 | /* | |
194 | * Directory data block operations | |
195 | */ | |
9d23fc85 | 196 | |
1c9a5b2e DC |
197 | /* |
198 | * For special situations, the dirent size ends up fixed because we always know | |
199 | * what the size of the entry is. That's true for the "." and "..", and | |
200 | * therefore we know that they are a fixed size and hence their offsets are | |
201 | * constant, as is the first entry. | |
202 | * | |
203 | * Hence, this calculation is written as a macro to be able to be calculated at | |
204 | * compile time and so certain offsets can be calculated directly in the | |
205 | * structure initaliser via the macro. There are two macros - one for dirents | |
206 | * with ftype and without so there are no unresolvable conditionals in the | |
207 | * calculations. We also use round_up() as XFS_DIR2_DATA_ALIGN is always a power | |
208 | * of 2 and the compiler doesn't reject it (unlike roundup()). | |
209 | */ | |
210 | #define XFS_DIR2_DATA_ENTSIZE(n) \ | |
211 | round_up((offsetof(struct xfs_dir2_data_entry, name[0]) + (n) + \ | |
212 | sizeof(xfs_dir2_data_off_t)), XFS_DIR2_DATA_ALIGN) | |
213 | ||
214 | #define XFS_DIR3_DATA_ENTSIZE(n) \ | |
215 | round_up((offsetof(struct xfs_dir2_data_entry, name[0]) + (n) + \ | |
c8ce540d | 216 | sizeof(xfs_dir2_data_off_t) + sizeof(uint8_t)), \ |
1c9a5b2e | 217 | XFS_DIR2_DATA_ALIGN) |
9d23fc85 DC |
218 | |
219 | static int | |
220 | xfs_dir2_data_entsize( | |
221 | int n) | |
222 | { | |
1c9a5b2e | 223 | return XFS_DIR2_DATA_ENTSIZE(n); |
9d23fc85 | 224 | } |
1c9a5b2e | 225 | |
9d23fc85 DC |
226 | static int |
227 | xfs_dir3_data_entsize( | |
228 | int n) | |
229 | { | |
1c9a5b2e | 230 | return XFS_DIR3_DATA_ENTSIZE(n); |
9d23fc85 DC |
231 | } |
232 | ||
c8ce540d | 233 | static uint8_t |
9d23fc85 DC |
234 | xfs_dir2_data_get_ftype( |
235 | struct xfs_dir2_data_entry *dep) | |
236 | { | |
237 | return XFS_DIR3_FT_UNKNOWN; | |
238 | } | |
239 | ||
240 | static void | |
241 | xfs_dir2_data_put_ftype( | |
242 | struct xfs_dir2_data_entry *dep, | |
c8ce540d | 243 | uint8_t ftype) |
9d23fc85 DC |
244 | { |
245 | ASSERT(ftype < XFS_DIR3_FT_MAX); | |
246 | } | |
247 | ||
c8ce540d | 248 | static uint8_t |
9d23fc85 DC |
249 | xfs_dir3_data_get_ftype( |
250 | struct xfs_dir2_data_entry *dep) | |
251 | { | |
c8ce540d | 252 | uint8_t ftype = dep->name[dep->namelen]; |
9d23fc85 | 253 | |
9d23fc85 DC |
254 | if (ftype >= XFS_DIR3_FT_MAX) |
255 | return XFS_DIR3_FT_UNKNOWN; | |
256 | return ftype; | |
257 | } | |
258 | ||
259 | static void | |
260 | xfs_dir3_data_put_ftype( | |
261 | struct xfs_dir2_data_entry *dep, | |
c8ce540d | 262 | uint8_t type) |
9d23fc85 DC |
263 | { |
264 | ASSERT(type < XFS_DIR3_FT_MAX); | |
265 | ASSERT(dep->namelen != 0); | |
266 | ||
267 | dep->name[dep->namelen] = type; | |
268 | } | |
269 | ||
270 | /* | |
271 | * Pointer to an entry's tag word. | |
272 | */ | |
273 | static __be16 * | |
274 | xfs_dir2_data_entry_tag_p( | |
275 | struct xfs_dir2_data_entry *dep) | |
276 | { | |
277 | return (__be16 *)((char *)dep + | |
278 | xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16)); | |
279 | } | |
280 | ||
281 | static __be16 * | |
282 | xfs_dir3_data_entry_tag_p( | |
283 | struct xfs_dir2_data_entry *dep) | |
284 | { | |
285 | return (__be16 *)((char *)dep + | |
286 | xfs_dir3_data_entsize(dep->namelen) - sizeof(__be16)); | |
287 | } | |
288 | ||
9d23fc85 DC |
289 | /* |
290 | * location of . and .. in data space (always block 0) | |
291 | */ | |
292 | static struct xfs_dir2_data_entry * | |
293 | xfs_dir2_data_dot_entry_p( | |
294 | struct xfs_dir2_data_hdr *hdr) | |
295 | { | |
296 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e | 297 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); |
9d23fc85 DC |
298 | } |
299 | ||
300 | static struct xfs_dir2_data_entry * | |
301 | xfs_dir2_data_dotdot_entry_p( | |
302 | struct xfs_dir2_data_hdr *hdr) | |
303 | { | |
304 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e DC |
305 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + |
306 | XFS_DIR2_DATA_ENTSIZE(1)); | |
9d23fc85 DC |
307 | } |
308 | ||
309 | static struct xfs_dir2_data_entry * | |
310 | xfs_dir2_data_first_entry_p( | |
311 | struct xfs_dir2_data_hdr *hdr) | |
312 | { | |
313 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e DC |
314 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + |
315 | XFS_DIR2_DATA_ENTSIZE(1) + | |
316 | XFS_DIR2_DATA_ENTSIZE(2)); | |
9d23fc85 DC |
317 | } |
318 | ||
b01ef655 DC |
319 | static struct xfs_dir2_data_entry * |
320 | xfs_dir2_ftype_data_dotdot_entry_p( | |
321 | struct xfs_dir2_data_hdr *hdr) | |
322 | { | |
323 | return (struct xfs_dir2_data_entry *) | |
324 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + | |
325 | XFS_DIR3_DATA_ENTSIZE(1)); | |
326 | } | |
327 | ||
328 | static struct xfs_dir2_data_entry * | |
329 | xfs_dir2_ftype_data_first_entry_p( | |
330 | struct xfs_dir2_data_hdr *hdr) | |
331 | { | |
332 | return (struct xfs_dir2_data_entry *) | |
333 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + | |
334 | XFS_DIR3_DATA_ENTSIZE(1) + | |
335 | XFS_DIR3_DATA_ENTSIZE(2)); | |
336 | } | |
337 | ||
9d23fc85 DC |
338 | static struct xfs_dir2_data_entry * |
339 | xfs_dir3_data_dot_entry_p( | |
340 | struct xfs_dir2_data_hdr *hdr) | |
341 | { | |
342 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e | 343 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); |
9d23fc85 DC |
344 | } |
345 | ||
346 | static struct xfs_dir2_data_entry * | |
347 | xfs_dir3_data_dotdot_entry_p( | |
348 | struct xfs_dir2_data_hdr *hdr) | |
349 | { | |
350 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e DC |
351 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + |
352 | XFS_DIR3_DATA_ENTSIZE(1)); | |
9d23fc85 DC |
353 | } |
354 | ||
355 | static struct xfs_dir2_data_entry * | |
356 | xfs_dir3_data_first_entry_p( | |
357 | struct xfs_dir2_data_hdr *hdr) | |
358 | { | |
359 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e DC |
360 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + |
361 | XFS_DIR3_DATA_ENTSIZE(1) + | |
362 | XFS_DIR3_DATA_ENTSIZE(2)); | |
9d23fc85 DC |
363 | } |
364 | ||
2ca98774 DC |
365 | static struct xfs_dir2_data_free * |
366 | xfs_dir2_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) | |
367 | { | |
368 | return hdr->bestfree; | |
369 | } | |
370 | ||
371 | static struct xfs_dir2_data_free * | |
372 | xfs_dir3_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) | |
373 | { | |
374 | return ((struct xfs_dir3_data_hdr *)hdr)->best_free; | |
375 | } | |
376 | ||
2ca98774 DC |
377 | static struct xfs_dir2_data_entry * |
378 | xfs_dir2_data_entry_p(struct xfs_dir2_data_hdr *hdr) | |
379 | { | |
380 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e | 381 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); |
2ca98774 DC |
382 | } |
383 | ||
384 | static struct xfs_dir2_data_unused * | |
385 | xfs_dir2_data_unused_p(struct xfs_dir2_data_hdr *hdr) | |
386 | { | |
387 | return (struct xfs_dir2_data_unused *) | |
1c9a5b2e | 388 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); |
2ca98774 DC |
389 | } |
390 | ||
391 | static struct xfs_dir2_data_entry * | |
392 | xfs_dir3_data_entry_p(struct xfs_dir2_data_hdr *hdr) | |
393 | { | |
394 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e | 395 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); |
2ca98774 DC |
396 | } |
397 | ||
398 | static struct xfs_dir2_data_unused * | |
399 | xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr) | |
400 | { | |
401 | return (struct xfs_dir2_data_unused *) | |
1c9a5b2e | 402 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); |
2ca98774 DC |
403 | } |
404 | ||
4141956a DC |
405 | |
406 | /* | |
407 | * Directory Leaf block operations | |
408 | */ | |
4141956a | 409 | static int |
8f66193c | 410 | xfs_dir2_max_leaf_ents(struct xfs_da_geometry *geo) |
4141956a | 411 | { |
8f66193c | 412 | return (geo->blksize - sizeof(struct xfs_dir2_leaf_hdr)) / |
4141956a DC |
413 | (uint)sizeof(struct xfs_dir2_leaf_entry); |
414 | } | |
415 | ||
416 | static struct xfs_dir2_leaf_entry * | |
417 | xfs_dir2_leaf_ents_p(struct xfs_dir2_leaf *lp) | |
418 | { | |
419 | return lp->__ents; | |
420 | } | |
421 | ||
01ba43b8 | 422 | static int |
8f66193c | 423 | xfs_dir3_max_leaf_ents(struct xfs_da_geometry *geo) |
4141956a | 424 | { |
8f66193c | 425 | return (geo->blksize - sizeof(struct xfs_dir3_leaf_hdr)) / |
4141956a DC |
426 | (uint)sizeof(struct xfs_dir2_leaf_entry); |
427 | } | |
428 | ||
01ba43b8 | 429 | static struct xfs_dir2_leaf_entry * |
4141956a DC |
430 | xfs_dir3_leaf_ents_p(struct xfs_dir2_leaf *lp) |
431 | { | |
432 | return ((struct xfs_dir3_leaf *)lp)->__ents; | |
433 | } | |
434 | ||
01ba43b8 DC |
435 | static void |
436 | xfs_dir2_leaf_hdr_from_disk( | |
437 | struct xfs_dir3_icleaf_hdr *to, | |
438 | struct xfs_dir2_leaf *from) | |
439 | { | |
440 | to->forw = be32_to_cpu(from->hdr.info.forw); | |
441 | to->back = be32_to_cpu(from->hdr.info.back); | |
442 | to->magic = be16_to_cpu(from->hdr.info.magic); | |
443 | to->count = be16_to_cpu(from->hdr.count); | |
444 | to->stale = be16_to_cpu(from->hdr.stale); | |
445 | ||
446 | ASSERT(to->magic == XFS_DIR2_LEAF1_MAGIC || | |
447 | to->magic == XFS_DIR2_LEAFN_MAGIC); | |
448 | } | |
449 | ||
450 | static void | |
451 | xfs_dir2_leaf_hdr_to_disk( | |
452 | struct xfs_dir2_leaf *to, | |
453 | struct xfs_dir3_icleaf_hdr *from) | |
454 | { | |
455 | ASSERT(from->magic == XFS_DIR2_LEAF1_MAGIC || | |
456 | from->magic == XFS_DIR2_LEAFN_MAGIC); | |
457 | ||
458 | to->hdr.info.forw = cpu_to_be32(from->forw); | |
459 | to->hdr.info.back = cpu_to_be32(from->back); | |
460 | to->hdr.info.magic = cpu_to_be16(from->magic); | |
461 | to->hdr.count = cpu_to_be16(from->count); | |
462 | to->hdr.stale = cpu_to_be16(from->stale); | |
463 | } | |
464 | ||
465 | static void | |
466 | xfs_dir3_leaf_hdr_from_disk( | |
467 | struct xfs_dir3_icleaf_hdr *to, | |
468 | struct xfs_dir2_leaf *from) | |
469 | { | |
470 | struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)from; | |
471 | ||
472 | to->forw = be32_to_cpu(hdr3->info.hdr.forw); | |
473 | to->back = be32_to_cpu(hdr3->info.hdr.back); | |
474 | to->magic = be16_to_cpu(hdr3->info.hdr.magic); | |
475 | to->count = be16_to_cpu(hdr3->count); | |
476 | to->stale = be16_to_cpu(hdr3->stale); | |
477 | ||
478 | ASSERT(to->magic == XFS_DIR3_LEAF1_MAGIC || | |
479 | to->magic == XFS_DIR3_LEAFN_MAGIC); | |
480 | } | |
481 | ||
482 | static void | |
483 | xfs_dir3_leaf_hdr_to_disk( | |
484 | struct xfs_dir2_leaf *to, | |
485 | struct xfs_dir3_icleaf_hdr *from) | |
486 | { | |
487 | struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)to; | |
488 | ||
489 | ASSERT(from->magic == XFS_DIR3_LEAF1_MAGIC || | |
490 | from->magic == XFS_DIR3_LEAFN_MAGIC); | |
491 | ||
492 | hdr3->info.hdr.forw = cpu_to_be32(from->forw); | |
493 | hdr3->info.hdr.back = cpu_to_be32(from->back); | |
494 | hdr3->info.hdr.magic = cpu_to_be16(from->magic); | |
495 | hdr3->count = cpu_to_be16(from->count); | |
496 | hdr3->stale = cpu_to_be16(from->stale); | |
497 | } | |
498 | ||
499 | ||
4bceb18f DC |
500 | /* |
501 | * Directory/Attribute Node block operations | |
502 | */ | |
4bceb18f DC |
503 | static struct xfs_da_node_entry * |
504 | xfs_da2_node_tree_p(struct xfs_da_intnode *dap) | |
505 | { | |
506 | return dap->__btree; | |
507 | } | |
508 | ||
1c9a5b2e | 509 | static struct xfs_da_node_entry * |
4bceb18f DC |
510 | xfs_da3_node_tree_p(struct xfs_da_intnode *dap) |
511 | { | |
512 | return ((struct xfs_da3_intnode *)dap)->__btree; | |
513 | } | |
514 | ||
01ba43b8 DC |
515 | static void |
516 | xfs_da2_node_hdr_from_disk( | |
517 | struct xfs_da3_icnode_hdr *to, | |
518 | struct xfs_da_intnode *from) | |
519 | { | |
520 | ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC)); | |
521 | to->forw = be32_to_cpu(from->hdr.info.forw); | |
522 | to->back = be32_to_cpu(from->hdr.info.back); | |
523 | to->magic = be16_to_cpu(from->hdr.info.magic); | |
524 | to->count = be16_to_cpu(from->hdr.__count); | |
525 | to->level = be16_to_cpu(from->hdr.__level); | |
526 | } | |
527 | ||
528 | static void | |
529 | xfs_da2_node_hdr_to_disk( | |
530 | struct xfs_da_intnode *to, | |
531 | struct xfs_da3_icnode_hdr *from) | |
532 | { | |
533 | ASSERT(from->magic == XFS_DA_NODE_MAGIC); | |
534 | to->hdr.info.forw = cpu_to_be32(from->forw); | |
535 | to->hdr.info.back = cpu_to_be32(from->back); | |
536 | to->hdr.info.magic = cpu_to_be16(from->magic); | |
537 | to->hdr.__count = cpu_to_be16(from->count); | |
538 | to->hdr.__level = cpu_to_be16(from->level); | |
539 | } | |
540 | ||
541 | static void | |
542 | xfs_da3_node_hdr_from_disk( | |
543 | struct xfs_da3_icnode_hdr *to, | |
544 | struct xfs_da_intnode *from) | |
545 | { | |
546 | struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)from; | |
547 | ||
548 | ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)); | |
549 | to->forw = be32_to_cpu(hdr3->info.hdr.forw); | |
550 | to->back = be32_to_cpu(hdr3->info.hdr.back); | |
551 | to->magic = be16_to_cpu(hdr3->info.hdr.magic); | |
552 | to->count = be16_to_cpu(hdr3->__count); | |
553 | to->level = be16_to_cpu(hdr3->__level); | |
554 | } | |
555 | ||
556 | static void | |
557 | xfs_da3_node_hdr_to_disk( | |
558 | struct xfs_da_intnode *to, | |
559 | struct xfs_da3_icnode_hdr *from) | |
560 | { | |
561 | struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)to; | |
562 | ||
563 | ASSERT(from->magic == XFS_DA3_NODE_MAGIC); | |
564 | hdr3->info.hdr.forw = cpu_to_be32(from->forw); | |
565 | hdr3->info.hdr.back = cpu_to_be32(from->back); | |
566 | hdr3->info.hdr.magic = cpu_to_be16(from->magic); | |
567 | hdr3->__count = cpu_to_be16(from->count); | |
568 | hdr3->__level = cpu_to_be16(from->level); | |
569 | } | |
570 | ||
571 | ||
572 | /* | |
573 | * Directory free space block operations | |
574 | */ | |
24dd0f54 | 575 | static int |
8f66193c | 576 | xfs_dir2_free_max_bests(struct xfs_da_geometry *geo) |
24dd0f54 | 577 | { |
8f66193c | 578 | return (geo->blksize - sizeof(struct xfs_dir2_free_hdr)) / |
24dd0f54 DC |
579 | sizeof(xfs_dir2_data_off_t); |
580 | } | |
581 | ||
582 | static __be16 * | |
583 | xfs_dir2_free_bests_p(struct xfs_dir2_free *free) | |
584 | { | |
1c9a5b2e | 585 | return (__be16 *)((char *)free + sizeof(struct xfs_dir2_free_hdr)); |
24dd0f54 DC |
586 | } |
587 | ||
588 | /* | |
589 | * Convert data space db to the corresponding free db. | |
590 | */ | |
591 | static xfs_dir2_db_t | |
8f66193c | 592 | xfs_dir2_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db) |
24dd0f54 | 593 | { |
8f66193c DC |
594 | return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) + |
595 | (db / xfs_dir2_free_max_bests(geo)); | |
24dd0f54 DC |
596 | } |
597 | ||
598 | /* | |
599 | * Convert data space db to the corresponding index in a free db. | |
600 | */ | |
601 | static int | |
8f66193c | 602 | xfs_dir2_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db) |
24dd0f54 | 603 | { |
8f66193c | 604 | return db % xfs_dir2_free_max_bests(geo); |
24dd0f54 DC |
605 | } |
606 | ||
24dd0f54 | 607 | static int |
8f66193c | 608 | xfs_dir3_free_max_bests(struct xfs_da_geometry *geo) |
24dd0f54 | 609 | { |
8f66193c | 610 | return (geo->blksize - sizeof(struct xfs_dir3_free_hdr)) / |
24dd0f54 DC |
611 | sizeof(xfs_dir2_data_off_t); |
612 | } | |
613 | ||
614 | static __be16 * | |
615 | xfs_dir3_free_bests_p(struct xfs_dir2_free *free) | |
616 | { | |
1c9a5b2e | 617 | return (__be16 *)((char *)free + sizeof(struct xfs_dir3_free_hdr)); |
24dd0f54 DC |
618 | } |
619 | ||
620 | /* | |
621 | * Convert data space db to the corresponding free db. | |
622 | */ | |
623 | static xfs_dir2_db_t | |
8f66193c | 624 | xfs_dir3_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db) |
24dd0f54 | 625 | { |
8f66193c DC |
626 | return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) + |
627 | (db / xfs_dir3_free_max_bests(geo)); | |
24dd0f54 DC |
628 | } |
629 | ||
630 | /* | |
631 | * Convert data space db to the corresponding index in a free db. | |
632 | */ | |
633 | static int | |
8f66193c | 634 | xfs_dir3_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db) |
24dd0f54 | 635 | { |
8f66193c | 636 | return db % xfs_dir3_free_max_bests(geo); |
24dd0f54 DC |
637 | } |
638 | ||
01ba43b8 DC |
639 | static void |
640 | xfs_dir2_free_hdr_from_disk( | |
641 | struct xfs_dir3_icfree_hdr *to, | |
642 | struct xfs_dir2_free *from) | |
643 | { | |
644 | to->magic = be32_to_cpu(from->hdr.magic); | |
645 | to->firstdb = be32_to_cpu(from->hdr.firstdb); | |
646 | to->nvalid = be32_to_cpu(from->hdr.nvalid); | |
647 | to->nused = be32_to_cpu(from->hdr.nused); | |
648 | ASSERT(to->magic == XFS_DIR2_FREE_MAGIC); | |
649 | } | |
650 | ||
651 | static void | |
652 | xfs_dir2_free_hdr_to_disk( | |
653 | struct xfs_dir2_free *to, | |
654 | struct xfs_dir3_icfree_hdr *from) | |
655 | { | |
656 | ASSERT(from->magic == XFS_DIR2_FREE_MAGIC); | |
657 | ||
658 | to->hdr.magic = cpu_to_be32(from->magic); | |
659 | to->hdr.firstdb = cpu_to_be32(from->firstdb); | |
660 | to->hdr.nvalid = cpu_to_be32(from->nvalid); | |
661 | to->hdr.nused = cpu_to_be32(from->nused); | |
662 | } | |
663 | ||
664 | static void | |
665 | xfs_dir3_free_hdr_from_disk( | |
666 | struct xfs_dir3_icfree_hdr *to, | |
667 | struct xfs_dir2_free *from) | |
668 | { | |
669 | struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)from; | |
670 | ||
671 | to->magic = be32_to_cpu(hdr3->hdr.magic); | |
672 | to->firstdb = be32_to_cpu(hdr3->firstdb); | |
673 | to->nvalid = be32_to_cpu(hdr3->nvalid); | |
674 | to->nused = be32_to_cpu(hdr3->nused); | |
675 | ||
676 | ASSERT(to->magic == XFS_DIR3_FREE_MAGIC); | |
677 | } | |
678 | ||
679 | static void | |
680 | xfs_dir3_free_hdr_to_disk( | |
681 | struct xfs_dir2_free *to, | |
682 | struct xfs_dir3_icfree_hdr *from) | |
683 | { | |
684 | struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)to; | |
685 | ||
686 | ASSERT(from->magic == XFS_DIR3_FREE_MAGIC); | |
687 | ||
688 | hdr3->hdr.magic = cpu_to_be32(from->magic); | |
689 | hdr3->firstdb = cpu_to_be32(from->firstdb); | |
690 | hdr3->nvalid = cpu_to_be32(from->nvalid); | |
691 | hdr3->nused = cpu_to_be32(from->nused); | |
692 | } | |
693 | ||
632b89e8 | 694 | static const struct xfs_dir_ops xfs_dir2_ops = { |
32c5483a DC |
695 | .sf_entsize = xfs_dir2_sf_entsize, |
696 | .sf_nextentry = xfs_dir2_sf_nextentry, | |
4740175e DC |
697 | .sf_get_ftype = xfs_dir2_sfe_get_ftype, |
698 | .sf_put_ftype = xfs_dir2_sfe_put_ftype, | |
699 | .sf_get_ino = xfs_dir2_sfe_get_ino, | |
700 | .sf_put_ino = xfs_dir2_sfe_put_ino, | |
701 | .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, | |
702 | .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, | |
9d23fc85 DC |
703 | |
704 | .data_entsize = xfs_dir2_data_entsize, | |
705 | .data_get_ftype = xfs_dir2_data_get_ftype, | |
706 | .data_put_ftype = xfs_dir2_data_put_ftype, | |
707 | .data_entry_tag_p = xfs_dir2_data_entry_tag_p, | |
2ca98774 | 708 | .data_bestfree_p = xfs_dir2_data_bestfree_p, |
9d23fc85 | 709 | |
1c9a5b2e DC |
710 | .data_dot_offset = sizeof(struct xfs_dir2_data_hdr), |
711 | .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) + | |
712 | XFS_DIR2_DATA_ENTSIZE(1), | |
713 | .data_first_offset = sizeof(struct xfs_dir2_data_hdr) + | |
714 | XFS_DIR2_DATA_ENTSIZE(1) + | |
715 | XFS_DIR2_DATA_ENTSIZE(2), | |
716 | .data_entry_offset = sizeof(struct xfs_dir2_data_hdr), | |
2ca98774 | 717 | |
9d23fc85 DC |
718 | .data_dot_entry_p = xfs_dir2_data_dot_entry_p, |
719 | .data_dotdot_entry_p = xfs_dir2_data_dotdot_entry_p, | |
720 | .data_first_entry_p = xfs_dir2_data_first_entry_p, | |
2ca98774 DC |
721 | .data_entry_p = xfs_dir2_data_entry_p, |
722 | .data_unused_p = xfs_dir2_data_unused_p, | |
723 | ||
1c9a5b2e | 724 | .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), |
01ba43b8 DC |
725 | .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, |
726 | .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, | |
4141956a DC |
727 | .leaf_max_ents = xfs_dir2_max_leaf_ents, |
728 | .leaf_ents_p = xfs_dir2_leaf_ents_p, | |
729 | ||
1c9a5b2e | 730 | .node_hdr_size = sizeof(struct xfs_da_node_hdr), |
01ba43b8 DC |
731 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, |
732 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
4bceb18f | 733 | .node_tree_p = xfs_da2_node_tree_p, |
01ba43b8 | 734 | |
1c9a5b2e | 735 | .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), |
01ba43b8 DC |
736 | .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, |
737 | .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, | |
24dd0f54 DC |
738 | .free_max_bests = xfs_dir2_free_max_bests, |
739 | .free_bests_p = xfs_dir2_free_bests_p, | |
740 | .db_to_fdb = xfs_dir2_db_to_fdb, | |
741 | .db_to_fdindex = xfs_dir2_db_to_fdindex, | |
32c5483a DC |
742 | }; |
743 | ||
632b89e8 | 744 | static const struct xfs_dir_ops xfs_dir2_ftype_ops = { |
32c5483a DC |
745 | .sf_entsize = xfs_dir3_sf_entsize, |
746 | .sf_nextentry = xfs_dir3_sf_nextentry, | |
4740175e DC |
747 | .sf_get_ftype = xfs_dir3_sfe_get_ftype, |
748 | .sf_put_ftype = xfs_dir3_sfe_put_ftype, | |
749 | .sf_get_ino = xfs_dir3_sfe_get_ino, | |
750 | .sf_put_ino = xfs_dir3_sfe_put_ino, | |
751 | .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, | |
752 | .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, | |
9d23fc85 DC |
753 | |
754 | .data_entsize = xfs_dir3_data_entsize, | |
755 | .data_get_ftype = xfs_dir3_data_get_ftype, | |
756 | .data_put_ftype = xfs_dir3_data_put_ftype, | |
757 | .data_entry_tag_p = xfs_dir3_data_entry_tag_p, | |
2ca98774 | 758 | .data_bestfree_p = xfs_dir2_data_bestfree_p, |
9d23fc85 | 759 | |
1c9a5b2e DC |
760 | .data_dot_offset = sizeof(struct xfs_dir2_data_hdr), |
761 | .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) + | |
762 | XFS_DIR3_DATA_ENTSIZE(1), | |
763 | .data_first_offset = sizeof(struct xfs_dir2_data_hdr) + | |
764 | XFS_DIR3_DATA_ENTSIZE(1) + | |
765 | XFS_DIR3_DATA_ENTSIZE(2), | |
766 | .data_entry_offset = sizeof(struct xfs_dir2_data_hdr), | |
2ca98774 | 767 | |
9d23fc85 | 768 | .data_dot_entry_p = xfs_dir2_data_dot_entry_p, |
b01ef655 DC |
769 | .data_dotdot_entry_p = xfs_dir2_ftype_data_dotdot_entry_p, |
770 | .data_first_entry_p = xfs_dir2_ftype_data_first_entry_p, | |
2ca98774 DC |
771 | .data_entry_p = xfs_dir2_data_entry_p, |
772 | .data_unused_p = xfs_dir2_data_unused_p, | |
4141956a | 773 | |
1c9a5b2e | 774 | .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), |
01ba43b8 DC |
775 | .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, |
776 | .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, | |
4141956a DC |
777 | .leaf_max_ents = xfs_dir2_max_leaf_ents, |
778 | .leaf_ents_p = xfs_dir2_leaf_ents_p, | |
4bceb18f | 779 | |
1c9a5b2e | 780 | .node_hdr_size = sizeof(struct xfs_da_node_hdr), |
01ba43b8 DC |
781 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, |
782 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
4bceb18f | 783 | .node_tree_p = xfs_da2_node_tree_p, |
01ba43b8 | 784 | |
1c9a5b2e | 785 | .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), |
01ba43b8 DC |
786 | .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, |
787 | .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, | |
24dd0f54 DC |
788 | .free_max_bests = xfs_dir2_free_max_bests, |
789 | .free_bests_p = xfs_dir2_free_bests_p, | |
790 | .db_to_fdb = xfs_dir2_db_to_fdb, | |
791 | .db_to_fdindex = xfs_dir2_db_to_fdindex, | |
32c5483a DC |
792 | }; |
793 | ||
632b89e8 | 794 | static const struct xfs_dir_ops xfs_dir3_ops = { |
32c5483a DC |
795 | .sf_entsize = xfs_dir3_sf_entsize, |
796 | .sf_nextentry = xfs_dir3_sf_nextentry, | |
4740175e DC |
797 | .sf_get_ftype = xfs_dir3_sfe_get_ftype, |
798 | .sf_put_ftype = xfs_dir3_sfe_put_ftype, | |
799 | .sf_get_ino = xfs_dir3_sfe_get_ino, | |
800 | .sf_put_ino = xfs_dir3_sfe_put_ino, | |
801 | .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, | |
802 | .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, | |
9d23fc85 DC |
803 | |
804 | .data_entsize = xfs_dir3_data_entsize, | |
805 | .data_get_ftype = xfs_dir3_data_get_ftype, | |
806 | .data_put_ftype = xfs_dir3_data_put_ftype, | |
807 | .data_entry_tag_p = xfs_dir3_data_entry_tag_p, | |
2ca98774 | 808 | .data_bestfree_p = xfs_dir3_data_bestfree_p, |
9d23fc85 | 809 | |
1c9a5b2e DC |
810 | .data_dot_offset = sizeof(struct xfs_dir3_data_hdr), |
811 | .data_dotdot_offset = sizeof(struct xfs_dir3_data_hdr) + | |
812 | XFS_DIR3_DATA_ENTSIZE(1), | |
813 | .data_first_offset = sizeof(struct xfs_dir3_data_hdr) + | |
814 | XFS_DIR3_DATA_ENTSIZE(1) + | |
815 | XFS_DIR3_DATA_ENTSIZE(2), | |
816 | .data_entry_offset = sizeof(struct xfs_dir3_data_hdr), | |
2ca98774 | 817 | |
9d23fc85 DC |
818 | .data_dot_entry_p = xfs_dir3_data_dot_entry_p, |
819 | .data_dotdot_entry_p = xfs_dir3_data_dotdot_entry_p, | |
820 | .data_first_entry_p = xfs_dir3_data_first_entry_p, | |
2ca98774 DC |
821 | .data_entry_p = xfs_dir3_data_entry_p, |
822 | .data_unused_p = xfs_dir3_data_unused_p, | |
4141956a | 823 | |
1c9a5b2e | 824 | .leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr), |
01ba43b8 DC |
825 | .leaf_hdr_to_disk = xfs_dir3_leaf_hdr_to_disk, |
826 | .leaf_hdr_from_disk = xfs_dir3_leaf_hdr_from_disk, | |
4141956a DC |
827 | .leaf_max_ents = xfs_dir3_max_leaf_ents, |
828 | .leaf_ents_p = xfs_dir3_leaf_ents_p, | |
4bceb18f | 829 | |
1c9a5b2e | 830 | .node_hdr_size = sizeof(struct xfs_da3_node_hdr), |
01ba43b8 DC |
831 | .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, |
832 | .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, | |
4bceb18f | 833 | .node_tree_p = xfs_da3_node_tree_p, |
01ba43b8 | 834 | |
1c9a5b2e | 835 | .free_hdr_size = sizeof(struct xfs_dir3_free_hdr), |
01ba43b8 DC |
836 | .free_hdr_to_disk = xfs_dir3_free_hdr_to_disk, |
837 | .free_hdr_from_disk = xfs_dir3_free_hdr_from_disk, | |
24dd0f54 DC |
838 | .free_max_bests = xfs_dir3_free_max_bests, |
839 | .free_bests_p = xfs_dir3_free_bests_p, | |
840 | .db_to_fdb = xfs_dir3_db_to_fdb, | |
841 | .db_to_fdindex = xfs_dir3_db_to_fdindex, | |
4bceb18f DC |
842 | }; |
843 | ||
632b89e8 | 844 | static const struct xfs_dir_ops xfs_dir2_nondir_ops = { |
1c9a5b2e | 845 | .node_hdr_size = sizeof(struct xfs_da_node_hdr), |
01ba43b8 DC |
846 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, |
847 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
4bceb18f DC |
848 | .node_tree_p = xfs_da2_node_tree_p, |
849 | }; | |
850 | ||
632b89e8 | 851 | static const struct xfs_dir_ops xfs_dir3_nondir_ops = { |
1c9a5b2e | 852 | .node_hdr_size = sizeof(struct xfs_da3_node_hdr), |
01ba43b8 DC |
853 | .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, |
854 | .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, | |
4bceb18f | 855 | .node_tree_p = xfs_da3_node_tree_p, |
32c5483a | 856 | }; |
4141956a DC |
857 | |
858 | /* | |
859 | * Return the ops structure according to the current config. If we are passed | |
860 | * an inode, then that overrides the default config we use which is based on | |
861 | * feature bits. | |
862 | */ | |
863 | const struct xfs_dir_ops * | |
864 | xfs_dir_get_ops( | |
865 | struct xfs_mount *mp, | |
866 | struct xfs_inode *dp) | |
867 | { | |
868 | if (dp) | |
869 | return dp->d_ops; | |
870 | if (mp->m_dir_inode_ops) | |
871 | return mp->m_dir_inode_ops; | |
872 | if (xfs_sb_version_hascrc(&mp->m_sb)) | |
873 | return &xfs_dir3_ops; | |
874 | if (xfs_sb_version_hasftype(&mp->m_sb)) | |
875 | return &xfs_dir2_ftype_ops; | |
876 | return &xfs_dir2_ops; | |
877 | } | |
4bceb18f DC |
878 | |
879 | const struct xfs_dir_ops * | |
880 | xfs_nondir_get_ops( | |
881 | struct xfs_mount *mp, | |
882 | struct xfs_inode *dp) | |
883 | { | |
884 | if (dp) | |
885 | return dp->d_ops; | |
886 | if (mp->m_nondir_inode_ops) | |
887 | return mp->m_nondir_inode_ops; | |
888 | if (xfs_sb_version_hascrc(&mp->m_sb)) | |
889 | return &xfs_dir3_nondir_ops; | |
890 | return &xfs_dir2_nondir_ops; | |
891 | } |