From 8272958f08c676a1d8107a03d7e696a723501301 Mon Sep 17 00:00:00 2001 From: ChinYikMing Date: Thu, 31 Mar 2022 03:50:26 +0800 Subject: [PATCH 01/10] fixed typo --- Documentation/teaching/labs/filesystems_part2.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/teaching/labs/filesystems_part2.rst b/Documentation/teaching/labs/filesystems_part2.rst index ae45781127fec8..18a221bfcf4b89 100644 --- a/Documentation/teaching/labs/filesystems_part2.rst +++ b/Documentation/teaching/labs/filesystems_part2.rst @@ -477,7 +477,7 @@ In the minix case, the function is ``minix_lookup``. This function is called indirectly when information about the inode associated with an entry in a directory is needed. Such a function performs the following operations: - #. Searces in the directory indicated by ``dir`` the entry having the name ``dentry->d_name.name``. + #. Searches in the directory indicated by ``dir`` the entry having the name ``dentry->d_name.name``. #. If the entry is found, it will return ``NULL`` and associate the inode with the name using the :c:func:`d_add` function. #. Otherwise, returns ``ERR_PTR``. From 3b90c7f3f6b858534d4ce0467d3f664e56fb4497 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 4 Apr 2022 12:05:02 +0300 Subject: [PATCH 02/10] teaching: Add collaboration guideline for SO2 assignments This documents serves as a guideline for working inside a team. It encourages members to use git and PR, work on a common design, split the work into smaller tasks and then doing peer review. The final result should be the code together with git history logs. Signed-off-by: Daniel Baluta --- .../teaching/so2/assign-collaboration.rst | 144 ++++++++++++++++++ Documentation/teaching/so2/index.rst | 1 + 2 files changed, 145 insertions(+) create mode 100644 Documentation/teaching/so2/assign-collaboration.rst diff --git a/Documentation/teaching/so2/assign-collaboration.rst b/Documentation/teaching/so2/assign-collaboration.rst new file mode 100644 index 00000000000000..7f51f7c175dd31 --- /dev/null +++ b/Documentation/teaching/so2/assign-collaboration.rst @@ -0,0 +1,144 @@ +============= +Collaboration +============= + +Collaboration is essential in open source world and we encourage you +to pick a team partner to work on selected assignments. + +Here is a simple guide to get you started: + +1. Use Github / Gitlab +---------------------- + +Best way to share your work inside the team is to use a version control system (VCS) +in order to track each change. Mind that you must make your repo private and only allow +read/write access rights to team members. + +2. Start with a skeleton for the assignment +------------------------------------------- + +Add `init`/`exit` functions, driver operations and global structures that you driver might need. + +.. code-block:: c + + // SPDX-License-Identifier: GPL-2.0 + /* + * uart16550.c - UART16550 driver + * + * Author: John Doe + * Author: Ionut Popescu + */ + struct uart16550_dev { + struct cdev cdev; + /*TODO */ + }; + + static struct uart16550_dev devs[MAX_NUMBER_DEVICES]; + + static int uart16550_open(struct inode *inode, struct file *file) + { + /*TODO */ + return 0; + } + + static int uart16550_release(struct inode *inode, struct file *file) + { + /*TODO */ + return 0; + } + + static ssize_t uart16550_read(struct file *file, char __user *user_buffer, + size_t size, loff_t *offset) + { + /*TODO */ + } + + static ssize_t uart16550_write(struct file *file, + const char __user *user_buffer, + size_t size, loff_t *offset) + { + /*TODO */ + } + + static long + uart16550_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + { + /*TODO */ + return 0; + } + + static const struct file_operations uart16550_fops = { + .owner = THIS_MODULE, + .open = uart16550_open, + .release = uart16550_release, + .read = uart16550_read, + .write = uart16550_write, + .unlocked_ioctl = uart16550_ioctl + }; + + static int __init uart16550_init(void) + { + /* TODO: */ + } + + static void __exit uart16550_exit(void) + { + /* TODO: */ + } + + module_init(uart16550_init); + module_exit(uart16550_exit); + + MODULE_DESCRIPTION("UART16550 Driver"); + MODULE_AUTHOR("John Doe tema2) + Author: John Doe + Date: Mon Apr 4 11:54:39 2022 +0300 + + uart16550: Add initial skeleton for ssignment #2 + + This adds simple skeleton file for uart16550 assignment. Notice + module init/exit callbacks and file_operations dummy implementation + for open/release/read/write/ioctl. + + Signed-off-by: John Doe + +4. Split the work inside the team +--------------------------------- + +Add `TODOs` with each team member tasks. Try to split the work evenly. + +Before starting to code, make a plan. On top of your skeleton file, add TODOs with each member tasks. Agree on global +structures and the overlall driver design. Then start coding. + +5. Do reviews +------------- + +Create Pull Requests with your commits and go through review rounds with your team members. You can follow `How to create a PR` `video `_. + +6. Merge the work +----------------- + +The final work is the result of merging all the pull requests. Following the commit messages +one should clearly understand the progress of the code and how the work was managed inside the team. + +.. code-block:: console + + f5118b873294 uart16550: Add uart16550_interrupt implementation + 2115503fc3e3 uart16550: Add uart16550_ioctl implementation + b31a257fd8b8 uart16550: Add uart16550_write implementation + ac1af6d88a25 uart16550: Add uart16550_read implementation + 9f680e8136bf uart16550: Add uart16550_open/release implementation + 3c92a02cc527 uart16550: Add skeleton for SO2 assignment #2 diff --git a/Documentation/teaching/so2/index.rst b/Documentation/teaching/so2/index.rst index d96528f63c1c17..d38047b8f9fecd 100644 --- a/Documentation/teaching/so2/index.rst +++ b/Documentation/teaching/so2/index.rst @@ -41,6 +41,7 @@ Operating Systems 2 :caption: Assignments :maxdepth: 1 + assign-collaboration.rst assign0-kernel-api.rst assign1-kprobe-based-tracer.rst assign2-driver-uart.rst From 2f6486ce913748c5ced076ebfbe66832a469aabc Mon Sep 17 00:00:00 2001 From: Cristian Olaru Date: Thu, 7 Apr 2022 22:32:24 +0300 Subject: [PATCH 03/10] lab 5: add skel Signed-off-by: Cristian Olaru --- tools/labs/skels/Kbuild | 5 + .../labs/skels/deferred_work/1-2-timer/Kbuild | 3 + .../skels/deferred_work/1-2-timer/timer.c | 46 +++++ .../3-4-5-deferred/include/deferred.h | 35 ++++ .../3-4-5-deferred/kernel/Kbuild | 3 + .../3-4-5-deferred/kernel/deferred.c | 189 ++++++++++++++++++ .../3-4-5-deferred/kernel/makenode | 9 + .../3-4-5-deferred/user/.gitignore | 1 + .../3-4-5-deferred/user/Makefile | 9 + .../deferred_work/3-4-5-deferred/user/test.c | 93 +++++++++ .../labs/skels/deferred_work/6-kthread/Kbuild | 3 + .../skels/deferred_work/6-kthread/kthread.c | 54 +++++ 12 files changed, 450 insertions(+) create mode 100644 tools/labs/skels/Kbuild create mode 100644 tools/labs/skels/deferred_work/1-2-timer/Kbuild create mode 100644 tools/labs/skels/deferred_work/1-2-timer/timer.c create mode 100644 tools/labs/skels/deferred_work/3-4-5-deferred/include/deferred.h create mode 100644 tools/labs/skels/deferred_work/3-4-5-deferred/kernel/Kbuild create mode 100644 tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c create mode 100644 tools/labs/skels/deferred_work/3-4-5-deferred/kernel/makenode create mode 100644 tools/labs/skels/deferred_work/3-4-5-deferred/user/.gitignore create mode 100644 tools/labs/skels/deferred_work/3-4-5-deferred/user/Makefile create mode 100644 tools/labs/skels/deferred_work/3-4-5-deferred/user/test.c create mode 100644 tools/labs/skels/deferred_work/6-kthread/Kbuild create mode 100644 tools/labs/skels/deferred_work/6-kthread/kthread.c diff --git a/tools/labs/skels/Kbuild b/tools/labs/skels/Kbuild new file mode 100644 index 00000000000000..d88fa6735f6198 --- /dev/null +++ b/tools/labs/skels/Kbuild @@ -0,0 +1,5 @@ +# autogenerated, do not edit +ccflags-y += -Wno-unused-function -Wno-unused-label -Wno-unused-variable +obj-m += ./deferred_work/1-2-timer/ +obj-m += ./deferred_work/3-4-5-deferred/kernel/ +obj-m += ./deferred_work/6-kthread/ diff --git a/tools/labs/skels/deferred_work/1-2-timer/Kbuild b/tools/labs/skels/deferred_work/1-2-timer/Kbuild new file mode 100644 index 00000000000000..fa3cd3e263f84b --- /dev/null +++ b/tools/labs/skels/deferred_work/1-2-timer/Kbuild @@ -0,0 +1,3 @@ +ccflags-y = -Wno-unused-function -Wno-unused-label -Wno-unused-variable + +obj-m = timer.o diff --git a/tools/labs/skels/deferred_work/1-2-timer/timer.c b/tools/labs/skels/deferred_work/1-2-timer/timer.c new file mode 100644 index 00000000000000..f7b0d6578bbe3c --- /dev/null +++ b/tools/labs/skels/deferred_work/1-2-timer/timer.c @@ -0,0 +1,46 @@ +/* + * Deferred Work + * + * Exercise #1, #2: simple timer + */ + +#include +#include +#include +#include + +MODULE_DESCRIPTION("Simple kernel timer"); +MODULE_AUTHOR("SO2"); +MODULE_LICENSE("GPL"); + +#define TIMER_TIMEOUT 1 + +static struct timer_list timer; + +static void timer_handler(struct timer_list *tl) +{ + /* TODO 1: print a message */ + + /* TODO 2: rechedule timer */ +} + +static int __init timer_init(void) +{ + pr_info("[timer_init] Init module\n"); + + /* TODO 1: initialize timer */ + + /* TODO 1: schedule timer for the first time */ + + return 0; +} + +static void __exit timer_exit(void) +{ + pr_info("[timer_exit] Exit module\n"); + + /* TODO 1: cleanup; make sure the timer is not running after we exit */ +} + +module_init(timer_init); +module_exit(timer_exit); diff --git a/tools/labs/skels/deferred_work/3-4-5-deferred/include/deferred.h b/tools/labs/skels/deferred_work/3-4-5-deferred/include/deferred.h new file mode 100644 index 00000000000000..f9408c704401ad --- /dev/null +++ b/tools/labs/skels/deferred_work/3-4-5-deferred/include/deferred.h @@ -0,0 +1,35 @@ +/* + * SO2 - Lab 6 - Deferred Work + * + * Exercises #3, #4, #5: deferred work + * + * Header file. + */ + +#ifndef __DEFERRED_H__ +#define __DEFERRED_H__ + +#include + +#define MY_IOCTL_TIMER_SET _IOW('k', 1, unsigned long) +#define MY_IOCTL_TIMER_CANCEL _IO ('k', 2) +#define MY_IOCTL_TIMER_ALLOC _IOW('k', 3, unsigned long) +#define MY_IOCTL_TIMER_MON _IO ('k', 4) + +/* converts ioctl command code to message */ +inline static char *ioctl_command_to_string(int cmd) +{ + switch(cmd) { + case MY_IOCTL_TIMER_SET: + return "Set timer"; + case MY_IOCTL_TIMER_CANCEL: + return "Cancel timer"; + case MY_IOCTL_TIMER_ALLOC: + return "Allocate memory"; + case MY_IOCTL_TIMER_MON: + return "Monitor pid"; + } + return "Unknown command"; +} + +#endif /* __DEFERRED_H__ */ diff --git a/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/Kbuild b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/Kbuild new file mode 100644 index 00000000000000..fa3f727c8a53d2 --- /dev/null +++ b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/Kbuild @@ -0,0 +1,3 @@ +ccflags-y = -Wno-unused-function -Wno-unused-label -Wno-unused-variable + +obj-m = deferred.o diff --git a/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c new file mode 100644 index 00000000000000..48fdd4cfd43f37 --- /dev/null +++ b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c @@ -0,0 +1,189 @@ +/* + * SO2 - Lab 6 - Deferred Work + * + * Exercises #3, #4, #5: deferred work + * + * Code skeleton. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/deferred.h" + +#define MY_MAJOR 42 +#define MY_MINOR 0 +#define MODULE_NAME "deferred" + +#define TIMER_TYPE_NONE -1 +#define TIMER_TYPE_SET 0 +#define TIMER_TYPE_ALLOC 1 +#define TIMER_TYPE_MON 2 + +MODULE_DESCRIPTION("Deferred work character device"); +MODULE_AUTHOR("SO2"); +MODULE_LICENSE("GPL"); + +struct mon_proc { + struct task_struct *task; + struct list_head list; +}; + +static struct my_device_data { + struct cdev cdev; + /* TODO 1: add timer */ + /* TODO 2: add flag */ + /* TODO 3: add work */ + /* TODO 4: add list for monitored processes */ + /* TODO 4: add spinlock to protect list */ +} dev; + +static void alloc_io(void) +{ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(5 * HZ); + pr_info("Yawn! I've been sleeping for 5 seconds.\n"); +} + +static struct mon_proc *get_proc(pid_t pid) +{ + struct task_struct *task; + struct mon_proc *p; + + rcu_read_lock(); + task = pid_task(find_vpid(pid), PIDTYPE_PID); + rcu_read_unlock(); + if (!task) + return ERR_PTR(-ESRCH); + + p = kmalloc(sizeof(*p), GFP_ATOMIC); + if (!p) + return ERR_PTR(-ENOMEM); + + get_task_struct(task); + p->task = task; + + return p; +} + + +/* TODO 3: define work handler */ + +#define ALLOC_IO_DIRECT +/* TODO 3: undef ALLOC_IO_DIRECT*/ + +static void timer_handler(struct timer_list *tl) +{ + /* TODO 1: implement timer handler */ + /* TODO 2: check flags: TIMER_TYPE_SET or TIMER_TYPE_ALLOC */ + /* TODO 3: schedule work */ + /* TODO 4: iterate the list and check the proccess state */ + /* TODO 4: if task is dead print info ... */ + /* TODO 4: ... decrement task usage counter ... */ + /* TODO 4: ... remove it from the list ... */ + /* TODO 4: ... free the struct mon_proc */ +} + +static int deferred_open(struct inode *inode, struct file *file) +{ + struct my_device_data *my_data = + container_of(inode->i_cdev, struct my_device_data, cdev); + file->private_data = my_data; + pr_info("[deferred_open] Device opened\n"); + return 0; +} + +static int deferred_release(struct inode *inode, struct file *file) +{ + pr_info("[deferred_release] Device released\n"); + return 0; +} + +static long deferred_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct my_device_data *my_data = (struct my_device_data*) file->private_data; + + pr_info("[deferred_ioctl] Command: %s\n", ioctl_command_to_string(cmd)); + + switch (cmd) { + case MY_IOCTL_TIMER_SET: + /* TODO 2: set flag */ + /* TODO 1: schedule timer */ + break; + case MY_IOCTL_TIMER_CANCEL: + /* TODO 1: cancel timer */ + break; + case MY_IOCTL_TIMER_ALLOC: + /* TODO 2: set flag and schedule timer */ + break; + case MY_IOCTL_TIMER_MON: + { + /* TODO 4: use get_proc() and add task to list */ + /* TODO 4: protect access to list */ + + /* TODO 4: set flag and schedule timer */ + break; + } + default: + return -ENOTTY; + } + return 0; +} + +struct file_operations my_fops = { + .owner = THIS_MODULE, + .open = deferred_open, + .release = deferred_release, + .unlocked_ioctl = deferred_ioctl, +}; + +static int deferred_init(void) +{ + int err; + + pr_info("[deferred_init] Init module\n"); + err = register_chrdev_region(MKDEV(MY_MAJOR, MY_MINOR), 1, MODULE_NAME); + if (err) { + pr_info("[deffered_init] register_chrdev_region: %d\n", err); + return err; + } + + /* TODO 2: Initialize flag. */ + /* TODO 3: Initialize work. */ + + /* TODO 4: Initialize lock and list. */ + + cdev_init(&dev.cdev, &my_fops); + cdev_add(&dev.cdev, MKDEV(MY_MAJOR, MY_MINOR), 1); + + /* TODO 1: Initialize timer. */ + + return 0; +} + +static void deferred_exit(void) +{ + struct mon_proc *p, *n; + + pr_info("[deferred_exit] Exit module\n" ); + + cdev_del(&dev.cdev); + unregister_chrdev_region(MKDEV(MY_MAJOR, MY_MINOR), 1); + + /* TODO 1: Cleanup: make sure the timer is not running after exiting. */ + /* TODO 3: Cleanup: make sure the work handler is not scheduled. */ + + /* TODO 4: Cleanup the monitered process list */ + /* TODO 4: ... decrement task usage counter ... */ + /* TODO 4: ... remove it from the list ... */ + /* TODO 4: ... free the struct mon_proc */ +} + +module_init(deferred_init); +module_exit(deferred_exit); diff --git a/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/makenode b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/makenode new file mode 100644 index 00000000000000..1e46669d4a1c98 --- /dev/null +++ b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/makenode @@ -0,0 +1,9 @@ +#!/bin/sh + +device=deferred +type=c +major=42 +minor=0 + +rm -f /dev/${device} +mknod /dev/${device} $type $major $minor && ls -al /dev/${device} diff --git a/tools/labs/skels/deferred_work/3-4-5-deferred/user/.gitignore b/tools/labs/skels/deferred_work/3-4-5-deferred/user/.gitignore new file mode 100644 index 00000000000000..ee4c92682341e4 --- /dev/null +++ b/tools/labs/skels/deferred_work/3-4-5-deferred/user/.gitignore @@ -0,0 +1 @@ +/test diff --git a/tools/labs/skels/deferred_work/3-4-5-deferred/user/Makefile b/tools/labs/skels/deferred_work/3-4-5-deferred/user/Makefile new file mode 100644 index 00000000000000..62768622c42fee --- /dev/null +++ b/tools/labs/skels/deferred_work/3-4-5-deferred/user/Makefile @@ -0,0 +1,9 @@ +CFLAGS=-Wall -m32 +LDFLAGS=-static -m32 + +test: test.o + +.PHONY: clean + +clean: + -rm -f *~ *.o test diff --git a/tools/labs/skels/deferred_work/3-4-5-deferred/user/test.c b/tools/labs/skels/deferred_work/3-4-5-deferred/user/test.c new file mode 100644 index 00000000000000..3cef70f86e2b75 --- /dev/null +++ b/tools/labs/skels/deferred_work/3-4-5-deferred/user/test.c @@ -0,0 +1,93 @@ +/* + * SO2 - Lab 6 - Deferred Work + * + * Exercises #3, #4, #5: deferred work + * + * User-mode test program. + */ + +#include +#include +#include +#include +#include +#include +#include "../include/deferred.h" + +#define DEVICE_PATH "/dev/deferred" + +/* prints error message and exits */ +void error(char *message) +{ + perror(message); + exit(EXIT_FAILURE); +} + +/* prints usage message and exits */ +void usage() +{ + printf("Usage: test \n options:\n" + "\ts - set timer to run after seconds\n" + "\tc - cancel timer\n" + "\ta - allocate memory after seconds\n" + "\tp - monitor pid\n" + "\n"); + exit(1); +} + +#define BUFFER_LEN 128 + +int main(int argc, char **argv) +{ + int fd; + unsigned long seconds, pid; + + if (argc < 2) + usage(); + + fd = open(DEVICE_PATH, O_RDONLY); + if (fd < 0) + error(DEVICE_PATH); + + switch (argv[1][0]) { + case 's': + /* Set timer. */ + if (argc < 3) + usage(); + seconds = atoi(argv[2]); + printf("Set timer to %ld seconds\n", seconds); + if (ioctl(fd, MY_IOCTL_TIMER_SET, seconds) < 0) + error("ioctl set timer error"); + break; + case 'c': + /* Cancel timer. */ + printf("Cancel timer\n"); + if (ioctl(fd, MY_IOCTL_TIMER_CANCEL) < 0) + error("ioctl cancel timer error"); + break; + case 'a': + /* Allocate memory. */ + if (argc < 3) + usage(); + seconds = atoi(argv[2]); + printf("Allocate memory after %ld seconds\n",seconds); + if (ioctl(fd, MY_IOCTL_TIMER_ALLOC, seconds) < 0) + error("ioctl allocate memory error"); + break; + case 'p': + /* Monitor pid. */ + if (argc < 3) + usage(); + pid = atoi(argv[2]); + printf("Monitor PID %lu.\n", pid); + if (ioctl(fd, MY_IOCTL_TIMER_MON, pid) < 0) + error("ioctl monitor pid error"); + break; + default: + error("Wrong parameter"); + } + + close(fd); + + return 0; +} diff --git a/tools/labs/skels/deferred_work/6-kthread/Kbuild b/tools/labs/skels/deferred_work/6-kthread/Kbuild new file mode 100644 index 00000000000000..028c060071dd8c --- /dev/null +++ b/tools/labs/skels/deferred_work/6-kthread/Kbuild @@ -0,0 +1,3 @@ +ccflags-y = -Wno-unused-function -Wno-unused-label -Wno-unused-variable + +obj-m = kthread.o diff --git a/tools/labs/skels/deferred_work/6-kthread/kthread.c b/tools/labs/skels/deferred_work/6-kthread/kthread.c new file mode 100644 index 00000000000000..ad1770211be519 --- /dev/null +++ b/tools/labs/skels/deferred_work/6-kthread/kthread.c @@ -0,0 +1,54 @@ +/* + * SO2 - Lab 6 - Deferred Work + * + * Exercise #6: kernel thread + */ + +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Simple kernel thread"); +MODULE_AUTHOR("SO2"); +MODULE_LICENSE("GPL"); + +wait_queue_head_t wq_stop_thread; +atomic_t flag_stop_thread; +wait_queue_head_t wq_thread_terminated; +atomic_t flag_thread_terminated; + + +int my_thread_f(void *data) +{ + pr_info("[my_thread_f] Current process id is %d (%s)\n", + current->pid, current->comm); + /* TODO: Wait for command to remove module on wq_stop_thread queue. */ + + /* TODO: set flag to mark kernel thread termination */ + /* TODO: notify the unload process that we have exited */ + pr_info("[my_thread_f] Exiting\n"); + do_exit(0); +} + +static int __init kthread_init(void) +{ + pr_info("[kthread_init] Init module\n"); + + /* TODO: init the waitqueues and flags */ + /* TODO: create and start the kernel thread */ + + return 0; +} + +static void __exit kthread_exit(void) +{ + /* TODO: notify the kernel thread that its time to exit */ + /* TODO: wait for the kernel thread to exit */ + pr_info("[kthread_exit] Exit module\n"); +} + +module_init(kthread_init); +module_exit(kthread_exit); From 12cc457e0bcc49756e2340c8aaf85f4d6ac22ecf Mon Sep 17 00:00:00 2001 From: Cristian Olaru Date: Thu, 7 Apr 2022 22:34:44 +0300 Subject: [PATCH 04/10] lab 5: ex 1 Signed-off-by: Cristian Olaru --- tools/labs/skels/deferred_work/1-2-timer/timer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/labs/skels/deferred_work/1-2-timer/timer.c b/tools/labs/skels/deferred_work/1-2-timer/timer.c index f7b0d6578bbe3c..02fa8db39d93a6 100644 --- a/tools/labs/skels/deferred_work/1-2-timer/timer.c +++ b/tools/labs/skels/deferred_work/1-2-timer/timer.c @@ -20,6 +20,10 @@ static struct timer_list timer; static void timer_handler(struct timer_list *tl) { /* TODO 1: print a message */ + static size_t nseconds; + + nseconds += TIMER_TIMEOUT; + pr_info("[timer_handler] nseconds = %d\n", nseconds); /* TODO 2: rechedule timer */ } @@ -29,8 +33,10 @@ static int __init timer_init(void) pr_info("[timer_init] Init module\n"); /* TODO 1: initialize timer */ + timer_setup(&timer, timer_handler, 0); /* TODO 1: schedule timer for the first time */ + mod_timer(&timer, jiffies + TIMER_TIMEOUT * HZ); return 0; } @@ -40,6 +46,7 @@ static void __exit timer_exit(void) pr_info("[timer_exit] Exit module\n"); /* TODO 1: cleanup; make sure the timer is not running after we exit */ + del_timer_sync(&timer); } module_init(timer_init); From 6caf86161760a1e2d0127e4ffc780e171f4dfadd Mon Sep 17 00:00:00 2001 From: Cristian Olaru Date: Thu, 7 Apr 2022 22:35:20 +0300 Subject: [PATCH 05/10] lab 5: ex 2 Signed-off-by: Cristian Olaru --- tools/labs/skels/deferred_work/1-2-timer/timer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/labs/skels/deferred_work/1-2-timer/timer.c b/tools/labs/skels/deferred_work/1-2-timer/timer.c index 02fa8db39d93a6..9917ffc50bbd78 100644 --- a/tools/labs/skels/deferred_work/1-2-timer/timer.c +++ b/tools/labs/skels/deferred_work/1-2-timer/timer.c @@ -26,6 +26,7 @@ static void timer_handler(struct timer_list *tl) pr_info("[timer_handler] nseconds = %d\n", nseconds); /* TODO 2: rechedule timer */ + mod_timer(tl, jiffies + TIMER_TIMEOUT * HZ); } static int __init timer_init(void) From f5bc8a1f7920c76dcc72351080238262a5291e37 Mon Sep 17 00:00:00 2001 From: Cristian Olaru Date: Thu, 7 Apr 2022 22:47:08 +0300 Subject: [PATCH 06/10] lab 5: ex 3 Signed-off-by: Cristian Olaru --- .../skels/deferred_work/3-4-5-deferred/kernel/deferred.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c index 48fdd4cfd43f37..778b7f92727017 100644 --- a/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c +++ b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c @@ -38,6 +38,7 @@ struct mon_proc { static struct my_device_data { struct cdev cdev; /* TODO 1: add timer */ + struct timer_list timer; /* TODO 2: add flag */ /* TODO 3: add work */ /* TODO 4: add list for monitored processes */ @@ -81,6 +82,10 @@ static struct mon_proc *get_proc(pid_t pid) static void timer_handler(struct timer_list *tl) { /* TODO 1: implement timer handler */ + struct my_device_data *my_data = from_timer(my_data, tl, timer); + + pr_info("[timer_handler] pid = %d, comm = %s\n", + current->pid, current->comm); /* TODO 2: check flags: TIMER_TYPE_SET or TIMER_TYPE_ALLOC */ /* TODO 3: schedule work */ /* TODO 4: iterate the list and check the proccess state */ @@ -115,9 +120,11 @@ static long deferred_ioctl(struct file *file, unsigned int cmd, unsigned long ar case MY_IOCTL_TIMER_SET: /* TODO 2: set flag */ /* TODO 1: schedule timer */ + mod_timer(&my_data->timer, jiffies + arg * HZ); break; case MY_IOCTL_TIMER_CANCEL: /* TODO 1: cancel timer */ + del_timer(&my_data->timer); break; case MY_IOCTL_TIMER_ALLOC: /* TODO 2: set flag and schedule timer */ @@ -163,6 +170,7 @@ static int deferred_init(void) cdev_add(&dev.cdev, MKDEV(MY_MAJOR, MY_MINOR), 1); /* TODO 1: Initialize timer. */ + timer_setup(&dev.timer, timer_handler, 0); return 0; } @@ -177,6 +185,7 @@ static void deferred_exit(void) unregister_chrdev_region(MKDEV(MY_MAJOR, MY_MINOR), 1); /* TODO 1: Cleanup: make sure the timer is not running after exiting. */ + del_timer_sync(&dev.timer); /* TODO 3: Cleanup: make sure the work handler is not scheduled. */ /* TODO 4: Cleanup the monitered process list */ From 847292bdf7820c4d5d8c6aac7e24516bf280cbc5 Mon Sep 17 00:00:00 2001 From: Cristian Olaru Date: Thu, 7 Apr 2022 22:50:01 +0300 Subject: [PATCH 07/10] lab 5: ex 4 Signed-off-by: Cristian Olaru --- .../3-4-5-deferred/kernel/deferred.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c index 778b7f92727017..8b60ae6ca046ab 100644 --- a/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c +++ b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c @@ -39,7 +39,10 @@ static struct my_device_data { struct cdev cdev; /* TODO 1: add timer */ struct timer_list timer; + /* TODO 2: add flag */ + unsigned int flag; + /* TODO 3: add work */ /* TODO 4: add list for monitored processes */ /* TODO 4: add spinlock to protect list */ @@ -87,6 +90,15 @@ static void timer_handler(struct timer_list *tl) pr_info("[timer_handler] pid = %d, comm = %s\n", current->pid, current->comm); /* TODO 2: check flags: TIMER_TYPE_SET or TIMER_TYPE_ALLOC */ + switch(dev.flag){ + case TIMER_TYPE_SET: + break; + case TIMER_TYPE_ALLOC: + alloc_io(); + break; + default: + break; + } /* TODO 3: schedule work */ /* TODO 4: iterate the list and check the proccess state */ /* TODO 4: if task is dead print info ... */ @@ -119,6 +131,7 @@ static long deferred_ioctl(struct file *file, unsigned int cmd, unsigned long ar switch (cmd) { case MY_IOCTL_TIMER_SET: /* TODO 2: set flag */ + my_data->flag = TIMER_TYPE_SET; /* TODO 1: schedule timer */ mod_timer(&my_data->timer, jiffies + arg * HZ); break; @@ -128,6 +141,8 @@ static long deferred_ioctl(struct file *file, unsigned int cmd, unsigned long ar break; case MY_IOCTL_TIMER_ALLOC: /* TODO 2: set flag and schedule timer */ + my_data->flag = TIMER_TYPE_ALLOC; + mod_timer(&my_data->timer, jiffies + arg * HZ); break; case MY_IOCTL_TIMER_MON: { @@ -162,6 +177,7 @@ static int deferred_init(void) } /* TODO 2: Initialize flag. */ + dev.flag = TIMER_TYPE_NONE; /* TODO 3: Initialize work. */ /* TODO 4: Initialize lock and list. */ From 3bf643acb02ff0f956f08837cc2f563d7fb337d6 Mon Sep 17 00:00:00 2001 From: Cristian Olaru Date: Thu, 7 Apr 2022 22:57:38 +0300 Subject: [PATCH 08/10] lab 5: ex 5 Signed-off-by: Cristian Olaru --- .../3-4-5-deferred/kernel/deferred.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c index 8b60ae6ca046ab..767a249b3bab0b 100644 --- a/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c +++ b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c @@ -44,6 +44,8 @@ static struct my_device_data { unsigned int flag; /* TODO 3: add work */ + struct work_struct work; + /* TODO 4: add list for monitored processes */ /* TODO 4: add spinlock to protect list */ } dev; @@ -78,9 +80,14 @@ static struct mon_proc *get_proc(pid_t pid) /* TODO 3: define work handler */ +static void work_handler(struct work_struct *work) +{ + alloc_io(); +} #define ALLOC_IO_DIRECT /* TODO 3: undef ALLOC_IO_DIRECT*/ +#undef ALLOC_IO_DIRECT static void timer_handler(struct timer_list *tl) { @@ -94,8 +101,13 @@ static void timer_handler(struct timer_list *tl) case TIMER_TYPE_SET: break; case TIMER_TYPE_ALLOC: +#ifdef ALLOC_IO_DIRECT alloc_io(); +#else + schedule_work(&my_data->work); +#endif break; + default: break; } @@ -178,7 +190,9 @@ static int deferred_init(void) /* TODO 2: Initialize flag. */ dev.flag = TIMER_TYPE_NONE; + /* TODO 3: Initialize work. */ + INIT_WORK(&dev.work, work_handler); /* TODO 4: Initialize lock and list. */ @@ -202,7 +216,9 @@ static void deferred_exit(void) /* TODO 1: Cleanup: make sure the timer is not running after exiting. */ del_timer_sync(&dev.timer); + /* TODO 3: Cleanup: make sure the work handler is not scheduled. */ + flush_scheduled_work(); /* TODO 4: Cleanup the monitered process list */ /* TODO 4: ... decrement task usage counter ... */ From 1afba217086b537f4ed3cf0050404dafc6fc8018 Mon Sep 17 00:00:00 2001 From: Cristian Olaru Date: Thu, 7 Apr 2022 22:58:09 +0300 Subject: [PATCH 09/10] lab 5: ex 6 Signed-off-by: Cristian Olaru --- tools/labs/skels/deferred_work/6-kthread/kthread.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/labs/skels/deferred_work/6-kthread/kthread.c b/tools/labs/skels/deferred_work/6-kthread/kthread.c index ad1770211be519..7159c045f9e93d 100644 --- a/tools/labs/skels/deferred_work/6-kthread/kthread.c +++ b/tools/labs/skels/deferred_work/6-kthread/kthread.c @@ -26,9 +26,12 @@ int my_thread_f(void *data) pr_info("[my_thread_f] Current process id is %d (%s)\n", current->pid, current->comm); /* TODO: Wait for command to remove module on wq_stop_thread queue. */ + wait_event_interruptible(wq_stop_thread, atomic_read(&flag_stop_thread) != 0); /* TODO: set flag to mark kernel thread termination */ + atomic_set(&flag_thread_terminated, 1); /* TODO: notify the unload process that we have exited */ + wake_up_interruptible(&wq_thread_terminated); pr_info("[my_thread_f] Exiting\n"); do_exit(0); } @@ -38,7 +41,13 @@ static int __init kthread_init(void) pr_info("[kthread_init] Init module\n"); /* TODO: init the waitqueues and flags */ + init_waitqueue_head(&wq_stop_thread); + atomic_set(&flag_stop_thread, 0); + init_waitqueue_head(&wq_thread_terminated); + atomic_set(&flag_thread_terminated, 0); + /* TODO: create and start the kernel thread */ + kthread_run(my_thread_f, NULL, "%skthread%d", "my", 0); return 0; } @@ -46,7 +55,11 @@ static int __init kthread_init(void) static void __exit kthread_exit(void) { /* TODO: notify the kernel thread that its time to exit */ + atomic_set(&flag_stop_thread, 1); + wake_up_interruptible(&wq_stop_thread); + /* TODO: wait for the kernel thread to exit */ + wait_event_interruptible(wq_thread_terminated, atomic_read(&flag_thread_terminated) != 0); pr_info("[kthread_exit] Exit module\n"); } From f29ca44ed3565ec170000cfb623093eb5bceb7e6 Mon Sep 17 00:00:00 2001 From: Cristian Olaru Date: Thu, 7 Apr 2022 23:00:43 +0300 Subject: [PATCH 10/10] lab 5: ex 7 Signed-off-by: Cristian Olaru --- .../3-4-5-deferred/kernel/deferred.c | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c index 767a249b3bab0b..5b61f037ae8a8a 100644 --- a/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c +++ b/tools/labs/skels/deferred_work/3-4-5-deferred/kernel/deferred.c @@ -47,7 +47,11 @@ static struct my_device_data { struct work_struct work; /* TODO 4: add list for monitored processes */ + struct list_head list; + /* TODO 4: add spinlock to protect list */ + spinlock_t lock; + } dev; static void alloc_io(void) @@ -108,6 +112,26 @@ static void timer_handler(struct timer_list *tl) #endif break; + case TIMER_TYPE_MON: + { + struct mon_proc *p, *n; + + spin_lock(&my_data->lock); + list_for_each_entry_safe(p, n, &my_data->list, list) { + if (p->task->state == TASK_DEAD) { + pr_info("task %s (%d) is dead\n", p->task->comm, + p->task->pid); + put_task_struct(p->task); + list_del(&p->list); + kfree(p); + } + } + + spin_unlock(&my_data->lock); + + mod_timer(&my_data->timer, jiffies + HZ); + break; + } default: break; } @@ -159,9 +183,19 @@ static long deferred_ioctl(struct file *file, unsigned int cmd, unsigned long ar case MY_IOCTL_TIMER_MON: { /* TODO 4: use get_proc() and add task to list */ + struct mon_proc *p = get_proc(arg); + if (IS_ERR(p)) + return PTR_ERR(p); + /* TODO 4: protect access to list */ + spin_lock_bh(&my_data->lock); + list_add(&p->list, &my_data->list); + spin_unlock_bh(&my_data->lock); /* TODO 4: set flag and schedule timer */ + my_data->flag = TIMER_TYPE_MON; + mod_timer(&my_data->timer, jiffies + HZ); + break; } default: @@ -195,6 +229,8 @@ static int deferred_init(void) INIT_WORK(&dev.work, work_handler); /* TODO 4: Initialize lock and list. */ + spin_lock_init(&dev.lock); + INIT_LIST_HEAD(&dev.list); cdev_init(&dev.cdev, &my_fops); cdev_add(&dev.cdev, MKDEV(MY_MAJOR, MY_MINOR), 1); @@ -224,6 +260,11 @@ static void deferred_exit(void) /* TODO 4: ... decrement task usage counter ... */ /* TODO 4: ... remove it from the list ... */ /* TODO 4: ... free the struct mon_proc */ + list_for_each_entry_safe(p, n, &dev.list, list) { + put_task_struct(p->task); + list_del(&p->list); + kfree(p); + } } module_init(deferred_init);