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 strncpy(d->hdr->label.name, newname, GV_MAXDRIVENAME);
146
147 /* XXX can we rename providers here? */
148
149 LIST_FOREACH(s, &d->subdisks, from_drive)
150 strncpy(s->drive, d->name, GV_MAXDRIVENAME);
151
152 return (0);
153 }
154
155 static int
156 gv_rename_plex(struct gv_softc *sc, struct gctl_req *req, struct gv_plex *p, char *newname, int flags)
157 {
158 struct gv_sd *s;
159 char *plexnum, *plexnump, *oldplex, *oldplexp;
160 char *newsd, *oldsd, *oldsdp;
161 int err;
162
163 g_topology_assert();
164 KASSERT(p != NULL, ("gv_rename_plex: NULL p"));
165
166 err = 0;
167
168 if (gv_object_type(sc, newname) != -1) {
169 gctl_error(req, "plex name '%s' already in use", newname);
170 return (-1);
171 }
172
173 /* Needed for sanity checking. */
174 plexnum = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO);
175 strncpy(plexnum, newname, GV_MAXPLEXNAME);
176 plexnump = plexnum;
177
178 oldplex = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO);
179 strncpy(oldplex, p->name, GV_MAXPLEXNAME);
180 oldplexp = oldplex;
181
182 /*
183 * Locate the plex number part of the plex names.
184 *
185 * XXX: can we be sure that the current plex name has the format
186 * 'foo.pX'?
187 */
188 strsep(&oldplexp, ".");
189 strsep(&plexnump, ".");
190 if (plexnump == NULL || *plexnump == '\0') {
191 gctl_error(req, "proposed plex name '%s' is not a valid plex "
192 "name", newname);
193 err = -1;
194 goto failure;
195 }
196 if (strcmp(oldplexp, plexnump)) {
197 gctl_error(req, "current and proposed plex numbers (%s, %s) "
198 "do not match", plexnump, oldplexp);
199 err = -1;
200 goto failure;
201 }
202
203 strncpy(p->name, newname, GV_MAXPLEXNAME);
204
205 /* XXX can we rename providers here? */
206
207 /* Fix up references and potentially rename subdisks. */
208 LIST_FOREACH(s, &p->subdisks, in_plex) {
209 strncpy(s->plex, p->name, GV_MAXPLEXNAME);
210 if (flags && GV_FLAG_R) {
211 newsd = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO);
212 oldsd = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO);
213 oldsdp = oldsd;
214 strncpy(oldsd, s->name, GV_MAXSDNAME);
215 /*
216 * XXX: can we be sure that the current sd name has the
217 * format 'foo.pX.sY'?
218 */
219 strsep(&oldsdp, ".");
220 strsep(&oldsdp, ".");
221 snprintf(newsd, GV_MAXSDNAME, "%s.%s", p->name, oldsdp);
222 err = gv_rename_sd(sc, req, s, newsd, flags);
223 g_free(newsd);
224 g_free(oldsd);
225 if (err)
226 goto failure;
227 }
228 }
229
230 failure:
231 g_free(plexnum);
232 g_free(oldplex);
233
234 return (err);
235 }
236
237 /*
238 * gv_rename_sd: renames a subdisk. Note that the 'flags' argument is ignored,
239 * since there are no structures below a subdisk. Similarly, we don't have to
240 * clean up any references elsewhere to the subdisk's name.
241 */
242 static int
243 gv_rename_sd(struct gv_softc *sc, struct gctl_req *req, struct gv_sd *s, char * newname, int flags)
244 {
245 char *new, *newp, *old, *oldp;
246 int err;
247
248 g_topology_assert();
249 KASSERT(s != NULL, ("gv_rename_sd: NULL s"));
250
251 err = 0;
252
253 if (gv_object_type(sc, newname) != -1) {
254 gctl_error(req, "subdisk name %s already in use", newname);
255 return (-1);
256 }
257
258 /* Needed for sanity checking. */
259 new = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO);
260 strncpy(new, newname, GV_MAXSDNAME);
261 newp = new;
262
263 old = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO);
264 strncpy(old, s->name, GV_MAXSDNAME);
265 oldp = old;
266
267 /*
268 * Locate the sd number part of the sd names.
269 *
270 * XXX: can we be sure that the current sd name has the format
271 * 'foo.pX.sY'?
272 */
273 strsep(&oldp, ".");
274 strsep(&oldp, ".");
275 strsep(&newp, ".");
276 if (newp == NULL || *newp == '\0') {
277 gctl_error(req, "proposed sd name '%s' is not a valid sd name",
278 newname);
279 err = -1;
280 goto fail;
281 }
282 strsep(&newp, ".");
283 if (newp == NULL || *newp == '\0') {
284 gctl_error(req, "proposed sd name '%s' is not a valid sd name",
285 newname);
286 err = -1;
287 goto fail;
288 }
289 if (strcmp(newp, oldp)) {
290 gctl_error(req, "current and proposed sd numbers (%s, %s) do "
291 "not match", oldp, newp);
292 err = -1;
293 goto fail;
294 }
295
296 strncpy(s->name, newname, GV_MAXSDNAME);
297
298 /* XXX: can we rename providers here? */
299
300 fail:
301 g_free(new);
302 g_free(old);
303
304 return (err);
305 }
306
307 static int
308 gv_rename_vol(struct gv_softc *sc, struct gctl_req *req, struct gv_volume *v, char *newname, int flags)
309 {
310 struct gv_plex *p;
311 char *new, *old, *oldp;
312 int err;
313
314 g_topology_assert();
315 KASSERT(v != NULL, ("gv_rename_vol: NULL v"));
316
317 if (gv_object_type(sc, newname) != -1) {
318 gctl_error(req, "volume name %s already in use", newname);
319 return (-1);
320 }
321
322 /* Rename the volume. */
323 strncpy(v->name, newname, GV_MAXVOLNAME);
324
325 /* Fix up references and potentially rename plexes. */
326 LIST_FOREACH(p, &v->plexes, in_volume) {
327 strncpy(p->volume, v->name, GV_MAXVOLNAME);
328 if (flags && GV_FLAG_R) {
329 new = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO);
330 old = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO);
331 oldp = old;
332 strncpy(old, p->name, GV_MAXPLEXNAME);
333 /*
334 * XXX: can we be sure that the current plex name has
335 * the format 'foo.pX'?
336 */
337 strsep(&oldp, ".");
338 snprintf(new, GV_MAXPLEXNAME, "%s.%s", v->name, oldp);
339 err = gv_rename_plex(sc, req, p, new, flags);
340 g_free(new);
341 g_free(old);
342 if (err)
343 return (err);
344 }
345 }
346
347 return (0);
348 }
Cache object: 27b2863894288b60ef211285a1e96bd6
|