]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
client: add mount/initialize states support and convert to RWRef
authorXiubo Li <xiubli@redhat.com>
Sun, 2 Aug 2020 00:35:24 +0000 (08:35 +0800)
committerXiubo Li <xiubli@redhat.com>
Thu, 6 Aug 2020 08:23:29 +0000 (16:23 +0800)
This will help us to break the big client_lock. Such as if we want
to add one separate lock for each inode, it will work like:

inode_lock.lock();
...
client_lock.lock();

client_lock.unlock();
...
inode_lock.unlock();

So we must get rid of the client_lock for all the "readers", which
must hold the client_lock from the beginning until the end.

Fixes: https://tracker.ceph.com/issues/46649
Signed-off-by: Xiubo Li <xiubli@redhat.com>
src/client/Client.cc
src/client/Client.h

index 8a2db48552600c1875e8554e1d0c828dc7c5d5df..a4e1ee59838f60741d7c0af4dca96e1ca8cce719 100755 (executable)
@@ -273,6 +273,8 @@ Client::Client(Messenger *m, MonClient *mc, Objecter *objecter_)
     monclient(mc),
     objecter(objecter_),
     whoami(mc->get_global_id()),
+    mount_state(CLIENT_UNMOUNTED, "Client::mountstate_lock"),
+    initialize_state(CLIENT_NEW, "Client::initstate_lock"),
     async_ino_invalidator(m->cct),
     async_dentry_invalidator(m->cct),
     interrupt_finisher(m->cct),
@@ -491,13 +493,16 @@ void Client::_pre_init()
 
 int Client::init()
 {
+  RWRef_t iref_writer(initialize_state, CLIENT_INITIALIZING, false);
+  ceph_assert(iref_writer.is_first_writer());
+
   _pre_init();
   {
     std::lock_guard l{client_lock};
-    ceph_assert(!initialized);
     messenger->add_dispatcher_tail(this);
   }
   _finish_init();
+  iref_writer.update_state(CLIENT_INITIALIZED);
   return 0;
 }
 
@@ -554,9 +559,6 @@ void Client::_finish_init()
     lderr(cct) << "error registering admin socket command: "
               << cpp_strerror(-ret) << dendl;
   }
-
-  std::lock_guard l{client_lock};
-  initialized = true;
 }
 
 void Client::shutdown() 
@@ -604,16 +606,24 @@ void Client::shutdown()
   }
 
   objectcacher->stop();  // outside of client_lock! this does a join.
-  {
-    std::lock_guard l{client_lock};
-    ceph_assert(initialized);
-    initialized = false;
-  }
+
+  /*
+   * We are shuting down the client.
+   *
+   * Just declare the state to CLIENT_NEW to block and fail any
+   * new comming "reader" and then try to wait all the in-flight
+   * "readers" to finish.
+   */
+  RWRef_t iref_writer(initialize_state, CLIENT_NEW, false);
+  if (!iref_writer.is_first_writer())
+    return;
+  iref_writer.wait_readers_done();
 
   {
     std::scoped_lock l(timer_lock);
     timer.shutdown();
   }
+
   objecter_finisher.wait_for_empty();
   objecter_finisher.stop();
 
@@ -635,13 +645,13 @@ void Client::trim_cache(bool trim_kernel_dcache)
   while (lru.lru_get_size() != last) {
     last = lru.lru_get_size();
 
-    if (!unmounting && lru.lru_get_size() <= max)  break;
+    if (!is_unmounting() && lru.lru_get_size() <= max)  break;
 
     // trim!
     Dentry *dn = static_cast<Dentry*>(lru.lru_get_next_expire());
     if (!dn)
       break;  // done
-    
+
     trim_dentry(dn);
   }
 
@@ -840,7 +850,7 @@ Inode * Client::add_update_inode(InodeStat *st, utime_t from,
         _assign_faked_root(root);
       root_ancestor = in;
       cwd = root;
-    } else if (!mounted) {
+    } else if (is_mounting()) {
       root_parents[root_ancestor] = in;
       root_ancestor = in;
     }
@@ -2038,8 +2048,10 @@ void Client::populate_metadata(const std::string &mount_root)
  */
 void Client::update_metadata(std::string const &k, std::string const &v)
 {
+  RWRef_t iref_reader(initialize_state, CLIENT_INITIALIZED);
+  ceph_assert(iref_reader.is_state_satisfied());
+
   std::lock_guard l(client_lock);
-  ceph_assert(initialized);
 
   auto it = metadata.find(k);
   if (it != metadata.end()) {
@@ -2119,7 +2131,7 @@ void Client::handle_client_session(const MConstRef<MClientSession>& m)
 
       renew_caps(session);
       session->state = MetaSession::STATE_OPEN;
-      if (unmounting)
+      if (is_unmounting())
        mount_cond.notify_all();
       else
        connect_mds_targets(from);
@@ -2448,7 +2460,7 @@ void Client::handle_client_reply(const MConstRef<MClientReply>& reply)
     request->item.remove_myself();
     unregister_request(request);
   }
-  if (unmounting)
+  if (is_unmounting())
     mount_cond.notify_all();
 }
 
@@ -2584,11 +2596,15 @@ void Client::handle_osd_map(const MConstRef<MOSDMap>& m)
 
 bool Client::ms_dispatch2(const MessageRef &m)
 {
-  std::lock_guard l(client_lock);
-  if (!initialized) {
+  RWRef_t iref_reader(initialize_state, CLIENT_INITIALIZED);
+  if (!iref_reader.is_state_satisfied()) {
     ldout(cct, 10) << "inactive, discarding " << *m << dendl;
     return true;
   }
+//  if (!is_initialized())
+//    return true;
+
+  std::lock_guard l(client_lock);
 
   switch (m->get_type()) {
     // mounting and mds sessions
@@ -2647,7 +2663,7 @@ bool Client::ms_dispatch2(const MessageRef &m)
   }
 
   // unmounting?
-  if (unmounting) {
+  if (is_unmounting()) {
     ldout(cct, 10) << "unmounting: trim pass, size was " << lru.lru_get_size() 
              << "+" << inode_map.size() << dendl;
     long unsigned size = lru.lru_get_size() + inode_map.size();
@@ -3546,7 +3562,7 @@ void Client::check_caps(Inode *in, unsigned flags)
   used = adjust_caps_used_for_lazyio(used, issued, implemented);
 
   int retain = wanted | used | CEPH_CAP_PIN;
-  if (!unmounting && in->nlink > 0) {
+  if (!is_unmounting() && in->nlink > 0) {
     if (wanted) {
       retain |= CEPH_CAP_ANY;
     } else if (in->is_dir() &&
@@ -3629,7 +3645,7 @@ void Client::check_caps(Inode *in, unsigned flags)
     if (wanted & ~(cap.wanted | cap.issued))
       goto ack;
 
-    if (!revoking && unmounting && (cap_used == 0))
+    if (!revoking && is_unmounting() && (cap_used == 0))
       goto ack;
 
     if ((cap.issued & ~retain) == 0 && // and we don't have anything we wouldn't like
@@ -3911,8 +3927,10 @@ public:
 
 void Client::_async_invalidate(vinodeno_t ino, int64_t off, int64_t len)
 {
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return;
+
   ldout(cct, 10) << __func__ << " " << ino << " " << off << "~" << len << dendl;
   ino_invalidate_cb(callback_handle, ino, off, len);
 }
@@ -4252,7 +4270,7 @@ int Client::_do_remount(bool retry_on_error)
       (cct->_conf.get_val<bool>("client_die_on_failed_remount") ||
        cct->_conf.get_val<bool>("client_die_on_failed_dentry_invalidate")) &&
       !(retry_on_error && (++retries_on_invalidate < max_retries));
-    if (should_abort && !unmounting) {
+    if (should_abort && !is_unmounting()) {
       lderr(cct) << "failed to remount for kernel dentry trimming; quitting!" << dendl;
       ceph_abort();
     }
@@ -4273,8 +4291,10 @@ public:
 
 void Client::_invalidate_kernel_dcache()
 {
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return;
+
   if (can_invalidate_dentries) {
     if (dentry_invalidate_cb && root->dir) {
       for (ceph::unordered_map<string, Dentry*>::iterator p = root->dir->dentries.begin();
@@ -4336,8 +4356,10 @@ public:
 
 void Client::_async_inode_release(vinodeno_t ino)
 {
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return;
+
   ldout(cct, 10) << __func__ << " " << ino << dendl;
   ino_release_cb(callback_handle, ino);
 }
@@ -5218,8 +5240,10 @@ public:
 
 void Client::_async_dentry_invalidate(vinodeno_t dirino, vinodeno_t ino, string& name)
 {
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return;
+
   ldout(cct, 10) << __func__ << " '" << name << "' ino " << ino
                 << " in dir " << dirino << dendl;
   dentry_invalidate_cb(callback_handle, dirino, ino, name.c_str(), name.length());
@@ -5818,11 +5842,12 @@ int Client::mds_command(
     string *outs,
     Context *onfinish)
 {
-  std::lock_guard lock(client_lock);
-
-  if (!initialized)
+  RWRef_t iref_reader(initialize_state, CLIENT_INITIALIZED);
+  if (!iref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   int r;
   r = authenticate();
   if (r < 0) {
@@ -5964,14 +5989,17 @@ int Client::subscribe_mdsmap(const std::string &fs_name)
 int Client::mount(const std::string &mount_root, const UserPerm& perms,
                  bool require_mds, const std::string &fs_name)
 {
-  std::unique_lock lock(client_lock);
+  ceph_assert(is_initialized());
 
-  if (mounted) {
-    ldout(cct, 5) << "already mounted" << dendl;
+  /*
+   * To make sure that the _unmount() must wait until the mount()
+   * is done.
+   */
+  RWRef_t mref_writer(mount_state, CLIENT_MOUNTING, false);
+  if (!mref_writer.is_first_writer()) // already mounting or mounted
     return 0;
-  }
 
-  unmounting = false;
+  std::unique_lock cl(client_lock);
 
   int r = subscribe_mdsmap(fs_name);
   if (r < 0) {
@@ -5979,10 +6007,10 @@ int Client::mount(const std::string &mount_root, const UserPerm& perms,
     return r;
   }
 
-  lock.unlock();
+  cl.unlock();
   tick(); // start tick
-  lock.lock();
-  
+  cl.lock();
+
   if (require_mds) {
     while (1) {
       auto availability = mdsmap->is_cluster_available();
@@ -6032,8 +6060,6 @@ int Client::mount(const std::string &mount_root, const UserPerm& perms,
   ceph_assert(root);
   _ll_get(root);
 
-  mounted = true;
-
   // trace?
   if (!cct->_conf->client_trace.empty()) {
     traceout.open(cct->_conf->client_trace.c_str());
@@ -6054,6 +6080,8 @@ int Client::mount(const std::string &mount_root, const UserPerm& perms,
   ldout(cct, 3) << "op: map<int, int> open_files;" << dendl;
   ldout(cct, 3) << "op: int fd;" << dendl;
   */
+
+  mref_writer.update_state(CLIENT_MOUNTED);
   return 0;
 }
 
@@ -6149,16 +6177,25 @@ void Client::_abort_mds_sessions(int err)
 
 void Client::_unmount(bool abort)
 {
-  std::unique_lock lock{client_lock};
-  if (unmounting)
+  /*
+   * We are unmounting the client.
+   *
+   * Just declare the state to STATE_UNMOUNTING to block and fail
+   * any new comming "reader" and then try to wait all the in-flight
+   * "readers" to finish.
+   */
+  RWRef_t mref_writer(mount_state, CLIENT_UNMOUNTING, false);
+  if (!mref_writer.is_first_writer())
     return;
+  mref_writer.wait_readers_done();
+
+  std::unique_lock lock{client_lock};
 
   if (abort || blacklisted) {
     ldout(cct, 2) << "unmounting (" << (abort ? "abort)" : "blacklisted)") << dendl;
   } else {
     ldout(cct, 2) << "unmounting" << dendl;
   }
-  unmounting = true;
 
   deleg_timeout = 0;
 
@@ -6283,7 +6320,7 @@ void Client::_unmount(bool abort)
 
   _close_sessions();
 
-  mounted = false;
+  mref_writer.update_state(CLIENT_UNMOUNTED);
 
   ldout(cct, 2) << "unmounted." << dendl;
 }
@@ -6336,19 +6373,21 @@ void Client::tick()
 
   utime_t now = ceph_clock_now();
 
-  std::lock_guard lock(client_lock);
-
-  if (!mounted && !mds_requests.empty()) {
+  std::scoped_lock cl(client_lock);
+  /*
+   * If the mount() is not finished
+   */
+  if (is_mounting() && !mds_requests.empty()) {
     MetaRequest *req = mds_requests.begin()->second;
     if (req->op_stamp + cct->_conf->client_mount_timeout < now) {
       req->abort(-ETIMEDOUT);
       if (req->caller_cond) {
-       req->kick = true;
-       req->caller_cond->notify_all();
+        req->kick = true;
+        req->caller_cond->notify_all();
       }
       signal_cond_list(waiting_for_mdsmap);
       for (auto &p : mds_sessions) {
-       signal_context_list(p.second.waiting_for_open);
+        signal_context_list(p.second.waiting_for_open);
       }
     }
   }
@@ -6377,7 +6416,7 @@ void Client::tick()
 
   trim_cache(true);
 
-  if (blacklisted && mounted &&
+  if (blacklisted && (is_mounted() || is_unmounting()) &&
       last_auto_reconnect + 30 * 60 < now &&
       cct->_conf.get_val<bool>("client_reconnect_stale")) {
     messenger->client_reset();
@@ -6717,17 +6756,19 @@ int Client::path_walk(const filepath& origpath, InodeRef *end,
 
 int Client::link(const char *relexisting, const char *relpath, const UserPerm& perm)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << "link" << std::endl;
   tout(cct) << relexisting << std::endl;
   tout(cct) << relpath << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath existing(relexisting);
 
   InodeRef in, dir;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(existing, &in, perm, true);
   if (r < 0)
     return r;
@@ -6760,14 +6801,13 @@ int Client::link(const char *relexisting, const char *relpath, const UserPerm& p
 
 int Client::unlink(const char *relpath, const UserPerm& perm)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
 
-  std::scoped_lock lock(client_lock);
-
-  if (unmounting)
-    return -ENOTCONN;
-
   if (std::string(relpath) == "/")
     return -EISDIR;
 
@@ -6775,6 +6815,8 @@ int Client::unlink(const char *relpath, const UserPerm& perm)
   string name = path.last_dentry();
   path.pop_dentry();
   InodeRef dir;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &dir, perm);
   if (r < 0)
     return r;
@@ -6788,14 +6830,14 @@ int Client::unlink(const char *relpath, const UserPerm& perm)
 
 int Client::rename(const char *relfrom, const char *relto, const UserPerm& perm)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relfrom << std::endl;
   tout(cct) << relto << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   if (std::string(relfrom) == "/" || std::string(relto) == "/")
     return -EBUSY;
 
@@ -6807,6 +6849,8 @@ int Client::rename(const char *relfrom, const char *relto, const UserPerm& perm)
   to.pop_dentry();
 
   InodeRef fromdir, todir;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(from, &fromdir, perm);
   if (r < 0)
     goto out;
@@ -6831,15 +6875,15 @@ out:
 
 int Client::mkdir(const char *relpath, mode_t mode, const UserPerm& perm)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << mode << std::endl;
   ldout(cct, 10) << __func__ << ": " << relpath << dendl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   if (std::string(relpath) == "/")
     return -EEXIST;
 
@@ -6847,6 +6891,8 @@ int Client::mkdir(const char *relpath, mode_t mode, const UserPerm& perm)
   string name = path.last_dentry();
   path.pop_dentry();
   InodeRef dir;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &dir, perm);
   if (r < 0)
     return r;
@@ -6860,20 +6906,22 @@ int Client::mkdir(const char *relpath, mode_t mode, const UserPerm& perm)
 
 int Client::mkdirs(const char *relpath, mode_t mode, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 10) << "Client::mkdirs " << relpath << dendl;
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << mode << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   //get through existing parts of path
   filepath path(relpath);
   unsigned int i;
   int r = 0, caps = 0;
   InodeRef cur, next;
+
+  std::scoped_lock lock(client_lock);
   cur = cwd;
   for (i=0; i<path.depth(); ++i) {
     if (cct->_conf->client_permissions) {
@@ -6915,13 +6963,13 @@ int Client::mkdirs(const char *relpath, mode_t mode, const UserPerm& perms)
 
 int Client::rmdir(const char *relpath, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   if (std::string(relpath) == "/")
     return -EBUSY;
 
@@ -6929,6 +6977,8 @@ int Client::rmdir(const char *relpath, const UserPerm& perms)
   string name = path.last_dentry();
   path.pop_dentry();
   InodeRef dir;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &dir, perms);
   if (r < 0)
     return r;
@@ -6942,15 +6992,15 @@ int Client::rmdir(const char *relpath, const UserPerm& perms)
 
 int Client::mknod(const char *relpath, mode_t mode, const UserPerm& perms, dev_t rdev) 
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << mode << std::endl;
   tout(cct) << rdev << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   if (std::string(relpath) == "/")
     return -EEXIST;
 
@@ -6958,6 +7008,8 @@ int Client::mknod(const char *relpath, mode_t mode, const UserPerm& perms, dev_t
   string name = path.last_dentry();
   path.pop_dentry();
   InodeRef dir;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &dir, perms);
   if (r < 0)
     return r;
@@ -6973,14 +7025,14 @@ int Client::mknod(const char *relpath, mode_t mode, const UserPerm& perms, dev_t
   
 int Client::symlink(const char *target, const char *relpath, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << target << std::endl;
   tout(cct) << relpath << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   if (std::string(relpath) == "/")
     return -EEXIST;
 
@@ -6988,6 +7040,8 @@ int Client::symlink(const char *target, const char *relpath, const UserPerm& per
   string name = path.last_dentry();
   path.pop_dentry();
   InodeRef dir;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &dir, perms);
   if (r < 0)
     return r;
@@ -7001,15 +7055,17 @@ int Client::symlink(const char *target, const char *relpath, const UserPerm& per
 
 int Client::readlink(const char *relpath, char *buf, loff_t size, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms, false);
   if (r < 0)
     return r;
@@ -7307,16 +7363,18 @@ int Client::_setattr(InodeRef &in, struct stat *attr, int mask,
 int Client::setattr(const char *relpath, struct stat *attr, int mask,
                    const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << mask  << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms);
   if (r < 0)
     return r;
@@ -7326,16 +7384,18 @@ int Client::setattr(const char *relpath, struct stat *attr, int mask,
 int Client::setattrx(const char *relpath, struct ceph_statx *stx, int mask,
                     const UserPerm& perms, int flags)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << mask  << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW));
   if (r < 0)
     return r;
@@ -7344,14 +7404,15 @@ int Client::setattrx(const char *relpath, struct ceph_statx *stx, int mask,
 
 int Client::fsetattr(int fd, struct stat *attr, int mask, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << fd << std::endl;
   tout(cct) << mask  << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -7364,14 +7425,15 @@ int Client::fsetattr(int fd, struct stat *attr, int mask, const UserPerm& perms)
 
 int Client::fsetattrx(int fd, struct ceph_statx *stx, int mask, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << fd << std::endl;
   tout(cct) << mask  << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -7385,16 +7447,18 @@ int Client::fsetattrx(int fd, struct ceph_statx *stx, int mask, const UserPerm&
 int Client::stat(const char *relpath, struct stat *stbuf, const UserPerm& perms,
                 frag_info_t *dirstat, int mask)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << __func__ << " enter (relpath " << relpath << " mask " << mask << ")" << dendl;
   tout(cct) << "stat" << std::endl;
   tout(cct) << relpath << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms, true, mask);
   if (r < 0)
     return r;
@@ -7434,19 +7498,20 @@ int Client::statx(const char *relpath, struct ceph_statx *stx,
                  const UserPerm& perms,
                  unsigned int want, unsigned int flags)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << __func__ << " enter (relpath " << relpath << " want " << want << ")" << dendl;
   tout(cct) << "statx" << std::endl;
   tout(cct) << relpath << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
 
   unsigned mask = statx_to_mask(flags, want);
 
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), mask);
   if (r < 0)
     return r;
@@ -7465,16 +7530,18 @@ int Client::statx(const char *relpath, struct ceph_statx *stx,
 int Client::lstat(const char *relpath, struct stat *stbuf,
                  const UserPerm& perms, frag_info_t *dirstat, int mask)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << __func__ << " enter (relpath " << relpath << " mask " << mask << ")" << dendl;
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   // don't follow symlinks
   int r = path_walk(path, &in, perms, false, mask);
   if (r < 0)
@@ -7641,16 +7708,18 @@ void Client::touch_dn(Dentry *dn)
 
 int Client::chmod(const char *relpath, mode_t mode, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << mode << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms);
   if (r < 0)
     return r;
@@ -7661,14 +7730,15 @@ int Client::chmod(const char *relpath, mode_t mode, const UserPerm& perms)
 
 int Client::fchmod(int fd, mode_t mode, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << fd << std::endl;
   tout(cct) << mode << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -7683,16 +7753,18 @@ int Client::fchmod(int fd, mode_t mode, const UserPerm& perms)
 
 int Client::lchmod(const char *relpath, mode_t mode, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << mode << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   // don't follow symlinks
   int r = path_walk(path, &in, perms, false);
   if (r < 0)
@@ -7705,17 +7777,19 @@ int Client::lchmod(const char *relpath, mode_t mode, const UserPerm& perms)
 int Client::chown(const char *relpath, uid_t new_uid, gid_t new_gid,
                  const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << new_uid << std::endl;
   tout(cct) << new_gid << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms);
   if (r < 0)
     return r;
@@ -7727,15 +7801,16 @@ int Client::chown(const char *relpath, uid_t new_uid, gid_t new_gid,
 
 int Client::fchown(int fd, uid_t new_uid, gid_t new_gid, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << fd << std::endl;
   tout(cct) << new_uid << std::endl;
   tout(cct) << new_gid << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -7755,17 +7830,19 @@ int Client::fchown(int fd, uid_t new_uid, gid_t new_gid, const UserPerm& perms)
 int Client::lchown(const char *relpath, uid_t new_uid, gid_t new_gid,
                   const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << new_uid << std::endl;
   tout(cct) << new_gid << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   // don't follow symlinks
   int r = path_walk(path, &in, perms, false);
   if (r < 0)
@@ -7830,6 +7907,10 @@ int Client::futime(int fd, struct utimbuf *buf, const UserPerm& perms)
 int Client::utimes(const char *relpath, struct timeval times[2],
                    const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << "atime: " << times[0].tv_sec << "." << times[0].tv_usec
@@ -7837,12 +7918,10 @@ int Client::utimes(const char *relpath, struct timeval times[2],
   tout(cct) << "mtime: " << times[1].tv_sec << "." << times[1].tv_usec
             << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms);
   if (r < 0)
     return r;
@@ -7857,6 +7936,10 @@ int Client::utimes(const char *relpath, struct timeval times[2],
 int Client::lutimes(const char *relpath, struct timeval times[2],
                     const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << "atime: " << times[0].tv_sec << "." << times[0].tv_usec
@@ -7864,12 +7947,10 @@ int Client::lutimes(const char *relpath, struct timeval times[2],
   tout(cct) << "mtime: " << times[1].tv_sec << "." << times[1].tv_usec
             << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms, false);
   if (r < 0)
     return r;
@@ -7894,6 +7975,10 @@ int Client::futimes(int fd, struct timeval times[2], const UserPerm& perms)
 
 int Client::futimens(int fd, struct timespec times[2], const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << fd << std::endl;
   tout(cct) << "atime: " << times[0].tv_sec << "." << times[0].tv_nsec
@@ -7902,9 +7987,6 @@ int Client::futimens(int fd, struct timespec times[2], const UserPerm& perms)
             << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -7922,15 +8004,16 @@ int Client::futimens(int fd, struct timespec times[2], const UserPerm& perms)
 
 int Client::flock(int fd, int operation, uint64_t owner)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << fd << std::endl;
   tout(cct) << operation << std::endl;
   tout(cct) << owner << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -7940,15 +8023,17 @@ int Client::flock(int fd, int operation, uint64_t owner)
 
 int Client::opendir(const char *relpath, dir_result_t **dirpp, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << relpath << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms, true);
   if (r < 0)
     return r;
@@ -8001,12 +8086,13 @@ void Client::_closedir(dir_result_t *dirp)
 
 void Client::rewinddir(dir_result_t *dirp)
 {
-  std::lock_guard lock(client_lock);
   ldout(cct, 3) << __func__ << "(" << dirp << ")" << dendl;
 
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return;
 
+  std::lock_guard lock(client_lock);
   dir_result_t *d = static_cast<dir_result_t*>(dirp);
   _readdir_drop_dirp_buffer(d);
   d->reset();
@@ -8021,13 +8107,14 @@ loff_t Client::telldir(dir_result_t *dirp)
 
 void Client::seekdir(dir_result_t *dirp, loff_t offset)
 {
-  std::lock_guard lock(client_lock);
-
   ldout(cct, 3) << __func__ << "(" << dirp << ", " << offset << ")" << dendl;
 
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return;
 
+  std::lock_guard lock(client_lock);
+
   if (offset == dirp->offset)
     return;
 
@@ -8282,11 +8369,12 @@ int Client::readdir_r_cb(dir_result_t *d, add_dirent_cb_t cb, void *p,
 {
   int caps = statx_to_mask(flags, want);
 
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   dir_result_t *dirp = static_cast<dir_result_t*>(d);
 
   ldout(cct, 10) << __func__ << " " << *dirp->inode << " offset " << hex << dirp->offset
@@ -8655,15 +8743,15 @@ int Client::open(const char *relpath, int flags, const UserPerm& perms,
                 mode_t mode, int stripe_unit, int stripe_count,
                 int object_size, const char *data_pool)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << "open enter(" << relpath << ", " << ceph_flags_sys2wire(flags) << "," << mode << ")" << dendl;
   tout(cct) << "open" << std::endl;
   tout(cct) << relpath << std::endl;
   tout(cct) << ceph_flags_sys2wire(flags) << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *fh = NULL;
 
 #if defined(__linux__) && defined(O_PATH)
@@ -8679,6 +8767,8 @@ int Client::open(const char *relpath, int flags, const UserPerm& perms,
   bool created = false;
   /* O_CREATE with O_EXCL enforces O_NOFOLLOW. */
   bool followsym = !((flags & O_NOFOLLOW) || ((flags & O_CREAT) && (flags & O_EXCL)));
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms, followsym, ceph_caps_for_mode(mode));
 
   if (r == 0 && (flags & O_CREAT) && (flags & O_EXCL))
@@ -8745,12 +8835,13 @@ int Client::open(const char *relpath, int flags, const UserPerm& perms, mode_t m
 int Client::lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name,
                        const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
   ldout(cct, 3) << __func__ << " enter(" << ino << ", #" << dirino << "/" << name << ")" << dendl;
 
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
   MetaRequest *req = new MetaRequest(CEPH_MDS_OP_LOOKUPHASH);
   filepath path(ino);
   req->set_filepath(path);
@@ -8780,7 +8871,8 @@ int Client::_lookup_ino(inodeno_t ino, const UserPerm& perms, Inode **inode)
 {
   ldout(cct, 8) << __func__ << " enter(" << ino << ")" << dendl;
 
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
   MetaRequest *req = new MetaRequest(CEPH_MDS_OP_LOOKUPINO);
@@ -8843,7 +8935,8 @@ int Client::_lookup_name(Inode *ino, Inode *parent, const UserPerm& perms)
   ceph_assert(parent->is_dir());
   ldout(cct, 3) << __func__ << " enter(" << ino->ino << ")" << dendl;
 
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
   MetaRequest *req = new MetaRequest(CEPH_MDS_OP_LOOKUPNAME);
@@ -9058,14 +9151,15 @@ int Client::_renew_caps(Inode *in)
 
 int Client::close(int fd)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << "close enter(" << fd << ")" << dendl;
   tout(cct) << "close" << std::endl;
   tout(cct) << fd << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *fh = get_filehandle(fd);
   if (!fh)
     return -EBADF;
@@ -9082,15 +9176,16 @@ int Client::close(int fd)
 
 loff_t Client::lseek(int fd, loff_t offset, int whence)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << "lseek" << std::endl;
   tout(cct) << fd << std::endl;
   tout(cct) << offset << std::endl;
   tout(cct) << whence << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -9254,15 +9349,16 @@ int Client::uninline_data(Inode *in, Context *onfinish)
 
 int Client::read(int fd, char *buf, loff_t size, loff_t offset)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << "read" << std::endl;
   tout(cct) << fd << std::endl;
   tout(cct) << size << std::endl;
   tout(cct) << offset << std::endl;
 
   std::unique_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -9574,7 +9670,7 @@ void Client::_sync_write_commit(Inode *in)
   put_cap_ref(in, CEPH_CAP_FILE_BUFFER);
 
   ldout(cct, 15) << __func__ << " unsafe_sync_write = " << unsafe_sync_write << dendl;
-  if (unsafe_sync_write == 0 && unmounting) {
+  if (unsafe_sync_write == 0 && is_unmounting()) {
     ldout(cct, 10) << __func__ << " -- no more unsafe writes, unmount can proceed" << dendl;
     mount_cond.notify_all();
   }
@@ -9582,15 +9678,16 @@ void Client::_sync_write_commit(Inode *in)
 
 int Client::write(int fd, const char *buf, loff_t size, loff_t offset) 
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << "write" << std::endl;
   tout(cct) << fd << std::endl;
   tout(cct) << size << std::endl;
   tout(cct) << offset << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *fh = get_filehandle(fd);
   if (!fh)
     return -EBADF;
@@ -9661,13 +9758,14 @@ int64_t Client::_preadv_pwritev_locked(Fh *fh, const struct iovec *iov,
 
 int Client::_preadv_pwritev(int fd, const struct iovec *iov, unsigned iovcnt, int64_t offset, bool write)
 {
+    RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+    if (!mref_reader.is_state_satisfied())
+      return -ENOTCONN;
+
     tout(cct) << fd << std::endl;
     tout(cct) << offset << std::endl;
 
     std::scoped_lock lock(client_lock);
-    if (unmounting)
-     return -ENOTCONN;
-
     Fh *fh = get_filehandle(fd);
     if (!fh)
         return -EBADF;
@@ -9930,14 +10028,15 @@ int Client::truncate(const char *relpath, loff_t length, const UserPerm& perms)
 
 int Client::ftruncate(int fd, loff_t length, const UserPerm& perms) 
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   tout(cct) << fd << std::endl;
   tout(cct) << length << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -9952,14 +10051,15 @@ int Client::ftruncate(int fd, loff_t length, const UserPerm& perms)
 
 int Client::fsync(int fd, bool syncdataonly) 
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << "fsync" << std::endl;
   tout(cct) << fd << std::endl;
   tout(cct) << syncdataonly << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -10061,13 +10161,14 @@ int Client::_fsync(Fh *f, bool syncdataonly)
 
 int Client::fstat(int fd, struct stat *stbuf, const UserPerm& perms, int mask)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << "fstat mask " << hex << mask << dec << std::endl;
   tout(cct) << fd << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -10082,13 +10183,14 @@ int Client::fstat(int fd, struct stat *stbuf, const UserPerm& perms, int mask)
 int Client::fstatx(int fd, struct ceph_statx *stx, const UserPerm& perms,
                   unsigned int want, unsigned int flags)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << "fstatx flags " << hex << flags << " want " << want << dec << std::endl;
   tout(cct) << fd << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -10114,15 +10216,17 @@ int Client::fstatx(int fd, struct ceph_statx *stx, const UserPerm& perms,
 int Client::chdir(const char *relpath, std::string &new_cwd,
                  const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << "chdir" << std::endl;
   tout(cct) << relpath << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   filepath path(relpath);
   InodeRef in;
+
+  std::scoped_lock lock(client_lock);
   int r = path_walk(path, &in, perms);
   if (r < 0)
     return r;
@@ -10180,24 +10284,29 @@ void Client::_getcwd(string& dir, const UserPerm& perms)
 
 void Client::getcwd(string& dir, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return;
+
   std::lock_guard l(client_lock);
-  if (!unmounting)
-    _getcwd(dir, perms);
+
+  _getcwd(dir, perms);
 }
 
 int Client::statfs(const char *path, struct statvfs *stbuf,
                   const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << std::endl;
   unsigned long int total_files_on_fs;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   ceph_statfs stats;
   C_SaferCond cond;
 
+  std::scoped_lock lock(client_lock);
   const vector<int64_t> &data_pools = mdsmap->get_data_pools();
   if (data_pools.size() == 1) {
     objecter->get_fs_stats(stats, data_pools[0], &cond);
@@ -10649,6 +10758,10 @@ int Client::test_dentry_handling(bool can_invalidate)
 {
   int r = 0;
 
+  RWRef_t iref_reader(initialize_state, CLIENT_INITIALIZED);
+  if (!iref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   can_invalidate_dentries = can_invalidate;
 
   if (can_invalidate_dentries) {
@@ -10697,11 +10810,12 @@ int Client::_sync_fs()
 
 int Client::sync_fs()
 {
-  std::lock_guard l(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard l(client_lock);
+
   return _sync_fs();
 }
 
@@ -10796,11 +10910,12 @@ int Client::lazyio_synchronize(int fd, loff_t offset, size_t count)
 
 int Client::mksnap(const char *relpath, const char *name, const UserPerm& perm)
 {
-  std::lock_guard l(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard l(client_lock);
+
   filepath path(relpath);
   InodeRef in;
   int r = path_walk(path, &in, perm);
@@ -10817,11 +10932,12 @@ int Client::mksnap(const char *relpath, const char *name, const UserPerm& perm)
 
 int Client::rmsnap(const char *relpath, const char *name, const UserPerm& perms)
 {
-  std::lock_guard l(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard l(client_lock);
+
   filepath path(relpath);
   InodeRef in;
   int r = path_walk(path, &in, perms);
@@ -10839,13 +10955,14 @@ int Client::rmsnap(const char *relpath, const char *name, const UserPerm& perms)
 // =============================
 // expose caps
 
-int Client::get_caps_issued(int fd) {
+int Client::get_caps_issued(int fd)
+{
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
 
   std::lock_guard lock(client_lock);
 
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -10855,11 +10972,12 @@ int Client::get_caps_issued(int fd) {
 
 int Client::get_caps_issued(const char *path, const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   filepath p(path);
   InodeRef in;
   int r = path_walk(p, &in, perms, true);
@@ -10908,14 +11026,16 @@ Inode *Client::open_snapdir(Inode *diri)
 int Client::ll_lookup(Inode *parent, const char *name, struct stat *attr,
                      Inode **out, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vparent = _get_vino(parent);
   ldout(cct, 3) << __func__ << " " << vparent << " " << name << dendl;
   tout(cct) << __func__ << std::endl;
   tout(cct) << name << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   int r = 0;
   if (!fuse_default_permissions) {
@@ -10953,11 +11073,12 @@ int Client::ll_lookup_inode(
     Inode **inode)
 {
   ceph_assert(inode != NULL);
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   std::lock_guard lock(client_lock);
   ldout(cct, 3) << "ll_lookup_inode " << ino  << dendl;
-   
-  if (unmounting)
-    return -ENOTCONN;
 
   // Num1: get inode and *inode
   int r = _lookup_ino(ino, perms, inode);
@@ -11003,14 +11124,16 @@ int Client::ll_lookupx(Inode *parent, const char *name, Inode **out,
                       struct ceph_statx *stx, unsigned want, unsigned flags,
                       const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vparent = _get_vino(parent);
   ldout(cct, 3) << __func__ << " " << vparent << " " << name << dendl;
   tout(cct) << "ll_lookupx" << std::endl;
   tout(cct) << name << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   int r = 0;
   if (!fuse_default_permissions) {
@@ -11043,6 +11166,10 @@ int Client::ll_lookupx(Inode *parent, const char *name, Inode **out,
 int Client::ll_walk(const char* name, Inode **out, struct ceph_statx *stx,
                    unsigned int want, unsigned int flags, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   filepath fp(name, 0);
   InodeRef in;
   int rc;
@@ -11053,9 +11180,6 @@ int Client::ll_walk(const char* name, Inode **out, struct ceph_statx *stx,
   tout(cct) << name << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   rc = path_walk(fp, &in, perms, !(flags & AT_SYMLINK_NOFOLLOW), mask);
   if (rc < 0) {
     /* zero out mask, just in case... */
@@ -11138,7 +11262,8 @@ bool Client::_ll_forget(Inode *in, uint64_t count)
   tout(cct) << count << std::endl;
 
   // Ignore forget if we're no longer mounted
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return true;
 
   if (ino == 1) return true;  // ignore forget on root.
@@ -11186,11 +11311,12 @@ snapid_t Client::ll_get_snapid(Inode *in)
 
 Inode *Client::ll_get_inode(ino_t ino)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return NULL;
 
+  std::lock_guard lock(client_lock);
+
   vinodeno_t vino = _map_faked_ino(ino);
   unordered_map<vinodeno_t,Inode*>::iterator p = inode_map.find(vino);
   if (p == inode_map.end())
@@ -11202,11 +11328,12 @@ Inode *Client::ll_get_inode(ino_t ino)
 
 Inode *Client::ll_get_inode(vinodeno_t vino)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return NULL;
 
+  std::lock_guard lock(client_lock);
+
   unordered_map<vinodeno_t,Inode*>::iterator p = inode_map.find(vino);
   if (p == inode_map.end())
     return NULL;
@@ -11231,11 +11358,12 @@ int Client::_ll_getattr(Inode *in, int caps, const UserPerm& perms)
 
 int Client::ll_getattr(Inode *in, struct stat *attr, const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   int res = _ll_getattr(in, CEPH_STAT_CAP_INODE_ALL, perms);
 
   if (res == 0)
@@ -11247,11 +11375,12 @@ int Client::ll_getattr(Inode *in, struct stat *attr, const UserPerm& perms)
 int Client::ll_getattrx(Inode *in, struct ceph_statx *stx, unsigned int want,
                        unsigned int flags, const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   int res = 0;
   unsigned mask = statx_to_mask(flags, want);
 
@@ -11296,11 +11425,12 @@ int Client::_ll_setattrx(Inode *in, struct ceph_statx *stx, int mask,
 int Client::ll_setattrx(Inode *in, struct ceph_statx *stx, int mask,
                        const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   InodeRef target(in);
   int res = _ll_setattrx(in, stx, mask, perms, &target);
   if (res == 0) {
@@ -11318,11 +11448,12 @@ int Client::ll_setattr(Inode *in, struct stat *attr, int mask,
   struct ceph_statx stx;
   stat_to_statx(attr, &stx);
 
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   InodeRef target(in);
   int res = _ll_setattrx(in, &stx, mask, perms, &target);
   if (res == 0) {
@@ -11341,11 +11472,12 @@ int Client::ll_setattr(Inode *in, struct stat *attr, int mask,
 int Client::getxattr(const char *path, const char *name, void *value, size_t size,
                     const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   InodeRef in;
   int r = Client::path_walk(path, &in, perms, true, CEPH_STAT_CAP_XATTR);
   if (r < 0)
@@ -11356,11 +11488,12 @@ int Client::getxattr(const char *path, const char *name, void *value, size_t siz
 int Client::lgetxattr(const char *path, const char *name, void *value, size_t size,
                      const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   InodeRef in;
   int r = Client::path_walk(path, &in, perms, false, CEPH_STAT_CAP_XATTR);
   if (r < 0)
@@ -11371,11 +11504,12 @@ int Client::lgetxattr(const char *path, const char *name, void *value, size_t si
 int Client::fgetxattr(int fd, const char *name, void *value, size_t size,
                      const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -11385,11 +11519,12 @@ int Client::fgetxattr(int fd, const char *name, void *value, size_t size,
 int Client::listxattr(const char *path, char *list, size_t size,
                      const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   InodeRef in;
   int r = Client::path_walk(path, &in, perms, true, CEPH_STAT_CAP_XATTR);
   if (r < 0)
@@ -11400,11 +11535,12 @@ int Client::listxattr(const char *path, char *list, size_t size,
 int Client::llistxattr(const char *path, char *list, size_t size,
                       const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   InodeRef in;
   int r = Client::path_walk(path, &in, perms, false, CEPH_STAT_CAP_XATTR);
   if (r < 0)
@@ -11414,11 +11550,12 @@ int Client::llistxattr(const char *path, char *list, size_t size,
 
 int Client::flistxattr(int fd, char *list, size_t size, const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -11428,11 +11565,12 @@ int Client::flistxattr(int fd, char *list, size_t size, const UserPerm& perms)
 int Client::removexattr(const char *path, const char *name,
                        const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   InodeRef in;
   int r = Client::path_walk(path, &in, perms, true);
   if (r < 0)
@@ -11443,11 +11581,12 @@ int Client::removexattr(const char *path, const char *name,
 int Client::lremovexattr(const char *path, const char *name,
                         const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   InodeRef in;
   int r = Client::path_walk(path, &in, perms, false);
   if (r < 0)
@@ -11457,11 +11596,12 @@ int Client::lremovexattr(const char *path, const char *name,
 
 int Client::fremovexattr(int fd, const char *name, const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -11473,11 +11613,12 @@ int Client::setxattr(const char *path, const char *name, const void *value,
 {
   _setxattr_maybe_wait_for_osdmap(name, value, size);
 
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   InodeRef in;
   int r = Client::path_walk(path, &in, perms, true);
   if (r < 0)
@@ -11490,11 +11631,12 @@ int Client::lsetxattr(const char *path, const char *name, const void *value,
 {
   _setxattr_maybe_wait_for_osdmap(name, value, size);
 
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   InodeRef in;
   int r = Client::path_walk(path, &in, perms, false);
   if (r < 0)
@@ -11507,11 +11649,12 @@ int Client::fsetxattr(int fd, const char *name, const void *value, size_t size,
 {
   _setxattr_maybe_wait_for_osdmap(name, value, size);
 
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -11595,6 +11738,10 @@ int Client::_getxattr(InodeRef &in, const char *name, void *value, size_t size,
 int Client::ll_getxattr(Inode *in, const char *name, void *value,
                        size_t size, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vino = _get_vino(in);
 
   ldout(cct, 3) << __func__ << " " << vino << " " << name << " size " << size << dendl;
@@ -11603,9 +11750,6 @@ int Client::ll_getxattr(Inode *in, const char *name, void *value,
   tout(cct) << name << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   if (!fuse_default_permissions) {
     int r = xattr_permission(in, name, MAY_READ, perms);
     if (r < 0)
@@ -11648,6 +11792,10 @@ out:
 int Client::ll_listxattr(Inode *in, char *names, size_t size,
                         const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vino = _get_vino(in);
 
   ldout(cct, 3) << __func__ << " " << vino << " size " << size << dendl;
@@ -11656,9 +11804,6 @@ int Client::ll_listxattr(Inode *in, char *names, size_t size,
   tout(cct) << size << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   return _listxattr(in, names, size, perms);
 }
 
@@ -11850,6 +11995,10 @@ void Client::_setxattr_maybe_wait_for_osdmap(const char *name, const void *value
 int Client::ll_setxattr(Inode *in, const char *name, const void *value,
                        size_t size, int flags, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   _setxattr_maybe_wait_for_osdmap(name, value, size);
 
   vinodeno_t vino = _get_vino(in);
@@ -11860,9 +12009,6 @@ int Client::ll_setxattr(Inode *in, const char *name, const void *value,
   tout(cct) << name << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   if (!fuse_default_permissions) {
     int r = xattr_permission(in, name, MAY_WRITE, perms);
     if (r < 0)
@@ -11915,6 +12061,10 @@ int Client::_removexattr(InodeRef &in, const char *name, const UserPerm& perms)
 
 int Client::ll_removexattr(Inode *in, const char *name, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vino = _get_vino(in);
 
   ldout(cct, 3) << "ll_removexattr " << vino << " " << name << dendl;
@@ -11923,9 +12073,6 @@ int Client::ll_removexattr(Inode *in, const char *name, const UserPerm& perms)
   tout(cct) << name << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   if (!fuse_default_permissions) {
     int r = xattr_permission(in, name, MAY_WRITE, perms);
     if (r < 0)
@@ -12195,6 +12342,10 @@ const Client::VXattr *Client::_match_vxattr(Inode *in, const char *name)
 
 int Client::ll_readlink(Inode *in, char *buf, size_t buflen, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vino = _get_vino(in);
 
   ldout(cct, 3) << "ll_readlink " << vino << dendl;
@@ -12202,9 +12353,6 @@ int Client::ll_readlink(Inode *in, char *buf, size_t buflen, const UserPerm& per
   tout(cct) << vino.ino.val << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   for (auto dn : in->dentries) {
     touch_dn(dn);
   }
@@ -12272,6 +12420,10 @@ int Client::ll_mknod(Inode *parent, const char *name, mode_t mode,
                     dev_t rdev, struct stat *attr, Inode **out,
                     const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vparent = _get_vino(parent);
 
   ldout(cct, 3) << "ll_mknod " << vparent << " " << name << dendl;
@@ -12282,9 +12434,6 @@ int Client::ll_mknod(Inode *parent, const char *name, mode_t mode,
   tout(cct) << rdev << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   if (!fuse_default_permissions) {
     int r = may_create(parent, perms);
     if (r < 0)
@@ -12309,7 +12458,12 @@ int Client::ll_mknodx(Inode *parent, const char *name, mode_t mode,
                      struct ceph_statx *stx, unsigned want, unsigned flags,
                      const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   unsigned caps = statx_to_mask(flags, want);
+
   vinodeno_t vparent = _get_vino(parent);
 
   ldout(cct, 3) << "ll_mknodx " << vparent << " " << name << dendl;
@@ -12320,8 +12474,6 @@ int Client::ll_mknodx(Inode *parent, const char *name, mode_t mode,
   tout(cct) << rdev << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   if (!fuse_default_permissions) {
     int r = may_create(parent, perms);
@@ -12497,6 +12649,10 @@ int Client::_mkdir(Inode *dir, const char *name, mode_t mode, const UserPerm& pe
 int Client::ll_mkdir(Inode *parent, const char *name, mode_t mode,
                     struct stat *attr, Inode **out, const UserPerm& perm)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vparent = _get_vino(parent);
 
   ldout(cct, 3) << "ll_mkdir " << vparent << " " << name << dendl;
@@ -12506,8 +12662,6 @@ int Client::ll_mkdir(Inode *parent, const char *name, mode_t mode,
   tout(cct) << mode << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   if (!fuse_default_permissions) {
     int r = may_create(parent, perm);
@@ -12532,6 +12686,10 @@ int Client::ll_mkdirx(Inode *parent, const char *name, mode_t mode, Inode **out,
                      struct ceph_statx *stx, unsigned want, unsigned flags,
                      const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vparent = _get_vino(parent);
 
   ldout(cct, 3) << "ll_mkdirx " << vparent << " " << name << dendl;
@@ -12541,8 +12699,6 @@ int Client::ll_mkdirx(Inode *parent, const char *name, mode_t mode, Inode **out,
   tout(cct) << mode << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   if (!fuse_default_permissions) {
     int r = may_create(parent, perms);
@@ -12615,6 +12771,10 @@ int Client::_symlink(Inode *dir, const char *name, const char *target,
 int Client::ll_symlink(Inode *parent, const char *name, const char *value,
                       struct stat *attr, Inode **out, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vparent = _get_vino(parent);
 
   ldout(cct, 3) << "ll_symlink " << vparent << " " << name << " -> " << value
@@ -12625,8 +12785,6 @@ int Client::ll_symlink(Inode *parent, const char *name, const char *value,
   tout(cct) << value << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   if (!fuse_default_permissions) {
     int r = may_create(parent, perms);
@@ -12651,6 +12809,10 @@ int Client::ll_symlinkx(Inode *parent, const char *name, const char *value,
                        Inode **out, struct ceph_statx *stx, unsigned want,
                        unsigned flags, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vparent = _get_vino(parent);
 
   ldout(cct, 3) << "ll_symlinkx " << vparent << " " << name << " -> " << value
@@ -12661,8 +12823,6 @@ int Client::ll_symlinkx(Inode *parent, const char *name, const char *value,
   tout(cct) << value << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   if (!fuse_default_permissions) {
     int r = may_create(parent, perms);
@@ -12735,6 +12895,10 @@ int Client::_unlink(Inode *dir, const char *name, const UserPerm& perm)
 
 int Client::ll_unlink(Inode *in, const char *name, const UserPerm& perm)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vino = _get_vino(in);
 
   ldout(cct, 3) << "ll_unlink " << vino << " " << name << dendl;
@@ -12743,8 +12907,6 @@ int Client::ll_unlink(Inode *in, const char *name, const UserPerm& perm)
   tout(cct) << name << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   if (!fuse_default_permissions) {
     int r = may_delete(in, name, perm);
@@ -12809,6 +12971,10 @@ int Client::_rmdir(Inode *dir, const char *name, const UserPerm& perms)
 
 int Client::ll_rmdir(Inode *in, const char *name, const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vino = _get_vino(in);
 
   ldout(cct, 3) << "ll_rmdir " << vino << " " << name << dendl;
@@ -12817,8 +12983,6 @@ int Client::ll_rmdir(Inode *in, const char *name, const UserPerm& perms)
   tout(cct) << name << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   if (!fuse_default_permissions) {
     int r = may_delete(in, name, perms);
@@ -12988,6 +13152,10 @@ int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const ch
 int Client::ll_rename(Inode *parent, const char *name, Inode *newparent,
                      const char *newname, const UserPerm& perm)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vparent = _get_vino(parent);
   vinodeno_t vnewparent = _get_vino(newparent);
 
@@ -13000,8 +13168,6 @@ int Client::ll_rename(Inode *parent, const char *name, Inode *newparent,
   tout(cct) << newname << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   if (!fuse_default_permissions) {
     int r = may_delete(parent, name, perm);
@@ -13063,6 +13229,10 @@ int Client::_link(Inode *in, Inode *dir, const char *newname, const UserPerm& pe
 int Client::ll_link(Inode *in, Inode *newparent, const char *newname,
                    const UserPerm& perm)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vino = _get_vino(in);
   vinodeno_t vnewparent = _get_vino(newparent);
 
@@ -13073,12 +13243,10 @@ int Client::ll_link(Inode *in, Inode *newparent, const char *newname,
   tout(cct) << vnewparent << std::endl;
   tout(cct) << newname << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   InodeRef target;
 
+  std::scoped_lock lock(client_lock);
+
   if (!fuse_default_permissions) {
     if (S_ISDIR(in->mode))
       return -EPERM;
@@ -13197,6 +13365,10 @@ uint64_t Client::ll_get_internal_offset(Inode *in, uint64_t blockno)
 int Client::ll_opendir(Inode *in, int flags, dir_result_t** dirpp,
                       const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vino = _get_vino(in);
 
   ldout(cct, 3) << "ll_opendir " << vino << dendl;
@@ -13204,8 +13376,6 @@ int Client::ll_opendir(Inode *in, int flags, dir_result_t** dirpp,
   tout(cct) << vino.ino.val << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   if (!fuse_default_permissions) {
     int r = may_open(in, flags, perms);
@@ -13223,13 +13393,15 @@ int Client::ll_opendir(Inode *in, int flags, dir_result_t** dirpp,
 
 int Client::ll_releasedir(dir_result_t *dirp)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << "ll_releasedir " << dirp << dendl;
   tout(cct) << "ll_releasedir" << std::endl;
   tout(cct) << (unsigned long)dirp << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   _closedir(dirp);
   return 0;
@@ -13237,14 +13409,15 @@ int Client::ll_releasedir(dir_result_t *dirp)
 
 int Client::ll_fsyncdir(dir_result_t *dirp)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << "ll_fsyncdir " << dirp << dendl;
   tout(cct) << "ll_fsyncdir" << std::endl;
   tout(cct) << (unsigned long)dirp << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   return _fsync(dirp->inode.get(), false);
 }
 
@@ -13252,6 +13425,10 @@ int Client::ll_open(Inode *in, int flags, Fh **fhp, const UserPerm& perms)
 {
   ceph_assert(!(flags & O_CREAT));
 
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   vinodeno_t vino = _get_vino(in);
 
   ldout(cct, 3) << "ll_open " << vino << " " << ceph_flags_sys2wire(flags) << dendl;
@@ -13260,8 +13437,6 @@ int Client::ll_open(Inode *in, int flags, Fh **fhp, const UserPerm& perms)
   tout(cct) << ceph_flags_sys2wire(flags) << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   int r;
   if (!fuse_default_permissions) {
@@ -13369,12 +13544,13 @@ int Client::ll_create(Inode *parent, const char *name, mode_t mode,
                      int flags, struct stat *attr, Inode **outp, Fh **fhp,
                      const UserPerm& perms)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   std::lock_guard lock(client_lock);
   InodeRef in;
 
-  if (unmounting)
-    return -ENOTCONN;
-
   int r = _ll_create(parent, name, mode, flags, &in, CEPH_STAT_CAP_INODE_ALL,
                      fhp, perms);
   if (r >= 0) {
@@ -13399,12 +13575,13 @@ int Client::ll_createx(Inode *parent, const char *name, mode_t mode,
                        const UserPerm& perms)
 {
   unsigned caps = statx_to_mask(lflags, want);
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   std::lock_guard lock(client_lock);
   InodeRef in;
 
-  if (unmounting)
-    return -ENOTCONN;
-
   int r = _ll_create(parent, name, mode, oflags, &in, caps, fhp, perms);
   if (r >= 0) {
     ceph_assert(in);
@@ -13425,31 +13602,34 @@ int Client::ll_createx(Inode *parent, const char *name, mode_t mode,
 
 loff_t Client::ll_lseek(Fh *fh, loff_t offset, int whence)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << "ll_lseek" << std::endl;
   tout(cct) << offset << std::endl;
   tout(cct) << whence << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   return _lseek(fh, offset, whence);
 }
 
 int Client::ll_read(Fh *fh, loff_t off, loff_t len, bufferlist *bl)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << "ll_read " << fh << " " << fh->inode->ino << " " << " " << off << "~" << len << dendl;
   tout(cct) << "ll_read" << std::endl;
   tout(cct) << (unsigned long)fh << std::endl;
   tout(cct) << off << std::endl;
   tout(cct) << len << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   /* We can't return bytes written larger than INT_MAX, clamp len to that */
   len = std::min(len, (loff_t)INT_MAX);
+  std::scoped_lock lock(client_lock);
+
   int r = _read(fh, off, len, bl);
   ldout(cct, 3) << "ll_read " << fh << " " << off << "~" << len << " = " << r
                << dendl;
@@ -13462,9 +13642,8 @@ int Client::ll_read_block(Inode *in, uint64_t blockid,
                          uint64_t length,
                          file_layout_t* layout)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
   vinodeno_t vino = _get_vino(in);
@@ -13472,6 +13651,8 @@ int Client::ll_read_block(Inode *in, uint64_t blockid,
   C_SaferCond onfinish;
   bufferlist bl;
 
+  std::scoped_lock lock(client_lock);
+
   objecter->read(oid,
                 object_locator_t(layout->pool_id),
                 offset,
@@ -13504,7 +13685,11 @@ int Client::ll_write_block(Inode *in, uint64_t blockid,
   vinodeno_t vino = ll_get_vino(in);
   int r = 0;
   std::unique_ptr<C_SaferCond> onsafe = nullptr;
-  
+
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   if (length == 0) {
     return -EINVAL;
   }
@@ -13527,11 +13712,6 @@ int Client::ll_write_block(Inode *in, uint64_t blockid,
 
   /* lock just in time */
   client_lock.lock();
-  if (unmounting) {
-    client_lock.unlock();
-    return -ENOTCONN;
-  }
-
   objecter->write(oid,
                  object_locator_t(layout->pool_id),
                  offset,
@@ -13558,7 +13738,6 @@ int Client::ll_commit_blocks(Inode *in,
                             uint64_t offset,
                             uint64_t length)
 {
-    std::lock_guard lock(client_lock);
     /*
     BarrierContext *bctx;
     vinodeno_t vino = _get_vino(in);
@@ -13571,6 +13750,7 @@ int Client::ll_commit_blocks(Inode *in,
       return -EINVAL;
     }
 
+    std::scoped_lock lock(client_lock);
     map<uint64_t, BarrierContext*>::iterator p = barriers.find(ino);
     if (p != barriers.end()) {
       barrier_interval civ(offset, offset + length);
@@ -13589,12 +13769,14 @@ int Client::ll_write(Fh *fh, loff_t off, loff_t len, const char *data)
   tout(cct) << off << std::endl;
   tout(cct) << len << std::endl;
 
-  std::scoped_lock lock(client_lock);
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
   /* We can't return bytes written larger than INT_MAX, clamp len to that */
   len = std::min(len, (loff_t)INT_MAX);
+  std::scoped_lock lock(client_lock);
+
   int r = _write(fh, off, len, data, NULL, 0);
   ldout(cct, 3) << "ll_write " << fh << " " << off << "~" << len << " = " << r
                << dendl;
@@ -13603,43 +13785,49 @@ int Client::ll_write(Fh *fh, loff_t off, loff_t len, const char *data)
 
 int64_t Client::ll_writev(struct Fh *fh, const struct iovec *iov, int iovcnt, int64_t off)
 {
-  std::lock_guard lock(client_lock);
-  if (unmounting)
-   return -ENOTCONN;
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
+  std::scoped_lock lock(client_lock);
   return _preadv_pwritev_locked(fh, iov, iovcnt, off, true, false);
 }
 
 int64_t Client::ll_readv(struct Fh *fh, const struct iovec *iov, int iovcnt, int64_t off)
 {
-  std::lock_guard lock(client_lock);
-  if (unmounting)
-   return -ENOTCONN;
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
+  std::scoped_lock lock(client_lock);
   return _preadv_pwritev_locked(fh, iov, iovcnt, off, false, false);
 }
 
 int Client::ll_flush(Fh *fh)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << "ll_flush " << fh << " " << fh->inode->ino << " " << dendl;
   tout(cct) << "ll_flush" << std::endl;
   tout(cct) << (unsigned long)fh << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   return _flush(fh);
 }
 
 int Client::ll_fsync(Fh *fh, bool syncdataonly)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << "ll_fsync " << fh << " " << fh->inode->ino << " " << dendl;
   tout(cct) << "ll_fsync" << std::endl;
   tout(cct) << (unsigned long)fh << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   int r = _fsync(fh, syncdataonly);
   if (r) {
     // If we're returning an error, clear it from the FH
@@ -13650,14 +13838,15 @@ int Client::ll_fsync(Fh *fh, bool syncdataonly)
 
 int Client::ll_sync_inode(Inode *in, bool syncdataonly)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << "ll_sync_inode " << *in << " " << dendl;
   tout(cct) << "ll_sync_inode" << std::endl;
   tout(cct) << (unsigned long)in << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   return _fsync(in, syncdataonly);
 }
 
@@ -13795,25 +13984,27 @@ int Client::_fallocate(Fh *fh, int mode, int64_t offset, int64_t length)
 
 int Client::ll_fallocate(Fh *fh, int mode, int64_t offset, int64_t length)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << __func__ << " " << fh << " " << fh->inode->ino << " " << dendl;
   tout(cct) << __func__ << " " << mode << " " << offset << " " << length << std::endl;
   tout(cct) << (unsigned long)fh << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   return _fallocate(fh, mode, offset, length);
 }
 
 int Client::fallocate(int fd, int mode, loff_t offset, loff_t length)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   tout(cct) << __func__ << " " << " " << fd << mode << " " << offset << " " << length << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   Fh *fh = get_filehandle(fd);
   if (!fh)
     return -EBADF;
@@ -13826,14 +14017,16 @@ int Client::fallocate(int fd, int mode, loff_t offset, loff_t length)
 
 int Client::ll_release(Fh *fh)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << __func__ << " (fh)" << fh << " " << fh->inode->ino << " " <<
     dendl;
   tout(cct) << __func__ << " (fh)" << std::endl;
   tout(cct) << (unsigned long)fh << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
 
   if (ll_unclosed_fh_set.count(fh))
     ll_unclosed_fh_set.erase(fh);
@@ -13842,43 +14035,46 @@ int Client::ll_release(Fh *fh)
 
 int Client::ll_getlk(Fh *fh, struct flock *fl, uint64_t owner)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << "ll_getlk (fh)" << fh << " " << fh->inode->ino << dendl;
   tout(cct) << "ll_getk (fh)" << (unsigned long)fh << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   return _getlk(fh, fl, owner);
 }
 
 int Client::ll_setlk(Fh *fh, struct flock *fl, uint64_t owner, int sleep)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << __func__ << "  (fh) " << fh << " " << fh->inode->ino << dendl;
   tout(cct) << __func__ << " (fh)" << (unsigned long)fh << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   return _setlk(fh, fl, owner, sleep);
 }
 
 int Client::ll_flock(Fh *fh, int cmd, uint64_t owner)
 {
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
+    return -ENOTCONN;
+
   ldout(cct, 3) << __func__ << "  (fh) " << fh << " " << fh->inode->ino << dendl;
   tout(cct) << __func__ << " (fh)" << (unsigned long)fh << std::endl;
 
   std::scoped_lock lock(client_lock);
-  if (unmounting)
-    return -ENOTCONN;
-
   return _flock(fh, cmd, owner);
 }
 
 int Client::set_deleg_timeout(uint32_t timeout)
 {
-  std::lock_guard lock(client_lock);
+  std::scoped_lock lock(client_lock);
 
   /*
    * The whole point is to prevent blacklisting so we must time out the
@@ -13895,11 +14091,12 @@ int Client::ll_delegation(Fh *fh, unsigned cmd, ceph_deleg_cb_t cb, void *priv)
 {
   int ret = -EINVAL;
 
-  std::lock_guard lock(client_lock);
-
-  if (!mounted)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   Inode *inode = fh->inode.get();
 
   switch(cmd) {
@@ -13950,11 +14147,12 @@ void Client::ll_interrupt(void *d)
 int Client::describe_layout(const char *relpath, file_layout_t *lp,
                            const UserPerm& perms)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   filepath path(relpath);
   InodeRef in;
   int r = path_walk(path, &in, perms);
@@ -13969,11 +14167,12 @@ int Client::describe_layout(const char *relpath, file_layout_t *lp,
 
 int Client::fdescribe_layout(int fd, file_layout_t *lp)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -13987,11 +14186,12 @@ int Client::fdescribe_layout(int fd, file_layout_t *lp)
 
 int64_t Client::get_default_pool_id()
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   /* first data pool is the default */ 
   return mdsmap->get_first_data_pool(); 
 }
@@ -14000,22 +14200,24 @@ int64_t Client::get_default_pool_id()
 
 int64_t Client::get_pool_id(const char *pool_name)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::lock_guard lock(client_lock);
+
   return objecter->with_osdmap(std::mem_fn(&OSDMap::lookup_pg_pool_name),
                               pool_name);
 }
 
 string Client::get_pool_name(int64_t pool)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return string();
 
+  std::scoped_lock lock(client_lock);
+
   return objecter->with_osdmap([pool](const OSDMap& o) {
       return o.have_pg_pool(pool) ? o.get_pool_name(pool) : string();
     });
@@ -14023,11 +14225,12 @@ string Client::get_pool_name(int64_t pool)
 
 int Client::get_pool_replication(int64_t pool)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   return objecter->with_osdmap([pool](const OSDMap& o) {
       return o.have_pg_pool(pool) ? o.get_pg_pool(pool)->get_size() : -ENOENT;
     });
@@ -14035,11 +14238,12 @@ int Client::get_pool_replication(int64_t pool)
 
 int Client::get_file_extent_osds(int fd, loff_t off, loff_t *len, vector<int>& osds)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -14081,11 +14285,12 @@ int Client::get_file_extent_osds(int fd, loff_t off, loff_t *len, vector<int>& o
 
 int Client::get_osd_crush_location(int id, vector<pair<string, string> >& path)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   if (id < 0)
     return -EINVAL;
   return objecter->with_osdmap([&](const OSDMap& o) {
@@ -14096,11 +14301,12 @@ int Client::get_osd_crush_location(int id, vector<pair<string, string> >& path)
 int Client::get_file_stripe_address(int fd, loff_t offset,
                                    vector<entity_addr_t>& address)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -14129,11 +14335,12 @@ int Client::get_file_stripe_address(int fd, loff_t offset,
 
 int Client::get_osd_addr(int osd, entity_addr_t& addr)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   return objecter->with_osdmap([&](const OSDMap& o) {
       if (!o.exists(osd))
        return -ENOENT;
@@ -14146,11 +14353,12 @@ int Client::get_osd_addr(int osd, entity_addr_t& addr)
 int Client::enumerate_layout(int fd, vector<ObjectExtent>& result,
                             loff_t length, loff_t offset)
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   Fh *f = get_filehandle(fd);
   if (!f)
     return -EBADF;
@@ -14167,11 +14375,12 @@ int Client::enumerate_layout(int fd, vector<ObjectExtent>& result,
 /* find an osd with the same ip.  -ENXIO if none. */
 int Client::get_local_osd()
 {
-  std::lock_guard lock(client_lock);
-
-  if (unmounting)
+  RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
+  if (!mref_reader.is_state_satisfied())
     return -ENOTCONN;
 
+  std::scoped_lock lock(client_lock);
+
   objecter->with_osdmap([this](const OSDMap& o) {
       if (o.get_epoch() != local_osd_epoch) {
        local_osd = o.find_osd_on_ip(messenger->get_myaddrs().front());
@@ -14201,8 +14410,8 @@ bool Client::ms_handle_reset(Connection *con)
 
 void Client::ms_handle_remote_reset(Connection *con)
 {
+  std::scoped_lock lock(client_lock);
   ldout(cct, 0) << __func__ << " on " << con->get_peer_addr() << dendl;
-  std::lock_guard l(client_lock);
   switch (con->get_peer_type()) {
   case CEPH_ENTITY_TYPE_MDS:
     {
@@ -14562,8 +14771,10 @@ void Client::clear_filer_flags(int flags)
 // called before mount
 void Client::set_uuid(const std::string& uuid)
 {
+  RWRef_t iref_reader(initialize_state, CLIENT_INITIALIZED);
+  ceph_assert(iref_reader.is_state_satisfied());
+
   std::lock_guard l(client_lock);
-  assert(initialized);
   assert(!uuid.empty());
 
   metadata["uuid"] = uuid;
@@ -14573,8 +14784,10 @@ void Client::set_uuid(const std::string& uuid)
 // called before mount. 0 means infinite
 void Client::set_session_timeout(unsigned timeout)
 {
+  RWRef_t iref_reader(initialize_state, CLIENT_INITIALIZED);
+  ceph_assert(iref_reader.is_state_satisfied());
+
   std::lock_guard l(client_lock);
-  assert(initialized);
 
   metadata["timeout"] = stringify(timeout);
 }
@@ -14583,13 +14796,14 @@ void Client::set_session_timeout(unsigned timeout)
 int Client::start_reclaim(const std::string& uuid, unsigned flags,
                          const std::string& fs_name)
 {
-  std::unique_lock l(client_lock);
-  if (!initialized)
+  RWRef_t iref_reader(initialize_state, CLIENT_INITIALIZED);
+  if (!iref_reader.is_state_satisfied())
     return -ENOTCONN;
 
   if (uuid.empty())
     return -EINVAL;
 
+  std::unique_lock l(client_lock);
   {
     auto it = metadata.find("uuid");
     if (it != metadata.end() && it->second == uuid)
@@ -14806,11 +15020,13 @@ StandaloneClient::~StandaloneClient()
 
 int StandaloneClient::init()
 {
+  RWRef_t iref_writer(initialize_state, CLIENT_INITIALIZING, false);
+  ceph_assert(iref_writer.is_first_writer());
+
   _pre_init();
   objecter->init();
 
   client_lock.lock();
-  ceph_assert(!is_initialized());
 
   messenger->add_dispatcher_tail(objecter);
   messenger->add_dispatcher_tail(this);
@@ -14834,6 +15050,7 @@ int StandaloneClient::init()
 
   client_lock.unlock();
   _finish_init();
+  iref_writer.update_state(CLIENT_INITIALIZED);
 
   return 0;
 }
index f1057e8465d32229aa88f840019d79a473a5445b..1437d8f29b01a5f17e838cb13730c69ea31dd346 100644 (file)
@@ -37,6 +37,7 @@
 #include "msg/Messenger.h"
 #include "osdc/ObjectCacher.h"
 
+#include "RWRef.h"
 #include "InodeRef.h"
 #include "MetaSession.h"
 #include "UserPerm.h"
@@ -66,6 +67,7 @@ class WritebackHandler;
 
 class MDSMap;
 class Message;
+class destructive_lock_ref_t;
 
 enum {
   l_c_first = 20000,
@@ -236,6 +238,8 @@ public:
   friend class C_Client_CacheRelease; // Asserts on client_lock
   friend class SyntheticClient;
   friend void intrusive_ptr_release(Inode *in);
+  template <typename T> friend struct RWRefState;
+  template <typename T> friend class RWRef;
 
   using Dispatcher::cct;
 
@@ -760,9 +764,6 @@ protected:
   static const unsigned CHECK_CAPS_NODELAY = 0x1;
   static const unsigned CHECK_CAPS_SYNCHRONOUS = 0x2;
 
-
-  bool is_initialized() const { return initialized; }
-
   void check_caps(Inode *in, unsigned flags);
 
   void set_cap_epoch_barrier(epoch_t e);
@@ -982,6 +983,124 @@ protected:
 
   client_t whoami;
 
+  /* The state migration mechanism */
+  enum _state {
+    /* For the initialize_state */
+    CLIENT_NEW, // The initial state for the initialize_state or after Client::shutdown()
+    CLIENT_INITIALIZING, // At the beginning of the Client::init()
+    CLIENT_INITIALIZED, // At the end of CLient::init()
+
+    /* For the mount_state */
+    CLIENT_UNMOUNTED, // The initial state for the mount_state or after unmounted
+    CLIENT_MOUNTING, // At the beginning of Client::mount()
+    CLIENT_MOUNTED, // At the end of Client::mount()
+    CLIENT_UNMOUNTING, // At the beginning of the Client::_unmout()
+  };
+
+  typedef enum _state state_t;
+  using RWRef_t = RWRef<state_t>;
+
+  struct mount_state_t : public RWRefState<state_t> {
+    public:
+      bool is_valid_state(state_t state) override {
+        switch (state) {
+         case Client::CLIENT_MOUNTING:
+         case Client::CLIENT_MOUNTED:
+         case Client::CLIENT_UNMOUNTING:
+         case Client::CLIENT_UNMOUNTED:
+            return true;
+          default:
+            return false;
+        }
+      }
+
+      int check_reader_state(state_t require) override {
+        if (require == Client::CLIENT_MOUNTING &&
+            (state == Client::CLIENT_MOUNTING || state == Client::CLIENT_MOUNTED))
+          return true;
+        else
+          return false;
+      }
+
+      /* The state migration check */
+      int check_writer_state(state_t require) override {
+        if (require == Client::CLIENT_MOUNTING &&
+            state == Client::CLIENT_UNMOUNTED)
+          return true;
+       else if (require == Client::CLIENT_MOUNTED &&
+            state == Client::CLIENT_MOUNTING)
+          return true;
+       else if (require == Client::CLIENT_UNMOUNTING &&
+            state == Client::CLIENT_MOUNTED)
+          return true;
+       else if (require == Client::CLIENT_UNMOUNTED &&
+            state == Client::CLIENT_UNMOUNTING)
+          return true;
+        else
+          return false;
+      }
+
+      mount_state_t(state_t state, const char *lockname, uint64_t reader_cnt=0)
+        : RWRefState (state, lockname, reader_cnt) {}
+      ~mount_state_t() {}
+  };
+
+  struct initialize_state_t : public RWRefState<state_t> {
+    public:
+      bool is_valid_state(state_t state) override {
+        switch (state) {
+         case Client::CLIENT_NEW:
+          case Client::CLIENT_INITIALIZING:
+         case Client::CLIENT_INITIALIZED:
+            return true;
+          default:
+            return false;
+        }
+      }
+
+      int check_reader_state(state_t require) override {
+        if (require == Client::CLIENT_INITIALIZED &&
+            state >= Client::CLIENT_INITIALIZED)
+          return true;
+        else
+          return false;
+      }
+
+      /* The state migration check */
+      int check_writer_state(state_t require) override {
+        if (require == Client::CLIENT_INITIALIZING &&
+            (state == Client::CLIENT_NEW))
+          return true;
+       else if (require == Client::CLIENT_INITIALIZED &&
+            (state == Client::CLIENT_INITIALIZING))
+          return true;
+       else if (require == Client::CLIENT_NEW &&
+            (state == Client::CLIENT_INITIALIZED))
+          return true;
+        else
+          return false;
+      }
+
+      initialize_state_t(state_t state, const char *lockname, uint64_t reader_cnt=0)
+        : RWRefState (state, lockname, reader_cnt) {}
+      ~initialize_state_t() {}
+  };
+
+  struct mount_state_t mount_state;
+  bool is_unmounting() {
+    return mount_state.check_current_state(CLIENT_UNMOUNTING);
+  }
+  bool is_mounted() {
+    return mount_state.check_current_state(CLIENT_MOUNTED);
+  }
+  bool is_mounting() {
+    return mount_state.check_current_state(CLIENT_MOUNTING);
+  }
+
+  struct initialize_state_t initialize_state;
+  bool is_initialized() {
+    return initialize_state.check_current_state(CLIENT_INITIALIZED);
+  }
 
 private:
   struct C_Readahead : public Context {
@@ -1249,9 +1368,6 @@ private:
   ceph::unordered_set<dir_result_t*> opened_dirs;
   uint64_t fd_gen = 1;
 
-  bool   initialized = false;
-  bool   mounted = false;
-  bool   unmounting = false;
   bool   blacklisted = false;
 
   ceph::unordered_map<vinodeno_t, Inode*> inode_map;