vm_area_struc 和 vm_struct

vm_area_struct 用于表示0~3G的空间中一段连续的虚拟地址空间,是给user space的process使用.
vm_struct 是kernel space 除low memory中用于表示连续的虚拟地址空间,常用于vmalloc/vfree的操作
struct vm_struct {
    struct vm_struct    *next; //表示下一个vm,所有的vm组成一个链表
    void            *addr;//虚拟地址
    unsigned long        size; //大小
    unsigned long        flags;
    struct page        **pages;//vm所映射的page
    unsigned int        nr_pages;//vm 所映射的page 的个数
    phys_addr_t        phys_addr;//对应起始的物理地址和addr相对应
    const void        *caller;//当前调用vm的指针
};
vm_struct的常用操作如下:可以看出这些都返回vm_struct
extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
extern struct vm_struct *get_vm_area_caller(unsigned long size,
                    unsigned long flags, const void *caller);
extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
                    unsigned long start, unsigned long end);
extern struct vm_struct *__get_vm_area_caller(unsigned long size,
                    unsigned long flags,
                    unsigned long start, unsigned long end,
                    const void *caller);
extern struct vm_struct *remove_vm_area(const void *addr);
extern struct vm_struct *find_vm_area(const void *addr);
struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
{
    return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
                  NUMA_NO_NODE, GFP_KERNEL,
                  __builtin_return_address(0));
}
可见是从VMALLOC_START 和 VMALLOC_END 之间分配内存,也间接证实了vm_struct 是kernel space管理虚拟内存的。
static struct vm_struct *__get_vm_area_node(unsigned long size,
        unsigned long align, unsigned long flags, unsigned long start,
        unsigned long end, int node, gfp_t gfp_mask, const void *caller)
{
    struct vmap_area *va;
    struct vm_struct *area;

    BUG_ON(in_interrupt());
    size = PAGE_ALIGN(size);
    if (unlikely(!size))
        return NULL;

    if (flags & VM_IOREMAP)
        align = 1ul << clamp_t(int, get_count_order_long(size),
                       PAGE_SHIFT, IOREMAP_MAX_ORDER);

    area = kzalloc_node(sizeof(*area), gfp_mask & GFP_RECLAIM_MASK, node);
    if (unlikely(!area))
        return NULL;

    if (!(flags & VM_NO_GUARD))
        size += PAGE_SIZE;

    va = alloc_vmap_area(size, align, start, end, node, gfp_mask);
    if (IS_ERR(va)) {
        kfree(area);
        return NULL;
    }

    setup_vmalloc_vm(area, va, flags, caller);

    return area;
}
__get_vm_area_node 的实现也很简单
首先申请一个vm_struct area的结构
area = kzalloc_node(sizeof(*area), gfp_mask & GFP_RECLAIM_MASK, node);
然后通过alloc_vmap_area 申请已经映射过的虚拟内存,已经映射的虚拟内存用vmap_area 表示,这段虚拟内存用rb tree表示,是在开机的过程中
vmalloc_init->__insert_vmap_area来插入的
static void __insert_vmap_area(struct vmap_area *va)
{
    struct rb_node **p = &vmap_area_root.rb_node;
    struct rb_node *parent = NULL;
    struct rb_node *tmp;

    while (*p) {
        struct vmap_area *tmp_va;

        parent = *p;
        tmp_va = rb_entry(parent, struct vmap_area, rb_node);
        if (va->va_start < tmp_va->va_end)
            p = &(*p)->rb_left;
        else if (va->va_end > tmp_va->va_start)
            p = &(*p)->rb_right;
        else
            BUG();
    }

    rb_link_node(&va->rb_node, parent, p);
    rb_insert_color(&va->rb_node, &vmap_area_root);

    /* address-sort this list */
    tmp = rb_prev(&va->rb_node);
    if (tmp) {
        struct vmap_area *prev;
        prev = rb_entry(tmp, struct vmap_area, rb_node);
        list_add_rcu(&va->list, &prev->list);
    } else
        list_add_rcu(&va->list, &vmap_area_list);
}
注意这个rb tree的root是vmap_area_root.rb_node。
回到__get_vm_area_node 中通过alloc_vmap_area 申请到虚拟内存后,就调用setup_vmalloc_vm 填充vm_struct
static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
                  unsigned long flags, const void *caller)
{
    spin_lock(&vmap_area_lock);
    vm->flags = flags;
    vm->addr = (void *)va->va_start;
    vm->size = va->va_end - va->va_start;
    vm->caller = caller;
    va->vm = vm;
    va->flags |= VM_VM_AREA;
    spin_unlock(&vmap_area_lock);
}


而vm_area_struct 是给进程用的,常用find_vma 来找到虚拟地址所在的vm_area_struct
struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
{
    struct rb_node *rb_node;
    struct vm_area_struct *vma;

    /* Check the cache first. */
    vma = vmacache_find(mm, addr);
    if (likely(vma))
        return vma;

    rb_node = mm->mm_rb.rb_node;

    while (rb_node) {
        struct vm_area_struct *tmp;

        tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);

        if (tmp->vm_end > addr) {
            vma = tmp;
            if (tmp->vm_start <= addr)
                break;
            rb_node = rb_node->rb_left;
        } else
            rb_node = rb_node->rb_right;
    }

    if (vma)
        vmacache_update(addr, vma);
    return vma;
}
可见也是用rb tree表示,但是这个rb tree的根节点是在自身mm中保存,每个进程都有自己的mm。如果能找到就返回vm_area_struct。负责就发生page fault。
从find_vma 中可以看到查找的时候会首先从vm cache中也就是vmacache_find 中查找,最后将查找的结构更新到vmacache_update 中.

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以通过修改 `get_tc_graph_struc` 函数来构造您需要的有向图。具体而言,您可以按照如下方式修改代码: ```python def get_tc_graph_struc(temporal_len): struc_map = {} temporal_list = list(range(0,temporal_len)) for tp in temporal_list: if tp not in struc_map: struc_map[tp] = [] if tp % 2 == 1 and tp > 0: struc_map[tp].append(tp-1) if tp % 2 == 0 and tp < temporal_len-1: struc_map[tp].append(tp+1) return struc_map ``` 在上面的代码中,我们首先创建了一个空字典 `struc_map`,然后使用 `list` 函数创建了一个包含 0 到 `temporal_len-1` 的整数列表 `temporal_list`,表示时间序列上的所有时间点。 接下来,我们遍历所有时间点,对于每个时间点 `tp`,如果它还没有出现在 `struc_map` 中,就将其加入字典,并且初始化对应的值为一个空列表。然后,我们使用 if 语句来判断当前时间点 `tp` 的奇偶性,并且根据奇偶性来确定与其相邻的时间点,并将其加入 `tp` 对应的列表中,表示在时间序列上存在一条从 `tp` 到相邻时间点的有向边。具体而言,如果 `tp` 是奇数且大于 0,则将 `tp-1` 加入 `tp` 对应的列表中;如果 `tp` 是偶数且小于 `temporal_len-1`,则将 `tp+1` 加入 `tp` 对应的列表中。 最后,我们返回构建好的结构映射字典 `struc_map`。 总之,通过修改上述代码,您可以构造出满足您需要的有向图,其中时间点 1 和时间点 3 连接,时间点 2 和时间点 4 连接,以此类推。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值