博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux 3.10的list_del
阅读量:5963 次
发布时间:2019-06-19

本文共 3971 字,大约阅读时间需要 13 分钟。

最近看到一个page的数据比较奇怪:

crash> page ffffea002c239c58struct page {  flags = 54043195528445952,  _count = {    counter = 34-----------------------被引用34次  },  {    _mapcount = {      counter = -1---------------------没有映射    },    {      inuse = 65535,      objects = 65535    }  },  {    {      private = 0,      mapping = 0x0------------------为NULL,    },    ptl = {      raw_lock = {        slock = 0      }    },    slab = 0x0,    first_page = 0x0  },  {    index = 18446612222659373184,------------index这么大,明显不对    freelist = 0xffff881508fda880------------转成16进制,这个倒是像对的  },  lru = {    next = 0xdead000000100100,    prev = 0xdead000000200200  }}

查看一下这个地址:

crash> kmem 0xffff881508fda880CACHE            NAME                 OBJSIZE  ALLOCATED     TOTAL  SLABS  SSIZEffff880c17fb0d00 mm_struct               1408        230       580    116     8kSLAB              MEMORY            TOTAL  ALLOCATED  FREEffff881508fda280  ffff881508fda300      5          2     3FREE / [ALLOCATED]   ffff881508fda880      PAGE         PHYSICAL      MAPPING       INDEX CNT FLAGSffffea00499f77b0 1508fda000                0        0  1 c0000000000080 slab

最后看到的是lru的next和prev成员,一开始才疏学浅,觉得这个 0xdead000000100100 和 0xdead000000200200 很奇怪。

后来搜索之后,才发现这个是将一个entry删除之后,设置的标记值:

/* * Architectures might want to move the poison pointer offset * into some well-recognized area such as 0xdead000000000000, * that is also not mappable by user-space exploits: */#ifdef CONFIG_ILLEGAL_POINTER_VALUE# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL)#else# define POISON_POINTER_DELTA 0#endif/* * These are non-NULL pointers that will result in page faults * under normal circumstances, used to verify that nobody uses * non-initialized list entries. */#define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)#define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)

删除的代码实现如下:

static inline void list_del(struct list_head *entry){    __list_del(entry->prev, entry->next);    entry->next = LIST_POISON1;    entry->prev = LIST_POISON2;}

不光光是list,hlist也有类似动作:

static inline void hlist_del(struct hlist_node *n){    __hlist_del(n);    n->next = LIST_POISON1;    n->pprev = LIST_POISON2;}

 

在用户态程序中,我们一般通过判断指针是不是是null来判断能否使用这个指针,在将一个entry从list删除后,一般将prev和next设置为NULL,这样做没有什么问题,但是这样就没有

区分这个entry是从list摘除的,还是本身初始化的,所以为了调试方便,将其设置为一些特殊值,是有意义的。

当开启调试之后,即开启 CONFIG_DEBUG_LIST,则在加入链表和删除的时候都会加入调试warn

void __list_del_entry(struct list_head *entry){    struct list_head *prev, *next;    prev = entry->prev;    next = entry->next;    if (WARN(next == LIST_POISON1,        "list_del corruption, %p->next is LIST_POISON1 (%p)\n",        entry, LIST_POISON1) ||        WARN(prev == LIST_POISON2,        "list_del corruption, %p->prev is LIST_POISON2 (%p)\n",        entry, LIST_POISON2) ||        WARN(prev->next != entry,        "list_del corruption. prev->next should be %p, "        "but was %p\n", entry, prev->next) ||        WARN(next->prev != entry,        "list_del corruption. next->prev should be %p, "        "but was %p\n", entry, next->prev))        return;    __list_del(prev, next);}
void __list_add(struct list_head *new,                  struct list_head *prev,                  struct list_head *next){    WARN(next->prev != prev,        "list_add corruption. next->prev should be "        "prev (%p), but was %p. (next=%p).\n",        prev, next->prev, next);    WARN(prev->next != next,        "list_add corruption. prev->next should be "        "next (%p), but was %p. (prev=%p).\n",        next, prev->next, prev);    WARN(new == prev || new == next,         "list_add double add: new=%p, prev=%p, next=%p.\n",         new, prev, next);    next->prev = new;    new->next = next;    new->prev = prev;    prev->next = new;}

 当然,如果你摘链之后,还要继续挂链的话,还是要初始化的,这个时候就使用:

static inline voidlist_del_init(struct list_head *entry){    __list_del(entry->prev, entry->next);    INIT_LIST_HEAD(entry);-----------------------会重新初始化}

 

转载于:https://www.cnblogs.com/10087622blog/p/9625455.html

你可能感兴趣的文章
[Linux][Redis][05]Benchmark
查看>>
第一次作业-准备篇
查看>>
HDU1848 Fibonacci again and again
查看>>
HTML思维导图
查看>>
office2016选择性安装
查看>>
C# 自定义控件入门
查看>>
git改密码出现授权问题
查看>>
Hadoop IO 特性详解(2)
查看>>
ORA-02266: 表中的唯一/主键被启用的外键引用
查看>>
MySQL类型转换 使用CAST将varchar转换成int类型排序
查看>>
Django的POST请求时因为开启防止csrf,报403错误,及四种解决方法
查看>>
Apache common-fileupload用户指南
查看>>
day-6 and day-7:面向对象
查看>>
IE维护(IEM)策略不再适用于IE10及后续IE版本
查看>>
Java7中的ForkJoin并发框架初探(下)—— ForkJoin的应用
查看>>
java中的重量级与轻量级概念
查看>>
Linux设备驱动工程师之路——硬件访问及混杂设备LED驱动
查看>>
进程和线程<一>
查看>>
远程算数程序——版本v1.0
查看>>
Mysql常见四种索引的使用
查看>>