add tasks list
This commit is contained in:
parent
d50dadc153
commit
aa602678c0
2 changed files with 797 additions and 8 deletions
12
README.md
12
README.md
|
@ -3,9 +3,10 @@
|
|||
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). Je rajouterai peut-être la
|
||||
liste des questions plus tard, afin de vous épargner quelques clics.
|
||||
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.
|
||||
|
@ -58,11 +59,6 @@ commande `dmesg`.
|
|||
|
||||
* [The Linux Kernel Module Programming Guide](https://sysprog21.github.io/lkmpg)
|
||||
|
||||
### Tâche 2
|
||||
|
||||
J'utilise Gentoo et configure puis compile moi-même mon kernel. Je passe cette
|
||||
étape.
|
||||
|
||||
### Tâche 3
|
||||
|
||||
Patch basé sur la version `v6.2-rc5` du kernel Linux, créé avec la commande
|
||||
|
|
793
TASKS.txt
Normal file
793
TASKS.txt
Normal file
|
@ -0,0 +1,793 @@
|
|||
My solutions to Eudyptula challenges.
|
||||
Tasks:
|
||||
|
||||
This is Task 01 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Write a Linux kernel module, and stand-alone Makefile, that when loaded
|
||||
prints to the kernel debug log level, "Hello World!" Be sure to make
|
||||
the module be able to be unloaded as well.
|
||||
|
||||
The Makefile should build the kernel module against the source for the
|
||||
currently running kernel, or, use an environment variable to specify
|
||||
what kernel tree to build it against.
|
||||
|
||||
Please show proof of this module being built, and running, in your
|
||||
kernel. What this proof is is up to you, I'm sure you can come up with
|
||||
something. Also be sure to send the kernel module you wrote, along with
|
||||
the Makefile you created to build the module.
|
||||
|
||||
Remember to use your ID assigned to you in the Subject: line when
|
||||
responding to this task, so that I can figure out who to attribute it
|
||||
to. You can just respond to the task with the answers and all should be
|
||||
fine.
|
||||
|
||||
If you forgot, your id is "7c1caf2f50d1". But of course you have not
|
||||
forgotten that yet, you are better than that.
|
||||
|
||||
This is Task 02 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Now that you have written your first kernel module, it's time to take
|
||||
off the training wheels and move on to building a custom kernel. No
|
||||
more distro kernels for you, for this task you must run your own kernel.
|
||||
And use git! Exciting isn't it! No, oh, ok...
|
||||
|
||||
The tasks for this round is:
|
||||
- download Linus's latest git tree from git.kernel.org (you have to
|
||||
figure out which one is his, it's not that hard, just remember what
|
||||
his last name is and you should be fine.)
|
||||
- build it, install it, and boot it. You can use whatever kernel
|
||||
configuration options you wish to use, but you must enable
|
||||
CONFIG_LOCALVERSION_AUTO=y.
|
||||
- show proof of booting this kernel. Bonus points for you if you do
|
||||
it on a "real" machine, and not a virtual machine (virtual machines
|
||||
are acceptable, but come on, real kernel developers don't mess
|
||||
around with virtual machines, they are too slow. Oh yeah, we aren't
|
||||
real kernel developers just yet. Well, I'm not anyway, I'm just a
|
||||
script...) Again, proof of running this kernel is up to you, I'm
|
||||
sure you can do well.
|
||||
|
||||
Hint, you should look into the 'make localmodconfig' option, and base
|
||||
your kernel configuration on a working distro kernel configuration.
|
||||
Don't sit there and answer all 1625 different kernel configuration
|
||||
options by hand, even I, a foolish script, know better than to do that!
|
||||
|
||||
After doing this, don't throw away that kernel and git tree and
|
||||
configuration file. You'll be using it for later tasks, a working
|
||||
kernel configuration file is a precious thing, all kernel developers
|
||||
have one they have grown and tended to over the years. This is the
|
||||
start of a long journey with yours, don't discard it like was a broken
|
||||
umbrella, it deserves better than that.
|
||||
|
||||
Remember to use your ID assigned to you in the Subject: line when
|
||||
responding to this task, so that I can figure out who to attribute it
|
||||
to.
|
||||
|
||||
If you forgot, your id is "7c1caf2f50d1". But why do I repeat myself?
|
||||
Of course you know your id, you made it through the first task just fine
|
||||
with it.
|
||||
|
||||
This is Task 03 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Now that you have your custom kernel up and running, it's time to modify
|
||||
it!
|
||||
|
||||
The tasks for this round is:
|
||||
- take the kernel git tree from Task 02 and modify the Makefile to
|
||||
and modify the EXTRAVERSION field. Do this in a way that the
|
||||
running kernel (after modifying the Makefile, rebuilding, and
|
||||
rebooting) has the characters "-eudyptula" in the version string.
|
||||
- show proof of booting this kernel. Extra cookies for you by
|
||||
providing creative examples, especially if done in intrepretive
|
||||
dance at your local pub.
|
||||
- Send a patch that shows the Makefile modified. Do this in a manner
|
||||
that would be acceptable for merging in the kernel source tree.
|
||||
(Hint, read the file Documentation/SubmittingPatches and follow the
|
||||
steps there.)
|
||||
|
||||
Remember to use your ID assigned to you in the Subject: line when
|
||||
responding to this task, so that I can figure out who to attribute it
|
||||
to.
|
||||
|
||||
If you forgot, your id is "7c1caf2f50d1". Surely I don't need to keep
|
||||
saying this right? I know, _you_ wouldn't forget, but someone else, of
|
||||
course they would, so I'll just leave it here for those "others".
|
||||
|
||||
This is Task 04 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Wonderful job in making it this far, I hope you have been having fun.
|
||||
Oh, you're getting bored, just booting and installing kernels? Well,
|
||||
time for some pedantic things to make you feel that those kernel builds
|
||||
are actually fun!
|
||||
|
||||
Part of the job of being a kernel developer is recognizing the proper
|
||||
Linux kernel coding style. The full description of this coding style
|
||||
can be found in the kernel itself, in the Documentation/CodingStyle
|
||||
file. I'd recommend going and reading that right now, it's pretty
|
||||
simple stuff, and something that you are going to need to know and
|
||||
understand. There is also a tool in the kernel source tree in the
|
||||
scripts/ directory called checkpatch.pl that can be used to test for
|
||||
adhering to the coding style rules, as kernel programmers are lazy and
|
||||
prefer to let scripts do their work for them...
|
||||
|
||||
And why a coding standard at all? That's because of your brain (yes,
|
||||
yours, not mine, remember, I'm just some dumb shell scripts). Once your
|
||||
brain learns the patterns, the information contained really starts to
|
||||
sink in better. So it's important that everyone follow the same
|
||||
standard so that the patterns become consistent. In other words, you
|
||||
want to make it really easy for other people to find the bugs in your
|
||||
code, and not be confused and distracted by the fact that you happen to
|
||||
prefer 5 spaces instead of tabs for indentation. Of course you would
|
||||
never prefer such a thing, I'd never accuse you of that, it was just an
|
||||
example, please forgive my impertinence!
|
||||
|
||||
Anyway, the tasks for this round all deal with the Linux kernel coding
|
||||
style. Attached to this message are two kernel modules that do not
|
||||
follow the proper Linux kernel coding style rules. Please fix both of
|
||||
them up, and send it back to me in such a way that does follow the
|
||||
rules.
|
||||
|
||||
What, you recognize one of these modules? Imagine that, perhaps I was
|
||||
right to accuse you of the using a "wrong" coding style :)
|
||||
|
||||
Yes, the logic in the second module is crazy, and probably wrong, but
|
||||
don't focus on that, just look at the patterns here, and fix up the
|
||||
coding style, do not remove lines of code.
|
||||
|
||||
As always, please remember to use your ID assigned to you in the
|
||||
Subject: line when responding to this task, so that I can figure out who
|
||||
to attribute it to. And if you forgot (which of course you have not,
|
||||
we've been through all of this before), your id is "7c1caf2f50d1".
|
||||
|
||||
This is Task 05 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Yeah, you survived the coding style mess! Now, on to some "real"
|
||||
things, as I know you are getting bored by these so far.
|
||||
|
||||
So, simple task this time around:
|
||||
- take the kernel module you wrote for task 01, and modify it so that
|
||||
when a USB keyboard is plugged in, the module will be automatically
|
||||
loaded by the correct userspace hotplug tools (which are implemented
|
||||
by depmod / kmod / udev / mdev / systemd, depending on what distro
|
||||
you are using.)
|
||||
|
||||
Yes, so simple, and yet, it's a bit tricky. As a hint, go read chapter
|
||||
14 of the book, "Linux Device Drivers, 3rd edition." Don't worry, it's
|
||||
free, and online, no need to go buy anything.
|
||||
|
||||
As always, please remember to use your ID assigned to you, yadda yadda
|
||||
yadda... It's "7c1caf2f50d1" of course.
|
||||
|
||||
This is Task 06 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Nice job with the module loading macros, those are tricky, but a very
|
||||
valuable skill to know about, especially when running across them in
|
||||
real kernel code.
|
||||
|
||||
Speaking of real kernel code, let's write some!
|
||||
|
||||
The task this time is this:
|
||||
- Take the kernel module you wrote for task 01, and modify it to be a
|
||||
misc char device driver. The misc interface is a very simple way to
|
||||
be able to create a character device, without having to worry about
|
||||
all of the sysfs and character device registration mess. And what a
|
||||
mess it is, so stick to the simple interfaces wherever possible.
|
||||
- The misc device should be created with a dynamic minor number, no
|
||||
need running off and trying to reserve a real minor number for your
|
||||
test module, that would be crazy.
|
||||
- The misc device should implement the read and write functions.
|
||||
- The misc device node should show up in /dev/eudyptula.
|
||||
- When the character device node is read from, your assigned id is
|
||||
returned to the caller.
|
||||
- When the character device node is written to, the data sent to the
|
||||
kernel needs to be checked. If it matches your assigned id, then
|
||||
return a correct write return value. If the value does not match
|
||||
your assigned id, return the "invalid value" error value.
|
||||
- The misc device should be registered when your module is loaded, and
|
||||
unregistered when it is unloaded.
|
||||
- Provide some "proof" this all works properly.
|
||||
|
||||
As you will be putting your id into the kernel module, of course you
|
||||
haven't forgotten it, but just to be safe, it's "7c1caf2f50d1".
|
||||
|
||||
This is Task 07 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Great work with that misc device driver. Isn't that a nice and simple
|
||||
way to write a character driver?
|
||||
|
||||
Just when you think this challenge is all about writing kernel code,
|
||||
this task is a throwback to your second one. Yes, that's right,
|
||||
building kernels. Turns out that's what most developers end up doing,
|
||||
tons and tons of rebuilds, not writing new code. Sad, but it is a good
|
||||
skill to know.
|
||||
|
||||
The tasks this round are:
|
||||
- Download the linux-next kernel for today. Or tomorrow, just use
|
||||
the latest one. It changes every day so there is no specific one
|
||||
you need to pick. Build it. Boot it. Provide proof that you built
|
||||
and booted it.
|
||||
|
||||
What is the linux-next kernel? Ah, that's part of the challenge.
|
||||
|
||||
For a hint, you should read the excellent documentation about how the
|
||||
Linux kernel is developed in Documentation/development-process/ in the
|
||||
kernel source itself. It's a great read, and should tell you all you
|
||||
never wanted to know about what Linux kernel developers do and how they
|
||||
do it.
|
||||
|
||||
As always, please respond to this challenge with your id. I know you
|
||||
know what it is. I'll not even include it this time, I trust you.
|
||||
Don't make me feel that is a mistake.
|
||||
|
||||
This is Task 08 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
We will come back to the linux-next kernel in a later exercise, so don't
|
||||
go and delete that directory, you'll want it around. But enough of
|
||||
building kernels, let's write more code!
|
||||
|
||||
This task is much like the 06 task with the misc device, but this time
|
||||
we are going to focus on another user/kernel interface, debugfs. It is
|
||||
rumored that the creator of debugfs said that there is only one rule for
|
||||
debugfs use, "There are no rules when using debugfs." So let's take
|
||||
them up on that offer and see how to use it.
|
||||
|
||||
debugfs should be mounted by your distro in /sys/kernel/debug/, if it
|
||||
isn't, then you can mount it with the line:
|
||||
mount -t debugfs none /sys/kernel/debug/
|
||||
|
||||
Make sure it is enabled in your kernel, with the CONFIG_DEBUG_FS option,
|
||||
you will need it for this task.
|
||||
|
||||
The task, in specifics is:
|
||||
|
||||
- Take the kernel module you wrote for task 01, and modify it to be
|
||||
create a debugfs subdirectory called "eudyptula". In that
|
||||
directory, create 3 virtual files called "id", "jiffies", and "foo".
|
||||
- The file "id" operates just like it did for example 06, use the same
|
||||
logic there, the file must be readable and writable by any user.
|
||||
- The file "jiffies" is to be read only by any user, and when read,
|
||||
should return the current value of the jiffies kernel timer.
|
||||
- The file "foo" needs to be writable only by root, but readable by
|
||||
anyone. When writing to it, the value must be stored, up to one
|
||||
page of data. When read, which can be done by any user, the value
|
||||
must be returned that is stored it it. Properly handle the fact
|
||||
that someone could be reading from the file while someone else is
|
||||
writing to it (oh, a locking hint!)
|
||||
- When the module is unloaded, all of the debugfs files are cleaned
|
||||
up, and any memory allocated is freed.
|
||||
- Provide some "proof" this all works.
|
||||
|
||||
Again, you are using your id in the code, so you know what it is by now,
|
||||
no need to repeat it again.
|
||||
|
||||
This is Task 09 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Nice job with debugfs, that is a handy thing to remember when wanting to
|
||||
print out some debugging information. Never use /proc/ that is only for
|
||||
processes, use debugfs instead.
|
||||
|
||||
Along with debugfs, sysfs is a common place to put information that
|
||||
needs to move from the user to the kernel. So let us focus on sysfs for
|
||||
this task.
|
||||
|
||||
The task this time:
|
||||
|
||||
- Take the code you wrote in task 08, and move it to sysfs. Put the
|
||||
"eudyptula" directory under the /sys/kernel/ location in sysfs.
|
||||
- Provide some "proof" this works.
|
||||
|
||||
That's it! Simple, right? No, you are right, it's more complex, sysfs
|
||||
is complicated. I'd recommend reading Documentation/kobject.txt as a
|
||||
primer on how to use kobjects and sysfs.
|
||||
|
||||
Feel free to ask for hints and help with this one if you have questions
|
||||
by sending in code to review if you get stuck, many people have dropped
|
||||
out in the challenge at this point in time, so don't feel bad about
|
||||
asking, we don't want to see you go away just because sysfs is so damn
|
||||
complicated.
|
||||
|
||||
This is Task 10 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Yeah, you conquered the sysfs monster, great job!
|
||||
|
||||
Now you know to never want to mess with a kobject again, right? Trust
|
||||
me, there are easier ways to create sysfs files, and we will get into
|
||||
that for a future task, but for now, let's make it a bit more simple
|
||||
after all of that coding.
|
||||
|
||||
For this task, go back to the linux-next tree you used for task 07.
|
||||
Update it, and then do the following:
|
||||
- Create a patch that fixes one coding style problem in any of the
|
||||
files in drivers/staging/
|
||||
- Make sure the patch is correct by running it through
|
||||
scripts/checkpatch.pl
|
||||
- Submit the code to the maintainer of the driver/subsystem, finding
|
||||
the proper name and mailing lists to send it to by running the tool,
|
||||
scripts/get_maintainer.pl on your patch.
|
||||
- Send a web link back to me of your patch on the public mailing list
|
||||
archive (don't cc: me on the patch, that will only confuse me and
|
||||
everyone in the kernel development community.)
|
||||
- If you want to mention the Eudyptula Challenge as the reason for
|
||||
writing the patch, feel free to do so in the body of the patch, but
|
||||
it's not necessary at all.
|
||||
|
||||
Hopefully this patch will be accepted into the kernel tree, and all of a
|
||||
sudden, you are an "official" kernel developer!
|
||||
|
||||
Don't worry, there's plenty more tasks coming, but a little breather
|
||||
every now and again for something simple is always nice to have.
|
||||
|
||||
This is Task 11 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
You made a successful patch to the kernel source tree, that's a great
|
||||
step!
|
||||
|
||||
But, let's not rest, time to get back to code.
|
||||
|
||||
Remember that mess of kobject and sysfs code back in task 09? Let's
|
||||
move one level up the tree and start to mess with devices and not raw
|
||||
kobjects.
|
||||
|
||||
For this task:
|
||||
- Write a patch against any driver that you are currently using on
|
||||
your machine. So first you have to figure out which drivers you are
|
||||
using, and where the source code in the kernel tree is for that
|
||||
driver.
|
||||
- In that driver, add a sysfs file to show up in the /sys/devices/
|
||||
tree for the device that is called "id". As you might expect, this
|
||||
file follows the same rules as task 09 as for what you can read and
|
||||
write to it.
|
||||
- The file is to show up only for devices that are controlled by a
|
||||
single driver, not for all devices of a single type (like all USB
|
||||
devices. But all USB maibox LEDs would be acceptable, if you happen
|
||||
to have the device that that driver controls.)
|
||||
|
||||
Submit both the patch, in proper kernel commit form, and "proof" of it
|
||||
working properly on your machine.
|
||||
|
||||
And as always, please use your id in the subject line. If you happened
|
||||
to forget it, as it has been a while since I reminded you of it, it is
|
||||
"7c1caf2f50d1".
|
||||
|
||||
This is Task 12 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Nice job with the driver patch. That took some work in finding the
|
||||
proper place to modify, and demonstrates a great skill in tracking down
|
||||
issues when you can't get a specific piece of hardware working.
|
||||
|
||||
Now let's step back from drivers (they are boring things), and focus on
|
||||
the kernel core. To do that, we need to go way back to the basics --
|
||||
stuff you would learn in your "intro to data structures" class, if you
|
||||
happened to take one.
|
||||
|
||||
Yes, I'm talking about linked lists.
|
||||
|
||||
The kernel has a unique way of creating and handling linked lists, that
|
||||
is quite different than the "textbook" way of doing so. But, it turns
|
||||
out to be faster, and simpler, than a "textbook" would describe, so
|
||||
that's a good thing.
|
||||
|
||||
For this task, write a kernel module, based on your cleaned up one from
|
||||
task 04, that does the following:
|
||||
- You have a structure that has 3 fields:
|
||||
char name[20];
|
||||
int id;
|
||||
bool busy;
|
||||
name this structure "identity".
|
||||
- Your module has a static variable that points to a list of these
|
||||
"identity" structures.
|
||||
- Write a function that looks like:
|
||||
int identity_create(char *name, int id)
|
||||
that creates the structure "identity", copies in the 'name' and 'id'
|
||||
fields and sets 'busy' to false. Proper error checking for out of
|
||||
memory issues is required. Return 0 if everything went ok; an error
|
||||
value if something went wrong.
|
||||
- Write a function that looks like:
|
||||
struct identity *identity_find(int id);
|
||||
that takes a given id, iterates over the list of all ids, and
|
||||
returns the proper 'struct identity' associated with it. If the
|
||||
identity is not found, return NULL.
|
||||
- Write a function that looks like:
|
||||
void identity_destroy(int id);
|
||||
that given an id, finds the proper 'struct identity' and removes it
|
||||
from the system.
|
||||
- Your module_init() function will look much like the following:
|
||||
|
||||
struct identity *temp;
|
||||
|
||||
identity_create("Alice", 1);
|
||||
identity_create("Bob", 2);
|
||||
identity_create("Dave", 3);
|
||||
identity_create("Gena", 10);
|
||||
|
||||
temp = identity_find(3);
|
||||
pr_debug("id 3 = %s\n", temp->name);
|
||||
|
||||
temp = identity_find(42);
|
||||
if (temp == NULL)
|
||||
pr_debug("id 42 not found\n");
|
||||
|
||||
identity_destroy(2);
|
||||
identity_destroy(1);
|
||||
identity_destroy(10);
|
||||
identity_destroy(42);
|
||||
identity_destroy(3);
|
||||
|
||||
Bonus points for properly checking return values of the above
|
||||
functions.
|
||||
|
||||
As always, please send the full module (following the proper kernel
|
||||
coding style rules), and "proof" of it working properly. And remember
|
||||
to use your id of "7c1caf2f50d1" in the Subject line properly.
|
||||
|
||||
This is Task 13 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Weren't those lists fun to play with? You should get used to them, they
|
||||
are used all over the kernel in lots of different places.
|
||||
|
||||
Now that we are allocating a structure that we want to use a lot of, we
|
||||
might want to start caring about the speed of the allocation, and not
|
||||
have to worry about the creation of those objects from the "general"
|
||||
memory pools of the kernel.
|
||||
|
||||
This task is to take the code written in task 12, and cause all memory
|
||||
allocated from the 'struct identity' to come from a private slab cache
|
||||
just for the fun of it.
|
||||
|
||||
Instead of using kmalloc() and kfree() in the module, use
|
||||
kmem_cache_alloc() and kmem_cache_free() instead. Of course this means
|
||||
you will have to initialize your memory cache properly when the module
|
||||
starts up. Don't forget to do that. You are free to name your memory
|
||||
cache whatever you wish, but it should show up in the /proc/slabinfo
|
||||
file.
|
||||
|
||||
Don't send the full module for this task, only a patch with the diff
|
||||
from task 12 showing the lines changed. This means you will have to
|
||||
keep a copy of your 12 task results somewhere to make sure you don't
|
||||
overwrite them.
|
||||
|
||||
Also show the output of /proc/slabinfo with your module loaded.
|
||||
|
||||
This is Task 14 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Now that you have the basics of lists, and we glossed over the custom
|
||||
allocators (the first cut at that task was much harder, you got off
|
||||
easy), it's time to move on to something a bit more old-school: tasks.
|
||||
|
||||
For this task:
|
||||
- Add a new field to the core kernel task structure called, wait for
|
||||
it, "id".
|
||||
- When the task is created, set the id to your id. Imaginative, I
|
||||
know. You try writing these tasks.
|
||||
- Add a new proc file for every task called, "id", located in the
|
||||
/proc/${PID}/ directory for that task.
|
||||
- When the proc file is read from, have it print out the value of
|
||||
your id, and then increment it by one, allowing different tasks to
|
||||
have different values for the "id" file over time as they are read
|
||||
from.
|
||||
- Provide some "proof" it all works properly.
|
||||
|
||||
As you are touching files all over the kernel tree, a patch is the
|
||||
required result to be sent in here. Please specify which kernel version
|
||||
you make this patch against, to give my virtual machines a chance to
|
||||
figure out how to apply it.
|
||||
|
||||
Also provide some kind of proof that you tested the patch.
|
||||
|
||||
And, in case you happened to forget it, your id is "7c1caf2f50d1".
|
||||
|
||||
This is Task 15 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
That process task turned out to not be all that complex, but digging
|
||||
through the core kernel was a tough task, nice work with that.
|
||||
|
||||
Speaking of "core kernel" tasks, let's do another one. It's one of the
|
||||
most common undergraduate tasks there is: create a new syscall!
|
||||
Yeah, loads of fun, but it's good to know the basics of how to do this,
|
||||
and, how to call it from userspace.
|
||||
|
||||
For this task:
|
||||
- Add a new syscall to the kernel called "sys_eudyptula", so this is
|
||||
all going to be changes to the kernel tree itself, no stand-alone
|
||||
module needed for this task (unless you want to do it that way
|
||||
without hacking around the syscall table, if so, bonus points for
|
||||
you...)
|
||||
- The syscall number needs to be the next syscall number for the
|
||||
architecture you test it on (some of you all are doing this on ARM
|
||||
systems, showoffs, and syscall numbers are not the same across all
|
||||
architectures). Document the arch you are using and why you picked
|
||||
this number in the module.
|
||||
- The syscall should take two parameters: int high_id, int low_id.
|
||||
- The syscall will take the two values, mush them together into one
|
||||
64bit value (low_id being the lower 32bits of the id, high_id being
|
||||
the upper 32bits of the id).
|
||||
- If the id value matches your id (which of course you know as
|
||||
"7c1caf2f50d1", then the syscall returns success. Otherwise it
|
||||
returns a return code signifying an invalid value was passed to it.
|
||||
- Write a userspace C program that calls the syscall and properly
|
||||
exercises it (valid and invalid calls need to be made).
|
||||
- "Proof" of running the code needs to be provided.
|
||||
|
||||
So you need to send in a .c userspace program, a kernel patch, and
|
||||
"proof" that it all works, as a response.
|
||||
|
||||
This is Task 16 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Good job with the new syscall. The odds of you ever having to write a
|
||||
new syscall is pretty rare, but now you know where to look them up, and
|
||||
what the code involved in creating one looks like, which is useful when
|
||||
you try to debug things.
|
||||
|
||||
Let's take a breather after all of that code, and go back to doing a bit
|
||||
of reading, and learn some more about some common kernel tools.
|
||||
|
||||
Go install the tool 'sparse'. It was started by Linus as a
|
||||
static-analysis tool that acts much like a compiler. The kernel build
|
||||
system is set up to have it run if you ask it to, and it will report a
|
||||
bunch of issues in C code that are really specific to the kernel.
|
||||
|
||||
When you build the kernel, pass the "C=1" option to the build, to have
|
||||
sparse run on the .c file before gcc is run. Depending on the file,
|
||||
nothing might be printed out, or something might. Here's an example of
|
||||
it being run on the ext4 code:
|
||||
|
||||
$ make C=1 M=fs/ext4
|
||||
CHECK fs/ext4/balloc.c
|
||||
CC fs/ext4/balloc.o
|
||||
CHECK fs/ext4/bitmap.c
|
||||
CC fs/ext4/bitmap.o
|
||||
CHECK fs/ext4/dir.c
|
||||
CC fs/ext4/dir.o
|
||||
CHECK fs/ext4/file.c
|
||||
CC fs/ext4/file.o
|
||||
CHECK fs/ext4/fsync.c
|
||||
CC fs/ext4/fsync.o
|
||||
CHECK fs/ext4/ialloc.c
|
||||
CC fs/ext4/ialloc.o
|
||||
CHECK fs/ext4/inode.c
|
||||
CC fs/ext4/inode.o
|
||||
CHECK fs/ext4/page-io.c
|
||||
CC fs/ext4/page-io.o
|
||||
CHECK fs/ext4/ioctl.c
|
||||
CC fs/ext4/ioctl.o
|
||||
CHECK fs/ext4/namei.c
|
||||
CC fs/ext4/namei.o
|
||||
CHECK fs/ext4/super.c
|
||||
CC fs/ext4/super.o
|
||||
CHECK fs/ext4/symlink.c
|
||||
CC fs/ext4/symlink.o
|
||||
CHECK fs/ext4/hash.c
|
||||
CC fs/ext4/hash.o
|
||||
CHECK fs/ext4/resize.c
|
||||
CC fs/ext4/resize.o
|
||||
CHECK fs/ext4/extents.c
|
||||
CC fs/ext4/extents.o
|
||||
CHECK fs/ext4/ext4_jbd2.c
|
||||
CC fs/ext4/ext4_jbd2.o
|
||||
CHECK fs/ext4/migrate.c
|
||||
CC fs/ext4/migrate.o
|
||||
CHECK fs/ext4/mballoc.c
|
||||
fs/ext4/mballoc.c:5018:9: warning: context imbalance in 'ext4_trim_extent' - unexpected unlock
|
||||
CC fs/ext4/mballoc.o
|
||||
CHECK fs/ext4/block_validity.c
|
||||
CC fs/ext4/block_validity.o
|
||||
CHECK fs/ext4/move_extent.c
|
||||
CC fs/ext4/move_extent.o
|
||||
CHECK fs/ext4/mmp.c
|
||||
CC fs/ext4/mmp.o
|
||||
CHECK fs/ext4/indirect.c
|
||||
CC fs/ext4/indirect.o
|
||||
CHECK fs/ext4/extents_status.c
|
||||
CC fs/ext4/extents_status.o
|
||||
CHECK fs/ext4/xattr.c
|
||||
CC fs/ext4/xattr.o
|
||||
CHECK fs/ext4/xattr_user.c
|
||||
CC fs/ext4/xattr_user.o
|
||||
CHECK fs/ext4/xattr_trusted.c
|
||||
CC fs/ext4/xattr_trusted.o
|
||||
CHECK fs/ext4/inline.c
|
||||
CC fs/ext4/inline.o
|
||||
CHECK fs/ext4/acl.c
|
||||
CC fs/ext4/acl.o
|
||||
CHECK fs/ext4/xattr_security.c
|
||||
CC fs/ext4/xattr_security.o
|
||||
LD fs/ext4/ext4.o
|
||||
LD fs/ext4/built-in.o
|
||||
Building modules, stage 2.
|
||||
MODPOST 0 modules
|
||||
|
||||
As you can see, only one warning was found here, and odds are, it is a
|
||||
false-positive, as I'm sure those ext4 developers know what they are
|
||||
doing with their locking functions, right?
|
||||
|
||||
Anyway the task this time is:
|
||||
- Run sparse on the drivers/staging/ directory, yes, that horrible
|
||||
code again, sorry.
|
||||
- Find one warning that looks interesting.
|
||||
- Write a patch that resolves the issue.
|
||||
- Make sure the patch is correct by running it through
|
||||
scripts/checkpatch.pl
|
||||
- Submit the code to the maintainer of the driver/subsystem, finding
|
||||
the proper name and mailing lists to send it to by running the tool,
|
||||
scripts/get_maintainer.pl on your patch.
|
||||
- Send a web link back to me of your patch in the public mailing list
|
||||
archive (don't cc: me on the patch, that will only confuse me and
|
||||
everyone in the kernel development community.)
|
||||
- If you want to mention the Eudyptula Challenge as the reason for
|
||||
writing the patch, feel free to do so in the body of the patch, but
|
||||
it's not necessary at all.
|
||||
|
||||
That's it, much like task 10 was, but this time you are fixing logical
|
||||
issues, not just pesky coding style issues. You are a real developer
|
||||
now, fixing real bugs!
|
||||
|
||||
This is Task 17 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Another patch made and sent in. See, that wasn't so hard. Keep sending
|
||||
in kernel patches outside of this challenge, those lazy kernel
|
||||
developers need all the help they can get in cleaning up their code.
|
||||
|
||||
It is time to start putting the different pieces of what we have done in
|
||||
the past together, into a much larger module, doing more complex things.
|
||||
Much more like what a "real" kernel module has to do.
|
||||
|
||||
Go dig up your code from task 06, the misc char device driver, and make
|
||||
the following changes:
|
||||
|
||||
- Delete the read function. You don't need that anymore, so make it a
|
||||
write-only misc device and be sure to set the mode of the device to
|
||||
be write-only, by anyone. If you do this right, udev will set up the
|
||||
node automatically with the correct permissions.
|
||||
- Create a wait queue, name it "wee_wait".
|
||||
- In your module init function, create a kernel thread, named of course
|
||||
"eudyptula".
|
||||
- The thread's main function should not do anything at this point in
|
||||
time, except make sure to shutdown if asked to, and wait on the
|
||||
"wee_wait" waitqueue.
|
||||
- In your module exit function, shut down the kernel thread you started
|
||||
up.
|
||||
|
||||
Load and unload the module and "prove" that it works properly (that the
|
||||
thread is created, it can be found in the process list, and that the
|
||||
device node is created with the correct permission value.) Send in the
|
||||
proof and the .c file for the module.
|
||||
|
||||
Be sure to keep this code around, as we will be doing more with it next
|
||||
time.
|
||||
|
||||
This is Task 18 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Nice job with the kernel thread. It really doesn't take much code at
|
||||
all to create a new thread. So now let us get some data into the module
|
||||
to give the thread something to do.
|
||||
|
||||
Base all of this work on your task 17 codebase.
|
||||
|
||||
Go back and dig up task 12's source code, the one with the list
|
||||
handling. Copy the structure into this module, and the
|
||||
identity_create(), identity_find(), and identity_destroy() functions
|
||||
into this module as well.
|
||||
|
||||
Write a new function, identity_get(), that looks like:
|
||||
struct identity identity_get(void);
|
||||
and returns the next "identity" structure that is on the list, and
|
||||
removes it from the list. If nothing is on the list, return NULL.
|
||||
|
||||
Then, hook up the misc char device "write" function to do the following:
|
||||
- If a write is larger than 19 characters, truncate it at 19.
|
||||
- Take the write data and pass it to identity_create() as the string,
|
||||
and use an incrementing counter as the "id" value.
|
||||
- Wake up the "wee_wait" queue.
|
||||
|
||||
In the kernel thread function:
|
||||
- If the "wee_wait" queue wakes us up, get the next identity in the
|
||||
system with a call to identity_get().
|
||||
- Sleep (in an interruptable state, don't go increasing the system
|
||||
load in a bad way) for 5 seconds.
|
||||
- Write out the identity name, and id to the debug kernel log and then
|
||||
free the memory.
|
||||
|
||||
When the module exits, clean up the whole list by using the functions
|
||||
given, no fair mucking around with the list variables directly.
|
||||
|
||||
Yes, it's a bit clunky, but it shows the basics of taking work from
|
||||
userspace, and then quickly returning to the user, and then going off
|
||||
and doing something else with the data and cleaning everything up. It's
|
||||
a common pattern for a kernel, as it's really all that a kernel ends up
|
||||
doing most of the time (get a disk block, write a disk block, handle a
|
||||
mouse event, etc.)
|
||||
|
||||
Load and unload the module and "prove" that it works properly by writing
|
||||
and looking at the debug log, and that everything cleans up properly
|
||||
when the module is unloaded.
|
||||
|
||||
Send in the proof and the .c file for the module.
|
||||
|
||||
A good test script would be the following:
|
||||
echo "Alice" > /dev/eudyptula
|
||||
echo "Bob" > /dev/eudyptula
|
||||
sleep 15
|
||||
echo "Dave" > /dev/eudyptula
|
||||
echo "Gena" > /dev/eudyptula
|
||||
rmmod task18
|
||||
|
||||
Removing the module while there is pending work is always a good stress
|
||||
test.
|
||||
|
||||
This is Task 19 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Handling delayed work is easy now, right? So, time to move on to
|
||||
something totally different. How about networking? We have been
|
||||
ignoring that part of the kernel, so let us now focus on the network
|
||||
side of the kernel, as that is a huge reason for why Linux has taken
|
||||
over the world.
|
||||
|
||||
For this task, write a netfilter kernel module that does the following:
|
||||
- monitors all IPv4 network traffic that is coming into the machine
|
||||
- prints the id to the kernel debug log if the network traffic stream
|
||||
contains your id.
|
||||
- properly unregisters you from the netfilter core when the module
|
||||
unloads.
|
||||
|
||||
Test this by sending yourself an email with your id in the subject, much
|
||||
like the email you need to send back to me.
|
||||
|
||||
Send in the proof and the .c file for the module.
|
||||
|
||||
This is Task 20 of the Eudyptula Challenge
|
||||
------------------------------------------
|
||||
|
||||
Networking filters turned out to be not all that complex in the end,
|
||||
great work with that.
|
||||
|
||||
So, here's the final task.
|
||||
|
||||
There might be other tasks that get created and sent out later on, but
|
||||
the original challenge had 20 tasks, so after finishing this one, you
|
||||
can consider yourself done!
|
||||
|
||||
Let's try something a bit harder. Something that might cause some data
|
||||
loss on a filesystem, always a fun thing to play with, if for no other
|
||||
reason than to not be afraid of things like that in the future.
|
||||
|
||||
This task requires you to work on the fat filesystem code:
|
||||
- Add an ioctl to modify the volume label of a mounted fat filesystem.
|
||||
Be sure to handle both 16 and 32 bit fat filesystems {hint!}
|
||||
- Provide a userspace .c program to test this new ioctl.
|
||||
|
||||
That's it! Seems so simple, right? I wonder why that option isn't in
|
||||
the kernel tree already...
|
||||
|
||||
Anyway, provide a patch to the kernel, and the .c file used to test the
|
||||
new ioctl, as well as "proof" of this working. Make sure you don't run
|
||||
into 32/64bit kernel issues with the ioctl, if you do things correctly,
|
||||
you shouldn't have any problems.
|
||||
|
||||
I recommend doing this work on either a loop-back fat filesystem on your
|
||||
"normal" filesystem, or on a USB stick. Either will work just as well,
|
||||
and make things easier to debug and test.
|
||||
|
||||
Watch out for locking issues, as well as dirty filesystem state
|
||||
problems.
|
||||
|
||||
Best of luck!
|
||||
|
||||
|
Loading…
Reference in a new issue