}
 
 /*
- * Copy one xattr cluster from src_blk to to_blk.
- * The to_blk will become the first bucket header of the cluster, so its
- * xh_num_buckets will be initialized as the bucket num in the cluster.
+ * src_blk points to the last cluster of an existing extent.  to_blk
+ * points to a newly allocated extent.  We copy the cluster over to the
+ * new extent, initializing its xh_num_buckets.  The old extent's
+ * xh_num_buckets shrinks by the same amount.
  */
 static int ocfs2_cp_xattr_cluster(struct inode *inode,
                                  handle_t *handle,
        int i, ret, credits;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+       int blks_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
        int num_buckets = ocfs2_xattr_buckets_per_cluster(osb);
-       struct buffer_head *bh = NULL;
-       struct ocfs2_xattr_header *xh;
-       u64 to_blk_start = to_blk;
+       struct ocfs2_xattr_bucket *old_first, *new_first;
 
        mlog(0, "cp xattrs from cluster %llu to %llu\n",
             (unsigned long long)src_blk, (unsigned long long)to_blk);
 
+       /* The first bucket of the original extent */
+       old_first = ocfs2_xattr_bucket_new(inode);
+       /* The first bucket of the new extent */
+       new_first = ocfs2_xattr_bucket_new(inode);
+       if (!old_first || !new_first) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_read_xattr_bucket(old_first, first_bh->b_blocknr);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
        /*
-        * We need to update the new cluster and 1 more for the update of
-        * the 1st bucket of the previous extent rec.
+        * We need to update the first bucket of the old extent and the
+        * entire first cluster of the new extent.
         */
-       credits = bpc + 1 + handle->h_buffer_credits;
+       credits = blks_per_bucket + bpc + handle->h_buffer_credits;
        ret = ocfs2_extend_trans(handle, credits);
        if (ret) {
                mlog_errno(ret);
                goto out;
        }
 
-       ret = ocfs2_journal_access(handle, inode, first_bh,
-                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       ret = ocfs2_xattr_bucket_journal_access(handle, old_first,
+                                               OCFS2_JOURNAL_ACCESS_WRITE);
        if (ret) {
                mlog_errno(ret);
                goto out;
 
        for (i = 0; i < num_buckets; i++) {
                ret = ocfs2_cp_xattr_bucket(inode, handle,
-                                           src_blk, to_blk, 1);
+                                           src_blk + (i * blks_per_bucket),
+                                           to_blk + (i * blks_per_bucket),
+                                           1);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
                }
-
-               src_blk += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
-               to_blk += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
        }
 
-       /* update the old bucket header. */
-       xh = (struct ocfs2_xattr_header *)first_bh->b_data;
-       le16_add_cpu(&xh->xh_num_buckets, -num_buckets);
-
-       ocfs2_journal_dirty(handle, first_bh);
-
-       /* update the new bucket header. */
-       ret = ocfs2_read_block(inode, to_blk_start, &bh, NULL);
-       if (ret < 0) {
+       /*
+        * Get the new bucket ready before we dirty anything
+        * (This actually shouldn't fail, because we already dirtied
+        * it once in ocfs2_cp_xattr_bucket()).
+        */
+       ret = ocfs2_read_xattr_bucket(new_first, to_blk);
+       if (ret) {
                mlog_errno(ret);
                goto out;
        }
-
-       ret = ocfs2_journal_access(handle, inode, bh,
-                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       ret = ocfs2_xattr_bucket_journal_access(handle, new_first,
+                                               OCFS2_JOURNAL_ACCESS_WRITE);
        if (ret) {
                mlog_errno(ret);
                goto out;
        }
 
-       xh = (struct ocfs2_xattr_header *)bh->b_data;
-       xh->xh_num_buckets = cpu_to_le16(num_buckets);
+       /* Now update the headers */
+       le16_add_cpu(&bucket_xh(old_first)->xh_num_buckets, -num_buckets);
+       ocfs2_xattr_bucket_journal_dirty(handle, old_first);
 
-       ocfs2_journal_dirty(handle, bh);
+       bucket_xh(new_first)->xh_num_buckets = cpu_to_le16(num_buckets);
+       ocfs2_xattr_bucket_journal_dirty(handle, new_first);
 
        if (first_hash)
-               *first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
+               *first_hash = le32_to_cpu(bucket_xh(new_first)->xh_entries[0].xe_name_hash);
+
 out:
-       brelse(bh);
+       ocfs2_xattr_bucket_free(new_first);
+       ocfs2_xattr_bucket_free(old_first);
        return ret;
 }