@@ -39,9 +39,11 @@ typedef struct BDRVNBDState {
int sock;
off_t size;
size_t blocksize;
+ char *filename;
} BDRVNBDState;
-static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
+
+static int nbd_open(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
uint32_t nbdflags;
@@ -56,7 +58,7 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
int ret;
int err = -EINVAL;
- file = qemu_strdup(filename);
+ file = qemu_strdup(s->filename);
name = strstr(file, EN_OPTSTR);
if (name) {
@@ -121,32 +123,62 @@ out:
return err;
}
+// Puts the filename into the driver state and calls nbd_open - hanging until
+// it is successful.
+static int nbd_setup(BlockDriverState *bs, const char* filename, int flags)
+{
+ BDRVNBDState *s = bs->opaque;
+ int err = 1;
+
+ s->filename = qemu_strdup(filename);
+ while (err != 0)
+ {
+ err = nbd_open(bs);
+ // Avoid tight loops
+ if (err != 0)
+ sleep(1);
+ }
+
+ return err;
+}
+
static int nbd_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ bool success = false;
request.type = NBD_CMD_READ;
request.handle = (uint64_t)(intptr_t)bs;
- request.from = sector_num * 512;;
+ request.from = sector_num * 512;
request.len = nb_sectors * 512;
- if (nbd_send_request(s->sock, &request) == -1)
- return -errno;
+ while (success == false)
+ {
+ if ( (nbd_send_request(s->sock, &request) == -1) ||
+ (nbd_receive_reply(s->sock, &reply) == -1) )
+ {
+ // We hang here until the TCP session is established
+ close(s->sock);
+ while(nbd_open(bs) != 0)
+ sleep(1);
+ continue;
+ }
- if (nbd_receive_reply(s->sock, &reply) == -1)
- return -errno;
+ if (reply.error !=0)
+ return -reply.error;
- if (reply.error !=0)
- return -reply.error;
+ if (reply.handle != request.handle)
+ return -EIO;
- if (reply.handle != request.handle)
- return -EIO;
+ // If reading the actual data fails, we retry the whole request
+ if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len)
+ continue;
- if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len)
- return -EIO;
+ success = true;
+ }
return 0;
}
@@ -157,26 +189,39 @@ static int nbd_write(BlockDriverState *bs, int64_t sector_num,
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ bool success = false;
request.type = NBD_CMD_WRITE;
request.handle = (uint64_t)(intptr_t)bs;
request.from = sector_num * 512;;
request.len = nb_sectors * 512;
- if (nbd_send_request(s->sock, &request) == -1)
- return -errno;
+ while (success == false)
+ {
+ if ( (nbd_send_request(s->sock, &request) == -1) ||
+ (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len) )
+ {
+ // We hang here until the TCP session is established
+ close(s->sock);
+ while(nbd_open(bs) != 0)
+ sleep(1);
+ continue;
+ }
+
+ // We didn't get a reply from the write, so try again
+ if (nbd_receive_reply(s->sock, &reply) == -1)
+ continue;
- if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len)
- return -EIO;
+ // Problem with the response itself
+ if (reply.error !=0)
+ return -reply.error;
- if (nbd_receive_reply(s->sock, &reply) == -1)
- return -errno;
+ if (reply.handle != request.handle)
+ return -EIO;
- if (reply.error !=0)
- return -reply.error;
+ success = true;
+ }
- if (reply.handle != request.handle)
- return -EIO;
return 0;
}
@@ -191,6 +236,7 @@ static void nbd_close(BlockDriverState *bs)
request.from = 0;
request.len = 0;
nbd_send_request(s->sock, &request);
+ qemu_free(s->filename);
close(s->sock);
}
@@ -205,7 +251,7 @@ static int64_t nbd_getlength(BlockDriverState *bs)
static BlockDriver bdrv_nbd = {
.format_name = "nbd",
.instance_size = sizeof(BDRVNBDState),
- .bdrv_file_open = nbd_open,
+ .bdrv_file_open = nbd_setup,
.bdrv_read = nbd_read,
.bdrv_write = nbd_write,
.bdrv_close = nbd_close,