Allocate returns a range of initially-zeroed pages of the given length, with a single reference on each page held by the caller. When the last reference on an allocated page is released, ownership of the page is returned to the MemoryFile, allowing it to be returned by a future call to Allocate. Pr
(length uint64, opts AllocOpts)
| 647 | // - length must be page-aligned. |
| 648 | // - If opts.Hugepage == true, length must be hugepage-aligned. |
| 649 | func (f *MemoryFile) Allocate(length uint64, opts AllocOpts) (memmap.FileRange, error) { |
| 650 | if length == 0 || !hostarch.IsPageAligned(length) || (opts.Huge && !hostarch.IsHugePageAligned(length)) { |
| 651 | panic(fmt.Sprintf("invalid allocation length: %#x", length)) |
| 652 | } |
| 653 | |
| 654 | alloc := allocState{ |
| 655 | length: length, |
| 656 | opts: opts, |
| 657 | willCommit: opts.Mode != AllocateUncommitted, |
| 658 | huge: opts.Huge && f.opts.ExpectHugepages, |
| 659 | } |
| 660 | |
| 661 | fr, err := f.findAllocatableAndMarkUsed(&alloc) |
| 662 | if err != nil { |
| 663 | return fr, err |
| 664 | } |
| 665 | |
| 666 | var dsts safemem.BlockSeq |
| 667 | if alloc.willCommit { |
| 668 | needHugeTouch := false |
| 669 | if alloc.recycled { |
| 670 | // We will need writable page table entries in our address space to |
| 671 | // zero these pages. |
| 672 | alloc.opts.Mode = AllocateAndWritePopulate |
| 673 | } else if alloc.opts.Mode != AllocateAndWritePopulate && ((alloc.huge && f.opts.AdviseHugepage) || (!alloc.huge && f.opts.AdviseNoHugepage)) { |
| 674 | // If Mode is AllocateCallerIndirectCommit and we do nothing, the |
| 675 | // first access to the allocation may be by the application, |
| 676 | // through a platform.AddressSpace, which may not have |
| 677 | // MADV_HUGEPAGE (=> vma flag VM_HUGEPAGE) set. Consequently, |
| 678 | // shmem_fault() => shmem_get_folio_gfp() will commit a small page. |
| 679 | // |
| 680 | // If Mode is AllocateAndCommit and we do nothing, the first access |
| 681 | // to the allocation is via fallocate(2), which has the same |
| 682 | // problem: shmem_fallocate() => shmem_get_folio() => |
| 683 | // shmem_get_folio_gfp(vma=NULL). |
| 684 | // |
| 685 | // khugepaged may eventually collapse the containing |
| 686 | // hugepage-aligned region into a huge page when it scans our |
| 687 | // mapping (khugepaged_scan_mm_slot() => khugepaged_scan_file()), |
| 688 | // but this depends on khugepaged_max_ptes_none, and in addition to |
| 689 | // the latency and overhead of doing so, this will incur another |
| 690 | // round of page faults. |
| 691 | // |
| 692 | // If write-populating through our mappings succeeds, then it will |
| 693 | // avoid this problem. Otherwise, we need to touch each huge page |
| 694 | // through our mappings. |
| 695 | // |
| 696 | // An analogous problem applies if MADV_NOHUGEPAGE is required |
| 697 | // rather than MADV_HUGEPAGE; MADV_NOHUGEPAGE is only enabled if |
| 698 | // the file defaults to huge pages, so populating or touching |
| 699 | // through our mappings is needed to ensure that the allocation is |
| 700 | // small-page-backed. In this case, we only need to force |
| 701 | // commitment of one small page per huge page to prevent future |
| 702 | // page faults within the huge page from faulting a huge page, |
| 703 | // though there's nothing we can do about khugepaged. |
| 704 | alloc.opts.Mode = AllocateAndWritePopulate |
| 705 | needHugeTouch = true |
| 706 | } |
nothing calls this directly
no test coverage detected