]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Invalidate Linux buffer cache on vdevs upon each flush
authorRichard Yao <ryao@gentoo.org>
Thu, 27 Feb 2014 19:03:39 +0000 (14:03 -0500)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 4 Mar 2014 20:22:03 +0000 (12:22 -0800)
Userland tools such as blkid, grub2-probe and zdb will go through the
buffer cache. However, ZFS uses on submit_bio() to bypass the buffer
cache when performing IO operations on vdevs for efficiency purposes.
This permits the on-disk state and buffer cache to fall out of
synchronization. That causes seemingly random failures when tools
reading stale metadata from the buffer cache try to access references to
data that is no longer there.

A particularly bad failure this causes involves grub2-probe, which is
used by grub2-mkconfig. Ordinarily, a rootfs might be called
rpool/ROOT/gentoo. However, when a failure occurs in grub2-probe,
grub2-mkconfig will generate a configuration file containing
/ROOT/gentoo, which omits the pool name and causes a boot failure.

This is avoidable by calling invalidate_bdev() on each flush, which is a
simple way to ensure that all non-dirty pages are wiped. Since userland
tools rarely access vdevs directly, this should be a fancy noop >99.999%
of the time and have little impact on IO. We could have tried a finer
grained approach for the rare instances in which the vdevs are accessed
frequently by userland. However, that would require consideration of
corner cases and it is not worth the effort.

Memory-wise, it would have been better to use a Linux kernel API hook to
disable the buffer cache on such devices, but it provides us no way of
doing that, so we opt for this approach instead. We should revisit that
idea in the future when higher priority issues have been tackled.

Signed-off-by: Richard Yao <ryao@gentoo.org>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2150

module/zfs/vdev_disk.c

index 1d8bf3f8cc518d24fc346f766596d40e96145e1c..5bd38e9832e2016005c425c360d5975c722905a6 100644 (file)
@@ -643,6 +643,7 @@ vdev_disk_io_flush(struct block_device *bdev, zio_t *zio)
        bio->bi_bdev = bdev;
        zio->io_delay = jiffies_64;
        submit_bio(VDEV_WRITE_FLUSH_FUA, bio);
+       invalidate_bdev(bdev);
 
        return (0);
 }