1 /* 2 * Copyright (c) 2007 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/hammer.c,v 1.44 2008/11/13 02:04:27 dillon Exp $ 35 */ 36 37 #include "hammer.h" 38 #include <signal.h> 39 #include <math.h> 40 #include <fstab.h> 41 42 static void hammer_parsedevs(const char *blkdevs); 43 static void sigalrm(int signo); 44 static void sigintr(int signo); 45 static void usage(int exit_code); 46 47 int RecurseOpt; 48 int VerboseOpt; 49 int QuietOpt; 50 int NoSyncOpt; 51 int TwoWayPipeOpt; 52 int TimeoutOpt; 53 int DelayOpt = 5; 54 char *SshPort; 55 int ForceYesOpt = 0; 56 int CompressOpt; 57 int ForceOpt; 58 int RunningIoctl; 59 int DidInterrupt; 60 int BulkOpt; 61 u_int64_t BandwidthOpt; 62 u_int64_t SplitupOpt = 4ULL * 1024ULL * 1024ULL * 1024ULL; 63 u_int64_t MemoryLimit = 1024LLU * 1024 * 1024; 64 const char *CyclePath; 65 const char *LinkPath; 66 67 int 68 main(int ac, char **av) 69 { 70 char *blkdevs = NULL; 71 char *ptr; 72 u_int32_t status; 73 int ch; 74 int cacheSize = 0; 75 76 while ((ch = getopt(ac, av, "b:c:dhf:i:m:p:qrs:t:v2yBC:FS:X")) != -1) { 77 switch(ch) { 78 case '2': 79 TwoWayPipeOpt = 1; 80 break; 81 case 'y': 82 ForceYesOpt = 1; 83 break; 84 case 'b': 85 BandwidthOpt = strtoull(optarg, &ptr, 0); 86 switch(*ptr) { 87 case 'g': 88 case 'G': 89 BandwidthOpt *= 1024; 90 /* fall through */ 91 case 'm': 92 case 'M': 93 BandwidthOpt *= 1024; 94 /* fall through */ 95 case 'k': 96 case 'K': 97 BandwidthOpt *= 1024; 98 break; 99 case '\0': 100 /* bytes per second if no suffix */ 101 break; 102 default: 103 usage(1); 104 } 105 break; 106 case 'S': 107 SplitupOpt = strtoull(optarg, &ptr, 0); 108 switch(*ptr) { 109 case 'g': 110 case 'G': 111 SplitupOpt *= 1024; 112 /* fall through */ 113 case 'm': 114 case 'M': 115 SplitupOpt *= 1024; 116 /* fall through */ 117 case 'k': 118 case 'K': 119 SplitupOpt *= 1024; 120 break; 121 case '\0': 122 /* bytes per second if no suffix */ 123 break; 124 default: 125 usage(1); 126 } 127 break; 128 case 'c': 129 CyclePath = optarg; 130 break; 131 case 'd': 132 ++DebugOpt; 133 break; 134 case 'h': 135 usage(0); 136 /* not reached */ 137 case 'i': 138 DelayOpt = strtol(optarg, NULL, 0); 139 break; 140 case 'm': 141 MemoryLimit = strtouq(optarg, &ptr, 0); 142 switch(*ptr) { 143 case 't': 144 case 'T': 145 MemoryLimit *= 1024; 146 /* fall through */ 147 case 'g': 148 case 'G': 149 MemoryLimit *= 1024; 150 /* fall through */ 151 case 'm': 152 case 'M': 153 MemoryLimit *= 1024; 154 /* fall through */ 155 case 'k': 156 case 'K': 157 MemoryLimit *= 1024; 158 /* fall through */ 159 default: 160 break; 161 } 162 163 /* minimum limit */ 164 if (MemoryLimit < 1024 * 1024) 165 MemoryLimit = 1024 * 1024; 166 break; 167 case 'p': 168 SshPort = optarg; 169 break; 170 case 'r': 171 RecurseOpt = 1; 172 break; 173 case 'f': 174 blkdevs = optarg; 175 break; 176 case 's': 177 LinkPath = optarg; 178 break; 179 case 't': 180 TimeoutOpt = strtol(optarg, NULL, 0); 181 break; 182 case 'v': 183 if (QuietOpt > 0) 184 --QuietOpt; 185 else 186 ++VerboseOpt; 187 break; 188 case 'q': 189 if (VerboseOpt > 0) 190 --VerboseOpt; 191 else 192 ++QuietOpt; 193 break; 194 case 'B': 195 BulkOpt = 1; 196 break; 197 case 'C': 198 cacheSize = strtol(optarg, &ptr, 0); 199 switch(*ptr) { 200 case 'm': 201 case 'M': 202 cacheSize *= 1024; 203 /* fall through */ 204 case 'k': 205 case 'K': 206 cacheSize *= 1024; 207 ++ptr; 208 break; 209 case '\0': 210 case ':': 211 /* bytes if no suffix */ 212 break; 213 default: 214 usage(1); 215 } 216 if (*ptr == ':') { 217 UseReadAhead = strtol(ptr + 1, NULL, 0); 218 UseReadBehind = -UseReadAhead; 219 } 220 if (cacheSize < 1024 * 1024) 221 cacheSize = 1024 * 1024; 222 if (UseReadAhead < 0) 223 usage(1); 224 if (UseReadAhead * HAMMER_BUFSIZE / cacheSize / 16) { 225 UseReadAhead = cacheSize / 16 / HAMMER_BUFSIZE; 226 UseReadBehind = -UseReadAhead; 227 } 228 hammer_cache_set(cacheSize); 229 break; 230 case 'F': 231 ForceOpt = 1; 232 break; 233 case 'X': 234 CompressOpt = 1; 235 break; 236 default: 237 usage(1); 238 /* not reached */ 239 } 240 } 241 ac -= optind; 242 av += optind; 243 if (ac < 1) { 244 usage(1); 245 /* not reached */ 246 } 247 248 signal(SIGALRM, sigalrm); 249 signal(SIGINT, sigintr); 250 251 if (strcmp(av[0], "synctid") == 0) { 252 hammer_cmd_synctid(av + 1, ac - 1); 253 exit(0); 254 } 255 if (strcmp(av[0], "namekey2") == 0) { 256 int64_t key; 257 int32_t crcx; 258 int len; 259 const char *aname = av[1]; 260 261 if (aname == NULL) 262 usage(1); 263 len = strlen(aname); 264 key = (u_int32_t)crc32(aname, len) & 0xFFFFFFFEU; 265 266 switch(len) { 267 default: 268 crcx = crc32(aname + 3, len - 5); 269 crcx = crcx ^ (crcx >> 6) ^ (crcx >> 12); 270 key |= (int64_t)(crcx & 0x3F) << 42; 271 /* fall through */ 272 case 5: 273 case 4: 274 /* fall through */ 275 case 3: 276 key |= ((int64_t)(aname[2] & 0x1F) << 48); 277 /* fall through */ 278 case 2: 279 key |= ((int64_t)(aname[1] & 0x1F) << 53) | 280 ((int64_t)(aname[len-2] & 0x1F) << 37); 281 /* fall through */ 282 case 1: 283 key |= ((int64_t)(aname[0] & 0x1F) << 58) | 284 ((int64_t)(aname[len-1] & 0x1F) << 32); 285 /* fall through */ 286 case 0: 287 break; 288 } 289 if (key == 0) 290 key |= 0x100000000LL; 291 printf("0x%016jx\n", (uintmax_t)key); 292 exit(0); 293 } 294 if (strcmp(av[0], "namekey1") == 0) { 295 int64_t key; 296 297 if (av[1] == NULL) 298 usage(1); 299 key = (int64_t)(crc32(av[1], strlen(av[1])) & 0x7FFFFFFF) << 32; 300 if (key == 0) 301 key |= 0x100000000LL; 302 printf("0x%016jx\n", (uintmax_t)key); 303 exit(0); 304 } 305 if (strcmp(av[0], "namekey32") == 0) { 306 int32_t key; 307 308 if (av[1] == NULL) 309 usage(1); 310 key = crc32(av[1], strlen(av[1])) & 0x7FFFFFFF; 311 if (key == 0) 312 ++key; 313 printf("0x%08x\n", key); 314 exit(0); 315 } 316 if (strcmp(av[0], "pfs-status") == 0) { 317 hammer_cmd_pseudofs_status(av + 1, ac - 1); 318 exit(0); 319 } 320 if (strcmp(av[0], "pfs-master") == 0) { 321 hammer_cmd_pseudofs_create(av + 1, ac - 1, 0); 322 exit(0); 323 } 324 if (strcmp(av[0], "pfs-slave") == 0) { 325 hammer_cmd_pseudofs_create(av + 1, ac - 1, 1); 326 exit(0); 327 } 328 if (strcmp(av[0], "pfs-update") == 0) { 329 hammer_cmd_pseudofs_update(av + 1, ac - 1); 330 exit(0); 331 } 332 if (strcmp(av[0], "pfs-upgrade") == 0) { 333 hammer_cmd_pseudofs_upgrade(av + 1, ac - 1); 334 exit(0); 335 } 336 if (strcmp(av[0], "pfs-downgrade") == 0) { 337 hammer_cmd_pseudofs_downgrade(av + 1, ac - 1); 338 exit(0); 339 } 340 if (strcmp(av[0], "pfs-destroy") == 0) { 341 hammer_cmd_pseudofs_destroy(av + 1, ac - 1); 342 exit(0); 343 } 344 if (strcmp(av[0], "status") == 0) { 345 hammer_cmd_status(av + 1, ac - 1); 346 exit(0); 347 } 348 if (strcmp(av[0], "prune") == 0) { 349 hammer_cmd_softprune(av + 1, ac - 1, 0); 350 exit(0); 351 } 352 if (strcmp(av[0], "config") == 0) { 353 hammer_cmd_config(av + 1, ac - 1); 354 exit(0); 355 } 356 if (strcmp(av[0], "viconfig") == 0) { 357 hammer_cmd_viconfig(av + 1, ac - 1); 358 exit(0); 359 } 360 if (strcmp(av[0], "cleanup") == 0) { 361 hammer_cmd_cleanup(av + 1, ac - 1); 362 exit(0); 363 } 364 if (strcmp(av[0], "info") == 0) { 365 hammer_cmd_info(); 366 exit(0); 367 } 368 if (strcmp(av[0], "prune-everything") == 0) { 369 hammer_cmd_softprune(av + 1, ac - 1, 1); 370 exit(0); 371 } 372 if (strcmp(av[0], "snap") == 0) { 373 hammer_cmd_snap(av + 1, ac - 1, 0, 1); 374 exit(0); 375 } 376 if (strcmp(av[0], "snaplo") == 0) { 377 hammer_cmd_snap(av + 1, ac - 1, 0, 0); 378 exit(0); 379 } 380 if (strcmp(av[0], "snapq") == 0) { 381 hammer_cmd_snap(av + 1, ac - 1, 1, 0); 382 exit(0); 383 } 384 if (strcmp(av[0], "snapls") == 0) { 385 hammer_cmd_snapls(av + 1, ac - 1); 386 exit(0); 387 } 388 if (strcmp(av[0], "snaprm") == 0) { 389 hammer_cmd_snaprm(av + 1, ac - 1); 390 exit(0); 391 } 392 if (strcmp(av[0], "snapshot") == 0) { 393 hammer_cmd_snapshot(av + 1, ac - 1); 394 exit(0); 395 } 396 if (strcmp(av[0], "bstats") == 0) { 397 hammer_cmd_bstats(av + 1, ac - 1); 398 exit(0); 399 } 400 if (strcmp(av[0], "iostats") == 0) { 401 hammer_cmd_iostats(av + 1, ac - 1); 402 exit(0); 403 } 404 405 if (strncmp(av[0], "history", 7) == 0) { 406 hammer_cmd_history(av[0] + 7, av + 1, ac - 1); 407 exit(0); 408 } 409 if (strcmp(av[0], "rebalance") == 0) { 410 signal(SIGINT, sigalrm); 411 hammer_cmd_rebalance(av + 1, ac - 1); 412 exit(0); 413 } 414 if (strncmp(av[0], "reblock", 7) == 0) { 415 signal(SIGINT, sigalrm); 416 if (strcmp(av[0], "reblock") == 0) 417 hammer_cmd_reblock(av + 1, ac - 1, -1); 418 else if (strcmp(av[0], "reblock-btree") == 0) 419 hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_BTREE); 420 else if (strcmp(av[0], "reblock-inodes") == 0) 421 hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_INODES); 422 else if (strcmp(av[0], "reblock-dirs") == 0) 423 hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_DIRS); 424 else if (strcmp(av[0], "reblock-data") == 0) 425 hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_DATA); 426 else 427 usage(1); 428 exit(0); 429 } 430 if (strncmp(av[0], "mirror", 6) == 0) { 431 if (strcmp(av[0], "mirror-read") == 0) 432 hammer_cmd_mirror_read(av + 1, ac - 1, 0); 433 else if (strcmp(av[0], "mirror-read-stream") == 0) 434 hammer_cmd_mirror_read(av + 1, ac - 1, 1); 435 else if (strcmp(av[0], "mirror-write") == 0) 436 hammer_cmd_mirror_write(av + 1, ac - 1); 437 else if (strcmp(av[0], "mirror-copy") == 0) 438 hammer_cmd_mirror_copy(av + 1, ac - 1, 0); 439 else if (strcmp(av[0], "mirror-stream") == 0) 440 hammer_cmd_mirror_copy(av + 1, ac - 1, 1); 441 else if (strcmp(av[0], "mirror-dump") == 0) 442 hammer_cmd_mirror_dump(); 443 else 444 usage(1); 445 exit(0); 446 } 447 if (strcmp(av[0], "dedup-simulate") == 0) { 448 hammer_cmd_dedup_simulate(av + 1, ac - 1); 449 exit(0); 450 } 451 if (strcmp(av[0], "dedup") == 0) { 452 hammer_cmd_dedup(av + 1, ac - 1); 453 exit(0); 454 } 455 if (strcmp(av[0], "version") == 0) { 456 hammer_cmd_get_version(av + 1, ac - 1); 457 exit(0); 458 } 459 if (strcmp(av[0], "version-upgrade") == 0) { 460 hammer_cmd_set_version(av + 1, ac - 1); 461 exit(0); 462 } 463 if (strcmp(av[0], "volume-add") == 0) { 464 hammer_cmd_volume_add(av + 1, ac - 1); 465 exit(0); 466 } 467 if (strcmp(av[0], "volume-del") == 0) { 468 hammer_cmd_volume_del(av + 1, ac - 1); 469 exit(0); 470 } 471 if (strcmp(av[0], "volume-list") == 0) { 472 hammer_cmd_volume_list(av + 1, ac - 1); 473 exit(0); 474 } 475 476 uuid_name_lookup(&Hammer_FSType, "DragonFly HAMMER", &status); 477 if (status != uuid_s_ok) { 478 errx(1, "uuids file does not have the DragonFly " 479 "HAMMER filesystem type"); 480 } 481 482 if (strcmp(av[0], "show") == 0) { 483 u_int32_t lo = 0; 484 intmax_t obj_id = (int64_t)HAMMER_MIN_OBJID; 485 486 hammer_parsedevs(blkdevs); 487 if (ac > 1) 488 sscanf(av[1], "%08x:%jx", &lo, &obj_id); 489 hammer_cmd_show(-1, lo, (int64_t)obj_id, 0, NULL, NULL); 490 exit(0); 491 } 492 if (strcmp(av[0], "show-undo") == 0) { 493 hammer_parsedevs(blkdevs); 494 hammer_cmd_show_undo(); 495 exit(0); 496 } 497 if (strcmp(av[0], "recover") == 0) { 498 hammer_parsedevs(blkdevs); 499 if (ac <= 1) 500 errx(1, "hammer recover required target directory"); 501 hammer_cmd_recover(av[1]); 502 exit(0); 503 } 504 if (strcmp(av[0], "blockmap") == 0) { 505 hammer_parsedevs(blkdevs); 506 hammer_cmd_blockmap(); 507 exit(0); 508 } 509 if (strcmp(av[0], "checkmap") == 0) { 510 hammer_parsedevs(blkdevs); 511 hammer_cmd_checkmap(); 512 exit(0); 513 } 514 usage(1); 515 /* not reached */ 516 return(0); 517 } 518 519 /* 520 * Parse the device specification. 521 * 522 * Multi-volume hammer devices are colon-separated. Each element 523 * may be further expanded via /etc/devtab. One may also specify 524 * a single element which is expanded into multiple elements via 525 * /etc/devtab. 526 */ 527 static 528 void 529 hammer_parsedevs(const char *blkdevs) 530 { 531 char *copy; 532 char *volname; 533 534 if (blkdevs == NULL) { 535 errx(1, "A -f blkdevs specification is required " 536 "for this command"); 537 } 538 539 copy = strdup(blkdevs); 540 while ((volname = copy) != NULL) { 541 if ((copy = strchr(copy, ':')) != NULL) 542 *copy++ = 0; 543 volname = getdevpath(volname, 0); 544 if (strchr(volname, ':')) 545 hammer_parsedevs(volname); 546 else 547 setup_volume(-1, volname, 0, O_RDONLY); 548 } 549 } 550 551 static 552 void 553 sigalrm(int signo __unused) 554 { 555 /* do nothing (interrupts HAMMER ioctl) */ 556 } 557 558 static 559 void 560 sigintr(int signo __unused) 561 { 562 if (RunningIoctl == 0) 563 _exit(1); 564 DidInterrupt = 1; 565 /* do nothing (interrupts HAMMER ioctl) */ 566 } 567 568 static 569 void 570 usage(int exit_code) 571 { 572 fprintf(stderr, 573 "hammer -h\n" 574 "hammer [-2BqrvXy] [-b bandwidth] [-C cachesize[:readahead]] [-c cyclefile]\n" 575 " [-f blkdevs] [-i delay] [-t seconds] [-S splitup]\n" 576 " command [argument ...]\n" 577 "hammer synctid <filesystem> [quick]\n" 578 "hammer bstats [interval]\n" 579 "hammer iostats [interval]\n" 580 "hammer history[@offset[,len]] <file> ...\n" 581 "hammer namekey1 <path>\n" 582 "hammer namekey2 <path>\n" 583 "hammer namekey32 <path>\n" 584 "hammer cleanup [<filesystem> ...]\n" 585 "hammer info\n" 586 "hammer snapshot [<filesystem>] <snapshot-dir>\n" 587 "hammer snapshot <filesystem> <snapshot-dir> [<note>]\n" 588 "hammer prune <softlink-dir>\n" 589 "hammer prune-everything <filesystem>\n" 590 "hammer rebalance <filesystem> [saturation_percentage]\n" 591 "hammer reblock[-btree|-inodes|-dirs|-data] " 592 "<filesystem> [fill_percentage]\n" 593 "hammer pfs-status <dirpath> ...\n" 594 "hammer pfs-master <dirpath> [options]\n" 595 "hammer pfs-slave <dirpath> [options]\n" 596 "hammer pfs-update <dirpath> [options]\n" 597 "hammer pfs-upgrade <dirpath>\n" 598 "hammer pfs-downgrade <dirpath>\n" 599 "hammer pfs-destroy <dirpath>\n" 600 "hammer mirror-read <filesystem> [begin-tid]\n" 601 "hammer mirror-read-stream <filesystem> [begin-tid]\n" 602 "hammer mirror-write <filesystem>\n" 603 "hammer mirror-dump\n" 604 "hammer mirror-copy [[user@]host:]<filesystem>" 605 " [[user@]host:]<filesystem>\n" 606 "hammer mirror-stream [[user@]host:]<filesystem>" 607 " [[user@]host:]<filesystem>\n" 608 "hammer version <filesystem>\n" 609 "hammer version-upgrade <filesystem> <version> [force]\n" 610 "hammer volume-add <device> <filesystem>\n" 611 "hammer volume-del <device> <filesystem>\n" 612 "hammer volume-list <filesystem>\n" 613 ); 614 615 fprintf(stderr, "\nHAMMER utility version 3+ commands:\n"); 616 617 fprintf(stderr, 618 "hammer config [<filesystem> [<configfile>]]\n" 619 "hammer viconfig [<filesystem>]\n" 620 "hammer snap <path> [<note>]\n" 621 "hammer snaplo <path> [<note>]\n" 622 "hammer snapq <dir> [<note>]\n" 623 "hammer snaprm <path> ...\n" 624 "hammer snaprm <transid> ...\n" 625 "hammer snaprm <filesystem> <transid> ...\n" 626 "hammer snapls [<path> ...]\n" 627 ); 628 629 fprintf(stderr, "\nHAMMER utility version 4+ commands:\n"); 630 631 fprintf(stderr, 632 "hammer -f blkdevs blockmap\n" 633 "hammer -f blkdevs checkmap\n" 634 "hammer -f blkdevs [-qqq] show [lo:objid]\n" 635 "hammer -f blkdevs show-undo\n" 636 "hammer -f blkdevs recover <target_dir>\n" 637 ); 638 639 fprintf(stderr, "\nHAMMER utility version 5+ commands:\n"); 640 641 fprintf(stderr, 642 "hammer dedup-simulate <filesystem>\n" 643 "hammer dedup <filesystem>\n" 644 ); 645 646 exit(exit_code); 647 } 648 649