From 7c5ca58cbcaeaea20653ee430ee39694a976aaab Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 30 Jan 2015 10:58:52 +0000 Subject: [PATCH] Initial commit. --- .gitignore | 7 +++ Makefile | 52 +++++++++++++++++++ init.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 init.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4348522 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*~ +*.ko + +/dev +/init +/initrd +/sd*.img diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a232ee6 --- /dev/null +++ b/Makefile @@ -0,0 +1,52 @@ +kver = 3.19.0-0.rc5.git2.1.fc22.aarch64 +modules = virtio.ko virtio_ring.ko virtio_mmio.ko virtio_scsi.ko +disks = sda.img sdb.img sdc.img sdd.img sde.img sdf.img + +all: initrd $(disks) + +initrd: dev init $(modules) + ls -1d $^ | cpio -o -H newc | gzip -9 > $@ + +dev: + rm -rf $@ + mkdir $@ + +%.ko: + find /lib/modules/$(kver) -name $@ -exec cp {} . \; + +init: init.c + gcc -Wall -Werror -static $< -o $@ + +%.img: + rm -f $@ + truncate -s 1G $@ + +clean: + rm -f $(disks) $(modules) init initrd + +kernel = /boot/vmlinuz-$(kver) +qemu = qemu-system-aarch64 + +run: initrd $(disks) + $(qemu) \ + -nodefconfig -nodefaults -display none \ + -machine virt,accel=kvm \ + -no-reboot \ + -cpu host \ + -m 1024 \ + -kernel $(kernel) -initrd initrd \ + -append 'panic=1 earlyprintk=pl011,0x9000000 ignore_loglevel console=ttyAMA0 no_timer_check printk.time=1' \ + -serial stdio \ + -device virtio-scsi-device,id=scsi \ + -drive file=sda.img,cache=writeback,format=raw,if=none,id=sda \ + -device scsi-hd,drive=sda \ + -drive file=sdb.img,cache=writeback,format=raw,if=none,id=sdb \ + -device scsi-hd,drive=sdb \ + -drive file=sdc.img,cache=writeback,format=raw,if=none,id=sdc \ + -device scsi-hd,drive=sdc \ + -drive file=sdd.img,cache=writeback,format=raw,if=none,id=sdd \ + -device scsi-hd,drive=sdd \ + -drive file=sde.img,cache=writeback,format=raw,if=none,id=sde \ + -device scsi-hd,drive=sde \ + -drive file=sdf.img,cache=writeback,format=raw,if=none,id=sdf \ + -device scsi-hd,drive=sdf diff --git a/init.c b/init.c new file mode 100644 index 0000000..4694818 --- /dev/null +++ b/init.c @@ -0,0 +1,173 @@ +/* Try to reproduce RHBZ#1184405. + * Note: needs to be linked statically. + * By Richard W.M. Jones + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern long init_module (void *, unsigned long, const char *); + +/* NB! Must match the number of disks in Makefile. */ +#define NR_SCSI_DISKS 6 + +/* NB! Must match the module list in Makefile. Also they must be + * in module dependency order. + */ +static const char *modules[] = { + "virtio.ko", + "virtio_ring.ko", + "virtio_mmio.ko", + "virtio_scsi.ko", + NULL +}; + +static void load_modules (void); +static void make_devices (void); +static void run_test (const char *dev); + +int +main (int argc, char *argv[]) +{ + int i; + char dev[] = "/dev/sda"; + int child_pids[NR_SCSI_DISKS-1]; + + printf ("init: started\n"); + load_modules (); + + /* Really we should wait for the kernel to probe devices, but bleah. */ + sleep (2); + + make_devices (); + + for (i = 0; i < NR_SCSI_DISKS-1; ++i) { + child_pids[i] = fork (); + if (child_pids[i] == -1) { + perror ("fork"); + exit (EXIT_FAILURE); + } + if (child_pids[i] == 0) { /* child */ + dev[7] = 'a' + i + 1; /* /dev/sd[b..] */ + run_test (dev); + _exit (EXIT_SUCCESS); + } + } + + run_test (dev); /* /dev/sda test in parent */ + + for (i = 0; i < NR_SCSI_DISKS-1; ++i) { + waitpid (child_pids[i], NULL, 0); + } + + printf ("init: parent process exiting\n"); + exit (EXIT_SUCCESS); +} + +static char buffer[BUFSIZ]; +#define MIN(a,b) ((a)<(b)?(a):(b)) + +static void +run_test (const char *dev) +{ + int fd; + uint64_t size; + ssize_t r; + + printf ("init: testing %s\n", dev); + fflush (stdout); + + fd = open (dev, O_RDONLY); + if (fd == -1) { + perror (dev); + _exit (EXIT_FAILURE); + } + if (ioctl (fd, BLKGETSIZE64, &size) == -1) { + perror ("ioctl: BLKGETSIZE64"); + _exit (EXIT_FAILURE); + } + + while (size > 0) { + r = read (fd, buffer, MIN (BUFSIZ, size)); + if (r == -1) { + perror ("read"); + _exit (EXIT_FAILURE); + } + size -= r; + } + + if (close (fd) == -1) { + perror ("close"); + _exit (EXIT_FAILURE); + } + + printf ("init: test of %s finished successfully\n", dev); + fflush (stdout); +} + +/* Originally taken from supermin's init.c */ +static void +load_modules (void) +{ + size_t i; + int fd; + struct stat statbuf; + size_t size; + ssize_t r; + + for (i = 0; modules[i] != NULL; ++i) { + printf ("init: loading module %s\n", modules[i]); + + fd = open (modules[i], O_RDONLY); + if (fd == -1) { + perror (modules[i]); + exit (EXIT_FAILURE); + } + if (fstat (fd, &statbuf) == -1) { + perror (modules[i]); + exit (EXIT_FAILURE); + } + char buf[size = statbuf.st_size]; + while (size > 0) { + r = read (fd, buf, size); + if (r == -1) { + perror ("read"); + exit (EXIT_FAILURE); + } + size -= r; + } + close (fd); + + if (init_module (buf, statbuf.st_size, "") != 0) { + fprintf (stderr, "insmod: "); + perror (modules[i]); + exit (EXIT_FAILURE); + } + } +} + +/* Much less trouble than udev! */ +static void +make_devices (void) +{ + int i; + char dev[] = "/dev/sda"; + + printf ("init: creating device nodes\n"); + + for (i = 0; i < NR_SCSI_DISKS; ++i) { + dev[7] = 'a' + i; + if (mknod (dev, S_IFBLK, makedev (8, 16*i)) == -1) { + perror (dev); + exit (EXIT_FAILURE); + } + } +} -- 1.8.3.1