From 848cd6f0f115876485ab7daf0d4f03f1d65fcbfb Mon Sep 17 00:00:00 2001 From: Ayush Ranjan Date: Tue, 24 May 2022 16:09:11 -0700 Subject: [PATCH] Flush Close RPCs for deleted regular files immediately. This is to release disk space on the remote filesystem immediately. If we batch the Close RPC then the control FD for the deleted file will be close later. Until then, the corresponding control FD on the server will hold a host FD on the deleted file. Linux does not release disk resources until all references on the file are dropped. So all host FDs must be closed immediately in such cases. We only need to do such a flush for regular files which can be really large in practice. Tested: ``` host:/$ mkdir /tmp/mountpoint host:/$ sudo mount -t tmpfs lisafs_test /tmp/mountpoint host:/$ docker run --runtime=runsc-lisafs -v /tmp/mountpoint:/mountpoint --rm -it ubuntu bash root@97a9ec17bc29:/# dd if=/dev/zero of=/mountpoint/big bs=10485760 count=1 host:/$ df -h mountpoint/ Filesystem Size Used Avail Use% Mounted on lisafs_test 32G 10M 32G 1% /tmp/mountpoint root@97a9ec17bc29:/# rm mountpoint/big host:/$ df -h mountpoint/ Filesystem Size Used Avail Use% Mounted on lisafs_test 32G 0 32G 0% /tmp/mountpoint ``` Without this change, the last df command still shows 10M usage. Fixes #7613 PiperOrigin-RevId: 450791695 --- pkg/sentry/fsimpl/gofer/gofer.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pkg/sentry/fsimpl/gofer/gofer.go b/pkg/sentry/fsimpl/gofer/gofer.go index e0c0c9644..55df58017 100644 --- a/pkg/sentry/fsimpl/gofer/gofer.go +++ b/pkg/sentry/fsimpl/gofer/gofer.go @@ -814,7 +814,7 @@ type dentry struct { controlFDLisa lisafs.ClientFD `state:"nosave"` // If deleted is non-zero, the file represented by this dentry has been - // deleted is accessed using atomic memory operations. + // deleted is accessed using atomic memory operations. deleted atomicbitops.Uint32 // cachingMu is used to synchronize concurrent dentry caching attempts on @@ -2029,7 +2029,7 @@ func (d *dentry) destroyLocked(ctx context.Context) { d.mmapFD = atomicbitops.FromInt32(-1) d.handleMu.Unlock() - if d.isControlFileOk() { + if !d.isSynthetic() { // Note that it's possible that d.atimeDirty or d.mtimeDirty are true, // i.e. client and server timestamps may differ (because e.g. a client // write was serviced by the page cache, and only written back to the @@ -2041,7 +2041,11 @@ func (d *dentry) destroyLocked(ctx context.Context) { // Close the control FD. if d.fs.opts.lisaEnabled { - d.controlFDLisa.Close(ctx, false /* flush */) + // Propagate the Close RPCs immediately to the server if the dentry being + // destroyed is a deleted regular file. This is to release the disk space + // on remote immediately. + flushClose := d.isDeleted() && d.isRegularFile() + d.controlFDLisa.Close(ctx, flushClose) } else { if err := d.file.close(ctx); err != nil { log.Warningf("gofer.dentry.destroyLocked: failed to close file: %v", err)