I've been working with a userland program writeread.c
(referred here), utilizing the ftdi_sio
Linux driver.
I had worked with the default ftdi_sio
that comes with Ubuntu Lucid that I use - and then, as a sanity check, decided to rebuild ftdi_sio
from source. I did not want to download the entire kernel source, so I opted for so called "building out-of-tree modules":
- Howto: Build Linux Kernel Module Against Installed Kernel w/o Full Kernel Source Tree
- Debian Linux Kernel Handbook - Common kernel-related tasks: Building out-of-tree kernel modules
- Building a custom kernel - FedoraProject: Building Only Kernel Modules (Out Of Tree Modules)
... which means you can only have installed linux-headers-*
packages (instead of having entire linux-source-*
installed) - and the respective kernel module source - in order to build a kernel module.
So, I basically got the following files in a folder:
- ftdi_sio.c
- ftdi_sio.h
- ftdi_sio_ids.h
- Makefile (included below)
and ran make
- and a ftdi_sio.ko
kernel objects compiles, which also can be insmod
-ed without a problem.
The problem is now here - as long as I work with low speeds (115200 bps), there is no observable difference between: loading the 'vanilla' driver (using sudo modprobe ftdi_sio
); and loading the newly built driver (using sudo modprobe usbserial; sudo insmod /path/to/ftdi_sio.ko
) - in respect to the performance of the userland program (writeread.c
).
However, if I try the same at 2000000 bps, then the 'vanilla' driver works fine - while the build driver causes a segfault of the userland program (writeread.c
). In pa开发者_StackOverflowrticular, this segfault happened at free()
-ing memory resources - because the driver would end up reading more bytes from the loopback connection, than it itself would write! However, that in itself is not that relevant for this discussion, because I finally found a way to get the built ftdi_sio
to work (Edit: just noticed that a similar procedure is also given in External Linux kernel module dependencies R#2238581 - Stack Overflow):
$ sudo modprobe -r ftdi_sio # remove 'vanilla' driver from memory
...
# build the driver
$ cd /path/to/ftdi_sio_2.6.32/
$ make clean && make
# check vanilla version
$ ls -la /lib/modules/2.6.32-25-generic/kernel/drivers/usb/serial/ftdi_sio.ko
-rw-r--r-- 1 root root 102396 2010-10-17 01:47 /lib/modules/2.6.32-25-generic/kernel/drivers/usb/serial/ftdi_sio.ko
# (re)move the 'vanilla' kernel object
$ sudo mv /lib/modules/2.6.32-25-generic/kernel/drivers/usb/serial/ftdi_sio.ko ~/Desktop/ftdi_sio_orig.ko
# symlink our built version, as if it is the 'vanilla' one
$ sudo ln -s /path/to/ftdi_sio_2.6.32/ftdi_sio.ko /lib/modules/2.6.32-25-generic/kernel/drivers/usb/serial/
# check
$ ls -la /lib/modules/2.6.32-25-generic/kernel/drivers/usb/serial/ftdi_sio.ko
lrwxrwxrwx 1 root root 57 2010-10-26 12:49 /lib/modules/2.6.32-25-generic/kernel/drivers/usb/serial/ftdi_sio.ko -> /path/to/ftdi_sio_2.6.32/ftdi_sio.ko
# call depmod
$ sudo depmod
# !! plug in USB at this point, built driver autoloads;
# however, running `writeread.c` will segfault!
# !! REBOOT at this point
# after reboot:
# !! plug in USB at this point, built driver autoloads;
# and `writeread.c` runs without segfault
So, my question is: can anyone clarify to me, why - even after running depmod
- do I still have to reboot, to have the built driver behave properly? In other words: is there any other command I could call (maybe after depmod
), so that the driver works properly when it's loaded, without rebooting?
The reason I'm asking, is that I suspect that upon each recompilation of the kernel module, the symbol table will change - so to ensure that it works properly, I'd have to run depmod
and reboot after each time the driver is built - which I think would be kind of tedious :) So, it would be nice to be able to rebuild the kernel module, and use it in the same session - without having to reboot.
Well, thanks in advance for any answers,
Cheers!!
Makefile:
CONFIG_MODULE_FORCE_UNLOAD=y
# flags passed to gcc for compilation - -v:verbose, -H:show include files
# KBUILD_CFLAGS += -v
# for debugging make itself, use --debug=i in make command for targets
# debug build:
EXTRA_CFLAGS=-g -O0
KVERSION = $(shell uname -r)
obj-m += ftdi_sio.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
In short, no, I can't see anything wrong with the sequence you're doing, or why it would cause that behaviour.
The fact that the kernel allows the newly built module to be inserted basically means that you've built it properly and it has also inserted correctly, so there are no version mismatches or anything.
I'll guess that when you run the test at 2000000 bps, you first tested the vanilla driver and then the new driver? So my guess is the driver is not cleaning up something correctly, so when you run the test again (with the new driver) you see a segfault. But like I said, that's a guess.
精彩评论