Annotation of nono/host/diskimage.cpp, revision 1.1.1.8

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.