diff --git a/repos/os/src/server/part_block/ahdi.h b/repos/os/src/server/part_block/ahdi.h index abc0b4a040..27d7cc1f1a 100644 --- a/repos/os/src/server/part_block/ahdi.h +++ b/repos/os/src/server/part_block/ahdi.h @@ -90,7 +90,8 @@ struct Ahdi for (unsigned i = 0; i < MAX_PARTITIONS; i++) { Partition_record const &part = root.partitions[i]; if (part.valid()) - fn(i + 1, Block::Partition(part.start.value(), part.length.value())); + fn(i + 1, Block::Partition(part.start.value(), part.length.value(), + Fs::Type(), 0)); } } }; diff --git a/repos/os/src/server/part_block/gpt.h b/repos/os/src/server/part_block/gpt.h index 2f2965c241..ce8084a98f 100644 --- a/repos/os/src/server/part_block/gpt.h +++ b/repos/os/src/server/part_block/gpt.h @@ -23,7 +23,6 @@ #include #include "partition_table.h" -#include "fsprobe.h" static bool constexpr verbose = false; @@ -193,6 +192,12 @@ class Block::Gpt : public Block::Partition_table }; + /* state needed for generating the partitions report */ + uint64_t _gpt_part_lba_end { 0 }; + uint64_t _gpt_total { 0 }; + uint64_t _gpt_used { 0 }; + + /** * GUID partition entry format */ @@ -239,47 +244,57 @@ class Block::Gpt : public Block::Partition_table }; + /** + * Iterate over each constructed partition and execute FN + */ + template + void _for_each_valid_partition(FN const &fn) const + { + for (unsigned i = 0; i < MAX_PARTITIONS; i++) + if (_part_list[i].constructed()) + fn(i); + }; + + /** * Calculate free blocks until the start of the logical next entry * - * \param header pointer to GPT header - * \param entry pointer to current entry - * \param entries pointer to entries - * \param num number of entries + * \param entry number of current entry + * \param total number of total blocks on the device * * \return the number of free blocks to the next logical entry */ - uint64_t _calculate_gap(Gpt_hdr const &header, - Gpt_entry const &entry, - Gpt_entry const &entries, - Genode::uint32_t num, - Genode::uint64_t total_blocks) + uint64_t _calculate_gap(uint32_t entry, + uint64_t total_blocks) const { + Partition const ¤t = *_part_list[entry]; + /* add one block => end == start */ - uint64_t const end_lba = entry.lba_end() + 1; + uint64_t const end_lba = current.lba + current.sectors; enum { INVALID_START = ~0ull, }; uint64_t next_start_lba = INVALID_START; - for (uint32_t i = 0; i < num; i++) { - Gpt_entry const e(entries.base() + i * header.entry_size()); + _for_each_valid_partition([&] (unsigned i) { - if (!e.valid() || e.base() == entry.base()) { continue; } + if (i == entry) + return; + + Partition const &p = *_part_list[i]; /* * Check if the entry starts afterwards and save the * entry with the smallest distance. */ - if (e.lba_start() >= end_lba) { - next_start_lba = min(next_start_lba, e.lba_start()); - } - } + if (p.lba >= end_lba) + next_start_lba = min(next_start_lba, p.lba); + }); /* sanity check if GPT is broken */ - if (end_lba > header.part_lba_end()) { return 0; } + if (end_lba > _gpt_part_lba_end) { return 0; } - /* if the underyling Block device changes we might be able to expand more */ - uint64_t const part_end = max(header.part_lba_end(), total_blocks); + /* if the underlying Block device changes we might be able to expand more */ + uint64_t const part_end = max(_gpt_part_lba_end, total_blocks); /* * Use stored next start LBA or paritions end LBA from header, @@ -299,9 +314,9 @@ class Block::Gpt : public Block::Partition_table * * \return the number of used blocks */ - uint64_t _calculate_used(Gpt_hdr const &header, - Gpt_entry const &entries, - uint32_t num) + uint64_t _calculate_used(Gpt_hdr const &header, + Gpt_entry const &entries, + uint32_t num) { uint64_t used = 0; @@ -330,6 +345,10 @@ class Block::Gpt : public Block::Partition_table gpt.entries() * gpt.entry_size() / block.info().block_size); Gpt_entry entries(entry_array.addr()); + _gpt_part_lba_end = gpt.part_lba_end(); + _gpt_total = (gpt.part_lba_end() - gpt.part_lba_start()) + 1; + _gpt_used = _calculate_used(gpt, entries, gpt.entries()); + for (int i = 0; i < MAX_PARTITIONS; i++) { Gpt_entry e(entries.base() + i * gpt.entry_size()); @@ -337,69 +356,23 @@ class Block::Gpt : public Block::Partition_table if (!e.valid()) continue; - block_number_t start = e.lba_start(); - block_count_t length = (block_count_t)(e.lba_end() - e.lba_start() + 1); /* [...) */ + block_number_t const lba_start = e.lba_start(); + block_count_t const length = (block_count_t)(e.lba_end() - lba_start + 1); /* [...) */ - _part_list[i].construct(start, length); + enum { BYTES = 4096, }; + Sector fs(data, lba_start, BYTES / block.info().block_size); + Fs::Type fs_type = Fs::probe(fs.addr(), BYTES); - log("GPT Partition ", i + 1, ": LBA ", start, " (", length, - " blocks) type: '", e.type(), - "' name: '", e, "'"); - } + String<40> guid { e.guid() }; + String<40> type { e.type() }; + String name { e }; - /* Report the partitions */ - if (reporter.constructed()) - { - reporter->generate([&] (Xml_generator &xml) { - xml.attribute("type", "gpt"); + _part_list[i].construct(lba_start, length, fs_type, + guid, type, name); - uint64_t const total_blocks = block.info().block_count; - xml.attribute("total_blocks", total_blocks); - - uint64_t const gpt_total = - (gpt.part_lba_end() - gpt.part_lba_start()) + 1; - xml.attribute("gpt_total", gpt_total); - - uint64_t const gpt_used = - _calculate_used(gpt, entries, gpt.entries()); - xml.attribute("gpt_used", gpt_used); - - for (int i = 0; i < MAX_PARTITIONS; i++) { - Gpt_entry e(entries.base() + i * gpt.entry_size()); - - if (!e.valid()){ - continue; - } - - enum { BYTES = 4096, }; - Sector fs(data, e.lba_start(), BYTES / block.info().block_size); - - Fs::Type fs_type = Fs::probe(fs.addr(), BYTES); - - String<40> guid { e.guid() }; - String<40> type { e.type() }; - String name { e }; - - xml.node("partition", [&] () { - xml.attribute("number", i + 1); - xml.attribute("name", name); - xml.attribute("type", type); - xml.attribute("guid", guid);; - xml.attribute("start", e.lba_start()); - xml.attribute("length", e.lba_end() - e.lba_start() + 1); - xml.attribute("block_size", block.info().block_size); - - uint64_t const gap = _calculate_gap(gpt, e, entries, - gpt.entries(), - total_blocks); - if (gap) { xml.attribute("expandable", gap); } - - if (fs_type.valid()) { - xml.attribute("file_system", fs_type); - } - }); - } - }); + log("GPT Partition ", i + 1, ": LBA ", lba_start, " (", length, + " blocks) type: '", type, + "' name: '", name, "'"); } } @@ -425,14 +398,51 @@ class Block::Gpt : public Block::Partition_table block.sigh(io_sigh); Sector s(data, Gpt_hdr::Hdr_lba::LBA, 1); - Gpt_hdr hdr(s.addr()); - _parse_gpt(hdr); + Gpt_hdr gpt_hdr(s.addr()); + + _parse_gpt(gpt_hdr); for (unsigned num = 0; num < MAX_PARTITIONS; num++) if (_part_list[num].constructed()) return true; return false; } + + void generate_report(Xml_generator &xml) const override + { + xml.attribute("type", "gpt"); + + uint64_t const total_blocks = block.info().block_count; + xml.attribute("total_blocks", total_blocks); + + xml.attribute("gpt_total", _gpt_total); + xml.attribute("gpt_used", _gpt_used); + + size_t const block_size = block.info().block_size; + + _for_each_valid_partition([&] (unsigned i) { + + Block::Partition const &part = *_part_list[i]; + + xml.node("partition", [&] () { + xml.attribute("number", i + 1); + xml.attribute("name", part.name); + xml.attribute("type", part.gpt_type); + xml.attribute("guid", part.guid); + xml.attribute("start", part.lba); + xml.attribute("length", part.sectors); + xml.attribute("block_size", block_size); + + uint64_t const gap = + _calculate_gap(i, total_blocks); + if (gap) + xml.attribute("expandable", gap); + + if (part.fs_type.valid()) + xml.attribute("file_system", part.fs_type); + }); + }); + } }; #endif /* _PART_BLOCK__GUID_PARTITION_TABLE_H_ */ diff --git a/repos/os/src/server/part_block/main.cc b/repos/os/src/server/part_block/main.cc index a60bba4efc..b64300911c 100644 --- a/repos/os/src/server/part_block/main.cc +++ b/repos/os/src/server/part_block/main.cc @@ -222,8 +222,8 @@ class Block::Main : Rpc_object>, Allocator_avl _block_alloc { &_heap }; Block_connection _block { _env, &_block_alloc, _io_buffer_size }; Io_signal_handler
_io_sigh { _env.ep(), *this, &Main::_handle_io }; - Mbr_partition_table _mbr { _env, _block, _heap, _reporter }; - Gpt _gpt { _env, _block, _heap, _reporter }; + Mbr_partition_table _mbr { _env, _block, _heap }; + Gpt _gpt { _env, _block, _heap }; Partition_table &_partition_table { _table() }; enum { MAX_SESSIONS = 128 }; @@ -494,12 +494,16 @@ Block::Partition_table & Block::Main::_table() throw Invalid_config(); } + config.with_optional_sub_node("report", [&] (Xml_node const &node) { + report = node.attribute_value("partitions", false); }); + try { - report = _config.xml().sub_node("report").attribute_value - ("partitions", false); if (report) _reporter.construct(_env, "partitions", "partitions"); - } catch(...) {} + } catch (...) { + error("cannot construct partitions reporter: abort"); + throw; + } /* * Try to parse MBR as well as GPT first if not instructued @@ -537,6 +541,13 @@ Block::Partition_table & Block::Main::_table() warning("found protective MBR but GPT is to be ignored"); } + /* generate appropriate report */ + if (_reporter.constructed()) + _reporter->generate([&] (Xml_generator &xml) { + if (valid_gpt) _gpt.generate_report(xml); + if (valid_mbr) _mbr.generate_report(xml); + }); + /* * Return the appropriate table or abort if none is found. */ diff --git a/repos/os/src/server/part_block/mbr.h b/repos/os/src/server/part_block/mbr.h index 68f47731de..2998c1983d 100644 --- a/repos/os/src/server/part_block/mbr.h +++ b/repos/os/src/server/part_block/mbr.h @@ -158,6 +158,10 @@ struct Block::Mbr_partition_table : public Block::Partition_table } } + /* state for partitions report */ + bool _mbr_valid { false }; + bool _ahdi_valid { false }; + public: using Partition_table::Partition_table; @@ -189,86 +193,44 @@ struct Block::Mbr_partition_table : public Block::Partition_table /* check for MBR */ Mbr const mbr(s.addr()); - bool const mbr_valid = mbr.valid(); - if (mbr_valid) { + _mbr_valid = mbr.valid(); + if (_mbr_valid) { _parse_mbr(mbr, [&] (int i, Partition_record const &r, unsigned offset) { log("MBR Partition ", i, ": LBA ", r.lba() + offset, " (", r.sectors(), " blocks) type: ", Hex(r.type(), Hex::OMIT_PREFIX)); - if (!r.extended()) - _part_list[i].construct(Partition(r.lba() + offset, r.sectors())); + + if (!r.extended()) { + + block_number_t const lba = r.lba() + offset; + + /* probe for known file-system types */ + enum { PROBE_BYTES = 4096, }; + Sector fs(data, lba , PROBE_BYTES / block.info().block_size); + Fs::Type const fs_type = + Fs::probe(fs.addr(), PROBE_BYTES); + + _part_list[i].construct( + Partition(lba, r.sectors(), fs_type, r.type())); + } }); } /* check for AHDI partition table */ - bool const ahdi_valid = !mbr_valid && Ahdi::valid(s); - if (ahdi_valid) + _ahdi_valid = !_mbr_valid && Ahdi::valid(s); + if (_ahdi_valid) Ahdi::for_each_partition(s, [&] (unsigned i, Partition info) { if (i < MAX_PARTITIONS) _part_list[i].construct( - Partition(info.lba, info.sectors)); }); + Partition(info.lba, info.sectors, Fs::Type(), 0)); + }); /* no partition table, use whole disc as partition 0 */ - if (!mbr_valid && !ahdi_valid) + if (!_mbr_valid && !_ahdi_valid) _part_list[0].construct( - Partition(0, (block_count_t)(block.info().block_count - 1))); - - /* report the partitions */ - if (reporter.constructed()) { - - auto gen_partition_attr = [&] (Xml_generator &xml, unsigned i) - { - Partition const &part = *_part_list[i]; - - size_t const block_size = block.info().block_size; - - xml.attribute("number", i); - xml.attribute("start", part.lba); - xml.attribute("length", part.sectors); - xml.attribute("block_size", block_size); - - /* probe for known file-system types */ - enum { PROBE_BYTES = 4096, }; - Sector fs(data, part.lba, PROBE_BYTES / block_size); - Fs::Type const fs_type = - Fs::probe(fs.addr(), PROBE_BYTES); - - if (fs_type.valid()) - xml.attribute("file_system", fs_type); - }; - - reporter->generate([&] (Xml_generator &xml) { - - xml.attribute("type", mbr_valid ? "mbr" : - ahdi_valid ? "ahdi" : - "disk"); - - if (mbr_valid) { - _parse_mbr(mbr, [&] (int i, Partition_record const &r, unsigned) { - - /* nullptr if extended */ - if (!_part_list[i].constructed()) - return; - - xml.node("partition", [&] { - gen_partition_attr(xml, i); - xml.attribute("type", r.type()); }); - }); - - } else if (ahdi_valid) { - _for_each_valid_partition([&] (unsigned i) { - xml.node("partition", [&] { - gen_partition_attr(xml, i); - xml.attribute("type", "bgm"); }); }); - - } else { - - xml.node("partition", [&] { - gen_partition_attr(xml, 0); }); - } - }); - } + Partition(0, (block_count_t)(block.info().block_count - 1), + Fs::Type(), 0)); bool any_partition_valid = false; _for_each_valid_partition([&] (unsigned) { @@ -276,6 +238,44 @@ struct Block::Mbr_partition_table : public Block::Partition_table return any_partition_valid; } + + void generate_report(Xml_generator &xml) const override + { + auto gen_partition_attr = [&] (Xml_generator &xml, unsigned i) + { + Partition const &part = *_part_list[i]; + + size_t const block_size = block.info().block_size; + + xml.attribute("number", i); + xml.attribute("start", part.lba); + xml.attribute("length", part.sectors); + xml.attribute("block_size", block_size); + + if (_mbr_valid) + xml.attribute("type", part.mbr_type); + else if (_ahdi_valid) + xml.attribute("type", "bgm"); + + if (part.fs_type.valid()) + xml.attribute("file_system", part.fs_type); + }; + + xml.attribute("type", _mbr_valid ? "mbr" : + _ahdi_valid ? "ahdi" : + "disk"); + + if (_mbr_valid || _ahdi_valid) { + _for_each_valid_partition([&] (unsigned i) { + xml.node("partition", [&] { + gen_partition_attr(xml, i); }); }); + + } else { + + xml.node("partition", [&] { + gen_partition_attr(xml, 0); }); + } + } }; #endif /* _PART_BLOCK__MBR_H_ */ diff --git a/repos/os/src/server/part_block/partition_table.h b/repos/os/src/server/part_block/partition_table.h index faa2b90ce9..7b1e1cecf6 100644 --- a/repos/os/src/server/part_block/partition_table.h +++ b/repos/os/src/server/part_block/partition_table.h @@ -21,6 +21,8 @@ #include #include +#include "fsprobe.h" + namespace Block { struct Partition; class Partition_table; @@ -35,8 +37,35 @@ struct Block::Partition block_number_t lba; /* logical block address on device */ block_count_t sectors; /* number of sectors in patitions */ - Partition(block_number_t lba, block_count_t sectors) - : lba(lba), sectors(sectors) { } + Fs::Type fs_type { }; + + uint8_t mbr_type { 0 }; + + using Uuid = String<40>; + Uuid guid { }; + Uuid gpt_type { }; + + using Name = String<72>; /* use GPT name antry length */ + Name name { }; + + Partition(block_number_t lba, + block_count_t sectors, + Fs::Type fs_type, + uint8_t mbr_type) + : + lba(lba), sectors(sectors), fs_type(fs_type), + mbr_type(mbr_type) + { } + + Partition(block_number_t lba, + block_count_t sectors, + Fs::Type fs_type, + Uuid const &guid, Uuid const &gpt_type, + Name const &name) + : + lba(lba), sectors(sectors), fs_type(fs_type), + guid(guid), gpt_type(gpt_type), name(name) + { } }; @@ -154,7 +183,6 @@ struct Block::Partition_table : Interface Env &env; Block_connection █ - Constructible &reporter; Sector_data data; Io_signal_handler io_sigh { @@ -167,14 +195,15 @@ struct Block::Partition_table : Interface Partition_table(Env &env, Block_connection &block, - Allocator &alloc, - Constructible &r) - : env(env), block(block), reporter(r), data(env, block, alloc) + Allocator &alloc) + : env(env), block(block), data(env, block, alloc) { } virtual Partition &partition(long num) = 0; virtual bool parse() = 0; + + virtual void generate_report(Xml_generator &xml) const = 0; }; #endif /* _PART_BLOCK__PARTITION_TABLE_H_ */