Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F169263820
D21525.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D21525.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D21525: [wip] vfs: decentralize device usecount
Attached
Detach File
Event Timeline
Log In to Comment