1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-11 14:10:34 +00:00

Stuff object into v_vmdata rather than pager. Not important which at

the moment, but will be in the future. Other changes mostly cosmetic,
but are made for future VMIO considerations.

Submitted by:	John Dyson
This commit is contained in:
David Greenman 1994-10-05 09:48:45 +00:00
parent 5cedf6806b
commit 8e58bf6875
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=3374
13 changed files with 209 additions and 127 deletions

View File

@ -16,7 +16,7 @@
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
* $Id: vfs_bio.c,v 1.12 1994/09/25 19:33:51 phk Exp $
* $Id: vfs_bio.c,v 1.13 1994/10/04 03:10:47 davidg Exp $
*/
#include <sys/param.h>
@ -60,6 +60,7 @@ bufinit()
{
struct buf *bp;
int i;
caddr_t baddr;
TAILQ_INIT(&bswlist);
LIST_INIT(&invalhash);
@ -72,6 +73,7 @@ bufinit()
for(i=0;i<BUFFER_QUEUES;i++)
TAILQ_INIT(&bufqueues[i]);
baddr = (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];
@ -83,7 +85,7 @@ bufinit()
bp->b_wcred = NOCRED;
bp->b_qindex = QUEUE_EMPTY;
bp->b_vnbufs.le_next = NOLIST;
bp->b_data = (caddr_t)kmem_alloc_pageable(buffer_map, MAXBSIZE);
bp->b_data = baddr + i * MAXBSIZE;
TAILQ_INSERT_TAIL(&bufqueues[QUEUE_EMPTY], bp, b_freelist);
LIST_INSERT_HEAD(&invalhash, bp, b_hash);
}
@ -446,11 +448,13 @@ incore(struct vnode *vp, daddr_t blkno)
/* Search hash chain */
while (bp) {
#ifdef DEBUG
if( (bp < buf) || (bp >= buf + nbuf)) {
printf("incore: buf out of range: %p, hash: %d\n",
bp, bh - bufhashtbl);
panic("incore: buf fault");
}
#endif
/* hit */
if (bp->b_lblkno == blkno && bp->b_vp == vp
&& (bp->b_flags & B_INVAL) == 0) {
@ -494,25 +498,14 @@ getblk(struct vnode *vp, daddr_t blkno, int size, int slpflag, int slptimeo)
goto loop;
}
} else {
if ((bp = getnewbuf(0, 0)) == 0)
goto loop;
allocbuf(bp, size);
/*
* have to check again, because of a possible
* race condition.
*/
if (incore( vp, blkno)) {
allocbuf(bp, 0);
bp->b_flags |= B_INVAL;
brelse(bp);
goto loop;
}
bp->b_blkno = bp->b_lblkno = blkno;
bgetvp(vp, bp);
LIST_REMOVE(bp, b_hash);
bh = BUFHASH(vp, blkno);
LIST_INSERT_HEAD(bh, bp, b_hash);
allocbuf(bp, size);
}
splx(s);
return (bp);
@ -664,11 +657,13 @@ vfs_update() {
}
}
#if 0
#define MAXFREEBP 128
#define LDFREE_BUSY 1
#define LDFREE_WANT 2
int loadfreeing;
struct buf *freebp[MAXFREEBP];
#endif
/*
* these routines are not in the correct place (yet)
* also they work *ONLY* for kernel_pmap!!!

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)vfs_subr.c 8.13 (Berkeley) 4/18/94
* $Id: vfs_subr.c,v 1.9 1994/09/25 19:33:52 phk Exp $
* $Id: vfs_subr.c,v 1.10 1994/10/02 17:35:38 phk Exp $
*/
/*
@ -491,7 +491,10 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
}
}
pager = (vm_pager_t)vp->v_vmdata;
pager = NULL;
object = (vm_object_t)vp->v_vmdata;
if( object != NULL)
pager = object->pager;
if (pager != NULL) {
object = vm_object_lookup(pager);
if (object) {

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94
* $Id: vfs_syscalls.c,v 1.9 1994/09/28 16:45:11 dfr Exp $
* $Id: vfs_syscalls.c,v 1.10 1994/10/02 17:35:39 phk Exp $
*/
#include <sys/param.h>
@ -2224,6 +2224,8 @@ revoke(p, uap, retval)
if (p->p_ucred->cr_uid != vattr.va_uid &&
(error = suser(p->p_ucred, &p->p_acflag)))
goto out;
if( vp->v_vmdata)
vnode_pager_uncache( vp);
if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
vgoneall(vp);
out:

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)vfs_subr.c 8.13 (Berkeley) 4/18/94
* $Id: vfs_subr.c,v 1.9 1994/09/25 19:33:52 phk Exp $
* $Id: vfs_subr.c,v 1.10 1994/10/02 17:35:38 phk Exp $
*/
/*
@ -491,7 +491,10 @@ vinvalbuf(vp, flags, cred, p, slpflag, slptimeo)
}
}
pager = (vm_pager_t)vp->v_vmdata;
pager = NULL;
object = (vm_object_t)vp->v_vmdata;
if( object != NULL)
pager = object->pager;
if (pager != NULL) {
object = vm_object_lookup(pager);
if (object) {

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94
* $Id: vfs_syscalls.c,v 1.9 1994/09/28 16:45:11 dfr Exp $
* $Id: vfs_syscalls.c,v 1.10 1994/10/02 17:35:39 phk Exp $
*/
#include <sys/param.h>
@ -2224,6 +2224,8 @@ revoke(p, uap, retval)
if (p->p_ucred->cr_uid != vattr.va_uid &&
(error = suser(p->p_ucred, &p->p_acflag)))
goto out;
if( vp->v_vmdata)
vnode_pager_uncache( vp);
if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
vgoneall(vp);
out:

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)vfs_vnops.c 8.2 (Berkeley) 1/21/94
* $Id: vfs_vnops.c,v 1.4 1994/08/18 03:53:38 davidg Exp $
* $Id: vfs_vnops.c,v 1.5 1994/10/02 17:35:40 phk Exp $
*/
#include <sys/param.h>
@ -152,6 +152,30 @@ vn_open(ndp, fmode, cmode)
goto bad;
if (fmode & FWRITE)
vp->v_writecount++;
/*
* this is here for VMIO support
*/
if( vp->v_type == VREG) {
vm_object_t object;
vm_pager_t pager;
if( (vp->v_flag & VVMIO) == 0) {
pager = (vm_pager_t) vnode_pager_alloc(vp, 0, 0, 0);
object = (vm_object_t) vp->v_vmdata;
if( object->pager != pager)
panic("ufs_open: pager/object mismatch");
(void) vm_object_lookup( pager);
pager_cache( object, TRUE);
vp->v_flag |= VVMIO;
} else {
object = (vm_object_t) vp->v_vmdata;
if( !object)
panic("ufs_open: VMIO object missing");
pager = object->pager;
if( !pager)
panic("ufs_open: VMIO pager missing");
(void) vm_object_lookup( pager);
}
}
return (0);
bad:
vput(vp);
@ -206,6 +230,15 @@ vn_close(vp, flags, cred, p)
if (flags & FWRITE)
vp->v_writecount--;
error = VOP_CLOSE(vp, flags, cred, p);
/*
* this code is here for VMIO support, will eventually
* be in vfs code.
*/
if (vp->v_flag & VVMIO) {
if( vp->v_vmdata == NULL)
panic("ufs_close: VMIO object missing");
vm_object_deallocate( (vm_object_t) vp->v_vmdata);
}
vrele(vp);
return (error);
}

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)buf.h 8.7 (Berkeley) 1/21/94
* $Id: buf.h,v 1.6 1994/08/18 22:35:40 wollman Exp $
* $Id: buf.h,v 1.7 1994/09/25 19:33:59 phk Exp $
*/
#ifndef _SYS_BUF_H_
@ -82,7 +82,12 @@ struct buf {
void *b_driver1; /* for private use by the driver */
void *b_driver2; /* for private use by the driver */
void *b_spc;
#ifndef VMIO
void *b_pages[(MAXBSIZE + PAGE_SIZE - 1)/PAGE_SIZE];
#else
vm_page_t b_pages[(MAXBSIZE + PAGE_SIZE - 1)/PAGE_SIZE];
#endif
int b_npages;
};
/* Device driver compatibility definitions. */
@ -122,6 +127,7 @@ struct buf {
#define B_WRITE 0x00000000 /* Write buffer (pseudo flag). */
#define B_WRITEINPROG 0x01000000 /* Write in progress. */
#define B_XXX 0x02000000 /* Debugging flag. */
#define B_VMIO 0x20000000 /* VMIO flag */
#define B_CLUSTER 0x40000000 /* pagein op, so swap() can count it */
#define B_BOUNCE 0x80000000 /* bounce buffer flag */

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)buf.h 8.7 (Berkeley) 1/21/94
* $Id: buf.h,v 1.6 1994/08/18 22:35:40 wollman Exp $
* $Id: buf.h,v 1.7 1994/09/25 19:33:59 phk Exp $
*/
#ifndef _SYS_BUF_H_
@ -82,7 +82,12 @@ struct buf {
void *b_driver1; /* for private use by the driver */
void *b_driver2; /* for private use by the driver */
void *b_spc;
#ifndef VMIO
void *b_pages[(MAXBSIZE + PAGE_SIZE - 1)/PAGE_SIZE];
#else
vm_page_t b_pages[(MAXBSIZE + PAGE_SIZE - 1)/PAGE_SIZE];
#endif
int b_npages;
};
/* Device driver compatibility definitions. */
@ -122,6 +127,7 @@ struct buf {
#define B_WRITE 0x00000000 /* Write buffer (pseudo flag). */
#define B_WRITEINPROG 0x01000000 /* Write in progress. */
#define B_XXX 0x02000000 /* Debugging flag. */
#define B_VMIO 0x20000000 /* VMIO flag */
#define B_CLUSTER 0x40000000 /* pagein op, so swap() can count it */
#define B_BOUNCE 0x80000000 /* bounce buffer flag */

View File

@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)vnode.h 8.7 (Berkeley) 2/4/94
* $Id: vnode.h,v 1.9 1994/09/25 19:34:02 phk Exp $
* $Id: vnode.h,v 1.10 1994/10/02 17:25:04 phk Exp $
*/
#ifndef _SYS_VNODE_H_
@ -115,6 +115,7 @@ struct vnode {
#define VBWAIT 0x0400 /* waiting for output to complete */
#define VALIASED 0x0800 /* vnode has an alias */
#define VDIROP 0x1000 /* LFS: vnode is involved in a directory op */
#define VVMIO 0x2000 /* VMIO flag */
/*
* Vnode attributes. A field value of VNOVAL represents a field whose value

View File

@ -66,7 +66,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: vm_fault.c,v 1.3 1994/08/02 07:55:18 davidg Exp $
* $Id: vm_fault.c,v 1.4 1994/08/06 09:15:37 davidg Exp $
*/
/*
@ -266,11 +266,11 @@ vm_fault(map, vaddr, fault_type, change_wiring)
* If the page is being brought in,
* wait for it and then retry.
*/
if (m->flags & PG_BUSY) {
if (m->flags & (PG_BUSY|PG_VMIO)) {
int s;
UNLOCK_THINGS;
s = splhigh();
if (m->flags & PG_BUSY) {
if (m->flags & (PG_BUSY|PG_VMIO)) {
m->flags |= PG_WANTED;
tsleep((caddr_t)m,PSWP,"vmpfw",0);
}
@ -643,7 +643,7 @@ vm_fault(map, vaddr, fault_type, change_wiring)
- copy_object->shadow_offset;
copy_m = vm_page_lookup(copy_object, copy_offset);
if (page_exists = (copy_m != NULL)) {
if (copy_m->flags & PG_BUSY) {
if (copy_m->flags & (PG_BUSY|PG_VMIO)) {
/*
* If the page is being brought
* in, wait for it and then retry.

View File

@ -61,7 +61,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: vm_object.c,v 1.5 1994/08/18 22:36:06 wollman Exp $
* $Id: vm_object.c,v 1.6 1994/08/27 16:14:39 davidg Exp $
*/
/*
@ -657,7 +657,7 @@ vm_object_cache_trim()
vm_object_cache_unlock();
if (object != vm_object_lookup(object->pager))
panic("vm_object_deactivate: I'm sooo confused.");
panic("vm_object_cache_trim: I'm sooo confused.");
pager_cache(object, FALSE);

View File

@ -61,7 +61,7 @@
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*
* $Id: vm_page.h,v 1.5 1994/09/06 11:28:44 davidg Exp $
* $Id: vm_page.h,v 1.6 1994/09/27 18:00:29 davidg Exp $
*/
/*
@ -134,6 +134,7 @@ struct vm_page {
#define PG_FILLED 0x0400 /* client flag to set when filled */
#define PG_DIRTY 0x0800 /* client flag to set when dirty */
#define PG_REFERENCED 0x1000 /* page has been referenced */
#define PG_VMIO 0x2000 /* VMIO flag */
#define PG_PAGEROWNED 0x4000 /* DEBUG: async paging op in progress */
#define PG_FREE 0x8000 /* page is in free list */

View File

@ -37,7 +37,7 @@
* SUCH DAMAGE.
*
* from: @(#)vnode_pager.c 7.5 (Berkeley) 4/20/91
* $Id: vnode_pager.c,v 1.7 1994/08/29 06:23:19 davidg Exp $
* $Id: vnode_pager.c,v 1.8 1994/09/06 17:53:24 davidg Exp $
*/
/*
@ -150,7 +150,10 @@ vnode_pager_alloc(handle, size, prot, offset)
* with vm_pager_lookup.
*/
vp = (struct vnode *) handle;
pager = (vm_pager_t) vp->v_vmdata;
object = (vm_object_t) vp->v_vmdata;
pager = NULL;
if( object != NULL)
pager = object->pager;
if (pager == NULL) {
/*
@ -191,14 +194,14 @@ vnode_pager_alloc(handle, size, prot, offset)
pager->pg_type = PG_VNODE;
pager->pg_ops = &vnodepagerops;
pager->pg_data = (caddr_t) vnp;
vp->v_vmdata = (caddr_t) pager;
vp->v_vmdata = (caddr_t) object;
} else {
/*
* vm_object_lookup() will remove the object from the cache if
* found and also gain a reference to the object.
*/
object = vm_object_lookup(pager);
(void) vm_object_lookup(pager);
}
return (pager);
}
@ -213,11 +216,7 @@ vnode_pager_dealloc(pager)
if (vp = vnp->vnp_vp) {
vp->v_vmdata = NULL;
vp->v_flag &= ~VTEXT;
#if 0
/* can hang if done at reboot on NFS FS */
(void) VOP_FSYNC(vp, p->p_ucred, p);
#endif
vp->v_flag &= ~(VTEXT|VVMIO);
vrele(vp);
}
TAILQ_REMOVE(&vnode_pager_list, pager, pg_list);
@ -308,6 +307,10 @@ vnode_pager_haspage(pager, offset)
err = VOP_BMAP(vnp->vnp_vp,
offset / vnp->vnp_vp->v_mount->mnt_stat.f_iosize,
(struct vnode **) 0, &bn, 0);
/*
printf("vnode_pager_haspage: (%d)0x%x: err: %d, bn: %d\n",
offset, offset, err, bn);
*/
if (err) {
return (TRUE);
}
@ -341,7 +344,11 @@ vnode_pager_setsize(vp, nsize)
/*
* Hasn't changed size
*/
pager = (vm_pager_t) vp->v_vmdata;
object = (vm_object_t) vp->v_vmdata;
if( object == NULL)
return;
if( (pager = object->pager) == NULL)
return;
vnp = (vn_pager_t) pager->pg_data;
if (nsize == vnp->vnp_size)
return;
@ -446,7 +453,10 @@ vnode_pager_uncache(vp)
/*
* Not a mapped vnode
*/
pager = (vm_pager_t) vp->v_vmdata;
object = (vm_object_t) vp->v_vmdata;
if( object == NULL)
return(TRUE);
pager = object->pager;
if (pager == NULL)
return (TRUE);
@ -829,6 +839,9 @@ vnode_pager_input(vnp, m, count, reqpage)
*/
#ifdef NOTYET
if( (vp->v_flag & VVMIO) == 0) {
#endif
/*
* This pathetic hack gets data from the buffer cache, if it's there.
* I believe that this is not really necessary, and the ends can be
@ -838,89 +851,92 @@ vnode_pager_input(vnp, m, count, reqpage)
* and keep from flushing it by reading in a program.
*/
/*
* calculate logical block and offset
*/
block = foff / bsize;
offset = foff % bsize;
s = splbio();
/*
* if we have a buffer in core, then try to use it
*/
while (bp = incore(vp, block)) {
int amount;
/*
* calculate logical block and offset
*/
block = foff / bsize;
offset = foff % bsize;
s = splbio();
/*
* wait until the buffer is avail or gone
* if we have a buffer in core, then try to use it
*/
if (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
tsleep((caddr_t) bp, PVM, "vnwblk", 0);
continue;
}
amount = PAGE_SIZE;
if ((foff + amount) > vnp->vnp_size)
amount = vnp->vnp_size - foff;
/*
* make sure that this page is in the buffer
*/
if ((amount > 0) && (offset + amount) <= bp->b_bcount) {
bp->b_flags |= B_BUSY;
splx(s);
kva = kmem_alloc_pageable( pager_map, PAGE_SIZE);
while (bp = incore(vp, block)) {
int amount;
/*
* map the requested page
* wait until the buffer is avail or gone
*/
pmap_qenter(kva, &m[reqpage], 1);
/*
* copy the data from the buffer
*/
bcopy(bp->b_un.b_addr + offset, (caddr_t) kva, amount);
if (amount < PAGE_SIZE) {
bzero((caddr_t) kva + amount, PAGE_SIZE - amount);
if (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
tsleep((caddr_t) bp, PVM, "vnwblk", 0);
continue;
}
amount = PAGE_SIZE;
if ((foff + amount) > vnp->vnp_size)
amount = vnp->vnp_size - foff;
/*
* unmap the page and free the kva
* make sure that this page is in the buffer
*/
pmap_qremove( kva, 1);
kmem_free_wakeup(pager_map, kva, PAGE_SIZE);
if ((amount > 0) && (offset + amount) <= bp->b_bcount) {
bp->b_flags |= B_BUSY;
splx(s);
kva = kmem_alloc_wait( pager_map, PAGE_SIZE);
/*
* release the buffer back to the block subsystem
*/
bp->b_flags &= ~B_BUSY;
wakeup((caddr_t) bp);
/*
* map the requested page
*/
pmap_qenter(kva, &m[reqpage], 1);
/*
* we did not have to do any work to get the requested
* page, the read behind/ahead does not justify a read
*/
for (i = 0; i < count; i++) {
if (i != reqpage) {
vnode_pager_freepage(m[i]);
/*
* copy the data from the buffer
*/
bcopy(bp->b_un.b_addr + offset, (caddr_t) kva, amount);
if (amount < PAGE_SIZE) {
bzero((caddr_t) kva + amount, PAGE_SIZE - amount);
}
/*
* unmap the page and free the kva
*/
pmap_qremove( kva, 1);
kmem_free_wakeup(pager_map, kva, PAGE_SIZE);
/*
* release the buffer back to the block subsystem
*/
bp->b_flags &= ~B_BUSY;
wakeup((caddr_t) bp);
/*
* we did not have to do any work to get the requested
* page, the read behind/ahead does not justify a read
*/
for (i = 0; i < count; i++) {
if (i != reqpage) {
vnode_pager_freepage(m[i]);
}
}
count = 1;
reqpage = 0;
m[0] = m[reqpage];
/*
* sorry for the goto
*/
goto finishup;
}
count = 1;
reqpage = 0;
m[0] = m[reqpage];
/*
* sorry for the goto
* buffer is nowhere to be found, read from the disk
*/
goto finishup;
break;
}
/*
* buffer is nowhere to be found, read from the disk
*/
break;
splx(s);
#ifdef NOTYET
}
splx(s);
#endif
reqaddr = vnode_pager_addr(vp, foff);
s = splbio();
@ -934,7 +950,11 @@ vnode_pager_input(vnp, m, count, reqpage)
first = reqpage;
for (i = reqpage - 1; i >= 0; --i) {
if (failflag ||
incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize) ||
#ifdef NOTYET
((vp->v_flag & VVMIO) == 0 && incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) ||
#else
(incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) ||
#endif
(vnode_pager_addr(vp, m[i]->offset + paging_offset))
!= reqaddr + (i - reqpage) * PAGE_SIZE) {
vnode_pager_freepage(m[i]);
@ -952,7 +972,11 @@ vnode_pager_input(vnp, m, count, reqpage)
last = reqpage + 1;
for (i = reqpage + 1; i < count; i++) {
if (failflag ||
incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize) ||
#ifdef NOTYET
((vp->v_flag & VVMIO) == 0 && incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) ||
#else
(incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) ||
#endif
(vnode_pager_addr(vp, m[i]->offset + paging_offset))
!= reqaddr + (i - reqpage) * PAGE_SIZE) {
vnode_pager_freepage(m[i]);
@ -1384,27 +1408,33 @@ vnode_pager_output(vnp, m, count, rtvals)
/*
* next invalidate the incore vfs_bio data
*/
for (i = 0; i < count; i++) {
int filblock = (foff + i * PAGE_SIZE) / bsize;
struct buf *fbp;
#ifdef NOTYET
if( (vp->v_flag & VVMIO) == 0) {
#endif
for (i = 0; i < count; i++) {
int filblock = (foff + i * PAGE_SIZE) / bsize;
struct buf *fbp;
s = splbio();
if (fbp = incore(vp, filblock)) {
fbp = getblk(vp, filblock, fbp->b_bufsize, 0, 0);
if (fbp->b_flags & B_DELWRI) {
if (fbp->b_bufsize <= PAGE_SIZE)
fbp->b_flags &= ~B_DELWRI;
else {
bwrite(fbp);
fbp = getblk(vp, filblock,
fbp->b_bufsize, 0, 0);
s = splbio();
if (fbp = incore(vp, filblock)) {
fbp = getblk(vp, filblock, fbp->b_bufsize, 0, 0);
if (fbp->b_flags & B_DELWRI) {
if (fbp->b_bufsize <= PAGE_SIZE)
fbp->b_flags &= ~B_DELWRI;
else {
bwrite(fbp);
fbp = getblk(vp, filblock,
fbp->b_bufsize, 0, 0);
}
}
fbp->b_flags |= B_INVAL;
brelse(fbp);
}
fbp->b_flags |= B_INVAL;
brelse(fbp);
splx(s);
}
splx(s);
#ifdef NOTYET
}
#endif
VHOLD(vp);