Skip to content

Commit

Permalink
init: wait untill btrfs multidevice gets assembled
Browse files Browse the repository at this point in the history
And only after that proceed with mounting

Fixes #194
  • Loading branch information
anatol committed Nov 2, 2022
1 parent 37ef876 commit 1b3902f
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 0 deletions.
57 changes: 57 additions & 0 deletions init/ioctl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package main

import (
"fmt"

"golang.org/x/sys/unix"
)

const (
directionNone = 0
directionWrite = 1
directionRead = 2

numberBits = 8
typeBits = 8
sizeBits = 14
directionBits = 2

numberMask = (1 << numberBits) - 1
typeMask = (1 << typeBits) - 1
sizeMask = (1 << sizeBits) - 1
directionMask = (1 << directionBits) - 1

numberShift = 0
typeShift = numberShift + numberBits
sizeShift = typeShift + typeBits
directionShift = sizeShift + sizeBits
)

// ioc calculates the ioctl command for the specified direction, type, number and size
func ioc(dir, t, nr, size uintptr) uintptr {
return (dir << directionShift) | (t << typeShift) | (nr << numberShift) | (size << sizeShift)
}

// ior calculates the ioctl command for a read-ioctl of the specified type, number and size
func ior(t, nr, size uintptr) uintptr {
return ioc(directionRead, t, nr, size)
}

// iow calculates the ioctl command for a write-ioctl of the specified type, number and size
func iow(t, nr, size uintptr) uintptr {
return ioc(directionWrite, t, nr, size)
}

// iowr calculates the ioctl command for a read/write-ioctl of the specified type, number and size
func iowr(t, nr, size uintptr) uintptr {
return ioc(directionWrite|directionRead, t, nr, size)
}

// ioctl executes an ioctl command on the specified file descriptor
func ioctl(fd, cmd, ptr uintptr) error {
_, _, errno := unix.Syscall(unix.SYS_IOCTL, fd, cmd, ptr)
if errno != 0 {
return fmt.Errorf("ioctl(0x%x): %v", cmd, errno)
}
return nil
}
30 changes: 30 additions & 0 deletions init/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"sync"
"sync/atomic"
"time"
"unsafe"

"github.com/yookoala/realpath"
"golang.org/x/sys/unix"
Expand Down Expand Up @@ -372,6 +373,12 @@ func mountRootFs(dev, fstype string) error {
wg := loadModules(fstype)
wg.Wait()

if fstype == "btrfs" {
if err := waitForBtrfsDevicesReady(dev); err != nil {
return err
}
}

if err := fsck(dev); err != nil {
return err
}
Expand All @@ -386,6 +393,29 @@ func mountRootFs(dev, fstype string) error {
return nil
}

// Wait until all devices of a multiple-device filesystem are scanned and registered within the kernel module
func waitForBtrfsDevicesReady(dev string) error {
controlFile, err := os.OpenFile("/dev/btrfs-control", os.O_RDWR, 0)
if err != nil {
return err
}
defer controlFile.Close()

/* this should be 4k */
var btrfsIoctlVolArgs struct {
fs int64
name [4088]uint8
}

warning("!!!!!!! BTRFS_IOC_DEVICES_READY for %s", dev)

copy(btrfsIoctlVolArgs.name[:], dev)

var BTRFS_IOCTL_MAGIC uintptr = 0x94
BTRFS_IOC_DEVICES_READY := ior(BTRFS_IOCTL_MAGIC, 39, unsafe.Sizeof(btrfsIoctlVolArgs))
return ioctl(controlFile.Fd(), BTRFS_IOC_DEVICES_READY, uintptr(unsafe.Pointer(&btrfsIoctlVolArgs)))
}

func mountFlags() (uintptr, string) {
rootMountFlags, options := sunderMountFlags(rootFlags, rootAutodiscoveryMountFlags)
if rootRo {
Expand Down
1 change: 1 addition & 0 deletions tests/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var assetGenerators = map[string]assetGenerator{
"lvm.img": {"lvm.sh", []string{"FS_UUID=74c9e30c-506f-4106-9f61-a608466ef29c", "FS_LABEL=lvmr00t"}},
"mdraid_raid1.img": {"mdraid_raid1.sh", []string{"FS_UUID=98b1a905-3c72-42f0-957a-6c23b303b1fd", "FS_LABEL=boosmdraid"}},
"mdraid_raid5.img": {"mdraid_raid5.sh", []string{"FS_UUID=e62c7dc0-5728-4571-b475-7745de2eef1e", "FS_LABEL=boosmdraid"}},
"btrfs_raid0.img": {"btrfs_raid0.sh", []string{"FS_UUID=5eaa0c1c-e1dc-4be7-9b03-9f1ed5a87289"}},
"archlinux.ext4.raw": {"archlinux_ext4.sh", nil},
"archlinux.btrfs.raw": {"archlinux_btrfs.sh", []string{"LUKS_PASSWORD=hello"}},
"voidlinux.img": {"voidlinux.sh", nil},
Expand Down
18 changes: 18 additions & 0 deletions tests/btrfs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package tests

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestBtrfsRaid0(t *testing.T) {
vm, err := buildVmInstance(t, Opts{
disk: "assets/btrfs_raid0.img",
kernelArgs: []string{"root=UUID=5eaa0c1c-e1dc-4be7-9b03-9f1ed5a87289"},
})
require.NoError(t, err)
defer vm.Shutdown()

require.NoError(t, vm.ConsoleExpect("Hello, booster!"))
}
37 changes: 37 additions & 0 deletions tests/generators/btrfs_raid0.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash

trap 'quit' EXIT ERR

quit() {
set +o errexit
sudo umount "${dir}"
rm -r "${dir}"
}

truncate --size 650M "${OUTPUT}"
lodev=$(sudo losetup -f -P --show "${OUTPUT}")
# create 2 partitions equal size
sudo fdisk "${lodev}" <<< "g
n
+300M
t
29
n
+300M
t
29
w
"

sudo mkfs.btrfs --uuid=$FS_UUID -d raid0 "${lodev}p1" "${lodev}p2"
dir=$(mktemp -d)
sudo mount "${lodev}p1" "${dir}"
sudo chown "${USER}" "${dir}"
mkdir "${dir}/sbin"
cp assets/init "${dir}/sbin/init"

0 comments on commit 1b3902f

Please sign in to comment.