From 30b56afca8140422ab724fa63d8d0819169d37a0 Mon Sep 17 00:00:00 2001 From: Victor Krasnoshchok Date: Mon, 20 Dec 2021 12:13:28 +0200 Subject: [PATCH 1/2] TASK4: Implement sysfs attributes example [1/1] Implement a kernel module which contains a kobject instance containing a linked list and having a sysfs attribute named "list". Writing to it should create a new node holding the string received from user and attach it to the aforementioned list. Reading the attribute should print all the exisitng nodes in the list. Signed-off-by: Victor Krasnoshchok --- 04_basic_struct/Makefile | 17 +++ 04_basic_struct/build_log.txt | 13 +++ 04_basic_struct/console_log.txt | 41 ++++++++ 04_basic_struct/sysfs_list.c | 176 ++++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100644 04_basic_struct/Makefile create mode 100644 04_basic_struct/build_log.txt create mode 100644 04_basic_struct/console_log.txt create mode 100644 04_basic_struct/sysfs_list.c diff --git a/04_basic_struct/Makefile b/04_basic_struct/Makefile new file mode 100644 index 0000000..8936dc0 --- /dev/null +++ b/04_basic_struct/Makefile @@ -0,0 +1,17 @@ +KDIR ?= ~/work/buildroot-2021.02.7/output/build/linux-5.10.7 +CHECKPATCH := $(KDIR)/scripts/checkpatch.pl + +SRC := sysfs_list.c +OBJS := $(SRC:.c=.o) + +obj-m += $(OBJS) + +all: + $(CHECKPATCH) -f $(SRC) || exit 1 + $(MAKE) -C $(KDIR) M=$(PWD) modules + +default: all + +clean: + $(MAKE) -C $(KDIR) M=$(PWD) clean + diff --git a/04_basic_struct/build_log.txt b/04_basic_struct/build_log.txt new file mode 100644 index 0000000..b5809d8 --- /dev/null +++ b/04_basic_struct/build_log.txt @@ -0,0 +1,13 @@ +victor@orion5491  ~/work/gl_kernel_procamp_2021/04_basic_struct   task04  make +~/work/buildroot-2021.02.7/output/build/linux-5.10.7/scripts/checkpatch.pl -f sysfs_list.c || exit 1 +total: 0 errors, 0 warnings, 176 lines checked + +sysfs_list.c has no obvious style problems and is ready for submission. +make -C ~/work/buildroot-2021.02.7/output/build/linux-5.10.7 M=/home/victor/work/gl_kernel_procamp_2021/04_basic_struct modules +make[1]: Entering directory '/home/victor/work/buildroot-2021.02.7/output/build/linux-5.10.7' + CC [M] /home/victor/work/gl_kernel_procamp_2021/04_basic_struct/sysfs_list.o + MODPOST /home/victor/work/gl_kernel_procamp_2021/04_basic_struct/Module.symvers +WARNING: modpost: Symbol info of vmlinux is missing. Unresolved symbol check will be entirely skipped. + CC [M] /home/victor/work/gl_kernel_procamp_2021/04_basic_struct/sysfs_list.mod.o + LD [M] /home/victor/work/gl_kernel_procamp_2021/04_basic_struct/sysfs_list.ko +make[1]: Leaving directory '/home/victor/work/buildroot-2021.02.7/output/build/linux-5.10.7' diff --git a/04_basic_struct/console_log.txt b/04_basic_struct/console_log.txt new file mode 100644 index 0000000..cc9b059 --- /dev/null +++ b/04_basic_struct/console_log.txt @@ -0,0 +1,41 @@ +... +OK +Starting dropbear sshd: OK + +Welcome to Buildroot +buildroot login: root +# cd /home/user +# ls +sysfs_list.ko +# dmesg -c +Linux version 5.10.7 (victor@orion5491) (x86_64-buildroot-linux-uclibc-gcc.br_real (Buildroot 2021.02.7) 9.4.0, GNU ld (GNU Binutils) 2.35.2) #1 SMP Sun Nov 28 01:28:29 EET 2021 +Command line: rootwait root=/dev/vda console=tty1 console=ttyS0 +x86/fpu: x87 FPU will use FXSAVE +... +# insmod sysfs_list.ko +sysfs_list: loading out-of-tree module taints kernel. +# echo "Foo!" > /sys/kernel/mod_sysfs/list +Node added: Foo! +# echo "Bar!" > /sys/kernel/mod_sysfs/list +Node added: Bar! +# echo "12345" > /sys/kernel/mod_sysfs/list +Node added: 12345 +# echo "%3@*&%#@" > /sys/kernel/mod_sysfs/list +Node added: %3@*&%#@ +# cat /sys/kernel/mod_sysfs/list +Foo! +Bar! +12345 +%3@*&%#@ +# dmesg +sysfs_list: loading out-of-tree module taints kernel. +Node added: Foo! +Node added: Bar! +Node added: 12345 +Node added: %3@*&%#@ +# rmmod sysfs_list.ko +4 nodes freed, the list is empty +# exit + +Welcome to Buildroot +buildroot login: qemu-system-x86_64: terminating on signal 2 diff --git a/04_basic_struct/sysfs_list.c b/04_basic_struct/sysfs_list.c new file mode 100644 index 0000000..d09f437 --- /dev/null +++ b/04_basic_struct/sysfs_list.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Victor Krasnoshchok "); +MODULE_DESCRIPTION("Interface to a linked list of strings through sysfs."); +MODULE_VERSION("0.1"); + +/* ------------------------------------------ */ +/* List-related logic and data manipulation. */ + +struct data_item { + struct list_head list_node; + char *payload; + size_t payload_len; +}; + +static struct list_head root_node = { NULL, NULL }; + +static ssize_t add_node(struct list_head *parent, const char *node_data, + size_t node_data_len) +{ + struct data_item *new_item; + size_t payload_len; + + if (parent == NULL || node_data == NULL) + return -EINVAL; + + new_item = kmalloc(sizeof(struct data_item), GFP_KERNEL); + if (new_item == NULL) + return -ENOMEM; + + payload_len = node_data_len + 1; /* Including \0 */ + new_item->payload = kzalloc(payload_len, GFP_KERNEL); + if (new_item->payload == NULL) { + pr_err("Failed to alloc. %lu bytes for payload.", payload_len); + kfree(new_item); + return -ENOMEM; + } + + strncpy(new_item->payload, node_data, node_data_len); + new_item->payload_len = node_data_len; + + list_add_tail(&new_item->list_node, parent); + + /* No extra newline needed here - echo appends NLs by itself */ + pr_info("Node added: %s", new_item->payload); + return node_data_len; +} + +static ssize_t serialize_list(struct list_head *list_root, char *output) +{ + ssize_t total_len = 0; + char *wr_ptr = output; + struct list_head *curr_node; + struct data_item *curr_data; + + if (output == NULL) + return -EINVAL; + + list_for_each(curr_node, list_root) { + curr_data = list_entry(curr_node, struct data_item, list_node); + strncpy(wr_ptr, curr_data->payload, curr_data->payload_len); + wr_ptr += curr_data->payload_len; + total_len += curr_data->payload_len; + } + + return total_len; +} + +static void destroy_list(struct list_head *list_root) +{ + struct data_item *curr_data_item, *placeholder; + size_t nodes_cnt = 0; + + list_for_each_entry_safe(curr_data_item, placeholder, list_root, + list_node) { + kfree(curr_data_item->payload); + list_del(&curr_data_item->list_node); + kfree(curr_data_item); + ++nodes_cnt; + } + + pr_info("%lu nodes freed, the list is%sempty\n", nodes_cnt, + (list_empty_careful(list_root) ? " " : " NOT ")); +} + +/* ------------------------------------------ */ +/* Generic module context. */ + +static ssize_t mod_sysfs_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + (void)kobj; + (void)attr; + + return serialize_list(&root_node, buf); +} + +static ssize_t mod_sysfs_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, + size_t count) +{ + (void)kobj; + (void)attr; + + return add_node(&root_node, buf, count); +} + +static struct module_context { + struct kobj_attribute mod_attr; + struct kobject *mod_kobj; +} mod_sysfs_ctx = { __ATTR(list, 0644, mod_sysfs_show, mod_sysfs_store), NULL }; + +static int module_context_init(struct module_context *ctx) +{ + int ret; + + if (ctx == NULL) + return -EINVAL; + + if (ctx->mod_kobj != NULL) { + pr_err("Context has been already initialized."); + return -EEXIST; + } + + ctx->mod_kobj = kobject_create_and_add("mod_sysfs", kernel_kobj); + if (ctx->mod_kobj == NULL) + return -ENOMEM; + + ret = sysfs_create_file(ctx->mod_kobj, &ctx->mod_attr.attr); + if (ret) { + kobject_put(ctx->mod_kobj); + ctx->mod_kobj = NULL; + } + + return ret; +} + +static void module_context_cleanup(struct module_context *ctx) +{ + if (ctx->mod_kobj != NULL) + kobject_put(ctx->mod_kobj); +} + +static int __init mod_sysfs_init(void) +{ + int ret = module_context_init(&mod_sysfs_ctx); + + if (ret != 0) { + pr_err("Ctx init. failed: %d", ret); + return ret; + } + + INIT_LIST_HEAD(&root_node); + return 0; +} + +static void __exit mod_sysfs_exit(void) +{ + destroy_list(&root_node); + module_context_cleanup(&mod_sysfs_ctx); +} + +module_init(mod_sysfs_init); +module_exit(mod_sysfs_exit); + From c3714e640de9e806cc6b604f28ec4ab3aadf7b9a Mon Sep 17 00:00:00 2001 From: Victor Krasnoshchok Date: Mon, 3 Jan 2022 15:30:05 +0200 Subject: [PATCH 2/2] TASK4: Address comments in CR #136 Fix coding style issues raised in CR #136. Signed-off-by: Victor Krasnoshchok --- 04_basic_struct/console_log.txt | 39 +++++++++++++++++---------------- 04_basic_struct/sysfs_list.c | 7 +++--- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/04_basic_struct/console_log.txt b/04_basic_struct/console_log.txt index cc9b059..9ee910a 100644 --- a/04_basic_struct/console_log.txt +++ b/04_basic_struct/console_log.txt @@ -1,40 +1,41 @@ ... +random: mktemp: uninitialized urandom read (6 bytes read) +adding dns 10.0.2.3 OK Starting dropbear sshd: OK Welcome to Buildroot buildroot login: root -# cd /home/user +# ls +# cd /home/user/ # ls sysfs_list.ko -# dmesg -c -Linux version 5.10.7 (victor@orion5491) (x86_64-buildroot-linux-uclibc-gcc.br_real (Buildroot 2021.02.7) 9.4.0, GNU ld (GNU Binutils) 2.35.2) #1 SMP Sun Nov 28 01:28:29 EET 2021 -Command line: rootwait root=/dev/vda console=tty1 console=ttyS0 -x86/fpu: x87 FPU will use FXSAVE -... +# rm sysfs_list.ko +# random: crng init done + # insmod sysfs_list.ko sysfs_list: loading out-of-tree module taints kernel. -# echo "Foo!" > /sys/kernel/mod_sysfs/list +# echo "Foo!" > /sys/kernel/mod_sysfs/list Node added: Foo! -# echo "Bar!" > /sys/kernel/mod_sysfs/list +# echo "Bar!" > /sys/kernel/mod_sysfs/list Node added: Bar! -# echo "12345" > /sys/kernel/mod_sysfs/list -Node added: 12345 -# echo "%3@*&%#@" > /sys/kernel/mod_sysfs/list -Node added: %3@*&%#@ -# cat /sys/kernel/mod_sysfs/list +# cat /sys/kernel/mod_sysfs/list Foo! Bar! -12345 -%3@*&%#@ +# rmmod sysfs_list.ko +The list is empty # dmesg +Linux version 5.10.7 (victor@orion5491) (x86_64-buildroot-linux-uclibc-gcc.br_real (Buildroot 2021.02.7) 9.4.0, GNU ld (GNU Binutils) 2.35.2) #1 SMP Sun Nov 28 01:28:29 EET 2021 +Command line: rootwait root=/dev/vda console=tty1 console=ttyS0 +... +random: dd: uninitialized urandom read (512 bytes read) +random: mktemp: uninitialized urandom read (6 bytes read) +random: mktemp: uninitialized urandom read (6 bytes read) +random: crng init done sysfs_list: loading out-of-tree module taints kernel. Node added: Foo! Node added: Bar! -Node added: 12345 -Node added: %3@*&%#@ -# rmmod sysfs_list.ko -4 nodes freed, the list is empty +The list is empty # exit Welcome to Buildroot diff --git a/04_basic_struct/sysfs_list.c b/04_basic_struct/sysfs_list.c index d09f437..2193d01 100644 --- a/04_basic_struct/sysfs_list.c +++ b/04_basic_struct/sysfs_list.c @@ -79,18 +79,17 @@ static ssize_t serialize_list(struct list_head *list_root, char *output) static void destroy_list(struct list_head *list_root) { - struct data_item *curr_data_item, *placeholder; - size_t nodes_cnt = 0; + struct data_item *curr_data_item; + struct data_item *placeholder; list_for_each_entry_safe(curr_data_item, placeholder, list_root, list_node) { kfree(curr_data_item->payload); list_del(&curr_data_item->list_node); kfree(curr_data_item); - ++nodes_cnt; } - pr_info("%lu nodes freed, the list is%sempty\n", nodes_cnt, + pr_info("The list is%sempty\n", (list_empty_careful(list_root) ? " " : " NOT ")); }