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