Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/devfs/devfs_vnops.c
Show First 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | |||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/vm_object.h> | #include <vm/vm_object.h> | ||||
static MALLOC_DEFINE(M_CDEVPDATA, "DEVFSP", "Metainfo for cdev-fp data"); | static MALLOC_DEFINE(M_CDEVPDATA, "DEVFSP", "Metainfo for cdev-fp data"); | ||||
MALLOC_DECLARE(M_CDEV_VP); | |||||
struct mtx devfs_de_interlock; | struct mtx devfs_de_interlock; | ||||
MTX_SYSINIT(devfs_de_interlock, &devfs_de_interlock, "devfs interlock", MTX_DEF); | MTX_SYSINIT(devfs_de_interlock, &devfs_de_interlock, "devfs interlock", MTX_DEF); | ||||
struct sx clone_drain_lock; | struct sx clone_drain_lock; | ||||
SX_SYSINIT(clone_drain_lock, &clone_drain_lock, "clone events drain lock"); | SX_SYSINIT(clone_drain_lock, &clone_drain_lock, "clone events drain lock"); | ||||
struct mtx cdevpriv_mtx; | struct mtx cdevpriv_mtx; | ||||
MTX_SYSINIT(cdevpriv_mtx, &cdevpriv_mtx, "cdevpriv lock", MTX_DEF); | MTX_SYSINIT(cdevpriv_mtx, &cdevpriv_mtx, "cdevpriv lock", MTX_DEF); | ||||
▲ Show 20 Lines • Show All 320 Lines • ▼ Show 20 Lines | devfs_insmntque_dtr(struct vnode *vp, void *arg) | ||||
mtx_lock(&devfs_de_interlock); | mtx_lock(&devfs_de_interlock); | ||||
vp->v_data = NULL; | vp->v_data = NULL; | ||||
de->de_vnode = NULL; | de->de_vnode = NULL; | ||||
mtx_unlock(&devfs_de_interlock); | mtx_unlock(&devfs_de_interlock); | ||||
vgone(vp); | vgone(vp); | ||||
vput(vp); | vput(vp); | ||||
} | } | ||||
static void | |||||
dev_vn_growtable(struct cdev *dev) | |||||
{ | |||||
struct vnode **vt, **tofree; | |||||
int newsize; | |||||
newsize = dev->si_vnodes_size * 2; | |||||
vt = malloc(newsize * sizeof(*vt), M_CDEV_VP, M_WAITOK | M_ZERO); | |||||
dev_lock(); | |||||
if (dev->si_vnodes_size >= newsize) { | |||||
dev_unlock(); | |||||
free(vt, M_CDEV_VP); | |||||
return; | |||||
} | |||||
memcpy(vt, dev->si_vnodes, dev->si_vnodes_size * sizeof(*vt)); | |||||
if (dev->si_vnodes != (void *)&dev->si_vnodes_local) | |||||
tofree = dev->si_vnodes; | |||||
else | |||||
tofree = NULL; | |||||
dev->si_vnodes = vt; | |||||
dev->si_vnodes_size = newsize; | |||||
dev_unlock(); | |||||
free(tofree, M_CDEV_VP); | |||||
} | |||||
static int | |||||
dev_vn_add_vp(struct cdev *dev, struct vnode *vp) | |||||
{ | |||||
if (dev->si_vnodes_size == dev->si_vnodes_assigned) | |||||
return (EAGAIN); | |||||
vp->v_rdev = dev; | |||||
KASSERT(vp->v_usecount == 1, | |||||
("%s %d (%d)\n", __func__, __LINE__, vp->v_usecount)); | |||||
dev->si_vnodes_assigned++; | |||||
dev_vn_table_add(dev, vp); | |||||
return (0); | |||||
} | |||||
static void | |||||
dev_vn_remove_vp(struct cdev *dev, struct vnode *vp) | |||||
{ | |||||
mtx_assert(&devmtx, MA_OWNED); | |||||
if (dev == NULL) | |||||
return; | |||||
dev_vn_table_remove(dev, vp); | |||||
dev->si_vnodes_assigned--; | |||||
vp->v_rdev = NULL; | |||||
} | |||||
void | |||||
dev_vn_table_add(struct cdev *dev, struct vnode *vp) | |||||
{ | |||||
mtx_assert(&devmtx, MA_OWNED); | |||||
if (dev->si_vnodes_size == dev->si_vnodes_index) | |||||
panic("%s: no room for vnode %p in cdev %p table\n", | |||||
__func__, vp, dev); | |||||
dev->si_vnodes[dev->si_vnodes_index++] = vp; | |||||
} | |||||
void | |||||
dev_vn_table_remove(struct cdev *dev, struct vnode *vp) | |||||
{ | |||||
int i; | |||||
mtx_assert(&devmtx, MA_OWNED); | |||||
for (i = 0; i < dev->si_vnodes_index; i++) { | |||||
if (dev->si_vnodes[i] == vp) { | |||||
dev->si_vnodes[i] = dev->si_vnodes[dev->si_vnodes_index - 1]; | |||||
dev->si_vnodes[dev->si_vnodes_index - 1] = NULL; | |||||
dev->si_vnodes_index--; | |||||
return; | |||||
} | |||||
} | |||||
panic("%s: vnode %p not found in cdev %p table\n", __func__, vp, dev); | |||||
} | |||||
/* | /* | ||||
* devfs_allocv shall be entered with dmp->dm_lock held, and it drops | * devfs_allocv shall be entered with dmp->dm_lock held, and it drops | ||||
* it on return. | * it on return. | ||||
*/ | */ | ||||
int | int | ||||
devfs_allocv(struct devfs_dirent *de, struct mount *mp, int lockmode, | devfs_allocv(struct devfs_dirent *de, struct mount *mp, int lockmode, | ||||
struct vnode **vpp) | struct vnode **vpp) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | loop: | ||||
if (error != 0) { | if (error != 0) { | ||||
devfs_allocv_drop_refs(1, dmp, de); | devfs_allocv_drop_refs(1, dmp, de); | ||||
printf("devfs_allocv: failed to allocate new vnode\n"); | printf("devfs_allocv: failed to allocate new vnode\n"); | ||||
return (error); | return (error); | ||||
} | } | ||||
if (de->de_dirent->d_type == DT_CHR) { | if (de->de_dirent->d_type == DT_CHR) { | ||||
vp->v_type = VCHR; | vp->v_type = VCHR; | ||||
for (;;) { | |||||
VI_LOCK(vp); | VI_LOCK(vp); | ||||
dev_lock(); | dev_lock(); | ||||
if (dev_vn_add_vp(dev, vp) == 0) | |||||
break; | |||||
dev_unlock(); | |||||
VI_UNLOCK(vp); | |||||
dev_vn_growtable(dev); | |||||
} | |||||
dev_refl(dev); | dev_refl(dev); | ||||
/* XXX: v_rdev should be protect by vnode lock */ | |||||
vp->v_rdev = dev; | |||||
KASSERT(vp->v_usecount == 1, | |||||
("%s %d (%d)\n", __func__, __LINE__, vp->v_usecount)); | |||||
dev->si_usecount += vp->v_usecount; | |||||
/* Special casing of ttys for deadfs. Probably redundant. */ | /* Special casing of ttys for deadfs. Probably redundant. */ | ||||
dsw = dev->si_devsw; | dsw = dev->si_devsw; | ||||
if (dsw != NULL && (dsw->d_flags & D_TTY) != 0) | if (dsw != NULL && (dsw->d_flags & D_TTY) != 0) | ||||
vp->v_vflag |= VV_ISTTY; | vp->v_vflag |= VV_ISTTY; | ||||
dev_unlock(); | dev_unlock(); | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
if ((dev->si_flags & SI_ETERNAL) != 0) | if ((dev->si_flags & SI_ETERNAL) != 0) | ||||
vp->v_vflag |= VV_ETERNALDEV; | vp->v_vflag |= VV_ETERNALDEV; | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | if (td != NULL) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
if (vp == p->p_session->s_ttyvp) { | if (vp == p->p_session->s_ttyvp) { | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
oldvp = NULL; | oldvp = NULL; | ||||
sx_xlock(&proctree_lock); | sx_xlock(&proctree_lock); | ||||
if (vp == p->p_session->s_ttyvp) { | if (vp == p->p_session->s_ttyvp) { | ||||
SESS_LOCK(p->p_session); | SESS_LOCK(p->p_session); | ||||
VI_LOCK(vp); | VI_LOCK(vp); | ||||
if (count_dev(dev) == 2 && | if (count_dev_cmp(dev, 2) == 0 && | ||||
(vp->v_iflag & VI_DOOMED) == 0) { | (vp->v_iflag & VI_DOOMED) == 0) { | ||||
p->p_session->s_ttyvp = NULL; | p->p_session->s_ttyvp = NULL; | ||||
p->p_session->s_ttydp = NULL; | p->p_session->s_ttydp = NULL; | ||||
oldvp = vp; | oldvp = vp; | ||||
} | } | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
SESS_UNLOCK(p->p_session); | SESS_UNLOCK(p->p_session); | ||||
} | } | ||||
Show All 17 Lines | if (dsw == NULL) | ||||
return (ENXIO); | return (ENXIO); | ||||
dflags = 0; | dflags = 0; | ||||
VI_LOCK(vp); | VI_LOCK(vp); | ||||
if (vp->v_iflag & VI_DOOMED) { | if (vp->v_iflag & VI_DOOMED) { | ||||
/* Forced close. */ | /* Forced close. */ | ||||
dflags |= FREVOKE | FNONBLOCK; | dflags |= FREVOKE | FNONBLOCK; | ||||
} else if (dsw->d_flags & D_TRACKCLOSE) { | } else if (dsw->d_flags & D_TRACKCLOSE) { | ||||
/* Keep device updated on status. */ | /* Keep device updated on status. */ | ||||
} else if (count_dev(dev) > 1) { | } else if (count_dev_cmp(dev, 1) > 0) { | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
dev_relthread(dev, ref); | dev_relthread(dev, ref); | ||||
return (0); | return (0); | ||||
} | } | ||||
if (count_dev(dev) == 1) | if (count_dev_cmp(dev, 1) == 0) | ||||
dflags |= FLASTCLOSE; | dflags |= FLASTCLOSE; | ||||
vholdl(vp); | vholdl(vp); | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
vp_locked = VOP_ISLOCKED(vp); | vp_locked = VOP_ISLOCKED(vp); | ||||
VOP_UNLOCK(vp, 0); | VOP_UNLOCK(vp, 0); | ||||
KASSERT(dev->si_refcount > 0, | KASSERT(dev->si_refcount > 0, | ||||
("devfs_close() on un-referenced struct cdev *(%s)", devtoname(dev))); | ("devfs_close() on un-referenced struct cdev *(%s)", devtoname(dev))); | ||||
error = dsw->d_close(dev, ap->a_fflag | dflags, S_IFCHR, td); | error = dsw->d_close(dev, ap->a_fflag | dflags, S_IFCHR, td); | ||||
▲ Show 20 Lines • Show All 787 Lines • ▼ Show 20 Lines | devfs_reclaim_vchr(struct vop_reclaim_args *ap) | ||||
vp = ap->a_vp; | vp = ap->a_vp; | ||||
MPASS(vp->v_type == VCHR); | MPASS(vp->v_type == VCHR); | ||||
devfs_reclaim(ap); | devfs_reclaim(ap); | ||||
VI_LOCK(vp); | VI_LOCK(vp); | ||||
dev_lock(); | dev_lock(); | ||||
dev = vp->v_rdev; | dev = vp->v_rdev; | ||||
vp->v_rdev = NULL; | dev_vn_remove_vp(dev, vp); | ||||
if (dev != NULL) | |||||
dev->si_usecount -= vp->v_usecount; | |||||
dev_unlock(); | dev_unlock(); | ||||
VI_UNLOCK(vp); | VI_UNLOCK(vp); | ||||
if (dev != NULL) | if (dev != NULL) | ||||
dev_rel(dev); | dev_rel(dev); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 537 Lines • Show Last 20 Lines |