icount.c revision de8f3a76218255e443ba57dec5d74850180fa75d
1/* 2 * icount.c --- an efficient inode count abstraction 3 * 4 * Copyright (C) 1997 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Public 8 * License. 9 * %End-Header% 10 */ 11 12#if HAVE_UNISTD_H 13#include <unistd.h> 14#endif 15#include <string.h> 16#include <stdio.h> 17#include <sys/stat.h> 18#include <fcntl.h> 19#include <errno.h> 20 21#include "ext2_fs.h" 22#include "ext2fs.h" 23#include "tdb.h" 24 25/* 26 * The data storage strategy used by icount relies on the observation 27 * that most inode counts are either zero (for non-allocated inodes), 28 * one (for most files), and only a few that are two or more 29 * (directories and files that are linked to more than one directory). 30 * 31 * Also, e2fsck tends to load the icount data sequentially. 32 * 33 * So, we use an inode bitmap to indicate which inodes have a count of 34 * one, and then use a sorted list to store the counts for inodes 35 * which are greater than one. 36 * 37 * We also use an optional bitmap to indicate which inodes are already 38 * in the sorted list, to speed up the use of this abstraction by 39 * e2fsck's pass 2. Pass 2 increments inode counts as it finds them, 40 * so this extra bitmap avoids searching the sorted list to see if a 41 * particular inode is on the sorted list already. 42 */ 43 44struct ext2_icount_el { 45 ext2_ino_t ino; 46 __u16 count; 47}; 48 49struct ext2_icount { 50 errcode_t magic; 51 ext2fs_inode_bitmap single; 52 ext2fs_inode_bitmap multiple; 53 ext2_ino_t count; 54 ext2_ino_t size; 55 ext2_ino_t num_inodes; 56 ext2_ino_t cursor; 57 struct ext2_icount_el *list; 58 struct ext2_icount_el *last_lookup; 59 char *tdb_fn; 60 TDB_CONTEXT *tdb; 61}; 62 63void ext2fs_free_icount(ext2_icount_t icount) 64{ 65 if (!icount) 66 return; 67 68 icount->magic = 0; 69 if (icount->list) 70 ext2fs_free_mem(&icount->list); 71 if (icount->single) 72 ext2fs_free_inode_bitmap(icount->single); 73 if (icount->multiple) 74 ext2fs_free_inode_bitmap(icount->multiple); 75 if (icount->tdb) 76 tdb_close(icount->tdb); 77 if (icount->tdb_fn) { 78 unlink(icount->tdb_fn); 79 free(icount->tdb_fn); 80 } 81 82 ext2fs_free_mem(&icount); 83} 84 85static errcode_t alloc_icount(ext2_filsys fs, int flags, ext2_icount_t *ret) 86{ 87 ext2_icount_t icount; 88 errcode_t retval; 89 90 *ret = 0; 91 92 retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount); 93 if (retval) 94 return retval; 95 memset(icount, 0, sizeof(struct ext2_icount)); 96 97 retval = ext2fs_allocate_inode_bitmap(fs, 0, &icount->single); 98 if (retval) 99 goto errout; 100 101 if (flags & EXT2_ICOUNT_OPT_INCREMENT) { 102 retval = ext2fs_allocate_inode_bitmap(fs, 0, 103 &icount->multiple); 104 if (retval) 105 goto errout; 106 } else 107 icount->multiple = 0; 108 109 icount->magic = EXT2_ET_MAGIC_ICOUNT; 110 icount->num_inodes = fs->super->s_inodes_count; 111 112 *ret = icount; 113 return 0; 114 115errout: 116 ext2fs_free_icount(icount); 117 return(retval); 118} 119 120struct uuid { 121 __u32 time_low; 122 __u16 time_mid; 123 __u16 time_hi_and_version; 124 __u16 clock_seq; 125 __u8 node[6]; 126}; 127 128static void unpack_uuid(void *in, struct uuid *uu) 129{ 130 __u8 *ptr = in; 131 __u32 tmp; 132 133 tmp = *ptr++; 134 tmp = (tmp << 8) | *ptr++; 135 tmp = (tmp << 8) | *ptr++; 136 tmp = (tmp << 8) | *ptr++; 137 uu->time_low = tmp; 138 139 tmp = *ptr++; 140 tmp = (tmp << 8) | *ptr++; 141 uu->time_mid = tmp; 142 143 tmp = *ptr++; 144 tmp = (tmp << 8) | *ptr++; 145 uu->time_hi_and_version = tmp; 146 147 tmp = *ptr++; 148 tmp = (tmp << 8) | *ptr++; 149 uu->clock_seq = tmp; 150 151 memcpy(uu->node, ptr, 6); 152} 153 154static void uuid_unparse(void *uu, char *out) 155{ 156 struct uuid uuid; 157 158 unpack_uuid(uu, &uuid); 159 sprintf(out, 160 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 161 uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, 162 uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, 163 uuid.node[0], uuid.node[1], uuid.node[2], 164 uuid.node[3], uuid.node[4], uuid.node[5]); 165} 166 167errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir, 168 int flags, ext2_icount_t *ret) 169{ 170 ext2_icount_t icount; 171 errcode_t retval; 172 char *fn, uuid[40]; 173 int fd; 174 175 retval = alloc_icount(fs, flags, &icount); 176 if (retval) 177 return retval; 178 179 retval = ext2fs_get_mem(strlen(tdb_dir) + 64, &fn); 180 if (retval) 181 goto errout; 182 uuid_unparse(fs->super->s_uuid, uuid); 183 sprintf(fn, "%s/%s-icount-XXXXXX", tdb_dir, uuid); 184 fd = mkstemp(fn); 185 186 icount->tdb_fn = fn; 187 icount->tdb = tdb_open(fn, 0, TDB_CLEAR_IF_FIRST, 188 O_RDWR | O_CREAT | O_TRUNC, 0600); 189 if (icount->tdb) { 190 close(fd); 191 *ret = icount; 192 return 0; 193 } 194 195 retval = errno; 196 close(fd); 197 198errout: 199 ext2fs_free_icount(icount); 200 return(retval); 201} 202 203errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size, 204 ext2_icount_t hint, ext2_icount_t *ret) 205{ 206 ext2_icount_t icount; 207 errcode_t retval; 208 size_t bytes; 209 ext2_ino_t i; 210 211 if (hint) { 212 EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT); 213 if (hint->size > size) 214 size = (size_t) hint->size; 215 } 216 217 retval = alloc_icount(fs, flags, &icount); 218 if (retval) 219 return retval; 220 221 if (size) { 222 icount->size = size; 223 } else { 224 /* 225 * Figure out how many special case inode counts we will 226 * have. We know we will need one for each directory; 227 * we also need to reserve some extra room for file links 228 */ 229 retval = ext2fs_get_num_dirs(fs, &icount->size); 230 if (retval) 231 goto errout; 232 icount->size += fs->super->s_inodes_count / 50; 233 } 234 235 bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el)); 236#if 0 237 printf("Icount allocated %u entries, %d bytes.\n", 238 icount->size, bytes); 239#endif 240 retval = ext2fs_get_mem(bytes, &icount->list); 241 if (retval) 242 goto errout; 243 memset(icount->list, 0, bytes); 244 245 icount->count = 0; 246 icount->cursor = 0; 247 248 /* 249 * Populate the sorted list with those entries which were 250 * found in the hint icount (since those are ones which will 251 * likely need to be in the sorted list this time around). 252 */ 253 if (hint) { 254 for (i=0; i < hint->count; i++) 255 icount->list[i].ino = hint->list[i].ino; 256 icount->count = hint->count; 257 } 258 259 *ret = icount; 260 return 0; 261 262errout: 263 ext2fs_free_icount(icount); 264 return(retval); 265} 266 267errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, 268 unsigned int size, 269 ext2_icount_t *ret) 270{ 271 return ext2fs_create_icount2(fs, flags, size, 0, ret); 272} 273 274/* 275 * insert_icount_el() --- Insert a new entry into the sorted list at a 276 * specified position. 277 */ 278static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount, 279 ext2_ino_t ino, int pos) 280{ 281 struct ext2_icount_el *el; 282 errcode_t retval; 283 ext2_ino_t new_size = 0; 284 int num; 285 286 if (icount->last_lookup && icount->last_lookup->ino == ino) 287 return icount->last_lookup; 288 289 if (icount->count >= icount->size) { 290 if (icount->count) { 291 new_size = icount->list[(unsigned)icount->count-1].ino; 292 new_size = (ext2_ino_t) (icount->count * 293 ((float) icount->num_inodes / new_size)); 294 } 295 if (new_size < (icount->size + 100)) 296 new_size = icount->size + 100; 297#if 0 298 printf("Reallocating icount %u entries...\n", new_size); 299#endif 300 retval = ext2fs_resize_mem((size_t) icount->size * 301 sizeof(struct ext2_icount_el), 302 (size_t) new_size * 303 sizeof(struct ext2_icount_el), 304 &icount->list); 305 if (retval) 306 return 0; 307 icount->size = new_size; 308 } 309 num = (int) icount->count - pos; 310 if (num < 0) 311 return 0; /* should never happen */ 312 if (num) { 313 memmove(&icount->list[pos+1], &icount->list[pos], 314 sizeof(struct ext2_icount_el) * num); 315 } 316 icount->count++; 317 el = &icount->list[pos]; 318 el->count = 0; 319 el->ino = ino; 320 icount->last_lookup = el; 321 return el; 322} 323 324/* 325 * get_icount_el() --- given an inode number, try to find icount 326 * information in the sorted list. If the create flag is set, 327 * and we can't find an entry, create one in the sorted list. 328 */ 329static struct ext2_icount_el *get_icount_el(ext2_icount_t icount, 330 ext2_ino_t ino, int create) 331{ 332 float range; 333 int low, high, mid; 334 ext2_ino_t lowval, highval; 335 336 if (!icount || !icount->list) 337 return 0; 338 339 if (create && ((icount->count == 0) || 340 (ino > icount->list[(unsigned)icount->count-1].ino))) { 341 return insert_icount_el(icount, ino, (unsigned) icount->count); 342 } 343 if (icount->count == 0) 344 return 0; 345 346 if (icount->cursor >= icount->count) 347 icount->cursor = 0; 348 if (ino == icount->list[icount->cursor].ino) 349 return &icount->list[icount->cursor++]; 350#if 0 351 printf("Non-cursor get_icount_el: %u\n", ino); 352#endif 353 low = 0; 354 high = (int) icount->count-1; 355 while (low <= high) { 356#if 0 357 mid = (low+high)/2; 358#else 359 if (low == high) 360 mid = low; 361 else { 362 /* Interpolate for efficiency */ 363 lowval = icount->list[low].ino; 364 highval = icount->list[high].ino; 365 366 if (ino < lowval) 367 range = 0; 368 else if (ino > highval) 369 range = 1; 370 else { 371 range = ((float) (ino - lowval)) / 372 (highval - lowval); 373 if (range > 0.9) 374 range = 0.9; 375 if (range < 0.1) 376 range = 0.1; 377 } 378 mid = low + ((int) (range * (high-low))); 379 } 380#endif 381 if (ino == icount->list[mid].ino) { 382 icount->cursor = mid+1; 383 return &icount->list[mid]; 384 } 385 if (ino < icount->list[mid].ino) 386 high = mid-1; 387 else 388 low = mid+1; 389 } 390 /* 391 * If we need to create a new entry, it should be right at 392 * low (where high will be left at low-1). 393 */ 394 if (create) 395 return insert_icount_el(icount, ino, low); 396 return 0; 397} 398 399static errcode_t set_inode_count(ext2_icount_t icount, ext2_ino_t ino, 400 __u16 count) 401{ 402 struct ext2_icount_el *el; 403 TDB_DATA key, data; 404 405 if (icount->tdb) { 406 key.dptr = (unsigned char *) &ino; 407 key.dsize = sizeof(ext2_ino_t); 408 data.dptr = (unsigned char *) &count; 409 data.dsize = sizeof(__u16); 410 if (count) { 411 if (tdb_store(icount->tdb, key, data, TDB_REPLACE)) 412 return tdb_error(icount->tdb) + 413 EXT2_ET_TDB_SUCCESS; 414 } else { 415 if (tdb_delete(icount->tdb, key)) 416 return tdb_error(icount->tdb) + 417 EXT2_ET_TDB_SUCCESS; 418 } 419 return 0; 420 } 421 422 el = get_icount_el(icount, ino, 1); 423 if (!el) 424 return EXT2_ET_NO_MEMORY; 425 426 el->count = count; 427 return 0; 428} 429 430static errcode_t get_inode_count(ext2_icount_t icount, ext2_ino_t ino, 431 __u16 *count) 432{ 433 struct ext2_icount_el *el; 434 TDB_DATA key, data; 435 436 if (icount->tdb) { 437 key.dptr = (unsigned char *) &ino; 438 key.dsize = sizeof(ext2_ino_t); 439 440 data = tdb_fetch(icount->tdb, key); 441 if (data.dptr == NULL) { 442 *count = 0; 443 return tdb_error(icount->tdb) + EXT2_ET_TDB_SUCCESS; 444 } 445 446 *count = *((__u16 *) data.dptr); 447 free(data.dptr); 448 return 0; 449 } 450 el = get_icount_el(icount, ino, 0); 451 if (!el) { 452 *count = 0; 453 return ENOENT; 454 } 455 456 *count = el->count; 457 return 0; 458} 459 460errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out) 461{ 462 errcode_t ret = 0; 463 unsigned int i; 464 const char *bad = "bad icount"; 465 466 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 467 468 if (icount->count > icount->size) { 469 fprintf(out, "%s: count > size\n", bad); 470 return EXT2_ET_INVALID_ARGUMENT; 471 } 472 for (i=1; i < icount->count; i++) { 473 if (icount->list[i-1].ino >= icount->list[i].ino) { 474 fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n", 475 bad, i-1, icount->list[i-1].ino, 476 i, icount->list[i].ino); 477 ret = EXT2_ET_INVALID_ARGUMENT; 478 } 479 } 480 return ret; 481} 482 483errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret) 484{ 485 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 486 487 if (!ino || (ino > icount->num_inodes)) 488 return EXT2_ET_INVALID_ARGUMENT; 489 490 if (ext2fs_test_inode_bitmap(icount->single, ino)) { 491 *ret = 1; 492 return 0; 493 } 494 if (icount->multiple && 495 !ext2fs_test_inode_bitmap(icount->multiple, ino)) { 496 *ret = 0; 497 return 0; 498 } 499 get_inode_count(icount, ino, ret); 500 return 0; 501} 502 503errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino, 504 __u16 *ret) 505{ 506 __u16 curr_value; 507 508 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 509 510 if (!ino || (ino > icount->num_inodes)) 511 return EXT2_ET_INVALID_ARGUMENT; 512 513 if (ext2fs_test_inode_bitmap(icount->single, ino)) { 514 /* 515 * If the existing count is 1, then we know there is 516 * no entry in the list. 517 */ 518 if (set_inode_count(icount, ino, 2)) 519 return EXT2_ET_NO_MEMORY; 520 curr_value = 2; 521 ext2fs_unmark_inode_bitmap(icount->single, ino); 522 } else if (icount->multiple) { 523 /* 524 * The count is either zero or greater than 1; if the 525 * inode is set in icount->multiple, then there should 526 * be an entry in the list, so we need to fix it. 527 */ 528 if (ext2fs_test_inode_bitmap(icount->multiple, ino)) { 529 get_inode_count(icount, ino, &curr_value); 530 curr_value++; 531 if (set_inode_count(icount, ino, curr_value)) 532 return EXT2_ET_NO_MEMORY; 533 } else { 534 /* 535 * The count was zero; mark the single bitmap 536 * and return. 537 */ 538 ext2fs_mark_inode_bitmap(icount->single, ino); 539 if (ret) 540 *ret = 1; 541 return 0; 542 } 543 } else { 544 /* 545 * The count is either zero or greater than 1; try to 546 * find an entry in the list to determine which. 547 */ 548 get_inode_count(icount, ino, &curr_value); 549 curr_value++; 550 if (set_inode_count(icount, ino, curr_value)) 551 return EXT2_ET_NO_MEMORY; 552 } 553 if (icount->multiple) 554 ext2fs_mark_inode_bitmap(icount->multiple, ino); 555 if (ret) 556 *ret = curr_value; 557 return 0; 558} 559 560errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, 561 __u16 *ret) 562{ 563 __u16 curr_value; 564 565 if (!ino || (ino > icount->num_inodes)) 566 return EXT2_ET_INVALID_ARGUMENT; 567 568 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 569 570 if (ext2fs_test_inode_bitmap(icount->single, ino)) { 571 ext2fs_unmark_inode_bitmap(icount->single, ino); 572 if (icount->multiple) 573 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 574 else { 575 set_inode_count(icount, ino, 0); 576 } 577 if (ret) 578 *ret = 0; 579 return 0; 580 } 581 582 if (icount->multiple && 583 !ext2fs_test_inode_bitmap(icount->multiple, ino)) 584 return EXT2_ET_INVALID_ARGUMENT; 585 586 get_inode_count(icount, ino, &curr_value); 587 if (!curr_value) 588 return EXT2_ET_INVALID_ARGUMENT; 589 curr_value--; 590 if (set_inode_count(icount, ino, curr_value)) 591 return EXT2_ET_NO_MEMORY; 592 593 if (curr_value == 1) 594 ext2fs_mark_inode_bitmap(icount->single, ino); 595 if ((curr_value == 0) && icount->multiple) 596 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 597 598 if (ret) 599 *ret = curr_value; 600 return 0; 601} 602 603errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, 604 __u16 count) 605{ 606 if (!ino || (ino > icount->num_inodes)) 607 return EXT2_ET_INVALID_ARGUMENT; 608 609 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 610 611 if (count == 1) { 612 ext2fs_mark_inode_bitmap(icount->single, ino); 613 if (icount->multiple) 614 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 615 return 0; 616 } 617 if (count == 0) { 618 ext2fs_unmark_inode_bitmap(icount->single, ino); 619 if (icount->multiple) { 620 /* 621 * If the icount->multiple bitmap is enabled, 622 * we can just clear both bitmaps and we're done 623 */ 624 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 625 } else 626 set_inode_count(icount, ino, 0); 627 return 0; 628 } 629 630 if (set_inode_count(icount, ino, count)) 631 return EXT2_ET_NO_MEMORY; 632 ext2fs_unmark_inode_bitmap(icount->single, ino); 633 if (icount->multiple) 634 ext2fs_mark_inode_bitmap(icount->multiple, ino); 635 return 0; 636} 637 638ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount) 639{ 640 if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT) 641 return 0; 642 643 return icount->size; 644} 645 646#ifdef DEBUG 647 648ext2_filsys test_fs; 649ext2_icount_t icount; 650 651#define EXIT 0x00 652#define FETCH 0x01 653#define STORE 0x02 654#define INCREMENT 0x03 655#define DECREMENT 0x04 656 657struct test_program { 658 int cmd; 659 ext2_ino_t ino; 660 __u16 arg; 661 __u16 expected; 662}; 663 664struct test_program prog[] = { 665 { STORE, 42, 42, 42 }, 666 { STORE, 1, 1, 1 }, 667 { STORE, 2, 2, 2 }, 668 { STORE, 3, 3, 3 }, 669 { STORE, 10, 1, 1 }, 670 { STORE, 42, 0, 0 }, 671 { INCREMENT, 5, 0, 1 }, 672 { INCREMENT, 5, 0, 2 }, 673 { INCREMENT, 5, 0, 3 }, 674 { INCREMENT, 5, 0, 4 }, 675 { DECREMENT, 5, 0, 3 }, 676 { DECREMENT, 5, 0, 2 }, 677 { DECREMENT, 5, 0, 1 }, 678 { DECREMENT, 5, 0, 0 }, 679 { FETCH, 10, 0, 1 }, 680 { FETCH, 1, 0, 1 }, 681 { FETCH, 2, 0, 2 }, 682 { FETCH, 3, 0, 3 }, 683 { INCREMENT, 1, 0, 2 }, 684 { DECREMENT, 2, 0, 1 }, 685 { DECREMENT, 2, 0, 0 }, 686 { FETCH, 12, 0, 0 }, 687 { EXIT, 0, 0, 0 } 688}; 689 690struct test_program extended[] = { 691 { STORE, 1, 1, 1 }, 692 { STORE, 2, 2, 2 }, 693 { STORE, 3, 3, 3 }, 694 { STORE, 4, 4, 4 }, 695 { STORE, 5, 5, 5 }, 696 { STORE, 6, 1, 1 }, 697 { STORE, 7, 2, 2 }, 698 { STORE, 8, 3, 3 }, 699 { STORE, 9, 4, 4 }, 700 { STORE, 10, 5, 5 }, 701 { STORE, 11, 1, 1 }, 702 { STORE, 12, 2, 2 }, 703 { STORE, 13, 3, 3 }, 704 { STORE, 14, 4, 4 }, 705 { STORE, 15, 5, 5 }, 706 { STORE, 16, 1, 1 }, 707 { STORE, 17, 2, 2 }, 708 { STORE, 18, 3, 3 }, 709 { STORE, 19, 4, 4 }, 710 { STORE, 20, 5, 5 }, 711 { STORE, 21, 1, 1 }, 712 { STORE, 22, 2, 2 }, 713 { STORE, 23, 3, 3 }, 714 { STORE, 24, 4, 4 }, 715 { STORE, 25, 5, 5 }, 716 { STORE, 26, 1, 1 }, 717 { STORE, 27, 2, 2 }, 718 { STORE, 28, 3, 3 }, 719 { STORE, 29, 4, 4 }, 720 { STORE, 30, 5, 5 }, 721 { EXIT, 0, 0, 0 } 722}; 723 724/* 725 * Setup the variables for doing the inode scan test. 726 */ 727static void setup(void) 728{ 729 errcode_t retval; 730 struct ext2_super_block param; 731 732 initialize_ext2_error_table(); 733 734 memset(¶m, 0, sizeof(param)); 735 param.s_blocks_count = 12000; 736 737 retval = ext2fs_initialize("test fs", 0, ¶m, 738 test_io_manager, &test_fs); 739 if (retval) { 740 com_err("setup", retval, 741 "while initializing filesystem"); 742 exit(1); 743 } 744 retval = ext2fs_allocate_tables(test_fs); 745 if (retval) { 746 com_err("setup", retval, 747 "while allocating tables for test filesystem"); 748 exit(1); 749 } 750} 751 752int run_test(int flags, int size, char *dir, struct test_program *prog) 753{ 754 errcode_t retval; 755 ext2_icount_t icount; 756 struct test_program *pc; 757 __u16 result; 758 int problem = 0; 759 760 if (dir) { 761 retval = ext2fs_create_icount_tdb(test_fs, dir, 762 flags, &icount); 763 if (retval) { 764 com_err("run_test", retval, 765 "while creating icount using tdb"); 766 exit(1); 767 } 768 } else { 769 retval = ext2fs_create_icount2(test_fs, flags, size, 0, 770 &icount); 771 if (retval) { 772 com_err("run_test", retval, "while creating icount"); 773 exit(1); 774 } 775 } 776 for (pc = prog; pc->cmd != EXIT; pc++) { 777 switch (pc->cmd) { 778 case FETCH: 779 printf("icount_fetch(%u) = ", pc->ino); 780 break; 781 case STORE: 782 retval = ext2fs_icount_store(icount, pc->ino, pc->arg); 783 if (retval) { 784 com_err("run_test", retval, 785 "while calling icount_store"); 786 exit(1); 787 } 788 printf("icount_store(%u, %u) = ", pc->ino, pc->arg); 789 break; 790 case INCREMENT: 791 retval = ext2fs_icount_increment(icount, pc->ino, 0); 792 if (retval) { 793 com_err("run_test", retval, 794 "while calling icount_increment"); 795 exit(1); 796 } 797 printf("icount_increment(%u) = ", pc->ino); 798 break; 799 case DECREMENT: 800 retval = ext2fs_icount_decrement(icount, pc->ino, 0); 801 if (retval) { 802 com_err("run_test", retval, 803 "while calling icount_decrement"); 804 exit(1); 805 } 806 printf("icount_decrement(%u) = ", pc->ino); 807 break; 808 } 809 retval = ext2fs_icount_fetch(icount, pc->ino, &result); 810 if (retval) { 811 com_err("run_test", retval, 812 "while calling icount_fetch"); 813 exit(1); 814 } 815 printf("%u (%s)\n", result, (result == pc->expected) ? 816 "OK" : "NOT OK"); 817 if (result != pc->expected) 818 problem++; 819 } 820 printf("icount size is %u\n", ext2fs_get_icount_size(icount)); 821 retval = ext2fs_icount_validate(icount, stdout); 822 if (retval) { 823 com_err("run_test", retval, "while calling icount_validate"); 824 exit(1); 825 } 826 ext2fs_free_icount(icount); 827 return problem; 828} 829 830 831int main(int argc, char **argv) 832{ 833 int failed = 0; 834 835 setup(); 836 printf("Standard icount run:\n"); 837 failed += run_test(0, 0, 0, prog); 838 printf("\nMultiple bitmap test:\n"); 839 failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, 0, prog); 840 printf("\nResizing icount:\n"); 841 failed += run_test(0, 3, 0, extended); 842 printf("\nStandard icount run with tdb:\n"); 843 failed += run_test(0, 0, ".", prog); 844 printf("\nMultiple bitmap test with tdb:\n"); 845 failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, ".", prog); 846 if (failed) 847 printf("FAILED!\n"); 848 return failed; 849} 850#endif 851