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

Package upgrades break if hardlinks got added #1278

Closed
Vogtinator opened this issue Jun 19, 2020 · 8 comments · Fixed by #1279
Closed

Package upgrades break if hardlinks got added #1278

Vogtinator opened this issue Jun 19, 2020 · 8 comments · Fixed by #1279
Labels

Comments

@Vogtinator
Copy link
Contributor

Vogtinator commented Jun 19, 2020

The algorithm used for installing hardlinks does not handle the case where a package upgrade includes additional names for an inode. It iterates the list of files from the beginning until the end and only writes content and metadata for the last occurence of an inode.
For upgrades, there is no hardlink relationship though, the added file has a different inode. This means that the content and metadata are written only to the files from the old package.
As the file content didn't change, the other names for the inode verify successfully and are thus not written to, so neither recreated as hardlinks to the new file nor file content written into the inode.
Reproducer:

Name: pkg
Version: %{ver}
Release: 0
License: WTFPL
Summary: Package

%description
.

%install
mkdir -p %{buildroot}/usr
echo "content" > %{buildroot}/usr/file2
%if %{ver} == 1
ln %{buildroot}/usr/file2 %{buildroot}/usr/file1
%endif

%files
%if %{ver} == 1
/usr/file1
%endif
/usr/file2

To build:

rpmbuild -bb -D 'ver 0' pkg.spec
rpmbuild -bb -D 'ver 1' pkg.spec

To install:

localhost:~ # rpm -U pkg-0-0.x86_64.rpm
localhost:~ # ll /usr/file{1,2}
ls: cannot access '/usr/file1': No such file or directory
-rw-r--r-- 1 root root 8 Jun 22  2020 /usr/file2
localhost:~ # rpm -U pkg-1-0.x86_64.rpm
localhost:~ # ll /usr/file{1,2}
--w------- 1 root root 0 Jun 22 05:34 /usr/file1
-rw-r--r-- 1 root root 8 Jun 22  2020 /usr/file2

As you can see, /usr/file1 was created with wrong mode and no content. The two files do not share an inode. It works if the package is installed directly:

localhost:~ # rpm -e pkg
localhost:~ # rpm -U pkg-1-0.x86_64.rpm
localhost:~ # ll /usr/file{1,2}
-rw-r--r-- 2 root root 8 Jun 22  2020 /usr/file1
-rw-r--r-- 2 root root 8 Jun 22  2020 /usr/file2
@pmatilai
Copy link
Member

With --force, if something breaks you get to keep the pieces. Is it reproducable without --force?

@Vogtinator
Copy link
Contributor Author

Yes.

I only used --force so that I can use the same commands for install, upgrade and downgrade.

@Vogtinator
Copy link
Contributor Author

I ran the commands again without --force and edited the post accordingly.

@pmatilai pmatilai added the bug label Jun 22, 2020
@pmatilai
Copy link
Member

Ok, thanks for verifying.

Just FWIW, --oldpackage is the "appropriate" flag for downgrades, --force is the BFH usually best left in the toolshed 😁

@Vogtinator
Copy link
Contributor Author

Just found out that this only happens with %_minimize_writes enabled, as otherwise even unchanged files are recreated correctly as hardlinks.

D: create     100644  2 (   0,   0)     0 /usr/file1;5ef086f0
D: touch      100644  2 (   0,   0)     8 /usr/file2

vs.

D: create     100644  2 (   0,   0)     0 /usr/file1;5ef09669
D: create     100644  2 (   0,   0)     8 /usr/file2;5ef09669

%_minimize_writes is the default for SSDs (and on openSUSE in general) though.

@pmatilai
Copy link
Member

Ah... makes sense. Thanks for spotting that!

pmatilai added a commit to pmatilai/rpm that referenced this issue Jun 23, 2020
The existing FSM code doesn't correctly handle FA_TOUCH on hardlinked
file sets, which causes the hardlink set to break on at least some
upgrade scenarios when minimize_writes is enabled.

Only enable FA_TOUCH on non-hardlinked files to work around the issue
for now. While at it, rearrange the conditionals around min_writes to make
it a bit clearer. Testcase adopted from original reproducer by
Fabian Vogt, thanks!

Fixes: rpm-software-management#1278
pmatilai added a commit that referenced this issue Jun 23, 2020
The existing FSM code doesn't correctly handle FA_TOUCH on hardlinked
file sets, which causes the hardlink set to break on at least some
upgrade scenarios when minimize_writes is enabled.

Only enable FA_TOUCH on non-hardlinked files to work around the issue
for now. While at it, rearrange the conditionals around min_writes to make
it a bit clearer. Testcase adopted from original reproducer by
Fabian Vogt, thanks!

Fixes: #1278
@pmatilai
Copy link
Member

Thanks for reporting and the nice reproducer!

@Vogtinator
Copy link
Contributor Author

Thanks for the quick fix!

pmatilai added a commit to pmatilai/rpm that referenced this issue Jun 23, 2020
The existing FSM code doesn't correctly handle FA_TOUCH on hardlinked
file sets, which causes the hardlink set to break on at least some
upgrade scenarios when minimize_writes is enabled.

Only enable FA_TOUCH on non-hardlinked files to work around the issue
for now. While at it, rearrange the conditionals around min_writes to make
it a bit clearer. Testcase adopted from original reproducer by
Fabian Vogt, thanks!

Fixes: rpm-software-management#1278
(cherry picked from commit 4017582)
pmatilai added a commit that referenced this issue Jun 23, 2020
The existing FSM code doesn't correctly handle FA_TOUCH on hardlinked
file sets, which causes the hardlink set to break on at least some
upgrade scenarios when minimize_writes is enabled.

Only enable FA_TOUCH on non-hardlinked files to work around the issue
for now. While at it, rearrange the conditionals around min_writes to make
it a bit clearer. Testcase adopted from original reproducer by
Fabian Vogt, thanks!

Fixes: #1278
(cherry picked from commit 4017582)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants