Example #1
0
/*
 * 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
}
Example #2
0
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);
	}
}
Example #3
0
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);
	}
}