iobuf.c 3.1 KB

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