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/devsegment.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 enum
    9 {
   10         Qtopdir,
   11         Qsegdir,
   12         Qctl,
   13         Qdata,
   14 
   15         /* commands to kproc */
   16         Cnone=0,
   17         Cread,
   18         Cwrite,
   19         Cstart,
   20         Cdie,
   21 };
   22 
   23 #define TYPE(x)         (int)( (c)->qid.path & 0x7 )
   24 #define SEG(x)          ( ((c)->qid.path >> 3) & 0x3f )
   25 #define PATH(s, t)      ( ((s)<<3) | (t) )
   26 
   27 typedef struct Globalseg Globalseg;
   28 struct Globalseg
   29 {
   30         Ref;
   31         Segment *s;
   32 
   33         char    *name;
   34         char    *uid;
   35         vlong   length;
   36         long    perm;
   37 
   38         /* kproc to do reading and writing */
   39         QLock   l;              /* sync kproc access */
   40         Rendez  cmdwait;        /* where kproc waits */
   41         Rendez  replywait;      /* where requestor waits */
   42         Proc    *kproc;
   43         char    *data;
   44         long    off;
   45         int     dlen;
   46         int     cmd;    
   47         char    err[64];
   48 };
   49 
   50 static Globalseg *globalseg[100];
   51 static Lock globalseglock;
   52 
   53 
   54         Segment* (*_globalsegattach)(Proc*, char*);
   55 static  Segment* globalsegattach(Proc *p, char *name);
   56 static  int     cmddone(void*);
   57 static  void    segmentkproc(void*);
   58 static  void    docmd(Globalseg *g, int cmd);
   59 
   60 /*
   61  *  returns with globalseg incref'd
   62  */
   63 static Globalseg*
   64 getgseg(Chan *c)
   65 {
   66         int x;
   67         Globalseg *g;
   68 
   69         x = SEG(c);
   70         lock(&globalseglock);
   71         if(x >= nelem(globalseg))
   72                 panic("getgseg");
   73         g = globalseg[x];
   74         if(g != nil)
   75                 incref(g);
   76         unlock(&globalseglock);
   77         if(g == nil)
   78                 error("global segment disappeared");
   79         return g;
   80 }
   81 
   82 static void
   83 putgseg(Globalseg *g)
   84 {
   85         if(decref(g) > 0)
   86                 return;
   87         if(g->s != nil)
   88                 putseg(g->s);
   89         if(g->kproc)
   90                 docmd(g, Cdie);
   91         free(g->name);
   92         free(g->uid);
   93         free(g);
   94 }
   95 
   96 static int
   97 segmentgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
   98 {
   99         Qid q;
  100         Globalseg *g;
  101         ulong size;
  102 
  103         switch(TYPE(c)) {
  104         case Qtopdir:
  105                 if(s == DEVDOTDOT){
  106                         q.vers = 0;
  107                         q.path = PATH(0, Qtopdir);
  108                         q.type = QTDIR;
  109                         devdir(c, q, "#g", 0, eve, DMDIR|0777, dp);
  110                         break;
  111                 }
  112 
  113                 if(s >= nelem(globalseg))
  114                         return -1;
  115 
  116                 lock(&globalseglock);
  117                 g = globalseg[s];
  118                 if(g == nil){
  119                         unlock(&globalseglock);
  120                         return 0;
  121                 }
  122                 q.vers = 0;
  123                 q.path = PATH(s, Qsegdir);
  124                 q.type = QTDIR;
  125                 devdir(c, q, g->name, 0, g->uid, DMDIR|0777, dp);
  126                 unlock(&globalseglock);
  127 
  128                 break;
  129         case Qsegdir:
  130                 if(s == DEVDOTDOT){
  131                         q.vers = 0;
  132                         q.path = PATH(0, Qtopdir);
  133                         q.type = QTDIR;
  134                         devdir(c, q, "#g", 0, eve, DMDIR|0777, dp);
  135                         break;
  136                 }
  137                 /* fall through */
  138         case Qctl:
  139         case Qdata:
  140                 switch(s){
  141                 case 0:
  142                         g = getgseg(c);
  143                         q.vers = 0;
  144                         q.path = PATH(SEG(c), Qctl);
  145                         q.type = QTFILE;
  146                         devdir(c, q, "ctl", 0, g->uid, g->perm, dp);
  147                         putgseg(g);
  148                         break;
  149                 case 1:
  150                         g = getgseg(c);
  151                         q.vers = 0;
  152                         q.path = PATH(SEG(c), Qdata);
  153                         q.type = QTFILE;
  154                         if(g->s != nil)
  155                                 size = g->s->top - g->s->base;
  156                         else
  157                                 size = 0;
  158                         devdir(c, q, "data", size, g->uid, g->perm, dp);
  159                         putgseg(g);
  160                         break;
  161                 default:
  162                         return -1;
  163                 }
  164                 break;
  165         }
  166         return 1;
  167 }
  168 
  169 static void
  170 segmentinit(void)
  171 {
  172         _globalsegattach = globalsegattach;
  173 }
  174 
  175 static Chan*
  176 segmentattach(char *spec)
  177 {
  178         return devattach('g', spec);
  179 }
  180 
  181 static Walkqid*
  182 segmentwalk(Chan *c, Chan *nc, char **name, int nname)
  183 {
  184         return devwalk(c, nc, name, nname, 0, 0, segmentgen);
  185 }
  186 
  187 static int
  188 segmentstat(Chan *c, uchar *db, int n)
  189 {
  190         return devstat(c, db, n, 0, 0, segmentgen);
  191 }
  192 
  193 static int
  194 cmddone(void *arg)
  195 {
  196         Globalseg *g = arg;
  197 
  198         return g->cmd == Cnone;
  199 }
  200 
  201 static Chan*
  202 segmentopen(Chan *c, int omode)
  203 {
  204         Globalseg *g;
  205 
  206         switch(TYPE(c)){
  207         case Qtopdir:
  208         case Qsegdir:
  209                 if(omode != 0)
  210                         error(Eisdir);
  211                 break;
  212         case Qctl:
  213                 g = getgseg(c);
  214                 if(waserror()){
  215                         putgseg(g);
  216                         nexterror();
  217                 }
  218                 devpermcheck(g->uid, g->perm, omode);
  219                 c->aux = g;
  220                 poperror();
  221                 c->flag |= COPEN;
  222                 break;
  223         case Qdata:
  224                 g = getgseg(c);
  225                 if(waserror()){
  226                         putgseg(g);
  227                         nexterror();
  228                 }
  229                 devpermcheck(g->uid, g->perm, omode);
  230                 if(g->s == nil)
  231                         error("segment not yet allocated");
  232                 if(g->kproc == nil){
  233                         qlock(&g->l);
  234                         if(waserror()){
  235                                 qunlock(&g->l);
  236                                 nexterror();
  237                         }
  238                         if(g->kproc == nil){
  239                                 g->cmd = Cnone;
  240                                 kproc(g->name, segmentkproc, g);
  241                                 docmd(g, Cstart);
  242                         }
  243                         qunlock(&g->l);
  244                         poperror();
  245                 }
  246                 c->aux = g;
  247                 poperror();
  248                 c->flag |= COPEN;
  249                 break;
  250         default:
  251                 panic("segmentopen");
  252         }
  253         c->mode = openmode(omode);
  254         c->offset = 0;
  255         return c;
  256 }
  257 
  258 static void
  259 segmentclose(Chan *c)
  260 {
  261         if(TYPE(c) == Qtopdir)
  262                 return;
  263         if(c->flag & COPEN)
  264                 putgseg(c->aux);
  265 }
  266 
  267 static void
  268 segmentcreate(Chan *c, char *name, int omode, ulong perm)
  269 {
  270         int x, xfree;
  271         Globalseg *g;
  272 
  273         if(TYPE(c) != Qtopdir)
  274                 error(Eperm);
  275 
  276         if(isphysseg(name))
  277                 error(Eexist);
  278 
  279         if((perm & DMDIR) == 0)
  280                 error(Ebadarg);
  281 
  282         if(waserror()){
  283                 unlock(&globalseglock);
  284                 nexterror();
  285         }
  286         lock(&globalseglock);
  287         xfree = -1;
  288         for(x = 0; x < nelem(globalseg); x++){
  289                 g = globalseg[x];
  290                 if(g == nil){
  291                         if(xfree < 0)
  292                                 xfree = x;
  293                 } else {
  294                         if(strcmp(g->name, name) == 0)
  295                                 error(Eexist);
  296                 }
  297         }
  298         if(xfree < 0)
  299                 error("too many global segments");
  300         g = smalloc(sizeof(Globalseg));
  301         g->ref = 1;
  302         kstrdup(&g->name, name);
  303         kstrdup(&g->uid, up->user);
  304         g->perm = 0660; 
  305         globalseg[xfree] = g;
  306         unlock(&globalseglock);
  307         poperror();
  308 
  309         c->qid.path = PATH(x, Qsegdir);
  310         c->qid.type = QTDIR;
  311         c->qid.vers = 0;
  312         c->mode = openmode(omode);
  313         c->mode = OWRITE;
  314 }
  315 
  316 static long
  317 segmentread(Chan *c, void *a, long n, vlong voff)
  318 {
  319         Globalseg *g;
  320         char buf[32];
  321 
  322         if(c->qid.type == QTDIR)
  323                 return devdirread(c, a, n, (Dirtab *)0, 0L, segmentgen);
  324 
  325         switch(TYPE(c)){
  326         case Qctl:
  327                 g = c->aux;
  328                 if(g->s == nil)
  329                         error("segment not yet allocated");
  330                 sprint(buf, "va %#lux %#lux\n", g->s->base, g->s->top-g->s->base);
  331                 return readstr(voff, a, n, buf);
  332         case Qdata:
  333                 g = c->aux;
  334                 if(voff > g->s->top - g->s->base)
  335                         error(Ebadarg);
  336                 if(voff + n > g->s->top - g->s->base)
  337                         n = g->s->top - g->s->base - voff;
  338                 qlock(&g->l);
  339                 g->off = voff + g->s->base;
  340                 g->data = smalloc(n);
  341                 if(waserror()){
  342                         free(g->data);
  343                         qunlock(&g->l);
  344                         nexterror();
  345                 }
  346                 g->dlen = n;
  347                 docmd(g, Cread);
  348                 memmove(a, g->data, g->dlen);
  349                 free(g->data);
  350                 qunlock(&g->l);
  351                 poperror();
  352                 return g->dlen;
  353         default:
  354                 panic("segmentread");
  355         }
  356         return 0;       /* not reached */
  357 }
  358 
  359 static long
  360 segmentwrite(Chan *c, void *a, long n, vlong voff)
  361 {
  362         Cmdbuf *cb;
  363         Globalseg *g;
  364         ulong va, len, top;
  365 
  366         if(c->qid.type == QTDIR)
  367                 error(Eperm);
  368 
  369         switch(TYPE(c)){
  370         case Qctl:
  371                 g = c->aux;
  372                 cb = parsecmd(a, n);
  373                 if(strcmp(cb->f[0], "va") == 0){
  374                         if(g->s != nil)
  375                                 error("already has a virtual address");
  376                         if(cb->nf < 3)
  377                                 error(Ebadarg);
  378                         va = strtoul(cb->f[1], 0, 0);
  379                         len = strtoul(cb->f[2], 0, 0);
  380                         top = PGROUND(va + len);
  381                         va = va&~(BY2PG-1);
  382                         len = (top - va) / BY2PG;
  383                         if(len == 0)
  384                                 error(Ebadarg);
  385                         g->s = newseg(SG_SHARED, va, len);
  386                 } else
  387                         error(Ebadctl);
  388                 break;
  389         case Qdata:
  390                 g = c->aux;
  391                 if(voff + n > g->s->top - g->s->base)
  392                         error(Ebadarg);
  393                 qlock(&g->l);
  394                 g->off = voff + g->s->base;
  395                 g->data = smalloc(n);
  396                 if(waserror()){
  397                         free(g->data);
  398                         qunlock(&g->l);
  399                         nexterror();
  400                 }
  401                 g->dlen = n;
  402                 memmove(g->data, a, g->dlen);
  403                 docmd(g, Cwrite);
  404                 free(g->data);
  405                 qunlock(&g->l);
  406                 poperror();
  407                 return g->dlen;
  408         default:
  409                 panic("segmentwrite");
  410         }
  411         return 0;       /* not reached */
  412 }
  413 
  414 static int
  415 segmentwstat(Chan *c, uchar *dp, int n)
  416 {
  417         Globalseg *g;
  418         Dir *d;
  419 
  420         if(c->qid.type == QTDIR)
  421                 error(Eperm);
  422 
  423         g = getgseg(c);
  424         if(waserror()){
  425                 putgseg(g);
  426                 nexterror();
  427         }
  428 
  429         if(strcmp(g->uid, up->user) && !iseve())
  430                 error(Eperm);
  431         d = smalloc(sizeof(Dir)+n);
  432         n = convM2D(dp, n, &d[0], (char*)&d[1]);
  433         g->perm = d->mode & 0777;
  434 
  435         putgseg(g);
  436         poperror();
  437 
  438         free(d);
  439         return n;
  440 }
  441 
  442 static void
  443 segmentremove(Chan *c)
  444 {
  445         Globalseg *g;
  446         int x;
  447 
  448         if(TYPE(c) != Qsegdir)
  449                 error(Eperm);
  450         lock(&globalseglock);
  451         x = SEG(c);
  452         g = globalseg[x];
  453         globalseg[x] = nil;
  454         unlock(&globalseglock);
  455         if(g != nil)
  456                 putgseg(g);
  457 }
  458 
  459 /*
  460  *  called by segattach()
  461  */
  462 static Segment*
  463 globalsegattach(Proc *p, char *name)
  464 {
  465         int x;
  466         Globalseg *g;
  467         Segment *s;
  468 
  469         g = nil;
  470         if(waserror()){
  471                 unlock(&globalseglock);
  472                 nexterror();
  473         }
  474         lock(&globalseglock);
  475         for(x = 0; x < nelem(globalseg); x++){
  476                 g = globalseg[x];
  477                 if(g != nil && strcmp(g->name, name) == 0)
  478                         break;
  479         }
  480         if(x == nelem(globalseg)){
  481                 unlock(&globalseglock);
  482                 poperror();
  483                 return nil;
  484         }
  485         devpermcheck(g->uid, g->perm, ORDWR);
  486         s = g->s;
  487         if(s == nil)
  488                 error("global segment not assigned a virtual address");
  489         if(isoverlap(p, s->base, s->top - s->base) != nil)
  490                 error("overlaps existing segment");
  491         incref(s);
  492         unlock(&globalseglock);
  493         poperror();
  494         return s;
  495 }
  496 
  497 static void
  498 docmd(Globalseg *g, int cmd)
  499 {
  500         g->err[0] = 0;
  501         g->cmd = cmd;
  502         wakeup(&g->cmdwait);
  503         sleep(&g->replywait, cmddone, g);
  504         if(g->err[0])
  505                 error(g->err);
  506 }
  507 
  508 static int
  509 cmdready(void *arg)
  510 {
  511         Globalseg *g = arg;
  512 
  513         return g->cmd != Cnone;
  514 }
  515 
  516 static void
  517 segmentkproc(void *arg)
  518 {
  519         Globalseg *g = arg;
  520         int done;
  521         int sno;
  522 
  523         for(sno = 0; sno < NSEG; sno++)
  524                 if(up->seg[sno] == nil && sno != ESEG)
  525                         break;
  526         if(sno == NSEG)
  527                 panic("segmentkproc");
  528         g->kproc = up;
  529 
  530         incref(g->s);
  531         up->seg[sno] = g->s;
  532 
  533         for(done = 0; !done;){
  534                 sleep(&g->cmdwait, cmdready, g);
  535                 if(waserror()){
  536                         strncpy(g->err, up->errstr, sizeof(g->err));
  537                 } else {
  538                         switch(g->cmd){
  539                         case Cstart:
  540                                 break;
  541                         case Cdie:
  542                                 done = 1;
  543                                 break;
  544                         case Cread:
  545                                 memmove(g->data, (char*)g->off, g->dlen);
  546                                 break;
  547                         case Cwrite:
  548                                 memmove((char*)g->off, g->data, g->dlen);
  549                                 break;
  550                         }
  551                         poperror();
  552                 }
  553                 g->cmd = Cnone;
  554                 wakeup(&g->replywait);
  555         }
  556 }
  557 
  558 Dev segmentdevtab = {
  559         'g',
  560         "segment",
  561 
  562         devreset,
  563         segmentinit,
  564         devshutdown,
  565         segmentattach,
  566         segmentwalk,
  567         segmentstat,
  568         segmentopen,
  569         segmentcreate,
  570         segmentclose,
  571         segmentread,
  572         devbread,
  573         segmentwrite,
  574         devbwrite,
  575         segmentremove,
  576         segmentwstat,
  577 };
  578 

Cache object: 8d402d67b239a6124a3a84e6da9737e1


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