grant table 相关代码分析(基于linux2.6.32) 初始化与构建部分

来源:互联网 发布:iar编译51单片机怎么样 编辑:程序博客网 时间:2024/06/10 00:24

初始化部分:

static int __devinit gnttab_init(void)
{
    int i;
    unsigned int max_nr_glist_frames, nr_glist_frames;
    unsigned int nr_init_grefs;

    if (!xen_domain()) 判断是否为xen的domain(直接忽略掉)
        return -ENODEV;

    nr_grant_frames = 1;
    boot_max_nr_grant_frames = __max_nr_grant_frames();    //得到xen中定义的grant页框数,4.1中定义为32

    /* Determine the maximum number of frames required for the
     * grant reference free list on the current hypervisor.
     */
    max_nr_glist_frames = (boot_max_nr_grant_frames *
                   GREFS_PER_GRANT_FRAME / RPP); //RPP是每页能装载的 grant_ref_t(uint32_t)数, GREFS_PER_GRANT_FRAME是每页装载的grant_entry数(大概64位),那么这应该等于16

    gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
                  GFP_KERNEL);
  //为granttable分配足够空间, 16 * 4
    if (gnttab_list == NULL)
        return -ENOMEM;

    nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP; //应该是granttable的个数,一共2页
    for (i = 0; i < nr_glist_frames; i++) {
        gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);//每一项分配一页物理内存
        if (gnttab_list[i] == NULL)
            goto ini_nomem;
    }

    if (gnttab_resume() < 0)
        return -ENODEV;

    nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME; //64项

    for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
        gnttab_entry(i) = i + 1;

    gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
    gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
    gnttab_free_head  = NR_RESERVED_ENTRIES;

//构建好了gnttab_list应该是2行32列,每行前8列不用,那么应该剩48项

    printk("Grant table initialized\n");
    return 0;

 ini_nomem:
    for (i--; i >= 0; i--)
        free_page((unsigned long)gnttab_list[i]);
    kfree(gnttab_list);
    return -ENOMEM;
}

常用接口部分:

//将共享信息写入grant table中

static void update_grant_entry(grant_ref_t ref, domid_t domid,
                   unsigned long frame, unsigned flags)
{
    /*
     * Introducing a valid entry into the grant table:
     *  1. Write ent->domid.
     *  2. Write ent->frame:
     *      GTF_permit_access:   Frame to which access is permitted.
     *      GTF_accept_transfer: Pseudo-phys frame slot being filled by new
     *                           frame, or zero if none.
     *  3. Write memory barrier (WMB).
     *  4. Write ent->flags, inc. valid type.
     */
    shared[ref].frame = frame;
    shared[ref].domid = domid;
    wmb();
    shared[ref].flags = flags;
}

void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
                     unsigned long frame, int readonly)
{
    update_grant_entry(ref, domid, frame,
               GTF_permit_access | (readonly ? GTF_readonly : 0));
// GTF_permit_access表示允许domid映射或访问该frame
}
EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);

int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
                int readonly)
{
    int ref;

    ref = get_free_entries(1);//先得到一空项
    if (unlikely(ref < 0))
        return -ENOSPC;

    gnttab_grant_foreign_access_ref(ref, domid, frame, readonly);

    return ref;
}

结束访问部分:

static void do_free_callbacks(void)
{
    struct gnttab_free_callback *callback, *next;

    callback = gnttab_free_callback_list;
    gnttab_free_callback_list = NULL;

    while (callback != NULL) {
        next = callback->next;
        if (gnttab_free_count >= callback->count) {
            callback->next = NULL;
            callback->fn(callback->arg);
        } else {
            callback->next = gnttab_free_callback_list;
            gnttab_free_callback_list = callback;
        }
        callback = next;
    }
}

static inline void check_free_callbacks(void)
{
    if (unlikely(gnttab_free_callback_list))
        do_free_callbacks();
}

static void put_free_entry(grant_ref_t ref)//回收ref
{
    unsigned long flags;
    spin_lock_irqsave(&gnttab_list_lock, flags);
    gnttab_entry(ref) = gnttab_free_head;
    gnttab_free_head = ref;
    gnttab_free_count++;
    check_free_callbacks();
    spin_unlock_irqrestore(&gnttab_list_lock, flags);
}

int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
{
    u16 flags, nflags;

    nflags = shared[ref].flags;
    do {
        flags = nflags;
        if (flags & (GTF_reading|GTF_writing)) {
            printk(KERN_ALERT "WARNING: g.e. still in use!\n");
            return 0;
        }
    } while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags);
// 判断是否正在使用,如果正在使用就不能删除

    return 1;
}
EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);

void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
                   unsigned long page)
{
    if (gnttab_end_foreign_access_ref(ref, readonly)) {
        put_free_entry(ref);//回收该ref(即对应的项)
        if (page != 0)
            free_page(page);
    } else {
        /* XXX This needs to be fixed so that the ref and page are
           placed on a list to be freed up later. */
        printk(KERN_WARNING
               "WARNING: leaking g.e. and page still in use!\n");
    }
}



原创粉丝点击