summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authordyson <dyson@FreeBSD.org>1996-11-30 22:41:49 +0000
committerdyson <dyson@FreeBSD.org>1996-11-30 22:41:49 +0000
commit7a58275f33a773bf61557817714efe27f3611aaf (patch)
treec2414524de2607538eaf1294e5d9ee92fc65c8d6 /sys/kern
parent7c59df49d939e5f564cc78e9a17c7d2393e11420 (diff)
downloadFreeBSD-src-7a58275f33a773bf61557817714efe27f3611aaf.zip
FreeBSD-src-7a58275f33a773bf61557817714efe27f3611aaf.tar.gz
Implement a new totally dynamic (up to MAXPHYS) buffer kva allocation
scheme. Additionally, add the capability for checking for unexpected kernel page faults. The maximum amount of kva space for buffers hasn't been decreased from where it is, but it will now be possible to do so. This scheme manages the kva space similar to the buffers themselves. If there isn't enough kva space because of usage or fragementation, buffers will be reclaimed until a buffer allocation is successful. This scheme should be very resistant to fragmentation problems until/if the LFS code is fixed and uses the bogus buffer locking scheme -- but a 'fixed' LFS is not likely to use such a scheme. Now there should be NO problem allocating buffers up to MAXPHYS.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/vfs_bio.c100
-rw-r--r--sys/kern/vfs_cluster.c10
2 files changed, 89 insertions, 21 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index 3e6e6f9..a653395 100644
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -18,7 +18,7 @@
* 5. Modifications may be freely made to this file if the above conditions
* are met.
*
- * $Id: vfs_bio.c,v 1.105 1996/11/17 02:10:48 dyson Exp $
+ * $Id: vfs_bio.c,v 1.106 1996/11/28 04:26:04 dyson Exp $
*/
/*
@@ -51,6 +51,8 @@
#include <vm/vm_page.h>
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
+#include <vm/lock.h>
+#include <vm/vm_map.h>
#include <sys/buf.h>
#include <sys/mount.h>
#include <sys/malloc.h>
@@ -92,7 +94,6 @@ int vfs_update_wakeup;
/*
* buffers base kva
*/
-caddr_t buffers_kva;
/*
* bogus page -- for I/O to/from partially complete buffers
@@ -134,7 +135,6 @@ bufinit()
for (i = 0; i < BUFFER_QUEUES; i++)
TAILQ_INIT(&bufqueues[i]);
- buffers_kva = (caddr_t) kmem_alloc_pageable(buffer_map, MAXBSIZE * nbuf);
/* finally, initialize each buffer header and stick on empty q */
for (i = 0; i < nbuf; i++) {
bp = &buf[i];
@@ -145,7 +145,6 @@ bufinit()
bp->b_wcred = NOCRED;
bp->b_qindex = QUEUE_EMPTY;
bp->b_vnbufs.le_next = NOLIST;
- bp->b_data = buffers_kva + i * MAXBSIZE;
TAILQ_INSERT_TAIL(&bufqueues[QUEUE_EMPTY], bp, b_freelist);
LIST_INSERT_HEAD(&invalhash, bp, b_hash);
}
@@ -177,6 +176,25 @@ bufinit()
}
/*
+ * Free the kva allocation for a buffer
+ * Must be called only at splbio or higher,
+ * as this is the only locking for buffer_map.
+ */
+static void
+bfreekva(struct buf * bp)
+{
+ if (bp->b_kvasize == 0)
+ return;
+
+ vm_map_delete(buffer_map,
+ (vm_offset_t) bp->b_kvabase,
+ (vm_offset_t) bp->b_kvabase + bp->b_kvasize);
+
+ bp->b_kvasize = 0;
+
+}
+
+/*
* remove the buffer from the appropriate free list
*/
void
@@ -562,6 +580,10 @@ brelse(struct buf * bp)
LIST_REMOVE(bp, b_hash);
LIST_INSERT_HEAD(&invalhash, bp, b_hash);
bp->b_dev = NODEV;
+ /*
+ * Get rid of the kva allocation *now*
+ */
+ bfreekva(bp);
if (needsbuffer) {
wakeup(&needsbuffer);
needsbuffer=0;
@@ -724,7 +746,7 @@ vfs_vmio_release(bp)
/*
* Check to see if a block is currently memory resident.
*/
-__inline struct buf *
+struct buf *
gbincore(struct vnode * vp, daddr_t blkno)
{
struct buf *bp;
@@ -812,10 +834,11 @@ vfs_bio_awrite(struct buf * bp)
* Find a buffer header which is available for use.
*/
static struct buf *
-getnewbuf(int slpflag, int slptimeo, int doingvmio)
+getnewbuf(int slpflag, int slptimeo, int size, int maxsize)
{
struct buf *bp;
int nbyteswritten = 0;
+ vm_offset_t addr;
start:
if (bufspace >= maxbufspace)
@@ -926,15 +949,43 @@ fillbuf:
bp->b_resid = 0;
bp->b_bcount = 0;
bp->b_npages = 0;
- bp->b_data = buffers_kva + (bp - buf) * MAXBSIZE;
bp->b_dirtyoff = bp->b_dirtyend = 0;
bp->b_validoff = bp->b_validend = 0;
bp->b_usecount = 4;
- if (bufspace >= maxbufspace + nbyteswritten) {
+
+ maxsize = (maxsize + PAGE_MASK) & ~PAGE_MASK;
+ bfreekva(bp);
+
+ /*
+ * See if we have buffer kva space
+ */
+ if (vm_map_findspace(buffer_map, 0, maxsize, &addr)) {
bp->b_flags |= B_INVAL;
brelse(bp);
goto trytofreespace;
}
+
+ /*
+ * See if we are below are allocated minimum
+ */
+ if (bufspace >= (maxbufspace + nbyteswritten)) {
+ bp->b_flags |= B_INVAL;
+ brelse(bp);
+ goto trytofreespace;
+ }
+
+ /*
+ * create a map entry for the buffer -- in essence
+ * reserving the kva space.
+ */
+ vm_map_insert(buffer_map, NULL, 0,
+ addr, addr + maxsize,
+ VM_PROT_ALL, VM_PROT_ALL, MAP_NOFAULT);
+
+ bp->b_data = (caddr_t) addr;
+ bp->b_kvabase = (caddr_t) addr;
+ bp->b_kvasize = maxsize;
+
return (bp);
}
@@ -1057,6 +1108,18 @@ getblk(struct vnode * vp, daddr_t blkno, int size, int slpflag, int slptimeo)
struct buf *bp;
int s;
struct bufhashhdr *bh;
+ int maxsize;
+
+ if (vp->v_mount) {
+ maxsize = vp->v_mount->mnt_stat.f_iosize;
+ /*
+ * This happens on mount points.
+ */
+ if (maxsize < size)
+ maxsize = size;
+ } else {
+ maxsize = size;
+ }
if (size > MAXBSIZE)
panic("getblk: size(%d) > MAXBSIZE(%d)\n", size, MAXBSIZE);
@@ -1086,7 +1149,7 @@ loop:
*/
if (bp->b_bcount != size) {
- if (bp->b_flags & B_VMIO) {
+ if ((bp->b_flags & B_VMIO) && (size <= bp->b_kvasize)) {
allocbuf(bp, size);
} else {
bp->b_flags |= B_NOCACHE;
@@ -1101,14 +1164,8 @@ loop:
return (bp);
} else {
vm_object_t obj;
- int doingvmio;
- if ((obj = vp->v_object) && (vp->v_flag & VVMIO)) {
- doingvmio = 1;
- } else {
- doingvmio = 0;
- }
- if ((bp = getnewbuf(slpflag, slptimeo, doingvmio)) == 0) {
+ if ((bp = getnewbuf(slpflag, slptimeo, size, maxsize)) == 0) {
if (slpflag || slptimeo) {
splx(s);
return NULL;
@@ -1138,7 +1195,7 @@ loop:
bh = BUFHASH(vp, blkno);
LIST_INSERT_HEAD(bh, bp, b_hash);
- if (doingvmio) {
+ if ((obj = vp->v_object) && (vp->v_flag & VVMIO)) {
bp->b_flags |= (B_VMIO | B_CACHE);
#if defined(VFS_BIO_DEBUG)
if (vp->v_type != VREG && vp->v_type != VBLK)
@@ -1171,7 +1228,7 @@ geteblk(int size)
int s;
s = splbio();
- while ((bp = getnewbuf(0, 0, 0)) == 0);
+ while ((bp = getnewbuf(0, 0, size, MAXBSIZE)) == 0);
splx(s);
allocbuf(bp, size);
bp->b_flags |= B_INVAL;
@@ -1201,6 +1258,9 @@ allocbuf(struct buf * bp, int size)
if (!(bp->b_flags & B_BUSY))
panic("allocbuf: buffer not busy");
+ if (bp->b_kvasize < size)
+ panic("allocbuf: buffer too small");
+
if ((bp->b_flags & B_VMIO) == 0) {
caddr_t origbuf;
int origbufsize;
@@ -1227,7 +1287,7 @@ allocbuf(struct buf * bp, int size)
free(bp->b_data, M_BIOBUF);
bufspace -= bp->b_bufsize;
bufmallocspace -= bp->b_bufsize;
- bp->b_data = (caddr_t) buffers_kva + (bp - buf) * MAXBSIZE;
+ bp->b_data = bp->b_kvabase;
bp->b_bufsize = 0;
bp->b_bcount = 0;
bp->b_flags &= ~B_MALLOC;
@@ -1268,7 +1328,7 @@ allocbuf(struct buf * bp, int size)
if (bp->b_flags & B_MALLOC) {
origbuf = bp->b_data;
origbufsize = bp->b_bufsize;
- bp->b_data = (caddr_t) buffers_kva + (bp - buf) * MAXBSIZE;
+ bp->b_data = bp->b_kvabase;
bufspace -= bp->b_bufsize;
bufmallocspace -= bp->b_bufsize;
bp->b_bufsize = 0;
diff --git a/sys/kern/vfs_cluster.c b/sys/kern/vfs_cluster.c
index 386d981..d45663a 100644
--- a/sys/kern/vfs_cluster.c
+++ b/sys/kern/vfs_cluster.c
@@ -33,7 +33,7 @@
* SUCH DAMAGE.
*
* @(#)vfs_cluster.c 8.7 (Berkeley) 2/13/94
- * $Id: vfs_cluster.c,v 1.37 1996/07/27 18:49:18 dyson Exp $
+ * $Id: vfs_cluster.c,v 1.38 1996/10/06 07:50:04 dyson Exp $
*/
#include <sys/param.h>
@@ -385,6 +385,10 @@ cluster_rbuild(vp, filesize, lbn, blkno, size, run)
VM_PAGE_BITS_ALL)
bp->b_pages[j] = bogus_page;
}
+ if (bp->b_bufsize > bp->b_kvasize)
+ panic("cluster_rbuild: b_bufsize(%d) > b_kvasize(%d)\n",
+ bp->b_bufsize, bp->b_kvasize);
+ bp->b_kvasize = bp->b_bufsize;
pmap_qenter(trunc_page((vm_offset_t) bp->b_data),
(vm_page_t *)bp->b_pages, bp->b_npages);
@@ -690,6 +694,10 @@ cluster_wbuild(vp, size, start_lbn, len)
}
pmap_qenter(trunc_page((vm_offset_t) bp->b_data),
(vm_page_t *) bp->b_pages, bp->b_npages);
+ if (bp->b_bufsize > bp->b_kvasize)
+ panic("cluster_wbuild: b_bufsize(%d) > b_kvasize(%d)\n",
+ bp->b_bufsize, bp->b_kvasize);
+ bp->b_kvasize = bp->b_bufsize;
totalwritten += bp->b_bufsize;
bp->b_dirtyoff = 0;
bp->b_dirtyend = bp->b_bufsize;
OpenPOWER on IntegriCloud