diff options
author | Joel Becker <joel.becker@oracle.com> | 2009-08-18 06:56:01 +0400 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2010-02-27 02:41:10 +0300 |
commit | 9dc474005d0e34cf21d4b510f347e3942f24b021 (patch) | |
tree | f19e028c6f500802623a5c8256c64e434a79a2be | |
parent | 69a3e539d083ac09aec92b8705b8ff2c2e5c810c (diff) | |
download | linux-9dc474005d0e34cf21d4b510f347e3942f24b021.tar.xz |
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: Joel Becker <joel.becker@oracle.com>
-rw-r--r-- | fs/ocfs2/xattr.c | 54 |
1 files changed, 16 insertions, 38 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 4bf6ec849e19..6d362e2d3960 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -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,16 +2088,9 @@ 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)) { - 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 (xi->xi_value && (free < ocfs2_xi_entry_usage(xi))) { + ret = -ENOSPC; + goto out; } if (!xs->not_found) { @@ -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. */ |