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 }