summaryrefslogtreecommitdiffstats
path: root/module/zfs
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs')
-rw-r--r--module/zfs/zvol.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c
index 9dda04077..0aaa268fa 100644
--- a/module/zfs/zvol.c
+++ b/module/zfs/zvol.c
@@ -534,6 +534,17 @@ zvol_write(void *arg)
dmu_tx_t *tx;
rl_t *rl;
+ if (req->cmd_flags & VDEV_REQ_FLUSH)
+ zil_commit(zv->zv_zilog, ZVOL_OBJ);
+
+ /*
+ * Some requests are just for flush and nothing else.
+ */
+ if (size == 0) {
+ blk_end_request(req, 0, size);
+ return;
+ }
+
rl = zfs_range_lock(&zv->zv_znode, offset, size, RL_WRITER);
tx = dmu_tx_create(zv->zv_objset);
@@ -550,12 +561,14 @@ zvol_write(void *arg)
error = dmu_write_req(zv->zv_objset, ZVOL_OBJ, req, tx);
if (error == 0)
- zvol_log_write(zv, tx, offset, size, rq_is_sync(req));
+ zvol_log_write(zv, tx, offset, size,
+ req->cmd_flags & VDEV_REQ_FUA);
dmu_tx_commit(tx);
zfs_range_unlock(rl);
- if (rq_is_sync(req) || zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS)
+ if ((req->cmd_flags & VDEV_REQ_FUA) ||
+ zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS)
zil_commit(zv->zv_zilog, ZVOL_OBJ);
blk_end_request(req, -error, size);
@@ -578,6 +591,11 @@ zvol_read(void *arg)
int error;
rl_t *rl;
+ if (size == 0) {
+ blk_end_request(req, 0, size);
+ return;
+ }
+
rl = zfs_range_lock(&zv->zv_znode, offset, size, RL_READER);
error = dmu_read_req(zv->zv_objset, ZVOL_OBJ, req);
@@ -627,7 +645,7 @@ zvol_request(struct request_queue *q)
while ((req = blk_fetch_request(q)) != NULL) {
size = blk_rq_bytes(req);
- if (blk_rq_pos(req) + blk_rq_sectors(req) >
+ if (size != 0 && blk_rq_pos(req) + blk_rq_sectors(req) >
get_capacity(zv->zv_disk)) {
printk(KERN_INFO
"%s: bad access: block=%llu, count=%lu\n",
@@ -1062,6 +1080,12 @@ zvol_alloc(dev_t dev, const char *name)
if (zv->zv_queue == NULL)
goto out_kmem;
+#ifdef HAVE_BLK_QUEUE_FLUSH
+ blk_queue_flush(zv->zv_queue, VDEV_REQ_FLUSH | VDEV_REQ_FUA);
+#else
+ blk_queue_ordered(zv->zv_queue, QUEUE_ORDERED_DRAIN, NULL);
+#endif /* HAVE_BLK_QUEUE_FLUSH */
+
zv->zv_disk = alloc_disk(ZVOL_MINORS);
if (zv->zv_disk == NULL)
goto out_queue;