summaryrefslogtreecommitdiffstats
path: root/sys/fs/nullfs
diff options
context:
space:
mode:
authorbp <bp@FreeBSD.org>2000-09-05 09:02:07 +0000
committerbp <bp@FreeBSD.org>2000-09-05 09:02:07 +0000
commit64ac0aa678e382d03d7bad1b3c1401222e4bc7e7 (patch)
treee7cfe6afe4dacc7a1ef0b7d39a7453db9fee0a61 /sys/fs/nullfs
parent106f8e14c88b3d49326a76d131a37eaaf6f29ed4 (diff)
downloadFreeBSD-src-64ac0aa678e382d03d7bad1b3c1401222e4bc7e7.zip
FreeBSD-src-64ac0aa678e382d03d7bad1b3c1401222e4bc7e7.tar.gz
Various cleanups towards make nullfs functional (it is still broken
at this point): Replace all '#ifdef DEBUG' with '#ifdef NULLFS_DEBUG' and add NULLFSDEBUG macro. Protect nullfs hash table with lockmgr. Use proper order of operations when freeing mnt_data. Return correct fsid in the null_getattr(). Add null_open() function to catch MNT_NODEV (obtained from NetBSD). Add null_rename() to catch cross-fs rename operations (submitted by Ustimenko Semen <semen@iclub.nsu.ru>) Remove duplicate $FreeBSD$ tags.
Diffstat (limited to 'sys/fs/nullfs')
-rw-r--r--sys/fs/nullfs/null.h12
-rw-r--r--sys/fs/nullfs/null_subr.c44
-rw-r--r--sys/fs/nullfs/null_vfsops.c40
-rw-r--r--sys/fs/nullfs/null_vnops.c72
4 files changed, 130 insertions, 38 deletions
diff --git a/sys/fs/nullfs/null.h b/sys/fs/nullfs/null.h
index f825ee8..a5ebf87 100644
--- a/sys/fs/nullfs/null.h
+++ b/sys/fs/nullfs/null.h
@@ -62,6 +62,7 @@ struct null_node {
#define NULLTOV(xp) ((xp)->null_vnode)
int nullfs_init(struct vfsconf *vfsp);
+int nullfs_uninit(struct vfsconf *vfsp);
int null_node_create(struct mount *mp, struct vnode *target, struct vnode **vpp);
int null_bypass(struct vop_generic_args *ap);
@@ -73,5 +74,16 @@ struct vnode *null_checkvp(struct vnode *vp, char *fil, int lno);
#endif
extern vop_t **null_vnodeop_p;
+extern struct lock null_hashlock;
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_NULLFSNODE);
+#endif
+
+#ifdef NULLFS_DEBUG
+#define NULLFSDEBUG(format, args...) printf(format ,## args)
+#else
+#define NULLFSDEBUG(format, args...)
+#endif /* NULLFS_DEBUG */
#endif /* _KERNEL */
diff --git a/sys/fs/nullfs/null_subr.c b/sys/fs/nullfs/null_subr.c
index 900bd15..3671f0a 100644
--- a/sys/fs/nullfs/null_subr.c
+++ b/sys/fs/nullfs/null_subr.c
@@ -40,6 +40,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/mount.h>
@@ -59,8 +60,13 @@
#define NULL_NHASH(vp) \
(&null_node_hashtbl[(((uintptr_t)vp)>>LOG2_SIZEVNODE) & null_node_hash])
+
static LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
static u_long null_node_hash;
+struct lock null_hashlock;
+
+static MALLOC_DEFINE(M_NULLFSHASH, "NULLFS hash", "NULLFS hash table");
+MALLOC_DEFINE(M_NULLFSNODE, "NULLFS node", "NULLFS vnode private part");
static int null_node_alloc(struct mount *mp, struct vnode *lowervp,
struct vnode **vpp);
@@ -75,10 +81,19 @@ nullfs_init(vfsp)
struct vfsconf *vfsp;
{
-#ifdef DEBUG
- printf("nullfs_init\n"); /* printed during system boot */
-#endif
- null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash);
+ NULLFSDEBUG("nullfs_init\n"); /* printed during system boot */
+ null_node_hashtbl = hashinit(NNULLNODECACHE, M_NULLFSHASH, &null_node_hash);
+ lockinit(&null_hashlock, PVFS, "nullhs", 0, 0);
+ return (0);
+}
+
+int
+nullfs_uninit(vfsp)
+ struct vfsconf *vfsp;
+{
+
+ if (null_node_hashtbl)
+ free(null_node_hashtbl, M_NULLFSHASH);
return (0);
}
@@ -103,9 +118,11 @@ null_node_find(mp, lowervp)
*/
hd = NULL_NHASH(lowervp);
loop:
+ lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, p);
for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) {
if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
vp = NULLTOV(a);
+ lockmgr(&null_hashlock, LK_RELEASE, NULL, p);
/*
* We need vget for the VXLOCK
* stuff, but we don't want to lock
@@ -118,6 +135,7 @@ loop:
return (vp);
}
}
+ lockmgr(&null_hashlock, LK_RELEASE, NULL, p);
return NULLVP;
}
@@ -134,6 +152,7 @@ null_node_alloc(mp, lowervp, vpp)
struct vnode *lowervp;
struct vnode **vpp;
{
+ struct proc *p = curproc; /* XXX */
struct null_node_hashhead *hd;
struct null_node *xp;
struct vnode *othervp, *vp;
@@ -144,11 +163,12 @@ null_node_alloc(mp, lowervp, vpp)
* might cause a bogus v_data pointer to get dereferenced
* elsewhere if MALLOC should block.
*/
- MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
+ MALLOC(xp, struct null_node *, sizeof(struct null_node),
+ M_NULLFSNODE, M_WAITOK);
error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp);
if (error) {
- FREE(xp, M_TEMP);
+ FREE(xp, M_NULLFSNODE);
return (error);
}
vp = *vpp;
@@ -164,15 +184,17 @@ null_node_alloc(mp, lowervp, vpp)
*/
othervp = null_node_find(mp, lowervp);
if (othervp) {
- FREE(xp, M_TEMP);
+ FREE(xp, M_NULLFSNODE);
vp->v_type = VBAD; /* node is discarded */
vp->v_usecount = 0; /* XXX */
*vpp = othervp;
return 0;
};
+ lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, p);
VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */
hd = NULL_NHASH(lowervp);
LIST_INSERT_HEAD(hd, xp, null_hash);
+ lockmgr(&null_hashlock, LK_RELEASE, NULL, p);
return 0;
}
@@ -196,7 +218,7 @@ null_node_create(mp, lowervp, newvpp)
* null_node_find has taken another reference
* to the alias vnode.
*/
-#ifdef DEBUG
+#ifdef NULLFS_DEBUG
vprint("null_node_create: exists", aliasvp);
#endif
/* VREF(aliasvp); --- done in null_node_find */
@@ -206,9 +228,7 @@ null_node_create(mp, lowervp, newvpp)
/*
* Get new vnode.
*/
-#ifdef DEBUG
- printf("null_node_create: create new alias vnode\n");
-#endif
+ NULLFSDEBUG("null_node_create: create new alias vnode\n");
/*
* Make new vnode reference the null_node.
@@ -233,7 +253,7 @@ null_node_create(mp, lowervp, newvpp)
};
#endif
-#ifdef DEBUG
+#ifdef NULLFS_DEBUG
vprint("null_node_create: alias", aliasvp);
vprint("null_node_create: lower", lowervp);
#endif
diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c
index 754a121..5b49fbb 100644
--- a/sys/fs/nullfs/null_vfsops.c
+++ b/sys/fs/nullfs/null_vfsops.c
@@ -93,9 +93,7 @@ nullfs_mount(mp, path, data, ndp, p)
u_int size;
int isvnunlocked = 0;
-#ifdef DEBUG
- printf("nullfs_mount(mp = %p)\n", (void *)mp);
-#endif
+ NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp);
/*
* Update is a no-op
@@ -149,9 +147,7 @@ nullfs_mount(mp, path, data, ndp, p)
* Check multi null mount to avoid `lock against myself' panic.
*/
if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) {
-#ifdef DEBUG
- printf("nullfs_mount: multi null mount?\n");
-#endif
+ NULLFSDEBUG("nullfs_mount: multi null mount?\n");
return (EDEADLK);
}
@@ -199,10 +195,8 @@ nullfs_mount(mp, path, data, ndp, p)
&size);
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
(void)nullfs_statfs(mp, &mp->mnt_stat, p);
-#ifdef DEBUG
- printf("nullfs_mount: lower %s, alias at %s\n",
+ NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n",
mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
-#endif
return (0);
}
@@ -231,12 +225,11 @@ nullfs_unmount(mp, mntflags, p)
struct proc *p;
{
struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
+ void *mntdata;
int error;
int flags = 0;
-#ifdef DEBUG
- printf("nullfs_unmount(mp = %p)\n", (void *)mp);
-#endif
+ NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp);
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
@@ -257,7 +250,7 @@ nullfs_unmount(mp, mntflags, p)
if (error)
return (error);
-#ifdef DEBUG
+#ifdef NULLFS_DEBUG
vprint("alias root of lower", nullm_rootvp);
#endif
/*
@@ -271,8 +264,9 @@ nullfs_unmount(mp, mntflags, p)
/*
* Finally, throw away the null_mount structure
*/
- free(mp->mnt_data, M_NULLFSMNT); /* XXX */
+ mntdata = mp->mnt_data;
mp->mnt_data = 0;
+ free(mntdata, M_NULLFSMNT); /* XXX */
return 0;
}
@@ -284,29 +278,27 @@ nullfs_root(mp, vpp)
struct proc *p = curproc; /* XXX */
struct vnode *vp;
-#ifdef DEBUG
- printf("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp,
+ NULLFSDEBUG("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp,
(void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp,
(void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp));
-#endif
/*
* Return locked reference to root.
*/
vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
VREF(vp);
+#ifdef NULLFS_DEBUG
if (VOP_ISLOCKED(vp, NULL)) {
/*
* XXX
* Should we check type of node?
*/
-#ifdef DEBUG
printf("nullfs_root: multi null mount?\n");
-#endif
vrele(vp);
return (EDEADLK);
- } else
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ }
+#endif
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
*vpp = vp;
return 0;
}
@@ -331,11 +323,9 @@ nullfs_statfs(mp, sbp, p)
int error;
struct statfs mstat;
-#ifdef DEBUG
- printf("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp,
+ NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp,
(void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp,
(void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp));
-#endif
bzero(&mstat, sizeof(mstat));
@@ -440,7 +430,7 @@ static struct vfsops null_vfsops = {
nullfs_checkexp,
nullfs_vptofh,
nullfs_init,
- vfs_stduninit,
+ nullfs_uninit,
nullfs_extattrctl,
};
diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c
index 8329d5e..5692df6 100644
--- a/sys/fs/nullfs/null_vnops.c
+++ b/sys/fs/nullfs/null_vnops.c
@@ -37,7 +37,6 @@
*
* Ancestors:
* @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92
- * $FreeBSD$
* ...and...
* @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
*
@@ -193,8 +192,10 @@ static int null_getattr(struct vop_getattr_args *ap);
static int null_inactive(struct vop_inactive_args *ap);
static int null_lock(struct vop_lock_args *ap);
static int null_lookup(struct vop_lookup_args *ap);
+static int null_open(struct vop_open_args *ap);
static int null_print(struct vop_print_args *ap);
static int null_reclaim(struct vop_reclaim_args *ap);
+static int null_rename(struct vop_rename_args *ap);
static int null_setattr(struct vop_setattr_args *ap);
static int null_unlock(struct vop_unlock_args *ap);
@@ -448,6 +449,8 @@ null_getattr(ap)
if ((error = null_bypass((struct vop_generic_args *)ap)) != 0)
return (error);
+
+ ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
return (0);
}
@@ -484,6 +487,66 @@ null_access(ap)
}
/*
+ * We must handle open to be able to catch MNT_NODEV and friends.
+ */
+static int
+null_open(ap)
+ struct vop_open_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct vnode *lvp = NULLVPTOLOWERVP(ap->a_vp);
+
+ if ((vp->v_mount->mnt_flag & MNT_NODEV) &&
+ (lvp->v_type == VBLK || lvp->v_type == VCHR))
+ return ENXIO;
+
+ return (null_bypass((struct vop_generic_args *)ap));
+}
+
+/*
+ * We handle this to eliminate null FS to lower FS
+ * file moving. Don't know why we don't allow this,
+ * possibly we should.
+ */
+static int
+null_rename(ap)
+ struct vop_rename_args /* {
+ struct vnode *a_fdvp;
+ struct vnode *a_fvp;
+ struct componentname *a_fcnp;
+ struct vnode *a_tdvp;
+ struct vnode *a_tvp;
+ struct componentname *a_tcnp;
+ } */ *ap;
+{
+ struct vnode *tdvp = ap->a_tdvp;
+ struct vnode *fvp = ap->a_fvp;
+ struct vnode *fdvp = ap->a_fdvp;
+ struct vnode *tvp = ap->a_tvp;
+
+ /* Check for cross-device rename. */
+ if ((fvp->v_mount != tdvp->v_mount) ||
+ (tvp && (fvp->v_mount != tvp->v_mount))) {
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ if (tvp)
+ vput(tvp);
+ vrele(fdvp);
+ vrele(fvp);
+ return (EXDEV);
+ }
+
+ return (null_bypass((struct vop_generic_args *)ap));
+}
+
+/*
* We need to process our own vnode lock and then clear the
* interlock flag as it applies only to our vnode, not the
* vnodes below us on the stack.
@@ -568,7 +631,9 @@ null_reclaim(ap)
*/
/* After this assignment, this node will not be re-used. */
xp->null_lowervp = NULLVP;
+ lockmgr(&null_hashlock, LK_EXCLUSIVE, NULL, ap->a_p);
LIST_REMOVE(xp, null_hash);
+ lockmgr(&null_hashlock, LK_RELEASE, NULL, ap->a_p);
FREE(vp->v_data, M_TEMP);
vp->v_data = NULL;
vrele (lowervp);
@@ -593,13 +658,18 @@ vop_t **null_vnodeop_p;
static struct vnodeopv_entry_desc null_vnodeop_entries[] = {
{ &vop_default_desc, (vop_t *) null_bypass },
{ &vop_access_desc, (vop_t *) null_access },
+ { &vop_bmap_desc, (vop_t *) vop_eopnotsupp },
{ &vop_getattr_desc, (vop_t *) null_getattr },
+ { &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount},
{ &vop_inactive_desc, (vop_t *) null_inactive },
{ &vop_lock_desc, (vop_t *) null_lock },
{ &vop_lookup_desc, (vop_t *) null_lookup },
+ { &vop_open_desc, (vop_t *) null_open },
{ &vop_print_desc, (vop_t *) null_print },
{ &vop_reclaim_desc, (vop_t *) null_reclaim },
+ { &vop_rename_desc, (vop_t *) null_rename },
{ &vop_setattr_desc, (vop_t *) null_setattr },
+ { &vop_strategy_desc, (vop_t *) vop_eopnotsupp },
{ &vop_unlock_desc, (vop_t *) null_unlock },
{ NULL, NULL }
};
OpenPOWER on IntegriCloud