blob: d72aa4c772e6081d9fa51945ccb7e26ad0cb43ae [file] [log] [blame]
rsc46f79932005-01-04 21:22:40 +00001/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
2/* See COPYRIGHT */
3
4#include <u.h>
5#include <libc.h>
6#include <fcall.h>
7#include <9pclient.h>
8#include <thread.h>
9#include "fsimpl.h"
10
11static int _fssend(Mux*, void*);
12static void *_fsrecv(Mux*);
13static int _fsgettag(Mux*, void*);
14static int _fssettag(Mux*, void*, uint);
15
16enum
17{
18 CFidchunk = 32
19};
20
21CFsys*
22fsinit(int fd)
23{
24 CFsys *fs;
25
26 fmtinstall('F', fcallfmt);
27 fmtinstall('D', dirfmt);
28 fmtinstall('M', dirmodefmt);
29
30 fs = mallocz(sizeof(CFsys), 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 fs->iorecv = ioproc();
43 fs->iosend = ioproc();
44 muxinit(&fs->mux);
45 return fs;
46}
47
48CFid*
49fsroot(CFsys *fs)
50{
51 /* N.B. no incref */
52 return fs->root;
53}
54
55CFsys*
56fsmount(int fd, char *aname)
57{
58 int n;
59 char *user;
60 CFsys *fs;
61 CFid *fid;
62
63 fs = fsinit(fd);
64 if(fs == nil)
65 return nil;
66 strcpy(fs->version, "9P2000");
67 if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){
68 Error:
69 fs->fd = -1;
70 fsunmount(fs);
71 return nil;
72 }
73 fs->msize = n;
74
75 user = getuser();
76 if((fid = fsattach(fs, nil, getuser(), aname)) == nil)
77 goto Error;
78 fssetroot(fs, fid);
79 return fs;
80}
81
82void
83fsunmount(CFsys *fs)
84{
85 fsclose(fs->root);
86 fs->root = nil;
87 _fsdecref(fs);
88}
89
90void
91_fsdecref(CFsys *fs)
92{
93 CFid *f, **l, *next;
94
95 qlock(&fs->lk);
96 --fs->ref;
97 //fprint(2, "fsdecref %p to %d\n", fs, fs->ref);
98 if(fs->ref == 0){
99 close(fs->fd);
100 /* trim the list down to just the first in each chunk */
101 for(l=&fs->freefid; *l; ){
102 if((*l)->fid%CFidchunk == 0)
103 l = &(*l)->next;
104 else
105 *l = (*l)->next;
106 }
107 /* now free the list */
108 for(f=fs->freefid; f; f=next){
109 next = f->next;
110 free(f);
111 }
112 closeioproc(fs->iorecv);
113 closeioproc(fs->iosend);
114 free(fs);
115 return;
116 }
117 qunlock(&fs->lk);
118}
119
120int
121fsversion(CFsys *fs, int msize, char *version, int nversion)
122{
123 void *freep;
124 int r, oldmintag, oldmaxtag;
125 Fcall tx, rx;
126
127 tx.tag = 0;
128 tx.type = Tversion;
129 tx.version = version;
130 tx.msize = msize;
131
132 /*
133 * bit of a clumsy hack -- force libmux to use NOTAG as tag.
134 * version can only be sent when there are no other messages
135 * outstanding on the wire, so this is more reasonable than it looks.
136 */
137 oldmintag = fs->mux.mintag;
138 oldmaxtag = fs->mux.maxtag;
139 fs->mux.mintag = NOTAG;
140 fs->mux.maxtag = NOTAG+1;
141 r = _fsrpc(fs, &tx, &rx, &freep);
142 fs->mux.mintag = oldmintag;
143 fs->mux.maxtag = oldmaxtag;
144 if(r < 0)
145 return -1;
146
147 strecpy(version, version+nversion, rx.version);
148 free(freep);
149 return rx.msize;
150}
151
152CFid*
153fsattach(CFsys *fs, CFid *afid, char *user, char *aname)
154{
155 Fcall tx, rx;
156 CFid *fid;
157
158 if(aname == nil)
159 aname = "";
160
161 if((fid = _fsgetfid(fs)) == nil)
162 return nil;
163
164 tx.tag = 0;
165 tx.type = Tattach;
166 tx.afid = afid ? afid->fid : NOFID;
167 tx.fid = fid->fid;
168 tx.uname = user;
169 tx.aname = aname;
170
171 if(_fsrpc(fs, &tx, &rx, 0) < 0){
172 _fsputfid(fid);
173 return nil;
174 }
175 fid->qid = rx.qid;
176 return fid;
177}
178
179void
180fssetroot(CFsys *fs, CFid *fid)
181{
182 if(fs->root)
183 _fsputfid(fs->root);
184 fs->root = fid;
185}
186
187int
188_fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)
189{
190 int n, nn;
191 void *tpkt, *rpkt;
192
193 n = sizeS2M(tx);
194 tpkt = malloc(n);
195 if(freep)
196 *freep = nil;
197 if(tpkt == nil)
198 return -1;
199 //fprint(2, "<- %F\n", tx);
200 nn = convS2M(tx, tpkt, n);
201 if(nn != n){
202 free(tpkt);
203 werrstr("libfs: sizeS2M convS2M mismatch");
204 fprint(2, "%r\n");
205 return -1;
206 }
207 rpkt = muxrpc(&fs->mux, tpkt);
208 free(tpkt);
209 if(rpkt == nil)
210 return -1;
211 n = GBIT32((uchar*)rpkt);
212 nn = convM2S(rpkt, n, rx);
213 if(nn != n){
214 free(rpkt);
215 werrstr("libfs: convM2S packet size mismatch %d %d", n, nn);
216 fprint(2, "%r\n");
217 return -1;
218 }
219 //fprint(2, "-> %F\n", rx);
220 if(rx->type == Rerror){
221 werrstr("%s", rx->ename);
222 free(rpkt);
223 return -1;
224 }
225 if(rx->type != tx->type+1){
226 werrstr("packet type mismatch -- tx %d rx %d",
227 tx->type, rx->type);
228 free(rpkt);
229 return -1;
230 }
231 if(freep)
232 *freep = rpkt;
233 else
234 free(rpkt);
235 return 0;
236}
237
238CFid*
239_fsgetfid(CFsys *fs)
240{
241 int i;
242 CFid *f;
243
244 qlock(&fs->lk);
245 if(fs->freefid == nil){
246 f = mallocz(sizeof(CFid)*CFidchunk, 1);
247 if(f == nil){
248 qunlock(&fs->lk);
249 return nil;
250 }
251 for(i=0; i<CFidchunk; i++){
252 f[i].fid = fs->nextfid++;
253 f[i].next = &f[i+1];
254 f[i].fs = fs;
255 }
256 f[i-1].next = nil;
257 fs->freefid = f;
258 }
259 f = fs->freefid;
260 fs->freefid = f->next;
261 fs->ref++;
262 qunlock(&fs->lk);
263 return f;
264}
265
266void
267_fsputfid(CFid *f)
268{
269 CFsys *fs;
270
271 fs = f->fs;
272 qlock(&fs->lk);
273 f->next = fs->freefid;
274 fs->freefid = f;
275 qunlock(&fs->lk);
276 _fsdecref(fs);
277}
278
279static int
280_fsgettag(Mux *mux, void *pkt)
281{
282 return GBIT16((uchar*)pkt+5);
283}
284
285static int
286_fssettag(Mux *mux, void *pkt, uint tag)
287{
288 PBIT16((uchar*)pkt+5, tag);
289 return 0;
290}
291
292static int
293_fssend(Mux *mux, void *pkt)
294{
295 CFsys *fs;
296
297 fs = mux->aux;
298 return iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));
299}
300
301static void*
302_fsrecv(Mux *mux)
303{
304 uchar *pkt;
305 uchar buf[4];
306 int n, nfd;
307 CFsys *fs;
308
309 fs = mux->aux;
310 n = ioreadn(fs->iorecv, fs->fd, buf, 4);
311 if(n != 4)
312 return nil;
313 n = GBIT32(buf);
314 pkt = malloc(n+4);
315 if(pkt == nil){
316 fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");
317 return nil;
318 }
319 PBIT32(pkt, n);
320 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){
321 free(pkt);
322 return nil;
323 }
324 if(pkt[4] == Ropenfd){
325 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){
326 fprint(2, "recv fd error: %r\n");
327 free(pkt);
328 return nil;
329 }
330 PBIT32(pkt+n-4, nfd);
331 }
332 return pkt;
333}