From ef1bdf363c021525c1db9630647dea73498c6bfd Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Thu, 9 Mar 2017 17:43:36 -0800 Subject: Fix ZVOL BLKFLSBUF ioctl The BLKFLSBUF ioctl is expected to do two things: - flush dirty pages to stable storage, and - invalidate clean pages Unfortunately, the existing implementation of BLKFLSBUF in zvol_ioctl() only flushes pages which are part of the current TXG to disk. There may be additional dirty pages in the page cache which haven't yet been submitted to the DMU and therefore aren't part of any TXG. Furthermore because zvol_ioctl() returns 0 the generic blkdev_flushbuf() does not invalidate the page cache. Resolve the issue by moving bdev_flush() in to zvol_ioctl() and explicitly waiting for a full TXG sync. Then invalidate the page cache. The associated ARC buffers need not be evicted since they cannot be bypassed using O_DIRECT. Reviewed-by: Chunwei Chen Reviewed-by: George Melikov Signed-off-by: Brian Behlendorf Closes #5871 Closes #5879 --- module/zfs/zvol.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index abe77ecd4..420282c4a 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -1215,20 +1215,29 @@ zvol_ioctl(struct block_device *bdev, fmode_t mode, ASSERT(zv && zv->zv_open_count > 0); - rw_enter(&zv->zv_suspend_lock, RW_READER); switch (cmd) { case BLKFLSBUF: - zil_commit(zv->zv_zilog, ZVOL_OBJ); + fsync_bdev(bdev); + invalidate_bdev(bdev); + rw_enter(&zv->zv_suspend_lock, RW_READER); + + if (dsl_dataset_is_dirty(dmu_objset_ds(zv->zv_objset)) && + !(zv->zv_flags & ZVOL_RDONLY)) + txg_wait_synced(dmu_objset_pool(zv->zv_objset), 0); + + rw_exit(&zv->zv_suspend_lock); break; + case BLKZNAME: + mutex_enter(&zvol_state_lock); error = copy_to_user((void *)arg, zv->zv_name, MAXNAMELEN); + mutex_exit(&zvol_state_lock); break; default: error = -ENOTTY; break; } - rw_exit(&zv->zv_suspend_lock); return (SET_ERROR(error)); } -- cgit v1.2.3