Path: blob/main/lib/geom/multipath/geom_multipath.c
34862 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2006 Mathew Jacob <[email protected]>4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <sys/param.h>29#include <errno.h>30#include <paths.h>31#include <stdio.h>32#include <stdlib.h>33#include <stdint.h>34#include <string.h>35#include <strings.h>36#include <assert.h>37#include <libgeom.h>38#include <unistd.h>39#include <uuid.h>40#include <geom/multipath/g_multipath.h>4142#include "core/geom.h"43#include "misc/subr.h"4445uint32_t lib_version = G_LIB_VERSION;46uint32_t version = G_MULTIPATH_VERSION;4748static void mp_main(struct gctl_req *, unsigned int);49static void mp_label(struct gctl_req *);50static void mp_clear(struct gctl_req *);51static void mp_prefer(struct gctl_req *);5253struct g_command class_commands[] = {54{55"create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,56{57{ 'A', "active_active", NULL, G_TYPE_BOOL },58{ 'R', "active_read", NULL, G_TYPE_BOOL },59G_OPT_SENTINEL60},61"[-vAR] name prov ..."62},63{64"label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, mp_main,65{66{ 'A', "active_active", NULL, G_TYPE_BOOL },67{ 'R', "active_read", NULL, G_TYPE_BOOL },68G_OPT_SENTINEL69},70"[-vAR] name prov ..."71},72{ "configure", G_FLAG_VERBOSE, NULL,73{74{ 'A', "active_active", NULL, G_TYPE_BOOL },75{ 'P', "active_passive", NULL, G_TYPE_BOOL },76{ 'R', "active_read", NULL, G_TYPE_BOOL },77G_OPT_SENTINEL78},79"[-vAPR] name"80},81{82"add", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,83"[-v] name prov"84},85{86"remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,87"[-v] name prov"88},89{90"prefer", G_FLAG_VERBOSE, mp_main, G_NULL_OPTS,91"[-v] prov ..."92},93{94"fail", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,95"[-v] name prov"96},97{98"restore", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,99"[-v] name prov"100},101{102"rotate", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,103"[-v] name"104},105{106"getactive", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,107"[-v] name"108},109{110"destroy", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,111"[-v] name"112},113{114"stop", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,115"[-v] name"116},117{118"clear", G_FLAG_VERBOSE, mp_main, G_NULL_OPTS,119"[-v] prov ..."120},121G_CMD_SENTINEL122};123124static void125mp_main(struct gctl_req *req, unsigned int flags __unused)126{127const char *name;128129name = gctl_get_ascii(req, "verb");130if (name == NULL) {131gctl_error(req, "No '%s' argument.", "verb");132return;133}134if (strcmp(name, "label") == 0) {135mp_label(req);136} else if (strcmp(name, "clear") == 0) {137mp_clear(req);138} else if (strcmp(name, "prefer") == 0) {139mp_prefer(req);140} else {141gctl_error(req, "Unknown command: %s.", name);142}143}144145static void146mp_label(struct gctl_req *req)147{148struct g_multipath_metadata md;149off_t disksize = 0, msize;150uint8_t *sector, *rsector;151char *ptr;152uuid_t uuid;153ssize_t secsize = 0, ssize;154uint32_t status;155const char *name, *name2, *mpname;156int error, i, nargs, fd;157158nargs = gctl_get_int(req, "nargs");159if (nargs < 2) {160gctl_error(req, "wrong number of arguments.");161return;162}163164/*165* First, check each provider to make sure it's the same size.166* This also gets us our size and sectorsize for the metadata.167*/168for (i = 1; i < nargs; i++) {169name = gctl_get_ascii(req, "arg%d", i);170msize = g_get_mediasize(name);171ssize = g_get_sectorsize(name);172if (msize == 0 || ssize == 0) {173gctl_error(req, "cannot get information about %s: %s.",174name, strerror(errno));175return;176}177if (i == 1) {178secsize = ssize;179disksize = msize;180} else {181if (secsize != ssize) {182gctl_error(req, "%s sector size %ju different.",183name, (intmax_t)ssize);184return;185}186if (disksize != msize) {187gctl_error(req, "%s media size %ju different.",188name, (intmax_t)msize);189return;190}191}192193}194195/*196* Generate metadata.197*/198strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));199md.md_version = G_MULTIPATH_VERSION;200mpname = gctl_get_ascii(req, "arg0");201strlcpy(md.md_name, mpname, sizeof(md.md_name));202md.md_size = disksize;203md.md_sectorsize = secsize;204uuid_create(&uuid, &status);205if (status != uuid_s_ok) {206gctl_error(req, "cannot create a UUID.");207return;208}209uuid_to_string(&uuid, &ptr, &status);210if (status != uuid_s_ok) {211gctl_error(req, "cannot stringify a UUID.");212return;213}214strlcpy(md.md_uuid, ptr, sizeof (md.md_uuid));215md.md_active_active = gctl_get_int(req, "active_active");216if (gctl_get_int(req, "active_read"))217md.md_active_active = 2;218free(ptr);219220/*221* Allocate a sector to write as metadata.222*/223sector = calloc(1, secsize);224if (sector == NULL) {225gctl_error(req, "unable to allocate metadata buffer");226return;227}228rsector = malloc(secsize);229if (rsector == NULL) {230gctl_error(req, "unable to allocate metadata buffer");231goto done;232}233234/*235* encode the metadata236*/237multipath_metadata_encode(&md, sector);238239/*240* Store metadata on the initial provider.241*/242name = gctl_get_ascii(req, "arg1");243error = g_metadata_store(name, sector, secsize);244if (error != 0) {245gctl_error(req, "cannot store metadata on %s: %s.", name, strerror(error));246goto done;247}248249/*250* Now touch the rest of the providers to hint retaste.251*/252for (i = 2; i < nargs; i++) {253name2 = gctl_get_ascii(req, "arg%d", i);254fd = g_open(name2, 1);255if (fd < 0) {256fprintf(stderr, "Unable to open %s: %s.\n",257name2, strerror(errno));258continue;259}260if (pread(fd, rsector, secsize, disksize - secsize) !=261(ssize_t)secsize) {262fprintf(stderr, "Unable to read metadata from %s: %s.\n",263name2, strerror(errno));264g_close(fd);265continue;266}267g_close(fd);268if (memcmp(sector, rsector, secsize)) {269fprintf(stderr, "No metadata found on %s."270" It is not a path of %s.\n",271name2, name);272}273}274done:275free(rsector);276free(sector);277}278279280static void281mp_clear(struct gctl_req *req)282{283const char *name;284int error, i, nargs;285286nargs = gctl_get_int(req, "nargs");287if (nargs < 1) {288gctl_error(req, "Too few arguments.");289return;290}291292for (i = 0; i < nargs; i++) {293name = gctl_get_ascii(req, "arg%d", i);294error = g_metadata_clear(name, G_MULTIPATH_MAGIC);295if (error != 0) {296fprintf(stderr, "Can't clear metadata on %s: %s.\n",297name, strerror(error));298gctl_error(req, "Not fully done.");299continue;300}301}302}303304static void305mp_prefer(struct gctl_req *req)306{307const char *name, *comp, *errstr;308int nargs;309310nargs = gctl_get_int(req, "nargs");311if (nargs != 2) {312gctl_error(req, "Usage: prefer GEOM PROVIDER");313return;314}315name = gctl_get_ascii(req, "arg0");316comp = gctl_get_ascii(req, "arg1");317errstr = gctl_issue (req);318if (errstr != NULL) {319fprintf(stderr, "Can't set %s preferred provider to %s: %s.\n",320name, comp, errstr);321}322}323324325