diff options
author | dillon <dillon@FreeBSD.org> | 2001-02-04 06:19:28 +0000 |
---|---|---|
committer | dillon <dillon@FreeBSD.org> | 2001-02-04 06:19:28 +0000 |
commit | c8a95a285d887ca5e3be08f3c04f4efde25a5bf1 (patch) | |
tree | 9e2c267eac87bf24403df67147f7cc32082387c6 | |
parent | bb46130566593c534d92d1f9327521daa1faa946 (diff) | |
download | FreeBSD-src-c8a95a285d887ca5e3be08f3c04f4efde25a5bf1.zip FreeBSD-src-c8a95a285d887ca5e3be08f3c04f4efde25a5bf1.tar.gz |
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
-rw-r--r-- | sys/amd64/amd64/machdep.c | 1 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 1 | ||||
-rw-r--r-- | sys/kern/vfs_bio.c | 19 | ||||
-rw-r--r-- | sys/vm/vm_map.c | 30 |
4 files changed, 38 insertions, 13 deletions
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index e03d64f..d5c7ece 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -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; diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index e03d64f..d5c7ece 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -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; diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 14ae4a8..a0d693c 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -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) { diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 8cc61b1..471e0af 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -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; |