Send SETATTR request after open when atomic_o_trunc is not set.

In Linux, the VFS is responsible for implementing O_TRUNC. It does
this by calling setattr with a zero size on the underlying inode.
The sentry VFS does not have the same inode abstraction, so we need
to implement the SETATTR behavior inside the fusefs implementation.

PiperOrigin-RevId: 501385452
This commit is contained in:
Lucas Manning
2023-01-11 14:51:36 -08:00
committed by gVisor bot
parent 69859a21f8
commit 320004cbe6
4 changed files with 18 additions and 10 deletions
@@ -141,6 +141,7 @@ func (conn *connection) initProcessReply(out *linux.FUSEInitOut, hasSysAdminCap
conn.bigWrites = out.Flags&linux.FUSE_BIG_WRITES != 0
conn.dontMask = out.Flags&linux.FUSE_DONT_MASK != 0
conn.writebackCache = out.Flags&linux.FUSE_WRITEBACK_CACHE != 0
conn.atomicOTrunc = out.Flags&linux.FUSE_ATOMIC_O_TRUNC != 0
// TODO(gvisor.dev/issue/3195): figure out how to use TimeGran (0 < TimeGran <= fuseMaxTimeGranNs).
+14 -9
View File
@@ -476,15 +476,20 @@ func (i *inode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentr
fd.Nonseekable = true
}
// If we don't send SETATTR before open (which is indicated by atomicOTrunc)
// and O_TRUNC is set, update the inode's version number and clean existing data
// by setting the file size to 0.
if i.fs.conn.atomicOTrunc && opts.Flags&linux.O_TRUNC != 0 {
i.fs.conn.mu.Lock()
i.attributeVersion.Store(i.fs.conn.attributeVersion.Add(1))
i.size.Store(0)
i.fs.conn.mu.Unlock()
i.attributeTime = 0
// If atomicOTrunc and O_TRUNC are set, just update the inode's version number
// and set its size to 0 since the truncation is handled by the FUSE daemon.
// Otherwise send a separate SETATTR to truncate the file size.
if opts.Flags&linux.O_TRUNC != 0 {
if i.fs.conn.atomicOTrunc {
i.fs.conn.mu.Lock()
i.attributeVersion.Store(i.fs.conn.attributeVersion.Add(1))
i.size.Store(0)
i.fs.conn.mu.Unlock()
i.attributeTime = 0
} else {
opts := vfs.SetStatOptions{Stat: linux.Statx{Size: 0, Mask: linux.STATX_SIZE}}
i.setAttr(ctx, i.fs.VFSFilesystem(), auth.CredentialsFromContext(ctx), opts, true, i.newFhData.fh)
}
}
if err := fd.vfsfd.Init(fdImpl, opts.Flags, rp.Mount(), d.VFSDentry(), fdOptions); err != nil {
+2 -1
View File
@@ -35,7 +35,8 @@ namespace testing {
constexpr char kMountOpts[] = "rootmode=755,user_id=0,group_id=0";
constexpr struct fuse_init_out kDefaultFUSEInitOutPayload = {.major = 7};
constexpr struct fuse_init_out kDefaultFUSEInitOutPayload = {
.major = 7, .minor = 14, .flags = FUSE_ATOMIC_O_TRUNC};
// Internal commands used to communicate between testing thread and the FUSE
// server. See test/fuse/README.md for further detail.
+1
View File
@@ -128,6 +128,7 @@ syscall_test(
syscall_test(
add_overlay = True,
test = "//test/syscalls/linux:creat_test",
use_fusefs = True,
)
syscall_test(