Ejemplo n.º 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;
}
Ejemplo n.º 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;
}
Ejemplo n.º 3
0
static int
puffs_vnop_advlock(struct vop_advlock_args *ap)
{
    PUFFS_MSG_VARS(vn, advlock);
    struct vnode *vp = ap->a_vp;
    struct puffs_node *pn = VPTOPP(vp);
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    int error;

    if (!EXISTSOP(pmp, ADVLOCK))
        return lf_advlock(ap, &pn->pn_lockf, vp->v_filesize);

    PUFFS_MSG_ALLOC(vn, advlock);
    (void)memcpy(&advlock_msg->pvnr_fl, ap->a_fl,
                 sizeof(advlock_msg->pvnr_fl));
    advlock_msg->pvnr_id = ap->a_id;
    advlock_msg->pvnr_op = ap->a_op;
    advlock_msg->pvnr_flags = ap->a_flags;
    puffs_msg_setinfo(park_advlock, PUFFSOP_VN,
                      PUFFS_VN_ADVLOCK, VPTOPNC(vp));
    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_advlock, vp->v_data, NULL, error);
    error = checkerr(pmp, error, __func__);
    PUFFS_MSG_RELEASE(advlock);

    return error;
}
Ejemplo n.º 4
0
static int
puffs_vnop_print(struct vop_print_args *ap)
{
    PUFFS_MSG_VARS(vn, print);
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    struct puffs_node *pn = VPTOPP(vp);
    int error;

    /* kernel portion */
    kprintf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
            "\tuserspace cookie: %p", vp, pn, pn->pn_cookie);
    if (vp->v_type == VFIFO)
        fifo_printinfo(vp);
    kprintf("\n");

    /* userspace portion */
    if (EXISTSOP(pmp, PRINT)) {
        PUFFS_MSG_ALLOC(vn, print);
        puffs_msg_setinfo(park_print, PUFFSOP_VN,
                          PUFFS_VN_PRINT, VPTOPNC(vp));
        PUFFS_MSG_ENQUEUEWAIT2(pmp, park_print, vp->v_data,
                               NULL, error);
        PUFFS_MSG_RELEASE(print);
    }

    return 0;
}
Ejemplo n.º 5
0
static int
puffs_vnop_mknod(struct vop_nmknod_args *ap)
{
    PUFFS_MSG_VARS(vn, mknod);
    struct vnode *dvp = ap->a_dvp;
    struct vattr *vap = ap->a_vap;
    struct puffs_node *dpn = VPTOPP(dvp);
    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, MKNOD))
        return EOPNOTSUPP;

    DPRINTF(("puffs_mknod: dvp %p, name: %s\n",
             dvp, ncp->nc_name));

    if (vap->va_type != VFIFO)
        return EINVAL;

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

    PUFFS_MSG_ALLOC(vn, mknod);
    puffs_makecn(&mknod_msg->pvnr_cn, &mknod_msg->pvnr_cn_cred,
                 ncp, cred);
    mknod_msg->pvnr_va = *ap->a_vap;
    puffs_msg_setinfo(park_mknod, PUFFSOP_VN,
                      PUFFS_VN_MKNOD, VPTOPNC(dvp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mknod, dvp->v_data, NULL, error);

    error = checkerr(pmp, error, __func__);
    if (error)
        goto out;

    error = puffs_newnode(mp, dvp, ap->a_vpp,
                          mknod_msg->pvnr_newnode, vap->va_type);
    if (error)
        puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, dpn->pn_cookie,
                          mknod_msg->pvnr_newnode, ncp, cred);

out:
    vput(dvp);
    if (!error) {
        cache_setunresolved(nch);
        cache_setvp(nch, *ap->a_vpp);
    }
    PUFFS_MSG_RELEASE(mknod);
    return error;
}
Ejemplo n.º 6
0
static int
puffs_vnop_symlink(struct vop_nsymlink_args *ap)
{
    PUFFS_MSG_VARS(vn, symlink);
    struct vnode *dvp = ap->a_dvp;
    struct puffs_node *dpn = VPTOPP(dvp);
    struct mount *mp = dvp->v_mount;
    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, SYMLINK))
        return EOPNOTSUPP;

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

    *ap->a_vpp = NULL;

    PUFFS_MSG_ALLOC(vn, symlink);
    puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred,
                 ncp, cred);
    symlink_msg->pvnr_va = *ap->a_vap;
    (void)strlcpy(symlink_msg->pvnr_link, ap->a_target,
                  sizeof(symlink_msg->pvnr_link));
    puffs_msg_setinfo(park_symlink, PUFFSOP_VN,
                      PUFFS_VN_SYMLINK, VPTOPNC(dvp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_symlink, dvp->v_data, NULL, error);

    error = checkerr(pmp, error, __func__);
    if (error)
        goto out;

    error = puffs_newnode(mp, dvp, ap->a_vpp,
                          symlink_msg->pvnr_newnode, VLNK);
    if (error)
        puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie,
                          symlink_msg->pvnr_newnode, ncp, cred);

out:
    vput(dvp);
    PUFFS_MSG_RELEASE(symlink);
    if (!error) {
        cache_setunresolved(nch);
        cache_setvp(nch, *ap->a_vpp);
    }
    return error;
}
Ejemplo n.º 7
0
void
puffs_gop_markupdate(struct vnode *vp, int flags)
{
	int uflags = 0;

	if (flags & GOP_UPDATE_ACCESSED)
		uflags |= PUFFS_UPDATEATIME;
	if (flags & GOP_UPDATE_MODIFIED)
		uflags |= PUFFS_UPDATEMTIME;

	puffs_updatenode(VPTOPP(vp), uflags, 0);
}
Ejemplo n.º 8
0
static int
puffs_vnop_getattr(struct vop_getattr_args *ap)
{
    PUFFS_MSG_VARS(vn, getattr);
    struct vnode *vp = ap->a_vp;
    struct mount *mp = vp->v_mount;
    struct puffs_mount *pmp = MPTOPUFFSMP(mp);
    struct vattr *vap, *rvap;
    struct puffs_node *pn = VPTOPP(vp);
    int error = 0;

    if (vp->v_type == VBLK || vp->v_type == VCHR)
        return ENOTSUP;

    vap = ap->a_vap;

    PUFFS_MSG_ALLOC(vn, getattr);
    vattr_null(&getattr_msg->pvnr_va);
    puffs_credcvt(&getattr_msg->pvnr_cred, curproc->p_ucred);
    puffs_msg_setinfo(park_getattr, PUFFSOP_VN,
                      PUFFS_VN_GETATTR, VPTOPNC(vp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getattr, vp->v_data, NULL, error);
    error = checkerr(pmp, error, __func__);
    if (error)
        goto out;

    rvap = &getattr_msg->pvnr_va;

    (void) memcpy(vap, rvap, sizeof(struct vattr));
    vap->va_fsid = mp->mnt_stat.f_fsid.val[0];

    if (pn->pn_stat & PNODE_METACACHE_ATIME)
        vap->va_atime = pn->pn_mc_atime;
    if (pn->pn_stat & PNODE_METACACHE_CTIME)
        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 (rvap->va_size != VNOVAL
                && vp->v_type != VBLK && vp->v_type != VCHR) {
            pn->pn_serversize = rvap->va_size;
            if (vp->v_type == VREG)
                puffs_meta_setsize(vp, rvap->va_size, 0);
        }
    }

out:
    PUFFS_MSG_RELEASE(getattr);
    return error;
}
Ejemplo n.º 9
0
/*
 * always FAF, we don't really care if the server wants to fail to
 * reclaim the node or not
 */
static int
puffs_vnop_reclaim(struct vop_reclaim_args *ap)
{
    struct vnode *vp = ap->a_vp;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    struct puffs_node *pnode = VPTOPP(vp);
    boolean_t notifyserver = TRUE;

    vinvalbuf(vp, V_SAVE, 0, 0);

    /*
     * first things first: check if someone is trying to reclaim the
     * root vnode.  do not allow that to travel to userspace.
     * Note that we don't need to take the lock similarly to
     * puffs_root(), since there is only one of us.
     */
    if (vp->v_flag & VROOT) {
        lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
        KKASSERT(pmp->pmp_root != NULL);
        pmp->pmp_root = NULL;
        lockmgr(&pmp->pmp_lock, LK_RELEASE);
        notifyserver = FALSE;
    }

    /*
     * purge info from kernel before issueing FAF, since we
     * don't really know when we'll get around to it after
     * that and someone might race us into node creation
     */
    lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
    LIST_REMOVE(pnode, pn_hashent);
    lockmgr(&pmp->pmp_lock, LK_RELEASE);

    if (notifyserver)
        callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp));

    puffs_putvnode(vp);
    vp->v_data = NULL;

    return 0;
}
Ejemplo n.º 10
0
static int
puffs_vnop_fsync(struct vop_fsync_args *ap)
{
    PUFFS_MSG_VARS(vn, fsync);
    struct vnode *vp = ap->a_vp;
    int waitfor = ap->a_waitfor;
    struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
    struct puffs_node *pn = VPTOPP(vp);
    int error, dofaf;

    error = flushvncache(vp, waitfor);
    if (error)
        return error;

    /*
     * HELLO!  We exit already here if the user server does not
     * support fsync OR if we should call fsync for a node which
     * has references neither in the kernel or the fs server.
     * Otherwise we continue to issue fsync() forward.
     */
    if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING))
        return 0;

    dofaf = (waitfor & MNT_WAIT) == 0 || (waitfor & MNT_LAZY) != 0;

    PUFFS_MSG_ALLOC(vn, fsync);
    if (dofaf)
        puffs_msg_setfaf(park_fsync);

    fsync_msg->pvnr_flags = ap->a_flags;
    puffs_msg_setinfo(park_fsync, PUFFSOP_VN,
                      PUFFS_VN_FSYNC, VPTOPNC(vp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fsync, vp->v_data, NULL, error);
    PUFFS_MSG_RELEASE(fsync);

    error = checkerr(pmp, error, __func__);

    return error;
}
Ejemplo n.º 11
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;
}
Ejemplo n.º 12
0
static int
flushvncache(struct vnode *vp, int waitfor)
{
    struct puffs_node *pn = VPTOPP(vp);
    struct vattr va;
    int error = 0;

    /* flush out information from our metacache, see vop_setattr */
    if (pn->pn_stat & PNODE_METACACHE_MASK
            && (pn->pn_stat & PNODE_DYING) == 0) {
        vattr_null(&va);
        error = dosetattr(vp, &va, FSCRED, SETATTR_CHSIZE |
                          (waitfor == MNT_NOWAIT ? 0 : SETATTR_ASYNC));
        if (error)
            return error;
    }

    /*
     * flush pages to avoid being overly dirty
     */
    vfsync(vp, waitfor, 0, NULL, NULL);

    return error;
}
Ejemplo n.º 13
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;
}
Ejemplo n.º 14
0
static int
puffs_vnop_lookupdotdot(struct vop_nlookupdotdot_args *ap)
{
    PUFFS_MSG_VARS(vn, lookupdotdot);
    struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
    struct ucred *cred = ap->a_cred;
    struct vnode *vp, *dvp = ap->a_dvp;
    struct puffs_node *dpn;
    int error;

    *ap->a_vpp = NULL;

    DPRINTF(("puffs_lookupdotdot: vnode %p\n", dvp));

    PUFFS_MSG_ALLOC(vn, lookupdotdot);
    puffs_credcvt(&lookupdotdot_msg->pvnr_cred, cred);

    puffs_msg_setinfo(park_lookupdotdot, PUFFSOP_VN,
                      PUFFS_VN_LOOKUPDOTDOT, VPTOPNC(dvp));
    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_lookupdotdot, dvp->v_data, NULL,
                           error);
    DPRINTF(("puffs_lookupdotdot: return of the userspace, part %d\n",
             error));
    if (error) {
        error = checkerr(pmp, error, __func__);
        goto out;
    }

    /*
     * Check that we don't get our node back, that would cause
     * a pretty obvious deadlock.
     */
    dpn = VPTOPP(dvp);
    if (lookupdotdot_msg->pvnr_newnode == dpn->pn_cookie) {
        puffs_senderr(pmp, PUFFS_ERR_LOOKUP, EINVAL,
                      "lookupdotdot produced the same cookie",
                      lookupdotdot_msg->pvnr_newnode);
        error = EPROTO;
        goto out;
    }

    error = puffs_cookie2vnode(pmp, lookupdotdot_msg->pvnr_newnode,
                               1, &vp);
    if (error == PUFFS_NOSUCHCOOKIE) {
        error = puffs_getvnode(dvp->v_mount,
                               lookupdotdot_msg->pvnr_newnode, VDIR, 0, &vp);
        if (error) {
            puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
                              lookupdotdot_msg->pvnr_newnode, NULL, cred);
            goto out;
        }
    } else if (error) {
        puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
                          lookupdotdot_msg->pvnr_newnode, NULL, cred);
        goto out;
    }

    *ap->a_vpp = vp;
    vn_unlock(vp);

out:
    DPRINTF(("puffs_lookupdotdot: returning %d %p\n", error, *ap->a_vpp));
    PUFFS_MSG_RELEASE(lookupdotdot);
    return error;
}
Ejemplo n.º 15
0
static int
puffs_vnop_rename(struct vop_nrename_args *ap)
{
    PUFFS_MSG_VARS(vn, rename);
    struct nchandle *fnch = ap->a_fnch;
    struct nchandle *tnch = ap->a_tnch;
    struct vnode *fdvp = ap->a_fdvp;
    struct vnode *fvp = fnch->ncp->nc_vp;
    struct vnode *tdvp = ap->a_tdvp;
    struct vnode *tvp = tnch->ncp->nc_vp;
    struct ucred *cred = ap->a_cred;
    struct puffs_mount *pmp = MPTOPUFFSMP(fdvp->v_mount);
    int error;

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

    error = vget(tdvp, LK_EXCLUSIVE);
    if (error != 0) {
        DPRINTF(("puffs_vnop_rename: EAGAIN on tdvp vnode %p %s\n",
                 tdvp, tnch->ncp->nc_name));
        return EAGAIN;
    }
    if (tvp != NULL) {
        error = vget(tvp, LK_EXCLUSIVE);
        if (error != 0) {
            DPRINTF(("puffs_vnop_rename: EAGAIN on tvp vnode %p %s\n",
                     tvp, tnch->ncp->nc_name));
            vput(tdvp);
            return EAGAIN;
        }
    }

    if ((fvp->v_mount != tdvp->v_mount) ||
            (tvp && (fvp->v_mount != tvp->v_mount))) {
        error = EXDEV;
        goto out;
    }

    if (tvp) {
        if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
            error = ENOTDIR;
            goto out;
        } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
            error = EISDIR;
            goto out;
        }
    }

    PUFFS_MSG_ALLOC(vn, rename);
    rename_msg->pvnr_cookie_src = VPTOPNC(fvp);
    rename_msg->pvnr_cookie_targdir = VPTOPNC(tdvp);
    if (tvp)
        rename_msg->pvnr_cookie_targ = VPTOPNC(tvp);
    else
        rename_msg->pvnr_cookie_targ = NULL;
    puffs_makecn(&rename_msg->pvnr_cn_src, &rename_msg->pvnr_cn_src_cred,
                 fnch->ncp, cred);
    puffs_makecn(&rename_msg->pvnr_cn_targ, &rename_msg->pvnr_cn_targ_cred,
                 tnch->ncp, cred);
    puffs_msg_setinfo(park_rename, PUFFSOP_VN,
                      PUFFS_VN_RENAME, VPTOPNC(fdvp));

    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rename, fdvp->v_data, NULL, error);
    PUFFS_MSG_RELEASE(rename);
    error = checkerr(pmp, error, __func__);

    if (error == 0)
        puffs_updatenode(VPTOPP(fvp), PUFFS_UPDATECTIME);

out:
    if (tvp != NULL)
        vn_unlock(tvp);
    if (tdvp != tvp)
        vn_unlock(tdvp);
    if (error == 0)
        cache_rename(fnch, tnch);
    if (tvp != NULL)
        vrele(tvp);
    vrele(tdvp);

    return error;
}
Ejemplo n.º 16
0
/*
 * Begin vnode operations.
 *
 * A word from the keymaster about locks: generally we don't want
 * to use the vnode locks at all: it creates an ugly dependency between
 * the userlandia file server and the kernel.  But we'll play along with
 * the kernel vnode locks for now.  However, even currently we attempt
 * to release locks as early as possible.  This is possible for some
 * operations which a) don't need a locked vnode after the userspace op
 * and b) return with the vnode unlocked.  Theoretically we could
 * unlock-do op-lock for others and order the graph in userspace, but I
 * don't want to think of the consequences for the time being.
 */
static int
puffs_vnop_lookup(struct vop_nresolve_args *ap)
{
    PUFFS_MSG_VARS(vn, lookup);
    struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
    struct nchandle *nch = ap->a_nch;
    struct namecache *ncp = nch->ncp;
    struct ucred *cred = ap->a_cred;
    struct vnode *vp = NULL, *dvp = ap->a_dvp;
    struct puffs_node *dpn;
    int error;

    DPRINTF(("puffs_lookup: \"%s\", parent vnode %p\n",
             ncp->nc_name, dvp));

    PUFFS_MSG_ALLOC(vn, lookup);
    puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred,
                 ncp, cred);

    puffs_msg_setinfo(park_lookup, PUFFSOP_VN,
                      PUFFS_VN_LOOKUP, VPTOPNC(dvp));
    PUFFS_MSG_ENQUEUEWAIT2(pmp, park_lookup, dvp->v_data, NULL, error);
    DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error));
    if (error) {
        error = checkerr(pmp, error, __func__);
        if (error == ENOENT)
            cache_setvp(nch, NULL);
        goto out;
    }

    /*
     * Check that we don't get our parent node back, that would cause
     * a pretty obvious deadlock.
     */
    dpn = VPTOPP(dvp);
    if (lookup_msg->pvnr_newnode == dpn->pn_cookie) {
        puffs_senderr(pmp, PUFFS_ERR_LOOKUP, EINVAL,
                      "lookup produced parent cookie", lookup_msg->pvnr_newnode);
        error = EPROTO;
        goto out;
    }

    error = puffs_cookie2vnode(pmp, lookup_msg->pvnr_newnode, 1, &vp);
    if (error == PUFFS_NOSUCHCOOKIE) {
        error = puffs_getvnode(dvp->v_mount,
                               lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype,
                               lookup_msg->pvnr_size, &vp);
        if (error) {
            puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
                              lookup_msg->pvnr_newnode, ncp, cred);
            goto out;
        }
    } else if (error) {
        puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
                          lookup_msg->pvnr_newnode, ncp, cred);
        goto out;
    }

out:
    if (!error && vp != NULL) {
        vn_unlock(vp);
        cache_setvp(nch, vp);
        vrele(vp);
    }
    DPRINTF(("puffs_lookup: returning %d\n", error));
    PUFFS_MSG_RELEASE(lookup);
    return error;
}