/* * Find the offset of the base PFN from the specified align_order. * The value returned is represented in order_per_bits.
*/ staticunsignedlong cma_bitmap_aligned_offset(conststruct cma *cma, conststruct cma_memrange *cmr, unsignedint align_order)
{ return (cmr->base_pfn & ((1UL << align_order) - 1))
>> cma->order_per_bit;
}
/* * Check if a CMA area contains no ranges that intersect with * multiple zones. Store the result in the flags in case * this gets called more than once.
*/ bool cma_validate_zones(struct cma *cma)
{ int r; unsignedlong base_pfn; struct cma_memrange *cmr; bool valid_bit_set;
/* * If already validated, return result of previous check. * Either the valid or invalid bit will be set if this * check has already been done. If neither is set, the * check has not been performed yet.
*/
valid_bit_set = test_bit(CMA_ZONES_VALID, &cma->flags); if (valid_bit_set || test_bit(CMA_ZONES_INVALID, &cma->flags)) return valid_bit_set;
for (r = 0; r < cma->nranges; r++) {
cmr = &cma->ranges[r];
base_pfn = cmr->base_pfn;
/* * alloc_contig_range() requires the pfn range specified * to be in the same zone. Simplify by forcing the entire * CMA resv range to be in the same zone.
*/
WARN_ON_ONCE(!pfn_valid(base_pfn)); if (pfn_range_intersects_zones(cma->nid, base_pfn, cmr->count)) {
set_bit(CMA_ZONES_INVALID, &cma->flags); returnfalse;
}
}
cleanup: for (r = 0; r < allocrange; r++)
bitmap_free(cma->ranges[r].bitmap);
/* Expose all pages to the buddy, they are useless for CMA. */ if (!test_bit(CMA_RESERVE_PAGES_ON_ERROR, &cma->flags)) { for (r = 0; r < allocrange; r++) {
cmr = &cma->ranges[r];
end_pfn = cmr->base_pfn + cmr->count; for (pfn = early_pfn[r]; pfn < end_pfn; pfn++)
free_reserved_page(pfn_to_page(pfn));
}
}
totalcma_pages -= cma->count;
cma->available_count = cma->count = 0;
pr_err("CMA area %s could not be activated\n", cma->name);
}
staticint __init cma_init_reserved_areas(void)
{ int i;
for (i = 0; i < cma_area_count; i++)
cma_activate_area(&cma_areas[i]);
if (cma_area_count == ARRAY_SIZE(cma_areas)) {
pr_err("Not enough slots for CMA reserved regions!\n"); return -ENOSPC;
}
/* * Each reserved area must be initialised later, when more kernel * subsystems (like slab allocator) are available.
*/
cma = &cma_areas[cma_area_count];
cma_area_count++;
/** * cma_init_reserved_mem() - create custom contiguous area from reserved memory * @base: Base address of the reserved area * @size: Size of the reserved area (in bytes), * @order_per_bit: Order of pages represented by one bit on bitmap. * @name: The name of the area. If this parameter is NULL, the name of * the area will be set to "cmaN", where N is a running counter of * used areas. * @res_cma: Pointer to store the created cma region. * * This function creates custom contiguous area from already reserved memory.
*/ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, unsignedint order_per_bit, constchar *name, struct cma **res_cma)
{ struct cma *cma; int ret;
/* * CMA uses CMA_MIN_ALIGNMENT_BYTES as alignment requirement which * needs pageblock_order to be initialized. Let's enforce it.
*/ if (!pageblock_order) {
pr_err("pageblock_order not yet initialized. Called during early boot?\n"); return -EINVAL;
}
/* ensure minimal alignment required by mm core */ if (!IS_ALIGNED(base | size, CMA_MIN_ALIGNMENT_BYTES)) return -EINVAL;
ret = cma_new_area(name, size, order_per_bit, &cma); if (ret != 0) return ret;
/* * Structure used while walking physical memory ranges and finding out * which one(s) to use for a CMA area.
*/ struct cma_init_memrange {
phys_addr_t base;
phys_addr_t size; struct list_head list;
};
/* * Work array used during CMA initialization.
*/ staticstruct cma_init_memrange memranges[CMA_MAX_RANGES] __initdata;
/* * If allocating at a fixed base the request region must not * cross the low/high memory boundary.
*/ if (base < highmem_start && base + size > highmem_start) {
pr_err("Region at %pa defined on low/high memory boundary (%pa)\n",
&base, &highmem_start); return -EINVAL;
}
}
/* * If there is enough memory, try a bottom-up allocation first. * It will place the new cma area close to the start of the node * and guarantee that the compaction is moving pages out of the * cma area and not into it. * Avoid using first 4GB to not interfere with constrained zones * like DMA/DMA32.
*/ #ifdef CONFIG_PHYS_ADDR_T_64BIT if (!memblock_bottom_up() && limit >= SZ_4G + size) {
memblock_set_bottom_up(true);
addr = memblock_alloc_range_nid(size, align, SZ_4G, limit,
nid, true);
memblock_set_bottom_up(false);
} #endif
/* * On systems with HIGHMEM try allocating from there before consuming * memory in lower zones.
*/ if (!addr && IS_ENABLED(CONFIG_HIGHMEM)) {
phys_addr_t highmem = __pa(high_memory - 1) + 1;
/* * All pages in the reserved area must come from the same zone. * If the requested region crosses the low/high memory boundary, * try allocating from high memory first and fall back to low * memory in case of failure.
*/ if (base < highmem && limit > highmem) {
addr = memblock_alloc_range_nid(size, align, highmem,
limit, nid, true);
limit = highmem;
}
}
if (!addr)
addr = memblock_alloc_range_nid(size, align, base, limit, nid, true);
if (cma_area_count == ARRAY_SIZE(cma_areas)) {
pr_err("Not enough slots for CMA reserved regions!\n"); return -ENOSPC;
}
if (!size) return -EINVAL;
if (alignment && !is_power_of_2(alignment)) return -EINVAL;
if (!IS_ENABLED(CONFIG_NUMA))
nid = NUMA_NO_NODE;
/* Sanitise input arguments. */
alignment = max_t(phys_addr_t, alignment, CMA_MIN_ALIGNMENT_BYTES); if (fixed && base & (alignment - 1)) {
pr_err("Region at %pa must be aligned to %pa bytes\n",
&base, &alignment); return -EINVAL;
}
base = ALIGN(base, alignment);
size = ALIGN(size, alignment);
limit &= ~(alignment - 1);
if (!base)
fixed = false;
/* size should be aligned with order_per_bit */ if (!IS_ALIGNED(size >> PAGE_SHIFT, 1 << order_per_bit)) return -EINVAL;
/* * If the limit is unspecified or above the memblock end, its effective * value will be the memblock end. Set it explicitly to simplify further * checks.
*/ if (limit == 0 || limit > memblock_end)
limit = memblock_end;
if (base + size > limit) {
pr_err("Size (%pa) of region at %pa exceeds limit (%pa)\n",
&size, &base, &limit); return -EINVAL;
}
/* Reserve memory */ if (fixed) {
ret = cma_fixed_reserve(base, size); if (ret) return ret;
} else {
base = cma_alloc_mem(base, size, alignment, limit, nid); if (!base) return -ENOMEM;
/* * kmemleak scans/reads tracked objects for pointers to other * objects but this address isn't mapped and accessible
*/
kmemleak_ignore_phys(base);
}
ret = cma_init_reserved_mem(base, size, order_per_bit, name, res_cma); if (ret) {
memblock_phys_free(base, size); return ret;
}
(*res_cma)->nid = nid;
*basep = base;
return 0;
}
/* * Create CMA areas with a total size of @total_size. A normal allocation * for one area is tried first. If that fails, the biggest memblock * ranges above 4G are selected, and allocated bottom up. * * The complexity here is not great, but this function will only be * called during boot, and the lists operated on have fewer than * CMA_MAX_RANGES elements (default value: 8).
*/ int __init cma_declare_contiguous_multi(phys_addr_t total_size,
phys_addr_t align, unsignedint order_per_bit, constchar *name, struct cma **res_cma, int nid)
{
phys_addr_t start = 0, end;
phys_addr_t size, sizesum, sizeleft; struct cma_init_memrange *mrp, *mlp, *failed; struct cma_memrange *cmrp;
LIST_HEAD(ranges);
LIST_HEAD(final_ranges); struct list_head *mp, *next; int ret, nr = 1;
u64 i; struct cma *cma;
/* * First, try it the normal way, producing just one range.
*/
ret = __cma_declare_contiguous_nid(&start, total_size, 0, align,
order_per_bit, false, name, res_cma, nid); if (ret != -ENOMEM) goto out;
/* * Couldn't find one range that fits our needs, so try multiple * ranges. * * No need to do the alignment checks here, the call to * cma_declare_contiguous_nid above would have caught * any issues. With the checks, we know that: * * - @align is a power of 2 * - @align is >= pageblock alignment * - @size is aligned to @align and to @order_per_bit * * So, as long as we create ranges that have a base * aligned to @align, and a size that is aligned to * both @align and @order_to_bit, things will work out.
*/
nr = 0;
sizesum = 0;
failed = NULL;
ret = cma_new_area(name, total_size, order_per_bit, &cma); if (ret != 0) goto out;
align = max_t(phys_addr_t, align, CMA_MIN_ALIGNMENT_BYTES); /* * Create a list of ranges above 4G, largest range first.
*/
for_each_free_mem_range(i, nid, MEMBLOCK_NONE, &start, &end, NULL) { if (upper_32_bits(start) == 0) continue;
start = ALIGN(start, align); if (start >= end) continue;
end = ALIGN_DOWN(end, align); if (end <= start) continue;
size = end - start;
size = ALIGN_DOWN(size, (PAGE_SIZE << order_per_bit)); if (!size) continue;
sizesum += size;
/* * If we don't yet have used the maximum number of * areas, grab a new one. * * If we can't use anymore, see if this range is not * smaller than the smallest one already recorded. If * not, re-use the smallest element.
*/ if (nr < CMA_MAX_RANGES)
mrp = &memranges[nr++]; else {
mrp = list_last_entry(&ranges, struct cma_init_memrange, list); if (size < mrp->size) continue;
list_del(&mrp->list);
sizesum -= mrp->size;
pr_debug("deleted %016llx - %016llx from the list\n",
(u64)mrp->base, (u64)mrp->base + size);
}
mrp->base = start;
mrp->size = size;
/* * Now do a sorted insert.
*/
list_insert_sorted(&ranges, mrp, revsizecmp);
pr_debug("added %016llx - %016llx to the list\n",
(u64)mrp->base, (u64)mrp->base + size);
pr_debug("total size now %llu\n", (u64)sizesum);
}
/* * There is not enough room in the CMA_MAX_RANGES largest * ranges, so bail out.
*/ if (sizesum < total_size) {
cma_drop_area(cma);
ret = -ENOMEM; goto out;
}
/* * Found ranges that provide enough combined space. * Now, sorted them by address, smallest first, because we * want to mimic a bottom-up memblock allocation.
*/
sizesum = 0;
list_for_each_safe(mp, next, &ranges) {
mlp = list_entry(mp, struct cma_init_memrange, list);
list_del(mp);
list_insert_sorted(&final_ranges, mlp, basecmp);
sizesum += mlp->size; if (sizesum >= total_size) break;
}
/* * Walk the final list, and add a CMA range for * each range, possibly not using the last one fully.
*/
nr = 0;
sizeleft = total_size;
list_for_each(mp, &final_ranges) {
mlp = list_entry(mp, struct cma_init_memrange, list);
size = min(sizeleft, mlp->size); if (memblock_reserve(mlp->base, size)) { /* * Unexpected error. Could go on to * the next one, but just abort to * be safe.
*/
failed = mlp; break;
}
out: if (ret != 0)
pr_err("Failed to reserve %lu MiB\n",
(unsignedlong)total_size / SZ_1M); else
pr_info("Reserved %lu MiB in %d range%s\n",
(unsignedlong)total_size / SZ_1M, nr, str_plural(nr)); return ret;
}
/** * cma_declare_contiguous_nid() - reserve custom contiguous area * @base: Base address of the reserved area optional, use 0 for any * @size: Size of the reserved area (in bytes), * @limit: End address of the reserved memory (optional, 0 for any). * @alignment: Alignment for the CMA area, should be power of 2 or zero * @order_per_bit: Order of pages represented by one bit on bitmap. * @fixed: hint about where to place the reserved area * @name: The name of the area. See function cma_init_reserved_mem() * @res_cma: Pointer to store the created cma region. * @nid: nid of the free area to find, %NUMA_NO_NODE for any node * * This function reserves memory from early allocator. It should be * called by arch specific code once the early allocator (memblock or bootmem) * has been activated and all other subsystems have already allocated/reserved * memory. This function allows to create custom reserved areas. * * If @fixed is true, reserve contiguous area at exactly @base. If false, * reserve in range from @base to @limit.
*/ int __init cma_declare_contiguous_nid(phys_addr_t base,
phys_addr_t size, phys_addr_t limit,
phys_addr_t alignment, unsignedint order_per_bit, bool fixed, constchar *name, struct cma **res_cma, int nid)
{ int ret;
ret = __cma_declare_contiguous_nid(&base, size, limit, alignment,
order_per_bit, fixed, name, res_cma, nid); if (ret != 0)
pr_err("Failed to reserve %ld MiB\n",
(unsignedlong)size / SZ_1M); else
pr_info("Reserved %ld MiB at %pa\n",
(unsignedlong)size / SZ_1M, &base);
for (;;) {
spin_lock_irq(&cma->lock); /* * If the request is larger than the available number * of pages, stop right away.
*/ if (count > cma->available_count) {
spin_unlock_irq(&cma->lock); break;
}
bitmap_no = bitmap_find_next_zero_area_off(cmr->bitmap,
bitmap_maxno, start, bitmap_count, mask,
offset); if (bitmap_no >= bitmap_maxno) {
spin_unlock_irq(&cma->lock); break;
}
bitmap_set(cmr->bitmap, bitmap_no, bitmap_count);
cma->available_count -= count; /* * It's safe to drop the lock here. We've marked this region for * our exclusive use. If the migration fails we will take the * lock again and unmark it.
*/
spin_unlock_irq(&cma->lock);
ret = cma_range_alloc(cma, &cma->ranges[r], count, align,
&page, gfp); if (ret != -EBUSY || page) break;
}
/* * CMA can allocate multiple page blocks, which results in different * blocks being marked with different tags. Reset the tags to ignore * those page blocks.
*/ if (page) { for (i = 0; i < count; i++)
page_kasan_tag_reset(nth_page(page, i));
}
/** * cma_alloc() - allocate pages from contiguous area * @cma: Contiguous memory region for which the allocation is performed. * @count: Requested number of pages. * @align: Requested alignment of pages (in PAGE_SIZE order). * @no_warn: Avoid printing message about failed allocation * * This function allocates part of contiguous memory on specific * contiguous memory area.
*/ struct page *cma_alloc(struct cma *cma, unsignedlong count, unsignedint align, bool no_warn)
{ return __cma_alloc(cma, count, align, GFP_KERNEL | (no_warn ? __GFP_NOWARN : 0));
}
if (!cma || !pages || count > cma->count) returnfalse;
pfn = page_to_pfn(pages);
ret = false;
for (r = 0; r < cma->nranges; r++) {
cmr = &cma->ranges[r];
end = cmr->base_pfn + cmr->count; if (pfn >= cmr->base_pfn && pfn < end) {
ret = pfn + count <= end; break;
}
}
if (!ret)
pr_debug("%s(page %p, count %lu)\n",
__func__, (void *)pages, count);
return ret;
}
/** * cma_release() - release allocated pages * @cma: Contiguous memory region for which the allocation is performed. * @pages: Allocated pages. * @count: Number of allocated pages. * * This function releases memory allocated by cma_alloc(). * It returns false when provided pages do not belong to contiguous area and * true otherwise.
*/ bool cma_release(struct cma *cma, conststruct page *pages, unsignedlong count)
{ struct cma_memrange *cmr; unsignedlong pfn, end_pfn; int r;
for (r = 0; r < cma->nranges; r++) {
cmr = &cma->ranges[r];
rstart = PFN_PHYS(cmr->base_pfn);
rend = PFN_PHYS(cmr->base_pfn + cmr->count); if (end < rstart) continue; if (start >= rend) continue; returntrue;
}
returnfalse;
}
/* * Very basic function to reserve memory from a CMA area that has not * yet been activated. This is expected to be called early, when the * system is single-threaded, so there is no locking. The alignment * checking is restrictive - only pageblock-aligned areas * (CMA_MIN_ALIGNMENT_BYTES) may be reserved through this function. * This keeps things simple, and is enough for the current use case. * * The CMA bitmaps have not yet been allocated, so just start * reserving from the bottom up, using a PFN to keep track * of what has been reserved. Unreserving is not possible. * * The caller is responsible for initializing the page structures * in the area properly, since this just points to memblock-allocated * memory. The caller should subsequently use init_cma_pageblock to * set the migrate type and CMA stats the pageblocks that were reserved. * * If the CMA area fails to activate later, memory obtained through * this interface is not handed to the page allocator, this is * the responsibility of the caller (e.g. like normal memblock-allocated * memory).
*/ void __init *cma_reserve_early(struct cma *cma, unsignedlong size)
{ int r; struct cma_memrange *cmr; unsignedlong available; void *ret = NULL;
if (!cma || !cma->count) return NULL; /* * Can only be called early in init.
*/ if (test_bit(CMA_ACTIVATED, &cma->flags)) return NULL;
if (!IS_ALIGNED(size, CMA_MIN_ALIGNMENT_BYTES)) return NULL;
if (!IS_ALIGNED(size, (PAGE_SIZE << cma->order_per_bit))) return NULL;
size >>= PAGE_SHIFT;
if (size > cma->available_count) return NULL;
for (r = 0; r < cma->nranges; r++) {
cmr = &cma->ranges[r];
available = cmr->count - (cmr->early_pfn - cmr->base_pfn); if (size <= available) {
ret = phys_to_virt(PFN_PHYS(cmr->early_pfn));
cmr->early_pfn += size;
cma->available_count -= size; return ret;
}
}
return ret;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.31 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.