[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[Nbd] [CFT][PATCH 2/4] nbd: support FLUSH/FUA



From: Alex Bligh <alex@...872...>

Cc: Paul Clements <Paul.Clements@...124...>
Cc: <nbd-general@...72...>
Signed-off-by: Alex Bligh <alex@...872...>
Signed-off-by: Paolo Bonzini <pbonzini@...696...>
---
	After splitting the ROTATIONAL part into a separate patch, this
	is all that is left in http://git.alex.org.uk/nbd-module.git.

 drivers/block/nbd.c |   46 +++++++++++++++++++++++++++++++++++++++++-----
 include/linux/nbd.h |    8 +++++++-
 2 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 616c982..bece3cc 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -100,9 +100,10 @@ static const char *ioctl_cmd_to_ascii(int cmd)
 static const char *nbdcmd_to_ascii(int cmd)
 {
 	switch (cmd) {
-	case  NBD_CMD_READ: return "read";
+	case NBD_CMD_READ: return "read";
 	case NBD_CMD_WRITE: return "write";
-	case  NBD_CMD_DISC: return "disconnect";
+	case NBD_CMD_DISC: return "disconnect";
+	case NBD_CMD_FLUSH: return "flush";
 	}
 	return "invalid";
 }
@@ -242,9 +243,18 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
 	unsigned long size = blk_rq_bytes(req);
 
 	request.magic = htonl(NBD_REQUEST_MAGIC);
-	request.type = htonl(nbd_cmd(req));
-	request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9);
-	request.len = htonl(size);
+	/* If FUA is set in the request, and we are told to send FUA, then OR in NBD_CMD_FLAG_FUA */
+	request.type = htonl(nbd_cmd(req) |
+			     (( (req->cmd_flags & REQ_FUA) && (lo->flags & NBD_FLAG_SEND_FUA)) ?
+			      NBD_CMD_FLAG_FUA : 0));
+	/* Send from & len as zero on FLUSH - other values reserved per protocol */
+	if (nbd_cmd(req) == NBD_CMD_FLUSH) {
+		request.from = 0;
+		request.len = 0;
+	} else {
+		request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9);
+		request.len = htonl(size);
+	}
 	memcpy(request.handle, &req, sizeof(req));
 
 	dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%uB)\n",
@@ -468,6 +478,27 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req)
 		}
 	}
 
+	if (req->cmd_flags & REQ_FLUSH) {
+		if (unlikely(blk_rq_sectors(req))) {
+			/* Elevator is meant to guarantee that a request with REQ_FLUSH
+			 * set is broken into an empty request with REQ_FLUSH set then
+			 * the rest of the content (if any). If this doesn't happen,
+			 * whinge, then proceed to do the content without a flush.
+			 */
+			printk(KERN_ERR "%s: nbd passed non-empty flush request\n",
+			       lo->disk->disk_name);
+
+		} else {
+			if (lo->flags & NBD_FLAG_SEND_FLUSH)
+				nbd_cmd(req) = NBD_CMD_FLUSH;
+			else {
+				/* Ignore flush that we don't need */
+				nbd_end_request(req);
+				return;
+			}
+		}
+	}
+
 	req->errors = 0;
 
 	mutex_lock(&lo->tx_lock);
@@ -784,6 +815,11 @@ static int __init nbd_init(void)
 			put_disk(disk);
 			goto out;
 		}
+		/* In order not to confuse the elevator, say we always
+		 * want FLUSH and FUA. We won't send them to the server
+		 * unless the relevant flag bit is set
+		 */
+		blk_queue_flush(disk->queue, REQ_FLUSH | REQ_FUA);
 		/*
 		 * Tell the block layer that we are not a rotational device
 		 */
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
index 3e5a05e..d8cd251 100644
--- a/include/linux/nbd.h
+++ b/include/linux/nbd.h
@@ -32,12 +32,18 @@
 enum {
 	NBD_CMD_READ = 0,
 	NBD_CMD_WRITE = 1,
-	NBD_CMD_DISC = 2
+	NBD_CMD_DISC = 2,
+	NBD_CMD_FLUSH = 3
 };
 
+#define NBD_CMD_MASK_COMMAND 0x0000ffff
+#define NBD_CMD_FLAG_FUA (1<<16)
+
 /* values for flags field */
 #define NBD_FLAG_HAS_FLAGS	(1 << 0)	/* Flags are there */
 #define NBD_FLAG_READ_ONLY	(1 << 1)	/* Device is read only */
+#define NBD_FLAG_SEND_FLUSH	(1 << 2)	/* Send FLUSH */
+#define NBD_FLAG_SEND_FUA	(1 << 3)	/* Send FUA (Force Unit Access) */
 
 #define nbd_cmd(req) ((req)->cmd[0])
 
-- 
1.7.6





Reply to: