]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/mount/mount.ceph.c
import quincy beta 17.1.0
[ceph.git] / ceph / src / mount / mount.ceph.c
index af3e4389fbf6bb5d0ec61c86a830498dcf54b828..43c2cdccb7a9ef23ec370cfb5d04fbb36eaab1c8 100644 (file)
 bool verboseflag = false;
 bool skip_mtab_flag = false;
 bool v2_addrs = false;
+bool no_fallback = false;
+bool ms_mode_specified = false;
+bool mon_addr_specified = false;
 static const char * const EMPTY_STRING = "";
 
 /* TODO duplicates logic from kernel */
 #define CEPH_AUTH_NAME_DEFAULT "guest"
 
+/* path to sysfs for ceph */
+#define CEPH_SYS_FS_PATH "/sys/module/ceph/"
+#define CEPH_SYS_FS_PARAM_PATH CEPH_SYS_FS_PATH"/parameters"
+
+/*
+ * mount support hint from kernel -- we only need to check
+ * v2 support for catching bugs.
+ */
+#define CEPH_V2_MOUNT_SUPPORT_PATH CEPH_SYS_FS_PARAM_PATH"/mount_syntax_v2"
+
+#define CEPH_DEFAULT_V2_MS_MODE "prefer-crc"
+
 #include "mtab.c"
 
+enum mount_dev_format {
+  MOUNT_DEV_FORMAT_OLD = 0,
+  MOUNT_DEV_FORMAT_NEW = 1,
+};
+
 struct ceph_mount_info {
        unsigned long   cmi_flags;
        char            *cmi_name;
+       char            *cmi_fsname;
+       char            *cmi_fsid;
        char            *cmi_path;
        char            *cmi_mons;
        char            *cmi_conf;
        char            *cmi_opts;
        int             cmi_opts_len;
        char            cmi_secret[SECRET_BUFSIZE];
+
+       /* mount dev syntax format */
+       enum mount_dev_format format;
 };
 
+static void mon_addr_as_resolve_param(char *mon_addr)
+{
+       for (; *mon_addr; ++mon_addr)
+               if (*mon_addr == '/')
+                       *mon_addr = ',';
+}
+
+static void resolved_mon_addr_as_mount_opt(char *mon_addr)
+{
+       for (; *mon_addr; ++mon_addr)
+               if (*mon_addr == ',')
+                       *mon_addr = '/';
+}
+
+static void resolved_mon_addr_as_mount_dev(char *mon_addr)
+{
+       for (; *mon_addr; ++mon_addr)
+               if (*mon_addr == '/')
+                       *mon_addr = ',';
+}
+
 static void block_signals (int how)
 {
      sigset_t sigs;
@@ -59,20 +105,100 @@ void mount_ceph_debug(const char *fmt, ...)
        }
 }
 
-static int parse_src(const char *orig_str, struct ceph_mount_info *cmi)
+/*
+ * append a key value pair option to option string.
+ */
+static void append_opt(const char *key, const char *value,
+                      struct ceph_mount_info *cmi, int *pos)
+{
+       if (*pos != 0)
+               *pos = safe_cat(&cmi->cmi_opts, &cmi->cmi_opts_len, *pos, ",");
+
+       if (value) {
+               *pos = safe_cat(&cmi->cmi_opts, &cmi->cmi_opts_len, *pos, key);
+               *pos = safe_cat(&cmi->cmi_opts, &cmi->cmi_opts_len, *pos, "=");
+               *pos = safe_cat(&cmi->cmi_opts, &cmi->cmi_opts_len, *pos, value);
+       } else {
+               *pos = safe_cat(&cmi->cmi_opts, &cmi->cmi_opts_len, *pos, key);
+       }
+}
+
+/*
+ * remove a key value pair from option string. caller should ensure that the
+ * key value pair is separated by "=".
+ */
+static int remove_opt(struct ceph_mount_info *cmi, const char *key, char **value)
+{
+       char *key_start = strstr(cmi->cmi_opts, key);
+       if (!key_start) {
+               return -ENOENT;
+       }
+
+       /* key present -- try to split */
+       char *key_sep = strstr(key_start, "=");
+       if (!key_sep) {
+               return -ENOENT;
+       }
+
+       if (strncmp(key, key_start, key_sep - key_start) != 0) {
+               return -ENOENT;
+       }
+
+       ++key_sep;
+       char *value_end = strstr(key_sep, ",");
+       if (!value_end)
+               value_end = key_sep + strlen(key_sep);
+
+       if (value_end != key_sep && value) {
+               size_t len1 = value_end - key_sep;
+               *value = strndup(key_sep, len1+1);
+               if (!*value)
+                       return -ENOMEM;
+               (*value)[len1] = '\0';
+       }
+
+       /* purge it */
+       size_t len2 = strlen(value_end);
+       if (len2) {
+               ++value_end;
+               memmove(key_start, value_end, len2);
+       } else {
+                /* last kv pair - swallow the comma */
+               --key_start;
+               *key_start = '\0';
+       }
+
+       return 0;
+}
+
+static void record_name(const char *name, struct ceph_mount_info *cmi)
+{
+       int name_pos = 0;
+       int name_len = 0;
+
+       name_pos = safe_cat(&cmi->cmi_name, &name_len, name_pos, name);
+}
+
+/*
+ * parse old device string of format: <mon_addr>:/<path>
+ */
+static int parse_old_dev(const char *dev_str, struct ceph_mount_info *cmi,
+                        int *opt_pos)
 {
        size_t len;
        char *mount_path;
 
-       mount_path = strstr(orig_str, ":/");
+       mount_path = strstr(dev_str, ":/");
        if (!mount_path) {
                fprintf(stderr, "source mount path was not specified\n");
                return -EINVAL;
        }
 
-       len = mount_path - orig_str;
+       len = mount_path - dev_str;
        if (len != 0) {
-               cmi->cmi_mons = strndup(orig_str, len);
+               free(cmi->cmi_mons);
+               /* overrides mon_addr passed via mount option (if any) */
+               cmi->cmi_mons = strndup(dev_str, len);
                if (!cmi->cmi_mons)
                        return -ENOMEM;
        }
@@ -81,23 +207,138 @@ static int parse_src(const char *orig_str, struct ceph_mount_info *cmi)
        cmi->cmi_path = strdup(mount_path);
        if (!cmi->cmi_path)
                return -ENOMEM;
+       if (!cmi->cmi_name)
+               record_name(CEPH_AUTH_NAME_DEFAULT, cmi);
+
+       cmi->format = MOUNT_DEV_FORMAT_OLD;
+       return 0;
+}
+
+/*
+ * parse new device string of format: name@<fsid>.fs_name=/path
+ */
+static int parse_new_dev(const char *dev_str, struct ceph_mount_info *cmi,
+                        int *opt_pos)
+{
+       size_t len;
+       char *name;
+       char *name_end;
+       char *dot;
+       char *fs_name;
+
+       name_end = strstr(dev_str, "@");
+       if (!name_end) {
+               mount_ceph_debug("invalid new device string format\n");
+               return -ENODEV;
+       }
+
+       len = name_end - dev_str;
+       if (!len) {
+               fprintf(stderr, "missing <name> in device\n");
+               return -EINVAL;
+       }
+
+       name = (char *)alloca(len+1);
+       memcpy(name, dev_str, len);
+       name[len] = '\0';
+
+       if (cmi->cmi_name && strcmp(cmi->cmi_name, name)) {
+               fprintf(stderr, "mismatching ceph user in mount option and device string\n");
+               return -EINVAL;
+       }
+
+       /* record name and store in option string */
+       if (!cmi->cmi_name) {
+               record_name(name, cmi);
+               append_opt("name", name, cmi, opt_pos);
+       }
+
+       ++name_end;
+       /* check if an fsid is included in the device string */
+       dot = strstr(name_end, ".");
+       if (!dot) {
+               fprintf(stderr, "invalid device string format\n");
+               return -EINVAL;
+       }
+       len = dot - name_end;
+       if (len) {
+               /* check if this _looks_ like a UUID */
+               if (len != CLUSTER_FSID_LEN - 1) {
+                       fprintf(stderr, "invalid device string format\n");
+                       return -EINVAL;
+               }
+
+               cmi->cmi_fsid = strndup(name_end, len);
+               if (!cmi->cmi_fsid)
+                       return -ENOMEM;
+       }
+
+       ++dot;
+       fs_name = strstr(dot, "=");
+       if (!fs_name) {
+               fprintf(stderr, "invalid device string format\n");
+               return -EINVAL;
+       }
+       len = fs_name - dot;
+       if (!len) {
+               fprintf(stderr, "missing <fs_name> in device\n");
+               return -EINVAL;
+       }
+       cmi->cmi_fsname = strndup(dot, len);
+       if (!cmi->cmi_fsname)
+               return -ENOMEM;
+
+       ++fs_name;
+       if (strlen(fs_name)) {
+               cmi->cmi_path = strdup(fs_name);
+               if (!cmi->cmi_path)
+                       return -ENOMEM;
+       }
+
+       /* new-style dev - force using v2 addrs first */
+       if (!ms_mode_specified && !mon_addr_specified) {
+               v2_addrs = true;
+               append_opt("ms_mode", CEPH_DEFAULT_V2_MS_MODE, cmi,
+                          opt_pos);
+       }
+
+       cmi->format = MOUNT_DEV_FORMAT_NEW;
        return 0;
 }
 
-static char *finalize_src(struct ceph_mount_info *cmi)
+static int parse_dev(const char *dev_str, struct ceph_mount_info *cmi,
+                    int *opt_pos)
+{
+       int ret;
+
+       ret = parse_new_dev(dev_str, cmi, opt_pos);
+       if (ret < 0 && ret != -ENODEV)
+               return -EINVAL;
+       if (ret)
+               ret = parse_old_dev(dev_str, cmi, opt_pos);
+       if (ret < 0)
+               fprintf(stderr, "error parsing device string\n");
+       return ret;
+}
+
+/* resolve monitor host and record in option string */
+static int finalize_src(struct ceph_mount_info *cmi, int *opt_pos)
 {
-       int pos, len;
        char *src;
+        size_t len = strlen(cmi->cmi_mons);
+        char *addr = alloca(len+1);
 
-       src = resolve_addrs(cmi->cmi_mons);
-       if (!src)
-               return NULL;
+        memcpy(addr, cmi->cmi_mons, len+1);
+        mon_addr_as_resolve_param(addr);
 
-       len = strlen(src);
-       pos = safe_cat(&src, &len, len, ":");
-       safe_cat(&src, &len, pos, cmi->cmi_path);
+       src = resolve_addrs(addr);
+       if (!src)
+               return -1;
 
-       return src;
+       resolved_mon_addr_as_mount_opt(src);
+       append_opt("mon_addr", src, cmi, opt_pos);
+       free(src);
+       return 0;
 }
 
 static int
@@ -133,7 +374,7 @@ static int fetch_config_info(struct ceph_mount_info *cmi)
        struct ceph_config_info *cci;
 
        /* Don't do anything if we already have requisite info */
-       if (cmi->cmi_secret[0] && cmi->cmi_mons)
+       if (cmi->cmi_secret[0] && cmi->cmi_mons && cmi->cmi_fsid)
                return 0;
 
        cci = mmap((void *)0, sizeof(*cci), PROT_READ | PROT_WRITE,
@@ -152,11 +393,19 @@ static int fetch_config_info(struct ceph_mount_info *cmi)
        }
 
        if (pid == 0) {
+               char *entity_name = NULL;
+               int name_pos = 0;
+               int name_len = 0;
+
                /* child */
                ret = drop_capabilities();
                if (ret)
                        exit(1);
-               mount_ceph_get_config_info(cmi->cmi_conf, cmi->cmi_name, v2_addrs, cci);
+
+               name_pos = safe_cat(&entity_name, &name_len, name_pos, "client.");
+               name_pos = safe_cat(&entity_name, &name_len, name_pos, cmi->cmi_name);
+               mount_ceph_get_config_info(cmi->cmi_conf, entity_name, v2_addrs, cci);
+               free(entity_name);
                exit(0);
        } else {
                /* parent */
@@ -192,6 +441,11 @@ static int fetch_config_info(struct ceph_mount_info *cmi)
                        if (len < MON_LIST_BUFSIZE)
                                cmi->cmi_mons = strndup(cci->cci_mons, len + 1);
                }
+               if (!cmi->cmi_fsid) {
+                       len = strnlen(cci->cci_fsid, CLUSTER_FSID_LEN);
+                       if (len < CLUSTER_FSID_LEN)
+                               cmi->cmi_fsid = strndup(cci->cci_fsid, len + 1);
+               }
        }
 out:
        munmap(cci, sizeof(*cci));
@@ -201,13 +455,11 @@ out:
 /*
  * this one is partially based on parse_options() from cifs.mount.c
  */
-static int parse_options(const char *data, struct ceph_mount_info *cmi)
+static int parse_options(const char *data, struct ceph_mount_info *cmi,
+                        int *opt_pos)
 {
        char * next_keyword = NULL;
-       int pos = 0;
        char *name = NULL;
-       int name_len = 0;
-       int name_pos = 0;
 
        if (data == EMPTY_STRING)
                goto out;
@@ -279,6 +531,8 @@ static int parse_options(const char *data, struct ceph_mount_info *cmi)
                        }
                        data = "mds_namespace";
                        skip = false;
+               } else if (strcmp(data, "nofallback") == 0) {
+                       no_fallback = true;
                } else if (strcmp(data, "secretfile") == 0) {
                        int ret;
 
@@ -327,35 +581,38 @@ static int parse_options(const char *data, struct ceph_mount_info *cmi)
                        /* Only legacy ms_mode needs v1 addrs */
                        v2_addrs = strcmp(value, "legacy");
                        skip = false;
+                       ms_mode_specified = true;
+               } else if (strcmp(data, "mon_addr") == 0) {
+                       /* monitor address to use for mounting */
+                       if (!value || !*value) {
+                               fprintf(stderr, "mount option mon_addr requires a value.\n");
+                               return -EINVAL;
+                       }
+                       cmi->cmi_mons = strdup(value);
+                       if (!cmi->cmi_mons)
+                               return -ENOMEM;
+                       mon_addr_specified = true;
                } else {
                        /* unrecognized mount options, passing to kernel */
                        skip = false;
                }
 
                /* Copy (possibly modified) option to out */
-               if (!skip) {
-                       if (pos)
-                               pos = safe_cat(&cmi->cmi_opts, &cmi->cmi_opts_len, pos, ",");
-
-                       if (value) {
-                               pos = safe_cat(&cmi->cmi_opts, &cmi->cmi_opts_len, pos, data);
-                               pos = safe_cat(&cmi->cmi_opts, &cmi->cmi_opts_len, pos, "=");
-                               pos = safe_cat(&cmi->cmi_opts, &cmi->cmi_opts_len, pos, value);
-                       } else {
-                               pos = safe_cat(&cmi->cmi_opts, &cmi->cmi_opts_len, pos, data);
-                       }
-               }
+               if (!skip)
+                        append_opt(data, value, cmi, opt_pos);
                data = next_keyword;
        } while (data);
 
 out:
-       name_pos = safe_cat(&cmi->cmi_name, &name_len, name_pos, "client.");
-       name_pos = safe_cat(&cmi->cmi_name, &name_len, name_pos,
-                           name ? name : CEPH_AUTH_NAME_DEFAULT);
-
+       /*
+        * set ->cmi_name conditionally -- this gets checked when parsing new
+        * device format. for old device format, ->cmi_name is set to default
+        * user name when name option is not passed in.
+        */
+       if (name)
+               record_name(name, cmi);
        if (cmi->cmi_opts)
-               mount_ceph_debug("mount.ceph: options \"%s\" will pass to kernel.\n",
-                                                cmi->cmi_opts);
+               mount_ceph_debug("mount.ceph: options \"%s\".\n",  cmi->cmi_opts);
 
        if (!cmi->cmi_opts) {
                cmi->cmi_opts = strdup(EMPTY_STRING);
@@ -402,8 +659,7 @@ static int parse_arguments(int argc, char *const *const argv,
                                return -EINVAL;
                        }
                        *opts = argv[i];
-               }
-               else {
+                } else {
                        fprintf(stderr, "Can't understand option: '%s'\n\n", argv[i]);
                        return -EINVAL;
                }
@@ -442,11 +698,175 @@ static void ceph_mount_info_free(struct ceph_mount_info *cmi)
 {
        free(cmi->cmi_opts);
        free(cmi->cmi_name);
+       free(cmi->cmi_fsname);
+       free(cmi->cmi_fsid);
        free(cmi->cmi_path);
        free(cmi->cmi_mons);
        free(cmi->cmi_conf);
 }
 
+static int mount_new_device_format(const char *node, struct ceph_mount_info *cmi)
+{
+       int r;
+       char *rsrc = NULL;
+       int pos = 0;
+       int len = 0;
+
+       if (!cmi->cmi_fsid) {
+               fprintf(stderr, "missing ceph cluster-id");
+               return -EINVAL;
+       }
+
+       pos = safe_cat(&rsrc, &len, pos, cmi->cmi_name);
+       pos = safe_cat(&rsrc, &len, pos, "@");
+       pos = safe_cat(&rsrc, &len, pos, cmi->cmi_fsid);
+       pos = safe_cat(&rsrc, &len, pos, ".");
+       pos = safe_cat(&rsrc, &len, pos, cmi->cmi_fsname);
+       pos = safe_cat(&rsrc, &len, pos, "=");
+       if (cmi->cmi_path)
+               safe_cat(&rsrc, &len, pos, cmi->cmi_path);
+
+       mount_ceph_debug("mount.ceph: trying mount with new device syntax: %s\n",
+                        rsrc);
+       if (cmi->cmi_opts)
+               mount_ceph_debug("mount.ceph: options \"%s\" will pass to kernel\n",
+                                cmi->cmi_opts);
+       r = mount(rsrc, node, "ceph", cmi->cmi_flags, cmi->cmi_opts);
+       if (r)
+               r = -errno;
+       free(rsrc);
+       return r;
+}
+
+static int mount_old_device_format(const char *node, struct ceph_mount_info *cmi)
+{
+       int r;
+       int len = 0;
+       int pos = 0;
+       char *mon_addr;
+       char *rsrc = NULL;
+
+       r = remove_opt(cmi, "mon_addr", &mon_addr);
+       if (r) {
+               fprintf(stderr, "failed to switch using old device format\n");
+               return -EINVAL;
+       }
+
+       pos = strlen(cmi->cmi_opts);
+        if (cmi->cmi_fsname)
+                append_opt("mds_namespace", cmi->cmi_fsname, cmi, &pos);
+       if (cmi->cmi_fsid)
+               append_opt("fsid", cmi->cmi_fsid, cmi, &pos);
+
+       pos = 0;
+       resolved_mon_addr_as_mount_dev(mon_addr);
+       pos = safe_cat(&rsrc, &len, pos, mon_addr);
+       pos = safe_cat(&rsrc, &len, pos, ":");
+       if (cmi->cmi_path)
+               safe_cat(&rsrc, &len, pos, cmi->cmi_path);
+
+       mount_ceph_debug("mount.ceph: trying mount with old device syntax: %s\n",
+                        rsrc);
+       if (cmi->cmi_opts)
+               mount_ceph_debug("mount.ceph: options \"%s\" will pass to kernel\n",
+                                cmi->cmi_opts);
+
+       r = mount(rsrc, node, "ceph", cmi->cmi_flags, cmi->cmi_opts);
+       free(mon_addr);
+       free(rsrc);
+
+       return r;
+}
+
+/*
+ * check whether to fall-back to using old-style mount syntax (called
+ * when new-style mount syntax fails). this is mostly to catch any
+ * new-style (v2) implementation bugs in the kernel and is primarly
+ * used in teuthology tests.
+ */
+static bool should_fallback()
+{
+       int ret;
+       struct stat stbuf;
+
+       if (!no_fallback)
+               return true;
+
+       ret = stat(CEPH_V2_MOUNT_SUPPORT_PATH, &stbuf);
+       if (ret) {
+               mount_ceph_debug("mount.ceph: v2 mount support check returned %d\n",
+                                errno);
+               if (errno == ENOENT)
+                       mount_ceph_debug("mount.ceph: kernel does not support v2"
+                                        " syntax\n");
+               /* fallback on *all* errors */
+               return true;
+       }
+
+       fprintf(stderr, "mount.ceph: kernel BUG!\n");
+       return false;
+}
+
+static int do_mount(const char *dev, const char *node,
+                   struct ceph_mount_info *cmi) {
+       int pos = 0;
+       int retval= -EINVAL;
+       bool fallback = true;
+
+        /* no v2 addresses available via config - try v1 addresses */
+       if (!cmi->cmi_mons &&
+           !ms_mode_specified &&
+           !mon_addr_specified &&
+           cmi->format == MOUNT_DEV_FORMAT_NEW) {
+               mount_ceph_debug("mount.ceph: switching to using v1 address\n");
+               v2_addrs = false;
+               fetch_config_info(cmi);
+               remove_opt(cmi, "ms_mode", NULL);
+       }
+
+       if (!cmi->cmi_mons) {
+               fprintf(stderr, "unable to determine mon addresses\n");
+               return -EINVAL;
+       }
+
+       pos = strlen(cmi->cmi_opts);
+       retval = finalize_src(cmi, &pos);
+       if (retval) {
+               fprintf(stderr, "failed to resolve source\n");
+               return -EINVAL;
+       }
+
+       retval = -1;
+       if (cmi->format == MOUNT_DEV_FORMAT_NEW) {
+               retval = mount_new_device_format(node, cmi);
+               if (retval)
+                       fallback = (should_fallback() && retval == -EINVAL && cmi->cmi_fsid);
+       }
+
+       /* pass-through or fallback to old-style mount device */
+       if (retval && fallback)
+               retval = mount_old_device_format(node, cmi);
+       if (retval) {
+               retval = EX_FAIL;
+               switch (errno) {
+               case ENODEV:
+                       fprintf(stderr, "mount error: ceph filesystem not supported by the system\n");
+                       break;
+               case EHOSTUNREACH:
+                       fprintf(stderr, "mount error: no mds server is up or the cluster is laggy\n");
+                       break;
+               default:
+                       fprintf(stderr, "mount error %d = %s\n", errno, strerror(errno));
+               }
+       }
+
+       if (!retval && !skip_mtab_flag) {
+               update_mtab_entry(dev, node, "ceph", cmi->cmi_opts, cmi->cmi_flags, 0, 0);
+       }
+
+       return retval;
+}
+
 static int append_key_or_secret_option(struct ceph_mount_info *cmi)
 {
        int pos = strlen(cmi->cmi_opts);
@@ -485,48 +905,39 @@ static int append_key_or_secret_option(struct ceph_mount_info *cmi)
 
 int main(int argc, char *argv[])
 {
-       const char *src, *node, *opts;
-       char *rsrc = NULL;
+       int opt_pos = 0;
+       const char *dev, *node, *opts;
        int retval;
        struct ceph_mount_info cmi = { 0 };
 
-       retval = parse_arguments(argc, argv, &src, &node, &opts);
+       retval = parse_arguments(argc, argv, &dev, &node, &opts);
        if (retval) {
                usage(argv[0]);
                retval = (retval > 0) ? 0 : EX_USAGE;
                goto out;
        }
 
-       retval = parse_options(opts, &cmi);
+       retval = parse_options(opts, &cmi, &opt_pos);
        if (retval) {
                fprintf(stderr, "failed to parse ceph_options: %d\n", retval);
                retval = EX_USAGE;
                goto out;
        }
 
-       retval = parse_src(src, &cmi);
+       retval = parse_dev(dev, &cmi, &opt_pos);
        if (retval) {
-               fprintf(stderr, "unable to parse mount source: %d\n", retval);
+               fprintf(stderr, "unable to parse mount device string: %d\n", retval);
                retval = EX_USAGE;
                goto out;
        }
 
-       /* We don't care if this errors out, since this is best-effort */
+       /*
+        * We don't care if this errors out, since this is best-effort.
+        * note that this fetches v1 or v2 addr depending on @v2_addr
+        * flag.
+        */
        fetch_config_info(&cmi);
 
-       if (!cmi.cmi_mons) {
-               fprintf(stderr, "unable to determine mon addresses\n");
-               retval = EX_USAGE;
-               goto out;
-       }
-
-       rsrc = finalize_src(&cmi);
-       if (!rsrc) {
-               fprintf(stderr, "failed to resolve source\n");
-               retval = EX_USAGE;
-               goto out;
-       }
-
        /* Ensure the ceph key_type is available */
        modprobe();
 
@@ -538,29 +949,10 @@ int main(int argc, char *argv[])
        }
 
        block_signals(SIG_BLOCK);
-
-       if (mount(rsrc, node, "ceph", cmi.cmi_flags, cmi.cmi_opts)) {
-               retval = EX_FAIL;
-               switch (errno) {
-               case ENODEV:
-                       fprintf(stderr, "mount error: ceph filesystem not supported by the system\n");
-                       break;
-               case EHOSTUNREACH:
-                       fprintf(stderr, "mount error: no mds server is up or the cluster is laggy\n");
-                       break;
-               default:
-                       fprintf(stderr, "mount error %d = %s\n",errno,strerror(errno));
-               }
-       } else {
-               if (!skip_mtab_flag) {
-                       update_mtab_entry(rsrc, node, "ceph", cmi.cmi_opts, cmi.cmi_flags, 0, 0);
-               }
-       }
-
+       retval = do_mount(dev, node, &cmi);
        block_signals(SIG_UNBLOCK);
 out:
        ceph_mount_info_free(&cmi);
-       free(rsrc);
        return retval;
 }