1 #include <u.h> 2 #include <libc.h> 3 #include "iotrack.h" 4 #include "dat.h" 5 #include "fns.h" 6 7 #define FIDMOD 127 /* prime */ 8 9 static Xfs *xhead; 10 static Xfile *xfiles[FIDMOD], *freelist; 11 static Lock xlock, xlocks[FIDMOD], freelock; 12 13 int client; 14 15 Xfs * 16 getxfs(char *name) 17 { 18 int fd; Dir dir; Xfs *xf, *fxf; 19 20 if(name==0 || name[0]==0) 21 name = deffile; 22 if(name == 0){ 23 errno = Enofilsys; 24 return 0; 25 } 26 fd = open(name, ORDWR); 27 if(fd < 0){ 28 errno = Enonexist; 29 return 0; 30 } 31 if(dirfstat(fd, &dir) < 0){ 32 errno = Eio; 33 close(fd); 34 return 0; 35 } 36 lock(&xlock); 37 for(fxf=0,xf=xhead; xf; xf=xf->next){ 38 if(xf->ref == 0){ 39 if(fxf == 0) 40 fxf = xf; 41 continue; 42 } 43 if(xf->qid.path != dir.qid.path || xf->qid.vers != dir.qid.vers) 44 continue; 45 if(strcmp(xf->name, name) != 0 || xf->dev < 0) 46 continue; 47 if(devcheck(xf) < 0) /* look for media change */ 48 continue; 49 chat("incref \"%s\", dev=%d...", xf->name, xf->dev); 50 ++xf->ref; 51 unlock(&xlock); 52 close(fd); 53 return xf; 54 } 55 if(fxf==0){ 56 fxf = malloc(sizeof(Xfs)); 57 if(fxf==0){ 58 unlock(&xlock); 59 close(fd); 60 errno = Enomem; 61 return 0; 62 } 63 fxf->next = xhead; 64 xhead = fxf; 65 } 66 chat("alloc \"%s\", dev=%d...", name, fd); 67 fxf->name = strdup(name); 68 fxf->ref = 1; 69 fxf->qid = dir.qid; 70 fxf->dev = fd; 71 fxf->fmt = 0; 72 fxf->offset = 0; 73 fxf->ptr = 0; 74 unlock(&xlock); 75 return fxf; 76 } 77 78 void 79 refxfs(Xfs *xf, int delta) 80 { 81 lock(&xlock); 82 xf->ref += delta; 83 if(xf->ref == 0){ 84 chat("free \"%s\", dev=%d...", xf->name, xf->dev); 85 free(xf->name); 86 free(xf->ptr); 87 purgebuf(xf); 88 if(xf->dev >= 0){ 89 close(xf->dev); 90 xf->dev = -1; 91 } 92 } 93 unlock(&xlock); 94 } 95 96 Xfile * 97 xfile(int fid, int flag) 98 { 99 int k = ((ulong)fid^(ulong)client)%FIDMOD; 100 Xfile **hp=&xfiles[k], *f, *pf; 101 102 lock(&xlocks[k]); 103 for(f=*hp,pf=0; f; pf=f, f=f->next) 104 if(f->fid == fid && f->client == client) 105 break; 106 if(f && pf){ 107 pf->next = f->next; 108 f->next = *hp; 109 *hp = f; 110 } 111 switch(flag){ 112 default: 113 panic("xfile"); 114 case Asis: 115 unlock(&xlocks[k]); 116 return (f && f->xf && f->xf->dev < 0) ? 0 : f; 117 case Clean: 118 break; 119 case Clunk: 120 if(f){ 121 *hp = f->next; 122 unlock(&xlocks[k]); 123 clean(f); 124 lock(&freelock); 125 f->next = freelist; 126 freelist = f; 127 unlock(&freelock); 128 } else 129 unlock(&xlocks[k]); 130 return 0; 131 } 132 unlock(&xlocks[k]); 133 if(f) 134 return clean(f); 135 lock(&freelock); 136 if(f = freelist){ /* assign = */ 137 freelist = f->next; 138 unlock(&freelock); 139 } else { 140 unlock(&freelock); 141 f = malloc(sizeof(Xfile)); 142 } 143 lock(&xlocks[k]); 144 f->next = *hp; 145 *hp = f; 146 unlock(&xlocks[k]); 147 f->fid = fid; 148 f->client = client; 149 f->flags = 0; 150 f->qid = (Qid){0,0}; 151 f->xf = 0; 152 f->ptr = 0; 153 return f; 154 } 155 156 Xfile * 157 clean(Xfile *f) 158 { 159 if(f->ptr){ 160 free(f->ptr); 161 f->ptr = 0; 162 } 163 if(f->xf){ 164 refxfs(f->xf, -1); 165 f->xf = 0; 166 } 167 f->xf = 0; 168 f->flags = 0; 169 f->qid = (Qid){0,0}; 170 return f; 171 } 172 173 int 174 xfspurge(void) 175 { 176 Xfile **hp, *f, *pf, *nf; 177 int k, count=0; 178 179 for(k=0; k<FIDMOD; k++){ 180 lock(&xlocks[k]); 181 hp=&xfiles[k]; 182 for(f=*hp,pf=0; f; f=nf){ 183 nf = f->next; 184 if(f->client != client){ 185 pf = f; 186 continue; 187 } 188 if (pf) 189 pf->next = f->next; 190 else 191 *hp = f->next; 192 clean(f); 193 lock(&freelock); 194 f->next = freelist; 195 freelist = f; 196 unlock(&freelock); 197 ++count; 198 } 199 unlock(&xlocks[k]); 200 } 201 return count; 202 } 203