xfs: Add write support for dirent filetype field

Add support to propagate and add filetype values into the on-disk
directs. This involves passing the filetype into the xfs_da_args
structure along with the name and namelength for direct operations,
and encoding it into the dirent at the same time we write the inode
number into the dirent.

With write support, add the feature flag to the
XFS_SB_FEAT_INCOMPAT_ALL mask so we can now mount filesystems with
this feature set.

Performance of directory recursion is now much improved. Parallel
walk of ~50 million directory entries across hundreds of directories
improves significantly. Unpatched, no CRCs:

Walking via ls -R

real    3m19.886s
user    6m36.960s
sys     28m19.087s

THis is doing roughly 500 getdents() calls per second, and 250,000
inode lookups per second to determine the inode type at roughly
17,000 read IOPS. CPU usage is 90% kernel space.

With dtype support patched in and the fileset recreated with CRCs
enabled:

Walking via ls -R

real    0m31.316s
user    6m32.975s
sys     0m21.111s

This is doing roughly 3500 getdents() calls per second at 16,000
IOPS. There are no inode lookups at all. CPU usages is almost 100%
userspace.

This is a big win for recursive directory walks that only need to
find file names and file types.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
This commit is contained in:
Dave Chinner 2013-08-12 20:50:10 +10:00 committed by Ben Myers
parent 0cb97766f2
commit 1c55cece08
7 changed files with 47 additions and 9 deletions

View File

@ -209,6 +209,7 @@ xfs_dir_createname(
memset(&args, 0, sizeof(xfs_da_args_t)); memset(&args, 0, sizeof(xfs_da_args_t));
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.filetype = name->type;
args.hashval = dp->i_mount->m_dirnameops->hashname(name); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.inumber = inum; args.inumber = inum;
args.dp = dp; args.dp = dp;
@ -283,6 +284,7 @@ xfs_dir_lookup(
memset(&args, 0, sizeof(xfs_da_args_t)); memset(&args, 0, sizeof(xfs_da_args_t));
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.filetype = name->type;
args.hashval = dp->i_mount->m_dirnameops->hashname(name); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.dp = dp; args.dp = dp;
args.whichfork = XFS_DATA_FORK; args.whichfork = XFS_DATA_FORK;
@ -338,6 +340,7 @@ xfs_dir_removename(
memset(&args, 0, sizeof(xfs_da_args_t)); memset(&args, 0, sizeof(xfs_da_args_t));
args.name = name->name; args.name = name->name;
args.namelen = name->len; args.namelen = name->len;
args.filetype = name->type;
args.hashval = dp->i_mount->m_dirnameops->hashname(name); args.hashval = dp->i_mount->m_dirnameops->hashname(name);
args.inumber = ino; args.inumber = ino;
args.dp = dp; args.dp = dp;

View File

@ -549,6 +549,7 @@ xfs_dir2_block_addname(
dep->inumber = cpu_to_be64(args->inumber); dep->inumber = cpu_to_be64(args->inumber);
dep->namelen = args->namelen; dep->namelen = args->namelen;
memcpy(dep->name, args->name, args->namelen); memcpy(dep->name, args->name, args->namelen);
xfs_dir3_dirent_put_ftype(mp, dep, args->filetype);
tagp = xfs_dir3_data_entry_tag_p(mp, dep); tagp = xfs_dir3_data_entry_tag_p(mp, dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr); *tagp = cpu_to_be16((char *)dep - (char *)hdr);
/* /*
@ -641,6 +642,7 @@ xfs_dir2_block_lookup(
* Fill in inode number, CI name if appropriate, release the block. * Fill in inode number, CI name if appropriate, release the block.
*/ */
args->inumber = be64_to_cpu(dep->inumber); args->inumber = be64_to_cpu(dep->inumber);
args->filetype = xfs_dir3_dirent_get_ftype(mp, dep);
error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
xfs_trans_brelse(args->trans, bp); xfs_trans_brelse(args->trans, bp);
return XFS_ERROR(error); return XFS_ERROR(error);
@ -873,6 +875,7 @@ xfs_dir2_block_replace(
* Change the inode number to the new value. * Change the inode number to the new value.
*/ */
dep->inumber = cpu_to_be64(args->inumber); dep->inumber = cpu_to_be64(args->inumber);
xfs_dir3_dirent_put_ftype(mp, dep, args->filetype);
xfs_dir2_data_log_entry(args->trans, bp, dep); xfs_dir2_data_log_entry(args->trans, bp, dep);
xfs_dir3_data_check(dp, bp); xfs_dir3_data_check(dp, bp);
return 0; return 0;
@ -1159,6 +1162,7 @@ xfs_dir2_sf_to_block(
dep->inumber = cpu_to_be64(dp->i_ino); dep->inumber = cpu_to_be64(dp->i_ino);
dep->namelen = 1; dep->namelen = 1;
dep->name[0] = '.'; dep->name[0] = '.';
xfs_dir3_dirent_put_ftype(mp, dep, XFS_DIR3_FT_DIR);
tagp = xfs_dir3_data_entry_tag_p(mp, dep); tagp = xfs_dir3_data_entry_tag_p(mp, dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr); *tagp = cpu_to_be16((char *)dep - (char *)hdr);
xfs_dir2_data_log_entry(tp, bp, dep); xfs_dir2_data_log_entry(tp, bp, dep);
@ -1172,6 +1176,7 @@ xfs_dir2_sf_to_block(
dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp)); dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp));
dep->namelen = 2; dep->namelen = 2;
dep->name[0] = dep->name[1] = '.'; dep->name[0] = dep->name[1] = '.';
xfs_dir3_dirent_put_ftype(mp, dep, XFS_DIR3_FT_DIR);
tagp = xfs_dir3_data_entry_tag_p(mp, dep); tagp = xfs_dir3_data_entry_tag_p(mp, dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr); *tagp = cpu_to_be16((char *)dep - (char *)hdr);
xfs_dir2_data_log_entry(tp, bp, dep); xfs_dir2_data_log_entry(tp, bp, dep);
@ -1219,6 +1224,8 @@ xfs_dir2_sf_to_block(
dep = (xfs_dir2_data_entry_t *)((char *)hdr + newoffset); dep = (xfs_dir2_data_entry_t *)((char *)hdr + newoffset);
dep->inumber = cpu_to_be64(xfs_dir3_sfe_get_ino(mp, sfp, sfep)); dep->inumber = cpu_to_be64(xfs_dir3_sfe_get_ino(mp, sfp, sfep));
dep->namelen = sfep->namelen; dep->namelen = sfep->namelen;
xfs_dir3_dirent_put_ftype(mp, dep,
xfs_dir3_sfe_get_ftype(mp, sfp, sfep));
memcpy(dep->name, sfep->name, dep->namelen); memcpy(dep->name, sfep->name, dep->namelen);
tagp = xfs_dir3_data_entry_tag_p(mp, dep); tagp = xfs_dir3_data_entry_tag_p(mp, dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr); *tagp = cpu_to_be16((char *)dep - (char *)hdr);

View File

@ -149,6 +149,8 @@ __xfs_dir3_data_check(
XFS_WANT_CORRUPTED_RETURN( XFS_WANT_CORRUPTED_RETURN(
be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)) == be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)) ==
(char *)dep - (char *)hdr); (char *)dep - (char *)hdr);
XFS_WANT_CORRUPTED_RETURN(
xfs_dir3_dirent_get_ftype(mp, dep) < XFS_DIR3_FT_MAX);
count++; count++;
lastfree = 0; lastfree = 0;
if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||

View File

@ -897,6 +897,7 @@ xfs_dir2_leaf_addname(
dep->inumber = cpu_to_be64(args->inumber); dep->inumber = cpu_to_be64(args->inumber);
dep->namelen = args->namelen; dep->namelen = args->namelen;
memcpy(dep->name, args->name, dep->namelen); memcpy(dep->name, args->name, dep->namelen);
xfs_dir3_dirent_put_ftype(mp, dep, args->filetype);
tagp = xfs_dir3_data_entry_tag_p(mp, dep); tagp = xfs_dir3_data_entry_tag_p(mp, dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr); *tagp = cpu_to_be16((char *)dep - (char *)hdr);
/* /*
@ -1225,6 +1226,7 @@ xfs_dir2_leaf_lookup(
* Return the found inode number & CI name if appropriate * Return the found inode number & CI name if appropriate
*/ */
args->inumber = be64_to_cpu(dep->inumber); args->inumber = be64_to_cpu(dep->inumber);
args->filetype = xfs_dir3_dirent_get_ftype(dp->i_mount, dep);
error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
xfs_trans_brelse(tp, dbp); xfs_trans_brelse(tp, dbp);
xfs_trans_brelse(tp, lbp); xfs_trans_brelse(tp, lbp);
@ -1555,6 +1557,7 @@ xfs_dir2_leaf_replace(
* Put the new inode number in, log it. * Put the new inode number in, log it.
*/ */
dep->inumber = cpu_to_be64(args->inumber); dep->inumber = cpu_to_be64(args->inumber);
xfs_dir3_dirent_put_ftype(dp->i_mount, dep, args->filetype);
tp = args->trans; tp = args->trans;
xfs_dir2_data_log_entry(tp, dbp, dep); xfs_dir2_data_log_entry(tp, dbp, dep);
xfs_dir3_leaf_check(dp->i_mount, lbp); xfs_dir3_leaf_check(dp->i_mount, lbp);

View File

@ -816,6 +816,7 @@ xfs_dir2_leafn_lookup_for_entry(
xfs_trans_brelse(tp, state->extrablk.bp); xfs_trans_brelse(tp, state->extrablk.bp);
args->cmpresult = cmp; args->cmpresult = cmp;
args->inumber = be64_to_cpu(dep->inumber); args->inumber = be64_to_cpu(dep->inumber);
args->filetype = xfs_dir3_dirent_get_ftype(mp, dep);
*indexp = index; *indexp = index;
state->extravalid = 1; state->extravalid = 1;
state->extrablk.bp = curbp; state->extrablk.bp = curbp;
@ -2007,6 +2008,7 @@ xfs_dir2_node_addname_int(
dep->inumber = cpu_to_be64(args->inumber); dep->inumber = cpu_to_be64(args->inumber);
dep->namelen = args->namelen; dep->namelen = args->namelen;
memcpy(dep->name, args->name, dep->namelen); memcpy(dep->name, args->name, dep->namelen);
xfs_dir3_dirent_put_ftype(mp, dep, args->filetype);
tagp = xfs_dir3_data_entry_tag_p(mp, dep); tagp = xfs_dir3_data_entry_tag_p(mp, dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr); *tagp = cpu_to_be16((char *)dep - (char *)hdr);
xfs_dir2_data_log_entry(tp, dbp, dep); xfs_dir2_data_log_entry(tp, dbp, dep);
@ -2227,6 +2229,7 @@ xfs_dir2_node_replace(
* Fill in the new inode number and log the entry. * Fill in the new inode number and log the entry.
*/ */
dep->inumber = cpu_to_be64(inum); dep->inumber = cpu_to_be64(inum);
xfs_dir3_dirent_put_ftype(state->mp, dep, args->filetype);
xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep); xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep);
rval = 0; rval = 0;
} }

View File

@ -333,6 +333,8 @@ xfs_dir2_block_to_sf(
memcpy(sfep->name, dep->name, dep->namelen); memcpy(sfep->name, dep->name, dep->namelen);
xfs_dir3_sfe_put_ino(mp, sfp, sfep, xfs_dir3_sfe_put_ino(mp, sfp, sfep,
be64_to_cpu(dep->inumber)); be64_to_cpu(dep->inumber));
xfs_dir3_sfe_put_ftype(mp, sfp, sfep,
xfs_dir3_dirent_get_ftype(mp, dep));
sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep); sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
} }
@ -496,6 +498,8 @@ xfs_dir2_sf_addname_easy(
xfs_dir2_sf_put_offset(sfep, offset); xfs_dir2_sf_put_offset(sfep, offset);
memcpy(sfep->name, args->name, sfep->namelen); memcpy(sfep->name, args->name, sfep->namelen);
xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep, args->inumber); xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep, args->inumber);
xfs_dir3_sfe_put_ftype(dp->i_mount, sfp, sfep, args->filetype);
/* /*
* Update the header and inode. * Update the header and inode.
*/ */
@ -589,6 +593,7 @@ xfs_dir2_sf_addname_hard(
xfs_dir2_sf_put_offset(sfep, offset); xfs_dir2_sf_put_offset(sfep, offset);
memcpy(sfep->name, args->name, sfep->namelen); memcpy(sfep->name, args->name, sfep->namelen);
xfs_dir3_sfe_put_ino(mp, sfp, sfep, args->inumber); xfs_dir3_sfe_put_ino(mp, sfp, sfep, args->inumber);
xfs_dir3_sfe_put_ftype(mp, sfp, sfep, args->filetype);
sfp->count++; sfp->count++;
#if XFS_BIG_INUMS #if XFS_BIG_INUMS
if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange) if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
@ -825,6 +830,7 @@ xfs_dir2_sf_lookup(
if (args->namelen == 1 && args->name[0] == '.') { if (args->namelen == 1 && args->name[0] == '.') {
args->inumber = dp->i_ino; args->inumber = dp->i_ino;
args->cmpresult = XFS_CMP_EXACT; args->cmpresult = XFS_CMP_EXACT;
args->filetype = XFS_DIR3_FT_DIR;
return XFS_ERROR(EEXIST); return XFS_ERROR(EEXIST);
} }
/* /*
@ -834,6 +840,7 @@ xfs_dir2_sf_lookup(
args->name[0] == '.' && args->name[1] == '.') { args->name[0] == '.' && args->name[1] == '.') {
args->inumber = xfs_dir2_sf_get_parent_ino(sfp); args->inumber = xfs_dir2_sf_get_parent_ino(sfp);
args->cmpresult = XFS_CMP_EXACT; args->cmpresult = XFS_CMP_EXACT;
args->filetype = XFS_DIR3_FT_DIR;
return XFS_ERROR(EEXIST); return XFS_ERROR(EEXIST);
} }
/* /*
@ -853,6 +860,8 @@ xfs_dir2_sf_lookup(
args->cmpresult = cmp; args->cmpresult = cmp;
args->inumber = xfs_dir3_sfe_get_ino(dp->i_mount, args->inumber = xfs_dir3_sfe_get_ino(dp->i_mount,
sfp, sfep); sfp, sfep);
args->filetype = xfs_dir3_sfe_get_ftype(dp->i_mount,
sfp, sfep);
if (cmp == XFS_CMP_EXACT) if (cmp == XFS_CMP_EXACT)
return XFS_ERROR(EEXIST); return XFS_ERROR(EEXIST);
ci_sfep = sfep; ci_sfep = sfep;
@ -1052,6 +1061,8 @@ xfs_dir2_sf_replace(
#endif #endif
xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep, xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep,
args->inumber); args->inumber);
xfs_dir3_sfe_put_ftype(dp->i_mount, sfp, sfep,
args->filetype);
break; break;
} }
} }
@ -1118,10 +1129,12 @@ xfs_dir2_sf_toino4(
int oldsize; /* old inode size */ int oldsize; /* old inode size */
xfs_dir2_sf_entry_t *sfep; /* new sf entry */ xfs_dir2_sf_entry_t *sfep; /* new sf entry */
xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ xfs_dir2_sf_hdr_t *sfp; /* new sf directory */
struct xfs_mount *mp;
trace_xfs_dir2_sf_toino4(args); trace_xfs_dir2_sf_toino4(args);
dp = args->dp; dp = args->dp;
mp = dp->i_mount;
/* /*
* Copy the old directory to the buffer. * Copy the old directory to the buffer.
@ -1159,13 +1172,15 @@ xfs_dir2_sf_toino4(
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
oldsfep = xfs_dir2_sf_firstentry(oldsfp); oldsfep = xfs_dir2_sf_firstentry(oldsfp);
i < sfp->count; i < sfp->count;
i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep), i++, sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep),
oldsfep = xfs_dir3_sf_nextentry(dp->i_mount, oldsfp, oldsfep)) { oldsfep = xfs_dir3_sf_nextentry(mp, oldsfp, oldsfep)) {
sfep->namelen = oldsfep->namelen; sfep->namelen = oldsfep->namelen;
sfep->offset = oldsfep->offset; sfep->offset = oldsfep->offset;
memcpy(sfep->name, oldsfep->name, sfep->namelen); memcpy(sfep->name, oldsfep->name, sfep->namelen);
xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep, xfs_dir3_sfe_put_ino(mp, sfp, sfep,
xfs_dir3_sfe_get_ino(dp->i_mount, oldsfp, oldsfep)); xfs_dir3_sfe_get_ino(mp, oldsfp, oldsfep));
xfs_dir3_sfe_put_ftype(mp, sfp, sfep,
xfs_dir3_sfe_get_ftype(mp, oldsfp, oldsfep));
} }
/* /*
* Clean up the inode. * Clean up the inode.
@ -1193,10 +1208,12 @@ xfs_dir2_sf_toino8(
int oldsize; /* old inode size */ int oldsize; /* old inode size */
xfs_dir2_sf_entry_t *sfep; /* new sf entry */ xfs_dir2_sf_entry_t *sfep; /* new sf entry */
xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ xfs_dir2_sf_hdr_t *sfp; /* new sf directory */
struct xfs_mount *mp;
trace_xfs_dir2_sf_toino8(args); trace_xfs_dir2_sf_toino8(args);
dp = args->dp; dp = args->dp;
mp = dp->i_mount;
/* /*
* Copy the old directory to the buffer. * Copy the old directory to the buffer.
@ -1234,13 +1251,15 @@ xfs_dir2_sf_toino8(
for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
oldsfep = xfs_dir2_sf_firstentry(oldsfp); oldsfep = xfs_dir2_sf_firstentry(oldsfp);
i < sfp->count; i < sfp->count;
i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep), i++, sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep),
oldsfep = xfs_dir3_sf_nextentry(dp->i_mount, oldsfp, oldsfep)) { oldsfep = xfs_dir3_sf_nextentry(mp, oldsfp, oldsfep)) {
sfep->namelen = oldsfep->namelen; sfep->namelen = oldsfep->namelen;
sfep->offset = oldsfep->offset; sfep->offset = oldsfep->offset;
memcpy(sfep->name, oldsfep->name, sfep->namelen); memcpy(sfep->name, oldsfep->name, sfep->namelen);
xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep, xfs_dir3_sfe_put_ino(mp, sfp, sfep,
xfs_dir3_sfe_get_ino(dp->i_mount, oldsfp, oldsfep)); xfs_dir3_sfe_get_ino(mp, oldsfp, oldsfep));
xfs_dir3_sfe_put_ftype(mp, sfp, sfep,
xfs_dir3_sfe_get_ftype(mp, oldsfp, oldsfep));
} }
/* /*
* Clean up the inode. * Clean up the inode.

View File

@ -594,7 +594,8 @@ xfs_sb_has_ro_compat_feature(
} }
#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */ #define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */
#define XFS_SB_FEAT_INCOMPAT_ALL 0 #define XFS_SB_FEAT_INCOMPAT_ALL \
(XFS_SB_FEAT_INCOMPAT_FTYPE)
#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL #define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL
static inline bool static inline bool