Statistics
| Branch: | Revision:

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);