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:
Peter Maydell 2014-02-12 16:42:50 +00:00
commit 628a746cf0
50 changed files with 730 additions and 84 deletions

View file

@ -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
View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

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

View file

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

View file

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

View file

@ -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;
}

View file

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

View file

@ -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
View file

@ -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

View file

@ -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'?

View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -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"

View file

@ -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" \

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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" \

View file

@ -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

View file

@ -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" \

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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" \

View file

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

View file

@ -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

View file

@ -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" \

View file

@ -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"

View file

@ -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()

View file

@ -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

View file

@ -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
View 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

View 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

View file

@ -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

View file

@ -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

View file

@ -82,3 +82,4 @@
073 rw auto
074 rw auto
077 rw auto
079 rw auto

View file

@ -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"