Defer initialization of per-CPU workers and registration for CPU hotplug
events until the first mount. Similarly, unregister from hotplug events
and destroy per-CPU workers when the last mount is unmounted.

Signed-off-by: Sandeep Dhavale <dhav...@google.com>
---
 fs/erofs/internal.h |  5 +++++
 fs/erofs/super.c    | 27 +++++++++++++++++++++++++++
 fs/erofs/zdata.c    | 35 +++++++++++++++++++++++------------
 3 files changed, 55 insertions(+), 12 deletions(-)

diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 4ac188d5d894..c88cba4da3eb 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -450,6 +450,8 @@ int z_erofs_gbuf_growsize(unsigned int nrpages);
 int __init z_erofs_gbuf_init(void);
 void z_erofs_gbuf_exit(void);
 int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb);
+int z_erofs_init_workers(void);
+void z_erofs_destroy_workers(void);
 #else
 static inline void erofs_shrinker_register(struct super_block *sb) {}
 static inline void erofs_shrinker_unregister(struct super_block *sb) {}
@@ -458,6 +460,9 @@ static inline void erofs_exit_shrinker(void) {}
 static inline int z_erofs_init_subsystem(void) { return 0; }
 static inline void z_erofs_exit_subsystem(void) {}
 static inline int z_erofs_init_super(struct super_block *sb) { return 0; }
+static inline int z_erofs_init_workers(void) { return 0; };
+static inline  z_erofs_exit_workers(void);
+
 #endif /* !CONFIG_EROFS_FS_ZIP */
 
 #ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index cadec6b1b554..8e8d3a7c8dba 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -17,6 +17,7 @@
 #include <trace/events/erofs.h>
 
 static struct kmem_cache *erofs_inode_cachep __read_mostly;
+static atomic_t erofs_mount_count = ATOMIC_INIT(0);
 
 void _erofs_printk(struct super_block *sb, const char *fmt, ...)
 {
@@ -777,9 +778,28 @@ static const struct fs_context_operations 
erofs_context_ops = {
        .free           = erofs_fc_free,
 };
 
+static inline int erofs_init_zip_workers_if_needed(void)
+{
+       int ret;
+
+       if (atomic_inc_return(&erofs_mount_count) == 1) {
+               ret = z_erofs_init_workers();
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+static inline void erofs_destroy_zip_workers_if_last(void)
+{
+       if (atomic_dec_and_test(&erofs_mount_count))
+               z_erofs_destroy_workers();
+}
+
 static int erofs_init_fs_context(struct fs_context *fc)
 {
        struct erofs_sb_info *sbi;
+       int err;
 
        sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
@@ -790,6 +810,12 @@ static int erofs_init_fs_context(struct fs_context *fc)
                kfree(sbi);
                return -ENOMEM;
        }
+       err = erofs_init_zip_workers_if_needed();
+       if (err) {
+               kfree(sbi->devs);
+               kfree(sbi);
+               return err;
+       }
        fc->s_fs_info = sbi;
 
        idr_init(&sbi->devs->tree);
@@ -823,6 +849,7 @@ static void erofs_kill_sb(struct super_block *sb)
        erofs_fscache_unregister_fs(sb);
        erofs_sb_free(sbi);
        sb->s_fs_info = NULL;
+       erofs_destroy_zip_workers_if_last();
 }
 
 static void erofs_put_super(struct super_block *sb)
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
index 0671184d9cf1..4cd91b798716 100644
--- a/fs/erofs/zdata.c
+++ b/fs/erofs/zdata.c
@@ -403,10 +403,32 @@ static inline int erofs_cpu_hotplug_init(void) { return 
0; }
 static inline void erofs_cpu_hotplug_destroy(void) {}
 #endif
 
-void z_erofs_exit_subsystem(void)
+int z_erofs_init_workers(void)
+{
+       int err;
+
+       err = erofs_init_percpu_workers();
+       if (err)
+               return err;
+
+       err = erofs_cpu_hotplug_init();
+       if (err < 0)
+               goto err_cpuhp_init;
+       return err;
+
+err_cpuhp_init:
+       erofs_destroy_percpu_workers();
+       return err;
+}
+
+void z_erofs_destroy_workers(void)
 {
        erofs_cpu_hotplug_destroy();
        erofs_destroy_percpu_workers();
+}
+
+void z_erofs_exit_subsystem(void)
+{
        destroy_workqueue(z_erofs_workqueue);
        z_erofs_destroy_pcluster_pool();
        z_erofs_exit_decompressor();
@@ -430,19 +452,8 @@ int __init z_erofs_init_subsystem(void)
                goto err_workqueue_init;
        }
 
-       err = erofs_init_percpu_workers();
-       if (err)
-               goto err_pcpu_worker;
-
-       err = erofs_cpu_hotplug_init();
-       if (err < 0)
-               goto err_cpuhp_init;
        return err;
 
-err_cpuhp_init:
-       erofs_destroy_percpu_workers();
-err_pcpu_worker:
-       destroy_workqueue(z_erofs_workqueue);
 err_workqueue_init:
        z_erofs_destroy_pcluster_pool();
 err_pcluster_pool:
-- 
2.49.0.472.ge94155a9ec-goog


Reply via email to