master
c 958 lines 27.5 KB
Raw
1 /*
2 * QEMU Block driver for native access to files on NFS shares
3 *
4 * Copyright (c) 2014-2017 Peter Lieven <pl@kamp.de>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25 #include "qemu/osdep.h"
26
27 #if !defined(_WIN32)
28 #include <poll.h>
29 #endif
30 #include "qemu/config-file.h"
31 #include "qemu/error-report.h"
32 #include "qapi/error.h"
33 #include "block/block-io.h"
34 #include "block/block_int.h"
35 #include "block/qdict.h"
36 #include "trace.h"
37 #include "qemu/iov.h"
38 #include "qemu/main-loop.h"
39 #include "qemu/module.h"
40 #include "qemu/option.h"
41 #include "qemu/cutils.h"
42 #include "system/replay.h"
43 #include "qapi/qapi-visit-block-core.h"
44 #include "qobject/qdict.h"
45 #include "qobject/qstring.h"
46 #include "qapi/qobject-input-visitor.h"
47 #include "qapi/qobject-output-visitor.h"
48 #include <nfsc/libnfs.h>
49
50
51 #define QEMU_NFS_MAX_READAHEAD_SIZE 1048576
52 #define QEMU_NFS_MAX_PAGECACHE_SIZE (8388608 / NFS_BLKSIZE)
53 #define QEMU_NFS_MAX_DEBUG_LEVEL 2
54
55 typedef struct NFSClient {
56 struct nfs_context *context;
57 struct nfsfh *fh;
58 int events;
59 bool has_zero_init;
60 AioContext *aio_context;
61 QemuMutex mutex;
62 uint64_t st_blocks;
63 bool cache_used;
64 NFSServer *server;
65 char *path;
66 int64_t uid, gid, tcp_syncnt, readahead, pagecache, debug;
67 } NFSClient;
68
69 typedef struct NFSRPC {
70 BlockDriverState *bs;
71 int ret;
72 #ifndef LIBNFS_API_V2
73 QEMUIOVector *iov;
74 #endif
75 struct stat *st;
76 Coroutine *co;
77 NFSClient *client;
78 } NFSRPC;
79
80 static int nfs_parse_uri(const char *filename, QDict *options, Error **errp)
81 {
82 g_autoptr(GUri) uri = g_uri_parse(filename, G_URI_FLAGS_NONE, NULL);
83 GUriParamsIter qp;
84 const char *uri_server, *uri_path, *uri_query;
85 char *qp_name, *qp_value;
86 GError *gerror = NULL;
87
88 if (!uri) {
89 error_setg(errp, "Invalid URI specified");
90 return -EINVAL;
91 }
92 if (!g_str_equal(g_uri_get_scheme(uri), "nfs")) {
93 error_setg(errp, "URI scheme must be 'nfs'");
94 return -EINVAL;
95 }
96
97 uri_server = g_uri_get_host(uri);
98 if (!uri_server || !uri_server[0]) {
99 error_setg(errp, "missing hostname in URI");
100 return -EINVAL;
101 }
102
103 uri_path = g_uri_get_path(uri);
104 if (!uri_path || !uri_path[0]) {
105 error_setg(errp, "missing file path in URI");
106 return -EINVAL;
107 }
108
109 qdict_put_str(options, "server.host", uri_server);
110 qdict_put_str(options, "server.type", "inet");
111 qdict_put_str(options, "path", uri_path);
112
113 uri_query = g_uri_get_query(uri);
114 if (uri_query) {
115 g_uri_params_iter_init(&qp, uri_query, -1, "&", G_URI_PARAMS_NONE);
116 while (g_uri_params_iter_next(&qp, &qp_name, &qp_value, &gerror)) {
117 uint64_t val;
118 if (!qp_name || gerror) {
119 error_setg(errp, "Failed to parse NFS parameter");
120 return -EINVAL;
121 }
122 if (!qp_value) {
123 error_setg(errp, "Value for NFS parameter expected: %s",
124 qp_name);
125 return -EINVAL;
126 }
127 if (parse_uint_full(qp_value, 0, &val)) {
128 error_setg(errp, "Invalid value for NFS parameter: %s",
129 qp_name);
130 return -EINVAL;
131 }
132 if (g_str_equal(qp_name, "uid")) {
133 qdict_put_str(options, "user", qp_value);
134 } else if (g_str_equal(qp_name, "gid")) {
135 qdict_put_str(options, "group", qp_value);
136 } else if (g_str_equal(qp_name, "tcp-syncnt")) {
137 qdict_put_str(options, "tcp-syn-count", qp_value);
138 } else if (g_str_equal(qp_name, "readahead")) {
139 qdict_put_str(options, "readahead-size", qp_value);
140 } else if (g_str_equal(qp_name, "pagecache")) {
141 qdict_put_str(options, "page-cache-size", qp_value);
142 } else if (g_str_equal(qp_name, "debug")) {
143 qdict_put_str(options, "debug", qp_value);
144 } else {
145 error_setg(errp, "Unknown NFS parameter name: %s", qp_name);
146 return -EINVAL;
147 }
148 }
149 }
150
151 return 0;
152 }
153
154 static bool nfs_has_filename_options_conflict(QDict *options, Error **errp)
155 {
156 const QDictEntry *qe;
157
158 for (qe = qdict_first(options); qe; qe = qdict_next(options, qe)) {
159 if (!strcmp(qe->key, "host") ||
160 !strcmp(qe->key, "path") ||
161 !strcmp(qe->key, "user") ||
162 !strcmp(qe->key, "group") ||
163 !strcmp(qe->key, "tcp-syn-count") ||
164 !strcmp(qe->key, "readahead-size") ||
165 !strcmp(qe->key, "page-cache-size") ||
166 !strcmp(qe->key, "debug") ||
167 strstart(qe->key, "server.", NULL))
168 {
169 error_setg(errp, "Option %s cannot be used with a filename",
170 qe->key);
171 return true;
172 }
173 }
174
175 return false;
176 }
177
178 static void nfs_parse_filename(const char *filename, QDict *options,
179 Error **errp)
180 {
181 if (nfs_has_filename_options_conflict(options, errp)) {
182 return;
183 }
184
185 nfs_parse_uri(filename, options, errp);
186 }
187
188 static void nfs_process_read(void *arg);
189 static void nfs_process_write(void *arg);
190
191 /* Called with QemuMutex held. */
192 static void nfs_set_events(NFSClient *client)
193 {
194 int ev = nfs_which_events(client->context);
195 if (ev != client->events) {
196 aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
197 (ev & POLLIN) ? nfs_process_read : NULL,
198 (ev & POLLOUT) ? nfs_process_write : NULL,
199 NULL, NULL, client);
200
201 }
202 client->events = ev;
203 }
204
205 static void nfs_process_read(void *arg)
206 {
207 NFSClient *client = arg;
208
209 qemu_mutex_lock(&client->mutex);
210 nfs_service(client->context, POLLIN);
211 nfs_set_events(client);
212 qemu_mutex_unlock(&client->mutex);
213 }
214
215 static void nfs_process_write(void *arg)
216 {
217 NFSClient *client = arg;
218
219 qemu_mutex_lock(&client->mutex);
220 nfs_service(client->context, POLLOUT);
221 nfs_set_events(client);
222 qemu_mutex_unlock(&client->mutex);
223 }
224
225 static void coroutine_fn nfs_co_init_task(BlockDriverState *bs, NFSRPC *task)
226 {
227 *task = (NFSRPC) {
228 .co = qemu_coroutine_self(),
229 .bs = bs,
230 .client = bs->opaque,
231 };
232 }
233
234 /* Called (via nfs_service) with QemuMutex held. */
235 static void
236 nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
237 void *private_data)
238 {
239 NFSRPC *task = private_data;
240 task->ret = ret;
241 assert(!task->st);
242 #ifndef LIBNFS_API_V2
243 if (task->ret > 0 && task->iov) {
244 if (task->ret <= task->iov->size) {
245 qemu_iovec_from_buf(task->iov, 0, data, task->ret);
246 } else {
247 task->ret = -EIO;
248 }
249 }
250 #endif
251 if (task->ret < 0) {
252 error_report("NFS Error: %s", nfs_get_error(nfs));
253 }
254
255 /*
256 * Using aio_co_wake() here could re-enter the coroutine directly, while we
257 * still hold the mutex. The current request will not attempt to re-take
258 * the mutex, so that is fine; but if the same coroutine then goes on to
259 * submit another request, that new request will try to re-take the mutex,
260 * resulting in a deadlock.
261 * To prevent that, only schedule the coroutine so it will be entered later,
262 * with the mutex released.
263 */
264 aio_co_schedule(qemu_coroutine_get_aio_context(task->co), task->co);
265 }
266
267 static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, int64_t offset,
268 int64_t bytes, QEMUIOVector *iov,
269 BdrvRequestFlags flags)
270 {
271 NFSClient *client = bs->opaque;
272 NFSRPC task;
273 char *buf = NULL;
274 bool my_buffer = false;
275
276 nfs_co_init_task(bs, &task);
277
278 #ifdef LIBNFS_API_V2
279 if (iov->niov != 1) {
280 buf = g_try_malloc(bytes);
281 if (bytes && buf == NULL) {
282 return -ENOMEM;
283 }
284 my_buffer = true;
285 } else {
286 buf = iov->iov[0].iov_base;
287 }
288 #endif
289
290 WITH_QEMU_LOCK_GUARD(&client->mutex) {
291 #ifdef LIBNFS_API_V2
292 if (nfs_pread_async(client->context, client->fh,
293 buf, bytes, offset,
294 nfs_co_generic_cb, &task) != 0) {
295 #else
296 task.iov = iov;
297 if (nfs_pread_async(client->context, client->fh,
298 offset, bytes, nfs_co_generic_cb, &task) != 0) {
299 #endif
300 if (my_buffer) {
301 g_free(buf);
302 }
303 return -ENOMEM;
304 }
305
306 nfs_set_events(client);
307 }
308 qemu_coroutine_yield();
309
310 if (my_buffer) {
311 if (task.ret > 0) {
312 qemu_iovec_from_buf(iov, 0, buf, task.ret);
313 }
314 g_free(buf);
315 }
316
317 if (task.ret < 0) {
318 return task.ret;
319 }
320
321 /* zero pad short reads */
322 if (task.ret < iov->size) {
323 qemu_iovec_memset(iov, task.ret, 0, iov->size - task.ret);
324 }
325
326 return 0;
327 }
328
329 static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, int64_t offset,
330 int64_t bytes, QEMUIOVector *iov,
331 BdrvRequestFlags flags)
332 {
333 NFSClient *client = bs->opaque;
334 NFSRPC task;
335 char *buf = NULL;
336 bool my_buffer = false;
337
338 nfs_co_init_task(bs, &task);
339
340 if (iov->niov != 1) {
341 buf = g_try_malloc(bytes);
342 if (bytes && buf == NULL) {
343 return -ENOMEM;
344 }
345 qemu_iovec_to_buf(iov, 0, buf, bytes);
346 my_buffer = true;
347 } else {
348 buf = iov->iov[0].iov_base;
349 }
350
351 WITH_QEMU_LOCK_GUARD(&client->mutex) {
352 #ifdef LIBNFS_API_V2
353 if (nfs_pwrite_async(client->context, client->fh,
354 buf, bytes, offset,
355 nfs_co_generic_cb, &task) != 0) {
356 #else
357 if (nfs_pwrite_async(client->context, client->fh,
358 offset, bytes, buf,
359 nfs_co_generic_cb, &task) != 0) {
360 #endif
361 if (my_buffer) {
362 g_free(buf);
363 }
364 return -ENOMEM;
365 }
366
367 nfs_set_events(client);
368 }
369 qemu_coroutine_yield();
370
371 if (my_buffer) {
372 g_free(buf);
373 }
374
375 if (task.ret != bytes) {
376 return task.ret < 0 ? task.ret : -EIO;
377 }
378
379 return 0;
380 }
381
382 static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
383 {
384 NFSClient *client = bs->opaque;
385 NFSRPC task;
386
387 nfs_co_init_task(bs, &task);
388
389 WITH_QEMU_LOCK_GUARD(&client->mutex) {
390 if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
391 &task) != 0) {
392 return -ENOMEM;
393 }
394
395 nfs_set_events(client);
396 }
397 qemu_coroutine_yield();
398
399 return task.ret;
400 }
401
402 static void nfs_detach_aio_context(BlockDriverState *bs)
403 {
404 NFSClient *client = bs->opaque;
405
406 aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
407 NULL, NULL, NULL, NULL, NULL);
408 client->events = 0;
409 }
410
411 static void nfs_attach_aio_context(BlockDriverState *bs,
412 AioContext *new_context)
413 {
414 NFSClient *client = bs->opaque;
415
416 client->aio_context = new_context;
417 nfs_set_events(client);
418 }
419
420 static void nfs_client_close(NFSClient *client)
421 {
422 if (client->context) {
423 qemu_mutex_lock(&client->mutex);
424 aio_set_fd_handler(client->aio_context, nfs_get_fd(client->context),
425 NULL, NULL, NULL, NULL, NULL);
426 qemu_mutex_unlock(&client->mutex);
427 if (client->fh) {
428 nfs_close(client->context, client->fh);
429 client->fh = NULL;
430 }
431 #ifdef LIBNFS_FEATURE_UMOUNT
432 nfs_umount(client->context);
433 #endif
434 nfs_destroy_context(client->context);
435 client->context = NULL;
436 }
437 g_free(client->path);
438 qemu_mutex_destroy(&client->mutex);
439 qapi_free_NFSServer(client->server);
440 client->server = NULL;
441 }
442
443 static void nfs_file_close(BlockDriverState *bs)
444 {
445 NFSClient *client = bs->opaque;
446 nfs_client_close(client);
447 }
448
449 static int64_t nfs_client_open(NFSClient *client, BlockdevOptionsNfs *opts,
450 int flags, int open_flags, Error **errp)
451 {
452 int64_t ret = -EINVAL;
453 #ifdef _WIN32
454 struct __stat64 st;
455 #else
456 struct stat st;
457 #endif
458 char *file = NULL, *strp = NULL;
459
460 qemu_mutex_init(&client->mutex);
461
462 client->path = g_strdup(opts->path);
463
464 strp = strrchr(client->path, '/');
465 if (strp == NULL) {
466 error_setg(errp, "Invalid URL specified");
467 goto fail;
468 }
469 file = g_strdup(strp);
470 *strp = 0;
471
472 /* Steal the NFSServer object from opts; set the original pointer to NULL
473 * to avoid use after free and double free. */
474 client->server = opts->server;
475 opts->server = NULL;
476
477 client->context = nfs_init_context();
478 if (client->context == NULL) {
479 error_setg(errp, "Failed to init NFS context");
480 goto fail;
481 }
482
483 if (opts->has_user) {
484 client->uid = opts->user;
485 nfs_set_uid(client->context, client->uid);
486 }
487
488 if (opts->has_group) {
489 client->gid = opts->group;
490 nfs_set_gid(client->context, client->gid);
491 }
492
493 if (opts->has_tcp_syn_count) {
494 client->tcp_syncnt = opts->tcp_syn_count;
495 nfs_set_tcp_syncnt(client->context, client->tcp_syncnt);
496 }
497
498 #ifdef LIBNFS_FEATURE_READAHEAD
499 if (opts->has_readahead_size) {
500 if (open_flags & BDRV_O_NOCACHE) {
501 error_setg(errp, "Cannot enable NFS readahead "
502 "if cache.direct = on");
503 goto fail;
504 }
505 client->readahead = opts->readahead_size;
506 if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {
507 warn_report("Truncating NFS readahead size to %d",
508 QEMU_NFS_MAX_READAHEAD_SIZE);
509 client->readahead = QEMU_NFS_MAX_READAHEAD_SIZE;
510 }
511 nfs_set_readahead(client->context, client->readahead);
512 #ifdef LIBNFS_FEATURE_PAGECACHE
513 nfs_set_pagecache_ttl(client->context, 0);
514 #endif
515 client->cache_used = true;
516 }
517 #endif
518
519 #ifdef LIBNFS_FEATURE_PAGECACHE
520 if (opts->has_page_cache_size) {
521 if (open_flags & BDRV_O_NOCACHE) {
522 error_setg(errp, "Cannot enable NFS pagecache "
523 "if cache.direct = on");
524 goto fail;
525 }
526 client->pagecache = opts->page_cache_size;
527 if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {
528 warn_report("Truncating NFS pagecache size to %d pages",
529 QEMU_NFS_MAX_PAGECACHE_SIZE);
530 client->pagecache = QEMU_NFS_MAX_PAGECACHE_SIZE;
531 }
532 nfs_set_pagecache(client->context, client->pagecache);
533 nfs_set_pagecache_ttl(client->context, 0);
534 client->cache_used = true;
535 }
536 #endif
537
538 #ifdef LIBNFS_FEATURE_DEBUG
539 if (opts->has_debug) {
540 client->debug = opts->debug;
541 /* limit the maximum debug level to avoid potential flooding
542 * of our log files. */
543 if (client->debug > QEMU_NFS_MAX_DEBUG_LEVEL) {
544 warn_report("Limiting NFS debug level to %d",
545 QEMU_NFS_MAX_DEBUG_LEVEL);
546 client->debug = QEMU_NFS_MAX_DEBUG_LEVEL;
547 }
548 nfs_set_debug(client->context, client->debug);
549 }
550 #endif
551
552 ret = nfs_mount(client->context, client->server->host, client->path);
553 if (ret < 0) {
554 error_setg(errp, "Failed to mount nfs share: %s",
555 nfs_get_error(client->context));
556 goto fail;
557 }
558
559 if (flags & O_CREAT) {
560 ret = nfs_creat(client->context, file, 0600, &client->fh);
561 if (ret < 0) {
562 error_setg(errp, "Failed to create file: %s",
563 nfs_get_error(client->context));
564 goto fail;
565 }
566 } else {
567 ret = nfs_open(client->context, file, flags, &client->fh);
568 if (ret < 0) {
569 error_setg(errp, "Failed to open file : %s",
570 nfs_get_error(client->context));
571 goto fail;
572 }
573 }
574
575 ret = nfs_fstat(client->context, client->fh, &st);
576 if (ret < 0) {
577 error_setg(errp, "Failed to fstat file: %s",
578 nfs_get_error(client->context));
579 goto fail;
580 }
581
582 ret = DIV_ROUND_UP(st.st_size, BDRV_SECTOR_SIZE);
583 #if !defined(_WIN32)
584 client->st_blocks = st.st_blocks;
585 #endif
586 client->has_zero_init = S_ISREG(st.st_mode);
587 *strp = '/';
588 goto out;
589
590 fail:
591 nfs_client_close(client);
592 out:
593 g_free(file);
594 return ret;
595 }
596
597 static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
598 Error **errp)
599 {
600 BlockdevOptionsNfs *opts = NULL;
601 Visitor *v;
602 const QDictEntry *e;
603
604 v = qobject_input_visitor_new_flat_confused(options, errp);
605 if (!v) {
606 return NULL;
607 }
608
609 visit_type_BlockdevOptionsNfs(v, NULL, &opts, errp);
610 visit_free(v);
611 if (!opts) {
612 return NULL;
613 }
614
615 /* Remove the processed options from the QDict (the visitor processes
616 * _all_ options in the QDict) */
617 while ((e = qdict_first(options))) {
618 qdict_del(options, e->key);
619 }
620
621 return opts;
622 }
623
624 static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
625 int flags, int open_flags, Error **errp)
626 {
627 BlockdevOptionsNfs *opts;
628 int64_t ret;
629
630 opts = nfs_options_qdict_to_qapi(options, errp);
631 if (opts == NULL) {
632 ret = -EINVAL;
633 goto fail;
634 }
635
636 ret = nfs_client_open(client, opts, flags, open_flags, errp);
637 fail:
638 qapi_free_BlockdevOptionsNfs(opts);
639 return ret;
640 }
641
642 static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
643 Error **errp) {
644 NFSClient *client = bs->opaque;
645 int64_t ret;
646
647 client->aio_context = bdrv_get_aio_context(bs);
648
649 ret = nfs_client_open_qdict(client, options,
650 (flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
651 bs->open_flags, errp);
652 if (ret < 0) {
653 return ret;
654 }
655
656 bs->total_sectors = ret;
657 if (client->has_zero_init) {
658 bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
659 }
660 return 0;
661 }
662
663 static QemuOptsList nfs_create_opts = {
664 .name = "nfs-create-opts",
665 .head = QTAILQ_HEAD_INITIALIZER(nfs_create_opts.head),
666 .desc = {
667 {
668 .name = BLOCK_OPT_SIZE,
669 .type = QEMU_OPT_SIZE,
670 .help = "Virtual disk size"
671 },
672 { /* end of list */ }
673 }
674 };
675
676 static int nfs_file_co_create(BlockdevCreateOptions *options, Error **errp)
677 {
678 BlockdevCreateOptionsNfs *opts = &options->u.nfs;
679 NFSClient *client = g_new0(NFSClient, 1);
680 int ret;
681
682 assert(options->driver == BLOCKDEV_DRIVER_NFS);
683
684 client->aio_context = qemu_get_aio_context();
685
686 ret = nfs_client_open(client, opts->location, O_CREAT, 0, errp);
687 if (ret < 0) {
688 goto out;
689 }
690 ret = nfs_ftruncate(client->context, client->fh, opts->size);
691 nfs_client_close(client);
692
693 out:
694 g_free(client);
695 return ret;
696 }
697
698 static int coroutine_fn nfs_file_co_create_opts(BlockDriver *drv,
699 const char *url,
700 QemuOpts *opts,
701 Error **errp)
702 {
703 BlockdevCreateOptions *create_options;
704 BlockdevCreateOptionsNfs *nfs_opts;
705 QDict *options;
706 int ret;
707
708 create_options = g_new0(BlockdevCreateOptions, 1);
709 create_options->driver = BLOCKDEV_DRIVER_NFS;
710 nfs_opts = &create_options->u.nfs;
711
712 /* Read out options */
713 nfs_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
714 BDRV_SECTOR_SIZE);
715
716 options = qdict_new();
717 ret = nfs_parse_uri(url, options, errp);
718 if (ret < 0) {
719 goto out;
720 }
721
722 nfs_opts->location = nfs_options_qdict_to_qapi(options, errp);
723 if (nfs_opts->location == NULL) {
724 ret = -EINVAL;
725 goto out;
726 }
727
728 ret = nfs_file_co_create(create_options, errp);
729 if (ret < 0) {
730 goto out;
731 }
732
733 ret = 0;
734 out:
735 qobject_unref(options);
736 qapi_free_BlockdevCreateOptions(create_options);
737 return ret;
738 }
739
740 static int nfs_has_zero_init(BlockDriverState *bs)
741 {
742 NFSClient *client = bs->opaque;
743 return client->has_zero_init;
744 }
745
746 #if !defined(_WIN32)
747 /* Called (via nfs_service) with QemuMutex held. */
748 static void
749 nfs_get_allocated_file_size_cb(int ret, struct nfs_context *nfs, void *data,
750 void *private_data)
751 {
752 NFSRPC *task = private_data;
753 task->ret = ret;
754 if (task->ret == 0) {
755 memcpy(task->st, data, sizeof(struct stat));
756 }
757 if (task->ret < 0) {
758 error_report("NFS Error: %s", nfs_get_error(nfs));
759 }
760 /* Must not use aio_co_wake(), see nfs_co_generic_cb() */
761 aio_co_schedule(qemu_coroutine_get_aio_context(task->co), task->co);
762 }
763
764 static int64_t coroutine_fn nfs_co_get_allocated_file_size(BlockDriverState *bs)
765 {
766 NFSClient *client = bs->opaque;
767 NFSRPC task = {0};
768 struct stat st;
769
770 if (bdrv_is_read_only(bs) &&
771 !(bs->open_flags & BDRV_O_NOCACHE)) {
772 return client->st_blocks * 512;
773 }
774
775 nfs_co_init_task(bs, &task);
776 task.st = &st;
777 WITH_QEMU_LOCK_GUARD(&client->mutex) {
778 if (nfs_fstat_async(client->context, client->fh, nfs_get_allocated_file_size_cb,
779 &task) != 0) {
780 return -ENOMEM;
781 }
782
783 nfs_set_events(client);
784 }
785 qemu_coroutine_yield();
786
787 return (task.ret < 0 ? task.ret : st.st_blocks * 512);
788 }
789 #endif
790
791 static int coroutine_fn
792 nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
793 PreallocMode prealloc, BdrvRequestFlags flags,
794 Error **errp)
795 {
796 NFSClient *client = bs->opaque;
797 int ret;
798
799 if (prealloc != PREALLOC_MODE_OFF) {
800 error_setg(errp, "Unsupported preallocation mode '%s'",
801 PreallocMode_str(prealloc));
802 return -ENOTSUP;
803 }
804
805 ret = nfs_ftruncate(client->context, client->fh, offset);
806 if (ret < 0) {
807 error_setg_errno(errp, -ret, "Failed to truncate file");
808 return ret;
809 }
810
811 return 0;
812 }
813
814 /* Note that this will not re-establish a connection with the NFS server
815 * - it is effectively a NOP. */
816 static int nfs_reopen_prepare(BDRVReopenState *state,
817 BlockReopenQueue *queue, Error **errp)
818 {
819 NFSClient *client = state->bs->opaque;
820 #ifdef _WIN32
821 struct __stat64 st;
822 #else
823 struct stat st;
824 #endif
825 int ret = 0;
826
827 if (state->flags & BDRV_O_RDWR && bdrv_is_read_only(state->bs)) {
828 error_setg(errp, "Cannot open a read-only mount as read-write");
829 return -EACCES;
830 }
831
832 if ((state->flags & BDRV_O_NOCACHE) && client->cache_used) {
833 error_setg(errp, "Cannot disable cache if libnfs readahead or"
834 " pagecache is enabled");
835 return -EINVAL;
836 }
837
838 /* Update cache for read-only reopens */
839 if (!(state->flags & BDRV_O_RDWR)) {
840 ret = nfs_fstat(client->context, client->fh, &st);
841 if (ret < 0) {
842 error_setg(errp, "Failed to fstat file: %s",
843 nfs_get_error(client->context));
844 return ret;
845 }
846 #if !defined(_WIN32)
847 client->st_blocks = st.st_blocks;
848 #endif
849 }
850
851 return 0;
852 }
853
854 static void nfs_refresh_filename(BlockDriverState *bs)
855 {
856 NFSClient *client = bs->opaque;
857
858 if (client->uid && !client->gid) {
859 snprintf(bs->exact_filename, sizeof(bs->exact_filename),
860 "nfs://%s%s?uid=%" PRId64, client->server->host, client->path,
861 client->uid);
862 } else if (!client->uid && client->gid) {
863 snprintf(bs->exact_filename, sizeof(bs->exact_filename),
864 "nfs://%s%s?gid=%" PRId64, client->server->host, client->path,
865 client->gid);
866 } else if (client->uid && client->gid) {
867 snprintf(bs->exact_filename, sizeof(bs->exact_filename),
868 "nfs://%s%s?uid=%" PRId64 "&gid=%" PRId64,
869 client->server->host, client->path, client->uid, client->gid);
870 } else {
871 snprintf(bs->exact_filename, sizeof(bs->exact_filename),
872 "nfs://%s%s", client->server->host, client->path);
873 }
874 }
875
876 static char * GRAPH_RDLOCK nfs_dirname(BlockDriverState *bs, Error **errp)
877 {
878 NFSClient *client = bs->opaque;
879
880 if (client->uid || client->gid) {
881 bdrv_refresh_filename(bs);
882 error_setg(errp, "Cannot generate a base directory for NFS node '%s'",
883 bs->filename);
884 return NULL;
885 }
886
887 return g_strdup_printf("nfs://%s%s/", client->server->host, client->path);
888 }
889
890 #ifdef LIBNFS_FEATURE_PAGECACHE
891 static void coroutine_fn nfs_co_invalidate_cache(BlockDriverState *bs,
892 Error **errp)
893 {
894 NFSClient *client = bs->opaque;
895 nfs_pagecache_invalidate(client->context, client->fh);
896 }
897 #endif
898
899 static void nfs_refresh_limits(BlockDriverState *bs, Error **errp)
900 {
901 NFSClient *client = bs->opaque;
902 bs->bl.max_transfer = MIN((uint32_t)nfs_get_readmax(client->context),
903 (uint32_t)nfs_get_writemax(client->context));
904 }
905
906 static const char *nfs_strong_runtime_opts[] = {
907 "path",
908 "user",
909 "group",
910 "server.",
911
912 NULL
913 };
914
915 static BlockDriver bdrv_nfs = {
916 .format_name = "nfs",
917 .protocol_name = "nfs",
918
919 .instance_size = sizeof(NFSClient),
920 .bdrv_parse_filename = nfs_parse_filename,
921 .create_opts = &nfs_create_opts,
922
923 .bdrv_has_zero_init = nfs_has_zero_init,
924 /* libnfs does not provide the allocated filesize of a file on win32. */
925 #if !defined(_WIN32)
926 .bdrv_co_get_allocated_file_size = nfs_co_get_allocated_file_size,
927 #endif
928 .bdrv_co_truncate = nfs_file_co_truncate,
929
930 .bdrv_open = nfs_file_open,
931 .bdrv_close = nfs_file_close,
932 .bdrv_co_create = nfs_file_co_create,
933 .bdrv_co_create_opts = nfs_file_co_create_opts,
934 .bdrv_reopen_prepare = nfs_reopen_prepare,
935
936 .bdrv_co_preadv = nfs_co_preadv,
937 .bdrv_co_pwritev = nfs_co_pwritev,
938 .bdrv_co_flush_to_disk = nfs_co_flush,
939
940 .bdrv_detach_aio_context = nfs_detach_aio_context,
941 .bdrv_attach_aio_context = nfs_attach_aio_context,
942 .bdrv_refresh_filename = nfs_refresh_filename,
943 .bdrv_refresh_limits = nfs_refresh_limits,
944 .bdrv_dirname = nfs_dirname,
945
946 .strong_runtime_opts = nfs_strong_runtime_opts,
947
948 #ifdef LIBNFS_FEATURE_PAGECACHE
949 .bdrv_co_invalidate_cache = nfs_co_invalidate_cache,
950 #endif
951 };
952
953 static void nfs_block_init(void)
954 {
955 bdrv_register(&bdrv_nfs);
956 }
957
958 block_init(nfs_block_init);