diff options
| author | John Forte <John.Forte@Sun.COM> | 2008-10-14 15:09:13 -0700 | 
|---|---|---|
| committer | John Forte <John.Forte@Sun.COM> | 2008-10-14 15:09:13 -0700 | 
| commit | fcf3ce441efd61da9bb2884968af01cb7c1452cc (patch) | |
| tree | 0e80d59ad41702571586195bf099ccc14222ce02 /usr/src/cmd/avs/dsbitmap/dsbitmap.c | |
| parent | 247b82a1f1cb5ebd2d163bd9afdb1a3065611962 (diff) | |
| download | illumos-joyent-fcf3ce441efd61da9bb2884968af01cb7c1452cc.tar.gz | |
6745433 Merge NWS consolidation into OS/Net consolidation
Diffstat (limited to 'usr/src/cmd/avs/dsbitmap/dsbitmap.c')
| -rw-r--r-- | usr/src/cmd/avs/dsbitmap/dsbitmap.c | 436 | 
1 files changed, 436 insertions, 0 deletions
| diff --git a/usr/src/cmd/avs/dsbitmap/dsbitmap.c b/usr/src/cmd/avs/dsbitmap/dsbitmap.c new file mode 100644 index 0000000000..77c5be7c1f --- /dev/null +++ b/usr/src/cmd/avs/dsbitmap/dsbitmap.c @@ -0,0 +1,436 @@ +/* + * 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); +} | 
