]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: initial code for client states reclaim
authorYan, Zheng <zyan@redhat.com>
Tue, 25 Sep 2018 16:50:08 +0000 (12:50 -0400)
committerYan, Zheng <zyan@redhat.com>
Wed, 26 Sep 2018 13:42:51 +0000 (21:42 +0800)
this patch only implements function that cancels out old session

[ jlayton: adapt to new fs_name field in cmount ]

Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
15 files changed:
src/client/Client.cc
src/client/Client.h
src/client/MetaSession.h
src/common/ceph_strings.cc
src/include/ceph_fs.h
src/include/cephfs/libcephfs.h
src/libcephfs.cc
src/mds/MDSRank.cc
src/mds/Server.cc
src/mds/Server.h
src/mds/SessionMap.h
src/mds/cephfs_features.h
src/messages/MClientReclaim.h [new file with mode: 0644]
src/messages/MClientReclaimReply.h [new file with mode: 0644]
src/msg/Message.cc

index 82577eff64fe56f92b71e00d0f6b8435abe81806..a8534663ad28d765dc20a5b5210c1666a3a6bffe 100644 (file)
@@ -54,6 +54,8 @@
 #include "messages/MClientCaps.h"
 #include "messages/MClientLease.h"
 #include "messages/MClientSnap.h"
+#include "messages/MClientReclaim.h"
+#include "messages/MClientReclaimReply.h"
 #include "messages/MCommandReply.h"
 #include "messages/MOSDMap.h"
 #include "messages/MClientQuota.h"
@@ -2550,6 +2552,11 @@ bool Client::ms_dispatch(Message *m)
     handle_client_reply(static_cast<MClientReply*>(m));
     break;
 
+  // reclaim reply
+  case CEPH_MSG_CLIENT_RECLAIM_REPLY:
+    handle_client_reclaim_reply(static_cast<MClientReclaimReply*>(m));
+    break;
+
   case CEPH_MSG_CLIENT_SNAP:
     handle_snap(static_cast<MClientSnap*>(m));
     break;
@@ -2775,6 +2782,9 @@ void Client::send_reconnect(MetaSession *session)
   session->con->send_message(m);
 
   mount_cond.Signal();
+
+  if (session->reclaim_state == MetaSession::RECLAIMING)
+    signal_cond_list(waiting_for_reclaim);
 }
 
 
@@ -5709,18 +5719,8 @@ void Client::handle_command_reply(MCommandReply *m)
 // -------------------
 // MOUNT
 
-int Client::mount(const std::string &mount_root, const UserPerm& perms,
-                 bool require_mds, const std::string &fs_name)
+int Client::subscribe_mdsmap(const std::string &fs_name)
 {
-  Mutex::Locker lock(client_lock);
-
-  if (mounted) {
-    ldout(cct, 5) << "already mounted" << dendl;
-    return 0;
-  }
-
-  unmounting = false;
-
   int r = authenticate();
   if (r < 0) {
     lderr(cct) << "authentication failed: " << cpp_strerror(r) << dendl;
@@ -5753,6 +5753,27 @@ int Client::mount(const std::string &mount_root, const UserPerm& perms,
   monclient->sub_want(want, 0, 0);
   monclient->renew_subs();
 
+  return 0;
+}
+
+int Client::mount(const std::string &mount_root, const UserPerm& perms,
+                 bool require_mds, const std::string &fs_name)
+{
+  Mutex::Locker lock(client_lock);
+
+  if (mounted) {
+    ldout(cct, 5) << "already mounted" << dendl;
+    return 0;
+  }
+
+  unmounting = false;
+
+  int r = subscribe_mdsmap(fs_name);
+  if (r < 0) {
+    lderr(cct) << "mdsmap subscription failed: " << cpp_strerror(r) << dendl;
+    return r;
+  }
+
   tick(); // start tick
   
   if (require_mds) {
@@ -14174,6 +14195,162 @@ void Client::clear_filer_flags(int flags)
   objecter->clear_global_op_flag(flags);
 }
 
+// called before mount
+void Client::set_uuid(const std::string& uuid)
+{
+  Mutex::Locker l(client_lock);
+  assert(initialized);
+  assert(!uuid.empty());
+
+  metadata["uuid"] = uuid;
+  _close_sessions();
+}
+
+// called before mount
+int Client::start_reclaim(const std::string& uuid, unsigned flags,
+                         const std::string& fs_name)
+{
+  Mutex::Locker l(client_lock);
+  if (!initialized)
+    return -ENOTCONN;
+
+  if (uuid.empty())
+    return -EINVAL;
+
+  {
+    auto it = metadata.find("uuid");
+    if (it != metadata.end() && it->second == uuid)
+      return -EINVAL;
+  }
+
+  int r = subscribe_mdsmap(fs_name);
+  if (r < 0) {
+    lderr(cct) << "mdsmap subscription failed: " << cpp_strerror(r) << dendl;
+    return r;
+  }
+
+  if (metadata.empty())
+    populate_metadata("");
+
+  while (mdsmap->get_epoch() == 0)
+    wait_on_list(waiting_for_mdsmap);
+
+  reclaim_errno = 0;
+  for (unsigned mds = 0; mds < mdsmap->get_num_in_mds(); ) {
+    if (!mdsmap->is_up(mds)) {
+      ldout(cct, 10) << "mds." << mds << " not active, waiting for new mdsmap" << dendl;
+      wait_on_list(waiting_for_mdsmap);
+      continue;
+    }
+
+    MetaSession *session;
+    if (!have_open_session(mds)) {
+      session = _get_or_open_mds_session(mds);
+      if (session->state != MetaSession::STATE_OPENING) {
+       // umounting?
+       return -EINVAL;
+      }
+      ldout(cct, 10) << "waiting for session to mds." << mds << " to open" << dendl;
+      wait_on_context_list(session->waiting_for_open);
+      if (rejected_by_mds.count(mds))
+       return -EPERM;
+      continue;
+    }
+
+    session = &mds_sessions.at(mds);
+    if (!session->mds_features.test(CEPHFS_FEATURE_RECLAIM_CLIENT))
+      return -EOPNOTSUPP;
+
+    if (session->reclaim_state == MetaSession::RECLAIM_NULL ||
+       session->reclaim_state == MetaSession::RECLAIMING) {
+      session->reclaim_state = MetaSession::RECLAIMING;
+      auto m = MClientReclaim::create(uuid, flags);
+      session->con->send_message2(m);
+      wait_on_list(waiting_for_reclaim);
+    } else if (session->reclaim_state == MetaSession::RECLAIM_FAIL) {
+      return reclaim_errno ? : -ENOTRECOVERABLE;
+    } else {
+      mds++;
+    }
+  }
+
+  // didn't find target session in any mds
+  if (reclaim_target_addrs.empty()) {
+    if (flags & CEPH_RECLAIM_RESET)
+      return -ENOENT;
+    return -ENOTRECOVERABLE;
+  }
+
+  if (flags & CEPH_RECLAIM_RESET)
+    return 0;
+
+  // use blacklist to check if target session was killed
+  // (config option mds_session_blacklist_on_evict needs to be true)
+  C_SaferCond cond;
+  if (!objecter->wait_for_map(reclaim_osd_epoch, &cond)) {
+    ldout(cct, 10) << __func__ << ": waiting for OSD epoch " << reclaim_osd_epoch << dendl;
+    client_lock.Unlock();
+    cond.wait();
+    client_lock.Lock();
+  }
+
+  bool blacklisted = objecter->with_osdmap(
+      [this](const OSDMap &osd_map) -> bool {
+       return osd_map.is_blacklisted(reclaim_target_addrs);
+      });
+  if (blacklisted)
+    return -ENOTRECOVERABLE;
+
+  metadata["reclaiming_uuid"] = uuid;
+  return 0;
+}
+
+void Client::finish_reclaim()
+{
+  auto it = metadata.find("reclaiming_uuid");
+  if (it == metadata.end()) {
+    for (auto &it : mds_sessions)
+      it.second.reclaim_state = MetaSession::RECLAIM_NULL;
+    return;
+  }
+
+  for (auto &it : mds_sessions) {
+    it.second.reclaim_state = MetaSession::RECLAIM_NULL;
+    auto m = MClientReclaim::create("", MClientReclaim::FLAG_FINISH);
+    it.second.con->send_message2(m);
+  }
+
+  metadata["uuid"] = it->second;
+  metadata.erase(it);
+}
+
+void Client::handle_client_reclaim_reply(MClientReclaimReply *reply)
+{
+  mds_rank_t from = mds_rank_t(reply->get_source().num());
+  ldout(cct, 10) << __func__ << " " << *reply << " from mds." << from << dendl;
+
+  MetaSession *session = _get_mds_session(from, reply->get_connection().get());
+  if (!session) {
+    ldout(cct, 10) << " discarding reclaim reply from sessionless mds." <<  from << dendl;
+    reply->put();
+    return;
+  }
+
+  if (reply->get_result() >= 0) {
+    session->reclaim_state = MetaSession::RECLAIM_OK;
+    if (reply->get_epoch() > reclaim_osd_epoch)
+      reclaim_osd_epoch = reply->get_epoch();
+    if (!reply->get_addrs().empty())
+      reclaim_target_addrs = reply->get_addrs();
+  } else {
+    session->reclaim_state = MetaSession::RECLAIM_FAIL;
+    reclaim_errno = reply->get_result();
+  }
+
+  signal_cond_list(waiting_for_reclaim);
+  reply->put();
+}
+
 /**
  * This is included in cap release messages, to cause
  * the MDS to wait until this OSD map epoch.  It is necessary
index 8aacf6d07eda4ff217cf1f68c103924aca2c9465..b8c4d7cc044ae0bd0eb613f9e253198bcae38649 100644 (file)
@@ -58,8 +58,9 @@ class MClientRequest;
 class MClientSession;
 class MClientRequest;
 class MClientRequestForward;
-struct MClientLease;
+class MClientLease;
 class MClientCaps;
+class MClientReclaimReply;
 
 struct DirStat;
 struct LeaseStat;
@@ -296,6 +297,11 @@ public:
   void unmount();
   void abort_conn();
 
+  void set_uuid(const std::string& uuid);
+  int start_reclaim(const std::string& uuid, unsigned flags,
+                   const std::string& fs_name);
+  void finish_reclaim();
+
   int mds_command(
     const std::string &mds_spec,
     const std::vector<std::string>& cmd,
@@ -862,7 +868,10 @@ protected:
   void put_inode(Inode *in, int n=1);
   void close_dir(Dir *dir);
 
+  int subscribe_mdsmap(const std::string &fs_name="");
+
   void _abort_mds_sessions(int err);
+
   // same as unmount() but for when the client_lock is already held
   void _unmount(bool abort);
 
@@ -928,6 +937,8 @@ protected:
 
   int check_pool_perm(Inode *in, int need);
 
+  void handle_client_reclaim_reply(MClientReclaimReply *reply);
+
   /**
    * Call this when an OSDMap is seen with a full flag (global or per pool)
    * set.
@@ -1276,6 +1287,12 @@ private:
   list<Cond*> waiting_for_pool_perm;
 
   uint64_t retries_on_invalidate = 0;
+
+  // state reclaim
+  list<Cond*> waiting_for_reclaim;
+  int reclaim_errno = 0;
+  epoch_t reclaim_osd_epoch = 0;
+  entity_addrvec_t reclaim_target_addrs;
 };
 
 /**
index b00abad27e6115e15432927820174cdb6861f4e2..af2d7acd76415dfa9dec2f093b0bc0dafdef1485 100644 (file)
@@ -35,6 +35,13 @@ struct MetaSession {
     STATE_STALE,
   } state;
 
+  enum {
+    RECLAIM_NULL,
+    RECLAIMING,
+    RECLAIM_OK,
+    RECLAIM_FAIL,
+  } reclaim_state;
+
   int mds_state;
   bool readonly;
 
@@ -53,7 +60,8 @@ struct MetaSession {
              const entity_addrvec_t& addrs)
     : mds_num(mds_num), con(con),
       seq(0), cap_gen(0), cap_renew_seq(0), addrs(addrs),
-      state(STATE_OPENING), mds_state(MDSMap::STATE_NULL), readonly(false)
+      state(STATE_OPENING), reclaim_state(RECLAIM_NULL),
+      mds_state(MDSMap::STATE_NULL), readonly(false)
   {}
 
   const char *get_state_name() const;
index 3709d597764aa18f4f34f89fff43755ce85eaa7c..3e453a2663a53e6752553c0042dfcdd8d78669e9 100644 (file)
@@ -294,7 +294,7 @@ const char *ceph_session_op_name(int op)
        case CEPH_SESSION_FLUSHMSG_ACK: return "flushmsg_ack";
        case CEPH_SESSION_FORCE_RO: return "force_ro";
        case CEPH_SESSION_REJECT: return "reject";
-       case CEPH_SESSION_REQUEST_FLUSH_MDLOG: return "request_flush_mdlog";
+       case CEPH_SESSION_REQUEST_FLUSH_MDLOG: return "request_flushmdlog";
        }
        return "???";
 }
index 68305939cdb977d0cfeaf66af55fa44178b73de4..b4f4cbea6e78bfc8bd4cbf700eec332b5756efaa 100644 (file)
@@ -111,6 +111,8 @@ struct ceph_dir_layout {
 #define CEPH_MSG_CLIENT_REQUEST         24
 #define CEPH_MSG_CLIENT_REQUEST_FORWARD 25
 #define CEPH_MSG_CLIENT_REPLY           26
+#define CEPH_MSG_CLIENT_RECLAIM                27
+#define CEPH_MSG_CLIENT_RECLAIM_REPLY   28
 #define CEPH_MSG_CLIENT_CAPS            0x310
 #define CEPH_MSG_CLIENT_LEASE           0x311
 #define CEPH_MSG_CLIENT_SNAP            0x312
@@ -310,6 +312,9 @@ enum {
         CEPH_SESSION_REQUEST_FLUSH_MDLOG
 };
 
+// flags for state reclaim
+#define CEPH_RECLAIM_RESET     1
+
 extern const char *ceph_session_op_name(int op);
 
 struct ceph_mds_session_head {
index be367e45b8b0026f82f3f37003df0201f2356a89..4573fa5ce84437859e5a50876dbd722d669e1af5 100644 (file)
@@ -1772,6 +1772,37 @@ int ceph_ll_delegation(struct ceph_mount_info *cmount, Fh *fh,
 
 mode_t ceph_umask(struct ceph_mount_info *cmount, mode_t mode);
 
+/* state reclaim */
+#define CEPH_RECLAIM_RESET     1
+
+/**
+ * Set ceph client uuid
+ * @param cmount the ceph mount handle to use.
+ * @param uuid the uuid to set
+ *
+ * Must be called before mount.
+ */
+void ceph_set_uuid(struct ceph_mount_info *cmount, const char *uuid);
+
+/**
+ * Start to reclaim states of other client
+ * @param cmount the ceph mount handle to use.
+ * @param uuid uuid of client whose states need to be reclaimed
+ * @param flags flags that control how states get reclaimed
+ *
+ * Returns 0 success, -EOPNOTSUPP if mds does not support the operation,
+ * -ENOENT if CEPH_RECLAIM_RESET is specified and there is no client
+ * with the given uuid, -ENOTRECOVERABLE in all other error cases.
+ */
+int ceph_start_reclaim(struct ceph_mount_info *cmount,
+                      const char *uuid, unsigned flags);
+
+/**
+ * finish reclaiming states of other client (
+ * @param cmount the ceph mount handle to use.
+ */
+void ceph_finish_reclaim(struct ceph_mount_info *cmount);
+
 #ifdef __cplusplus
 }
 #endif
index eff9cc70a7374b3218deed732d3b47122bd7f489..9d27e23984a04ec04e078489168fde0724660124 100644 (file)
@@ -137,6 +137,11 @@ public:
     return 0;
   }
 
+  const std::string& get_filesystem(void)
+  {
+    return fs_name;
+  }
+
   int mount(const std::string &mount_root, const UserPerm& perms)
   {
     int ret;
@@ -1912,3 +1917,25 @@ extern "C" int ceph_set_deleg_timeout(class ceph_mount_info *cmount, uint32_t ti
     return -ENOTCONN;
   return cmount->get_client()->set_deleg_timeout(timeout);
 }
+
+extern "C" void ceph_set_uuid(class ceph_mount_info *cmount, const char *uuid)
+{
+  cmount->get_client()->set_uuid(std::string(uuid));
+}
+
+extern "C" int ceph_start_reclaim(class ceph_mount_info *cmount,
+                                 const char *uuid, unsigned flags)
+{
+  if (!cmount->is_initialized()) {
+    int ret = cmount->init();
+    if (ret != 0)
+      return ret;
+  }
+  return cmount->get_client()->start_reclaim(std::string(uuid), flags,
+                                            cmount->get_filesystem());
+}
+
+extern "C" void ceph_finish_reclaim(class ceph_mount_info *cmount)
+{
+  cmount->get_client()->finish_reclaim();
+}
index a365ed8223a874bba6b36375a3b4d3b82fe83a35..58ed76055b307019249889f523fd7a86e8427ce1 100644 (file)
@@ -754,6 +754,7 @@ bool MDSRank::handle_deferrable_message(const Message::const_ref &m)
       // SERVER
     case CEPH_MSG_CLIENT_SESSION:
     case CEPH_MSG_CLIENT_RECONNECT:
+    case CEPH_MSG_CLIENT_RECLAIM:
       ALLOW_MESSAGES_FROM(CEPH_ENTITY_TYPE_CLIENT);
       // fall-thru
     case CEPH_MSG_CLIENT_REQUEST:
index 3d8f3c9a2bce7e32b634ad83e6968c83898e4e09..8ba4d7fa6f97905b88d8e8c65881d476c12088f3 100644 (file)
@@ -40,6 +40,7 @@
 #include "events/EOpen.h"
 #include "events/ECommitted.h"
 
+#include "include/stringify.h"
 #include "include/filepath.h"
 #include "common/errno.h"
 #include "common/Timer.h"
@@ -259,6 +260,9 @@ void Server::dispatch(const Message::const_ref &m)
   case CEPH_MSG_CLIENT_REQUEST:
     handle_client_request(MClientRequest::msgref_cast(m));
     return;
+  case CEPH_MSG_CLIENT_RECLAIM:
+    handle_client_reclaim(MClientReclaim::msgref_cast(m));
+    return;
   case MSG_MDS_SLAVE_REQUEST:
     handle_slave_request(MMDSSlaveRequest::msgref_cast(m));
     return;
@@ -295,6 +299,132 @@ public:
   }
 };
 
+Session* Server::find_session_by_uuid(std::string_view uuid)
+{
+  Session* session = nullptr;
+  for (auto& it : mds->sessionmap.get_sessions()) {
+    auto& metadata = it.second->info.client_metadata;
+
+    auto p = metadata.find("uuid");
+    if (p == metadata.end() || p->second != uuid)
+      continue;
+
+    if (!session) {
+      session = it.second;
+    } else if (!session->reclaiming_from) {
+      assert(it.second->reclaiming_from == session);
+      session = it.second;
+    } else {
+      assert(session->reclaiming_from == it.second);
+    }
+  }
+  return session;
+}
+
+void Server::reclaim_session(Session *session, const MClientReclaim::const_ref &m)
+{
+  if (!session->is_open() && !session->is_stale()) {
+    dout(10) << "session not open, dropping this req" << dendl;
+    return;
+  }
+
+  auto reply = MClientReclaimReply::create(0);
+  if (m->get_uuid().empty()) {
+    dout(10) << __func__ << " invalid message (no uuid)" << dendl;
+    reply->set_result(-EINVAL);
+    mds->send_message_client(reply, session);
+    return;
+  }
+
+  unsigned flags = m->get_flags();
+  if (flags != CEPH_RECLAIM_RESET) { // currently only support reset
+    dout(10) << __func__ << " unsupported flags" << dendl;
+    reply->set_result(-EOPNOTSUPP);
+    mds->send_message_client(reply, session);
+    return;
+  }
+
+  Session* target = find_session_by_uuid(m->get_uuid());
+  if (target) {
+    assert(!target->reclaiming_from);
+    assert(!session->reclaiming_from);
+    session->reclaiming_from = target;
+    reply->set_addrs(entity_addrvec_t(target->info.inst.addr));
+  }
+
+  if (flags & CEPH_RECLAIM_RESET) {
+    finish_reclaim_session(session, reply);
+    return;
+  }
+
+  ceph_abort();
+}
+
+void Server::finish_reclaim_session(Session *session, const MClientReclaimReply::ref &reply)
+{
+  Session *target = session->reclaiming_from;
+  if (target) {
+    session->reclaiming_from = nullptr;
+
+    Context *send_reply;
+    if (reply) {
+      int64_t session_id = session->get_client().v;
+      send_reply = new FunctionContext([this, session_id, reply](int r) {
+           assert(mds->mds_lock.is_locked_by_me());
+           Session *session = mds->sessionmap.get_session(entity_name_t::CLIENT(session_id));
+           if (!session) {
+             reply->put();
+             return;
+           }
+           auto epoch = mds->objecter->with_osdmap([](const OSDMap &map){ return map.get_epoch(); });
+           reply->set_epoch(epoch);
+           mds->send_message_client(reply, session);
+         });
+    } else {
+      send_reply = nullptr;
+    }
+
+    bool blacklisted = mds->objecter->with_osdmap([target](const OSDMap &map) {
+         return map.is_blacklisted(target->info.inst.addr);
+       });
+
+    if (blacklisted || !g_conf()->mds_session_blacklist_on_evict) {
+      kill_session(target, send_reply);
+    } else {
+      std::stringstream ss;
+      mds->evict_client(target->get_client().v, false, true, ss, send_reply);
+    }
+  } else if (reply) {
+    mds->send_message_client(reply, session);
+  }
+}
+
+void Server::handle_client_reclaim(const MClientReclaim::const_ref &m)
+{
+  Session *session = mds->get_session(m);
+  dout(3) << __func__ <<  " " << *m << " from " << m->get_source() << dendl;
+  assert(m->get_source().is_client()); // should _not_ come from an mds!
+
+  if (!session) {
+    dout(0) << " ignoring sessionless msg " << *m << dendl;
+    m->put();
+    return;
+  }
+
+  if (mds->get_state() < MDSMap::STATE_CLIENTREPLAY) {
+    mds->wait_for_replay(new C_MDS_RetryMessage(mds, m));
+    return;
+  }
+
+  if (m->get_flags() & MClientReclaim::FLAG_FINISH) {
+    finish_reclaim_session(session);
+  } else {
+    reclaim_session(session, m);
+  }
+  m->put();
+}
+
+/* This function DOES put the passed message before returning*/
 void Server::handle_client_session(const MClientSession::const_ref &m)
 {
   version_t pv;
@@ -415,6 +545,17 @@ void Server::handle_client_session(const MClientSession::const_ref &m)
        }
       }
 
+      it = client_metadata.find("uuid");
+      if (it != client_metadata.end()) {
+       if (find_session_by_uuid(it->second)) {
+         send_reject_message("duplicated session uuid");
+         mds->clog->warn() << "client session with duplicated session uuid '"
+                           << it->second << "' denied (" << session->info.inst << ")";
+         session->clear();
+         break;
+       }
+      }
+
       session->set_client_metadata(client_metadata);
 
       if (session->is_closed())
@@ -871,12 +1012,15 @@ void Server::kill_session(Session *session, Context *on_safe)
     journal_close_session(session, Session::STATE_KILLING, on_safe);
   } else {
     dout(10) << "kill_session importing or already closing/killing " << session << dendl;
-    ceph_assert(session->is_closing() || 
-          session->is_closed() || 
-          session->is_killing() ||
-          session->is_importing());
-    if (on_safe) {
-      on_safe->complete(0);
+    if (session->is_closing() ||
+       session->is_killing()) {
+      if (on_safe)
+       mdlog->wait_for_safe(new MDSInternalContextWrapper(mds, on_safe));
+    } else {
+      ceph_assert(session->is_closed() ||
+                 session->is_importing());
+      if (on_safe)
+       on_safe->complete(0);
     }
   }
 }
index c53f7271d185f46b45ea087015235b53e1846fd8..40b1077d2004bd9f41ad843062caa244f29234f4 100644 (file)
@@ -22,6 +22,8 @@
 #include "messages/MClientRequest.h"
 #include "messages/MClientSession.h"
 #include "messages/MClientSnap.h"
+#include "messages/MClientReclaim.h"
+#include "messages/MClientReclaimReply.h"
 #include "messages/MLock.h"
 
 #include "MDSRank.h"
@@ -33,8 +35,8 @@ class PerfCounters;
 class LogEvent;
 class EMetaBlob;
 class EUpdate;
-struct SnapInfo;
 class MDLog;
+struct SnapInfo;
 
 enum {
   l_mdss_first = 1000,
@@ -142,6 +144,12 @@ public:
   void kill_session(Session *session, Context *on_safe);
   size_t apply_blacklist(const std::set<entity_addr_t> &blacklist);
   void journal_close_session(Session *session, int state, Context *on_safe);
+
+  Session *find_session_by_uuid(std::string_view uuid);
+  void reclaim_session(Session *session, const MClientReclaim::const_ref &m);
+  void finish_reclaim_session(Session *session, const MClientReclaimReply::ref &reply=nullptr);
+  void handle_client_reclaim(const MClientReclaim::const_ref &m);
+
   void reconnect_clients(MDSInternalContext *reconnect_done_);
   void handle_client_reconnect(const MClientReconnect::const_ref &m);
   void infer_supported_features(Session *session, client_metadata_t& client_metadata);
index 1c1d9f818a122b9a222bded40f1f2d2d33b680bf..8e9bebea4421eec5637736677db3f4ff21f45dc4 100644 (file)
@@ -120,6 +120,7 @@ private:
   time birth_time;
 
 public:
+  Session *reclaiming_from = nullptr;
 
   void push_pv(version_t pv)
   {
index 4788d4ba5714d9b27bb802ac5c099a93567290e9..8ad16cc2f8c7710c824b1eaf7968cc4311897a68 100644 (file)
@@ -24,6 +24,7 @@
 #define CEPHFS_FEATURE_LUMINOUS                7
 #define CEPHFS_FEATURE_MIMIC           8
 #define CEPHFS_FEATURE_REPLY_ENCODING   9
+#define CEPHFS_FEATURE_RECLAIM_CLIENT  10
 
 #define CEPHFS_FEATURES_ALL {          \
   0, 1, 2, 3, 4,                       \
@@ -32,6 +33,7 @@
   CEPHFS_FEATURE_LUMINOUS,             \
   CEPHFS_FEATURE_MIMIC,                        \
   CEPHFS_FEATURE_REPLY_ENCODING,        \
+  CEPHFS_FEATURE_RECLAIM_CLIENT,       \
 }
 
 #define CEPHFS_FEATURES_MDS_SUPPORTED CEPHFS_FEATURES_ALL
diff --git a/src/messages/MClientReclaim.h b/src/messages/MClientReclaim.h
new file mode 100644 (file)
index 0000000..75206f9
--- /dev/null
@@ -0,0 +1,64 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software 
+ * Foundation.  See file COPYING.
+ * 
+ */
+
+
+#ifndef CEPH_MCLIENTRECLAIM_H
+#define CEPH_MCLIENTRECLAIM_H
+
+#include "msg/Message.h"
+
+class MClientReclaim: public MessageInstance<MClientReclaim> {
+public:
+  static constexpr int HEAD_VERSION = 1;
+  static constexpr int COMPAT_VERSION = 1;
+  static constexpr uint32_t FLAG_FINISH = 1U << 31;
+
+  uint32_t get_flags() const { return flags; }
+  std::string_view get_uuid() const { return uuid; }
+
+  const char *get_type_name() const override { return "client_reclaim"; }
+  void print(ostream& o) const override {
+    std::ios_base::fmtflags f(o.flags());
+    o << "client_reclaim(" << get_uuid() << " flags 0x" << std::hex << get_flags() << ")";
+    o.flags(f);
+  }
+
+  void encode_payload(uint64_t features) override {
+    using ceph::encode;
+    encode(uuid, payload);
+    encode(flags, payload);
+  }
+
+  void decode_payload() override {
+    using ceph::decode;
+    auto p = payload.cbegin();
+    decode(uuid, p);
+    decode(flags, p);
+  }
+
+protected:
+  friend factory;
+  MClientReclaim() :
+    MessageInstance(CEPH_MSG_CLIENT_RECLAIM, HEAD_VERSION, COMPAT_VERSION) {}
+  MClientReclaim(std::string_view _uuid, uint32_t _flags) :
+    MessageInstance(CEPH_MSG_CLIENT_RECLAIM, HEAD_VERSION, COMPAT_VERSION),
+    uuid(_uuid), flags(_flags) {}
+private:
+  ~MClientReclaim() override {}
+
+  std::string uuid;
+  uint32_t flags = 0;
+};
+
+#endif
diff --git a/src/messages/MClientReclaimReply.h b/src/messages/MClientReclaimReply.h
new file mode 100644 (file)
index 0000000..7f88c3d
--- /dev/null
@@ -0,0 +1,69 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software 
+ * Foundation.  See file COPYING.
+ * 
+ */
+
+
+#ifndef CEPH_MCLIENTRECLAIMREPLY_H
+#define CEPH_MCLIENTRECLAIMREPLY_H
+
+#include "msg/Message.h"
+
+class MClientReclaimReply: public MessageInstance<MClientReclaimReply> {
+public:
+  static constexpr int HEAD_VERSION = 1;
+  static constexpr int COMPAT_VERSION = 1;
+
+  int32_t get_result() const { return result; }
+  void set_result(int r) { result = r; }
+  epoch_t get_epoch() const { return epoch; }
+  void set_epoch(epoch_t e) { epoch = e; }
+  const entity_addrvec_t& get_addrs() const { return addrs; }
+  void set_addrs(const entity_addrvec_t& _addrs)  { addrs = _addrs; }
+
+  const char *get_type_name() const override { return "client_reclaim_reply"; }
+  void print(ostream& o) const override {
+    o << "client_reclaim_reply(" << result << " e " << epoch << ")";
+  }
+
+  void encode_payload(uint64_t features) override {
+    using ceph::encode;
+    encode(result, payload);
+    encode(epoch, payload);
+    encode(addrs, payload, features);
+  }
+
+  void decode_payload() override {
+    using ceph::decode;
+    auto p = payload.cbegin();
+    decode(result, p);
+    decode(epoch, p);
+    decode(addrs, p);
+  }
+
+protected:
+  friend factory;
+  MClientReclaimReply() :
+    MessageInstance(CEPH_MSG_CLIENT_RECLAIM_REPLY, HEAD_VERSION, COMPAT_VERSION) {}
+  MClientReclaimReply(int r, epoch_t e=0) :
+    MessageInstance(CEPH_MSG_CLIENT_RECLAIM_REPLY, HEAD_VERSION, COMPAT_VERSION),
+    result(r), epoch(e) {}
+
+private:
+  ~MClientReclaimReply() override {}
+
+  int32_t result;
+  epoch_t epoch;
+  entity_addrvec_t addrs;
+};
+
+#endif
index 92defd17d437e4a3a7e89e380b7e99b45b5d8f78..693ecc94cd26105d3e9cba1e7c753d418b8554b5 100644 (file)
 #include "messages/MClientRequest.h"
 #include "messages/MClientRequestForward.h"
 #include "messages/MClientReply.h"
+#include "messages/MClientReclaim.h"
+#include "messages/MClientReclaimReply.h"
 #include "messages/MClientCaps.h"
 #include "messages/MClientCapRelease.h"
 #include "messages/MClientLease.h"
@@ -617,6 +619,12 @@ Message *decode_message(CephContext *cct, int crcflags,
   case CEPH_MSG_CLIENT_REPLY:
     m = MClientReply::create();
     break;
+  case CEPH_MSG_CLIENT_RECLAIM:
+    m = MClientReclaim::create();
+    break;
+  case CEPH_MSG_CLIENT_RECLAIM_REPLY:
+    m = MClientReclaimReply::create();
+    break;
   case CEPH_MSG_CLIENT_CAPS:
     m = MClientCaps::create();
     break;