From e6918187568dbd01842d8d1d2c808ce16a894239 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:54:28 +0200 Subject: Adding upstream version 18.2.2. Signed-off-by: Daniel Baumann --- src/client/Delegation.cc | 131 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/client/Delegation.cc (limited to 'src/client/Delegation.cc') diff --git a/src/client/Delegation.cc b/src/client/Delegation.cc new file mode 100644 index 000000000..0c0ac1b35 --- /dev/null +++ b/src/client/Delegation.cc @@ -0,0 +1,131 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +#include "common/Clock.h" +#include "common/Timer.h" + +#include "Client.h" +#include "Inode.h" +#include "Fh.h" +#include "Delegation.h" + +class C_Deleg_Timeout : public Context { + Delegation *deleg; +public: + explicit C_Deleg_Timeout(Delegation *d) : deleg(d) {} + void finish(int r) override { + Inode *in = deleg->get_fh()->inode.get(); + Client *client = in->client; + + lsubdout(client->cct, client, 0) << __func__ << + ": delegation return timeout for inode 0x" << + std::hex << in->ino << ". Forcibly unmounting client. "<< + client << std::dec << dendl; + client->_unmount(false); + } +}; + +/** + * ceph_deleg_caps_for_type - what caps are necessary for a delegation? + * @type: delegation request type + * + * Determine what caps are necessary in order to grant a delegation of a given + * type. For read delegations, we need whatever we require in order to do + * cached reads, plus AsLs to cover metadata changes that should trigger a + * recall. We also grab Xs since changing xattrs usually alters the mtime and + * so would trigger a recall. + * + * For write delegations, we need whatever read delegations need plus the + * caps to allow writing to the file (Fbwx). + */ +int ceph_deleg_caps_for_type(unsigned type) +{ + int caps = CEPH_CAP_PIN; + + switch (type) { + case CEPH_DELEGATION_WR: + caps |= CEPH_CAP_FILE_EXCL | + CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER; + /* Fallthrough */ + case CEPH_DELEGATION_RD: + caps |= CEPH_CAP_FILE_SHARED | + CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE | + CEPH_CAP_XATTR_SHARED | + CEPH_CAP_LINK_SHARED | CEPH_CAP_AUTH_SHARED; + break; + default: + // Should never happen + ceph_abort(); + } + return caps; +} + +/* + * A delegation is a container for holding caps on behalf of a client that + * wants to be able to rely on them until recalled. + */ +Delegation::Delegation(Fh *_fh, unsigned _type, ceph_deleg_cb_t _cb, void *_priv) + : fh(_fh), priv(_priv), type(_type), recall_cb(_cb), + recall_time(utime_t()), timeout_event(nullptr) +{ + Inode *inode = _fh->inode.get(); + inode->client->get_cap_ref(inode, ceph_deleg_caps_for_type(_type)); +}; + +Delegation::~Delegation() +{ + disarm_timeout(); + Inode *inode = fh->inode.get(); + inode->client->put_cap_ref(inode, ceph_deleg_caps_for_type(type)); +} + +void Delegation::reinit(unsigned _type, ceph_deleg_cb_t _recall_cb, void *_priv) +{ + /* update cap refs -- note that we do a get first to avoid any going to 0 */ + if (type != _type) { + Inode *inode = fh->inode.get(); + + inode->client->get_cap_ref(inode, ceph_deleg_caps_for_type(_type)); + inode->client->put_cap_ref(inode, ceph_deleg_caps_for_type(type)); + type = _type; + } + + recall_cb = _recall_cb; + priv = _priv; +} + +void Delegation::arm_timeout() +{ + Client *client = fh->inode.get()->client; + + std::scoped_lock l(client->timer_lock); + if (timeout_event) + return; + + timeout_event = new C_Deleg_Timeout(this); + client->timer.add_event_after(client->get_deleg_timeout(), timeout_event); +} + +void Delegation::disarm_timeout() +{ + Client *client = fh->inode.get()->client; + + std::scoped_lock l(client->timer_lock); + if (!timeout_event) + return; + + client->timer.cancel_event(timeout_event); + timeout_event = nullptr; +} + +void Delegation::recall(bool skip_read) +{ + /* If skip_read is true, don't break read delegations */ + if (skip_read && type == CEPH_DELEGATION_RD) + return; + + if (!is_recalled()) { + recall_cb(fh, priv); + recall_time = ceph_clock_now(); + arm_timeout(); + } +} -- cgit v1.2.3