/* * 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 #include #include #include #include #ifdef DKIOCPARTITION #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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); }