1/****************************************************************************** 2 3VERSION $FreeBSD: src/lib/libc/db/mpool/mpool.libtp,v 1.4 1999/08/27 23:58:23 peter Exp $ 4VERSION $DragonFly: src/lib/libc/db/mpool/mpool.libtp,v 1.2 2003/06/17 04:26:42 dillon Exp $ 5PACKAGE: User Level Shared Memory Manager 6 7DESCRIPTION: 8 This package provides a buffer pool interface implemented as 9 a collection of file pages mapped into shared memory. 10 11 Based on Mark's buffer manager 12 13ROUTINES: 14 External 15 buf_alloc 16 buf_flags 17 buf_get 18 buf_init 19 buf_last 20 buf_open 21 buf_pin 22 buf_sync 23 buf_unpin 24 Internal 25 bf_assign_buf 26 bf_fid_to_fd 27 bf_newbuf 28 bf_put_page 29 30 31******************************************************************************/ 32#include <sys/types.h> 33#include <assert.h> 34#include <sys/file.h> 35#include <sys/stat.h> 36#include <stdio.h> 37#include <errno.h> 38#include "list.h" 39#include "user.h" 40#include "txn_sys.h" 41#include "buf.h" 42#include "semkeys.h" 43#include "error.h" 44 45/* 46 we need to translate between some type of file id that the user 47 process passes and a file descriptor. For now, it's a nop. 48*/ 49#define GET_MASTER get_sem ( buf_spinlock ) 50#define RELEASE_MASTER release_sem ( buf_spinlock ) 51 52#define LRUID *buf_lru 53#define LRUP (bufhdr_table+*buf_lru) 54#define MRU bufhdr_table[*buf_lru].lru.prev 55 56/* Global indicator that you have started reusing buffers */ 57int do_statistics = 0; 58/* 59 Process Statics (pointers into shared memory) 60*/ 61static BUF_T *buf_table = 0; 62static BUFHDR_T *bufhdr_table; 63static int *buf_hash_table; 64static int *buf_lru; /* LRU is the free list */ 65static int buf_spinlock; 66static FINFO_T *buf_fids; 67static int *buf_sp; /* Pointer to string free space */ 68static char *buf_strings; 69 70/* Process Local FID->FD table */ 71static int fds[NUM_FILE_ENTRIES]; 72 73/* Static routines */ 74static BUFHDR_T *bf_assign_buf(); 75static int bf_fid_to_fd(); 76static BUFHDR_T *bf_newbuf(); 77static int bf_put_page(); 78 79/* 80 Return 0 on success 81 1 on failure 82*/ 83extern int 84buf_init ( ) 85{ 86 ADDR_T buf_region; 87 BUFHDR_T *bhp; 88 int i; 89 int ref_count; 90 int *spinlockp; 91 92 /* 93 Initialize Process local structures 94 */ 95 for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) { 96 fds[i] = -1; 97 } 98 99 buf_region = attach_region ( BUF_REGION_NAME, BUF_REGION_NUM, 100 BUF_REGION_SIZE, &ref_count ); 101 if ( !buf_region ) { 102 return (1); 103 } 104 error_log3 ( "Buf Region: ADDR: %d ID: %d SIZE: %d\n", buf_region, 105 BUF_REGION_NUM, BUF_REGION_SIZE ); 106 107 buf_table = (BUF_T *)buf_region; 108 bufhdr_table = (BUFHDR_T *)(buf_table + NUM_BUFS); 109 buf_hash_table = (int *)(bufhdr_table + NUM_BUFS); 110 buf_lru = buf_hash_table + NUMTABLE_ENTRIES; 111 spinlockp = buf_lru + 1; 112 buf_fids = (FINFO_T *)(spinlockp+1); 113 buf_sp = (int *)(buf_fids + NUM_FILE_ENTRIES); 114 buf_strings = (char *)(buf_sp + 1); 115 116 /* Create locking spinlock (gets creating holding the lock) */ 117 buf_spinlock = create_sem ( BUF_SPIN_NAME, BUF_SPIN_NUM, ref_count <= 1 ); 118 if ( buf_spinlock < 0 ) { 119 return(1); 120 } 121 if ( ref_count <= 1 ) { 122 *spinlockp = buf_spinlock; 123 124 /* Now initialize the buffer manager */ 125 126 /* 1. Free list */ 127 *buf_lru = 0; 128 129 /* 2. Buffer headers */ 130 for ( i = 0, bhp = bufhdr_table; i < NUM_BUFS; bhp++, i++ ) { 131 bhp->lru.next = i+1; 132 bhp->lru.prev = i-1; 133 bhp->flags = 0; /* All Flags off */ 134 bhp->refcount = 0; 135 bhp->wait_proc = -1; /* No sleepers */ 136 LISTPE_INIT ( hash, bhp, i ); /* Hash chains */ 137 } 138 bufhdr_table[0].lru.prev = NUM_BUFS-1; 139 bufhdr_table[NUM_BUFS-1].lru.next = 0; 140 141 /* 3. Hash Table */ 142 for ( i = 0; i < NUMTABLE_ENTRIES; i++ ) { 143 buf_hash_table[i] = NUM_BUFS; 144 } 145 146 /* 4. File ID Table */ 147 for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) { 148 buf_fids[i].offset = -1; 149 buf_fids[i].npages = -1; 150 buf_fids[i].refcount = 0; 151 } 152 153 /* 5. Free String Pointer */ 154 *buf_sp = (FILE_NAME_LEN*NUM_FILE_ENTRIES); 155 if (RELEASE_MASTER) { 156 return(1); 157 } 158 error_log0 ( "Initialized buffer region\n" ); 159 } 160 return (0); 161} 162 163extern void 164buf_exit() 165{ 166 int ref; 167 int i; 168 169 /* Flush Buffer Pool on Exit */ 170 for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) { 171 if ( fds[i] != -1 ) { 172 close ( fds[i] ); 173 } 174 } 175 if ( buf_table ) { 176 detach_region ( buf_table, BUF_REGION_NUM, BUF_REGION_SIZE, &ref ); 177 } 178 return; 179} 180 181/* 182 We need an empty buffer. Find the LRU unpinned NON-Dirty page. 183*/ 184static BUFHDR_T * 185bf_newbuf() 186{ 187 int fd; 188 int lruid; 189 int nbytes; 190 int ndx; 191 BUFHDR_T *bhp; 192 193 lruid = LRUID; 194 for ( bhp = LRUP; 195 bhp->flags & (BUF_PINNED|BUF_IO_IN_PROGRESS); 196 bhp = LISTP_NEXTP (bufhdr_table, lru, bhp ) ) { 197 198 if ( bhp->lru.next == lruid ) { 199 /* OUT OF BUFFERS */ 200 error_log1 ( "All buffers are pinned. %s\n", 201 "Unable to grant buffer request" ); 202 return(NULL); 203 } 204 } 205 /* BHP can be used */ 206 if ( bhp->flags & BUF_DIRTY ) { 207 do_statistics = 1; 208 /* 209 MIS Check for log flushed appropriately 210 */ 211 fd = bf_fid_to_fd(bhp->id.file_id); 212 if ( fd == -1 ) { 213 error_log1 ("Invalid fid %d\n", bhp->id.file_id); 214 return(NULL); 215 } 216 if ( bf_put_page(fd, bhp) < 0 ) { 217 return(NULL); 218 } 219 } 220 /* Update Hash Pointers */ 221 ndx = BUF_HASH ( bhp->id.file_id, bhp->id.obj_id ); 222 LISTP_REMOVE(bufhdr_table, hash, bhp); 223 if ( buf_hash_table[ndx] == (bhp-bufhdr_table) ) { 224 if ( bhp->hash.next != (bhp-bufhdr_table) ) { 225 buf_hash_table[ndx] = bhp->hash.next; 226 } else { 227 buf_hash_table[ndx] = NUM_BUFS; 228 } 229 } 230 INIT_BUF(bhp); 231 232 return(bhp); 233} 234/* 235 buf_alloc 236 237 Add a page to a file and return a buffer for it. 238 239*/ 240ADDR_T 241buf_alloc ( fid, new_pageno ) 242int fid; 243int *new_pageno; 244{ 245 BUFHDR_T *bhp; 246 int fd; 247 int len; 248 int ndx; 249 OBJ_T fobj; 250 251 if (GET_MASTER) { 252 return(NULL); 253 } 254 if ( buf_fids[fid].npages == -1 ) { 255 /* initialize npages field */ 256 fd = bf_fid_to_fd ( fid ); 257 } 258 assert (fid < NUM_FILE_ENTRIES); 259 260 *new_pageno = buf_fids[fid].npages; 261 if ( *new_pageno == -1 ) { 262 RELEASE_MASTER; 263 return ( NULL ); 264 } 265 buf_fids[fid].npages++; 266 ndx = BUF_HASH ( fid, *new_pageno ); 267 fobj.file_id = fid; 268 fobj.obj_id = *new_pageno; 269 bhp = bf_assign_buf ( ndx, &fobj, BF_PIN|BF_DIRTY|BF_EMPTY, &len ); 270 if ( RELEASE_MASTER ) { 271 /* Memory leak */ 272 return(NULL); 273 } 274 if ( bhp ) { 275 return ((ADDR_T)(buf_table+(bhp-bufhdr_table))); 276 } else { 277 return ( NULL ); 278 } 279} 280 281 282/* 283 Buffer Flags 284 BF_DIRTY Mark page as dirty 285 BF_EMPTY Don't initialize page, just get buffer 286 BF_PIN Retrieve with pin 287 288MIS 289Might want to add a flag that sets an LSN for this buffer is the 290DIRTY flag is set 291 292Eventually, you may want a flag that indicates the I/O and lock 293request should be shipped off together, but not for now. 294*/ 295extern ADDR_T 296buf_get ( file_id, page_id, flags, len ) 297int file_id; 298int page_id; 299u_long flags; 300int *len; /* Number of bytes read into buffer */ 301{ 302 BUFHDR_T *bhp; 303 int bufid; 304 int fd; 305 int ndx; 306 int next_bufid; 307 int stat; 308 OBJ_T fobj; 309 310 ndx = BUF_HASH ( file_id, page_id ); 311 fobj.file_id = (long) file_id; 312 fobj.obj_id = (long) page_id; 313 if ( GET_MASTER ) { 314 return(NULL); 315 } 316 /* 317 This could be a for loop, but we lose speed 318 by making all the cases general purpose so we 319 optimize for the no-collision case. 320 */ 321 bufid = buf_hash_table[ndx]; 322 if ( bufid < NUM_BUFS ) { 323 for ( bhp = bufhdr_table+bufid; 324 !OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID); 325 bhp = LISTP_NEXTP ( bufhdr_table, hash, bhp ) ) { 326 327 if ( bhp->hash.next == bufid ) { 328 goto not_found; 329 } 330 } 331/* found */ 332 if ( flags & BF_PIN ) { 333 bhp->flags |= BUF_PINNED; 334 bhp->refcount++; 335#ifdef PIN_DEBUG 336 fprintf(stderr, "buf_get: %X PINNED (%d)\n", 337 buf_table + (bhp-bufhdr_table), bhp->refcount); 338#endif 339 } 340 if ( flags & BF_DIRTY ) { 341 bhp->flags |= BUF_DIRTY; 342 } 343 344 while ( bhp->flags & BUF_IO_IN_PROGRESS ) { 345 /* MIS -- eventually err check here */ 346#ifdef DEBUG 347 printf("About to sleep on %d (me: %d\n)\n", bhp->wait_proc, 348 my_txnp - txn_table); 349#endif 350#ifdef WAIT_STATS 351 buf_waits++; 352#endif 353 stat = proc_sleep_on ( &(bhp->wait_proc), buf_spinlock ); 354 if ( stat ) { 355 /* Memory leak */ 356 return(NULL); 357 } 358 if (!( bhp->flags & BUF_IO_IN_PROGRESS) && 359 (!OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID))) { 360 if (RELEASE_MASTER) 361 return(NULL); 362 return(buf_get ( file_id, page_id, flags, len )); 363 } 364 } 365 MAKE_MRU( bhp ); 366 *len = BUFSIZE; 367 } else { 368not_found: 369 /* If you get here, the page isn't in the hash table */ 370 bhp = bf_assign_buf ( ndx, &fobj, flags, len ); 371 } 372 /* Common code between found and not found */ 373 374 if ( bhp && bhp->flags & BUF_NEWPAGE ) { 375 *len = 0; 376 } 377 if (RELEASE_MASTER){ 378 /* Memory leak */ 379 return(NULL); 380 } 381 if ( bhp ) { 382 return ((ADDR_T)(buf_table+(bhp-bufhdr_table))); 383 } else { 384 return ( NULL ); 385 } 386} 387 388/* 389 MIS - do I want to add file links to buffer pool? 390*/ 391extern int 392buf_sync ( fid, close ) 393int fid; 394int close; /* should we dec refcount and possibly 395 invalidate all the buffers */ 396{ 397 int i; 398 int fd; 399 int invalidate; 400 BUFHDR_T *bhp; 401 402 if ( (fd = bf_fid_to_fd ( fid )) < 0 ) { 403 return(1); 404 } 405 if (GET_MASTER) { 406 return(1); 407 } 408 invalidate = (buf_fids[fid].refcount == 1 && close); 409 if ( invalidate ) 410 for ( bhp = bufhdr_table, i = 0; i < NUM_BUFS; bhp++, i++ ) { 411 if (bhp->id.file_id == fid) { 412 if ((bhp->flags & BF_DIRTY) && (bf_put_page( fd, bhp ) < 0)) { 413 return(1); 414 } 415 bhp->id.file_id = -1; 416 } 417 } 418 if (invalidate || close) 419 buf_fids[fid].refcount--; 420 421 if (RELEASE_MASTER) { 422 return(1); 423 } 424 return(0); 425 426 427} 428 429extern int 430buf_flags ( addr, set_flags, unset_flags ) 431ADDR_T addr; 432u_long set_flags; 433u_long unset_flags; 434{ 435 int bufid; 436 BUFHDR_T *bhp; 437 438#ifdef PIN_DEBUG 439 fprintf(stderr, "buf_flags: %X setting %s%s%s%s%s releasing %s%s%s%s%s\n", 440 addr, 441 set_flags&BUF_DIRTY ? "DIRTY " : "", 442 set_flags&BUF_VALID ? "VALID " : "", 443 set_flags&BUF_PINNED ? "PINNED " : "", 444 set_flags&BUF_IO_ERROR ? "IO_ERROR " : "", 445 set_flags&BUF_IO_IN_PROGRESS ? "IO_IN_PROG " : "", 446 set_flags&BUF_NEWPAGE ? "NEWPAGE " : "", 447 unset_flags&BUF_DIRTY ? "DIRTY " : "", 448 unset_flags&BUF_VALID ? "VALID " : "", 449 unset_flags&BUF_PINNED ? "PINNED " : "", 450 unset_flags&BUF_IO_ERROR ? "IO_ERROR " : "", 451 unset_flags&BUF_IO_IN_PROGRESS ? "IO_IN_PROG " : "", 452 unset_flags&BUF_NEWPAGE ? "NEWPAGE " : "" ); 453#endif 454 if (!ADDR_OK(addr)) { 455 error_log1 ( "buf_pin: Invalid Buffer Address %x\n", addr ); 456 return(1); 457 } 458 bufid = ((BUF_T *)addr) - buf_table; 459 assert ( bufid < NUM_BUFS); 460 bhp = &bufhdr_table[bufid]; 461 if (GET_MASTER) { 462 return(1); 463 } 464 bhp->flags |= set_flags; 465 if ( set_flags & BUF_PINNED ) { 466 bhp->refcount++; 467 } 468 if ( set_flags & BUF_DIRTY ) { 469 unset_flags |= BUF_NEWPAGE; 470 } 471 472 if ( unset_flags & BUF_PINNED ) { 473 bhp->refcount--; 474 if ( bhp->refcount ) { 475 /* Turn off pin bit so it doesn't get unset */ 476 unset_flags &= ~BUF_PINNED; 477 } 478 } 479 bhp->flags &= ~unset_flags; 480 MAKE_MRU(bhp); 481 if (RELEASE_MASTER) { 482 return(1); 483 } 484 return(0); 485} 486 487/* 488 Take a string name and produce an fid. 489 490 returns -1 on error 491 492 MIS -- this is a potential problem -- you keep actual names 493 here -- what if people run from different directories? 494*/ 495extern int 496buf_name_lookup ( fname ) 497char *fname; 498{ 499 int i; 500 int fid; 501 int ndx; 502 503 fid = -1; 504 if (GET_MASTER) { 505 return(-1); 506 } 507 for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) { 508 if ( buf_fids[i].offset == -1 ) { 509 fid = i; 510 } else { 511 if (!strcmp (fname, buf_strings+buf_fids[i].offset)) { 512 if (RELEASE_MASTER) { 513 return(-1); 514 } 515 buf_fids[i].refcount++; 516 return(i); 517 } 518 } 519 } 520 if ( fid == -1 ) { 521 error_log0 ( "No more file ID's\n" ); 522 } else { 523 ndx = *buf_sp - strlen(fname) - 1; 524 if ( ndx < 0 ) { 525 error_log0 ( "Out of string space\n" ); 526 fid = -1; 527 } else { 528 *buf_sp = ndx; 529 strcpy ( buf_strings+ndx, fname ); 530 buf_fids[fid].offset = ndx; 531 } 532 buf_fids[fid].refcount = 1; 533 } 534 if (RELEASE_MASTER) { 535 return(-1); 536 } 537 return(fid); 538} 539 540static int 541bf_fid_to_fd ( fid ) 542int fid; 543{ 544 struct stat sbuf; 545 546 assert ( (fid < NUM_FILE_ENTRIES) && (buf_fids[fid].offset != -1) ); 547 if ( fds[fid] != -1 ) { 548 return(fds[fid]); 549 550 } 551 fds[fid] = open ( buf_strings+buf_fids[fid].offset, O_RDWR|O_CREAT, 552 0666 ); 553 if ( fds[fid] < 0 ) { 554 error_log3 ( "Error Opening File %s FID: %d FD: %d. Errno = %d\n", 555 buf_strings+buf_fids[fid].offset, fid, fds[fid], 556 errno ); 557 return(-1); 558 } 559 error_log3 ( "Opening File %s FID: %d FD: %d\n", 560 buf_strings+buf_fids[fid].offset, fid, fds[fid] ); 561 if ( buf_fids[fid].npages == -1 ) { 562 /* Initialize the npages field */ 563 if ( fstat ( fds[fid], &sbuf ) ) { 564 error_log3 ( "Error Fstating %s FID: %d. Errno = %d\n", 565 buf_strings+buf_fids[fid].offset, fid, errno ); 566 } else { 567 buf_fids[fid].npages = ( sbuf.st_size / BUFSIZE ); 568 } 569 } 570 571 return ( fds[fid] ); 572} 573 574static int 575bf_put_page ( fd, bhp ) 576int fd; 577BUFHDR_T *bhp; 578{ 579 int nbytes; 580 581 assert ( (bhp-bufhdr_table) < NUM_BUFS ); 582 if ( lseek ( fd, bhp->id.obj_id << BUFSHIFT, L_SET ) < 0 ) { 583 return(-1); 584 } 585 bhp->flags |= BUF_IO_IN_PROGRESS; 586 if (RELEASE_MASTER) { 587 return(-1); 588 } 589 nbytes = write(fd, buf_table[bhp-bufhdr_table], BUFSIZE); 590 if (GET_MASTER) { 591 return(-2); 592 } 593 if ( nbytes < 0 ) { 594 error_log1 ("Write failed with error code %d\n", errno); 595 return(-1); 596 } else if ( nbytes != BUFSIZE ) { 597 error_log1 ("Short write: %d bytes of %d\n", nbytes, BUFSIZE ); 598 } 599 bhp->flags &= ~(BUF_DIRTY|BUF_IO_IN_PROGRESS); 600 return (0); 601} 602 603static BUFHDR_T * 604bf_assign_buf ( ndx, obj, flags, len ) 605int ndx; 606OBJ_T *obj; 607u_long flags; 608int *len; /* Number of bytes read */ 609{ 610 BUFHDR_T *bhp; 611 int fd; 612 613 assert ( obj->file_id < NUM_FILE_ENTRIES ); 614 bhp = bf_newbuf(); 615 if ( !bhp ) { 616 return(NULL); 617 } 618 OBJ_ASSIGN ( (*obj), bhp->id ); 619 if ( buf_hash_table[ndx] >= NUM_BUFS ) { 620 buf_hash_table[ndx] = bhp-bufhdr_table; 621 } else { 622 LISTPE_INSERT ( bufhdr_table, hash, bhp, buf_hash_table[ndx] ); 623 } 624 625 bhp->flags |= BUF_VALID; 626 if ( flags & BF_PIN ) { 627 bhp->flags |= BUF_PINNED; 628 bhp->refcount++; 629#ifdef PIN_DEBUG 630 fprintf(stderr, "bf_assign_buf: %X PINNED (%d)\n", 631 buf_table + (bhp-bufhdr_table), bhp->refcount); 632#endif 633 } 634 fd = bf_fid_to_fd(obj->file_id); 635 if ( fd == -1 ) { 636 error_log1 ("Invalid fid %d\n", obj->file_id); 637 bhp->flags |= ~BUF_IO_ERROR; 638 return(NULL); 639 } 640 if ( obj->obj_id >= buf_fids[obj->file_id].npages) { 641 buf_fids[obj->file_id].npages = obj->obj_id+1; 642 *len = 0; 643 } else if ( flags & BF_EMPTY ) { 644 *len = 0; 645 } else { 646 bhp->flags |= BUF_IO_IN_PROGRESS; 647 if (RELEASE_MASTER) { 648 return(NULL); 649 } 650 if ( lseek ( fd, obj->obj_id << BUFSHIFT, L_SET ) < -1 ) { 651 error_log2 ("Unable to perform seek on file: %d to page %d", 652 obj->file_id, obj->obj_id ); 653 bhp->flags &= ~BUF_IO_IN_PROGRESS; 654 bhp->flags |= ~BUF_IO_ERROR; 655 return(NULL); 656 } 657 *len = read(fd, buf_table[bhp-bufhdr_table], BUFSIZE); 658 if ( *len < 0 ) { 659 error_log2 ("Unable to perform read on file: %d to page %d", 660 obj->file_id, obj->obj_id ); 661 bhp->flags &= ~BUF_IO_IN_PROGRESS; 662 bhp->flags |= ~BUF_IO_ERROR; 663 return(NULL); 664 } 665 if (GET_MASTER) { 666 return(NULL); 667 } 668 bhp->flags &= ~BUF_IO_IN_PROGRESS; 669 if ( bhp->wait_proc != -1 ) { 670 /* wake up waiter and anyone waiting on it */ 671#ifdef DEBUG 672 printf("Waking transaction %d due to completed I/O\n", 673 bhp->wait_proc); 674#endif 675 proc_wake_id ( bhp->wait_proc ); 676 bhp->wait_proc = -1; 677 } 678 MAKE_MRU(bhp); 679 } 680 681 if ( flags & BF_DIRTY ) { 682 bhp->flags |= BUF_DIRTY; 683 } else if ( *len < BUFSIZE ) { 684 bhp->flags |= BUF_NEWPAGE; 685 } 686 return ( bhp ); 687} 688 689int 690buf_last ( fid ) 691int fid; 692{ 693 int val; 694 695 if (GET_MASTER) { 696 return(-1); 697 } 698 assert ( fid < NUM_FILE_ENTRIES ); 699 if ( buf_fids[fid].npages == -1 ) { 700 /* initialize npages field */ 701 (void) bf_fid_to_fd ( fid ); 702 } 703 val = buf_fids[fid].npages; 704 if ( val ) { 705 val--; /* Convert to page number */ 706 } 707 if (RELEASE_MASTER) { 708 return(-1); 709 } 710 return(val); 711} 712 713#ifdef DEBUG 714extern void 715buf_dump ( id, all ) 716int id; 717int all; 718{ 719 int i; 720 BUFHDR_T *bhp; 721 722 printf ( "LRU + %d\n", *buf_lru ); 723 if ( all ) { 724 printf("ID\tFID\tPID\tLNEXT\tLPREV\tHNEXT\tHPREV\tSLEEP\tFLAG\tREFS\n"); 725 for ( bhp = bufhdr_table, i = 0; i < NUM_BUFS; bhp++, i++ ) { 726 printf ( "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%x\t%d\n", i, 727 bhp->id.file_id, bhp->id.obj_id, 728 bhp->lru.next, bhp->lru.prev, 729 bhp->hash.next, bhp->hash.prev, 730 bhp->wait_proc, bhp->flags, bhp->refcount ); 731 } 732 } else { 733 if ( id >= NUM_BUFS ) { 734 printf ( "Buffer ID (%d) too high\n", id ); 735 return; 736 } 737 bhp = bufhdr_table+id; 738 printf ( "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%x\t%d\n", i, 739 bhp->id.file_id, bhp->id.obj_id, 740 bhp->lru.next, bhp->lru.prev, 741 bhp->hash.next, bhp->hash.prev, 742 bhp->wait_proc, bhp->flags, bhp->refcount ); 743 } 744 return; 745} 746#endif 747 748