1152615Sle/*- 2152615Sle * Copyright (c) 2005 Chris Jones 3152615Sle * All rights reserved. 4152632Sle * 5152632Sle * This software was developed for the FreeBSD Project by Chris Jones 6152632Sle * thanks to the support of Google's Summer of Code program and 7152632Sle * mentoring by Lukas Ertl. 8152632Sle * 9152615Sle * Redistribution and use in source and binary forms, with or without 10152615Sle * modification, are permitted provided that the following conditions 11152615Sle * are met: 12152615Sle * 1. Redistributions of source code must retain the above copyright 13152615Sle * notice, this list of conditions and the following disclaimer. 14152615Sle * 2. Redistributions in binary form must reproduce the above copyright 15152615Sle * notice, this list of conditions and the following disclaimer in the 16152615Sle * documentation and/or other materials provided with the distribution. 17152632Sle * 18152615Sle * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19152615Sle * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20152615Sle * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21152615Sle * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22152615Sle * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23152615Sle * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24152615Sle * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25152615Sle * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26152615Sle * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27152615Sle * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28152615Sle * SUCH DAMAGE. 29152615Sle * 30152615Sle */ 31152615Sle 32152615Sle#include <sys/cdefs.h> 33152615Sle__FBSDID("$FreeBSD$"); 34152615Sle 35152615Sle#include <sys/libkern.h> 36152615Sle#include <sys/malloc.h> 37152615Sle 38152615Sle#include <geom/geom.h> 39152615Sle#include <geom/vinum/geom_vinum_var.h> 40152615Sle#include <geom/vinum/geom_vinum.h> 41152615Sle 42152615Slevoid 43152615Slegv_move(struct g_geom *gp, struct gctl_req *req) 44152615Sle{ 45152615Sle struct gv_softc *sc; 46152615Sle struct gv_sd *s; 47190507Slulf struct gv_drive *d; 48152615Sle char buf[20], *destination, *object; 49190507Slulf int *argc, *flags, i, type; 50152615Sle 51152615Sle sc = gp->softc; 52152615Sle 53152615Sle argc = gctl_get_paraml(req, "argc", sizeof(*argc)); 54185309Slulf if (argc == NULL) { 55185309Slulf gctl_error(req, "no arguments given"); 56185309Slulf return; 57185309Slulf } 58152615Sle flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 59185309Slulf if (flags == NULL) { 60185309Slulf gctl_error(req, "no flags given"); 61185309Slulf return; 62185309Slulf } 63152615Sle destination = gctl_get_param(req, "destination", NULL); 64152615Sle if (destination == NULL) { 65152615Sle gctl_error(req, "no destination given"); 66152615Sle return; 67152615Sle } 68152615Sle if (gv_object_type(sc, destination) != GV_TYPE_DRIVE) { 69152615Sle gctl_error(req, "destination '%s' is not a drive", destination); 70152615Sle return; 71152615Sle } 72190507Slulf d = gv_find_drive(sc, destination); 73152615Sle 74152615Sle /* 75152615Sle * We start with 1 here, because argv[0] on the command line is the 76152615Sle * destination drive. 77152615Sle */ 78152615Sle for (i = 1; i < *argc; i++) { 79152615Sle snprintf(buf, sizeof(buf), "argv%d", i); 80152615Sle object = gctl_get_param(req, buf, NULL); 81152615Sle if (object == NULL) 82152615Sle continue; 83152615Sle 84152615Sle type = gv_object_type(sc, object); 85152615Sle if (type != GV_TYPE_SD) { 86152615Sle gctl_error(req, "you can only move subdisks; " 87197767Slulf "'%s' is not a subdisk", object); 88152615Sle return; 89152615Sle } 90152615Sle 91152615Sle s = gv_find_sd(sc, object); 92152615Sle if (s == NULL) { 93152615Sle gctl_error(req, "unknown subdisk '%s'", object); 94152615Sle return; 95152615Sle } 96190507Slulf gv_post_event(sc, GV_EVENT_MOVE_SD, s, d, *flags, 0); 97152615Sle } 98152615Sle} 99152615Sle 100152615Sle/* Move a subdisk. */ 101190507Slulfint 102190507Slulfgv_move_sd(struct gv_softc *sc, struct gv_sd *cursd, 103190507Slulf struct gv_drive *destination, int flags) 104152615Sle{ 105152615Sle struct gv_drive *d; 106152615Sle struct gv_sd *newsd, *s, *s2; 107152615Sle struct gv_plex *p; 108152632Sle int err; 109152615Sle 110152632Sle g_topology_assert(); 111152632Sle KASSERT(cursd != NULL, ("gv_move_sd: NULL cursd")); 112190507Slulf KASSERT(destination != NULL, ("gv_move_sd: NULL destination")); 113152615Sle 114190507Slulf d = cursd->drive_sc; 115152615Sle 116190507Slulf if ((gv_consumer_is_open(d->consumer) || 117190507Slulf gv_consumer_is_open(destination->consumer)) && 118213318Slulf !(flags & GV_FLAG_F)) { 119190507Slulf G_VINUM_DEBUG(0, "consumers on current and destination drive " 120190507Slulf " still open"); 121190507Slulf return (GV_ERR_ISBUSY); 122152615Sle } 123152615Sle 124213318Slulf if (!(flags & GV_FLAG_F)) { 125190507Slulf G_VINUM_DEBUG(1, "-f flag not passed; move would be " 126152615Sle "destructive"); 127190507Slulf return (GV_ERR_INVFLAG); 128152615Sle } 129152615Sle 130190507Slulf if (destination == cursd->drive_sc) { 131190507Slulf G_VINUM_DEBUG(1, "subdisk '%s' already on drive '%s'", 132190507Slulf cursd->name, destination->name); 133190507Slulf return (GV_ERR_ISATTACHED); 134152615Sle } 135152615Sle 136152615Sle /* XXX: Does it have to be part of a plex? */ 137152615Sle p = gv_find_plex(sc, cursd->plex); 138152615Sle if (p == NULL) { 139190507Slulf G_VINUM_DEBUG(0, "subdisk '%s' is not part of a plex", 140152615Sle cursd->name); 141190507Slulf return (GV_ERR_NOTFOUND); 142152615Sle } 143190507Slulf 144152615Sle /* Stale the old subdisk. */ 145152615Sle err = gv_set_sd_state(cursd, GV_SD_STALE, 146152615Sle GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG); 147152615Sle if (err) { 148197767Slulf G_VINUM_DEBUG(0, "unable to set the subdisk '%s' to state " 149152615Sle "'stale'", cursd->name); 150152615Sle return (err); 151152615Sle } 152152615Sle 153152615Sle /* 154152615Sle * Create new subdisk. Ideally, we'd use gv_new_sd, but that requires 155152615Sle * us to create a string for it to parse, which is silly. 156152615Sle * TODO: maybe refactor gv_new_sd such that this is no longer the case. 157152615Sle */ 158152615Sle newsd = g_malloc(sizeof(struct gv_sd), M_WAITOK | M_ZERO); 159152615Sle newsd->plex_offset = cursd->plex_offset; 160152632Sle newsd->size = cursd->size; 161152615Sle newsd->drive_offset = -1; 162190507Slulf strlcpy(newsd->name, cursd->name, sizeof(newsd->name)); 163190507Slulf strlcpy(newsd->drive, destination->name, sizeof(newsd->drive)); 164190507Slulf strlcpy(newsd->plex, cursd->plex, sizeof(newsd->plex)); 165152615Sle newsd->state = GV_SD_STALE; 166152615Sle newsd->vinumconf = cursd->vinumconf; 167152615Sle 168190507Slulf err = gv_sd_to_drive(newsd, destination); 169152615Sle if (err) { 170152615Sle /* XXX not enough free space? */ 171152615Sle g_free(newsd); 172152615Sle return (err); 173152615Sle } 174152615Sle 175152615Sle /* Replace the old sd by the new one. */ 176152615Sle LIST_FOREACH_SAFE(s, &p->subdisks, in_plex, s2) { 177152615Sle if (s == cursd) { 178190507Slulf gv_rm_sd(sc, s); 179152615Sle } 180152615Sle } 181190507Slulf gv_sd_to_plex(newsd, p); 182152615Sle LIST_INSERT_HEAD(&sc->subdisks, newsd, sd); 183190507Slulf /* Update volume size of plex. */ 184190507Slulf if (p->vol_sc != NULL) 185190507Slulf gv_update_vol_size(p->vol_sc, gv_vol_size(p->vol_sc)); 186190507Slulf gv_save_config(p->vinumconf); 187152615Sle return (0); 188152615Sle} 189