summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/libxfs/xfs_attr.c4
-rw-r--r--fs/xfs/libxfs/xfs_attr_leaf.c38
-rw-r--r--fs/xfs/libxfs/xfs_attr_leaf.h1
-rw-r--r--fs/xfs/xfs_trace.h1
4 files changed, 44 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 54be75edb2eb..93caa1dae501 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -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);
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index c3327b10709c..47f48ae555c0 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -843,6 +843,44 @@ xfs_attr_sf_findname(
}
/*
+ * 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.
*/
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
index 589f810eedc0..aca46da2bc50 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.h
+++ b/fs/xfs/libxfs/xfs_attr_leaf.h
@@ -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);
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index f70afbf3cb19..a8bea99e0024 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -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);