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(),