xref: /plan9/sys/src/cmd/cfs/cfs.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 
6 #include "cformat.h"
7 #include "lru.h"
8 #include "bcache.h"
9 #include "disk.h"
10 #include "inode.h"
11 #include "file.h"
12 
13 enum
14 {
15 	Nfid=		1024,
16 };
17 
18 
19 typedef struct Mfile Mfile;
20 typedef struct Ram Ram;
21 typedef struct P9fs P9fs;
22 
23 struct Mfile
24 {
25 	Qid	qid;
26 	short	oldfid;
27 	char	needclone;
28 	char	busy;
29 };
30 
31 Mfile	mfile[Nfid];
32 char	user[NAMELEN];
33 Icache	ic;
34 int	debug;
35 
36 struct P9fs
37 {
38 	int	fd[2];
39 	Fcall	rhdr;
40 	Fcall	thdr;
41 	long	len;
42 	char	*name;
43 };
44 
45 P9fs	c;	/* client conversation */
46 P9fs	s;	/* server conversation */
47 
48 char	datasnd[MAXFDATA + MAXMSG];
49 char	datarcv[MAXFDATA + MAXMSG];
50 
51 void	rsession(void);
52 void	rflush(void);
53 void	rattach(Mfile*);
54 void	rclone(Mfile*);
55 void	rwalk(Mfile*);
56 void	rclwalk(Mfile*);
57 void	ropen(Mfile*);
58 void	rcreate(Mfile*);
59 void	rread(Mfile*);
60 void	rwrite(Mfile*);
61 void	rclunk(Mfile*);
62 void	rremove(Mfile*);
63 void	rstat(Mfile*);
64 void	rwstat(Mfile*);
65 void	error(char*);
66 void	warning(char*);
67 void	mountinit(char*, char*);
68 void	io(void);
69 void	sendreply(char*);
70 void	sendmsg(P9fs*, Fcall*);
71 void	rcvmsg(P9fs*, Fcall*);
72 int	delegate(void);
73 int	askserver(void);
74 void	cachesetup(int, char*);
75 int	doclone(Mfile*);
76 void	doclwalk(Mfile*, char*);
77 
78 #define PREFACE(m) if(doclone(m) < 0) return
79 
80 char *mname[]={
81 	[Tnop]		"Tnop",
82 	[Tsession]	"Tsession",
83 	[Tflush]	"Tflush",
84 	[Tattach]	"Tattach",
85 	[Tclone]	"Tclone",
86 	[Twalk]		"Twalk",
87 	[Topen]		"Topen",
88 	[Tcreate]	"Tcreate",
89 	[Tclunk]	"Tclunk",
90 	[Tread]		"Tread",
91 	[Twrite]	"Twrite",
92 	[Tremove]	"Tremove",
93 	[Tstat]		"Tstat",
94 	[Twstat]	"Twstat",
95 	[Tclwalk]	"Tclwalk",
96 	[Rnop]		"Rnop",
97 	[Rsession]	"Rsession",
98 	[Rerror]	"Rerror",
99 	[Rflush]	"Rflush",
100 	[Rattach]	"Rattach",
101 	[Rclone]	"Rclone",
102 	[Rwalk]		"Rwalk",
103 	[Ropen]		"Ropen",
104 	[Rcreate]	"Rcreate",
105 	[Rclunk]	"Rclunk",
106 	[Rread]		"Rread",
107 	[Rwrite]	"Rwrite",
108 	[Rremove]	"Rremove",
109 	[Rstat]		"Rstat",
110 	[Rwstat]	"Rwstat",
111 	[Rclwalk]	"Rclwalk",
112 	[Rauth]		"Rauth",
113 			0,
114 };
115 
116 void
117 usage(void)
118 {
119 	fprint(2, "usage:\tcfs -s [-rd] [-f partition]");
120 	fprint(2, "\tcfs [-rd] [-f partition] [-a netaddr] [mt-pt]\n");
121 }
122 
123 void
124 main(int argc, char *argv[])
125 {
126 	int std;
127 	int format;
128 	char *part;
129 	char *server;
130 	char *mtpt;
131 
132 	std = 0;
133 	format = 0;
134 	part = "/dev/hd0cache";
135 	server = "dk!bootes";
136 	mtpt = "/tmp";
137 
138 	ARGBEGIN{
139 	case 'a':
140 		server = ARGF();
141 		if(server == 0)
142 			usage();
143 		break;
144 	case 's':
145 		std = 1;
146 		break;
147 	case 'r':
148 		format = 1;
149 		break;
150 	case 'f':
151 		part = ARGF();
152 		if(part == 0)
153 			usage();
154 		break;
155 	case 'd':
156 		debug = 1;
157 		break;
158 	default:
159 		usage();
160 	}ARGEND
161 	if(argc && *argv)
162 		mtpt = *argv;
163 
164 	cachesetup(format, part);
165 
166 	c.name = "client";
167 	s.name = "server";
168 	if(std){
169 		c.fd[0] = c.fd[1] = 1;
170 		s.fd[0] = s.fd[1] = 0;
171 	}else
172 		mountinit(server, mtpt);
173 
174 	switch(fork()){
175 	case 0:
176 		io();
177 		exits("");
178 	case -1:
179 		error("fork");
180 	default:
181 		exits("");
182 	}
183 }
184 
185 void
186 cachesetup(int format, char *partition)
187 {
188 	int f;
189 	int secsize;
190 	int inodes;
191 	int blocksize;
192 
193 	secsize = 512;
194 	inodes = 1024;
195 	blocksize = 4*1024;
196 
197 	f = open(partition, ORDWR);
198 	if(f < 0)
199 		error("opening partition");
200 
201 	if(format || iinit(&ic, f, secsize)<0){
202 		if(iformat(&ic, f, inodes, "bootes", blocksize, secsize) < 0)
203 			error("formatting failed");
204 	}
205 }
206 
207 void
208 mountinit(char *server, char *mountpoint)
209 {
210 	int p[2];
211 
212 	/*
213 	 *  grab a channel and call up the file server
214 	 */
215 	s.fd[0] = s.fd[1] = dial(netmkaddr(server, 0, 0), 0, 0, 0);
216 	if(s.fd[0] < 0)
217 		error("opening data");
218 
219 	/*
220  	 *  mount onto name space
221 	 */
222 	if(pipe(p) < 0)
223 		error("pipe failed");
224 	switch(fork()){
225 	case 0:
226 		break;
227 	default:
228 		if(amount(p[1], mountpoint, MREPL|MCREATE, "") < 0)
229 			error("mount failed");
230 		exits(0);
231 	case -1:
232 		error("fork failed\n");
233 /*BUG: no wait!*/
234 	}
235 	c.fd[0] = c.fd[1] = p[0];
236 }
237 
238 void
239 io(void)
240 {
241 	Mfile *mf;
242     loop:
243 	rcvmsg(&c, &c.thdr);
244 	mf = &mfile[c.thdr.fid];
245 	switch(c.thdr.type){
246 	default:
247 		error("type");
248 		break;
249 	case Tsession:
250 		rsession();
251 		break;
252 	case Tnop:
253 		rflush();
254 		break;
255 	case Tflush:
256 		rflush();
257 		break;
258 	case Tattach:
259 		rattach(mf);
260 		break;
261 	case Tclone:
262 		rclone(mf);
263 		break;
264 	case Twalk:
265 		rwalk(mf);
266 		break;
267 	case Topen:
268 		ropen(mf);
269 		break;
270 	case Tcreate:
271 		rcreate(mf);
272 		break;
273 	case Tread:
274 		rread(mf);
275 		break;
276 	case Twrite:
277 		rwrite(mf);
278 		break;
279 	case Tclunk:
280 		rclunk(mf);
281 		break;
282 	case Tremove:
283 		rremove(mf);
284 		break;
285 	case Tstat:
286 		rstat(mf);
287 		break;
288 	case Twstat:
289 		rwstat(mf);
290 		break;
291 	}
292 	goto loop;
293 }
294 
295 void
296 rsession(void)
297 {
298 	delegate();
299 }
300 
301 void
302 rflush(void)		/* synchronous so easy */
303 {
304 	sendreply(0);
305 }
306 
307 void
308 rattach(Mfile *mf)
309 {
310 	if(delegate() == 0){
311 		mf->qid = s.rhdr.qid;
312 		mf->busy = 1;
313 		mf->needclone = 0;
314 	}
315 }
316 
317 /*
318  *  check consistency and perform a delayed clone
319  */
320 int
321 doclone(Mfile *mf)
322 {
323 	Mfile *omf;
324 
325 	if(!mf->busy)
326 		error("bad fid");
327 	if(!mf->needclone)
328 		return 0;
329 	omf = &mfile[mf->oldfid];
330 	if(!omf->busy)
331 		error("bad old fid");
332 
333 	s.thdr.type = Tclone;
334 	s.thdr.fid = mf->oldfid;
335 	s.thdr.newfid = mf - mfile;
336 	mf->needclone = 0;
337 	if(askserver() == 0)
338 		return 0;
339 	sendreply(s.rhdr.ename);
340 	return -1;
341 }
342 
343 /*
344  *  don't send clone to server, just reply to client
345  */
346 void
347 rclone(Mfile *mf)
348 {
349 	Mfile *nmf;
350 
351 	PREFACE(mf);
352 	if(c.thdr.newfid<0 || Nfid<=c.thdr.newfid)
353 		error("clone nfid out of range");
354 	nmf = &mfile[c.thdr.newfid];
355 	if(nmf->busy)
356 		error("clone to used channel");
357 	nmf = &mfile[c.thdr.newfid];
358 	nmf->qid = mf->qid;
359 	nmf->needclone = 1;
360 	nmf->oldfid = mf - mfile;
361 	nmf->busy = 1;
362 	sendreply(0);
363 }
364 
365 /*
366  *  do a combined clone and walk. An error implies a clunk.  A reply with
367  *  the wrong fid implies a "directory entry not found".
368  */
369 void
370 doclwalk(Mfile *mf, char *name)
371 {
372 	s.thdr.type = Tclwalk;
373 	s.thdr.fid = mf->oldfid;
374 	s.thdr.newfid = mf - mfile;
375 	memmove(s.thdr.name, name, sizeof s.thdr.name);
376 	if(askserver() == 0){
377 		if(s.rhdr.fid == s.thdr.fid){
378 			/*
379 			 *  this is really a short form of
380 			 *	Terror "directory entry not found"
381 			 */
382 			mf->busy = 0;
383 			sendreply("directory entry not found");
384 			return;
385 		}
386 		mf->qid = s.rhdr.qid;
387 		c.rhdr.qid = s.rhdr.qid;
388 		mf->needclone = 0;
389 		sendreply(0);
390 	} else {
391 		mf->busy = 0;
392 		sendreply(s.rhdr.ename);
393 	}
394 }
395 
396 void
397 rwalk(Mfile *mf)
398 {
399 	if(mf->needclone){
400 		doclwalk(mf, c.thdr.name);
401 		return;
402 	}
403 	if(delegate() == 0)
404 		mf->qid = s.rhdr.qid;
405 }
406 
407 void
408 rclwalk(Mfile *mf)
409 {
410 	if(delegate() == 0)
411 		mf->qid = s.rhdr.qid;
412 }
413 
414 void
415 ropen(Mfile *mf)
416 {
417 	PREFACE(mf);
418 	if(delegate() == 0){
419 		mf->qid = s.rhdr.qid;
420 		if(c.thdr.mode & OTRUNC){
421 			mf->qid.vers++;
422 			iget(&ic, mf->qid);
423 		}
424 	}
425 }
426 
427 void
428 rcreate(Mfile *mf)
429 {
430 	PREFACE(mf);
431 	if(delegate() == 0){
432 		mf->qid = s.rhdr.qid;
433 		mf->qid.vers++;
434 	}
435 }
436 
437 void
438 rclunk(Mfile *mf)
439 {
440 	if(!mf->busy){
441 		sendreply(0);
442 		return;
443 	}
444 	mf->busy = 0;
445 	mf->needclone = 0;
446 	delegate();
447 }
448 
449 void
450 rremove(Mfile *mf)
451 {
452 	PREFACE(mf);
453 	mf->busy = 0;
454 	delegate();
455 }
456 
457 void
458 rread(Mfile *mf)
459 {
460 	int cnt;
461 	long off, first;
462 	char *cp;
463 	Ibuf *b;
464 	long n;
465 	char data[MAXFDATA];
466 	int done;
467 
468 	PREFACE(mf);
469 	first = off = c.thdr.offset;
470 	cnt = c.thdr.count;
471 
472 	if(mf->qid.path & CHDIR){
473 		delegate();
474 		return;
475 	}
476 
477 	b = iget(&ic, mf->qid);
478 	if(b == 0){
479 		delegate();
480 		return;
481 	}
482 
483 	cp = data;
484 	done = 0;
485 	while(cnt>0 && !done){
486 		n = fread(&ic, b, cp, off, cnt);
487 		if(n <= 0){
488 			n = -n;
489 			if(n==0 || n>cnt)
490 				n = cnt;
491 			s.thdr.type = c.thdr.type;
492 			s.thdr.fid = c.thdr.fid;
493 			s.thdr.tag = c.thdr.tag;
494 			s.thdr.offset = off;
495 			s.thdr.count = n;
496 			if(askserver() < 0)
497 				sendreply(s.rhdr.ename);
498 			if(s.rhdr.count != n)
499 				done = 1;
500 			n = s.rhdr.count;
501 			memmove(cp, s.rhdr.data, n);
502 			fwrite(&ic, b, cp, off, n);
503 		}
504 		cnt -= n;
505 		off += n;
506 		cp += n;
507 	}
508 	c.rhdr.data = data;
509 	c.rhdr.count = off - first;
510 	sendreply(0);
511 }
512 
513 void
514 rwrite(Mfile *mf)
515 {
516 	Ibuf *b;
517 	char buf[MAXFDATA];
518 
519 	PREFACE(mf);
520 	if(mf->qid.path & CHDIR){
521 		delegate();
522 		return;
523 	}
524 
525 	memmove(buf, c.thdr.data, c.thdr.count);
526 	if(delegate() < 0)
527 		return;
528 
529 	b = iget(&ic, mf->qid);
530 	if(b == 0)
531 		return;
532 	mf->qid.vers++;
533 	if(fwrite(&ic, b, buf, c.thdr.offset, c.thdr.count) == c.thdr.count)
534 		iinc(&ic, b);
535 }
536 
537 void
538 rstat(Mfile *mf)
539 {
540 	PREFACE(mf);
541 	delegate();
542 }
543 
544 void
545 rwstat(Mfile *mf)
546 {
547 	PREFACE(mf);
548 	delegate();
549 }
550 
551 void
552 error(char *s)
553 {
554 	fprint(2, "cfs: %s: ", s);
555 	perror("");
556 	exits(s);
557 }
558 
559 void
560 warning(char *s)
561 {
562 	char buf[ERRLEN];
563 
564 	errstr(buf);
565 	fprint(2, "cfs: %s: %s\n", s, buf);
566 	if(strstr(buf, "illegal network address"))
567 		exits("death");
568 }
569 
570 /*
571  *  send a reply to the client
572  */
573 void
574 sendreply(char *err)
575 {
576 
577 	if(err){
578 		c.rhdr.type = Rerror;
579 		strncpy(c.rhdr.ename, err, ERRLEN);
580 	}else{
581 		c.rhdr.type = c.thdr.type+1;
582 		c.rhdr.fid = c.thdr.fid;
583 	}
584 	c.rhdr.tag = c.thdr.tag;
585 	sendmsg(&c, &c.rhdr);
586 }
587 
588 /*
589  *  send a request to the server, get the reply, and send that to
590  *  the client
591  */
592 int
593 delegate(void)
594 {
595 	sendmsg(&s, &c.thdr);
596 	rcvmsg(&s, &s.rhdr);
597 	sendmsg(&c, &s.rhdr);
598 	return c.thdr.type+1 == s.rhdr.type ? 0 : -1;
599 }
600 
601 /*
602  *  send a request to the server and get a reply
603  */
604 int
605 askserver(void)
606 {
607 	s.thdr.tag = c.thdr.tag;
608 	sendmsg(&s, &s.thdr);
609 	rcvmsg(&s, &s.rhdr);
610 	return s.thdr.type+1 == s.rhdr.type ? 0 : -1;
611 }
612 
613 /*
614  *  send/receive messages with logging
615  */
616 void
617 sendmsg(P9fs *p, Fcall *f)
618 {
619 	DPRINT(2, "->%s: %d %s on %d\n", p->name, f->type,
620 		mname[f->type]? mname[f->type] : "mystery",
621 		f->fid);
622 
623 	p->len = convS2M(f, datasnd);
624 	if(write9p(p->fd[1], datasnd, p->len)!=p->len)
625 		error("smdmsg");
626 }
627 
628 void
629 dump(uchar *p, int len)
630 {
631 	fprint(2, "%d bytes", len);
632 	while(len > 0){
633 		fprint(2, " %.2ux", *p++);
634 		len--;
635 	}
636 	fprint(2, "\n");
637 }
638 
639 void
640 rcvmsg(P9fs *p, Fcall *f)
641 {
642 	int olen;
643 
644 	olen = p->len;
645 retry:
646 	p->len = read9p(p->fd[0], datarcv, sizeof(datarcv));
647 	if(p->len <= 0)
648 		error("rcvmsg");
649 	if(p->len==2 && datarcv[0]=='O' && datarcv[1]=='K')
650 		goto retry;
651 	if(convM2S(datarcv, f, p->len) == 0)
652 		error("rcvmsg format error");
653 	if(f->type != Rauth && (f->fid<0 || Nfid<=f->fid)){
654 		fprint(2, "<-%s: %d %s on %d\n", p->name, f->type,
655 			mname[f->type]? mname[f->type] : "mystery",
656 			f->fid);
657 		dump((uchar*)datasnd, olen);
658 		dump((uchar*)datarcv, p->len);
659 		error("rcvmsg fid out of range");
660 	}
661 	DPRINT(2, "<-%s: %d %s on %d\n", p->name, f->type,
662 		mname[f->type]? mname[f->type] : "mystery",
663 		f->fid);
664 }
665