]> git.proxmox.com Git - ceph.git/blob - ceph/src/include/cephfs/types.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / include / cephfs / types.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2020 Red Hat, Inc.
7 *
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.
12 */
13 #ifndef CEPH_CEPHFS_TYPES_H
14 #define CEPH_CEPHFS_TYPES_H
15 #include "include/int_types.h"
16
17 #include <ostream>
18 #include <set>
19 #include <map>
20 #include <string_view>
21
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"
27
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"
36
37 #include "mds/inode_backtrace.h"
38
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"
44
45 #define CEPH_FS_ONDISK_MAGIC "ceph fs volume v011"
46 #define MAX_MDS 0x100
47
48 BOOST_STRONG_TYPEDEF(uint64_t, mds_gid_t)
49 extern const mds_gid_t MDS_GID_NONE;
50
51 typedef int32_t fs_cluster_id_t;
52 constexpr fs_cluster_id_t FS_CLUSTER_ID_NONE = -1;
53
54 // The namespace ID of the anonymous default filesystem from legacy systems
55 constexpr fs_cluster_id_t FS_CLUSTER_ID_ANONYMOUS = 0;
56
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;
61
62 struct scatter_info_t {
63 version_t version = 0;
64 };
65
66 struct frag_info_t : public scatter_info_t {
67 int64_t size() const { return nfiles + nsubdirs; }
68
69 void zero() {
70 *this = frag_info_t();
71 }
72
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) {
76 mtime = cur.mtime;
77 if (touched_mtime)
78 *touched_mtime = true;
79 }
80 if (cur.change_attr > change_attr) {
81 change_attr = cur.change_attr;
82 if (touched_chattr)
83 *touched_chattr = true;
84 }
85 nfiles += cur.nfiles - acc.nfiles;
86 nsubdirs += cur.nsubdirs - acc.nsubdirs;
87 }
88
89 void add(const frag_info_t& other) {
90 if (other.mtime > mtime)
91 mtime = other.mtime;
92 if (other.change_attr > change_attr)
93 change_attr = other.change_attr;
94 nfiles += other.nfiles;
95 nsubdirs += other.nsubdirs;
96 }
97
98 bool same_sums(const frag_info_t &o) const {
99 return mtime <= o.mtime &&
100 nfiles == o.nfiles &&
101 nsubdirs == o.nsubdirs;
102 }
103
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);
109
110 // this frag
111 utime_t mtime;
112 uint64_t change_attr = 0;
113 int64_t nfiles = 0; // files
114 int64_t nsubdirs = 0; // subdirs
115 };
116 WRITE_CLASS_ENCODER(frag_info_t)
117
118 inline bool operator==(const frag_info_t &l, const frag_info_t &r) {
119 return memcmp(&l, &r, sizeof(l)) == 0;
120 }
121 inline bool operator!=(const frag_info_t &l, const frag_info_t &r) {
122 return !(l == r);
123 }
124
125 std::ostream& operator<<(std::ostream &out, const frag_info_t &f);
126
127 struct nest_info_t : public scatter_info_t {
128 int64_t rsize() const { return rfiles + rsubdirs; }
129
130 void zero() {
131 *this = nest_info_t();
132 }
133
134 void sub(const nest_info_t &other) {
135 add(other, -1);
136 }
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;
144 }
145
146 // *this += cur - acc;
147 void add_delta(const nest_info_t &cur, const nest_info_t &acc) {
148 if (cur.rctime > rctime)
149 rctime = cur.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;
154 }
155
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 &&
161 rsnaps == o.rsnaps;
162 }
163
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);
169
170 // this frag + children
171 utime_t rctime;
172 int64_t rbytes = 0;
173 int64_t rfiles = 0;
174 int64_t rsubdirs = 0;
175 int64_t rsnaps = 0;
176 };
177 WRITE_CLASS_ENCODER(nest_info_t)
178
179 inline bool operator==(const nest_info_t &l, const nest_info_t &r) {
180 return memcmp(&l, &r, sizeof(l)) == 0;
181 }
182 inline bool operator!=(const nest_info_t &l, const nest_info_t &r) {
183 return !(l == r);
184 }
185
186 std::ostream& operator<<(std::ostream &out, const nest_info_t &n);
187
188 struct vinodeno_t {
189 vinodeno_t() {}
190 vinodeno_t(inodeno_t i, snapid_t s) : ino(i), snapid(s) {}
191
192 void encode(ceph::buffer::list& bl) const {
193 using ceph::encode;
194 encode(ino, bl);
195 encode(snapid, bl);
196 }
197 void decode(ceph::buffer::list::const_iterator& p) {
198 using ceph::decode;
199 decode(ino, p);
200 decode(snapid, p);
201 }
202
203 inodeno_t ino;
204 snapid_t snapid;
205 };
206 WRITE_CLASS_ENCODER(vinodeno_t)
207
208 inline bool operator==(const vinodeno_t &l, const vinodeno_t &r) {
209 return l.ino == r.ino && l.snapid == r.snapid;
210 }
211 inline bool operator!=(const vinodeno_t &l, const vinodeno_t &r) {
212 return !(l == r);
213 }
214 inline bool operator<(const vinodeno_t &l, const vinodeno_t &r) {
215 return
216 l.ino < r.ino ||
217 (l.ino == r.ino && l.snapid < r.snapid);
218 }
219
220 typedef enum {
221 QUOTA_MAX_FILES,
222 QUOTA_MAX_BYTES,
223 QUOTA_ANY
224 } quota_max_t;
225
226 struct quota_info_t
227 {
228 void encode(ceph::buffer::list& bl) const {
229 ENCODE_START(1, 1, bl);
230 encode(max_bytes, bl);
231 encode(max_files, bl);
232 ENCODE_FINISH(bl);
233 }
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);
238 DECODE_FINISH(p);
239 }
240
241 void dump(ceph::Formatter *f) const;
242 static void generate_test_instances(std::list<quota_info_t *>& ls);
243
244 bool is_valid() const {
245 return max_bytes >=0 && max_files >=0;
246 }
247 bool is_enabled(quota_max_t type=QUOTA_ANY) const {
248 switch (type) {
249 case QUOTA_MAX_FILES:
250 return !!max_files;
251 case QUOTA_MAX_BYTES:
252 return !!max_bytes;
253 case QUOTA_ANY:
254 default:
255 return !!max_bytes || !!max_files;
256 }
257 }
258 void decode_json(JSONObj *obj);
259
260 int64_t max_bytes = 0;
261 int64_t max_files = 0;
262 };
263 WRITE_CLASS_ENCODER(quota_info_t)
264
265 inline bool operator==(const quota_info_t &l, const quota_info_t &r) {
266 return memcmp(&l, &r, sizeof(l)) == 0;
267 }
268
269 std::ostream& operator<<(std::ostream &out, const quota_info_t &n);
270
271 struct client_writeable_range_t {
272 struct byte_range_t {
273 uint64_t first = 0, last = 0; // interval client can write to
274 byte_range_t() {}
275 void decode_json(JSONObj *obj);
276 };
277
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);
282
283 byte_range_t range;
284 snapid_t follows = 0; // aka "data+metadata flushed thru"
285 };
286
287 inline void decode(client_writeable_range_t::byte_range_t& range, ceph::buffer::list::const_iterator& bl) {
288 using ceph::decode;
289 decode(range.first, bl);
290 decode(range.last, bl);
291 }
292
293 WRITE_CLASS_ENCODER(client_writeable_range_t)
294
295 std::ostream& operator<<(std::ostream& out, const client_writeable_range_t& r);
296
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;
301 }
302
303 struct inline_data_t {
304 public:
305 inline_data_t() {}
306 inline_data_t(const inline_data_t& o) : version(o.version) {
307 if (o.blp)
308 set_data(*o.blp);
309 }
310 inline_data_t& operator=(const inline_data_t& o) {
311 version = o.version;
312 if (o.blp)
313 set_data(*o.blp);
314 else
315 free_data();
316 return *this;
317 }
318
319 void free_data() {
320 blp.reset();
321 }
322 void get_data(ceph::buffer::list& ret) const {
323 if (blp)
324 ret = *blp;
325 else
326 ret.clear();
327 }
328 void set_data(const ceph::buffer::list& bl) {
329 if (!blp)
330 blp.reset(new ceph::buffer::list);
331 *blp = bl;
332 }
333 size_t length() const { return blp ? blp->length() : 0; }
334
335 bool operator==(const inline_data_t& o) const {
336 return length() == o.length() &&
337 (length() == 0 ||
338 (*const_cast<ceph::buffer::list*>(blp.get()) == *const_cast<ceph::buffer::list*>(o.blp.get())));
339 }
340 bool operator!=(const inline_data_t& o) const {
341 return !(*this == o);
342 }
343 void encode(ceph::buffer::list &bl) const;
344 void decode(ceph::buffer::list::const_iterator& bl);
345
346 version_t version = 1;
347
348 private:
349 std::unique_ptr<ceph::buffer::list> blp;
350 };
351 WRITE_CLASS_ENCODER(inline_data_t)
352
353 enum {
354 DAMAGE_STATS, // statistics (dirstat, size, etc)
355 DAMAGE_RSTATS, // recursive statistics (rstat, accounted_rstat)
356 DAMAGE_FRAGTREE // fragtree -- repair by searching
357 };
358
359 template<template<typename> class Allocator = std::allocator>
360 struct inode_t {
361 /**
362 * ***************
363 * Do not forget to add any new fields to the compare() function.
364 * ***************
365 */
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>>>;
367
368 inode_t()
369 {
370 clear_layout();
371 }
372
373 // file type
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; }
377
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;
382 }
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;
388 size = new_size;
389 rstat.rbytes = new_size;
390 truncate_size = size;
391 truncate_seq++;
392 truncate_pending++;
393 }
394
395 bool has_layout() const {
396 return layout != file_layout_t();
397 }
398
399 void clear_layout() {
400 layout = file_layout_t();
401 }
402
403 uint64_t get_layout_size_increment() const {
404 return layout.get_period();
405 }
406
407 bool is_dirty_rstat() const { return !(rstat == accounted_rstat); }
408
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;
412 }
413
414 uint64_t get_max_size() const {
415 uint64_t max = 0;
416 for (std::map<client_t,client_writeable_range_t>::const_iterator p = client_ranges.begin();
417 p != client_ranges.end();
418 ++p)
419 if (p->second.range.last > max)
420 max = p->second.range.last;
421 return max;
422 }
423 void set_max_size(uint64_t new_max) {
424 if (new_max == 0) {
425 client_ranges.clear();
426 } else {
427 for (std::map<client_t,client_writeable_range_t>::iterator p = client_ranges.begin();
428 p != client_ranges.end();
429 ++p)
430 p->second.range.last = new_max;
431 }
432 }
433
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++);
439 else
440 ++p;
441 }
442 }
443
444 bool is_backtrace_updated() const {
445 return backtrace_version == version;
446 }
447 void update_backtrace(version_t pv=0) {
448 backtrace_version = pv ? pv : version;
449 }
450
451 void add_old_pool(int64_t l) {
452 backtrace_version = version;
453 old_pools.insert(l);
454 }
455
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);
463 /**
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
467 *
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.
472 *
473 * @returns 1 if we are newer than the other, 0 if equal, -1 if older.
474 */
475 int compare(const inode_t &other, bool *divergent) const;
476
477 // base (immutable)
478 inodeno_t ino = 0;
479 uint32_t rdev = 0; // if special file
480
481 // affected by any inode change...
482 utime_t ctime; // inode change time
483 utime_t btime; // birth time
484
485 // perm (namespace permissions)
486 uint32_t mode = 0;
487 uid_t uid = 0;
488 gid_t gid = 0;
489
490 // nlink
491 int32_t nlink = 0;
492
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
506
507 // change attribute
508 uint64_t change_attr = 0;
509
510 client_range_map client_ranges; // client(s) can write to these ranges
511
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
516
517 quota_info_t quota;
518
519 mds_rank_t export_pin = MDS_RANK_NONE;
520
521 double export_ephemeral_random_pin = 0;
522 bool export_ephemeral_distributed_pin = false;
523
524 // special stuff
525 version_t version = 0; // auth only
526 version_t file_data_version = 0; // auth only
527 version_t xattr_version = 0;
528
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
531
532 version_t backtrace_version = 0;
533
534 snapid_t oldest_snap;
535
536 std::basic_string<char,std::char_traits<char>,Allocator<char>> stray_prior_path; //stores path before unlink
537
538 std::vector<uint8_t> fscrypt_auth;
539 std::vector<uint8_t> fscrypt_file;
540
541 bufferlist fscrypt_last_block;
542
543 private:
544 bool older_is_consistent(const inode_t &other) const;
545 };
546
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
550 {
551 ENCODE_START(19, 6, bl);
552
553 encode(ino, bl);
554 encode(rdev, bl);
555 encode(ctime, bl);
556
557 encode(mode, bl);
558 encode(uid, bl);
559 encode(gid, bl);
560
561 encode(nlink, bl);
562 {
563 // removed field
564 bool anchored = 0;
565 encode(anchored, bl);
566 }
567
568 encode(dir_layout, bl);
569 encode(layout, bl, features);
570 encode(size, bl);
571 encode(truncate_seq, bl);
572 encode(truncate_size, bl);
573 encode(truncate_from, bl);
574 encode(truncate_pending, bl);
575 encode(mtime, bl);
576 encode(atime, bl);
577 encode(time_warp_seq, bl);
578 encode(client_ranges, bl);
579
580 encode(dirstat, bl);
581 encode(rstat, bl);
582 encode(accounted_rstat, bl);
583
584 encode(version, 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);
591 encode(quota, bl);
592
593 encode(stray_prior_path, bl);
594
595 encode(last_scrub_version, bl);
596 encode(last_scrub_stamp, bl);
597
598 encode(btime, bl);
599 encode(change_attr, bl);
600
601 encode(export_pin, bl);
602
603 encode(export_ephemeral_random_pin, bl);
604 encode(export_ephemeral_distributed_pin, bl);
605
606 encode(!fscrypt_auth.empty(), bl);
607 encode(fscrypt_auth, bl);
608 encode(fscrypt_file, bl);
609 encode(fscrypt_last_block, bl);
610 ENCODE_FINISH(bl);
611 }
612
613 template<template<typename> class Allocator>
614 void inode_t<Allocator>::decode(ceph::buffer::list::const_iterator &p)
615 {
616 DECODE_START_LEGACY_COMPAT_LEN(19, 6, 6, p);
617
618 decode(ino, p);
619 decode(rdev, p);
620 decode(ctime, p);
621
622 decode(mode, p);
623 decode(uid, p);
624 decode(gid, p);
625
626 decode(nlink, p);
627 {
628 bool anchored;
629 decode(anchored, p);
630 }
631
632 if (struct_v >= 4)
633 decode(dir_layout, p);
634 else {
635 // FIPS zeroization audit 20191117: this memset is not security related.
636 memset(&dir_layout, 0, sizeof(dir_layout));
637 }
638 decode(layout, p);
639 decode(size, p);
640 decode(truncate_seq, p);
641 decode(truncate_size, p);
642 decode(truncate_from, p);
643 if (struct_v >= 5)
644 decode(truncate_pending, p);
645 else
646 truncate_pending = 0;
647 decode(mtime, p);
648 decode(atime, p);
649 decode(time_warp_seq, p);
650 if (struct_v >= 3) {
651 decode(client_ranges, p);
652 } else {
653 std::map<client_t, client_writeable_range_t::byte_range_t> m;
654 decode(m, p);
655 for (auto q = m.begin(); q != m.end(); ++q)
656 client_ranges[q->first].range = q->second;
657 }
658
659 decode(dirstat, p);
660 decode(rstat, p);
661 decode(accounted_rstat, p);
662
663 decode(version, p);
664 decode(file_data_version, p);
665 decode(xattr_version, p);
666 if (struct_v >= 2)
667 decode(backtrace_version, p);
668 if (struct_v >= 7)
669 decode(old_pools, p);
670 if (struct_v >= 8)
671 decode(max_size_ever, p);
672 if (struct_v >= 9) {
673 decode(inline_data, p);
674 } else {
675 inline_data.version = CEPH_INLINE_NONE;
676 }
677 if (struct_v < 10)
678 backtrace_version = 0; // force update backtrace
679 if (struct_v >= 11)
680 decode(quota, p);
681
682 if (struct_v >= 12) {
683 std::string tmp;
684 decode(tmp, p);
685 stray_prior_path = std::string_view(tmp);
686 }
687
688 if (struct_v >= 13) {
689 decode(last_scrub_version, p);
690 decode(last_scrub_stamp, p);
691 }
692 if (struct_v >= 14) {
693 decode(btime, p);
694 decode(change_attr, p);
695 } else {
696 btime = utime_t();
697 change_attr = 0;
698 }
699
700 if (struct_v >= 15) {
701 decode(export_pin, p);
702 } else {
703 export_pin = MDS_RANK_NONE;
704 }
705
706 if (struct_v >= 16) {
707 decode(export_ephemeral_random_pin, p);
708 decode(export_ephemeral_distributed_pin, p);
709 } else {
710 export_ephemeral_random_pin = 0;
711 export_ephemeral_distributed_pin = false;
712 }
713
714 if (struct_v >= 17) {
715 bool fscrypt_flag;
716 decode(fscrypt_flag, p); // ignored
717 }
718
719 if (struct_v >= 18) {
720 decode(fscrypt_auth, p);
721 decode(fscrypt_file, p);
722 }
723
724 if (struct_v >= 19) {
725 decode(fscrypt_last_block, p);
726 }
727 DECODE_FINISH(p);
728 }
729
730 template<template<typename> class Allocator>
731 void inode_t<Allocator>::dump(ceph::Formatter *f) const
732 {
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);
741
742 f->open_object_section("dir_layout");
743 ::dump(dir_layout, f);
744 f->close_section();
745
746 f->dump_object("layout", layout);
747
748 f->open_array_section("old_pools");
749 for (const auto &p : old_pools) {
750 f->dump_int("pool", p);
751 }
752 f->close_section();
753
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);
766
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);
771 p.second.dump(f);
772 f->close_section();
773 }
774 f->close_section();
775
776 f->open_object_section("dirstat");
777 dirstat.dump(f);
778 f->close_section();
779
780 f->open_object_section("rstat");
781 rstat.dump(f);
782 f->close_section();
783
784 f->open_object_section("accounted_rstat");
785 accounted_rstat.dump(f);
786 f->close_section();
787
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);
792
793 f->dump_string("stray_prior_path", stray_prior_path);
794 f->dump_unsigned("max_size_ever", max_size_ever);
795
796 f->open_object_section("quota");
797 quota.dump(f);
798 f->close_section();
799
800 f->dump_stream("last_scrub_stamp") << last_scrub_stamp;
801 f->dump_unsigned("last_scrub_version", last_scrub_version);
802 }
803
804 template<template<typename> class Allocator>
805 void inode_t<Allocator>::client_ranges_cb(typename inode_t<Allocator>::client_range_map& c, JSONObj *obj){
806
807 int64_t client;
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;
813 }
814
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){
817
818 int64_t tmp;
819 decode_json_obj(tmp, obj);
820 c.insert(tmp);
821 }
822
823 template<template<typename> class Allocator>
824 void inode_t<Allocator>::decode_json(JSONObj *obj)
825 {
826
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);
861 }
862
863 template<template<typename> class Allocator>
864 void inode_t<Allocator>::generate_test_instances(std::list<inode_t*>& ls)
865 {
866 ls.push_back(new inode_t<Allocator>);
867 ls.push_back(new inode_t<Allocator>);
868 ls.back()->ino = 1;
869 // i am lazy.
870 }
871
872 template<template<typename> class Allocator>
873 int inode_t<Allocator>::compare(const inode_t<Allocator> &other, bool *divergent) const
874 {
875 ceph_assert(ino == other.ino);
876 *divergent = false;
877 if (version == other.version) {
878 if (rdev != other.rdev ||
879 ctime != other.ctime ||
880 btime != other.btime ||
881 mode != other.mode ||
882 uid != other.uid ||
883 gid != other.gid ||
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) {
906 *divergent = true;
907 }
908 return 0;
909 } else if (version > other.version) {
910 *divergent = !older_is_consistent(other);
911 return 1;
912 } else {
913 ceph_assert(version < other.version);
914 *divergent = !other.older_is_consistent(*this);
915 return -1;
916 }
917 }
918
919 template<template<typename> class Allocator>
920 bool inode_t<Allocator>::older_is_consistent(const inode_t<Allocator> &other) const
921 {
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) {
932 return false;
933 }
934 return true;
935 }
936
937 template<template<typename> class Allocator>
938 inline void encode(const inode_t<Allocator> &c, ::ceph::buffer::list &bl, uint64_t features)
939 {
940 ENCODE_DUMP_PRE();
941 c.encode(bl, features);
942 ENCODE_DUMP_POST(cl);
943 }
944 template<template<typename> class Allocator>
945 inline void decode(inode_t<Allocator> &c, ::ceph::buffer::list::const_iterator &p)
946 {
947 c.decode(p);
948 }
949
950 // parse a map of keys/values.
951 namespace qi = boost::spirit::qi;
952
953 template <typename Iterator>
954 struct keys_and_values
955 : qi::grammar<Iterator, std::map<std::string, std::string>()>
956 {
957 keys_and_values()
958 : keys_and_values::base_type(query)
959 {
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-_.");
964 }
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;
968 };
969
970 #endif