diff options
author | bp <bp@FreeBSD.org> | 2000-09-05 09:02:07 +0000 |
---|---|---|
committer | bp <bp@FreeBSD.org> | 2000-09-05 09:02:07 +0000 |
commit | 64ac0aa678e382d03d7bad1b3c1401222e4bc7e7 (patch) | |
tree | e7cfe6afe4dacc7a1ef0b7d39a7453db9fee0a61 /sys/miscfs | |
parent | 106f8e14c88b3d49326a76d131a37eaaf6f29ed4 (diff) | |
download | FreeBSD-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/miscfs')
-rw-r--r-- | sys/miscfs/nullfs/null.h | 12 | ||||
-rw-r--r-- | sys/miscfs/nullfs/null_subr.c | 44 | ||||
-rw-r--r-- | sys/miscfs/nullfs/null_vfsops.c | 40 | ||||
-rw-r--r-- | sys/miscfs/nullfs/null_vnops.c | 72 |
4 files changed, 130 insertions, 38 deletions
diff --git a/sys/miscfs/nullfs/null.h b/sys/miscfs/nullfs/null.h index f825ee8..a5ebf87 100644 --- a/sys/miscfs/nullfs/null.h +++ b/sys/miscfs/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/miscfs/nullfs/null_subr.c b/sys/miscfs/nullfs/null_subr.c index 900bd15..3671f0a 100644 --- a/sys/miscfs/nullfs/null_subr.c +++ b/sys/miscfs/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/miscfs/nullfs/null_vfsops.c b/sys/miscfs/nullfs/null_vfsops.c index 754a121..5b49fbb 100644 --- a/sys/miscfs/nullfs/null_vfsops.c +++ b/sys/miscfs/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/miscfs/nullfs/null_vnops.c b/sys/miscfs/nullfs/null_vnops.c index 8329d5e..5692df6 100644 --- a/sys/miscfs/nullfs/null_vnops.c +++ b/sys/miscfs/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 } }; |