gem5  v20.0.0.3
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 
171 class CowDiskCallback : public Callback
172 {
173  private:
175 
176  public:
178  void process() { image->save(); delete this; }
179 };
180 
182  : DiskImage(p), filename(p->image_file), child(p->child), table(NULL)
183 {
184  if (filename.empty()) {
185  initSectorTable(p->table_size);
186  } else {
187  if (!open(filename)) {
188  if (p->read_only)
189  fatal("could not open read-only file");
190  initSectorTable(p->table_size);
191  }
192 
193  if (!p->read_only)
195  }
196 }
197 
199 {
200  SectorTable::iterator i = table->begin();
201  SectorTable::iterator end = table->end();
202 
203  while (i != end) {
204  delete (*i).second;
205  ++i;
206  }
207 }
208 
209 void
211 {
212  if (!dynamic_cast<const Params *>(params())->read_only &&
213  !filename.empty()) {
214  inform("Disabling saving of COW image in forked child process.\n");
215  filename = "";
216  }
217 }
218 
219 void
220 SafeRead(ifstream &stream, void *data, int count)
221 {
222  stream.read((char *)data, count);
223  if (!stream.is_open())
224  panic("file not open");
225 
226  if (stream.eof())
227  panic("premature end-of-file");
228 
229  if (stream.bad() || stream.fail())
230  panic("error reading cowdisk image");
231 }
232 
233 template<class T>
234 void
235 SafeRead(ifstream &stream, T &data)
236 {
237  SafeRead(stream, &data, sizeof(data));
238 }
239 
240 template<class T>
241 void
242 SafeReadSwap(ifstream &stream, T &data)
243 {
244  SafeRead(stream, &data, sizeof(data));
245  data = letoh(data); //is this the proper byte order conversion?
246 }
247 
248 bool
249 CowDiskImage::open(const string &file)
250 {
251  ifstream stream(file.c_str());
252  if (!stream.is_open())
253  return false;
254 
255  if (stream.fail() || stream.bad())
256  panic("Error opening %s", file);
257 
258  uint64_t magic;
259  SafeRead(stream, magic);
260 
261  if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0)
262  panic("Could not open %s: Invalid magic", file);
263 
264  uint32_t major, minor;
265  SafeReadSwap(stream, major);
266  SafeReadSwap(stream, minor);
267 
268  if (major != VersionMajor && minor != VersionMinor)
269  panic("Could not open %s: invalid version %d.%d != %d.%d",
270  file, major, minor, VersionMajor, VersionMinor);
271 
272  uint64_t sector_count;
273  SafeReadSwap(stream, sector_count);
274  table = new SectorTable(sector_count);
275 
276 
277  for (uint64_t i = 0; i < sector_count; i++) {
278  uint64_t offset;
279  SafeReadSwap(stream, offset);
280 
281  Sector *sector = new Sector;
282  SafeRead(stream, sector, sizeof(Sector));
283 
284  assert(table->find(offset) == table->end());
285  (*table)[offset] = sector;
286  }
287 
288  stream.close();
289 
290  initialized = true;
291  return true;
292 }
293 
294 void
296 {
297  table = new SectorTable(hash_size);
298 
299  initialized = true;
300 }
301 
302 void
303 SafeWrite(ofstream &stream, const void *data, int count)
304 {
305  stream.write((const char *)data, count);
306  if (!stream.is_open())
307  panic("file not open");
308 
309  if (stream.eof())
310  panic("premature end-of-file");
311 
312  if (stream.bad() || stream.fail())
313  panic("error reading cowdisk image");
314 }
315 
316 template<class T>
317 void
318 SafeWrite(ofstream &stream, const T &data)
319 {
320  SafeWrite(stream, &data, sizeof(data));
321 }
322 
323 template<class T>
324 void
325 SafeWriteSwap(ofstream &stream, const T &data)
326 {
327  T swappeddata = letoh(data); //is this the proper byte order conversion?
328  SafeWrite(stream, &swappeddata, sizeof(data));
329 }
330 void
332 {
333  // filename will be set to the empty string to disable saving of
334  // the COW image in a forked child process. Save will still be
335  // called because there is no easy way to unregister the exit
336  // callback.
337  if (!filename.empty())
338  save(filename);}
339 
340 void
341 CowDiskImage::save(const string &file) const
342 {
343  if (!initialized)
344  panic("RawDiskImage not initialized");
345 
346  ofstream stream(file.c_str());
347  if (!stream.is_open() || stream.fail() || stream.bad())
348  panic("Error opening %s", file);
349 
350  uint64_t magic;
351  memcpy(&magic, "COWDISK!", sizeof(magic));
352  SafeWrite(stream, magic);
353 
354  SafeWriteSwap(stream, (uint32_t)VersionMajor);
355  SafeWriteSwap(stream, (uint32_t)VersionMinor);
356  SafeWriteSwap(stream, (uint64_t)table->size());
357 
358  uint64_t size = table->size();
359  SectorTable::iterator iter = table->begin();
360  SectorTable::iterator end = table->end();
361 
362  for (uint64_t i = 0; i < size; i++) {
363  if (iter == end)
364  panic("Incorrect Table Size during save of COW disk image");
365 
366  SafeWriteSwap(stream, (uint64_t)(*iter).first);
367  SafeWrite(stream, (*iter).second->data, sizeof(Sector));
368  ++iter;
369  }
370 
371  stream.close();
372 }
373 
374 void
376 {
377  SectorTable::iterator i = table->begin();
378  SectorTable::iterator end = table->end();
379 
380  while (i != end) {
381  child->write((*i).second->data, (*i).first);
382  ++i;
383  }
384 }
385 
386 std::streampos
388 { return child->size(); }
389 
390 std::streampos
391 CowDiskImage::read(uint8_t *data, std::streampos offset) const
392 {
393  if (!initialized)
394  panic("CowDiskImage not initialized");
395 
396  if (offset > size())
397  panic("access out of bounds");
398 
399  SectorTable::const_iterator i = table->find(offset);
400  if (i == table->end())
401  return child->read(data, offset);
402  else {
403  memcpy(data, (*i).second->data, SectorSize);
404  DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
405  DDUMP(DiskImageRead, data, SectorSize);
406  return SectorSize;
407  }
408 }
409 
410 std::streampos
411 CowDiskImage::write(const uint8_t *data, std::streampos offset)
412 {
413  if (!initialized)
414  panic("RawDiskImage not initialized");
415 
416  if (offset > size())
417  panic("access out of bounds");
418 
419  SectorTable::iterator i = table->find(offset);
420  if (i == table->end()) {
421  Sector *sector = new Sector;
422  memcpy(sector, data, SectorSize);
423  table->insert(make_pair(offset, sector));
424  } else {
425  memcpy((*i).second->data, data, SectorSize);
426  }
427 
428  DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
429  DDUMP(DiskImageWrite, data, SectorSize);
430 
431  return SectorSize;
432 }
433 
434 void
436 {
437  string cowFilename = name() + ".cow";
438  SERIALIZE_SCALAR(cowFilename);
439  save(CheckpointIn::dir() + "/" + cowFilename);
440 }
441 
442 void
444 {
445  string cowFilename;
446  UNSERIALIZE_SCALAR(cowFilename);
447  cowFilename = cp.getCptDir() + "/" + cowFilename;
448  open(cowFilename);
449 }
450 
451 CowDiskImage *
452 CowDiskImageParams::create()
453 {
454  return new CowDiskImage(this);
455 }
count
Definition: misc.hh:703
std::streampos write(const uint8_t *data, std::streampos offset) override
Definition: disk_image.cc:411
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:163
#define DPRINTF(x,...)
Definition: trace.hh:225
std::streampos size() const override
Definition: disk_image.cc:100
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:171
Generic callback class.
Definition: callback.hh:39
void save() const
Definition: disk_image.cc:331
Bitfield< 7 > i
CowDiskImage(const Params *p)
Definition: disk_image.cc:181
std::streampos read(uint8_t *data, std::streampos offset) const override
Definition: disk_image.cc:113
bool initialized
Definition: disk_image.hh:52
#define DDUMP(x, data, count)
Definition: trace.hh:224
std::streampos size() const override
Definition: disk_image.cc:387
Bitfield< 23, 0 > offset
Definition: types.hh:152
void SafeReadSwap(ifstream &stream, T &data)
Definition: disk_image.cc:242
Overload hash function for BasicBlockRange type.
Definition: vec_reg.hh:587
T letoh(T value)
Definition: byteswap.hh:141
Definition: cprintf.cc:40
Bitfield< 4, 0 > mode
Specialization for accessing a copy-on-write disk image layer.
Definition: disk_image.hh:104
static const uint32_t VersionMinor
Definition: disk_image.hh:108
void SafeWrite(ofstream &stream, const void *data, int count)
Definition: disk_image.cc:303
CowDiskImage * image
Definition: disk_image.cc:174
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: disk_image.cc:435
void notifyFork() override
Notify a child process of a fork.
Definition: disk_image.cc:66
virtual std::streampos size() const =0
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:770
std::string filename
Definition: disk_image.hh:117
#define inform(...)
Definition: logging.hh:209
void close()
Definition: disk_image.cc:94
std::unordered_map< uint64_t, Sector * > SectorTable
Definition: disk_image.hh:114
std::string file
Definition: disk_image.hh:74
virtual std::streampos write(const uint8_t *data, std::streampos offset)=0
#define SectorSize
Definition: disk_image.hh:44
void registerExitCallback(Callback *callback)
Register an exit callback.
Definition: core.cc:140
void SafeRead(ifstream &stream, void *data, int count)
Definition: disk_image.cc:220
Basic interface for accessing a disk image.
Definition: disk_image.hh:49
const Params * params() const
Definition: sim_object.hh:119
void open(const std::string &filename, bool rd_only=false)
Definition: disk_image.cc:77
std::streampos disk_size
Definition: disk_image.hh:76
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:763
RawDiskImage(const Params *p)
Definition: disk_image.cc:58
static std::string dir()
Get the current checkout directory name.
Definition: serialize.cc:263
static const uint32_t VersionMajor
Definition: disk_image.hh:107
virtual const std::string name() const
Definition: sim_object.hh:129
void SafeWriteSwap(ofstream &stream, const T &data)
Definition: disk_image.cc:325
std::ostream CheckpointOut
Definition: serialize.hh:63
void writeback()
Definition: disk_image.cc:375
DiskImage * child
Definition: disk_image.hh:118
std::streampos read(uint8_t *data, std::streampos offset) const override
Definition: disk_image.cc:391
SectorTable * table
Definition: disk_image.hh:119
virtual std::streampos read(uint8_t *data, std::streampos offset) const =0
std::fstream stream
Definition: disk_image.hh:73
Disk Image Interfaces.
const uint8_t image_file[]
This image file contains the text "This is a test image.\n" 31 times.
const std::string getCptDir()
Definition: serialize.hh:85
std::streampos write(const uint8_t *data, std::streampos offset) override
Definition: disk_image.cc:135
void initSectorTable(int hash_size)
Definition: disk_image.cc:295
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: disk_image.cc:443
bool open(const std::string &file)
Definition: disk_image.cc:249
Specialization for accessing a raw disk image.
Definition: disk_image.hh:70
DiskImageParams Params
Definition: disk_image.hh:55
Bitfield< 0 > p
const char data[]
void process()
virtual process function that is invoked when the callback queue is executed.
Definition: disk_image.cc:178
CowDiskCallback(CowDiskImage *i)
Definition: disk_image.cc:177
void notifyFork() override
Notify a child process of a fork.
Definition: disk_image.cc:210

Generated on Fri Jul 3 2020 15:53:02 for gem5 by doxygen 1.8.13