From 835607d4979b9bd6541210a0366ad5f753ed210c Mon Sep 17 00:00:00 2001 From: Tom Rollet Date: Tue, 8 Jun 2021 14:55:48 +0200 Subject: [PATCH] sim: Add serialization for file descriptor array Add serialization of the fd array when checkpointing in SE mode. With this patch, host backed files are restored. Further work needs to be done for restoring other types of file descriptor. As the file path saved is relative, on restoration of the checkpoint, it may fail to open the file if the path is no longer valid. If it cannot open the file, it will exit the simulation with a meaningful error message. Change-Id: I4d0c7cd614a8abaffcae9aba1a28c9fdbc023c5a Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/46619 Reviewed-by: Jason Lowe-Power Maintainer: Jason Lowe-Power Tested-by: kokoro --- src/sim/fd_array.cc | 83 ++++++++++++++++++++++++++++++++++++++++- src/sim/fd_array.hh | 9 ++++- src/sim/fd_entry.cc | 2 + src/sim/fd_entry.hh | 41 ++++++++++++++------ src/sim/process.cc | 15 +++++--- src/sim/syscall_emul.hh | 2 + 6 files changed, 133 insertions(+), 19 deletions(-) diff --git a/src/sim/fd_array.cc b/src/sim/fd_array.cc index 364bd10500..0da99787c1 100644 --- a/src/sim/fd_array.cc +++ b/src/sim/fd_array.cc @@ -298,7 +298,7 @@ FDArray::openFile(std::string const& filename, int flags, mode_t mode) const int sim_fd = open(filename.c_str(), flags, mode); if (sim_fd != -1) return sim_fd; - fatal("Unable to open %s with mode %O", filename, mode); + fatal("Unable to open %s with mode %d", filename, mode); } int @@ -348,3 +348,84 @@ FDArray::closeFDEntry(int tgt_fd) return status; } + +void +FDArray::serialize(CheckpointOut &cp) const { + ScopedCheckpointSection sec(cp, "fdarray"); + paramOut(cp, "size", _fdArray.size()); + for (int tgt_fd = 0; tgt_fd < _fdArray.size(); tgt_fd++) { + auto fd = _fdArray[tgt_fd]; + ScopedCheckpointSection sec(cp, csprintf("Entry%d", tgt_fd)); + if (!fd) { + paramOut(cp, "class", FDEntry::FDClass::fd_null); + continue; + } + paramOut(cp, "class", fd->getClass()); + fd->serialize(cp); + } +} + +void +FDArray::unserialize(CheckpointIn &cp) { + ScopedCheckpointSection sec(cp, "fdarray"); + uint64_t size; + paramIn(cp, "size", size); + assert(_fdArray.size() == size && + "FDArray sizes do not match at unserialize!"); + + for (int tgt_fd = 0; tgt_fd < _fdArray.size(); tgt_fd++) { + if (tgt_fd == STDIN_FILENO || tgt_fd == STDOUT_FILENO || + tgt_fd == STDERR_FILENO) + continue; + ScopedCheckpointSection sec(cp, csprintf("Entry%d", tgt_fd)); + FDEntry::FDClass fd_class; + paramIn(cp, "class", fd_class); + std::shared_ptr fdep; + + switch (fd_class) { + case FDEntry::FDClass::fd_base: + panic("Abstract fd entry was serialized"); + break; + case FDEntry::FDClass::fd_hb: + fdep = std::make_shared(0, 0); + break; + case FDEntry::FDClass::fd_file: + fdep = std::make_shared(0, 0, "", 0, 00); + break; + case FDEntry::FDClass::fd_device: + fdep = std::make_shared(nullptr, ""); + break; + case FDEntry::FDClass::fd_pipe: + fdep = std::make_shared( + 0, 0, PipeFDEntry::EndType::read); + break; + case FDEntry::FDClass::fd_socket: + fdep = std::make_shared(0, 0, 0, 0); + break; + case FDEntry::FDClass::fd_null: + continue; + default: + panic("Unrecognized fd class"); + break; + } + + fdep->unserialize(cp); + + auto this_ffd = std::dynamic_pointer_cast(fdep); + if (!this_ffd) + continue; + setFDEntry(tgt_fd, fdep); + + mode_t mode = this_ffd->getFileMode(); + std::string const& path = this_ffd->getFileName(); + int flags = this_ffd->getFlags(); + + // Re-open the file and assign a new sim_fd + int sim_fd = openFile(path, flags, mode); + this_ffd->setSimFD(sim_fd); + + // Restore the file offset to the proper value + uint64_t file_offset = this_ffd->getFileOffset(); + lseek(sim_fd, file_offset, SEEK_SET); + } +} diff --git a/src/sim/fd_array.hh b/src/sim/fd_array.hh index 5295566471..e80673f018 100644 --- a/src/sim/fd_array.hh +++ b/src/sim/fd_array.hh @@ -40,8 +40,9 @@ #include #include "sim/fd_entry.hh" +#include "sim/serialize.hh" -class FDArray +class FDArray : public Serializable { public: /** @@ -111,6 +112,12 @@ class FDArray */ int closeFDEntry(int tgt_fd); + /* + * Serialization methods for file descriptors + */ + void serialize(CheckpointOut &cp) const override; + void unserialize(CheckpointIn &cp) override; + private: /** * Help clarify our intention when opening files in the init and diff --git a/src/sim/fd_entry.cc b/src/sim/fd_entry.cc index 02677d6224..6861a940a0 100644 --- a/src/sim/fd_entry.cc +++ b/src/sim/fd_entry.cc @@ -54,6 +54,7 @@ FileFDEntry::serialize(CheckpointOut &cp) const SERIALIZE_SCALAR(_flags); SERIALIZE_SCALAR(_fileName); SERIALIZE_SCALAR(_fileOffset); + SERIALIZE_SCALAR(_mode); } void @@ -63,6 +64,7 @@ FileFDEntry::unserialize(CheckpointIn &cp) UNSERIALIZE_SCALAR(_flags); UNSERIALIZE_SCALAR(_fileName); UNSERIALIZE_SCALAR(_fileOffset); + UNSERIALIZE_SCALAR(_mode); } void diff --git a/src/sim/fd_entry.hh b/src/sim/fd_entry.hh index c24710dfa1..50a9e60bb6 100644 --- a/src/sim/fd_entry.hh +++ b/src/sim/fd_entry.hh @@ -42,6 +42,7 @@ class EmulatedDriver; + /** * Holds a single file descriptor mapping and that mapping's data for * processes running in syscall emulation mode. @@ -49,14 +50,28 @@ class EmulatedDriver; class FDEntry : public Serializable { public: + + enum FDClass + { + fd_base, + fd_hb, + fd_file, + fd_pipe, + fd_device, + fd_socket, + fd_null + }; + FDEntry(bool close_on_exec = false) : _closeOnExec(close_on_exec) - { } + { _class = FDClass::fd_base; } virtual std::shared_ptr clone() const = 0; bool getCOE() const { return _closeOnExec; } + FDClass getClass() const { return _class; } + void setCOE(bool close_on_exec) { _closeOnExec = close_on_exec; } virtual void serialize(CheckpointOut &cp) const; @@ -64,6 +79,7 @@ class FDEntry : public Serializable protected: bool _closeOnExec; + FDClass _class; }; /** @@ -76,11 +92,11 @@ class HBFDEntry: public FDEntry public: HBFDEntry(int flags, int sim_fd, bool close_on_exec = false) : FDEntry(close_on_exec), _flags(flags), _simFD(sim_fd) - { } + { _class = FDClass::fd_hb; } HBFDEntry(HBFDEntry const& reg, bool close_on_exec = false) : FDEntry(close_on_exec), _flags(reg._flags), _simFD(reg._simFD) - { } + { _class = FDClass::fd_hb; } std::shared_ptr clone() const override @@ -114,12 +130,12 @@ class FileFDEntry: public HBFDEntry uint64_t file_offset, bool close_on_exec = false) : HBFDEntry(flags, sim_fd, close_on_exec), _fileName(file_name), _fileOffset(file_offset) - { } + { _class = FDClass::fd_file; } FileFDEntry(FileFDEntry const& reg, bool close_on_exec = false) : HBFDEntry(reg._flags, reg._simFD, close_on_exec), _fileName(reg._fileName), _fileOffset(reg._fileOffset) - { } + { _class = FDClass::fd_file; } std::shared_ptr clone() const override @@ -129,9 +145,11 @@ class FileFDEntry: public HBFDEntry std::string const& getFileName() const { return _fileName; } uint64_t getFileOffset() const { return _fileOffset; } + mode_t getFileMode() const { return _mode; } void setFileName(std::string const& file_name) { _fileName = file_name; } void setFileOffset(uint64_t f_off) { _fileOffset = f_off; } + void setFileMode(mode_t mode) { _mode = mode; } void serialize(CheckpointOut &cp) const override; void unserialize(CheckpointIn &cp) override; @@ -139,6 +157,7 @@ class FileFDEntry: public HBFDEntry private: std::string _fileName; uint64_t _fileOffset; + mode_t _mode; }; /** @@ -158,13 +177,13 @@ class PipeFDEntry: public HBFDEntry bool close_on_exec = false) : HBFDEntry(flags, sim_fd, close_on_exec), _pipeReadSource(-1), _pipeEndType(pipe_end_type) - { } + { _class = FDClass::fd_pipe; } PipeFDEntry(PipeFDEntry const& pipe, bool close_on_exec = false) : HBFDEntry(pipe._flags, pipe._simFD, close_on_exec), _pipeReadSource(pipe._pipeReadSource), _pipeEndType(pipe._pipeEndType) - { } + { _class = FDClass::fd_pipe; } std::shared_ptr clone() const override @@ -196,12 +215,12 @@ class DeviceFDEntry : public FDEntry DeviceFDEntry(EmulatedDriver *driver, std::string const& file_name, bool close_on_exec = false) : FDEntry(close_on_exec), _driver(driver), _fileName(file_name) - { } + { _class = FDClass::fd_device; } DeviceFDEntry(DeviceFDEntry const& dev, bool close_on_exec = false) : FDEntry(close_on_exec), _driver(dev._driver), _fileName(dev._fileName) - { } + { _class = FDClass::fd_device; } std::shared_ptr clone() const override @@ -227,12 +246,12 @@ class SocketFDEntry: public HBFDEntry bool close_on_exec = false) : HBFDEntry(0, sim_fd, close_on_exec), _domain(domain), _type(type), _protocol(protocol) - { } + { _class = FDClass::fd_socket; } SocketFDEntry(SocketFDEntry const& reg, bool close_on_exec = false) : HBFDEntry(reg._flags, reg._simFD, close_on_exec), _domain(reg._domain), _type(reg._type), _protocol(reg._protocol) - { } + { _class = FDClass::fd_socket; } std::shared_ptr clone() const override diff --git a/src/sim/process.cc b/src/sim/process.cc index 4902a13634..a77bef3a96 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -356,12 +356,14 @@ Process::serialize(CheckpointOut &cp) const { memState->serialize(cp); pTable->serialize(cp); + fds->serialize(cp); + /** - * Checkpoints for file descriptors currently do not work. Need to - * come back and fix them at a later date. + * Checkpoints for pipes, device drivers or sockets currently + * do not work. Need to come back and fix them at a later date. */ - warn("Checkpoints for file descriptors currently do not work."); + warn("Checkpoints for pipes, device drivers and sockets do not work."); } void @@ -369,11 +371,12 @@ Process::unserialize(CheckpointIn &cp) { memState->unserialize(cp); pTable->unserialize(cp); + fds->unserialize(cp); /** - * Checkpoints for file descriptors currently do not work. Need to - * come back and fix them at a later date. + * Checkpoints for pipes, device drivers or sockets currently + * do not work. Need to come back and fix them at a later date. */ - warn("Checkpoints for file descriptors currently do not work."); + warn("Checkpoints for pipes, device drivers and sockets do not work."); // The above returns a bool so that you could do something if you don't // find the param in the checkpoint if you wanted to, like set a default // but in this case we'll just stick with the instantiated value if not diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh index 54e92b218b..cd2d8d16ef 100644 --- a/src/sim/syscall_emul.hh +++ b/src/sim/syscall_emul.hh @@ -887,6 +887,8 @@ openatFunc(SyscallDesc *desc, ThreadContext *tc, * process to act as a handle for the opened file. */ auto ffdp = std::make_shared(sim_fd, host_flags, path, 0); + // Record the file mode for checkpoint restoring + ffdp->setFileMode(mode); int tgt_fd = p->fds->allocFD(ffdp); DPRINTF_SYSCALL(Verbose, "%s: sim_fd[%d], target_fd[%d] -> path:%s\n" "(inferred from:%s)\n", desc->name(),