Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Aug 2000 01:10:07 -0700 (PDT)
From:      Sheldon Hearn <sheldonh@uunet.co.za>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: kern/20632: stacking mount_null causes an error: mount_null: Resource deadlock avoided 
Message-ID:  <200008160810.BAA92657@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/20632; it has been noted by GNATS.

From: Sheldon Hearn <sheldonh@uunet.co.za>
To: akr@m17n.org
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: kern/20632: stacking mount_null causes an error: mount_null: Resource deadlock avoided 
Date: Wed, 16 Aug 2000 10:01:58 +0200

 On Wed, 16 Aug 2000 12:45:21 +0900, akr@m17n.org wrote:
 
 > If null file system is stacked by mount_null, following error is caused.
 > 
 >   mount_null: Resource deadlock avoided
 > 
 > Then, umount cannot unmount the file system with same error and some
 > commands hangs forever.
 
 NULLFS is known to be broken.  You might want to try out the following
 patch (unfortunately I forget who sent it, but I'll have a look) and
 report back.
 
 Ciao,
 Sheldon.
 
 Common subdirectories: ./nullfs.orig/CVS and ./nullfs/CVS
 diff -c ./nullfs.orig/null_vfsops.c ./nullfs/null_vfsops.c
 *** ./nullfs.orig/null_vfsops.c	Fri Aug  4 16:38:49 2000
 --- ./nullfs/null_vfsops.c	Sun Aug  6 19:58:23 2000
 ***************
 *** 57,66 ****
   
   static MALLOC_DEFINE(M_NULLFSMNT, "NULLFS mount", "NULLFS mount structure");
   
 - static int	nullfs_fhtovp __P((struct mount *mp, struct fid *fidp,
 - 				   struct vnode **vpp));
   static int	nullfs_checkexp __P((struct mount *mp, struct sockaddr *nam,
   				    int *extflagsp, struct ucred **credanonp));
   static int	nullfs_mount __P((struct mount *mp, char *path, caddr_t data,
   				  struct nameidata *ndp, struct proc *p));
   static int	nullfs_quotactl __P((struct mount *mp, int cmd, uid_t uid,
 --- 57,69 ----
   
   static MALLOC_DEFINE(M_NULLFSMNT, "NULLFS mount", "NULLFS mount structure");
   
   static int	nullfs_checkexp __P((struct mount *mp, struct sockaddr *nam,
   				    int *extflagsp, struct ucred **credanonp));
 + static int	nullfs_extattrctl __P((struct mount *mp, int cmd,
 + 				       const char *attrname, caddr_t arg,
 + 				       struct proc *p));
 + static int	nullfs_fhtovp __P((struct mount *mp, struct fid *fidp,
 + 				   struct vnode **vpp));
   static int	nullfs_mount __P((struct mount *mp, char *path, caddr_t data,
   				  struct nameidata *ndp, struct proc *p));
   static int	nullfs_quotactl __P((struct mount *mp, int cmd, uid_t uid,
 ***************
 *** 372,378 ****
   	struct proc *p;
   {
   	/*
 ! 	 * XXX - Assumes no data cached at null layer.
   	 */
   	return (0);
   }
 --- 375,383 ----
   	struct proc *p;
   {
   	/*
 ! 	 * XXX There are no buffers to flush, as we don't
 ! 	 *     have VOP_BMAP. But there are pages. Don't 
 ! 	 *     know how to flush pages.
   	 */
   	return (0);
   }
 ***************
 *** 383,390 ****
   	ino_t ino;
   	struct vnode **vpp;
   {
   
 ! 	return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
   }
   
   static int
 --- 388,399 ----
   	ino_t ino;
   	struct vnode **vpp;
   {
 + 	int error;
 + 	error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
 + 	if (error)
 + 		return (error);
   
 ! 	return (null_node_create(mp, *vpp, vpp));
   }
   
   static int
 ***************
 *** 393,400 ****
   	struct fid *fidp;
   	struct vnode **vpp;
   {
   
 ! 	return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, vpp);
   }
   
   static int
 --- 402,413 ----
   	struct fid *fidp;
   	struct vnode **vpp;
   {
 + 	int error;
 + 	error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, vpp);
 + 	if (error)
 + 		return (error);
   
 ! 	return (null_node_create(mp, *vpp, vpp));
   }
   
   static int
 diff -c ./nullfs.orig/null_vnops.c ./nullfs/null_vnops.c
 *** ./nullfs.orig/null_vnops.c	Fri Aug  4 16:38:49 2000
 --- ./nullfs/null_vnops.c	Sun Aug  6 20:05:18 2000
 ***************
 *** 37,43 ****
    *
    * Ancestors:
    *	@(#)lofs_vnops.c	1.2 (Berkeley) 6/18/92
 -  * $FreeBSD: src/sys/miscfs/nullfs/null_vnops.c,v 1.38 1999/12/11 16:12:56 eivind Exp $
    *	...and...
    *	@(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
    *
 --- 37,42 ----
 ***************
 *** 183,188 ****
 --- 182,193 ----
   #include <sys/namei.h>
   #include <sys/malloc.h>
   #include <sys/buf.h>
 + 
 + #include <vm/vm.h>
 + #include <vm/vm_extern.h>
 + #include <vm/vm_object.h>
 + #include <vm/vnode_pager.h>
 + 
   #include <miscfs/nullfs/null.h>
   
   static int null_bug_bypass = 0;   /* for debugging: enables bypass printf'ing */
 ***************
 *** 191,203 ****
 --- 196,341 ----
   
   static int	null_access __P((struct vop_access_args *ap));
   static int	null_getattr __P((struct vop_getattr_args *ap));
 + static int	null_getpages __P((struct vop_getpages_args *ap));
   static int	null_inactive __P((struct vop_inactive_args *ap));
   static int	null_lock __P((struct vop_lock_args *ap));
   static int	null_lookup __P((struct vop_lookup_args *ap));
 + static int	null_open __P((struct vop_open_args *));
   static int	null_print __P((struct vop_print_args *ap));
 + static int	null_putpages __P((struct vop_putpages_args *));
   static int	null_reclaim __P((struct vop_reclaim_args *ap));
 + static int	null_rename __P((struct vop_rename_args *));
   static int	null_setattr __P((struct vop_setattr_args *ap));
 + static int	null_strategy __P((struct vop_strategy_args *ap));
   static int	null_unlock __P((struct vop_unlock_args *ap));
 + static int	null_write __P((struct vop_write_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 handle this to create vm_object for lowervp as
 +  * vn_open does for us.
 +  */
 + int
 + null_open(ap)
 + 	struct vop_open_args *ap;
 + {
 + 	int error;
 + 
 + 	/* Process operation */
 + 	error = null_bypass((struct vop_generic_args *)ap);
 + 	if (error)
 + 		return (error);
 + 
 + 	/* Create object, vfs_object_create() check itself if vnode 
 + 	 * already have one or if it can't have one */
 + 	vfs_object_create (NULLVPTOLOWERVP(ap->a_vp), ap->a_p, ap->a_cred);
 + 
 + 	return (error);
 + }
 + 
 + /*
 +  * Panic VOP_STRATEGY operation. Shouldn't happen, as we
 +  * don't have VOP_BMAP.
 +  */
 + static int
 + null_strategy(ap)
 + 	struct vop_strategy_args *ap;
 + {
 + 	panic("null_strategy: NOT IMPLEMENTED!");
 + 
 + 	return (EOPNOTSUPP);
 + }
 + 
 + /*
 +  * We need to look for file size changes, to keep
 +  * vnode_pager up with correct file size.
 +  */
 + static int
 + null_write(ap)
 + 	struct vop_write_args /* {
 + 		struct vnode *a_vp;
 + 		struct uio *a_uio;
 + 		int  a_ioflag;
 + 		struct ucred *a_cred;
 + 	} */ *ap;
 + {
 + 	struct vnode *vp = ap->a_vp;
 + 	struct uio *uio = ap->a_uio;
 + 	off_t newsize;
 + 	off_t oldsize;
 + 	int error;
 + 
 + 	/* Process write operation */
 + 	error = null_bypass((struct vop_generic_args *)ap);
 + 
 + 	/* Update vm_object size, if exist and file size changed */
 + 	if (vp->v_object) {
 + 		oldsize = vp->v_object->un_pager.vnp.vnp_size;
 + 		newsize = uio->uio_offset;
 + 		if (newsize > oldsize)
 + 			vnode_pager_setsize(vp, newsize);
 + 	}
 + 
 + 	return (error);
 + }
 + 
 + /*
 +  * We use generic (put|get)pages routines and no VOP_BMAP operation,
 +  * this force vnode_pager to use VOP_READ and VOP_WRITE
 +  * to access pages.
 +  */
 + int
 + null_getpages(ap)
 + 	struct vop_getpages_args *ap;
 + {
 + 	return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
 + 		ap->a_reqpage);
 + }
 + 
 + int
 + null_putpages(ap)
 + 	struct vop_putpages_args *ap;
 + {
 + 	return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
 + 		ap->a_sync, ap->a_rtvals);
 + }
   
   /*
    * This is the 10-Apr-92 bypass routine.
 ***************
 *** 389,394 ****
 --- 527,534 ----
   
   /*
    * Setattr call. Disallow write attempts if the layer is mounted read-only.
 +  * Also look for file size change, and do appropriate vm_object
 +  * modification.
    */
   int
   null_setattr(ap)
 ***************
 *** 402,407 ****
 --- 542,548 ----
   {
   	struct vnode *vp = ap->a_vp;
   	struct vattr *vap = ap->a_vap;
 + 	int error;
   
     	if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
   	    vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
 ***************
 *** 430,436 ****
   				return (EROFS);
   		}
   	}
 ! 	return (null_bypass((struct vop_generic_args *)ap));
   }
   
   /*
 --- 571,590 ----
   				return (EROFS);
   		}
   	}
 ! 
 ! 	error = null_bypass((struct vop_generic_args *)ap);
 ! 	if (error || vp->v_object == NULL || vap->va_size == VNOVAL)
 ! 		return (error);
 ! 
 ! 	/* If they have changed file size, tell to vnode_pager.
 ! 	 * XXX If they have shrink the file, do we need to
 ! 	 *     invalidate buffers with vtruncbuf()? I think
 ! 	 *     no.
 ! 	 */
 ! 	if (vap->va_size != vp->v_object->un_pager.vnp.vnp_size)
 ! 		vnode_pager_setsize(vp, vap->va_size);
 ! 
 ! 	return (error);
   }
   
   /*
 ***************
 *** 449,457 ****
 --- 603,618 ----
   
   	if ((error = null_bypass((struct vop_generic_args *)ap)) != 0)
   		return (error);
 + 
 + 	/* Fake fsid, also done in vn_stat(), but... */
 + 	ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
 + 
   	return (0);
   }
   
 + /*
 +  * Handle to disallow write access if mounted read-only.
 +  */
   static int
   null_access(ap)
   	struct vop_access_args /* {
 ***************
 *** 519,528 ****
 --- 680,700 ----
   	} */ *ap;
   {
   	vop_nounlock(ap);
 + 
 + 	/* Support unlocking of inactive vnodes */
 + 	if (NULLVPTOLOWERVP(ap->a_vp) == NULLVP)
 + 		return (0);
 + 
   	ap->a_flags &= ~LK_INTERLOCK;
   	return (null_bypass((struct vop_generic_args *)ap));
   }
   
 + /*
 +  * We have to vrele lowervp as soon as possible. Otherway
 +  * we can never discover that someone has removed file
 +  * on lower FS. This technique removes advantages of hash,
 +  * but i don't know other way.
 +  */
   static int
   null_inactive(ap)
   	struct vop_inactive_args /* {
 ***************
 *** 533,557 ****
   	struct vnode *vp = ap->a_vp;
   	struct null_node *xp = VTONULL(vp);
   	struct vnode *lowervp = xp->null_lowervp;
 ! 	/*
 ! 	 * Do nothing (and _don't_ bypass).
 ! 	 * Wait to vrele lowervp until reclaim,
 ! 	 * so that until then our null_node is in the
 ! 	 * cache and reusable.
 ! 	 * We still have to tell the lower layer the vnode
 ! 	 * is now inactive though.
 ! 	 *
 ! 	 * NEEDSWORK: Someday, consider inactive'ing
 ! 	 * the lowervp and then trying to reactivate it
 ! 	 * with capabilities (v_id)
 ! 	 * like they do in the name lookup cache code.
 ! 	 * That's too much work for now.
 ! 	 */
 ! 	VOP_INACTIVE(lowervp, ap->a_p);
   	VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
   	return (0);
   }
   
   static int
   null_reclaim(ap)
   	struct vop_reclaim_args /* {
 --- 705,729 ----
   	struct vnode *vp = ap->a_vp;
   	struct null_node *xp = VTONULL(vp);
   	struct vnode *lowervp = xp->null_lowervp;
 ! 
 ! 	/* Release lowervp totaly */
 ! 	VOP_UNLOCK(lowervp, 0, ap->a_p);
 ! 	vrele (lowervp);
 ! 
 ! 	/* Forget all we knew, remove hash entry */
 ! 	xp->null_lowervp = NULLVP;
 ! 	LIST_REMOVE(xp, null_hash);
 ! 
 ! 	/* Unlock our vnode */
   	VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
 + 
   	return (0);
   }
   
 + /*
 +  * We can free memory in null_inactive, but we do this
 +  * here. (Possible to guard vp->v_data to point somewhere)
 +  */
   static int
   null_reclaim(ap)
   	struct vop_reclaim_args /* {
 ***************
 *** 560,578 ****
   	} */ *ap;
   {
   	struct vnode *vp = ap->a_vp;
 - 	struct null_node *xp = VTONULL(vp);
 - 	struct vnode *lowervp = xp->null_lowervp;
   
 - 	/*
 - 	 * Note: in vop_reclaim, vp->v_op == dead_vnodeop_p,
 - 	 * so we can't call VOPs on ourself.
 - 	 */
 - 	/* After this assignment, this node will not be re-used. */
 - 	xp->null_lowervp = NULLVP;
 - 	LIST_REMOVE(xp, null_hash);
   	FREE(vp->v_data, M_TEMP);
   	vp->v_data = NULL;
 ! 	vrele (lowervp);
   	return (0);
   }
   
 --- 732,741 ----
   	} */ *ap;
   {
   	struct vnode *vp = ap->a_vp;
   
   	FREE(vp->v_data, M_TEMP);
   	vp->v_data = NULL;
 ! 
   	return (0);
   }
   
 ***************
 *** 593,607 ****
 --- 756,778 ----
   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_getpages_desc,		(vop_t *) null_getpages },
   	{ &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_putpages_desc,		(vop_t *) null_putpages },
   	{ &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 *) null_strategy },
   	{ &vop_unlock_desc,		(vop_t *) null_unlock },
 + 	{ &vop_write_desc,		(vop_t *) null_write },
   	{ NULL, NULL }
   };
   static struct vnodeopv_desc null_vnodeop_opv_desc =
 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200008160810.BAA92657>