a3a1ac61072369705be2b08356853f330f000bb2
[linux-2.6.git] / fs / 9p / 9p.c
1 /*
2  *  linux/fs/9p/9p.c
3  *
4  *  This file contains functions 9P2000 functions
5  *
6  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to:
21  *  Free Software Foundation
22  *  51 Franklin Street, Fifth Floor
23  *  Boston, MA  02111-1301  USA
24  *
25  */
26
27 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/errno.h>
30 #include <linux/fs.h>
31 #include <linux/idr.h>
32
33 #include "debug.h"
34 #include "v9fs.h"
35 #include "9p.h"
36 #include "mux.h"
37
38 /**
39  * v9fs_t_version - negotiate protocol parameters with sever
40  * @v9ses: 9P2000 session information
41  * @msize: requested max size packet
42  * @version: requested version.extension string
43  * @fcall: pointer to response fcall pointer
44  *
45  */
46
47 int
48 v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
49                char *version, struct v9fs_fcall **fcall)
50 {
51         struct v9fs_fcall msg;
52
53         dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version);
54         msg.id = TVERSION;
55         msg.tag = ~0;
56         msg.params.tversion.msize = msize;
57         msg.params.tversion.version = version;
58
59         return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
60 }
61
62 /**
63  * v9fs_t_attach - mount the server
64  * @v9ses: 9P2000 session information
65  * @uname: user name doing the attach
66  * @aname: remote name being attached to
67  * @fid: mount fid to attatch to root node
68  * @afid: authentication fid (in this case result key)
69  * @fcall: pointer to response fcall pointer
70  *
71  */
72
73 int
74 v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
75               u32 fid, u32 afid, struct v9fs_fcall **fcall)
76 {
77         struct v9fs_fcall msg;
78
79         dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
80                 aname, fid, afid);
81         msg.id = TATTACH;
82         msg.params.tattach.fid = fid;
83         msg.params.tattach.afid = afid;
84         msg.params.tattach.uname = uname;
85         msg.params.tattach.aname = aname;
86
87         return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
88 }
89
90 static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
91         struct v9fs_fcall *rc, int err)
92 {
93         int fid;
94         struct v9fs_session_info *v9ses;
95
96         if (err)
97                 return;
98
99         fid = tc->params.tclunk.fid;
100         kfree(tc);
101
102         if (!rc)
103                 return;
104
105         dprintk(DEBUG_9P, "tcall id %d rcall id %d\n", tc->id, rc->id);
106         v9ses = a;
107         if (rc->id == RCLUNK)
108                 v9fs_put_idpool(fid, &v9ses->fidpool);
109
110         kfree(rc);
111 }
112
113 /**
114  * v9fs_t_clunk - release a fid (finish a transaction)
115  * @v9ses: 9P2000 session information
116  * @fid: fid to release
117  * @fcall: pointer to response fcall pointer
118  *
119  */
120 int
121 v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid)
122 {
123         int err;
124         struct v9fs_fcall *tc, *rc;
125
126         tc = kmalloc(sizeof(struct v9fs_fcall), GFP_KERNEL);
127
128         dprintk(DEBUG_9P, "fid %d\n", fid);
129         tc->id = TCLUNK;
130         tc->params.tclunk.fid = fid;
131
132         err = v9fs_mux_rpc(v9ses->mux, tc, &rc);
133         if (err >= 0) {
134                 v9fs_t_clunk_cb(v9ses, tc, rc, 0);
135         }
136
137         return err;
138 }
139
140 /**
141  * v9fs_v9fs_t_flush - flush a pending transaction
142  * @v9ses: 9P2000 session information
143  * @tag: tid to release
144  *
145  */
146
147 int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag)
148 {
149         struct v9fs_fcall msg;
150
151         dprintk(DEBUG_9P, "oldtag %d\n", tag);
152         msg.id = TFLUSH;
153         msg.params.tflush.oldtag = tag;
154         return v9fs_mux_rpc(v9ses->mux, &msg, NULL);
155 }
156
157 /**
158  * v9fs_t_stat - read a file's meta-data
159  * @v9ses: 9P2000 session information
160  * @fid: fid pointing to file or directory to get info about
161  * @fcall: pointer to response fcall
162  *
163  */
164
165 int
166 v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall)
167 {
168         struct v9fs_fcall msg;
169
170         dprintk(DEBUG_9P, "fid %d\n", fid);
171         if (fcall)
172                 *fcall = NULL;
173
174         msg.id = TSTAT;
175         msg.params.tstat.fid = fid;
176         return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
177 }
178
179 /**
180  * v9fs_t_wstat - write a file's meta-data
181  * @v9ses: 9P2000 session information
182  * @fid: fid pointing to file or directory to write info about
183  * @stat: metadata
184  * @fcall: pointer to response fcall
185  *
186  */
187
188 int
189 v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
190              struct v9fs_stat *stat, struct v9fs_fcall **fcall)
191 {
192         struct v9fs_fcall msg;
193
194         dprintk(DEBUG_9P, "fid %d length %d\n", fid, (int)stat->length);
195         msg.id = TWSTAT;
196         msg.params.twstat.fid = fid;
197         msg.params.twstat.stat = stat;
198
199         return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
200 }
201
202 /**
203  * v9fs_t_walk - walk a fid to a new file or directory
204  * @v9ses: 9P2000 session information
205  * @fid: fid to walk
206  * @newfid: new fid (for clone operations)
207  * @name: path to walk fid to
208  * @fcall: pointer to response fcall
209  *
210  */
211
212 /* TODO: support multiple walk */
213
214 int
215 v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
216             char *name, struct v9fs_fcall **fcall)
217 {
218         struct v9fs_fcall msg;
219
220         dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name);
221         msg.id = TWALK;
222         msg.params.twalk.fid = fid;
223         msg.params.twalk.newfid = newfid;
224
225         if (name) {
226                 msg.params.twalk.nwname = 1;
227                 msg.params.twalk.wnames = &name;
228         } else {
229                 msg.params.twalk.nwname = 0;
230         }
231
232         return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
233 }
234
235 /**
236  * v9fs_t_open - open a file
237  *
238  * @v9ses - 9P2000 session information
239  * @fid - fid to open
240  * @mode - mode to open file (R, RW, etc)
241  * @fcall - pointer to response fcall
242  *
243  */
244
245 int
246 v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
247             struct v9fs_fcall **fcall)
248 {
249         struct v9fs_fcall msg;
250         int errorno = -1;
251
252         dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
253         msg.id = TOPEN;
254         msg.params.topen.fid = fid;
255         msg.params.topen.mode = mode;
256
257         errorno = v9fs_mux_rpc(v9ses->mux, &msg, fcall);
258
259         return errorno;
260 }
261
262 /**
263  * v9fs_t_remove - remove a file or directory
264  * @v9ses: 9P2000 session information
265  * @fid: fid to remove
266  * @fcall: pointer to response fcall
267  *
268  */
269
270 int
271 v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
272               struct v9fs_fcall **fcall)
273 {
274         struct v9fs_fcall msg;
275
276         dprintk(DEBUG_9P, "fid %d\n", fid);
277         msg.id = TREMOVE;
278         msg.params.tremove.fid = fid;
279         return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
280 }
281
282 /**
283  * v9fs_t_create - create a file or directory
284  * @v9ses: 9P2000 session information
285  * @fid: fid to create
286  * @name: name of the file or directory to create
287  * @perm: permissions to create with
288  * @mode: mode to open file (R, RW, etc)
289  * @fcall: pointer to response fcall
290  *
291  */
292
293 int
294 v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
295               u32 perm, u8 mode, struct v9fs_fcall **fcall)
296 {
297         struct v9fs_fcall msg;
298
299         dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
300                 fid, name, perm, mode);
301
302         msg.id = TCREATE;
303         msg.params.tcreate.fid = fid;
304         msg.params.tcreate.name = name;
305         msg.params.tcreate.perm = perm;
306         msg.params.tcreate.mode = mode;
307
308         return v9fs_mux_rpc(v9ses->mux, &msg, fcall);
309 }
310
311 /**
312  * v9fs_t_read - read data
313  * @v9ses: 9P2000 session information
314  * @fid: fid to read from
315  * @offset: offset to start read at
316  * @count: how many bytes to read
317  * @fcall: pointer to response fcall (with data)
318  *
319  */
320
321 int
322 v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
323             u32 count, struct v9fs_fcall **fcall)
324 {
325         struct v9fs_fcall msg;
326         struct v9fs_fcall *rc = NULL;
327         long errorno = -1;
328
329         dprintk(DEBUG_9P, "fid %d offset 0x%lx count 0x%x\n", fid,
330                 (long unsigned int)offset, count);
331         msg.id = TREAD;
332         msg.params.tread.fid = fid;
333         msg.params.tread.offset = offset;
334         msg.params.tread.count = count;
335         errorno = v9fs_mux_rpc(v9ses->mux, &msg, &rc);
336
337         if (!errorno) {
338                 errorno = rc->params.rread.count;
339                 dump_data(rc->params.rread.data, rc->params.rread.count);
340         }
341
342         if (fcall)
343                 *fcall = rc;
344         else
345                 kfree(rc);
346
347         return errorno;
348 }
349
350 /**
351  * v9fs_t_write - write data
352  * @v9ses: 9P2000 session information
353  * @fid: fid to write to
354  * @offset: offset to start write at
355  * @count: how many bytes to write
356  * @fcall: pointer to response fcall
357  *
358  */
359
360 int
361 v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid,
362              u64 offset, u32 count, void *data, struct v9fs_fcall **fcall)
363 {
364         struct v9fs_fcall msg;
365         struct v9fs_fcall *rc = NULL;
366         long errorno = -1;
367
368         dprintk(DEBUG_9P, "fid %d offset 0x%llx count 0x%x\n", fid,
369                 (unsigned long long)offset, count);
370         dump_data(data, count);
371
372         msg.id = TWRITE;
373         msg.params.twrite.fid = fid;
374         msg.params.twrite.offset = offset;
375         msg.params.twrite.count = count;
376         msg.params.twrite.data = data;
377
378         errorno = v9fs_mux_rpc(v9ses->mux, &msg, &rc);
379
380         if (!errorno)
381                 errorno = rc->params.rwrite.count;
382
383         if (fcall)
384                 *fcall = rc;
385         else
386                 kfree(rc);
387
388         return errorno;
389 }