Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9dc47400 authored by Joel Becker's avatar Joel Becker
Browse files

ocfs2: Handle value tree roots in ocfs2_xa_set_inline_value()



Previously the xattr code would send in a fake value, containing a tree
root, to the function that installed name+value pairs.  Instead, we pass
the real value to ocfs2_xa_set_inline_value(), and it notices that the
value cannot fit.  Thus, it installs a tree root.

Signed-off-by: default avatarJoel Becker <joel.becker@oracle.com>
parent 69a3e539
Loading
Loading
Loading
Loading
+16 −38
Original line number Diff line number Diff line
@@ -1968,14 +1968,19 @@ static void ocfs2_xa_store_inline_value(struct ocfs2_xa_loc *loc,
{
	int nameval_offset = le16_to_cpu(loc->xl_entry->xe_name_offset);
	int name_size = OCFS2_XATTR_SIZE(xi->xi_name_len);
	int size = namevalue_size_xi(xi);
	int inline_value_size = namevalue_size_xi(xi) - name_size;
	const void *value = xi->xi_value;
	char *nameval_buf;

	if (!xi->xi_value)
		return;

	if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) {
		value = &def_xv;
		inline_value_size = OCFS2_XATTR_ROOT_SIZE;
	}
	nameval_buf = ocfs2_xa_offset_pointer(loc, nameval_offset);
	memcpy(nameval_buf + name_size, xi->xi_value, size - name_size);
	memcpy(nameval_buf + name_size, value, inline_value_size);
}

static void ocfs2_init_dinode_xa_loc(struct ocfs2_xa_loc *loc,
@@ -2054,13 +2059,6 @@ static int ocfs2_xattr_set_entry(struct inode *inode,
	u32 name_hash = ocfs2_xattr_name_hash(inode, xi->xi_name,
					      xi->xi_name_len);
	struct ocfs2_xa_loc loc;
	struct ocfs2_xattr_info xi_l = {
		.xi_name_index = xi->xi_name_index,
		.xi_name = xi->xi_name,
		.xi_name_len = xi->xi_name_len,
		.xi_value = xi->xi_value,
		.xi_value_len = xi->xi_value_len,
	};
	struct ocfs2_xattr_value_buf vb = {
		.vb_bh = xs->xattr_bh,
		.vb_access = ocfs2_journal_access_di,
@@ -2090,17 +2088,10 @@ static int ocfs2_xattr_set_entry(struct inode *inode,
		free += ocfs2_xe_entry_usage(xs->here);

	/* Check free space in inode or block */
	if (xi->xi_value) {
		if (free < ocfs2_xi_entry_usage(xi)) {
	if (xi->xi_value && (free < ocfs2_xi_entry_usage(xi))) {
		ret = -ENOSPC;
		goto out;
	}
		if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) {
			size_l = namevalue_size_xi(xi);
			xi_l.xi_value = (void *)&def_xv;
			xi_l.xi_value_len = OCFS2_XATTR_ROOT_SIZE;
		}
	}

	if (!xs->not_found) {
		/* For existing extended attribute */
@@ -5255,8 +5246,7 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode,
					   handle_t *handle,
					   struct ocfs2_xattr_info *xi,
					   struct ocfs2_xattr_search *xs,
					   u32 name_hash,
					   int local)
					   u32 name_hash)
{
	int ret;
	u64 blkno;
@@ -5571,13 +5561,14 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode,
				     struct ocfs2_xattr_search *xs,
				     struct ocfs2_xattr_set_ctxt *ctxt)
{
	int ret, local = 1;
	int ret;
	size_t value_len;
	char *val = (char *)xi->xi_value;
	struct ocfs2_xattr_entry *xe = xs->here;
	u32 name_hash = ocfs2_xattr_name_hash(inode, xi->xi_name,
					      xi->xi_name_len);

	value_len = xi->xi_value_len;
	if (!xs->not_found && !ocfs2_xattr_is_local(xe)) {
		/*
		 * We need to truncate the xattr storage first.
@@ -5591,9 +5582,7 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode,
		 * the modification to the xattr block will be done
		 * by following steps.
		 */
		if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE)
			value_len = xi->xi_value_len;
		else
		if (xi->xi_value_len <= OCFS2_XATTR_INLINE_SIZE)
			value_len = 0;

		ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
@@ -5606,26 +5595,15 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode,
			goto set_value_outside;
	}

	value_len = xi->xi_value_len;
	/* So we have to handle the inside block change now. */
	if (value_len > OCFS2_XATTR_INLINE_SIZE) {
		/*
		 * If the new value will be stored outside of block,
		 * initalize a new empty value root and insert it first.
		 */
		local = 0;
		xi->xi_value = &def_xv;
		xi->xi_value_len = OCFS2_XATTR_ROOT_SIZE;
	}

	ret = ocfs2_xattr_set_entry_in_bucket(inode, ctxt->handle, xi, xs,
					      name_hash, local);
					      name_hash);
	if (ret) {
		mlog_errno(ret);
		goto out;
	}

	if (value_len <= OCFS2_XATTR_INLINE_SIZE)
	if (xi->xi_value_len <= OCFS2_XATTR_INLINE_SIZE)
		goto out;

	/* allocate the space now for the outside block storage. */