aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_dir2_format.h
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_dir2_format.h')
-rw-r--r--fs/xfs/xfs_dir2_format.h183
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 */
74typedef __uint16_t xfs_dir2_data_off_t; 91typedef __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
165static inline int
166xfs_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
175static inline struct xfs_dir2_sf_entry * 185static inline struct xfs_dir2_sf_entry *
176xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr) 186xfs_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
192static inline int
193xfs_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
182static inline struct xfs_dir2_sf_entry * 208static inline struct xfs_dir2_sf_entry *
183xfs_dir2_sf_nextentry(struct xfs_dir2_sf_hdr *hdr, 209xfs_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 */
223static inline __uint8_t *
224xfs_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
231static inline __uint8_t
232xfs_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
248static inline void
249xfs_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 */
291typedef struct xfs_dir2_data_entry { 370typedef 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 */
314static inline int xfs_dir2_data_entsize(int n) 394static 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}
407static inline int
408xfs_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
416static inline __uint8_t
417xfs_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
432static inline void
433xfs_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 */
323static inline __be16 * 448static inline __be16 *
324xfs_dir2_data_entry_tag_p(struct xfs_dir2_data_entry *dep) 449xfs_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
386static inline xfs_dir2_data_aoff_t 517static inline xfs_dir2_data_aoff_t
387xfs_dir3_data_dot_offset(struct xfs_dir2_data_hdr *hdr) 518xfs_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)
392static inline xfs_dir2_data_aoff_t 523static inline xfs_dir2_data_aoff_t
393xfs_dir3_data_dotdot_offset(struct xfs_dir2_data_hdr *hdr) 524xfs_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
398static inline xfs_dir2_data_aoff_t 532static inline xfs_dir2_data_aoff_t
399xfs_dir3_data_first_offset(struct xfs_dir2_data_hdr *hdr) 533xfs_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/*