sys/vfs/hammer2/hammer2_freemap.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 | /* * Copyright (c) 2011-2018 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Matthew Dillon <dillon@dragonflybsd.org> * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name of The DragonFly Project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific, prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/proc.h> #include <sys/mount.h> #include "hammer2.h" #define FREEMAP_DEBUG 0 struct hammer2_fiterate { hammer2_off_t bpref; hammer2_off_t bnext; int loops; int relaxed; }; typedef struct hammer2_fiterate hammer2_fiterate_t; static int hammer2_freemap_try_alloc(hammer2_chain_t **parentp, hammer2_blockref_t *bref, int radix, hammer2_fiterate_t *iter, hammer2_tid_t mtid); static void hammer2_freemap_init(hammer2_dev_t *hmp, hammer2_key_t key, hammer2_chain_t *chain); static int hammer2_bmap_alloc(hammer2_dev_t *hmp, hammer2_bmap_data_t *bmap, uint16_t class, int n, int sub_key, int radix, hammer2_key_t *basep); static int hammer2_freemap_iterate(hammer2_chain_t **parentp, hammer2_chain_t **chainp, hammer2_fiterate_t *iter); /* * Calculate the device offset for the specified FREEMAP_NODE or FREEMAP_LEAF * bref. Return a combined media offset and physical size radix. Freemap * chains use fixed storage offsets in the 4MB reserved area at the * beginning of each 1GB zone. * * Rotate between eight possibilities. Theoretically this means we have seven * good freemaps in case of a crash which we can use as a base for the fixup * scan at mount-time. */ static int hammer2_freemap_reserve(hammer2_chain_t *chain, int radix) { hammer2_blockref_t *bref = &chain->bref; hammer2_off_t off; int index; int index_inc; size_t bytes; /* * Physical allocation size. */ bytes = (size_t)1 << radix; /* * Calculate block selection index 0..7 of current block. If this * is the first allocation of the block (verses a modification of an * existing block), we use index 0, otherwise we use the next rotating * index. */ if ((bref->data_off & ~HAMMER2_OFF_MASK_RADIX) == 0) { index = 0; } else { off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX & HAMMER2_SEGMASK; off = off / HAMMER2_PBUFSIZE; KKASSERT(off >= HAMMER2_ZONE_FREEMAP_00 && off < HAMMER2_ZONE_FREEMAP_END); index = (int)(off - HAMMER2_ZONE_FREEMAP_00) / HAMMER2_ZONE_FREEMAP_INC; KKASSERT(index >= 0 && index < HAMMER2_NFREEMAPS); if (++index == HAMMER2_NFREEMAPS) index = 0; } /* * Calculate the block offset of the reserved block. This will * point into the 4MB reserved area at the base of the appropriate * 2GB zone, once added to the FREEMAP_x selection above. */ index_inc = index * HAMMER2_ZONE_FREEMAP_INC; switch(bref->keybits) { /* case HAMMER2_FREEMAP_LEVEL6_RADIX: not applicable */ case HAMMER2_FREEMAP_LEVEL5_RADIX: /* 4EB */ KKASSERT(bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE); KKASSERT(bytes == HAMMER2_FREEMAP_LEVELN_PSIZE); off = H2FMBASE(bref->key, HAMMER2_FREEMAP_LEVEL5_RADIX) + (index_inc + HAMMER2_ZONE_FREEMAP_00 + HAMMER2_ZONEFM_LEVEL5) * HAMMER2_PBUFSIZE; break; case HAMMER2_FREEMAP_LEVEL4_RADIX: /* 16PB */ KKASSERT(bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE); KKASSERT(bytes == HAMMER2_FREEMAP_LEVELN_PSIZE); off = H2FMBASE(bref->key, HAMMER2_FREEMAP_LEVEL4_RADIX) + (index_inc + HAMMER2_ZONE_FREEMAP_00 + HAMMER2_ZONEFM_LEVEL4) * HAMMER2_PBUFSIZE; break; case HAMMER2_FREEMAP_LEVEL3_RADIX: /* 64TB */ KKASSERT(bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE); KKASSERT(bytes == HAMMER2_FREEMAP_LEVELN_PSIZE); off = H2FMBASE(bref->key, HAMMER2_FREEMAP_LEVEL3_RADIX) + (index_inc + HAMMER2_ZONE_FREEMAP_00 + HAMMER2_ZONEFM_LEVEL3) * HAMMER2_PBUFSIZE; break; case HAMMER2_FREEMAP_LEVEL2_RADIX: /* 256GB */ KKASSERT(bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE); KKASSERT(bytes == HAMMER2_FREEMAP_LEVELN_PSIZE); off = H2FMBASE(bref->key, HAMMER2_FREEMAP_LEVEL2_RADIX) + (index_inc + HAMMER2_ZONE_FREEMAP_00 + HAMMER2_ZONEFM_LEVEL2) * HAMMER2_PBUFSIZE; break; case HAMMER2_FREEMAP_LEVEL1_RADIX: /* 1GB */ KKASSERT(bref->type == HAMMER2_BREF_TYPE_FREEMAP_LEAF); KKASSERT(bytes == HAMMER2_FREEMAP_LEVELN_PSIZE); off = H2FMBASE(bref->key, HAMMER2_FREEMAP_LEVEL1_RADIX) + (index_inc + HAMMER2_ZONE_FREEMAP_00 + HAMMER2_ZONEFM_LEVEL1) * HAMMER2_PBUFSIZE; break; default: panic("freemap: bad radix(2) %p %d\n", bref, bref->keybits); /* NOT REACHED */ off = (hammer2_off_t)-1; break; } bref->data_off = off | radix; #if FREEMAP_DEBUG kprintf("FREEMAP BLOCK TYPE %d %016jx/%d DATA_OFF=%016jx\n", bref->type, bref->key, bref->keybits, bref->data_off); #endif return (0); } /* * Normal freemap allocator * * Use available hints to allocate space using the freemap. Create missing * freemap infrastructure on-the-fly as needed (including marking initial * allocations using the iterator as allocated, instantiating new 2GB zones, * and dealing with the end-of-media edge case). * * bpref is only used as a heuristic to determine locality of reference. * * This function is a NOP if bytes is 0. */ int hammer2_freemap_alloc(hammer2_chain_t *chain, size_t bytes) { hammer2_dev_t *hmp = chain->hmp; hammer2_blockref_t *bref = &chain->bref; hammer2_chain_t *parent; hammer2_tid_t mtid; int radix; int error; unsigned int hindex; hammer2_fiterate_t iter; /* * If allocating or downsizing to zero we just get rid of whatever * data_off we had. */ if (bytes == 0) { chain->bref.data_off = 0; return 0; } KKASSERT(hmp->spmp); mtid = hammer2_trans_sub(hmp->spmp); /* * Validate the allocation size. It must be a power of 2. * * For now require that the caller be aware of the minimum * allocation (1K). */ radix = hammer2_getradix(bytes); KKASSERT((size_t)1 << radix == bytes); if (bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE || bref->type == HAMMER2_BREF_TYPE_FREEMAP_LEAF) { /* * Freemap blocks themselves are assigned from the reserve * area, not allocated from the freemap. */ error = hammer2_freemap_reserve(chain, radix); return error; } KKASSERT(bytes >= HAMMER2_ALLOC_MIN && bytes <= HAMMER2_ALLOC_MAX); /* * Heuristic tracking index. We would like one for each distinct * bref type if possible. heur_freemap[] has room for two classes * for each type. At a minimum we have to break-up our heuristic * by device block sizes. */ hindex = HAMMER2_PBUFRADIX - HAMMER2_LBUFRADIX; KKASSERT(hindex < HAMMER2_FREEMAP_HEUR_NRADIX); hindex += bref->type * HAMMER2_FREEMAP_HEUR_NRADIX; hindex &= HAMMER2_FREEMAP_HEUR_TYPES * HAMMER2_FREEMAP_HEUR_NRADIX - 1; KKASSERT(hindex < HAMMER2_FREEMAP_HEUR_SIZE); iter.bpref = hmp->heur_freemap[hindex]; iter.relaxed = hmp->freemap_relaxed; /* * Make sure bpref is in-bounds. It's ok if bpref covers a zone's * reserved area, the try code will iterate past it. */ if (iter.bpref > hmp->total_size) iter.bpref = hmp->total_size - 1; /* * Iterate the freemap looking for free space before and after. */ parent = &hmp->fchain; hammer2_chain_ref(parent); hammer2_chain_lock(parent, HAMMER2_RESOLVE_ALWAYS); error = HAMMER2_ERROR_EAGAIN; iter.bnext = iter.bpref; iter.loops = 0; while (error == HAMMER2_ERROR_EAGAIN) { error = hammer2_freemap_try_alloc(&parent, bref, radix, &iter, mtid); } hmp->freemap_relaxed |= iter.relaxed; /* heuristical, SMP race ok */ hmp->heur_freemap[hindex] = iter.bnext; hammer2_chain_unlock(parent); hammer2_chain_drop(parent); return (error); } static int hammer2_freemap_try_alloc(hammer2_chain_t **parentp, hammer2_blockref_t *bref, int radix, hammer2_fiterate_t *iter, hammer2_tid_t mtid) { hammer2_dev_t *hmp = (*parentp)->hmp; hammer2_off_t l0size; hammer2_off_t l1size; hammer2_off_t l1mask; hammer2_key_t key_dummy; hammer2_chain_t *chain; hammer2_off_t key; size_t bytes; uint16_t class; int error; /* * Calculate the number of bytes being allocated. */ bytes = (size_t)1 << radix; class = (bref->type << 8) | HAMMER2_PBUFRADIX; /* * Lookup the level1 freemap chain, creating and initializing one * if necessary. Intermediate levels will be created automatically * when necessary by hammer2_chain_create(). */ key = H2FMBASE(iter->bnext, HAMMER2_FREEMAP_LEVEL1_RADIX); l0size = HAMMER2_FREEMAP_LEVEL0_SIZE; l1size = HAMMER2_FREEMAP_LEVEL1_SIZE; l1mask = l1size - 1; chain = hammer2_chain_lookup(parentp, &key_dummy, key, key + l1mask, &error, HAMMER2_LOOKUP_ALWAYS | HAMMER2_LOOKUP_MATCHIND); if (chain == NULL) { /* * Create the missing leaf, be sure to initialize * the auxillary freemap tracking information in * the bref.check.freemap structure. */ #if 0 kprintf("freemap create L1 @ %016jx bpref %016jx\n", key, iter->bpref); #endif error = hammer2_chain_create(parentp, &chain, NULL, hmp->spmp, HAMMER2_METH_DEFAULT, key, HAMMER2_FREEMAP_LEVEL1_RADIX, HAMMER2_BREF_TYPE_FREEMAP_LEAF, HAMMER2_FREEMAP_LEVELN_PSIZE, mtid, 0, 0); KKASSERT(error == 0); if (error == 0) { /* * An error should not be possible here because freemap * blocks are laid out algorithmically, not dynamically. * * But have an error path anyway. */ error = hammer2_chain_modify(chain, mtid, 0, 0); if (error == 0) { bzero(&chain->data->bmdata[0], HAMMER2_FREEMAP_LEVELN_PSIZE); chain->bref.check.freemap.bigmask = (uint32_t)-1; chain->bref.check.freemap.avail = l1size; /* bref.methods should already be inherited */ hammer2_freemap_init(hmp, key, chain); } } } else if (chain->error) { /* * Error during lookup. */ kprintf("hammer2_freemap_try_alloc: %016jx: error %s\n", (intmax_t)bref->data_off, hammer2_error_str(chain->error)); error = HAMMER2_ERROR_EIO; } else if ((chain->bref.check.freemap.bigmask & ((size_t)1 << radix)) == 0) { /* * Already flagged as not having enough space */ error = HAMMER2_ERROR_ENOSPC; } else { /* * Modify existing chain to setup for adjustment. * * An error should not be possible here because freemap * blocks are laid out algorithmically, not dynamically. * * But have an error path anyway. */ error = hammer2_chain_modify(chain, mtid, 0, 0); } /* * Scan 4MB entries. */ if (error == 0) { hammer2_bmap_data_t *bmap; hammer2_key_t base_key; int count; int start; int n; KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_FREEMAP_LEAF); start = (int)((iter->bnext - key) >> HAMMER2_FREEMAP_LEVEL0_RADIX); KKASSERT(start >= 0 && start < HAMMER2_FREEMAP_COUNT); /* * An error should not be possible here because freemap * blocks are laid out algorithmically, not dynamically. * * But have an error path anyway. */ error = hammer2_chain_modify(chain, mtid, 0, 0); if (error) goto skip_scan; error = HAMMER2_ERROR_ENOSPC; for (count = 0; count < HAMMER2_FREEMAP_COUNT; ++count) { int availchk; if (start + count >= HAMMER2_FREEMAP_COUNT && start - count < 0) { break; } /* * Calculate bmap pointer from thart starting index * forwards. * * NOTE: bmap pointer is invalid if n >= FREEMAP_COUNT. */ n = start + count; bmap = &chain->data->bmdata[n]; if (n >= HAMMER2_FREEMAP_COUNT) { availchk = 0; } else if (bmap->avail) { availchk = 1; } else if (radix < HAMMER2_FREEMAP_BLOCK_RADIX && (bmap->linear & HAMMER2_FREEMAP_BLOCK_MASK)) { availchk = 1; } else { availchk = 0; } /* * Try to allocate from a matching freemap class * superblock. If we are in relaxed mode we allocate * from any freemap class superblock. */ if (availchk && (bmap->class == 0 || bmap->class == class || iter->relaxed)) { base_key = key + n * l0size; error = hammer2_bmap_alloc(hmp, bmap, class, n, (int)bref->key, radix, &base_key); if (error != HAMMER2_ERROR_ENOSPC) { key = base_key; break; } } /* * Calculate bmap pointer from the starting index * backwards (locality). * * Must recalculate after potentially having called * hammer2_bmap_alloc() above in case chain was * reallocated. * * NOTE: bmap pointer is invalid if n < 0. */ n = start - count; bmap = &chain->data->bmdata[n]; if (n < 0) { availchk = 0; } else if (bmap->avail) { availchk = 1; } else if (radix < HAMMER2_FREEMAP_BLOCK_RADIX && (bmap->linear & HAMMER2_FREEMAP_BLOCK_MASK)) { availchk = 1; } else { availchk = 0; } /* * Try to allocate from a matching freemap class * superblock. If we are in relaxed mode we allocate * from any freemap class superblock. */ if (availchk && (bmap->class == 0 || bmap->class == class || iter->relaxed)) { base_key = key + n * l0size; error = hammer2_bmap_alloc(hmp, bmap, class, n, (int)bref->key, radix, &base_key); if (error != HAMMER2_ERROR_ENOSPC) { key = base_key; break; } } } /* * We only know for sure that we can clear the bitmap bit * if we scanned the entire array (start == 0) in relaxed * mode. */ if (error == HAMMER2_ERROR_ENOSPC && start == 0 && iter->relaxed) { chain->bref.check.freemap.bigmask &= (uint32_t)~((size_t)1 << radix); } /* XXX also scan down from original count */ skip_scan: ; } if (error == 0) { /* * Assert validity. Must be beyond the static allocator used * by newfs_hammer2 (and thus also beyond the aux area), * not go past the volume size, and must not be in the * reserved segment area for a zone. */ KKASSERT(key >= hmp->voldata.allocator_beg && key + bytes <= hmp->total_size); KKASSERT((key & HAMMER2_ZONE_MASK64) >= HAMMER2_ZONE_SEG); bref->data_off = key | radix; /* * Record dedupability. The dedup bits are cleared * when bulkfree transitions the freemap from 11->10, * and asserted to be clear on the 10->00 transition. * * We must record the bitmask with the chain locked * at the time we set the allocation bits to avoid * racing a bulkfree. */ if (bref->type == HAMMER2_BREF_TYPE_DATA) hammer2_io_dedup_set(hmp, bref); #if 0 kprintf("alloc cp=%p %016jx %016jx using %016jx\n", chain, bref->key, bref->data_off, chain->bref.data_off); #endif } else if (error == HAMMER2_ERROR_ENOSPC) { /* * Return EAGAIN with next iteration in iter->bnext, or * return ENOSPC if the allocation map has been exhausted. */ error = hammer2_freemap_iterate(parentp, &chain, iter); } /* * Cleanup */ if (chain) { hammer2_chain_unlock(chain); hammer2_chain_drop(chain); } return (error); } /* * Allocate (1<<radix) bytes from the bmap whos base data offset is (*basep). * * If the linear iterator is mid-block we use it directly (the bitmap should * already be marked allocated), otherwise we search for a block in the * bitmap that fits the allocation request. * * A partial bitmap allocation sets the minimum bitmap granularity (16KB) * to fully allocated and adjusts the linear allocator to allow the * remaining space to be allocated. * * sub_key is the lower 32 bits of the chain->bref.key for the chain whos * bref is being allocated. If the radix represents an allocation >= 16KB * (aka HAMMER2_FREEMAP_BLOCK_RADIX) we try to use this key to select the * blocks directly out of the bmap. */ static int hammer2_bmap_alloc(hammer2_dev_t *hmp, hammer2_bmap_data_t *bmap, uint16_t class, int n, int sub_key, int radix, hammer2_key_t *basep) { size_t size; size_t bgsize; int bmradix; hammer2_bitmap_t bmmask; int offset; int i; int j; /* * Take into account 2-bits per block when calculating bmradix. */ size = (size_t)1 << radix; if (radix <= HAMMER2_FREEMAP_BLOCK_RADIX) { bmradix = 2; /* (16K) 2 bits per allocation block */ } else { bmradix = (hammer2_bitmap_t)2 << (radix - HAMMER2_FREEMAP_BLOCK_RADIX); /* (32K-64K) 4, 8 bits per allocation block */ } /* * Use the linear iterator to pack small allocations, otherwise * fall-back to finding a free 16KB chunk. The linear iterator * is only valid when *NOT* on a freemap chunking boundary (16KB). * If it is the bitmap must be scanned. It can become invalid * once we pack to the boundary. We adjust it after a bitmap * allocation only for sub-16KB allocations (so the perfectly good * previous value can still be used for fragments when 16KB+ * allocations are made inbetween fragmentary allocations). * * Beware of hardware artifacts when bmradix == 64 (intermediate * result can wind up being '1' instead of '0' if hardware masks * bit-count & 63). * * NOTE: j needs to be even in the j= calculation. As an artifact * of the /2 division, our bitmask has to clear bit 0. * * NOTE: TODO this can leave little unallocatable fragments lying * around. */ if (((uint32_t)bmap->linear & HAMMER2_FREEMAP_BLOCK_MASK) + size <= HAMMER2_FREEMAP_BLOCK_SIZE && (bmap->linear & HAMMER2_FREEMAP_BLOCK_MASK) && bmap->linear < HAMMER2_SEGSIZE) { /* * Use linear iterator if it is not block-aligned to avoid * wasting space. * * Calculate the bitmapq[] index (i) and calculate the * shift count within the 64-bit bitmapq[] entry. * * The freemap block size is 16KB, but each bitmap * entry is two bits so use a little trick to get * a (j) shift of 0, 2, 4, ... 62 in 16KB chunks. */ KKASSERT(bmap->linear >= 0 && bmap->linear + size <= HAMMER2_SEGSIZE && (bmap->linear & (HAMMER2_ALLOC_MIN - 1)) == 0); offset = bmap->linear; i = offset / (HAMMER2_SEGSIZE / HAMMER2_BMAP_ELEMENTS); j = (offset / (HAMMER2_FREEMAP_BLOCK_SIZE / 2)) & 62; bmmask = (bmradix == HAMMER2_BMAP_BITS_PER_ELEMENT) ? HAMMER2_BMAP_ALLONES : ((hammer2_bitmap_t)1 << bmradix) - 1; bmmask <<= j; bmap->linear = offset + size; } else { /* * Try to index a starting point based on sub_key. This * attempts to restore sequential block ordering on-disk * whenever possible, even if data is committed out of * order. * * i - Index bitmapq[], full data range represented is * HAMMER2_BMAP_SIZE. * * j - Index within bitmapq[i], full data range represented is * HAMMER2_BMAP_INDEX_SIZE. * * WARNING! */ i = -1; j = -1; switch(class >> 8) { case HAMMER2_BREF_TYPE_DATA: if (radix >= HAMMER2_FREEMAP_BLOCK_RADIX) { i = (sub_key & HAMMER2_BMAP_MASK) / (HAMMER2_BMAP_SIZE / HAMMER2_BMAP_ELEMENTS); j = (sub_key & HAMMER2_BMAP_INDEX_MASK) / (HAMMER2_BMAP_INDEX_SIZE / HAMMER2_BMAP_BLOCKS_PER_ELEMENT); j = j * 2; } break; case HAMMER2_BREF_TYPE_INODE: break; default: break; } if (i >= 0) { KKASSERT(i < HAMMER2_BMAP_ELEMENTS && j < 2 * HAMMER2_BMAP_BLOCKS_PER_ELEMENT); KKASSERT(j + bmradix <= HAMMER2_BMAP_BITS_PER_ELEMENT); bmmask = (bmradix == HAMMER2_BMAP_BITS_PER_ELEMENT) ? HAMMER2_BMAP_ALLONES : ((hammer2_bitmap_t)1 << bmradix) - 1; bmmask <<= j; if ((bmap->bitmapq[i] & bmmask) == 0) goto success; } /* * General element scan. * * WARNING: (j) is iterating a bit index (by 2's) */ for (i = 0; i < HAMMER2_BMAP_ELEMENTS; ++i) { bmmask = (bmradix == HAMMER2_BMAP_BITS_PER_ELEMENT) ? HAMMER2_BMAP_ALLONES : ((hammer2_bitmap_t)1 << bmradix) - 1; for (j = 0; j < HAMMER2_BMAP_BITS_PER_ELEMENT; j += bmradix) { if ((bmap->bitmapq[i] & bmmask) == 0) goto success; bmmask <<= bmradix; } } /*fragments might remain*/ /*KKASSERT(bmap->avail == 0);*/ return (HAMMER2_ERROR_ENOSPC); success: offset = i * (HAMMER2_SEGSIZE / HAMMER2_BMAP_ELEMENTS) + (j * (HAMMER2_FREEMAP_BLOCK_SIZE / 2)); if (size & HAMMER2_FREEMAP_BLOCK_MASK) bmap->linear = offset + size; } /* 8 x (64/2) -> 256 x 16K -> 4MB */ KKASSERT(i >= 0 && i < HAMMER2_BMAP_ELEMENTS); /* * Optimize the buffer cache to avoid unnecessary read-before-write * operations. * * The device block size could be larger than the allocation size * so the actual bitmap test is somewhat more involved. We have * to use a compatible buffer size for this operation. */ if ((bmap->bitmapq[i] & bmmask) == 0 && HAMMER2_PBUFSIZE != size) { size_t psize = HAMMER2_PBUFSIZE; hammer2_off_t pmask = (hammer2_off_t)psize - 1; int pbmradix = (hammer2_bitmap_t)2 << (HAMMER2_PBUFRADIX - HAMMER2_FREEMAP_BLOCK_RADIX); hammer2_bitmap_t pbmmask; int pradix = hammer2_getradix(psize); pbmmask = (pbmradix == HAMMER2_BMAP_BITS_PER_ELEMENT) ? HAMMER2_BMAP_ALLONES : ((hammer2_bitmap_t)1 << pbmradix) - 1; while ((pbmmask & bmmask) == 0) pbmmask <<= pbmradix; #if 0 kprintf("%016jx mask %016jx %016jx %016jx (%zd/%zd)\n", *basep + offset, bmap->bitmapq[i], pbmmask, bmmask, size, psize); #endif if ((bmap->bitmapq[i] & pbmmask) == 0) { hammer2_io_t *dio; hammer2_io_newnz(hmp, class >> 8, (*basep + (offset & ~pmask)) | pradix, psize, &dio); hammer2_io_putblk(&dio); } } #if 0 /* * When initializing a new inode segment also attempt to initialize * an adjacent segment. Be careful not to index beyond the array * bounds. * * We do this to try to localize inode accesses to improve * directory scan rates. XXX doesn't improve scan rates. */ if (size == HAMMER2_INODE_BYTES) { if (n & 1) { if (bmap[-1].radix == 0 && bmap[-1].avail) bmap[-1].radix = radix; } else { if (bmap[1].radix == 0 && bmap[1].avail) bmap[1].radix = radix; } } #endif /* * Calculate the bitmap-granular change in bgsize for the volume * header. We cannot use the fine-grained change here because * the bulkfree code can't undo it. If the bitmap element is already * marked allocated it has already been accounted for. */ if (radix < HAMMER2_FREEMAP_BLOCK_RADIX) { if (bmap->bitmapq[i] & bmmask) bgsize = 0; else bgsize = HAMMER2_FREEMAP_BLOCK_SIZE; } else { bgsize = size; } /* * Adjust the bitmap, set the class (it might have been 0), * and available bytes, update the allocation offset (*basep) * from the L0 base to the actual offset. * * Do not override the class if doing a relaxed class allocation. * * avail must reflect the bitmap-granular availability. The allocator * tests will also check the linear iterator. */ bmap->bitmapq[i] |= bmmask; if (bmap->class == 0) bmap->class = class; bmap->avail -= bgsize; *basep += offset; /* * Adjust the volume header's allocator_free parameter. This * parameter has to be fixed up by bulkfree which has no way to * figure out sub-16K chunking, so it must be adjusted by the * bitmap-granular size. */ if (bgsize) { hammer2_voldata_lock(hmp); hammer2_voldata_modify(hmp); hmp->voldata.allocator_free -= bgsize; hammer2_voldata_unlock(hmp); } return(0); } /* * Initialize a freemap for the storage area (in bytes) that begins at (key). */ static void hammer2_freemap_init(hammer2_dev_t *hmp, hammer2_key_t key, hammer2_chain_t *chain) { hammer2_off_t lokey; hammer2_off_t hikey; hammer2_bmap_data_t *bmap; int count; /* * Calculate the portion of the 1GB map that should be initialized * as free. Portions below or after will be initialized as allocated. * SEGMASK-align the areas so we don't have to worry about sub-scans * or endianess when using memset. * * WARNING! It is possible for lokey to be larger than hikey if the * entire 2GB segment is within the static allocation. */ /* * (1) Ensure that all statically allocated space from newfs_hammer2 * is marked allocated, and take it up to the level1 base for * this key. */ lokey = (hmp->voldata.allocator_beg + HAMMER2_SEGMASK64) & ~HAMMER2_SEGMASK64; if (lokey < H2FMBASE(key, HAMMER2_FREEMAP_LEVEL1_RADIX)) lokey = H2FMBASE(key, HAMMER2_FREEMAP_LEVEL1_RADIX); /* * (2) Ensure that the reserved area is marked allocated (typically * the first 4MB of each 2GB area being represented). Since * each LEAF represents 1GB of storage and the zone is 2GB, we * have to adjust lowkey upward every other LEAF sequentially. */ if (lokey < H2FMZONEBASE(key) + HAMMER2_ZONE_SEG64) lokey = H2FMZONEBASE(key) + HAMMER2_ZONE_SEG64; /* * (3) Ensure that any trailing space at the end-of-volume is marked * allocated. */ hikey = key + HAMMER2_FREEMAP_LEVEL1_SIZE; if (hikey > hmp->total_size) { hikey = hmp->total_size & ~HAMMER2_SEGMASK64; } /* * Heuristic highest possible value */ chain->bref.check.freemap.avail = HAMMER2_FREEMAP_LEVEL1_SIZE; bmap = &chain->data->bmdata[0]; /* * Initialize bitmap (bzero'd by caller) */ for (count = 0; count < HAMMER2_FREEMAP_COUNT; ++count) { if (key < lokey || key >= hikey) { memset(bmap->bitmapq, -1, sizeof(bmap->bitmapq)); bmap->avail = 0; bmap->linear = HAMMER2_SEGSIZE; chain->bref.check.freemap.avail -= HAMMER2_FREEMAP_LEVEL0_SIZE; } else { bmap->avail = HAMMER2_FREEMAP_LEVEL0_SIZE; } key += HAMMER2_FREEMAP_LEVEL0_SIZE; ++bmap; } } /* * The current Level 1 freemap has been exhausted, iterate to the next * one, return ENOSPC if no freemaps remain. * * At least two loops are required. If we are not in relaxed mode and * we run out of storage we enter relaxed mode and do a third loop. * The relaxed mode is recorded back in the hmp so once we enter the mode * we remain relaxed until stuff begins to get freed and only do 2 loops. * * XXX this should rotate back to the beginning to handle freed-up space * XXX or use intermediate entries to locate free space. TODO */ static int hammer2_freemap_iterate(hammer2_chain_t **parentp, hammer2_chain_t **chainp, hammer2_fiterate_t *iter) { hammer2_dev_t *hmp = (*parentp)->hmp; iter->bnext &= ~HAMMER2_FREEMAP_LEVEL1_MASK; iter->bnext += HAMMER2_FREEMAP_LEVEL1_SIZE; if (iter->bnext >= hmp->total_size) { iter->bnext = 0; if (++iter->loops >= 2) { if (iter->relaxed == 0) iter->relaxed = 1; else return (HAMMER2_ERROR_ENOSPC); } } return(HAMMER2_ERROR_EAGAIN); } /* * Adjust the bit-pattern for data in the freemap bitmap according to * (how). This code is called from on-mount recovery to fixup (mark * as allocated) blocks whos freemap upates might not have been committed * in the last crash and is used by the bulk freemap scan to stage frees. * * WARNING! Cannot be called with a empty-data bref (radix == 0). * * XXX currently disabled when how == 0 (the normal real-time case). At * the moment we depend on the bulk freescan to actually free blocks. It * will still call this routine with a non-zero how to stage possible frees * and to do the actual free. */ void hammer2_freemap_adjust(hammer2_dev_t *hmp, hammer2_blockref_t *bref, int how) { hammer2_off_t data_off = bref->data_off; hammer2_chain_t *chain; hammer2_chain_t *parent; hammer2_bmap_data_t *bmap; hammer2_key_t key; hammer2_key_t key_dummy; hammer2_off_t l1size; hammer2_off_t l1mask; hammer2_tid_t mtid; hammer2_bitmap_t *bitmap; const hammer2_bitmap_t bmmask00 = 0; //hammer2_bitmap_t bmmask01; //hammer2_bitmap_t bmmask10; hammer2_bitmap_t bmmask11; size_t bytes; uint16_t class; int radix; int start; int count; int modified = 0; int error; size_t bgsize = 0; KKASSERT(how == HAMMER2_FREEMAP_DORECOVER); KKASSERT(hmp->spmp); mtid = hammer2_trans_sub(hmp->spmp); radix = (int)data_off & HAMMER2_OFF_MASK_RADIX; KKASSERT(radix != 0); data_off &= ~HAMMER2_OFF_MASK_RADIX; KKASSERT(radix <= HAMMER2_RADIX_MAX); if (radix) bytes = (size_t)1 << radix; else bytes = 0; class = (bref->type << 8) | HAMMER2_PBUFRADIX; /* * We can't adjust the freemap for data allocations made by * newfs_hammer2. */ if (data_off < hmp->voldata.allocator_beg) return; KKASSERT((data_off & HAMMER2_ZONE_MASK64) >= HAMMER2_ZONE_SEG); /* * Lookup the level1 freemap chain. The chain must exist. */ key = H2FMBASE(data_off, HAMMER2_FREEMAP_LEVEL1_RADIX); l1size = HAMMER2_FREEMAP_LEVEL1_SIZE; l1mask = l1size - 1; parent = &hmp->fchain; hammer2_chain_ref(parent); hammer2_chain_lock(parent, HAMMER2_RESOLVE_ALWAYS); chain = hammer2_chain_lookup(&parent, &key_dummy, key, key + l1mask, &error, HAMMER2_LOOKUP_ALWAYS | HAMMER2_LOOKUP_MATCHIND); /* * Stop early if we are trying to free something but no leaf exists. */ if (chain == NULL && how != HAMMER2_FREEMAP_DORECOVER) { kprintf("hammer2_freemap_adjust: %016jx: no chain\n", (intmax_t)bref->data_off); goto done; } if (chain->error) { kprintf("hammer2_freemap_adjust: %016jx: error %s\n", (intmax_t)bref->data_off, hammer2_error_str(chain->error)); hammer2_chain_unlock(chain); hammer2_chain_drop(chain); chain = NULL; goto done; } /* * Create any missing leaf(s) if we are doing a recovery (marking * the block(s) as being allocated instead of being freed). Be sure * to initialize the auxillary freemap tracking info in the * bref.check.freemap structure. */ if (chain == NULL && how == HAMMER2_FREEMAP_DORECOVER) { error = hammer2_chain_create(&parent, &chain, NULL, hmp->spmp, HAMMER2_METH_DEFAULT, key, HAMMER2_FREEMAP_LEVEL1_RADIX, HAMMER2_BREF_TYPE_FREEMAP_LEAF, HAMMER2_FREEMAP_LEVELN_PSIZE, mtid, 0, 0); if (hammer2_debug & 0x0040) { kprintf("fixup create chain %p %016jx:%d\n", chain, chain->bref.key, chain->bref.keybits); } if (error == 0) { error = hammer2_chain_modify(chain, mtid, 0, 0); KKASSERT(error == 0); bzero(&chain->data->bmdata[0], HAMMER2_FREEMAP_LEVELN_PSIZE); chain->bref.check.freemap.bigmask = (uint32_t)-1; chain->bref.check.freemap.avail = l1size; /* bref.methods should already be inherited */ hammer2_freemap_init(hmp, key, chain); } /* XXX handle error */ } #if FREEMAP_DEBUG kprintf("FREEMAP ADJUST TYPE %d %016jx/%d DATA_OFF=%016jx\n", chain->bref.type, chain->bref.key, chain->bref.keybits, chain->bref.data_off); #endif /* * Calculate the bitmask (runs in 2-bit pairs). */ start = ((int)(data_off >> HAMMER2_FREEMAP_BLOCK_RADIX) & 15) * 2; //bmmask01 = (hammer2_bitmap_t)1 << start; //bmmask10 = (hammer2_bitmap_t)2 << start; bmmask11 = (hammer2_bitmap_t)3 << start; /* * Fixup the bitmap. Partial blocks cannot be fully freed unless * a bulk scan is able to roll them up. */ if (radix < HAMMER2_FREEMAP_BLOCK_RADIX) { count = 1; #if 0 if (how == HAMMER2_FREEMAP_DOREALFREE) how = HAMMER2_FREEMAP_DOMAYFREE; #endif } else { count = 1 << (radix - HAMMER2_FREEMAP_BLOCK_RADIX); } /* * [re]load the bmap and bitmap pointers. Each bmap entry covers * a 4MB swath. The bmap itself (LEVEL1) covers 2GB. * * Be sure to reset the linear iterator to ensure that the adjustment * is not ignored. */ again: bmap = &chain->data->bmdata[(int)(data_off >> HAMMER2_SEGRADIX) & (HAMMER2_FREEMAP_COUNT - 1)]; bitmap = &bmap->bitmapq[(int)(data_off >> (HAMMER2_SEGRADIX - 3)) & 7]; if (modified) bmap->linear = 0; while (count) { KKASSERT(bmmask11); if (how == HAMMER2_FREEMAP_DORECOVER) { /* * Recovery request, mark as allocated. */ if ((*bitmap & bmmask11) != bmmask11) { if (modified == 0) { hammer2_chain_modify(chain, mtid, 0, 0); modified = 1; goto again; } if ((*bitmap & bmmask11) == bmmask00) { bmap->avail -= HAMMER2_FREEMAP_BLOCK_SIZE; bgsize += HAMMER2_FREEMAP_BLOCK_SIZE; } if (bmap->class == 0) bmap->class = class; *bitmap |= bmmask11; if (hammer2_debug & 0x0040) { kprintf("hammer2_freemap_adjust: " "fixup type=%02x " "block=%016jx/%zd\n", bref->type, data_off, bytes); } } else { /* kprintf("hammer2_freemap_adjust: good " "type=%02x block=%016jx/%zd\n", bref->type, data_off, bytes); */ } } #if 0 /* * XXX this stuff doesn't work, avail is miscalculated and * code 10 means something else now. */ else if ((*bitmap & bmmask11) == bmmask11) { /* * Mayfree/Realfree request and bitmap is currently * marked as being fully allocated. */ if (!modified) { hammer2_chain_modify(chain, 0); modified = 1; goto again; } if (how == HAMMER2_FREEMAP_DOREALFREE) *bitmap &= ~bmmask11; else *bitmap = (*bitmap & ~bmmask11) | bmmask10; } else if ((*bitmap & bmmask11) == bmmask10) { /* * Mayfree/Realfree request and bitmap is currently * marked as being possibly freeable. */ if (how == HAMMER2_FREEMAP_DOREALFREE) { if (!modified) { hammer2_chain_modify(chain, 0); modified = 1; goto again; } *bitmap &= ~bmmask11; } } else { /* * 01 - Not implemented, currently illegal state * 00 - Not allocated at all, illegal free. */ panic("hammer2_freemap_adjust: " "Illegal state %08x(%08x)", *bitmap, *bitmap & bmmask11); } #endif --count; //bmmask01 <<= 2; //bmmask10 <<= 2; bmmask11 <<= 2; } #if 0 #if HAMMER2_BMAP_ELEMENTS != 8 #error "hammer2_freemap.c: HAMMER2_BMAP_ELEMENTS expected to be 8" #endif if (how == HAMMER2_FREEMAP_DOREALFREE && modified) { bmap->avail += 1 << radix; KKASSERT(bmap->avail <= HAMMER2_SEGSIZE); if (bmap->avail == HAMMER2_SEGSIZE && bmap->bitmapq[0] == 0 && bmap->bitmapq[1] == 0 && bmap->bitmapq[2] == 0 && bmap->bitmapq[3] == 0 && bmap->bitmapq[4] == 0 && bmap->bitmapq[5] == 0 && bmap->bitmapq[6] == 0 && bmap->bitmapq[7] == 0) { key = H2FMBASE(data_off, HAMMER2_FREEMAP_LEVEL0_RADIX); kprintf("Freeseg %016jx\n", (intmax_t)key); bmap->class = 0; } } #endif /* * chain->bref.check.freemap.bigmask (XXX) * * Setting bigmask is a hint to the allocation code that there might * be something allocatable. We also set this in recovery... it * doesn't hurt and we might want to use the hint for other validation * operations later on. * * We could calculate the largest possible allocation and set the * radixes that could fit, but its easier just to set bigmask to -1. */ if (modified) { chain->bref.check.freemap.bigmask = -1; hmp->freemap_relaxed = 0; /* reset heuristic */ } hammer2_chain_unlock(chain); hammer2_chain_drop(chain); done: hammer2_chain_unlock(parent); hammer2_chain_drop(parent); if (bgsize) { hammer2_voldata_lock(hmp); hammer2_voldata_modify(hmp); hmp->voldata.allocator_free -= bgsize; hammer2_voldata_unlock(hmp); } } /* * Validate the freemap, in three stages. * * stage-1 ALLOCATED -> POSSIBLY FREE * POSSIBLY FREE -> POSSIBLY FREE (type corrected) * * This transitions bitmap entries from ALLOCATED to POSSIBLY FREE. * The POSSIBLY FREE state does not mean that a block is actually free * and may be transitioned back to ALLOCATED in stage-2. * * This is typically done during normal filesystem operations when * something is deleted or a block is replaced. * * This is done by bulkfree in-bulk after a memory-bounded meta-data * scan to try to determine what might be freeable. * * This can be done unconditionally through a freemap scan when the * intention is to brute-force recover the proper state of the freemap. * * stage-2 POSSIBLY FREE -> ALLOCATED (scan metadata topology) * * This is done by bulkfree during a meta-data scan to ensure that * all blocks still actually allocated by the filesystem are marked * as such. * * NOTE! Live filesystem transitions to POSSIBLY FREE can occur while * the bulkfree stage-2 and stage-3 is running. The live filesystem * will use the alternative POSSIBLY FREE type (2) to prevent * stage-3 from improperly transitioning unvetted possibly-free * blocks to FREE. * * stage-3 POSSIBLY FREE (type 1) -> FREE (scan freemap) * * This is done by bulkfree to finalize POSSIBLY FREE states. * */ |