Reap more benefits from DEVFS:
List devfs_dirents rather than vnodes off their shared struct cdev, this saves a pointer field in the vnode at the expense of a field in the devfs_dirent. There are often 100 times more vnodes so this is bargain. In addition it makes it harder for people to try to do stypid things like "finding the vnode from cdev". Since DEVFS handles all VCHR nodes now, we can do the vnode related cleanup in devfs_reclaim() instead of in dev_rel() and vgonel(). Similarly, we can do the struct cdev related cleanup in dev_rel() instead of devfs_reclaim(). rename idestroy_dev() to destroy_devl() for consistency. Add LIST_ENTRY de_alias to struct devfs_dirent. Remove v_specnext from struct vnode. Change si_hlist to si_alist in struct cdev. String new devfs vnodes' devfs_dirent on si_alist when we create them and take them off in devfs_reclaim(). Fix devfs_revoke() accordingly. Also don't clear fields devfs_reclaim() will clear when called from vgone(); Let devfs_reclaim() call dev_rel() instead of vgonel(). Move the usecount tracking from dev_rel() to devfs_reclaim(), and let dev_rel() take a struct cdev argument instead of vnode. Destroy SI_CHEAPCLONE devices in dev_rel() (instead of devfs_reclaim()) when they are no longer used. (This should maybe happen in devfs_close() instead.)
This commit is contained in:
parent
8b25904e36
commit
aa2f6ddc3f
@ -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;
|
||||
|
@ -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,
|
||||
@ -1119,11 +1120,11 @@ devfs_revoke(ap)
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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 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 */
|
||||
|
Loading…
Reference in New Issue
Block a user