Not sure if this is the place for nbd kernel code changes but we hit a
problem where we were never receiving commands with the fua flag set on our
nbd server (running on ubuntu 16.04 lts with 4.4.0-78 kernel)

After digging into the nbd kernel module code it turns out that the linux
kernel module is not handling the NBD_FLAG_SEND_FUA and was not setting
REQ_FUA on the request queue.

Here is a patch to enable FUA writes on the queue and then detect them in
the req->cmd_flags and set the appropriate bit in the request.type field
for the server.

This patch also includes a fix to the /sys/kernel/debug/nbd/*/flags file
that was being incorrectly called resulting in garbage to the debug file
instead of the flags that we came across while trying to decipher why we
weren't receiving the fua cmds.

I've never contributed code to the linux kernel before so if this isn't the
right place then if someone more knowledgeable on the linux kernel nbd
module maintainer could direct me to him/her I would appreciate it.
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index b05226d..3f59227 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -238,7 +238,7 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req)
 	int result, flags;
 	struct nbd_request request;
 	unsigned long size = blk_rq_bytes(req);
-	u32 type;
+	u32 type, nbd_cmd_flags = 0;
 
 	if (req->cmd_type == REQ_TYPE_DRV_PRIV)
 		type = NBD_CMD_DISC;
@@ -251,9 +251,12 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req)
 	else
 		type = NBD_CMD_READ;
 
+	if (req->cmd_flags & REQ_FUA)
+		nbd_cmd_flags |= NBD_CMD_FLAG_FUA;
+
 	memset(&request, 0, sizeof(request));
 	request.magic = htonl(NBD_REQUEST_MAGIC);
-	request.type = htonl(type);
+	request.type = htonl(type | nbd_cmd_flags);
 	if (type != NBD_CMD_FLUSH && type != NBD_CMD_DISC) {
 		request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9);
 		request.len = htonl(size);
@@ -736,6 +739,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
 		struct task_struct *thread;
 		struct socket *sock;
 		int error;
+		unsigned int flush = 0;
 
 		if (nbd->task_recv)
 			return -EBUSY;
@@ -750,9 +754,10 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
 			queue_flag_set_unlocked(QUEUE_FLAG_DISCARD,
 				nbd->disk->queue);
 		if (nbd->flags & NBD_FLAG_SEND_FLUSH)
-			blk_queue_flush(nbd->disk->queue, REQ_FLUSH);
-		else
-			blk_queue_flush(nbd->disk->queue, 0);
+			flush |= REQ_FLUSH;
+		if (nbd->flags & NBD_FLAG_SEND_FUA)
+			flush |= REQ_FUA;
+		blk_queue_flush(nbd->disk->queue, flush);
 
 		thread = kthread_run(nbd_thread_send, nbd, "%s",
 				     nbd_name(nbd));
@@ -870,6 +875,8 @@ static int nbd_dbg_flags_show(struct seq_file *s, void *unused)
 		seq_puts(s, "NBD_FLAG_READ_ONLY\n");
 	if (flags & NBD_FLAG_SEND_FLUSH)
 		seq_puts(s, "NBD_FLAG_SEND_FLUSH\n");
+	if (flags & NBD_FLAG_SEND_FUA)
+		seq_puts(s, "NBD_FLAG_SEND_FUA\n");
 	if (flags & NBD_FLAG_SEND_TRIM)
 		seq_puts(s, "NBD_FLAG_SEND_TRIM\n");
 
@@ -929,7 +936,7 @@ static int nbd_dev_dbg_init(struct nbd_device *nbd)
 		return PTR_ERR(f);
 	}
 
-	f = debugfs_create_file("flags", 0444, dir, &nbd, &nbd_dbg_flags_ops);
+	f = debugfs_create_file("flags", 0444, dir, nbd, &nbd_dbg_flags_ops);
 	if (IS_ERR_OR_NULL(f)) {
 		dev_err(nbd_to_dev(nbd), "Failed to create debugfs file 'flags', %ld\n",
 			PTR_ERR(f));
diff --git a/include/uapi/linux/nbd.h b/include/uapi/linux/nbd.h
index e08e413..47c8fb3 100644
--- a/include/uapi/linux/nbd.h
+++ b/include/uapi/linux/nbd.h
@@ -37,10 +37,13 @@ enum {
 	NBD_CMD_TRIM = 4
 };
 
+#define NBD_CMD_FLAG_FUA      (1 << 16) /* forced unit access */
+
 /* values for flags field */
 #define NBD_FLAG_HAS_FLAGS    (1 << 0) /* nbd-server supports flags */
 #define NBD_FLAG_READ_ONLY    (1 << 1) /* device is read-only */
 #define NBD_FLAG_SEND_FLUSH   (1 << 2) /* can flush writeback cache */
+#define NBD_FLAG_SEND_FUA     (1 << 3) /* Send FUA (Force Unit Access) */
 /* there is a gap here to match userspace */
 #define NBD_FLAG_SEND_TRIM    (1 << 5) /* send trim/discard */
 
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Nbd-general mailing list
Nbd-general@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nbd-general

Reply via email to