mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 19:49:43 +00:00
Block patches
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJS9ziDAAoJEH8JsnLIjy/WPLUP/3S9OfbaRWcz5beambW+5i/0 9IeK1jdlb2BkxBu2pMr74RtAmd0JcR5tZTzt5iEGWFZMjwMnGAyiiwqNcraQL/01 UMPwZCeQBbBJihfp+jA9Pez5p5ruWcS2P0wWGgszaLb2zwIk8t20elc9ctmE+/hl kB5O2Ig6TKf/C9grO+9c1QkEfPBygLLZwspm8AFI8gvrqOQ7tpN3LqkVjRyNegUI orprqXEZrWzQuKYhERMgcWOZjtUGILhYuzaCTPpVW9YnnCNzgwjMaKdKK+IgVr2s qdnCjWHJavZp9/3iRjTKURwk9gmeJOlbPp+hUu3maeMj4r8bzQK89p6RSAbiXCuI fC10Z/i5qmftlOdZwiIm19tqEfevgnnSYorZq3ALVR4nC4eruPNjpTIJNJ41Le5M SF90umsw86OkOR2KIm3DfXEla85ftUh/54aaVr80b8lfogJpHa0zfurVZwHGXBOx 7wHFa1bcwRg4F8wAY8ptSwMxp97JGJADvQj+PzlK1WLIeeXp7Nh1jlVBg9HW1YVa AlKJAn2+hvUIuF3wbz8rkS2eKKnkjtsqjkQAWlsoAhQ79FiLBJ4SmgWftNgIqCKt Yh5dUY/bC5gM0O0eR+U4oBl/wqj9s/nei0waJ6snvgXkLJBoN3yuP1C3mfLx1o4v /XubiSe7z3+9zPL30GKb =XErB -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-anthony' into staging Block patches # gpg: Signature made Sun 09 Feb 2014 08:12:51 GMT using RSA key ID C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" * remotes/kevin/tags/for-anthony: block: Fix 32 bit truncation in mark_request_serialising() blkdebug: Don't leak bs->file on failure block: Don't call ROUND_UP with negative values block: bdrv_aligned_pwritev: Assert overlap range block: Fix memory leaks in bdrv_co_do_pwritev() raw: Fix BlockLimits passthrough qemu-iotests: add test for qcow2 preallocation with different cluster sizes qcow2: check for NULL l2meta qcow2: fix offset overflow in qcow2_alloc_clusters_at() qcow2: remove n_start and n_end of qcow2_alloc_cluster_offset() block/iscsi: always fill bs->bl.opt_transfer_length block: Fail gracefully with missing filename qemu-iotests: enable support for NFS protocol qemu-iotests: enable test 016 and 025 to work with NFS protocol qemu-iotests: blacklist test 020 for NFS protocol qemu-iotests: change _supported_proto to file for various tests block: add native support for NFS qemu-iotest: Make 077 raw-only Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
628a746cf0
@ -937,6 +937,11 @@ M: Peter Lieven <pl@kamp.de>
|
||||
S: Supported
|
||||
F: block/iscsi.c
|
||||
|
||||
NFS
|
||||
M: Peter Lieven <pl@kamp.de>
|
||||
S: Maintained
|
||||
F: block/nfs.c
|
||||
|
||||
SSH
|
||||
M: Richard W.M. Jones <rjones@redhat.com>
|
||||
S: Supported
|
||||
|
27
block.c
27
block.c
@ -832,6 +832,12 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
||||
filename = qdict_get_try_str(options, "filename");
|
||||
}
|
||||
|
||||
if (drv->bdrv_needs_filename && !filename) {
|
||||
error_setg(errp, "The '%s' block driver requires a file name",
|
||||
drv->format_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name);
|
||||
|
||||
node_name = qdict_get_try_str(options, "node-name");
|
||||
@ -1031,11 +1037,6 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
|
||||
goto fail;
|
||||
}
|
||||
qdict_del(options, "filename");
|
||||
} else if (drv->bdrv_needs_filename && !filename) {
|
||||
error_setg(errp, "The '%s' block driver requires a file name",
|
||||
drv->format_name);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!drv->bdrv_file_open) {
|
||||
@ -2239,11 +2240,11 @@ static void tracked_request_begin(BdrvTrackedRequest *req,
|
||||
QLIST_INSERT_HEAD(&bs->tracked_requests, req, list);
|
||||
}
|
||||
|
||||
static void mark_request_serialising(BdrvTrackedRequest *req, size_t align)
|
||||
static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
|
||||
{
|
||||
int64_t overlap_offset = req->offset & ~(align - 1);
|
||||
int overlap_bytes = ROUND_UP(req->offset + req->bytes, align)
|
||||
- overlap_offset;
|
||||
unsigned int overlap_bytes = ROUND_UP(req->offset + req->bytes, align)
|
||||
- overlap_offset;
|
||||
|
||||
if (!req->serialising) {
|
||||
req->bs->serialising_in_flight++;
|
||||
@ -2914,8 +2915,8 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
total_sectors = DIV_ROUND_UP(len, BDRV_SECTOR_SIZE);
|
||||
max_nb_sectors = MAX(0, ROUND_UP(total_sectors - sector_num,
|
||||
align >> BDRV_SECTOR_BITS));
|
||||
max_nb_sectors = ROUND_UP(MAX(0, total_sectors - sector_num),
|
||||
align >> BDRV_SECTOR_BITS);
|
||||
if (max_nb_sectors > 0) {
|
||||
ret = drv->bdrv_co_readv(bs, sector_num,
|
||||
MIN(nb_sectors, max_nb_sectors), qiov);
|
||||
@ -3133,6 +3134,8 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||
|
||||
waited = wait_serialising_requests(req);
|
||||
assert(!waited || !req->serialising);
|
||||
assert(req->overlap_offset <= offset);
|
||||
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
|
||||
|
||||
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
|
||||
|
||||
@ -3278,9 +3281,9 @@ fail:
|
||||
|
||||
if (use_local_qiov) {
|
||||
qemu_iovec_destroy(&local_qiov);
|
||||
qemu_vfree(head_buf);
|
||||
qemu_vfree(tail_buf);
|
||||
}
|
||||
qemu_vfree(head_buf);
|
||||
qemu_vfree(tail_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
ifeq ($(CONFIG_POSIX),y)
|
||||
block-obj-y += nbd.o nbd-client.o sheepdog.o
|
||||
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
|
||||
block-obj-$(CONFIG_LIBNFS) += nfs.o
|
||||
block-obj-$(CONFIG_CURL) += curl.o
|
||||
block-obj-$(CONFIG_RBD) += rbd.o
|
||||
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
|
||||
|
@ -396,14 +396,14 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Read rules from config file or command line options */
|
||||
config = qemu_opt_get(opts, "config");
|
||||
ret = read_config(s, config, options, errp);
|
||||
if (ret) {
|
||||
goto fail;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set initial state */
|
||||
@ -414,7 +414,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
flags, true, false, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set request alignment */
|
||||
@ -424,11 +424,15 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
} else {
|
||||
error_setg(errp, "Invalid alignment");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
goto fail_unref;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
goto out;
|
||||
|
||||
fail_unref:
|
||||
bdrv_unref(bs->file);
|
||||
out:
|
||||
qemu_opts_del(opts);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1330,10 +1330,9 @@ static int iscsi_refresh_limits(BlockDriverState *bs)
|
||||
}
|
||||
bs->bl.write_zeroes_alignment = sector_lun2qemu(iscsilun->bl.opt_unmap_gran,
|
||||
iscsilun);
|
||||
|
||||
bs->bl.opt_transfer_length = sector_lun2qemu(iscsilun->bl.opt_xfer_len,
|
||||
iscsilun);
|
||||
}
|
||||
bs->bl.opt_transfer_length = sector_lun2qemu(iscsilun->bl.opt_xfer_len,
|
||||
iscsilun);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
439
block/nfs.c
Normal file
439
block/nfs.c
Normal file
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* QEMU Block driver for native access to files on NFS shares
|
||||
*
|
||||
* Copyright (c) 2014 Peter Lieven <pl@kamp.de>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config-host.h"
|
||||
|
||||
#include <poll.h>
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "block/block_int.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qemu/uri.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include <nfsc/libnfs.h>
|
||||
|
||||
typedef struct NFSClient {
|
||||
struct nfs_context *context;
|
||||
struct nfsfh *fh;
|
||||
int events;
|
||||
bool has_zero_init;
|
||||
} NFSClient;
|
||||
|
||||
typedef struct NFSRPC {
|
||||
int ret;
|
||||
int complete;
|
||||
QEMUIOVector *iov;
|
||||
struct stat *st;
|
||||
Coroutine *co;
|
||||
QEMUBH *bh;
|
||||
} NFSRPC;
|
||||
|
||||
static void nfs_process_read(void *arg);
|
||||
static void nfs_process_write(void *arg);
|
||||
|
||||
static void nfs_set_events(NFSClient *client)
|
||||
{
|
||||
int ev = nfs_which_events(client->context);
|
||||
if (ev != client->events) {
|
||||
qemu_aio_set_fd_handler(nfs_get_fd(client->context),
|
||||
(ev & POLLIN) ? nfs_process_read : NULL,
|
||||
(ev & POLLOUT) ? nfs_process_write : NULL,
|
||||
client);
|
||||
|
||||
}
|
||||
client->events = ev;
|
||||
}
|
||||
|
||||
static void nfs_process_read(void *arg)
|
||||
{
|
||||
NFSClient *client = arg;
|
||||
nfs_service(client->context, POLLIN);
|
||||
nfs_set_events(client);
|
||||
}
|
||||
|
||||
static void nfs_process_write(void *arg)
|
||||
{
|
||||
NFSClient *client = arg;
|
||||
nfs_service(client->context, POLLOUT);
|
||||
nfs_set_events(client);
|
||||
}
|
||||
|
||||
static void nfs_co_init_task(NFSClient *client, NFSRPC *task)
|
||||
{
|
||||
*task = (NFSRPC) {
|
||||
.co = qemu_coroutine_self(),
|
||||
};
|
||||
}
|
||||
|
||||
static void nfs_co_generic_bh_cb(void *opaque)
|
||||
{
|
||||
NFSRPC *task = opaque;
|
||||
qemu_bh_delete(task->bh);
|
||||
qemu_coroutine_enter(task->co, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
|
||||
void *private_data)
|
||||
{
|
||||
NFSRPC *task = private_data;
|
||||
task->complete = 1;
|
||||
task->ret = ret;
|
||||
if (task->ret > 0 && task->iov) {
|
||||
if (task->ret <= task->iov->size) {
|
||||
qemu_iovec_from_buf(task->iov, 0, data, task->ret);
|
||||
} else {
|
||||
task->ret = -EIO;
|
||||
}
|
||||
}
|
||||
if (task->ret == 0 && task->st) {
|
||||
memcpy(task->st, data, sizeof(struct stat));
|
||||
}
|
||||
if (task->co) {
|
||||
task->bh = qemu_bh_new(nfs_co_generic_bh_cb, task);
|
||||
qemu_bh_schedule(task->bh);
|
||||
}
|
||||
}
|
||||
|
||||
static int coroutine_fn nfs_co_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
NFSRPC task;
|
||||
|
||||
nfs_co_init_task(client, &task);
|
||||
task.iov = iov;
|
||||
|
||||
if (nfs_pread_async(client->context, client->fh,
|
||||
sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE,
|
||||
nfs_co_generic_cb, &task) != 0) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while (!task.complete) {
|
||||
nfs_set_events(client);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
if (task.ret < 0) {
|
||||
return task.ret;
|
||||
}
|
||||
|
||||
/* zero pad short reads */
|
||||
if (task.ret < iov->size) {
|
||||
qemu_iovec_memset(iov, task.ret, 0, iov->size - task.ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coroutine_fn nfs_co_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
NFSRPC task;
|
||||
char *buf = NULL;
|
||||
|
||||
nfs_co_init_task(client, &task);
|
||||
|
||||
buf = g_malloc(nb_sectors * BDRV_SECTOR_SIZE);
|
||||
qemu_iovec_to_buf(iov, 0, buf, nb_sectors * BDRV_SECTOR_SIZE);
|
||||
|
||||
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);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while (!task.complete) {
|
||||
nfs_set_events(client);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
g_free(buf);
|
||||
|
||||
if (task.ret != nb_sectors * BDRV_SECTOR_SIZE) {
|
||||
return task.ret < 0 ? task.ret : -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
NFSRPC task;
|
||||
|
||||
nfs_co_init_task(client, &task);
|
||||
|
||||
if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
|
||||
&task) != 0) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while (!task.complete) {
|
||||
nfs_set_events(client);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
return task.ret;
|
||||
}
|
||||
|
||||
/* TODO Convert to fine grained options */
|
||||
static QemuOptsList runtime_opts = {
|
||||
.name = "nfs",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "filename",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "URL to the NFS file",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static void nfs_client_close(NFSClient *client)
|
||||
{
|
||||
if (client->context) {
|
||||
if (client->fh) {
|
||||
nfs_close(client->context, client->fh);
|
||||
}
|
||||
qemu_aio_set_fd_handler(nfs_get_fd(client->context), NULL, NULL, NULL);
|
||||
nfs_destroy_context(client->context);
|
||||
}
|
||||
memset(client, 0, sizeof(NFSClient));
|
||||
}
|
||||
|
||||
static void nfs_file_close(BlockDriverState *bs)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
nfs_client_close(client);
|
||||
}
|
||||
|
||||
static int64_t nfs_client_open(NFSClient *client, const char *filename,
|
||||
int flags, Error **errp)
|
||||
{
|
||||
int ret = -EINVAL, i;
|
||||
struct stat st;
|
||||
URI *uri;
|
||||
QueryParams *qp = NULL;
|
||||
char *file = NULL, *strp = NULL;
|
||||
|
||||
uri = uri_parse(filename);
|
||||
if (!uri) {
|
||||
error_setg(errp, "Invalid URL specified");
|
||||
goto fail;
|
||||
}
|
||||
strp = strrchr(uri->path, '/');
|
||||
if (strp == NULL) {
|
||||
error_setg(errp, "Invalid URL specified");
|
||||
goto fail;
|
||||
}
|
||||
file = g_strdup(strp);
|
||||
*strp = 0;
|
||||
|
||||
client->context = nfs_init_context();
|
||||
if (client->context == NULL) {
|
||||
error_setg(errp, "Failed to init NFS context");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
qp = query_params_parse(uri->query);
|
||||
for (i = 0; i < qp->n; i++) {
|
||||
if (!qp->p[i].value) {
|
||||
error_setg(errp, "Value for NFS parameter expected: %s",
|
||||
qp->p[i].name);
|
||||
goto fail;
|
||||
}
|
||||
if (!strncmp(qp->p[i].name, "uid", 3)) {
|
||||
nfs_set_uid(client->context, atoi(qp->p[i].value));
|
||||
} else if (!strncmp(qp->p[i].name, "gid", 3)) {
|
||||
nfs_set_gid(client->context, atoi(qp->p[i].value));
|
||||
} else if (!strncmp(qp->p[i].name, "tcp-syncnt", 10)) {
|
||||
nfs_set_tcp_syncnt(client->context, atoi(qp->p[i].value));
|
||||
} else {
|
||||
error_setg(errp, "Unknown NFS parameter name: %s",
|
||||
qp->p[i].name);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = nfs_mount(client->context, uri->server, uri->path);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Failed to mount nfs share: %s",
|
||||
nfs_get_error(client->context));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (flags & O_CREAT) {
|
||||
ret = nfs_creat(client->context, file, 0600, &client->fh);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Failed to create file: %s",
|
||||
nfs_get_error(client->context));
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
ret = nfs_open(client->context, file, flags, &client->fh);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Failed to open file : %s",
|
||||
nfs_get_error(client->context));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = nfs_fstat(client->context, client->fh, &st);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Failed to fstat file: %s",
|
||||
nfs_get_error(client->context));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = DIV_ROUND_UP(st.st_size, BDRV_SECTOR_SIZE);
|
||||
client->has_zero_init = S_ISREG(st.st_mode);
|
||||
goto out;
|
||||
fail:
|
||||
nfs_client_close(client);
|
||||
out:
|
||||
if (qp) {
|
||||
query_params_free(qp);
|
||||
}
|
||||
uri_free(uri);
|
||||
g_free(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp) {
|
||||
NFSClient *client = bs->opaque;
|
||||
int64_t ret;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
|
||||
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = nfs_client_open(client, qemu_opt_get(opts, "filename"),
|
||||
(flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
|
||||
errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
bs->total_sectors = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfs_file_create(const char *url, QEMUOptionParameter *options,
|
||||
Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
int64_t total_size = 0;
|
||||
NFSClient *client = g_malloc0(sizeof(NFSClient));
|
||||
|
||||
/* Read out options */
|
||||
while (options && options->name) {
|
||||
if (!strcmp(options->name, "size")) {
|
||||
total_size = options->value.n;
|
||||
}
|
||||
options++;
|
||||
}
|
||||
|
||||
ret = nfs_client_open(client, url, O_CREAT, errp);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = nfs_ftruncate(client->context, client->fh, total_size);
|
||||
nfs_client_close(client);
|
||||
out:
|
||||
g_free(client);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nfs_has_zero_init(BlockDriverState *bs)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
return client->has_zero_init;
|
||||
}
|
||||
|
||||
static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
NFSRPC task = {0};
|
||||
struct stat st;
|
||||
|
||||
task.st = &st;
|
||||
if (nfs_fstat_async(client->context, client->fh, nfs_co_generic_cb,
|
||||
&task) != 0) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while (!task.complete) {
|
||||
nfs_set_events(client);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
|
||||
return (task.ret < 0 ? task.ret : st.st_blocks * st.st_blksize);
|
||||
}
|
||||
|
||||
static int nfs_file_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
NFSClient *client = bs->opaque;
|
||||
return nfs_ftruncate(client->context, client->fh, offset);
|
||||
}
|
||||
|
||||
static BlockDriver bdrv_nfs = {
|
||||
.format_name = "nfs",
|
||||
.protocol_name = "nfs",
|
||||
|
||||
.instance_size = sizeof(NFSClient),
|
||||
.bdrv_needs_filename = true,
|
||||
.bdrv_has_zero_init = nfs_has_zero_init,
|
||||
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
|
||||
.bdrv_truncate = nfs_file_truncate,
|
||||
|
||||
.bdrv_file_open = nfs_file_open,
|
||||
.bdrv_close = nfs_file_close,
|
||||
.bdrv_create = nfs_file_create,
|
||||
|
||||
.bdrv_co_readv = nfs_co_readv,
|
||||
.bdrv_co_writev = nfs_co_writev,
|
||||
.bdrv_co_flush_to_disk = nfs_co_flush,
|
||||
};
|
||||
|
||||
static void nfs_block_init(void)
|
||||
{
|
||||
bdrv_register(&bdrv_nfs);
|
||||
}
|
||||
|
||||
block_init(nfs_block_init);
|
@ -1182,7 +1182,7 @@ fail:
|
||||
* Return 0 on success and -errno in error cases
|
||||
*/
|
||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int n_start, int n_end, int *num, uint64_t *host_offset, QCowL2Meta **m)
|
||||
int *num, uint64_t *host_offset, QCowL2Meta **m)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t start, remaining;
|
||||
@ -1190,15 +1190,13 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t cur_bytes;
|
||||
int ret;
|
||||
|
||||
trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset,
|
||||
n_start, n_end);
|
||||
trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset, *num);
|
||||
|
||||
assert(n_start * BDRV_SECTOR_SIZE == offset_into_cluster(s, offset));
|
||||
offset = start_of_cluster(s, offset);
|
||||
assert((offset & ~BDRV_SECTOR_MASK) == 0);
|
||||
|
||||
again:
|
||||
start = offset + (n_start << BDRV_SECTOR_BITS);
|
||||
remaining = (n_end - n_start) << BDRV_SECTOR_BITS;
|
||||
start = offset;
|
||||
remaining = *num << BDRV_SECTOR_BITS;
|
||||
cluster_offset = 0;
|
||||
*host_offset = 0;
|
||||
cur_bytes = 0;
|
||||
@ -1284,7 +1282,7 @@ again:
|
||||
}
|
||||
}
|
||||
|
||||
*num = (n_end - n_start) - (remaining >> BDRV_SECTOR_BITS);
|
||||
*num -= remaining >> BDRV_SECTOR_BITS;
|
||||
assert(*num > 0);
|
||||
assert(*host_offset != 0);
|
||||
|
||||
|
@ -676,7 +676,13 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t cluster_index;
|
||||
uint64_t old_free_cluster_index;
|
||||
int i, refcount, ret;
|
||||
uint64_t i;
|
||||
int refcount, ret;
|
||||
|
||||
assert(nb_clusters >= 0);
|
||||
if (nb_clusters == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check how many clusters there are free */
|
||||
cluster_index = offset >> s->cluster_bits;
|
||||
|
@ -1000,7 +1000,6 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int index_in_cluster;
|
||||
int n_end;
|
||||
int ret;
|
||||
int cur_nr_sectors; /* number of sectors in current iteration */
|
||||
uint64_t cluster_offset;
|
||||
@ -1024,14 +1023,16 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||
|
||||
trace_qcow2_writev_start_part(qemu_coroutine_self());
|
||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
||||
n_end = index_in_cluster + remaining_sectors;
|
||||
cur_nr_sectors = remaining_sectors;
|
||||
if (s->crypt_method &&
|
||||
n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors) {
|
||||
n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
|
||||
cur_nr_sectors >
|
||||
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors - index_in_cluster) {
|
||||
cur_nr_sectors =
|
||||
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors - index_in_cluster;
|
||||
}
|
||||
|
||||
ret = qcow2_alloc_cluster_offset(bs, sector_num << 9,
|
||||
index_in_cluster, n_end, &cur_nr_sectors, &cluster_offset, &l2meta);
|
||||
&cur_nr_sectors, &cluster_offset, &l2meta);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
@ -1403,34 +1404,34 @@ static int preallocate(BlockDriverState *bs)
|
||||
int ret;
|
||||
QCowL2Meta *meta;
|
||||
|
||||
nb_sectors = bdrv_getlength(bs) >> 9;
|
||||
nb_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
|
||||
offset = 0;
|
||||
|
||||
while (nb_sectors) {
|
||||
num = MIN(nb_sectors, INT_MAX >> 9);
|
||||
ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
|
||||
num = MIN(nb_sectors, INT_MAX >> BDRV_SECTOR_BITS);
|
||||
ret = qcow2_alloc_cluster_offset(bs, offset, &num,
|
||||
&host_offset, &meta);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = qcow2_alloc_cluster_link_l2(bs, meta);
|
||||
if (ret < 0) {
|
||||
qcow2_free_any_clusters(bs, meta->alloc_offset, meta->nb_clusters,
|
||||
QCOW2_DISCARD_NEVER);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* There are no dependent requests, but we need to remove our request
|
||||
* from the list of in-flight requests */
|
||||
if (meta != NULL) {
|
||||
ret = qcow2_alloc_cluster_link_l2(bs, meta);
|
||||
if (ret < 0) {
|
||||
qcow2_free_any_clusters(bs, meta->alloc_offset,
|
||||
meta->nb_clusters, QCOW2_DISCARD_NEVER);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* There are no dependent requests, but we need to remove our
|
||||
* request from the list of in-flight requests */
|
||||
QLIST_REMOVE(meta, next_in_flight);
|
||||
}
|
||||
|
||||
/* TODO Preallocate data if requested */
|
||||
|
||||
nb_sectors -= num;
|
||||
offset += num << 9;
|
||||
offset += num << BDRV_SECTOR_BITS;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1439,9 +1440,10 @@ static int preallocate(BlockDriverState *bs)
|
||||
* EOF). Extend the image to the last allocated sector.
|
||||
*/
|
||||
if (host_offset != 0) {
|
||||
uint8_t buf[512];
|
||||
memset(buf, 0, 512);
|
||||
ret = bdrv_write(bs->file, (host_offset >> 9) + num - 1, buf, 1);
|
||||
uint8_t buf[BDRV_SECTOR_SIZE];
|
||||
memset(buf, 0, BDRV_SECTOR_SIZE);
|
||||
ret = bdrv_write(bs->file, (host_offset >> BDRV_SECTOR_BITS) + num - 1,
|
||||
buf, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -468,7 +468,7 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
|
||||
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int *num, uint64_t *cluster_offset);
|
||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
int n_start, int n_end, int *num, uint64_t *host_offset, QCowL2Meta **m);
|
||||
int *num, uint64_t *host_offset, QCowL2Meta **m);
|
||||
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||
uint64_t offset,
|
||||
int compressed_size);
|
||||
|
@ -90,6 +90,12 @@ static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
return bdrv_get_info(bs->file, bdi);
|
||||
}
|
||||
|
||||
static int raw_refresh_limits(BlockDriverState *bs)
|
||||
{
|
||||
bs->bl = bs->file->bl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||
{
|
||||
return bdrv_truncate(bs->file, offset);
|
||||
@ -150,7 +156,6 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
bs->sg = bs->file->sg;
|
||||
bs->bl = bs->file->bl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -182,6 +187,7 @@ static BlockDriver bdrv_raw = {
|
||||
.bdrv_getlength = &raw_getlength,
|
||||
.has_variable_length = true,
|
||||
.bdrv_get_info = &raw_get_info,
|
||||
.bdrv_refresh_limits = &raw_refresh_limits,
|
||||
.bdrv_is_inserted = &raw_is_inserted,
|
||||
.bdrv_media_changed = &raw_media_changed,
|
||||
.bdrv_eject = &raw_eject,
|
||||
|
26
configure
vendored
26
configure
vendored
@ -251,6 +251,7 @@ vss_win32_sdk=""
|
||||
win_sdk="no"
|
||||
want_tools="yes"
|
||||
libiscsi=""
|
||||
libnfs=""
|
||||
coroutine=""
|
||||
coroutine_pool=""
|
||||
seccomp=""
|
||||
@ -840,6 +841,10 @@ for opt do
|
||||
;;
|
||||
--enable-libiscsi) libiscsi="yes"
|
||||
;;
|
||||
--disable-libnfs) libnfs="no"
|
||||
;;
|
||||
--enable-libnfs) libnfs="yes"
|
||||
;;
|
||||
--enable-profiler) profiler="yes"
|
||||
;;
|
||||
--disable-cocoa) cocoa="no"
|
||||
@ -1229,6 +1234,8 @@ Advanced options (experts only):
|
||||
--enable-rbd enable building the rados block device (rbd)
|
||||
--disable-libiscsi disable iscsi support
|
||||
--enable-libiscsi enable iscsi support
|
||||
--disable-libnfs disable nfs support
|
||||
--enable-libnfs enable nfs support
|
||||
--disable-smartcard-nss disable smartcard nss support
|
||||
--enable-smartcard-nss enable smartcard nss support
|
||||
--disable-libusb disable libusb (for usb passthrough)
|
||||
@ -3600,6 +3607,20 @@ elif test "$debug" = "no" ; then
|
||||
CFLAGS="-O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS"
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# Do we have libnfs
|
||||
if test "$libnfs" != "no" ; then
|
||||
if $pkg_config --atleast-version=1.9.2 libnfs; then
|
||||
libnfs="yes"
|
||||
libnfs_libs=$($pkg_config --libs libnfs)
|
||||
LIBS="$LIBS $libnfs_libs"
|
||||
else
|
||||
if test "$libnfs" = "yes" ; then
|
||||
feature_not_found "libnfs"
|
||||
fi
|
||||
libnfs="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Disable zero malloc errors for official releases unless explicitly told to
|
||||
# enable/disable
|
||||
@ -3829,6 +3850,7 @@ echo "libiscsi support $libiscsi (1.4.0)"
|
||||
else
|
||||
echo "libiscsi support $libiscsi"
|
||||
fi
|
||||
echo "libnfs support $libnfs"
|
||||
echo "build guest agent $guest_agent"
|
||||
echo "QGA VSS support $guest_agent_with_vss"
|
||||
echo "seccomp support $seccomp"
|
||||
@ -4165,6 +4187,10 @@ if test "$libiscsi" = "yes" ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$libnfs" = "yes" ; then
|
||||
echo "CONFIG_LIBNFS=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$seccomp" = "yes"; then
|
||||
echo "CONFIG_SECCOMP=y" >> $config_host_mak
|
||||
fi
|
||||
|
@ -4371,6 +4371,7 @@
|
||||
# TODO gluster: Wait for structured options
|
||||
# TODO iscsi: Wait for structured options
|
||||
# TODO nbd: Should take InetSocketAddress for 'host'?
|
||||
# TODO nfs: Wait for structured options
|
||||
# TODO rbd: Wait for structured options
|
||||
# TODO sheepdog: Wait for structured options
|
||||
# TODO ssh: Should take InetSocketAddress for 'host'?
|
||||
|
@ -41,7 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# much of this could be generic for any format supporting compression.
|
||||
_supported_fmt qcow qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
TEST_OFFSETS="0 4294967296"
|
||||
|
@ -43,7 +43,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# much of this could be generic for any format supporting snapshots
|
||||
_supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
TEST_OFFSETS="0 4294967296"
|
||||
|
@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt raw
|
||||
_supported_proto file sheepdog
|
||||
_supported_proto file sheepdog nfs
|
||||
_supported_os Linux
|
||||
|
||||
|
||||
|
@ -41,7 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# Any format supporting backing files
|
||||
_supported_fmt qcow qcow2 vmdk qed
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
|
||||
|
||||
|
@ -45,7 +45,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# Any format supporting backing files
|
||||
_supported_fmt qcow qcow2 vmdk qed
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
_unsupported_imgopts "subformat=monolithicFlat" \
|
||||
"subformat=twoGbMaxExtentFlat" \
|
||||
|
@ -49,6 +49,11 @@ _unsupported_imgopts "subformat=monolithicFlat" \
|
||||
"subformat=twoGbMaxExtentFlat" \
|
||||
"subformat=twoGbMaxExtentSparse"
|
||||
|
||||
# NFS does not support bdrv_reopen_prepare thus qemu-img commit fails.
|
||||
if [ "$IMGPROTO" = "nfs" ]; then
|
||||
_notrun "image protocol $IMGPROTO does not support bdrv_commit"
|
||||
fi
|
||||
|
||||
TEST_OFFSETS="0 4294967296"
|
||||
|
||||
_make_test_img 6G
|
||||
|
@ -41,7 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# much of this could be generic for any format supporting compression.
|
||||
_supported_fmt qcow qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
TEST_OFFSETS="0 4294967296"
|
||||
|
@ -43,7 +43,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# Currently only qcow2 and qed support rebasing
|
||||
_supported_fmt qcow2 qed
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
CLUSTER_SIZE=65536
|
||||
|
@ -40,7 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.pattern
|
||||
|
||||
_supported_fmt raw qcow2 qed
|
||||
_supported_proto file sheepdog rbd
|
||||
_supported_proto file sheepdog rbd nfs
|
||||
_supported_os Linux
|
||||
|
||||
echo "=== Creating image"
|
||||
|
@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# Currently only qcow2 supports rebasing
|
||||
_supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
_default_cache_mode "writethrough"
|
||||
_supported_cache_modes "writethrough" "none"
|
||||
|
@ -45,7 +45,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
# Any format supporting backing files except vmdk and qcow which do not support
|
||||
# smaller backing files.
|
||||
_supported_fmt qcow2 qed
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
# Choose a size that is not necessarily a cluster size multiple for image
|
||||
|
@ -41,7 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# This tests qcow2-specific low-level functionality
|
||||
_supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
CLUSTER_SIZE=65536
|
||||
|
@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow qcow2 vmdk qed
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
_unsupported_imgopts "subformat=monolithicFlat" \
|
||||
"subformat=twoGbMaxExtentFlat" \
|
||||
|
@ -44,7 +44,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# This tests qcow2-specific low-level functionality
|
||||
_supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
# Only qcow2v3 and later supports feature bits
|
||||
|
@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow qcow2 vmdk qed
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
_unsupported_imgopts "subformat=monolithicFlat" \
|
||||
"subformat=twoGbMaxExtentFlat" \
|
||||
|
@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow2 qed
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
CLUSTER_SIZE=2M
|
||||
|
@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
_default_cache_mode "writethrough"
|
||||
_supported_cache_modes "writethrough"
|
||||
|
@ -41,7 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# Any format supporting backing files
|
||||
_supported_fmt qcow2 qed
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
CLUSTER_SIZE=64k
|
||||
|
@ -171,6 +171,18 @@ echo
|
||||
run_qemu -drive file="$TEST_IMG",file.driver=file
|
||||
run_qemu -drive file="$TEST_IMG",file.driver=qcow2
|
||||
|
||||
echo
|
||||
echo === Leaving out required options ===
|
||||
echo
|
||||
|
||||
run_qemu -drive driver=file
|
||||
run_qemu -drive driver=nbd
|
||||
run_qemu -drive driver=raw
|
||||
run_qemu -drive file.driver=file
|
||||
run_qemu -drive file.driver=nbd
|
||||
run_qemu -drive file.driver=raw
|
||||
run_qemu -drive foo=bar
|
||||
|
||||
echo
|
||||
echo === Parsing protocol from file name ===
|
||||
echo
|
||||
|
@ -225,6 +225,30 @@ Testing: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2
|
||||
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device '' doesn't support the option 'filename'
|
||||
|
||||
|
||||
=== Leaving out required options ===
|
||||
|
||||
Testing: -drive driver=file
|
||||
QEMU_PROG: -drive driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name
|
||||
|
||||
Testing: -drive driver=nbd
|
||||
QEMU_PROG: -drive driver=nbd: could not open disk image ide0-hd0: Could not open image: Invalid argument
|
||||
|
||||
Testing: -drive driver=raw
|
||||
QEMU_PROG: -drive driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level
|
||||
|
||||
Testing: -drive file.driver=file
|
||||
QEMU_PROG: -drive file.driver=file: could not open disk image ide0-hd0: The 'file' block driver requires a file name
|
||||
|
||||
Testing: -drive file.driver=nbd
|
||||
QEMU_PROG: -drive file.driver=nbd: could not open disk image ide0-hd0: Could not open image: Invalid argument
|
||||
|
||||
Testing: -drive file.driver=raw
|
||||
QEMU_PROG: -drive file.driver=raw: could not open disk image ide0-hd0: Can't use 'raw' as a block driver for the protocol level
|
||||
|
||||
Testing: -drive foo=bar
|
||||
QEMU_PROG: -drive foo=bar: could not open disk image ide0-hd0: Must specify either driver or file
|
||||
|
||||
|
||||
=== Parsing protocol from file name ===
|
||||
|
||||
Testing: -hda foo:bar
|
||||
|
@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt generic
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
_default_cache_mode "writethrough"
|
||||
_supported_cache_modes "writethrough"
|
||||
|
@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
echo
|
||||
|
@ -40,7 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# This tests vmdk-specific low-level functionality
|
||||
_supported_fmt vmdk
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
_unsupported_imgopts "subformat=monolithicFlat" \
|
||||
"subformat=twoGbMaxExtentFlat" \
|
||||
|
@ -40,7 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# This tests qocw2-specific low-level functionality
|
||||
_supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
rt_offset=65536 # 0x10000 (XXX: just an assumption)
|
||||
|
@ -40,7 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# This tests qocw2-specific low-level functionality
|
||||
_supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
echo
|
||||
|
@ -42,7 +42,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.pattern
|
||||
|
||||
_supported_fmt qcow qcow2 vmdk qed raw
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
_unsupported_imgopts "subformat=monolithicFlat" \
|
||||
"subformat=twoGbMaxExtentFlat" \
|
||||
|
@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt cow qed qcow qcow2 vmdk
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
|
||||
|
||||
|
@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow2
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
function do_run_qemu()
|
||||
|
@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt vpc vmdk vhdx vdi qed qcow2 qcow cow
|
||||
_supported_proto generic
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
IMG_SIZE=64M
|
||||
|
@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt generic
|
||||
_supported_fmt raw
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
|
63
tests/qemu-iotests/079
Executable file
63
tests/qemu-iotests/079
Executable file
@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test qcow2 preallocation with different cluster_sizes
|
||||
#
|
||||
# Copyright (C) 2014 Fujitsu.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=hutao@cn.fujitsu.com
|
||||
|
||||
seq=`basename $0`
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here=`pwd`
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow2
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
function test_qemu_img()
|
||||
{
|
||||
echo qemu-img "$@" | _filter_testdir
|
||||
$QEMU_IMG "$@" 2>&1 | _filter_testdir
|
||||
echo
|
||||
}
|
||||
|
||||
echo "=== Check option preallocation and cluster_size ==="
|
||||
echo
|
||||
cluster_sizes="16384 32768 65536 131072 262144 524288 1048576 2097152 4194304"
|
||||
|
||||
for s in $cluster_sizes; do
|
||||
test_qemu_img create -f $IMGFMT -o preallocation=metadata,cluster_size=$s "$TEST_IMG" 4G
|
||||
done
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
32
tests/qemu-iotests/079.out
Normal file
32
tests/qemu-iotests/079.out
Normal file
@ -0,0 +1,32 @@
|
||||
QA output created by 079
|
||||
=== Check option preallocation and cluster_size ===
|
||||
|
||||
qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=16384 TEST_DIR/t.qcow2 4G
|
||||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=16384 preallocation='metadata' lazy_refcounts=off
|
||||
|
||||
qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=32768 TEST_DIR/t.qcow2 4G
|
||||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=32768 preallocation='metadata' lazy_refcounts=off
|
||||
|
||||
qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=65536 TEST_DIR/t.qcow2 4G
|
||||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=65536 preallocation='metadata' lazy_refcounts=off
|
||||
|
||||
qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=131072 TEST_DIR/t.qcow2 4G
|
||||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=131072 preallocation='metadata' lazy_refcounts=off
|
||||
|
||||
qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=262144 TEST_DIR/t.qcow2 4G
|
||||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=262144 preallocation='metadata' lazy_refcounts=off
|
||||
|
||||
qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=524288 TEST_DIR/t.qcow2 4G
|
||||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=524288 preallocation='metadata' lazy_refcounts=off
|
||||
|
||||
qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=1048576 TEST_DIR/t.qcow2 4G
|
||||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=1048576 preallocation='metadata' lazy_refcounts=off
|
||||
|
||||
qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=2097152 TEST_DIR/t.qcow2 4G
|
||||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=2097152 preallocation='metadata' lazy_refcounts=off
|
||||
|
||||
qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=4194304 TEST_DIR/t.qcow2 4G
|
||||
qemu-img: TEST_DIR/t.qcow2: Cluster size must be a power of two between 512 and 2048k
|
||||
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=4194304 preallocation='metadata' lazy_refcounts=off
|
||||
|
||||
*** done
|
@ -144,10 +144,12 @@ check options
|
||||
-vpc test vpc
|
||||
-vhdx test vhdx
|
||||
-vmdk test vmdk
|
||||
-file test file (default)
|
||||
-rbd test rbd
|
||||
-sheepdog test sheepdog
|
||||
-nbd test nbd
|
||||
-ssh test ssh
|
||||
-nfs test nfs
|
||||
-xdiff graphical mode diff
|
||||
-nocache use O_DIRECT on backing file
|
||||
-misalign misalign memory allocations
|
||||
@ -211,22 +213,36 @@ testlist options
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-file)
|
||||
IMGPROTO=file
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-rbd)
|
||||
IMGPROTO=rbd
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-sheepdog)
|
||||
IMGPROTO=sheepdog
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-nbd)
|
||||
IMGPROTO=nbd
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-ssh)
|
||||
IMGPROTO=ssh
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-nfs)
|
||||
IMGPROTO=nfs
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-nocache)
|
||||
CACHEMODE="none"
|
||||
CACHEMODE_IS_DEFAULT=false
|
||||
@ -238,10 +254,10 @@ testlist options
|
||||
xpand=false
|
||||
;;
|
||||
|
||||
-valgrind)
|
||||
valgrind=true
|
||||
-valgrind)
|
||||
valgrind=true
|
||||
xpand=false
|
||||
;;
|
||||
;;
|
||||
|
||||
-g) # -g group ... pick from group file
|
||||
group=true
|
||||
|
@ -61,6 +61,9 @@ elif [ "$IMGPROTO" = "nbd" ]; then
|
||||
elif [ "$IMGPROTO" = "ssh" ]; then
|
||||
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
|
||||
TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE"
|
||||
elif [ "$IMGPROTO" = "nfs" ]; then
|
||||
TEST_DIR="nfs://127.0.0.1/$TEST_DIR"
|
||||
TEST_IMG=$TEST_DIR/t.$IMGFMT
|
||||
else
|
||||
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
|
||||
fi
|
||||
|
@ -82,3 +82,4 @@
|
||||
073 rw auto
|
||||
074 rw auto
|
||||
077 rw auto
|
||||
079 rw auto
|
||||
|
@ -495,7 +495,7 @@ qcow2_writev_done_part(void *co, int cur_nr_sectors) "co %p cur_nr_sectors %d"
|
||||
qcow2_writev_data(void *co, uint64_t offset) "co %p offset %" PRIx64
|
||||
|
||||
# block/qcow2-cluster.c
|
||||
qcow2_alloc_clusters_offset(void *co, uint64_t offset, int n_start, int n_end) "co %p offet %" PRIx64 " n_start %d n_end %d"
|
||||
qcow2_alloc_clusters_offset(void *co, uint64_t offset, int num) "co %p offet %" PRIx64 " num %d"
|
||||
qcow2_handle_copied(void *co, uint64_t guest_offset, uint64_t host_offset, uint64_t bytes) "co %p guest_offet %" PRIx64 " host_offset %" PRIx64 " bytes %" PRIx64
|
||||
qcow2_handle_alloc(void *co, uint64_t guest_offset, uint64_t host_offset, uint64_t bytes) "co %p guest_offet %" PRIx64 " host_offset %" PRIx64 " bytes %" PRIx64
|
||||
qcow2_do_alloc_clusters_offset(void *co, uint64_t guest_offset, uint64_t host_offset, int nb_clusters) "co %p guest_offet %" PRIx64 " host_offset %" PRIx64 " nb_clusters %d"
|
||||
|
Loading…
Reference in New Issue
Block a user