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 = -22,pos打印出来是一个负数。
调试过程:
计算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引起的,然后再做具体处理。