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 fs->iorecv = ioproc();
43 fs->iosend = ioproc();
44 muxinit(&fs->mux);
45 return fs;
46 }
48 Fid*
49 fsroot(Fsys *fs)
50 {
51 /* N.B. no incref */
52 return fs->root;
53 }
55 Fsys*
56 fsmount(int fd, char *aname)
57 {
58 int n;
59 char *user;
60 Fsys *fs;
62 fs = fsinit(fd);
63 if(fs == nil)
64 return nil;
65 strcpy(fs->version, "9P2000");
66 if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){
67 Error:
68 fs->fd = -1;
69 fsunmount(fs);
70 return nil;
71 }
72 fs->msize = n;
74 user = getuser();
75 if((fs->root = fsattach(fs, nil, getuser(), aname)) == nil)
76 goto Error;
77 return fs;
78 }
80 void
81 fsunmount(Fsys *fs)
82 {
83 fsclose(fs->root);
84 fs->root = nil;
85 _fsdecref(fs);
86 }
88 void
89 _fsdecref(Fsys *fs)
90 {
91 Fid *f, **l, *next;
93 qlock(&fs->lk);
94 --fs->ref;
95 //fprint(2, "fsdecref %p to %d\n", fs, fs->ref);
96 if(fs->ref == 0){
97 close(fs->fd);
98 /* trim the list down to just the first in each chunk */
99 for(l=&fs->freefid; *l; ){
100 if((*l)->fid%Fidchunk == 0)
101 l = &(*l)->next;
102 else
103 *l = (*l)->next;
105 /* now free the list */
106 for(f=fs->freefid; f; f=next){
107 next = f->next;
108 free(f);
110 closeioproc(fs->iorecv);
111 closeioproc(fs->iosend);
112 free(fs);
113 return;
115 qunlock(&fs->lk);
118 int
119 fsversion(Fsys *fs, int msize, char *version, int nversion)
121 void *freep;
122 Fcall tx, rx;
124 tx.tag = 0;
125 tx.type = Tversion;
126 tx.version = version;
127 tx.msize = msize;
129 if(fsrpc(fs, &tx, &rx, &freep) < 0)
130 return -1;
131 strecpy(version, version+nversion, rx.version);
132 free(freep);
133 return rx.msize;
136 Fid*
137 fsattach(Fsys *fs, Fid *afid, char *user, char *aname)
139 Fcall tx, rx;
140 Fid *fid;
142 if(aname == nil)
143 aname = "";
145 if((fid = _fsgetfid(fs)) == nil)
146 return nil;
148 tx.tag = 0;
149 tx.type = Tattach;
150 tx.afid = afid ? afid->fid : NOFID;
151 tx.fid = fid->fid;
152 tx.uname = user;
153 tx.aname = aname;
155 if(fsrpc(fs, &tx, &rx, 0) < 0){
156 _fsputfid(fid);
157 return nil;
159 fid->qid = rx.qid;
160 return fid;
163 int
164 fsrpc(Fsys *fs, Fcall *tx, Fcall *rx, void **freep)
166 int n, nn;
167 void *tpkt, *rpkt;
169 n = sizeS2M(tx);
170 tpkt = malloc(n);
171 if(freep)
172 *freep = nil;
173 if(tpkt == nil)
174 return -1;
175 //fprint(2, "<- %F\n", tx);
176 nn = convS2M(tx, tpkt, n);
177 if(nn != n){
178 free(tpkt);
179 werrstr("libfs: sizeS2M convS2M mismatch");
180 fprint(2, "%r\n");
181 return -1;
183 rpkt = muxrpc(&fs->mux, tpkt);
184 free(tpkt);
185 if(rpkt == nil)
186 return -1;
187 n = GBIT32((uchar*)rpkt);
188 nn = convM2S(rpkt, n, rx);
189 if(nn != n){
190 free(rpkt);
191 werrstr("libfs: convM2S packet size mismatch %d %d", n, nn);
192 fprint(2, "%r\n");
193 return -1;
195 //fprint(2, "-> %F\n", rx);
196 if(rx->type == Rerror){
197 werrstr("%s", rx->ename);
198 free(rpkt);
199 return -1;
201 if(rx->type != tx->type+1){
202 werrstr("packet type mismatch -- tx %d rx %d",
203 tx->type, rx->type);
204 free(rpkt);
205 return -1;
207 if(freep)
208 *freep = rpkt;
209 else
210 free(rpkt);
211 return 0;
214 Fid*
215 _fsgetfid(Fsys *fs)
217 int i;
218 Fid *f;
220 qlock(&fs->lk);
221 if(fs->freefid == nil){
222 f = mallocz(sizeof(Fid)*Fidchunk, 1);
223 if(f == nil){
224 qunlock(&fs->lk);
225 return nil;
227 for(i=0; i<Fidchunk; i++){
228 f[i].fid = fs->nextfid++;
229 f[i].next = &f[i+1];
230 f[i].fs = fs;
232 f[i-1].next = nil;
233 fs->freefid = f;
235 f = fs->freefid;
236 fs->freefid = f->next;
237 fs->ref++;
238 qunlock(&fs->lk);
239 return f;
242 void
243 _fsputfid(Fid *f)
245 Fsys *fs;
247 fs = f->fs;
248 qlock(&fs->lk);
249 f->next = fs->freefid;
250 fs->freefid = f;
251 qunlock(&fs->lk);
252 _fsdecref(fs);
255 static int
256 _fsgettag(Mux *mux, void *pkt)
258 return GBIT16((uchar*)pkt+5);
261 static int
262 _fssettag(Mux *mux, void *pkt, uint tag)
264 PBIT16((uchar*)pkt+5, tag);
265 return 0;
268 static int
269 _fssend(Mux *mux, void *pkt)
271 Fsys *fs;
273 fs = mux->aux;
274 return iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));
277 static void*
278 _fsrecv(Mux *mux)
280 uchar *pkt;
281 uchar buf[4];
282 int n, nfd;
283 Fsys *fs;
285 fs = mux->aux;
286 n = ioreadn(fs->iorecv, fs->fd, buf, 4);
287 if(n != 4)
288 return nil;
289 n = GBIT32(buf);
290 pkt = malloc(n+4);
291 if(pkt == nil){
292 fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");
293 return nil;
295 PBIT32(pkt, n);
296 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){
297 free(pkt);
298 return nil;
300 if(pkt[4] == Ropenfd){
301 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){
302 fprint(2, "recv fd error: %r\n");
303 free(pkt);
304 return nil;
306 PBIT32(pkt+n-4, nfd);
308 return pkt;