Skip to content
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

storage: set backlinks only if other post-init methods succeed #2138

Merged
merged 1 commit into from
Jan 17, 2025

Conversation

ogayot
Copy link
Member

@ogayot ogayot commented Jan 17, 2025

When creating a fsobj, e.g., a partition, we automatically modify associated fsobj-s (e.g., the underlying disk) to make them aware of the newly created object.

We do this through the use of backlinks and more specifically the function _set_backlinks. Currently, this function is automatically called first when entering the fsobj's __post_init__ method.

If a fsobj defines its own __post_init__ method (let's called it user-defined), it gets called after _set_backlinks. This is usually fine.

However if the user-defined __post_init__ raises an exception, we end up with backlinks referencing an object that was not successfully initialized.

This is what happens with the Partition fsobj. In its user-defined __post_init__, we determine the partition number by looking at the underlying disk. If the number could not be determined (because there is no more number available), we raise an exception "Exceeded number of available partitions". However, at this point, the underlying disk is already aware of the new partition - through the use of backlinks.

Iterating over the list of partitions will then raise a TypeError when trying to use partition.number - which has not been successfully assigned.

  File "/snap/ubuntu-desktop-installer/1269/bin/subiquity/subiquity/common/filesystem/manipulator.py", line 230, in reformat
    self.delete_partition(p, True)
  File "/snap/ubuntu-desktop-installer/1269/bin/subiquity/subiquity/common/filesystem/manipulator.py", line 117, in delete_partition
    self.model.remove_partition(part)
  File "/snap/ubuntu-desktop-installer/1269/bin/subiquity/subiquity/models/filesystem.py", line 2041, in remove_partition
    part.device.renumber_logical_partitions(part)
  File "/snap/ubuntu-desktop-installer/1269/bin/subiquity/subiquity/models/filesystem.py", line 688, in renumber_logical_partitions
    for p in self.partitions_by_number()
  File "/snap/ubuntu-desktop-installer/1269/bin/subiquity/subiquity/models/filesystem.py", line 638, in partitions_by_number
    return sorted(self._partitions, key=lambda p: p.number)
TypeError: '<' not supported between instances of 'NoneType' and 'int'

Fixed by calling _set_backlinks after the user-defined __post_init__, so that we only set the backlinks on success.

LP:#2095159

This was causing double pain to people who were already affected by the installer suggesting buggy guided scenarios (e.g., LP:#2081724). If a user selects a buggy scenario, it would fail and leave the system in a bad state, making other scenarios more likely to fail too.

When creating a fsobj, e.g., a partition, we automatically modify
associated fsobj-s (e.g., the underlying disk) to make them aware of the
newly created object.

We do this through the use of backlinks and more specifically the
function _set_backlinks. Currently, this function is automatically
called first when entering the fsobj's __post_init__ method.

If a fsobj defines its own __post_init__ method (let's called it
user-defined), it gets called after _set_backlinks. This is usually
fine.

However if the user-defined __post_init__ raises an exception, we end up
with backlinks referencing an object that was not successfully
initialized.

This is what happens with the Partition fsobj. In its user-defined
__post_init__, we determine the partition number by looking at the
underlying disk. If the number could not be determined (because there is
no more number available), we raise an exception "Exceeded number of
available partitions". However, at this point, the underlying disk is
already aware of the new partition - through the use of backlinks.

Iterating over the list of partitions will then raise a TypeError when
trying to use partition.number - which has not been successfully
assigned.

Fixed by calling _set_backlinks after the user-defined __post_init__, so
that we only set the backlinks on success.

refs LP: #2095159

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
@ogayot ogayot requested a review from dbungert January 17, 2025 12:30
Copy link
Collaborator

@dbungert dbungert left a comment

Choose a reason for hiding this comment

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

OK, so we're interesting with objects that have failed their class_post_init. I think this PR is in the right direction but assume we need more failure handling fixes?

@ogayot ogayot merged commit aaa1738 into canonical:main Jan 17, 2025
10 checks passed
@ogayot ogayot deleted the backlinks branch January 17, 2025 16:47
@ogayot ogayot mentioned this pull request Jan 27, 2025
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.

2 participants