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:
parent
2c083a42ed
commit
4e71e795a1
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user