]> Git Repo - qemu.git/blob - block/nbd.c
Merge branch 'pci' into for_anthony
[qemu.git] / block / nbd.c
1 /*
2  * QEMU Block driver for  NBD
3  *
4  * Copyright (C) 2008 Bull S.A.S.
5  *     Author: Laurent Vivier <[email protected]>
6  *
7  * Some parts:
8  *    Copyright (C) 2007 Anthony Liguori <[email protected]>
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 #define EN_OPTSTR ":exportname="
37
38 typedef struct BDRVNBDState {
39     int sock;
40     off_t size;
41     size_t blocksize;
42 } BDRVNBDState;
43
44 static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
45 {
46     BDRVNBDState *s = bs->opaque;
47     uint32_t nbdflags;
48
49     char *file;
50     char *name;
51     const char *host;
52     const char *unixpath;
53     int sock;
54     off_t size;
55     size_t blocksize;
56     int ret;
57     int err = -EINVAL;
58
59     file = qemu_strdup(filename);
60
61     name = strstr(file, EN_OPTSTR);
62     if (name) {
63         if (name[strlen(EN_OPTSTR)] == 0) {
64             goto out;
65         }
66         name[0] = 0;
67         name += strlen(EN_OPTSTR);
68     }
69
70     if (!strstart(file, "nbd:", &host)) {
71         goto out;
72     }
73
74     if (strstart(host, "unix:", &unixpath)) {
75
76         if (unixpath[0] != '/') {
77             goto out;
78         }
79
80         sock = unix_socket_outgoing(unixpath);
81
82     } else {
83         uint16_t port = NBD_DEFAULT_PORT;
84         char *p, *r;
85         char hostname[128];
86
87         pstrcpy(hostname, 128, host);
88
89         p = strchr(hostname, ':');
90         if (p != NULL) {
91             *p = '\0';
92             p++;
93
94             port = strtol(p, &r, 0);
95             if (r == p) {
96                 goto out;
97             }
98         }
99
100         sock = tcp_socket_outgoing(hostname, port);
101     }
102
103     if (sock == -1) {
104         err = -errno;
105         goto out;
106     }
107
108     ret = nbd_receive_negotiate(sock, name, &nbdflags, &size, &blocksize);
109     if (ret == -1) {
110         err = -errno;
111         goto out;
112     }
113
114     s->sock = sock;
115     s->size = size;
116     s->blocksize = blocksize;
117     err = 0;
118
119 out:
120     qemu_free(file);
121     return err;
122 }
123
124 static int nbd_read(BlockDriverState *bs, int64_t sector_num,
125                     uint8_t *buf, int nb_sectors)
126 {
127     BDRVNBDState *s = bs->opaque;
128     struct nbd_request request;
129     struct nbd_reply reply;
130
131     request.type = NBD_CMD_READ;
132     request.handle = (uint64_t)(intptr_t)bs;
133     request.from = sector_num * 512;;
134     request.len = nb_sectors * 512;
135
136     if (nbd_send_request(s->sock, &request) == -1)
137         return -errno;
138
139     if (nbd_receive_reply(s->sock, &reply) == -1)
140         return -errno;
141
142     if (reply.error !=0)
143         return -reply.error;
144
145     if (reply.handle != request.handle)
146         return -EIO;
147
148     if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len)
149         return -EIO;
150
151     return 0;
152 }
153
154 static int nbd_write(BlockDriverState *bs, int64_t sector_num,
155                      const uint8_t *buf, int nb_sectors)
156 {
157     BDRVNBDState *s = bs->opaque;
158     struct nbd_request request;
159     struct nbd_reply reply;
160
161     request.type = NBD_CMD_WRITE;
162     request.handle = (uint64_t)(intptr_t)bs;
163     request.from = sector_num * 512;;
164     request.len = nb_sectors * 512;
165
166     if (nbd_send_request(s->sock, &request) == -1)
167         return -errno;
168
169     if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len)
170         return -EIO;
171
172     if (nbd_receive_reply(s->sock, &reply) == -1)
173         return -errno;
174
175     if (reply.error !=0)
176         return -reply.error;
177
178     if (reply.handle != request.handle)
179         return -EIO;
180
181     return 0;
182 }
183
184 static void nbd_close(BlockDriverState *bs)
185 {
186     BDRVNBDState *s = bs->opaque;
187     struct nbd_request request;
188
189     request.type = NBD_CMD_DISC;
190     request.handle = (uint64_t)(intptr_t)bs;
191     request.from = 0;
192     request.len = 0;
193     nbd_send_request(s->sock, &request);
194
195     close(s->sock);
196 }
197
198 static int64_t nbd_getlength(BlockDriverState *bs)
199 {
200     BDRVNBDState *s = bs->opaque;
201
202     return s->size;
203 }
204
205 static BlockDriver bdrv_nbd = {
206     .format_name        = "nbd",
207     .instance_size      = sizeof(BDRVNBDState),
208     .bdrv_file_open     = nbd_open,
209     .bdrv_read          = nbd_read,
210     .bdrv_write         = nbd_write,
211     .bdrv_close         = nbd_close,
212     .bdrv_getlength     = nbd_getlength,
213     .protocol_name      = "nbd",
214 };
215
216 static void bdrv_nbd_init(void)
217 {
218     bdrv_register(&bdrv_nbd);
219 }
220
221 block_init(bdrv_nbd_init);
This page took 0.037494 seconds and 4 git commands to generate.