diff --git a/cpp/core/MsgsGen.cpp b/cpp/core/MsgsGen.cpp index ba8d0e47..74373d3a 100644 --- a/cpp/core/MsgsGen.cpp +++ b/cpp/core/MsgsGen.cpp @@ -331,6 +331,9 @@ std::ostream& operator<<(std::ostream& out, ShuckleMessageKind kind) { case ShuckleMessageKind::CDC: out << "CDC"; break; + case ShuckleMessageKind::INFO: + out << "INFO"; + break; case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: out << "REGISTER_BLOCK_SERVICES"; break; @@ -2914,6 +2917,54 @@ std::ostream& operator<<(std::ostream& out, const CdcResp& x) { return out; } +void InfoReq::pack(BincodeBuf& buf) const { +} +void InfoReq::unpack(BincodeBuf& buf) { +} +void InfoReq::clear() { +} +bool InfoReq::operator==(const InfoReq& rhs) const { + return true; +} +std::ostream& operator<<(std::ostream& out, const InfoReq& x) { + out << "InfoReq(" << ")"; + return out; +} + +void InfoResp::pack(BincodeBuf& buf) const { + buf.packScalar(numBlockServices); + buf.packScalar(numFailureDomains); + buf.packScalar(capacity); + buf.packScalar(available); + buf.packScalar(blocks); +} +void InfoResp::unpack(BincodeBuf& buf) { + numBlockServices = buf.unpackScalar(); + numFailureDomains = buf.unpackScalar(); + capacity = buf.unpackScalar(); + available = buf.unpackScalar(); + blocks = buf.unpackScalar(); +} +void InfoResp::clear() { + numBlockServices = uint32_t(0); + numFailureDomains = uint32_t(0); + capacity = uint64_t(0); + available = uint64_t(0); + blocks = uint64_t(0); +} +bool InfoResp::operator==(const InfoResp& rhs) const { + if ((uint32_t)this->numBlockServices != (uint32_t)rhs.numBlockServices) { return false; }; + if ((uint32_t)this->numFailureDomains != (uint32_t)rhs.numFailureDomains) { return false; }; + if ((uint64_t)this->capacity != (uint64_t)rhs.capacity) { return false; }; + if ((uint64_t)this->available != (uint64_t)rhs.available) { return false; }; + if ((uint64_t)this->blocks != (uint64_t)rhs.blocks) { return false; }; + return true; +} +std::ostream& operator<<(std::ostream& out, const InfoResp& x) { + out << "InfoResp(" << "NumBlockServices=" << x.numBlockServices << ", " << "NumFailureDomains=" << x.numFailureDomains << ", " << "Capacity=" << x.capacity << ", " << "Available=" << x.available << ", " << "Blocks=" << x.blocks << ")"; + return out; +} + void RegisterBlockServicesReq::pack(BincodeBuf& buf) const { buf.packList(blockServices); } @@ -5112,43 +5163,53 @@ CdcReq& ShuckleReqContainer::setCdc() { x.clear(); return x; } +const InfoReq& ShuckleReqContainer::getInfo() const { + ALWAYS_ASSERT(_kind == ShuckleMessageKind::INFO, "%s != %s", _kind, ShuckleMessageKind::INFO); + return std::get<2>(_data); +} +InfoReq& ShuckleReqContainer::setInfo() { + _kind = ShuckleMessageKind::INFO; + auto& x = std::get<2>(_data); + x.clear(); + return x; +} const RegisterBlockServicesReq& ShuckleReqContainer::getRegisterBlockServices() const { ALWAYS_ASSERT(_kind == ShuckleMessageKind::REGISTER_BLOCK_SERVICES, "%s != %s", _kind, ShuckleMessageKind::REGISTER_BLOCK_SERVICES); - return std::get<2>(_data); + return std::get<3>(_data); } RegisterBlockServicesReq& ShuckleReqContainer::setRegisterBlockServices() { _kind = ShuckleMessageKind::REGISTER_BLOCK_SERVICES; - auto& x = std::get<2>(_data); + auto& x = std::get<3>(_data); x.clear(); return x; } const RegisterShardReq& ShuckleReqContainer::getRegisterShard() const { ALWAYS_ASSERT(_kind == ShuckleMessageKind::REGISTER_SHARD, "%s != %s", _kind, ShuckleMessageKind::REGISTER_SHARD); - return std::get<3>(_data); + return std::get<4>(_data); } RegisterShardReq& ShuckleReqContainer::setRegisterShard() { _kind = ShuckleMessageKind::REGISTER_SHARD; - auto& x = std::get<3>(_data); + auto& x = std::get<4>(_data); x.clear(); return x; } const AllBlockServicesReq& ShuckleReqContainer::getAllBlockServices() const { ALWAYS_ASSERT(_kind == ShuckleMessageKind::ALL_BLOCK_SERVICES, "%s != %s", _kind, ShuckleMessageKind::ALL_BLOCK_SERVICES); - return std::get<4>(_data); + return std::get<5>(_data); } AllBlockServicesReq& ShuckleReqContainer::setAllBlockServices() { _kind = ShuckleMessageKind::ALL_BLOCK_SERVICES; - auto& x = std::get<4>(_data); + auto& x = std::get<5>(_data); x.clear(); return x; } const RegisterCdcReq& ShuckleReqContainer::getRegisterCdc() const { ALWAYS_ASSERT(_kind == ShuckleMessageKind::REGISTER_CDC, "%s != %s", _kind, ShuckleMessageKind::REGISTER_CDC); - return std::get<5>(_data); + return std::get<6>(_data); } RegisterCdcReq& ShuckleReqContainer::setRegisterCdc() { _kind = ShuckleMessageKind::REGISTER_CDC; - auto& x = std::get<5>(_data); + auto& x = std::get<6>(_data); x.clear(); return x; } @@ -5158,14 +5219,16 @@ size_t ShuckleReqContainer::packedSize() const { return std::get<0>(_data).packedSize(); case ShuckleMessageKind::CDC: return std::get<1>(_data).packedSize(); - case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: + case ShuckleMessageKind::INFO: return std::get<2>(_data).packedSize(); - case ShuckleMessageKind::REGISTER_SHARD: + case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: return std::get<3>(_data).packedSize(); - case ShuckleMessageKind::ALL_BLOCK_SERVICES: + case ShuckleMessageKind::REGISTER_SHARD: return std::get<4>(_data).packedSize(); - case ShuckleMessageKind::REGISTER_CDC: + case ShuckleMessageKind::ALL_BLOCK_SERVICES: return std::get<5>(_data).packedSize(); + case ShuckleMessageKind::REGISTER_CDC: + return std::get<6>(_data).packedSize(); default: throw EGGS_EXCEPTION("bad ShuckleMessageKind kind %s", _kind); } @@ -5179,18 +5242,21 @@ void ShuckleReqContainer::pack(BincodeBuf& buf) const { case ShuckleMessageKind::CDC: std::get<1>(_data).pack(buf); break; - case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: + case ShuckleMessageKind::INFO: std::get<2>(_data).pack(buf); break; - case ShuckleMessageKind::REGISTER_SHARD: + case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: std::get<3>(_data).pack(buf); break; - case ShuckleMessageKind::ALL_BLOCK_SERVICES: + case ShuckleMessageKind::REGISTER_SHARD: std::get<4>(_data).pack(buf); break; - case ShuckleMessageKind::REGISTER_CDC: + case ShuckleMessageKind::ALL_BLOCK_SERVICES: std::get<5>(_data).pack(buf); break; + case ShuckleMessageKind::REGISTER_CDC: + std::get<6>(_data).pack(buf); + break; default: throw EGGS_EXCEPTION("bad ShuckleMessageKind kind %s", _kind); } @@ -5205,18 +5271,21 @@ void ShuckleReqContainer::unpack(BincodeBuf& buf, ShuckleMessageKind kind) { case ShuckleMessageKind::CDC: std::get<1>(_data).unpack(buf); break; - case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: + case ShuckleMessageKind::INFO: std::get<2>(_data).unpack(buf); break; - case ShuckleMessageKind::REGISTER_SHARD: + case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: std::get<3>(_data).unpack(buf); break; - case ShuckleMessageKind::ALL_BLOCK_SERVICES: + case ShuckleMessageKind::REGISTER_SHARD: std::get<4>(_data).unpack(buf); break; - case ShuckleMessageKind::REGISTER_CDC: + case ShuckleMessageKind::ALL_BLOCK_SERVICES: std::get<5>(_data).unpack(buf); break; + case ShuckleMessageKind::REGISTER_CDC: + std::get<6>(_data).unpack(buf); + break; default: throw BINCODE_EXCEPTION("bad ShuckleMessageKind kind %s", kind); } @@ -5230,6 +5299,9 @@ std::ostream& operator<<(std::ostream& out, const ShuckleReqContainer& x) { case ShuckleMessageKind::CDC: out << x.getCdc(); break; + case ShuckleMessageKind::INFO: + out << x.getInfo(); + break; case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: out << x.getRegisterBlockServices(); break; @@ -5268,43 +5340,53 @@ CdcResp& ShuckleRespContainer::setCdc() { x.clear(); return x; } +const InfoResp& ShuckleRespContainer::getInfo() const { + ALWAYS_ASSERT(_kind == ShuckleMessageKind::INFO, "%s != %s", _kind, ShuckleMessageKind::INFO); + return std::get<2>(_data); +} +InfoResp& ShuckleRespContainer::setInfo() { + _kind = ShuckleMessageKind::INFO; + auto& x = std::get<2>(_data); + x.clear(); + return x; +} const RegisterBlockServicesResp& ShuckleRespContainer::getRegisterBlockServices() const { ALWAYS_ASSERT(_kind == ShuckleMessageKind::REGISTER_BLOCK_SERVICES, "%s != %s", _kind, ShuckleMessageKind::REGISTER_BLOCK_SERVICES); - return std::get<2>(_data); + return std::get<3>(_data); } RegisterBlockServicesResp& ShuckleRespContainer::setRegisterBlockServices() { _kind = ShuckleMessageKind::REGISTER_BLOCK_SERVICES; - auto& x = std::get<2>(_data); + auto& x = std::get<3>(_data); x.clear(); return x; } const RegisterShardResp& ShuckleRespContainer::getRegisterShard() const { ALWAYS_ASSERT(_kind == ShuckleMessageKind::REGISTER_SHARD, "%s != %s", _kind, ShuckleMessageKind::REGISTER_SHARD); - return std::get<3>(_data); + return std::get<4>(_data); } RegisterShardResp& ShuckleRespContainer::setRegisterShard() { _kind = ShuckleMessageKind::REGISTER_SHARD; - auto& x = std::get<3>(_data); + auto& x = std::get<4>(_data); x.clear(); return x; } const AllBlockServicesResp& ShuckleRespContainer::getAllBlockServices() const { ALWAYS_ASSERT(_kind == ShuckleMessageKind::ALL_BLOCK_SERVICES, "%s != %s", _kind, ShuckleMessageKind::ALL_BLOCK_SERVICES); - return std::get<4>(_data); + return std::get<5>(_data); } AllBlockServicesResp& ShuckleRespContainer::setAllBlockServices() { _kind = ShuckleMessageKind::ALL_BLOCK_SERVICES; - auto& x = std::get<4>(_data); + auto& x = std::get<5>(_data); x.clear(); return x; } const RegisterCdcResp& ShuckleRespContainer::getRegisterCdc() const { ALWAYS_ASSERT(_kind == ShuckleMessageKind::REGISTER_CDC, "%s != %s", _kind, ShuckleMessageKind::REGISTER_CDC); - return std::get<5>(_data); + return std::get<6>(_data); } RegisterCdcResp& ShuckleRespContainer::setRegisterCdc() { _kind = ShuckleMessageKind::REGISTER_CDC; - auto& x = std::get<5>(_data); + auto& x = std::get<6>(_data); x.clear(); return x; } @@ -5314,14 +5396,16 @@ size_t ShuckleRespContainer::packedSize() const { return std::get<0>(_data).packedSize(); case ShuckleMessageKind::CDC: return std::get<1>(_data).packedSize(); - case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: + case ShuckleMessageKind::INFO: return std::get<2>(_data).packedSize(); - case ShuckleMessageKind::REGISTER_SHARD: + case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: return std::get<3>(_data).packedSize(); - case ShuckleMessageKind::ALL_BLOCK_SERVICES: + case ShuckleMessageKind::REGISTER_SHARD: return std::get<4>(_data).packedSize(); - case ShuckleMessageKind::REGISTER_CDC: + case ShuckleMessageKind::ALL_BLOCK_SERVICES: return std::get<5>(_data).packedSize(); + case ShuckleMessageKind::REGISTER_CDC: + return std::get<6>(_data).packedSize(); default: throw EGGS_EXCEPTION("bad ShuckleMessageKind kind %s", _kind); } @@ -5335,18 +5419,21 @@ void ShuckleRespContainer::pack(BincodeBuf& buf) const { case ShuckleMessageKind::CDC: std::get<1>(_data).pack(buf); break; - case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: + case ShuckleMessageKind::INFO: std::get<2>(_data).pack(buf); break; - case ShuckleMessageKind::REGISTER_SHARD: + case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: std::get<3>(_data).pack(buf); break; - case ShuckleMessageKind::ALL_BLOCK_SERVICES: + case ShuckleMessageKind::REGISTER_SHARD: std::get<4>(_data).pack(buf); break; - case ShuckleMessageKind::REGISTER_CDC: + case ShuckleMessageKind::ALL_BLOCK_SERVICES: std::get<5>(_data).pack(buf); break; + case ShuckleMessageKind::REGISTER_CDC: + std::get<6>(_data).pack(buf); + break; default: throw EGGS_EXCEPTION("bad ShuckleMessageKind kind %s", _kind); } @@ -5361,18 +5448,21 @@ void ShuckleRespContainer::unpack(BincodeBuf& buf, ShuckleMessageKind kind) { case ShuckleMessageKind::CDC: std::get<1>(_data).unpack(buf); break; - case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: + case ShuckleMessageKind::INFO: std::get<2>(_data).unpack(buf); break; - case ShuckleMessageKind::REGISTER_SHARD: + case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: std::get<3>(_data).unpack(buf); break; - case ShuckleMessageKind::ALL_BLOCK_SERVICES: + case ShuckleMessageKind::REGISTER_SHARD: std::get<4>(_data).unpack(buf); break; - case ShuckleMessageKind::REGISTER_CDC: + case ShuckleMessageKind::ALL_BLOCK_SERVICES: std::get<5>(_data).unpack(buf); break; + case ShuckleMessageKind::REGISTER_CDC: + std::get<6>(_data).unpack(buf); + break; default: throw BINCODE_EXCEPTION("bad ShuckleMessageKind kind %s", kind); } @@ -5386,6 +5476,9 @@ std::ostream& operator<<(std::ostream& out, const ShuckleRespContainer& x) { case ShuckleMessageKind::CDC: out << x.getCdc(); break; + case ShuckleMessageKind::INFO: + out << x.getInfo(); + break; case ShuckleMessageKind::REGISTER_BLOCK_SERVICES: out << x.getRegisterBlockServices(); break; diff --git a/cpp/core/MsgsGen.hpp b/cpp/core/MsgsGen.hpp index d488d2be..406486b5 100644 --- a/cpp/core/MsgsGen.hpp +++ b/cpp/core/MsgsGen.hpp @@ -122,6 +122,7 @@ enum class ShuckleMessageKind : uint8_t { ERROR = 0, SHARDS = 3, CDC = 7, + INFO = 8, REGISTER_BLOCK_SERVICES = 2, REGISTER_SHARD = 4, ALL_BLOCK_SERVICES = 5, @@ -2619,6 +2620,50 @@ struct CdcResp { std::ostream& operator<<(std::ostream& out, const CdcResp& x); +struct InfoReq { + + static constexpr uint16_t STATIC_SIZE = 0; // + + InfoReq() { clear(); } + uint16_t packedSize() const { + uint16_t _size = 0; + return _size; + } + void pack(BincodeBuf& buf) const; + void unpack(BincodeBuf& buf); + void clear(); + bool operator==(const InfoReq&rhs) const; +}; + +std::ostream& operator<<(std::ostream& out, const InfoReq& x); + +struct InfoResp { + uint32_t numBlockServices; + uint32_t numFailureDomains; + uint64_t capacity; + uint64_t available; + uint64_t blocks; + + static constexpr uint16_t STATIC_SIZE = 4 + 4 + 8 + 8 + 8; // numBlockServices + numFailureDomains + capacity + available + blocks + + InfoResp() { clear(); } + uint16_t packedSize() const { + uint16_t _size = 0; + _size += 4; // numBlockServices + _size += 4; // numFailureDomains + _size += 8; // capacity + _size += 8; // available + _size += 8; // blocks + return _size; + } + void pack(BincodeBuf& buf) const; + void unpack(BincodeBuf& buf); + void clear(); + bool operator==(const InfoResp&rhs) const; +}; + +std::ostream& operator<<(std::ostream& out, const InfoResp& x); + struct RegisterBlockServicesReq { BincodeList blockServices; @@ -3198,13 +3243,15 @@ std::ostream& operator<<(std::ostream& out, const CDCRespContainer& x); struct ShuckleReqContainer { private: ShuckleMessageKind _kind = (ShuckleMessageKind)0; - std::tuple _data; + std::tuple _data; public: ShuckleMessageKind kind() const { return _kind; } const ShardsReq& getShards() const; ShardsReq& setShards(); const CdcReq& getCdc() const; CdcReq& setCdc(); + const InfoReq& getInfo() const; + InfoReq& setInfo(); const RegisterBlockServicesReq& getRegisterBlockServices() const; RegisterBlockServicesReq& setRegisterBlockServices(); const RegisterShardReq& getRegisterShard() const; @@ -3226,13 +3273,15 @@ std::ostream& operator<<(std::ostream& out, const ShuckleReqContainer& x); struct ShuckleRespContainer { private: ShuckleMessageKind _kind = (ShuckleMessageKind)0; - std::tuple _data; + std::tuple _data; public: ShuckleMessageKind kind() const { return _kind; } const ShardsResp& getShards() const; ShardsResp& setShards(); const CdcResp& getCdc() const; CdcResp& setCdc(); + const InfoResp& getInfo() const; + InfoResp& setInfo(); const RegisterBlockServicesResp& getRegisterBlockServices() const; RegisterBlockServicesResp& setRegisterBlockServices(); const RegisterShardResp& getRegisterShard() const; diff --git a/cpp/ktools/eggsktools.cpp b/cpp/ktools/eggsktools.cpp index 7b7e4e27..ff6fd0b7 100644 --- a/cpp/ktools/eggsktools.cpp +++ b/cpp/ktools/eggsktools.cpp @@ -15,7 +15,7 @@ const char* exe = NULL; #define badUsage(...) do { \ - fprintf(stderr, "Bad usage, expecting %s writefile|readfile \n", exe); \ + fprintf(stderr, "Bad usage, expecting %s writefile|readfile|readlink \n", exe); \ __VA_OPT__(fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n");) \ exit(2); \ } while(0) \ diff --git a/go/bincodegen/bincodegen.go b/go/bincodegen/bincodegen.go index 60b86636..1b377a68 100644 --- a/go/bincodegen/bincodegen.go +++ b/go/bincodegen/bincodegen.go @@ -1495,6 +1495,11 @@ func main() { reflect.TypeOf(msgs.CdcReq{}), reflect.TypeOf(msgs.CdcResp{}), }, + { + 0x08, + reflect.TypeOf(msgs.InfoReq{}), + reflect.TypeOf(msgs.InfoResp{}), + }, } shuckleReqResps := append(kernelShuckleReqResps, []reqRespType{ diff --git a/go/eggsshuckle/eggsshuckle.go b/go/eggsshuckle/eggsshuckle.go index a12b536c..f854c0cd 100644 --- a/go/eggsshuckle/eggsshuckle.go +++ b/go/eggsshuckle/eggsshuckle.go @@ -145,6 +145,25 @@ func handleRegisterCdcReq(log *lib.Logger, s *state, w io.Writer, req *msgs.Regi return &msgs.RegisterCdcResp{} } +func handleInfoReq(log *lib.Logger, s *state, w io.Writer, req *msgs.InfoReq) *msgs.InfoResp { + s.mutex.RLock() + defer s.mutex.RUnlock() + + resp := msgs.InfoResp{} + failureDomains := make(map[[16]byte]struct{}) + + for _, bs := range s.blockServices { + resp.Capacity += bs.CapacityBytes + resp.NumBlockServices++ + resp.Available += bs.AvailableBytes + resp.Blocks += bs.Blocks + failureDomains[bs.FailureDomain] = struct{}{} + } + resp.NumFailureDomains = uint32(len(failureDomains)) + + return &resp +} + func handleRequest(log *lib.Logger, s *state, conn *net.TCPConn) { conn.SetLinger(0) // poor man error handling for now defer conn.Close() @@ -174,6 +193,8 @@ func handleRequest(log *lib.Logger, s *state, conn *net.TCPConn) { resp = handleCdcReq(log, s, conn, whichReq) case *msgs.RegisterCdcReq: resp = handleRegisterCdcReq(log, s, conn, whichReq) + case *msgs.InfoReq: + resp = handleInfoReq(log, s, conn, whichReq) default: log.RaiseAlert(fmt.Errorf("bad req type %T", req)) } diff --git a/go/lib/shucklereq.go b/go/lib/shucklereq.go index 11142285..d47079e8 100644 --- a/go/lib/shucklereq.go +++ b/go/lib/shucklereq.go @@ -45,6 +45,8 @@ func ReadShuckleRequest( req = &msgs.RegisterCdcReq{} case msgs.CDC: req = &msgs.CdcReq{} + case msgs.INFO: + req = &msgs.InfoReq{} default: return nil, fmt.Errorf("bad shuckle request kind %v", kind) } @@ -109,6 +111,8 @@ func ReadShuckleResponse( resp = &msgs.RegisterCdcResp{} case msgs.CDC: resp = &msgs.CdcResp{} + case msgs.INFO: + resp = &msgs.InfoResp{} default: return nil, fmt.Errorf("bad shuckle response kind %v", kind) } diff --git a/go/msgs/msgs.go b/go/msgs/msgs.go index eaa029db..4de3eaa1 100644 --- a/go/msgs/msgs.go +++ b/go/msgs/msgs.go @@ -1384,6 +1384,16 @@ type CdcResp struct { LastSeen EggsTime } +type InfoReq struct{} + +type InfoResp struct { + NumBlockServices uint32 + NumFailureDomains uint32 + Capacity uint64 + Available uint64 + Blocks uint64 +} + // -------------------------------------------------------------------- // block service requests/responses diff --git a/go/msgs/msgs_bincode.go b/go/msgs/msgs_bincode.go index c461bc88..a506780f 100644 --- a/go/msgs/msgs_bincode.go +++ b/go/msgs/msgs_bincode.go @@ -542,6 +542,8 @@ func (k ShuckleMessageKind) String() string { return "SHARDS" case 7: return "CDC" + case 8: + return "INFO" case 2: return "REGISTER_BLOCK_SERVICES" case 4: @@ -559,6 +561,7 @@ func (k ShuckleMessageKind) String() string { const ( SHARDS ShuckleMessageKind = 0x3 CDC ShuckleMessageKind = 0x7 + INFO ShuckleMessageKind = 0x8 REGISTER_BLOCK_SERVICES ShuckleMessageKind = 0x2 REGISTER_SHARD ShuckleMessageKind = 0x4 ALL_BLOCK_SERVICES ShuckleMessageKind = 0x5 @@ -571,6 +574,8 @@ func MkShuckleMessage(k string) (ShuckleRequest, ShuckleResponse) { return &ShardsReq{}, &ShardsResp{} case k == "CDC": return &CdcReq{}, &CdcResp{} + case k == "INFO": + return &InfoReq{}, &InfoResp{} case k == "REGISTER_BLOCK_SERVICES": return &RegisterBlockServicesReq{}, &RegisterBlockServicesResp{} case k == "REGISTER_SHARD": @@ -3624,6 +3629,60 @@ func (v *CdcResp) Unpack(r io.Reader) error { return nil } +func (v *InfoReq) ShuckleRequestKind() ShuckleMessageKind { + return INFO +} + +func (v *InfoReq) Pack(w io.Writer) error { + return nil +} + +func (v *InfoReq) Unpack(r io.Reader) error { + return nil +} + +func (v *InfoResp) ShuckleResponseKind() ShuckleMessageKind { + return INFO +} + +func (v *InfoResp) Pack(w io.Writer) error { + if err := bincode.PackScalar(w, uint32(v.NumBlockServices)); err != nil { + return err + } + if err := bincode.PackScalar(w, uint32(v.NumFailureDomains)); err != nil { + return err + } + if err := bincode.PackScalar(w, uint64(v.Capacity)); err != nil { + return err + } + if err := bincode.PackScalar(w, uint64(v.Available)); err != nil { + return err + } + if err := bincode.PackScalar(w, uint64(v.Blocks)); err != nil { + return err + } + return nil +} + +func (v *InfoResp) Unpack(r io.Reader) error { + if err := bincode.UnpackScalar(r, (*uint32)(&v.NumBlockServices)); err != nil { + return err + } + if err := bincode.UnpackScalar(r, (*uint32)(&v.NumFailureDomains)); err != nil { + return err + } + if err := bincode.UnpackScalar(r, (*uint64)(&v.Capacity)); err != nil { + return err + } + if err := bincode.UnpackScalar(r, (*uint64)(&v.Available)); err != nil { + return err + } + if err := bincode.UnpackScalar(r, (*uint64)(&v.Blocks)); err != nil { + return err + } + return nil +} + func (v *RegisterBlockServicesReq) ShuckleRequestKind() ShuckleMessageKind { return REGISTER_BLOCK_SERVICES } diff --git a/kmod/bincodegen.h b/kmod/bincodegen.h index bbec9b94..e3895a55 100644 --- a/kmod/bincodegen.h +++ b/kmod/bincodegen.h @@ -84,7 +84,8 @@ #define EGGSFS_SHUCKLE_SHARDS 0x3 #define EGGSFS_SHUCKLE_CDC 0x7 -#define __print_eggsfs_shuckle_kind(k) __print_symbolic(k, { 3, "SHARDS" }, { 7, "CDC" }) +#define EGGSFS_SHUCKLE_INFO 0x8 +#define __print_eggsfs_shuckle_kind(k) __print_symbolic(k, { 3, "SHARDS" }, { 7, "CDC" }, { 8, "INFO" }) #define EGGSFS_BLOCKS_FETCH_BLOCK 0x2 #define EGGSFS_BLOCKS_WRITE_BLOCK 0x3 @@ -4821,6 +4822,173 @@ static inline void _eggsfs_cdc_resp_put_last_seen(struct eggsfs_bincode_put_ctx* { struct eggsfs_cdc_resp_last_seen* __dummy __attribute__((unused)) = &(prev); }\ struct eggsfs_cdc_resp_end* next __attribute__((unused)) = NULL +#define EGGSFS_INFO_REQ_SIZE 0 +struct eggsfs_info_req_start; +#define eggsfs_info_req_get_start(ctx, start) struct eggsfs_info_req_start* start = NULL + +struct eggsfs_info_req_end; +#define eggsfs_info_req_get_end(ctx, prev, next) \ + { struct eggsfs_info_req_start** __dummy __attribute__((unused)) = &(prev); }\ + struct eggsfs_info_req_end* next = NULL + +static inline void eggsfs_info_req_get_finish(struct eggsfs_bincode_get_ctx* ctx, struct eggsfs_info_req_end* end) { + if (unlikely(ctx->buf != ctx->end)) { + ctx->err = EGGSFS_ERR_MALFORMED_RESPONSE; + } +} + +#define eggsfs_info_req_put_start(ctx, start) struct eggsfs_info_req_start* start = NULL + +#define eggsfs_info_req_put_end(ctx, prev, next) \ + { struct eggsfs_info_req_start** __dummy __attribute__((unused)) = &(prev); }\ + struct eggsfs_info_req_end* next __attribute__((unused)) = NULL + +#define EGGSFS_INFO_RESP_SIZE 32 +struct eggsfs_info_resp_start; +#define eggsfs_info_resp_get_start(ctx, start) struct eggsfs_info_resp_start* start = NULL + +struct eggsfs_info_resp_num_block_services { u32 x; }; +static inline void _eggsfs_info_resp_get_num_block_services(struct eggsfs_bincode_get_ctx* ctx, struct eggsfs_info_resp_start** prev, struct eggsfs_info_resp_num_block_services* next) { + if (likely(ctx->err == 0)) { + if (unlikely(ctx->end - ctx->buf < 4)) { + ctx->err = EGGSFS_ERR_MALFORMED_RESPONSE; + } else { + next->x = get_unaligned_le32(ctx->buf); + ctx->buf += 4; + } + } +} +#define eggsfs_info_resp_get_num_block_services(ctx, prev, next) \ + struct eggsfs_info_resp_num_block_services next; \ + _eggsfs_info_resp_get_num_block_services(ctx, &(prev), &(next)) + +struct eggsfs_info_resp_num_failure_domains { u32 x; }; +static inline void _eggsfs_info_resp_get_num_failure_domains(struct eggsfs_bincode_get_ctx* ctx, struct eggsfs_info_resp_num_block_services* prev, struct eggsfs_info_resp_num_failure_domains* next) { + if (likely(ctx->err == 0)) { + if (unlikely(ctx->end - ctx->buf < 4)) { + ctx->err = EGGSFS_ERR_MALFORMED_RESPONSE; + } else { + next->x = get_unaligned_le32(ctx->buf); + ctx->buf += 4; + } + } +} +#define eggsfs_info_resp_get_num_failure_domains(ctx, prev, next) \ + struct eggsfs_info_resp_num_failure_domains next; \ + _eggsfs_info_resp_get_num_failure_domains(ctx, &(prev), &(next)) + +struct eggsfs_info_resp_capacity { u64 x; }; +static inline void _eggsfs_info_resp_get_capacity(struct eggsfs_bincode_get_ctx* ctx, struct eggsfs_info_resp_num_failure_domains* prev, struct eggsfs_info_resp_capacity* next) { + if (likely(ctx->err == 0)) { + if (unlikely(ctx->end - ctx->buf < 8)) { + ctx->err = EGGSFS_ERR_MALFORMED_RESPONSE; + } else { + next->x = get_unaligned_le64(ctx->buf); + ctx->buf += 8; + } + } +} +#define eggsfs_info_resp_get_capacity(ctx, prev, next) \ + struct eggsfs_info_resp_capacity next; \ + _eggsfs_info_resp_get_capacity(ctx, &(prev), &(next)) + +struct eggsfs_info_resp_available { u64 x; }; +static inline void _eggsfs_info_resp_get_available(struct eggsfs_bincode_get_ctx* ctx, struct eggsfs_info_resp_capacity* prev, struct eggsfs_info_resp_available* next) { + if (likely(ctx->err == 0)) { + if (unlikely(ctx->end - ctx->buf < 8)) { + ctx->err = EGGSFS_ERR_MALFORMED_RESPONSE; + } else { + next->x = get_unaligned_le64(ctx->buf); + ctx->buf += 8; + } + } +} +#define eggsfs_info_resp_get_available(ctx, prev, next) \ + struct eggsfs_info_resp_available next; \ + _eggsfs_info_resp_get_available(ctx, &(prev), &(next)) + +struct eggsfs_info_resp_blocks { u64 x; }; +static inline void _eggsfs_info_resp_get_blocks(struct eggsfs_bincode_get_ctx* ctx, struct eggsfs_info_resp_available* prev, struct eggsfs_info_resp_blocks* next) { + if (likely(ctx->err == 0)) { + if (unlikely(ctx->end - ctx->buf < 8)) { + ctx->err = EGGSFS_ERR_MALFORMED_RESPONSE; + } else { + next->x = get_unaligned_le64(ctx->buf); + ctx->buf += 8; + } + } +} +#define eggsfs_info_resp_get_blocks(ctx, prev, next) \ + struct eggsfs_info_resp_blocks next; \ + _eggsfs_info_resp_get_blocks(ctx, &(prev), &(next)) + +struct eggsfs_info_resp_end; +#define eggsfs_info_resp_get_end(ctx, prev, next) \ + { struct eggsfs_info_resp_blocks* __dummy __attribute__((unused)) = &(prev); }\ + struct eggsfs_info_resp_end* next = NULL + +static inline void eggsfs_info_resp_get_finish(struct eggsfs_bincode_get_ctx* ctx, struct eggsfs_info_resp_end* end) { + if (unlikely(ctx->buf != ctx->end)) { + ctx->err = EGGSFS_ERR_MALFORMED_RESPONSE; + } +} + +#define eggsfs_info_resp_put_start(ctx, start) struct eggsfs_info_resp_start* start = NULL + +static inline void _eggsfs_info_resp_put_num_block_services(struct eggsfs_bincode_put_ctx* ctx, struct eggsfs_info_resp_start** prev, struct eggsfs_info_resp_num_block_services* next, u32 x) { + next = NULL; + BUG_ON(ctx->end - ctx->cursor < 4); + put_unaligned_le32(x, ctx->cursor); + ctx->cursor += 4; +} +#define eggsfs_info_resp_put_num_block_services(ctx, prev, next, x) \ + struct eggsfs_info_resp_num_block_services next; \ + _eggsfs_info_resp_put_num_block_services(ctx, &(prev), &(next), x) + +static inline void _eggsfs_info_resp_put_num_failure_domains(struct eggsfs_bincode_put_ctx* ctx, struct eggsfs_info_resp_num_block_services* prev, struct eggsfs_info_resp_num_failure_domains* next, u32 x) { + next = NULL; + BUG_ON(ctx->end - ctx->cursor < 4); + put_unaligned_le32(x, ctx->cursor); + ctx->cursor += 4; +} +#define eggsfs_info_resp_put_num_failure_domains(ctx, prev, next, x) \ + struct eggsfs_info_resp_num_failure_domains next; \ + _eggsfs_info_resp_put_num_failure_domains(ctx, &(prev), &(next), x) + +static inline void _eggsfs_info_resp_put_capacity(struct eggsfs_bincode_put_ctx* ctx, struct eggsfs_info_resp_num_failure_domains* prev, struct eggsfs_info_resp_capacity* next, u64 x) { + next = NULL; + BUG_ON(ctx->end - ctx->cursor < 8); + put_unaligned_le64(x, ctx->cursor); + ctx->cursor += 8; +} +#define eggsfs_info_resp_put_capacity(ctx, prev, next, x) \ + struct eggsfs_info_resp_capacity next; \ + _eggsfs_info_resp_put_capacity(ctx, &(prev), &(next), x) + +static inline void _eggsfs_info_resp_put_available(struct eggsfs_bincode_put_ctx* ctx, struct eggsfs_info_resp_capacity* prev, struct eggsfs_info_resp_available* next, u64 x) { + next = NULL; + BUG_ON(ctx->end - ctx->cursor < 8); + put_unaligned_le64(x, ctx->cursor); + ctx->cursor += 8; +} +#define eggsfs_info_resp_put_available(ctx, prev, next, x) \ + struct eggsfs_info_resp_available next; \ + _eggsfs_info_resp_put_available(ctx, &(prev), &(next), x) + +static inline void _eggsfs_info_resp_put_blocks(struct eggsfs_bincode_put_ctx* ctx, struct eggsfs_info_resp_available* prev, struct eggsfs_info_resp_blocks* next, u64 x) { + next = NULL; + BUG_ON(ctx->end - ctx->cursor < 8); + put_unaligned_le64(x, ctx->cursor); + ctx->cursor += 8; +} +#define eggsfs_info_resp_put_blocks(ctx, prev, next, x) \ + struct eggsfs_info_resp_blocks next; \ + _eggsfs_info_resp_put_blocks(ctx, &(prev), &(next), x) + +#define eggsfs_info_resp_put_end(ctx, prev, next) \ + { struct eggsfs_info_resp_blocks* __dummy __attribute__((unused)) = &(prev); }\ + struct eggsfs_info_resp_end* next __attribute__((unused)) = NULL + #define EGGSFS_FETCH_BLOCK_REQ_SIZE 16 struct eggsfs_fetch_block_req_start; #define eggsfs_fetch_block_req_get_start(ctx, start) struct eggsfs_fetch_block_req_start* start = NULL diff --git a/kmod/shuckle.c b/kmod/shuckle.c index e8eb9d56..a5569abf 100644 --- a/kmod/shuckle.c +++ b/kmod/shuckle.c @@ -28,29 +28,15 @@ int eggsfs_read_shuckle_resp_header(char* buf, u32* resp_len, u8* resp_kind) { return 0; } -int eggsfs_create_shuckle_socket(const char* shuckle_addr, struct socket** sock) { +int eggsfs_create_shuckle_socket(struct sockaddr_in* addr, struct socket** sock) { int err; - const char* addr_end; - u16 port; - - // parse device, which is the shuckle address in 0.0.0.0:0 form (ipv4, port) - struct sockaddr_in addr; - addr.sin_family = AF_INET; - if (in4_pton(shuckle_addr, -1, (u8*)&addr.sin_addr, ':', &addr_end) != 1) { - err = -EINVAL; - goto out_err; - } - err = kstrtou16(addr_end+1, 10, &port); - if (err < 0) { goto out_err; } - addr.sin_port = htons(port); - eggsfs_debug_print("parsed shuckle addr %pI4:%d", &addr.sin_addr, ntohs(addr.sin_port)); // create socket err = sock_create_kern(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP, sock); if (err < 0) { goto out_err; } // connect - err = kernel_connect(*sock, (struct sockaddr*)&addr, sizeof(addr), 0); + err = kernel_connect(*sock, (struct sockaddr*)addr, sizeof(*addr), 0); if (err < 0) { goto out_connect; } eggsfs_debug_print("connected to shuckle"); @@ -62,3 +48,21 @@ out_err: eggsfs_debug_print("failed err=%d", err); return err; } + +int eggsfs_parse_shuckle_addr(const char* str, struct sockaddr_in* addr) { + int err; + const char* addr_end; + u16 port; + + // parse device, which is the shuckle address in 0.0.0.0:0 form (ipv4, port) + addr->sin_family = AF_INET; + if (in4_pton(str, -1, (u8*)&addr->sin_addr, ':', &addr_end) != 1) { + return -EINVAL; + } + err = kstrtou16(addr_end+1, 10, &port); + if (err < 0) { return err; } + addr->sin_port = htons(port); + eggsfs_debug_print("parsed shuckle addr %pI4:%d", &addr->sin_addr, ntohs(addr->sin_port)); + + return 0; +} \ No newline at end of file diff --git a/kmod/shuckle.h b/kmod/shuckle.h index 49853f18..212f870b 100644 --- a/kmod/shuckle.h +++ b/kmod/shuckle.h @@ -10,6 +10,8 @@ void eggsfs_write_shuckle_req_header(char* buf, u32 req_len, u8 req_kind); #define EGGSFS_SHUCKLE_RESP_HEADER_SIZE (4 + 4 + 1) // protocol + len + kind int eggsfs_read_shuckle_resp_header(char* buf, u32* resp_len, u8* resp_kind); -int eggsfs_create_shuckle_socket(const char* shuckle_addr, struct socket** sock); +int eggsfs_parse_shuckle_addr(const char* str, struct sockaddr_in* addr); + +int eggsfs_create_shuckle_socket(struct sockaddr_in* addr, struct socket** sock); #endif diff --git a/kmod/super.c b/kmod/super.c index bc404c42..d7443162 100644 --- a/kmod/super.c +++ b/kmod/super.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "log.h" #include "inode.h" @@ -27,11 +28,14 @@ static struct eggsfs_fs_info* eggsfs_init_fs_info(const char* dev_name) { struct eggsfs_fs_info* info = kmalloc(sizeof(struct eggsfs_fs_info), GFP_KERNEL); if (!info) { err = -ENOMEM; goto out; } + err = eggsfs_parse_shuckle_addr(dev_name, &info->shuckle_addr); + if (err) { goto out; } + err = eggsfs_init_shard_socket(&info->sock); if (err) { goto out_info; } struct socket* shuckle_sock; - err = eggsfs_create_shuckle_socket(dev_name, &shuckle_sock); + err = eggsfs_create_shuckle_socket(&info->shuckle_addr, &shuckle_sock); if (err < 0) { goto out_info; } struct kvec iov; @@ -193,12 +197,96 @@ static void eggsfs_put_super(struct super_block* sb) { sb->s_fs_info = NULL; } +#define EGGSFS_SUPER_MAGIC 0x45474753 // EGGS + +int eggsfs_statfs(struct dentry* dentry, struct kstatfs* stats) { + struct eggsfs_fs_info* info = (struct eggsfs_fs_info*)dentry->d_sb->s_fs_info; + + struct socket* shuckle_sock; + int err = eggsfs_create_shuckle_socket(&info->shuckle_addr, &shuckle_sock); + if (err < 0) { return err; } + + struct kvec iov; + struct msghdr msg = {NULL}; + + static_assert(EGGSFS_INFO_REQ_SIZE == 0); + char shuckle_req[EGGSFS_SHUCKLE_REQ_HEADER_SIZE]; + eggsfs_write_shuckle_req_header(shuckle_req, 0, EGGSFS_SHUCKLE_INFO); + int written_so_far; + for (written_so_far = 0; written_so_far < sizeof(shuckle_req);) { + iov.iov_base = shuckle_req + written_so_far; + iov.iov_len = sizeof(shuckle_req) - written_so_far; + int written = kernel_sendmsg(shuckle_sock, &msg, &iov, 1, iov.iov_len); + if (written < 0) { err = written; goto out_sock; } + written_so_far += written; + } + + char shuckle_resp_header[EGGSFS_SHUCKLE_RESP_HEADER_SIZE]; + int read_so_far; + for (read_so_far = 0; read_so_far < sizeof(shuckle_resp_header);) { + iov.iov_base = shuckle_resp_header + read_so_far; + iov.iov_len = sizeof(shuckle_resp_header) - read_so_far; + int read = kernel_recvmsg(shuckle_sock, &msg, &iov, 1, iov.iov_len, 0); + if (read < 0) { err = read; goto out_sock; } + read_so_far += read; + } + u32 shuckle_resp_len; + u8 shuckle_resp_kind; + err = eggsfs_read_shuckle_resp_header(shuckle_resp_header, &shuckle_resp_len, &shuckle_resp_kind); + if (err < 0) { goto out_sock; } + if (shuckle_resp_len != EGGSFS_INFO_RESP_SIZE) { + eggsfs_debug_print("expected size of %d, got %d", EGGSFS_INFO_RESP_SIZE, shuckle_resp_len); + err = -EINVAL; goto out_sock; + } + char shuckle_resp[EGGSFS_INFO_RESP_SIZE]; + for (read_so_far = 0; read_so_far < sizeof(shuckle_resp);) { + iov.iov_base = (char*)&shuckle_resp + read_so_far; + iov.iov_len = sizeof(shuckle_resp) - read_so_far; + int read = kernel_recvmsg(shuckle_sock, &msg, &iov, 1, iov.iov_len, 0); + if (read < 0) { err = read; goto out_sock; } + read_so_far += read; + } + struct eggsfs_bincode_get_ctx ctx = { + .buf = shuckle_resp, + .end = shuckle_resp + sizeof(shuckle_resp), + .err = 0, + }; + eggsfs_info_resp_get_start(&ctx, start); + eggsfs_info_resp_get_num_block_services(&ctx, start, num_block_services); + eggsfs_info_resp_get_num_failure_domains(&ctx, num_block_services, num_failure_domains); + eggsfs_info_resp_get_capacity(&ctx, num_failure_domains, capacity); + eggsfs_info_resp_get_available(&ctx, capacity, available); + eggsfs_info_resp_get_blocks(&ctx, available, blocks); + eggsfs_info_resp_get_end(&ctx, blocks, end); + eggsfs_info_resp_get_finish(&ctx, end); + if (ctx.err != 0) { err = eggsfs_error_to_linux(ctx.err); goto out_sock; } + + stats->f_type = EGGSFS_SUPER_MAGIC; + stats->f_bsize = PAGE_SIZE; + stats->f_frsize = PAGE_SIZE; + stats->f_blocks = capacity.x / PAGE_SIZE; + stats->f_bfree = available.x / PAGE_SIZE; + stats->f_bavail = available.x / PAGE_SIZE; + stats->f_files = -1; + stats->f_ffree = -1; + stats->f_namelen = EGGSFS_MAX_FILENAME; + + sock_release(shuckle_sock); + return 0; + +out_sock: + sock_release(shuckle_sock); + return err; +} + static const struct super_operations eggsfs_super_ops = { .alloc_inode = eggsfs_inode_alloc, .evict_inode = eggsfs_inode_evict, .free_inode = eggsfs_inode_free, .put_super = eggsfs_put_super, + + .statfs = eggsfs_statfs, }; static struct dentry* eggsfs_mount(struct file_system_type* fs_type, int flags, const char* dev_name, void* data) { diff --git a/kmod/super.h b/kmod/super.h index cf9f7bc6..d2dbc9ae 100644 --- a/kmod/super.h +++ b/kmod/super.h @@ -6,6 +6,8 @@ #include "net.h" struct eggsfs_fs_info { + struct sockaddr_in shuckle_addr; + struct eggsfs_shard_socket sock; // NB: ->msg_iter is used by `kernel_sendmsg`, so when you want to use the `struct msghhdr`