NBD: implemented read/write
This commit is contained in:
parent
f61d49c98f
commit
89a9fbead0
4 changed files with 236 additions and 9 deletions
|
@ -1,9 +1,12 @@
|
|||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "disk_backend_nbd.h"
|
||||
#include "log.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef ESP32
|
||||
#include <lwip/netdb.h>
|
||||
|
@ -13,6 +16,9 @@
|
|||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#define HTONLL(x) ((1==htonl(1)) ? (x) : (((uint64_t)htonl((x) & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)((x) >> 32)))
|
||||
#define NTOHLL(x) ((1==ntohl(1)) ? (x) : (((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32)))
|
||||
|
||||
|
||||
disk_backend_nbd::disk_backend_nbd(const std::string & host, const int port) :
|
||||
host(host),
|
||||
|
@ -80,6 +86,30 @@ bool disk_backend_nbd::connect(const bool retry)
|
|||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
struct __attribute__ ((packed)) {
|
||||
uint8_t magic1[8];
|
||||
uint8_t magic2[8];
|
||||
uint64_t size;
|
||||
uint32_t flags;
|
||||
uint8_t padding[124];
|
||||
} nbd_hello;
|
||||
|
||||
if (fd != -1) {
|
||||
if (READ(fd, reinterpret_cast<char *>(&nbd_hello), sizeof nbd_hello) != sizeof nbd_hello) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
DOLOG(debug, false, "disk_backend_nbd::connect: connect short read");
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(nbd_hello.magic1, "NBDMAGIC", 8) != 0) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
DOLOG(debug, false, "disk_backend_nbd::connect: magic invalid");
|
||||
}
|
||||
|
||||
DOLOG(info, false, "NBD size: %u", NTOHLL(nbd_hello.size));
|
||||
}
|
||||
while(fd == -1 && retry);
|
||||
|
||||
|
@ -90,21 +120,150 @@ bool disk_backend_nbd::read(const off_t offset, const size_t n, uint8_t *const t
|
|||
{
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: read %zu bytes from offset %zu", n, offset);
|
||||
|
||||
connect(true);
|
||||
if (n == 0)
|
||||
return true;
|
||||
|
||||
// TODO: loop dat als read() aangeeft dat de peer weg is, dat er dan gereconnect wordt
|
||||
// anders return false
|
||||
return pread(fd, target, n, offset) == ssize_t(n);
|
||||
do {
|
||||
if (fd == -1 && !connect(true)) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: (re-)connect");
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct __attribute__ ((packed)) {
|
||||
uint32_t magic;
|
||||
uint32_t type;
|
||||
uint64_t handle;
|
||||
uint64_t offset;
|
||||
uint32_t length;
|
||||
} nbd_request { 0 };
|
||||
|
||||
nbd_request.magic = ntohl(0x25609513);
|
||||
nbd_request.type = 0; // READ
|
||||
nbd_request.offset = HTONLL(uint64_t(offset));
|
||||
nbd_request.length = htonl(n);
|
||||
|
||||
if (WRITE(fd, reinterpret_cast<const char *>(&nbd_request), sizeof nbd_request) != sizeof nbd_request) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: problem sending request");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct __attribute__ ((packed)) {
|
||||
uint32_t magic;
|
||||
uint32_t error;
|
||||
uint64_t handle;
|
||||
} nbd_reply;
|
||||
|
||||
if (READ(fd, reinterpret_cast<char *>(&nbd_reply), sizeof nbd_reply) != sizeof nbd_reply) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: problem receiving reply header");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ntohl(nbd_reply.magic) != 0x67446698) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: bad reply header %08x", nbd_reply.magic);
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
int error = ntohl(nbd_reply.error);
|
||||
if (error) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: NBD server indicated error: %d", error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (READ(fd, reinterpret_cast<char *>(target), n) != ssize_t(n)) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::read: problem receiving payload");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while(fd == -1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disk_backend_nbd::write(const off_t offset, const size_t n, const uint8_t *const from)
|
||||
{
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: write %zu bytes to offset %zu", n, offset);
|
||||
|
||||
connect(true);
|
||||
if (n == 0)
|
||||
return true;
|
||||
|
||||
// TODO: loop dat als write() aangeeft dat de peer weg is, dat er dan gereconnect wordt
|
||||
// anders return false
|
||||
do {
|
||||
if (!connect(true)) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: (re-)connect");
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
return pwrite(fd, from, n, offset) == ssize_t(n);
|
||||
struct __attribute__ ((packed)) {
|
||||
uint32_t magic;
|
||||
uint32_t type;
|
||||
uint64_t handle;
|
||||
uint64_t offset;
|
||||
uint32_t length;
|
||||
} nbd_request { 0 };
|
||||
|
||||
nbd_request.magic = ntohl(0x25609513);
|
||||
nbd_request.type = 1; // WRITE
|
||||
nbd_request.offset = HTONLL(uint64_t(offset));
|
||||
nbd_request.length = htonl(n);
|
||||
|
||||
if (WRITE(fd, reinterpret_cast<const char *>(&nbd_request), sizeof nbd_request) != sizeof nbd_request) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: problem sending request");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (WRITE(fd, reinterpret_cast<const char *>(from), n) != ssize_t(n)) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: problem sending payload");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct __attribute__ ((packed)) {
|
||||
uint32_t magic;
|
||||
uint32_t error;
|
||||
uint64_t handle;
|
||||
} nbd_reply;
|
||||
|
||||
if (READ(fd, reinterpret_cast<char *>(&nbd_reply), sizeof nbd_reply) != sizeof nbd_reply) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: problem receiving reply header");
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ntohl(nbd_reply.magic) != 0x67446698) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: bad reply header %08x", nbd_reply.magic);
|
||||
close(fd);
|
||||
fd = -1;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
int error = ntohl(nbd_reply.error);
|
||||
if (error) {
|
||||
DOLOG(debug, false, "disk_backend_nbd::write: NBD server indicated error: %d", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while(fd == -1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
20
main.cpp
20
main.cpp
|
@ -14,6 +14,7 @@
|
|||
#include "debugger.h"
|
||||
#include "disk_backend.h"
|
||||
#include "disk_backend_file.h"
|
||||
#include "disk_backend_nbd.h"
|
||||
#include "gen.h"
|
||||
#include "kw11-l.h"
|
||||
#include "loaders.h"
|
||||
|
@ -47,6 +48,7 @@ void help()
|
|||
printf("-T t.bin load file as a binary tape file (like simh \"load\" command)\n");
|
||||
printf("-R d.rk load file as a RK05 disk device\n");
|
||||
printf("-r d.rl load file as a RL02 disk device\n");
|
||||
printf("-N host:port:type use NBD-server as disk device, type being either \"rk05\" or \"rl02\"\n");
|
||||
printf("-p 123 set CPU start pointer to decimal(!) value\n");
|
||||
printf("-b x enable bootloader (build-in), parameter must be \"rk05\" or \"rl02\"\n");
|
||||
printf("-n ncurses UI\n");
|
||||
|
@ -85,7 +87,7 @@ int main(int argc, char *argv[])
|
|||
disk_backend *temp_d = nullptr;
|
||||
|
||||
int opt = -1;
|
||||
while((opt = getopt(argc, argv, "hm:T:r:R:p:ndtL:b:l:s:Q:")) != -1)
|
||||
while((opt = getopt(argc, argv, "hm:T:r:R:p:ndtL:b:l:s:Q:N:")) != -1)
|
||||
{
|
||||
switch(opt) {
|
||||
case 'h':
|
||||
|
@ -149,6 +151,22 @@ int main(int argc, char *argv[])
|
|||
rl02_files.push_back(temp_d);
|
||||
break;
|
||||
|
||||
case 'N': {
|
||||
auto parts = split(optarg, ":");
|
||||
if (parts.size() != 3)
|
||||
error_exit(false, "-N: parameter missing");
|
||||
|
||||
temp_d = new disk_backend_nbd(parts.at(0), atoi(parts.at(1).c_str()));
|
||||
|
||||
if (parts.at(2) == "rk05")
|
||||
rk05_files.push_back(temp_d);
|
||||
else if (parts.at(2) == "rl02")
|
||||
rl02_files.push_back(temp_d);
|
||||
else
|
||||
error_exit(false, "\"%s\" is not recognized as a disk type", parts.at(2).c_str());
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
start_addr = atoi(optarg);
|
||||
sa_set = true;
|
||||
|
|
47
utils.cpp
47
utils.cpp
|
@ -10,6 +10,7 @@
|
|||
#include <string>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <sys/time.h>
|
||||
|
||||
|
@ -144,3 +145,49 @@ void set_thread_name(std::string name)
|
|||
pthread_setname_np(pthread_self(), name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t WRITE(int fd, const char *whereto, size_t len)
|
||||
{
|
||||
ssize_t cnt=0;
|
||||
|
||||
while(len > 0)
|
||||
{
|
||||
ssize_t rc = write(fd, whereto, len);
|
||||
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
else if (rc == 0)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
whereto += rc;
|
||||
len -= rc;
|
||||
cnt += rc;
|
||||
}
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
ssize_t READ(int fd, char *whereto, size_t len)
|
||||
{
|
||||
ssize_t cnt=0;
|
||||
|
||||
while(len > 0)
|
||||
{
|
||||
ssize_t rc = read(fd, whereto, len);
|
||||
|
||||
if (rc == -1)
|
||||
return -1;
|
||||
else if (rc == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
whereto += rc;
|
||||
len -= rc;
|
||||
cnt += rc;
|
||||
}
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
|
3
utils.h
3
utils.h
|
@ -18,3 +18,6 @@ uint64_t get_us();
|
|||
void myusleep(uint64_t us);
|
||||
|
||||
void set_thread_name(std::string name);
|
||||
|
||||
ssize_t WRITE(int fd, const char *whereto, size_t len);
|
||||
ssize_t READ(int fd, char *whereto, size_t len);
|
||||
|
|
Loading…
Add table
Reference in a new issue