]>
Commit | Line | Data |
---|---|---|
37b3b4d6 | 1 | // SPDX-License-Identifier: GPL-2.0 |
ff105f75 DC |
2 | /* |
3 | * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. | |
4 | * Copyright (c) 2013 Red Hat, Inc. | |
5 | * All Rights Reserved. | |
ff105f75 | 6 | */ |
9c799827 | 7 | #include "libxfs_priv.h" |
b626fb59 DC |
8 | #include "xfs_fs.h" |
9 | #include "xfs_shared.h" | |
10 | #include "xfs_format.h" | |
11 | #include "xfs_log_format.h" | |
12 | #include "xfs_trans_resv.h" | |
13 | #include "xfs_mount.h" | |
14 | #include "xfs_da_format.h" | |
15 | #include "xfs_da_btree.h" | |
16 | #include "xfs_inode.h" | |
17 | #include "xfs_dir2.h" | |
18 | #include "xfs_dir2_priv.h" | |
ff105f75 DC |
19 | |
20 | /* | |
21 | * Shortform directory ops | |
22 | */ | |
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 */ | |
d8bf9c63 | 31 | count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE; /* ino # */ |
ff105f75 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 | { | |
4a492e72 | 40 | return xfs_dir2_sf_entsize(hdr, len) + sizeof(uint8_t); |
ff105f75 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 | ||
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 | */ | |
4a492e72 | 68 | static uint8_t |
ff105f75 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, | |
4a492e72 | 78 | uint8_t ftype) |
ff105f75 DC |
79 | { |
80 | ASSERT(ftype < XFS_DIR3_FT_MAX); | |
81 | } | |
82 | ||
4a492e72 | 83 | static uint8_t |
ff105f75 DC |
84 | xfs_dir3_sfe_get_ftype( |
85 | struct xfs_dir2_sf_entry *sfep) | |
86 | { | |
4a492e72 | 87 | uint8_t ftype; |
ff105f75 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, | |
4a492e72 | 98 | uint8_t ftype) |
ff105f75 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, | |
4a492e72 | 115 | uint8_t *from) |
ff105f75 DC |
116 | { |
117 | if (hdr->i8count) | |
d8bf9c63 | 118 | return get_unaligned_be64(from) & 0x00ffffffffffffffULL; |
ff105f75 | 119 | else |
d8bf9c63 | 120 | return get_unaligned_be32(from); |
ff105f75 DC |
121 | } |
122 | ||
123 | static void | |
124 | xfs_dir2_sf_put_ino( | |
125 | struct xfs_dir2_sf_hdr *hdr, | |
4a492e72 | 126 | uint8_t *to, |
ff105f75 DC |
127 | xfs_ino_t ino) |
128 | { | |
129 | ASSERT((ino & 0xff00000000000000ULL) == 0); | |
130 | ||
131 | if (hdr->i8count) | |
d8bf9c63 | 132 | put_unaligned_be64(ino, to); |
ff105f75 | 133 | else |
d8bf9c63 | 134 | put_unaligned_be32(ino, to); |
ff105f75 DC |
135 | } |
136 | ||
137 | static xfs_ino_t | |
138 | xfs_dir2_sf_get_parent_ino( | |
139 | struct xfs_dir2_sf_hdr *hdr) | |
140 | { | |
d8bf9c63 | 141 | return xfs_dir2_sf_get_ino(hdr, hdr->parent); |
ff105f75 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 | { | |
d8bf9c63 | 149 | xfs_dir2_sf_put_ino(hdr, hdr->parent, ino); |
ff105f75 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 | { | |
d8bf9c63 | 163 | return xfs_dir2_sf_get_ino(hdr, &sfep->name[sfep->namelen]); |
ff105f75 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 | { | |
d8bf9c63 | 172 | xfs_dir2_sf_put_ino(hdr, &sfep->name[sfep->namelen], ino); |
ff105f75 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 | { | |
d8bf9c63 | 180 | return xfs_dir2_sf_get_ino(hdr, &sfep->name[sfep->namelen + 1]); |
ff105f75 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 | { | |
d8bf9c63 | 189 | xfs_dir2_sf_put_ino(hdr, &sfep->name[sfep->namelen + 1], ino); |
ff105f75 DC |
190 | } |
191 | ||
192 | ||
193 | /* | |
194 | * Directory data block operations | |
195 | */ | |
196 | ||
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) + \ | |
4a492e72 | 216 | sizeof(xfs_dir2_data_off_t) + sizeof(uint8_t)), \ |
ff105f75 DC |
217 | XFS_DIR2_DATA_ALIGN) |
218 | ||
219 | static int | |
220 | xfs_dir2_data_entsize( | |
221 | int n) | |
222 | { | |
223 | return XFS_DIR2_DATA_ENTSIZE(n); | |
224 | } | |
225 | ||
226 | static int | |
227 | xfs_dir3_data_entsize( | |
228 | int n) | |
229 | { | |
230 | return XFS_DIR3_DATA_ENTSIZE(n); | |
231 | } | |
232 | ||
4a492e72 | 233 | static uint8_t |
ff105f75 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, | |
4a492e72 | 243 | uint8_t ftype) |
ff105f75 DC |
244 | { |
245 | ASSERT(ftype < XFS_DIR3_FT_MAX); | |
246 | } | |
247 | ||
4a492e72 | 248 | static uint8_t |
ff105f75 DC |
249 | xfs_dir3_data_get_ftype( |
250 | struct xfs_dir2_data_entry *dep) | |
251 | { | |
4a492e72 | 252 | uint8_t ftype = dep->name[dep->namelen]; |
ff105f75 | 253 | |
ff105f75 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, | |
4a492e72 | 262 | uint8_t type) |
ff105f75 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 | ||
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 *) | |
297 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); | |
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 *) | |
305 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + | |
306 | XFS_DIR2_DATA_ENTSIZE(1)); | |
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 *) | |
314 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + | |
315 | XFS_DIR2_DATA_ENTSIZE(1) + | |
316 | XFS_DIR2_DATA_ENTSIZE(2)); | |
317 | } | |
318 | ||
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 | ||
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 *) | |
343 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); | |
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 *) | |
351 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + | |
352 | XFS_DIR3_DATA_ENTSIZE(1)); | |
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 *) | |
360 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + | |
361 | XFS_DIR3_DATA_ENTSIZE(1) + | |
362 | XFS_DIR3_DATA_ENTSIZE(2)); | |
363 | } | |
364 | ||
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 | ||
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 *) | |
381 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); | |
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 *) | |
388 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); | |
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 *) | |
395 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); | |
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 *) | |
402 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); | |
403 | } | |
404 | ||
405 | ||
406 | /* | |
407 | * Directory Leaf block operations | |
408 | */ | |
409 | static int | |
410 | xfs_dir2_max_leaf_ents(struct xfs_da_geometry *geo) | |
411 | { | |
412 | return (geo->blksize - sizeof(struct xfs_dir2_leaf_hdr)) / | |
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 | ||
422 | static int | |
423 | xfs_dir3_max_leaf_ents(struct xfs_da_geometry *geo) | |
424 | { | |
425 | return (geo->blksize - sizeof(struct xfs_dir3_leaf_hdr)) / | |
426 | (uint)sizeof(struct xfs_dir2_leaf_entry); | |
427 | } | |
428 | ||
429 | static struct xfs_dir2_leaf_entry * | |
430 | xfs_dir3_leaf_ents_p(struct xfs_dir2_leaf *lp) | |
431 | { | |
432 | return ((struct xfs_dir3_leaf *)lp)->__ents; | |
433 | } | |
434 | ||
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 | ||
500 | /* | |
501 | * Directory/Attribute Node block operations | |
502 | */ | |
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 | ||
509 | static struct xfs_da_node_entry * | |
510 | xfs_da3_node_tree_p(struct xfs_da_intnode *dap) | |
511 | { | |
512 | return ((struct xfs_da3_intnode *)dap)->__btree; | |
513 | } | |
514 | ||
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 | */ | |
575 | static int | |
576 | xfs_dir2_free_max_bests(struct xfs_da_geometry *geo) | |
577 | { | |
578 | return (geo->blksize - sizeof(struct xfs_dir2_free_hdr)) / | |
579 | sizeof(xfs_dir2_data_off_t); | |
580 | } | |
581 | ||
582 | static __be16 * | |
583 | xfs_dir2_free_bests_p(struct xfs_dir2_free *free) | |
584 | { | |
585 | return (__be16 *)((char *)free + sizeof(struct xfs_dir2_free_hdr)); | |
586 | } | |
587 | ||
588 | /* | |
589 | * Convert data space db to the corresponding free db. | |
590 | */ | |
591 | static xfs_dir2_db_t | |
592 | xfs_dir2_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db) | |
593 | { | |
594 | return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) + | |
595 | (db / xfs_dir2_free_max_bests(geo)); | |
596 | } | |
597 | ||
598 | /* | |
599 | * Convert data space db to the corresponding index in a free db. | |
600 | */ | |
601 | static int | |
602 | xfs_dir2_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db) | |
603 | { | |
604 | return db % xfs_dir2_free_max_bests(geo); | |
605 | } | |
606 | ||
607 | static int | |
608 | xfs_dir3_free_max_bests(struct xfs_da_geometry *geo) | |
609 | { | |
610 | return (geo->blksize - sizeof(struct xfs_dir3_free_hdr)) / | |
611 | sizeof(xfs_dir2_data_off_t); | |
612 | } | |
613 | ||
614 | static __be16 * | |
615 | xfs_dir3_free_bests_p(struct xfs_dir2_free *free) | |
616 | { | |
617 | return (__be16 *)((char *)free + sizeof(struct xfs_dir3_free_hdr)); | |
618 | } | |
619 | ||
620 | /* | |
621 | * Convert data space db to the corresponding free db. | |
622 | */ | |
623 | static xfs_dir2_db_t | |
624 | xfs_dir3_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db) | |
625 | { | |
626 | return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) + | |
627 | (db / xfs_dir3_free_max_bests(geo)); | |
628 | } | |
629 | ||
630 | /* | |
631 | * Convert data space db to the corresponding index in a free db. | |
632 | */ | |
633 | static int | |
634 | xfs_dir3_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db) | |
635 | { | |
636 | return db % xfs_dir3_free_max_bests(geo); | |
637 | } | |
638 | ||
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 | ||
694 | static const struct xfs_dir_ops xfs_dir2_ops = { | |
695 | .sf_entsize = xfs_dir2_sf_entsize, | |
696 | .sf_nextentry = xfs_dir2_sf_nextentry, | |
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, | |
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, | |
708 | .data_bestfree_p = xfs_dir2_data_bestfree_p, | |
709 | ||
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), | |
717 | ||
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, | |
721 | .data_entry_p = xfs_dir2_data_entry_p, | |
722 | .data_unused_p = xfs_dir2_data_unused_p, | |
723 | ||
724 | .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), | |
725 | .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, | |
726 | .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, | |
727 | .leaf_max_ents = xfs_dir2_max_leaf_ents, | |
728 | .leaf_ents_p = xfs_dir2_leaf_ents_p, | |
729 | ||
730 | .node_hdr_size = sizeof(struct xfs_da_node_hdr), | |
731 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, | |
732 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
733 | .node_tree_p = xfs_da2_node_tree_p, | |
734 | ||
735 | .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), | |
736 | .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, | |
737 | .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, | |
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, | |
742 | }; | |
743 | ||
744 | static const struct xfs_dir_ops xfs_dir2_ftype_ops = { | |
745 | .sf_entsize = xfs_dir3_sf_entsize, | |
746 | .sf_nextentry = xfs_dir3_sf_nextentry, | |
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, | |
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, | |
758 | .data_bestfree_p = xfs_dir2_data_bestfree_p, | |
759 | ||
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), | |
767 | ||
768 | .data_dot_entry_p = xfs_dir2_data_dot_entry_p, | |
769 | .data_dotdot_entry_p = xfs_dir2_ftype_data_dotdot_entry_p, | |
770 | .data_first_entry_p = xfs_dir2_ftype_data_first_entry_p, | |
771 | .data_entry_p = xfs_dir2_data_entry_p, | |
772 | .data_unused_p = xfs_dir2_data_unused_p, | |
773 | ||
774 | .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), | |
775 | .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, | |
776 | .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, | |
777 | .leaf_max_ents = xfs_dir2_max_leaf_ents, | |
778 | .leaf_ents_p = xfs_dir2_leaf_ents_p, | |
779 | ||
780 | .node_hdr_size = sizeof(struct xfs_da_node_hdr), | |
781 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, | |
782 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
783 | .node_tree_p = xfs_da2_node_tree_p, | |
784 | ||
785 | .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), | |
786 | .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, | |
787 | .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, | |
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, | |
792 | }; | |
793 | ||
794 | static const struct xfs_dir_ops xfs_dir3_ops = { | |
795 | .sf_entsize = xfs_dir3_sf_entsize, | |
796 | .sf_nextentry = xfs_dir3_sf_nextentry, | |
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, | |
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, | |
808 | .data_bestfree_p = xfs_dir3_data_bestfree_p, | |
809 | ||
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), | |
817 | ||
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, | |
821 | .data_entry_p = xfs_dir3_data_entry_p, | |
822 | .data_unused_p = xfs_dir3_data_unused_p, | |
823 | ||
824 | .leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr), | |
825 | .leaf_hdr_to_disk = xfs_dir3_leaf_hdr_to_disk, | |
826 | .leaf_hdr_from_disk = xfs_dir3_leaf_hdr_from_disk, | |
827 | .leaf_max_ents = xfs_dir3_max_leaf_ents, | |
828 | .leaf_ents_p = xfs_dir3_leaf_ents_p, | |
829 | ||
830 | .node_hdr_size = sizeof(struct xfs_da3_node_hdr), | |
831 | .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, | |
832 | .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, | |
833 | .node_tree_p = xfs_da3_node_tree_p, | |
834 | ||
835 | .free_hdr_size = sizeof(struct xfs_dir3_free_hdr), | |
836 | .free_hdr_to_disk = xfs_dir3_free_hdr_to_disk, | |
837 | .free_hdr_from_disk = xfs_dir3_free_hdr_from_disk, | |
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, | |
842 | }; | |
843 | ||
844 | static const struct xfs_dir_ops xfs_dir2_nondir_ops = { | |
845 | .node_hdr_size = sizeof(struct xfs_da_node_hdr), | |
846 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, | |
847 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
848 | .node_tree_p = xfs_da2_node_tree_p, | |
849 | }; | |
850 | ||
851 | static const struct xfs_dir_ops xfs_dir3_nondir_ops = { | |
852 | .node_hdr_size = sizeof(struct xfs_da3_node_hdr), | |
853 | .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, | |
854 | .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, | |
855 | .node_tree_p = xfs_da3_node_tree_p, | |
856 | }; | |
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 | } | |
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 | } |