From a8dc1f52704aa713258258a5479ff5f815b8606f Mon Sep 17 00:00:00 2001 From: attilio Date: Sat, 23 Jun 2012 01:30:51 +0000 Subject: [PATCH] Give vm_radix_lookupn() a way to specify that the whole range has been exhausted while searching and when a "maximum" value is passed as end (or end == 0). This allow for avoiding starting address overflow while searching through and avoids livelock with "start" wrapping up to "end". Reported by: pho (supposedly) --- sys/vm/vm_object.c | 29 ++++++++++++++++++++--------- sys/vm/vm_radix.c | 9 ++++++++- sys/vm/vm_radix.h | 5 +++-- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 4ce02fb02bfb..25d3057497b9 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -679,6 +679,7 @@ vm_object_terminate(vm_object_t object) vm_page_t pa[VM_RADIX_STACK]; vm_page_t p; vm_pindex_t start; + u_int exhausted; int n, i; VM_OBJECT_LOCK_ASSERT(object, MA_OWNED); @@ -725,8 +726,10 @@ vm_object_terminate(vm_object_t object) * the object, the page and object are reset to any empty state. */ start = 0; - while ((n = vm_radix_lookupn(&object->rtree, start, 0, VM_RADIX_ANY, - (void **)pa, VM_RADIX_STACK, &start)) != 0) { + exhausted = 0; + while (exhausted == 0 && (n = vm_radix_lookupn(&object->rtree, start, + 0, VM_RADIX_ANY, (void **)pa, VM_RADIX_STACK, &start, + &exhausted)) != 0) { for (i = 0; i < n; i++) { p = pa[i]; /* @@ -1315,6 +1318,7 @@ vm_object_split(vm_map_entry_t entry) vm_object_t orig_object, new_object, source; vm_pindex_t idx, offidxstart, start; vm_size_t size; + u_int exhausted; int i, n; orig_object = entry->object.vm_object; @@ -1370,9 +1374,10 @@ vm_object_split(vm_map_entry_t entry) } start = offidxstart; retry: - while ((n = vm_radix_lookupn(&orig_object->rtree, start, - offidxstart + size, VM_RADIX_ANY, (void **)ma, VM_RADIX_STACK, - &start)) != 0) { + exhausted = 0; + while (exhausted == 0 && (n = vm_radix_lookupn(&orig_object->rtree, + start, offidxstart + size, VM_RADIX_ANY, (void **)ma, + VM_RADIX_STACK, &start, &exhausted)) != 0) { for (i = 0; i < n; i++) { m = ma[i]; idx = m->pindex - offidxstart; @@ -1457,6 +1462,7 @@ vm_object_backing_scan(vm_object_t object, int op) vm_object_t backing_object; vm_pindex_t backing_offset_index, new_pindex; vm_pindex_t start; + u_int exhausted; int color, i, n; int r = 1; @@ -1495,13 +1501,15 @@ vm_object_backing_scan(vm_object_t object, int op) restart: start = 0; i = n = VM_RADIX_STACK; + exhausted = 0; for (;;) { if (i == n) { if (n < VM_RADIX_STACK) break; - if ((n = vm_radix_lookupn(&backing_object->rtree, + if (exhausted != 0 && + (n = vm_radix_lookupn(&backing_object->rtree, start, 0, color, (void **)pa, VM_RADIX_STACK, - &start)) == 0) + &start, &exhausted)) == 0) break; i = 0; } @@ -1909,6 +1917,7 @@ vm_object_page_remove(vm_object_t object, vm_pindex_t start, vm_pindex_t end, struct vnode *vp; vm_page_t pa[VM_RADIX_STACK]; vm_page_t p; + u_int exhausted; int i, n; int wirings; @@ -1921,8 +1930,10 @@ vm_object_page_remove(vm_object_t object, vm_pindex_t start, vm_pindex_t end, vp = NULL; vm_object_pip_add(object, 1); restart: - while ((n = vm_radix_lookupn(&object->rtree, start, end, VM_RADIX_ANY, - (void **)pa, VM_RADIX_STACK, &start)) != 0) { + exhausted = 0; + while (exhausted == 0 && (n = vm_radix_lookupn(&object->rtree, start, + end, VM_RADIX_ANY, (void **)pa, VM_RADIX_STACK, &start, + &exhausted)) != 0) { for (i = 0; i < n; i++) { p = pa[i]; /* diff --git a/sys/vm/vm_radix.c b/sys/vm/vm_radix.c index 4ec541743879..6d21a8d45e54 100644 --- a/sys/vm/vm_radix.c +++ b/sys/vm/vm_radix.c @@ -726,7 +726,8 @@ vm_radix_leaf(struct vm_radix *rtree, vm_pindex_t *startp, vm_pindex_t end) */ int vm_radix_lookupn(struct vm_radix *rtree, vm_pindex_t start, - vm_pindex_t end, int color, void **out, int cnt, vm_pindex_t *next) + vm_pindex_t end, int color, void **out, int cnt, vm_pindex_t *next, + u_int *exhausted) { struct vm_radix_node *rnode; void *val; @@ -736,6 +737,8 @@ vm_radix_lookupn(struct vm_radix *rtree, vm_pindex_t start, CTR5(KTR_VM, "lookupn: tree %p, " KFRMT64(start) ", " KFRMT64(end), rtree, KSPLT64L(start), KSPLT64H(start), KSPLT64L(end), KSPLT64H(end)); + if (end == 0) + *exhausted = 0; if (rtree->rt_root == 0) return (0); outidx = 0; @@ -760,6 +763,8 @@ vm_radix_lookupn(struct vm_radix *rtree, vm_pindex_t start, */ if ((VM_RADIX_MAXVAL - start) == 0) { start++; + if (end == 0) + *exhausted = 1; goto out; } continue; @@ -771,6 +776,8 @@ vm_radix_lookupn(struct vm_radix *rtree, vm_pindex_t start, if (++outidx == cnt || (VM_RADIX_MAXVAL - start) == 0) { start++; + if (end == 0) + *exhausted = 1; goto out; } } diff --git a/sys/vm/vm_radix.h b/sys/vm/vm_radix.h index 2ec9293b22af..72a77e627f8f 100644 --- a/sys/vm/vm_radix.h +++ b/sys/vm/vm_radix.h @@ -60,7 +60,7 @@ int vm_radix_insert(struct vm_radix *, vm_pindex_t, void *); void *vm_radix_color(struct vm_radix *, vm_pindex_t, int); void *vm_radix_lookup(struct vm_radix *, vm_pindex_t, int); int vm_radix_lookupn(struct vm_radix *, vm_pindex_t, vm_pindex_t, int, - void **, int, vm_pindex_t *); + void **, int, vm_pindex_t *, u_int *); void *vm_radix_lookup_le(struct vm_radix *, vm_pindex_t, int); void vm_radix_reclaim_allnodes(struct vm_radix *); void vm_radix_remove(struct vm_radix *, vm_pindex_t, int); @@ -72,8 +72,9 @@ static inline void * vm_radix_lookup_ge(struct vm_radix *rtree, vm_pindex_t index, int color) { void *val; + u_int dummy; - if (vm_radix_lookupn(rtree, index, 0, color, &val, 1, &index)) + if (vm_radix_lookupn(rtree, index, 0, color, &val, 1, &index, &dummy)) return (val); return (NULL); }