private void Load() { if (mHdds.Count == 0) { throw new Exception("Did not find any hard drives."); } //make sure we support reading the pool foreach (var hdd in mHdds) { CheckVersion(hdd.Config); } //ensure all HDDs are part of the same pool var poolGuid = mHdds.Select(h => h.Config.Get <ulong>("pool_guid")).Distinct().ToArray(); if (poolGuid.Length != 1) { throw new Exception("Hard drives are part of different pools: " + string.Join(", ", poolGuid.Select(p => p.ToString()))); } //ensure all HDDs agree on the transaction group id var txg = mHdds.Select(hdd => hdd.Uberblock.Txg).Distinct().ToArray(); if (txg.Length != 1) { throw new Exception("Uberblocks do not all have the same transaction group id: " + string.Join(", ", txg.Select(p => p.ToString()))); } var ub = mHdds[0].Uberblock; if (ub.Txg == 0) { throw new Exception("Root block pointer's transaction group is zero!"); } var vdevs = Vdev.CreateVdevTree(mHdds); mZio = new Zio(vdevs); mMos = new ObjectSet(mZio, mZio.Get <objset_phys_t>(ub.rootbp)); if (mMos.Type != dmu_objset_type_t.DMU_OST_META) { throw new Exception("Given block pointer did not point to the MOS."); } mZio.InitMetaSlabs(mMos); //the second time we will make sure that space maps contain themselves mZio.InitMetaSlabs(mMos); var objectDirectory = mMos.ReadEntry(1); //The MOS's directory sometimes has things that don't like like directory entries. //For example, the "scan" entry has scrub status stuffed into as an array of longs. mObjDir = Zap.GetDirectoryEntries(objectDirectory, true); if (mObjDir.ContainsKey(DDT_STATISTICS)) { var ddtStats = Zap.Parse(mMos.ReadEntry(mObjDir[DDT_STATISTICS])); //TODO: maybe do something interesting with the stats } { var configDn = mMos.ReadEntry(mObjDir[CONFIG]); var configBytes = Program.RentBytes(checked ((int)configDn.AvailableDataSize)); configDn.Read(configBytes, 0); mConfig = new NvList(configBytes); Program.ReturnBytes(configBytes); } CheckVersion(mConfig); CheckFeatures(); }