diff --git a/Dockerfile b/Dockerfile index b9094909e..0748c3a53 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,8 +44,8 @@ FROM --platform=arm64 ghcr.io/talos-systems/libressl:${PKGS} AS pkg-libressl-arm FROM --platform=amd64 ghcr.io/talos-systems/libseccomp:${PKGS} AS pkg-libseccomp-amd64 FROM --platform=arm64 ghcr.io/talos-systems/libseccomp:${PKGS} AS pkg-libseccomp-arm64 -FROM --platform=amd64 ghcr.io/talos-systems/linux-firmware:${PKGS} AS pkg-linux-firmware-amd64 -FROM --platform=arm64 ghcr.io/talos-systems/linux-firmware:${PKGS} AS pkg-linux-firmware-arm64 +# linux-firmware is not arch-specific +FROM --platform=amd64 ghcr.io/talos-systems/linux-firmware:${PKGS} AS pkg-linux-firmware FROM --platform=amd64 ghcr.io/talos-systems/lvm2:${PKGS} AS pkg-lvm2-amd64 FROM --platform=arm64 ghcr.io/talos-systems/lvm2:${PKGS} AS pkg-lvm2-arm64 @@ -359,8 +359,6 @@ COPY --from=pkg-libjson-c-amd64 / /rootfs COPY --from=pkg-libpopt-amd64 / /rootfs COPY --from=pkg-libressl-amd64 / /rootfs COPY --from=pkg-libseccomp-amd64 / /rootfs -COPY --from=pkg-linux-firmware-amd64 /lib/firmware/bnx2 /rootfs/lib/firmware/bnx2 -COPY --from=pkg-linux-firmware-amd64 /lib/firmware/bnx2x /rootfs/lib/firmware/bnx2x COPY --from=pkg-lvm2-amd64 / /rootfs COPY --from=pkg-libaio-amd64 / /rootfs COPY --from=pkg-musl-amd64 / /rootfs @@ -378,7 +376,7 @@ COPY --from=machined-build-amd64 /machined /rootfs/sbin/init # symlinks to avoid accidentally cleaning them up. COPY ./hack/cleanup.sh /toolchain/bin/cleanup.sh RUN cleanup.sh /rootfs -RUN mkdir -pv /rootfs/{boot,etc/cri/conf.d/hosts,usr/local/share,mnt,system,opt} +RUN mkdir -pv /rootfs/{boot,etc/cri/conf.d/hosts,lib/firmware,usr/local/share,mnt,system,opt} RUN mkdir -pv /rootfs/{etc/kubernetes/manifests,etc/cni/net.d,usr/libexec/kubernetes} RUN mkdir -pv /rootfs/opt/{containerd/bin,containerd/lib} COPY --chmod=0644 hack/containerd.toml /rootfs/etc/containerd/config.toml @@ -402,10 +400,6 @@ COPY --from=pkg-libjson-c-arm64 / /rootfs COPY --from=pkg-libpopt-arm64 / /rootfs COPY --from=pkg-libressl-arm64 / /rootfs COPY --from=pkg-libseccomp-arm64 / /rootfs -COPY --from=pkg-linux-firmware-arm64 /lib/firmware/bnx2 /rootfs/lib/firmware/bnx2 -COPY --from=pkg-linux-firmware-arm64 /lib/firmware/bnx2x /rootfs/lib/firmware/bnx2x -COPY --from=pkg-linux-firmware-arm64 /lib/firmware/rtl_nic /rootfs/lib/firmware/rtl_nic -COPY --from=pkg-linux-firmware-arm64 /lib/firmware/nvidia/tegra210 /rootfs/lib/firmware/nvidia/tegra210 COPY --from=pkg-lvm2-arm64 / /rootfs COPY --from=pkg-libaio-arm64 / /rootfs COPY --from=pkg-musl-arm64 / /rootfs @@ -423,7 +417,7 @@ COPY --from=machined-build-arm64 /machined /rootfs/sbin/init # symlinks to avoid accidentally cleaning them up. COPY ./hack/cleanup.sh /toolchain/bin/cleanup.sh RUN cleanup.sh /rootfs -RUN mkdir -pv /rootfs/{boot,etc/cri/conf.d/hosts,usr/local/share,mnt,system,opt} +RUN mkdir -pv /rootfs/{boot,etc/cri/conf.d/hosts,lib/firmware,usr/local/share,mnt,system,opt} RUN mkdir -pv /rootfs/{etc/kubernetes/manifests,etc/cni/net.d,usr/libexec/kubernetes} RUN mkdir -pv /rootfs/opt/{containerd/bin,containerd/lib} COPY --chmod=0644 hack/containerd.toml /rootfs/etc/containerd/config.toml @@ -463,8 +457,8 @@ WORKDIR /initramfs COPY --from=squashfs-arm64 /rootfs.sqsh . COPY --from=init-build-arm64 /init . # copying over firmware binary blobs to initramfs -COPY --from=pkg-linux-firmware-arm64 /lib/firmware/rtl_nic ./lib/firmware/rtl_nic -COPY --from=pkg-linux-firmware-arm64 /lib/firmware/nvidia/tegra210 ./lib/firmware/nvidia/tegra210 +COPY --from=pkg-linux-firmware /lib/firmware/rtl_nic ./lib/firmware/rtl_nic +COPY --from=pkg-linux-firmware /lib/firmware/nvidia/tegra210 ./lib/firmware/nvidia/tegra210 RUN find . -print0 \ | xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}" RUN set -o pipefail \ @@ -478,6 +472,9 @@ FROM build AS initramfs-archive-amd64 WORKDIR /initramfs COPY --from=squashfs-amd64 /rootfs.sqsh . COPY --from=init-build-amd64 /init . +# copying over firmware binary blobs to initramfs +COPY --from=pkg-linux-firmware /lib/firmware/bnx2 ./lib/firmware/bnx2 +COPY --from=pkg-linux-firmware /lib/firmware/bnx2x ./lib/firmware/bnx2x RUN find . -print0 \ | xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}" RUN set -o pipefail \ diff --git a/internal/app/init/main.go b/internal/app/init/main.go index c9edd8ed4..552d5e6e7 100644 --- a/internal/app/init/main.go +++ b/internal/app/init/main.go @@ -57,6 +57,11 @@ func run() (err error) { return err } + // Bind mount the lib/firmware if needed. + if err = bindMountFirmware(); err != nil { + return err + } + // Switch into the new rootfs. log.Println("entering the rootfs") @@ -172,6 +177,20 @@ func mountRootFS() error { return nil } +func bindMountFirmware() error { + if _, err := os.Stat(constants.FirmwarePath); err != nil { + if os.IsNotExist(err) { + return nil + } + + return err + } + + log.Printf("bind mounting %s", constants.FirmwarePath) + + return unix.Mount(constants.FirmwarePath, filepath.Join(constants.NewRoot, constants.FirmwarePath), "", unix.MS_BIND|unix.MS_RDONLY, "") +} + func main() { defer recovery() diff --git a/internal/pkg/mount/switchroot/switchroot.go b/internal/pkg/mount/switchroot/switchroot.go index 0be3dc5bb..6ce361d54 100644 --- a/internal/pkg/mount/switchroot/switchroot.go +++ b/internal/pkg/mount/switchroot/switchroot.go @@ -20,6 +20,7 @@ import ( // Paths preserved in the initramfs. var preservedPaths = map[string]struct{}{ constants.ExtensionsConfigFile: {}, + constants.FirmwarePath: {}, } // Switch moves the rootfs to a specified directory. See @@ -60,7 +61,7 @@ func Switch(prefix string, mountpoints *mount.Points) (err error) { log.Println("cleaning up initramfs") - if err = recursiveDelete(int(old.Fd()), "/"); err != nil { + if _, err = recursiveDelete(int(old.Fd()), "/"); err != nil { return fmt.Errorf("error deleting initramfs: %w", err) } @@ -83,10 +84,10 @@ func Switch(prefix string, mountpoints *mount.Points) (err error) { return nil } -func recursiveDelete(fd int, path string) error { +func recursiveDelete(fd int, path string) (preserved bool, err error) { parentDev, err := getDev(fd) if err != nil { - return err + return false, err } dir := os.NewFile(uintptr(fd), "__ignored__") @@ -95,42 +96,57 @@ func recursiveDelete(fd int, path string) error { names, err := dir.Readdirnames(-1) if err != nil { - return err + return false, err } + preserved = false + for _, name := range names { - if err := recusiveDeleteInner(fd, parentDev, name, filepath.Join(path, name)); err != nil { - return err + p, err := recusiveDeleteInner(fd, parentDev, name, filepath.Join(path, name)) + if err != nil { + return false, err } + + preserved = preserved || p } - return nil + return preserved, nil } -func recusiveDeleteInner(parentFd int, parentDev uint64, childName, path string) error { - if _, preserve := preservedPaths[path]; preserve { - return nil +func recusiveDeleteInner(parentFd int, parentDev uint64, childName, path string) (preserved bool, err error) { + if _, preserved = preservedPaths[path]; preserved { + return preserved, nil } childFd, err := unix.Openat(parentFd, childName, unix.O_DIRECTORY|unix.O_NOFOLLOW, unix.O_RDWR) if err != nil { - return unix.Unlinkat(parentFd, childName, 0) + return false, unix.Unlinkat(parentFd, childName, 0) } //nolint:errcheck defer unix.Close(childFd) - if childFdDev, err := getDev(childFd); err != nil { - return err + var childFdDev uint64 + + if childFdDev, err = getDev(childFd); err != nil { + return false, err } else if childFdDev != parentDev { - return nil + return false, nil } - if err := recursiveDelete(childFd, path); err != nil { - return err + preserved, err = recursiveDelete(childFd, path) + if err != nil { + return false, err } - return unix.Unlinkat(parentFd, childName, unix.AT_REMOVEDIR) + if preserved { + // some child paths got preserved, skip unlinking the parent + return preserved, nil + } + + err = unix.Unlinkat(parentFd, childName, unix.AT_REMOVEDIR) + + return false, err } func getDev(fd int) (dev uint64, err error) { diff --git a/pkg/machinery/constants/constants.go b/pkg/machinery/constants/constants.go index cec2d1e04..c129dad1f 100644 --- a/pkg/machinery/constants/constants.go +++ b/pkg/machinery/constants/constants.go @@ -592,6 +592,9 @@ const ( // PlatformNetworkConfigFilename is the filename to cache platform network configuration reboots. PlatformNetworkConfigFilename = "platform-network.yaml" + + // FirmwarePath is the path to the standard Linux firmware location. + FirmwarePath = "/lib/firmware" ) // See https://linux.die.net/man/3/klogctl