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