[RFC PATCH 4/7] lib/cpio: Allow use outside of initramfs creation

Jonathan McDowell noodles at fb.com
Fri Jul 8 03:12:11 PDT 2022


Now we no longer depend on anything that lives in __init add a Kconfig
option to allow the cpio code to be used by other code within the
kernel. If not selected the code will continue to be placed within the
__init section and discarded after boot.

Signed-off-by: Jonathan McDowell <noodles at fb.com>
---
 include/linux/cpio.h | 20 ++++++++---
 lib/Kconfig          |  3 ++
 lib/cpio.c           | 80 +++++++++++++++++++++++---------------------
 3 files changed, 61 insertions(+), 42 deletions(-)

diff --git a/include/linux/cpio.h b/include/linux/cpio.h
index d8c1344a6cc3..b05140a565cb 100644
--- a/include/linux/cpio.h
+++ b/include/linux/cpio.h
@@ -11,6 +11,18 @@
 
 #define N_ALIGN(len) ((((len) + 1) & ~3) + 2)
 
+/*
+ * If nothing explicitly wants us then we can live in the __init section as
+ * only the initramfs code will call us.
+ */
+#ifdef CONFIG_CPIO
+#define __cpio
+#define __cpiodata
+#else
+#define __cpio __init
+#define __cpiodata __initdata
+#endif
+
 enum cpio_state {
 	CPIO_START,
 	CPIO_COLLECT,
@@ -67,11 +79,11 @@ struct cpio_context {
 	struct list_head dir_list;
 };
 
-int __init cpio_start(struct cpio_context *ctx);
-void __init cpio_finish(struct cpio_context *ctx);
-long __init cpio_write_buffer(struct cpio_context *ctx, char *buf,
+int __cpio cpio_start(struct cpio_context *ctx);
+void __cpio cpio_finish(struct cpio_context *ctx);
+long __cpio cpio_write_buffer(struct cpio_context *ctx, char *buf,
 			      unsigned long len);
-long __init cpio_process_buffer(struct cpio_context *ctx, void *bufv,
+long __cpio cpio_process_buffer(struct cpio_context *ctx, void *bufv,
 				unsigned long len);
 
 #endif /* _LINUX_CPIO_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index eaaad4d85bf2..fad66ee4caed 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -743,3 +743,6 @@ config ASN1_ENCODER
 
 config POLYNOMIAL
        tristate
+
+config CPIO
+	bool
diff --git a/lib/cpio.c b/lib/cpio.c
index 6ae443a1c103..16629ad1e339 100644
--- a/lib/cpio.c
+++ b/lib/cpio.c
@@ -8,7 +8,7 @@
 #include <linux/security.h>
 #include <linux/slab.h>
 
-static ssize_t __init xwrite(struct cpio_context *ctx, struct file *file,
+static ssize_t __cpio xwrite(struct cpio_context *ctx, struct file *file,
 			     const unsigned char *p, size_t count, loff_t *pos)
 {
 	ssize_t out = 0;
@@ -50,7 +50,7 @@ static inline int hash(int major, int minor, int ino)
 	return tmp & (CPIO_LINK_HASH_SIZE - 1);
 }
 
-static char __init *find_link(struct cpio_context *ctx, int major, int minor,
+static char __cpio *find_link(struct cpio_context *ctx, int major, int minor,
 			      int ino, umode_t mode, char *name)
 {
 	struct cpio_link_hash **p, *q;
@@ -79,7 +79,7 @@ static char __init *find_link(struct cpio_context *ctx, int major, int minor,
 	return NULL;
 }
 
-static void __init free_hash(struct cpio_context *ctx)
+static void __cpio free_hash(struct cpio_context *ctx)
 {
 	struct cpio_link_hash **p, *q;
 
@@ -93,14 +93,14 @@ static void __init free_hash(struct cpio_context *ctx)
 }
 
 #ifdef CONFIG_INITRAMFS_PRESERVE_MTIME
-static void __init do_utime_path(const struct path *path, time64_t mtime)
+static void __cpio do_utime_path(const struct path *path, time64_t mtime)
 {
 	struct timespec64 t[2] = { { .tv_sec = mtime }, { .tv_sec = mtime } };
 
 	vfs_utimes(path, t);
 }
 
-static int __init do_utime(char *filename, time64_t mtime)
+static int __cpio do_utime(char *filename, time64_t mtime)
 {
 	struct path path;
 	int error;
@@ -114,7 +114,7 @@ static int __init do_utime(char *filename, time64_t mtime)
 	return error;
 }
 
-static int __init dir_add(struct cpio_context *ctx, const char *name, time64_t mtime)
+static int __cpio dir_add(struct cpio_context *ctx, const char *name, time64_t mtime)
 {
 	size_t nlen = strlen(name) + 1;
 	struct cpio_dir_entry *de;
@@ -130,7 +130,7 @@ static int __init dir_add(struct cpio_context *ctx, const char *name, time64_t m
 	return 0;
 }
 
-static void __init dir_utime(struct cpio_context *ctx)
+static void __cpio dir_utime(struct cpio_context *ctx)
 {
 	struct cpio_dir_entry *de, *tmp;
 
@@ -141,13 +141,13 @@ static void __init dir_utime(struct cpio_context *ctx)
 	}
 }
 #else
-static int __init do_utime(char *filename, time64_t mtime) { return 0; }
-static void __init do_utime_path(const struct path *path, time64_t mtime) {}
-static int __init dir_add(struct cpio_context *ctx, const char *name, time64_t mtime) { return 0; }
-static void __init dir_utime(struct cpio_context *ctx) {}
+static int __cpio do_utime(char *filename, time64_t mtime) { return 0; }
+static void __cpio do_utime_path(const struct path *path, time64_t mtime) {}
+static int __cpio dir_add(struct cpio_context *ctx, const char *name, time64_t mtime) { return 0; }
+static void __cpio dir_utime(struct cpio_context *ctx) {}
 #endif
 
-static int __init cpio_chown(const char *filename, uid_t user, gid_t group,
+static int __cpio cpio_chown(const char *filename, uid_t user, gid_t group,
 			     int flags)
 {
 	int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
@@ -168,7 +168,7 @@ static int __init cpio_chown(const char *filename, uid_t user, gid_t group,
 
 /* cpio header parsing */
 
-static void __init parse_header(struct cpio_context *ctx, char *s)
+static void __cpio parse_header(struct cpio_context *ctx, char *s)
 {
 	unsigned long parsed[13];
 	char buf[9];
@@ -195,14 +195,14 @@ static void __init parse_header(struct cpio_context *ctx, char *s)
 
 /* FSM */
 
-static inline void __init eat(struct cpio_context *ctx, unsigned int n)
+static inline void __cpio eat(struct cpio_context *ctx, unsigned int n)
 {
 	ctx->victim += n;
 	ctx->this_header += n;
 	ctx->byte_count -= n;
 }
 
-static void __init read_into(struct cpio_context *ctx, char *buf,
+static void __cpio read_into(struct cpio_context *ctx, char *buf,
 			     unsigned int size, enum cpio_state next)
 {
 	if (ctx->byte_count >= size) {
@@ -218,13 +218,13 @@ static void __init read_into(struct cpio_context *ctx, char *buf,
 	}
 }
 
-static int __init do_start(struct cpio_context *ctx)
+static int __cpio do_start(struct cpio_context *ctx)
 {
 	read_into(ctx, ctx->header_buf, 110, CPIO_GOTHEADER);
 	return 0;
 }
 
-static int __init do_collect(struct cpio_context *ctx)
+static int __cpio do_collect(struct cpio_context *ctx)
 {
 	unsigned long n = ctx->remains;
 
@@ -242,7 +242,7 @@ static int __init do_collect(struct cpio_context *ctx)
 	return 0;
 }
 
-static int __init do_header(struct cpio_context *ctx)
+static int __cpio do_header(struct cpio_context *ctx)
 {
 	if (!memcmp(ctx->collected, "070701", 6)) {
 		ctx->csum_present = false;
@@ -274,7 +274,7 @@ static int __init do_header(struct cpio_context *ctx)
 	return 0;
 }
 
-static int __init do_skip(struct cpio_context *ctx)
+static int __cpio do_skip(struct cpio_context *ctx)
 {
 	if (ctx->this_header + ctx->byte_count < ctx->next_header) {
 		eat(ctx, ctx->byte_count);
@@ -286,7 +286,7 @@ static int __init do_skip(struct cpio_context *ctx)
 	return 0;
 }
 
-static int __init do_reset(struct cpio_context *ctx)
+static int __cpio do_reset(struct cpio_context *ctx)
 {
 	while (ctx->byte_count && *ctx->victim == '\0')
 		eat(ctx, 1);
@@ -296,7 +296,7 @@ static int __init do_reset(struct cpio_context *ctx)
 	return 1;
 }
 
-static void __init clean_path(char *pathname, umode_t fmode)
+static void __cpio clean_path(char *pathname, umode_t fmode)
 {
 	struct path path;
 	struct kstat st;
@@ -318,7 +318,7 @@ static void __init clean_path(char *pathname, umode_t fmode)
 	}
 }
 
-static int __init maybe_link(struct cpio_context *ctx)
+static int __cpio maybe_link(struct cpio_context *ctx)
 {
 	struct dentry *new_dentry;
 	struct path old_path, new_path;
@@ -362,7 +362,7 @@ static int __init maybe_link(struct cpio_context *ctx)
 	return 0;
 }
 
-static int __init do_name(struct cpio_context *ctx)
+static int __cpio do_name(struct cpio_context *ctx)
 {
 	struct dentry *dentry;
 	struct path path;
@@ -397,14 +397,18 @@ static int __init do_name(struct cpio_context *ctx)
 		}
 	} else if (S_ISDIR(ctx->mode)) {
 		dentry = kern_path_create(AT_FDCWD, ctx->collected, &path, LOOKUP_DIRECTORY);
-		if (IS_ERR(dentry))
-			return PTR_ERR(dentry);
-		error = security_path_mkdir(&path, dentry, ctx->mode);
-		if (!error)
-			error = vfs_mkdir(mnt_user_ns(path.mnt), path.dentry->d_inode,
-					  dentry, ctx->mode);
-		done_path_create(&path, dentry);
-		if (error)
+		if (!IS_ERR(dentry)) {
+			error = security_path_mkdir(&path, dentry, ctx->mode);
+			if (!error)
+				error = vfs_mkdir(mnt_user_ns(path.mnt),
+						  path.dentry->d_inode,
+						  dentry, ctx->mode);
+			done_path_create(&path, dentry);
+		} else {
+			error = PTR_ERR(dentry);
+		}
+
+		if (error && error != -EEXIST)
 			return error;
 
 		cpio_chown(ctx->collected, ctx->uid, ctx->gid, 0);
@@ -438,7 +442,7 @@ static int __init do_name(struct cpio_context *ctx)
 	return 0;
 }
 
-static int __init do_copy(struct cpio_context *ctx)
+static int __cpio do_copy(struct cpio_context *ctx)
 {
 	int ret;
 
@@ -468,7 +472,7 @@ static int __init do_copy(struct cpio_context *ctx)
 	return 1;
 }
 
-static int __init do_symlink(struct cpio_context *ctx)
+static int __cpio do_symlink(struct cpio_context *ctx)
 {
 	struct dentry *dentry;
 	struct path path;
@@ -497,7 +501,7 @@ static int __init do_symlink(struct cpio_context *ctx)
 	return 0;
 }
 
-static __initdata int (*actions[])(struct cpio_context *) = {
+static __cpiodata int (*actions[])(struct cpio_context *) = {
 	[CPIO_START]		= do_start,
 	[CPIO_COLLECT]		= do_collect,
 	[CPIO_GOTHEADER]	= do_header,
@@ -508,7 +512,7 @@ static __initdata int (*actions[])(struct cpio_context *) = {
 	[CPIO_RESET]		= do_reset,
 };
 
-long __init cpio_write_buffer(struct cpio_context *ctx, char *buf,
+long __cpio cpio_write_buffer(struct cpio_context *ctx, char *buf,
 			      unsigned long len)
 {
 	int ret;
@@ -526,7 +530,7 @@ long __init cpio_write_buffer(struct cpio_context *ctx, char *buf,
 		return len - ctx->byte_count;
 }
 
-long __init cpio_process_buffer(struct cpio_context *ctx, void *bufv,
+long __cpio cpio_process_buffer(struct cpio_context *ctx, void *bufv,
 				unsigned long len)
 {
 	char *buf = (char *)bufv;
@@ -557,7 +561,7 @@ long __init cpio_process_buffer(struct cpio_context *ctx, void *bufv,
 	return len;
 }
 
-int __init cpio_start(struct cpio_context *ctx)
+int __cpio cpio_start(struct cpio_context *ctx)
 {
 	ctx->header_buf = kmalloc(110, GFP_KERNEL);
 	ctx->symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
@@ -573,7 +577,7 @@ int __init cpio_start(struct cpio_context *ctx)
 	return 0;
 }
 
-void __init cpio_finish(struct cpio_context *ctx)
+void __cpio cpio_finish(struct cpio_context *ctx)
 {
 	dir_utime(ctx);
 	kfree(ctx->name_buf);
-- 
2.36.1



More information about the kexec mailing list