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 <power.jg@gmail.com> Maintainer: Jason Lowe-Power <power.jg@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
@@ -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<FDEntry> 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<HBFDEntry>(0, 0);
|
||||
break;
|
||||
case FDEntry::FDClass::fd_file:
|
||||
fdep = std::make_shared<FileFDEntry>(0, 0, "", 0, 00);
|
||||
break;
|
||||
case FDEntry::FDClass::fd_device:
|
||||
fdep = std::make_shared<DeviceFDEntry>(nullptr, "");
|
||||
break;
|
||||
case FDEntry::FDClass::fd_pipe:
|
||||
fdep = std::make_shared<PipeFDEntry>(
|
||||
0, 0, PipeFDEntry::EndType::read);
|
||||
break;
|
||||
case FDEntry::FDClass::fd_socket:
|
||||
fdep = std::make_shared<SocketFDEntry>(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<FileFDEntry>(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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,9 @@
|
||||
#include <string>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<FDEntry> 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<FDEntry>
|
||||
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<FDEntry>
|
||||
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<FDEntry>
|
||||
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<FDEntry>
|
||||
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<FDEntry>
|
||||
clone() const override
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -887,6 +887,8 @@ openatFunc(SyscallDesc *desc, ThreadContext *tc,
|
||||
* process to act as a handle for the opened file.
|
||||
*/
|
||||
auto ffdp = std::make_shared<FileFDEntry>(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(),
|
||||
|
||||
Reference in New Issue
Block a user