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.
16 #ifndef CEPH_MCLIENTREQUEST_H
17 #define CEPH_MCLIENTREQUEST_H
21 * MClientRequest - container for a client METADATA request. created/sent by clients.
22 * can be forwarded around between MDS's.
24 * int client - the originating client
25 * long tid - transaction id, unique among requests for that client. probably just a counter!
26 * -> the MDS passes the Request to the Reply constructor, so this always matches.
28 * int op - the metadata op code. MDS_OP_RENAME, etc.
29 * int caller_uid, _gid - guess
31 * fixed size arguments are in a union.
32 * there's also a string argument, for e.g. symlink().
36 #include <string_view>
38 #include "include/filepath.h"
39 #include "mds/mdstypes.h"
40 #include "include/ceph_features.h"
41 #include "messages/MMDSOp.h"
43 #include <sys/types.h>
49 std::map
<std::string
, std::string
> metadata
;
51 void encode(ceph::buffer::list
&bl
) const {
52 ENCODE_START(1, 1, bl
);
57 void decode(ceph::buffer::list::const_iterator
&iter
) {
58 DECODE_START(1, iter
);
59 decode(metadata
, iter
);
64 WRITE_CLASS_ENCODER(SnapPayload
)
68 class MClientRequest final
: public MMDSOp
{
70 static constexpr int HEAD_VERSION
= 6;
71 static constexpr int COMPAT_VERSION
= 1;
74 mutable struct ceph_mds_request_head head
; /* XXX HACK! */
76 bool peer_old_version
= false;
79 mutable ceph_mds_request_release item
;
82 Release() : item(), dname() {}
83 Release(const ceph_mds_request_release
& rel
, std::string name
) :
84 item(rel
), dname(name
) {}
86 void encode(ceph::buffer::list
& bl
) const {
88 item
.dname_len
= dname
.length();
90 ceph::encode_nohead(dname
, bl
);
92 void decode(ceph::buffer::list::const_iterator
& bl
) {
95 ceph::decode_nohead(item
.dname_len
, dname
, bl
);
98 mutable std::vector
<Release
> releases
; /* XXX HACK! */
101 filepath path
, path2
;
102 std::string alternate_name
;
103 std::vector
<uint64_t> gid_list
;
105 std::vector
<uint8_t> fscrypt_auth
;
106 std::vector
<uint8_t> fscrypt_file
;
109 mutable bool queued_for_replay
= false;
114 : MMDSOp(CEPH_MSG_CLIENT_REQUEST
, HEAD_VERSION
, COMPAT_VERSION
) {
115 memset(&head
, 0, sizeof(head
));
117 MClientRequest(int op
, bool over
=true)
118 : MMDSOp(CEPH_MSG_CLIENT_REQUEST
, HEAD_VERSION
, COMPAT_VERSION
) {
119 memset(&head
, 0, sizeof(head
));
121 peer_old_version
= over
;
123 ~MClientRequest() final
{}
126 void set_mdsmap_epoch(epoch_t e
) { head
.mdsmap_epoch
= e
; }
127 epoch_t
get_mdsmap_epoch() const { return head
.mdsmap_epoch
; }
128 epoch_t
get_osdmap_epoch() const {
129 ceph_assert(head
.op
== CEPH_MDS_OP_SETXATTR
);
130 if (header
.version
>= 3)
131 return head
.args
.setxattr
.osdmap_epoch
;
135 void set_osdmap_epoch(epoch_t e
) {
136 ceph_assert(head
.op
== CEPH_MDS_OP_SETXATTR
);
137 head
.args
.setxattr
.osdmap_epoch
= e
;
140 metareqid_t
get_reqid() const {
141 // FIXME: for now, assume clients always have 1 incarnation
142 return metareqid_t(get_orig_source(), header
.tid
);
145 /*bool open_file_mode_is_readonly() {
146 return file_mode_is_readonly(ceph_flags_to_mode(head.args.open.flags));
148 bool may_write() const {
150 (head
.op
& CEPH_MDS_OP_WRITE
) ||
151 (head
.op
== CEPH_MDS_OP_OPEN
&& (head
.args
.open
.flags
& (O_CREAT
|O_TRUNC
)));
154 int get_flags() const {
157 bool is_replay() const {
158 return get_flags() & CEPH_MDS_FLAG_REPLAY
;
160 bool is_async() const {
161 return get_flags() & CEPH_MDS_FLAG_ASYNC
;
165 void set_stamp(utime_t t
) { stamp
= t
; }
166 void set_oldest_client_tid(ceph_tid_t t
) { head
.oldest_client_tid
= t
; }
167 void inc_num_fwd() { head
.ext_num_fwd
= head
.ext_num_fwd
+ 1; }
168 void set_retry_attempt(int a
) { head
.ext_num_retry
= a
; }
169 void set_filepath(const filepath
& fp
) { path
= fp
; }
170 void set_filepath2(const filepath
& fp
) { path2
= fp
; }
171 void set_string2(const char *s
) { path2
.set_path(std::string_view(s
), 0); }
172 void set_caller_uid(unsigned u
) { head
.caller_uid
= u
; }
173 void set_caller_gid(unsigned g
) { head
.caller_gid
= g
; }
174 void set_gid_list(int count
, const gid_t
*gids
) {
175 gid_list
.reserve(count
);
176 for (int i
= 0; i
< count
; ++i
) {
177 gid_list
.push_back(gids
[i
]);
180 void set_dentry_wanted() {
181 head
.flags
= head
.flags
| CEPH_MDS_FLAG_WANT_DENTRY
;
183 void set_replayed_op() {
184 head
.flags
= head
.flags
| CEPH_MDS_FLAG_REPLAY
;
186 void set_async_op() {
187 head
.flags
= head
.flags
| CEPH_MDS_FLAG_ASYNC
;
190 void set_alternate_name(std::string _alternate_name
) {
191 alternate_name
= std::move(_alternate_name
);
193 void set_alternate_name(bufferptr
&& cipher
) {
194 alternate_name
= std::move(cipher
.c_str());
197 utime_t
get_stamp() const { return stamp
; }
198 ceph_tid_t
get_oldest_client_tid() const { return head
.oldest_client_tid
; }
199 int get_num_fwd() const { return head
.ext_num_fwd
; }
200 int get_retry_attempt() const { return head
.ext_num_retry
; }
201 int get_op() const { return head
.op
; }
202 unsigned get_caller_uid() const { return head
.caller_uid
; }
203 unsigned get_caller_gid() const { return head
.caller_gid
; }
204 const std::vector
<uint64_t>& get_caller_gid_list() const { return gid_list
; }
206 const std::string
& get_path() const { return path
.get_path(); }
207 const filepath
& get_filepath() const { return path
; }
208 const std::string
& get_path2() const { return path2
.get_path(); }
209 const filepath
& get_filepath2() const { return path2
; }
210 std::string_view
get_alternate_name() const { return std::string_view(alternate_name
); }
212 int get_dentry_wanted() const { return get_flags() & CEPH_MDS_FLAG_WANT_DENTRY
; }
214 void mark_queued_for_replay() const { queued_for_replay
= true; }
215 bool is_queued_for_replay() const { return queued_for_replay
; }
217 void decode_payload() override
{
219 auto p
= payload
.cbegin();
221 if (header
.version
>= 4) {
224 struct ceph_mds_request_head_legacy old_mds_head
;
226 decode(old_mds_head
, p
);
227 copy_from_legacy_head(&head
, &old_mds_head
);
230 /* Can't set the btime from legacy struct */
231 if (head
.op
== CEPH_MDS_OP_SETATTR
) {
232 int localmask
= head
.args
.setattr
.mask
;
234 localmask
&= ~CEPH_SETATTR_BTIME
;
236 head
.args
.setattr
.btime
= { ceph_le32(0), ceph_le32(0) };
237 head
.args
.setattr
.mask
= localmask
;
243 ceph::decode_nohead(head
.num_releases
, releases
, p
);
244 if (header
.version
>= 2)
246 if (header
.version
>= 4) // epoch 3 was for a ceph_mds_request_args change
248 if (header
.version
>= 5)
249 decode(alternate_name
, p
);
250 if (header
.version
>= 6) {
251 decode(fscrypt_auth
, p
);
252 decode(fscrypt_file
, p
);
256 void encode_payload(uint64_t features
) override
{
258 head
.num_releases
= releases
.size();
260 * If the peer is old version, we must skip all the
261 * new members, because the old version of MDS or
262 * client will just copy the 'head' memory and isn't
263 * that smart to skip them.
265 if (peer_old_version
) {
268 head
.version
= CEPH_MDS_REQUEST_HEAD_VERSION
;
271 if (features
& CEPH_FEATURE_FS_BTIME
) {
272 encode(head
, payload
, peer_old_version
);
274 struct ceph_mds_request_head_legacy old_mds_head
;
276 copy_to_legacy_head(&old_mds_head
, &head
);
277 encode(old_mds_head
, payload
);
280 encode(path
, payload
);
281 encode(path2
, payload
);
282 ceph::encode_nohead(releases
, payload
);
283 encode(stamp
, payload
);
284 encode(gid_list
, payload
);
285 encode(alternate_name
, payload
);
286 encode(fscrypt_auth
, payload
);
287 encode(fscrypt_file
, payload
);
290 std::string_view
get_type_name() const override
{ return "creq"; }
291 void print(std::ostream
& out
) const override
{
292 out
<< "client_request(" << get_orig_source()
294 << " " << ceph_mds_op_name(get_op());
295 if (head
.op
== CEPH_MDS_OP_GETATTR
)
296 out
<< " " << ccap_string(head
.args
.getattr
.mask
);
297 if (head
.op
== CEPH_MDS_OP_SETATTR
) {
298 if (head
.args
.setattr
.mask
& CEPH_SETATTR_MODE
)
299 out
<< " mode=0" << std::oct
<< head
.args
.setattr
.mode
<< std::dec
;
300 if (head
.args
.setattr
.mask
& CEPH_SETATTR_UID
)
301 out
<< " uid=" << head
.args
.setattr
.uid
;
302 if (head
.args
.setattr
.mask
& CEPH_SETATTR_GID
)
303 out
<< " gid=" << head
.args
.setattr
.gid
;
304 if (head
.args
.setattr
.mask
& CEPH_SETATTR_SIZE
)
305 out
<< " size=" << head
.args
.setattr
.size
;
306 if (head
.args
.setattr
.mask
& CEPH_SETATTR_MTIME
)
307 out
<< " mtime=" << utime_t(head
.args
.setattr
.mtime
);
308 if (head
.args
.setattr
.mask
& CEPH_SETATTR_ATIME
)
309 out
<< " atime=" << utime_t(head
.args
.setattr
.atime
);
311 if (head
.op
== CEPH_MDS_OP_SETFILELOCK
||
312 head
.op
== CEPH_MDS_OP_GETFILELOCK
) {
313 out
<< " rule " << (int)head
.args
.filelock_change
.rule
314 << ", type " << (int)head
.args
.filelock_change
.type
315 << ", owner " << head
.args
.filelock_change
.owner
316 << ", pid " << head
.args
.filelock_change
.pid
317 << ", start " << head
.args
.filelock_change
.start
318 << ", length " << head
.args
.filelock_change
.length
319 << ", wait " << (int)head
.args
.filelock_change
.wait
;
321 //if (!get_filepath().empty())
322 out
<< " " << get_filepath();
323 if (alternate_name
.size())
324 out
<< " (" << alternate_name
<< ") ";
325 if (!get_filepath2().empty())
326 out
<< " " << get_filepath2();
327 if (stamp
!= utime_t())
329 if (head
.ext_num_fwd
)
330 out
<< " FWD=" << (int)head
.ext_num_fwd
;
331 if (head
.ext_num_retry
)
332 out
<< " RETRY=" << (int)head
.ext_num_retry
;
337 if (queued_for_replay
)
338 out
<< " QUEUED_FOR_REPLAY";
339 out
<< " caller_uid=" << head
.caller_uid
340 << ", caller_gid=" << head
.caller_gid
342 for (auto i
= gid_list
.begin(); i
!= gid_list
.end(); ++i
)
348 template<class T
, typename
... Args
>
349 friend boost::intrusive_ptr
<T
> ceph::make_message(Args
&&... args
);
350 template<class T
, typename
... Args
>
351 friend MURef
<T
> crimson::make_message(Args
&&... args
);
354 WRITE_CLASS_ENCODER(MClientRequest::Release
)