>From fd76bb26a629dbe42840ff8807047fe531494bc0 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 | 4 + configure.ac | 14 ++ rumpdisk/Makefile | 35 +++++ rumpdisk/block-rump.c | 341 ++++++++++++++++++++++++++++++++++++++++++ rumpdisk/block-rump.h | 23 +++ rumpdisk/ioc-rump.h | 32 ++++ rumpdisk/main.c | 39 +++++ 7 files changed, 488 insertions(+) create mode 100644 rumpdisk/Makefile create mode 100644 rumpdisk/block-rump.c create mode 100644 rumpdisk/block-rump.h create mode 100644 rumpdisk/ioc-rump.h create mode 100644 rumpdisk/main.c diff --git a/Makefile b/Makefile index 6b1e8066..caf99921 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,10 @@ prog-subdirs = auth proc exec term \ acpi \ shutdown +ifeq ($(HAVE_LIBRUMP),1) +prog-subdirs += rumpdisk +endif + ifeq ($(HAVE_SUN_RPC),yes) prog-subdirs += nfs nfsd endif diff --git a/configure.ac b/configure.ac index 897a9146..76c10df3 100644 --- a/configure.ac +++ b/configure.ac @@ -243,6 +243,20 @@ AS_IF([test "x$with_libz" != xno], [ ]) AC_SUBST([HAVE_LIBZ]) +AC_ARG_WITH([librump], + [AS_HELP_STRING([--without-librump], [disable librump])], , [with_librump=yes]) + +AC_DEFUN([LIBRUMP_FAIL], [ + AC_MSG_FAILURE([Please install required libraries or use --without-librump.]) +]) +AS_IF([test "x$with_librump" != xno], [ + AC_CHECK_HEADER([rump/rump.h], + [AC_DEFINE(HAVE_RUMP_RUMP_H)], + [LIBRUMP_FAIL]) + AC_CHECK_LIB(rump, rump_init, [HAVE_LIBRUMP=1], [LIBRUMP_FAIL]) +]) +AC_SUBST([HAVE_LIBRUMP]) + AC_ARG_ENABLE(boot-store-types, [ --enable-boot-store-types=TYPES... list of store types included in statically diff --git a/rumpdisk/Makefile b/rumpdisk/Makefile new file mode 100644 index 00000000..ab4c3ef7 --- /dev/null +++ b/rumpdisk/Makefile @@ -0,0 +1,35 @@ +# +# 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 ioc-rump.h +target = rumpdisk +OBJS = $(SRCS:.c=.o) +HURDLIBS = machdev ports trivfs shouldbeinlibc iohelp ihash fshelp +LDLIBS += -lpthread -lpciaccess -ldl +LDLIBS += -Wl,--whole-archive $(RUMPLIBS:%=$(RUMPPATH)/lib%_pic.a) -Wl,--no-whole-archive $(RUMPEXTRA:%=$(RUMPPATH)/lib%_pic.a) + +include ../Makeconf + +rumpdisk.static: main.o block-rump.o diff --git a/rumpdisk/block-rump.c b/rumpdisk/block-rump.c new file mode 100644 index 00000000..6ab66eeb --- /dev/null +++ b/rumpdisk/block-rump.c @@ -0,0 +1,341 @@ +/* + * 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 +#include "ioc-rump.h" + +#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 void +translate_name (char *name, char *output) +{ + snprintf (output, DISK_NAME_LEN, "%sd", name); +} + +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[DISK_NAME_LEN + 1]; + off_t media_size; + uint32_t block_size; + + translate_name (name, dev_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) + { + 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: + 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; + int64_t written = 0; + + 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; + } + + written = rump_sys_write (bd->rump_fd, data, count); + if (written < 0) + { + *bytes_written = 0; + return EIO; + } + else + { + *bytes_written = (int)written; + 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; + munmap (buf, npages * pagesize); + 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; +} + +/* FIXME: + * Call rump_sys_aio_read/write and return MIG_NO_REPLY from + * device_read/write, and send the mig reply once the aio request has + * completed. That way, only the aio request will be kept in rumpdisk + * memory instead of a whole thread structure. + */ +static struct machdev_device_emulation_ops rump_block_emulation_ops = { + device_init, + NULL, + device_dealloc, + dev_to_port, + device_open, + device_close, + device_write, /* FIXME: make multithreaded */ + NULL, + device_read, /* FIXME: make multithreaded */ + 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..be70b9eb --- /dev/null +++ b/rumpdisk/block-rump.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020 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. + */ +#ifndef _BLOCK_RUMP_H_ +#define _BLOCK_RUMP_H_ + +void rump_register_block (void); + +#endif diff --git a/rumpdisk/ioc-rump.h b/rumpdisk/ioc-rump.h new file mode 100644 index 00000000..c7d51a4e --- /dev/null +++ b/rumpdisk/ioc-rump.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 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. + */ +#ifndef _IOC_RUMP_H_ +#define _IOC_RUMP_H_ + +#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) + +#endif diff --git a/rumpdisk/main.c b/rumpdisk/main.c new file mode 100644 index 00000000..0181f685 --- /dev/null +++ b/rumpdisk/main.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 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 "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