Compare commits
4 commits
1441afda58
...
d50dadc153
Author | SHA1 | Date | |
---|---|---|---|
d50dadc153 | |||
bfd0eb6be1 | |||
050fe309f9 | |||
3d9046f06d |
5 changed files with 316 additions and 51 deletions
61
README.md
61
README.md
|
@ -28,6 +28,15 @@ 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
|
Parfois, d'autres commandes sont nécessaires. Lisez la partie réponse pour
|
||||||
avoir ces dernières.
|
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
|
## Réponses
|
||||||
|
|
||||||
L'Eudyptula challenge demande souvent des preuves de notre réussite. Vous
|
L'Eudyptula challenge demande souvent des preuves de notre réussite. Vous
|
||||||
|
@ -230,6 +239,58 @@ ls -l /sys/kernel/debug/eudyptula/
|
||||||
* [Chapitre 3, Linux Device Drivers, 3rd Edition](https://lwn.net/Kernel/LDD3/)
|
* [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)
|
* [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/)
|
||||||
|
|
||||||
## Informations diverses
|
## Informations diverses
|
||||||
|
|
||||||
Je liste dans cette section quelques informations que j'ai pu découvrir en
|
Je liste dans cette section quelques informations que j'ai pu découvrir en
|
||||||
|
|
|
@ -41,4 +41,4 @@ module_exit(my_exit);
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("rick <rick@gnous.eu>");
|
MODULE_AUTHOR("rick <rick@gnous.eu>");
|
||||||
MODULE_DESCRIPTION("Module chargé lorsqu'un un clavier est branché.");
|
MODULE_DESCRIPTION("Module chargé lorsqu'un clavier est branché.");
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
|
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/rwsem.h>
|
#include <linux/rwsem.h>
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#include <linux/kernel.h>
|
#include <linux/delay.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BUFFER_LENGTH 10
|
#define BUFFER_LENGTH 10
|
||||||
|
@ -23,18 +23,19 @@ static char *id_msg;
|
||||||
static char *foo_msg;
|
static char *foo_msg;
|
||||||
static struct rw_semaphore foo_sem;
|
static struct rw_semaphore foo_sem;
|
||||||
|
|
||||||
static ssize_t id_read(struct file *, char __user *buffer, size_t length, loff_t *offset)
|
static ssize_t id_read(struct file *, char __user *buffer, size_t length,
|
||||||
|
loff_t *offset)
|
||||||
{
|
{
|
||||||
int bytes = 0;
|
int bytes = 0;
|
||||||
const char *msg_tmp = id_msg;
|
const char *msg_tmp = id_msg;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO
|
* TODO
|
||||||
if (!*(msg_tmp + *offset)) {
|
if (!*(msg_tmp + *offset)) {
|
||||||
*offset = 0;
|
*offset = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
msg_tmp += *offset;
|
msg_tmp += *offset;
|
||||||
|
|
||||||
|
@ -82,46 +83,51 @@ static const struct file_operations id_fops = {
|
||||||
.write = id_write,
|
.write = id_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t foo_read(struct file *, char __user *buffer, size_t count, loff_t *offset)
|
static ssize_t foo_read(struct file *, char __user *buffer, size_t count,
|
||||||
|
loff_t *offset)
|
||||||
{
|
{
|
||||||
int bytes = -EINVAL;
|
int bytes = -EINVAL;
|
||||||
int tmp_len = strlen(foo_msg);
|
int tmp_len = strlen(foo_msg);
|
||||||
|
|
||||||
if (*offset > tmp_len) bytes = -EFAULT;
|
if (*offset > tmp_len) {
|
||||||
else if (down_read_trylock(&foo_sem))
|
bytes = -EFAULT;
|
||||||
{
|
} else if (down_read_trylock(&foo_sem)) {
|
||||||
char *tmp_str = foo_msg + *offset;
|
char *tmp_str = foo_msg + *offset;
|
||||||
tmp_len = strlen(tmp_str);
|
|
||||||
|
|
||||||
bytes = tmp_len > count ? count : tmp_len;
|
tmp_len = strlen(tmp_str);
|
||||||
if (copy_to_user(buffer, tmp_str, bytes)) bytes = -EFAULT;
|
bytes = tmp_len > count ? count : tmp_len;
|
||||||
else *offset += bytes;
|
|
||||||
|
if (copy_to_user(buffer, tmp_str, bytes))
|
||||||
|
bytes = -EFAULT;
|
||||||
|
else
|
||||||
|
*offset += bytes;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
msleep(5000);
|
msleep(5000);
|
||||||
#endif
|
#endif
|
||||||
up_read(&foo_sem);
|
up_read(&foo_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t foo_write(struct file *, const char __user *buffer,
|
static ssize_t foo_write(struct file *, const char __user *buffer,
|
||||||
size_t count, loff_t * offset)
|
size_t count, loff_t *offset)
|
||||||
{
|
{
|
||||||
int bytes = -EINVAL;
|
int bytes = -EINVAL;
|
||||||
|
|
||||||
if ((*offset + count) > PAGE_SIZE) bytes = -EFAULT;
|
if ((*offset + count) > PAGE_SIZE) {
|
||||||
else if (down_write_trylock(&foo_sem))
|
bytes = -EFAULT;
|
||||||
{
|
} else if (down_write_trylock(&foo_sem)) {
|
||||||
bytes = count;
|
bytes = count;
|
||||||
if (copy_from_user(foo_msg, buffer, bytes)) bytes = -EINVAL;
|
if (copy_from_user(foo_msg, buffer, bytes))
|
||||||
|
bytes = -EINVAL;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
msleep(5000);
|
msleep(5000);
|
||||||
#endif
|
#endif
|
||||||
up_write(&foo_sem);
|
up_write(&foo_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations foo_fops = {
|
static const struct file_operations foo_fops = {
|
||||||
|
@ -132,25 +138,25 @@ static const struct file_operations foo_fops = {
|
||||||
|
|
||||||
static int __init my_init(void)
|
static int __init my_init(void)
|
||||||
{
|
{
|
||||||
init_rwsem(&foo_sem);
|
init_rwsem(&foo_sem);
|
||||||
id_msg = kmalloc(12, GFP_KERNEL);
|
id_msg = kmalloc(12, GFP_KERNEL);
|
||||||
foo_msg = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
foo_msg = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||||
strcpy(id_msg, "pouetpouet\n");
|
strscpy(id_msg, "pouetpouet\n", 12);
|
||||||
pr_info("Coucou le gens !!!!\n");
|
pr_info("Coucou le gens !!!!\n");
|
||||||
|
|
||||||
folder = debugfs_create_dir("eudyptula", NULL);
|
folder = debugfs_create_dir("eudyptula", NULL);
|
||||||
id_file = debugfs_create_file("id", 0666, folder, NULL, &id_fops);
|
id_file = debugfs_create_file("id", 0666, folder, NULL, &id_fops);
|
||||||
debugfs_create_u64("jiffies", 0444, folder, &jiffies_64);
|
debugfs_create_u64("jiffies", 0444, folder, &jiffies_64);
|
||||||
foo_file = debugfs_create_file("foo", 0664, folder, NULL, &foo_fops);
|
foo_file = debugfs_create_file("foo", 0664, folder, NULL, &foo_fops);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit my_exit(void)
|
static void __exit my_exit(void)
|
||||||
{
|
{
|
||||||
debugfs_remove_recursive(folder);
|
debugfs_remove_recursive(folder);
|
||||||
kfree(id_msg);
|
kfree(id_msg);
|
||||||
kfree(foo_msg);
|
kfree(foo_msg);
|
||||||
pr_info("Tschuss !!!\n");
|
pr_info("Tschuss !!!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
task_09/Makefile
Normal file
9
task_09/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
obj-m += sysfs.o
|
||||||
|
|
||||||
|
PWD := $(CURDIR)
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
|
189
task_09/sysfs.c
Normal file
189
task_09/sysfs.c
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
#define DEBUG 1
|
||||||
|
|
||||||
|
#include <asm/page.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/kobject.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/rwsem.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/sysfs.h>
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BUFFER_LENGTH 10
|
||||||
|
|
||||||
|
// représente un dossier sur sysfs
|
||||||
|
static struct kobject eudyptula;
|
||||||
|
|
||||||
|
// représente un fichier sur sysfs
|
||||||
|
static struct attribute id_file = {
|
||||||
|
.name = "id",
|
||||||
|
.mode = 0666
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute jiffies_file = {
|
||||||
|
.name = "jiffies",
|
||||||
|
.mode = 0444
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute foo_file = {
|
||||||
|
.name = "foo",
|
||||||
|
.mode = 0644
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *id_msg;
|
||||||
|
static char *foo_msg;
|
||||||
|
static struct rw_semaphore foo_sem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fonctions pour pouvoir lire et écrire dans les fichiers. elles sont ici
|
||||||
|
* découpées pour mieux se rendre compte. Il faut cependant les appeler depuis
|
||||||
|
* les fonctions se trouvant plus bas.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static ssize_t id_read(char *buffer)
|
||||||
|
{
|
||||||
|
return sysfs_emit(buffer, id_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t id_write(const char *buffer, size_t size)
|
||||||
|
{
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
if (!strcmp(buffer, "congruent"))
|
||||||
|
ret = size;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t jiffies_read(char *buffer)
|
||||||
|
{
|
||||||
|
return sprintf(buffer, "%lld\n", jiffies_64);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t foo_read(char *buffer)
|
||||||
|
{
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
if (down_read_trylock(&foo_sem)) {
|
||||||
|
ret = sysfs_emit(buffer, foo_msg);
|
||||||
|
#ifdef DEBUG
|
||||||
|
msleep(5000);
|
||||||
|
#endif
|
||||||
|
up_read(&foo_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t foo_write(const char *buffer, size_t count)
|
||||||
|
{
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
if (down_write_trylock(&foo_sem)) {
|
||||||
|
ret = strscpy(foo_msg, buffer, count + 1);
|
||||||
|
#ifdef DEBUG
|
||||||
|
msleep(5000);
|
||||||
|
#endif
|
||||||
|
up_write(&foo_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fonctions utilisées pour lire et écrire dans les attributes. Elles sont
|
||||||
|
* mises dans une structure sysfs_ops et mis à l'initialisation du kobject via
|
||||||
|
* un ktype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ssize_t show(struct kobject *kobj, struct attribute *attr, char *buffer)
|
||||||
|
{
|
||||||
|
ssize_t ret = 0;
|
||||||
|
|
||||||
|
if (!strcmp(attr->name, "id"))
|
||||||
|
ret = id_read(buffer);
|
||||||
|
else if (!strcmp(attr->name, "jiffies"))
|
||||||
|
ret = jiffies_read(buffer);
|
||||||
|
else if (!strcmp(attr->name, "foo"))
|
||||||
|
ret = foo_read(buffer);
|
||||||
|
else
|
||||||
|
pr_info("keske tu essaies de lire ?!");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t store(struct kobject *kobj, struct attribute *attr, const char *buffer,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
ssize_t ret = 0;
|
||||||
|
|
||||||
|
if (!strcmp(attr->name, "id"))
|
||||||
|
ret = id_write(buffer, len);
|
||||||
|
else if (!strcmp(attr->name, "foo"))
|
||||||
|
ret = foo_write(buffer, len);
|
||||||
|
else
|
||||||
|
pr_info("keske tu essaies d'ecrire ?!");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sysfs_ops my_ops = {
|
||||||
|
.show = &show,
|
||||||
|
.store = &store,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct kobj_type my_type = {
|
||||||
|
.sysfs_ops = &my_ops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init my_init(void)
|
||||||
|
{
|
||||||
|
pr_info("Coucou le gens !!!!\n");
|
||||||
|
|
||||||
|
if (!memset(&eudyptula, 0, sizeof(struct kobject)))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (kobject_init_and_add(&eudyptula, &my_type, NULL, "eudyptula")) {
|
||||||
|
kobject_put(&eudyptula);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sysfs_create_file(&eudyptula, &id_file)
|
||||||
|
|| sysfs_create_file(&eudyptula, &jiffies_file)
|
||||||
|
|| sysfs_create_file(&eudyptula, &foo_file)) {
|
||||||
|
kobject_put(&eudyptula);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_rwsem(&foo_sem);
|
||||||
|
id_msg = kmalloc(12, GFP_KERNEL);
|
||||||
|
foo_msg = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||||
|
strscpy(id_msg, "pouetpouet\n", 12);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit my_exit(void)
|
||||||
|
{
|
||||||
|
sysfs_remove_file(&eudyptula, &id_file);
|
||||||
|
sysfs_remove_file(&eudyptula, &jiffies_file);
|
||||||
|
sysfs_remove_file(&eudyptula, &foo_file);
|
||||||
|
kobject_put(&eudyptula);
|
||||||
|
kfree(id_msg);
|
||||||
|
kfree(foo_msg);
|
||||||
|
pr_info("Tschuss !!!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(my_init);
|
||||||
|
module_exit(my_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("rick <rick@gnous.eu>");
|
||||||
|
MODULE_DESCRIPTION("Module pour tester le sysfs.");
|
Loading…
Add table
Reference in a new issue