This commit represents work mainly submitted by Tor and slightly modified

by myself.  It solves a serious vm_map corruption problem that can occur
with the buffer cache when block sizes > 64K are used.  This code has been
heavily tested in -stable but only tested somewhat on -current.  An MFC
will occur in a few days.  My additions include the vm_map_simplify_entry()
and minor buffer cache boundry case fix.

Make the buffer cache use a system map for buffer cache KVM rather then a
normal map.

Ensure that VM objects are not allocated for system maps.  There were cases
where a buffer map could wind up with a backing VM object -- normally
harmless, but this could also result in the buffer cache blocking in places
where it assumes no blocking will occur, possibly resulting in corrupted
maps.

Fix a minor boundry case in the buffer cache size limit is reached that
could result in non-optimal code.

Add vm_map_simplify_entry() calls to prevent 'creeping proliferation'
of vm_map_entry's in the buffer cache's vm_map.  Previously only a simple
linear optimization was made.  (The buffer vm_map typically has only a
handful of vm_map_entry's.  This stabilizes it at that level permanently).

PR: 20609
Submitted by: (Tor Egge) tegge
This commit is contained in:
Matthew Dillon 2001-02-04 06:19:28 +00:00
parent 2c083a42ed
commit 4e71e795a1
4 changed files with 38 additions and 13 deletions

View File

@ -398,6 +398,7 @@ again:
(nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size);
buffer_map = kmem_suballoc(clean_map, &buffer_sva, &buffer_eva,
(nbuf*BKVASIZE));
buffer_map->system_map = 1;
pager_map = kmem_suballoc(clean_map, &pager_sva, &pager_eva,
(nswbuf*MAXPHYS) + pager_map_size);
pager_map->system_map = 1;

View File

@ -398,6 +398,7 @@ again:
(nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size);
buffer_map = kmem_suballoc(clean_map, &buffer_sva, &buffer_eva,
(nbuf*BKVASIZE));
buffer_map->system_map = 1;
pager_map = kmem_suballoc(clean_map, &pager_sva, &pager_eva,
(nswbuf*MAXPHYS) + pager_map_size);
pager_map->system_map = 1;

View File

@ -1235,9 +1235,8 @@ brelse(struct buf * bp)
bufcountwakeup();
/*
* Something we can maybe free.
* Something we can maybe free or reuse
*/
if (bp->b_bufsize || bp->b_kvasize)
bufspacewakeup();
@ -1304,7 +1303,7 @@ bqrelse(struct buf * bp)
}
/*
* Something we can maybe wakeup
* Something we can maybe free or reuse.
*/
if (bp->b_bufsize && !(bp->b_flags & B_DELWRI))
bufspacewakeup();
@ -1551,10 +1550,13 @@ restart:
}
/*
* Nada. If we are allowed to allocate an EMPTY
* buffer, go get one.
* If we could not find or were not allowed to reuse a
* CLEAN buffer, check to see if it is ok to use an EMPTY
* buffer. We can only use an EMPTY buffer if allocating
* its KVA would not otherwise run us out of buffer space.
*/
if (nbp == NULL && defrag == 0 && bufspace < hibufspace) {
if (nbp == NULL && defrag == 0 &&
bufspace + maxsize < hibufspace) {
nqindex = QUEUE_EMPTY;
nbp = TAILQ_FIRST(&bufqueues[QUEUE_EMPTY]);
}
@ -1686,6 +1688,11 @@ restart:
goto restart;
}
/*
* If we are overcomitted then recover the buffer and its
* KVM space. This occurs in rare situations when multiple
* processes are blocked in getnewbuf() or allocbuf().
*/
if (bufspace >= hibufspace)
flushingbufs = 1;
if (flushingbufs && bp->b_kvasize != 0) {

View File

@ -508,6 +508,7 @@ vm_map_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
(prev_entry->max_protection == max)) {
map->size += (end - prev_entry->end);
prev_entry->end = end;
vm_map_simplify_entry(map, prev_entry);
return (KERN_SUCCESS);
}
@ -515,7 +516,7 @@ vm_map_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
* If we can extend the object but cannot extend the
* map entry, we have to create a new map entry. We
* must bump the ref count on the extended object to
* account for it.
* account for it. object may be NULL.
*/
object = prev_entry->object.vm_object;
offset = prev_entry->offset +
@ -562,6 +563,11 @@ vm_map_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
map->first_free = new_entry;
}
/*
* It may be possible to simplify the entry
*/
vm_map_simplify_entry(map, new_entry);
if (cow & (MAP_PREFAULT|MAP_PREFAULT_PARTIAL)) {
pmap_object_init_pt(map->pmap, start,
object, OFF_TO_IDX(offset), end - start,
@ -681,7 +687,14 @@ vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
/*
* vm_map_simplify_entry:
*
* Simplify the given map entry by merging with either neighbor.
* Simplify the given map entry by merging with either neighbor. This
* routine also has the ability to merge with both neighbors.
*
* The map must be locked.
*
* This routine guarentees that the passed entry remains valid (though
* possibly extended). When merging, this routine may delete one or
* both neighbors.
*/
void
vm_map_simplify_entry(map, entry)
@ -784,7 +797,7 @@ _vm_map_clip_start(map, entry, start)
* put this improvement.
*/
if (entry->object.vm_object == NULL) {
if (entry->object.vm_object == NULL && !map->system_map) {
vm_object_t object;
object = vm_object_allocate(OBJT_DEFAULT,
atop(entry->end - entry->start));
@ -840,7 +853,7 @@ _vm_map_clip_end(map, entry, end)
* put this improvement.
*/
if (entry->object.vm_object == NULL) {
if (entry->object.vm_object == NULL && !map->system_map) {
vm_object_t object;
object = vm_object_allocate(OBJT_DEFAULT,
atop(entry->end - entry->start));
@ -1295,7 +1308,8 @@ vm_map_user_pageable(map, start, end, new_pageable)
atop(entry->end - entry->start));
entry->eflags &= ~MAP_ENTRY_NEEDS_COPY;
} else if (entry->object.vm_object == NULL) {
} else if (entry->object.vm_object == NULL &&
!map->system_map) {
entry->object.vm_object =
vm_object_allocate(OBJT_DEFAULT,
@ -1485,7 +1499,8 @@ vm_map_pageable(map, start, end, new_pageable)
&entry->offset,
atop(entry->end - entry->start));
entry->eflags &= ~MAP_ENTRY_NEEDS_COPY;
} else if (entry->object.vm_object == NULL) {
} else if (entry->object.vm_object == NULL &&
!map->system_map) {
entry->object.vm_object =
vm_object_allocate(OBJT_DEFAULT,
atop(entry->end - entry->start));
@ -2614,7 +2629,8 @@ RetryLookup:;
/*
* Create an object if necessary.
*/
if (entry->object.vm_object == NULL) {
if (entry->object.vm_object == NULL &&
!map->system_map) {
if (vm_map_lock_upgrade(map))
goto RetryLookup;