/* * Parent pointer attribute handling. * * Because the attribute name is a filename component, it will never be longer * than 255 bytes and must not contain nulls or slashes. These are roughly the * same constraints that apply to attribute names. * * The attribute value must always be a struct xfs_parent_rec. This means the * attribute will never be in remote format because 12 bytes is nowhere near * xfs_attr_leaf_entsize_local_max() (~75% of block size). * * Creating a new parent attribute will always create a new attribute - there * should never, ever be an existing attribute in the tree for a new inode. * ENOSPC behavior is problematic - creating the inode without the parent * pointer is effectively a corruption, so we allow parent attribute creation * to dip into the reserve block pool to avoid unexpected ENOSPC errors from * occurring.
*/
/* Return true if parent pointer attr name is valid. */ bool
xfs_parent_namecheck( unsignedint attr_flags, constvoid *name,
size_t length)
{ /* * Parent pointers always use logged operations, so there should never * be incomplete xattrs.
*/ if (attr_flags & XFS_ATTR_INCOMPLETE) returnfalse;
return xfs_dir2_namecheck(name, length);
}
/* Return true if parent pointer attr value is valid. */ bool
xfs_parent_valuecheck( struct xfs_mount *mp, constvoid *value,
size_t valuelen)
{ conststruct xfs_parent_rec *rec = value;
if (!xfs_has_parent(mp)) returnfalse;
/* The xattr value must be a parent record. */ if (valuelen != sizeof(struct xfs_parent_rec)) returnfalse;
/* The parent record must be local. */ if (value == NULL) returnfalse;
/* The parent inumber must be valid. */ if (!xfs_verify_dir_ino(mp, be64_to_cpu(rec->p_ino))) returnfalse;
returntrue;
}
/* Compute the attribute name hash for a parent pointer. */
xfs_dahash_t
xfs_parent_hashval( struct xfs_mount *mp, const uint8_t *name, int namelen,
xfs_ino_t parent_ino)
{ struct xfs_name xname = {
.name = name,
.len = namelen,
};
/* * Use the same dirent name hash as would be used on the directory, but * mix in the parent inode number to avoid collisions on hardlinked * files with identical names but different parents.
*/ return xfs_dir2_hashname(mp, &xname) ^
upper_32_bits(parent_ino) ^ lower_32_bits(parent_ino);
}
/* Compute the attribute name hash from the xattr components. */
xfs_dahash_t
xfs_parent_hashattr( struct xfs_mount *mp, const uint8_t *name, int namelen, constvoid *value, int valuelen)
{ conststruct xfs_parent_rec *rec = value;
/* Requires a local attr value in xfs_parent_rec format */ if (valuelen != sizeof(struct xfs_parent_rec)) {
ASSERT(valuelen == sizeof(struct xfs_parent_rec)); return 0;
}
/* Make sure the incore state is ready for a parent pointer query/update. */ staticinlineint
xfs_parent_iread_extents( struct xfs_trans *tp, struct xfs_inode *child)
{ /* Parent pointers require that the attr fork must exist. */ if (XFS_IS_CORRUPT(child->i_mount, !xfs_inode_has_attr_fork(child))) {
xfs_inode_mark_sick(child, XFS_SICK_INO_PARENT); return -EFSCORRUPTED;
}
/* * Extract parent pointer information from any parent pointer xattr into * @parent_ino/gen. The last two parameters can be NULL pointers. * * Returns 0 if this is not a parent pointer xattr at all; or -EFSCORRUPTED for * garbage.
*/ int
xfs_parent_from_attr( struct xfs_mount *mp, unsignedint attr_flags, constunsignedchar *name, unsignedint namelen, constvoid *value, unsignedint valuelen,
xfs_ino_t *parent_ino,
uint32_t *parent_gen)
{ conststruct xfs_parent_rec *rec = value;
ASSERT(attr_flags & XFS_ATTR_PARENT);
if (!xfs_parent_namecheck(attr_flags, name, namelen)) return -EFSCORRUPTED; if (!xfs_parent_valuecheck(mp, value, valuelen)) return -EFSCORRUPTED;
if (parent_ino)
*parent_ino = be64_to_cpu(rec->p_ino); if (parent_gen)
*parent_gen = be32_to_cpu(rec->p_gen); return 0;
}
/* * Look up a parent pointer record (@parent_name -> @pptr) of @ip. * * Caller must hold at least ILOCK_SHARED. The scratchpad need not be * initialized. * * Returns 0 if the pointer is found, -ENOATTR if there is no match, or a * negative errno.
*/ int
xfs_parent_lookup( struct xfs_trans *tp, struct xfs_inode *ip, conststruct xfs_name *parent_name, struct xfs_parent_rec *pptr, struct xfs_da_args *scratch)
{
memset(scratch, 0, sizeof(struct xfs_da_args));
xfs_parent_da_args_init(scratch, tp, pptr, ip, ip->i_ino, parent_name); return xfs_attr_get_ilocked(scratch);
}
/* Sanity-check a parent pointer before we try to perform repairs. */ staticinlinebool
xfs_parent_sanity_check( struct xfs_mount *mp, conststruct xfs_name *parent_name, conststruct xfs_parent_rec *pptr)
{ if (!xfs_parent_namecheck(XFS_ATTR_PARENT, parent_name->name,
parent_name->len)) returnfalse;
if (!xfs_parent_valuecheck(mp, pptr, sizeof(*pptr))) returnfalse;
returntrue;
}
/* * Attach the parent pointer (@parent_name -> @pptr) to @ip immediately. * Caller must not have a transaction or hold the ILOCK. This is for * specialized repair functions only. The scratchpad need not be initialized.
*/ int
xfs_parent_set( struct xfs_inode *ip,
xfs_ino_t owner, conststruct xfs_name *parent_name, struct xfs_parent_rec *pptr, struct xfs_da_args *scratch)
{ if (!xfs_parent_sanity_check(ip->i_mount, parent_name, pptr)) {
ASSERT(0); return -EFSCORRUPTED;
}
/* * Remove the parent pointer (@parent_name -> @pptr) from @ip immediately. * Caller must not have a transaction or hold the ILOCK. This is for * specialized repair functions only. The scratchpad need not be initialized.
*/ int
xfs_parent_unset( struct xfs_inode *ip,
xfs_ino_t owner, conststruct xfs_name *parent_name, struct xfs_parent_rec *pptr, struct xfs_da_args *scratch)
{ if (!xfs_parent_sanity_check(ip->i_mount, parent_name, pptr)) {
ASSERT(0); return -EFSCORRUPTED;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.