aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-08-12 06:50:09 -0400
committerBen Myers <bpm@sgi.com>2013-08-22 09:40:24 -0400
commit0cb97766f2928579f1029ea7b28ae946cdd6fbe1 (patch)
tree4e64fcd122c5b3ddda050e23efc940eaaea4bb9c /fs/xfs
parented56f34f11da4f491680cd39482fd533134fd589 (diff)
xfs: Add read-only support for dirent filetype field
Add support for the file type field in directory entries so that readdir can return the type of the inode the dirent points to to userspace without first having to read the inode off disk. The encoding of the type field is a single byte that is added to the end of the directory entry name length. For all intents and purposes, it appends a "hidden" byte to the name field which contains the type information. As the directory entry is already of dynamic size, helpers are already required to access and decode the direct entry structures. Hence the relevent extraction and iteration helpers are updated to understand the hidden byte. Helpers for reading and writing the filetype field from the directory entries are also added. Only the read helpers are used by this patch. It also adds all the code necessary to read the type information out of the dirents on disk. Further we add the superblock feature bit and helpers to indicate that we understand the on-disk format change. This is not a compatible change - existing kernels cannot read the new format successfully - so an incompatible feature flag is added. We don't yet allow filesystems to mount with this flag yet - that will be added once write support is added. Finally, the code to take the type from the VFS, convert it to an XFS on-disk type and put it into the xfs_name structures passed around is added, but the directory code does not use this field yet. That will be in the next patch. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_da_btree.h1
-rw-r--r--fs/xfs/xfs_dir2.c5
-rw-r--r--fs/xfs/xfs_dir2.h4
-rw-r--r--fs/xfs/xfs_dir2_block.c16
-rw-r--r--fs/xfs/xfs_dir2_data.c13
-rw-r--r--fs/xfs/xfs_dir2_format.h183
-rw-r--r--fs/xfs/xfs_dir2_leaf.c6
-rw-r--r--fs/xfs/xfs_dir2_node.c8
-rw-r--r--fs/xfs/xfs_dir2_priv.h9
-rw-r--r--fs/xfs/xfs_dir2_readdir.c69
-rw-r--r--fs/xfs/xfs_dir2_sf.c121
-rw-r--r--fs/xfs/xfs_iops.c27
-rw-r--r--fs/xfs/xfs_sb.h22
-rw-r--r--fs/xfs/xfs_types.h1
14 files changed, 362 insertions, 123 deletions
diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h
index 6fb3371c63cf..8cdc77b2e58d 100644
--- a/fs/xfs/xfs_da_btree.h
+++ b/fs/xfs/xfs_da_btree.h
@@ -176,6 +176,7 @@ enum xfs_dacmp {
176typedef struct xfs_da_args { 176typedef struct xfs_da_args {
177 const __uint8_t *name; /* string (maybe not NULL terminated) */ 177 const __uint8_t *name; /* string (maybe not NULL terminated) */
178 int namelen; /* length of string (maybe no NULL) */ 178 int namelen; /* length of string (maybe no NULL) */
179 __uint8_t filetype; /* filetype of inode for directories */
179 __uint8_t *value; /* set of bytes (maybe contain NULLs) */ 180 __uint8_t *value; /* set of bytes (maybe contain NULLs) */
180 int valuelen; /* length of value */ 181 int valuelen; /* length of value */
181 int flags; /* argument flags (eg: ATTR_NOCREATE) */ 182 int flags; /* argument flags (eg: ATTR_NOCREATE) */
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
index 841933c9e80f..f9825b125fcf 100644
--- a/fs/xfs/xfs_dir2.c
+++ b/fs/xfs/xfs_dir2.c
@@ -37,7 +37,8 @@
37#include "xfs_error.h" 37#include "xfs_error.h"
38#include "xfs_trace.h" 38#include "xfs_trace.h"
39 39
40struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2}; 40struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };
41
41 42
42/* 43/*
43 * ASCII case-insensitive (ie. A-Z) support for directories that was 44 * ASCII case-insensitive (ie. A-Z) support for directories that was
@@ -386,6 +387,7 @@ xfs_dir_replace(
386 memset(&args, 0, sizeof(xfs_da_args_t)); 387 memset(&args, 0, sizeof(xfs_da_args_t));
387 args.name = name->name; 388 args.name = name->name;
388 args.namelen = name->len; 389 args.namelen = name->len;
390 args.filetype = name->type;
389 args.hashval = dp->i_mount->m_dirnameops->hashname(name); 391 args.hashval = dp->i_mount->m_dirnameops->hashname(name);
390 args.inumber = inum; 392 args.inumber = inum;
391 args.dp = dp; 393 args.dp = dp;
@@ -433,6 +435,7 @@ xfs_dir_canenter(
433 memset(&args, 0, sizeof(xfs_da_args_t)); 435 memset(&args, 0, sizeof(xfs_da_args_t));
434 args.name = name->name; 436 args.name = name->name;
435 args.namelen = name->len; 437 args.namelen = name->len;
438 args.filetype = name->type;
436 args.hashval = dp->i_mount->m_dirnameops->hashname(name); 439 args.hashval = dp->i_mount->m_dirnameops->hashname(name);
437 args.dp = dp; 440 args.dp = dp;
438 args.whichfork = XFS_DATA_FORK; 441 args.whichfork = XFS_DATA_FORK;
diff --git a/fs/xfs/xfs_dir2.h b/fs/xfs/xfs_dir2.h
index 7fe2b8f0a9e3..768ddad41b84 100644
--- a/fs/xfs/xfs_dir2.h
+++ b/fs/xfs/xfs_dir2.h
@@ -68,8 +68,8 @@ extern int xfs_dir2_sf_to_block(struct xfs_da_args *args);
68extern xfs_ino_t xfs_dir2_sf_get_parent_ino(struct xfs_dir2_sf_hdr *sfp); 68extern xfs_ino_t xfs_dir2_sf_get_parent_ino(struct xfs_dir2_sf_hdr *sfp);
69extern void xfs_dir2_sf_put_parent_ino(struct xfs_dir2_sf_hdr *sfp, 69extern void xfs_dir2_sf_put_parent_ino(struct xfs_dir2_sf_hdr *sfp,
70 xfs_ino_t ino); 70 xfs_ino_t ino);
71extern xfs_ino_t xfs_dir2_sfe_get_ino(struct xfs_dir2_sf_hdr *sfp, 71extern xfs_ino_t xfs_dir3_sfe_get_ino(struct xfs_mount *mp,
72 struct xfs_dir2_sf_entry *sfep); 72 struct xfs_dir2_sf_hdr *sfp, struct xfs_dir2_sf_entry *sfep);
73extern void xfs_dir2_sfe_put_ino( struct xfs_dir2_sf_hdr *, 73extern void xfs_dir2_sfe_put_ino( struct xfs_dir2_sf_hdr *,
74 struct xfs_dir2_sf_entry *sfep, xfs_ino_t ino); 74 struct xfs_dir2_sf_entry *sfep, xfs_ino_t ino);
75 75
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index becd69f6e4b8..1cd2f564e374 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -369,7 +369,7 @@ xfs_dir2_block_addname(
369 if (error) 369 if (error)
370 return error; 370 return error;
371 371
372 len = xfs_dir2_data_entsize(args->namelen); 372 len = xfs_dir3_data_entsize(mp, args->namelen);
373 373
374 /* 374 /*
375 * Set up pointers to parts of the block. 375 * Set up pointers to parts of the block.
@@ -549,7 +549,7 @@ xfs_dir2_block_addname(
549 dep->inumber = cpu_to_be64(args->inumber); 549 dep->inumber = cpu_to_be64(args->inumber);
550 dep->namelen = args->namelen; 550 dep->namelen = args->namelen;
551 memcpy(dep->name, args->name, args->namelen); 551 memcpy(dep->name, args->name, args->namelen);
552 tagp = xfs_dir2_data_entry_tag_p(dep); 552 tagp = xfs_dir3_data_entry_tag_p(mp, dep);
553 *tagp = cpu_to_be16((char *)dep - (char *)hdr); 553 *tagp = cpu_to_be16((char *)dep - (char *)hdr);
554 /* 554 /*
555 * Clean up the bestfree array and log the header, tail, and entry. 555 * Clean up the bestfree array and log the header, tail, and entry.
@@ -799,7 +799,7 @@ xfs_dir2_block_removename(
799 needlog = needscan = 0; 799 needlog = needscan = 0;
800 xfs_dir2_data_make_free(tp, bp, 800 xfs_dir2_data_make_free(tp, bp,
801 (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr), 801 (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr),
802 xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan); 802 xfs_dir3_data_entsize(mp, dep->namelen), &needlog, &needscan);
803 /* 803 /*
804 * Fix up the block tail. 804 * Fix up the block tail.
805 */ 805 */
@@ -1159,7 +1159,7 @@ xfs_dir2_sf_to_block(
1159 dep->inumber = cpu_to_be64(dp->i_ino); 1159 dep->inumber = cpu_to_be64(dp->i_ino);
1160 dep->namelen = 1; 1160 dep->namelen = 1;
1161 dep->name[0] = '.'; 1161 dep->name[0] = '.';
1162 tagp = xfs_dir2_data_entry_tag_p(dep); 1162 tagp = xfs_dir3_data_entry_tag_p(mp, dep);
1163 *tagp = cpu_to_be16((char *)dep - (char *)hdr); 1163 *tagp = cpu_to_be16((char *)dep - (char *)hdr);
1164 xfs_dir2_data_log_entry(tp, bp, dep); 1164 xfs_dir2_data_log_entry(tp, bp, dep);
1165 blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot); 1165 blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot);
@@ -1172,7 +1172,7 @@ xfs_dir2_sf_to_block(
1172 dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp)); 1172 dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp));
1173 dep->namelen = 2; 1173 dep->namelen = 2;
1174 dep->name[0] = dep->name[1] = '.'; 1174 dep->name[0] = dep->name[1] = '.';
1175 tagp = xfs_dir2_data_entry_tag_p(dep); 1175 tagp = xfs_dir3_data_entry_tag_p(mp, dep);
1176 *tagp = cpu_to_be16((char *)dep - (char *)hdr); 1176 *tagp = cpu_to_be16((char *)dep - (char *)hdr);
1177 xfs_dir2_data_log_entry(tp, bp, dep); 1177 xfs_dir2_data_log_entry(tp, bp, dep);
1178 blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot); 1178 blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
@@ -1217,10 +1217,10 @@ xfs_dir2_sf_to_block(
1217 * Copy a real entry. 1217 * Copy a real entry.
1218 */ 1218 */
1219 dep = (xfs_dir2_data_entry_t *)((char *)hdr + newoffset); 1219 dep = (xfs_dir2_data_entry_t *)((char *)hdr + newoffset);
1220 dep->inumber = cpu_to_be64(xfs_dir2_sfe_get_ino(sfp, sfep)); 1220 dep->inumber = cpu_to_be64(xfs_dir3_sfe_get_ino(mp, sfp, sfep));
1221 dep->namelen = sfep->namelen; 1221 dep->namelen = sfep->namelen;
1222 memcpy(dep->name, sfep->name, dep->namelen); 1222 memcpy(dep->name, sfep->name, dep->namelen);
1223 tagp = xfs_dir2_data_entry_tag_p(dep); 1223 tagp = xfs_dir3_data_entry_tag_p(mp, dep);
1224 *tagp = cpu_to_be16((char *)dep - (char *)hdr); 1224 *tagp = cpu_to_be16((char *)dep - (char *)hdr);
1225 xfs_dir2_data_log_entry(tp, bp, dep); 1225 xfs_dir2_data_log_entry(tp, bp, dep);
1226 name.name = sfep->name; 1226 name.name = sfep->name;
@@ -1233,7 +1233,7 @@ xfs_dir2_sf_to_block(
1233 if (++i == sfp->count) 1233 if (++i == sfp->count)
1234 sfep = NULL; 1234 sfep = NULL;
1235 else 1235 else
1236 sfep = xfs_dir2_sf_nextentry(sfp, sfep); 1236 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
1237 } 1237 }
1238 /* Done with the temporary buffer */ 1238 /* Done with the temporary buffer */
1239 kmem_free(sfp); 1239 kmem_free(sfp);
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
index 98c23faa701c..1b59e43d97d9 100644
--- a/fs/xfs/xfs_dir2_data.c
+++ b/fs/xfs/xfs_dir2_data.c
@@ -147,7 +147,7 @@ __xfs_dir3_data_check(
147 XFS_WANT_CORRUPTED_RETURN( 147 XFS_WANT_CORRUPTED_RETURN(
148 !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber))); 148 !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)));
149 XFS_WANT_CORRUPTED_RETURN( 149 XFS_WANT_CORRUPTED_RETURN(
150 be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) == 150 be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)) ==
151 (char *)dep - (char *)hdr); 151 (char *)dep - (char *)hdr);
152 count++; 152 count++;
153 lastfree = 0; 153 lastfree = 0;
@@ -166,7 +166,7 @@ __xfs_dir3_data_check(
166 } 166 }
167 XFS_WANT_CORRUPTED_RETURN(i < be32_to_cpu(btp->count)); 167 XFS_WANT_CORRUPTED_RETURN(i < be32_to_cpu(btp->count));
168 } 168 }
169 p += xfs_dir2_data_entsize(dep->namelen); 169 p += xfs_dir3_data_entsize(mp, dep->namelen);
170 } 170 }
171 /* 171 /*
172 * Need to have seen all the entries and all the bestfree slots. 172 * Need to have seen all the entries and all the bestfree slots.
@@ -536,8 +536,8 @@ xfs_dir2_data_freescan(
536 else { 536 else {
537 dep = (xfs_dir2_data_entry_t *)p; 537 dep = (xfs_dir2_data_entry_t *)p;
538 ASSERT((char *)dep - (char *)hdr == 538 ASSERT((char *)dep - (char *)hdr ==
539 be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep))); 539 be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)));
540 p += xfs_dir2_data_entsize(dep->namelen); 540 p += xfs_dir3_data_entsize(mp, dep->namelen);
541 } 541 }
542 } 542 }
543} 543}
@@ -627,7 +627,8 @@ xfs_dir2_data_log_entry(
627 struct xfs_buf *bp, 627 struct xfs_buf *bp,
628 xfs_dir2_data_entry_t *dep) /* data entry pointer */ 628 xfs_dir2_data_entry_t *dep) /* data entry pointer */
629{ 629{
630 xfs_dir2_data_hdr_t *hdr = bp->b_addr; 630 struct xfs_dir2_data_hdr *hdr = bp->b_addr;
631 struct xfs_mount *mp = tp->t_mountp;
631 632
632 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || 633 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
633 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || 634 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
@@ -635,7 +636,7 @@ xfs_dir2_data_log_entry(
635 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); 636 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
636 637
637 xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr), 638 xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr),
638 (uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) - 639 (uint)((char *)(xfs_dir3_data_entry_tag_p(mp, dep) + 1) -
639 (char *)hdr - 1)); 640 (char *)hdr - 1));
640} 641}
641 642
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/*
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index 591eaf235919..887b1bdec6dd 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -696,7 +696,7 @@ xfs_dir2_leaf_addname(
696 ents = xfs_dir3_leaf_ents_p(leaf); 696 ents = xfs_dir3_leaf_ents_p(leaf);
697 xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); 697 xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
698 bestsp = xfs_dir2_leaf_bests_p(ltp); 698 bestsp = xfs_dir2_leaf_bests_p(ltp);
699 length = xfs_dir2_data_entsize(args->namelen); 699 length = xfs_dir3_data_entsize(mp, args->namelen);
700 700
701 /* 701 /*
702 * See if there are any entries with the same hash value 702 * See if there are any entries with the same hash value
@@ -897,7 +897,7 @@ xfs_dir2_leaf_addname(
897 dep->inumber = cpu_to_be64(args->inumber); 897 dep->inumber = cpu_to_be64(args->inumber);
898 dep->namelen = args->namelen; 898 dep->namelen = args->namelen;
899 memcpy(dep->name, args->name, dep->namelen); 899 memcpy(dep->name, args->name, dep->namelen);
900 tagp = xfs_dir2_data_entry_tag_p(dep); 900 tagp = xfs_dir3_data_entry_tag_p(mp, dep);
901 *tagp = cpu_to_be16((char *)dep - (char *)hdr); 901 *tagp = cpu_to_be16((char *)dep - (char *)hdr);
902 /* 902 /*
903 * Need to scan fix up the bestfree table. 903 * Need to scan fix up the bestfree table.
@@ -1427,7 +1427,7 @@ xfs_dir2_leaf_removename(
1427 */ 1427 */
1428 xfs_dir2_data_make_free(tp, dbp, 1428 xfs_dir2_data_make_free(tp, dbp,
1429 (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr), 1429 (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr),
1430 xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan); 1430 xfs_dir3_data_entsize(mp, dep->namelen), &needlog, &needscan);
1431 /* 1431 /*
1432 * We just mark the leaf entry stale by putting a null in it. 1432 * We just mark the leaf entry stale by putting a null in it.
1433 */ 1433 */
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index 18e287deee66..49f1e9ed492c 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -605,7 +605,7 @@ xfs_dir2_leafn_lookup_for_addname(
605 ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || 605 ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) ||
606 free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); 606 free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
607 } 607 }
608 length = xfs_dir2_data_entsize(args->namelen); 608 length = xfs_dir3_data_entsize(mp, args->namelen);
609 /* 609 /*
610 * Loop over leaf entries with the right hash value. 610 * Loop over leaf entries with the right hash value.
611 */ 611 */
@@ -1259,7 +1259,7 @@ xfs_dir2_leafn_remove(
1259 longest = be16_to_cpu(bf[0].length); 1259 longest = be16_to_cpu(bf[0].length);
1260 needlog = needscan = 0; 1260 needlog = needscan = 0;
1261 xfs_dir2_data_make_free(tp, dbp, off, 1261 xfs_dir2_data_make_free(tp, dbp, off,
1262 xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan); 1262 xfs_dir3_data_entsize(mp, dep->namelen), &needlog, &needscan);
1263 /* 1263 /*
1264 * Rescan the data block freespaces for bestfree. 1264 * Rescan the data block freespaces for bestfree.
1265 * Log the data block header if needed. 1265 * Log the data block header if needed.
@@ -1711,7 +1711,7 @@ xfs_dir2_node_addname_int(
1711 dp = args->dp; 1711 dp = args->dp;
1712 mp = dp->i_mount; 1712 mp = dp->i_mount;
1713 tp = args->trans; 1713 tp = args->trans;
1714 length = xfs_dir2_data_entsize(args->namelen); 1714 length = xfs_dir3_data_entsize(mp, args->namelen);
1715 /* 1715 /*
1716 * If we came in with a freespace block that means that lookup 1716 * If we came in with a freespace block that means that lookup
1717 * found an entry with our hash value. This is the freespace 1717 * found an entry with our hash value. This is the freespace
@@ -2007,7 +2007,7 @@ xfs_dir2_node_addname_int(
2007 dep->inumber = cpu_to_be64(args->inumber); 2007 dep->inumber = cpu_to_be64(args->inumber);
2008 dep->namelen = args->namelen; 2008 dep->namelen = args->namelen;
2009 memcpy(dep->name, args->name, dep->namelen); 2009 memcpy(dep->name, args->name, dep->namelen);
2010 tagp = xfs_dir2_data_entry_tag_p(dep); 2010 tagp = xfs_dir3_data_entry_tag_p(mp, dep);
2011 *tagp = cpu_to_be16((char *)dep - (char *)hdr); 2011 *tagp = cpu_to_be16((char *)dep - (char *)hdr);
2012 xfs_dir2_data_log_entry(tp, dbp, dep); 2012 xfs_dir2_data_log_entry(tp, dbp, dep);
2013 /* 2013 /*
diff --git a/fs/xfs/xfs_dir2_priv.h b/fs/xfs/xfs_dir2_priv.h
index 6d2a99c224b7..1bad84c40829 100644
--- a/fs/xfs/xfs_dir2_priv.h
+++ b/fs/xfs/xfs_dir2_priv.h
@@ -18,6 +18,8 @@
18#ifndef __XFS_DIR2_PRIV_H__ 18#ifndef __XFS_DIR2_PRIV_H__
19#define __XFS_DIR2_PRIV_H__ 19#define __XFS_DIR2_PRIV_H__
20 20
21struct dir_context;
22
21/* xfs_dir2.c */ 23/* xfs_dir2.c */
22extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); 24extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);
23extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space, 25extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space,
@@ -25,6 +27,13 @@ extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space,
25extern int xfs_dir_cilookup_result(struct xfs_da_args *args, 27extern int xfs_dir_cilookup_result(struct xfs_da_args *args,
26 const unsigned char *name, int len); 28 const unsigned char *name, int len);
27 29
30#define S_SHIFT 12
31extern const unsigned char xfs_mode_to_ftype[];
32
33extern unsigned char xfs_dir3_get_dtype(struct xfs_mount *mp,
34 __uint8_t filetype);
35
36
28/* xfs_dir2_block.c */ 37/* xfs_dir2_block.c */
29extern int xfs_dir3_block_read(struct xfs_trans *tp, struct xfs_inode *dp, 38extern int xfs_dir3_block_read(struct xfs_trans *tp, struct xfs_inode *dp,
30 struct xfs_buf **bpp); 39 struct xfs_buf **bpp);
diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c
index 5f4f705eebbb..8993ec17452c 100644
--- a/fs/xfs/xfs_dir2_readdir.c
+++ b/fs/xfs/xfs_dir2_readdir.c
@@ -36,6 +36,44 @@
36#include "xfs_trace.h" 36#include "xfs_trace.h"
37#include "xfs_bmap.h" 37#include "xfs_bmap.h"
38 38
39/*
40 * Directory file type support functions
41 */
42static unsigned char xfs_dir3_filetype_table[] = {
43 DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK,
44 DT_FIFO, DT_SOCK, DT_LNK, DT_WHT,
45};
46
47unsigned char
48xfs_dir3_get_dtype(
49 struct xfs_mount *mp,
50 __uint8_t filetype)
51{
52 if (!xfs_sb_version_hasftype(&mp->m_sb))
53 return DT_UNKNOWN;
54
55 if (filetype >= XFS_DIR3_FT_MAX)
56 return DT_UNKNOWN;
57
58 return xfs_dir3_filetype_table[filetype];
59}
60/*
61 * @mode, if set, indicates that the type field needs to be set up.
62 * This uses the transformation from file mode to DT_* as defined in linux/fs.h
63 * for file type specification. This will be propagated into the directory
64 * structure if appropriate for the given operation and filesystem config.
65 */
66const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = {
67 [0] = XFS_DIR3_FT_UNKNOWN,
68 [S_IFREG >> S_SHIFT] = XFS_DIR3_FT_REG_FILE,
69 [S_IFDIR >> S_SHIFT] = XFS_DIR3_FT_DIR,
70 [S_IFCHR >> S_SHIFT] = XFS_DIR3_FT_CHRDEV,
71 [S_IFBLK >> S_SHIFT] = XFS_DIR3_FT_BLKDEV,
72 [S_IFIFO >> S_SHIFT] = XFS_DIR3_FT_FIFO,
73 [S_IFSOCK >> S_SHIFT] = XFS_DIR3_FT_SOCK,
74 [S_IFLNK >> S_SHIFT] = XFS_DIR3_FT_SYMLINK,
75};
76
39STATIC int 77STATIC int
40xfs_dir2_sf_getdents( 78xfs_dir2_sf_getdents(
41 xfs_inode_t *dp, /* incore directory inode */ 79 xfs_inode_t *dp, /* incore directory inode */
@@ -109,20 +147,23 @@ xfs_dir2_sf_getdents(
109 */ 147 */
110 sfep = xfs_dir2_sf_firstentry(sfp); 148 sfep = xfs_dir2_sf_firstentry(sfp);
111 for (i = 0; i < sfp->count; i++) { 149 for (i = 0; i < sfp->count; i++) {
150 __uint8_t filetype;
151
112 off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, 152 off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
113 xfs_dir2_sf_get_offset(sfep)); 153 xfs_dir2_sf_get_offset(sfep));
114 154
115 if (ctx->pos > off) { 155 if (ctx->pos > off) {
116 sfep = xfs_dir2_sf_nextentry(sfp, sfep); 156 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
117 continue; 157 continue;
118 } 158 }
119 159
120 ino = xfs_dir2_sfe_get_ino(sfp, sfep); 160 ino = xfs_dir3_sfe_get_ino(mp, sfp, sfep);
161 filetype = xfs_dir3_sfe_get_ftype(mp, sfp, sfep);
121 ctx->pos = off & 0x7fffffff; 162 ctx->pos = off & 0x7fffffff;
122 if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, 163 if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino,
123 ino, DT_UNKNOWN)) 164 xfs_dir3_get_dtype(mp, filetype)))
124 return 0; 165 return 0;
125 sfep = xfs_dir2_sf_nextentry(sfp, sfep); 166 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
126 } 167 }
127 168
128 ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) & 169 ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
@@ -180,6 +221,8 @@ xfs_dir2_block_getdents(
180 * Each object is a real entry (dep) or an unused one (dup). 221 * Each object is a real entry (dep) or an unused one (dup).
181 */ 222 */
182 while (ptr < endptr) { 223 while (ptr < endptr) {
224 __uint8_t filetype;
225
183 dup = (xfs_dir2_data_unused_t *)ptr; 226 dup = (xfs_dir2_data_unused_t *)ptr;
184 /* 227 /*
185 * Unused, skip it. 228 * Unused, skip it.
@@ -194,7 +237,7 @@ xfs_dir2_block_getdents(
194 /* 237 /*
195 * Bump pointer for the next iteration. 238 * Bump pointer for the next iteration.
196 */ 239 */
197 ptr += xfs_dir2_data_entsize(dep->namelen); 240 ptr += xfs_dir3_data_entsize(mp, dep->namelen);
198 /* 241 /*
199 * The entry is before the desired starting point, skip it. 242 * The entry is before the desired starting point, skip it.
200 */ 243 */
@@ -205,11 +248,13 @@ xfs_dir2_block_getdents(
205 (char *)dep - (char *)hdr); 248 (char *)dep - (char *)hdr);
206 249
207 ctx->pos = cook & 0x7fffffff; 250 ctx->pos = cook & 0x7fffffff;
251 filetype = xfs_dir3_dirent_get_ftype(mp, dep);
208 /* 252 /*
209 * If it didn't fit, set the final offset to here & return. 253 * If it didn't fit, set the final offset to here & return.
210 */ 254 */
211 if (!dir_emit(ctx, (char *)dep->name, dep->namelen, 255 if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
212 be64_to_cpu(dep->inumber), DT_UNKNOWN)) { 256 be64_to_cpu(dep->inumber),
257 xfs_dir3_get_dtype(mp, filetype))) {
213 xfs_trans_brelse(NULL, bp); 258 xfs_trans_brelse(NULL, bp);
214 return 0; 259 return 0;
215 } 260 }
@@ -500,6 +545,8 @@ xfs_dir2_leaf_getdents(
500 * Get more blocks and readahead as necessary. 545 * Get more blocks and readahead as necessary.
501 */ 546 */
502 while (curoff < XFS_DIR2_LEAF_OFFSET) { 547 while (curoff < XFS_DIR2_LEAF_OFFSET) {
548 __uint8_t filetype;
549
503 /* 550 /*
504 * If we have no buffer, or we're off the end of the 551 * If we have no buffer, or we're off the end of the
505 * current buffer, need to get another one. 552 * current buffer, need to get another one.
@@ -554,7 +601,7 @@ xfs_dir2_leaf_getdents(
554 } 601 }
555 dep = (xfs_dir2_data_entry_t *)ptr; 602 dep = (xfs_dir2_data_entry_t *)ptr;
556 length = 603 length =
557 xfs_dir2_data_entsize(dep->namelen); 604 xfs_dir3_data_entsize(mp, dep->namelen);
558 ptr += length; 605 ptr += length;
559 } 606 }
560 /* 607 /*
@@ -585,11 +632,13 @@ xfs_dir2_leaf_getdents(
585 } 632 }
586 633
587 dep = (xfs_dir2_data_entry_t *)ptr; 634 dep = (xfs_dir2_data_entry_t *)ptr;
588 length = xfs_dir2_data_entsize(dep->namelen); 635 length = xfs_dir3_data_entsize(mp, dep->namelen);
636 filetype = xfs_dir3_dirent_get_ftype(mp, dep);
589 637
590 ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff; 638 ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
591 if (!dir_emit(ctx, (char *)dep->name, dep->namelen, 639 if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
592 be64_to_cpu(dep->inumber), DT_UNKNOWN)) 640 be64_to_cpu(dep->inumber),
641 xfs_dir3_get_dtype(mp, filetype)))
593 break; 642 break;
594 643
595 /* 644 /*
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
index 65b65c5f8c3c..bd14e1a72c62 100644
--- a/fs/xfs/xfs_dir2_sf.c
+++ b/fs/xfs/xfs_dir2_sf.c
@@ -105,31 +105,38 @@ xfs_dir2_sf_put_parent_ino(
105 105
106/* 106/*
107 * In short-form directory entries the inode numbers are stored at variable 107 * In short-form directory entries the inode numbers are stored at variable
108 * offset behind the entry name. The inode numbers may only be accessed 108 * offset behind the entry name. If the entry stores a filetype value, then it
109 * through the helpers below. 109 * sits between the name and the inode number. Hence the inode numbers may only
110 * be accessed through the helpers below.
110 */ 111 */
111static xfs_dir2_inou_t * 112static xfs_dir2_inou_t *
112xfs_dir2_sfe_inop( 113xfs_dir3_sfe_inop(
114 struct xfs_mount *mp,
113 struct xfs_dir2_sf_entry *sfep) 115 struct xfs_dir2_sf_entry *sfep)
114{ 116{
115 return (xfs_dir2_inou_t *)&sfep->name[sfep->namelen]; 117 __uint8_t *ptr = &sfep->name[sfep->namelen];
118 if (xfs_sb_version_hasftype(&mp->m_sb))
119 ptr++;
120 return (xfs_dir2_inou_t *)ptr;
116} 121}
117 122
118xfs_ino_t 123xfs_ino_t
119xfs_dir2_sfe_get_ino( 124xfs_dir3_sfe_get_ino(
125 struct xfs_mount *mp,
120 struct xfs_dir2_sf_hdr *hdr, 126 struct xfs_dir2_sf_hdr *hdr,
121 struct xfs_dir2_sf_entry *sfep) 127 struct xfs_dir2_sf_entry *sfep)
122{ 128{
123 return xfs_dir2_sf_get_ino(hdr, xfs_dir2_sfe_inop(sfep)); 129 return xfs_dir2_sf_get_ino(hdr, xfs_dir3_sfe_inop(mp, sfep));
124} 130}
125 131
126void 132void
127xfs_dir2_sfe_put_ino( 133xfs_dir3_sfe_put_ino(
134 struct xfs_mount *mp,
128 struct xfs_dir2_sf_hdr *hdr, 135 struct xfs_dir2_sf_hdr *hdr,
129 struct xfs_dir2_sf_entry *sfep, 136 struct xfs_dir2_sf_entry *sfep,
130 xfs_ino_t ino) 137 xfs_ino_t ino)
131{ 138{
132 xfs_dir2_sf_put_ino(hdr, xfs_dir2_sfe_inop(sfep), ino); 139 xfs_dir2_sf_put_ino(hdr, xfs_dir3_sfe_inop(mp, sfep), ino);
133} 140}
134 141
135/* 142/*
@@ -157,9 +164,16 @@ xfs_dir2_block_sfsize(
157 int namelen; /* total name bytes */ 164 int namelen; /* total name bytes */
158 xfs_ino_t parent = 0; /* parent inode number */ 165 xfs_ino_t parent = 0; /* parent inode number */
159 int size=0; /* total computed size */ 166 int size=0; /* total computed size */
167 int has_ftype;
160 168
161 mp = dp->i_mount; 169 mp = dp->i_mount;
162 170
171 /*
172 * if there is a filetype field, add the extra byte to the namelen
173 * for each entry that we see.
174 */
175 has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0;
176
163 count = i8count = namelen = 0; 177 count = i8count = namelen = 0;
164 btp = xfs_dir2_block_tail_p(mp, hdr); 178 btp = xfs_dir2_block_tail_p(mp, hdr);
165 blp = xfs_dir2_block_leaf_p(btp); 179 blp = xfs_dir2_block_leaf_p(btp);
@@ -188,9 +202,10 @@ xfs_dir2_block_sfsize(
188 if (!isdot) 202 if (!isdot)
189 i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM; 203 i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
190#endif 204#endif
205 /* take into account the file type field */
191 if (!isdot && !isdotdot) { 206 if (!isdot && !isdotdot) {
192 count++; 207 count++;
193 namelen += dep->namelen; 208 namelen += dep->namelen + has_ftype;
194 } else if (isdotdot) 209 } else if (isdotdot)
195 parent = be64_to_cpu(dep->inumber); 210 parent = be64_to_cpu(dep->inumber);
196 /* 211 /*
@@ -316,12 +331,12 @@ xfs_dir2_block_to_sf(
316 (xfs_dir2_data_aoff_t) 331 (xfs_dir2_data_aoff_t)
317 ((char *)dep - (char *)hdr)); 332 ((char *)dep - (char *)hdr));
318 memcpy(sfep->name, dep->name, dep->namelen); 333 memcpy(sfep->name, dep->name, dep->namelen);
319 xfs_dir2_sfe_put_ino(sfp, sfep, 334 xfs_dir3_sfe_put_ino(mp, sfp, sfep,
320 be64_to_cpu(dep->inumber)); 335 be64_to_cpu(dep->inumber));
321 336
322 sfep = xfs_dir2_sf_nextentry(sfp, sfep); 337 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
323 } 338 }
324 ptr += xfs_dir2_data_entsize(dep->namelen); 339 ptr += xfs_dir3_data_entsize(mp, dep->namelen);
325 } 340 }
326 ASSERT((char *)sfep - (char *)sfp == size); 341 ASSERT((char *)sfep - (char *)sfp == size);
327 xfs_dir2_sf_check(args); 342 xfs_dir2_sf_check(args);
@@ -372,7 +387,7 @@ xfs_dir2_sf_addname(
372 /* 387 /*
373 * Compute entry (and change in) size. 388 * Compute entry (and change in) size.
374 */ 389 */
375 add_entsize = xfs_dir2_sf_entsize(sfp, args->namelen); 390 add_entsize = xfs_dir3_sf_entsize(dp->i_mount, sfp, args->namelen);
376 incr_isize = add_entsize; 391 incr_isize = add_entsize;
377 objchange = 0; 392 objchange = 0;
378#if XFS_BIG_INUMS 393#if XFS_BIG_INUMS
@@ -466,8 +481,9 @@ xfs_dir2_sf_addname_easy(
466 /* 481 /*
467 * Grow the in-inode space. 482 * Grow the in-inode space.
468 */ 483 */
469 xfs_idata_realloc(dp, xfs_dir2_sf_entsize(sfp, args->namelen), 484 xfs_idata_realloc(dp,
470 XFS_DATA_FORK); 485 xfs_dir3_sf_entsize(dp->i_mount, sfp, args->namelen),
486 XFS_DATA_FORK);
471 /* 487 /*
472 * Need to set up again due to realloc of the inode data. 488 * Need to set up again due to realloc of the inode data.
473 */ 489 */
@@ -479,7 +495,7 @@ xfs_dir2_sf_addname_easy(
479 sfep->namelen = args->namelen; 495 sfep->namelen = args->namelen;
480 xfs_dir2_sf_put_offset(sfep, offset); 496 xfs_dir2_sf_put_offset(sfep, offset);
481 memcpy(sfep->name, args->name, sfep->namelen); 497 memcpy(sfep->name, args->name, sfep->namelen);
482 xfs_dir2_sfe_put_ino(sfp, sfep, args->inumber); 498 xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep, args->inumber);
483 /* 499 /*
484 * Update the header and inode. 500 * Update the header and inode.
485 */ 501 */
@@ -519,11 +535,13 @@ xfs_dir2_sf_addname_hard(
519 xfs_dir2_sf_hdr_t *oldsfp; /* original shortform dir */ 535 xfs_dir2_sf_hdr_t *oldsfp; /* original shortform dir */
520 xfs_dir2_sf_entry_t *sfep; /* entry in new dir */ 536 xfs_dir2_sf_entry_t *sfep; /* entry in new dir */
521 xfs_dir2_sf_hdr_t *sfp; /* new shortform dir */ 537 xfs_dir2_sf_hdr_t *sfp; /* new shortform dir */
538 struct xfs_mount *mp;
522 539
523 /* 540 /*
524 * Copy the old directory to the stack buffer. 541 * Copy the old directory to the stack buffer.
525 */ 542 */
526 dp = args->dp; 543 dp = args->dp;
544 mp = dp->i_mount;
527 545
528 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 546 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
529 old_isize = (int)dp->i_d.di_size; 547 old_isize = (int)dp->i_d.di_size;
@@ -535,13 +553,13 @@ xfs_dir2_sf_addname_hard(
535 * to insert the new entry. 553 * to insert the new entry.
536 * If it's going to end up at the end then oldsfep will point there. 554 * If it's going to end up at the end then oldsfep will point there.
537 */ 555 */
538 for (offset = XFS_DIR3_DATA_FIRST_OFFSET(dp->i_mount), 556 for (offset = XFS_DIR3_DATA_FIRST_OFFSET(mp),
539 oldsfep = xfs_dir2_sf_firstentry(oldsfp), 557 oldsfep = xfs_dir2_sf_firstentry(oldsfp),
540 add_datasize = xfs_dir2_data_entsize(args->namelen), 558 add_datasize = xfs_dir3_data_entsize(mp, args->namelen),
541 eof = (char *)oldsfep == &buf[old_isize]; 559 eof = (char *)oldsfep == &buf[old_isize];
542 !eof; 560 !eof;
543 offset = new_offset + xfs_dir2_data_entsize(oldsfep->namelen), 561 offset = new_offset + xfs_dir3_data_entsize(mp, oldsfep->namelen),
544 oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep), 562 oldsfep = xfs_dir3_sf_nextentry(mp, oldsfp, oldsfep),
545 eof = (char *)oldsfep == &buf[old_isize]) { 563 eof = (char *)oldsfep == &buf[old_isize]) {
546 new_offset = xfs_dir2_sf_get_offset(oldsfep); 564 new_offset = xfs_dir2_sf_get_offset(oldsfep);
547 if (offset + add_datasize <= new_offset) 565 if (offset + add_datasize <= new_offset)
@@ -570,7 +588,7 @@ xfs_dir2_sf_addname_hard(
570 sfep->namelen = args->namelen; 588 sfep->namelen = args->namelen;
571 xfs_dir2_sf_put_offset(sfep, offset); 589 xfs_dir2_sf_put_offset(sfep, offset);
572 memcpy(sfep->name, args->name, sfep->namelen); 590 memcpy(sfep->name, args->name, sfep->namelen);
573 xfs_dir2_sfe_put_ino(sfp, sfep, args->inumber); 591 xfs_dir3_sfe_put_ino(mp, sfp, sfep, args->inumber);
574 sfp->count++; 592 sfp->count++;
575#if XFS_BIG_INUMS 593#if XFS_BIG_INUMS
576 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange) 594 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
@@ -580,7 +598,7 @@ xfs_dir2_sf_addname_hard(
580 * If there's more left to copy, do that. 598 * If there's more left to copy, do that.
581 */ 599 */
582 if (!eof) { 600 if (!eof) {
583 sfep = xfs_dir2_sf_nextentry(sfp, sfep); 601 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
584 memcpy(sfep, oldsfep, old_isize - nbytes); 602 memcpy(sfep, oldsfep, old_isize - nbytes);
585 } 603 }
586 kmem_free(buf); 604 kmem_free(buf);
@@ -616,7 +634,7 @@ xfs_dir2_sf_addname_pick(
616 mp = dp->i_mount; 634 mp = dp->i_mount;
617 635
618 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 636 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
619 size = xfs_dir2_data_entsize(args->namelen); 637 size = xfs_dir3_data_entsize(mp, args->namelen);
620 offset = XFS_DIR3_DATA_FIRST_OFFSET(mp); 638 offset = XFS_DIR3_DATA_FIRST_OFFSET(mp);
621 sfep = xfs_dir2_sf_firstentry(sfp); 639 sfep = xfs_dir2_sf_firstentry(sfp);
622 holefit = 0; 640 holefit = 0;
@@ -629,8 +647,8 @@ xfs_dir2_sf_addname_pick(
629 if (!holefit) 647 if (!holefit)
630 holefit = offset + size <= xfs_dir2_sf_get_offset(sfep); 648 holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
631 offset = xfs_dir2_sf_get_offset(sfep) + 649 offset = xfs_dir2_sf_get_offset(sfep) +
632 xfs_dir2_data_entsize(sfep->namelen); 650 xfs_dir3_data_entsize(mp, sfep->namelen);
633 sfep = xfs_dir2_sf_nextentry(sfp, sfep); 651 sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
634 } 652 }
635 /* 653 /*
636 * Calculate data bytes used excluding the new entry, if this 654 * Calculate data bytes used excluding the new entry, if this
@@ -684,31 +702,34 @@ xfs_dir2_sf_check(
684 int offset; /* data offset */ 702 int offset; /* data offset */
685 xfs_dir2_sf_entry_t *sfep; /* shortform dir entry */ 703 xfs_dir2_sf_entry_t *sfep; /* shortform dir entry */
686 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 704 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */
705 struct xfs_mount *mp;
687 706
688 dp = args->dp; 707 dp = args->dp;
708 mp = dp->i_mount;
689 709
690 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 710 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
691 offset = XFS_DIR3_DATA_FIRST_OFFSET(dp->i_mount); 711 offset = XFS_DIR3_DATA_FIRST_OFFSET(mp);
692 ino = xfs_dir2_sf_get_parent_ino(sfp); 712 ino = xfs_dir2_sf_get_parent_ino(sfp);
693 i8count = ino > XFS_DIR2_MAX_SHORT_INUM; 713 i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
694 714
695 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); 715 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
696 i < sfp->count; 716 i < sfp->count;
697 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { 717 i++, sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep)) {
698 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset); 718 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
699 ino = xfs_dir2_sfe_get_ino(sfp, sfep); 719 ino = xfs_dir3_sfe_get_ino(mp, sfp, sfep);
700 i8count += ino > XFS_DIR2_MAX_SHORT_INUM; 720 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
701 offset = 721 offset =
702 xfs_dir2_sf_get_offset(sfep) + 722 xfs_dir2_sf_get_offset(sfep) +
703 xfs_dir2_data_entsize(sfep->namelen); 723 xfs_dir3_data_entsize(mp, sfep->namelen);
724 ASSERT(xfs_dir3_sfe_get_ftype(mp, sfp, sfep) <
725 XFS_DIR3_FT_MAX);
704 } 726 }
705 ASSERT(i8count == sfp->i8count); 727 ASSERT(i8count == sfp->i8count);
706 ASSERT(XFS_BIG_INUMS || i8count == 0); 728 ASSERT(XFS_BIG_INUMS || i8count == 0);
707 ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size); 729 ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size);
708 ASSERT(offset + 730 ASSERT(offset +
709 (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + 731 (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
710 (uint)sizeof(xfs_dir2_block_tail_t) <= 732 (uint)sizeof(xfs_dir2_block_tail_t) <= mp->m_dirblksize);
711 dp->i_mount->m_dirblksize);
712} 733}
713#endif /* DEBUG */ 734#endif /* DEBUG */
714 735
@@ -820,7 +841,7 @@ xfs_dir2_sf_lookup(
820 */ 841 */
821 ci_sfep = NULL; 842 ci_sfep = NULL;
822 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; 843 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
823 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { 844 i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep)) {
824 /* 845 /*
825 * Compare name and if it's an exact match, return the inode 846 * Compare name and if it's an exact match, return the inode
826 * number. If it's the first case-insensitive match, store the 847 * number. If it's the first case-insensitive match, store the
@@ -830,7 +851,8 @@ xfs_dir2_sf_lookup(
830 sfep->namelen); 851 sfep->namelen);
831 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { 852 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
832 args->cmpresult = cmp; 853 args->cmpresult = cmp;
833 args->inumber = xfs_dir2_sfe_get_ino(sfp, sfep); 854 args->inumber = xfs_dir3_sfe_get_ino(dp->i_mount,
855 sfp, sfep);
834 if (cmp == XFS_CMP_EXACT) 856 if (cmp == XFS_CMP_EXACT)
835 return XFS_ERROR(EEXIST); 857 return XFS_ERROR(EEXIST);
836 ci_sfep = sfep; 858 ci_sfep = sfep;
@@ -886,10 +908,10 @@ xfs_dir2_sf_removename(
886 * Find the one we're deleting. 908 * Find the one we're deleting.
887 */ 909 */
888 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; 910 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
889 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { 911 i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep)) {
890 if (xfs_da_compname(args, sfep->name, sfep->namelen) == 912 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
891 XFS_CMP_EXACT) { 913 XFS_CMP_EXACT) {
892 ASSERT(xfs_dir2_sfe_get_ino(sfp, sfep) == 914 ASSERT(xfs_dir3_sfe_get_ino(dp->i_mount, sfp, sfep) ==
893 args->inumber); 915 args->inumber);
894 break; 916 break;
895 } 917 }
@@ -903,7 +925,7 @@ xfs_dir2_sf_removename(
903 * Calculate sizes. 925 * Calculate sizes.
904 */ 926 */
905 byteoff = (int)((char *)sfep - (char *)sfp); 927 byteoff = (int)((char *)sfep - (char *)sfp);
906 entsize = xfs_dir2_sf_entsize(sfp, args->namelen); 928 entsize = xfs_dir3_sf_entsize(dp->i_mount, sfp, args->namelen);
907 newsize = oldsize - entsize; 929 newsize = oldsize - entsize;
908 /* 930 /*
909 * Copy the part if any after the removed entry, sliding it down. 931 * Copy the part if any after the removed entry, sliding it down.
@@ -1019,16 +1041,17 @@ xfs_dir2_sf_replace(
1019 * Normal entry, look for the name. 1041 * Normal entry, look for the name.
1020 */ 1042 */
1021 else { 1043 else {
1022 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); 1044 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
1023 i < sfp->count; 1045 i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep)) {
1024 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
1025 if (xfs_da_compname(args, sfep->name, sfep->namelen) == 1046 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
1026 XFS_CMP_EXACT) { 1047 XFS_CMP_EXACT) {
1027#if XFS_BIG_INUMS || defined(DEBUG) 1048#if XFS_BIG_INUMS || defined(DEBUG)
1028 ino = xfs_dir2_sfe_get_ino(sfp, sfep); 1049 ino = xfs_dir3_sfe_get_ino(dp->i_mount,
1050 sfp, sfep);
1029 ASSERT(args->inumber != ino); 1051 ASSERT(args->inumber != ino);
1030#endif 1052#endif
1031 xfs_dir2_sfe_put_ino(sfp, sfep, args->inumber); 1053 xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep,
1054 args->inumber);
1032 break; 1055 break;
1033 } 1056 }
1034 } 1057 }
@@ -1136,13 +1159,13 @@ xfs_dir2_sf_toino4(
1136 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), 1159 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1137 oldsfep = xfs_dir2_sf_firstentry(oldsfp); 1160 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1138 i < sfp->count; 1161 i < sfp->count;
1139 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep), 1162 i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep),
1140 oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) { 1163 oldsfep = xfs_dir3_sf_nextentry(dp->i_mount, oldsfp, oldsfep)) {
1141 sfep->namelen = oldsfep->namelen; 1164 sfep->namelen = oldsfep->namelen;
1142 sfep->offset = oldsfep->offset; 1165 sfep->offset = oldsfep->offset;
1143 memcpy(sfep->name, oldsfep->name, sfep->namelen); 1166 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1144 xfs_dir2_sfe_put_ino(sfp, sfep, 1167 xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep,
1145 xfs_dir2_sfe_get_ino(oldsfp, oldsfep)); 1168 xfs_dir3_sfe_get_ino(dp->i_mount, oldsfp, oldsfep));
1146 } 1169 }
1147 /* 1170 /*
1148 * Clean up the inode. 1171 * Clean up the inode.
@@ -1211,13 +1234,13 @@ xfs_dir2_sf_toino8(
1211 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), 1234 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1212 oldsfep = xfs_dir2_sf_firstentry(oldsfp); 1235 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1213 i < sfp->count; 1236 i < sfp->count;
1214 i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep), 1237 i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep),
1215 oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) { 1238 oldsfep = xfs_dir3_sf_nextentry(dp->i_mount, oldsfp, oldsfep)) {
1216 sfep->namelen = oldsfep->namelen; 1239 sfep->namelen = oldsfep->namelen;
1217 sfep->offset = oldsfep->offset; 1240 sfep->offset = oldsfep->offset;
1218 memcpy(sfep->name, oldsfep->name, sfep->namelen); 1241 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1219 xfs_dir2_sfe_put_ino(sfp, sfep, 1242 xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep,
1220 xfs_dir2_sfe_get_ino(oldsfp, oldsfep)); 1243 xfs_dir3_sfe_get_ino(dp->i_mount, oldsfp, oldsfep));
1221 } 1244 }
1222 /* 1245 /*
1223 * Clean up the inode. 1246 * Clean up the inode.
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 6d7e9e2d7651..2b8952d9199b 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -40,6 +40,9 @@
40#include "xfs_trace.h" 40#include "xfs_trace.h"
41#include "xfs_icache.h" 41#include "xfs_icache.h"
42#include "xfs_symlink.h" 42#include "xfs_symlink.h"
43#include "xfs_da_btree.h"
44#include "xfs_dir2_format.h"
45#include "xfs_dir2_priv.h"
43 46
44#include <linux/capability.h> 47#include <linux/capability.h>
45#include <linux/xattr.h> 48#include <linux/xattr.h>
@@ -88,10 +91,12 @@ xfs_init_security(
88static void 91static void
89xfs_dentry_to_name( 92xfs_dentry_to_name(
90 struct xfs_name *namep, 93 struct xfs_name *namep,
91 struct dentry *dentry) 94 struct dentry *dentry,
95 int mode)
92{ 96{
93 namep->name = dentry->d_name.name; 97 namep->name = dentry->d_name.name;
94 namep->len = dentry->d_name.len; 98 namep->len = dentry->d_name.len;
99 namep->type = xfs_mode_to_ftype[(mode & S_IFMT) >> S_SHIFT];
95} 100}
96 101
97STATIC void 102STATIC void
@@ -107,7 +112,7 @@ xfs_cleanup_inode(
107 * xfs_init_security we must back out. 112 * xfs_init_security we must back out.
108 * ENOSPC can hit here, among other things. 113 * ENOSPC can hit here, among other things.
109 */ 114 */
110 xfs_dentry_to_name(&teardown, dentry); 115 xfs_dentry_to_name(&teardown, dentry, 0);
111 116
112 xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); 117 xfs_remove(XFS_I(dir), &teardown, XFS_I(inode));
113 iput(inode); 118 iput(inode);
@@ -147,7 +152,7 @@ xfs_vn_mknod(
147 mode &= ~current_umask(); 152 mode &= ~current_umask();
148 } 153 }
149 154
150 xfs_dentry_to_name(&name, dentry); 155 xfs_dentry_to_name(&name, dentry, mode);
151 error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); 156 error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip);
152 if (unlikely(error)) 157 if (unlikely(error))
153 goto out_free_acl; 158 goto out_free_acl;
@@ -208,7 +213,7 @@ xfs_vn_lookup(
208 if (dentry->d_name.len >= MAXNAMELEN) 213 if (dentry->d_name.len >= MAXNAMELEN)
209 return ERR_PTR(-ENAMETOOLONG); 214 return ERR_PTR(-ENAMETOOLONG);
210 215
211 xfs_dentry_to_name(&name, dentry); 216 xfs_dentry_to_name(&name, dentry, 0);
212 error = xfs_lookup(XFS_I(dir), &name, &cip, NULL); 217 error = xfs_lookup(XFS_I(dir), &name, &cip, NULL);
213 if (unlikely(error)) { 218 if (unlikely(error)) {
214 if (unlikely(error != ENOENT)) 219 if (unlikely(error != ENOENT))
@@ -235,7 +240,7 @@ xfs_vn_ci_lookup(
235 if (dentry->d_name.len >= MAXNAMELEN) 240 if (dentry->d_name.len >= MAXNAMELEN)
236 return ERR_PTR(-ENAMETOOLONG); 241 return ERR_PTR(-ENAMETOOLONG);
237 242
238 xfs_dentry_to_name(&xname, dentry); 243 xfs_dentry_to_name(&xname, dentry, 0);
239 error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name); 244 error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name);
240 if (unlikely(error)) { 245 if (unlikely(error)) {
241 if (unlikely(error != ENOENT)) 246 if (unlikely(error != ENOENT))
@@ -270,7 +275,7 @@ xfs_vn_link(
270 struct xfs_name name; 275 struct xfs_name name;
271 int error; 276 int error;
272 277
273 xfs_dentry_to_name(&name, dentry); 278 xfs_dentry_to_name(&name, dentry, inode->i_mode);
274 279
275 error = xfs_link(XFS_I(dir), XFS_I(inode), &name); 280 error = xfs_link(XFS_I(dir), XFS_I(inode), &name);
276 if (unlikely(error)) 281 if (unlikely(error))
@@ -289,7 +294,7 @@ xfs_vn_unlink(
289 struct xfs_name name; 294 struct xfs_name name;
290 int error; 295 int error;
291 296
292 xfs_dentry_to_name(&name, dentry); 297 xfs_dentry_to_name(&name, dentry, 0);
293 298
294 error = -xfs_remove(XFS_I(dir), &name, XFS_I(dentry->d_inode)); 299 error = -xfs_remove(XFS_I(dir), &name, XFS_I(dentry->d_inode));
295 if (error) 300 if (error)
@@ -319,7 +324,7 @@ xfs_vn_symlink(
319 324
320 mode = S_IFLNK | 325 mode = S_IFLNK |
321 (irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO); 326 (irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO);
322 xfs_dentry_to_name(&name, dentry); 327 xfs_dentry_to_name(&name, dentry, mode);
323 328
324 error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip); 329 error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip);
325 if (unlikely(error)) 330 if (unlikely(error))
@@ -351,12 +356,12 @@ xfs_vn_rename(
351 struct xfs_name oname; 356 struct xfs_name oname;
352 struct xfs_name nname; 357 struct xfs_name nname;
353 358
354 xfs_dentry_to_name(&oname, odentry); 359 xfs_dentry_to_name(&oname, odentry, 0);
355 xfs_dentry_to_name(&nname, ndentry); 360 xfs_dentry_to_name(&nname, ndentry, odentry->d_inode->i_mode);
356 361
357 return -xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode), 362 return -xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode),
358 XFS_I(ndir), &nname, new_inode ? 363 XFS_I(ndir), &nname, new_inode ?
359 XFS_I(new_inode) : NULL); 364 XFS_I(new_inode) : NULL);
360} 365}
361 366
362/* 367/*
diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h
index db7593f4bc7e..3c297a451622 100644
--- a/fs/xfs/xfs_sb.h
+++ b/fs/xfs/xfs_sb.h
@@ -555,12 +555,6 @@ static inline void xfs_sb_version_addprojid32bit(xfs_sb_t *sbp)
555 sbp->sb_bad_features2 |= XFS_SB_VERSION2_PROJID32BIT; 555 sbp->sb_bad_features2 |= XFS_SB_VERSION2_PROJID32BIT;
556} 556}
557 557
558static inline int xfs_sb_version_hascrc(xfs_sb_t *sbp)
559{
560 return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
561}
562
563
564/* 558/*
565 * Extended v5 superblock feature masks. These are to be used for new v5 559 * Extended v5 superblock feature masks. These are to be used for new v5
566 * superblock features only. 560 * superblock features only.
@@ -599,7 +593,9 @@ xfs_sb_has_ro_compat_feature(
599 return (sbp->sb_features_ro_compat & feature) != 0; 593 return (sbp->sb_features_ro_compat & feature) != 0;
600} 594}
601 595
596#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */
602#define XFS_SB_FEAT_INCOMPAT_ALL 0 597#define XFS_SB_FEAT_INCOMPAT_ALL 0
598
603#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL 599#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL
604static inline bool 600static inline bool
605xfs_sb_has_incompat_feature( 601xfs_sb_has_incompat_feature(
@@ -619,11 +615,25 @@ xfs_sb_has_incompat_log_feature(
619 return (sbp->sb_features_log_incompat & feature) != 0; 615 return (sbp->sb_features_log_incompat & feature) != 0;
620} 616}
621 617
618/*
619 * V5 superblock specific feature checks
620 */
621static inline int xfs_sb_version_hascrc(xfs_sb_t *sbp)
622{
623 return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
624}
625
622static inline int xfs_sb_version_has_pquotino(xfs_sb_t *sbp) 626static inline int xfs_sb_version_has_pquotino(xfs_sb_t *sbp)
623{ 627{
624 return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5; 628 return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
625} 629}
626 630
631static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp)
632{
633 return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
634 xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_FTYPE);
635}
636
627/* 637/*
628 * end of superblock version macros 638 * end of superblock version macros
629 */ 639 */
diff --git a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h
index ce44b182821f..82bbc34d54a3 100644
--- a/fs/xfs/xfs_types.h
+++ b/fs/xfs/xfs_types.h
@@ -140,6 +140,7 @@ typedef enum {
140struct xfs_name { 140struct xfs_name {
141 const unsigned char *name; 141 const unsigned char *name;
142 int len; 142 int len;
143 int type;
143}; 144};
144 145
145/* 146/*