Commit eaec8aef authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: add a method to replace shortform attrs



If we're trying to replace an xattr in a shortform attr structure and
the old entry fits the new entry, we can just memcpy and exit without
having to delete, compact, and re-add the entry (or worse use the attr
intent machinery).  For parent pointers this only advantages renaming
where the filename length stays the same (e.g. mv autoexec.bat
scandisk.exe) but for regular xattrs it might be useful for updating
security labels and the like.

Signed-off-by: default avatar"Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent d6935345
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1085,6 +1085,10 @@ xfs_attr_replacename(
		return 0;
	}

	error = xfs_attr_shortform_replace(args);
	if (error != -ENOSPC)
		return error;

	args->op_flags |= XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE;

	error = xfs_attr_sf_removename(args);
+38 −0
Original line number Diff line number Diff line
@@ -842,6 +842,44 @@ xfs_attr_sf_findname(
	return NULL;
}

/*
 * Replace a shortform xattr if it's the right length.  Returns 0 on success,
 * -ENOSPC if the length is wrong, or -ENOATTR if the attr was not found.
 */
int
xfs_attr_shortform_replace(
	struct xfs_da_args		*args)
{
	struct xfs_attr_sf_entry	*sfe;

	ASSERT(args->dp->i_af.if_format == XFS_DINODE_FMT_LOCAL);

	trace_xfs_attr_sf_replace(args);

	sfe = xfs_attr_sf_findname(args);
	if (!sfe)
		return -ENOATTR;

	if (args->attr_filter & XFS_ATTR_PARENT) {
		if (sfe->namelen != args->new_namelen ||
		    sfe->valuelen != args->new_valuelen)
			return -ENOSPC;

		memcpy(sfe->nameval, args->new_name, sfe->namelen);
		memcpy(&sfe->nameval[sfe->namelen], args->new_value,
				sfe->valuelen);
	} else {
		if (sfe->valuelen != args->valuelen)
			return -ENOSPC;
		memcpy(&sfe->nameval[sfe->namelen], args->value,
				sfe->valuelen);
	}

	xfs_trans_log_inode(args->trans, args->dp,
			XFS_ILOG_CORE | XFS_ILOG_ADATA);
	return 0;
}

/*
 * Add a name/value pair to the shortform attribute list.
 * Overflow from the inode has already been checked for.
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ struct xfs_attr3_icleaf_hdr {
 * Internal routines when attribute fork size < XFS_LITINO(mp).
 */
void	xfs_attr_shortform_create(struct xfs_da_args *args);
int	xfs_attr_shortform_replace(struct xfs_da_args *args);
void	xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args);
+1 −0
Original line number Diff line number Diff line
@@ -2410,6 +2410,7 @@ DEFINE_ATTR_EVENT(xfs_attr_sf_addname);
DEFINE_ATTR_EVENT(xfs_attr_sf_create);
DEFINE_ATTR_EVENT(xfs_attr_sf_lookup);
DEFINE_ATTR_EVENT(xfs_attr_sf_remove);
DEFINE_ATTR_EVENT(xfs_attr_sf_replace);
DEFINE_ATTR_EVENT(xfs_attr_sf_to_leaf);

DEFINE_ATTR_EVENT(xfs_attr_leaf_add);