aboutsummaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
Diffstat (limited to 'block')
-rw-r--r--block/nbd.c157
-rw-r--r--block/qed-check.c9
-rw-r--r--block/qed-cluster.c31
-rw-r--r--block/qed.c21
-rw-r--r--block/qed.h28
-rw-r--r--block/sheepdog.c15
-rw-r--r--block/vdi.c4
-rw-r--r--block/vpc.c8
8 files changed, 178 insertions, 95 deletions
diff --git a/block/nbd.c b/block/nbd.c
index c8dc763c6b..7a52f62e7e 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -29,96 +29,152 @@
#include "qemu-common.h"
#include "nbd.h"
#include "module.h"
+#include "qemu_socket.h"
#include <sys/types.h>
#include <unistd.h>
#define EN_OPTSTR ":exportname="
+/* #define DEBUG_NBD */
+
+#if defined(DEBUG_NBD)
+#define logout(fmt, ...) \
+ fprintf(stderr, "nbd\t%-24s" fmt, __func__, ##__VA_ARGS__)
+#else
+#define logout(fmt, ...) ((void)0)
+#endif
+
typedef struct BDRVNBDState {
int sock;
off_t size;
size_t blocksize;
+ char *export_name; /* An NBD server may export several devices */
+
+ /* If it begins with '/', this is a UNIX domain socket. Otherwise,
+ * it's a string of the form <hostname|ip4|\[ip6\]>:port
+ */
+ char *host_spec;
} BDRVNBDState;
-static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
+static int nbd_config(BDRVNBDState *s, const char *filename, int flags)
{
- BDRVNBDState *s = bs->opaque;
- uint32_t nbdflags;
-
char *file;
- char *name;
- const char *host;
+ char *export_name;
+ const char *host_spec;
const char *unixpath;
- int sock;
- off_t size;
- size_t blocksize;
- int ret;
int err = -EINVAL;
file = qemu_strdup(filename);
- name = strstr(file, EN_OPTSTR);
- if (name) {
- if (name[strlen(EN_OPTSTR)] == 0) {
+ export_name = strstr(file, EN_OPTSTR);
+ if (export_name) {
+ if (export_name[strlen(EN_OPTSTR)] == 0) {
goto out;
}
- name[0] = 0;
- name += strlen(EN_OPTSTR);
+ export_name[0] = 0; /* truncate 'file' */
+ export_name += strlen(EN_OPTSTR);
+ s->export_name = qemu_strdup(export_name);
}
- if (!strstart(file, "nbd:", &host)) {
+ /* extract the host_spec - fail if it's not nbd:... */
+ if (!strstart(file, "nbd:", &host_spec)) {
goto out;
}
- if (strstart(host, "unix:", &unixpath)) {
-
- if (unixpath[0] != '/') {
+ /* are we a UNIX or TCP socket? */
+ if (strstart(host_spec, "unix:", &unixpath)) {
+ if (unixpath[0] != '/') { /* We demand an absolute path*/
goto out;
}
-
- sock = unix_socket_outgoing(unixpath);
-
+ s->host_spec = qemu_strdup(unixpath);
} else {
- uint16_t port = NBD_DEFAULT_PORT;
- char *p, *r;
- char hostname[128];
+ s->host_spec = qemu_strdup(host_spec);
+ }
- pstrcpy(hostname, 128, host);
+ err = 0;
- p = strchr(hostname, ':');
- if (p != NULL) {
- *p = '\0';
- p++;
+out:
+ qemu_free(file);
+ if (err != 0) {
+ qemu_free(s->export_name);
+ qemu_free(s->host_spec);
+ }
+ return err;
+}
- port = strtol(p, &r, 0);
- if (r == p) {
- goto out;
- }
- }
+static int nbd_establish_connection(BlockDriverState *bs)
+{
+ BDRVNBDState *s = bs->opaque;
+ int sock;
+ int ret;
+ off_t size;
+ size_t blocksize;
+ uint32_t nbdflags;
- sock = tcp_socket_outgoing(hostname, port);
+ if (s->host_spec[0] == '/') {
+ sock = unix_socket_outgoing(s->host_spec);
+ } else {
+ sock = tcp_socket_outgoing_spec(s->host_spec);
}
+ /* Failed to establish connection */
if (sock == -1) {
- err = -errno;
- goto out;
+ logout("Failed to establish connection to NBD server\n");
+ return -errno;
}
- ret = nbd_receive_negotiate(sock, name, &nbdflags, &size, &blocksize);
+ /* NBD handshake */
+ ret = nbd_receive_negotiate(sock, s->export_name, &nbdflags, &size,
+ &blocksize);
if (ret == -1) {
- err = -errno;
- goto out;
+ logout("Failed to negotiate with the NBD server\n");
+ closesocket(sock);
+ return -errno;
}
+ /* Now that we're connected, set the socket to be non-blocking */
+ socket_set_nonblock(sock);
+
s->sock = sock;
s->size = size;
s->blocksize = blocksize;
- err = 0;
-out:
- qemu_free(file);
- return err;
+ logout("Established connection with NBD server\n");
+ return 0;
+}
+
+static void nbd_teardown_connection(BlockDriverState *bs)
+{
+ BDRVNBDState *s = bs->opaque;
+ struct nbd_request request;
+
+ request.type = NBD_CMD_DISC;
+ request.handle = (uint64_t)(intptr_t)bs;
+ request.from = 0;
+ request.len = 0;
+ nbd_send_request(s->sock, &request);
+
+ closesocket(s->sock);
+}
+
+static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
+{
+ BDRVNBDState *s = bs->opaque;
+ int result;
+
+ /* Pop the config into our state object. Exit if invalid. */
+ result = nbd_config(s, filename, flags);
+ if (result != 0) {
+ return result;
+ }
+
+ /* establish TCP connection, return error if it fails
+ * TODO: Configurable retry-until-timeout behaviour.
+ */
+ result = nbd_establish_connection(bs);
+
+ return result;
}
static int nbd_read(BlockDriverState *bs, int64_t sector_num,
@@ -184,15 +240,10 @@ static int nbd_write(BlockDriverState *bs, int64_t sector_num,
static void nbd_close(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
- struct nbd_request request;
-
- request.type = NBD_CMD_DISC;
- request.handle = (uint64_t)(intptr_t)bs;
- request.from = 0;
- request.len = 0;
- nbd_send_request(s->sock, &request);
+ qemu_free(s->export_name);
+ qemu_free(s->host_spec);
- close(s->sock);
+ nbd_teardown_connection(bs);
}
static int64_t nbd_getlength(BlockDriverState *bs)
diff --git a/block/qed-check.c b/block/qed-check.c
index 4600932bf2..22cd07fa1f 100644
--- a/block/qed-check.c
+++ b/block/qed-check.c
@@ -18,7 +18,7 @@ typedef struct {
BdrvCheckResult *result;
bool fix; /* whether to fix invalid offsets */
- size_t nclusters;
+ uint64_t nclusters;
uint32_t *used_clusters; /* referenced cluster bitmap */
QEDRequest request;
@@ -72,7 +72,8 @@ static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table)
for (i = 0; i < s->table_nelems; i++) {
uint64_t offset = table->offsets[i];
- if (!offset) {
+ if (qed_offset_is_unalloc_cluster(offset) ||
+ qed_offset_is_zero_cluster(offset)) {
continue;
}
@@ -111,7 +112,7 @@ static int qed_check_l1_table(QEDCheck *check, QEDTable *table)
unsigned int num_invalid_l2;
uint64_t offset = table->offsets[i];
- if (!offset) {
+ if (qed_offset_is_unalloc_cluster(offset)) {
continue;
}
@@ -176,7 +177,7 @@ static int qed_check_l1_table(QEDCheck *check, QEDTable *table)
static void qed_check_for_leaks(QEDCheck *check)
{
BDRVQEDState *s = check->s;
- size_t i;
+ uint64_t i;
for (i = s->header.header_size; i < check->nclusters; i++) {
if (!qed_test_bit(check->used_clusters, i)) {
diff --git a/block/qed-cluster.c b/block/qed-cluster.c
index 0ec864b14c..3e19ad1766 100644
--- a/block/qed-cluster.c
+++ b/block/qed-cluster.c
@@ -23,7 +23,8 @@
* @n: Maximum number of clusters
* @offset: Set to first cluster offset
*
- * This function scans tables for contiguous allocated or free clusters.
+ * This function scans tables for contiguous clusters. A contiguous run of
+ * clusters may be allocated, unallocated, or zero.
*/
static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
QEDTable *table,
@@ -38,9 +39,14 @@ static unsigned int qed_count_contiguous_clusters(BDRVQEDState *s,
*offset = last;
for (i = index + 1; i < end; i++) {
- if (last == 0) {
- /* Counting free clusters */
- if (table->offsets[i] != 0) {
+ if (qed_offset_is_unalloc_cluster(last)) {
+ /* Counting unallocated clusters */
+ if (!qed_offset_is_unalloc_cluster(table->offsets[i])) {
+ break;
+ }
+ } else if (qed_offset_is_zero_cluster(last)) {
+ /* Counting zero clusters */
+ if (!qed_offset_is_zero_cluster(table->offsets[i])) {
break;
}
} else {
@@ -87,14 +93,19 @@ static void qed_find_cluster_cb(void *opaque, int ret)
n = qed_count_contiguous_clusters(s, request->l2_table->table,
index, n, &offset);
- ret = offset ? QED_CLUSTER_FOUND : QED_CLUSTER_L2;
- len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
- qed_offset_into_cluster(s, find_cluster_cb->pos));
-
- if (offset && !qed_check_cluster_offset(s, offset)) {
+ if (qed_offset_is_unalloc_cluster(offset)) {
+ ret = QED_CLUSTER_L2;
+ } else if (qed_offset_is_zero_cluster(offset)) {
+ ret = QED_CLUSTER_ZERO;
+ } else if (qed_check_cluster_offset(s, offset)) {
+ ret = QED_CLUSTER_FOUND;
+ } else {
ret = -EINVAL;
}
+ len = MIN(find_cluster_cb->len, n * s->header.cluster_size -
+ qed_offset_into_cluster(s, find_cluster_cb->pos));
+
out:
find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
qemu_free(find_cluster_cb);
@@ -132,7 +143,7 @@ void qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos,
len = MIN(len, (((pos >> s->l1_shift) + 1) << s->l1_shift) - pos);
l2_offset = s->l1_table->offsets[qed_l1_index(s, pos)];
- if (!l2_offset) {
+ if (qed_offset_is_unalloc_cluster(l2_offset)) {
cb(opaque, QED_CLUSTER_L1, 0, len);
return;
}
diff --git a/block/qed.c b/block/qed.c
index 75ae2440ee..c8c5930448 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -573,7 +573,7 @@ static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t l
{
QEDIsAllocatedCB *cb = opaque;
*cb->pnum = len / BDRV_SECTOR_SIZE;
- cb->is_allocated = ret == QED_CLUSTER_FOUND;
+ cb->is_allocated = (ret == QED_CLUSTER_FOUND || ret == QED_CLUSTER_ZERO);
}
static int bdrv_qed_is_allocated(BlockDriverState *bs, int64_t sector_num,
@@ -745,7 +745,10 @@ static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
* @table: L2 table
* @index: First cluster index
* @n: Number of contiguous clusters
- * @cluster: First cluster byte offset in image file
+ * @cluster: First cluster offset
+ *
+ * The cluster offset may be an allocated byte offset in the image file, the
+ * zero cluster marker, or the unallocated cluster marker.
*/
static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
unsigned int n, uint64_t cluster)
@@ -753,7 +756,10 @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
int i;
for (i = index; i < index + n; i++) {
table->offsets[i] = cluster;
- cluster += s->header.cluster_size;
+ if (!qed_offset_is_unalloc_cluster(cluster) &&
+ !qed_offset_is_zero_cluster(cluster)) {
+ cluster += s->header.cluster_size;
+ }
}
}
@@ -1075,6 +1081,7 @@ static void qed_aio_write_data(void *opaque, int ret,
case QED_CLUSTER_L2:
case QED_CLUSTER_L1:
+ case QED_CLUSTER_ZERO:
qed_aio_write_alloc(acb, len);
break;
@@ -1114,8 +1121,12 @@ static void qed_aio_read_data(void *opaque, int ret,
qemu_iovec_copy(&acb->cur_qiov, acb->qiov, acb->qiov_offset, len);
- /* Handle backing file and unallocated sparse hole reads */
- if (ret != QED_CLUSTER_FOUND) {
+ /* Handle zero cluster and backing file reads */
+ if (ret == QED_CLUSTER_ZERO) {
+ qemu_iovec_memset(&acb->cur_qiov, 0, acb->cur_qiov.size);
+ qed_aio_next_io(acb, 0);
+ return;
+ } else if (ret != QED_CLUSTER_FOUND) {
qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov,
qed_aio_next_io, acb);
return;
diff --git a/block/qed.h b/block/qed.h
index 2925e37b1c..1d1421fee1 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -161,6 +161,7 @@ typedef struct {
enum {
QED_CLUSTER_FOUND, /* cluster found */
+ QED_CLUSTER_ZERO, /* zero cluster found */
QED_CLUSTER_L2, /* cluster missing in L2 */
QED_CLUSTER_L1, /* cluster missing in L1 */
};
@@ -251,7 +252,7 @@ static inline uint64_t qed_offset_into_cluster(BDRVQEDState *s, uint64_t offset)
return offset & (s->header.cluster_size - 1);
}
-static inline unsigned int qed_bytes_to_clusters(BDRVQEDState *s, size_t bytes)
+static inline uint64_t qed_bytes_to_clusters(BDRVQEDState *s, uint64_t bytes)
{
return qed_start_of_cluster(s, bytes + (s->header.cluster_size - 1)) /
(s->header.cluster_size - 1);
@@ -298,4 +299,29 @@ static inline bool qed_check_table_offset(BDRVQEDState *s, uint64_t offset)
qed_check_cluster_offset(s, end_offset);
}
+static inline bool qed_offset_is_cluster_aligned(BDRVQEDState *s,
+ uint64_t offset)
+{
+ if (qed_offset_into_cluster(s, offset)) {
+ return false;
+ }
+ return true;
+}
+
+static inline bool qed_offset_is_unalloc_cluster(uint64_t offset)
+{
+ if (offset == 0) {
+ return true;
+ }
+ return false;
+}
+
+static inline bool qed_offset_is_zero_cluster(uint64_t offset)
+{
+ if (offset == 1) {
+ return true;
+ }
+ return false;
+}
+
#endif /* BLOCK_QED_H */
diff --git a/block/sheepdog.c b/block/sheepdog.c
index a54e0dee31..98946d72b7 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -13,6 +13,7 @@
#include "qemu-error.h"
#include "qemu_socket.h"
#include "block_int.h"
+#include "bitops.h"
#define SD_PROTO_VER 0x01
@@ -1829,20 +1830,6 @@ static int sd_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
return 0;
}
-#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
-#define BITS_PER_BYTE 8
-#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
-#define DECLARE_BITMAP(name,bits) \
- unsigned long name[BITS_TO_LONGS(bits)]
-
-#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long))
-
-static inline int test_bit(unsigned int nr, const unsigned long *addr)
-{
- return ((1UL << (nr % BITS_PER_LONG)) &
- (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
-}
-
static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
{
BDRVSheepdogState *s = bs->opaque;
diff --git a/block/vdi.c b/block/vdi.c
index 90540792d3..701745bf8c 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -113,7 +113,7 @@ void uuid_unparse(const uuid_t uu, char *out);
*/
#define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
-/* Unallocated blocks use this index (no need to convert endianess). */
+/* Unallocated blocks use this index (no need to convert endianness). */
#define VDI_UNALLOCATED UINT32_MAX
#if !defined(CONFIG_UUID)
@@ -194,7 +194,7 @@ typedef struct {
uint32_t block_sectors;
/* First sector of block map. */
uint32_t bmap_sector;
- /* VDI header (converted to host endianess). */
+ /* VDI header (converted to host endianness). */
VdiHeader header;
} BDRVVdiState;
diff --git a/block/vpc.c b/block/vpc.c
index 7b025be01d..56865da5bc 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -505,12 +505,8 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
int ret = -EIO;
// Read out options
- while (options && options->name) {
- if (!strcmp(options->name, "size")) {
- total_sectors = options->value.n / 512;
- }
- options++;
- }
+ total_sectors = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n /
+ BDRV_SECTOR_SIZE;
// Create the file
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);