diff --git a/build/meta-bsp/recipes-bsp/linux/bsp-linux_1.0.bb b/build/meta-bsp/recipes-bsp/linux/bsp-linux_1.0.bb index 374a739a3..56764e1bb 100644 --- a/build/meta-bsp/recipes-bsp/linux/bsp-linux_1.0.bb +++ b/build/meta-bsp/recipes-bsp/linux/bsp-linux_1.0.bb @@ -170,16 +170,31 @@ addtask do_prepare_initrd before do_itb # Deploy everything # # Deploy is decoupled from the build: it writes the already-built artefacts -# onto the boot media WITHOUT recompiling. It pulls rootfs-linux:do_deploy -# (which extracts the final rootfs.cpio — apps baked in at build time — onto -# p2) and writes the .itb produced by do_itb during `build.sh -a` onto p1 -# (__do_platform_deploy). It does NOT pull do_build / do_itb / usr-linux's -# rootfs.cpio populate — those belong to `build.sh -a`. Workflow: -# edit -> build.sh -> deploy.sh. A deploy with no prior build fails clearly -# (missing rootfs.cpio / .itb) rather than silently rebuilding. +# onto the boot media WITHOUT recompiling. The rootfs is extracted onto p2 +# (rootfs-linux:do_deploy); when p2 is the running root (IB_RAMFS_SOURCE other +# than "rootfs") it also pulls usr-linux:do_deploy, which copies the usr apps +# (linux/usr/build/deploy) on top — see the anonymous function below. With +# the rootfs.cpio ramfs the apps travel inside the ITB instead. +# It then writes the .itb produced by do_itb during `build.sh -a` onto p1 +# (__do_platform_deploy). It does NOT pull do_build / do_itb / usr-linux: +# do_build — those belong to `build.sh -a`. Workflow: edit -> build.sh -> +# deploy.sh. A deploy with no prior build fails clearly (missing rootfs.cpio / +# usr build/deploy / .itb) rather than silently rebuilding. do_deploy[depends] = "filesystem:do_fs_check rootfs-linux:do_deploy" +# usr-linux:do_deploy goes where the running root is (see usr-linux_1.0.bb): +# with IB_RAMFS_SOURCE = "rootfs" it bakes the apps into rootfs.cpio, so it is +# part of the BUILD, before do_prepare_initrd gzips that cpio into the ITB; +# otherwise it copies them onto p2 and is part of the DEPLOY. + +python () { + if (d.getVar('IB_RAMFS_SOURCE') or "rootfs").strip() == "rootfs": + d.appendVarFlag('do_prepare_initrd', 'depends', ' usr-linux:do_deploy') + else: + d.appendVarFlag('do_deploy', 'depends', ' usr-linux:do_deploy') +} + do_deploy[nostamp] = "1" python do_deploy() { diff --git a/build/meta-rootfs/recipes-rootfs/linux/rootfs-linux_1.0.bb b/build/meta-rootfs/recipes-rootfs/linux/rootfs-linux_1.0.bb index 2c9118a21..ddaba2735 100644 --- a/build/meta-rootfs/recipes-rootfs/linux/rootfs-linux_1.0.bb +++ b/build/meta-rootfs/recipes-rootfs/linux/rootfs-linux_1.0.bb @@ -22,8 +22,9 @@ do_configure[noexec] = "1" do_build[depends] = "${IB_ROOTFS_METHOD}:do_build" do_build[depends] += "linux:do_build" -# do_deploy extracts rootfs.cpio (apps baked in by usr-linux:do_deploy), -# copies it onto p2 and repacks it. +# do_deploy extracts rootfs.cpio, copies it onto p2 and repacks it. The usr +# apps are either already in rootfs.cpio (IB_RAMFS_SOURCE = "rootfs") or +# copied on top afterwards by usr-linux:do_deploy. # # It DOES depend on ${IB_ROOTFS_METHOD}:do_build, and that dependency is # load-bearing rather than a leftover: nothing else orders this task after diff --git a/build/meta-usr/recipes-usr/linux/usr-linux_1.0.bb b/build/meta-usr/recipes-usr/linux/usr-linux_1.0.bb index 9eae62bd9..dfbede236 100644 --- a/build/meta-usr/recipes-usr/linux/usr-linux_1.0.bb +++ b/build/meta-usr/recipes-usr/linux/usr-linux_1.0.bb @@ -25,38 +25,99 @@ do_unpack[depends] += "linux:do_build" do_deploy[depends] = "rootfs-linux:do_deploy" do_deploy[nostamp] = "1" -# Deploy the usr contents, i.e. the deploy/ dir, in the corresponding partition of the filesystem +# Deploy the usr contents, i.e. the deploy/ dir, where the running system will +# find them. That depends on what the kernel boots as its root, and the apps go +# to ONE place only: +# +# IB_RAMFS_SOURCE = "rootfs" - the embedded ramfs IS rootfs.cpio, so the apps +# are baked INTO rootfs.cpio (rsync into the extracted tree, then re-pack). +# bsp-linux:do_prepare_initrd pulls this task into the BUILD, before it +# gzips rootfs.cpio into the ITB, so here it must not touch the boot media: +# it depends on rootfs-linux:do_build instead of rootfs-linux:do_deploy and +# runs after do_build (anonymous function below). +# +# any other value (the static "initrd" ramfs, which pivots to p2) - the apps +# are copied onto the rootfs partition p2, on top of what +# rootfs-linux:do_deploy extracted. bsp-linux:do_deploy pulls this task, +# so a full deploy always carries the user space. +# +# Unset means "rootfs", the bsp.bbclass default. + +def usr_linux_ramfs_is_rootfs(d): + return (d.getVar('IB_RAMFS_SOURCE') or "rootfs").strip() == "rootfs" + +python () { + if usr_linux_ramfs_is_rootfs(d): + d.setVarFlag('do_deploy', 'depends', 'rootfs-linux:do_build') + bb.build.addtask('do_deploy', None, 'do_build', d) +} + python do_deploy() { import os - - __do_fs_mount(d) - + IB_USR_PATH = d.getVar('IB_USR_PATH') + deploy_src = os.path.join(IB_USR_PATH, "build", "deploy") + + if not os.path.isdir(deploy_src): + bb.fatal("The {} does not exist; please build usr first...".format(deploy_src)) + + if usr_linux_ramfs_is_rootfs(d): + IB_ROOTFS_PATH = d.getVar('IB_ROOTFS_PATH') + IB_PLATFORM = d.getVar('IB_PLATFORM') + + if not os.path.isfile(os.path.join(IB_ROOTFS_PATH, "board", IB_PLATFORM, "rootfs.cpio")): + bb.fatal("rootfs.cpio is missing; please build rootfs first...") + + # The extracted tree is root-owned (cpio -id), so rsync needs root to + # write into it while preserving mode bits and ownership. + + d.setVar('ROOTFS_FILENAME', 'rootfs') + __do_rootfs_mount(d) + utils_sudo(["rsync", "-a", "--keep-dirlinks", + deploy_src + "/", f"{IB_ROOTFS_PATH}/fs/"], check=True) + __do_rootfs_umount(d) + + bb.plain("usr deployed into rootfs.cpio (IB_RAMFS_SOURCE = rootfs)") + return + + # Same exception as rootfs-linux:do_deploy: verdin-imx8mp storage goes + # through the Tezi / HTTP recovery flow, there is no p2 to mount here. + + if d.getVar('IB_PLATFORM') == "verdin-imx8mp": + bb.plain("verdin-imx8mp: rootfs delivered via Tezi/HTTP, skipping usr partition deploy") + return + IB_FILESYSTEM_PATH = d.getVar('IB_FILESYSTEM_PATH') IB_ROOTFS_PARTITION = d.getVar('IB_ROOTFS_PARTITION') + rootfs_dst = os.path.join(IB_FILESYSTEM_PATH, IB_ROOTFS_PARTITION) - if not os.path.isdir(os.path.join(IB_USR_PATH, "build", "deploy")): - - __do_fs_umount(d) - bb.fatal("The {} does not exist; please build usr first...".format(IB_USR_PATH)) + __do_fs_mount(d) - if not os.path.isdir(os.path.join(IB_FILESYSTEM_PATH, IB_ROOTFS_PARTITION, "root")): + if not os.path.isdir(os.path.join(rootfs_dst, "root")): __do_fs_umount(d) bb.fatal("The root directory is not present in the second partition; please deploy rootfs...") - - - os.system("cp -r {}/build/deploy/* {}/{}/".format(IB_USR_PATH, IB_FILESYSTEM_PATH, IB_ROOTFS_PARTITION)) - - __do_fs_umount(d) + + # p2 is written by rootfs-linux:do_deploy with `sudo cp -a`, so its tree + # is root-owned: the copy needs root too. --keep-dirlinks keeps the + # rootfs directory symlinks (e.g. /lib -> usr/lib) instead of replacing + # them with real directories. check=True: a failed copy must fail the + # deploy, not leave a rootfs silently without the apps. + + try: + utils_sudo(["rsync", "-a", "--keep-dirlinks", + deploy_src + "/", rootfs_dst + "/"], check=True) + finally: + __do_fs_umount(d) } -# `after do_build`: do_deploy copies build/deploy/ into the rootfs, so the -# recipe's own do_build must have produced it first. Without this ordering -# a single-shot `bitbake bsp-linux` (whose do_prepare_initrd pulls this -# do_deploy early) can schedule do_deploy before do_build and fatal on the -# missing build/deploy dir. -addtask do_deploy after do_build +# No static `after do_build`: in the p2 case do_deploy is a pure deploy step +# (edit -> build.sh -> deploy.sh) that copies the already-built build/deploy/ +# and fails clearly when it is missing, instead of dragging usr-linux:do_build +# (and linux:do_build through do_unpack) into every deploy. The rootfs.cpio +# case, which runs inside the build, gets its ordering above. + +addtask do_deploy # Build extra components which is not in src/ directory like modules do_build:prepend () {