xref: /freebsd/sys/geom/vinum/geom_vinum_rename.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
1 /*-
2  *  Copyright (c) 2005 Chris Jones
3  *  All rights reserved.
4  *
5  * This software was developed for the FreeBSD Project by Chris Jones
6  * thanks to the support of Google's Summer of Code program and
7  * mentoring by Lukas Ertl.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/libkern.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 
40 #include <geom/geom.h>
41 #include <geom/vinum/geom_vinum_var.h>
42 #include <geom/vinum/geom_vinum.h>
43 #include <geom/vinum/geom_vinum_share.h>
44 
45 static int	gv_rename_drive(struct gv_softc *, struct gctl_req *,
46 		    struct gv_drive *, char *, int);
47 static int	gv_rename_plex(struct gv_softc *, struct gctl_req *,
48 		    struct gv_plex *, char *, int);
49 static int	gv_rename_sd(struct gv_softc *, struct gctl_req *,
50 		    struct gv_sd *, char *, int);
51 static int	gv_rename_vol(struct gv_softc *, struct gctl_req *,
52 		    struct gv_volume *, char *, int);
53 
54 void
55 gv_rename(struct g_geom *gp, struct gctl_req *req)
56 {
57 	struct gv_softc *sc;
58 	struct gv_volume *v;
59 	struct gv_plex *p;
60 	struct gv_sd *s;
61 	struct gv_drive *d;
62 	char *newname, *object;
63 	int err, *flags, type;
64 
65 	sc = gp->softc;
66 
67 	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
68 
69 	newname = gctl_get_param(req, "newname", NULL);
70 	if (newname == NULL) {
71 		gctl_error(req, "no new name given");
72 		return;
73 	}
74 
75 	object = gctl_get_param(req, "object", NULL);
76 	if (object == NULL) {
77 		gctl_error(req, "no object given");
78 		return;
79 	}
80 
81 	type = gv_object_type(sc, object);
82 	switch (type) {
83 	case GV_TYPE_VOL:
84 		v = gv_find_vol(sc, object);
85 		if (v == NULL) 	{
86 			gctl_error(req, "unknown volume '%s'", object);
87 			return;
88 		}
89 		err = gv_rename_vol(sc, req, v, newname, *flags);
90 		if (err)
91 			return;
92 		break;
93 	case GV_TYPE_PLEX:
94 		p = gv_find_plex(sc, object);
95 		if (p == NULL) {
96 			gctl_error(req, "unknown plex '%s'", object);
97 			return;
98 		}
99 		err = gv_rename_plex(sc, req, p, newname, *flags);
100 		if (err)
101 			return;
102 		break;
103 	case GV_TYPE_SD:
104 		s = gv_find_sd(sc, object);
105 		if (s == NULL) {
106 			gctl_error(req, "unknown subdisk '%s'", object);
107 			return;
108 		}
109 		err = gv_rename_sd(sc, req, s, newname, *flags);
110 		if (err)
111 			return;
112 		break;
113 	case GV_TYPE_DRIVE:
114 		d = gv_find_drive(sc, object);
115 		if (d == NULL) {
116 			gctl_error(req, "unknown drive '%s'", object);
117 			return;
118 		}
119 		err = gv_rename_drive(sc, req, d, newname, *flags);
120 		if (err)
121 			return;
122 		break;
123 	default:
124 		gctl_error(req, "unknown object '%s'", object);
125 		return;
126 	}
127 
128 	gv_save_config_all(sc);
129 }
130 
131 static int
132 gv_rename_drive(struct gv_softc *sc, struct gctl_req *req, struct gv_drive *d, char *newname, int flags)
133 {
134 	struct gv_sd *s;
135 
136 	g_topology_assert();
137 	KASSERT(d != NULL, ("gv_rename_drive: NULL d"));
138 
139 	if (gv_object_type(sc, newname) != -1) {
140 		gctl_error(req, "drive name '%s' already in use", newname);
141 		return (-1);
142 	}
143 
144 	strncpy(d->name, newname, GV_MAXDRIVENAME);
145 
146 	/* XXX can we rename providers here? */
147 
148 	LIST_FOREACH(s, &d->subdisks, from_drive)
149 		strncpy(s->drive, d->name, GV_MAXDRIVENAME);
150 
151 	return (0);
152 }
153 
154 static int
155 gv_rename_plex(struct gv_softc *sc, struct gctl_req *req, struct gv_plex *p, char *newname, int flags)
156 {
157 	struct gv_sd *s;
158 	char *plexnum, *plexnump, *oldplex, *oldplexp;
159 	char *newsd, *oldsd, *oldsdp;
160 	int err;
161 
162 	g_topology_assert();
163 	KASSERT(p != NULL, ("gv_rename_plex: NULL p"));
164 
165 	err = 0;
166 
167 	if (gv_object_type(sc, newname) != -1) {
168 		gctl_error(req, "plex name '%s' already in use", newname);
169 		return (-1);
170 	}
171 
172 	/* Needed for sanity checking. */
173 	plexnum = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO);
174 	strncpy(plexnum, newname, GV_MAXPLEXNAME);
175 	plexnump = plexnum;
176 
177 	oldplex = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO);
178 	strncpy(oldplex, p->name, GV_MAXPLEXNAME);
179 	oldplexp = oldplex;
180 
181 	/*
182 	 * Locate the plex number part of the plex names.
183 	 *
184 	 * XXX: can we be sure that the current plex name has the format
185 	 * 'foo.pX'?
186 	 */
187 	strsep(&oldplexp, ".");
188 	strsep(&plexnump, ".");
189 	if (plexnump == NULL || *plexnump == '\0') {
190 		gctl_error(req, "proposed plex name '%s' is not a valid plex "
191 		    "name", newname);
192 		err = -1;
193 		goto failure;
194 	}
195 	if (strcmp(oldplexp, plexnump)) {
196 		gctl_error(req, "current and proposed plex numbers (%s, %s) "
197 		    "do not match", plexnump, oldplexp);
198 		err = -1;
199 		goto failure;
200 	}
201 
202 	strncpy(p->name, newname, GV_MAXPLEXNAME);
203 
204 	/* XXX can we rename providers here? */
205 
206 	/* Fix up references and potentially rename subdisks. */
207 	LIST_FOREACH(s, &p->subdisks, in_plex) {
208 		strncpy(s->plex, p->name, GV_MAXPLEXNAME);
209 		if (flags && GV_FLAG_R) {
210 			newsd = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO);
211 			oldsd = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO);
212 			oldsdp = oldsd;
213 			strncpy(oldsd, s->name, GV_MAXSDNAME);
214 			/*
215 			 * XXX: can we be sure that the current sd name has the
216 			 * format 'foo.pX.sY'?
217 			 */
218 			strsep(&oldsdp, ".");
219 			strsep(&oldsdp, ".");
220 			snprintf(newsd, GV_MAXSDNAME, "%s.%s", p->name, oldsdp);
221 			err = gv_rename_sd(sc, req, s, newsd, flags);
222 			g_free(newsd);
223 			g_free(oldsd);
224 			if (err)
225 				goto failure;
226 		}
227 	}
228 
229 failure:
230 	g_free(plexnum);
231 	g_free(oldplex);
232 
233 	return (err);
234 }
235 
236 /*
237  * gv_rename_sd: renames a subdisk.  Note that the 'flags' argument is ignored,
238  * since there are no structures below a subdisk.  Similarly, we don't have to
239  * clean up any references elsewhere to the subdisk's name.
240  */
241 static int
242 gv_rename_sd(struct gv_softc *sc, struct gctl_req *req, struct gv_sd *s, char * newname, int flags)
243 {
244 	char *new, *newp, *old, *oldp;
245 	int err;
246 
247 	g_topology_assert();
248 	KASSERT(s != NULL, ("gv_rename_sd: NULL s"));
249 
250 	err = 0;
251 
252 	if (gv_object_type(sc, newname) != -1) {
253 		gctl_error(req, "subdisk name %s already in use", newname);
254 		return (-1);
255 	}
256 
257 	/* Needed for sanity checking. */
258 	new = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO);
259 	strncpy(new, newname, GV_MAXSDNAME);
260 	newp = new;
261 
262 	old = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO);
263 	strncpy(old, s->name, GV_MAXSDNAME);
264 	oldp = old;
265 
266 	/*
267 	 * Locate the sd number part of the sd names.
268 	 *
269 	 * XXX: can we be sure that the current sd name has the format
270 	 * 'foo.pX.sY'?
271 	 */
272 	strsep(&oldp, ".");
273 	strsep(&oldp, ".");
274 	strsep(&newp, ".");
275 	if (newp == NULL || *newp == '\0') {
276 		gctl_error(req, "proposed sd name '%s' is not a valid sd name",
277 		    newname);
278 		err = -1;
279 		goto fail;
280 	}
281 	strsep(&newp, ".");
282 	if (newp == NULL || *newp == '\0') {
283 		gctl_error(req, "proposed sd name '%s' is not a valid sd name",
284 		    newname);
285 		err = -1;
286 		goto fail;
287 	}
288 	if (strcmp(newp, oldp)) {
289 		gctl_error(req, "current and proposed sd numbers (%s, %s) do "
290 		    "not match", oldp, newp);
291 		err = -1;
292 		goto fail;
293 	}
294 
295 	strncpy(s->name, newname, GV_MAXSDNAME);
296 
297 	/* XXX: can we rename providers here? */
298 
299 fail:
300 	g_free(new);
301 	g_free(old);
302 
303 	return (err);
304 }
305 
306 static int
307 gv_rename_vol(struct gv_softc *sc, struct gctl_req *req, struct gv_volume *v, char *newname, int flags)
308 {
309 	struct gv_plex *p;
310 	char *new, *old, *oldp;
311 	int err;
312 
313 	g_topology_assert();
314 	KASSERT(v != NULL, ("gv_rename_vol: NULL v"));
315 
316 	if (gv_object_type(sc, newname) != -1) {
317 		gctl_error(req, "volume name %s already in use", newname);
318 		return (-1);
319 	}
320 
321 	/* Rename the volume. */
322 	strncpy(v->name, newname, GV_MAXVOLNAME);
323 
324 	/* Fix up references and potentially rename plexes. */
325 	LIST_FOREACH(p, &v->plexes, in_volume) {
326 		strncpy(p->volume, v->name, GV_MAXVOLNAME);
327 		if (flags && GV_FLAG_R) {
328 			new = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO);
329 			old = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO);
330 			oldp = old;
331 			strncpy(old, p->name, GV_MAXPLEXNAME);
332 			/*
333 			 * XXX: can we be sure that the current plex name has
334 			 * the format 'foo.pX'?
335 			 */
336 			strsep(&oldp, ".");
337 			snprintf(new, GV_MAXPLEXNAME, "%s.%s", v->name, oldp);
338 			err = gv_rename_plex(sc, req, p, new, flags);
339 			g_free(new);
340 			g_free(old);
341 			if (err)
342 				return (err);
343 		}
344 	}
345 
346 	return (0);
347 }
348