Skip to content

Commit

Permalink
erofs: introduce fscache-based domain
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Jingbo Xu <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Gao Xiang <[email protected]>
  • Loading branch information
Jia Zhu authored and hsiangkao committed Sep 20, 2022
1 parent e1de2da commit 8b7adf1
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 17 deletions.
129 changes: 112 additions & 17 deletions fs/erofs/fscache.c
Original file line number Diff line number Diff line change
@@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);

Expand All @@ -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;
}
9 changes: 9 additions & 0 deletions fs/erofs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ struct erofs_mount_opts {
#endif
unsigned int mount_opt;
char *fsid;
char *domain_id;
};

struct erofs_dev_context {
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 8b7adf1

Please sign in to comment.