-
Notifications
You must be signed in to change notification settings - Fork 650
cmd/snap-bootstrap: use libblkid to find information about disks #16182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
cmd/snap-bootstrap: use libblkid to find information about disks #16182
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #16182 +/- ##
==========================================
+ Coverage 77.50% 77.59% +0.08%
==========================================
Files 1342 1337 -5
Lines 184078 184336 +258
Branches 2444 2444
==========================================
+ Hits 142664 143029 +365
+ Misses 32780 32670 -110
- Partials 8634 8637 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Wed Jan 21 02:34:17 UTC 2026 Failures:Preparing:
Executing:
Restoring:
|
|
I have been doing some tests with the imx93. I think that we should stop relying on the udev properties added by So, we have 3 options to know which are the partitions to mount:
|
c5bb8cd to
5d1b68d
Compare
b4b3120 to
3626af8
Compare
|
This is rebased now on top of #16370 - it is ready for an initial pass, even if it might be necessary to split. Fwiw even on qemu this removes 25% of the time spent by the snap-bootstrap command. |
5bac26e to
45fb797
Compare
|
Changing to ready to review now |
cmd/snap-bootstrap/cmd_scan_disk.go
Outdated
|
|
||
| // PartitionWithFsLabel returns a partition with a filesystem matching fsLabel. | ||
| func (d *Disk) PartitionWithFsLabel(fsLabel string) (*Partition, error) { | ||
| // We are case-insensitive, this is especially important for the vfat case |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should rethink that. We should only use filesystem labels only when the partition table does not have names (mbr).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We saw labels using capital letters in vfat filesystems, so we allow this in the code that was comparing labels in the past, but only for vfat. I can add a check for the fs type easily by extracting also that infomation when probing, let me know if this was your concern here.
Otherwise, we still use only partition info in the GPT case - it is just that now we always probe the fs as that was needed for the "initramfs-mounts" snap-bootstrap command, and in the past we were using this only for the "scan" command. It was simpler code to just probe always everything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the objection here is that we should try not to match against the FS label, only in cases where we have no other choice (mbr) - not whether it's case-insensitive. You say we are still using partition information for GPT case, but I'm not sure i see that? It looks to me like we are now using filesystem label in all cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This says that we are case-insensitive, which puts me on guard in general as it makes things more forgiving, but it just says "this is especially important for the vfat case" - but is that because we want to only be case-insensitive for VFAT or do we also want for other filesystems?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have checked and we use the filesystem label/UUID in quite a few places when running the "initramfs-mounts" command, so we need to probe in that case. But that is not necessary for the "scan-disk" command, so I have added an option so the caller can decide whether to fully probe or not, so we save some time when scanning disks.
Otherwise, now I check for the partition type so we are case insensitive for vfat, which is what we were doing previously.
| // GetSize is a wrapper for blkid_partition_get_size | ||
| // GetSize returns the size of the partition in bytes | ||
| GetSize() int64 | ||
| // GetNumber is a wrapper for blkid_partition_get_partno |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // GetNumber is a wrapper for blkid_partition_get_partno | |
| // GetNumber returns the proposed partition number of the partition |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just following here the style of the previous function descriptions, just changed GetSize/Start because there were not wrappers anymore. I'm actually happy with changing this, but we should do that then for all methods in AbstractBlkidProbe/AbstractBlkidPartition. Let me know if you are ok with changing this now or as a follow-up.
| func (p *blkidPartition) GetNumber() int { | ||
| return int(C.blkid_partition_get_partno(p.partitionHandle)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| func (p *blkidPartition) GetNumber() int { | |
| return int(C.blkid_partition_get_partno(p.partitionHandle)) | |
| func (p *blkidPartition) GetNumber() int { | |
| // blkid_partition_get_partno proposed partition number (e.g. 'N' from sda'N'). Note that the number | |
| // is generated by library independently of the OS. | |
| // See | |
| // https://www.kernel.org/pub/linux/utils/util-linux/v2.41/libblkid-docs/libblkid-Partitions-probing.html#blkid-partition-get-partno | |
| return int(C.blkid_partition_get_partno(p.partitionHandle)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment added. I find it a bit weird that is says "proposed" as I expect the number to be deterministic as afaict by looking at blkid it comes from the order in GPT/MBR headers. And we would be in trouble if it was assigned differently in the kernel.
cmd/snap-bootstrap/cmd_scan_disk.go
Outdated
| } | ||
|
|
||
| // Filesystem is the information reported by blkid on a filesystem. | ||
| type Filesystem struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I notice this is public API, and used across the cmd files - I'm not a huge fan of this being inside a cmd_* file as this feels like library code, even if it's simple. My opinion is it would be clearer for this to be in a dedicated file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, moved now.
cmd/snap-bootstrap/cmd_scan_disk.go
Outdated
|
|
||
| // PartitionWithFsLabel returns a partition with a filesystem matching fsLabel. | ||
| func (d *Disk) PartitionWithFsLabel(fsLabel string) (*Partition, error) { | ||
| // We are case-insensitive, this is especially important for the vfat case |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the objection here is that we should try not to match against the FS label, only in cases where we have no other choice (mbr) - not whether it's case-insensitive. You say we are still using partition information for GPT case, but I'm not sure i see that? It looks to me like we are now using filesystem label in all cases?
cmd/snap-bootstrap/cmd_scan_disk.go
Outdated
|
|
||
| // PartitionWithFsLabel returns a partition with a filesystem matching fsLabel. | ||
| func (d *Disk) PartitionWithFsLabel(fsLabel string) (*Partition, error) { | ||
| // We are case-insensitive, this is especially important for the vfat case |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This says that we are case-insensitive, which puts me on guard in general as it makes things more forgiving, but it just says "this is especially important for the vfat case" - but is that because we want to only be case-insensitive for VFAT or do we also want for other filesystems?
0f75c39 to
9ffa601
Compare
Use libblkid instead of using the disks package, as the latter calls to udevadm trigger/settle, which delays boot considerably.
b0a9c9f to
8b94b78
Compare
alfonsosanchezbeato
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comments addressed now. I have also implemented now Model() so it returns the content of the "model" file in sysfs, which looks like the main thing that is used by udevd to fill ID_MODEL.
| // GetSize is a wrapper for blkid_partition_get_size | ||
| // GetSize returns the size of the partition in bytes | ||
| GetSize() int64 | ||
| // GetNumber is a wrapper for blkid_partition_get_partno |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just following here the style of the previous function descriptions, just changed GetSize/Start because there were not wrappers anymore. I'm actually happy with changing this, but we should do that then for all methods in AbstractBlkidProbe/AbstractBlkidPartition. Let me know if you are ok with changing this now or as a follow-up.
| func (p *blkidPartition) GetNumber() int { | ||
| return int(C.blkid_partition_get_partno(p.partitionHandle)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment added. I find it a bit weird that is says "proposed" as I expect the number to be deterministic as afaict by looking at blkid it comes from the order in GPT/MBR headers. And we would be in trouble if it was assigned differently in the kernel.
cmd/snap-bootstrap/cmd_scan_disk.go
Outdated
| } | ||
|
|
||
| // Filesystem is the information reported by blkid on a filesystem. | ||
| type Filesystem struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, moved now.
cmd/snap-bootstrap/cmd_scan_disk.go
Outdated
|
|
||
| // PartitionWithFsLabel returns a partition with a filesystem matching fsLabel. | ||
| func (d *Disk) PartitionWithFsLabel(fsLabel string) (*Partition, error) { | ||
| // We are case-insensitive, this is especially important for the vfat case |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have checked and we use the filesystem label/UUID in quite a few places when running the "initramfs-mounts" command, so we need to probe in that case. But that is not necessary for the "scan-disk" command, so I have added an option so the caller can decide whether to fully probe or not, so we save some time when scanning disks.
Otherwise, now I check for the partition type so we are case insensitive for vfat, which is what we were doing previously.
pedronis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did a first pass, some comments and questions
secboot/secboot.go
Outdated
| // Disk implementations provide disk information required by secboot. | ||
| type Disk interface { | ||
| SecbootPartitionWithFsLabel(string) (Partition, error) | ||
| Model() string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe this should be called DiskModel, as we have too many things called model already
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, done
secboot/secboot.go
Outdated
|
|
||
| // Disk implementations provide disk information required by secboot. | ||
| type Disk interface { | ||
| SecbootPartitionWithFsLabel(string) (Partition, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a strange name, are you trying to convey that the result is a secboot.Partition, I don't think golang conventions usually do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a conflict with the definition of PartitionWithFsLabel in snap-bootstrap for Disk. In the end I have used an adapter so the name can be the same.
| // Implemention of interface needed by secboot. | ||
| var _ = secboot.Partition(&Partition{}) | ||
|
|
||
| func (p *Partition) PartitionNode() string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a few of these accessors don't seem to be tested
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added checks
| } | ||
|
|
||
| func (d *Disk) Model() string { | ||
| // Get file information for the device node |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function is not tested it seems
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added tests now
| m.degradedState.partition(part).MountState = boot.PartitionMounted | ||
| m.degradedState.partition(part).MountLocation = where | ||
|
|
||
| if err := m.verifyMountPoint(where, part); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you explain why we don't need/want this anymore? is it related to the switch to scan_disk?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because of that and also because we are moving to libblkid also in initramfs-mounts command - this means that snap-bootstrap is probing directly blocks in /dev/<node>, so we read all partition information for the disk we know it was the boot disk. Previously we had to do this verification as we were relying on symlinks created by udevd, where there is always a chance that some other disk had the same label/UUID, etc.
So now fsDevice points to /dev/<disk>p<N> instead of to /dev/disk/by-partuuid/<UUID>.
| disk, err := disks.DiskFromDeviceName("/dev/disk/snapd/disk") | ||
| // If the disk kernel came from cannot be determined, then it will fallback to | ||
| // looking at the specified disk label. | ||
| func findBootDisk(fallbacklabel string) (*Disk, string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this and helpers perhaps live in disk.go ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, moved now
alfonsosanchezbeato
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pedronis thanks for the review, I've addressed the comments now
| m.degradedState.partition(part).MountState = boot.PartitionMounted | ||
| m.degradedState.partition(part).MountLocation = where | ||
|
|
||
| if err := m.verifyMountPoint(where, part); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because of that and also because we are moving to libblkid also in initramfs-mounts command - this means that snap-bootstrap is probing directly blocks in /dev/<node>, so we read all partition information for the disk we know it was the boot disk. Previously we had to do this verification as we were relying on symlinks created by udevd, where there is always a chance that some other disk had the same label/UUID, etc.
So now fsDevice points to /dev/<disk>p<N> instead of to /dev/disk/by-partuuid/<UUID>.
| disk, err := disks.DiskFromDeviceName("/dev/disk/snapd/disk") | ||
| // If the disk kernel came from cannot be determined, then it will fallback to | ||
| // looking at the specified disk label. | ||
| func findBootDisk(fallbacklabel string) (*Disk, string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, moved now
secboot/secboot.go
Outdated
|
|
||
| // Disk implementations provide disk information required by secboot. | ||
| type Disk interface { | ||
| SecbootPartitionWithFsLabel(string) (Partition, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a conflict with the definition of PartitionWithFsLabel in snap-bootstrap for Disk. In the end I have used an adapter so the name can be the same.
secboot/secboot.go
Outdated
| // Disk implementations provide disk information required by secboot. | ||
| type Disk interface { | ||
| SecbootPartitionWithFsLabel(string) (Partition, error) | ||
| Model() string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, done
| // Implemention of interface needed by secboot. | ||
| var _ = secboot.Partition(&Partition{}) | ||
|
|
||
| func (p *Partition) PartitionNode() string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added checks
| } | ||
|
|
||
| func (d *Disk) Model() string { | ||
| // Get file information for the device node |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added tests now
Use libblkid instead of using the disks package, as the latter calls to udevadm
trigger/settle, which delays boot considerably.