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 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 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 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 218 hammer_init_zone_stat(void) 219 { 220 return(calloc(HAMMER_MAX_ZONES, sizeof(struct zone_stat))); 221 } 222 223 zone_stat_t 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 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 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 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 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 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 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