Message ID | 20250408205709.7013-1-twoerner@gmail.com |
---|---|
State | New |
Headers | show |
Series | wic: do not ignore ROOTFS_SIZE if the rootfs is modified | expand |
On Tue Apr 8, 2025 at 10:57 PM CEST, Trevor Woerner via lists.openembedded.org wrote: > If the *.wks file contains a "--source rootfs" then > lib/wic/plugins/source/rootfs.py will be invoked to generate (what is assumed > to be) the rootfs partition. If the rootfs partition needs to be tweaked or > modified, the "rootfs.py" plugin will make a copy of the filesystem and then > perform the changes on that copy. In other words, if the "--source rootfs" > line of the *.wks file also contains any of: > > --exclude-path > --include-path > --change-directory > --use-label (i.e. modify etc/fstab) > > then the rootfs will be copied first, then the copy is modified. > > If, for example, the unmodified IMAGE_ROOTFS is: > > .../tmp/work/qemuarm64_secureboot-oe-linux/core-image-base/1.0/rootfs > > then the copy would be made at: > > .../tmp/work/qemuarm64_secureboot-oe-linux/core-image-base/1.0/tmp-wic/rootfs${LINENO} > > where ${LINENO} is the line number where this "--source rootfs" line appears > in the *wks file. > > When it comes time to make an actual partition of a specific filesystem type, > lib/wic/partition.py::prepare_rootfs() is called. It is in this function that > wic figures out if any extra size needs to be added. The bitbake variable used > to specify the ultimate rootfs size is ROOTFS_SIZE, and since this variable is > only valid for the rootfs (and not any other partitions), the code also > verifies that the partition being created is ${IMAGE_ROOTFS}: > > rsize_bb = get_bitbake_var('ROOTFS_SIZE') > rdir = get_bitbake_var('IMAGE_ROOTFS') > if rsize_bb and rdir == rootfs_dir: > <use rsize_bb> > else: > <calculate the partition size using "du -ks $p"> > > As noted above, if lib/wic/plugins/source/rootfs.py has made a copy, then the > "rdir == rootfs_dir" clause will fail and the code will assume this partition > is not a rootfs since the strings do not compare equal. > > Therefore, in order to determine if this is a rootfs, retain the existing > "rdir == rootfs_dir" comparison, but also add another one to check whether or > not this is a wic-generated copy of the rootfs. > > STEPS TO REPRODUCE: > - start with the following *wks file: > bootloader --ptable gpt > part /boot --ondisk=vda --align 64 --size=100M --active --source bootimg-partition --fstype=ext4 --label boot --sourceparams="loader=u-boot" > part / --ondisk=vda --source rootfs --fstype=ext4 --label root > - and the following extra variable in conf/local.conf: > IMAGE_ROOTFS_EXTRA_SPACE = "500000" > - build an image > - run it in qemu > $ runqemu slirp nographic serial > - verify the root partition has extra space: > root@qemuarm64-secureboot:~# df -h > Filesystem Size Used Available Use% Mounted on > /dev/root 721.5M 67.4M 600.6M 10% / > devtmpfs 477.7M 0 477.7M 0% /dev > tmpfs 40.0K 0 40.0K 0% /mnt > tmpfs 489.3M 92.0K 489.2M 0% /run > tmpfs 489.3M 68.0K 489.2M 0% /var/volatile > /dev/vda1 120.4M 19.9M 91.4M 18% /boot > - modify the "/" line of the *wks file to be: > part / --ondisk=vda --exclude-path boot/ --source rootfs --fstype=ext4 --label root > - build image > > when it fails: > root@qemuarm64-secureboot:~# df -h > Filesystem Size Used Available Use% Mounted on > /dev/root 73.4M 41.9M 25.8M 62% / > devtmpfs 477.7M 0 477.7M 0% /dev > tmpfs 40.0K 0 40.0K 0% /mnt > tmpfs 489.3M 92.0K 489.2M 0% /run > tmpfs 489.3M 68.0K 489.2M 0% /var/volatile > /dev/vda1 120.4M 19.9M 91.4M 18% /boot > > after this fix: > root@qemuarm64-secureboot:~# df -h > Filesystem Size Used Available Use% Mounted on > /dev/root 721.5M 47.4M 620.6M 7% / > devtmpfs 477.7M 0 477.7M 0% /dev > tmpfs 40.0K 0 40.0K 0% /mnt > tmpfs 489.3M 92.0K 489.2M 0% /run > tmpfs 489.3M 68.0K 489.2M 0% /var/volatile > /dev/vda1 120.4M 19.9M 91.4M 18% /boot > > Doing the math we see that the /boot partition is ~20MB and in the first image > the / partition contains this ~20MB in addition to the rest of the rootfs. > This ~20MB is completely wasted since it is used in the / partition, but then > the /boot partition is mounted on top of it, making the /boot directory of / > inaccessible. After the fix the / partition has an additional ~20MB since the > /boot portion is excluded. > > Fixes [YOCTO #15555] > > Signed-off-by: Trevor Woerner <twoerner@gmail.com> > --- Hi Trevor, Thanks for your patch. I do have some build issue on the autobuilder: 2025-04-09 11:14:21,897 - oe-selftest - INFO - wic.Wic.test_exclude_path_with_extra_space (subunit.RemotedTestCase) 2025-04-09 11:14:21,898 - oe-selftest - INFO - ... FAIL ... [Wed Apr 9 11:01:08 2025] (1309377/1309395): 192.168.7.4:53040 UA:elfutils/0.192,Linux/x86_64,/ XFF: GET /buildid/da3aea1c8160034e1b0961a7f2b5ce5c5a95553b/debuginfo 200 237848 0+9ms ERROR: When reparsing /tmp/selftest-fetchw3a6djws/test.bb:do_checkuri, the basehash value changed from 84b9e23a83a764e7a5d8a96ee523199e2b1c604f4280a45030e248de0ff52962 to 4123da244f465feffecb2b4fd2b132b64851981ec2fb70bf9445df8b0ea6a69e. The metadata is not deterministic and this needs to be fixed. ERROR: The following commands may help: ERROR: $ bitbake test -cdo_checkuri -Snone ERROR: Then: ERROR: $ bitbake test -cdo_checkuri -Sprintdiff ERROR: When reparsing /tmp/selftest-fetchw3a6djws/test.bb:do_fetch, the basehash value changed from 6d55d6743729b615749dc016857d7e5f9c884a8b92f0d57f68e743f4910333d3 to fa7d6ea0563b60362418d2a6c5e41a6684183d01ec578b65abd0c64a9cfba7cf. The metadata is not deterministic and this needs to be fixed. ERROR: The following commands may help: ERROR: $ bitbake test -cdo_fetch -Snone ERROR: Then: ERROR: $ bitbake test -cdo_fetch -Sprintdiff https://autobuilder.yoctoproject.org/valkyrie/#/builders/35/builds/1329 I tried to reproduce this locally, and reproduced a fail with "oe-selftest -r wic.Wic.test_exclude_path_with_extra_space", but with a different error: | INFO: Creating image(s)... | | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/imager/direct.py | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/bootimg-biosplusefi.py | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/empty.py | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/bootimg-efi.py | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/bootimg-pcbios.py | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/isoimage-isohybrid.py | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/bootimg-partition.py | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/rootfs.py | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/rawcopy.py | DEBUG: _exec_cmd: install -d /home/mdubois-briand/swat/oe-sefltest/poky-contrib/build-st/tmp/work/qemux86_64-poky-linux/core-image-minimal/1.0/tmp-wic/boot.1 | DEBUG: ['install', '-d', '/home/mdubois-briand/swat/oe-sefltest/poky-contrib/build-st/tmp/work/qemux86_64-poky-linux/core-image-minimal/1.0/tmp-wic/boot.1'] | DEBUG: _exec_cmd: output for install -d /home/mdubois-briand/swat/oe-sefltest/poky-contrib/build-st/tmp/work/qemux86_64-poky-linux/core-image-minimal/1.0/tmp-wic/boot.1 (rc = 0): | ERROR: No boot files defined, IMAGE_BOOT_FILES unset for entry #1 So maybe I'm missing something here. The exact branch I used for this build should be available in https://web.git.yoctoproject.org/poky-ci-archive/tag/?h=autobuilder.yoctoproject.org/valkyrie/a-full-1372, but the mirror seems out of sync. I hope it will be there a bit later today. Can you have a look at this, please?
Hi Mathieu, Thanks for looking at my patch! On Wed 2025-04-09 @ 04:29:57 PM, Mathieu Dubois-Briand wrote: > On Tue Apr 8, 2025 at 10:57 PM CEST, Trevor Woerner via lists.openembedded.org wrote: > I do have some build issue on the autobuilder: > > 2025-04-09 11:14:21,897 - oe-selftest - INFO - wic.Wic.test_exclude_path_with_extra_space (subunit.RemotedTestCase) > 2025-04-09 11:14:21,898 - oe-selftest - INFO - ... FAIL > ... > [Wed Apr 9 11:01:08 2025] (1309377/1309395): 192.168.7.4:53040 UA:elfutils/0.192,Linux/x86_64,/ XFF: GET /buildid/da3aea1c8160034e1b0961a7f2b5ce5c5a95553b/debuginfo 200 237848 0+9ms > ERROR: When reparsing /tmp/selftest-fetchw3a6djws/test.bb:do_checkuri, the basehash value changed from 84b9e23a83a764e7a5d8a96ee523199e2b1c604f4280a45030e248de0ff52962 to 4123da244f465feffecb2b4fd2b132b64851981ec2fb70bf9445df8b0ea6a69e. The metadata is not deterministic and this needs to be fixed. > ERROR: The following commands may help: > ERROR: $ bitbake test -cdo_checkuri -Snone > ERROR: Then: > ERROR: $ bitbake test -cdo_checkuri -Sprintdiff > > ERROR: When reparsing /tmp/selftest-fetchw3a6djws/test.bb:do_fetch, the basehash value changed from 6d55d6743729b615749dc016857d7e5f9c884a8b92f0d57f68e743f4910333d3 to fa7d6ea0563b60362418d2a6c5e41a6684183d01ec578b65abd0c64a9cfba7cf. The metadata is not deterministic and this needs to be fixed. > ERROR: The following commands may help: > ERROR: $ bitbake test -cdo_fetch -Snone > ERROR: Then: > ERROR: $ bitbake test -cdo_fetch -Sprintdiff > > https://autobuilder.yoctoproject.org/valkyrie/#/builders/35/builds/1329 Strange. This *sounds* like what happens when I update my layers while a build is running. I wouldn't expect the AB to do something like that in the middle of a build? > I tried to reproduce this locally, and reproduced a fail with > "oe-selftest -r wic.Wic.test_exclude_path_with_extra_space", but with a > different error: > > | INFO: Creating image(s)... > | > | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/imager/direct.py > | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/bootimg-biosplusefi.py > | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/empty.py > | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/bootimg-efi.py > | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/bootimg-pcbios.py > | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/isoimage-isohybrid.py > | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/bootimg-partition.py > | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/rootfs.py > | DEBUG: loading plugin module /home/mdubois-briand/swat/oe-sefltest/poky-contrib/scripts/lib/wic/plugins/source/rawcopy.py > | DEBUG: _exec_cmd: install -d /home/mdubois-briand/swat/oe-sefltest/poky-contrib/build-st/tmp/work/qemux86_64-poky-linux/core-image-minimal/1.0/tmp-wic/boot.1 > | DEBUG: ['install', '-d', '/home/mdubois-briand/swat/oe-sefltest/poky-contrib/build-st/tmp/work/qemux86_64-poky-linux/core-image-minimal/1.0/tmp-wic/boot.1'] > | DEBUG: _exec_cmd: output for install -d /home/mdubois-briand/swat/oe-sefltest/poky-contrib/build-st/tmp/work/qemux86_64-poky-linux/core-image-minimal/1.0/tmp-wic/boot.1 (rc = 0): > | ERROR: No boot files defined, IMAGE_BOOT_FILES unset for entry #1 > > So maybe I'm missing something here. > > The exact branch I used for this build should be available in > https://web.git.yoctoproject.org/poky-ci-archive/tag/?h=autobuilder.yoctoproject.org/valkyrie/a-full-1372, > but the mirror seems out of sync. I hope it will be there a bit later > today. > > Can you have a look at this, please? This is my first oe-selftest, so I'm not entirely surprised. It succeeded for me, I thought I had it figured out, but I've probably done something wrong in my testing. Thanks, I'll take another look at this with your branch. Best regards, Trevor
diff --git a/meta/lib/oeqa/selftest/cases/wic.py b/meta/lib/oeqa/selftest/cases/wic.py index 59fd99a78836..67f938351bde 100644 --- a/meta/lib/oeqa/selftest/cases/wic.py +++ b/meta/lib/oeqa/selftest/cases/wic.py @@ -535,6 +535,38 @@ part /mnt --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/whoa finally: os.environ['PATH'] = oldpath + def test_exclude_path_with_extra_space(self): + """Test having --exclude-path with IMAGE_ROOTFS_EXTRA_SPACE. [Yocto #15555]""" + + with NamedTemporaryFile("w", suffix=".wks") as wks: + wks.writelines( + ['bootloader --ptable gpt\n', + 'part /boot --size=100M --active --source bootimg-partition --fstype=ext4 --label boot\n', + 'part / --exclude-path boot/ --source rootfs --fstype=ext4 --label root\n']) + wks.flush() + config = 'IMAGE_ROOTFS_EXTRA_SPACE = "500000"\n'\ + 'IMAGE_FSTYPES += "wic"\n'\ + 'WKS_FILE = "%s"\n' % wks.name + self.append_config(config) + bitbake('core-image-minimal') + + """ + the output of "wic ls <image>.wic" will look something like: + Num Start End Size Fstype + 1 17408 136332287 136314880 ext4 + 2 136332288 171464703 35132416 ext4 + we are looking for the size of partition 2 + i.e. in this case the number 35,132,416 + without the fix the size will be around 85,403,648 + with the fix the size should be around 799,960,064 + """ + bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'MACHINE'], 'core-image-minimal') + deploy_dir = bb_vars['DEPLOY_DIR_IMAGE'] + machine = bb_vars['MACHINE'] + wicout = glob(os.path.join(deploy_dir, "core-image-minimal-%s.rootfs-*.wic" % machine))[0] + size_of_root_partition = int(runCmd("wic ls %s" % wicout).output.split('\n')[2].split()[3]) + self.assertGreater(size_of_root_partition, 500000000) + def test_include_path(self): """Test --include-path wks option.""" diff --git a/scripts/lib/wic/partition.py b/scripts/lib/wic/partition.py index bf2c34d5940f..b18431d8fb84 100644 --- a/scripts/lib/wic/partition.py +++ b/scripts/lib/wic/partition.py @@ -244,7 +244,7 @@ class Partition(): # from bitbake variable rsize_bb = get_bitbake_var('ROOTFS_SIZE') rdir = get_bitbake_var('IMAGE_ROOTFS') - if rsize_bb and rdir == rootfs_dir: + if rsize_bb and (rdir == rootfs_dir or (rootfs_dir.split('/')[-2] == "tmp-wic" and rootfs_dir.split('/')[-1][:6] == "rootfs")): # Bitbake variable ROOTFS_SIZE is calculated in # Image._get_rootfs_size method from meta/lib/oe/image.py # using IMAGE_ROOTFS_SIZE, IMAGE_ROOTFS_ALIGNMENT,
If the *.wks file contains a "--source rootfs" then lib/wic/plugins/source/rootfs.py will be invoked to generate (what is assumed to be) the rootfs partition. If the rootfs partition needs to be tweaked or modified, the "rootfs.py" plugin will make a copy of the filesystem and then perform the changes on that copy. In other words, if the "--source rootfs" line of the *.wks file also contains any of: --exclude-path --include-path --change-directory --use-label (i.e. modify etc/fstab) then the rootfs will be copied first, then the copy is modified. If, for example, the unmodified IMAGE_ROOTFS is: .../tmp/work/qemuarm64_secureboot-oe-linux/core-image-base/1.0/rootfs then the copy would be made at: .../tmp/work/qemuarm64_secureboot-oe-linux/core-image-base/1.0/tmp-wic/rootfs${LINENO} where ${LINENO} is the line number where this "--source rootfs" line appears in the *wks file. When it comes time to make an actual partition of a specific filesystem type, lib/wic/partition.py::prepare_rootfs() is called. It is in this function that wic figures out if any extra size needs to be added. The bitbake variable used to specify the ultimate rootfs size is ROOTFS_SIZE, and since this variable is only valid for the rootfs (and not any other partitions), the code also verifies that the partition being created is ${IMAGE_ROOTFS}: rsize_bb = get_bitbake_var('ROOTFS_SIZE') rdir = get_bitbake_var('IMAGE_ROOTFS') if rsize_bb and rdir == rootfs_dir: <use rsize_bb> else: <calculate the partition size using "du -ks $p"> As noted above, if lib/wic/plugins/source/rootfs.py has made a copy, then the "rdir == rootfs_dir" clause will fail and the code will assume this partition is not a rootfs since the strings do not compare equal. Therefore, in order to determine if this is a rootfs, retain the existing "rdir == rootfs_dir" comparison, but also add another one to check whether or not this is a wic-generated copy of the rootfs. STEPS TO REPRODUCE: - start with the following *wks file: bootloader --ptable gpt part /boot --ondisk=vda --align 64 --size=100M --active --source bootimg-partition --fstype=ext4 --label boot --sourceparams="loader=u-boot" part / --ondisk=vda --source rootfs --fstype=ext4 --label root - and the following extra variable in conf/local.conf: IMAGE_ROOTFS_EXTRA_SPACE = "500000" - build an image - run it in qemu $ runqemu slirp nographic serial - verify the root partition has extra space: root@qemuarm64-secureboot:~# df -h Filesystem Size Used Available Use% Mounted on /dev/root 721.5M 67.4M 600.6M 10% / devtmpfs 477.7M 0 477.7M 0% /dev tmpfs 40.0K 0 40.0K 0% /mnt tmpfs 489.3M 92.0K 489.2M 0% /run tmpfs 489.3M 68.0K 489.2M 0% /var/volatile /dev/vda1 120.4M 19.9M 91.4M 18% /boot - modify the "/" line of the *wks file to be: part / --ondisk=vda --exclude-path boot/ --source rootfs --fstype=ext4 --label root - build image when it fails: root@qemuarm64-secureboot:~# df -h Filesystem Size Used Available Use% Mounted on /dev/root 73.4M 41.9M 25.8M 62% / devtmpfs 477.7M 0 477.7M 0% /dev tmpfs 40.0K 0 40.0K 0% /mnt tmpfs 489.3M 92.0K 489.2M 0% /run tmpfs 489.3M 68.0K 489.2M 0% /var/volatile /dev/vda1 120.4M 19.9M 91.4M 18% /boot after this fix: root@qemuarm64-secureboot:~# df -h Filesystem Size Used Available Use% Mounted on /dev/root 721.5M 47.4M 620.6M 7% / devtmpfs 477.7M 0 477.7M 0% /dev tmpfs 40.0K 0 40.0K 0% /mnt tmpfs 489.3M 92.0K 489.2M 0% /run tmpfs 489.3M 68.0K 489.2M 0% /var/volatile /dev/vda1 120.4M 19.9M 91.4M 18% /boot Doing the math we see that the /boot partition is ~20MB and in the first image the / partition contains this ~20MB in addition to the rest of the rootfs. This ~20MB is completely wasted since it is used in the / partition, but then the /boot partition is mounted on top of it, making the /boot directory of / inaccessible. After the fix the / partition has an additional ~20MB since the /boot portion is excluded. Fixes [YOCTO #15555] Signed-off-by: Trevor Woerner <twoerner@gmail.com> --- meta/lib/oeqa/selftest/cases/wic.py | 32 +++++++++++++++++++++++++++++ scripts/lib/wic/partition.py | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-)