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 * Layer1 needs ((2^18) / 64) = 4096 uint64_t and 205 * Layer2 needs ((2^19) / 64) = 8192 uint64_t for each Layer1 on demand. 206 */ 207 #define HAMMER_LAYER1_UINT64 4096 208 #define HAMMER_LAYER2_UINT64 8192 209 #define HAMMER_LAYER1_BYTES (HAMMER_LAYER1_UINT64 * sizeof(uint64_t)) 210 #define HAMMER_LAYER2_BYTES (HAMMER_LAYER2_UINT64 * sizeof(uint64_t)) 211 212 static uint64_t *l1_bits = NULL; 213 static uint64_t *l2_bits = NULL; 214 static int l1_max = 0; 215 216 static __inline 217 int 218 hammer_set_layer_bits(uint64_t *bits, int i) 219 { 220 int q, r; 221 222 q = i >> 6; 223 r = i & ((1 << 6) - 1); 224 225 bits += q; 226 if (!((*bits) & ((uint64_t)1 << r))) { 227 (*bits) |= ((uint64_t)1 << r); 228 return(1); 229 } 230 return(0); /* already seen this block */ 231 } 232 233 static 234 void 235 hammer_extend_layer2_bits(int newsiz, int oldsiz) 236 { 237 uint64_t *p; 238 239 assert(newsiz > oldsiz); 240 if (l2_bits == NULL) 241 l2_bits = malloc(HAMMER_LAYER2_BYTES * newsiz); 242 else 243 l2_bits = realloc(l2_bits, HAMMER_LAYER2_BYTES * newsiz); 244 if (l2_bits == NULL) 245 perror("alloc"); 246 247 p = l2_bits + HAMMER_LAYER2_UINT64 * oldsiz; 248 bzero((void*)p, HAMMER_LAYER2_BYTES * (newsiz - oldsiz)); 249 } 250 251 struct zone_stat* 252 hammer_init_zone_stat(void) 253 { 254 return calloc(HAMMER_MAX_ZONES, sizeof(struct zone_stat)); 255 } 256 257 struct zone_stat* 258 hammer_init_zone_stat_bits(void) 259 { 260 l1_bits = malloc(HAMMER_LAYER1_BYTES); 261 if (l1_bits == NULL) 262 perror("malloc"); 263 bzero(l1_bits, HAMMER_LAYER1_BYTES); 264 assert(hammer_set_layer_bits(l1_bits, 0) == 1); 265 266 hammer_extend_layer2_bits(1, 0); 267 268 return(hammer_init_zone_stat()); 269 } 270 271 void 272 hammer_cleanup_zone_stat(struct zone_stat *stats) 273 { 274 l1_max = 0; 275 free(l1_bits); 276 free(l2_bits); 277 free(stats); 278 } 279 280 static 281 void 282 _hammer_add_zone_stat(struct zone_stat *stats, int zone, 283 hammer_off_t bytes, int new_block, int new_item) 284 { 285 struct zone_stat *stat = stats + zone; 286 287 if (new_block) 288 stat->blocks++; 289 if (new_item) 290 stat->items++; 291 stat->used += bytes; 292 } 293 294 void 295 hammer_add_zone_stat(struct zone_stat *stats, hammer_off_t offset, 296 hammer_off_t bytes) 297 { 298 int zone, new_block, i, j; 299 300 offset &= ~HAMMER_BIGBLOCK_MASK64; 301 zone = HAMMER_ZONE_DECODE(offset); 302 i = (int)HAMMER_BLOCKMAP_LAYER1_INDEX(offset); 303 j = (int)HAMMER_BLOCKMAP_LAYER2_INDEX(offset); 304 new_block = 0; 305 306 if (i > l1_max) { 307 hammer_extend_layer2_bits(i + 1, l1_max + 1); 308 new_block |= hammer_set_layer_bits(l1_bits, i); 309 assert(new_block == 1); 310 l1_max = i; 311 } 312 313 new_block |= hammer_set_layer_bits(l2_bits + i, j); 314 _hammer_add_zone_stat(stats, zone, bytes, new_block, 1); 315 } 316 317 /* 318 * If the same layer2 is used more than once the result will be wrong. 319 */ 320 void 321 hammer_add_zone_stat_layer2(struct zone_stat *stats, 322 struct hammer_blockmap_layer2 *layer2) 323 { 324 _hammer_add_zone_stat(stats, layer2->zone, 325 HAMMER_BIGBLOCK_SIZE - layer2->bytes_free, 1, 0); 326 } 327 328 void 329 hammer_print_zone_stat(const struct zone_stat *stats) 330 { 331 int i; 332 double per; 333 hammer_off_t total_blocks = 0; 334 hammer_off_t total_items = 0; 335 hammer_off_t total_used = 0; 336 const struct zone_stat *p = stats; 337 338 printf("HAMMER zone statistics\n"); 339 printf("\tzone # blocks items used[B] used[%%]\n"); 340 341 for (i = 0; i < HAMMER_MAX_ZONES; i++) { 342 if (p->blocks) 343 per = ((double)(p->used * 100)) / 344 (p->blocks * HAMMER_BIGBLOCK_SIZE); 345 else 346 per = 0; 347 printf("\tzone %-2d %-12ju %-18ju %-19ju %g\n", 348 i, p->blocks, p->items, p->used, per); 349 total_blocks += p->blocks; 350 total_items += p->items; 351 total_used += p->used; 352 p++; 353 } 354 355 /* 356 * Remember that zone0 is always 0% used and zone15 is 357 * always 100% used. 358 */ 359 if (total_blocks) 360 per = ((double)(total_used * 100)) / 361 (total_blocks * HAMMER_BIGBLOCK_SIZE); 362 else 363 per = 0; 364 365 printf("\t----------------------------------------------------------------------\n"); 366 printf("\ttotal %-12ju %-18ju %-19ju %g\n", 367 (uintmax_t)total_blocks, (uintmax_t)total_items, 368 (uintmax_t)total_used, per); 369 } 370