Page MenuHomeFreeBSD

D21525.diff
No OneTemporary

D21525.diff

Index: sys/fs/devfs/devfs_devs.c
===================================================================
--- sys/fs/devfs/devfs_devs.c
+++ sys/fs/devfs/devfs_devs.c
@@ -62,6 +62,7 @@
static MALLOC_DEFINE(M_DEVFS2, "DEVFS2", "DEVFS data 2");
static MALLOC_DEFINE(M_DEVFS3, "DEVFS3", "DEVFS data 3");
static MALLOC_DEFINE(M_CDEVP, "DEVFS1", "DEVFS cdev_priv storage");
+MALLOC_DEFINE(M_CDEV_VP, "DEVFS4", "DEVFS vnode tables");
SYSCTL_NODE(_vfs, OID_AUTO, devfs, CTLFLAG_RW, 0, "DEVFS filesystem");
@@ -144,6 +145,8 @@
LIST_INIT(&cdev->si_children);
vfs_timestamp(&ts);
cdev->si_atime = cdev->si_mtime = cdev->si_ctime = ts;
+ cdev->si_vnodes = (void *)&cdev->si_vnodes_local;
+ cdev->si_vnodes_size = nitems(cdev->si_vnodes_local);
return (cdev);
}
@@ -173,6 +176,9 @@
devfs_free(struct cdev *cdev)
{
struct cdev_priv *cdp;
+#ifdef INVARIANTS
+ int i;
+#endif
cdp = cdev2priv(cdev);
if (cdev->si_cred != NULL)
@@ -180,6 +186,18 @@
devfs_free_cdp_inode(cdp->cdp_inode);
if (cdp->cdp_maxdirent > 0)
free(cdp->cdp_dirents, M_DEVFS2);
+ KASSERT(cdev->si_vnodes_assigned == 0, ("%s: cdev %p still has "
+ "vnodes %d assigned", __func__, cdev, cdev->si_vnodes_assigned));
+#ifdef INVARIANTS
+ for (i = 0; i < cdev->si_vnodes_size; i++) {
+ if (cdev->si_vnodes[i] != NULL) {
+ printf("%s: cdev %p non-NULL entry at %d\n", __func__,
+ cdev, i);
+ }
+ }
+#endif
+ if (cdev->si_vnodes != (void *)&cdev->si_vnodes_local)
+ free(cdev->si_vnodes, M_CDEV_VP);
free(cdp, M_CDEVP);
}
Index: sys/fs/devfs/devfs_vnops.c
===================================================================
--- sys/fs/devfs/devfs_vnops.c
+++ sys/fs/devfs/devfs_vnops.c
@@ -82,6 +82,7 @@
#include <vm/vm_object.h>
static MALLOC_DEFINE(M_CDEVPDATA, "DEVFSP", "Metainfo for cdev-fp data");
+MALLOC_DECLARE(M_CDEV_VP);
struct mtx devfs_de_interlock;
MTX_SYSINIT(devfs_de_interlock, &devfs_de_interlock, "devfs interlock", MTX_DEF);
@@ -418,6 +419,88 @@
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
* it on return.
@@ -485,14 +568,16 @@
if (de->de_dirent->d_type == DT_CHR) {
vp->v_type = VCHR;
- VI_LOCK(vp);
- dev_lock();
+ for (;;) {
+ VI_LOCK(vp);
+ dev_lock();
+ if (dev_vn_add_vp(dev, vp) == 0)
+ break;
+ dev_unlock();
+ VI_UNLOCK(vp);
+ dev_vn_growtable(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. */
dsw = dev->si_devsw;
if (dsw != NULL && (dsw->d_flags & D_TTY) != 0)
@@ -602,7 +687,7 @@
if (vp == p->p_session->s_ttyvp) {
SESS_LOCK(p->p_session);
VI_LOCK(vp);
- if (count_dev(dev) == 2 &&
+ if (count_dev_cmp(dev, 2) == 0 &&
(vp->v_iflag & VI_DOOMED) == 0) {
p->p_session->s_ttyvp = NULL;
p->p_session->s_ttydp = NULL;
@@ -636,12 +721,12 @@
dflags |= FREVOKE | FNONBLOCK;
} else if (dsw->d_flags & D_TRACKCLOSE) {
/* Keep device updated on status. */
- } else if (count_dev(dev) > 1) {
+ } else if (count_dev_cmp(dev, 1) > 0) {
VI_UNLOCK(vp);
dev_relthread(dev, ref);
return (0);
}
- if (count_dev(dev) == 1)
+ if (count_dev_cmp(dev, 1) == 0)
dflags |= FLASTCLOSE;
vholdl(vp);
VI_UNLOCK(vp);
@@ -1445,9 +1530,7 @@
VI_LOCK(vp);
dev_lock();
dev = vp->v_rdev;
- vp->v_rdev = NULL;
- if (dev != NULL)
- dev->si_usecount -= vp->v_usecount;
+ dev_vn_remove_vp(dev, vp);
dev_unlock();
VI_UNLOCK(vp);
if (dev != NULL)
Index: sys/kern/kern_conf.c
===================================================================
--- sys/kern/kern_conf.c
+++ sys/kern/kern_conf.c
@@ -1526,8 +1526,8 @@
dev = (struct cdev *)addr;
cdp = cdev2priv(dev);
- db_printf("dev %s ref %d use %ld thr %ld inuse %u fdpriv %p\n",
- dev->si_name, dev->si_refcount, dev->si_usecount,
+ db_printf("dev %s ref %d use %d thr %ld inuse %u fdpriv %p\n",
+ dev->si_name, dev->si_refcount, count_dev(dev),
dev->si_threadcount, cdp->cdp_inuse, cdp->cdp_fdpriv.lh_first);
db_printf("devsw %p si_drv0 %d si_drv1 %p si_drv2 %p\n",
dev->si_devsw, dev->si_drv0, dev->si_drv1, dev->si_drv2);
@@ -1563,5 +1563,8 @@
CDP_FLAG(CDP_ACTIVE);
CDP_FLAG(CDP_SCHED_DTR);
db_printf("cdp_flags %s\n", buf);
+ db_printf("si_vnodes %p si_vnodes_assigned %d si_vnodes_index %d"
+ "si_vnodes_size %d\n", dev->si_vnodes, dev->si_vnodes_assigned,
+ dev->si_vnodes_index, dev->si_vnodes_size);
}
#endif
Index: sys/kern/vfs_subr.c
===================================================================
--- sys/kern/vfs_subr.c
+++ sys/kern/vfs_subr.c
@@ -107,8 +107,6 @@
static void syncer_shutdown(void *arg, int howto);
static int vtryrecycle(struct vnode *vp);
static void v_init_counters(struct vnode *);
-static void v_incr_devcount(struct vnode *);
-static void v_decr_devcount(struct vnode *);
static void vgonel(struct vnode *);
static void vfs_knllock(void *arg);
static void vfs_knlunlock(void *arg);
@@ -2630,36 +2628,6 @@
refcount_init(&vp->v_usecount, 1);
}
-/*
- * Increment si_usecount of the associated device, if any.
- */
-static void
-v_incr_devcount(struct vnode *vp)
-{
-
- ASSERT_VI_LOCKED(vp, __FUNCTION__);
- if (vp->v_type == VCHR && vp->v_rdev != NULL) {
- dev_lock();
- vp->v_rdev->si_usecount++;
- dev_unlock();
- }
-}
-
-/*
- * Decrement si_usecount of the associated device, if any.
- */
-static void
-v_decr_devcount(struct vnode *vp)
-{
-
- ASSERT_VI_LOCKED(vp, __FUNCTION__);
- if (vp->v_type == VCHR && vp->v_rdev != NULL) {
- dev_lock();
- vp->v_rdev->si_usecount--;
- dev_unlock();
- }
-}
-
/*
* Grab a particular vnode from the free list, increment its
* reference count and lock it. VI_DOOMED is set if the vnode
@@ -2679,26 +2647,11 @@
{
enum vgetstate vs;
- if (__predict_true(vp->v_type != VCHR)) {
- if (refcount_acquire_if_not_zero(&vp->v_usecount)) {
- vs = VGET_USECOUNT;
- } else {
- _vhold(vp, interlock);
- vs = VGET_HOLDCNT;
- }
+ if (refcount_acquire_if_not_zero(&vp->v_usecount)) {
+ vs = VGET_USECOUNT;
} else {
- if (!interlock)
- VI_LOCK(vp);
- if (vp->v_usecount == 0) {
- vholdl(vp);
- vs = VGET_HOLDCNT;
- } else {
- v_incr_devcount(vp);
- refcount_acquire(&vp->v_usecount);
- vs = VGET_USECOUNT;
- }
- if (!interlock)
- VI_UNLOCK(vp);
+ _vhold(vp, interlock);
+ vs = VGET_HOLDCNT;
}
return (vs);
}
@@ -2761,8 +2714,7 @@
* the vnode around. Otherwise someone else lended their hold count and
* we have to drop ours.
*/
- if (vp->v_type != VCHR &&
- refcount_acquire_if_not_zero(&vp->v_usecount)) {
+ if (refcount_acquire_if_not_zero(&vp->v_usecount)) {
#ifdef INVARIANTS
int old = atomic_fetchadd_int(&vp->v_holdcnt, -1) - 1;
VNASSERT(old > 0, vp, ("%s: wrong hold count", __func__));
@@ -2793,7 +2745,6 @@
}
if (vp->v_usecount > 0)
refcount_release(&vp->v_holdcnt);
- v_incr_devcount(vp);
refcount_acquire(&vp->v_usecount);
if (oweinact && VOP_ISLOCKED(vp) == LK_EXCLUSIVE &&
(flags & LK_NOWAIT) == 0)
@@ -2812,8 +2763,7 @@
ASSERT_VI_UNLOCKED(vp, __func__);
CTR2(KTR_VFS, "%s: vp %p", __func__, vp);
- if (vp->v_type != VCHR &&
- refcount_acquire_if_not_zero(&vp->v_usecount)) {
+ if (refcount_acquire_if_not_zero(&vp->v_usecount)) {
VNODE_REFCOUNT_FENCE_ACQ();
VNASSERT(vp->v_holdcnt > 0, vp,
("%s: active vnode not held", __func__));
@@ -2838,7 +2788,6 @@
vp->v_iflag &= ~VI_OWEINACT;
VNODE_REFCOUNT_FENCE_REL();
}
- v_incr_devcount(vp);
refcount_acquire(&vp->v_usecount);
}
@@ -2847,12 +2796,6 @@
{
CTR2(KTR_VFS, "%s: vp %p", __func__, vp);
- if (__predict_false(vp->v_type == VCHR)) {
- VNASSERT(vp->v_holdcnt > 0 && vp->v_usecount > 0, vp,
- ("%s: wrong ref counts", __func__));
- vref(vp);
- return;
- }
#ifdef INVARIANTS
int old = atomic_fetchadd_int(&vp->v_usecount, 1);
VNASSERT(old > 0, vp, ("%s: wrong use count", __func__));
@@ -2917,8 +2860,7 @@
if (func == VPUTX_VPUT)
VOP_UNLOCK(vp, 0);
- if (vp->v_type != VCHR &&
- refcount_release_if_not_last(&vp->v_usecount))
+ if (refcount_release_if_not_last(&vp->v_usecount))
return;
VI_LOCK(vp);
@@ -2928,7 +2870,6 @@
* prevent vgone() races. We drop the use count here and the
* hold count below when we're done.
*/
- v_decr_devcount(vp);
if (!refcount_release(&vp->v_usecount)) {
VI_UNLOCK(vp);
return;
@@ -3083,6 +3024,13 @@
mp->mnt_activevnodelistsize++;
mtx_unlock(&mp->mnt_listmtx);
refcount_acquire(&vp->v_holdcnt);
+ if (vp->v_rdev != NULL) {
+ VNASSERT(vp->v_type == VCHR, vp,
+ ("vdropl: non-VCHR vnode with v_rdev"));
+ dev_lock();
+ dev_vn_table_add(vp->v_rdev, vp);
+ dev_unlock();
+ }
if (!locked)
VI_UNLOCK(vp);
}
@@ -3145,6 +3093,13 @@
("vnode already free"));
VNASSERT(vp->v_holdcnt == 0, vp,
("vdropl: freeing when we shouldn't"));
+ if (vp->v_rdev != NULL) {
+ VNASSERT(vp->v_type == VCHR, vp,
+ ("vdropl: non-VCHR vnode with v_rdev"));
+ dev_lock();
+ dev_vn_table_remove(vp->v_rdev, vp);
+ dev_unlock();
+ }
active = vp->v_iflag & VI_ACTIVE;
if ((vp->v_iflag & VI_OWEINACT) == 0) {
vp->v_iflag &= ~VI_ACTIVE;
@@ -3652,12 +3607,8 @@
int
vcount(struct vnode *vp)
{
- int count;
- dev_lock();
- count = vp->v_rdev->si_usecount;
- dev_unlock();
- return (count);
+ return (count_dev(vp->v_rdev));
}
/*
@@ -3666,12 +3617,38 @@
int
count_dev(struct cdev *dev)
{
- int count;
+ int count, i;
+
+ count = 0;
+ dev_lock();
+ for (i = 0; i < dev->si_vnodes_index; i++) {
+ count += dev->si_vnodes[i]->v_usecount;
+ }
+ dev_unlock();
+ return (count);
+}
+
+int
+count_dev_cmp(struct cdev *dev, int n)
+{
+ int count, i, ret;
+ count = 0;
dev_lock();
- count = dev->si_usecount;
+ for (i = 0; i < dev->si_vnodes_index; i++) {
+ count += dev->si_vnodes[i]->v_usecount;
+ if (count > n) {
+ ret = 1;
+ goto out;
+ }
+ }
+ if (count == n)
+ ret = 0;
+ else
+ ret = -1;
+out:
dev_unlock();
- return(count);
+ return (ret);
}
/*
Index: sys/sys/conf.h
===================================================================
--- sys/sys/conf.h
+++ sys/sys/conf.h
@@ -83,12 +83,16 @@
void *si_drv1, *si_drv2;
struct cdevsw *si_devsw;
int si_iosize_max; /* maximum I/O size (for physio &al) */
- u_long si_usecount;
u_long si_threadcount;
+ struct vnode **si_vnodes;
+ int si_vnodes_index;
+ int si_vnodes_size;
+ int si_vnodes_assigned;
union {
struct snapdata *__sid_snapdata;
} __si_u;
char si_name[SPECNAMELEN + 1];
+ struct vnode *si_vnodes_local[2];
};
#define si_snapdata __si_u.__sid_snapdata
@@ -256,7 +260,10 @@
#define make_dev_args_init(a) \
make_dev_args_init_impl((a), sizeof(struct make_dev_args))
+void dev_vn_table_add(struct cdev *dev, struct vnode *vp);
+void dev_vn_table_remove(struct cdev *dev, struct vnode *vp);
int count_dev(struct cdev *_dev);
+int count_dev_cmp(struct cdev *_dev, int n);
void delist_dev(struct cdev *_dev);
void destroy_dev(struct cdev *_dev);
int destroy_dev_sched(struct cdev *dev);

File Metadata

Mime Type
text/plain
Expires
Wed, Sep 2, 2:23 AM (1 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37877449
Default Alt Text
D21525.diff (12 KB)

Event Timeline