gem5  v20.1.0.0
disk_image.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2005 The Regents of The University of Michigan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
34 
35 #include <sys/types.h>
36 #include <sys/uio.h>
37 #include <unistd.h>
38 
39 #include <cerrno>
40 #include <cstring>
41 #include <fstream>
42 #include <string>
43 
44 #include "base/callback.hh"
45 #include "base/logging.hh"
46 #include "base/trace.hh"
47 #include "debug/DiskImageRead.hh"
48 #include "debug/DiskImageWrite.hh"
49 #include "sim/byteswap.hh"
50 #include "sim/sim_exit.hh"
51 
52 using namespace std;
53 
55 //
56 // Raw Disk image
57 //
59  : DiskImage(p), disk_size(0)
60 { open(p->image_file, p->read_only); }
61 
63 { close(); }
64 
65 void
67 {
68  if (initialized && !readonly)
69  panic("Attempting to fork system with read-write raw disk image.");
70 
71  const Params *p(dynamic_cast<const Params *>(params()));
72  close();
73  open(p->image_file, p->read_only);
74 }
75 
76 void
77 RawDiskImage::open(const string &filename, bool rd_only)
78 {
79  if (!filename.empty()) {
80  initialized = true;
81  readonly = rd_only;
82  file = filename;
83 
84  ios::openmode mode = ios::in | ios::binary;
85  if (!readonly)
86  mode |= ios::out;
87  stream.open(file.c_str(), mode);
88  if (!stream.is_open())
89  panic("Error opening %s", filename);
90  }
91 }
92 
93 void
95 {
96  stream.close();
97 }
98 
99 std::streampos
101 {
102  if (disk_size == 0) {
103  if (!stream.is_open())
104  panic("file not open!\n");
105  stream.seekg(0, ios::end);
106  disk_size = stream.tellg();
107  }
108 
109  return disk_size / SectorSize;
110 }
111 
112 std::streampos
113 RawDiskImage::read(uint8_t *data, std::streampos offset) const
114 {
115  if (!initialized)
116  panic("RawDiskImage not initialized");
117 
118  if (!stream.is_open())
119  panic("file not open!\n");
120 
121  stream.seekg(offset * SectorSize, ios::beg);
122  if (!stream.good())
123  panic("Could not seek to location in file");
124 
125  streampos pos = stream.tellg();
126  stream.read((char *)data, SectorSize);
127 
128  DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
129  DDUMP(DiskImageRead, data, SectorSize);
130 
131  return stream.tellg() - pos;
132 }
133 
134 std::streampos
135 RawDiskImage::write(const uint8_t *data, std::streampos offset)
136 {
137  if (!initialized)
138  panic("RawDiskImage not initialized");
139 
140  if (readonly)
141  panic("Cannot write to a read only disk image");
142 
143  if (!stream.is_open())
144  panic("file not open!\n");
145 
146  stream.seekp(offset * SectorSize, ios::beg);
147  if (!stream.good())
148  panic("Could not seek to location in file");
149 
150  DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
151  DDUMP(DiskImageWrite, data, SectorSize);
152 
153  streampos pos = stream.tellp();
154  stream.write((const char *)data, SectorSize);
155  return stream.tellp() - pos;
156 }
157 
158 RawDiskImage *
159 RawDiskImageParams::create()
160 {
161  return new RawDiskImage(this);
162 }
163 
165 //
166 // Copy on Write Disk image
167 //
168 const uint32_t CowDiskImage::VersionMajor = 1;
169 const uint32_t CowDiskImage::VersionMinor = 0;
170 
172  : DiskImage(p), filename(p->image_file), child(p->child), table(NULL)
173 {
174  if (filename.empty()) {
175  initSectorTable(p->table_size);
176  } else {
177  if (!open(filename)) {
178  if (p->read_only)
179  fatal("could not open read-only file");
180  initSectorTable(p->table_size);
181  }
182 
183  if (!p->read_only)
184  registerExitCallback([this]() { save(); });
185  }
186 }
187 
189 {
190  SectorTable::iterator i = table->begin();
191  SectorTable::iterator end = table->end();
192 
193  while (i != end) {
194  delete (*i).second;
195  ++i;
196  }
197 }
198 
199 void
201 {
202  if (!dynamic_cast<const Params *>(params())->read_only &&
203  !filename.empty()) {
204  inform("Disabling saving of COW image in forked child process.\n");
205  filename = "";
206  }
207 }
208 
209 void
210 SafeRead(ifstream &stream, void *data, int count)
211 {
212  stream.read((char *)data, count);
213  if (!stream.is_open())
214  panic("file not open");
215 
216  if (stream.eof())
217  panic("premature end-of-file");
218 
219  if (stream.bad() || stream.fail())
220  panic("error reading cowdisk image");
221 }
222 
223 template<class T>
224 void
225 SafeRead(ifstream &stream, T &data)
226 {
227  SafeRead(stream, &data, sizeof(data));
228 }
229 
230 template<class T>
231 void
232 SafeReadSwap(ifstream &stream, T &data)
233 {
234  SafeRead(stream, &data, sizeof(data));
235  data = letoh(data); //is this the proper byte order conversion?
236 }
237 
238 bool
239 CowDiskImage::open(const string &file)
240 {
241  ifstream stream(file.c_str());
242  if (!stream.is_open())
243  return false;
244 
245  if (stream.fail() || stream.bad())
246  panic("Error opening %s", file);
247 
248  uint64_t magic;
249  SafeRead(stream, magic);
250 
251  if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0)
252  panic("Could not open %s: Invalid magic", file);
253 
254  uint32_t major, minor;
255  SafeReadSwap(stream, major);
256  SafeReadSwap(stream, minor);
257 
258  if (major != VersionMajor && minor != VersionMinor)
259  panic("Could not open %s: invalid version %d.%d != %d.%d",
260  file, major, minor, VersionMajor, VersionMinor);
261 
262  uint64_t sector_count;
263  SafeReadSwap(stream, sector_count);
264  table = new SectorTable(sector_count);
265 
266 
267  for (uint64_t i = 0; i < sector_count; i++) {
268  uint64_t offset;
269  SafeReadSwap(stream, offset);
270 
271  Sector *sector = new Sector;
272  SafeRead(stream, sector, sizeof(Sector));
273 
274  assert(table->find(offset) == table->end());
275  (*table)[offset] = sector;
276  }
277 
278  stream.close();
279 
280  initialized = true;
281  return true;
282 }
283 
284 void
286 {
287  table = new SectorTable(hash_size);
288 
289  initialized = true;
290 }
291 
292 void
293 SafeWrite(ofstream &stream, const void *data, int count)
294 {
295  stream.write((const char *)data, count);
296  if (!stream.is_open())
297  panic("file not open");
298 
299  if (stream.eof())
300  panic("premature end-of-file");
301 
302  if (stream.bad() || stream.fail())
303  panic("error reading cowdisk image");
304 }
305 
306 template<class T>
307 void
308 SafeWrite(ofstream &stream, const T &data)
309 {
310  SafeWrite(stream, &data, sizeof(data));
311 }
312 
313 template<class T>
314 void
315 SafeWriteSwap(ofstream &stream, const T &data)
316 {
317  T swappeddata = letoh(data); //is this the proper byte order conversion?
318  SafeWrite(stream, &swappeddata, sizeof(data));
319 }
320 void
322 {
323  // filename will be set to the empty string to disable saving of
324  // the COW image in a forked child process. Save will still be
325  // called because there is no easy way to unregister the exit
326  // callback.
327  if (!filename.empty())
328  save(filename);}
329 
330 void
331 CowDiskImage::save(const string &file) const
332 {
333  if (!initialized)
334  panic("RawDiskImage not initialized");
335 
336  ofstream stream(file.c_str());
337  if (!stream.is_open() || stream.fail() || stream.bad())
338  panic("Error opening %s", file);
339 
340  uint64_t magic;
341  memcpy(&magic, "COWDISK!", sizeof(magic));
342  SafeWrite(stream, magic);
343 
344  SafeWriteSwap(stream, (uint32_t)VersionMajor);
345  SafeWriteSwap(stream, (uint32_t)VersionMinor);
346  SafeWriteSwap(stream, (uint64_t)table->size());
347 
348  uint64_t size = table->size();
349  SectorTable::iterator iter = table->begin();
350  SectorTable::iterator end = table->end();
351 
352  for (uint64_t i = 0; i < size; i++) {
353  if (iter == end)
354  panic("Incorrect Table Size during save of COW disk image");
355 
356  SafeWriteSwap(stream, (uint64_t)(*iter).first);
357  SafeWrite(stream, (*iter).second->data, sizeof(Sector));
358  ++iter;
359  }
360 
361  stream.close();
362 }
363 
364 void
366 {
367  SectorTable::iterator i = table->begin();
368  SectorTable::iterator end = table->end();
369 
370  while (i != end) {
371  child->write((*i).second->data, (*i).first);
372  ++i;
373  }
374 }
375 
376 std::streampos
378 { return child->size(); }
379 
380 std::streampos
381 CowDiskImage::read(uint8_t *data, std::streampos offset) const
382 {
383  if (!initialized)
384  panic("CowDiskImage not initialized");
385 
386  if (offset > size())
387  panic("access out of bounds");
388 
389  SectorTable::const_iterator i = table->find(offset);
390  if (i == table->end())
391  return child->read(data, offset);
392  else {
393  memcpy(data, (*i).second->data, SectorSize);
394  DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
395  DDUMP(DiskImageRead, data, SectorSize);
396  return SectorSize;
397  }
398 }
399 
400 std::streampos
401 CowDiskImage::write(const uint8_t *data, std::streampos offset)
402 {
403  if (!initialized)
404  panic("RawDiskImage not initialized");
405 
406  if (offset > size())
407  panic("access out of bounds");
408 
409  SectorTable::iterator i = table->find(offset);
410  if (i == table->end()) {
411  Sector *sector = new Sector;
412  memcpy(sector, data, SectorSize);
413  table->insert(make_pair(offset, sector));
414  } else {
415  memcpy((*i).second->data, data, SectorSize);
416  }
417 
418  DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
419  DDUMP(DiskImageWrite, data, SectorSize);
420 
421  return SectorSize;
422 }
423 
424 void
426 {
427  string cowFilename = name() + ".cow";
428  SERIALIZE_SCALAR(cowFilename);
429  save(CheckpointIn::dir() + "/" + cowFilename);
430 }
431 
432 void
434 {
435  string cowFilename;
436  UNSERIALIZE_SCALAR(cowFilename);
437  cowFilename = cp.getCptDir() + "/" + cowFilename;
438  open(cowFilename);
439 }
440 
441 CowDiskImage *
442 CowDiskImageParams::create()
443 {
444  return new CowDiskImage(this);
445 }
RawDiskImage
Specialization for accessing a raw disk image.
Definition: disk_image.hh:70
fatal
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:183
DiskImage::write
virtual std::streampos write(const uint8_t *data, std::streampos offset)=0
CowDiskImage::write
std::streampos write(const uint8_t *data, std::streampos offset) override
Definition: disk_image.cc:401
SafeReadSwap
void SafeReadSwap(ifstream &stream, T &data)
Definition: disk_image.cc:232
CowDiskImage::Sector
Definition: disk_image.hh:111
data
const char data[]
Definition: circlebuf.test.cc:42
UNSERIALIZE_SCALAR
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:797
DiskImage::initialized
bool initialized
Definition: disk_image.hh:52
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
SectorSize
#define SectorSize
Definition: disk_image.hh:44
RawDiskImage::readonly
bool readonly
Definition: disk_image.hh:75
disk_image.hh
CowDiskImage::notifyFork
void notifyFork() override
Notify a child process of a fork.
Definition: disk_image.cc:200
RawDiskImage::size
std::streampos size() const override
Definition: disk_image.cc:100
SafeWriteSwap
void SafeWriteSwap(ofstream &stream, const T &data)
Definition: disk_image.cc:315
X86ISA::count
count
Definition: misc.hh:703
sim_exit.hh
DiskImage::size
virtual std::streampos size() const =0
RawDiskImage::file
std::string file
Definition: disk_image.hh:74
CowDiskImage::CowDiskImage
CowDiskImage(const Params *p)
Definition: disk_image.cc:171
SafeRead
void SafeRead(ifstream &stream, void *data, int count)
Definition: disk_image.cc:210
letoh
T letoh(T value)
Definition: byteswap.hh:141
cp
Definition: cprintf.cc:40
CowDiskImage::table
SectorTable * table
Definition: disk_image.hh:119
registerExitCallback
void registerExitCallback(const std::function< void()> &callback)
Register an exit callback.
Definition: core.cc:140
DiskImage
Basic interface for accessing a disk image.
Definition: disk_image.hh:49
CowDiskImage::size
std::streampos size() const override
Definition: disk_image.cc:377
RawDiskImage::RawDiskImage
RawDiskImage(const Params *p)
Definition: disk_image.cc:58
CowDiskImage::child
DiskImage * child
Definition: disk_image.hh:118
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:234
CowDiskImage::read
std::streampos read(uint8_t *data, std::streampos offset) const override
Definition: disk_image.cc:381
CowDiskImage
Specialization for accessing a copy-on-write disk image layer.
Definition: disk_image.hh:104
CowDiskImage::unserialize
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: disk_image.cc:433
CowDiskImage::writeback
void writeback()
Definition: disk_image.cc:365
ArmISA::mode
Bitfield< 4, 0 > mode
Definition: miscregs_types.hh:70
RawDiskImage::~RawDiskImage
~RawDiskImage()
Definition: disk_image.cc:62
SafeWrite
void SafeWrite(ofstream &stream, const void *data, int count)
Definition: disk_image.cc:293
CowDiskImage::~CowDiskImage
~CowDiskImage()
Definition: disk_image.cc:188
RawDiskImage::stream
std::fstream stream
Definition: disk_image.hh:73
RawDiskImage::notifyFork
void notifyFork() override
Notify a child process of a fork.
Definition: disk_image.cc:66
RawDiskImage::close
void close()
Definition: disk_image.cc:94
CowDiskImage::open
bool open(const std::string &file)
Definition: disk_image.cc:239
RawDiskImage::write
std::streampos write(const uint8_t *data, std::streampos offset) override
Definition: disk_image.cc:135
SimObject::params
const Params * params() const
Definition: sim_object.hh:119
SERIALIZE_SCALAR
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:790
DDUMP
#define DDUMP(x, data, count)
DPRINTF is a debugging trace facility that allows one to selectively enable tracing statements.
Definition: trace.hh:233
SimObject::name
virtual const std::string name() const
Definition: sim_object.hh:133
CheckpointIn::dir
static std::string dir()
Get the current checkout directory name.
Definition: serialize.cc:263
inform
#define inform(...)
Definition: logging.hh:240
CowDiskImage::VersionMajor
static const uint32_t VersionMajor
Definition: disk_image.hh:107
std
Overload hash function for BasicBlockRange type.
Definition: vec_reg.hh:587
CowDiskImage::VersionMinor
static const uint32_t VersionMinor
Definition: disk_image.hh:108
logging.hh
DiskImage::read
virtual std::streampos read(uint8_t *data, std::streampos offset) const =0
CheckpointOut
std::ostream CheckpointOut
Definition: serialize.hh:63
trace.hh
RawDiskImage::open
void open(const std::string &filename, bool rd_only=false)
Definition: disk_image.cc:77
CowDiskImage::filename
std::string filename
Definition: disk_image.hh:117
RawDiskImage::disk_size
std::streampos disk_size
Definition: disk_image.hh:76
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
CheckpointIn
Definition: serialize.hh:67
CowDiskImage::save
void save() const
Definition: disk_image.cc:321
image_file
const uint8_t image_file[]
This image file contains the text "This is a test image.\n" 31 times.
Definition: small_image_file.test.hh:37
CowDiskImage::SectorTable
std::unordered_map< uint64_t, Sector * > SectorTable
Definition: disk_image.hh:114
callback.hh
DiskImage::Params
DiskImageParams Params
Definition: disk_image.hh:55
byteswap.hh
CowDiskImage::serialize
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: disk_image.cc:425
RawDiskImage::read
std::streampos read(uint8_t *data, std::streampos offset) const override
Definition: disk_image.cc:113
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
CowDiskImage::initSectorTable
void initSectorTable(int hash_size)
Definition: disk_image.cc:285
ArmISA::offset
Bitfield< 23, 0 > offset
Definition: types.hh:153

Generated on Wed Sep 30 2020 14:02:11 for gem5 by doxygen 1.8.17