return 0;
 }
 
-static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
-                                           struct file *file,
-                                           loff_t pos, size_t count,
-                                           int *meta_level)
+static int ocfs2_inode_lock_for_extent_tree(struct inode *inode,
+                                           struct buffer_head **di_bh,
+                                           int meta_level,
+                                           int overwrite_io,
+                                           int write_sem,
+                                           int wait)
 {
-       int ret;
-       struct buffer_head *di_bh = NULL;
-       u32 cpos = pos >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
-       u32 clusters =
-               ocfs2_clusters_for_bytes(inode->i_sb, pos + count) - cpos;
+       int ret = 0;
 
-       ret = ocfs2_inode_lock(inode, &di_bh, 1);
-       if (ret) {
-               mlog_errno(ret);
+       if (wait)
+               ret = ocfs2_inode_lock(inode, NULL, meta_level);
+       else
+               ret = ocfs2_try_inode_lock(inode,
+                       overwrite_io ? NULL : di_bh, meta_level);
+       if (ret < 0)
                goto out;
+
+       if (wait) {
+               if (write_sem)
+                       down_write(&OCFS2_I(inode)->ip_alloc_sem);
+               else
+                       down_read(&OCFS2_I(inode)->ip_alloc_sem);
+       } else {
+               if (write_sem)
+                       ret = down_write_trylock(&OCFS2_I(inode)->ip_alloc_sem);
+               else
+                       ret = down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem);
+
+               if (!ret) {
+                       ret = -EAGAIN;
+                       goto out_unlock;
+               }
        }
 
-       *meta_level = 1;
+       return ret;
 
-       ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX);
-       if (ret)
-               mlog_errno(ret);
+out_unlock:
+       brelse(*di_bh);
+       ocfs2_inode_unlock(inode, meta_level);
 out:
-       brelse(di_bh);
        return ret;
 }
 
+static void ocfs2_inode_unlock_for_extent_tree(struct inode *inode,
+                                              struct buffer_head **di_bh,
+                                              int meta_level,
+                                              int write_sem)
+{
+       if (write_sem)
+               up_write(&OCFS2_I(inode)->ip_alloc_sem);
+       else
+               up_read(&OCFS2_I(inode)->ip_alloc_sem);
+
+       brelse(*di_bh);
+       *di_bh = NULL;
+
+       if (meta_level >= 0)
+               ocfs2_inode_unlock(inode, meta_level);
+}
+
 static int ocfs2_prepare_inode_for_write(struct file *file,
                                         loff_t pos, size_t count, int wait)
 {
        int ret = 0, meta_level = 0, overwrite_io = 0;
+       int write_sem = 0;
        struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = d_inode(dentry);
        struct buffer_head *di_bh = NULL;
+       u32 cpos;
+       u32 clusters;
 
        /*
         * We start with a read level meta lock and only jump to an ex
         * if we need to make modifications here.
         */
        for(;;) {
-               if (wait)
-                       ret = ocfs2_inode_lock(inode, NULL, meta_level);
-               else
-                       ret = ocfs2_try_inode_lock(inode,
-                               overwrite_io ? NULL : &di_bh, meta_level);
+               ret = ocfs2_inode_lock_for_extent_tree(inode,
+                                                      &di_bh,
+                                                      meta_level,
+                                                      overwrite_io,
+                                                      write_sem,
+                                                      wait);
                if (ret < 0) {
-                       meta_level = -1;
                        if (ret != -EAGAIN)
                                mlog_errno(ret);
                        goto out;
                 */
                if (!wait && !overwrite_io) {
                        overwrite_io = 1;
-                       if (!down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem)) {
-                               ret = -EAGAIN;
-                               goto out_unlock;
-                       }
 
                        ret = ocfs2_overwrite_io(inode, di_bh, pos, count);
-                       brelse(di_bh);
-                       di_bh = NULL;
-                       up_read(&OCFS2_I(inode)->ip_alloc_sem);
                        if (ret < 0) {
                                if (ret != -EAGAIN)
                                        mlog_errno(ret);
                 * set inode->i_size at the end of a write. */
                if (should_remove_suid(dentry)) {
                        if (meta_level == 0) {
-                               ocfs2_inode_unlock(inode, meta_level);
+                               ocfs2_inode_unlock_for_extent_tree(inode,
+                                                                  &di_bh,
+                                                                  meta_level,
+                                                                  write_sem);
                                meta_level = 1;
                                continue;
                        }
 
                ret = ocfs2_check_range_for_refcount(inode, pos, count);
                if (ret == 1) {
-                       ocfs2_inode_unlock(inode, meta_level);
-                       meta_level = -1;
-
-                       ret = ocfs2_prepare_inode_for_refcount(inode,
-                                                              file,
-                                                              pos,
-                                                              count,
-                                                              &meta_level);
+                       ocfs2_inode_unlock_for_extent_tree(inode,
+                                                          &di_bh,
+                                                          meta_level,
+                                                          write_sem);
+                       ret = ocfs2_inode_lock_for_extent_tree(inode,
+                                                              &di_bh,
+                                                              meta_level,
+                                                              overwrite_io,
+                                                              1,
+                                                              wait);
+                       write_sem = 1;
+                       if (ret < 0) {
+                               if (ret != -EAGAIN)
+                                       mlog_errno(ret);
+                               goto out;
+                       }
+
+                       cpos = pos >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
+                       clusters =
+                               ocfs2_clusters_for_bytes(inode->i_sb, pos + count) - cpos;
+                       ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX);
                }
 
                if (ret < 0) {
-                       mlog_errno(ret);
+                       if (ret != -EAGAIN)
+                               mlog_errno(ret);
                        goto out_unlock;
                }
 
        trace_ocfs2_prepare_inode_for_write(OCFS2_I(inode)->ip_blkno,
                                            pos, count, wait);
 
-       brelse(di_bh);
-
-       if (meta_level >= 0)
-               ocfs2_inode_unlock(inode, meta_level);
+       ocfs2_inode_unlock_for_extent_tree(inode,
+                                          &di_bh,
+                                          meta_level,
+                                          write_sem);
 
 out:
        return ret;