Btrfs: fix file loss on log replay after renaming a file and fsync
[cascardo/linux.git] / fs / btrfs / ioctl.c
index 48aee98..0af5ecb 100644 (file)
@@ -59,6 +59,7 @@
 #include "props.h"
 #include "sysfs.h"
 #include "qgroup.h"
+#include "tree-log.h"
 
 #ifdef CONFIG_64BIT
 /* If we have a 32-bit userspace and 64-bit kernel, then the UAPI
@@ -347,7 +348,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
 
        btrfs_update_iflags(inode);
        inode_inc_iversion(inode);
-       inode->i_ctime = CURRENT_TIME;
+       inode->i_ctime = current_fs_time(inode->i_sb);
        ret = btrfs_update_inode(trans, root, inode);
 
        btrfs_end_transaction(trans, root);
@@ -443,7 +444,7 @@ static noinline int create_subvol(struct inode *dir,
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct btrfs_root *new_root;
        struct btrfs_block_rsv block_rsv;
-       struct timespec cur_time = CURRENT_TIME;
+       struct timespec cur_time = current_fs_time(dir->i_sb);
        struct inode *inode;
        int ret;
        int err;
@@ -844,10 +845,6 @@ static noinline int btrfs_mksubvol(struct path *parent,
        if (IS_ERR(dentry))
                goto out_unlock;
 
-       error = -EEXIST;
-       if (d_really_is_positive(dentry))
-               goto out_dput;
-
        error = btrfs_may_create(dir, dentry);
        if (error)
                goto out_dput;
@@ -2097,8 +2094,6 @@ static noinline int search_ioctl(struct inode *inode,
                key.offset = (u64)-1;
                root = btrfs_read_fs_root_no_name(info, &key);
                if (IS_ERR(root)) {
-                       btrfs_err(info, "could not find root %llu",
-                              sk->tree_id);
                        btrfs_free_path(path);
                        return -ENOENT;
                }
@@ -2476,6 +2471,8 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
        trans->block_rsv = &block_rsv;
        trans->bytes_reserved = block_rsv.size;
 
+       btrfs_record_snapshot_destroy(trans, dir);
+
        ret = btrfs_unlink_subvol(trans, root, dir,
                                dest->root_key.objectid,
                                dentry->d_name.name,
@@ -2960,8 +2957,8 @@ static int btrfs_cmp_data_prepare(struct inode *src, u64 loff,
         * of the array is bounded by len, which is in turn bounded by
         * BTRFS_MAX_DEDUPE_LEN.
         */
-       src_pgarr = kzalloc(num_pages * sizeof(struct page *), GFP_NOFS);
-       dst_pgarr = kzalloc(num_pages * sizeof(struct page *), GFP_NOFS);
+       src_pgarr = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL);
+       dst_pgarr = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL);
        if (!src_pgarr || !dst_pgarr) {
                kfree(src_pgarr);
                kfree(dst_pgarr);
@@ -3217,7 +3214,7 @@ static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
 
        inode_inc_iversion(inode);
        if (!no_time_update)
-               inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+               inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
        /*
         * We round up to the block size at eof when determining which
         * extents to clone above, but shouldn't round up the file size.
@@ -3889,8 +3886,9 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
         * Truncate page cache pages so that future reads will see the cloned
         * data immediately and not the previous data.
         */
-       truncate_inode_pages_range(&inode->i_data, destoff,
-                                  PAGE_CACHE_ALIGN(destoff + len) - 1);
+       truncate_inode_pages_range(&inode->i_data,
+                               round_down(destoff, PAGE_CACHE_SIZE),
+                               round_up(destoff + len, PAGE_CACHE_SIZE) - 1);
 out_unlock:
        if (!same_inode)
                btrfs_double_inode_unlock(src, inode);
@@ -5031,7 +5029,7 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_root_item *root_item = &root->root_item;
        struct btrfs_trans_handle *trans;
-       struct timespec ct = CURRENT_TIME;
+       struct timespec ct = current_fs_time(inode->i_sb);
        int ret = 0;
        int received_uuid_changed;
 
@@ -5262,8 +5260,7 @@ out_unlock:
          .compat_ro_flags = BTRFS_FEATURE_COMPAT_RO_##suffix, \
          .incompat_flags = BTRFS_FEATURE_INCOMPAT_##suffix }
 
-static int btrfs_ioctl_get_supported_features(struct file *file,
-                                             void __user *arg)
+int btrfs_ioctl_get_supported_features(void __user *arg)
 {
        static const struct btrfs_ioctl_feature_flags features[3] = {
                INIT_FEATURE_FLAGS(SUPP),
@@ -5542,7 +5539,7 @@ long btrfs_ioctl(struct file *file, unsigned int
        case BTRFS_IOC_SET_FSLABEL:
                return btrfs_ioctl_set_fslabel(file, argp);
        case BTRFS_IOC_GET_SUPPORTED_FEATURES:
-               return btrfs_ioctl_get_supported_features(file, argp);
+               return btrfs_ioctl_get_supported_features(argp);
        case BTRFS_IOC_GET_FEATURES:
                return btrfs_ioctl_get_features(file, argp);
        case BTRFS_IOC_SET_FEATURES: