Skip to content

Commit 52cd6d3

Browse files
ayushr2gvisor-bot
authored andcommitted
gofer: Support restore of deleted files whose original path is occupied.
It is possible that the application can open an FD to a file, delete the file, create another file at that path and then checkpoint the container. In such a scenario, our gofer restore logic will fail with EEXIST because a file already exists on the host at that location when we try to recreate it. Use a temporary filename to recreate the file in such a scenario. This file is deleted again anyways. Fixes #11425 PiperOrigin-RevId: 766720146
1 parent f3f2ea7 commit 52cd6d3

File tree

1 file changed

+9
-3
lines changed

1 file changed

+9
-3
lines changed

pkg/sentry/fsimpl/gofer/save_restore.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -426,14 +426,20 @@ func (d *dentry) restoreDeletedDirectory(ctx context.Context, opts *vfs.Complete
426426
func (d *dentry) restoreDeletedRegularFile(ctx context.Context, opts *vfs.CompleteRestoreOptions) error {
427427
// Recreate the file on the host filesystem (this is temporary).
428428
parent := d.parent.Load()
429-
_, h, err := parent.openCreate(ctx, d.name, linux.O_WRONLY, linux.FileMode(d.mode.Load()), auth.KUID(d.uid.Load()), auth.KGID(d.gid.Load()), false /* createDentry */)
429+
name := d.name
430+
_, h, err := parent.openCreate(ctx, name, linux.O_WRONLY, linux.FileMode(d.mode.Load()), auth.KUID(d.uid.Load()), auth.KGID(d.gid.Load()), false /* createDentry */)
431+
if linuxerr.Equals(linuxerr.EEXIST, err) {
432+
name = fmt.Sprintf("%s.tmp-gvisor-restore", name)
433+
log.Warningf("Deleted file %q was replaced with a new file at the same path, using new name %q", genericDebugPathname(d.fs, d), name)
434+
_, h, err = parent.openCreate(ctx, name, linux.O_WRONLY, linux.FileMode(d.mode.Load()), auth.KUID(d.uid.Load()), auth.KGID(d.gid.Load()), false /* createDentry */)
435+
}
430436
if err != nil {
431437
return fmt.Errorf("failed to re-create deleted file %q: %w", genericDebugPathname(d.fs, d), err)
432438
}
433439
defer h.close(ctx)
434440
// In case of errors, clean up the recreated file.
435441
unlinkCU := cleanup.Make(func() {
436-
if err := parent.unlink(ctx, d.name, 0 /* flags */); err != nil {
442+
if err := parent.unlink(ctx, name, 0 /* flags */); err != nil {
437443
log.Warningf("failed to clean up recreated deleted file %q: %v", genericDebugPathname(d.fs, d), err)
438444
}
439445
})
@@ -456,7 +462,7 @@ func (d *dentry) restoreDeletedRegularFile(ctx context.Context, opts *vfs.Comple
456462
}
457463
// Finally, unlink the recreated file.
458464
unlinkCU.Release()
459-
if err := parent.unlink(ctx, d.name, 0 /* flags */); err != nil {
465+
if err := parent.unlink(ctx, name, 0 /* flags */); err != nil {
460466
return fmt.Errorf("failed to clean up recreated deleted file %q: %v", genericDebugPathname(d.fs, d), err)
461467
}
462468
delete(d.fs.savedDeletedOpenDentries, d)

0 commit comments

Comments
 (0)