示例#1
0
文件: fscmd.c 项目: CoryXie/nix-os
/*
 * Walks elems starting at f.
 * Ok if nelems is 0.
 */
static Path*
walkpath(Memblk *f, char *elems[], int nelems)
{
	int i;
	Memblk *nf;
	Path *p;

	p = newpath(f);
	if(catcherror()){
		putpath(p);
		error(nil);
	}
	isfile(f);
	for(i = 0; i < nelems; i++){
		if((f->d.mode&DMDIR) == 0)
			error("not a directory");
		rwlock(f, Rd);
		if(catcherror()){
			rwunlock(f, Rd);
			error("walk: %r");
		}
		nf = dfwalk(f, elems[i], Rd);
		rwunlock(f, Rd);
		addelem(&p, nf);
		mbput(nf);
		f = nf;
		USED(&f);	/* in case of error() */
		noerror();
	}
	noerror();
	return p;
}
示例#2
0
文件: fscmd.c 项目: CoryXie/nix-os
static void
fsrm(int, char *argv[])
{
	Memblk *f, *pf;
	Path *p;

	p = walkto(argv[1], nil);	
	if(catcherror()){
		putpath(p);
		error(nil);
	}
	if(p->nf < 2)
		error("short path for rm");
	dfmelt(&p, p->nf-1);
	f = p->f[p->nf-1];
	pf = p->f[p->nf-2];
	rwlock(f, Wr);
	if(catcherror()){
		rwunlock(f, Wr);
		rwunlock(pf, Wr);
		error(nil);
	}
	dfremove(pf, f);
	p->f[p->nf-1] = nil;
	noerror();
	noerror();
	rwunlock(pf, Wr);
	putpath(p);
}
示例#3
0
文件: fscmd.c 项目: 99years/plan9
static void
fsget(int, char *argv[])
{
	Memblk *f;
	Mfile *m;
	char buf[4096], *nm;
	uvlong off;
	long nr;
	int fd;
	Path *p;

	fd = create(argv[1], OWRITE, 0664);
	if(fd < 0)
		error("create: %r\n");
	nm = fsname(argv[2]);
	if(catcherror()){
		free(nm);
		close(fd);
		error(nil);
	}
	p = walkto(nm, nil);
	f = p->f[p->nf-1];
	rwlock(f, Rd);
	if(catcherror()){
		rwunlock(f, Rd);
		putpath(p);
		error(nil);
	}
	m = f->mf;
	print("get %-30s\t%M\t%5ulld\t%s %ulld refs\n",
		m->name, (ulong)f->d.mode, f->d.length, m->uid, dbgetref(f->addr));
	if((f->d.mode&DMDIR) == 0){
		off = 0;
		for(;;){
			if(fsmemfree() < Mminfree)
				fslru();
			nr = dfpread(f, buf, sizeof buf, off);
			if(nr <= 0)
				break;
			if(write(fd, buf, nr) != nr){
				fprint(2, "%s: error: %r\n", argv[0]);
				break;
			}
			off += nr;
		}
	}
	close(fd);
	noerror();
	noerror();
	rwunlock(f, Rd);
	putpath(p);
	free(nm);
}
示例#4
0
文件: fblk.c 项目: CoryXie/nix-os
long
dfcountrefs(Memblk *f)
{
	Memblk *b;
	int i;
	long nfails;

	nfails = 0;
	isfile(f);
	if((f->addr&Fakeaddr) == 0 && f->addr >= fs->limit){
		fprint(2, "fscheck: '%s' d%#010ullx: out of range\n",
			f->mf->name, f->addr);
		return 1;
	}
	if((f->addr&Fakeaddr) == 0)
		if(countref(f->addr) != 0)		/* already visited */
			return 0;			/* skip children */
	rwlock(f, Rd);
	if(catcherror()){
		fprint(2, "fscheck: '%s' d%#010ullx: data: %r\n",
			f->mf->name, f->addr);
		rwunlock(f, Rd);
		return 1;
	}
	for(i = 0; i < nelem(f->d.dptr); i++)
		ptrmap(f->d.dptr[i], 0, bcountrefs, Disk);
	for(i = 0; i < nelem(f->d.iptr); i++)
		ptrmap(f->d.iptr[i], i+1, bcountrefs, Disk);
	if(f->d.mode&DMDIR)
		for(i = 0; i < f->d.length/Daddrsz; i++){
			b = dfchild(f, i);
			if(catcherror()){
				fprint(2, "fscheck: '%s'  d%#010ullx:"
					" child[%d]: %r\n",
					f->mf->name, f->addr, i);
				nfails++;
			}else{
				nfails += dfcountrefs(b);
				noerror();
			}
			mbput(b);
		}
	noerror();
	rwunlock(f, Rd);
	return nfails;
}
示例#5
0
文件: fblk.c 项目: CoryXie/nix-os
/*
 * May be called with null parent, for root and ctl files.
 * The first call with a null parent is root, all others are ctl
 * files linked at root.
 */
Memblk*
dfcreate(Memblk *parent, char *name, int uid, ulong mode)
{
	Memblk *nf;
	Mfile *m;
	int isctl;

	if(fsfull())
		error("file system full");
	isctl = parent == nil;
	if(parent == nil)
		parent = fs->root;

	if(parent != nil){
		dprint("dfcreate '%s' %M at\n%H\n", name, mode, parent);
		isdir(parent);
		isrwlocked(parent, Wr);
		ismelted(parent);
	}else
		dprint("dfcreate '%s' %M", name, mode);

	if(isctl)
		nf = dballoc(DBctl);
	else
		nf = dballoc(DBfile);
	if(catcherror()){
		mbput(nf);
		if(parent != nil)
			rwunlock(parent, Wr);
		error(nil);
	}

	m = nf->mf;
	nf->d.id = nsec();
	nf->d.mode = mode;
	nf->d.mtime = nf->d.id;
	nf->d.atime = nf->d.id;
	nf->d.length = 0;
	m->uid = usrname(uid);
	nf->d.uid = uid;
	m->gid = m->uid;
	nf->d.gid = nf->d.uid;
	m->muid = m->uid;
	nf->d.muid = nf->d.uid;
	m->name = name;
	nf->d.asize = pmeta(nf->d.embed, Embedsz, nf);
	changed(nf);

	if(parent != nil){
		m->gid = parent->mf->gid;
		nf->d.gid = parent->d.gid;
		dflink(parent, nf);
	}
	noerror();
	dprint("dfcreate-> %H\n within %H\n", nf, parent);
	return nf;
}
示例#6
0
文件: fscmd.c 项目: 99years/plan9
static void
fscat(int, char *argv[])
{
	Memblk *f;
	Mfile *m;
	char buf[4096], *nm;
	uvlong off;
	long nr;
	Path *p;

	nm = fsname(argv[2]);
	if(catcherror()){
		free(nm);
		error(nil);
	}
	p = walkto(nm, nil);
	f = p->f[p->nf-1];
	rwlock(f, Rd);
	if(catcherror()){
		rwunlock(f, Rd);
		putpath(p);
		error(nil);
	}
	m = f->mf;
	print("cat %-30s\t%M\t%5ulld\t%s %ulld refs\n",
		m->name, (ulong)f->d.mode, f->d.length, m->uid, dbgetref(f->addr));
	if((f->d.mode&DMDIR) == 0){
		off = 0;
		for(;;){
			if(fsmemfree() < Mminfree)
				fslru();
			nr = dfpread(f, buf, sizeof buf, off);
			if(nr <= 0)
				break;
			write(1, buf, nr);
			off += nr;
		}
	}
	noerror();
	noerror();
	rwunlock(f, Rd);
	putpath(p);
	free(nm);
}
示例#7
0
文件: fblk.c 项目: CoryXie/nix-os
void
dfused(Path *p)
{
	Memblk *f;

	f = p->f[p->nf-1];
	isfile(f);
	rwlock(f, Wr);
	f->d.atime = nsec();
	rwunlock(f, Wr);
}
示例#8
0
文件: fscmd.c 项目: 99years/plan9
static void
fsrm(int, char *argv[])
{
	Memblk *f, *pf;
	Path *p;
	char *nm;

	nm = fsname(argv[1]);
	if(catcherror()){
		free(nm);
		error(nil);
	}
	p = walkto(nm, nil);	
	if(catcherror()){
		putpath(p);
		error(nil);
	}
	if(p->nf < 2)
		error("short path for rm");
	meltedpath(&p, p->nf-1, 1);
	f = p->f[p->nf-1];
	pf = p->f[p->nf-2];
	rwlock(f, Wr);
	if(catcherror()){
		rwunlock(f, Wr);
		rwunlock(pf, Wr);
		error(nil);
	}
	dfremove(pf, f);
	p->f[p->nf-1] = nil;
	noerror();
	noerror();
	noerror();
	rwunlock(pf, Wr);
	putpath(p);
	free(nm);
}
示例#9
0
文件: fblk.c 项目: CoryXie/nix-os
int
dffreeze(Memblk *f)
{
	int i;
	Memblk *b;
	long tot;

	isfile(f);
	if(f->frozen && f != fs->active && f != fs->archive)
		return 0;
	rwlock(f, Wr);
	if(catcherror()){
		rwunlock(f, Wr);
		error(nil);
	}
	f->frozen = 1;
	tot = 1;
	for(i = 0; i < nelem(f->d.dptr); i++)
		tot += ptrmap(f->d.dptr[i], 0, bfreeze, Mem);
	for(i = 0; i < nelem(f->d.iptr); i++)
		tot += ptrmap(f->d.iptr[i], i+1, bfreeze, Mem);
	if((f->d.mode&DMDIR) != 0){
		for(i = 0; i < f->d.length/Daddrsz; i++){
			b = mfchild(f, i);
			if(b == nil)
				continue;
			if(!catcherror()){
				tot += dffreeze(b);
				noerror();
			}
			mbput(b);
		}
	}
	noerror();
	rwunlock(f, Wr);
	return tot;
}
示例#10
0
文件: fblk.c 项目: CoryXie/nix-os
/*
 * Drop one disk reference for f and reclaim its storage if it's gone.
 * The given memory reference is not released.
 * For directories, all files contained have their disk references adjusted,
 * and they are also reclaimed if no further references exist.
 *
 * NB: Time ago, directories were not in compact form (they had holes
 * due to removals) and this had a bug while reclaiming that could lead
 * to double frees of disk blocks.
 * The bug was fixed, but since then, directories have changed again to
 * have holes. If the a double free happens again, this is the place where
 * to look, besides dbdup and dfchdentry.
 */
int
dfput(Memblk *f)
{
	int i;
	Memblk *b;
	long tot;

	isfile(f);
	dKprint("dfput %H\n", f);
	/*
	 * Remove children if it's the last disk ref before we drop data blocks.
	 * No new disk refs may be added, so there's no race here.
	 */
	tot = 0;
	if(dbgetref(f->addr) == 1 && (f->d.mode&DMDIR) != 0){
		rwlock(f, Wr);
		if(catcherror()){
			rwunlock(f, Wr);
			error(nil);
		}
		for(i = 0; i < f->d.ndents; i++){
			b = dfchild(f, i);
			if(!catcherror()){
				tot += dfput(b);
				noerror();
			}
			mbput(b);
		}
		noerror();
		rwunlock(f, Wr);
	}

	if(dbput(f, f->type, f->addr) == 0)
		tot++;
	return tot;
}
示例#11
0
文件: fblk.c 项目: CoryXie/nix-os
/*
 * Return the last version for *fp, wlocked, be it frozen or melted.
 */
void
followmelted(Memblk **fp, int iswr)
{
	Memblk *f;

	f = *fp;
	isfile(f);
	rwlock(f, iswr);
	while(f->mf->melted != nil){
		incref(f->mf->melted);
		*fp = f->mf->melted;
		rwunlock(f, iswr);
		mbput(f);
		f = *fp;
		rwlock(f, iswr);
		if(!f->frozen)
			return;
	}
}
示例#12
0
文件: fblk.c 项目: CoryXie/nix-os
/*
 * Report that a file has been modified.
 * Modification times propagate up to the root of the file tree.
 * But frozen files are never changed.
 */
void
dfchanged(Path *p, int muid)
{
	Memblk *f;
	u64int t, u;
	int i;

	t = nsec();
	u = muid;
	for(i = 0; i < p->nf; i++){
		f = p->f[i];
		rwlock(f, Wr);
		if(f->frozen == 0)
			if(!catcherror()){
				f->d.mtime = t;
				f->d.atime = t;
				f->d.muid = muid;
				changed(f);
				noerror();
			}
		rwunlock(f, Wr);
	}
}
示例#13
0
文件: fblk.c 项目: CoryXie/nix-os
void
dfremove(Memblk *p, Memblk *f)
{
	vlong n;

	/* funny as it seems, we may need extra blocks to melt */
	if(fsfull())
		error("file system full");

	isrwlocked(f, Wr);
	isrwlocked(p, Wr);
	ismelted(p);
	if((f->d.mode&DMDIR) != 0 && f->d.ndents > 0)
		error("directory not empty");
	incref(p);
	if(catcherror()){
		mbput(p);
		error(nil);
	}
	dfunlink(p, f);
	/* shouldn't fail now. it's unlinked */

	if(p->d.ndents == 0 && p->d.length > 0){	/* all gone, make it public */
		p->d.length = 0;
		changed(p);
	}

	noerror();
	rwunlock(f, Wr);
	if(!catcherror()){
		n = dfput(f);
		dprint("dfput d%#ullx: %lld blks\n", f->addr, n);
		noerror();
	}
	mbput(f);
	mbput(p);
}
示例#14
0
文件: taskq.c 项目: jeffpc/suntaskq
static void *
taskq_thread(void *arg)
{
	taskq_t *tq = arg;
	taskq_ent_t *t;
	bool prealloc;

	mxlock(&tq->tq_lock);
	while (tq->tq_flags & TASKQ_ACTIVE) {
		if ((t = tq->tq_task.tqent_next) == &tq->tq_task) {
			if (--tq->tq_active == 0)
				condbcast(&tq->tq_wait_cv);
			condwait(&tq->tq_dispatch_cv, &tq->tq_lock);
			tq->tq_active++;
			continue;
		}
		t->tqent_prev->tqent_next = t->tqent_next;
		t->tqent_next->tqent_prev = t->tqent_prev;
		t->tqent_next = NULL;
		t->tqent_prev = NULL;
		prealloc = t->tqent_flags & TQENT_FLAG_PREALLOC;
		mxunlock(&tq->tq_lock);

		rwlock(&tq->tq_threadlock, false);
		t->tqent_func(t->tqent_arg);
		rwunlock(&tq->tq_threadlock);

		mxlock(&tq->tq_lock);
		if (!prealloc)
			task_free(tq, t);
	}
	tq->tq_nthreads--;
	condbcast(&tq->tq_wait_cv);
	mxunlock(&tq->tq_lock);
	return (NULL);
}
示例#15
0
文件: fblk.c 项目: CoryXie/nix-os
/*
 * Advance path to use the most recent version of each file.
 */
Path*
dflast(Path **pp, int nth)
{
	Memblk *f;
	Path *p;
	int i;

	p = *pp;
	for(i = 0; i < nth; i++){
		f = p->f[i];
		if(f != nil && f->mf != nil && f->mf->melted != nil)
			break;
	}
	if(i == nth)
		return p;	/* all files have the last version */

	ownpath(pp);
	p = *pp;
	for(i = 0; i < nth; i++){
		followmelted(&p->f[i], Rd);
		rwunlock(p->f[i], Rd);
	}
	return p;
}
示例#16
0
文件: fscmd.c 项目: 99years/plan9
/*
 * This is unrealistic in that it keeps the file locked
 * during the entire put. This means that we can only give
 * fslru() a chance before each put, and not before each
 * write, because everything is going to be in use and dirty if
 * we run out of memory.
 */
static void
fsput(int, char *argv[])
{
	int fd;
	char *fn;
	Memblk *m, *f;
	Dir *d;
	char buf[4096];
	uvlong off;
	long nw, nr;
	Path *p;
	char *nm;

	fd = open(argv[1], OREAD);
	if(fd < 0)
		error("open: %r\n");
	d = dirfstat(fd);
	if(d == nil){
		error("dirfstat: %r\n");
	}
	nm = fsname(argv[2]);
	if(catcherror()){
		free(nm);
		close(fd);
		free(d);
		error(nil);
	}
	p = walkto(nm, &fn);
	if(catcherror()){
		putpath(p);
		error(nil);
	}
	meltedpath(&p, p->nf, 1);
	m = p->f[p->nf-1];
	if(catcherror()){
		rwunlock(m, Wr);
		error(nil);
	}
	f = dfcreate(m, fn, usrid(d->uid), d->mode&(DMDIR|0777));
	noerror();
	addelem(&p, f);
	decref(f);	/* kept now in p */
	rwlock(f, Wr);
	rwunlock(m, Wr);
	if(catcherror()){
		rwunlock(f, Wr);
		error(nil);
	}
	if((d->mode&DMDIR) == 0){
		off = 0;
		for(;;){
			if(fsmemfree() < Mminfree)
				fslru();
			nr = read(fd, buf, sizeof buf);
			if(nr <= 0)
				break;
			nw = dfpwrite(f, buf, nr, &off);
			dprint("wrote %ld of %ld bytes\n", nw, nr);
			off += nr;
		}
	}
	noerror();
	noerror();
	noerror();
	if(verb)
		print("created %H\nat %H\n", f, m);
	rwunlock(f, Wr);
	free(nm);
	putpath(p);
	close(fd);
	free(d);
}
示例#17
0
文件: fblk.c 项目: CoryXie/nix-os
/*
 * Caller walked down p, and now requires the nth element to be
 * melted, and wlocked for writing. (nth count starts at 1);
 * 
 * Return the path with the version of f that we must use,
 * locked for writing and melted.
 * References kept in the path are traded for the ones returned.
 */
Path*
dfmelt(Path **pp, int nth)
{
	int i;
	Memblk *f, **fp, *nf;
	Path *p;

	ownpath(pp);
	p = *pp;
	assert(nth >= 1 && p->nf >= nth && p->nf >= 2);
	assert(p->f[0] == fs->root);
	fp = &p->f[nth-1];

	/*
	 * 1. Optimistic: Try to get a loaded melted version for f.
	 */
	followmelted(fp, Wr);
	f = *fp;
	if(!f->frozen)
		return p;
	ainc(&fs->nmelts);
	rwunlock(f, Wr);

	/*
	 * 2. Realistic:
	 * walk down the path, melting every frozen thing until we
	 * reach f. Keep wlocks so melted files are not frozen while we walk.
	 * /active is special, because it's only frozen temporarily while
	 * creating a frozen version of the tree. Instead of melting it,
	 * we should just wait for it.
	 * p[0] is /
	 * p[1] is /active
	 */
	for(;;){
		followmelted(&p->f[1], Wr);
		if(p->f[1]->frozen == 0)
			break;
		rwunlock(p->f[1], Wr);
		yield();
	}
	/*
	 * At loop header, parent is p->f[i-1], melted and wlocked.
	 * At the end of the loop, p->f[i] is melted and wlocked.
	 */
	for(i = 2; i < nth; i++){
		followmelted(&p->f[i], Wr);
		if(!p->f[i]->frozen){
			rwunlock(p->f[i-1], Wr);
			continue;
		}
		if(catcherror()){
			rwunlock(p->f[i-1], Wr);
			rwunlock(p->f[i], Wr);
			error(nil);
		}

		nf = dbdup(p->f[i]);
		rwlock(nf, Wr);

		if(catcherror()){
			rwunlock(nf, Wr);
			mbput(nf);
			error(nil);
		}
		dfchdentry(p->f[i-1], p->f[i]->addr, nf->addr, Mkit);
		noerror();
		noerror();
		/* committed */
		rwunlock(p->f[i-1], Wr);		/* parent */
		rwunlock(p->f[i], Wr);		/* old frozen version */
		f = p->f[i];
		p->f[i] = nf;
		assert(f->ref > 1);
		mbput(f);			/* ref from path */
		if(!catcherror()){
			dbput(f, f->type, f->addr); /* p->f[i] ref from disk */
			noerror();
		}
	}
	return p;
}