int events;
bool has_zero_init;
AioContext *aio_context;
+ QemuMutex mutex;
blkcnt_t st_blocks;
bool cache_used;
NFSServer *server;
qdict_put(options, "path", qstring_from_str(uri->path));
for (i = 0; i < qp->n; i++) {
+ unsigned long long val;
if (!qp->p[i].value) {
error_setg(errp, "Value for NFS parameter expected: %s",
qp->p[i].name);
goto out;
}
- if (parse_uint_full(qp->p[i].value, NULL, 0)) {
+ if (parse_uint_full(qp->p[i].value, &val, 0)) {
error_setg(errp, "Illegal value for NFS parameter: %s",
qp->p[i].name);
goto out;
static void nfs_process_read(void *arg);
static void nfs_process_write(void *arg);
+/* Called with QemuMutex held. */
static void nfs_set_events(NFSClient *client)
{
int ev = nfs_which_events(client->context);
static void nfs_process_read(void *arg)
{
NFSClient *client = arg;
+
+ qemu_mutex_lock(&client->mutex);
nfs_service(client->context, POLLIN);
nfs_set_events(client);
+ qemu_mutex_unlock(&client->mutex);
}
static void nfs_process_write(void *arg)
{
NFSClient *client = arg;
+
+ qemu_mutex_lock(&client->mutex);
nfs_service(client->context, POLLOUT);
nfs_set_events(client);
+ qemu_mutex_unlock(&client->mutex);
}
static void nfs_co_init_task(BlockDriverState *bs, NFSRPC *task)
static void nfs_co_generic_bh_cb(void *opaque)
{
NFSRPC *task = opaque;
+
task->complete = 1;
- qemu_coroutine_enter(task->co);
+ aio_co_wake(task->co);
}
+/* Called (via nfs_service) with QemuMutex held. */
static void
nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
void *private_data)
nfs_co_generic_bh_cb, task);
}
-static int coroutine_fn nfs_co_readv(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors,
- QEMUIOVector *iov)
+static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,
+ uint64_t bytes, QEMUIOVector *iov,
+ int flags)
{
NFSClient *client = bs->opaque;
NFSRPC task;
nfs_co_init_task(bs, &task);
task.iov = iov;
+ qemu_mutex_lock(&client->mutex);
if (nfs_pread_async(client->context, client->fh,
- sector_num * BDRV_SECTOR_SIZE,
- nb_sectors * BDRV_SECTOR_SIZE,
- nfs_co_generic_cb, &task) != 0) {
+ offset, bytes, nfs_co_generic_cb, &task) != 0) {
+ qemu_mutex_unlock(&client->mutex);
return -ENOMEM;
}
nfs_set_events(client);
+ qemu_mutex_unlock(&client->mutex);
while (!task.complete) {
qemu_coroutine_yield();
}
return 0;
}
-static int coroutine_fn nfs_co_writev(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors,
- QEMUIOVector *iov)
+static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, uint64_t offset,
+ uint64_t bytes, QEMUIOVector *iov,
+ int flags)
{
NFSClient *client = bs->opaque;
NFSRPC task;
char *buf = NULL;
+ bool my_buffer = false;
nfs_co_init_task(bs, &task);
- buf = g_try_malloc(nb_sectors * BDRV_SECTOR_SIZE);
- if (nb_sectors && buf == NULL) {
- return -ENOMEM;
+ if (iov->niov != 1) {
+ buf = g_try_malloc(bytes);
+ if (bytes && buf == NULL) {
+ return -ENOMEM;
+ }
+ qemu_iovec_to_buf(iov, 0, buf, bytes);
+ my_buffer = true;
+ } else {
+ buf = iov->iov[0].iov_base;
}
- qemu_iovec_to_buf(iov, 0, buf, nb_sectors * BDRV_SECTOR_SIZE);
-
+ qemu_mutex_lock(&client->mutex);
if (nfs_pwrite_async(client->context, client->fh,
- sector_num * BDRV_SECTOR_SIZE,
- nb_sectors * BDRV_SECTOR_SIZE,
- buf, nfs_co_generic_cb, &task) != 0) {
- g_free(buf);
+ offset, bytes, buf,
+ nfs_co_generic_cb, &task) != 0) {
+ qemu_mutex_unlock(&client->mutex);
+ if (my_buffer) {
+ g_free(buf);
+ }
return -ENOMEM;
}
nfs_set_events(client);
+ qemu_mutex_unlock(&client->mutex);
while (!task.complete) {
qemu_coroutine_yield();
}
- g_free(buf);
+ if (my_buffer) {
+ g_free(buf);
+ }
- if (task.ret != nb_sectors * BDRV_SECTOR_SIZE) {
+ if (task.ret != bytes) {
return task.ret < 0 ? task.ret : -EIO;
}
nfs_co_init_task(bs, &task);
+ qemu_mutex_lock(&client->mutex);
if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
&task) != 0) {
+ qemu_mutex_unlock(&client->mutex);
return -ENOMEM;
}
nfs_set_events(client);
+ qemu_mutex_unlock(&client->mutex);
while (!task.complete) {
qemu_coroutine_yield();
}
.help = "Path of the image on the host",
},
{
- .name = "uid",
+ .name = "user",
.type = QEMU_OPT_NUMBER,
.help = "UID value to use when talking to the server",
},
{
- .name = "gid",
+ .name = "group",
.type = QEMU_OPT_NUMBER,
.help = "GID value to use when talking to the server",
},
{
- .name = "tcp-syncnt",
+ .name = "tcp-syn-count",
.type = QEMU_OPT_NUMBER,
.help = "Number of SYNs to send during the session establish",
},
{
- .name = "readahead",
+ .name = "readahead-size",
.type = QEMU_OPT_NUMBER,
.help = "Set the readahead size in bytes",
},
{
- .name = "pagecache",
+ .name = "page-cache-size",
.type = QEMU_OPT_NUMBER,
.help = "Set the pagecache size in bytes",
},
{
NFSClient *client = bs->opaque;
nfs_client_close(client);
+ qemu_mutex_destroy(&client->mutex);
}
static NFSServer *nfs_config(QDict *options, Error **errp)
goto out;
}
- iv = qobject_input_visitor_new(crumpled_addr, true);
+ iv = qobject_input_visitor_new(crumpled_addr);
visit_type_NFSServer(iv, NULL, &server, &local_error);
if (local_error) {
error_propagate(errp, local_error);
goto fail;
}
- if (qemu_opt_get(opts, "uid")) {
- client->uid = qemu_opt_get_number(opts, "uid", 0);
+ if (qemu_opt_get(opts, "user")) {
+ client->uid = qemu_opt_get_number(opts, "user", 0);
nfs_set_uid(client->context, client->uid);
}
- if (qemu_opt_get(opts, "gid")) {
- client->gid = qemu_opt_get_number(opts, "gid", 0);
+ if (qemu_opt_get(opts, "group")) {
+ client->gid = qemu_opt_get_number(opts, "group", 0);
nfs_set_gid(client->context, client->gid);
}
- if (qemu_opt_get(opts, "tcp-syncnt")) {
- client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syncnt", 0);
+ if (qemu_opt_get(opts, "tcp-syn-count")) {
+ client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syn-count", 0);
nfs_set_tcp_syncnt(client->context, client->tcp_syncnt);
}
#ifdef LIBNFS_FEATURE_READAHEAD
- if (qemu_opt_get(opts, "readahead")) {
+ if (qemu_opt_get(opts, "readahead-size")) {
if (open_flags & BDRV_O_NOCACHE) {
error_setg(errp, "Cannot enable NFS readahead "
"if cache.direct = on");
goto fail;
}
- client->readahead = qemu_opt_get_number(opts, "readahead", 0);
+ client->readahead = qemu_opt_get_number(opts, "readahead-size", 0);
if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {
error_report("NFS Warning: Truncating NFS readahead "
"size to %d", QEMU_NFS_MAX_READAHEAD_SIZE);
#endif
#ifdef LIBNFS_FEATURE_PAGECACHE
- if (qemu_opt_get(opts, "pagecache")) {
+ if (qemu_opt_get(opts, "page-cache-size")) {
if (open_flags & BDRV_O_NOCACHE) {
error_setg(errp, "Cannot enable NFS pagecache "
"if cache.direct = on");
goto fail;
}
- client->pagecache = qemu_opt_get_number(opts, "pagecache", 0);
+ client->pagecache = qemu_opt_get_number(opts, "page-cache-size", 0);
if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {
error_report("NFS Warning: Truncating NFS pagecache "
"size to %d pages", QEMU_NFS_MAX_PAGECACHE_SIZE);
if (ret < 0) {
return ret;
}
+ qemu_mutex_init(&client->mutex);
bs->total_sectors = ret;
ret = 0;
return ret;
return client->has_zero_init;
}
+/* Called (via nfs_service) with QemuMutex held. */
static void
nfs_get_allocated_file_size_cb(int ret, struct nfs_context *nfs, void *data,
void *private_data)
ov = qobject_output_visitor_new(&server_qdict);
visit_type_NFSServer(ov, NULL, &client->server, &error_abort);
visit_complete(ov, &server_qdict);
- assert(qobject_type(server_qdict) == QTYPE_QDICT);
-
qdict_put_obj(opts, "server", server_qdict);
qdict_put(opts, "path", qstring_from_str(client->path));
if (client->uid) {
- qdict_put(opts, "uid", qint_from_int(client->uid));
+ qdict_put(opts, "user", qint_from_int(client->uid));
}
if (client->gid) {
- qdict_put(opts, "gid", qint_from_int(client->gid));
+ qdict_put(opts, "group", qint_from_int(client->gid));
}
if (client->tcp_syncnt) {
- qdict_put(opts, "tcp-syncnt",
- qint_from_int(client->tcp_syncnt));
+ qdict_put(opts, "tcp-syn-cnt",
+ qint_from_int(client->tcp_syncnt));
}
if (client->readahead) {
- qdict_put(opts, "readahead",
- qint_from_int(client->readahead));
+ qdict_put(opts, "readahead-size",
+ qint_from_int(client->readahead));
}
if (client->pagecache) {
- qdict_put(opts, "pagecache",
- qint_from_int(client->pagecache));
+ qdict_put(opts, "page-cache-size",
+ qint_from_int(client->pagecache));
}
if (client->debug) {
qdict_put(opts, "debug", qint_from_int(client->debug));
.bdrv_create = nfs_file_create,
.bdrv_reopen_prepare = nfs_reopen_prepare,
- .bdrv_co_readv = nfs_co_readv,
- .bdrv_co_writev = nfs_co_writev,
+ .bdrv_co_preadv = nfs_co_preadv,
+ .bdrv_co_pwritev = nfs_co_pwritev,
.bdrv_co_flush_to_disk = nfs_co_flush,
.bdrv_detach_aio_context = nfs_detach_aio_context,