]>
Commit | Line | Data |
---|---|---|
32c5483a 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 | */ | |
19 | #include "xfs.h" | |
20 | #include "xfs_fs.h" | |
21 | #include "xfs_format.h" | |
22 | #include "xfs_log_format.h" | |
23 | #include "xfs_trans_resv.h" | |
24 | #include "xfs_sb.h" | |
25 | #include "xfs_ag.h" | |
26 | #include "xfs_mount.h" | |
27 | #include "xfs_da_format.h" | |
28 | #include "xfs_inode.h" | |
29 | #include "xfs_dir2.h" | |
30 | ||
9d23fc85 DC |
31 | /* |
32 | * Shortform directory ops | |
33 | */ | |
32c5483a DC |
34 | static int |
35 | xfs_dir2_sf_entsize( | |
36 | struct xfs_dir2_sf_hdr *hdr, | |
37 | int len) | |
38 | { | |
39 | int count = sizeof(struct xfs_dir2_sf_entry); /* namelen + offset */ | |
40 | ||
41 | count += len; /* name */ | |
42 | count += hdr->i8count ? sizeof(xfs_dir2_ino8_t) : | |
43 | sizeof(xfs_dir2_ino4_t); /* ino # */ | |
44 | return count; | |
45 | } | |
46 | ||
47 | static int | |
48 | xfs_dir3_sf_entsize( | |
49 | struct xfs_dir2_sf_hdr *hdr, | |
50 | int len) | |
51 | { | |
52 | return xfs_dir2_sf_entsize(hdr, len) + sizeof(__uint8_t); | |
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 | ||
4740175e DC |
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 | */ | |
80 | static __uint8_t | |
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, | |
90 | __uint8_t ftype) | |
91 | { | |
92 | ASSERT(ftype < XFS_DIR3_FT_MAX); | |
93 | } | |
94 | ||
95 | static __uint8_t | |
96 | xfs_dir3_sfe_get_ftype( | |
97 | struct xfs_dir2_sf_entry *sfep) | |
98 | { | |
99 | __uint8_t ftype; | |
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, | |
110 | __uint8_t ftype) | |
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, | |
127 | xfs_dir2_inou_t *from) | |
128 | { | |
129 | if (hdr->i8count) | |
130 | return get_unaligned_be64(&from->i8.i) & 0x00ffffffffffffffULL; | |
131 | else | |
132 | return get_unaligned_be32(&from->i4.i); | |
133 | } | |
134 | ||
135 | static void | |
136 | xfs_dir2_sf_put_ino( | |
137 | struct xfs_dir2_sf_hdr *hdr, | |
138 | xfs_dir2_inou_t *to, | |
139 | xfs_ino_t ino) | |
140 | { | |
141 | ASSERT((ino & 0xff00000000000000ULL) == 0); | |
142 | ||
143 | if (hdr->i8count) | |
144 | put_unaligned_be64(ino, &to->i8.i); | |
145 | else | |
146 | put_unaligned_be32(ino, &to->i4.i); | |
147 | } | |
148 | ||
149 | static xfs_ino_t | |
150 | xfs_dir2_sf_get_parent_ino( | |
151 | struct xfs_dir2_sf_hdr *hdr) | |
152 | { | |
153 | return xfs_dir2_sf_get_ino(hdr, &hdr->parent); | |
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 | { | |
161 | xfs_dir2_sf_put_ino(hdr, &hdr->parent, ino); | |
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 | { | |
175 | return xfs_dir2_sf_get_ino(hdr, | |
176 | (xfs_dir2_inou_t *)&sfep->name[sfep->namelen]); | |
177 | } | |
178 | ||
179 | static void | |
180 | xfs_dir2_sfe_put_ino( | |
181 | struct xfs_dir2_sf_hdr *hdr, | |
182 | struct xfs_dir2_sf_entry *sfep, | |
183 | xfs_ino_t ino) | |
184 | { | |
185 | xfs_dir2_sf_put_ino(hdr, | |
186 | (xfs_dir2_inou_t *)&sfep->name[sfep->namelen], ino); | |
187 | } | |
188 | ||
189 | static xfs_ino_t | |
190 | xfs_dir3_sfe_get_ino( | |
191 | struct xfs_dir2_sf_hdr *hdr, | |
192 | struct xfs_dir2_sf_entry *sfep) | |
193 | { | |
194 | return xfs_dir2_sf_get_ino(hdr, | |
195 | (xfs_dir2_inou_t *)&sfep->name[sfep->namelen + 1]); | |
196 | } | |
197 | ||
198 | static void | |
199 | xfs_dir3_sfe_put_ino( | |
200 | struct xfs_dir2_sf_hdr *hdr, | |
201 | struct xfs_dir2_sf_entry *sfep, | |
202 | xfs_ino_t ino) | |
203 | { | |
204 | xfs_dir2_sf_put_ino(hdr, | |
205 | (xfs_dir2_inou_t *)&sfep->name[sfep->namelen + 1], ino); | |
206 | } | |
207 | ||
9d23fc85 DC |
208 | |
209 | /* | |
210 | * Directory data block operations | |
211 | */ | |
212 | static int | |
213 | __xfs_dir3_data_entsize( | |
214 | bool ftype, | |
215 | int n) | |
216 | { | |
217 | int size = offsetof(struct xfs_dir2_data_entry, name[0]); | |
218 | ||
219 | size += n; | |
220 | size += sizeof(xfs_dir2_data_off_t); | |
221 | if (ftype) | |
222 | size += sizeof(__uint8_t); | |
223 | return roundup(size, XFS_DIR2_DATA_ALIGN); | |
224 | } | |
225 | ||
226 | static int | |
227 | xfs_dir2_data_entsize( | |
228 | int n) | |
229 | { | |
230 | return __xfs_dir3_data_entsize(false, n); | |
231 | } | |
232 | static int | |
233 | xfs_dir3_data_entsize( | |
234 | int n) | |
235 | { | |
236 | return __xfs_dir3_data_entsize(true, n); | |
237 | } | |
238 | ||
239 | static __uint8_t | |
240 | xfs_dir2_data_get_ftype( | |
241 | struct xfs_dir2_data_entry *dep) | |
242 | { | |
243 | return XFS_DIR3_FT_UNKNOWN; | |
244 | } | |
245 | ||
246 | static void | |
247 | xfs_dir2_data_put_ftype( | |
248 | struct xfs_dir2_data_entry *dep, | |
249 | __uint8_t ftype) | |
250 | { | |
251 | ASSERT(ftype < XFS_DIR3_FT_MAX); | |
252 | } | |
253 | ||
254 | static __uint8_t | |
255 | xfs_dir3_data_get_ftype( | |
256 | struct xfs_dir2_data_entry *dep) | |
257 | { | |
258 | __uint8_t ftype = dep->name[dep->namelen]; | |
259 | ||
260 | ASSERT(ftype < XFS_DIR3_FT_MAX); | |
261 | if (ftype >= XFS_DIR3_FT_MAX) | |
262 | return XFS_DIR3_FT_UNKNOWN; | |
263 | return ftype; | |
264 | } | |
265 | ||
266 | static void | |
267 | xfs_dir3_data_put_ftype( | |
268 | struct xfs_dir2_data_entry *dep, | |
269 | __uint8_t type) | |
270 | { | |
271 | ASSERT(type < XFS_DIR3_FT_MAX); | |
272 | ASSERT(dep->namelen != 0); | |
273 | ||
274 | dep->name[dep->namelen] = type; | |
275 | } | |
276 | ||
277 | /* | |
278 | * Pointer to an entry's tag word. | |
279 | */ | |
280 | static __be16 * | |
281 | xfs_dir2_data_entry_tag_p( | |
282 | struct xfs_dir2_data_entry *dep) | |
283 | { | |
284 | return (__be16 *)((char *)dep + | |
285 | xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16)); | |
286 | } | |
287 | ||
288 | static __be16 * | |
289 | xfs_dir3_data_entry_tag_p( | |
290 | struct xfs_dir2_data_entry *dep) | |
291 | { | |
292 | return (__be16 *)((char *)dep + | |
293 | xfs_dir3_data_entsize(dep->namelen) - sizeof(__be16)); | |
294 | } | |
295 | ||
296 | /* | |
297 | * Offsets of . and .. in data space (always block 0) | |
298 | */ | |
299 | static xfs_dir2_data_aoff_t | |
300 | xfs_dir2_data_dot_offset(void) | |
301 | { | |
302 | return sizeof(struct xfs_dir2_data_hdr); | |
303 | } | |
304 | ||
305 | static xfs_dir2_data_aoff_t | |
306 | xfs_dir2_data_dotdot_offset(void) | |
307 | { | |
308 | return xfs_dir2_data_dot_offset() + xfs_dir2_data_entsize(1); | |
309 | } | |
310 | ||
311 | static xfs_dir2_data_aoff_t | |
312 | xfs_dir2_data_first_offset(void) | |
313 | { | |
314 | return xfs_dir2_data_dotdot_offset() + xfs_dir2_data_entsize(2); | |
315 | } | |
316 | ||
317 | static xfs_dir2_data_aoff_t | |
318 | xfs_dir3_data_dot_offset(void) | |
319 | { | |
320 | return sizeof(struct xfs_dir3_data_hdr); | |
321 | } | |
322 | ||
323 | static xfs_dir2_data_aoff_t | |
324 | xfs_dir3_data_dotdot_offset(void) | |
325 | { | |
326 | return xfs_dir3_data_dot_offset() + xfs_dir3_data_entsize(1); | |
327 | } | |
328 | ||
329 | static xfs_dir2_data_aoff_t | |
330 | xfs_dir3_data_first_offset(void) | |
331 | { | |
332 | return xfs_dir3_data_dotdot_offset() + xfs_dir3_data_entsize(2); | |
333 | } | |
334 | ||
335 | /* | |
336 | * location of . and .. in data space (always block 0) | |
337 | */ | |
338 | static struct xfs_dir2_data_entry * | |
339 | xfs_dir2_data_dot_entry_p( | |
340 | struct xfs_dir2_data_hdr *hdr) | |
341 | { | |
342 | return (struct xfs_dir2_data_entry *) | |
343 | ((char *)hdr + xfs_dir2_data_dot_offset()); | |
344 | } | |
345 | ||
346 | static struct xfs_dir2_data_entry * | |
347 | xfs_dir2_data_dotdot_entry_p( | |
348 | struct xfs_dir2_data_hdr *hdr) | |
349 | { | |
350 | return (struct xfs_dir2_data_entry *) | |
351 | ((char *)hdr + xfs_dir2_data_dotdot_offset()); | |
352 | } | |
353 | ||
354 | static struct xfs_dir2_data_entry * | |
355 | xfs_dir2_data_first_entry_p( | |
356 | struct xfs_dir2_data_hdr *hdr) | |
357 | { | |
358 | return (struct xfs_dir2_data_entry *) | |
359 | ((char *)hdr + xfs_dir2_data_first_offset()); | |
360 | } | |
361 | ||
362 | static struct xfs_dir2_data_entry * | |
363 | xfs_dir3_data_dot_entry_p( | |
364 | struct xfs_dir2_data_hdr *hdr) | |
365 | { | |
366 | return (struct xfs_dir2_data_entry *) | |
367 | ((char *)hdr + xfs_dir3_data_dot_offset()); | |
368 | } | |
369 | ||
370 | static struct xfs_dir2_data_entry * | |
371 | xfs_dir3_data_dotdot_entry_p( | |
372 | struct xfs_dir2_data_hdr *hdr) | |
373 | { | |
374 | return (struct xfs_dir2_data_entry *) | |
375 | ((char *)hdr + xfs_dir3_data_dotdot_offset()); | |
376 | } | |
377 | ||
378 | static struct xfs_dir2_data_entry * | |
379 | xfs_dir3_data_first_entry_p( | |
380 | struct xfs_dir2_data_hdr *hdr) | |
381 | { | |
382 | return (struct xfs_dir2_data_entry *) | |
383 | ((char *)hdr + xfs_dir3_data_first_offset()); | |
384 | } | |
385 | ||
2ca98774 DC |
386 | static struct xfs_dir2_data_free * |
387 | xfs_dir2_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) | |
388 | { | |
389 | return hdr->bestfree; | |
390 | } | |
391 | ||
392 | static struct xfs_dir2_data_free * | |
393 | xfs_dir3_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) | |
394 | { | |
395 | return ((struct xfs_dir3_data_hdr *)hdr)->best_free; | |
396 | } | |
397 | ||
398 | static size_t | |
399 | xfs_dir2_data_entry_offset(void) | |
400 | { | |
401 | return sizeof(struct xfs_dir2_data_hdr); | |
402 | } | |
403 | ||
404 | static struct xfs_dir2_data_entry * | |
405 | xfs_dir2_data_entry_p(struct xfs_dir2_data_hdr *hdr) | |
406 | { | |
407 | return (struct xfs_dir2_data_entry *) | |
408 | ((char *)hdr + xfs_dir2_data_entry_offset()); | |
409 | } | |
410 | ||
411 | static struct xfs_dir2_data_unused * | |
412 | xfs_dir2_data_unused_p(struct xfs_dir2_data_hdr *hdr) | |
413 | { | |
414 | return (struct xfs_dir2_data_unused *) | |
415 | ((char *)hdr + xfs_dir2_data_entry_offset()); | |
416 | } | |
417 | ||
418 | static size_t | |
419 | xfs_dir3_data_entry_offset(void) | |
420 | { | |
421 | return sizeof(struct xfs_dir3_data_hdr); | |
422 | } | |
423 | ||
424 | static struct xfs_dir2_data_entry * | |
425 | xfs_dir3_data_entry_p(struct xfs_dir2_data_hdr *hdr) | |
426 | { | |
427 | return (struct xfs_dir2_data_entry *) | |
428 | ((char *)hdr + xfs_dir3_data_entry_offset()); | |
429 | } | |
430 | ||
431 | static struct xfs_dir2_data_unused * | |
432 | xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr) | |
433 | { | |
434 | return (struct xfs_dir2_data_unused *) | |
435 | ((char *)hdr + xfs_dir3_data_entry_offset()); | |
436 | } | |
437 | ||
4141956a DC |
438 | |
439 | /* | |
440 | * Directory Leaf block operations | |
441 | */ | |
442 | static int | |
443 | xfs_dir2_leaf_hdr_size(void) | |
444 | { | |
445 | return sizeof(struct xfs_dir2_leaf_hdr); | |
446 | } | |
447 | ||
448 | static int | |
449 | xfs_dir2_max_leaf_ents(struct xfs_mount *mp) | |
450 | { | |
451 | return (mp->m_dirblksize - xfs_dir2_leaf_hdr_size()) / | |
452 | (uint)sizeof(struct xfs_dir2_leaf_entry); | |
453 | } | |
454 | ||
455 | static struct xfs_dir2_leaf_entry * | |
456 | xfs_dir2_leaf_ents_p(struct xfs_dir2_leaf *lp) | |
457 | { | |
458 | return lp->__ents; | |
459 | } | |
460 | ||
461 | static int | |
462 | xfs_dir3_leaf_hdr_size(void) | |
463 | { | |
464 | return sizeof(struct xfs_dir3_leaf_hdr); | |
465 | } | |
466 | ||
01ba43b8 | 467 | static int |
4141956a DC |
468 | xfs_dir3_max_leaf_ents(struct xfs_mount *mp) |
469 | { | |
470 | return (mp->m_dirblksize - xfs_dir3_leaf_hdr_size()) / | |
471 | (uint)sizeof(struct xfs_dir2_leaf_entry); | |
472 | } | |
473 | ||
01ba43b8 | 474 | static struct xfs_dir2_leaf_entry * |
4141956a DC |
475 | xfs_dir3_leaf_ents_p(struct xfs_dir2_leaf *lp) |
476 | { | |
477 | return ((struct xfs_dir3_leaf *)lp)->__ents; | |
478 | } | |
479 | ||
01ba43b8 DC |
480 | static void |
481 | xfs_dir2_leaf_hdr_from_disk( | |
482 | struct xfs_dir3_icleaf_hdr *to, | |
483 | struct xfs_dir2_leaf *from) | |
484 | { | |
485 | to->forw = be32_to_cpu(from->hdr.info.forw); | |
486 | to->back = be32_to_cpu(from->hdr.info.back); | |
487 | to->magic = be16_to_cpu(from->hdr.info.magic); | |
488 | to->count = be16_to_cpu(from->hdr.count); | |
489 | to->stale = be16_to_cpu(from->hdr.stale); | |
490 | ||
491 | ASSERT(to->magic == XFS_DIR2_LEAF1_MAGIC || | |
492 | to->magic == XFS_DIR2_LEAFN_MAGIC); | |
493 | } | |
494 | ||
495 | static void | |
496 | xfs_dir2_leaf_hdr_to_disk( | |
497 | struct xfs_dir2_leaf *to, | |
498 | struct xfs_dir3_icleaf_hdr *from) | |
499 | { | |
500 | ASSERT(from->magic == XFS_DIR2_LEAF1_MAGIC || | |
501 | from->magic == XFS_DIR2_LEAFN_MAGIC); | |
502 | ||
503 | to->hdr.info.forw = cpu_to_be32(from->forw); | |
504 | to->hdr.info.back = cpu_to_be32(from->back); | |
505 | to->hdr.info.magic = cpu_to_be16(from->magic); | |
506 | to->hdr.count = cpu_to_be16(from->count); | |
507 | to->hdr.stale = cpu_to_be16(from->stale); | |
508 | } | |
509 | ||
510 | static void | |
511 | xfs_dir3_leaf_hdr_from_disk( | |
512 | struct xfs_dir3_icleaf_hdr *to, | |
513 | struct xfs_dir2_leaf *from) | |
514 | { | |
515 | struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)from; | |
516 | ||
517 | to->forw = be32_to_cpu(hdr3->info.hdr.forw); | |
518 | to->back = be32_to_cpu(hdr3->info.hdr.back); | |
519 | to->magic = be16_to_cpu(hdr3->info.hdr.magic); | |
520 | to->count = be16_to_cpu(hdr3->count); | |
521 | to->stale = be16_to_cpu(hdr3->stale); | |
522 | ||
523 | ASSERT(to->magic == XFS_DIR3_LEAF1_MAGIC || | |
524 | to->magic == XFS_DIR3_LEAFN_MAGIC); | |
525 | } | |
526 | ||
527 | static void | |
528 | xfs_dir3_leaf_hdr_to_disk( | |
529 | struct xfs_dir2_leaf *to, | |
530 | struct xfs_dir3_icleaf_hdr *from) | |
531 | { | |
532 | struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)to; | |
533 | ||
534 | ASSERT(from->magic == XFS_DIR3_LEAF1_MAGIC || | |
535 | from->magic == XFS_DIR3_LEAFN_MAGIC); | |
536 | ||
537 | hdr3->info.hdr.forw = cpu_to_be32(from->forw); | |
538 | hdr3->info.hdr.back = cpu_to_be32(from->back); | |
539 | hdr3->info.hdr.magic = cpu_to_be16(from->magic); | |
540 | hdr3->count = cpu_to_be16(from->count); | |
541 | hdr3->stale = cpu_to_be16(from->stale); | |
542 | } | |
543 | ||
544 | ||
4bceb18f DC |
545 | /* |
546 | * Directory/Attribute Node block operations | |
547 | */ | |
548 | static inline int | |
549 | xfs_da2_node_hdr_size(void) | |
550 | { | |
551 | return sizeof(struct xfs_da_node_hdr); | |
552 | } | |
553 | ||
554 | static struct xfs_da_node_entry * | |
555 | xfs_da2_node_tree_p(struct xfs_da_intnode *dap) | |
556 | { | |
557 | return dap->__btree; | |
558 | } | |
559 | ||
560 | static inline int | |
561 | xfs_da3_node_hdr_size(void) | |
562 | { | |
563 | return sizeof(struct xfs_da3_node_hdr); | |
564 | } | |
565 | ||
566 | static inline struct xfs_da_node_entry * | |
567 | xfs_da3_node_tree_p(struct xfs_da_intnode *dap) | |
568 | { | |
569 | return ((struct xfs_da3_intnode *)dap)->__btree; | |
570 | } | |
571 | ||
01ba43b8 DC |
572 | static void |
573 | xfs_da2_node_hdr_from_disk( | |
574 | struct xfs_da3_icnode_hdr *to, | |
575 | struct xfs_da_intnode *from) | |
576 | { | |
577 | ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC)); | |
578 | to->forw = be32_to_cpu(from->hdr.info.forw); | |
579 | to->back = be32_to_cpu(from->hdr.info.back); | |
580 | to->magic = be16_to_cpu(from->hdr.info.magic); | |
581 | to->count = be16_to_cpu(from->hdr.__count); | |
582 | to->level = be16_to_cpu(from->hdr.__level); | |
583 | } | |
584 | ||
585 | static void | |
586 | xfs_da2_node_hdr_to_disk( | |
587 | struct xfs_da_intnode *to, | |
588 | struct xfs_da3_icnode_hdr *from) | |
589 | { | |
590 | ASSERT(from->magic == XFS_DA_NODE_MAGIC); | |
591 | to->hdr.info.forw = cpu_to_be32(from->forw); | |
592 | to->hdr.info.back = cpu_to_be32(from->back); | |
593 | to->hdr.info.magic = cpu_to_be16(from->magic); | |
594 | to->hdr.__count = cpu_to_be16(from->count); | |
595 | to->hdr.__level = cpu_to_be16(from->level); | |
596 | } | |
597 | ||
598 | static void | |
599 | xfs_da3_node_hdr_from_disk( | |
600 | struct xfs_da3_icnode_hdr *to, | |
601 | struct xfs_da_intnode *from) | |
602 | { | |
603 | struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)from; | |
604 | ||
605 | ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)); | |
606 | to->forw = be32_to_cpu(hdr3->info.hdr.forw); | |
607 | to->back = be32_to_cpu(hdr3->info.hdr.back); | |
608 | to->magic = be16_to_cpu(hdr3->info.hdr.magic); | |
609 | to->count = be16_to_cpu(hdr3->__count); | |
610 | to->level = be16_to_cpu(hdr3->__level); | |
611 | } | |
612 | ||
613 | static void | |
614 | xfs_da3_node_hdr_to_disk( | |
615 | struct xfs_da_intnode *to, | |
616 | struct xfs_da3_icnode_hdr *from) | |
617 | { | |
618 | struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)to; | |
619 | ||
620 | ASSERT(from->magic == XFS_DA3_NODE_MAGIC); | |
621 | hdr3->info.hdr.forw = cpu_to_be32(from->forw); | |
622 | hdr3->info.hdr.back = cpu_to_be32(from->back); | |
623 | hdr3->info.hdr.magic = cpu_to_be16(from->magic); | |
624 | hdr3->__count = cpu_to_be16(from->count); | |
625 | hdr3->__level = cpu_to_be16(from->level); | |
626 | } | |
627 | ||
628 | ||
629 | /* | |
630 | * Directory free space block operations | |
631 | */ | |
24dd0f54 DC |
632 | static int |
633 | xfs_dir2_free_hdr_size(void) | |
634 | { | |
635 | return sizeof(struct xfs_dir2_free_hdr); | |
636 | } | |
637 | ||
638 | static int | |
639 | xfs_dir2_free_max_bests(struct xfs_mount *mp) | |
640 | { | |
641 | return (mp->m_dirblksize - xfs_dir2_free_hdr_size()) / | |
642 | sizeof(xfs_dir2_data_off_t); | |
643 | } | |
644 | ||
645 | static __be16 * | |
646 | xfs_dir2_free_bests_p(struct xfs_dir2_free *free) | |
647 | { | |
648 | return (__be16 *)((char *)free + xfs_dir2_free_hdr_size()); | |
649 | } | |
650 | ||
651 | /* | |
652 | * Convert data space db to the corresponding free db. | |
653 | */ | |
654 | static xfs_dir2_db_t | |
655 | xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db) | |
656 | { | |
657 | return XFS_DIR2_FREE_FIRSTDB(mp) + db / xfs_dir2_free_max_bests(mp); | |
658 | } | |
659 | ||
660 | /* | |
661 | * Convert data space db to the corresponding index in a free db. | |
662 | */ | |
663 | static int | |
664 | xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db) | |
665 | { | |
666 | return db % xfs_dir2_free_max_bests(mp); | |
667 | } | |
668 | ||
669 | static int | |
670 | xfs_dir3_free_hdr_size(void) | |
671 | { | |
672 | return sizeof(struct xfs_dir3_free_hdr); | |
673 | } | |
674 | ||
675 | static int | |
676 | xfs_dir3_free_max_bests(struct xfs_mount *mp) | |
677 | { | |
678 | return (mp->m_dirblksize - xfs_dir3_free_hdr_size()) / | |
679 | sizeof(xfs_dir2_data_off_t); | |
680 | } | |
681 | ||
682 | static __be16 * | |
683 | xfs_dir3_free_bests_p(struct xfs_dir2_free *free) | |
684 | { | |
685 | return (__be16 *)((char *)free + xfs_dir3_free_hdr_size()); | |
686 | } | |
687 | ||
688 | /* | |
689 | * Convert data space db to the corresponding free db. | |
690 | */ | |
691 | static xfs_dir2_db_t | |
692 | xfs_dir3_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db) | |
693 | { | |
694 | return XFS_DIR2_FREE_FIRSTDB(mp) + db / xfs_dir3_free_max_bests(mp); | |
695 | } | |
696 | ||
697 | /* | |
698 | * Convert data space db to the corresponding index in a free db. | |
699 | */ | |
700 | static int | |
701 | xfs_dir3_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db) | |
702 | { | |
703 | return db % xfs_dir3_free_max_bests(mp); | |
704 | } | |
705 | ||
01ba43b8 DC |
706 | static void |
707 | xfs_dir2_free_hdr_from_disk( | |
708 | struct xfs_dir3_icfree_hdr *to, | |
709 | struct xfs_dir2_free *from) | |
710 | { | |
711 | to->magic = be32_to_cpu(from->hdr.magic); | |
712 | to->firstdb = be32_to_cpu(from->hdr.firstdb); | |
713 | to->nvalid = be32_to_cpu(from->hdr.nvalid); | |
714 | to->nused = be32_to_cpu(from->hdr.nused); | |
715 | ASSERT(to->magic == XFS_DIR2_FREE_MAGIC); | |
716 | } | |
717 | ||
718 | static void | |
719 | xfs_dir2_free_hdr_to_disk( | |
720 | struct xfs_dir2_free *to, | |
721 | struct xfs_dir3_icfree_hdr *from) | |
722 | { | |
723 | ASSERT(from->magic == XFS_DIR2_FREE_MAGIC); | |
724 | ||
725 | to->hdr.magic = cpu_to_be32(from->magic); | |
726 | to->hdr.firstdb = cpu_to_be32(from->firstdb); | |
727 | to->hdr.nvalid = cpu_to_be32(from->nvalid); | |
728 | to->hdr.nused = cpu_to_be32(from->nused); | |
729 | } | |
730 | ||
731 | static void | |
732 | xfs_dir3_free_hdr_from_disk( | |
733 | struct xfs_dir3_icfree_hdr *to, | |
734 | struct xfs_dir2_free *from) | |
735 | { | |
736 | struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)from; | |
737 | ||
738 | to->magic = be32_to_cpu(hdr3->hdr.magic); | |
739 | to->firstdb = be32_to_cpu(hdr3->firstdb); | |
740 | to->nvalid = be32_to_cpu(hdr3->nvalid); | |
741 | to->nused = be32_to_cpu(hdr3->nused); | |
742 | ||
743 | ASSERT(to->magic == XFS_DIR3_FREE_MAGIC); | |
744 | } | |
745 | ||
746 | static void | |
747 | xfs_dir3_free_hdr_to_disk( | |
748 | struct xfs_dir2_free *to, | |
749 | struct xfs_dir3_icfree_hdr *from) | |
750 | { | |
751 | struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)to; | |
752 | ||
753 | ASSERT(from->magic == XFS_DIR3_FREE_MAGIC); | |
754 | ||
755 | hdr3->hdr.magic = cpu_to_be32(from->magic); | |
756 | hdr3->firstdb = cpu_to_be32(from->firstdb); | |
757 | hdr3->nvalid = cpu_to_be32(from->nvalid); | |
758 | hdr3->nused = cpu_to_be32(from->nused); | |
759 | } | |
760 | ||
32c5483a DC |
761 | const struct xfs_dir_ops xfs_dir2_ops = { |
762 | .sf_entsize = xfs_dir2_sf_entsize, | |
763 | .sf_nextentry = xfs_dir2_sf_nextentry, | |
4740175e DC |
764 | .sf_get_ftype = xfs_dir2_sfe_get_ftype, |
765 | .sf_put_ftype = xfs_dir2_sfe_put_ftype, | |
766 | .sf_get_ino = xfs_dir2_sfe_get_ino, | |
767 | .sf_put_ino = xfs_dir2_sfe_put_ino, | |
768 | .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, | |
769 | .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, | |
9d23fc85 DC |
770 | |
771 | .data_entsize = xfs_dir2_data_entsize, | |
772 | .data_get_ftype = xfs_dir2_data_get_ftype, | |
773 | .data_put_ftype = xfs_dir2_data_put_ftype, | |
774 | .data_entry_tag_p = xfs_dir2_data_entry_tag_p, | |
2ca98774 | 775 | .data_bestfree_p = xfs_dir2_data_bestfree_p, |
9d23fc85 DC |
776 | |
777 | .data_dot_offset = xfs_dir2_data_dot_offset, | |
778 | .data_dotdot_offset = xfs_dir2_data_dotdot_offset, | |
779 | .data_first_offset = xfs_dir2_data_first_offset, | |
2ca98774 DC |
780 | .data_entry_offset = xfs_dir2_data_entry_offset, |
781 | ||
9d23fc85 DC |
782 | .data_dot_entry_p = xfs_dir2_data_dot_entry_p, |
783 | .data_dotdot_entry_p = xfs_dir2_data_dotdot_entry_p, | |
784 | .data_first_entry_p = xfs_dir2_data_first_entry_p, | |
2ca98774 DC |
785 | .data_entry_p = xfs_dir2_data_entry_p, |
786 | .data_unused_p = xfs_dir2_data_unused_p, | |
787 | ||
4141956a | 788 | .leaf_hdr_size = xfs_dir2_leaf_hdr_size, |
01ba43b8 DC |
789 | .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, |
790 | .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, | |
4141956a DC |
791 | .leaf_max_ents = xfs_dir2_max_leaf_ents, |
792 | .leaf_ents_p = xfs_dir2_leaf_ents_p, | |
793 | ||
4bceb18f | 794 | .node_hdr_size = xfs_da2_node_hdr_size, |
01ba43b8 DC |
795 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, |
796 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
4bceb18f | 797 | .node_tree_p = xfs_da2_node_tree_p, |
01ba43b8 | 798 | |
24dd0f54 | 799 | .free_hdr_size = xfs_dir2_free_hdr_size, |
01ba43b8 DC |
800 | .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, |
801 | .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, | |
24dd0f54 DC |
802 | .free_max_bests = xfs_dir2_free_max_bests, |
803 | .free_bests_p = xfs_dir2_free_bests_p, | |
804 | .db_to_fdb = xfs_dir2_db_to_fdb, | |
805 | .db_to_fdindex = xfs_dir2_db_to_fdindex, | |
32c5483a DC |
806 | }; |
807 | ||
808 | const struct xfs_dir_ops xfs_dir2_ftype_ops = { | |
809 | .sf_entsize = xfs_dir3_sf_entsize, | |
810 | .sf_nextentry = xfs_dir3_sf_nextentry, | |
4740175e DC |
811 | .sf_get_ftype = xfs_dir3_sfe_get_ftype, |
812 | .sf_put_ftype = xfs_dir3_sfe_put_ftype, | |
813 | .sf_get_ino = xfs_dir3_sfe_get_ino, | |
814 | .sf_put_ino = xfs_dir3_sfe_put_ino, | |
815 | .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, | |
816 | .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, | |
9d23fc85 DC |
817 | |
818 | .data_entsize = xfs_dir3_data_entsize, | |
819 | .data_get_ftype = xfs_dir3_data_get_ftype, | |
820 | .data_put_ftype = xfs_dir3_data_put_ftype, | |
821 | .data_entry_tag_p = xfs_dir3_data_entry_tag_p, | |
2ca98774 | 822 | .data_bestfree_p = xfs_dir2_data_bestfree_p, |
9d23fc85 DC |
823 | |
824 | .data_dot_offset = xfs_dir2_data_dot_offset, | |
825 | .data_dotdot_offset = xfs_dir2_data_dotdot_offset, | |
826 | .data_first_offset = xfs_dir2_data_first_offset, | |
2ca98774 DC |
827 | .data_entry_offset = xfs_dir2_data_entry_offset, |
828 | ||
9d23fc85 DC |
829 | .data_dot_entry_p = xfs_dir2_data_dot_entry_p, |
830 | .data_dotdot_entry_p = xfs_dir2_data_dotdot_entry_p, | |
831 | .data_first_entry_p = xfs_dir2_data_first_entry_p, | |
2ca98774 DC |
832 | .data_entry_p = xfs_dir2_data_entry_p, |
833 | .data_unused_p = xfs_dir2_data_unused_p, | |
4141956a DC |
834 | |
835 | .leaf_hdr_size = xfs_dir2_leaf_hdr_size, | |
01ba43b8 DC |
836 | .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, |
837 | .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, | |
4141956a DC |
838 | .leaf_max_ents = xfs_dir2_max_leaf_ents, |
839 | .leaf_ents_p = xfs_dir2_leaf_ents_p, | |
4bceb18f DC |
840 | |
841 | .node_hdr_size = xfs_da2_node_hdr_size, | |
01ba43b8 DC |
842 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, |
843 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
4bceb18f | 844 | .node_tree_p = xfs_da2_node_tree_p, |
01ba43b8 | 845 | |
24dd0f54 | 846 | .free_hdr_size = xfs_dir2_free_hdr_size, |
01ba43b8 DC |
847 | .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, |
848 | .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, | |
24dd0f54 DC |
849 | .free_max_bests = xfs_dir2_free_max_bests, |
850 | .free_bests_p = xfs_dir2_free_bests_p, | |
851 | .db_to_fdb = xfs_dir2_db_to_fdb, | |
852 | .db_to_fdindex = xfs_dir2_db_to_fdindex, | |
32c5483a DC |
853 | }; |
854 | ||
855 | const struct xfs_dir_ops xfs_dir3_ops = { | |
856 | .sf_entsize = xfs_dir3_sf_entsize, | |
857 | .sf_nextentry = xfs_dir3_sf_nextentry, | |
4740175e DC |
858 | .sf_get_ftype = xfs_dir3_sfe_get_ftype, |
859 | .sf_put_ftype = xfs_dir3_sfe_put_ftype, | |
860 | .sf_get_ino = xfs_dir3_sfe_get_ino, | |
861 | .sf_put_ino = xfs_dir3_sfe_put_ino, | |
862 | .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, | |
863 | .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, | |
9d23fc85 DC |
864 | |
865 | .data_entsize = xfs_dir3_data_entsize, | |
866 | .data_get_ftype = xfs_dir3_data_get_ftype, | |
867 | .data_put_ftype = xfs_dir3_data_put_ftype, | |
868 | .data_entry_tag_p = xfs_dir3_data_entry_tag_p, | |
2ca98774 | 869 | .data_bestfree_p = xfs_dir3_data_bestfree_p, |
9d23fc85 DC |
870 | |
871 | .data_dot_offset = xfs_dir3_data_dot_offset, | |
872 | .data_dotdot_offset = xfs_dir3_data_dotdot_offset, | |
873 | .data_first_offset = xfs_dir3_data_first_offset, | |
2ca98774 DC |
874 | .data_entry_offset = xfs_dir3_data_entry_offset, |
875 | ||
9d23fc85 DC |
876 | .data_dot_entry_p = xfs_dir3_data_dot_entry_p, |
877 | .data_dotdot_entry_p = xfs_dir3_data_dotdot_entry_p, | |
878 | .data_first_entry_p = xfs_dir3_data_first_entry_p, | |
2ca98774 DC |
879 | .data_entry_p = xfs_dir3_data_entry_p, |
880 | .data_unused_p = xfs_dir3_data_unused_p, | |
4141956a DC |
881 | |
882 | .leaf_hdr_size = xfs_dir3_leaf_hdr_size, | |
01ba43b8 DC |
883 | .leaf_hdr_to_disk = xfs_dir3_leaf_hdr_to_disk, |
884 | .leaf_hdr_from_disk = xfs_dir3_leaf_hdr_from_disk, | |
4141956a DC |
885 | .leaf_max_ents = xfs_dir3_max_leaf_ents, |
886 | .leaf_ents_p = xfs_dir3_leaf_ents_p, | |
4bceb18f DC |
887 | |
888 | .node_hdr_size = xfs_da3_node_hdr_size, | |
01ba43b8 DC |
889 | .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, |
890 | .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, | |
4bceb18f | 891 | .node_tree_p = xfs_da3_node_tree_p, |
01ba43b8 | 892 | |
24dd0f54 | 893 | .free_hdr_size = xfs_dir3_free_hdr_size, |
01ba43b8 DC |
894 | .free_hdr_to_disk = xfs_dir3_free_hdr_to_disk, |
895 | .free_hdr_from_disk = xfs_dir3_free_hdr_from_disk, | |
24dd0f54 DC |
896 | .free_max_bests = xfs_dir3_free_max_bests, |
897 | .free_bests_p = xfs_dir3_free_bests_p, | |
898 | .db_to_fdb = xfs_dir3_db_to_fdb, | |
899 | .db_to_fdindex = xfs_dir3_db_to_fdindex, | |
4bceb18f DC |
900 | }; |
901 | ||
902 | const struct xfs_dir_ops xfs_dir2_nondir_ops = { | |
903 | .node_hdr_size = xfs_da2_node_hdr_size, | |
01ba43b8 DC |
904 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, |
905 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
4bceb18f DC |
906 | .node_tree_p = xfs_da2_node_tree_p, |
907 | }; | |
908 | ||
909 | const struct xfs_dir_ops xfs_dir3_nondir_ops = { | |
910 | .node_hdr_size = xfs_da3_node_hdr_size, | |
01ba43b8 DC |
911 | .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, |
912 | .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, | |
4bceb18f | 913 | .node_tree_p = xfs_da3_node_tree_p, |
32c5483a | 914 | }; |
4141956a DC |
915 | |
916 | /* | |
917 | * Return the ops structure according to the current config. If we are passed | |
918 | * an inode, then that overrides the default config we use which is based on | |
919 | * feature bits. | |
920 | */ | |
921 | const struct xfs_dir_ops * | |
922 | xfs_dir_get_ops( | |
923 | struct xfs_mount *mp, | |
924 | struct xfs_inode *dp) | |
925 | { | |
926 | if (dp) | |
927 | return dp->d_ops; | |
928 | if (mp->m_dir_inode_ops) | |
929 | return mp->m_dir_inode_ops; | |
930 | if (xfs_sb_version_hascrc(&mp->m_sb)) | |
931 | return &xfs_dir3_ops; | |
932 | if (xfs_sb_version_hasftype(&mp->m_sb)) | |
933 | return &xfs_dir2_ftype_ops; | |
934 | return &xfs_dir2_ops; | |
935 | } | |
4bceb18f DC |
936 | |
937 | const struct xfs_dir_ops * | |
938 | xfs_nondir_get_ops( | |
939 | struct xfs_mount *mp, | |
940 | struct xfs_inode *dp) | |
941 | { | |
942 | if (dp) | |
943 | return dp->d_ops; | |
944 | if (mp->m_nondir_inode_ops) | |
945 | return mp->m_nondir_inode_ops; | |
946 | if (xfs_sb_version_hascrc(&mp->m_sb)) | |
947 | return &xfs_dir3_nondir_ops; | |
948 | return &xfs_dir2_nondir_ops; | |
949 | } |