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