- 论坛徽章:
- 4
|
本帖最后由 chishanmingshen 于 2014-03-26 12:58 编辑
静态和动态的per-cpu变量存储在一段(貌似同一段?!)连续的虚拟空间?
如果上面猜测是对的,就需要在vmalloc空间预留一段连续空间啊,code在哪里?
希望结合pcpu_get_vm_areas这个函数 (3.12以上)指点下啊,谢谢!
3.12
- /**
- * pcpu_get_vm_areas - allocate vmalloc areas for percpu allocator
- * @offsets: array containing offset of each area
- * @sizes: array containing size of each area
- * @nr_vms: the number of areas to allocate
- * @align: alignment, all entries in @offsets and @sizes must be aligned to this
- *
- * Returns: kmalloc'd vm_struct pointer array pointing to allocated
- * vm_structs on success, %NULL on failure
- *
- * Percpu allocator wants to use congruent vm areas so that it can
- * maintain the offsets among percpu areas. This function allocates
- * congruent vmalloc areas for it with GFP_KERNEL. These areas tend to
- * be scattered pretty far, distance between two areas easily going up
- * to gigabytes. To avoid interacting with regular vmallocs, these
- * areas are allocated from top.
- *
- * Despite its complicated look, this allocator is rather simple. It
- * does everything top-down and scans areas from the end looking for
- * matching slot. While scanning, if any of the areas overlaps with
- * existing vmap_area, the base address is pulled down to fit the
- * area. Scanning is repeated till all the areas fit and then all
- * necessary data structres are inserted and the result is returned.
- */
- struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
- const size_t *sizes, int nr_vms,
- /**
- * pcpu_get_vm_areas - allocate vmalloc areas for percpu allocator
- * @offsets: array containing offset of each area
- * @sizes: array containing size of each area
- * @nr_vms: the number of areas to allocate
- * @align: alignment, all entries in @offsets and @sizes must be aligned to this
- *
- * Returns: kmalloc'd vm_struct pointer array pointing to allocated
- * vm_structs on success, %NULL on failure
- *
- * Percpu allocator wants to use congruent vm areas so that it can
- * maintain the offsets among percpu areas. This function allocates
- * congruent vmalloc areas for it with GFP_KERNEL. These areas tend to
- * be scattered pretty far, distance between two areas easily going up
- * to gigabytes. To avoid interacting with regular vmallocs, these
- * areas are allocated from top.
- *
- * Despite its complicated look, this allocator is rather simple. It
- * does everything top-down and scans areas from the end looking for
- * matching slot. While scanning, if any of the areas overlaps with
- * existing vmap_area, the base address is pulled down to fit the
- * area. Scanning is repeated till all the areas fit and then all
- * necessary data structres are inserted and the result is returned.
- */
- struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets,
- const size_t *sizes, int nr_vms,
- size_t align)
- {
- const unsigned long vmalloc_start = ALIGN(VMALLOC_START, align);
- const unsigned long vmalloc_end = VMALLOC_END & ~(align - 1);
- struct vmap_area **vas, *prev, *next;
- struct vm_struct **vms;
- int area, area2, last_area, term_area;
- unsigned long base, start, end, last_end;
- bool purged = false;
- /* verify parameters and allocate data structures */
- BUG_ON(align & ~PAGE_MASK || !is_power_of_2(align));
- for (last_area = 0, area = 0; area < nr_vms; area++) {
- start = offsets[area];
- end = start + sizes[area];
- /* is everything aligned properly? */
- BUG_ON(!IS_ALIGNED(offsets[area], align));
- BUG_ON(!IS_ALIGNED(sizes[area], align));
- /* detect the area with the highest address */
- if (start > offsets[last_area])
- last_area = area;
- for (area2 = 0; area2 < nr_vms; area2++) {
- unsigned long start2 = offsets[area2];
- unsigned long end2 = start2 + sizes[area2];
- if (area2 == area)
- continue;
- BUG_ON(start2 >= start && start2 < end);
- BUG_ON(end2 <= end && end2 > start);
- }
- }
- last_end = offsets[last_area] + sizes[last_area];
- if (vmalloc_end - vmalloc_start < last_end) {
- WARN_ON(true);
- return NULL;
- }
- vms = kcalloc(nr_vms, sizeof(vms[0]), GFP_KERNEL);
- vas = kcalloc(nr_vms, sizeof(vas[0]), GFP_KERNEL);
- if (!vas || !vms)
- goto err_free2;
- for (area = 0; area < nr_vms; area++) {
- vas[area] = kzalloc(sizeof(struct vmap_area), GFP_KERNEL);
- vms[area] = kzalloc(sizeof(struct vm_struct), GFP_KERNEL);
- if (!vas[area] || !vms[area])
- goto err_free;
- }
- retry:
- spin_lock(&vmap_area_lock);
- /* start scanning - we scan from the top, begin with the last area */
- area = term_area = last_area;
- start = offsets[area];
- end = start + sizes[area];
- if (!pvm_find_next_prev(vmap_area_pcpu_hole, &next, &prev)) {
- base = vmalloc_end - last_end;
- goto found;
- }
- base = pvm_determine_end(&next, &prev, align) - end;
- while (true) {
- BUG_ON(next && next->va_end <= base + end);
- BUG_ON(prev && prev->va_end > base + end);
- /*
- * base might have underflowed, add last_end before
- * comparing.
- */
- if (base + last_end < vmalloc_start + last_end) {
- spin_unlock(&vmap_area_lock);
- if (!purged) {
- purge_vmap_area_lazy();
- purged = true;
- goto retry;
- }
- goto err_free;
- }
- /*
- * If next overlaps, move base downwards so that it's
- * right below next and then recheck.
- */
- if (next && next->va_start < base + end) {
- base = pvm_determine_end(&next, &prev, align) - end;
- term_area = area;
- continue;
- }
- /*
- * If prev overlaps, shift down next and prev and move
- * base so that it's right below new next and then
- * recheck.
- */
- if (prev && prev->va_end > base + start) {
- next = prev;
- prev = node_to_va(rb_prev(&next->rb_node));
- base = pvm_determine_end(&next, &prev, align) - end;
- term_area = area;
- continue;
- }
- /*
- * This area fits, move on to the previous one. If
- * the previous one is the terminal one, we're done.
- */
- area = (area + nr_vms - 1) % nr_vms;
- if (area == term_area)
- break;
- start = offsets[area];
- end = start + sizes[area];
- pvm_find_next_prev(base + end, &next, &prev);
- }
- found:
- /* we've found a fitting base, insert all va's */
- for (area = 0; area < nr_vms; area++) {
- struct vmap_area *va = vas[area];
- va->va_start = base + offsets[area];
- va->va_end = va->va_start + sizes[area];
- __insert_vmap_area(va);
- }
- vmap_area_pcpu_hole = base + offsets[last_area];
- spin_unlock(&vmap_area_lock);
- /* insert all vm's */
- for (area = 0; area < nr_vms; area++)
- setup_vmalloc_vm(vms[area], vas[area], VM_ALLOC,
- pcpu_get_vm_areas);
- kfree(vas);
- return vms;
- err_free:
- for (area = 0; area < nr_vms; area++) {
- kfree(vas[area]);
- kfree(vms[area]);
- }
- err_free2:
- kfree(vas);
- kfree(vms);
- return NULL;
- }
复制代码 |
|