>From 45ac091794bd7b96e7b0cb01852f3bee72c29168 Mon Sep 17 00:00:00 2001 From: Damien Zammit Date: Sun, 29 Mar 2020 22:37:23 +1100 Subject: [PATCH] rumpdisk: Add userspace disk support via librump --- Makefile | 1 + rumpdisk/Makefile | 36 +++++ rumpdisk/block-rump.c | 351 ++++++++++++++++++++++++++++++++++++++++++ rumpdisk/block-rump.h | 6 + rumpdisk/main.c | 20 +++ 5 files changed, 414 insertions(+) create mode 100644 rumpdisk/Makefile create mode 100644 rumpdisk/block-rump.c create mode 100644 rumpdisk/block-rump.h create mode 100644 rumpdisk/main.c diff --git a/Makefile b/Makefile index 6b1e8066..0e23c5b2 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,7 @@ prog-subdirs = auth proc exec term \ devnode \ eth-multiplexer \ acpi \ + rumpdisk \ shutdown ifeq ($(HAVE_SUN_RPC),yes) diff --git a/rumpdisk/Makefile b/rumpdisk/Makefile new file mode 100644 index 00000000..227f6187 --- /dev/null +++ b/rumpdisk/Makefile @@ -0,0 +1,36 @@ +# +# Copyright (C) 2019 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2, or (at +# your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +RUMPPATH=/usr/lib +RUMPLIBS=rump rumpuser rumpdev rumpdev_disk rumpdev_pci rumpvfs rumpdev_ahcisata +RUMPEXTRA=rumpdev_scsipi + +dir := rumpdisk +makemode := server + +SRCS = main.c block-rump.c +LCLHDRS = block-rump.h +target = rumpdisk +OBJS = $(SRCS:.c=.o) +HURDLIBS = machdev ports +LDLIBS += -lpthread +LDLIBS += $(RUMPLIBS:%=-l%) $(RUMPEXTRA:%=-l%) + +include ../Makeconf + +rumpdisk.static: main.o block-rump.o + $(CC) -static main.o block-rump.o -Wl,--whole-archive $(RUMPLIBS:%=$(RUMPPATH)/lib%_pic.a) ../libmachdev/libmachdev_pic.a -Wl,--no-whole-archive $(RUMPEXTRA:%=$(RUMPPATH)/lib%_pic.a) ../libtrivfs/libtrivfs_pic.a ../libshouldbeinlibc/libshouldbeinlibc_pic.a ../libports/libports_pic.a ../libiohelp/libiohelp_pic.a ../libihash/libihash_pic.a ../libfshelp/libfshelp_pic.a /usr/lib/i386-gnu/libpthread.a /usr/lib/i386-gnu/libpciaccess.a /usr/lib/i386-gnu/libdl.a -o $@ diff --git a/rumpdisk/block-rump.c b/rumpdisk/block-rump.c new file mode 100644 index 00000000..424fc4ef --- /dev/null +++ b/rumpdisk/block-rump.c @@ -0,0 +1,351 @@ +/* + * Rump block driver support + * + * Copyright (C) 2019 Free Software Foundation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "mach_U.h" + +#include +#include +#include + +#define MACH_INCLUDE + +#include "libmachdev/machdev.h" +#include "device_reply_U.h" + +#include +#include +#include + +/* rump ioctl stuff */ +#define IOCPARM_MASK 0x1fff +#define IOCPARM_SHIFT 16 +#define IOCGROUP_SHIFT 8 +#define _IOC(inout, group, num, len) \ + ((inout) | (((len) & IOCPARM_MASK) << IOCPARM_SHIFT) | \ + ((group) << IOCGROUP_SHIFT) | (num)) +#define IOC_OUT (unsigned long)0x40000000 +#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t)) +#define DIOCGMEDIASIZE _IOR('d', 132, off_t) +#define DIOCGSECTORSIZE _IOR('d', 133, unsigned int) + +#define DISK_NAME_LEN 32 + +/* One of these is associated with each open instance of a device. */ +struct block_data +{ + struct port_info port; /* device port */ + struct machdev_emul_device device; /* generic device structure */ + dev_mode_t mode; /* r/w etc */ + int rump_fd; /* block device fd handle */ + char name[DISK_NAME_LEN]; /* eg /dev/wd0 */ + off_t media_size; /* total block device size */ + uint32_t block_size; /* size in bytes of 1 sector */ + bool taken; /* simple refcount */ + struct block_data *next; +}; + +/* Return a send right associated with network device ND. */ +static mach_port_t +dev_to_port (void *nd) +{ + return (nd + ? ports_get_send_right (nd) + : MACH_PORT_NULL); +} + +static struct block_data *block_head; +static struct machdev_device_emulation_ops rump_block_emulation_ops; + +static struct block_data * +search_bd (char *name) +{ + struct block_data *bd = block_head; + + while (bd) + { + if (!strcmp(bd->name, name)) + return bd; + bd = bd->next; + } + return NULL; +} + +/* BSD name of whole disk device is /dev/wdXd + * but we will receive /dev/wdX as the name */ +static char * +translate_name (char *name) +{ + char *ret; + ret = malloc (DISK_NAME_LEN); + snprintf (ret, DISK_NAME_LEN, "%sd", name); + return ret; +} + +static int dev_mode_to_rump_mode(const dev_mode_t mode) +{ + int ret = 0; + if (mode & D_READ) + { + if (mode & D_WRITE) + ret = RUMP_O_RDWR; + else + ret = RUMP_O_RDONLY; + } + else + { + if (mode & D_WRITE) + ret = RUMP_O_WRONLY; + } + return ret; +} + +static void +device_init (void) +{ + rump_init(); +} + +static io_return_t +device_close (void *d) +{ + io_return_t err; + struct block_data *bd = d; + + err = rump_errno2host (rump_sys_close (bd->rump_fd)); + + return err; +} + +static void +device_dealloc (void *d) +{ + rump_sys_reboot(0, NULL); +} + +static io_return_t +device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, + dev_mode_t mode, char *name, device_t *devp, + mach_msg_type_name_t *devicePoly) +{ + io_return_t err = D_SUCCESS; + struct block_data *bd = NULL; + char *dev_name; + off_t media_size; + uint32_t block_size; + + dev_name = translate_name (name); + + /* Find previous device or open if new */ + bd = search_bd (name); + if (!bd) + { + err = machdev_create_device_port (sizeof (*bd), &bd); + + snprintf(bd->name, DISK_NAME_LEN, "%s", name); + bd->mode = mode; + bd->device.emul_data = bd; + bd->device.emul_ops = &rump_block_emulation_ops; + bd->next = block_head; + block_head = bd; + + err = rump_sys_open (dev_name, dev_mode_to_rump_mode (bd->mode)); + if (err < 0) + { + mach_print ("rump_sys_open fails: "); + mach_print (dev_name); + mach_print ("\n"); + err = rump_errno2host (errno); + goto out; + } + bd->rump_fd = err; + + err = rump_sys_ioctl (bd->rump_fd, DIOCGMEDIASIZE, &media_size); + if (err < 0) + { + mach_print ("DIOCGMEDIASIZE ioctl fails\n"); + err = D_NO_SUCH_DEVICE; + goto out; + } + + err = rump_sys_ioctl (bd->rump_fd, DIOCGSECTORSIZE, &block_size); + if (err < 0) + { + mach_print ("DIOCGSECTORSIZE ioctl fails\n"); + err = D_NO_SUCH_DEVICE; + goto out; + } + bd->media_size = media_size; + bd->block_size = block_size; + + err = D_SUCCESS; + } + +out: + free (dev_name); + if (err) + { + if (bd) + { + ports_port_deref (bd); + ports_destroy_right (bd); + bd = NULL; + } + } + + if (bd) + { + *devp = ports_get_right (bd); + *devicePoly = MACH_MSG_TYPE_MAKE_SEND; + } + return err; +} + +static io_return_t +device_write (void *d, mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, dev_mode_t mode, + recnum_t bn, io_buf_ptr_t data, unsigned int count, + int *bytes_written) +{ + struct block_data *bd = d; + io_return_t err = D_SUCCESS; + + if ((bd->mode & D_WRITE) == 0) + return D_INVALID_OPERATION; + + if (rump_sys_lseek (bd->rump_fd, (off_t)bn * bd->block_size, SEEK_SET) < 0) + { + *bytes_written = 0; + return EIO; + } + + err = rump_sys_write (bd->rump_fd, data, count); + if (err < 0) + { + *bytes_written = 0; + return EIO; + } + else + { + *bytes_written = err; + return D_SUCCESS; + } +} + +static io_return_t +device_read (void *d, mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, dev_mode_t mode, + recnum_t bn, int count, io_buf_ptr_t *data, + unsigned *bytes_read) +{ + struct block_data *bd = d; + io_return_t err = D_SUCCESS; + char *buf; + int pagesize = sysconf(_SC_PAGE_SIZE); + int npages = (count + pagesize - 1) / pagesize; + + if ((bd->mode & D_READ) == 0) + return D_INVALID_OPERATION; + + if (count == 0) + return D_SUCCESS; + + *data = 0; + buf = mmap (NULL, npages * pagesize, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); + if (buf == MAP_FAILED) + return errno; + + if (rump_sys_lseek(bd->rump_fd, (off_t)bn * bd->block_size, SEEK_SET) < 0) + { + *bytes_read = 0; + return EIO; + } + + err = rump_sys_read(bd->rump_fd, buf, count); + if (err < 0) + { + *bytes_read = 0; + return EIO; + } + else + { + *bytes_read = err; + *data = buf; + return D_SUCCESS; + } +} + +static io_return_t +device_get_status (void *d, dev_flavor_t flavor, dev_status_t status, + mach_msg_type_number_t *count) +{ + struct block_data *bd = d; + + switch (flavor) + { + case DEV_GET_SIZE: + status[DEV_GET_SIZE_RECORD_SIZE] = bd->block_size; + status[DEV_GET_SIZE_DEVICE_SIZE] = bd->media_size; + *count = 2; + break; + case DEV_GET_RECORDS: + status[DEV_GET_RECORDS_RECORD_SIZE] = bd->block_size; + status[DEV_GET_RECORDS_DEVICE_RECORDS] = bd->media_size / (unsigned long long)bd->block_size; + *count = 2; + break; + default: + return D_INVALID_OPERATION; + break; + } + return D_SUCCESS; +} + +static struct machdev_device_emulation_ops rump_block_emulation_ops = +{ + device_init, + NULL, + device_dealloc, + dev_to_port, + device_open, + device_close, + device_write, + NULL, + device_read, + NULL, + NULL, + device_get_status, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +void rump_register_block(void) +{ + machdev_register (&rump_block_emulation_ops); +} diff --git a/rumpdisk/block-rump.h b/rumpdisk/block-rump.h new file mode 100644 index 00000000..2824e8f5 --- /dev/null +++ b/rumpdisk/block-rump.h @@ -0,0 +1,6 @@ +#ifndef _BLOCK_RUMP_H_ +#define _BLOCK_RUMP_H_ + +void rump_register_block (void); + +#endif diff --git a/rumpdisk/main.c b/rumpdisk/main.c new file mode 100644 index 00000000..9b0cda53 --- /dev/null +++ b/rumpdisk/main.c @@ -0,0 +1,20 @@ +#include "libmachdev/machdev.h" +#include "block-rump.h" +#include +#include + +int main() +{ + int err; + pthread_t t; + + rump_register_block (); + machdev_device_init (); + machdev_trivfs_init (); + err = pthread_create (&t, NULL, machdev_server, NULL); + if (err) + return err; + pthread_detach (t); + machdev_trivfs_server (); + return 0; +} -- 2.25.1