From d1ef4e44e2cfbae2159ad4932f3545f1661577ef Mon Sep 17 00:00:00 2001 From: Alex Bligh Date: Wed, 18 May 2011 08:46:35 +0100 Subject: [PATCH] First patch to support FUA, FLUSH and ROTATIONAL --- nbd.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- nbd.h | 18 +++++++++++++----- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/nbd.c b/nbd.c index 0eeed20..274e2f7 100644 --- a/nbd.c +++ b/nbd.c @@ -89,6 +89,8 @@ static const char *ioctl_cmd_to_ascii(int cmd) case NBD_PRINT_DEBUG: return "print-debug"; case NBD_SET_SIZE_BLOCKS: return "set-size-blocks"; case NBD_DISCONNECT: return "disconnect"; + case NBD_SET_TIMEOUT: return "set-timeout"; + case NBD_SET_FLAGS: return "set-flags"; case BLKROSET: return "set-read-only"; case BLKFLSBUF: return "flush-buffer-cache"; } @@ -98,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"; } @@ -240,7 +243,10 @@ 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)); + /* 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)); request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9); request.len = htonl(size); memcpy(request.handle, &req, sizeof(req)); @@ -459,13 +465,34 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req) nbd_cmd(req) = NBD_CMD_READ; if (rq_data_dir(req) == WRITE) { nbd_cmd(req) = NBD_CMD_WRITE; - if (lo->flags & NBD_READ_ONLY) { + if (lo->flags & NBD_FLAG_READ_ONLY) { printk(KERN_ERR "%s: Write on read-only\n", lo->disk->disk_name); goto error_out; } } + 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); @@ -642,6 +669,18 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, lo->xmit_timeout = arg * HZ; return 0; + case NBD_SET_FLAGS: + lo->flags = arg; + if (lo->disk) + { + if (lo->flags & NBD_FLAG_ROTATIONAL) + queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, lo->disk->queue); + else + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, lo->disk->queue); + + } + return 0; + case NBD_SET_SIZE_BLOCKS: lo->bytesize = ((u64) arg) * lo->blksize; bdev->bd_inode->i_size = lo->bytesize; @@ -775,6 +814,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/nbd.h b/nbd.h index d146ca1..5cf18a0 100644 --- a/nbd.h +++ b/nbd.h @@ -27,13 +27,25 @@ #define NBD_SET_SIZE_BLOCKS _IO( 0xab, 7 ) #define NBD_DISCONNECT _IO( 0xab, 8 ) #define NBD_SET_TIMEOUT _IO( 0xab, 9 ) +#define NBD_SET_FLAGS _IO( 0xab, 10 ) 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_FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */ + #define nbd_cmd(req) ((req)->cmd[0]) /* userspace doesn't need the nbd_device structure */ @@ -42,10 +54,6 @@ enum { #include #include -/* values for flags field */ -#define NBD_READ_ONLY 0x0001 -#define NBD_WRITE_NOCHK 0x0002 - struct request; struct nbd_device { -- 1.7.10.4