linux内核bug调试指南(一)

1.      do_sync_write/do_sync_read读写错误,返回值ret=-22;

通过查对应内核源代码中errno-bash.h,可以知道-22表示Invalid argument

函数调用的形式如下:

#define WRITE_STRIPE_SIZE (128*1024)

loff_t pos;

mm_segment_t oldfs;

int offset;

offset = 17000;

pos = offset * WRITE_STRIPE_SIZE;

oldfs = get_fs();

set_fs(get_ds());

ret = do_sync_write(filp, buf, count, &pos);        

set_fs(oldfs);

if(ret != count)

eprintk("ret = %d, count = %d, pos = %lld/n”, ret, count, pos);

       结果写出错,ret = -22pos打印出来是一个负数。

       调试过程:

       计算offset * WRITE_STRIPE_SIZE = 2228224000

loff_t在内核态下就是long long类型的,长度为64bit,显然2228224000没有超过loff_t的范围,但是为什么赋值之后pos就是一个负数呢?出现负数的情况一般是数值溢出了。

加入下面语句

unsigned int temp;

temp = 17000 * WRITE_STRIPE_SIZE;

然后打印出来发现temp的值就是2228224000。然后再

pos = temp;

打印出来pos的值就是2228224000

可以确定是赋值的时候导致的数值溢出了!

所以采用强制类型转换

pos = (loff_t)offset * WRITE_STRIPE_SIZE;

或者#define WRITE_STRIPE_SIZE (128ll*1024)

这样就不会溢出了。

本来就是一个很小的细节问题,只要平时注意一点就不会出现这样的bug。所以细节很重要的,编程的时候注重风格规范,否则像这样的不起眼的bug会让人困扰好几天,这也算是一种经验积累的过程。

附录:常见错误信息(errno-bash.h

#define  EPERM         1   /* Operation not permitted */

#define  ENOENT              2   /* No such file or directory */

#define  ESRCH          3   /* No such process */

#define  EINTR           4   /* Interrupted system call */

#define  EIO        5   /* I/O error */

#define  ENXIO           6   /* No such device or address */

#define  E2BIG           7   /* Argument list too long */

#define  ENOEXEC             8   /* Exec format error */

#define  EBADF          9   /* Bad file number */

#define  ECHILD         10   /* No child processes */

#define  EAGAIN         11   /* Try again */

#define  ENOMEM            12   /* Out of memory */

#define  EACCES         13   /* Permission denied */

#define  EFAULT         14   /* Bad address */

#define  ENOTBLK             15   /* Block device required */

#define  EBUSY           16   /* Device or resource busy */

#define  EEXIST          17   /* File exists */

#define  EXDEV          18   /* Cross-device link */

#define  ENODEV              19   /* No such device */

#define  ENOTDIR             20   /* Not a directory */

#define  EISDIR           21   /* Is a directory */

#define  EINVAL          22   /* Invalid argument */

#define  ENFILE          23   /* File table overflow */

#define  EMFILE         24   /* Too many open files */

#define  ENOTTY        25   /* Not a typewriter */

#define  ETXTBSY              26   /* Text file busy */

#define  EFBIG            27   /* File too large */

#define  ENOSPC        28   /* No space left on device */

#define  ESPIPE          29   /* Illegal seek */

#define  EROFS           30   /* Read-only file system */

#define  EMLINK        31   /* Too many links */

#define  EPIPE            32   /* Broken pipe */

#define  EDOM          33   /* Math argument out of domain of func */

#define  ERANGE        34   /* Math result not representable */

2.      死锁问题

iscsitarget的代码运行时出现如下问题:

iscsi_trgt: cmnd_abort(1148) 5000000 1 0 42 3584 0 0

iscsi_trgt: Abort Task (01) issued on tid:1 lun:0 by sid:281475265921536 (Unknown Task)

ietd: Can't get session param 1 4

iscsi_trgt: ioctl(282) interrupted -4 -1066374899

这个问题是由程序中加的互斥锁引起多线程访问资源导致的死锁产生的。

检查程序中加锁的地方,逻辑上判断会不会出现死锁的地方加以修改。

3.      Unable to handle kernel paging request

问题如下:

Unable to handle kernel paging request at ffffc20000c03c00 RIP:

 [<ffffffff882ca7f7>] :iscsi_trgt:do_write+0x10e/0x4cf

PGD 37c00067 PUD 37c01067 PMD 35492067 PTE 0

Oops: 0002 [1] SMP

……

原因一:内存拷贝的错误,一般是memcpy(dst_buf, src_buf, count)det_buf或者src_buf地址出现错误。

       objdump反汇编目标文件可以查看出错的位置

       objdump –S xxx.o > debug_file

定位错误:根据“do_write+0x10e/0x4cf”可以定位出错的位置,在反汇编出来的debug_file里面先找到eraid10_write的函数入口地址0xeb1,然后0x10e是出错位置的相对偏移,则出错的地址为0xeb1+0x10e=0xfbf,找到对应位置的汇编代码如下:

repz movsb %ds:(%rsi),%es:(%rdi)

这句汇编指令就是表示memcpy这个函数的功能

然后根据这个错误再查看代码,分析是由dst_buf还是src_buf引起的,然后再做具体处理。

你可能感兴趣的:(linux内核bug调试指南(一))