version 1.51.2.1, 2007/02/27 16:54:13 |
version 1.51.2.2, 2007/03/24 14:55:58 |
Line 81 int puffs_advlock(void *); |
|
Line 81 int puffs_advlock(void *); |
|
int puffs_strategy(void *); |
int puffs_strategy(void *); |
int puffs_bmap(void *); |
int puffs_bmap(void *); |
int puffs_mmap(void *); |
int puffs_mmap(void *); |
|
int puffs_getpages(void *); |
|
|
int puffs_spec_read(void *); |
int puffs_spec_read(void *); |
int puffs_spec_write(void *); |
int puffs_spec_write(void *); |
Line 284 const struct vnodeopv_entry_desc puffs_m |
|
Line 285 const struct vnodeopv_entry_desc puffs_m |
|
{ &vop_write_desc, puffs_write }, /* write */ |
{ &vop_write_desc, puffs_write }, /* write */ |
{ &vop_fcntl_desc, puffs_fcntl }, /* fcntl */ |
{ &vop_fcntl_desc, puffs_fcntl }, /* fcntl */ |
{ &vop_ioctl_desc, puffs_ioctl }, /* ioctl */ |
{ &vop_ioctl_desc, puffs_ioctl }, /* ioctl */ |
{ &vop_fsync_desc, puffs_fsync }, /* fsync */ |
|
{ &vop_seek_desc, puffs_seek }, /* seek */ |
{ &vop_seek_desc, puffs_seek }, /* seek */ |
{ &vop_remove_desc, puffs_remove }, /* remove */ |
{ &vop_remove_desc, puffs_remove }, /* remove */ |
{ &vop_link_desc, puffs_link }, /* link */ |
{ &vop_link_desc, puffs_link }, /* link */ |
Line 298 const struct vnodeopv_entry_desc puffs_m |
|
Line 298 const struct vnodeopv_entry_desc puffs_m |
|
{ &vop_islocked_desc, puffs_islocked }, /* islocked */ |
{ &vop_islocked_desc, puffs_islocked }, /* islocked */ |
{ &vop_pathconf_desc, puffs_pathconf }, /* pathconf */ |
{ &vop_pathconf_desc, puffs_pathconf }, /* pathconf */ |
{ &vop_advlock_desc, puffs_advlock }, /* advlock */ |
{ &vop_advlock_desc, puffs_advlock }, /* advlock */ |
{ &vop_getpages_desc, genfs_getpages }, /* getpages */ |
{ &vop_getpages_desc, puffs_getpages }, /* getpages */ |
{ NULL, NULL } |
{ NULL, NULL } |
}; |
}; |
const struct vnodeopv_desc puffs_msgop_opv_desc = |
const struct vnodeopv_desc puffs_msgop_opv_desc = |
Line 691 puffs_getattr(void *v) |
|
Line 691 puffs_getattr(void *v) |
|
struct lwp *a_l; |
struct lwp *a_l; |
} */ *ap = v; |
} */ *ap = v; |
struct mount *mp; |
struct mount *mp; |
|
struct vnode *vp; |
|
struct vattr *vap; |
|
struct puffs_node *pn; |
int error; |
int error; |
|
|
PUFFS_VNREQ(getattr); |
PUFFS_VNREQ(getattr); |
|
|
mp = ap->a_vp->v_mount; |
vp = ap->a_vp; |
|
mp = vp->v_mount; |
|
vap = ap->a_vap; |
|
|
vattr_null(&getattr_arg.pvnr_va); |
vattr_null(&getattr_arg.pvnr_va); |
puffs_credcvt(&getattr_arg.pvnr_cred, ap->a_cred); |
puffs_credcvt(&getattr_arg.pvnr_cred, ap->a_cred); |
Line 707 puffs_getattr(void *v) |
|
Line 712 puffs_getattr(void *v) |
|
* around with VXLOCK and therefore breaks vn_lock(). Proper |
* around with VXLOCK and therefore breaks vn_lock(). Proper |
* fix pending. |
* fix pending. |
*/ |
*/ |
error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_GETATTR, |
error = puffs_vntouser(MPTOPUFFSMP(vp->v_mount), PUFFS_VN_GETATTR, |
&getattr_arg, sizeof(getattr_arg), VPTOPNC(ap->a_vp), |
&getattr_arg, sizeof(getattr_arg), VPTOPNC(vp), |
NULL /* XXXseeabove: should be LOCKEDVP(ap->a_vp) */, NULL); |
NULL /* XXXseeabove: should be LOCKEDVP(vp) */, NULL); |
if (error) |
if (error) |
return error; |
return error; |
|
|
(void)memcpy(ap->a_vap, &getattr_arg.pvnr_va, sizeof(struct vattr)); |
(void) memcpy(vap, &getattr_arg.pvnr_va, sizeof(struct vattr)); |
|
vap->va_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; |
|
|
/* |
pn = VPTOPP(vp); |
* fill in information userspace does not have |
if (pn->pn_stat & PNODE_METACACHE_ATIME) |
* XXX: but would it be better to do fsid at the generic level? |
vap->va_atime = pn->pn_mc_atime; |
*/ |
if (pn->pn_stat & PNODE_METACACHE_CTIME) |
ap->a_vap->va_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; |
vap->va_ctime = pn->pn_mc_ctime; |
|
if (pn->pn_stat & PNODE_METACACHE_MTIME) |
|
vap->va_mtime = pn->pn_mc_mtime; |
|
if (pn->pn_stat & PNODE_METACACHE_SIZE) { |
|
vap->va_size = pn->pn_mc_size; |
|
} else { |
|
if (getattr_arg.pvnr_va.va_size != VNOVAL) |
|
uvm_vnp_setsize(vp, getattr_arg.pvnr_va.va_size); |
|
} |
|
|
return 0; |
return 0; |
} |
} |
Line 944 puffs_fsync(void *v) |
|
Line 958 puffs_fsync(void *v) |
|
off_t a_offhi; |
off_t a_offhi; |
struct lwp *a_l; |
struct lwp *a_l; |
} */ *ap = v; |
} */ *ap = v; |
|
struct vattr va; |
struct puffs_mount *pmp; |
struct puffs_mount *pmp; |
struct puffs_vnreq_fsync *fsync_argp; |
struct puffs_vnreq_fsync *fsync_argp; |
struct vnode *vp; |
struct vnode *vp; |
Line 956 puffs_fsync(void *v) |
|
Line 971 puffs_fsync(void *v) |
|
pn = VPTOPP(vp); |
pn = VPTOPP(vp); |
pmp = MPTOPUFFSMP(vp->v_mount); |
pmp = MPTOPUFFSMP(vp->v_mount); |
|
|
pflags = PGO_CLEANIT; |
/* flush out information from our metacache */ |
if (ap->a_flags & FSYNC_WAIT) |
if (pn->pn_stat & PNODE_METACACHE_MASK) { |
pflags |= PGO_SYNCIO; |
vattr_null(&va); |
|
if (pn->pn_stat & PNODE_METACACHE_ATIME) |
|
va.va_atime = pn->pn_mc_atime; |
|
if (pn->pn_stat & PNODE_METACACHE_CTIME) |
|
va.va_ctime = pn->pn_mc_ctime; |
|
if (pn->pn_stat & PNODE_METACACHE_MTIME) |
|
va.va_mtime = pn->pn_mc_ctime; |
|
if (pn->pn_stat & PNODE_METACACHE_SIZE) |
|
va.va_size = pn->pn_mc_size; |
|
|
|
error = VOP_SETATTR(vp, &va, FSCRED, NULL); |
|
if (error) |
|
return error; |
|
|
|
pn->pn_stat &= ~PNODE_METACACHE_MASK; |
|
} |
|
|
/* |
/* |
* flush pages to avoid being overly dirty |
* flush pages to avoid being overly dirty |
*/ |
*/ |
|
pflags = PGO_CLEANIT; |
|
if (ap->a_flags & FSYNC_WAIT) |
|
pflags |= PGO_SYNCIO; |
simple_lock(&vp->v_interlock); |
simple_lock(&vp->v_interlock); |
error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), |
error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo), |
round_page(ap->a_offhi), pflags); |
round_page(ap->a_offhi), pflags); |
Line 1164 puffs_link(void *v) |
|
Line 1197 puffs_link(void *v) |
|
error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_LINK, |
error = puffs_vntouser(MPTOPUFFSMP(ap->a_dvp->v_mount), PUFFS_VN_LINK, |
&link_arg, sizeof(link_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL); |
&link_arg, sizeof(link_arg), VPTOPNC(ap->a_dvp), ap->a_dvp, NULL); |
|
|
|
/* |
|
* XXX: stay in touch with the cache. I don't like this, but |
|
* don't have a better solution either. See also puffs_rename(). |
|
*/ |
|
if (error == 0) |
|
puffs_updatenode(ap->a_vp, PUFFS_UPDATECTIME); |
|
|
vput(ap->a_dvp); |
vput(ap->a_dvp); |
|
|
return error; |
return error; |
Line 1275 puffs_rename(void *v) |
|
Line 1315 puffs_rename(void *v) |
|
PUFFS_VN_RENAME, &rename_arg, sizeof(rename_arg), |
PUFFS_VN_RENAME, &rename_arg, sizeof(rename_arg), |
VPTOPNC(ap->a_fdvp), NULL, NULL); |
VPTOPNC(ap->a_fdvp), NULL, NULL); |
|
|
|
/* |
|
* XXX: stay in touch with the cache. I don't like this, but |
|
* don't have a better solution either. See also puffs_link(). |
|
*/ |
|
if (error == 0) |
|
puffs_updatenode(ap->a_fvp, PUFFS_UPDATECTIME); |
|
|
out: |
out: |
if (ap->a_tvp != NULL) |
if (ap->a_tvp != NULL) |
vput(ap->a_tvp); |
vput(ap->a_tvp); |
Line 1785 puffs_strategy(void *v) |
|
Line 1832 puffs_strategy(void *v) |
|
dowritefaf = 1; |
dowritefaf = 1; |
|
|
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
if (dowritefaf) |
|
KASSERT((bp->b_flags & B_READ) == 0); |
|
if (curproc == uvm.pagedaemon_proc) |
if (curproc == uvm.pagedaemon_proc) |
KASSERT(dowritefaf); |
KASSERT(dowritefaf); |
#endif |
#endif |
|
|
if (bp->b_flags & B_READ) { |
tomove = PUFFS_TOMOVE(bp->b_bcount, pmp); |
|
|
|
if ((bp->b_flags & (B_READ | B_ASYNC)) == (B_READ | B_ASYNC)) { |
|
puffs_vntouser_bioread_async(pmp, VPTOPNC(vp), tomove, |
|
bp->b_blkno << DEV_BSHIFT, bp, LOCKEDVP(vp), NULL); |
|
} else if (bp->b_flags & B_READ) { |
argsize = sizeof(struct puffs_vnreq_read); |
argsize = sizeof(struct puffs_vnreq_read); |
read_argp = malloc(argsize, M_PUFFS, M_NOWAIT | M_ZERO); |
read_argp = malloc(argsize, M_PUFFS, M_NOWAIT | M_ZERO); |
if (read_argp == NULL) { |
if (read_argp == NULL) { |
Line 1799 puffs_strategy(void *v) |
|
Line 1849 puffs_strategy(void *v) |
|
goto out; |
goto out; |
} |
} |
|
|
tomove = PUFFS_TOMOVE(bp->b_bcount, pmp); |
|
|
|
read_argp->pvnr_ioflag = 0; |
read_argp->pvnr_ioflag = 0; |
read_argp->pvnr_resid = tomove; |
read_argp->pvnr_resid = tomove; |
read_argp->pvnr_offset = bp->b_blkno << DEV_BSHIFT; |
read_argp->pvnr_offset = bp->b_blkno << DEV_BSHIFT; |
Line 1823 puffs_strategy(void *v) |
|
Line 1871 puffs_strategy(void *v) |
|
(void)memcpy(bp->b_data, read_argp->pvnr_data, moved); |
(void)memcpy(bp->b_data, read_argp->pvnr_data, moved); |
bp->b_resid = bp->b_bcount - moved; |
bp->b_resid = bp->b_bcount - moved; |
} else { |
} else { |
|
/* |
|
* make pages read-only before we write them if we want |
|
* write caching info |
|
*/ |
|
if (PUFFS_WCACHEINFO(pmp)) { |
|
struct uvm_object *uobj = &vp->v_uobj; |
|
int npages = (bp->b_bcount + PAGE_SIZE-1) >> PAGE_SHIFT; |
|
struct vm_page *vmp; |
|
int i; |
|
|
|
for (i = 0; i < npages; i++) { |
|
vmp= uvm_pageratop((vaddr_t)bp->b_data |
|
+ (i << PAGE_SHIFT)); |
|
DPRINTF(("puffs_strategy: write-protecting " |
|
"vp %p page %p, offset %" PRId64"\n", |
|
vp, vmp, vmp->offset)); |
|
simple_lock(&uobj->vmobjlock); |
|
vmp->flags |= PG_RDONLY; |
|
pmap_page_protect(vmp, VM_PROT_READ); |
|
simple_unlock(&uobj->vmobjlock); |
|
} |
|
} |
|
|
argsize = sizeof(struct puffs_vnreq_write) + bp->b_bcount; |
argsize = sizeof(struct puffs_vnreq_write) + bp->b_bcount; |
write_argp = malloc(argsize, M_PUFFS, M_NOWAIT | M_ZERO); |
write_argp = malloc(argsize, M_PUFFS, M_NOWAIT | M_ZERO); |
if (write_argp == NULL) { |
if (write_argp == NULL) { |
Line 1830 puffs_strategy(void *v) |
|
Line 1901 puffs_strategy(void *v) |
|
goto out; |
goto out; |
} |
} |
|
|
tomove = PUFFS_TOMOVE(bp->b_bcount, pmp); |
|
|
|
write_argp->pvnr_ioflag = 0; |
write_argp->pvnr_ioflag = 0; |
write_argp->pvnr_resid = tomove; |
write_argp->pvnr_resid = tomove; |
write_argp->pvnr_offset = bp->b_blkno << DEV_BSHIFT; |
write_argp->pvnr_offset = bp->b_blkno << DEV_BSHIFT; |
Line 1877 puffs_strategy(void *v) |
|
Line 1946 puffs_strategy(void *v) |
|
bp->b_flags |= B_ERROR; |
bp->b_flags |= B_ERROR; |
} |
} |
|
|
biodone(bp); |
if ((bp->b_flags & (B_READ | B_ASYNC)) != (B_READ | B_ASYNC)) |
|
biodone(bp); |
return error; |
return error; |
} |
} |
|
|
Line 1951 puffs_bmap(void *v) |
|
Line 2021 puffs_bmap(void *v) |
|
return 0; |
return 0; |
} |
} |
|
|
|
/* |
|
* Handle getpages faults in puffs. We let genfs_getpages() do most |
|
* of the dirty work, but we come in this route to do accounting tasks. |
|
* If the user server has specified functions for cache notifications |
|
* about reads and/or writes, we record which type of operation we got, |
|
* for which page range, and proceed to issue a FAF notification to the |
|
* server about it. |
|
*/ |
|
int |
|
puffs_getpages(void *v) |
|
{ |
|
struct vop_getpages_args /* { |
|
const struct vnodeop_desc *a_desc; |
|
struct vnode *a_vp; |
|
voff_t a_offset; |
|
struct vm_page **a_m; |
|
int *a_count; |
|
int a_centeridx; |
|
vm_prot_t a_access_type; |
|
int a_advice; |
|
int a_flags; |
|
} */ *ap = v; |
|
struct puffs_mount *pmp; |
|
struct vnode *vp; |
|
struct vm_page **pgs; |
|
struct puffs_park *ppark = NULL; |
|
struct puffs_cacheinfo *pcinfo = NULL; |
|
struct puffs_cacherun *pcrun; |
|
size_t runsizes; |
|
int i, npages, si, streakon; |
|
int error, locked, write; |
|
|
|
pmp = MPTOPUFFSMP(ap->a_vp->v_mount); |
|
npages = *ap->a_count; |
|
pgs = ap->a_m; |
|
vp = ap->a_vp; |
|
locked = (ap->a_flags & PGO_LOCKED) != 0; |
|
write = (ap->a_access_type & VM_PROT_WRITE) != 0; |
|
|
|
/* ccg xnaht - gets Wuninitialized wrong */ |
|
pcrun = NULL; |
|
runsizes = 0; |
|
|
|
if (write && PUFFS_WCACHEINFO(pmp)) { |
|
/* allocate worst-case memory */ |
|
runsizes = ((npages / 2) + 1) * sizeof(struct puffs_cacherun); |
|
pcinfo = malloc(sizeof(struct puffs_cacheinfo) + runsizes, |
|
M_PUFFS, M_ZERO | locked ? M_NOWAIT : M_WAITOK); |
|
|
|
/* |
|
* can't block if we're locked and can't mess up caching |
|
* information for fs server. so come back later, please |
|
*/ |
|
if (pcinfo == NULL) { |
|
error = ENOMEM; |
|
goto out; |
|
} |
|
|
|
ppark = malloc(sizeof(struct puffs_park), M_PUFFS, M_NOWAIT); |
|
if (ppark == NULL) { |
|
error = ENOMEM; |
|
goto out; |
|
} |
|
|
|
pcrun = pcinfo->pcache_runs; |
|
} |
|
|
|
error = genfs_getpages(v); |
|
if (error) |
|
goto out; |
|
|
|
if (PUFFS_WCACHEINFO(pmp) == 0) |
|
goto out; |
|
|
|
/* |
|
* Let's see whose fault it was and inform the user server of |
|
* possibly read/written pages. Map pages from read faults |
|
* strictly read-only, since otherwise we might miss info on |
|
* when the page is actually write-faulted to. |
|
*/ |
|
if (!locked) |
|
simple_lock(&vp->v_uobj.vmobjlock); |
|
for (i = 0, si = 0, streakon = 0; i < npages; i++) { |
|
if (pgs[i] == NULL || pgs[i] == PGO_DONTCARE) { |
|
if (streakon && write) { |
|
streakon = 0; |
|
pcrun[si].pcache_runend |
|
= trunc_page(pgs[i]->offset) + PAGE_MASK; |
|
si++; |
|
} |
|
continue; |
|
} |
|
if (streakon == 0 && write) { |
|
streakon = 1; |
|
pcrun[si].pcache_runstart = pgs[i]->offset; |
|
} |
|
|
|
if (!write) |
|
pgs[i]->flags |= PG_RDONLY; |
|
} |
|
/* was the last page part of our streak? */ |
|
if (streakon) { |
|
pcrun[si].pcache_runend |
|
= trunc_page(pgs[i-1]->offset) + PAGE_MASK; |
|
si++; |
|
} |
|
if (!locked) |
|
simple_unlock(&vp->v_uobj.vmobjlock); |
|
|
|
KASSERT(si <= (npages / 2) + 1); |
|
|
|
/* send results to userspace */ |
|
if (write) |
|
puffs_cacheop(pmp, ppark, pcinfo, |
|
sizeof(struct puffs_cacheinfo) + runsizes, VPTOPNC(vp)); |
|
|
|
out: |
|
if (error) { |
|
if (pcinfo != NULL) |
|
free(pcinfo, M_PUFFS); |
|
if (ppark != NULL) |
|
free(ppark, M_PUFFS); |
|
} |
|
|
|
return error; |
|
} |
|
|
int |
int |
puffs_lock(void *v) |
puffs_lock(void *v) |