diff options
author | mckusick <mckusick@FreeBSD.org> | 2000-07-24 05:28:33 +0000 |
---|---|---|
committer | mckusick <mckusick@FreeBSD.org> | 2000-07-24 05:28:33 +0000 |
commit | acc66855bf5786e46e7a1f2c9805ca96cc90c681 (patch) | |
tree | 293bc9453d98bf984dd4fb4392b47ad92614d53f /sys/kern/vfs_subr.c | |
parent | 35aeef29b58a4f4acf20b4a13f1326e85affab9e (diff) | |
download | FreeBSD-src-acc66855bf5786e46e7a1f2c9805ca96cc90c681.zip FreeBSD-src-acc66855bf5786e46e7a1f2c9805ca96cc90c681.tar.gz |
This patch corrects the first round of panics and hangs reported
with the new snapshot code.
Update addaliasu to correctly implement the semantics of the old
checkalias function. When a device vnode first comes into existence,
check to see if an anonymous vnode for the same device was created
at boot time by bdevvp(). If so, adopt the bdevvp vnode rather than
creating a new vnode for the device. This corrects a problem which
caused the kernel to panic when taking a snapshot of the root
filesystem.
Change the calling convention of vn_write_suspend_wait() to be the
same as vn_start_write().
Split out softdep_flushworklist() from softdep_flushfiles() so that
it can be used to clear the work queue when suspending filesystem
operations.
Access to buffers becomes recursive so that snapshots can recursively
traverse their indirect blocks using ffs_copyonwrite() when checking
for the need for copy on write when flushing one of their own indirect
blocks. This eliminates a deadlock between the syncer daemon and a
process taking a snapshot.
Ensure that softdep_process_worklist() can never block because of a
snapshot being taken. This eliminates a problem with buffer starvation.
Cleanup change in ffs_sync() which did not synchronously wait when
MNT_WAIT was specified. The result was an unclean filesystem panic
when doing forcible unmount with heavy filesystem I/O in progress.
Return a zero'ed block when reading a block that was not in use at
the time that a snapshot was taken. Normally, these blocks should
never be read. However, the readahead code will occationally read
them which can cause unexpected behavior.
Clean up the debugging code that ensures that no blocks be written
on a filesystem while it is suspended. Snapshots must explicitly
label the blocks that they are writing during the suspension so that
they do not cause a `write on suspended filesystem' panic.
Reorganize ffs_copyonwrite() to eliminate a deadlock and also to
prevent a race condition that would permit the same block to be
copied twice. This change eliminates an unexpected soft updates
inconsistency in fsck caused by the double allocation.
Use bqrelse rather than brelse for buffers that will be needed
soon again by the snapshot code. This improves snapshot performance.
Diffstat (limited to 'sys/kern/vfs_subr.c')
-rw-r--r-- | sys/kern/vfs_subr.c | 36 |
1 files changed, 33 insertions, 3 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 0e5ec3f..db16d9f 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1296,15 +1296,45 @@ bdevvp(dev, vpp) * how many users there are is inadequate; the v_usecount for * the vnodes need to be accumulated. vcount() does that. */ -void +struct vnode * addaliasu(nvp, nvp_rdev) struct vnode *nvp; udev_t nvp_rdev; { + struct vnode *ovp; + vop_t **ops; + dev_t dev; if (nvp->v_type != VBLK && nvp->v_type != VCHR) panic("addaliasu on non-special vnode"); - addalias(nvp, udev2dev(nvp_rdev, nvp->v_type == VBLK ? 1 : 0)); + dev = udev2dev(nvp_rdev, nvp->v_type == VBLK ? 1 : 0); + /* + * Check to see if we have a bdevvp vnode with no associated + * filesystem. If so, we want to associate the filesystem of + * the new newly instigated vnode with the bdevvp vnode and + * discard the newly created vnode rather than leaving the + * bdevvp vnode lying around with no associated filesystem. + */ + if (vfinddev(dev, nvp->v_type, &ovp) == 0 || ovp->v_data != NULL) { + addalias(nvp, dev); + return (nvp); + } + /* + * Discard unneeded vnode, but save its node specific data. + * Note that if there is a lock, it is carried over in the + * node specific data to the replacement vnode. + */ + vref(ovp); + ovp->v_data = nvp->v_data; + ovp->v_tag = nvp->v_tag; + nvp->v_data = NULL; + ops = nvp->v_op; + nvp->v_op = ovp->v_op; + ovp->v_op = ops; + insmntque(ovp, nvp->v_mount); + vrele(nvp); + vgone(nvp); + return (ovp); } void @@ -1648,7 +1678,7 @@ vclean(vp, flags, p) */ if (flags & DOCLOSE) { if (TAILQ_FIRST(&vp->v_dirtyblkhd) != NULL) - (void) vn_write_suspend_wait(vp, V_WAIT); + (void) vn_write_suspend_wait(vp, NULL, V_WAIT); if (vinvalbuf(vp, V_SAVE, NOCRED, p, 0, 0) != 0) vinvalbuf(vp, 0, NOCRED, p, 0, 0); } |