xref: /titanic_52/usr/src/cmd/avs/dsbitmap/dsbitmap.c (revision b9e93c10c0a2a4bb069d38bb311021a9478c4711)
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 }
437