19 /* maximum length of a file */
20 enum { MAXLEN = ~0ULL >> 1 };
22 typedef struct Mfile Mfile;
23 typedef struct Ram Ram;
24 typedef struct P9fs P9fs;
34 int debug, statson, noauth, openserver;
45 P9fs c; /* client conversation */
46 P9fs s; /* server conversation */
48 struct Cfsstat cfsstat, cfsprev;
52 #define MAXFDATA 8192 /* i/o size for read/write */
54 int messagesize = MAXFDATA+IOHDRSZ;
56 uchar datasnd[MAXFDATA + IOHDRSZ];
57 uchar datarcv[MAXFDATA + IOHDRSZ];
60 Qid ctlqid = {0x5555555555555555LL, 0, 0};
75 void error(char*, ...);
77 void mountinit(char*, char*);
79 void sendreply(char*);
80 void sendmsg(P9fs*, Fcall*);
81 void rcvmsg(P9fs*, Fcall*);
84 void cachesetup(int, char*, char*);
89 [Tversion] "Tversion",
102 [Rversion] "Rversion",
122 fprint(2, "usage:\tcfs -s [-dknrS] [-f partition]\n");
123 fprint(2, "\tcfs [-a netaddr | -F srv] [-dknrS] [-f partition] [mntpt]\n");
128 main(int argc, char *argv[])
130 int std, format, chkid;
131 char *part, *server, *mtpt;
137 part = "/dev/sdC0/cache";
143 server = EARGF(usage());
149 part = EARGF(usage());
152 server = EARGF(usage());
177 fmtinstall('F', fcallfmt);
182 c.fd[0] = c.fd[1] = 1;
183 s.fd[0] = s.fd[1] = 0;
185 mountinit(server, mtpt);
188 if((snci = getnetconninfo(nil, s.fd[0])) == nil)
189 /* Failed to lookup information; format */
190 cachesetup(1, nil, part);
192 /* Do partition check */
193 cachesetup(0, snci->raddr, part);
195 /* Obey -f w/o regard to cache vs. remote server */
196 cachesetup(format, nil, part);
210 cachesetup(int format, char *name, char *partition)
221 f = open(partition, ORDWR);
223 error("opening partition");
225 if(format || iinit(&ic, f, secsize, name) < 0){
227 * If we need to format and don't have a name, fall
228 * back to our old behavior of using "bootes"
230 name = (name == nil? "bootes": name);
231 if(iformat(&ic, f, inodes, name, blocksize, secsize) < 0)
232 error("formatting failed");
237 mountinit(char *server, char *mountpoint)
243 * grab a channel and call up the file server
246 s.fd[0] = open(server, ORDWR);
248 s.fd[0] = dial(netmkaddr(server, 0, "9fs"), 0, 0, 0);
250 error("opening data: %r");
254 * mount onto name space
257 error("pipe failed");
263 err = mount(p[1], -1, mountpoint, MREPL|MCREATE, "");
265 err = amount(p[1], mountpoint, MREPL|MCREATE, "");
267 error("mount failed: %r");
270 error("fork failed\n");
273 c.fd[0] = c.fd[1] = p[0];
287 cfsstat.cm[type].n++;
288 cfsstat.cm[type].s = nsec();
290 mf = &mfile[c.thdr.fid];
299 mf = &mfile[c.thdr.afid];
337 cfsstat.cm[type].t += nsec() -cfsstat.cm[type].s;
345 if(messagesize > c.thdr.msize)
346 messagesize = c.thdr.msize;
347 c.thdr.msize = messagesize; /* set downstream size */
355 error("auth to used channel");
358 mf->qid = s.rhdr.aqid;
364 rflush(void) /* synchronous so easy */
373 mf->qid = s.rhdr.qid;
389 && mf->qid.type == rootqid.type && mf->qid.path == rootqid.path
390 && c.thdr.nwname == 1 && strcmp(c.thdr.wname[0], "cfsctl") == 0){
391 /* This is the ctl file */
392 nmf = &mfile[c.thdr.newfid];
393 if(c.thdr.newfid != c.thdr.fid && nmf->busy)
394 error("clone to used channel");
395 nmf = &mfile[c.thdr.newfid];
399 c.rhdr.wqid[0] = ctlqid;
403 if(c.thdr.newfid != c.thdr.fid){
404 if(c.thdr.newfid >= Nfid)
405 error("clone nfid out of range");
406 nmf = &mfile[c.thdr.newfid];
408 error("clone to used channel");
409 nmf = &mfile[c.thdr.newfid];
412 mf = nmf; /* Walk mf */
415 if(delegate() < 0){ /* complete failure */
421 if(s.rhdr.nwqid == c.thdr.nwname){ /* complete success */
423 mf->qid = s.rhdr.wqid[s.rhdr.nwqid-1];
427 /* partial success; release fid */
435 if(statson && ctltest(mf)){
436 /* Opening ctl file */
437 if(c.thdr.mode != OREAD){
438 sendreply("does not exist");
449 mf->qid = s.rhdr.qid;
450 if(c.thdr.mode & OTRUNC)
458 if(statson && ctltest(mf)){
463 mf->qid = s.rhdr.qid;
482 if(statson && ctltest(mf)){
483 sendreply("not removed");
504 if(statson && ctltest(mf)){
505 if(cnt > statlen-off)
506 c.rhdr.count = statlen-off;
509 if((int)c.rhdr.count < 0){
513 c.rhdr.data = statbuf + off;
517 if(mf->qid.type & (QTDIR|QTAUTH)){
521 if(c.rhdr.count > 0){
522 cfsstat.bytesread += c.rhdr.count;
523 cfsstat.bytesfromdirs += c.rhdr.count;
529 b = iget(&ic, mf->qid);
531 DPRINT(2, "delegating read\n");
534 cfsstat.ndelegateread++;
535 if(c.rhdr.count > 0){
536 cfsstat.bytesread += c.rhdr.count;
537 cfsstat.bytesfromserver += c.rhdr.count;
545 while(cnt>0 && !done){
546 if(off >= b->inode.length){
547 DPRINT(2, "offset %lld greater than length %lld\n",
548 off, b->inode.length);
551 n = fread(&ic, b, cp, off, cnt);
557 "fetch %ld bytes of data from server at offset %lld\n",
559 s.thdr.type = c.thdr.type;
560 s.thdr.fid = c.thdr.fid;
561 s.thdr.tag = c.thdr.tag;
565 cfsstat.ndelegateread++;
567 sendreply(s.rhdr.ename);
570 if(s.rhdr.count != n)
575 if(b->inode.length > off){
576 DPRINT(2, "file %llud.%ld, length %lld\n",
578 b->inode.qid.vers, off);
579 b->inode.length = off;
583 memmove(cp, s.rhdr.data, n);
584 fwrite(&ic, b, cp, off, n);
586 cfsstat.bytestocache += n;
587 cfsstat.bytesfromserver += n;
590 DPRINT(2, "fetched %ld bytes from cache\n", n);
592 cfsstat.bytesfromcache += n;
599 c.rhdr.count = off - first;
601 cfsstat.bytesread += c.rhdr.count;
611 if(statson && ctltest(mf)){
612 sendreply("read only");
615 if(mf->qid.type & (QTDIR|QTAUTH)){
617 if(statson && c.rhdr.count > 0)
618 cfsstat.byteswritten += c.rhdr.count;
622 memmove(buf, c.thdr.data, c.thdr.count);
627 cfsstat.byteswritten += s.rhdr.count;
628 /* don't modify our cache for append-only data; always read from server*/
629 if(mf->qid.type & QTAPPEND)
631 b = iget(&ic, mf->qid);
634 if (b->inode.length < c.thdr.offset + s.rhdr.count)
635 b->inode.length = c.thdr.offset + s.rhdr.count;
637 if (s.rhdr.count != c.thdr.count)
638 syslog(0, "cfslog", "rhdr.count %ud, thdr.count %ud",
639 s.rhdr.count, c.thdr.count);
640 if(fwrite(&ic, b, buf, c.thdr.offset, s.rhdr.count) == s.rhdr.count){
643 cfsstat.bytestocache += s.rhdr.count;
653 if(statson && ctltest(mf)){
656 d.length = statlen; /* would be nice to do better */
663 c.rhdr.nstat = convD2M(&d, buf, sizeof buf);
671 convM2D(s.rhdr.stat, s.rhdr.nstat , &d, nil);
673 b = iget(&ic, mf->qid);
675 b->inode.length = d.length;
684 if(statson && ctltest(mf)){
685 sendreply("read only");
689 if(b = iget(&ic, mf->qid))
690 b->inode.length = MAXLEN;
694 error(char *fmt, ...)
697 static char buf[2048];
700 vseprint(buf, buf+sizeof(buf), fmt, arg);
702 fprint(2, "%s: %s\n", argv0, buf);
709 fprint(2, "cfs: %s: %r\n", s);
713 * send a reply to the client
720 c.rhdr.type = Rerror;
723 c.rhdr.type = c.thdr.type+1;
724 c.rhdr.fid = c.thdr.fid;
726 c.rhdr.tag = c.thdr.tag;
727 sendmsg(&c, &c.rhdr);
731 * send a request to the server, get the reply, and send that to
741 cfsstat.sm[type].n++;
742 cfsstat.sm[type].s = nsec();
745 sendmsg(&s, &c.thdr);
749 cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
751 sendmsg(&c, &s.rhdr);
752 return c.thdr.type+1 == s.rhdr.type ? 0 : -1;
756 * send a request to the server and get a reply
763 s.thdr.tag = c.thdr.tag;
767 cfsstat.sm[type].n++;
768 cfsstat.sm[type].s = nsec();
771 sendmsg(&s, &s.thdr);
775 cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
777 return s.thdr.type+1 == s.rhdr.type ? 0 : -1;
781 * send/receive messages with logging
784 sendmsg(P9fs *p, Fcall *f)
786 DPRINT(2, "->%s: %F\n", p->name, f);
788 p->len = convS2M(f, datasnd, messagesize);
791 if(write(p->fd[1], datasnd, p->len)!=p->len)
796 dump(uchar *p, int len)
798 fprint(2, "%d bytes", len);
800 fprint(2, " %.2ux", *p++);
805 rcvmsg(P9fs *p, Fcall *f)
811 p->len = read9pmsg(p->fd[0], datarcv, sizeof(datarcv));
815 snprint(buf, sizeof buf, "read9pmsg(%d)->%ld: %r",
819 if((rlen = convM2S(datarcv, p->len, f)) != p->len)
820 error("rcvmsg format error, expected length %d, got %d",
823 fprint(2, "<-%s: %d %s on %d\n", p->name, f->type,
824 mname[f->type]? mname[f->type]: "mystery", f->fid);
825 dump((uchar*)datasnd, olen);
826 dump((uchar*)datarcv, p->len);
827 error("rcvmsg fid out of range");
829 DPRINT(2, "<-%s: %F\n", p->name, f);
835 return mf->busy && mf->qid.type == ctlqid.type &&
836 mf->qid.path == ctlqid.path;
847 p += snprint(p, sizeof statbuf+statbuf-p,
849 p += snprint(p, sizeof statbuf+statbuf-p,
850 " #calls Δ ms/call Δ #calls Δ ms/call Δ\n");
851 for (i = 0; i < nelem(cfsstat.cm); i++)
852 if(cfsstat.cm[i].n || cfsstat.sm[i].n) {
853 p += snprint(p, sizeof statbuf+statbuf-p,
854 "%7lud %7lud ", cfsstat.cm[i].n,
855 cfsstat.cm[i].n - cfsprev.cm[i].n);
857 p += snprint(p, sizeof statbuf+statbuf-p,
858 "%7.3f ", 0.000001*cfsstat.cm[i].t/
861 p += snprint(p, sizeof statbuf+statbuf-p,
863 if(cfsstat.cm[i].n - cfsprev.cm[i].n)
864 p += snprint(p, sizeof statbuf+statbuf-p,
866 (cfsstat.cm[i].t - cfsprev.cm[i].t)/
867 (cfsstat.cm[i].n - cfsprev.cm[i].n));
869 p += snprint(p, sizeof statbuf+statbuf-p,
871 p += snprint(p, sizeof statbuf+statbuf-p,
872 "%7lud %7lud ", cfsstat.sm[i].n,
873 cfsstat.sm[i].n - cfsprev.sm[i].n);
875 p += snprint(p, sizeof statbuf+statbuf-p,
876 "%7.3f ", 0.000001*cfsstat.sm[i].t/
879 p += snprint(p, sizeof statbuf+statbuf-p,
881 if(cfsstat.sm[i].n - cfsprev.sm[i].n)
882 p += snprint(p, sizeof statbuf+statbuf-p,
884 (cfsstat.sm[i].t - cfsprev.sm[i].t)/
885 (cfsstat.sm[i].n - cfsprev.sm[i].n));
887 p += snprint(p, sizeof statbuf+statbuf-p,
889 p += snprint(p, sizeof statbuf+statbuf-p, "%s\n",
892 p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndirread\n",
893 cfsstat.ndirread, cfsstat.ndirread - cfsprev.ndirread);
894 p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelegateread\n",
895 cfsstat.ndelegateread, cfsstat.ndelegateread -
896 cfsprev.ndelegateread);
897 p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ninsert\n",
898 cfsstat.ninsert, cfsstat.ninsert - cfsprev.ninsert);
899 p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelete\n",
900 cfsstat.ndelete, cfsstat.ndelete - cfsprev.ndelete);
901 p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud nupdate\n",
902 cfsstat.nupdate, cfsstat.nupdate - cfsprev.nupdate);
904 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesread\n",
905 cfsstat.bytesread, cfsstat.bytesread - cfsprev.bytesread);
906 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud byteswritten\n",
907 cfsstat.byteswritten, cfsstat.byteswritten -
908 cfsprev.byteswritten);
909 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromserver\n",
910 cfsstat.bytesfromserver, cfsstat.bytesfromserver -
911 cfsprev.bytesfromserver);
912 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromdirs\n",
913 cfsstat.bytesfromdirs, cfsstat.bytesfromdirs -
914 cfsprev.bytesfromdirs);
915 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromcache\n",
916 cfsstat.bytesfromcache, cfsstat.bytesfromcache -
917 cfsprev.bytesfromcache);
918 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytestocache\n",
919 cfsstat.bytestocache, cfsstat.bytestocache -
920 cfsprev.bytestocache);
921 statlen = p - statbuf;