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.
15 #ifndef CEPH_MCLIENTCAPS_H
16 #define CEPH_MCLIENTCAPS_H
18 #include "msg/Message.h"
19 #include "mds/mdstypes.h"
20 #include "include/ceph_features.h"
22 class MClientCaps final
: public SafeMessage
{
25 static constexpr int HEAD_VERSION
= 11;
26 static constexpr int COMPAT_VERSION
= 1;
29 static constexpr unsigned FLAG_SYNC
= (1<<0);
30 static constexpr unsigned FLAG_NO_CAPSNAP
= (1<<1); // unused
31 static constexpr unsigned FLAG_PENDING_CAPSNAP
= (1<<2);
33 struct ceph_mds_caps_head head
;
36 uint64_t max_size
= 0;
37 uint64_t truncate_size
= 0;
38 uint64_t change_attr
= 0;
39 uint32_t truncate_seq
= 0;
40 utime_t mtime
, atime
, ctime
, btime
;
41 uint32_t time_warp_seq
= 0;
42 int64_t nfiles
= -1; // files in dir
43 int64_t nsubdirs
= -1; // subdirs in dir
45 struct ceph_mds_cap_peer peer
;
47 ceph::buffer::list snapbl
;
48 ceph::buffer::list xattrbl
;
49 ceph::buffer::list flockbl
;
50 version_t inline_version
= 0;
51 ceph::buffer::list inline_data
;
53 // Receivers may not use their new caps until they have this OSD map
54 epoch_t osd_epoch_barrier
= 0;
55 ceph_tid_t oldest_flush_tid
= 0;
56 uint32_t caller_uid
= 0;
57 uint32_t caller_gid
= 0;
59 /* advisory CLIENT_CAPS_* flags to send to mds */
62 int get_caps() const { return head
.caps
; }
63 int get_wanted() const { return head
.wanted
; }
64 int get_dirty() const { return head
.dirty
; }
65 ceph_seq_t
get_seq() const { return head
.seq
; }
66 ceph_seq_t
get_issue_seq() const { return head
.issue_seq
; }
67 ceph_seq_t
get_mseq() const { return head
.migrate_seq
; }
69 inodeno_t
get_ino() const { return inodeno_t(head
.ino
); }
70 inodeno_t
get_realm() const { return inodeno_t(head
.realm
); }
71 uint64_t get_cap_id() const { return head
.cap_id
; }
73 uint64_t get_size() const { return size
; }
74 uint64_t get_max_size() const { return max_size
; }
75 __u32
get_truncate_seq() const { return truncate_seq
; }
76 uint64_t get_truncate_size() const { return truncate_size
; }
77 utime_t
get_ctime() const { return ctime
; }
78 utime_t
get_btime() const { return btime
; }
79 utime_t
get_mtime() const { return mtime
; }
80 utime_t
get_atime() const { return atime
; }
81 __u64
get_change_attr() const { return change_attr
; }
82 __u32
get_time_warp_seq() const { return time_warp_seq
; }
83 uint64_t get_nfiles() const { return nfiles
; }
84 uint64_t get_nsubdirs() const { return nsubdirs
; }
85 bool dirstat_is_valid() const { return nfiles
!= -1 || nsubdirs
!= -1; }
87 const file_layout_t
& get_layout() const {
91 void set_layout(const file_layout_t
&l
) {
95 int get_migrate_seq() const { return head
.migrate_seq
; }
96 int get_op() const { return head
.op
; }
98 uint64_t get_client_tid() const { return get_tid(); }
99 void set_client_tid(uint64_t s
) { set_tid(s
); }
101 snapid_t
get_snap_follows() const { return snapid_t(head
.snap_follows
); }
102 void set_snap_follows(snapid_t s
) { head
.snap_follows
= s
; }
104 void set_caps(int c
) { head
.caps
= c
; }
105 void set_wanted(int w
) { head
.wanted
= w
; }
107 void set_max_size(uint64_t ms
) { max_size
= ms
; }
109 void set_migrate_seq(unsigned m
) { head
.migrate_seq
= m
; }
110 void set_op(int o
) { head
.op
= o
; }
112 void set_size(loff_t s
) { size
= s
; }
113 void set_mtime(const utime_t
&t
) { mtime
= t
; }
114 void set_ctime(const utime_t
&t
) { ctime
= t
; }
115 void set_atime(const utime_t
&t
) { atime
= t
; }
117 void set_cap_peer(uint64_t id
, ceph_seq_t seq
, ceph_seq_t mseq
, int mds
, int flags
) {
125 void set_oldest_flush_tid(ceph_tid_t tid
) { oldest_flush_tid
= tid
; }
126 ceph_tid_t
get_oldest_flush_tid() const { return oldest_flush_tid
; }
128 void clear_dirty() { head
.dirty
= 0; }
132 : SafeMessage
{CEPH_MSG_CLIENT_CAPS
, HEAD_VERSION
, COMPAT_VERSION
} {}
143 : SafeMessage
{CEPH_MSG_CLIENT_CAPS
, HEAD_VERSION
, COMPAT_VERSION
},
144 osd_epoch_barrier(oeb
) {
145 memset(&head
, 0, sizeof(head
));
152 head
.wanted
= wanted
;
154 head
.migrate_seq
= mseq
;
155 memset(&peer
, 0, sizeof(peer
));
158 inodeno_t ino
, inodeno_t realm
,
159 uint64_t id
, int mseq
, epoch_t oeb
)
160 : SafeMessage
{CEPH_MSG_CLIENT_CAPS
, HEAD_VERSION
, COMPAT_VERSION
},
161 osd_epoch_barrier(oeb
) {
162 memset(&head
, 0, sizeof(head
));
167 head
.migrate_seq
= mseq
;
168 memset(&peer
, 0, sizeof(peer
));
170 ~MClientCaps() final
{}
173 file_layout_t layout
;
176 std::string_view
get_type_name() const override
{ return "Cfcap";}
177 void print(std::ostream
& out
) const override
{
178 out
<< "client_caps(" << ceph_cap_op_name(head
.op
)
179 << " ino " << inodeno_t(head
.ino
)
180 << " " << head
.cap_id
181 << " seq " << head
.seq
;
183 out
<< " tid " << get_tid();
184 out
<< " caps=" << ccap_string(head
.caps
)
185 << " dirty=" << ccap_string(head
.dirty
)
186 << " wanted=" << ccap_string(head
.wanted
);
187 out
<< " follows " << snapid_t(head
.snap_follows
);
188 if (head
.migrate_seq
)
189 out
<< " mseq " << head
.migrate_seq
;
191 out
<< " size " << size
<< "/" << max_size
;
193 out
<< " ts " << truncate_seq
<< "/" << truncate_size
;
194 out
<< " mtime " << mtime
195 << " ctime " << ctime
196 << " change_attr " << change_attr
;
198 out
<< " tws " << time_warp_seq
;
200 if (head
.xattr_version
)
201 out
<< " xattrs(v=" << head
.xattr_version
<< " l=" << xattrbl
.length() << ")";
206 void decode_payload() override
{
208 auto p
= payload
.cbegin();
210 if (head
.op
== CEPH_CAP_OP_EXPORT
) {
211 ceph_mds_caps_export_body body
;
214 p
+= (sizeof(ceph_mds_caps_non_export_body
) -
215 sizeof(ceph_mds_caps_export_body
));
217 ceph_mds_caps_non_export_body body
;
220 max_size
= body
.max_size
;
221 truncate_size
= body
.truncate_size
;
222 truncate_seq
= body
.truncate_seq
;
223 mtime
= utime_t(body
.mtime
);
224 atime
= utime_t(body
.atime
);
225 ctime
= utime_t(body
.ctime
);
226 layout
.from_legacy(body
.layout
);
227 time_warp_seq
= body
.time_warp_seq
;
229 ceph::decode_nohead(head
.snap_trace_len
, snapbl
, p
);
231 ceph_assert(middle
.length() == head
.xattr_len
);
235 // conditionally decode flock metadata
236 if (header
.version
>= 2)
239 if (header
.version
>= 3) {
240 if (head
.op
== CEPH_CAP_OP_IMPORT
)
244 if (header
.version
>= 4) {
245 decode(inline_version
, p
);
246 decode(inline_data
, p
);
248 inline_version
= CEPH_INLINE_NONE
;
251 if (header
.version
>= 5) {
252 decode(osd_epoch_barrier
, p
);
254 if (header
.version
>= 6) {
255 decode(oldest_flush_tid
, p
);
257 if (header
.version
>= 7) {
258 decode(caller_uid
, p
);
259 decode(caller_gid
, p
);
261 if (header
.version
>= 8) {
262 decode(layout
.pool_ns
, p
);
264 if (header
.version
>= 9) {
266 decode(change_attr
, p
);
268 if (header
.version
>= 10) {
271 if (header
.version
>= 11) {
276 void encode_payload(uint64_t features
) override
{
278 header
.version
= HEAD_VERSION
;
279 head
.snap_trace_len
= snapbl
.length();
280 head
.xattr_len
= xattrbl
.length();
282 encode(head
, payload
);
283 static_assert(sizeof(ceph_mds_caps_non_export_body
) >
284 sizeof(ceph_mds_caps_export_body
));
285 if (head
.op
== CEPH_CAP_OP_EXPORT
) {
286 ceph_mds_caps_export_body body
;
288 encode(body
, payload
);
289 payload
.append_zero(sizeof(ceph_mds_caps_non_export_body
) -
290 sizeof(ceph_mds_caps_export_body
));
292 ceph_mds_caps_non_export_body body
;
294 body
.max_size
= max_size
;
295 body
.truncate_size
= truncate_size
;
296 body
.truncate_seq
= truncate_seq
;
297 mtime
.encode_timeval(&body
.mtime
);
298 atime
.encode_timeval(&body
.atime
);
299 ctime
.encode_timeval(&body
.ctime
);
300 layout
.to_legacy(&body
.layout
);
301 body
.time_warp_seq
= time_warp_seq
;
302 encode(body
, payload
);
304 ceph::encode_nohead(snapbl
, payload
);
308 // conditionally include flock metadata
309 if (features
& CEPH_FEATURE_FLOCK
) {
310 encode(flockbl
, payload
);
316 if (features
& CEPH_FEATURE_EXPORT_PEER
) {
317 if (head
.op
== CEPH_CAP_OP_IMPORT
)
318 encode(peer
, payload
);
324 if (features
& CEPH_FEATURE_MDS_INLINE_DATA
) {
325 encode(inline_version
, payload
);
326 encode(inline_data
, payload
);
328 encode(inline_version
, payload
);
329 encode(ceph::buffer::list(), payload
);
332 encode(osd_epoch_barrier
, payload
);
333 encode(oldest_flush_tid
, payload
);
334 encode(caller_uid
, payload
);
335 encode(caller_gid
, payload
);
337 encode(layout
.pool_ns
, payload
);
338 encode(btime
, payload
);
339 encode(change_attr
, payload
);
340 encode(flags
, payload
);
341 encode(nfiles
, payload
);
342 encode(nsubdirs
, payload
);
345 template<class T
, typename
... Args
>
346 friend boost::intrusive_ptr
<T
> ceph::make_message(Args
&&... args
);
347 template<class T
, typename
... Args
>
348 friend MURef
<T
> crimson::make_message(Args
&&... args
);