NBD: implemented read/write

This commit is contained in:
folkert van heusden 2023-03-22 10:24:23 +01:00
parent f61d49c98f
commit 89a9fbead0
Signed by untrusted user who does not match committer: folkert
GPG key ID: 6B6455EDFEED3BD1
4 changed files with 236 additions and 9 deletions

View file

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

View file

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

View file

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

View file

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