1219974Smav/*- 2219974Smav * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org> 3219974Smav * All rights reserved. 4219974Smav * 5219974Smav * Redistribution and use in source and binary forms, with or without 6219974Smav * modification, are permitted provided that the following conditions 7219974Smav * are met: 8219974Smav * 1. Redistributions of source code must retain the above copyright 9219974Smav * notice, this list of conditions and the following disclaimer. 10219974Smav * 2. Redistributions in binary form must reproduce the above copyright 11219974Smav * notice, this list of conditions and the following disclaimer in the 12219974Smav * documentation and/or other materials provided with the distribution. 13219974Smav * 14219974Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15219974Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16219974Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17219974Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18219974Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19219974Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20219974Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21219974Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22219974Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23219974Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24219974Smav * SUCH DAMAGE. 25219974Smav */ 26219974Smav 27219974Smav#include <sys/cdefs.h> 28219974Smav__FBSDID("$FreeBSD$"); 29219974Smav 30219974Smav#include <sys/param.h> 31219974Smav#include <sys/systm.h> 32219974Smav#include <sys/kernel.h> 33219974Smav#include <sys/module.h> 34219974Smav#include <sys/lock.h> 35219974Smav#include <sys/mutex.h> 36219974Smav#include <sys/bio.h> 37219974Smav#include <sys/sysctl.h> 38219974Smav#include <sys/malloc.h> 39219974Smav#include <sys/bitstring.h> 40219974Smav#include <vm/uma.h> 41219974Smav#include <machine/atomic.h> 42219974Smav#include <geom/geom.h> 43219974Smav#include <sys/proc.h> 44219974Smav#include <sys/kthread.h> 45219974Smav#include <geom/raid/g_raid.h> 46219974Smav#include "g_raid_md_if.h" 47219974Smav 48219974Smav 49219974Smavstatic struct g_raid_softc * 50219974Smavg_raid_find_node(struct g_class *mp, const char *name) 51219974Smav{ 52219974Smav struct g_raid_softc *sc; 53219974Smav struct g_geom *gp; 54241329Smav struct g_provider *pp; 55241329Smav struct g_raid_volume *vol; 56219974Smav 57241329Smav /* Look for geom with specified name. */ 58219974Smav LIST_FOREACH(gp, &mp->geom, geom) { 59219974Smav sc = gp->softc; 60219974Smav if (sc == NULL) 61219974Smav continue; 62219974Smav if (sc->sc_stopping != 0) 63219974Smav continue; 64219974Smav if (strcasecmp(sc->sc_name, name) == 0) 65219974Smav return (sc); 66219974Smav } 67241329Smav 68241329Smav /* Look for provider with specified name. */ 69241329Smav LIST_FOREACH(gp, &mp->geom, geom) { 70241329Smav sc = gp->softc; 71241329Smav if (sc == NULL) 72241329Smav continue; 73241329Smav if (sc->sc_stopping != 0) 74241329Smav continue; 75241329Smav LIST_FOREACH(pp, &gp->provider, provider) { 76241329Smav if (strcmp(pp->name, name) == 0) 77241329Smav return (sc); 78241329Smav if (strncmp(pp->name, "raid/", 5) == 0 && 79241329Smav strcmp(pp->name + 5, name) == 0) 80241329Smav return (sc); 81241329Smav } 82241329Smav } 83241329Smav 84241329Smav /* Look for volume with specified name. */ 85241329Smav LIST_FOREACH(gp, &mp->geom, geom) { 86241329Smav sc = gp->softc; 87241329Smav if (sc == NULL) 88241329Smav continue; 89241329Smav if (sc->sc_stopping != 0) 90241329Smav continue; 91241329Smav TAILQ_FOREACH(vol, &sc->sc_volumes, v_next) { 92241329Smav if (strcmp(vol->v_name, name) == 0) 93241329Smav return (sc); 94241329Smav } 95241329Smav } 96219974Smav return (NULL); 97219974Smav} 98219974Smav 99219974Smavstatic void 100219974Smavg_raid_ctl_label(struct gctl_req *req, struct g_class *mp) 101219974Smav{ 102219974Smav struct g_geom *geom; 103219974Smav struct g_raid_softc *sc; 104219974Smav const char *format; 105219974Smav int *nargs; 106219974Smav int crstatus, ctlstatus; 107219974Smav char buf[64]; 108219974Smav 109219974Smav nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 110219974Smav if (nargs == NULL) { 111219974Smav gctl_error(req, "No '%s' argument.", "nargs"); 112219974Smav return; 113219974Smav } 114219974Smav if (*nargs < 4) { 115219974Smav gctl_error(req, "Invalid number of arguments."); 116219974Smav return; 117219974Smav } 118219974Smav format = gctl_get_asciiparam(req, "arg0"); 119219974Smav if (format == NULL) { 120299497Spfg gctl_error(req, "No format received."); 121219974Smav return; 122219974Smav } 123234940Smav crstatus = g_raid_create_node_format(format, req, &geom); 124219974Smav if (crstatus == G_RAID_MD_TASTE_FAIL) { 125219974Smav gctl_error(req, "Failed to create array with format '%s'.", 126219974Smav format); 127219974Smav return; 128219974Smav } 129219974Smav sc = (struct g_raid_softc *)geom->softc; 130219974Smav g_topology_unlock(); 131219974Smav sx_xlock(&sc->sc_lock); 132219974Smav ctlstatus = G_RAID_MD_CTL(sc->sc_md, req); 133219974Smav if (ctlstatus < 0) { 134219974Smav gctl_error(req, "Command failed: %d.", ctlstatus); 135219974Smav if (crstatus == G_RAID_MD_TASTE_NEW) 136219974Smav g_raid_destroy_node(sc, 0); 137219974Smav } else { 138219974Smav if (crstatus == G_RAID_MD_TASTE_NEW) 139219974Smav snprintf(buf, sizeof(buf), "%s created\n", sc->sc_name); 140219974Smav else 141219974Smav snprintf(buf, sizeof(buf), "%s reused\n", sc->sc_name); 142219974Smav gctl_set_param_err(req, "output", buf, strlen(buf) + 1); 143219974Smav } 144219974Smav sx_xunlock(&sc->sc_lock); 145219974Smav g_topology_lock(); 146219974Smav} 147219974Smav 148219974Smavstatic void 149219974Smavg_raid_ctl_stop(struct gctl_req *req, struct g_class *mp) 150219974Smav{ 151219974Smav struct g_raid_softc *sc; 152219974Smav const char *nodename; 153219974Smav int *nargs, *force; 154219974Smav int error, how; 155219974Smav 156219974Smav nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 157219974Smav if (nargs == NULL) { 158219974Smav gctl_error(req, "No '%s' argument.", "nargs"); 159219974Smav return; 160219974Smav } 161219974Smav if (*nargs != 1) { 162219974Smav gctl_error(req, "Invalid number of arguments."); 163219974Smav return; 164219974Smav } 165219974Smav nodename = gctl_get_asciiparam(req, "arg0"); 166219974Smav if (nodename == NULL) { 167299497Spfg gctl_error(req, "No array name received."); 168219974Smav return; 169219974Smav } 170219974Smav sc = g_raid_find_node(mp, nodename); 171219974Smav if (sc == NULL) { 172219974Smav gctl_error(req, "Array '%s' not found.", nodename); 173219974Smav return; 174219974Smav } 175219974Smav force = gctl_get_paraml(req, "force", sizeof(*force)); 176219974Smav if (force != NULL && *force) 177219974Smav how = G_RAID_DESTROY_HARD; 178219974Smav else 179219974Smav how = G_RAID_DESTROY_SOFT; 180219974Smav g_topology_unlock(); 181219974Smav sx_xlock(&sc->sc_lock); 182219974Smav error = g_raid_destroy(sc, how); 183219974Smav if (error != 0) 184253706Smav gctl_error(req, "Array is busy."); 185219974Smav g_topology_lock(); 186219974Smav} 187219974Smav 188219974Smavstatic void 189219974Smavg_raid_ctl_other(struct gctl_req *req, struct g_class *mp) 190219974Smav{ 191219974Smav struct g_raid_softc *sc; 192219974Smav const char *nodename; 193219974Smav int *nargs; 194219974Smav int ctlstatus; 195219974Smav 196219974Smav nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 197219974Smav if (nargs == NULL) { 198219974Smav gctl_error(req, "No '%s' argument.", "nargs"); 199219974Smav return; 200219974Smav } 201219974Smav if (*nargs < 1) { 202219974Smav gctl_error(req, "Invalid number of arguments."); 203219974Smav return; 204219974Smav } 205219974Smav nodename = gctl_get_asciiparam(req, "arg0"); 206219974Smav if (nodename == NULL) { 207299497Spfg gctl_error(req, "No array name received."); 208219974Smav return; 209219974Smav } 210219974Smav sc = g_raid_find_node(mp, nodename); 211219974Smav if (sc == NULL) { 212219974Smav gctl_error(req, "Array '%s' not found.", nodename); 213219974Smav return; 214219974Smav } 215219974Smav g_topology_unlock(); 216219974Smav sx_xlock(&sc->sc_lock); 217219974Smav if (sc->sc_md != NULL) { 218219974Smav ctlstatus = G_RAID_MD_CTL(sc->sc_md, req); 219219974Smav if (ctlstatus < 0) 220219974Smav gctl_error(req, "Command failed: %d.", ctlstatus); 221219974Smav } 222219974Smav sx_xunlock(&sc->sc_lock); 223219974Smav g_topology_lock(); 224219974Smav} 225219974Smav 226219974Smavvoid 227219974Smavg_raid_ctl(struct gctl_req *req, struct g_class *mp, const char *verb) 228219974Smav{ 229219974Smav uint32_t *version; 230219974Smav 231219974Smav g_topology_assert(); 232219974Smav 233219974Smav version = gctl_get_paraml(req, "version", sizeof(*version)); 234219974Smav if (version == NULL) { 235219974Smav gctl_error(req, "No '%s' argument.", "version"); 236219974Smav return; 237219974Smav } 238219974Smav if (*version != G_RAID_VERSION) { 239219974Smav gctl_error(req, "Userland and kernel parts are out of sync."); 240219974Smav return; 241219974Smav } 242219974Smav 243219974Smav if (strcmp(verb, "label") == 0) 244219974Smav g_raid_ctl_label(req, mp); 245219974Smav else if (strcmp(verb, "stop") == 0) 246219974Smav g_raid_ctl_stop(req, mp); 247219974Smav else 248219974Smav g_raid_ctl_other(req, mp); 249219974Smav} 250