int ret;
        u64 len = olen;
        u64 bs = root->fs_info->sb->s_blocksize;
+       int same_inode = 0;
 
        /*
         * TODO:
 
        ret = -EINVAL;
        if (src == inode)
-               goto out_fput;
+               same_inode = 1;
 
        /* the src must be open for reading */
        if (!(src_file.file->f_mode & FMODE_READ))
        }
        path->reada = 2;
 
-       if (inode < src) {
-               mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
-               mutex_lock_nested(&src->i_mutex, I_MUTEX_CHILD);
+       if (!same_inode) {
+               if (inode < src) {
+                       mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
+                       mutex_lock_nested(&src->i_mutex, I_MUTEX_CHILD);
+               } else {
+                       mutex_lock_nested(&src->i_mutex, I_MUTEX_PARENT);
+                       mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
+               }
        } else {
-               mutex_lock_nested(&src->i_mutex, I_MUTEX_PARENT);
-               mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
+               mutex_lock(&src->i_mutex);
        }
 
        /* determine range to clone */
            !IS_ALIGNED(destoff, bs))
                goto out_unlock;
 
+       /* verify if ranges are overlapped within the same file */
+       if (same_inode) {
+               if (destoff + len > off && destoff < off + len)
+                       goto out_unlock;
+       }
+
        if (destoff > inode->i_size) {
                ret = btrfs_cont_expand(inode, inode->i_size, destoff);
                if (ret)
        unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
 out_unlock:
        mutex_unlock(&src->i_mutex);
-       mutex_unlock(&inode->i_mutex);
+       if (!same_inode)
+               mutex_unlock(&inode->i_mutex);
        vfree(buf);
        btrfs_free_path(path);
 out_fput: