gem5  v22.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/serialize.hh"
51 #include "sim/sim_exit.hh"
52 
53 namespace gem5
54 {
55 
57 //
58 // Raw Disk image
59 //
61  : DiskImage(p), disk_size(0)
62 {
63  open(p.image_file, p.read_only);
64 }
65 
67 {
68  close();
69 }
70 
71 void
73 {
74  if (initialized && !readonly)
75  panic("Attempting to fork system with read-write raw disk image.");
76 
77  const Params &p = dynamic_cast<const Params &>(params());
78  close();
79  open(p.image_file, p.read_only);
80 }
81 
82 void
83 RawDiskImage::open(const std::string &filename, bool rd_only)
84 {
85  if (!filename.empty()) {
86  initialized = true;
87  readonly = rd_only;
88  file = filename;
89 
90  std::ios::openmode mode = std::ios::in | std::ios::binary;
91  if (!readonly)
92  mode |= std::ios::out;
93  stream.open(file.c_str(), mode);
94  if (!stream.is_open())
95  panic("Error opening %s", filename);
96  }
97 }
98 
99 void
101 {
102  stream.close();
103 }
104 
105 std::streampos
107 {
108  if (disk_size == 0) {
109  if (!stream.is_open())
110  panic("file not open!\n");
111  stream.seekg(0, std::ios::end);
112  disk_size = stream.tellg();
113  }
114 
115  return disk_size / SectorSize;
116 }
117 
118 std::streampos
119 RawDiskImage::read(uint8_t *data, std::streampos offset) const
120 {
121  if (!initialized)
122  panic("RawDiskImage not initialized");
123 
124  if (!stream.is_open())
125  panic("file not open!\n");
126 
127  stream.seekg(offset * SectorSize, std::ios::beg);
128  if (!stream.good())
129  panic("Could not seek to location in file");
130 
131  std::streampos pos = stream.tellg();
132  stream.read((char *)data, SectorSize);
133 
134  DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
135  DDUMP(DiskImageRead, data, SectorSize);
136 
137  return stream.tellg() - pos;
138 }
139 
140 std::streampos
141 RawDiskImage::write(const uint8_t *data, std::streampos offset)
142 {
143  if (!initialized)
144  panic("RawDiskImage not initialized");
145 
146  if (readonly)
147  panic("Cannot write to a read only disk image");
148 
149  if (!stream.is_open())
150  panic("file not open!\n");
151 
152  stream.seekp(offset * SectorSize, std::ios::beg);
153  if (!stream.good())
154  panic("Could not seek to location in file");
155 
156  DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
157  DDUMP(DiskImageWrite, data, SectorSize);
158 
159  std::streampos pos = stream.tellp();
160  stream.write((const char *)data, SectorSize);
161  return stream.tellp() - pos;
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(std::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(std::ifstream &stream, T &data)
226 {
227  SafeRead(stream, &data, sizeof(data));
228 }
229 
230 template<class T>
231 void
232 SafeReadSwap(std::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 std::string &file)
240 {
241  std::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_version, minor_version;
255  SafeReadSwap(stream, major_version);
256  SafeReadSwap(stream, minor_version);
257 
258  if (major_version != VersionMajor && minor_version != VersionMinor)
259  panic("Could not open %s: invalid version %d.%d != %d.%d",
260  file, major_version, minor_version, 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(std::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(std::ofstream &stream, const T &data)
309 {
310  SafeWrite(stream, &data, sizeof(data));
311 }
312 
313 template<class T>
314 void
315 SafeWriteSwap(std::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 std::string &file) const
332 {
333  if (!initialized)
334  panic("RawDiskImage not initialized");
335 
336  std::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  std::string cowFilename = name() + ".cow";
428  SERIALIZE_SCALAR(cowFilename);
429  save(CheckpointIn::dir() + "/" + cowFilename);
430 }
431 
432 void
434 {
435  std::string cowFilename;
436  UNSERIALIZE_SCALAR(cowFilename);
437  cowFilename = cp.getCptDir() + "/" + cowFilename;
438  open(cowFilename);
439 }
440 
441 } // namespace gem5
#define DDUMP(x, data, count)
DPRINTF is a debugging trace facility that allows one to selectively enable tracing statements.
Definition: trace.hh:180
#define DPRINTF(x,...)
Definition: trace.hh:186
const char data[]
void notifyFork() override
Notify a child process of a fork.
Definition: disk_image.cc:200
std::streampos write(const uint8_t *data, std::streampos offset) override
Definition: disk_image.cc:401
std::streampos size() const override
Definition: disk_image.cc:377
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: disk_image.cc:433
static const uint32_t VersionMajor
Definition: disk_image.hh:110
std::streampos read(uint8_t *data, std::streampos offset) const override
Definition: disk_image.cc:381
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: disk_image.cc:425
std::unordered_map< uint64_t, Sector * > SectorTable
Definition: disk_image.hh:118
void save() const
Definition: disk_image.cc:321
bool open(const std::string &file)
Definition: disk_image.cc:239
SectorTable * table
Definition: disk_image.hh:123
static const uint32_t VersionMinor
Definition: disk_image.hh:111
void initSectorTable(int hash_size)
Definition: disk_image.cc:285
CowDiskImage(const Params &p)
Definition: disk_image.cc:171
std::string filename
Definition: disk_image.hh:121
DiskImage * child
Definition: disk_image.hh:122
Basic interface for accessing a disk image.
Definition: disk_image.hh:53
virtual std::streampos write(const uint8_t *data, std::streampos offset)=0
DiskImageParams Params
Definition: disk_image.hh:58
virtual std::streampos size() const =0
virtual std::streampos read(uint8_t *data, std::streampos offset) const =0
virtual std::string name() const
Definition: named.hh:47
void notifyFork() override
Notify a child process of a fork.
Definition: disk_image.cc:72
void open(const std::string &filename, bool rd_only=false)
Definition: disk_image.cc:83
std::streampos size() const override
Definition: disk_image.cc:106
std::fstream stream
Definition: disk_image.hh:76
std::streampos disk_size
Definition: disk_image.hh:79
RawDiskImage(const Params &p)
Definition: disk_image.cc:60
std::streampos read(uint8_t *data, std::streampos offset) const override
Definition: disk_image.cc:119
std::streampos write(const uint8_t *data, std::streampos offset) override
Definition: disk_image.cc:141
std::string file
Definition: disk_image.hh:77
Disk Image Interfaces.
#define SectorSize
Definition: disk_image.hh:44
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
const std::string getCptDir()
Definition: serialize.hh:85
static std::string dir()
Get the current checkout directory name.
Definition: serialize.cc:154
const Params & params() const
Definition: sim_object.hh:176
#define inform(...)
Definition: logging.hh:247
Bitfield< 4, 0 > mode
Definition: misc_types.hh:74
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 54 > p
Definition: pagetable.hh:70
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
T letoh(T value)
Definition: byteswap.hh:173
void SafeWriteSwap(std::ofstream &stream, const T &data)
Definition: disk_image.cc:315
std::ostream CheckpointOut
Definition: serialize.hh:66
void SafeRead(std::ifstream &stream, void *data, int count)
Definition: disk_image.cc:210
const uint8_t image_file[]
This image file contains the text "This is a test image.\n" 31 times.
void SafeWrite(std::ofstream &stream, const void *data, int count)
Definition: disk_image.cc:293
void SafeReadSwap(std::ifstream &stream, T &data)
Definition: disk_image.cc:232
void registerExitCallback(const std::function< void()> &callback)
Register an exit callback.
Definition: core.cc:146
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568

Generated on Wed Dec 21 2022 10:22:35 for gem5 by doxygen 1.9.1