Beispiel #1
0
/*
 * XXX: can't use callremove now because can't catch setbacks with
 * it due to lack of a pnode argument.
 */
static int
puffs_vnop_remove(struct vop_nremove_args *ap)
{
    PUFFS_MSG_VARS(vn, remove);
    struct vnode *dvp = ap->a_dvp;
    struct vnode *vp;
    struct puffs_node *dpn = VPTOPP(dvp);
    struct puffs_node *pn;
    struct nchandle *nch = ap->a_nch;
    struct namecache *ncp = nch->ncp;
    struct ucred *cred = ap->a_cred;
    struct mount *mp = dvp->v_mount;
    struct puffs_mount *pmp = MPTOPUFFSMP(mp);
    int error;

    if (!EXISTSOP(pmp, REMOVE))
        return EOPNOTSUPP;

    error = vget(dvp, LK_EXCLUSIVE);
    if (error != 0) {
        DPRINTF(("puffs_vnop_remove: EAGAIN on parent vnode %p %s\n",
                 dvp, ncp->nc_name));
        return EAGAIN;
    }

    error = cache_vget(nch, cred, LK_EXCLUSIVE, &vp);
    if (error != 0) {
        DPRINTF(("puffs_vnop_remove: cache_vget error: %p %s\n",
                 dvp, ncp->nc_name));
        return EAGAIN;
    }
    if (vp->v_type == VDIR) {
        error = EISDIR;
        goto out;
    }

    pn = VPTOPP(vp);
    PUFFS_MSG_ALLOC(vn, remove);
    remove_msg->pvnr_cookie_targ = VPTOPNC(vp);
    puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
                 ncp, cred);
    puffs_msg_setinfo(park_remove, PUFFSOP_VN,
                      PUFFS_VN_REMOVE, VPTOPNC(dvp));

    puffs_msg_enqueue(pmp, park_remove);
    error = puffs_msg_wait2(pmp, park_remove, dpn, pn);

    PUFFS_MSG_RELEASE(remove);

    error = checkerr(pmp, error, __func__);

out:
    vput(dvp);
    vn_unlock(vp);
    if (error == 0)
        cache_unlink(nch);
    vrele(vp);
    return error;
}
Beispiel #2
0
static int
puffs_vnop_link(struct vop_nlink_args *ap)
{
    PUFFS_MSG_VARS(vn, link);
    struct vnode *dvp = ap->a_dvp;
    struct vnode *vp = ap->a_vp;
    struct puffs_node *dpn = VPTOPP(dvp);
    struct puffs_node *pn = VPTOPP(vp);
    struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
    struct nchandle *nch = ap->a_nch;
    struct namecache *ncp = nch->ncp;
    struct ucred *cred = ap->a_cred;
    int error;

    if (!EXISTSOP(pmp, LINK))
        return EOPNOTSUPP;

    if (vp->v_mount != dvp->v_mount)
        return EXDEV;

    if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
        DPRINTF(("puffs_vnop_link: EAGAIN on ncp %p %s\n",
                 ncp, ncp->nc_name));
        return EAGAIN;
    }

    PUFFS_MSG_ALLOC(vn, link);
    link_msg->pvnr_cookie_targ = VPTOPNC(vp);
    puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred,
                 ncp, cred);
    puffs_msg_setinfo(park_link, PUFFSOP_VN,
                      PUFFS_VN_LINK, VPTOPNC(dvp));

    puffs_msg_enqueue(pmp, park_link);
    error = puffs_msg_wait2(pmp, park_link, dpn, pn);

    PUFFS_MSG_RELEASE(link);

    error = checkerr(pmp, error, __func__);

    /*
     * 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(pn, PUFFS_UPDATECTIME);
    }

    vput(dvp);
    if (error == 0) {
        cache_setunresolved(nch);
        cache_setvp(nch, vp);
    }
    return error;
}
Beispiel #3
0
static void
callreclaim(struct puffs_mount *pmp, puffs_cookie_t ck)
{
    PUFFS_MSG_VARS(vn, reclaim);

    if (!EXISTSOP(pmp, RECLAIM))
        return;

    PUFFS_MSG_ALLOC(vn, reclaim);
    puffs_msg_setfaf(park_reclaim);
    puffs_msg_setinfo(park_reclaim, PUFFSOP_VN, PUFFS_VN_RECLAIM, ck);

    puffs_msg_enqueue(pmp, park_reclaim);
    PUFFS_MSG_RELEASE(reclaim);
}
Beispiel #4
0
void
puffs_senderr(struct puffs_mount *pmp, int type, int error,
	const char *str, puffs_cookie_t ck)
{
	struct puffs_msgpark *park;
	struct puffs_error *perr;

	puffs_msgmem_alloc(sizeof(struct puffs_error), &park, (void *)&perr, 1);
	puffs_msg_setfaf(park);
	puffs_msg_setinfo(park, PUFFSOP_ERROR, type, ck);

	perr->perr_error = error;
	strlcpy(perr->perr_str, str, sizeof(perr->perr_str));

	puffs_msg_enqueue(pmp, park);
	puffs_msgmem_release(park);
}
Beispiel #5
0
static int
puffs_vnop_close(struct vop_close_args *ap)
{
    PUFFS_MSG_VARS(vn, close);
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);

    vn_lock(vp, LK_UPGRADE | LK_RETRY);

    if (!EXISTSOP(pmp, CLOSE))
        return vop_stdclose(ap);

    PUFFS_MSG_ALLOC(vn, close);
    puffs_msg_setfaf(park_close);
    close_msg->pvnr_fflag = ap->a_fflag;
    puffs_msg_setinfo(park_close, PUFFSOP_VN,
                      PUFFS_VN_CLOSE, VPTOPNC(vp));

    puffs_msg_enqueue(pmp, park_close);
    PUFFS_MSG_RELEASE(close);
    return vop_stdclose(ap);
}
Beispiel #6
0
/* XXX: callinactive can't setback */
static int
puffs_vnop_inactive(struct vop_inactive_args *ap)
{
    PUFFS_MSG_VARS(vn, inactive);
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    struct puffs_node *pnode = VPTOPP(vp);

    flushvncache(vp, MNT_NOWAIT);

    if (doinact(pmp, pnode->pn_stat & PNODE_DOINACT)) {
        /*
         * do not wait for reply from userspace, otherwise it may
         * deadlock.
         */

        PUFFS_MSG_ALLOC(vn, inactive);
        puffs_msg_setfaf(park_inactive);
        puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
                          PUFFS_VN_INACTIVE, VPTOPNC(vp));

        puffs_msg_enqueue(pmp, park_inactive);
        PUFFS_MSG_RELEASE(inactive);
    }
    pnode->pn_stat &= ~PNODE_DOINACT;

    /*
     * file server thinks it's gone?  then don't be afraid care,
     * node's life was already all it would ever be
     */
    if (pnode->pn_stat & PNODE_NOREFS) {
        pnode->pn_stat |= PNODE_DYING;
        vrecycle(vp);
    }

    return 0;
}
Beispiel #7
0
static int
dosetattr(struct vnode *vp, struct vattr *vap, struct ucred *cred, int flags)
{
    PUFFS_MSG_VARS(vn, setattr);
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    struct puffs_node *pn = VPTOPP(vp);
    int error = 0;

    if ((vp->v_mount->mnt_flag & MNT_RDONLY) &&
            (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
             || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
             || vap->va_mode != (mode_t)VNOVAL))
        return EROFS;

    if ((vp->v_mount->mnt_flag & MNT_RDONLY)
            && vp->v_type == VREG && vap->va_size != VNOVAL)
        return EROFS;

    /*
     * Flush metacache first.  If we are called with some explicit
     * parameters, treat them as information overriding metacache
     * information.
     */
    if (pn->pn_stat & PNODE_METACACHE_MASK) {
        if ((pn->pn_stat & PNODE_METACACHE_ATIME)
                && vap->va_atime.tv_sec == VNOVAL)
            vap->va_atime = pn->pn_mc_atime;
        if ((pn->pn_stat & PNODE_METACACHE_CTIME)
                && vap->va_ctime.tv_sec == VNOVAL)
            vap->va_ctime = pn->pn_mc_ctime;
        if ((pn->pn_stat & PNODE_METACACHE_MTIME)
                && vap->va_mtime.tv_sec == VNOVAL)
            vap->va_mtime = pn->pn_mc_mtime;
        if ((pn->pn_stat & PNODE_METACACHE_SIZE)
                && vap->va_size == VNOVAL)
            vap->va_size = pn->pn_mc_size;

        pn->pn_stat &= ~PNODE_METACACHE_MASK;
    }

    PUFFS_MSG_ALLOC(vn, setattr);
    (void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr));
    puffs_credcvt(&setattr_msg->pvnr_cred, cred);
    puffs_msg_setinfo(park_setattr, PUFFSOP_VN,
                      PUFFS_VN_SETATTR, VPTOPNC(vp));
    if (flags & SETATTR_ASYNC)
        puffs_msg_setfaf(park_setattr);

    puffs_msg_enqueue(pmp, park_setattr);
    if ((flags & SETATTR_ASYNC) == 0)
        error = puffs_msg_wait2(pmp, park_setattr, vp->v_data, NULL);
    PUFFS_MSG_RELEASE(setattr);
    if ((flags & SETATTR_ASYNC) == 0) {
        error = checkerr(pmp, error, __func__);
        if (error)
            return error;
    } else {
        error = 0;
    }

    if (vap->va_size != VNOVAL) {
        pn->pn_serversize = vap->va_size;
        if (flags & SETATTR_CHSIZE)
            puffs_meta_setsize(vp, vap->va_size, 0);
    }

    return 0;
}