gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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  * Authors: Nathan Binkert
29  */
30 
36 
37 #include <sys/types.h>
38 #include <sys/uio.h>
39 #include <unistd.h>
40 
41 #include <cerrno>
42 #include <cstring>
43 #include <fstream>
44 #include <string>
45 
46 #include "base/callback.hh"
47 #include "base/misc.hh"
48 #include "base/trace.hh"
49 #include "debug/DiskImageRead.hh"
50 #include "debug/DiskImageWrite.hh"
51 #include "sim/byteswap.hh"
52 #include "sim/sim_exit.hh"
53 
54 using namespace std;
55 
57 //
58 // Raw Disk image
59 //
61  : DiskImage(p), disk_size(0)
62 { open(p->image_file, p->read_only); }
63 
65 { close(); }
66 
67 void
69 {
70  if (initialized && !readonly)
71  panic("Attempting to fork system with read-write raw disk image.");
72 
73  const Params *p(dynamic_cast<const Params *>(params()));
74  close();
75  open(p->image_file, p->read_only);
76 }
77 
78 void
79 RawDiskImage::open(const string &filename, bool rd_only)
80 {
81  if (!filename.empty()) {
82  initialized = true;
83  readonly = rd_only;
84  file = filename;
85 
86  ios::openmode mode = ios::in | ios::binary;
87  if (!readonly)
88  mode |= ios::out;
89  stream.open(file.c_str(), mode);
90  if (!stream.is_open())
91  panic("Error opening %s", filename);
92  }
93 }
94 
95 void
97 {
98  stream.close();
99 }
100 
101 std::streampos
103 {
104  if (disk_size == 0) {
105  if (!stream.is_open())
106  panic("file not open!\n");
107  stream.seekg(0, ios::end);
108  disk_size = stream.tellg();
109  }
110 
111  return disk_size / SectorSize;
112 }
113 
114 std::streampos
115 RawDiskImage::read(uint8_t *data, std::streampos offset) const
116 {
117  if (!initialized)
118  panic("RawDiskImage not initialized");
119 
120  if (!stream.is_open())
121  panic("file not open!\n");
122 
123  stream.seekg(offset * SectorSize, ios::beg);
124  if (!stream.good())
125  panic("Could not seek to location in file");
126 
127  streampos pos = stream.tellg();
128  stream.read((char *)data, SectorSize);
129 
130  DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
131  DDUMP(DiskImageRead, data, SectorSize);
132 
133  return stream.tellg() - pos;
134 }
135 
136 std::streampos
137 RawDiskImage::write(const uint8_t *data, std::streampos offset)
138 {
139  if (!initialized)
140  panic("RawDiskImage not initialized");
141 
142  if (readonly)
143  panic("Cannot write to a read only disk image");
144 
145  if (!stream.is_open())
146  panic("file not open!\n");
147 
148  stream.seekp(offset * SectorSize, ios::beg);
149  if (!stream.good())
150  panic("Could not seek to location in file");
151 
152  DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
153  DDUMP(DiskImageWrite, data, SectorSize);
154 
155  streampos pos = stream.tellp();
156  stream.write((const char *)data, SectorSize);
157  return stream.tellp() - pos;
158 }
159 
160 RawDiskImage *
161 RawDiskImageParams::create()
162 {
163  return new RawDiskImage(this);
164 }
165 
167 //
168 // Copy on Write Disk image
169 //
170 const uint32_t CowDiskImage::VersionMajor = 1;
171 const uint32_t CowDiskImage::VersionMinor = 0;
172 
173 class CowDiskCallback : public Callback
174 {
175  private:
177 
178  public:
180  void process() { image->save(); delete this; }
181 };
182 
184  : DiskImage(p), filename(p->image_file), child(p->child), table(NULL)
185 {
186  if (filename.empty()) {
187  initSectorTable(p->table_size);
188  } else {
189  if (!open(filename)) {
190  if (p->read_only)
191  fatal("could not open read-only file");
192  initSectorTable(p->table_size);
193  }
194 
195  if (!p->read_only)
197  }
198 }
199 
201 {
202  SectorTable::iterator i = table->begin();
203  SectorTable::iterator end = table->end();
204 
205  while (i != end) {
206  delete (*i).second;
207  ++i;
208  }
209 }
210 
211 void
213 {
214  if (!dynamic_cast<const Params *>(params())->read_only &&
215  !filename.empty()) {
216  inform("Disabling saving of COW image in forked child process.\n");
217  filename = "";
218  }
219 }
220 
221 void
222 SafeRead(ifstream &stream, void *data, int count)
223 {
224  stream.read((char *)data, count);
225  if (!stream.is_open())
226  panic("file not open");
227 
228  if (stream.eof())
229  panic("premature end-of-file");
230 
231  if (stream.bad() || stream.fail())
232  panic("error reading cowdisk image");
233 }
234 
235 template<class T>
236 void
237 SafeRead(ifstream &stream, T &data)
238 {
239  SafeRead(stream, &data, sizeof(data));
240 }
241 
242 template<class T>
243 void
244 SafeReadSwap(ifstream &stream, T &data)
245 {
246  SafeRead(stream, &data, sizeof(data));
247  data = letoh(data); //is this the proper byte order conversion?
248 }
249 
250 bool
251 CowDiskImage::open(const string &file)
252 {
253  ifstream stream(file.c_str());
254  if (!stream.is_open())
255  return false;
256 
257  if (stream.fail() || stream.bad())
258  panic("Error opening %s", file);
259 
260  uint64_t magic;
261  SafeRead(stream, magic);
262 
263  if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0)
264  panic("Could not open %s: Invalid magic", file);
265 
266  uint32_t major, minor;
267  SafeReadSwap(stream, major);
268  SafeReadSwap(stream, minor);
269 
270  if (major != VersionMajor && minor != VersionMinor)
271  panic("Could not open %s: invalid version %d.%d != %d.%d",
272  file, major, minor, VersionMajor, VersionMinor);
273 
274  uint64_t sector_count;
275  SafeReadSwap(stream, sector_count);
276  table = new SectorTable(sector_count);
277 
278 
279  for (uint64_t i = 0; i < sector_count; i++) {
280  uint64_t offset;
281  SafeReadSwap(stream, offset);
282 
283  Sector *sector = new Sector;
284  SafeRead(stream, sector, sizeof(Sector));
285 
286  assert(table->find(offset) == table->end());
287  (*table)[offset] = sector;
288  }
289 
290  stream.close();
291 
292  initialized = true;
293  return true;
294 }
295 
296 void
298 {
299  table = new SectorTable(hash_size);
300 
301  initialized = true;
302 }
303 
304 void
305 SafeWrite(ofstream &stream, const void *data, int count)
306 {
307  stream.write((const char *)data, count);
308  if (!stream.is_open())
309  panic("file not open");
310 
311  if (stream.eof())
312  panic("premature end-of-file");
313 
314  if (stream.bad() || stream.fail())
315  panic("error reading cowdisk image");
316 }
317 
318 template<class T>
319 void
320 SafeWrite(ofstream &stream, const T &data)
321 {
322  SafeWrite(stream, &data, sizeof(data));
323 }
324 
325 template<class T>
326 void
327 SafeWriteSwap(ofstream &stream, const T &data)
328 {
329  T swappeddata = letoh(data); //is this the proper byte order conversion?
330  SafeWrite(stream, &swappeddata, sizeof(data));
331 }
332 void
334 {
335  // filename will be set to the empty string to disable saving of
336  // the COW image in a forked child process. Save will still be
337  // called because there is no easy way to unregister the exit
338  // callback.
339  if (!filename.empty())
340  save(filename);}
341 
342 void
343 CowDiskImage::save(const string &file) const
344 {
345  if (!initialized)
346  panic("RawDiskImage not initialized");
347 
348  ofstream stream(file.c_str());
349  if (!stream.is_open() || stream.fail() || stream.bad())
350  panic("Error opening %s", file);
351 
352  uint64_t magic;
353  memcpy(&magic, "COWDISK!", sizeof(magic));
354  SafeWrite(stream, magic);
355 
356  SafeWriteSwap(stream, (uint32_t)VersionMajor);
357  SafeWriteSwap(stream, (uint32_t)VersionMinor);
358  SafeWriteSwap(stream, (uint64_t)table->size());
359 
360  uint64_t size = table->size();
361  SectorTable::iterator iter = table->begin();
362  SectorTable::iterator end = table->end();
363 
364  for (uint64_t i = 0; i < size; i++) {
365  if (iter == end)
366  panic("Incorrect Table Size during save of COW disk image");
367 
368  SafeWriteSwap(stream, (uint64_t)(*iter).first);
369  SafeWrite(stream, (*iter).second->data, sizeof(Sector));
370  ++iter;
371  }
372 
373  stream.close();
374 }
375 
376 void
378 {
379  SectorTable::iterator i = table->begin();
380  SectorTable::iterator end = table->end();
381 
382  while (i != end) {
383  child->write((*i).second->data, (*i).first);
384  ++i;
385  }
386 }
387 
388 std::streampos
390 { return child->size(); }
391 
392 std::streampos
393 CowDiskImage::read(uint8_t *data, std::streampos offset) const
394 {
395  if (!initialized)
396  panic("CowDiskImage not initialized");
397 
398  if (offset > size())
399  panic("access out of bounds");
400 
401  SectorTable::const_iterator i = table->find(offset);
402  if (i == table->end())
403  return child->read(data, offset);
404  else {
405  memcpy(data, (*i).second->data, SectorSize);
406  DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
407  DDUMP(DiskImageRead, data, SectorSize);
408  return SectorSize;
409  }
410 }
411 
412 std::streampos
413 CowDiskImage::write(const uint8_t *data, std::streampos offset)
414 {
415  if (!initialized)
416  panic("RawDiskImage not initialized");
417 
418  if (offset > size())
419  panic("access out of bounds");
420 
421  SectorTable::iterator i = table->find(offset);
422  if (i == table->end()) {
423  Sector *sector = new Sector;
424  memcpy(sector, data, SectorSize);
425  table->insert(make_pair(offset, sector));
426  } else {
427  memcpy((*i).second->data, data, SectorSize);
428  }
429 
430  DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
431  DDUMP(DiskImageWrite, data, SectorSize);
432 
433  return SectorSize;
434 }
435 
436 void
438 {
439  string cowFilename = name() + ".cow";
440  SERIALIZE_SCALAR(cowFilename);
441  save(CheckpointIn::dir() + "/" + cowFilename);
442 }
443 
444 void
446 {
447  string cowFilename;
448  UNSERIALIZE_SCALAR(cowFilename);
449  cowFilename = cp.cptDir + "/" + cowFilename;
450  open(cowFilename);
451 }
452 
453 CowDiskImage *
454 CowDiskImageParams::create()
455 {
456  return new CowDiskImage(this);
457 }
count
Definition: misc.hh:704
std::streampos write(const uint8_t *data, std::streampos offset) override
Definition: disk_image.cc:413
#define DPRINTF(x,...)
Definition: trace.hh:212
const std::string cptDir
Definition: serialize.hh:352
std::streampos size() const override
Definition: disk_image.cc:102
Generic callback class.
Definition: callback.hh:41
static std::string dir()
Definition: serialize.cc:676
Bitfield< 7 > i
Definition: miscregs.hh:1378
#define panic(...)
Definition: misc.hh:153
CowDiskImage(const Params *p)
Definition: disk_image.cc:183
std::streampos read(uint8_t *data, std::streampos offset) const override
Definition: disk_image.cc:115
bool initialized
Definition: disk_image.hh:54
#define DDUMP(x, data, count)
Definition: trace.hh:211
const Params * params() const
Definition: sim_object.hh:111
std::streampos size() const override
Definition: disk_image.cc:389
Bitfield< 23, 0 > offset
Definition: types.hh:149
void SafeReadSwap(ifstream &stream, T &data)
Definition: disk_image.cc:244
T letoh(T value)
Definition: byteswap.hh:152
Bitfield< 4, 0 > mode
Definition: miscregs.hh:1385
Specialization for accessing a copy-on-write disk image layer.
Definition: disk_image.hh:106
static const uint32_t VersionMinor
Definition: disk_image.hh:110
void SafeWrite(ofstream &stream, const void *data, int count)
Definition: disk_image.cc:305
const char data[]
Definition: circlebuf.cc:43
CowDiskImage * image
Definition: disk_image.cc:176
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: disk_image.cc:437
void notifyFork() override
Notify a child process of a fork.
Definition: disk_image.cc:68
virtual std::streampos size() const =0
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:145
std::string filename
Definition: disk_image.hh:119
void close()
Definition: disk_image.cc:96
void save() const
Definition: disk_image.cc:333
std::unordered_map< uint64_t, Sector * > SectorTable
Definition: disk_image.hh:116
std::string file
Definition: disk_image.hh:76
virtual std::streampos write(const uint8_t *data, std::streampos offset)=0
#define fatal(...)
Definition: misc.hh:163
#define SectorSize
Definition: disk_image.hh:46
void registerExitCallback(Callback *callback)
Register an exit callback.
Definition: core.cc:116
void SafeRead(ifstream &stream, void *data, int count)
Definition: disk_image.cc:222
Basic interface for accessing a disk image.
Definition: disk_image.hh:51
void open(const std::string &filename, bool rd_only=false)
Definition: disk_image.cc:79
std::streampos disk_size
Definition: disk_image.hh:78
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:143
RawDiskImage(const Params *p)
Definition: disk_image.cc:60
static const uint32_t VersionMajor
Definition: disk_image.hh:109
virtual const std::string name() const
Definition: sim_object.hh:117
void SafeWriteSwap(ofstream &stream, const T &data)
Definition: disk_image.cc:327
std::ostream CheckpointOut
Definition: serialize.hh:67
void writeback()
Definition: disk_image.cc:377
DiskImage * child
Definition: disk_image.hh:120
std::streampos read(uint8_t *data, std::streampos offset) const override
Definition: disk_image.cc:393
SectorTable * table
Definition: disk_image.hh:121
virtual std::streampos read(uint8_t *data, std::streampos offset) const =0
std::fstream stream
Definition: disk_image.hh:75
Disk Image Interfaces.
std::streampos write(const uint8_t *data, std::streampos offset) override
Definition: disk_image.cc:137
void initSectorTable(int hash_size)
Definition: disk_image.cc:297
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: disk_image.cc:445
bool open(const std::string &file)
Definition: disk_image.cc:251
Specialization for accessing a raw disk image.
Definition: disk_image.hh:72
DiskImageParams Params
Definition: disk_image.hh:57
#define inform(...)
Definition: misc.hh:221
Bitfield< 0 > p
void process()
virtual process function that is invoked when the callback queue is executed.
Definition: disk_image.cc:180
CowDiskCallback(CowDiskImage *i)
Definition: disk_image.cc:179
void notifyFork() override
Notify a child process of a fork.
Definition: disk_image.cc:212

Generated on Fri Jun 9 2017 13:03:47 for gem5 by doxygen 1.8.6