项目调试bug感悟 && 取数的高位

来源:互联网 发布:php md5 编辑:程序博客网 时间:2024/05/02 21:21

1

spin_lock_irqsave的第二个参数 flag 必须为unsign long 型,否则会出内存溢出的问题

 

2

对一块内存free(vfree, kfree, mempool_free)后,一定要将相应的指针置空。 否则会出野指针的问题。 这一点在mempool_alloc,mempool_free尤其会出现。因为如果mempool_free没有将一个指针置空,下次在mempool_alloc拿到这块内存,进行并发操作,很有可能发生问题。

 

3

schedule 函数中,一进去,就会判断 unlikely(in_atomic() .... 看当前的thread_info中的抢占是否被禁止, 如果是,就立刻出错,并dump_stack()告诉用户出错信息。

 

原因: in_atomic 是说从“中断上下文” schedule 出来。 

 

 

#if defined(CONFIG_PREEMPT) && !defined(CONFIG_PREEMPT_BKL)

# define in_atomic()    ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())

#else

# define in_atomic()    ((preempt_count() & ~PREEMPT_ACTIVE) != 0)

#endif

 

 

由于我们一般使用的内核定义了 CONFIG_PREEMPT_BKL, 所以 

define in_atomic()    ((preempt_count() & ~PREEMPT_ACTIVE) != 0)

相当于看,3种计数器是否有一种不为0

0~7 : 抢占计数器

8~15:软中断计数器

16~27: 硬中断计数器

详细参看 ulk  p176

 

比较好的文章:http://www.21ic.com/app/embed/201003/54493_2.htm

 

 

CONFIG_PREEMPT_NONE,CONFIG_PREEMPT_VOLUNTARY和CONFIG_PREEMPT等多种配置选项。

分别适合于计算型任务系统,桌面用户系统和毫秒级延迟嵌入式系统


 

嵌入式 linux 实时化技术 : 

中断运行在中断上下文,没有一个所谓的中断描述符来描述它,它不是操作系统调度的单位。一旦在中断上下文中睡眠,首先无法切换上下文(因为没有中断描述符,当前上下文的状态得不到保存),其次,没有人来唤醒它,因为它不是操作系统的调度单位。
此外,中断的发生是非常非常频繁的,在一个中断睡眠期间,其它中断发生并睡眠了,那很容易就造成中断栈溢出导致系统崩溃

 

具体参考: http://blogold.chinaunix.net/u3/93255/showart.php?id=2418515

 

 

 

4

 

通过看MINOR宏和MAJOR宏 看到一个基本的问题:

dev_t 32位的数

#define MINORBITS 20

#define MINORMASK (1UL << MINORBITS) -1

 

1)

取一个数的高多少位:   右移几位

#define MAJOR(dev)      ((unsigned int) ((dev) >> MINORBITS))

 

 

2)

取一个数的低多少位:   与mask &

 

#define MINOR(dev)      ((unsigned int) ((dev) & MINORMASK))

 

5

mempool_alloc 的分配函数由 get_free_pages

则只需要对mempool_alloc打桩就可以了。 因为如果对get_free_pages打桩,返回0. 进过mempool_alloc之后,会变成一个野指针。

 

6

做测试时,一定要用iperf测试网络环境是否达到要求。 千兆网卡,混合读写下,所能提供带宽肯定小于千兆。 而且如果交换机也不给力的话,网络环境会更差。

 

7

对于并发的情况,如果对于它们所访问的临界资源没有用锁控制好,bug往往是随机(不是每次都出)出在一个奇怪的问题。 

上次在修改一个打桩的模块时, 信息往radix_tree上加时,上了锁。但radix_tree_delete时没有上锁,因此耽误了2天时间~


8     如果内核代码中老是panic到其系统,属于“Unable to handle kernel paging request at ffffc20000910b50 RIP” 这种错误访问内存的问题,可以再释放内存时,利用memset清空一下。 这样可以判断是否是我们的问题。   另外这里kfree时,想memset需要知道内存的大小, 内核中有ksize,但是是在mm/slab.c中实现的该函数,外面无法通过包含头文件, 来调用这个函数。  但是在/proc/kallsyms里面看到它导出了,可以知道它的地址。 这样可以定义一个函数指针,把那个地址赋给这个函数指针, 一个小的trick


/**
 * clear_bit - Clears a bit in memory
 * @nr: Bit to clear
 * @addr: Address to start counting from
 *
 * clear_bit() is atomic and may not be reordered.  However, it does
 * not contain a memory barrier, so if it is used for locking purposes,
 * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
 * in order to ensure changes are visible on other processors.
 */
static __inline__ void clear_bit(int nr, volatile void * addr)
{
__asm__ __volatile__( LOCK_PREFIX
"btrl %1,%0"
:"+m" (ADDR)
:"dIr" (nr));
}

这里遇到的一个问题是: 分配一段内存, 最后对u8的flag进行clear_bit , 发生内存请求错误。 

原因是: clear_bit 会先把1字节的内存放到通用寄存器中, 宏 ADDR会把该数转化成LONG型的, 这样就会访问8字节的内存。 

内存越界访问