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