1058
Comment:
|
28604
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
= Getting Started as an OPW applicant = Hooray! Thanks for your interest in working on the Linux kernel. If you run into any issues with this tutorial, please ask questions on the [https://live.gnome.org/OutreachProgramForWomen#Introduction #opw IRC channel] TODO: * Outline of what this tutorial covers * If you run into any issues, ask on the opw irc channel, or email sarah.a.sharp at linux.intel.com * Step 0: install Linux on a home computer (alternative instructions for installing in a VM would be good, but I have no background in that). * Build a custom kernel * Find out which drivers you have installed (maybe plug in any USB devices on hand) * Make small change in one of the drivers (e.g. run checkpatch over them, or fix some grammer in the printks) * Or maybe pick a driver in staging and run checkpatch on it * Test your patch (may need to enable debugging) * Make a patch (link to art of patch description creation) * Send patch to kernel newbies mailing list as RFC (perhaps we need a separate mailing list?) |
Hooray! Thanks for your interest in working on the Linux kernel. The next step is to [:OPWApply:apply] to OPW, and use this tutorial to create your first patch to the Linux kernel. '''Warning: this is still a work in progress. We'll announce on the opw-kernel mailing list when this tutorial is finished. Please [https://live.gnome.org/OutreachProgramForWomen#Application_Process turn in your application] to express interest in the kernel project, and sign up for the [https://groups.google.com/forum/#!forum/opw-kernel opw-kernel mailing list].''' == Intro == If you run into any issues with this tutorial, please ask questions on the #kernel-opw IRC channel on irc.oftc.net, or on the [https://groups.google.com/forum/#!forum/opw-kernel opw-kernel mailing list]. This tutorial will cover how to get your first patch submitted. You have three choices for how to complete this tutorial: 1. Run Linux in VMPlayer from Windows. 1. Run Linux natively on your own machine. 1. Run Linux within VMPlayer on Linux. We recommend options 1 or 2, with a preference towards running Linux natively. Accepted interns will be expected to run Linux natively, so you may as well get used to it. :) If you want to run Linux in VMPlayer, follow [:OPWfirstpatchAlt:these directions]. == Overview == [[Anchor(kernel-setup-done)]] This tutorial will show you how to: [[TableOfContents(0)]] = Setup your tools = You'll need to install, configure, and download some software to get started. You should follow the [OPWfirstpatchSetup setup directions] here. == Setup vim == (Note, if you're running a native Linux install and you're used to another editor like emacs or nano, you can still use that editor, and you can skip this step. You may not be able to use gvim.) Tip: Vim is a simple text editor that has a couple modes. It starts out in standard mode, and you can move the cursor down or up with the arrow keys (or the 'j' or 'k' keys), and move the cursor left or right with the arrow keys (or the 'h' and 'l' keys). You can go into "Insert mode" by typing 'i'. Now you can change text. To get back into standard mode, type <Escape>. To write a file, get into standard mode, and type :w<enter>. To quit vim, type :q<enter>. If you want to learn more about vim, the [http://vim-adventures.com/ VIM adventures game] is quite fun. First, we need to make sure to enable the C indentation module in our default text editor (vim). Turning on this module will ensure that lines automatically get indented to the right level as you're editing. It saves you from hitting <tab> a lot. You can turn on automatic indentation based on the file type. First run: {{{ vim ~/.vimrc}}} Then add this line: {{{ filetype plugin indent on}}} You'll also want to add a couple more lines, to turn syntax highlighting on, and show the file name in the terminal title bar: {{{ syn on se title}}} == Setup vim as your default editor == Next, we'll need to set up mutt to use vim as the default editor, instead of nano. Run: {{{ sudo update-alternatives --config editor}}} and chose /usr/bin/vim.basic as the default editor. == Set up email == To be able to send Linux kernel patches, you'll need to be able to send email from the Linux VM image (or your computer that is natively running Linux). The VM image comes installed with esmtp, and if you were following the [:OPWfirstpatchAlt:native Linux install directions] you should have that installed on your computer as well. Esmtp is a mail transport agent. It routes email to your mail server, such as gmail. To know what information to give esmtp, you will need to look up your mail server settings. == Gmail set up == In gmail, go click the gear icon, go to "Settings", go to the tab "Forwarding POP/IMAP", and click the "Configuration instructions" link at the very bottom of the page. Then click "I want to set up IMAP". At the bottom of the page, under the paragraph about configuring your mail client, select "Other". Note the outgoing mail server information, and copy it into the .esmtprc file, as shown in the next section. == Configure esmtp == First, create a .esmtprc file with the right permissions: {{{ touch ~/.esmtprc chmod g-rwx ~/.esmtprc chmod o-rwx ~/.esmtprc }}} Edit the .esmtprc in your home directory, and add lines like this: {{{ identity "my.email@gmail.com" hostname smtp.gmail.com:587 username "my.email@gmail.com" password "ThisIsNotARealPassWord" starttls required }}} Next, set up the mail client, mutt, with some defaults, but creating a .muttrc file in your homedirectory: {{{ set sendmail="/usr/bin/esmtp" set envelope_from=yes set from="Your Name <my.email@gmail.com>" set use_from=yes set edit_headers=yes }}} == Test your email setup == Next, let's send a test email message with mutt. Run this command: {{{ mutt}}} Say "no" to creating an inbox for now. Type 'm' to create a new message. Specify your own email address (or a secondary email) to send the test message to. Set the Subject however you want to. Type a message in the body, and then save and quit. Hit 'y' to send the message, hit 'e' to edit the message again, or hit 'q' to abort sending the message. Look in your email to double check you received a message. If you send the email to yourself, for some mail services like gmail, the message will not show up in your inbox, and you will have to look in your Sent Mail folder. == Setup git == First, you need to tell git what your name and email address is, so that it can be used in the authorship information in the git commit. Create a file called {{{.gitconfig}}} and add lines like these to it: {{{ [user] name = Your Name email = your.email@example.com }}} '''Make sure that the email you specify here is the same email you used to set up sending mail.''' The Linux kernel developers will not accept a patch where the "From" email differs from the "Signed-off-by" line, which is what will happen if these two emails do not match. = Explore the kernel tree = First, open a terminal, by clicking the black screen icon with the "{{{>_}}}" text in it. Tip: You can exit out of a terminal tab or window by pressing {{{<CTRL>d}}} at any time. This is the recommended way of closing the terminal, since it won't kill any processes you have running in the background. Get used to exiting the terminal this way by opening and closing the terminal a couple times. The VM Image already has Linus' git tree checked out for you. Change directories to that git checkout: {{{ cd git/kernels/linux/}}} This is the Linux kernel tree. You can explore it by using the {{{`ls`}}} and {{{`cd`}}} commands. If you run {{{`ls}}}, you'll see several different folders: {{{ intern@ubuntu:~/git/kernels/linux$ ls arch init modules.order System.map block ipc Module.symvers tags COPYING Kbuild net tools CREDITS Kconfig README usr crypto kernel REPORTING-BUGS virt Documentation lib samples vmlinux drivers MAINTAINERS scripts vmlinux.o extra_certificates Makefile security x509.genkey firmware mm signing_key.priv fs Module.markers signing_key.x509 include modules.builtin sound }}} There's more to this directory than meets the eye! If you run ls -A, you'll see there's a hidden directory called {{{.git}}}. This contains all the meta information that git uses to track branches, remote repositories, and changes to files in the local directory. You can view the commit history by running {{{ git log}}} If you want a more compact form, you can run a command to see just the "short description" for each commit, with an abbrevated git commit ID: {{{ git log --pretty=oneline --abbrev-commit}}} = Play with some git basics = Git is a distributed revision control system, which means you can hack on your version of the code without having to coordinate with other developers. Think of your git checkout as a separate copy of Linus' kernel respository. Git includes support for branches. Each branch can contain a completely different set of patches. Kernel developers typically use one branch per patchset. For example, you might have one branch that includes bug fixes, and another branch that contains commits for a new feature you're working on. You can run {{{`git branch`}}} to see which branch you're on, and what other branches are available: {{{ intern@ubuntu:~/git/kernels/linux$ git branch * master }}} In this case, there is only one branch, called master. The start indicates that the "master" branch is the one you are currently on. In git speak, we say that you currently have the master branch "checked out". Create a new branch called 'staging', and checkout that branch by running: {{{ git checkout -b staging}}} Now if you run git branch, you'll see that there are two branches, and you are currently on the "staging" branch: {{{ intern@ubuntu:~/git/kernels/linux$ git branch master * staging }}} You can also use the git branch command to show branches on Linus' repository (the remote repository). Run the command: {{{intern@ubuntu:~/git/kernels/linux$ git branch -a master * staging remotes/origin/HEAD -> origin/master remotes/origin/master}}} The first remote repository that is used to create the git checkout is called "origin". For now, just remember that "origin" means Linus' remote git repository. = Update your kernel = When you create patches, you want to create them on top of the latest kernel from Linus. If your patch is out-of-date and doesn't apply to the latest tree, it may be rejected. You'll need to use git to fetch the latest changes: {{{ git fetch origin}}} The third word in that command is the name of the remote repository you are fetching from. That command will fetch the changes from Linus' tree, but it won't actually change in files in the working copy (i.e. the files in this directory). If you run: {{{ git log}}} You will see that your current working directory still points to the original commit (3.9). So where are Linus' current changes? The answer is that git stores the changes in a special hidden directory called {{{.git}}}. You can view the history of Linus' repository by giving git log the "master" branch of the "origin" remote repository (i.e. Linus' master branch): {{{ git log origin/master}}} Next, we need to update our branch to include the changes in Linus' tree. The safest way to do this is to "rebase" your branch. This means that if you have any commits on your branch, they will be placed on top of Linus' commits. Sometimes you may have to edit your commits if there are conflicts, but you should ask your mentor for help with this. For now, run: {{{ git rebase origin/master}}} If you run {{{`git log`}}} to show your staging branch history and then {{{`git log origin/master`}}} to show Linus' master branch history, you should see that they have exactly the same commits. == Configure the kernel == The next step is to create a configuration file, compile the new kernel, and install it. The first thing to know is that the Linux kernel is completely configurable. Each driver can be separately configured to be installed or not. There are three choices for driver installation: * disable the driver completely, * build the driver into the main kernel file (vmlinuz), * or build it as a module. If you build the driver into the main kernel file, it will be loaded at boot time. The downside is that the kernel will have to load more code at boot for drivers that may not even corespond to hardware on the system. To avoid this, kernel developers often compile drivers as "modules". A module is a stand-alone .ko driver file that is loaded when the kernel detects hardware that matches the driver. For example, you could configure your wifi driver as a module, and the kernel will load it when it detects the wifi card. The Linux kernel make system uses a special file called {{{.config}}} that stores what drivers are compiled in, or compiled as modules. Most Linux distributions store the .config file they used to compile your distro kernel in the /boot/ directory: {{{ intern@ubuntu:~/git/kernels/linux$ ls /boot/ abi-3.5.0-23-generic initrd.img-3.9.0-rc8+ abi-3.5.0-27-generic memtest86+.bin config-3.5.0-23-generic memtest86+_multiboot.bin config-3.5.0-27-generic System.map-3.5.0-23-generic config-3.9.0 System.map-3.5.0-27-generic grub System.map-3.9.0 initrd.img-3.5.0-23-generic vmlinuz-3.5.0-23-generic initrd.img-3.5.0-27-generic vmlinuz-3.5.0-27-generic initrd.img-3.9.0 vmlinuz-3.9.0 }}} You can duplicate the distro's configuration by copying one of the config-* files to a .config file in your git tree. This has already been done for you in the VM image. == Compile the kernel == Next, you'll need to run {{{make}}} to compile your new kernel. Optionally, make can take a flag that indicates how many threads to spawn to start separate compilations. Usually you want to pick a number that is equal to the number of CPUs you have in your machine. For example, if you had a dual core system, you would run: {{{ make -j2}}} That may take a while. I would suggest reading some of the [http://lwn.net/Kernel/LDD3/ Linux Device Drivers book] while you're waiting. = Make a driver change = These next couple of steps will allow you to make a change to a driver, and test that you've correctly compiled and installed the modified driver. One driver that's included in all VM images is the e1000 driver, the Intel ethernet driver. (Interns running Linux natively may want to use {{{lsmod}}} to see what other drivers they have loaded, and pick one from that list to modify.) The e1000 driver is found in the networking portion of the kernel: {{{ intern@ubuntu:~/git/kernels/linux$ ls drivers/net/ethernet/intel/e1000/ e1000_ethtool.c e1000.h e1000_hw.c e1000_hw.h e1000_main.c e1000_osdep.h e1000_param.c Makefile }}} Let's make a small change to the probe function of the e1000 driver. A probe function is called when the driver is loaded. Let's edit e1000_main.c: {{{ vim drivers/net/ethernet/intel/e1000/e1000_main.c}}} Next, find the probe function. You can search for text by typing '/' in standard mode. Once you've found the probe function, add a printk line to it: {{{ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct e1000_adapter *adapter; struct e1000_hw *hw; printk(KERN_DEBUG "I can modify the Linux kernel!\n"); static int cards_found = 0; }}} Then type {{{:wq<enter>}}} to save the file and quit. A printk function causes a message to be written to the kernel log buffer, which can then be viewed using the {{{dmesg}}} command. == Compile your changes == Recompile your kernel, by running {{{make}}} (with an optional {{{-jN}}} flag): {{{ make -j2}}} You may need to fixed some compilation errors. Also fix any new warnings that are due to your changes. In the Linux kernel, we strive to make sure that drivers do not produce warnings on anyone's system (this includes 32-bit and 64-bit systems, as well as different architectures, such as PPC, ARM, or x86). New features or bug fix patches that add additional warnings may not get merged. == Install your changes == After you've compiled the driver, you need to install your changes by running: {{{ sudo make modules_install install}}} == Test your changes == Since you've compiled a completely new kernel, you need to reboot into that new kernel in order to test your module changes. Reboot your VM (or computer), and then run: {{{ dmesg | less}}} Search for your printk in the log file by typing "/I can modify". You should be able to find this message within the driver output during boot. If you don't see this message, ask for help on the #kernel-opw IRC channel on irc.oftc.net, or on the [https://groups.google.com/forum/#!forum/opw-kernel opw-kernel mailing list] == Revert your changes == Since that was just a simple test, and you probably don't want to commit that change, you can revert your changes. Exit out of your editor by typing {{{:q<enter>}}} and running this command: {{{ git reset --hard HEAD}}} That will revert '''ALL FILES''' in your current working directory to the last known commit (the HEAD commit), wiping out all your uncommited changes. Read the git reset manual for more information on ways to reset the state for specific files. = Start creating your first patch = Next, you'll get to do some useful modifications to the kernel, create your first git commit, and send out your first patch. Before you make your first commit using git, you'll need to do some setup. == Git pre-commit hooks == Git includes some "hooks" for scripts that can be run before specific git commands are executed. The "pre-commit" hook is run before you make a git commit with the {{{`git commit``}}} command. Linux kernel developer have very stringent guidelines for [http://lxr.linux.no/#linux/Documentation/CodingStyle coding style]. They're so picky, they created a script called [http://lxr.linux.no/#linux/scripts/checkpatch.pl checkpatch.pl] that you can run over your patches to make sure the patch compiles to the kernel coding style. To ensure that you create good commits that comply with the coding style, you can run checkpatch.pl over your commit with the "pre-commit" hook. That means git will refuse to commit your changes if it doesn't compily with kernel coding style. Edit the {{{.git/hooks/pre-commit}}} file and add the following line: {{{ exec git diff --cached | scripts/checkpatch.pl --no-signoff -}}} Tip: Sometimes you need to bypass checkpatch.pl (check with your mentor before doing this). If you need to bypass it, you can pass {{{`git commit`}}} the -n flag to bypass git hooks. = Understand patch best practices = Before you create your patch, we suggest you read about PatchPhilosophy. That document will help you create patches that are easy to read, and have a better chance of being applied by maintainers. = Find a driver to clean up = The staging tree, in {{{drivers/staging/}}} is full of drivers that are not quite up to kernel coding style, or that use deprecated API. Drivers get placed here in order to get cleaned up. Some drivers have a TODO file in their parent directory, that lists things that need to be done to it: {{{ find drivers/staging -name TODO}}} You can either tackle one of those TODO items, or you can do a simple coding style cleanup. == Running checkpatch.pl == If you pick a driver in staging, you can run the script that checks whether a file conforms to kernel coding style: {{{ perl scripts/checkpatch.pl -f drivers/staging/csr/* | less}}} Pick a warning, and try to fix it. == Recompiling the driver == You'll need to make sure the driver you're changing is configured as a module. Run: {{{ make menuconfig}}} This opens up a text-based GUI that allows you to explore the configuration options. Use the arrow keys to go to {{{Device Drivers -> }}} and hit <enter>. Then go down to {{{Staging drivers}}}. At any time, you can hit '?', which will show you the help text for that kernel configuration option. You can search for the driver you're modifying by '/', in order to get the driver's longer name. Make sure the driver you're working on is compiled as a module ('M'), instead of being built-in ('*'). You can change a driver to being compiled as a module by typing 'm' when the driver is selected in the menu. Hitting <enter> will change the driver to being built-in. Once you've enabled the driver you're modifying, use <tab> or the right arrow key to move the cursor from 'Select' to 'Exit' and hit <enter>. Continue to do this until you get to the main menu. When it asks you to save your configuration, chose 'Yes'. Then recompile the kernel with: {{{ make -j2}}} You should reboot your kernel, load the driver with {{{modprobe}}}. You'll be able to see that the driver is loaded by running {{{lsmod}}}. Loading the driver at least makes sure that the driver probe function works. == Reloading modules == If you're running a kernel that has the same release version ({{{`uname -r`}}}) as the new code you're compiling, you can test your changes without rebooting. Simply install the module in /lib/modules, and unload and reload the driver: {{{ make -j2 && sudo make modules_install sudo modprobe -r <module_name> sudo modprobe <module_name> }}} How do you know what the module name is? If you've compiled the driver as a module, there should be a .ko file in the parent directory. For example, after we configure the CSR driver to be compiled as a module, we can run this command: {{{ intern@ubuntu:~/git/kernel/linux$ ls drivers/staging/csr/*.ko drivers/staging/csr/csr_helper.ko drivers/staging/csr/csr_wifi.ko }}} So, there are two drivers that we need to load with modprobe. You can load those drivers one at a time by passing modprobe the base filename: {{{ sudo modprobe csr_wifi }}} To ensure the driver got loaded, you can run: {{{ lsmod | less}}} In this case, you'll notice that both the csr_wifi and csr_helper modules got loaded. This is because the csr_wifi driver depends on the csr_helper driver, and modprobe automatically figured out it needed to load the csr_helper driver before it loaded the csr_wifi driver. = Committing your changes = In this example, assume we've addressed a warning in the CSR driver, modified the file, recompiled the driver, and tested our changes. == Viewing your changes == Git keeps track of changes in the working directory. Git can be told to ignore binary files (like .o or .ko files), so it won't track changes to those files. You can see which files have been modified by running: {{{ git status}}} git can also show you a diff stat of what changed: {{{ git diff}}} == Commit your changes == Assuming we want to include all of our changes in one git commit, you can use git to add the changed file to the list of changes to be committed (the "staging area"): {{{ git add <file>}}} If you run {{{`git diff`}}} again, you'll notice it doesn't list any changed files. That's because, by default, git diff only shows you the unstaged changes. If you run this command instead, you'll see the staged changes: {{{ git diff --cached}}} That command will show you the changes to be committed. == Reverting your staged changes == If you don't want to commit those changes, you can remove those changes from the staging area by running: {{{ git reset <file>}}} == Committing parts of files == You can also add parts of files to the staging area by using the {{-p}} flag: {{{ git add -p}}} That will allow you to add hunks of the file to the staging area, or even edit hunks that you want to commit. This is useful, for instance, if you've made whitespace changes, and also made a camel-case variable name fix, but those changes are on the same line. You can edit the line to revert the camel-case name change, and just add the whitespace change to the staging area. Then when you commit, you will just be committing the whitespace change. == Committing changes == Finally, you can commit your staged changes: {{{ git commit -s -v}}} That will add the Signed-off-by line that is needed at the end of your patch description. The -v flag will show you the diff that you're committing. This is very useful to decide whether you are committing the correct code. Make sure that when you create your patch, you follow the PatchPhilosophy guidelines. Make sure to include a blank line between your short description (what will become the Subject line of your patch) and the body of your patch. Make sure there is a blank line between the body of your patch and your Signed-off-by line. == Editing your commits == If you should need to edit your commit message, you can run {{{ git commit --amend -v}}} Tip: If you add new changes to the staging area with git add, when you run the above command, it will include those changes along with the previously commited changes. == Viewing your commit == Make sure your commit looks fine by running these commands: {{{ git show HEAD}}} This will show the latest commit. If you want git to show a different commit, you can pass the commit ID (the long number that's shown in {{{`git log`}}}, or the short number that's shown in {{{`git log --pretty=oneline --abbrev-commit`}}}). Read the "Specifying Revisions section" of the {{{`git rev-parse`}}} manual page for more details on what you can in place of a commit ID. You'll also want to make sure your commit looks fine when you run these two commands: {{{ git log}}} {{{ git log --pretty=oneline --abbrev-commit}}} = Submit a patch = The first step to submitting a patch is to create and send a patch as an email. You cannot send patches as attachments to the mailing list. Instead, you will have to craft a special email, and send the patch inline. There are two ways to send a patch. Either way is correct, and we suggest you get comfortable with sending patches both ways. We suggest sending your first patch to yourself, in order to make sure it works. == Creating a patch to send with mutt == First, create a patch that describes the, using {{{`git format-patch`}}}. That command takes a starting commit ID (and optionally) an ending commit ID, in order to create patches for the commit '''after''' the starting commit ID. We want to create a patch for the first commit in our history (the HEAD commit). To specify the commit before the HEAD commit, you can use either "HEAD^" or "HEAD~". {{{ git format patch -o /tmp/ HEAD^}}} The -o flag specifies where to put the patch. If you've run the command correctly, you should see the command output a filename in /tmp/. If it outputs nothing, you've forgotten the '^'. == Sending your patch with mutt == Next, tell mutt to use that patch as a draft email, with the -H flag: {{{ mutt -H /tmp/0001-<whatever your filename is>}}} Send this first patch to yourself. Leave the Subject line intact. Now you can see how your patch translates to an inline email. The git short description becomes the email subject line, and the patch body and diff become the body of the email. Write the mail, quit out of vim, and send the mail with 'y'. == Sending patches with git send-email == You can also send a patch with the command-line tool {{{`git send-email`}}}. You can either pass it the file that {{{`git format-patch`}}} generated, or you can give it the same commit ID range you gave {{{`git format-patch`}}}: {{{ git send-email --annotate HEAD^}}} git send email will prompt you with who to send the message to, and other odd questions. {{{ (FIXME: I don't use git send-email, someone else should expand this section.) }}} == Tips and Tricks == Please read the [:PatchTipsAndTricks:patch tips and tricks] page for an explanation of how to send multiple patches in one patchset, and when to use [PATCH] vs. [RFC] in your patch subject prefix. = Send your patch to your mentors = Once you've send your patch to your own email, and ensured that it looks fine, it's time to send your patch off to the [https://groups.google.com/forum/#!forum/opw-kernel opw-kernel mailing list]. '''DO NOT SEND YOUR FIRST PATCH TO THE MAIN LINUX MAILING LISTS!''' Make sure you have your mentor's ACK on the patch through the opw-kernel mailing list before sending it off to the main mailing lists. There may be protocol around who to send the email to, or which driver files should not be cleaned up with checkpatch.pl. Again, make sure you have your mentor's ACK before sending email off to the main mailing lists. |
Hooray! Thanks for your interest in working on the Linux kernel. The next step is to [:OPWApply:apply] to OPW, and use this tutorial to create your first patch to the Linux kernel.
Warning: this is still a work in progress. We'll announce on the opw-kernel mailing list when this tutorial is finished. Please [https://live.gnome.org/OutreachProgramForWomen#Application_Process turn in your application] to express interest in the kernel project, and sign up for the [https://groups.google.com/forum/#!forum/opw-kernel opw-kernel mailing list].
Intro
If you run into any issues with this tutorial, please ask questions on the #kernel-opw IRC channel on irc.oftc.net, or on the [https://groups.google.com/forum/#!forum/opw-kernel opw-kernel mailing list].
This tutorial will cover how to get your first patch submitted. You have three choices for how to complete this tutorial:
- Run Linux in VMPlayer from Windows.
- Run Linux natively on your own machine.
- Run Linux within VMPlayer on Linux.
We recommend options 1 or 2, with a preference towards running Linux natively. Accepted interns will be expected to run Linux natively, so you may as well get used to it. If you want to run Linux in VMPlayer, follow [:OPWfirstpatchAlt:these directions].
Overview
This tutorial will show you how to:
Setup your tools
You'll need to install, configure, and download some software to get started. You should follow the [OPWfirstpatchSetup setup directions] here.
Setup vim
(Note, if you're running a native Linux install and you're used to another editor like emacs or nano, you can still use that editor, and you can skip this step. You may not be able to use gvim.)
Tip: Vim is a simple text editor that has a couple modes. It starts out in standard mode, and you can move the cursor down or up with the arrow keys (or the 'j' or 'k' keys), and move the cursor left or right with the arrow keys (or the 'h' and 'l' keys). You can go into "Insert mode" by typing 'i'. Now you can change text. To get back into standard mode, type <Escape>. To write a file, get into standard mode, and type :w<enter>. To quit vim, type :q<enter>. If you want to learn more about vim, the [http://vim-adventures.com/ VIM adventures game] is quite fun.
First, we need to make sure to enable the C indentation module in our default text editor (vim). Turning on this module will ensure that lines automatically get indented to the right level as you're editing. It saves you from hitting <tab> a lot. You can turn on automatic indentation based on the file type. First run:
vim ~/.vimrc
Then add this line:
filetype plugin indent on
You'll also want to add a couple more lines, to turn syntax highlighting on, and show the file name in the terminal title bar:
syn on se title
Setup vim as your default editor
Next, we'll need to set up mutt to use vim as the default editor, instead of nano. Run:
sudo update-alternatives --config editor
and chose /usr/bin/vim.basic as the default editor.
Set up email
To be able to send Linux kernel patches, you'll need to be able to send email from the Linux VM image (or your computer that is natively running Linux). The VM image comes installed with esmtp, and if you were following the [:OPWfirstpatchAlt:native Linux install directions] you should have that installed on your computer as well. Esmtp is a mail transport agent. It routes email to your mail server, such as gmail. To know what information to give esmtp, you will need to look up your mail server settings.
Gmail set up
In gmail, go click the gear icon, go to "Settings", go to the tab "Forwarding POP/IMAP", and click the "Configuration instructions" link at the very bottom of the page.
Then click "I want to set up IMAP". At the bottom of the page, under the paragraph about configuring your mail client, select "Other". Note the outgoing mail server information, and copy it into the .esmtprc file, as shown in the next section.
Configure esmtp
First, create a .esmtprc file with the right permissions:
touch ~/.esmtprc chmod g-rwx ~/.esmtprc chmod o-rwx ~/.esmtprc
Edit the .esmtprc in your home directory, and add lines like this:
identity "my.email@gmail.com" hostname smtp.gmail.com:587 username "my.email@gmail.com" password "ThisIsNotARealPassWord" starttls required
Next, set up the mail client, mutt, with some defaults, but creating a .muttrc file in your homedirectory:
set sendmail="/usr/bin/esmtp" set envelope_from=yes set from="Your Name <my.email@gmail.com>" set use_from=yes set edit_headers=yes
Test your email setup
Next, let's send a test email message with mutt. Run this command:
mutt
Say "no" to creating an inbox for now. Type 'm' to create a new message. Specify your own email address (or a secondary email) to send the test message to. Set the Subject however you want to. Type a message in the body, and then save and quit. Hit 'y' to send the message, hit 'e' to edit the message again, or hit 'q' to abort sending the message.
Look in your email to double check you received a message. If you send the email to yourself, for some mail services like gmail, the message will not show up in your inbox, and you will have to look in your Sent Mail folder.
Setup git
First, you need to tell git what your name and email address is, so that it can be used in the authorship information in the git commit. Create a file called .gitconfig and add lines like these to it:
[user] name = Your Name email = your.email@example.com
Make sure that the email you specify here is the same email you used to set up sending mail. The Linux kernel developers will not accept a patch where the "From" email differs from the "Signed-off-by" line, which is what will happen if these two emails do not match.
Explore the kernel tree
First, open a terminal, by clicking the black screen icon with the ">_" text in it.
Tip: You can exit out of a terminal tab or window by pressing <CTRL>d at any time. This is the recommended way of closing the terminal, since it won't kill any processes you have running in the background. Get used to exiting the terminal this way by opening and closing the terminal a couple times.
The VM Image already has Linus' git tree checked out for you. Change directories to that git checkout:
cd git/kernels/linux/
This is the Linux kernel tree. You can explore it by using the `ls` and `cd` commands. If you run `ls, you'll see several different folders:
intern@ubuntu:~/git/kernels/linux$ ls arch init modules.order System.map block ipc Module.symvers tags COPYING Kbuild net tools CREDITS Kconfig README usr crypto kernel REPORTING-BUGS virt Documentation lib samples vmlinux drivers MAINTAINERS scripts vmlinux.o extra_certificates Makefile security x509.genkey firmware mm signing_key.priv fs Module.markers signing_key.x509 include modules.builtin sound
There's more to this directory than meets the eye! If you run ls -A, you'll see there's a hidden directory called .git. This contains all the meta information that git uses to track branches, remote repositories, and changes to files in the local directory.
You can view the commit history by running
git log
If you want a more compact form, you can run a command to see just the "short description" for each commit, with an abbrevated git commit ID:
git log --pretty=oneline --abbrev-commit
Play with some git basics
Git is a distributed revision control system, which means you can hack on your version of the code without having to coordinate with other developers. Think of your git checkout as a separate copy of Linus' kernel respository.
Git includes support for branches. Each branch can contain a completely different set of patches. Kernel developers typically use one branch per patchset. For example, you might have one branch that includes bug fixes, and another branch that contains commits for a new feature you're working on.
You can run `git branch` to see which branch you're on, and what other branches are available:
intern@ubuntu:~/git/kernels/linux$ git branch * master
In this case, there is only one branch, called master. The start indicates that the "master" branch is the one you are currently on. In git speak, we say that you currently have the master branch "checked out".
Create a new branch called 'staging', and checkout that branch by running:
git checkout -b staging
Now if you run git branch, you'll see that there are two branches, and you are currently on the "staging" branch:
intern@ubuntu:~/git/kernels/linux$ git branch master * staging
You can also use the git branch command to show branches on Linus' repository (the remote repository). Run the command:
{{{intern@ubuntu:~/git/kernels/linux$ git branch -a
- master
* staging
remotes/origin/HEAD -> origin/master remotes/origin/master}}}
The first remote repository that is used to create the git checkout is called "origin". For now, just remember that "origin" means Linus' remote git repository.
Update your kernel
When you create patches, you want to create them on top of the latest kernel from Linus. If your patch is out-of-date and doesn't apply to the latest tree, it may be rejected. You'll need to use git to fetch the latest changes:
git fetch origin
The third word in that command is the name of the remote repository you are fetching from.
That command will fetch the changes from Linus' tree, but it won't actually change in files in the working copy (i.e. the files in this directory). If you run:
git log
You will see that your current working directory still points to the original commit (3.9). So where are Linus' current changes?
The answer is that git stores the changes in a special hidden directory called .git. You can view the history of Linus' repository by giving git log the "master" branch of the "origin" remote repository (i.e. Linus' master branch):
git log origin/master
Next, we need to update our branch to include the changes in Linus' tree. The safest way to do this is to "rebase" your branch. This means that if you have any commits on your branch, they will be placed on top of Linus' commits. Sometimes you may have to edit your commits if there are conflicts, but you should ask your mentor for help with this. For now, run:
git rebase origin/master
If you run `git log` to show your staging branch history and then `git log origin/master` to show Linus' master branch history, you should see that they have exactly the same commits.
Configure the kernel
The next step is to create a configuration file, compile the new kernel, and install it.
The first thing to know is that the Linux kernel is completely configurable. Each driver can be separately configured to be installed or not. There are three choices for driver installation:
- disable the driver completely,
- build the driver into the main kernel file (vmlinuz),
- or build it as a module.
If you build the driver into the main kernel file, it will be loaded at boot time. The downside is that the kernel will have to load more code at boot for drivers that may not even corespond to hardware on the system. To avoid this, kernel developers often compile drivers as "modules". A module is a stand-alone .ko driver file that is loaded when the kernel detects hardware that matches the driver. For example, you could configure your wifi driver as a module, and the kernel will load it when it detects the wifi card.
The Linux kernel make system uses a special file called .config that stores what drivers are compiled in, or compiled as modules. Most Linux distributions store the .config file they used to compile your distro kernel in the /boot/ directory:
intern@ubuntu:~/git/kernels/linux$ ls /boot/ abi-3.5.0-23-generic initrd.img-3.9.0-rc8+ abi-3.5.0-27-generic memtest86+.bin config-3.5.0-23-generic memtest86+_multiboot.bin config-3.5.0-27-generic System.map-3.5.0-23-generic config-3.9.0 System.map-3.5.0-27-generic grub System.map-3.9.0 initrd.img-3.5.0-23-generic vmlinuz-3.5.0-23-generic initrd.img-3.5.0-27-generic vmlinuz-3.5.0-27-generic initrd.img-3.9.0 vmlinuz-3.9.0
You can duplicate the distro's configuration by copying one of the config-* files to a .config file in your git tree. This has already been done for you in the VM image.
Compile the kernel
Next, you'll need to run make to compile your new kernel. Optionally, make can take a flag that indicates how many threads to spawn to start separate compilations. Usually you want to pick a number that is equal to the number of CPUs you have in your machine. For example, if you had a dual core system, you would run:
make -j2
That may take a while. I would suggest reading some of the [http://lwn.net/Kernel/LDD3/ Linux Device Drivers book] while you're waiting.
Make a driver change
These next couple of steps will allow you to make a change to a driver, and test that you've correctly compiled and installed the modified driver.
One driver that's included in all VM images is the e1000 driver, the Intel ethernet driver. (Interns running Linux natively may want to use lsmod to see what other drivers they have loaded, and pick one from that list to modify.) The e1000 driver is found in the networking portion of the kernel:
intern@ubuntu:~/git/kernels/linux$ ls drivers/net/ethernet/intel/e1000/ e1000_ethtool.c e1000.h e1000_hw.c e1000_hw.h e1000_main.c e1000_osdep.h e1000_param.c Makefile
Let's make a small change to the probe function of the e1000 driver. A probe function is called when the driver is loaded. Let's edit e1000_main.c:
vim drivers/net/ethernet/intel/e1000/e1000_main.c
Next, find the probe function. You can search for text by typing '/' in standard mode. Once you've found the probe function, add a printk line to it:
static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct e1000_adapter *adapter; struct e1000_hw *hw; printk(KERN_DEBUG "I can modify the Linux kernel!\n"); static int cards_found = 0;
Then type :wq<enter> to save the file and quit.
A printk function causes a message to be written to the kernel log buffer, which can then be viewed using the dmesg command.
Compile your changes
Recompile your kernel, by running make (with an optional -jN flag):
make -j2
You may need to fixed some compilation errors. Also fix any new warnings that are due to your changes. In the Linux kernel, we strive to make sure that drivers do not produce warnings on anyone's system (this includes 32-bit and 64-bit systems, as well as different architectures, such as PPC, ARM, or x86). New features or bug fix patches that add additional warnings may not get merged.
Install your changes
After you've compiled the driver, you need to install your changes by running:
sudo make modules_install install
Test your changes
Since you've compiled a completely new kernel, you need to reboot into that new kernel in order to test your module changes. Reboot your VM (or computer), and then run:
dmesg | less
Search for your printk in the log file by typing "/I can modify". You should be able to find this message within the driver output during boot. If you don't see this message, ask for help on the #kernel-opw IRC channel on irc.oftc.net, or on the [https://groups.google.com/forum/#!forum/opw-kernel opw-kernel mailing list]
Revert your changes
Since that was just a simple test, and you probably don't want to commit that change, you can revert your changes. Exit out of your editor by typing :q<enter> and running this command:
git reset --hard HEAD
That will revert ALL FILES in your current working directory to the last known commit (the HEAD commit), wiping out all your uncommited changes. Read the git reset manual for more information on ways to reset the state for specific files.
Start creating your first patch
Next, you'll get to do some useful modifications to the kernel, create your first git commit, and send out your first patch. Before you make your first commit using git, you'll need to do some setup.
Git pre-commit hooks
Git includes some "hooks" for scripts that can be run before specific git commands are executed. The "pre-commit" hook is run before you make a git commit with the `git commit`` command.
Linux kernel developer have very stringent guidelines for [http://lxr.linux.no/#linux/Documentation/CodingStyle coding style]. They're so picky, they created a script called [http://lxr.linux.no/#linux/scripts/checkpatch.pl checkpatch.pl] that you can run over your patches to make sure the patch compiles to the kernel coding style.
To ensure that you create good commits that comply with the coding style, you can run checkpatch.pl over your commit with the "pre-commit" hook. That means git will refuse to commit your changes if it doesn't compily with kernel coding style.
Edit the .git/hooks/pre-commit file and add the following line:
exec git diff --cached | scripts/checkpatch.pl --no-signoff -
Tip: Sometimes you need to bypass checkpatch.pl (check with your mentor before doing this). If you need to bypass it, you can pass `git commit` the -n flag to bypass git hooks.
Understand patch best practices
Before you create your patch, we suggest you read about PatchPhilosophy. That document will help you create patches that are easy to read, and have a better chance of being applied by maintainers.
Find a driver to clean up
The staging tree, in drivers/staging/ is full of drivers that are not quite up to kernel coding style, or that use deprecated API. Drivers get placed here in order to get cleaned up. Some drivers have a TODO file in their parent directory, that lists things that need to be done to it:
find drivers/staging -name TODO
You can either tackle one of those TODO items, or you can do a simple coding style cleanup.
Running checkpatch.pl
If you pick a driver in staging, you can run the script that checks whether a file conforms to kernel coding style:
perl scripts/checkpatch.pl -f drivers/staging/csr/* | less
Pick a warning, and try to fix it.
Recompiling the driver
You'll need to make sure the driver you're changing is configured as a module. Run:
make menuconfig
This opens up a text-based GUI that allows you to explore the configuration options.
Use the arrow keys to go to Device Drivers -> and hit <enter>. Then go down to Staging drivers. At any time, you can hit '?', which will show you the help text for that kernel configuration option. You can search for the driver you're modifying by '/', in order to get the driver's longer name. Make sure the driver you're working on is compiled as a module ('M'), instead of being built-in ('*'). You can change a driver to being compiled as a module by typing 'm' when the driver is selected in the menu. Hitting <enter> will change the driver to being built-in.
Once you've enabled the driver you're modifying, use <tab> or the right arrow key to move the cursor from 'Select' to 'Exit' and hit <enter>. Continue to do this until you get to the main menu. When it asks you to save your configuration, chose 'Yes'.
Then recompile the kernel with:
make -j2
You should reboot your kernel, load the driver with modprobe. You'll be able to see that the driver is loaded by running lsmod. Loading the driver at least makes sure that the driver probe function works.
Reloading modules
If you're running a kernel that has the same release version (`uname -r`) as the new code you're compiling, you can test your changes without rebooting. Simply install the module in /lib/modules, and unload and reload the driver:
make -j2 && sudo make modules_install sudo modprobe -r <module_name> sudo modprobe <module_name>
How do you know what the module name is? If you've compiled the driver as a module, there should be a .ko file in the parent directory. For example, after we configure the CSR driver to be compiled as a module, we can run this command:
intern@ubuntu:~/git/kernel/linux$ ls drivers/staging/csr/*.ko drivers/staging/csr/csr_helper.ko drivers/staging/csr/csr_wifi.ko
So, there are two drivers that we need to load with modprobe. You can load those drivers one at a time by passing modprobe the base filename:
sudo modprobe csr_wifi
To ensure the driver got loaded, you can run:
lsmod | less
In this case, you'll notice that both the csr_wifi and csr_helper modules got loaded. This is because the csr_wifi driver depends on the csr_helper driver, and modprobe automatically figured out it needed to load the csr_helper driver before it loaded the csr_wifi driver.
Committing your changes
In this example, assume we've addressed a warning in the CSR driver, modified the file, recompiled the driver, and tested our changes.
Viewing your changes
Git keeps track of changes in the working directory. Git can be told to ignore binary files (like .o or .ko files), so it won't track changes to those files. You can see which files have been modified by running:
git status
git can also show you a diff stat of what changed:
git diff
Commit your changes
Assuming we want to include all of our changes in one git commit, you can use git to add the changed file to the list of changes to be committed (the "staging area"):
git add <file>
If you run `git diff` again, you'll notice it doesn't list any changed files. That's because, by default, git diff only shows you the unstaged changes. If you run this command instead, you'll see the staged changes:
git diff --cached
That command will show you the changes to be committed.
Reverting your staged changes
If you don't want to commit those changes, you can remove those changes from the staging area by running:
git reset <file>
Committing parts of files
You can also add parts of files to the staging area by using the flag:
git add -p
That will allow you to add hunks of the file to the staging area, or even edit hunks that you want to commit. This is useful, for instance, if you've made whitespace changes, and also made a camel-case variable name fix, but those changes are on the same line. You can edit the line to revert the camel-case name change, and just add the whitespace change to the staging area. Then when you commit, you will just be committing the whitespace change.
Committing changes
Finally, you can commit your staged changes:
git commit -s -v
That will add the Signed-off-by line that is needed at the end of your patch description. The -v flag will show you the diff that you're committing. This is very useful to decide whether you are committing the correct code.
Make sure that when you create your patch, you follow the PatchPhilosophy guidelines. Make sure to include a blank line between your short description (what will become the Subject line of your patch) and the body of your patch. Make sure there is a blank line between the body of your patch and your Signed-off-by line.
Editing your commits
If you should need to edit your commit message, you can run
git commit --amend -v
- Tip: If you add new changes to the staging area with git add, when you run the above command, it will include those changes along with the previously commited changes.
Viewing your commit
Make sure your commit looks fine by running these commands:
git show HEAD
This will show the latest commit. If you want git to show a different commit, you can pass the commit ID (the long number that's shown in `git log`, or the short number that's shown in `git log --pretty=oneline --abbrev-commit`). Read the "Specifying Revisions section" of the `git rev-parse` manual page for more details on what you can in place of a commit ID.
You'll also want to make sure your commit looks fine when you run these two commands:
git log
git log --pretty=oneline --abbrev-commit
Submit a patch
The first step to submitting a patch is to create and send a patch as an email. You cannot send patches as attachments to the mailing list. Instead, you will have to craft a special email, and send the patch inline.
There are two ways to send a patch. Either way is correct, and we suggest you get comfortable with sending patches both ways. We suggest sending your first patch to yourself, in order to make sure it works.
Creating a patch to send with mutt
First, create a patch that describes the, using `git format-patch`. That command takes a starting commit ID (and optionally) an ending commit ID, in order to create patches for the commit after the starting commit ID. We want to create a patch for the first commit in our history (the HEAD commit). To specify the commit before the HEAD commit, you can use either "HEAD^" or "HEAD~".
git format patch -o /tmp/ HEAD^
The -o flag specifies where to put the patch. If you've run the command correctly, you should see the command output a filename in /tmp/. If it outputs nothing, you've forgotten the '^'.
Sending your patch with mutt
Next, tell mutt to use that patch as a draft email, with the -H flag:
mutt -H /tmp/0001-<whatever your filename is>
Send this first patch to yourself. Leave the Subject line intact. Now you can see how your patch translates to an inline email. The git short description becomes the email subject line, and the patch body and diff become the body of the email.
Write the mail, quit out of vim, and send the mail with 'y'.
Sending patches with git send-email
You can also send a patch with the command-line tool `git send-email`. You can either pass it the file that `git format-patch` generated, or you can give it the same commit ID range you gave `git format-patch`:
git send-email --annotate HEAD^
git send email will prompt you with who to send the message to, and other odd questions.
(FIXME: I don't use git send-email, someone else should expand this section.)
Tips and Tricks
Please read the [:PatchTipsAndTricks:patch tips and tricks] page for an explanation of how to send multiple patches in one patchset, and when to use [PATCH] vs. [RFC] in your patch subject prefix.
Send your patch to your mentors
Once you've send your patch to your own email, and ensured that it looks fine, it's time to send your patch off to the [https://groups.google.com/forum/#!forum/opw-kernel opw-kernel mailing list].
DO NOT SEND YOUR FIRST PATCH TO THE MAIN LINUX MAILING LISTS!
Make sure you have your mentor's ACK on the patch through the opw-kernel mailing list before sending it off to the main mailing lists. There may be protocol around who to send the email to, or which driver files should not be cleaned up with checkpatch.pl. Again, make sure you have your mentor's ACK before sending email off to the main mailing lists.