diff options
author | Nikhilkumar Shelke <nshelke@redhat.com> | 2022-01-07 07:26:13 +0100 |
---|---|---|
committer | Nikhilkumar Shelke <nshelke@redhat.com> | 2022-03-07 09:43:42 +0100 |
commit | cd7bd5200df803f96af8ee9df822cad22337df48 (patch) | |
tree | b3b89828ad7b8b1d73f6a0218e1317e04be46c3b /src/client/fuse_ll.cc | |
parent | Merge pull request #42098 from joscollin/wip-B50033-rank0-stale-perf-stats (diff) | |
download | ceph-cd7bd5200df803f96af8ee9df822cad22337df48.tar.xz ceph-cd7bd5200df803f96af8ee9df822cad22337df48.zip |
ceph-fuse: ignore fuse mount failure if path is already mounted
Fixes: https://tracker.ceph.com/issues/46075
Signed-off-by: Nikhilkumar Shelke <nshelke@redhat.com>
Diffstat (limited to 'src/client/fuse_ll.cc')
-rw-r--r-- | src/client/fuse_ll.cc | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index c2de8940fb7..e060ac88087 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -23,6 +23,10 @@ #include <errno.h> #include <fcntl.h> #include <unistd.h> +#include <libgen.h> +#include <sys/vfs.h> +#include <sys/xattr.h> +#include <linux/magic.h> // ceph #include "common/errno.h" @@ -53,6 +57,12 @@ #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) +#ifndef FUSE_SUPER_MAGIC +#define FUSE_SUPER_MAGIC 0x65735546 +#endif + +#define _CEPH_CLIENT_ID "ceph.client_id" + using namespace std; static const ceph::unordered_map<int,int> cephfs_errno_to_system_errno = { @@ -163,6 +173,76 @@ public: struct fuse_args args; }; +static int already_fuse_mounted(const char *path, bool &already_mounted) +{ + struct statx path_statx; + struct statx parent_statx; + char path_copy[PATH_MAX] = {0}; + char *parent_path = NULL; + int err = 0; + + already_mounted = false; + + strncpy(path_copy, path, sizeof(path_copy)-1); + parent_path = dirname(path_copy); + + // get stat information for original path + if (-1 == statx(AT_FDCWD, path, AT_STATX_DONT_SYNC, STATX_INO, &path_statx)) { + err = errno; + derr << "fuse_ll: already_fuse_mounted: statx(" << path << ") failed with error " + << cpp_strerror(err) << dendl; + return err; + } + + // if path isn't directory, then it can't be a mountpoint. + if (!(path_statx.stx_mode & S_IFDIR)) { + err = EINVAL; + derr << "fuse_ll: already_fuse_mounted: " + << path << " is not a directory" << dendl; + return err; + } + + // get stat information for parent path + if (-1 == statx(AT_FDCWD, parent_path, AT_STATX_DONT_SYNC, STATX_INO, &parent_statx)) { + err = errno; + derr << "fuse_ll: already_fuse_mounted: statx(" << parent_path << ") failed with error " + << cpp_strerror(err) << dendl; + return err; + } + + // if original path and parent have different device ids, + // then the path is a mount point + // or, if they refer to the same path, then it's probably + // the root directory '/' and therefore path is a mountpoint + if( path_statx.stx_dev_major != parent_statx.stx_dev_major || + path_statx.stx_dev_minor != parent_statx.stx_dev_minor || + ( path_statx.stx_dev_major == parent_statx.stx_dev_major && + path_statx.stx_dev_minor == parent_statx.stx_dev_minor && + path_statx.stx_ino == parent_statx.stx_ino + ) + ) { + struct statfs path_statfs; + if (-1 == statfs(path, &path_statfs)) { + err = errno; + derr << "fuse_ll: already_fuse_mounted: statfs(" << path << ") failed with error " + << cpp_strerror(err) << dendl; + return err; + } + + if(FUSE_SUPER_MAGIC == path_statfs.f_type) { + // if getxattr returns positive length means value exist for ceph.client_id + // then ceph fuse is already mounted on path + char client_id[128] = {0}; + if (getxattr(path, _CEPH_CLIENT_ID, &client_id, sizeof(client_id)) > 0) { + already_mounted = true; + derr << path << " already mounted by " << client_id << dendl; + } + } + } + + return err; +} + static int getgroups(fuse_req_t req, gid_t **sgids) { #if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) @@ -1349,6 +1429,20 @@ int CephFuse::Handle::init(int argc, const char *argv[]) int CephFuse::Handle::start() { + bool is_mounted = false; +#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0) + int err = already_fuse_mounted(opts.mountpoint, is_mounted); +#else + int err = already_fuse_mounted(mountpoint, is_mounted); +#endif + if (err) { + return err; + } + + if (is_mounted) { + return EBUSY; + } + #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0) se = fuse_session_new(&args, &fuse_ll_oper, sizeof(fuse_ll_oper), this); if (!se) { |