static void stripe_clear(struct gctl_req *req) { const char *name; int error, i, nargs; nargs = gctl_get_int(req, "nargs"); if (nargs < 1) { gctl_error(req, "Too few arguments."); return; } for (i = 0; i < nargs; i++) { name = gctl_get_ascii(req, "arg%d", i); error = g_metadata_clear(name, G_STRIPE_MAGIC); if (error != 0) { fprintf(stderr, "Can't clear metadata on %s: %s.\n", name, strerror(error)); gctl_error(req, "Not fully done."); continue; } if (verbose) printf("Metadata cleared on %s.\n", name); } }
static void label_label(struct gctl_req *req) { struct g_label_metadata md; const char *name, *label; u_char sector[512]; int error, nargs; nargs = gctl_get_int(req, "nargs"); if (nargs != 2) { gctl_error(req, "Invalid number of arguments."); return; } /* * Clear last sector first to spoil all components if device exists. */ name = gctl_get_ascii(req, "arg1"); error = g_metadata_clear(name, NULL); if (error != 0) { gctl_error(req, "Can't store metadata on %s: %s.", name, strerror(error)); return; } strlcpy(md.md_magic, G_LABEL_MAGIC, sizeof(md.md_magic)); md.md_version = G_LABEL_VERSION; label = gctl_get_ascii(req, "arg0"); strlcpy(md.md_label, label, sizeof(md.md_label)); md.md_provsize = g_get_mediasize(name); if (md.md_provsize == 0) { gctl_error(req, "Can't get mediasize of %s: %s.", name, strerror(errno)); return; } /* * Ok, store metadata. */ label_metadata_encode(&md, sector); error = g_metadata_store(name, sector, sizeof(sector)); if (error != 0) { fprintf(stderr, "Can't store metadata on %s: %s.\n", name, strerror(error)); gctl_error(req, "Not done."); } if (verbose) printf("Metadata value stored on %s.\n", name); }
/* Clears metadata on given provider(s) IF it's owned by us */ static void virstor_clear(struct gctl_req *req) { const char *name; char param[32]; unsigned i; int nargs, error; int fd; nargs = gctl_get_int(req, "nargs"); if (nargs < 1) { gctl_error(req, "Too few arguments."); return; } for (i = 0; i < (unsigned)nargs; i++) { snprintf(param, sizeof(param), "arg%u", i); name = gctl_get_ascii(req, "%s", param); error = g_metadata_clear(name, G_VIRSTOR_MAGIC); if (error != 0) { fprintf(stderr, "Can't clear metadata on %s: %s " "(do I own it?)\n", name, strerror(error)); gctl_error(req, "Not fully done (can't clear metadata)."); continue; } if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) fd = open(name, O_RDWR); else { sprintf(param, "%s%s", _PATH_DEV, name); fd = open(param, O_RDWR); } if (fd < 0) { gctl_error(req, "Cannot clear header sector for %s", name); continue; } if (verbose) printf("Metadata cleared on %s.\n", name); } }
static void stripe_label(struct gctl_req *req) { struct g_stripe_metadata md; intmax_t stripesize; off_t compsize, msize; u_char sector[512]; unsigned ssize, secsize; const char *name; int error, i, nargs, hardcode; nargs = gctl_get_int(req, "nargs"); if (nargs < 3) { gctl_error(req, "Too few arguments."); return; } hardcode = gctl_get_int(req, "hardcode"); /* * Clear last sector first to spoil all components if device exists. */ compsize = 0; secsize = 0; for (i = 1; i < nargs; i++) { name = gctl_get_ascii(req, "arg%d", i); msize = g_get_mediasize(name); ssize = g_get_sectorsize(name); if (msize == 0 || ssize == 0) { gctl_error(req, "Can't get informations about %s: %s.", name, strerror(errno)); return; } msize -= ssize; if (compsize == 0 || (compsize > 0 && msize < compsize)) compsize = msize; if (secsize == 0) secsize = ssize; else secsize = g_lcm(secsize, ssize); error = g_metadata_clear(name, NULL); if (error != 0) { gctl_error(req, "Can't store metadata on %s: %s.", name, strerror(error)); return; } } strlcpy(md.md_magic, G_STRIPE_MAGIC, sizeof(md.md_magic)); md.md_version = G_STRIPE_VERSION; name = gctl_get_ascii(req, "arg0"); strlcpy(md.md_name, name, sizeof(md.md_name)); md.md_id = arc4random(); md.md_all = nargs - 1; stripesize = gctl_get_intmax(req, "stripesize"); if ((stripesize % secsize) != 0) { gctl_error(req, "Stripesize should be multiple of %u.", secsize); return; } md.md_stripesize = stripesize; /* * Ok, store metadata. */ for (i = 1; i < nargs; i++) { name = gctl_get_ascii(req, "arg%d", i); msize = g_get_mediasize(name); ssize = g_get_sectorsize(name); if (compsize < msize - ssize) { fprintf(stderr, "warning: %s: only %jd bytes from %jd bytes used.\n", name, (intmax_t)compsize, (intmax_t)(msize - ssize)); } md.md_no = i - 1; md.md_provsize = msize; if (!hardcode) bzero(md.md_provider, sizeof(md.md_provider)); else { if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) name += sizeof(_PATH_DEV) - 1; strlcpy(md.md_provider, name, sizeof(md.md_provider)); } stripe_metadata_encode(&md, sector); error = g_metadata_store(name, sector, sizeof(sector)); if (error != 0) { fprintf(stderr, "Can't store metadata on %s: %s.\n", name, strerror(error)); gctl_error(req, "Not fully done."); continue; } if (verbose) printf("Metadata value stored on %s.\n", name); } }
/* * Labels a new geom Meaning: parses and checks the parameters, calculates & * writes metadata to the relevant providers so when the next round of * "tasting" comes (which will be just after the provider(s) are closed) geom * can be instantiated with the tasted metadata. */ static void virstor_label(struct gctl_req *req) { struct g_virstor_metadata md; off_t msize; unsigned char *sect; unsigned int i; size_t ssize, secsize; const char *name; char param[32]; int hardcode, nargs, error; struct virstor_map_entry *map; size_t total_chunks; /* We'll run out of memory if this needs to be bigger. */ unsigned int map_chunks; /* Chunks needed by the map (map size). */ size_t map_size; /* In bytes. */ ssize_t written; int fd; nargs = gctl_get_int(req, "nargs"); if (nargs < 2) { gctl_error(req, "Too few arguments (%d): expecting: name " "provider0 [provider1 ...]", nargs); return; } hardcode = gctl_get_int(req, "hardcode"); /* * Initialize constant parts of metadata: magic signature, version, * name. */ bzero(&md, sizeof(md)); strlcpy(md.md_magic, G_VIRSTOR_MAGIC, sizeof(md.md_magic)); md.md_version = G_VIRSTOR_VERSION; name = gctl_get_ascii(req, "arg0"); if (name == NULL) { gctl_error(req, "No 'arg%u' argument.", 0); return; } strlcpy(md.md_name, name, sizeof(md.md_name)); md.md_virsize = (off_t)gctl_get_intmax(req, "vir_size"); md.md_chunk_size = gctl_get_intmax(req, "chunk_size"); md.md_count = nargs - 1; if (md.md_virsize == 0 || md.md_chunk_size == 0) { gctl_error(req, "Virtual size and chunk size must be non-zero"); return; } if (md.md_chunk_size % MAXPHYS != 0) { /* XXX: This is not strictly needed, but it's convenient to * impose some limitations on it, so why not MAXPHYS. */ size_t new_size = (md.md_chunk_size / MAXPHYS) * MAXPHYS; if (new_size < md.md_chunk_size) new_size += MAXPHYS; fprintf(stderr, "Resizing chunk size to be a multiple of " "MAXPHYS (%d kB).\n", MAXPHYS / 1024); fprintf(stderr, "New chunk size: %zu kB\n", new_size / 1024); md.md_chunk_size = new_size; } if (md.md_virsize % md.md_chunk_size != 0) { off_t chunk_count = md.md_virsize / md.md_chunk_size; md.md_virsize = chunk_count * md.md_chunk_size; fprintf(stderr, "Resizing virtual size to be a multiple of " "chunk size.\n"); fprintf(stderr, "New virtual size: %zu MB\n", (size_t)(md.md_virsize/(1024 * 1024))); } msize = secsize = 0; for (i = 1; i < (unsigned)nargs; i++) { snprintf(param, sizeof(param), "arg%u", i); name = gctl_get_ascii(req, "%s", param); ssize = g_get_sectorsize(name); if (ssize == 0) fprintf(stderr, "%s for %s\n", strerror(errno), name); msize += g_get_mediasize(name); if (secsize == 0) secsize = ssize; else if (secsize != ssize) { gctl_error(req, "Devices need to have same sector size " "(%u on %s needs to be %u).", (u_int)ssize, name, (u_int)secsize); return; } } if (secsize == 0) { gctl_error(req, "Device not specified"); return; } if (md.md_chunk_size % secsize != 0) { fprintf(stderr, "Error: chunk size is not a multiple of sector " "size."); gctl_error(req, "Chunk size (in bytes) must be multiple of %u.", (unsigned int)secsize); return; } total_chunks = md.md_virsize / md.md_chunk_size; map_size = total_chunks * sizeof(*map); assert(md.md_virsize % md.md_chunk_size == 0); ssize = map_size % secsize; if (ssize != 0) { size_t add_chunks = (secsize - ssize) / sizeof(*map); total_chunks += add_chunks; md.md_virsize = (off_t)total_chunks * (off_t)md.md_chunk_size; map_size = total_chunks * sizeof(*map); fprintf(stderr, "Resizing virtual size to fit virstor " "structures.\n"); fprintf(stderr, "New virtual size: %ju MB (%zu new chunks)\n", (uintmax_t)(md.md_virsize / (1024 * 1024)), add_chunks); } if (verbose) printf("Total virtual chunks: %zu (%zu MB each), %ju MB total " "virtual size.\n", total_chunks, (size_t)(md.md_chunk_size / (1024 * 1024)), md.md_virsize/(1024 * 1024)); if ((off_t)md.md_virsize < msize) fprintf(stderr, "WARNING: Virtual storage size < Physical " "available storage (%ju < %ju)\n", md.md_virsize, msize); /* Clear last sector first to spoil all components if device exists. */ if (verbose) printf("Clearing metadata on"); for (i = 1; i < (unsigned)nargs; i++) { snprintf(param, sizeof(param), "arg%u", i); name = gctl_get_ascii(req, "%s", param); if (verbose) printf(" %s", name); msize = g_get_mediasize(name); ssize = g_get_sectorsize(name); if (msize == 0 || ssize == 0) { gctl_error(req, "Can't retrieve information about " "%s: %s.", name, strerror(errno)); return; } if (msize < (off_t) MAX(md.md_chunk_size*4, map_size)) gctl_error(req, "Device %s is too small", name); error = g_metadata_clear(name, NULL); if (error != 0) { gctl_error(req, "Can't clear metadata on %s: %s.", name, strerror(error)); return; } } /* Write allocation table to the first provider - this needs to be done * before metadata is written because when kernel tastes it it's too * late */ name = gctl_get_ascii(req, "arg1"); /* device with metadata */ if (verbose) printf(".\nWriting allocation table to %s...", name); /* How many chunks does the map occupy? */ map_chunks = map_size/md.md_chunk_size; if (map_size % md.md_chunk_size != 0) map_chunks++; if (verbose) { printf(" (%zu MB, %d chunks) ", map_size/(1024*1024), map_chunks); fflush(stdout); } if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) fd = open(name, O_RDWR); else { sprintf(param, "%s%s", _PATH_DEV, name); fd = open(param, O_RDWR); } if (fd < 0) gctl_error(req, "Cannot open provider %s to write map", name); /* Do it with calloc because there might be a need to set up chunk flags * in the future */ map = calloc(total_chunks, sizeof(*map)); if (map == NULL) { gctl_error(req, "Out of memory (need %zu bytes for allocation map)", map_size); } written = pwrite(fd, map, map_size, 0); free(map); if ((size_t)written != map_size) { if (verbose) { fprintf(stderr, "\nTried to write %zu, written %zd (%s)\n", map_size, written, strerror(errno)); } gctl_error(req, "Error writing out allocation map!"); return; } close (fd); if (verbose) printf("\nStoring metadata on "); /* * ID is randomly generated, unique for a geom. This is used to * recognize all providers belonging to one geom. */ md.md_id = arc4random(); /* Ok, store metadata. */ for (i = 1; i < (unsigned)nargs; i++) { snprintf(param, sizeof(param), "arg%u", i); name = gctl_get_ascii(req, "%s", param); msize = g_get_mediasize(name); ssize = g_get_sectorsize(name); if (verbose) printf("%s ", name); /* this provider's position/type in geom */ md.no = i - 1; /* this provider's size */ md.provsize = msize; /* chunk allocation info */ md.chunk_count = md.provsize / md.md_chunk_size; if (verbose) printf("(%u chunks) ", md.chunk_count); /* Check to make sure last sector is unused */ if ((off_t)(md.chunk_count * md.md_chunk_size) > (off_t)(msize-ssize)) md.chunk_count--; md.chunk_next = 0; if (i != 1) { md.chunk_reserved = 0; md.flags = 0; } else { md.chunk_reserved = map_chunks * 2; md.flags = VIRSTOR_PROVIDER_ALLOCATED | VIRSTOR_PROVIDER_CURRENT; md.chunk_next = md.chunk_reserved; if (verbose) printf("(%u reserved) ", md.chunk_reserved); } if (!hardcode) bzero(md.provider, sizeof(md.provider)); else { /* convert "/dev/something" to "something" */ if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) { strlcpy(md.provider, name + sizeof(_PATH_DEV) - 1, sizeof(md.provider)); } else strlcpy(md.provider, name, sizeof(md.provider)); } sect = malloc(ssize); if (sect == NULL) err(1, "Cannot allocate sector of %zu bytes", ssize); bzero(sect, ssize); virstor_metadata_encode(&md, sect); error = my_g_metadata_store(name, sect, ssize); free(sect); if (error != 0) { if (verbose) printf("\n"); fprintf(stderr, "Can't store metadata on %s: %s.\n", name, strerror(error)); gctl_error(req, "Not fully done (error storing metadata)."); return; } } #if 0 if (verbose) printf("\n"); #endif }
static void journal_label(struct gctl_req *req) { struct g_journal_metadata md; const char *data, *journal, *str; u_char sector[512]; intmax_t jsize, msize, ssize; int error, force, i, nargs, checksum, hardcode; nargs = gctl_get_int(req, "nargs"); str = NULL; /* gcc */ strlcpy(md.md_magic, G_JOURNAL_MAGIC, sizeof(md.md_magic)); md.md_version = G_JOURNAL_VERSION; md.md_id = arc4random(); md.md_joffset = 0; md.md_jid = 0; md.md_flags = GJ_FLAG_CLEAN; checksum = gctl_get_int(req, "checksum"); if (checksum) md.md_flags |= GJ_FLAG_CHECKSUM; force = gctl_get_int(req, "force"); hardcode = gctl_get_int(req, "hardcode"); if (nargs != 1 && nargs != 2) { gctl_error(req, "Invalid number of arguments."); return; } /* Verify the given providers. */ for (i = 0; i < nargs; i++) { str = gctl_get_ascii(req, "arg%d", i); if (g_get_mediasize(str) == 0) { gctl_error(req, "Invalid provider %s.", str); return; } } data = gctl_get_ascii(req, "arg0"); jsize = gctl_get_intmax(req, "jsize"); journal = NULL; switch (nargs) { case 1: if (!force && g_journal_fs_exists(data)) { gctl_error(req, "File system exists on %s and this " "operation would destroy it.\nUse -f if you " "really want to do it.", data); return; } journal = data; msize = g_get_mediasize(data); ssize = g_get_sectorsize(data); if (jsize == -1) { /* * No journal size specified. 1GB should be safe * default. */ jsize = 1073741824ULL; } else { if (jsize < 104857600) { gctl_error(req, "Journal too small."); return; } if ((jsize % ssize) != 0) { gctl_error(req, "Invalid journal size."); return; } } if (jsize + ssize >= msize) { gctl_error(req, "Provider too small for journalling. " "You can try smaller jsize (default is %jd).", jsize); return; } md.md_jstart = msize - ssize - jsize; md.md_jend = msize - ssize; break; case 2: if (!force && g_journal_fs_using_last_sector(data)) { gctl_error(req, "File system on %s is using the last " "sector and this operation is going to overwrite " "it. Use -f if you really want to do it.", data); return; } journal = gctl_get_ascii(req, "arg1"); if (jsize != -1) { gctl_error(req, "jsize argument is valid only for " "all-in-one configuration."); return; } msize = g_get_mediasize(journal); ssize = g_get_sectorsize(journal); md.md_jstart = 0; md.md_jend = msize - ssize; break; } if (g_get_sectorsize(data) != g_get_sectorsize(journal)) { gctl_error(req, "Not equal sector sizes."); return; } /* * Clear last sector first, to spoil all components if device exists. */ for (i = 0; i < nargs; i++) { str = gctl_get_ascii(req, "arg%d", i); error = g_metadata_clear(str, NULL); if (error != 0) { gctl_error(req, "Cannot clear metadata on %s: %s.", str, strerror(error)); return; } } /* * Ok, store metadata. */ for (i = 0; i < nargs; i++) { switch (i) { case 0: str = data; md.md_type = GJ_TYPE_DATA; if (nargs == 1) md.md_type |= GJ_TYPE_JOURNAL; break; case 1: str = journal; md.md_type = GJ_TYPE_JOURNAL; break; } md.md_provsize = g_get_mediasize(str); assert(md.md_provsize != 0); if (!hardcode) bzero(md.md_provider, sizeof(md.md_provider)); else { if (strncmp(str, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) str += sizeof(_PATH_DEV) - 1; strlcpy(md.md_provider, str, sizeof(md.md_provider)); } journal_metadata_encode(&md, sector); error = g_metadata_store(str, sector, sizeof(sector)); if (error != 0) { fprintf(stderr, "Cannot store metadata on %s: %s.\n", str, strerror(error)); gctl_error(req, "Not fully done."); continue; } if (verbose) printf("Metadata value stored on %s.\n", str); } }