btrfs: inode: Don't compress if NODATASUM or NODATACOW set
[sfrench/cifs-2.6.git] / fs / btrfs / inode.c
index a2aabdb85226d7c11eba224d6acf40d4948f307b..ee582a36653d30ee1f833153f9bc00225f7978ae 100644 (file)
@@ -47,6 +47,7 @@
 #include "props.h"
 #include "qgroup.h"
 #include "dedupe.h"
+#include "delalloc-space.h"
 
 struct btrfs_iget_args {
        struct btrfs_key *location;
@@ -394,10 +395,31 @@ static noinline int add_async_extent(struct async_chunk *cow,
        return 0;
 }
 
+/*
+ * Check if the inode has flags compatible with compression
+ */
+static inline bool inode_can_compress(struct inode *inode)
+{
+       if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW ||
+           BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
+               return false;
+       return true;
+}
+
+/*
+ * Check if the inode needs to be submitted to compression, based on mount
+ * options, defragmentation, properties or heuristics.
+ */
 static inline int inode_need_compress(struct inode *inode, u64 start, u64 end)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
 
+       if (!inode_can_compress(inode)) {
+               WARN(IS_ENABLED(CONFIG_BTRFS_DEBUG),
+                       KERN_ERR "BTRFS: unexpected compression for ino %llu\n",
+                       btrfs_ino(BTRFS_I(inode)));
+               return 0;
+       }
        /* force compress */
        if (btrfs_test_opt(fs_info, FORCE_COMPRESS))
                return 1;
@@ -1630,7 +1652,8 @@ int btrfs_run_delalloc_range(struct inode *inode, struct page *locked_page,
        } else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC && !force_cow) {
                ret = run_delalloc_nocow(inode, locked_page, start, end,
                                         page_started, 0, nr_written);
-       } else if (!inode_need_compress(inode, start, end)) {
+       } else if (!inode_can_compress(inode) ||
+                  !inode_need_compress(inode, start, end)) {
                ret = cow_file_range(inode, locked_page, start, end, end,
                                      page_started, nr_written, 1, NULL);
        } else {
@@ -1932,17 +1955,19 @@ int btrfs_bio_fits_in_stripe(struct page *page, size_t size, struct bio *bio,
        u64 length = 0;
        u64 map_length;
        int ret;
+       struct btrfs_io_geometry geom;
 
        if (bio_flags & EXTENT_BIO_COMPRESSED)
                return 0;
 
        length = bio->bi_iter.bi_size;
        map_length = length;
-       ret = btrfs_map_block(fs_info, btrfs_op(bio), logical, &map_length,
-                             NULL, 0);
+       ret = btrfs_get_io_geometry(fs_info, btrfs_op(bio), logical, map_length,
+                                   &geom);
        if (ret < 0)
                return ret;
-       if (map_length < length + size)
+
+       if (geom.len < length + size)
                return 1;
        return 0;
 }
@@ -3203,16 +3228,23 @@ static int __readpage_endio_check(struct inode *inode,
                                  int icsum, struct page *page,
                                  int pgoff, u64 start, size_t len)
 {
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+       SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
        char *kaddr;
-       u32 csum_expected;
-       u32 csum = ~(u32)0;
+       u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
+       u8 *csum_expected;
+       u8 csum[BTRFS_CSUM_SIZE];
 
-       csum_expected = *(((u32 *)io_bio->csum) + icsum);
+       csum_expected = ((u8 *)io_bio->csum) + icsum * csum_size;
 
        kaddr = kmap_atomic(page);
-       csum = btrfs_csum_data(kaddr + pgoff, csum,  len);
-       btrfs_csum_final(csum, (u8 *)&csum);
-       if (csum != csum_expected)
+       shash->tfm = fs_info->csum_shash;
+
+       crypto_shash_init(shash);
+       crypto_shash_update(shash, kaddr + pgoff, len);
+       crypto_shash_final(shash, csum);
+
+       if (memcmp(csum, csum_expected, csum_size))
                goto zeroit;
 
        kunmap_atomic(kaddr);
@@ -3286,6 +3318,28 @@ void btrfs_add_delayed_iput(struct inode *inode)
                wake_up_process(fs_info->cleaner_kthread);
 }
 
+static void run_delayed_iput_locked(struct btrfs_fs_info *fs_info,
+                                   struct btrfs_inode *inode)
+{
+       list_del_init(&inode->delayed_iput);
+       spin_unlock(&fs_info->delayed_iput_lock);
+       iput(&inode->vfs_inode);
+       if (atomic_dec_and_test(&fs_info->nr_delayed_iputs))
+               wake_up(&fs_info->delayed_iputs_wait);
+       spin_lock(&fs_info->delayed_iput_lock);
+}
+
+static void btrfs_run_delayed_iput(struct btrfs_fs_info *fs_info,
+                                  struct btrfs_inode *inode)
+{
+       if (!list_empty(&inode->delayed_iput)) {
+               spin_lock(&fs_info->delayed_iput_lock);
+               if (!list_empty(&inode->delayed_iput))
+                       run_delayed_iput_locked(fs_info, inode);
+               spin_unlock(&fs_info->delayed_iput_lock);
+       }
+}
+
 void btrfs_run_delayed_iputs(struct btrfs_fs_info *fs_info)
 {
 
@@ -3295,12 +3349,7 @@ void btrfs_run_delayed_iputs(struct btrfs_fs_info *fs_info)
 
                inode = list_first_entry(&fs_info->delayed_iputs,
                                struct btrfs_inode, delayed_iput);
-               list_del_init(&inode->delayed_iput);
-               spin_unlock(&fs_info->delayed_iput_lock);
-               iput(&inode->vfs_inode);
-               if (atomic_dec_and_test(&fs_info->nr_delayed_iputs))
-                       wake_up(&fs_info->delayed_iputs_wait);
-               spin_lock(&fs_info->delayed_iput_lock);
+               run_delayed_iput_locked(fs_info, inode);
        }
        spin_unlock(&fs_info->delayed_iput_lock);
 }
@@ -3935,9 +3984,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_path *path;
        int ret = 0;
-       struct extent_buffer *leaf;
        struct btrfs_dir_item *di;
-       struct btrfs_key key;
        u64 index;
        u64 ino = btrfs_ino(inode);
        u64 dir_ino = btrfs_ino(dir);
@@ -3955,8 +4002,6 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
                ret = di ? PTR_ERR(di) : -ENOENT;
                goto err;
        }
-       leaf = path->nodes[0];
-       btrfs_dir_item_key_to_cpu(leaf, di, &key);
        ret = btrfs_delete_one_dir_name(trans, root, path, di);
        if (ret)
                goto err;
@@ -4009,6 +4054,17 @@ skip_backref:
                ret = 0;
        else if (ret)
                btrfs_abort_transaction(trans, ret);
+
+       /*
+        * If we have a pending delayed iput we could end up with the final iput
+        * being run in btrfs-cleaner context.  If we have enough of these built
+        * up we can end up burning a lot of time in btrfs-cleaner without any
+        * way to throttle the unlinks.  Since we're currently holding a ref on
+        * the inode we can run the delayed iput here without any issues as the
+        * final iput won't be done until after we drop the ref we're currently
+        * holding.
+        */
+       btrfs_run_delayed_iput(fs_info, inode);
 err:
        btrfs_free_path(path);
        if (ret)
@@ -5008,21 +5064,8 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
        if (size <= hole_start)
                return 0;
 
-       while (1) {
-               struct btrfs_ordered_extent *ordered;
-
-               lock_extent_bits(io_tree, hole_start, block_end - 1,
-                                &cached_state);
-               ordered = btrfs_lookup_ordered_range(BTRFS_I(inode), hole_start,
-                                                    block_end - hole_start);
-               if (!ordered)
-                       break;
-               unlock_extent_cached(io_tree, hole_start, block_end - 1,
-                                    &cached_state);
-               btrfs_start_ordered_extent(inode, ordered, 1);
-               btrfs_put_ordered_extent(ordered);
-       }
-
+       btrfs_lock_and_flush_ordered_range(io_tree, BTRFS_I(inode), hole_start,
+                                          block_end - 1, &cached_state);
        cur_offset = hole_start;
        while (1) {
                em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, cur_offset,
@@ -8318,22 +8361,21 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip)
        struct bio *orig_bio = dip->orig_bio;
        u64 start_sector = orig_bio->bi_iter.bi_sector;
        u64 file_offset = dip->logical_offset;
-       u64 map_length;
        int async_submit = 0;
        u64 submit_len;
        int clone_offset = 0;
        int clone_len;
        int ret;
        blk_status_t status;
+       struct btrfs_io_geometry geom;
 
-       map_length = orig_bio->bi_iter.bi_size;
-       submit_len = map_length;
-       ret = btrfs_map_block(fs_info, btrfs_op(orig_bio), start_sector << 9,
-                             &map_length, NULL, 0);
+       submit_len = orig_bio->bi_iter.bi_size;
+       ret = btrfs_get_io_geometry(fs_info, btrfs_op(orig_bio),
+                                   start_sector << 9, submit_len, &geom);
        if (ret)
                return -EIO;
 
-       if (map_length >= submit_len) {
+       if (geom.len >= submit_len) {
                bio = orig_bio;
                dip->flags |= BTRFS_DIO_ORIG_BIO_SUBMITTED;
                goto submit;
@@ -8346,10 +8388,10 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip)
                async_submit = 1;
 
        /* bio split */
-       ASSERT(map_length <= INT_MAX);
+       ASSERT(geom.len <= INT_MAX);
        atomic_inc(&dip->pending_bios);
        do {
-               clone_len = min_t(int, submit_len, map_length);
+               clone_len = min_t(int, submit_len, geom.len);
 
                /*
                 * This will never fail as it's passing GPF_NOFS and
@@ -8386,9 +8428,8 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip)
                start_sector += clone_len >> 9;
                file_offset += clone_len;
 
-               map_length = submit_len;
-               ret = btrfs_map_block(fs_info, btrfs_op(orig_bio),
-                                     start_sector << 9, &map_length, NULL, 0);
+               ret = btrfs_get_io_geometry(fs_info, btrfs_op(orig_bio),
+                                     start_sector << 9, submit_len, &geom);
                if (ret)
                        goto out_err;
        } while (submit_len > 0);