Blob


1 /* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
2 /* See COPYRIGHT */
4 #include <u.h>
5 #include <libc.h>
6 #include <fcall.h>
7 #include <fs.h>
8 #include <thread.h>
9 #include "fsimpl.h"
11 static int _fssend(Mux*, void*);
12 static void *_fsrecv(Mux*);
13 static int _fsgettag(Mux*, void*);
14 static int _fssettag(Mux*, void*, uint);
16 enum
17 {
18 Fidchunk = 32
19 };
21 Fsys*
22 fsinit(int fd)
23 {
24 Fsys *fs;
26 fmtinstall('F', fcallfmt);
27 fmtinstall('D', dirfmt);
28 fmtinstall('M', dirmodefmt);
30 fs = mallocz(sizeof(Fsys), 1);
31 if(fs == nil)
32 return nil;
33 fs->fd = fd;
34 fs->ref = 1;
35 fs->mux.aux = fs;
36 fs->mux.mintag = 0;
37 fs->mux.maxtag = 256;
38 fs->mux.send = _fssend;
39 fs->mux.recv = _fsrecv;
40 fs->mux.gettag = _fsgettag;
41 fs->mux.settag = _fssettag;
42 muxinit(&fs->mux);
43 return fs;
44 }
46 Fid*
47 fsroot(Fsys *fs)
48 {
49 /* N.B. no incref */
50 return fs->root;
51 }
53 Fsys*
54 fsmount(int fd, char *aname)
55 {
56 int n;
57 char *user;
58 Fsys *fs;
60 fs = fsinit(fd);
61 if(fs == nil)
62 return nil;
63 strcpy(fs->version, "9P2000");
64 if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){
65 Error:
66 fs->fd = -1;
67 fsunmount(fs);
68 return nil;
69 }
70 fs->msize = n;
72 user = getuser();
73 if((fs->root = fsattach(fs, nil, getuser(), aname)) == nil)
74 goto Error;
75 return fs;
76 }
78 void
79 fsunmount(Fsys *fs)
80 {
81 fsclose(fs->root);
82 fs->root = nil;
83 _fsdecref(fs);
84 }
86 void
87 _fsdecref(Fsys *fs)
88 {
89 Fid *f, **l, *next;
91 qlock(&fs->lk);
92 --fs->ref;
93 //fprint(2, "fsdecref %p to %d\n", fs, fs->ref);
94 if(fs->ref == 0){
95 close(fs->fd);
96 /* trim the list down to just the first in each chunk */
97 for(l=&fs->freefid; *l; ){
98 if((*l)->fid%Fidchunk == 0)
99 l = &(*l)->next;
100 else
101 *l = (*l)->next;
103 /* now free the list */
104 for(f=fs->freefid; f; f=next){
105 next = f->next;
106 free(f);
108 free(fs);
109 return;
111 qunlock(&fs->lk);
114 int
115 fsversion(Fsys *fs, int msize, char *version, int nversion)
117 void *freep;
118 Fcall tx, rx;
120 tx.tag = 0;
121 tx.type = Tversion;
122 tx.version = version;
123 tx.msize = msize;
125 if(fsrpc(fs, &tx, &rx, &freep) < 0)
126 return -1;
127 strecpy(version, version+nversion, rx.version);
128 free(freep);
129 return rx.msize;
132 Fid*
133 fsattach(Fsys *fs, Fid *afid, char *user, char *aname)
135 Fcall tx, rx;
136 Fid *fid;
138 if(aname == nil)
139 aname = "";
141 if((fid = _fsgetfid(fs)) == nil)
142 return nil;
144 tx.tag = 0;
145 tx.type = Tattach;
146 tx.afid = afid ? afid->fid : NOFID;
147 tx.fid = fid->fid;
148 tx.uname = user;
149 tx.aname = aname;
151 if(fsrpc(fs, &tx, &rx, 0) < 0){
152 _fsputfid(fid);
153 return nil;
155 fid->qid = rx.qid;
156 return fid;
159 int
160 fsrpc(Fsys *fs, Fcall *tx, Fcall *rx, void **freep)
162 int n, nn;
163 void *tpkt, *rpkt;
165 n = sizeS2M(tx);
166 tpkt = malloc(n);
167 if(freep)
168 *freep = nil;
169 if(tpkt == nil)
170 return -1;
171 //fprint(2, "<- %F\n", tx);
172 nn = convS2M(tx, tpkt, n);
173 if(nn != n){
174 free(tpkt);
175 werrstr("libfs: sizeS2M convS2M mismatch");
176 fprint(2, "%r\n");
177 return -1;
179 rpkt = muxrpc(&fs->mux, tpkt);
180 free(tpkt);
181 if(rpkt == nil)
182 return -1;
183 n = GBIT32((uchar*)rpkt);
184 nn = convM2S(rpkt, n, rx);
185 if(nn != n){
186 free(rpkt);
187 werrstr("libfs: convM2S packet size mismatch %d %d", n, nn);
188 fprint(2, "%r\n");
189 return -1;
191 //fprint(2, "-> %F\n", rx);
192 if(rx->type == Rerror){
193 werrstr("%s", rx->ename);
194 free(rpkt);
195 return -1;
197 if(rx->type != tx->type+1){
198 werrstr("packet type mismatch -- tx %d rx %d",
199 tx->type, rx->type);
200 free(rpkt);
201 return -1;
203 if(freep)
204 *freep = rpkt;
205 else
206 free(rpkt);
207 return 0;
210 Fid*
211 _fsgetfid(Fsys *fs)
213 int i;
214 Fid *f;
216 qlock(&fs->lk);
217 if(fs->freefid == nil){
218 f = mallocz(sizeof(Fid)*Fidchunk, 1);
219 if(f == nil){
220 qunlock(&fs->lk);
221 return nil;
223 for(i=0; i<Fidchunk; i++){
224 f[i].fid = fs->nextfid++;
225 f[i].next = &f[i+1];
226 f[i].fs = fs;
228 f[i-1].next = nil;
229 fs->freefid = f;
231 f = fs->freefid;
232 fs->freefid = f->next;
233 fs->ref++;
234 qunlock(&fs->lk);
235 return f;
238 void
239 _fsputfid(Fid *f)
241 Fsys *fs;
243 fs = f->fs;
244 qlock(&fs->lk);
245 f->next = fs->freefid;
246 fs->freefid = f;
247 qunlock(&fs->lk);
248 _fsdecref(fs);
251 static int
252 _fsgettag(Mux *mux, void *pkt)
254 return GBIT16((uchar*)pkt+5);
257 static int
258 _fssettag(Mux *mux, void *pkt, uint tag)
260 PBIT16((uchar*)pkt+5, tag);
261 return 0;
264 static int
265 _fssend(Mux *mux, void *pkt)
267 Fsys *fs;
269 fs = mux->aux;
270 return threadwrite(fs->fd, pkt, GBIT32((uchar*)pkt));
273 static void*
274 _fsrecv(Mux *mux)
276 uchar *pkt;
277 uchar buf[4];
278 int n, nfd;
279 Fsys *fs;
281 fs = mux->aux;
282 n = threadreadn(fs->fd, buf, 4);
283 if(n != 4)
284 return nil;
285 n = GBIT32(buf);
286 pkt = malloc(n+4);
287 if(pkt == nil){
288 fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");
289 return nil;
291 PBIT32(pkt, n);
292 if(threadreadn(fs->fd, pkt+4, n-4) != n-4){
293 free(pkt);
294 return nil;
296 if(pkt[4] == Ropenfd){
297 if((nfd=threadrecvfd(fs->fd)) < 0){
298 fprint(2, "recv fd error: %r\n");
299 free(pkt);
300 return nil;
302 PBIT32(pkt+n-4, nfd);
304 return pkt;