@@ -979,11 +979,21 @@ struct xfs_icreate_log {
struct xfs_attri_log_format {
uint16_t alfi_type; /* attri log item type */
uint16_t alfi_size; /* size of this item */
- uint32_t alfi_nname_len; /* attr new name length */
+ uint32_t __pad; /* pad to 64 bit aligned */
uint64_t alfi_id; /* attri identifier */
uint64_t alfi_ino; /* the inode for this attr operation */
uint32_t alfi_op_flags; /* marks the op as a set or remove */
- uint32_t alfi_name_len; /* attr name length */
+ union {
+ uint32_t alfi_name_len; /* attr name length */
+ struct {
+ /*
+ * For NVREPLACE, these are the lengths of the old and
+ * new attr name.
+ */
+ uint16_t alfi_oldname_len;
+ uint16_t alfi_newname_len;
+ };
+ };
uint32_t alfi_value_len; /* attr value length */
uint32_t alfi_attr_filter;/* attr filter flags */
};
@@ -402,8 +402,14 @@ xfs_attr_log_item(
ASSERT(!(attr->xattri_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK));
attrp->alfi_op_flags = attr->xattri_op_flags;
attrp->alfi_value_len = attr->xattri_nameval->value.i_len;
- attrp->alfi_name_len = attr->xattri_nameval->name.i_len;
- attrp->alfi_nname_len = attr->xattri_nameval->nname.i_len;
+
+ if (xfs_attr_log_item_op(attrp) == XFS_ATTRI_OP_FLAGS_NVREPLACE) {
+ attrp->alfi_oldname_len = attr->xattri_nameval->name.i_len;
+ attrp->alfi_newname_len = attr->xattri_nameval->nname.i_len;
+ } else {
+ attrp->alfi_name_len = attr->xattri_nameval->name.i_len;
+ }
+
ASSERT(!(attr->xattri_da_args->attr_filter & ~XFS_ATTRI_FILTER_MASK));
attrp->alfi_attr_filter = attr->xattri_da_args->attr_filter;
}
@@ -533,10 +539,6 @@ xfs_attri_validate(
{
unsigned int op = xfs_attr_log_item_op(attrp);
- if (attrp->alfi_op_flags != XFS_ATTRI_OP_FLAGS_NVREPLACE &&
- attrp->alfi_nname_len != 0)
- return false;
-
if (attrp->alfi_op_flags & ~XFS_ATTRI_OP_FLAGS_TYPE_MASK)
return false;
@@ -545,29 +547,37 @@ xfs_attri_validate(
/* alfi_op_flags should be either a set or remove */
switch (op) {
+ case XFS_ATTRI_OP_FLAGS_REMOVE:
+ if (attrp->alfi_value_len != 0)
+ return false;
+ if (attrp->alfi_name_len == 0 ||
+ attrp->alfi_name_len > XATTR_NAME_MAX)
+ return false;
+ break;
case XFS_ATTRI_OP_FLAGS_SET:
case XFS_ATTRI_OP_FLAGS_REPLACE:
- case XFS_ATTRI_OP_FLAGS_REMOVE:
- case XFS_ATTRI_OP_FLAGS_NVREPLACE:
case XFS_ATTRI_OP_FLAGS_NVREMOVE:
case XFS_ATTRI_OP_FLAGS_NVSET:
+ if (attrp->alfi_name_len == 0 ||
+ attrp->alfi_name_len > XATTR_NAME_MAX)
+ return false;
+ if (attrp->alfi_value_len > XATTR_SIZE_MAX)
+ return false;
+ break;
+ case XFS_ATTRI_OP_FLAGS_NVREPLACE:
+ if (attrp->alfi_oldname_len == 0 ||
+ attrp->alfi_oldname_len > XATTR_NAME_MAX)
+ return false;
+ if (attrp->alfi_newname_len == 0 ||
+ attrp->alfi_newname_len > XATTR_NAME_MAX)
+ return false;
+ if (attrp->alfi_value_len > XATTR_SIZE_MAX)
+ return false;
break;
default:
return false;
}
- if (attrp->alfi_value_len > XATTR_SIZE_MAX)
- return false;
-
- if ((attrp->alfi_name_len > XATTR_NAME_MAX) ||
- (attrp->alfi_nname_len > XATTR_NAME_MAX) ||
- (attrp->alfi_name_len == 0))
- return false;
-
- if (op == XFS_ATTRI_OP_FLAGS_REMOVE &&
- attrp->alfi_value_len != 0)
- return false;
-
return xfs_verify_ino(mp, attrp->alfi_ino);
}
@@ -737,8 +747,12 @@ xfs_attri_item_relog(
new_attrp->alfi_ino = old_attrp->alfi_ino;
new_attrp->alfi_op_flags = old_attrp->alfi_op_flags;
new_attrp->alfi_value_len = old_attrp->alfi_value_len;
- new_attrp->alfi_name_len = old_attrp->alfi_name_len;
- new_attrp->alfi_nname_len = old_attrp->alfi_nname_len;
+ if (xfs_attr_log_item_op(old_attrp) == XFS_ATTRI_OP_FLAGS_NVREPLACE) {
+ new_attrp->alfi_newname_len = old_attrp->alfi_newname_len;
+ new_attrp->alfi_oldname_len = old_attrp->alfi_oldname_len;
+ } else {
+ new_attrp->alfi_name_len = old_attrp->alfi_name_len;
+ }
new_attrp->alfi_attr_filter = old_attrp->alfi_attr_filter;
xfs_trans_add_item(tp, &new_attrip->attri_item);
@@ -762,6 +776,7 @@ xlog_recover_attri_commit_pass2(
const void *attr_name;
size_t len;
const void *attr_nname = NULL;
+ unsigned int name_len = 0, newname_len = 0;
int op, i = 0;
/* Validate xfs_attri_log_format before the large memory allocation */
@@ -790,6 +805,7 @@ xlog_recover_attri_commit_pass2(
attri_formatp, len);
return -EFSCORRUPTED;
}
+ name_len = attri_formatp->alfi_name_len;
break;
case XFS_ATTRI_OP_FLAGS_REMOVE:
if (item->ri_total != 2) {
@@ -797,6 +813,7 @@ xlog_recover_attri_commit_pass2(
attri_formatp, len);
return -EFSCORRUPTED;
}
+ name_len = attri_formatp->alfi_name_len;
break;
case XFS_ATTRI_OP_FLAGS_NVREPLACE:
if (item->ri_total != 3 && item->ri_total != 4) {
@@ -804,6 +821,8 @@ xlog_recover_attri_commit_pass2(
attri_formatp, len);
return -EFSCORRUPTED;
}
+ name_len = attri_formatp->alfi_oldname_len;
+ newname_len = attri_formatp->alfi_newname_len;
break;
default:
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
@@ -813,15 +832,14 @@ xlog_recover_attri_commit_pass2(
i++;
/* Validate the attr name */
- if (item->ri_buf[i].i_len !=
- xlog_calc_iovec_len(attri_formatp->alfi_name_len)) {
+ if (item->ri_buf[i].i_len != xlog_calc_iovec_len(name_len)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
attri_formatp, len);
return -EFSCORRUPTED;
}
attr_name = item->ri_buf[i].i_addr;
- if (!xfs_attr_namecheck(mp, attr_name, attri_formatp->alfi_name_len,
+ if (!xfs_attr_namecheck(mp, attr_name, name_len,
attri_formatp->alfi_attr_filter)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
item->ri_buf[i].i_addr, item->ri_buf[i].i_len);
@@ -829,10 +847,9 @@ xlog_recover_attri_commit_pass2(
}
i++;
- if (attri_formatp->alfi_nname_len) {
+ if (newname_len > 0) {
/* Validate the attr nname */
- if (item->ri_buf[i].i_len !=
- xlog_calc_iovec_len(attri_formatp->alfi_nname_len)) {
+ if (item->ri_buf[i].i_len != xlog_calc_iovec_len(newname_len)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
item->ri_buf[i].i_addr,
item->ri_buf[i].i_len);
@@ -840,8 +857,7 @@ xlog_recover_attri_commit_pass2(
}
attr_nname = item->ri_buf[i].i_addr;
- if (!xfs_attr_namecheck(mp, attr_nname,
- attri_formatp->alfi_nname_len,
+ if (!xfs_attr_namecheck(mp, attr_nname, newname_len,
attri_formatp->alfi_attr_filter)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
item->ri_buf[i].i_addr,
@@ -868,9 +884,8 @@ xlog_recover_attri_commit_pass2(
* name/value buffer to the recovered incore log item and drop our
* reference.
*/
- nv = xfs_attri_log_nameval_alloc(attr_name,
- attri_formatp->alfi_name_len, attr_nname,
- attri_formatp->alfi_nname_len, attr_value,
+ nv = xfs_attri_log_nameval_alloc(attr_name, name_len, attr_nname,
+ newname_len, attr_value,
attri_formatp->alfi_value_len);
attrip = xfs_attri_init(mp, nv);