Skip to content

create: do not archive an atime we caused ourselves, fixes #6194 - #10111

Open
ThomasWaldmann wants to merge 1 commit into
borgbackup:masterfrom
ThomasWaldmann:atime-6194
Open

create: do not archive an atime we caused ourselves, fixes #6194#10111
ThomasWaldmann wants to merge 1 commit into
borgbackup:masterfrom
ThomasWaldmann:atime-6194

Conversation

@ThomasWaldmann

Copy link
Copy Markdown
Member

borg has to open() a fs item before it can fstat() it. On platforms without O_NOATIME
support (or when we are not allowed to use it), that open() may already have updated the
atime - and then we archive an atime that we caused ourselves, instead of the one the item
had before borg touched it.

stat_update_check() now returns a os.stat_result look-alike (StatOrigAtime) that has
everything from the fd-based stat, but the atime from the stat we did before opening the
item - as suggested in the issue. This is only done if the atime actually changed between
the two stat calls, so when O_NOATIME worked, the plain stat result is returned as before
(no proxy object, no overhead).

Doing this in stat_update_check() covers all its call sites at once: regular files, fifos,
devices and both directory opens.

Note: this only changes what we archive - without O_NOATIME we still can not avoid
updating the atime in the source filesystem.

Tests:

  • test_atime_open_updates_atime simulates a platform where the open() already updates the
    atime (by reading a byte in a monkeypatched os_open) and checks that the archived atime is
    still the one from before. It fails without the fix.
  • unit tests for stat_update_check(): atime fixup, unchanged atime (returns the stat result
    as is) and the two race condition checks, which had no test coverage.

@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.07%. Comparing base (daa1944) to head (9c3a5ef).
⚠️ Report is 3 commits behind head on master.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #10111      +/-   ##
==========================================
+ Coverage   87.03%   87.07%   +0.04%     
==========================================
  Files         101      101              
  Lines       17730    17740      +10     
  Branches     2678     2679       +1     
==========================================
+ Hits        15431    15447      +16     
+ Misses       1598     1595       -3     
+ Partials      701      698       -3     

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

…#6194

borg has to open() a fs item before it can fstat() it. On platforms
without O_NOATIME support (or when we are not allowed to use it), that
open() may already have updated the atime - and then we would archive
that atime instead of the one the item had before borg touched it.

stat_update_check() now returns a stat result look-alike that has the
atime from the stat we did before opening the item, if the atime changed
between the two stat calls. If it did not change (e.g. O_NOATIME worked),
the fd-based stat result is returned as before.
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.

1 participant