1 /*- 2 * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/module.h> 34 #include <sys/lock.h> 35 #include <sys/mutex.h> 36 #include <sys/bio.h> 37 #include <sys/sysctl.h> 38 #include <sys/malloc.h> 39 #include <geom/geom.h> 40 #include <geom/geom_slice.h> 41 #include <geom/label/g_label.h> 42 43 44 SYSCTL_DECL(_kern_geom); 45 SYSCTL_NODE(_kern_geom, OID_AUTO, label, CTLFLAG_RW, 0, "GEOM_LABEL stuff"); 46 u_int g_label_debug = 0; 47 SYSCTL_UINT(_kern_geom_label, OID_AUTO, debug, CTLFLAG_RW, &g_label_debug, 0, 48 "Debug level"); 49 50 static int g_label_destroy(struct g_geom *gp, boolean_t force); 51 static struct g_geom *g_label_taste(struct g_class *mp, struct g_provider *pp, 52 int flags __unused); 53 static void g_label_config(struct gctl_req *req, struct g_class *mp, 54 const char *verb); 55 56 struct g_class g_label_class = { 57 .name = G_LABEL_CLASS_NAME, 58 .ctlreq = g_label_config, 59 .taste = g_label_taste 60 }; 61 62 /* 63 * To add a new file system where you want to look for volume labels, 64 * you have to: 65 * 1. Add a file which implements looking for volume labels. 66 * 2. Add an 'extern const struct g_label_desc g_label_<your file system>;'. 67 * 3. Add an element to the table below '&g_label_<your_file_system>,'. 68 */ 69 const struct g_label_desc *g_labels[] = { 70 &g_label_ufs, 71 &g_label_iso9660, 72 &g_label_msdosfs, 73 NULL 74 }; 75 76 77 static void 78 g_label_orphan(struct g_consumer *cp __unused) 79 { 80 81 KASSERT(1 == 0, ("%s called?", __func__)); 82 } 83 84 static void 85 g_label_start(struct bio *bp __unused) 86 { 87 88 KASSERT(1 == 0, ("%s called?", __func__)); 89 } 90 91 static int 92 g_label_access(struct g_provider *pp __unused, int dr __unused, int dw __unused, 93 int de __unused) 94 { 95 96 KASSERT(1 == 0, ("%s called", __func__)); 97 return (EOPNOTSUPP); 98 } 99 100 static struct g_geom * 101 g_label_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, 102 const char *label, const char *dir, off_t mediasize) 103 { 104 struct g_geom *gp; 105 struct g_provider *pp2; 106 struct g_consumer *cp; 107 char name[64]; 108 109 g_topology_assert(); 110 111 gp = NULL; 112 cp = NULL; 113 snprintf(name, sizeof(name), "%s/%s", dir, label); 114 LIST_FOREACH(gp, &mp->geom, geom) { 115 pp2 = LIST_FIRST(&gp->provider); 116 if (pp2 == NULL) 117 continue; 118 if (strcmp(pp2->name, name) == 0) { 119 G_LABEL_DEBUG(1, "Label %s(%s) already exists (%s).", 120 label, name, pp->name); 121 if (req != NULL) { 122 gctl_error(req, "Provider %s already exists.", 123 name); 124 } 125 return (NULL); 126 } 127 } 128 gp = g_slice_new(mp, 1, pp, &cp, NULL, 0, NULL); 129 if (gp == NULL) { 130 G_LABEL_DEBUG(0, "Cannot create slice %s.", label); 131 if (req != NULL) 132 gctl_error(req, "Cannot create slice %s.", label); 133 return (NULL); 134 } 135 g_access(cp, -1, 0, 0); 136 g_slice_config(gp, 0, G_SLICE_CONFIG_SET, (off_t)0, mediasize, 137 pp->sectorsize, name); 138 G_LABEL_DEBUG(0, "Label for provider %s is %s.", pp->name, name); 139 return (gp); 140 } 141 142 static int 143 g_label_destroy(struct g_geom *gp, boolean_t force) 144 { 145 struct g_provider *pp; 146 147 g_topology_assert(); 148 pp = LIST_FIRST(&gp->provider); 149 if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 150 if (force) { 151 G_LABEL_DEBUG(0, "Provider %s is still open, so it " 152 "can't be definitely removed.", pp->name); 153 } else { 154 G_LABEL_DEBUG(1, 155 "Provider %s is still open (r%dw%de%d).", pp->name, 156 pp->acr, pp->acw, pp->ace); 157 return (EBUSY); 158 } 159 } else { 160 G_LABEL_DEBUG(0, "Label %s removed.", 161 LIST_FIRST(&gp->provider)->name); 162 } 163 g_slice_spoiled(LIST_FIRST(&gp->consumer)); 164 return (0); 165 } 166 167 static int 168 g_label_read_metadata(struct g_consumer *cp, struct g_label_metadata *md) 169 { 170 struct g_provider *pp; 171 u_char *buf; 172 int error; 173 174 g_topology_assert(); 175 176 pp = cp->provider; 177 g_topology_unlock(); 178 buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, 179 &error); 180 g_topology_lock(); 181 if (buf == NULL) 182 return (error); 183 /* Decode metadata. */ 184 label_metadata_decode(buf, md); 185 g_free(buf); 186 187 return (0); 188 } 189 190 static struct g_geom * 191 g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 192 { 193 struct g_label_metadata md; 194 struct g_consumer *cp; 195 struct g_geom *gp; 196 int error, i; 197 198 g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 199 g_topology_assert(); 200 201 G_LABEL_DEBUG(3, "Tasting %s.", pp->name); 202 203 if (strcmp(pp->geom->class->name, mp->name) == 0) 204 return (NULL); 205 206 gp = g_new_geomf(mp, "label:taste"); 207 gp->start = g_label_start; 208 gp->access = g_label_access; 209 gp->orphan = g_label_orphan; 210 cp = g_new_consumer(gp); 211 g_attach(cp, pp); 212 error = g_access(cp, 1, 0, 0); 213 if (error != 0) 214 return (NULL); 215 216 do { 217 error = g_label_read_metadata(cp, &md); 218 if (error != 0) 219 break; 220 if (strcmp(md.md_magic, G_LABEL_MAGIC) != 0) 221 break; 222 if (md.md_version > G_LABEL_VERSION) { 223 printf("geom_label.ko module is too old to handle %s.\n", 224 pp->name); 225 break; 226 } 227 g_label_create(NULL, mp, pp, md.md_label, G_LABEL_DIR, 228 pp->mediasize - pp->sectorsize); 229 } while (0); 230 for (i = 0; g_labels[i] != NULL; i++) { 231 char label[64]; 232 233 g_topology_unlock(); 234 g_labels[i]->ld_taste(cp, label, sizeof(label)); 235 g_topology_lock(); 236 if (label[0] == '\0') 237 continue; 238 g_label_create(NULL, mp, pp, label, g_labels[i]->ld_dir, 239 pp->mediasize); 240 } 241 242 g_access(cp, -1, 0, 0); 243 g_wither_geom(gp, ENXIO); 244 245 return (NULL); 246 } 247 248 static void 249 g_label_ctl_create(struct gctl_req *req, struct g_class *mp) 250 { 251 struct g_provider *pp; 252 const char *name; 253 int *nargs; 254 255 g_topology_assert(); 256 257 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 258 if (nargs == NULL) { 259 gctl_error(req, "No '%s' argument", "nargs"); 260 return; 261 } 262 if (*nargs != 2) { 263 gctl_error(req, "Invalid number of argument."); 264 return; 265 } 266 /* 267 * arg1 is the name of provider. 268 */ 269 name = gctl_get_asciiparam(req, "arg1"); 270 if (name == NULL) { 271 gctl_error(req, "No 'arg%d' argument", 1); 272 return; 273 } 274 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 275 name += strlen("/dev/"); 276 pp = g_provider_by_name(name); 277 if (pp == NULL) { 278 G_LABEL_DEBUG(1, "Provider %s is invalid.", name); 279 gctl_error(req, "Provider %s is invalid.", name); 280 return; 281 } 282 /* 283 * arg0 is the label. 284 */ 285 name = gctl_get_asciiparam(req, "arg0"); 286 if (name == NULL) { 287 gctl_error(req, "No 'arg%d' argument", 0); 288 return; 289 } 290 g_label_create(req, mp, pp, name, G_LABEL_DIR, pp->mediasize); 291 } 292 293 static const char * 294 g_label_skip_dir(const char *name) 295 { 296 char path[64]; 297 u_int i; 298 299 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 300 name += strlen("/dev/"); 301 if (strncmp(name, G_LABEL_DIR "/", strlen(G_LABEL_DIR "/")) == 0) 302 name += strlen(G_LABEL_DIR "/"); 303 for (i = 0; g_labels[i] != NULL; i++) { 304 snprintf(path, sizeof(path), "%s/", g_labels[i]->ld_dir); 305 if (strncmp(name, path, strlen(path)) == 0) { 306 name += strlen(path); 307 break; 308 } 309 } 310 return (name); 311 } 312 313 static struct g_geom * 314 g_label_find_geom(struct g_class *mp, const char *name) 315 { 316 struct g_geom *gp; 317 struct g_provider *pp; 318 const char *pname; 319 320 name = g_label_skip_dir(name); 321 LIST_FOREACH(gp, &mp->geom, geom) { 322 pp = LIST_FIRST(&gp->provider); 323 pname = g_label_skip_dir(pp->name); 324 if (strcmp(pname, name) == 0) 325 return (gp); 326 } 327 return (NULL); 328 } 329 330 static void 331 g_label_ctl_destroy(struct gctl_req *req, struct g_class *mp) 332 { 333 int *nargs, *force, error, i; 334 struct g_geom *gp; 335 const char *name; 336 char param[16]; 337 338 g_topology_assert(); 339 340 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 341 if (nargs == NULL) { 342 gctl_error(req, "No '%s' argument", "nargs"); 343 return; 344 } 345 if (*nargs <= 0) { 346 gctl_error(req, "Missing device(s)."); 347 return; 348 } 349 force = gctl_get_paraml(req, "force", sizeof(*force)); 350 if (force == NULL) { 351 gctl_error(req, "No 'force' argument"); 352 return; 353 } 354 355 for (i = 0; i < *nargs; i++) { 356 snprintf(param, sizeof(param), "arg%d", i); 357 name = gctl_get_asciiparam(req, param); 358 if (name == NULL) { 359 gctl_error(req, "No 'arg%d' argument", i); 360 return; 361 } 362 gp = g_label_find_geom(mp, name); 363 if (gp == NULL) { 364 G_LABEL_DEBUG(1, "Label %s is invalid.", name); 365 gctl_error(req, "Label %s is invalid.", name); 366 return; 367 } 368 error = g_label_destroy(gp, *force); 369 if (error != 0) { 370 gctl_error(req, "Cannot destroy label %s (error=%d).", 371 LIST_FIRST(&gp->provider)->name, error); 372 return; 373 } 374 } 375 } 376 377 static void 378 g_label_config(struct gctl_req *req, struct g_class *mp, const char *verb) 379 { 380 uint32_t *version; 381 382 g_topology_assert(); 383 384 version = gctl_get_paraml(req, "version", sizeof(*version)); 385 if (version == NULL) { 386 gctl_error(req, "No '%s' argument.", "version"); 387 return; 388 } 389 if (*version != G_LABEL_VERSION) { 390 gctl_error(req, "Userland and kernel parts are out of sync."); 391 return; 392 } 393 394 if (strcmp(verb, "create") == 0) { 395 g_label_ctl_create(req, mp); 396 return; 397 } else if (strcmp(verb, "destroy") == 0) { 398 g_label_ctl_destroy(req, mp); 399 return; 400 } 401 402 gctl_error(req, "Unknown verb."); 403 } 404 405 DECLARE_GEOM_CLASS(g_label_class, g_label); 406