Home | History | Annotate | Download | only in dsbitmap
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/types.h>
     27 #include <sys/stat.h>
     28 #include <sys/dkio.h>
     29 #include <sys/vtoc.h>
     30 #include <sys/mkdev.h>
     31 #ifdef DKIOCPARTITION
     32 #include <sys/efi_partition.h>
     33 #endif
     34 #include <strings.h>
     35 #include <stdarg.h>
     36 #include <stdlib.h>
     37 #include <fcntl.h>
     38 #include <errno.h>
     39 #include <stdio.h>
     40 #include <locale.h>
     41 #include <unistd.h>
     42 #include <libgen.h>
     43 #include <kstat.h>
     44 
     45 #include <sys/unistat/spcs_s.h>
     46 #include <sys/unistat/spcs_s_u.h>
     47 #include <sys/unistat/spcs_errors.h>
     48 
     49 #include <sys/nsctl/dsw.h>
     50 #include <sys/nsctl/dsw_dev.h>
     51 #include <sys/nsctl/rdc_io.h>
     52 #include <sys/nsctl/rdc_bitmap.h>
     53 
     54 enum { UNKNOWN = 0, SNDR, II };
     55 
     56 static char *program;
     57 
     58 void
     59 usage(void)
     60 {
     61 	(void) printf(gettext("usage: %s -h\n"), program);
     62 	(void) printf(gettext("       %s { -p | -r } data_volume "
     63 	    "[bitmap_volume]\n"), program);
     64 	(void) printf(gettext("       -h : This usage message\n"));
     65 	(void) printf(gettext("       -p : Calculate size of Point in Time "
     66 	    "bitmap\n"));
     67 	(void) printf(gettext("       -r : Calculate size of Remote Mirror "
     68 	    "bitmap\n"));
     69 }
     70 
     71 
     72 static void
     73 message(char *prefix, spcs_s_info_t *status, caddr_t string, va_list ap)
     74 {
     75 	(void) fprintf(stderr, "%s: %s: ", program, prefix);
     76 	(void) vfprintf(stderr, string, ap);
     77 	(void) fprintf(stderr, "\n");
     78 
     79 	if (status) {
     80 		spcs_s_report(*status, stderr);
     81 		spcs_s_ufree(status);
     82 	}
     83 }
     84 
     85 
     86 static void
     87 error(spcs_s_info_t *status, char *string, ...)
     88 {
     89 	va_list ap;
     90 	va_start(ap, string);
     91 
     92 	message(gettext("error"), status, string, ap);
     93 	va_end(ap);
     94 	exit(1);
     95 }
     96 
     97 
     98 static void
     99 warn(spcs_s_info_t *status, char *string, ...)
    100 {
    101 	va_list ap;
    102 	va_start(ap, string);
    103 
    104 	message(gettext("warning"), status, string, ap);
    105 	va_end(ap);
    106 }
    107 
    108 #if defined(_LP64)
    109 					/* max value of a "long int" */
    110 #define	ULONG_MAX	18446744073709551615UL
    111 #else /* _ILP32 */
    112 #define	ULONG_MAX	4294967295UL	/* max of "unsigned long int" */
    113 #endif
    114 
    115 static uint64_t
    116 get_partsize(char *partition)
    117 {
    118 #ifdef DKIOCPARTITION
    119 	struct dk_cinfo dki_info;
    120 	struct partition64 p64;
    121 #endif
    122 	struct vtoc vtoc;
    123 	uint64_t size;
    124 	int fd;
    125 	int rc;
    126 
    127 	if ((fd = open(partition, O_RDONLY)) < 0) {
    128 		error(NULL, gettext("unable to open partition, %s: %s"),
    129 		    partition, strerror(errno));
    130 		/* NOTREACHED */
    131 	}
    132 
    133 	rc = read_vtoc(fd, &vtoc);
    134 	if (rc >= 0) {
    135 		size = (uint64_t)(ULONG_MAX & vtoc.v_part[rc].p_size);
    136 		return (size);
    137 	}
    138 #ifdef DKIOCPARTITION
    139 	else if (rc != VT_ENOTSUP) {
    140 #endif
    141 		error(NULL,
    142 		    gettext("unable to read the vtoc from partition, %s: %s"),
    143 		    partition, strerror(errno));
    144 		/* NOTREACHED */
    145 #ifdef DKIOCPARTITION
    146 	}
    147 
    148 	/* See if there is an EFI label */
    149 	rc = ioctl(fd, DKIOCINFO, &dki_info);
    150 	if (rc < 0) {
    151 		error(NULL, gettext("unable to get controller info "
    152 		    "from partition, %s: %s"),
    153 		    partition, strerror(errno));
    154 		/* NOTREACHED */
    155 	}
    156 
    157 	bzero(&p64, sizeof (p64));
    158 	p64.p_partno = (uint_t)dki_info.dki_partition;
    159 	rc = ioctl(fd, DKIOCPARTITION, &p64);
    160 	if (rc >= 0) {
    161 		size = (uint64_t)p64.p_size;
    162 		return (size);
    163 	} else {
    164 		struct stat64 stb1, stb2;
    165 		struct dk_minfo dkm;
    166 
    167 		/*
    168 		 * See if the stat64 for ZFS's zvol matches
    169 		 * this file descriptor's fstat64 data.
    170 		 */
    171 		if (stat64("/devices/pseudo/zfs@0:zfs", &stb1) != 0 ||
    172 		    fstat64(fd, &stb2) != 0 ||
    173 		    !S_ISCHR(stb1.st_mode) ||
    174 		    !S_ISCHR(stb2.st_mode) ||
    175 		    major(stb1.st_rdev) != major(stb2.st_rdev)) {
    176 			error(NULL,
    177 			    gettext("unable to read disk partition, %s: %s"),
    178 			    partition, strerror(errno));
    179 			/* NOTREACHED */
    180 		}
    181 
    182 		rc = ioctl(fd, DKIOCGMEDIAINFO, (void *)&dkm);
    183 		if (rc >= 0) {
    184 			size = LE_64(dkm.dki_capacity) *
    185 				dkm.dki_lbsize / 512;
    186 			return (size);
    187 		} else {
    188 			error(NULL, gettext("unable to read EFI label "
    189 			    "from partition, %s: %s"),
    190 			    partition, strerror(errno));
    191 			/* NOTREACHED */
    192 		}
    193 	}
    194 	return (size);
    195 
    196 #endif	/* DKIOCPARTITION */
    197 }
    198 
    199 
    200 int
    201 do_sndr(char *volume, char *bitmap)
    202 {
    203 	uint64_t vblocks;
    204 	uint64_t bblocks;
    205 	uint64_t bsize_bits;	/* size of the bits alone */
    206 	uint64_t bsize_simple;	/* size of the simple bitmap */
    207 	uint64_t bsize_diskq;	/* size of the diskq bitmap, 8 bit refcnt */
    208 	uint64_t bsize_diskq32;	/* size of the diskq bitmap, 32 bit refcnt */
    209 	int rc = 0;
    210 
    211 	vblocks = get_partsize(volume);
    212 	if (bitmap) {
    213 		bblocks = get_partsize(bitmap);
    214 	}
    215 
    216 	bsize_bits = BMAP_LOG_BYTES(vblocks);
    217 	bsize_bits = (bsize_bits + 511) / 512;
    218 
    219 	bsize_simple = RDC_BITMAP_FBA + bsize_bits;
    220 	bsize_diskq = RDC_BITMAP_FBA + bsize_bits + (BITS_IN_BYTE * bsize_bits);
    221 	bsize_diskq32 = RDC_BITMAP_FBA + bsize_bits + (BITS_IN_BYTE *
    222 		bsize_bits * sizeof (unsigned int));
    223 
    224 	(void) printf(gettext("Remote Mirror bitmap sizing\n\n"));
    225 	(void) printf(gettext("Data volume (%s) size: %llu blocks\n"),
    226 	    volume, vblocks);
    227 
    228 	(void) printf(gettext("Required bitmap volume size:\n"));
    229 	(void) printf(gettext("  Sync replication: %llu blocks\n"),
    230 	    bsize_simple);
    231 	(void) printf(gettext("  Async replication with memory queue: "
    232 	    "%llu blocks\n"), bsize_simple);
    233 	(void) printf(gettext("  Async replication with disk queue: "
    234 	    "%llu blocks\n"), bsize_diskq);
    235 	(void) printf(gettext("  Async replication with disk queue and 32 bit "
    236 	    "refcount: %llu blocks\n"), bsize_diskq32);
    237 
    238 	if (bitmap) {
    239 		(void) printf("\n");
    240 		(void) printf(gettext("Supplied bitmap volume %s "
    241 		    "(%llu blocks)\n"),
    242 		    bitmap, bblocks);
    243 		if (bblocks >= bsize_diskq32) {
    244 			(void) printf(gettext("is large enough for all "
    245 			    "replication modes\n"));
    246 		} else if (bblocks >= bsize_diskq) {
    247 			(void) printf(gettext("is large enough for all "
    248 			    "replication modes, but with restricted diskq "
    249 			    "reference counts\n"));
    250 		} else if (bblocks >= bsize_simple) {
    251 			(void) printf(gettext(
    252 			    "is large enough for: Sync and Async(memory) "
    253 			    "replication modes only\n"));
    254 			rc = 3;
    255 		} else {
    256 			(void) printf(gettext(
    257 			    "is not large enough for any replication modes\n"));
    258 			rc = 4;
    259 		}
    260 	}
    261 
    262 	return (rc);
    263 }
    264 
    265 
    266 /* sizes in bytes */
    267 #define	KILO	(1024)
    268 #define	MEGA	(KILO * KILO)
    269 #define	GIGA	(MEGA * KILO)
    270 #define	TERA	((uint64_t)((uint64_t)GIGA * (uint64_t)KILO))
    271 
    272 /* rounding function */
    273 #define	roundup_2n(x, y)	(((x) + ((y) - 1)) & (~y))
    274 
    275 int
    276 do_ii(char *volume, char *bitmap)
    277 {
    278 	const uint64_t int64_bits = sizeof (uint64_t) * BITS_IN_BYTE;
    279 	const uint64_t int32_bits = sizeof (uint32_t) * BITS_IN_BYTE;
    280 	const uint64_t terablocks = TERA / ((uint64_t)FBA_SIZE(1));
    281 	uint64_t vblocks_phys, vblocks;
    282 	uint64_t bblocks;
    283 	uint64_t bsize_ind;	/* indep and dep not compact */
    284 	uint64_t bsize_cdep;	/* compact dep */
    285 	int rc = 0;
    286 
    287 	vblocks_phys = get_partsize(volume);
    288 	if (bitmap) {
    289 		bblocks = get_partsize(bitmap);
    290 	}
    291 
    292 	/* round up to multiple of DSW_SIZE blocks */
    293 	vblocks = roundup_2n(vblocks_phys, DSW_SIZE);
    294 	bsize_ind = DSW_SHD_BM_OFFSET + (2 * DSW_BM_FBA_LEN(vblocks));
    295 	bsize_cdep = bsize_ind;
    296 	bsize_cdep += DSW_BM_FBA_LEN(vblocks) *
    297 	    ((vblocks < (uint64_t)(terablocks * DSW_SIZE)) ?
    298 	    int32_bits : int64_bits);
    299 
    300 	(void) printf(gettext("Point in Time bitmap sizing\n\n"));
    301 	(void) printf(gettext("Data volume (%s) size: %llu blocks\n"),
    302 	    volume, vblocks_phys);
    303 
    304 	(void) printf(gettext("Required bitmap volume size:\n"));
    305 	(void) printf(gettext("  Independent shadow: %llu blocks\n"),
    306 	    bsize_ind);
    307 	(void) printf(gettext("  Full size dependent shadow: %llu blocks\n"),
    308 	    bsize_ind);
    309 	(void) printf(gettext("  Compact dependent shadow: %llu blocks\n"),
    310 	    bsize_cdep);
    311 
    312 	if (bitmap) {
    313 		(void) printf("\n");
    314 		(void) printf(gettext("Supplied bitmap volume %s "
    315 		    "(%llu blocks)\n"), bitmap, bblocks);
    316 
    317 		if (bblocks >= bsize_cdep) {
    318 			(void) printf(gettext("is large enough for all types "
    319 			    "of shadow volume\n"));
    320 		} else if (bblocks >= bsize_ind) {
    321 			(void) printf(gettext("is large enough for: "
    322 			    "Independent and full size dependent shadow "
    323 			    "volumes only\n"));
    324 			rc = 6;
    325 		} else {
    326 			(void) printf(gettext("is not large enough for"
    327 			    "any type of shadow volume\n"));
    328 			rc = 5;
    329 		}
    330 	}
    331 
    332 	return (rc);
    333 }
    334 
    335 
    336 /*
    337  * Return codes:
    338  *	0 success (if bitmap was supplied it is large enough for all uses)
    339  *	1 usage, programing, or access errors
    340  *	2 unknown option supplied on command line
    341  *	3 SNDR bitmap is not large enough for diskq usage
    342  *	4 SNDR bitmap is not large enough for any usage
    343  *	5 II bitmap is not large enough for any usage
    344  *	6 II bitmap is not large enough for compact dependent usage
    345  */
    346 int
    347 main(int argc, char *argv[])
    348 {
    349 	extern int optind;
    350 	char *volume, *bitmap;
    351 	int type = UNKNOWN;
    352 	int opt;
    353 	int rc = 0;
    354 
    355 	(void) setlocale(LC_ALL, "");
    356 	(void) textdomain("dsbitmap");
    357 
    358 	program = strdup(basename(argv[0]));
    359 
    360 	while ((opt = getopt(argc, argv, "hpr")) != EOF) {
    361 		switch (opt) {
    362 		case 'p':
    363 			if (type != UNKNOWN) {
    364 				warn(NULL, gettext(
    365 				    "cannot specify -p with other options"));
    366 				usage();
    367 				return (1);
    368 			}
    369 			type = II;
    370 			break;
    371 
    372 		case 'r':
    373 			if (type != UNKNOWN) {
    374 				warn(NULL, gettext(
    375 				    "cannot specify -r with other options"));
    376 				usage();
    377 				return (1);
    378 			}
    379 			type = SNDR;
    380 			break;
    381 
    382 		case 'h':
    383 			if (argc != 2) {
    384 				warn(NULL, gettext(
    385 				    "cannot specify -h with other options"));
    386 				rc = 1;
    387 			}
    388 			usage();
    389 			return (rc);
    390 			/* NOTREACHED */
    391 
    392 		default:
    393 			usage();
    394 			return (2);
    395 			/* NOTREACHED */
    396 		}
    397 	}
    398 
    399 	if (type == UNKNOWN) {
    400 		warn(NULL, gettext("one of -p and -r must be specified"));
    401 		usage();
    402 		return (1);
    403 	}
    404 
    405 	if ((argc - optind) != 1 && (argc - optind) != 2) {
    406 		warn(NULL, gettext("incorrect number of arguments to %s"),
    407 		    (type == SNDR) ? "-r" : "-p");
    408 		usage();
    409 		return (1);
    410 	}
    411 
    412 	volume = argv[optind];
    413 	if ((argc - optind) == 2) {
    414 		bitmap = argv[optind+1];
    415 	} else {
    416 		bitmap = NULL;
    417 	}
    418 
    419 	switch (type) {
    420 	case SNDR:
    421 		rc = do_sndr(volume, bitmap);
    422 		break;
    423 
    424 	case II:
    425 		rc = do_ii(volume, bitmap);
    426 		break;
    427 
    428 	default:
    429 		/* cannot happen */
    430 		warn(NULL, gettext("one of -p and -r must be specified"));
    431 		rc = 1;
    432 		break;
    433 	}
    434 
    435 	return (rc);
    436 }
    437