bio.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. /* Buffered I/O functions. By cacheing the most recently used blocks,
  6. * we can cut WAAY down on disk traffic...
  7. */
  8. static int bio_fd = -1;
  9. static int bio_counter = 0;
  10. static int bio_blocksize = 0;
  11. struct bio_buf {
  12. int blkno;
  13. int last_access;
  14. int dirty;
  15. char * data;
  16. };
  17. #define NBUFS 32
  18. struct bio_buf buflist[NBUFS];
  19. /* initialize the buffer cache. Blow away anything that may
  20. * have been previously cached...
  21. */
  22. void
  23. binit(int fd, int blocksize)
  24. {
  25. int i;
  26. bio_fd = fd;
  27. bio_blocksize = blocksize;
  28. for(i = 0; i < NBUFS; i++) {
  29. buflist[i].blkno = 0;
  30. if(buflist[i].data) {
  31. free(buflist[i].data);
  32. }
  33. buflist[i].data = 0;
  34. buflist[i].last_access = 0;
  35. buflist[i].dirty = 0;
  36. }
  37. }
  38. /* Flush out any dirty blocks */
  39. void
  40. bflush(void)
  41. {
  42. int i;
  43. for(i = 0; i < NBUFS; i++) {
  44. if(buflist[i].dirty) {
  45. #ifdef BIO_DEBUG
  46. printf("bflush: writing block %d\n", buflist[i].blkno);
  47. #endif
  48. lseek(bio_fd, buflist[i].blkno * bio_blocksize, 0);
  49. write(bio_fd, buflist[i].data, bio_blocksize);
  50. buflist[i].dirty = 0;
  51. }
  52. }
  53. }
  54. /* Read a block. */
  55. void
  56. bread(int blkno, void * blkbuf)
  57. {
  58. int i;
  59. int lowcount;
  60. int lowcount_buf;
  61. /* First, see if the block is already in memory... */
  62. for(i = 0; i < NBUFS; i++) {
  63. if(buflist[i].blkno == blkno) {
  64. /* Got it! Bump the access count and return. */
  65. buflist[i].last_access = ++bio_counter;
  66. #ifdef BIO_DEBUG
  67. printf("bread: buffer hit on block %d\n", blkno);
  68. #endif
  69. memcpy(blkbuf, buflist[i].data, bio_blocksize);
  70. return;
  71. }
  72. }
  73. /* Not in memory; need to find a buffer and read it in. */
  74. lowcount = buflist[0].last_access;
  75. lowcount_buf = 0;
  76. for(i = 1; i < NBUFS; i++) {
  77. if(buflist[i].last_access < lowcount) {
  78. lowcount = buflist[i].last_access;
  79. lowcount_buf = i;
  80. }
  81. }
  82. /* If the buffer is dirty, we need to write it out... */
  83. if(buflist[lowcount_buf].dirty) {
  84. #ifdef BIO_DEBUG
  85. printf("bread: recycling dirty buffer %d for block %d\n",
  86. lowcount_buf, buflist[lowcount_buf].blkno);
  87. #endif
  88. lseek(bio_fd, buflist[lowcount_buf].blkno * bio_blocksize, 0);
  89. write(bio_fd, buflist[lowcount_buf].data, bio_blocksize);
  90. buflist[lowcount_buf].dirty = 0;
  91. }
  92. #ifdef BIO_DEBUG
  93. printf("bread: Using buffer %d for block %d\n", lowcount_buf, blkno);
  94. #endif
  95. buflist[lowcount_buf].blkno = blkno;
  96. if(!buflist[lowcount_buf].data) {
  97. buflist[lowcount_buf].data = (char *)malloc(bio_blocksize);
  98. }
  99. lseek(bio_fd, blkno * bio_blocksize, 0);
  100. if(read(bio_fd,buflist[lowcount_buf].data,bio_blocksize)!=bio_blocksize) {
  101. perror("bread: I/O error");
  102. }
  103. buflist[lowcount_buf].last_access = ++bio_counter;
  104. memcpy(blkbuf, buflist[lowcount_buf].data, bio_blocksize);
  105. }
  106. /* Write a block */
  107. void
  108. bwrite(int blkno, void * blkbuf)
  109. {
  110. int i;
  111. int lowcount;
  112. int lowcount_buf;
  113. /* First, see if the block is already in memory... */
  114. for(i = 0; i < NBUFS; i++) {
  115. if(buflist[i].blkno == blkno) {
  116. /* Got it! Bump the access count and return. */
  117. #ifdef BIO_DEBUG
  118. printf("bwrite: buffer hit on block %d\n", blkno);
  119. #endif
  120. buflist[i].last_access = ++bio_counter;
  121. memcpy(buflist[i].data, blkbuf, bio_blocksize);
  122. buflist[i].dirty = 1;
  123. return;
  124. }
  125. }
  126. /* Not in memory; need to find a buffer and stuff it. */
  127. lowcount = buflist[0].last_access;
  128. lowcount_buf = 0;
  129. for(i = 1; i < NBUFS; i++) {
  130. if(buflist[i].last_access < lowcount) {
  131. lowcount = buflist[i].last_access;
  132. lowcount_buf = i;
  133. }
  134. }
  135. /* If the buffer is dirty, we need to write it out... */
  136. if(buflist[lowcount_buf].dirty) {
  137. #ifdef BIO_DEBUG
  138. printf("bwrite: recycling dirty buffer %d for block %d\n",
  139. lowcount_buf, buflist[lowcount_buf].blkno);
  140. #endif
  141. lseek(bio_fd, buflist[lowcount_buf].blkno * bio_blocksize, 0);
  142. write(bio_fd, buflist[lowcount_buf].data, bio_blocksize);
  143. buflist[lowcount_buf].dirty = 0;
  144. }
  145. #ifdef BIO_DEBUG
  146. printf("bwrite: Using buffer %d for block %d\n", lowcount_buf, blkno);
  147. #endif
  148. buflist[lowcount_buf].blkno = blkno;
  149. if(!buflist[lowcount_buf].data) {
  150. buflist[lowcount_buf].data = (char *)malloc(bio_blocksize);
  151. }
  152. buflist[lowcount_buf].last_access = ++bio_counter;
  153. memcpy(buflist[lowcount_buf].data, blkbuf, bio_blocksize);
  154. buflist[lowcount_buf].dirty = 1;
  155. }