summaryrefslogtreecommitdiff
path: root/sys/src/cmd/ext2srv/iobuf.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ext2srv/iobuf.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ext2srv/iobuf.c')
-rwxr-xr-xsys/src/cmd/ext2srv/iobuf.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/sys/src/cmd/ext2srv/iobuf.c b/sys/src/cmd/ext2srv/iobuf.c
new file mode 100755
index 000000000..07e834c3c
--- /dev/null
+++ b/sys/src/cmd/ext2srv/iobuf.c
@@ -0,0 +1,174 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "dat.h"
+#include "fns.h"
+
+#define NIOBUF 100
+#define HIOB (NIOBUF/3)
+
+static Iobuf* hiob[HIOB]; /* hash buckets */
+static Iobuf iobuf[NIOBUF]; /* buffer headers */
+static Iobuf* iohead;
+static Iobuf* iotail;
+
+Iobuf*
+getbuf(Xfs *dev, long addr)
+{
+ Iobuf *p, *h, **l, **f;
+
+ l = &hiob[addr%HIOB];
+ for(p = *l; p; p = p->hash) {
+ if(p->addr == addr && p->dev == dev) {
+ p->busy++;
+ return p;
+ }
+ }
+ /* Find a non-busy buffer from the tail */
+ for(p = iotail; p && (p->busy > 0); p = p->prev)
+ ;
+ if(!p)
+ panic("all buffers busy");
+ if(p->dirty){
+ xwrite(p);
+ p->dirty = 0;
+ }
+
+ if( xread(dev, p, addr) < 0)
+ return 0;
+ /* Delete from hash chain */
+ f = &hiob[p->addr%HIOB];
+ if( *f == p )
+ *f = p->hash;
+ else {
+ for(h = *f; h ; h = h->hash)
+ if( h->hash == p ){
+ h->hash = p->hash;
+ break;
+ }
+ }
+ /* Fill and hash */
+ p->hash = *l;
+ *l = p;
+ p->addr = addr;
+ p->dev = dev;
+ p->busy=1;
+
+ return p;
+}
+void
+putbuf(Iobuf *p)
+{
+ if(p->busy <= 0)
+ panic("putbuf");
+ p->busy--;
+
+ /* Link onto head for lru */
+ if(p == iohead)
+ return;
+ if( p == iotail ){
+ p->prev->next = 0;
+ iotail = p->prev;
+ }else{
+ p->prev->next = p->next;
+ p->next->prev = p->prev;
+ }
+
+ p->prev = 0;
+ p->next = iohead;
+ iohead->prev = p;
+ iohead = p;
+}
+void
+dirtybuf(Iobuf *p)
+{
+ if(p->busy <=0)
+ panic("dirtybuf");
+ p->dirty = 1;
+}
+void
+syncbuf(void)
+{
+ Iobuf *p;
+
+ for(p=&iobuf[0] ; p<&iobuf[NIOBUF]; p++)
+ if( p->dirty ){
+ xwrite(p);
+ p->dirty = 0;
+ }
+}
+void
+purgebuf(Xfs *dev)
+{
+ Iobuf *p;
+
+ for(p=&iobuf[0]; p<&iobuf[NIOBUF]; p++)
+ if(p->dev == dev)
+ p->busy = 0;
+
+ /* Blow hash chains */
+ memset(hiob, 0, sizeof(hiob));
+}
+void
+iobuf_init(void)
+{
+ Iobuf *p;
+
+ iohead = iobuf;
+ iotail = iobuf+NIOBUF-1;
+
+ for(p = iobuf; p <= iotail; p++) {
+ p->next = p+1;
+ p->prev = p-1;
+
+ p->iobuf = (char *)malloc(EXT2_MAX_BLOCK_SIZE);
+ if(p->iobuf == 0)
+ panic("iobuf_init");
+ }
+
+ iohead->prev = 0;
+ iotail->next = 0;
+}
+int
+xread(Xfs *dev, Iobuf *p, long addr)
+{
+ /*chat("xread %d,%d...", dev->dev, addr);*/
+
+ seek(dev->dev, (vlong)addr*dev->block_size, 0);
+ if(read(dev->dev, p->iobuf, dev->block_size) != dev->block_size){
+ chat("xread %d, block=%d failed ...", dev->dev, addr);
+ errno = Eio;
+ return -1;
+ }
+ /*chat("xread ok...");*/
+ return 0;
+}
+void
+xwrite(Iobuf *p)
+{
+ Xfs *dev;
+ long addr;
+
+ dev = p->dev;
+ addr = p->addr;
+ /*chat("xwrite %d,%d...", dev->dev, addr);*/
+
+ seek(dev->dev, (vlong)addr*dev->block_size, 0);
+ if(write(dev->dev, p->iobuf, dev->block_size) != dev->block_size){
+ chat("xwrite %d, block=%d failed ...", dev->dev, addr);
+ errno = Eio;
+ return;
+ }
+ /*chat("xwrite ok...");*/
+}
+void
+dumpbuf(void)
+{
+ Iobuf *p;
+
+ for(p = iotail; p ; p = p->prev)
+ if( p->busy )
+ mchat("\nHi ERROR buf(%x, %d, %d)\n", p, p->addr, p->busy);
+}