Btrfs: Fix extent replacment race
[linux-2.6-block.git] / fs / btrfs / ioctl.c
index 926332a73cdefd957cf1ef483544f460d9f1278a..e2d8e90259b05c2499a1f9cbc54ac9cf529ecbe0 100644 (file)
@@ -112,7 +112,12 @@ void btrfs_update_iflags(struct inode *inode)
  */
 void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
 {
-       unsigned int flags = BTRFS_I(dir)->flags;
+       unsigned int flags;
+
+       if (!dir)
+               return;
+
+       flags = BTRFS_I(dir)->flags;
 
        if (S_ISREG(inode->i_mode))
                flags &= ~BTRFS_INODE_DIRSYNC;
@@ -592,9 +597,8 @@ again:
                clear_page_dirty_for_io(page);
 
                btrfs_set_extent_delalloc(inode, page_start, page_end);
-
-               unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
                set_page_dirty(page);
+               unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
                unlock_page(page);
                page_cache_release(page);
                balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1);
@@ -972,7 +976,7 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
 
        /* punch hole in destination first */
        btrfs_drop_extents(trans, root, inode, off, off + len,
-                          off + len, 0, &hint_byte);
+                          off + len, 0, &hint_byte, 1);
 
        /* clone data */
        key.objectid = src->i_ino;
@@ -1023,7 +1027,8 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                                struct btrfs_file_extent_item);
                        comp = btrfs_file_extent_compression(leaf, extent);
                        type = btrfs_file_extent_type(leaf, extent);
-                       if (type == BTRFS_FILE_EXTENT_REG) {
+                       if (type == BTRFS_FILE_EXTENT_REG ||
+                           type == BTRFS_FILE_EXTENT_PREALLOC) {
                                disko = btrfs_file_extent_disk_bytenr(leaf,
                                                                      extent);
                                diskl = btrfs_file_extent_disk_num_bytes(leaf,
@@ -1046,7 +1051,8 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                        new_key.objectid = inode->i_ino;
                        new_key.offset = key.offset + destoff - off;
 
-                       if (type == BTRFS_FILE_EXTENT_REG) {
+                       if (type == BTRFS_FILE_EXTENT_REG ||
+                           type == BTRFS_FILE_EXTENT_PREALLOC) {
                                ret = btrfs_insert_empty_item(trans, root, path,
                                                              &new_key, size);
                                if (ret)