/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h> #include "cformat.h"#include "lru.h"#include "bcache.h"#include "disk.h"#include "inode.h"#include "file.h"#include "stats.h" enum{ Nfid= 10240,}; /* maximum length of a file */enum { MAXLEN = ~0ULL >> 1 }; typedef struct Mfile Mfile;typedef struct Ram Ram;typedef struct P9fs P9fs; struct Mfile{ Qid qid; char busy;}; Mfile mfile[Nfid];Icache ic;int debug, statson, noauth, openserver; struct P9fs{ int fd[2]; Fcall rhdr; Fcall thdr; long len; char *name;}; P9fs c; /* client conversation */P9fs s; /* server conversation */ struct Cfsstat cfsstat, cfsprev;char statbuf[2048];int statlen; #define MAXFDATA 8192 /* i/o size for read/write */ int messagesize = MAXFDATA+IOHDRSZ; uchar datasnd[MAXFDATA + IOHDRSZ];uchar datarcv[MAXFDATA + IOHDRSZ]; Qid rootqid;Qid ctlqid = {0x5555555555555555LL, 0, 0}; void rversion(void);void rauth(Mfile*);void rflush(void);void rattach(Mfile*);void rwalk(Mfile*);void ropen(Mfile*);void rcreate(Mfile*);void rread(Mfile*);void rwrite(Mfile*);void rclunk(Mfile*);void rremove(Mfile*);void rstat(Mfile*);void rwstat(Mfile*);void error(char*, ...);void warning(char*);void mountinit(char*, char*);void io(void);void sendreply(char*);void sendmsg(P9fs*, Fcall*);void rcvmsg(P9fs*, Fcall*);int delegate(void);int askserver(void);void cachesetup(int, char*, char*);int ctltest(Mfile*);void genstats(void); char *mname[]={ [Tversion] "Tversion", [Tauth] "Tauth", [Tflush] "Tflush", [Tattach] "Tattach", [Twalk] "Twalk", [Topen] "Topen", [Tcreate] "Tcreate", [Tclunk] "Tclunk", [Tread] "Tread", [Twrite] "Twrite", [Tremove] "Tremove", [Tstat] "Tstat", [Twstat] "Twstat", [Rversion] "Rversion", [Rauth] "Rauth", [Rerror] "Rerror", [Rflush] "Rflush", [Rattach] "Rattach", [Rwalk] "Rwalk", [Ropen] "Ropen", [Rcreate] "Rcreate", [Rclunk] "Rclunk", [Rread] "Rread", [Rwrite] "Rwrite", [Rremove] "Rremove", [Rstat] "Rstat", [Rwstat] "Rwstat", 0,}; voidusage(void){ fprint(2, "usage:\tcfs -s [-dknrS] [-f partition]\n"); fprint(2, "\tcfs [-a netaddr | -F srv] [-dknrS] [-f partition] [mntpt]\n"); exits("usage");} voidmain(int argc, char *argv[]){ int std, format, chkid; char *part, *server, *mtpt; NetConnInfo *snci; std = 0; format = 0; chkid = 1; part = "/dev/sdC0/cache"; server = "tcp!fs"; mtpt = "/tmp"; ARGBEGIN{ case 'a': server = EARGF(usage()); break; case 'd': debug = 1; break; case 'f': part = EARGF(usage()); break; case 'F': server = EARGF(usage()); openserver = 1; break; case 'k': chkid = 0; break; case 'n': noauth = 1; break; case 'r': format = 1; break; case 'S': statson = 1; break; case 's': std = 1; break; default: usage(); }ARGEND if(argc && *argv) mtpt = *argv; if(debug) fmtinstall('F', fcallfmt); c.name = "client"; s.name = "server"; if(std){ c.fd[0] = c.fd[1] = 1; s.fd[0] = s.fd[1] = 0; }else mountinit(server, mtpt); if(chkid){ if((snci = getnetconninfo(nil, s.fd[0])) == nil) /* Failed to lookup information; format */ cachesetup(1, nil, part); else /* Do partition check */ cachesetup(0, snci->raddr, part); }else /* Obey -f w/o regard to cache vs. remote server */ cachesetup(format, nil, part); switch(fork()){ case 0: io(); exits(""); case -1: error("fork"); default: exits(""); }} voidcachesetup(int format, char *name, char *partition){ int f; int secsize; int inodes; int blocksize; secsize = 512; inodes = 1024; blocksize = 4*1024; f = open(partition, ORDWR); if(f < 0) error("opening partition"); if(format || iinit(&ic, f, secsize, name) < 0){ /* * If we need to format and don't have a name, fall * back to our old behavior of using "bootes" */ name = (name == nil? "bootes": name); if(iformat(&ic, f, inodes, name, blocksize, secsize) < 0) error("formatting failed"); }} voidmountinit(char *server, char *mountpoint){ int err; int p[2]; /* * grab a channel and call up the file server */ if (openserver) s.fd[0] = open(server, ORDWR); else s.fd[0] = dial(netmkaddr(server, 0, "9fs"), 0, 0, 0); if(s.fd[0] < 0) error("opening data: %r"); s.fd[1] = s.fd[0]; /* * mount onto name space */ if(pipe(p) < 0) error("pipe failed"); switch(fork()){ case 0: break; default: if (noauth) err = mount(p[1], -1, mountpoint, MREPL|MCREATE, ""); else err = amount(p[1], mountpoint, MREPL|MCREATE, ""); if (err < 0) error("mount failed: %r"); exits(0); case -1: error("fork failed\n");/*BUG: no wait!*/ } c.fd[0] = c.fd[1] = p[0];} voidio(void){ int type; Mfile *mf; loop: rcvmsg(&c, &c.thdr); type = c.thdr.type; if(statson){ cfsstat.cm[type].n++; cfsstat.cm[type].s = nsec(); } mf = &mfile[c.thdr.fid]; switch(type){ default: error("type"); break; case Tversion: rversion(); break; case Tauth: mf = &mfile[c.thdr.afid]; rauth(mf); break; case Tflush: rflush(); break; case Tattach: rattach(mf); break; case Twalk: rwalk(mf); break; case Topen: ropen(mf); break; case Tcreate: rcreate(mf); break; case Tread: rread(mf); break; case Twrite: rwrite(mf); break; case Tclunk: rclunk(mf); break; case Tremove: rremove(mf); break; case Tstat: rstat(mf); break; case Twstat: rwstat(mf); break; } if(statson){ cfsstat.cm[type].t += nsec() -cfsstat.cm[type].s; } goto loop;} voidrversion(void){ if(messagesize > c.thdr.msize) messagesize = c.thdr.msize; c.thdr.msize = messagesize; /* set downstream size */ delegate();} voidrauth(Mfile *mf){ if(mf->busy) error("auth to used channel"); if(delegate() == 0){ mf->qid = s.rhdr.aqid; mf->busy = 1; }} voidrflush(void) /* synchronous so easy */{ sendreply(0);} voidrattach(Mfile *mf){ if(delegate() == 0){ mf->qid = s.rhdr.qid; mf->busy = 1; if (statson == 1){ statson++; rootqid = mf->qid; } }} voidrwalk(Mfile *mf){ Mfile *nmf; nmf = nil; if(statson && mf->qid.type == rootqid.type && mf->qid.path == rootqid.path && c.thdr.nwname == 1 && strcmp(c.thdr.wname[0], "cfsctl") == 0){ /* This is the ctl file */ nmf = &mfile[c.thdr.newfid]; if(c.thdr.newfid != c.thdr.fid && nmf->busy) error("clone to used channel"); nmf = &mfile[c.thdr.newfid]; nmf->qid = ctlqid; nmf->busy = 1; c.rhdr.nwqid = 1; c.rhdr.wqid[0] = ctlqid; sendreply(0); return; } if(c.thdr.newfid != c.thdr.fid){ if(c.thdr.newfid >= Nfid) error("clone nfid out of range"); nmf = &mfile[c.thdr.newfid]; if(nmf->busy) error("clone to used channel"); nmf = &mfile[c.thdr.newfid]; nmf->qid = mf->qid; nmf->busy = 1; mf = nmf; /* Walk mf */ } if(delegate() < 0){ /* complete failure */ if(nmf) nmf->busy = 0; return; } if(s.rhdr.nwqid == c.thdr.nwname){ /* complete success */ if(s.rhdr.nwqid > 0) mf->qid = s.rhdr.wqid[s.rhdr.nwqid-1]; return; } /* partial success; release fid */ if(nmf) nmf->busy = 0;} voidropen(Mfile *mf){ if(statson && ctltest(mf)){ /* Opening ctl file */ if(c.thdr.mode != OREAD){ sendreply("does not exist"); return; } c.rhdr.qid = ctlqid; c.rhdr.iounit = 0; sendreply(0); genstats(); return; } if(delegate() == 0){ mf->qid = s.rhdr.qid; if(c.thdr.mode & OTRUNC) iget(&ic, mf->qid); }} voidrcreate(Mfile *mf){ if(statson && ctltest(mf)){ sendreply("exists"); return; } if(delegate() == 0){ mf->qid = s.rhdr.qid; mf->qid.vers++; }} voidrclunk(Mfile *mf){ if(!mf->busy){ sendreply(0); return; } mf->busy = 0; delegate();} voidrremove(Mfile *mf){ if(statson && ctltest(mf)){ sendreply("not removed"); return; } mf->busy = 0; delegate();} voidrread(Mfile *mf){Lines 1–500 of 930. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h> #include <libc.h> #include <auth.h> #include <fcall.h> #include "cformat.h" #include "lru.h" #include "bcache.h" #include "disk.h" #include "inode.h" #include "file.h" #include "stats.h" enum { Nfid= 10240, }; /* maximum length of a file */ enum { MAXLEN = ~0ULL >> 1 }; typedef struct Mfile Mfile; typedef struct Ram Ram; typedef struct P9fs P9fs; struct Mfile { Qid qid; char busy; }; Mfile mfile[Nfid]; Icache ic; int debug, statson, noauth, openserver; struct P9fs { int fd[2]; Fcall rhdr; Fcall thdr; long len; char *name; }; P9fs c; /* client conversation */ P9fs s; /* server conversation */ struct Cfsstat cfsstat, cfsprev; char statbuf[2048]; int statlen; #define MAXFDATA 8192 /* i/o size for read/write */ int messagesize = MAXFDATA+IOHDRSZ; uchar datasnd[MAXFDATA + IOHDRSZ]; uchar datarcv[MAXFDATA + IOHDRSZ]; Qid rootqid; Qid ctlqid = {0x5555555555555555LL, 0, 0}; void rversion(void); void rauth(Mfile*); void rflush(void); void rattach(Mfile*); void rwalk(Mfile*); void ropen(Mfile*); void rcreate(Mfile*); void rread(Mfile*); void rwrite(Mfile*); void rclunk(Mfile*); void rremove(Mfile*); void rstat(Mfile*); void rwstat(Mfile*); void error(char*, ...); void warning(char*); void mountinit(char*, char*); void io(void); void sendreply(char*); void sendmsg(P9fs*, Fcall*); void rcvmsg(P9fs*, Fcall*); int delegate(void); int askserver(void); void cachesetup(int, char*, char*); int ctltest(Mfile*); void genstats(void); char *mname[]={ [Tversion] "Tversion", [Tauth] "Tauth", [Tflush] "Tflush", [Tattach] "Tattach", [Twalk] "Twalk", [Topen] "Topen", [Tcreate] "Tcreate", [Tclunk] "Tclunk", [Tread] "Tread", [Twrite] "Twrite", [Tremove] "Tremove", [Tstat] "Tstat", [Twstat] "Twstat", [Rversion] "Rversion", [Rauth] "Rauth", [Rerror] "Rerror", [Rflush] "Rflush", [Rattach] "Rattach", [Rwalk] "Rwalk", [Ropen] "Ropen", [Rcreate] "Rcreate", [Rclunk] "Rclunk", [Rread] "Rread", [Rwrite] "Rwrite", [Rremove] "Rremove", [Rstat] "Rstat", [Rwstat] "Rwstat", 0, }; void usage(void) { fprint(2, "usage:\tcfs -s [-dknrS] [-f partition]\n"); fprint(2, "\tcfs [-a netaddr | -F srv] [-dknrS] [-f partition] [mntpt]\n"); exits("usage"); } void main(int argc, char *argv[]) { int std, format, chkid; char *part, *server, *mtpt; NetConnInfo *snci; std = 0; format = 0; chkid = 1; part = "/dev/sdC0/cache"; server = "tcp!fs"; mtpt = "/tmp"; ARGBEGIN{ case 'a': server = EARGF(usage()); break; case 'd': debug = 1; break; case 'f': part = EARGF(usage()); break; case 'F': server = EARGF(usage()); openserver = 1; break; case 'k': chkid = 0; break; case 'n': noauth = 1; break; case 'r': format = 1; break; case 'S': statson = 1; break; case 's': std = 1; break; default: usage(); }ARGEND if(argc && *argv) mtpt = *argv; if(debug) fmtinstall('F', fcallfmt); c.name = "client"; s.name = "server"; if(std){ c.fd[0] = c.fd[1] = 1; s.fd[0] = s.fd[1] = 0; }else mountinit(server, mtpt); if(chkid){ if((snci = getnetconninfo(nil, s.fd[0])) == nil) /* Failed to lookup information; format */ cachesetup(1, nil, part); else /* Do partition check */ cachesetup(0, snci->raddr, part); }else /* Obey -f w/o regard to cache vs. remote server */ cachesetup(format, nil, part); switch(fork()){ case 0: io(); exits(""); case -1: error("fork"); default: exits(""); } } void cachesetup(int format, char *name, char *partition) { int f; int secsize; int inodes; int blocksize; secsize = 512; inodes = 1024; blocksize = 4*1024; f = open(partition, ORDWR); if(f < 0) error("opening partition"); if(format || iinit(&ic, f, secsize, name) < 0){ /* * If we need to format and don't have a name, fall * back to our old behavior of using "bootes" */ name = (name == nil? "bootes": name); if(iformat(&ic, f, inodes, name, blocksize, secsize) < 0) error("formatting failed"); } } void mountinit(char *server, char *mountpoint) { int err; int p[2]; /* * grab a channel and call up the file server */ if (openserver) s.fd[0] = open(server, ORDWR); else s.fd[0] = dial(netmkaddr(server, 0, "9fs"), 0, 0, 0); if(s.fd[0] < 0) error("opening data: %r"); s.fd[1] = s.fd[0]; /* * mount onto name space */ if(pipe(p) < 0) error("pipe failed"); switch(fork()){ case 0: break; default: if (noauth) err = mount(p[1], -1, mountpoint, MREPL|MCREATE, ""); else err = amount(p[1], mountpoint, MREPL|MCREATE, ""); if (err < 0) error("mount failed: %r"); exits(0); case -1: error("fork failed\n"); /*BUG: no wait!*/ } c.fd[0] = c.fd[1] = p[0]; } void io(void) { int type; Mfile *mf; loop: rcvmsg(&c, &c.thdr); type = c.thdr.type; if(statson){ cfsstat.cm[type].n++; cfsstat.cm[type].s = nsec(); } mf = &mfile[c.thdr.fid]; switch(type){ default: error("type"); break; case Tversion: rversion(); break; case Tauth: mf = &mfile[c.thdr.afid]; rauth(mf); break; case Tflush: rflush(); break; case Tattach: rattach(mf); break; case Twalk: rwalk(mf); break; case Topen: ropen(mf); break; case Tcreate: rcreate(mf); break; case Tread: rread(mf); break; case Twrite: rwrite(mf); break; case Tclunk: rclunk(mf); break; case Tremove: rremove(mf); break; case Tstat: rstat(mf); break; case Twstat: rwstat(mf); break; } if(statson){ cfsstat.cm[type].t += nsec() -cfsstat.cm[type].s; } goto loop; } void rversion(void) { if(messagesize > c.thdr.msize) messagesize = c.thdr.msize; c.thdr.msize = messagesize; /* set downstream size */ delegate(); } void rauth(Mfile *mf) { if(mf->busy) error("auth to used channel"); if(delegate() == 0){ mf->qid = s.rhdr.aqid; mf->busy = 1; } } void rflush(void) /* synchronous so easy */ { sendreply(0); } void rattach(Mfile *mf) { if(delegate() == 0){ mf->qid = s.rhdr.qid; mf->busy = 1; if (statson == 1){ statson++; rootqid = mf->qid; } } } void rwalk(Mfile *mf) { Mfile *nmf; nmf = nil; if(statson && mf->qid.type == rootqid.type && mf->qid.path == rootqid.path && c.thdr.nwname == 1 && strcmp(c.thdr.wname[0], "cfsctl") == 0){ /* This is the ctl file */ nmf = &mfile[c.thdr.newfid]; if(c.thdr.newfid != c.thdr.fid && nmf->busy) error("clone to used channel"); nmf = &mfile[c.thdr.newfid]; nmf->qid = ctlqid; nmf->busy = 1; c.rhdr.nwqid = 1; c.rhdr.wqid[0] = ctlqid; sendreply(0); return; } if(c.thdr.newfid != c.thdr.fid){ if(c.thdr.newfid >= Nfid) error("clone nfid out of range"); nmf = &mfile[c.thdr.newfid]; if(nmf->busy) error("clone to used channel"); nmf = &mfile[c.thdr.newfid]; nmf->qid = mf->qid; nmf->busy = 1; mf = nmf; /* Walk mf */ } if(delegate() < 0){ /* complete failure */ if(nmf) nmf->busy = 0; return; } if(s.rhdr.nwqid == c.thdr.nwname){ /* complete success */ if(s.rhdr.nwqid > 0) mf->qid = s.rhdr.wqid[s.rhdr.nwqid-1]; return; } /* partial success; release fid */ if(nmf) nmf->busy = 0; } void ropen(Mfile *mf) { if(statson && ctltest(mf)){ /* Opening ctl file */ if(c.thdr.mode != OREAD){ sendreply("does not exist"); return; } c.rhdr.qid = ctlqid; c.rhdr.iounit = 0; sendreply(0); genstats(); return; } if(delegate() == 0){ mf->qid = s.rhdr.qid; if(c.thdr.mode & OTRUNC) iget(&ic, mf->qid); } } void rcreate(Mfile *mf) { if(statson && ctltest(mf)){ sendreply("exists"); return; } if(delegate() == 0){ mf->qid = s.rhdr.qid; mf->qid.vers++; } } void rclunk(Mfile *mf) { if(!mf->busy){ sendreply(0); return; } mf->busy = 0; delegate(); } void rremove(Mfile *mf) { if(statson && ctltest(mf)){ sendreply("not removed"); return; } mf->busy = 0; delegate(); } void rread(Mfile *mf) {