hyperv/vmbus: Make sure that interrupt cputimer can be enabled.
[dragonfly.git] / sbin / hammer / misc.c
blob1f49592f864fa4ac8adcf5d59ebb4ac59612b10e
1 /*
2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
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.
34 * $DragonFly: src/sbin/hammer/misc.c,v 1.5 2008/06/26 04:07:57 dillon Exp $
37 #include "hammer.h"
39 const char *ScoreBoardFile;
42 * (taken from /usr/src/sys/vfs/hammer/hammer_btree.c)
44 * Compare two B-Tree elements, return -N, 0, or +N (e.g. similar to strcmp).
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.
50 * See also hammer_rec_rb_compare() and hammer_rec_cmp() in hammer_object.c.
52 int
53 hammer_btree_cmp(hammer_base_elm_t key1, hammer_base_elm_t key2)
55 if (key1->localization < key2->localization)
56 return(-5);
57 if (key1->localization > key2->localization)
58 return(5);
60 if (key1->obj_id < key2->obj_id)
61 return(-4);
62 if (key1->obj_id > key2->obj_id)
63 return(4);
65 if (key1->rec_type < key2->rec_type)
66 return(-3);
67 if (key1->rec_type > key2->rec_type)
68 return(3);
70 if (key1->key < key2->key)
71 return(-2);
72 if (key1->key > key2->key)
73 return(2);
75 if (key1->create_tid == 0) {
76 if (key2->create_tid == 0)
77 return(0);
78 return(1);
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);
89 void
90 hammer_key_beg_init(hammer_base_elm_t base)
92 bzero(base, sizeof(*base));
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;
101 void
102 hammer_key_end_init(hammer_base_elm_t base)
104 bzero(base, sizeof(*base));
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;
114 hammer_crc_test_leaf(void *data, hammer_btree_leaf_elm_t leaf)
116 hammer_crc_t crc;
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;
132 return (leaf->data_crc == crc);
135 void
136 score_printf(size_t i, size_t w, const char *ctl, ...)
138 va_list va;
139 size_t n;
140 static size_t SSize;
141 static int SFd = -1;
142 static char ScoreBuf[1024];
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;
153 for (n = 0; n < i; ++n) {
154 if (ScoreBuf[n] == 0)
155 ScoreBuf[n] = ' ';
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;
165 ScoreBuf[i + n] = '\n';
166 if (SSize < i + w)
167 SSize = i + w;
168 pwrite(SFd, ScoreBuf, SSize, 0);
171 void
172 hammer_check_restrict(const char *filesystem)
174 size_t rlen;
175 int atslash;
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);
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);
192 if (filesystem[rlen] == '/')
193 atslash = 1;
194 else
195 atslash = 0;
196 ++rlen;
201 getyn(void)
203 char buf[256];
204 int len;
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);
218 return(0);
222 hammer_fs_to_vol(const char *fs, struct hammer_ioc_volume_list *p)
224 struct hammer_ioc_volume_list ioc;
225 int fd;
227 fd = open(fs, O_RDONLY);
228 if (fd < 0) {
229 perror("open");
230 return(-1);
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);
242 if (ioctl(fd, HAMMERIOC_LIST_VOLUMES, &ioc) < 0) {
243 perror("ioctl");
244 close(fd);
245 free(ioc.vols);
246 return(-1);
249 bcopy(&ioc, p, sizeof(ioc));
250 close(fd);
252 return(0);
256 hammer_fs_to_rootvol(const char *fs, char *buf, int len)
258 struct hammer_ioc_volume_list ioc;
259 int i;
261 if (hammer_fs_to_vol(fs, &ioc) == -1)
262 return(-1);
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;
270 assert(i != ioc.nvols); /* root volume must exist */
272 free(ioc.vols);
273 return(0);
277 * Functions and data structure for zone statistics
280 * Each layer1 needs ((2^19) / 64) = 8192 uint64_t.
282 #define HAMMER_LAYER1_UINT64 8192
283 #define HAMMER_LAYER1_BYTES (HAMMER_LAYER1_UINT64 * sizeof(uint64_t))
285 static int *l1_max = NULL;
286 static uint64_t **l1_bits = NULL;
288 static __inline
290 hammer_set_layer_bits(uint64_t *bits, int i)
292 int q, r;
294 q = i >> 6;
295 r = i & ((1 << 6) - 1);
297 bits += q;
298 if (!((*bits) & ((uint64_t)1 << r))) {
299 (*bits) |= ((uint64_t)1 << r);
300 return(1);
302 return(0); /* already seen this block */
305 static
306 void
307 hammer_extend_layer1_bits(int vol, int newsiz, int oldsiz)
309 uint64_t *p;
311 assert(newsiz > oldsiz);
312 assert(newsiz > 0 && oldsiz >= 0);
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;
323 p += HAMMER_LAYER1_UINT64 * oldsiz;
324 bzero(p, HAMMER_LAYER1_BYTES * (newsiz - oldsiz));
327 struct zone_stat*
328 hammer_init_zone_stat(void)
330 return(calloc(HAMMER_MAX_ZONES, sizeof(struct zone_stat)));
333 struct zone_stat*
334 hammer_init_zone_stat_bits(void)
336 int i;
338 l1_max = calloc(HAMMER_MAX_VOLUMES, sizeof(int));
339 if (l1_max == NULL)
340 err(1, "calloc");
342 l1_bits = calloc(HAMMER_MAX_VOLUMES, sizeof(uint64_t*));
343 if (l1_bits == NULL)
344 err(1, "calloc");
346 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) {
347 l1_max[i] = -1; /* +1 needs to be 0 */
348 l1_bits[i] = NULL;
350 return(hammer_init_zone_stat());
353 void
354 hammer_cleanup_zone_stat(struct zone_stat *stats)
356 int i;
358 if (l1_bits) {
359 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) {
360 free(l1_bits[i]);
361 l1_bits[i] = NULL;
365 free(l1_bits);
366 l1_bits = NULL;
368 free(l1_max);
369 l1_max = NULL;
371 free(stats);
374 static
375 void
376 _hammer_add_zone_stat(struct zone_stat *stats, int zone,
377 hammer_off_t bytes, int new_block, int new_item)
379 struct zone_stat *sp = stats + zone;
381 if (new_block)
382 sp->blocks++;
383 if (new_item)
384 sp->items++;
385 sp->used += bytes;
388 void
389 hammer_add_zone_stat(struct zone_stat *stats, hammer_off_t offset,
390 hammer_off_t bytes)
392 int zone, vol, i, j, new_block;
393 uint64_t *p;
395 offset &= ~HAMMER_BIGBLOCK_MASK64;
396 zone = HAMMER_ZONE_DECODE(offset);
397 vol = HAMMER_VOL_DECODE(offset);
399 offset &= HAMMER_OFF_SHORT_MASK; /* cut off volume bits from layer1 */
400 i = HAMMER_BLOCKMAP_LAYER1_INDEX(offset);
401 j = HAMMER_BLOCKMAP_LAYER2_INDEX(offset);
403 if (i > l1_max[vol]) {
404 assert(i < 1024); /* no >1024 layer1 per volume */
405 hammer_extend_layer1_bits(vol, i + 1, l1_max[vol] + 1);
406 l1_max[vol] = i;
409 p = l1_bits[vol] + i * HAMMER_LAYER1_UINT64;
410 new_block = hammer_set_layer_bits(p, j);
411 _hammer_add_zone_stat(stats, zone, bytes, new_block, 1);
415 * If the same layer2 is used more than once the result will be wrong.
417 void
418 hammer_add_zone_stat_layer2(struct zone_stat *stats,
419 struct hammer_blockmap_layer2 *layer2)
421 _hammer_add_zone_stat(stats, layer2->zone,
422 HAMMER_BIGBLOCK_SIZE - layer2->bytes_free, 1, 0);
425 static __inline
426 double
427 _calc_used_percentage(hammer_off_t blocks, hammer_off_t used)
429 double res;
431 if (blocks)
432 res = ((double)(used * 100)) / (blocks << HAMMER_BIGBLOCK_BITS);
433 else
434 res = 0;
435 return(res);
438 void
439 hammer_print_zone_stat(const struct zone_stat *stats)
441 int i;
442 hammer_off_t total_blocks = 0;
443 hammer_off_t total_items = 0;
444 hammer_off_t total_used = 0;
445 const struct zone_stat *p = stats;
447 printf("HAMMER zone statistics\n");
448 printf("\tzone # blocks items used[B] used[%%]\n");
450 for (i = 0; i < HAMMER_MAX_ZONES; i++) {
451 printf("\tzone %-2d %-12ju %-18ju %-19ju %g\n",
452 i, p->blocks, p->items, p->used,
453 _calc_used_percentage(p->blocks, p->used));
454 total_blocks += p->blocks;
455 total_items += p->items;
456 total_used += p->used;
457 p++;
461 * Remember that zone0 is always 0% used and zone15 is
462 * always 100% used.
464 printf("\t----------------------------------------------------------------------\n");
465 printf("\ttotal %-12ju %-18ju %-19ju %g\n",
466 (uintmax_t)total_blocks,
467 (uintmax_t)total_items,
468 (uintmax_t)total_used,
469 _calc_used_percentage(total_blocks, total_used));