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