Commit 40452ffc authored by Huang Jianan's avatar Huang Jianan Committed by Gao Xiang

erofs: add sysfs node to control sync decompression strategy

Although readpage is a synchronous path, there will be no additional
kworker scheduling overhead in non-atomic contexts together with
dm-verity.

Let's add a sysfs node to disable sync decompression as an option.

Link: https://lore.kernel.org/r/20211206143552.8384-1-huangjianan@oppo.comReviewed-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarHuang Jianan <huangjianan@oppo.com>
Signed-off-by: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
parent 168e9a76
...@@ -5,3 +5,12 @@ Description: Shows all enabled kernel features. ...@@ -5,3 +5,12 @@ Description: Shows all enabled kernel features.
Supported features: Supported features:
zero_padding, compr_cfgs, big_pcluster, chunked_file, zero_padding, compr_cfgs, big_pcluster, chunked_file,
device_table, compr_head2, sb_chksum. device_table, compr_head2, sb_chksum.
What: /sys/fs/erofs/<disk>/sync_decompress
Date: November 2021
Contact: "Huang Jianan" <huangjianan@oppo.com>
Description: Control strategy of sync decompression
- 0 (default, auto): enable for readpage, and enable for
readahead on atomic contexts only,
- 1 (force on): enable for readpage and readahead.
- 2 (force off): disable for all situations.
...@@ -56,12 +56,18 @@ struct erofs_device_info { ...@@ -56,12 +56,18 @@ struct erofs_device_info {
u32 mapped_blkaddr; u32 mapped_blkaddr;
}; };
enum {
EROFS_SYNC_DECOMPRESS_AUTO,
EROFS_SYNC_DECOMPRESS_FORCE_ON,
EROFS_SYNC_DECOMPRESS_FORCE_OFF
};
struct erofs_mount_opts { struct erofs_mount_opts {
#ifdef CONFIG_EROFS_FS_ZIP #ifdef CONFIG_EROFS_FS_ZIP
/* current strategy of how to use managed cache */ /* current strategy of how to use managed cache */
unsigned char cache_strategy; unsigned char cache_strategy;
/* strategy of sync decompression (false - auto, true - force on) */ /* strategy of sync decompression (0 - auto, 1 - force on, 2 - force off) */
bool readahead_sync_decompress; unsigned int sync_decompress;
/* threshold for decompression synchronously */ /* threshold for decompression synchronously */
unsigned int max_sync_decompress_pages; unsigned int max_sync_decompress_pages;
......
...@@ -423,7 +423,7 @@ static void erofs_default_options(struct erofs_fs_context *ctx) ...@@ -423,7 +423,7 @@ static void erofs_default_options(struct erofs_fs_context *ctx)
#ifdef CONFIG_EROFS_FS_ZIP #ifdef CONFIG_EROFS_FS_ZIP
ctx->opt.cache_strategy = EROFS_ZIP_CACHE_READAROUND; ctx->opt.cache_strategy = EROFS_ZIP_CACHE_READAROUND;
ctx->opt.max_sync_decompress_pages = 3; ctx->opt.max_sync_decompress_pages = 3;
ctx->opt.readahead_sync_decompress = false; ctx->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_AUTO;
#endif #endif
#ifdef CONFIG_EROFS_FS_XATTR #ifdef CONFIG_EROFS_FS_XATTR
set_opt(&ctx->opt, XATTR_USER); set_opt(&ctx->opt, XATTR_USER);
......
...@@ -16,6 +16,7 @@ enum { ...@@ -16,6 +16,7 @@ enum {
enum { enum {
struct_erofs_sb_info, struct_erofs_sb_info,
struct_erofs_mount_opts,
}; };
struct erofs_attr { struct erofs_attr {
...@@ -54,7 +55,14 @@ static struct erofs_attr erofs_attr_##_name = { \ ...@@ -54,7 +55,14 @@ static struct erofs_attr erofs_attr_##_name = { \
#define ATTR_LIST(name) (&erofs_attr_##name.attr) #define ATTR_LIST(name) (&erofs_attr_##name.attr)
#ifdef CONFIG_EROFS_FS_ZIP
EROFS_ATTR_RW_UI(sync_decompress, erofs_mount_opts);
#endif
static struct attribute *erofs_attrs[] = { static struct attribute *erofs_attrs[] = {
#ifdef CONFIG_EROFS_FS_ZIP
ATTR_LIST(sync_decompress),
#endif
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(erofs); ATTRIBUTE_GROUPS(erofs);
...@@ -85,6 +93,8 @@ static unsigned char *__struct_ptr(struct erofs_sb_info *sbi, ...@@ -85,6 +93,8 @@ static unsigned char *__struct_ptr(struct erofs_sb_info *sbi,
{ {
if (struct_type == struct_erofs_sb_info) if (struct_type == struct_erofs_sb_info)
return (unsigned char *)sbi + offset; return (unsigned char *)sbi + offset;
if (struct_type == struct_erofs_mount_opts)
return (unsigned char *)&sbi->opt + offset;
return NULL; return NULL;
} }
...@@ -130,6 +140,11 @@ static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr, ...@@ -130,6 +140,11 @@ static ssize_t erofs_attr_store(struct kobject *kobj, struct attribute *attr,
return ret; return ret;
if (t != (unsigned int)t) if (t != (unsigned int)t)
return -ERANGE; return -ERANGE;
#ifdef CONFIG_EROFS_FS_ZIP
if (!strcmp(a->attr.name, "sync_decompress") &&
(t > EROFS_SYNC_DECOMPRESS_FORCE_OFF))
return -EINVAL;
#endif
*(unsigned int *)ptr = t; *(unsigned int *)ptr = t;
return len; return len;
case attr_pointer_bool: case attr_pointer_bool:
......
...@@ -762,6 +762,21 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, ...@@ -762,6 +762,21 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
goto out; goto out;
} }
static bool z_erofs_get_sync_decompress_policy(struct erofs_sb_info *sbi,
unsigned int readahead_pages)
{
/* auto: enable for readpage, disable for readahead */
if ((sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) &&
!readahead_pages)
return true;
if ((sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_FORCE_ON) &&
(readahead_pages <= sbi->opt.max_sync_decompress_pages))
return true;
return false;
}
static void z_erofs_decompressqueue_work(struct work_struct *work); static void z_erofs_decompressqueue_work(struct work_struct *work);
static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
bool sync, int bios) bool sync, int bios)
...@@ -784,7 +799,9 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, ...@@ -784,7 +799,9 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
/* Use workqueue and sync decompression for atomic contexts only */ /* Use workqueue and sync decompression for atomic contexts only */
if (in_atomic() || irqs_disabled()) { if (in_atomic() || irqs_disabled()) {
queue_work(z_erofs_workqueue, &io->u.work); queue_work(z_erofs_workqueue, &io->u.work);
sbi->opt.readahead_sync_decompress = true; /* enable sync decompression for readahead */
if (sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO)
sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON;
return; return;
} }
z_erofs_decompressqueue_work(&io->u.work); z_erofs_decompressqueue_work(&io->u.work);
...@@ -1435,6 +1452,7 @@ static void z_erofs_pcluster_readmore(struct z_erofs_decompress_frontend *f, ...@@ -1435,6 +1452,7 @@ static void z_erofs_pcluster_readmore(struct z_erofs_decompress_frontend *f,
static int z_erofs_readpage(struct file *file, struct page *page) static int z_erofs_readpage(struct file *file, struct page *page)
{ {
struct inode *const inode = page->mapping->host; struct inode *const inode = page->mapping->host;
struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
struct z_erofs_decompress_frontend f = DECOMPRESS_FRONTEND_INIT(inode); struct z_erofs_decompress_frontend f = DECOMPRESS_FRONTEND_INIT(inode);
struct page *pagepool = NULL; struct page *pagepool = NULL;
int err; int err;
...@@ -1450,7 +1468,8 @@ static int z_erofs_readpage(struct file *file, struct page *page) ...@@ -1450,7 +1468,8 @@ static int z_erofs_readpage(struct file *file, struct page *page)
(void)z_erofs_collector_end(&f.clt); (void)z_erofs_collector_end(&f.clt);
/* if some compressed cluster ready, need submit them anyway */ /* if some compressed cluster ready, need submit them anyway */
z_erofs_runqueue(inode->i_sb, &f, &pagepool, true); z_erofs_runqueue(inode->i_sb, &f, &pagepool,
z_erofs_get_sync_decompress_policy(sbi, 0));
if (err) if (err)
erofs_err(inode->i_sb, "failed to read, err [%d]", err); erofs_err(inode->i_sb, "failed to read, err [%d]", err);
...@@ -1501,8 +1520,7 @@ static void z_erofs_readahead(struct readahead_control *rac) ...@@ -1501,8 +1520,7 @@ static void z_erofs_readahead(struct readahead_control *rac)
(void)z_erofs_collector_end(&f.clt); (void)z_erofs_collector_end(&f.clt);
z_erofs_runqueue(inode->i_sb, &f, &pagepool, z_erofs_runqueue(inode->i_sb, &f, &pagepool,
sbi->opt.readahead_sync_decompress && z_erofs_get_sync_decompress_policy(sbi, nr_pages));
nr_pages <= sbi->opt.max_sync_decompress_pages);
if (f.map.mpage) if (f.map.mpage)
put_page(f.map.mpage); put_page(f.map.mpage);
erofs_release_pages(&pagepool); erofs_release_pages(&pagepool);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment