Skip to content

Commit

Permalink
xfs: Add read-only support for dirent filetype field
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Dave Chinner authored and Ben Myers committed Aug 22, 2013
1 parent ed56f34 commit 0cb9776
Show file tree
Hide file tree
Showing 14 changed files with 362 additions and 123 deletions.
1 change: 1 addition & 0 deletions fs/xfs/xfs_da_btree.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ enum xfs_dacmp {
typedef struct xfs_da_args {
const __uint8_t *name; /* string (maybe not NULL terminated) */
int namelen; /* length of string (maybe no NULL) */
__uint8_t filetype; /* filetype of inode for directories */
__uint8_t *value; /* set of bytes (maybe contain NULLs) */
int valuelen; /* length of value */
int flags; /* argument flags (eg: ATTR_NOCREATE) */
Expand Down
5 changes: 4 additions & 1 deletion fs/xfs/xfs_dir2.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
#include "xfs_error.h"
#include "xfs_trace.h"

struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2};
struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };


/*
* ASCII case-insensitive (ie. A-Z) support for directories that was
Expand Down Expand Up @@ -386,6 +387,7 @@ xfs_dir_replace(
memset(&args, 0, sizeof(xfs_da_args_t));
args.name = name->name;
args.namelen = name->len;
args.filetype = name->type;
args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.inumber = inum;
args.dp = dp;
Expand Down Expand Up @@ -433,6 +435,7 @@ xfs_dir_canenter(
memset(&args, 0, sizeof(xfs_da_args_t));
args.name = name->name;
args.namelen = name->len;
args.filetype = name->type;
args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.dp = dp;
args.whichfork = XFS_DATA_FORK;
Expand Down
4 changes: 2 additions & 2 deletions fs/xfs/xfs_dir2.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ extern int xfs_dir2_sf_to_block(struct xfs_da_args *args);
extern xfs_ino_t xfs_dir2_sf_get_parent_ino(struct xfs_dir2_sf_hdr *sfp);
extern void xfs_dir2_sf_put_parent_ino(struct xfs_dir2_sf_hdr *sfp,
xfs_ino_t ino);
extern xfs_ino_t xfs_dir2_sfe_get_ino(struct xfs_dir2_sf_hdr *sfp,
struct xfs_dir2_sf_entry *sfep);
extern xfs_ino_t xfs_dir3_sfe_get_ino(struct xfs_mount *mp,
struct xfs_dir2_sf_hdr *sfp, struct xfs_dir2_sf_entry *sfep);
extern void xfs_dir2_sfe_put_ino( struct xfs_dir2_sf_hdr *,
struct xfs_dir2_sf_entry *sfep, xfs_ino_t ino);

Expand Down
16 changes: 8 additions & 8 deletions fs/xfs/xfs_dir2_block.c
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ xfs_dir2_block_addname(
if (error)
return error;

len = xfs_dir2_data_entsize(args->namelen);
len = xfs_dir3_data_entsize(mp, args->namelen);

/*
* Set up pointers to parts of the block.
Expand Down Expand Up @@ -549,7 +549,7 @@ xfs_dir2_block_addname(
dep->inumber = cpu_to_be64(args->inumber);
dep->namelen = args->namelen;
memcpy(dep->name, args->name, args->namelen);
tagp = xfs_dir2_data_entry_tag_p(dep);
tagp = xfs_dir3_data_entry_tag_p(mp, dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr);
/*
* Clean up the bestfree array and log the header, tail, and entry.
Expand Down Expand Up @@ -799,7 +799,7 @@ xfs_dir2_block_removename(
needlog = needscan = 0;
xfs_dir2_data_make_free(tp, bp,
(xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr),
xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan);
xfs_dir3_data_entsize(mp, dep->namelen), &needlog, &needscan);
/*
* Fix up the block tail.
*/
Expand Down Expand Up @@ -1159,7 +1159,7 @@ xfs_dir2_sf_to_block(
dep->inumber = cpu_to_be64(dp->i_ino);
dep->namelen = 1;
dep->name[0] = '.';
tagp = xfs_dir2_data_entry_tag_p(dep);
tagp = xfs_dir3_data_entry_tag_p(mp, dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr);
xfs_dir2_data_log_entry(tp, bp, dep);
blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot);
Expand All @@ -1172,7 +1172,7 @@ xfs_dir2_sf_to_block(
dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp));
dep->namelen = 2;
dep->name[0] = dep->name[1] = '.';
tagp = xfs_dir2_data_entry_tag_p(dep);
tagp = xfs_dir3_data_entry_tag_p(mp, dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr);
xfs_dir2_data_log_entry(tp, bp, dep);
blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
Expand Down Expand Up @@ -1217,10 +1217,10 @@ xfs_dir2_sf_to_block(
* Copy a real entry.
*/
dep = (xfs_dir2_data_entry_t *)((char *)hdr + newoffset);
dep->inumber = cpu_to_be64(xfs_dir2_sfe_get_ino(sfp, sfep));
dep->inumber = cpu_to_be64(xfs_dir3_sfe_get_ino(mp, sfp, sfep));
dep->namelen = sfep->namelen;
memcpy(dep->name, sfep->name, dep->namelen);
tagp = xfs_dir2_data_entry_tag_p(dep);
tagp = xfs_dir3_data_entry_tag_p(mp, dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr);
xfs_dir2_data_log_entry(tp, bp, dep);
name.name = sfep->name;
Expand All @@ -1233,7 +1233,7 @@ xfs_dir2_sf_to_block(
if (++i == sfp->count)
sfep = NULL;
else
sfep = xfs_dir2_sf_nextentry(sfp, sfep);
sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
}
/* Done with the temporary buffer */
kmem_free(sfp);
Expand Down
13 changes: 7 additions & 6 deletions fs/xfs/xfs_dir2_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ __xfs_dir3_data_check(
XFS_WANT_CORRUPTED_RETURN(
!xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)));
XFS_WANT_CORRUPTED_RETURN(
be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) ==
be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)) ==
(char *)dep - (char *)hdr);
count++;
lastfree = 0;
Expand All @@ -166,7 +166,7 @@ __xfs_dir3_data_check(
}
XFS_WANT_CORRUPTED_RETURN(i < be32_to_cpu(btp->count));
}
p += xfs_dir2_data_entsize(dep->namelen);
p += xfs_dir3_data_entsize(mp, dep->namelen);
}
/*
* Need to have seen all the entries and all the bestfree slots.
Expand Down Expand Up @@ -536,8 +536,8 @@ xfs_dir2_data_freescan(
else {
dep = (xfs_dir2_data_entry_t *)p;
ASSERT((char *)dep - (char *)hdr ==
be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)));
p += xfs_dir2_data_entsize(dep->namelen);
be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)));
p += xfs_dir3_data_entsize(mp, dep->namelen);
}
}
}
Expand Down Expand Up @@ -627,15 +627,16 @@ xfs_dir2_data_log_entry(
struct xfs_buf *bp,
xfs_dir2_data_entry_t *dep) /* data entry pointer */
{
xfs_dir2_data_hdr_t *hdr = bp->b_addr;
struct xfs_dir2_data_hdr *hdr = bp->b_addr;
struct xfs_mount *mp = tp->t_mountp;

ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));

xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr),
(uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) -
(uint)((char *)(xfs_dir3_data_entry_tag_p(mp, dep) + 1) -
(char *)hdr - 1));
}

Expand Down
Loading

0 comments on commit 0cb9776

Please sign in to comment.