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