Compare commits

...

12 Commits
a1.3 ... a1.2

Author SHA1 Message Date
hamza
a4ff800d78 - properly turn on debug 2025-05-14 15:21:48 +02:00
hamza
141983790d - fixed a1.2 memory leaks and documented in a1.2.txt 2025-05-08 21:44:13 +02:00
46a6cd2c89 Backports sst fixes 2025-04-25 16:18:43 +02:00
eea50e36c8 Updated a1.2.config 2025-04-17 20:14:10 +02:00
Alexander Lochmann
665a540021 Merge remote-tracking branch 'origin/linux-6.1.y' into a1.2 2025-04-17 19:47:15 +02:00
Alexander Lochmann
9c26da7e87 sst: Quick port of recent fixes from sst branch 2024-05-08 12:30:44 +02:00
Alexander Lochmann
197d13357f Let them find all the leaks 2024-05-02 14:31:26 +02:00
Alexander Lochmann
45c6c2012d Fixed boundedbuffer 2024-05-02 14:30:24 +02:00
Alexander Lochmann
a558bbe732 Added defconfigs for exercises 2024-05-02 14:27:31 +02:00
Alexander Lochmann
6ac7dac4ad sst-driver: Set default config options 2024-05-02 13:54:32 +02:00
Alexander Lochmann
f51ce7f10b Fully implemented SST driver 2024-05-02 12:54:15 +02:00
Alexander Lochmann
303909439d Basic version of SST example module 2024-05-02 12:54:11 +02:00
17 changed files with 19254 additions and 0 deletions

4680
a1.1.config Normal file

File diff suppressed because it is too large Load Diff

4686
a1.2.config Normal file

File diff suppressed because it is too large Load Diff

10
a1.2.txt Normal file
View File

@ -0,0 +1,10 @@
1) a) um debug beim start des kerns zu aktivieren, reicht kern parameter (mit hilfe -a im unserem skript) zu geben dyndbg=\"module sst_chrdev +p\"
b) gleiche idee aber statt module zu wählen, kann mann eine file und zeile auswählen wie z.B
dyndbg=\"file sst_chrdev.c line 40 +p; file sst_chrdev.c line 72 +p\"
2) Mein grundlegendes Verständnis davon, wie kmemleak funktioniert, ist, dass jede neue Speicherzuweisung und ihre Zeiger zusammen mit einer Vielzahl von Metainformationen wie Größe verfolgt werden.
Informationen wie z.B. der Größe verfolgt und in einer Baumstruktur (rbtree) gespeichert wird.
einen Memory Allocator existiert, bedeutet dies, dass der Kernel nicht mehr in der Lage ist, ihn zu zerstören und er wird als Orphan bezeichnet.
3) um detector standardmäßige auszuschalten, kann mann CONFIG_DEBUG_KMEMLEAK=n setzen oder entfernen im kconfig

4684
a1.3.config Normal file

File diff suppressed because it is too large Load Diff

4684
a1.4.config Normal file

File diff suppressed because it is too large Load Diff

View File

@ -239,4 +239,6 @@ source "drivers/peci/Kconfig"
source "drivers/hte/Kconfig"
source "drivers/sst/Kconfig"
endmenu

View File

@ -189,3 +189,4 @@ obj-$(CONFIG_COUNTER) += counter/
obj-$(CONFIG_MOST) += most/
obj-$(CONFIG_PECI) += peci/
obj-$(CONFIG_HTE) += hte/
obj-$(CONFIG_SST) += sst/

View File

@ -22,6 +22,7 @@
#include <net/route.h>
#include <net/xdp.h>
#include <net/net_failover.h>
#include <linux/sst.h>
static int napi_weight = NAPI_POLL_WEIGHT;
module_param(napi_weight, int, 0444);
@ -1674,8 +1675,25 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
struct send_queue *sq;
unsigned int received;
unsigned int xdp_xmit = 0;
#ifdef CONFIG_SST_LOCKING
static unsigned long next_time = 0;
char *question = NULL;
#endif
virtnet_poll_cleantx(rq, budget);
#ifdef CONFIG_SST_LOCKING
if (next_time == 0) {
next_time = msecs_to_jiffies(65000) + jiffies;
} else if (time_after_eq(jiffies, next_time)) {
pr_debug("sst: Sending a random question (0x%lx,0x%lx)\n", in_hardirq(), in_softirq());
next_time = msecs_to_jiffies((get_random_u8() % 100) * 1000 + 15000) + jiffies;
question = kmalloc(sizeof(char) * 100, GFP_NOWAIT);
if (question) {
snprintf(question, 100, sst_questions[(get_random_u8() % SST_MAX_QUESTIONS)]);
sst_produce_question(get_sst_info(), question);
}
}
#endif
received = virtnet_receive(rq, budget, &xdp_xmit);

24
drivers/sst/Kconfig Normal file
View File

@ -0,0 +1,24 @@
# SPDX-License-Identifier: GPL-2.0
#
# Character device configuration
#
menuconfig SST
tristate "Modules for system software techniques"
default y
help
TODO
if SST
config SST_BOUNDS
tristate "Out-of-bounds accesses for exercise a1.3"
default n
help
Activate out-of-bounds accesses for exercise a1.3
config SST_ASYNC_SOURCE
tristate "Enable async source of messages from the universe"
default n
help
This is needed for task a1.4
endif

6
drivers/sst/Makefile Normal file
View File

@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the SST's faulty drivers
#
obj-$(CONFIG_SST) += sst_chrdev.o boundedbuffer.o sst_common.o

View File

@ -0,0 +1,42 @@
#include "sst_internal.h"
#ifdef CONFIG_SST_BOUNDS
#define OFFSET (4 * BOUNDEDBUFFER_SIZE)
#else
#define OFFSET 0
#endif
void init_bbuffer(struct boundedbuffer *buffer) {
buffer->next_in = 0;
buffer->next_out = 0;
buffer->size = BOUNDEDBUFFER_SIZE;
}
int is_full(struct boundedbuffer *buffer) {
return (buffer->next_in + 1) % buffer->size == buffer->next_out;
}
int is_empty(struct boundedbuffer *buffer) {
return buffer->next_out == buffer->next_in;
}
int produce(struct boundedbuffer *buffer, BOUNDEDBUFFER_STORAGE_TYPE data) {
if (is_full(buffer)) {
return -1;
}
buffer->data[buffer->next_in + OFFSET] = data;
buffer->next_in = (buffer->next_in + 1) % buffer->size;
return 0;
}
int consume(struct boundedbuffer *buffer, BOUNDEDBUFFER_STORAGE_TYPE *ret) {
if (is_empty(buffer)) {
return -1;
}
*ret = buffer->data[buffer->next_out + OFFSET];
buffer->next_out = (buffer->next_out + 1) % buffer->size;
return 0;
}

View File

@ -0,0 +1,29 @@
#ifndef __BOUNDEDBUFFER_H__
#define __BOUNDEDBUFFER_H__
/*
* For some reasons, our ring buffer (aka BSB ring buffer)
* can only hold size - 1 elements.
* If we want to store BOUNDEDBUFFER_SIZE elements, as desired,
* the buffer must be one element larger.
* Hence, BOUNDEDBUFFER_SIZE_REAL is used for allocating the actual buffer
* and used for the size member.
*/
#ifndef BOUNDEDBUFFER_SIZE
#error Buffer size not defined!
#endif
#define BOUNDEDBUFFER_SIZE_REAL (BOUNDEDBUFFER_SIZE + 1)
#define BOUNDEDBUFFER_SIZE_VIRT (BOUNDEDBUFFER_SIZE_REAL - 1)
struct boundedbuffer {
int next_in;
int next_out;
int size;
BOUNDEDBUFFER_STORAGE_TYPE data[BOUNDEDBUFFER_SIZE_REAL];
};
void init_bbuffer(struct boundedbuffer *buffer);
int is_full(struct boundedbuffer *buffer);
int is_empty(struct boundedbuffer *buffer);
int produce(struct boundedbuffer *buffer, BOUNDEDBUFFER_STORAGE_TYPE data);
int consume(struct boundedbuffer *buffer, BOUNDEDBUFFER_STORAGE_TYPE *ret);
#endif // __BOUNDEDBUFFER_H__

136
drivers/sst/sst_chrdev.c Normal file
View File

@ -0,0 +1,136 @@
#include "sst_internal.h"
#include "../../include/linux/slab.h"
#include <linux/module.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#define SST_CHRDEV "the-universe"
static int sst_chrdev_major = 0;
static struct device *my_universe = NULL;
static int universe_open(struct inode *inode, struct file *file) {
file->private_data = get_sst_info();
return 0;
}
static int universe_release(struct inode *inode, struct file *file) {
return 0;
}
static ssize_t universe_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos) {
struct sst_info *sst_info = (struct sst_info*)file->private_data;
char *answer = NULL;
int min = 0;
size_t len = 0;
if (sst_consume_answer(sst_info, &answer)) {
pr_debug("Cannot read from answers!\n");
kfree(answer);
return 0;
}
len = strlen(answer);
sst_debug("About to copy %lu bytes of your answer at 0x%lx to the userspace\n", len, (uintptr_t)answer);
min = min(len, count);
if (min != len) {
pr_err("Sorry, your buffer is %lu bytes too small.\n", len - min);
}
if (copy_to_user(buf, answer, min)) {
pr_err("User copy failed!\n");
kfree(answer);
return -EFAULT;
}
sst_debug("Copied %u bytes of your answer to the userspace: %s\n", min, answer);
*ppos += len;
kfree(answer);
return len;
}
static ssize_t universe_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos) {
struct sst_info *sst_info = (struct sst_info*)file->private_data;
char *buf_copy;
int err;
buf_copy = memdup_user_nul(buf, count);
if (IS_ERR(buf_copy)) {
return PTR_ERR(buf_copy);
}
err = sst_produce_question(sst_info, buf_copy);
if (err) {
pr_err("Weird! The universe is full.\n");
kfree(buf_copy);
return -ENOMEM;
}
sst_debug("Asked the universe a question...\n");
kfree(buf_copy);
return count;
}
static const struct file_operations universe_fops = {
.owner = THIS_MODULE,
.read = universe_read,
.write = universe_write,
.open = universe_open,
.release = universe_release,
};
static struct class universe_class = {
.name = SST_CHRDEV,
};
static int __init sst_chrdev_init(void) {
int err;
sst_chrdev_major = err = register_chrdev(0, SST_CHRDEV, &universe_fops);
if (err < 0) {
pr_err("Cannot register chrdev: %d\n", err);
goto out;
}
err = class_register(&universe_class);
if (err) {
pr_err("Cannot register universe class: %d\n", err);
goto out_chrdev;
}
my_universe = device_create(&universe_class, NULL, MKDEV(sst_chrdev_major, 0), NULL, SST_CHRDEV);
if (IS_ERR(my_universe)) {
err = PTR_ERR(my_universe);
pr_err("Cannot create device: %d\n", err);
goto out_class;
}
err = sst_init();
if (err) {
pr_err("Cannot init sst_common: %d\n", err);
goto out_device;
}
pr_notice("Loaded module %s\n", KBUILD_MODNAME);
return 0;
out_device:
device_destroy(&universe_class, MKDEV(sst_chrdev_major, 0));
out_class:
class_unregister(&universe_class);
out_chrdev:
unregister_chrdev(sst_chrdev_major, SST_CHRDEV);
out:
return err;
}
static void __exit sst_chrdev_exit(void) {
sst_destroy();
device_destroy(&universe_class, MKDEV(sst_chrdev_major, 0));
class_unregister(&universe_class);
unregister_chrdev(sst_chrdev_major, SST_CHRDEV);
pr_notice("Unloaded module %s\n", KBUILD_MODNAME);
}
module_init(sst_chrdev_init);
module_exit(sst_chrdev_exit);
MODULE_LICENSE("LGPL");

186
drivers/sst/sst_common.c Normal file
View File

@ -0,0 +1,186 @@
#include "sst_internal.h"
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/random.h>
#include <linux/slab.h>
static sst_info_t *cur_sst_info = NULL;
static char an_answer[] = "You shall ask a question!\n";
char *sst_questions[SST_MAX_QUESTIONS] = {
"What is the answer to the Ultimate Question of Life, The Universe, and Everything?",
"What do you get if you multiply six by nine?"
};
EXPORT_SYMBOL(sst_questions);
char *sst_answers[SST_MAX_ANSWERS] = {
"42!\n",
"Six by nine. Forty two.\n",
"Flash!, a-ah. Savior of the Universe. Flash!, a-ah.\n"
};
EXPORT_SYMBOL(sst_answers);
sst_info_t* get_sst_info(void) {
return cur_sst_info;
}
EXPORT_SYMBOL(get_sst_info);
static int control_thread_work(void *data) {
sst_info_t *info = (sst_info_t*)data;
int err, i;
#if 0
int sleep = 0;
#endif
size_t len_answer = 0, len_question = 0;
char *question = NULL, *answer = NULL, *my_answer = NULL;
sst_debug("Using data at 0x%lx\n", (uintptr_t)info);
while(1) {
wait_event_interruptible(info->wait, !is_empty(&info->questions));
if (kthread_should_stop()) {
break;
}
err = sst_consume_question(info, &question);
if (err) {
pr_err("Questions was empty!\n");
continue;
} else if (question == NULL) {
pr_err("Question is NULL although ret value is 0.\n");
continue;
} else {
sst_debug("Received msg '%s' at 0x%lx\n", question, (uintptr_t)question);
}
len_question = strlen(question);
if (len_question > 2 && (question[len_question - 1] == '?' ||
(question[len_question - 1] == '\n' && question[len_question - 2] == '?'))) {
my_answer = sst_answers[0];
for (i = 0; i < SST_MAX_QUESTIONS; i++) {
if (strcmp(question, sst_questions[i]) == 0) {
my_answer = sst_answers[i];
break;
}
}
} else {
my_answer = an_answer;
}
len_answer = strlen(my_answer) + 1;
answer = kmalloc(len_answer, GFP_KERNEL);
if (!answer) {
pr_err("Cannot allocate memory for answer!\n");
kfree(question);
continue;
}
snprintf(answer, len_answer, "%s", my_answer);
if (sst_produce_answer(info, answer)) {
pr_err("Answers is full!\n");
kfree(answer);
} else {
sst_debug("The universe has an answer at 0x%lx for you!\n", (uintptr_t)answer);
}
#if 0
sleep = get_random_u8() % 90;
sst_debug("Randomly sleeping for %d secs. ZzzzZZzz\n", sleep);
ssleep(sleep);
#endif
}
return 0;
}
int sst_init(void) {
cur_sst_info = kmalloc(sizeof(*cur_sst_info), GFP_KERNEL);
if (!cur_sst_info) {
return -ENOMEM;
}
spin_lock_init(&cur_sst_info->lock_questions);
spin_lock_init(&cur_sst_info->lock_answers);
sema_init(&cur_sst_info->answers_rdy, 0);
init_waitqueue_head(&cur_sst_info->wait);
init_bbuffer(&cur_sst_info->answers);
init_bbuffer(&cur_sst_info->questions);
sst_debug("Allocated private data for the universe at [0x%lx,0x%lx]\n", (uintptr_t)cur_sst_info, (uintptr_t)((uintptr_t)cur_sst_info + sizeof(*cur_sst_info)));
cur_sst_info->thread = kthread_create(control_thread_work, get_sst_info(), "sst-worker-%d", 1);
if (IS_ERR(cur_sst_info->thread)) {
kfree(cur_sst_info);
return -EFAULT;
}
wake_up_process(cur_sst_info->thread);
sst_debug("Created and started control thread (%d)\n", cur_sst_info->thread->pid);
return 0;
}
EXPORT_SYMBOL(sst_init);
void sst_destroy(void) {
sst_debug("Waiting for control thread (%d) to terminate...\n", cur_sst_info->thread->pid);
kthread_stop(cur_sst_info->thread);
sst_debug("Control thread (%d) terminated.\n", cur_sst_info->thread->pid);
kfree(cur_sst_info);
sst_debug("Freed private data for the universe at 0x%lx\n", (uintptr_t)cur_sst_info);
};
EXPORT_SYMBOL(sst_destroy);
int sst_produce_question(sst_info_t *info, char *value) {
int err = 0;
if (!info) {
return -1;
}
sst_debug("%s:info=%lx, questions=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->questions);
spin_lock_bh(&info->lock_questions);
err = produce(&info->questions, value);
spin_unlock_bh(&info->lock_questions);
if (!err) {
wake_up_interruptible(&info->wait);
}
return err;
}
EXPORT_SYMBOL(sst_produce_question);
int sst_produce_answer(sst_info_t *info, char *value) {
int err = 0;
unsigned long flags;
if (!info) {
return -1;
}
sst_debug("%s:info=%lx, answers=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->answers);
spin_lock_irqsave(&info->lock_answers, flags);
err = produce(&info->answers, value);
spin_unlock_irqrestore(&info->lock_answers, flags);
up(&info->answers_rdy);
return err;
}
EXPORT_SYMBOL(sst_produce_answer);
int sst_consume_question(sst_info_t *info, char **value) {
int err = 0;
if (!info) {
return -1;
}
sst_debug("%s:info=%lx, questions=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->questions);
spin_lock_bh(&info->lock_questions);
err = consume(&info->questions, value);
spin_unlock_bh(&info->lock_questions);
return err;
}
EXPORT_SYMBOL(sst_consume_question);
int sst_consume_answer(sst_info_t *info, char **value) {
int err = 0;
unsigned long flags;
if (!info) {
return -1;
}
sst_debug("%s:info=%lx, answers=%lx\n", __func__, (uintptr_t)cur_sst_info, (uintptr_t)&info->answers);
if (down_trylock(&info->answers_rdy)) {
sst_debug("Sry. No answer for you!\n");
return -2;
}
spin_lock_irqsave(&info->lock_answers, flags);
err = consume(&info->answers, value);
spin_unlock_irqrestore(&info->lock_answers, flags);
return err;
}
EXPORT_SYMBOL(sst_consume_answer);

View File

@ -0,0 +1,30 @@
#ifndef __SST_INTERNAL_H__
#define __SST_INTERNAL_H__
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/printk.h>
#define sst_debug(format, ...) \
pr_debug("(file:%s,line:%d,pid:%d): " format, \
__FILE__, __LINE__, \
current->pid, ##__VA_ARGS__)
#include <linux/sst.h>
#define BOUNDEDBUFFER_SIZE 20
#define BOUNDEDBUFFER_STORAGE_TYPE char*
#include "boundedbuffer.h"
#include <linux/spinlock.h>
#include <linux/semaphore.h>
#include <linux/wait.h>
struct sst_info {
struct boundedbuffer questions;
struct semaphore answers_rdy;
struct boundedbuffer answers;
struct task_struct *thread;
wait_queue_head_t wait;
spinlock_t lock_questions;
spinlock_t lock_answers;
};
typedef struct sst_info sst_info_t;
#endif // __SST_INTERNAL_H__

17
include/linux/sst.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef __SST_H__
#define __SST_H__
#define SST_MAX_QUESTIONS 2
extern char *sst_questions[SST_MAX_QUESTIONS];
#define SST_MAX_ANSWERS 3
extern char *sst_answers[SST_MAX_ANSWERS];
struct sst_info;
int sst_init(void);
void sst_destroy(void);
struct sst_info* get_sst_info(void);
int sst_produce_question(struct sst_info *info, char *value);
int sst_produce_answer(struct sst_info *info, char *value);
int sst_consume_question(struct sst_info *info, char **value);
int sst_consume_answer(struct sst_info *info, char **value);
#endif // __SST_H__

View File

@ -45,6 +45,8 @@
#include <linux/compat.h>
#include <linux/random.h>
#include <linux/sysctl.h>
#include <linux/sst.h>
#include <linux/random.h>
#include <linux/uaccess.h>
#include <asm/unistd.h>
@ -1840,6 +1842,10 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h)
*/
static void run_local_timers(void)
{
#ifdef CONFIG_SST_LOCKING
static unsigned long next_time = 0;
char *answer = NULL;
#endif
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
hrtimer_run_queues();
@ -1852,6 +1858,19 @@ static void run_local_timers(void)
if (time_before(jiffies, base->next_expiry))
return;
}
#ifdef CONFIG_SST_LOCKING
if (next_time == 0) {
next_time = msecs_to_jiffies(65000) + jiffies;
} else if (time_after_eq(jiffies, next_time)) {
pr_debug("sst: Sending a random answer\n");
next_time = msecs_to_jiffies((get_random_u8() % 100) * 1000 + 15000) + jiffies;
answer = kmalloc(sizeof(char) * 100, GFP_NOWAIT);
if (answer) {
snprintf(answer, 100, sst_answers[(get_random_u8() % SST_MAX_ANSWERS)]);
sst_produce_answer(get_sst_info(), answer);
}
}
#endif
raise_softirq(TIMER_SOFTIRQ);
}