// print Image cache contents
IHASHSIZE = 64;
defn imagecacheline(h) {
+ local d, p, q;
+
while h != 0 do {
complex Image h;
- print (h\X, " ", qid(h.qid), " type ", h.type\D, " ref ", h.ref, " next ", h.next\X, " ", path(h.c.path), "\n");
+
+ d=(Dev)(*(devtab+4*h.type));
+ p = "*closed*";
+ if h.c != 0 then
+ p = path(h.c.path);
+ q = h.qid;
+ print (h\X, " ref=", h.ref, " pgref=", h.pgref, "\t#", d.dc\r, h.dev\D, " (",
+ q.path, " ", q.vers\D, " ", q.type\X, ") ", p, "\n");
h = h.hash;
}
}
return;
}
- if(p->image && p->image->nocache)
- uncachepage(p);
-
if(p->image && p->image != &swapimage)
pagechaintail(p);
else
return;
}
- /* No freelist cache with uncached image or when memory is very low */
- if(p->image->nocache || palloc.freecount < swapalloc.highwater) {
+ /* No freelist cache when memory is very low */
+ if(palloc.freecount < swapalloc.highwater) {
unlock(&palloc);
uncachepage(p);
return;
uncachepage(Page *p) /* Always called with a locked page */
{
Page **l, *f;
+ Image *i;
- if(p->image == 0)
+ i = p->image;
+ if(i == 0)
return;
lock(&palloc.hashlock);
l = &f->hash;
}
unlock(&palloc.hashlock);
- putimage(p->image);
p->image = 0;
p->daddr = 0;
+
+ lock(i);
+ i->pgref--;
+ unlock(i);
+ putimage(i);
}
void
if(p->image)
panic("cachepage");
- incref(i);
+ lock(i);
+ i->ref++;
+ i->pgref++;
+ unlock(i);
+
lock(&palloc.hashlock);
p->image = i;
l = &pghash(p->daddr);
struct Image
{
Ref;
- Chan *c; /* channel to text file */
+ long pgref; /* number of cached pages (pgref <= ref) */
+ Chan *c; /* channel to text file, nil when not used */
Qid qid; /* Qid for page cache coherence */
- Qid mqid;
- Chan *mchan;
+ ulong dev; /* Device id of owning channel */
ushort type; /* Device type of owning channel */
Segment *s; /* TEXT segment for image if running */
Image *hash; /* Qid hash chains */
Image *next; /* Free list */
char notext; /* no file associated */
- char nocache; /* no freelist page caching */
};
struct Pte
for(i = ihash(c->qid.path); i; i = i->hash) {
if(c->qid.path == i->qid.path) {
lock(i);
- if(eqqid(c->qid, i->qid) &&
- eqqid(c->mqid, i->mqid) &&
- c->mchan == i->mchan &&
- c->type == i->type) {
+ if(eqchantdqid(c, i->type, i->dev, i->qid, 0) && c->qid.type == i->qid.type)
goto found;
- }
unlock(i);
}
}
imagealloc.free = i->next;
lock(i);
- incref(c);
- i->nocache = (c->flag & CCACHE) == 0;
- c->flag &= ~CCACHE;
- i->c = c;
i->type = c->type;
+ i->dev = c->dev;
i->qid = c->qid;
- i->mqid = c->mqid;
- i->mchan = c->mchan;
+
l = &ihash(c->qid.path);
i->hash = *l;
*l = i;
+
found:
+ if(i->c == nil){
+ i->c = c;
+ c->flag &= ~CCACHE;
+ incref(c);
+ }
unlock(&imagealloc);
if(i->s == 0) {
if(i->notext)
return;
+ c = nil;
lock(i);
- if(--i->ref == 0) {
+ if(--i->ref == i->pgref){
+ /*
+ * all remaining references to this image are from the
+ * page cache now. close the channel as we can reattach
+ * the chan on attachimage()
+ */
+ c = i->c;
+ i->c = nil;
+ }
+ if(i->ref == 0){
l = &ihash(i->qid.path);
mkqid(&i->qid, ~0, ~0, QTFILE);
unlock(i);
- c = i->c;
lock(&imagealloc);
for(f = *l; f; f = f->hash) {
}
l = &f->hash;
}
-
i->next = imagealloc.free;
imagealloc.free = i;
unlock(&imagealloc);
-
+ } else
+ unlock(i);
+ if(c)
ccloseq(c); /* does not block */
- return;
- }
- unlock(i);
}
long