aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_dir2_readdir.c
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/xfs_dir2_readdir.c
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/xfs_dir2_readdir.c')
-rw-r--r--fs/xfs/xfs_dir2_readdir.c69
1 files changed, 59 insertions, 10 deletions
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 /*