diff options
Diffstat (limited to 'fs/xfs/xfs_dir2_format.h')
-rw-r--r-- | fs/xfs/xfs_dir2_format.h | 183 |
1 files changed, 160 insertions, 23 deletions
diff --git a/fs/xfs/xfs_dir2_format.h b/fs/xfs/xfs_dir2_format.h index 2095e17b75cb..a0961a61ac1a 100644 --- a/fs/xfs/xfs_dir2_format.h +++ b/fs/xfs/xfs_dir2_format.h | |||
@@ -69,6 +69,23 @@ | |||
69 | #define XFS_DIR3_FREE_MAGIC 0x58444633 /* XDF3: free index blocks */ | 69 | #define XFS_DIR3_FREE_MAGIC 0x58444633 /* XDF3: free index blocks */ |
70 | 70 | ||
71 | /* | 71 | /* |
72 | * Dirents in version 3 directories have a file type field. Additions to this | ||
73 | * list are an on-disk format change, requiring feature bits. Valid values | ||
74 | * are as follows: | ||
75 | */ | ||
76 | #define XFS_DIR3_FT_UNKNOWN 0 | ||
77 | #define XFS_DIR3_FT_REG_FILE 1 | ||
78 | #define XFS_DIR3_FT_DIR 2 | ||
79 | #define XFS_DIR3_FT_CHRDEV 3 | ||
80 | #define XFS_DIR3_FT_BLKDEV 4 | ||
81 | #define XFS_DIR3_FT_FIFO 5 | ||
82 | #define XFS_DIR3_FT_SOCK 6 | ||
83 | #define XFS_DIR3_FT_SYMLINK 7 | ||
84 | #define XFS_DIR3_FT_WHT 8 | ||
85 | |||
86 | #define XFS_DIR3_FT_MAX 9 | ||
87 | |||
88 | /* | ||
72 | * Byte offset in data block and shortform entry. | 89 | * Byte offset in data block and shortform entry. |
73 | */ | 90 | */ |
74 | typedef __uint16_t xfs_dir2_data_off_t; | 91 | typedef __uint16_t xfs_dir2_data_off_t; |
@@ -138,6 +155,9 @@ typedef struct xfs_dir2_sf_entry { | |||
138 | xfs_dir2_sf_off_t offset; /* saved offset */ | 155 | xfs_dir2_sf_off_t offset; /* saved offset */ |
139 | __u8 name[]; /* name, variable size */ | 156 | __u8 name[]; /* name, variable size */ |
140 | /* | 157 | /* |
158 | * A single byte containing the file type field follows the inode | ||
159 | * number for version 3 directory entries. | ||
160 | * | ||
141 | * A xfs_dir2_ino8_t or xfs_dir2_ino4_t follows here, at a | 161 | * A xfs_dir2_ino8_t or xfs_dir2_ino4_t follows here, at a |
142 | * variable offset after the name. | 162 | * variable offset after the name. |
143 | */ | 163 | */ |
@@ -162,16 +182,6 @@ xfs_dir2_sf_put_offset(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off) | |||
162 | put_unaligned_be16(off, &sfep->offset.i); | 182 | put_unaligned_be16(off, &sfep->offset.i); |
163 | } | 183 | } |
164 | 184 | ||
165 | static inline int | ||
166 | xfs_dir2_sf_entsize(struct xfs_dir2_sf_hdr *hdr, int len) | ||
167 | { | ||
168 | return sizeof(struct xfs_dir2_sf_entry) + /* namelen + offset */ | ||
169 | len + /* name */ | ||
170 | (hdr->i8count ? /* ino */ | ||
171 | sizeof(xfs_dir2_ino8_t) : | ||
172 | sizeof(xfs_dir2_ino4_t)); | ||
173 | } | ||
174 | |||
175 | static inline struct xfs_dir2_sf_entry * | 185 | static inline struct xfs_dir2_sf_entry * |
176 | xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr) | 186 | xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr) |
177 | { | 187 | { |
@@ -179,14 +189,78 @@ xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr) | |||
179 | ((char *)hdr + xfs_dir2_sf_hdr_size(hdr->i8count)); | 189 | ((char *)hdr + xfs_dir2_sf_hdr_size(hdr->i8count)); |
180 | } | 190 | } |
181 | 191 | ||
192 | static inline int | ||
193 | xfs_dir3_sf_entsize( | ||
194 | struct xfs_mount *mp, | ||
195 | struct xfs_dir2_sf_hdr *hdr, | ||
196 | int len) | ||
197 | { | ||
198 | int count = sizeof(struct xfs_dir2_sf_entry); /* namelen + offset */ | ||
199 | |||
200 | count += len; /* name */ | ||
201 | count += hdr->i8count ? sizeof(xfs_dir2_ino8_t) : | ||
202 | sizeof(xfs_dir2_ino4_t); /* ino # */ | ||
203 | if (xfs_sb_version_hasftype(&mp->m_sb)) | ||
204 | count += sizeof(__uint8_t); /* file type */ | ||
205 | return count; | ||
206 | } | ||
207 | |||
182 | static inline struct xfs_dir2_sf_entry * | 208 | static inline struct xfs_dir2_sf_entry * |
183 | xfs_dir2_sf_nextentry(struct xfs_dir2_sf_hdr *hdr, | 209 | xfs_dir3_sf_nextentry( |
184 | struct xfs_dir2_sf_entry *sfep) | 210 | struct xfs_mount *mp, |
211 | struct xfs_dir2_sf_hdr *hdr, | ||
212 | struct xfs_dir2_sf_entry *sfep) | ||
185 | { | 213 | { |
186 | return (struct xfs_dir2_sf_entry *) | 214 | return (struct xfs_dir2_sf_entry *) |
187 | ((char *)sfep + xfs_dir2_sf_entsize(hdr, sfep->namelen)); | 215 | ((char *)sfep + xfs_dir3_sf_entsize(mp, hdr, sfep->namelen)); |
188 | } | 216 | } |
189 | 217 | ||
218 | /* | ||
219 | * in dir3 shortform directories, the file type field is stored at a variable | ||
220 | * offset after the inode number. Because it's only a single byte, endian | ||
221 | * conversion is not necessary. | ||
222 | */ | ||
223 | static inline __uint8_t * | ||
224 | xfs_dir3_sfe_ftypep( | ||
225 | struct xfs_dir2_sf_hdr *hdr, | ||
226 | struct xfs_dir2_sf_entry *sfep) | ||
227 | { | ||
228 | return (__uint8_t *)&sfep->name[sfep->namelen]; | ||
229 | } | ||
230 | |||
231 | static inline __uint8_t | ||
232 | xfs_dir3_sfe_get_ftype( | ||
233 | struct xfs_mount *mp, | ||
234 | struct xfs_dir2_sf_hdr *hdr, | ||
235 | struct xfs_dir2_sf_entry *sfep) | ||
236 | { | ||
237 | __uint8_t *ftp; | ||
238 | |||
239 | if (!xfs_sb_version_hasftype(&mp->m_sb)) | ||
240 | return XFS_DIR3_FT_UNKNOWN; | ||
241 | |||
242 | ftp = xfs_dir3_sfe_ftypep(hdr, sfep); | ||
243 | if (*ftp >= XFS_DIR3_FT_MAX) | ||
244 | return XFS_DIR3_FT_UNKNOWN; | ||
245 | return *ftp; | ||
246 | } | ||
247 | |||
248 | static inline void | ||
249 | xfs_dir3_sfe_put_ftype( | ||
250 | struct xfs_mount *mp, | ||
251 | struct xfs_dir2_sf_hdr *hdr, | ||
252 | struct xfs_dir2_sf_entry *sfep, | ||
253 | __uint8_t ftype) | ||
254 | { | ||
255 | __uint8_t *ftp; | ||
256 | |||
257 | ASSERT(ftype < XFS_DIR3_FT_MAX); | ||
258 | |||
259 | if (!xfs_sb_version_hasftype(&mp->m_sb)) | ||
260 | return; | ||
261 | ftp = xfs_dir3_sfe_ftypep(hdr, sfep); | ||
262 | *ftp = ftype; | ||
263 | } | ||
190 | 264 | ||
191 | /* | 265 | /* |
192 | * Data block structures. | 266 | * Data block structures. |
@@ -286,12 +360,18 @@ xfs_dir3_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) | |||
286 | * Active entry in a data block. | 360 | * Active entry in a data block. |
287 | * | 361 | * |
288 | * Aligned to 8 bytes. After the variable length name field there is a | 362 | * Aligned to 8 bytes. After the variable length name field there is a |
289 | * 2 byte tag field, which can be accessed using xfs_dir2_data_entry_tag_p. | 363 | * 2 byte tag field, which can be accessed using xfs_dir3_data_entry_tag_p. |
364 | * | ||
365 | * For dir3 structures, there is file type field between the name and the tag. | ||
366 | * This can only be manipulated by helper functions. It is packed hard against | ||
367 | * the end of the name so any padding for rounding is between the file type and | ||
368 | * the tag. | ||
290 | */ | 369 | */ |
291 | typedef struct xfs_dir2_data_entry { | 370 | typedef struct xfs_dir2_data_entry { |
292 | __be64 inumber; /* inode number */ | 371 | __be64 inumber; /* inode number */ |
293 | __u8 namelen; /* name length */ | 372 | __u8 namelen; /* name length */ |
294 | __u8 name[]; /* name bytes, no null */ | 373 | __u8 name[]; /* name bytes, no null */ |
374 | /* __u8 filetype; */ /* type of inode we point to */ | ||
295 | /* __be16 tag; */ /* starting offset of us */ | 375 | /* __be16 tag; */ /* starting offset of us */ |
296 | } xfs_dir2_data_entry_t; | 376 | } xfs_dir2_data_entry_t; |
297 | 377 | ||
@@ -311,20 +391,67 @@ typedef struct xfs_dir2_data_unused { | |||
311 | /* | 391 | /* |
312 | * Size of a data entry. | 392 | * Size of a data entry. |
313 | */ | 393 | */ |
314 | static inline int xfs_dir2_data_entsize(int n) | 394 | static inline int |
395 | __xfs_dir3_data_entsize( | ||
396 | bool ftype, | ||
397 | int n) | ||
315 | { | 398 | { |
316 | return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n + | 399 | int size = offsetof(struct xfs_dir2_data_entry, name[0]); |
317 | (uint)sizeof(xfs_dir2_data_off_t), XFS_DIR2_DATA_ALIGN); | 400 | |
401 | size += n; | ||
402 | size += sizeof(xfs_dir2_data_off_t); | ||
403 | if (ftype) | ||
404 | size += sizeof(__uint8_t); | ||
405 | return roundup(size, XFS_DIR2_DATA_ALIGN); | ||
406 | } | ||
407 | static inline int | ||
408 | xfs_dir3_data_entsize( | ||
409 | struct xfs_mount *mp, | ||
410 | int n) | ||
411 | { | ||
412 | bool ftype = xfs_sb_version_hasftype(&mp->m_sb) ? true : false; | ||
413 | return __xfs_dir3_data_entsize(ftype, n); | ||
414 | } | ||
415 | |||
416 | static inline __uint8_t | ||
417 | xfs_dir3_dirent_get_ftype( | ||
418 | struct xfs_mount *mp, | ||
419 | struct xfs_dir2_data_entry *dep) | ||
420 | { | ||
421 | if (xfs_sb_version_hasftype(&mp->m_sb)) { | ||
422 | __uint8_t type = dep->name[dep->namelen]; | ||
423 | |||
424 | ASSERT(type < XFS_DIR3_FT_MAX); | ||
425 | if (type < XFS_DIR3_FT_MAX) | ||
426 | return type; | ||
427 | |||
428 | } | ||
429 | return XFS_DIR3_FT_UNKNOWN; | ||
430 | } | ||
431 | |||
432 | static inline void | ||
433 | xfs_dir3_dirent_put_ftype( | ||
434 | struct xfs_mount *mp, | ||
435 | struct xfs_dir2_data_entry *dep, | ||
436 | __uint8_t type) | ||
437 | { | ||
438 | ASSERT(type < XFS_DIR3_FT_MAX); | ||
439 | ASSERT(dep->namelen != 0); | ||
440 | |||
441 | if (xfs_sb_version_hasftype(&mp->m_sb)) | ||
442 | dep->name[dep->namelen] = type; | ||
318 | } | 443 | } |
319 | 444 | ||
320 | /* | 445 | /* |
321 | * Pointer to an entry's tag word. | 446 | * Pointer to an entry's tag word. |
322 | */ | 447 | */ |
323 | static inline __be16 * | 448 | static inline __be16 * |
324 | xfs_dir2_data_entry_tag_p(struct xfs_dir2_data_entry *dep) | 449 | xfs_dir3_data_entry_tag_p( |
450 | struct xfs_mount *mp, | ||
451 | struct xfs_dir2_data_entry *dep) | ||
325 | { | 452 | { |
326 | return (__be16 *)((char *)dep + | 453 | return (__be16 *)((char *)dep + |
327 | xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16)); | 454 | xfs_dir3_data_entsize(mp, dep->namelen) - sizeof(__be16)); |
328 | } | 455 | } |
329 | 456 | ||
330 | /* | 457 | /* |
@@ -375,13 +502,17 @@ xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr) | |||
375 | * data block header because the sfe embeds the block offset of the entry into | 502 | * data block header because the sfe embeds the block offset of the entry into |
376 | * it so that it doesn't change when format conversion occurs. Bad Things Happen | 503 | * it so that it doesn't change when format conversion occurs. Bad Things Happen |
377 | * if we don't follow this rule. | 504 | * if we don't follow this rule. |
505 | * | ||
506 | * XXX: there is scope for significant optimisation of the logic here. Right | ||
507 | * now we are checking for "dir3 format" over and over again. Ideally we should | ||
508 | * only do it once for each operation. | ||
378 | */ | 509 | */ |
379 | #define XFS_DIR3_DATA_DOT_OFFSET(mp) \ | 510 | #define XFS_DIR3_DATA_DOT_OFFSET(mp) \ |
380 | xfs_dir3_data_hdr_size(xfs_sb_version_hascrc(&(mp)->m_sb)) | 511 | xfs_dir3_data_hdr_size(xfs_sb_version_hascrc(&(mp)->m_sb)) |
381 | #define XFS_DIR3_DATA_DOTDOT_OFFSET(mp) \ | 512 | #define XFS_DIR3_DATA_DOTDOT_OFFSET(mp) \ |
382 | (XFS_DIR3_DATA_DOT_OFFSET(mp) + xfs_dir2_data_entsize(1)) | 513 | (XFS_DIR3_DATA_DOT_OFFSET(mp) + xfs_dir3_data_entsize(mp, 1)) |
383 | #define XFS_DIR3_DATA_FIRST_OFFSET(mp) \ | 514 | #define XFS_DIR3_DATA_FIRST_OFFSET(mp) \ |
384 | (XFS_DIR3_DATA_DOTDOT_OFFSET(mp) + xfs_dir2_data_entsize(2)) | 515 | (XFS_DIR3_DATA_DOTDOT_OFFSET(mp) + xfs_dir3_data_entsize(mp, 2)) |
385 | 516 | ||
386 | static inline xfs_dir2_data_aoff_t | 517 | static inline xfs_dir2_data_aoff_t |
387 | xfs_dir3_data_dot_offset(struct xfs_dir2_data_hdr *hdr) | 518 | xfs_dir3_data_dot_offset(struct xfs_dir2_data_hdr *hdr) |
@@ -392,13 +523,19 @@ xfs_dir3_data_dot_offset(struct xfs_dir2_data_hdr *hdr) | |||
392 | static inline xfs_dir2_data_aoff_t | 523 | static inline xfs_dir2_data_aoff_t |
393 | xfs_dir3_data_dotdot_offset(struct xfs_dir2_data_hdr *hdr) | 524 | xfs_dir3_data_dotdot_offset(struct xfs_dir2_data_hdr *hdr) |
394 | { | 525 | { |
395 | return xfs_dir3_data_dot_offset(hdr) + xfs_dir2_data_entsize(1); | 526 | bool dir3 = hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || |
527 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC); | ||
528 | return xfs_dir3_data_dot_offset(hdr) + | ||
529 | __xfs_dir3_data_entsize(dir3, 1); | ||
396 | } | 530 | } |
397 | 531 | ||
398 | static inline xfs_dir2_data_aoff_t | 532 | static inline xfs_dir2_data_aoff_t |
399 | xfs_dir3_data_first_offset(struct xfs_dir2_data_hdr *hdr) | 533 | xfs_dir3_data_first_offset(struct xfs_dir2_data_hdr *hdr) |
400 | { | 534 | { |
401 | return xfs_dir3_data_dotdot_offset(hdr) + xfs_dir2_data_entsize(2); | 535 | bool dir3 = hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || |
536 | hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC); | ||
537 | return xfs_dir3_data_dotdot_offset(hdr) + | ||
538 | __xfs_dir3_data_entsize(dir3, 2); | ||
402 | } | 539 | } |
403 | 540 | ||
404 | /* | 541 | /* |