iobuf.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include "dat.h"
  6. #include "fns.h"
  7. /*
  8. * We used to use 100 i/o buffers of size 2kb (Sectorsize).
  9. * Unfortunately, reading 2kb at a time often hopping around
  10. * the disk doesn't let us get near the disk bandwidth.
  11. *
  12. * Based on a trace of iobuf address accesses taken while
  13. * tarring up a Plan 9 distribution CD, we now use 16 128kb
  14. * buffers. This works for ISO9660 because data is required
  15. * to be laid out contiguously; effectively we're doing agressive
  16. * readahead. Because the buffers are so big and the typical
  17. * disk accesses so concentrated, it's okay that we have so few
  18. * of them.
  19. *
  20. * If this is used to access multiple discs at once, it's not clear
  21. * how gracefully the scheme degrades, but I'm not convinced
  22. * it's worth worrying about. -rsc
  23. */
  24. /* trying a larger value to get greater throughput - geoff */
  25. #define BUFPERCLUST 256 /* sectors/cluster; was 64, 64*Sectorsize = 128kb */
  26. #define NCLUST 16
  27. int nclust = NCLUST;
  28. static Ioclust* iohead;
  29. static Ioclust* iotail;
  30. static Ioclust* getclust(Xdata*, long);
  31. static void putclust(Ioclust*);
  32. static void xread(Ioclust*);
  33. void
  34. iobuf_init(void)
  35. {
  36. int i, j, n;
  37. Ioclust *c;
  38. Iobuf *b;
  39. uchar *mem;
  40. n = nclust*sizeof(Ioclust) +
  41. nclust*BUFPERCLUST*(sizeof(Iobuf)+Sectorsize);
  42. mem = sbrk(n);
  43. if(mem == (void*)-1)
  44. panic(0, "iobuf_init");
  45. memset(mem, 0, n);
  46. for(i=0; i<nclust; i++){
  47. c = (Ioclust*)mem;
  48. mem += sizeof(Ioclust);
  49. c->addr = -1;
  50. c->prev = iotail;
  51. if(iotail)
  52. iotail->next = c;
  53. iotail = c;
  54. if(iohead == nil)
  55. iohead = c;
  56. c->buf = (Iobuf*)mem;
  57. mem += BUFPERCLUST*sizeof(Iobuf);
  58. c->iobuf = mem;
  59. mem += BUFPERCLUST*Sectorsize;
  60. for(j=0; j<BUFPERCLUST; j++){
  61. b = &c->buf[j];
  62. b->clust = c;
  63. b->addr = -1;
  64. b->iobuf = c->iobuf+j*Sectorsize;
  65. }
  66. }
  67. }
  68. void
  69. purgebuf(Xdata *dev)
  70. {
  71. Ioclust *p;
  72. for(p=iohead; p!=nil; p=p->next)
  73. if(p->dev == dev){
  74. p->addr = -1;
  75. p->busy = 0;
  76. }
  77. }
  78. static Ioclust*
  79. getclust(Xdata *dev, long addr)
  80. {
  81. Ioclust *c, *f;
  82. f = nil;
  83. for(c=iohead; c; c=c->next){
  84. if(!c->busy)
  85. f = c;
  86. if(c->addr == addr && c->dev == dev){
  87. c->busy++;
  88. return c;
  89. }
  90. }
  91. if(f == nil)
  92. panic(0, "out of buffers");
  93. f->addr = addr;
  94. f->dev = dev;
  95. f->busy++;
  96. if(waserror()){
  97. f->addr = -1; /* stop caching */
  98. putclust(f);
  99. nexterror();
  100. }
  101. xread(f);
  102. poperror();
  103. return f;
  104. }
  105. static void
  106. putclust(Ioclust *c)
  107. {
  108. if(c->busy <= 0)
  109. panic(0, "putbuf");
  110. c->busy--;
  111. /* Link onto head for LRU */
  112. if(c == iohead)
  113. return;
  114. c->prev->next = c->next;
  115. if(c->next)
  116. c->next->prev = c->prev;
  117. else
  118. iotail = c->prev;
  119. c->prev = nil;
  120. c->next = iohead;
  121. iohead->prev = c;
  122. iohead = c;
  123. }
  124. Iobuf*
  125. getbuf(Xdata *dev, ulong addr)
  126. {
  127. int off;
  128. Ioclust *c;
  129. off = addr%BUFPERCLUST;
  130. c = getclust(dev, addr - off);
  131. if(c->nbuf < off){
  132. c->busy--;
  133. error("I/O read error");
  134. }
  135. return &c->buf[off];
  136. }
  137. void
  138. putbuf(Iobuf *b)
  139. {
  140. putclust(b->clust);
  141. }
  142. static void
  143. xread(Ioclust *c)
  144. {
  145. int n;
  146. Xdata *dev;
  147. dev = c->dev;
  148. seek(dev->dev, (vlong)c->addr * Sectorsize, 0);
  149. n = readn(dev->dev, c->iobuf, BUFPERCLUST*Sectorsize);
  150. if(n < Sectorsize)
  151. error("I/O read error");
  152. c->nbuf = n/Sectorsize;
  153. }