linux内核bug调试指南(一)

本文探讨了Linux内核编程中常见的问题,包括do_sync_write/do_sync_read读写错误、死锁问题及无法处理内核分页请求等问题,并详细介绍了如何通过检查参数有效性、避免死锁和正确进行内存拷贝来解决这些问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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引起的,然后再做具体处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值