URI:
       t9fid.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       t9fid.c (5452B)
       ---
            1 #include "stdinc.h"
            2 
            3 #include "9.h"
            4 
            5 static struct {
            6         QLock        lock;
            7 
            8         Fid*        free;
            9         int        nfree;
           10         int        inuse;
           11 } fbox;
           12 
           13 static void
           14 fidLock(Fid* fid, int flags)
           15 {
           16         if(flags & FidFWlock){
           17                 wlock(&fid->lock);
           18                 fid->flags = flags;
           19         }
           20         else
           21                 rlock(&fid->lock);
           22 
           23         /*
           24          * Callers of file* routines are expected to lock fsys->fs->elk
           25          * before making any calls in order to make sure the epoch doesn't
           26          * change underfoot. With the exception of Tversion and Tattach,
           27          * that implies all 9P functions need to lock on entry and unlock
           28          * on exit. Fortunately, the general case is the 9P functions do
           29          * fidGet on entry and fidPut on exit, so this is a convenient place
           30          * to do the locking.
           31          * No fsys->fs->elk lock is required if the fid is being created
           32          * (Tauth, Tattach and Twalk). FidFCreate is always accompanied by
           33          * FidFWlock so the setting and testing of FidFCreate here and in
           34          * fidUnlock below is always done under fid->lock.
           35          * A side effect is that fidFree is called with the fid locked, and
           36          * must call fidUnlock only after it has disposed of any File
           37          * resources still held.
           38          */
           39         if(!(flags & FidFCreate))
           40                 fsysFsRlock(fid->fsys);
           41 }
           42 
           43 static void
           44 fidUnlock(Fid* fid)
           45 {
           46         if(!(fid->flags & FidFCreate))
           47                 fsysFsRUnlock(fid->fsys);
           48         if(fid->flags & FidFWlock){
           49                 fid->flags = 0;
           50                 wunlock(&fid->lock);
           51                 return;
           52         }
           53         runlock(&fid->lock);
           54 }
           55 
           56 static Fid*
           57 fidAlloc(void)
           58 {
           59         Fid *fid;
           60 
           61         qlock(&fbox.lock);
           62         if(fbox.nfree > 0){
           63                 fid = fbox.free;
           64                 fbox.free = fid->hash;
           65                 fbox.nfree--;
           66         }
           67         else{
           68                 fid = vtmallocz(sizeof(Fid));
           69         }
           70         fbox.inuse++;
           71         qunlock(&fbox.lock);
           72 
           73         fid->con = nil;
           74         fid->fidno = NOFID;
           75         fid->ref = 0;
           76         fid->flags = 0;
           77         fid->open = FidOCreate;
           78         assert(fid->fsys == nil);
           79         assert(fid->file == nil);
           80         fid->qid = (Qid){0, 0, 0};
           81         assert(fid->uid == nil);
           82         assert(fid->uname == nil);
           83         assert(fid->db == nil);
           84         assert(fid->excl == nil);
           85         assert(fid->rpc == nil);
           86         assert(fid->cuname == nil);
           87         fid->hash = fid->next = fid->prev = nil;
           88 
           89         return fid;
           90 }
           91 
           92 static void
           93 fidFree(Fid* fid)
           94 {
           95         if(fid->file != nil){
           96                 fileDecRef(fid->file);
           97                 fid->file = nil;
           98         }
           99         if(fid->db != nil){
          100                 dirBufFree(fid->db);
          101                 fid->db = nil;
          102         }
          103         fidUnlock(fid);
          104 
          105         if(fid->uid != nil){
          106                 vtfree(fid->uid);
          107                 fid->uid = nil;
          108         }
          109         if(fid->uname != nil){
          110                 vtfree(fid->uname);
          111                 fid->uname = nil;
          112         }
          113         if(fid->excl != nil)
          114                 exclFree(fid);
          115         if(fid->rpc != nil){
          116                 close(fid->rpc->afd);
          117                 auth_freerpc(fid->rpc);
          118                 fid->rpc = nil;
          119         }
          120         if(fid->fsys != nil){
          121                 fsysPut(fid->fsys);
          122                 fid->fsys = nil;
          123         }
          124         if(fid->cuname != nil){
          125                 vtfree(fid->cuname);
          126                 fid->cuname = nil;
          127         }
          128 
          129         qlock(&fbox.lock);
          130         fbox.inuse--;
          131         if(fbox.nfree < 10){
          132                 fid->hash = fbox.free;
          133                 fbox.free = fid;
          134                 fbox.nfree++;
          135         }
          136         else{
          137                 vtfree(fid);
          138         }
          139         qunlock(&fbox.lock);
          140 }
          141 
          142 static void
          143 fidUnHash(Fid* fid)
          144 {
          145         Fid *fp, **hash;
          146 
          147         assert(fid->ref == 0);
          148 
          149         hash = &fid->con->fidhash[fid->fidno % NFidHash];
          150         for(fp = *hash; fp != nil; fp = fp->hash){
          151                 if(fp == fid){
          152                         *hash = fp->hash;
          153                         break;
          154                 }
          155                 hash = &fp->hash;
          156         }
          157         assert(fp == fid);
          158 
          159         if(fid->prev != nil)
          160                 fid->prev->next = fid->next;
          161         else
          162                 fid->con->fhead = fid->next;
          163         if(fid->next != nil)
          164                 fid->next->prev = fid->prev;
          165         else
          166                 fid->con->ftail = fid->prev;
          167         fid->prev = fid->next = nil;
          168 
          169         fid->con->nfid--;
          170 }
          171 
          172 Fid*
          173 fidGet(Con* con, u32int fidno, int flags)
          174 {
          175         Fid *fid, **hash;
          176 
          177         if(fidno == NOFID)
          178                 return nil;
          179 
          180         hash = &con->fidhash[fidno % NFidHash];
          181         qlock(&con->fidlock);
          182         for(fid = *hash; fid != nil; fid = fid->hash){
          183                 if(fid->fidno != fidno)
          184                         continue;
          185 
          186                 /*
          187                  * Already in use is an error
          188                  * when called from attach, clone or walk.
          189                  */
          190                 if(flags & FidFCreate){
          191                         qunlock(&con->fidlock);
          192                         werrstr("%s: fid 0x%ud in use", argv0, fidno);
          193                         return nil;
          194                 }
          195                 fid->ref++;
          196                 qunlock(&con->fidlock);
          197 
          198                 fidLock(fid, flags);
          199                 if((fid->open & FidOCreate) || fid->fidno == NOFID){
          200                         fidPut(fid);
          201                         werrstr("%s: fid invalid", argv0);
          202                         return nil;
          203                 }
          204                 return fid;
          205         }
          206 
          207         if((flags & FidFCreate) && (fid = fidAlloc()) != nil){
          208                 assert(flags & FidFWlock);
          209                 fid->con = con;
          210                 fid->fidno = fidno;
          211                 fid->ref = 1;
          212 
          213                 fid->hash = *hash;
          214                 *hash = fid;
          215                 if(con->ftail != nil){
          216                         fid->prev = con->ftail;
          217                         con->ftail->next = fid;
          218                 }
          219                 else{
          220                         con->fhead = fid;
          221                         fid->prev = nil;
          222                 }
          223                 con->ftail = fid;
          224                 fid->next = nil;
          225 
          226                 con->nfid++;
          227                 qunlock(&con->fidlock);
          228 
          229                 /*
          230                  * The FidOCreate flag is used to prevent any
          231                  * accidental access to the Fid between unlocking the
          232                  * hash and acquiring the Fid lock for return.
          233                  */
          234                 fidLock(fid, flags);
          235                 fid->open &= ~FidOCreate;
          236                 return fid;
          237         }
          238         qunlock(&con->fidlock);
          239 
          240         werrstr("%s: fid not found", argv0);
          241         return nil;
          242 }
          243 
          244 void
          245 fidPut(Fid* fid)
          246 {
          247         qlock(&fid->con->fidlock);
          248         assert(fid->ref > 0);
          249         fid->ref--;
          250         qunlock(&fid->con->fidlock);
          251 
          252         if(fid->ref == 0 && fid->fidno == NOFID){
          253                 fidFree(fid);
          254                 return;
          255         }
          256         fidUnlock(fid);
          257 }
          258 
          259 void
          260 fidClunk(Fid* fid)
          261 {
          262         assert(fid->flags & FidFWlock);
          263 
          264         qlock(&fid->con->fidlock);
          265         assert(fid->ref > 0);
          266         fid->ref--;
          267         fidUnHash(fid);
          268         fid->fidno = NOFID;
          269         qunlock(&fid->con->fidlock);
          270 
          271         if(fid->ref > 0){
          272                 /* not reached - fidUnHash requires ref == 0 */
          273                 fidUnlock(fid);
          274                 return;
          275         }
          276         fidFree(fid);
          277 }
          278 
          279 void
          280 fidClunkAll(Con* con)
          281 {
          282         Fid *fid;
          283         u32int fidno;
          284 
          285         qlock(&con->fidlock);
          286         while(con->fhead != nil){
          287                 fidno = con->fhead->fidno;
          288                 qunlock(&con->fidlock);
          289                 if((fid = fidGet(con, fidno, FidFWlock)) != nil)
          290                         fidClunk(fid);
          291                 qlock(&con->fidlock);
          292         }
          293         qunlock(&con->fidlock);
          294 }
          295 
          296 void
          297 fidInit(void)
          298 {
          299 }