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
|
||||
/*
|
||||
* Copyright (C) 2022, Alibaba Cloud
|
||||
* Copyright (C) 2022, Bytedance Inc. All rights reserved.
|
||||
*/
|
||||
#include <linux/fscache.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,
|
||||
loff_t start, size_t len)
|
||||
{
|
||||
@ -421,6 +425,99 @@ const struct address_space_operations erofs_fscache_access_aops = {
|
||||
.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,
|
||||
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 ret;
|
||||
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
||||
struct fscache_volume *volume;
|
||||
struct erofs_fscache *fscache;
|
||||
char *name;
|
||||
|
||||
name = kasprintf(GFP_KERNEL, "erofs,%s", 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);
|
||||
kfree(name);
|
||||
return volume ? PTR_ERR(volume) : -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
sbi->volume = volume;
|
||||
kfree(name);
|
||||
if (sbi->opt.domain_id)
|
||||
ret = erofs_fscache_register_domain(sb);
|
||||
else
|
||||
ret = erofs_fscache_register_volume(sb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* acquired domain/volume will be relinquished in kill_sb() on error */
|
||||
fscache = erofs_fscache_register_cookie(sb, sbi->opt.fsid, true);
|
||||
/* acquired volume will be relinquished in kill_sb() */
|
||||
if (IS_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);
|
||||
|
||||
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->volume = NULL;
|
||||
sbi->domain = NULL;
|
||||
}
|
||||
|
@ -76,6 +76,7 @@ struct erofs_mount_opts {
|
||||
#endif
|
||||
unsigned int mount_opt;
|
||||
char *fsid;
|
||||
char *domain_id;
|
||||
};
|
||||
|
||||
struct erofs_dev_context {
|
||||
@ -98,6 +99,13 @@ struct erofs_sb_lz4_info {
|
||||
u16 max_pclusterblks;
|
||||
};
|
||||
|
||||
struct erofs_domain {
|
||||
refcount_t ref;
|
||||
struct list_head list;
|
||||
struct fscache_volume *volume;
|
||||
char *domain_id;
|
||||
};
|
||||
|
||||
struct erofs_fscache {
|
||||
struct fscache_cookie *cookie;
|
||||
struct inode *inode;
|
||||
@ -157,6 +165,7 @@ struct erofs_sb_info {
|
||||
/* fscache support */
|
||||
struct fscache_volume *volume;
|
||||
struct erofs_fscache *s_fscache;
|
||||
struct erofs_domain *domain;
|
||||
};
|
||||
|
||||
#define EROFS_SB(sb) ((struct erofs_sb_info *)(sb)->s_fs_info)
|
||||
|
Loading…
Reference in New Issue
Block a user