]> git.proxmox.com Git - ceph.git/blame - ceph/src/client/Delegation.cc
update sources to v12.2.3
[ceph.git] / ceph / src / client / Delegation.cc
CommitLineData
b32b8144
FG
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"
5
6#include "Client.h"
7#include "Inode.h"
8#include "Fh.h"
9#include "Delegation.h"
10
11class C_Deleg_Timeout : public Context {
12 Delegation *deleg;
13public:
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;
18
19 // Called back via Timer, which takes client_lock for us
20 assert(client->client_lock.is_locked_by_me());
21
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;
26 client->_unmount();
27 }
28};
29
30/**
31 * ceph_deleg_caps_for_type - what caps are necessary for a delegation?
32 * @type: delegation request type
33 *
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.
39 *
40 * For write delegations, we need whatever read delegations need plus the
41 * caps to allow writing to the file (Fbwx).
42 */
43int ceph_deleg_caps_for_type(unsigned type)
44{
45 int caps = CEPH_CAP_PIN;
46
47 switch (type) {
48 case CEPH_DELEGATION_WR:
49 caps |= CEPH_CAP_FILE_EXCL |
50 CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER;
51 /* Fallthrough */
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;
57 break;
58 default:
59 // Should never happen
60 assert(false);
61 }
62 return caps;
63}
64
65/*
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.
68 */
69Delegation::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)
72{
73 Inode *inode = _fh->inode.get();
74 inode->client->get_cap_ref(inode, ceph_deleg_caps_for_type(_type));
75};
76
77Delegation::~Delegation()
78{
79 disarm_timeout();
80 Inode *inode = fh->inode.get();
81 inode->client->put_cap_ref(inode, ceph_deleg_caps_for_type(type));
82}
83
84void Delegation::reinit(unsigned _type, ceph_deleg_cb_t _recall_cb, void *_priv)
85{
86 /* update cap refs -- note that we do a get first to avoid any going to 0 */
87 if (type != _type) {
88 Inode *inode = fh->inode.get();
89
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));
92 type = _type;
93 }
94
95 recall_cb = _recall_cb;
96 priv = _priv;
97}
98
99void Delegation::arm_timeout()
100{
101 Client *client = fh->inode.get()->client;
102
103 if (timeout_event)
104 return;
105
106 timeout_event = new C_Deleg_Timeout(this);
107 client->timer.add_event_after(client->get_deleg_timeout(), timeout_event);
108}
109
110void Delegation::disarm_timeout()
111{
112 Client *client = fh->inode.get()->client;
113
114 if (!timeout_event)
115 return;
116
117 client->timer.cancel_event(timeout_event);
118 timeout_event = nullptr;
119}
120
121void Delegation::recall(bool skip_read)
122{
123 /* If skip_read is true, don't break read delegations */
124 if (skip_read && type == CEPH_DELEGATION_RD)
125 return;
126
127 if (!is_recalled()) {
128 recall_cb(fh, priv);
129 recall_time = ceph_clock_now();
130 arm_timeout();
131 }
132}