summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/include/sys/vnode.h4
-rw-r--r--sys/kern/vfs_subr.c19
2 files changed, 23 insertions, 0 deletions
diff --git a/sys/include/sys/vnode.h b/sys/include/sys/vnode.h
index 545fa2f..3f3b011 100644
--- a/sys/include/sys/vnode.h
+++ b/sys/include/sys/vnode.h
@@ -31,6 +31,7 @@
#define _SYS_VNODE_H_
#include <sys/types.h>
+#include <sys/atomic.h>
#include <sys/sio.h>
#if defined(_KERNEL)
@@ -42,8 +43,11 @@ struct vnode {
int flags;
void *data;
const struct vops *vops;
+ uint32_t refcount;
};
+#define vfs_vref(VP) (atomic_inc_int(&(VP)->refcount))
+
/* Vnode type flags */
#define VNON 0x00 /* Uninitialized */
#define VREG 0x01 /* Regular file */
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index b732cb4..0d4be72 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -30,6 +30,7 @@
#include <sys/vnode.h>
#include <sys/errno.h>
#include <sys/mount.h>
+#include <sys/syslog.h>
#include <vm/dynalloc.h>
#include <string.h>
@@ -46,6 +47,7 @@ vfs_alloc_vnode(struct vnode **res, int type)
memset(vp, 0, sizeof(*vp));
vp->type = type;
+ vp->refcount = 1;
*res = vp;
return 0;
}
@@ -83,6 +85,23 @@ vfs_release_vnode(struct vnode *vp)
if (vp == NULL)
return -EINVAL;
+
+ /*
+ * The refcount cannot be zero before we decrement it,
+ * something is quite wrong if this happens.
+ */
+ if (vp->refcount == 0) {
+ kprintf("Cannot release vnode, bad refcount\n");
+ return -EIO;
+ }
+
+ /*
+ * Drop the reference and don't destroy the vnode
+ * if it's still not zero.
+ */
+ if (atomic_dec_int(&vp->refcount) > 0)
+ return 0;
+
if (vops->reclaim != NULL)
status = vops->reclaim(vp);
if (status != 0)