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:
Tom Rollet
2021-06-08 14:55:48 +02:00
parent b9d35c7edc
commit 835607d497
6 changed files with 133 additions and 19 deletions

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

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