diff options
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); +} |