For those who are just starting, the author (Tanenbaum) also wrote a book called Operating Systems: Design and Implementation, which is a great resource for learning the ins and outs of OSs. But it is a necessity to know C beforehand, and you should have a reasonable understanding of basic CS first, also.
Edit 2: Oh, also, Minix is in a lot of ways responsible for the genesis of Linux, for those who didn't know. [http://groups.google.com/group/comp.os.minix/msg/b813d52cbc5...]
Find something interesting and figure out how it works. The best learning happens when you get in over your head. Once you get sufficiently lost, go back and learn some C. You'll appreciate it more and have a context to apply what you learned.
The kernel code is complicated. Learning C and some CS concepts before diving in will save you a lot of time and headaches. What you could do is learning C and CS while trying to understand some bits and bytes of the kernel, but for that I guess you would need someone else to guide you
If you want to learn that way, you have to be incredibly tenacious. Some people are, some people aren't, but I think my time was better served by learning all the dependencies and then breezing through it when I was in the right place. I mean, you could learn Organic Chemistry and just backtrack to learn Chemistry where applicable, but that's a very hard way of doing it.
I'm not doubting your story, but it's not a hard-and-fast rule. Con Kolivas, who has written some interesting/thought-provoking schedulers for the Linux kernel (and stirred up some politics along the way) had never touched C before jumping in. (http://apcmag.com/interview_with_con_kolivas_part_1_computin...)
At the end you tend to re-invent the wheel if you learn that way. Learning about the existing wheels will save much time and correct a lot of errors that you might never even see when working that way.
And kids knowledge is generally supplemented by adults to complete the picture and sometimes we have to lie to introduce them to some concepts.
For a real-world example, I second the recommendation of BSD, combined with the book below.
other kernels (like NetBSD) where designed with being portable across architectures in mind and so have much cleaner code paths (typically just one system call table and the bare minimum arch specific code to link it all together).
minix is okay but it's not really going to give you a grip on a real work kernel. "design and implementation of 4.4BSD-lite" is a really good book for this: most BSDs are very similar to this design still in a lot of ways, and many of the ideas described (e.g., VFS) are also used in linux.
Second, actually the more architectures you are compatible with, the more code is involved, and it tends to be more, not less, complicated. This is especially the case because all OSs have some assembly in them, and that assembly DOES change per your architecture.
Third, Minix is a "working" kernel. The main difference between Minix and BSD/Linux/whatever is that it is a microkernel, which is easily the best to learn on, on account of things like the permissions structure being MUCH simpler (arguably one of the most difficult things to grasp), but not the best in terms of (for example) security.
2. linux duplicates the system call dispatch table for each architecture. check it out:
whereas NetBSD has no such duplication. in fact, one complaint about the linux kernel is that it has too much per-architecture code.
3. who uses minix? the linux kernel is actually not too bad. ctags is your friend. i learnt on linux+netbsd, it's not really as bad as people make out.
Here's how you do a 2-arg mkdir:
movq $0x27, %rax
movq $path, %rbx
movq $mode, %rcx
movq $0x128, %rax
movq $dfd, %rbx
movq $path, %rcx
movq $mode, %rdx
$ objdump -D /lib/libc.so.6 | grep 'int[[:space:]]*$0x80' | wc -l
$ objdump -D /lib64/libc.so.6 | grep 'int[[:space:]]+$0x80' | wc -l
char *cmd = __alloca (80 + strlen (path));
(mkdir command line parsing)
status = system (cmd);
That's right, it just relays. I'm not sure how it gets to the kernel. I suspect with a system call somewhere.
What I know is that it arrives in the kernel, in the fs source files: namei.c for the vfs part and <fs-name>/namei.c for filesystem specific implementations (that are called by the vfs code in the end, I guess).
Ps. Feel free to correct me. I only concluded this by poking around the sources a bit, not into kernel development myself.
I wouldn't say it's necessary for every programmer to know how the linux vsf system works and how files, directories and links are stored behind the scenes, but it is really interesting. Here's a good description of vfs http://www.mjmwired.net/kernel/Documentation/filesystems/vfs... . The implementation in ramfs is pretty simple (compared to ext3). You can find it in your kernel source in fs/ramfs/inode.c. Theres a function in there called ramfs_mkdir that allocates and configures a new inode. Anyway, thats how i'd answer the question.
I think now that it's happened to more than one online community, it's worth a lot of careful thinking to figure out why and how these communities develop deletionist subcultures.