diff --git a/lib/geom/multipath/geom_multipath.c b/lib/geom/multipath/geom_multipath.c --- a/lib/geom/multipath/geom_multipath.c +++ b/lib/geom/multipath/geom_multipath.c @@ -121,6 +121,10 @@ "clear", G_FLAG_VERBOSE, mp_main, G_NULL_OPTS, "[-v] prov ..." }, + { + "which", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, + "[-v] name" + }, G_CMD_SENTINEL }; diff --git a/lib/geom/multipath/gmultipath.8 b/lib/geom/multipath/gmultipath.8 --- a/lib/geom/multipath/gmultipath.8 +++ b/lib/geom/multipath/gmultipath.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 8, 2016 +.Dd November 7, 2022 .Dt GMULTIPATH 8 .Os .Sh NAME @@ -87,6 +87,9 @@ .Op Fl v .Ar prov ... .Nm +.Cm which +.Ar prov +.Nm .Cm list .Nm .Cm status @@ -187,6 +190,8 @@ Stop the given multipath device without clearing metadata. .It Cm clear Clear metadata on the given provider. +.It Cm which +Get multipath device from provider/path. .It Cm list See .Xr geom 8 . diff --git a/sys/geom/multipath/g_multipath.c b/sys/geom/multipath/g_multipath.c --- a/sys/geom/multipath/g_multipath.c +++ b/sys/geom/multipath/g_multipath.c @@ -1491,6 +1491,54 @@ sbuf_delete(sb); } +static void +g_multipath_ctl_which(struct gctl_req *req, struct g_class *mp) +{ + struct sbuf *sb; + struct g_geom *gp; + struct g_consumer *cp; + struct g_provider *pp; + struct g_multipath_softc *sc; + const char *name; + bool found = false; + + sb = sbuf_new_auto(); + + g_topology_assert(); + name = gctl_get_asciiparam(req, "arg0"); + if (name == NULL) { + gctl_error(req, "No 'arg0' argument"); + return; + } + if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) + name += strlen(_PATH_DEV); + + pp = g_provider_by_name(name); + if (pp == NULL) { + gctl_error(req, "Provider %s is invalid", name); + return; + } + LIST_FOREACH(gp, &mp->geom, geom) { + if (found) + break; + sc = gp->softc; + if (sc == NULL || sc->sc_stopping) + continue; + LIST_FOREACH(cp, &gp->consumer, consumer) { + if (cp->provider == pp) { + sbuf_printf(sb, "%s\n", gp->name); + found = true; + break; + } + } + } + + sbuf_finish(sb); + gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); + sbuf_delete(sb); + +} + static void g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb) { @@ -1523,6 +1571,8 @@ g_multipath_ctl_rotate(req, mp); } else if (strcmp(verb, "getactive") == 0) { g_multipath_ctl_getactive(req, mp); + } else if (strcmp(verb, "which") == 0) { + g_multipath_ctl_which(req, mp); } else { gctl_error(req, "Unknown verb %s", verb); } diff --git a/tests/sys/geom/class/multipath/misc.sh b/tests/sys/geom/class/multipath/misc.sh --- a/tests/sys/geom/class/multipath/misc.sh +++ b/tests/sys/geom/class/multipath/misc.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (c) 2019 Axcient +# Copyright (c) 2022 Axcient # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -346,6 +346,32 @@ { common_cleanup } +atf_test_case which cleanup +which_head() +{ + atf_set "descr" "Get multipath device from provider" + atf_set "require.user" "root" + +} +which_body() +{ + load_gmultipath + + md0=$(alloc_md) + md1=$(alloc_md) + name=$(mkname) + + atf_check -s exit:0 gmultipath create "$name" ${md0} ${md1} + atf_check -s exit:0 -o "match:$name" gmultipath which "${md0}" + atf_check -s exit:0 -o "match:$name" gmultipath which "/dev/${md0}" + + +} +which_cleanup() +{ + common_cleanup +} + atf_init_test_cases() { @@ -360,4 +386,5 @@ atf_add_test_case restore atf_add_test_case restore_on_error atf_add_test_case rotate + atf_add_test_case which }