Commit b7c62d90 authored by Allison Henderson's avatar Allison Henderson Committed by Darrick J. Wong
Browse files

xfs: parent pointer attribute creation



Add parent pointer attribute during xfs_create, and subroutines to
initialize attributes.  Note that the xfs_attr_intent object contains a
pointer to the caller's xfs_da_args object, so the latter must persist
until transaction commit.

Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarAllison Henderson <allison.henderson@oracle.com>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
[djwong: shorten names, adjust to new format, set init_xattrs for parent
pointers]
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent fb102fe7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ xfs-y += $(addprefix libxfs/, \
				   xfs_symlink_remote.o \
				   xfs_trans_inode.o \
				   xfs_trans_resv.o \
				   xfs_trans_space.o \
				   xfs_types.o \
				   )
# xfs_rtbitmap is shared with libxfs
+68 −0
Original line number Diff line number Diff line
@@ -27,6 +27,10 @@
#include "xfs_xattr.h"
#include "xfs_parent.h"
#include "xfs_trans_space.h"
#include "xfs_attr_item.h"
#include "xfs_health.h"

struct kmem_cache		*xfs_parent_args_cache;

/*
 * Parent pointer attribute handling.
@@ -137,3 +141,67 @@ xfs_parent_hashattr(

	return xfs_parent_hashval(mp, name, namelen, be64_to_cpu(rec->p_ino));
}

/*
 * Initialize the parent pointer arguments structure.  Caller must have zeroed
 * the contents of @args.  @tp is only required for updates.
 */
static void
xfs_parent_da_args_init(
	struct xfs_da_args	*args,
	struct xfs_trans	*tp,
	struct xfs_parent_rec	*rec,
	struct xfs_inode	*child,
	xfs_ino_t		owner,
	const struct xfs_name	*parent_name)
{
	args->geo = child->i_mount->m_attr_geo;
	args->whichfork = XFS_ATTR_FORK;
	args->attr_filter = XFS_ATTR_PARENT;
	args->op_flags = XFS_DA_OP_LOGGED | XFS_DA_OP_OKNOENT;
	args->trans = tp;
	args->dp = child;
	args->owner = owner;
	args->name = parent_name->name;
	args->namelen = parent_name->len;
	args->value = rec;
	args->valuelen = sizeof(struct xfs_parent_rec);
	xfs_attr_sethash(args);
}

/* Make sure the incore state is ready for a parent pointer query/update. */
static inline int
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;
	}

	return xfs_iread_extents(tp, child, XFS_ATTR_FORK);
}

/* Add a parent pointer to reflect a dirent addition. */
int
xfs_parent_addname(
	struct xfs_trans	*tp,
	struct xfs_parent_args	*ppargs,
	struct xfs_inode	*dp,
	const struct xfs_name	*parent_name,
	struct xfs_inode	*child)
{
	int			error;

	error = xfs_parent_iread_extents(tp, child);
	if (error)
		return error;

	xfs_inode_to_parent_rec(&ppargs->rec, dp);
	xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
			child->i_ino, parent_name);
	xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_SET);
	return 0;
}
+65 −0
Original line number Diff line number Diff line
@@ -17,4 +17,69 @@ xfs_dahash_t xfs_parent_hashval(struct xfs_mount *mp, const uint8_t *name,
xfs_dahash_t xfs_parent_hashattr(struct xfs_mount *mp, const uint8_t *name,
		int namelen, const void *value, int valuelen);

/* Initializes a xfs_parent_rec to be stored as an attribute name. */
static inline void
xfs_parent_rec_init(
	struct xfs_parent_rec	*rec,
	xfs_ino_t		ino,
	uint32_t		gen)
{
	rec->p_ino = cpu_to_be64(ino);
	rec->p_gen = cpu_to_be32(gen);
}

/* Initializes a xfs_parent_rec to be stored as an attribute name. */
static inline void
xfs_inode_to_parent_rec(
	struct xfs_parent_rec	*rec,
	const struct xfs_inode	*dp)
{
	xfs_parent_rec_init(rec, dp->i_ino, VFS_IC(dp)->i_generation);
}

extern struct kmem_cache	*xfs_parent_args_cache;

/*
 * Parent pointer information needed to pass around the deferred xattr update
 * machinery.
 */
struct xfs_parent_args {
	struct xfs_parent_rec	rec;
	struct xfs_da_args	args;
};

/*
 * Start a parent pointer update by allocating the context object we need to
 * perform a parent pointer update.
 */
static inline int
xfs_parent_start(
	struct xfs_mount	*mp,
	struct xfs_parent_args	**ppargsp)
{
	if (!xfs_has_parent(mp)) {
		*ppargsp = NULL;
		return 0;
	}

	*ppargsp = kmem_cache_zalloc(xfs_parent_args_cache, GFP_KERNEL);
	if (!*ppargsp)
		return -ENOMEM;
	return 0;
}

/* Finish a parent pointer update by freeing the context object. */
static inline void
xfs_parent_finish(
	struct xfs_mount	*mp,
	struct xfs_parent_args	*ppargs)
{
	if (ppargs)
		kmem_cache_free(xfs_parent_args_cache, ppargs);
}

int xfs_parent_addname(struct xfs_trans *tp, struct xfs_parent_args *ppargs,
		struct xfs_inode *dp, const struct xfs_name *parent_name,
		struct xfs_inode *child);

#endif /* __XFS_PARENT_H__ */
+52 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2000,2005 Silicon Graphics, Inc.
 * All Rights Reserved.
 */
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_shared.h"
#include "xfs_format.h"
#include "xfs_da_format.h"
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
#include "xfs_mount.h"
#include "xfs_da_btree.h"
#include "xfs_bmap_btree.h"
#include "xfs_trans_space.h"

/* Calculate the disk space required to add a parent pointer. */
unsigned int
xfs_parent_calc_space_res(
	struct xfs_mount	*mp,
	unsigned int		namelen)
{
	/*
	 * Parent pointers are always the first attr in an attr tree, and never
	 * larger than a block
	 */
	return XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) +
	       XFS_NEXTENTADD_SPACE_RES(mp, namelen, XFS_ATTR_FORK);
}

unsigned int
xfs_create_space_res(
	struct xfs_mount	*mp,
	unsigned int		namelen)
{
	unsigned int		ret;

	ret = XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp, namelen);
	if (xfs_has_parent(mp))
		ret += xfs_parent_calc_space_res(mp, namelen);

	return ret;
}

unsigned int
xfs_mkdir_space_res(
	struct xfs_mount	*mp,
	unsigned int		namelen)
{
	return xfs_create_space_res(mp, namelen);
}
+5 −4
Original line number Diff line number Diff line
@@ -80,8 +80,6 @@
/* This macro is not used - see inline code in xfs_attr_set */
#define	XFS_ATTRSET_SPACE_RES(mp, v)	\
	(XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + XFS_B_TO_FSB(mp, v))
#define	XFS_CREATE_SPACE_RES(mp,nl)	\
	(XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl))
#define	XFS_DIOSTRAT_SPACE_RES(mp, v)	\
	(XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + (v))
#define	XFS_GROWFS_SPACE_RES(mp)	\
@@ -90,8 +88,6 @@
	((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK))
#define	XFS_LINK_SPACE_RES(mp,nl)	\
	XFS_DIRENTER_SPACE_RES(mp,nl)
#define	XFS_MKDIR_SPACE_RES(mp,nl)	\
	(XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl))
#define	XFS_QM_DQALLOC_SPACE_RES(mp)	\
	(XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \
	 XFS_DQUOT_CLUSTER_SIZE_FSB)
@@ -106,5 +102,10 @@
#define XFS_IFREE_SPACE_RES(mp)		\
	(xfs_has_finobt(mp) ? M_IGEO(mp)->inobt_maxlevels : 0)

unsigned int xfs_parent_calc_space_res(struct xfs_mount *mp,
		unsigned int namelen);

unsigned int xfs_create_space_res(struct xfs_mount *mp, unsigned int namelen);
unsigned int xfs_mkdir_space_res(struct xfs_mount *mp, unsigned int namelen);

#endif	/* __XFS_TRANS_SPACE_H__ */
Loading