ocfs2: Handle value tree roots in ocfs2_xa_set_inline_value()
Joel Becker [Tue, 18 Aug 2009 02:56:01 +0000 (19:56 -0700)]
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>

fs/ocfs2/xattr.c

index 4bf6ec8..6d362e2 100644 (file)
@@ -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. */