root / block / nfs.c @ f53f81e0
History | View | Annotate | Download (11.7 kB)
1 | 6542aa9c | Peter Lieven | /*
|
---|---|---|---|
2 | 6542aa9c | Peter Lieven | * QEMU Block driver for native access to files on NFS shares
|
3 | 6542aa9c | Peter Lieven | *
|
4 | 6542aa9c | Peter Lieven | * Copyright (c) 2014 Peter Lieven <pl@kamp.de>
|
5 | 6542aa9c | Peter Lieven | *
|
6 | 6542aa9c | Peter Lieven | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 6542aa9c | Peter Lieven | * of this software and associated documentation files (the "Software"), to deal
|
8 | 6542aa9c | Peter Lieven | * in the Software without restriction, including without limitation the rights
|
9 | 6542aa9c | Peter Lieven | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 6542aa9c | Peter Lieven | * copies of the Software, and to permit persons to whom the Software is
|
11 | 6542aa9c | Peter Lieven | * furnished to do so, subject to the following conditions:
|
12 | 6542aa9c | Peter Lieven | *
|
13 | 6542aa9c | Peter Lieven | * The above copyright notice and this permission notice shall be included in
|
14 | 6542aa9c | Peter Lieven | * all copies or substantial portions of the Software.
|
15 | 6542aa9c | Peter Lieven | *
|
16 | 6542aa9c | Peter Lieven | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 6542aa9c | Peter Lieven | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 6542aa9c | Peter Lieven | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 6542aa9c | Peter Lieven | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 6542aa9c | Peter Lieven | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 6542aa9c | Peter Lieven | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 6542aa9c | Peter Lieven | * THE SOFTWARE.
|
23 | 6542aa9c | Peter Lieven | */
|
24 | 6542aa9c | Peter Lieven | |
25 | 6542aa9c | Peter Lieven | #include "config-host.h" |
26 | 6542aa9c | Peter Lieven | |
27 | 6542aa9c | Peter Lieven | #include <poll.h> |
28 | 6542aa9c | Peter Lieven | #include "qemu-common.h" |
29 | 6542aa9c | Peter Lieven | #include "qemu/config-file.h" |
30 | 6542aa9c | Peter Lieven | #include "qemu/error-report.h" |
31 | 6542aa9c | Peter Lieven | #include "block/block_int.h" |
32 | 6542aa9c | Peter Lieven | #include "trace.h" |
33 | 6542aa9c | Peter Lieven | #include "qemu/iov.h" |
34 | 6542aa9c | Peter Lieven | #include "qemu/uri.h" |
35 | 6542aa9c | Peter Lieven | #include "sysemu/sysemu.h" |
36 | 6542aa9c | Peter Lieven | #include <nfsc/libnfs.h> |
37 | 6542aa9c | Peter Lieven | |
38 | 6542aa9c | Peter Lieven | typedef struct NFSClient { |
39 | 6542aa9c | Peter Lieven | struct nfs_context *context;
|
40 | 6542aa9c | Peter Lieven | struct nfsfh *fh;
|
41 | 6542aa9c | Peter Lieven | int events;
|
42 | 6542aa9c | Peter Lieven | bool has_zero_init;
|
43 | 6542aa9c | Peter Lieven | } NFSClient; |
44 | 6542aa9c | Peter Lieven | |
45 | 6542aa9c | Peter Lieven | typedef struct NFSRPC { |
46 | 6542aa9c | Peter Lieven | int ret;
|
47 | 6542aa9c | Peter Lieven | int complete;
|
48 | 6542aa9c | Peter Lieven | QEMUIOVector *iov; |
49 | 6542aa9c | Peter Lieven | struct stat *st;
|
50 | 6542aa9c | Peter Lieven | Coroutine *co; |
51 | 6542aa9c | Peter Lieven | QEMUBH *bh; |
52 | 6542aa9c | Peter Lieven | } NFSRPC; |
53 | 6542aa9c | Peter Lieven | |
54 | 6542aa9c | Peter Lieven | static void nfs_process_read(void *arg); |
55 | 6542aa9c | Peter Lieven | static void nfs_process_write(void *arg); |
56 | 6542aa9c | Peter Lieven | |
57 | 6542aa9c | Peter Lieven | static void nfs_set_events(NFSClient *client) |
58 | 6542aa9c | Peter Lieven | { |
59 | 6542aa9c | Peter Lieven | int ev = nfs_which_events(client->context);
|
60 | 6542aa9c | Peter Lieven | if (ev != client->events) {
|
61 | 6542aa9c | Peter Lieven | qemu_aio_set_fd_handler(nfs_get_fd(client->context), |
62 | 6542aa9c | Peter Lieven | (ev & POLLIN) ? nfs_process_read : NULL,
|
63 | 6542aa9c | Peter Lieven | (ev & POLLOUT) ? nfs_process_write : NULL,
|
64 | 6542aa9c | Peter Lieven | client); |
65 | 6542aa9c | Peter Lieven | |
66 | 6542aa9c | Peter Lieven | } |
67 | 6542aa9c | Peter Lieven | client->events = ev; |
68 | 6542aa9c | Peter Lieven | } |
69 | 6542aa9c | Peter Lieven | |
70 | 6542aa9c | Peter Lieven | static void nfs_process_read(void *arg) |
71 | 6542aa9c | Peter Lieven | { |
72 | 6542aa9c | Peter Lieven | NFSClient *client = arg; |
73 | 6542aa9c | Peter Lieven | nfs_service(client->context, POLLIN); |
74 | 6542aa9c | Peter Lieven | nfs_set_events(client); |
75 | 6542aa9c | Peter Lieven | } |
76 | 6542aa9c | Peter Lieven | |
77 | 6542aa9c | Peter Lieven | static void nfs_process_write(void *arg) |
78 | 6542aa9c | Peter Lieven | { |
79 | 6542aa9c | Peter Lieven | NFSClient *client = arg; |
80 | 6542aa9c | Peter Lieven | nfs_service(client->context, POLLOUT); |
81 | 6542aa9c | Peter Lieven | nfs_set_events(client); |
82 | 6542aa9c | Peter Lieven | } |
83 | 6542aa9c | Peter Lieven | |
84 | 6542aa9c | Peter Lieven | static void nfs_co_init_task(NFSClient *client, NFSRPC *task) |
85 | 6542aa9c | Peter Lieven | { |
86 | 6542aa9c | Peter Lieven | *task = (NFSRPC) { |
87 | 6542aa9c | Peter Lieven | .co = qemu_coroutine_self(), |
88 | 6542aa9c | Peter Lieven | }; |
89 | 6542aa9c | Peter Lieven | } |
90 | 6542aa9c | Peter Lieven | |
91 | 6542aa9c | Peter Lieven | static void nfs_co_generic_bh_cb(void *opaque) |
92 | 6542aa9c | Peter Lieven | { |
93 | 6542aa9c | Peter Lieven | NFSRPC *task = opaque; |
94 | 6542aa9c | Peter Lieven | qemu_bh_delete(task->bh); |
95 | 6542aa9c | Peter Lieven | qemu_coroutine_enter(task->co, NULL);
|
96 | 6542aa9c | Peter Lieven | } |
97 | 6542aa9c | Peter Lieven | |
98 | 6542aa9c | Peter Lieven | static void |
99 | 6542aa9c | Peter Lieven | nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data, |
100 | 6542aa9c | Peter Lieven | void *private_data)
|
101 | 6542aa9c | Peter Lieven | { |
102 | 6542aa9c | Peter Lieven | NFSRPC *task = private_data; |
103 | 6542aa9c | Peter Lieven | task->complete = 1;
|
104 | 6542aa9c | Peter Lieven | task->ret = ret; |
105 | 6542aa9c | Peter Lieven | if (task->ret > 0 && task->iov) { |
106 | 6542aa9c | Peter Lieven | if (task->ret <= task->iov->size) {
|
107 | 6542aa9c | Peter Lieven | qemu_iovec_from_buf(task->iov, 0, data, task->ret);
|
108 | 6542aa9c | Peter Lieven | } else {
|
109 | 6542aa9c | Peter Lieven | task->ret = -EIO; |
110 | 6542aa9c | Peter Lieven | } |
111 | 6542aa9c | Peter Lieven | } |
112 | 6542aa9c | Peter Lieven | if (task->ret == 0 && task->st) { |
113 | 6542aa9c | Peter Lieven | memcpy(task->st, data, sizeof(struct stat)); |
114 | 6542aa9c | Peter Lieven | } |
115 | 6542aa9c | Peter Lieven | if (task->co) {
|
116 | 6542aa9c | Peter Lieven | task->bh = qemu_bh_new(nfs_co_generic_bh_cb, task); |
117 | 6542aa9c | Peter Lieven | qemu_bh_schedule(task->bh); |
118 | 6542aa9c | Peter Lieven | } |
119 | 6542aa9c | Peter Lieven | } |
120 | 6542aa9c | Peter Lieven | |
121 | 6542aa9c | Peter Lieven | static int coroutine_fn nfs_co_readv(BlockDriverState *bs, |
122 | 6542aa9c | Peter Lieven | int64_t sector_num, int nb_sectors,
|
123 | 6542aa9c | Peter Lieven | QEMUIOVector *iov) |
124 | 6542aa9c | Peter Lieven | { |
125 | 6542aa9c | Peter Lieven | NFSClient *client = bs->opaque; |
126 | 6542aa9c | Peter Lieven | NFSRPC task; |
127 | 6542aa9c | Peter Lieven | |
128 | 6542aa9c | Peter Lieven | nfs_co_init_task(client, &task); |
129 | 6542aa9c | Peter Lieven | task.iov = iov; |
130 | 6542aa9c | Peter Lieven | |
131 | 6542aa9c | Peter Lieven | if (nfs_pread_async(client->context, client->fh,
|
132 | 6542aa9c | Peter Lieven | sector_num * BDRV_SECTOR_SIZE, |
133 | 6542aa9c | Peter Lieven | nb_sectors * BDRV_SECTOR_SIZE, |
134 | 6542aa9c | Peter Lieven | nfs_co_generic_cb, &task) != 0) {
|
135 | 6542aa9c | Peter Lieven | return -ENOMEM;
|
136 | 6542aa9c | Peter Lieven | } |
137 | 6542aa9c | Peter Lieven | |
138 | 6542aa9c | Peter Lieven | while (!task.complete) {
|
139 | 6542aa9c | Peter Lieven | nfs_set_events(client); |
140 | 6542aa9c | Peter Lieven | qemu_coroutine_yield(); |
141 | 6542aa9c | Peter Lieven | } |
142 | 6542aa9c | Peter Lieven | |
143 | 6542aa9c | Peter Lieven | if (task.ret < 0) { |
144 | 6542aa9c | Peter Lieven | return task.ret;
|
145 | 6542aa9c | Peter Lieven | } |
146 | 6542aa9c | Peter Lieven | |
147 | 6542aa9c | Peter Lieven | /* zero pad short reads */
|
148 | 6542aa9c | Peter Lieven | if (task.ret < iov->size) {
|
149 | 6542aa9c | Peter Lieven | qemu_iovec_memset(iov, task.ret, 0, iov->size - task.ret);
|
150 | 6542aa9c | Peter Lieven | } |
151 | 6542aa9c | Peter Lieven | |
152 | 6542aa9c | Peter Lieven | return 0; |
153 | 6542aa9c | Peter Lieven | } |
154 | 6542aa9c | Peter Lieven | |
155 | 6542aa9c | Peter Lieven | static int coroutine_fn nfs_co_writev(BlockDriverState *bs, |
156 | 6542aa9c | Peter Lieven | int64_t sector_num, int nb_sectors,
|
157 | 6542aa9c | Peter Lieven | QEMUIOVector *iov) |
158 | 6542aa9c | Peter Lieven | { |
159 | 6542aa9c | Peter Lieven | NFSClient *client = bs->opaque; |
160 | 6542aa9c | Peter Lieven | NFSRPC task; |
161 | 6542aa9c | Peter Lieven | char *buf = NULL; |
162 | 6542aa9c | Peter Lieven | |
163 | 6542aa9c | Peter Lieven | nfs_co_init_task(client, &task); |
164 | 6542aa9c | Peter Lieven | |
165 | 6542aa9c | Peter Lieven | buf = g_malloc(nb_sectors * BDRV_SECTOR_SIZE); |
166 | 6542aa9c | Peter Lieven | qemu_iovec_to_buf(iov, 0, buf, nb_sectors * BDRV_SECTOR_SIZE);
|
167 | 6542aa9c | Peter Lieven | |
168 | 6542aa9c | Peter Lieven | if (nfs_pwrite_async(client->context, client->fh,
|
169 | 6542aa9c | Peter Lieven | sector_num * BDRV_SECTOR_SIZE, |
170 | 6542aa9c | Peter Lieven | nb_sectors * BDRV_SECTOR_SIZE, |
171 | 6542aa9c | Peter Lieven | buf, nfs_co_generic_cb, &task) != 0) {
|
172 | 6542aa9c | Peter Lieven | g_free(buf); |
173 | 6542aa9c | Peter Lieven | return -ENOMEM;
|
174 | 6542aa9c | Peter Lieven | } |
175 | 6542aa9c | Peter Lieven | |
176 | 6542aa9c | Peter Lieven | while (!task.complete) {
|
177 | 6542aa9c | Peter Lieven | nfs_set_events(client); |
178 | 6542aa9c | Peter Lieven | qemu_coroutine_yield(); |
179 | 6542aa9c | Peter Lieven | } |
180 | 6542aa9c | Peter Lieven | |
181 | 6542aa9c | Peter Lieven | g_free(buf); |
182 | 6542aa9c | Peter Lieven | |
183 | 6542aa9c | Peter Lieven | if (task.ret != nb_sectors * BDRV_SECTOR_SIZE) {
|
184 | 6542aa9c | Peter Lieven | return task.ret < 0 ? task.ret : -EIO; |
185 | 6542aa9c | Peter Lieven | } |
186 | 6542aa9c | Peter Lieven | |
187 | 6542aa9c | Peter Lieven | return 0; |
188 | 6542aa9c | Peter Lieven | } |
189 | 6542aa9c | Peter Lieven | |
190 | 6542aa9c | Peter Lieven | static int coroutine_fn nfs_co_flush(BlockDriverState *bs) |
191 | 6542aa9c | Peter Lieven | { |
192 | 6542aa9c | Peter Lieven | NFSClient *client = bs->opaque; |
193 | 6542aa9c | Peter Lieven | NFSRPC task; |
194 | 6542aa9c | Peter Lieven | |
195 | 6542aa9c | Peter Lieven | nfs_co_init_task(client, &task); |
196 | 6542aa9c | Peter Lieven | |
197 | 6542aa9c | Peter Lieven | if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
|
198 | 6542aa9c | Peter Lieven | &task) != 0) {
|
199 | 6542aa9c | Peter Lieven | return -ENOMEM;
|
200 | 6542aa9c | Peter Lieven | } |
201 | 6542aa9c | Peter Lieven | |
202 | 6542aa9c | Peter Lieven | while (!task.complete) {
|
203 | 6542aa9c | Peter Lieven | nfs_set_events(client); |
204 | 6542aa9c | Peter Lieven | qemu_coroutine_yield(); |
205 | 6542aa9c | Peter Lieven | } |
206 | 6542aa9c | Peter Lieven | |
207 | 6542aa9c | Peter Lieven | return task.ret;
|
208 | 6542aa9c | Peter Lieven | } |
209 | 6542aa9c | Peter Lieven | |
210 | 6542aa9c | Peter Lieven | /* TODO Convert to fine grained options */
|
211 | 6542aa9c | Peter Lieven | static QemuOptsList runtime_opts = {
|
212 | 6542aa9c | Peter Lieven | .name = "nfs",
|
213 | 6542aa9c | Peter Lieven | .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), |
214 | 6542aa9c | Peter Lieven | .desc = { |
215 | 6542aa9c | Peter Lieven | { |
216 | 6542aa9c | Peter Lieven | .name = "filename",
|
217 | 6542aa9c | Peter Lieven | .type = QEMU_OPT_STRING, |
218 | 6542aa9c | Peter Lieven | .help = "URL to the NFS file",
|
219 | 6542aa9c | Peter Lieven | }, |
220 | 6542aa9c | Peter Lieven | { /* end of list */ }
|
221 | 6542aa9c | Peter Lieven | }, |
222 | 6542aa9c | Peter Lieven | }; |
223 | 6542aa9c | Peter Lieven | |
224 | 6542aa9c | Peter Lieven | static void nfs_client_close(NFSClient *client) |
225 | 6542aa9c | Peter Lieven | { |
226 | 6542aa9c | Peter Lieven | if (client->context) {
|
227 | 6542aa9c | Peter Lieven | if (client->fh) {
|
228 | 6542aa9c | Peter Lieven | nfs_close(client->context, client->fh); |
229 | 6542aa9c | Peter Lieven | } |
230 | 6542aa9c | Peter Lieven | qemu_aio_set_fd_handler(nfs_get_fd(client->context), NULL, NULL, NULL); |
231 | 6542aa9c | Peter Lieven | nfs_destroy_context(client->context); |
232 | 6542aa9c | Peter Lieven | } |
233 | 6542aa9c | Peter Lieven | memset(client, 0, sizeof(NFSClient)); |
234 | 6542aa9c | Peter Lieven | } |
235 | 6542aa9c | Peter Lieven | |
236 | 6542aa9c | Peter Lieven | static void nfs_file_close(BlockDriverState *bs) |
237 | 6542aa9c | Peter Lieven | { |
238 | 6542aa9c | Peter Lieven | NFSClient *client = bs->opaque; |
239 | 6542aa9c | Peter Lieven | nfs_client_close(client); |
240 | 6542aa9c | Peter Lieven | } |
241 | 6542aa9c | Peter Lieven | |
242 | 6542aa9c | Peter Lieven | static int64_t nfs_client_open(NFSClient *client, const char *filename, |
243 | 6542aa9c | Peter Lieven | int flags, Error **errp)
|
244 | 6542aa9c | Peter Lieven | { |
245 | 6542aa9c | Peter Lieven | int ret = -EINVAL, i;
|
246 | 6542aa9c | Peter Lieven | struct stat st;
|
247 | 6542aa9c | Peter Lieven | URI *uri; |
248 | 6542aa9c | Peter Lieven | QueryParams *qp = NULL;
|
249 | 6542aa9c | Peter Lieven | char *file = NULL, *strp = NULL; |
250 | 6542aa9c | Peter Lieven | |
251 | 6542aa9c | Peter Lieven | uri = uri_parse(filename); |
252 | 6542aa9c | Peter Lieven | if (!uri) {
|
253 | 6542aa9c | Peter Lieven | error_setg(errp, "Invalid URL specified");
|
254 | 6542aa9c | Peter Lieven | goto fail;
|
255 | 6542aa9c | Peter Lieven | } |
256 | 6542aa9c | Peter Lieven | strp = strrchr(uri->path, '/');
|
257 | 6542aa9c | Peter Lieven | if (strp == NULL) { |
258 | 6542aa9c | Peter Lieven | error_setg(errp, "Invalid URL specified");
|
259 | 6542aa9c | Peter Lieven | goto fail;
|
260 | 6542aa9c | Peter Lieven | } |
261 | 6542aa9c | Peter Lieven | file = g_strdup(strp); |
262 | 6542aa9c | Peter Lieven | *strp = 0;
|
263 | 6542aa9c | Peter Lieven | |
264 | 6542aa9c | Peter Lieven | client->context = nfs_init_context(); |
265 | 6542aa9c | Peter Lieven | if (client->context == NULL) { |
266 | 6542aa9c | Peter Lieven | error_setg(errp, "Failed to init NFS context");
|
267 | 6542aa9c | Peter Lieven | goto fail;
|
268 | 6542aa9c | Peter Lieven | } |
269 | 6542aa9c | Peter Lieven | |
270 | 6542aa9c | Peter Lieven | qp = query_params_parse(uri->query); |
271 | 6542aa9c | Peter Lieven | for (i = 0; i < qp->n; i++) { |
272 | 6542aa9c | Peter Lieven | if (!qp->p[i].value) {
|
273 | 6542aa9c | Peter Lieven | error_setg(errp, "Value for NFS parameter expected: %s",
|
274 | 6542aa9c | Peter Lieven | qp->p[i].name); |
275 | 6542aa9c | Peter Lieven | goto fail;
|
276 | 6542aa9c | Peter Lieven | } |
277 | 6542aa9c | Peter Lieven | if (!strncmp(qp->p[i].name, "uid", 3)) { |
278 | 6542aa9c | Peter Lieven | nfs_set_uid(client->context, atoi(qp->p[i].value)); |
279 | 6542aa9c | Peter Lieven | } else if (!strncmp(qp->p[i].name, "gid", 3)) { |
280 | 6542aa9c | Peter Lieven | nfs_set_gid(client->context, atoi(qp->p[i].value)); |
281 | 6542aa9c | Peter Lieven | } else if (!strncmp(qp->p[i].name, "tcp-syncnt", 10)) { |
282 | 6542aa9c | Peter Lieven | nfs_set_tcp_syncnt(client->context, atoi(qp->p[i].value)); |
283 | 6542aa9c | Peter Lieven | } else {
|
284 | 6542aa9c | Peter Lieven | error_setg(errp, "Unknown NFS parameter name: %s",
|
285 | 6542aa9c | Peter Lieven | qp->p[i].name); |
286 | 6542aa9c | Peter Lieven | goto fail;
|
287 | 6542aa9c | Peter Lieven | } |
288 | 6542aa9c | Peter Lieven | } |
289 | 6542aa9c | Peter Lieven | |
290 | 6542aa9c | Peter Lieven | ret = nfs_mount(client->context, uri->server, uri->path); |
291 | 6542aa9c | Peter Lieven | if (ret < 0) { |
292 | 6542aa9c | Peter Lieven | error_setg(errp, "Failed to mount nfs share: %s",
|
293 | 6542aa9c | Peter Lieven | nfs_get_error(client->context)); |
294 | 6542aa9c | Peter Lieven | goto fail;
|
295 | 6542aa9c | Peter Lieven | } |
296 | 6542aa9c | Peter Lieven | |
297 | 6542aa9c | Peter Lieven | if (flags & O_CREAT) {
|
298 | 6542aa9c | Peter Lieven | ret = nfs_creat(client->context, file, 0600, &client->fh);
|
299 | 6542aa9c | Peter Lieven | if (ret < 0) { |
300 | 6542aa9c | Peter Lieven | error_setg(errp, "Failed to create file: %s",
|
301 | 6542aa9c | Peter Lieven | nfs_get_error(client->context)); |
302 | 6542aa9c | Peter Lieven | goto fail;
|
303 | 6542aa9c | Peter Lieven | } |
304 | 6542aa9c | Peter Lieven | } else {
|
305 | 6542aa9c | Peter Lieven | ret = nfs_open(client->context, file, flags, &client->fh); |
306 | 6542aa9c | Peter Lieven | if (ret < 0) { |
307 | 6542aa9c | Peter Lieven | error_setg(errp, "Failed to open file : %s",
|
308 | 6542aa9c | Peter Lieven | nfs_get_error(client->context)); |
309 | 6542aa9c | Peter Lieven | goto fail;
|
310 | 6542aa9c | Peter Lieven | } |
311 | 6542aa9c | Peter Lieven | } |
312 | 6542aa9c | Peter Lieven | |
313 | 6542aa9c | Peter Lieven | ret = nfs_fstat(client->context, client->fh, &st); |
314 | 6542aa9c | Peter Lieven | if (ret < 0) { |
315 | 6542aa9c | Peter Lieven | error_setg(errp, "Failed to fstat file: %s",
|
316 | 6542aa9c | Peter Lieven | nfs_get_error(client->context)); |
317 | 6542aa9c | Peter Lieven | goto fail;
|
318 | 6542aa9c | Peter Lieven | } |
319 | 6542aa9c | Peter Lieven | |
320 | 6542aa9c | Peter Lieven | ret = DIV_ROUND_UP(st.st_size, BDRV_SECTOR_SIZE); |
321 | 6542aa9c | Peter Lieven | client->has_zero_init = S_ISREG(st.st_mode); |
322 | 6542aa9c | Peter Lieven | goto out;
|
323 | 6542aa9c | Peter Lieven | fail:
|
324 | 6542aa9c | Peter Lieven | nfs_client_close(client); |
325 | 6542aa9c | Peter Lieven | out:
|
326 | 6542aa9c | Peter Lieven | if (qp) {
|
327 | 6542aa9c | Peter Lieven | query_params_free(qp); |
328 | 6542aa9c | Peter Lieven | } |
329 | 6542aa9c | Peter Lieven | uri_free(uri); |
330 | 6542aa9c | Peter Lieven | g_free(file); |
331 | 6542aa9c | Peter Lieven | return ret;
|
332 | 6542aa9c | Peter Lieven | } |
333 | 6542aa9c | Peter Lieven | |
334 | 6542aa9c | Peter Lieven | static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags, |
335 | 6542aa9c | Peter Lieven | Error **errp) { |
336 | 6542aa9c | Peter Lieven | NFSClient *client = bs->opaque; |
337 | 6542aa9c | Peter Lieven | int64_t ret; |
338 | 6542aa9c | Peter Lieven | QemuOpts *opts; |
339 | 6542aa9c | Peter Lieven | Error *local_err = NULL;
|
340 | 6542aa9c | Peter Lieven | |
341 | 6542aa9c | Peter Lieven | opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); |
342 | 6542aa9c | Peter Lieven | qemu_opts_absorb_qdict(opts, options, &local_err); |
343 | 6542aa9c | Peter Lieven | if (error_is_set(&local_err)) {
|
344 | 6542aa9c | Peter Lieven | error_propagate(errp, local_err); |
345 | 6542aa9c | Peter Lieven | return -EINVAL;
|
346 | 6542aa9c | Peter Lieven | } |
347 | 6542aa9c | Peter Lieven | ret = nfs_client_open(client, qemu_opt_get(opts, "filename"),
|
348 | 6542aa9c | Peter Lieven | (flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY, |
349 | 6542aa9c | Peter Lieven | errp); |
350 | 6542aa9c | Peter Lieven | if (ret < 0) { |
351 | 6542aa9c | Peter Lieven | return ret;
|
352 | 6542aa9c | Peter Lieven | } |
353 | 6542aa9c | Peter Lieven | bs->total_sectors = ret; |
354 | 6542aa9c | Peter Lieven | return 0; |
355 | 6542aa9c | Peter Lieven | } |
356 | 6542aa9c | Peter Lieven | |
357 | 6542aa9c | Peter Lieven | static int nfs_file_create(const char *url, QEMUOptionParameter *options, |
358 | 6542aa9c | Peter Lieven | Error **errp) |
359 | 6542aa9c | Peter Lieven | { |
360 | 6542aa9c | Peter Lieven | int ret = 0; |
361 | 6542aa9c | Peter Lieven | int64_t total_size = 0;
|
362 | 6542aa9c | Peter Lieven | NFSClient *client = g_malloc0(sizeof(NFSClient));
|
363 | 6542aa9c | Peter Lieven | |
364 | 6542aa9c | Peter Lieven | /* Read out options */
|
365 | 6542aa9c | Peter Lieven | while (options && options->name) {
|
366 | 6542aa9c | Peter Lieven | if (!strcmp(options->name, "size")) { |
367 | 6542aa9c | Peter Lieven | total_size = options->value.n; |
368 | 6542aa9c | Peter Lieven | } |
369 | 6542aa9c | Peter Lieven | options++; |
370 | 6542aa9c | Peter Lieven | } |
371 | 6542aa9c | Peter Lieven | |
372 | 6542aa9c | Peter Lieven | ret = nfs_client_open(client, url, O_CREAT, errp); |
373 | 6542aa9c | Peter Lieven | if (ret < 0) { |
374 | 6542aa9c | Peter Lieven | goto out;
|
375 | 6542aa9c | Peter Lieven | } |
376 | 6542aa9c | Peter Lieven | ret = nfs_ftruncate(client->context, client->fh, total_size); |
377 | 6542aa9c | Peter Lieven | nfs_client_close(client); |
378 | 6542aa9c | Peter Lieven | out:
|
379 | 6542aa9c | Peter Lieven | g_free(client); |
380 | 6542aa9c | Peter Lieven | return ret;
|
381 | 6542aa9c | Peter Lieven | } |
382 | 6542aa9c | Peter Lieven | |
383 | 6542aa9c | Peter Lieven | static int nfs_has_zero_init(BlockDriverState *bs) |
384 | 6542aa9c | Peter Lieven | { |
385 | 6542aa9c | Peter Lieven | NFSClient *client = bs->opaque; |
386 | 6542aa9c | Peter Lieven | return client->has_zero_init;
|
387 | 6542aa9c | Peter Lieven | } |
388 | 6542aa9c | Peter Lieven | |
389 | 6542aa9c | Peter Lieven | static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
|
390 | 6542aa9c | Peter Lieven | { |
391 | 6542aa9c | Peter Lieven | NFSClient *client = bs->opaque; |
392 | 6542aa9c | Peter Lieven | NFSRPC task = {0};
|
393 | 6542aa9c | Peter Lieven | struct stat st;
|
394 | 6542aa9c | Peter Lieven | |
395 | 6542aa9c | Peter Lieven | task.st = &st; |
396 | 6542aa9c | Peter Lieven | if (nfs_fstat_async(client->context, client->fh, nfs_co_generic_cb,
|
397 | 6542aa9c | Peter Lieven | &task) != 0) {
|
398 | 6542aa9c | Peter Lieven | return -ENOMEM;
|
399 | 6542aa9c | Peter Lieven | } |
400 | 6542aa9c | Peter Lieven | |
401 | 6542aa9c | Peter Lieven | while (!task.complete) {
|
402 | 6542aa9c | Peter Lieven | nfs_set_events(client); |
403 | 6542aa9c | Peter Lieven | qemu_aio_wait(); |
404 | 6542aa9c | Peter Lieven | } |
405 | 6542aa9c | Peter Lieven | |
406 | 6542aa9c | Peter Lieven | return (task.ret < 0 ? task.ret : st.st_blocks * st.st_blksize); |
407 | 6542aa9c | Peter Lieven | } |
408 | 6542aa9c | Peter Lieven | |
409 | 6542aa9c | Peter Lieven | static int nfs_file_truncate(BlockDriverState *bs, int64_t offset) |
410 | 6542aa9c | Peter Lieven | { |
411 | 6542aa9c | Peter Lieven | NFSClient *client = bs->opaque; |
412 | 6542aa9c | Peter Lieven | return nfs_ftruncate(client->context, client->fh, offset);
|
413 | 6542aa9c | Peter Lieven | } |
414 | 6542aa9c | Peter Lieven | |
415 | 6542aa9c | Peter Lieven | static BlockDriver bdrv_nfs = {
|
416 | 6542aa9c | Peter Lieven | .format_name = "nfs",
|
417 | 6542aa9c | Peter Lieven | .protocol_name = "nfs",
|
418 | 6542aa9c | Peter Lieven | |
419 | 6542aa9c | Peter Lieven | .instance_size = sizeof(NFSClient),
|
420 | 6542aa9c | Peter Lieven | .bdrv_needs_filename = true,
|
421 | 6542aa9c | Peter Lieven | .bdrv_has_zero_init = nfs_has_zero_init, |
422 | 6542aa9c | Peter Lieven | .bdrv_get_allocated_file_size = nfs_get_allocated_file_size, |
423 | 6542aa9c | Peter Lieven | .bdrv_truncate = nfs_file_truncate, |
424 | 6542aa9c | Peter Lieven | |
425 | 6542aa9c | Peter Lieven | .bdrv_file_open = nfs_file_open, |
426 | 6542aa9c | Peter Lieven | .bdrv_close = nfs_file_close, |
427 | 6542aa9c | Peter Lieven | .bdrv_create = nfs_file_create, |
428 | 6542aa9c | Peter Lieven | |
429 | 6542aa9c | Peter Lieven | .bdrv_co_readv = nfs_co_readv, |
430 | 6542aa9c | Peter Lieven | .bdrv_co_writev = nfs_co_writev, |
431 | 6542aa9c | Peter Lieven | .bdrv_co_flush_to_disk = nfs_co_flush, |
432 | 6542aa9c | Peter Lieven | }; |
433 | 6542aa9c | Peter Lieven | |
434 | 6542aa9c | Peter Lieven | static void nfs_block_init(void) |
435 | 6542aa9c | Peter Lieven | { |
436 | 6542aa9c | Peter Lieven | bdrv_register(&bdrv_nfs); |
437 | 6542aa9c | Peter Lieven | } |
438 | 6542aa9c | Peter Lieven | |
439 | 6542aa9c | Peter Lieven | block_init(nfs_block_init); |