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
This commit is contained in:
Ayush Ranjan
2022-05-24 16:11:46 -07:00
committed by gVisor bot
parent b274736ac7
commit 848cd6f0f1
+7 -3
View File
@@ -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)