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, *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 for(f=fs->freefid; f; f=next){
97 next = f->next;
98 if(f->fid%Fidchunk == 0)
99 free(f);
101 free(fs);
103 qunlock(&fs->lk);
106 int
107 fsversion(Fsys *fs, int msize, char *version, int nversion)
109 void *freep;
110 Fcall tx, rx;
112 tx.tag = 0;
113 tx.type = Tversion;
114 tx.version = version;
115 tx.msize = msize;
117 if(fsrpc(fs, &tx, &rx, &freep) < 0)
118 return -1;
119 strecpy(version, version+nversion, rx.version);
120 free(freep);
121 return rx.msize;
124 Fid*
125 fsattach(Fsys *fs, Fid *afid, char *user, char *aname)
127 Fcall tx, rx;
128 Fid *fid;
130 if(aname == nil)
131 aname = "";
133 if((fid = _fsgetfid(fs)) == nil)
134 return nil;
136 tx.tag = 0;
137 tx.type = Tattach;
138 tx.afid = afid ? afid->fid : NOFID;
139 tx.fid = fid->fid;
140 tx.uname = user;
141 tx.aname = aname;
143 if(fsrpc(fs, &tx, &rx, 0) < 0){
144 _fsputfid(fid);
145 return nil;
147 fid->qid = rx.qid;
148 return fid;
151 int
152 fsrpc(Fsys *fs, Fcall *tx, Fcall *rx, void **freep)
154 int n, nn;
155 void *tpkt, *rpkt;
157 n = sizeS2M(tx);
158 tpkt = malloc(n);
159 if(freep)
160 *freep = nil;
161 if(tpkt == nil)
162 return -1;
163 //fprint(2, "<- %F\n", tx);
164 nn = convS2M(tx, tpkt, n);
165 if(nn != n){
166 free(tpkt);
167 werrstr("libfs: sizeS2M convS2M mismatch");
168 fprint(2, "%r\n");
169 return -1;
171 rpkt = muxrpc(&fs->mux, tpkt);
172 free(tpkt);
173 if(rpkt == nil)
174 return -1;
175 n = GBIT32((uchar*)rpkt);
176 nn = convM2S(rpkt, n, rx);
177 if(nn != n){
178 free(rpkt);
179 werrstr("libfs: convM2S packet size mismatch %d %d", n, nn);
180 fprint(2, "%r\n");
181 return -1;
183 //fprint(2, "-> %F\n", rx);
184 if(rx->type == Rerror){
185 werrstr("%s", rx->ename);
186 free(rpkt);
187 return -1;
189 if(rx->type != tx->type+1){
190 werrstr("packet type mismatch -- tx %d rx %d",
191 tx->type, rx->type);
192 free(rpkt);
193 return -1;
195 if(freep)
196 *freep = rpkt;
197 else
198 free(rpkt);
199 return 0;
202 Fid*
203 _fsgetfid(Fsys *fs)
205 int i;
206 Fid *f;
208 qlock(&fs->lk);
209 if(fs->freefid == nil){
210 f = mallocz(sizeof(Fid)*Fidchunk, 1);
211 if(f == nil){
212 qunlock(&fs->lk);
213 return nil;
215 for(i=0; i<Fidchunk; i++){
216 f[i].fid = fs->nextfid++;
217 f[i].next = &f[i+1];
218 f[i].fs = fs;
220 f[i-1].next = nil;
221 fs->freefid = f;
223 f = fs->freefid;
224 fs->freefid = f->next;
225 fs->ref++;
226 qunlock(&fs->lk);
227 return f;
230 void
231 _fsputfid(Fid *f)
233 Fsys *fs;
235 fs = f->fs;
236 qlock(&fs->lk);
237 f->next = fs->freefid;
238 fs->freefid = f;
239 qunlock(&fs->lk);
240 _fsdecref(fs);
243 static int
244 _fsgettag(Mux *mux, void *pkt)
246 return GBIT16((uchar*)pkt+5);
249 static int
250 _fssettag(Mux *mux, void *pkt, uint tag)
252 PBIT16((uchar*)pkt+5, tag);
253 return 0;
256 static int
257 _fssend(Mux *mux, void *pkt)
259 Fsys *fs;
261 fs = mux->aux;
262 return threadwrite(fs->fd, pkt, GBIT32((uchar*)pkt));
265 static void*
266 _fsrecv(Mux *mux)
268 uchar *pkt;
269 uchar buf[4];
270 int n, nfd;
271 Fsys *fs;
273 fs = mux->aux;
274 n = threadreadn(fs->fd, buf, 4);
275 if(n != 4)
276 return nil;
277 n = GBIT32(buf);
278 pkt = malloc(n+4);
279 if(pkt == nil){
280 fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");
281 return nil;
283 PBIT32(pkt, n);
284 if(threadreadn(fs->fd, pkt+4, n-4) != n-4){
285 free(pkt);
286 return nil;
288 if(pkt[4] == Ropenfd){
289 if((nfd=threadrecvfd(fs->fd)) < 0){
290 fprint(2, "recv fd error: %r\n");
291 free(pkt);
292 return nil;
294 PBIT32(pkt+n-4, nfd);
296 return pkt;