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/devloopback.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 typedef struct Link     Link;
    9 typedef struct Loop     Loop;
   10 
   11 struct Link
   12 {
   13         Lock;
   14 
   15         int     ref;
   16 
   17         long    packets;        /* total number of packets sent */
   18         long    bytes;          /* total number of bytes sent */
   19         int     indrop;         /* enable dropping on iq overflow */
   20         long    soverflows;     /* packets dropped because iq overflowed */
   21         long    droprate;       /* drop 1/droprate packets in tq */
   22         long    drops;          /* packets deliberately dropped */
   23 
   24         vlong   delay0ns;       /* nanosec of delay in the link */
   25         long    delaynns;       /* nanosec of delay per byte */
   26 
   27         Block   *tq;            /* transmission queue */
   28         Block   *tqtail;
   29         vlong   tout;           /* time the last packet in tq is really out */
   30         vlong   tin;            /* time the head packet in tq enters the remote side  */
   31 
   32         long    limit;          /* queue buffering limit */
   33         Queue   *oq;            /* output queue from other side & packets in the link */
   34         Queue   *iq;
   35 
   36         Timer   ci;             /* time to move packets from  next packet from oq */
   37 };
   38 
   39 struct Loop
   40 {
   41         QLock;
   42         int     ref;
   43         int     minmtu;         /* smallest block transmittable */
   44         Loop    *next;
   45         ulong   path;
   46         Link    link[2];
   47 };
   48 
   49 static struct
   50 {
   51         Lock;
   52         ulong   path;
   53 } loopbackalloc;
   54 
   55 enum
   56 {
   57         Qtopdir=        1,              /* top level directory */
   58 
   59         Qloopdir,                       /* loopback* directory */
   60 
   61         Qportdir,                       /* directory each end of the loop */
   62         Qctl,
   63         Qstatus,
   64         Qstats,
   65         Qdata,
   66 
   67         MaxQ,
   68 
   69         Nloopbacks      = 5,
   70 
   71         Statelen        = 23*1024,      /* status buffer size */
   72 
   73         Tmsize          = 8,
   74         Delayn          = 10000,        /* default delays in ns */
   75         Delay0          = 2500000,
   76 
   77         Loopqlim        = 32*1024,      /* default size of queues */
   78 };
   79 
   80 static Dirtab loopportdir[] =
   81 {
   82         "ctl",          {Qctl},         0,                      0222,
   83         "status",       {Qstatus},      0,                      0444,
   84         "stats",        {Qstats},       0,                      0444,
   85         "data",         {Qdata},        0,                      0666,
   86 };
   87 static Dirtab loopdirs[MaxQ];
   88 
   89 static Loop     loopbacks[Nloopbacks];
   90 
   91 #define TYPE(x)         (((ulong)(x))&0xff)
   92 #define ID(x)           (((ulong)(x))>>8)
   93 #define QID(x,y)        ((((ulong)(x))<<8)|((ulong)(y)))
   94 
   95 static void     looper(Loop *lb);
   96 static long     loopoput(Loop *lb, Link *link, Block *bp);
   97 static void     ptime(uchar *p, vlong t);
   98 static vlong    gtime(uchar *p);
   99 static void     closelink(Link *link, int dofree);
  100 static void     pushlink(Link *link, vlong now);
  101 static void     freelb(Loop *lb);
  102 static void     linkintr(Ureg*, Timer *ci);
  103 
  104 static void
  105 loopbackinit(void)
  106 {
  107         int i;
  108 
  109         for(i = 0; i < Nloopbacks; i++)
  110                 loopbacks[i].path = i;
  111 
  112         /* invert directory tables for non-directory entries */
  113         for(i=0; i<nelem(loopportdir); i++)
  114                 loopdirs[loopportdir[i].qid.path] = loopportdir[i];
  115 }
  116 
  117 static Chan*
  118 loopbackattach(char *spec)
  119 {
  120         Loop *volatile lb;
  121         Queue *q;
  122         Chan *c;
  123         int chan;
  124         int dev;
  125 
  126         dev = 0;
  127         if(spec != nil){
  128                 dev = atoi(spec);
  129                 if(dev >= Nloopbacks)
  130                         error(Ebadspec);
  131         }
  132 
  133         c = devattach('X', spec);
  134         lb = &loopbacks[dev];
  135 
  136         qlock(lb);
  137         if(waserror()){
  138                 lb->ref--;
  139                 qunlock(lb);
  140                 nexterror();
  141         }
  142 
  143         lb->ref++;
  144         if(lb->ref == 1){
  145                 for(chan = 0; chan < 2; chan++){
  146                         lb->link[chan].ci.mode = Trelative;
  147                         lb->link[chan].ci.a = &lb->link[chan];
  148                         lb->link[chan].ci.f = linkintr;
  149                         lb->link[chan].limit = Loopqlim;
  150                         q = qopen(lb->link[chan].limit, 0, 0, 0);
  151                         lb->link[chan].iq = q;
  152                         if(q == nil){
  153                                 freelb(lb);
  154                                 exhausted("memory");
  155                         }
  156                         q = qopen(lb->link[chan].limit, 0, 0, 0);
  157                         lb->link[chan].oq = q;
  158                         if(q == nil){
  159                                 freelb(lb);
  160                                 exhausted("memory");
  161                         }
  162                         lb->link[chan].indrop = 1;
  163 
  164                         lb->link[chan].delaynns = Delayn;
  165                         lb->link[chan].delay0ns = Delay0;
  166                 }
  167         }
  168         poperror();
  169         qunlock(lb);
  170 
  171         mkqid(&c->qid, QID(0, Qtopdir), 0, QTDIR);
  172         c->aux = lb;
  173         c->dev = dev;
  174         return c;
  175 }
  176 
  177 static int
  178 loopbackgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp)
  179 {
  180         Dirtab *tab;
  181         int len, type;
  182         Qid qid;
  183 
  184         type = TYPE(c->qid.path);
  185         if(i == DEVDOTDOT){
  186                 switch(type){
  187                 case Qtopdir:
  188                 case Qloopdir:
  189                         snprint(up->genbuf, sizeof(up->genbuf), "#X%ld", c->dev);
  190                         mkqid(&qid, QID(0, Qtopdir), 0, QTDIR);
  191                         devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
  192                         break;
  193                 case Qportdir:
  194                         snprint(up->genbuf, sizeof(up->genbuf), "loopback%ld", c->dev);
  195                         mkqid(&qid, QID(0, Qloopdir), 0, QTDIR);
  196                         devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
  197                         break;
  198                 default:
  199                         panic("loopbackgen %llux", c->qid.path);
  200                 }
  201                 return 1;
  202         }
  203 
  204         switch(type){
  205         case Qtopdir:
  206                 if(i != 0)
  207                         return -1;
  208                 snprint(up->genbuf, sizeof(up->genbuf), "loopback%ld", c->dev);
  209                 mkqid(&qid, QID(0, Qloopdir), 0, QTDIR);
  210                 devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
  211                 return 1;
  212         case Qloopdir:
  213                 if(i >= 2)
  214                         return -1;
  215                 snprint(up->genbuf, sizeof(up->genbuf), "%d", i);
  216                 mkqid(&qid, QID(i, QID(0, Qportdir)), 0, QTDIR);
  217                 devdir(c, qid, up->genbuf, 0, eve, 0555, dp);
  218                 return 1;
  219         case Qportdir:
  220                 if(i >= nelem(loopportdir))
  221                         return -1;
  222                 tab = &loopportdir[i];
  223                 mkqid(&qid, QID(ID(c->qid.path), tab->qid.path), 0, QTFILE);
  224                 devdir(c, qid, tab->name, tab->length, eve, tab->perm, dp);
  225                 return 1;
  226         default:
  227                 /* non directory entries end up here; must be in lowest level */
  228                 if(c->qid.type & QTDIR)
  229                         panic("loopbackgen: unexpected directory");     
  230                 if(i != 0)
  231                         return -1;
  232                 tab = &loopdirs[type];
  233                 if(tab == nil)
  234                         panic("loopbackgen: unknown type: %d", type);
  235                 len = tab->length;
  236                 devdir(c, c->qid, tab->name, len, eve, tab->perm, dp);
  237                 return 1;
  238         }
  239 }
  240 
  241 
  242 static Walkqid*
  243 loopbackwalk(Chan *c, Chan *nc, char **name, int nname)
  244 {
  245         Walkqid *wq;
  246         Loop *lb;
  247 
  248         wq = devwalk(c, nc, name, nname, nil, 0, loopbackgen);
  249         if(wq != nil && wq->clone != nil && wq->clone != c){
  250                 lb = c->aux;
  251                 qlock(lb);
  252                 lb->ref++;
  253                 if((c->flag & COPEN) && TYPE(c->qid.path) == Qdata)
  254                         lb->link[ID(c->qid.path)].ref++;
  255                 qunlock(lb);
  256         }
  257         return wq;
  258 }
  259 
  260 static int
  261 loopbackstat(Chan *c, uchar *db, int n)
  262 {
  263         return devstat(c, db, n, nil, 0, loopbackgen);
  264 }
  265 
  266 /*
  267  *  if the stream doesn't exist, create it
  268  */
  269 static Chan*
  270 loopbackopen(Chan *c, int omode)
  271 {
  272         Loop *lb;
  273 
  274         if(c->qid.type & QTDIR){
  275                 if(omode != OREAD)
  276                         error(Ebadarg);
  277                 c->mode = omode;
  278                 c->flag |= COPEN;
  279                 c->offset = 0;
  280                 return c;
  281         }
  282 
  283         lb = c->aux;
  284         qlock(lb);
  285         if(TYPE(c->qid.path) == Qdata){
  286                 if(lb->link[ID(c->qid.path)].ref){
  287                         qunlock(lb);
  288                         error(Einuse);
  289                 }
  290                 lb->link[ID(c->qid.path)].ref++;
  291         }
  292         qunlock(lb);
  293 
  294         c->mode = openmode(omode);
  295         c->flag |= COPEN;
  296         c->offset = 0;
  297         c->iounit = qiomaxatomic;
  298         return c;
  299 }
  300 
  301 static void
  302 loopbackclose(Chan *c)
  303 {
  304         Loop *lb;
  305         int ref, chan;
  306 
  307         lb = c->aux;
  308 
  309         qlock(lb);
  310 
  311         /*
  312          * closing either side hangs up the stream
  313          */
  314         if((c->flag & COPEN) && TYPE(c->qid.path) == Qdata){
  315                 chan = ID(c->qid.path);
  316                 if(--lb->link[chan].ref == 0){
  317                         qhangup(lb->link[chan ^ 1].oq, nil);
  318                         looper(lb);
  319                 }
  320         }
  321 
  322 
  323         /*
  324          *  if both sides are closed, they are reusable
  325          */
  326         if(lb->link[0].ref == 0 && lb->link[1].ref == 0){
  327                 for(chan = 0; chan < 2; chan++){
  328                         closelink(&lb->link[chan], 0);
  329                         qreopen(lb->link[chan].iq);
  330                         qreopen(lb->link[chan].oq);
  331                         qsetlimit(lb->link[chan].oq, lb->link[chan].limit);
  332                         qsetlimit(lb->link[chan].iq, lb->link[chan].limit);
  333                 }
  334         }
  335         ref = --lb->ref;
  336         if(ref == 0)
  337                 freelb(lb);
  338         qunlock(lb);
  339 }
  340 
  341 static void
  342 freelb(Loop *lb)
  343 {
  344         int chan;
  345 
  346         for(chan = 0; chan < 2; chan++)
  347                 closelink(&lb->link[chan], 1);
  348 }
  349 
  350 /*
  351  * called with the Loop qlocked,
  352  * so only pushlink can mess with the queues
  353  */
  354 static void
  355 closelink(Link *link, int dofree)
  356 {
  357         Queue *iq, *oq;
  358         Block *bp;
  359 
  360         ilock(link);
  361         iq = link->iq;
  362         oq = link->oq;
  363         bp = link->tq;
  364         link->tq = nil;
  365         link->tqtail = nil;
  366         link->tout = 0;
  367         link->tin = 0;
  368         timerdel(&link->ci);
  369         iunlock(link);
  370         if(iq != nil){
  371                 qclose(iq);
  372                 if(dofree){
  373                         ilock(link);
  374                         free(iq);
  375                         link->iq = nil;
  376                         iunlock(link);
  377                 }
  378         }
  379         if(oq != nil){
  380                 qclose(oq);
  381                 if(dofree){
  382                         ilock(link);
  383                         free(oq);
  384                         link->oq = nil;
  385                         iunlock(link);
  386                 }
  387         }
  388         freeblist(bp);
  389 }
  390 
  391 static long
  392 loopbackread(Chan *c, void *va, long n, vlong offset)
  393 {
  394         Loop *lb;
  395         Link *link;
  396         char *buf;
  397         long rv;
  398 
  399         lb = c->aux;
  400         switch(TYPE(c->qid.path)){
  401         default:
  402                 error(Eperm);
  403                 return -1;      /* not reached */
  404         case Qtopdir:
  405         case Qloopdir:
  406         case Qportdir:
  407                 return devdirread(c, va, n, nil, 0, loopbackgen);
  408         case Qdata:
  409                 return qread(lb->link[ID(c->qid.path)].iq, va, n);
  410         case Qstatus:
  411                 link = &lb->link[ID(c->qid.path)];
  412                 buf = smalloc(Statelen);
  413                 rv = snprint(buf, Statelen, "delay %lld %ld\n", link->delay0ns, link->delaynns);
  414                 rv += snprint(buf+rv, Statelen-rv, "limit %ld\n", link->limit);
  415                 rv += snprint(buf+rv, Statelen-rv, "indrop %d\n", link->indrop);
  416                 snprint(buf+rv, Statelen-rv, "droprate %ld\n", link->droprate);
  417                 rv = readstr(offset, va, n, buf);
  418                 free(buf);
  419                 break;
  420         case Qstats:
  421                 link = &lb->link[ID(c->qid.path)];
  422                 buf = smalloc(Statelen);
  423                 rv = snprint(buf, Statelen, "packets: %ld\n", link->packets);
  424                 rv += snprint(buf+rv, Statelen-rv, "bytes: %ld\n", link->bytes);
  425                 rv += snprint(buf+rv, Statelen-rv, "dropped: %ld\n", link->drops);
  426                 snprint(buf+rv, Statelen-rv, "soft overflows: %ld\n", link->soverflows);
  427                 rv = readstr(offset, va, n, buf);
  428                 free(buf);
  429                 break;
  430         }
  431         return rv;
  432 }
  433 
  434 static Block*
  435 loopbackbread(Chan *c, long n, ulong offset)
  436 {
  437         Loop *lb;
  438 
  439         lb = c->aux;
  440         if(TYPE(c->qid.path) == Qdata)
  441                 return qbread(lb->link[ID(c->qid.path)].iq, n);
  442 
  443         return devbread(c, n, offset);
  444 }
  445 
  446 static long
  447 loopbackbwrite(Chan *c, Block *bp, ulong off)
  448 {
  449         Loop *lb;
  450 
  451         lb = c->aux;
  452         if(TYPE(c->qid.path) == Qdata)
  453                 return loopoput(lb, &lb->link[ID(c->qid.path) ^ 1], bp);
  454         return devbwrite(c, bp, off);
  455 }
  456 
  457 static long
  458 loopbackwrite(Chan *c, void *va, long n, vlong off)
  459 {
  460         Loop *lb;
  461         Link *link;
  462         Cmdbuf *volatile cb;
  463         Block *volatile bp;
  464         vlong d0, d0ns;
  465         long dn, dnns;
  466 
  467         switch(TYPE(c->qid.path)){
  468         case Qdata:
  469                 bp = allocb(n);
  470                 if(waserror()){
  471                         freeb(bp);
  472                         nexterror();
  473                 }
  474                 memmove(bp->wp, va, n);
  475                 poperror();
  476                 bp->wp += n;
  477                 return loopbackbwrite(c, bp, off);
  478         case Qctl:
  479                 lb = c->aux;
  480                 link = &lb->link[ID(c->qid.path)];
  481                 cb = parsecmd(va, n);
  482                 if(waserror()){
  483                         free(cb);
  484                         nexterror();
  485                 }
  486                 if(cb->nf < 1)
  487                         error("short control request");
  488                 if(strcmp(cb->f[0], "delay") == 0){
  489                         if(cb->nf != 3)
  490                                 error("usage: delay latency bytedelay");
  491                         d0ns = strtoll(cb->f[1], nil, 10);
  492                         dnns = strtol(cb->f[2], nil, 10);
  493 
  494                         /*
  495                          * it takes about 20000 cycles on a pentium ii
  496                          * to run pushlink; perhaps this should be accounted.
  497                          */
  498 
  499                         ilock(link);
  500                         link->delay0ns = d0ns;
  501                         link->delaynns = dnns;
  502                         iunlock(link);
  503                 }else if(strcmp(cb->f[0], "indrop") == 0){
  504                         if(cb->nf != 2)
  505                                 error("usage: indrop [01]");
  506                         ilock(link);
  507                         link->indrop = strtol(cb->f[1], nil, 0) != 0;
  508                         iunlock(link);
  509                 }else if(strcmp(cb->f[0], "droprate") == 0){
  510                         if(cb->nf != 2)
  511                                 error("usage: droprate ofn");
  512                         ilock(link);
  513                         link->droprate = strtol(cb->f[1], nil, 0);
  514                         iunlock(link);
  515                 }else if(strcmp(cb->f[0], "limit") == 0){
  516                         if(cb->nf != 2)
  517                                 error("usage: limit maxqsize");
  518                         ilock(link);
  519                         link->limit = strtol(cb->f[1], nil, 0);
  520                         qsetlimit(link->oq, link->limit);
  521                         qsetlimit(link->iq, link->limit);
  522                         iunlock(link);
  523                 }else if(strcmp(cb->f[0], "reset") == 0){
  524                         if(cb->nf != 1)
  525                                 error("usage: reset");
  526                         ilock(link);
  527                         link->packets = 0;
  528                         link->bytes = 0;
  529                         link->indrop = 0;
  530                         link->soverflows = 0;
  531                         link->drops = 0;
  532                         iunlock(link);
  533                 }else
  534                         error("unknown control request");
  535                 poperror();
  536                 free(cb);
  537                 break;
  538         default:
  539                 error(Eperm);
  540         }
  541 
  542         return n;
  543 }
  544 
  545 static long
  546 loopoput(Loop *lb, Link *link, Block *volatile bp)
  547 {
  548         long n;
  549 
  550         n = BLEN(bp);
  551 
  552         /* make it a single block with space for the loopback timing header */
  553         if(waserror()){
  554                 freeb(bp);
  555                 nexterror();
  556         }
  557         bp = padblock(bp, Tmsize);
  558         if(bp->next)
  559                 bp = concatblock(bp);
  560         if(BLEN(bp) < lb->minmtu)
  561                 bp = adjustblock(bp, lb->minmtu);
  562         poperror();
  563         ptime(bp->rp, todget(nil));
  564 
  565         link->packets++;
  566         link->bytes += n;
  567 
  568         qbwrite(link->oq, bp);
  569 
  570         looper(lb);
  571         return n;
  572 }
  573 
  574 static void
  575 looper(Loop *lb)
  576 {
  577         vlong t;
  578         int chan;
  579 
  580         t = todget(nil);
  581         for(chan = 0; chan < 2; chan++)
  582                 pushlink(&lb->link[chan], t);
  583 }
  584 
  585 static void
  586 linkintr(Ureg*, Timer *ci)
  587 {
  588         Link *link;
  589 
  590         link = ci->a;
  591         pushlink(link, ci->ns);
  592 }
  593 
  594 /*
  595  * move blocks between queues if they are ready.
  596  * schedule an interrupt for the next interesting time.
  597  *
  598  * must be called with the link ilocked.
  599  */
  600 static void
  601 pushlink(Link *link, vlong now)
  602 {
  603         Block *bp;
  604         vlong tout, tin;
  605 
  606         /*
  607          * put another block in the link queue
  608          */
  609         ilock(link);
  610         if(link->iq == nil || link->oq == nil){
  611                 iunlock(link);
  612                 return;
  613 
  614         }
  615         timerdel(&link->ci);
  616 
  617         /*
  618          * put more blocks into the xmit queue
  619          * use the time the last packet was supposed to go out
  620          * as the start time for the next packet, rather than
  621          * the current time.  this more closely models a network
  622          * device which can queue multiple output packets.
  623          */
  624         tout = link->tout;
  625         if(!tout)
  626                 tout = now;
  627         while(tout <= now){
  628                 bp = qget(link->oq);
  629                 if(bp == nil){
  630                         tout = 0;
  631                         break;
  632                 }
  633 
  634                 /*
  635                  * can't send the packet before it gets queued
  636                  */
  637                 tin = gtime(bp->rp);
  638                 if(tin > tout)
  639                         tout = tin;
  640                 tout = tout + (BLEN(bp) - Tmsize) * link->delayn;
  641 
  642                 /*
  643                  * drop packets
  644                  */
  645                 if(link->droprate && nrand(link->droprate) == 0)
  646                         link->drops++;
  647                 else{
  648                         ptime(bp->rp, tout + link->delay0ns);
  649                         if(link->tq == nil)
  650                                 link->tq = bp;
  651                         else
  652                                 link->tqtail->next = bp;
  653                         link->tqtail = bp;
  654                 }
  655         }
  656 
  657         /*
  658          * record the next time a packet can be sent,
  659          * but don't schedule an interrupt if none is waiting
  660          */
  661         link->tout = tout;
  662         if(!qcanread(link->oq))
  663                 tout = 0;
  664 
  665         /*
  666          * put more blocks into the receive queue
  667          */
  668         tin = 0;
  669         while(bp = link->tq){
  670                 tin = gtime(bp->rp);
  671                 if(tin > now)
  672                         break;
  673                 bp->rp += Tmsize;
  674                 link->tq = bp->next;
  675                 bp->next = nil;
  676                 if(!link->indrop)
  677                         qpassnolim(link->iq, bp);
  678                 else if(qpass(link->iq, bp) < 0)
  679                         link->soverflows++;
  680                 tin = 0;
  681         }
  682         if(bp == nil && qisclosed(link->oq) && !qcanread(link->oq) && !qisclosed(link->iq))
  683                 qhangup(link->iq, nil);
  684         link->tin = tin;
  685         if(!tin || tin > tout && tout)
  686                 tin = tout;
  687 
  688         link->ci.ns = tin - now;
  689         if(tin){
  690                 if(tin < now)
  691                         panic("loopback unfinished business");
  692                 timeradd(&link->ci);
  693         }
  694         iunlock(link);
  695 }
  696 
  697 static void
  698 ptime(uchar *p, vlong t)
  699 {
  700         ulong tt;
  701 
  702         tt = t >> 32;
  703         p[0] = tt >> 24;
  704         p[1] = tt >> 16;
  705         p[2] = tt >> 8;
  706         p[3] = tt;
  707         tt = t;
  708         p[4] = tt >> 24;
  709         p[5] = tt >> 16;
  710         p[6] = tt >> 8;
  711         p[7] = tt;
  712 }
  713 
  714 static vlong
  715 gtime(uchar *p)
  716 {
  717         ulong t1, t2;
  718 
  719         t1 = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
  720         t2 = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7];
  721         return ((vlong)t1 << 32) | t2;
  722 }
  723 
  724 Dev loopbackdevtab = {
  725         'X',
  726         "loopback",
  727 
  728         devreset,
  729         loopbackinit,
  730         devshutdown,
  731         loopbackattach,
  732         loopbackwalk,
  733         loopbackstat,
  734         loopbackopen,
  735         devcreate,
  736         loopbackclose,
  737         loopbackread,
  738         loopbackbread,
  739         loopbackwrite,
  740         loopbackbwrite,
  741         devremove,
  742         devwstat,
  743 };

Cache object: 9282fefd64222727653770827f7d6d85


[ 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.