Esempio n. 1
0
/*
 * Find root of lofs mount.
 */
static int
lo_root(struct vfs *vfsp, struct vnode **vpp)
{
    *vpp = vtoli(vfsp)->li_rootvp;
#ifdef LODEBUG
    lo_dprint(4, "lo_root(0x%p) = %p\n", vfsp, *vpp);
#endif
    /*
     * If the root of the filesystem is a special file, return the specvp
     * version of the vnode. We don't save the specvp vnode in our
     * hashtable since that's exclusively for lnodes.
     */
    if (IS_DEVVP(*vpp)) {
        struct vnode *svp;

        svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, kcred);
        if (svp == NULL)
            return (ENOSYS);
        *vpp = svp;
    } else {
        VN_HOLD(*vpp);
    }

    return (0);
}
Esempio n. 2
0
/*
 * Undo loopback mount
 */
static int
lo_unmount(struct vfs *vfsp, int flag, struct cred *cr)
{
    struct loinfo *li;

    if (secpolicy_fs_unmount(cr, vfsp) != 0)
        return (EPERM);

    /*
     * Forced unmount is not supported by this file system
     * and thus, ENOTSUP, is being returned.
     */
    if (flag & MS_FORCE)
        return (ENOTSUP);

    li = vtoli(vfsp);
#ifdef LODEBUG
    lo_dprint(4, "lo_unmount(%p) li %p\n", vfsp, li);
#endif
    if (li->li_refct != 1 || li->li_rootvp->v_count != 1) {
#ifdef LODEBUG
        lo_dprint(4, "refct %d v_ct %d\n", li->li_refct,
                  li->li_rootvp->v_count);
#endif
        return (EBUSY);
    }
    VN_RELE(li->li_rootvp);
    return (0);
}
Esempio n. 3
0
/*
 * Free mount-specific data.
 */
static void
lo_freevfs(struct vfs *vfsp)
{
    struct loinfo *li = vtoli(vfsp);

    ldestroy(li);
    kmem_free(li, sizeof (struct loinfo));
}
Esempio n. 4
0
/*
 * Find real vfs given loopback vfs
 */
struct vfs *
lo_realvfs(struct vfs *vfsp, struct vnode **realrootvpp)
{
    struct loinfo *li = vtoli(vfsp);
    struct lfsnode *lfs;

    ASSERT(li->li_refct > 0);
    if (vfsp == li->li_mountvfs) {
        if (realrootvpp != NULL)
            *realrootvpp = vtol(li->li_rootvp)->lo_vp;
        return (li->li_realvfs);
    }
    mutex_enter(&li->li_lfslock);
    for (lfs = li->li_lfs; lfs != NULL; lfs = lfs->lfs_next) {
        if (vfsp == &lfs->lfs_vfs) {
            if (realrootvpp != NULL)
                *realrootvpp = lfs->lfs_realrootvp;
            mutex_exit(&li->li_lfslock);
            return (lfs->lfs_realvfs);
        }
    }
    panic("lo_realvfs");
    /*NOTREACHED*/
}
Esempio n. 5
0
/*
 * Remove a lnode from the table
 */
void
freelonode(lnode_t *lp)
{
    lnode_t *lt;
    lnode_t *ltprev = NULL;
    struct lfsnode *lfs, *nextlfs;
    struct vfs *vfsp;
    struct vnode *vp = ltov(lp);
    struct vnode *realvp = realvp(vp);
    struct loinfo *li = vtoli(vp->v_vfsp);

#ifdef LODEBUG
    lo_dprint(4, "freelonode lp %p hash %d\n",
              lp, ltablehash(lp->lo_vp, li));
#endif
    TABLE_LOCK_ENTER(lp->lo_vp, li);

    mutex_enter(&vp->v_lock);
    if (vp->v_count > 1) {
        vp->v_count--;	/* release our hold from vn_rele */
        mutex_exit(&vp->v_lock);
        TABLE_LOCK_EXIT(lp->lo_vp, li);
        return;
    }
    mutex_exit(&vp->v_lock);

    for (lt = TABLE_BUCKET(lp->lo_vp, li); lt != NULL;
            ltprev = lt, lt = lt->lo_next) {
        if (lt == lp) {
#ifdef LODEBUG
            lo_dprint(4, "freeing %p, vfsp %p\n",
                      vp, vp->v_vfsp);
#endif
            atomic_dec_32(&li->li_refct);
            vfsp = vp->v_vfsp;
            vn_invalid(vp);
            if (vfsp != li->li_mountvfs) {
                mutex_enter(&li->li_lfslock);
                /*
                 * Check for unused lfs
                 */
                lfs = li->li_lfs;
                while (lfs != NULL) {
                    nextlfs = lfs->lfs_next;
                    if (vfsp == &lfs->lfs_vfs) {
                        lfs_rele(lfs, li);
                        break;
                    }
                    if (lfs->lfs_vfs.vfs_count == 1) {
                        /*
                         * Lfs is idle
                         */
                        freelfsnode(lfs, li);
                    }
                    lfs = nextlfs;
                }
                mutex_exit(&li->li_lfslock);
            }
            if (ltprev == NULL) {
                TABLE_BUCKET(lt->lo_vp, li) = lt->lo_next;
            } else {
                ltprev->lo_next = lt->lo_next;
            }
            TABLE_COUNT(lt->lo_vp, li)--;
            TABLE_LOCK_EXIT(lt->lo_vp, li);
            kmem_cache_free(lnode_cache, lt);
            vn_free(vp);
            VN_RELE(realvp);
            return;
        }
    }
    panic("freelonode");
    /*NOTREACHED*/
}