]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/ocfs2/xattr.c
Linux 2.6.28-rc4
[linux-2.6-omap-h63xx.git] / fs / ocfs2 / xattr.c
index 9c3d4dc3e2eac1ef8a3b69fde0a0b69049bed376..802c41492214ca928cd30448deb972bbbbe6a05f 100644 (file)
@@ -37,6 +37,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>
@@ -134,32 +137,24 @@ 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 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 +175,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 +201,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 +297,6 @@ leave:
                goto restart_all;
        }
 
-       ocfs2_put_extent_tree(&et);
        return status;
 }
 
@@ -325,11 +314,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 +373,6 @@ out:
        if (meta_ac)
                ocfs2_free_alloc_context(meta_ac);
 
-       ocfs2_put_extent_tree(&et);
        return ret;
 }
 
@@ -465,33 +452,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,9 +537,7 @@ 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;
@@ -662,8 +670,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;
@@ -754,9 +761,7 @@ static int ocfs2_xattr_block_get(struct inode *inode,
 
        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);
+       ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
        if (ret < 0) {
                mlog_errno(ret);
                return ret;
@@ -912,8 +917,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;
@@ -1339,8 +1343,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 +1434,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 +1495,83 @@ 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;
+       }
+
+       /*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 (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+       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 +1579,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 +1597,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 +1621,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 +1634,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,9 +1766,7 @@ 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;
@@ -2080,18 +2094,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 +2207,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 +2259,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 +2275,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 +2290,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 +2347,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 +2380,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;
@@ -2424,9 +2425,8 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode,
             clusters, 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 +2440,8 @@ 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", blkno,
+                    le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash));
                if (func) {
                        ret = func(inode, &bucket, para);
                        if (ret) {
@@ -2464,6 +2465,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 +2491,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 +2509,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 +2537,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 +2565,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,10 +2691,10 @@ 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;
@@ -2885,7 +2888,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 +2898,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;
 
@@ -3097,8 +3098,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 +3151,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);
@@ -3468,7 +3467,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;
@@ -3632,7 +3631,7 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode,
             (unsigned long long)OCFS2_I(inode)->ip_blkno,
             prev_cpos, 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,6 +3703,18 @@ 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);
        ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block,
@@ -3727,7 +3738,6 @@ leave:
        if (meta_ac)
                ocfs2_free_alloc_context(meta_ac);
 
-       ocfs2_put_extent_tree(&et);
        return ret;
 }
 
@@ -3844,8 +3854,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 +3903,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 +3911,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 +3964,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 +3988,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 +3997,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 +4084,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 +4096,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 +4123,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,
@@ -4190,8 +4205,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 +4271,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 +4287,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 +4298,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;
        }
@@ -4407,58 +4357,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 +4411,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 +4457,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;
        }
 
@@ -4830,3 +4723,110 @@ static int ocfs2_delete_xattr_index_block(struct inode *inode,
 out:
        return ret;
 }
+
+/*
+ * 'trusted' attributes support
+ */
+
+#define XATTR_TRUSTED_PREFIX "trusted."
+
+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 = sizeof(XATTR_TRUSTED_PREFIX) - 1;
+       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
+ */
+
+#define XATTR_USER_PREFIX "user."
+
+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 = sizeof(XATTR_USER_PREFIX) - 1;
+       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,
+};