]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/ocfs2/xattr.c
Merge branch 'linus' into cpus4096
[linux-2.6-omap-h63xx.git] / fs / ocfs2 / xattr.c
index 9c3d4dc3e2eac1ef8a3b69fde0a0b69049bed376..74d7367ade13e1e36cb74a13327ca65573fabf86 100644 (file)
@@ -3,25 +3,20 @@
  *
  * xattr.c
  *
- * Copyright (C) 2008 Oracle.  All rights reserved.
+ * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
  *
  * CREDITS:
- * Lots of code in this file is taken from ext3.
+ * Lots of code in this file is copy from linux/fs/ext3/xattr.c.
+ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * License version 2 as published by the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
  */
 
 #include <linux/capability.h>
@@ -37,6 +32,9 @@
 #include <linux/writeback.h>
 #include <linux/falloc.h>
 #include <linux/sort.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
 
 #define MLOG_MASK_PREFIX ML_XATTR
 #include <cluster/masklog.h>
@@ -80,7 +78,7 @@ struct xattr_handler *ocfs2_xattr_handlers[] = {
        NULL
 };
 
-static struct xattr_handler *ocfs2_xattr_handler_map[] = {
+static struct xattr_handler *ocfs2_xattr_handler_map[OCFS2_XATTR_MAX] = {
        [OCFS2_XATTR_INDEX_USER]        = &ocfs2_xattr_user_handler,
        [OCFS2_XATTR_INDEX_TRUSTED]     = &ocfs2_xattr_trusted_handler,
 };
@@ -113,6 +111,10 @@ static int ocfs2_xattr_bucket_get_name_value(struct inode *inode,
                                             int *block_off,
                                             int *new_offset);
 
+static int ocfs2_xattr_block_find(struct inode *inode,
+                                 int name_index,
+                                 const char *name,
+                                 struct ocfs2_xattr_search *xs);
 static int ocfs2_xattr_index_block_find(struct inode *inode,
                                        struct buffer_head *root_bh,
                                        int name_index,
@@ -134,32 +136,42 @@ static int ocfs2_xattr_set_entry_index_block(struct inode *inode,
 static int ocfs2_delete_xattr_index_block(struct inode *inode,
                                          struct buffer_head *xb_bh);
 
-static inline struct xattr_handler *ocfs2_xattr_handler(int name_index)
+static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb)
+{
+       return (1 << osb->s_clustersize_bits) / OCFS2_XATTR_BUCKET_SIZE;
+}
+
+static inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb)
+{
+       return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits);
+}
+
+static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb)
+{
+       u16 len = sb->s_blocksize -
+                offsetof(struct ocfs2_xattr_header, xh_entries);
+
+       return len / sizeof(struct ocfs2_xattr_entry);
+}
+
+static inline const char *ocfs2_xattr_prefix(int name_index)
 {
        struct xattr_handler *handler = NULL;
 
        if (name_index > 0 && name_index < OCFS2_XATTR_MAX)
                handler = ocfs2_xattr_handler_map[name_index];
 
-       return handler;
+       return handler ? handler->prefix : NULL;
 }
 
-static inline u32 ocfs2_xattr_name_hash(struct inode *inode,
-                                       char *prefix,
-                                       int prefix_len,
-                                       char *name,
-                                       int name_len)
+static u32 ocfs2_xattr_name_hash(struct inode *inode,
+                                const char *name,
+                                int name_len)
 {
        /* Get hash value of uuid from super block */
        u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash;
        int i;
 
-       /* hash extended attribute prefix */
-       for (i = 0; i < prefix_len; i++) {
-               hash = (hash << OCFS2_HASH_SHIFT) ^
-                      (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^
-                      *prefix++;
-       }
        /* hash extended attribute name */
        for (i = 0; i < name_len; i++) {
                hash = (hash << OCFS2_HASH_SHIFT) ^
@@ -180,14 +192,9 @@ static void ocfs2_xattr_hash_entry(struct inode *inode,
                                   struct ocfs2_xattr_entry *entry)
 {
        u32 hash = 0;
-       struct xattr_handler *handler =
-                       ocfs2_xattr_handler(ocfs2_xattr_get_type(entry));
-       char *prefix = handler->prefix;
        char *name = (char *)header + le16_to_cpu(entry->xe_name_offset);
-       int prefix_len = strlen(handler->prefix);
 
-       hash = ocfs2_xattr_name_hash(inode, prefix, prefix_len, name,
-                                    entry->xe_name_len);
+       hash = ocfs2_xattr_name_hash(inode, name, entry->xe_name_len);
        entry->xe_name_hash = cpu_to_le32(hash);
 
        return;
@@ -211,7 +218,7 @@ static int ocfs2_xattr_extend_allocation(struct inode *inode,
 
        mlog(0, "(clusters_to_add for xattr= %u)\n", clusters_to_add);
 
-       ocfs2_get_xattr_value_extent_tree(&et, inode, xattr_bh, xv);
+       ocfs2_init_xattr_value_extent_tree(&et, inode, xattr_bh, xv);
 
 restart_all:
 
@@ -307,7 +314,6 @@ leave:
                goto restart_all;
        }
 
-       ocfs2_put_extent_tree(&et);
        return status;
 }
 
@@ -325,11 +331,10 @@ static int __ocfs2_remove_xattr_range(struct inode *inode,
        struct ocfs2_alloc_context *meta_ac = NULL;
        struct ocfs2_extent_tree et;
 
-       ocfs2_get_xattr_value_extent_tree(&et, inode, root_bh, xv);
+       ocfs2_init_xattr_value_extent_tree(&et, inode, root_bh, xv);
 
        ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
        if (ret) {
-               ocfs2_put_extent_tree(&et);
                mlog_errno(ret);
                return ret;
        }
@@ -385,7 +390,6 @@ out:
        if (meta_ac)
                ocfs2_free_alloc_context(meta_ac);
 
-       ocfs2_put_extent_tree(&et);
        return ret;
 }
 
@@ -465,33 +469,56 @@ static int ocfs2_xattr_value_truncate(struct inode *inode,
        return ret;
 }
 
+static int ocfs2_xattr_list_entry(char *buffer, size_t size,
+                                 size_t *result, const char *prefix,
+                                 const char *name, int name_len)
+{
+       char *p = buffer + *result;
+       int prefix_len = strlen(prefix);
+       int total_len = prefix_len + name_len + 1;
+
+       *result += total_len;
+
+       /* we are just looking for how big our buffer needs to be */
+       if (!size)
+               return 0;
+
+       if (*result > size)
+               return -ERANGE;
+
+       memcpy(p, prefix, prefix_len);
+       memcpy(p + prefix_len, name, name_len);
+       p[prefix_len + name_len] = '\0';
+
+       return 0;
+}
+
 static int ocfs2_xattr_list_entries(struct inode *inode,
                                    struct ocfs2_xattr_header *header,
                                    char *buffer, size_t buffer_size)
 {
-       size_t rest = buffer_size;
-       int i;
+       size_t result = 0;
+       int i, type, ret;
+       const char *prefix, *name;
 
        for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) {
                struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
-               struct xattr_handler *handler =
-                       ocfs2_xattr_handler(ocfs2_xattr_get_type(entry));
-
-               if (handler) {
-                       size_t size = handler->list(inode, buffer, rest,
-                                       ((char *)header +
-                                       le16_to_cpu(entry->xe_name_offset)),
-                                       entry->xe_name_len);
-                       if (buffer) {
-                               if (size > rest)
-                                       return -ERANGE;
-                               buffer += size;
-                       }
-                       rest -= size;
+               type = ocfs2_xattr_get_type(entry);
+               prefix = ocfs2_xattr_prefix(type);
+
+               if (prefix) {
+                       name = (const char *)header +
+                               le16_to_cpu(entry->xe_name_offset);
+
+                       ret = ocfs2_xattr_list_entry(buffer, buffer_size,
+                                                    &result, prefix, name,
+                                                    entry->xe_name_len);
+                       if (ret)
+                               return ret;
                }
        }
 
-       return buffer_size - rest;
+       return result;
 }
 
 static int ocfs2_xattr_ibody_list(struct inode *inode,
@@ -527,21 +554,17 @@ static int ocfs2_xattr_block_list(struct inode *inode,
        if (!di->i_xattr_loc)
                return ret;
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                              le64_to_cpu(di->i_xattr_loc),
-                              &blk_bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
        if (ret < 0) {
                mlog_errno(ret);
                return ret;
        }
-       /*Verify the signature of xattr block*/
-       if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
-                  strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
-               ret = -EFAULT;
-               goto cleanup;
-       }
 
        xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+       if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) {
+               ret = -EIO;
+               goto cleanup;
+       }
 
        if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
                struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header;
@@ -662,8 +685,7 @@ static int ocfs2_xattr_get_value_outside(struct inode *inode,
                blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
                /* Copy ocfs2_xattr_value */
                for (i = 0; i < num_clusters * bpc; i++, blkno++) {
-                       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
-                                              &bh, OCFS2_BH_CACHED, inode);
+                       ret = ocfs2_read_block(inode, blkno, &bh);
                        if (ret) {
                                mlog_errno(ret);
                                goto out;
@@ -742,49 +764,25 @@ static int ocfs2_xattr_block_get(struct inode *inode,
                                 size_t buffer_size,
                                 struct ocfs2_xattr_search *xs)
 {
-       struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
-       struct buffer_head *blk_bh = NULL;
        struct ocfs2_xattr_block *xb;
        struct ocfs2_xattr_value_root *xv;
        size_t size;
        int ret = -ENODATA, name_offset, name_len, block_off, i;
 
-       if (!di->i_xattr_loc)
-               return ret;
-
        memset(&xs->bucket, 0, sizeof(xs->bucket));
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                              le64_to_cpu(di->i_xattr_loc),
-                              &blk_bh, OCFS2_BH_CACHED, inode);
-       if (ret < 0) {
+       ret = ocfs2_xattr_block_find(inode, name_index, name, xs);
+       if (ret) {
                mlog_errno(ret);
-               return ret;
-       }
-       /*Verify the signature of xattr block*/
-       if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
-                  strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
-               ret = -EFAULT;
                goto cleanup;
        }
 
-       xs->xattr_bh = blk_bh;
-       xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
-
-       if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
-               xs->header = &xb->xb_attrs.xb_header;
-               xs->base = (void *)xs->header;
-               xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
-               xs->here = xs->header->xh_entries;
-
-               ret = ocfs2_xattr_find_entry(name_index, name, xs);
-       } else
-               ret = ocfs2_xattr_index_block_find(inode, blk_bh,
-                                                  name_index,
-                                                  name, xs);
-
-       if (ret)
+       if (xs->not_found) {
+               ret = -ENODATA;
                goto cleanup;
+       }
+
+       xb = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
        size = le64_to_cpu(xs->here->xe_value_size);
        if (buffer) {
                ret = -ERANGE;
@@ -823,7 +821,8 @@ cleanup:
                brelse(xs->bucket.bhs[i]);
        memset(&xs->bucket, 0, sizeof(xs->bucket));
 
-       brelse(blk_bh);
+       brelse(xs->xattr_bh);
+       xs->xattr_bh = NULL;
        return ret;
 }
 
@@ -832,11 +831,11 @@ cleanup:
  * Copy an extended attribute into the buffer provided.
  * Buffer is NULL to compute the size of buffer required.
  */
-int ocfs2_xattr_get(struct inode *inode,
-                   int name_index,
-                   const char *name,
-                   void *buffer,
-                   size_t buffer_size)
+static int ocfs2_xattr_get(struct inode *inode,
+                          int name_index,
+                          const char *name,
+                          void *buffer,
+                          size_t buffer_size)
 {
        int ret;
        struct ocfs2_dinode *di = NULL;
@@ -866,7 +865,7 @@ int ocfs2_xattr_get(struct inode *inode,
        down_read(&oi->ip_xattr_sem);
        ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer,
                                    buffer_size, &xis);
-       if (ret == -ENODATA)
+       if (ret == -ENODATA && di->i_xattr_loc)
                ret = ocfs2_xattr_block_get(inode, name_index, name, buffer,
                                            buffer_size, &xbs);
        up_read(&oi->ip_xattr_sem);
@@ -912,8 +911,7 @@ static int __ocfs2_xattr_set_value_outside(struct inode *inode,
                blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
 
                for (i = 0; i < num_clusters * bpc; i++, blkno++) {
-                       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
-                                              &bh, OCFS2_BH_CACHED, inode);
+                       ret = ocfs2_read_block(inode, blkno, &bh);
                        if (ret) {
                                mlog_errno(ret);
                                goto out_commit;
@@ -1225,7 +1223,7 @@ static int ocfs2_xattr_set_entry(struct inode *inode,
 
        free = min_offs - ((void *)last - xs->base) - sizeof(__u32);
        if (free < 0)
-               return -EFAULT;
+               return -EIO;
 
        if (!xs->not_found) {
                size_t size = 0;
@@ -1339,8 +1337,9 @@ static int ocfs2_xattr_set_entry(struct inode *inode,
        }
 
        if (!(flag & OCFS2_INLINE_XATTR_FL)) {
-               /*set extended attribue in external blcok*/
+               /* set extended attribute in external block. */
                ret = ocfs2_extend_trans(handle,
+                                        OCFS2_INODE_UPDATE_CREDITS +
                                         OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
                if (ret) {
                        mlog_errno(ret);
@@ -1429,51 +1428,6 @@ out:
 
 }
 
-static int ocfs2_xattr_free_block(handle_t *handle,
-                                 struct ocfs2_super *osb,
-                                 struct ocfs2_xattr_block *xb)
-{
-       struct inode *xb_alloc_inode;
-       struct buffer_head *xb_alloc_bh = NULL;
-       u64 blk = le64_to_cpu(xb->xb_blkno);
-       u16 bit = le16_to_cpu(xb->xb_suballoc_bit);
-       u64 bg_blkno = ocfs2_which_suballoc_group(blk, bit);
-       int ret = 0;
-
-       xb_alloc_inode = ocfs2_get_system_file_inode(osb,
-                               EXTENT_ALLOC_SYSTEM_INODE,
-                               le16_to_cpu(xb->xb_suballoc_slot));
-       if (!xb_alloc_inode) {
-               ret = -ENOMEM;
-               mlog_errno(ret);
-               goto out;
-       }
-       mutex_lock(&xb_alloc_inode->i_mutex);
-
-       ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1);
-       if (ret < 0) {
-               mlog_errno(ret);
-               goto out_mutex;
-       }
-       ret = ocfs2_extend_trans(handle, OCFS2_SUBALLOC_FREE);
-       if (ret < 0) {
-               mlog_errno(ret);
-               goto out_unlock;
-       }
-       ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh,
-                                      bit, bg_blkno, 1);
-       if (ret < 0)
-               mlog_errno(ret);
-out_unlock:
-       ocfs2_inode_unlock(xb_alloc_inode, 1);
-       brelse(xb_alloc_bh);
-out_mutex:
-       mutex_unlock(&xb_alloc_inode->i_mutex);
-       iput(xb_alloc_inode);
-out:
-       return ret;
-}
-
 static int ocfs2_remove_value_outside(struct inode*inode,
                                      struct buffer_head *bh,
                                      struct ocfs2_xattr_header *header)
@@ -1535,6 +1489,81 @@ static int ocfs2_xattr_block_remove(struct inode *inode,
        return ret;
 }
 
+static int ocfs2_xattr_free_block(struct inode *inode,
+                                 u64 block)
+{
+       struct inode *xb_alloc_inode;
+       struct buffer_head *xb_alloc_bh = NULL;
+       struct buffer_head *blk_bh = NULL;
+       struct ocfs2_xattr_block *xb;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       handle_t *handle;
+       int ret = 0;
+       u64 blk, bg_blkno;
+       u16 bit;
+
+       ret = ocfs2_read_block(inode, block, &blk_bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+       if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) {
+               ret = -EIO;
+               goto out;
+       }
+
+       ret = ocfs2_xattr_block_remove(inode, blk_bh);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       blk = le64_to_cpu(xb->xb_blkno);
+       bit = le16_to_cpu(xb->xb_suballoc_bit);
+       bg_blkno = ocfs2_which_suballoc_group(blk, bit);
+
+       xb_alloc_inode = ocfs2_get_system_file_inode(osb,
+                               EXTENT_ALLOC_SYSTEM_INODE,
+                               le16_to_cpu(xb->xb_suballoc_slot));
+       if (!xb_alloc_inode) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+       mutex_lock(&xb_alloc_inode->i_mutex);
+
+       ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1);
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out_mutex;
+       }
+
+       handle = ocfs2_start_trans(osb, OCFS2_SUBALLOC_FREE);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out_unlock;
+       }
+
+       ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh,
+                                      bit, bg_blkno, 1);
+       if (ret < 0)
+               mlog_errno(ret);
+
+       ocfs2_commit_trans(osb, handle);
+out_unlock:
+       ocfs2_inode_unlock(xb_alloc_inode, 1);
+       brelse(xb_alloc_bh);
+out_mutex:
+       mutex_unlock(&xb_alloc_inode->i_mutex);
+       iput(xb_alloc_inode);
+out:
+       brelse(blk_bh);
+       return ret;
+}
+
 /*
  * ocfs2_xattr_remove()
  *
@@ -1542,9 +1571,6 @@ static int ocfs2_xattr_block_remove(struct inode *inode,
  */
 int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh)
 {
-       struct ocfs2_xattr_block *xb;
-       struct buffer_head *blk_bh = NULL;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
        struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
        handle_t *handle;
@@ -1563,22 +1589,10 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh)
                        goto out;
                }
        }
-       if (di->i_xattr_loc) {
-               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                                      le64_to_cpu(di->i_xattr_loc),
-                                      &blk_bh, OCFS2_BH_CACHED, inode);
-               if (ret < 0) {
-                       mlog_errno(ret);
-                       return ret;
-               }
-               /*Verify the signature of xattr block*/
-               if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
-                          strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
-                       ret = -EFAULT;
-                       goto out;
-               }
 
-               ret = ocfs2_xattr_block_remove(inode, blk_bh);
+       if (di->i_xattr_loc) {
+               ret = ocfs2_xattr_free_block(inode,
+                                            le64_to_cpu(di->i_xattr_loc));
                if (ret < 0) {
                        mlog_errno(ret);
                        goto out;
@@ -1599,11 +1613,7 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh)
                goto out_commit;
        }
 
-       if (di->i_xattr_loc) {
-               xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
-               ocfs2_xattr_free_block(handle, osb, xb);
-               di->i_xattr_loc = cpu_to_le64(0);
-       }
+       di->i_xattr_loc = 0;
 
        spin_lock(&oi->ip_lock);
        oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL);
@@ -1616,8 +1626,6 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh)
 out_commit:
        ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
 out:
-       brelse(blk_bh);
-
        return ret;
 }
 
@@ -1750,22 +1758,19 @@ static int ocfs2_xattr_block_find(struct inode *inode,
        if (!di->i_xattr_loc)
                return ret;
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                              le64_to_cpu(di->i_xattr_loc),
-                              &blk_bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
        if (ret < 0) {
                mlog_errno(ret);
                return ret;
        }
-       /*Verify the signature of xattr block*/
-       if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
-                  strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
-                       ret = -EFAULT;
-                       goto cleanup;
+
+       xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+       if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) {
+               ret = -EIO;
+               goto cleanup;
        }
 
        xs->xattr_bh = blk_bh;
-       xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
 
        if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
                xs->header = &xb->xb_attrs.xb_header;
@@ -1791,52 +1796,6 @@ cleanup:
        return ret;
 }
 
-/*
- * When all the xattrs are deleted from index btree, the ocfs2_xattr_tree
- * will be erased and ocfs2_xattr_block will have its ocfs2_xattr_header
- * re-initialized.
- */
-static int ocfs2_restore_xattr_block(struct inode *inode,
-                                    struct ocfs2_xattr_search *xs)
-{
-       int ret;
-       handle_t *handle;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-       struct ocfs2_xattr_block *xb =
-               (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
-       struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
-       u16 xb_flags = le16_to_cpu(xb->xb_flags);
-
-       BUG_ON(!(xb_flags & OCFS2_XATTR_INDEXED) ||
-               le16_to_cpu(el->l_next_free_rec) != 0);
-
-       handle = ocfs2_start_trans(osb, OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
-       if (IS_ERR(handle)) {
-               ret = PTR_ERR(handle);
-               handle = NULL;
-               goto out;
-       }
-
-       ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
-                                  OCFS2_JOURNAL_ACCESS_WRITE);
-       if (ret < 0) {
-               mlog_errno(ret);
-               goto out_commit;
-       }
-
-       memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize -
-              offsetof(struct ocfs2_xattr_block, xb_attrs));
-
-       xb->xb_flags = cpu_to_le16(xb_flags & ~OCFS2_XATTR_INDEXED);
-
-       ocfs2_journal_dirty(handle, xs->xattr_bh);
-
-out_commit:
-       ocfs2_commit_trans(osb, handle);
-out:
-       return ret;
-}
-
 /*
  * ocfs2_xattr_block_set()
  *
@@ -1947,8 +1906,6 @@ out:
        }
 
        ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs);
-       if (!ret && xblk->xb_attrs.xb_root.xt_list.l_next_free_rec == 0)
-               ret = ocfs2_restore_xattr_block(inode, xs);
 
 end:
 
@@ -2080,18 +2037,6 @@ cleanup:
        return ret;
 }
 
-static inline u32 ocfs2_xattr_hash_by_name(struct inode *inode,
-                                          int name_index,
-                                          const char *suffix_name)
-{
-       struct xattr_handler *handler = ocfs2_xattr_handler(name_index);
-       char *prefix = handler->prefix;
-       int prefix_len = strlen(handler->prefix);
-
-       return ocfs2_xattr_name_hash(inode, prefix, prefix_len,
-                                    (char *)suffix_name, strlen(suffix_name));
-}
-
 /*
  * Find the xattr extent rec which may contains name_hash.
  * e_cpos will be the first name hash of the xattr rec.
@@ -2205,9 +2150,8 @@ static int ocfs2_find_xe_in_bucket(struct inode *inode,
                        break;
                }
 
-               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                                      header_bh->b_blocknr + block_off,
-                                      &name_bh, OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_block(inode, header_bh->b_blocknr + block_off,
+                                      &name_bh);
                if (ret) {
                        mlog_errno(ret);
                        break;
@@ -2258,8 +2202,7 @@ static int ocfs2_xattr_bucket_find(struct inode *inode,
        u32 last_hash;
        u64 blkno;
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno,
-                              &bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, p_blkno, &bh);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -2275,8 +2218,7 @@ static int ocfs2_xattr_bucket_find(struct inode *inode,
 
                blkno = p_blkno + bucket * blk_per_bucket;
 
-               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
-                                      &bh, OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_block(inode, blkno, &bh);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -2291,9 +2233,12 @@ static int ocfs2_xattr_bucket_find(struct inode *inode,
 
                /*
                 * Check whether the hash of the last entry in our
-                * bucket is larger than the search one.
+                * bucket is larger than the search one. for an empty
+                * bucket, the last one is also the first one.
                 */
-               xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1];
+               if (xh->xh_count)
+                       xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1];
+
                last_hash = le32_to_cpu(xe->xe_name_hash);
 
                /* record lower_bh which may be the insert place. */
@@ -2345,10 +2290,9 @@ static int ocfs2_xattr_bucket_find(struct inode *inode,
                 * If we have found the xattr enty, read all the blocks in
                 * this bucket.
                 */
-               ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb),
-                                       xs->bucket.bhs[0]->b_blocknr + 1,
+               ret = ocfs2_read_blocks(inode, xs->bucket.bhs[0]->b_blocknr + 1,
                                        blk_per_bucket - 1, &xs->bucket.bhs[1],
-                                       OCFS2_BH_CACHED, inode);
+                                       0);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -2379,7 +2323,7 @@ static int ocfs2_xattr_index_block_find(struct inode *inode,
        struct ocfs2_extent_list *el = &xb_root->xt_list;
        u64 p_blkno = 0;
        u32 first_hash, num_clusters = 0;
-       u32 name_hash = ocfs2_xattr_hash_by_name(inode, name_index, name);
+       u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name));
 
        if (le16_to_cpu(el->l_next_free_rec) == 0)
                return -ENODATA;
@@ -2397,7 +2341,8 @@ static int ocfs2_xattr_index_block_find(struct inode *inode,
        BUG_ON(p_blkno == 0 || num_clusters == 0 || first_hash > name_hash);
 
        mlog(0, "find xattr extent rec %u clusters from %llu, the first hash "
-            "in the rec is %u\n", num_clusters, p_blkno, first_hash);
+            "in the rec is %u\n", num_clusters, (unsigned long long)p_blkno,
+            first_hash);
 
        ret = ocfs2_xattr_bucket_find(inode, name_index, name, name_hash,
                                      p_blkno, first_hash, num_clusters, xs);
@@ -2421,12 +2366,11 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode,
        memset(&bucket, 0, sizeof(bucket));
 
        mlog(0, "iterating xattr buckets in %u clusters starting from %llu\n",
-            clusters, blkno);
+            clusters, (unsigned long long)blkno);
 
        for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) {
-               ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb),
-                                       blkno, blk_per_bucket,
-                                       bucket.bhs, OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket,
+                                       bucket.bhs, 0);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -2440,7 +2384,9 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode,
                if (i == 0)
                        num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets);
 
-               mlog(0, "iterating xattr bucket %llu\n", blkno);
+               mlog(0, "iterating xattr bucket %llu, first hash %u\n",
+                    (unsigned long long)blkno,
+                    le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash));
                if (func) {
                        ret = func(inode, &bucket, para);
                        if (ret) {
@@ -2464,6 +2410,7 @@ out:
 struct ocfs2_xattr_tree_list {
        char *buffer;
        size_t buffer_size;
+       size_t result;
 };
 
 static int ocfs2_xattr_bucket_get_name_value(struct inode *inode,
@@ -2489,17 +2436,17 @@ static int ocfs2_list_xattr_bucket(struct inode *inode,
                                   struct ocfs2_xattr_bucket *bucket,
                                   void *para)
 {
-       int ret = 0;
+       int ret = 0, type;
        struct ocfs2_xattr_tree_list *xl = (struct ocfs2_xattr_tree_list *)para;
-       size_t size;
        int i, block_off, new_offset;
+       const char *prefix, *name;
 
        for (i = 0 ; i < le16_to_cpu(bucket->xh->xh_count); i++) {
                struct ocfs2_xattr_entry *entry = &bucket->xh->xh_entries[i];
-               struct xattr_handler *handler =
-                       ocfs2_xattr_handler(ocfs2_xattr_get_type(entry));
+               type = ocfs2_xattr_get_type(entry);
+               prefix = ocfs2_xattr_prefix(type);
 
-               if (handler) {
+               if (prefix) {
                        ret = ocfs2_xattr_bucket_get_name_value(inode,
                                                                bucket->xh,
                                                                i,
@@ -2507,16 +2454,16 @@ static int ocfs2_list_xattr_bucket(struct inode *inode,
                                                                &new_offset);
                        if (ret)
                                break;
-                       size = handler->list(inode, xl->buffer, xl->buffer_size,
-                                            bucket->bhs[block_off]->b_data +
-                                            new_offset,
-                                            entry->xe_name_len);
-                       if (xl->buffer) {
-                               if (size > xl->buffer_size)
-                                       return -ERANGE;
-                               xl->buffer += size;
-                       }
-                       xl->buffer_size -= size;
+
+                       name = (const char *)bucket->bhs[block_off]->b_data +
+                               new_offset;
+                       ret = ocfs2_xattr_list_entry(xl->buffer,
+                                                    xl->buffer_size,
+                                                    &xl->result,
+                                                    prefix, name,
+                                                    entry->xe_name_len);
+                       if (ret)
+                               break;
                }
        }
 
@@ -2535,6 +2482,7 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
        struct ocfs2_xattr_tree_list xl = {
                .buffer = buffer,
                .buffer_size = buffer_size,
+               .result = 0,
        };
 
        if (le16_to_cpu(el->l_next_free_rec) == 0)
@@ -2562,7 +2510,7 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
                name_hash = e_cpos - 1;
        }
 
-       ret = buffer_size - xl.buffer_size;
+       ret = xl.result;
 out:
        return ret;
 }
@@ -2688,18 +2636,18 @@ static int ocfs2_xattr_update_xattr_search(struct inode *inode,
 
        if (!xs->not_found) {
                if (OCFS2_XATTR_BUCKET_SIZE != blocksize) {
-                       ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb),
+                       ret = ocfs2_read_blocks(inode,
                                        xs->bucket.bhs[0]->b_blocknr + 1,
                                        blk_per_bucket - 1, &xs->bucket.bhs[1],
-                                       OCFS2_BH_CACHED, inode);
+                                       0);
                        if (ret) {
                                mlog_errno(ret);
                                return ret;
                        }
 
-                       i = xs->here - old_xh->xh_entries;
-                       xs->here = &xs->header->xh_entries[i];
                }
+               i = xs->here - old_xh->xh_entries;
+               xs->here = &xs->header->xh_entries[i];
        }
 
        return ret;
@@ -2773,7 +2721,8 @@ static int ocfs2_xattr_create_index_block(struct inode *inode,
         */
        blkno = ocfs2_clusters_to_blocks(inode->i_sb, bit_off);
 
-       mlog(0, "allocate 1 cluster from %llu to xattr block\n", blkno);
+       mlog(0, "allocate 1 cluster from %llu to xattr block\n",
+            (unsigned long long)blkno);
 
        xh_bh = sb_getblk(inode->i_sb, blkno);
        if (!xh_bh) {
@@ -2815,7 +2764,11 @@ static int ocfs2_xattr_create_index_block(struct inode *inode,
        if (data_bh)
                ocfs2_journal_dirty(handle, data_bh);
 
-       ocfs2_xattr_update_xattr_search(inode, xs, xb_bh, xh_bh);
+       ret = ocfs2_xattr_update_xattr_search(inode, xs, xb_bh, xh_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
 
        /* Change from ocfs2_xattr_header to ocfs2_xattr_tree_root */
        memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize -
@@ -2885,7 +2838,6 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode,
        u64 blkno = bucket->bhs[0]->b_blocknr;
        u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
        u16 xh_free_start;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        size_t blocksize = inode->i_sb->s_blocksize;
        handle_t *handle;
        struct buffer_head **bhs;
@@ -2896,8 +2848,7 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode,
        if (!bhs)
                return -ENOMEM;
 
-       ret = ocfs2_read_blocks(osb, blkno, blk_per_bucket, bhs,
-                               OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, bhs, 0);
        if (ret)
                goto out;
 
@@ -2940,8 +2891,8 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode,
 
        mlog(0, "adjust xattr bucket in %llu, count = %u, "
             "xh_free_start = %u, xh_name_value_len = %u.\n",
-            blkno, le16_to_cpu(xh->xh_count), xh_free_start,
-            le16_to_cpu(xh->xh_name_value_len));
+            (unsigned long long)blkno, le16_to_cpu(xh->xh_count),
+            xh_free_start, le16_to_cpu(xh->xh_name_value_len));
 
        /*
         * sort all the entries by their offset.
@@ -3057,7 +3008,7 @@ static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode,
        prev_blkno += (num_clusters - 1) * bpc + bpc / 2;
 
        mlog(0, "move half of xattrs in cluster %llu to %llu\n",
-            prev_blkno, new_blkno);
+            (unsigned long long)prev_blkno, (unsigned long long)new_blkno);
 
        /*
         * We need to update the 1st half of the new cluster and
@@ -3097,8 +3048,7 @@ static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode,
                        goto out;
                }
 
-               ret = ocfs2_read_block(osb, prev_blkno,
-                                      &old_bh, OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_block(inode, prev_blkno, &old_bh);
                if (ret < 0) {
                        mlog_errno(ret);
                        brelse(new_bh);
@@ -3151,9 +3101,8 @@ static int ocfs2_read_xattr_bucket(struct inode *inode,
        u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
 
        if (!new)
-               return ocfs2_read_blocks(OCFS2_SB(inode->i_sb), blkno,
-                                        blk_per_bucket, bhs,
-                                        OCFS2_BH_CACHED, inode);
+               return ocfs2_read_blocks(inode, blkno,
+                                        blk_per_bucket, bhs, 0);
 
        for (i = 0; i < blk_per_bucket; i++) {
                bhs[i] = sb_getblk(inode->i_sb, blkno + i);
@@ -3169,26 +3118,74 @@ static int ocfs2_read_xattr_bucket(struct inode *inode,
 }
 
 /*
- * Move half num of the xattrs in old bucket(blk) to new bucket(new_blk).
+ * Find the suitable pos when we divide a bucket into 2.
+ * We have to make sure the xattrs with the same hash value exist
+ * in the same bucket.
+ *
+ * If this ocfs2_xattr_header covers more than one hash value, find a
+ * place where the hash value changes.  Try to find the most even split.
+ * The most common case is that all entries have different hash values,
+ * and the first check we make will find a place to split.
+ */
+static int ocfs2_xattr_find_divide_pos(struct ocfs2_xattr_header *xh)
+{
+       struct ocfs2_xattr_entry *entries = xh->xh_entries;
+       int count = le16_to_cpu(xh->xh_count);
+       int delta, middle = count / 2;
+
+       /*
+        * We start at the middle.  Each step gets farther away in both
+        * directions.  We therefore hit the change in hash value
+        * nearest to the middle.  Note that this loop does not execute for
+        * count < 2.
+        */
+       for (delta = 0; delta < middle; delta++) {
+               /* Let's check delta earlier than middle */
+               if (cmp_xe(&entries[middle - delta - 1],
+                          &entries[middle - delta]))
+                       return middle - delta;
+
+               /* For even counts, don't walk off the end */
+               if ((middle + delta + 1) == count)
+                       continue;
+
+               /* Now try delta past middle */
+               if (cmp_xe(&entries[middle + delta],
+                          &entries[middle + delta + 1]))
+                       return middle + delta + 1;
+       }
+
+       /* Every entry had the same hash */
+       return count;
+}
+
+/*
+ * Move some xattrs in old bucket(blk) to new bucket(new_blk).
  * first_hash will record the 1st hash of the new bucket.
+ *
+ * Normally half of the xattrs will be moved.  But we have to make
+ * sure that the xattrs with the same hash value are stored in the
+ * same bucket. If all the xattrs in this bucket have the same hash
+ * value, the new bucket will be initialized as an empty one and the
+ * first_hash will be initialized as (hash_value+1).
  */
-static int ocfs2_half_xattr_bucket(struct inode *inode,
-                                  handle_t *handle,
-                                  u64 blk,
-                                  u64 new_blk,
-                                  u32 *first_hash,
-                                  int new_bucket_head)
+static int ocfs2_divide_xattr_bucket(struct inode *inode,
+                                   handle_t *handle,
+                                   u64 blk,
+                                   u64 new_blk,
+                                   u32 *first_hash,
+                                   int new_bucket_head)
 {
        int ret, i;
-       u16 count, start, len, name_value_len, xe_len, name_offset;
+       int count, start, len, name_value_len = 0, xe_len, name_offset = 0;
        u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
        struct buffer_head **s_bhs, **t_bhs = NULL;
        struct ocfs2_xattr_header *xh;
        struct ocfs2_xattr_entry *xe;
        int blocksize = inode->i_sb->s_blocksize;
 
-       mlog(0, "move half of xattrs from bucket %llu to %llu\n",
-            blk, new_blk);
+       mlog(0, "move some of xattrs from bucket %llu to %llu\n",
+            (unsigned long long)blk, (unsigned long long)new_blk);
 
        s_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS);
        if (!s_bhs)
@@ -3221,21 +3218,44 @@ static int ocfs2_half_xattr_bucket(struct inode *inode,
 
        for (i = 0; i < blk_per_bucket; i++) {
                ret = ocfs2_journal_access(handle, inode, t_bhs[i],
-                                          OCFS2_JOURNAL_ACCESS_CREATE);
+                                          new_bucket_head ?
+                                          OCFS2_JOURNAL_ACCESS_CREATE :
+                                          OCFS2_JOURNAL_ACCESS_WRITE);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
                }
        }
 
+       xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data;
+       count = le16_to_cpu(xh->xh_count);
+       start = ocfs2_xattr_find_divide_pos(xh);
+
+       if (start == count) {
+               xe = &xh->xh_entries[start-1];
+
+               /*
+                * initialized a new empty bucket here.
+                * The hash value is set as one larger than
+                * that of the last entry in the previous bucket.
+                */
+               for (i = 0; i < blk_per_bucket; i++)
+                       memset(t_bhs[i]->b_data, 0, blocksize);
+
+               xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data;
+               xh->xh_free_start = cpu_to_le16(blocksize);
+               xh->xh_entries[0].xe_name_hash = xe->xe_name_hash;
+               le32_add_cpu(&xh->xh_entries[0].xe_name_hash, 1);
+
+               goto set_num_buckets;
+       }
+
        /* copy the whole bucket to the new first. */
        for (i = 0; i < blk_per_bucket; i++)
                memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize);
 
        /* update the new bucket. */
        xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data;
-       count = le16_to_cpu(xh->xh_count);
-       start = count / 2;
 
        /*
         * Calculate the total name/value len and xh_free_start for
@@ -3292,6 +3312,7 @@ static int ocfs2_half_xattr_bucket(struct inode *inode,
                        xh->xh_free_start = xe->xe_name_offset;
        }
 
+set_num_buckets:
        /* set xh->xh_num_buckets for the new xh. */
        if (new_bucket_head)
                xh->xh_num_buckets = cpu_to_le16(1);
@@ -3309,9 +3330,13 @@ static int ocfs2_half_xattr_bucket(struct inode *inode,
                *first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
 
        /*
-        * Now only update the 1st block of the old bucket.
-        * Please note that the entry has been sorted already above.
+        * Now only update the 1st block of the old bucket.  If we
+        * just added a new empty bucket, there is no need to modify
+        * it.
         */
+       if (start == count)
+               goto out;
+
        xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data;
        memset(&xh->xh_entries[start], 0,
               sizeof(struct ocfs2_xattr_entry) * (count - start));
@@ -3359,7 +3384,8 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode,
        BUG_ON(s_blkno == t_blkno);
 
        mlog(0, "cp bucket %llu to %llu, target is %d\n",
-            s_blkno, t_blkno, t_is_new);
+            (unsigned long long)s_blkno, (unsigned long long)t_blkno,
+            t_is_new);
 
        s_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket,
                        GFP_NOFS);
@@ -3383,6 +3409,8 @@ static int ocfs2_cp_xattr_bucket(struct inode *inode,
 
        for (i = 0; i < blk_per_bucket; i++) {
                ret = ocfs2_journal_access(handle, inode, t_bhs[i],
+                                          t_is_new ?
+                                          OCFS2_JOURNAL_ACCESS_CREATE :
                                           OCFS2_JOURNAL_ACCESS_WRITE);
                if (ret)
                        goto out;
@@ -3429,7 +3457,8 @@ static int ocfs2_cp_xattr_cluster(struct inode *inode,
        struct ocfs2_xattr_header *xh;
        u64 to_blk_start = to_blk;
 
-       mlog(0, "cp xattrs from cluster %llu to %llu\n", src_blk, to_blk);
+       mlog(0, "cp xattrs from cluster %llu to %llu\n",
+            (unsigned long long)src_blk, (unsigned long long)to_blk);
 
        /*
         * We need to update the new cluster and 1 more for the update of
@@ -3468,7 +3497,7 @@ static int ocfs2_cp_xattr_cluster(struct inode *inode,
        ocfs2_journal_dirty(handle, first_bh);
 
        /* update the new bucket header. */
-       ret = ocfs2_read_block(osb, to_blk_start, &bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, to_blk_start, &bh);
        if (ret < 0) {
                mlog_errno(ret);
                goto out;
@@ -3494,15 +3523,15 @@ out:
 }
 
 /*
- * Move half of the xattrs in this cluster to the new cluster.
+ * Move some xattrs in this cluster to the new cluster.
  * This function should only be called when bucket size == cluster size.
  * Otherwise ocfs2_mv_xattr_bucket_cross_cluster should be used instead.
  */
-static int ocfs2_half_xattr_cluster(struct inode *inode,
-                                   handle_t *handle,
-                                   u64 prev_blk,
-                                   u64 new_blk,
-                                   u32 *first_hash)
+static int ocfs2_divide_xattr_cluster(struct inode *inode,
+                                     handle_t *handle,
+                                     u64 prev_blk,
+                                     u64 new_blk,
+                                     u32 *first_hash)
 {
        u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
        int ret, credits = 2 * blk_per_bucket;
@@ -3516,8 +3545,8 @@ static int ocfs2_half_xattr_cluster(struct inode *inode,
        }
 
        /* Move half of the xattr in start_blk to the next bucket. */
-       return  ocfs2_half_xattr_bucket(inode, handle, prev_blk,
-                                       new_blk, first_hash, 1);
+       return  ocfs2_divide_xattr_bucket(inode, handle, prev_blk,
+                                         new_blk, first_hash, 1);
 }
 
 /*
@@ -3560,7 +3589,8 @@ static int ocfs2_adjust_xattr_cross_cluster(struct inode *inode,
        int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
 
        mlog(0, "adjust xattrs from cluster %llu len %u to %llu\n",
-            prev_blk, prev_clusters, new_blk);
+            (unsigned long long)prev_blk, prev_clusters,
+            (unsigned long long)new_blk);
 
        if (ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)) > 1)
                ret = ocfs2_mv_xattr_bucket_cross_cluster(inode,
@@ -3579,9 +3609,9 @@ static int ocfs2_adjust_xattr_cross_cluster(struct inode *inode,
                                                     last_blk, new_blk,
                                                     v_start);
                else {
-                       ret = ocfs2_half_xattr_cluster(inode, handle,
-                                                      last_blk, new_blk,
-                                                      v_start);
+                       ret = ocfs2_divide_xattr_cluster(inode, handle,
+                                                        last_blk, new_blk,
+                                                        v_start);
 
                        if ((*header_bh)->b_blocknr == last_blk && extend)
                                *extend = 0;
@@ -3630,9 +3660,9 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode,
        mlog(0, "Add new xattr cluster for %llu, previous xattr hash = %u, "
             "previous xattr blkno = %llu\n",
             (unsigned long long)OCFS2_I(inode)->ip_blkno,
-            prev_cpos, prev_blkno);
+            prev_cpos, (unsigned long long)prev_blkno);
 
-       ocfs2_get_xattr_tree_extent_tree(&et, inode, root_bh);
+       ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh);
 
        ret = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
                                    &data_ac, &meta_ac);
@@ -3704,8 +3734,20 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode,
                }
        }
 
+       if (handle->h_buffer_credits < credits) {
+               /*
+                * The journal has been restarted before, and don't
+                * have enough space for the insertion, so extend it
+                * here.
+                */
+               ret = ocfs2_extend_trans(handle, credits);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto leave;
+               }
+       }
        mlog(0, "Insert %u clusters at block %llu for xattr at %u\n",
-            num_bits, block, v_start);
+            num_bits, (unsigned long long)block, v_start);
        ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block,
                                  num_bits, 0, meta_ac);
        if (ret < 0) {
@@ -3727,7 +3769,6 @@ leave:
        if (meta_ac)
                ocfs2_free_alloc_context(meta_ac);
 
-       ocfs2_put_extent_tree(&et);
        return ret;
 }
 
@@ -3751,7 +3792,7 @@ static int ocfs2_extend_xattr_bucket(struct inode *inode,
        u16 bucket = le16_to_cpu(first_xh->xh_num_buckets);
 
        mlog(0, "extend xattr bucket in %llu, xattr extend rec starting "
-            "from %llu, len = %u\n", start_blk,
+            "from %llu, len = %u\n", (unsigned long long)start_blk,
             (unsigned long long)first_bh->b_blocknr, num_clusters);
 
        BUG_ON(bucket >= num_buckets);
@@ -3787,8 +3828,8 @@ static int ocfs2_extend_xattr_bucket(struct inode *inode,
        }
 
        /* Move half of the xattr in start_blk to the next bucket. */
-       ret = ocfs2_half_xattr_bucket(inode, handle, start_blk,
-                                     start_blk + blk_per_bucket, NULL, 0);
+       ret = ocfs2_divide_xattr_bucket(inode, handle, start_blk,
+                                       start_blk + blk_per_bucket, NULL, 0);
 
        le16_add_cpu(&first_xh->xh_num_buckets, 1);
        ocfs2_journal_dirty(handle, first_bh);
@@ -3844,8 +3885,7 @@ static int ocfs2_add_new_xattr_bucket(struct inode *inode,
                goto out;
        }
 
-       ret = ocfs2_read_block(osb, p_blkno,
-                              &first_bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, p_blkno, &first_bh);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -3894,8 +3934,6 @@ static inline char *ocfs2_xattr_bucket_get_val(struct inode *inode,
 
 /*
  * Handle the normal xattr set, including replace, delete and new.
- * When the bucket is empty, "is_empty" is set and the caller can
- * free this bucket.
  *
  * Note: "local" indicates the real data's locality. So we can't
  * just its bucket locality by its length.
@@ -3904,8 +3942,7 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
                                         struct ocfs2_xattr_info *xi,
                                         struct ocfs2_xattr_search *xs,
                                         u32 name_hash,
-                                        int local,
-                                        int *is_empty)
+                                        int local)
 {
        struct ocfs2_xattr_entry *last, *xe;
        int name_len = strlen(xi->name);
@@ -3958,14 +3995,23 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
                        ocfs2_xattr_set_local(xe, local);
                        return;
                } else {
-                       /* Remove the old entry. */
+                       /*
+                        * Remove the old entry if there is more than one.
+                        * We don't remove the last entry so that we can
+                        * use it to indicate the hash value of the empty
+                        * bucket.
+                        */
                        last -= 1;
-                       memmove(xe, xe + 1,
-                               (void *)last - (void *)xe);
-                       memset(last, 0, sizeof(struct ocfs2_xattr_entry));
                        le16_add_cpu(&xh->xh_count, -1);
-                       if (xh->xh_count == 0 && is_empty)
-                               *is_empty = 1;
+                       if (xh->xh_count) {
+                               memmove(xe, xe + 1,
+                                       (void *)last - (void *)xe);
+                               memset(last, 0,
+                                      sizeof(struct ocfs2_xattr_entry));
+                       } else
+                               xh->xh_free_start =
+                                       cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
+
                        return;
                }
        } else {
@@ -3973,7 +4019,7 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
                int low = 0, high = count - 1, tmp;
                struct ocfs2_xattr_entry *tmp_xe;
 
-               while (low <= high) {
+               while (low <= high && count) {
                        tmp = (low + high) / 2;
                        tmp_xe = &xh->xh_entries[tmp];
 
@@ -3982,8 +4028,10 @@ static void ocfs2_xattr_set_entry_normal(struct inode *inode,
                        else if (name_hash <
                                 le32_to_cpu(tmp_xe->xe_name_hash))
                                high = tmp - 1;
-                       else
+                       else {
+                               low = tmp;
                                break;
+                       }
                }
 
                xe = &xh->xh_entries[low];
@@ -4067,8 +4115,7 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode,
                                           struct ocfs2_xattr_info *xi,
                                           struct ocfs2_xattr_search *xs,
                                           u32 name_hash,
-                                          int local,
-                                          int *bucket_empty)
+                                          int local)
 {
        int i, ret;
        handle_t *handle = NULL;
@@ -4080,10 +4127,10 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode,
             (unsigned long long)xs->bucket.bhs[0]->b_blocknr);
 
        if (!xs->bucket.bhs[1]) {
-               ret = ocfs2_read_blocks(osb,
+               ret = ocfs2_read_blocks(inode,
                                        xs->bucket.bhs[0]->b_blocknr + 1,
                                        blk_per_bucket - 1, &xs->bucket.bhs[1],
-                                       OCFS2_BH_CACHED, inode);
+                                       0);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -4107,8 +4154,7 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode,
                }
        }
 
-       ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash,
-                                    local, bucket_empty);
+       ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, local);
 
        /*Only dirty the blocks we have touched in set xattr. */
        ret = ocfs2_xattr_bucket_handle_journal(inode, handle, xs,
@@ -4131,7 +4177,7 @@ static int ocfs2_xattr_value_update_size(struct inode *inode,
        handle_t *handle = NULL;
 
        handle = ocfs2_start_trans(osb, 1);
-       if (handle == NULL) {
+       if (IS_ERR(handle)) {
                ret = -ENOMEM;
                mlog_errno(ret);
                goto out;
@@ -4190,8 +4236,7 @@ static int ocfs2_xattr_bucket_value_truncate(struct inode *inode,
        BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize);
        value_blk += header_bh->b_blocknr;
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), value_blk,
-                              &value_bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, value_blk, &value_bh);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -4257,69 +4302,6 @@ static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode,
        return __ocfs2_xattr_set_value_outside(inode, xv, val, value_len);
 }
 
-/*
- * Remove the xattr bucket pointed by bucket_bh.
- * All the buckets after it in the same xattr extent rec will be
- * move forward one by one.
- */
-static int ocfs2_rm_xattr_bucket(struct inode *inode,
-                                struct buffer_head *first_bh,
-                                struct ocfs2_xattr_bucket *bucket)
-{
-       int ret = 0, credits;
-       struct ocfs2_xattr_header *xh =
-                               (struct ocfs2_xattr_header *)first_bh->b_data;
-       u16 bucket_num = le16_to_cpu(xh->xh_num_buckets);
-       u64 end, start = bucket->bhs[0]->b_blocknr;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-       handle_t *handle;
-       u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
-
-       end = first_bh->b_blocknr + (bucket_num - 1) * blk_per_bucket;
-
-       mlog(0, "rm xattr bucket %llu\n", start);
-       /*
-        * We need to update the first xattr_header and all the buckets starting
-        * from start in this xattr rec.
-        *
-        * XXX: Should we empty the old last bucket here?
-        */
-       credits = 1 + end - start;
-       handle = ocfs2_start_trans(osb, credits);
-       if (IS_ERR(handle)) {
-               ret = PTR_ERR(handle);
-               mlog_errno(ret);
-               return ret;
-       }
-
-       ret = ocfs2_journal_access(handle, inode, first_bh,
-                                  OCFS2_JOURNAL_ACCESS_WRITE);
-       if (ret) {
-               mlog_errno(ret);
-               goto out_commit;
-       }
-
-
-       while (start < end) {
-               ret = ocfs2_cp_xattr_bucket(inode, handle,
-                                           start + blk_per_bucket,
-                                           start, 0);
-               if (ret) {
-                       mlog_errno(ret);
-                       goto out_commit;
-               }
-               start += blk_per_bucket;
-       }
-
-       /* update the first_bh. */
-       xh->xh_num_buckets = cpu_to_le16(bucket_num - 1);
-       ocfs2_journal_dirty(handle, first_bh);
-
-out_commit:
-       ocfs2_commit_trans(osb, handle);
-       return ret;
-}
-
 static int ocfs2_rm_xattr_cluster(struct inode *inode,
                                  struct buffer_head *root_bh,
                                  u64 blkno,
@@ -4336,7 +4318,7 @@ static int ocfs2_rm_xattr_cluster(struct inode *inode,
        struct ocfs2_cached_dealloc_ctxt dealloc;
        struct ocfs2_extent_tree et;
 
-       ocfs2_get_xattr_tree_extent_tree(&et, inode, root_bh);
+       ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh);
 
        ocfs2_init_dealloc_ctxt(&dealloc);
 
@@ -4347,7 +4329,6 @@ static int ocfs2_rm_xattr_cluster(struct inode *inode,
 
        ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
        if (ret) {
-               ocfs2_put_extent_tree(&et);
                mlog_errno(ret);
                return ret;
        }
@@ -4363,7 +4344,7 @@ static int ocfs2_rm_xattr_cluster(struct inode *inode,
        }
 
        handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS);
-       if (handle == NULL) {
+       if (IS_ERR(handle)) {
                ret = -ENOMEM;
                mlog_errno(ret);
                goto out;
@@ -4407,58 +4388,6 @@ out:
 
        ocfs2_run_deallocs(osb, &dealloc);
 
-       ocfs2_put_extent_tree(&et);
-       return ret;
-}
-
-/*
- * Free the xattr bucket indicated by xs->bucket and if all the buckets
- * in the clusters is free, free the clusters also.
- */
-static int ocfs2_xattr_bucket_shrink(struct inode *inode,
-                                    struct ocfs2_xattr_info *xi,
-                                    struct ocfs2_xattr_search *xs,
-                                    u32 name_hash)
-{
-       int ret;
-       u32 e_cpos, num_clusters;
-       u64 p_blkno;
-       struct buffer_head *first_bh = NULL;
-       struct ocfs2_xattr_header *first_xh;
-       struct ocfs2_xattr_block *xb =
-                       (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
-
-       BUG_ON(xs->header->xh_count != 0);
-
-       ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno,
-                                 &e_cpos, &num_clusters,
-                                 &xb->xb_attrs.xb_root.xt_list);
-       if (ret) {
-               mlog_errno(ret);
-               return ret;
-       }
-
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno,
-                              &first_bh, OCFS2_BH_CACHED, inode);
-       if (ret) {
-               mlog_errno(ret);
-               return ret;
-       }
-
-       ret = ocfs2_rm_xattr_bucket(inode, first_bh, &xs->bucket);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
-       }
-
-       first_xh = (struct ocfs2_xattr_header *)first_bh->b_data;
-       if (first_xh->xh_num_buckets == 0)
-               ret = ocfs2_rm_xattr_cluster(inode, xs->xattr_bh,
-                                            p_blkno, e_cpos,
-                                            num_clusters);
-
-out:
-       brelse(first_bh);
        return ret;
 }
 
@@ -4513,12 +4442,12 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode,
                                     struct ocfs2_xattr_info *xi,
                                     struct ocfs2_xattr_search *xs)
 {
-       int ret, local = 1, bucket_empty = 0;
+       int ret, local = 1;
        size_t value_len;
        char *val = (char *)xi->value;
        struct ocfs2_xattr_entry *xe = xs->here;
-       u32 name_hash = ocfs2_xattr_hash_by_name(inode,
-                                                xi->name_index, xi->name);
+       u32 name_hash = ocfs2_xattr_name_hash(inode, xi->name,
+                                             strlen(xi->name));
 
        if (!xs->not_found && !ocfs2_xattr_is_local(xe)) {
                /*
@@ -4559,34 +4488,29 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode,
                xi->value_len = OCFS2_XATTR_ROOT_SIZE;
        }
 
-       ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash,
-                                             local, &bucket_empty);
+       ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash, local);
        if (ret) {
                mlog_errno(ret);
                goto out;
        }
 
-       if (value_len > OCFS2_XATTR_INLINE_SIZE) {
-               /* allocate the space now for the outside block storage. */
-               ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
-                                                          value_len);
-               if (ret) {
-                       mlog_errno(ret);
+       if (value_len <= OCFS2_XATTR_INLINE_SIZE)
+               goto out;
 
-                       if (xs->not_found) {
-                               /*
-                                * We can't allocate enough clusters for outside
-                                * storage and we have allocated xattr already,
-                                * so need to remove it.
-                                */
-                               ocfs2_xattr_bucket_remove_xs(inode, xs);
-                       }
-                       goto out;
+       /* allocate the space now for the outside block storage. */
+       ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
+                                                  value_len);
+       if (ret) {
+               mlog_errno(ret);
+
+               if (xs->not_found) {
+                       /*
+                        * We can't allocate enough clusters for outside
+                        * storage and we have allocated xattr already,
+                        * so need to remove it.
+                        */
+                       ocfs2_xattr_bucket_remove_xs(inode, xs);
                }
-       } else {
-               if (bucket_empty)
-                       ret = ocfs2_xattr_bucket_shrink(inode, xi,
-                                                       xs, name_hash);
                goto out;
        }
 
@@ -4596,11 +4520,21 @@ out:
        return ret;
 }
 
-/* check whether the xattr bucket is filled up with the same hash value. */
+/*
+ * check whether the xattr bucket is filled up with the same hash value.
+ * If we want to insert the xattr with the same hash, return -ENOSPC.
+ * If we want to insert a xattr with different hash value, go ahead
+ * and ocfs2_divide_xattr_bucket will handle this.
+ */
 static int ocfs2_check_xattr_bucket_collision(struct inode *inode,
-                                             struct ocfs2_xattr_bucket *bucket)
+                                             struct ocfs2_xattr_bucket *bucket,
+                                             const char *name)
 {
        struct ocfs2_xattr_header *xh = bucket->xh;
+       u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name));
+
+       if (name_hash != le32_to_cpu(xh->xh_entries[0].xe_name_hash))
+               return 0;
 
        if (xh->xh_entries[le16_to_cpu(xh->xh_count) - 1].xe_name_hash ==
            xh->xh_entries[0].xe_name_hash) {
@@ -4723,7 +4657,9 @@ try_again:
                 * one bucket's worth, so check it here whether we need to
                 * add a new bucket for the insert.
                 */
-               ret = ocfs2_check_xattr_bucket_collision(inode, &xs->bucket);
+               ret = ocfs2_check_xattr_bucket_collision(inode,
+                                                        &xs->bucket,
+                                                        xi->name);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -4830,3 +4766,103 @@ static int ocfs2_delete_xattr_index_block(struct inode *inode,
 out:
        return ret;
 }
+
+/*
+ * 'trusted' attributes support
+ */
+static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list,
+                                      size_t list_size, const char *name,
+                                      size_t name_len)
+{
+       const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
+       const size_t total_len = prefix_len + name_len + 1;
+
+       if (list && total_len <= list_size) {
+               memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
+               memcpy(list + prefix_len, name, name_len);
+               list[prefix_len + name_len] = '\0';
+       }
+       return total_len;
+}
+
+static int ocfs2_xattr_trusted_get(struct inode *inode, const char *name,
+                                  void *buffer, size_t size)
+{
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED, name,
+                              buffer, size);
+}
+
+static int ocfs2_xattr_trusted_set(struct inode *inode, const char *name,
+                                  const void *value, size_t size, int flags)
+{
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED, name, value,
+                              size, flags);
+}
+
+struct xattr_handler ocfs2_xattr_trusted_handler = {
+       .prefix = XATTR_TRUSTED_PREFIX,
+       .list   = ocfs2_xattr_trusted_list,
+       .get    = ocfs2_xattr_trusted_get,
+       .set    = ocfs2_xattr_trusted_set,
+};
+
+/*
+ * 'user' attributes support
+ */
+static size_t ocfs2_xattr_user_list(struct inode *inode, char *list,
+                                   size_t list_size, const char *name,
+                                   size_t name_len)
+{
+       const size_t prefix_len = XATTR_USER_PREFIX_LEN;
+       const size_t total_len = prefix_len + name_len + 1;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+               return 0;
+
+       if (list && total_len <= list_size) {
+               memcpy(list, XATTR_USER_PREFIX, prefix_len);
+               memcpy(list + prefix_len, name, name_len);
+               list[prefix_len + name_len] = '\0';
+       }
+       return total_len;
+}
+
+static int ocfs2_xattr_user_get(struct inode *inode, const char *name,
+                               void *buffer, size_t size)
+{
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+               return -EOPNOTSUPP;
+       return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_USER, name,
+                              buffer, size);
+}
+
+static int ocfs2_xattr_user_set(struct inode *inode, const char *name,
+                               const void *value, size_t size, int flags)
+{
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+               return -EOPNOTSUPP;
+
+       return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER, name, value,
+                              size, flags);
+}
+
+struct xattr_handler ocfs2_xattr_user_handler = {
+       .prefix = XATTR_USER_PREFIX,
+       .list   = ocfs2_xattr_user_list,
+       .get    = ocfs2_xattr_user_get,
+       .set    = ocfs2_xattr_user_set,
+};