]> git.proxmox.com Git - ceph.git/blob - ceph/src/client/MetaRequest.h
update ceph source to reef 18.2.1
[ceph.git] / ceph / src / client / MetaRequest.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #ifndef CEPH_CLIENT_METAREQUEST_H
5 #define CEPH_CLIENT_METAREQUEST_H
6
7
8 #include "include/types.h"
9 #include "include/xlist.h"
10 #include "include/filepath.h"
11 #include "mds/mdstypes.h"
12 #include "InodeRef.h"
13 #include "UserPerm.h"
14
15 #include "messages/MClientRequest.h"
16 #include "messages/MClientReply.h"
17
18 class Dentry;
19 class dir_result_t;
20
21 struct MetaRequest {
22 private:
23 InodeRef _inode, _old_inode, _other_inode;
24 Dentry *_dentry = NULL; //associated with path
25 Dentry *_old_dentry = NULL; //associated with path2
26 int abort_rc = 0;
27 public:
28 ceph::coarse_mono_time created = ceph::coarse_mono_clock::zero();
29 uint64_t tid = 0;
30 utime_t op_stamp;
31 ceph_mds_request_head head;
32 filepath path, path2;
33 std::string alternate_name;
34 std::vector<uint8_t> fscrypt_auth;
35 std::vector<uint8_t> fscrypt_file;
36 bufferlist data;
37 int inode_drop = 0; //the inode caps this operation will drop
38 int inode_unless = 0; //unless we have these caps already
39 int old_inode_drop = 0, old_inode_unless = 0;
40 int dentry_drop = 0, dentry_unless = 0;
41 int old_dentry_drop = 0, old_dentry_unless = 0;
42 int other_inode_drop = 0, other_inode_unless = 0;
43 std::vector<MClientRequest::Release> cap_releases;
44
45 int regetattr_mask = 0; // getattr mask if i need to re-stat after a traceless reply
46
47 utime_t sent_stamp;
48 mds_rank_t mds = -1; // who i am asking
49 mds_rank_t resend_mds = -1; // someone wants you to (re)send the request here
50 bool send_to_auth = false; // must send to auth mds
51 __u32 sent_on_mseq = 0; // mseq at last submission of this request
52 int num_fwd = 0; // # of times i've been forwarded
53 int retry_attempt = 0;
54 std::atomic<uint64_t> ref = { 1 };
55
56 ceph::cref_t<MClientReply> reply = NULL; // the reply
57 bool kick = false;
58 bool success = false;
59
60 // readdir result
61 dir_result_t *dirp = NULL;
62
63 //possible responses
64 bool got_unsafe = false;
65
66 xlist<MetaRequest*>::item item;
67 xlist<MetaRequest*>::item unsafe_item;
68 xlist<MetaRequest*>::item unsafe_dir_item;
69 xlist<MetaRequest*>::item unsafe_target_item;
70
71 ceph::condition_variable *caller_cond = NULL; // who to take up
72 ceph::condition_variable *dispatch_cond = NULL; // who to kick back
73 std::list<ceph::condition_variable*> waitfor_safe;
74
75 InodeRef target;
76 UserPerm perms;
77
78 explicit MetaRequest(int op) :
79 item(this), unsafe_item(this), unsafe_dir_item(this),
80 unsafe_target_item(this) {
81 memset(&head, 0, sizeof(head));
82 head.op = op;
83 head.owner_uid = -1;
84 head.owner_gid = -1;
85 }
86 ~MetaRequest();
87
88 /**
89 * Prematurely terminate the request, such that callers
90 * to make_request will receive `rc` as their result.
91 */
92 void abort(int rc)
93 {
94 ceph_assert(rc != 0);
95 abort_rc = rc;
96 }
97
98 /**
99 * Whether abort() has been called for this request
100 */
101 inline bool aborted() const
102 {
103 return abort_rc != 0;
104 }
105
106 /**
107 * Given that abort() has been called for this request, what `rc` was
108 * passed into it?
109 */
110 int get_abort_code() const
111 {
112 return abort_rc;
113 }
114
115 void set_inode(Inode *in) {
116 _inode = in;
117 }
118 Inode *inode() {
119 return _inode.get();
120 }
121 void take_inode(InodeRef *out) {
122 out->swap(_inode);
123 }
124 void set_old_inode(Inode *in) {
125 _old_inode = in;
126 }
127 Inode *old_inode() {
128 return _old_inode.get();
129 }
130 void take_old_inode(InodeRef *out) {
131 out->swap(_old_inode);
132 }
133 void set_other_inode(Inode *in) {
134 _other_inode = in;
135 }
136 Inode *other_inode() {
137 return _other_inode.get();
138 }
139 void take_other_inode(InodeRef *out) {
140 out->swap(_other_inode);
141 }
142 void set_dentry(Dentry *d);
143 Dentry *dentry();
144 void set_old_dentry(Dentry *d);
145 Dentry *old_dentry();
146
147 MetaRequest* get() {
148 ref++;
149 return this;
150 }
151
152 /// psuedo-private put method; use Client::put_request()
153 bool _put() {
154 int v = --ref;
155 return v == 0;
156 }
157
158 void set_inode_owner_uid_gid(unsigned u, unsigned g) {
159 /* it makes sense to set owner_{u,g}id only for OPs which create inodes */
160 ceph_assert(IS_CEPH_MDS_OP_NEWINODE(head.op));
161 head.owner_uid = u;
162 head.owner_gid = g;
163 }
164
165 // normal fields
166 void set_tid(ceph_tid_t t) { tid = t; }
167 void set_oldest_client_tid(ceph_tid_t t) { head.oldest_client_tid = t; }
168 void inc_num_fwd() { head.ext_num_fwd = head.ext_num_fwd + 1; }
169 void set_retry_attempt(int a) { head.ext_num_retry = a; }
170 void set_filepath(const filepath& fp) { path = fp; }
171 void set_filepath2(const filepath& fp) { path2 = fp; }
172 void set_alternate_name(std::string an) { alternate_name = an; }
173 void set_string2(const char *s) { path2.set_path(std::string_view(s), 0); }
174 void set_caller_perms(const UserPerm& _perms) {
175 perms = _perms;
176 head.caller_uid = perms.uid();
177 head.caller_gid = perms.gid();
178 }
179 uid_t get_uid() { return perms.uid(); }
180 uid_t get_gid() { return perms.gid(); }
181 void set_data(const bufferlist &d) { data = d; }
182 void set_dentry_wanted() {
183 head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY;
184 }
185 int get_op() { return head.op; }
186 ceph_tid_t get_tid() { return tid; }
187 filepath& get_filepath() { return path; }
188 filepath& get_filepath2() { return path2; }
189
190 bool is_write() {
191 return
192 (head.op & CEPH_MDS_OP_WRITE) ||
193 (head.op == CEPH_MDS_OP_OPEN && (head.args.open.flags & (O_CREAT|O_TRUNC)));
194 }
195 bool can_forward() {
196 if ((head.op & CEPH_MDS_OP_WRITE) ||
197 head.op == CEPH_MDS_OP_OPEN) // do not forward _any_ open request.
198 return false;
199 return true;
200 }
201 bool auth_is_best(int issued) {
202 if (send_to_auth)
203 return true;
204
205 /* Any write op ? */
206 if (head.op & CEPH_MDS_OP_WRITE)
207 return true;
208
209 switch (head.op) {
210 case CEPH_MDS_OP_OPEN:
211 case CEPH_MDS_OP_READDIR:
212 return true;
213 case CEPH_MDS_OP_GETATTR:
214 /*
215 * If any 'x' caps is issued we can just choose the auth MDS
216 * instead of the random replica MDSes. Because only when the
217 * Locker is in LOCK_EXEC state will the loner client could
218 * get the 'x' caps. And if we send the getattr requests to
219 * any replica MDS it must auth pin and tries to rdlock from
220 * the auth MDS, and then the auth MDS need to do the Locker
221 * state transition to LOCK_SYNC. And after that the lock state
222 * will change back.
223 *
224 * This cost much when doing the Locker state transition and
225 * usually will need to revoke caps from clients.
226 *
227 * And for the 'Xs' caps for getxattr we will also choose the
228 * auth MDS, because the MDS side code is buggy due to setxattr
229 * won't notify the replica MDSes when the values changed and
230 * the replica MDS will return the old values. Though we will
231 * fix it in MDS code, but this still makes sense for old ceph.
232 */
233 if (((head.args.getattr.mask & CEPH_CAP_ANY_SHARED) &&
234 (issued & CEPH_CAP_ANY_EXCL)) ||
235 (head.args.getattr.mask & (CEPH_STAT_RSTAT | CEPH_STAT_CAP_XATTR)))
236 return true;
237 default:
238 return false;
239 }
240 }
241
242 void dump(Formatter *f) const;
243
244 };
245
246 #endif