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
usage(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
message(char * prefix,spcs_s_info_t * status,caddr_t string,va_list ap)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
error(spcs_s_info_t * status,char * string,...)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
warn(spcs_s_info_t * status,char * string,...)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
get_partsize(char * partition)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
do_sndr(char * volume,char * bitmap)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
do_ii(char * volume,char * bitmap)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
main(int argc,char * argv[])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