1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #include <thread.h>
5 #include <9p.h>
6 #include "dat.h"
7 #include "fns.h"
8
9
10 static Xfs *xhead;
11 static Xfile *freelist;
12 static Lock xlock, freelock;
13
14 int client;
15
16 Xfs *
getxfs(char * name)17 getxfs(char *name)
18 {
19 int fd;
20 Dir *dir;
21 Xfs *xf, *fxf;
22
23 if(name==0 || name[0]==0)
24 name = deffile;
25 if(name == 0){
26 errno = Enofilsys;
27 return 0;
28 }
29 fd = open(name, rdonly ? OREAD : ORDWR);
30 if(fd < 0){
31 errno = Enonexist;
32 return 0;
33 }
34 if((dir = dirfstat(fd)) == 0){
35 errno = Eio;
36 close(fd);
37 return 0;
38 }
39 lock(&xlock);
40 for(fxf=0, xf=xhead; xf; xf=xf->next){
41 if(xf->ref == 0){
42 if(fxf == 0)
43 fxf = xf;
44 continue;
45 }
46 if(xf->qid.path != dir->qid.path || xf->qid.vers != dir->qid.vers)
47 continue;
48 if(strcmp(xf->name, name) != 0 || xf->dev < 0)
49 continue;
50 chat("incref \"%s\", dev=%d...", xf->name, xf->dev);
51 ++xf->ref;
52 unlock(&xlock);
53 close(fd);
54 free(dir);
55 return xf;
56 }
57 if(fxf==0){
58 fxf = malloc(sizeof(Xfs));
59 if(fxf==0){
60 unlock(&xlock);
61 close(fd);
62 free(dir);
63 errno = Enomem;
64 return 0;
65 }
66 fxf->next = xhead;
67 xhead = fxf;
68 }
69 chat("alloc \"%s\", dev=%d...", name, fd);
70 fxf->name = strdup(name);
71 fxf->ref = 1;
72 fxf->qid = dir->qid;
73 fxf->dev = fd;
74 fxf->fmt = 0;
75 fxf->ptr = 0;
76 free(dir);
77 if( ext2fs(fxf)<0 ){
78 xhead = fxf->next;
79 free(fxf);
80 unlock(&xlock);
81 return 0;
82 }
83 unlock(&xlock);
84 return fxf;
85 }
86
87 void
refxfs(Xfs * xf,int delta)88 refxfs(Xfs *xf, int delta)
89 {
90 lock(&xlock);
91 xf->ref += delta;
92 if(xf->ref == 0){
93 /*mchat("free \"%s\", dev=%d...", xf->name, xf->dev);
94 dumpbuf();*/
95 CleanSuper(xf);
96 syncbuf();
97 free(xf->name);
98 purgebuf(xf);
99 if(xf->dev >= 0){
100 close(xf->dev);
101 xf->dev = -1;
102 }
103 }
104 unlock(&xlock);
105 }
106
107 Xfile *
xfile(Fid * fid,int flag)108 xfile(Fid *fid, int flag)
109 {
110 Xfile *f;
111
112 f = (Xfile*)fid->aux;
113 switch(flag){
114 default:
115 panic("xfile");
116 case Asis:
117 return (f && f->xf && f->xf->dev < 0) ? 0 : f;
118 case Clean:
119 if (f) chat("Clean and fid->aux already exists\n");
120 break;
121 case Clunk:
122 if(f){
123 clean(f);
124 lock(&freelock);
125 f->next = freelist;
126 freelist = f;
127 unlock(&freelock);
128 fid->aux = 0;
129 }
130 return 0;
131 }
132 if(f)
133 return clean(f);
134 lock(&freelock);
135 if(f = freelist){ /* assign = */
136 freelist = f->next;
137 unlock(&freelock);
138 } else {
139 unlock(&freelock);
140 f = malloc(sizeof(Xfile));
141 }
142 fid->aux = f;
143 f->fid = fid->fid;
144 f->client = client;
145 f->xf = 0;
146 f->ptr = 0;
147 f->root = 0;
148 return f;
149 }
150 Xfile *
clean(Xfile * f)151 clean(Xfile *f)
152 {
153 if(f->xf && f->root){
154 refxfs(f->xf, -1);
155 f->xf = 0;
156 }
157 f->xf = 0;
158 f->root = 0;
159 f->dirindex = 0;
160 return f;
161 }
162