Skip to content

tmpfs: Update mtime/ctime on open(O_TRUNC) for zero-length files#12771

Open
tanyifeng wants to merge 1 commit intogoogle:masterfrom
tanyifeng:tmpfs-otrunc-mtime
Open

tmpfs: Update mtime/ctime on open(O_TRUNC) for zero-length files#12771
tanyifeng wants to merge 1 commit intogoogle:masterfrom
tanyifeng:tmpfs-otrunc-mtime

Conversation

@tanyifeng
Copy link
Copy Markdown
Contributor

Linux unconditionally updates mtime and ctime when handling O_TRUNC via handle_truncate() -> do_truncate() with ATTR_MTIME|ATTR_CTIME, regardless of whether the file size actually changes.

gVisor's tmpfs truncateLocked() returns early when newSize == oldSize, skipping the timestamp update. This causes programs that rely on mtime changes (e.g. file sync tools, make) to malfunction when repeatedly truncating an already-empty file.

Fix by calling d.inode.touchCMtime() after truncate(0) in the O_TRUNC path of dentry.open(), ensuring timestamps are always updated consistent with Linux behavior.

@tanyifeng tanyifeng force-pushed the tmpfs-otrunc-mtime branch from f65bb8b to e82ab6c Compare March 25, 2026 07:34
Currently, tmpfs truncate only updates mtime/ctime when the file size actually changes. This causes open(O_TRUNC) on an already-empty file to skip the timestamp update, breaking applications like khal that rely on open('w').close() to advance mtime. Fix this by unconditionally updating mtime/ctime on every truncate call. Rename truncateLocked() to truncateNoTimeUpdateLocked() and move timestamp updates into its callers. This is slightly more aggressive than Linux tmpfs for the truncate(2) same-size case (Linux tmpfs skips, ext4 updates), but simplifies the implementation Signed-off-by: Tan Yifeng <yiftan@tencent.com>
@tanyifeng tanyifeng force-pushed the tmpfs-otrunc-mtime branch from e82ab6c to d5da431 Compare March 26, 2026 07:13
@ayushr2
Copy link
Copy Markdown
Collaborator

ayushr2 commented Mar 26, 2026

Thanks, the current changes look good! I think we'd need to make the same fix in fsimpl/gofer because we run the same syscall tests against gofer and tmpfs so that new test will fail when we try to submit it.

@tanyifeng tanyifeng force-pushed the tmpfs-otrunc-mtime branch from d5da431 to ec4efec Compare March 27, 2026 06:34
@tanyifeng
Copy link
Copy Markdown
Contributor Author

Thanks, the current changes look good! I think we'd need to make the same fix in fsimpl/gofer because we run the same syscall tests against gofer and tmpfs so that new test will fail when we try to submit it.

I've applied the same fix to fsimpl/gofer/gofer.go — moved the "truncate updates mtime" logic out of the cachedMetadataAuthoritative() block so it takes effect in all interop modes. PTAL.

@ayushr2
Copy link
Copy Markdown
Collaborator

ayushr2 commented Mar 27, 2026

Actually I was mistaken above when I said that fsimpl/gofer is also impacted. When I was experiementing, the container was running with default overlayfs setting. So the rootfs was actually an overlayfs, so I was observing tmpfs behavior on rootfs. In reality, the fsimpl/gofer filesystem is not impacted. Here is the fixed-up incompatibility table:

Environment truncate
(no size change)
ftruncate
(no size change)
open(O_TRUNC)
(no size change)
truncate
(size change)
ftruncate
(size change)
open(O_TRUNC)
(size change)
Linux - tmpfs No Yes Yes Yes Yes Yes
Linux - ext4 Yes Yes Yes Yes Yes Yes
gVisor - tmpfs ctime-only ctime-only No Yes Yes No
gVisor - gofer Yes Yes Yes Yes Yes Yes

So if you could just revert your changes in fsimpl/gofer, then this PR looks good to me. Sorry for the back-and-forth.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Revert changes here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the verification, I reverted the changes in fsimpl/gofer.

@tanyifeng tanyifeng force-pushed the tmpfs-otrunc-mtime branch from ec4efec to d5da431 Compare March 28, 2026 03:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants