disk_image.cc revision 412
12139SN/A/* 22139SN/A * Copyright (c) 2003 The Regents of The University of Michigan 32139SN/A * All rights reserved. 42139SN/A * 52139SN/A * Redistribution and use in source and binary forms, with or without 62139SN/A * modification, are permitted provided that the following conditions are 72139SN/A * met: redistributions of source code must retain the above copyright 82139SN/A * notice, this list of conditions and the following disclaimer; 92139SN/A * redistributions in binary form must reproduce the above copyright 102139SN/A * notice, this list of conditions and the following disclaimer in the 112139SN/A * documentation and/or other materials provided with the distribution; 122139SN/A * neither the name of the copyright holders nor the names of its 132139SN/A * contributors may be used to endorse or promote products derived from 142139SN/A * this software without specific prior written permission. 152139SN/A * 162139SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172139SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182139SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192139SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202139SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212139SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222139SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232139SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242139SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252139SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262139SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272139SN/A */ 282665Ssaidi@eecs.umich.edu 292665Ssaidi@eecs.umich.edu/* @file 302139SN/A * Disk Image Definitions 312718Sstever@eecs.umich.edu */ 322139SN/A 332139SN/A#include <sys/types.h> 342139SN/A#include <sys/uio.h> 352139SN/A#include <errno.h> 362152SN/A#include <unistd.h> 372152SN/A 382152SN/A#include <cstdio> 392152SN/A#include <cstring> 402139SN/A#include <fstream> 412139SN/A#include <string> 422139SN/A 432139SN/A#include "base/callback.hh" 442139SN/A#include "base/misc.hh" 452152SN/A#include "base/trace.hh" 462152SN/A#include "dev/disk_image.hh" 472139SN/A#include "sim/builder.hh" 482139SN/A#include "sim/sim_exit.hh" 492139SN/A 502984Sgblack@eecs.umich.eduusing namespace std; 512439SN/A 523520Sgblack@eecs.umich.edu//////////////////////////////////////////////////////////////////////// 532139SN/A// 543170Sstever@eecs.umich.edu// Raw Disk image 552439SN/A// 562460SN/ARawDiskImage::RawDiskImage(const string &name, const string &filename, 572439SN/A bool rd_only) 582972Sgblack@eecs.umich.edu : DiskImage(name), disk_size(0) 592171SN/A{ open(filename, rd_only); } 602439SN/A 612439SN/ARawDiskImage::~RawDiskImage() 622170SN/A{ close(); } 632139SN/A 642139SN/Avoid 652139SN/ARawDiskImage::open(const string &filename, bool rd_only) 662139SN/A{ 672139SN/A if (!filename.empty()) { 682139SN/A initialized = true; 692139SN/A readonly = rd_only; 702139SN/A file = filename; 712139SN/A 722139SN/A ios::openmode mode = ios::in | ios::binary; 732139SN/A if (!readonly) 742139SN/A mode |= ios::out; 752139SN/A stream.open(file.c_str(), mode); 762139SN/A if (!stream.is_open()) 772139SN/A panic("Error opening %s", filename); 782139SN/A } 792139SN/A} 802139SN/A 812139SN/Avoid 822139SN/ARawDiskImage::close() 832139SN/A{ 842139SN/A stream.close(); 852139SN/A} 862139SN/A 872178SN/Aoff_t 882139SN/ARawDiskImage::size() const 892139SN/A{ 902139SN/A if (disk_size == 0) { 912139SN/A if (!stream.is_open()) 922139SN/A panic("file not open!\n"); 932139SN/A stream.seekg(0, ios::end); 942139SN/A disk_size = stream.tellg(); 952152SN/A } 962152SN/A 972152SN/A return disk_size / SectorSize; 982152SN/A} 992152SN/A 1002152SN/Aoff_t 1012152SN/ARawDiskImage::read(uint8_t *data, off_t offset) const 1022152SN/A{ 1032152SN/A if (!initialized) 1042152SN/A panic("RawDiskImage not initialized"); 1052152SN/A 1062152SN/A if (!stream.is_open()) 1072504SN/A panic("file not open!\n"); 1082504SN/A 1092504SN/A if (stream.seekg(offset * SectorSize, ios::beg) < 0) 1102504SN/A panic("Could not seek to location in file"); 1112152SN/A 1122504SN/A streampos pos = stream.tellg(); 1132152SN/A stream.read((char *)data, SectorSize); 1142152SN/A 1152152SN/A DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); 1162152SN/A DDUMP(DiskImageRead, data, SectorSize); 1172152SN/A 1182152SN/A return stream.tellg() - pos; 1192152SN/A} 1202152SN/A 1212632Sstever@eecs.umich.eduoff_t 1222155SN/ARawDiskImage::write(const uint8_t *data, off_t offset) 1232155SN/A{ 1242155SN/A if (!initialized) 1252155SN/A panic("RawDiskImage not initialized"); 1262155SN/A 1272155SN/A if (readonly) 1282155SN/A panic("Cannot write to a read only disk image"); 1292155SN/A 1302155SN/A if (!stream.is_open()) 1312155SN/A panic("file not open!\n"); 1322152SN/A 1332766Sktlim@umich.edu if (stream.seekp(offset * SectorSize, ios::beg) < 0) 1342766Sktlim@umich.edu panic("Could not seek to location in file"); 1352766Sktlim@umich.edu 1362766Sktlim@umich.edu DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); 1372766Sktlim@umich.edu DDUMP(DiskImageWrite, data, SectorSize); 1382152SN/A 1392152SN/A streampos pos = stream.tellp(); 1402152SN/A stream.write((const char *)data, SectorSize); 1412155SN/A return stream.tellp() - pos; 1422152SN/A} 1432152SN/A 1442718Sstever@eecs.umich.eduDEFINE_SIM_OBJECT_CLASS_NAME("DiskImage", DiskImage) 1452921Sktlim@umich.edu 1462921Sktlim@umich.eduBEGIN_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) 1472921Sktlim@umich.edu 1482921Sktlim@umich.edu Param<string> image_file; 1492921Sktlim@umich.edu Param<bool> read_only; 1502921Sktlim@umich.edu 1512921Sktlim@umich.eduEND_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) 1522921Sktlim@umich.edu 1532921Sktlim@umich.eduBEGIN_INIT_SIM_OBJECT_PARAMS(RawDiskImage) 1542152SN/A 1552152SN/A INIT_PARAM(image_file, "disk image file"), 1562152SN/A INIT_PARAM_DFLT(read_only, "read only image", false) 1572152SN/A 1582152SN/AEND_INIT_SIM_OBJECT_PARAMS(RawDiskImage) 1592152SN/A 1602152SN/A 1612152SN/ACREATE_SIM_OBJECT(RawDiskImage) 1622152SN/A{ 1632152SN/A return new RawDiskImage(getInstanceName(), image_file, read_only); 1642667Sstever@eecs.umich.edu} 1652152SN/A 1662152SN/AREGISTER_SIM_OBJECT("RawDiskImage", RawDiskImage) 167 168//////////////////////////////////////////////////////////////////////// 169// 170// Copy on Write Disk image 171// 172const int CowDiskImage::VersionMajor = 1; 173const int CowDiskImage::VersionMinor = 0; 174 175CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size) 176 : DiskImage(name), child(kid), table(NULL) 177{ init(hash_size); } 178 179class CowDiskCallback : public Callback 180{ 181 private: 182 CowDiskImage *image; 183 184 public: 185 CowDiskCallback(CowDiskImage *i) : image(i) {} 186 void process() { image->save(); delete this; } 187}; 188 189CowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size, 190 const string &file, bool read_only) 191 : DiskImage(name), filename(file), child(kid), table(NULL) 192{ 193 if (!open(filename)) { 194 assert(!read_only && "why have a non-existent read only file?"); 195 init(hash_size); 196 } 197 198 if (!read_only) 199 registerExitCallback(new CowDiskCallback(this)); 200} 201 202CowDiskImage::~CowDiskImage() 203{ 204 SectorTable::iterator i = table->begin(); 205 SectorTable::iterator end = table->end(); 206 207 while (i != end) { 208 delete (*i).second; 209 ++i; 210 } 211} 212 213void 214SafeRead(ifstream &stream, void *data, int count) 215{ 216 stream.read((char *)data, count); 217 if (!stream.is_open()) 218 panic("file not open"); 219 220 if (stream.eof()) 221 panic("premature end-of-file"); 222 223 if (stream.bad() || stream.fail()) 224 panic("error reading cowdisk image"); 225} 226 227template<class T> 228void 229SafeRead(ifstream &stream, T &data) 230{ SafeRead(stream, &data, sizeof(data)); } 231 232bool 233CowDiskImage::open(const string &file) 234{ 235 ifstream stream(file.c_str()); 236 if (!stream.is_open()) 237 return false; 238 239 if (stream.fail() || stream.bad()) 240 panic("Error opening %s", file); 241 242 uint64_t magic; 243 SafeRead(stream, magic); 244 245 if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0) 246 panic("Could not open %s: Invalid magic", file); 247 248 uint32_t major, minor; 249 SafeRead(stream, major); 250 SafeRead(stream, minor); 251 252 if (major != VersionMajor && minor != VersionMinor) 253 panic("Could not open %s: invalid version %d.%d != %d.%d", 254 file, major, minor, VersionMajor, VersionMinor); 255 256 uint64_t sector_count; 257 SafeRead(stream, sector_count); 258 table = new SectorTable(sector_count); 259 260 261 for (uint64_t i = 0; i < sector_count; i++) { 262 uint64_t offset; 263 SafeRead(stream, offset); 264 265 Sector *sector = new Sector; 266 SafeRead(stream, sector, sizeof(Sector)); 267 268 assert(table->find(offset) == table->end()); 269 (*table)[offset] = sector; 270 } 271 272 stream.close(); 273 274 initialized = true; 275 return true; 276} 277 278void 279CowDiskImage::init(int hash_size) 280{ 281 table = new SectorTable(hash_size); 282 283 initialized = true; 284} 285 286void 287SafeWrite(ofstream &stream, const void *data, int count) 288{ 289 stream.write((const char *)data, count); 290 if (!stream.is_open()) 291 panic("file not open"); 292 293 if (stream.eof()) 294 panic("premature end-of-file"); 295 296 if (stream.bad() || stream.fail()) 297 panic("error reading cowdisk image"); 298} 299 300template<class T> 301void 302SafeWrite(ofstream &stream, const T &data) 303{ SafeWrite(stream, &data, sizeof(data)); } 304 305void 306CowDiskImage::save() 307{ 308 save(filename); 309} 310 311void 312CowDiskImage::save(const string &file) 313{ 314 if (!initialized) 315 panic("RawDiskImage not initialized"); 316 317 ofstream stream(file.c_str()); 318 if (!stream.is_open() || stream.fail() || stream.bad()) 319 panic("Error opening %s", file); 320 321 uint64_t magic; 322 memcpy(&magic, "COWDISK!", sizeof(magic)); 323 SafeWrite(stream, magic); 324 325 SafeWrite(stream, (uint32_t)VersionMajor); 326 SafeWrite(stream, (uint32_t)VersionMinor); 327 SafeWrite(stream, (uint64_t)table->size()); 328 329 uint64_t size = table->size(); 330 SectorTable::iterator iter = table->begin(); 331 SectorTable::iterator end = table->end(); 332 333 for (uint64_t i = 0; i < size; i++) { 334 if (iter == end) 335 panic("Incorrect Table Size during save of COW disk image"); 336 337 SafeWrite(stream, (uint64_t)(*iter).first); 338 SafeWrite(stream, (*iter).second->data, sizeof(Sector)); 339 ++iter; 340 } 341 342 stream.close(); 343} 344 345void 346CowDiskImage::writeback() 347{ 348 SectorTable::iterator i = table->begin(); 349 SectorTable::iterator end = table->end(); 350 351 while (i != end) { 352 child->write((*i).second->data, (*i).first); 353 ++i; 354 } 355} 356 357off_t 358CowDiskImage::size() const 359{ return child->size(); } 360 361off_t 362CowDiskImage::read(uint8_t *data, off_t offset) const 363{ 364 if (!initialized) 365 panic("CowDiskImage not initialized"); 366 367 if (offset > size()) 368 panic("access out of bounds"); 369 370 SectorTable::const_iterator i = table->find(offset); 371 if (i == table->end()) 372 return child->read(data, offset); 373 else { 374 memcpy(data, (*i).second->data, SectorSize); 375 DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); 376 DDUMP(DiskImageRead, data, SectorSize); 377 return SectorSize; 378 } 379} 380 381off_t 382CowDiskImage::write(const uint8_t *data, off_t offset) 383{ 384 if (!initialized) 385 panic("RawDiskImage not initialized"); 386 387 if (offset > size()) 388 panic("access out of bounds"); 389 390 SectorTable::iterator i = table->find(offset); 391 if (i == table->end()) { 392 Sector *sector = new Sector; 393 memcpy(sector, data, SectorSize); 394 table->insert(make_pair(offset, sector)); 395 } else { 396 memcpy((*i).second->data, data, SectorSize); 397 } 398 399 DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); 400 DDUMP(DiskImageWrite, data, SectorSize); 401 402 return SectorSize; 403} 404 405void 406CowDiskImage::serialize(ostream &os) 407{ 408 string cowFilename = CheckpointDir() + name() + ".cow"; 409 SERIALIZE_SCALAR(cowFilename); 410 save(cowFilename); 411} 412 413void 414CowDiskImage::unserialize(Checkpoint *cp, const string §ion) 415{ 416 string cowFilename; 417 UNSERIALIZE_SCALAR(cowFilename); 418 open(cowFilename); 419} 420 421BEGIN_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) 422 423 SimObjectParam<DiskImage *> child; 424 Param<string> image_file; 425 Param<int> table_size; 426 Param<bool> read_only; 427 428END_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) 429 430BEGIN_INIT_SIM_OBJECT_PARAMS(CowDiskImage) 431 432 INIT_PARAM(child, "child image"), 433 INIT_PARAM_DFLT(image_file, "disk image file", ""), 434 INIT_PARAM_DFLT(table_size, "initial table size", 65536), 435 INIT_PARAM_DFLT(read_only, "don't write back to the copy-on-write file", 436 true) 437 438END_INIT_SIM_OBJECT_PARAMS(CowDiskImage) 439 440 441CREATE_SIM_OBJECT(CowDiskImage) 442{ 443 if (((string)image_file).empty()) 444 return new CowDiskImage(getInstanceName(), child, table_size); 445 else 446 return new CowDiskImage(getInstanceName(), child, table_size, 447 image_file, read_only); 448} 449 450REGISTER_SIM_OBJECT("CowDiskImage", CowDiskImage) 451