|
1 /* |
|
2 * QEMU Block driver for NBD |
|
3 * |
|
4 * Copyright (C) 2008 Bull S.A.S. |
|
5 * Author: Laurent Vivier <Laurent.Vivier@bull.net> |
|
6 * |
|
7 * Some parts: |
|
8 * Copyright (C) 2007 Anthony Liguori <anthony@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 |
|
32 #include <sys/types.h> |
|
33 #include <unistd.h> |
|
34 |
|
35 typedef struct BDRVNBDState { |
|
36 int sock; |
|
37 off_t size; |
|
38 size_t blocksize; |
|
39 } BDRVNBDState; |
|
40 |
|
41 static int nbd_open(BlockDriverState *bs, const char* filename, int flags) |
|
42 { |
|
43 BDRVNBDState *s = bs->opaque; |
|
44 const char *host; |
|
45 const char *unixpath; |
|
46 int sock; |
|
47 off_t size; |
|
48 size_t blocksize; |
|
49 int ret; |
|
50 |
|
51 if ((flags & BDRV_O_CREAT)) |
|
52 return -EINVAL; |
|
53 |
|
54 if (!strstart(filename, "nbd:", &host)) |
|
55 return -EINVAL; |
|
56 |
|
57 if (strstart(host, "unix:", &unixpath)) { |
|
58 |
|
59 if (unixpath[0] != '/') |
|
60 return -EINVAL; |
|
61 |
|
62 sock = unix_socket_outgoing(unixpath); |
|
63 |
|
64 } else { |
|
65 uint16_t port; |
|
66 char *p, *r; |
|
67 char hostname[128]; |
|
68 |
|
69 pstrcpy(hostname, 128, host); |
|
70 |
|
71 p = strchr(hostname, ':'); |
|
72 if (p == NULL) |
|
73 return -EINVAL; |
|
74 |
|
75 *p = '\0'; |
|
76 p++; |
|
77 |
|
78 port = strtol(p, &r, 0); |
|
79 if (r == p) |
|
80 return -EINVAL; |
|
81 sock = tcp_socket_outgoing(hostname, port); |
|
82 } |
|
83 |
|
84 if (sock == -1) |
|
85 return -errno; |
|
86 |
|
87 ret = nbd_receive_negotiate(sock, &size, &blocksize); |
|
88 if (ret == -1) |
|
89 return -errno; |
|
90 |
|
91 s->sock = sock; |
|
92 s->size = size; |
|
93 s->blocksize = blocksize; |
|
94 |
|
95 return 0; |
|
96 } |
|
97 |
|
98 static int nbd_read(BlockDriverState *bs, int64_t sector_num, |
|
99 uint8_t *buf, int nb_sectors) |
|
100 { |
|
101 BDRVNBDState *s = bs->opaque; |
|
102 struct nbd_request request; |
|
103 struct nbd_reply reply; |
|
104 |
|
105 request.type = NBD_CMD_READ; |
|
106 request.handle = (uint64_t)(intptr_t)bs; |
|
107 request.from = sector_num * 512;; |
|
108 request.len = nb_sectors * 512; |
|
109 |
|
110 if (nbd_send_request(s->sock, &request) == -1) |
|
111 return -errno; |
|
112 |
|
113 if (nbd_receive_reply(s->sock, &reply) == -1) |
|
114 return -errno; |
|
115 |
|
116 if (reply.error !=0) |
|
117 return -reply.error; |
|
118 |
|
119 if (reply.handle != request.handle) |
|
120 return -EIO; |
|
121 |
|
122 if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len) |
|
123 return -EIO; |
|
124 |
|
125 return 0; |
|
126 } |
|
127 |
|
128 static int nbd_write(BlockDriverState *bs, int64_t sector_num, |
|
129 const uint8_t *buf, int nb_sectors) |
|
130 { |
|
131 BDRVNBDState *s = bs->opaque; |
|
132 struct nbd_request request; |
|
133 struct nbd_reply reply; |
|
134 |
|
135 request.type = NBD_CMD_WRITE; |
|
136 request.handle = (uint64_t)(intptr_t)bs; |
|
137 request.from = sector_num * 512;; |
|
138 request.len = nb_sectors * 512; |
|
139 |
|
140 if (nbd_send_request(s->sock, &request) == -1) |
|
141 return -errno; |
|
142 |
|
143 if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len) |
|
144 return -EIO; |
|
145 |
|
146 if (nbd_receive_reply(s->sock, &reply) == -1) |
|
147 return -errno; |
|
148 |
|
149 if (reply.error !=0) |
|
150 return -reply.error; |
|
151 |
|
152 if (reply.handle != request.handle) |
|
153 return -EIO; |
|
154 |
|
155 return 0; |
|
156 } |
|
157 |
|
158 static void nbd_close(BlockDriverState *bs) |
|
159 { |
|
160 BDRVNBDState *s = bs->opaque; |
|
161 struct nbd_request request; |
|
162 |
|
163 request.type = NBD_CMD_DISC; |
|
164 request.handle = (uint64_t)(intptr_t)bs; |
|
165 request.from = 0; |
|
166 request.len = 0; |
|
167 nbd_send_request(s->sock, &request); |
|
168 |
|
169 close(s->sock); |
|
170 } |
|
171 |
|
172 static int64_t nbd_getlength(BlockDriverState *bs) |
|
173 { |
|
174 BDRVNBDState *s = bs->opaque; |
|
175 |
|
176 return s->size; |
|
177 } |
|
178 |
|
179 BlockDriver bdrv_nbd = { |
|
180 "nbd", |
|
181 sizeof(BDRVNBDState), |
|
182 NULL, /* no probe for protocols */ |
|
183 nbd_open, |
|
184 nbd_read, |
|
185 nbd_write, |
|
186 nbd_close, |
|
187 .bdrv_getlength = nbd_getlength, |
|
188 .protocol_name = "nbd", |
|
189 }; |