1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 #include "common/Clock.h"
4 #include "common/Timer.h"
9 #include "Delegation.h"
11 class C_Deleg_Timeout
: public Context
{
14 explicit C_Deleg_Timeout(Delegation
*d
) : deleg(d
) {}
15 void finish(int r
) override
{
16 Inode
*in
= deleg
->get_fh()->inode
.get();
17 Client
*client
= in
->client
;
19 // Called back via Timer, which takes client_lock for us
20 assert(client
->client_lock
.is_locked_by_me());
22 lsubdout(client
->cct
, client
, 0) << __func__
<<
23 ": delegation return timeout for inode 0x" <<
24 std::hex
<< in
->ino
<< ". Forcibly unmounting client. "<<
25 client
<< std::dec
<< dendl
;
31 * ceph_deleg_caps_for_type - what caps are necessary for a delegation?
32 * @type: delegation request type
34 * Determine what caps are necessary in order to grant a delegation of a given
35 * type. For read delegations, we need whatever we require in order to do
36 * cached reads, plus AsLs to cover metadata changes that should trigger a
37 * recall. We also grab Xs since changing xattrs usually alters the mtime and
38 * so would trigger a recall.
40 * For write delegations, we need whatever read delegations need plus the
41 * caps to allow writing to the file (Fbwx).
43 int ceph_deleg_caps_for_type(unsigned type
)
45 int caps
= CEPH_CAP_PIN
;
48 case CEPH_DELEGATION_WR
:
49 caps
|= CEPH_CAP_FILE_EXCL
|
50 CEPH_CAP_FILE_WR
| CEPH_CAP_FILE_BUFFER
;
52 case CEPH_DELEGATION_RD
:
53 caps
|= CEPH_CAP_FILE_SHARED
|
54 CEPH_CAP_FILE_RD
| CEPH_CAP_FILE_CACHE
|
55 CEPH_CAP_XATTR_SHARED
|
56 CEPH_CAP_LINK_SHARED
| CEPH_CAP_AUTH_SHARED
;
59 // Should never happen
66 * A delegation is a container for holding caps on behalf of a client that
67 * wants to be able to rely on them until recalled.
69 Delegation::Delegation(Fh
*_fh
, unsigned _type
, ceph_deleg_cb_t _cb
, void *_priv
)
70 : fh(_fh
), priv(_priv
), type(_type
), recall_cb(_cb
),
71 recall_time(utime_t()), timeout_event(nullptr)
73 Inode
*inode
= _fh
->inode
.get();
74 inode
->client
->get_cap_ref(inode
, ceph_deleg_caps_for_type(_type
));
77 Delegation::~Delegation()
80 Inode
*inode
= fh
->inode
.get();
81 inode
->client
->put_cap_ref(inode
, ceph_deleg_caps_for_type(type
));
84 void Delegation::reinit(unsigned _type
, ceph_deleg_cb_t _recall_cb
, void *_priv
)
86 /* update cap refs -- note that we do a get first to avoid any going to 0 */
88 Inode
*inode
= fh
->inode
.get();
90 inode
->client
->get_cap_ref(inode
, ceph_deleg_caps_for_type(_type
));
91 inode
->client
->put_cap_ref(inode
, ceph_deleg_caps_for_type(type
));
95 recall_cb
= _recall_cb
;
99 void Delegation::arm_timeout()
101 Client
*client
= fh
->inode
.get()->client
;
106 timeout_event
= new C_Deleg_Timeout(this);
107 client
->timer
.add_event_after(client
->get_deleg_timeout(), timeout_event
);
110 void Delegation::disarm_timeout()
112 Client
*client
= fh
->inode
.get()->client
;
117 client
->timer
.cancel_event(timeout_event
);
118 timeout_event
= nullptr;
121 void Delegation::recall(bool skip_read
)
123 /* If skip_read is true, don't break read delegations */
124 if (skip_read
&& type
== CEPH_DELEGATION_RD
)
127 if (!is_recalled()) {
129 recall_time
= ceph_clock_now();