version 1.182, 2014/07/25 08:20:52 |
version 1.182.2.9, 2014/11/05 18:16:17 |
Line 73 int puffs_vnop_symlink(void *); |
|
Line 73 int puffs_vnop_symlink(void *); |
|
int puffs_vnop_rename(void *); |
int puffs_vnop_rename(void *); |
int puffs_vnop_read(void *); |
int puffs_vnop_read(void *); |
int puffs_vnop_write(void *); |
int puffs_vnop_write(void *); |
|
int puffs_vnop_fallocate(void *); |
|
int puffs_vnop_fdiscard(void *); |
int puffs_vnop_fcntl(void *); |
int puffs_vnop_fcntl(void *); |
int puffs_vnop_ioctl(void *); |
int puffs_vnop_ioctl(void *); |
int puffs_vnop_inactive(void *); |
int puffs_vnop_inactive(void *); |
Line 113 const struct vnodeopv_entry_desc puffs_v |
|
Line 115 const struct vnodeopv_entry_desc puffs_v |
|
{ &vop_setattr_desc, puffs_vnop_checkop }, /* setattr */ |
{ &vop_setattr_desc, puffs_vnop_checkop }, /* setattr */ |
{ &vop_read_desc, puffs_vnop_checkop }, /* read */ |
{ &vop_read_desc, puffs_vnop_checkop }, /* read */ |
{ &vop_write_desc, puffs_vnop_checkop }, /* write */ |
{ &vop_write_desc, puffs_vnop_checkop }, /* write */ |
{ &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */ |
{ &vop_fallocate_desc, puffs_vnop_fallocate }, /* fallocate */ |
{ &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */ |
{ &vop_fdiscard_desc, puffs_vnop_fdiscard }, /* fdiscard */ |
{ &vop_fsync_desc, puffs_vnop_fsync }, /* REAL fsync */ |
{ &vop_fsync_desc, puffs_vnop_fsync }, /* REAL fsync */ |
{ &vop_seek_desc, puffs_vnop_checkop }, /* seek */ |
{ &vop_seek_desc, puffs_vnop_checkop }, /* seek */ |
{ &vop_remove_desc, puffs_vnop_checkop }, /* remove */ |
{ &vop_remove_desc, puffs_vnop_checkop }, /* remove */ |
Line 668 puffs_vnop_lookup(void *v) |
|
Line 670 puffs_vnop_lookup(void *v) |
|
* match the userland cookie anymore: is the node known? |
* match the userland cookie anymore: is the node known? |
*/ |
*/ |
if (vp == NULL) { |
if (vp == NULL) { |
error = puffs_cookie2vnode(pmp, lookup_msg->pvnr_newnode, |
|
1, 1, &vp); |
|
} |
|
|
|
if (error == PUFFS_NOSUCHCOOKIE) { |
|
error = puffs_getvnode(dvp->v_mount, |
error = puffs_getvnode(dvp->v_mount, |
lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype, |
lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype, |
lookup_msg->pvnr_size, lookup_msg->pvnr_rdev, &vp); |
lookup_msg->pvnr_size, lookup_msg->pvnr_rdev, &vp); |
Line 684 puffs_vnop_lookup(void *v) |
|
Line 681 puffs_vnop_lookup(void *v) |
|
} |
} |
|
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); |
} else if (error) { |
|
puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp), |
|
lookup_msg->pvnr_newnode, ap->a_cnp); |
|
goto out; |
|
} |
} |
|
|
/* |
/* |
Line 893 puffs_vnop_open(void *v) |
|
Line 886 puffs_vnop_open(void *v) |
|
PUFFS_MSG_VARS(vn, open); |
PUFFS_MSG_VARS(vn, open); |
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
|
struct puffs_node *pn = VPTOPP(vp); |
int mode = ap->a_mode; |
int mode = ap->a_mode; |
int error; |
int error; |
|
|
Line 913 puffs_vnop_open(void *v) |
|
Line 907 puffs_vnop_open(void *v) |
|
PUFFS_MSG_ENQUEUEWAIT2(pmp, park_open, vp->v_data, NULL, error); |
PUFFS_MSG_ENQUEUEWAIT2(pmp, park_open, vp->v_data, NULL, error); |
error = checkerr(pmp, error, __func__); |
error = checkerr(pmp, error, __func__); |
|
|
|
if (open_msg->pvnr_oflags & PUFFS_OPEN_IO_DIRECT) { |
|
if (mode & FREAD) |
|
pn->pn_stat |= PNODE_RDIRECT; |
|
if (mode & FWRITE) |
|
pn->pn_stat |= PNODE_WDIRECT; |
|
} |
out: |
out: |
DPRINTF(("puffs_open: returning %d\n", error)); |
DPRINTF(("puffs_open: returning %d\n", error)); |
PUFFS_MSG_RELEASE(open); |
PUFFS_MSG_RELEASE(open); |
Line 1132 puffs_vnop_getattr(void *v) |
|
Line 1132 puffs_vnop_getattr(void *v) |
|
return error; |
return error; |
} |
} |
|
|
|
static void |
|
zerofill_lastpage(struct vnode *vp, voff_t off) |
|
{ |
|
char zbuf[PAGE_SIZE]; |
|
struct iovec iov; |
|
struct uio uio; |
|
vsize_t len; |
|
int error; |
|
|
|
if (trunc_page(off) == off) |
|
return; |
|
|
|
if (vp->v_writecount == 0) |
|
return; |
|
|
|
len = round_page(off) - off; |
|
memset(zbuf, 0, len); |
|
|
|
iov.iov_base = zbuf; |
|
iov.iov_len = len; |
|
UIO_SETUP_SYSSPACE(&uio); |
|
uio.uio_iov = &iov; |
|
uio.uio_iovcnt = 1; |
|
uio.uio_offset = off; |
|
uio.uio_resid = len; |
|
uio.uio_rw = UIO_WRITE; |
|
|
|
error = ubc_uiomove(&vp->v_uobj, &uio, len, |
|
UVM_ADV_SEQUENTIAL, UBC_WRITE|UBC_UNMAP_FLAG(vp)); |
|
if (error) { |
|
DPRINTF(("zero-fill 0x%" PRIxVSIZE "@0x%" PRIx64 |
|
" failed: error = %d\n", len, off, error)); |
|
} |
|
|
|
return; |
|
} |
|
|
static int |
static int |
dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred, int flags) |
dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred, int flags) |
{ |
{ |
PUFFS_MSG_VARS(vn, setattr); |
PUFFS_MSG_VARS(vn, setattr); |
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
struct puffs_node *pn = vp->v_data; |
struct puffs_node *pn = vp->v_data; |
|
vsize_t oldsize = vp->v_size; |
int error = 0; |
int error = 0; |
|
|
KASSERT(!(flags & SETATTR_CHSIZE) || mutex_owned(&pn->pn_sizemtx)); |
KASSERT(!(flags & SETATTR_CHSIZE) || mutex_owned(&pn->pn_sizemtx)); |
Line 1210 dosetattr(struct vnode *vp, struct vattr |
|
Line 1248 dosetattr(struct vnode *vp, struct vattr |
|
} |
} |
|
|
if (vap->va_size != VNOVAL) { |
if (vap->va_size != VNOVAL) { |
|
/* |
|
* If we truncated the file, make sure the data beyond |
|
* EOF in last page does not remain in cache, otherwise |
|
* if the file is later truncated to a larger size (creating |
|
* a hole), that area will not return zeroes as it |
|
* should. |
|
*/ |
|
if ((flags & SETATTR_CHSIZE) && PUFFS_USE_PAGECACHE(pmp) && |
|
(vap->va_size < oldsize)) |
|
zerofill_lastpage(vp, vap->va_size); |
|
|
pn->pn_serversize = vap->va_size; |
pn->pn_serversize = vap->va_size; |
if (flags & SETATTR_CHSIZE) |
if (flags & SETATTR_CHSIZE) |
uvm_vnp_setsize(vp, vap->va_size); |
uvm_vnp_setsize(vp, vap->va_size); |
Line 1394 puffs_vnop_reclaim(void *v) |
|
Line 1443 puffs_vnop_reclaim(void *v) |
|
} */ *ap = v; |
} */ *ap = v; |
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
struct puffs_node *pnode = vp->v_data; |
|
bool notifyserver = true; |
bool notifyserver = true; |
|
|
/* |
/* |
Line 1417 puffs_vnop_reclaim(void *v) |
|
Line 1465 puffs_vnop_reclaim(void *v) |
|
* that and someone might race us into node creation |
* that and someone might race us into node creation |
*/ |
*/ |
mutex_enter(&pmp->pmp_lock); |
mutex_enter(&pmp->pmp_lock); |
LIST_REMOVE(pnode, pn_hashent); |
|
if (PUFFS_USE_NAMECACHE(pmp)) |
if (PUFFS_USE_NAMECACHE(pmp)) |
cache_purge(vp); |
cache_purge(vp); |
mutex_exit(&pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
Line 1432 puffs_vnop_reclaim(void *v) |
|
Line 1479 puffs_vnop_reclaim(void *v) |
|
if (__predict_true(VPTOPP(vp)->pn_parent != NULL)) |
if (__predict_true(VPTOPP(vp)->pn_parent != NULL)) |
vrele(VPTOPP(vp)->pn_parent); |
vrele(VPTOPP(vp)->pn_parent); |
else |
else |
KASSERT(vp->v_vflag & VV_ROOT); |
KASSERT(vp->v_type == VNON || (vp->v_vflag & VV_ROOT)); |
} |
} |
|
|
puffs_putvnode(vp); |
puffs_putvnode(vp); |
vp->v_data = NULL; |
|
|
|
return 0; |
return 0; |
} |
} |
Line 1810 puffs_vnop_remove(void *v) |
|
Line 1856 puffs_vnop_remove(void *v) |
|
|
|
PUFFS_MSG_RELEASE(remove); |
PUFFS_MSG_RELEASE(remove); |
|
|
|
puffs_updatenode(VPTOPP(dvp), PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, 0); |
|
|
RELEPN_AND_VP(dvp, dpn); |
RELEPN_AND_VP(dvp, dpn); |
RELEPN_AND_VP(vp, pn); |
RELEPN_AND_VP(vp, pn); |
|
|
Line 1927 puffs_vnop_rmdir(void *v) |
|
Line 1975 puffs_vnop_rmdir(void *v) |
|
|
|
PUFFS_MSG_RELEASE(rmdir); |
PUFFS_MSG_RELEASE(rmdir); |
|
|
|
puffs_updatenode(VPTOPP(dvp), PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, 0); |
|
|
/* XXX: some call cache_purge() *for both vnodes* here, investigate */ |
/* XXX: some call cache_purge() *for both vnodes* here, investigate */ |
RELEPN_AND_VP(dvp, dpn); |
RELEPN_AND_VP(dvp, dpn); |
RELEPN_AND_VP(vp, pn); |
RELEPN_AND_VP(vp, pn); |
Line 1972 puffs_vnop_link(void *v) |
|
Line 2022 puffs_vnop_link(void *v) |
|
* XXX: stay in touch with the cache. I don't like this, but |
* XXX: stay in touch with the cache. I don't like this, but |
* don't have a better solution either. See also puffs_rename(). |
* don't have a better solution either. See also puffs_rename(). |
*/ |
*/ |
if (error == 0) |
if (error == 0) { |
puffs_updatenode(pn, PUFFS_UPDATECTIME, 0); |
puffs_updatenode(pn, PUFFS_UPDATECTIME, 0); |
|
puffs_updatenode(VPTOPP(dvp), |
|
PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, 0); |
|
} |
|
|
RELEPN_AND_VP(dvp, dpn); |
RELEPN_AND_VP(dvp, dpn); |
puffs_releasenode(pn); |
puffs_releasenode(pn); |
Line 2138 puffs_vnop_rename(void *v) |
|
Line 2191 puffs_vnop_rename(void *v) |
|
*/ |
*/ |
if (error == 0) { |
if (error == 0) { |
puffs_updatenode(fpn, PUFFS_UPDATECTIME, 0); |
puffs_updatenode(fpn, PUFFS_UPDATECTIME, 0); |
|
puffs_updatenode(VPTOPP(fdvp), |
|
PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, 0); |
|
if (fdvp != tdvp) |
|
puffs_updatenode(VPTOPP(tdvp), |
|
PUFFS_UPDATECTIME|PUFFS_UPDATEMTIME, |
|
0); |
|
|
if (PUFFS_USE_DOTDOTCACHE(pmp) && |
if (PUFFS_USE_DOTDOTCACHE(pmp) && |
(VPTOPP(fvp)->pn_parent != tdvp)) |
(VPTOPP(fvp)->pn_parent != tdvp)) |
Line 2181 puffs_vnop_read(void *v) |
|
Line 2240 puffs_vnop_read(void *v) |
|
} */ *ap = v; |
} */ *ap = v; |
PUFFS_MSG_VARS(vn, read); |
PUFFS_MSG_VARS(vn, read); |
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
|
struct puffs_node *pn = VPTOPP(vp); |
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
struct uio *uio = ap->a_uio; |
struct uio *uio = ap->a_uio; |
size_t tomove, argsize; |
size_t tomove, argsize; |
Line 2194 puffs_vnop_read(void *v) |
|
Line 2254 puffs_vnop_read(void *v) |
|
if (uio->uio_resid == 0) |
if (uio->uio_resid == 0) |
return 0; |
return 0; |
if (uio->uio_offset < 0) |
if (uio->uio_offset < 0) |
return EINVAL; |
return EFBIG; |
|
|
if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) { |
if (vp->v_type == VREG && |
|
PUFFS_USE_PAGECACHE(pmp) && |
|
!(pn->pn_stat & PNODE_RDIRECT)) { |
const int advice = IO_ADV_DECODE(ap->a_ioflag); |
const int advice = IO_ADV_DECODE(ap->a_ioflag); |
|
|
while (uio->uio_resid > 0) { |
while (uio->uio_resid > 0) { |
Line 2299 puffs_vnop_write(void *v) |
|
Line 2361 puffs_vnop_write(void *v) |
|
error = uflags = 0; |
error = uflags = 0; |
write_msg = NULL; |
write_msg = NULL; |
|
|
|
/* std sanity */ |
|
if (uio->uio_resid == 0) |
|
return 0; |
|
if (uio->uio_offset < 0) |
|
return EFBIG; |
|
|
mutex_enter(&pn->pn_sizemtx); |
mutex_enter(&pn->pn_sizemtx); |
|
|
if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) { |
if (vp->v_type == VREG && |
|
PUFFS_USE_PAGECACHE(pmp) && |
|
!(pn->pn_stat & PNODE_WDIRECT)) { |
ubcflags = UBC_WRITE | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp); |
ubcflags = UBC_WRITE | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp); |
|
|
/* |
/* |
Line 2313 puffs_vnop_write(void *v) |
|
Line 2383 puffs_vnop_write(void *v) |
|
|
|
origoff = uio->uio_offset; |
origoff = uio->uio_offset; |
while (uio->uio_resid > 0) { |
while (uio->uio_resid > 0) { |
if (vp->v_mount->mnt_flag & MNT_RELATIME) |
|
uflags |= PUFFS_UPDATEATIME; |
|
uflags |= PUFFS_UPDATECTIME; |
|
uflags |= PUFFS_UPDATEMTIME; |
|
oldoff = uio->uio_offset; |
oldoff = uio->uio_offset; |
bytelen = uio->uio_resid; |
bytelen = uio->uio_resid; |
|
|
Line 2377 puffs_vnop_write(void *v) |
|
Line 2443 puffs_vnop_write(void *v) |
|
error = VOP_PUTPAGES(vp, trunc_page(origoff), |
error = VOP_PUTPAGES(vp, trunc_page(origoff), |
round_page(uio->uio_offset), PGO_CLEANIT); |
round_page(uio->uio_offset), PGO_CLEANIT); |
} |
} |
|
|
puffs_updatenode(VPTOPP(vp), uflags, vp->v_size); |
|
} else { |
} else { |
/* tomove is non-increasing */ |
/* tomove is non-increasing */ |
tomove = PUFFS_TOMOVE(uio->uio_resid, pmp); |
tomove = PUFFS_TOMOVE(uio->uio_resid, pmp); |
Line 2412 puffs_vnop_write(void *v) |
|
Line 2476 puffs_vnop_write(void *v) |
|
} |
} |
|
|
/* adjust file size */ |
/* adjust file size */ |
if (vp->v_size < uio->uio_offset) |
if (vp->v_size < uio->uio_offset) { |
|
uflags |= PUFFS_UPDATESIZE; |
uvm_vnp_setsize(vp, uio->uio_offset); |
uvm_vnp_setsize(vp, uio->uio_offset); |
|
} |
|
|
/* didn't move everything? bad userspace. bail */ |
/* didn't move everything? bad userspace. bail */ |
if (write_msg->pvnr_resid != 0) { |
if (write_msg->pvnr_resid != 0) { |
Line 2424 puffs_vnop_write(void *v) |
|
Line 2490 puffs_vnop_write(void *v) |
|
puffs_msgmem_release(park_write); |
puffs_msgmem_release(park_write); |
} |
} |
|
|
|
if (vp->v_mount->mnt_flag & MNT_RELATIME) |
|
uflags |= PUFFS_UPDATEATIME; |
|
uflags |= PUFFS_UPDATECTIME; |
|
uflags |= PUFFS_UPDATEMTIME; |
|
puffs_updatenode(VPTOPP(vp), uflags, vp->v_size); |
|
|
mutex_exit(&pn->pn_sizemtx); |
mutex_exit(&pn->pn_sizemtx); |
return error; |
return error; |
} |
} |
|
|
int |
int |
|
puffs_vnop_fallocate(void *v) |
|
{ |
|
struct vop_fallocate_args /* { |
|
const struct vnodeop_desc *a_desc; |
|
struct vnode *a_vp; |
|
off_t a_pos; |
|
off_t a_len; |
|
} */ *ap = v; |
|
struct vnode *vp = ap->a_vp; |
|
struct puffs_node *pn = VPTOPP(vp); |
|
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
|
PUFFS_MSG_VARS(vn, fallocate); |
|
int error; |
|
|
|
mutex_enter(&pn->pn_sizemtx); |
|
|
|
PUFFS_MSG_ALLOC(vn, fallocate); |
|
fallocate_msg->pvnr_off = ap->a_pos; |
|
fallocate_msg->pvnr_len = ap->a_len; |
|
puffs_msg_setinfo(park_fallocate, PUFFSOP_VN, |
|
PUFFS_VN_FALLOCATE, VPTOPNC(vp)); |
|
|
|
PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fallocate, vp->v_data, NULL, error); |
|
error = checkerr(pmp, error, __func__); |
|
PUFFS_MSG_RELEASE(fallocate); |
|
|
|
switch (error) { |
|
case 0: |
|
break; |
|
case EAGAIN: |
|
error = EIO; |
|
/* FALLTHROUGH */ |
|
default: |
|
goto out; |
|
} |
|
|
|
if (ap->a_pos + ap->a_len > vp->v_size) { |
|
uvm_vnp_setsize(vp, ap->a_pos + ap->a_len); |
|
puffs_updatenode(pn, PUFFS_UPDATESIZE, vp->v_size); |
|
} |
|
out: |
|
mutex_exit(&pn->pn_sizemtx); |
|
|
|
return error; |
|
} |
|
|
|
int |
|
puffs_vnop_fdiscard(void *v) |
|
{ |
|
struct vop_fdiscard_args /* { |
|
const struct vnodeop_desc *a_desc; |
|
struct vnode *a_vp; |
|
off_t a_pos; |
|
off_t a_len; |
|
} */ *ap = v; |
|
struct vnode *vp = ap->a_vp; |
|
struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount); |
|
PUFFS_MSG_VARS(vn, fdiscard); |
|
int error; |
|
|
|
PUFFS_MSG_ALLOC(vn, fdiscard); |
|
fdiscard_msg->pvnr_off = ap->a_pos; |
|
fdiscard_msg->pvnr_len = ap->a_len; |
|
puffs_msg_setinfo(park_fdiscard, PUFFSOP_VN, |
|
PUFFS_VN_FALLOCATE, VPTOPNC(vp)); |
|
|
|
PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fdiscard, vp->v_data, NULL, error); |
|
error = checkerr(pmp, error, __func__); |
|
PUFFS_MSG_RELEASE(fdiscard); |
|
|
|
return error; |
|
} |
|
|
|
int |
puffs_vnop_print(void *v) |
puffs_vnop_print(void *v) |
{ |
{ |
struct vop_print_args /* { |
struct vop_print_args /* { |
Line 2695 puffs_vnop_strategy(void *v) |
|
Line 2841 puffs_vnop_strategy(void *v) |
|
if (dobiodone == 0) |
if (dobiodone == 0) |
goto out; |
goto out; |
|
|
/* |
|
* XXXXXXXX: wrong, but kernel can't survive strategy |
|
* failure currently. Here, have one more X: X. |
|
*/ |
|
if (error != ENOMEM) |
|
error = 0; |
|
|
|
error = checkerr(pmp, error, __func__); |
error = checkerr(pmp, error, __func__); |
if (error) |
if (error) |
goto out; |
goto out; |