return ret;
 }
 
-static int ocfs2_xattr_value_update_size(struct inode *inode,
-                                        handle_t *handle,
-                                        struct buffer_head *xe_bh,
-                                        struct ocfs2_xattr_entry *xe,
-                                        u64 new_size)
-{
-       int ret;
-
-       ret = ocfs2_journal_access(handle, inode, xe_bh,
-                                  OCFS2_JOURNAL_ACCESS_WRITE);
-       if (ret < 0) {
-               mlog_errno(ret);
-               goto out;
-       }
-
-       xe->xe_value_size = cpu_to_le64(new_size);
-
-       ret = ocfs2_journal_dirty(handle, xe_bh);
-       if (ret < 0)
-               mlog_errno(ret);
-
-out:
-       return ret;
-}
-
 /*
  * Truncate the specified xe_off entry in xattr bucket.
  * bucket is indicated by header_bh and len is the new length.
  * Copy the new updated xe and xe_value_root to new_xe and new_xv if needed.
  */
 static int ocfs2_xattr_bucket_value_truncate(struct inode *inode,
-                                            struct buffer_head *header_bh,
+                                            struct ocfs2_xattr_bucket *bucket,
                                             int xe_off,
                                             int len,
                                             struct ocfs2_xattr_set_ctxt *ctxt)
        struct buffer_head *value_bh = NULL;
        struct ocfs2_xattr_value_root *xv;
        struct ocfs2_xattr_entry *xe;
-       struct ocfs2_xattr_header *xh =
-                       (struct ocfs2_xattr_header *)header_bh->b_data;
+       struct ocfs2_xattr_header *xh = bucket_xh(bucket);
        size_t blocksize = inode->i_sb->s_blocksize;
 
        xe = &xh->xh_entries[xe_off];
 
        /* We don't allow ocfs2_xattr_value to be stored in different block. */
        BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize);
-       value_blk += header_bh->b_blocknr;
 
-       ret = ocfs2_read_block(inode, value_blk, &value_bh, NULL);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
-       }
+       value_bh = bucket->bu_bhs[value_blk];
+       BUG_ON(!value_bh);
 
        xv = (struct ocfs2_xattr_value_root *)
                (value_bh->b_data + offset % blocksize);
 
-       mlog(0, "truncate %u in xattr bucket %llu to %d bytes.\n",
-            xe_off, (unsigned long long)header_bh->b_blocknr, len);
-       ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len, ctxt);
+       ret = ocfs2_xattr_bucket_journal_access(ctxt->handle, bucket,
+                                               OCFS2_JOURNAL_ACCESS_WRITE);
        if (ret) {
                mlog_errno(ret);
                goto out;
        }
 
-       ret = ocfs2_xattr_value_update_size(inode, ctxt->handle,
-                                           header_bh, xe, len);
+       /*
+        * From here on out we have to dirty the bucket.  The generic
+        * value calls only modify one of the bucket's bhs, but we need
+        * to send the bucket at once.  So if they error, they *could* have
+        * modified something.  We have to assume they did, and dirty
+        * the whole bucket.  This leaves us in a consistent state.
+        */
+       mlog(0, "truncate %u in xattr bucket %llu to %d bytes.\n",
+            xe_off, (unsigned long long)bucket_blkno(bucket), len);
+       ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len, ctxt);
        if (ret) {
                mlog_errno(ret);
-               goto out;
+               goto out_dirty;
        }
 
+       xe->xe_value_size = cpu_to_le64(len);
+
+out_dirty:
+       ocfs2_xattr_bucket_journal_dirty(ctxt->handle, bucket);
+
 out:
-       brelse(value_bh);
        return ret;
 }
 
        BUG_ON(!xs->bucket->bu_bhs[0] || !xe || ocfs2_xattr_is_local(xe));
 
        offset = xe - xh->xh_entries;
-       ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket->bu_bhs[0],
+       ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket,
                                                offset, len, ctxt);
        if (ret)
                mlog_errno(ret);
        struct ocfs2_xattr_entry *xe;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct ocfs2_xattr_set_ctxt ctxt = {NULL, NULL,};
+       int credits = ocfs2_remove_extent_credits(osb->sb) +
+               ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
 
        ocfs2_init_dealloc_ctxt(&ctxt.dealloc);
 
-       ctxt.handle = ocfs2_start_trans(osb,
-                                       ocfs2_remove_extent_credits(osb->sb));
+       ctxt.handle = ocfs2_start_trans(osb, credits);
        if (IS_ERR(ctxt.handle)) {
                ret = PTR_ERR(ctxt.handle);
                mlog_errno(ret);
                if (ocfs2_xattr_is_local(xe))
                        continue;
 
-               ret = ocfs2_xattr_bucket_value_truncate(inode,
-                                                       bucket->bu_bhs[0],
+               ret = ocfs2_xattr_bucket_value_truncate(inode, bucket,
                                                        i, 0, &ctxt);
                if (ret) {
                        mlog_errno(ret);