static Packet * vtRPC(VtSession *z, int op, Packet *p) { uint8_t *hdr, buf[2]; char *err; if(z == nil){ vtSetError(ENotConnected); return nil; } /* * single threaded for the momment */ vtLock(z->lk); if(z->cstate != VtStateConnected){ vtSetError(ENotConnected); goto Err; } hdr = packetHeader(p, 2); hdr[0] = op; /* op */ hdr[1] = 0; /* tid */ vtDebug(z, "client send: "); vtDebugMesg(z, p, "\n"); if(!vtSendPacket(z, p)) { p = nil; goto Err; } p = vtRecvPacket(z); if(p == nil) goto Err; vtDebug(z, "client recv: "); vtDebugMesg(z, p, "\n"); if(!packetConsume(p, buf, 2)) goto Err; if(buf[0] == VtRError) { if(!vtGetString(p, &err)) { vtSetError(EProtocolBotch); goto Err; } vtSetError(err); vtMemFree(err); packetFree(p); vtUnlock(z->lk); return nil; } if(buf[0] != op+1 || buf[1] != 0) { vtSetError(EProtocolBotch); goto Err; } vtUnlock(z->lk); return p; Err: vtDebug(z, "vtRPC failed: %s\n", vtGetError()); if(p != nil) packetFree(p); vtUnlock(z->lk); vtDisconnect(z, 1); return nil; }
static void periodicThread(void *a) { Periodic *p = a; vlong t, ct, ts; /* times in ms. */ vtThreadSetName("periodic"); ct = nsec() / 1000000; t = ct + p->msec; /* call p->f at or after this time */ for(;;){ ts = t - ct; /* ms. to next cycle's start */ if(ts > 1000) ts = 1000; /* bound sleep duration */ if(ts > 0) sleep(ts); /* wait for cycle's start */ vtLock(p->lk); if(p->die){ vtUnlock(p->lk); break; } ct = nsec() / 1000000; if(t <= ct){ /* due to call p->f? */ p->f(p->a); ct = nsec() / 1000000; while(t <= ct) /* advance t to future cycle start */ t += p->msec; } vtUnlock(p->lk); } periodicFree(p); }
static void periodicThread(void *a) { Periodic *p = a; double t, ct, ts; vtThreadSetName("periodic"); ct = nsec()*1e-6; t = ct + p->msec; for(;;){ /* skip missed */ while(t <= ct) t += p->msec; ts = t - ct; if(ts > 1000) ts = 1000; sleep(ts); ct = nsec()*1e-6; vtLock(p->lk); if(p->die){ vtUnlock(p->lk); break; } if(t <= ct){ p->f(p->a); t += p->msec; } vtUnlock(p->lk); } periodicFree(p); }
int fsEpochLow(Fs *fs, uint32_t low) { Block *bs; Super super; vtLock(fs->elk); if(low > fs->ehi){ vtSetError("bad low epoch (must be <= %ud)", fs->ehi); vtUnlock(fs->elk); return 0; } if((bs = superGet(fs->cache, &super)) == nil){ vtUnlock(fs->elk); return 0; } super.epochLow = low; fs->elo = low; superWrite(bs, &super, 1); blockPut(bs); vtUnlock(fs->elk); return 1; }
int exclAlloc(Fid* fid) { ulong t; Excl *excl; assert(fid->excl == nil); t = time(0L); vtLock(ebox.lock); for(excl = ebox.head; excl != nil; excl = excl->next){ if(excl->fsys != fid->fsys || excl->path != fid->qid.path) continue; /* * Found it. * Now, check if it's timed out. * If not, return error, it's locked. * If it has timed out, zap the old * one and continue on to allocate a * a new one. */ if(excl->time >= t){ vtUnlock(ebox.lock); vtSetError("exclusive lock"); return 0; } excl->fsys = nil; } /* * Not found or timed-out. * Alloc a new one and initialise. */ excl = vtMemAllocZ(sizeof(Excl)); excl->fsys = fid->fsys; excl->path = fid->qid.path; excl->time = t+LifeTime; if(ebox.tail != nil){ excl->prev = ebox.tail; ebox.tail->next = excl; } else{ ebox.head = excl; excl->prev = nil; } ebox.tail = excl; excl->next = nil; vtUnlock(ebox.lock); fid->excl = excl; return 1; }
int vtSetCompression(VtSession *z, int fd) { vtLock(z->lk); if(z->cstate != VtStateAlloc) { vtSetError("bad state"); vtUnlock(z->lk); return 0; } z->fd = fd; vtUnlock(z->lk); return 1; }
static Srv* srvAlloc(char* service, int mode, int fd) { Dir *dir; Srv *srv; int srvfd; char *mntpnt; vtLock(sbox.lock); for(srv = sbox.head; srv != nil; srv = srv->next){ if(strcmp(srv->service, service) != 0) continue; /* * If the service exists, but is stale, * free it up and let the name be reused. */ if((dir = dirfstat(srv->srvfd)) != nil){ free(dir); vtSetError("srv: already serving '%s'", service); vtUnlock(sbox.lock); return nil; } srvFree(srv); break; } if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){ vtUnlock(sbox.lock); return nil; } close(fd); srv = vtMemAllocZ(sizeof(Srv)); srv->srvfd = srvfd; srv->service = vtStrDup(service); srv->mntpnt = mntpnt; if(sbox.tail != nil){ srv->prev = sbox.tail; sbox.tail->next = srv; } else{ sbox.head = srv; srv->prev = nil; } sbox.tail = srv; vtUnlock(sbox.lock); return srv; }
int vtSetFd(VtSession *z, int fd) { vtLock(z->lk); if(z->cstate != VtStateAlloc) { vtSetError("bad state"); vtUnlock(z->lk); return 0; } if(z->fd >= 0) vtFdClose(z->fd); z->fd = fd; vtUnlock(z->lk); return 1; }
Packet* vtRecvPacket(VtSession *z) { uint8_t buf[10], *b; int n; Packet *p; int size, len; if(z->cstate != VtStateConnected) { vtSetError("session not connected"); return 0; } vtLock(z->inLock); p = z->part; /* get enough for head size */ size = packetSize(p); while(size < 2) { b = packetTrailer(p, MaxFragSize); assert(b != nil); n = vtFdRead(z->fd, b, MaxFragSize); if(n <= 0) goto Err; size += n; packetTrim(p, 0, size); } if(!packetConsume(p, buf, 2)) goto Err; len = (buf[0] << 8) | buf[1]; size -= 2; while(size < len) { n = len - size; if(n > MaxFragSize) n = MaxFragSize; b = packetTrailer(p, n); if(!vtFdReadFully(z->fd, b, n)) goto Err; size += n; } p = packetSplit(p, len); vtUnlock(z->inLock); return p; Err: vtUnlock(z->inLock); return nil; }
static int cmdLstn(int argc, char* argv[]) { int dflag, flags; Lstn *lstn; char *usage = "usage: listen [-dIN] [address]"; dflag = 0; flags = 0; ARGBEGIN{ default: return cliError(usage); case 'd': dflag = 1; break; case 'I': flags |= ConIPCheck; break; case 'N': flags |= ConNoneAllow; break; }ARGEND switch(argc){ default: return cliError(usage); case 0: vtRLock(lbox.lock); for(lstn = lbox.head; lstn != nil; lstn = lstn->next) consPrint("\t%s\t%s\n", lstn->address, lstn->dir); vtRUnlock(lbox.lock); break; case 1: if(!dflag){ if(lstnAlloc(argv[0], flags) == nil) return 0; break; } vtLock(lbox.lock); for(lstn = lbox.head; lstn != nil; lstn = lstn->next){ if(strcmp(lstn->address, argv[0]) != 0) continue; if(lstn->afd != -1){ close(lstn->afd); lstn->afd = -1; } break; } vtUnlock(lbox.lock); if(lstn == nil){ vtSetError("listen: '%s' not found", argv[0]); return 0; } break; } return 1; }
void fidClunkAll(Con* con) { Fid *fid; u32int fidno; vtLock(con->fidlock); while(con->fhead != nil){ fidno = con->fhead->fidno; vtUnlock(con->fidlock); if((fid = fidGet(con, fidno, FidFWlock)) != nil) fidClunk(fid); vtLock(con->fidlock); } vtUnlock(con->fidlock); }
/* * Check whether the calling thread can validly lock b. * That is, check that the calling thread doesn't hold * locks for any of b's children. */ void bwatchLock(Block *b) { int i; WThread *w; if(bwatchDisabled) return; if(b->part != PartData) return; vtLock(map.lk); w = getWThread(); for(i=0; i<w->nb; i++){ if(lockConflicts(w->b[i]->score, b->score)){ fprint(2, "%d: have block %V; shouldn't lock %V\n", w->pid, w->b[i]->score, b->score); stop(); } } vtUnlock(map.lk); if(w->nb >= MaxLock){ fprint(2, "%d: too many blocks held\n", w->pid); stop(); }else w->b[w->nb++] = b; }
/* * Derive dependencies from the contents of b. */ void bwatchDependency(Block *b) { int i, epb, ppb; Entry e; if(bwatchDisabled) return; vtLock(map.lk); _bwatchResetParent(b->score); switch(b->l.type){ case BtData: break; case BtDir: epb = blockSize / VtEntrySize; for(i=0; i<epb; i++){ entryUnpack(&e, b->data, i); if(!(e.flags & VtEntryActive)) continue; addChild(b->score, e.score, i); } break; default: ppb = blockSize / VtScoreSize; for(i=0; i<ppb; i++) addChild(b->score, b->data+i*VtScoreSize, i); break; } vtUnlock(map.lk); }
static void snapEvent(void *v) { Snap *s; uint32_t now, min; Tm tm; int need; uint32_t snaplife; s = v; now = time(0)/60; vtLock(s->lk); /* * Snapshots happen every snapMinutes minutes. * If we miss a snapshot (for example, because we * were down), we wait for the next one. */ if(s->snapMinutes != ~0 && s->snapMinutes != 0 && now%s->snapMinutes==0 && now != s->lastSnap){ if(!fsSnapshot(s->fs, nil, nil, 0)) fprint(2, "%s: fsSnapshot snap: %R\n", argv0); s->lastSnap = now; } /* * Archival snapshots happen at archMinute. * If we miss an archive (for example, because we * were down), we do it as soon as possible. */ tm = *localtime(now*60); min = tm.hour*60+tm.min; if(s->archMinute != ~0){ need = 0; if(min == s->archMinute && now != s->lastArch) need = 1; if(s->lastArch == 0){ s->lastArch = 1; if(fsNeedArch(s->fs, s->archMinute)) need = 1; } if(need){ fsSnapshot(s->fs, nil, nil, 1); s->lastArch = now; } } /* * Snapshot cleanup happens every snaplife or every day. */ snaplife = s->snapLife; if(snaplife == ~0) snaplife = 24*60; if(s->lastCleanup+snaplife < now){ fsSnapshotCleanup(s->fs, s->snapLife); s->lastCleanup = now; } vtUnlock(s->lk); }
static Lstn* lstnAlloc(char* address, int flags) { int afd; Lstn *lstn; char dir[NETPATHLEN]; vtLock(lbox.lock); for(lstn = lbox.head; lstn != nil; lstn = lstn->next){ if(strcmp(lstn->address, address) != 0) continue; vtSetError("listen: already serving '%s'", address); vtUnlock(lbox.lock); return nil; } if((afd = announce(address, dir)) < 0){ vtSetError("listen: announce '%s': %r", address); vtUnlock(lbox.lock); return nil; } lstn = vtMemAllocZ(sizeof(Lstn)); lstn->afd = afd; lstn->address = vtStrDup(address); lstn->flags = flags; memmove(lstn->dir, dir, NETPATHLEN); if(lbox.tail != nil){ lstn->prev = lbox.tail; lbox.tail->next = lstn; } else{ lbox.head = lstn; lstn->prev = nil; } lbox.tail = lstn; vtUnlock(lbox.lock); if(vtThread(lstnListen, lstn) < 0){ vtSetError("listen: thread '%s': %r", lstn->address); lstnFree(lstn); return nil; } return lstn; }
void bwatchReset(uchar score[VtScoreSize]) { vtLock(map.lk); _bwatchResetParent(score); _bwatchResetChild(score); vtUnlock(map.lk); }
void periodicKill(Periodic *p) { if(p == nil) return; vtLock(p->lk); p->die = 1; vtUnlock(p->lk); }
int fsUnhalt(Fs *fs) { if(!fs->halted) return 0; fs->halted = 0; vtUnlock(fs->elk); return 1; }
int fsSync(Fs *fs) { vtLock(fs->elk); fileMetaFlush(fs->file, 1); cacheFlush(fs->cache, 1); vtUnlock(fs->elk); return 1; }
int vtSetDebug(VtSession *z, int debug) { int old; vtLock(z->lk); old = z->debug; z->debug = debug; vtUnlock(z->lk); return old; }
void sourceClose(Source *r) { if(r == nil) return; vtLock(r->lk); r->ref--; if(r->ref) { vtUnlock(r->lk); return; } assert(r->ref == 0); vtUnlock(r->lk); if(r->parent) sourceClose(r->parent); vtLockFree(r->lk); memset(r, ~0, sizeof(*r)); vtMemFree(r); }
int exclUpdate(Fid* fid) { ulong t; Excl *excl; excl = fid->excl; t = time(0L); vtLock(ebox.lock); if(excl->time < t || excl->fsys != fid->fsys){ vtUnlock(ebox.lock); vtSetError("exclusive lock broken"); return 0; } excl->time = t+LifeTime; vtUnlock(ebox.lock); return 1; }
void archKick(Arch *a) { if(a == nil){ fprint(2, "warning: archKick nil\n"); return; } vtLock(a->lk); vtWakeup(a->starve); vtUnlock(a->lk); }
void vtReset(VtSession *z) { vtLock(z->lk); z->cstate = VtStateAlloc; if(z->fd >= 0){ vtFdClose(z->fd); z->fd = -1; } vtUnlock(z->lk); }
void snapSetTimes(Snap *s, uint32_t arch, uint32_t snap, uint32_t snaplen) { if(s == nil) return; vtLock(s->lk); s->snapMinutes = snap; s->archMinute = arch; s->snapLife = snaplen; vtUnlock(s->lk); }
static void fidUnlock(Fid* fid) { if(!(fid->flags & FidFCreate)) fsysFsRUnlock(fid->fsys); if(fid->flags & FidFWlock){ fid->flags = 0; vtUnlock(fid->lock); return; } vtRUnlock(fid->lock); }
int vtHello(VtSession *z) { Packet *p; uint8_t buf[10]; char *sid; int crypto, codec; sid = nil; p = packetAlloc(); if(!vtAddString(p, vtGetVersion(z))) goto Err; if(!vtAddString(p, vtGetUid(z))) goto Err; buf[0] = vtGetCryptoStrength(z); buf[1] = 0; buf[2] = 0; packetAppend(p, buf, 3); p = vtRPC(z, VtQHello, p); if(p == nil) return 0; if(!vtGetString(p, &sid)) goto Err; if(!packetConsume(p, buf, 2)) goto Err; if(packetSize(p) != 0) { vtSetError(EProtocolBotch); goto Err; } crypto = buf[0]; codec = buf[1]; USED(crypto); USED(codec); packetFree(p); vtLock(z->lk); z->sid = sid; z->auth.state = VtAuthOK; vtSha1Free(z->inHash); z->inHash = nil; vtSha1Free(z->outHash); z->outHash = nil; vtUnlock(z->lk); return 1; Err: packetFree(p); vtMemFree(sid); return 0; }
static void fidFree(Fid* fid) { if(fid->file != nil){ fileDecRef(fid->file); fid->file = nil; } if(fid->db != nil){ dirBufFree(fid->db); fid->db = nil; } fidUnlock(fid); if(fid->uid != nil){ vtMemFree(fid->uid); fid->uid = nil; } if(fid->uname != nil){ vtMemFree(fid->uname); fid->uname = nil; } if(fid->excl != nil) exclFree(fid); if(fid->rpc != nil){ close(fid->rpc->afd); auth_freerpc(fid->rpc); fid->rpc = nil; } if(fid->fsys != nil){ fsysPut(fid->fsys); fid->fsys = nil; } if(fid->cuname != nil){ vtMemFree(fid->cuname); fid->cuname = nil; } vtLock(fbox.lock); fbox.inuse--; if(fbox.nfree < 10){ fid->hash = fbox.free; fbox.free = fid; fbox.nfree++; } else{ vtLockFree(fid->alock); vtLockFree(fid->lock); vtMemFree(fid); } vtUnlock(fbox.lock); }
void fidPut(Fid* fid) { vtLock(fid->con->fidlock); assert(fid->ref > 0); fid->ref--; vtUnlock(fid->con->fidlock); if(fid->ref == 0 && fid->fidno == NOFID){ fidFree(fid); return; } fidUnlock(fid); }
void archFree(Arch *a) { /* kill slave */ vtLock(a->lk); a->die = vtRendezAlloc(a->lk); vtWakeup(a->starve); while(a->ref > 1) vtSleep(a->die); vtUnlock(a->lk); vtRendezFree(a->starve); vtRendezFree(a->die); vtLockFree(a->lk); vtMemFree(a); }