The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/devmnt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "../port/error.h"
    7 
    8 /*
    9  * References are managed as follows:
   10  * The channel to the server - a network connection or pipe - has one
   11  * reference for every Chan open on the server.  The server channel has
   12  * c->mux set to the Mnt used for muxing control to that server.  Mnts
   13  * have no reference count; they go away when c goes away.
   14  * Each channel derived from the mount point has mchan set to c,
   15  * and increfs/decrefs mchan to manage references on the server
   16  * connection.
   17  */
   18 
   19 #define MAXRPC (IOHDRSZ+8192)
   20 
   21 struct Mntrpc
   22 {
   23         Chan*   c;              /* Channel for whom we are working */
   24         Mntrpc* list;           /* Free/pending list */
   25         Fcall   request;        /* Outgoing file system protocol message */
   26         Fcall   reply;          /* Incoming reply */
   27         Mnt*    m;              /* Mount device during rpc */
   28         Rendez  r;              /* Place to hang out */
   29         uchar*  rpc;            /* I/O Data buffer */
   30         uint    rpclen;         /* len of buffer */
   31         Block   *b;             /* reply blocks */
   32         char    done;           /* Rpc completed */
   33         uvlong  stime;          /* start time for mnt statistics */
   34         ulong   reqlen;         /* request length for mnt statistics */
   35         ulong   replen;         /* reply length for mnt statistics */
   36         Mntrpc* flushed;        /* message this one flushes */
   37 };
   38 
   39 enum
   40 {
   41         TAGSHIFT = 5,                   /* ulong has to be 32 bits */
   42         TAGMASK = (1<<TAGSHIFT)-1,
   43         NMASK = (64*1024)>>TAGSHIFT,
   44 };
   45 
   46 struct Mntalloc
   47 {
   48         Lock;
   49         Mnt*    list;           /* Mount devices in use */
   50         Mnt*    mntfree;        /* Free list */
   51         Mntrpc* rpcfree;
   52         int     nrpcfree;
   53         int     nrpcused;
   54         ulong   id;
   55         ulong   tagmask[NMASK];
   56 }mntalloc;
   57 
   58 Mnt*    mntchk(Chan*);
   59 void    mntdirfix(uchar*, Chan*);
   60 Mntrpc* mntflushalloc(Mntrpc*, ulong);
   61 void    mntflushfree(Mnt*, Mntrpc*);
   62 void    mntfree(Mntrpc*);
   63 void    mntgate(Mnt*);
   64 void    mntpntfree(Mnt*);
   65 void    mntqrm(Mnt*, Mntrpc*);
   66 Mntrpc* mntralloc(Chan*, ulong);
   67 long    mntrdwr(int, Chan*, void*, long, vlong);
   68 int     mntrpcread(Mnt*, Mntrpc*);
   69 void    mountio(Mnt*, Mntrpc*);
   70 void    mountmux(Mnt*, Mntrpc*);
   71 void    mountrpc(Mnt*, Mntrpc*);
   72 int     rpcattn(void*);
   73 Chan*   mntchan(void);
   74 
   75 char    Esbadstat[] = "invalid directory entry received from server";
   76 char    Enoversion[] = "version not established for mount channel";
   77 
   78 
   79 void (*mntstats)(int, Chan*, uvlong, ulong);
   80 
   81 static void
   82 mntreset(void)
   83 {
   84         mntalloc.id = 1;
   85         mntalloc.tagmask[0] = 1;                        /* don't allow 0 as a tag */
   86         mntalloc.tagmask[NMASK-1] = 0x80000000UL;       /* don't allow NOTAG */
   87         fmtinstall('F', fcallfmt);
   88         fmtinstall('D', dirfmt);
   89 /* We can't install %M since eipfmt does and is used in the kernel [sape] */
   90 
   91         cinit();
   92 }
   93 
   94 /*
   95  * Version is not multiplexed: message sent only once per connection.
   96  */
   97 long
   98 mntversion(Chan *c, char *version, int msize, int returnlen)
   99 {
  100         Fcall f;
  101         uchar *msg;
  102         Mnt *m;
  103         char *v;
  104         long k, l;
  105         uvlong oo;
  106         char buf[128];
  107 
  108         qlock(&c->umqlock);     /* make sure no one else does this until we've established ourselves */
  109         if(waserror()){
  110                 qunlock(&c->umqlock);
  111                 nexterror();
  112         }
  113 
  114         /* defaults */
  115         if(msize == 0)
  116                 msize = MAXRPC;
  117         if(msize > c->iounit && c->iounit != 0)
  118                 msize = c->iounit;
  119         v = version;
  120         if(v == nil || v[0] == '\0')
  121                 v = VERSION9P;
  122 
  123         /* validity */
  124         if(msize < 0)
  125                 error("bad iounit in version call");
  126         if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
  127                 error("bad 9P version specification");
  128 
  129         m = c->mux;
  130 
  131         if(m != nil){
  132                 qunlock(&c->umqlock);
  133                 poperror();
  134 
  135                 strecpy(buf, buf+sizeof buf, m->version);
  136                 k = strlen(buf);
  137                 if(strncmp(buf, v, k) != 0){
  138                         snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
  139                         error(buf);
  140                 }
  141                 if(returnlen > 0){
  142                         if(returnlen < k)
  143                                 error(Eshort);
  144                         memmove(version, buf, k);
  145                 }
  146                 return k;
  147         }
  148 
  149         f.type = Tversion;
  150         f.tag = NOTAG;
  151         f.msize = msize;
  152         f.version = v;
  153         msg = malloc(8192+IOHDRSZ);
  154         if(msg == nil)
  155                 exhausted("version memory");
  156         if(waserror()){
  157                 free(msg);
  158                 nexterror();
  159         }
  160         k = convS2M(&f, msg, 8192+IOHDRSZ);
  161         if(k == 0)
  162                 error("bad fversion conversion on send");
  163 
  164         lock(c);
  165         oo = c->offset;
  166         c->offset += k;
  167         unlock(c);
  168 
  169         l = devtab[c->type]->write(c, msg, k, oo);
  170 
  171         if(l < k){
  172                 lock(c);
  173                 c->offset -= k - l;
  174                 unlock(c);
  175                 error("short write in fversion");
  176         }
  177 
  178         /* message sent; receive and decode reply */
  179         k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
  180         if(k <= 0)
  181                 error("EOF receiving fversion reply");
  182 
  183         lock(c);
  184         c->offset += k;
  185         unlock(c);
  186 
  187         l = convM2S(msg, k, &f);
  188         if(l != k)
  189                 error("bad fversion conversion on reply");
  190         if(f.type != Rversion){
  191                 if(f.type == Rerror)
  192                         error(f.ename);
  193                 error("unexpected reply type in fversion");
  194         }
  195         if(f.msize > msize)
  196                 error("server tries to increase msize in fversion");
  197         if(f.msize<256 || f.msize>1024*1024)
  198                 error("nonsense value of msize in fversion");
  199         k = strlen(f.version);
  200         if(strncmp(f.version, v, k) != 0)
  201                 error("bad 9P version returned from server");
  202 
  203         /* now build Mnt associated with this connection */
  204         lock(&mntalloc);
  205         m = mntalloc.mntfree;
  206         if(m != 0)
  207                 mntalloc.mntfree = m->list;
  208         else {
  209                 m = malloc(sizeof(Mnt));
  210                 if(m == 0) {
  211                         unlock(&mntalloc);
  212                         exhausted("mount devices");
  213                 }
  214         }
  215         m->list = mntalloc.list;
  216         mntalloc.list = m;
  217         m->version = nil;
  218         kstrdup(&m->version, f.version);
  219         m->id = mntalloc.id++;
  220         m->q = qopen(10*MAXRPC, 0, nil, nil);
  221         m->msize = f.msize;
  222         unlock(&mntalloc);
  223 
  224         if(returnlen > 0){
  225                 if(returnlen < k)
  226                         error(Eshort);
  227                 memmove(version, f.version, k);
  228         }
  229 
  230         poperror();     /* msg */
  231         free(msg);
  232 
  233         lock(m);
  234         m->queue = 0;
  235         m->rip = 0;
  236 
  237         c->flag |= CMSG;
  238         c->mux = m;
  239         m->c = c;
  240         unlock(m);
  241 
  242         poperror();     /* c */
  243         qunlock(&c->umqlock);
  244 
  245         return k;
  246 }
  247 
  248 Chan*
  249 mntauth(Chan *c, char *spec)
  250 {
  251         Mnt *m;
  252         Mntrpc *r;
  253 
  254         m = c->mux;
  255 
  256         if(m == nil){
  257                 mntversion(c, VERSION9P, MAXRPC, 0);
  258                 m = c->mux;
  259                 if(m == nil)
  260                         error(Enoversion);
  261         }
  262 
  263         c = mntchan();
  264         if(waserror()) {
  265                 /* Close must not be called since it will
  266                  * call mnt recursively
  267                  */
  268                 chanfree(c);
  269                 nexterror();
  270         }
  271 
  272         r = mntralloc(0, m->msize);
  273 
  274         if(waserror()) {
  275                 mntfree(r);
  276                 nexterror();
  277         }
  278 
  279         r->request.type = Tauth;
  280         r->request.afid = c->fid;
  281         r->request.uname = up->user;
  282         r->request.aname = spec;
  283         mountrpc(m, r);
  284 
  285         c->qid = r->reply.aqid;
  286         c->mchan = m->c;
  287         incref(m->c);
  288         c->mqid = c->qid;
  289         c->mode = ORDWR;
  290 
  291         poperror();     /* r */
  292         mntfree(r);
  293 
  294         poperror();     /* c */
  295 
  296         return c;
  297 
  298 }
  299 
  300 static Chan*
  301 mntattach(char *muxattach)
  302 {
  303         Mnt *m;
  304         Chan *c;
  305         Mntrpc *r;
  306         struct bogus{
  307                 Chan    *chan;
  308                 Chan    *authchan;
  309                 char    *spec;
  310                 int     flags;
  311         }bogus;
  312 
  313         bogus = *((struct bogus *)muxattach);
  314         c = bogus.chan;
  315 
  316         m = c->mux;
  317 
  318         if(m == nil){
  319                 mntversion(c, nil, 0, 0);
  320                 m = c->mux;
  321                 if(m == nil)
  322                         error(Enoversion);
  323         }
  324 
  325         c = mntchan();
  326         if(waserror()) {
  327                 /* Close must not be called since it will
  328                  * call mnt recursively
  329                  */
  330                 chanfree(c);
  331                 nexterror();
  332         }
  333 
  334         r = mntralloc(0, m->msize);
  335 
  336         if(waserror()) {
  337                 mntfree(r);
  338                 nexterror();
  339         }
  340 
  341         r->request.type = Tattach;
  342         r->request.fid = c->fid;
  343         if(bogus.authchan == nil)
  344                 r->request.afid = NOFID;
  345         else
  346                 r->request.afid = bogus.authchan->fid;
  347         r->request.uname = up->user;
  348         r->request.aname = bogus.spec;
  349         mountrpc(m, r);
  350 
  351         c->qid = r->reply.qid;
  352         c->mchan = m->c;
  353         incref(m->c);
  354         c->mqid = c->qid;
  355 
  356         poperror();     /* r */
  357         mntfree(r);
  358 
  359         poperror();     /* c */
  360 
  361         if(bogus.flags&MCACHE)
  362                 c->flag |= CCACHE;
  363         return c;
  364 }
  365 
  366 Chan*
  367 mntchan(void)
  368 {
  369         Chan *c;
  370 
  371         c = devattach('M', 0);
  372         lock(&mntalloc);
  373         c->dev = mntalloc.id++;
  374         unlock(&mntalloc);
  375 
  376         if(c->mchan)
  377                 panic("mntchan non-zero %p", c->mchan);
  378         return c;
  379 }
  380 
  381 static Walkqid*
  382 mntwalk(Chan *c, Chan *nc, char **name, int nname)
  383 {
  384         int i, alloc;
  385         Mnt *m;
  386         Mntrpc *r;
  387         Walkqid *wq;
  388 
  389         if(nc != nil)
  390                 print("mntwalk: nc != nil\n");
  391         if(nname > MAXWELEM)
  392                 error("devmnt: too many name elements");
  393         alloc = 0;
  394         wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
  395         if(waserror()){
  396                 if(alloc && wq->clone!=nil)
  397                         cclose(wq->clone);
  398                 free(wq);
  399                 return nil;
  400         }
  401 
  402         alloc = 0;
  403         m = mntchk(c);
  404         r = mntralloc(c, m->msize);
  405         if(nc == nil){
  406                 nc = devclone(c);
  407                 /*
  408                  * Until the other side accepts this fid, we can't mntclose it.
  409                  * Therefore set type to 0 for now; rootclose is known to be safe.
  410                  */
  411                 nc->type = 0;
  412                 alloc = 1;
  413         }
  414         wq->clone = nc;
  415 
  416         if(waserror()) {
  417                 mntfree(r);
  418                 nexterror();
  419         }
  420         r->request.type = Twalk;
  421         r->request.fid = c->fid;
  422         r->request.newfid = nc->fid;
  423         r->request.nwname = nname;
  424         memmove(r->request.wname, name, nname*sizeof(char*));
  425 
  426         mountrpc(m, r);
  427 
  428         if(r->reply.nwqid > nname)
  429                 error("too many QIDs returned by walk");
  430         if(r->reply.nwqid < nname){
  431                 if(alloc)
  432                         cclose(nc);
  433                 wq->clone = nil;
  434                 if(r->reply.nwqid == 0){
  435                         free(wq);
  436                         wq = nil;
  437                         goto Return;
  438                 }
  439         }
  440 
  441         /* move new fid onto mnt device and update its qid */
  442         if(wq->clone != nil){
  443                 if(wq->clone != c){
  444                         wq->clone->type = c->type;
  445                         wq->clone->mchan = c->mchan;
  446                         incref(c->mchan);
  447                 }
  448                 if(r->reply.nwqid > 0)
  449                         wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
  450         }
  451         wq->nqid = r->reply.nwqid;
  452         for(i=0; i<wq->nqid; i++)
  453                 wq->qid[i] = r->reply.wqid[i];
  454 
  455     Return:
  456         poperror();
  457         mntfree(r);
  458         poperror();
  459         return wq;
  460 }
  461 
  462 static int
  463 mntstat(Chan *c, uchar *dp, int n)
  464 {
  465         Mnt *m;
  466         Mntrpc *r;
  467 
  468         if(n < BIT16SZ)
  469                 error(Eshortstat);
  470         m = mntchk(c);
  471         r = mntralloc(c, m->msize);
  472         if(waserror()) {
  473                 mntfree(r);
  474                 nexterror();
  475         }
  476         r->request.type = Tstat;
  477         r->request.fid = c->fid;
  478         mountrpc(m, r);
  479 
  480         if(r->reply.nstat > n){
  481                 n = BIT16SZ;
  482                 PBIT16((uchar*)dp, r->reply.nstat-2);
  483         }else{
  484                 n = r->reply.nstat;
  485                 memmove(dp, r->reply.stat, n);
  486                 validstat(dp, n);
  487                 mntdirfix(dp, c);
  488         }
  489         poperror();
  490         mntfree(r);
  491         return n;
  492 }
  493 
  494 static Chan*
  495 mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
  496 {
  497         Mnt *m;
  498         Mntrpc *r;
  499 
  500         m = mntchk(c);
  501         r = mntralloc(c, m->msize);
  502         if(waserror()) {
  503                 mntfree(r);
  504                 nexterror();
  505         }
  506         r->request.type = type;
  507         r->request.fid = c->fid;
  508         r->request.mode = omode;
  509         if(type == Tcreate){
  510                 r->request.perm = perm;
  511                 r->request.name = name;
  512         }
  513         mountrpc(m, r);
  514 
  515         c->qid = r->reply.qid;
  516         c->offset = 0;
  517         c->mode = openmode(omode);
  518         c->iounit = r->reply.iounit;
  519         if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
  520                 c->iounit = m->msize-IOHDRSZ;
  521         c->flag |= COPEN;
  522         poperror();
  523         mntfree(r);
  524 
  525         if(c->flag & CCACHE)
  526                 copen(c);
  527 
  528         return c;
  529 }
  530 
  531 static Chan*
  532 mntopen(Chan *c, int omode)
  533 {
  534         return mntopencreate(Topen, c, nil, omode, 0);
  535 }
  536 
  537 static void
  538 mntcreate(Chan *c, char *name, int omode, ulong perm)
  539 {
  540         mntopencreate(Tcreate, c, name, omode, perm);
  541 }
  542 
  543 static void
  544 mntclunk(Chan *c, int t)
  545 {
  546         Mnt *m;
  547         Mntrpc *r;
  548 
  549         m = mntchk(c);
  550         r = mntralloc(c, m->msize);
  551         if(waserror()){
  552                 mntfree(r);
  553                 nexterror();
  554         }
  555 
  556         r->request.type = t;
  557         r->request.fid = c->fid;
  558         mountrpc(m, r);
  559         mntfree(r);
  560         poperror();
  561 }
  562 
  563 void
  564 muxclose(Mnt *m)
  565 {
  566         Mntrpc *q, *r;
  567 
  568         for(q = m->queue; q; q = r) {
  569                 r = q->list;
  570                 mntfree(q);
  571         }
  572         m->id = 0;
  573         free(m->version);
  574         m->version = nil;
  575         mntpntfree(m);
  576 }
  577 
  578 void
  579 mntpntfree(Mnt *m)
  580 {
  581         Mnt *f, **l;
  582         Queue *q;
  583 
  584         lock(&mntalloc);
  585         l = &mntalloc.list;
  586         for(f = *l; f; f = f->list) {
  587                 if(f == m) {
  588                         *l = m->list;
  589                         break;
  590                 }
  591                 l = &f->list;
  592         }
  593         m->list = mntalloc.mntfree;
  594         mntalloc.mntfree = m;
  595         q = m->q;
  596         unlock(&mntalloc);
  597 
  598         qfree(q);
  599 }
  600 
  601 static void
  602 mntclose(Chan *c)
  603 {
  604         mntclunk(c, Tclunk);
  605 }
  606 
  607 static void
  608 mntremove(Chan *c)
  609 {
  610         mntclunk(c, Tremove);
  611 }
  612 
  613 static int
  614 mntwstat(Chan *c, uchar *dp, int n)
  615 {
  616         Mnt *m;
  617         Mntrpc *r;
  618 
  619         m = mntchk(c);
  620         r = mntralloc(c, m->msize);
  621         if(waserror()) {
  622                 mntfree(r);
  623                 nexterror();
  624         }
  625         r->request.type = Twstat;
  626         r->request.fid = c->fid;
  627         r->request.nstat = n;
  628         r->request.stat = dp;
  629         mountrpc(m, r);
  630         poperror();
  631         mntfree(r);
  632         return n;
  633 }
  634 
  635 static long
  636 mntread(Chan *c, void *buf, long n, vlong off)
  637 {
  638         uchar *p, *e;
  639         int nc, cache, isdir, dirlen;
  640 
  641         isdir = 0;
  642         cache = c->flag & CCACHE;
  643         if(c->qid.type & QTDIR) {
  644                 cache = 0;
  645                 isdir = 1;
  646         }
  647 
  648         p = buf;
  649         if(cache) {
  650                 nc = cread(c, buf, n, off);
  651                 if(nc > 0) {
  652                         n -= nc;
  653                         if(n == 0)
  654                                 return nc;
  655                         p += nc;
  656                         off += nc;
  657                 }
  658                 n = mntrdwr(Tread, c, p, n, off);
  659                 cupdate(c, p, n, off);
  660                 return n + nc;
  661         }
  662 
  663         n = mntrdwr(Tread, c, buf, n, off);
  664         if(isdir) {
  665                 for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
  666                         dirlen = BIT16SZ+GBIT16(p);
  667                         if(p+dirlen > e)
  668                                 break;
  669                         validstat(p, dirlen);
  670                         mntdirfix(p, c);
  671                 }
  672                 if(p != e)
  673                         error(Esbadstat);
  674         }
  675         return n;
  676 }
  677 
  678 static long
  679 mntwrite(Chan *c, void *buf, long n, vlong off)
  680 {
  681         return mntrdwr(Twrite, c, buf, n, off);
  682 }
  683 
  684 long
  685 mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
  686 {
  687         Mnt *m;
  688         Mntrpc *r;
  689         char *uba;
  690         int cache;
  691         ulong cnt, nr, nreq;
  692 
  693         m = mntchk(c);
  694         uba = buf;
  695         cnt = 0;
  696         cache = c->flag & CCACHE;
  697         if(c->qid.type & QTDIR)
  698                 cache = 0;
  699         for(;;) {
  700                 r = mntralloc(c, m->msize);
  701                 if(waserror()) {
  702                         mntfree(r);
  703                         nexterror();
  704                 }
  705                 r->request.type = type;
  706                 r->request.fid = c->fid;
  707                 r->request.offset = off;
  708                 r->request.data = uba;
  709                 nr = n;
  710                 if(nr > m->msize-IOHDRSZ)
  711                         nr = m->msize-IOHDRSZ;
  712                 r->request.count = nr;
  713                 mountrpc(m, r);
  714                 nreq = r->request.count;
  715                 nr = r->reply.count;
  716                 if(nr > nreq)
  717                         nr = nreq;
  718 
  719                 if(type == Tread)
  720                         r->b = bl2mem((uchar*)uba, r->b, nr);
  721                 else if(cache)
  722                         cwrite(c, (uchar*)uba, nr, off);
  723 
  724                 poperror();
  725                 mntfree(r);
  726                 off += nr;
  727                 uba += nr;
  728                 cnt += nr;
  729                 n -= nr;
  730                 if(nr != nreq || n == 0 || up->nnote)
  731                         break;
  732         }
  733         return cnt;
  734 }
  735 
  736 void
  737 mountrpc(Mnt *m, Mntrpc *r)
  738 {
  739         char *sn, *cn;
  740         int t;
  741 
  742         r->reply.tag = 0;
  743         r->reply.type = Tmax;   /* can't ever be a valid message type */
  744 
  745         mountio(m, r);
  746 
  747         t = r->reply.type;
  748         switch(t) {
  749         case Rerror:
  750                 error(r->reply.ename);
  751         case Rflush:
  752                 error(Eintr);
  753         default:
  754                 if(t == r->request.type+1)
  755                         break;
  756                 sn = "?";
  757                 if(m->c->path != nil)
  758                         sn = m->c->path->s;
  759                 cn = "?";
  760                 if(r->c != nil && r->c->path != nil)
  761                         cn = r->c->path->s;
  762                 print("mnt: proc %s %lud: mismatch from %s %s rep %#p tag %d fid %d T%d R%d rp %d\n",
  763                         up->text, up->pid, sn, cn,
  764                         r, r->request.tag, r->request.fid, r->request.type,
  765                         r->reply.type, r->reply.tag);
  766                 error(Emountrpc);
  767         }
  768 }
  769 
  770 void
  771 mountio(Mnt *m, Mntrpc *r)
  772 {
  773         int n;
  774 
  775         while(waserror()) {
  776                 if(m->rip == up)
  777                         mntgate(m);
  778                 if(strcmp(up->errstr, Eintr) != 0){
  779                         mntflushfree(m, r);
  780                         nexterror();
  781                 }
  782                 r = mntflushalloc(r, m->msize);
  783         }
  784 
  785         lock(m);
  786         r->m = m;
  787         r->list = m->queue;
  788         m->queue = r;
  789         unlock(m);
  790 
  791         /* Transmit a file system rpc */
  792         if(m->msize == 0)
  793                 panic("msize");
  794         n = convS2M(&r->request, r->rpc, m->msize);
  795         if(n < 0)
  796                 panic("bad message type in mountio");
  797         if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
  798                 error(Emountrpc);
  799         r->stime = fastticks(nil);
  800         r->reqlen = n;
  801 
  802         /* Gate readers onto the mount point one at a time */
  803         for(;;) {
  804                 lock(m);
  805                 if(m->rip == 0)
  806                         break;
  807                 unlock(m);
  808                 sleep(&r->r, rpcattn, r);
  809                 if(r->done){
  810                         poperror();
  811                         mntflushfree(m, r);
  812                         return;
  813                 }
  814         }
  815         m->rip = up;
  816         unlock(m);
  817         while(r->done == 0) {
  818                 if(mntrpcread(m, r) < 0)
  819                         error(Emountrpc);
  820                 mountmux(m, r);
  821         }
  822         mntgate(m);
  823         poperror();
  824         mntflushfree(m, r);
  825 }
  826 
  827 static int
  828 doread(Mnt *m, int len)
  829 {
  830         Block *b;
  831 
  832         while(qlen(m->q) < len){
  833                 b = devtab[m->c->type]->bread(m->c, m->msize, 0);
  834                 if(b == nil)
  835                         return -1;
  836                 if(blocklen(b) == 0){
  837                         freeblist(b);
  838                         return -1;
  839                 }
  840                 qaddlist(m->q, b);
  841         }
  842         return 0;
  843 }
  844 
  845 int
  846 mntrpcread(Mnt *m, Mntrpc *r)
  847 {
  848         int i, t, len, hlen;
  849         Block *b, **l, *nb;
  850 
  851         r->reply.type = 0;
  852         r->reply.tag = 0;
  853 
  854         /* read at least length, type, and tag and pullup to a single block */
  855         if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
  856                 return -1;
  857         nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
  858 
  859         /* read in the rest of the message, avoid ridiculous (for now) message sizes */
  860         len = GBIT32(nb->rp);
  861         if(len > m->msize){
  862                 qdiscard(m->q, qlen(m->q));
  863                 return -1;
  864         }
  865         if(doread(m, len) < 0)
  866                 return -1;
  867 
  868         /* pullup the header (i.e. everything except data) */
  869         t = nb->rp[BIT32SZ];
  870         switch(t){
  871         case Rread:
  872                 hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
  873                 break;
  874         default:
  875                 hlen = len;
  876                 break;
  877         }
  878         nb = pullupqueue(m->q, hlen);
  879 
  880         if(convM2S(nb->rp, len, &r->reply) <= 0){
  881                 /* bad message, dump it */
  882                 print("mntrpcread: convM2S failed\n");
  883                 qdiscard(m->q, len);
  884                 return -1;
  885         }
  886 
  887         /* hang the data off of the fcall struct */
  888         l = &r->b;
  889         *l = nil;
  890         do {
  891                 b = qremove(m->q);
  892                 if(hlen > 0){
  893                         b->rp += hlen;
  894                         len -= hlen;
  895                         hlen = 0;
  896                 }
  897                 i = BLEN(b);
  898                 if(i <= len){
  899                         len -= i;
  900                         *l = b;
  901                         l = &(b->next);
  902                 } else {
  903                         /* split block and put unused bit back */
  904                         nb = allocb(i-len);
  905                         memmove(nb->wp, b->rp+len, i-len);
  906                         b->wp = b->rp+len;
  907                         nb->wp += i-len;
  908                         qputback(m->q, nb);
  909                         *l = b;
  910                         return 0;
  911                 }
  912         }while(len > 0);
  913 
  914         return 0;
  915 }
  916 
  917 void
  918 mntgate(Mnt *m)
  919 {
  920         Mntrpc *q;
  921 
  922         lock(m);
  923         m->rip = 0;
  924         for(q = m->queue; q; q = q->list) {
  925                 if(q->done == 0)
  926                 if(wakeup(&q->r))
  927                         break;
  928         }
  929         unlock(m);
  930 }
  931 
  932 void
  933 mountmux(Mnt *m, Mntrpc *r)
  934 {
  935         Mntrpc **l, *q;
  936 
  937         lock(m);
  938         l = &m->queue;
  939         for(q = *l; q; q = q->list) {
  940                 /* look for a reply to a message */
  941                 if(q->request.tag == r->reply.tag) {
  942                         *l = q->list;
  943                         if(q != r) {
  944                                 /*
  945                                  * Completed someone else.
  946                                  * Trade pointers to receive buffer.
  947                                  */
  948                                 q->reply = r->reply;
  949                                 q->b = r->b;
  950                                 r->b = nil;
  951                         }
  952                         q->done = 1;
  953                         unlock(m);
  954                         if(mntstats != nil)
  955                                 (*mntstats)(q->request.type,
  956                                         m->c, q->stime,
  957                                         q->reqlen + r->replen);
  958                         if(q != r)
  959                                 wakeup(&q->r);
  960                         return;
  961                 }
  962                 l = &q->list;
  963         }
  964         unlock(m);
  965         print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
  966 }
  967 
  968 /*
  969  * Create a new flush request and chain the previous
  970  * requests from it
  971  */
  972 Mntrpc*
  973 mntflushalloc(Mntrpc *r, ulong iounit)
  974 {
  975         Mntrpc *fr;
  976 
  977         fr = mntralloc(0, iounit);
  978 
  979         fr->request.type = Tflush;
  980         if(r->request.type == Tflush)
  981                 fr->request.oldtag = r->request.oldtag;
  982         else
  983                 fr->request.oldtag = r->request.tag;
  984         fr->flushed = r;
  985 
  986         return fr;
  987 }
  988 
  989 /*
  990  *  Free a chain of flushes.  Remove each unanswered
  991  *  flush and the original message from the unanswered
  992  *  request queue.  Mark the original message as done
  993  *  and if it hasn't been answered set the reply to to
  994  *  Rflush.
  995  */
  996 void
  997 mntflushfree(Mnt *m, Mntrpc *r)
  998 {
  999         Mntrpc *fr;
 1000 
 1001         while(r){
 1002                 fr = r->flushed;
 1003                 if(!r->done){
 1004                         r->reply.type = Rflush;
 1005                         mntqrm(m, r);
 1006                 }
 1007                 if(fr)
 1008                         mntfree(r);
 1009                 r = fr;
 1010         }
 1011 }
 1012 
 1013 int
 1014 alloctag(void)
 1015 {
 1016         int i, j;
 1017         ulong v;
 1018 
 1019         for(i = 0; i < NMASK; i++){
 1020                 v = mntalloc.tagmask[i];
 1021                 if(v == ~0UL)
 1022                         continue;
 1023                 for(j = 0; j < 1<<TAGSHIFT; j++)
 1024                         if((v & (1<<j)) == 0){
 1025                                 mntalloc.tagmask[i] |= 1<<j;
 1026                                 return (i<<TAGSHIFT) + j;
 1027                         }
 1028         }
 1029         panic("no friggin tags left");
 1030         return NOTAG;
 1031 }
 1032 
 1033 void
 1034 freetag(int t)
 1035 {
 1036         mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
 1037 }
 1038 
 1039 Mntrpc*
 1040 mntralloc(Chan *c, ulong msize)
 1041 {
 1042         Mntrpc *new;
 1043 
 1044         lock(&mntalloc);
 1045         new = mntalloc.rpcfree;
 1046         if(new == nil){
 1047                 new = malloc(sizeof(Mntrpc));
 1048                 if(new == nil) {
 1049                         unlock(&mntalloc);
 1050                         exhausted("mount rpc header");
 1051                 }
 1052                 /*
 1053                  * The header is split from the data buffer as
 1054                  * mountmux may swap the buffer with another header.
 1055                  */
 1056                 new->rpc = mallocz(msize, 0);
 1057                 if(new->rpc == nil){
 1058                         free(new);
 1059                         unlock(&mntalloc);
 1060                         exhausted("mount rpc buffer");
 1061                 }
 1062                 new->rpclen = msize;
 1063                 new->request.tag = alloctag();
 1064         }
 1065         else {
 1066                 mntalloc.rpcfree = new->list;
 1067                 mntalloc.nrpcfree--;
 1068                 if(new->rpclen < msize){
 1069                         free(new->rpc);
 1070                         new->rpc = mallocz(msize, 0);
 1071                         if(new->rpc == nil){
 1072                                 free(new);
 1073                                 mntalloc.nrpcused--;
 1074                                 unlock(&mntalloc);
 1075                                 exhausted("mount rpc buffer");
 1076                         }
 1077                         new->rpclen = msize;
 1078                 }
 1079         }
 1080         mntalloc.nrpcused++;
 1081         unlock(&mntalloc);
 1082         new->c = c;
 1083         new->done = 0;
 1084         new->flushed = nil;
 1085         new->b = nil;
 1086         return new;
 1087 }
 1088 
 1089 void
 1090 mntfree(Mntrpc *r)
 1091 {
 1092         if(r->b != nil)
 1093                 freeblist(r->b);
 1094         lock(&mntalloc);
 1095         if(mntalloc.nrpcfree >= 10){
 1096                 free(r->rpc);
 1097                 free(r);
 1098                 freetag(r->request.tag);
 1099         }
 1100         else{
 1101                 r->list = mntalloc.rpcfree;
 1102                 mntalloc.rpcfree = r;
 1103                 mntalloc.nrpcfree++;
 1104         }
 1105         mntalloc.nrpcused--;
 1106         unlock(&mntalloc);
 1107 }
 1108 
 1109 void
 1110 mntqrm(Mnt *m, Mntrpc *r)
 1111 {
 1112         Mntrpc **l, *f;
 1113 
 1114         lock(m);
 1115         r->done = 1;
 1116 
 1117         l = &m->queue;
 1118         for(f = *l; f; f = f->list) {
 1119                 if(f == r) {
 1120                         *l = r->list;
 1121                         break;
 1122                 }
 1123                 l = &f->list;
 1124         }
 1125         unlock(m);
 1126 }
 1127 
 1128 Mnt*
 1129 mntchk(Chan *c)
 1130 {
 1131         Mnt *m;
 1132 
 1133         /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
 1134 
 1135         if(c->mchan == nil)
 1136                 panic("mntchk 1: nil mchan c %s\n", chanpath(c));
 1137 
 1138         m = c->mchan->mux;
 1139 
 1140         if(m == nil)
 1141                 print("mntchk 2: nil mux c %s c->mchan %s \n", chanpath(c), chanpath(c->mchan));
 1142 
 1143         /*
 1144          * Was it closed and reused (was error(Eshutdown); now, it cannot happen)
 1145          */
 1146         if(m->id == 0 || m->id >= c->dev)
 1147                 panic("mntchk 3: can't happen");
 1148 
 1149         return m;
 1150 }
 1151 
 1152 /*
 1153  * Rewrite channel type and dev for in-flight data to
 1154  * reflect local values.  These entries are known to be
 1155  * the first two in the Dir encoding after the count.
 1156  */
 1157 void
 1158 mntdirfix(uchar *dirbuf, Chan *c)
 1159 {
 1160         uint r;
 1161 
 1162         r = devtab[c->type]->dc;
 1163         dirbuf += BIT16SZ;      /* skip count */
 1164         PBIT16(dirbuf, r);
 1165         dirbuf += BIT16SZ;
 1166         PBIT32(dirbuf, c->dev);
 1167 }
 1168 
 1169 int
 1170 rpcattn(void *v)
 1171 {
 1172         Mntrpc *r;
 1173 
 1174         r = v;
 1175         return r->done || r->m->rip == 0;
 1176 }
 1177 
 1178 Dev mntdevtab = {
 1179         'M',
 1180         "mnt",
 1181 
 1182         mntreset,
 1183         devinit,
 1184         devshutdown,
 1185         mntattach,
 1186         mntwalk,
 1187         mntstat,
 1188         mntopen,
 1189         mntcreate,
 1190         mntclose,
 1191         mntread,
 1192         devbread,
 1193         mntwrite,
 1194         devbwrite,
 1195         mntremove,
 1196         mntwstat,
 1197 };

Cache object: 94a5340ca147f55e33f53437570f77f4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.