Use O_DIRECT to read pages.img.

Suggested-by: Jamie Liu <jamieliu@google.com>
PiperOrigin-RevId: 627496836
This commit is contained in:
Ayush Ranjan
2024-04-23 14:01:42 -07:00
committed by gVisor bot
parent e3c20b0bc3
commit f895b63b04
4 changed files with 25 additions and 11 deletions
+9 -1
View File
@@ -39,6 +39,13 @@ type Restore struct {
// detach indicates that runsc has to start a process and exit without waiting it. // detach indicates that runsc has to start a process and exit without waiting it.
detach bool detach bool
// direct indicates whether O_DIRECT should be used for reading the
// checkpoint pages file. It is faster if the checkpoint files are not
// already in the page cache (for example if its coming from an untouched
// network block device). Usually the restore is done only once, so the cost
// of adding the checkpoint files to the page cache can be redundant.
direct bool
} }
// Name implements subcommands.Command.Name. // Name implements subcommands.Command.Name.
@@ -62,6 +69,7 @@ func (r *Restore) SetFlags(f *flag.FlagSet) {
r.Create.SetFlags(f) r.Create.SetFlags(f)
f.StringVar(&r.imagePath, "image-path", "", "directory path to saved container image") f.StringVar(&r.imagePath, "image-path", "", "directory path to saved container image")
f.BoolVar(&r.detach, "detach", false, "detach from the container's process") f.BoolVar(&r.detach, "detach", false, "detach from the container's process")
f.BoolVar(&r.direct, "direct", false, "use O_DIRECT for reading checkpoint pages file")
// Unimplemented flags necessary for compatibility with docker. // Unimplemented flags necessary for compatibility with docker.
@@ -138,7 +146,7 @@ func (r *Restore) Execute(_ context.Context, f *flag.FlagSet, args ...any) subco
} }
log.Debugf("Restore: %v", r.imagePath) log.Debugf("Restore: %v", r.imagePath)
if err := c.Restore(conf, r.imagePath); err != nil { if err := c.Restore(conf, r.imagePath, r.direct); err != nil {
return util.Errorf("starting container: %v", err) return util.Errorf("starting container: %v", err)
} }
+2 -2
View File
@@ -525,7 +525,7 @@ func (c *Container) Start(conf *config.Config) error {
// Restore takes a container and replaces its kernel and file system // Restore takes a container and replaces its kernel and file system
// to restore a container from its state file. // to restore a container from its state file.
func (c *Container) Restore(conf *config.Config, imagePath string) error { func (c *Container) Restore(conf *config.Config, imagePath string, direct bool) error {
log.Debugf("Restore container, cid: %s", c.ID) log.Debugf("Restore container, cid: %s", c.ID)
if err := c.Saver.lock(BlockAcquire); err != nil { if err := c.Saver.lock(BlockAcquire); err != nil {
return err return err
@@ -542,7 +542,7 @@ func (c *Container) Restore(conf *config.Config, imagePath string) error {
log.Warningf("StartContainer hook skipped because running inside container namespace is not supported") log.Warningf("StartContainer hook skipped because running inside container namespace is not supported")
} }
if err := c.Sandbox.Restore(conf, c.ID, imagePath); err != nil { if err := c.Sandbox.Restore(conf, c.ID, imagePath, direct); err != nil {
return err return err
} }
c.changeStatus(Running) c.changeStatus(Running)
+4 -4
View File
@@ -1101,7 +1101,7 @@ func testCheckpointRestore(t *testing.T, conf *config.Config, compression statef
} }
defer cont2.Destroy() defer cont2.Destroy()
if err := cont2.Restore(conf, dir); err != nil { if err := cont2.Restore(conf, dir, false /* direct */); err != nil {
t.Fatalf("error restoring container: %v", err) t.Fatalf("error restoring container: %v", err)
} }
@@ -1144,7 +1144,7 @@ func testCheckpointRestore(t *testing.T, conf *config.Config, compression statef
} }
defer cont3.Destroy() defer cont3.Destroy()
if err := cont3.Restore(conf, dir); err != nil { if err := cont3.Restore(conf, dir, false /* direct */); err != nil {
t.Fatalf("error restoring container: %v", err) t.Fatalf("error restoring container: %v", err)
} }
@@ -1263,7 +1263,7 @@ func TestCheckpointRestoreExecKilled(t *testing.T) {
} }
defer cont2.Destroy() defer cont2.Destroy()
if err := cont2.Restore(conf, dir); err != nil { if err := cont2.Restore(conf, dir, false /* direct */); err != nil {
t.Fatalf("error restoring container: %v", err) t.Fatalf("error restoring container: %v", err)
} }
@@ -1377,7 +1377,7 @@ func TestUnixDomainSockets(t *testing.T) {
} }
defer contRestore.Destroy() defer contRestore.Destroy()
if err := contRestore.Restore(conf, dir); err != nil { if err := contRestore.Restore(conf, dir, false /* direct */); err != nil {
t.Fatalf("error restoring container: %v", err) t.Fatalf("error restoring container: %v", err)
} }
+10 -4
View File
@@ -443,7 +443,7 @@ func (s *Sandbox) StartSubcontainer(spec *specs.Spec, conf *config.Config, cid s
} }
// Restore sends the restore call for a container in the sandbox. // Restore sends the restore call for a container in the sandbox.
func (s *Sandbox) Restore(conf *config.Config, cid string, imagePath string) error { func (s *Sandbox) Restore(conf *config.Config, cid string, imagePath string, direct bool) error {
log.Debugf("Restore sandbox %q", s.ID) log.Debugf("Restore sandbox %q", s.ID)
stateFileName := path.Join(imagePath, boot.CheckpointStateFileName) stateFileName := path.Join(imagePath, boot.CheckpointStateFileName)
@@ -459,9 +459,14 @@ func (s *Sandbox) Restore(conf *config.Config, cid string, imagePath string) err
}, },
} }
// If the image file exists, we must pass it in. // If the pages file exists, we must pass it in.
pagesFileName := path.Join(imagePath, boot.CheckpointPagesFileName) pagesFileName := path.Join(imagePath, boot.CheckpointPagesFileName)
if pf, err := os.Open(pagesFileName); err == nil { pagesReadFlags := os.O_RDONLY
if direct {
// The contents are page-aligned, so it can be opened with O_DIRECT.
pagesReadFlags |= syscall.O_DIRECT
}
if pf, err := os.OpenFile(pagesFileName, pagesReadFlags, 0); err == nil {
defer pf.Close() defer pf.Close()
opt.HavePagesFile = true opt.HavePagesFile = true
opt.FilePayload.Files = append(opt.FilePayload.Files, pf) opt.FilePayload.Files = append(opt.FilePayload.Files, pf)
@@ -1289,9 +1294,10 @@ func (s *Sandbox) Checkpoint(cid string, imagePath string, options statefile.Opt
// When there is no compression, MemoryFile contents are page-aligned. // When there is no compression, MemoryFile contents are page-aligned.
// It is beneficial to store them separately so certain optimizations can be // It is beneficial to store them separately so certain optimizations can be
// applied during restore. // applied during restore. See Restore().
if options.Compression == statefile.CompressionLevelNone { if options.Compression == statefile.CompressionLevelNone {
pagesFilePath := filepath.Join(imagePath, boot.CheckpointPagesFileName) pagesFilePath := filepath.Join(imagePath, boot.CheckpointPagesFileName)
// TODO(b/327603247): Implement optional async O_DIRECT write.
pf, err := os.OpenFile(pagesFilePath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0644) pf, err := os.OpenFile(pagesFilePath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0644)
if err != nil { if err != nil {
return fmt.Errorf("creating checkpoint pages file %q: %w", pagesFilePath, err) return fmt.Errorf("creating checkpoint pages file %q: %w", pagesFilePath, err)