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" | |
25 | #include "xfs_sb.h" | |
26 | #include "xfs_ag.h" | |
27 | #include "xfs_mount.h" | |
28 | #include "xfs_da_format.h" | |
29 | #include "xfs_inode.h" | |
30 | #include "xfs_dir2.h" | |
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 | ||
271 | ASSERT(ftype < XFS_DIR3_FT_MAX); | |
272 | if (ftype >= XFS_DIR3_FT_MAX) | |
273 | return XFS_DIR3_FT_UNKNOWN; | |
274 | return ftype; | |
275 | } | |
276 | ||
277 | static void | |
278 | xfs_dir3_data_put_ftype( | |
279 | struct xfs_dir2_data_entry *dep, | |
280 | __uint8_t type) | |
281 | { | |
282 | ASSERT(type < XFS_DIR3_FT_MAX); | |
283 | ASSERT(dep->namelen != 0); | |
284 | ||
285 | dep->name[dep->namelen] = type; | |
286 | } | |
287 | ||
288 | /* | |
289 | * Pointer to an entry's tag word. | |
290 | */ | |
291 | static __be16 * | |
292 | xfs_dir2_data_entry_tag_p( | |
293 | struct xfs_dir2_data_entry *dep) | |
294 | { | |
295 | return (__be16 *)((char *)dep + | |
296 | xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16)); | |
297 | } | |
298 | ||
299 | static __be16 * | |
300 | xfs_dir3_data_entry_tag_p( | |
301 | struct xfs_dir2_data_entry *dep) | |
302 | { | |
303 | return (__be16 *)((char *)dep + | |
304 | xfs_dir3_data_entsize(dep->namelen) - sizeof(__be16)); | |
305 | } | |
306 | ||
9d23fc85 DC |
307 | /* |
308 | * location of . and .. in data space (always block 0) | |
309 | */ | |
310 | static struct xfs_dir2_data_entry * | |
311 | xfs_dir2_data_dot_entry_p( | |
312 | struct xfs_dir2_data_hdr *hdr) | |
313 | { | |
314 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e | 315 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); |
9d23fc85 DC |
316 | } |
317 | ||
318 | static struct xfs_dir2_data_entry * | |
319 | xfs_dir2_data_dotdot_entry_p( | |
320 | struct xfs_dir2_data_hdr *hdr) | |
321 | { | |
322 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e DC |
323 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + |
324 | XFS_DIR2_DATA_ENTSIZE(1)); | |
9d23fc85 DC |
325 | } |
326 | ||
327 | static struct xfs_dir2_data_entry * | |
328 | xfs_dir2_data_first_entry_p( | |
329 | struct xfs_dir2_data_hdr *hdr) | |
330 | { | |
331 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e DC |
332 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + |
333 | XFS_DIR2_DATA_ENTSIZE(1) + | |
334 | XFS_DIR2_DATA_ENTSIZE(2)); | |
9d23fc85 DC |
335 | } |
336 | ||
b01ef655 DC |
337 | static struct xfs_dir2_data_entry * |
338 | xfs_dir2_ftype_data_dotdot_entry_p( | |
339 | struct xfs_dir2_data_hdr *hdr) | |
340 | { | |
341 | return (struct xfs_dir2_data_entry *) | |
342 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + | |
343 | XFS_DIR3_DATA_ENTSIZE(1)); | |
344 | } | |
345 | ||
346 | static struct xfs_dir2_data_entry * | |
347 | xfs_dir2_ftype_data_first_entry_p( | |
348 | struct xfs_dir2_data_hdr *hdr) | |
349 | { | |
350 | return (struct xfs_dir2_data_entry *) | |
351 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + | |
352 | XFS_DIR3_DATA_ENTSIZE(1) + | |
353 | XFS_DIR3_DATA_ENTSIZE(2)); | |
354 | } | |
355 | ||
9d23fc85 DC |
356 | static struct xfs_dir2_data_entry * |
357 | xfs_dir3_data_dot_entry_p( | |
358 | struct xfs_dir2_data_hdr *hdr) | |
359 | { | |
360 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e | 361 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); |
9d23fc85 DC |
362 | } |
363 | ||
364 | static struct xfs_dir2_data_entry * | |
365 | xfs_dir3_data_dotdot_entry_p( | |
366 | struct xfs_dir2_data_hdr *hdr) | |
367 | { | |
368 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e DC |
369 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + |
370 | XFS_DIR3_DATA_ENTSIZE(1)); | |
9d23fc85 DC |
371 | } |
372 | ||
373 | static struct xfs_dir2_data_entry * | |
374 | xfs_dir3_data_first_entry_p( | |
375 | struct xfs_dir2_data_hdr *hdr) | |
376 | { | |
377 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e DC |
378 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + |
379 | XFS_DIR3_DATA_ENTSIZE(1) + | |
380 | XFS_DIR3_DATA_ENTSIZE(2)); | |
9d23fc85 DC |
381 | } |
382 | ||
2ca98774 DC |
383 | static struct xfs_dir2_data_free * |
384 | xfs_dir2_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) | |
385 | { | |
386 | return hdr->bestfree; | |
387 | } | |
388 | ||
389 | static struct xfs_dir2_data_free * | |
390 | xfs_dir3_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) | |
391 | { | |
392 | return ((struct xfs_dir3_data_hdr *)hdr)->best_free; | |
393 | } | |
394 | ||
2ca98774 DC |
395 | static struct xfs_dir2_data_entry * |
396 | xfs_dir2_data_entry_p(struct xfs_dir2_data_hdr *hdr) | |
397 | { | |
398 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e | 399 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); |
2ca98774 DC |
400 | } |
401 | ||
402 | static struct xfs_dir2_data_unused * | |
403 | xfs_dir2_data_unused_p(struct xfs_dir2_data_hdr *hdr) | |
404 | { | |
405 | return (struct xfs_dir2_data_unused *) | |
1c9a5b2e | 406 | ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); |
2ca98774 DC |
407 | } |
408 | ||
409 | static struct xfs_dir2_data_entry * | |
410 | xfs_dir3_data_entry_p(struct xfs_dir2_data_hdr *hdr) | |
411 | { | |
412 | return (struct xfs_dir2_data_entry *) | |
1c9a5b2e | 413 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); |
2ca98774 DC |
414 | } |
415 | ||
416 | static struct xfs_dir2_data_unused * | |
417 | xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr) | |
418 | { | |
419 | return (struct xfs_dir2_data_unused *) | |
1c9a5b2e | 420 | ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); |
2ca98774 DC |
421 | } |
422 | ||
4141956a DC |
423 | |
424 | /* | |
425 | * Directory Leaf block operations | |
426 | */ | |
4141956a DC |
427 | static int |
428 | xfs_dir2_max_leaf_ents(struct xfs_mount *mp) | |
429 | { | |
1c9a5b2e | 430 | return (mp->m_dirblksize - sizeof(struct xfs_dir2_leaf_hdr)) / |
4141956a DC |
431 | (uint)sizeof(struct xfs_dir2_leaf_entry); |
432 | } | |
433 | ||
434 | static struct xfs_dir2_leaf_entry * | |
435 | xfs_dir2_leaf_ents_p(struct xfs_dir2_leaf *lp) | |
436 | { | |
437 | return lp->__ents; | |
438 | } | |
439 | ||
01ba43b8 | 440 | static int |
4141956a DC |
441 | xfs_dir3_max_leaf_ents(struct xfs_mount *mp) |
442 | { | |
1c9a5b2e | 443 | return (mp->m_dirblksize - sizeof(struct xfs_dir3_leaf_hdr)) / |
4141956a DC |
444 | (uint)sizeof(struct xfs_dir2_leaf_entry); |
445 | } | |
446 | ||
01ba43b8 | 447 | static struct xfs_dir2_leaf_entry * |
4141956a DC |
448 | xfs_dir3_leaf_ents_p(struct xfs_dir2_leaf *lp) |
449 | { | |
450 | return ((struct xfs_dir3_leaf *)lp)->__ents; | |
451 | } | |
452 | ||
01ba43b8 DC |
453 | static void |
454 | xfs_dir2_leaf_hdr_from_disk( | |
455 | struct xfs_dir3_icleaf_hdr *to, | |
456 | struct xfs_dir2_leaf *from) | |
457 | { | |
458 | to->forw = be32_to_cpu(from->hdr.info.forw); | |
459 | to->back = be32_to_cpu(from->hdr.info.back); | |
460 | to->magic = be16_to_cpu(from->hdr.info.magic); | |
461 | to->count = be16_to_cpu(from->hdr.count); | |
462 | to->stale = be16_to_cpu(from->hdr.stale); | |
463 | ||
464 | ASSERT(to->magic == XFS_DIR2_LEAF1_MAGIC || | |
465 | to->magic == XFS_DIR2_LEAFN_MAGIC); | |
466 | } | |
467 | ||
468 | static void | |
469 | xfs_dir2_leaf_hdr_to_disk( | |
470 | struct xfs_dir2_leaf *to, | |
471 | struct xfs_dir3_icleaf_hdr *from) | |
472 | { | |
473 | ASSERT(from->magic == XFS_DIR2_LEAF1_MAGIC || | |
474 | from->magic == XFS_DIR2_LEAFN_MAGIC); | |
475 | ||
476 | to->hdr.info.forw = cpu_to_be32(from->forw); | |
477 | to->hdr.info.back = cpu_to_be32(from->back); | |
478 | to->hdr.info.magic = cpu_to_be16(from->magic); | |
479 | to->hdr.count = cpu_to_be16(from->count); | |
480 | to->hdr.stale = cpu_to_be16(from->stale); | |
481 | } | |
482 | ||
483 | static void | |
484 | xfs_dir3_leaf_hdr_from_disk( | |
485 | struct xfs_dir3_icleaf_hdr *to, | |
486 | struct xfs_dir2_leaf *from) | |
487 | { | |
488 | struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)from; | |
489 | ||
490 | to->forw = be32_to_cpu(hdr3->info.hdr.forw); | |
491 | to->back = be32_to_cpu(hdr3->info.hdr.back); | |
492 | to->magic = be16_to_cpu(hdr3->info.hdr.magic); | |
493 | to->count = be16_to_cpu(hdr3->count); | |
494 | to->stale = be16_to_cpu(hdr3->stale); | |
495 | ||
496 | ASSERT(to->magic == XFS_DIR3_LEAF1_MAGIC || | |
497 | to->magic == XFS_DIR3_LEAFN_MAGIC); | |
498 | } | |
499 | ||
500 | static void | |
501 | xfs_dir3_leaf_hdr_to_disk( | |
502 | struct xfs_dir2_leaf *to, | |
503 | struct xfs_dir3_icleaf_hdr *from) | |
504 | { | |
505 | struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)to; | |
506 | ||
507 | ASSERT(from->magic == XFS_DIR3_LEAF1_MAGIC || | |
508 | from->magic == XFS_DIR3_LEAFN_MAGIC); | |
509 | ||
510 | hdr3->info.hdr.forw = cpu_to_be32(from->forw); | |
511 | hdr3->info.hdr.back = cpu_to_be32(from->back); | |
512 | hdr3->info.hdr.magic = cpu_to_be16(from->magic); | |
513 | hdr3->count = cpu_to_be16(from->count); | |
514 | hdr3->stale = cpu_to_be16(from->stale); | |
515 | } | |
516 | ||
517 | ||
4bceb18f DC |
518 | /* |
519 | * Directory/Attribute Node block operations | |
520 | */ | |
4bceb18f DC |
521 | static struct xfs_da_node_entry * |
522 | xfs_da2_node_tree_p(struct xfs_da_intnode *dap) | |
523 | { | |
524 | return dap->__btree; | |
525 | } | |
526 | ||
1c9a5b2e | 527 | static struct xfs_da_node_entry * |
4bceb18f DC |
528 | xfs_da3_node_tree_p(struct xfs_da_intnode *dap) |
529 | { | |
530 | return ((struct xfs_da3_intnode *)dap)->__btree; | |
531 | } | |
532 | ||
01ba43b8 DC |
533 | static void |
534 | xfs_da2_node_hdr_from_disk( | |
535 | struct xfs_da3_icnode_hdr *to, | |
536 | struct xfs_da_intnode *from) | |
537 | { | |
538 | ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC)); | |
539 | to->forw = be32_to_cpu(from->hdr.info.forw); | |
540 | to->back = be32_to_cpu(from->hdr.info.back); | |
541 | to->magic = be16_to_cpu(from->hdr.info.magic); | |
542 | to->count = be16_to_cpu(from->hdr.__count); | |
543 | to->level = be16_to_cpu(from->hdr.__level); | |
544 | } | |
545 | ||
546 | static void | |
547 | xfs_da2_node_hdr_to_disk( | |
548 | struct xfs_da_intnode *to, | |
549 | struct xfs_da3_icnode_hdr *from) | |
550 | { | |
551 | ASSERT(from->magic == XFS_DA_NODE_MAGIC); | |
552 | to->hdr.info.forw = cpu_to_be32(from->forw); | |
553 | to->hdr.info.back = cpu_to_be32(from->back); | |
554 | to->hdr.info.magic = cpu_to_be16(from->magic); | |
555 | to->hdr.__count = cpu_to_be16(from->count); | |
556 | to->hdr.__level = cpu_to_be16(from->level); | |
557 | } | |
558 | ||
559 | static void | |
560 | xfs_da3_node_hdr_from_disk( | |
561 | struct xfs_da3_icnode_hdr *to, | |
562 | struct xfs_da_intnode *from) | |
563 | { | |
564 | struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)from; | |
565 | ||
566 | ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)); | |
567 | to->forw = be32_to_cpu(hdr3->info.hdr.forw); | |
568 | to->back = be32_to_cpu(hdr3->info.hdr.back); | |
569 | to->magic = be16_to_cpu(hdr3->info.hdr.magic); | |
570 | to->count = be16_to_cpu(hdr3->__count); | |
571 | to->level = be16_to_cpu(hdr3->__level); | |
572 | } | |
573 | ||
574 | static void | |
575 | xfs_da3_node_hdr_to_disk( | |
576 | struct xfs_da_intnode *to, | |
577 | struct xfs_da3_icnode_hdr *from) | |
578 | { | |
579 | struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)to; | |
580 | ||
581 | ASSERT(from->magic == XFS_DA3_NODE_MAGIC); | |
582 | hdr3->info.hdr.forw = cpu_to_be32(from->forw); | |
583 | hdr3->info.hdr.back = cpu_to_be32(from->back); | |
584 | hdr3->info.hdr.magic = cpu_to_be16(from->magic); | |
585 | hdr3->__count = cpu_to_be16(from->count); | |
586 | hdr3->__level = cpu_to_be16(from->level); | |
587 | } | |
588 | ||
589 | ||
590 | /* | |
591 | * Directory free space block operations | |
592 | */ | |
24dd0f54 DC |
593 | static int |
594 | xfs_dir2_free_max_bests(struct xfs_mount *mp) | |
595 | { | |
1c9a5b2e | 596 | return (mp->m_dirblksize - sizeof(struct xfs_dir2_free_hdr)) / |
24dd0f54 DC |
597 | sizeof(xfs_dir2_data_off_t); |
598 | } | |
599 | ||
600 | static __be16 * | |
601 | xfs_dir2_free_bests_p(struct xfs_dir2_free *free) | |
602 | { | |
1c9a5b2e | 603 | return (__be16 *)((char *)free + sizeof(struct xfs_dir2_free_hdr)); |
24dd0f54 DC |
604 | } |
605 | ||
606 | /* | |
607 | * Convert data space db to the corresponding free db. | |
608 | */ | |
609 | static xfs_dir2_db_t | |
610 | xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db) | |
611 | { | |
612 | return XFS_DIR2_FREE_FIRSTDB(mp) + db / xfs_dir2_free_max_bests(mp); | |
613 | } | |
614 | ||
615 | /* | |
616 | * Convert data space db to the corresponding index in a free db. | |
617 | */ | |
618 | static int | |
619 | xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db) | |
620 | { | |
621 | return db % xfs_dir2_free_max_bests(mp); | |
622 | } | |
623 | ||
24dd0f54 DC |
624 | static int |
625 | xfs_dir3_free_max_bests(struct xfs_mount *mp) | |
626 | { | |
1c9a5b2e | 627 | return (mp->m_dirblksize - 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 | |
641 | xfs_dir3_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db) | |
642 | { | |
643 | return XFS_DIR2_FREE_FIRSTDB(mp) + db / xfs_dir3_free_max_bests(mp); | |
644 | } | |
645 | ||
646 | /* | |
647 | * Convert data space db to the corresponding index in a free db. | |
648 | */ | |
649 | static int | |
650 | xfs_dir3_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db) | |
651 | { | |
652 | return db % xfs_dir3_free_max_bests(mp); | |
653 | } | |
654 | ||
01ba43b8 DC |
655 | static void |
656 | xfs_dir2_free_hdr_from_disk( | |
657 | struct xfs_dir3_icfree_hdr *to, | |
658 | struct xfs_dir2_free *from) | |
659 | { | |
660 | to->magic = be32_to_cpu(from->hdr.magic); | |
661 | to->firstdb = be32_to_cpu(from->hdr.firstdb); | |
662 | to->nvalid = be32_to_cpu(from->hdr.nvalid); | |
663 | to->nused = be32_to_cpu(from->hdr.nused); | |
664 | ASSERT(to->magic == XFS_DIR2_FREE_MAGIC); | |
665 | } | |
666 | ||
667 | static void | |
668 | xfs_dir2_free_hdr_to_disk( | |
669 | struct xfs_dir2_free *to, | |
670 | struct xfs_dir3_icfree_hdr *from) | |
671 | { | |
672 | ASSERT(from->magic == XFS_DIR2_FREE_MAGIC); | |
673 | ||
674 | to->hdr.magic = cpu_to_be32(from->magic); | |
675 | to->hdr.firstdb = cpu_to_be32(from->firstdb); | |
676 | to->hdr.nvalid = cpu_to_be32(from->nvalid); | |
677 | to->hdr.nused = cpu_to_be32(from->nused); | |
678 | } | |
679 | ||
680 | static void | |
681 | xfs_dir3_free_hdr_from_disk( | |
682 | struct xfs_dir3_icfree_hdr *to, | |
683 | struct xfs_dir2_free *from) | |
684 | { | |
685 | struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)from; | |
686 | ||
687 | to->magic = be32_to_cpu(hdr3->hdr.magic); | |
688 | to->firstdb = be32_to_cpu(hdr3->firstdb); | |
689 | to->nvalid = be32_to_cpu(hdr3->nvalid); | |
690 | to->nused = be32_to_cpu(hdr3->nused); | |
691 | ||
692 | ASSERT(to->magic == XFS_DIR3_FREE_MAGIC); | |
693 | } | |
694 | ||
695 | static void | |
696 | xfs_dir3_free_hdr_to_disk( | |
697 | struct xfs_dir2_free *to, | |
698 | struct xfs_dir3_icfree_hdr *from) | |
699 | { | |
700 | struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)to; | |
701 | ||
702 | ASSERT(from->magic == XFS_DIR3_FREE_MAGIC); | |
703 | ||
704 | hdr3->hdr.magic = cpu_to_be32(from->magic); | |
705 | hdr3->firstdb = cpu_to_be32(from->firstdb); | |
706 | hdr3->nvalid = cpu_to_be32(from->nvalid); | |
707 | hdr3->nused = cpu_to_be32(from->nused); | |
708 | } | |
709 | ||
632b89e8 | 710 | static const struct xfs_dir_ops xfs_dir2_ops = { |
32c5483a DC |
711 | .sf_entsize = xfs_dir2_sf_entsize, |
712 | .sf_nextentry = xfs_dir2_sf_nextentry, | |
4740175e DC |
713 | .sf_get_ftype = xfs_dir2_sfe_get_ftype, |
714 | .sf_put_ftype = xfs_dir2_sfe_put_ftype, | |
715 | .sf_get_ino = xfs_dir2_sfe_get_ino, | |
716 | .sf_put_ino = xfs_dir2_sfe_put_ino, | |
717 | .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, | |
718 | .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, | |
9d23fc85 DC |
719 | |
720 | .data_entsize = xfs_dir2_data_entsize, | |
721 | .data_get_ftype = xfs_dir2_data_get_ftype, | |
722 | .data_put_ftype = xfs_dir2_data_put_ftype, | |
723 | .data_entry_tag_p = xfs_dir2_data_entry_tag_p, | |
2ca98774 | 724 | .data_bestfree_p = xfs_dir2_data_bestfree_p, |
9d23fc85 | 725 | |
1c9a5b2e DC |
726 | .data_dot_offset = sizeof(struct xfs_dir2_data_hdr), |
727 | .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) + | |
728 | XFS_DIR2_DATA_ENTSIZE(1), | |
729 | .data_first_offset = sizeof(struct xfs_dir2_data_hdr) + | |
730 | XFS_DIR2_DATA_ENTSIZE(1) + | |
731 | XFS_DIR2_DATA_ENTSIZE(2), | |
732 | .data_entry_offset = sizeof(struct xfs_dir2_data_hdr), | |
2ca98774 | 733 | |
9d23fc85 DC |
734 | .data_dot_entry_p = xfs_dir2_data_dot_entry_p, |
735 | .data_dotdot_entry_p = xfs_dir2_data_dotdot_entry_p, | |
736 | .data_first_entry_p = xfs_dir2_data_first_entry_p, | |
2ca98774 DC |
737 | .data_entry_p = xfs_dir2_data_entry_p, |
738 | .data_unused_p = xfs_dir2_data_unused_p, | |
739 | ||
1c9a5b2e | 740 | .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), |
01ba43b8 DC |
741 | .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, |
742 | .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, | |
4141956a DC |
743 | .leaf_max_ents = xfs_dir2_max_leaf_ents, |
744 | .leaf_ents_p = xfs_dir2_leaf_ents_p, | |
745 | ||
1c9a5b2e | 746 | .node_hdr_size = sizeof(struct xfs_da_node_hdr), |
01ba43b8 DC |
747 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, |
748 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
4bceb18f | 749 | .node_tree_p = xfs_da2_node_tree_p, |
01ba43b8 | 750 | |
1c9a5b2e | 751 | .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), |
01ba43b8 DC |
752 | .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, |
753 | .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, | |
24dd0f54 DC |
754 | .free_max_bests = xfs_dir2_free_max_bests, |
755 | .free_bests_p = xfs_dir2_free_bests_p, | |
756 | .db_to_fdb = xfs_dir2_db_to_fdb, | |
757 | .db_to_fdindex = xfs_dir2_db_to_fdindex, | |
32c5483a DC |
758 | }; |
759 | ||
632b89e8 | 760 | static const struct xfs_dir_ops xfs_dir2_ftype_ops = { |
32c5483a DC |
761 | .sf_entsize = xfs_dir3_sf_entsize, |
762 | .sf_nextentry = xfs_dir3_sf_nextentry, | |
4740175e DC |
763 | .sf_get_ftype = xfs_dir3_sfe_get_ftype, |
764 | .sf_put_ftype = xfs_dir3_sfe_put_ftype, | |
765 | .sf_get_ino = xfs_dir3_sfe_get_ino, | |
766 | .sf_put_ino = xfs_dir3_sfe_put_ino, | |
767 | .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, | |
768 | .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, | |
9d23fc85 DC |
769 | |
770 | .data_entsize = xfs_dir3_data_entsize, | |
771 | .data_get_ftype = xfs_dir3_data_get_ftype, | |
772 | .data_put_ftype = xfs_dir3_data_put_ftype, | |
773 | .data_entry_tag_p = xfs_dir3_data_entry_tag_p, | |
2ca98774 | 774 | .data_bestfree_p = xfs_dir2_data_bestfree_p, |
9d23fc85 | 775 | |
1c9a5b2e DC |
776 | .data_dot_offset = sizeof(struct xfs_dir2_data_hdr), |
777 | .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) + | |
778 | XFS_DIR3_DATA_ENTSIZE(1), | |
779 | .data_first_offset = sizeof(struct xfs_dir2_data_hdr) + | |
780 | XFS_DIR3_DATA_ENTSIZE(1) + | |
781 | XFS_DIR3_DATA_ENTSIZE(2), | |
782 | .data_entry_offset = sizeof(struct xfs_dir2_data_hdr), | |
2ca98774 | 783 | |
9d23fc85 | 784 | .data_dot_entry_p = xfs_dir2_data_dot_entry_p, |
b01ef655 DC |
785 | .data_dotdot_entry_p = xfs_dir2_ftype_data_dotdot_entry_p, |
786 | .data_first_entry_p = xfs_dir2_ftype_data_first_entry_p, | |
2ca98774 DC |
787 | .data_entry_p = xfs_dir2_data_entry_p, |
788 | .data_unused_p = xfs_dir2_data_unused_p, | |
4141956a | 789 | |
1c9a5b2e | 790 | .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), |
01ba43b8 DC |
791 | .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, |
792 | .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, | |
4141956a DC |
793 | .leaf_max_ents = xfs_dir2_max_leaf_ents, |
794 | .leaf_ents_p = xfs_dir2_leaf_ents_p, | |
4bceb18f | 795 | |
1c9a5b2e | 796 | .node_hdr_size = sizeof(struct xfs_da_node_hdr), |
01ba43b8 DC |
797 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, |
798 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
4bceb18f | 799 | .node_tree_p = xfs_da2_node_tree_p, |
01ba43b8 | 800 | |
1c9a5b2e | 801 | .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), |
01ba43b8 DC |
802 | .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, |
803 | .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, | |
24dd0f54 DC |
804 | .free_max_bests = xfs_dir2_free_max_bests, |
805 | .free_bests_p = xfs_dir2_free_bests_p, | |
806 | .db_to_fdb = xfs_dir2_db_to_fdb, | |
807 | .db_to_fdindex = xfs_dir2_db_to_fdindex, | |
32c5483a DC |
808 | }; |
809 | ||
632b89e8 | 810 | static const struct xfs_dir_ops xfs_dir3_ops = { |
32c5483a DC |
811 | .sf_entsize = xfs_dir3_sf_entsize, |
812 | .sf_nextentry = xfs_dir3_sf_nextentry, | |
4740175e DC |
813 | .sf_get_ftype = xfs_dir3_sfe_get_ftype, |
814 | .sf_put_ftype = xfs_dir3_sfe_put_ftype, | |
815 | .sf_get_ino = xfs_dir3_sfe_get_ino, | |
816 | .sf_put_ino = xfs_dir3_sfe_put_ino, | |
817 | .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, | |
818 | .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, | |
9d23fc85 DC |
819 | |
820 | .data_entsize = xfs_dir3_data_entsize, | |
821 | .data_get_ftype = xfs_dir3_data_get_ftype, | |
822 | .data_put_ftype = xfs_dir3_data_put_ftype, | |
823 | .data_entry_tag_p = xfs_dir3_data_entry_tag_p, | |
2ca98774 | 824 | .data_bestfree_p = xfs_dir3_data_bestfree_p, |
9d23fc85 | 825 | |
1c9a5b2e DC |
826 | .data_dot_offset = sizeof(struct xfs_dir3_data_hdr), |
827 | .data_dotdot_offset = sizeof(struct xfs_dir3_data_hdr) + | |
828 | XFS_DIR3_DATA_ENTSIZE(1), | |
829 | .data_first_offset = sizeof(struct xfs_dir3_data_hdr) + | |
830 | XFS_DIR3_DATA_ENTSIZE(1) + | |
831 | XFS_DIR3_DATA_ENTSIZE(2), | |
832 | .data_entry_offset = sizeof(struct xfs_dir3_data_hdr), | |
2ca98774 | 833 | |
9d23fc85 DC |
834 | .data_dot_entry_p = xfs_dir3_data_dot_entry_p, |
835 | .data_dotdot_entry_p = xfs_dir3_data_dotdot_entry_p, | |
836 | .data_first_entry_p = xfs_dir3_data_first_entry_p, | |
2ca98774 DC |
837 | .data_entry_p = xfs_dir3_data_entry_p, |
838 | .data_unused_p = xfs_dir3_data_unused_p, | |
4141956a | 839 | |
1c9a5b2e | 840 | .leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr), |
01ba43b8 DC |
841 | .leaf_hdr_to_disk = xfs_dir3_leaf_hdr_to_disk, |
842 | .leaf_hdr_from_disk = xfs_dir3_leaf_hdr_from_disk, | |
4141956a DC |
843 | .leaf_max_ents = xfs_dir3_max_leaf_ents, |
844 | .leaf_ents_p = xfs_dir3_leaf_ents_p, | |
4bceb18f | 845 | |
1c9a5b2e | 846 | .node_hdr_size = sizeof(struct xfs_da3_node_hdr), |
01ba43b8 DC |
847 | .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, |
848 | .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, | |
4bceb18f | 849 | .node_tree_p = xfs_da3_node_tree_p, |
01ba43b8 | 850 | |
1c9a5b2e | 851 | .free_hdr_size = sizeof(struct xfs_dir3_free_hdr), |
01ba43b8 DC |
852 | .free_hdr_to_disk = xfs_dir3_free_hdr_to_disk, |
853 | .free_hdr_from_disk = xfs_dir3_free_hdr_from_disk, | |
24dd0f54 DC |
854 | .free_max_bests = xfs_dir3_free_max_bests, |
855 | .free_bests_p = xfs_dir3_free_bests_p, | |
856 | .db_to_fdb = xfs_dir3_db_to_fdb, | |
857 | .db_to_fdindex = xfs_dir3_db_to_fdindex, | |
4bceb18f DC |
858 | }; |
859 | ||
632b89e8 | 860 | static const struct xfs_dir_ops xfs_dir2_nondir_ops = { |
1c9a5b2e | 861 | .node_hdr_size = sizeof(struct xfs_da_node_hdr), |
01ba43b8 DC |
862 | .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, |
863 | .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, | |
4bceb18f DC |
864 | .node_tree_p = xfs_da2_node_tree_p, |
865 | }; | |
866 | ||
632b89e8 | 867 | static const struct xfs_dir_ops xfs_dir3_nondir_ops = { |
1c9a5b2e | 868 | .node_hdr_size = sizeof(struct xfs_da3_node_hdr), |
01ba43b8 DC |
869 | .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, |
870 | .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, | |
4bceb18f | 871 | .node_tree_p = xfs_da3_node_tree_p, |
32c5483a | 872 | }; |
4141956a DC |
873 | |
874 | /* | |
875 | * Return the ops structure according to the current config. If we are passed | |
876 | * an inode, then that overrides the default config we use which is based on | |
877 | * feature bits. | |
878 | */ | |
879 | const struct xfs_dir_ops * | |
880 | xfs_dir_get_ops( | |
881 | struct xfs_mount *mp, | |
882 | struct xfs_inode *dp) | |
883 | { | |
884 | if (dp) | |
885 | return dp->d_ops; | |
886 | if (mp->m_dir_inode_ops) | |
887 | return mp->m_dir_inode_ops; | |
888 | if (xfs_sb_version_hascrc(&mp->m_sb)) | |
889 | return &xfs_dir3_ops; | |
890 | if (xfs_sb_version_hasftype(&mp->m_sb)) | |
891 | return &xfs_dir2_ftype_ops; | |
892 | return &xfs_dir2_ops; | |
893 | } | |
4bceb18f DC |
894 | |
895 | const struct xfs_dir_ops * | |
896 | xfs_nondir_get_ops( | |
897 | struct xfs_mount *mp, | |
898 | struct xfs_inode *dp) | |
899 | { | |
900 | if (dp) | |
901 | return dp->d_ops; | |
902 | if (mp->m_nondir_inode_ops) | |
903 | return mp->m_nondir_inode_ops; | |
904 | if (xfs_sb_version_hascrc(&mp->m_sb)) | |
905 | return &xfs_dir3_nondir_ops; | |
906 | return &xfs_dir2_nondir_ops; | |
907 | } |