erofs: maintain cookies of share domain in self-contained list
authorJingbo Xu <jefflexu@linux.alibaba.com>
Thu, 9 Feb 2023 06:39:11 +0000 (14:39 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Wed, 15 Feb 2023 00:11:27 +0000 (08:11 +0800)
We'd better not touch sb->s_inodes list and inode->i_count directly.
Let's maintain cookies of share domain in a self-contained list in erofs.

Besides, relinquish cookie with the mutex held.  Otherwise if a cookie
is registered when the old cookie with the same name in the same domain
has been removed from the list but not relinquished yet, fscache may
complain "Duplicate cookie detected".

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Jia Zhu <zhujia.zj@bytedance.com>
Link: https://lore.kernel.org/r/20230209063913.46341-3-jefflexu@linux.alibaba.com
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
fs/erofs/fscache.c
fs/erofs/internal.h

index 9658cf8689d9dc1b5d4817f239bd1d29a659c3bd..0ee08e51c4a65ca8d8c79361c8c2ea9e732031f5 100644 (file)
@@ -9,6 +9,7 @@
 static DEFINE_MUTEX(erofs_domain_list_lock);
 static DEFINE_MUTEX(erofs_domain_cookies_lock);
 static LIST_HEAD(erofs_domain_list);
+static LIST_HEAD(erofs_domain_cookies_list);
 static struct vfsmount *erofs_pseudo_mnt;
 
 struct erofs_fscache_request {
@@ -318,8 +319,6 @@ const struct address_space_operations erofs_fscache_access_aops = {
 
 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);
@@ -434,6 +433,8 @@ struct erofs_fscache *erofs_fscache_acquire_cookie(struct super_block *sb,
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return ERR_PTR(-ENOMEM);
+       INIT_LIST_HEAD(&ctx->node);
+       refcount_set(&ctx->ref, 1);
 
        cookie = fscache_acquire_cookie(volume, FSCACHE_ADV_WANT_CACHE_SIZE,
                                        name, strlen(name), NULL, 0, 0);
@@ -479,6 +480,7 @@ static void erofs_fscache_relinquish_cookie(struct erofs_fscache *ctx)
        fscache_unuse_cookie(ctx->cookie, NULL, NULL);
        fscache_relinquish_cookie(ctx->cookie, false);
        iput(ctx->inode);
+       iput(ctx->anon_inode);
        kfree(ctx->name);
        kfree(ctx);
 }
@@ -511,6 +513,7 @@ struct erofs_fscache *erofs_fscache_domain_init_cookie(struct super_block *sb,
 
        ctx->domain = domain;
        ctx->anon_inode = inode;
+       list_add(&ctx->node, &erofs_domain_cookies_list);
        inode->i_private = ctx;
        refcount_inc(&domain->ref);
        return ctx;
@@ -524,29 +527,23 @@ struct erofs_fscache *erofs_domain_register_cookie(struct super_block *sb,
                                                   char *name,
                                                   unsigned int flags)
 {
-       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);
-       spin_lock(&psb->s_inode_list_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))
+       list_for_each_entry(ctx, &erofs_domain_cookies_list, node) {
+               if (ctx->domain != domain || strcmp(ctx->name, name))
                        continue;
                if (!(flags & EROFS_REG_COOKIE_NEED_NOEXIST)) {
-                       igrab(inode);
+                       refcount_inc(&ctx->ref);
                } else {
                        erofs_err(sb, "%s already exists in domain %s", name,
                                  domain->domain_id);
                        ctx = ERR_PTR(-EEXIST);
                }
-               spin_unlock(&psb->s_inode_list_lock);
                mutex_unlock(&erofs_domain_cookies_lock);
                return ctx;
        }
-       spin_unlock(&psb->s_inode_list_lock);
        ctx = erofs_fscache_domain_init_cookie(sb, name, flags);
        mutex_unlock(&erofs_domain_cookies_lock);
        return ctx;
@@ -563,23 +560,22 @@ struct erofs_fscache *erofs_fscache_register_cookie(struct super_block *sb,
 
 void erofs_fscache_unregister_cookie(struct erofs_fscache *ctx)
 {
-       bool drop;
-       struct erofs_domain *domain;
+       struct erofs_domain *domain = NULL;
 
        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;
-       }
+       if (!ctx->domain)
+               return erofs_fscache_relinquish_cookie(ctx);
 
-       erofs_fscache_relinquish_cookie(ctx);
-       erofs_fscache_domain_put(domain);
+       mutex_lock(&erofs_domain_cookies_lock);
+       if (refcount_dec_and_test(&ctx->ref)) {
+               domain = ctx->domain;
+               list_del(&ctx->node);
+               erofs_fscache_relinquish_cookie(ctx);
+       }
+       mutex_unlock(&erofs_domain_cookies_lock);
+       if (domain)
+               erofs_fscache_domain_put(domain);
 }
 
 int erofs_fscache_register_fs(struct super_block *sb)
index 8a6ae820cd6de4d2567194afaa9971f4705c81dc..4c190b1b9a9e0e1872b579a362ead1b9fee8c6d3 100644 (file)
@@ -109,7 +109,11 @@ struct erofs_fscache {
        struct fscache_cookie *cookie;
        struct inode *inode;
        struct inode *anon_inode;
+
+       /* used for share domain mode */
        struct erofs_domain *domain;
+       struct list_head node;
+       refcount_t ref;
        char *name;
 };