mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 08:04:22 +08:00
erofs: introduce fscache-based domain
A new fscache-based shared domain mode is going to be introduced for erofs. In which case, same data blobs in same domain will be shared and reused to reduce on-disk space usage. The implementation of sharing blobs will be introduced in subsequent patches. Signed-off-by: Jia Zhu <zhujia.zj@bytedance.com> Reviewed-by: Jingbo Xu <jefflexu@linux.alibaba.com> Link: https://lore.kernel.org/r/20220918043456.147-4-zhujia.zj@bytedance.com Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
This commit is contained in:
parent
e1de2da0b7
commit
8b7adf1dff
@ -1,10 +1,14 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022, Alibaba Cloud
|
* Copyright (C) 2022, Alibaba Cloud
|
||||||
|
* Copyright (C) 2022, Bytedance Inc. All rights reserved.
|
||||||
*/
|
*/
|
||||||
#include <linux/fscache.h>
|
#include <linux/fscache.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
static DEFINE_MUTEX(erofs_domain_list_lock);
|
||||||
|
static LIST_HEAD(erofs_domain_list);
|
||||||
|
|
||||||
static struct netfs_io_request *erofs_fscache_alloc_request(struct address_space *mapping,
|
static struct netfs_io_request *erofs_fscache_alloc_request(struct address_space *mapping,
|
||||||
loff_t start, size_t len)
|
loff_t start, size_t len)
|
||||||
{
|
{
|
||||||
@ -421,6 +425,99 @@ const struct address_space_operations erofs_fscache_access_aops = {
|
|||||||
.readahead = erofs_fscache_readahead,
|
.readahead = erofs_fscache_readahead,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void erofs_fscache_domain_put(struct erofs_domain *domain)
|
||||||
|
{
|
||||||
|
if (!domain)
|
||||||
|
return;
|
||||||
|
mutex_lock(&erofs_domain_list_lock);
|
||||||
|
if (refcount_dec_and_test(&domain->ref)) {
|
||||||
|
list_del(&domain->list);
|
||||||
|
mutex_unlock(&erofs_domain_list_lock);
|
||||||
|
fscache_relinquish_volume(domain->volume, NULL, false);
|
||||||
|
kfree(domain->domain_id);
|
||||||
|
kfree(domain);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mutex_unlock(&erofs_domain_list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int erofs_fscache_register_volume(struct super_block *sb)
|
||||||
|
{
|
||||||
|
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
||||||
|
char *domain_id = sbi->opt.domain_id;
|
||||||
|
struct fscache_volume *volume;
|
||||||
|
char *name;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
name = kasprintf(GFP_KERNEL, "erofs,%s",
|
||||||
|
domain_id ? domain_id : sbi->opt.fsid);
|
||||||
|
if (!name)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
volume = fscache_acquire_volume(name, NULL, NULL, 0);
|
||||||
|
if (IS_ERR_OR_NULL(volume)) {
|
||||||
|
erofs_err(sb, "failed to register volume for %s", name);
|
||||||
|
ret = volume ? PTR_ERR(volume) : -EOPNOTSUPP;
|
||||||
|
volume = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sbi->volume = volume;
|
||||||
|
kfree(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int erofs_fscache_init_domain(struct super_block *sb)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct erofs_domain *domain;
|
||||||
|
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
||||||
|
|
||||||
|
domain = kzalloc(sizeof(struct erofs_domain), GFP_KERNEL);
|
||||||
|
if (!domain)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
domain->domain_id = kstrdup(sbi->opt.domain_id, GFP_KERNEL);
|
||||||
|
if (!domain->domain_id) {
|
||||||
|
kfree(domain);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = erofs_fscache_register_volume(sb);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
domain->volume = sbi->volume;
|
||||||
|
refcount_set(&domain->ref, 1);
|
||||||
|
list_add(&domain->list, &erofs_domain_list);
|
||||||
|
sbi->domain = domain;
|
||||||
|
return 0;
|
||||||
|
out:
|
||||||
|
kfree(domain->domain_id);
|
||||||
|
kfree(domain);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int erofs_fscache_register_domain(struct super_block *sb)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct erofs_domain *domain;
|
||||||
|
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
||||||
|
|
||||||
|
mutex_lock(&erofs_domain_list_lock);
|
||||||
|
list_for_each_entry(domain, &erofs_domain_list, list) {
|
||||||
|
if (!strcmp(domain->domain_id, sbi->opt.domain_id)) {
|
||||||
|
sbi->domain = domain;
|
||||||
|
sbi->volume = domain->volume;
|
||||||
|
refcount_inc(&domain->ref);
|
||||||
|
mutex_unlock(&erofs_domain_list_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = erofs_fscache_init_domain(sb);
|
||||||
|
mutex_unlock(&erofs_domain_list_lock);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
struct erofs_fscache *erofs_fscache_register_cookie(struct super_block *sb,
|
struct erofs_fscache *erofs_fscache_register_cookie(struct super_block *sb,
|
||||||
char *name, bool need_inode)
|
char *name, bool need_inode)
|
||||||
{
|
{
|
||||||
@ -484,27 +581,19 @@ void erofs_fscache_unregister_cookie(struct erofs_fscache *ctx)
|
|||||||
|
|
||||||
int erofs_fscache_register_fs(struct super_block *sb)
|
int erofs_fscache_register_fs(struct super_block *sb)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
||||||
struct fscache_volume *volume;
|
|
||||||
struct erofs_fscache *fscache;
|
struct erofs_fscache *fscache;
|
||||||
char *name;
|
|
||||||
|
|
||||||
name = kasprintf(GFP_KERNEL, "erofs,%s", sbi->opt.fsid);
|
if (sbi->opt.domain_id)
|
||||||
if (!name)
|
ret = erofs_fscache_register_domain(sb);
|
||||||
return -ENOMEM;
|
else
|
||||||
|
ret = erofs_fscache_register_volume(sb);
|
||||||
volume = fscache_acquire_volume(name, NULL, NULL, 0);
|
if (ret)
|
||||||
if (IS_ERR_OR_NULL(volume)) {
|
return ret;
|
||||||
erofs_err(sb, "failed to register volume for %s", name);
|
|
||||||
kfree(name);
|
|
||||||
return volume ? PTR_ERR(volume) : -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
sbi->volume = volume;
|
|
||||||
kfree(name);
|
|
||||||
|
|
||||||
|
/* acquired domain/volume will be relinquished in kill_sb() on error */
|
||||||
fscache = erofs_fscache_register_cookie(sb, sbi->opt.fsid, true);
|
fscache = erofs_fscache_register_cookie(sb, sbi->opt.fsid, true);
|
||||||
/* acquired volume will be relinquished in kill_sb() */
|
|
||||||
if (IS_ERR(fscache))
|
if (IS_ERR(fscache))
|
||||||
return PTR_ERR(fscache);
|
return PTR_ERR(fscache);
|
||||||
|
|
||||||
@ -517,7 +606,13 @@ void erofs_fscache_unregister_fs(struct super_block *sb)
|
|||||||
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
||||||
|
|
||||||
erofs_fscache_unregister_cookie(sbi->s_fscache);
|
erofs_fscache_unregister_cookie(sbi->s_fscache);
|
||||||
fscache_relinquish_volume(sbi->volume, NULL, false);
|
|
||||||
|
if (sbi->domain)
|
||||||
|
erofs_fscache_domain_put(sbi->domain);
|
||||||
|
else
|
||||||
|
fscache_relinquish_volume(sbi->volume, NULL, false);
|
||||||
|
|
||||||
sbi->s_fscache = NULL;
|
sbi->s_fscache = NULL;
|
||||||
sbi->volume = NULL;
|
sbi->volume = NULL;
|
||||||
|
sbi->domain = NULL;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,7 @@ struct erofs_mount_opts {
|
|||||||
#endif
|
#endif
|
||||||
unsigned int mount_opt;
|
unsigned int mount_opt;
|
||||||
char *fsid;
|
char *fsid;
|
||||||
|
char *domain_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct erofs_dev_context {
|
struct erofs_dev_context {
|
||||||
@ -98,6 +99,13 @@ struct erofs_sb_lz4_info {
|
|||||||
u16 max_pclusterblks;
|
u16 max_pclusterblks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct erofs_domain {
|
||||||
|
refcount_t ref;
|
||||||
|
struct list_head list;
|
||||||
|
struct fscache_volume *volume;
|
||||||
|
char *domain_id;
|
||||||
|
};
|
||||||
|
|
||||||
struct erofs_fscache {
|
struct erofs_fscache {
|
||||||
struct fscache_cookie *cookie;
|
struct fscache_cookie *cookie;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
@ -157,6 +165,7 @@ struct erofs_sb_info {
|
|||||||
/* fscache support */
|
/* fscache support */
|
||||||
struct fscache_volume *volume;
|
struct fscache_volume *volume;
|
||||||
struct erofs_fscache *s_fscache;
|
struct erofs_fscache *s_fscache;
|
||||||
|
struct erofs_domain *domain;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EROFS_SB(sb) ((struct erofs_sb_info *)(sb)->s_fs_info)
|
#define EROFS_SB(sb) ((struct erofs_sb_info *)(sb)->s_fs_info)
|
||||||
|
Loading…
Reference in New Issue
Block a user