GFP_ATOMIC allocations are special. If you call kmalloc(GFP_KERNEL), or alloc_page(GFP_KERNEL), you actually implicitly pass a couple of other flags in:
#define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS)
#define GFP_KERNEL (__GFP_WAIT | __GFP_IO | __GFP_FS)
From: MyWife Hansen <notmywife@yahoo.com>The From: name matches, but the email address does not. This is basically normal spam, but with a twist: someone has found out who I know in order to craft messages which I am very likely to open. How are they making the connection? There were two clues.
I make the kernel crash a lot. To debug those crashes, I add a lot of printk()s, recompile the kernel, and make it crash again. I repeat this until I fix the crash. This is time consuming, especially when the crash is bad enough that the system is unusable. For every cycle, I have to:
On some hardware, each of these reboots can be upwards of several minutes. Virtually all (>90%) of the time is spent waiting for the firmware before the bootloader and and way before the kernel loads. If I could get this down to one reboot cycle instead of two, it would drastically reduce the amount of time that this takes. Ideally, I'd also like to be compiling in parallel with the system booting.
My solution to this is to use a separate build machine and iPXE (I used to use GRUB for this). In short, iPXE can boot your system from the network. I use it instead of the "boot to a good kernel", "recompile, or copy new kernel over" step.
There are many ways to do this, but here's how I do it:
Compile yourself:
git clone http://git.ipxe.org/ipxe.git
cd ipxe/src
make -j4 bin/ipxe.lkrn
cp bin/ipxe.lkrn /boot
iPXE needs two bits of information to boot:
Those can be assigned at compile time, passed in by a DHCP server, or passed in at boot-time. I prefer to let the DHCP server assign the IP address, but I pass in the URL at boot-time from GRUB by putting the following in menu.lst:
title iPXE uuidkernel /boot/ipxe.lkrn && dhcp && chain http://1.2.3.4/~dave/ipxe.script
Remember to fill in your IP address and URL with appropriate values for your server.
Note that it references a URL on a web server. We need to go make sure that file exists. The kernel command-line should be a copy of what you see in menu.lst above.
$ cat ~/public_html/ipxe.script
#!gpxe kernel http://1.2.3.4/~dave/vmlinuz root=ro debug profile=2 console=ttyS0,115200
initrd http://1.2.3.4/~dave/initrd-from-boot.img
boot
Again, that will differ for your systems. You can either build the initrd each time you compile a kernel, or just ensure that the kernel image doesn't need any modules at all, and use an arbitrary initrd. Note that the whole kernel command-line is now in this file. That means that you can edit it on the web server with vim or emacs instead of having to do it on the GRUB command-line. I greatly prefer this to trying to use GRUB's console.
iPXE also has support for variables. You can do fun things like fetch a file with the system's IP address in the filename:
kernel http://9.47.67.96/~dave/vmlinuz-${net0/ip}
192.168.22.33 rss.framechannel.comwhere 192.168.22.33 is the IP of your web server. You can do this with bind, but it's a bit more involved. After you get this part working, you need some pictures in to Framechannel's XML format. I use this script to fetch a Picasa feed and put it in Framechannel's format. Lastly, you need a webserver which can serve the XML back out. In my case, I needed a path like this:
/productId=MOT001/frameId=00FD53221ABC/language=en/firmware=20090721I did it with this simple script:
DIR=/var/www/productId=MOT001/frameId=00FD53221ABC/language=en/Note: if you are going to do this, remember that this makes your pictures publicly accessible. You should at least set your web server to not let folks get directory indexes on "/productId=MOT001". But, they can still guess your frameId pretty easily.
mkdir -p "$DIR"
perl picasa-to-framechannel-rss.pl [your RSS feed here] > "$DIR/firmware=20090721"
Let's say you were trying to interpret this stack trace. Sometimes, the compiler will inline function calls and they might not show up in a stack trace, so it is not immediately apparent how tty_read() might call try_to_wake_up(). You can disassemble or use a debugger, but those both require skill. I prefer to replace having skill with tools instead, which is why I love addr2line. You need to feed it a vmlinux (not a vmlinuz or bzImage mind you), but its output is wonderful:[71818.339389] bash S 0000000000000000 0 3829 3753 0x00000000
[71818.339389] ffff88007a5fdd38 0000000000000086 0000000000000001 0000000000011e80
[71818.339389] 0000000000000000 ffff88007af31080 ffff88007bc15040 ffff88007fc11e80
[71818.339389] ffff88007af31080 0000000000000000 ffff88007fc11e80 0000000000000000
[71818.339389] Call Trace:
[71818.339389] [] ? check_preempt_curr+0x7a/0x90
[71818.339389] [] ? try_to_wake_up+0x1e5/0x280
[71818.339389] [] schedule+0x45/0x60
[71818.339389] [] schedule_timeout+0x14f/0x250
[71818.339389] [] n_tty_read+0x2f0/0x810
[71818.339389] [] ? try_to_wake_up+0x280/0x280
[71818.339389] [] tty_read+0xa6/0xe0
[71818.339389] [] vfs_read+0xcb/0x170
[71818.339389] [] sys_read+0x55/0x90
[71818.339389] [] system_call_fastpath+0x16/0x1b
Which points to:
dave@kernel:~/linux-2.6.git$ addr2line -e vmlinux ffffffff81389ff6
/home/dave/work/linux-2.6.git/drivers/tty/tty_io.c:959
dave@kernel:~/linux-2.6.git$ vi /home/dave/work/linux-2.6.git/drivers/tty/tty_io.c +959
and it's fairly easy to follow the call path from there.i = (ld->ops->read)(tty, file, buf, count);
else
i = -EIO;
tty_ldisc_deref(ld); <------------------
if (i > 0)
inode->i_atime = current_fs_time(inode->i_sb);
return i;
}
socat TCP4-LISTEN:12345 TCP4-LISTEN:56789The '12345' and '56789' are arbitrary (just remember to open them up in your local firewall). You can use just about whatever TCP ports you want as long as they are >1024 and <65536. This tells socat to sit around on tcp port 12345 and wait for a connection. When it gets a connection, it should only then wait for another connection on port 56789. All the traffic that comes in
socat TCP:yourserverfoo.dyndns.org:12345 TCP4:localhost:22That tells it to connect to yourserverfoo.dyndns.org's TCP port, and then pipe all that traffic to the local port 22 where the ssh daemon is listening. Finally, back on the internet-accessible system, you can do:
ssh -o HostName=localhost -p 56789 my-ssh-pushThe "-o HostName" bit is helpful to keep your ~/.ssh/known_hosts file from getting confused about what the key for 'localhost' might be. Once you do this, verify and accept the SSH host key, you should get a chance to log in.