diff --git a/sys/fs/devfs/devfs.h b/sys/fs/devfs/devfs.h index ba8bbf02a4be..5a484c96c074 100644 --- a/sys/fs/devfs/devfs.h +++ b/sys/fs/devfs/devfs.h @@ -154,6 +154,7 @@ struct devfs_dirent { struct dirent *de_dirent; TAILQ_ENTRY(devfs_dirent) de_list; TAILQ_HEAD(, devfs_dirent) de_dlist; + LIST_ENTRY(devfs_dirent) de_alias; struct devfs_dirent *de_dir; int de_links; mode_t de_mode; diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c index e51ca4fd7db0..4adacb453d2c 100644 --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -199,7 +199,7 @@ devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, stru dev_lock(); dev_ref(dev); vp->v_rdev = dev; - SLIST_INSERT_HEAD(&dev->si_hlist, vp, v_specnext); + LIST_INSERT_HEAD(&dev->si_alist, de, de_alias); dev->si_usecount += vp->v_usecount; dev_unlock(); VI_UNLOCK(vp); @@ -1041,19 +1041,23 @@ devfs_reclaim(ap) { struct vnode *vp = ap->a_vp; struct devfs_dirent *de; - int i; + struct cdev *dev; de = vp->v_data; if (de != NULL) de->de_vnode = NULL; vp->v_data = NULL; - if (vp->v_rdev != NULL) { - i = vcount(vp); - if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 && - (vp->v_rdev->si_flags & SI_NAMED)) - destroy_dev(vp->v_rdev); - } vnode_destroy_vobject(vp); + + dev = vp->v_rdev; + vp->v_rdev = NULL; + + dev_lock(); + if (de != NULL) + LIST_REMOVE(de, de_alias); + dev->si_usecount -= vp->v_usecount; + dev_unlock(); + dev_rel(dev); return (0); } @@ -1101,13 +1105,10 @@ devfs_revoke(ap) } */ *ap; { struct vnode *vp = ap->a_vp; - struct vnode *vq; - struct devfs_dirent *de; struct cdev *dev; + struct devfs_dirent *de; KASSERT((ap->a_flags & REVOKEALL) != 0, ("devfs_revoke !REVOKEALL")); - de = vp->v_data; - de->de_vnode = NULL; /* * If a vgone (or vclean) is already in progress, @@ -1115,15 +1116,15 @@ devfs_revoke(ap) */ if (vx_wait(vp)) return (0); - + dev = vp->v_rdev; for (;;) { dev_lock(); - vq = SLIST_FIRST(&dev->si_hlist); + de = LIST_FIRST(&dev->si_alist); dev_unlock(); - if (vq == NULL) + if (de == NULL) break; - vgone(vq); + vgone(de->de_vnode); } return (0); } diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c index 12402cb1383e..fe9339d52809 100644 --- a/sys/kern/kern_conf.c +++ b/sys/kern/kern_conf.c @@ -61,6 +61,7 @@ static LIST_HEAD(, cdev) dev_hash[DEVT_HASH]; static struct mtx devmtx; static void freedev(struct cdev *dev); static struct cdev *newdev(int x, int y, struct cdev *); +static void destroy_devl(struct cdev *dev); void dev_lock(void) @@ -86,21 +87,17 @@ dev_ref(struct cdev *dev) } void -dev_rel(struct vnode *vp) +dev_rel(struct cdev *dev) { - struct cdev *dev; - int flag; + int flag = 0; - dev = vp->v_rdev; mtx_assert(&devmtx, MA_NOTOWNED); dev_lock(); - SLIST_REMOVE(&dev->si_hlist, vp, vnode, v_specnext); - dev->si_usecount -= vp->v_usecount; - vp->v_rdev = NULL; dev->si_refcount--; KASSERT(dev->si_refcount >= 0, ("dev_rel(%s) gave negative count", devtoname(dev))); - flag = 0; + if (dev->si_usecount == 0 && + (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) if (dev->si_devsw == NULL && dev->si_refcount == 0) { LIST_REMOVE(dev, si_list); flag = 1; @@ -108,7 +105,6 @@ dev_rel(struct vnode *vp) dev_unlock(); if (flag) freedev(dev); - return; } struct cdevsw * @@ -287,6 +283,7 @@ allocdev(void) si = malloc(sizeof *si, M_DEVT, M_USE_RESERVE | M_ZERO | M_WAITOK); si->si_name = si->__si_namebuf; LIST_INIT(&si->si_children); + LIST_INIT(&si->si_alist); return (si); } @@ -547,10 +544,11 @@ make_dev_alias(struct cdev *pdev, const char *fmt, ...) } static void -idestroy_dev(struct cdev *dev) +destroy_devl(struct cdev *dev) { struct cdevsw *csw; + mtx_assert(&devmtx, MA_OWNED); KASSERT(dev->si_flags & SI_NAMED, ("WARNING: Driver mistake: destroy_dev on %d/%d\n", major(dev), minor(dev))); @@ -568,7 +566,7 @@ idestroy_dev(struct cdev *dev) /* Kill our children */ while (!LIST_EMPTY(&dev->si_children)) - idestroy_dev(LIST_FIRST(&dev->si_children)); + destroy_devl(LIST_FIRST(&dev->si_children)); /* Remove from clone list */ if (dev->si_flags & SI_CLONELIST) { @@ -615,7 +613,7 @@ destroy_dev(struct cdev *dev) { dev_lock(); - idestroy_dev(dev); + destroy_devl(dev); dev_unlock(); } @@ -796,7 +794,7 @@ clone_cleanup(struct clonedevs **cdp) ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); KASSERT(dev->si_flags & SI_NAMED, ("Driver has goofed in cloning underways udev %x", dev->si_udev)); - idestroy_dev(dev); + destroy_devl(dev); } dev_unlock(); free(cd, M_DEVBUF); diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 97fa19ddea11..e36f937f2160 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -2394,8 +2394,6 @@ vgonel(struct vnode *vp, struct thread *td) * if it is on one. */ VI_LOCK(vp); - if (vp->v_type == VCHR && vp->v_rdev != NULL) - dev_rel(vp); /* * If it is on the freelist and not already at the head, diff --git a/sys/sys/conf.h b/sys/sys/conf.h index 143faf5ef556..16a132cf3184 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -51,6 +51,7 @@ struct disk; struct vnode; struct buf; struct snapdata; +struct devfs_dirent; struct cdev { u_int si_flags; @@ -71,7 +72,7 @@ struct cdev { LIST_ENTRY(cdev) si_list; LIST_ENTRY(cdev) si_clone; LIST_ENTRY(cdev) si_hash; - SLIST_HEAD(, vnode) si_hlist; + LIST_HEAD(,devfs_dirent)si_alist; LIST_HEAD(, cdev) si_children; LIST_ENTRY(cdev) si_siblings; struct cdev *si_parent; @@ -258,7 +259,7 @@ const char *devtoname(struct cdev *_dev); int dev_named(struct cdev *_pdev, const char *_name); void dev_depends(struct cdev *_pdev, struct cdev *_cdev); void dev_ref(struct cdev *dev); -void dev_rel(struct vnode *vp); +void dev_rel(struct cdev *dev); void dev_strategy(struct cdev *dev, struct buf *bp); struct cdev *makebdev(int _maj, int _min); struct cdev *make_dev(struct cdevsw *_devsw, int _minor, uid_t _uid, gid_t _gid, diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 0671248d89ac..2139919a606f 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -121,10 +121,7 @@ struct vnode { union { struct mount *vu_mountedhere;/* v ptr to mounted vfs (VDIR) */ struct socket *vu_socket; /* v unix ipc (VSOCK) */ - struct { - struct cdev *vu_cdev; /* v device (VCHR, VBLK) */ - SLIST_ENTRY(vnode) vu_specnext; /* s device aliases */ - } vu_spec; + struct cdev *vu_cdev; /* v device (VCHR, VBLK) */ struct fifoinfo *vu_fifoinfo; /* v fifo (VFIFO) */ } v_un; TAILQ_ENTRY(vnode) v_freelist; /* f vnode freelist */ @@ -153,8 +150,7 @@ struct vnode { #define v_mountedhere v_un.vu_mountedhere #define v_socket v_un.vu_socket -#define v_rdev v_un.vu_spec.vu_cdev -#define v_specnext v_un.vu_spec.vu_specnext +#define v_rdev v_un.vu_cdev #define v_fifoinfo v_un.vu_fifoinfo /* XXX: These are temporary to avoid a source sweep at this time */