Skip to content

Commit

Permalink
staging: erofs: introduce cached decompression
Browse files Browse the repository at this point in the history
This patch adds an optional choice which can be
enabled by users in order to cache both incomplete
ends of compressed clusters as a complement to
the in-place decompression in order to boost random
read, but it costs more memory than the in-place
decompression only.

Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Gao Xiang authored and Greg Kroah-Hartman committed Jul 27, 2018
1 parent 3883a79 commit 105d4ad
Show file tree
Hide file tree
Showing 5 changed files with 427 additions and 1 deletion.
38 changes: 38 additions & 0 deletions drivers/staging/erofs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,41 @@ config EROFS_FS_CLUSTER_PAGE_LIMIT
than 2. Otherwise, the image cannot be mounted
correctly on this kernel.

choice
prompt "EROFS VLE Data Decompression mode"
depends on EROFS_FS_ZIP
default EROFS_FS_ZIP_CACHE_BIPOLAR
help
EROFS supports three options for VLE decompression.
"In-place Decompression Only" consumes the minimum memory
with lowest random read.

"Bipolar Cached Decompression" consumes the maximum memory
with highest random read.

If unsure, select "Bipolar Cached Decompression"

config EROFS_FS_ZIP_NO_CACHE
bool "In-place Decompression Only"
help
Read compressed data into page cache and do in-place
decompression directly.

config EROFS_FS_ZIP_CACHE_UNIPOLAR
bool "Unipolar Cached Decompression"
help
For each request, it caches the last compressed page
for further reading.
It still decompresses in place for the rest compressed pages.

config EROFS_FS_ZIP_CACHE_BIPOLAR
bool "Bipolar Cached Decompression"
help
For each request, it caches the both end compressed pages
for further reading.
It still decompresses in place for the rest compressed pages.

Recommended for performance priority.

endchoice

26 changes: 26 additions & 0 deletions drivers/staging/erofs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ struct erofs_fault_info {
};
#endif

#ifdef CONFIG_EROFS_FS_ZIP_CACHE_BIPOLAR
#define EROFS_FS_ZIP_CACHE_LVL (2)
#elif defined(EROFS_FS_ZIP_CACHE_UNIPOLAR)
#define EROFS_FS_ZIP_CACHE_LVL (1)
#else
#define EROFS_FS_ZIP_CACHE_LVL (0)
#endif

#if (!defined(EROFS_FS_HAS_MANAGED_CACHE) && (EROFS_FS_ZIP_CACHE_LVL > 0))
#define EROFS_FS_HAS_MANAGED_CACHE
#endif

/* EROFS_SUPER_MAGIC_V1 to represent the whole file system */
#define EROFS_SUPER_MAGIC EROFS_SUPER_MAGIC_V1

Expand All @@ -82,6 +94,11 @@ struct erofs_sb_info {

/* the dedicated workstation for compression */
struct radix_tree_root workstn_tree;

#ifdef EROFS_FS_HAS_MANAGED_CACHE
struct inode *managed_cache;
#endif

#endif

u32 build_time_nsec;
Expand Down Expand Up @@ -240,6 +257,15 @@ static inline void erofs_workstation_cleanup_all(struct super_block *sb)
erofs_shrink_workstation(EROFS_SB(sb), ~0UL, true);
}

#ifdef EROFS_FS_HAS_MANAGED_CACHE
#define EROFS_UNALLOCATED_CACHED_PAGE ((void *)0x5F0EF00D)

extern int try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
struct erofs_workgroup *egrp);
extern int try_to_free_cached_page(struct address_space *mapping,
struct page *page);
#endif

#endif

/* we strictly follow PAGE_SIZE and no buffer head yet */
Expand Down
73 changes: 73 additions & 0 deletions drivers/staging/erofs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,63 @@ static int parse_options(struct super_block *sb, char *options)
return 0;
}

#ifdef EROFS_FS_HAS_MANAGED_CACHE

static const struct address_space_operations managed_cache_aops;

static int managed_cache_releasepage(struct page *page, gfp_t gfp_mask)
{
int ret = 1; /* 0 - busy */
struct address_space *const mapping = page->mapping;

BUG_ON(!PageLocked(page));
BUG_ON(mapping->a_ops != &managed_cache_aops);

if (PagePrivate(page))
ret = try_to_free_cached_page(mapping, page);

return ret;
}

static void managed_cache_invalidatepage(struct page *page,
unsigned int offset, unsigned int length)
{
const unsigned int stop = length + offset;

BUG_ON(!PageLocked(page));

/* Check for overflow */
BUG_ON(stop > PAGE_SIZE || stop < length);

if (offset == 0 && stop == PAGE_SIZE)
while (!managed_cache_releasepage(page, GFP_NOFS))
cond_resched();
}

static const struct address_space_operations managed_cache_aops = {
.releasepage = managed_cache_releasepage,
.invalidatepage = managed_cache_invalidatepage,
};

static struct inode *erofs_init_managed_cache(struct super_block *sb)
{
struct inode *inode = new_inode(sb);

if (unlikely(inode == NULL))
return ERR_PTR(-ENOMEM);

set_nlink(inode, 1);
inode->i_size = OFFSET_MAX;

inode->i_mapping->a_ops = &managed_cache_aops;
mapping_set_gfp_mask(inode->i_mapping,
GFP_NOFS | __GFP_HIGHMEM |
__GFP_MOVABLE | __GFP_NOFAIL);
return inode;
}

#endif

static int erofs_read_super(struct super_block *sb,
const char *dev_name, void *data, int silent)
{
Expand Down Expand Up @@ -307,6 +364,14 @@ static int erofs_read_super(struct super_block *sb,
INIT_RADIX_TREE(&sbi->workstn_tree, GFP_ATOMIC);
#endif

#ifdef EROFS_FS_HAS_MANAGED_CACHE
sbi->managed_cache = erofs_init_managed_cache(sb);
if (IS_ERR(sbi->managed_cache)) {
err = PTR_ERR(sbi->managed_cache);
goto err_init_managed_cache;
}
#endif

/* get the root inode */
inode = erofs_iget(sb, ROOT_NID(sbi), true);
if (IS_ERR(inode)) {
Expand Down Expand Up @@ -361,6 +426,10 @@ static int erofs_read_super(struct super_block *sb,
if (sb->s_root == NULL)
iput(inode);
err_iget:
#ifdef EROFS_FS_HAS_MANAGED_CACHE
iput(sbi->managed_cache);
err_init_managed_cache:
#endif
err_parseopt:
err_sbread:
sb->s_fs_info = NULL;
Expand All @@ -386,6 +455,10 @@ static void erofs_put_super(struct super_block *sb)
infoln("unmounted for %s", sbi->dev_name);
__putname(sbi->dev_name);

#ifdef EROFS_FS_HAS_MANAGED_CACHE
iput(sbi->managed_cache);
#endif

mutex_lock(&sbi->umount_mutex);

#ifdef CONFIG_EROFS_FS_ZIP
Expand Down
Loading

0 comments on commit 105d4ad

Please sign in to comment.