Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[pandora-kernel.git] / fs / btrfs / ioctl.c
index 47127c1..e568c47 100644 (file)
@@ -181,6 +181,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
        int ret;
        u64 ip_oldflags;
        unsigned int i_oldflags;
+       umode_t mode;
 
        if (btrfs_root_readonly(root))
                return -EROFS;
@@ -203,6 +204,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
 
        ip_oldflags = ip->flags;
        i_oldflags = inode->i_flags;
+       mode = inode->i_mode;
 
        flags = btrfs_mask_flags(inode->i_mode, flags);
        oldflags = btrfs_flags_to_ioctl(ip->flags);
@@ -237,10 +239,31 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
                ip->flags |= BTRFS_INODE_DIRSYNC;
        else
                ip->flags &= ~BTRFS_INODE_DIRSYNC;
-       if (flags & FS_NOCOW_FL)
-               ip->flags |= BTRFS_INODE_NODATACOW;
-       else
-               ip->flags &= ~BTRFS_INODE_NODATACOW;
+       if (flags & FS_NOCOW_FL) {
+               if (S_ISREG(mode)) {
+                       /*
+                        * It's safe to turn csums off here, no extents exist.
+                        * Otherwise we want the flag to reflect the real COW
+                        * status of the file and will not set it.
+                        */
+                       if (inode->i_size == 0)
+                               ip->flags |= BTRFS_INODE_NODATACOW
+                                          | BTRFS_INODE_NODATASUM;
+               } else {
+                       ip->flags |= BTRFS_INODE_NODATACOW;
+               }
+       } else {
+               /*
+                * Revert back under same assuptions as above
+                */
+               if (S_ISREG(mode)) {
+                       if (inode->i_size == 0)
+                               ip->flags &= ~(BTRFS_INODE_NODATACOW
+                                            | BTRFS_INODE_NODATASUM);
+               } else {
+                       ip->flags &= ~BTRFS_INODE_NODATACOW;
+               }
+       }
 
        /*
         * The COMPRESS flag can only be changed by users, while the NOCOMPRESS
@@ -516,7 +539,8 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
        if (!pending_snapshot)
                return -ENOMEM;
 
-       btrfs_init_block_rsv(&pending_snapshot->block_rsv);
+       btrfs_init_block_rsv(&pending_snapshot->block_rsv,
+                            BTRFS_BLOCK_RSV_TEMP);
        pending_snapshot->dentry = dentry;
        pending_snapshot->root = root;
        pending_snapshot->readonly = readonly;
@@ -525,7 +549,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
                *inherit = NULL;        /* take responsibility to free it */
        }
 
-       trans = btrfs_start_transaction(root->fs_info->extent_root, 5);
+       trans = btrfs_start_transaction(root->fs_info->extent_root, 6);
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
                goto fail;
@@ -1022,8 +1046,8 @@ again:
                         page_start, page_end - 1, 0, &cached_state);
        clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start,
                          page_end - 1, EXTENT_DIRTY | EXTENT_DELALLOC |
-                         EXTENT_DO_ACCOUNTING, 0, 0, &cached_state,
-                         GFP_NOFS);
+                         EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 0, 0,
+                         &cached_state, GFP_NOFS);
 
        if (i_done != page_cnt) {
                spin_lock(&BTRFS_I(inode)->lock);
@@ -1034,8 +1058,8 @@ again:
        }
 
 
-       btrfs_set_extent_delalloc(inode, page_start, page_end - 1,
-                                 &cached_state);
+       set_extent_defrag(&BTRFS_I(inode)->io_tree, page_start, page_end - 1,
+                         &cached_state, GFP_NOFS);
 
        unlock_extent_cached(&BTRFS_I(inode)->io_tree,
                             page_start, page_end - 1, &cached_state,
@@ -2351,7 +2375,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
        int ret;
        u64 len = olen;
        u64 bs = root->fs_info->sb->s_blocksize;
-       u64 hint_byte;
 
        /*
         * TODO:
@@ -2456,13 +2479,13 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
           another, and lock file content */
        while (1) {
                struct btrfs_ordered_extent *ordered;
-               lock_extent(&BTRFS_I(src)->io_tree, off, off+len);
-               ordered = btrfs_lookup_first_ordered_extent(src, off+len);
+               lock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
+               ordered = btrfs_lookup_first_ordered_extent(src, off + len - 1);
                if (!ordered &&
-                   !test_range_bit(&BTRFS_I(src)->io_tree, off, off+len,
-                                  EXTENT_DELALLOC, 0, NULL))
+                   !test_range_bit(&BTRFS_I(src)->io_tree, off, off + len - 1,
+                                   EXTENT_DELALLOC, 0, NULL))
                        break;
-               unlock_extent(&BTRFS_I(src)->io_tree, off, off+len);
+               unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
                if (ordered)
                        btrfs_put_ordered_extent(ordered);
                btrfs_wait_ordered_range(src, off, len);
@@ -2536,7 +2559,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                        btrfs_release_path(path);
 
                        if (key.offset + datal <= off ||
-                           key.offset >= off+len)
+                           key.offset >= off + len - 1)
                                goto next;
 
                        memcpy(&new_key, &key, sizeof(new_key));
@@ -2574,10 +2597,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                        datal -= off - key.offset;
                                }
 
-                               ret = btrfs_drop_extents(trans, inode,
+                               ret = btrfs_drop_extents(trans, root, inode,
                                                         new_key.offset,
                                                         new_key.offset + datal,
-                                                        &hint_byte, 1);
+                                                        1);
                                if (ret) {
                                        btrfs_abort_transaction(trans, root,
                                                                ret);
@@ -2637,8 +2660,8 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                        new_key.offset += skip;
                                }
 
-                               if (key.offset + datal > off+len)
-                                       trim = key.offset + datal - (off+len);
+                               if (key.offset + datal > off + len)
+                                       trim = key.offset + datal - (off + len);
 
                                if (comp && (skip || trim)) {
                                        ret = -EINVAL;
@@ -2648,10 +2671,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                                size -= skip + trim;
                                datal -= skip + trim;
 
-                               ret = btrfs_drop_extents(trans, inode,
+                               ret = btrfs_drop_extents(trans, root, inode,
                                                         new_key.offset,
                                                         new_key.offset + datal,
-                                                        &hint_byte, 1);
+                                                        1);
                                if (ret) {
                                        btrfs_abort_transaction(trans, root,
                                                                ret);
@@ -2715,7 +2738,7 @@ next:
        ret = 0;
 out:
        btrfs_release_path(path);
-       unlock_extent(&BTRFS_I(src)->io_tree, off, off+len);
+       unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
 out_unlock:
        mutex_unlock(&src->i_mutex);
        mutex_unlock(&inode->i_mutex);
@@ -2850,8 +2873,8 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
        return 0;
 }
 
-static void get_block_group_info(struct list_head *groups_list,
-                                struct btrfs_ioctl_space_info *space)
+void btrfs_get_block_group_info(struct list_head *groups_list,
+                               struct btrfs_ioctl_space_info *space)
 {
        struct btrfs_block_group_cache *block_group;
 
@@ -2959,8 +2982,8 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
                down_read(&info->groups_sem);
                for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) {
                        if (!list_empty(&info->block_groups[c])) {
-                               get_block_group_info(&info->block_groups[c],
-                                                    &space);
+                               btrfs_get_block_group_info(
+                                       &info->block_groups[c], &space);
                                memcpy(dest, &space, sizeof(space));
                                dest++;
                                space_args.total_spaces++;
@@ -3208,11 +3231,9 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
 {
        int ret = 0;
        int size;
-       u64 extent_item_pos;
        struct btrfs_ioctl_logical_ino_args *loi;
        struct btrfs_data_container *inodes = NULL;
        struct btrfs_path *path = NULL;
-       struct btrfs_key key;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -3230,7 +3251,7 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
                goto out;
        }
 
-       size = min_t(u32, loi->size, 4096);
+       size = min_t(u32, loi->size, 64 * 1024);
        inodes = init_data_container(size);
        if (IS_ERR(inodes)) {
                ret = PTR_ERR(inodes);
@@ -3238,22 +3259,13 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
                goto out;
        }
 
-       ret = extent_from_logical(root->fs_info, loi->logical, path, &key);
-       btrfs_release_path(path);
-
-       if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK)
+       ret = iterate_inodes_from_logical(loi->logical, root->fs_info, path,
+                                         build_ino_list, inodes);
+       if (ret == -EINVAL)
                ret = -ENOENT;
        if (ret < 0)
                goto out;
 
-       extent_item_pos = loi->logical - key.objectid;
-       ret = iterate_extent_inodes(root->fs_info, key.objectid,
-                                       extent_item_pos, 0, build_ino_list,
-                                       inodes);
-
-       if (ret < 0)
-               goto out;
-
        ret = copy_to_user((void *)(unsigned long)loi->inodes,
                           (void *)(unsigned long)inodes, size);
        if (ret)
@@ -3261,7 +3273,7 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
 
 out:
        btrfs_free_path(path);
-       kfree(inodes);
+       vfree(inodes);
        kfree(loi);
 
        return ret;