1 /* 2 * QEMU Block driver for NBD 3 * 4 * Copyright (C) 2008 Bull S.A.S. 5 * Author: Laurent Vivier <Laurent.Vivier (at) bull.net> 6 * 7 * Some parts: 8 * Copyright (C) 2007 Anthony Liguori <anthony (at) codemonkey.ws> 9 * 10 * Permission is hereby granted, free of charge, to any person obtaining a copy 11 * of this software and associated documentation files (the "Software"), to deal 12 * in the Software without restriction, including without limitation the rights 13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 * copies of the Software, and to permit persons to whom the Software is 15 * furnished to do so, subject to the following conditions: 16 * 17 * The above copyright notice and this permission notice shall be included in 18 * all copies or substantial portions of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 * THE SOFTWARE. 27 */ 28 29 #include "qemu-common.h" 30 #include "nbd.h" 31 #include "module.h" 32 33 #include <sys/types.h> 34 #include <unistd.h> 35 36 typedef struct BDRVNBDState { 37 int sock; 38 off_t size; 39 size_t blocksize; 40 } BDRVNBDState; 41 42 static int nbd_open(BlockDriverState *bs, const char* filename, int flags) 43 { 44 BDRVNBDState *s = bs->opaque; 45 const char *host; 46 const char *unixpath; 47 int sock; 48 off_t size; 49 size_t blocksize; 50 int ret; 51 52 if (!strstart(filename, "nbd:", &host)) 53 return -EINVAL; 54 55 if (strstart(host, "unix:", &unixpath)) { 56 57 if (unixpath[0] != '/') 58 return -EINVAL; 59 60 sock = unix_socket_outgoing(unixpath); 61 62 } else { 63 uint16_t port; 64 char *p, *r; 65 char hostname[128]; 66 67 pstrcpy(hostname, 128, host); 68 69 p = strchr(hostname, ':'); 70 if (p == NULL) 71 return -EINVAL; 72 73 *p = '\0'; 74 p++; 75 76 port = strtol(p, &r, 0); 77 if (r == p) 78 return -EINVAL; 79 sock = tcp_socket_outgoing(hostname, port); 80 } 81 82 if (sock == -1) 83 return -errno; 84 85 ret = nbd_receive_negotiate(sock, &size, &blocksize); 86 if (ret == -1) 87 return -errno; 88 89 s->sock = sock; 90 s->size = size; 91 s->blocksize = blocksize; 92 93 return 0; 94 } 95 96 static int nbd_read(BlockDriverState *bs, int64_t sector_num, 97 uint8_t *buf, int nb_sectors) 98 { 99 BDRVNBDState *s = bs->opaque; 100 struct nbd_request request; 101 struct nbd_reply reply; 102 103 request.type = NBD_CMD_READ; 104 request.handle = (uint64_t)(intptr_t)bs; 105 request.from = sector_num * 512;; 106 request.len = nb_sectors * 512; 107 108 if (nbd_send_request(s->sock, &request) == -1) 109 return -errno; 110 111 if (nbd_receive_reply(s->sock, &reply) == -1) 112 return -errno; 113 114 if (reply.error !=0) 115 return -reply.error; 116 117 if (reply.handle != request.handle) 118 return -EIO; 119 120 if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len) 121 return -EIO; 122 123 return 0; 124 } 125 126 static int nbd_write(BlockDriverState *bs, int64_t sector_num, 127 const uint8_t *buf, int nb_sectors) 128 { 129 BDRVNBDState *s = bs->opaque; 130 struct nbd_request request; 131 struct nbd_reply reply; 132 133 request.type = NBD_CMD_WRITE; 134 request.handle = (uint64_t)(intptr_t)bs; 135 request.from = sector_num * 512;; 136 request.len = nb_sectors * 512; 137 138 if (nbd_send_request(s->sock, &request) == -1) 139 return -errno; 140 141 if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len) 142 return -EIO; 143 144 if (nbd_receive_reply(s->sock, &reply) == -1) 145 return -errno; 146 147 if (reply.error !=0) 148 return -reply.error; 149 150 if (reply.handle != request.handle) 151 return -EIO; 152 153 return 0; 154 } 155 156 static void nbd_close(BlockDriverState *bs) 157 { 158 BDRVNBDState *s = bs->opaque; 159 struct nbd_request request; 160 161 request.type = NBD_CMD_DISC; 162 request.handle = (uint64_t)(intptr_t)bs; 163 request.from = 0; 164 request.len = 0; 165 nbd_send_request(s->sock, &request); 166 167 close(s->sock); 168 } 169 170 static int64_t nbd_getlength(BlockDriverState *bs) 171 { 172 BDRVNBDState *s = bs->opaque; 173 174 return s->size; 175 } 176 177 static BlockDriver bdrv_nbd = { 178 .format_name = "nbd", 179 .instance_size = sizeof(BDRVNBDState), 180 .bdrv_file_open = nbd_open, 181 .bdrv_read = nbd_read, 182 .bdrv_write = nbd_write, 183 .bdrv_close = nbd_close, 184 .bdrv_getlength = nbd_getlength, 185 .protocol_name = "nbd", 186 }; 187 188 static void bdrv_nbd_init(void) 189 { 190 bdrv_register(&bdrv_nbd); 191 } 192 193 block_init(bdrv_nbd_init); 194