From: Youling Tang <youling.tang@linux.dev>
To: Arnd Bergmann <arnd@arndb.de>,
Luis Chamberlain <mcgrof@kernel.org>, Chris Mason <clm@fb.com>,
Josef Bacik <josef@toxicpanda.com>,
David Sterba <dsterba@suse.com>,
tytso@mit.edu, Andreas Dilger <adilger.kernel@dilger.ca>,
Jaegeuk Kim <jaegeuk@kernel.org>, Chao Yu <chao@kernel.org>,
Christoph Hellwig <hch@infradead.org>
Cc: linux-arch@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-modules@vger.kernel.org, linux-btrfs@vger.kernel.org,
linux-ext4@vger.kernel.org,
linux-f2fs-devel@lists.sourceforge.net, youling.tang@linux.dev,
Youling Tang <tangyouling@kylinos.cn>
Subject: [PATCH 1/4] module: Add module_subinit{_noexit} and module_subeixt helper macros
Date: Tue, 23 Jul 2024 16:32:36 +0800 [thread overview]
Message-ID: <20240723083239.41533-2-youling.tang@linux.dev> (raw)
In-Reply-To: <20240723083239.41533-1-youling.tang@linux.dev>
From: Youling Tang <tangyouling@kylinos.cn>
In theory init/exit should match their sequence, thus normally they should
look like this:
-------------------------+------------------------
init_A(); |
init_B(); |
init_C(); |
| exit_C();
| exit_B();
| exit_A();
Providing module_subinit{_noexit} and module_subeixt helps macros ensure
that modules init/exit match their order, while also simplifying the code.
The three macros are defined as follows:
- module_subinit(initfn, exitfn,rollback)
- module_subinit_noexit(initfn, rollback)
- module_subexit(rollback)
`initfn` is the initialization function and `exitfn` is the corresponding
exit function.
Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
---
include/asm-generic/vmlinux.lds.h | 5 +++
include/linux/init.h | 62 ++++++++++++++++++++++++++++++-
include/linux/module.h | 22 +++++++++++
3 files changed, 88 insertions(+), 1 deletion(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 677315e51e54..48ccac7c6448 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -927,6 +927,10 @@
INIT_CALLS_LEVEL(7) \
__initcall_end = .;
+#define SUBINIT_CALL \
+ *(.subinitcall.init) \
+ *(.subexitcall.exit)
+
#define CON_INITCALL \
BOUNDED_SECTION_POST_LABEL(.con_initcall.init, __con_initcall, _start, _end)
@@ -1155,6 +1159,7 @@
INIT_DATA \
INIT_SETUP(initsetup_align) \
INIT_CALLS \
+ SUBINIT_CALL \
CON_INITCALL \
INIT_RAM_FS \
}
diff --git a/include/linux/init.h b/include/linux/init.h
index ee1309473bc6..e8689ff2cb6c 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -55,6 +55,9 @@
#define __exitdata __section(".exit.data")
#define __exit_call __used __section(".exitcall.exit")
+#define __subinit_call __used __section(".subinitcall.init")
+#define __subexit_call __used __section(".subexitcall.exit")
+
/*
* modpost check for section mismatches during the kernel build.
* A section mismatch happens when there are references from a
@@ -115,6 +118,9 @@
typedef int (*initcall_t)(void);
typedef void (*exitcall_t)(void);
+typedef int (*subinitcall_t)(void);
+typedef void (*subexitcall_t)(void);
+
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
typedef int initcall_entry_t;
@@ -183,7 +189,61 @@ extern struct module __this_module;
#endif
#endif
-
+
+#ifndef __ASSEMBLY__
+struct subexitcall_rollback {
+ /*
+ * Records the address of the first sub-initialization function in the
+ * ".subexitcall.exit" section
+ */
+ unsigned long first_addr;
+ int ncalls;
+};
+
+static inline void __subexitcall_rollback(struct subexitcall_rollback *r)
+{
+ unsigned long addr = r->first_addr - sizeof(r->first_addr) * (r->ncalls - 1);
+
+ for (; r->ncalls--; addr += sizeof(r->first_addr)) {
+ unsigned long *tmp = (void *)addr;
+ subexitcall_t fn = (subexitcall_t)*tmp;
+ fn();
+ }
+}
+
+static inline void set_rollback_ncalls(struct subexitcall_rollback *r)
+{
+ r->ncalls++;
+}
+
+static inline void set_rollback_first_addr(struct subexitcall_rollback *rollback,
+ unsigned long addr)
+{
+ if (!rollback->first_addr)
+ rollback->first_addr = addr;
+}
+
+#define __subinitcall_noexit(initfn, rollback) \
+do { \
+ static subinitcall_t __subinitcall_##initfn __subinit_call = initfn; \
+ int _ret; \
+ _ret = initfn(); \
+ if (_ret < 0) { \
+ __subexitcall_rollback(rollback); \
+ return _ret; \
+ } \
+} while (0)
+
+#define __subinitcall(initfn, exitfn, rollback) \
+do { \
+ static subexitcall_t __subexitcall_##exitfn __subexit_call = exitfn; \
+ set_rollback_first_addr(rollback, (unsigned long)&__subexitcall_##exitfn); \
+ __subinitcall_noexit(initfn, rollback); \
+ set_rollback_ncalls(rollback); \
+} while (0)
+
+#endif /* !__ASSEMBLY__ */
+
#ifndef MODULE
#ifndef __ASSEMBLY__
diff --git a/include/linux/module.h b/include/linux/module.h
index 4213d8993cd8..95f7c60dede9 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -76,6 +76,28 @@ extern struct module_attribute module_uevent;
extern int init_module(void);
extern void cleanup_module(void);
+/*
+ * module_subinit() - Called when the driver is subinitialized
+ * @initfn: The subinitialization function that is called
+ * @exitfn: Corresponding exit function
+ * @rollback: Record information when the subinitialization failed
+ * or the driver was removed
+ *
+ * Use module_subinit_noexit() when there is only an subinitialization
+ * function but no corresponding exit function.
+ */
+#define module_subinit(initfn, exitfn, rollback) \
+ __subinitcall(initfn, exitfn, rollback);
+
+#define module_subinit_noexit(initfn, rollback) \
+ __subinitcall_noexit(initfn, rollback);
+
+/*
+ * module_subexit() - Called when the driver exits
+ */
+#define module_subexit(rollback) \
+ __subexitcall_rollback(rollback);
+
#ifndef MODULE
/**
* module_init() - driver initialization entry point
--
2.34.1
WARNING: multiple messages have this Message-ID (diff)
From: Youling Tang <youling.tang@linux.dev>
To: Arnd Bergmann <arnd@arndb.de>,
Luis Chamberlain <mcgrof@kernel.org>, Chris Mason <clm@fb.com>,
Josef Bacik <josef@toxicpanda.com>,
David Sterba <dsterba@suse.com>,
tytso@mit.edu, Andreas Dilger <adilger.kernel@dilger.ca>,
Jaegeuk Kim <jaegeuk@kernel.org>, Chao Yu <chao@kernel.org>,
Christoph Hellwig <hch@infradead.org>
Cc: linux-arch@vger.kernel.org, Youling Tang <tangyouling@kylinos.cn>,
linux-kernel@vger.kernel.org,
linux-f2fs-devel@lists.sourceforge.net,
linux-modules@vger.kernel.org, youling.tang@linux.dev,
linux-ext4@vger.kernel.org, linux-btrfs@vger.kernel.org
Subject: [f2fs-dev] [PATCH 1/4] module: Add module_subinit{_noexit} and module_subeixt helper macros
Date: Tue, 23 Jul 2024 16:32:36 +0800 [thread overview]
Message-ID: <20240723083239.41533-2-youling.tang@linux.dev> (raw)
In-Reply-To: <20240723083239.41533-1-youling.tang@linux.dev>
From: Youling Tang <tangyouling@kylinos.cn>
In theory init/exit should match their sequence, thus normally they should
look like this:
-------------------------+------------------------
init_A(); |
init_B(); |
init_C(); |
| exit_C();
| exit_B();
| exit_A();
Providing module_subinit{_noexit} and module_subeixt helps macros ensure
that modules init/exit match their order, while also simplifying the code.
The three macros are defined as follows:
- module_subinit(initfn, exitfn,rollback)
- module_subinit_noexit(initfn, rollback)
- module_subexit(rollback)
`initfn` is the initialization function and `exitfn` is the corresponding
exit function.
Signed-off-by: Youling Tang <tangyouling@kylinos.cn>
---
include/asm-generic/vmlinux.lds.h | 5 +++
include/linux/init.h | 62 ++++++++++++++++++++++++++++++-
include/linux/module.h | 22 +++++++++++
3 files changed, 88 insertions(+), 1 deletion(-)
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 677315e51e54..48ccac7c6448 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -927,6 +927,10 @@
INIT_CALLS_LEVEL(7) \
__initcall_end = .;
+#define SUBINIT_CALL \
+ *(.subinitcall.init) \
+ *(.subexitcall.exit)
+
#define CON_INITCALL \
BOUNDED_SECTION_POST_LABEL(.con_initcall.init, __con_initcall, _start, _end)
@@ -1155,6 +1159,7 @@
INIT_DATA \
INIT_SETUP(initsetup_align) \
INIT_CALLS \
+ SUBINIT_CALL \
CON_INITCALL \
INIT_RAM_FS \
}
diff --git a/include/linux/init.h b/include/linux/init.h
index ee1309473bc6..e8689ff2cb6c 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -55,6 +55,9 @@
#define __exitdata __section(".exit.data")
#define __exit_call __used __section(".exitcall.exit")
+#define __subinit_call __used __section(".subinitcall.init")
+#define __subexit_call __used __section(".subexitcall.exit")
+
/*
* modpost check for section mismatches during the kernel build.
* A section mismatch happens when there are references from a
@@ -115,6 +118,9 @@
typedef int (*initcall_t)(void);
typedef void (*exitcall_t)(void);
+typedef int (*subinitcall_t)(void);
+typedef void (*subexitcall_t)(void);
+
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
typedef int initcall_entry_t;
@@ -183,7 +189,61 @@ extern struct module __this_module;
#endif
#endif
-
+
+#ifndef __ASSEMBLY__
+struct subexitcall_rollback {
+ /*
+ * Records the address of the first sub-initialization function in the
+ * ".subexitcall.exit" section
+ */
+ unsigned long first_addr;
+ int ncalls;
+};
+
+static inline void __subexitcall_rollback(struct subexitcall_rollback *r)
+{
+ unsigned long addr = r->first_addr - sizeof(r->first_addr) * (r->ncalls - 1);
+
+ for (; r->ncalls--; addr += sizeof(r->first_addr)) {
+ unsigned long *tmp = (void *)addr;
+ subexitcall_t fn = (subexitcall_t)*tmp;
+ fn();
+ }
+}
+
+static inline void set_rollback_ncalls(struct subexitcall_rollback *r)
+{
+ r->ncalls++;
+}
+
+static inline void set_rollback_first_addr(struct subexitcall_rollback *rollback,
+ unsigned long addr)
+{
+ if (!rollback->first_addr)
+ rollback->first_addr = addr;
+}
+
+#define __subinitcall_noexit(initfn, rollback) \
+do { \
+ static subinitcall_t __subinitcall_##initfn __subinit_call = initfn; \
+ int _ret; \
+ _ret = initfn(); \
+ if (_ret < 0) { \
+ __subexitcall_rollback(rollback); \
+ return _ret; \
+ } \
+} while (0)
+
+#define __subinitcall(initfn, exitfn, rollback) \
+do { \
+ static subexitcall_t __subexitcall_##exitfn __subexit_call = exitfn; \
+ set_rollback_first_addr(rollback, (unsigned long)&__subexitcall_##exitfn); \
+ __subinitcall_noexit(initfn, rollback); \
+ set_rollback_ncalls(rollback); \
+} while (0)
+
+#endif /* !__ASSEMBLY__ */
+
#ifndef MODULE
#ifndef __ASSEMBLY__
diff --git a/include/linux/module.h b/include/linux/module.h
index 4213d8993cd8..95f7c60dede9 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -76,6 +76,28 @@ extern struct module_attribute module_uevent;
extern int init_module(void);
extern void cleanup_module(void);
+/*
+ * module_subinit() - Called when the driver is subinitialized
+ * @initfn: The subinitialization function that is called
+ * @exitfn: Corresponding exit function
+ * @rollback: Record information when the subinitialization failed
+ * or the driver was removed
+ *
+ * Use module_subinit_noexit() when there is only an subinitialization
+ * function but no corresponding exit function.
+ */
+#define module_subinit(initfn, exitfn, rollback) \
+ __subinitcall(initfn, exitfn, rollback);
+
+#define module_subinit_noexit(initfn, rollback) \
+ __subinitcall_noexit(initfn, rollback);
+
+/*
+ * module_subexit() - Called when the driver exits
+ */
+#define module_subexit(rollback) \
+ __subexitcall_rollback(rollback);
+
#ifndef MODULE
/**
* module_init() - driver initialization entry point
--
2.34.1
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
next prev parent reply other threads:[~2024-07-23 8:33 UTC|newest]
Thread overview: 64+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-23 8:32 [PATCH 0/4] Add module_subinit{_noexit} and module_subeixt helper macros Youling Tang
2024-07-23 8:32 ` [f2fs-dev] " Youling Tang
2024-07-23 8:32 ` Youling Tang [this message]
2024-07-23 8:32 ` [f2fs-dev] [PATCH 1/4] module: " Youling Tang
2024-07-23 9:58 ` Mika Penttilä
2024-07-23 9:58 ` [f2fs-dev] " Mika Penttilä
2024-07-24 1:20 ` Youling Tang
2024-07-24 1:20 ` [f2fs-dev] " Youling Tang
2024-07-23 14:33 ` Christoph Hellwig
2024-07-23 14:33 ` [f2fs-dev] " Christoph Hellwig
2024-07-24 1:57 ` Youling Tang
2024-07-24 1:57 ` [f2fs-dev] " Youling Tang
2024-07-24 15:43 ` Christoph Hellwig
2024-07-24 15:43 ` [f2fs-dev] " Christoph Hellwig
2024-07-25 3:01 ` Youling Tang
2024-07-25 3:01 ` [f2fs-dev] " Youling Tang
2024-07-25 14:39 ` Christoph Hellwig
2024-07-25 14:39 ` [f2fs-dev] " Christoph Hellwig
2024-07-25 15:30 ` Arnd Bergmann
2024-07-25 15:30 ` [f2fs-dev] " Arnd Bergmann
2024-07-25 15:34 ` Christoph Hellwig
2024-07-25 15:34 ` [f2fs-dev] " Christoph Hellwig
2024-07-25 17:14 ` Goffredo Baroncelli
2024-07-25 17:14 ` [f2fs-dev] " Goffredo Baroncelli via Linux-f2fs-devel
2024-07-25 19:46 ` Christoph Hellwig
2024-07-25 19:46 ` [f2fs-dev] " Christoph Hellwig
2024-07-26 8:54 ` Youling Tang
2024-07-26 8:54 ` [f2fs-dev] " Youling Tang
2024-07-26 14:04 ` Christoph Hellwig
2024-07-26 14:04 ` [f2fs-dev] " Christoph Hellwig
2024-07-26 15:22 ` David Sterba
2024-07-26 15:22 ` [f2fs-dev] " David Sterba
2024-07-26 17:58 ` Theodore Ts'o
2024-07-26 17:58 ` [f2fs-dev] " Theodore Ts'o
2024-07-26 18:09 ` Christoph Hellwig
2024-07-26 18:09 ` [f2fs-dev] " Christoph Hellwig
2024-07-26 22:45 ` David Sterba
2024-07-26 22:45 ` [f2fs-dev] " David Sterba
2024-07-27 14:52 ` Theodore Ts'o
2024-07-27 14:52 ` [f2fs-dev] " Theodore Ts'o
2024-07-29 1:46 ` Youling Tang
2024-07-29 1:46 ` [f2fs-dev] " Youling Tang
2024-07-29 2:44 ` Theodore Ts'o
2024-07-29 2:44 ` [f2fs-dev] " Theodore Ts'o
2024-07-29 3:01 ` Youling Tang
2024-07-29 3:01 ` [f2fs-dev] " Youling Tang
2024-07-29 18:57 ` Christoph Hellwig
2024-07-29 18:57 ` [f2fs-dev] " Christoph Hellwig
2024-07-23 8:32 ` [PATCH 2/4] btrfs: Use " Youling Tang
2024-07-23 8:32 ` [f2fs-dev] " Youling Tang
2024-07-23 22:24 ` kernel test robot
2024-07-23 22:24 ` [f2fs-dev] " kernel test robot
2024-07-24 6:29 ` Youling Tang
2024-07-24 6:29 ` [f2fs-dev] " Youling Tang
2024-07-23 8:32 ` [PATCH 3/4] ext4: Use module_{subinit, subexit} " Youling Tang
2024-07-23 8:32 ` [f2fs-dev] " Youling Tang
2024-07-23 8:32 ` [PATCH 4/4] f2fs: Use module_{subinit, subeixt} " Youling Tang
2024-07-23 8:32 ` [f2fs-dev] " Youling Tang
2024-07-23 18:51 ` kernel test robot
2024-07-23 18:51 ` [f2fs-dev] " kernel test robot
2024-07-24 2:14 ` Youling Tang
2024-07-24 2:14 ` [f2fs-dev] " Youling Tang
2024-07-23 21:31 ` kernel test robot
2024-07-23 21:31 ` [f2fs-dev] " kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240723083239.41533-2-youling.tang@linux.dev \
--to=youling.tang@linux.dev \
--cc=adilger.kernel@dilger.ca \
--cc=arnd@arndb.de \
--cc=chao@kernel.org \
--cc=clm@fb.com \
--cc=dsterba@suse.com \
--cc=hch@infradead.org \
--cc=jaegeuk@kernel.org \
--cc=josef@toxicpanda.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-modules@vger.kernel.org \
--cc=mcgrof@kernel.org \
--cc=tangyouling@kylinos.cn \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.