aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-17 18:05:58 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-17 18:05:58 -0400
commit9d8190f87b5458160ba75d05e8ad6abefbe48a26 (patch)
tree7abeb91aa2a40b91004f53520b7bf1f2c80aab7e
parentc2f73fd07d2ce4605b404f34395eb734a7ba9967 (diff)
parent982c37cfb6e61c0e64634abc2e305d757c1405b2 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: 9p: remove sysctl 9p: fix bad kconfig cross-dependency 9p: soften invalidation in loose_mode 9p: attach-per-user 9p: rename uid and gid parameters 9p: define session flags 9p: Make transports dynamic
-rw-r--r--Documentation/filesystems/9p.txt22
-rw-r--r--fs/9p/fid.c157
-rw-r--r--fs/9p/v9fs.c189
-rw-r--r--fs/9p/v9fs.h38
-rw-r--r--fs/9p/vfs_file.c6
-rw-r--r--fs/9p/vfs_inode.c50
-rw-r--r--fs/9p/vfs_super.c19
-rw-r--r--include/net/9p/9p.h21
-rw-r--r--include/net/9p/client.h9
-rw-r--r--include/net/9p/conn.h4
-rw-r--r--include/net/9p/transport.h27
-rw-r--r--net/9p/Kconfig10
-rw-r--r--net/9p/Makefile5
-rw-r--r--net/9p/client.c13
-rw-r--r--net/9p/conv.c32
-rw-r--r--net/9p/mod.c71
-rw-r--r--net/9p/mux.c5
-rw-r--r--net/9p/sysctl.c81
-rw-r--r--net/9p/trans_fd.c419
19 files changed, 689 insertions, 489 deletions
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt
index cda6905cbe49..d6fd6c6e4244 100644
--- a/Documentation/filesystems/9p.txt
+++ b/Documentation/filesystems/9p.txt
@@ -35,12 +35,12 @@ For remote file server:
35 35
36For Plan 9 From User Space applications (http://swtch.com/plan9) 36For Plan 9 From User Space applications (http://swtch.com/plan9)
37 37
38 mount -t 9p `namespace`/acme /mnt/9 -o proto=unix,uname=$USER 38 mount -t 9p `namespace`/acme /mnt/9 -o trans=unix,uname=$USER
39 39
40OPTIONS 40OPTIONS
41======= 41=======
42 42
43 proto=name select an alternative transport. Valid options are 43 trans=name select an alternative transport. Valid options are
44 currently: 44 currently:
45 unix - specifying a named pipe mount point 45 unix - specifying a named pipe mount point
46 tcp - specifying a normal TCP/IP connection 46 tcp - specifying a normal TCP/IP connection
@@ -68,9 +68,9 @@ OPTIONS
68 0x40 = display transport debug 68 0x40 = display transport debug
69 0x80 = display allocation debug 69 0x80 = display allocation debug
70 70
71 rfdno=n the file descriptor for reading with proto=fd 71 rfdno=n the file descriptor for reading with trans=fd
72 72
73 wfdno=n the file descriptor for writing with proto=fd 73 wfdno=n the file descriptor for writing with trans=fd
74 74
75 maxdata=n the number of bytes to use for 9p packet payload (msize) 75 maxdata=n the number of bytes to use for 9p packet payload (msize)
76 76
@@ -78,9 +78,9 @@ OPTIONS
78 78
79 noextend force legacy mode (no 9p2000.u semantics) 79 noextend force legacy mode (no 9p2000.u semantics)
80 80
81 uid attempt to mount as a particular uid 81 dfltuid attempt to mount as a particular uid
82 82
83 gid attempt to mount with a particular gid 83 dfltgid attempt to mount with a particular gid
84 84
85 afid security channel - used by Plan 9 authentication protocols 85 afid security channel - used by Plan 9 authentication protocols
86 86
@@ -88,6 +88,16 @@ OPTIONS
88 This can be used to share devices/named pipes/sockets between 88 This can be used to share devices/named pipes/sockets between
89 hosts. This functionality will be expanded in later versions. 89 hosts. This functionality will be expanded in later versions.
90 90
91 access there are three access modes.
92 user = if a user tries to access a file on v9fs
93 filesystem for the first time, v9fs sends an
94 attach command (Tattach) for that user.
95 This is the default mode.
96 <uid> = allows only user with uid=<uid> to access
97 the files on the mounted filesystem
98 any = v9fs does single attach and performs all
99 operations as one user
100
91RESOURCES 101RESOURCES
92========= 102=========
93 103
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 15e05a15b575..b364da70ff28 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * V9FS FID Management 2 * V9FS FID Management
3 * 3 *
4 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
4 * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com> 5 * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com>
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
@@ -34,9 +35,9 @@
34#include "fid.h" 35#include "fid.h"
35 36
36/** 37/**
37 * v9fs_fid_insert - add a fid to a dentry 38 * v9fs_fid_add - add a fid to a dentry
39 * @dentry: dentry that the fid is being added to
38 * @fid: fid to add 40 * @fid: fid to add
39 * @dentry: dentry that it is being added to
40 * 41 *
41 */ 42 */
42 43
@@ -66,52 +67,144 @@ int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
66} 67}
67 68
68/** 69/**
69 * v9fs_fid_lookup - return a locked fid from a dentry 70 * v9fs_fid_find - retrieve a fid that belongs to the specified uid
70 * @dentry: dentry to look for fid in 71 * @dentry: dentry to look for fid in
71 * 72 * @uid: return fid that belongs to the specified user
72 * find a fid in the dentry, obtain its semaphore and return a reference to it. 73 * @any: if non-zero, return any fid associated with the dentry
73 * code calling lookup is responsible for releasing lock
74 *
75 * TODO: only match fids that have the same uid as current user
76 * 74 *
77 */ 75 */
78 76
79struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) 77static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any)
80{ 78{
81 struct v9fs_dentry *dent; 79 struct v9fs_dentry *dent;
82 struct p9_fid *fid; 80 struct p9_fid *fid, *ret;
83 81
84 P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); 82 P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p) uid %d any %d\n",
85 dent = dentry->d_fsdata; 83 dentry->d_iname, dentry, uid, any);
86 if (dent) 84 dent = (struct v9fs_dentry *) dentry->d_fsdata;
87 fid = list_entry(dent->fidlist.next, struct p9_fid, dlist); 85 ret = NULL;
88 else 86 if (dent) {
89 fid = ERR_PTR(-EBADF); 87 spin_lock(&dent->lock);
88 list_for_each_entry(fid, &dent->fidlist, dlist) {
89 if (any || fid->uid == uid) {
90 ret = fid;
91 break;
92 }
93 }
94 spin_unlock(&dent->lock);
95 }
90 96
91 P9_DPRINTK(P9_DEBUG_VFS, " fid: %p\n", fid); 97 return ret;
92 return fid;
93} 98}
94 99
95/** 100/**
96 * v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and 101 * v9fs_fid_lookup - lookup for a fid, try to walk if not found
97 * release it
98 * @dentry: dentry to look for fid in 102 * @dentry: dentry to look for fid in
99 * 103 *
100 * find a fid in the dentry and then clone to a new private fid 104 * Look for a fid in the specified dentry for the current user.
101 * 105 * If no fid is found, try to create one walking from a fid from the parent
102 * TODO: only match fids that have the same uid as current user 106 * dentry (if it has one), or the root dentry. If the user haven't accessed
103 * 107 * the fs yet, attach now and walk from the root.
104 */ 108 */
105 109
106struct p9_fid *v9fs_fid_clone(struct dentry *dentry) 110struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
107{ 111{
108 struct p9_fid *ofid, *fid; 112 int i, n, l, clone, any, access;
113 u32 uid;
114 struct p9_fid *fid;
115 struct dentry *d, *ds;
116 struct v9fs_session_info *v9ses;
117 char **wnames, *uname;
118
119 v9ses = v9fs_inode2v9ses(dentry->d_inode);
120 access = v9ses->flags & V9FS_ACCESS_MASK;
121 switch (access) {
122 case V9FS_ACCESS_SINGLE:
123 case V9FS_ACCESS_USER:
124 uid = current->fsuid;
125 any = 0;
126 break;
127
128 case V9FS_ACCESS_ANY:
129 uid = v9ses->uid;
130 any = 1;
131 break;
132
133 default:
134 uid = ~0;
135 any = 0;
136 break;
137 }
109 138
110 P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); 139 fid = v9fs_fid_find(dentry, uid, any);
111 ofid = v9fs_fid_lookup(dentry); 140 if (fid)
112 if (IS_ERR(ofid)) 141 return fid;
113 return ofid; 142
143 ds = dentry->d_parent;
144 fid = v9fs_fid_find(ds, uid, any);
145 if (!fid) { /* walk from the root */
146 n = 0;
147 for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
148 n++;
149
150 fid = v9fs_fid_find(ds, uid, any);
151 if (!fid) { /* the user is not attached to the fs yet */
152 if (access == V9FS_ACCESS_SINGLE)
153 return ERR_PTR(-EPERM);
154
155 if (v9fs_extended(v9ses))
156 uname = NULL;
157 else
158 uname = v9ses->uname;
159
160 fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
161 v9ses->aname);
162
163 if (IS_ERR(fid))
164 return fid;
165
166 v9fs_fid_add(ds, fid);
167 }
168 } else /* walk from the parent */
169 n = 1;
170
171 if (ds == dentry)
172 return fid;
173
174 wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
175 if (!wnames)
176 return ERR_PTR(-ENOMEM);
177
178 for (d = dentry, i = n; i >= 0; i--, d = d->d_parent)
179 wnames[i] = (char *) d->d_name.name;
180
181 clone = 1;
182 i = 0;
183 while (i < n) {
184 l = min(n - i, P9_MAXWELEM);
185 fid = p9_client_walk(fid, l, &wnames[i], clone);
186 if (!fid) {
187 kfree(wnames);
188 return fid;
189 }
190
191 i += l;
192 clone = 0;
193 }
114 194
115 fid = p9_client_walk(ofid, 0, NULL, 1); 195 kfree(wnames);
196 v9fs_fid_add(dentry, fid);
116 return fid; 197 return fid;
117} 198}
199
200struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
201{
202 struct p9_fid *fid, *ret;
203
204 fid = v9fs_fid_lookup(dentry);
205 if (IS_ERR(fid))
206 return fid;
207
208 ret = p9_client_walk(fid, 0, NULL, 1);
209 return ret;
210}
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 0a7068e30ecb..873802de21cd 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -38,56 +38,41 @@
38 38
39/* 39/*
40 * Option Parsing (code inspired by NFS code) 40 * Option Parsing (code inspired by NFS code)
41 * 41 * NOTE: each transport will parse its own options
42 */ 42 */
43 43
44enum { 44enum {
45 /* Options that take integer arguments */ 45 /* Options that take integer arguments */
46 Opt_debug, Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, 46 Opt_debug, Opt_msize, Opt_dfltuid, Opt_dfltgid, Opt_afid,
47 Opt_rfdno, Opt_wfdno,
48 /* String options */ 47 /* String options */
49 Opt_uname, Opt_remotename, 48 Opt_uname, Opt_remotename, Opt_trans,
50 /* Options that take no arguments */ 49 /* Options that take no arguments */
51 Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, Opt_pci, 50 Opt_legacy, Opt_nodevmap,
52 /* Cache options */ 51 /* Cache options */
53 Opt_cache_loose, 52 Opt_cache_loose,
53 /* Access options */
54 Opt_access,
54 /* Error token */ 55 /* Error token */
55 Opt_err 56 Opt_err
56}; 57};
57 58
58static match_table_t tokens = { 59static match_table_t tokens = {
59 {Opt_debug, "debug=%x"}, 60 {Opt_debug, "debug=%x"},
60 {Opt_port, "port=%u"},
61 {Opt_msize, "msize=%u"}, 61 {Opt_msize, "msize=%u"},
62 {Opt_uid, "uid=%u"}, 62 {Opt_dfltuid, "dfltuid=%u"},
63 {Opt_gid, "gid=%u"}, 63 {Opt_dfltgid, "dfltgid=%u"},
64 {Opt_afid, "afid=%u"}, 64 {Opt_afid, "afid=%u"},
65 {Opt_rfdno, "rfdno=%u"},
66 {Opt_wfdno, "wfdno=%u"},
67 {Opt_uname, "uname=%s"}, 65 {Opt_uname, "uname=%s"},
68 {Opt_remotename, "aname=%s"}, 66 {Opt_remotename, "aname=%s"},
69 {Opt_unix, "proto=unix"}, 67 {Opt_trans, "trans=%s"},
70 {Opt_tcp, "proto=tcp"},
71 {Opt_fd, "proto=fd"},
72#ifdef CONFIG_PCI_9P
73 {Opt_pci, "proto=pci"},
74#endif
75 {Opt_tcp, "tcp"},
76 {Opt_unix, "unix"},
77 {Opt_fd, "fd"},
78 {Opt_legacy, "noextend"}, 68 {Opt_legacy, "noextend"},
79 {Opt_nodevmap, "nodevmap"}, 69 {Opt_nodevmap, "nodevmap"},
80 {Opt_cache_loose, "cache=loose"}, 70 {Opt_cache_loose, "cache=loose"},
81 {Opt_cache_loose, "loose"}, 71 {Opt_cache_loose, "loose"},
72 {Opt_access, "access=%s"},
82 {Opt_err, NULL} 73 {Opt_err, NULL}
83}; 74};
84 75
85extern struct p9_transport *p9pci_trans_create(void);
86
87/*
88 * Parse option string.
89 */
90
91/** 76/**
92 * v9fs_parse_options - parse mount options into session structure 77 * v9fs_parse_options - parse mount options into session structure
93 * @options: options string passed from mount 78 * @options: options string passed from mount
@@ -95,23 +80,21 @@ extern struct p9_transport *p9pci_trans_create(void);
95 * 80 *
96 */ 81 */
97 82
98static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) 83static void v9fs_parse_options(struct v9fs_session_info *v9ses)
99{ 84{
100 char *p; 85 char *options = v9ses->options;
101 substring_t args[MAX_OPT_ARGS]; 86 substring_t args[MAX_OPT_ARGS];
87 char *p;
102 int option; 88 int option;
103 int ret; 89 int ret;
90 char *s, *e;
104 91
105 /* setup defaults */ 92 /* setup defaults */
106 v9ses->port = V9FS_PORT; 93 v9ses->maxdata = 8192;
107 v9ses->maxdata = 9000;
108 v9ses->proto = PROTO_TCP;
109 v9ses->extended = 1;
110 v9ses->afid = ~0; 94 v9ses->afid = ~0;
111 v9ses->debug = 0; 95 v9ses->debug = 0;
112 v9ses->rfdno = ~0;
113 v9ses->wfdno = ~0;
114 v9ses->cache = 0; 96 v9ses->cache = 0;
97 v9ses->trans = v9fs_default_trans();
115 98
116 if (!options) 99 if (!options)
117 return; 100 return;
@@ -135,47 +118,29 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
135 p9_debug_level = option; 118 p9_debug_level = option;
136#endif 119#endif
137 break; 120 break;
138 case Opt_port:
139 v9ses->port = option;
140 break;
141 case Opt_msize: 121 case Opt_msize:
142 v9ses->maxdata = option; 122 v9ses->maxdata = option;
143 break; 123 break;
144 case Opt_uid: 124 case Opt_dfltuid:
145 v9ses->uid = option; 125 v9ses->dfltuid = option;
146 break; 126 break;
147 case Opt_gid: 127 case Opt_dfltgid:
148 v9ses->gid = option; 128 v9ses->dfltgid = option;
149 break; 129 break;
150 case Opt_afid: 130 case Opt_afid:
151 v9ses->afid = option; 131 v9ses->afid = option;
152 break; 132 break;
153 case Opt_rfdno: 133 case Opt_trans:
154 v9ses->rfdno = option; 134 v9ses->trans = v9fs_match_trans(&args[0]);
155 break;
156 case Opt_wfdno:
157 v9ses->wfdno = option;
158 break;
159 case Opt_tcp:
160 v9ses->proto = PROTO_TCP;
161 break;
162 case Opt_unix:
163 v9ses->proto = PROTO_UNIX;
164 break;
165 case Opt_pci:
166 v9ses->proto = PROTO_PCI;
167 break;
168 case Opt_fd:
169 v9ses->proto = PROTO_FD;
170 break; 135 break;
171 case Opt_uname: 136 case Opt_uname:
172 match_strcpy(v9ses->name, &args[0]); 137 match_strcpy(v9ses->uname, &args[0]);
173 break; 138 break;
174 case Opt_remotename: 139 case Opt_remotename:
175 match_strcpy(v9ses->remotename, &args[0]); 140 match_strcpy(v9ses->aname, &args[0]);
176 break; 141 break;
177 case Opt_legacy: 142 case Opt_legacy:
178 v9ses->extended = 0; 143 v9ses->flags &= ~V9FS_EXTENDED;
179 break; 144 break;
180 case Opt_nodevmap: 145 case Opt_nodevmap:
181 v9ses->nodev = 1; 146 v9ses->nodev = 1;
@@ -183,6 +148,22 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
183 case Opt_cache_loose: 148 case Opt_cache_loose:
184 v9ses->cache = CACHE_LOOSE; 149 v9ses->cache = CACHE_LOOSE;
185 break; 150 break;
151
152 case Opt_access:
153 s = match_strdup(&args[0]);
154 v9ses->flags &= ~V9FS_ACCESS_MASK;
155 if (strcmp(s, "user") == 0)
156 v9ses->flags |= V9FS_ACCESS_USER;
157 else if (strcmp(s, "any") == 0)
158 v9ses->flags |= V9FS_ACCESS_ANY;
159 else {
160 v9ses->flags |= V9FS_ACCESS_SINGLE;
161 v9ses->uid = simple_strtol(s, &e, 10);
162 if (*e != '\0')
163 v9ses->uid = ~0;
164 }
165 break;
166
186 default: 167 default:
187 continue; 168 continue;
188 } 169 }
@@ -201,56 +182,46 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
201 const char *dev_name, char *data) 182 const char *dev_name, char *data)
202{ 183{
203 int retval = -EINVAL; 184 int retval = -EINVAL;
204 struct p9_transport *trans; 185 struct p9_trans *trans = NULL;
205 struct p9_fid *fid; 186 struct p9_fid *fid;
206 187
207 v9ses->name = __getname(); 188 v9ses->uname = __getname();
208 if (!v9ses->name) 189 if (!v9ses->uname)
209 return ERR_PTR(-ENOMEM); 190 return ERR_PTR(-ENOMEM);
210 191
211 v9ses->remotename = __getname(); 192 v9ses->aname = __getname();
212 if (!v9ses->remotename) { 193 if (!v9ses->aname) {
213 __putname(v9ses->name); 194 __putname(v9ses->uname);
214 return ERR_PTR(-ENOMEM); 195 return ERR_PTR(-ENOMEM);
215 } 196 }
216 197
217 strcpy(v9ses->name, V9FS_DEFUSER); 198 v9ses->flags = V9FS_EXTENDED | V9FS_ACCESS_USER;
218 strcpy(v9ses->remotename, V9FS_DEFANAME); 199 strcpy(v9ses->uname, V9FS_DEFUSER);
219 200 strcpy(v9ses->aname, V9FS_DEFANAME);
220 v9fs_parse_options(data, v9ses); 201 v9ses->uid = ~0;
221 202 v9ses->dfltuid = V9FS_DEFUID;
222 switch (v9ses->proto) { 203 v9ses->dfltgid = V9FS_DEFGID;
223 case PROTO_TCP: 204 v9ses->options = kstrdup(data, GFP_KERNEL);
224 trans = p9_trans_create_tcp(dev_name, v9ses->port); 205 v9fs_parse_options(v9ses);
225 break; 206
226 case PROTO_UNIX: 207 if (v9ses->trans == NULL) {
227 trans = p9_trans_create_unix(dev_name); 208 retval = -EPROTONOSUPPORT;
228 *v9ses->remotename = 0; 209 P9_DPRINTK(P9_DEBUG_ERROR,
229 break; 210 "No transport defined or default transport\n");
230 case PROTO_FD:
231 trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno);
232 *v9ses->remotename = 0;
233 break;
234#ifdef CONFIG_PCI_9P
235 case PROTO_PCI:
236 trans = p9pci_trans_create();
237 *v9ses->remotename = 0;
238 break;
239#endif
240 default:
241 printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto);
242 retval = -ENOPROTOOPT;
243 goto error; 211 goto error;
244 }; 212 }
245 213
214 trans = v9ses->trans->create(dev_name, v9ses->options);
246 if (IS_ERR(trans)) { 215 if (IS_ERR(trans)) {
247 retval = PTR_ERR(trans); 216 retval = PTR_ERR(trans);
248 trans = NULL; 217 trans = NULL;
249 goto error; 218 goto error;
250 } 219 }
220 if ((v9ses->maxdata+P9_IOHDRSZ) > v9ses->trans->maxsize)
221 v9ses->maxdata = v9ses->trans->maxsize-P9_IOHDRSZ;
251 222
252 v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ, 223 v9ses->clnt = p9_client_create(trans, v9ses->maxdata+P9_IOHDRSZ,
253 v9ses->extended); 224 v9fs_extended(v9ses));
254 225
255 if (IS_ERR(v9ses->clnt)) { 226 if (IS_ERR(v9ses->clnt)) {
256 retval = PTR_ERR(v9ses->clnt); 227 retval = PTR_ERR(v9ses->clnt);
@@ -259,8 +230,20 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
259 goto error; 230 goto error;
260 } 231 }
261 232
262 fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name, 233 if (!v9ses->clnt->dotu)
263 v9ses->remotename); 234 v9ses->flags &= ~V9FS_EXTENDED;
235
236 /* for legacy mode, fall back to V9FS_ACCESS_ANY */
237 if (!v9fs_extended(v9ses) &&
238 ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
239
240 v9ses->flags &= ~V9FS_ACCESS_MASK;
241 v9ses->flags |= V9FS_ACCESS_ANY;
242 v9ses->uid = ~0;
243 }
244
245 fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, ~0,
246 v9ses->aname);
264 if (IS_ERR(fid)) { 247 if (IS_ERR(fid)) {
265 retval = PTR_ERR(fid); 248 retval = PTR_ERR(fid);
266 fid = NULL; 249 fid = NULL;
@@ -268,6 +251,11 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
268 goto error; 251 goto error;
269 } 252 }
270 253
254 if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_SINGLE)
255 fid->uid = v9ses->uid;
256 else
257 fid->uid = ~0;
258
271 return fid; 259 return fid;
272 260
273error: 261error:
@@ -288,8 +276,9 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
288 v9ses->clnt = NULL; 276 v9ses->clnt = NULL;
289 } 277 }
290 278
291 __putname(v9ses->name); 279 __putname(v9ses->uname);
292 __putname(v9ses->remotename); 280 __putname(v9ses->aname);
281 kfree(v9ses->options);
293} 282}
294 283
295/** 284/**
@@ -311,7 +300,7 @@ extern int v9fs_error_init(void);
311static int __init init_v9fs(void) 300static int __init init_v9fs(void)
312{ 301{
313 printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); 302 printk(KERN_INFO "Installing v9fs 9p2000 file system support\n");
314 303 /* TODO: Setup list of registered trasnport modules */
315 return register_filesystem(&v9fs_fs_type); 304 return register_filesystem(&v9fs_fs_type);
316} 305}
317 306
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index abc4b1668ace..db4b4193f2e2 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -29,31 +29,30 @@
29struct v9fs_session_info { 29struct v9fs_session_info {
30 /* options */ 30 /* options */
31 unsigned int maxdata; 31 unsigned int maxdata;
32 unsigned char extended; /* set to 1 if we are using UNIX extensions */ 32 unsigned char flags; /* session flags */
33 unsigned char nodev; /* set to 1 if no disable device mapping */ 33 unsigned char nodev; /* set to 1 if no disable device mapping */
34 unsigned short port; /* port to connect to */
35 unsigned short debug; /* debug level */ 34 unsigned short debug; /* debug level */
36 unsigned short proto; /* protocol to use */
37 unsigned int afid; /* authentication fid */ 35 unsigned int afid; /* authentication fid */
38 unsigned int rfdno; /* read file descriptor number */
39 unsigned int wfdno; /* write file descriptor number */
40 unsigned int cache; /* cache mode */ 36 unsigned int cache; /* cache mode */
41 37
42 char *name; /* user name to mount as */ 38 char *options; /* copy of mount options */
43 char *remotename; /* name of remote hierarchy being mounted */ 39 char *uname; /* user name to mount as */
44 unsigned int uid; /* default uid/muid for legacy support */ 40 char *aname; /* name of remote hierarchy being mounted */
45 unsigned int gid; /* default gid for legacy support */ 41 unsigned int dfltuid; /* default uid/muid for legacy support */
46 42 unsigned int dfltgid; /* default gid for legacy support */
43 u32 uid; /* if ACCESS_SINGLE, the uid that has access */
44 struct p9_trans_module *trans; /* 9p transport */
47 struct p9_client *clnt; /* 9p client */ 45 struct p9_client *clnt; /* 9p client */
48 struct dentry *debugfs_dir; 46 struct dentry *debugfs_dir;
49}; 47};
50 48
51/* possible values of ->proto */ 49/* session flags */
52enum { 50enum {
53 PROTO_TCP, 51 V9FS_EXTENDED = 0x01, /* 9P2000.u */
54 PROTO_UNIX, 52 V9FS_ACCESS_MASK = 0x06, /* access mask */
55 PROTO_FD, 53 V9FS_ACCESS_SINGLE = 0x02, /* only one user can access the files */
56 PROTO_PCI, 54 V9FS_ACCESS_USER = 0x04, /* attache per user */
55 V9FS_ACCESS_ANY = 0x06, /* use the same attach for all users */
57}; 56};
58 57
59/* possible values of ->cache */ 58/* possible values of ->cache */
@@ -73,11 +72,18 @@ void v9fs_session_cancel(struct v9fs_session_info *v9ses);
73#define V9FS_MAGIC 0x01021997 72#define V9FS_MAGIC 0x01021997
74 73
75/* other default globals */ 74/* other default globals */
76#define V9FS_PORT 564 75#define V9FS_PORT 564
77#define V9FS_DEFUSER "nobody" 76#define V9FS_DEFUSER "nobody"
78#define V9FS_DEFANAME "" 77#define V9FS_DEFANAME ""
78#define V9FS_DEFUID (-2)
79#define V9FS_DEFGID (-2)
79 80
80static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode) 81static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
81{ 82{
82 return (inode->i_sb->s_fs_info); 83 return (inode->i_sb->s_fs_info);
83} 84}
85
86static inline int v9fs_extended(struct v9fs_session_info *v9ses)
87{
88 return v9ses->flags & V9FS_EXTENDED;
89}
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 716691689fd5..ba4b1caa9c43 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -162,15 +162,17 @@ v9fs_file_write(struct file *filp, const char __user * data,
162 162
163 fid = filp->private_data; 163 fid = filp->private_data;
164 ret = p9_client_uwrite(fid, data, *offset, count); 164 ret = p9_client_uwrite(fid, data, *offset, count);
165 if (ret > 0) 165 if (ret > 0) {
166 invalidate_inode_pages2_range(inode->i_mapping, *offset,
167 *offset+ret);
166 *offset += ret; 168 *offset += ret;
169 }
167 170
168 if (*offset > inode->i_size) { 171 if (*offset > inode->i_size) {
169 inode->i_size = *offset; 172 inode->i_size = *offset;
170 inode->i_blocks = (inode->i_size + 512 - 1) >> 9; 173 inode->i_blocks = (inode->i_size + 512 - 1) >> 9;
171 } 174 }
172 175
173 invalidate_inode_pages2(inode->i_mapping);
174 return ret; 176 return ret;
175} 177}
176 178
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index e5c45eed58a9..175b4d9bf3f8 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -59,7 +59,7 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
59 res = mode & 0777; 59 res = mode & 0777;
60 if (S_ISDIR(mode)) 60 if (S_ISDIR(mode))
61 res |= P9_DMDIR; 61 res |= P9_DMDIR;
62 if (v9ses->extended) { 62 if (v9fs_extended(v9ses)) {
63 if (S_ISLNK(mode)) 63 if (S_ISLNK(mode))
64 res |= P9_DMSYMLINK; 64 res |= P9_DMSYMLINK;
65 if (v9ses->nodev == 0) { 65 if (v9ses->nodev == 0) {
@@ -99,21 +99,21 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
99 99
100 if ((mode & P9_DMDIR) == P9_DMDIR) 100 if ((mode & P9_DMDIR) == P9_DMDIR)
101 res |= S_IFDIR; 101 res |= S_IFDIR;
102 else if ((mode & P9_DMSYMLINK) && (v9ses->extended)) 102 else if ((mode & P9_DMSYMLINK) && (v9fs_extended(v9ses)))
103 res |= S_IFLNK; 103 res |= S_IFLNK;
104 else if ((mode & P9_DMSOCKET) && (v9ses->extended) 104 else if ((mode & P9_DMSOCKET) && (v9fs_extended(v9ses))
105 && (v9ses->nodev == 0)) 105 && (v9ses->nodev == 0))
106 res |= S_IFSOCK; 106 res |= S_IFSOCK;
107 else if ((mode & P9_DMNAMEDPIPE) && (v9ses->extended) 107 else if ((mode & P9_DMNAMEDPIPE) && (v9fs_extended(v9ses))
108 && (v9ses->nodev == 0)) 108 && (v9ses->nodev == 0))
109 res |= S_IFIFO; 109 res |= S_IFIFO;
110 else if ((mode & P9_DMDEVICE) && (v9ses->extended) 110 else if ((mode & P9_DMDEVICE) && (v9fs_extended(v9ses))
111 && (v9ses->nodev == 0)) 111 && (v9ses->nodev == 0))
112 res |= S_IFBLK; 112 res |= S_IFBLK;
113 else 113 else
114 res |= S_IFREG; 114 res |= S_IFREG;
115 115
116 if (v9ses->extended) { 116 if (v9fs_extended(v9ses)) {
117 if ((mode & P9_DMSETUID) == P9_DMSETUID) 117 if ((mode & P9_DMSETUID) == P9_DMSETUID)
118 res |= S_ISUID; 118 res |= S_ISUID;
119 119
@@ -214,7 +214,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
214 case S_IFBLK: 214 case S_IFBLK:
215 case S_IFCHR: 215 case S_IFCHR:
216 case S_IFSOCK: 216 case S_IFSOCK:
217 if(!v9ses->extended) { 217 if (!v9fs_extended(v9ses)) {
218 P9_DPRINTK(P9_DEBUG_ERROR, 218 P9_DPRINTK(P9_DEBUG_ERROR,
219 "special files without extended mode\n"); 219 "special files without extended mode\n");
220 return ERR_PTR(-EINVAL); 220 return ERR_PTR(-EINVAL);
@@ -227,7 +227,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
227 inode->i_fop = &v9fs_file_operations; 227 inode->i_fop = &v9fs_file_operations;
228 break; 228 break;
229 case S_IFLNK: 229 case S_IFLNK:
230 if(!v9ses->extended) { 230 if (!v9fs_extended(v9ses)) {
231 P9_DPRINTK(P9_DEBUG_ERROR, 231 P9_DPRINTK(P9_DEBUG_ERROR,
232 "extended modes used w/o 9P2000.u\n"); 232 "extended modes used w/o 9P2000.u\n");
233 return ERR_PTR(-EINVAL); 233 return ERR_PTR(-EINVAL);
@@ -236,7 +236,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
236 break; 236 break;
237 case S_IFDIR: 237 case S_IFDIR:
238 inc_nlink(inode); 238 inc_nlink(inode);
239 if(v9ses->extended) 239 if (v9fs_extended(v9ses))
240 inode->i_op = &v9fs_dir_inode_operations_ext; 240 inode->i_op = &v9fs_dir_inode_operations_ext;
241 else 241 else
242 inode->i_op = &v9fs_dir_inode_operations; 242 inode->i_op = &v9fs_dir_inode_operations;
@@ -364,7 +364,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
364 file_inode = file->d_inode; 364 file_inode = file->d_inode;
365 v9ses = v9fs_inode2v9ses(file_inode); 365 v9ses = v9fs_inode2v9ses(file_inode);
366 v9fid = v9fs_fid_clone(file); 366 v9fid = v9fs_fid_clone(file);
367 if(IS_ERR(v9fid)) 367 if (IS_ERR(v9fid))
368 return PTR_ERR(v9fid); 368 return PTR_ERR(v9fid);
369 369
370 return p9_client_remove(v9fid); 370 return p9_client_remove(v9fid);
@@ -398,7 +398,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
398 fid = NULL; 398 fid = NULL;
399 name = (char *) dentry->d_name.name; 399 name = (char *) dentry->d_name.name;
400 dfid = v9fs_fid_clone(dentry->d_parent); 400 dfid = v9fs_fid_clone(dentry->d_parent);
401 if(IS_ERR(dfid)) { 401 if (IS_ERR(dfid)) {
402 err = PTR_ERR(dfid); 402 err = PTR_ERR(dfid);
403 dfid = NULL; 403 dfid = NULL;
404 goto error; 404 goto error;
@@ -432,7 +432,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
432 goto error; 432 goto error;
433 } 433 }
434 434
435 if(v9ses->cache) 435 if (v9ses->cache)
436 dentry->d_op = &v9fs_cached_dentry_operations; 436 dentry->d_op = &v9fs_cached_dentry_operations;
437 else 437 else
438 dentry->d_op = &v9fs_dentry_operations; 438 dentry->d_op = &v9fs_dentry_operations;
@@ -593,7 +593,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
593 if (result < 0) 593 if (result < 0)
594 goto error; 594 goto error;
595 595
596 if((fid->qid.version)&&(v9ses->cache)) 596 if ((fid->qid.version) && (v9ses->cache))
597 dentry->d_op = &v9fs_cached_dentry_operations; 597 dentry->d_op = &v9fs_cached_dentry_operations;
598 else 598 else
599 dentry->d_op = &v9fs_dentry_operations; 599 dentry->d_op = &v9fs_dentry_operations;
@@ -658,17 +658,17 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
658 old_inode = old_dentry->d_inode; 658 old_inode = old_dentry->d_inode;
659 v9ses = v9fs_inode2v9ses(old_inode); 659 v9ses = v9fs_inode2v9ses(old_inode);
660 oldfid = v9fs_fid_lookup(old_dentry); 660 oldfid = v9fs_fid_lookup(old_dentry);
661 if(IS_ERR(oldfid)) 661 if (IS_ERR(oldfid))
662 return PTR_ERR(oldfid); 662 return PTR_ERR(oldfid);
663 663
664 olddirfid = v9fs_fid_clone(old_dentry->d_parent); 664 olddirfid = v9fs_fid_clone(old_dentry->d_parent);
665 if(IS_ERR(olddirfid)) { 665 if (IS_ERR(olddirfid)) {
666 retval = PTR_ERR(olddirfid); 666 retval = PTR_ERR(olddirfid);
667 goto done; 667 goto done;
668 } 668 }
669 669
670 newdirfid = v9fs_fid_clone(new_dentry->d_parent); 670 newdirfid = v9fs_fid_clone(new_dentry->d_parent);
671 if(IS_ERR(newdirfid)) { 671 if (IS_ERR(newdirfid)) {
672 retval = PTR_ERR(newdirfid); 672 retval = PTR_ERR(newdirfid);
673 goto clunk_olddir; 673 goto clunk_olddir;
674 } 674 }
@@ -682,7 +682,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
682 } 682 }
683 683
684 v9fs_blank_wstat(&wstat); 684 v9fs_blank_wstat(&wstat);
685 wstat.muid = v9ses->name; 685 wstat.muid = v9ses->uname;
686 wstat.name = (char *) new_dentry->d_name.name; 686 wstat.name = (char *) new_dentry->d_name.name;
687 retval = p9_client_wstat(oldfid, &wstat); 687 retval = p9_client_wstat(oldfid, &wstat);
688 688
@@ -768,7 +768,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
768 if (iattr->ia_valid & ATTR_SIZE) 768 if (iattr->ia_valid & ATTR_SIZE)
769 wstat.length = iattr->ia_size; 769 wstat.length = iattr->ia_size;
770 770
771 if (v9ses->extended) { 771 if (v9fs_extended(v9ses)) {
772 if (iattr->ia_valid & ATTR_UID) 772 if (iattr->ia_valid & ATTR_UID)
773 wstat.n_uid = iattr->ia_uid; 773 wstat.n_uid = iattr->ia_uid;
774 774
@@ -805,10 +805,10 @@ v9fs_stat2inode(struct p9_stat *stat, struct inode *inode,
805 inode->i_mtime.tv_sec = stat->mtime; 805 inode->i_mtime.tv_sec = stat->mtime;
806 inode->i_ctime.tv_sec = stat->mtime; 806 inode->i_ctime.tv_sec = stat->mtime;
807 807
808 inode->i_uid = v9ses->uid; 808 inode->i_uid = v9ses->dfltuid;
809 inode->i_gid = v9ses->gid; 809 inode->i_gid = v9ses->dfltgid;
810 810
811 if (v9ses->extended) { 811 if (v9fs_extended(v9ses)) {
812 inode->i_uid = stat->n_uid; 812 inode->i_uid = stat->n_uid;
813 inode->i_gid = stat->n_gid; 813 inode->i_gid = stat->n_gid;
814 } 814 }
@@ -887,10 +887,10 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
887 retval = -EPERM; 887 retval = -EPERM;
888 v9ses = v9fs_inode2v9ses(dentry->d_inode); 888 v9ses = v9fs_inode2v9ses(dentry->d_inode);
889 fid = v9fs_fid_lookup(dentry); 889 fid = v9fs_fid_lookup(dentry);
890 if(IS_ERR(fid)) 890 if (IS_ERR(fid))
891 return PTR_ERR(fid); 891 return PTR_ERR(fid);
892 892
893 if (!v9ses->extended) 893 if (!v9fs_extended(v9ses))
894 return -EBADF; 894 return -EBADF;
895 895
896 st = p9_client_stat(fid); 896 st = p9_client_stat(fid);
@@ -1011,7 +1011,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
1011 struct p9_fid *fid; 1011 struct p9_fid *fid;
1012 1012
1013 v9ses = v9fs_inode2v9ses(dir); 1013 v9ses = v9fs_inode2v9ses(dir);
1014 if (!v9ses->extended) { 1014 if (!v9fs_extended(v9ses)) {
1015 P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n"); 1015 P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n");
1016 return -EPERM; 1016 return -EPERM;
1017 } 1017 }
@@ -1070,7 +1070,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1070 old_dentry->d_name.name); 1070 old_dentry->d_name.name);
1071 1071
1072 oldfid = v9fs_fid_clone(old_dentry); 1072 oldfid = v9fs_fid_clone(old_dentry);
1073 if(IS_ERR(oldfid)) 1073 if (IS_ERR(oldfid))
1074 return PTR_ERR(oldfid); 1074 return PTR_ERR(oldfid);
1075 1075
1076 name = __getname(); 1076 name = __getname();
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index ba904371218b..bb0cef9a6b8a 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -216,24 +216,7 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
216{ 216{
217 struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info; 217 struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info;
218 218
219 if (v9ses->debug != 0) 219 seq_printf(m, "%s", v9ses->options);
220 seq_printf(m, ",debug=%x", v9ses->debug);
221 if (v9ses->port != V9FS_PORT)
222 seq_printf(m, ",port=%u", v9ses->port);
223 if (v9ses->maxdata != 9000)
224 seq_printf(m, ",msize=%u", v9ses->maxdata);
225 if (v9ses->afid != ~0)
226 seq_printf(m, ",afid=%u", v9ses->afid);
227 if (v9ses->proto == PROTO_UNIX)
228 seq_puts(m, ",proto=unix");
229 if (v9ses->extended == 0)
230 seq_puts(m, ",noextend");
231 if (v9ses->nodev == 1)
232 seq_puts(m, ",nodevmap");
233 seq_printf(m, ",name=%s", v9ses->name);
234 seq_printf(m, ",aname=%s", v9ses->remotename);
235 seq_printf(m, ",uid=%u", v9ses->uid);
236 seq_printf(m, ",gid=%u", v9ses->gid);
237 return 0; 220 return 0;
238} 221}
239 222
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index 7726ff41c3e6..686425a97b0f 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -216,6 +216,7 @@ struct p9_tauth {
216 u32 afid; 216 u32 afid;
217 struct p9_str uname; 217 struct p9_str uname;
218 struct p9_str aname; 218 struct p9_str aname;
219 u32 n_uname; /* 9P2000.u extensions */
219}; 220};
220 221
221struct p9_rauth { 222struct p9_rauth {
@@ -239,6 +240,7 @@ struct p9_tattach {
239 u32 afid; 240 u32 afid;
240 struct p9_str uname; 241 struct p9_str uname;
241 struct p9_str aname; 242 struct p9_str aname;
243 u32 n_uname; /* 9P2000.u extensions */
242}; 244};
243 245
244struct p9_rattach { 246struct p9_rattach {
@@ -382,8 +384,9 @@ int p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *fc, int dotu);
382void p9_set_tag(struct p9_fcall *fc, u16 tag); 384void p9_set_tag(struct p9_fcall *fc, u16 tag);
383struct p9_fcall *p9_create_tversion(u32 msize, char *version); 385struct p9_fcall *p9_create_tversion(u32 msize, char *version);
384struct p9_fcall *p9_create_tattach(u32 fid, u32 afid, char *uname, 386struct p9_fcall *p9_create_tattach(u32 fid, u32 afid, char *uname,
385 char *aname); 387 char *aname, u32 n_uname, int dotu);
386struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname); 388struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname,
389 u32 n_uname, int dotu);
387struct p9_fcall *p9_create_tflush(u16 oldtag); 390struct p9_fcall *p9_create_tflush(u16 oldtag);
388struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname, 391struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname,
389 char **wnames); 392 char **wnames);
@@ -412,18 +415,4 @@ int p9_idpool_check(int id, struct p9_idpool *p);
412 415
413int p9_error_init(void); 416int p9_error_init(void);
414int p9_errstr2errno(char *, int); 417int p9_errstr2errno(char *, int);
415
416#ifdef CONFIG_SYSCTL
417int __init p9_sysctl_register(void);
418void __exit p9_sysctl_unregister(void);
419#else
420static inline int p9_sysctl_register(void)
421{
422 return 0;
423}
424static inline void p9_sysctl_unregister(void)
425{
426}
427#endif
428
429#endif /* NET_9P_H */ 418#endif /* NET_9P_H */
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index d65ed7c69063..9b9221a21392 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -29,7 +29,7 @@ struct p9_client {
29 spinlock_t lock; /* protect client structure */ 29 spinlock_t lock; /* protect client structure */
30 int msize; 30 int msize;
31 unsigned char dotu; 31 unsigned char dotu;
32 struct p9_transport *trans; 32 struct p9_trans *trans;
33 struct p9_conn *conn; 33 struct p9_conn *conn;
34 34
35 struct p9_idpool *fidpool; 35 struct p9_idpool *fidpool;
@@ -52,13 +52,14 @@ struct p9_fid {
52 struct list_head dlist; /* list of all fids attached to a dentry */ 52 struct list_head dlist; /* list of all fids attached to a dentry */
53}; 53};
54 54
55struct p9_client *p9_client_create(struct p9_transport *trans, int msize, 55struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
56 int dotu); 56 int dotu);
57void p9_client_destroy(struct p9_client *clnt); 57void p9_client_destroy(struct p9_client *clnt);
58void p9_client_disconnect(struct p9_client *clnt); 58void p9_client_disconnect(struct p9_client *clnt);
59struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 59struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
60 char *uname, char *aname); 60 char *uname, u32 n_uname, char *aname);
61struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname); 61struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
62 u32 n_uname, char *aname);
62struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, 63struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
63 int clone); 64 int clone);
64int p9_client_open(struct p9_fid *fid, int mode); 65int p9_client_open(struct p9_fid *fid, int mode);
diff --git a/include/net/9p/conn.h b/include/net/9p/conn.h
index 583b6a2cb3df..756d8784f953 100644
--- a/include/net/9p/conn.h
+++ b/include/net/9p/conn.h
@@ -42,8 +42,8 @@ struct p9_req;
42 */ 42 */
43typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a); 43typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a);
44 44
45struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize, 45struct p9_conn *p9_conn_create(struct p9_trans *trans, int msize,
46 unsigned char *dotu); 46 unsigned char *dotu);
47void p9_conn_destroy(struct p9_conn *); 47void p9_conn_destroy(struct p9_conn *);
48int p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc, struct p9_fcall **rc); 48int p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc, struct p9_fcall **rc);
49 49
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h
index 462d42279fb0..9dd4a05619a8 100644
--- a/include/net/9p/transport.h
+++ b/include/net/9p/transport.h
@@ -26,24 +26,31 @@
26#ifndef NET_9P_TRANSPORT_H 26#ifndef NET_9P_TRANSPORT_H
27#define NET_9P_TRANSPORT_H 27#define NET_9P_TRANSPORT_H
28 28
29enum p9_transport_status { 29enum p9_trans_status {
30 Connected, 30 Connected,
31 Disconnected, 31 Disconnected,
32 Hung, 32 Hung,
33}; 33};
34 34
35struct p9_transport { 35struct p9_trans {
36 enum p9_transport_status status; 36 enum p9_trans_status status;
37 void *priv; 37 void *priv;
38 int (*write) (struct p9_trans *, void *, int);
39 int (*read) (struct p9_trans *, void *, int);
40 void (*close) (struct p9_trans *);
41 unsigned int (*poll)(struct p9_trans *, struct poll_table_struct *);
42};
38 43
39 int (*write) (struct p9_transport *, void *, int); 44struct p9_trans_module {
40 int (*read) (struct p9_transport *, void *, int); 45 struct list_head list;
41 void (*close) (struct p9_transport *); 46 char *name; /* name of transport */
42 unsigned int (*poll)(struct p9_transport *, struct poll_table_struct *); 47 int maxsize; /* max message size of transport */
48 int def; /* this transport should be default */
49 struct p9_trans * (*create)(const char *devname, char *options);
43}; 50};
44 51
45struct p9_transport *p9_trans_create_tcp(const char *addr, int port); 52void v9fs_register_trans(struct p9_trans_module *m);
46struct p9_transport *p9_trans_create_unix(const char *addr); 53struct p9_trans_module *v9fs_match_trans(const substring_t *name);
47struct p9_transport *p9_trans_create_fd(int rfd, int wfd); 54struct p9_trans_module *v9fs_default_trans(void);
48 55
49#endif /* NET_9P_TRANSPORT_H */ 56#endif /* NET_9P_TRANSPORT_H */
diff --git a/net/9p/Kconfig b/net/9p/Kconfig
index 66821cd64a76..eecbf12f6393 100644
--- a/net/9p/Kconfig
+++ b/net/9p/Kconfig
@@ -13,6 +13,16 @@ menuconfig NET_9P
13 13
14 If unsure, say N. 14 If unsure, say N.
15 15
16config NET_9P_FD
17 depends on NET_9P
18 default y if NET_9P
19 tristate "9P File Descriptor Transports (Experimental)"
20 help
21 This builds support for file descriptor transports for 9p
22 which includes support for TCP/IP, named pipes, or passed
23 file descriptors. TCP/IP is the default transport for 9p,
24 so if you are going to use 9p, you'll likely want this.
25
16config NET_9P_DEBUG 26config NET_9P_DEBUG
17 bool "Debug information" 27 bool "Debug information"
18 depends on NET_9P 28 depends on NET_9P
diff --git a/net/9p/Makefile b/net/9p/Makefile
index 85b3a7838acf..5059bc06f8f3 100644
--- a/net/9p/Makefile
+++ b/net/9p/Makefile
@@ -1,8 +1,8 @@
1obj-$(CONFIG_NET_9P) := 9pnet.o 1obj-$(CONFIG_NET_9P) := 9pnet.o
2obj-$(CONFIG_NET_9P_FD) += 9pnet_fd.o
2 3
39pnet-objs := \ 49pnet-objs := \
4 mod.o \ 5 mod.o \
5 trans_fd.o \
6 mux.o \ 6 mux.o \
7 client.o \ 7 client.o \
8 conv.o \ 8 conv.o \
@@ -10,4 +10,5 @@ obj-$(CONFIG_NET_9P) := 9pnet.o
10 fcprint.o \ 10 fcprint.o \
11 util.o \ 11 util.o \
12 12
139pnet-$(CONFIG_SYSCTL) += sysctl.o 139pnet_fd-objs := \
14 trans_fd.o \
diff --git a/net/9p/client.c b/net/9p/client.c
index cb170750337c..af9199364049 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -30,6 +30,7 @@
30#include <linux/sched.h> 30#include <linux/sched.h>
31#include <linux/uaccess.h> 31#include <linux/uaccess.h>
32#include <net/9p/9p.h> 32#include <net/9p/9p.h>
33#include <linux/parser.h>
33#include <net/9p/transport.h> 34#include <net/9p/transport.h>
34#include <net/9p/conn.h> 35#include <net/9p/conn.h>
35#include <net/9p/client.h> 36#include <net/9p/client.h>
@@ -38,7 +39,7 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt);
38static void p9_fid_destroy(struct p9_fid *fid); 39static void p9_fid_destroy(struct p9_fid *fid);
39static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu); 40static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
40 41
41struct p9_client *p9_client_create(struct p9_transport *trans, int msize, 42struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
42 int dotu) 43 int dotu)
43{ 44{
44 int err, n; 45 int err, n;
@@ -146,7 +147,7 @@ void p9_client_disconnect(struct p9_client *clnt)
146EXPORT_SYMBOL(p9_client_disconnect); 147EXPORT_SYMBOL(p9_client_disconnect);
147 148
148struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 149struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
149 char *uname, char *aname) 150 char *uname, u32 n_uname, char *aname)
150{ 151{
151 int err; 152 int err;
152 struct p9_fcall *tc, *rc; 153 struct p9_fcall *tc, *rc;
@@ -165,7 +166,8 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
165 goto error; 166 goto error;
166 } 167 }
167 168
168 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname); 169 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname,
170 n_uname, clnt->dotu);
169 if (IS_ERR(tc)) { 171 if (IS_ERR(tc)) {
170 err = PTR_ERR(tc); 172 err = PTR_ERR(tc);
171 tc = NULL; 173 tc = NULL;
@@ -190,7 +192,8 @@ error:
190} 192}
191EXPORT_SYMBOL(p9_client_attach); 193EXPORT_SYMBOL(p9_client_attach);
192 194
193struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname) 195struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
196 u32 n_uname, char *aname)
194{ 197{
195 int err; 198 int err;
196 struct p9_fcall *tc, *rc; 199 struct p9_fcall *tc, *rc;
@@ -209,7 +212,7 @@ struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname)
209 goto error; 212 goto error;
210 } 213 }
211 214
212 tc = p9_create_tauth(fid->fid, uname, aname); 215 tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu);
213 if (IS_ERR(tc)) { 216 if (IS_ERR(tc)) {
214 err = PTR_ERR(tc); 217 err = PTR_ERR(tc);
215 tc = NULL; 218 tc = NULL;
diff --git a/net/9p/conv.c b/net/9p/conv.c
index d979d958ea19..aa2aa9884f95 100644
--- a/net/9p/conv.c
+++ b/net/9p/conv.c
@@ -547,7 +547,8 @@ error:
547} 547}
548EXPORT_SYMBOL(p9_create_tversion); 548EXPORT_SYMBOL(p9_create_tversion);
549 549
550struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname) 550struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname,
551 u32 n_uname, int dotu)
551{ 552{
552 int size; 553 int size;
553 struct p9_fcall *fc; 554 struct p9_fcall *fc;
@@ -555,7 +556,16 @@ struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname)
555 struct cbuf *bufp = &buffer; 556 struct cbuf *bufp = &buffer;
556 557
557 /* afid[4] uname[s] aname[s] */ 558 /* afid[4] uname[s] aname[s] */
558 size = 4 + 2 + strlen(uname) + 2 + strlen(aname); 559 size = 4 + 2 + 2;
560 if (uname)
561 size += strlen(uname);
562
563 if (aname)
564 size += strlen(aname);
565
566 if (dotu)
567 size += 4; /* n_uname */
568
559 fc = p9_create_common(bufp, size, P9_TAUTH); 569 fc = p9_create_common(bufp, size, P9_TAUTH);
560 if (IS_ERR(fc)) 570 if (IS_ERR(fc))
561 goto error; 571 goto error;
@@ -563,6 +573,8 @@ struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname)
563 p9_put_int32(bufp, afid, &fc->params.tauth.afid); 573 p9_put_int32(bufp, afid, &fc->params.tauth.afid);
564 p9_put_str(bufp, uname, &fc->params.tauth.uname); 574 p9_put_str(bufp, uname, &fc->params.tauth.uname);
565 p9_put_str(bufp, aname, &fc->params.tauth.aname); 575 p9_put_str(bufp, aname, &fc->params.tauth.aname);
576 if (dotu)
577 p9_put_int32(bufp, n_uname, &fc->params.tauth.n_uname);
566 578
567 if (buf_check_overflow(bufp)) { 579 if (buf_check_overflow(bufp)) {
568 kfree(fc); 580 kfree(fc);
@@ -574,7 +586,8 @@ error:
574EXPORT_SYMBOL(p9_create_tauth); 586EXPORT_SYMBOL(p9_create_tauth);
575 587
576struct p9_fcall * 588struct p9_fcall *
577p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname) 589p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname,
590 u32 n_uname, int dotu)
578{ 591{
579 int size; 592 int size;
580 struct p9_fcall *fc; 593 struct p9_fcall *fc;
@@ -582,7 +595,16 @@ p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
582 struct cbuf *bufp = &buffer; 595 struct cbuf *bufp = &buffer;
583 596
584 /* fid[4] afid[4] uname[s] aname[s] */ 597 /* fid[4] afid[4] uname[s] aname[s] */
585 size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); 598 size = 4 + 4 + 2 + 2;
599 if (uname)
600 size += strlen(uname);
601
602 if (aname)
603 size += strlen(aname);
604
605 if (dotu)
606 size += 4; /* n_uname */
607
586 fc = p9_create_common(bufp, size, P9_TATTACH); 608 fc = p9_create_common(bufp, size, P9_TATTACH);
587 if (IS_ERR(fc)) 609 if (IS_ERR(fc))
588 goto error; 610 goto error;
@@ -591,6 +613,8 @@ p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
591 p9_put_int32(bufp, afid, &fc->params.tattach.afid); 613 p9_put_int32(bufp, afid, &fc->params.tattach.afid);
592 p9_put_str(bufp, uname, &fc->params.tattach.uname); 614 p9_put_str(bufp, uname, &fc->params.tattach.uname);
593 p9_put_str(bufp, aname, &fc->params.tattach.aname); 615 p9_put_str(bufp, aname, &fc->params.tattach.aname);
616 if (dotu)
617 p9_put_int32(bufp, n_uname, &fc->params.tattach.n_uname);
594 618
595error: 619error:
596 return fc; 620 return fc;
diff --git a/net/9p/mod.c b/net/9p/mod.c
index 4f9e1d2ac257..41d70f47375d 100644
--- a/net/9p/mod.c
+++ b/net/9p/mod.c
@@ -27,6 +27,10 @@
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/moduleparam.h> 28#include <linux/moduleparam.h>
29#include <net/9p/9p.h> 29#include <net/9p/9p.h>
30#include <linux/fs.h>
31#include <linux/parser.h>
32#include <net/9p/transport.h>
33#include <linux/list.h>
30 34
31#ifdef CONFIG_NET_9P_DEBUG 35#ifdef CONFIG_NET_9P_DEBUG
32unsigned int p9_debug_level = 0; /* feature-rific global debug level */ 36unsigned int p9_debug_level = 0; /* feature-rific global debug level */
@@ -37,8 +41,64 @@ MODULE_PARM_DESC(debug, "9P debugging level");
37 41
38extern int p9_mux_global_init(void); 42extern int p9_mux_global_init(void);
39extern void p9_mux_global_exit(void); 43extern void p9_mux_global_exit(void);
40extern int p9_sysctl_register(void); 44
41extern void p9_sysctl_unregister(void); 45/*
46 * Dynamic Transport Registration Routines
47 *
48 */
49
50static LIST_HEAD(v9fs_trans_list);
51static struct p9_trans_module *v9fs_default_transport;
52
53/**
54 * v9fs_register_trans - register a new transport with 9p
55 * @m - structure describing the transport module and entry points
56 *
57 */
58void v9fs_register_trans(struct p9_trans_module *m)
59{
60 list_add_tail(&m->list, &v9fs_trans_list);
61 if (m->def)
62 v9fs_default_transport = m;
63}
64EXPORT_SYMBOL(v9fs_register_trans);
65
66/**
67 * v9fs_match_trans - match transport versus registered transports
68 * @arg: string identifying transport
69 *
70 */
71struct p9_trans_module *v9fs_match_trans(const substring_t *name)
72{
73 struct list_head *p;
74 struct p9_trans_module *t = NULL;
75
76 list_for_each(p, &v9fs_trans_list) {
77 t = list_entry(p, struct p9_trans_module, list);
78 if (strncmp(t->name, name->from, name->to-name->from) == 0)
79 break;
80 }
81 return t;
82}
83EXPORT_SYMBOL(v9fs_match_trans);
84
85/**
86 * v9fs_default_trans - returns pointer to default transport
87 *
88 */
89
90struct p9_trans_module *v9fs_default_trans(void)
91{
92 if (v9fs_default_transport)
93 return v9fs_default_transport;
94 else if (!list_empty(&v9fs_trans_list))
95 return list_first_entry(&v9fs_trans_list,
96 struct p9_trans_module, list);
97 else
98 return NULL;
99}
100EXPORT_SYMBOL(v9fs_default_trans);
101
42 102
43/** 103/**
44 * v9fs_init - Initialize module 104 * v9fs_init - Initialize module
@@ -56,12 +116,6 @@ static int __init init_p9(void)
56 return ret; 116 return ret;
57 } 117 }
58 118
59 ret = p9_sysctl_register();
60 if (ret) {
61 printk(KERN_WARNING "9p: registering sysctl failed\n");
62 return ret;
63 }
64
65 return ret; 119 return ret;
66} 120}
67 121
@@ -72,7 +126,6 @@ static int __init init_p9(void)
72 126
73static void __exit exit_p9(void) 127static void __exit exit_p9(void)
74{ 128{
75 p9_sysctl_unregister();
76 p9_mux_global_exit(); 129 p9_mux_global_exit();
77} 130}
78 131
diff --git a/net/9p/mux.c b/net/9p/mux.c
index 5d70558c4c61..f14014793bed 100644
--- a/net/9p/mux.c
+++ b/net/9p/mux.c
@@ -31,6 +31,7 @@
31#include <linux/idr.h> 31#include <linux/idr.h>
32#include <linux/mutex.h> 32#include <linux/mutex.h>
33#include <net/9p/9p.h> 33#include <net/9p/9p.h>
34#include <linux/parser.h>
34#include <net/9p/transport.h> 35#include <net/9p/transport.h>
35#include <net/9p/conn.h> 36#include <net/9p/conn.h>
36 37
@@ -71,7 +72,7 @@ struct p9_conn {
71 struct p9_mux_poll_task *poll_task; 72 struct p9_mux_poll_task *poll_task;
72 int msize; 73 int msize;
73 unsigned char *extended; 74 unsigned char *extended;
74 struct p9_transport *trans; 75 struct p9_trans *trans;
75 struct p9_idpool *tagpool; 76 struct p9_idpool *tagpool;
76 int err; 77 int err;
77 wait_queue_head_t equeue; 78 wait_queue_head_t equeue;
@@ -271,7 +272,7 @@ static void p9_mux_poll_stop(struct p9_conn *m)
271 * @msize - maximum message size 272 * @msize - maximum message size
272 * @extended - pointer to the extended flag 273 * @extended - pointer to the extended flag
273 */ 274 */
274struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize, 275struct p9_conn *p9_conn_create(struct p9_trans *trans, int msize,
275 unsigned char *extended) 276 unsigned char *extended)
276{ 277{
277 int i, n; 278 int i, n;
diff --git a/net/9p/sysctl.c b/net/9p/sysctl.c
deleted file mode 100644
index 8b61027a24ea..000000000000
--- a/net/9p/sysctl.c
+++ /dev/null
@@ -1,81 +0,0 @@
1/*
2 * net/9p/sysctl.c
3 *
4 * 9P sysctl interface
5 *
6 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to:
19 * Free Software Foundation
20 * 51 Franklin Street, Fifth Floor
21 * Boston, MA 02111-1301 USA
22 *
23 */
24
25#include <linux/kernel.h>
26#include <linux/mm.h>
27#include <linux/sysctl.h>
28#include <linux/init.h>
29#include <net/9p/9p.h>
30
31static struct ctl_table p9_table[] = {
32#ifdef CONFIG_NET_9P_DEBUG
33 {
34 .ctl_name = CTL_UNNUMBERED,
35 .procname = "debug",
36 .data = &p9_debug_level,
37 .maxlen = sizeof(int),
38 .mode = 0644,
39 .proc_handler = &proc_dointvec
40 },
41#endif
42 {},
43};
44
45static struct ctl_table p9_net_table[] = {
46 {
47 .ctl_name = CTL_UNNUMBERED,
48 .procname = "9p",
49 .maxlen = 0,
50 .mode = 0555,
51 .child = p9_table,
52 },
53 {},
54};
55
56static struct ctl_table p9_ctl_table[] = {
57 {
58 .ctl_name = CTL_NET,
59 .procname = "net",
60 .maxlen = 0,
61 .mode = 0555,
62 .child = p9_net_table,
63 },
64 {},
65};
66
67static struct ctl_table_header *p9_table_header;
68
69int __init p9_sysctl_register(void)
70{
71 p9_table_header = register_sysctl_table(p9_ctl_table);
72 if (!p9_table_header)
73 return -ENOMEM;
74
75 return 0;
76}
77
78void __exit p9_sysctl_unregister(void)
79{
80 unregister_sysctl_table(p9_table_header);
81}
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index fd636e94358f..30269a4ff22a 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -5,7 +5,7 @@
5 * 5 *
6 * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> 6 * Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
7 * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> 7 * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
8 * Copyright (C) 2004-2005 by Eric Van Hensbergen <ericvh@gmail.com> 8 * Copyright (C) 2004-2007 by Eric Van Hensbergen <ericvh@gmail.com>
9 * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> 9 * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
10 * 10 *
11 * This program is free software; you can redistribute it and/or modify 11 * This program is free software; you can redistribute it and/or modify
@@ -36,160 +36,114 @@
36#include <linux/inet.h> 36#include <linux/inet.h>
37#include <linux/idr.h> 37#include <linux/idr.h>
38#include <linux/file.h> 38#include <linux/file.h>
39#include <linux/parser.h>
39#include <net/9p/9p.h> 40#include <net/9p/9p.h>
40#include <net/9p/transport.h> 41#include <net/9p/transport.h>
41 42
42#define P9_PORT 564 43#define P9_PORT 564
44#define MAX_SOCK_BUF (64*1024)
45
46
47struct p9_fd_opts {
48 int rfd;
49 int wfd;
50 u16 port;
51};
43 52
44struct p9_trans_fd { 53struct p9_trans_fd {
45 struct file *rd; 54 struct file *rd;
46 struct file *wr; 55 struct file *wr;
47}; 56};
48 57
49static int p9_socket_open(struct p9_transport *trans, struct socket *csocket); 58/*
50static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd); 59 * Option Parsing (code inspired by NFS code)
51static int p9_fd_read(struct p9_transport *trans, void *v, int len); 60 * - a little lazy - parse all fd-transport options
52static int p9_fd_write(struct p9_transport *trans, void *v, int len); 61 */
53static unsigned int p9_fd_poll(struct p9_transport *trans,
54 struct poll_table_struct *pt);
55static void p9_fd_close(struct p9_transport *trans);
56
57struct p9_transport *p9_trans_create_tcp(const char *addr, int port)
58{
59 int err;
60 struct p9_transport *trans;
61 struct socket *csocket;
62 struct sockaddr_in sin_server;
63
64 csocket = NULL;
65 trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
66 if (!trans)
67 return ERR_PTR(-ENOMEM);
68
69 trans->write = p9_fd_write;
70 trans->read = p9_fd_read;
71 trans->close = p9_fd_close;
72 trans->poll = p9_fd_poll;
73
74 sin_server.sin_family = AF_INET;
75 sin_server.sin_addr.s_addr = in_aton(addr);
76 sin_server.sin_port = htons(port);
77 sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
78
79 if (!csocket) {
80 P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
81 err = -EIO;
82 goto error;
83 }
84
85 err = csocket->ops->connect(csocket,
86 (struct sockaddr *)&sin_server,
87 sizeof(struct sockaddr_in), 0);
88 if (err < 0) {
89 P9_EPRINTK(KERN_ERR,
90 "p9_trans_tcp: problem connecting socket to %s\n",
91 addr);
92 goto error;
93 }
94
95 err = p9_socket_open(trans, csocket);
96 if (err < 0)
97 goto error;
98 62
99 return trans; 63enum {
64 /* Options that take integer arguments */
65 Opt_port, Opt_rfdno, Opt_wfdno,
66};
100 67
101error: 68static match_table_t tokens = {
102 if (csocket) 69 {Opt_port, "port=%u"},
103 sock_release(csocket); 70 {Opt_rfdno, "rfdno=%u"},
71 {Opt_wfdno, "wfdno=%u"},
72};
104 73
105 kfree(trans); 74/**
106 return ERR_PTR(err); 75 * v9fs_parse_options - parse mount options into session structure
107} 76 * @options: options string passed from mount
108EXPORT_SYMBOL(p9_trans_create_tcp); 77 * @v9ses: existing v9fs session information
78 *
79 */
109 80
110struct p9_transport *p9_trans_create_unix(const char *addr) 81static void parse_opts(char *options, struct p9_fd_opts *opts)
111{ 82{
112 int err; 83 char *p;
113 struct socket *csocket; 84 substring_t args[MAX_OPT_ARGS];
114 struct sockaddr_un sun_server; 85 int option;
115 struct p9_transport *trans; 86 int ret;
116
117 csocket = NULL;
118 trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
119 if (!trans)
120 return ERR_PTR(-ENOMEM);
121 87
122 trans->write = p9_fd_write; 88 opts->port = P9_PORT;
123 trans->read = p9_fd_read; 89 opts->rfd = ~0;
124 trans->close = p9_fd_close; 90 opts->wfd = ~0;
125 trans->poll = p9_fd_poll;
126 91
127 if (strlen(addr) > UNIX_PATH_MAX) { 92 if (!options)
128 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", 93 return;
129 addr);
130 err = -ENAMETOOLONG;
131 goto error;
132 }
133 94
134 sun_server.sun_family = PF_UNIX; 95 while ((p = strsep(&options, ",")) != NULL) {
135 strcpy(sun_server.sun_path, addr); 96 int token;
136 sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); 97 if (!*p)
137 err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, 98 continue;
138 sizeof(struct sockaddr_un) - 1, 0); 99 token = match_token(p, tokens, args);
139 if (err < 0) { 100 ret = match_int(&args[0], &option);
140 P9_EPRINTK(KERN_ERR, 101 if (ret < 0) {
141 "p9_trans_unix: problem connecting socket: %s: %d\n", 102 P9_DPRINTK(P9_DEBUG_ERROR,
142 addr, err); 103 "integer field, but no integer?\n");
143 goto error; 104 continue;
105 }
106 switch (token) {
107 case Opt_port:
108 opts->port = option;
109 break;
110 case Opt_rfdno:
111 opts->rfd = option;
112 break;
113 case Opt_wfdno:
114 opts->wfd = option;
115 break;
116 default:
117 continue;
118 }
144 } 119 }
145
146 err = p9_socket_open(trans, csocket);
147 if (err < 0)
148 goto error;
149
150 return trans;
151
152error:
153 if (csocket)
154 sock_release(csocket);
155
156 kfree(trans);
157 return ERR_PTR(err);
158} 120}
159EXPORT_SYMBOL(p9_trans_create_unix);
160 121
161struct p9_transport *p9_trans_create_fd(int rfd, int wfd) 122static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd)
162{ 123{
163 int err; 124 struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
164 struct p9_transport *trans; 125 GFP_KERNEL);
126 if (!ts)
127 return -ENOMEM;
165 128
166 if (rfd == ~0 || wfd == ~0) { 129 ts->rd = fget(rfd);
167 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); 130 ts->wr = fget(wfd);
168 return ERR_PTR(-ENOPROTOOPT); 131 if (!ts->rd || !ts->wr) {
132 if (ts->rd)
133 fput(ts->rd);
134 if (ts->wr)
135 fput(ts->wr);
136 kfree(ts);
137 return -EIO;
169 } 138 }
170 139
171 trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL); 140 trans->priv = ts;
172 if (!trans) 141 trans->status = Connected;
173 return ERR_PTR(-ENOMEM);
174
175 trans->write = p9_fd_write;
176 trans->read = p9_fd_read;
177 trans->close = p9_fd_close;
178 trans->poll = p9_fd_poll;
179
180 err = p9_fd_open(trans, rfd, wfd);
181 if (err < 0)
182 goto error;
183
184 return trans;
185 142
186error: 143 return 0;
187 kfree(trans);
188 return ERR_PTR(err);
189} 144}
190EXPORT_SYMBOL(p9_trans_create_fd);
191 145
192static int p9_socket_open(struct p9_transport *trans, struct socket *csocket) 146static int p9_socket_open(struct p9_trans *trans, struct socket *csocket)
193{ 147{
194 int fd, ret; 148 int fd, ret;
195 149
@@ -212,30 +166,6 @@ static int p9_socket_open(struct p9_transport *trans, struct socket *csocket)
212 return 0; 166 return 0;
213} 167}
214 168
215static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd)
216{
217 struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
218 GFP_KERNEL);
219 if (!ts)
220 return -ENOMEM;
221
222 ts->rd = fget(rfd);
223 ts->wr = fget(wfd);
224 if (!ts->rd || !ts->wr) {
225 if (ts->rd)
226 fput(ts->rd);
227 if (ts->wr)
228 fput(ts->wr);
229 kfree(ts);
230 return -EIO;
231 }
232
233 trans->priv = ts;
234 trans->status = Connected;
235
236 return 0;
237}
238
239/** 169/**
240 * p9_fd_read- read from a fd 170 * p9_fd_read- read from a fd
241 * @v9ses: session information 171 * @v9ses: session information
@@ -243,7 +173,7 @@ static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd)
243 * @len: size of receive buffer 173 * @len: size of receive buffer
244 * 174 *
245 */ 175 */
246static int p9_fd_read(struct p9_transport *trans, void *v, int len) 176static int p9_fd_read(struct p9_trans *trans, void *v, int len)
247{ 177{
248 int ret; 178 int ret;
249 struct p9_trans_fd *ts = NULL; 179 struct p9_trans_fd *ts = NULL;
@@ -270,7 +200,7 @@ static int p9_fd_read(struct p9_transport *trans, void *v, int len)
270 * @len: size of send buffer 200 * @len: size of send buffer
271 * 201 *
272 */ 202 */
273static int p9_fd_write(struct p9_transport *trans, void *v, int len) 203static int p9_fd_write(struct p9_trans *trans, void *v, int len)
274{ 204{
275 int ret; 205 int ret;
276 mm_segment_t oldfs; 206 mm_segment_t oldfs;
@@ -297,7 +227,7 @@ static int p9_fd_write(struct p9_transport *trans, void *v, int len)
297} 227}
298 228
299static unsigned int 229static unsigned int
300p9_fd_poll(struct p9_transport *trans, struct poll_table_struct *pt) 230p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt)
301{ 231{
302 int ret, n; 232 int ret, n;
303 struct p9_trans_fd *ts = NULL; 233 struct p9_trans_fd *ts = NULL;
@@ -341,7 +271,7 @@ end:
341 * @trans: private socket structure 271 * @trans: private socket structure
342 * 272 *
343 */ 273 */
344static void p9_fd_close(struct p9_transport *trans) 274static void p9_fd_close(struct p9_trans *trans)
345{ 275{
346 struct p9_trans_fd *ts; 276 struct p9_trans_fd *ts;
347 277
@@ -361,3 +291,182 @@ static void p9_fd_close(struct p9_transport *trans)
361 kfree(ts); 291 kfree(ts);
362} 292}
363 293
294static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args)
295{
296 int err;
297 struct p9_trans *trans;
298 struct socket *csocket;
299 struct sockaddr_in sin_server;
300 struct p9_fd_opts opts;
301
302 parse_opts(args, &opts);
303
304 csocket = NULL;
305 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
306 if (!trans)
307 return ERR_PTR(-ENOMEM);
308
309 trans->write = p9_fd_write;
310 trans->read = p9_fd_read;
311 trans->close = p9_fd_close;
312 trans->poll = p9_fd_poll;
313
314 sin_server.sin_family = AF_INET;
315 sin_server.sin_addr.s_addr = in_aton(addr);
316 sin_server.sin_port = htons(opts.port);
317 sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
318
319 if (!csocket) {
320 P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
321 err = -EIO;
322 goto error;
323 }
324
325 err = csocket->ops->connect(csocket,
326 (struct sockaddr *)&sin_server,
327 sizeof(struct sockaddr_in), 0);
328 if (err < 0) {
329 P9_EPRINTK(KERN_ERR,
330 "p9_trans_tcp: problem connecting socket to %s\n",
331 addr);
332 goto error;
333 }
334
335 err = p9_socket_open(trans, csocket);
336 if (err < 0)
337 goto error;
338
339 return trans;
340
341error:
342 if (csocket)
343 sock_release(csocket);
344
345 kfree(trans);
346 return ERR_PTR(err);
347}
348
349static struct p9_trans *p9_trans_create_unix(const char *addr, char *args)
350{
351 int err;
352 struct socket *csocket;
353 struct sockaddr_un sun_server;
354 struct p9_trans *trans;
355
356 csocket = NULL;
357 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
358 if (!trans)
359 return ERR_PTR(-ENOMEM);
360
361 trans->write = p9_fd_write;
362 trans->read = p9_fd_read;
363 trans->close = p9_fd_close;
364 trans->poll = p9_fd_poll;
365
366 if (strlen(addr) > UNIX_PATH_MAX) {
367 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
368 addr);
369 err = -ENAMETOOLONG;
370 goto error;
371 }
372
373 sun_server.sun_family = PF_UNIX;
374 strcpy(sun_server.sun_path, addr);
375 sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
376 err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
377 sizeof(struct sockaddr_un) - 1, 0);
378 if (err < 0) {
379 P9_EPRINTK(KERN_ERR,
380 "p9_trans_unix: problem connecting socket: %s: %d\n",
381 addr, err);
382 goto error;
383 }
384
385 err = p9_socket_open(trans, csocket);
386 if (err < 0)
387 goto error;
388
389 return trans;
390
391error:
392 if (csocket)
393 sock_release(csocket);
394
395 kfree(trans);
396 return ERR_PTR(err);
397}
398
399static struct p9_trans *p9_trans_create_fd(const char *name, char *args)
400{
401 int err;
402 struct p9_trans *trans;
403 struct p9_fd_opts opts;
404
405 parse_opts(args, &opts);
406
407 if (opts.rfd == ~0 || opts.wfd == ~0) {
408 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
409 return ERR_PTR(-ENOPROTOOPT);
410 }
411
412 trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
413 if (!trans)
414 return ERR_PTR(-ENOMEM);
415
416 trans->write = p9_fd_write;
417 trans->read = p9_fd_read;
418 trans->close = p9_fd_close;
419 trans->poll = p9_fd_poll;
420
421 err = p9_fd_open(trans, opts.rfd, opts.wfd);
422 if (err < 0)
423 goto error;
424
425 return trans;
426
427error:
428 kfree(trans);
429 return ERR_PTR(err);
430}
431
432static struct p9_trans_module p9_tcp_trans = {
433 .name = "tcp",
434 .maxsize = MAX_SOCK_BUF,
435 .def = 1,
436 .create = p9_trans_create_tcp,
437};
438
439static struct p9_trans_module p9_unix_trans = {
440 .name = "unix",
441 .maxsize = MAX_SOCK_BUF,
442 .def = 0,
443 .create = p9_trans_create_unix,
444};
445
446static struct p9_trans_module p9_fd_trans = {
447 .name = "fd",
448 .maxsize = MAX_SOCK_BUF,
449 .def = 0,
450 .create = p9_trans_create_fd,
451};
452
453static int __init p9_trans_fd_init(void)
454{
455 v9fs_register_trans(&p9_tcp_trans);
456 v9fs_register_trans(&p9_unix_trans);
457 v9fs_register_trans(&p9_fd_trans);
458
459 return 1;
460}
461
462static void __exit p9_trans_fd_exit(void) {
463 printk(KERN_ERR "Removal of 9p transports not implemented\n");
464 BUG();
465}
466
467module_init(p9_trans_fd_init);
468module_exit(p9_trans_fd_exit);
469
470MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
471MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
472MODULE_LICENSE("GPL");