btrfs: detect fast implementation of crc32c on all architectures
authorDavid Sterba <dsterba@suse.com>
Thu, 16 May 2019 11:39:59 +0000 (13:39 +0200)
committerDavid Sterba <dsterba@suse.com>
Mon, 1 Jul 2019 11:34:53 +0000 (13:34 +0200)
Currently, there's only check for fast crc32c implementation on X86,
based on the CPU flags. This is used to decide if checksumming should be
offloaded to worker threads or can be calculated by the caller.

As there are more architectures that implement a faster version of
crc32c (ARM, SPARC, s390, MIPS, PowerPC), also there are specialized hw
cards.

The detection is based on driver name, all generic C implementations
contain 'generic', while the specialized versions do not. Alternatively
the priority could be used, but this is not currently provided by the
crypto API.

The flag is set per-filesystem at mount time and used for the offloading
decisions.

Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/super.c

index 0a61dff27f57a50120ef4c3bf0f4424bf29ba262..02870c1bb68ac6ec815de8a408f09b1d57ad2144 100644 (file)
@@ -791,6 +791,12 @@ enum {
 
        /* Indicate that the cleaner thread is awake and doing something. */
        BTRFS_FS_CLEANER_RUNNING,
+
+       /*
+        * The checksumming has an optimized version and is considered fast,
+        * so we don't need to offload checksums to workqueues.
+        */
+       BTRFS_FS_CSUM_IMPL_FAST,
 };
 
 struct btrfs_fs_info {
index deb74a8c191a47583189dcc0cb9fc6ff4c8dac58..024c9fadeaeb5ff9e105850cb14deb55f2c2a421 100644 (file)
 #include "tree-checker.h"
 #include "ref-verify.h"
 
-#ifdef CONFIG_X86
-#include <asm/cpufeature.h>
-#endif
-
 #define BTRFS_SUPER_FLAG_SUPP  (BTRFS_HEADER_FLAG_WRITTEN |\
                                 BTRFS_HEADER_FLAG_RELOC |\
                                 BTRFS_SUPER_FLAG_ERROR |\
@@ -873,14 +869,13 @@ static blk_status_t btree_submit_bio_start(void *private_data, struct bio *bio,
        return btree_csum_one_bio(bio);
 }
 
-static int check_async_write(struct btrfs_inode *bi)
+static int check_async_write(struct btrfs_fs_info *fs_info,
+                            struct btrfs_inode *bi)
 {
        if (atomic_read(&bi->sync_writers))
                return 0;
-#ifdef CONFIG_X86
-       if (static_cpu_has(X86_FEATURE_XMM4_2))
+       if (test_bit(BTRFS_FS_CSUM_IMPL_FAST, &fs_info->flags))
                return 0;
-#endif
        return 1;
 }
 
@@ -889,7 +884,7 @@ static blk_status_t btree_submit_bio_hook(struct inode *inode, struct bio *bio,
                                          unsigned long bio_flags)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
-       int async = check_async_write(BTRFS_I(inode));
+       int async = check_async_write(fs_info, BTRFS_I(inode));
        blk_status_t ret;
 
        if (bio_op(bio) != REQ_OP_WRITE) {
index 0645ec428b4f5b81a7de982f78182c8aa3362337..db410c6b5f5fe7726147d2efa5b690255af1de9f 100644 (file)
@@ -1553,6 +1553,8 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
        } else {
                snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
                btrfs_sb(s)->bdev_holder = fs_type;
+               if (!strstr(crc32c_impl(), "generic"))
+                       set_bit(BTRFS_FS_CSUM_IMPL_FAST, &fs_info->flags);
                error = btrfs_fill_super(s, fs_devices, data);
        }
        if (!error)