Stefan Kempf wrote:
> amap_extend is called when merging two adjacent areas of virtual address
> space. However, merging is done only for kernel
> virtual address space. It's not done for user space:
>
> uvm/uvm_map.c:1359
> /*
> * Try to merge entry.
> *
> * Userland allocations are kept separated most of the time.
> * Forego the effort of merging what most of the time can't be merged
> * and only try the merge if it concerns a kernel entry.
> */
> if ((flags & UVM_FLAG_NOMERGE) == 0 &&
> (map->flags & VM_MAP_ISVMSPACE) == 0)
> uvm_mapent_tryjoin(map, entry, &dead);
>
>
> As far as I can tell, kernel vm_map_entries do not use amaps. So
> amap_extend should never be called. Can we remove it?
Any objections against committing this diff?
Merging vm map entries for userspace was turned off a long time
ago in r1.104 of uvm/uvm_map.c.
The kernel doesn't use amaps either. Removing this would make the amap
shrink diffs simpler.
> Index: uvm/uvm_amap.c
> ===================================================================
> RCS file: /cvs/src/sys/uvm/uvm_amap.c,v
> retrieving revision 1.62
> diff -u -p -r1.62 uvm_amap.c
> --- uvm/uvm_amap.c 16 Mar 2016 16:53:43 -0000 1.62
> +++ uvm/uvm_amap.c 23 Mar 2016 17:03:53 -0000
> @@ -279,174 +279,6 @@ amap_free(struct vm_amap *amap)
> }
>
> /*
> - * amap_extend: extend the size of an amap (if needed)
> - *
> - * => called from uvm_map when we want to extend an amap to cover
> - * a new mapping (rather than allocate a new one)
> - * => to safely extend an amap it should have a reference count of
> - * one (thus it can't be shared)
> - * => XXXCDC: support padding at this level?
> - */
> -int
> -amap_extend(struct vm_map_entry *entry, vsize_t addsize)
> -{
> - struct vm_amap *amap = entry->aref.ar_amap;
> - int slotoff = entry->aref.ar_pageoff;
> - int slotmapped, slotadd, slotneed, slotalloc;
> -#ifdef UVM_AMAP_PPREF
> - int *newppref, *oldppref;
> -#endif
> - u_int *newsl, *newbck, *oldsl, *oldbck;
> - struct vm_anon **newover, **oldover;
> - int slotadded;
> -
> - /*
> - * first, determine how many slots we need in the amap. don't
> - * forget that ar_pageoff could be non-zero: this means that
> - * there are some unused slots before us in the amap.
> - */
> - AMAP_B2SLOT(slotmapped, entry->end - entry->start); /* slots mapped */
> - AMAP_B2SLOT(slotadd, addsize); /* slots to add */
> - slotneed = slotoff + slotmapped + slotadd;
> -
> - /*
> - * case 1: we already have enough slots in the map and thus
> - * only need to bump the reference counts on the slots we are
> - * adding.
> - */
> - if (amap->am_nslot >= slotneed) {
> -#ifdef UVM_AMAP_PPREF
> - if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
> - amap_pp_adjref(amap, slotoff + slotmapped, slotadd, 1);
> - }
> -#endif
> - return (0);
> - }
> -
> - /*
> - * case 2: we pre-allocated slots for use and we just need to
> - * bump nslot up to take account for these slots.
> - */
> - if (amap->am_maxslot >= slotneed) {
> -#ifdef UVM_AMAP_PPREF
> - if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
> - if ((slotoff + slotmapped) < amap->am_nslot)
> - amap_pp_adjref(amap, slotoff + slotmapped,
> - (amap->am_nslot - (slotoff + slotmapped)),
> - 1);
> - pp_setreflen(amap->am_ppref, amap->am_nslot, 1,
> - slotneed - amap->am_nslot);
> - }
> -#endif
> - amap->am_nslot = slotneed;
> - /*
> - * no need to zero am_anon since that was done at
> - * alloc time and we never shrink an allocation.
> - */
> - return (0);
> - }
> -
> - /*
> - * case 3: we need to malloc a new amap and copy all the amap
> - * data over from old amap to the new one.
> - *
> - * XXXCDC: could we take advantage of a kernel realloc()?
> - */
> - if (slotneed >= UVM_AMAP_LARGE)
> - return E2BIG;
> -
> - if (slotneed > UVM_AMAP_CHUNK)
> - slotalloc = malloc_roundup(slotneed * MALLOC_SLOT_UNIT) /
> - MALLOC_SLOT_UNIT;
> - else
> - slotalloc = slotneed;
> -
> -#ifdef UVM_AMAP_PPREF
> - newppref = NULL;
> - if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
> - newppref = mallocarray(slotalloc, sizeof(int), M_UVMAMAP,
> - M_WAITOK | M_CANFAIL);
> - if (newppref == NULL) {
> - /* give up if malloc fails */
> - free(amap->am_ppref, M_UVMAMAP, 0);
> - amap->am_ppref = PPREF_NONE;
> - }
> - }
> -#endif
> - if (slotneed > UVM_AMAP_CHUNK)
> - newsl = malloc(slotalloc * MALLOC_SLOT_UNIT, M_UVMAMAP,
> - M_WAITOK | M_CANFAIL);
> - else
> - newsl = pool_get(&uvm_amap_slot_pools[slotalloc - 1],
> - PR_WAITOK | PR_LIMITFAIL);
> - if (newsl == NULL) {
> -#ifdef UVM_AMAP_PPREF
> - if (newppref != NULL) {
> - free(newppref, M_UVMAMAP, 0);
> - }
> -#endif
> - return (ENOMEM);
> - }
> - newbck = (int *)(((char *)newsl) + slotalloc * sizeof(int));
> - newover = (struct vm_anon **)(((char *)newbck) + slotalloc *
> - sizeof(int));
> - KASSERT(amap->am_maxslot < slotneed);
> -
> - /* now copy everything over to new malloc'd areas... */
> - slotadded = slotalloc - amap->am_nslot;
> -
> - /* do am_slots */
> - oldsl = amap->am_slots;
> - memcpy(newsl, oldsl, sizeof(int) * amap->am_nused);
> - amap->am_slots = newsl;
> -
> - /* do am_anon */
> - oldover = amap->am_anon;
> - memcpy(newover, oldover, sizeof(struct vm_anon *) * amap->am_nslot);
> - memset(newover + amap->am_nslot, 0, sizeof(struct vm_anon *) *
> - slotadded);
> - amap->am_anon = newover;
> -
> - /* do am_bckptr */
> - oldbck = amap->am_bckptr;
> - memcpy(newbck, oldbck, sizeof(int) * amap->am_nslot);
> - memset(newbck + amap->am_nslot, 0, sizeof(int) * slotadded); /* XXX:
> needed? */
> - amap->am_bckptr = newbck;
> -
> -#ifdef UVM_AMAP_PPREF
> - /* do ppref */
> - oldppref = amap->am_ppref;
> - if (newppref) {
> - memcpy(newppref, oldppref, sizeof(int) * amap->am_nslot);
> - memset(newppref + amap->am_nslot, 0, sizeof(int) * slotadded);
> - amap->am_ppref = newppref;
> - if ((slotoff + slotmapped) < amap->am_nslot)
> - amap_pp_adjref(amap, slotoff + slotmapped,
> - (amap->am_nslot - (slotoff + slotmapped)), 1);
> - pp_setreflen(newppref, amap->am_nslot, 1,
> - slotneed - amap->am_nslot);
> - }
> -#endif
> -
> - /* free */
> - if (amap->am_maxslot > UVM_AMAP_CHUNK)
> - free(oldsl, M_UVMAMAP, 0);
> - else
> - pool_put(&uvm_amap_slot_pools[amap->am_maxslot - 1],
> - oldsl);
> -
> - /* and update master values */
> - amap->am_nslot = slotneed;
> - amap->am_maxslot = slotalloc;
> -
> -#ifdef UVM_AMAP_PPREF
> - if (oldppref && oldppref != PPREF_NONE)
> - free(oldppref, M_UVMAMAP, 0);
> -#endif
> - return (0);
> -}
> -
> -/*
> * amap_wipeout: wipeout all anon's in an amap; then free the amap!
> *
> * => called from amap_unref when the final reference to an amap is
> Index: uvm/uvm_amap.h
> ===================================================================
> RCS file: /cvs/src/sys/uvm/uvm_amap.h,v
> retrieving revision 1.21
> diff -u -p -r1.21 uvm_amap.h
> --- uvm/uvm_amap.h 6 Mar 2016 14:47:07 -0000 1.21
> +++ uvm/uvm_amap.h 23 Mar 2016 17:03:53 -0000
> @@ -72,8 +72,6 @@ void amap_copy(vm_map_t, vm_map_entry_t
> vaddr_t);
> /* resolve all COW faults now */
> void amap_cow_now(vm_map_t, vm_map_entry_t);
> - /* make amap larger */
> -int amap_extend(vm_map_entry_t, vsize_t);
> /* get amap's flags */
> int amap_flags(struct vm_amap *);
> /* free amap */
> Index: uvm/uvm_map.c
> ===================================================================
> RCS file: /cvs/src/sys/uvm/uvm_map.c,v
> retrieving revision 1.209
> diff -u -p -r1.209 uvm_map.c
> --- uvm/uvm_map.c 15 Mar 2016 20:50:23 -0000 1.209
> +++ uvm/uvm_map.c 23 Mar 2016 17:03:54 -0000
> @@ -1448,14 +1448,15 @@ uvm_mapent_merge(struct vm_map *map, str
> struct uvm_addr_state *free;
>
> /*
> - * Amap of e1 must be extended to include e2.
> + * Merging is not supported for map entries that
> + * contain an amap in e1. This should never happen
> + * anyway, because only kernel entries are merged.
> + * These do not contain amaps.
> * e2 contains no real information in its amap,
> * so it can be erased immediately.
> */
> - if (e1->aref.ar_amap) {
> - if (amap_extend(e1, e2->end - e2->start))
> - return NULL;
> - }
> + if (e1->aref.ar_amap)
> + return NULL;
>
> /*
> * Don't drop obj reference: