ftdi_sio v1.4.3 中的 ftdi_open() 在 _spin_lock_irqsave 处崩溃

ftdi_sio v1.4.3 中的 ftdi_open() 在 _spin_lock_irqsave 处崩溃

我正在使用 gentoo-2.6.30 中的 ftdichip 调制解调器和 ftdi_sio 驱动程序 v1.4.3 开发一个与短信相关的程序。但我现在遇到了一个奇怪的情况:当操作系统启动时,我的程序会不断尝试打开 /dev/ttyUSB0 而不休眠,直到成功(由于编码时没有正确考虑),然后我插入 USB 串行调制解调器,dmesg 会立即显示一个错误消息,如果我拔下调制解调器,系统将没有响应。

BUG信息如下:

[   43.769794] BUG: unable to handle kernel NULL pointer dereference at 00000074
[   43.775687] IP: [<405829ba>] _spin_lock_irqsave+0x8/0x1a
[   43.775687] *pdpt = 000000009ad51001 <6>usb 2-2: Detected FT232BM
[   43.785760] usb 2-2: FTDI USB Serial Device converter now attached to ttyUSB0
[   43.785840] drivers/usb/core/inode.c: creating file '002'
[   43.785686] *pde = 0000000000000000
[   43.785686] Oops: 0002 [#1] SMP
[   43.785686] last sysfs file:
[   43.785686] Modules linked in: ixgbe igb dca e1000e e1000
[   43.785686]
[   43.785686] Pid: 1059, comm: smssp.orig Not tainted (2.6.30-gentoo-r8 #24) AM5400B
[   43.785686] EIP: 0060:[<405829ba>] EFLAGS: 00010046 CPU: 1
[   43.785686] EIP is at _spin_lock_irqsave+0x8/0x1a
[   43.785686] EAX: 00000074 EBX: 00000074 ECX: 00000246 EDX: 00000100
[   43.785686] ESI: dade8400 EDI: 00000000 EBP: d903ba00 ESP: da43be28
[   43.785686]  DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
[   43.785686] Process smssp.orig (pid: 1059, ti=da43a000 task=dad6f710 task.ti=da43a000)
[   43.785686] Stack:
[   43.785686]  4047d5c8 da5f3000 4045bbb5 4073d460 d903ba00 d9001340 dade8400 404799fd
[   43.785686]  d88bfb40 d9001378 d903bad0 d903ba58 d903ba04 da652300 dade8400 d88bfb40
[   43.785686]  dade8400 4035d144 da8e48a8 00000000 00000902 00000100 0bc00000 00000000
[   43.785686] Call Trace:
[   43.785686]  [<4047d5c8>] ? ftdi_open+0x42/0x1a1
[   43.785686]  [<4045bbb5>] ? usb_autopm_do_interface+0x9a/0xa1
[   43.785686]  [<404799fd>] ? serial_open+0x112/0x189
[   43.785686]  [<4035d144>] ? tty_open+0x27b/0x3a9
[   43.785686]  [<40293524>] ? chrdev_open+0x128/0x152
[   43.785686]  [<402a198c>] ? mntput_no_expire+0x12/0xe0
[   43.785686]  [<402933fc>] ? chrdev_open+0x0/0x152
[   43.785686]  [<4028f5dd>] ? __dentry_open+0x113/0x1e9
[   43.785686]  [<40290413>] ? nameidata_to_filp+0x29/0x3c
[   43.785686]  [<40299ac4>] ? do_filp_open+0x3ab/0x689
[   43.785686]  [<4025d5bb>] ? __rcu_process_callbacks+0x57/0x159
[   43.785686]  [<40236d6a>] ? autoremove_wake_function+0x0/0x2d
[   43.785686]  [<402a05ff>] ? alloc_fd+0x5e/0xd0
[   43.785686]  [<4028f3ea>] ? do_sys_open+0x44/0xb4
[   43.785686]  [<4028f49e>] ? sys_open+0x1e/0x23
[   43.785686]  [<40202964>] ? sysenter_do_call+0x12/0x22
[   43.785686] Code: 74 05 e8 3e fe ff ff c3 fa f0 83 28 01 79 05 e8 4d fe ff ff c3 f0 81 00 00 00 00 01 fb c3 f0 ff 00 fb c3 9c 59 fa ba 00 01 00 00 <f0> 66 0f c1 10 38 f2 74 06 f3 90 8a 10 eb f6 89 c8 c3 9c 5a fa
[   43.785686] EIP: [<405829ba>] _spin_lock_irqsave+0x8/0x1a SS:ESP 0068:da43be28
[   43.785686] CR2: 0000000000000074
[   43.785686] ---[ end trace b68e6189f2a3d267 ]---
[   45.882827] hub 1-0:1.0: hub_suspend
[   45.886552] usb usb1: bus auto-suspend
[   45.890434] ehci_hcd 0000:00:1d.7: suspend root hub

这是我的等效重现测试程序:

/*
 * =====================================================================================
 *   compile:
 *      gcc -g usb.c -o usb_sleep.exe -DSLEEP -D_GNU_SOURCE
 *      gcc -g usb.c -o usb.exe -D_GNU_SOURCE
 *
 * =====================================================================================
 */
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int
main()
{
    char *dev = "/dev/ttyUSB0";

    //int fd = open(dev, O_RDONLY|O_LARGEFILE/* O_RDWR | O_NOCTTY | O_NONBLOCK */);
    //int fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
    int fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
    while(fd < 0)
    {
        //fd = open(dev, O_RDONLY|O_LARGEFILE/* O_RDWR | O_NOCTTY | O_NONBLOCK */);
        //fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
        fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
#ifdef SLEEP
        sleep(1);
#endif
    }
    printf("open tty ok!\n");
    char buf[1024];
    printf(buf, "at");
    int ret = write(fd, buf, strlen(buf));
    if(ret < 0){
        printf("write error:%s\n", strerror(errno));
    }
    ret = read(fd, buf, sizeof(buf) - 1);
    if(ret < 0){
        printf("read error:%s\n", strerror(errno));
    }
    close(fd);
}

重现过程:1.insmod usbserial.ko ftdi_sio.ko 2.#./usb.exe 运行我的测试程序 3.插入 USB 调制解调器,然后出现上面关于 ftdi_sio 堆栈信息的 dmesg

奇怪的是,如果我使用其他 usb_sleep.exe 进行测试,堆栈信息不会出现,并且打开 ttyUSB0 正常

我已经在另一个装有内核为 2.4.30 的机器上进行了测试,该机器的 ftdi_sio 版本为 1.3.5,没有发生任何奇怪的事情。

我已经在 Google 上搜索了几天并试图弄清楚,但没有发现任何有价值的东西。这是我在 Google 群组中找到的链接:http://groups.google.com/group/linux.kernel/browse_thread/thread/2c0c32a649006cf5/de263399cb0c38c9?show_docid=de263399cb0c38c9#,标题为“USB:ftdi_sio:修复 2.6.31 中的回归并清理”,但我真的不知道它是否有帮助,因为我对内核或驱动程序来说绝对是新手。

顺便说一句,我尝试用内核 2.6.32.58 中的较新版本 1.5.0 替换 ftdi_sio 驱动程序,但编译失败,错误消息如下:

drivers/usb/serial/ftdi_sio.o
drivers/usb/serial/ftdi_sio.c:931: warning: initialization from incompatible pointer type
drivers/usb/serial/ftdi_sio.c:932: warning: initialization from incompatible pointer type
drivers/usb/serial/ftdi_sio.c:933: error: unknown field ‘dtr_rts’ specified in initializer
drivers/usb/serial/ftdi_sio.c:933: warning: initialization from incompatible pointer type
drivers/usb/serial/ftdi_sio.c: In function ‘ftdi_process_packet’:
drivers/usb/serial/ftdi_sio.c:2219: error: implicit declaration of function ‘usb_serial_handle_break’
drivers/usb/serial/ftdi_sio.c:2235: error: ‘struct usb_serial_port’ has no member named ‘sysrq’
drivers/usb/serial/ftdi_sio.c:2239: error: implicit declaration of function ‘usb_serial_handle_sysrq_char’
make[3]: *** [drivers/usb/serial/ftdi_sio.o] Error 1
make[2]: *** [drivers/usb/serial] Error 2
make[1]: *** [drivers/usb] Error 2
make: *** [drivers] Error 2

我真的很沮丧,还有其他人遇到过这个问题吗?驱动程序有问题吗?

任何有帮助的答复都将受到感谢。

PSi 在 linux.kernel Google Groups 中发布了这个帖子,但是发布后我没有找到我的帖子,所以我在这里再次发布了帖子。:( 真诚的 ken

答案1

最后我把这个错误发布到[电子邮件保护]邮件列表,并且 Johan Hovold 好心地
提供了一个补丁来修复它。

以下是补丁的详细信息:

drivers/usb/serial/usb-serial.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index cc274fd..cb08235 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1059,6 +1059,12 @@ int usb_serial_probe(struct usb_interface *interface,
               serial->attached = 1;
       }

+       /* Avoid race with tty_open and serial_install by setting the
+        * disconnected flag and not clearing it until all ports are
+        * registered and the serial struct is fully initialised.
+        */
+       serial->disconnected = 1;
+
       if (get_free_serial(serial, num_ports, &minor) == NULL) {
               dev_err(&interface->dev, "No more free serial devices\n");
               goto probe_error;
@@ -1088,6 +1094,7 @@ int usb_serial_probe(struct usb_interface *interface,
 exit:
       /* success */
       usb_set_intfdata(interface, serial);
+       serial->disconnected = 0;
       module_put(type->driver.owner);
       return 0;

相关内容