@@ -824,17 +824,22 @@ static inline unsigned int xfs_dir2_dirblock_bytes(struct xfs_sb *sbp)
xfs_failaddr_t xfs_da3_blkinfo_verify(struct xfs_buf *bp,
struct xfs_da3_blkinfo *hdr3);
+/* We use sha512 for the parent pointer name hash. */
+#define XFS_PARENT_NAME_HASH_SIZE (64)
+
/*
* Parent pointer attribute format definition
*
- * EA name encodes the parent inode number, generation and the offset of
- * the dirent that points to the child inode. The EA value contains the
- * same name as the dirent in the parent directory.
+ * The EA name encodes the parent inode number, generation and a collision
+ * resistant hash computed from the dirent name. The hash is defined to be the
+ * sha512 of the child inode generation and the dirent name.
+ *
+ * The EA value contains the same name as the dirent in the parent directory.
*/
struct xfs_parent_name_rec {
__be64 p_ino;
__be32 p_gen;
- __be32 p_diroffset;
-};
+ __u8 p_namehash[XFS_PARENT_NAME_HASH_SIZE];
+} __attribute__((packed));
#endif /* __XFS_DA_FORMAT_H__ */
@@ -770,8 +770,8 @@ struct xfs_scrub_metadata {
struct xfs_parent_ptr {
__u64 xpp_ino; /* Inode */
__u32 xpp_gen; /* Inode generation */
- __u32 xpp_diroffset; /* Directory offset */
- __u64 xpp_rsvd; /* Reserved */
+ __u32 xpp_rsvd; /* Reserved */
+ __u64 xpp_rsvd2; /* Reserved */
__u8 xpp_name[XFS_PPTR_MAXNAMELEN]; /* File name */
};
@@ -26,6 +26,7 @@
#include "xfs_xattr.h"
#include "xfs_parent.h"
#include "xfs_trans_space.h"
+#include "xfs_sha512.h"
struct kmem_cache *xfs_parent_intent_cache;
@@ -54,7 +55,6 @@ xfs_parent_namecheck(
unsigned int attr_flags)
{
xfs_ino_t p_ino;
- xfs_dir2_dataptr_t p_diroffset;
if (reclen != sizeof(struct xfs_parent_name_rec))
return false;
@@ -67,10 +67,6 @@ xfs_parent_namecheck(
if (!xfs_verify_ino(mp, p_ino))
return false;
- p_diroffset = be32_to_cpu(rec->p_diroffset);
- if (p_diroffset > XFS_DIR2_MAX_DATAPTR)
- return false;
-
return true;
}
@@ -91,18 +87,17 @@ xfs_parent_valuecheck(
}
/* Initializes a xfs_parent_name_rec to be stored as an attribute name */
-static inline void
+static inline int
xfs_init_parent_name_rec(
struct xfs_parent_name_rec *rec,
- const struct xfs_inode *ip,
- uint32_t p_diroffset)
+ const struct xfs_inode *dp,
+ const struct xfs_name *name,
+ struct xfs_inode *ip)
{
- xfs_ino_t p_ino = ip->i_ino;
- uint32_t p_gen = VFS_IC(ip)->i_generation;
-
- rec->p_ino = cpu_to_be64(p_ino);
- rec->p_gen = cpu_to_be32(p_gen);
- rec->p_diroffset = cpu_to_be32(p_diroffset);
+ rec->p_ino = cpu_to_be64(dp->i_ino);
+ rec->p_gen = cpu_to_be32(VFS_IC(dp)->i_generation);
+ return xfs_parent_namehash(ip, name, rec->p_namehash,
+ sizeof(rec->p_namehash));
}
/*
@@ -118,7 +113,7 @@ xfs_parent_irec_from_disk(
{
irec->p_ino = be64_to_cpu(rec->p_ino);
irec->p_gen = be32_to_cpu(rec->p_gen);
- irec->p_diroffset = be32_to_cpu(rec->p_diroffset);
+ memcpy(irec->p_namehash, rec->p_namehash, sizeof(irec->p_namehash));
if (!value) {
irec->p_namelen = 0;
@@ -148,7 +143,7 @@ xfs_parent_irec_to_disk(
{
rec->p_ino = cpu_to_be64(irec->p_ino);
rec->p_gen = cpu_to_be32(irec->p_gen);
- rec->p_diroffset = cpu_to_be32(irec->p_diroffset);
+ memcpy(rec->p_namehash, irec->p_namehash, sizeof(rec->p_namehash));
if (valuelen) {
ASSERT(*valuelen > 0);
@@ -208,12 +203,15 @@ xfs_parent_add(
struct xfs_parent_defer *parent,
struct xfs_inode *dp,
const struct xfs_name *parent_name,
- xfs_dir2_dataptr_t diroffset,
struct xfs_inode *child)
{
struct xfs_da_args *args = &parent->args;
+ int error;
+
+ error = xfs_init_parent_name_rec(&parent->rec, dp, parent_name, child);
+ if (error)
+ return error;
- xfs_init_parent_name_rec(&parent->rec, dp, diroffset);
args->hashval = xfs_da_hashname(args->name, args->namelen);
args->trans = tp;
@@ -230,14 +228,18 @@ xfs_parent_add(
int
xfs_parent_remove(
struct xfs_trans *tp,
- struct xfs_inode *dp,
struct xfs_parent_defer *parent,
- xfs_dir2_dataptr_t diroffset,
+ struct xfs_inode *dp,
+ const struct xfs_name *name,
struct xfs_inode *child)
{
struct xfs_da_args *args = &parent->args;
+ int error;
+
+ error = xfs_init_parent_name_rec(&parent->rec, dp, name, child);
+ if (error)
+ return error;
- xfs_init_parent_name_rec(&parent->rec, dp, diroffset);
args->trans = tp;
args->dp = child;
args->hashval = xfs_da_hashname(args->name, args->namelen);
@@ -250,16 +252,23 @@ xfs_parent_replace(
struct xfs_trans *tp,
struct xfs_parent_defer *new_parent,
struct xfs_inode *old_dp,
- xfs_dir2_dataptr_t old_diroffset,
- const struct xfs_name *parent_name,
+ const struct xfs_name *old_name,
struct xfs_inode *new_dp,
- xfs_dir2_dataptr_t new_diroffset,
+ const struct xfs_name *new_name,
struct xfs_inode *child)
{
struct xfs_da_args *args = &new_parent->args;
+ int error;
+
+ error = xfs_init_parent_name_rec(&new_parent->old_rec, old_dp,
+ old_name, child);
+ if (error)
+ return error;
+ error = xfs_init_parent_name_rec(&new_parent->rec, new_dp, new_name,
+ child);
+ if (error)
+ return error;
- xfs_init_parent_name_rec(&new_parent->old_rec, old_dp, old_diroffset);
- xfs_init_parent_name_rec(&new_parent->rec, new_dp, new_diroffset);
new_parent->args.name = (const uint8_t *)&new_parent->old_rec;
new_parent->args.namelen = sizeof(struct xfs_parent_name_rec);
new_parent->args.new_name = (const uint8_t *)&new_parent->rec;
@@ -267,9 +276,8 @@ xfs_parent_replace(
args->trans = tp;
args->dp = child;
- ASSERT(parent_name != NULL);
- new_parent->args.value = (void *)parent_name->name;
- new_parent->args.valuelen = parent_name->len;
+ new_parent->args.value = (void *)new_name->name;
+ new_parent->args.valuelen = new_name->len;
args->hashval = xfs_da_hashname(args->name, args->namelen);
return xfs_attr_defer_replace(args);
@@ -388,3 +396,62 @@ xfs_parent_unset(
return xfs_attr_set(&scr->args);
}
+
+/*
+ * Compute the parent pointer namehash for the given child file and dirent
+ * name.
+ */
+int
+xfs_parent_namehash(
+ struct xfs_inode *ip,
+ const struct xfs_name *name,
+ void *namehash,
+ unsigned int namehash_len)
+{
+ SHA512_DESC_ON_STACK(ip->i_mount, shash);
+ __be32 gen = cpu_to_be32(VFS_I(ip)->i_generation);
+ int error;
+
+ ASSERT(SHA512_DIGEST_SIZE ==
+ crypto_shash_digestsize(ip->i_mount->m_sha512));
+
+ if (namehash_len != SHA512_DIGEST_SIZE) {
+ ASSERT(0);
+ return -EINVAL;
+ }
+
+ error = sha512_init(&shash);
+ if (error)
+ goto out;
+
+ error = sha512_process(&shash, (const u8 *)&gen, sizeof(gen));
+ if (error)
+ goto out;
+
+ error = sha512_process(&shash, name->name, name->len);
+ if (error)
+ goto out;
+
+ error = sha512_done(&shash, namehash);
+ if (error)
+ goto out;
+
+out:
+ sha512_erase(&shash);
+ return error;
+}
+
+/* Recalculate the name hash of this parent pointer. */
+int
+xfs_parent_irec_hash(
+ struct xfs_inode *ip,
+ struct xfs_parent_name_irec *pptr)
+{
+ struct xfs_name xname = {
+ .name = pptr->p_name,
+ .len = pptr->p_namelen,
+ };
+
+ return xfs_parent_namehash(ip, &xname, &pptr->p_namehash,
+ sizeof(pptr->p_namehash));
+}
@@ -23,7 +23,7 @@ struct xfs_parent_name_irec {
/* Key fields for looking up a particular parent pointer. */
xfs_ino_t p_ino;
uint32_t p_gen;
- xfs_dir2_dataptr_t p_diroffset;
+ uint8_t p_namehash[XFS_PARENT_NAME_HASH_SIZE];
/* Attributes of a parent pointer. */
uint8_t p_namelen;
@@ -79,15 +79,14 @@ xfs_parent_start_locked(
int xfs_parent_add(struct xfs_trans *tp, struct xfs_parent_defer *parent,
struct xfs_inode *dp, const struct xfs_name *parent_name,
- xfs_dir2_dataptr_t diroffset, struct xfs_inode *child);
+ struct xfs_inode *child);
int xfs_parent_replace(struct xfs_trans *tp,
struct xfs_parent_defer *new_parent, struct xfs_inode *old_dp,
- xfs_dir2_dataptr_t old_diroffset,
- const struct xfs_name *parent_name, struct xfs_inode *new_ip,
- xfs_dir2_dataptr_t new_diroffset, struct xfs_inode *child);
-int xfs_parent_remove(struct xfs_trans *tp, struct xfs_inode *dp,
- struct xfs_parent_defer *parent, xfs_dir2_dataptr_t diroffset,
- struct xfs_inode *child);
+ const struct xfs_name *old_name, struct xfs_inode *new_ip,
+ const struct xfs_name *new_name, struct xfs_inode *child);
+int xfs_parent_remove(struct xfs_trans *tp,
+ struct xfs_parent_defer *parent, struct xfs_inode *dp,
+ const struct xfs_name *name, struct xfs_inode *child);
void __xfs_parent_cancel(struct xfs_mount *mp, struct xfs_parent_defer *parent);
@@ -100,6 +99,12 @@ xfs_parent_finish(
__xfs_parent_cancel(mp, p);
}
+int xfs_parent_namehash(struct xfs_inode *ip, const struct xfs_name *name,
+ void *namehash, unsigned int namehash_len);
+
+int xfs_parent_irec_hash(struct xfs_inode *ip,
+ struct xfs_parent_name_irec *pptr);
+
unsigned int xfs_pptr_calc_space_res(struct xfs_mount *mp,
unsigned int namelen);
@@ -139,16 +139,20 @@ xchk_dir_lock_child(
STATIC int
xchk_dir_parent_pointer(
struct xchk_dir *sd,
- xfs_dir2_dataptr_t dapos,
const struct xfs_name *name,
struct xfs_inode *ip)
{
struct xfs_scrub *sc = sd->sc;
int pptr_namelen;
+ int error;
sd->pptr.p_ino = sc->ip->i_ino;
sd->pptr.p_gen = VFS_I(sc->ip)->i_generation;
- sd->pptr.p_diroffset = dapos;
+
+ error = xfs_parent_namehash(ip, name, &sd->pptr.p_namehash,
+ sizeof(sd->pptr.p_namehash));
+ if (error)
+ return error;
pptr_namelen = xfs_parent_lookup(sc->tp, ip, &sd->pptr, sd->namebuf,
MAXNAMELEN, &sd->pptr_scratch);
@@ -216,7 +220,7 @@ xchk_dir_check_pptr_fast(
return 0;
}
- error = xchk_dir_parent_pointer(sd, dapos, name, ip);
+ error = xchk_dir_parent_pointer(sd, name, ip);
xfs_iunlock(ip, lockmode);
return error;
}
@@ -1041,7 +1045,7 @@ xchk_dir_slow_dirent(
goto out_unlock;
check_pptr:
- error = xchk_dir_parent_pointer(sd, dirent->diroffset, &xname, ip);
+ error = xchk_dir_parent_pointer(sd, &xname, ip);
out_unlock:
xfs_iunlock(ip, lockmode);
out_rele:
@@ -93,9 +93,6 @@ struct xrep_dirent {
/* Child inode number. */
xfs_ino_t ino;
- /* Directory offset that we want. We're not going to get it. */
- xfs_dir2_dataptr_t diroffset;
-
/* Length of the dirent name. */
uint8_t namelen;
@@ -261,8 +258,7 @@ xrep_dir_createname(
struct xrep_dir *rd,
const struct xfs_name *name,
xfs_ino_t inum,
- xfs_extlen_t total,
- xfs_dir2_dataptr_t diroffset)
+ xfs_extlen_t total)
{
struct xfs_scrub *sc = rd->sc;
struct xfs_inode *dp = rd->args.dp;
@@ -275,7 +271,7 @@ xrep_dir_createname(
if (error)
return error;
- trace_xrep_dir_createname(dp, name, inum, diroffset);
+ trace_xrep_dir_createname(dp, name, inum);
/* reset cmpresult as if we haven't done a lookup */
rd->args.cmpresult = XFS_CMP_DIFFERENT;
@@ -307,8 +303,7 @@ STATIC int
xrep_dir_removename(
struct xrep_dir *rd,
const struct xfs_name *name,
- xfs_extlen_t total,
- xfs_dir2_dataptr_t diroffset)
+ xfs_extlen_t total)
{
struct xfs_inode *dp = rd->args.dp;
bool is_block, is_leaf;
@@ -321,7 +316,7 @@ xrep_dir_removename(
rd->args.op_flags = 0;
rd->args.total = total;
- trace_xrep_dir_removename(dp, name, rd->args.inumber, diroffset);
+ trace_xrep_dir_removename(dp, name, rd->args.inumber);
if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)
return xfs_dir2_sf_removename(&rd->args);
@@ -385,8 +380,7 @@ xrep_dir_replay_update(
goto out_cancel;
}
- error = xrep_dir_removename(rd, &xname, resblks,
- dirent->diroffset);
+ error = xrep_dir_removename(rd, &xname, resblks);
} else {
/* Add this dirent. The lookup must not succeed. */
if (error == 0)
@@ -394,8 +388,7 @@ xrep_dir_replay_update(
if (error != -ENOENT)
goto out_cancel;
- error = xrep_dir_createname(rd, &xname, dirent->ino, resblks,
- dirent->diroffset);
+ error = xrep_dir_createname(rd, &xname, dirent->ino, resblks);
}
if (error)
goto out_cancel;
@@ -465,19 +458,17 @@ STATIC int
xrep_dir_add_dirent(
struct xrep_dir *rd,
const struct xfs_name *name,
- xfs_ino_t ino,
- xfs_dir2_dataptr_t diroffset)
+ xfs_ino_t ino)
{
struct xrep_dirent dirent = {
.action = XREP_DIRENT_ADD,
.ino = ino,
.namelen = name->len,
.ftype = name->type,
- .diroffset = diroffset,
};
int error;
- trace_xrep_dir_add_dirent(rd->sc->tempip, name, ino, diroffset);
+ trace_xrep_dir_add_dirent(rd->sc->tempip, name, ino);
error = xfblob_store(rd->dir_names, &dirent.name_cookie, name->name,
name->len);
@@ -495,19 +486,17 @@ STATIC int
xrep_dir_remove_dirent(
struct xrep_dir *rd,
const struct xfs_name *name,
- xfs_ino_t ino,
- xfs_dir2_dataptr_t diroffset)
+ xfs_ino_t ino)
{
struct xrep_dirent dirent = {
.action = XREP_DIRENT_REMOVE,
.ino = ino,
.namelen = name->len,
.ftype = name->type,
- .diroffset = diroffset,
};
int error;
- trace_xrep_dir_remove_dirent(rd->sc->tempip, name, ino, diroffset);
+ trace_xrep_dir_remove_dirent(rd->sc->tempip, name, ino);
error = xfblob_store(rd->dir_names, &dirent.name_cookie, name->name,
name->len);
@@ -567,8 +556,7 @@ xrep_dir_scan_parent_pointer(
xname.type = xfs_mode_to_ftype(VFS_I(ip)->i_mode);
mutex_lock(&rd->lock);
- error = xrep_dir_add_dirent(rd, &xname, ip->i_ino,
- rd->pptr.p_diroffset);
+ error = xrep_dir_add_dirent(rd, &xname, ip->i_ino);
mutex_unlock(&rd->lock);
return error;
}
@@ -605,7 +593,7 @@ xrep_dir_scan_dirent(
xrep_dir_samename(name, &xfs_name_dot))
return 0;
- trace_xrep_dir_replacename(sc->tempip, &xfs_name_dotdot, dp->i_ino, 0);
+ trace_xrep_dir_replacename(sc->tempip, &xfs_name_dotdot, dp->i_ino);
mutex_lock(&rd->lock);
rd->parent_ino = dp->i_ino;
@@ -773,7 +761,6 @@ xrep_dir_dump_tempdir(
struct xrep_dir *rd = priv;
xfs_ino_t child_ino;
bool child = true;
- xfs_dir2_dataptr_t child_diroffset = XFS_DIR2_NULL_DATAPTR;
int error;
/*
@@ -800,7 +787,7 @@ xrep_dir_dump_tempdir(
ino = sc->ip->i_ino;
}
- trace_xrep_dir_dumpname(sc->tempip, name, ino, dapos);
+ trace_xrep_dir_dumpname(sc->tempip, name, ino);
if (!child)
return 0;
@@ -812,17 +799,15 @@ xrep_dir_dump_tempdir(
* and reap it responsibly, but I didn't feel like porting all that.
*/
mutex_lock(&rd->lock);
- error = xrep_dir_remove_dirent(rd, name, ino, dapos);
+ error = xrep_dir_remove_dirent(rd, name, ino);
mutex_unlock(&rd->lock);
if (error)
return error;
/* Check that the dir being repaired has the same entry. */
- error = xchk_dir_lookup(sc, sc->ip, name, &child_ino,
- &child_diroffset);
+ error = xchk_dir_lookup(sc, sc->ip, name, &child_ino, NULL);
if (error == -ENOENT) {
- trace_xrep_dir_checkname(sc->ip, name, NULLFSINO,
- XFS_DIR2_NULL_DATAPTR);
+ trace_xrep_dir_checkname(sc->ip, name, NULLFSINO);
ASSERT(error != -ENOENT);
return -EFSCORRUPTED;
}
@@ -830,18 +815,11 @@ xrep_dir_dump_tempdir(
return error;
if (ino != child_ino) {
- trace_xrep_dir_checkname(sc->ip, name, child_ino,
- child_diroffset);
+ trace_xrep_dir_checkname(sc->ip, name, child_ino);
ASSERT(ino == child_ino);
return -EFSCORRUPTED;
}
- if (dapos != child_diroffset) {
- trace_xrep_dir_badposname(sc->ip, name, child_ino,
- child_diroffset);
- /* We have no way to update this, so we just leave it. */
- }
-
return 0;
}
@@ -860,7 +838,6 @@ xrep_dir_dump_baddir(
void *priv)
{
xfs_ino_t child_ino;
- xfs_dir2_dataptr_t child_diroffset = XFS_DIR2_NULL_DATAPTR;
int error;
/* Ignore the directory's dot and dotdot entries. */
@@ -868,14 +845,12 @@ xrep_dir_dump_baddir(
xrep_dir_samename(name, &xfs_name_dot))
return 0;
- trace_xrep_dir_dumpname(sc->ip, name, ino, dapos);
+ trace_xrep_dir_dumpname(sc->ip, name, ino);
/* Check that the tempdir has the same entry. */
- error = xchk_dir_lookup(sc, sc->tempip, name, &child_ino,
- &child_diroffset);
+ error = xchk_dir_lookup(sc, sc->tempip, name, &child_ino, NULL);
if (error == -ENOENT) {
- trace_xrep_dir_checkname(sc->tempip, name, NULLFSINO,
- XFS_DIR2_NULL_DATAPTR);
+ trace_xrep_dir_checkname(sc->tempip, name, NULLFSINO);
ASSERT(error != -ENOENT);
return -EFSCORRUPTED;
}
@@ -883,18 +858,11 @@ xrep_dir_dump_baddir(
return error;
if (ino != child_ino) {
- trace_xrep_dir_checkname(sc->tempip, name, child_ino,
- child_diroffset);
+ trace_xrep_dir_checkname(sc->tempip, name, child_ino);
ASSERT(ino == child_ino);
return -EFSCORRUPTED;
}
- if (dapos != child_diroffset) {
- trace_xrep_dir_badposname(sc->ip, name, child_ino,
- child_diroffset);
- /* We have no way to update this, so we just leave it. */
- }
-
return 0;
}
@@ -1011,11 +979,10 @@ xrep_dir_live_update(
xchk_iscan_want_live_update(&rd->iscan, p->ip->i_ino)) {
mutex_lock(&rd->lock);
if (p->delta > 0)
- error = xrep_dir_add_dirent(rd, p->name, p->ip->i_ino,
- p->diroffset);
+ error = xrep_dir_add_dirent(rd, p->name, p->ip->i_ino);
else
error = xrep_dir_remove_dirent(rd, p->name,
- p->ip->i_ino, p->diroffset);
+ p->ip->i_ino);
mutex_unlock(&rd->lock);
if (error)
goto out_abort;
@@ -1030,12 +997,12 @@ xrep_dir_live_update(
mutex_lock(&rd->lock);
if (p->delta > 0) {
trace_xrep_dir_add_dirent(sc->tempip, &xfs_name_dotdot,
- p->dp->i_ino, 0);
+ p->dp->i_ino);
rd->parent_ino = p->dp->i_ino;
} else {
trace_xrep_dir_remove_dirent(sc->tempip,
- &xfs_name_dotdot, NULLFSINO, 0);
+ &xfs_name_dotdot, NULLFSINO);
rd->parent_ino = NULLFSINO;
}
@@ -323,7 +323,6 @@ struct xchk_pptr {
/* Parent pointer attr key. */
xfs_ino_t p_ino;
uint32_t p_gen;
- xfs_dir2_dataptr_t p_diroffset;
/* Length of the pptr name. */
uint8_t namelen;
@@ -350,6 +349,9 @@ struct xchk_pptrs {
/* xattr key and da args for parent pointer revalidation. */
struct xfs_parent_scratch pptr_scratch;
+ /* Name hashes */
+ uint8_t child_namehash[XFS_PARENT_NAME_HASH_SIZE];
+
/* Name buffer for revalidation. */
uint8_t namebuf[MAXNAMELEN];
};
@@ -426,14 +428,13 @@ xchk_parent_dirent(
};
struct xfs_scrub *sc = pp->sc;
xfs_ino_t child_ino;
- xfs_dir2_dataptr_t child_diroffset;
int error;
/*
* Use the name attached to this parent pointer to look up the
* directory entry in the alleged parent.
*/
- error = xchk_dir_lookup(sc, dp, &xname, &child_ino, &child_diroffset);
+ error = xchk_dir_lookup(sc, dp, &xname, &child_ino, NULL);
if (error == -ENOENT) {
xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
return 0;
@@ -447,15 +448,6 @@ xchk_parent_dirent(
return 0;
}
- /* Does the directory offset match? */
- if (pp->pptr.p_diroffset != child_diroffset) {
- trace_xchk_parent_bad_dapos(sc->ip, pp->pptr.p_diroffset,
- dp->i_ino, child_diroffset, xname.name,
- xname.len);
- xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
- return 0;
- }
-
/*
* If we're scanning a directory, we should only ever encounter a
* single parent pointer, and it should match the dotdot entry. We set
@@ -534,6 +526,7 @@ xchk_parent_scan_attr(
unsigned int valuelen,
void *priv)
{
+ struct xfs_name xname = { };
struct xchk_pptrs *pp = priv;
struct xfs_inode *dp = NULL;
const struct xfs_parent_name_rec *rec = (const void *)name;
@@ -561,6 +554,26 @@ xchk_parent_scan_attr(
xfs_parent_irec_from_disk(&pp->pptr, rec, value, valuelen);
+ xname.name = pp->pptr.p_name;
+ xname.len = pp->pptr.p_namelen;
+
+ /*
+ * Does the namehash in the parent pointer match the actual name?
+ * If not, there's no point in checking further.
+ */
+ error = xfs_parent_namehash(sc->ip, &xname, pp->child_namehash,
+ sizeof(pp->child_namehash));
+ if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error))
+ return error;
+
+ if (memcmp(pp->pptr.p_namehash, pp->child_namehash,
+ sizeof(pp->pptr.p_namehash))) {
+ trace_xchk_parent_bad_namehash(sc->ip, pp->pptr.p_ino,
+ xname.name, xname.len);
+ xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
+ return 0;
+ }
+
error = xchk_parent_iget(pp, &dp);
if (error)
return error;
@@ -573,7 +586,6 @@ xchk_parent_scan_attr(
struct xchk_pptr save_pp = {
.p_ino = pp->pptr.p_ino,
.p_gen = pp->pptr.p_gen,
- .p_diroffset = pp->pptr.p_diroffset,
.namelen = pp->pptr.p_namelen,
};
@@ -655,7 +667,6 @@ xchk_parent_slow_pptr(
/* Restore the saved parent pointer into the irec. */
pp->pptr.p_ino = pptr->p_ino;
pp->pptr.p_gen = pptr->p_gen;
- pp->pptr.p_diroffset = pptr->p_diroffset;
error = xfblob_load(pp->pptr_names, pptr->name_cookie, pp->pptr.p_name,
pptr->namelen);
@@ -664,6 +675,10 @@ xchk_parent_slow_pptr(
pp->pptr.p_name[MAXNAMELEN - 1] = 0;
pp->pptr.p_namelen = pptr->namelen;
+ error = xfs_parent_irec_hash(sc->ip, &pp->pptr);
+ if (error)
+ return error;
+
/* Check that the deferred parent pointer still exists. */
if (pp->need_revalidate) {
error = xchk_parent_revalidate_pptr(pp);
@@ -95,7 +95,6 @@ struct xrep_pptr {
/* Parent pointer attr key. */
xfs_ino_t p_ino;
uint32_t p_gen;
- xfs_dir2_dataptr_t p_diroffset;
/* Length of the pptr name. */
uint8_t namelen;
@@ -183,12 +182,16 @@ xrep_pptr_replay_update(
const struct xrep_pptr *pptr)
{
struct xfs_scrub *sc = rp->sc;
+ int error;
rp->pptr.p_ino = pptr->p_ino;
rp->pptr.p_gen = pptr->p_gen;
- rp->pptr.p_diroffset = pptr->p_diroffset;
rp->pptr.p_namelen = pptr->namelen;
+ error = xfs_parent_irec_hash(sc->ip, &rp->pptr);
+ if (error)
+ return error;
+
if (pptr->action == XREP_PPTR_ADD) {
/* Create parent pointer. */
trace_xrep_pptr_createname(sc->tempip, &rp->pptr);
@@ -261,19 +264,17 @@ STATIC int
xrep_pptr_add_pointer(
struct xrep_pptrs *rp,
const struct xfs_name *name,
- const struct xfs_inode *dp,
- xfs_dir2_dataptr_t diroffset)
+ const struct xfs_inode *dp)
{
struct xrep_pptr pptr = {
.action = XREP_PPTR_ADD,
.namelen = name->len,
.p_ino = dp->i_ino,
.p_gen = VFS_IC(dp)->i_generation,
- .p_diroffset = diroffset,
};
int error;
- trace_xrep_pptr_add_pointer(rp->sc->tempip, dp, diroffset, name);
+ trace_xrep_pptr_add_pointer(rp->sc->tempip, dp, name);
error = xfblob_store(rp->pptr_names, &pptr.name_cookie, name->name,
name->len);
@@ -291,19 +292,17 @@ STATIC int
xrep_pptr_remove_pointer(
struct xrep_pptrs *rp,
const struct xfs_name *name,
- const struct xfs_inode *dp,
- xfs_dir2_dataptr_t diroffset)
+ const struct xfs_inode *dp)
{
struct xrep_pptr pptr = {
.action = XREP_PPTR_REMOVE,
.namelen = name->len,
.p_ino = dp->i_ino,
.p_gen = VFS_IC(dp)->i_generation,
- .p_diroffset = diroffset,
};
int error;
- trace_xrep_pptr_remove_pointer(rp->sc->tempip, dp, diroffset, name);
+ trace_xrep_pptr_remove_pointer(rp->sc->tempip, dp, name);
error = xfblob_store(rp->pptr_names, &pptr.name_cookie, name->name,
name->len);
@@ -352,7 +351,7 @@ xrep_pptr_scan_dirent(
* addition to the temporary file.
*/
mutex_lock(&rp->lock);
- error = xrep_pptr_add_pointer(rp, name, dp, dapos);
+ error = xrep_pptr_add_pointer(rp, name, dp);
mutex_unlock(&rp->lock);
return error;
}
@@ -646,11 +645,9 @@ xrep_pptr_live_update(
xchk_iscan_want_live_update(&rp->iscan, p->dp->i_ino)) {
mutex_lock(&rp->lock);
if (p->delta > 0)
- error = xrep_pptr_add_pointer(rp, p->name, p->dp,
- p->diroffset);
+ error = xrep_pptr_add_pointer(rp, p->name, p->dp);
else
- error = xrep_pptr_remove_pointer(rp, p->name, p->dp,
- p->diroffset);
+ error = xrep_pptr_remove_pointer(rp, p->name, p->dp);
mutex_unlock(&rp->lock);
if (error)
goto out_abort;
@@ -897,35 +897,28 @@ TRACE_EVENT(xchk_nlinks_live_update,
__get_str(name))
);
-TRACE_EVENT(xchk_parent_bad_dapos,
- TP_PROTO(struct xfs_inode *ip, unsigned int p_diroffset,
- xfs_ino_t parent_ino, unsigned int dapos,
- const char *name, unsigned int namelen),
- TP_ARGS(ip, p_diroffset, parent_ino, dapos, name, namelen),
+TRACE_EVENT(xchk_parent_bad_namehash,
+ TP_PROTO(struct xfs_inode *ip, xfs_ino_t parent_ino, const char *name,
+ unsigned int namelen),
+ TP_ARGS(ip, parent_ino, name, namelen),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, ino)
- __field(unsigned int, p_diroffset)
__field(xfs_ino_t, parent_ino)
- __field(unsigned int, dapos)
__field(unsigned int, namelen)
__dynamic_array(char, name, namelen)
),
TP_fast_assign(
__entry->dev = ip->i_mount->m_super->s_dev;
__entry->ino = ip->i_ino;
- __entry->p_diroffset = p_diroffset;
__entry->parent_ino = parent_ino;
- __entry->dapos = dapos;
__entry->namelen = namelen;
memcpy(__get_str(name), name, namelen);
),
- TP_printk("dev %d:%d ino 0x%llx p_diroff 0x%x parent_ino 0x%llx parent_diroff 0x%x name '%.*s'",
+ TP_printk("dev %d:%d ino 0x%llx parent_ino 0x%llx name '%.*s'",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
- __entry->p_diroffset,
__entry->parent_ino,
- __entry->dapos,
__entry->namelen,
__get_str(name))
);
@@ -1253,8 +1246,8 @@ TRACE_EVENT(xrep_tempfile_create,
DECLARE_EVENT_CLASS(xrep_dirent_class,
TP_PROTO(struct xfs_inode *dp, const struct xfs_name *name,
- xfs_ino_t ino, unsigned int diroffset),
- TP_ARGS(dp, name, ino, diroffset),
+ xfs_ino_t ino),
+ TP_ARGS(dp, name, ino),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, dir_ino)
@@ -1262,7 +1255,6 @@ DECLARE_EVENT_CLASS(xrep_dirent_class,
__dynamic_array(char, name, name->len)
__field(xfs_ino_t, ino)
__field(uint8_t, ftype)
- __field(unsigned int, diroffset)
),
TP_fast_assign(
__entry->dev = dp->i_mount->m_super->s_dev;
@@ -1271,12 +1263,10 @@ DECLARE_EVENT_CLASS(xrep_dirent_class,
memcpy(__get_str(name), name->name, name->len);
__entry->ino = ino;
__entry->ftype = name->type;
- __entry->diroffset = diroffset;
),
- TP_printk("dev %d:%d dir 0x%llx dapos 0x%x ftype %s name '%.*s' ino 0x%llx",
+ TP_printk("dev %d:%d dir 0x%llx ftype %s name '%.*s' ino 0x%llx",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->dir_ino,
- __entry->diroffset,
__print_symbolic(__entry->ftype, XFS_DIR3_FTYPE_STR),
__entry->namelen,
__get_str(name),
@@ -1285,8 +1275,8 @@ DECLARE_EVENT_CLASS(xrep_dirent_class,
#define DEFINE_XREP_DIRENT_CLASS(name) \
DEFINE_EVENT(xrep_dirent_class, name, \
TP_PROTO(struct xfs_inode *dp, const struct xfs_name *name, \
- xfs_ino_t ino, unsigned int diroffset), \
- TP_ARGS(dp, name, ino, diroffset))
+ xfs_ino_t ino), \
+ TP_ARGS(dp, name, ino))
DEFINE_XREP_DIRENT_CLASS(xrep_dir_add_dirent);
DEFINE_XREP_DIRENT_CLASS(xrep_dir_remove_dirent);
DEFINE_XREP_DIRENT_CLASS(xrep_dir_createname);
@@ -1329,7 +1319,6 @@ DECLARE_EVENT_CLASS(xrep_pptr_class,
__field(xfs_ino_t, ino)
__field(xfs_ino_t, parent_ino)
__field(unsigned int, parent_gen)
- __field(unsigned int, parent_diroffset)
__field(unsigned int, namelen)
__dynamic_array(char, name, pptr->p_namelen)
),
@@ -1338,16 +1327,14 @@ DECLARE_EVENT_CLASS(xrep_pptr_class,
__entry->ino = ip->i_ino;
__entry->parent_ino = pptr->p_ino;
__entry->parent_gen = pptr->p_gen;
- __entry->parent_diroffset = pptr->p_diroffset;
__entry->namelen = pptr->p_namelen;
memcpy(__get_str(name), pptr->p_name, pptr->p_namelen);
),
- TP_printk("dev %d:%d ino 0x%llx parent_ino 0x%llx parent_gen 0x%x parent_dapos 0x%x name '%.*s'",
+ TP_printk("dev %d:%d ino 0x%llx parent_ino 0x%llx parent_gen 0x%x name '%.*s'",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->parent_ino,
__entry->parent_gen,
- __entry->parent_diroffset,
__entry->namelen,
__get_str(name))
)
@@ -1362,14 +1349,13 @@ DEFINE_XREP_PPTR_CLASS(xrep_pptr_checkname);
DECLARE_EVENT_CLASS(xrep_pptr_scan_class,
TP_PROTO(struct xfs_inode *ip, const struct xfs_inode *dp,
- unsigned int diroffset, const struct xfs_name *name),
- TP_ARGS(ip, dp, diroffset, name),
+ const struct xfs_name *name),
+ TP_ARGS(ip, dp, name),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, ino)
__field(xfs_ino_t, parent_ino)
__field(unsigned int, parent_gen)
- __field(unsigned int, parent_diroffset)
__field(unsigned int, namelen)
__dynamic_array(char, name, name->len)
),
@@ -1378,24 +1364,22 @@ DECLARE_EVENT_CLASS(xrep_pptr_scan_class,
__entry->ino = ip->i_ino;
__entry->parent_ino = dp->i_ino;
__entry->parent_gen = VFS_IC(dp)->i_generation;
- __entry->parent_diroffset = diroffset;
__entry->namelen = name->len;
memcpy(__get_str(name), name->name, name->len);
),
- TP_printk("dev %d:%d ino 0x%llx parent_ino 0x%llx parent_gen 0x%x parent_dapos 0x%x name '%.*s'",
+ TP_printk("dev %d:%d ino 0x%llx parent_ino 0x%llx parent_gen 0x%x name '%.*s'",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->parent_ino,
__entry->parent_gen,
- __entry->parent_diroffset,
__entry->namelen,
__get_str(name))
)
#define DEFINE_XREP_PPTR_SCAN_CLASS(name) \
DEFINE_EVENT(xrep_pptr_scan_class, name, \
TP_PROTO(struct xfs_inode *ip, const struct xfs_inode *dp, \
- unsigned int diroffset, const struct xfs_name *name), \
- TP_ARGS(ip, dp, diroffset, name))
+ const struct xfs_name *name), \
+ TP_ARGS(ip, dp, name))
DEFINE_XREP_PPTR_SCAN_CLASS(xrep_pptr_add_pointer);
DEFINE_XREP_PPTR_SCAN_CLASS(xrep_pptr_remove_pointer);
@@ -1202,8 +1202,7 @@ xfs_create(
* the parent information now.
*/
if (parent) {
- error = xfs_parent_add(tp, parent, dp, name, diroffset,
- ip);
+ error = xfs_parent_add(tp, parent, dp, name, ip);
if (error)
goto out_trans_cancel;
}
@@ -1477,8 +1476,7 @@ xfs_link(
* the parent to the inode.
*/
if (parent) {
- error = xfs_parent_add(tp, parent, tdp, target_name,
- diroffset, sip);
+ error = xfs_parent_add(tp, parent, tdp, target_name, sip);
if (error)
goto error_return;
}
@@ -2750,7 +2748,7 @@ xfs_remove(
}
if (parent) {
- error = xfs_parent_remove(tp, dp, parent, dir_offset, ip);
+ error = xfs_parent_remove(tp, parent, dp, name, ip);
if (error)
goto out_trans_cancel;
}
@@ -3061,13 +3059,13 @@ xfs_cross_rename(
}
if (xfs_has_parent(mp)) {
- error = xfs_parent_replace(tp, ip1_pptr, dp1,
- old_diroffset, name2, dp2, new_diroffset, ip1);
+ error = xfs_parent_replace(tp, ip1_pptr, dp1, name1, dp2,
+ name2, ip1);
if (error)
goto out_trans_abort;
- error = xfs_parent_replace(tp, ip2_pptr, dp2,
- new_diroffset, name1, dp1, old_diroffset, ip2);
+ error = xfs_parent_replace(tp, ip2_pptr, dp2, name2, dp1,
+ name1, ip2);
if (error)
goto out_trans_abort;
}
@@ -3540,25 +3538,21 @@ xfs_rename(
goto out_trans_cancel;
if (wip_pptr) {
- error = xfs_parent_add(tp, wip_pptr,
- src_dp, src_name,
- old_diroffset, wip);
+ error = xfs_parent_add(tp, wip_pptr, src_dp, src_name, wip);
if (error)
goto out_trans_cancel;
}
if (src_ip_pptr) {
- error = xfs_parent_replace(tp, src_ip_pptr, src_dp,
- old_diroffset, target_name, target_dp,
- new_diroffset, src_ip);
+ error = xfs_parent_replace(tp, src_ip_pptr, src_dp, src_name,
+ target_dp, target_name, src_ip);
if (error)
goto out_trans_cancel;
}
if (tgt_ip_pptr) {
- error = xfs_parent_remove(tp, target_dp,
- tgt_ip_pptr,
- new_diroffset, target_ip);
+ error = xfs_parent_remove(tp, tgt_ip_pptr, target_dp,
+ target_name, target_ip);
if (error)
goto out_trans_cancel;
}
@@ -6,6 +6,8 @@
#ifndef __XFS_ONDISK_H
#define __XFS_ONDISK_H
+#include <crypto/sha2.h>
+
#define XFS_CHECK_STRUCT_SIZE(structname, size) \
BUILD_BUG_ON_MSG(sizeof(structname) != (size), "XFS: sizeof(" \
#structname ") is wrong, expected " #size)
@@ -114,6 +116,8 @@ xfs_check_ondisk_structs(void)
XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, offset, 1);
XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, name, 3);
XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10);
+ XFS_CHECK_STRUCT_SIZE(struct xfs_parent_name_rec, 76);
+ BUILD_BUG_ON(XFS_PARENT_NAME_HASH_SIZE != SHA512_DIGEST_SIZE);
/* log structures */
XFS_CHECK_STRUCT_SIZE(struct xfs_buf_log_format, 88);
@@ -83,7 +83,7 @@ xfs_getparent_listent(
pptr = &ppi->pi_parents[ppi->pi_ptrs_used++];
pptr->xpp_ino = irec->p_ino;
pptr->xpp_gen = irec->p_gen;
- pptr->xpp_diroffset = irec->p_diroffset;
+ pptr->xpp_rsvd2 = 0;
pptr->xpp_rsvd = 0;
memcpy(pptr->xpp_name, irec->p_name, irec->p_namelen);
new file mode 100644
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2023 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#ifndef __XFS_SHA512_H__
+#define __XFS_SHA512_H__
+
+struct sha512_state {
+ union {
+ struct shash_desc desc;
+ char __desc[sizeof(struct shash_desc) + HASH_MAX_DESCSIZE];
+ };
+};
+
+#define SHA512_DESC_ON_STACK(mp, name) \
+ struct sha512_state name = { .desc.tfm = (mp)->m_sha512 }
+
+#define SHA512_DIGEST_SIZE 64
+
+static inline int sha512_init(struct sha512_state *md)
+{
+ return crypto_shash_init(&md->desc);
+}
+
+static inline int sha512_done(struct sha512_state *md, unsigned char *out)
+{
+ return crypto_shash_final(&md->desc, out);
+}
+
+static inline int sha512_process(struct sha512_state *md,
+ const unsigned char *in, unsigned long inlen)
+{
+ return crypto_shash_update(&md->desc, in, inlen);
+}
+
+static inline void sha512_erase(struct sha512_state *md)
+{
+ memset(md, 0, sizeof(*md));
+}
+
+#endif /* __XFS_SHA512_H__ */
@@ -348,8 +348,7 @@ xfs_symlink(
xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
if (parent) {
- error = xfs_parent_add(tp, parent, dp, link_name,
- diroffset, ip);
+ error = xfs_parent_add(tp, parent, dp, link_name, ip);
if (error)
goto out_trans_cancel;
}