xfs: vectorise directory data operations
[firefly-linux-kernel-4.4.55.git] / fs / xfs / xfs_da_format.c
1 /*
2  * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc.
3  * Copyright (c) 2013 Red Hat, Inc.
4  * All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it would be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write the Free Software Foundation,
17  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 #include "xfs.h"
20 #include "xfs_fs.h"
21 #include "xfs_format.h"
22 #include "xfs_log_format.h"
23 #include "xfs_trans_resv.h"
24 #include "xfs_sb.h"
25 #include "xfs_ag.h"
26 #include "xfs_mount.h"
27 #include "xfs_da_format.h"
28 #include "xfs_inode.h"
29 #include "xfs_dir2.h"
30
31 /*
32  * Shortform directory ops
33  */
34 static int
35 xfs_dir2_sf_entsize(
36         struct xfs_dir2_sf_hdr  *hdr,
37         int                     len)
38 {
39         int count = sizeof(struct xfs_dir2_sf_entry);   /* namelen + offset */
40
41         count += len;                                   /* name */
42         count += hdr->i8count ? sizeof(xfs_dir2_ino8_t) :
43                                 sizeof(xfs_dir2_ino4_t); /* ino # */
44         return count;
45 }
46
47 static int
48 xfs_dir3_sf_entsize(
49         struct xfs_dir2_sf_hdr  *hdr,
50         int                     len)
51 {
52         return xfs_dir2_sf_entsize(hdr, len) + sizeof(__uint8_t);
53 }
54
55 static struct xfs_dir2_sf_entry *
56 xfs_dir2_sf_nextentry(
57         struct xfs_dir2_sf_hdr  *hdr,
58         struct xfs_dir2_sf_entry *sfep)
59 {
60         return (struct xfs_dir2_sf_entry *)
61                 ((char *)sfep + xfs_dir2_sf_entsize(hdr, sfep->namelen));
62 }
63
64 static struct xfs_dir2_sf_entry *
65 xfs_dir3_sf_nextentry(
66         struct xfs_dir2_sf_hdr  *hdr,
67         struct xfs_dir2_sf_entry *sfep)
68 {
69         return (struct xfs_dir2_sf_entry *)
70                 ((char *)sfep + xfs_dir3_sf_entsize(hdr, sfep->namelen));
71 }
72
73
74 /*
75  * For filetype enabled shortform directories, the file type field is stored at
76  * the end of the name.  Because it's only a single byte, endian conversion is
77  * not necessary. For non-filetype enable directories, the type is always
78  * unknown and we never store the value.
79  */
80 static __uint8_t
81 xfs_dir2_sfe_get_ftype(
82         struct xfs_dir2_sf_entry *sfep)
83 {
84         return XFS_DIR3_FT_UNKNOWN;
85 }
86
87 static void
88 xfs_dir2_sfe_put_ftype(
89         struct xfs_dir2_sf_entry *sfep,
90         __uint8_t               ftype)
91 {
92         ASSERT(ftype < XFS_DIR3_FT_MAX);
93 }
94
95 static __uint8_t
96 xfs_dir3_sfe_get_ftype(
97         struct xfs_dir2_sf_entry *sfep)
98 {
99         __uint8_t       ftype;
100
101         ftype = sfep->name[sfep->namelen];
102         if (ftype >= XFS_DIR3_FT_MAX)
103                 return XFS_DIR3_FT_UNKNOWN;
104         return ftype;
105 }
106
107 static void
108 xfs_dir3_sfe_put_ftype(
109         struct xfs_dir2_sf_entry *sfep,
110         __uint8_t               ftype)
111 {
112         ASSERT(ftype < XFS_DIR3_FT_MAX);
113
114         sfep->name[sfep->namelen] = ftype;
115 }
116
117 /*
118  * Inode numbers in short-form directories can come in two versions,
119  * either 4 bytes or 8 bytes wide.  These helpers deal with the
120  * two forms transparently by looking at the headers i8count field.
121  *
122  * For 64-bit inode number the most significant byte must be zero.
123  */
124 static xfs_ino_t
125 xfs_dir2_sf_get_ino(
126         struct xfs_dir2_sf_hdr  *hdr,
127         xfs_dir2_inou_t         *from)
128 {
129         if (hdr->i8count)
130                 return get_unaligned_be64(&from->i8.i) & 0x00ffffffffffffffULL;
131         else
132                 return get_unaligned_be32(&from->i4.i);
133 }
134
135 static void
136 xfs_dir2_sf_put_ino(
137         struct xfs_dir2_sf_hdr  *hdr,
138         xfs_dir2_inou_t         *to,
139         xfs_ino_t               ino)
140 {
141         ASSERT((ino & 0xff00000000000000ULL) == 0);
142
143         if (hdr->i8count)
144                 put_unaligned_be64(ino, &to->i8.i);
145         else
146                 put_unaligned_be32(ino, &to->i4.i);
147 }
148
149 static xfs_ino_t
150 xfs_dir2_sf_get_parent_ino(
151         struct xfs_dir2_sf_hdr  *hdr)
152 {
153         return xfs_dir2_sf_get_ino(hdr, &hdr->parent);
154 }
155
156 static void
157 xfs_dir2_sf_put_parent_ino(
158         struct xfs_dir2_sf_hdr  *hdr,
159         xfs_ino_t               ino)
160 {
161         xfs_dir2_sf_put_ino(hdr, &hdr->parent, ino);
162 }
163
164 /*
165  * In short-form directory entries the inode numbers are stored at variable
166  * offset behind the entry name. If the entry stores a filetype value, then it
167  * sits between the name and the inode number. Hence the inode numbers may only
168  * be accessed through the helpers below.
169  */
170 static xfs_ino_t
171 xfs_dir2_sfe_get_ino(
172         struct xfs_dir2_sf_hdr  *hdr,
173         struct xfs_dir2_sf_entry *sfep)
174 {
175         return xfs_dir2_sf_get_ino(hdr,
176                                 (xfs_dir2_inou_t *)&sfep->name[sfep->namelen]);
177 }
178
179 static void
180 xfs_dir2_sfe_put_ino(
181         struct xfs_dir2_sf_hdr  *hdr,
182         struct xfs_dir2_sf_entry *sfep,
183         xfs_ino_t               ino)
184 {
185         xfs_dir2_sf_put_ino(hdr,
186                             (xfs_dir2_inou_t *)&sfep->name[sfep->namelen], ino);
187 }
188
189 static xfs_ino_t
190 xfs_dir3_sfe_get_ino(
191         struct xfs_dir2_sf_hdr  *hdr,
192         struct xfs_dir2_sf_entry *sfep)
193 {
194         return xfs_dir2_sf_get_ino(hdr,
195                         (xfs_dir2_inou_t *)&sfep->name[sfep->namelen + 1]);
196 }
197
198 static void
199 xfs_dir3_sfe_put_ino(
200         struct xfs_dir2_sf_hdr  *hdr,
201         struct xfs_dir2_sf_entry *sfep,
202         xfs_ino_t               ino)
203 {
204         xfs_dir2_sf_put_ino(hdr,
205                         (xfs_dir2_inou_t *)&sfep->name[sfep->namelen + 1], ino);
206 }
207
208
209 /*
210  * Directory data block operations
211  */
212 static int
213 __xfs_dir3_data_entsize(
214         bool    ftype,
215         int     n)
216 {
217         int     size = offsetof(struct xfs_dir2_data_entry, name[0]);
218
219         size += n;
220         size += sizeof(xfs_dir2_data_off_t);
221         if (ftype)
222                 size += sizeof(__uint8_t);
223         return roundup(size, XFS_DIR2_DATA_ALIGN);
224 }
225
226 static int
227 xfs_dir2_data_entsize(
228         int                     n)
229 {
230         return __xfs_dir3_data_entsize(false, n);
231 }
232 static int
233 xfs_dir3_data_entsize(
234         int                     n)
235 {
236         return __xfs_dir3_data_entsize(true, n);
237 }
238
239 static __uint8_t
240 xfs_dir2_data_get_ftype(
241         struct xfs_dir2_data_entry *dep)
242 {
243         return XFS_DIR3_FT_UNKNOWN;
244 }
245
246 static void
247 xfs_dir2_data_put_ftype(
248         struct xfs_dir2_data_entry *dep,
249         __uint8_t               ftype)
250 {
251         ASSERT(ftype < XFS_DIR3_FT_MAX);
252 }
253
254 static __uint8_t
255 xfs_dir3_data_get_ftype(
256         struct xfs_dir2_data_entry *dep)
257 {
258         __uint8_t       ftype = dep->name[dep->namelen];
259
260         ASSERT(ftype < XFS_DIR3_FT_MAX);
261         if (ftype >= XFS_DIR3_FT_MAX)
262                 return XFS_DIR3_FT_UNKNOWN;
263         return ftype;
264 }
265
266 static void
267 xfs_dir3_data_put_ftype(
268         struct xfs_dir2_data_entry *dep,
269         __uint8_t               type)
270 {
271         ASSERT(type < XFS_DIR3_FT_MAX);
272         ASSERT(dep->namelen != 0);
273
274         dep->name[dep->namelen] = type;
275 }
276
277 /*
278  * Pointer to an entry's tag word.
279  */
280 static __be16 *
281 xfs_dir2_data_entry_tag_p(
282         struct xfs_dir2_data_entry *dep)
283 {
284         return (__be16 *)((char *)dep +
285                 xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16));
286 }
287
288 static __be16 *
289 xfs_dir3_data_entry_tag_p(
290         struct xfs_dir2_data_entry *dep)
291 {
292         return (__be16 *)((char *)dep +
293                 xfs_dir3_data_entsize(dep->namelen) - sizeof(__be16));
294 }
295
296 /*
297  * Offsets of . and .. in data space (always block 0)
298  */
299 static xfs_dir2_data_aoff_t
300 xfs_dir2_data_dot_offset(void)
301 {
302         return sizeof(struct xfs_dir2_data_hdr);
303 }
304
305 static xfs_dir2_data_aoff_t
306 xfs_dir2_data_dotdot_offset(void)
307 {
308         return xfs_dir2_data_dot_offset() + xfs_dir2_data_entsize(1);
309 }
310
311 static xfs_dir2_data_aoff_t
312 xfs_dir2_data_first_offset(void)
313 {
314         return xfs_dir2_data_dotdot_offset() + xfs_dir2_data_entsize(2);
315 }
316
317 static xfs_dir2_data_aoff_t
318 xfs_dir3_data_dot_offset(void)
319 {
320         return sizeof(struct xfs_dir3_data_hdr);
321 }
322
323 static xfs_dir2_data_aoff_t
324 xfs_dir3_data_dotdot_offset(void)
325 {
326         return xfs_dir3_data_dot_offset() + xfs_dir3_data_entsize(1);
327 }
328
329 static xfs_dir2_data_aoff_t
330 xfs_dir3_data_first_offset(void)
331 {
332         return xfs_dir3_data_dotdot_offset() + xfs_dir3_data_entsize(2);
333 }
334
335 /*
336  * location of . and .. in data space (always block 0)
337  */
338 static struct xfs_dir2_data_entry *
339 xfs_dir2_data_dot_entry_p(
340         struct xfs_dir2_data_hdr *hdr)
341 {
342         return (struct xfs_dir2_data_entry *)
343                 ((char *)hdr + xfs_dir2_data_dot_offset());
344 }
345
346 static struct xfs_dir2_data_entry *
347 xfs_dir2_data_dotdot_entry_p(
348         struct xfs_dir2_data_hdr *hdr)
349 {
350         return (struct xfs_dir2_data_entry *)
351                 ((char *)hdr + xfs_dir2_data_dotdot_offset());
352 }
353
354 static struct xfs_dir2_data_entry *
355 xfs_dir2_data_first_entry_p(
356         struct xfs_dir2_data_hdr *hdr)
357 {
358         return (struct xfs_dir2_data_entry *)
359                 ((char *)hdr + xfs_dir2_data_first_offset());
360 }
361
362 static struct xfs_dir2_data_entry *
363 xfs_dir3_data_dot_entry_p(
364         struct xfs_dir2_data_hdr *hdr)
365 {
366         return (struct xfs_dir2_data_entry *)
367                 ((char *)hdr + xfs_dir3_data_dot_offset());
368 }
369
370 static struct xfs_dir2_data_entry *
371 xfs_dir3_data_dotdot_entry_p(
372         struct xfs_dir2_data_hdr *hdr)
373 {
374         return (struct xfs_dir2_data_entry *)
375                 ((char *)hdr + xfs_dir3_data_dotdot_offset());
376 }
377
378 static struct xfs_dir2_data_entry *
379 xfs_dir3_data_first_entry_p(
380         struct xfs_dir2_data_hdr *hdr)
381 {
382         return (struct xfs_dir2_data_entry *)
383                 ((char *)hdr + xfs_dir3_data_first_offset());
384 }
385
386 const struct xfs_dir_ops xfs_dir2_ops = {
387         .sf_entsize = xfs_dir2_sf_entsize,
388         .sf_nextentry = xfs_dir2_sf_nextentry,
389         .sf_get_ftype = xfs_dir2_sfe_get_ftype,
390         .sf_put_ftype = xfs_dir2_sfe_put_ftype,
391         .sf_get_ino = xfs_dir2_sfe_get_ino,
392         .sf_put_ino = xfs_dir2_sfe_put_ino,
393         .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino,
394         .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino,
395
396         .data_entsize = xfs_dir2_data_entsize,
397         .data_get_ftype = xfs_dir2_data_get_ftype,
398         .data_put_ftype = xfs_dir2_data_put_ftype,
399         .data_entry_tag_p = xfs_dir2_data_entry_tag_p,
400
401         .data_dot_offset = xfs_dir2_data_dot_offset,
402         .data_dotdot_offset = xfs_dir2_data_dotdot_offset,
403         .data_first_offset = xfs_dir2_data_first_offset,
404         .data_dot_entry_p = xfs_dir2_data_dot_entry_p,
405         .data_dotdot_entry_p = xfs_dir2_data_dotdot_entry_p,
406         .data_first_entry_p = xfs_dir2_data_first_entry_p,
407 };
408
409 const struct xfs_dir_ops xfs_dir2_ftype_ops = {
410         .sf_entsize = xfs_dir3_sf_entsize,
411         .sf_nextentry = xfs_dir3_sf_nextentry,
412         .sf_get_ftype = xfs_dir3_sfe_get_ftype,
413         .sf_put_ftype = xfs_dir3_sfe_put_ftype,
414         .sf_get_ino = xfs_dir3_sfe_get_ino,
415         .sf_put_ino = xfs_dir3_sfe_put_ino,
416         .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino,
417         .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino,
418
419         .data_entsize = xfs_dir3_data_entsize,
420         .data_get_ftype = xfs_dir3_data_get_ftype,
421         .data_put_ftype = xfs_dir3_data_put_ftype,
422         .data_entry_tag_p = xfs_dir3_data_entry_tag_p,
423
424         .data_dot_offset = xfs_dir2_data_dot_offset,
425         .data_dotdot_offset = xfs_dir2_data_dotdot_offset,
426         .data_first_offset = xfs_dir2_data_first_offset,
427         .data_dot_entry_p = xfs_dir2_data_dot_entry_p,
428         .data_dotdot_entry_p = xfs_dir2_data_dotdot_entry_p,
429         .data_first_entry_p = xfs_dir2_data_first_entry_p,
430 };
431
432 const struct xfs_dir_ops xfs_dir3_ops = {
433         .sf_entsize = xfs_dir3_sf_entsize,
434         .sf_nextentry = xfs_dir3_sf_nextentry,
435         .sf_get_ftype = xfs_dir3_sfe_get_ftype,
436         .sf_put_ftype = xfs_dir3_sfe_put_ftype,
437         .sf_get_ino = xfs_dir3_sfe_get_ino,
438         .sf_put_ino = xfs_dir3_sfe_put_ino,
439         .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino,
440         .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino,
441
442         .data_entsize = xfs_dir3_data_entsize,
443         .data_get_ftype = xfs_dir3_data_get_ftype,
444         .data_put_ftype = xfs_dir3_data_put_ftype,
445         .data_entry_tag_p = xfs_dir3_data_entry_tag_p,
446
447         .data_dot_offset = xfs_dir3_data_dot_offset,
448         .data_dotdot_offset = xfs_dir3_data_dotdot_offset,
449         .data_first_offset = xfs_dir3_data_first_offset,
450         .data_dot_entry_p = xfs_dir3_data_dot_entry_p,
451         .data_dotdot_entry_p = xfs_dir3_data_dotdot_entry_p,
452         .data_first_entry_p = xfs_dir3_data_first_entry_p,
453 };