]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-extent-tree-operation-for-x.patch
Move xen patchset to new version's subdir.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.suse / ocfs2-Add-extent-tree-operation-for-x.patch
diff --git a/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-extent-tree-operation-for-x.patch b/src/patches/suse-2.6.27.31/patches.suse/ocfs2-Add-extent-tree-operation-for-x.patch
new file mode 100644 (file)
index 0000000..8515ee3
--- /dev/null
@@ -0,0 +1,992 @@
+From: Tao Ma <tao.ma@oracle.com>
+Subject: [PATCH 07/16] ocfs2: Add extent tree operation for xattr value btrees
+Patch-mainline: 2.6.28?
+References: FATE302067 
+
+Add some thin wrappers around ocfs2_insert_extent() for each of the 3
+different btree types, ocfs2_inode_insert_extent(),
+ocfs2_xattr_value_insert_extent() and ocfs2_xattr_tree_insert_extent(). The
+last is for the xattr index btree, which will be used in a followup patch.
+
+All the old callers in file.c etc will call ocfs2_dinode_insert_extent(),
+while the other two handle the xattr issue. And the init of extent tree are
+handled by these functions.
+
+When storing xattr value which is too large, we will allocate some clusters
+for it and here ocfs2_extent_list and ocfs2_extent_rec will also be used. In
+order to re-use the b-tree operation code, a new parameter named "private"
+is added into ocfs2_extent_tree and it is used to indicate the root of
+ocfs2_exent_list. The reason is that we can't deduce the root from the
+buffer_head now. It may be in an inode, an ocfs2_xattr_block or even worse,
+in any place in an ocfs2_xattr_bucket.
+
+Signed-off-by: Tao Ma <tao.ma@oracle.com>
+Signed-off-by: Mark Fasheh <mfasheh@suse.com>
+---
+ fs/ocfs2/Makefile          |    3 +-
+ fs/ocfs2/alloc.c           |  184 +++++++++++++++++++++-----
+ fs/ocfs2/alloc.h           |   42 ++++--
+ fs/ocfs2/aops.c            |    5 +-
+ fs/ocfs2/cluster/masklog.c |    1 +
+ fs/ocfs2/cluster/masklog.h |    1 +
+ fs/ocfs2/dir.c             |   11 +-
+ fs/ocfs2/extent_map.c      |   60 +++++++++
+ fs/ocfs2/extent_map.h      |    3 +
+ fs/ocfs2/file.c            |    9 +-
+ fs/ocfs2/suballoc.c        |    5 +-
+ fs/ocfs2/suballoc.h        |    3 +-
+ fs/ocfs2/xattr.c           |  305 ++++++++++++++++++++++++++++++++++++++++++++
+ 13 files changed, 568 insertions(+), 64 deletions(-)
+ create mode 100644 fs/ocfs2/xattr.c
+
+Index: linux-2.6.26/fs/ocfs2/Makefile
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/Makefile
++++ linux-2.6.26/fs/ocfs2/Makefile
+@@ -34,7 +34,8 @@ ocfs2-objs := \
+       symlink.o               \
+       sysfile.o               \
+       uptodate.o              \
+-      ver.o
++      ver.o                   \
++      xattr.o                 \
+ ocfs2_stackglue-objs := stackglue.o
+ ocfs2_stack_o2cb-objs := stack_o2cb.o
+Index: linux-2.6.26/fs/ocfs2/alloc.c
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/alloc.c
++++ linux-2.6.26/fs/ocfs2/alloc.c
+@@ -78,6 +78,7 @@ struct ocfs2_extent_tree {
+       struct ocfs2_extent_tree_operations *eops;
+       struct buffer_head *root_bh;
+       struct ocfs2_extent_list *root_el;
++      void *private;
+ };
+ static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et,
+@@ -136,9 +137,50 @@ static struct ocfs2_extent_tree_operatio
+       .sanity_check           = ocfs2_dinode_sanity_check,
+ };
++static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et,
++                                            u64 blkno)
++{
++      struct ocfs2_xattr_value_root *xv =
++              (struct ocfs2_xattr_value_root *)et->private;
++
++      xv->xr_last_eb_blk = cpu_to_le64(blkno);
++}
++
++static u64 ocfs2_xattr_value_get_last_eb_blk(struct ocfs2_extent_tree *et)
++{
++      struct ocfs2_xattr_value_root *xv =
++              (struct ocfs2_xattr_value_root *) et->private;
++
++      return le64_to_cpu(xv->xr_last_eb_blk);
++}
++
++static void ocfs2_xattr_value_update_clusters(struct inode *inode,
++                                            struct ocfs2_extent_tree *et,
++                                            u32 clusters)
++{
++      struct ocfs2_xattr_value_root *xv =
++              (struct ocfs2_xattr_value_root *)et->private;
++
++      le32_add_cpu(&xv->xr_clusters, clusters);
++}
++
++static int ocfs2_xattr_value_sanity_check(struct inode *inode,
++                                        struct ocfs2_extent_tree *et)
++{
++      return 0;
++}
++
++static struct ocfs2_extent_tree_operations ocfs2_xattr_et_ops = {
++      .set_last_eb_blk        = ocfs2_xattr_value_set_last_eb_blk,
++      .get_last_eb_blk        = ocfs2_xattr_value_get_last_eb_blk,
++      .update_clusters        = ocfs2_xattr_value_update_clusters,
++      .sanity_check           = ocfs2_xattr_value_sanity_check,
++};
++
+ static struct ocfs2_extent_tree*
+        ocfs2_new_extent_tree(struct buffer_head *bh,
+-                             enum ocfs2_extent_tree_type et_type)
++                             enum ocfs2_extent_tree_type et_type,
++                             void *private)
+ {
+       struct ocfs2_extent_tree *et;
+@@ -149,12 +191,16 @@ static struct ocfs2_extent_tree*
+       et->type = et_type;
+       get_bh(bh);
+       et->root_bh = bh;
++      et->private = private;
+-      /* current we only support dinode extent. */
+-      BUG_ON(et->type != OCFS2_DINODE_EXTENT);
+       if (et_type == OCFS2_DINODE_EXTENT) {
+               et->root_el = &((struct ocfs2_dinode *)bh->b_data)->id2.i_list;
+               et->eops = &ocfs2_dinode_et_ops;
++      } else if (et_type == OCFS2_XATTR_VALUE_EXTENT) {
++              struct ocfs2_xattr_value_root *xv =
++                      (struct ocfs2_xattr_value_root *) private;
++              et->root_el = &xv->xr_list;
++              et->eops = &ocfs2_xattr_et_ops;
+       }
+       return et;
+@@ -495,7 +541,8 @@ struct ocfs2_merge_ctxt {
+ int ocfs2_num_free_extents(struct ocfs2_super *osb,
+                          struct inode *inode,
+                          struct buffer_head *root_bh,
+-                         enum ocfs2_extent_tree_type type)
++                         enum ocfs2_extent_tree_type type,
++                         void *private)
+ {
+       int retval;
+       struct ocfs2_extent_list *el = NULL;
+@@ -517,6 +564,12 @@ int ocfs2_num_free_extents(struct ocfs2_
+               if (fe->i_last_eb_blk)
+                       last_eb_blk = le64_to_cpu(fe->i_last_eb_blk);
+               el = &fe->id2.i_list;
++      } else if (type == OCFS2_XATTR_VALUE_EXTENT) {
++              struct ocfs2_xattr_value_root *xv =
++                      (struct ocfs2_xattr_value_root *) private;
++
++              last_eb_blk = le64_to_cpu(xv->xr_last_eb_blk);
++              el = &xv->xr_list;
+       }
+       if (last_eb_blk) {
+@@ -4218,33 +4271,25 @@ out:
+  *
+  * The caller needs to update fe->i_clusters
+  */
+-int ocfs2_insert_extent(struct ocfs2_super *osb,
+-                      handle_t *handle,
+-                      struct inode *inode,
+-                      struct buffer_head *root_bh,
+-                      u32 cpos,
+-                      u64 start_blk,
+-                      u32 new_clusters,
+-                      u8 flags,
+-                      struct ocfs2_alloc_context *meta_ac,
+-                      enum ocfs2_extent_tree_type et_type)
++static int ocfs2_insert_extent(struct ocfs2_super *osb,
++                             handle_t *handle,
++                             struct inode *inode,
++                             struct buffer_head *root_bh,
++                             u32 cpos,
++                             u64 start_blk,
++                             u32 new_clusters,
++                             u8 flags,
++                             struct ocfs2_alloc_context *meta_ac,
++                             struct ocfs2_extent_tree *et)
+ {
+       int status;
+       int uninitialized_var(free_records);
+       struct buffer_head *last_eb_bh = NULL;
+       struct ocfs2_insert_type insert = {0, };
+       struct ocfs2_extent_rec rec;
+-      struct ocfs2_extent_tree *et = NULL;
+       BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
+-      et = ocfs2_new_extent_tree(root_bh, et_type);
+-      if (!et) {
+-              status = -ENOMEM;
+-              mlog_errno(status);
+-              goto bail;
+-      }
+-
+       mlog(0, "add %u clusters at position %u to inode %llu\n",
+            new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno);
+@@ -4296,9 +4341,68 @@ bail:
+       if (last_eb_bh)
+               brelse(last_eb_bh);
++      mlog_exit(status);
++      return status;
++}
++
++int ocfs2_dinode_insert_extent(struct ocfs2_super *osb,
++                             handle_t *handle,
++                             struct inode *inode,
++                             struct buffer_head *root_bh,
++                             u32 cpos,
++                             u64 start_blk,
++                             u32 new_clusters,
++                             u8 flags,
++                             struct ocfs2_alloc_context *meta_ac)
++{
++      int status;
++      struct ocfs2_extent_tree *et = NULL;
++
++      et = ocfs2_new_extent_tree(root_bh, OCFS2_DINODE_EXTENT, NULL);
++      if (!et) {
++              status = -ENOMEM;
++              mlog_errno(status);
++              goto bail;
++      }
++
++      status = ocfs2_insert_extent(osb, handle, inode, root_bh,
++                                   cpos, start_blk, new_clusters,
++                                   flags, meta_ac, et);
++
+       if (et)
+               ocfs2_free_extent_tree(et);
+-      mlog_exit(status);
++bail:
++      return status;
++}
++
++int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb,
++                                  handle_t *handle,
++                                  struct inode *inode,
++                                  struct buffer_head *root_bh,
++                                  u32 cpos,
++                                  u64 start_blk,
++                                  u32 new_clusters,
++                                  u8 flags,
++                                  struct ocfs2_alloc_context *meta_ac,
++                                  void *private)
++{
++      int status;
++      struct ocfs2_extent_tree *et = NULL;
++
++      et = ocfs2_new_extent_tree(root_bh, OCFS2_XATTR_VALUE_EXTENT, private);
++      if (!et) {
++              status = -ENOMEM;
++              mlog_errno(status);
++              goto bail;
++      }
++
++      status = ocfs2_insert_extent(osb, handle, inode, root_bh,
++                                   cpos, start_blk, new_clusters,
++                                   flags, meta_ac, et);
++
++      if (et)
++              ocfs2_free_extent_tree(et);
++bail:
+       return status;
+ }
+@@ -4320,7 +4424,8 @@ int ocfs2_add_clusters_in_btree(struct o
+                               struct ocfs2_alloc_context *data_ac,
+                               struct ocfs2_alloc_context *meta_ac,
+                               enum ocfs2_alloc_restarted *reason_ret,
+-                              enum ocfs2_extent_tree_type type)
++                              enum ocfs2_extent_tree_type type,
++                              void *private)
+ {
+       int status = 0;
+       int free_extents;
+@@ -4334,7 +4439,8 @@ int ocfs2_add_clusters_in_btree(struct o
+       if (mark_unwritten)
+               flags = OCFS2_EXT_UNWRITTEN;
+-      free_extents = ocfs2_num_free_extents(osb, inode, root_bh, type);
++      free_extents = ocfs2_num_free_extents(osb, inode, root_bh, type,
++                                            private);
+       if (free_extents < 0) {
+               status = free_extents;
+               mlog_errno(status);
+@@ -4381,9 +4487,16 @@ int ocfs2_add_clusters_in_btree(struct o
+       block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
+       mlog(0, "Allocating %u clusters at block %u for inode %llu\n",
+            num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
+-      status = ocfs2_insert_extent(osb, handle, inode, root_bh,
+-                                   *logical_offset, block, num_bits,
+-                                   flags, meta_ac, type);
++      if (type == OCFS2_DINODE_EXTENT)
++              status = ocfs2_dinode_insert_extent(osb, handle, inode, root_bh,
++                                                  *logical_offset, block,
++                                                  num_bits, flags, meta_ac);
++      else
++              status = ocfs2_xattr_value_insert_extent(osb, handle,
++                                                       inode, root_bh,
++                                                       *logical_offset,
++                                                       block, num_bits, flags,
++                                                       meta_ac, private);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+@@ -4664,7 +4777,8 @@ int ocfs2_mark_extent_written(struct ino
+                             handle_t *handle, u32 cpos, u32 len, u32 phys,
+                             struct ocfs2_alloc_context *meta_ac,
+                             struct ocfs2_cached_dealloc_ctxt *dealloc,
+-                            enum ocfs2_extent_tree_type et_type)
++                            enum ocfs2_extent_tree_type et_type,
++                            void *private)
+ {
+       int ret, index;
+       u64 start_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys);
+@@ -4685,7 +4799,7 @@ int ocfs2_mark_extent_written(struct ino
+               goto out;
+       }
+-      et = ocfs2_new_extent_tree(root_bh, et_type);
++      et = ocfs2_new_extent_tree(root_bh, et_type, private);
+       if (!et) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+@@ -4973,7 +5087,8 @@ int ocfs2_remove_extent(struct inode *in
+                       u32 cpos, u32 len, handle_t *handle,
+                       struct ocfs2_alloc_context *meta_ac,
+                       struct ocfs2_cached_dealloc_ctxt *dealloc,
+-                      enum ocfs2_extent_tree_type et_type)
++                      enum ocfs2_extent_tree_type et_type,
++                      void *private)
+ {
+       int ret, index;
+       u32 rec_range, trunc_range;
+@@ -4982,7 +5097,7 @@ int ocfs2_remove_extent(struct inode *in
+       struct ocfs2_path *path = NULL;
+       struct ocfs2_extent_tree *et = NULL;
+-      et = ocfs2_new_extent_tree(root_bh, et_type);
++      et = ocfs2_new_extent_tree(root_bh, et_type, private);
+       if (!et) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+@@ -6617,9 +6732,8 @@ int ocfs2_convert_inline_data_to_extents
+                * this proves to be false, we could always re-build
+                * the in-inode data from our pages.
+                */
+-              ret = ocfs2_insert_extent(osb, handle, inode, di_bh,
+-                                        0, block, 1, 0,
+-                                        NULL, OCFS2_DINODE_EXTENT);
++              ret = ocfs2_dinode_insert_extent(osb, handle, inode, di_bh,
++                                               0, block, 1, 0, NULL);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+Index: linux-2.6.26/fs/ocfs2/alloc.h
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/alloc.h
++++ linux-2.6.26/fs/ocfs2/alloc.h
+@@ -28,19 +28,29 @@
+ enum ocfs2_extent_tree_type {
+       OCFS2_DINODE_EXTENT = 0,
++      OCFS2_XATTR_VALUE_EXTENT,
+ };
+ struct ocfs2_alloc_context;
+-int ocfs2_insert_extent(struct ocfs2_super *osb,
+-                      handle_t *handle,
+-                      struct inode *inode,
+-                      struct buffer_head *root_bh,
+-                      u32 cpos,
+-                      u64 start_blk,
+-                      u32 new_clusters,
+-                      u8 flags,
+-                      struct ocfs2_alloc_context *meta_ac,
+-                      enum ocfs2_extent_tree_type et_type);
++int ocfs2_dinode_insert_extent(struct ocfs2_super *osb,
++                             handle_t *handle,
++                             struct inode *inode,
++                             struct buffer_head *root_bh,
++                             u32 cpos,
++                             u64 start_blk,
++                             u32 new_clusters,
++                             u8 flags,
++                             struct ocfs2_alloc_context *meta_ac);
++int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb,
++                                  handle_t *handle,
++                                  struct inode *inode,
++                                  struct buffer_head *root_bh,
++                                  u32 cpos,
++                                  u64 start_blk,
++                                  u32 new_clusters,
++                                  u8 flags,
++                                  struct ocfs2_alloc_context *meta_ac,
++                                  void *private);
+ enum ocfs2_alloc_restarted {
+       RESTART_NONE = 0,
+       RESTART_TRANS,
+@@ -57,22 +67,26 @@ int ocfs2_add_clusters_in_btree(struct o
+                               struct ocfs2_alloc_context *data_ac,
+                               struct ocfs2_alloc_context *meta_ac,
+                               enum ocfs2_alloc_restarted *reason_ret,
+-                              enum ocfs2_extent_tree_type type);
++                              enum ocfs2_extent_tree_type type,
++                              void *private);
+ struct ocfs2_cached_dealloc_ctxt;
+ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh,
+                             handle_t *handle, u32 cpos, u32 len, u32 phys,
+                             struct ocfs2_alloc_context *meta_ac,
+                             struct ocfs2_cached_dealloc_ctxt *dealloc,
+-                            enum ocfs2_extent_tree_type et_type);
++                            enum ocfs2_extent_tree_type et_type,
++                            void *private);
+ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh,
+                       u32 cpos, u32 len, handle_t *handle,
+                       struct ocfs2_alloc_context *meta_ac,
+                       struct ocfs2_cached_dealloc_ctxt *dealloc,
+-                      enum ocfs2_extent_tree_type et_type);
++                      enum ocfs2_extent_tree_type et_type,
++                      void *private);
+ int ocfs2_num_free_extents(struct ocfs2_super *osb,
+                          struct inode *inode,
+                          struct buffer_head *root_bh,
+-                         enum ocfs2_extent_tree_type et_type);
++                         enum ocfs2_extent_tree_type et_type,
++                         void *private);
+ /*
+  * how many new metadata chunks would an allocation need at maximum?
+Index: linux-2.6.26/fs/ocfs2/aops.c
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/aops.c
++++ linux-2.6.26/fs/ocfs2/aops.c
+@@ -1279,7 +1279,7 @@ static int ocfs2_write_cluster(struct ad
+               ret = ocfs2_mark_extent_written(inode, wc->w_di_bh,
+                                               wc->w_handle, cpos, 1, phys,
+                                               meta_ac, &wc->w_dealloc,
+-                                              OCFS2_DINODE_EXTENT);
++                                              OCFS2_DINODE_EXTENT, NULL);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+@@ -1721,7 +1721,8 @@ int ocfs2_write_begin_nolock(struct addr
+               ret = ocfs2_lock_allocators(inode, wc->w_di_bh, &di->id2.i_list,
+                                           clusters_to_alloc, extents_to_split,
+-                                          &data_ac, &meta_ac);
++                                          &data_ac, &meta_ac,
++                                          OCFS2_DINODE_EXTENT, NULL);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+Index: linux-2.6.26/fs/ocfs2/cluster/masklog.c
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/cluster/masklog.c
++++ linux-2.6.26/fs/ocfs2/cluster/masklog.c
+@@ -109,6 +109,7 @@ static struct mlog_attribute mlog_attrs[
+       define_mask(CONN),
+       define_mask(QUORUM),
+       define_mask(EXPORT),
++      define_mask(XATTR),
+       define_mask(ERROR),
+       define_mask(NOTICE),
+       define_mask(KTHREAD),
+Index: linux-2.6.26/fs/ocfs2/cluster/masklog.h
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/cluster/masklog.h
++++ linux-2.6.26/fs/ocfs2/cluster/masklog.h
+@@ -112,6 +112,7 @@
+ #define ML_CONN               0x0000000004000000ULL /* net connection management */
+ #define ML_QUORUM     0x0000000008000000ULL /* net connection quorum */
+ #define ML_EXPORT     0x0000000010000000ULL /* ocfs2 export operations */
++#define ML_XATTR      0x0000000020000000ULL /* ocfs2 extended attributes */
+ /* bits that are infrequently given and frequently matched in the high word */
+ #define ML_ERROR      0x0000000100000000ULL /* sent to KERN_ERR */
+ #define ML_NOTICE     0x0000000200000000ULL /* setn to KERN_NOTICE */
+Index: linux-2.6.26/fs/ocfs2/dir.c
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/dir.c
++++ linux-2.6.26/fs/ocfs2/dir.c
+@@ -1305,8 +1305,8 @@ static int ocfs2_expand_inline_dir(struc
+        * This should never fail as our extent list is empty and all
+        * related blocks have been journaled already.
+        */
+-      ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0,
+-                                NULL, OCFS2_DINODE_EXTENT);
++      ret = ocfs2_dinode_insert_extent(osb, handle, dir, di_bh, 0, blkno,
++                                       len, 0, NULL);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+@@ -1337,8 +1337,8 @@ static int ocfs2_expand_inline_dir(struc
+               }
+               blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
+-              ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno,
+-                                        len, 0, NULL, OCFS2_DINODE_EXTENT);
++              ret = ocfs2_dinode_insert_extent(osb, handle, dir, di_bh, 1,
++                                               blkno, len, 0, NULL);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out_commit;
+@@ -1482,7 +1482,8 @@ static int ocfs2_extend_dir(struct ocfs2
+               spin_unlock(&OCFS2_I(dir)->ip_lock);
+               num_free_extents = ocfs2_num_free_extents(osb, dir,
+                                                         parent_fe_bh,
+-                                                        OCFS2_DINODE_EXTENT);
++                                                        OCFS2_DINODE_EXTENT,
++                                                        NULL);
+               if (num_free_extents < 0) {
+                       status = num_free_extents;
+                       mlog_errno(status);
+Index: linux-2.6.26/fs/ocfs2/extent_map.c
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/extent_map.c
++++ linux-2.6.26/fs/ocfs2/extent_map.c
+@@ -373,6 +373,66 @@ out:
+       return ret;
+ }
++int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
++                           u32 *p_cluster, u32 *num_clusters,
++                           struct ocfs2_extent_list *el)
++{
++      int ret = 0, i;
++      struct buffer_head *eb_bh = NULL;
++      struct ocfs2_extent_block *eb;
++      struct ocfs2_extent_rec *rec;
++      u32 coff;
++
++      if (el->l_tree_depth) {
++              ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
++              if (ret) {
++                      mlog_errno(ret);
++                      goto out;
++              }
++
++              eb = (struct ocfs2_extent_block *) eb_bh->b_data;
++              el = &eb->h_list;
++
++              if (el->l_tree_depth) {
++                      ocfs2_error(inode->i_sb,
++                                  "Inode %lu has non zero tree depth in "
++                                  "xattr leaf block %llu\n", inode->i_ino,
++                                  (unsigned long long)eb_bh->b_blocknr);
++                      ret = -EROFS;
++                      goto out;
++              }
++      }
++
++      i = ocfs2_search_extent_list(el, v_cluster);
++      if (i == -1) {
++              ret = -EROFS;
++              mlog_errno(ret);
++              goto out;
++      } else {
++              rec = &el->l_recs[i];
++              BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
++
++              if (!rec->e_blkno) {
++                      ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
++                                  "record (%u, %u, 0) in xattr", inode->i_ino,
++                                  le32_to_cpu(rec->e_cpos),
++                                  ocfs2_rec_clusters(el, rec));
++                      ret = -EROFS;
++                      goto out;
++              }
++              coff = v_cluster - le32_to_cpu(rec->e_cpos);
++              *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb,
++                                                  le64_to_cpu(rec->e_blkno));
++              *p_cluster = *p_cluster + coff;
++              if (num_clusters)
++                      *num_clusters = ocfs2_rec_clusters(el, rec) - coff;
++      }
++out:
++      if (eb_bh)
++              brelse(eb_bh);
++      return ret;
++}
++
+ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
+                      u32 *p_cluster, u32 *num_clusters,
+                      unsigned int *extent_flags)
+Index: linux-2.6.26/fs/ocfs2/extent_map.h
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/extent_map.h
++++ linux-2.6.26/fs/ocfs2/extent_map.h
+@@ -50,4 +50,7 @@ int ocfs2_get_clusters(struct inode *ino
+ int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
+                               u64 *ret_count, unsigned int *extent_flags);
++int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
++                           u32 *p_cluster, u32 *num_clusters,
++                           struct ocfs2_extent_list *el);
+ #endif  /* _EXTENT_MAP_H */
+Index: linux-2.6.26/fs/ocfs2/file.c
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/file.c
++++ linux-2.6.26/fs/ocfs2/file.c
+@@ -515,7 +515,7 @@ int ocfs2_add_inode_data(struct ocfs2_su
+                                          clusters_to_add, mark_unwritten,
+                                          fe_bh, el, handle,
+                                          data_ac, meta_ac, reason_ret,
+-                                         OCFS2_DINODE_EXTENT);
++                                         OCFS2_DINODE_EXTENT, NULL);
+ }
+ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
+@@ -565,7 +565,7 @@ restart_all:
+            clusters_to_add);
+       status = ocfs2_lock_allocators(inode, bh, &fe->id2.i_list,
+                                      clusters_to_add, 0, &data_ac,
+-                                     &meta_ac);
++                                     &meta_ac, OCFS2_DINODE_EXTENT, NULL);
+       if (status) {
+               mlog_errno(status);
+               goto leave;
+@@ -1237,7 +1237,8 @@ static int __ocfs2_remove_inode_range(st
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       ret = ocfs2_lock_allocators(inode, di_bh, &di->id2.i_list,
+-                                  0, 1, NULL, &meta_ac);
++                                  0, 1, NULL, &meta_ac,
++                                  OCFS2_DINODE_EXTENT, NULL);
+       if (ret) {
+               mlog_errno(ret);
+               return ret;
+@@ -1268,7 +1269,7 @@ static int __ocfs2_remove_inode_range(st
+       }
+       ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac,
+-                                dealloc, OCFS2_DINODE_EXTENT);
++                                dealloc, OCFS2_DINODE_EXTENT, NULL);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+Index: linux-2.6.26/fs/ocfs2/suballoc.c
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/suballoc.c
++++ linux-2.6.26/fs/ocfs2/suballoc.c
+@@ -1906,7 +1906,8 @@ int ocfs2_lock_allocators(struct inode *
+                         struct ocfs2_extent_list *root_el,
+                         u32 clusters_to_add, u32 extents_to_split,
+                         struct ocfs2_alloc_context **data_ac,
+-                        struct ocfs2_alloc_context **meta_ac)
++                        struct ocfs2_alloc_context **meta_ac,
++                        enum ocfs2_extent_tree_type type, void *private)
+ {
+       int ret = 0, num_free_extents;
+       unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split;
+@@ -1919,7 +1920,7 @@ int ocfs2_lock_allocators(struct inode *
+       BUG_ON(clusters_to_add != 0 && data_ac == NULL);
+       num_free_extents = ocfs2_num_free_extents(osb, inode, root_bh,
+-                                                OCFS2_DINODE_EXTENT);
++                                                type, private);
+       if (num_free_extents < 0) {
+               ret = num_free_extents;
+               mlog_errno(ret);
+Index: linux-2.6.26/fs/ocfs2/suballoc.h
+===================================================================
+--- linux-2.6.26.orig/fs/ocfs2/suballoc.h
++++ linux-2.6.26/fs/ocfs2/suballoc.h
+@@ -165,5 +165,6 @@ int ocfs2_lock_allocators(struct inode *
+                         struct ocfs2_extent_list *root_el,
+                         u32 clusters_to_add, u32 extents_to_split,
+                         struct ocfs2_alloc_context **data_ac,
+-                        struct ocfs2_alloc_context **meta_ac);
++                        struct ocfs2_alloc_context **meta_ac,
++                        enum ocfs2_extent_tree_type type, void *private);
+ #endif /* _CHAINALLOC_H_ */
+Index: linux-2.6.26/fs/ocfs2/xattr.c
+===================================================================
+--- /dev/null
++++ linux-2.6.26/fs/ocfs2/xattr.c
+@@ -0,0 +1,305 @@
++/* -*- mode: c; c-basic-offset: 8; -*-
++ * vim: noexpandtab sw=8 ts=8 sts=0:
++ *
++ * xattr.c
++ *
++ * Copyright (C) 2008 Oracle.  All rights reserved.
++ *
++ * 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.
++ *
++ * 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.
++ */
++
++#define MLOG_MASK_PREFIX ML_XATTR
++#include <cluster/masklog.h>
++
++#include "ocfs2.h"
++#include "alloc.h"
++#include "dlmglue.h"
++#include "file.h"
++#include "inode.h"
++#include "journal.h"
++#include "ocfs2_fs.h"
++#include "suballoc.h"
++#include "uptodate.h"
++#include "buffer_head_io.h"
++
++static int ocfs2_xattr_extend_allocation(struct inode *inode,
++                                       u32 clusters_to_add,
++                                       struct buffer_head *xattr_bh,
++                                       struct ocfs2_xattr_value_root *xv)
++{
++      int status = 0;
++      int restart_func = 0;
++      int credits = 0;
++      handle_t *handle = NULL;
++      struct ocfs2_alloc_context *data_ac = NULL;
++      struct ocfs2_alloc_context *meta_ac = NULL;
++      enum ocfs2_alloc_restarted why;
++      struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++      struct ocfs2_extent_list *root_el = &xv->xr_list;
++      u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters);
++
++      mlog(0, "(clusters_to_add for xattr= %u)\n", clusters_to_add);
++
++restart_all:
++
++      status = ocfs2_lock_allocators(inode, xattr_bh, root_el,
++                                     clusters_to_add, 0, &data_ac,
++                                     &meta_ac, OCFS2_XATTR_VALUE_EXTENT, xv);
++      if (status) {
++              mlog_errno(status);
++              goto leave;
++      }
++
++      credits = ocfs2_calc_extend_credits(osb->sb, root_el, clusters_to_add);
++      handle = ocfs2_start_trans(osb, credits);
++      if (IS_ERR(handle)) {
++              status = PTR_ERR(handle);
++              handle = NULL;
++              mlog_errno(status);
++              goto leave;
++      }
++
++restarted_transaction:
++      status = ocfs2_journal_access(handle, inode, xattr_bh,
++                                    OCFS2_JOURNAL_ACCESS_WRITE);
++      if (status < 0) {
++              mlog_errno(status);
++              goto leave;
++      }
++
++      prev_clusters = le32_to_cpu(xv->xr_clusters);
++      status = ocfs2_add_clusters_in_btree(osb,
++                                           inode,
++                                           &logical_start,
++                                           clusters_to_add,
++                                           0,
++                                           xattr_bh,
++                                           root_el,
++                                           handle,
++                                           data_ac,
++                                           meta_ac,
++                                           &why,
++                                           OCFS2_XATTR_VALUE_EXTENT,
++                                           xv);
++      if ((status < 0) && (status != -EAGAIN)) {
++              if (status != -ENOSPC)
++                      mlog_errno(status);
++              goto leave;
++      }
++
++      status = ocfs2_journal_dirty(handle, xattr_bh);
++      if (status < 0) {
++              mlog_errno(status);
++              goto leave;
++      }
++
++      clusters_to_add -= le32_to_cpu(xv->xr_clusters) - prev_clusters;
++
++      if (why != RESTART_NONE && clusters_to_add) {
++              if (why == RESTART_META) {
++                      mlog(0, "restarting function.\n");
++                      restart_func = 1;
++              } else {
++                      BUG_ON(why != RESTART_TRANS);
++
++                      mlog(0, "restarting transaction.\n");
++                      /* TODO: This can be more intelligent. */
++                      credits = ocfs2_calc_extend_credits(osb->sb,
++                                                          root_el,
++                                                          clusters_to_add);
++                      status = ocfs2_extend_trans(handle, credits);
++                      if (status < 0) {
++                              /* handle still has to be committed at
++                               * this point. */
++                              status = -ENOMEM;
++                              mlog_errno(status);
++                              goto leave;
++                      }
++                      goto restarted_transaction;
++              }
++      }
++
++leave:
++      if (handle) {
++              ocfs2_commit_trans(osb, handle);
++              handle = NULL;
++      }
++      if (data_ac) {
++              ocfs2_free_alloc_context(data_ac);
++              data_ac = NULL;
++      }
++      if (meta_ac) {
++              ocfs2_free_alloc_context(meta_ac);
++              meta_ac = NULL;
++      }
++      if ((!status) && restart_func) {
++              restart_func = 0;
++              goto restart_all;
++      }
++
++      return status;
++}
++
++static int __ocfs2_remove_xattr_range(struct inode *inode,
++                                    struct buffer_head *root_bh,
++                                    struct ocfs2_xattr_value_root *xv,
++                                    u32 cpos, u32 phys_cpos, u32 len,
++                                    struct ocfs2_cached_dealloc_ctxt *dealloc)
++{
++      int ret;
++      u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
++      struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++      struct inode *tl_inode = osb->osb_tl_inode;
++      handle_t *handle;
++      struct ocfs2_alloc_context *meta_ac = NULL;
++
++      ret = ocfs2_lock_allocators(inode, root_bh, &xv->xr_list,
++                                  0, 1, NULL, &meta_ac,
++                                  OCFS2_XATTR_VALUE_EXTENT, xv);
++      if (ret) {
++              mlog_errno(ret);
++              return ret;
++      }
++
++      mutex_lock(&tl_inode->i_mutex);
++
++      if (ocfs2_truncate_log_needs_flush(osb)) {
++              ret = __ocfs2_flush_truncate_log(osb);
++              if (ret < 0) {
++                      mlog_errno(ret);
++                      goto out;
++              }
++      }
++
++      handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS);
++      if (IS_ERR(handle)) {
++              ret = PTR_ERR(handle);
++              mlog_errno(ret);
++              goto out;
++      }
++
++      ret = ocfs2_journal_access(handle, inode, root_bh,
++                                 OCFS2_JOURNAL_ACCESS_WRITE);
++      if (ret) {
++              mlog_errno(ret);
++              goto out_commit;
++      }
++
++      ret = ocfs2_remove_extent(inode, root_bh, cpos, len, handle, meta_ac,
++                                dealloc, OCFS2_XATTR_VALUE_EXTENT, xv);
++      if (ret) {
++              mlog_errno(ret);
++              goto out_commit;
++      }
++
++      le32_add_cpu(&xv->xr_clusters, -len);
++
++      ret = ocfs2_journal_dirty(handle, root_bh);
++      if (ret) {
++              mlog_errno(ret);
++              goto out_commit;
++      }
++
++      ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len);
++      if (ret)
++              mlog_errno(ret);
++
++out_commit:
++      ocfs2_commit_trans(osb, handle);
++out:
++      mutex_unlock(&tl_inode->i_mutex);
++
++      if (meta_ac)
++              ocfs2_free_alloc_context(meta_ac);
++
++      return ret;
++}
++
++static int ocfs2_xattr_shrink_size(struct inode *inode,
++                                 u32 old_clusters,
++                                 u32 new_clusters,
++                                 struct buffer_head *root_bh,
++                                 struct ocfs2_xattr_value_root *xv)
++{
++      int ret = 0;
++      u32 trunc_len, cpos, phys_cpos, alloc_size;
++      u64 block;
++      struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
++      struct ocfs2_cached_dealloc_ctxt dealloc;
++
++      ocfs2_init_dealloc_ctxt(&dealloc);
++
++      if (old_clusters <= new_clusters)
++              return 0;
++
++      cpos = new_clusters;
++      trunc_len = old_clusters - new_clusters;
++      while (trunc_len) {
++              ret = ocfs2_xattr_get_clusters(inode, cpos, &phys_cpos,
++                                             &alloc_size, &xv->xr_list);
++              if (ret) {
++                      mlog_errno(ret);
++                      goto out;
++              }
++
++              if (alloc_size > trunc_len)
++                      alloc_size = trunc_len;
++
++              ret = __ocfs2_remove_xattr_range(inode, root_bh, xv, cpos,
++                                               phys_cpos, alloc_size,
++                                               &dealloc);
++              if (ret) {
++                      mlog_errno(ret);
++                      goto out;
++              }
++
++              block = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
++              ocfs2_remove_xattr_clusters_from_cache(inode, block,
++                                                     alloc_size);
++              cpos += alloc_size;
++              trunc_len -= alloc_size;
++      }
++
++out:
++      ocfs2_schedule_truncate_log_flush(osb, 1);
++      ocfs2_run_deallocs(osb, &dealloc);
++
++      return ret;
++}
++
++static int ocfs2_xattr_value_truncate(struct inode *inode,
++                                    struct buffer_head *root_bh,
++                                    struct ocfs2_xattr_value_root *xv,
++                                    int len)
++{
++      int ret;
++      u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, len);
++      u32 old_clusters = le32_to_cpu(xv->xr_clusters);
++
++      if (new_clusters == old_clusters)
++              return 0;
++
++      if (new_clusters > old_clusters)
++              ret = ocfs2_xattr_extend_allocation(inode,
++                                                  new_clusters - old_clusters,
++                                                  root_bh, xv);
++      else
++              ret = ocfs2_xattr_shrink_size(inode,
++                                            old_clusters, new_clusters,
++                                            root_bh, xv);
++
++      return ret;
++}