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.h" 38 39 const char *ScoreBoardFile; 40 41 /* 42 * (taken from /usr/src/sys/vfs/hammer/hammer_btree.c) 43 * 44 * Compare two B-Tree elements, return -N, 0, or +N (e.g. similar to strcmp). 45 * 46 * Note that for this particular function a return value of -1, 0, or +1 47 * can denote a match if delete_tid is otherwise discounted. A delete_tid 48 * of zero is considered to be 'infinity' in comparisons. 49 * 50 * See also hammer_rec_rb_compare() and hammer_rec_cmp() in hammer_object.c. 51 */ 52 int 53 hammer_btree_cmp(hammer_base_elm_t key1, hammer_base_elm_t key2) 54 { 55 if (key1->localization < key2->localization) 56 return(-5); 57 if (key1->localization > key2->localization) 58 return(5); 59 60 if (key1->obj_id < key2->obj_id) 61 return(-4); 62 if (key1->obj_id > key2->obj_id) 63 return(4); 64 65 if (key1->rec_type < key2->rec_type) 66 return(-3); 67 if (key1->rec_type > key2->rec_type) 68 return(3); 69 70 if (key1->key < key2->key) 71 return(-2); 72 if (key1->key > key2->key) 73 return(2); 74 75 if (key1->create_tid == 0) { 76 if (key2->create_tid == 0) 77 return(0); 78 return(1); 79 } 80 if (key2->create_tid == 0) 81 return(-1); 82 if (key1->create_tid < key2->create_tid) 83 return(-1); 84 if (key1->create_tid > key2->create_tid) 85 return(1); 86 return(0); 87 } 88 89 void 90 hammer_key_beg_init(hammer_base_elm_t base) 91 { 92 bzero(base, sizeof(*base)); 93 94 base->localization = HAMMER_MIN_LOCALIZATION; 95 base->obj_id = HAMMER_MIN_OBJID; 96 base->key = HAMMER_MIN_KEY; 97 base->create_tid = 1; 98 base->rec_type = HAMMER_MIN_RECTYPE; 99 } 100 101 void 102 hammer_key_end_init(hammer_base_elm_t base) 103 { 104 bzero(base, sizeof(*base)); 105 106 base->localization = HAMMER_MAX_LOCALIZATION; 107 base->obj_id = HAMMER_MAX_OBJID; 108 base->key = HAMMER_MAX_KEY; 109 base->create_tid = HAMMER_MAX_TID; 110 base->rec_type = HAMMER_MAX_RECTYPE; 111 } 112 113 int 114 hammer_crc_test_leaf(void *data, hammer_btree_leaf_elm_t leaf) 115 { 116 hammer_crc_t crc; 117 118 if (leaf->data_len == 0) { 119 crc = 0; 120 } else { 121 switch(leaf->base.rec_type) { 122 case HAMMER_RECTYPE_INODE: 123 if (leaf->data_len != sizeof(struct hammer_inode_data)) 124 return(0); 125 crc = crc32(data, HAMMER_INODE_CRCSIZE); 126 break; 127 default: 128 crc = crc32(data, leaf->data_len); 129 break; 130 } 131 } 132 return (leaf->data_crc == crc); 133 } 134 135 void 136 score_printf(size_t i, size_t w, const char *ctl, ...) 137 { 138 va_list va; 139 size_t n; 140 static size_t SSize; 141 static int SFd = -1; 142 static char ScoreBuf[1024]; 143 144 if (ScoreBoardFile == NULL) 145 return; 146 assert(i + w < sizeof(ScoreBuf)); 147 if (SFd < 0) { 148 SFd = open(ScoreBoardFile, O_RDWR|O_CREAT|O_TRUNC, 0644); 149 if (SFd < 0) 150 return; 151 SSize = 0; 152 } 153 for (n = 0; n < i; ++n) { 154 if (ScoreBuf[n] == 0) 155 ScoreBuf[n] = ' '; 156 } 157 va_start(va, ctl); 158 vsnprintf(ScoreBuf + i, w - 1, ctl, va); 159 va_end(va); 160 n = strlen(ScoreBuf + i); 161 while (n < w - 1) { 162 ScoreBuf[i + n] = ' '; 163 ++n; 164 } 165 ScoreBuf[i + n] = '\n'; 166 if (SSize < i + w) 167 SSize = i + w; 168 pwrite(SFd, ScoreBuf, SSize, 0); 169 } 170 171 void 172 hammer_check_restrict(const char *filesystem) 173 { 174 size_t rlen; 175 int atslash; 176 177 if (RestrictTarget == NULL) 178 return; 179 rlen = strlen(RestrictTarget); 180 if (strncmp(filesystem, RestrictTarget, rlen) != 0) { 181 fprintf(stderr, "hammer-remote: restricted target\n"); 182 exit(1); 183 } 184 atslash = 1; 185 while (filesystem[rlen]) { 186 if (atslash && 187 filesystem[rlen] == '.' && 188 filesystem[rlen+1] == '.') { 189 fprintf(stderr, "hammer-remote: '..' not allowed\n"); 190 exit(1); 191 } 192 if (filesystem[rlen] == '/') 193 atslash = 1; 194 else 195 atslash = 0; 196 ++rlen; 197 } 198 } 199 200 int 201 getyn(void) 202 { 203 char buf[256]; 204 int len; 205 206 if (fgets(buf, sizeof(buf), stdin) == NULL) 207 return(0); 208 len = strlen(buf); 209 while (len && (buf[len-1] == '\n' || buf[len-1] == '\r')) 210 --len; 211 buf[len] = 0; 212 if (strcmp(buf, "y") == 0 || 213 strcmp(buf, "yes") == 0 || 214 strcmp(buf, "Y") == 0 || 215 strcmp(buf, "YES") == 0) { 216 return(1); 217 } 218 return(0); 219 } 220 221 int 222 hammer_fs_to_vol(const char *fs, struct hammer_ioc_volume_list *p) 223 { 224 struct hammer_ioc_volume_list ioc; 225 int fd; 226 227 fd = open(fs, O_RDONLY); 228 if (fd < 0) { 229 perror("open"); 230 return(-1); 231 } 232 233 bzero(&ioc, sizeof(ioc)); 234 ioc.nvols = HAMMER_MAX_VOLUMES; 235 ioc.vols = malloc(ioc.nvols * sizeof(*ioc.vols)); 236 if (ioc.vols == NULL) { 237 perror("malloc"); 238 close(fd); 239 return(-1); 240 } 241 242 if (ioctl(fd, HAMMERIOC_LIST_VOLUMES, &ioc) < 0) { 243 perror("ioctl"); 244 close(fd); 245 free(ioc.vols); 246 return(-1); 247 } 248 249 bcopy(&ioc, p, sizeof(ioc)); 250 close(fd); 251 252 return(0); 253 } 254 255 int 256 hammer_fs_to_rootvol(const char *fs, char *buf, int len) 257 { 258 struct hammer_ioc_volume_list ioc; 259 int i; 260 261 if (hammer_fs_to_vol(fs, &ioc) == -1) 262 return(-1); 263 264 for (i = 0; i < ioc.nvols; i++) { 265 if (ioc.vols[i].vol_no == HAMMER_ROOT_VOLNO) { 266 strlcpy(buf, ioc.vols[i].device_name, len); 267 break; 268 } 269 } 270 assert(i != ioc.nvols); /* root volume must exist */ 271 272 free(ioc.vols); 273 return(0); 274 } 275 276 /* 277 * Functions and data structure for zone statistics 278 */ 279 /* 280 * Each layer1 needs ((2^19) / 64) = 8192 uint64_t. 281 */ 282 #define HAMMER_LAYER1_UINT64 8192 283 #define HAMMER_LAYER1_BYTES (HAMMER_LAYER1_UINT64 * sizeof(uint64_t)) 284 285 static int *l1_max = NULL; 286 static uint64_t **l1_bits = NULL; 287 288 static __inline 289 int 290 hammer_set_layer_bits(uint64_t *bits, int i) 291 { 292 int q, r; 293 294 q = i >> 6; 295 r = i & ((1 << 6) - 1); 296 297 bits += q; 298 if (!((*bits) & ((uint64_t)1 << r))) { 299 (*bits) |= ((uint64_t)1 << r); 300 return(1); 301 } 302 return(0); /* already seen this block */ 303 } 304 305 static 306 void 307 hammer_extend_layer1_bits(int vol, int newsiz, int oldsiz) 308 { 309 uint64_t *p; 310 311 assert(newsiz > oldsiz); 312 assert(newsiz > 0 && oldsiz >= 0); 313 314 p = l1_bits[vol]; 315 if (p == NULL) 316 p = malloc(HAMMER_LAYER1_BYTES * newsiz); 317 else 318 p = realloc(p, HAMMER_LAYER1_BYTES * newsiz); 319 if (p == NULL) 320 err(1, "alloc"); 321 l1_bits[vol] = p; 322 323 p += HAMMER_LAYER1_UINT64 * oldsiz; 324 bzero((void*)p, HAMMER_LAYER1_BYTES * (newsiz - oldsiz)); 325 } 326 327 static 328 void 329 hammer_dump_layer1_bits(void) 330 { 331 int i, j, n; 332 333 assert(l1_bits); 334 printf("Layer1 bitmaps\n"); 335 336 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) { 337 if (l1_max[i] != -1) { 338 printf("volume=%d %p\n", i, l1_bits[i]); 339 n = (l1_max[i] + 1) * HAMMER_LAYER1_UINT64; 340 for (j = 0; j < n; j++) { 341 printf("\tblock[%d][%d]=0x%016lX\n", 342 i, j << 6, *(l1_bits[i] + j)); 343 } 344 } 345 } 346 } 347 348 struct zone_stat* 349 hammer_init_zone_stat(void) 350 { 351 return calloc(HAMMER_MAX_ZONES, sizeof(struct zone_stat)); 352 } 353 354 struct zone_stat* 355 hammer_init_zone_stat_bits(void) 356 { 357 int i; 358 359 l1_max = calloc(HAMMER_MAX_VOLUMES, sizeof(int)); 360 if (l1_max == NULL) 361 err(1, "calloc"); 362 363 l1_bits = calloc(HAMMER_MAX_VOLUMES, sizeof(uint64_t*)); 364 if (l1_bits == NULL) 365 err(1, "calloc"); 366 367 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) { 368 l1_max[i] = -1; /* +1 needs to be 0 */ 369 l1_bits[i] = NULL; 370 } 371 return(hammer_init_zone_stat()); 372 } 373 374 void 375 hammer_cleanup_zone_stat(struct zone_stat *stats) 376 { 377 int i; 378 379 if (l1_bits) { 380 if (DebugOpt) 381 hammer_dump_layer1_bits(); 382 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) { 383 free(l1_bits[i]); 384 l1_bits[i] = NULL; 385 } 386 } 387 388 free(l1_bits); 389 l1_bits = NULL; 390 391 free(l1_max); 392 l1_max = NULL; 393 394 free(stats); 395 } 396 397 static 398 void 399 _hammer_add_zone_stat(struct zone_stat *stats, int zone, 400 hammer_off_t bytes, int new_block, int new_item) 401 { 402 struct zone_stat *sp = stats + zone; 403 404 if (new_block) 405 sp->blocks++; 406 if (new_item) 407 sp->items++; 408 sp->used += bytes; 409 } 410 411 void 412 hammer_add_zone_stat(struct zone_stat *stats, hammer_off_t offset, 413 hammer_off_t bytes) 414 { 415 int zone, vol, i, j, new_block; 416 uint64_t *p; 417 418 offset &= ~HAMMER_BIGBLOCK_MASK64; 419 zone = HAMMER_ZONE_DECODE(offset); 420 vol = HAMMER_VOL_DECODE(offset); 421 422 offset &= HAMMER_OFF_SHORT_MASK; /* cut off volume bits from layer1 */ 423 i = HAMMER_BLOCKMAP_LAYER1_INDEX(offset); 424 j = HAMMER_BLOCKMAP_LAYER2_INDEX(offset); 425 426 if (i > l1_max[vol]) { 427 assert(i < 1024); /* XXX hardcoded */ 428 hammer_extend_layer1_bits(vol, i + 1, l1_max[vol] + 1); 429 l1_max[vol] = i; 430 } 431 432 p = l1_bits[vol] + i * HAMMER_LAYER1_UINT64; 433 new_block = hammer_set_layer_bits(p, j); 434 _hammer_add_zone_stat(stats, zone, bytes, new_block, 1); 435 } 436 437 /* 438 * If the same layer2 is used more than once the result will be wrong. 439 */ 440 void 441 hammer_add_zone_stat_layer2(struct zone_stat *stats, 442 struct hammer_blockmap_layer2 *layer2) 443 { 444 _hammer_add_zone_stat(stats, layer2->zone, 445 HAMMER_BIGBLOCK_SIZE - layer2->bytes_free, 1, 0); 446 } 447 448 void 449 hammer_print_zone_stat(const struct zone_stat *stats) 450 { 451 int i; 452 double per; 453 hammer_off_t total_blocks = 0; 454 hammer_off_t total_items = 0; 455 hammer_off_t total_used = 0; 456 const struct zone_stat *p = stats; 457 458 printf("HAMMER zone statistics\n"); 459 printf("\tzone # blocks items used[B] used[%%]\n"); 460 461 for (i = 0; i < HAMMER_MAX_ZONES; i++) { 462 if (p->blocks) 463 per = ((double)(p->used * 100)) / 464 (p->blocks * HAMMER_BIGBLOCK_SIZE); 465 else 466 per = 0; 467 printf("\tzone %-2d %-12ju %-18ju %-19ju %g\n", 468 i, p->blocks, p->items, p->used, per); 469 total_blocks += p->blocks; 470 total_items += p->items; 471 total_used += p->used; 472 p++; 473 } 474 475 /* 476 * Remember that zone0 is always 0% used and zone15 is 477 * always 100% used. 478 */ 479 if (total_blocks) 480 per = ((double)(total_used * 100)) / 481 (total_blocks * HAMMER_BIGBLOCK_SIZE); 482 else 483 per = 0; 484 485 printf("\t----------------------------------------------------------------------\n"); 486 printf("\ttotal %-12ju %-18ju %-19ju %g\n", 487 (uintmax_t)total_blocks, (uintmax_t)total_items, 488 (uintmax_t)total_used, per); 489 } 490