Created attachment 208465 [details]
ctime should be updated whenever a file's link count changes. If its destination is multiply-linked, rename(2) will decrease its link count, and therefore should update its ctime. ZFS complies, but as of r353698 UFS does not. I have two test cases demonstrating the problem: a standalone C program (attached), and a pjdfstest test case (https://github.com/pjd/pjdfstest/pull/37).
Standalone test's output on UFS:
nlink: 2 -> 1 ctime 1571584801.941284000 -> 1571584801.941284000
Renamed failed to update destination's ctime.
And on ZFS:
nlink: 2 -> 1 ctime 1571584883.332680000 -> 1571584884.384654000
$ uname -a
FreeBSD fbsd-head.lauralan.noip.me 13.0-CURRENT FreeBSD 13.0-CURRENT #50 r353698: Thu Oct 17 15:17:38 MDT 2019 email@example.com:/usr/obj/usr/home/somers/freebsd/base/head/amd64.amd64/sys/GENERIC amd64
/dev/vtbd0p2 on / (ufs, local, journaled soft-updates)
devfs on /dev (devfs)
192.168.0.2:/home on /usr/home (nfs, nfsv4acls)
tank on /tank (zfs, local, nfsv4acls)
Could you bisect to find the specific change that caused this breakage?
Kirk, are you sure that it ever worked? I'm not. In case I wasn't clear, my two test cases are freshly written.
(In reply to Alan Somers from comment #2)
OK, I thought that you were reporting that something had stopped working. Do you have access to an older system (11.X say) that you can test?
The oldest VM I have is 11.2-STABLE #0 r339079. I just checked there, and the test still fails.
Created attachment 208490 [details]
Version of the test case that also works on 11.2-STABLE
Created attachment 208499 [details]
fix to avoid delayed ctime update
Your test passes on a filesystem without soft updates which was my first clue. It also passes if you add to your test program a usleep(1000000) call after the call to rename() which was the second clue. When running with soft updates, the ctime is not updated until the soft updates background process has settled all the needed I/O operations. Your test program stat()s it immediately after the rename() has returned, but soft updates has not finished with the processing, so the ctime has not yet been updated.
The attached patch causes the ctime to be updated immediately during the rename() which makes your test happy. The ctime will be updated again when soft updates has finished its processing because that is the time that is correct from the perspective of programs that look at the disk (like dump). This change does not cause any extra I/O to be done, it just ensures that stat() updates the ctime before handing it back to you.
(In reply to Alan Somers from comment #5)
Let me know if my patch solves your problem.
Works for me!
A commit references this bug:
Date: Thu Oct 24 21:28:37 UTC 2019
New revision: 354050
After the unlink() of one name of a file with multiple links, a
stat() of one of the remaining names of the file does not show an
updated ctime (inode modification time) until several seconds after
the unlink() completes. The problem only occurs when the filesystem
is running with soft updates enabled. When running with soft updates,
the ctime is not updated until the soft updates background process
has settled all the needed I/O operations.
This commit causes the ctime to be updated immediately during the
unlink(). A side effect of this change is that the ctime is updated
again when soft updates has finished its processing because that
is the time that is correct from the perspective of programs that
look at the disk (like dump). This change does not cause any extra
I/O to be done, it just ensures that stat() updates the ctime before
handing it back.
Reported by: Alan Somers
Tested by: Alan Somers
MFC after: 3 days
Sponsored by: Netflix
MFC'ed to 11-stable and 12-stable