]> git.proxmox.com Git - ceph.git/blob - ceph/src/messages/MClientRequest.h
d8cec31531a9640e567361eac571307da9f62fa8
[ceph.git] / ceph / src / messages / MClientRequest.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) 2004-2006 Sage Weil <sage@newdream.net>
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 */
14
15
16 #ifndef CEPH_MCLIENTREQUEST_H
17 #define CEPH_MCLIENTREQUEST_H
18
19 /**
20 *
21 * MClientRequest - container for a client METADATA request. created/sent by clients.
22 * can be forwarded around between MDS's.
23 *
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.
27 *
28 * int op - the metadata op code. MDS_OP_RENAME, etc.
29 * int caller_uid, _gid - guess
30 *
31 * fixed size arguments are in a union.
32 * there's also a string argument, for e.g. symlink().
33 *
34 */
35
36 #include <string_view>
37
38 #include "include/filepath.h"
39 #include "mds/mdstypes.h"
40 #include "include/ceph_features.h"
41 #include "messages/MMDSOp.h"
42
43 #include <sys/types.h>
44 #include <utime.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47
48 struct SnapPayload {
49 std::map<std::string, std::string> metadata;
50
51 void encode(ceph::buffer::list &bl) const {
52 ENCODE_START(1, 1, bl);
53 encode(metadata, bl);
54 ENCODE_FINISH(bl);
55 }
56
57 void decode(ceph::buffer::list::const_iterator &iter) {
58 DECODE_START(1, iter);
59 decode(metadata, iter);
60 DECODE_FINISH(iter);
61 }
62 };
63
64 WRITE_CLASS_ENCODER(SnapPayload)
65
66 // metadata ops.
67
68 class MClientRequest final : public MMDSOp {
69 private:
70 static constexpr int HEAD_VERSION = 6;
71 static constexpr int COMPAT_VERSION = 1;
72
73 public:
74 mutable struct ceph_mds_request_head head; /* XXX HACK! */
75 utime_t stamp;
76 bool peer_old_version = false;
77
78 struct Release {
79 mutable ceph_mds_request_release item;
80 std::string dname;
81
82 Release() : item(), dname() {}
83 Release(const ceph_mds_request_release& rel, std::string name) :
84 item(rel), dname(name) {}
85
86 void encode(ceph::buffer::list& bl) const {
87 using ceph::encode;
88 item.dname_len = dname.length();
89 encode(item, bl);
90 ceph::encode_nohead(dname, bl);
91 }
92 void decode(ceph::buffer::list::const_iterator& bl) {
93 using ceph::decode;
94 decode(item, bl);
95 ceph::decode_nohead(item.dname_len, dname, bl);
96 }
97 };
98 mutable std::vector<Release> releases; /* XXX HACK! */
99
100 // path arguments
101 filepath path, path2;
102 std::string alternate_name;
103 std::vector<uint64_t> gid_list;
104
105 std::vector<uint8_t> fscrypt_auth;
106 std::vector<uint8_t> fscrypt_file;
107
108 /* XXX HACK */
109 mutable bool queued_for_replay = false;
110
111 protected:
112 // cons
113 MClientRequest()
114 : MMDSOp(CEPH_MSG_CLIENT_REQUEST, HEAD_VERSION, COMPAT_VERSION) {
115 memset(&head, 0, sizeof(head));
116 }
117 MClientRequest(int op, bool over=true)
118 : MMDSOp(CEPH_MSG_CLIENT_REQUEST, HEAD_VERSION, COMPAT_VERSION) {
119 memset(&head, 0, sizeof(head));
120 head.op = op;
121 peer_old_version = over;
122 }
123 ~MClientRequest() final {}
124
125 public:
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;
132 else
133 return 0;
134 }
135 void set_osdmap_epoch(epoch_t e) {
136 ceph_assert(head.op == CEPH_MDS_OP_SETXATTR);
137 head.args.setxattr.osdmap_epoch = e;
138 }
139
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);
143 }
144
145 /*bool open_file_mode_is_readonly() {
146 return file_mode_is_readonly(ceph_flags_to_mode(head.args.open.flags));
147 }*/
148 bool may_write() const {
149 return
150 (head.op & CEPH_MDS_OP_WRITE) ||
151 (head.op == CEPH_MDS_OP_OPEN && (head.args.open.flags & (O_CREAT|O_TRUNC)));
152 }
153
154 int get_flags() const {
155 return head.flags;
156 }
157 bool is_replay() const {
158 return get_flags() & CEPH_MDS_FLAG_REPLAY;
159 }
160 bool is_async() const {
161 return get_flags() & CEPH_MDS_FLAG_ASYNC;
162 }
163
164 // normal fields
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]);
178 }
179 }
180 void set_dentry_wanted() {
181 head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY;
182 }
183 void set_replayed_op() {
184 head.flags = head.flags | CEPH_MDS_FLAG_REPLAY;
185 }
186 void set_async_op() {
187 head.flags = head.flags | CEPH_MDS_FLAG_ASYNC;
188 }
189
190 void set_alternate_name(std::string _alternate_name) {
191 alternate_name = std::move(_alternate_name);
192 }
193 void set_alternate_name(bufferptr&& cipher) {
194 alternate_name = std::move(cipher.c_str());
195 }
196
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; }
205
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); }
211
212 int get_dentry_wanted() const { return get_flags() & CEPH_MDS_FLAG_WANT_DENTRY; }
213
214 void mark_queued_for_replay() const { queued_for_replay = true; }
215 bool is_queued_for_replay() const { return queued_for_replay; }
216
217 void decode_payload() override {
218 using ceph::decode;
219 auto p = payload.cbegin();
220
221 if (header.version >= 4) {
222 decode(head, p);
223 } else {
224 struct ceph_mds_request_head_legacy old_mds_head;
225
226 decode(old_mds_head, p);
227 copy_from_legacy_head(&head, &old_mds_head);
228 head.version = 0;
229
230 /* Can't set the btime from legacy struct */
231 if (head.op == CEPH_MDS_OP_SETATTR) {
232 int localmask = head.args.setattr.mask;
233
234 localmask &= ~CEPH_SETATTR_BTIME;
235
236 head.args.setattr.btime = { ceph_le32(0), ceph_le32(0) };
237 head.args.setattr.mask = localmask;
238 }
239 }
240
241 decode(path, p);
242 decode(path2, p);
243 ceph::decode_nohead(head.num_releases, releases, p);
244 if (header.version >= 2)
245 decode(stamp, p);
246 if (header.version >= 4) // epoch 3 was for a ceph_mds_request_args change
247 decode(gid_list, p);
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);
253 }
254 }
255
256 void encode_payload(uint64_t features) override {
257 using ceph::encode;
258 head.num_releases = releases.size();
259 /*
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.
264 */
265 if (peer_old_version) {
266 head.version = 1;
267 } else {
268 head.version = CEPH_MDS_REQUEST_HEAD_VERSION;
269 }
270
271 if (features & CEPH_FEATURE_FS_BTIME) {
272 encode(head, payload, peer_old_version);
273 } else {
274 struct ceph_mds_request_head_legacy old_mds_head;
275
276 copy_to_legacy_head(&old_mds_head, &head);
277 encode(old_mds_head, payload);
278 }
279
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);
288 }
289
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()
293 << ":" << get_tid()
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);
310 }
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;
320 }
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())
328 out << " " << stamp;
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;
333 if (is_async())
334 out << " ASYNC";
335 if (is_replay())
336 out << " REPLAY";
337 if (queued_for_replay)
338 out << " QUEUED_FOR_REPLAY";
339 out << " caller_uid=" << head.caller_uid
340 << ", caller_gid=" << head.caller_gid
341 << '{';
342 for (auto i = gid_list.begin(); i != gid_list.end(); ++i)
343 out << *i << ',';
344 out << '}'
345 << ")";
346 }
347 private:
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);
352 };
353
354 WRITE_CLASS_ENCODER(MClientRequest::Release)
355
356 #endif