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 }