From 4cc3d626ee3d9129716642b6c3a7dcb56a58b1fc Mon Sep 17 00:00:00 2001 From: dparmar18 Date: Tue, 17 May 2022 11:49:35 +0530 Subject: [PATCH 1/2] mds: split up mdstypes mdstypes.h contains both MDS-exclusive and client-shared structs. This PR splits it up into "mdstypes.h" and "sharedtypes.h". Fixes: https://tracker.ceph.com/issues/3998 Signed-off-by: Dhairya Parmar --- src/client/Client.h | 1 + src/client/Inode.h | 1 + src/include/cephfs/types.h | 956 ++++++++++++++++++++++++++++ src/mds/mdstypes.cc | 1 + src/mds/mdstypes.h | 913 +------------------------- src/tools/ceph-dencoder/mds_types.h | 1 + 6 files changed, 961 insertions(+), 912 deletions(-) create mode 100644 src/include/cephfs/types.h diff --git a/src/client/Client.h b/src/client/Client.h index d888e74d9dd6e..fae1a2ff17610 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -32,6 +32,7 @@ #include "include/unordered_set.h" #include "include/cephfs/metrics/Types.h" #include "mds/mdstypes.h" +#include "include/cephfs/types.h" #include "msg/Dispatcher.h" #include "msg/MessageRef.h" #include "msg/Messenger.h" diff --git a/src/client/Inode.h b/src/client/Inode.h index f5db5d7a905e1..f7aed860b74ca 100644 --- a/src/client/Inode.h +++ b/src/client/Inode.h @@ -13,6 +13,7 @@ #include "mds/flock.h" #include "mds/mdstypes.h" // hrm +#include "include/cephfs/types.h" #include "osdc/ObjectCacher.h" diff --git a/src/include/cephfs/types.h b/src/include/cephfs/types.h new file mode 100644 index 0000000000000..92cb3acb468d0 --- /dev/null +++ b/src/include/cephfs/types.h @@ -0,0 +1,956 @@ +// -*- 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) 2020 Red Hat, Inc. + * + * 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_CEPHFS_TYPES_H +#define CEPH_CEPHFS_TYPES_H +#include "include/int_types.h" + +#include +#include +#include +#include + +#include "common/config.h" +#include "common/Clock.h" +#include "common/DecayCounter.h" +#include "common/StackStringStream.h" +#include "common/entity_name.h" + +#include "include/compat.h" +#include "include/Context.h" +#include "include/frag.h" +#include "include/xlist.h" +#include "include/interval_set.h" +#include "include/compact_set.h" +#include "include/fs_types.h" +#include "include/ceph_fs.h" + +#include "mds/inode_backtrace.h" + +#include +#include +#include "include/ceph_assert.h" +#include +#include "common/ceph_json.h" + +#define CEPH_FS_ONDISK_MAGIC "ceph fs volume v011" +#define MAX_MDS 0x100 + +BOOST_STRONG_TYPEDEF(uint64_t, mds_gid_t) +extern const mds_gid_t MDS_GID_NONE; + +typedef int32_t fs_cluster_id_t; +constexpr fs_cluster_id_t FS_CLUSTER_ID_NONE = -1; + +// The namespace ID of the anonymous default filesystem from legacy systems +constexpr fs_cluster_id_t FS_CLUSTER_ID_ANONYMOUS = 0; + +typedef int32_t mds_rank_t; +constexpr mds_rank_t MDS_RANK_NONE = -1; +constexpr mds_rank_t MDS_RANK_EPHEMERAL_DIST = -2; +constexpr mds_rank_t MDS_RANK_EPHEMERAL_RAND = -3; + +struct scatter_info_t { + version_t version = 0; +}; + +struct frag_info_t : public scatter_info_t { + int64_t size() const { return nfiles + nsubdirs; } + + void zero() { + *this = frag_info_t(); + } + + // *this += cur - acc; + void add_delta(const frag_info_t &cur, const frag_info_t &acc, bool *touched_mtime=0, bool *touched_chattr=0) { + if (cur.mtime > mtime) { + mtime = cur.mtime; + if (touched_mtime) + *touched_mtime = true; + } + if (cur.change_attr > change_attr) { + change_attr = cur.change_attr; + if (touched_chattr) + *touched_chattr = true; + } + nfiles += cur.nfiles - acc.nfiles; + nsubdirs += cur.nsubdirs - acc.nsubdirs; + } + + void add(const frag_info_t& other) { + if (other.mtime > mtime) + mtime = other.mtime; + if (other.change_attr > change_attr) + change_attr = other.change_attr; + nfiles += other.nfiles; + nsubdirs += other.nsubdirs; + } + + bool same_sums(const frag_info_t &o) const { + return mtime <= o.mtime && + nfiles == o.nfiles && + nsubdirs == o.nsubdirs; + } + + void encode(ceph::buffer::list &bl) const; + void decode(ceph::buffer::list::const_iterator& bl); + void dump(ceph::Formatter *f) const; + void decode_json(JSONObj *obj); + static void generate_test_instances(std::list& ls); + + // this frag + utime_t mtime; + uint64_t change_attr = 0; + int64_t nfiles = 0; // files + int64_t nsubdirs = 0; // subdirs +}; +WRITE_CLASS_ENCODER(frag_info_t) + +inline bool operator==(const frag_info_t &l, const frag_info_t &r) { + return memcmp(&l, &r, sizeof(l)) == 0; +} +inline bool operator!=(const frag_info_t &l, const frag_info_t &r) { + return !(l == r); +} + +std::ostream& operator<<(std::ostream &out, const frag_info_t &f); + +struct nest_info_t : public scatter_info_t { + int64_t rsize() const { return rfiles + rsubdirs; } + + void zero() { + *this = nest_info_t(); + } + + void sub(const nest_info_t &other) { + add(other, -1); + } + void add(const nest_info_t &other, int fac=1) { + if (other.rctime > rctime) + rctime = other.rctime; + rbytes += fac*other.rbytes; + rfiles += fac*other.rfiles; + rsubdirs += fac*other.rsubdirs; + rsnaps += fac*other.rsnaps; + } + + // *this += cur - acc; + void add_delta(const nest_info_t &cur, const nest_info_t &acc) { + if (cur.rctime > rctime) + rctime = cur.rctime; + rbytes += cur.rbytes - acc.rbytes; + rfiles += cur.rfiles - acc.rfiles; + rsubdirs += cur.rsubdirs - acc.rsubdirs; + rsnaps += cur.rsnaps - acc.rsnaps; + } + + bool same_sums(const nest_info_t &o) const { + return rctime <= o.rctime && + rbytes == o.rbytes && + rfiles == o.rfiles && + rsubdirs == o.rsubdirs && + rsnaps == o.rsnaps; + } + + void encode(ceph::buffer::list &bl) const; + void decode(ceph::buffer::list::const_iterator& bl); + void dump(ceph::Formatter *f) const; + void decode_json(JSONObj *obj); + static void generate_test_instances(std::list& ls); + + // this frag + children + utime_t rctime; + int64_t rbytes = 0; + int64_t rfiles = 0; + int64_t rsubdirs = 0; + int64_t rsnaps = 0; +}; +WRITE_CLASS_ENCODER(nest_info_t) + +inline bool operator==(const nest_info_t &l, const nest_info_t &r) { + return memcmp(&l, &r, sizeof(l)) == 0; +} +inline bool operator!=(const nest_info_t &l, const nest_info_t &r) { + return !(l == r); +} + +std::ostream& operator<<(std::ostream &out, const nest_info_t &n); + +struct vinodeno_t { + vinodeno_t() {} + vinodeno_t(inodeno_t i, snapid_t s) : ino(i), snapid(s) {} + + void encode(ceph::buffer::list& bl) const { + using ceph::encode; + encode(ino, bl); + encode(snapid, bl); + } + void decode(ceph::buffer::list::const_iterator& p) { + using ceph::decode; + decode(ino, p); + decode(snapid, p); + } + + inodeno_t ino; + snapid_t snapid; +}; +WRITE_CLASS_ENCODER(vinodeno_t) + +inline bool operator==(const vinodeno_t &l, const vinodeno_t &r) { + return l.ino == r.ino && l.snapid == r.snapid; +} +inline bool operator!=(const vinodeno_t &l, const vinodeno_t &r) { + return !(l == r); +} +inline bool operator<(const vinodeno_t &l, const vinodeno_t &r) { + return + l.ino < r.ino || + (l.ino == r.ino && l.snapid < r.snapid); +} + +struct quota_info_t +{ + void encode(ceph::buffer::list& bl) const { + ENCODE_START(1, 1, bl); + encode(max_bytes, bl); + encode(max_files, bl); + ENCODE_FINISH(bl); + } + void decode(ceph::buffer::list::const_iterator& p) { + DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, p); + decode(max_bytes, p); + decode(max_files, p); + DECODE_FINISH(p); + } + + void dump(ceph::Formatter *f) const; + static void generate_test_instances(std::list& ls); + + bool is_valid() const { + return max_bytes >=0 && max_files >=0; + } + bool is_enable() const { + return max_bytes || max_files; + } + void decode_json(JSONObj *obj); + + int64_t max_bytes = 0; + int64_t max_files = 0; +}; +WRITE_CLASS_ENCODER(quota_info_t) + +inline bool operator==(const quota_info_t &l, const quota_info_t &r) { + return memcmp(&l, &r, sizeof(l)) == 0; +} + +std::ostream& operator<<(std::ostream &out, const quota_info_t &n); + +struct client_writeable_range_t { + struct byte_range_t { + uint64_t first = 0, last = 0; // interval client can write to + byte_range_t() {} + void decode_json(JSONObj *obj); + }; + + void encode(ceph::buffer::list &bl) const; + void decode(ceph::buffer::list::const_iterator& bl); + void dump(ceph::Formatter *f) const; + static void generate_test_instances(std::list& ls); + + byte_range_t range; + snapid_t follows = 0; // aka "data+metadata flushed thru" +}; + +inline void decode(client_writeable_range_t::byte_range_t& range, ceph::buffer::list::const_iterator& bl) { + using ceph::decode; + decode(range.first, bl); + decode(range.last, bl); +} + +WRITE_CLASS_ENCODER(client_writeable_range_t) + +std::ostream& operator<<(std::ostream& out, const client_writeable_range_t& r); + +inline bool operator==(const client_writeable_range_t& l, + const client_writeable_range_t& r) { + return l.range.first == r.range.first && l.range.last == r.range.last && + l.follows == r.follows; +} + +struct inline_data_t { +public: + inline_data_t() {} + inline_data_t(const inline_data_t& o) : version(o.version) { + if (o.blp) + set_data(*o.blp); + } + inline_data_t& operator=(const inline_data_t& o) { + version = o.version; + if (o.blp) + set_data(*o.blp); + else + free_data(); + return *this; + } + + void free_data() { + blp.reset(); + } + void get_data(ceph::buffer::list& ret) const { + if (blp) + ret = *blp; + else + ret.clear(); + } + void set_data(const ceph::buffer::list& bl) { + if (!blp) + blp.reset(new ceph::buffer::list); + *blp = bl; + } + size_t length() const { return blp ? blp->length() : 0; } + + bool operator==(const inline_data_t& o) const { + return length() == o.length() && + (length() == 0 || + (*const_cast(blp.get()) == *const_cast(o.blp.get()))); + } + bool operator!=(const inline_data_t& o) const { + return !(*this == o); + } + void encode(ceph::buffer::list &bl) const; + void decode(ceph::buffer::list::const_iterator& bl); + + version_t version = 1; + +private: + std::unique_ptr blp; +}; +WRITE_CLASS_ENCODER(inline_data_t) + +enum { + DAMAGE_STATS, // statistics (dirstat, size, etc) + DAMAGE_RSTATS, // recursive statistics (rstat, accounted_rstat) + DAMAGE_FRAGTREE // fragtree -- repair by searching +}; + +template class Allocator = std::allocator> +struct inode_t { + /** + * *************** + * Do not forget to add any new fields to the compare() function. + * *************** + */ + using client_range_map = std::map,Allocator>>; + + inode_t() + { + clear_layout(); + } + + // file type + bool is_symlink() const { return (mode & S_IFMT) == S_IFLNK; } + bool is_dir() const { return (mode & S_IFMT) == S_IFDIR; } + bool is_file() const { return (mode & S_IFMT) == S_IFREG; } + + bool is_truncating() const { return (truncate_pending > 0); } + void truncate(uint64_t old_size, uint64_t new_size, const bufferlist &fbl) { + truncate(old_size, new_size); + fscrypt_last_block = fbl; + } + void truncate(uint64_t old_size, uint64_t new_size) { + ceph_assert(new_size <= old_size); + if (old_size > max_size_ever) + max_size_ever = old_size; + truncate_from = old_size; + size = new_size; + rstat.rbytes = new_size; + truncate_size = size; + truncate_seq++; + truncate_pending++; + } + + bool has_layout() const { + return layout != file_layout_t(); + } + + void clear_layout() { + layout = file_layout_t(); + } + + uint64_t get_layout_size_increment() const { + return layout.get_period(); + } + + bool is_dirty_rstat() const { return !(rstat == accounted_rstat); } + + uint64_t get_client_range(client_t client) const { + auto it = client_ranges.find(client); + return it != client_ranges.end() ? it->second.range.last : 0; + } + + uint64_t get_max_size() const { + uint64_t max = 0; + for (std::map::const_iterator p = client_ranges.begin(); + p != client_ranges.end(); + ++p) + if (p->second.range.last > max) + max = p->second.range.last; + return max; + } + void set_max_size(uint64_t new_max) { + if (new_max == 0) { + client_ranges.clear(); + } else { + for (std::map::iterator p = client_ranges.begin(); + p != client_ranges.end(); + ++p) + p->second.range.last = new_max; + } + } + + void trim_client_ranges(snapid_t last) { + std::map::iterator p = client_ranges.begin(); + while (p != client_ranges.end()) { + if (p->second.follows >= last) + client_ranges.erase(p++); + else + ++p; + } + } + + bool is_backtrace_updated() const { + return backtrace_version == version; + } + void update_backtrace(version_t pv=0) { + backtrace_version = pv ? pv : version; + } + + void add_old_pool(int64_t l) { + backtrace_version = version; + old_pools.insert(l); + } + + void encode(ceph::buffer::list &bl, uint64_t features) const; + void decode(ceph::buffer::list::const_iterator& bl); + void dump(ceph::Formatter *f) const; + static void client_ranges_cb(client_range_map& c, JSONObj *obj); + static void old_pools_cb(compact_set, Allocator >& c, JSONObj *obj); + void decode_json(JSONObj *obj); + static void generate_test_instances(std::list& ls); + /** + * Compare this inode_t with another that represent *the same inode* + * at different points in time. + * @pre The inodes are the same ino + * + * @param other The inode_t to compare ourselves with + * @param divergent A bool pointer which will be set to true + * if the values are different in a way that can't be explained + * by one being a newer version than the other. + * + * @returns 1 if we are newer than the other, 0 if equal, -1 if older. + */ + int compare(const inode_t &other, bool *divergent) const; + + // base (immutable) + inodeno_t ino = 0; + uint32_t rdev = 0; // if special file + + // affected by any inode change... + utime_t ctime; // inode change time + utime_t btime; // birth time + + // perm (namespace permissions) + uint32_t mode = 0; + uid_t uid = 0; + gid_t gid = 0; + + // nlink + int32_t nlink = 0; + + // file (data access) + ceph_dir_layout dir_layout = {}; // [dir only] + file_layout_t layout; + compact_set, Allocator> old_pools; + uint64_t size = 0; // on directory, # dentries + uint64_t max_size_ever = 0; // max size the file has ever been + uint32_t truncate_seq = 0; + uint64_t truncate_size = 0, truncate_from = 0; + uint32_t truncate_pending = 0; + utime_t mtime; // file data modify time. + utime_t atime; // file data access time. + uint32_t time_warp_seq = 0; // count of (potential) mtime/atime timewarps (i.e., utimes()) + inline_data_t inline_data; // FIXME check + + // change attribute + uint64_t change_attr = 0; + + client_range_map client_ranges; // client(s) can write to these ranges + + // dirfrag, recursive accountin + frag_info_t dirstat; // protected by my filelock + nest_info_t rstat; // protected by my nestlock + nest_info_t accounted_rstat; // protected by parent's nestlock + + quota_info_t quota; + + mds_rank_t export_pin = MDS_RANK_NONE; + + double export_ephemeral_random_pin = 0; + bool export_ephemeral_distributed_pin = false; + + // special stuff + version_t version = 0; // auth only + version_t file_data_version = 0; // auth only + version_t xattr_version = 0; + + utime_t last_scrub_stamp; // start time of last complete scrub + version_t last_scrub_version = 0;// (parent) start version of last complete scrub + + version_t backtrace_version = 0; + + snapid_t oldest_snap; + + std::basic_string,Allocator> stray_prior_path; //stores path before unlink + + std::vector fscrypt_auth; + std::vector fscrypt_file; + + bufferlist fscrypt_last_block; + +private: + bool older_is_consistent(const inode_t &other) const; +}; + +// These methods may be moved back to mdstypes.cc when we have pmr +template class Allocator> +void inode_t::encode(ceph::buffer::list &bl, uint64_t features) const +{ + ENCODE_START(19, 6, bl); + + encode(ino, bl); + encode(rdev, bl); + encode(ctime, bl); + + encode(mode, bl); + encode(uid, bl); + encode(gid, bl); + + encode(nlink, bl); + { + // removed field + bool anchored = 0; + encode(anchored, bl); + } + + encode(dir_layout, bl); + encode(layout, bl, features); + encode(size, bl); + encode(truncate_seq, bl); + encode(truncate_size, bl); + encode(truncate_from, bl); + encode(truncate_pending, bl); + encode(mtime, bl); + encode(atime, bl); + encode(time_warp_seq, bl); + encode(client_ranges, bl); + + encode(dirstat, bl); + encode(rstat, bl); + encode(accounted_rstat, bl); + + encode(version, bl); + encode(file_data_version, bl); + encode(xattr_version, bl); + encode(backtrace_version, bl); + encode(old_pools, bl); + encode(max_size_ever, bl); + encode(inline_data, bl); + encode(quota, bl); + + encode(stray_prior_path, bl); + + encode(last_scrub_version, bl); + encode(last_scrub_stamp, bl); + + encode(btime, bl); + encode(change_attr, bl); + + encode(export_pin, bl); + + encode(export_ephemeral_random_pin, bl); + encode(export_ephemeral_distributed_pin, bl); + + encode(!fscrypt_auth.empty(), bl); + encode(fscrypt_auth, bl); + encode(fscrypt_file, bl); + encode(fscrypt_last_block, bl); + ENCODE_FINISH(bl); +} + +template class Allocator> +void inode_t::decode(ceph::buffer::list::const_iterator &p) +{ + DECODE_START_LEGACY_COMPAT_LEN(19, 6, 6, p); + + decode(ino, p); + decode(rdev, p); + decode(ctime, p); + + decode(mode, p); + decode(uid, p); + decode(gid, p); + + decode(nlink, p); + { + bool anchored; + decode(anchored, p); + } + + if (struct_v >= 4) + decode(dir_layout, p); + else { + // FIPS zeroization audit 20191117: this memset is not security related. + memset(&dir_layout, 0, sizeof(dir_layout)); + } + decode(layout, p); + decode(size, p); + decode(truncate_seq, p); + decode(truncate_size, p); + decode(truncate_from, p); + if (struct_v >= 5) + decode(truncate_pending, p); + else + truncate_pending = 0; + decode(mtime, p); + decode(atime, p); + decode(time_warp_seq, p); + if (struct_v >= 3) { + decode(client_ranges, p); + } else { + std::map m; + decode(m, p); + for (auto q = m.begin(); q != m.end(); ++q) + client_ranges[q->first].range = q->second; + } + + decode(dirstat, p); + decode(rstat, p); + decode(accounted_rstat, p); + + decode(version, p); + decode(file_data_version, p); + decode(xattr_version, p); + if (struct_v >= 2) + decode(backtrace_version, p); + if (struct_v >= 7) + decode(old_pools, p); + if (struct_v >= 8) + decode(max_size_ever, p); + if (struct_v >= 9) { + decode(inline_data, p); + } else { + inline_data.version = CEPH_INLINE_NONE; + } + if (struct_v < 10) + backtrace_version = 0; // force update backtrace + if (struct_v >= 11) + decode(quota, p); + + if (struct_v >= 12) { + std::string tmp; + decode(tmp, p); + stray_prior_path = std::string_view(tmp); + } + + if (struct_v >= 13) { + decode(last_scrub_version, p); + decode(last_scrub_stamp, p); + } + if (struct_v >= 14) { + decode(btime, p); + decode(change_attr, p); + } else { + btime = utime_t(); + change_attr = 0; + } + + if (struct_v >= 15) { + decode(export_pin, p); + } else { + export_pin = MDS_RANK_NONE; + } + + if (struct_v >= 16) { + decode(export_ephemeral_random_pin, p); + decode(export_ephemeral_distributed_pin, p); + } else { + export_ephemeral_random_pin = 0; + export_ephemeral_distributed_pin = false; + } + + if (struct_v >= 17) { + bool fscrypt_flag; + decode(fscrypt_flag, p); // ignored + } + + if (struct_v >= 18) { + decode(fscrypt_auth, p); + decode(fscrypt_file, p); + } + + if (struct_v >= 19) { + decode(fscrypt_last_block, p); + } + DECODE_FINISH(p); +} + +template class Allocator> +void inode_t::dump(ceph::Formatter *f) const +{ + f->dump_unsigned("ino", ino); + f->dump_unsigned("rdev", rdev); + f->dump_stream("ctime") << ctime; + f->dump_stream("btime") << btime; + f->dump_unsigned("mode", mode); + f->dump_unsigned("uid", uid); + f->dump_unsigned("gid", gid); + f->dump_unsigned("nlink", nlink); + + f->open_object_section("dir_layout"); + ::dump(dir_layout, f); + f->close_section(); + + f->dump_object("layout", layout); + + f->open_array_section("old_pools"); + for (const auto &p : old_pools) { + f->dump_int("pool", p); + } + f->close_section(); + + f->dump_unsigned("size", size); + f->dump_unsigned("truncate_seq", truncate_seq); + f->dump_unsigned("truncate_size", truncate_size); + f->dump_unsigned("truncate_from", truncate_from); + f->dump_unsigned("truncate_pending", truncate_pending); + f->dump_stream("mtime") << mtime; + f->dump_stream("atime") << atime; + f->dump_unsigned("time_warp_seq", time_warp_seq); + f->dump_unsigned("change_attr", change_attr); + f->dump_int("export_pin", export_pin); + f->dump_int("export_ephemeral_random_pin", export_ephemeral_random_pin); + f->dump_bool("export_ephemeral_distributed_pin", export_ephemeral_distributed_pin); + + f->open_array_section("client_ranges"); + for (const auto &p : client_ranges) { + f->open_object_section("client"); + f->dump_unsigned("client", p.first.v); + p.second.dump(f); + f->close_section(); + } + f->close_section(); + + f->open_object_section("dirstat"); + dirstat.dump(f); + f->close_section(); + + f->open_object_section("rstat"); + rstat.dump(f); + f->close_section(); + + f->open_object_section("accounted_rstat"); + accounted_rstat.dump(f); + f->close_section(); + + f->dump_unsigned("version", version); + f->dump_unsigned("file_data_version", file_data_version); + f->dump_unsigned("xattr_version", xattr_version); + f->dump_unsigned("backtrace_version", backtrace_version); + + f->dump_string("stray_prior_path", stray_prior_path); + f->dump_unsigned("max_size_ever", max_size_ever); + + f->open_object_section("quota"); + quota.dump(f); + f->close_section(); + + f->dump_stream("last_scrub_stamp") << last_scrub_stamp; + f->dump_unsigned("last_scrub_version", last_scrub_version); +} + +template class Allocator> +void inode_t::client_ranges_cb(typename inode_t::client_range_map& c, JSONObj *obj){ + + int64_t client; + JSONDecoder::decode_json("client", client, obj, true); + client_writeable_range_t client_range_tmp; + JSONDecoder::decode_json("byte range", client_range_tmp.range, obj, true); + JSONDecoder::decode_json("follows", client_range_tmp.follows.val, obj, true); + c[client] = client_range_tmp; +} + +template class Allocator> +void inode_t::old_pools_cb(compact_set, Allocator >& c, JSONObj *obj){ + + int64_t tmp; + decode_json_obj(tmp, obj); + c.insert(tmp); +} + +template class Allocator> +void inode_t::decode_json(JSONObj *obj) +{ + + JSONDecoder::decode_json("ino", ino.val, obj, true); + JSONDecoder::decode_json("rdev", rdev, obj, true); + //JSONDecoder::decode_json("ctime", ctime, obj, true); + //JSONDecoder::decode_json("btime", btime, obj, true); + JSONDecoder::decode_json("mode", mode, obj, true); + JSONDecoder::decode_json("uid", uid, obj, true); + JSONDecoder::decode_json("gid", gid, obj, true); + JSONDecoder::decode_json("nlink", nlink, obj, true); + JSONDecoder::decode_json("dir_layout", dir_layout, obj, true); + JSONDecoder::decode_json("layout", layout, obj, true); + JSONDecoder::decode_json("old_pools", old_pools, inode_t::old_pools_cb, obj, true); + JSONDecoder::decode_json("size", size, obj, true); + JSONDecoder::decode_json("truncate_seq", truncate_seq, obj, true); + JSONDecoder::decode_json("truncate_size", truncate_size, obj, true); + JSONDecoder::decode_json("truncate_from", truncate_from, obj, true); + JSONDecoder::decode_json("truncate_pending", truncate_pending, obj, true); + //JSONDecoder::decode_json("mtime", mtime, obj, true); + //JSONDecoder::decode_json("atime", atime, obj, true); + JSONDecoder::decode_json("time_warp_seq", time_warp_seq, obj, true); + JSONDecoder::decode_json("change_attr", change_attr, obj, true); + JSONDecoder::decode_json("export_pin", export_pin, obj, true); + JSONDecoder::decode_json("client_ranges", client_ranges, inode_t::client_ranges_cb, obj, true); + JSONDecoder::decode_json("dirstat", dirstat, obj, true); + JSONDecoder::decode_json("rstat", rstat, obj, true); + JSONDecoder::decode_json("accounted_rstat", accounted_rstat, obj, true); + JSONDecoder::decode_json("version", version, obj, true); + JSONDecoder::decode_json("file_data_version", file_data_version, obj, true); + JSONDecoder::decode_json("xattr_version", xattr_version, obj, true); + JSONDecoder::decode_json("backtrace_version", backtrace_version, obj, true); + JSONDecoder::decode_json("stray_prior_path", stray_prior_path, obj, true); + JSONDecoder::decode_json("max_size_ever", max_size_ever, obj, true); + JSONDecoder::decode_json("quota", quota, obj, true); + JSONDecoder::decode_json("last_scrub_stamp", last_scrub_stamp, obj, true); + JSONDecoder::decode_json("last_scrub_version", last_scrub_version, obj, true); +} + +template class Allocator> +void inode_t::generate_test_instances(std::list& ls) +{ + ls.push_back(new inode_t); + ls.push_back(new inode_t); + ls.back()->ino = 1; + // i am lazy. +} + +template class Allocator> +int inode_t::compare(const inode_t &other, bool *divergent) const +{ + ceph_assert(ino == other.ino); + *divergent = false; + if (version == other.version) { + if (rdev != other.rdev || + ctime != other.ctime || + btime != other.btime || + mode != other.mode || + uid != other.uid || + gid != other.gid || + nlink != other.nlink || + memcmp(&dir_layout, &other.dir_layout, sizeof(dir_layout)) || + layout != other.layout || + old_pools != other.old_pools || + size != other.size || + max_size_ever != other.max_size_ever || + truncate_seq != other.truncate_seq || + truncate_size != other.truncate_size || + truncate_from != other.truncate_from || + truncate_pending != other.truncate_pending || + change_attr != other.change_attr || + mtime != other.mtime || + atime != other.atime || + time_warp_seq != other.time_warp_seq || + inline_data != other.inline_data || + client_ranges != other.client_ranges || + !(dirstat == other.dirstat) || + !(rstat == other.rstat) || + !(accounted_rstat == other.accounted_rstat) || + file_data_version != other.file_data_version || + xattr_version != other.xattr_version || + backtrace_version != other.backtrace_version) { + *divergent = true; + } + return 0; + } else if (version > other.version) { + *divergent = !older_is_consistent(other); + return 1; + } else { + ceph_assert(version < other.version); + *divergent = !other.older_is_consistent(*this); + return -1; + } +} + +template class Allocator> +bool inode_t::older_is_consistent(const inode_t &other) const +{ + if (max_size_ever < other.max_size_ever || + truncate_seq < other.truncate_seq || + time_warp_seq < other.time_warp_seq || + inline_data.version < other.inline_data.version || + dirstat.version < other.dirstat.version || + rstat.version < other.rstat.version || + accounted_rstat.version < other.accounted_rstat.version || + file_data_version < other.file_data_version || + xattr_version < other.xattr_version || + backtrace_version < other.backtrace_version) { + return false; + } + return true; +} + +template class Allocator> +inline void encode(const inode_t &c, ::ceph::buffer::list &bl, uint64_t features) +{ + ENCODE_DUMP_PRE(); + c.encode(bl, features); + ENCODE_DUMP_POST(cl); +} +template class Allocator> +inline void decode(inode_t &c, ::ceph::buffer::list::const_iterator &p) +{ + c.decode(p); +} + +// parse a map of keys/values. +namespace qi = boost::spirit::qi; + +template +struct keys_and_values + : qi::grammar()> +{ + keys_and_values() + : keys_and_values::base_type(query) + { + query = pair >> *(qi::lit(' ') >> pair); + pair = key >> '=' >> value; + key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9"); + value = +qi::char_("a-zA-Z0-9-_."); + } + qi::rule()> query; + qi::rule()> pair; + qi::rule key, value; +}; + +#endif diff --git a/src/mds/mdstypes.cc b/src/mds/mdstypes.cc index 9d46c8d867924..d8b03915a0030 100644 --- a/src/mds/mdstypes.cc +++ b/src/mds/mdstypes.cc @@ -2,6 +2,7 @@ // vim: ts=8 sw=2 smarttab #include "mdstypes.h" +#include "include/cephfs/types.h" #include "MDSContext.h" #include "common/Formatter.h" #include "common/StackStringStream.h" diff --git a/src/mds/mdstypes.h b/src/mds/mdstypes.h index f6d9e524325f7..4d03c1523f3be 100644 --- a/src/mds/mdstypes.h +++ b/src/mds/mdstypes.h @@ -30,16 +30,13 @@ #include #include #include "include/ceph_assert.h" -#include #include "common/ceph_json.h" - -#define CEPH_FS_ONDISK_MAGIC "ceph fs volume v011" +#include "include/cephfs/types.h" #define MDS_PORT_CACHE 0x200 #define MDS_PORT_LOCKER 0x300 #define MDS_PORT_MIGRATOR 0x400 -#define MAX_MDS 0x100 #define NUM_STRAY 10 // Inode numbers 1,2 and 4 please see CEPH_INO_* in include/ceph_fs.h @@ -67,20 +64,6 @@ #define MDS_IS_PRIVATE_INO(i) ((i) < MDS_INO_SYSTEM_BASE && (i) >= MDS_INO_MDSDIR_OFFSET) -typedef int32_t mds_rank_t; -constexpr mds_rank_t MDS_RANK_NONE = -1; -constexpr mds_rank_t MDS_RANK_EPHEMERAL_DIST = -2; -constexpr mds_rank_t MDS_RANK_EPHEMERAL_RAND = -3; - -BOOST_STRONG_TYPEDEF(uint64_t, mds_gid_t) -extern const mds_gid_t MDS_GID_NONE; - -typedef int32_t fs_cluster_id_t; -constexpr fs_cluster_id_t FS_CLUSTER_ID_NONE = -1; - -// The namespace ID of the anonymous default filesystem from legacy systems -constexpr fs_cluster_id_t FS_CLUSTER_ID_ANONYMOUS = 0; - class mds_role_t { public: mds_role_t(fs_cluster_id_t fscid_, mds_rank_t rank_) @@ -145,202 +128,6 @@ inline std::string ccap_string(int cap) return s; } -struct scatter_info_t { - version_t version = 0; -}; - -struct frag_info_t : public scatter_info_t { - int64_t size() const { return nfiles + nsubdirs; } - - void zero() { - *this = frag_info_t(); - } - - // *this += cur - acc; - void add_delta(const frag_info_t &cur, const frag_info_t &acc, bool *touched_mtime=0, bool *touched_chattr=0) { - if (cur.mtime > mtime) { - mtime = cur.mtime; - if (touched_mtime) - *touched_mtime = true; - } - if (cur.change_attr > change_attr) { - change_attr = cur.change_attr; - if (touched_chattr) - *touched_chattr = true; - } - nfiles += cur.nfiles - acc.nfiles; - nsubdirs += cur.nsubdirs - acc.nsubdirs; - } - - void add(const frag_info_t& other) { - if (other.mtime > mtime) - mtime = other.mtime; - if (other.change_attr > change_attr) - change_attr = other.change_attr; - nfiles += other.nfiles; - nsubdirs += other.nsubdirs; - } - - bool same_sums(const frag_info_t &o) const { - return mtime <= o.mtime && - nfiles == o.nfiles && - nsubdirs == o.nsubdirs; - } - - void encode(ceph::buffer::list &bl) const; - void decode(ceph::buffer::list::const_iterator& bl); - void dump(ceph::Formatter *f) const; - void decode_json(JSONObj *obj); - static void generate_test_instances(std::list& ls); - - // this frag - utime_t mtime; - uint64_t change_attr = 0; - int64_t nfiles = 0; // files - int64_t nsubdirs = 0; // subdirs -}; -WRITE_CLASS_ENCODER(frag_info_t) - -inline bool operator==(const frag_info_t &l, const frag_info_t &r) { - return memcmp(&l, &r, sizeof(l)) == 0; -} -inline bool operator!=(const frag_info_t &l, const frag_info_t &r) { - return !(l == r); -} - -std::ostream& operator<<(std::ostream &out, const frag_info_t &f); - - -struct nest_info_t : public scatter_info_t { - int64_t rsize() const { return rfiles + rsubdirs; } - - void zero() { - *this = nest_info_t(); - } - - void sub(const nest_info_t &other) { - add(other, -1); - } - void add(const nest_info_t &other, int fac=1) { - if (other.rctime > rctime) - rctime = other.rctime; - rbytes += fac*other.rbytes; - rfiles += fac*other.rfiles; - rsubdirs += fac*other.rsubdirs; - rsnaps += fac*other.rsnaps; - } - - // *this += cur - acc; - void add_delta(const nest_info_t &cur, const nest_info_t &acc) { - if (cur.rctime > rctime) - rctime = cur.rctime; - rbytes += cur.rbytes - acc.rbytes; - rfiles += cur.rfiles - acc.rfiles; - rsubdirs += cur.rsubdirs - acc.rsubdirs; - rsnaps += cur.rsnaps - acc.rsnaps; - } - - bool same_sums(const nest_info_t &o) const { - return rctime <= o.rctime && - rbytes == o.rbytes && - rfiles == o.rfiles && - rsubdirs == o.rsubdirs && - rsnaps == o.rsnaps; - } - - void encode(ceph::buffer::list &bl) const; - void decode(ceph::buffer::list::const_iterator& bl); - void dump(ceph::Formatter *f) const; - void decode_json(JSONObj *obj); - static void generate_test_instances(std::list& ls); - - // this frag + children - utime_t rctime; - int64_t rbytes = 0; - int64_t rfiles = 0; - int64_t rsubdirs = 0; - int64_t rsnaps = 0; -}; -WRITE_CLASS_ENCODER(nest_info_t) - -inline bool operator==(const nest_info_t &l, const nest_info_t &r) { - return memcmp(&l, &r, sizeof(l)) == 0; -} -inline bool operator!=(const nest_info_t &l, const nest_info_t &r) { - return !(l == r); -} - -std::ostream& operator<<(std::ostream &out, const nest_info_t &n); - -struct vinodeno_t { - vinodeno_t() {} - vinodeno_t(inodeno_t i, snapid_t s) : ino(i), snapid(s) {} - - void encode(ceph::buffer::list& bl) const { - using ceph::encode; - encode(ino, bl); - encode(snapid, bl); - } - void decode(ceph::buffer::list::const_iterator& p) { - using ceph::decode; - decode(ino, p); - decode(snapid, p); - } - - inodeno_t ino; - snapid_t snapid; -}; -WRITE_CLASS_ENCODER(vinodeno_t) - -inline bool operator==(const vinodeno_t &l, const vinodeno_t &r) { - return l.ino == r.ino && l.snapid == r.snapid; -} -inline bool operator!=(const vinodeno_t &l, const vinodeno_t &r) { - return !(l == r); -} -inline bool operator<(const vinodeno_t &l, const vinodeno_t &r) { - return - l.ino < r.ino || - (l.ino == r.ino && l.snapid < r.snapid); -} - -struct quota_info_t -{ - void encode(ceph::buffer::list& bl) const { - ENCODE_START(1, 1, bl); - encode(max_bytes, bl); - encode(max_files, bl); - ENCODE_FINISH(bl); - } - void decode(ceph::buffer::list::const_iterator& p) { - DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, p); - decode(max_bytes, p); - decode(max_files, p); - DECODE_FINISH(p); - } - - void dump(ceph::Formatter *f) const; - static void generate_test_instances(std::list& ls); - - bool is_valid() const { - return max_bytes >=0 && max_files >=0; - } - bool is_enable() const { - return max_bytes || max_files; - } - void decode_json(JSONObj *obj); - - int64_t max_bytes = 0; - int64_t max_files = 0; -}; -WRITE_CLASS_ENCODER(quota_info_t) - -inline bool operator==(const quota_info_t &l, const quota_info_t &r) { - return memcmp(&l, &r, sizeof(l)) == 0; -} - -std::ostream& operator<<(std::ostream &out, const quota_info_t &n); - namespace std { template<> struct hash { size_t operator()(const vinodeno_t &vino) const { @@ -360,686 +147,8 @@ inline std::ostream& operator<<(std::ostream &out, const vinodeno_t &vino) { return out; } -struct client_writeable_range_t { - struct byte_range_t { - uint64_t first = 0, last = 0; // interval client can write to - byte_range_t() {} - void decode_json(JSONObj *obj); - }; - - void encode(ceph::buffer::list &bl) const; - void decode(ceph::buffer::list::const_iterator& bl); - void dump(ceph::Formatter *f) const; - static void generate_test_instances(std::list& ls); - - byte_range_t range; - snapid_t follows = 0; // aka "data+metadata flushed thru" -}; - -inline void decode(client_writeable_range_t::byte_range_t& range, ceph::buffer::list::const_iterator& bl) { - using ceph::decode; - decode(range.first, bl); - decode(range.last, bl); -} - -WRITE_CLASS_ENCODER(client_writeable_range_t) - -std::ostream& operator<<(std::ostream& out, const client_writeable_range_t& r); - -inline bool operator==(const client_writeable_range_t& l, - const client_writeable_range_t& r) { - return l.range.first == r.range.first && l.range.last == r.range.last && - l.follows == r.follows; -} - -struct inline_data_t { -public: - inline_data_t() {} - inline_data_t(const inline_data_t& o) : version(o.version) { - if (o.blp) - set_data(*o.blp); - } - inline_data_t& operator=(const inline_data_t& o) { - version = o.version; - if (o.blp) - set_data(*o.blp); - else - free_data(); - return *this; - } - - void free_data() { - blp.reset(); - } - void get_data(ceph::buffer::list& ret) const { - if (blp) - ret = *blp; - else - ret.clear(); - } - void set_data(const ceph::buffer::list& bl) { - if (!blp) - blp.reset(new ceph::buffer::list); - *blp = bl; - } - size_t length() const { return blp ? blp->length() : 0; } - - bool operator==(const inline_data_t& o) const { - return length() == o.length() && - (length() == 0 || - (*const_cast(blp.get()) == *const_cast(o.blp.get()))); - } - bool operator!=(const inline_data_t& o) const { - return !(*this == o); - } - void encode(ceph::buffer::list &bl) const; - void decode(ceph::buffer::list::const_iterator& bl); - - version_t version = 1; - -private: - std::unique_ptr blp; -}; -WRITE_CLASS_ENCODER(inline_data_t) - -enum { - DAMAGE_STATS, // statistics (dirstat, size, etc) - DAMAGE_RSTATS, // recursive statistics (rstat, accounted_rstat) - DAMAGE_FRAGTREE // fragtree -- repair by searching -}; typedef uint32_t damage_flags_t; -template class Allocator = std::allocator> -struct inode_t { - /** - * *************** - * Do not forget to add any new fields to the compare() function. - * *************** - */ - using client_range_map = std::map,Allocator>>; - - inode_t() - { - clear_layout(); - } - - // file type - bool is_symlink() const { return (mode & S_IFMT) == S_IFLNK; } - bool is_dir() const { return (mode & S_IFMT) == S_IFDIR; } - bool is_file() const { return (mode & S_IFMT) == S_IFREG; } - - bool is_truncating() const { return (truncate_pending > 0); } - void truncate(uint64_t old_size, uint64_t new_size, const bufferlist &fbl) { - truncate(old_size, new_size); - fscrypt_last_block = fbl; - } - void truncate(uint64_t old_size, uint64_t new_size) { - ceph_assert(new_size <= old_size); - if (old_size > max_size_ever) - max_size_ever = old_size; - truncate_from = old_size; - size = new_size; - rstat.rbytes = new_size; - truncate_size = size; - truncate_seq++; - truncate_pending++; - } - - bool has_layout() const { - return layout != file_layout_t(); - } - - void clear_layout() { - layout = file_layout_t(); - } - - uint64_t get_layout_size_increment() const { - return layout.get_period(); - } - - bool is_dirty_rstat() const { return !(rstat == accounted_rstat); } - - uint64_t get_client_range(client_t client) const { - auto it = client_ranges.find(client); - return it != client_ranges.end() ? it->second.range.last : 0; - } - - uint64_t get_max_size() const { - uint64_t max = 0; - for (std::map::const_iterator p = client_ranges.begin(); - p != client_ranges.end(); - ++p) - if (p->second.range.last > max) - max = p->second.range.last; - return max; - } - void set_max_size(uint64_t new_max) { - if (new_max == 0) { - client_ranges.clear(); - } else { - for (std::map::iterator p = client_ranges.begin(); - p != client_ranges.end(); - ++p) - p->second.range.last = new_max; - } - } - - void trim_client_ranges(snapid_t last) { - std::map::iterator p = client_ranges.begin(); - while (p != client_ranges.end()) { - if (p->second.follows >= last) - client_ranges.erase(p++); - else - ++p; - } - } - - bool is_backtrace_updated() const { - return backtrace_version == version; - } - void update_backtrace(version_t pv=0) { - backtrace_version = pv ? pv : version; - } - - void add_old_pool(int64_t l) { - backtrace_version = version; - old_pools.insert(l); - } - - void encode(ceph::buffer::list &bl, uint64_t features) const; - void decode(ceph::buffer::list::const_iterator& bl); - void dump(ceph::Formatter *f) const; - static void client_ranges_cb(client_range_map& c, JSONObj *obj); - static void old_pools_cb(compact_set, Allocator >& c, JSONObj *obj); - void decode_json(JSONObj *obj); - static void generate_test_instances(std::list& ls); - /** - * Compare this inode_t with another that represent *the same inode* - * at different points in time. - * @pre The inodes are the same ino - * - * @param other The inode_t to compare ourselves with - * @param divergent A bool pointer which will be set to true - * if the values are different in a way that can't be explained - * by one being a newer version than the other. - * - * @returns 1 if we are newer than the other, 0 if equal, -1 if older. - */ - int compare(const inode_t &other, bool *divergent) const; - - // base (immutable) - inodeno_t ino = 0; - uint32_t rdev = 0; // if special file - - // affected by any inode change... - utime_t ctime; // inode change time - utime_t btime; // birth time - - // perm (namespace permissions) - uint32_t mode = 0; - uid_t uid = 0; - gid_t gid = 0; - - // nlink - int32_t nlink = 0; - - // file (data access) - ceph_dir_layout dir_layout = {}; // [dir only] - file_layout_t layout; - compact_set, Allocator> old_pools; - uint64_t size = 0; // on directory, # dentries - uint64_t max_size_ever = 0; // max size the file has ever been - uint32_t truncate_seq = 0; - uint64_t truncate_size = 0, truncate_from = 0; - uint32_t truncate_pending = 0; - utime_t mtime; // file data modify time. - utime_t atime; // file data access time. - uint32_t time_warp_seq = 0; // count of (potential) mtime/atime timewarps (i.e., utimes()) - inline_data_t inline_data; // FIXME check - - // change attribute - uint64_t change_attr = 0; - - client_range_map client_ranges; // client(s) can write to these ranges - - // dirfrag, recursive accountin - frag_info_t dirstat; // protected by my filelock - nest_info_t rstat; // protected by my nestlock - nest_info_t accounted_rstat; // protected by parent's nestlock - - quota_info_t quota; - - mds_rank_t export_pin = MDS_RANK_NONE; - - double export_ephemeral_random_pin = 0; - bool export_ephemeral_distributed_pin = false; - - // special stuff - version_t version = 0; // auth only - version_t file_data_version = 0; // auth only - version_t xattr_version = 0; - - utime_t last_scrub_stamp; // start time of last complete scrub - version_t last_scrub_version = 0;// (parent) start version of last complete scrub - - version_t backtrace_version = 0; - - snapid_t oldest_snap; - - std::basic_string,Allocator> stray_prior_path; //stores path before unlink - - std::vector fscrypt_auth; - std::vector fscrypt_file; - - bufferlist fscrypt_last_block; - -private: - bool older_is_consistent(const inode_t &other) const; -}; - -// These methods may be moved back to mdstypes.cc when we have pmr -template class Allocator> -void inode_t::encode(ceph::buffer::list &bl, uint64_t features) const -{ - ENCODE_START(19, 6, bl); - - encode(ino, bl); - encode(rdev, bl); - encode(ctime, bl); - - encode(mode, bl); - encode(uid, bl); - encode(gid, bl); - - encode(nlink, bl); - { - // removed field - bool anchored = 0; - encode(anchored, bl); - } - - encode(dir_layout, bl); - encode(layout, bl, features); - encode(size, bl); - encode(truncate_seq, bl); - encode(truncate_size, bl); - encode(truncate_from, bl); - encode(truncate_pending, bl); - encode(mtime, bl); - encode(atime, bl); - encode(time_warp_seq, bl); - encode(client_ranges, bl); - - encode(dirstat, bl); - encode(rstat, bl); - encode(accounted_rstat, bl); - - encode(version, bl); - encode(file_data_version, bl); - encode(xattr_version, bl); - encode(backtrace_version, bl); - encode(old_pools, bl); - encode(max_size_ever, bl); - encode(inline_data, bl); - encode(quota, bl); - - encode(stray_prior_path, bl); - - encode(last_scrub_version, bl); - encode(last_scrub_stamp, bl); - - encode(btime, bl); - encode(change_attr, bl); - - encode(export_pin, bl); - - encode(export_ephemeral_random_pin, bl); - encode(export_ephemeral_distributed_pin, bl); - - encode(!fscrypt_auth.empty(), bl); - encode(fscrypt_auth, bl); - encode(fscrypt_file, bl); - encode(fscrypt_last_block, bl); - ENCODE_FINISH(bl); -} - -template class Allocator> -void inode_t::decode(ceph::buffer::list::const_iterator &p) -{ - DECODE_START_LEGACY_COMPAT_LEN(19, 6, 6, p); - - decode(ino, p); - decode(rdev, p); - decode(ctime, p); - - decode(mode, p); - decode(uid, p); - decode(gid, p); - - decode(nlink, p); - { - bool anchored; - decode(anchored, p); - } - - if (struct_v >= 4) - decode(dir_layout, p); - else { - // FIPS zeroization audit 20191117: this memset is not security related. - memset(&dir_layout, 0, sizeof(dir_layout)); - } - decode(layout, p); - decode(size, p); - decode(truncate_seq, p); - decode(truncate_size, p); - decode(truncate_from, p); - if (struct_v >= 5) - decode(truncate_pending, p); - else - truncate_pending = 0; - decode(mtime, p); - decode(atime, p); - decode(time_warp_seq, p); - if (struct_v >= 3) { - decode(client_ranges, p); - } else { - std::map m; - decode(m, p); - for (auto q = m.begin(); q != m.end(); ++q) - client_ranges[q->first].range = q->second; - } - - decode(dirstat, p); - decode(rstat, p); - decode(accounted_rstat, p); - - decode(version, p); - decode(file_data_version, p); - decode(xattr_version, p); - if (struct_v >= 2) - decode(backtrace_version, p); - if (struct_v >= 7) - decode(old_pools, p); - if (struct_v >= 8) - decode(max_size_ever, p); - if (struct_v >= 9) { - decode(inline_data, p); - } else { - inline_data.version = CEPH_INLINE_NONE; - } - if (struct_v < 10) - backtrace_version = 0; // force update backtrace - if (struct_v >= 11) - decode(quota, p); - - if (struct_v >= 12) { - std::string tmp; - decode(tmp, p); - stray_prior_path = std::string_view(tmp); - } - - if (struct_v >= 13) { - decode(last_scrub_version, p); - decode(last_scrub_stamp, p); - } - if (struct_v >= 14) { - decode(btime, p); - decode(change_attr, p); - } else { - btime = utime_t(); - change_attr = 0; - } - - if (struct_v >= 15) { - decode(export_pin, p); - } else { - export_pin = MDS_RANK_NONE; - } - - if (struct_v >= 16) { - decode(export_ephemeral_random_pin, p); - decode(export_ephemeral_distributed_pin, p); - } else { - export_ephemeral_random_pin = 0; - export_ephemeral_distributed_pin = false; - } - - if (struct_v >= 17) { - bool fscrypt_flag; - decode(fscrypt_flag, p); // ignored - } - - if (struct_v >= 18) { - decode(fscrypt_auth, p); - decode(fscrypt_file, p); - } - - if (struct_v >= 19) { - decode(fscrypt_last_block, p); - } - DECODE_FINISH(p); -} - -template class Allocator> -void inode_t::dump(ceph::Formatter *f) const -{ - f->dump_unsigned("ino", ino); - f->dump_unsigned("rdev", rdev); - f->dump_stream("ctime") << ctime; - f->dump_stream("btime") << btime; - f->dump_unsigned("mode", mode); - f->dump_unsigned("uid", uid); - f->dump_unsigned("gid", gid); - f->dump_unsigned("nlink", nlink); - - f->open_object_section("dir_layout"); - ::dump(dir_layout, f); - f->close_section(); - - f->dump_object("layout", layout); - - f->open_array_section("old_pools"); - for (const auto &p : old_pools) { - f->dump_int("pool", p); - } - f->close_section(); - - f->dump_unsigned("size", size); - f->dump_unsigned("truncate_seq", truncate_seq); - f->dump_unsigned("truncate_size", truncate_size); - f->dump_unsigned("truncate_from", truncate_from); - f->dump_unsigned("truncate_pending", truncate_pending); - f->dump_stream("mtime") << mtime; - f->dump_stream("atime") << atime; - f->dump_unsigned("time_warp_seq", time_warp_seq); - f->dump_unsigned("change_attr", change_attr); - f->dump_int("export_pin", export_pin); - f->dump_int("export_ephemeral_random_pin", export_ephemeral_random_pin); - f->dump_bool("export_ephemeral_distributed_pin", export_ephemeral_distributed_pin); - - f->open_array_section("client_ranges"); - for (const auto &p : client_ranges) { - f->open_object_section("client"); - f->dump_unsigned("client", p.first.v); - p.second.dump(f); - f->close_section(); - } - f->close_section(); - - f->open_object_section("dirstat"); - dirstat.dump(f); - f->close_section(); - - f->open_object_section("rstat"); - rstat.dump(f); - f->close_section(); - - f->open_object_section("accounted_rstat"); - accounted_rstat.dump(f); - f->close_section(); - - f->dump_unsigned("version", version); - f->dump_unsigned("file_data_version", file_data_version); - f->dump_unsigned("xattr_version", xattr_version); - f->dump_unsigned("backtrace_version", backtrace_version); - - f->dump_string("stray_prior_path", stray_prior_path); - f->dump_unsigned("max_size_ever", max_size_ever); - - f->open_object_section("quota"); - quota.dump(f); - f->close_section(); - - f->dump_stream("last_scrub_stamp") << last_scrub_stamp; - f->dump_unsigned("last_scrub_version", last_scrub_version); -} - -template class Allocator> -void inode_t::client_ranges_cb(typename inode_t::client_range_map& c, JSONObj *obj){ - - int64_t client; - JSONDecoder::decode_json("client", client, obj, true); - client_writeable_range_t client_range_tmp; - JSONDecoder::decode_json("byte range", client_range_tmp.range, obj, true); - JSONDecoder::decode_json("follows", client_range_tmp.follows.val, obj, true); - c[client] = client_range_tmp; -} - -template class Allocator> -void inode_t::old_pools_cb(compact_set, Allocator >& c, JSONObj *obj){ - - int64_t tmp; - decode_json_obj(tmp, obj); - c.insert(tmp); -} - -template class Allocator> -void inode_t::decode_json(JSONObj *obj) -{ - - JSONDecoder::decode_json("ino", ino.val, obj, true); - JSONDecoder::decode_json("rdev", rdev, obj, true); - //JSONDecoder::decode_json("ctime", ctime, obj, true); - //JSONDecoder::decode_json("btime", btime, obj, true); - JSONDecoder::decode_json("mode", mode, obj, true); - JSONDecoder::decode_json("uid", uid, obj, true); - JSONDecoder::decode_json("gid", gid, obj, true); - JSONDecoder::decode_json("nlink", nlink, obj, true); - JSONDecoder::decode_json("dir_layout", dir_layout, obj, true); - JSONDecoder::decode_json("layout", layout, obj, true); - JSONDecoder::decode_json("old_pools", old_pools, inode_t::old_pools_cb, obj, true); - JSONDecoder::decode_json("size", size, obj, true); - JSONDecoder::decode_json("truncate_seq", truncate_seq, obj, true); - JSONDecoder::decode_json("truncate_size", truncate_size, obj, true); - JSONDecoder::decode_json("truncate_from", truncate_from, obj, true); - JSONDecoder::decode_json("truncate_pending", truncate_pending, obj, true); - //JSONDecoder::decode_json("mtime", mtime, obj, true); - //JSONDecoder::decode_json("atime", atime, obj, true); - JSONDecoder::decode_json("time_warp_seq", time_warp_seq, obj, true); - JSONDecoder::decode_json("change_attr", change_attr, obj, true); - JSONDecoder::decode_json("export_pin", export_pin, obj, true); - JSONDecoder::decode_json("client_ranges", client_ranges, inode_t::client_ranges_cb, obj, true); - JSONDecoder::decode_json("dirstat", dirstat, obj, true); - JSONDecoder::decode_json("rstat", rstat, obj, true); - JSONDecoder::decode_json("accounted_rstat", accounted_rstat, obj, true); - JSONDecoder::decode_json("version", version, obj, true); - JSONDecoder::decode_json("file_data_version", file_data_version, obj, true); - JSONDecoder::decode_json("xattr_version", xattr_version, obj, true); - JSONDecoder::decode_json("backtrace_version", backtrace_version, obj, true); - JSONDecoder::decode_json("stray_prior_path", stray_prior_path, obj, true); - JSONDecoder::decode_json("max_size_ever", max_size_ever, obj, true); - JSONDecoder::decode_json("quota", quota, obj, true); - JSONDecoder::decode_json("last_scrub_stamp", last_scrub_stamp, obj, true); - JSONDecoder::decode_json("last_scrub_version", last_scrub_version, obj, true); -} - -template class Allocator> -void inode_t::generate_test_instances(std::list& ls) -{ - ls.push_back(new inode_t); - ls.push_back(new inode_t); - ls.back()->ino = 1; - // i am lazy. -} - -template class Allocator> -int inode_t::compare(const inode_t &other, bool *divergent) const -{ - ceph_assert(ino == other.ino); - *divergent = false; - if (version == other.version) { - if (rdev != other.rdev || - ctime != other.ctime || - btime != other.btime || - mode != other.mode || - uid != other.uid || - gid != other.gid || - nlink != other.nlink || - memcmp(&dir_layout, &other.dir_layout, sizeof(dir_layout)) || - layout != other.layout || - old_pools != other.old_pools || - size != other.size || - max_size_ever != other.max_size_ever || - truncate_seq != other.truncate_seq || - truncate_size != other.truncate_size || - truncate_from != other.truncate_from || - truncate_pending != other.truncate_pending || - change_attr != other.change_attr || - mtime != other.mtime || - atime != other.atime || - time_warp_seq != other.time_warp_seq || - inline_data != other.inline_data || - client_ranges != other.client_ranges || - !(dirstat == other.dirstat) || - !(rstat == other.rstat) || - !(accounted_rstat == other.accounted_rstat) || - file_data_version != other.file_data_version || - xattr_version != other.xattr_version || - backtrace_version != other.backtrace_version) { - *divergent = true; - } - return 0; - } else if (version > other.version) { - *divergent = !older_is_consistent(other); - return 1; - } else { - ceph_assert(version < other.version); - *divergent = !other.older_is_consistent(*this); - return -1; - } -} - -template class Allocator> -bool inode_t::older_is_consistent(const inode_t &other) const -{ - if (max_size_ever < other.max_size_ever || - truncate_seq < other.truncate_seq || - time_warp_seq < other.time_warp_seq || - inline_data.version < other.inline_data.version || - dirstat.version < other.dirstat.version || - rstat.version < other.rstat.version || - accounted_rstat.version < other.accounted_rstat.version || - file_data_version < other.file_data_version || - xattr_version < other.xattr_version || - backtrace_version < other.backtrace_version) { - return false; - } - return true; -} - -template class Allocator> -inline void encode(const inode_t &c, ::ceph::buffer::list &bl, uint64_t features) -{ - ENCODE_DUMP_PRE(); - c.encode(bl, features); - ENCODE_DUMP_POST(cl); -} -template class Allocator> -inline void decode(inode_t &c, ::ceph::buffer::list::const_iterator &p) -{ - c.decode(p); -} - template class Allocator> using alloc_string = std::basic_string,Allocator>; @@ -1944,24 +1053,4 @@ inline bool operator==(const MDSCacheObjectInfo& l, const MDSCacheObjectInfo& r) } WRITE_CLASS_ENCODER(MDSCacheObjectInfo) -// parse a map of keys/values. -namespace qi = boost::spirit::qi; - -template -struct keys_and_values - : qi::grammar()> -{ - keys_and_values() - : keys_and_values::base_type(query) - { - query = pair >> *(qi::lit(' ') >> pair); - pair = key >> '=' >> value; - key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9"); - value = +qi::char_("a-zA-Z0-9-_."); - } - qi::rule()> query; - qi::rule()> pair; - qi::rule key, value; -}; - #endif diff --git a/src/tools/ceph-dencoder/mds_types.h b/src/tools/ceph-dencoder/mds_types.h index 9406bf88bc740..91ba86be0d1ec 100644 --- a/src/tools/ceph-dencoder/mds_types.h +++ b/src/tools/ceph-dencoder/mds_types.h @@ -11,6 +11,7 @@ TYPE(snaplink_t) TYPE(sr_t) #include "mds/mdstypes.h" +#include "include/cephfs/types.h" TYPE(frag_info_t) TYPE(nest_info_t) TYPE(quota_info_t) From f2bfea5bfd77120a189f42d72e6698df561cca68 Mon Sep 17 00:00:00 2001 From: dparmar18 Date: Wed, 8 Jun 2022 11:47:17 +0530 Subject: [PATCH 2/2] mds: add include/cephfs/types.h path in spec files Signed-off-by: Dhairya Parmar --- ceph.spec.in | 1 + debian/libcephfs-dev.install | 1 + src/include/CMakeLists.txt | 1 + 3 files changed, 3 insertions(+) diff --git a/ceph.spec.in b/ceph.spec.in index 3042d6e0dc975..f5a71ce144553 100644 --- a/ceph.spec.in +++ b/ceph.spec.in @@ -2349,6 +2349,7 @@ fi %dir %{_includedir}/cephfs %{_includedir}/cephfs/libcephfs.h %{_includedir}/cephfs/ceph_ll_client.h +%{_includedir}/cephfs/types.h %dir %{_includedir}/cephfs/metrics %{_includedir}/cephfs/metrics/Types.h %{_libdir}/libcephfs.so diff --git a/debian/libcephfs-dev.install b/debian/libcephfs-dev.install index e06363ad7008a..cf22dce62d46b 100644 --- a/debian/libcephfs-dev.install +++ b/debian/libcephfs-dev.install @@ -1,4 +1,5 @@ usr/include/cephfs/ceph_ll_client.h usr/include/cephfs/libcephfs.h +usr/include/cephfs/types.h usr/include/cephfs/metrics/Types.h usr/lib/libcephfs.so diff --git a/src/include/CMakeLists.txt b/src/include/CMakeLists.txt index 91eb92cdd1c60..cb9c2fea8f80b 100644 --- a/src/include/CMakeLists.txt +++ b/src/include/CMakeLists.txt @@ -41,5 +41,6 @@ if(WITH_LIBCEPHFS) install(FILES cephfs/libcephfs.h cephfs/ceph_ll_client.h + cephfs/types.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cephfs) endif()