`
tomhibolu
  • 浏览: 1431420 次
文章分类
社区版块
存档分类
最新评论

kernel hacker修炼之道之内存管理-SLUB(创建SLUB高速缓存kmem_cache_create())

 
阅读更多

创建SLUB高速缓存kmem_cache_create()


slab块内的对象是一个挨一个存放的,每个对象占用的空间主要包含两部分:对象本身和下一个空闲对象指针。依据空闲对象指针的位置,对象可分为两种:外置式和内置式。

先看外置式对象,如下图所示。指针位于对象的后面。对象还包括两个对齐用空间,word对齐是为了使后面的指针是word对齐的,obj对齐是为了使后面的对象按指定方式对齐。



再来看内置式对象,如下图所示。指针位于对象的头部,与对象共用存储空间。这是因为对象被分配出去之前,其存储空间是空闲的可用状态,可用于存放空闲对象指针。对象被分配出去后,也不再需要这个指针了,可以被对象内容覆盖。同理,对象释放时,不再使用对象内容,其空间可以用于存放指针。


如果在分配之前或释放之后,使用了对象的存储空间,那么就不能使用内置式指针,必须使用外置式指针,比如:

1)对象构造函数不为空:这样调用构造函数时,对象的存储空间被构造函数初始化。

2)使能了某些调试标记位:比如__OBJECT_POISON标记位,这样对象的存储空间会被初始化为固定的值,以利于调试。


struct kmem_cache *kmem_cache_create(const char *name, size_t size,
size_t align, unsigned long flags, void (*ctor)(void *))
{
struct kmem_cache *s;
char *n;
if (WARN_ON(!name))
return NULL;
down_write(&slub_lock);
/*查看是否可以复用*/
s = find_mergeable(size, align, flags, name, ctor);
if (s) {
/*如果可以复用就增加cache的引用计数*/
s->refcount++;
/*
* Adjust the object sizes so that we clear
* the complete object on kzalloc.
*/
/*cache对象的大小是cache中对象的大小和请求的对象的大小中最大的那个*/
s->objsize = max(s->objsize, (int)size);
s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *)));
if (sysfs_slab_alias(s, name)) {
s->refcount--;
goto err;
}
up_write(&slub_lock);
/*返回找到的cache*/
return s;
}
n = kstrdup(name, GFP_KERNEL);
if (!n)
goto err;
/*运行到这里说明不能复用,分配cache的描述符*/
s = kmalloc(kmem_size, GFP_KERNEL);
if (s) {
/*如果分配成功初始化cache,并把cache添加到slab_caches链表上*/
if (kmem_cache_open(s, n,
size, align, flags, ctor)) {
list_add(&s->list, &slab_caches);
if (sysfs_slab_add(s)) {
list_del(&s->list);
kfree(n);
kfree(s);
goto err;
}
up_write(&slub_lock);
return s;
}
kfree(n);
kfree(s);
}
err:
up_write(&slub_lock);
if (flags & SLAB_PANIC)
panic("Cannot create slabcache %s\n", name);
else
s = NULL;
return s;
}
EXPORT_SYMBOL(kmem_cache_create);

static struct kmem_cache *find_mergeable(size_t size,
size_t align, unsigned long flags, const char *name,
void (*ctor)(void *))
{
struct kmem_cache *s;
/*如果已经设置了不能复用标志则返回NULL*/
if (slub_nomerge || (flags & SLUB_NEVER_MERGE))
return NULL;
/*如果有构造函数返回NULL*/
if (ctor)
return NULL;
/*计算word对齐后的对象大小*/
size = ALIGN(size, sizeof(void *));
/*计算object对齐大小*/
align = calculate_alignment(flags, align, size);
size = ALIGN(size, align);
flags = kmem_cache_flags(size, flags, name, NULL);
/*找到合适的可以复用的cache*/
list_for_each_entry(s, &slab_caches, list) {
/*如果不满足复用的条件,跳过*/
if (slab_unmergeable(s))
continue;

if (size > s->size)
continue;

if ((flags & SLUB_MERGE_SAME) != (s->flags & SLUB_MERGE_SAME))
continue;
/*
* Check if alignment is compatible.
* Courtesy of Adrian Drzewiecki
*/
if ((s->size & ~(align - 1)) != s->size)
continue;

/*如果原来有cache的对象大小大于等于请求的大小,大的这部分小于sizeof(void*),则可以满足条件*/
if (s->size - size >= sizeof(void *))
continue;

return s;
}
return NULL;
}

static int kmem_cache_open(struct kmem_cache *s,
const char *name, size_t size,
size_t align, unsigned long flags,
void (*ctor)(void *))
{
/*设置cache描述符的相应成员*/
memset(s, 0, kmem_size);
s->name = name;
s->ctor = ctor;
s->objsize = size;
s->align = align;
s->flags = kmem_cache_flags(size, flags, name, ctor);
s->reserved = 0;

if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU))
s->reserved = sizeof(struct rcu_head);
/*计算内碎片的大小,页面的数量,对象的个数*/
if (!calculate_sizes(s, -1))
goto error;
if (disable_higher_order_debug) {
/*
* Disable debugging flags that store metadata if the min slab
* order increased.
*/
if (get_order(s->size) > get_order(s->objsize)) {
s->flags &= ~DEBUG_METADATA_FLAGS;
s->offset = 0;
if (!calculate_sizes(s, -1))
goto error;
}
}

/*
* The larger the object size is, the more pages we want on the partial
* list to avoid pounding the page allocator excessively.
*/
set_min_partial(s, ilog2(s->size));
/*新创建的,则引用计数置1*/
s->refcount = 1;
#ifdef CONFIG_NUMA
s->remote_node_defrag_ratio = 1000;
#endif
/*初始化节点相关的结构*/
if (!init_kmem_cache_nodes(s))
goto error;
/*初始化cpu local slab*/
if (alloc_kmem_cache_cpus(s))
return 1;

free_kmem_cache_nodes(s);
error:
if (flags & SLAB_PANIC)
panic("Cannot create slab %s size=%lu realsize=%u "
"order=%u offset=%u flags=%lx\n",
s->name, (unsigned long)size, s->size, oo_order(s->oo),
s->offset, flags);
return 0;
}

static int calculate_sizes(struct kmem_cache *s, int forced_order)
{
unsigned long flags = s->flags;
unsigned long size = s->objsize;
unsigned long align = s->align;
int order;

/*
* Round up object size to the next word boundary. We can only
* place the free pointer at word boundaries and this determines
* the possible location of the free pointer.
*/
/*对齐到word*/
size = ALIGN(size, sizeof(void *));

#ifdef CONFIG_SLUB_DEBUG
/*
* Determine if we can poison the object itself. If the user of
* the slab may touch the object after free or before allocation
* then we should never poison the object itself.
*/
if ((flags & SLAB_POISON) && !(flags & SLAB_DESTROY_BY_RCU) &&
!s->ctor)
s->flags |= __OBJECT_POISON;
else
s->flags &= ~__OBJECT_POISON;

/*
* If we are Redzoning then check if there is some space between the
* end of the object and the free pointer. If not then add an
* additional word to have some bytes to store Redzone information.
*/
if ((flags & SLAB_RED_ZONE) && size == s->objsize)
size += sizeof(void *);
#endif

/*
* With that we have determined the number of bytes in actual use
* by the object. This is the potential offset to the free pointer.
*/
s->inuse = size;

if (((flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) ||
s->ctor)) {
/*
* Relocate free pointer after the object if it is not
* permitted to overwrite the first word of the object on
* kmem_cache_free.
*
* This is the case if we do RCU, have a constructor or
* destructor or are poisoning the objects.
*/
s->offset = size;
size += sizeof(void *);
}

#ifdef CONFIG_SLUB_DEBUG
if (flags & SLAB_STORE_USER)
/*
* Need to store information about allocs and frees after
* the object.
*/
size += 2 * sizeof(struct track);

if (flags & SLAB_RED_ZONE)
/*
* Add some empty padding so that we can catch
* overwrites from earlier objects rather than let
* tracking information or the free pointer be
* corrupted if a user writes before the start
* of the object.
*/
size += sizeof(void *);
#endif

/*
* Determine the alignment based on various parameters that the
* user specified and the dynamic determination of cache line size
* on bootup.
*/
/*计算object对齐的大小*/
align = calculate_alignment(flags, align, s->objsize);
s->align = align;

/*
* SLUB stores one object immediately after another beginning from
* offset 0. In order to align the objects we have to simply size
* each object to conform to the alignment.
*/
size = ALIGN(size, align);
s->size = size;
/*如果指定了order就用指定的,否则自己计算一个合适的*/
if (forced_order >= 0)
order = forced_order;
else
order = calculate_order(size, s->reserved);

if (order < 0)
return 0;

s->allocflags = 0;
if (order)
s->allocflags |= __GFP_COMP;

if (s->flags & SLAB_CACHE_DMA)
s->allocflags |= SLUB_DMA;

if (s->flags & SLAB_RECLAIM_ACCOUNT)
s->allocflags |= __GFP_RECLAIMABLE;
/*
* Determine the number of objects per slab
*/
/*oo成员的高位保存页面的order,低位保存对象的个数。*/
s->oo = oo_make(order, size, s->reserved);
s->min = oo_make(get_order(size), size, s->reserved);
if (oo_objects(s->oo) > oo_objects(s->max))
s->max = s->oo;

return !!oo_objects(s->oo);
}

分享到:
评论

相关推荐

    Linux常见驱动源码分析(kernel hacker修炼之道全集)--李万鹏

    Linux常见驱动源码分析(kernel hacker修炼之道)--李万鹏 李万鹏 IBM Linux Technology Center kernel team 驱动资料清单内容如下: Linux设备模型(中)之上层容器.pdf Linux设备模型(上)之底层模型.pdf Linux...

    常见驱动源码分析(kernel hacker修炼之道)-李万鹏

    这本书是“Linux kernel hacker修炼之道”的一部分,通过深入剖析各种常见的驱动源码,帮助读者提升在Linux系统中的驱动开发能力。 在Linux操作系统中,驱动程序是连接硬件与内核的桥梁,它们负责管理和控制硬件...

    常见驱动源码分析(kernel hacker修炼之道)

    《常见驱动源码分析(kernel hacker修炼之道)》这本书或课程很可能深入探讨了如何理解和编写这些驱动,旨在帮助开发者提升对Linux内核和驱动编程的理解。在这个过程中,我们将会涉及到几个关键的知识点: 1. **Linux...

    linux kernel修炼之道

    如果刚刚对linux的kernel有兴趣,想了解点什么的话,请先看看此书吧,她风趣幽默的介绍了linux的发展趣事,让你开心快乐之余慢慢领会linux的魅力,让你了解学习掌握kernel的方法。其中的很多建议经过我的实践和摸索...

    Cmake-3.22.0-linux-x86_64安装包

    CMake是一款跨平台的构建工具,它用于管理软件构建过程,尤其适合大型项目或包含多个子项目的工程。CMake不依赖于任何特定的构建系统,而是生成本地构建文件(如Unix Makefiles、Visual Studio项目等),然后使用...

    网鼎杯-第三场-杂项-track_hacker

    【网鼎杯-第三场-杂项-track_hacker】是一个典型的网络安全竞赛中的挑战,涉及到的是CTF(Capture The Flag)比赛中的杂项类别。在CTF比赛中,参赛者需要运用各种安全技能解决难题,获取“旗标”(代表分数或解题...

    Linux内核驱动笔记

    内存管理负责分配、回收内存资源,管理虚拟内存和物理内存的映射关系,并实现内存保护机制。 Linux内核支持多种文件系统,例如ext2、fat、isofs等。虚拟文件系统(VFS)是Linux内核中的一个重要概念,它为不同文件...

    BotnetWebSocket-master_chancexvw_hacker_websocket_botnet_sangerp

    【标题解析】:“BotnetWebSocket-master_chancexvw_hacker_websocket_botnet_sangerp”这个标题中的关键词“BotnetWebSocket-master”暗示了一个与僵尸网络(Botnet)相关的项目,特别是利用WebSocket协议的。...

    Resource_Hacker_v5.1.6绿色版.zip

    资源 Hacker 是一款强大的Windows应用程序资源编辑工具,主要用于查看、修改、添加、删除以及替换应用程序中的资源,如图标、对话框、菜单、字符串表等。在本文中,我们将深入探讨Resource Hacker的功能、使用方法...

    HackerRank_2019-2018_Developer-Skills-Report.pdf

    这份标题为"HackerRank_2019-2018_Developer-Skills-Report.pdf"的报告,即HackerRank发布的2019-2018开发者技能报告,详细地探讨了开发者社区中的技术趋势和技能发展情况。根据描述,报告提出了React、物联网(IOT)...

    HackerRank-Interview-Preparation-Kit-master.rar

    《HackerRank面试准备套装详解》 HackerRank是一家知名的技术人才招聘平台,它提供了丰富的编程挑战和面试准备资源,帮助求职者提升技术能力并熟悉面试流程。"HackerRank-Interview-Preparation-Kit-master"是这个...

    通杀漏洞利用回显方法-linux平台 - 00theway _ blog _ hacker _ exp _ exploit _

    这需要深入理解JVM的工作原理和内存管理机制。同时,他还提到了`/proc/thread-self/`,这是一个学习线程信息的途径,对于理解系统级的调试和分析会有帮助。 4. **动手实践** 作者鼓励读者亲自尝试,通过动手实践来...

    x64_processhacker_源码

    Process Hacker是一款开源、免费且功能强大的系统信息工具,它允许用户查看并管理正在运行的进程、服务、线程以及内存等系统资源。 【描述】"Process Hacker 1.1 PH1" 提示我们这是Process Hacker的早期版本,版本...

    hacker成长之道

    有关hacker 的文章和资料分享给大家

    HackerRank---The-Linux-Shell-Problems_Solutions:问题可以通过-https

    1. **命令行基础**:如文件和目录的创建、删除、移动,以及文件属性的修改等。这涉及到`mkdir`、`rm`、`mv`、`cp`、`chmod`等基本命令。 2. **管道和重定向**:使用管道`|`可以将一个命令的输出作为另一个命令的...

    re-ad-to-se.zip_hacker

    super hacker tools pour tester beta

    matt-blaze-hacker-v1-0__1-13306

    骇客V1.0 描述 一个令人兴奋的游戏,将您带到了热门的位置,试图使MI6总部免遭破坏。 使用您的技能来克服这种情况。 记得保持冷静。 请下载并对其评分,以免错过。 即将推出进一步的升级! 更多信息 ...

    processhacker-2.39-bin

    ProcessHacker是一款强大的系统信息工具,它提供了进程管理、服务管理、硬件监控、内存查看等多种功能,深受系统管理员和高级用户的喜爱。这个"processhacker-2.39-bin"压缩包很可能包含了ProcessHacker的二进制版本...

Global site tag (gtag.js) - Google Analytics