Subject: re: GCC3.3.1 switch coming soon.
To: matthew green <mrg@eterna.com.au>
From: enami tsugutomo <enami@but-b.or.jp>
List: port-sparc64
Date: 09/01/2003 22:09:29
> i've seen the reports about topdown VM but i have not investigated
> them. someone who uses that option should, i have enough other
> things on my plate right now.
It isn't compiler matter since the kernel built by 2.95.3 as well. It
is actually a bug in topdown vm code. It incorrectly re-uses space
already in-use under some condition which began to met recently.
Attached is a change I'm currently playing with. It includes a fix
among other cleanups.
enami.
Index: uvm_map.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_map.c,v
retrieving revision 1.137
diff -c -r1.137 uvm_map.c
*** uvm_map.c 26 Aug 2003 15:12:18 -0000 1.137
--- uvm_map.c 1 Sep 2003 07:54:05 -0000
***************
*** 199,204 ****
--- 199,206 ----
static void uvm_map_entry_unwire __P((struct vm_map *, struct vm_map_entry *));
static void uvm_map_reference_amap __P((struct vm_map_entry *, int));
static void uvm_map_unreference_amap __P((struct vm_map_entry *, int));
+ static int uvm_map_space_avail __P((vaddr_t *, vsize_t, voff_t, vsize_t, int,
+ struct vm_map_entry *));
/*
* local inlines
***************
*** 1010,1016 ****
*/
last = &map->header;
! if ((cur != last) && (cur->end > address)) {
UVMCNT_INCR(uvm_mlk_hint);
*entry = cur;
UVMHIST_LOG(maphist,"<- got it via hint (0x%x)",
--- 1012,1019 ----
*/
last = &map->header;
! if (cur->end > address) {
! KASSERT(cur != last);
UVMCNT_INCR(uvm_mlk_hint);
*entry = cur;
UVMHIST_LOG(maphist,"<- got it via hint (0x%x)",
***************
*** 1056,1061 ****
--- 1059,1117 ----
}
/*
+ * See if the range between start and start + length fits in the gap
+ * entry->next->start and entry->end. Returns 1 if fits, 0 if doesn't
+ * fit, and -1 address wraps around.
+ */
+ static __inline int
+ uvm_map_space_avail(start, length, uoffset, align, topdown, entry)
+ vaddr_t *start;
+ vsize_t length;
+ voff_t uoffset;
+ vsize_t align;
+ int topdown;
+ struct vm_map_entry *entry;
+ {
+ vaddr_t end;
+
+ #ifdef PMAP_PREFER
+ /*
+ * push start address forward as needed to avoid VAC alias problems.
+ * we only do this if a valid offset is specified.
+ */
+
+ if (uoffset != UVM_UNKNOWN_OFFSET)
+ PMAP_PREFER(uoffset, start);
+ #endif
+ if (align != 0) {
+ if ((*start & (align - 1)) != 0) {
+ if (topdown)
+ *start &= ~(align - 1);
+ else
+ *start = roundup(*start, align);
+ }
+ /*
+ * XXX Should we PMAP_PREFER() here again?
+ */
+ }
+
+ /*
+ * Find the end of the proposed new region. Be sure we didn't
+ * wrap around the address; if so, we lose. Otherwise, if the
+ * proposed new region fits before the next entry, we win.
+ */
+
+ end = *start + length;
+ if (end < *start)
+ return (-1);
+
+ if (entry->next->start >= end && *start >= entry->end)
+ return (1);
+
+ return (0);
+ }
+
+ /*
* uvm_map_findspace: find "length" sized space in "map".
*
* => "hint" is a hint about where we want it, unless FINDSPACE_FIXED is
***************
*** 1079,1092 ****
vsize_t align;
int flags;
{
! struct vm_map_entry *entry, *next, *tmp;
! vaddr_t end, orig_hint;
const int topdown = map->flags & VM_MAP_TOPDOWN;
UVMHIST_FUNC("uvm_map_findspace");
UVMHIST_CALLED(maphist);
UVMHIST_LOG(maphist, "(map=0x%x, hint=0x%x, len=%d, flags=0x%x)",
! map, hint, length, flags);
KASSERT((align & (align - 1)) == 0);
KASSERT((flags & UVM_FLAG_FIXED) == 0 || align == 0);
--- 1135,1148 ----
vsize_t align;
int flags;
{
! struct vm_map_entry *entry;
! vaddr_t orig_hint;
const int topdown = map->flags & VM_MAP_TOPDOWN;
UVMHIST_FUNC("uvm_map_findspace");
UVMHIST_CALLED(maphist);
UVMHIST_LOG(maphist, "(map=0x%x, hint=0x%x, len=%d, flags=0x%x)",
! map, hint, length, flags);
KASSERT((align & (align - 1)) == 0);
KASSERT((flags & UVM_FLAG_FIXED) == 0 || align == 0);
***************
*** 1100,1113 ****
if (hint < map->min_offset) { /* check ranges ... */
if (flags & UVM_FLAG_FIXED) {
UVMHIST_LOG(maphist,"<- VA below map range",0,0,0,0);
! return(NULL);
}
hint = map->min_offset;
}
if (hint > map->max_offset) {
UVMHIST_LOG(maphist,"<- VA 0x%x > range [0x%x->0x%x]",
! hint, map->min_offset, map->max_offset, 0);
! return(NULL);
}
/*
--- 1156,1169 ----
if (hint < map->min_offset) { /* check ranges ... */
if (flags & UVM_FLAG_FIXED) {
UVMHIST_LOG(maphist,"<- VA below map range",0,0,0,0);
! return (NULL);
}
hint = map->min_offset;
}
if (hint > map->max_offset) {
UVMHIST_LOG(maphist,"<- VA 0x%x > range [0x%x->0x%x]",
! hint, map->min_offset, map->max_offset, 0);
! return (NULL);
}
/*
***************
*** 1120,1131 ****
*
* 0: found, fixed, bottom up -> fail
* 1: found, fixed, top down -> fail
! * 2: found, not fixed, bottom up -> start after tmp->end, loop up
! * 3: found, not fixed, top down -> start before tmp->start, loop down
! * 4: not found, fixed, bottom up -> check tmp->next->start, fail
! * 5: not found, fixed, top down -> check tmp->next->start, fail
! * 6: not found, not fixed, bottom up -> check tmp->next->start, loop up
! * 7: not found, not fixed, top down -> check tmp->next->start, loop down
*
* as you can see, it reduces to roughly five cases, and that
* adding top down mapping only adds one unique case (without
--- 1176,1191 ----
*
* 0: found, fixed, bottom up -> fail
* 1: found, fixed, top down -> fail
! * 2: found, not fixed, bottom up -> start after entry->end,
! * loop up
! * 3: found, not fixed, top down -> start before entry->start,
! * loop down
! * 4: not found, fixed, bottom up -> check entry->next->start, fail
! * 5: not found, fixed, top down -> check entry->next->start, fail
! * 6: not found, not fixed, bottom up -> check entry->next->start,
! * loop up
! * 7: not found, not fixed, top down -> check entry->next->start,
! * loop down
*
* as you can see, it reduces to roughly five cases, and that
* adding top down mapping only adds one unique case (without
***************
*** 1133,1229 ****
*/
if ((flags & UVM_FLAG_FIXED) == 0 && hint == map->min_offset) {
! if ((entry = map->first_free) != &map->header)
! hint = entry->end;
} else {
! if (uvm_map_lookup_entry(map, hint, &tmp)) {
/* "hint" address already in use ... */
if (flags & UVM_FLAG_FIXED) {
! UVMHIST_LOG(maphist,"<- fixed & VA in use",
0, 0, 0, 0);
! return(NULL);
}
! hint = topdown ? tmp->start - length : tmp->end;
! } else if ((tmp->next == &map->header ||
! tmp->next->start >= hint + length)) {
! entry = tmp;
! goto quickfind;
}
- entry = tmp;
}
/*
* Look through the rest of the map, trying to fit a new region in
* the gap between existing regions, or after the very last region.
! * note: entry->end = base VA of current gap,
! * next->start = VA of end of current gap
*/
! for (next = NULL;; hint = topdown ?
! (entry = next)->start - length :
! (entry = next)->end) {
!
! /*
! * Find the end of the proposed new region. Be sure we didn't
! * go beyond the end of the map, or wrap around the address;
! * if so, we lose. Otherwise, if this is the last entry, or
! * if the proposed new region fits before the next entry, we
! * win.
! */
!
! #ifdef PMAP_PREFER
! /*
! * push hint forward as needed to avoid VAC alias problems.
! * we only do this if a valid offset is specified.
! */
!
! if ((flags & UVM_FLAG_FIXED) == 0 &&
! uoffset != UVM_UNKNOWN_OFFSET)
! PMAP_PREFER(uoffset, &hint);
! #endif
! if (align != 0) {
! if ((hint & (align - 1)) != 0) {
! if (topdown)
! hint &= ~(align-1);
! else
! hint = roundup(hint, align);
}
! /*
! * XXX Should we PMAP_PREFER() here again?
! */
! }
! end = hint + length;
! if (end > map->max_offset || end < hint) {
! UVMHIST_LOG(maphist,"<- failed (off end)", 0,0,0,0);
! if (align != 0) {
! UVMHIST_LOG(maphist,
! "calling recursively, no align",
0,0,0,0);
! return (uvm_map_findspace(map, orig_hint,
! length, result, uobj, uoffset, 0, flags));
}
- return (NULL);
- }
- if (!topdown || next == NULL) {
- next = entry->next;
- } else
- next = entry->prev;
- if (next == &map->header ||
- (!topdown && next->start >= end) ||
- ( topdown && next->end <= hint))
- break;
- if (flags & UVM_FLAG_FIXED) {
- UVMHIST_LOG(maphist,"<- fixed mapping failed", 0,0,0,0);
- return(NULL); /* only one shot at it ... */
}
}
! quickfind:
SAVE_HINT(map, map->hint, entry);
- if (topdown && entry->start >= hint + length)
- entry = entry->prev;
*result = hint;
UVMHIST_LOG(maphist,"<- got it! (result=0x%x)", hint, 0,0,0);
return (entry);
}
/*
--- 1193,1301 ----
*/
if ((flags & UVM_FLAG_FIXED) == 0 && hint == map->min_offset) {
! entry = map->first_free;
} else {
! if (uvm_map_lookup_entry(map, hint, &entry)) {
/* "hint" address already in use ... */
if (flags & UVM_FLAG_FIXED) {
! UVMHIST_LOG(maphist, "<- fixed & VA in use",
0, 0, 0, 0);
! return (NULL);
! }
! if (topdown)
! /* Start from lower gap. */
! entry = entry->prev;
! } else if (flags & UVM_FLAG_FIXED) {
! if (entry->next->start >= hint + length &&
! hint + length > hint)
! goto found;
!
! /* "hint" address is gap but too small */
! UVMHIST_LOG(maphist, "<- fixed mapping failed",
! 0, 0, 0, 0);
! return (NULL); /* only one shot at it ... */
! } else {
! /*
! * See if given hint fits in this gap.
! */
! switch (uvm_map_space_avail(&hint, length,
! uoffset, align, topdown, entry)) {
! case 1:
! goto found;
! case -1:
! goto wraparound;
}
!
! if (topdown)
! /*
! * Still there is a chance to fit
! * if hint > entry->end.
! */
! ;
! else
! goto nextgap;
}
}
/*
* Look through the rest of the map, trying to fit a new region in
* the gap between existing regions, or after the very last region.
! * note: entry->end = base VA of current gap,
! * entry->next->start = VA of end of current gap
! *
! * Also note that all UVM_FLAGS_FIXED case is already handled.
*/
+ KDASSERT((flags & UVM_FLAG_FIXED) == 0);
! for (;;) {
! /* Update hint for current gap. */
! hint = topdown ? entry->next->start - length : entry->end;
!
! /* See if it fits. */
! switch (uvm_map_space_avail(&hint, length, uoffset, align,
! topdown, entry)) {
! case 1:
! goto found;
! case -1:
! goto wraparound;
! }
!
! /* Advance to next/previous gap */
! if (topdown) {
! if (entry == &map->header) {
! UVMHIST_LOG(maphist, "<- failed (off start)",
! 0,0,0,0);
! goto notfound;
}
! entry = entry->prev;
! } else {
! nextgap:
! entry = entry->next;
! if (entry == &map->header) {
! UVMHIST_LOG(maphist, "<- failed (off end)",
0,0,0,0);
! goto notfound;
}
}
}
!
! found:
SAVE_HINT(map, map->hint, entry);
*result = hint;
UVMHIST_LOG(maphist,"<- got it! (result=0x%x)", hint, 0,0,0);
return (entry);
+
+ wraparound:
+ UVMHIST_LOG(maphist, "<- failed (wrap around)", 0,0,0,0);
+
+ notfound:
+ if (align != 0) {
+ UVMHIST_LOG(maphist, "calling recursively, no align",
+ 0,0,0,0);
+ return (uvm_map_findspace(map, orig_hint,
+ length, result, uobj, uoffset, 0, flags));
+ }
+ return (NULL);
}
/*
***************
*** 1299,1305 ****
* up with a mapping to a page on the free list which would be very bad)
*/
! while ((entry != &map->header) && (entry->start < end)) {
UVM_MAP_CLIP_END(map, entry, end);
next = entry->next;
len = entry->end - entry->start;
--- 1371,1378 ----
* up with a mapping to a page on the free list which would be very bad)
*/
! while (entry->start < end) {
! KASSERT(entry != &map->header);
UVM_MAP_CLIP_END(map, entry, end);
next = entry->next;
len = entry->end - entry->start;
***************
*** 1730,1736 ****
* as we go.
*/
! while (entry->start < end && entry != &srcmap->header) {
/* if we are not doing a quick reference, clip it */
if ((flags & UVM_EXTRACT_QREF) == 0)
--- 1803,1810 ----
* as we go.
*/
! while (entry->start < end) {
! KASSERT(entry != &srcmap->header);
/* if we are not doing a quick reference, clip it */
if ((flags & UVM_EXTRACT_QREF) == 0)
***************
*** 1809,1819 ****
}
/* end of 'while' loop! */
! if ((flags & UVM_EXTRACT_CONTIG) && entry->end < end &&
! (entry->next == &srcmap->header ||
! entry->next->start != entry->end)) {
! error = EINVAL;
! goto bad;
}
entry = entry->next;
fudge = 0;
--- 1883,1894 ----
}
/* end of 'while' loop! */
! if ((flags & UVM_EXTRACT_CONTIG) && entry->end < end) {
! if (entry->next->start != entry->end) {
! error = EINVAL;
! goto bad;
! } else
! KASSERT(entry->next != &srcmap->header);
}
entry = entry->next;
fudge = 0;
***************
*** 1867,1873 ****
fudge = orig_fudge;
deadentry = NULL; /* for UVM_EXTRACT_REMOVE */
! while (entry->start < end && entry != &srcmap->header) {
if (copy_ok) {
oldoffset = (entry->start + fudge) - start;
elen = MIN(end, entry->end) -
--- 1942,1949 ----
fudge = orig_fudge;
deadentry = NULL; /* for UVM_EXTRACT_REMOVE */
! while (entry->start < end) {
! KASSERT(entry != &srcmap->header);
if (copy_ok) {
oldoffset = (entry->start + fudge) - start;
elen = MIN(end, entry->end) -
***************
*** 2035,2041 ****
*/
current = entry;
! while ((current != &map->header) && (current->start < end)) {
if (UVM_ET_ISSUBMAP(current)) {
error = EINVAL;
goto out;
--- 2111,2118 ----
*/
current = entry;
! while (current->start < end) {
! KASSERT(current != &map->header);
if (UVM_ET_ISSUBMAP(current)) {
error = EINVAL;
goto out;
***************
*** 2066,2074 ****
/* go back and fix up protections (no need to clip this time). */
current = entry;
! while ((current != &map->header) && (current->start < end)) {
vm_prot_t old_prot;
UVM_MAP_CLIP_END(map, current, end);
old_prot = current->protection;
if (set_max)
--- 2143,2152 ----
/* go back and fix up protections (no need to clip this time). */
current = entry;
! while (current->start < end) {
vm_prot_t old_prot;
+ KASSERT(current != &map->header);
UVM_MAP_CLIP_END(map, current, end);
old_prot = current->protection;
if (set_max)
***************
*** 2183,2189 ****
} else {
entry = temp_entry->next;
}
! while ((entry != &map->header) && (entry->start < end)) {
UVM_MAP_CLIP_END(map, entry, end);
entry->inheritance = new_inheritance;
entry = entry->next;
--- 2261,2268 ----
} else {
entry = temp_entry->next;
}
! while (entry->start < end) {
! KASSERT(entry != &map->header);
UVM_MAP_CLIP_END(map, entry, end);
entry->inheritance = new_inheritance;
entry = entry->next;
***************
*** 2224,2230 ****
* XXXJRT: disallow holes?
*/
! while ((entry != &map->header) && (entry->start < end)) {
UVM_MAP_CLIP_END(map, entry, end);
switch (new_advice) {
--- 2303,2310 ----
* XXXJRT: disallow holes?
*/
! while (entry->start < end) {
! KASSERT(entry != &map->header);
UVM_MAP_CLIP_END(map, entry, end);
switch (new_advice) {
***************
*** 2312,2327 ****
* really wired down and that there are no holes.
*/
! while ((entry != &map->header) && (entry->start < end)) {
if (entry->wired_count == 0 ||
(entry->end < end &&
! (entry->next == &map->header ||
! entry->next->start > entry->end))) {
if ((lockflags & UVM_LK_EXIT) == 0)
vm_map_unlock(map);
UVMHIST_LOG(maphist, "<- done (INVAL)",0,0,0,0);
return EINVAL;
! }
entry = entry->next;
}
--- 2392,2410 ----
* really wired down and that there are no holes.
*/
! while (entry->start < end) {
! KASSERT(entry != &map->header);
if (entry->wired_count == 0 ||
(entry->end < end &&
! entry->next->start > entry->end)) {
if ((lockflags & UVM_LK_EXIT) == 0)
vm_map_unlock(map);
UVMHIST_LOG(maphist, "<- done (INVAL)",0,0,0,0);
return EINVAL;
! } else
! KASSERT(entry->wired_count == 0 ||
! entry->end >= end ||
! entry->next != &map->header);
entry = entry->next;
}
***************
*** 2332,2338 ****
*/
entry = start_entry;
! while ((entry != &map->header) && (entry->start < end)) {
UVM_MAP_CLIP_END(map, entry, end);
if (VM_MAPENT_ISWIRED(entry))
uvm_map_entry_unwire(map, entry);
--- 2415,2422 ----
*/
entry = start_entry;
! while (entry->start < end) {
! KASSERT(entry != &map->header);
UVM_MAP_CLIP_END(map, entry, end);
if (VM_MAPENT_ISWIRED(entry))
uvm_map_entry_unwire(map, entry);
***************
*** 2365,2371 ****
* entries we modify here cannot change.
*/
! while ((entry != &map->header) && (entry->start < end)) {
if (VM_MAPENT_ISWIRED(entry) == 0) { /* not already wired? */
/*
--- 2449,2456 ----
* entries we modify here cannot change.
*/
! while (entry->start < end) {
! KASSERT(entry != &map->header);
if (VM_MAPENT_ISWIRED(entry) == 0) { /* not already wired? */
/*
***************
*** 2395,2410 ****
*/
if (entry->protection == VM_PROT_NONE ||
! (entry->end < end &&
! (entry->next == &map->header ||
! entry->next->start > entry->end))) {
/*
* found one. amap creation actions do not need to
* be undone, but the wired counts need to be restored.
*/
! while (entry != &map->header && entry->end > start) {
entry->wired_count--;
entry = entry->prev;
}
--- 2480,2494 ----
*/
if (entry->protection == VM_PROT_NONE ||
! (entry->end < end && entry->next->start > entry->end)) {
/*
* found one. amap creation actions do not need to
* be undone, but the wired counts need to be restored.
*/
! while (entry->end > start) {
! KASSERT(entry != &map->header);
entry->wired_count--;
entry = entry->prev;
}
***************
*** 2428,2434 ****
rv = 0;
entry = start_entry;
! while (entry != &map->header && entry->start < end) {
if (entry->wired_count == 1) {
rv = uvm_fault_wire(map, entry->start, entry->end,
VM_FAULT_WIREMAX, entry->max_protection);
--- 2512,2519 ----
rv = 0;
entry = start_entry;
! while (entry->start < end) {
! KASSERT(entry != &map->header);
if (entry->wired_count == 1) {
rv = uvm_fault_wire(map, entry->start, entry->end,
VM_FAULT_WIREMAX, entry->max_protection);
***************
*** 2466,2472 ****
*/
failed_entry = entry;
! while (entry != &map->header && entry->start < end) {
entry->wired_count--;
entry = entry->next;
}
--- 2551,2558 ----
*/
failed_entry = entry;
! while (entry->start < end) {
! KASSERT(entry != &map->header);
entry->wired_count--;
entry = entry->next;
}
Index: uvm_map.h
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_map.h,v
retrieving revision 1.34
diff -c -r1.34 uvm_map.h
*** uvm_map.h 20 Feb 2003 22:16:08 -0000 1.34
--- uvm_map.h 28 Aug 2003 02:18:08 -0000
***************
*** 219,226 ****
int flags; /* flags */
struct simplelock flags_lock; /* Lock for flags field */
unsigned int timestamp; /* Version number */
! #define min_offset header.start
! #define max_offset header.end
};
/* vm_map flags */
--- 219,226 ----
int flags; /* flags */
struct simplelock flags_lock; /* Lock for flags field */
unsigned int timestamp; /* Version number */
! #define min_offset header.end
! #define max_offset header.start
};
/* vm_map flags */
Index: uvm_mmap.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.77
diff -c -r1.77 uvm_mmap.c
*** uvm_mmap.c 24 Aug 2003 18:12:25 -0000 1.77
--- uvm_mmap.c 28 Aug 2003 13:56:58 -0000
***************
*** 184,194 ****
KASSERT(start >= entry->start);
/* Make sure there are no holes. */
! if (entry->end < end &&
! (entry->next == &map->header ||
! entry->next->start > entry->end)) {
! error = ENOMEM;
! goto out;
}
lim = end < entry->end ? end : entry->end;
--- 184,195 ----
KASSERT(start >= entry->start);
/* Make sure there are no holes. */
! if (entry->end < end) {
! if (entry->next->start > entry->end) {
! error = ENOMEM;
! goto out;
! } else
! KASSERT(entry->next != &map->header);
}
lim = end < entry->end ? end : entry->end;