diff --git a/src/add-ons/kernel/drivers/disk/virtual/Jamfile b/src/add-ons/kernel/drivers/disk/virtual/Jamfile new file mode 100644 index 0000000000..2569f04aa0 --- /dev/null +++ b/src/add-ons/kernel/drivers/disk/virtual/Jamfile @@ -0,0 +1,4 @@ +SubDir HAIKU_TOP src add-ons kernel drivers disk virtual ; + +#SubInclude HAIKU_TOP src add-ons kernel drivers disk virtual fmap ; +SubInclude HAIKU_TOP src add-ons kernel drivers disk virtual nbd ; diff --git a/src/add-ons/kernel/drivers/disk/virtual/fmap/Jamfile b/src/add-ons/kernel/drivers/disk/virtual/fmap/Jamfile new file mode 100644 index 0000000000..2101706f80 --- /dev/null +++ b/src/add-ons/kernel/drivers/disk/virtual/fmap/Jamfile @@ -0,0 +1,13 @@ +SubDir HAIKU_TOP src add-ons kernel drivers disk virtual fmap ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +if $(TARGET_PLATFORM) != haiku { + # Needed for . Unfortunately we also get the other headers there, + # that we don't really want. + UsePublicHeaders drivers ; +} + +KernelAddon fmap : kernel drivers bin : + fmap.c + ; diff --git a/src/add-ons/kernel/drivers/disk/virtual/fmap/fmap.c b/src/add-ons/kernel/drivers/disk/virtual/fmap/fmap.c new file mode 100644 index 0000000000..8ae37e8f44 --- /dev/null +++ b/src/add-ons/kernel/drivers/disk/virtual/fmap/fmap.c @@ -0,0 +1,60 @@ +/* + * Copyright 2006, François Revol. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +/* + fmap driver for Haiku + + Maps BEOS/IMAGE.BE files as virtual partitions. +*/ + +#include +#include +#include + +#define MAX_FMAPS 4 +#define DEVNAME_FMT "disk/virtual/fmap/%2d" + +status_t +init_hardware (void) +{ + return B_OK; +} + +status_t +init_driver (void) +{ + return B_OK; +} + +void +uninit_driver (void) +{ +} + +static const char *fmap_name[MAX_FMAPS+1] = { + NULL +}; + +device_hooks fmap_hooks = { + NULL, /* open */ + NULL, /* close */ + NULL, /* free */ + NULL, /* control */ + NULL, /* read */ + NULL, /* write */ + NULL, NULL, NULL, NULL +}; + +const char** +publish_devices() +{ + return fmap_name; +} + +device_hooks* +find_device(const char* name) +{ + return &fmap_hooks; +} diff --git a/src/add-ons/kernel/drivers/disk/virtual/nbd/Jamfile b/src/add-ons/kernel/drivers/disk/virtual/nbd/Jamfile new file mode 100644 index 0000000000..0a43a51661 --- /dev/null +++ b/src/add-ons/kernel/drivers/disk/virtual/nbd/Jamfile @@ -0,0 +1,15 @@ +SubDir HAIKU_TOP src add-ons kernel drivers disk virtual nbd ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +#if $(TARGET_PLATFORM) != haiku { +# # Needed for . Unfortunately we also get the other headers there, +# # that we don't really want. +# UsePublicHeaders drivers ; +#} + +UsePrivateHeaders drivers ; + +KernelAddon nbd : + nbd.c + ; diff --git a/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd-server.py b/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd-server.py new file mode 100644 index 0000000000..4323f90747 --- /dev/null +++ b/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd-server.py @@ -0,0 +1,136 @@ +#!/usr/bin/python +# from http://lists.canonical.org/pipermail/kragen-hacks/2004-May/000397.html +import struct, socket, sys +# network block device server, substitute for nbd-server. Probably slower. +# But it works! And it's probably a lot easier to improve the +# performance of this Python version than of the C version. This +# Python version is 14% of the size and perhaps 20% of the features of +# the C version. Hmm, that's not so great after all... +# Working: +# - nbd protocol +# - read/write serving up files +# - error handling +# - file size detection +# - in theory, large file support... not really +# - so_reuseaddr +# - nonforking +# Missing: +# - reporting errors to client (in particular writing and reading past end) +# - multiple clients (this probably requires copy-on-write or read-only) +# - copy on write +# - read-only +# - permission tracking +# - idle timeouts +# - running from inetd +# - filename substitution +# - partial file exports +# - exports of large files (bigger than 1/4 of RAM) +# - manual exportsize specification +# - so_keepalive +# - that "split an export file into multiple files" thing that sticks the .0 +# on the end of your filename +# - backgrounding +# - daemonizing + +class Error(Exception): pass + +class buffsock: + "Buffered socket wrapper; always returns the amount of data you want." + def __init__(self, sock): self.sock = sock + def recv(self, nbytes): + rv = '' + while len(rv) < nbytes: + more = self.sock.recv(nbytes - len(rv)) + if more == '': raise Error(nbytes) + rv += more + return rv + def send(self, astring): self.sock.send(astring) + def close(self): self.sock.close() + + +class debugsock: + "Debugging socket wrapper." + def __init__(self, sock): self.sock = sock + def recv(self, nbytes): + print "recv(%d) =" % nbytes, + rv = self.sock.recv(nbytes) + print `rv` + return rv + def send(self, astring): + print "send(%r) =" % astring, + rv = self.sock.send(astring) + print `rv` + return rv + def close(self): + print "close()" + self.sock.close() + +def negotiation(exportsize): + "Returns initial NBD negotiation sequence for exportsize in bytes." + return ('NBDMAGIC' + '\x00\x00\x42\x02\x81\x86\x12\x53' + + struct.pack('>Q', exportsize) + '\0' * 128); + +def nbd_reply(error=0, handle=1, data=''): + "Construct an NBD reply." + assert type(handle) is type('') and len(handle) == 8 + return ('\x67\x44\x66\x98' + struct.pack('>L', error) + handle + data) + +# possible request types +read_request = 0 +write_request = 1 +disconnect_request = 2 + +class nbd_request: + "Decodes an NBD request off the TCP socket." + def __init__(self, conn): + conn = buffsock(conn) + template = '>LL8sQL' + header = conn.recv(struct.calcsize(template)) + (self.magic, self.type, self.handle, self.offset, + self.len) = struct.unpack(template, header) + if self.magic != 0x25609513: raise Error(self.magic) + if self.type == write_request: + self.data = conn.recv(self.len) + assert len(self.data) == self.len + def reply(self, error, data=''): + return nbd_reply(error=error, handle=self.handle, data=data) + def range(self): + return slice(self.offset, self.offset + self.len) + +def serveclient(asock, afile): + "Serves a single client until it exits." + afile.seek(0) + abuf = list(afile.read()) + asock.send(negotiation(len(abuf))) + while 1: + req = nbd_request(asock) + if req.type == read_request: + asock.send(req.reply(error=0, + data=''.join(abuf[req.range()]))) + elif req.type == write_request: + abuf[req.range()] = req.data + afile.seek(req.offset) + afile.write(req.data) + afile.flush() + asock.send(req.reply(error=0)) + elif req.type == disconnect_request: + asock.close() + return + +def mainloop(listensock, afile): + "Serves clients forever." + while 1: + (sock, addr) = listensock.accept() + print "got conn on", addr + serveclient(sock, afile) + +def main(argv): + "Given a port and a filename, serves up the file." + afile = file(argv[2], 'rb+') + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind(('', int(argv[1]))) + sock.listen(5) + mainloop(sock, afile) + +if __name__ == '__main__': main(sys.argv) \ No newline at end of file diff --git a/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd.c b/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd.c new file mode 100644 index 0000000000..833915a156 --- /dev/null +++ b/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd.c @@ -0,0 +1,218 @@ +/* + * Copyright 2006-2007, François Revol. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +/* + nbd driver for Haiku + + Maps BEOS/IMAGE.BE files as virtual partitions. +*/ + +#include +#include +#include +#include + +#include "nbd.h" + +#define MAX_NBDS 4 +#define DEVICE_PREFIX "disk/virtual/nbd/" +#define DEVICE_FMT DEVICE_PREFIX "%2d/raw" +#define DEVICE_NAME_MAX 32 +#define MAX_REQ_SIZE (32*1024*1024) + +struct nbd_request_entry { + struct nbd_request_entry *next; + struct nbd_request req; + bool r; /* is read */ + size_t len; + void *buffer; /* write: ptr to passed buffer; read: ptr to malloc()ed extra */ +}; + +struct nbd_device { + //lock + vint32 refcnt; + uint64 req; /* next ID for requests */ + int sock; + thread_id postoffice; + uint64 size; + struct nbd_request_entry *reqs; +}; + +typedef struct cookie { + struct nbd_device *dev; + +} cookie_t; + +/* data=NULL on read */ +status_t nbd_alloc_request(struct nbd_device, struct nbd_request_entry **req, size_t len, const char *data); +status_t nbd_post_request(struct nbd_device, uint64 handle, struct nbd_request_entry **req); +status_t nbd_dequeue_request(struct nbd_device, uint64 handle, struct nbd_request_entry **req); +status_t nbd_free_request(struct nbd_device, struct nbd_request_entry *req); + +#pragma mark ==== request manager ==== + + +#pragma mark ==== nbd handler ==== + +int32 postoffice(void *arg) +{ + struct nbd_device *dev = (struct nbd_device *)arg; + int sock = dev->sock; + + + + return 0; +} + +#pragma mark ==== device hooks ==== + +status_t nbd_open(const char *name, uint32 flags, cookie_t **cookie) { + (void)name; (void)flags; + *cookie = (void*)malloc(sizeof(cookie_t)); + if (*cookie == NULL) { + dprintf("nbd_open : error allocating cookie\n"); + goto err0; + } + memset(*cookie, 0, sizeof(cookie_t)); + return B_OK; +err0: + return B_ERROR; +} + +status_t nbd_close(void *cookie) { + (void)cookie; + return B_OK; +} + +status_t nbd_free(cookie_t *cookie) { + free(cookie); + return B_OK; +} + +status_t nbd_control(cookie_t *cookie, uint32 op, void *data, size_t len) { + switch (op) { + case B_GET_DEVICE_SIZE: /* this one is broken anyway... */ + if (data) { + *(size_t *)data = (size_t)cookie->dev->size; + return B_OK; + } + return EINVAL; + case B_SET_DEVICE_SIZE: /* broken */ + return EINVAL; + case B_SET_NONBLOCKING_IO: + return EINVAL; + case B_SET_BLOCKING_IO: + return B_OK; + case B_GET_READ_STATUS: + case B_GET_WRITE_STATUS: + if (data) { + *(bool *)data = false; + return B_OK; + } + return EINVAL; + case B_GET_GEOMETRY: + case B_GET_BIOS_GEOMETRY: + if (data) { + device_geometry *geom = (device_geometry *)data; + geom->bytes_per_sector = 256; + geom->sectors_per_track = 1; + geom->cylinder_count = cookie->dev->size / 256; + geom->head_count = 1; + geom->device_type = B_DISK; + geom->removable = false; + geom->read_only = false; // XXX + geom->write_once = false; + return B_OK; + } + return EINVAL; + case B_GET_MEDIA_STATUS: + if (data) { + *(status_t *)data = B_OK; + return B_OK; + } + return EINVAL; + + case B_EJECT_DEVICE: + case B_LOAD_MEDIA: + return ENOSYS; + case B_FLUSH_DRIVE_CACHE: /* wait for request list to be empty ? */ + default: + return ENOSYS; + } + return B_NOT_ALLOWED; +} + +status_t nbd_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes) { + *numbytes = 0; + return B_NOT_ALLOWED; +} + +status_t nbd_write(cookie_t *cookie, off_t position, const void *data, size_t *numbytes) { + (void)cookie; (void)position; (void)data; (void)numbytes; + *numbytes = 0; + return EIO; +} + +device_hooks nbd_hooks={ + (device_open_hook)nbd_open, + nbd_close, + (device_free_hook)nbd_free, + (device_control_hook)nbd_control, + (device_read_hook)nbd_read, + (device_write_hook)nbd_write, + NULL, + NULL, + NULL, + NULL +}; + + +#pragma mark ==== driver hooks ==== + +static const char *nbd_name[MAX_NBDS+1] = { + NULL +}; + +status_t +init_hardware (void) +{ + return B_OK; +} + +status_t +init_driver (void) +{ + int i; + // load settings + for (i = 0; i < MAX_NBDS; i++) { + nbd_name[i] = malloc(DEVICE_NAME_MAX); + if (nbd_name[i] == NULL) + break; + sprintf(nbd_name[i], DEVICE_FMT, i); + } + nbd_name[i] = NULL; + return B_OK; +} + +void +uninit_driver (void) +{ + int i; + for (i = 0; i < MAX_NBDS; i++) { + free(nbd_name[i]); + } +} + +const char** +publish_devices() +{ + return nbd_name; +} + +device_hooks* +find_device(const char* name) +{ + return &nbd_hooks; +} diff --git a/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd.h b/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd.h new file mode 100644 index 0000000000..9494cdd788 --- /dev/null +++ b/src/add-ons/kernel/drivers/disk/virtual/nbd/nbd.h @@ -0,0 +1,46 @@ +/* + * Network Block Device protocol + * Copyright 2006-2007, François Revol. All rights reserved. + * Distributed under the terms of the MIT License. + * + * references: + * include/linux/nbd.h + */ + +enum { + NBD_CMD_READ = 0, + NBD_CMD_WRITE, + NBD_CMD_DISC +}; + +#define NBD_REQUEST_MAGIC 0x25609513 +#define NBD_REPLY_MAGIC 0x67446698 + +/* in network byte order */ +struct nbd_request { + uint32 magic; /* REQUEST_MAGIC */ + uint32 type; + uint64 handle; //char handle[8]; + uint64 from; + uint32 len; +} _PACKED; + +/* in network byte order */ +struct nbd_reply { + uint32 magic; /* REPLY_MAGIC */ + uint32 error; + uint64 handle; //char handle[8]; +} _PACKED; + +/* initialization protocol (ENBD ? or at least Linux specific ?) */ + +#define NBD_INIT_PASSWD "NBDMAGIC" +#define NBD_INIT_MAGIC 0x0000420281861253LL + +/* in network byte order */ +struct nbd_init_packet { + uint8 passwd[8]; /* "NBDMAGIC" */ + uint64 magic; /* INIT_MAGIC */ + uint64 device_size; /* size in bytes */ + uint8 dummy[128]; /* reserved for future use */ +} _PACKED; \ No newline at end of file