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 <9pclient.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 int chatty9pclient;
18 enum
19 {
20 CFidchunk = 32
21 };
23 CFsys*
24 fsinit(int fd)
25 {
26 CFsys *fs;
27 int n;
29 fmtinstall('F', fcallfmt);
30 fmtinstall('D', dirfmt);
31 fmtinstall('M', dirmodefmt);
33 fs = mallocz(sizeof(CFsys), 1);
34 if(fs == nil)
35 return nil;
36 fs->fd = fd;
37 fs->ref = 1;
38 fs->mux.aux = fs;
39 fs->mux.mintag = 0;
40 fs->mux.maxtag = 256;
41 fs->mux.send = _fssend;
42 fs->mux.recv = _fsrecv;
43 fs->mux.gettag = _fsgettag;
44 fs->mux.settag = _fssettag;
45 fs->iorecv = ioproc();
46 fs->iosend = ioproc();
47 muxinit(&fs->mux);
49 strcpy(fs->version, "9P2000");
50 if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){
51 _fsunmount(fs);
52 return nil;
53 }
54 fs->msize = n;
55 return fs;
56 }
58 CFid*
59 fsroot(CFsys *fs)
60 {
61 /* N.B. no incref */
62 return fs->root;
63 }
65 CFsys*
66 fsmount(int fd, char *aname)
67 {
68 CFsys *fs;
69 CFid *fid;
71 fs = fsinit(fd);
72 if(fs == nil)
73 return nil;
75 if((fid = fsattach(fs, nil, getuser(), aname)) == nil){
76 _fsunmount(fs);
77 return nil;
78 }
79 fssetroot(fs, fid);
80 return fs;
81 }
83 void
84 _fsunmount(CFsys *fs)
85 {
86 fs->fd = -1;
87 fsunmount(fs);
88 }
90 void
91 fsunmount(CFsys *fs)
92 {
93 fsclose(fs->root);
94 fs->root = nil;
95 _fsdecref(fs);
96 }
98 void
99 _fsdecref(CFsys *fs)
101 CFid *f, **l, *next;
103 qlock(&fs->lk);
104 --fs->ref;
105 //fprint(2, "fsdecref %p to %d\n", fs, fs->ref);
106 if(fs->ref == 0){
107 if(fs->fd >= 0)
108 close(fs->fd);
109 /* trim the list down to just the first in each chunk */
110 for(l=&fs->freefid; *l; ){
111 if((*l)->fid%CFidchunk == 0)
112 l = &(*l)->next;
113 else
114 *l = (*l)->next;
116 /* now free the list */
117 for(f=fs->freefid; f; f=next){
118 next = f->next;
119 free(f);
121 closeioproc(fs->iorecv);
122 closeioproc(fs->iosend);
123 free(fs);
124 return;
126 qunlock(&fs->lk);
129 int
130 fsversion(CFsys *fs, int msize, char *version, int nversion)
132 void *freep;
133 int r, oldmintag, oldmaxtag;
134 Fcall tx, rx;
136 tx.tag = 0;
137 tx.type = Tversion;
138 tx.version = version;
139 tx.msize = msize;
141 /*
142 * bit of a clumsy hack -- force libmux to use NOTAG as tag.
143 * version can only be sent when there are no other messages
144 * outstanding on the wire, so this is more reasonable than it looks.
145 */
146 oldmintag = fs->mux.mintag;
147 oldmaxtag = fs->mux.maxtag;
148 fs->mux.mintag = NOTAG;
149 fs->mux.maxtag = NOTAG+1;
150 r = _fsrpc(fs, &tx, &rx, &freep);
151 fs->mux.mintag = oldmintag;
152 fs->mux.maxtag = oldmaxtag;
153 if(r < 0)
154 return -1;
156 strecpy(version, version+nversion, rx.version);
157 free(freep);
158 fs->msize = rx.msize;
159 return rx.msize;
162 CFid*
163 fsattach(CFsys *fs, CFid *afid, char *user, char *aname)
165 Fcall tx, rx;
166 CFid *fid;
168 if(aname == nil)
169 aname = "";
171 if((fid = _fsgetfid(fs)) == nil)
172 return nil;
174 tx.tag = 0;
175 tx.type = Tattach;
176 tx.afid = afid ? afid->fid : NOFID;
177 tx.fid = fid->fid;
178 tx.uname = user;
179 tx.aname = aname;
181 if(_fsrpc(fs, &tx, &rx, 0) < 0){
182 _fsputfid(fid);
183 return nil;
185 fid->qid = rx.qid;
186 return fid;
189 void
190 fssetroot(CFsys *fs, CFid *fid)
192 if(fs->root)
193 _fsputfid(fs->root);
194 fs->root = fid;
197 int
198 _fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)
200 int n, nn;
201 void *tpkt, *rpkt;
203 n = sizeS2M(tx);
204 tpkt = malloc(n);
205 if(freep)
206 *freep = nil;
207 if(tpkt == nil)
208 return -1;
209 tx->tag = 0;
210 if(chatty9pclient)
211 fprint(2, "<- %F\n", tx);
212 nn = convS2M(tx, tpkt, n);
213 if(nn != n){
214 free(tpkt);
215 werrstr("libfs: sizeS2M convS2M mismatch");
216 fprint(2, "%r\n");
217 return -1;
219 rpkt = muxrpc(&fs->mux, tpkt);
220 free(tpkt);
221 if(rpkt == nil)
222 return -1;
223 n = GBIT32((uchar*)rpkt);
224 nn = convM2S(rpkt, n, rx);
225 if(nn != n){
226 free(rpkt);
227 werrstr("libfs: convM2S packet size mismatch %d %d", n, nn);
228 fprint(2, "%r\n");
229 return -1;
231 if(chatty9pclient)
232 fprint(2, "-> %F\n", rx);
233 if(rx->type == Rerror){
234 werrstr("%s", rx->ename);
235 free(rpkt);
236 return -1;
238 if(rx->type != tx->type+1){
239 werrstr("packet type mismatch -- tx %d rx %d",
240 tx->type, rx->type);
241 free(rpkt);
242 return -1;
244 if(freep)
245 *freep = rpkt;
246 else
247 free(rpkt);
248 return 0;
251 CFid*
252 _fsgetfid(CFsys *fs)
254 int i;
255 CFid *f;
257 qlock(&fs->lk);
258 if(fs->freefid == nil){
259 f = mallocz(sizeof(CFid)*CFidchunk, 1);
260 if(f == nil){
261 qunlock(&fs->lk);
262 return nil;
264 for(i=0; i<CFidchunk; i++){
265 f[i].fid = fs->nextfid++;
266 f[i].next = &f[i+1];
267 f[i].fs = fs;
269 f[i-1].next = nil;
270 fs->freefid = f;
272 f = fs->freefid;
273 fs->freefid = f->next;
274 fs->ref++;
275 qunlock(&fs->lk);
276 f->offset = 0;
277 f->mode = -1;
278 f->qid.path = 0;
279 f->qid.vers = 0;
280 f->qid.type = 0;
281 return f;
284 void
285 _fsputfid(CFid *f)
287 CFsys *fs;
289 fs = f->fs;
290 qlock(&fs->lk);
291 f->next = fs->freefid;
292 fs->freefid = f;
293 qunlock(&fs->lk);
294 _fsdecref(fs);
297 static int
298 _fsgettag(Mux *mux, void *pkt)
300 return GBIT16((uchar*)pkt+5);
303 static int
304 _fssettag(Mux *mux, void *pkt, uint tag)
306 PBIT16((uchar*)pkt+5, tag);
307 return 0;
310 static int
311 _fssend(Mux *mux, void *pkt)
313 CFsys *fs;
315 fs = mux->aux;
316 return iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));
319 static void*
320 _fsrecv(Mux *mux)
322 uchar *pkt;
323 uchar buf[4];
324 int n, nfd;
325 CFsys *fs;
327 fs = mux->aux;
328 n = ioreadn(fs->iorecv, fs->fd, buf, 4);
329 if(n != 4)
330 return nil;
331 n = GBIT32(buf);
332 pkt = malloc(n+4);
333 if(pkt == nil){
334 fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");
335 return nil;
337 PBIT32(pkt, n);
338 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){
339 free(pkt);
340 return nil;
342 if(pkt[4] == Ropenfd){
343 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){
344 fprint(2, "recv fd error: %r\n");
345 free(pkt);
346 return nil;
348 PBIT32(pkt+n-4, nfd);
350 return pkt;