summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authordyson <dyson@FreeBSD.org>1996-08-21 21:56:23 +0000
committerdyson <dyson@FreeBSD.org>1996-08-21 21:56:23 +0000
commit966cbc5d29e66792108ec7d19f731b46d171245b (patch)
tree07a76a1b97882ad9c1e3805d05f820bc976c60bd /sys/kern
parent2d0ae2fc91a319615c14ec10da1161bab780f734 (diff)
downloadFreeBSD-src-966cbc5d29e66792108ec7d19f731b46d171245b.zip
FreeBSD-src-966cbc5d29e66792108ec7d19f731b46d171245b.tar.gz
Even though this looks like it, this is not a complex code change.
The interface into the "VMIO" system has changed to be more consistant and robust. Essentially, it is now no longer necessary to call vn_open to get merged VM/Buffer cache operation, and exceptional conditions such as merged operation of VBLK devices is simpler and more correct. This code corrects a potentially large set of problems including the problems with ktrace output and loaded systems, file create/deletes, etc. Most of the changes to NFS are cosmetic and name changes, eliminating a layer of subroutine calls. The direct calls to vput/vrele have been re-instituted for better cross platform compatibility. Reviewed by: davidg
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/vfs_bio.c19
-rw-r--r--sys/kern/vfs_export.c113
-rw-r--r--sys/kern/vfs_subr.c113
-rw-r--r--sys/kern/vfs_vnops.c61
4 files changed, 228 insertions, 78 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
index 675ecab..b278f6c 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.94 1996/06/30 05:17:08 davidg Exp $
+ * $Id: vfs_bio.c,v 1.95 1996/08/04 20:13:08 phk Exp $
*/
/*
@@ -113,6 +113,9 @@ static struct bqueues bufqueues[BUFFER_QUEUES];
extern int vm_swap_size;
#define BUF_MAXUSE 8
+/*
+#define NO_B_MALLOC
+*/
/*
* Initialize buffer headers and related structures.
@@ -844,7 +847,7 @@ fillbuf:
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 = 2;
+ bp->b_usecount = 4;
if (bufspace >= maxbufspace + nbyteswritten) {
bp->b_flags |= B_INVAL;
brelse(bp);
@@ -1120,12 +1123,15 @@ allocbuf(struct buf * bp, int size)
* Just get anonymous memory from the kernel
*/
mbsize = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
+#if !defined(NO_B_MALLOC)
if (bp->b_flags & B_MALLOC)
newbsize = mbsize;
else
+#endif
newbsize = round_page(size);
if (newbsize < bp->b_bufsize) {
+#if !defined(NO_B_MALLOC)
/*
* malloced buffers are not shrunk
*/
@@ -1143,11 +1149,13 @@ allocbuf(struct buf * bp, int size)
}
return 1;
}
+#endif
vm_hold_free_pages(
bp,
(vm_offset_t) bp->b_data + newbsize,
(vm_offset_t) bp->b_data + bp->b_bufsize);
} else if (newbsize > bp->b_bufsize) {
+#if !defined(NO_B_MALLOC)
/*
* We only use malloced memory on the first allocation.
* and revert to page-allocated memory when the buffer grows.
@@ -1164,8 +1172,10 @@ allocbuf(struct buf * bp, int size)
bufmallocspace += mbsize;
return 1;
}
+#endif
origbuf = NULL;
origbufsize = 0;
+#if !defined(NO_B_MALLOC)
/*
* If the buffer is growing on it's other-than-first allocation,
* then we revert to the page-allocation scheme.
@@ -1180,14 +1190,17 @@ allocbuf(struct buf * bp, int size)
bp->b_flags &= ~B_MALLOC;
newbsize = round_page(newbsize);
}
+#endif
vm_hold_load_pages(
bp,
(vm_offset_t) bp->b_data + bp->b_bufsize,
(vm_offset_t) bp->b_data + newbsize);
+#if !defined(NO_B_MALLOC)
if (origbuf) {
bcopy(origbuf, bp->b_data, origbufsize);
free(origbuf, M_BIOBUF);
}
+#endif
}
} else {
vm_page_t m;
@@ -1196,8 +1209,10 @@ allocbuf(struct buf * bp, int size)
newbsize = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
desiredpages = (round_page(newbsize) >> PAGE_SHIFT);
+#if !defined(NO_B_MALLOC)
if (bp->b_flags & B_MALLOC)
panic("allocbuf: VMIO buffer can't be malloced");
+#endif
if (newbsize < bp->b_bufsize) {
if (desiredpages < bp->b_npages) {
diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c
index af966dd..fbe236d 100644
--- a/sys/kern/vfs_export.c
+++ b/sys/kern/vfs_export.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)vfs_subr.c 8.13 (Berkeley) 4/18/94
- * $Id: vfs_subr.c,v 1.57 1996/07/30 18:00:25 bde Exp $
+ * $Id: vfs_subr.c,v 1.58 1996/08/15 06:45:01 dyson Exp $
*/
/*
@@ -65,6 +65,8 @@
#include <vm/vm_param.h>
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
+#include <vm/vm_pager.h>
+#include <vm/vnode_pager.h>
#include <sys/sysctl.h>
#include <miscfs/specfs/specdev.h>
@@ -477,6 +479,8 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
if (vp->v_dirtyblkhd.lh_first != NULL)
panic("vinvalbuf: dirty bufs");
}
+
+ s = splbio();
for (;;) {
if ((blist = vp->v_cleanblkhd.lh_first) && (flags & V_SAVEMETA))
while (blist && blist->b_lblkno < 0)
@@ -492,7 +496,6 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
nbp = bp->b_vnbufs.le_next;
if ((flags & V_SAVEMETA) && bp->b_lblkno < 0)
continue;
- s = splbio();
if (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
error = tsleep((caddr_t) bp,
@@ -505,7 +508,6 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
}
bremfree(bp);
bp->b_flags |= B_BUSY;
- splx(s);
/*
* XXX Since there are no node locks for NFS, I
* believe there is a slight chance that a delayed
@@ -520,6 +522,7 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
brelse(bp);
}
}
+ splx(s);
s = splbio();
while (vp->v_numoutput > 0) {
@@ -638,7 +641,6 @@ reassignbuf(bp, newvp)
register struct buf *bp;
register struct vnode *newvp;
{
- register struct buflists *listheadp;
int s;
if (newvp == NULL) {
@@ -670,8 +672,7 @@ reassignbuf(bp, newvp)
LIST_INSERT_AFTER(tbp, bp, b_vnbufs);
}
} else {
- listheadp = &newvp->v_cleanblkhd;
- bufinsvn(bp, listheadp);
+ bufinsvn(bp, &newvp->v_cleanblkhd);
}
splx(s);
}
@@ -745,6 +746,7 @@ loop:
goto loop;
break;
}
+
if (vp == NULL || vp->v_tag != VT_NON) {
MALLOC(nvp->v_specinfo, struct specinfo *,
sizeof(struct specinfo), M_VNODE, M_WAITOK);
@@ -804,8 +806,18 @@ vget(vp, lockflag)
freevnodes--;
}
vp->v_usecount++;
+
+ /*
+ * Create the VM object, if needed
+ */
+ if ((vp->v_type == VREG) &&
+ ((vp->v_object == NULL) ||
+ (vp->v_object->flags & OBJ_VFS_REF) == 0)) {
+ vfs_object_create(vp, curproc, curproc->p_ucred, 0);
+ }
if (lockflag)
VOP_LOCK(vp);
+
return (0);
}
@@ -816,9 +828,21 @@ void
vref(vp)
struct vnode *vp;
{
-
if (vp->v_usecount <= 0)
panic("vref used where vget required");
+
+ if ((vp->v_type == VREG) &&
+ ((vp->v_object == NULL) ||
+ ((vp->v_object->flags & OBJ_VFS_REF) == 0)) ) {
+ /*
+ * We need to lock to VP during the time that
+ * the object is created. This is necessary to
+ * keep the system from re-entrantly doing it
+ * multiple times.
+ */
+ vfs_object_create(vp, curproc, curproc->p_ucred, 0);
+ }
+
vp->v_usecount++;
}
@@ -829,7 +853,6 @@ void
vput(vp)
register struct vnode *vp;
{
-
VOP_UNLOCK(vp);
vrele(vp);
}
@@ -847,10 +870,21 @@ vrele(vp)
if (vp == NULL)
panic("vrele: null vp");
#endif
+
vp->v_usecount--;
+
+ if ((vp->v_usecount == 1) &&
+ vp->v_object &&
+ (vp->v_object->flags & OBJ_VFS_REF)) {
+ vp->v_object->flags &= ~OBJ_VFS_REF;
+ vm_object_deallocate(vp->v_object);
+ return;
+ }
+
if (vp->v_usecount > 0)
return;
- if (vp->v_usecount < 0 /* || vp->v_writecount < 0 */ ) {
+
+ if (vp->v_usecount < 0) {
#ifdef DIAGNOSTIC
vprint("vrele: negative ref count", vp);
#endif
@@ -944,6 +978,11 @@ loop:
if ((flags & WRITECLOSE) &&
(vp->v_writecount == 0 || vp->v_type != VREG))
continue;
+
+ if ((vp->v_usecount == 1) && vp->v_object) {
+ pager_cache(vp->v_object, FALSE);
+ }
+
/*
* With v_usecount == 0, all we need to do is clear out the
* vnode data structures and we are done.
@@ -1546,8 +1585,62 @@ loop:
if (VOP_ISLOCKED(vp) && (flags != MNT_WAIT))
continue;
if (vp->v_object &&
- (((vm_object_t) vp->v_object)->flags & OBJ_MIGHTBEDIRTY)) {
+ (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
vm_object_page_clean(vp->v_object, 0, 0, TRUE, TRUE);
}
}
}
+
+/*
+ * Create the VM object needed for VMIO and mmap support. This
+ * is done for all VREG files in the system. Some filesystems might
+ * afford the additional metadata buffering capability of the
+ * VMIO code by making the device node be VMIO mode also.
+ */
+int
+vfs_object_create(vp, p, cred, waslocked)
+ struct vnode *vp;
+ struct proc *p;
+ struct ucred *cred;
+ int waslocked;
+{
+ struct vattr vat;
+ vm_object_t object;
+ int error = 0;
+
+retry:
+ if ((object = vp->v_object) == NULL) {
+ if (vp->v_type == VREG) {
+ if ((error = VOP_GETATTR(vp, &vat, cred, p)) != 0)
+ goto retn;
+ (void) vnode_pager_alloc(vp,
+ OFF_TO_IDX(round_page(vat.va_size)), 0, 0);
+ } else {
+ /*
+ * This simply allocates the biggest object possible
+ * for a VBLK vnode. This should be fixed, but doesn't
+ * cause any problems (yet).
+ */
+ (void) vnode_pager_alloc(vp, INT_MAX, 0, 0);
+ }
+ vp->v_object->flags |= OBJ_VFS_REF;
+ } else {
+ if (object->flags & OBJ_DEAD) {
+ if (waslocked)
+ VOP_UNLOCK(vp);
+ tsleep(object, PVM, "vodead", 0);
+ if (waslocked)
+ VOP_LOCK(vp);
+ goto retry;
+ }
+ if ((object->flags & OBJ_VFS_REF) == 0) {
+ object->flags |= OBJ_VFS_REF;
+ vm_object_reference(object);
+ }
+ }
+ if (vp->v_object)
+ vp->v_flag |= VVMIO;
+
+retn:
+ return error;
+}
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index af966dd..fbe236d 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)vfs_subr.c 8.13 (Berkeley) 4/18/94
- * $Id: vfs_subr.c,v 1.57 1996/07/30 18:00:25 bde Exp $
+ * $Id: vfs_subr.c,v 1.58 1996/08/15 06:45:01 dyson Exp $
*/
/*
@@ -65,6 +65,8 @@
#include <vm/vm_param.h>
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
+#include <vm/vm_pager.h>
+#include <vm/vnode_pager.h>
#include <sys/sysctl.h>
#include <miscfs/specfs/specdev.h>
@@ -477,6 +479,8 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
if (vp->v_dirtyblkhd.lh_first != NULL)
panic("vinvalbuf: dirty bufs");
}
+
+ s = splbio();
for (;;) {
if ((blist = vp->v_cleanblkhd.lh_first) && (flags & V_SAVEMETA))
while (blist && blist->b_lblkno < 0)
@@ -492,7 +496,6 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
nbp = bp->b_vnbufs.le_next;
if ((flags & V_SAVEMETA) && bp->b_lblkno < 0)
continue;
- s = splbio();
if (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
error = tsleep((caddr_t) bp,
@@ -505,7 +508,6 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
}
bremfree(bp);
bp->b_flags |= B_BUSY;
- splx(s);
/*
* XXX Since there are no node locks for NFS, I
* believe there is a slight chance that a delayed
@@ -520,6 +522,7 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
brelse(bp);
}
}
+ splx(s);
s = splbio();
while (vp->v_numoutput > 0) {
@@ -638,7 +641,6 @@ reassignbuf(bp, newvp)
register struct buf *bp;
register struct vnode *newvp;
{
- register struct buflists *listheadp;
int s;
if (newvp == NULL) {
@@ -670,8 +672,7 @@ reassignbuf(bp, newvp)
LIST_INSERT_AFTER(tbp, bp, b_vnbufs);
}
} else {
- listheadp = &newvp->v_cleanblkhd;
- bufinsvn(bp, listheadp);
+ bufinsvn(bp, &newvp->v_cleanblkhd);
}
splx(s);
}
@@ -745,6 +746,7 @@ loop:
goto loop;
break;
}
+
if (vp == NULL || vp->v_tag != VT_NON) {
MALLOC(nvp->v_specinfo, struct specinfo *,
sizeof(struct specinfo), M_VNODE, M_WAITOK);
@@ -804,8 +806,18 @@ vget(vp, lockflag)
freevnodes--;
}
vp->v_usecount++;
+
+ /*
+ * Create the VM object, if needed
+ */
+ if ((vp->v_type == VREG) &&
+ ((vp->v_object == NULL) ||
+ (vp->v_object->flags & OBJ_VFS_REF) == 0)) {
+ vfs_object_create(vp, curproc, curproc->p_ucred, 0);
+ }
if (lockflag)
VOP_LOCK(vp);
+
return (0);
}
@@ -816,9 +828,21 @@ void
vref(vp)
struct vnode *vp;
{
-
if (vp->v_usecount <= 0)
panic("vref used where vget required");
+
+ if ((vp->v_type == VREG) &&
+ ((vp->v_object == NULL) ||
+ ((vp->v_object->flags & OBJ_VFS_REF) == 0)) ) {
+ /*
+ * We need to lock to VP during the time that
+ * the object is created. This is necessary to
+ * keep the system from re-entrantly doing it
+ * multiple times.
+ */
+ vfs_object_create(vp, curproc, curproc->p_ucred, 0);
+ }
+
vp->v_usecount++;
}
@@ -829,7 +853,6 @@ void
vput(vp)
register struct vnode *vp;
{
-
VOP_UNLOCK(vp);
vrele(vp);
}
@@ -847,10 +870,21 @@ vrele(vp)
if (vp == NULL)
panic("vrele: null vp");
#endif
+
vp->v_usecount--;
+
+ if ((vp->v_usecount == 1) &&
+ vp->v_object &&
+ (vp->v_object->flags & OBJ_VFS_REF)) {
+ vp->v_object->flags &= ~OBJ_VFS_REF;
+ vm_object_deallocate(vp->v_object);
+ return;
+ }
+
if (vp->v_usecount > 0)
return;
- if (vp->v_usecount < 0 /* || vp->v_writecount < 0 */ ) {
+
+ if (vp->v_usecount < 0) {
#ifdef DIAGNOSTIC
vprint("vrele: negative ref count", vp);
#endif
@@ -944,6 +978,11 @@ loop:
if ((flags & WRITECLOSE) &&
(vp->v_writecount == 0 || vp->v_type != VREG))
continue;
+
+ if ((vp->v_usecount == 1) && vp->v_object) {
+ pager_cache(vp->v_object, FALSE);
+ }
+
/*
* With v_usecount == 0, all we need to do is clear out the
* vnode data structures and we are done.
@@ -1546,8 +1585,62 @@ loop:
if (VOP_ISLOCKED(vp) && (flags != MNT_WAIT))
continue;
if (vp->v_object &&
- (((vm_object_t) vp->v_object)->flags & OBJ_MIGHTBEDIRTY)) {
+ (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
vm_object_page_clean(vp->v_object, 0, 0, TRUE, TRUE);
}
}
}
+
+/*
+ * Create the VM object needed for VMIO and mmap support. This
+ * is done for all VREG files in the system. Some filesystems might
+ * afford the additional metadata buffering capability of the
+ * VMIO code by making the device node be VMIO mode also.
+ */
+int
+vfs_object_create(vp, p, cred, waslocked)
+ struct vnode *vp;
+ struct proc *p;
+ struct ucred *cred;
+ int waslocked;
+{
+ struct vattr vat;
+ vm_object_t object;
+ int error = 0;
+
+retry:
+ if ((object = vp->v_object) == NULL) {
+ if (vp->v_type == VREG) {
+ if ((error = VOP_GETATTR(vp, &vat, cred, p)) != 0)
+ goto retn;
+ (void) vnode_pager_alloc(vp,
+ OFF_TO_IDX(round_page(vat.va_size)), 0, 0);
+ } else {
+ /*
+ * This simply allocates the biggest object possible
+ * for a VBLK vnode. This should be fixed, but doesn't
+ * cause any problems (yet).
+ */
+ (void) vnode_pager_alloc(vp, INT_MAX, 0, 0);
+ }
+ vp->v_object->flags |= OBJ_VFS_REF;
+ } else {
+ if (object->flags & OBJ_DEAD) {
+ if (waslocked)
+ VOP_UNLOCK(vp);
+ tsleep(object, PVM, "vodead", 0);
+ if (waslocked)
+ VOP_LOCK(vp);
+ goto retry;
+ }
+ if ((object->flags & OBJ_VFS_REF) == 0) {
+ object->flags |= OBJ_VFS_REF;
+ vm_object_reference(object);
+ }
+ }
+ if (vp->v_object)
+ vp->v_flag |= VVMIO;
+
+retn:
+ return error;
+}
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 2817da1..abc85c4 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)vfs_vnops.c 8.2 (Berkeley) 1/21/94
- * $Id: vfs_vnops.c,v 1.24 1996/03/02 03:45:05 dyson Exp $
+ * $Id: vfs_vnops.c,v 1.25 1996/03/09 06:42:15 dyson Exp $
*/
#include <sys/param.h>
@@ -162,12 +162,13 @@ vn_open(ndp, fmode, cmode)
if (error)
goto bad;
/*
- * this is here for VMIO support
+ * Make sure that a VM object is created for VMIO support.
*/
if (vp->v_type == VREG) {
- if ((error = vn_vmio_open(vp, p, cred)) != 0)
+ if ((error = vfs_object_create(vp, p, cred, 1)) != 0)
goto bad;
}
+
if (fmode & FWRITE)
vp->v_writecount++;
return (0);
@@ -211,7 +212,7 @@ vn_close(vp, flags, cred, p)
if (flags & FWRITE)
vp->v_writecount--;
error = VOP_CLOSE(vp, flags, cred, p);
- vn_vmio_close(vp);
+ vrele(vp);
return (error);
}
@@ -462,55 +463,3 @@ vn_closefile(fp, p)
return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
fp->f_cred, p));
}
-
-int
-vn_vmio_open(vp, p, cred)
- struct vnode *vp;
- struct proc *p;
- struct ucred *cred;
-{
- struct vattr vat;
- int error;
- /*
- * this is here for VMIO support
- */
- if (vp->v_type == VREG || vp->v_type == VBLK) {
-retry:
- if ((vp->v_flag & VVMIO) == 0) {
- if ((error = VOP_GETATTR(vp, &vat, cred, p)) != 0)
- return error;
- (void) vnode_pager_alloc(vp, OFF_TO_IDX(round_page(vat.va_size)), 0, 0);
- vp->v_flag |= VVMIO;
- } else {
- vm_object_t object;
- if ((object = vp->v_object) &&
- (object->flags & OBJ_DEAD)) {
- VOP_UNLOCK(vp);
- tsleep(object, PVM, "vodead", 0);
- VOP_LOCK(vp);
- goto retry;
- }
- if (!object)
- panic("vn_open: VMIO object missing");
- vm_object_reference(object);
- }
- }
- return 0;
-}
-
-void
-vn_vmio_close(vp)
- struct vnode *vp;
-{
- /*
- * this code is here for VMIO support, will eventually
- * be in vfs code.
- */
- if (vp->v_flag & VVMIO) {
- vrele(vp);
- if (vp->v_object == NULL)
- panic("vn_close: VMIO object missing");
- vm_object_deallocate(vp->v_object);
- } else
- vrele(vp);
-}
OpenPOWER on IntegriCloud