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 "msg/Message.h"
37 #include "include/filepath.h"
38 #include "mds/mdstypes.h"
39 #include "include/ceph_features.h"
41 #include <sys/types.h>
49 class MClientRequest : public Message {
50 static const int HEAD_VERSION = 4;
51 static const int COMPAT_VERSION = 1;
54 struct ceph_mds_request_head head;
58 mutable ceph_mds_request_release item;
61 Release() : item(), dname() {}
62 Release(const ceph_mds_request_release& rel, string name) :
63 item(rel), dname(name) {}
65 void encode(bufferlist& bl) const {
66 item.dname_len = dname.length();
68 ::encode_nohead(dname, bl);
70 void decode(bufferlist::iterator& bl) {
72 ::decode_nohead(item.dname_len, dname, bl);
75 vector<Release> releases;
79 vector<uint64_t> gid_list;
81 bool queued_for_replay = false;
86 : Message(CEPH_MSG_CLIENT_REQUEST, HEAD_VERSION, COMPAT_VERSION) {}
87 MClientRequest(int op)
88 : Message(CEPH_MSG_CLIENT_REQUEST, HEAD_VERSION, COMPAT_VERSION) {
89 memset(&head, 0, sizeof(head));
93 ~MClientRequest() override {}
96 void set_mdsmap_epoch(epoch_t e) { head.mdsmap_epoch = e; }
97 epoch_t get_mdsmap_epoch() { return head.mdsmap_epoch; }
98 epoch_t get_osdmap_epoch() const {
99 assert(head.op == CEPH_MDS_OP_SETXATTR);
100 if (header.version >= 3)
101 return head.args.setxattr.osdmap_epoch;
105 void set_osdmap_epoch(epoch_t e) {
106 assert(head.op == CEPH_MDS_OP_SETXATTR);
107 head.args.setxattr.osdmap_epoch = e;
110 metareqid_t get_reqid() {
111 // FIXME: for now, assume clients always have 1 incarnation
112 return metareqid_t(get_orig_source(), header.tid);
115 /*bool open_file_mode_is_readonly() {
116 return file_mode_is_readonly(ceph_flags_to_mode(head.args.open.flags));
120 (head.op & CEPH_MDS_OP_WRITE) ||
121 (head.op == CEPH_MDS_OP_OPEN && (head.args.open.flags & (O_CREAT|O_TRUNC)));
124 int get_flags() const {
128 return get_flags() & CEPH_MDS_FLAG_REPLAY;
132 void set_stamp(utime_t t) { stamp = t; }
133 void set_oldest_client_tid(ceph_tid_t t) { head.oldest_client_tid = t; }
134 void inc_num_fwd() { head.num_fwd = head.num_fwd + 1; }
135 void set_retry_attempt(int a) { head.num_retry = a; }
136 void set_filepath(const filepath& fp) { path = fp; }
137 void set_filepath2(const filepath& fp) { path2 = fp; }
138 void set_string2(const char *s) { path2.set_path(s, 0); }
139 void set_caller_uid(unsigned u) { head.caller_uid = u; }
140 void set_caller_gid(unsigned g) { head.caller_gid = g; }
141 void set_gid_list(int count, const gid_t *gids) {
142 gid_list.reserve(count);
143 for (int i = 0; i < count; ++i) {
144 gid_list.push_back(gids[i]);
147 void set_dentry_wanted() {
148 head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY;
150 void set_replayed_op() {
151 head.flags = head.flags | CEPH_MDS_FLAG_REPLAY;
154 utime_t get_stamp() const { return stamp; }
155 ceph_tid_t get_oldest_client_tid() const { return head.oldest_client_tid; }
156 int get_num_fwd() const { return head.num_fwd; }
157 int get_retry_attempt() const { return head.num_retry; }
158 int get_op() const { return head.op; }
159 unsigned get_caller_uid() const { return head.caller_uid; }
160 unsigned get_caller_gid() const { return head.caller_gid; }
161 const vector<uint64_t>& get_caller_gid_list() const { return gid_list; }
163 const string& get_path() const { return path.get_path(); }
164 const filepath& get_filepath() const { return path; }
165 const string& get_path2() const { return path2.get_path(); }
166 const filepath& get_filepath2() const { return path2; }
168 int get_dentry_wanted() { return get_flags() & CEPH_MDS_FLAG_WANT_DENTRY; }
170 void mark_queued_for_replay() { queued_for_replay = true; }
171 bool is_queued_for_replay() { return queued_for_replay; }
173 void decode_payload() override {
174 bufferlist::iterator p = payload.begin();
176 if (header.version >= 4) {
179 struct ceph_mds_request_head_legacy old_mds_head;
181 ::decode(old_mds_head, p);
182 copy_from_legacy_head(&head, &old_mds_head);
185 /* Can't set the btime from legacy struct */
186 if (head.op == CEPH_MDS_OP_SETATTR) {
187 int localmask = head.args.setattr.mask;
189 localmask &= ~CEPH_SETATTR_BTIME;
191 head.args.setattr.btime = { 0 };
192 head.args.setattr.mask = localmask;
198 ::decode_nohead(head.num_releases, releases, p);
199 if (header.version >= 2)
201 if (header.version >= 4) // epoch 3 was for a ceph_mds_request_args change
202 ::decode(gid_list, p);
205 void encode_payload(uint64_t features) override {
206 head.num_releases = releases.size();
207 head.version = CEPH_MDS_REQUEST_HEAD_VERSION;
209 if (features & CEPH_FEATURE_FS_BTIME) {
210 ::encode(head, payload);
212 struct ceph_mds_request_head_legacy old_mds_head;
214 copy_to_legacy_head(&old_mds_head, &head);
215 ::encode(old_mds_head, payload);
218 ::encode(path, payload);
219 ::encode(path2, payload);
220 ::encode_nohead(releases, payload);
221 ::encode(stamp, payload);
222 ::encode(gid_list, payload);
225 const char *get_type_name() const override { return "creq"; }
226 void print(ostream& out) const override {
227 out << "client_request(" << get_orig_source()
229 << " " << ceph_mds_op_name(get_op());
230 if (head.op == CEPH_MDS_OP_GETATTR)
231 out << " " << ccap_string(head.args.getattr.mask);
232 if (head.op == CEPH_MDS_OP_SETATTR) {
233 if (head.args.setattr.mask & CEPH_SETATTR_MODE)
234 out << " mode=0" << std::oct << head.args.setattr.mode << std::dec;
235 if (head.args.setattr.mask & CEPH_SETATTR_UID)
236 out << " uid=" << head.args.setattr.uid;
237 if (head.args.setattr.mask & CEPH_SETATTR_GID)
238 out << " gid=" << head.args.setattr.gid;
239 if (head.args.setattr.mask & CEPH_SETATTR_SIZE)
240 out << " size=" << head.args.setattr.size;
241 if (head.args.setattr.mask & CEPH_SETATTR_MTIME)
242 out << " mtime=" << utime_t(head.args.setattr.mtime);
243 if (head.args.setattr.mask & CEPH_SETATTR_ATIME)
244 out << " atime=" << utime_t(head.args.setattr.atime);
246 if (head.op == CEPH_MDS_OP_SETFILELOCK ||
247 head.op == CEPH_MDS_OP_GETFILELOCK) {
248 out << "rule " << (int)head.args.filelock_change.rule
249 << ", type " << (int)head.args.filelock_change.type
250 << ", owner " << head.args.filelock_change.owner
251 << ", pid " << head.args.filelock_change.pid
252 << ", start " << head.args.filelock_change.start
253 << ", length " << head.args.filelock_change.length
254 << ", wait " << (int)head.args.filelock_change.wait;
256 //if (!get_filepath().empty())
257 out << " " << get_filepath();
258 if (!get_filepath2().empty())
259 out << " " << get_filepath2();
260 if (stamp != utime_t())
263 out << " RETRY=" << (int)head.num_retry;
264 if (get_flags() & CEPH_MDS_FLAG_REPLAY)
266 if (queued_for_replay)
267 out << " QUEUED_FOR_REPLAY";
268 out << " caller_uid=" << head.caller_uid
269 << ", caller_gid=" << head.caller_gid
271 for (auto i = gid_list.begin(); i != gid_list.end(); ++i)
279 WRITE_CLASS_ENCODER(MClientRequest::Release)