OpenSolaris_b135/cmd/avs/dsbitmap/dsbitmap.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dkio.h>
#include <sys/vtoc.h>
#include <sys/mkdev.h>
#ifdef DKIOCPARTITION
#include <sys/efi_partition.h>
#endif
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <locale.h>
#include <unistd.h>
#include <libgen.h>
#include <kstat.h>

#include <sys/unistat/spcs_s.h>
#include <sys/unistat/spcs_s_u.h>
#include <sys/unistat/spcs_errors.h>

#include <sys/nsctl/dsw.h>
#include <sys/nsctl/dsw_dev.h>
#include <sys/nsctl/rdc_io.h>
#include <sys/nsctl/rdc_bitmap.h>

enum { UNKNOWN = 0, SNDR, II };

static char *program;

void
usage(void)
{
	(void) printf(gettext("usage: %s -h\n"), program);
	(void) printf(gettext("       %s { -p | -r } data_volume "
	    "[bitmap_volume]\n"), program);
	(void) printf(gettext("       -h : This usage message\n"));
	(void) printf(gettext("       -p : Calculate size of Point in Time "
	    "bitmap\n"));
	(void) printf(gettext("       -r : Calculate size of Remote Mirror "
	    "bitmap\n"));
}


static void
message(char *prefix, spcs_s_info_t *status, caddr_t string, va_list ap)
{
	(void) fprintf(stderr, "%s: %s: ", program, prefix);
	(void) vfprintf(stderr, string, ap);
	(void) fprintf(stderr, "\n");

	if (status) {
		spcs_s_report(*status, stderr);
		spcs_s_ufree(status);
	}
}


static void
error(spcs_s_info_t *status, char *string, ...)
{
	va_list ap;
	va_start(ap, string);

	message(gettext("error"), status, string, ap);
	va_end(ap);
	exit(1);
}


static void
warn(spcs_s_info_t *status, char *string, ...)
{
	va_list ap;
	va_start(ap, string);

	message(gettext("warning"), status, string, ap);
	va_end(ap);
}

#if defined(_LP64)
					/* max value of a "long int" */
#define	ULONG_MAX	18446744073709551615UL
#else /* _ILP32 */
#define	ULONG_MAX	4294967295UL	/* max of "unsigned long int" */
#endif

static uint64_t
get_partsize(char *partition)
{
#ifdef DKIOCPARTITION
	struct dk_cinfo dki_info;
	struct partition64 p64;
#endif
	struct vtoc vtoc;
	uint64_t size;
	int fd;
	int rc;

	if ((fd = open(partition, O_RDONLY)) < 0) {
		error(NULL, gettext("unable to open partition, %s: %s"),
		    partition, strerror(errno));
		/* NOTREACHED */
	}

	rc = read_vtoc(fd, &vtoc);
	if (rc >= 0) {
		size = (uint64_t)(ULONG_MAX & vtoc.v_part[rc].p_size);
		return (size);
	}
#ifdef DKIOCPARTITION
	else if (rc != VT_ENOTSUP) {
#endif
		error(NULL,
		    gettext("unable to read the vtoc from partition, %s: %s"),
		    partition, strerror(errno));
		/* NOTREACHED */
#ifdef DKIOCPARTITION
	}

	/* See if there is an EFI label */
	rc = ioctl(fd, DKIOCINFO, &dki_info);
	if (rc < 0) {
		error(NULL, gettext("unable to get controller info "
		    "from partition, %s: %s"),
		    partition, strerror(errno));
		/* NOTREACHED */
	}

	bzero(&p64, sizeof (p64));
	p64.p_partno = (uint_t)dki_info.dki_partition;
	rc = ioctl(fd, DKIOCPARTITION, &p64);
	if (rc >= 0) {
		size = (uint64_t)p64.p_size;
		return (size);
	} else {
		struct stat64 stb1, stb2;
		struct dk_minfo dkm;

		/*
		 * See if the stat64 for ZFS's zvol matches
		 * this file descriptor's fstat64 data.
		 */
		if (stat64("/devices/pseudo/zfs@0:zfs", &stb1) != 0 ||
		    fstat64(fd, &stb2) != 0 ||
		    !S_ISCHR(stb1.st_mode) ||
		    !S_ISCHR(stb2.st_mode) ||
		    major(stb1.st_rdev) != major(stb2.st_rdev)) {
			error(NULL,
			    gettext("unable to read disk partition, %s: %s"),
			    partition, strerror(errno));
			/* NOTREACHED */
		}

		rc = ioctl(fd, DKIOCGMEDIAINFO, (void *)&dkm);
		if (rc >= 0) {
			size = LE_64(dkm.dki_capacity) *
				dkm.dki_lbsize / 512;
			return (size);
		} else {
			error(NULL, gettext("unable to read EFI label "
			    "from partition, %s: %s"),
			    partition, strerror(errno));
			/* NOTREACHED */
		}
	}
	return (size);

#endif	/* DKIOCPARTITION */
}


int
do_sndr(char *volume, char *bitmap)
{
	uint64_t vblocks;
	uint64_t bblocks;
	uint64_t bsize_bits;	/* size of the bits alone */
	uint64_t bsize_simple;	/* size of the simple bitmap */
	uint64_t bsize_diskq;	/* size of the diskq bitmap, 8 bit refcnt */
	uint64_t bsize_diskq32;	/* size of the diskq bitmap, 32 bit refcnt */
	int rc = 0;

	vblocks = get_partsize(volume);
	if (bitmap) {
		bblocks = get_partsize(bitmap);
	}

	bsize_bits = BMAP_LOG_BYTES(vblocks);
	bsize_bits = (bsize_bits + 511) / 512;

	bsize_simple = RDC_BITMAP_FBA + bsize_bits;
	bsize_diskq = RDC_BITMAP_FBA + bsize_bits + (BITS_IN_BYTE * bsize_bits);
	bsize_diskq32 = RDC_BITMAP_FBA + bsize_bits + (BITS_IN_BYTE *
		bsize_bits * sizeof (unsigned int));

	(void) printf(gettext("Remote Mirror bitmap sizing\n\n"));
	(void) printf(gettext("Data volume (%s) size: %llu blocks\n"),
	    volume, vblocks);

	(void) printf(gettext("Required bitmap volume size:\n"));
	(void) printf(gettext("  Sync replication: %llu blocks\n"),
	    bsize_simple);
	(void) printf(gettext("  Async replication with memory queue: "
	    "%llu blocks\n"), bsize_simple);
	(void) printf(gettext("  Async replication with disk queue: "
	    "%llu blocks\n"), bsize_diskq);
	(void) printf(gettext("  Async replication with disk queue and 32 bit "
	    "refcount: %llu blocks\n"), bsize_diskq32);

	if (bitmap) {
		(void) printf("\n");
		(void) printf(gettext("Supplied bitmap volume %s "
		    "(%llu blocks)\n"),
		    bitmap, bblocks);
		if (bblocks >= bsize_diskq32) {
			(void) printf(gettext("is large enough for all "
			    "replication modes\n"));
		} else if (bblocks >= bsize_diskq) {
			(void) printf(gettext("is large enough for all "
			    "replication modes, but with restricted diskq "
			    "reference counts\n"));
		} else if (bblocks >= bsize_simple) {
			(void) printf(gettext(
			    "is large enough for: Sync and Async(memory) "
			    "replication modes only\n"));
			rc = 3;
		} else {
			(void) printf(gettext(
			    "is not large enough for any replication modes\n"));
			rc = 4;
		}
	}

	return (rc);
}


/* sizes in bytes */
#define	KILO	(1024)
#define	MEGA	(KILO * KILO)
#define	GIGA	(MEGA * KILO)
#define	TERA	((uint64_t)((uint64_t)GIGA * (uint64_t)KILO))

/* rounding function */
#define	roundup_2n(x, y)	(((x) + ((y) - 1)) & (~y))

int
do_ii(char *volume, char *bitmap)
{
	const uint64_t int64_bits = sizeof (uint64_t) * BITS_IN_BYTE;
	const uint64_t int32_bits = sizeof (uint32_t) * BITS_IN_BYTE;
	const uint64_t terablocks = TERA / ((uint64_t)FBA_SIZE(1));
	uint64_t vblocks_phys, vblocks;
	uint64_t bblocks;
	uint64_t bsize_ind;	/* indep and dep not compact */
	uint64_t bsize_cdep;	/* compact dep */
	int rc = 0;

	vblocks_phys = get_partsize(volume);
	if (bitmap) {
		bblocks = get_partsize(bitmap);
	}

	/* round up to multiple of DSW_SIZE blocks */
	vblocks = roundup_2n(vblocks_phys, DSW_SIZE);
	bsize_ind = DSW_SHD_BM_OFFSET + (2 * DSW_BM_FBA_LEN(vblocks));
	bsize_cdep = bsize_ind;
	bsize_cdep += DSW_BM_FBA_LEN(vblocks) *
	    ((vblocks < (uint64_t)(terablocks * DSW_SIZE)) ?
	    int32_bits : int64_bits);

	(void) printf(gettext("Point in Time bitmap sizing\n\n"));
	(void) printf(gettext("Data volume (%s) size: %llu blocks\n"),
	    volume, vblocks_phys);

	(void) printf(gettext("Required bitmap volume size:\n"));
	(void) printf(gettext("  Independent shadow: %llu blocks\n"),
	    bsize_ind);
	(void) printf(gettext("  Full size dependent shadow: %llu blocks\n"),
	    bsize_ind);
	(void) printf(gettext("  Compact dependent shadow: %llu blocks\n"),
	    bsize_cdep);

	if (bitmap) {
		(void) printf("\n");
		(void) printf(gettext("Supplied bitmap volume %s "
		    "(%llu blocks)\n"), bitmap, bblocks);

		if (bblocks >= bsize_cdep) {
			(void) printf(gettext("is large enough for all types "
			    "of shadow volume\n"));
		} else if (bblocks >= bsize_ind) {
			(void) printf(gettext("is large enough for: "
			    "Independent and full size dependent shadow "
			    "volumes only\n"));
			rc = 6;
		} else {
			(void) printf(gettext("is not large enough for"
			    "any type of shadow volume\n"));
			rc = 5;
		}
	}

	return (rc);
}


/*
 * Return codes:
 *	0 success (if bitmap was supplied it is large enough for all uses)
 *	1 usage, programing, or access errors
 *	2 unknown option supplied on command line
 *	3 SNDR bitmap is not large enough for diskq usage
 *	4 SNDR bitmap is not large enough for any usage
 *	5 II bitmap is not large enough for any usage
 *	6 II bitmap is not large enough for compact dependent usage
 */
int
main(int argc, char *argv[])
{
	extern int optind;
	char *volume, *bitmap;
	int type = UNKNOWN;
	int opt;
	int rc = 0;

	(void) setlocale(LC_ALL, "");
	(void) textdomain("dsbitmap");

	program = strdup(basename(argv[0]));

	while ((opt = getopt(argc, argv, "hpr")) != EOF) {
		switch (opt) {
		case 'p':
			if (type != UNKNOWN) {
				warn(NULL, gettext(
				    "cannot specify -p with other options"));
				usage();
				return (1);
			}
			type = II;
			break;

		case 'r':
			if (type != UNKNOWN) {
				warn(NULL, gettext(
				    "cannot specify -r with other options"));
				usage();
				return (1);
			}
			type = SNDR;
			break;

		case 'h':
			if (argc != 2) {
				warn(NULL, gettext(
				    "cannot specify -h with other options"));
				rc = 1;
			}
			usage();
			return (rc);
			/* NOTREACHED */

		default:
			usage();
			return (2);
			/* NOTREACHED */
		}
	}

	if (type == UNKNOWN) {
		warn(NULL, gettext("one of -p and -r must be specified"));
		usage();
		return (1);
	}

	if ((argc - optind) != 1 && (argc - optind) != 2) {
		warn(NULL, gettext("incorrect number of arguments to %s"),
		    (type == SNDR) ? "-r" : "-p");
		usage();
		return (1);
	}

	volume = argv[optind];
	if ((argc - optind) == 2) {
		bitmap = argv[optind+1];
	} else {
		bitmap = NULL;
	}

	switch (type) {
	case SNDR:
		rc = do_sndr(volume, bitmap);
		break;

	case II:
		rc = do_ii(volume, bitmap);
		break;

	default:
		/* cannot happen */
		warn(NULL, gettext("one of -p and -r must be specified"));
		rc = 1;
		break;
	}

	return (rc);
}