summaryrefslogtreecommitdiffstats
path: root/src/client/fuse_ll.cc
diff options
context:
space:
mode:
authorNikhilkumar Shelke <nshelke@redhat.com>2022-01-07 07:26:13 +0100
committerNikhilkumar Shelke <nshelke@redhat.com>2022-03-07 09:43:42 +0100
commitcd7bd5200df803f96af8ee9df822cad22337df48 (patch)
treeb3b89828ad7b8b1d73f6a0218e1317e04be46c3b /src/client/fuse_ll.cc
parentMerge pull request #42098 from joscollin/wip-B50033-rank0-stale-perf-stats (diff)
downloadceph-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.cc94
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) {