]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/geom/vinum/geom_vinum_rename.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / geom / vinum / geom_vinum_rename.c
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 }