|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2021 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
1.1.1.2 root 8: // ディスクイメージ
1.1 root 9: //
10:
11: #include "diskimage.h"
1.1.1.8 ! root 12: #include "diskdriver_qcow2.h"
! 13: #include "diskdriver_raw.h"
1.1.1.2 root 14: #include "mainapp.h"
15: #include <fcntl.h>
16:
1.1 root 17: // コンストラクタ
1.1.1.2 root 18: DiskImage::DiskImage()
1.1.1.8 ! root 19: : inherited(OBJ_NONE)
1.1 root 20: {
1.1.1.8 ! root 21: // ログ名は SetName() で設定するのと、
! 22: // このオブジェクトを ID で検索することはないので、OBJ_NONE でいい。
1.1 root 23: }
24:
25: // デストラクタ
26: DiskImage::~DiskImage()
27: {
1.1.1.2 root 28: Close();
1.1 root 29: }
30:
1.1.1.8 ! root 31: // このディスクイメージのログ表示名とログ指定名を設定する。
! 32: // 歴史的経緯によりコンストラクタで指定できないので、ここで指定する。
! 33: void
! 34: DiskImage::SetName(const std::string& name)
! 35: {
! 36: // 名前は長いけどもうしょうがない。しょっちゅう指定するわけじゃないし…。
! 37: inherited::SetName("HostImage-" + name);
! 38: ClearAlias();
! 39: AddAlias(GetName());
! 40: }
! 41:
! 42: void
! 43: DiskImage::SetLogLevel(int loglevel_)
! 44: {
! 45: inherited::SetLogLevel(loglevel_);
! 46: if ((bool)driver) {
! 47: driver->SetLogLevel(loglevel_);
! 48: }
! 49: }
! 50:
1.1.1.2 root 51: // パス名を指定して、下位ドライバをオープン
52: bool
53: DiskImage::CreateHandler(const std::string& pathname_)
1.1 root 54: {
1.1.1.2 root 55: pathname = pathname_;
56: cow_enable = false;
57:
1.1.1.8 ! root 58: // ドライバを順に試す。
! 59: std::string errmsg;
1.1.1.7 root 60: try {
1.1.1.8 ! root 61: driver.reset(new DiskDriverQcow2(GetName(), pathname));
1.1.1.7 root 62: } catch (...) { }
1.1.1.8 ! root 63: if ((bool)driver && driver->Match()) {
! 64: goto match;
! 65: }
! 66:
! 67: try {
! 68: driver.reset(new DiskDriverRaw(GetName(), pathname));
! 69: } catch (...) { }
! 70: if ((bool)driver && driver->Match()) {
! 71: goto match;
! 72: }
1.1.1.2 root 73:
1.1.1.8 ! root 74: return false;
! 75:
! 76: match:
! 77: // 初期ログレベルをセット。
! 78: driver->SetLogLevel(loglevel);
! 79:
! 80: if (driver->Attach(errmsg) == false) {
! 81: warn("%s: %s", pathname.c_str(), errmsg.c_str());
! 82: return false;
! 83: }
! 84:
! 85: return true;
! 86: }
1.1.1.2 root 87:
1.1.1.6 root 88: // このディスクイメージが書き込み可能かどうかを返す。
1.1.1.2 root 89: // Open() 前でも動作する。
1.1.1.6 root 90: int
91: DiskImage::IsWriteable() const
1.1.1.2 root 92: {
93: assert((bool)driver);
1.1.1.6 root 94: return driver->IsWriteable();
1.1.1.2 root 95: }
96:
97: // オープン
98: //
99: // ro cow
100: // false false : RW オープン、書き込み可
101: // true false : RO オープン、読み込み専用
102: // * true : RO オープン、CoW
103: bool
104: DiskImage::Open(bool read_only, bool cow_enable_)
105: {
106: assert((bool)driver);
107: cow_enable = cow_enable_;
108:
109: // ベースファイルをオープン
110: if (cow_enable) {
111: read_only = true;
112: }
113: if (driver->Open(read_only) == false) {
114: return false;
115: }
116:
117: if (cow_enable) {
118: // CoW なら一時ファイルもオープン
119:
120: // VM ディレクトリに適当な名前の隠しファイルで作成
121: auto pos = pathname.rfind('/');
122: if (pos != std::string::npos) {
123: // パス区切りがあればファイル名部分
124: cowname = pathname.substr(pos + 1);
125: } else {
126: // なければ全部
127: cowname = pathname;
128: }
129: // 空になることはないはず
130: assert(cowname.empty() == false);
131:
132: cowname = gMainApp.GetVMDir() + "/." + cowname + ".cow";
1.1.1.5 root 133: cowfd = open(cowname.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0600);
1.1.1.2 root 134: if (cowfd < 0) {
135: return false;
136: }
137: }
138:
139: return true;
140: }
141:
142: // クローズ
143: void
144: DiskImage::Close()
145: {
146: if (cow_enable) {
147: if (cowfd.Valid()) {
148: cowfd.Close();
149: unlink(cowname.c_str());
150: }
151: cow_enable = false;
152: }
153:
154: if ((bool)driver) {
155: driver.reset();
156: }
157: }
158:
159: // このディスクイメージのサイズ(バイト数)を返す。
160: // オープン後のみ使用可能。
161: off_t
162: DiskImage::GetSize() const
163: {
164: assert((bool)driver);
165: return driver->GetSize();
166: }
167:
168: // 読み出し
169: bool
170: DiskImage::Read(void *buf, off_t offset, size_t size) const
171: {
172: assert((bool)driver);
173:
1.1.1.3 root 174: if (__predict_false(offset + size > GetSize())) {
1.1.1.2 root 175: return false;
176: }
177:
178: if (__predict_true(cow_enable == false)) {
179: // 通常モード
180: return driver->Read(buf, offset, size);
181:
182: } else {
183: // Copy-on-Write モード
184: while (size > 0) {
185: off_t blk_addr = offset / BLKSIZE;
186: size_t blk_off = offset % BLKSIZE;
187: size_t blk_size = std::min(size, BLKSIZE - blk_off);
188:
189: if (map_contains(blk_addr)) {
190: // キャッシュにあればそこから読み出す。
191: auto cow_offset = map.at(blk_addr);
192: if (lseek(cowfd, cow_offset + blk_off, SEEK_SET) < 0) {
193: return false;
194: }
195: if (read(cowfd, buf, blk_size) < 0) {
196: return false;
197: }
198: } else {
199: // キャッシュになければファイルから直接読む
200: if (driver->Read(buf, offset, blk_size) == false) {
201: return false;
202: }
203: }
204:
205: buf = (uint8 *)buf + blk_size;
206: offset += blk_size;
207: size -= blk_size;
208: }
209: }
210:
211: return true;
212: }
213:
214: // 書き込み
215: bool
216: DiskImage::Write(const void *buf, off_t offset, size_t size)
217: {
218: assert((bool)driver);
219:
1.1.1.3 root 220: if (__predict_false(offset + size > GetSize())) {
1.1.1.2 root 221: return false;
222: }
223:
224: if (__predict_true(cow_enable == false)) {
225: // 通常モード
226: return driver->Write(buf, offset, size);
227:
228: } else {
229: // Copy-on-Write モード
230:
231: off_t cow_offset;
232: while (size > 0) {
233: off_t blk_addr = offset / BLKSIZE;
234: size_t blk_off = offset % BLKSIZE;
235: size_t blk_size = std::min(size, BLKSIZE - blk_off);
236:
237: if (map_contains(blk_addr) == false) {
238: // キャッシュになければファイルから読んで..
239: SectBuf newbuf;
240: off_t read_off = blk_addr * BLKSIZE;
241: if (driver->Read(&newbuf[0], read_off, BLKSIZE) == false) {
242: return false;
243: }
244:
245: // それをキャッシュの末尾に追加
246: cow_offset = lseek(cowfd, 0, SEEK_END);
247: if (cow_offset == (off_t)-1) {
248: return false;
249: }
250: if (write(cowfd, &newbuf[0], BLKSIZE) < BLKSIZE) {
251: return false;
252: }
253: map.emplace(blk_addr, cow_offset);
254: }
255:
256: // キャッシュに書き込む
257: cow_offset = map.at(blk_addr);
258: if (lseek(cowfd, cow_offset + blk_off, SEEK_SET) < 0) {
259: return false;
260: }
261: if (write(cowfd, buf, blk_size) < 0) {
262: return false;
263: }
264:
265: buf = (const uint8 *)buf + blk_size;
266: offset += blk_size;
267: size -= blk_size;
268: }
269: }
270:
271: return true;
272: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.