[systemd-devel] [PATCH v2 5/5] mount: auto-detect iSCSI and FCoE as requiring network

Zbigniew Jędrzejewski-Szmek zbyszek at in.waw.pl
Fri Nov 28 11:50:33 PST 2014


On Sun, Nov 23, 2014 at 08:33:41PM -0800, Chris Leech wrote:
> This adds auto detection for iSCSI and some FCoE drivers and treats
> mounts to file-systems on those devices as remote-fs.
> 
> Signed-off-by: Chris Leech <cleech at redhat.com>
No need for this.

I now pushed patches 1-4 with some small changes here and there.
Since libmount is not optional, I removed if from the version string.

This patch I didn't push: this seems like something that would be better
done through udev rules, by setting some tags. Then systemd could simply
check for the presence of a tag on the device without having any
special knowledge about iscsi and firends.

Zbyszek


> ---
>  src/core/mount.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 158 insertions(+), 10 deletions(-)
> 
> diff --git a/src/core/mount.c b/src/core/mount.c
> index 513dcec..52a4ba7 100644
> --- a/src/core/mount.c
> +++ b/src/core/mount.c
> @@ -26,6 +26,7 @@
>  #include <signal.h>
>  #include <libmount.h>
>  #include <sys/inotify.h>
> +#include <libudev.h>
>  
>  #include "manager.h"
>  #include "unit.h"
> @@ -44,6 +45,7 @@
>  #include "bus-errors.h"
>  #include "exit-status.h"
>  #include "def.h"
> +#include "udev-util.h"
>  
>  static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
>          [MOUNT_DEAD] = UNIT_INACTIVE,
> @@ -64,20 +66,166 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
>  static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
>  static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
>  
> -static bool mount_needs_network(const char *options, const char *fstype) {
> +static bool scsi_host_is(struct udev_device *host, const char *type) {
> +        _cleanup_free_ char *path;
> +        struct stat st;
> +
> +        assert(host);
> +        assert(type);
> +
> +        /* a <type>_host device created by the scsi transport class
> +         * should exists for all the transport types looked for */
> +
> +        if (asprintf(&path, "%s/%s_host", udev_device_get_syspath(host), type) < 0) {
> +                log_oom();
> +                return false;
> +        }
> +        return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
> +}
> +
> +static bool scsi_host_is_network(struct udev_device *block) {
> +        struct udev_device *host = NULL;
> +        struct udev *udev;
> +
> +        assert(block);
> +        udev = udev_device_get_udev(block);
> +
> +        host = udev_device_get_parent_with_subsystem_devtype(block, "scsi", "scsi_host");
> +        if (!host)
> +                return false;
> +
> +        /* iSCSI */
> +        if (scsi_host_is(host, "iscsi"))
> +                return true;
> +
> +        /* FCoE appears as an FC host with a parent FCoE Ctlr device
> +         * This will at least detect the software fcoe module and bnx2fc on kernels >= 3.5 */
> +        if (scsi_host_is(host, "fc")) {
> +                _cleanup_free_ char *fc_host_path = NULL;
> +                _cleanup_udev_device_unref_ struct udev_device *fc_host = NULL;
> +                struct udev_device *fcoe_ctlr = NULL;
> +
> +                if (asprintf(&fc_host_path, "%s/fc_host/%s", udev_device_get_syspath(host), udev_device_get_sysname(host)) < 0) {
> +                        log_oom();
> +                        return false;
> +                };
> +                fc_host = udev_device_new_from_syspath(udev, fc_host_path);
> +                fcoe_ctlr = udev_device_get_parent_with_subsystem_devtype(fc_host, "fcoe", "fcoe_ctlr");
> +                if (fcoe_ctlr)
> +                        return true;
> +        }
> +
> +        return false;
> +}
> +
> +static int dot_filter(const struct dirent *d) {
> +        if (streq(".", d->d_name) || streq("..", d->d_name))
> +                return 0;
> +        return 1;
> +}
> +
> +static inline bool is_partition(struct udev_device *block) {
> +        const char *devtype;
> +
> +        devtype = udev_device_get_devtype(block);
> +        if (streq(devtype, "partition")) {
> +                return true;
> +        }
> +        return false;
> +}
> +
> +static bool block_needs_network(struct udev_device *block) {
> +        struct udev_device *parent = NULL;
> +        _cleanup_free_ char *slaves_path = NULL;
> +        _cleanup_free_ struct dirent **slaves = NULL;
> +        struct udev *udev;
> +        int n, i;
> +        bool rc = false;
> +
> +        assert(block);
> +        udev = udev_device_get_udev(block);
> +
> +        if (scsi_host_is_network(block))
> +                return true;
> +
> +        /* if this is a partition, check the parent device */
> +
> +        if (is_partition(block)) {
> +                parent = udev_device_get_parent(block);
> +                if (parent && block_needs_network(parent))
> +                        return true;
> +        }
> +
> +        /* if this block device has "slaves" check them as well
> +         * this handles DM maps including LVM and multipath */
> +
> +        if (asprintf(&slaves_path, "%s/slaves", udev_device_get_syspath(block)) < 0) {
> +                log_oom();
> +                return false;
> +        }
> +
> +        n = scandir(slaves_path, &slaves, dot_filter, alphasort);
> +        for (i = 0; i < n; i++) {
> +                _cleanup_udev_device_unref_ struct udev_device *slave = NULL;
> +                _cleanup_free_ char *newpath = NULL;
> +                _cleanup_free_ char *rp = NULL;
> +
> +                if (asprintf(&newpath, "%s/%s", slaves_path, slaves[i]->d_name) < 0) {
> +                        log_oom();
> +                        goto free_the_slaves;
> +                }
> +                rp = realpath(newpath, NULL);
> +                if (!rp) {
> +                        log_oom();
> +                        goto free_the_slaves;
> +                }
> +                slave = udev_device_new_from_syspath(udev, rp);
> +                if (slave && block_needs_network(slave)) {
> +                        rc = true;
> +                        goto free_the_slaves;
> +                }
> +        }
> +
> +free_the_slaves:
> +        for (i = 0; i < n; i++)
> +                free(slaves[i]);
> +        return rc;
> +}
> +
> +static bool block_transport_is_network(struct udev *udev, const char *what) {
> +        _cleanup_udev_device_unref_ struct udev_device *block = NULL;
> +        struct stat st;
> +
> +        assert(udev);
> +        assert(what);
> +
> +        if ((stat(what, &st) != 0) || (!S_ISBLK(st.st_mode)))
> +                return false;
> +
> +        block = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
> +        if (!block)
> +                return false;
> +
> +        return block_needs_network(block);
> +}
> +
> +static bool mount_needs_network(Manager *m, const char *what, const char *options, const char *fstype) {
>          if (mount_test_option(options, "_netdev"))
>                  return true;
>  
>          if (fstype && fstype_is_network(fstype))
>                  return true;
>  
> +        if (what && block_transport_is_network(m->udev, what))
> +                return true;
> +
>          return false;
>  }
>  
> -static bool mount_is_network(MountParameters *p) {
> +static bool mount_is_network(Mount *m, MountParameters *p) {
>          assert(p);
>  
> -        return mount_needs_network(p->options, p->fstype);
> +        return mount_needs_network(m->meta.manager, p->what, p->options, p->fstype);
>  }
>  
>  static bool mount_is_bind(MountParameters *p) {
> @@ -104,10 +252,10 @@ static bool mount_is_auto(MountParameters *p) {
>          return !mount_test_option(p->options, "noauto");
>  }
>  
> -static bool needs_quota(MountParameters *p) {
> +static bool needs_quota(Mount *m, MountParameters *p) {
>          assert(p);
>  
> -        if (mount_is_network(p))
> +        if (mount_is_network(m, p))
>                  return false;
>  
>          if (mount_is_bind(p))
> @@ -263,7 +411,7 @@ static int mount_add_mount_links(Mount *m) {
>          pm = get_mount_parameters_fragment(m);
>          if (pm && pm->what &&
>              path_is_absolute(pm->what) &&
> -            !mount_is_network(pm)) {
> +            !mount_is_network(m, pm)) {
>  
>                  r = unit_require_mounts_for(UNIT(m), pm->what);
>                  if (r < 0)
> @@ -342,7 +490,7 @@ static int mount_add_quota_links(Mount *m) {
>          if (!p)
>                  return 0;
>  
> -        if (!needs_quota(p))
> +        if (!needs_quota(m, p))
>                  return 0;
>  
>          r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true);
> @@ -390,7 +538,7 @@ static int mount_add_default_dependencies(Mount *m) {
>              path_equal(m->where, "/usr"))
>                  return 0;
>  
> -        if (mount_is_network(p)) {
> +        if (mount_is_network(m, p)) {
>                  after = SPECIAL_REMOTE_FS_PRE_TARGET;
>                  after2 = SPECIAL_NETWORK_TARGET;
>                  online = SPECIAL_NETWORK_ONLINE_TARGET;
> @@ -1408,7 +1556,7 @@ static int mount_add_one(
>                  if (m->running_as == SYSTEMD_SYSTEM) {
>                          const char* target;
>  
> -                        target = mount_needs_network(options, fstype) ?  SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
> +                        target = mount_needs_network(m, what, options, fstype) ?  SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
>                          r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true);
>                          if (r < 0)
>                                  goto fail;
> @@ -1436,7 +1584,7 @@ static int mount_add_one(
>                  if (m->running_as == SYSTEMD_SYSTEM) {
>                          const char* target;
>  
> -                        target = mount_needs_network(options, fstype) ?  SPECIAL_REMOTE_FS_TARGET : NULL;
> +                        target = mount_needs_network(m, what, options, fstype) ?  SPECIAL_REMOTE_FS_TARGET : NULL;
>                          /* _netdev option may have shown up late, or on a
>                           * remount. Add remote-fs dependencies, even though
>                           * local-fs ones may already be there */
> -- 
> 1.9.3
> 
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel


More information about the systemd-devel mailing list