]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
11fdf7f2 | 36 | #include <string_view> |
94b18763 | 37 | |
7c673cae FG |
38 | #include "msg/Message.h" |
39 | #include "include/filepath.h" | |
40 | #include "mds/mdstypes.h" | |
41 | #include "include/ceph_features.h" | |
42 | ||
43 | #include <sys/types.h> | |
44 | #include <utime.h> | |
45 | #include <sys/stat.h> | |
46 | #include <fcntl.h> | |
47 | ||
48 | ||
49 | // metadata ops. | |
50 | ||
9f95a23c | 51 | class MClientRequest : public SafeMessage { |
11fdf7f2 TL |
52 | private: |
53 | static constexpr int HEAD_VERSION = 4; | |
54 | static constexpr int COMPAT_VERSION = 1; | |
7c673cae FG |
55 | |
56 | public: | |
11fdf7f2 | 57 | mutable struct ceph_mds_request_head head; /* XXX HACK! */ |
7c673cae FG |
58 | utime_t stamp; |
59 | ||
60 | struct Release { | |
61 | mutable ceph_mds_request_release item; | |
62 | string dname; | |
63 | ||
64 | Release() : item(), dname() {} | |
65 | Release(const ceph_mds_request_release& rel, string name) : | |
66 | item(rel), dname(name) {} | |
67 | ||
68 | void encode(bufferlist& bl) const { | |
11fdf7f2 | 69 | using ceph::encode; |
7c673cae | 70 | item.dname_len = dname.length(); |
11fdf7f2 TL |
71 | encode(item, bl); |
72 | encode_nohead(dname, bl); | |
7c673cae | 73 | } |
11fdf7f2 TL |
74 | void decode(bufferlist::const_iterator& bl) { |
75 | using ceph::decode; | |
76 | decode(item, bl); | |
77 | decode_nohead(item.dname_len, dname, bl); | |
7c673cae FG |
78 | } |
79 | }; | |
11fdf7f2 | 80 | mutable vector<Release> releases; /* XXX HACK! */ |
7c673cae FG |
81 | |
82 | // path arguments | |
83 | filepath path, path2; | |
84 | vector<uint64_t> gid_list; | |
85 | ||
11fdf7f2 TL |
86 | /* XXX HACK */ |
87 | mutable bool queued_for_replay = false; | |
7c673cae | 88 | |
11fdf7f2 | 89 | protected: |
7c673cae FG |
90 | // cons |
91 | MClientRequest() | |
9f95a23c | 92 | : SafeMessage(CEPH_MSG_CLIENT_REQUEST, HEAD_VERSION, COMPAT_VERSION) {} |
7c673cae | 93 | MClientRequest(int op) |
9f95a23c | 94 | : SafeMessage(CEPH_MSG_CLIENT_REQUEST, HEAD_VERSION, COMPAT_VERSION) { |
7c673cae FG |
95 | memset(&head, 0, sizeof(head)); |
96 | head.op = op; | |
97 | } | |
7c673cae FG |
98 | ~MClientRequest() override {} |
99 | ||
100 | public: | |
101 | void set_mdsmap_epoch(epoch_t e) { head.mdsmap_epoch = e; } | |
11fdf7f2 | 102 | epoch_t get_mdsmap_epoch() const { return head.mdsmap_epoch; } |
7c673cae | 103 | epoch_t get_osdmap_epoch() const { |
11fdf7f2 | 104 | ceph_assert(head.op == CEPH_MDS_OP_SETXATTR); |
7c673cae FG |
105 | if (header.version >= 3) |
106 | return head.args.setxattr.osdmap_epoch; | |
107 | else | |
108 | return 0; | |
109 | } | |
110 | void set_osdmap_epoch(epoch_t e) { | |
11fdf7f2 | 111 | ceph_assert(head.op == CEPH_MDS_OP_SETXATTR); |
7c673cae FG |
112 | head.args.setxattr.osdmap_epoch = e; |
113 | } | |
114 | ||
11fdf7f2 | 115 | metareqid_t get_reqid() const { |
7c673cae FG |
116 | // FIXME: for now, assume clients always have 1 incarnation |
117 | return metareqid_t(get_orig_source(), header.tid); | |
118 | } | |
119 | ||
120 | /*bool open_file_mode_is_readonly() { | |
121 | return file_mode_is_readonly(ceph_flags_to_mode(head.args.open.flags)); | |
122 | }*/ | |
11fdf7f2 | 123 | bool may_write() const { |
7c673cae FG |
124 | return |
125 | (head.op & CEPH_MDS_OP_WRITE) || | |
126 | (head.op == CEPH_MDS_OP_OPEN && (head.args.open.flags & (O_CREAT|O_TRUNC))); | |
127 | } | |
128 | ||
129 | int get_flags() const { | |
130 | return head.flags; | |
131 | } | |
11fdf7f2 | 132 | bool is_replay() const { |
7c673cae FG |
133 | return get_flags() & CEPH_MDS_FLAG_REPLAY; |
134 | } | |
9f95a23c TL |
135 | bool is_async() const { |
136 | return get_flags() & CEPH_MDS_FLAG_ASYNC; | |
137 | } | |
7c673cae FG |
138 | |
139 | // normal fields | |
140 | void set_stamp(utime_t t) { stamp = t; } | |
141 | void set_oldest_client_tid(ceph_tid_t t) { head.oldest_client_tid = t; } | |
142 | void inc_num_fwd() { head.num_fwd = head.num_fwd + 1; } | |
143 | void set_retry_attempt(int a) { head.num_retry = a; } | |
144 | void set_filepath(const filepath& fp) { path = fp; } | |
145 | void set_filepath2(const filepath& fp) { path2 = fp; } | |
11fdf7f2 | 146 | void set_string2(const char *s) { path2.set_path(std::string_view(s), 0); } |
7c673cae FG |
147 | void set_caller_uid(unsigned u) { head.caller_uid = u; } |
148 | void set_caller_gid(unsigned g) { head.caller_gid = g; } | |
149 | void set_gid_list(int count, const gid_t *gids) { | |
150 | gid_list.reserve(count); | |
151 | for (int i = 0; i < count; ++i) { | |
152 | gid_list.push_back(gids[i]); | |
153 | } | |
154 | } | |
155 | void set_dentry_wanted() { | |
156 | head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY; | |
157 | } | |
158 | void set_replayed_op() { | |
159 | head.flags = head.flags | CEPH_MDS_FLAG_REPLAY; | |
160 | } | |
9f95a23c TL |
161 | void set_async_op() { |
162 | head.flags = head.flags | CEPH_MDS_FLAG_ASYNC; | |
163 | } | |
7c673cae FG |
164 | |
165 | utime_t get_stamp() const { return stamp; } | |
166 | ceph_tid_t get_oldest_client_tid() const { return head.oldest_client_tid; } | |
167 | int get_num_fwd() const { return head.num_fwd; } | |
168 | int get_retry_attempt() const { return head.num_retry; } | |
169 | int get_op() const { return head.op; } | |
170 | unsigned get_caller_uid() const { return head.caller_uid; } | |
171 | unsigned get_caller_gid() const { return head.caller_gid; } | |
172 | const vector<uint64_t>& get_caller_gid_list() const { return gid_list; } | |
173 | ||
174 | const string& get_path() const { return path.get_path(); } | |
175 | const filepath& get_filepath() const { return path; } | |
176 | const string& get_path2() const { return path2.get_path(); } | |
177 | const filepath& get_filepath2() const { return path2; } | |
178 | ||
11fdf7f2 | 179 | int get_dentry_wanted() const { return get_flags() & CEPH_MDS_FLAG_WANT_DENTRY; } |
7c673cae | 180 | |
11fdf7f2 TL |
181 | void mark_queued_for_replay() const { queued_for_replay = true; } |
182 | bool is_queued_for_replay() const { return queued_for_replay; } | |
7c673cae FG |
183 | |
184 | void decode_payload() override { | |
11fdf7f2 | 185 | auto p = payload.cbegin(); |
7c673cae FG |
186 | |
187 | if (header.version >= 4) { | |
11fdf7f2 | 188 | decode(head, p); |
7c673cae FG |
189 | } else { |
190 | struct ceph_mds_request_head_legacy old_mds_head; | |
191 | ||
11fdf7f2 | 192 | decode(old_mds_head, p); |
7c673cae FG |
193 | copy_from_legacy_head(&head, &old_mds_head); |
194 | head.version = 0; | |
195 | ||
196 | /* Can't set the btime from legacy struct */ | |
197 | if (head.op == CEPH_MDS_OP_SETATTR) { | |
198 | int localmask = head.args.setattr.mask; | |
199 | ||
200 | localmask &= ~CEPH_SETATTR_BTIME; | |
201 | ||
9f95a23c | 202 | head.args.setattr.btime = { init_le32(0), init_le32(0) }; |
7c673cae FG |
203 | head.args.setattr.mask = localmask; |
204 | } | |
205 | } | |
206 | ||
11fdf7f2 TL |
207 | decode(path, p); |
208 | decode(path2, p); | |
209 | decode_nohead(head.num_releases, releases, p); | |
7c673cae | 210 | if (header.version >= 2) |
11fdf7f2 | 211 | decode(stamp, p); |
7c673cae | 212 | if (header.version >= 4) // epoch 3 was for a ceph_mds_request_args change |
11fdf7f2 | 213 | decode(gid_list, p); |
7c673cae FG |
214 | } |
215 | ||
216 | void encode_payload(uint64_t features) override { | |
11fdf7f2 | 217 | using ceph::encode; |
7c673cae FG |
218 | head.num_releases = releases.size(); |
219 | head.version = CEPH_MDS_REQUEST_HEAD_VERSION; | |
220 | ||
221 | if (features & CEPH_FEATURE_FS_BTIME) { | |
11fdf7f2 | 222 | encode(head, payload); |
7c673cae FG |
223 | } else { |
224 | struct ceph_mds_request_head_legacy old_mds_head; | |
225 | ||
226 | copy_to_legacy_head(&old_mds_head, &head); | |
11fdf7f2 | 227 | encode(old_mds_head, payload); |
7c673cae FG |
228 | } |
229 | ||
11fdf7f2 TL |
230 | encode(path, payload); |
231 | encode(path2, payload); | |
232 | encode_nohead(releases, payload); | |
233 | encode(stamp, payload); | |
234 | encode(gid_list, payload); | |
7c673cae FG |
235 | } |
236 | ||
11fdf7f2 | 237 | std::string_view get_type_name() const override { return "creq"; } |
7c673cae FG |
238 | void print(ostream& out) const override { |
239 | out << "client_request(" << get_orig_source() | |
240 | << ":" << get_tid() | |
241 | << " " << ceph_mds_op_name(get_op()); | |
242 | if (head.op == CEPH_MDS_OP_GETATTR) | |
243 | out << " " << ccap_string(head.args.getattr.mask); | |
244 | if (head.op == CEPH_MDS_OP_SETATTR) { | |
245 | if (head.args.setattr.mask & CEPH_SETATTR_MODE) | |
246 | out << " mode=0" << std::oct << head.args.setattr.mode << std::dec; | |
247 | if (head.args.setattr.mask & CEPH_SETATTR_UID) | |
248 | out << " uid=" << head.args.setattr.uid; | |
249 | if (head.args.setattr.mask & CEPH_SETATTR_GID) | |
250 | out << " gid=" << head.args.setattr.gid; | |
251 | if (head.args.setattr.mask & CEPH_SETATTR_SIZE) | |
252 | out << " size=" << head.args.setattr.size; | |
253 | if (head.args.setattr.mask & CEPH_SETATTR_MTIME) | |
254 | out << " mtime=" << utime_t(head.args.setattr.mtime); | |
255 | if (head.args.setattr.mask & CEPH_SETATTR_ATIME) | |
256 | out << " atime=" << utime_t(head.args.setattr.atime); | |
257 | } | |
258 | if (head.op == CEPH_MDS_OP_SETFILELOCK || | |
259 | head.op == CEPH_MDS_OP_GETFILELOCK) { | |
11fdf7f2 | 260 | out << " rule " << (int)head.args.filelock_change.rule |
7c673cae FG |
261 | << ", type " << (int)head.args.filelock_change.type |
262 | << ", owner " << head.args.filelock_change.owner | |
263 | << ", pid " << head.args.filelock_change.pid | |
264 | << ", start " << head.args.filelock_change.start | |
265 | << ", length " << head.args.filelock_change.length | |
266 | << ", wait " << (int)head.args.filelock_change.wait; | |
267 | } | |
268 | //if (!get_filepath().empty()) | |
269 | out << " " << get_filepath(); | |
270 | if (!get_filepath2().empty()) | |
271 | out << " " << get_filepath2(); | |
272 | if (stamp != utime_t()) | |
273 | out << " " << stamp; | |
274 | if (head.num_retry) | |
275 | out << " RETRY=" << (int)head.num_retry; | |
9f95a23c TL |
276 | if (is_async()) |
277 | out << " ASYNC"; | |
278 | if (is_replay()) | |
7c673cae FG |
279 | out << " REPLAY"; |
280 | if (queued_for_replay) | |
281 | out << " QUEUED_FOR_REPLAY"; | |
282 | out << " caller_uid=" << head.caller_uid | |
283 | << ", caller_gid=" << head.caller_gid | |
284 | << '{'; | |
285 | for (auto i = gid_list.begin(); i != gid_list.end(); ++i) | |
286 | out << *i << ','; | |
287 | out << '}' | |
288 | << ")"; | |
289 | } | |
9f95a23c TL |
290 | private: |
291 | template<class T, typename... Args> | |
292 | friend boost::intrusive_ptr<T> ceph::make_message(Args&&... args); | |
7c673cae FG |
293 | }; |
294 | ||
295 | WRITE_CLASS_ENCODER(MClientRequest::Release) | |
296 | ||
297 | #endif |