内核代码阅读(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);
相关文章
|
4月前
|
Ubuntu Linux 数据安全/隐私保护
内核实验(七):使用内核KFIFO环形缓冲区机制
本文通过一个内核模块实验,演示了如何在Linux内核中使用KFIFO环形缓冲区机制,包括定义KFIFO、编写驱动程序以及在Qemu虚拟机中进行编译、部署和测试,展示了KFIFO在无需额外加锁的情况下如何安全地在读者和写者线程间进行数据传输。
184 0
内核实验(七):使用内核KFIFO环形缓冲区机制
|
7月前
|
存储 Linux 编译器
Linux用户空间和内核空间所有15种内存分配方法
Linux用户空间和内核空间所有15种内存分配方法
252 1
|
存储 安全 调度
DPDK环形缓冲区(Ring)详解及性能优化
DPDK环形缓冲区(Ring)详解及性能优化
|
存储 索引 Windows
驱动开发:内核物理内存寻址读写
在某些时候我们需要读写的进程可能存在虚拟内存保护机制,在该机制下用户的`CR3`以及`MDL`读写将直接失效,从而导致无法读取到正确的数据,本章我们将继续研究如何实现物理级别的寻址读写。首先,驱动中的物理页读写是指在驱动中直接读写物理内存页(而不是虚拟内存页)。这种方式的优点是它能够更快地访问内存,因为它避免了虚拟内存管理的开销,通过直接读写物理内存,驱动程序可以绕过虚拟内存的保护机制,获得对系统中内存的更高级别的访问权限。
7079 1
|
关系型数据库