Exemple #1
0
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);
}
Exemple #2
0
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);
}
Exemple #3
0
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;
}
Exemple #4
0
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;	
}
Exemple #5
0
void
snapGetTimes(Snap *s, uint32_t *arch, uint32_t *snap, uint32_t *snaplen)
{
	if(s == nil){
		*snap = -1;
		*arch = -1;
		*snaplen = -1;
		return;
	}

	vtLock(s->lk);
	*snap = s->snapMinutes;
	*arch = s->archMinute;
	*snaplen = s->snapLife;
	vtUnlock(s->lk);
}
Exemple #6
0
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;
}
Exemple #7
0
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);
}
Exemple #8
0
static void
lstnFree(Lstn* lstn)
{
	vtLock(lbox.lock);
	if(lstn->prev != nil)
		lstn->prev->next = lstn->next;
	else
		lbox.head = lstn->next;
	if(lstn->next != nil)
		lstn->next->prev = lstn->prev;
	else
		lbox.tail = lstn->prev;
	vtUnlock(lbox.lock);

	if(lstn->afd != -1)
		close(lstn->afd);
	vtMemFree(lstn->address);
	vtMemFree(lstn);
}
Exemple #9
0
void
fidClunk(Fid* fid)
{
	assert(fid->flags & FidFWlock);

	vtLock(fid->con->fidlock);
	assert(fid->ref > 0);
	fid->ref--;
	fidUnHash(fid);
	fid->fidno = NOFID;
	vtUnlock(fid->con->fidlock);

	if(fid->ref > 0){
		/* not reached - fidUnHash requires ref == 0 */
		fidUnlock(fid);
		return;
	}
	fidFree(fid);
}
Exemple #10
0
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;
}
Exemple #11
0
void
exclFree(Fid* fid)
{
	Excl *excl;

	if((excl = fid->excl) == nil)
		return;
	fid->excl = nil;

	vtLock(ebox.lock);
	if(excl->prev != nil)
		excl->prev->next = excl->next;
	else
		ebox.head = excl->next;
	if(excl->next != nil)
		excl->next->prev = excl->prev;
	else
		ebox.tail = excl->prev;
	vtUnlock(ebox.lock);

	vtMemFree(excl);
}
Exemple #12
0
void
vtDisconnect(VtSession *z, int error)
{
	Packet *p;
	uint8_t *b;

vtDebug(z, "vtDisconnect\n");
	vtLock(z->lk);
	if(z->cstate == VtStateConnected && !error && z->vtbl == nil) {
		/* clean shutdown */
		p = packetAlloc();
		b = packetHeader(p, 2);
		b[0] = VtQGoodbye;
		b[1] = 0;
		vtSendPacket(z, p);
	}
	if(z->fd >= 0)
		vtFdClose(z->fd);
	z->fd = -1;
	z->cstate = VtStateClosed;
	vtUnlock(z->lk);
}
Exemple #13
0
static Fid*
fidAlloc(void)
{
	Fid *fid;

	vtLock(fbox.lock);
	if(fbox.nfree > 0){
		fid = fbox.free;
		fbox.free = fid->hash;
		fbox.nfree--;
	}
	else{
		fid = vtMemAllocZ(sizeof(Fid));
		fid->lock = vtLockAlloc();
		fid->alock = vtLockAlloc();
	}
	fbox.inuse++;
	vtUnlock(fbox.lock);

	fid->con = nil;
	fid->fidno = NOFID;
	fid->ref = 0;
	fid->flags = 0;
	fid->open = FidOCreate;
	assert(fid->fsys == nil);
	assert(fid->file == nil);
	fid->qid = (Qid){0, 0, 0};
	assert(fid->uid == nil);
	assert(fid->uname == nil);
	assert(fid->db == nil);
	assert(fid->excl == nil);
	assert(fid->rpc == nil);
	assert(fid->cuname == nil);
	fid->hash = fid->next = fid->prev = nil;

	return fid;
}
Exemple #14
0
static int
archWalk(Param *p, u32int addr, uchar type, u32int tag)
{
	int ret, i, x, psize, dsize;
	uchar *data, score[VtScoreSize];
	Block *b;
	Label l;
	Entry *e;
	WalkPtr w;

	p->nvisit++;

	b = cacheLocalData(p->c, addr, type, tag, OReadWrite,0);
	if(b == nil){
		fprint(2, "archive(%ud, %#ux): cannot find block: %R\n", p->snapEpoch, addr);
		if(strcmp(vtGetError(), ELabelMismatch) == 0){
			/* might as well plod on so we write _something_ to Venti */
			memmove(p->score, vtZeroScore, VtScoreSize);
			return ArchFaked;
		}
		return ArchFailure;
	}

	if(DEBUG) fprint(2, "%*sarchive(%ud, %#ux): block label %L\n",
		p->depth*2, "",  p->snapEpoch, b->addr, &b->l);
	p->depth++;
	if(p->depth > p->maxdepth)
		p->maxdepth = p->depth;

	data = b->data;
	if((b->l.state&BsVenti) == 0){
		initWalk(&w, b, b->l.type==BtDir ? p->dsize : p->psize);
		for(i=0; nextWalk(&w, score, &type, &tag, &e); i++){
			if(e){
				if(!(e->flags&VtEntryActive))
					continue;
				if((e->snap && !e->archive)
				|| (e->flags&VtEntryNoArchive)){
					if(0) fprint(2, "snap; faking %#ux\n", b->addr);
					if(data == b->data){
						data = copyBlock(b, p->blockSize);
						if(data == nil){
							ret = ArchFailure;
							goto Out;
						}
						w.data = data;
					}
					memmove(e->score, vtZeroScore, VtScoreSize);
					e->depth = 0;
					e->size = 0;
					e->tag = 0;
					e->flags &= ~VtEntryLocal;
					entryPack(e, data, w.n-1);
					continue;
				}
			}
			addr = globalToLocal(score);
			if(addr == NilBlock)
				continue;
			dsize = p->dsize;
			psize = p->psize;
			if(e){
				p->dsize= e->dsize;
				p->psize = e->psize;
			}
			vtUnlock(b->lk);
			x = archWalk(p, addr, type, tag);
			vtLock(b->lk);
			if(e){
				p->dsize = dsize;
				p->psize = psize;
			}
			while(b->iostate != BioClean && b->iostate != BioDirty)
				vtSleep(b->ioready);
			switch(x){
			case ArchFailure:
				fprint(2, "archWalk %#ux failed; ptr is in %#ux offset %d\n",
					addr, b->addr, i);
				ret = ArchFailure;
				goto Out;
			case ArchFaked:
				/*
				 * When we're writing the entry for an archive directory
				 * (like /archive/2003/1215) then even if we've faked
				 * any data, record the score unconditionally.
				 * This way, we will always record the Venti score here.
				 * Otherwise, temporary data or corrupted file system
				 * would cause us to keep holding onto the on-disk
				 * copy of the archive.
				 */
				if(e==nil || !e->archive)
				if(data == b->data){
if(0) fprint(2, "faked %#ux, faking %#ux (%V)\n", addr, b->addr, p->score);
					data = copyBlock(b, p->blockSize);
					if(data == nil){
						ret = ArchFailure;
						goto Out;
					}
					w.data = data;
				}
				/* fall through */
if(0) fprint(2, "falling\n");
			case ArchSuccess:
				if(e){
					memmove(e->score, p->score, VtScoreSize);
					e->flags &= ~VtEntryLocal;
					entryPack(e, data, w.n-1);
				}else
					memmove(data+(w.n-1)*VtScoreSize, p->score, VtScoreSize);
				if(data == b->data){
					blockDirty(b);
					/*
					 * If b is in the active tree, then we need to note that we've
					 * just removed addr from the active tree (replacing it with the 
					 * copy we just stored to Venti).  If addr is in other snapshots,
					 * this will close addr but not free it, since it has a non-empty
					 * epoch range.
					 *
					 * If b is in the active tree but has been copied (this can happen
					 * if we get killed at just the right moment), then we will
					 * mistakenly leak its kids.  
					 *
					 * The children of an archive directory (e.g., /archive/2004/0604)
					 * are not treated as in the active tree.
					 */
					if((b->l.state&BsCopied)==0 && (e==nil || e->snap==0))
						blockRemoveLink(b, addr, p->l.type, p->l.tag, 0);
				}
				break;
			}
		}

		if(!ventiSend(p->a, b, data)){
			p->nfailsend++;
			ret = ArchFailure;
			goto Out;
		}
		p->nsend++;
		if(data != b->data)
			p->nfake++;
		if(data == b->data){	/* not faking it, so update state */
			p->nreal++;
			l = b->l;
			l.state |= BsVenti;
			if(!blockSetLabel(b, &l, 0)){
				ret = ArchFailure;
				goto Out;
			}
		}
	}

	shaBlock(p->score, b, data, p->blockSize);
if(0) fprint(2, "ventisend %V %p %p %p\n", p->score, data, b->data, w.data);
	ret = data!=b->data ? ArchFaked : ArchSuccess;
	p->l = b->l;
Out:
	if(data != b->data)
		vtMemFree(data);
	p->depth--;
	blockPut(b);
	return ret;
}
Exemple #15
0
static int
cmdUname(int argc, char* argv[])
{
	User *u, *up;
	int d, dflag, i, r;
	char *p, *uid, *uname;
	char *createfmt = "fsys main create /active/usr/%s %s %s d775";
	char *usage = "usage: uname [-d] uname [uid|:uid|%%newname|=leader|+member|-member]";

	dflag = 0;

	ARGBEGIN{
	default:
		return cliError(usage);
	case 'd':
		dflag = 1;
		break;
	}ARGEND

	if(argc < 1){
		if(!dflag)
			return cliError(usage);
		vtRLock(ubox.lock);
		uboxDump(ubox.box);
		vtRUnlock(ubox.lock);
		return 1;
	}

	uname = argv[0];
	argc--; argv++;

	if(argc == 0){
		vtRLock(ubox.lock);
		if((u = _userByUname(ubox.box, uname)) == nil){
			vtRUnlock(ubox.lock);
			return 0;
		}
		consPrint("\t%U\n", u);
		vtRUnlock(ubox.lock);
		return 1;
	}

	vtLock(ubox.lock);
	u = _userByUname(ubox.box, uname);
	while(argc--){
		if(argv[0][0] == '%'){
			if(u == nil){
				vtUnlock(ubox.lock);
				return 0;
			}
			p = &argv[0][1];
			if((up = _userByUname(ubox.box, p)) != nil){
				vtSetError("uname: uname '%s' already exists",
					up->uname);
				vtUnlock(ubox.lock);
				return 0;
			}
			for(i = 0; usersMandatory[i] != nil; i++){
				if(strcmp(usersMandatory[i], uname) != 0)
					continue;
				vtSetError("uname: uname '%s' is mandatory",
					uname);
				vtUnlock(ubox.lock);
				return 0;
			}

			d = strlen(p) - strlen(u->uname);
			for(up = ubox.box->head; up != nil; up = up->next){
				if(up->leader != nil){
					if(strcmp(up->leader, u->uname) == 0){
						vtMemFree(up->leader);
						up->leader = vtStrDup(p);
						ubox.box->len += d;
					}
				}
				for(i = 0; i < up->ngroup; i++){
					if(strcmp(up->group[i], u->uname) != 0)
						continue;
					vtMemFree(up->group[i]);
					up->group[i] = vtStrDup(p);
					ubox.box->len += d;
					break;
				}
			}

			uboxRemUser(ubox.box, u);
			vtMemFree(u->uname);
			u->uname = vtStrDup(p);
			uboxAddUser(ubox.box, u);
		}
		else if(argv[0][0] == '='){
			if(u == nil){
				vtUnlock(ubox.lock);
				return 0;
			}
			if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
				if(argv[0][1] != '\0'){
					vtUnlock(ubox.lock);
					return 0;
				}
			}
			if(u->leader != nil){
				ubox.box->len -= strlen(u->leader);
				vtMemFree(u->leader);
				u->leader = nil;
			}
			if(up != nil){
				u->leader = vtStrDup(up->uname);
				ubox.box->len += strlen(u->leader);
			}
		}
		else if(argv[0][0] == '+'){
			if(u == nil){
				vtUnlock(ubox.lock);
				return 0;
			}
			if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
				vtUnlock(ubox.lock);
				return 0;
			}
			if(!_groupAddMember(ubox.box, u, up->uname)){
				vtUnlock(ubox.lock);
				return 0;
			}
		}
		else if(argv[0][0] == '-'){
			if(u == nil){
				vtUnlock(ubox.lock);
				return 0;
			}
			if((up = _userByUname(ubox.box, &argv[0][1])) == nil){
				vtUnlock(ubox.lock);
				return 0;
			}
			if(!_groupRemMember(ubox.box, u, up->uname)){
				vtUnlock(ubox.lock);
				return 0;
			}
		}
		else{
			if(u != nil){
				vtSetError("uname: uname '%s' already exists",
					u->uname);
				vtUnlock(ubox.lock);
				return 0;
			}

			uid = argv[0];
			if(*uid == ':')
				uid++;
			if((u = _userByUid(ubox.box, uid)) != nil){
				vtSetError("uname: uid '%s' already exists",
					u->uid);
				vtUnlock(ubox.lock);
				return 0;
			}

			u = userAlloc(uid, uname);
			uboxAddUser(ubox.box, u);
			if(argv[0][0] != ':'){
				// should have an option for the mode and gid
				p = smprint(createfmt, uname, uname, uname);
				r = cliExec(p);
				vtMemFree(p);
				if(r == 0){
					vtUnlock(ubox.lock);
					return 0;
				}
			}
		}
		argv++;
	}

	if(usersFileWrite(ubox.box) == 0){
		vtUnlock(ubox.lock);
		return 0;
	}
	if(dflag)
		uboxDump(ubox.box);
	vtUnlock(ubox.lock);

	return 1;
}
Exemple #16
0
static int
uboxInit(char* users, int len)
{
	User *g, *u;
	Ubox *box, *obox;
	int blank, comment, i, nline, nuser;
	char *buf, *f[5], **line, *p, *q, *s;

	/*
	 * Strip out whitespace and comments.
	 * Note that comments are pointless, they disappear
	 * when the server writes the database back out.
	 */
	blank = 1;
	comment = nline = 0;

	s = p = buf = vtMemAlloc(len+1);
	for(q = users; *q != '\0'; q++){
		if(*q == '\r' || *q == '\t' || *q == ' ')
			continue;
		if(*q == '\n'){
			if(!blank){
				if(p != s){
					*p++ = '\n';
					nline++;
					s = p;
				}
				blank = 1;
			}
			comment = 0;
			continue;
		}
		if(*q == '#')
			comment = 1;
		blank = 0;
		if(!comment)
			*p++ = *q;
	}
	*p = '\0';

	line = vtMemAllocZ((nline+2)*sizeof(char*));
	if((i = gettokens(buf, line, nline+2, "\n")) != nline){
		fprint(2, "nline %d (%d) botch\n", nline, i);
		vtMemFree(line);
		vtMemFree(buf);
		return 0;
	}

	/*
	 * Everything is updated in a local Ubox until verified.
	 */
	box = vtMemAllocZ(sizeof(Ubox));

	/*
	 * First pass - check format, check for duplicates
	 * and enter in hash buckets.
	 */
	nuser = 0;
	for(i = 0; i < nline; i++){
		s = vtStrDup(line[i]);
		if(getfields(s, f, nelem(f), 0, ":") != 4){
			fprint(2, "bad line '%s'\n", line[i]);
			vtMemFree(s);
			continue;
		}
		if(*f[0] == '\0' || *f[1] == '\0'){
			fprint(2, "bad line '%s'\n", line[i]);
			vtMemFree(s);
			continue;
		}
		if(!validUserName(f[0])){
			fprint(2, "invalid uid '%s'\n", f[0]);
			vtMemFree(s);
			continue;
		}
		if(_userByUid(box, f[0]) != nil){
			fprint(2, "duplicate uid '%s'\n", f[0]);
			vtMemFree(s);
			continue;
		}
		if(!validUserName(f[1])){
			fprint(2, "invalid uname '%s'\n", f[0]);
			vtMemFree(s);
			continue;
		}
		if(_userByUname(box, f[1]) != nil){
			fprint(2, "duplicate uname '%s'\n", f[1]);
			vtMemFree(s);
			continue;
		}

		u = userAlloc(f[0], f[1]);
		uboxAddUser(box, u);
		line[nuser] = line[i];
		nuser++;

		vtMemFree(s);
	}
	assert(box->nuser == nuser);

	/*
	 * Second pass - fill in leader and group information.
	 */
	for(i = 0; i < nuser; i++){
		s = vtStrDup(line[i]);
		getfields(s, f, nelem(f), 0, ":");

		assert(g = _userByUname(box, f[1]));
		if(*f[2] != '\0'){
			if((u = _userByUname(box, f[2])) == nil)
				g->leader = vtStrDup(g->uname);
			else
				g->leader = vtStrDup(u->uname);
			box->len += strlen(g->leader);
		}
		for(p = f[3]; p != nil; p = q){
			if((q = utfrune(p, L',')) != nil)
				*q++ = '\0';
			if(!_groupAddMember(box, g, p)){
				// print/log error here
			}
		}

		vtMemFree(s);
	}

	vtMemFree(line);
	vtMemFree(buf);

	for(i = 0; usersMandatory[i] != nil; i++){
		if((u = _userByUid(box, usersMandatory[i])) == nil){
			vtSetError("user '%s' is mandatory", usersMandatory[i]);
			uboxFree(box);
			return 0;
		}
		if(strcmp(u->uid, u->uname) != 0){
			vtSetError("uid/uname for user '%s' must match",
				usersMandatory[i]);
			uboxFree(box);
			return 0;
		}
	}

	vtLock(ubox.lock);
	obox = ubox.box;
	ubox.box = box;
	vtUnlock(ubox.lock);

	if(obox != nil)
		uboxFree(obox);

	return 1;
}
Exemple #17
0
static int
cmdSrv(int argc, char* argv[])
{
	Con *con;
	Srv *srv;
	char *usage = "usage: srv [-APWdp] [service]";
	int conflags, dflag, fd[2], mode, pflag, r;

	dflag = 0;
	pflag = 0;
	conflags = 0;
	mode = 0666;

	ARGBEGIN{
	default:
		return cliError(usage);
	case 'A':
		conflags |= ConNoAuthCheck;
		break;
	case 'I':
		conflags |= ConIPCheck;
		break;
	case 'N':
		conflags |= ConNoneAllow;
		break;
	case 'P':
		conflags |= ConNoPermCheck;
		mode = 0600;
		break;
	case 'W':
		conflags |= ConWstatAllow;
		mode = 0600;
		break;
	case 'd':
		dflag = 1;
		break;
	case 'p':
		pflag = 1;
		mode = 0600;
		break;
	}ARGEND

	if(pflag && (conflags&ConNoPermCheck)){
		vtSetError("srv: cannot use -P with -p");
		return 0;
	}

	switch(argc){
	default:
		return cliError(usage);
	case 0:
		vtRLock(sbox.lock);
		for(srv = sbox.head; srv != nil; srv = srv->next)
			consPrint("\t%s\t%d\n", srv->service, srv->srvfd);
		vtRUnlock(sbox.lock);

		return 1;
	case 1:
		if(!dflag)
			break;

		vtLock(sbox.lock);
		for(srv = sbox.head; srv != nil; srv = srv->next){
			if(strcmp(srv->service, argv[0]) != 0)
				continue;
			srvFree(srv);
			break;
		}
		vtUnlock(sbox.lock);

		if(srv == nil){
			vtSetError("srv: '%s' not found", argv[0]);
			return 0;
		}

		return 1;
	}

	if(pipe(fd) < 0){
		vtSetError("srv pipe: %r");
		return 0;
	}
	if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){
		close(fd[0]); close(fd[1]);
		return 0;
	}

	if(pflag)
		r = consOpen(fd[1], srv->srvfd, -1);
	else{
		con = conAlloc(fd[1], srv->mntpnt, conflags);
		if(con == nil)
			r = 0;
		else
			r = 1;
	}
	if(r == 0){
		close(fd[1]);
		vtLock(sbox.lock);
		srvFree(srv);
		vtUnlock(sbox.lock);
	}

	return r;
}
Exemple #18
0
int
fsSnapshot(Fs *fs, char *srcpath, char *dstpath, int doarchive)
{
	File *src, *dst;

	assert(fs->mode == OReadWrite);

	dst = nil;

	if(fs->halted){
		vtSetError("file system is halted");
		return 0;
	}

	/*
	 * Freeze file system activity.
	 */
	vtLock(fs->elk);

	/*
	 * Get the root of the directory we're going to save.
	 */
	if(srcpath == nil)
		srcpath = "/active";
	src = fileOpen(fs, srcpath);
	if(src == nil)
		goto Err;

	/*
	 * It is important that we maintain the invariant that:
	 *	if both b and bb are marked as Active with start epoch e
	 *	and b points at bb, then no other pointers to bb exist.
	 * 
	 * When bb is unlinked from b, its close epoch is set to b's epoch.
	 * A block with epoch == close epoch is
	 * treated as free by cacheAllocBlock; this aggressively
	 * reclaims blocks after they have been stored to Venti.
	 *
	 * Let's say src->source is block sb, and src->msource is block
	 * mb.  Let's also say that block b holds the Entry structures for
	 * both src->source and src->msource (their Entry structures might
	 * be in different blocks, but the argument is the same).
	 * That is, right now we have:
	 *
	 *	b	Active w/ epoch e, holds ptrs to sb and mb.
	 *	sb	Active w/ epoch e.
	 *	mb	Active w/ epoch e.
	 *
	 * With things as they are now, the invariant requires that
	 * b holds the only pointers to sb and mb.  We want to record
	 * pointers to sb and mb in new Entries corresponding to dst,
	 * which breaks the invariant.  Thus we need to do something
	 * about b.  Specifically, we bump the file system's epoch and
	 * then rewalk the path from the root down to and including b.
	 * This will copy-on-write as we walk, so now the state will be:
	 *
	 *	b	Snap w/ epoch e, holds ptrs to sb and mb.
	 *	new-b	Active w/ epoch e+1, holds ptrs to sb and mb.
	 *	sb	Active w/ epoch e.
	 *	mb	Active w/ epoch e.
	 *
	 * In this state, it's perfectly okay to make more pointers to sb and mb.
	 */
	if(!bumpEpoch(fs, 0) || !fileWalkSources(src))
		goto Err;

	/*
	 * Sync to disk.  I'm not sure this is necessary, but better safe than sorry.
	 */
	cacheFlush(fs->cache, 1);

	/*
	 * Create the directory where we will store the copy of src.
	 */
	dst = fileOpenSnapshot(fs, dstpath, doarchive);
	if(dst == nil)
		goto Err;

	/*
	 * Actually make the copy by setting dst's source and msource
	 * to be src's.
	 */
	if(!fileSnapshot(dst, src, fs->ehi-1, doarchive))
		goto Err;

	fileDecRef(src);
	fileDecRef(dst);
	src = nil;
	dst = nil;

	/*
	 * Make another copy of the file system.  This one is for the
	 * archiver, so that the file system we archive has the recently
	 * added snapshot both in /active and in /archive/yyyy/mmdd[.#].
	 */
	if(doarchive){
		if(!saveQid(fs))
			goto Err;
		if(!bumpEpoch(fs, 1))
			goto Err;
	}

	vtUnlock(fs->elk);

	/* BUG? can fs->arch fall out from under us here? */
	if(doarchive && fs->arch)
		archKick(fs->arch);

	return 1;

Err:
	fprint(2, "%s: fsSnapshot: %R\n", argv0);
	if(src)
		fileDecRef(src);
	if(dst)
		fileDecRef(dst);
	vtUnlock(fs->elk);
	return 0;
}
Exemple #19
0
static Source *
sourceAlloc(Fs *fs, Block *b, Source *p, uint32_t offset, int mode,
            int issnapshot)
{
    int epb;
    uint32_t epoch;
    char *pname = nil;
    Source *r;
    Entry e;

    assert(p==nil || sourceIsLocked(p));

    if(p == nil) {
        assert(offset == 0);
        epb = 1;
    } else
        epb = p->dsize / VtEntrySize;

    if(b->l.type != BtDir)
        goto Bad;

    /*
     * a non-active entry is the only thing that
     * can legitimately happen here. all the others
     * get prints.
     */
    if(!entryUnpack(&e, b->data, offset % epb)) {
        pname = sourceName(p);
        consPrint("%s: %s %V: sourceAlloc: entryUnpack failed\n",
                  fs->name, pname, b->score);
        goto Bad;
    }
    if(!(e.flags & VtEntryActive)) {
        pname = sourceName(p);
        if(0) consPrint("%s: %s %V: sourceAlloc: not active\n",
                            fs->name, pname, e.score);
        goto Bad;
    }
    if(e.psize < 256 || e.dsize < 256) {
        pname = sourceName(p);
        consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud < 256\n",
                  fs->name, pname, e.score, e.psize, e.dsize);
        goto Bad;
    }

    if(e.depth < sizeToDepth(e.size, e.psize, e.dsize)) {
        pname = sourceName(p);
        consPrint("%s: %s %V: sourceAlloc: depth %ud size %llud "
                  "psize %ud dsize %ud\n", fs->name, pname,
                  e.score, e.depth, e.size, e.psize, e.dsize);
        goto Bad;
    }

    if((e.flags & VtEntryLocal) && e.tag == 0) {
        pname = sourceName(p);
        consPrint("%s: %s %V: sourceAlloc: flags %#ux tag %#ux\n",
                  fs->name, pname, e.score, e.flags, e.tag);
        goto Bad;
    }

    if(e.dsize > fs->blockSize || e.psize > fs->blockSize) {
        pname = sourceName(p);
        consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud "
                  "> blocksize %ud\n", fs->name, pname, e.score,
                  e.psize, e.dsize, fs->blockSize);
        goto Bad;
    }

    epoch = b->l.epoch;
    if(mode == OReadWrite) {
        if(e.snap != 0) {
            vtSetError(ESnapRO);
            return nil;
        }
    } else if(e.snap != 0) {
        if(e.snap < fs->elo) {
            vtSetError(ESnapOld);
            return nil;
        }
        if(e.snap >= fs->ehi)
            goto Bad;
        epoch = e.snap;
    }

    r = vtMemAllocZ(sizeof(Source));
    r->fs = fs;
    r->mode = mode;
    r->issnapshot = issnapshot;
    r->dsize = e.dsize;
    r->gen = e.gen;
    r->dir = (e.flags & VtEntryDir) != 0;
    r->lk = vtLockAlloc();
    r->ref = 1;
    r->parent = p;
    if(p) {
        vtLock(p->lk);
        assert(mode == OReadOnly || p->mode == OReadWrite);
        p->ref++;
        vtUnlock(p->lk);
    }
    r->epoch = epoch;
//	consPrint("sourceAlloc: have %V be.%d fse.%d %s\n", b->score,
//		b->l.epoch, r->fs->ehi, mode == OReadWrite? "rw": "ro");
    memmove(r->score, b->score, VtScoreSize);
    r->scoreEpoch = b->l.epoch;
    r->offset = offset;
    r->epb = epb;
    r->tag = b->l.tag;

//	consPrint("%s: sourceAlloc: %p -> %V %d\n", r, r->score, r->offset);

    return r;
Bad:
    free(pname);
    vtSetError(EBadEntry);
    return nil;
}
Exemple #20
0
int
vtConnect(VtSession *z, char *password)
{
	char buf[VtMaxStringSize], *p, *ep, *prefix;
	int i;

	USED(password);
	vtLock(z->lk);
	if(z->cstate != VtStateAlloc) {
		vtSetError("bad session state");
		vtUnlock(z->lk);
		return 0;
	}
	if(z->fd < 0){
		vtSetError("%s", z->fderror);
		vtUnlock(z->lk);
		return 0;
	}

	/* be a little anal */
	vtLock(z->inLock);
	vtLock(z->outLock);

	prefix = "venti-";
	p = buf;
	ep = buf + sizeof(buf);
	p = seprint(p, ep, "%s", prefix);
	p += strlen(p);
	for(i=0; vtVersions[i].version; i++) {
		if(i != 0)
			*p++ = ':';
		p = seprint(p, ep, "%s", vtVersions[i].s);
	}
	p = seprint(p, ep, "-libventi\n");
	assert(p-buf < sizeof(buf));
	if(z->outHash)
		vtSha1Update(z->outHash, (uint8_t*)buf, p-buf);
	if(!vtFdWrite(z->fd, (uint8_t*)buf, p-buf))
		goto Err;
	
	vtDebug(z, "version string out: %s", buf);

	if(!vtVersionRead(z, prefix, &z->version))
		goto Err;
		
	vtDebug(z, "version = %d: %s\n", z->version, vtGetVersion(z));

	vtUnlock(z->inLock);
	vtUnlock(z->outLock);
	z->cstate = VtStateConnected;
	vtUnlock(z->lk);

	if(z->vtbl)
		return 1;

	if(!vtHello(z))
		goto Err;
	return 1;	
Err:
	if(z->fd >= 0)
		vtFdClose(z->fd);
	z->fd = -1;
	vtUnlock(z->inLock);
	vtUnlock(z->outLock);
	z->cstate = VtStateClosed;
	vtUnlock(z->lk);
	return 0;	
}
Exemple #21
0
static void
archThread(void *v)
{
	Arch *a = v;
	Block *b;
	Param p;
	Super super;
	int ret;
	u32int addr;
	uchar rbuf[VtRootSize];
	VtRoot root;

	vtThreadSetName("arch");

	for(;;){
		/* look for work */
		vtLock(a->fs->elk);
		b = superGet(a->c, &super);
		if(b == nil){
			vtUnlock(a->fs->elk);
			fprint(2, "archThread: superGet: %R\n");
			sleep(60*1000);
			continue;
		}
		addr = super.next;
		if(addr != NilBlock && super.current == NilBlock){
			super.current = addr;
			super.next = NilBlock;
			superPack(&super, b->data);
			blockDirty(b);
		}else
			addr = super.current;
		blockPut(b);
		vtUnlock(a->fs->elk);

		if(addr == NilBlock){
			/* wait for work */
			vtLock(a->lk);
			vtSleep(a->starve);
			if(a->die != nil)
				goto Done;
			vtUnlock(a->lk);
			continue;
		}

sleep(10*1000);	/* window of opportunity to provoke races */

		/* do work */
		memset(&p, 0, sizeof p);
		p.blockSize = a->blockSize;
		p.dsize = 3*VtEntrySize;	/* root has three Entries */
		p.c = a->c;
		p.a = a;

		ret = archWalk(&p, addr, BtDir, RootTag);
		switch(ret){
		default:
			abort();
		case ArchFailure:
			fprint(2, "archiveBlock %#ux: %R\n", addr);
			sleep(60*1000);
			continue;
		case ArchSuccess:
		case ArchFaked:
			break;
		}

		if(0) fprint(2, "archiveSnapshot 0x%#ux: maxdepth %ud nfixed %ud"
			" send %ud nfailsend %ud nvisit %ud"
			" nreclaim %ud nfake %ud nreal %ud\n",
			addr, p.maxdepth, p.nfixed,
			p.nsend, p.nfailsend, p.nvisit,
			p.nreclaim, p.nfake, p.nreal);
		if(0) fprint(2, "archiveBlock %V (%ud)\n", p.score, p.blockSize);

		/* tie up vac root */
		memset(&root, 0, sizeof root);
		root.version = VtRootVersion;
		strecpy(root.type, root.type+sizeof root.type, "vac");
		strecpy(root.name, root.name+sizeof root.name, "fossil");
		memmove(root.score, p.score, VtScoreSize);
		memmove(root.prev, super.last, VtScoreSize);
		root.blockSize = a->blockSize;
		vtRootPack(&root, rbuf);
		if(!vtWrite(a->z, p.score, VtRootType, rbuf, VtRootSize)
		|| !vtSha1Check(p.score, rbuf, VtRootSize)){
			fprint(2, "vtWriteBlock %#ux: %R\n", addr);
			sleep(60*1000);
			continue;
		}

		/* record success */
		vtLock(a->fs->elk);
		b = superGet(a->c, &super);
		if(b == nil){
			vtUnlock(a->fs->elk);
			fprint(2, "archThread: superGet: %R\n");
			sleep(60*1000);
			continue;
		}
		super.current = NilBlock;
		memmove(super.last, p.score, VtScoreSize);
		superPack(&super, b->data);
		blockDirty(b);
		blockPut(b);
		vtUnlock(a->fs->elk);

		consPrint("archive vac:%V\n", p.score);
	}

Done:
	a->ref--;
	vtWakeup(a->die);
	vtUnlock(a->lk);
}
Exemple #22
0
Fid*
fidGet(Con* con, u32int fidno, int flags)
{
	Fid *fid, **hash;

	if(fidno == NOFID)
		return nil;

	hash = &con->fidhash[fidno % NFidHash];
	vtLock(con->fidlock);
	for(fid = *hash; fid != nil; fid = fid->hash){
		if(fid->fidno != fidno)
			continue;

		/*
		 * Already in use is an error
		 * when called from attach, clone or walk.
		 */
		if(flags & FidFCreate){
			vtUnlock(con->fidlock);
			vtSetError("%s: fid 0x%ud in use", argv0, fidno);
			return nil;
		}
		fid->ref++;
		vtUnlock(con->fidlock);

		fidLock(fid, flags);
		if((fid->open & FidOCreate) || fid->fidno == NOFID){
			fidPut(fid);
			vtSetError("%s: fid invalid", argv0);
			return nil;
		}
		return fid;
	}

	if((flags & FidFCreate) && (fid = fidAlloc()) != nil){
		assert(flags & FidFWlock);
		fid->con = con;
		fid->fidno = fidno;
		fid->ref = 1;

		fid->hash = *hash;
		*hash = fid;
		if(con->ftail != nil){
			fid->prev = con->ftail;
			con->ftail->next = fid;
		}
		else{
			con->fhead = fid;
			fid->prev = nil;
		}
		con->ftail = fid;
		fid->next = nil;

		con->nfid++;
		vtUnlock(con->fidlock);

		/*
		 * The FidOCreate flag is used to prevent any
		 * accidental access to the Fid between unlocking the
		 * hash and acquiring the Fid lock for return.
		 */
		fidLock(fid, flags);
		fid->open &= ~FidOCreate;
		return fid;
	}
	vtUnlock(con->fidlock);

	vtSetError("%s: fid not found", argv0);
	return nil;
}