1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2020 Red Hat, Inc.
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
13 #ifndef CEPH_CEPHFS_TYPES_H
14 #define CEPH_CEPHFS_TYPES_H
15 #include "include/int_types.h"
20 #include <string_view>
22 #include "common/config.h"
23 #include "common/Clock.h"
24 #include "common/DecayCounter.h"
25 #include "common/StackStringStream.h"
26 #include "common/entity_name.h"
28 #include "include/compat.h"
29 #include "include/Context.h"
30 #include "include/frag.h"
31 #include "include/xlist.h"
32 #include "include/interval_set.h"
33 #include "include/compact_set.h"
34 #include "include/fs_types.h"
35 #include "include/ceph_fs.h"
37 #include "mds/inode_backtrace.h"
39 #include <boost/spirit/include/qi.hpp>
40 #include <boost/pool/pool.hpp>
41 #include "include/ceph_assert.h"
42 #include <boost/serialization/strong_typedef.hpp>
43 #include "common/ceph_json.h"
45 #define CEPH_FS_ONDISK_MAGIC "ceph fs volume v011"
48 BOOST_STRONG_TYPEDEF(uint64_t, mds_gid_t
)
49 extern const mds_gid_t MDS_GID_NONE
;
51 typedef int32_t fs_cluster_id_t
;
52 constexpr fs_cluster_id_t FS_CLUSTER_ID_NONE
= -1;
54 // The namespace ID of the anonymous default filesystem from legacy systems
55 constexpr fs_cluster_id_t FS_CLUSTER_ID_ANONYMOUS
= 0;
57 typedef int32_t mds_rank_t
;
58 constexpr mds_rank_t MDS_RANK_NONE
= -1;
59 constexpr mds_rank_t MDS_RANK_EPHEMERAL_DIST
= -2;
60 constexpr mds_rank_t MDS_RANK_EPHEMERAL_RAND
= -3;
62 struct scatter_info_t
{
63 version_t version
= 0;
66 struct frag_info_t
: public scatter_info_t
{
67 int64_t size() const { return nfiles
+ nsubdirs
; }
70 *this = frag_info_t();
73 // *this += cur - acc;
74 void add_delta(const frag_info_t
&cur
, const frag_info_t
&acc
, bool *touched_mtime
=0, bool *touched_chattr
=0) {
75 if (cur
.mtime
> mtime
) {
78 *touched_mtime
= true;
80 if (cur
.change_attr
> change_attr
) {
81 change_attr
= cur
.change_attr
;
83 *touched_chattr
= true;
85 nfiles
+= cur
.nfiles
- acc
.nfiles
;
86 nsubdirs
+= cur
.nsubdirs
- acc
.nsubdirs
;
89 void add(const frag_info_t
& other
) {
90 if (other
.mtime
> mtime
)
92 if (other
.change_attr
> change_attr
)
93 change_attr
= other
.change_attr
;
94 nfiles
+= other
.nfiles
;
95 nsubdirs
+= other
.nsubdirs
;
98 bool same_sums(const frag_info_t
&o
) const {
99 return mtime
<= o
.mtime
&&
100 nfiles
== o
.nfiles
&&
101 nsubdirs
== o
.nsubdirs
;
104 void encode(ceph::buffer::list
&bl
) const;
105 void decode(ceph::buffer::list::const_iterator
& bl
);
106 void dump(ceph::Formatter
*f
) const;
107 void decode_json(JSONObj
*obj
);
108 static void generate_test_instances(std::list
<frag_info_t
*>& ls
);
112 uint64_t change_attr
= 0;
113 int64_t nfiles
= 0; // files
114 int64_t nsubdirs
= 0; // subdirs
116 WRITE_CLASS_ENCODER(frag_info_t
)
118 inline bool operator==(const frag_info_t
&l
, const frag_info_t
&r
) {
119 return memcmp(&l
, &r
, sizeof(l
)) == 0;
121 inline bool operator!=(const frag_info_t
&l
, const frag_info_t
&r
) {
125 std::ostream
& operator<<(std::ostream
&out
, const frag_info_t
&f
);
127 struct nest_info_t
: public scatter_info_t
{
128 int64_t rsize() const { return rfiles
+ rsubdirs
; }
131 *this = nest_info_t();
134 void sub(const nest_info_t
&other
) {
137 void add(const nest_info_t
&other
, int fac
=1) {
138 if (other
.rctime
> rctime
)
139 rctime
= other
.rctime
;
140 rbytes
+= fac
*other
.rbytes
;
141 rfiles
+= fac
*other
.rfiles
;
142 rsubdirs
+= fac
*other
.rsubdirs
;
143 rsnaps
+= fac
*other
.rsnaps
;
146 // *this += cur - acc;
147 void add_delta(const nest_info_t
&cur
, const nest_info_t
&acc
) {
148 if (cur
.rctime
> rctime
)
150 rbytes
+= cur
.rbytes
- acc
.rbytes
;
151 rfiles
+= cur
.rfiles
- acc
.rfiles
;
152 rsubdirs
+= cur
.rsubdirs
- acc
.rsubdirs
;
153 rsnaps
+= cur
.rsnaps
- acc
.rsnaps
;
156 bool same_sums(const nest_info_t
&o
) const {
157 return rctime
<= o
.rctime
&&
158 rbytes
== o
.rbytes
&&
159 rfiles
== o
.rfiles
&&
160 rsubdirs
== o
.rsubdirs
&&
164 void encode(ceph::buffer::list
&bl
) const;
165 void decode(ceph::buffer::list::const_iterator
& bl
);
166 void dump(ceph::Formatter
*f
) const;
167 void decode_json(JSONObj
*obj
);
168 static void generate_test_instances(std::list
<nest_info_t
*>& ls
);
170 // this frag + children
174 int64_t rsubdirs
= 0;
177 WRITE_CLASS_ENCODER(nest_info_t
)
179 inline bool operator==(const nest_info_t
&l
, const nest_info_t
&r
) {
180 return memcmp(&l
, &r
, sizeof(l
)) == 0;
182 inline bool operator!=(const nest_info_t
&l
, const nest_info_t
&r
) {
186 std::ostream
& operator<<(std::ostream
&out
, const nest_info_t
&n
);
190 vinodeno_t(inodeno_t i
, snapid_t s
) : ino(i
), snapid(s
) {}
192 void encode(ceph::buffer::list
& bl
) const {
197 void decode(ceph::buffer::list::const_iterator
& p
) {
206 WRITE_CLASS_ENCODER(vinodeno_t
)
208 inline bool operator==(const vinodeno_t
&l
, const vinodeno_t
&r
) {
209 return l
.ino
== r
.ino
&& l
.snapid
== r
.snapid
;
211 inline bool operator!=(const vinodeno_t
&l
, const vinodeno_t
&r
) {
214 inline bool operator<(const vinodeno_t
&l
, const vinodeno_t
&r
) {
217 (l
.ino
== r
.ino
&& l
.snapid
< r
.snapid
);
228 void encode(ceph::buffer::list
& bl
) const {
229 ENCODE_START(1, 1, bl
);
230 encode(max_bytes
, bl
);
231 encode(max_files
, bl
);
234 void decode(ceph::buffer::list::const_iterator
& p
) {
235 DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, p
);
236 decode(max_bytes
, p
);
237 decode(max_files
, p
);
241 void dump(ceph::Formatter
*f
) const;
242 static void generate_test_instances(std::list
<quota_info_t
*>& ls
);
244 bool is_valid() const {
245 return max_bytes
>=0 && max_files
>=0;
247 bool is_enabled(quota_max_t type
=QUOTA_ANY
) const {
249 case QUOTA_MAX_FILES
:
251 case QUOTA_MAX_BYTES
:
255 return !!max_bytes
|| !!max_files
;
258 void decode_json(JSONObj
*obj
);
260 int64_t max_bytes
= 0;
261 int64_t max_files
= 0;
263 WRITE_CLASS_ENCODER(quota_info_t
)
265 inline bool operator==(const quota_info_t
&l
, const quota_info_t
&r
) {
266 return memcmp(&l
, &r
, sizeof(l
)) == 0;
269 std::ostream
& operator<<(std::ostream
&out
, const quota_info_t
&n
);
271 struct client_writeable_range_t
{
272 struct byte_range_t
{
273 uint64_t first
= 0, last
= 0; // interval client can write to
275 void decode_json(JSONObj
*obj
);
278 void encode(ceph::buffer::list
&bl
) const;
279 void decode(ceph::buffer::list::const_iterator
& bl
);
280 void dump(ceph::Formatter
*f
) const;
281 static void generate_test_instances(std::list
<client_writeable_range_t
*>& ls
);
284 snapid_t follows
= 0; // aka "data+metadata flushed thru"
287 inline void decode(client_writeable_range_t::byte_range_t
& range
, ceph::buffer::list::const_iterator
& bl
) {
289 decode(range
.first
, bl
);
290 decode(range
.last
, bl
);
293 WRITE_CLASS_ENCODER(client_writeable_range_t
)
295 std::ostream
& operator<<(std::ostream
& out
, const client_writeable_range_t
& r
);
297 inline bool operator==(const client_writeable_range_t
& l
,
298 const client_writeable_range_t
& r
) {
299 return l
.range
.first
== r
.range
.first
&& l
.range
.last
== r
.range
.last
&&
300 l
.follows
== r
.follows
;
303 struct inline_data_t
{
306 inline_data_t(const inline_data_t
& o
) : version(o
.version
) {
310 inline_data_t
& operator=(const inline_data_t
& o
) {
322 void get_data(ceph::buffer::list
& ret
) const {
328 void set_data(const ceph::buffer::list
& bl
) {
330 blp
.reset(new ceph::buffer::list
);
333 size_t length() const { return blp
? blp
->length() : 0; }
335 bool operator==(const inline_data_t
& o
) const {
336 return length() == o
.length() &&
338 (*const_cast<ceph::buffer::list
*>(blp
.get()) == *const_cast<ceph::buffer::list
*>(o
.blp
.get())));
340 bool operator!=(const inline_data_t
& o
) const {
341 return !(*this == o
);
343 void encode(ceph::buffer::list
&bl
) const;
344 void decode(ceph::buffer::list::const_iterator
& bl
);
346 version_t version
= 1;
349 std::unique_ptr
<ceph::buffer::list
> blp
;
351 WRITE_CLASS_ENCODER(inline_data_t
)
354 DAMAGE_STATS
, // statistics (dirstat, size, etc)
355 DAMAGE_RSTATS
, // recursive statistics (rstat, accounted_rstat)
356 DAMAGE_FRAGTREE
// fragtree -- repair by searching
359 template<template<typename
> class Allocator
= std::allocator
>
363 * Do not forget to add any new fields to the compare() function.
366 using client_range_map
= std::map
<client_t
,client_writeable_range_t
,std::less
<client_t
>,Allocator
<std::pair
<const client_t
,client_writeable_range_t
>>>;
374 bool is_symlink() const { return (mode
& S_IFMT
) == S_IFLNK
; }
375 bool is_dir() const { return (mode
& S_IFMT
) == S_IFDIR
; }
376 bool is_file() const { return (mode
& S_IFMT
) == S_IFREG
; }
378 bool is_truncating() const { return (truncate_pending
> 0); }
379 void truncate(uint64_t old_size
, uint64_t new_size
, const bufferlist
&fbl
) {
380 truncate(old_size
, new_size
);
381 fscrypt_last_block
= fbl
;
383 void truncate(uint64_t old_size
, uint64_t new_size
) {
384 ceph_assert(new_size
<= old_size
);
385 if (old_size
> max_size_ever
)
386 max_size_ever
= old_size
;
387 truncate_from
= old_size
;
389 rstat
.rbytes
= new_size
;
390 truncate_size
= size
;
395 bool has_layout() const {
396 return layout
!= file_layout_t();
399 void clear_layout() {
400 layout
= file_layout_t();
403 uint64_t get_layout_size_increment() const {
404 return layout
.get_period();
407 bool is_dirty_rstat() const { return !(rstat
== accounted_rstat
); }
409 uint64_t get_client_range(client_t client
) const {
410 auto it
= client_ranges
.find(client
);
411 return it
!= client_ranges
.end() ? it
->second
.range
.last
: 0;
414 uint64_t get_max_size() const {
416 for (std::map
<client_t
,client_writeable_range_t
>::const_iterator p
= client_ranges
.begin();
417 p
!= client_ranges
.end();
419 if (p
->second
.range
.last
> max
)
420 max
= p
->second
.range
.last
;
423 void set_max_size(uint64_t new_max
) {
425 client_ranges
.clear();
427 for (std::map
<client_t
,client_writeable_range_t
>::iterator p
= client_ranges
.begin();
428 p
!= client_ranges
.end();
430 p
->second
.range
.last
= new_max
;
434 void trim_client_ranges(snapid_t last
) {
435 std::map
<client_t
, client_writeable_range_t
>::iterator p
= client_ranges
.begin();
436 while (p
!= client_ranges
.end()) {
437 if (p
->second
.follows
>= last
)
438 client_ranges
.erase(p
++);
444 bool is_backtrace_updated() const {
445 return backtrace_version
== version
;
447 void update_backtrace(version_t pv
=0) {
448 backtrace_version
= pv
? pv
: version
;
451 void add_old_pool(int64_t l
) {
452 backtrace_version
= version
;
456 void encode(ceph::buffer::list
&bl
, uint64_t features
) const;
457 void decode(ceph::buffer::list::const_iterator
& bl
);
458 void dump(ceph::Formatter
*f
) const;
459 static void client_ranges_cb(client_range_map
& c
, JSONObj
*obj
);
460 static void old_pools_cb(compact_set
<int64_t, std::less
<int64_t>, Allocator
<int64_t> >& c
, JSONObj
*obj
);
461 void decode_json(JSONObj
*obj
);
462 static void generate_test_instances(std::list
<inode_t
*>& ls
);
464 * Compare this inode_t with another that represent *the same inode*
465 * at different points in time.
466 * @pre The inodes are the same ino
468 * @param other The inode_t to compare ourselves with
469 * @param divergent A bool pointer which will be set to true
470 * if the values are different in a way that can't be explained
471 * by one being a newer version than the other.
473 * @returns 1 if we are newer than the other, 0 if equal, -1 if older.
475 int compare(const inode_t
&other
, bool *divergent
) const;
479 uint32_t rdev
= 0; // if special file
481 // affected by any inode change...
482 utime_t ctime
; // inode change time
483 utime_t btime
; // birth time
485 // perm (namespace permissions)
493 // file (data access)
494 ceph_dir_layout dir_layout
= {}; // [dir only]
495 file_layout_t layout
;
496 compact_set
<int64_t, std::less
<int64_t>, Allocator
<int64_t>> old_pools
;
497 uint64_t size
= 0; // on directory, # dentries
498 uint64_t max_size_ever
= 0; // max size the file has ever been
499 uint32_t truncate_seq
= 0;
500 uint64_t truncate_size
= 0, truncate_from
= 0;
501 uint32_t truncate_pending
= 0;
502 utime_t mtime
; // file data modify time.
503 utime_t atime
; // file data access time.
504 uint32_t time_warp_seq
= 0; // count of (potential) mtime/atime timewarps (i.e., utimes())
505 inline_data_t inline_data
; // FIXME check
508 uint64_t change_attr
= 0;
510 client_range_map client_ranges
; // client(s) can write to these ranges
512 // dirfrag, recursive accountin
513 frag_info_t dirstat
; // protected by my filelock
514 nest_info_t rstat
; // protected by my nestlock
515 nest_info_t accounted_rstat
; // protected by parent's nestlock
519 mds_rank_t export_pin
= MDS_RANK_NONE
;
521 double export_ephemeral_random_pin
= 0;
522 bool export_ephemeral_distributed_pin
= false;
525 version_t version
= 0; // auth only
526 version_t file_data_version
= 0; // auth only
527 version_t xattr_version
= 0;
529 utime_t last_scrub_stamp
; // start time of last complete scrub
530 version_t last_scrub_version
= 0;// (parent) start version of last complete scrub
532 version_t backtrace_version
= 0;
534 snapid_t oldest_snap
;
536 std::basic_string
<char,std::char_traits
<char>,Allocator
<char>> stray_prior_path
; //stores path before unlink
538 std::vector
<uint8_t> fscrypt_auth
;
539 std::vector
<uint8_t> fscrypt_file
;
541 bufferlist fscrypt_last_block
;
544 bool older_is_consistent(const inode_t
&other
) const;
547 // These methods may be moved back to mdstypes.cc when we have pmr
548 template<template<typename
> class Allocator
>
549 void inode_t
<Allocator
>::encode(ceph::buffer::list
&bl
, uint64_t features
) const
551 ENCODE_START(19, 6, bl
);
565 encode(anchored
, bl
);
568 encode(dir_layout
, bl
);
569 encode(layout
, bl
, features
);
571 encode(truncate_seq
, bl
);
572 encode(truncate_size
, bl
);
573 encode(truncate_from
, bl
);
574 encode(truncate_pending
, bl
);
577 encode(time_warp_seq
, bl
);
578 encode(client_ranges
, bl
);
582 encode(accounted_rstat
, bl
);
585 encode(file_data_version
, bl
);
586 encode(xattr_version
, bl
);
587 encode(backtrace_version
, bl
);
588 encode(old_pools
, bl
);
589 encode(max_size_ever
, bl
);
590 encode(inline_data
, bl
);
593 encode(stray_prior_path
, bl
);
595 encode(last_scrub_version
, bl
);
596 encode(last_scrub_stamp
, bl
);
599 encode(change_attr
, bl
);
601 encode(export_pin
, bl
);
603 encode(export_ephemeral_random_pin
, bl
);
604 encode(export_ephemeral_distributed_pin
, bl
);
606 encode(!fscrypt_auth
.empty(), bl
);
607 encode(fscrypt_auth
, bl
);
608 encode(fscrypt_file
, bl
);
609 encode(fscrypt_last_block
, bl
);
613 template<template<typename
> class Allocator
>
614 void inode_t
<Allocator
>::decode(ceph::buffer::list::const_iterator
&p
)
616 DECODE_START_LEGACY_COMPAT_LEN(19, 6, 6, p
);
633 decode(dir_layout
, p
);
635 // FIPS zeroization audit 20191117: this memset is not security related.
636 memset(&dir_layout
, 0, sizeof(dir_layout
));
640 decode(truncate_seq
, p
);
641 decode(truncate_size
, p
);
642 decode(truncate_from
, p
);
644 decode(truncate_pending
, p
);
646 truncate_pending
= 0;
649 decode(time_warp_seq
, p
);
651 decode(client_ranges
, p
);
653 std::map
<client_t
, client_writeable_range_t::byte_range_t
> m
;
655 for (auto q
= m
.begin(); q
!= m
.end(); ++q
)
656 client_ranges
[q
->first
].range
= q
->second
;
661 decode(accounted_rstat
, p
);
664 decode(file_data_version
, p
);
665 decode(xattr_version
, p
);
667 decode(backtrace_version
, p
);
669 decode(old_pools
, p
);
671 decode(max_size_ever
, p
);
673 decode(inline_data
, p
);
675 inline_data
.version
= CEPH_INLINE_NONE
;
678 backtrace_version
= 0; // force update backtrace
682 if (struct_v
>= 12) {
685 stray_prior_path
= std::string_view(tmp
);
688 if (struct_v
>= 13) {
689 decode(last_scrub_version
, p
);
690 decode(last_scrub_stamp
, p
);
692 if (struct_v
>= 14) {
694 decode(change_attr
, p
);
700 if (struct_v
>= 15) {
701 decode(export_pin
, p
);
703 export_pin
= MDS_RANK_NONE
;
706 if (struct_v
>= 16) {
707 decode(export_ephemeral_random_pin
, p
);
708 decode(export_ephemeral_distributed_pin
, p
);
710 export_ephemeral_random_pin
= 0;
711 export_ephemeral_distributed_pin
= false;
714 if (struct_v
>= 17) {
716 decode(fscrypt_flag
, p
); // ignored
719 if (struct_v
>= 18) {
720 decode(fscrypt_auth
, p
);
721 decode(fscrypt_file
, p
);
724 if (struct_v
>= 19) {
725 decode(fscrypt_last_block
, p
);
730 template<template<typename
> class Allocator
>
731 void inode_t
<Allocator
>::dump(ceph::Formatter
*f
) const
733 f
->dump_unsigned("ino", ino
);
734 f
->dump_unsigned("rdev", rdev
);
735 f
->dump_stream("ctime") << ctime
;
736 f
->dump_stream("btime") << btime
;
737 f
->dump_unsigned("mode", mode
);
738 f
->dump_unsigned("uid", uid
);
739 f
->dump_unsigned("gid", gid
);
740 f
->dump_unsigned("nlink", nlink
);
742 f
->open_object_section("dir_layout");
743 ::dump(dir_layout
, f
);
746 f
->dump_object("layout", layout
);
748 f
->open_array_section("old_pools");
749 for (const auto &p
: old_pools
) {
750 f
->dump_int("pool", p
);
754 f
->dump_unsigned("size", size
);
755 f
->dump_unsigned("truncate_seq", truncate_seq
);
756 f
->dump_unsigned("truncate_size", truncate_size
);
757 f
->dump_unsigned("truncate_from", truncate_from
);
758 f
->dump_unsigned("truncate_pending", truncate_pending
);
759 f
->dump_stream("mtime") << mtime
;
760 f
->dump_stream("atime") << atime
;
761 f
->dump_unsigned("time_warp_seq", time_warp_seq
);
762 f
->dump_unsigned("change_attr", change_attr
);
763 f
->dump_int("export_pin", export_pin
);
764 f
->dump_int("export_ephemeral_random_pin", export_ephemeral_random_pin
);
765 f
->dump_bool("export_ephemeral_distributed_pin", export_ephemeral_distributed_pin
);
767 f
->open_array_section("client_ranges");
768 for (const auto &p
: client_ranges
) {
769 f
->open_object_section("client");
770 f
->dump_unsigned("client", p
.first
.v
);
776 f
->open_object_section("dirstat");
780 f
->open_object_section("rstat");
784 f
->open_object_section("accounted_rstat");
785 accounted_rstat
.dump(f
);
788 f
->dump_unsigned("version", version
);
789 f
->dump_unsigned("file_data_version", file_data_version
);
790 f
->dump_unsigned("xattr_version", xattr_version
);
791 f
->dump_unsigned("backtrace_version", backtrace_version
);
793 f
->dump_string("stray_prior_path", stray_prior_path
);
794 f
->dump_unsigned("max_size_ever", max_size_ever
);
796 f
->open_object_section("quota");
800 f
->dump_stream("last_scrub_stamp") << last_scrub_stamp
;
801 f
->dump_unsigned("last_scrub_version", last_scrub_version
);
804 template<template<typename
> class Allocator
>
805 void inode_t
<Allocator
>::client_ranges_cb(typename inode_t
<Allocator
>::client_range_map
& c
, JSONObj
*obj
){
808 JSONDecoder::decode_json("client", client
, obj
, true);
809 client_writeable_range_t client_range_tmp
;
810 JSONDecoder::decode_json("byte range", client_range_tmp
.range
, obj
, true);
811 JSONDecoder::decode_json("follows", client_range_tmp
.follows
.val
, obj
, true);
812 c
[client
] = client_range_tmp
;
815 template<template<typename
> class Allocator
>
816 void inode_t
<Allocator
>::old_pools_cb(compact_set
<int64_t, std::less
<int64_t>, Allocator
<int64_t> >& c
, JSONObj
*obj
){
819 decode_json_obj(tmp
, obj
);
823 template<template<typename
> class Allocator
>
824 void inode_t
<Allocator
>::decode_json(JSONObj
*obj
)
827 JSONDecoder::decode_json("ino", ino
.val
, obj
, true);
828 JSONDecoder::decode_json("rdev", rdev
, obj
, true);
829 //JSONDecoder::decode_json("ctime", ctime, obj, true);
830 //JSONDecoder::decode_json("btime", btime, obj, true);
831 JSONDecoder::decode_json("mode", mode
, obj
, true);
832 JSONDecoder::decode_json("uid", uid
, obj
, true);
833 JSONDecoder::decode_json("gid", gid
, obj
, true);
834 JSONDecoder::decode_json("nlink", nlink
, obj
, true);
835 JSONDecoder::decode_json("dir_layout", dir_layout
, obj
, true);
836 JSONDecoder::decode_json("layout", layout
, obj
, true);
837 JSONDecoder::decode_json("old_pools", old_pools
, inode_t
<Allocator
>::old_pools_cb
, obj
, true);
838 JSONDecoder::decode_json("size", size
, obj
, true);
839 JSONDecoder::decode_json("truncate_seq", truncate_seq
, obj
, true);
840 JSONDecoder::decode_json("truncate_size", truncate_size
, obj
, true);
841 JSONDecoder::decode_json("truncate_from", truncate_from
, obj
, true);
842 JSONDecoder::decode_json("truncate_pending", truncate_pending
, obj
, true);
843 //JSONDecoder::decode_json("mtime", mtime, obj, true);
844 //JSONDecoder::decode_json("atime", atime, obj, true);
845 JSONDecoder::decode_json("time_warp_seq", time_warp_seq
, obj
, true);
846 JSONDecoder::decode_json("change_attr", change_attr
, obj
, true);
847 JSONDecoder::decode_json("export_pin", export_pin
, obj
, true);
848 JSONDecoder::decode_json("client_ranges", client_ranges
, inode_t
<Allocator
>::client_ranges_cb
, obj
, true);
849 JSONDecoder::decode_json("dirstat", dirstat
, obj
, true);
850 JSONDecoder::decode_json("rstat", rstat
, obj
, true);
851 JSONDecoder::decode_json("accounted_rstat", accounted_rstat
, obj
, true);
852 JSONDecoder::decode_json("version", version
, obj
, true);
853 JSONDecoder::decode_json("file_data_version", file_data_version
, obj
, true);
854 JSONDecoder::decode_json("xattr_version", xattr_version
, obj
, true);
855 JSONDecoder::decode_json("backtrace_version", backtrace_version
, obj
, true);
856 JSONDecoder::decode_json("stray_prior_path", stray_prior_path
, obj
, true);
857 JSONDecoder::decode_json("max_size_ever", max_size_ever
, obj
, true);
858 JSONDecoder::decode_json("quota", quota
, obj
, true);
859 JSONDecoder::decode_json("last_scrub_stamp", last_scrub_stamp
, obj
, true);
860 JSONDecoder::decode_json("last_scrub_version", last_scrub_version
, obj
, true);
863 template<template<typename
> class Allocator
>
864 void inode_t
<Allocator
>::generate_test_instances(std::list
<inode_t
*>& ls
)
866 ls
.push_back(new inode_t
<Allocator
>);
867 ls
.push_back(new inode_t
<Allocator
>);
872 template<template<typename
> class Allocator
>
873 int inode_t
<Allocator
>::compare(const inode_t
<Allocator
> &other
, bool *divergent
) const
875 ceph_assert(ino
== other
.ino
);
877 if (version
== other
.version
) {
878 if (rdev
!= other
.rdev
||
879 ctime
!= other
.ctime
||
880 btime
!= other
.btime
||
881 mode
!= other
.mode
||
884 nlink
!= other
.nlink
||
885 memcmp(&dir_layout
, &other
.dir_layout
, sizeof(dir_layout
)) ||
886 layout
!= other
.layout
||
887 old_pools
!= other
.old_pools
||
888 size
!= other
.size
||
889 max_size_ever
!= other
.max_size_ever
||
890 truncate_seq
!= other
.truncate_seq
||
891 truncate_size
!= other
.truncate_size
||
892 truncate_from
!= other
.truncate_from
||
893 truncate_pending
!= other
.truncate_pending
||
894 change_attr
!= other
.change_attr
||
895 mtime
!= other
.mtime
||
896 atime
!= other
.atime
||
897 time_warp_seq
!= other
.time_warp_seq
||
898 inline_data
!= other
.inline_data
||
899 client_ranges
!= other
.client_ranges
||
900 !(dirstat
== other
.dirstat
) ||
901 !(rstat
== other
.rstat
) ||
902 !(accounted_rstat
== other
.accounted_rstat
) ||
903 file_data_version
!= other
.file_data_version
||
904 xattr_version
!= other
.xattr_version
||
905 backtrace_version
!= other
.backtrace_version
) {
909 } else if (version
> other
.version
) {
910 *divergent
= !older_is_consistent(other
);
913 ceph_assert(version
< other
.version
);
914 *divergent
= !other
.older_is_consistent(*this);
919 template<template<typename
> class Allocator
>
920 bool inode_t
<Allocator
>::older_is_consistent(const inode_t
<Allocator
> &other
) const
922 if (max_size_ever
< other
.max_size_ever
||
923 truncate_seq
< other
.truncate_seq
||
924 time_warp_seq
< other
.time_warp_seq
||
925 inline_data
.version
< other
.inline_data
.version
||
926 dirstat
.version
< other
.dirstat
.version
||
927 rstat
.version
< other
.rstat
.version
||
928 accounted_rstat
.version
< other
.accounted_rstat
.version
||
929 file_data_version
< other
.file_data_version
||
930 xattr_version
< other
.xattr_version
||
931 backtrace_version
< other
.backtrace_version
) {
937 template<template<typename
> class Allocator
>
938 inline void encode(const inode_t
<Allocator
> &c
, ::ceph::buffer::list
&bl
, uint64_t features
)
941 c
.encode(bl
, features
);
942 ENCODE_DUMP_POST(cl
);
944 template<template<typename
> class Allocator
>
945 inline void decode(inode_t
<Allocator
> &c
, ::ceph::buffer::list::const_iterator
&p
)
950 // parse a map of keys/values.
951 namespace qi
= boost::spirit::qi
;
953 template <typename Iterator
>
954 struct keys_and_values
955 : qi::grammar
<Iterator
, std::map
<std::string
, std::string
>()>
958 : keys_and_values::base_type(query
)
960 query
= pair
>> *(qi::lit(' ') >> pair
);
961 pair
= key
>> '=' >> value
;
962 key
= qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
963 value
= +qi::char_("a-zA-Z0-9-_.");
965 qi::rule
<Iterator
, std::map
<std::string
, std::string
>()> query
;
966 qi::rule
<Iterator
, std::pair
<std::string
, std::string
>()> pair
;
967 qi::rule
<Iterator
, std::string()> key
, value
;