icount.c revision 1b9d8cb7057387afae106ffa662613205f07e131
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 return 0; 448 } 449 el = get_icount_el(icount, ino, 0); 450 if (!el) { 451 *count = 0; 452 return ENOENT; 453 } 454 455 *count = el->count; 456 return 0; 457} 458 459errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out) 460{ 461 errcode_t ret = 0; 462 unsigned int i; 463 const char *bad = "bad icount"; 464 465 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 466 467 if (icount->count > icount->size) { 468 fprintf(out, "%s: count > size\n", bad); 469 return EXT2_ET_INVALID_ARGUMENT; 470 } 471 for (i=1; i < icount->count; i++) { 472 if (icount->list[i-1].ino >= icount->list[i].ino) { 473 fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n", 474 bad, i-1, icount->list[i-1].ino, 475 i, icount->list[i].ino); 476 ret = EXT2_ET_INVALID_ARGUMENT; 477 } 478 } 479 return ret; 480} 481 482errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret) 483{ 484 struct ext2_icount_el *el; 485 486 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 487 488 if (!ino || (ino > icount->num_inodes)) 489 return EXT2_ET_INVALID_ARGUMENT; 490 491 if (ext2fs_test_inode_bitmap(icount->single, ino)) { 492 *ret = 1; 493 return 0; 494 } 495 if (icount->multiple && 496 !ext2fs_test_inode_bitmap(icount->multiple, ino)) { 497 *ret = 0; 498 return 0; 499 } 500 get_inode_count(icount, ino, ret); 501 return 0; 502} 503 504errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino, 505 __u16 *ret) 506{ 507 struct ext2_icount_el *el; 508 __u16 curr_value; 509 510 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 511 512 if (!ino || (ino > icount->num_inodes)) 513 return EXT2_ET_INVALID_ARGUMENT; 514 515 if (ext2fs_test_inode_bitmap(icount->single, ino)) { 516 /* 517 * If the existing count is 1, then we know there is 518 * no entry in the list. 519 */ 520 if (set_inode_count(icount, ino, 2)) 521 return EXT2_ET_NO_MEMORY; 522 curr_value = 2; 523 ext2fs_unmark_inode_bitmap(icount->single, ino); 524 } else if (icount->multiple) { 525 /* 526 * The count is either zero or greater than 1; if the 527 * inode is set in icount->multiple, then there should 528 * be an entry in the list, so we need to fix it. 529 */ 530 if (ext2fs_test_inode_bitmap(icount->multiple, ino)) { 531 get_inode_count(icount, ino, &curr_value); 532 curr_value++; 533 if (set_inode_count(icount, ino, curr_value)) 534 return EXT2_ET_NO_MEMORY; 535 } else { 536 /* 537 * The count was zero; mark the single bitmap 538 * and return. 539 */ 540 zero_count: 541 ext2fs_mark_inode_bitmap(icount->single, ino); 542 if (ret) 543 *ret = 1; 544 return 0; 545 } 546 } else { 547 /* 548 * The count is either zero or greater than 1; try to 549 * find an entry in the list to determine which. 550 */ 551 get_inode_count(icount, ino, &curr_value); 552 curr_value++; 553 if (set_inode_count(icount, ino, curr_value)) 554 return EXT2_ET_NO_MEMORY; 555 } 556 if (icount->multiple) 557 ext2fs_mark_inode_bitmap(icount->multiple, ino); 558 if (ret) 559 *ret = curr_value; 560 return 0; 561} 562 563errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, 564 __u16 *ret) 565{ 566 __u16 curr_value; 567 568 if (!ino || (ino > icount->num_inodes)) 569 return EXT2_ET_INVALID_ARGUMENT; 570 571 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 572 573 if (ext2fs_test_inode_bitmap(icount->single, ino)) { 574 ext2fs_unmark_inode_bitmap(icount->single, ino); 575 if (icount->multiple) 576 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 577 else { 578 set_inode_count(icount, ino, 0); 579 } 580 if (ret) 581 *ret = 0; 582 return 0; 583 } 584 585 if (icount->multiple && 586 !ext2fs_test_inode_bitmap(icount->multiple, ino)) 587 return EXT2_ET_INVALID_ARGUMENT; 588 589 get_inode_count(icount, ino, &curr_value); 590 if (!curr_value) 591 return EXT2_ET_INVALID_ARGUMENT; 592 curr_value--; 593 if (set_inode_count(icount, ino, curr_value)) 594 return EXT2_ET_NO_MEMORY; 595 596 if (curr_value == 1) 597 ext2fs_mark_inode_bitmap(icount->single, ino); 598 if ((curr_value == 0) && icount->multiple) 599 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 600 601 if (ret) 602 *ret = curr_value; 603 return 0; 604} 605 606errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, 607 __u16 count) 608{ 609 if (!ino || (ino > icount->num_inodes)) 610 return EXT2_ET_INVALID_ARGUMENT; 611 612 EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT); 613 614 if (count == 1) { 615 ext2fs_mark_inode_bitmap(icount->single, ino); 616 if (icount->multiple) 617 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 618 return 0; 619 } 620 if (count == 0) { 621 ext2fs_unmark_inode_bitmap(icount->single, ino); 622 if (icount->multiple) { 623 /* 624 * If the icount->multiple bitmap is enabled, 625 * we can just clear both bitmaps and we're done 626 */ 627 ext2fs_unmark_inode_bitmap(icount->multiple, ino); 628 } else 629 set_inode_count(icount, ino, 0); 630 return 0; 631 } 632 633 if (set_inode_count(icount, ino, count)) 634 return EXT2_ET_NO_MEMORY; 635 ext2fs_unmark_inode_bitmap(icount->single, ino); 636 if (icount->multiple) 637 ext2fs_mark_inode_bitmap(icount->multiple, ino); 638 return 0; 639} 640 641ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount) 642{ 643 if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT) 644 return 0; 645 646 return icount->size; 647} 648 649#ifdef DEBUG 650 651ext2_filsys test_fs; 652ext2_icount_t icount; 653 654#define EXIT 0x00 655#define FETCH 0x01 656#define STORE 0x02 657#define INCREMENT 0x03 658#define DECREMENT 0x04 659 660struct test_program { 661 int cmd; 662 ext2_ino_t ino; 663 __u16 arg; 664 __u16 expected; 665}; 666 667struct test_program prog[] = { 668 { STORE, 42, 42, 42 }, 669 { STORE, 1, 1, 1 }, 670 { STORE, 2, 2, 2 }, 671 { STORE, 3, 3, 3 }, 672 { STORE, 10, 1, 1 }, 673 { STORE, 42, 0, 0 }, 674 { INCREMENT, 5, 0, 1 }, 675 { INCREMENT, 5, 0, 2 }, 676 { INCREMENT, 5, 0, 3 }, 677 { INCREMENT, 5, 0, 4 }, 678 { DECREMENT, 5, 0, 3 }, 679 { DECREMENT, 5, 0, 2 }, 680 { DECREMENT, 5, 0, 1 }, 681 { DECREMENT, 5, 0, 0 }, 682 { FETCH, 10, 0, 1 }, 683 { FETCH, 1, 0, 1 }, 684 { FETCH, 2, 0, 2 }, 685 { FETCH, 3, 0, 3 }, 686 { INCREMENT, 1, 0, 2 }, 687 { DECREMENT, 2, 0, 1 }, 688 { DECREMENT, 2, 0, 0 }, 689 { FETCH, 12, 0, 0 }, 690 { EXIT, 0, 0, 0 } 691}; 692 693struct test_program extended[] = { 694 { STORE, 1, 1, 1 }, 695 { STORE, 2, 2, 2 }, 696 { STORE, 3, 3, 3 }, 697 { STORE, 4, 4, 4 }, 698 { STORE, 5, 5, 5 }, 699 { STORE, 6, 1, 1 }, 700 { STORE, 7, 2, 2 }, 701 { STORE, 8, 3, 3 }, 702 { STORE, 9, 4, 4 }, 703 { STORE, 10, 5, 5 }, 704 { STORE, 11, 1, 1 }, 705 { STORE, 12, 2, 2 }, 706 { STORE, 13, 3, 3 }, 707 { STORE, 14, 4, 4 }, 708 { STORE, 15, 5, 5 }, 709 { STORE, 16, 1, 1 }, 710 { STORE, 17, 2, 2 }, 711 { STORE, 18, 3, 3 }, 712 { STORE, 19, 4, 4 }, 713 { STORE, 20, 5, 5 }, 714 { STORE, 21, 1, 1 }, 715 { STORE, 22, 2, 2 }, 716 { STORE, 23, 3, 3 }, 717 { STORE, 24, 4, 4 }, 718 { STORE, 25, 5, 5 }, 719 { STORE, 26, 1, 1 }, 720 { STORE, 27, 2, 2 }, 721 { STORE, 28, 3, 3 }, 722 { STORE, 29, 4, 4 }, 723 { STORE, 30, 5, 5 }, 724 { EXIT, 0, 0, 0 } 725}; 726 727/* 728 * Setup the variables for doing the inode scan test. 729 */ 730static void setup(void) 731{ 732 errcode_t retval; 733 int i; 734 struct ext2_super_block param; 735 736 initialize_ext2_error_table(); 737 738 memset(¶m, 0, sizeof(param)); 739 param.s_blocks_count = 12000; 740 741 retval = ext2fs_initialize("test fs", 0, ¶m, 742 test_io_manager, &test_fs); 743 if (retval) { 744 com_err("setup", retval, 745 "while initializing filesystem"); 746 exit(1); 747 } 748 retval = ext2fs_allocate_tables(test_fs); 749 if (retval) { 750 com_err("setup", retval, 751 "while allocating tables for test filesystem"); 752 exit(1); 753 } 754} 755 756int run_test(int flags, int size, char *dir, struct test_program *prog) 757{ 758 errcode_t retval; 759 ext2_icount_t icount; 760 struct test_program *pc; 761 __u16 result; 762 int problem = 0; 763 764 if (dir) { 765 retval = ext2fs_create_icount_tdb(test_fs, dir, 766 flags, &icount); 767 if (retval) { 768 com_err("run_test", retval, 769 "while creating icount using tdb"); 770 exit(1); 771 } 772 } else { 773 retval = ext2fs_create_icount2(test_fs, flags, size, 0, 774 &icount); 775 if (retval) { 776 com_err("run_test", retval, "while creating icount"); 777 exit(1); 778 } 779 } 780 for (pc = prog; pc->cmd != EXIT; pc++) { 781 switch (pc->cmd) { 782 case FETCH: 783 printf("icount_fetch(%u) = ", pc->ino); 784 break; 785 case STORE: 786 retval = ext2fs_icount_store(icount, pc->ino, pc->arg); 787 if (retval) { 788 com_err("run_test", retval, 789 "while calling icount_store"); 790 exit(1); 791 } 792 printf("icount_store(%u, %u) = ", pc->ino, pc->arg); 793 break; 794 case INCREMENT: 795 retval = ext2fs_icount_increment(icount, pc->ino, 0); 796 if (retval) { 797 com_err("run_test", retval, 798 "while calling icount_increment"); 799 exit(1); 800 } 801 printf("icount_increment(%u) = ", pc->ino); 802 break; 803 case DECREMENT: 804 retval = ext2fs_icount_decrement(icount, pc->ino, 0); 805 if (retval) { 806 com_err("run_test", retval, 807 "while calling icount_decrement"); 808 exit(1); 809 } 810 printf("icount_decrement(%u) = ", pc->ino); 811 break; 812 } 813 retval = ext2fs_icount_fetch(icount, pc->ino, &result); 814 if (retval) { 815 com_err("run_test", retval, 816 "while calling icount_fetch"); 817 exit(1); 818 } 819 printf("%u (%s)\n", result, (result == pc->expected) ? 820 "OK" : "NOT OK"); 821 if (result != pc->expected) 822 problem++; 823 } 824 printf("icount size is %u\n", ext2fs_get_icount_size(icount)); 825 retval = ext2fs_icount_validate(icount, stdout); 826 if (retval) { 827 com_err("run_test", retval, "while calling icount_validate"); 828 exit(1); 829 } 830 ext2fs_free_icount(icount); 831 return problem; 832} 833 834 835int main(int argc, char **argv) 836{ 837 int failed = 0; 838 839 setup(); 840 printf("Standard icount run:\n"); 841 failed += run_test(0, 0, 0, prog); 842 printf("\nMultiple bitmap test:\n"); 843 failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, 0, prog); 844 printf("\nResizing icount:\n"); 845 failed += run_test(0, 3, 0, extended); 846 printf("\nStandard icount run with tdb:\n"); 847 failed += run_test(0, 0, ".", prog); 848 printf("\nMultiple bitmap test with tdb:\n"); 849 failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, ".", prog); 850 if (failed) 851 printf("FAILED!\n"); 852 return failed; 853} 854#endif 855