Skip to content

Commit

Permalink
staging: erofs: introduce VLE decompression support
Browse files Browse the repository at this point in the history
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.

Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:

        |---  variable-length extent ---|------ VLE ------|---  VLE ---|
         /> clusterofs                  /> clusterofs     /> clusterofs /> clusterofs
   ++---|-------++-----------++---------|-++-----------++-|---------++-|
...||   |       ||           ||         | ||           || |         || | ... original data
   ++---|-------++-----------++---------|-++-----------++-|---------++-|
   ++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
        size         size         size         size         size
         \                             /                 /            /
          \                      /              /            /
           \               /            /            /
            ++-----------++-----------++-----------++
        ... ||           ||           ||           || ... compressed clusters
            ++-----------++-----------++-----------++
            ++->cluster<-++->cluster<-++->cluster<-++
                 size         size         size

The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.

In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.

Signed-off-by: Gao Xiang <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
Gao Xiang authored and gregkh committed Jul 27, 2018
1 parent e7e9a30 commit 3883a79
Show file tree
Hide file tree
Showing 6 changed files with 1,418 additions and 2 deletions.
5 changes: 5 additions & 0 deletions drivers/staging/erofs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,12 @@ static int fill_inode(struct inode *inode, int isdir)
}

if (is_inode_layout_compression(inode)) {
#ifdef CONFIG_EROFS_FS_ZIP
inode->i_mapping->a_ops =
&z_erofs_vle_normalaccess_aops;
#else
err = -ENOTSUPP;
#endif
goto out_unlock;
}

Expand Down
6 changes: 6 additions & 0 deletions drivers/staging/erofs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ static inline void erofs_workstation_cleanup_all(struct super_block *sb)
#ifdef CONFIG_EROFS_FS_ZIP
/* hard limit of pages per compressed cluster */
#define Z_EROFS_CLUSTER_MAX_PAGES (CONFIG_EROFS_FS_CLUSTER_PAGE_LIMIT)

/* page count of a compressed cluster */
#define erofs_clusterpages(sbi) ((1 << (sbi)->clusterbits) / PAGE_SIZE)
#endif

typedef u64 erofs_off_t;
Expand Down Expand Up @@ -340,6 +343,9 @@ extern const struct inode_operations erofs_dir_iops;
extern const struct file_operations erofs_dir_fops;

extern const struct address_space_operations erofs_raw_access_aops;
#ifdef CONFIG_EROFS_FS_ZIP
extern const struct address_space_operations z_erofs_vle_normalaccess_aops;
#endif

/*
* Logical to physical block mapping, used by erofs_map_blocks()
Expand Down
25 changes: 25 additions & 0 deletions drivers/staging/erofs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ static int superblock_read(struct super_block *sb)
sbi->xattr_blkaddr = le32_to_cpu(layout->xattr_blkaddr);
#endif
sbi->islotbits = ffs(sizeof(struct erofs_inode_v1)) - 1;
#ifdef CONFIG_EROFS_FS_ZIP
sbi->clusterbits = 12;

if (1 << (sbi->clusterbits - 12) > Z_EROFS_CLUSTER_MAX_PAGES)
errln("clusterbits %u is not supported on this kernel",
sbi->clusterbits);
#endif

sbi->root_nid = le16_to_cpu(layout->root_nid);
sbi->inos = le64_to_cpu(layout->inos);
Expand Down Expand Up @@ -441,6 +448,11 @@ static struct file_system_type erofs_fs_type = {
};
MODULE_ALIAS_FS("erofs");

#ifdef CONFIG_EROFS_FS_ZIP
extern int z_erofs_init_zip_subsystem(void);
extern void z_erofs_exit_zip_subsystem(void);
#endif

static int __init erofs_module_init(void)
{
int err;
Expand All @@ -456,6 +468,12 @@ static int __init erofs_module_init(void)
if (err)
goto shrinker_err;

#ifdef CONFIG_EROFS_FS_ZIP
err = z_erofs_init_zip_subsystem();
if (err)
goto zip_err;
#endif

err = register_filesystem(&erofs_fs_type);
if (err)
goto fs_err;
Expand All @@ -464,6 +482,10 @@ static int __init erofs_module_init(void)
return 0;

fs_err:
#ifdef CONFIG_EROFS_FS_ZIP
z_erofs_exit_zip_subsystem();
zip_err:
#endif
unregister_shrinker(&erofs_shrinker_info);
shrinker_err:
erofs_exit_inode_cache();
Expand All @@ -474,6 +496,9 @@ static int __init erofs_module_init(void)
static void __exit erofs_module_exit(void)
{
unregister_filesystem(&erofs_fs_type);
#ifdef CONFIG_EROFS_FS_ZIP
z_erofs_exit_zip_subsystem();
#endif
unregister_shrinker(&erofs_shrinker_info);
erofs_exit_inode_cache();
infoln("successfully finalize erofs");
Expand Down
Loading

0 comments on commit 3883a79

Please sign in to comment.