eudyptula/README.md
2024-02-04 23:07:41 +01:00

435 lines
15 KiB
Markdown

# Eudyptula Challenge
Le challenge étant fermé, je m'appuie sur les questions trouvables sur des
dépôts Github.
Vous pouvez trouver des réponses (ainsi que des questions) [sur
Github](https://github.com/search?q=Eudyptula). Le fichier `TASKS.txt` contient
la liste des taches, reprises du dépot de
[agelastic](https://github.com/agelastic/eudyptula).
À noter que j'utilise la commande `indent -linux` pour pouvoir indenter et
formater les fichiers sources selon la convention du kernel Linux.
J'utilise aussi le script `checkpatch.pl -f` pour pouvoir vérifier plus en
profondeur si mes fichiers sources suivent bien la convention (cf. tâche 4).
## Compilation
La version utilisée et testée a varié durant la réalisation de ce challenge.
Voici la liste des challenges et de la version de Linux utilisée. À noter que
je n'ai pas prit le temps de tester ces challenges sur d'autres versions.
- tâches 1 à 7: 6.1.1, GCC 12
- tâches 8 à ... : 6.6.6, GCC 13
Il vous faut les fichiers d'en-têtes du kernel Linux (`linux-headers` sur les
distributions basées Debian et apt pilulé).
Il suffit ensuite d'aller dans le dossier de votre choix et faire `make`.
Parfois, d'autres commandes sont nécessaires. Lisez la partie réponse pour
avoir ces dernières.
## Tâches non faites
- 2 : je configure et compile moi-même mon kernel
- 7 : pas spécialement envie de compiler le next, je ne vois pas l'intérêt de
le faire
- 10 : je trouve la tache intéressante, mais je n'ai pas le temps pour le
faire ni l'envie d'envoyer des patchs faits par un débutant à des personnes
surchargées. À voir dans le futur cependant.
## Réponses
L'Eudyptula challenge demande souvent des preuves de notre réussite. Vous
pouvez retrouver les commandes et leur résultat ici. Si une tâche n'est pas
indiquée, cela veut surement dire qu'elle n'est pas assez intéressante ou trop
triviale (cf. tâche 7).
### Tâche 1
Pour montrer que mon module marche bien, on regarde les logs du kernel avec la
commande `dmesg`.
```text
# après insmod hello.ko
[102102.117958] Coucou le gens !!!!
# après rmmod hello
[102108.046104] Tschuss !!!
```
* [The Linux Kernel Module Programming Guide](https://sysprog21.github.io/lkmpg)
### Tâche 3
Patch basé sur la version `v6.2-rc5` du kernel Linux, créé avec la commande
`git format-patch -1 HEAD`.
```diff
From 6f41b705dbde5b42167c03b8d14ae695b226cb86 Mon Sep 17 00:00:00 2001
From: rick <rick@gnous.eu>
Date: Mon, 23 Jan 2023 16:49:42 +0100
Subject: [PATCH] custom extraversion
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index c1ead4cd2342..d67f2f5eb831 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
VERSION = 6
PATCHLEVEL = 2
SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -eudyptula
NAME = Hurr durr I'ma ninja sloth
# *DOCUMENTATION*
--
2.39.1
```
### Tâche 4
Je n'ai pas mis les fichiers corrigés. Il suffit d'utiliser la commande
`indent` pour pouvoir bien indenter le code dans un premier temps. Il faut
ensuite utiliser le script `scripts/checkpatch.pl` sur les fichiers pour
trouver les derniers soucis.
* [Les conventions de code (Documentation Kernel)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/coding-style.rst)
### Tâche 5
Il faut dans un premier temps générer l'alias du module. Cela va permettre de
lier les périphériques disponibles pour le module avec.
2 façons:
* `depmod $(uname -r) $(pwd)/task_5/my-usb-detect.ko` en étant à la racine du
dépôt git. **Cela va cependant réécrire le fichier
`/lib/modules/$(uname -r)/modules.alias`, ce qui peut casser votre
installation Linux.** Faites un backup de votre dossier avant.
* `cp task_5/my-usb-detect.ko /lib/modules/$(uname -r)/ && depmod -A`
La deuxième méthode est la plus recommandée. Je l'ai trouvé après avoir écrit
le module sans réussir à le charger. Le blog de Nihaal explique de manière
détaillée le fonctionnement des modules et de la détection de périphériques.
```text
# on branche le clavier
[ 6712.426017 ] usb 2-3: new full-speed USB device number 4 using xhci_hcd
[ 6712.569813 ] usb 2-3: New USB device found, idVendor=046d, idProduct=c52b, bcdDevice=24.01
[ 6712.569826 ] usb 2-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 6712.569830 ] usb 2-3: Product: USB Receiver
[ 6712.569833 ] usb 2-3: Manufacturer: Logitech
[ 6712.575345 ] input: Logitech USB Receiver as /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.0/0003:046D:C52B.0007/input/input32
[ 6712.629923 ] hid-generic 0003:046D:C52B.0007: input,hidraw0: USB HID v1.11 Keyboard [Logitech USB Receiver] on usb-0000:00:14.0-3/input0
[ 6712.634279 ] input: Logitech USB Receiver Mouse as /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.1/0003:046D:C52B.0008/input/input33
[ 6712.634743 ] input: Logitech USB Receiver Consumer Control as /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.1/0003:046D:C52B.0008/input/input34
[ 6712.689561 ] input: Logitech USB Receiver System Control as /devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3:1.1/0003:046D:C52B.0008/input/input35
[ 6712.689844 ] hid-generic 0003:046D:C52B.0008: input,hiddev96,hidraw1: USB HID v1.11 Mouse [Logitech USB Receiver] on usb-0000:00:14.0-3/input1
[ 6712.693283 ] hid-generic 0003:046D:C52B.0009: hiddev97,hidraw2: USB HID v1.11 Device [Logitech USB Receiver] on usb-0000:00:14.0-3/input2
# notre module s'est chargé tout seul !!
[ 6713.143767 ] Coucou le gens !!!!
[ 6713.259818 ] elogind-daemon[3774]: Watching system buttons on /dev/input/event18 (Logitech USB Receiver Consumer Control)
[ 6713.260009 ] elogind-daemon[3774]: Watching system buttons on /dev/input/event19 (Logitech USB Receiver System Control)
[ 6713.663077 ] elogind-daemon[3774]: Watching system buttons on /dev/input/event16 (Logitech USB Receiver)
# le clavier est débranché et notre module n'est pas déchargé.
[ 6716.982578 ] usb 2-3: USB disconnect, device number 4
```
Il faut le décharger à la main avec `rmmod`.
* [Writing USB Device Drivers (Documentation Kernel)](https://www.kernel.org/doc/html/latest/driver-api/usb/writing_usb_driver.html)
* [USB hotplugging/USB Modutils Support (Documentation Kernel)](https://www.kernel.org/doc/html/latest/driver-api/usb/hotplug.html#usb-modutils-support)
* [usb-skeleton.c (Code Kernel)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/usb-skeleton.c)
* [Nihaal - Eudyptula Challenge Task 5](https://nihaal.me/post/ec5/)
## Tâche 6
Il existe plusieurs façons pour créer un nouveau fichier dans `/dev`. J'ai
cependant décidé d'implémenter qu'une seule manière pour l'instant.
Pour pouvoir créer un fichier dans `/dev`, il faut créer le périphérique à la
main. Il faut connaitre le numéro majeur du driver, ce qui se fait ou en
regardant dans le fichier `/proc/devices` ou en regardant le journal du kernel.
Il suffit de taper la commande suivante pour créer le fichier :
`mknod /dev/eudyptula c <majeur> 0`. N'oubliez pas de changer les droits si
vous souhaitez écrire dedans !
**Je n'ai pas suivi les consignes à la lettre, en effet je n'utilise pas un
*misc char device* mais un *char device*.** C'est pour ça qu'il faut créer à
la main le device. Je l'ai codé directement comme ça, ne trouvant pas beaucoup
d'informations sur les *misc char devices*. En lisant des codes sources ainsi
que la documentation, je comprends mieux comment en faire, mais j'ai décidé de
ne pas changer tout le code que j'avais fait. Cepebdant, je le modifierai si
l'on doit faire un *char device* plus tard.
Lorsqu'on ouvre le device, on reçoit la chaine `coucou c'est rick`. Si l'on
souhaite écrire dans le fichier, il faut taper `congruent`, sinon un message
d'erreur est retourné.
```bash
cat /dev/eudyptula
# coucou c'est rick
echo "congruent" > /dev/eudyptula
# aucune réponse, $? vaut 0
echo "bonjour12" > /dev/eudyptula
# -bash: echo: erreur d'écriture : Argument invalide
# $? vaut 1
```
* [Chapitre 3, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
* [Linux Kernel Labs - Character device drivers](https://linux-kernel-labs.github.io/refs/heads/master/labs/device_drivers.html#read-and-write)
* [Nihall - Misc character devices](https://nihaal.me/post/misc_char_devices/)
## Tache 8
L'ajout d'une nouvelle string dans le fichier ne supprime l'entièreté du
contenu du fichier. J'ai testé les sémaphores avec des `msleep`
(`<linux/delay.h>`) rajouté dans le code. Il est possible de tester en
décommentant le premier `define`.
```bash
ls -l /sys/kernel/debug/eudyptula/
# total 0
# -rw-rw-r-- 1 root root 0 Jan 9 22:46 foo
# -rw-rw-rw- 1 root root 0 Jan 9 22:44 id
# -r--r--r-- 1 root root 0 Jan 9 22:45 jiffies
echo pouet > /sys/kernel/debug/eudyptula/foo
cat /sys/kernel/debug/eudyptula/foo
# pouet
echo coucou ! > /sys/kernel/debug/eudyptula/foo
cat /sys/kernel/debug/eudyptula/foo
# coucou !
cat /sys/kernel/debug/eudyptula/id
# pouetpouet
echo congruent > /sys/kernel/debug/eudyptula/id
echo $?
# 0
echo pouet > /sys/kernel/debug/eudyptula/id
# bash: echo: write error: Invalid argument
echo $?
# 1
echo pouet > /sys/kernel/debug/eudyptula/jiffies
# bash: echo: write error: Permission denied
cat /sys/kernel/debug/eudyptula/jiffies
# 4345895105
cat /sys/kernel/debug/eudyptula/jiffies
# 4345895338
echo pouet > /sys/kernel/debug/eudyptula/foo &
cat /sys/kernel/debug/eudyptula/foo
# cat: /sys/kernel/debug/eudyptula/foo: Invalid argument
cat /sys/kernel/debug/eudyptula/foo &
cat /sys/kernel/debug/eudyptula/foo &
echo pouet > /sys/kernel/debug/eudyptula/foo
# bash: echo: write error: Invalid argument
rmmod hello
ls -l /sys/kernel/debug/eudyptula/
# ls: cannot access '/sys/kernel/debug/eudyptula/': No such file or directory
```
* [DebugFS (Documentation kernel)](https://docs.kernel.org/filesystems/debugfs.html)
* [Chapitre 3, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
* [Jiffies, Linux Kernel Development 2nd Edition](https://litux.nl/mirror/kerneldevelopment/0672327201/ch10lev1sec3.html)
### Tache 9
Idem que la tache 8 pour tester les sémaphores.
```bash
ls -l /sys/eudyptula/
# total 0
# -rw-r--r-- 1 root root 4096 Jan 23 18:42 foo
# -rw-rw-rw- 1 root root 4096 Jan 23 18:42 id
# -r--r--r-- 1 root root 4096 Jan 23 18:42 jiffies
echo pouet > /sys/eudyptula/foo
cat /sys/eudyptula/foo
# pouet
echo coucou ! > /sys/eudyptula/foo
cat /sys/eudyptula/foo
# coucou !
cat /sys/eudyptula/id
# pouetpouet
echo -n congruent > /sys/eudyptula/id
echo $?
# 0
echo pouet > /sys/eudyptula/id
# bash: echo: write error: Invalid argument
echo $?
# 1
echo pouet > /sys/eudyptula/jiffies
# bash: /sys/eudyptula/jiffies: Permission denied
cat /sys/eudyptula/jiffies
# 4344413015
cat /sys/eudyptula/jiffies
# 4344413465
echo pouet > /sys/eudyptula/foo &
cat /sys/eudyptula/foo
# cat: /sys/eudyptula/foo: Invalid argument
cat /sys/eudyptula/foo &
cat /sys/eudyptula/foo &
echo pouet > /sys/eudyptula/foo
# bash: echo: write error: Invalid argument
rmmod sysfs
ls -l /sys/eudyptula/
# ls: cannot access '/sys/eudyptula/': No such file or directory
```
* [The zen of kobjects](https://lwn.net/Articles/51437/) : un peu vieux, certaines fonctions pas
à jour
* [kobjects and sysfs](https://lwn.net/Articles/54651/) : idem
* [Everything you never wanted to know about kobjects, ksets, and
ktypes](https://docs.kernel.org/core-api/kobject.html) (documentation noyau)
* [Exemple de code pour
`kobject`](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/samples/kobject)
* [Chapitre 14, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
### Tache 12
Il suffit de charger le menu et de lire les messages noyaux pour voir le bon
fonctionnement. J'ai repris le `main` donné dans l'ennoncé sans le modifier
plus que ça :
```
[1220142.976299] Coucou le gens !!!!
[1220142.976340] id 3 = Dave
[1220142.976346] id 42 not found
[1220148.124624] Tschuss !!!
```
* [Chapitre 11, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
### Tache 13
Il faut mettre un constructeur de manière exceptionnel. Cela permet de l'afficher séparemment dans le fichier `/proc/slabinfo`, sinon Linux va optimiser ça en le regroupant avec un autre cache.
Voici le patch :
```diff
From 4b55e26775647e71c86164aed41d82beeb17febe Mon Sep 17 00:00:00 2001
From: rick <rick@gnous.eu>
Date: Sun, 4 Feb 2024 23:02:32 +0100
Subject: [PATCH] add task 13
---
task_12/list.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/task_12/list.c b/task_12/list.c
index b5fa8fa..a7989be 100644
--- a/task_12/list.c
+++ b/task_12/list.c
@@ -4,6 +4,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/string.h>
#define NAME_SIZE 20
@@ -16,11 +17,13 @@ struct identity {
};
static struct list_head identity_list;
+static struct kmem_cache *cache;
static int identity_create(char *name, int id)
{
int ret = 0;
- struct identity *new = kmalloc(sizeof(*new), GFP_KERNEL);
+ struct identity *new = (struct identity *)kmem_cache_alloc(cache,
+ GFP_KERNEL);
if (!new) {
ret = -ENOMEM;
@@ -63,15 +66,31 @@ static void identity_destroy(int id)
if (tmp) {
list_del(&tmp->list);
- kfree(tmp);
+ kmem_cache_free(cache, tmp);
}
}
+/*
+ * juste pour pouvoir être dans le slabinfo, sinon Linux le fusionne avec un
+ * autre qui a des propriétés similaires.
+ */
+static void my_constructor(void *ptr)
+{
+ memset(ptr, 0, sizeof(struct identity));
+}
+
static int __init my_init(void)
{
struct identity *temp;
pr_info("Coucou le gens !!!!\n");
+ cache =
+ kmem_cache_create("eudyptula_identity", sizeof(struct identity), 0,
+ SLAB_HWCACHE_ALIGN, my_constructor);
+
+ if (!cache)
+ return -ENOMEM;
+
INIT_LIST_HEAD(&identity_list);
if (identity_create("Alice", 1))
@@ -86,8 +105,8 @@ static int __init my_init(void)
temp = identity_find(3);
if (!temp)
pr_info("id 3 not found\n");
- else
- pr_info("id 3 = %s\n", temp->name);
+ else
+ pr_info("id 3 = %s\n", temp->name);
temp = identity_find(42);
if (!temp)
@@ -103,6 +122,7 @@ static int __init my_init(void)
static void __exit my_exit(void)
{
+ kmem_cache_destroy(cache);
pr_info("Tschuss !!!\n");
}
--
2.43.0
```
Et la sortie :
```bash
insmod list.ko
grep eud /proc/slabinfo
# eudyptula_identity 64 64 64 64 1 : tunables 0 0 0 : slabdata 1 1 0
dmesg
# [1246412.478052] Coucou le gens !!!!
# [1246412.478108] id 3 = Dave
# [1246412.478112] id 42 not found
# [1246450.284783] Tschuss !!!
```
* [Chapitre 8, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
## Informations diverses
Je liste dans cette section quelques informations que j'ai pu découvrir en
lisant des ressources histoire de pouvoir les retrouver rapidement dans le
futur.
### /proc
* `devices` : On peut retrouver la liste des drivers avec leur numéro majeur,
le tout découpé entre les *character devices* et les *block devices*.
### Les *devices*
* *character devices*: on ne lit qu'un caractère dans ce type de device, c'est
comme ça que fonctionne un clavier par exemple
* *block devices*: on va lire le device uniquement par "block" (`char *` ou
`char[]`), le disque dur par exemple