Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 01 Dec 2000 01:23:26 +0000
From:      Ian Dowse <iedowse@maths.tcd.ie>
To:        hackers@freebsd.org
Cc:        iedowse@maths.tcd.ie
Subject:   rootvnode
Message-ID:   <200012010123.aa58484@salmon.maths.tcd.ie>

next in thread | raw e-mail | index | archive | help

It appears that the pointer to the root vnode, 'rootvnode' does
not hold a corresponding vnode reference. Here's a fragment of code
from start_init():

	/* Get the vnode for '/'.  Set p->p_fd->fd_cdir to reference it. */
	if (VFS_ROOT(TAILQ_FIRST(&mountlist), &rootvnode))
	panic("cannot find root vnode");
	p->p_fd->fd_cdir = rootvnode;
	VREF(p->p_fd->fd_cdir);
	p->p_fd->fd_rdir = rootvnode;
	VOP_UNLOCK(rootvnode, 0, p);

Since rootvnode is a global variable, three pointers to the root
vnode are stored, but only two references are counted (one by
VFS_ROOT, one by VREF).

Normally this is not a problem, since proc0's fd_cdir and fd_rdir
keep their references until the system is rebooted. However the
code in vfs_syscalls.c's checkdirs() function assumes that rootvnode
does hold a reference on the vnode:

	if (rootvnode == olddp) {
		vrele(rootvnode);
		VREF(newdp);
		rootvnode = newdp;
	}

This bug reliably causes a panic on reboot if any filesystem has
been mounted directly over /. For example, try:

	mount_mfs -T fd1440 none /
	Ctrl-Alt-Delete

On -current the panic is 'vrele: missed vn_close'; on 4.1-STABLE it
is 'vrele: negative ref cnt'. It occurs in dounmount() at the lines

	if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
		coveredvp->v_mountedhere = (struct mount *)0;
		vrele(coveredvp);
	}

when unmounting the second / filesystem. This occurs because
checkdirs() has stolen a reference to /, so the reference count
goes negative when we attempt to remove the last reference.

This brings up another question: should the code reverse the changes
made by checkdirs() when a filesystem is unmounted? It certainly
seems to make sense to make rootvnode point to underlying vnode
when the filesystem containing the current rootvnode is unmounted;
I'm not sure how useful fixing up other fd_cdir/fd_rdir pointers
would be.

I can produce a simple patch which does the following:
 -  vref(rootvnode) in start_init().
 -  vrele(rootvnode) if non-NULL, maybe in vfs_unmountall()
 -  point rootvnode at underlying vnode when the filesystem
    containing rootvnode is unmounted.

Does this sound reasonable?

Ian


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




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