Btrfs: truncate pages from clone ioctl target range
[pandora-kernel.git] / fs / btrfs / ioctl.c
index ac37040..b3d249d 100644 (file)
@@ -482,8 +482,10 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
        ret = btrfs_snap_reserve_metadata(trans, pending_snapshot);
        BUG_ON(ret);
 
+       spin_lock(&root->fs_info->trans_lock);
        list_add(&pending_snapshot->list,
                 &trans->transaction->pending_snapshots);
+       spin_unlock(&root->fs_info->trans_lock);
        if (async_transid) {
                *async_transid = trans->transid;
                ret = btrfs_commit_transaction_async(trans,
@@ -865,8 +867,8 @@ again:
        /* step one, lock all the pages */
        for (i = 0; i < num_pages; i++) {
                struct page *page;
-               page = grab_cache_page(inode->i_mapping,
-                                           start_index + i);
+               page = find_or_create_page(inode->i_mapping,
+                                           start_index + i, GFP_NOFS);
                if (!page)
                        break;
 
@@ -936,7 +938,9 @@ again:
                          GFP_NOFS);
 
        if (i_done != num_pages) {
-               atomic_inc(&BTRFS_I(inode)->outstanding_extents);
+               spin_lock(&BTRFS_I(inode)->lock);
+               BTRFS_I(inode)->outstanding_extents++;
+               spin_unlock(&BTRFS_I(inode)->lock);
                btrfs_delalloc_release_space(inode,
                                     (num_pages - i_done) << PAGE_CACHE_SHIFT);
        }
@@ -1753,11 +1757,10 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
                key.objectid = key.offset;
                key.offset = (u64)-1;
                dirid = key.objectid;
-
        }
        if (ptr < name)
                goto out;
-       memcpy(name, ptr, total_len);
+       memmove(name, ptr, total_len);
        name[total_len]='\0';
        ret = 0;
 out:
@@ -2054,29 +2057,34 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
 
 static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg)
 {
-       struct btrfs_ioctl_fs_info_args fi_args;
+       struct btrfs_ioctl_fs_info_args *fi_args;
        struct btrfs_device *device;
        struct btrfs_device *next;
        struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
+       int ret = 0;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       fi_args.num_devices = fs_devices->num_devices;
-       fi_args.max_id = 0;
-       memcpy(&fi_args.fsid, root->fs_info->fsid, sizeof(fi_args.fsid));
+       fi_args = kzalloc(sizeof(*fi_args), GFP_KERNEL);
+       if (!fi_args)
+               return -ENOMEM;
+
+       fi_args->num_devices = fs_devices->num_devices;
+       memcpy(&fi_args->fsid, root->fs_info->fsid, sizeof(fi_args->fsid));
 
        mutex_lock(&fs_devices->device_list_mutex);
        list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
-               if (device->devid > fi_args.max_id)
-                       fi_args.max_id = device->devid;
+               if (device->devid > fi_args->max_id)
+                       fi_args->max_id = device->devid;
        }
        mutex_unlock(&fs_devices->device_list_mutex);
 
-       if (copy_to_user(arg, &fi_args, sizeof(fi_args)))
-               return -EFAULT;
+       if (copy_to_user(arg, fi_args, sizeof(*fi_args)))
+               ret = -EFAULT;
 
-       return 0;
+       kfree(fi_args);
+       return ret;
 }
 
 static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
@@ -2236,6 +2244,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
                btrfs_wait_ordered_range(src, off, len);
        }
 
+       /* truncate page cache pages from target inode range */
+       truncate_inode_pages_range(&inode->i_data, off,
+                                  ALIGN(off + len, PAGE_CACHE_SIZE) - 1);
+
        /* clone data */
        key.objectid = btrfs_ino(src);
        key.type = BTRFS_EXTENT_DATA_KEY;