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. #define BUFPERCLUST 64 /* 64*Sectorsize = 128kb */
  25. #define NCLUST 16
  26. int nclust = NCLUST;
  27. static Ioclust* iohead;
  28. static Ioclust* iotail;
  29. static Ioclust* getclust(Xdata*, long);
  30. static void putclust(Ioclust*);
  31. static void xread(Ioclust*);
  32. void
  33. iobuf_init(void)
  34. {
  35. int i, j, n;
  36. Ioclust *c;
  37. Iobuf *b;
  38. uchar *mem;
  39. n = nclust*sizeof(Ioclust) +
  40. nclust*BUFPERCLUST*(sizeof(Iobuf)+Sectorsize);
  41. mem = sbrk(n);
  42. if(mem == (void*)-1)
  43. panic(0, "iobuf_init");
  44. memset(mem, 0, n);
  45. for(i=0; i<nclust; i++){
  46. c = (Ioclust*)mem;
  47. mem += sizeof(Ioclust);
  48. c->addr = -1;
  49. c->prev = iotail;
  50. if(iotail)
  51. iotail->next = c;
  52. iotail = c;
  53. if(iohead == nil)
  54. iohead = c;
  55. c->buf = (Iobuf*)mem;
  56. mem += BUFPERCLUST*sizeof(Iobuf);
  57. c->iobuf = mem;
  58. mem += BUFPERCLUST*Sectorsize;
  59. for(j=0; j<BUFPERCLUST; j++){
  60. b = &c->buf[j];
  61. b->clust = c;
  62. b->addr = -1;
  63. b->iobuf = c->iobuf+j*Sectorsize;
  64. }
  65. }
  66. }
  67. void
  68. purgebuf(Xdata *dev)
  69. {
  70. Ioclust *p;
  71. for(p=iohead; p!=nil; p=p->next)
  72. if(p->dev == dev){
  73. p->addr = -1;
  74. p->busy = 0;
  75. }
  76. }
  77. static Ioclust*
  78. getclust(Xdata *dev, long addr)
  79. {
  80. Ioclust *c, *f;
  81. f = nil;
  82. for(c=iohead; c; c=c->next){
  83. if(!c->busy)
  84. f = c;
  85. if(c->addr == addr && c->dev == dev){
  86. c->busy++;
  87. return c;
  88. }
  89. }
  90. if(f == nil)
  91. panic(0, "out of buffers");
  92. f->addr = addr;
  93. f->dev = dev;
  94. f->busy++;
  95. if(waserror()){
  96. f->addr = -1; /* stop caching */
  97. putclust(f);
  98. nexterror();
  99. }
  100. xread(f);
  101. poperror();
  102. return f;
  103. }
  104. static void
  105. putclust(Ioclust *c)
  106. {
  107. if(c->busy <= 0)
  108. panic(0, "putbuf");
  109. c->busy--;
  110. /* Link onto head for LRU */
  111. if(c == iohead)
  112. return;
  113. c->prev->next = c->next;
  114. if(c->next)
  115. c->next->prev = c->prev;
  116. else
  117. iotail = c->prev;
  118. c->prev = nil;
  119. c->next = iohead;
  120. iohead->prev = c;
  121. iohead = c;
  122. }
  123. Iobuf*
  124. getbuf(Xdata *dev, ulong addr)
  125. {
  126. int off;
  127. Ioclust *c;
  128. off = addr%BUFPERCLUST;
  129. c = getclust(dev, addr - off);
  130. if(c->nbuf < off){
  131. c->busy--;
  132. error("I/O read error");
  133. }
  134. return &c->buf[off];
  135. }
  136. void
  137. putbuf(Iobuf *b)
  138. {
  139. putclust(b->clust);
  140. }
  141. static void
  142. xread(Ioclust *c)
  143. {
  144. int n;
  145. vlong addr;
  146. Xdata *dev;
  147. dev = c->dev;
  148. addr = c->addr;
  149. seek(dev->dev, addr*Sectorsize, 0);
  150. n = readn(dev->dev, c->iobuf, BUFPERCLUST*Sectorsize);
  151. if(n < Sectorsize)
  152. error("I/O read error");
  153. c->nbuf = n/Sectorsize;
  154. }