1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
16 #ifndef CEPH_CAPABILITY_H
17 #define CEPH_CAPABILITY_H
19 #include "include/buffer_fwd.h"
20 #include "include/counter.h"
21 #include "include/mempool.h"
22 #include "include/xlist.h"
23 #include "include/elist.h"
25 #include "common/config.h"
32 Capability protocol notes.
34 - two types of cap events from mds -> client:
35 - cap "issue" in a MClientReply, or an MClientCaps IMPORT op.
36 - cap "update" (revocation or grant) .. an MClientCaps message.
37 - if client has cap, the mds should have it too.
39 - if client has no dirty data, it can release it without waiting for an mds ack.
40 - client may thus get a cap _update_ and not have the cap. ignore it.
42 - mds should track seq of last issue. any release
43 attempt will only succeed if the client has seen the latest.
45 - a UPDATE updates the clients issued caps, wanted, etc. it may also flush dirty metadata.
46 - 'caps' are which caps the client retains.
47 - if 0, client wishes to release the cap
48 - 'wanted' is which caps the client wants.
49 - 'dirty' is which metadata is to be written.
50 - client gets a FLUSH_ACK with matching dirty flags indicating which caps were written.
52 - a FLUSH_ACK acks a FLUSH.
53 - 'dirty' is the _original_ FLUSH's dirty (i.e., which metadata was written back)
54 - 'seq' is the _original_ FLUSH's seq.
55 - 'caps' is the _original_ FLUSH's caps (not actually important)
56 - client can conclude that (dirty & ~caps) bits were successfully cleaned.
58 - a FLUSHSNAP flushes snapshot metadata.
59 - 'dirty' indicates which caps, were dirty, if any.
60 - mds writes metadata. if dirty!=0, replies with FLUSHSNAP_ACK.
72 class Capability
: public Counter
<Capability
> {
74 MEMPOOL_CLASS_HELPERS();
78 Export(int64_t id
, int w
, int i
, int p
, snapid_t cf
,
79 ceph_seq_t s
, ceph_seq_t m
, utime_t lis
, unsigned st
) :
80 cap_id(id
), wanted(w
), issued(i
), pending(p
), client_follows(cf
),
81 seq(s
), mseq(m
), last_issue_stamp(lis
), state(st
) {}
82 void encode(ceph::buffer::list
&bl
) const;
83 void decode(ceph::buffer::list::const_iterator
&p
);
84 void dump(ceph::Formatter
*f
) const;
85 static void generate_test_instances(std::list
<Export
*>& ls
);
91 snapid_t client_follows
;
94 utime_t last_issue_stamp
;
99 Import(int64_t i
, ceph_seq_t s
, ceph_seq_t m
) : cap_id(i
), issue_seq(s
), mseq(m
) {}
100 void encode(ceph::buffer::list
&bl
) const;
101 void decode(ceph::buffer::list::const_iterator
&p
);
102 void dump(ceph::Formatter
*f
) const;
105 ceph_seq_t issue_seq
= 0;
110 revoke_info(__u32 b
, ceph_seq_t s
, ceph_seq_t li
) : before(b
), seq(s
), last_issue(li
) {}
111 void encode(ceph::buffer::list
& bl
) const;
112 void decode(ceph::buffer::list::const_iterator
& bl
);
113 void dump(ceph::Formatter
*f
) const;
114 static void generate_test_instances(std::list
<revoke_info
*>& ls
);
118 ceph_seq_t last_issue
= 0;
121 const static unsigned STATE_NOTABLE
= (1<<0);
122 const static unsigned STATE_NEW
= (1<<1);
123 const static unsigned STATE_IMPORTING
= (1<<2);
124 const static unsigned STATE_NEEDSNAPFLUSH
= (1<<3);
125 const static unsigned STATE_CLIENTWRITEABLE
= (1<<4);
126 const static unsigned STATE_NOINLINE
= (1<<5);
127 const static unsigned STATE_NOPOOLNS
= (1<<6);
128 const static unsigned STATE_NOQUOTA
= (1<<7);
130 const static unsigned MASK_STATE_EXPORTED
=
131 (STATE_CLIENTWRITEABLE
| STATE_NOINLINE
| STATE_NOPOOLNS
| STATE_NOQUOTA
);
133 Capability(CInode
*i
=nullptr, Session
*s
=nullptr, uint64_t id
=0);
134 Capability(const Capability
& other
) = delete;
136 const Capability
& operator=(const Capability
& other
) = delete;
138 int pending() const {
144 int revoking() const {
145 return _issued
& ~_pending
;
147 ceph_seq_t
issue(unsigned c
, bool reval
=false) {
152 // revoking (and maybe adding) bits. note caps prior to this revocation
153 _revokes
.emplace_back(_pending
, last_sent
, last_issue
);
158 } else if (~_pending
& c
) {
159 // adding bits only. remove obsolete revocations?
162 // drop old _revokes with no bits we don't have
163 while (!_revokes
.empty() &&
164 (_revokes
.back().before
& ~_pending
) == 0)
168 ceph_assert(_pending
== c
);
174 ceph_seq_t
issue_norevoke(unsigned c
, bool reval
=false) {
185 int confirm_receipt(ceph_seq_t seq
, unsigned caps
);
186 // we may get a release racing with revocations, which means our revokes will be ignored
187 // by the client. clean them out of our _revokes history so we don't wait on them.
188 void clean_revoke_from(ceph_seq_t li
) {
189 bool changed
= false;
190 while (!_revokes
.empty() && _revokes
.front().last_issue
<= li
) {
191 _revokes
.pop_front();
195 bool was_revoking
= (_issued
& ~_pending
);
197 if (was_revoking
&& _issued
== _pending
) {
198 item_revoking_caps
.remove_myself();
199 item_client_revoking_caps
.remove_myself();
200 maybe_clear_notable();
204 ceph_seq_t
get_mseq() const { return mseq
; }
205 void inc_mseq() { mseq
++; }
207 utime_t
get_last_issue_stamp() const { return last_issue_stamp
; }
208 utime_t
get_last_revoke_stamp() const { return last_revoke_stamp
; }
210 void set_last_issue() { last_issue
= last_sent
; }
211 void set_last_issue_stamp(utime_t t
) { last_issue_stamp
= t
; }
212 void set_last_revoke_stamp(utime_t t
) { last_revoke_stamp
= t
; }
213 void reset_num_revoke_warnings() { num_revoke_warnings
= 0; }
214 void inc_num_revoke_warnings() { ++num_revoke_warnings
; }
215 unsigned get_num_revoke_warnings() const { return num_revoke_warnings
; }
217 void set_cap_id(uint64_t i
) { cap_id
= i
; }
218 uint64_t get_cap_id() const { return cap_id
; }
220 //ceph_seq_t get_last_issue() { return last_issue; }
222 bool is_suppress() const { return suppress
> 0; }
223 void inc_suppress() { suppress
++; }
224 void dec_suppress() { suppress
--; }
226 static bool is_wanted_notable(int wanted
) {
227 return wanted
& (CEPH_CAP_ANY_WR
|CEPH_CAP_FILE_WR
|CEPH_CAP_FILE_RD
);
229 bool is_wanted_notable() const {
230 return is_wanted_notable(wanted());
232 bool is_notable() const { return state
& STATE_NOTABLE
; }
234 bool is_stale() const;
235 bool is_valid() const;
236 bool is_new() const { return state
& STATE_NEW
; }
237 void mark_new() { state
|= STATE_NEW
; }
238 void clear_new() { state
&= ~STATE_NEW
; }
239 bool is_importing() const { return state
& STATE_IMPORTING
; }
240 void mark_importing() { state
|= STATE_IMPORTING
; }
241 void clear_importing() { state
&= ~STATE_IMPORTING
; }
242 bool need_snapflush() const { return state
& STATE_NEEDSNAPFLUSH
; }
243 void mark_needsnapflush() { state
|= STATE_NEEDSNAPFLUSH
; }
244 void clear_needsnapflush() { state
&= ~STATE_NEEDSNAPFLUSH
; }
246 bool is_clientwriteable() const { return state
& STATE_CLIENTWRITEABLE
; }
247 void mark_clientwriteable() {
248 if (!is_clientwriteable()) {
249 state
|= STATE_CLIENTWRITEABLE
;
254 void clear_clientwriteable() {
255 if (is_clientwriteable()) {
256 state
&= ~STATE_CLIENTWRITEABLE
;
257 maybe_clear_notable();
261 bool is_noinline() const { return state
& STATE_NOINLINE
; }
262 bool is_nopoolns() const { return state
& STATE_NOPOOLNS
; }
263 bool is_noquota() const { return state
& STATE_NOQUOTA
; }
265 CInode
*get_inode() const { return inode
; }
266 Session
*get_session() const { return session
; }
267 client_t
get_client() const;
269 // caps this client wants to hold
270 int wanted() const { return _wanted
; }
271 void set_wanted(int w
);
273 void inc_last_seq() { last_sent
++; }
274 ceph_seq_t
get_last_seq() const {
277 ceph_seq_t
get_last_issue() const { return last_issue
; }
285 Export
make_export() const {
286 return Export(cap_id
, wanted(), issued(), pending(), client_follows
, get_last_seq(), mseq
+1, last_issue_stamp
, state
);
288 void merge(const Export
& other
, bool auth_cap
) {
290 int newpending
= other
.pending
| pending();
291 if (other
.issued
& ~newpending
)
292 issue(other
.issued
| newpending
);
295 last_issue_stamp
= other
.last_issue_stamp
;
297 client_follows
= other
.client_follows
;
299 state
|= other
.state
& MASK_STATE_EXPORTED
;
300 if ((other
.state
& STATE_CLIENTWRITEABLE
) && !is_notable())
304 set_wanted(wanted() | other
.wanted
);
308 void merge(int otherwanted
, int otherissued
) {
310 int newpending
= pending();
311 if (otherissued
& ~newpending
)
312 issue(otherissued
| newpending
);
317 set_wanted(wanted() | otherwanted
);
322 return confirm_receipt(last_sent
, pending());
327 void encode(ceph::buffer::list
&bl
) const;
328 void decode(ceph::buffer::list::const_iterator
&bl
);
329 void dump(ceph::Formatter
*f
) const;
330 static void generate_test_instances(std::list
<Capability
*>& ls
);
332 snapid_t client_follows
= 0;
333 version_t client_xattr_version
= 0;
334 version_t client_inline_version
= 0;
335 int64_t last_rbytes
= 0;
336 int64_t last_rsize
= 0;
338 xlist
<Capability
*>::item item_session_caps
;
339 xlist
<Capability
*>::item item_snaprealm_caps
;
340 xlist
<Capability
*>::item item_revoking_caps
;
341 xlist
<Capability
*>::item item_client_revoking_caps
;
343 elist
<MDLockCache
*> lock_caches
;
344 int get_lock_cache_allowed() const { return lock_cache_allowed
; }
345 void set_lock_cache_allowed(int c
) { lock_cache_allowed
|= c
; }
346 void clear_lock_cache_allowed(int c
) { lock_cache_allowed
&= ~c
; }
351 for (const auto &r
: _revokes
) {
359 void maybe_clear_notable();
367 __u32 _wanted
= 0; // what the client wants (ideally)
369 utime_t last_issue_stamp
;
370 utime_t last_revoke_stamp
;
371 unsigned num_revoke_warnings
= 0;
373 // track in-flight caps --------------
374 // - add new caps to _pending
375 // - track revocations in _revokes list
376 __u32 _pending
= 0, _issued
= 0;
377 mempool::mds_co::list
<revoke_info
> _revokes
;
379 ceph_seq_t last_sent
= 0;
380 ceph_seq_t last_issue
= 0;
386 int lock_cache_allowed
= 0;
389 WRITE_CLASS_ENCODER(Capability::Export
)
390 WRITE_CLASS_ENCODER(Capability::Import
)
391 WRITE_CLASS_ENCODER(Capability::revoke_info
)
392 WRITE_CLASS_ENCODER(Capability
)