xref: /dragonfly/sbin/hammer/misc.c (revision 52509364)
1 /*
2  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $DragonFly: src/sbin/hammer/misc.c,v 1.5 2008/06/26 04:07:57 dillon Exp $
35  */
36 
37 #include "hammer_util.h"
38 
39 void
40 hammer_key_beg_init(hammer_base_elm_t base)
41 {
42 	bzero(base, sizeof(*base));
43 
44 	base->localization = HAMMER_MIN_LOCALIZATION;
45 	base->obj_id = HAMMER_MIN_OBJID;
46 	base->key = HAMMER_MIN_KEY;
47 	base->create_tid = 1;
48 	base->rec_type = HAMMER_MIN_RECTYPE;
49 	base->obj_type = 0;
50 }
51 
52 void
53 hammer_key_end_init(hammer_base_elm_t base)
54 {
55 	bzero(base, sizeof(*base));
56 
57 	base->localization = HAMMER_MAX_LOCALIZATION;
58 	base->obj_id = HAMMER_MAX_OBJID;
59 	base->key = HAMMER_MAX_KEY;
60 	base->create_tid = HAMMER_MAX_TID;
61 	base->rec_type = HAMMER_MAX_RECTYPE;
62 	base->obj_type = 0;
63 }
64 
65 int
66 getyn(void)
67 {
68 	char buf[256];
69 	int len;
70 
71 	if (fgets(buf, sizeof(buf), stdin) == NULL)
72 		return(0);
73 	len = strlen(buf);
74 	while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
75 		--len;
76 	buf[len] = 0;
77 	if (strcmp(buf, "y") == 0 ||
78 	    strcmp(buf, "yes") == 0 ||
79 	    strcmp(buf, "Y") == 0 ||
80 	    strcmp(buf, "YES") == 0) {
81 		return(1);
82 	}
83 	return(0);
84 }
85 
86 const char *
87 sizetostr(off_t size)
88 {
89 	static char buf[32];
90 
91 	if (size < 1024 / 2) {
92 		snprintf(buf, sizeof(buf), "%6.2fB", (double)size);
93 	} else if (size < 1024 * 1024 / 2) {
94 		snprintf(buf, sizeof(buf), "%6.2fKB", (double)size / 1024);
95 	} else if (size < 1024 * 1024 * 1024LL / 2) {
96 		snprintf(buf, sizeof(buf), "%6.2fMB",
97 			(double)size / (1024 * 1024));
98 	} else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
99 		snprintf(buf, sizeof(buf), "%6.2fGB",
100 			(double)size / (1024 * 1024 * 1024LL));
101 	} else {
102 		snprintf(buf, sizeof(buf), "%6.2fTB",
103 			(double)size / (1024 * 1024 * 1024LL * 1024LL));
104 	}
105 	return(buf);
106 }
107 
108 int
109 hammer_fs_to_vol(const char *fs, struct hammer_ioc_volume_list *p)
110 {
111 	struct hammer_ioc_volume_list ioc;
112 	int fd;
113 
114 	fd = open(fs, O_RDONLY);
115 	if (fd < 0) {
116 		perror("open");
117 		return(-1);
118 	}
119 
120 	bzero(&ioc, sizeof(ioc));
121 	ioc.nvols = HAMMER_MAX_VOLUMES;
122 	ioc.vols = malloc(ioc.nvols * sizeof(*ioc.vols));
123 	if (ioc.vols == NULL) {
124 		perror("malloc");
125 		close(fd);
126 		return(-1);
127 	}
128 
129 	if (ioctl(fd, HAMMERIOC_LIST_VOLUMES, &ioc) < 0) {
130 		perror("ioctl");
131 		close(fd);
132 		free(ioc.vols);
133 		return(-1);
134 	}
135 
136 	bcopy(&ioc, p, sizeof(ioc));
137 	close(fd);
138 
139 	return(0);
140 }
141 
142 int
143 hammer_fs_to_rootvol(const char *fs, char *buf, int len)
144 {
145 	struct hammer_ioc_volume_list ioc;
146 	int i;
147 
148 	if (hammer_fs_to_vol(fs, &ioc) == -1)
149 		return(-1);
150 
151 	for (i = 0; i < ioc.nvols; i++) {
152 		if (ioc.vols[i].vol_no == HAMMER_ROOT_VOLNO) {
153 			strlcpy(buf, ioc.vols[i].device_name, len);
154 			break;
155 		}
156 	}
157 	assert(i != ioc.nvols);  /* root volume must exist */
158 
159 	free(ioc.vols);
160 	return(0);
161 }
162 
163 /*
164  * Functions and data structure for zone statistics
165  */
166 /*
167  * Each layer1 needs ((2^19) / 64) = 8192 uint64_t.
168  */
169 #define HAMMER_LAYER1_UINT64 8192
170 #define HAMMER_LAYER1_BYTES (HAMMER_LAYER1_UINT64 * sizeof(uint64_t))
171 
172 static int *l1_max = NULL;
173 static uint64_t **l1_bits = NULL;
174 
175 static __inline
176 int
177 hammer_set_layer_bits(uint64_t *bits, int i)
178 {
179 	int q, r;
180 
181 	q = i >> 6;
182 	r = i & ((1 << 6) - 1);
183 
184 	bits += q;
185 	if (!((*bits) & ((uint64_t)1 << r))) {
186 		(*bits) |= ((uint64_t)1 << r);
187 		return(1);
188 	}
189 	return(0);  /* already seen this block */
190 }
191 
192 static
193 void
194 hammer_extend_layer1_bits(int vol, int newsiz, int oldsiz)
195 {
196 	uint64_t *p;
197 
198 	assert(newsiz > oldsiz);
199 	assert(newsiz > 0 && oldsiz >= 0);
200 
201 	p = l1_bits[vol];
202 	if (p == NULL)
203 		p = malloc(HAMMER_LAYER1_BYTES * newsiz);
204 	else
205 		p = realloc(p, HAMMER_LAYER1_BYTES * newsiz);
206 	if (p == NULL) {
207 		err(1, "alloc");
208 		/* not reached */
209 	}
210 	l1_bits[vol] = p;
211 
212 	p += HAMMER_LAYER1_UINT64 * oldsiz;
213 	bzero(p, HAMMER_LAYER1_BYTES * (newsiz - oldsiz));
214 }
215 
216 zone_stat_t
217 hammer_init_zone_stat(void)
218 {
219 	return(calloc(HAMMER_MAX_ZONES, sizeof(struct zone_stat)));
220 }
221 
222 zone_stat_t
223 hammer_init_zone_stat_bits(void)
224 {
225 	int i;
226 
227 	l1_max = calloc(HAMMER_MAX_VOLUMES, sizeof(int));
228 	if (l1_max == NULL) {
229 		err(1, "calloc");
230 		/* not reached */
231 	}
232 
233 	l1_bits = calloc(HAMMER_MAX_VOLUMES, sizeof(uint64_t*));
234 	if (l1_bits == NULL) {
235 		err(1, "calloc");
236 		/* not reached */
237 	}
238 
239 	for (i = 0; i < HAMMER_MAX_VOLUMES; i++) {
240 		l1_max[i] = -1;  /* +1 needs to be 0 */
241 		l1_bits[i] = NULL;
242 	}
243 	return(hammer_init_zone_stat());
244 }
245 
246 void
247 hammer_cleanup_zone_stat(zone_stat_t stats)
248 {
249 	int i;
250 
251 	if (l1_bits) {
252 		for (i = 0; i < HAMMER_MAX_VOLUMES; i++) {
253 			free(l1_bits[i]);
254 			l1_bits[i] = NULL;
255 		}
256 	}
257 
258 	free(l1_bits);
259 	l1_bits = NULL;
260 
261 	free(l1_max);
262 	l1_max = NULL;
263 
264 	free(stats);
265 }
266 
267 static
268 void
269 _hammer_add_zone_stat(zone_stat_t stats, int zone, int bytes,
270 	int new_block, int new_item)
271 {
272 	zone_stat_t sp = stats + zone;
273 
274 	if (new_block)
275 		sp->blocks++;
276 	if (new_item)
277 		sp->items++;
278 	sp->used += bytes;
279 }
280 
281 void
282 hammer_add_zone_stat(zone_stat_t stats, hammer_off_t offset, int bytes)
283 {
284 	int zone, vol, i, j, new_block;
285 	uint64_t *p;
286 
287 	offset &= ~HAMMER_BIGBLOCK_MASK64;
288 	zone = HAMMER_ZONE_DECODE(offset);
289 	vol = HAMMER_VOL_DECODE(offset);
290 
291 	offset = HAMMER_OFF_SHORT_ENCODE(offset); /* cut off volume bits */
292 	i = HAMMER_BLOCKMAP_LAYER1_INDEX(offset);
293 	j = HAMMER_BLOCKMAP_LAYER2_INDEX(offset);
294 
295 	if (i > l1_max[vol]) {
296 		assert(i < (HAMMER_BLOCKMAP_RADIX1 / HAMMER_MAX_VOLUMES));
297 		hammer_extend_layer1_bits(vol, i + 1, l1_max[vol] + 1);
298 		l1_max[vol] = i;
299 	}
300 
301 	p = l1_bits[vol] + i * HAMMER_LAYER1_UINT64;
302 	new_block = hammer_set_layer_bits(p, j);
303 	_hammer_add_zone_stat(stats, zone, bytes, new_block, 1);
304 }
305 
306 /*
307  * If the same layer2 is used more than once the result will be wrong.
308  */
309 void
310 hammer_add_zone_stat_layer2(zone_stat_t stats,
311 	hammer_blockmap_layer2_t layer2)
312 {
313 	_hammer_add_zone_stat(stats, layer2->zone,
314 		HAMMER_BIGBLOCK_SIZE - layer2->bytes_free, 1, 0);
315 }
316 
317 static __inline
318 double
319 _calc_used_percentage(int64_t blocks, int64_t used)
320 {
321 	double res;
322 
323 	if (blocks)
324 		res = ((double)(used * 100)) / (blocks << HAMMER_BIGBLOCK_BITS);
325 	else
326 		res = 0;
327 	return(res);
328 }
329 
330 void
331 hammer_print_zone_stat(zone_stat_t stats)
332 {
333 	int i;
334 	int64_t total_blocks = 0;
335 	int64_t total_items = 0;
336 	int64_t total_used = 0;
337 	zone_stat_t p = stats;
338 #define INDENT ""
339 
340 	printf("HAMMER zone statistics\n");
341 	printf(INDENT"zone #             "
342 		"blocks       items              used[B]             used[%%]\n");
343 	for (i = 0; i < HAMMER_MAX_ZONES; i++) {
344 		printf(INDENT"zone %-2d %-10s %-12ju %-18ju %-19ju %g\n",
345 			i, zone_labels[i], p->blocks, p->items, p->used,
346 			_calc_used_percentage(p->blocks, p->used));
347 		total_blocks += p->blocks;
348 		total_items += p->items;
349 		total_used += p->used;
350 		p++;
351 	}
352 
353 	/*
354 	 * Remember that zone0 is always 0% used and zone15 is
355 	 * always 100% used.
356 	 */
357 	printf(INDENT"--------------------------------------------------------------------------------\n");
358 	printf(INDENT"total              %-12ju %-18ju %-19ju %g\n",
359 		(uintmax_t)total_blocks,
360 		(uintmax_t)total_items,
361 		(uintmax_t)total_used,
362 		_calc_used_percentage(total_blocks, total_used));
363 }
364