Several erofs filesystems can belong to one domain, and data blobs can
be shared among these erofs filesystems of same domain.
Users could specify domain_id mount option to create or join into a
domain.
Signed-off-by: Jia Zhu <zhujia.zj@bytedance.com>
---
fs/erofs/fscache.c | 90 ++++++++++++++++++++++++++++++++++++++++++++-
fs/erofs/internal.h | 3 ++
2 files changed, 91 insertions(+), 2 deletions(-)
diff --git a/fs/erofs/fscache.c b/fs/erofs/fscache.c
index ff8382df493e..8873a093cf7b 100644
--- a/fs/erofs/fscache.c
+++ b/fs/erofs/fscache.c
@@ -7,6 +7,7 @@
#include "internal.h"
static DEFINE_MUTEX(erofs_domain_list_lock);
+static DEFINE_MUTEX(erofs_domain_cookies_lock);
static LIST_HEAD(erofs_domain_list);
static struct vfsmount *erofs_pseudo_mnt;
@@ -527,8 +528,8 @@ static int erofs_fscache_register_domain(struct super_block *sb)
return err;
}
-struct erofs_fscache *erofs_fscache_register_cookie(struct super_block *sb,
- char *name, bool need_inode)
+struct erofs_fscache *erofs_fscache_acquire_cookie(struct super_block *sb,
+ char *name, bool need_inode)
{
struct fscache_volume *volume = EROFS_SB(sb)->volume;
struct erofs_fscache *ctx;
@@ -577,14 +578,99 @@ struct erofs_fscache *erofs_fscache_register_cookie(struct super_block *sb,
return ERR_PTR(ret);
}
+static
+struct erofs_fscache *erofs_fscache_domain_init_cookie(struct super_block *sb,
+ char *name, bool need_inode)
+{
+ int err;
+ struct inode *inode;
+ struct erofs_fscache *ctx;
+ struct erofs_domain *domain = EROFS_SB(sb)->domain;
+
+ ctx = erofs_fscache_acquire_cookie(sb, name, need_inode);
+ if (IS_ERR(ctx))
+ return ctx;
+
+ ctx->name = kstrdup(name, GFP_KERNEL);
+ if (!ctx->name) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ inode = new_inode(erofs_pseudo_mnt->mnt_sb);
+ if (!inode) {
+ kfree(ctx->name);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ ctx->domain = domain;
+ ctx->anon_inode = inode;
+ inode->i_private = ctx;
+ refcount_inc(&domain->ref);
+ return ctx;
+out:
+ fscache_unuse_cookie(ctx->cookie, NULL, NULL);
+ fscache_relinquish_cookie(ctx->cookie, false);
+ if (need_inode)
+ iput(ctx->inode);
+ kfree(ctx);
+ return ERR_PTR(err);
+}
+
+static
+struct erofs_fscache *erofs_domain_register_cookie(struct super_block *sb,
+ char *name, bool need_inode)
+{
+ struct inode *inode;
+ struct erofs_fscache *ctx;
+ struct erofs_domain *domain = EROFS_SB(sb)->domain;
+ struct super_block *psb = erofs_pseudo_mnt->mnt_sb;
+
+ mutex_lock(&erofs_domain_cookies_lock);
+ list_for_each_entry(inode, &psb->s_inodes, i_sb_list) {
+ ctx = inode->i_private;
+ if (!ctx || ctx->domain != domain || strcmp(ctx->name, name))
+ continue;
+ igrab(inode);
+ mutex_unlock(&erofs_domain_cookies_lock);
+ return ctx;
+ }
+ ctx = erofs_fscache_domain_init_cookie(sb, name, need_inode);
+ mutex_unlock(&erofs_domain_cookies_lock);
+ return ctx;
+}
+
+struct erofs_fscache *erofs_fscache_register_cookie(struct super_block *sb,
+ char *name, bool need_inode)
+{
+ if (EROFS_SB(sb)->opt.domain_id)
+ return erofs_domain_register_cookie(sb, name, need_inode);
+ return erofs_fscache_acquire_cookie(sb, name, need_inode);
+}
+
void erofs_fscache_unregister_cookie(struct erofs_fscache *ctx)
{
+ bool drop;
+ struct erofs_domain *domain;
+
if (!ctx)
return;
+ domain = ctx->domain;
+ if (domain) {
+ mutex_lock(&erofs_domain_cookies_lock);
+ drop = atomic_read(&ctx->anon_inode->i_count) == 1;
+ iput(ctx->anon_inode);
+ mutex_unlock(&erofs_domain_cookies_lock);
+ if (!drop)
+ return;
+ }
fscache_unuse_cookie(ctx->cookie, NULL, NULL);
fscache_relinquish_cookie(ctx->cookie, false);
+ erofs_fscache_domain_put(domain);
iput(ctx->inode);
+ kfree(ctx->name);
kfree(ctx);
}
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 88c1a46867b3..8a6f94b27a23 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -109,6 +109,9 @@ struct erofs_domain {
struct erofs_fscache {
struct fscache_cookie *cookie;
struct inode *inode;
+ struct inode *anon_inode;
+ struct erofs_domain *domain;
+ char *name;
};
struct erofs_sb_info {
--
2.20.1
On 9/15/22 8:42 PM, Jia Zhu wrote:
> +static
> +struct erofs_fscache *erofs_fscache_domain_init_cookie(struct super_block *sb,
> + char *name, bool need_inode)
> +{
> + int err;
> + struct inode *inode;
> + struct erofs_fscache *ctx;
> + struct erofs_domain *domain = EROFS_SB(sb)->domain;
> +
> + ctx = erofs_fscache_acquire_cookie(sb, name, need_inode);
> + if (IS_ERR(ctx))
> + return ctx;
> +
> + ctx->name = kstrdup(name, GFP_KERNEL);
> + if (!ctx->name) {
> + err = -ENOMEM;
> + goto out;
> + }
> +
> + inode = new_inode(erofs_pseudo_mnt->mnt_sb);
> + if (!inode) {
> + kfree(ctx->name);
> + err = -ENOMEM;
> + goto out;
> + }
> +
> + ctx->domain = domain;
> + ctx->anon_inode = inode;
> + inode->i_private = ctx;
> + refcount_inc(&domain->ref);
> + return ctx;
> +out:
> + fscache_unuse_cookie(ctx->cookie, NULL, NULL);
> + fscache_relinquish_cookie(ctx->cookie, false);
> + if (need_inode)
> + iput(ctx->inode);
> + kfree(ctx);
> + return ERR_PTR(err);
Could you please abstract the cleanup logic into one helper? like:
erofs_fscache_relinquish_cookie()
{
fscache_unuse_cookie(ctx->cookie, NULL, NULL);
fscache_relinquish_cookie(ctx->cookie, false);
iput(ctx->inode);
kfree(ctx->name);
kfree(ctx);
}
which could also be called in erofs_fscache_unregister_cookie().
> void erofs_fscache_unregister_cookie(struct erofs_fscache *ctx)
> {
> + bool drop;
> + struct erofs_domain *domain;
> +
> if (!ctx)
> return;
> + domain = ctx->domain;
> + if (domain) {
> + mutex_lock(&erofs_domain_cookies_lock);
> + drop = atomic_read(&ctx->anon_inode->i_count) == 1;
> + iput(ctx->anon_inode);
> + mutex_unlock(&erofs_domain_cookies_lock);
> + if (!drop)
> + return;
> + }
>
> fscache_unuse_cookie(ctx->cookie, NULL, NULL);
> fscache_relinquish_cookie(ctx->cookie, false);
> + erofs_fscache_domain_put(domain);
> iput(ctx->inode);
> + kfree(ctx->name);
> kfree(ctx);
> }
--
Thanks,
Jingbo
© 2016 - 2026 Red Hat, Inc.