]> git.proxmox.com Git - ceph.git/blob - ceph/src/client/Delegation.cc
update sources to v12.2.3
[ceph.git] / ceph / src / client / Delegation.cc
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
11 class C_Deleg_Timeout : public Context {
12 Delegation *deleg;
13 public:
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 */
43 int 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 */
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)
72 {
73 Inode *inode = _fh->inode.get();
74 inode->client->get_cap_ref(inode, ceph_deleg_caps_for_type(_type));
75 };
76
77 Delegation::~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
84 void 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
99 void 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
110 void 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
121 void 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 }