xref: /qemu/nbd/common.c (revision 72c58ff8958f6e00ce361d1d568dc21e41c85f45)
1 /*
2  *  Copyright (C) 2005  Anthony Liguori <anthony@codemonkey.ws>
3  *
4  *  Network Block Device Common Code
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; under version 2 of the License.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "qemu/osdep.h"
20 #include "trace.h"
21 #include "io/channel-socket.h"
22 #include "qapi/error.h"
23 #include "qemu/units.h"
24 #include "nbd-internal.h"
25 
26 /* Discard length bytes from channel.  Return -errno on failure and 0 on
27  * success */
nbd_drop(QIOChannel * ioc,size_t size,Error ** errp)28 int nbd_drop(QIOChannel *ioc, size_t size, Error **errp)
29 {
30     ssize_t ret = 0;
31     char small[1024];
32     char *buffer;
33 
34     buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size));
35     while (size > 0) {
36         ssize_t count = MIN(65536, size);
37         ret = nbd_read(ioc, buffer, MIN(65536, size), NULL, errp);
38 
39         if (ret < 0) {
40             goto cleanup;
41         }
42         size -= count;
43     }
44 
45  cleanup:
46     if (buffer != small) {
47         g_free(buffer);
48     }
49     return ret;
50 }
51 
52 
nbd_opt_lookup(uint32_t opt)53 const char *nbd_opt_lookup(uint32_t opt)
54 {
55     switch (opt) {
56     case NBD_OPT_EXPORT_NAME:
57         return "export name";
58     case NBD_OPT_ABORT:
59         return "abort";
60     case NBD_OPT_LIST:
61         return "list";
62     case NBD_OPT_STARTTLS:
63         return "starttls";
64     case NBD_OPT_INFO:
65         return "info";
66     case NBD_OPT_GO:
67         return "go";
68     case NBD_OPT_STRUCTURED_REPLY:
69         return "structured reply";
70     case NBD_OPT_LIST_META_CONTEXT:
71         return "list meta context";
72     case NBD_OPT_SET_META_CONTEXT:
73         return "set meta context";
74     case NBD_OPT_EXTENDED_HEADERS:
75         return "extended headers";
76     default:
77         return "<unknown>";
78     }
79 }
80 
81 
nbd_rep_lookup(uint32_t rep)82 const char *nbd_rep_lookup(uint32_t rep)
83 {
84     switch (rep) {
85     case NBD_REP_ACK:
86         return "ack";
87     case NBD_REP_SERVER:
88         return "server";
89     case NBD_REP_INFO:
90         return "info";
91     case NBD_REP_META_CONTEXT:
92         return "meta context";
93     case NBD_REP_ERR_UNSUP:
94         return "unsupported";
95     case NBD_REP_ERR_POLICY:
96         return "denied by policy";
97     case NBD_REP_ERR_INVALID:
98         return "invalid";
99     case NBD_REP_ERR_PLATFORM:
100         return "platform lacks support";
101     case NBD_REP_ERR_TLS_REQD:
102         return "TLS required";
103     case NBD_REP_ERR_UNKNOWN:
104         return "export unknown";
105     case NBD_REP_ERR_SHUTDOWN:
106         return "server shutting down";
107     case NBD_REP_ERR_BLOCK_SIZE_REQD:
108         return "block size required";
109     case NBD_REP_ERR_TOO_BIG:
110         return "option payload too big";
111     case NBD_REP_ERR_EXT_HEADER_REQD:
112         return "extended headers required";
113     default:
114         return "<unknown>";
115     }
116 }
117 
118 
nbd_info_lookup(uint16_t info)119 const char *nbd_info_lookup(uint16_t info)
120 {
121     switch (info) {
122     case NBD_INFO_EXPORT:
123         return "export";
124     case NBD_INFO_NAME:
125         return "name";
126     case NBD_INFO_DESCRIPTION:
127         return "description";
128     case NBD_INFO_BLOCK_SIZE:
129         return "block size";
130     default:
131         return "<unknown>";
132     }
133 }
134 
135 
nbd_cmd_lookup(uint16_t cmd)136 const char *nbd_cmd_lookup(uint16_t cmd)
137 {
138     switch (cmd) {
139     case NBD_CMD_READ:
140         return "read";
141     case NBD_CMD_WRITE:
142         return "write";
143     case NBD_CMD_DISC:
144         return "disconnect";
145     case NBD_CMD_FLUSH:
146         return "flush";
147     case NBD_CMD_TRIM:
148         return "trim";
149     case NBD_CMD_CACHE:
150         return "cache";
151     case NBD_CMD_WRITE_ZEROES:
152         return "write zeroes";
153     case NBD_CMD_BLOCK_STATUS:
154         return "block status";
155     default:
156         return "<unknown>";
157     }
158 }
159 
160 
nbd_reply_type_lookup(uint16_t type)161 const char *nbd_reply_type_lookup(uint16_t type)
162 {
163     switch (type) {
164     case NBD_REPLY_TYPE_NONE:
165         return "none";
166     case NBD_REPLY_TYPE_OFFSET_DATA:
167         return "data";
168     case NBD_REPLY_TYPE_OFFSET_HOLE:
169         return "hole";
170     case NBD_REPLY_TYPE_BLOCK_STATUS:
171         return "block status (32-bit)";
172     case NBD_REPLY_TYPE_BLOCK_STATUS_EXT:
173         return "block status (64-bit)";
174     case NBD_REPLY_TYPE_ERROR:
175         return "generic error";
176     case NBD_REPLY_TYPE_ERROR_OFFSET:
177         return "error at offset";
178     default:
179         if (type & (1 << 15)) {
180             return "<unknown error>";
181         }
182         return "<unknown>";
183     }
184 }
185 
186 
nbd_err_lookup(int err)187 const char *nbd_err_lookup(int err)
188 {
189     switch (err) {
190     case NBD_SUCCESS:
191         return "success";
192     case NBD_EPERM:
193         return "EPERM";
194     case NBD_EIO:
195         return "EIO";
196     case NBD_ENOMEM:
197         return "ENOMEM";
198     case NBD_EINVAL:
199         return "EINVAL";
200     case NBD_ENOSPC:
201         return "ENOSPC";
202     case NBD_EOVERFLOW:
203         return "EOVERFLOW";
204     case NBD_ENOTSUP:
205         return "ENOTSUP";
206     case NBD_ESHUTDOWN:
207         return "ESHUTDOWN";
208     default:
209         return "<unknown>";
210     }
211 }
212 
213 
nbd_errno_to_system_errno(int err)214 int nbd_errno_to_system_errno(int err)
215 {
216     int ret;
217     switch (err) {
218     case NBD_SUCCESS:
219         ret = 0;
220         break;
221     case NBD_EPERM:
222         ret = EPERM;
223         break;
224     case NBD_EIO:
225         ret = EIO;
226         break;
227     case NBD_ENOMEM:
228         ret = ENOMEM;
229         break;
230     case NBD_ENOSPC:
231         ret = ENOSPC;
232         break;
233     case NBD_EOVERFLOW:
234         ret = EOVERFLOW;
235         break;
236     case NBD_ENOTSUP:
237         ret = ENOTSUP;
238         break;
239     case NBD_ESHUTDOWN:
240         ret = ESHUTDOWN;
241         break;
242     default:
243         trace_nbd_unknown_error(err);
244         /* fallthrough */
245     case NBD_EINVAL:
246         ret = EINVAL;
247         break;
248     }
249     return ret;
250 }
251 
252 
nbd_mode_lookup(NBDMode mode)253 const char *nbd_mode_lookup(NBDMode mode)
254 {
255     switch (mode) {
256     case NBD_MODE_OLDSTYLE:
257         return "oldstyle";
258     case NBD_MODE_EXPORT_NAME:
259         return "export name only";
260     case NBD_MODE_SIMPLE:
261         return "simple headers";
262     case NBD_MODE_STRUCTURED:
263         return "structured replies";
264     case NBD_MODE_EXTENDED:
265         return "extended headers";
266     default:
267         return "<unknown>";
268     }
269 }
270 
271 /*
272  * Testing shows that 2m send buffer is optimal. Changing the receive buffer
273  * size has no effect on performance.
274  * On Linux we need to increase net.core.wmem_max to make this effective.
275  */
276 #if defined(__APPLE__) || defined(__linux__)
277 #define UNIX_STREAM_SOCKET_SEND_BUFFER_SIZE (2 * MiB)
278 #endif
279 
nbd_set_socket_send_buffer(QIOChannelSocket * sioc)280 void nbd_set_socket_send_buffer(QIOChannelSocket *sioc)
281 {
282 #ifdef UNIX_STREAM_SOCKET_SEND_BUFFER_SIZE
283     if (sioc->localAddr.ss_family == AF_UNIX) {
284         size_t size = UNIX_STREAM_SOCKET_SEND_BUFFER_SIZE;
285         Error *errp = NULL;
286 
287         if (qio_channel_socket_set_send_buffer(sioc, size, &errp) < 0) {
288             warn_report_err(errp);
289         }
290     }
291 #endif /* UNIX_STREAM_SOCKET_SEND_BUFFER_SIZE */
292 }
293