diff options
Diffstat (limited to 'src/messages/MClientReply.h')
-rw-r--r-- | src/messages/MClientReply.h | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/src/messages/MClientReply.h b/src/messages/MClientReply.h new file mode 100644 index 000000000..be33fad49 --- /dev/null +++ b/src/messages/MClientReply.h @@ -0,0 +1,425 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net> + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + + +#ifndef CEPH_MCLIENTREPLY_H +#define CEPH_MCLIENTREPLY_H + +#include "include/types.h" +#include "include/fs_types.h" +#include "include/mempool.h" +#include "MClientRequest.h" + +#include "msg/Message.h" +#include "include/ceph_features.h" +#include "common/errno.h" +#include "common/strescape.h" + +/*** + * + * MClientReply - container message for MDS reply to a client's MClientRequest + * + * key fields: + * long tid - transaction id, so the client can match up with pending request + * int result - error code, or fh if it was open + * + * for most requests: + * trace is a vector of InodeStat's tracing from root to the file/dir/whatever + * the operation referred to, so that the client can update it's info about what + * metadata lives on what MDS. + * + * for readdir replies: + * dir_contents is a vector of InodeStat*'s. + * + * that's mostly it, i think! + * + */ + + +struct LeaseStat { + // this matches ceph_mds_reply_lease + __u16 mask = 0; + __u32 duration_ms = 0; + __u32 seq = 0; + std::string alternate_name; + + LeaseStat() = default; + LeaseStat(__u16 msk, __u32 dur, __u32 sq) : mask{msk}, duration_ms{dur}, seq{sq} {} + + void decode(ceph::buffer::list::const_iterator &bl, const uint64_t features) { + using ceph::decode; + if (features == (uint64_t)-1) { + DECODE_START(2, bl); + decode(mask, bl); + decode(duration_ms, bl); + decode(seq, bl); + if (struct_v >= 2) + decode(alternate_name, bl); + DECODE_FINISH(bl); + } + else { + decode(mask, bl); + decode(duration_ms, bl); + decode(seq, bl); + } + } +}; + +inline std::ostream& operator<<(std::ostream& out, const LeaseStat& l) { + out << "lease(mask " << l.mask << " dur " << l.duration_ms; + if (l.alternate_name.size()) { + out << " altn " << binstrprint(l.alternate_name, 128) << ")"; + } + return out << ")"; +} + +struct DirStat { + // mds distribution hints + frag_t frag; + __s32 auth; + std::set<__s32> dist; + + DirStat() : auth(CDIR_AUTH_PARENT) {} + DirStat(ceph::buffer::list::const_iterator& p, const uint64_t features) { + decode(p, features); + } + + void decode(ceph::buffer::list::const_iterator& p, const uint64_t features) { + using ceph::decode; + if (features == (uint64_t)-1) { + DECODE_START(1, p); + decode(frag, p); + decode(auth, p); + decode(dist, p); + DECODE_FINISH(p); + } + else { + decode(frag, p); + decode(auth, p); + decode(dist, p); + } + } + + // see CDir::encode_dirstat for encoder. +}; + +struct InodeStat { + vinodeno_t vino; + uint32_t rdev = 0; + version_t version = 0; + version_t xattr_version = 0; + ceph_mds_reply_cap cap; + file_layout_t layout; + utime_t ctime, btime, mtime, atime, snap_btime; + uint32_t time_warp_seq = 0; + uint64_t size = 0, max_size = 0; + uint64_t change_attr = 0; + uint64_t truncate_size = 0; + uint32_t truncate_seq = 0; + uint32_t mode = 0, uid = 0, gid = 0, nlink = 0; + frag_info_t dirstat; + nest_info_t rstat; + + fragtree_t dirfragtree; + std::string symlink; // symlink content (if symlink) + + ceph_dir_layout dir_layout; + + ceph::buffer::list xattrbl; + + ceph::buffer::list inline_data; + version_t inline_version; + + quota_info_t quota; + + mds_rank_t dir_pin; + std::map<std::string,std::string> snap_metadata; + + std::vector<uint8_t> fscrypt_auth; + std::vector<uint8_t> fscrypt_file; + + public: + InodeStat() {} + InodeStat(ceph::buffer::list::const_iterator& p, const uint64_t features) { + decode(p, features); + } + + void decode(ceph::buffer::list::const_iterator &p, const uint64_t features) { + using ceph::decode; + if (features == (uint64_t)-1) { + DECODE_START(7, p); + decode(vino.ino, p); + decode(vino.snapid, p); + decode(rdev, p); + decode(version, p); + decode(xattr_version, p); + decode(cap, p); + { + ceph_file_layout legacy_layout; + decode(legacy_layout, p); + layout.from_legacy(legacy_layout); + } + decode(ctime, p); + decode(mtime, p); + decode(atime, p); + decode(time_warp_seq, p); + decode(size, p); + decode(max_size, p); + decode(truncate_size, p); + decode(truncate_seq, p); + decode(mode, p); + decode(uid, p); + decode(gid, p); + decode(nlink, p); + decode(dirstat.nfiles, p); + decode(dirstat.nsubdirs, p); + decode(rstat.rbytes, p); + decode(rstat.rfiles, p); + decode(rstat.rsubdirs, p); + decode(rstat.rctime, p); + decode(dirfragtree, p); + decode(symlink, p); + decode(dir_layout, p); + decode(xattrbl, p); + decode(inline_version, p); + decode(inline_data, p); + decode(quota, p); + decode(layout.pool_ns, p); + decode(btime, p); + decode(change_attr, p); + if (struct_v > 1) { + decode(dir_pin, p); + } else { + dir_pin = -ENODATA; + } + if (struct_v >= 3) { + decode(snap_btime, p); + } // else remains zero + if (struct_v >= 4) { + decode(rstat.rsnaps, p); + } // else remains zero + if (struct_v >= 5) { + decode(snap_metadata, p); + } + if (struct_v >= 6) { + bool fscrypt_flag; + + decode(fscrypt_flag, p); // ignore this + } + if (struct_v >= 7) { + decode(fscrypt_auth, p); + decode(fscrypt_file, p); + } + DECODE_FINISH(p); + } + else { + decode(vino.ino, p); + decode(vino.snapid, p); + decode(rdev, p); + decode(version, p); + decode(xattr_version, p); + decode(cap, p); + { + ceph_file_layout legacy_layout; + decode(legacy_layout, p); + layout.from_legacy(legacy_layout); + } + decode(ctime, p); + decode(mtime, p); + decode(atime, p); + decode(time_warp_seq, p); + decode(size, p); + decode(max_size, p); + decode(truncate_size, p); + decode(truncate_seq, p); + decode(mode, p); + decode(uid, p); + decode(gid, p); + decode(nlink, p); + decode(dirstat.nfiles, p); + decode(dirstat.nsubdirs, p); + decode(rstat.rbytes, p); + decode(rstat.rfiles, p); + decode(rstat.rsubdirs, p); + decode(rstat.rctime, p); + decode(dirfragtree, p); + decode(symlink, p); + if (features & CEPH_FEATURE_DIRLAYOUTHASH) + decode(dir_layout, p); + else + memset(&dir_layout, 0, sizeof(dir_layout)); + + decode(xattrbl, p); + + if (features & CEPH_FEATURE_MDS_INLINE_DATA) { + decode(inline_version, p); + decode(inline_data, p); + } else { + inline_version = CEPH_INLINE_NONE; + } + + if (features & CEPH_FEATURE_MDS_QUOTA) + decode(quota, p); + else + quota = quota_info_t{}; + + if ((features & CEPH_FEATURE_FS_FILE_LAYOUT_V2)) + decode(layout.pool_ns, p); + + if ((features & CEPH_FEATURE_FS_BTIME)) { + decode(btime, p); + decode(change_attr, p); + } else { + btime = utime_t(); + change_attr = 0; + } + } + } + + // see CInode::encode_inodestat for encoder. +}; + +struct openc_response_t { + _inodeno_t created_ino; + interval_set<inodeno_t> delegated_inos; + +public: + void encode(ceph::buffer::list& bl) const { + using ceph::encode; + ENCODE_START(1, 1, bl); + encode(created_ino, bl); + encode(delegated_inos, bl); + ENCODE_FINISH(bl); + } + void decode(ceph::buffer::list::const_iterator &p) { + using ceph::decode; + DECODE_START(1, p); + decode(created_ino, p); + decode(delegated_inos, p); + DECODE_FINISH(p); + } +} __attribute__ ((__may_alias__)); +WRITE_CLASS_ENCODER(openc_response_t) + +class MClientReply final : public MMDSOp { +public: + // reply data + struct ceph_mds_reply_head head {}; + ceph::buffer::list trace_bl; + ceph::buffer::list extra_bl; + ceph::buffer::list snapbl; + + int get_op() const { return head.op; } + + void set_mdsmap_epoch(epoch_t e) { head.mdsmap_epoch = e; } + epoch_t get_mdsmap_epoch() const { return head.mdsmap_epoch; } + + int get_result() const { + #ifdef _WIN32 + // libclient and libcephfs return CEPHFS_E* errors, which are basically + // Linux errno codes. If we convert mds errors to host errno values, we + // end up mixing error codes. + // + // For Windows, we'll preserve the original error value, which is expected + // to be a linux (CEPHFS_E*) error. It may be worth doing the same for + // other platforms. + return head.result; + #else + return ceph_to_hostos_errno((__s32)(__u32)head.result); + #endif + } + + void set_result(int r) { head.result = r; } + + void set_unsafe() { head.safe = 0; } + + bool is_safe() const { return head.safe; } + +protected: + MClientReply() : MMDSOp{CEPH_MSG_CLIENT_REPLY} {} + MClientReply(const MClientRequest &req, int result = 0) : + MMDSOp{CEPH_MSG_CLIENT_REPLY} { + memset(&head, 0, sizeof(head)); + header.tid = req.get_tid(); + head.op = req.get_op(); + head.result = result; + head.safe = 1; + } + ~MClientReply() final {} + +public: + std::string_view get_type_name() const override { return "creply"; } + void print(std::ostream& o) const override { + o << "client_reply(???:" << get_tid(); + o << " = " << get_result(); + if (get_result() <= 0) { + o << " " << cpp_strerror(get_result()); + } + if (head.op & CEPH_MDS_OP_WRITE) { + if (head.safe) + o << " safe"; + else + o << " unsafe"; + } + o << ")"; + } + + // serialization + void decode_payload() override { + using ceph::decode; + auto p = payload.cbegin(); + decode(head, p); + decode(trace_bl, p); + decode(extra_bl, p); + decode(snapbl, p); + ceph_assert(p.end()); + } + void encode_payload(uint64_t features) override { + using ceph::encode; + encode(head, payload); + encode(trace_bl, payload); + encode(extra_bl, payload); + encode(snapbl, payload); + } + + + // dir contents + void set_extra_bl(ceph::buffer::list& bl) { + extra_bl = std::move(bl); + } + ceph::buffer::list& get_extra_bl() { + return extra_bl; + } + const ceph::buffer::list& get_extra_bl() const { + return extra_bl; + } + + // trace + void set_trace(ceph::buffer::list& bl) { + trace_bl = std::move(bl); + } + ceph::buffer::list& get_trace_bl() { + return trace_bl; + } + const ceph::buffer::list& get_trace_bl() const { + return trace_bl; + } +private: + template<class T, typename... Args> + friend boost::intrusive_ptr<T> ceph::make_message(Args&&... args); + template<class T, typename... Args> + friend MURef<T> crimson::make_message(Args&&... args); +}; + +#endif |