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 /* 201 * Functions and data structure for zone statistics 202 */ 203 /* 204 * Each layer1 needs ((2^19) / 64) = 8192 uint64_t. 205 */ 206 #define HAMMER_LAYER1_UINT64 8192 207 #define HAMMER_LAYER1_BYTES (HAMMER_LAYER1_UINT64 * sizeof(uint64_t)) 208 209 static int *l1_max = NULL; 210 static uint64_t **l1_bits = NULL; 211 212 static __inline 213 int 214 hammer_set_layer_bits(uint64_t *bits, int i) 215 { 216 int q, r; 217 218 q = i >> 6; 219 r = i & ((1 << 6) - 1); 220 221 bits += q; 222 if (!((*bits) & ((uint64_t)1 << r))) { 223 (*bits) |= ((uint64_t)1 << r); 224 return(1); 225 } 226 return(0); /* already seen this block */ 227 } 228 229 static 230 void 231 hammer_extend_layer1_bits(int vol, int newsiz, int oldsiz) 232 { 233 uint64_t *p; 234 235 assert(newsiz > oldsiz); 236 assert(newsiz > 0 && oldsiz >= 0); 237 238 p = l1_bits[vol]; 239 if (p == NULL) 240 p = malloc(HAMMER_LAYER1_BYTES * newsiz); 241 else 242 p = realloc(p, HAMMER_LAYER1_BYTES * newsiz); 243 if (p == NULL) 244 perror("alloc"); 245 l1_bits[vol] = p; 246 247 p += HAMMER_LAYER1_UINT64 * oldsiz; 248 bzero((void*)p, HAMMER_LAYER1_BYTES * (newsiz - oldsiz)); 249 } 250 251 static 252 void 253 hammer_dump_layer1_bits(void) 254 { 255 int i, j, n; 256 257 assert(l1_bits); 258 printf("Layer1 bitmaps\n"); 259 260 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) { 261 if (l1_max[i] != -1) { 262 printf("volume=%d %p\n", i, l1_bits[i]); 263 n = (l1_max[i] + 1) * HAMMER_LAYER1_UINT64; 264 for (j = 0; j < n; j++) { 265 printf("\tblock[%d][%d]=0x%016lX\n", 266 i, j << 6, *(l1_bits[i] + j)); 267 } 268 } 269 } 270 } 271 272 struct zone_stat* 273 hammer_init_zone_stat(void) 274 { 275 return calloc(HAMMER_MAX_ZONES, sizeof(struct zone_stat)); 276 } 277 278 struct zone_stat* 279 hammer_init_zone_stat_bits(void) 280 { 281 int i; 282 283 l1_max = calloc(HAMMER_MAX_VOLUMES, sizeof(int)); 284 if (l1_max == NULL) 285 perror("calloc"); 286 287 l1_bits = calloc(HAMMER_MAX_VOLUMES, sizeof(uint64_t*)); 288 if (l1_bits == NULL) 289 perror("calloc"); 290 291 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) { 292 l1_max[i] = -1; /* +1 needs to be 0 */ 293 l1_bits[i] = NULL; 294 } 295 return(hammer_init_zone_stat()); 296 } 297 298 void 299 hammer_cleanup_zone_stat(struct zone_stat *stats) 300 { 301 int i; 302 303 if (l1_bits) { 304 if (DebugOpt) 305 hammer_dump_layer1_bits(); 306 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) { 307 free(l1_bits[i]); 308 l1_bits[i] = NULL; 309 } 310 } 311 312 free(l1_bits); 313 l1_bits = NULL; 314 315 free(l1_max); 316 l1_max = NULL; 317 318 free(stats); 319 } 320 321 static 322 void 323 _hammer_add_zone_stat(struct zone_stat *stats, int zone, 324 hammer_off_t bytes, int new_block, int new_item) 325 { 326 struct zone_stat *stat = stats + zone; 327 328 if (new_block) 329 stat->blocks++; 330 if (new_item) 331 stat->items++; 332 stat->used += bytes; 333 } 334 335 void 336 hammer_add_zone_stat(struct zone_stat *stats, hammer_off_t offset, 337 hammer_off_t bytes) 338 { 339 int zone, vol, i, j, new_block; 340 uint64_t *p; 341 342 offset &= ~HAMMER_BIGBLOCK_MASK64; 343 zone = HAMMER_ZONE_DECODE(offset); 344 vol = HAMMER_VOL_DECODE(offset); 345 346 offset &= HAMMER_OFF_SHORT_MASK; /* cut off volume bits from layer1 */ 347 i = (int)HAMMER_BLOCKMAP_LAYER1_INDEX(offset); 348 j = (int)HAMMER_BLOCKMAP_LAYER2_INDEX(offset); 349 350 if (i > l1_max[vol]) { 351 assert(i < 1024); /* XXX hardcoded */ 352 hammer_extend_layer1_bits(vol, i + 1, l1_max[vol] + 1); 353 l1_max[vol] = i; 354 } 355 356 p = l1_bits[vol] + i * HAMMER_LAYER1_UINT64; 357 new_block = hammer_set_layer_bits(p, j); 358 _hammer_add_zone_stat(stats, zone, bytes, new_block, 1); 359 } 360 361 /* 362 * If the same layer2 is used more than once the result will be wrong. 363 */ 364 void 365 hammer_add_zone_stat_layer2(struct zone_stat *stats, 366 struct hammer_blockmap_layer2 *layer2) 367 { 368 _hammer_add_zone_stat(stats, layer2->zone, 369 HAMMER_BIGBLOCK_SIZE - layer2->bytes_free, 1, 0); 370 } 371 372 void 373 hammer_print_zone_stat(const struct zone_stat *stats) 374 { 375 int i; 376 double per; 377 hammer_off_t total_blocks = 0; 378 hammer_off_t total_items = 0; 379 hammer_off_t total_used = 0; 380 const struct zone_stat *p = stats; 381 382 printf("HAMMER zone statistics\n"); 383 printf("\tzone # blocks items used[B] used[%%]\n"); 384 385 for (i = 0; i < HAMMER_MAX_ZONES; i++) { 386 if (p->blocks) 387 per = ((double)(p->used * 100)) / 388 (p->blocks * HAMMER_BIGBLOCK_SIZE); 389 else 390 per = 0; 391 printf("\tzone %-2d %-12ju %-18ju %-19ju %g\n", 392 i, p->blocks, p->items, p->used, per); 393 total_blocks += p->blocks; 394 total_items += p->items; 395 total_used += p->used; 396 p++; 397 } 398 399 /* 400 * Remember that zone0 is always 0% used and zone15 is 401 * always 100% used. 402 */ 403 if (total_blocks) 404 per = ((double)(total_used * 100)) / 405 (total_blocks * HAMMER_BIGBLOCK_SIZE); 406 else 407 per = 0; 408 409 printf("\t----------------------------------------------------------------------\n"); 410 printf("\ttotal %-12ju %-18ju %-19ju %g\n", 411 (uintmax_t)total_blocks, (uintmax_t)total_items, 412 (uintmax_t)total_used, per); 413 } 414