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");
264 err = mount(p[1], -1, mountpoint, MREPL|MCREATE, "");
266 err = amount(p[1], mountpoint, MREPL|MCREATE, "");
268 error("mount failed: %r");
271 error("fork failed\n");
274 c.fd[0] = c.fd[1] = p[0];
288 cfsstat.cm[type].n++;
289 cfsstat.cm[type].s = nsec();
291 mf = &mfile[c.thdr.fid];
300 mf = &mfile[c.thdr.afid];
338 cfsstat.cm[type].t += nsec() -cfsstat.cm[type].s;
346 if(messagesize > c.thdr.msize)
347 messagesize = c.thdr.msize;
348 c.thdr.msize = messagesize; /* set downstream size */
356 error("auth to used channel");
359 mf->qid = s.rhdr.aqid;
365 rflush(void) /* synchronous so easy */
374 mf->qid = s.rhdr.qid;
390 && mf->qid.type == rootqid.type && mf->qid.path == rootqid.path
391 && c.thdr.nwname == 1 && strcmp(c.thdr.wname[0], "cfsctl") == 0){
392 /* This is the ctl file */
393 nmf = &mfile[c.thdr.newfid];
394 if(c.thdr.newfid != c.thdr.fid && nmf->busy)
395 error("clone to used channel");
396 nmf = &mfile[c.thdr.newfid];
400 c.rhdr.wqid[0] = ctlqid;
404 if(c.thdr.newfid != c.thdr.fid){
405 if(c.thdr.newfid >= Nfid)
406 error("clone nfid out of range");
407 nmf = &mfile[c.thdr.newfid];
409 error("clone to used channel");
410 nmf = &mfile[c.thdr.newfid];
413 mf = nmf; /* Walk mf */
416 if(delegate() < 0){ /* complete failure */
422 if(s.rhdr.nwqid == c.thdr.nwname){ /* complete success */
424 mf->qid = s.rhdr.wqid[s.rhdr.nwqid-1];
428 /* partial success; release fid */
436 if(statson && ctltest(mf)){
437 /* Opening ctl file */
438 if(c.thdr.mode != OREAD){
439 sendreply("does not exist");
450 mf->qid = s.rhdr.qid;
451 if(c.thdr.mode & OTRUNC)
459 if(statson && ctltest(mf)){
464 mf->qid = s.rhdr.qid;
483 if(statson && ctltest(mf)){
484 sendreply("not removed");
505 if(statson && ctltest(mf)){
506 if(cnt > statlen-off)
507 c.rhdr.count = statlen-off;
510 if((int)c.rhdr.count < 0){
514 c.rhdr.data = statbuf + off;
518 if(mf->qid.type & (QTDIR|QTAUTH)){
522 if(c.rhdr.count > 0){
523 cfsstat.bytesread += c.rhdr.count;
524 cfsstat.bytesfromdirs += c.rhdr.count;
530 b = iget(&ic, mf->qid);
532 DPRINT(2, "delegating read\n");
535 cfsstat.ndelegateread++;
536 if(c.rhdr.count > 0){
537 cfsstat.bytesread += c.rhdr.count;
538 cfsstat.bytesfromserver += c.rhdr.count;
546 while(cnt>0 && !done){
547 if(off >= b->inode.length){
548 DPRINT(2, "offset %lld greater than length %lld\n",
549 off, b->inode.length);
552 n = fread(&ic, b, cp, off, cnt);
558 "fetch %ld bytes of data from server at offset %lld\n",
560 s.thdr.type = c.thdr.type;
561 s.thdr.fid = c.thdr.fid;
562 s.thdr.tag = c.thdr.tag;
566 cfsstat.ndelegateread++;
568 sendreply(s.rhdr.ename);
571 if(s.rhdr.count != n)
576 if(b->inode.length > off){
577 DPRINT(2, "file %llud.%ld, length %lld\n",
579 b->inode.qid.vers, off);
580 b->inode.length = off;
584 memmove(cp, s.rhdr.data, n);
585 fwrite(&ic, b, cp, off, n);
587 cfsstat.bytestocache += n;
588 cfsstat.bytesfromserver += n;
591 DPRINT(2, "fetched %ld bytes from cache\n", n);
593 cfsstat.bytesfromcache += n;
600 c.rhdr.count = off - first;
602 cfsstat.bytesread += c.rhdr.count;
612 if(statson && ctltest(mf)){
613 sendreply("read only");
616 if(mf->qid.type & (QTDIR|QTAUTH)){
618 if(statson && c.rhdr.count > 0)
619 cfsstat.byteswritten += c.rhdr.count;
623 memmove(buf, c.thdr.data, c.thdr.count);
628 cfsstat.byteswritten += s.rhdr.count;
629 /* don't modify our cache for append-only data; always read from server*/
630 if(mf->qid.type & QTAPPEND)
632 b = iget(&ic, mf->qid);
635 if (b->inode.length < c.thdr.offset + s.rhdr.count)
636 b->inode.length = c.thdr.offset + s.rhdr.count;
638 if (s.rhdr.count != c.thdr.count)
639 syslog(0, "cfslog", "rhdr.count %ud, thdr.count %ud",
640 s.rhdr.count, c.thdr.count);
641 if(fwrite(&ic, b, buf, c.thdr.offset, s.rhdr.count) == s.rhdr.count){
644 cfsstat.bytestocache += s.rhdr.count;
654 if(statson && ctltest(mf)){
657 d.length = statlen; /* would be nice to do better */
664 c.rhdr.nstat = convD2M(&d, buf, sizeof buf);
672 convM2D(s.rhdr.stat, s.rhdr.nstat , &d, nil);
674 b = iget(&ic, mf->qid);
676 b->inode.length = d.length;
685 if(statson && ctltest(mf)){
686 sendreply("read only");
690 if(b = iget(&ic, mf->qid))
691 b->inode.length = MAXLEN;
695 error(char *fmt, ...)
698 static char buf[2048];
701 vseprint(buf, buf+sizeof(buf), fmt, arg);
703 fprint(2, "%s: %s\n", argv0, buf);
710 fprint(2, "cfs: %s: %r\n", s);
714 * send a reply to the client
721 c.rhdr.type = Rerror;
724 c.rhdr.type = c.thdr.type+1;
725 c.rhdr.fid = c.thdr.fid;
727 c.rhdr.tag = c.thdr.tag;
728 sendmsg(&c, &c.rhdr);
732 * send a request to the server, get the reply, and send that to
742 cfsstat.sm[type].n++;
743 cfsstat.sm[type].s = nsec();
746 sendmsg(&s, &c.thdr);
750 cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
752 sendmsg(&c, &s.rhdr);
753 return c.thdr.type+1 == s.rhdr.type ? 0 : -1;
757 * send a request to the server and get a reply
764 s.thdr.tag = c.thdr.tag;
768 cfsstat.sm[type].n++;
769 cfsstat.sm[type].s = nsec();
772 sendmsg(&s, &s.thdr);
776 cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
778 return s.thdr.type+1 == s.rhdr.type ? 0 : -1;
782 * send/receive messages with logging
785 sendmsg(P9fs *p, Fcall *f)
787 DPRINT(2, "->%s: %F\n", p->name, f);
789 p->len = convS2M(f, datasnd, messagesize);
792 if(write(p->fd[1], datasnd, p->len)!=p->len)
797 dump(uchar *p, int len)
799 fprint(2, "%d bytes", len);
801 fprint(2, " %.2ux", *p++);
806 rcvmsg(P9fs *p, Fcall *f)
812 p->len = read9pmsg(p->fd[0], datarcv, sizeof(datarcv));
816 snprint(buf, sizeof buf, "read9pmsg(%d)->%ld: %r",
820 if((rlen = convM2S(datarcv, p->len, f)) != p->len)
821 error("rcvmsg format error, expected length %d, got %d",
824 fprint(2, "<-%s: %d %s on %d\n", p->name, f->type,
825 mname[f->type]? mname[f->type]: "mystery", f->fid);
826 dump((uchar*)datasnd, olen);
827 dump((uchar*)datarcv, p->len);
828 error("rcvmsg fid out of range");
830 DPRINT(2, "<-%s: %F\n", p->name, f);
836 return mf->busy && mf->qid.type == ctlqid.type &&
837 mf->qid.path == ctlqid.path;
848 p += snprint(p, sizeof statbuf+statbuf-p,
850 p += snprint(p, sizeof statbuf+statbuf-p,
851 " #calls Δ ms/call Δ #calls Δ ms/call Δ\n");
852 for (i = 0; i < nelem(cfsstat.cm); i++)
853 if(cfsstat.cm[i].n || cfsstat.sm[i].n) {
854 p += snprint(p, sizeof statbuf+statbuf-p,
855 "%7lud %7lud ", cfsstat.cm[i].n,
856 cfsstat.cm[i].n - cfsprev.cm[i].n);
858 p += snprint(p, sizeof statbuf+statbuf-p,
859 "%7.3f ", 0.000001*cfsstat.cm[i].t/
862 p += snprint(p, sizeof statbuf+statbuf-p,
864 if(cfsstat.cm[i].n - cfsprev.cm[i].n)
865 p += snprint(p, sizeof statbuf+statbuf-p,
867 (cfsstat.cm[i].t - cfsprev.cm[i].t)/
868 (cfsstat.cm[i].n - cfsprev.cm[i].n));
870 p += snprint(p, sizeof statbuf+statbuf-p,
872 p += snprint(p, sizeof statbuf+statbuf-p,
873 "%7lud %7lud ", cfsstat.sm[i].n,
874 cfsstat.sm[i].n - cfsprev.sm[i].n);
876 p += snprint(p, sizeof statbuf+statbuf-p,
877 "%7.3f ", 0.000001*cfsstat.sm[i].t/
880 p += snprint(p, sizeof statbuf+statbuf-p,
882 if(cfsstat.sm[i].n - cfsprev.sm[i].n)
883 p += snprint(p, sizeof statbuf+statbuf-p,
885 (cfsstat.sm[i].t - cfsprev.sm[i].t)/
886 (cfsstat.sm[i].n - cfsprev.sm[i].n));
888 p += snprint(p, sizeof statbuf+statbuf-p,
890 p += snprint(p, sizeof statbuf+statbuf-p, "%s\n",
893 p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndirread\n",
894 cfsstat.ndirread, cfsstat.ndirread - cfsprev.ndirread);
895 p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelegateread\n",
896 cfsstat.ndelegateread, cfsstat.ndelegateread -
897 cfsprev.ndelegateread);
898 p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ninsert\n",
899 cfsstat.ninsert, cfsstat.ninsert - cfsprev.ninsert);
900 p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelete\n",
901 cfsstat.ndelete, cfsstat.ndelete - cfsprev.ndelete);
902 p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud nupdate\n",
903 cfsstat.nupdate, cfsstat.nupdate - cfsprev.nupdate);
905 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesread\n",
906 cfsstat.bytesread, cfsstat.bytesread - cfsprev.bytesread);
907 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud byteswritten\n",
908 cfsstat.byteswritten, cfsstat.byteswritten -
909 cfsprev.byteswritten);
910 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromserver\n",
911 cfsstat.bytesfromserver, cfsstat.bytesfromserver -
912 cfsprev.bytesfromserver);
913 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromdirs\n",
914 cfsstat.bytesfromdirs, cfsstat.bytesfromdirs -
915 cfsprev.bytesfromdirs);
916 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromcache\n",
917 cfsstat.bytesfromcache, cfsstat.bytesfromcache -
918 cfsprev.bytesfromcache);
919 p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytestocache\n",
920 cfsstat.bytestocache, cfsstat.bytestocache -
921 cfsprev.bytestocache);
922 statlen = p - statbuf;