Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee13...
[linux-2.6] / fs / 9p / fcall.c
1 /*
2  *  linux/fs/9p/fcall.c
3  *
4  *  This file contains functions to perform synchronous 9P calls
5  *
6  *  Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
7  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License version 2
12  *  as published by the Free Software Foundation.
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/module.h>
28 #include <linux/errno.h>
29 #include <linux/fs.h>
30 #include <linux/idr.h>
31
32 #include "debug.h"
33 #include "v9fs.h"
34 #include "9p.h"
35 #include "conv.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 **rcp)
50 {
51         int ret;
52         struct v9fs_fcall *tc;
53
54         dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version);
55         tc = v9fs_create_tversion(msize, version);
56
57         if (!IS_ERR(tc)) {
58                 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
59                 kfree(tc);
60         } else
61                 ret = PTR_ERR(tc);
62
63         return ret;
64 }
65
66 /**
67  * v9fs_t_attach - mount the server
68  * @v9ses: 9P2000 session information
69  * @uname: user name doing the attach
70  * @aname: remote name being attached to
71  * @fid: mount fid to attatch to root node
72  * @afid: authentication fid (in this case result key)
73  * @fcall: pointer to response fcall pointer
74  *
75  */
76
77 int
78 v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
79               u32 fid, u32 afid, struct v9fs_fcall **rcp)
80 {
81         int ret;
82         struct v9fs_fcall* tc;
83
84         dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
85                 aname, fid, afid);
86
87         tc = v9fs_create_tattach(fid, afid, uname, aname);
88         if (!IS_ERR(tc)) {
89                 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
90                 kfree(tc);
91         } else
92                 ret = PTR_ERR(tc);
93
94         return ret;
95 }
96
97 static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
98         struct v9fs_fcall *rc, int err)
99 {
100         int fid, id;
101         struct v9fs_session_info *v9ses;
102
103         id = 0;
104         fid = tc->params.tclunk.fid;
105         if (rc)
106                 id = rc->id;
107
108         kfree(tc);
109         kfree(rc);
110         if (id == RCLUNK) {
111                 v9ses = a;
112                 v9fs_put_idpool(fid, &v9ses->fidpool);
113         }
114 }
115
116 /**
117  * v9fs_t_clunk - release a fid (finish a transaction)
118  * @v9ses: 9P2000 session information
119  * @fid: fid to release
120  * @fcall: pointer to response fcall pointer
121  *
122  */
123
124 int
125 v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid)
126 {
127         int ret;
128         struct v9fs_fcall *tc, *rc;
129
130         dprintk(DEBUG_9P, "fid %d\n", fid);
131
132         rc = NULL;
133         tc = v9fs_create_tclunk(fid);
134         if (!IS_ERR(tc))
135                 ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
136         else
137                 ret = PTR_ERR(tc);
138
139         if (ret)
140                 dprintk(DEBUG_ERROR, "failed fid %d err %d\n", fid, ret);
141
142         v9fs_t_clunk_cb(v9ses, tc, rc, ret);
143         return ret;
144 }
145
146 #if 0
147 /**
148  * v9fs_v9fs_t_flush - flush a pending transaction
149  * @v9ses: 9P2000 session information
150  * @tag: tag to release
151  *
152  */
153 int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag)
154 {
155         int ret;
156         struct v9fs_fcall *tc;
157
158         dprintk(DEBUG_9P, "oldtag %d\n", oldtag);
159
160         tc = v9fs_create_tflush(oldtag);
161         if (!IS_ERR(tc)) {
162                 ret = v9fs_mux_rpc(v9ses->mux, tc, NULL);
163                 kfree(tc);
164         } else
165                 ret = PTR_ERR(tc);
166
167         return ret;
168 }
169 #endif
170
171 /**
172  * v9fs_t_stat - read a file's meta-data
173  * @v9ses: 9P2000 session information
174  * @fid: fid pointing to file or directory to get info about
175  * @fcall: pointer to response fcall
176  *
177  */
178
179 int
180 v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **rcp)
181 {
182         int ret;
183         struct v9fs_fcall *tc;
184
185         dprintk(DEBUG_9P, "fid %d\n", fid);
186
187         ret = -ENOMEM;
188         tc = v9fs_create_tstat(fid);
189         if (!IS_ERR(tc)) {
190                 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
191                 kfree(tc);
192         } else
193                 ret = PTR_ERR(tc);
194
195         return ret;
196 }
197
198 /**
199  * v9fs_t_wstat - write a file's meta-data
200  * @v9ses: 9P2000 session information
201  * @fid: fid pointing to file or directory to write info about
202  * @stat: metadata
203  * @fcall: pointer to response fcall
204  *
205  */
206
207 int
208 v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
209              struct v9fs_wstat *wstat, struct v9fs_fcall **rcp)
210 {
211         int ret;
212         struct v9fs_fcall *tc;
213
214         dprintk(DEBUG_9P, "fid %d\n", fid);
215
216         tc = v9fs_create_twstat(fid, wstat, v9ses->extended);
217         if (!IS_ERR(tc)) {
218                 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
219                 kfree(tc);
220         } else
221                 ret = PTR_ERR(tc);
222
223         return ret;
224 }
225
226 /**
227  * v9fs_t_walk - walk a fid to a new file or directory
228  * @v9ses: 9P2000 session information
229  * @fid: fid to walk
230  * @newfid: new fid (for clone operations)
231  * @name: path to walk fid to
232  * @fcall: pointer to response fcall
233  *
234  */
235
236 /* TODO: support multiple walk */
237
238 int
239 v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
240             char *name, struct v9fs_fcall **rcp)
241 {
242         int ret;
243         struct v9fs_fcall *tc;
244         int nwname;
245
246         dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name);
247
248         if (name)
249                 nwname = 1;
250         else
251                 nwname = 0;
252
253         tc = v9fs_create_twalk(fid, newfid, nwname, &name);
254         if (!IS_ERR(tc)) {
255                 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
256                 kfree(tc);
257         } else
258                 ret = PTR_ERR(tc);
259
260         return ret;
261 }
262
263 /**
264  * v9fs_t_open - open a file
265  *
266  * @v9ses - 9P2000 session information
267  * @fid - fid to open
268  * @mode - mode to open file (R, RW, etc)
269  * @fcall - pointer to response fcall
270  *
271  */
272
273 int
274 v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
275             struct v9fs_fcall **rcp)
276 {
277         int ret;
278         struct v9fs_fcall *tc;
279
280         dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
281
282         tc = v9fs_create_topen(fid, mode);
283         if (!IS_ERR(tc)) {
284                 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
285                 kfree(tc);
286         } else
287                 ret = PTR_ERR(tc);
288
289         return ret;
290 }
291
292 /**
293  * v9fs_t_remove - remove a file or directory
294  * @v9ses: 9P2000 session information
295  * @fid: fid to remove
296  * @fcall: pointer to response fcall
297  *
298  */
299
300 int
301 v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
302               struct v9fs_fcall **rcp)
303 {
304         int ret;
305         struct v9fs_fcall *tc;
306
307         dprintk(DEBUG_9P, "fid %d\n", fid);
308
309         tc = v9fs_create_tremove(fid);
310         if (!IS_ERR(tc)) {
311                 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
312                 kfree(tc);
313         } else
314                 ret = PTR_ERR(tc);
315
316         return ret;
317 }
318
319 /**
320  * v9fs_t_create - create a file or directory
321  * @v9ses: 9P2000 session information
322  * @fid: fid to create
323  * @name: name of the file or directory to create
324  * @perm: permissions to create with
325  * @mode: mode to open file (R, RW, etc)
326  * @fcall: pointer to response fcall
327  *
328  */
329
330 int
331 v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, u32 perm,
332         u8 mode, char *extension, struct v9fs_fcall **rcp)
333 {
334         int ret;
335         struct v9fs_fcall *tc;
336
337         dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
338                 fid, name, perm, mode);
339
340         tc = v9fs_create_tcreate(fid, name, perm, mode, extension,
341                 v9ses->extended);
342
343         if (!IS_ERR(tc)) {
344                 ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
345                 kfree(tc);
346         } else
347                 ret = PTR_ERR(tc);
348
349         return ret;
350 }
351
352 /**
353  * v9fs_t_read - read data
354  * @v9ses: 9P2000 session information
355  * @fid: fid to read from
356  * @offset: offset to start read at
357  * @count: how many bytes to read
358  * @fcall: pointer to response fcall (with data)
359  *
360  */
361
362 int
363 v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
364             u32 count, struct v9fs_fcall **rcp)
365 {
366         int ret;
367         struct v9fs_fcall *tc, *rc;
368
369         dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
370                 (long long unsigned) offset, count);
371
372         tc = v9fs_create_tread(fid, offset, count);
373         if (!IS_ERR(tc)) {
374                 ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
375                 if (!ret)
376                         ret = rc->params.rread.count;
377                 if (rcp)
378                         *rcp = rc;
379                 else
380                         kfree(rc);
381
382                 kfree(tc);
383         } else
384                 ret = PTR_ERR(tc);
385
386         return ret;
387 }
388
389 /**
390  * v9fs_t_write - write data
391  * @v9ses: 9P2000 session information
392  * @fid: fid to write to
393  * @offset: offset to start write at
394  * @count: how many bytes to write
395  * @fcall: pointer to response fcall
396  *
397  */
398
399 int
400 v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count,
401         const char __user *data, struct v9fs_fcall **rcp)
402 {
403         int ret;
404         struct v9fs_fcall *tc, *rc;
405
406         dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
407                 (long long unsigned) offset, count);
408
409         tc = v9fs_create_twrite(fid, offset, count, data);
410         if (!IS_ERR(tc)) {
411                 ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
412
413                 if (!ret)
414                         ret = rc->params.rwrite.count;
415                 if (rcp)
416                         *rcp = rc;
417                 else
418                         kfree(rc);
419
420                 kfree(tc);
421         } else
422                 ret = PTR_ERR(tc);
423
424         return ret;
425 }
426