xref: /plan9-contrib/sys/src/cmd/fscfs/cfs.c (revision 518acb8505541d27c37065969099debc28466c8f)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include <thread.h>
6 
7 /*
8  * to do:
9  *	- concurrency?
10  *		- only worthwhile with several connections, perhaps to several file servers
11  *	- cache directories
12  *	- message size (dynamic buffers)
13  *	- more useful stats
14  *	- notes
15  *	- lru for sfids in paths (also correct ref counts for paths)
16  */
17 
18 #include "dat.h"
19 #include "fns.h"
20 #include "stats.h"
21 
22 #define DPRINT if(debug)fprint
23 
24 /* maximum length of a file (used for unknown lengths) */
25 enum { MAXLEN = ((uvlong)1<<63)-1 };
26 
27 int	debug, statson, noauth, openserver;
28 
29 #define	MAXFDATA	8192	/* i/o size for read/write */
30 
31 struct P9fs
32 {
33 	int	fd[2];
34 	Fcall	thdr;
35 	Fcall	rhdr;
36 	uchar	sndbuf[MAXFDATA+IOHDRSZ];	/* TO DO: dynamic */
37 	uchar	rcvbuf[2][MAXFDATA + IOHDRSZ];	/* extra buffer to protect client data over server calls */
38 	int	cb;	/* current buffer */
39 	long	len;
40 	char	*name;
41 };
42 
43 P9fs	c;	/* client conversation */
44 P9fs	s;	/* server conversation */
45 
46 Host	host[1];	/* clients, just the one for now */
47 
48 Cfsstat  cfsstat, cfsprev;
49 char	statbuf[2048];
50 int	statlen;
51 
52 int		messagesize = MAXFDATA+IOHDRSZ;	/* must be the same for all connections */
53 
54 Qid	rootqid;
55 Qid	ctlqid = {0x5555555555555555LL, 0, 0};
56 
57 uint	cachesize = 16 * 1024 * 1024;
58 
59 /*
60  * clients directly access directories, auth files, append-only files, exclusive-use files, and mount points
61  */
62 #define	isdirect(qid)	(((qid).type & ~QTTMP) != QTFILE)
63 
64 static char Efidinuse[] = "fid in use";
65 static char Ebadfid[] = "invalid fid";
66 static char Enotdir[] = "not a directory";
67 static char Enonexist[] = "file does not exist";
68 static char Eexist[] = "file already exists";
69 static char Eopened[] = "opened for I/O";
70 static char Emode[] = "bad open mode";
71 static char Eremoved[] = "file has been removed";
72 
73 static SFid*	freefids;
74 static u32int fidgen;
75 
76 static Data	datalist;
77 
78 static Auth*	authlist;
79 
80 void
usage(void)81 usage(void)
82 {
83 	fprint(2, "usage: %s [-a netaddr | -F srv] [-dknS] [mntpt] [spec]\n", argv0);
84 	threadexitsall("usage");
85 }
86 
87 void
threadmain(int argc,char * argv[])88 threadmain(int argc, char *argv[])
89 {
90 	int std;
91 	char *server, *mtpt, *aname;
92 
93 	std = 0;
94 	server = "net!$server";
95 	mtpt = "/n/remote";
96 	aname = "";
97 
98 	ARGBEGIN{
99 	case 'a':
100 		server = EARGF(usage());
101 		break;
102 	case 'd':
103 		debug = 1;
104 		break;
105 	case 'F':
106 		server = EARGF(usage());
107 		openserver = 1;
108 		break;
109 	case 'm':
110 		cachesize = atoi(EARGF(usage())) * 1024 * 1024;
111 		if(cachesize < 8 * 1024 * 1024 ||
112 		    cachesize > 3750UL * 1024 * 1024)
113 			sysfatal("implausible cache size %ud", cachesize);
114 		break;
115 	case 'n':
116 		noauth = 1;
117 		break;
118 	case 'S':
119 		statson = 1;
120 		break;
121 	case 's':
122 		std = 1;
123 		break;
124 	default:
125 		usage();
126 	}ARGEND
127 	if(argc && *argv)
128 		mtpt = *argv;
129 	if(argc > 1 && argv[1])
130 		aname = argv[1];
131 
132 	quotefmtinstall();
133 	if(debug){
134 		fmtinstall('F', fcallfmt);
135 		fmtinstall('D', dirfmt);
136 		fmtinstall('M', dirmodefmt);
137 	}
138 
139 	c.name = "client";
140 	s.name = "server";
141 	if(std){
142 		c.fd[0] = c.fd[1] = 1;
143 		s.fd[0] = s.fd[1] = 0;
144 	}else
145 		mountinit(server, mtpt, aname);
146 
147 	switch(fork()){
148 	case 0:
149 		io();
150 		threadexits("");
151 	case -1:
152 		error("fork");
153 	default:
154 		_exits("");
155 	}
156 }
157 
158 /*
159  * TO DO: need to use libthread variants
160  */
161 void
mountinit(char * server,char * mountpoint,char * aname)162 mountinit(char *server, char *mountpoint, char *aname)
163 {
164 	int err;
165 	int p[2];
166 
167 	/*
168 	 *  grab a channel and call up the file server
169 	 */
170 	if(openserver){
171 		s.fd[0] = open(server, ORDWR);
172 		if(s.fd[0] < 0)
173 			error("opening srv file %s: %r", server);
174 	} else {
175 		s.fd[0] = dial(netmkaddr(server, 0, "9fs"), 0, 0, 0);
176 		if(s.fd[0] < 0)
177 			error("dialing %s: %r", server);
178 	}
179 	s.fd[1] = s.fd[0];
180 
181 	/*
182  	 *  mount onto name space
183 	 */
184 	if(pipe(p) < 0)
185 		error("pipe failed");
186 	switch(fork()){
187 	case 0:
188 		break;
189 	default:
190 		rfork(RFFDG);
191 		close(p[0]);
192 		if(noauth)
193 			err = mount(p[1], -1, mountpoint, MREPL|MCREATE|MCACHE, aname);
194 		else
195 			err = amount(p[1], mountpoint, MREPL|MCREATE|MCACHE, aname);
196 		if(err < 0)
197 			error("mount failed: %r");
198 		_exits(0);
199 	case -1:
200 		error("fork failed\n");
201 /*BUG: no wait!*/
202 	}
203 	close(p[1]);
204 	c.fd[0] = c.fd[1] = p[0];
205 }
206 
207 void
io(void)208 io(void)
209 {
210 	Fcall *t;
211 
212 	datainit();
213 	t = &c.thdr;
214 
215     loop:
216 	rcvmsg(&c, t);
217 
218 	if(statson){
219 		cfsstat.cm[t->type].n++;
220 		cfsstat.cm[t->type].s = nsec();
221 	}
222 	switch(t->type){
223 	default:
224 		sendreply("invalid 9p operation");
225 		break;
226 	case Tversion:
227 		rversion(t);
228 		break;
229 	case Tauth:
230 		rauth(t);
231 		break;
232 	case Tflush:
233 		rflush(t);
234 		break;
235 	case Tattach:
236 		rattach(t);
237 		break;
238 	case Twalk:
239 		rwalk(t);
240 		break;
241 	case Topen:
242 		ropen(t);
243 		break;
244 	case Tcreate:
245 		rcreate(t);
246 		break;
247 	case Tread:
248 		rread(t);
249 		break;
250 	case Twrite:
251 		rwrite(t);
252 		break;
253 	case Tclunk:
254 		rclunk(t);
255 		break;
256 	case Tremove:
257 		rremove(t);
258 		break;
259 	case Tstat:
260 		rstat(t);
261 		break;
262 	case Twstat:
263 		rwstat(t);
264 		break;
265 	}
266 	if(statson){
267 		cfsstat.cm[t->type].t += nsec() -cfsstat.cm[t->type].s;
268 	}
269 	goto loop;
270 }
271 
272 void
rversion(Fcall * t)273 rversion(Fcall *t)
274 {
275 	if(messagesize > t->msize)
276 		messagesize = t->msize;
277 	t->msize = messagesize;	/* set downstream size */
278 	delegate(t, nil, nil);
279 }
280 
281 void
rauth(Fcall * t)282 rauth(Fcall *t)
283 {
284 	Fid *mf;
285 
286 	mf = findfid(host, t->afid, 1);
287 	if(mf == nil)
288 		return;
289 	mf->path = newpath(nil, "#auth", (Qid){0, 0, 0});	/* path name is never used */
290 	mf->opened = allocsfid();	/* newly allocated */
291 	if(delegate(t, mf, nil) == 0){
292 		mf->qid = s.rhdr.aqid;
293 		mf->mode = ORDWR;
294 	}else{
295 		freesfid(mf->opened);	/* free, don't clunk: failed to establish */
296 		mf->opened = nil;
297 		putfid(mf);
298 	}
299 }
300 
301 void
rflush(Fcall *)302 rflush(Fcall*)		/* synchronous so easy */
303 {
304 	/*TO DO: need a tag hash to find requests, once auth is asynchronous */
305 	sendreply(0);
306 }
307 
308 void
rattach(Fcall * t)309 rattach(Fcall *t)
310 {
311 	Fid *mf, *afid;
312 	SFid *sfid;
313 
314 	mf = findfid(host, t->fid, 1);
315 	if(mf == nil)
316 		return;
317 	sfid = nil;
318 	if(t->afid != NOFID){
319 		afid = findfid(host, t->afid, 0);
320 		if(afid == nil)
321 			return;
322 		sfid = afid->opened;
323 		if((afid->qid.type & QTAUTH) == 0 || sfid == nil){
324 			sendreply("bad auth file");
325 			return;
326 		}
327 	}
328 	mf->path = newpath(nil, "", (Qid){0, 0, 0});
329 	mf->path->sfid = allocsfid();	/* newly allocated */
330 	if(delegate(t, mf, sfid) == 0){
331 		mf->qid = s.rhdr.qid;
332 		mf->path->qid = mf->qid;
333 		if(statson == 1){
334 			statson++;
335 			rootqid = mf->qid;
336 		}
337 	}else{
338 		freesfid(mf->path->sfid);	/* free, don't clunk: failed to establish */
339 		mf->path->sfid = nil;
340 		putfid(mf);
341 	}
342 }
343 
344 void
rwalk(Fcall * t)345 rwalk(Fcall *t)
346 {
347 	Fid *mf, *nmf;
348 	SFid *sfid;
349 	Path *p;
350 	char *n;
351 	int i;
352 
353 	mf = findfid(host, t->fid, 0);
354 	if(mf == nil)
355 		return;
356 	if(mf->path){
357 		DPRINT(2, "walk from  %p %q + %d\n", mf, pathstr(mf->path), t->nwname);
358 	}
359 	if(mf->path->inval){
360 		sendreply(mf->path->inval);
361 		return;
362 	}
363 	nmf = nil;
364 	if(t->newfid != t->fid){
365 		nmf = findfid(host, t->newfid, 1);
366 		if(nmf == nil)
367 			return;
368 		nmf->qid = mf->qid;
369 		if(nmf->path != nil)
370 			freepath(nmf->path);
371 		mf->path->ref++;
372 		nmf->path = mf->path;
373 		mf = nmf; /* Walk mf */
374 	}
375 
376 	if(statson &&
377 	   mf->qid.type == rootqid.type && mf->qid.path == rootqid.path &&
378 	   t->nwname == 1 && strcmp(t->wname[0], "cfsctl") == 0){
379 		/* This is the ctl file */
380 		mf->qid = ctlqid;
381 		c.rhdr.nwqid = 1;
382 		c.rhdr.wqid[0] = ctlqid;
383 		sendreply(0);
384 		return;
385 	}
386 
387 	/*
388 	 * need this as an invariant, and it should always be true, because
389 	 * Twalk.fid should exist and thus have sfid. could compensate by
390 	 * rewalking from nearest parent with sfid (in the limit, root from attach)
391 	 */
392 	assert(mf->path->sfid != nil);
393 
394 	if(t->nwname == 0){
395 		/* new local fid (if any) refers to existing path, shares its sfid via that path */
396 		c.rhdr.nwqid = 0;
397 		sendreply(0);
398 		return;
399 	}
400 
401 	/* t->nwname != 0 */
402 
403 	if(localwalk(mf, &c.thdr, &c.rhdr, &p)){
404 		/* it all worked or is known to fail (in all or in part) */
405 		if(c.rhdr.type == Rerror){
406 			DPRINT(2, "walk error: %q\n", c.rhdr.ename);
407 			sendreply(c.rhdr.ename);
408 			if(nmf != nil)
409 				putfid(nmf);
410 			return;
411 		}
412 		if(c.rhdr.nwqid != t->nwname){
413 			DPRINT(2, "partial walk, hit error\n");
414 			sendreply(0);
415 			if(nmf != nil)
416 				putfid(nmf);
417 			return;
418 		}
419 		DPRINT(2, "seen it: %q %q\n", pathstr(p), p->inval);
420 		if(p->sfid != nil){
421 			p->ref++;
422 			freepath(mf->path);
423 			mf->path = p;
424 			if(c.rhdr.nwqid > 0)
425 				mf->qid = c.rhdr.wqid[c.rhdr.nwqid-1];
426 			sendreply(0);
427 			return;
428 		}
429 		/* know the path, but need a fid on the server */
430 	}
431 
432 	/* walk to a new server fid (ie, server always sees fid != newfid) */
433 	sfid = allocsfid();	/* must release it, if walk doesn't work */
434 
435 	if(delegate(t, mf, sfid) < 0){	/* complete failure */
436 		if(t->nwname > 0){	/* cache first item's failure */
437 			DPRINT(2, "bad path: %q + %q -> %q\n", pathstr(mf->path), t->wname[0], s.rhdr.ename);
438 			badpath(mf->path, t->wname[0], s.rhdr.ename);
439 		}
440 		if(nmf != nil)
441 			putfid(nmf);
442 		freesfid(sfid);	/* no need to clunk it, since it hasn't been assigned */
443 		return;
444 	}
445 
446 	if(s.rhdr.nwqid == t->nwname){	/* complete success */
447 		for(i = 0; i < t->nwname; i++){
448 			n = t->wname[i];
449 			if(strcmp(n, "..") == 0){
450 				p = mf->path->parent;
451 				if(p != nil){	/* otherwise at root, no change */
452 					p->ref++;
453 					freepath(mf->path);
454 					mf->path = p;
455 				}
456 			}else
457 				mf->path = newpath(mf->path, n, s.rhdr.wqid[i]);
458 		}
459 		mf->qid = s.rhdr.wqid[s.rhdr.nwqid-1];	/* nwname != 0 (above) */
460 		if(mf->path->sfid != nil){
461 			/* shouldn't happen (otherwise we wouldn't walk, because localwalk would find it) */
462 			sysfatal("rwalk: unexpected sfid: %q -> %ud\n", pathstr(mf->path), mf->path->sfid->fid);
463 		}
464 		mf->path->sfid = sfid;
465 		return;
466 	}
467 
468 	/* partial success; note success and failure, and release fid */
469 	p = mf->path;
470 	for(i = 0; i < s.rhdr.nwqid; i++){
471 		n = t->wname[i];
472 		if(strcmp(n, "..") == 0){
473 			if(p->parent != nil)
474 				p = p->parent;
475 		}else
476 			p = newpath(p, n, s.rhdr.wqid[i]);
477 	}
478 	n = t->wname[i];
479 	if(i == 0 || s.rhdr.wqid[i-1].type & QTDIR)
480 		badpath(p, n, Enonexist);
481 	if(nmf != nil)
482 		putfid(nmf);
483 	freesfid(sfid);
484 }
485 
486 int
localwalk(Fid * mf,Fcall * t,Fcall * r,Path ** pp)487 localwalk(Fid *mf, Fcall *t, Fcall *r, Path **pp)
488 {
489 	Path *p, *q;
490 	char *n, *err;
491 	int i;
492 
493 	*pp = nil;
494 	if(t->nwname == 0)
495 		return 0;	/* clone */
496 	if(mf->path == nil)
497 		return 0;
498 	r->type = Rwalk;
499 	r->nwqid = 0;
500 	p = mf->path;
501 	for(i = 0; i < t->nwname; i++){
502 		n = t->wname[i];
503 		if((err = p->inval) != nil)
504 			goto Err;
505 		if((p->qid.type & QTDIR) == 0){
506 			err = Enotdir;
507 			goto Err;
508 		}
509 		if(strcmp(n, "..") == 0){
510 			if((q = p->parent) == nil)
511 				q = p;
512 		}else{
513 			for(q = p->child; q != nil; q = q->next){
514 				if(strcmp(n, q->name) == 0){
515 					if((err = q->inval) != nil)
516 						goto Err;
517 					break;
518 				}
519 			}
520 			if(q == nil)
521 				return 0;	/* not found in cache, must try server */
522 		}
523 		r->wqid[r->nwqid++] = q->qid;
524 		p = q;
525 	}
526 	/* found them all: if p's not locally NOFID, link incoming fid to it as local value */
527 	*pp = p;
528 	return 1;
529 
530 Err:
531 	if(r->nwqid == 0){
532 		r->type = Rerror;
533 		r->ename = err;
534 	}
535 	return 1;
536 }
537 
538 void
ropen(Fcall * t)539 ropen(Fcall *t)
540 {
541 	Fid *mf;
542 	SFid *sfid;
543 	int omode;
544 	File *file;
545 
546 	mf = findfid(host, t->fid, 0);
547 	if(mf == nil)
548 		return;
549 	if(mf->opened != nil){
550 		sendreply(Eopened);
551 		return;
552 	}
553 	omode = openmode(t->mode);
554 	if(omode < 0){
555 		sendreply(Emode);
556 		return;
557 	}
558 	if(statson && ctltest(mf)){
559 		/* Opening ctl file */
560 		if(t->mode != OREAD){
561 			sendreply("permission denied");
562 			return;
563 		}
564 		mf->mode = OREAD;
565 		c.rhdr.qid = ctlqid;
566 		c.rhdr.iounit = 0;
567 		sendreply(0);
568 		genstats();
569 		return;
570 	}
571 	if(t->mode & (ORCLOSE|OTRUNC) || isdirect(mf->qid)){
572 		/* must have private sfid */
573 		DPRINT(2, "open dir/auth: %q\n", pathstr(mf->path));
574 		sfid = sfclone(mf->path->sfid);
575 		if(delegate(t, mf, sfid) < 0){
576 			sfclunk(sfid);
577 			return;
578 		}
579 		mf->qid = s.rhdr.qid;
580 		/* don't currently need iounit */
581 	}else if((sfid = alreadyopen(mf, omode)) == nil){
582 		sfid = sfclone(mf->path->sfid);
583 		DPRINT(2, "new open %q -> %ud\n", pathstr(mf->path), sfid->fid);
584 		if(delegate(t, mf, sfid) < 0){
585 			sfclunk(sfid);
586 			return;
587 		}
588 		if(mf->qid.type != s.rhdr.qid.type || mf->qid.path != s.rhdr.qid.path){
589 			/* file changed type or naming is volatile */
590 			print("file changed underfoot: %q %#ux %llud -> %#ux %llud\n",
591 				pathstr(mf->path), mf->qid.type, mf->qid.path, s.rhdr.qid.type, s.rhdr.qid.path);
592 			mf->path->qid = mf->qid;
593 			fileinval(mf->path);
594 		}
595 		mf->qid = s.rhdr.qid;	/* picks up vers */
596 		openfile(mf, omode, s.rhdr.iounit, sfid);
597 	}else{
598 		DPRINT(2, "cached open %q -> %ud\n", pathstr(mf->path), sfid->fid);
599 		c.rhdr.qid = mf->path->file->qid;
600 		c.rhdr.iounit = mf->path->file->iounit;
601 		sendreply(0);
602 	}
603 	mf->opened = sfid;
604 	mf->mode = omode;
605 	if(t->mode & OTRUNC && !(mf->qid.type & QTAPPEND)){
606 		file = mf->path->file;
607 		if(file != nil){
608 			cacheinval(file);	/* discard cached data */
609 			file->length = 0;
610 		}
611 	}
612 }
613 
614 void
rcreate(Fcall * t)615 rcreate(Fcall *t)
616 {
617 	Fid *mf;
618 	SFid *sfid;
619 	int omode;
620 
621 	mf = findfid(host, t->fid, 0);
622 	if(mf == nil)
623 		return;
624 	if(statson && ctltest(mf)){
625 		sendreply(Eexist);
626 		return;
627 	}
628 	omode = openmode(t->mode);
629 	if(omode < 0){
630 		sendreply(Emode);
631 		return;
632 	}
633 	/* always write-through, and by definition can't exist and be open */
634 	sfid = sfclone(mf->path->sfid);
635 	if(delegate(t, mf, sfid) == 0){
636 		mf->opened = sfid;
637 		mf->mode = omode;
638 		mf->qid = s.rhdr.qid;
639 		mf->path = newpath(mf->path, t->name, mf->qid);
640 		if(!(t->mode & ORCLOSE || isdirect(mf->qid))){
641 			/* can cache (if it's volatile, find out on subsequent open) */
642 			openfile(mf, omode, s.rhdr.iounit, sfid);
643 		}
644 		//mf->iounit = s.rhdr.iounit;
645 	}else
646 		sfclunk(sfid);
647 }
648 
649 void
rclunk(Fcall * t)650 rclunk(Fcall *t)
651 {
652 	Fid *mf;
653 
654 	mf = findfid(host, t->fid, 0);
655 	if(mf == nil)
656 		return;
657 	if(mf->opened != nil)
658 		closefile(mf, 1, 0);
659 	/* local clunk, not delegated */
660 	sendreply(0);
661 	putfid(mf);
662 }
663 
664 void
rremove(Fcall * t)665 rremove(Fcall *t)
666 {
667 	Fid *mf;
668 	Path *p;
669 	SFid *sfid;
670 	File *file;
671 
672 	mf = findfid(host, t->fid, 0);
673 	if(mf == nil)
674 		return;
675 	/* invalidate path entry; discard file; discard any local fids in use */
676 	if(statson && ctltest(mf)){
677 		sendreply("not removed");
678 		return;
679 	}
680 	file = nil;
681 	p = mf->path;
682 	if(delegate(t, mf, nil) == 0){
683 		setinval(p, Eremoved);
684 		file = p->file;
685 		p->file = nil;
686 	}
687 	/* in any case, the fid was clunked: free the sfid */
688 	if(mf->opened == nil){
689 		sfid = p->sfid;
690 		p->sfid = nil;
691 		freesfid(sfid);
692 	}else
693 		closefile(mf, 0, 1);
694 	putfid(mf);
695 	if(file != nil)
696 		putfile(file);
697 }
698 
699 void
rread(Fcall * t)700 rread(Fcall *t)
701 {
702 	Fid *mf;
703 	int cnt, done;
704 	long n;
705 	vlong off, first;
706 	char *cp;
707 	File *file;
708 	char data[MAXFDATA];
709 
710 	mf = findfid(host, t->fid, 0);
711 	if(mf == nil)
712 		return;
713 
714 	off = t->offset;
715 	cnt = t->count;
716 
717 	if(statson && ctltest(mf)){
718 		if(cnt > statlen-off)
719 			c.rhdr.count = statlen-off;
720 		else
721 			c.rhdr.count = cnt;
722 		if((int)c.rhdr.count < 0){
723 			c.rhdr.count = 0;
724 			sendreply(0);
725 			return;
726 		}
727 		c.rhdr.data = statbuf + off;
728 		sendreply(0);
729 		return;
730 	}
731 
732 	if(mf->opened == nil || mf->mode == OWRITE){
733 		sendreply("not open for reading");
734 		return;
735 	}
736 
737 	file = mf->path->file;
738 	if(isdirect(mf->qid) || file == nil){
739 		DPRINT(2, "delegating read\n");
740 		delegate(t, mf, nil);
741 		if(statson){
742 			if(mf->qid.type & QTDIR)
743 				cfsstat.ndirread++;
744 			else
745 				cfsstat.ndelegateread++;
746 			if(s.rhdr.count > 0){
747 				cfsstat.bytesread += s.rhdr.count;
748 				if(mf->qid.type & QTDIR)
749 					cfsstat.bytesfromdirs += s.rhdr.count;
750 				else
751 					cfsstat.bytesfromserver += s.rhdr.count;
752 			}
753 		}
754 		return;
755 	}
756 
757 	first = off;
758 	cp = data;
759 	done = 0;
760 	while(cnt>0 && !done){
761 		if(off >= file->clength){
762 			DPRINT(2, "offset %lld >= length %lld\n", off, file->clength);
763 			break;
764 		}
765 		n = cacheread(file, cp, off, cnt);
766 		if(n <= 0){
767 			n = -n;
768 			if(n==0 || n>cnt)
769 				n = cnt;
770 			DPRINT(2, "fetch %ld bytes of data from server at offset %lld\n", n, off);
771 			s.thdr.tag = t->tag;
772 			s.thdr.type = t->type;
773 			s.thdr.fid = t->fid;
774 			s.thdr.offset = off;
775 			s.thdr.count = n;
776 			if(statson)
777 				cfsstat.ndelegateread++;
778 			if(askserver(t, mf) < 0){
779 				sendreply(s.rhdr.ename);
780 				return;
781 			}
782 			if(s.rhdr.count != n)
783 				done = 1;
784 			n = s.rhdr.count;
785 			if(n == 0){
786 				/* end of file */
787 				if(file->clength > off){
788 					DPRINT(2, "file %llud.%ld, length %lld\n",
789 						file->qid.path,
790 						file->qid.vers, off);
791 					file->clength = off;
792 				}
793 				break;
794 			}
795 			memmove(cp, s.rhdr.data, n);
796 			cachewrite(file, cp, off, n);
797 			if(statson){
798 				cfsstat.bytestocache += n;
799 				cfsstat.bytesfromserver += n;
800 			}
801 		}else{
802 			DPRINT(2, "fetched %ld bytes from cache\n", n);
803 			if(statson)
804 				cfsstat.bytesfromcache += n;
805 		}
806 		cnt -= n;
807 		off += n;
808 		cp += n;
809 	}
810 	c.rhdr.data = data;
811 	c.rhdr.count = off - first;
812 	if(statson)
813 		cfsstat.bytesread += c.rhdr.count;
814 	sendreply(0);
815 }
816 
817 void
rwrite(Fcall * t)818 rwrite(Fcall *t)
819 {
820 	Fid *mf;
821 	File *file;
822 	u32int v1, v2, count;
823 
824 	mf = findfid(host, t->fid, 0);
825 	if(mf == nil)
826 		return;
827 	if(statson && ctltest(mf)){
828 		sendreply("read only");
829 		return;
830 	}
831 	if(mf->opened == nil || mf->mode == OREAD){
832 		sendreply("not open for writing");
833 		return;
834 	}
835 	file = mf->path->file;
836 	if(isdirect(mf->qid) || file == nil){
837 		delegate(t, mf, nil);
838 		if(statson && s.rhdr.count > 0)
839 			cfsstat.byteswritten += s.rhdr.count;
840 		return;
841 	}
842 
843 	/* add to local cache as write through */
844 	if(delegate(t, mf, nil) < 0)
845 		return;
846 
847 	count = s.rhdr.count;
848 	cfsstat.byteswritten += count;
849 
850 	v1 = mf->qid.vers + 1;
851 	v2 = mf->path->qid.vers + 1;
852 	if(v1 > v2)
853 		v1 = v2;
854 	mf->qid.vers = v1;
855 	mf->path->qid.vers = v1;
856 	file->qid.vers = v1;
857 	if(file->clength < t->offset + count)
858 		file->clength = t->offset + count;
859 	cachewrite(file, t->data, t->offset, count);
860 }
861 
862 void
rstat(Fcall * t)863 rstat(Fcall *t)
864 {
865 	Fid *mf;
866 	Dir d;
867 	uchar statbuf[256];
868 
869 	mf = findfid(host, t->fid, 0);
870 	if(mf == nil)
871 		return;
872 	if(statson && ctltest(mf)){
873 		genstats();
874 		d.qid = ctlqid;
875 		d.mode = 0444;
876 		d.length = statlen;
877 		d.name = "cfsctl";
878 		d.uid = "none";
879 		d.gid = "none";
880 		d.muid = "none";
881 		d.atime = time(nil);
882 		d.mtime = d.atime;
883 		c.rhdr.stat = statbuf;
884 		c.rhdr.nstat = convD2M(&d, statbuf, sizeof(statbuf));
885 		sendreply(0);
886 		return;
887 	}
888 	if(delegate(t, mf, nil) == 0){
889 		convM2D(s.rhdr.stat, s.rhdr.nstat , &d, nil);
890 		//mf->qid = d.qid;
891 		if(mf->path->file != nil)
892 			copystat(mf->path->file, &d, 0);
893 	}
894 }
895 
896 void
rwstat(Fcall * t)897 rwstat(Fcall *t)
898 {
899 	Fid *mf;
900 	Path *p;
901 	Dir *d;
902 	int qt;
903 
904 	mf = findfid(host, t->fid, 0);
905 	if(mf == nil)
906 		return;
907 	if(statson && ctltest(mf)){
908 		sendreply("read only");
909 		return;
910 	}
911 	if(delegate(t, mf, nil) == 0){
912 		d = malloc(sizeof(*d)+t->nstat);
913 		if(convM2D(t->stat, t->nstat, d, (char*)(d+1)) != 0){
914 			if(*d->name){	/* file renamed */
915 				p = mf->path;
916 				free(p->name);
917 				p->name = strdup(d->name);
918 				freeinval(p);
919 			}
920 			if(d->mode != ~0){
921 				qt = d->mode>>24;
922 				mf->qid.type = qt;
923 				mf->path->qid.type = qt;
924 			}
925 			if(mf->path->file != nil)
926 				copystat(mf->path->file, d, 1);
927 		}
928 		free(d);
929 	}
930 }
931 
932 int
openmode(uint o)933 openmode(uint o)
934 {
935 	uint m;
936 
937 	m = o & ~(OTRUNC|OCEXEC|ORCLOSE);
938 	if(m > OEXEC)
939 		return -1;
940 	if(m == OEXEC)
941 		m = OREAD;
942 	if(o&OTRUNC && m == OREAD)
943 		return -1;
944 	return m;
945 }
946 
947 void
error(char * fmt,...)948 error(char *fmt, ...)
949 {
950 	va_list arg;
951 	static char buf[2048];
952 
953 	va_start(arg, fmt);
954 	vseprint(buf, buf+sizeof(buf), fmt, arg);
955 	va_end(arg);
956 	fprint(2, "%s: %s\n", argv0, buf);
957 	threadexitsall("error");
958 }
959 
960 void
warning(char * s)961 warning(char *s)
962 {
963 	fprint(2, "%s: %s: %r\n", argv0, s);
964 }
965 
966 /*
967  *  send a reply to the client
968  */
969 void
sendreply(char * err)970 sendreply(char *err)
971 {
972 	if(err){
973 		c.rhdr.type = Rerror;
974 		c.rhdr.ename = err;
975 	}else{
976 		c.rhdr.type = c.thdr.type+1;
977 		c.rhdr.fid = c.thdr.fid;
978 	}
979 	c.rhdr.tag = c.thdr.tag;
980 	sendmsg(&c, &c.rhdr);
981 }
982 
983 /*
984  * local fids
985  */
986 Fid*
findfid(Host * host,u32int fid,int mk)987 findfid(Host *host, u32int fid, int mk)
988 {
989 	Fid *f, **l;
990 
991 	if(fid == NOFID){
992 		sendreply(Ebadfid);
993 		return nil;
994 	}
995 	l = &host->fids[fid & (FidHash-1)];
996 	for(f = *l; f != nil; f = f->next){
997 		if(f->fid == fid){
998 			if(mk){
999 				sendreply(Efidinuse);
1000 				return nil;
1001 			}
1002 			return f;
1003 		}
1004 	}
1005 	if(!mk){
1006 		sendreply(Ebadfid);
1007 		return nil;
1008 	}
1009 	f = mallocz(sizeof(*f), 1);
1010 	f->fid = fid;
1011 	f->next = *l;
1012 	*l = f;
1013 	return f;
1014 }
1015 
1016 void
putfid(Fid * f)1017 putfid(Fid *f)
1018 {
1019 	Fid **l;
1020 	static Qid zeroqid;
1021 
1022 	for(l = &host->fids[f->fid & (FidHash-1)]; *l != nil; l = &(*l)->next){
1023 		if(*l == f){
1024 			*l = f->next;
1025 			break;
1026 		}
1027 	}
1028 	if(f->opened != nil){
1029 		sfclunk(f->opened);
1030 		f->opened = nil;
1031 	}
1032 	freepath(f->path);
1033 	/* poison values just in case */
1034 	f->path = nil;
1035 	f->fid = NOFID;
1036 	f->qid = zeroqid;
1037 	free(f);
1038 }
1039 
1040 /*
1041  * return server fid for local fid
1042  */
1043 u32int
mapfid(Fid * f)1044 mapfid(Fid *f)
1045 {
1046 	if(f->opened != nil){
1047 		DPRINT(2, "mapfid: use open fid %ud -> %ud\n", f->fid, f->opened->fid);
1048 		return f->opened->fid;
1049 	}
1050 	if(f->path->sfid == nil)
1051 		sysfatal("mapfid: missing sfid for path %q\n", pathstr(f->path));
1052 	return f->path->sfid->fid;
1053 }
1054 
1055 /*
1056  *  send a request to the server, get the reply,
1057  * and send that to the client
1058  */
1059 int
delegate(Fcall * t,Fid * f1,SFid * f2)1060 delegate(Fcall *t, Fid *f1, SFid *f2)
1061 {
1062 	int type;
1063 
1064 	type = t->type;
1065 	if(statson){
1066 		cfsstat.sm[type].n++;
1067 		cfsstat.sm[type].s = nsec();
1068 	}
1069 
1070 	switch(type){
1071 	case Tversion:
1072 	case Tflush:	/* no fid */
1073 		break;
1074 	case Tauth:	/* afid */
1075 		t->afid = mapfid(f1);
1076 		break;
1077 	case Tattach:	/* fid, afid */
1078 		t->fid = mapfid(f1);
1079 		if(f2 != nil)
1080 			t->afid = f2->fid;
1081 		else
1082 			t->afid = NOFID;
1083 		break;
1084 	case Twalk:	/* fid, newfid */
1085 		t->fid = mapfid(f1);
1086 		t->newfid = f2->fid;
1087 		break;
1088 	default:	/* fid */
1089 		if(f2 != nil)
1090 			t->fid = f2->fid;
1091 		else
1092 			t->fid = mapfid(f1);
1093 		break;
1094 	}
1095 
1096 	sendmsg(&s, t);
1097 	rcvmsg(&s, &s.rhdr);
1098 
1099 	if(statson)
1100 		cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
1101 
1102 	sendmsg(&c, &s.rhdr);
1103 	return t->type+1 == s.rhdr.type? 0: -1;
1104 }
1105 
1106 /*
1107  *  send an i/o request to the server and get a reply
1108  */
1109 int
askserver(Fcall * t,Fid * f)1110 askserver(Fcall *t, Fid *f)
1111 {
1112 	int type;
1113 
1114 	s.thdr.tag = t->tag;
1115 
1116 	type = s.thdr.type;
1117 	if(statson){
1118 		cfsstat.sm[type].n++;
1119 		cfsstat.sm[type].s = nsec();
1120 	}
1121 
1122 	s.thdr.fid = mapfid(f);
1123 	sendmsg(&s, &s.thdr);
1124 	rcvmsg(&s, &s.rhdr);
1125 
1126 	if(statson)
1127 		cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
1128 
1129 	return s.thdr.type+1 == s.rhdr.type ? 0 : -1;
1130 }
1131 
1132 /*
1133  *  send/receive messages with logging
1134  */
1135 
1136 void
sendmsg(P9fs * p,Fcall * f)1137 sendmsg(P9fs *p, Fcall *f)
1138 {
1139 	DPRINT(2, "->%s: %F\n", p->name, f);
1140 
1141 	p->len = convS2M(f, p->sndbuf, messagesize);
1142 	if(p->len <= 0)
1143 		error("convS2M");
1144 	if(write(p->fd[1], p->sndbuf, p->len)!=p->len)
1145 		error("sendmsg");
1146 }
1147 
1148 void
rcvmsg(P9fs * p,Fcall * f)1149 rcvmsg(P9fs *p, Fcall *f)
1150 {
1151 	int rlen;
1152 	char buf[128];
1153 
1154 	p->len = read9pmsg(p->fd[0], p->rcvbuf[p->cb], sizeof(p->rcvbuf[0]));
1155 	if(p->len <= 0){
1156 		snprint(buf, sizeof buf, "read9pmsg(%d)->%ld: %r",
1157 			p->fd[0], p->len);
1158 		error(buf);
1159 	}
1160 
1161 	if((rlen = convM2S(p->rcvbuf[p->cb], p->len, f)) != p->len)
1162 		error("rcvmsg format error, expected length %d, got %d",
1163 			rlen, p->len);
1164 	DPRINT(2, "<-%s: %F\n", p->name, f);
1165 	p->cb = (p->cb+1)%nelem(p->rcvbuf);
1166 }
1167 
1168 void
dump(void * a,int len)1169 dump(void *a, int len)
1170 {
1171 	uchar *p;
1172 
1173 	p = a;
1174 	fprint(2, "%d bytes", len);
1175 	while(len-- > 0)
1176 		fprint(2, " %.2ux", *p++);
1177 	fprint(2, "\n");
1178 }
1179 
1180 /*
1181  * requests (later, unused now)
1182  */
1183 
1184 void
readtmsgproc(void * a)1185 readtmsgproc(void *a)
1186 {
1187 	//uint messagesize;
1188 	int n;
1189 	Req *r;
1190 	Channel *reqs;
1191 
1192 	reqs = a;
1193 	for(;;){
1194 		r = malloc(sizeof(*r)+messagesize);
1195 		r->msize = messagesize;
1196 		r->buf = (uchar*)(r+1);
1197 		n = read9pmsg(c.fd[0], r->buf, r->msize);
1198 		if(n <= 0){
1199 			free(r);
1200 			sendp(reqs, nil);
1201 			threadexits(nil);
1202 		}
1203 		if(convM2S(r->buf, n, &r->t) != n){
1204 			free(r);
1205 			error("convM2S error in readtmsgproc");
1206 		}
1207 		sendp(reqs, r);
1208 	}
1209 }
1210 
1211 void
readrmsgproc(void * a)1212 readrmsgproc(void *a)
1213 {
1214 	//uint messagesize;
1215 	int n;
1216 	Fcall *r;
1217 	uchar *buf;
1218 	Channel *reps;
1219 
1220 	reps = a;
1221 	for(;;){
1222 		r = malloc(sizeof(*r)+messagesize);
1223 		buf = (uchar*)(r+1);
1224 		n = read9pmsg(c.fd[0], buf, messagesize);
1225 		if(n <= 0){
1226 			free(r);
1227 			sendp(reps, nil);
1228 			threadexits(nil);
1229 		}
1230 		if(convM2S(buf, n, r) != n){
1231 			free(r);
1232 			error("convM2S error in readtmsgproc");
1233 		}
1234 		sendp(reps, r);
1235 	}
1236 }
1237 
1238 void
freereq(Req * r)1239 freereq(Req *r)
1240 {
1241 	free(r);
1242 }
1243 
1244 /*
1245  * server fids
1246 */
1247 
1248 SFid*
allocsfid(void)1249 allocsfid(void)
1250 {
1251 	SFid *sf;
1252 
1253 	sf = freefids;
1254 	if(sf != nil){
1255 		freefids = sf->next;
1256 		sf->ref = 1;
1257 		return sf;
1258 	}
1259 	sf = mallocz(sizeof(*sf), 1);
1260 	sf->ref = 1;
1261 	sf->fid = ++fidgen;
1262 	return sf;
1263 }
1264 
1265 void
freesfid(SFid * sf)1266 freesfid(SFid *sf)
1267 {
1268 	if(--sf->ref != 0)
1269 		return;
1270 	/* leave sf->fid alone */
1271 	sf->next = freefids;
1272 	freefids = sf;
1273 }
1274 
1275 SFid*
sfclone(SFid * sf)1276 sfclone(SFid *sf)
1277 {
1278 	Fcall t, r;
1279 	SFid *cf;
1280 
1281 	cf = allocsfid();
1282 	t.tag = c.thdr.tag;
1283 	t.type = Twalk;
1284 	t.fid = sf->fid;
1285 	t.newfid = cf->fid;
1286 	t.nwname = 0;
1287 	sendmsg(&s, &t);
1288 	rcvmsg(&s, &r);
1289 	if(r.type == Rerror){
1290 		werrstr("%s", r.ename);
1291 		return nil;
1292 	}
1293 	assert(r.type == Rwalk);	/* TO DO: out of order */
1294 	return cf;
1295 }
1296 
1297 Dir*
sfstat(Path * p,u32int tag)1298 sfstat(Path *p, u32int tag)
1299 {
1300 	Fcall t, r;
1301 	Dir *d;
1302 
1303 	assert(p->sfid != nil);
1304 	t.tag = tag;
1305 	t.type = Tstat;
1306 	t.fid = p->sfid->fid;
1307 	sendmsg(&s, &t);
1308 	rcvmsg(&s, &r);
1309 	if(r.type == Rerror){
1310 		werrstr("%s", r.ename);
1311 		return nil;
1312 	}
1313 	d = malloc(sizeof(*d)+r.nstat);
1314 	if(convM2D(r.stat, r.nstat, d, (char*)(d+1)) == 0){
1315 		free(d);
1316 		werrstr("invalid stat data");
1317 		return nil;
1318 	}
1319 	return d;
1320 }
1321 
1322 void
sfclunk(SFid * sf)1323 sfclunk(SFid *sf)
1324 {
1325 	Fcall t, r;
1326 
1327 	if(sf->ref > 1)
1328 		return;
1329 	t.tag = c.thdr.tag;
1330 	t.type = Tclunk;
1331 	t.fid = sf->fid;
1332 	sendmsg(&s, &t);
1333 	rcvmsg(&s, &r);
1334 	/* don't care about result */
1335 }
1336 
1337 void
printpath(Path * p,int level)1338 printpath(Path *p, int level)
1339 {
1340 	Path *q;
1341 
1342 	for(int i = 0; i < level; i++)
1343 		print("\t");
1344 	print("%q [%lud] %q\n", p->name, p->ref, p->inval?p->inval:"");
1345 	for(q = p->child; q != nil; q = q->next)
1346 		printpath(q, level+1);
1347 }
1348 
1349 int
ctltest(Fid * mf)1350 ctltest(Fid *mf)
1351 {
1352 	return mf->qid.type == ctlqid.type && mf->qid.path == ctlqid.path;
1353 }
1354 
1355 char *mname[]={
1356 	[Tversion]		"Tversion",
1357 	[Tauth]	"Tauth",
1358 	[Tflush]	"Tflush",
1359 	[Tattach]	"Tattach",
1360 	[Twalk]		"Twalk",
1361 	[Topen]		"Topen",
1362 	[Tcreate]	"Tcreate",
1363 	[Tclunk]	"Tclunk",
1364 	[Tread]		"Tread",
1365 	[Twrite]	"Twrite",
1366 	[Tremove]	"Tremove",
1367 	[Tstat]		"Tstat",
1368 	[Twstat]	"Twstat",
1369 	[Rversion]	"Rversion",
1370 	[Rauth]	"Rauth",
1371 	[Rerror]	"Rerror",
1372 	[Rflush]	"Rflush",
1373 	[Rattach]	"Rattach",
1374 	[Rwalk]		"Rwalk",
1375 	[Ropen]		"Ropen",
1376 	[Rcreate]	"Rcreate",
1377 	[Rclunk]	"Rclunk",
1378 	[Rread]		"Rread",
1379 	[Rwrite]	"Rwrite",
1380 	[Rremove]	"Rremove",
1381 	[Rstat]		"Rstat",
1382 	[Rwstat]	"Rwstat",
1383 			0,
1384 };
1385 
1386 void
genstats(void)1387 genstats(void)
1388 {
1389 	int i;
1390 	char *p;
1391 
1392 	p = statbuf;
1393 
1394 	p += snprint(p, sizeof statbuf+statbuf-p,
1395 		"        Client                          Server\n");
1396 	p += snprint(p, sizeof statbuf+statbuf-p,
1397 	    "   #calls     Δ  ms/call    Δ      #calls     Δ  ms/call    Δ\n");
1398 	for(i = 0; i < nelem(cfsstat.cm); i++)
1399 		if(cfsstat.cm[i].n || cfsstat.sm[i].n){
1400 			p += snprint(p, sizeof statbuf+statbuf-p,
1401 				"%7lud %7lud ", cfsstat.cm[i].n,
1402 				cfsstat.cm[i].n - cfsprev.cm[i].n);
1403 			if(cfsstat.cm[i].n)
1404 				p += snprint(p, sizeof statbuf+statbuf-p,
1405 					"%7.3f ", 0.000001*cfsstat.cm[i].t/
1406 					cfsstat.cm[i].n);
1407 			else
1408 				p += snprint(p, sizeof statbuf+statbuf-p,
1409 					"        ");
1410 			if(cfsstat.cm[i].n - cfsprev.cm[i].n)
1411 				p += snprint(p, sizeof statbuf+statbuf-p,
1412 					"%7.3f ", 0.000001*
1413 					(cfsstat.cm[i].t - cfsprev.cm[i].t)/
1414 					(cfsstat.cm[i].n - cfsprev.cm[i].n));
1415 			else
1416 				p += snprint(p, sizeof statbuf+statbuf-p,
1417 					"        ");
1418 			p += snprint(p, sizeof statbuf+statbuf-p,
1419 				"%7lud %7lud ", cfsstat.sm[i].n,
1420 				cfsstat.sm[i].n - cfsprev.sm[i].n);
1421 			if(cfsstat.sm[i].n)
1422 				p += snprint(p, sizeof statbuf+statbuf-p,
1423 					"%7.3f ", 0.000001*cfsstat.sm[i].t/
1424 					cfsstat.sm[i].n);
1425 			else
1426 				p += snprint(p, sizeof statbuf+statbuf-p,
1427 					"        ");
1428 			if(cfsstat.sm[i].n - cfsprev.sm[i].n)
1429 				p += snprint(p, sizeof statbuf+statbuf-p,
1430 					"%7.3f ", 0.000001*
1431 					(cfsstat.sm[i].t - cfsprev.sm[i].t)/
1432 					(cfsstat.sm[i].n - cfsprev.sm[i].n));
1433 			else
1434 				p += snprint(p, sizeof statbuf+statbuf-p,
1435 					"        ");
1436 			p += snprint(p, sizeof statbuf+statbuf-p, "%s\n",
1437 				mname[i]);
1438 		}
1439 	p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndirread\n",
1440 		cfsstat.ndirread, cfsstat.ndirread - cfsprev.ndirread);
1441 	p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelegateread\n",
1442 		cfsstat.ndelegateread, cfsstat.ndelegateread -
1443 		cfsprev.ndelegateread);
1444 	p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ninsert\n",
1445 		cfsstat.ninsert, cfsstat.ninsert - cfsprev.ninsert);
1446 	p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelete\n",
1447 		cfsstat.ndelete, cfsstat.ndelete - cfsprev.ndelete);
1448 	p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud nupdate\n",
1449 		cfsstat.nupdate, cfsstat.nupdate - cfsprev.nupdate);
1450 
1451 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesread\n",
1452 		cfsstat.bytesread, cfsstat.bytesread - cfsprev.bytesread);
1453 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud byteswritten\n",
1454 		cfsstat.byteswritten, cfsstat.byteswritten -
1455 		cfsprev.byteswritten);
1456 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromserver\n",
1457 		cfsstat.bytesfromserver, cfsstat.bytesfromserver -
1458 		cfsprev.bytesfromserver);
1459 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromdirs\n",
1460 		cfsstat.bytesfromdirs, cfsstat.bytesfromdirs -
1461 		cfsprev.bytesfromdirs);
1462 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromcache\n",
1463 		cfsstat.bytesfromcache, cfsstat.bytesfromcache -
1464 		cfsprev.bytesfromcache);
1465 	p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytestocache\n",
1466 		cfsstat.bytestocache, cfsstat.bytestocache -
1467 		cfsprev.bytestocache);
1468 	statlen = p - statbuf;
1469 	cfsprev = cfsstat;
1470 }
1471 
1472 /*
1473  * paths
1474  */
1475 
1476 Path*
newpath(Path * parent,char * name,Qid qid)1477 newpath(Path *parent, char *name, Qid qid)
1478 {
1479 	Path *p;
1480 
1481 	if(parent != nil){
1482 		for(p = parent->child; p != nil; p = p->next){
1483 			if(strcmp(p->name, name) == 0){
1484 				if(p->inval != nil){
1485 					free(p->inval);
1486 					p->inval = nil;
1487 				}
1488 				p->qid = qid;
1489 				p->ref++;
1490 				return p;
1491 			}
1492 		}
1493 	}
1494 	p = mallocz(sizeof(*p), 1);
1495 	p->ref = 2;
1496 	if(name != nil)
1497 		p->name = strdup(name);
1498 	p->qid = qid;
1499 	p->parent = parent;
1500 	if(parent != nil){
1501 		parent->ref++;
1502 		p->next = parent->child;
1503 		parent->child = p;
1504 	}
1505 	return p;
1506 }
1507 
1508 void
freeinval(Path * p)1509 freeinval(Path *p)
1510 {
1511 	Path *q, **r;
1512 
1513 	for(r = &p->parent->child; (q = *r) != nil; r = &q->next){
1514 		if(q == p)
1515 			continue;
1516 		if(strcmp(q->name, p->name) == 0 && q->inval != nil){
1517 			if(q->ref > 1){
1518 				*r = q->next;
1519 				q->next = p->next;
1520 				p->next = q;
1521 			}
1522 			freepath(q);
1523 			break;
1524 		}
1525 	}
1526 }
1527 
1528 void
setinval(Path * p,char * err)1529 setinval(Path *p, char *err)
1530 {
1531 	if(p->inval != nil){
1532 		free(p->inval);
1533 		p->inval = nil;
1534 	}
1535 	if(err != nil)
1536 		p->inval = strdup(err);
1537 }
1538 
1539 void
badpath(Path * parent,char * name,char * err)1540 badpath(Path *parent, char *name, char *err)
1541 {
1542 	Path *p;
1543 
1544 	for(p = parent->child; p != nil; p = p->next){
1545 		if(strcmp(p->name, name) == 0){
1546 			setinval(p, err);
1547 			return;
1548 		}
1549 	}
1550 	p = mallocz(sizeof(*p), 1);
1551 	p->ref = 2;
1552 	if(name != nil)
1553 		p->name = strdup(name);
1554 	p->inval = strdup(err);
1555 	p->parent = parent;
1556 	if(parent != nil){
1557 		parent->ref++;
1558 		p->next = parent->child;
1559 		parent->child = p;
1560 	}
1561 }
1562 
1563 void
fileinval(Path * p)1564 fileinval(Path *p)
1565 {
1566 	if(p->file != nil){
1567 		putfile(p->file);
1568 		p->file = nil;
1569 	}
1570 }
1571 
1572 void
freepath(Path * p)1573 freepath(Path *p)
1574 {
1575 	Path *q, **r;
1576 
1577 	while(p != nil && --p->ref == 0){
1578 		if(p->child != nil)
1579 			error("freepath child");
1580 		q = p->parent;
1581 		if(q != nil){
1582 			for(r = &q->child; *r != nil; r = &(*r)->next){
1583 				if(*r == p){
1584 					*r = p->next;
1585 					break;
1586 				}
1587 			}
1588 		}
1589 		if(p->sfid != nil){
1590 			/* TO DO: could queue these for a great clunking proc */
1591 			sfclunk(p->sfid);
1592 			p->sfid = nil;
1593 		}
1594 		if(p->inval != nil)
1595 			free(p->inval);
1596 		if(p->file != nil)
1597 			putfile(p->file);
1598 		free(p->name);
1599 		free(p);
1600 		p = q;
1601 	}
1602 }
1603 
1604 static char*
pathstr1(Path * p,char * ep)1605 pathstr1(Path *p, char *ep)
1606 {
1607 	ep -= strlen(p->name);
1608 	memmove(ep, p->name, strlen(p->name));
1609 	if(p->parent != nil){
1610 		*--ep = '/';
1611 		ep = pathstr1(p->parent, ep);
1612 	}
1613 	return ep;
1614 }
1615 
1616 char*
pathstr(Path * p)1617 pathstr(Path *p)
1618 {
1619 	static char buf[1000];
1620 	return pathstr1(p, buf+sizeof(buf)-1);
1621 }
1622 
1623 /*
1624  * files
1625  */
1626 
1627 void
openfile(Fid * mf,int omode,u32int iounit,SFid * sfid)1628 openfile(Fid *mf, int omode, u32int iounit, SFid *sfid)
1629 {
1630 	/* open mf and cache open File at p */
1631 	Path *p;
1632 	File *file;
1633 	SFid *osfid;
1634 
1635 	p = mf->path;
1636 	file = p->file;
1637 	if(file == nil){
1638 		file = mallocz(sizeof(*file), 1);
1639 		file->ref = 1;
1640 		file->qid = mf->qid;	/* TO DO: check for clone files */
1641 		file->clength = MAXLEN;
1642 		p->file = file;
1643 	}
1644 	osfid = file->open[omode];
1645 	if(osfid != nil){
1646 		DPRINT(2, "openfile: existing sfid %ud open %d\n", osfid->fid, omode);
1647 		return;
1648 	}
1649 	DPRINT(2, "openfile: cached %ud for %q mode %d\n", sfid->fid, pathstr(p), omode);
1650 	sfid->ref++;
1651 	file->open[omode] = sfid;
1652 	if(file->iounit == 0)
1653 		file->iounit = iounit;	/* BUG: might vary */
1654 }
1655 
1656 void
closefile(Fid * mf,int mustclunk,int removed)1657 closefile(Fid *mf, int mustclunk, int removed)
1658 {
1659 	Path *p;
1660 	File *file;
1661 	SFid *sfid, *osfid;
1662 
1663 	if((sfid = mf->opened) == nil)
1664 		return;
1665 	p = mf->path;
1666 	file = p->file;
1667 	if(file == nil){	/* TO DO: messy */
1668 		mf->opened = nil;
1669 		if(sfid->ref == 1 && mustclunk)
1670 			sfclunk(sfid);
1671 		freesfid(sfid);
1672 		return;
1673 	}
1674 	osfid = file->open[mf->mode];
1675 	if(osfid == sfid){
1676 		if(removed || sfid->ref == 1)
1677 			file->open[mf->mode] = nil;
1678 		if(sfid->ref == 1){
1679 			if(mustclunk)
1680 				sfclunk(sfid);
1681 			freesfid(sfid);
1682 		}else
1683 			sfid->ref--;
1684 	}
1685 	mf->opened = nil;
1686 }
1687 
1688 SFid*
alreadyopen(Fid * mf,uint mode)1689 alreadyopen(Fid *mf, uint mode)
1690 {
1691 	File *file;
1692 	SFid *sfid;
1693 
1694 	file = mf->path->file;
1695 	if(file == nil)
1696 		return nil;
1697 	sfid = file->open[mode&3];
1698 	if(sfid == nil)
1699 		return nil;
1700 	DPRINT(2, "openfile: existing sfid %ud open %d\n", sfid->fid, mode&3);
1701 	sfid->ref++;
1702 	return sfid;
1703 }
1704 
1705 void
copystat(File * file,Dir * d,int iswstat)1706 copystat(File *file, Dir *d, int iswstat)
1707 {
1708 	if(d->length != ~(vlong)0){
1709 		/* length change: discard cached data */
1710 		if(iswstat && file->length < file->clength)
1711 			cacheinval(file);
1712 		file->length = d->length;
1713 	}
1714 	if(d->mode != ~0){
1715 		file->mode = d->mode;
1716 		file->qid.type = d->mode>>24;
1717 	}
1718 	if(d->atime != ~0)
1719 		file->atime = d->atime;
1720 	if(d->mtime != ~0)
1721 		file->mtime = d->mtime;
1722 	if(*d->uid){
1723 		freestr(file->uid);
1724 		file->uid = newstr(d->uid);
1725 	}
1726 	if(*d->gid){
1727 		freestr(file->gid);
1728 		file->gid = newstr(d->gid);
1729 	}
1730 	if(*d->muid){
1731 		freestr(file->muid);
1732 		file->muid = newstr(d->muid);
1733 	}
1734 }
1735 
1736 void
putfile(File * f)1737 putfile(File *f)
1738 {
1739 	int i;
1740 	SFid *sfid;
1741 
1742 	if(--f->ref != 0)
1743 		return;
1744 	for(i = 0; i < nelem(f->open); i++){
1745 		sfid = f->open[i];
1746 		if(sfid != nil){
1747 			f->open[i] = nil;
1748 			sfclunk(sfid);
1749 			freesfid(sfid);
1750 		}
1751 	}
1752 	freestr(f->uid);
1753 	freestr(f->gid);
1754 	freestr(f->muid);
1755 	cacheinval(f);
1756 	free(f->cached);
1757 	free(f);
1758 }
1759 
1760 /*
1761  * data
1762  */
1763 
1764 static	int	radix[] = {10, 12, 14};
1765 static	uint	range[] = {8, 32, 0};
1766 static	uint	cacheused;
1767 
1768 void
datainit(void)1769 datainit(void)
1770 {
1771 	datalist.forw = datalist.back = &datalist;
1772 }
1773 
1774 Data*
allocdata(File * file,uint n,uint nbytes)1775 allocdata(File *file, uint n, uint nbytes)
1776 {
1777 	Data *d;
1778 
1779 	while(cacheused+nbytes > cachesize && datalist.forw != datalist.back)
1780 		freedata(datalist.forw);
1781 	cacheused += nbytes;
1782 	d = mallocz(sizeof(*d), 0);
1783 	d->owner = file;
1784 	d->n = n;
1785 	d->base = malloc(nbytes);
1786 	d->size = nbytes;
1787 	d->min = 0;
1788 	d->max = 0;
1789 	d->forw = &datalist;
1790 	d->back = datalist.back;
1791 	d->back->forw = d;
1792 	datalist.back = d;
1793 	return d;
1794 }
1795 
1796 void
freedata(Data * d)1797 freedata(Data *d)
1798 {
1799 	d->forw->back = d->back;
1800 	d->back->forw = d->forw;
1801 	cacheused -= d->size;
1802 	if(d->owner != nil)
1803 		d->owner->cached[d->n] = nil;
1804 	free(d->base);
1805 	free(d);
1806 }
1807 
1808 /*
1809  * move recently-used data to end
1810  */
1811 void
usedata(Data * d)1812 usedata(Data *d)
1813 {
1814 	if(datalist.back == d)
1815 		return;	/* already at end */
1816 
1817 	d->forw->back = d->back;
1818 	d->back->forw = d->forw;
1819 
1820 	d->forw = &datalist;
1821 	d->back = datalist.back;
1822 	d->back->forw = d;
1823 	datalist.back = d;
1824 }
1825 
1826 /*
1827  * data cache
1828  */
1829 
1830 int
cacheread(File * file,void * buf,vlong offset,int nbytes)1831 cacheread(File *file, void *buf, vlong offset, int nbytes)
1832 {
1833 	char *p;
1834 	Data *d;
1835 	int n, o;
1836 
1837 	DPRINT(2, "file %lld length %lld\n", file->qid.path, file->clength);
1838 	p = buf;
1839 	while(nbytes > 0){
1840 		d = finddata(file, offset, &o);
1841 		if(d == nil)
1842 			break;
1843 		if(o < d->min){
1844 			if(p == (char*)buf)
1845 				return -(d->min-o);	/* fill the gap */
1846 			break;
1847 		}else if(o >= d->max)
1848 			break;
1849 		usedata(d);
1850 		/* o >= d->min && o < d->max */
1851 		n = nbytes;
1852 		if(n > d->max-o)
1853 			n = d->max-o;
1854 		memmove(p, d->base+o, n);
1855 		p += n;
1856 		nbytes -= n;
1857 		offset += n;
1858 	}
1859 	return p-(char*)buf;
1860 }
1861 
1862 void
cachewrite(File * file,void * buf,vlong offset,int nbytes)1863 cachewrite(File *file, void *buf, vlong offset, int nbytes)
1864 {
1865 	char *p;
1866 	Data *d;
1867 	int n, o;
1868 
1869 	p = buf;
1870 	while(nbytes > 0){
1871 		d = storedata(file, offset, &o);
1872 		if(d == nil)
1873 			break;
1874 		n = nbytes;
1875 		if(n > d->size-o)
1876 			n = d->size-o;
1877 		cachemerge(d, p, o, n);
1878 		p += n;
1879 		offset += n;
1880 		nbytes -= n;
1881 	}
1882 	if(offset > file->clength)
1883 		file->clength = offset;
1884 }
1885 
1886 /*
1887  * merge data in if it overlaps existing contents,
1888  * or simply replace existing contents otherwise
1889  */
1890 void
cachemerge(Data * p,char * from,int start,int len)1891 cachemerge(Data *p, char *from, int start, int len)
1892 {
1893 	int end;
1894 
1895 	end = start + len;
1896 	memmove(p->base+start, from, len);
1897 
1898 	if(start > p->max || p->min > end){
1899 		p->min = start;
1900 		p->max = end;
1901 	}else{
1902 		if(start < p->min)
1903 			p->min = start;
1904 		if(end > p->max)
1905 			p->max = end;
1906 	}
1907 }
1908 
1909 void
cacheinval(File * file)1910 cacheinval(File *file)
1911 {
1912 	Data *d;
1913 	int i;
1914 
1915 	if(file->cached != nil){
1916 		for(i = 0; i < file->ndata; i++){
1917 			d = file->cached[i];
1918 			if(d != nil){
1919 				file->cached[i] = nil;
1920 				d->owner = nil;
1921 				freedata(d);
1922 			}
1923 		}
1924 		/* leave the array */
1925 	}
1926 	file->clength = 0;
1927 }
1928 
1929 Data*
finddata(File * file,uvlong offset,int * blkoff)1930 finddata(File *file, uvlong offset, int *blkoff)
1931 {
1932 	int r, x;
1933 	uvlong base, o;
1934 
1935 	x = 0;
1936 	base = 0;
1937 	for(r = 0; r < nelem(radix); r++){
1938 		o = (offset - base) >> radix[r];
1939 		DPRINT(2, "file %llud offset %llud x %d base %llud o %llud\n", file->qid.path, offset, x, base, o);
1940 		if(range[r] == 0 || o < range[r]){
1941 			o += x;
1942 			if(o >= file->ndata)
1943 				break;
1944 			*blkoff = (offset-base) & ((1<<radix[r])-1);
1945 			return file->cached[(int)o];
1946 		}
1947 		base += range[r]<<radix[r];
1948 		x += range[r];
1949 	}
1950 	return nil;
1951 }
1952 
1953 Data*
storedata(File * file,uvlong offset,int * blkoff)1954 storedata(File *file, uvlong offset, int *blkoff)
1955 {
1956 	int r, x, v, size;
1957 	uvlong base, o;
1958 	Data **p;
1959 
1960 	if(file->cached == nil){
1961 		file->cached = mallocz(16*sizeof(*file->cached), 1);
1962 		file->ndata = 16;
1963 	}
1964 	x = 0;
1965 	base = 0;
1966 	for(r = 0; r < nelem(radix); r++){
1967 		o = (offset - base) >> radix[r];
1968 		DPRINT(2, "store file %llud offset %llud x %d base %llud o %llud\n", file->qid.path, offset, x, base, o);
1969 		if(range[r] == 0 || o < range[r]){
1970 			o += x;
1971 			if(o >= file->ndata){
1972 				if(o >= 512)
1973 					return nil;	/* won't fit */
1974 				v = (o+32+31)&~31;
1975 				file->cached = realloc(file->cached, v*sizeof(*file->cached));
1976 				memset(file->cached+file->ndata, 0, (v-file->ndata)*sizeof(*file->cached));
1977 				file->ndata = v;
1978 			}
1979 			size = 1 << radix[r];
1980 			DPRINT(2, "	-> %d %d\n", (int)o, size);
1981 			*blkoff = (offset-base) & (size-1);
1982 			p = &file->cached[(int)o];
1983 			if(*p == nil)
1984 				*p = allocdata(file, (int)o, size);
1985 			else
1986 				usedata(*p);
1987 			return *p;
1988 		}
1989 		base += range[r]<<radix[r];
1990 		x += range[r];
1991 	}
1992 	return nil;
1993 }
1994 
1995 /*
1996  * Strings
1997  */
1998 
1999 enum{
2000 	Strhashmask=	(1<<8)-1,
2001 };
2002 
2003 static struct{
2004 	QLock;
2005 	String*	htab[Strhashmask+1];
2006 } stralloc;
2007 
2008 String**
hashslot(char * s)2009 hashslot(char *s)
2010 {
2011 	uint h, g;
2012 	uchar *p;
2013 
2014 	h = 0;
2015 	for(p = (uchar*)s; *p != 0; p++){
2016 		h = (h<<4) + *p;
2017 		g = h & (0xF<<28);
2018 		if(g != 0)
2019 			h ^= ((g>>24) & 0xFF) | g;
2020 	}
2021 	return &stralloc.htab[h & Strhashmask];
2022 }
2023 
2024 String*
newstr(char * val)2025 newstr(char *val)
2026 {
2027 	String *s, **l;
2028 
2029 	//qlock(&stralloc);
2030 	for(l = hashslot(val); (s = *l) != nil; l = &s->next){
2031 		if(strcmp(s->s, val) == 0){
2032 			s->ref++;
2033 			//qunlock(&stralloc);
2034 			return s;
2035 		}
2036 	}
2037 	s = malloc(sizeof(*s));
2038 	s->s = strdup(val);
2039 	s->len = strlen(s->s);
2040 	s->ref = 1;
2041 	s->next = *l;
2042 	*l = s;
2043 	//qunlock(&stralloc);
2044 	return s;
2045 }
2046 
2047 String*
dupstr(String * s)2048 dupstr(String *s)
2049 {
2050 	s->ref++;
2051 	return s;
2052 }
2053 
2054 void
freestr(String * s)2055 freestr(String *s)
2056 {
2057 	String **l;
2058 
2059 	if(s != nil && --s->ref == 0){
2060 		//qlock(&stralloc);
2061 		for(l = hashslot(s->s); *l != nil; l = &(*l)->next){
2062 			if(*l == s){
2063 				*l = s->next;
2064 				break;
2065 			}
2066 		}
2067 		//qunlock(&stralloc);
2068 		free(s->s);
2069 		free(s);
2070 	}
2071 }
2072