内核代码阅读(10) - 内核缓冲区的管理slab下-阿里云开发者社区

开发者社区> 游客ebdjhbkyk4vb4> 正文

内核代码阅读(10) - 内核缓冲区的管理slab下

简介: 内核缓冲区的管理slab下
+关注继续查看

专用缓冲区 kmem_cache_free 缓冲区的释放

static inline void kmem_cache_free_one(kmem_cache_t *cachep, void *objp)
    {
        slab_t* slabp;
        CHECK_PAGE(virt_to_page(objp));
        slabp = GET_PAGE_SLAB(virt_to_page(objp));
        {
                unsigned int objnr = (objp-slabp->s_mem)/cachep->objsize;
                slab_bufctl(slabp)[objnr] = slabp->free;
                slabp->free = objnr;
        }
        STATS_DEC_ACTIVE(cachep);
        
        if (slabp->inuse-- == cachep->num)
                goto moveslab_partial;
        if (!slabp->inuse)
                goto moveslab_free;
        return;
    moveslab_partial:
        {
                struct list_head *t = cachep->firstnotfull;
                cachep->firstnotfull = &slabp->list;
                if (slabp->list.next == t)
                        return;
                list_del(&slabp->list);
                list_add_tail(&slabp->list, t);
                return;
        }
    moveslab_free:
        {
                struct list_head *t = cachep->firstnotfull->prev;
                list_del(&slabp->list);
                list_add_tail(&slabp->list, &cachep->slabs);
                if (cachep->firstnotfull == &slabp->list)
                        cachep->firstnotfull = t->next;
                return;
        }
    }
1) slabp = GET_PAGE_SLAB(virt_to_page(objp));
   通过要释放的物理地址,可以获取到对应的 struct page结构, 通过page结构的list可以找到objp所属的slab。
2) unsigned int objnr = (objp-slabp->s_mem)/cachep->objsize;
   slab_bufctl(slabp)[objnr] = slabp->free;
   计算objp在slab中的下标。
   更新slab中的空闲链接数组。
3) if (slabp->inuse-- == cachep->num)
           goto moveslab_partial;
   更新inuse计数器。

通用缓冲区的分配 kmalloc

void * kmalloc (size_t size, int flags)
    {
        cache_sizes_t *csizep = cache_sizes;
        for (; csizep->cs_size; csizep++) {
                if (size > csizep->cs_size)
                        continue;
                return __kmem_cache_alloc(flags & GFP_DMA ?
                         csizep->cs_dmacachep : csizep->cs_cachep, flags);
        }
        return NULL;
    }
1) cache_sizes 是一个cache_sizes_t的结构数组。
   typedef struct cache_sizes {
       size_t                 cs_size;
       kmem_cache_t        *cs_cachep;
       kmem_cache_t        *cs_dmacachep;
   } cache_sizes_t;
2) for 寻转在cache_sizes数组中找到第一个 csizep->cs_size大于size的kmem_cache_t类型的指针。
3) 然后通过 kmem_cache_alloc 分配。

kmem_cache_reap slab的回收

void kmem_cache_reap(int gfp_mask)
    {
        searchp = clock_searchp;
        do {
                unsigned int pages;
                struct list_head* p;
                unsigned int full_free;
                if (searchp->flags & SLAB_NO_REAP)
                        goto next;
                spin_lock_irq(&searchp->spinlock);
                if (searchp->growing)
                        goto next_unlock;
                if (searchp->dflags & DFLGS_GROWN) {
                        searchp->dflags &= ~DFLGS_GROWN;
                        goto next_unlock;
                }
                full_free = 0;
                p = searchp->slabs.prev;
                while (p != &searchp->slabs) {
                        slabp = list_entry(p, slab_t, list);
                        if (slabp->inuse)
                                break;
                        full_free++;
                        p = p->prev;
                }
                pages = full_free * (1<<searchp->gfporder);
                if (searchp->ctor)
                        pages = (pages*4+1)/5;
                if (searchp->gfporder)
                        pages = (pages*4+1)/5;
                if (pages > best_pages) {
                        best_cachep = searchp;
                        best_len = full_free;
                        best_pages = pages;
                        if (full_free >= REAP_PERFECT) {
                                clock_searchp = list_entry(searchp->next.next,
                                                        kmem_cache_t,next);
                                goto perfect;
                        }
                }
                searchp = list_entry(searchp->next.next,kmem_cache_t,next);
        } while (--scan && searchp != clock_searchp);
        clock_searchp = searchp;
        if (!best_cachep)
                goto out;
        spin_lock_irq(&best_cachep->spinlock);
    perfect:
        best_len = (best_len*4 + 1)/5;
        for (scan = 0; scan < best_len; scan++) {
                struct list_head *p;
                if (best_cachep->growing)
                        break;
                p = best_cachep->slabs.prev;
                if (p == &best_cachep->slabs)
                        break;
                slabp = list_entry(p,slab_t,list);
                if (slabp->inuse)
                        break;
                list_del(&slabp->list);
                if (best_cachep->firstnotfull == &slabp->list)
                        best_cachep->firstnotfull = &best_cachep->slabs;
                STATS_INC_REAPED(best_cachep);
                spin_unlock_irq(&best_cachep->spinlock);
                kmem_slab_destroy(best_cachep, slabp);
                spin_lock_irq(&best_cachep->spinlock);
        }
        spin_unlock_irq(&best_cachep->spinlock);
    out:
        up(&cache_chain_sem);
        return;
    }
1) searchp = clock_searchp;
   并不是每次扫描所有的slab队列。clock_searchp 会记住上一次扫描的位置。
2) kmem_slab_destroy(best_cachep, slabp);

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
linux内存管理--用户空间和内核空间
关于虚拟内存有三点需要注意: 4G的进程地址空间被人为的分为两个部分--用户空间与内核空间。用户空间从0到3G(0xc0000000),内核空间占据3G到4G。用户进程通常情况下只能访问用户空间的虚拟地址,不能访问内核空间的虚拟地址。
686 0
《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》——2.10 初始化缓冲区管理结构
本节书摘来自华章计算机《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》一书中的第2章,第2.10节,作者:新设计团队著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1142 0
git学习------&gt;在CenterOS系统上安装GitLab并自定义域名访问GitLab管理页面
目前就职的公司一直使用SVN作为版本管理,现在打算尝试从SVN迁移到Git。安排我来预言并搭建好相关的环境以及自己尝试使用Git。今天我就尝试在Center OS系统上安装GitLab,现在在此记录一下整个安装过程。
3380 0
C语言清空输入缓冲区的N种方法对比【转】
转自:http://www.cnblogs.com/codingmylife/archive/2010/04/18/1714954.html C语言中有几个基本输入函数: //获取字符系列 int fgetc(FILE *stream); int getc(FILE *stream); int getchar(void); //获取行系列 char *fgets(char * restrict s, int n, FILE * restrict stream); char *gets(char *s);//可能导致溢出,用fgets代替之。
663 0
Linux内核分析(三)----初识linux内存管理子系统
原文:Linux内核分析(三)----初识linux内存管理子系统 Linux内核分析(三) 昨天我们对内核模块进行了简单的分析,今天为了让我们今后的分析没有太多障碍,我们今天先简单的分析一下linux的内存管理子系统,linux的内存管理子系统相当的庞大,所以我们今天只是初识,只要对其进行简单的了解就好了,不会去追究代码,但是在后面我们还会对内存管理子系统进行一次深度的分析。
1179 0
Flink-CEP之带版本的共享缓冲区
带版本的共享缓冲区 当股票模式以一个事件流作为输入时,状态转换将会作用于事件流从而引起事件的状态变化。结合窗口对参与匹配的事件的限制以及模式中结合事件上下文(状态)的过滤条件,同一事件流随着时间的流动或者多次运行都会产生多种不同的匹配结果。
1609 0
84
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载