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) 2004-2006 Sage Weil <sage@newdream.net>
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.
17 // this is needed for ceph_fs to compile in userland
18 #include "int_types.h"
19 #include "byteorder.h"
23 #include <netinet/in.h>
28 #include "ceph_frag.h"
29 #include "rbd_types.h"
32 #ifndef _BACKWARD_BACKWARD_WARNING_H
33 #define _BACKWARD_BACKWARD_WARNING_H // make gcc 4.3 shut up about hash_*
39 #include <sys/types.h>
47 #include <boost/container/flat_set.hpp>
48 #include <boost/container/flat_map.hpp>
56 #include "include/unordered_map.h"
65 // DARWIN compatibility
67 typedef long long loff_t
;
68 typedef long long off64_t
;
69 #define O_DIRECT 00040000
72 // FreeBSD compatibility
75 typedef off_t off64_t
;
78 #if defined(__sun) || defined(_AIX)
85 // Forward declare all the I/O helpers so strict ADL can find them in
86 // the case of containers of containers. I'm tempted to abstract this
87 // stuff using template templates like I did for denc.
90 template<class A
, class B
>
91 inline std::ostream
& operator<<(std::ostream
&out
, const std::pair
<A
,B
>& v
);
92 template<class A
, class Alloc
>
93 inline std::ostream
& operator<<(std::ostream
& out
, const std::vector
<A
,Alloc
>& v
);
94 template<class A
, std::size_t N
, class Alloc
>
95 inline std::ostream
& operator<<(std::ostream
& out
, const boost::container::small_vector
<A
,N
,Alloc
>& v
);
96 template<class A
, class Comp
, class Alloc
>
97 inline std::ostream
& operator<<(std::ostream
& out
, const std::deque
<A
,Alloc
>& v
);
98 template<typename
... Ts
>
99 inline std::ostream
& operator<<(std::ostream
& out
, const std::tuple
<Ts
...> &t
);
101 inline std::ostream
& operator<<(std::ostream
& out
, const std::optional
<T
> &t
);
102 template<class A
, class Alloc
>
103 inline std::ostream
& operator<<(std::ostream
& out
, const std::list
<A
,Alloc
>& ilist
);
104 template<class A
, class Comp
, class Alloc
>
105 inline std::ostream
& operator<<(std::ostream
& out
, const std::set
<A
, Comp
, Alloc
>& iset
);
106 template<class A
, class Comp
, class Alloc
>
107 inline std::ostream
& operator<<(std::ostream
& out
, const std::multiset
<A
,Comp
,Alloc
>& iset
);
108 template<class A
, class B
, class Comp
, class Alloc
>
109 inline std::ostream
& operator<<(std::ostream
& out
, const std::map
<A
,B
,Comp
,Alloc
>& m
);
110 template<class A
, class B
, class Comp
, class Alloc
>
111 inline std::ostream
& operator<<(std::ostream
& out
, const std::multimap
<A
,B
,Comp
,Alloc
>& m
);
115 template<typename
... Ts
>
116 inline std::ostream
& operator<<(std::ostream
& out
, const boost::tuple
<Ts
...> &t
);
118 namespace container
{
119 template<class A
, class Comp
, class Alloc
>
120 inline std::ostream
& operator<<(std::ostream
& out
, const boost::container::flat_set
<A
, Comp
, Alloc
>& iset
);
121 template<class A
, class B
, class Comp
, class Alloc
>
122 inline std::ostream
& operator<<(std::ostream
& out
, const boost::container::flat_map
<A
, B
, Comp
, Alloc
>& iset
);
127 template<class A
, class B
>
128 inline std::ostream
& operator<<(std::ostream
& out
, const std::pair
<A
,B
>& v
) {
129 return out
<< v
.first
<< "," << v
.second
;
132 template<class A
, class Alloc
>
133 inline std::ostream
& operator<<(std::ostream
& out
, const std::vector
<A
,Alloc
>& v
) {
136 for (const auto& p
: v
) {
137 if (!first
) out
<< ",";
145 template<class A
, std::size_t N
, class Alloc
>
146 inline std::ostream
& operator<<(std::ostream
& out
, const boost::container::small_vector
<A
,N
,Alloc
>& v
) {
149 for (const auto& p
: v
) {
150 if (!first
) out
<< ",";
158 template<class A
, class Alloc
>
159 inline std::ostream
& operator<<(std::ostream
& out
, const std::deque
<A
,Alloc
>& v
) {
161 for (auto p
= v
.begin(); p
!= v
.end(); ++p
) {
162 if (p
!= v
.begin()) out
<< ",";
169 template<typename
... Ts
>
170 inline std::ostream
& operator<<(std::ostream
& out
, const std::tuple
<Ts
...> &t
) {
171 auto f
= [n
= sizeof...(Ts
), i
= 0U, &out
](const auto& e
) mutable {
176 ceph::for_each(t
, f
);
180 // Mimics boost::optional
182 inline std::ostream
& operator<<(std::ostream
& out
, const std::optional
<T
> &t
) {
190 template<class A
, class Alloc
>
191 inline std::ostream
& operator<<(std::ostream
& out
, const std::list
<A
,Alloc
>& ilist
) {
192 for (auto it
= ilist
.begin();
195 if (it
!= ilist
.begin()) out
<< ",";
201 template<class A
, class Comp
, class Alloc
>
202 inline std::ostream
& operator<<(std::ostream
& out
, const std::set
<A
, Comp
, Alloc
>& iset
) {
203 for (auto it
= iset
.begin();
206 if (it
!= iset
.begin()) out
<< ",";
212 template<class A
, class Comp
, class Alloc
>
213 inline std::ostream
& operator<<(std::ostream
& out
, const std::multiset
<A
,Comp
,Alloc
>& iset
) {
214 for (auto it
= iset
.begin();
217 if (it
!= iset
.begin()) out
<< ",";
223 template<class A
, class B
, class Comp
, class Alloc
>
224 inline std::ostream
& operator<<(std::ostream
& out
, const std::map
<A
,B
,Comp
,Alloc
>& m
)
227 for (auto it
= m
.begin();
230 if (it
!= m
.begin()) out
<< ",";
231 out
<< it
->first
<< "=" << it
->second
;
237 template<class A
, class B
, class Comp
, class Alloc
>
238 inline std::ostream
& operator<<(std::ostream
& out
, const std::multimap
<A
,B
,Comp
,Alloc
>& m
)
241 for (auto it
= m
.begin();
244 if (it
!= m
.begin()) out
<< ",";
245 out
<< it
->first
<< "=" << it
->second
;
255 template<typename A
, typename B
, typename C
>
256 inline std::ostream
& operator<<(std::ostream
& out
, const boost::tuples::tuple
<A
, B
, C
> &t
) {
257 return out
<< boost::get
<0>(t
) << ","
258 << boost::get
<1>(t
) << ","
262 namespace container
{
263 template<class A
, class Comp
, class Alloc
>
264 inline std::ostream
& operator<<(std::ostream
& out
, const boost::container::flat_set
<A
, Comp
, Alloc
>& iset
) {
265 for (auto it
= iset
.begin();
268 if (it
!= iset
.begin()) out
<< ",";
274 template<class A
, class B
, class Comp
, class Alloc
>
275 inline std::ostream
& operator<<(std::ostream
& out
, const boost::container::flat_map
<A
, B
, Comp
, Alloc
>& m
) {
276 for (auto it
= m
.begin();
279 if (it
!= m
.begin()) out
<< ",";
280 out
<< it
->first
<< "=" << it
->second
;
290 * comparators for stl containers
292 // for ceph::unordered_map:
293 // ceph::unordered_map<const char*, long, hash<const char*>, eqstr> vals;
296 bool operator()(const char* s1
, const char* s2
) const
298 return strcmp(s1
, s2
) == 0;
305 bool operator()(const char* s1
, const char* s2
) const
307 return strcmp(s1
, s2
) < 0;
316 #include "encoding.h"
318 WRITE_RAW_ENCODER(ceph_fsid
)
319 WRITE_RAW_ENCODER(ceph_file_layout
)
320 WRITE_RAW_ENCODER(ceph_dir_layout
)
321 WRITE_RAW_ENCODER(ceph_mds_session_head
)
322 WRITE_RAW_ENCODER(ceph_mds_request_head_legacy
)
323 WRITE_RAW_ENCODER(ceph_mds_request_release
)
324 WRITE_RAW_ENCODER(ceph_filelock
)
325 WRITE_RAW_ENCODER(ceph_mds_caps_head
)
326 WRITE_RAW_ENCODER(ceph_mds_caps_export_body
)
327 WRITE_RAW_ENCODER(ceph_mds_caps_non_export_body
)
328 WRITE_RAW_ENCODER(ceph_mds_cap_peer
)
329 WRITE_RAW_ENCODER(ceph_mds_cap_release
)
330 WRITE_RAW_ENCODER(ceph_mds_cap_item
)
331 WRITE_RAW_ENCODER(ceph_mds_lease
)
332 WRITE_RAW_ENCODER(ceph_mds_snap_head
)
333 WRITE_RAW_ENCODER(ceph_mds_snap_realm
)
334 WRITE_RAW_ENCODER(ceph_mds_reply_head
)
335 WRITE_RAW_ENCODER(ceph_mds_reply_cap
)
336 WRITE_RAW_ENCODER(ceph_mds_cap_reconnect
)
337 WRITE_RAW_ENCODER(ceph_mds_snaprealm_reconnect
)
338 WRITE_RAW_ENCODER(ceph_frag_tree_split
)
339 WRITE_RAW_ENCODER(ceph_osd_reply_head
)
340 WRITE_RAW_ENCODER(ceph_osd_op
)
341 WRITE_RAW_ENCODER(ceph_msg_header
)
342 WRITE_RAW_ENCODER(ceph_msg_footer
)
343 WRITE_RAW_ENCODER(ceph_msg_footer_old
)
344 WRITE_RAW_ENCODER(ceph_mon_subscribe_item
)
346 WRITE_RAW_ENCODER(ceph_mon_statfs
)
347 WRITE_RAW_ENCODER(ceph_mon_statfs_reply
)
349 // ----------------------
352 // NOTE: these must match ceph_fs.h typedefs
353 typedef uint64_t ceph_tid_t
; // transaction id
354 typedef uint64_t version_t
;
355 typedef __u32 epoch_t
; // map epoch (32bits -> 13 epochs/second for 10 years)
357 // --------------------------------------
358 // identify individual mount clients by 64bit value
363 // cppcheck-suppress noExplicitConstructor
364 client_t(int64_t _v
= -2) : v(_v
) {}
366 void encode(ceph::buffer::list
& bl
) const {
370 void decode(ceph::buffer::list::const_iterator
& bl
) {
375 WRITE_CLASS_ENCODER(client_t
)
377 static inline bool operator==(const client_t
& l
, const client_t
& r
) { return l
.v
== r
.v
; }
378 static inline bool operator!=(const client_t
& l
, const client_t
& r
) { return l
.v
!= r
.v
; }
379 static inline bool operator<(const client_t
& l
, const client_t
& r
) { return l
.v
< r
.v
; }
380 static inline bool operator<=(const client_t
& l
, const client_t
& r
) { return l
.v
<= r
.v
; }
381 static inline bool operator>(const client_t
& l
, const client_t
& r
) { return l
.v
> r
.v
; }
382 static inline bool operator>=(const client_t
& l
, const client_t
& r
) { return l
.v
>= r
.v
; }
384 static inline bool operator>=(const client_t
& l
, int64_t o
) { return l
.v
>= o
; }
385 static inline bool operator<(const client_t
& l
, int64_t o
) { return l
.v
< o
; }
387 inline std::ostream
& operator<<(std::ostream
& out
, const client_t
& c
) {
396 inline std::ostream
& format_u(std::ostream
& out
, const uint64_t v
, const uint64_t n
,
397 const int index
, const uint64_t mult
, const char* u
)
402 (void) snprintf(buffer
, sizeof(buffer
), "%" PRId64
"%s", n
, u
);
403 } else if ((v
% mult
) == 0) {
404 // If this is an even multiple of the base, always display
405 // without any decimal fraction.
406 (void) snprintf(buffer
, sizeof(buffer
), "%" PRId64
"%s", n
, u
);
408 // We want to choose a precision that reflects the best choice
409 // for fitting in 5 characters. This can get rather tricky when
410 // we have numbers that are very close to an order of magnitude.
411 // For example, when displaying 10239 (which is really 9.999K),
412 // we want only a single place of precision for 10.0K. We could
413 // develop some complex heuristics for this, but it's much
414 // easier just to try each combination in turn.
416 for (i
= 2; i
>= 0; i
--) {
417 if (snprintf(buffer
, sizeof(buffer
), "%.*f%s", i
,
418 static_cast<double>(v
) / mult
, u
) <= 7)
423 return out
<< buffer
;
428 * Use this struct to pretty print values that should be formatted with a
429 * decimal unit prefix (the classic SI units). No actual unit will be added.
433 explicit si_u_t(uint64_t _v
) : v(_v
) {};
436 inline std::ostream
& operator<<(std::ostream
& out
, const si_u_t
& b
)
441 const char* u
[] = {"", "k", "M", "G", "T", "P", "E"};
443 while (n
>= 1000 && index
< 7) {
449 return format_u(out
, b
.v
, n
, index
, mult
, u
[index
]);
453 * Use this struct to pretty print values that should be formatted with a
454 * binary unit prefix (IEC units). Since binary unit prefixes are to be used for
455 * "multiples of units in data processing, data transmission, and digital
456 * information" (so bits and bytes) and so far bits are not printed, the unit
457 * "B" for "byte" is added besides the multiplier.
461 explicit byte_u_t(uint64_t _v
) : v(_v
) {};
464 inline std::ostream
& operator<<(std::ostream
& out
, const byte_u_t
& b
)
468 const char* u
[] = {" B", " KiB", " MiB", " GiB", " TiB", " PiB", " EiB"};
470 while (n
>= 1024 && index
< 7) {
475 return format_u(out
, b
.v
, n
, index
, 1ULL << (10 * index
), u
[index
]);
478 inline std::ostream
& operator<<(std::ostream
& out
, const ceph_mon_subscribe_item
& i
)
480 return out
<< (long)i
.start
481 << ((i
.flags
& CEPH_SUBSCRIBE_ONETIME
) ? "" : "+");
486 // cppcheck-suppress noExplicitConstructor
487 weightf_t(float _v
) : v(_v
) {}
490 inline std::ostream
& operator<<(std::ostream
& out
, const weightf_t
& w
)
494 } else if (w
.v
< 0.000001F
) {
497 std::streamsize p
= out
.precision();
498 return out
<< std::fixed
<< std::setprecision(5) << w
.v
<< std::setprecision(p
);
505 shard_id_t() : id(0) {}
506 explicit shard_id_t(int8_t _id
) : id(_id
) {}
508 operator int8_t() const { return id
; }
510 const static shard_id_t NO_SHARD
;
512 void encode(ceph::buffer::list
&bl
) const {
516 void decode(ceph::buffer::list::const_iterator
&bl
) {
521 bool operator==(const shard_id_t
&) const = default;
522 auto operator<=>(const shard_id_t
&) const = default;
524 WRITE_CLASS_ENCODER(shard_id_t
)
525 std::ostream
&operator<<(std::ostream
&lhs
, const shard_id_t
&rhs
);
527 #if defined(__sun) || defined(_AIX) || defined(__APPLE__) || \
528 defined(__FreeBSD__) || defined(_WIN32)
530 __s32
ceph_to_hostos_errno(__s32 e
);
531 __s32
hostos_to_ceph_errno(__s32 e
);
534 #define ceph_to_hostos_errno(e) (e)
535 #define hostos_to_ceph_errno(e) (e)
538 struct errorcode32_t
{
541 errorcode32_t() : code(0) {}
542 // cppcheck-suppress noExplicitConstructor
543 explicit errorcode32_t(int32_t i
) : code(i
) {}
545 operator int() const { return code
; }
546 int* operator&() { return &code
; }
547 errorcode32_t
& operator=(int32_t i
) {
551 bool operator==(const errorcode32_t
&) const = default;
552 auto operator<=>(const errorcode32_t
&) const = default;
554 void encode(ceph::buffer::list
&bl
) const {
556 __s32 newcode
= hostos_to_ceph_errno(code
);
559 void decode(ceph::buffer::list::const_iterator
&bl
) {
562 code
= ceph_to_hostos_errno(code
);
565 WRITE_CLASS_ENCODER(errorcode32_t
)
568 struct sha_digest_t
{
569 constexpr static uint32_t SIZE
= S
;
570 // TODO: we might consider std::array in the future. Avoiding it for now
571 // as sha_digest_t is a part of our public API.
572 unsigned char v
[S
] = {0};
574 std::string
to_str() const {
575 char str
[S
* 2 + 1] = {0};
577 for (size_t i
= 0; i
< S
; i
++) {
578 ::sprintf(&str
[i
* 2], "%02x", static_cast<int>(v
[i
]));
580 return std::string(str
);
582 sha_digest_t(const unsigned char *_v
) { memcpy(v
, _v
, SIZE
); };
585 bool operator==(const sha_digest_t
& r
) const {
586 return ::memcmp(v
, r
.v
, SIZE
) == 0;
588 bool operator!=(const sha_digest_t
& r
) const {
589 return ::memcmp(v
, r
.v
, SIZE
) != 0;
592 void encode(ceph::buffer::list
&bl
) const {
593 // copy to avoid reinterpret_cast, is_pod and other nasty things
595 std::array
<unsigned char, SIZE
> tmparr
;
596 memcpy(tmparr
.data(), v
, SIZE
);
599 void decode(ceph::buffer::list::const_iterator
&bl
) {
601 std::array
<unsigned char, SIZE
> tmparr
;
603 memcpy(v
, tmparr
.data(), SIZE
);
608 inline std::ostream
&operator<<(std::ostream
&out
, const sha_digest_t
<S
> &b
) {
609 std::string str
= b
.to_str();
613 #if FMT_VERSION >= 90000
614 template <uint8_t S
> struct fmt::formatter
<sha_digest_t
<S
>> : fmt::ostream_formatter
{};
617 using sha1_digest_t
= sha_digest_t
<20>;
618 WRITE_CLASS_ENCODER(sha1_digest_t
)
620 using sha256_digest_t
= sha_digest_t
<32>;
621 WRITE_CLASS_ENCODER(sha256_digest_t
)
623 using sha512_digest_t
= sha_digest_t
<64>;
625 using md5_digest_t
= sha_digest_t
<16>;
626 WRITE_CLASS_ENCODER(md5_digest_t
)