From: Nikhilkumar Shelke Date: Fri, 7 Jan 2022 06:26:13 +0000 (+0530) Subject: ceph-fuse: ignore fuse mount failure if path is already mounted X-Git-Tag: v18.0.0~1228^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=cd7bd5200df803f96af8ee9df822cad22337df48;p=ceph.git ceph-fuse: ignore fuse mount failure if path is already mounted Fixes: https://tracker.ceph.com/issues/46075 Signed-off-by: Nikhilkumar Shelke --- diff --git a/src/client/fuse_ll.cc b/src/client/fuse_ll.cc index c2de8940fb72..e060ac880877 100644 --- a/src/client/fuse_ll.cc +++ b/src/client/fuse_ll.cc @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include // 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 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) { diff --git a/src/mount.fuse.ceph b/src/mount.fuse.ceph index c61625a8c2f5..5f115d8efc30 100755 --- a/src/mount.fuse.ceph +++ b/src/mount.fuse.ceph @@ -27,6 +27,7 @@ id=myuser,conf=/etc/ceph/foo.conf /mnt/ceph fuse.ceph defaults 0 0 import sys import argparse +import errno from subprocess import Popen def ceph_options(mntops): @@ -73,7 +74,8 @@ def main(arguments): mount_cmd.communicate() if (mount_cmd.returncode != 0): - print("Mount failed with status code: {}".format(mount_cmd.returncode)) + if (mount_cmd.returncode != errno.EBUSY): + print("Mount failed with status code: {}".format(mount_cmd.returncode)) if __name__ == '__main__': sys.exit(main(sys.argv[1:]))