diff options
author | dyson <dyson@FreeBSD.org> | 1996-08-21 21:56:23 +0000 |
---|---|---|
committer | dyson <dyson@FreeBSD.org> | 1996-08-21 21:56:23 +0000 |
commit | 966cbc5d29e66792108ec7d19f731b46d171245b (patch) | |
tree | 07a76a1b97882ad9c1e3805d05f820bc976c60bd /sys/kern | |
parent | 2d0ae2fc91a319615c14ec10da1161bab780f734 (diff) | |
download | FreeBSD-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.c | 19 | ||||
-rw-r--r-- | sys/kern/vfs_export.c | 113 | ||||
-rw-r--r-- | sys/kern/vfs_subr.c | 113 | ||||
-rw-r--r-- | sys/kern/vfs_vnops.c | 61 |
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); -} |