Skip to content

Update LVM2Device sizes if the LVM2Device size is smaller than the PhysicalVolume size#61

Open
Miauwkeru wants to merge 6 commits intomainfrom
update-device-sizes
Open

Update LVM2Device sizes if the LVM2Device size is smaller than the PhysicalVolume size#61
Miauwkeru wants to merge 6 commits intomainfrom
update-device-sizes

Conversation

@Miauwkeru
Copy link
Contributor

@Miauwkeru Miauwkeru commented Mar 2, 2026

This seems to be the cause of fox-it/dissect#93
Where it, assumedly, tried to read beyond the LVM2Device disk size where it could not reach.

TODO

  • Generate test data that displays this behaviour
  • Create a test to show this behaviour is fixed

@Miauwkeru
Copy link
Contributor Author

@tuttimann I did find a issue in our lvm implementation, I believe this is also the issue you came accross in fox-it/dissect#93

@codecov
Copy link

codecov bot commented Mar 2, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.73%. Comparing base (b96d88f) to head (d90dd97).

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #61      +/-   ##
==========================================
+ Coverage   77.62%   77.73%   +0.10%     
==========================================
  Files          29       29              
  Lines        2337     2344       +7     
==========================================
+ Hits         1814     1822       +8     
+ Misses        523      522       -1     
Flag Coverage Δ
unittests 77.73% <100.00%> (+0.10%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment on lines +145 to +147
device.size = max(self.dev_size * self.vg.extent_size, device.size)
else:
device.size = max(self.pe_start + (self.pe_count * self.vg.extent_size * SECTOR_SIZE), device.size)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we change the code that utilizes this size instead of correcting it on the LVM2Device object? Now if you manually inspect the device.size after attaching, its value will not reflect the reality of that's in the header.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does seem it updates the pv_header to this size with the pvck tool if it detects this discrepancy. Although, it is correct it doesn't correctly represent what is inside the pv_header that the LVM2Device uses even if that size is wrong / too small.

As an alternative, to avoid misrepresenting the data inside the LVM2Device we could adjust LVM2Device.open to accept a pv_size = 0 by default. So it picks the actual pv_size when opening a LVM2Device.
As it will only read as far as was specified by the LVM2Device while there is more data available.

In code it would look a bit like:

class LVM2Device:
    def open(self, pv_size: int = 0):
        size = max(pv_size, self.size)
        # Use size for opening the stream and specifying the length.
...
class PhysicalVolume:
    @property
    def size(self):
        """Return the physical volume size in bytes"""
        ...

Where pv.size gets passed to LVM2Device.open inside segment.open()

It takes the pv size of the PhysicalVolume and uses it when opening the
device
the size of the LVM2Device has been manually changed.
While the test functions as intended, you can't use a loopback device to
mount the file itself
@Miauwkeru Miauwkeru requested a review from Schamper March 4, 2026 13:47
@Miauwkeru Miauwkeru requested review from twiggler March 12, 2026 09:28

def open(self) -> BinaryIO:
def open(self, pv_size: int = 0) -> BinaryIO:
# Use pv_size if the physical
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is truncated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

if self.dev_size:
return self.dev_size * self.vg.extent_size
# The size of the stripes on this device + the offset where it starts
return (self.pe_start + self.pe_count * self.vg.extent_size) * SECTOR_SIZE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignorance on my part, but why does the offset factor into the size?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is the size of the whole physical device. This includes the metadata that is before this specific region

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have the script used to construct this somewhere?
(could be helpful in the future, no biggie)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a script to create it, and adjusted the tests.
I didn't adjust the crc value of the label header. So this file won't behave like a lvm disk once mounted with losetup

def size(self) -> int:
"""Return the size of the physical volume in bytes.

This can sometimes be larger than what the LVM2Device dictates, but the VolumeGroup overwrites it:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in, the VolumeGroup overrides it?
Maybe change "but" to "in which case"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the volume group can override what it actually is it seems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants