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
hammer_key_beg_init(hammer_base_elm_t base)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
hammer_key_end_init(hammer_base_elm_t base)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
getyn(void)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 *
sizetostr(off_t size)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
hammer_fs_to_vol(const char * fs,struct hammer_ioc_volume_list * p)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
hammer_fs_to_rootvol(const char * fs,char * buf,int len)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 buf[len - 1] = '\0';
154 strncpy(buf, ioc.vols[i].device_name, len - 1);
155 break;
156 }
157 }
158 assert(i != ioc.nvols); /* root volume must exist */
159
160 free(ioc.vols);
161 return(0);
162 }
163
164 /*
165 * Functions and data structure for zone statistics
166 */
167 /*
168 * Each layer1 needs ((2^19) / 64) = 8192 uint64_t.
169 */
170 #define HAMMER_LAYER1_UINT64 8192
171 #define HAMMER_LAYER1_BYTES (HAMMER_LAYER1_UINT64 * sizeof(uint64_t))
172
173 static int *l1_max = NULL;
174 static uint64_t **l1_bits = NULL;
175
176 static __inline
177 int
hammer_set_layer_bits(uint64_t * bits,int i)178 hammer_set_layer_bits(uint64_t *bits, int i)
179 {
180 int q, r;
181
182 q = i >> 6;
183 r = i & ((1 << 6) - 1);
184
185 bits += q;
186 if (!((*bits) & ((uint64_t)1 << r))) {
187 (*bits) |= ((uint64_t)1 << r);
188 return(1);
189 }
190 return(0); /* already seen this block */
191 }
192
193 static
194 void
hammer_extend_layer1_bits(int vol,int newsiz,int oldsiz)195 hammer_extend_layer1_bits(int vol, int newsiz, int oldsiz)
196 {
197 uint64_t *p;
198
199 assert(newsiz > oldsiz);
200 assert(newsiz > 0 && oldsiz >= 0);
201
202 p = l1_bits[vol];
203 if (p == NULL)
204 p = malloc(HAMMER_LAYER1_BYTES * newsiz);
205 else
206 p = realloc(p, HAMMER_LAYER1_BYTES * newsiz);
207 if (p == NULL) {
208 err(1, "alloc");
209 /* not reached */
210 }
211 l1_bits[vol] = p;
212
213 p += HAMMER_LAYER1_UINT64 * oldsiz;
214 bzero(p, HAMMER_LAYER1_BYTES * (newsiz - oldsiz));
215 }
216
217 zone_stat_t
hammer_init_zone_stat(void)218 hammer_init_zone_stat(void)
219 {
220 return(calloc(HAMMER_MAX_ZONES, sizeof(struct zone_stat)));
221 }
222
223 zone_stat_t
hammer_init_zone_stat_bits(void)224 hammer_init_zone_stat_bits(void)
225 {
226 int i;
227
228 l1_max = calloc(HAMMER_MAX_VOLUMES, sizeof(int));
229 if (l1_max == NULL) {
230 err(1, "calloc");
231 /* not reached */
232 }
233
234 l1_bits = calloc(HAMMER_MAX_VOLUMES, sizeof(uint64_t*));
235 if (l1_bits == NULL) {
236 err(1, "calloc");
237 /* not reached */
238 }
239
240 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) {
241 l1_max[i] = -1; /* +1 needs to be 0 */
242 l1_bits[i] = NULL;
243 }
244 return(hammer_init_zone_stat());
245 }
246
247 void
hammer_cleanup_zone_stat(zone_stat_t stats)248 hammer_cleanup_zone_stat(zone_stat_t stats)
249 {
250 int i;
251
252 if (l1_bits) {
253 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) {
254 free(l1_bits[i]);
255 l1_bits[i] = NULL;
256 }
257 }
258
259 free(l1_bits);
260 l1_bits = NULL;
261
262 free(l1_max);
263 l1_max = NULL;
264
265 free(stats);
266 }
267
268 static
269 void
_hammer_add_zone_stat(zone_stat_t stats,int zone,int bytes,int new_block,int new_item)270 _hammer_add_zone_stat(zone_stat_t stats, int zone, int bytes,
271 int new_block, int new_item)
272 {
273 zone_stat_t sp = stats + zone;
274
275 if (new_block)
276 sp->blocks++;
277 if (new_item)
278 sp->items++;
279 sp->used += bytes;
280 }
281
282 void
hammer_add_zone_stat(zone_stat_t stats,hammer_off_t offset,int bytes)283 hammer_add_zone_stat(zone_stat_t stats, hammer_off_t offset, int bytes)
284 {
285 int zone, vol, i, j, new_block;
286 uint64_t *p;
287
288 offset &= ~HAMMER_BIGBLOCK_MASK64;
289 zone = HAMMER_ZONE_DECODE(offset);
290 vol = HAMMER_VOL_DECODE(offset);
291
292 offset = HAMMER_OFF_SHORT_ENCODE(offset); /* cut off volume bits */
293 i = HAMMER_BLOCKMAP_LAYER1_INDEX(offset);
294 j = HAMMER_BLOCKMAP_LAYER2_INDEX(offset);
295
296 if (i > l1_max[vol]) {
297 assert(i < (HAMMER_BLOCKMAP_RADIX1 / HAMMER_MAX_VOLUMES));
298 hammer_extend_layer1_bits(vol, i + 1, l1_max[vol] + 1);
299 l1_max[vol] = i;
300 }
301
302 p = l1_bits[vol] + i * HAMMER_LAYER1_UINT64;
303 new_block = hammer_set_layer_bits(p, j);
304 _hammer_add_zone_stat(stats, zone, bytes, new_block, 1);
305 }
306
307 /*
308 * If the same layer2 is used more than once the result will be wrong.
309 */
310 void
hammer_add_zone_stat_layer2(zone_stat_t stats,hammer_blockmap_layer2_t layer2)311 hammer_add_zone_stat_layer2(zone_stat_t stats,
312 hammer_blockmap_layer2_t layer2)
313 {
314 _hammer_add_zone_stat(stats, layer2->zone,
315 HAMMER_BIGBLOCK_SIZE - layer2->bytes_free, 1, 0);
316 }
317
318 static __inline
319 double
_calc_used_percentage(int64_t blocks,int64_t used)320 _calc_used_percentage(int64_t blocks, int64_t used)
321 {
322 double res;
323
324 if (blocks)
325 res = ((double)(used * 100)) / (blocks << HAMMER_BIGBLOCK_BITS);
326 else
327 res = 0;
328 return(res);
329 }
330
331 void
hammer_print_zone_stat(zone_stat_t stats)332 hammer_print_zone_stat(zone_stat_t stats)
333 {
334 int i;
335 int64_t total_blocks = 0;
336 int64_t total_items = 0;
337 int64_t total_used = 0;
338 zone_stat_t p = stats;
339 #define INDENT ""
340
341 printf("HAMMER zone statistics\n");
342 printf(INDENT"zone # "
343 "blocks items used[B] used[%%]\n");
344 for (i = 0; i < HAMMER_MAX_ZONES; i++) {
345 printf(INDENT"zone %-2d %-10s %-12ju %-18ju %-19ju %g\n",
346 i, zone_labels[i], p->blocks, p->items, p->used,
347 _calc_used_percentage(p->blocks, p->used));
348 total_blocks += p->blocks;
349 total_items += p->items;
350 total_used += p->used;
351 p++;
352 }
353
354 /*
355 * Remember that zone0 is always 0% used and zone15 is
356 * always 100% used.
357 */
358 printf(INDENT"--------------------------------------------------------------------------------\n");
359 printf(INDENT"total %-12ju %-18ju %-19ju %g\n",
360 (uintmax_t)total_blocks,
361 (uintmax_t)total_items,
362 (uintmax_t)total_used,
363 _calc_used_percentage(total_blocks, total_used));
364 }
365