]> git.proxmox.com Git - ceph.git/blob - ceph/src/mds/Capability.h
update sources to 12.2.7
[ceph.git] / ceph / src / mds / Capability.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_CAPABILITY_H
17 #define CEPH_CAPABILITY_H
18
19 #include "include/buffer_fwd.h"
20 #include "include/counter.h"
21 #include "include/mempool.h"
22 #include "include/xlist.h"
23
24 #include "common/config.h"
25
26 #include "mdstypes.h"
27
28
29 /*
30
31 Capability protocol notes.
32
33 - two types of cap events from mds -> client:
34 - cap "issue" in a MClientReply, or an MClientCaps IMPORT op.
35 - cap "update" (revocation or grant) .. an MClientCaps message.
36 - if client has cap, the mds should have it too.
37
38 - if client has no dirty data, it can release it without waiting for an mds ack.
39 - client may thus get a cap _update_ and not have the cap. ignore it.
40
41 - mds should track seq of last issue. any release
42 attempt will only succeed if the client has seen the latest.
43
44 - a UPDATE updates the clients issued caps, wanted, etc. it may also flush dirty metadata.
45 - 'caps' are which caps the client retains.
46 - if 0, client wishes to release the cap
47 - 'wanted' is which caps the client wants.
48 - 'dirty' is which metadata is to be written.
49 - client gets a FLUSH_ACK with matching dirty flags indicating which caps were written.
50
51 - a FLUSH_ACK acks a FLUSH.
52 - 'dirty' is the _original_ FLUSH's dirty (i.e., which metadata was written back)
53 - 'seq' is the _original_ FLUSH's seq.
54 - 'caps' is the _original_ FLUSH's caps (not actually important)
55 - client can conclude that (dirty & ~caps) bits were successfully cleaned.
56
57 - a FLUSHSNAP flushes snapshot metadata.
58 - 'dirty' indicates which caps, were dirty, if any.
59 - mds writes metadata. if dirty!=0, replies with FLUSHSNAP_ACK.
60
61 */
62
63 class CInode;
64
65 namespace ceph {
66 class Formatter;
67 }
68
69 class Capability : public Counter<Capability> {
70 public:
71 MEMPOOL_CLASS_HELPERS();
72
73 struct Export {
74 int64_t cap_id;
75 int32_t wanted;
76 int32_t issued;
77 int32_t pending;
78 snapid_t client_follows;
79 ceph_seq_t seq;
80 ceph_seq_t mseq;
81 utime_t last_issue_stamp;
82 Export() : cap_id(0), wanted(0), issued(0), pending(0), seq(0), mseq(0) {}
83 Export(int64_t id, int w, int i, int p, snapid_t cf, ceph_seq_t s, ceph_seq_t m, utime_t lis) :
84 cap_id(id), wanted(w), issued(i), pending(p), client_follows(cf),
85 seq(s), mseq(m), last_issue_stamp(lis) {}
86 void encode(bufferlist &bl) const;
87 void decode(bufferlist::iterator &p);
88 void dump(Formatter *f) const;
89 static void generate_test_instances(list<Export*>& ls);
90 };
91 struct Import {
92 int64_t cap_id;
93 ceph_seq_t issue_seq;
94 ceph_seq_t mseq;
95 Import() : cap_id(0), issue_seq(0), mseq(0) {}
96 Import(int64_t i, ceph_seq_t s, ceph_seq_t m) : cap_id(i), issue_seq(s), mseq(m) {}
97 void encode(bufferlist &bl) const;
98 void decode(bufferlist::iterator &p);
99 void dump(Formatter *f) const;
100 };
101 struct revoke_info {
102 __u32 before;
103 ceph_seq_t seq, last_issue;
104 revoke_info() : before(0), seq(0), last_issue(0) {}
105 revoke_info(__u32 b, ceph_seq_t s, ceph_seq_t li) : before(b), seq(s), last_issue(li) {}
106 void encode(bufferlist& bl) const;
107 void decode(bufferlist::iterator& bl);
108 void dump(Formatter *f) const;
109 static void generate_test_instances(list<revoke_info*>& ls);
110 };
111
112
113 const static unsigned STATE_STALE = (1<<0);
114 const static unsigned STATE_NEW = (1<<1);
115 const static unsigned STATE_IMPORTING = (1<<2);
116
117
118 Capability(CInode *i = NULL, uint64_t id = 0, client_t c = 0) :
119 client_follows(0), client_xattr_version(0),
120 client_inline_version(0),
121 last_rbytes(0), last_rsize(0),
122 item_session_caps(this), item_snaprealm_caps(this),
123 item_revoking_caps(this), item_client_revoking_caps(this),
124 inode(i), client(c),
125 cap_id(id),
126 _wanted(0), num_revoke_warnings(0),
127 _pending(0), _issued(0),
128 last_sent(0),
129 last_issue(0),
130 mseq(0),
131 suppress(0), state(0) {
132 }
133 Capability(const Capability& other); // no copying
134
135 const Capability& operator=(const Capability& other); // no copying
136
137 int pending() { return _pending; }
138 int issued() { return _issued; }
139 bool is_null() { return !_pending && _revokes.empty(); }
140
141 ceph_seq_t issue(unsigned c) {
142 if (_pending & ~c) {
143 // revoking (and maybe adding) bits. note caps prior to this revocation
144 _revokes.emplace_back(_pending, last_sent, last_issue);
145 _pending = c;
146 _issued |= c;
147 } else if (~_pending & c) {
148 // adding bits only. remove obsolete revocations?
149 _pending |= c;
150 _issued |= c;
151 // drop old _revokes with no bits we don't have
152 while (!_revokes.empty() &&
153 (_revokes.back().before & ~_pending) == 0)
154 _revokes.pop_back();
155 } else {
156 // no change.
157 assert(_pending == c);
158 }
159 //last_issue =
160 ++last_sent;
161 return last_sent;
162 }
163 ceph_seq_t issue_norevoke(unsigned c) {
164 _pending |= c;
165 _issued |= c;
166 //check_rdcaps_list();
167 ++last_sent;
168 return last_sent;
169 }
170 void _calc_issued() {
171 _issued = _pending;
172 for (const auto &r : _revokes) {
173 _issued |= r.before;
174 }
175 }
176 void confirm_receipt(ceph_seq_t seq, unsigned caps) {
177 if (seq == last_sent) {
178 _revokes.clear();
179 _issued = caps;
180 // don't add bits
181 _pending &= caps;
182 } else {
183 // can i forget any revocations?
184 while (!_revokes.empty() && _revokes.front().seq < seq)
185 _revokes.pop_front();
186 if (!_revokes.empty()) {
187 if (_revokes.front().seq == seq)
188 _revokes.begin()->before = caps;
189 _calc_issued();
190 } else {
191 // seq < last_sent
192 _issued = caps | _pending;
193 }
194 }
195
196 if (_issued == _pending) {
197 item_revoking_caps.remove_myself();
198 item_client_revoking_caps.remove_myself();
199 }
200 //check_rdcaps_list();
201 }
202 // we may get a release racing with revocations, which means our revokes will be ignored
203 // by the client. clean them out of our _revokes history so we don't wait on them.
204 void clean_revoke_from(ceph_seq_t li) {
205 bool changed = false;
206 while (!_revokes.empty() && _revokes.front().last_issue <= li) {
207 _revokes.pop_front();
208 changed = true;
209 }
210 if (changed) {
211 _calc_issued();
212 if (_issued == _pending) {
213 item_revoking_caps.remove_myself();
214 item_client_revoking_caps.remove_myself();
215 }
216 }
217 }
218 ceph_seq_t get_mseq() { return mseq; }
219 void inc_mseq() { mseq++; }
220
221 ceph_seq_t get_last_sent() { return last_sent; }
222 utime_t get_last_issue_stamp() { return last_issue_stamp; }
223 utime_t get_last_revoke_stamp() { return last_revoke_stamp; }
224
225 void set_last_issue() { last_issue = last_sent; }
226 void set_last_issue_stamp(utime_t t) { last_issue_stamp = t; }
227 void set_last_revoke_stamp(utime_t t) { last_revoke_stamp = t; }
228 void reset_num_revoke_warnings() { num_revoke_warnings = 0; }
229 void inc_num_revoke_warnings() { ++num_revoke_warnings; }
230 unsigned get_num_revoke_warnings() { return num_revoke_warnings; }
231
232 void set_cap_id(uint64_t i) { cap_id = i; }
233 uint64_t get_cap_id() { return cap_id; }
234
235 //ceph_seq_t get_last_issue() { return last_issue; }
236
237 bool is_suppress() { return suppress > 0; }
238 void inc_suppress() { suppress++; }
239 void dec_suppress() { suppress--; }
240
241 bool is_stale() { return state & STATE_STALE; }
242 void mark_stale() { state |= STATE_STALE; }
243 void clear_stale() { state &= ~STATE_STALE; }
244 bool is_new() { return state & STATE_NEW; }
245 void mark_new() { state |= STATE_NEW; }
246 void clear_new() { state &= ~STATE_NEW; }
247 bool is_importing() { return state & STATE_IMPORTING; }
248 void mark_importing() { state |= STATE_IMPORTING; }
249 void clear_importing() { state &= ~STATE_IMPORTING; }
250
251 CInode *get_inode() { return inode; }
252 client_t get_client() const { return client; }
253
254 // caps this client wants to hold
255 int wanted() { return _wanted; }
256 void set_wanted(int w) {
257 _wanted = w;
258 //check_rdcaps_list();
259 }
260
261 void inc_last_seq() { last_sent++; }
262 ceph_seq_t get_last_seq() { return last_sent; }
263 ceph_seq_t get_last_issue() { return last_issue; }
264
265 void reset_seq() {
266 last_sent = 0;
267 last_issue = 0;
268 }
269
270 // -- exports --
271 Export make_export() {
272 return Export(cap_id, _wanted, issued(), pending(), client_follows, last_sent, mseq+1, last_issue_stamp);
273 }
274 void merge(const Export& other, bool auth_cap) {
275 if (!is_stale()) {
276 // issued + pending
277 int newpending = other.pending | pending();
278 if (other.issued & ~newpending)
279 issue(other.issued | newpending);
280 else
281 issue(newpending);
282 last_issue_stamp = other.last_issue_stamp;
283 } else {
284 issue(CEPH_CAP_PIN);
285 }
286
287 client_follows = other.client_follows;
288
289 // wanted
290 _wanted = _wanted | other.wanted;
291 if (auth_cap)
292 mseq = other.mseq;
293 }
294 void merge(int otherwanted, int otherissued) {
295 if (!is_stale()) {
296 // issued + pending
297 int newpending = pending();
298 if (otherissued & ~newpending)
299 issue(otherissued | newpending);
300 else
301 issue(newpending);
302 } else {
303 issue(CEPH_CAP_PIN);
304 }
305
306 // wanted
307 _wanted = _wanted | otherwanted;
308 }
309
310 void revoke() {
311 if (pending() & ~CEPH_CAP_PIN)
312 issue(CEPH_CAP_PIN);
313 confirm_receipt(last_sent, CEPH_CAP_PIN);
314 }
315
316 // serializers
317 void encode(bufferlist &bl) const;
318 void decode(bufferlist::iterator &bl);
319 void dump(Formatter *f) const;
320 static void generate_test_instances(list<Capability*>& ls);
321
322 snapid_t client_follows;
323 version_t client_xattr_version;
324 version_t client_inline_version;
325 int64_t last_rbytes;
326 int64_t last_rsize;
327
328 xlist<Capability*>::item item_session_caps;
329 xlist<Capability*>::item item_snaprealm_caps;
330 xlist<Capability*>::item item_revoking_caps;
331 xlist<Capability*>::item item_client_revoking_caps;
332
333 private:
334 CInode *inode;
335 client_t client;
336
337 uint64_t cap_id;
338
339 __u32 _wanted; // what the client wants (ideally)
340
341 utime_t last_issue_stamp;
342 utime_t last_revoke_stamp;
343 unsigned num_revoke_warnings;
344
345 // track in-flight caps --------------
346 // - add new caps to _pending
347 // - track revocations in _revokes list
348 __u32 _pending, _issued;
349 mempool::mds_co::list<revoke_info> _revokes;
350
351 ceph_seq_t last_sent;
352 ceph_seq_t last_issue;
353 ceph_seq_t mseq;
354
355 int suppress;
356 unsigned state;
357 };
358
359 WRITE_CLASS_ENCODER(Capability::Export)
360 WRITE_CLASS_ENCODER(Capability::Import)
361 WRITE_CLASS_ENCODER(Capability::revoke_info)
362 WRITE_CLASS_ENCODER(Capability)
363
364
365
366 #endif