v9fs.c 8.3 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 *  linux/fs/9p/v9fs.c
 *
 *  This file contains functions assisting in mapping VFS to 9P2000
 *
 *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
 *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
 *
 *  This program is free software; you can redistribute it and/or modify
10 11
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to:
 *  Free Software Foundation
 *  51 Franklin Street, Fifth Floor
 *  Boston, MA  02111-1301  USA
 *
 */

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
29
#include <linux/sched.h>
30 31
#include <linux/parser.h>
#include <linux/idr.h>
32 33 34 35
#include <net/9p/9p.h>
#include <net/9p/transport.h>
#include <net/9p/conn.h>
#include <net/9p/client.h>
36 37 38
#include "v9fs.h"
#include "v9fs_vfs.h"

E
Eric Van Hensbergen 已提交
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
/*
 * Dynamic Transport Registration Routines
 *
 */

static LIST_HEAD(v9fs_trans_list);
static struct p9_trans_module *v9fs_default_trans;

/**
 * v9fs_register_trans - register a new transport with 9p
 * @m - structure describing the transport module and entry points
 *
 */
void v9fs_register_trans(struct p9_trans_module *m)
{
	list_add_tail(&m->list, &v9fs_trans_list);
	if (m->def)
		v9fs_default_trans = m;
}
EXPORT_SYMBOL(v9fs_register_trans);

/**
 * v9fs_match_trans - match transport versus registered transports
 * @arg: string identifying transport
 *
 */
static struct p9_trans_module *v9fs_match_trans(const substring_t *name)
{
	struct list_head *p;
	struct p9_trans_module *t = NULL;

	list_for_each(p, &v9fs_trans_list) {
		t = list_entry(p, struct p9_trans_module, list);
		if (strncmp(t->name, name->from, name->to-name->from) == 0) {
			P9_DPRINTK(P9_DEBUG_TRANS, "trans=%s\n", t->name);
			break;
		}
	}
	return t;
}

80 81
/*
  * Option Parsing (code inspired by NFS code)
E
Eric Van Hensbergen 已提交
82
  *  NOTE: each transport will parse its own options
83 84 85 86
  */

enum {
	/* Options that take integer arguments */
87
	Opt_debug, Opt_msize, Opt_dfltuid, Opt_dfltgid, Opt_afid,
88
	/* String options */
E
Eric Van Hensbergen 已提交
89
	Opt_uname, Opt_remotename, Opt_trans,
90
	/* Options that take no arguments */
E
Eric Van Hensbergen 已提交
91
	Opt_legacy, Opt_nodevmap,
92 93
	/* Cache options */
	Opt_cache_loose,
L
Latchesar Ionkov 已提交
94 95
	/* Access options */
	Opt_access,
96 97 98 99 100
	/* Error token */
	Opt_err
};

static match_table_t tokens = {
101
	{Opt_debug, "debug=%x"},
102
	{Opt_msize, "msize=%u"},
103 104
	{Opt_dfltuid, "dfltuid=%u"},
	{Opt_dfltgid, "dfltgid=%u"},
105
	{Opt_afid, "afid=%u"},
106
	{Opt_uname, "uname=%s"},
107
	{Opt_remotename, "aname=%s"},
E
Eric Van Hensbergen 已提交
108
	{Opt_trans, "trans=%s"},
109 110
	{Opt_legacy, "noextend"},
	{Opt_nodevmap, "nodevmap"},
111 112
	{Opt_cache_loose, "cache=loose"},
	{Opt_cache_loose, "loose"},
L
Latchesar Ionkov 已提交
113
	{Opt_access, "access=%s"},
114 115 116 117 118 119 120 121 122 123
	{Opt_err, NULL}
};

/**
 * v9fs_parse_options - parse mount options into session structure
 * @options: options string passed from mount
 * @v9ses: existing v9fs session information
 *
 */

E
Eric Van Hensbergen 已提交
124
static void v9fs_parse_options(struct v9fs_session_info *v9ses)
125
{
E
Eric Van Hensbergen 已提交
126
	char *options = v9ses->options;
127
	substring_t args[MAX_OPT_ARGS];
E
Eric Van Hensbergen 已提交
128
	char *p;
129 130
	int option;
	int ret;
L
Latchesar Ionkov 已提交
131
	char *s, *e;
132 133

	/* setup defaults */
E
Eric Van Hensbergen 已提交
134
	v9ses->maxdata = 8192;
135 136
	v9ses->afid = ~0;
	v9ses->debug = 0;
137
	v9ses->cache = 0;
E
Eric Van Hensbergen 已提交
138
	v9ses->trans = v9fs_default_trans;
139 140 141 142 143 144 145 146 147

	if (!options)
		return;

	while ((p = strsep(&options, ",")) != NULL) {
		int token;
		if (!*p)
			continue;
		token = match_token(p, tokens, args);
148
		if (token < Opt_uname) {
149
			if ((ret = match_int(&args[0], &option)) < 0) {
150
				P9_DPRINTK(P9_DEBUG_ERROR,
151 152 153 154 155
					"integer field, but no integer?\n");
				continue;
			}
		}
		switch (token) {
156 157
		case Opt_debug:
			v9ses->debug = option;
158
#ifdef CONFIG_NET_9P_DEBUG
159
			p9_debug_level = option;
160
#endif
161
			break;
162 163 164
		case Opt_msize:
			v9ses->maxdata = option;
			break;
165 166
		case Opt_dfltuid:
			v9ses->dfltuid = option;
167
			break;
168 169
		case Opt_dfltgid:
			v9ses->dfltgid = option;
170 171 172 173
			break;
		case Opt_afid:
			v9ses->afid = option;
			break;
E
Eric Van Hensbergen 已提交
174 175
		case Opt_trans:
			v9ses->trans = v9fs_match_trans(&args[0]);
176
			break;
177
		case Opt_uname:
L
Latchesar Ionkov 已提交
178
			match_strcpy(v9ses->uname, &args[0]);
179 180
			break;
		case Opt_remotename:
L
Latchesar Ionkov 已提交
181
			match_strcpy(v9ses->aname, &args[0]);
182 183
			break;
		case Opt_legacy:
L
Latchesar Ionkov 已提交
184
			v9ses->flags &= ~V9FS_EXTENDED;
185 186 187 188
			break;
		case Opt_nodevmap:
			v9ses->nodev = 1;
			break;
189 190 191
		case Opt_cache_loose:
			v9ses->cache = CACHE_LOOSE;
			break;
L
Latchesar Ionkov 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207

		case Opt_access:
			s = match_strdup(&args[0]);
			v9ses->flags &= ~V9FS_ACCESS_MASK;
			if (strcmp(s, "user") == 0)
				v9ses->flags |= V9FS_ACCESS_USER;
			else if (strcmp(s, "any") == 0)
				v9ses->flags |= V9FS_ACCESS_ANY;
			else {
				v9ses->flags |= V9FS_ACCESS_SINGLE;
				v9ses->uid = simple_strtol(s, &e, 10);
				if (*e != '\0')
					v9ses->uid = ~0;
			}
			break;

208 209 210 211 212 213 214 215 216 217 218 219 220 221
		default:
			continue;
		}
	}
}

/**
 * v9fs_session_init - initialize session
 * @v9ses: session information structure
 * @dev_name: device being mounted
 * @data: options
 *
 */

222
struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
223 224 225
		  const char *dev_name, char *data)
{
	int retval = -EINVAL;
E
Eric Van Hensbergen 已提交
226
	struct p9_trans *trans = NULL;
227
	struct p9_fid *fid;
228

L
Latchesar Ionkov 已提交
229 230
	v9ses->uname = __getname();
	if (!v9ses->uname)
231
		return ERR_PTR(-ENOMEM);
232

L
Latchesar Ionkov 已提交
233 234 235
	v9ses->aname = __getname();
	if (!v9ses->aname) {
		__putname(v9ses->uname);
236
		return ERR_PTR(-ENOMEM);
237 238
	}

L
Latchesar Ionkov 已提交
239 240 241 242
	v9ses->flags = V9FS_EXTENDED | V9FS_ACCESS_USER;
	strcpy(v9ses->uname, V9FS_DEFUSER);
	strcpy(v9ses->aname, V9FS_DEFANAME);
	v9ses->uid = ~0;
243 244
	v9ses->dfltuid = V9FS_DEFUID;
	v9ses->dfltgid = V9FS_DEFGID;
E
Eric Van Hensbergen 已提交
245 246 247 248 249 250 251 252 253 254 255
	v9ses->options = kstrdup(data, GFP_KERNEL);
	v9fs_parse_options(v9ses);

	if ((v9ses->trans == NULL) && !list_empty(&v9fs_trans_list))
		v9ses->trans = list_first_entry(&v9fs_trans_list,
		 struct p9_trans_module, list);

	if (v9ses->trans == NULL) {
		retval = -EPROTONOSUPPORT;
		P9_DPRINTK(P9_DEBUG_ERROR,
				"No transport defined or default transport\n");
256
		goto error;
E
Eric Van Hensbergen 已提交
257
	}
258

E
Eric Van Hensbergen 已提交
259
	trans = v9ses->trans->create(dev_name, v9ses->options);
260 261 262 263
	if (IS_ERR(trans)) {
		retval = PTR_ERR(trans);
		trans = NULL;
		goto error;
264
	}
E
Eric Van Hensbergen 已提交
265 266
	if ((v9ses->maxdata+P9_IOHDRSZ) > v9ses->trans->maxsize)
		v9ses->maxdata = v9ses->trans->maxsize-P9_IOHDRSZ;
267

E
Eric Van Hensbergen 已提交
268
	v9ses->clnt = p9_client_create(trans, v9ses->maxdata+P9_IOHDRSZ,
L
Latchesar Ionkov 已提交
269
		v9fs_extended(v9ses));
270

271 272 273 274 275
	if (IS_ERR(v9ses->clnt)) {
		retval = PTR_ERR(v9ses->clnt);
		v9ses->clnt = NULL;
		P9_DPRINTK(P9_DEBUG_ERROR, "problem initializing 9p client\n");
		goto error;
276 277
	}

L
Latchesar Ionkov 已提交
278 279 280 281 282 283 284 285 286 287 288 289 290 291
	if (!v9ses->clnt->dotu)
		v9ses->flags &= ~V9FS_EXTENDED;

	/* for legacy mode, fall back to V9FS_ACCESS_ANY */
	if (!v9fs_extended(v9ses) &&
		((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {

		v9ses->flags &= ~V9FS_ACCESS_MASK;
		v9ses->flags |= V9FS_ACCESS_ANY;
		v9ses->uid = ~0;
	}

	fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, ~0,
							v9ses->aname);
292 293 294 295 296
	if (IS_ERR(fid)) {
		retval = PTR_ERR(fid);
		fid = NULL;
		P9_DPRINTK(P9_DEBUG_ERROR, "cannot attach\n");
		goto error;
297 298
	}

L
Latchesar Ionkov 已提交
299 300 301 302 303
	if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE)
		fid->uid = v9ses->uid;
	else
		fid->uid = ~0;

304
	return fid;
305

306
error:
307
	v9fs_session_close(v9ses);
308
	return ERR_PTR(retval);
309 310 311 312 313 314 315 316 317 318
}

/**
 * v9fs_session_close - shutdown a session
 * @v9ses: session information structure
 *
 */

void v9fs_session_close(struct v9fs_session_info *v9ses)
{
319 320 321
	if (v9ses->clnt) {
		p9_client_destroy(v9ses->clnt);
		v9ses->clnt = NULL;
322
	}
323

L
Latchesar Ionkov 已提交
324 325
	__putname(v9ses->uname);
	__putname(v9ses->aname);
E
Eric Van Hensbergen 已提交
326
	kfree(v9ses->options);
327 328
}

329 330 331 332 333
/**
 * v9fs_session_cancel - mark transport as disconnected
 * 	and cancel all pending requests.
 */
void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
334 335
	P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
	p9_client_disconnect(v9ses->clnt);
336 337
}

338 339 340 341 342 343 344 345 346
extern int v9fs_error_init(void);

/**
 * v9fs_init - Initialize module
 *
 */

static int __init init_v9fs(void)
{
347
	printk(KERN_INFO "Installing v9fs 9p2000 file system support\n");
E
Eric Van Hensbergen 已提交
348
	/* TODO: Setup list of registered trasnport modules */
349
	return register_filesystem(&v9fs_fs_type);
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
}

/**
 * v9fs_init - shutdown module
 *
 */

static void __exit exit_v9fs(void)
{
	unregister_filesystem(&v9fs_fs_type);
}

module_init(init_v9fs)
module_exit(exit_v9fs)

365
MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
366 367 368
MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
MODULE_LICENSE("GPL");