diff options
author | Brian Behlendorf <[email protected]> | 2017-03-09 17:43:36 -0800 |
---|---|---|
committer | GitHub <[email protected]> | 2017-03-09 17:43:36 -0800 |
commit | ef1bdf363c021525c1db9630647dea73498c6bfd (patch) | |
tree | e8a0f6cb68803d158f31c94638747a18a102c102 /module | |
parent | 589bb918ef39058b1f06da72092e895835a7aaff (diff) |
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 <[email protected]>
Reviewed-by: George Melikov <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #5871
Closes #5879
Diffstat (limited to 'module')
-rw-r--r-- | module/zfs/zvol.c | 15 |
1 files 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)); } |