9p: rename uid and gid parameters
[safe/jmp/linux-2.6] / fs / 9p / v9fs.c
1 /*
2  *  linux/fs/9p/v9fs.c
3  *
4  *  This file contains functions assisting in mapping VFS to 9P2000
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 version 2
11  *  as published by the Free Software Foundation.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to:
20  *  Free Software Foundation
21  *  51 Franklin Street, Fifth Floor
22  *  Boston, MA  02111-1301  USA
23  *
24  */
25
26 #include <linux/module.h>
27 #include <linux/errno.h>
28 #include <linux/fs.h>
29 #include <linux/sched.h>
30 #include <linux/parser.h>
31 #include <linux/idr.h>
32 #include <net/9p/9p.h>
33 #include <net/9p/transport.h>
34 #include <net/9p/conn.h>
35 #include <net/9p/client.h>
36 #include "v9fs.h"
37 #include "v9fs_vfs.h"
38
39 /*
40  * Dynamic Transport Registration Routines
41  *
42  */
43
44 static LIST_HEAD(v9fs_trans_list);
45 static struct p9_trans_module *v9fs_default_trans;
46
47 /**
48  * v9fs_register_trans - register a new transport with 9p
49  * @m - structure describing the transport module and entry points
50  *
51  */
52 void v9fs_register_trans(struct p9_trans_module *m)
53 {
54         list_add_tail(&m->list, &v9fs_trans_list);
55         if (m->def)
56                 v9fs_default_trans = m;
57 }
58 EXPORT_SYMBOL(v9fs_register_trans);
59
60 /**
61  * v9fs_match_trans - match transport versus registered transports
62  * @arg: string identifying transport
63  *
64  */
65 static struct p9_trans_module *v9fs_match_trans(const substring_t *name)
66 {
67         struct list_head *p;
68         struct p9_trans_module *t = NULL;
69
70         list_for_each(p, &v9fs_trans_list) {
71                 t = list_entry(p, struct p9_trans_module, list);
72                 if (strncmp(t->name, name->from, name->to-name->from) == 0) {
73                         P9_DPRINTK(P9_DEBUG_TRANS, "trans=%s\n", t->name);
74                         break;
75                 }
76         }
77         return t;
78 }
79
80 /*
81   * Option Parsing (code inspired by NFS code)
82   *  NOTE: each transport will parse its own options
83   */
84
85 enum {
86         /* Options that take integer arguments */
87         Opt_debug, Opt_msize, Opt_dfltuid, Opt_dfltgid, Opt_afid,
88         /* String options */
89         Opt_uname, Opt_remotename, Opt_trans,
90         /* Options that take no arguments */
91         Opt_legacy, Opt_nodevmap,
92         /* Cache options */
93         Opt_cache_loose,
94         /* Error token */
95         Opt_err
96 };
97
98 static match_table_t tokens = {
99         {Opt_debug, "debug=%x"},
100         {Opt_msize, "msize=%u"},
101         {Opt_dfltuid, "dfltuid=%u"},
102         {Opt_dfltgid, "dfltgid=%u"},
103         {Opt_afid, "afid=%u"},
104         {Opt_uname, "uname=%s"},
105         {Opt_remotename, "aname=%s"},
106         {Opt_trans, "trans=%s"},
107         {Opt_legacy, "noextend"},
108         {Opt_nodevmap, "nodevmap"},
109         {Opt_cache_loose, "cache=loose"},
110         {Opt_cache_loose, "loose"},
111         {Opt_err, NULL}
112 };
113
114 /**
115  * v9fs_parse_options - parse mount options into session structure
116  * @options: options string passed from mount
117  * @v9ses: existing v9fs session information
118  *
119  */
120
121 static void v9fs_parse_options(struct v9fs_session_info *v9ses)
122 {
123         char *options = v9ses->options;
124         substring_t args[MAX_OPT_ARGS];
125         char *p;
126         int option;
127         int ret;
128
129         /* setup defaults */
130         v9ses->maxdata = 8192;
131         v9ses->flags = V9FS_EXTENDED;
132         v9ses->afid = ~0;
133         v9ses->debug = 0;
134         v9ses->cache = 0;
135         v9ses->trans = v9fs_default_trans;
136
137         if (!options)
138                 return;
139
140         while ((p = strsep(&options, ",")) != NULL) {
141                 int token;
142                 if (!*p)
143                         continue;
144                 token = match_token(p, tokens, args);
145                 if (token < Opt_uname) {
146                         if ((ret = match_int(&args[0], &option)) < 0) {
147                                 P9_DPRINTK(P9_DEBUG_ERROR,
148                                         "integer field, but no integer?\n");
149                                 continue;
150                         }
151                 }
152                 switch (token) {
153                 case Opt_debug:
154                         v9ses->debug = option;
155 #ifdef CONFIG_NET_9P_DEBUG
156                         p9_debug_level = option;
157 #endif
158                         break;
159                 case Opt_msize:
160                         v9ses->maxdata = option;
161                         break;
162                 case Opt_dfltuid:
163                         v9ses->dfltuid = option;
164                         break;
165                 case Opt_dfltgid:
166                         v9ses->dfltgid = option;
167                         break;
168                 case Opt_afid:
169                         v9ses->afid = option;
170                         break;
171                 case Opt_trans:
172                         v9ses->trans = v9fs_match_trans(&args[0]);
173                         break;
174                 case Opt_uname:
175                         match_strcpy(v9ses->name, &args[0]);
176                         break;
177                 case Opt_remotename:
178                         match_strcpy(v9ses->remotename, &args[0]);
179                         break;
180                 case Opt_legacy:
181                         v9ses->flags &= ~V9FS_EXTENDED;
182                         break;
183                 case Opt_nodevmap:
184                         v9ses->nodev = 1;
185                         break;
186                 case Opt_cache_loose:
187                         v9ses->cache = CACHE_LOOSE;
188                         break;
189                 default:
190                         continue;
191                 }
192         }
193 }
194
195 /**
196  * v9fs_session_init - initialize session
197  * @v9ses: session information structure
198  * @dev_name: device being mounted
199  * @data: options
200  *
201  */
202
203 struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
204                   const char *dev_name, char *data)
205 {
206         int retval = -EINVAL;
207         struct p9_trans *trans = NULL;
208         struct p9_fid *fid;
209
210         v9ses->name = __getname();
211         if (!v9ses->name)
212                 return ERR_PTR(-ENOMEM);
213
214         v9ses->remotename = __getname();
215         if (!v9ses->remotename) {
216                 __putname(v9ses->name);
217                 return ERR_PTR(-ENOMEM);
218         }
219
220         strcpy(v9ses->name, V9FS_DEFUSER);
221         strcpy(v9ses->remotename, V9FS_DEFANAME);
222         v9ses->dfltuid = V9FS_DEFUID;
223         v9ses->dfltgid = V9FS_DEFGID;
224
225         v9ses->options = kstrdup(data, GFP_KERNEL);
226         v9fs_parse_options(v9ses);
227
228         if ((v9ses->trans == NULL) && !list_empty(&v9fs_trans_list))
229                 v9ses->trans = list_first_entry(&v9fs_trans_list,
230                  struct p9_trans_module, list);
231
232         if (v9ses->trans == NULL) {
233                 retval = -EPROTONOSUPPORT;
234                 P9_DPRINTK(P9_DEBUG_ERROR,
235                                 "No transport defined or default transport\n");
236                 goto error;
237         }
238
239         trans = v9ses->trans->create(dev_name, v9ses->options);
240         if (IS_ERR(trans)) {
241                 retval = PTR_ERR(trans);
242                 trans = NULL;
243                 goto error;
244         }
245         if ((v9ses->maxdata+P9_IOHDRSZ) > v9ses->trans->maxsize)
246                 v9ses->maxdata = v9ses->trans->maxsize-P9_IOHDRSZ;
247
248         v9ses->clnt = p9_client_create(trans, v9ses->maxdata+P9_IOHDRSZ,
249                 v9fs_extended(v9ses));
250
251         if (IS_ERR(v9ses->clnt)) {
252                 retval = PTR_ERR(v9ses->clnt);
253                 v9ses->clnt = NULL;
254                 P9_DPRINTK(P9_DEBUG_ERROR, "problem initializing 9p client\n");
255                 goto error;
256         }
257
258         fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name,
259                                                         v9ses->remotename);
260         if (IS_ERR(fid)) {
261                 retval = PTR_ERR(fid);
262                 fid = NULL;
263                 P9_DPRINTK(P9_DEBUG_ERROR, "cannot attach\n");
264                 goto error;
265         }
266
267         return fid;
268
269 error:
270         v9fs_session_close(v9ses);
271         return ERR_PTR(retval);
272 }
273
274 /**
275  * v9fs_session_close - shutdown a session
276  * @v9ses: session information structure
277  *
278  */
279
280 void v9fs_session_close(struct v9fs_session_info *v9ses)
281 {
282         if (v9ses->clnt) {
283                 p9_client_destroy(v9ses->clnt);
284                 v9ses->clnt = NULL;
285         }
286
287         __putname(v9ses->name);
288         __putname(v9ses->remotename);
289         kfree(v9ses->options);
290 }
291
292 /**
293  * v9fs_session_cancel - mark transport as disconnected
294  *      and cancel all pending requests.
295  */
296 void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
297         P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
298         p9_client_disconnect(v9ses->clnt);
299 }
300
301 extern int v9fs_error_init(void);
302
303 /**
304  * v9fs_init - Initialize module
305  *
306  */
307
308 static int __init init_v9fs(void)
309 {
310         printk(KERN_INFO "Installing v9fs 9p2000 file system support\n");
311         /* TODO: Setup list of registered trasnport modules */
312         return register_filesystem(&v9fs_fs_type);
313 }
314
315 /**
316  * v9fs_init - shutdown module
317  *
318  */
319
320 static void __exit exit_v9fs(void)
321 {
322         unregister_filesystem(&v9fs_fs_type);
323 }
324
325 module_init(init_v9fs)
326 module_exit(exit_v9fs)
327
328 MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
329 MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
330 MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
331 MODULE_LICENSE("GPL");