]> git.proxmox.com Git - ceph.git/blob - ceph/src/client/MetaRequest.h
ea39306608254e371003b055d4d5aae7f65120a8
[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 }
84 ~MetaRequest();
85
86 /**
87 * Prematurely terminate the request, such that callers
88 * to make_request will receive `rc` as their result.
89 */
90 void abort(int rc)
91 {
92 ceph_assert(rc != 0);
93 abort_rc = rc;
94 }
95
96 /**
97 * Whether abort() has been called for this request
98 */
99 inline bool aborted() const
100 {
101 return abort_rc != 0;
102 }
103
104 /**
105 * Given that abort() has been called for this request, what `rc` was
106 * passed into it?
107 */
108 int get_abort_code() const
109 {
110 return abort_rc;
111 }
112
113 void set_inode(Inode *in) {
114 _inode = in;
115 }
116 Inode *inode() {
117 return _inode.get();
118 }
119 void take_inode(InodeRef *out) {
120 out->swap(_inode);
121 }
122 void set_old_inode(Inode *in) {
123 _old_inode = in;
124 }
125 Inode *old_inode() {
126 return _old_inode.get();
127 }
128 void take_old_inode(InodeRef *out) {
129 out->swap(_old_inode);
130 }
131 void set_other_inode(Inode *in) {
132 _other_inode = in;
133 }
134 Inode *other_inode() {
135 return _other_inode.get();
136 }
137 void take_other_inode(InodeRef *out) {
138 out->swap(_other_inode);
139 }
140 void set_dentry(Dentry *d);
141 Dentry *dentry();
142 void set_old_dentry(Dentry *d);
143 Dentry *old_dentry();
144
145 MetaRequest* get() {
146 ref++;
147 return this;
148 }
149
150 /// psuedo-private put method; use Client::put_request()
151 bool _put() {
152 int v = --ref;
153 return v == 0;
154 }
155
156 // normal fields
157 void set_tid(ceph_tid_t t) { tid = t; }
158 void set_oldest_client_tid(ceph_tid_t t) { head.oldest_client_tid = t; }
159 void inc_num_fwd() { head.ext_num_fwd = head.ext_num_fwd + 1; }
160 void set_retry_attempt(int a) { head.ext_num_retry = a; }
161 void set_filepath(const filepath& fp) { path = fp; }
162 void set_filepath2(const filepath& fp) { path2 = fp; }
163 void set_alternate_name(std::string an) { alternate_name = an; }
164 void set_string2(const char *s) { path2.set_path(std::string_view(s), 0); }
165 void set_caller_perms(const UserPerm& _perms) {
166 perms.shallow_copy(_perms);
167 head.caller_uid = perms.uid();
168 head.caller_gid = perms.gid();
169 }
170 uid_t get_uid() { return perms.uid(); }
171 uid_t get_gid() { return perms.gid(); }
172 void set_data(const bufferlist &d) { data = d; }
173 void set_dentry_wanted() {
174 head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY;
175 }
176 int get_op() { return head.op; }
177 ceph_tid_t get_tid() { return tid; }
178 filepath& get_filepath() { return path; }
179 filepath& get_filepath2() { return path2; }
180
181 bool is_write() {
182 return
183 (head.op & CEPH_MDS_OP_WRITE) ||
184 (head.op == CEPH_MDS_OP_OPEN && (head.args.open.flags & (O_CREAT|O_TRUNC)));
185 }
186 bool can_forward() {
187 if ((head.op & CEPH_MDS_OP_WRITE) ||
188 head.op == CEPH_MDS_OP_OPEN) // do not forward _any_ open request.
189 return false;
190 return true;
191 }
192 bool auth_is_best(int issued) {
193 if (send_to_auth)
194 return true;
195
196 /* Any write op ? */
197 if (head.op & CEPH_MDS_OP_WRITE)
198 return true;
199
200 switch (head.op) {
201 case CEPH_MDS_OP_OPEN:
202 case CEPH_MDS_OP_READDIR:
203 return true;
204 case CEPH_MDS_OP_GETATTR:
205 /*
206 * If any 'x' caps is issued we can just choose the auth MDS
207 * instead of the random replica MDSes. Because only when the
208 * Locker is in LOCK_EXEC state will the loner client could
209 * get the 'x' caps. And if we send the getattr requests to
210 * any replica MDS it must auth pin and tries to rdlock from
211 * the auth MDS, and then the auth MDS need to do the Locker
212 * state transition to LOCK_SYNC. And after that the lock state
213 * will change back.
214 *
215 * This cost much when doing the Locker state transition and
216 * usually will need to revoke caps from clients.
217 *
218 * And for the 'Xs' caps for getxattr we will also choose the
219 * auth MDS, because the MDS side code is buggy due to setxattr
220 * won't notify the replica MDSes when the values changed and
221 * the replica MDS will return the old values. Though we will
222 * fix it in MDS code, but this still makes sense for old ceph.
223 */
224 if (((head.args.getattr.mask & CEPH_CAP_ANY_SHARED) &&
225 (issued & CEPH_CAP_ANY_EXCL)) ||
226 (head.args.getattr.mask & (CEPH_STAT_RSTAT | CEPH_STAT_CAP_XATTR)))
227 return true;
228 default:
229 return false;
230 }
231 }
232
233 void dump(Formatter *f) const;
234
235 };
236
237 #endif