2011-03-30 12:46:40 +00:00
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "../port/error.h"
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
NHASH = 128,
|
2014-12-16 04:41:20 +00:00
|
|
|
NFILE = 4093, /* should be prime */
|
|
|
|
MAXCACHE = 8*1024*1024,
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-12-16 04:41:20 +00:00
|
|
|
MAPBITS = 8*sizeof(ulong),
|
|
|
|
NBITMAP = (PGROUND(MAXCACHE)/BY2PG + MAPBITS-1) / MAPBITS,
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
2015-07-26 03:43:26 +00:00
|
|
|
/* devmnt.c: parallel read ahread implementation */
|
|
|
|
extern void mntrahinit(Mntrah *rah);
|
|
|
|
extern long mntrahread(Mntrah *rah, Chan *c, uchar *buf, long len, vlong off);
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
typedef struct Mntcache Mntcache;
|
|
|
|
struct Mntcache
|
|
|
|
{
|
2015-07-26 03:43:26 +00:00
|
|
|
Qid qid;
|
|
|
|
int dev;
|
|
|
|
int type;
|
2014-12-16 04:41:20 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
QLock;
|
2015-07-26 03:43:26 +00:00
|
|
|
Proc *locked;
|
|
|
|
ulong nlocked;
|
|
|
|
|
2014-12-16 04:41:20 +00:00
|
|
|
Mntcache *hash;
|
|
|
|
Mntcache *prev;
|
|
|
|
Mntcache *next;
|
|
|
|
|
|
|
|
/* page bitmap of valid pages */
|
|
|
|
ulong bitmap[NBITMAP];
|
2015-07-26 03:43:26 +00:00
|
|
|
|
|
|
|
/* read ahead state */
|
|
|
|
Mntrah rah;
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct Cache Cache;
|
|
|
|
struct Cache
|
|
|
|
{
|
|
|
|
Lock;
|
2014-12-16 04:41:20 +00:00
|
|
|
Mntcache *alloc;
|
2011-03-30 12:46:40 +00:00
|
|
|
Mntcache *head;
|
|
|
|
Mntcache *tail;
|
|
|
|
Mntcache *hash[NHASH];
|
|
|
|
};
|
|
|
|
|
2014-06-22 13:12:45 +00:00
|
|
|
Image fscache;
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
static Cache cache;
|
|
|
|
|
|
|
|
void
|
|
|
|
cinit(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Mntcache *m;
|
|
|
|
|
2014-12-16 07:11:21 +00:00
|
|
|
m = xalloc(sizeof(Mntcache)*NFILE);
|
2011-03-30 12:46:40 +00:00
|
|
|
if (m == nil)
|
|
|
|
panic("cinit: no memory");
|
|
|
|
|
2014-12-16 07:11:21 +00:00
|
|
|
cache.alloc = m;
|
2014-12-16 04:41:20 +00:00
|
|
|
cache.head = m;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
for(i = 0; i < NFILE-1; i++) {
|
|
|
|
m->next = m+1;
|
|
|
|
m->prev = m-1;
|
|
|
|
m++;
|
|
|
|
}
|
|
|
|
|
|
|
|
cache.tail = m;
|
2014-12-15 05:28:27 +00:00
|
|
|
cache.tail->next = nil;
|
|
|
|
cache.head->prev = nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
fscache.notext = 1;
|
|
|
|
}
|
|
|
|
|
2014-12-16 04:41:20 +00:00
|
|
|
static uintptr
|
|
|
|
cacheaddr(Mntcache *m, ulong pn)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2014-12-16 04:41:20 +00:00
|
|
|
uintptr da = pn * NFILE + (m - cache.alloc);
|
|
|
|
return (da << PGSHIFT) | (da >> (sizeof(da)*8 - PGSHIFT));
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-12-15 05:28:27 +00:00
|
|
|
static void
|
2011-03-30 12:46:40 +00:00
|
|
|
cnodata(Mntcache *m)
|
|
|
|
{
|
2014-12-16 04:41:20 +00:00
|
|
|
memset(m->bitmap, 0, sizeof(m->bitmap));
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-12-15 05:28:27 +00:00
|
|
|
static void
|
2011-03-30 12:46:40 +00:00
|
|
|
ctail(Mntcache *m)
|
|
|
|
{
|
|
|
|
/* Unlink and send to the tail */
|
2014-12-15 05:28:27 +00:00
|
|
|
if(m->prev != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
m->prev->next = m->next;
|
|
|
|
else
|
|
|
|
cache.head = m->next;
|
2014-12-15 05:28:27 +00:00
|
|
|
if(m->next != nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
m->next->prev = m->prev;
|
|
|
|
else
|
|
|
|
cache.tail = m->prev;
|
|
|
|
|
2014-12-15 05:28:27 +00:00
|
|
|
if(cache.tail != nil) {
|
2011-03-30 12:46:40 +00:00
|
|
|
m->prev = cache.tail;
|
|
|
|
cache.tail->next = m;
|
2014-12-15 05:28:27 +00:00
|
|
|
m->next = nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
cache.tail = m;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cache.head = m;
|
|
|
|
cache.tail = m;
|
2014-12-15 05:28:27 +00:00
|
|
|
m->prev = nil;
|
|
|
|
m->next = nil;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-17 13:48:30 +00:00
|
|
|
/* called with cache locked */
|
|
|
|
static Mntcache*
|
|
|
|
clookup(Chan *c, int skipvers)
|
|
|
|
{
|
|
|
|
Mntcache *m;
|
|
|
|
|
2014-12-15 05:28:27 +00:00
|
|
|
for(m = cache.hash[c->qid.path%NHASH]; m != nil; m = m->hash)
|
2012-10-17 13:48:30 +00:00
|
|
|
if(eqchantdqid(c, m->type, m->dev, m->qid, skipvers) && c->qid.type == m->qid.type)
|
|
|
|
return m;
|
|
|
|
|
2014-12-15 05:28:27 +00:00
|
|
|
return nil;
|
2012-10-17 13:48:30 +00:00
|
|
|
}
|
|
|
|
|
2015-07-26 03:43:26 +00:00
|
|
|
/*
|
|
|
|
* resursive Mntcache locking. Mntcache.rah is protected by the
|
|
|
|
* same lock and we want to call cupdate() from mntrahread()
|
|
|
|
* while holding the lock.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
cancachelock(Mntcache *m)
|
|
|
|
{
|
|
|
|
if(m->locked == up || canqlock(m)){
|
|
|
|
m->locked = up;
|
|
|
|
m->nlocked++;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static void
|
|
|
|
cachelock(Mntcache *m)
|
|
|
|
{
|
|
|
|
if(m->locked != up){
|
|
|
|
qlock(m);
|
|
|
|
assert(m->nlocked == 0);
|
|
|
|
m->locked = up;
|
|
|
|
}
|
|
|
|
m->nlocked++;
|
|
|
|
|
|
|
|
}
|
|
|
|
static void
|
|
|
|
cacheunlock(Mntcache *m)
|
|
|
|
{
|
|
|
|
assert(m->locked == up);
|
|
|
|
if(--m->nlocked == 0){
|
|
|
|
m->locked = nil;
|
|
|
|
qunlock(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return locked Mntcache if still valid else reset mcp */
|
|
|
|
static Mntcache*
|
|
|
|
ccache(Chan *c)
|
|
|
|
{
|
|
|
|
Mntcache *m;
|
|
|
|
|
|
|
|
m = c->mcp;
|
|
|
|
if(m != nil) {
|
|
|
|
cachelock(m);
|
|
|
|
if(eqchantdqid(c, m->type, m->dev, m->qid, 0) && c->qid.type == m->qid.type)
|
|
|
|
return m;
|
|
|
|
c->mcp = nil;
|
|
|
|
cacheunlock(m);
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
kernel: make the mntcache robust against fileserver like fossil that do not change the qid.vers on wstat
introducing new ctrunc() function that invalidates any caches
for the passed in chan, invoked when handling wstat with a
specified file length or on file creation/truncation.
test program to reproduce the problem:
#include <u.h>
#include <libc.h>
#include <libsec.h>
void
main(int argc, char *argv[])
{
int fd;
Dir *d, nd;
fd = create("xxx", ORDWR, 0666);
write(fd, "1234", 4);
d = dirstat("xxx");
assert(d->length == 4);
nulldir(&nd);
nd.length = 0;
dirwstat("xxx", &nd);
d = dirstat("xxx");
assert(d->length == 0);
fd = open("xxx", OREAD);
assert(read(fd, (void*)&d, 4) == 0);
}
2017-01-12 19:13:20 +00:00
|
|
|
int
|
2011-03-30 12:46:40 +00:00
|
|
|
copen(Chan *c)
|
|
|
|
{
|
|
|
|
Mntcache *m, *f, **l;
|
|
|
|
|
2015-07-26 03:43:26 +00:00
|
|
|
/* directories aren't cacheable */
|
|
|
|
if(c->qid.type&QTDIR){
|
2014-12-15 05:28:27 +00:00
|
|
|
c->mcp = nil;
|
kernel: make the mntcache robust against fileserver like fossil that do not change the qid.vers on wstat
introducing new ctrunc() function that invalidates any caches
for the passed in chan, invoked when handling wstat with a
specified file length or on file creation/truncation.
test program to reproduce the problem:
#include <u.h>
#include <libc.h>
#include <libsec.h>
void
main(int argc, char *argv[])
{
int fd;
Dir *d, nd;
fd = create("xxx", ORDWR, 0666);
write(fd, "1234", 4);
d = dirstat("xxx");
assert(d->length == 4);
nulldir(&nd);
nd.length = 0;
dirwstat("xxx", &nd);
d = dirstat("xxx");
assert(d->length == 0);
fd = open("xxx", OREAD);
assert(read(fd, (void*)&d, 4) == 0);
}
2017-01-12 19:13:20 +00:00
|
|
|
return 0;
|
2012-10-17 13:48:30 +00:00
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
lock(&cache);
|
kernel: make the mntcache robust against fileserver like fossil that do not change the qid.vers on wstat
introducing new ctrunc() function that invalidates any caches
for the passed in chan, invoked when handling wstat with a
specified file length or on file creation/truncation.
test program to reproduce the problem:
#include <u.h>
#include <libc.h>
#include <libsec.h>
void
main(int argc, char *argv[])
{
int fd;
Dir *d, nd;
fd = create("xxx", ORDWR, 0666);
write(fd, "1234", 4);
d = dirstat("xxx");
assert(d->length == 4);
nulldir(&nd);
nd.length = 0;
dirwstat("xxx", &nd);
d = dirstat("xxx");
assert(d->length == 0);
fd = open("xxx", OREAD);
assert(read(fd, (void*)&d, 4) == 0);
}
2017-01-12 19:13:20 +00:00
|
|
|
m = clookup(c, 0);
|
|
|
|
if(m != nil){
|
2012-10-17 13:48:30 +00:00
|
|
|
ctail(m);
|
|
|
|
unlock(&cache);
|
|
|
|
c->mcp = m;
|
kernel: make the mntcache robust against fileserver like fossil that do not change the qid.vers on wstat
introducing new ctrunc() function that invalidates any caches
for the passed in chan, invoked when handling wstat with a
specified file length or on file creation/truncation.
test program to reproduce the problem:
#include <u.h>
#include <libc.h>
#include <libsec.h>
void
main(int argc, char *argv[])
{
int fd;
Dir *d, nd;
fd = create("xxx", ORDWR, 0666);
write(fd, "1234", 4);
d = dirstat("xxx");
assert(d->length == 4);
nulldir(&nd);
nd.length = 0;
dirwstat("xxx", &nd);
d = dirstat("xxx");
assert(d->length == 0);
fd = open("xxx", OREAD);
assert(read(fd, (void*)&d, 4) == 0);
}
2017-01-12 19:13:20 +00:00
|
|
|
return 1;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
kernel: make the mntcache robust against fileserver like fossil that do not change the qid.vers on wstat
introducing new ctrunc() function that invalidates any caches
for the passed in chan, invoked when handling wstat with a
specified file length or on file creation/truncation.
test program to reproduce the problem:
#include <u.h>
#include <libc.h>
#include <libsec.h>
void
main(int argc, char *argv[])
{
int fd;
Dir *d, nd;
fd = create("xxx", ORDWR, 0666);
write(fd, "1234", 4);
d = dirstat("xxx");
assert(d->length == 4);
nulldir(&nd);
nd.length = 0;
dirwstat("xxx", &nd);
d = dirstat("xxx");
assert(d->length == 0);
fd = open("xxx", OREAD);
assert(read(fd, (void*)&d, 4) == 0);
}
2017-01-12 19:13:20 +00:00
|
|
|
m = clookup(c, 1);
|
|
|
|
if(m == nil)
|
|
|
|
m = cache.head;
|
2012-10-17 13:48:30 +00:00
|
|
|
ctail(m);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
l = &cache.hash[m->qid.path%NHASH];
|
2014-12-15 05:28:27 +00:00
|
|
|
for(f = *l; f != nil; f = f->hash) {
|
2011-03-30 12:46:40 +00:00
|
|
|
if(f == m) {
|
|
|
|
*l = m->hash;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
l = &f->hash;
|
|
|
|
}
|
|
|
|
|
2015-07-26 03:43:26 +00:00
|
|
|
if(!cancachelock(m)){
|
2012-10-17 13:48:30 +00:00
|
|
|
unlock(&cache);
|
2015-07-26 03:43:26 +00:00
|
|
|
cachelock(m);
|
2012-10-17 13:48:30 +00:00
|
|
|
lock(&cache);
|
|
|
|
f = clookup(c, 0);
|
2014-12-15 05:28:27 +00:00
|
|
|
if(f != nil) {
|
2012-10-17 13:48:30 +00:00
|
|
|
/*
|
|
|
|
* someone got there first while cache lock
|
|
|
|
* was released and added a updated Mntcache
|
|
|
|
* for us. update LRU and use it.
|
|
|
|
*/
|
|
|
|
ctail(f);
|
|
|
|
unlock(&cache);
|
2015-07-26 03:43:26 +00:00
|
|
|
cacheunlock(m);
|
2012-10-17 13:48:30 +00:00
|
|
|
c->mcp = f;
|
kernel: make the mntcache robust against fileserver like fossil that do not change the qid.vers on wstat
introducing new ctrunc() function that invalidates any caches
for the passed in chan, invoked when handling wstat with a
specified file length or on file creation/truncation.
test program to reproduce the problem:
#include <u.h>
#include <libc.h>
#include <libsec.h>
void
main(int argc, char *argv[])
{
int fd;
Dir *d, nd;
fd = create("xxx", ORDWR, 0666);
write(fd, "1234", 4);
d = dirstat("xxx");
assert(d->length == 4);
nulldir(&nd);
nd.length = 0;
dirwstat("xxx", &nd);
d = dirstat("xxx");
assert(d->length == 0);
fd = open("xxx", OREAD);
assert(read(fd, (void*)&d, 4) == 0);
}
2017-01-12 19:13:20 +00:00
|
|
|
return 1;
|
2012-10-17 13:48:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
m->qid = c->qid;
|
|
|
|
m->dev = c->dev;
|
|
|
|
m->type = c->type;
|
|
|
|
|
2012-10-17 13:48:30 +00:00
|
|
|
l = &cache.hash[c->qid.path%NHASH];
|
2011-03-30 12:46:40 +00:00
|
|
|
m->hash = *l;
|
|
|
|
*l = m;
|
2015-07-26 03:43:26 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
unlock(&cache);
|
2015-07-26 03:43:26 +00:00
|
|
|
|
|
|
|
m->rah.vers = m->qid.vers;
|
|
|
|
mntrahinit(&m->rah);
|
2011-12-22 01:17:29 +00:00
|
|
|
cnodata(m);
|
2015-07-26 03:43:26 +00:00
|
|
|
cacheunlock(m);
|
|
|
|
c->mcp = m;
|
kernel: make the mntcache robust against fileserver like fossil that do not change the qid.vers on wstat
introducing new ctrunc() function that invalidates any caches
for the passed in chan, invoked when handling wstat with a
specified file length or on file creation/truncation.
test program to reproduce the problem:
#include <u.h>
#include <libc.h>
#include <libsec.h>
void
main(int argc, char *argv[])
{
int fd;
Dir *d, nd;
fd = create("xxx", ORDWR, 0666);
write(fd, "1234", 4);
d = dirstat("xxx");
assert(d->length == 4);
nulldir(&nd);
nd.length = 0;
dirwstat("xxx", &nd);
d = dirstat("xxx");
assert(d->length == 0);
fd = open("xxx", OREAD);
assert(read(fd, (void*)&d, 4) == 0);
}
2017-01-12 19:13:20 +00:00
|
|
|
return 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2015-03-16 04:46:08 +00:00
|
|
|
enum {
|
|
|
|
VABITS = 8*sizeof(uintptr) - 2*PGSHIFT,
|
|
|
|
VAMASK = (((uintptr)1 << VABITS)-1) << PGSHIFT,
|
|
|
|
};
|
|
|
|
|
2014-12-16 04:41:20 +00:00
|
|
|
static Page*
|
|
|
|
cpage(Mntcache *m, ulong pn, ulong *po, ulong *pe)
|
|
|
|
{
|
|
|
|
ulong b;
|
|
|
|
Page *p;
|
|
|
|
|
|
|
|
b = 1 << (pn%MAPBITS);
|
|
|
|
if((m->bitmap[pn/MAPBITS] & b) == 0)
|
|
|
|
return nil;
|
|
|
|
p = lookpage(&fscache, cacheaddr(m, pn));
|
|
|
|
if(p == nil){
|
|
|
|
m->bitmap[pn/MAPBITS] &= ~b;
|
|
|
|
return nil;
|
|
|
|
}
|
2015-03-16 04:46:08 +00:00
|
|
|
*po = p->va & (BY2PG-1);
|
|
|
|
*pe = 1 + (p->va >> (PGSHIFT+VABITS));
|
|
|
|
assert(*po < *pe);
|
2014-12-16 04:41:20 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2015-03-16 04:46:08 +00:00
|
|
|
static void
|
|
|
|
cpageset(Page *p, ulong po, ulong pe)
|
|
|
|
{
|
|
|
|
assert(po < pe);
|
|
|
|
p->va = po | (p->va & VAMASK) | ((uintptr)pe - 1) << (PGSHIFT+VABITS);
|
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
int
|
|
|
|
cread(Chan *c, uchar *buf, int len, vlong off)
|
|
|
|
{
|
|
|
|
KMap *k;
|
|
|
|
Page *p;
|
|
|
|
Mntcache *m;
|
2015-07-26 03:43:26 +00:00
|
|
|
int l, tot;
|
2014-12-16 04:41:20 +00:00
|
|
|
ulong offset, pn, po, pe;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2015-07-26 03:43:26 +00:00
|
|
|
if(len <= 0)
|
2011-03-30 12:46:40 +00:00
|
|
|
return 0;
|
|
|
|
|
2012-10-17 13:48:30 +00:00
|
|
|
m = ccache(c);
|
2014-12-15 05:28:27 +00:00
|
|
|
if(m == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
return 0;
|
|
|
|
|
2015-07-26 03:43:26 +00:00
|
|
|
if(waserror()){
|
|
|
|
cacheunlock(m);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
|
|
|
|
tot = 0;
|
|
|
|
if(off >= MAXCACHE)
|
|
|
|
goto Prefetch;
|
2014-12-16 04:41:20 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
offset = off;
|
2014-12-16 04:41:20 +00:00
|
|
|
if(offset+len > MAXCACHE)
|
|
|
|
len = MAXCACHE - offset;
|
|
|
|
pn = offset / BY2PG;
|
|
|
|
offset &= (BY2PG-1);
|
|
|
|
|
|
|
|
while(len > 0){
|
|
|
|
p = cpage(m, pn, &po, &pe);
|
|
|
|
if(p == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
2015-03-16 04:46:08 +00:00
|
|
|
if(offset < po || offset >= pe){
|
2014-12-16 04:41:20 +00:00
|
|
|
putpage(p);
|
2014-12-15 05:28:27 +00:00
|
|
|
break;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2014-12-16 04:41:20 +00:00
|
|
|
l = pe - offset;
|
|
|
|
if(l > len)
|
|
|
|
l = len;
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
k = kmap(p);
|
|
|
|
if(waserror()) {
|
|
|
|
kunmap(k);
|
|
|
|
putpage(p);
|
|
|
|
nexterror();
|
|
|
|
}
|
2014-12-16 04:41:20 +00:00
|
|
|
memmove(buf, (uchar*)VA(k) + offset, l);
|
2011-03-30 12:46:40 +00:00
|
|
|
kunmap(k);
|
|
|
|
putpage(p);
|
2015-07-26 03:43:26 +00:00
|
|
|
poperror();
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2015-07-26 03:43:26 +00:00
|
|
|
tot += l;
|
|
|
|
buf += l;
|
|
|
|
len -= l;
|
2014-12-16 04:41:20 +00:00
|
|
|
|
|
|
|
offset += l;
|
|
|
|
offset &= (BY2PG-1);
|
|
|
|
if(offset != 0)
|
2011-03-30 12:46:40 +00:00
|
|
|
break;
|
|
|
|
|
2014-12-16 04:41:20 +00:00
|
|
|
pn++;
|
|
|
|
}
|
|
|
|
|
2015-07-26 03:43:26 +00:00
|
|
|
Prefetch:
|
|
|
|
if(len > 0){
|
|
|
|
if(m->rah.vers != m->qid.vers){
|
|
|
|
mntrahinit(&m->rah);
|
|
|
|
m->rah.vers = m->qid.vers;
|
|
|
|
}
|
|
|
|
off += tot;
|
|
|
|
tot += mntrahread(&m->rah, c, buf, len, off);
|
|
|
|
}
|
|
|
|
cacheunlock(m);
|
|
|
|
poperror();
|
|
|
|
|
|
|
|
return tot;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2014-12-16 04:41:20 +00:00
|
|
|
/* invalidate pages in page bitmap */
|
|
|
|
static void
|
|
|
|
invalidate(Mntcache *m, ulong offset, int len)
|
|
|
|
{
|
|
|
|
ulong pn;
|
|
|
|
|
|
|
|
for(pn = offset/BY2PG; len > 0; pn++, len -= BY2PG)
|
|
|
|
m->bitmap[pn/MAPBITS] &= ~(1 << (pn%MAPBITS));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* replace buf data from [off, off+len) in the cache or invalidate */
|
|
|
|
static void
|
|
|
|
cachedata(Mntcache *m, uchar *buf, int len, vlong off)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
int l;
|
|
|
|
Page *p;
|
|
|
|
KMap *k;
|
2014-12-16 04:41:20 +00:00
|
|
|
ulong offset, pn, po, pe;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-12-16 04:41:20 +00:00
|
|
|
if(off >= MAXCACHE || len <= 0){
|
2015-07-26 03:43:26 +00:00
|
|
|
cacheunlock(m);
|
2014-12-16 04:41:20 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2014-12-16 04:41:20 +00:00
|
|
|
offset = off;
|
|
|
|
if(offset+len > MAXCACHE)
|
|
|
|
len = MAXCACHE - offset;
|
|
|
|
pn = offset / BY2PG;
|
|
|
|
offset &= (BY2PG-1);
|
|
|
|
|
|
|
|
while(len > 0){
|
|
|
|
l = BY2PG - offset;
|
|
|
|
if(l > len)
|
|
|
|
l = len;
|
|
|
|
p = cpage(m, pn, &po, &pe);
|
|
|
|
if(p != nil){
|
2015-03-16 04:46:08 +00:00
|
|
|
if(offset > pe || (offset+l) < po){
|
|
|
|
/* cached range not extendable, set new cached range */
|
2014-12-16 04:41:20 +00:00
|
|
|
po = offset;
|
|
|
|
pe = offset+l;
|
|
|
|
} else {
|
|
|
|
/* extend cached range */
|
|
|
|
if(offset < po)
|
|
|
|
po = offset;
|
|
|
|
if((offset+l) > pe)
|
|
|
|
pe = offset+l;
|
|
|
|
}
|
|
|
|
} else {
|
2015-06-16 04:05:12 +00:00
|
|
|
if(needpages(nil)){
|
2014-12-16 04:41:20 +00:00
|
|
|
invalidate(m, offset + pn*BY2PG, len);
|
|
|
|
break;
|
|
|
|
}
|
2015-03-16 04:46:08 +00:00
|
|
|
p = newpage(0, nil, pn*BY2PG);
|
2014-12-16 04:41:20 +00:00
|
|
|
p->daddr = cacheaddr(m, pn);
|
|
|
|
cachedel(&fscache, p->daddr);
|
|
|
|
cachepage(p, &fscache);
|
|
|
|
m->bitmap[pn/MAPBITS] |= 1 << (pn%MAPBITS);
|
|
|
|
|
|
|
|
po = offset;
|
|
|
|
pe = offset+l;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2015-03-16 04:46:08 +00:00
|
|
|
cpageset(p, po, pe);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
k = kmap(p);
|
2014-12-16 04:41:20 +00:00
|
|
|
if(waserror()) {
|
2011-03-30 12:46:40 +00:00
|
|
|
kunmap(k);
|
2014-12-16 04:41:20 +00:00
|
|
|
putpage(p);
|
|
|
|
invalidate(m, offset + pn*BY2PG, len);
|
2015-07-26 03:43:26 +00:00
|
|
|
cacheunlock(m);
|
2011-03-30 12:46:40 +00:00
|
|
|
nexterror();
|
|
|
|
}
|
2014-12-16 04:41:20 +00:00
|
|
|
memmove((uchar*)VA(k) + offset, buf, l);
|
2011-03-30 12:46:40 +00:00
|
|
|
poperror();
|
|
|
|
kunmap(k);
|
|
|
|
putpage(p);
|
|
|
|
|
2014-12-16 04:41:20 +00:00
|
|
|
offset = 0;
|
|
|
|
pn++;
|
2011-03-30 12:46:40 +00:00
|
|
|
buf += l;
|
|
|
|
len -= l;
|
|
|
|
}
|
2015-07-26 03:43:26 +00:00
|
|
|
cacheunlock(m);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cupdate(Chan *c, uchar *buf, int len, vlong off)
|
|
|
|
{
|
|
|
|
Mntcache *m;
|
|
|
|
|
2012-10-17 13:48:30 +00:00
|
|
|
m = ccache(c);
|
2014-12-15 05:28:27 +00:00
|
|
|
if(m == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
return;
|
2014-12-16 04:41:20 +00:00
|
|
|
cachedata(m, buf, len, off);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cwrite(Chan* c, uchar *buf, int len, vlong off)
|
|
|
|
{
|
|
|
|
Mntcache *m;
|
|
|
|
|
2012-10-17 13:48:30 +00:00
|
|
|
m = ccache(c);
|
2014-12-15 05:28:27 +00:00
|
|
|
if(m == nil)
|
2011-03-30 12:46:40 +00:00
|
|
|
return;
|
|
|
|
m->qid.vers++;
|
|
|
|
c->qid.vers++;
|
2015-07-26 03:43:26 +00:00
|
|
|
if(c->qid.type&QTAPPEND){
|
|
|
|
cacheunlock(m);
|
|
|
|
return;
|
|
|
|
}
|
2014-12-16 04:41:20 +00:00
|
|
|
cachedata(m, buf, len, off);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
2015-07-26 03:43:26 +00:00
|
|
|
|
kernel: make the mntcache robust against fileserver like fossil that do not change the qid.vers on wstat
introducing new ctrunc() function that invalidates any caches
for the passed in chan, invoked when handling wstat with a
specified file length or on file creation/truncation.
test program to reproduce the problem:
#include <u.h>
#include <libc.h>
#include <libsec.h>
void
main(int argc, char *argv[])
{
int fd;
Dir *d, nd;
fd = create("xxx", ORDWR, 0666);
write(fd, "1234", 4);
d = dirstat("xxx");
assert(d->length == 4);
nulldir(&nd);
nd.length = 0;
dirwstat("xxx", &nd);
d = dirstat("xxx");
assert(d->length == 0);
fd = open("xxx", OREAD);
assert(read(fd, (void*)&d, 4) == 0);
}
2017-01-12 19:13:20 +00:00
|
|
|
void
|
|
|
|
ctrunc(Chan *c)
|
|
|
|
{
|
|
|
|
Mntcache *m;
|
|
|
|
|
|
|
|
if(c->qid.type&QTDIR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if((c->flag&COPEN) == 0){
|
|
|
|
lock(&cache);
|
|
|
|
c->mcp = clookup(c, 0);
|
|
|
|
unlock(&cache);
|
|
|
|
}
|
|
|
|
|
|
|
|
m = ccache(c);
|
|
|
|
if(m == nil)
|
|
|
|
return;
|
|
|
|
mntrahinit(&m->rah);
|
|
|
|
cnodata(m);
|
|
|
|
cacheunlock(m);
|
|
|
|
|
|
|
|
if((c->flag&COPEN) == 0)
|
|
|
|
c->mcp = nil;
|
|
|
|
}
|
|
|
|
|
2015-07-26 03:43:26 +00:00
|
|
|
void
|
|
|
|
cclunk(Chan *c)
|
|
|
|
{
|
|
|
|
Mntcache *m;
|
|
|
|
|
|
|
|
m = ccache(c);
|
|
|
|
if(m == nil)
|
|
|
|
return;
|
|
|
|
mntrahinit(&m->rah);
|
|
|
|
cacheunlock(m);
|
|
|
|
c->mcp = nil;
|
|
|
|
}
|