]> git.proxmox.com Git - ceph.git/blame - ceph/src/mds/Capability.h
bump version to 12.2.12-pve1
[ceph.git] / ceph / src / mds / Capability.h
CommitLineData
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_CAPABILITY_H
17#define CEPH_CAPABILITY_H
18
7c673cae 19#include "include/buffer_fwd.h"
94b18763
FG
20#include "include/counter.h"
21#include "include/mempool.h"
7c673cae
FG
22#include "include/xlist.h"
23
24#include "common/config.h"
25
26#include "mdstypes.h"
27
94b18763 28
7c673cae
FG
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
63class CInode;
a8e16298 64class Session;
7c673cae
FG
65
66namespace ceph {
67 class Formatter;
68}
69
70class Capability : public Counter<Capability> {
71public:
94b18763
FG
72 MEMPOOL_CLASS_HELPERS();
73
7c673cae
FG
74 struct Export {
75 int64_t cap_id;
76 int32_t wanted;
77 int32_t issued;
78 int32_t pending;
79 snapid_t client_follows;
80 ceph_seq_t seq;
81 ceph_seq_t mseq;
82 utime_t last_issue_stamp;
83 Export() : cap_id(0), wanted(0), issued(0), pending(0), seq(0), mseq(0) {}
84 Export(int64_t id, int w, int i, int p, snapid_t cf, ceph_seq_t s, ceph_seq_t m, utime_t lis) :
85 cap_id(id), wanted(w), issued(i), pending(p), client_follows(cf),
86 seq(s), mseq(m), last_issue_stamp(lis) {}
87 void encode(bufferlist &bl) const;
88 void decode(bufferlist::iterator &p);
89 void dump(Formatter *f) const;
90 static void generate_test_instances(list<Export*>& ls);
91 };
92 struct Import {
93 int64_t cap_id;
94 ceph_seq_t issue_seq;
95 ceph_seq_t mseq;
96 Import() : cap_id(0), issue_seq(0), mseq(0) {}
97 Import(int64_t i, ceph_seq_t s, ceph_seq_t m) : cap_id(i), issue_seq(s), mseq(m) {}
98 void encode(bufferlist &bl) const;
99 void decode(bufferlist::iterator &p);
100 void dump(Formatter *f) const;
101 };
102 struct revoke_info {
103 __u32 before;
104 ceph_seq_t seq, last_issue;
105 revoke_info() : before(0), seq(0), last_issue(0) {}
106 revoke_info(__u32 b, ceph_seq_t s, ceph_seq_t li) : before(b), seq(s), last_issue(li) {}
107 void encode(bufferlist& bl) const;
108 void decode(bufferlist::iterator& bl);
109 void dump(Formatter *f) const;
110 static void generate_test_instances(list<revoke_info*>& ls);
111 };
112
a8e16298 113 const static unsigned STATE_NOTABLE = (1<<0);
7c673cae
FG
114 const static unsigned STATE_NEW = (1<<1);
115 const static unsigned STATE_IMPORTING = (1<<2);
a8e16298 116 const static unsigned STATE_CLIENTWRITEABLE = (1<<4);
7c673cae 117
a8e16298 118 Capability(CInode *i=nullptr, Session *s=nullptr, uint64_t id=0);
7c673cae
FG
119 Capability(const Capability& other); // no copying
120
121 const Capability& operator=(const Capability& other); // no copying
122
a8e16298
TL
123 int pending() const {
124 return is_valid() ? _pending : (_pending & CEPH_CAP_PIN);
125 }
126 int issued() const {
127 return is_valid() ? _issued : (_issued & CEPH_CAP_PIN);
128 }
7c673cae
FG
129
130 ceph_seq_t issue(unsigned c) {
a8e16298
TL
131 revalidate();
132
7c673cae
FG
133 if (_pending & ~c) {
134 // revoking (and maybe adding) bits. note caps prior to this revocation
94b18763 135 _revokes.emplace_back(_pending, last_sent, last_issue);
7c673cae
FG
136 _pending = c;
137 _issued |= c;
a8e16298
TL
138 if (!is_notable())
139 mark_notable();
7c673cae
FG
140 } else if (~_pending & c) {
141 // adding bits only. remove obsolete revocations?
142 _pending |= c;
143 _issued |= c;
144 // drop old _revokes with no bits we don't have
145 while (!_revokes.empty() &&
146 (_revokes.back().before & ~_pending) == 0)
147 _revokes.pop_back();
148 } else {
149 // no change.
150 assert(_pending == c);
151 }
152 //last_issue =
a8e16298 153 inc_last_seq();
7c673cae
FG
154 return last_sent;
155 }
156 ceph_seq_t issue_norevoke(unsigned c) {
a8e16298
TL
157 revalidate();
158
7c673cae
FG
159 _pending |= c;
160 _issued |= c;
161 //check_rdcaps_list();
a8e16298 162 inc_last_seq();
7c673cae
FG
163 return last_sent;
164 }
7c673cae 165 void confirm_receipt(ceph_seq_t seq, unsigned caps) {
a8e16298 166 bool was_revoking = (_issued & ~_pending);
7c673cae
FG
167 if (seq == last_sent) {
168 _revokes.clear();
169 _issued = caps;
170 // don't add bits
171 _pending &= caps;
172 } else {
173 // can i forget any revocations?
174 while (!_revokes.empty() && _revokes.front().seq < seq)
175 _revokes.pop_front();
176 if (!_revokes.empty()) {
177 if (_revokes.front().seq == seq)
178 _revokes.begin()->before = caps;
a8e16298 179 calc_issued();
7c673cae
FG
180 } else {
181 // seq < last_sent
182 _issued = caps | _pending;
183 }
184 }
185
a8e16298 186 if (was_revoking && _issued == _pending) {
7c673cae
FG
187 item_revoking_caps.remove_myself();
188 item_client_revoking_caps.remove_myself();
a8e16298 189 maybe_clear_notable();
7c673cae
FG
190 }
191 //check_rdcaps_list();
192 }
193 // we may get a release racing with revocations, which means our revokes will be ignored
194 // by the client. clean them out of our _revokes history so we don't wait on them.
195 void clean_revoke_from(ceph_seq_t li) {
196 bool changed = false;
197 while (!_revokes.empty() && _revokes.front().last_issue <= li) {
198 _revokes.pop_front();
199 changed = true;
200 }
201 if (changed) {
a8e16298
TL
202 bool was_revoking = (_issued & ~_pending);
203 calc_issued();
204 if (was_revoking && _issued == _pending) {
7c673cae
FG
205 item_revoking_caps.remove_myself();
206 item_client_revoking_caps.remove_myself();
a8e16298 207 maybe_clear_notable();
7c673cae
FG
208 }
209 }
210 }
211 ceph_seq_t get_mseq() { return mseq; }
212 void inc_mseq() { mseq++; }
213
a8e16298
TL
214 utime_t get_last_issue_stamp() const { return last_issue_stamp; }
215 utime_t get_last_revoke_stamp() const { return last_revoke_stamp; }
7c673cae
FG
216
217 void set_last_issue() { last_issue = last_sent; }
218 void set_last_issue_stamp(utime_t t) { last_issue_stamp = t; }
219 void set_last_revoke_stamp(utime_t t) { last_revoke_stamp = t; }
220 void reset_num_revoke_warnings() { num_revoke_warnings = 0; }
221 void inc_num_revoke_warnings() { ++num_revoke_warnings; }
222 unsigned get_num_revoke_warnings() { return num_revoke_warnings; }
223
224 void set_cap_id(uint64_t i) { cap_id = i; }
225 uint64_t get_cap_id() { return cap_id; }
226
227 //ceph_seq_t get_last_issue() { return last_issue; }
228
229 bool is_suppress() { return suppress > 0; }
230 void inc_suppress() { suppress++; }
231 void dec_suppress() { suppress--; }
232
a8e16298
TL
233 static bool is_wanted_notable(int wanted) {
234 return wanted & (CEPH_CAP_ANY_WR|CEPH_CAP_FILE_WR|CEPH_CAP_FILE_RD);
235 }
236 bool is_notable() const { return state & STATE_NOTABLE; }
237
238 bool is_stale() const;
239 bool is_new() const { return state & STATE_NEW; }
7c673cae
FG
240 void mark_new() { state |= STATE_NEW; }
241 void clear_new() { state &= ~STATE_NEW; }
242 bool is_importing() { return state & STATE_IMPORTING; }
243 void mark_importing() { state |= STATE_IMPORTING; }
244 void clear_importing() { state &= ~STATE_IMPORTING; }
245
a8e16298
TL
246 bool is_clientwriteable() const { return state & STATE_CLIENTWRITEABLE; }
247 void mark_clientwriteable() {
248 if (!is_clientwriteable()) {
249 state |= STATE_CLIENTWRITEABLE;
250 if (!is_notable())
251 mark_notable();
252 }
253 }
254 void clear_clientwriteable() {
255 if (is_clientwriteable()) {
256 state &= ~STATE_CLIENTWRITEABLE;
257 maybe_clear_notable();
258 }
259 }
260
261 CInode *get_inode() const { return inode; }
262 Session *get_session() const { return session; }
263 client_t get_client() const;
7c673cae
FG
264
265 // caps this client wants to hold
a8e16298
TL
266 int wanted() const { return _wanted; }
267 void set_wanted(int w);
7c673cae
FG
268
269 void inc_last_seq() { last_sent++; }
a8e16298
TL
270 ceph_seq_t get_last_seq() const {
271 if (!is_valid() && (_pending & ~CEPH_CAP_PIN))
272 return last_sent + 1;
273 return last_sent;
274 }
275 ceph_seq_t get_last_issue() const { return last_issue; }
7c673cae
FG
276
277 void reset_seq() {
278 last_sent = 0;
279 last_issue = 0;
280 }
281
282 // -- exports --
a8e16298
TL
283 Export make_export() const {
284 return Export(cap_id, wanted(), issued(), pending(), client_follows, get_last_seq(), mseq+1, last_issue_stamp);
7c673cae 285 }
28e407b8 286 void merge(const Export& other, bool auth_cap) {
7c673cae
FG
287 if (!is_stale()) {
288 // issued + pending
289 int newpending = other.pending | pending();
290 if (other.issued & ~newpending)
291 issue(other.issued | newpending);
292 else
293 issue(newpending);
294 last_issue_stamp = other.last_issue_stamp;
295 } else {
296 issue(CEPH_CAP_PIN);
297 }
298
299 client_follows = other.client_follows;
300
301 // wanted
a8e16298 302 set_wanted(wanted() | other.wanted);
7c673cae
FG
303 if (auth_cap)
304 mseq = other.mseq;
305 }
306 void merge(int otherwanted, int otherissued) {
307 if (!is_stale()) {
308 // issued + pending
309 int newpending = pending();
310 if (otherissued & ~newpending)
311 issue(otherissued | newpending);
312 else
313 issue(newpending);
314 } else {
315 issue(CEPH_CAP_PIN);
316 }
317
318 // wanted
a8e16298 319 set_wanted(wanted() | otherwanted);
7c673cae
FG
320 }
321
322 void revoke() {
323 if (pending() & ~CEPH_CAP_PIN)
324 issue(CEPH_CAP_PIN);
325 confirm_receipt(last_sent, CEPH_CAP_PIN);
326 }
327
328 // serializers
329 void encode(bufferlist &bl) const;
330 void decode(bufferlist::iterator &bl);
331 void dump(Formatter *f) const;
332 static void generate_test_instances(list<Capability*>& ls);
333
334 snapid_t client_follows;
335 version_t client_xattr_version;
336 version_t client_inline_version;
337 int64_t last_rbytes;
338 int64_t last_rsize;
339
340 xlist<Capability*>::item item_session_caps;
341 xlist<Capability*>::item item_snaprealm_caps;
342 xlist<Capability*>::item item_revoking_caps;
343 xlist<Capability*>::item item_client_revoking_caps;
344
345private:
346 CInode *inode;
a8e16298 347 Session *session;
7c673cae
FG
348
349 uint64_t cap_id;
a8e16298 350 uint32_t cap_gen;
7c673cae
FG
351
352 __u32 _wanted; // what the client wants (ideally)
353
354 utime_t last_issue_stamp;
355 utime_t last_revoke_stamp;
356 unsigned num_revoke_warnings;
357
358 // track in-flight caps --------------
359 // - add new caps to _pending
360 // - track revocations in _revokes list
361 __u32 _pending, _issued;
94b18763 362 mempool::mds_co::list<revoke_info> _revokes;
7c673cae
FG
363
364 ceph_seq_t last_sent;
365 ceph_seq_t last_issue;
366 ceph_seq_t mseq;
367
368 int suppress;
369 unsigned state;
a8e16298
TL
370
371 void calc_issued() {
372 _issued = _pending;
373 for (const auto &r : _revokes) {
374 _issued |= r.before;
375 }
376 }
377
378 bool is_valid() const;
379 void revalidate();
380
381 void mark_notable();
382 void maybe_clear_notable();
7c673cae
FG
383};
384
385WRITE_CLASS_ENCODER(Capability::Export)
386WRITE_CLASS_ENCODER(Capability::Import)
387WRITE_CLASS_ENCODER(Capability::revoke_info)
388WRITE_CLASS_ENCODER(Capability)
389
390
391
392#endif