aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.com>2017-07-21 19:15:59 +0200
committerDavid Sterba <dsterba@suse.com>2017-07-21 19:15:59 +0200
commite8cf7e61738fee99c0aee839a1c6434e59701824 (patch)
tree3ccee2a0c2bb8c404c0b6a98c2f690c3cd83de45 /fs
parent8c406a80725d63db2ca2209a2c845f98da6f098f (diff)
parentfb6ec5b37d4066a348be7ec65f5b8b3097feee3b (diff)
Merge branch 'compression' into for-next-next-v4.14-20170721
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/btrfs_inode.h9
-rw-r--r--fs/btrfs/compression.c33
-rw-r--r--fs/btrfs/compression.h2
-rw-r--r--fs/btrfs/inode.c24
-rw-r--r--fs/btrfs/ioctl.c16
-rw-r--r--fs/btrfs/props.c10
-rw-r--r--fs/btrfs/super.c4
7 files changed, 72 insertions, 26 deletions
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index a68fbf6d4bc0..219e971f8577 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -179,9 +179,14 @@ struct btrfs_inode {
unsigned reserved_extents;
/*
- * always compress this one file
+ * Cached values if inode properties
*/
- unsigned force_compress;
+ unsigned prop_compress; /* per-file compression algorithm */
+ /*
+ * Force compression on the file using the defrag ioctl, could be
+ * different from prop_compress and takes precedence if set
+ */
+ unsigned defrag_compress;
struct btrfs_delayed_node *delayed_node;
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index 5065d611a300..63f54bd2d5bb 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -1047,3 +1047,36 @@ int btrfs_decompress_buf2page(const char *buf, unsigned long buf_start,
return 1;
}
+
+/*
+ * Compression heuristic.
+ *
+ * For now is's a naive and optimistic 'return true', we'll extend the logic to
+ * quickly (compared to direct compression) detect data characteristics
+ * (compressible/uncompressible) to avoid wasting CPU time on uncompressible
+ * data.
+ *
+ * The following types of analysis can be performed:
+ * - detect mostly zero data
+ * - detect data with low "byte set" size (text, etc)
+ * - detect data with low/high "core byte" set
+ *
+ * Return non-zero if the compression should be done, 0 otherwise.
+ */
+int btrfs_compress_heuristic(struct inode *inode, u64 start, u64 end)
+{
+ u64 index = start >> PAGE_SHIFT;
+ u64 end_index = end >> PAGE_SHIFT;
+ struct page *page;
+ int ret = 1;
+
+ while (index <= end_index) {
+ page = find_get_page(inode->i_mapping, index);
+ kmap(page);
+ kunmap(page);
+ put_page(page);
+ index++;
+ }
+
+ return ret;
+}
diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h
index 89bcf975efb8..d1f4eee2d0af 100644
--- a/fs/btrfs/compression.h
+++ b/fs/btrfs/compression.h
@@ -129,4 +129,6 @@ struct btrfs_compress_op {
extern const struct btrfs_compress_op btrfs_zlib_compress;
extern const struct btrfs_compress_op btrfs_lzo_compress;
+int btrfs_compress_heuristic(struct inode *inode, u64 start, u64 end);
+
#endif
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 04ee3720afc4..9a4413a176c8 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -392,20 +392,23 @@ static noinline int add_async_extent(struct async_cow *cow,
return 0;
}
-static inline int inode_need_compress(struct inode *inode)
+static inline int inode_need_compress(struct inode *inode, u64 start, u64 end)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
/* force compress */
if (btrfs_test_opt(fs_info, FORCE_COMPRESS))
return 1;
+ /* defrag ioctl */
+ if (BTRFS_I(inode)->defrag_compress)
+ return 1;
/* bad compression ratios */
if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS)
return 0;
if (btrfs_test_opt(fs_info, COMPRESS) ||
BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS ||
- BTRFS_I(inode)->force_compress)
- return 1;
+ BTRFS_I(inode)->prop_compress)
+ return btrfs_compress_heuristic(inode, start, end);
return 0;
}
@@ -503,7 +506,7 @@ again:
* inode has not been flagged as nocompress. This flag can
* change at any time if we discover bad compression ratios.
*/
- if (inode_need_compress(inode)) {
+ if (inode_need_compress(inode, start, end)) {
WARN_ON(pages);
pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
if (!pages) {
@@ -511,8 +514,10 @@ again:
goto cont;
}
- if (BTRFS_I(inode)->force_compress)
- compress_type = BTRFS_I(inode)->force_compress;
+ if (BTRFS_I(inode)->defrag_compress)
+ compress_type = BTRFS_I(inode)->defrag_compress;
+ else if (BTRFS_I(inode)->prop_compress)
+ compress_type = BTRFS_I(inode)->prop_compress;
/*
* we need to call clear_page_dirty_for_io on each
@@ -645,7 +650,7 @@ cont:
/* flag the file so we don't compress in the future */
if (!btrfs_test_opt(fs_info, FORCE_COMPRESS) &&
- !(BTRFS_I(inode)->force_compress)) {
+ !(BTRFS_I(inode)->prop_compress)) {
BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
}
}
@@ -1577,7 +1582,7 @@ static int run_delalloc_range(void *private_data, 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)) {
+ } else if (!inode_need_compress(inode, start, end)) {
ret = cow_file_range(inode, locked_page, start, end, end,
page_started, nr_written, 1, NULL);
} else {
@@ -9431,7 +9436,8 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
ei->reserved_extents = 0;
ei->runtime_flags = 0;
- ei->force_compress = BTRFS_COMPRESS_NONE;
+ ei->prop_compress = BTRFS_COMPRESS_NONE;
+ ei->defrag_compress = BTRFS_COMPRESS_NONE;
ei->delayed_node = NULL;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 496e873b14de..bedeec66ca8b 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1255,6 +1255,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
unsigned long cluster = max_cluster;
u64 new_align = ~((u64)SZ_128K - 1);
struct page **pages = NULL;
+ bool do_compress = range->flags & BTRFS_DEFRAG_RANGE_COMPRESS;
if (isize == 0)
return 0;
@@ -1262,7 +1263,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
if (range->start >= isize)
return -EINVAL;
- if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) {
+ if (do_compress) {
if (range->compress_type > BTRFS_COMPRESS_TYPES)
return -EINVAL;
if (range->compress_type)
@@ -1341,8 +1342,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
if (!should_defrag_range(inode, (u64)i << PAGE_SHIFT,
extent_thresh, &last_len, &skip,
- &defrag_end, range->flags &
- BTRFS_DEFRAG_RANGE_COMPRESS)) {
+ &defrag_end, do_compress)){
unsigned long next;
/*
* the should_defrag function tells us how much to skip
@@ -1370,8 +1370,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
}
inode_lock(inode);
- if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)
- BTRFS_I(inode)->force_compress = compress_type;
+ if (do_compress)
+ BTRFS_I(inode)->defrag_compress = compress_type;
ret = cluster_pages_for_defrag(inode, pages, i, cluster);
if (ret < 0) {
inode_unlock(inode);
@@ -1418,7 +1418,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
filemap_flush(inode->i_mapping);
}
- if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) {
+ if (do_compress) {
/* the filemap_flush will queue IO into the worker threads, but
* we have to make sure the IO is actually started and that
* ordered extents get created before we return
@@ -1440,9 +1440,9 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
ret = defrag_count;
out_ra:
- if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) {
+ if (do_compress) {
inode_lock(inode);
- BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE;
+ BTRFS_I(inode)->defrag_compress = BTRFS_COMPRESS_NONE;
inode_unlock(inode);
}
if (!file)
diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c
index 4b23ae5d0e5c..09c0266f248d 100644
--- a/fs/btrfs/props.c
+++ b/fs/btrfs/props.c
@@ -403,28 +403,28 @@ static int prop_compression_apply(struct inode *inode,
if (len == 0) {
BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
- BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE;
+ BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
return 0;
}
- if (!strncmp("lzo", value, len))
+ if (!strncmp("lzo", value, 3))
type = BTRFS_COMPRESS_LZO;
- else if (!strncmp("zlib", value, len))
+ else if (!strncmp("zlib", value, 4))
type = BTRFS_COMPRESS_ZLIB;
else
return -EINVAL;
BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
- BTRFS_I(inode)->force_compress = type;
+ BTRFS_I(inode)->prop_compress = type;
return 0;
}
static const char *prop_compression_extract(struct inode *inode)
{
- switch (BTRFS_I(inode)->force_compress) {
+ switch (BTRFS_I(inode)->prop_compress) {
case BTRFS_COMPRESS_ZLIB:
return "zlib";
case BTRFS_COMPRESS_LZO:
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index eb0aeb81d576..ed8ce5edc9cc 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -499,14 +499,14 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
btrfs_test_opt(info, FORCE_COMPRESS);
if (token == Opt_compress ||
token == Opt_compress_force ||
- strcmp(args[0].from, "zlib") == 0) {
+ strncmp(args[0].from, "zlib", 4) == 0) {
compress_type = "zlib";
info->compress_type = BTRFS_COMPRESS_ZLIB;
btrfs_set_opt(info->mount_opt, COMPRESS);
btrfs_clear_opt(info->mount_opt, NODATACOW);
btrfs_clear_opt(info->mount_opt, NODATASUM);
no_compress = 0;
- } else if (strcmp(args[0].from, "lzo") == 0) {
+ } else if (strncmp(args[0].from, "lzo", 3) == 0) {
compress_type = "lzo";
info->compress_type = BTRFS_COMPRESS_LZO;
btrfs_set_opt(info->mount_opt, COMPRESS);