version 1.80.2.11, 2005/12/11 10:29:18 |
version 1.81, 2003/08/07 16:32:35 |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
__KERNEL_RCSID(0, "$NetBSD$"); |
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
#if defined(_KERNEL_OPT) |
|
#include "opt_nfsserver.h" |
#include "opt_nfsserver.h" |
#endif |
|
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
Line 70 static void filt_genfsdetach(struct knot |
|
Line 68 static void filt_genfsdetach(struct knot |
|
static int filt_genfsread(struct knote *, long); |
static int filt_genfsread(struct knote *, long); |
static int filt_genfsvnode(struct knote *, long); |
static int filt_genfsvnode(struct knote *, long); |
|
|
#define MAX_READ_PAGES 16 /* XXXUBC 16 */ |
|
|
#define MAX_READ_AHEAD 16 /* XXXUBC 16 */ |
|
int genfs_rapages = MAX_READ_AHEAD; /* # of pages in each chunk of readahead */ |
|
int genfs_racount = 2; /* # of page chunks to readahead */ |
|
int genfs_raskip = 2; /* # of busy page chunks allowed to skip */ |
|
|
int |
int |
genfs_poll(void *v) |
genfs_poll(void *v) |
Line 78 genfs_poll(void *v) |
|
Line 80 genfs_poll(void *v) |
|
struct vop_poll_args /* { |
struct vop_poll_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
int a_events; |
int a_events; |
struct lwp *a_l; |
struct proc *a_p; |
} */ *ap = v; |
} */ *ap = v; |
|
|
return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); |
return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); |
} |
} |
|
|
int |
int |
|
genfs_fsync(void *v) |
|
{ |
|
struct vop_fsync_args /* { |
|
struct vnode *a_vp; |
|
struct ucred *a_cred; |
|
int a_flags; |
|
off_t offlo; |
|
off_t offhi; |
|
struct proc *a_p; |
|
} */ *ap = v; |
|
struct vnode *vp = ap->a_vp; |
|
int wait; |
|
|
|
wait = (ap->a_flags & FSYNC_WAIT) != 0; |
|
vflushbuf(vp, wait); |
|
if ((ap->a_flags & FSYNC_DATAONLY) != 0) |
|
return (0); |
|
else |
|
return (VOP_UPDATE(vp, NULL, NULL, wait ? UPDATE_WAIT : 0)); |
|
} |
|
|
|
int |
genfs_seek(void *v) |
genfs_seek(void *v) |
{ |
{ |
struct vop_seek_args /* { |
struct vop_seek_args /* { |
Line 122 genfs_fcntl(void *v) |
|
Line 146 genfs_fcntl(void *v) |
|
caddr_t a_data; |
caddr_t a_data; |
int a_fflag; |
int a_fflag; |
struct ucred *a_cred; |
struct ucred *a_cred; |
struct lwp *a_l; |
struct proc *a_p; |
} */ *ap = v; |
} */ *ap = v; |
|
|
if (ap->a_command == F_SETFL) |
if (ap->a_command == F_SETFL) |
Line 233 genfs_revoke(void *v) |
|
Line 257 genfs_revoke(void *v) |
|
int a_flags; |
int a_flags; |
} */ *ap = v; |
} */ *ap = v; |
struct vnode *vp, *vq; |
struct vnode *vp, *vq; |
struct lwp *l = curlwp; /* XXX */ |
struct proc *p = curproc; /* XXX */ |
|
|
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
if ((ap->a_flags & REVOKEALL) == 0) |
if ((ap->a_flags & REVOKEALL) == 0) |
Line 250 genfs_revoke(void *v) |
|
Line 274 genfs_revoke(void *v) |
|
*/ |
*/ |
if (vp->v_flag & VXLOCK) { |
if (vp->v_flag & VXLOCK) { |
vp->v_flag |= VXWANT; |
vp->v_flag |= VXWANT; |
ltsleep(vp, PINOD|PNORELOCK, "vop_revokeall", 0, |
simple_unlock(&vp->v_interlock); |
&vp->v_interlock); |
tsleep((caddr_t)vp, PINOD, "vop_revokeall", 0); |
return (0); |
return (0); |
} |
} |
/* |
/* |
Line 281 genfs_revoke(void *v) |
|
Line 305 genfs_revoke(void *v) |
|
simple_lock(&vp->v_interlock); |
simple_lock(&vp->v_interlock); |
vp->v_flag &= ~VXLOCK; |
vp->v_flag &= ~VXLOCK; |
} |
} |
vgonel(vp, l); |
vgonel(vp, p); |
return (0); |
return (0); |
} |
} |
|
|
Line 297 genfs_lock(void *v) |
|
Line 321 genfs_lock(void *v) |
|
} */ *ap = v; |
} */ *ap = v; |
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
|
|
return (lockmgr(vp->v_vnlock, ap->a_flags, &vp->v_interlock)); |
return (lockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock)); |
} |
} |
|
|
/* |
/* |
Line 312 genfs_unlock(void *v) |
|
Line 336 genfs_unlock(void *v) |
|
} */ *ap = v; |
} */ *ap = v; |
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
|
|
return (lockmgr(vp->v_vnlock, ap->a_flags | LK_RELEASE, |
return (lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, |
&vp->v_interlock)); |
&vp->v_interlock)); |
} |
} |
|
|
Line 327 genfs_islocked(void *v) |
|
Line 351 genfs_islocked(void *v) |
|
} */ *ap = v; |
} */ *ap = v; |
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
|
|
return (lockstatus(vp->v_vnlock)); |
return (lockstatus(&vp->v_lock)); |
} |
} |
|
|
/* |
/* |
Line 339 genfs_nolock(void *v) |
|
Line 363 genfs_nolock(void *v) |
|
struct vop_lock_args /* { |
struct vop_lock_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
int a_flags; |
int a_flags; |
struct lwp *a_l; |
struct proc *a_p; |
} */ *ap = v; |
} */ *ap = v; |
|
|
/* |
/* |
Line 376 genfs_lease_check(void *v) |
|
Line 400 genfs_lease_check(void *v) |
|
#ifdef NFSSERVER |
#ifdef NFSSERVER |
struct vop_lease_args /* { |
struct vop_lease_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
struct lwp *a_l; |
struct proc *a_p; |
struct ucred *a_cred; |
struct ucred *a_cred; |
int a_flag; |
int a_flag; |
} */ *ap = v; |
} */ *ap = v; |
Line 385 genfs_lease_check(void *v) |
|
Line 409 genfs_lease_check(void *v) |
|
u_quad_t frev; |
u_quad_t frev; |
|
|
(void) nqsrv_getlease(ap->a_vp, &duration, ND_CHECK | ap->a_flag, |
(void) nqsrv_getlease(ap->a_vp, &duration, ND_CHECK | ap->a_flag, |
NQLOCALSLP, ap->a_l, (struct mbuf *)0, &cache, &frev, ap->a_cred); |
NQLOCALSLP, ap->a_p, (struct mbuf *)0, &cache, &frev, ap->a_cred); |
return (0); |
return (0); |
#else |
#else |
return (0); |
return (0); |
Line 451 genfs_getpages(void *v) |
|
Line 475 genfs_getpages(void *v) |
|
struct vnode *devvp; |
struct vnode *devvp; |
struct genfs_node *gp = VTOG(vp); |
struct genfs_node *gp = VTOG(vp); |
struct uvm_object *uobj = &vp->v_uobj; |
struct uvm_object *uobj = &vp->v_uobj; |
struct vm_page *pg, **pgs, *pgs_onstack[MAX_READ_PAGES]; |
struct vm_page *pg, **pgs, *pgs_onstack[MAX_READ_AHEAD]; |
int pgs_size; |
int pgs_size; |
struct ucred *cred = curproc->p_ucred; /* XXXUBC curlwp */ |
struct ucred *cred = curproc->p_ucred; /* XXXUBC curlwp */ |
boolean_t async = (flags & PGO_SYNCIO) == 0; |
boolean_t async = (flags & PGO_SYNCIO) == 0; |
boolean_t write = (ap->a_access_type & VM_PROT_WRITE) != 0; |
boolean_t write = (ap->a_access_type & VM_PROT_WRITE) != 0; |
boolean_t sawhole = FALSE; |
boolean_t sawhole = FALSE; |
boolean_t overwrite = (flags & PGO_OVERWRITE) != 0; |
boolean_t overwrite = (flags & PGO_OVERWRITE) != 0; |
boolean_t blockalloc = write && (flags & PGO_NOBLOCKALLOC) == 0; |
|
UVMHIST_FUNC("genfs_getpages"); UVMHIST_CALLED(ubchist); |
UVMHIST_FUNC("genfs_getpages"); UVMHIST_CALLED(ubchist); |
|
|
UVMHIST_LOG(ubchist, "vp %p off 0x%x/%x count %d", |
UVMHIST_LOG(ubchist, "vp %p off 0x%x/%x count %d", |
vp, ap->a_offset >> 32, ap->a_offset, *ap->a_count); |
vp, ap->a_offset >> 32, ap->a_offset, *ap->a_count); |
|
|
KASSERT(vp->v_type == VREG || vp->v_type == VBLK); |
|
|
|
/* XXXUBC temp limit */ |
/* XXXUBC temp limit */ |
if (*ap->a_count > MAX_READ_PAGES) { |
if (*ap->a_count > MAX_READ_AHEAD) { |
panic("genfs_getpages: too many pages"); |
panic("genfs_getpages: too many pages"); |
} |
} |
|
|
Line 478 genfs_getpages(void *v) |
|
Line 499 genfs_getpages(void *v) |
|
if (flags & PGO_PASTEOF) { |
if (flags & PGO_PASTEOF) { |
newsize = MAX(vp->v_size, |
newsize = MAX(vp->v_size, |
origoffset + (orignpages << PAGE_SHIFT)); |
origoffset + (orignpages << PAGE_SHIFT)); |
GOP_SIZE(vp, newsize, &memeof, GOP_SIZE_READ|GOP_SIZE_MEM); |
GOP_SIZE(vp, newsize, &memeof, GOP_SIZE_READ); |
} else { |
} else { |
GOP_SIZE(vp, vp->v_size, &memeof, GOP_SIZE_READ|GOP_SIZE_MEM); |
memeof = diskeof; |
} |
} |
KASSERT(ap->a_centeridx >= 0 || ap->a_centeridx <= orignpages); |
KASSERT(ap->a_centeridx >= 0 || ap->a_centeridx <= orignpages); |
KASSERT((origoffset & (PAGE_SIZE - 1)) == 0 && origoffset >= 0); |
KASSERT((origoffset & (PAGE_SIZE - 1)) == 0 && origoffset >= 0); |
Line 499 genfs_getpages(void *v) |
|
Line 520 genfs_getpages(void *v) |
|
return (EINVAL); |
return (EINVAL); |
} |
} |
|
|
/* uobj is locked */ |
|
|
|
if ((flags & PGO_NOTIMESTAMP) == 0 && |
|
(vp->v_type == VREG || |
|
(vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)) { |
|
int updflags = 0; |
|
|
|
if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0) { |
|
updflags = GOP_UPDATE_ACCESSED; |
|
} |
|
if (write) { |
|
updflags |= GOP_UPDATE_MODIFIED; |
|
} |
|
if (updflags != 0) { |
|
GOP_MARKUPDATE(vp, updflags); |
|
} |
|
} |
|
|
|
if (write) { |
|
gp->g_dirtygen++; |
|
if ((vp->v_flag & VONWORKLST) == 0) { |
|
vn_syncer_add_to_worklist(vp, filedelay); |
|
} |
|
if ((vp->v_flag & (VWRITEMAP|VWRITEMAPDIRTY)) == VWRITEMAP) { |
|
vp->v_flag |= VWRITEMAPDIRTY; |
|
} |
|
} |
|
|
|
/* |
/* |
* For PGO_LOCKED requests, just return whatever's in memory. |
* For PGO_LOCKED requests, just return whatever's in memory. |
*/ |
*/ |
Line 538 genfs_getpages(void *v) |
|
Line 531 genfs_getpages(void *v) |
|
return (ap->a_m[ap->a_centeridx] == NULL ? EBUSY : 0); |
return (ap->a_m[ap->a_centeridx] == NULL ? EBUSY : 0); |
} |
} |
|
|
|
/* vnode is VOP_LOCKed, uobj is locked */ |
|
|
|
if (write && (vp->v_flag & VONWORKLST) == 0) { |
|
vn_syncer_add_to_worklist(vp, filedelay); |
|
} |
|
|
/* |
/* |
* find the requested pages and make some simple checks. |
* find the requested pages and make some simple checks. |
* leave space in the page array for a whole block. |
* leave space in the page array for a whole block. |
Line 590 genfs_getpages(void *v) |
|
Line 589 genfs_getpages(void *v) |
|
*/ |
*/ |
|
|
for (i = 0; i < npages; i++) { |
for (i = 0; i < npages; i++) { |
struct vm_page *pg1 = pgs[ridx + i]; |
struct vm_page *pg = pgs[ridx + i]; |
|
|
if ((pg1->flags & PG_FAKE) || |
if ((pg->flags & PG_FAKE) || |
(blockalloc && (pg1->flags & PG_RDONLY))) { |
(write && (pg->flags & PG_RDONLY))) { |
break; |
break; |
} |
} |
} |
} |
Line 601 genfs_getpages(void *v) |
|
Line 600 genfs_getpages(void *v) |
|
UVMHIST_LOG(ubchist, "returning cached pages", 0,0,0,0); |
UVMHIST_LOG(ubchist, "returning cached pages", 0,0,0,0); |
raoffset = origoffset + (orignpages << PAGE_SHIFT); |
raoffset = origoffset + (orignpages << PAGE_SHIFT); |
npages += ridx; |
npages += ridx; |
goto out; |
goto raout; |
} |
} |
|
|
/* |
/* |
Line 612 genfs_getpages(void *v) |
|
Line 611 genfs_getpages(void *v) |
|
UVMHIST_LOG(ubchist, "PGO_OVERWRITE",0,0,0,0); |
UVMHIST_LOG(ubchist, "PGO_OVERWRITE",0,0,0,0); |
|
|
for (i = 0; i < npages; i++) { |
for (i = 0; i < npages; i++) { |
struct vm_page *pg1 = pgs[ridx + i]; |
struct vm_page *pg = pgs[ridx + i]; |
|
|
pg1->flags &= ~(PG_RDONLY|PG_CLEAN); |
pg->flags &= ~(PG_RDONLY|PG_CLEAN); |
} |
} |
npages += ridx; |
npages += ridx; |
goto out; |
goto out; |
Line 698 genfs_getpages(void *v) |
|
Line 697 genfs_getpages(void *v) |
|
* now loop over the pages, reading as needed. |
* now loop over the pages, reading as needed. |
*/ |
*/ |
|
|
if (blockalloc) { |
if (write) { |
lockmgr(&gp->g_glock, LK_EXCLUSIVE, NULL); |
lockmgr(&gp->g_glock, LK_EXCLUSIVE, NULL); |
} else { |
} else { |
lockmgr(&gp->g_glock, LK_SHARED, NULL); |
lockmgr(&gp->g_glock, LK_SHARED, NULL); |
Line 714 genfs_getpages(void *v) |
|
Line 713 genfs_getpages(void *v) |
|
*/ |
*/ |
|
|
pidx = (offset - startoffset) >> PAGE_SHIFT; |
pidx = (offset - startoffset) >> PAGE_SHIFT; |
while ((pgs[pidx]->flags & PG_FAKE) == 0) { |
while ((pgs[pidx]->flags & (PG_FAKE|PG_RDONLY)) == 0) { |
size_t b; |
size_t b; |
|
|
KASSERT((offset & (PAGE_SIZE - 1)) == 0); |
KASSERT((offset & (PAGE_SIZE - 1)) == 0); |
if ((pgs[pidx]->flags & PG_RDONLY)) { |
|
sawhole = TRUE; |
|
} |
|
b = MIN(PAGE_SIZE, bytes); |
b = MIN(PAGE_SIZE, bytes); |
offset += b; |
offset += b; |
bytes -= b; |
bytes -= b; |
Line 768 genfs_getpages(void *v) |
|
Line 764 genfs_getpages(void *v) |
|
|
|
/* |
/* |
* if this block isn't allocated, zero it instead of |
* if this block isn't allocated, zero it instead of |
* reading it. unless we are going to allocate blocks, |
* reading it. if this is a read access, mark the |
* mark the pages we zeroed PG_RDONLY. |
* pages we zeroed PG_RDONLY. |
*/ |
*/ |
|
|
if (blkno < 0) { |
if (blkno < 0) { |
Line 785 genfs_getpages(void *v) |
|
Line 781 genfs_getpages(void *v) |
|
for (i = 0; i < holepages; i++) { |
for (i = 0; i < holepages; i++) { |
if (write) { |
if (write) { |
pgs[pidx + i]->flags &= ~PG_CLEAN; |
pgs[pidx + i]->flags &= ~PG_CLEAN; |
} |
} else { |
if (!blockalloc) { |
|
pgs[pidx + i]->flags |= PG_RDONLY; |
pgs[pidx + i]->flags |= PG_RDONLY; |
} |
} |
} |
} |
Line 815 genfs_getpages(void *v) |
|
Line 810 genfs_getpages(void *v) |
|
} |
} |
bp->b_lblkno = 0; |
bp->b_lblkno = 0; |
bp->b_private = mbp; |
bp->b_private = mbp; |
|
if (devvp->v_type == VBLK) { |
|
bp->b_dev = devvp->v_rdev; |
|
} |
|
|
/* adjust physical blkno for partial blocks */ |
/* adjust physical blkno for partial blocks */ |
bp->b_blkno = blkno + ((offset - ((off_t)lbn << fs_bshift)) >> |
bp->b_blkno = blkno + ((offset - ((off_t)lbn << fs_bshift)) >> |
Line 824 genfs_getpages(void *v) |
|
Line 822 genfs_getpages(void *v) |
|
"bp %p offset 0x%x bcount 0x%x blkno 0x%x", |
"bp %p offset 0x%x bcount 0x%x blkno 0x%x", |
bp, offset, iobytes, bp->b_blkno); |
bp, offset, iobytes, bp->b_blkno); |
|
|
if (async) |
VOP_STRATEGY(bp); |
BIO_SETPRIO(bp, BPRIO_TIMELIMITED); |
|
else |
|
BIO_SETPRIO(bp, BPRIO_TIMECRITICAL); |
|
|
|
VOP_STRATEGY(devvp, bp); |
|
} |
} |
|
|
loopdone: |
loopdone: |
|
|
* the page is completely allocated while the pages are locked. |
* the page is completely allocated while the pages are locked. |
*/ |
*/ |
|
|
if (!error && sawhole && blockalloc) { |
if (!error && sawhole && write) { |
|
for (i = 0; i < npages; i++) { |
|
if (pgs[i] == NULL) { |
|
continue; |
|
} |
|
pgs[i]->flags &= ~PG_CLEAN; |
|
UVMHIST_LOG(ubchist, "mark dirty pg %p", pgs[i],0,0,0); |
|
} |
error = GOP_ALLOC(vp, startoffset, npages << PAGE_SHIFT, 0, |
error = GOP_ALLOC(vp, startoffset, npages << PAGE_SHIFT, 0, |
cred); |
cred); |
UVMHIST_LOG(ubchist, "gop_alloc off 0x%x/0x%x -> %d", |
UVMHIST_LOG(ubchist, "gop_alloc off 0x%x/0x%x -> %d", |
startoffset, npages << PAGE_SHIFT, error,0); |
startoffset, npages << PAGE_SHIFT, error,0); |
if (!error) { |
|
for (i = 0; i < npages; i++) { |
|
if (pgs[i] == NULL) { |
|
continue; |
|
} |
|
pgs[i]->flags &= ~(PG_CLEAN|PG_RDONLY); |
|
UVMHIST_LOG(ubchist, "mark dirty pg %p", |
|
pgs[i],0,0,0); |
|
} |
|
} |
|
} |
} |
lockmgr(&gp->g_glock, LK_RELEASE, NULL); |
lockmgr(&gp->g_glock, LK_RELEASE, NULL); |
simple_lock(&uobj->vmobjlock); |
simple_lock(&uobj->vmobjlock); |
|
|
/* |
/* |
|
* see if we want to start any readahead. |
|
* XXXUBC for now, just read the next 128k on 64k boundaries. |
|
* this is pretty nonsensical, but it is 50% faster than reading |
|
* just the next 64k. |
|
*/ |
|
|
|
raout: |
|
if (!error && !async && !write && ((int)raoffset & 0xffff) == 0 && |
|
PAGE_SHIFT <= 16) { |
|
off_t rasize; |
|
int rapages, err, i, skipped; |
|
|
|
/* XXXUBC temp limit, from above */ |
|
rapages = MIN(MIN(1 << (16 - PAGE_SHIFT), MAX_READ_AHEAD), |
|
genfs_rapages); |
|
rasize = rapages << PAGE_SHIFT; |
|
for (i = skipped = 0; i < genfs_racount; i++) { |
|
err = VOP_GETPAGES(vp, raoffset, NULL, &rapages, 0, |
|
VM_PROT_READ, 0, 0); |
|
simple_lock(&uobj->vmobjlock); |
|
if (err) { |
|
if (err != EBUSY || |
|
skipped++ == genfs_raskip) |
|
break; |
|
} |
|
raoffset += rasize; |
|
rapages = rasize >> PAGE_SHIFT; |
|
} |
|
} |
|
|
|
/* |
* we're almost done! release the pages... |
* we're almost done! release the pages... |
* for errors, we free the pages. |
* for errors, we free the pages. |
* otherwise we activate them and mark them as valid and clean. |
* otherwise we activate them and mark them as valid and clean. |
|
|
pg->flags &= ~(PG_FAKE); |
pg->flags &= ~(PG_FAKE); |
pmap_clear_modify(pgs[i]); |
pmap_clear_modify(pgs[i]); |
} |
} |
KASSERT(!write || !blockalloc || (pg->flags & PG_RDONLY) == 0); |
if (write) { |
|
pg->flags &= ~(PG_RDONLY); |
|
} |
if (i < ridx || i >= ridx + orignpages || async) { |
if (i < ridx || i >= ridx + orignpages || async) { |
UVMHIST_LOG(ubchist, "unbusy pg %p offset 0x%x", |
UVMHIST_LOG(ubchist, "unbusy pg %p offset 0x%x", |
pg, pg->offset,0,0); |
pg, pg->offset,0,0); |
Line 1034 genfs_putpages(void *v) |
|
Line 1057 genfs_putpages(void *v) |
|
int i, s, error, npages, nback; |
int i, s, error, npages, nback; |
int freeflag; |
int freeflag; |
struct vm_page *pgs[maxpages], *pg, *nextpg, *tpg, curmp, endmp; |
struct vm_page *pgs[maxpages], *pg, *nextpg, *tpg, curmp, endmp; |
boolean_t wasclean, by_list, needs_clean, yld; |
boolean_t wasclean, by_list, needs_clean, yield; |
boolean_t async = (flags & PGO_SYNCIO) == 0; |
boolean_t async = (flags & PGO_SYNCIO) == 0; |
boolean_t pagedaemon = curproc == uvm.pagedaemon_proc; |
boolean_t pagedaemon = curproc == uvm.pagedaemon_proc; |
struct lwp *l = curlwp ? curlwp : &lwp0; |
struct lwp *l = curlwp ? curlwp : &lwp0; |
struct genfs_node *gp = VTOG(vp); |
|
int dirtygen; |
|
boolean_t modified = FALSE; |
|
boolean_t cleanall; |
|
|
|
UVMHIST_FUNC("genfs_putpages"); UVMHIST_CALLED(ubchist); |
UVMHIST_FUNC("genfs_putpages"); UVMHIST_CALLED(ubchist); |
|
|
Line 1051 genfs_putpages(void *v) |
|
Line 1070 genfs_putpages(void *v) |
|
|
|
UVMHIST_LOG(ubchist, "vp %p pages %d off 0x%x len 0x%x", |
UVMHIST_LOG(ubchist, "vp %p pages %d off 0x%x len 0x%x", |
vp, uobj->uo_npages, startoff, endoff - startoff); |
vp, uobj->uo_npages, startoff, endoff - startoff); |
|
|
KASSERT((vp->v_flag & VONWORKLST) != 0 || |
|
(vp->v_flag & VWRITEMAPDIRTY) == 0); |
|
if (uobj->uo_npages == 0) { |
if (uobj->uo_npages == 0) { |
s = splbio(); |
s = splbio(); |
if (vp->v_flag & VONWORKLST) { |
if (LIST_FIRST(&vp->v_dirtyblkhd) == NULL && |
vp->v_flag &= ~VWRITEMAPDIRTY; |
(vp->v_flag & VONWORKLST)) { |
if (LIST_FIRST(&vp->v_dirtyblkhd) == NULL) { |
vp->v_flag &= ~VONWORKLST; |
vp->v_flag &= ~VONWORKLST; |
LIST_REMOVE(vp, v_synclist); |
LIST_REMOVE(vp, v_synclist); |
|
} |
|
} |
} |
splx(s); |
splx(s); |
simple_unlock(slock); |
simple_unlock(slock); |
Line 1085 genfs_putpages(void *v) |
|
Line 1099 genfs_putpages(void *v) |
|
by_list = (uobj->uo_npages <= |
by_list = (uobj->uo_npages <= |
((endoff - startoff) >> PAGE_SHIFT) * UVM_PAGE_HASH_PENALTY); |
((endoff - startoff) >> PAGE_SHIFT) * UVM_PAGE_HASH_PENALTY); |
|
|
#if !defined(DEBUG) |
|
/* |
|
* if this vnode is known not to have dirty pages, |
|
* don't bother to clean it out. |
|
*/ |
|
|
|
if ((vp->v_flag & VONWORKLST) == 0) { |
|
if ((flags & (PGO_FREE|PGO_DEACTIVATE)) == 0) { |
|
goto skip_scan; |
|
} |
|
flags &= ~PGO_CLEANIT; |
|
} |
|
#endif /* !defined(DEBUG) */ |
|
|
|
/* |
/* |
* start the loop. when scanning by list, hold the last page |
* start the loop. when scanning by list, hold the last page |
* in the list before we start. pages allocated after we start |
* in the list before we start. pages allocated after we start |
Line 1106 genfs_putpages(void *v) |
|
Line 1106 genfs_putpages(void *v) |
|
* current last page. |
* current last page. |
*/ |
*/ |
|
|
cleanall = (flags & PGO_CLEANIT) != 0 && wasclean && |
|
startoff == 0 && endoff == trunc_page(LLONG_MAX) && |
|
(vp->v_flag & VONWORKLST) != 0; |
|
dirtygen = gp->g_dirtygen; |
|
freeflag = pagedaemon ? PG_PAGEOUT : PG_RELEASED; |
freeflag = pagedaemon ? PG_PAGEOUT : PG_RELEASED; |
|
curmp.uobject = uobj; |
|
curmp.offset = (voff_t)-1; |
|
curmp.flags = PG_BUSY; |
|
endmp.uobject = uobj; |
|
endmp.offset = (voff_t)-1; |
|
endmp.flags = PG_BUSY; |
if (by_list) { |
if (by_list) { |
curmp.uobject = uobj; |
|
curmp.offset = (voff_t)-1; |
|
curmp.flags = PG_BUSY; |
|
endmp.uobject = uobj; |
|
endmp.offset = (voff_t)-1; |
|
endmp.flags = PG_BUSY; |
|
pg = TAILQ_FIRST(&uobj->memq); |
pg = TAILQ_FIRST(&uobj->memq); |
TAILQ_INSERT_TAIL(&uobj->memq, &endmp, listq); |
TAILQ_INSERT_TAIL(&uobj->memq, &endmp, listq); |
PHOLD(l); |
PHOLD(l); |
Line 1141 genfs_putpages(void *v) |
|
Line 1137 genfs_putpages(void *v) |
|
} |
} |
if (pg->offset < startoff || pg->offset >= endoff || |
if (pg->offset < startoff || pg->offset >= endoff || |
pg->flags & (PG_RELEASED|PG_PAGEOUT)) { |
pg->flags & (PG_RELEASED|PG_PAGEOUT)) { |
if (pg->flags & (PG_RELEASED|PG_PAGEOUT)) { |
|
wasclean = FALSE; |
|
} |
|
pg = TAILQ_NEXT(pg, listq); |
pg = TAILQ_NEXT(pg, listq); |
continue; |
continue; |
} |
} |
off = pg->offset; |
off = pg->offset; |
} else if (pg == NULL || pg->flags & (PG_RELEASED|PG_PAGEOUT)) { |
} else if (pg == NULL || |
if (pg != NULL) { |
pg->flags & (PG_RELEASED|PG_PAGEOUT)) { |
wasclean = FALSE; |
|
} |
|
off += PAGE_SIZE; |
off += PAGE_SIZE; |
if (off < endoff) { |
if (off < endoff) { |
pg = uvm_pagelookup(uobj, off); |
pg = uvm_pagelookup(uobj, off); |
Line 1164 genfs_putpages(void *v) |
|
Line 1155 genfs_putpages(void *v) |
|
* wait for it to become unbusy. |
* wait for it to become unbusy. |
*/ |
*/ |
|
|
yld = (l->l_cpu->ci_schedstate.spc_flags & |
yield = (l->l_cpu->ci_schedstate.spc_flags & |
SPCF_SHOULDYIELD) && !pagedaemon; |
SPCF_SHOULDYIELD) && !pagedaemon; |
if (pg->flags & PG_BUSY || yld) { |
if (pg->flags & PG_BUSY || yield) { |
UVMHIST_LOG(ubchist, "busy %p", pg,0,0,0); |
UVMHIST_LOG(ubchist, "busy %p", pg,0,0,0); |
if (flags & PGO_BUSYFAIL && pg->flags & PG_BUSY) { |
if (flags & PGO_BUSYFAIL && pg->flags & PG_BUSY) { |
UVMHIST_LOG(ubchist, "busyfail %p", pg, 0,0,0); |
UVMHIST_LOG(ubchist, "busyfail %p", pg, 0,0,0); |
Line 1179 genfs_putpages(void *v) |
|
Line 1170 genfs_putpages(void *v) |
|
UVMHIST_LOG(ubchist, "curmp next %p", |
UVMHIST_LOG(ubchist, "curmp next %p", |
TAILQ_NEXT(&curmp, listq), 0,0,0); |
TAILQ_NEXT(&curmp, listq), 0,0,0); |
} |
} |
if (yld) { |
if (yield) { |
simple_unlock(slock); |
simple_unlock(slock); |
preempt(1); |
preempt(1); |
simple_lock(slock); |
simple_lock(slock); |
Line 1206 genfs_putpages(void *v) |
|
Line 1197 genfs_putpages(void *v) |
|
|
|
if (flags & PGO_FREE) { |
if (flags & PGO_FREE) { |
pmap_page_protect(pg, VM_PROT_NONE); |
pmap_page_protect(pg, VM_PROT_NONE); |
} else if (flags & PGO_CLEANIT) { |
|
|
|
/* |
|
* if we still have some hope to pull this vnode off |
|
* from the syncer queue, write-protect the page. |
|
*/ |
|
|
|
if (cleanall && wasclean && |
|
gp->g_dirtygen == dirtygen) { |
|
|
|
/* |
|
* uobj pages get wired only by uvm_fault |
|
* where uobj is locked. |
|
*/ |
|
|
|
if (pg->wire_count == 0) { |
|
pmap_page_protect(pg, |
|
VM_PROT_READ|VM_PROT_EXECUTE); |
|
} else { |
|
cleanall = FALSE; |
|
} |
|
} |
|
} |
} |
|
|
if (flags & PGO_CLEANIT) { |
if (flags & PGO_CLEANIT) { |
needs_clean = pmap_clear_modify(pg) || |
needs_clean = pmap_clear_modify(pg) || |
(pg->flags & PG_CLEAN) == 0; |
(pg->flags & PG_CLEAN) == 0; |
Line 1246 genfs_putpages(void *v) |
|
Line 1214 genfs_putpages(void *v) |
|
*/ |
*/ |
|
|
if (needs_clean) { |
if (needs_clean) { |
KDASSERT((vp->v_flag & VONWORKLST)); |
|
wasclean = FALSE; |
wasclean = FALSE; |
memset(pgs, 0, sizeof(pgs)); |
memset(pgs, 0, sizeof(pgs)); |
pg->flags |= PG_BUSY; |
pg->flags |= PG_BUSY; |
Line 1330 genfs_putpages(void *v) |
|
Line 1297 genfs_putpages(void *v) |
|
|
|
nextpg = TAILQ_NEXT(tpg, listq); |
nextpg = TAILQ_NEXT(tpg, listq); |
uvm_pagefree(tpg); |
uvm_pagefree(tpg); |
if (pagedaemon) |
|
uvmexp.pdfreed++; |
|
} |
} |
} |
} |
} |
} |
Line 1339 genfs_putpages(void *v) |
|
Line 1304 genfs_putpages(void *v) |
|
uvm_unlock_pageq(); |
uvm_unlock_pageq(); |
} |
} |
if (needs_clean) { |
if (needs_clean) { |
modified = TRUE; |
|
|
|
/* |
/* |
* start the i/o. if we're traversing by list, |
* start the i/o. if we're traversing by list, |
Line 1388 genfs_putpages(void *v) |
|
Line 1352 genfs_putpages(void *v) |
|
PRELE(l); |
PRELE(l); |
} |
} |
|
|
if (modified && (vp->v_flag & VWRITEMAPDIRTY) != 0 && |
|
(vp->v_type == VREG || |
|
(vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)) { |
|
GOP_MARKUPDATE(vp, GOP_UPDATE_MODIFIED); |
|
} |
|
|
|
/* |
/* |
* if we're cleaning and there was nothing to clean, |
* if we're cleaning and there was nothing to clean, |
* take us off the syncer list. if we started any i/o |
* take us off the syncer list. if we started any i/o |
Line 1401 genfs_putpages(void *v) |
|
Line 1359 genfs_putpages(void *v) |
|
*/ |
*/ |
|
|
s = splbio(); |
s = splbio(); |
if (cleanall && wasclean && gp->g_dirtygen == dirtygen && |
if ((flags & PGO_CLEANIT) && wasclean && |
(vp->v_flag & VONWORKLST) != 0) { |
startoff == 0 && endoff == trunc_page(LLONG_MAX) && |
vp->v_flag &= ~VWRITEMAPDIRTY; |
LIST_FIRST(&vp->v_dirtyblkhd) == NULL && |
if (LIST_FIRST(&vp->v_dirtyblkhd) == NULL) { |
(vp->v_flag & VONWORKLST)) { |
vp->v_flag &= ~VONWORKLST; |
vp->v_flag &= ~VONWORKLST; |
LIST_REMOVE(vp, v_synclist); |
LIST_REMOVE(vp, v_synclist); |
} |
|
} |
} |
splx(s); |
splx(s); |
|
|
#if !defined(DEBUG) |
|
skip_scan: |
|
#endif /* !defined(DEBUG) */ |
|
if (!wasclean && !async) { |
if (!wasclean && !async) { |
s = splbio(); |
s = splbio(); |
/* |
/* |
Line 1526 genfs_gop_write(struct vnode *vp, struct |
|
Line 1479 genfs_gop_write(struct vnode *vp, struct |
|
} |
} |
bp->b_lblkno = 0; |
bp->b_lblkno = 0; |
bp->b_private = mbp; |
bp->b_private = mbp; |
|
if (devvp->v_type == VBLK) { |
|
bp->b_dev = devvp->v_rdev; |
|
} |
|
|
/* adjust physical blkno for partial blocks */ |
/* adjust physical blkno for partial blocks */ |
bp->b_blkno = blkno + ((offset - ((off_t)lbn << fs_bshift)) >> |
bp->b_blkno = blkno + ((offset - ((off_t)lbn << fs_bshift)) >> |
Line 1533 genfs_gop_write(struct vnode *vp, struct |
|
Line 1489 genfs_gop_write(struct vnode *vp, struct |
|
UVMHIST_LOG(ubchist, |
UVMHIST_LOG(ubchist, |
"vp %p offset 0x%x bcount 0x%x blkno 0x%x", |
"vp %p offset 0x%x bcount 0x%x blkno 0x%x", |
vp, offset, bp->b_bcount, bp->b_blkno); |
vp, offset, bp->b_bcount, bp->b_blkno); |
if (curproc == uvm.pagedaemon_proc) |
VOP_STRATEGY(bp); |
BIO_SETPRIO(bp, BPRIO_TIMELIMITED); |
|
else if (async) |
|
BIO_SETPRIO(bp, BPRIO_TIMENONCRITICAL); |
|
else |
|
BIO_SETPRIO(bp, BPRIO_TIMECRITICAL); |
|
|
|
VOP_STRATEGY(devvp, bp); |
|
} |
} |
if (skipbytes) { |
if (skipbytes) { |
UVMHIST_LOG(ubchist, "skipbytes %d", skipbytes, 0,0,0); |
UVMHIST_LOG(ubchist, "skipbytes %d", skipbytes, 0,0,0); |
Line 1587 genfs_null_putpages(void *v) |
|
Line 1536 genfs_null_putpages(void *v) |
|
} |
} |
|
|
void |
void |
genfs_node_init(struct vnode *vp, const struct genfs_ops *ops) |
genfs_node_init(struct vnode *vp, struct genfs_ops *ops) |
{ |
{ |
struct genfs_node *gp = VTOG(vp); |
struct genfs_node *gp = VTOG(vp); |
|
|
Line 1647 genfs_compat_getpages(void *v) |
|
Line 1596 genfs_compat_getpages(void *v) |
|
simple_unlock(&uobj->vmobjlock); |
simple_unlock(&uobj->vmobjlock); |
return (EINVAL); |
return (EINVAL); |
} |
} |
if ((ap->a_flags & PGO_SYNCIO) == 0) { |
|
return 0; |
|
} |
|
npages = orignpages; |
npages = orignpages; |
uvn_findpages(uobj, origoffset, &npages, pgs, UFP_ALL); |
uvn_findpages(uobj, origoffset, &npages, pgs, UFP_ALL); |
simple_unlock(&uobj->vmobjlock); |
simple_unlock(&uobj->vmobjlock); |
Line 1668 genfs_compat_getpages(void *v) |
|
Line 1614 genfs_compat_getpages(void *v) |
|
uio.uio_segflg = UIO_SYSSPACE; |
uio.uio_segflg = UIO_SYSSPACE; |
uio.uio_rw = UIO_READ; |
uio.uio_rw = UIO_READ; |
uio.uio_resid = PAGE_SIZE; |
uio.uio_resid = PAGE_SIZE; |
uio.uio_lwp = NULL; |
uio.uio_procp = curproc; |
/* XXX vn_lock */ |
|
error = VOP_READ(vp, &uio, 0, cred); |
error = VOP_READ(vp, &uio, 0, cred); |
if (error) { |
if (error) { |
break; |
break; |
Line 1722 genfs_compat_gop_write(struct vnode *vp, |
|
Line 1667 genfs_compat_gop_write(struct vnode *vp, |
|
uio.uio_segflg = UIO_SYSSPACE; |
uio.uio_segflg = UIO_SYSSPACE; |
uio.uio_rw = UIO_WRITE; |
uio.uio_rw = UIO_WRITE; |
uio.uio_resid = npages << PAGE_SHIFT; |
uio.uio_resid = npages << PAGE_SHIFT; |
uio.uio_lwp = NULL; |
uio.uio_procp = curproc; |
/* XXX vn_lock */ |
|
error = VOP_WRITE(vp, &uio, 0, cred); |
error = VOP_WRITE(vp, &uio, 0, cred); |
|
|
s = splbio(); |
s = splbio(); |
Line 1788 filt_genfsvnode(struct knote *kn, long h |
|
Line 1732 filt_genfsvnode(struct knote *kn, long h |
|
return (kn->kn_fflags != 0); |
return (kn->kn_fflags != 0); |
} |
} |
|
|
static const struct filterops genfsread_filtops = |
static const struct filterops genfsread_filtops = |
{ 1, NULL, filt_genfsdetach, filt_genfsread }; |
{ 1, NULL, filt_genfsdetach, filt_genfsread }; |
static const struct filterops genfsvnode_filtops = |
static const struct filterops genfsvnode_filtops = |
{ 1, NULL, filt_genfsdetach, filt_genfsvnode }; |
{ 1, NULL, filt_genfsdetach, filt_genfsvnode }; |
|
|
int |
int |