gem5 v24.0.0.0
Loading...
Searching...
No Matches
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
53namespace 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
70
71void
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
82void
83RawDiskImage::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
99void
101{
102 stream.close();
103}
104
105std::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
118std::streampos
119RawDiskImage::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
140std::streampos
141RawDiskImage::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//
168const uint32_t CowDiskImage::VersionMajor = 1;
169const 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
199void
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
209void
210SafeRead(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
223template<class T>
224void
225SafeRead(std::ifstream &stream, T &data)
226{
227 SafeRead(stream, &data, sizeof(data));
228}
229
230template<class T>
231void
232SafeReadSwap(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
238bool
239CowDiskImage::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
284void
286{
287 table = new SectorTable(hash_size);
288
289 initialized = true;
290}
291
292void
293SafeWrite(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
306template<class T>
307void
308SafeWrite(std::ofstream &stream, const T &data)
309{
310 SafeWrite(stream, &data, sizeof(data));
311}
312
313template<class T>
314void
315SafeWriteSwap(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}
320void
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
330void
331CowDiskImage::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
364void
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
376std::streampos
378{ return child->size(); }
379
380std::streampos
381CowDiskImage::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
400std::streampos
401CowDiskImage::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
424void
426{
427 std::string cowFilename = name() + ".cow";
428 SERIALIZE_SCALAR(cowFilename);
429 save(CheckpointIn::dir() + "/" + cowFilename);
430}
431
432void
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:204
#define DPRINTF(x,...)
Definition trace.hh:210
const char data[]
void notifyFork() override
Notify a child process of a fork.
std::streampos write(const uint8_t *data, std::streampos offset) override
std::streampos size() const override
void unserialize(CheckpointIn &cp) override
Unserialize an object.
static const uint32_t VersionMajor
std::streampos read(uint8_t *data, std::streampos offset) const override
void serialize(CheckpointOut &cp) const override
Serialize an object.
std::unordered_map< uint64_t, Sector * > SectorTable
void save() const
bool open(const std::string &file)
CowDiskImageParams Params
SectorTable * table
static const uint32_t VersionMinor
void initSectorTable(int hash_size)
CowDiskImage(const Params &p)
std::string filename
DiskImage * child
Basic interface for accessing a disk image.
Definition disk_image.hh:53
virtual std::streampos write(const uint8_t *data, std::streampos offset)=0
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
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
std::streampos write(const uint8_t *data, std::streampos offset) override
RawDiskImageParams Params
Definition disk_image.hh:82
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:188
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
const std::string getCptDir()
Definition serialize.hh:85
static std::string dir()
Get the current checkout directory name.
Definition serialize.cc:157
const Params & params() const
#define inform(...)
Definition logging.hh:257
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< 0 > p
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
T letoh(T value)
Definition byteswap.hh:173
void SafeWriteSwap(std::ofstream &stream, const T &data)
std::ostream CheckpointOut
Definition serialize.hh:66
void SafeRead(std::ifstream &stream, void *data, int count)
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)
void SafeReadSwap(std::ifstream &stream, T &data)
void registerExitCallback(const std::function< void()> &callback)
Register an exit callback.
Definition core.cc:143
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568

Generated on Tue Jun 18 2024 16:24:03 for gem5 by doxygen 1.11.0